Commit 8b7d92ca authored by Ben Skeggs's avatar Ben Skeggs Committed by Lyude Paul

drm/nouveau/kms/nv50-: create connectors based on nvkm info

- preparation for GSP-RM
Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
Reviewed-by: default avatarLyude Paul <lyude@redhat.com>
Acked-by: default avatarDanilo Krummrich <me@dakr.org>
Signed-off-by: default avatarLyude Paul <lyude@redhat.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20230919220442.202488-43-lyude@redhat.com
parent 9c3361de
......@@ -256,7 +256,7 @@ nv04_display_create(struct drm_device *dev)
for (i = 0; i < dcb->entries; i++) {
struct dcb_output *dcbent = &dcb->entry[i];
connector = nouveau_connector_create(dev, dcbent);
connector = nouveau_connector_create(dev, dcbent->connector);
if (IS_ERR(connector))
continue;
......
......@@ -2788,7 +2788,7 @@ nv50_display_create(struct drm_device *dev)
continue;
}
connector = nouveau_connector_create(dev, dcbe);
connector = nouveau_connector_create(dev, dcbe->connector);
if (IS_ERR(connector)) {
nvif_outp_dtor(&outp->outp);
kfree(outp);
......
......@@ -7,6 +7,21 @@ struct nvif_disp;
struct nvif_conn {
struct nvif_object object;
u32 id;
struct {
enum {
NVIF_CONN_VGA,
NVIF_CONN_TV,
NVIF_CONN_DVI_I,
NVIF_CONN_DVI_D,
NVIF_CONN_LVDS,
NVIF_CONN_LVDS_SPWG,
NVIF_CONN_HDMI,
NVIF_CONN_DP,
NVIF_CONN_EDP,
} type;
} info;
};
int nvif_conn_ctor(struct nvif_disp *, const char *name, int id, struct nvif_conn *);
......
......@@ -7,6 +7,16 @@ union nvif_conn_args {
__u8 version;
__u8 id; /* DCB connector table index. */
__u8 pad02[6];
#define NVIF_CONN_V0_VGA 0x00
#define NVIF_CONN_V0_TV 0x01
#define NVIF_CONN_V0_DVI_I 0x02
#define NVIF_CONN_V0_DVI_D 0x03
#define NVIF_CONN_V0_LVDS 0x04
#define NVIF_CONN_V0_LVDS_SPWG 0x05
#define NVIF_CONN_V0_HDMI 0x06
#define NVIF_CONN_V0_DP 0x07
#define NVIF_CONN_V0_EDP 0x08
__u8 type;
} v0;
};
......
......@@ -1275,15 +1275,13 @@ drm_conntype_from_dcb(enum dcb_connector_type dcb)
}
struct drm_connector *
nouveau_connector_create(struct drm_device *dev,
const struct dcb_output *dcbe)
nouveau_connector_create(struct drm_device *dev, int index)
{
struct nouveau_drm *drm = nouveau_drm(dev);
struct nouveau_display *disp = nouveau_display(dev);
struct nouveau_connector *nv_connector = NULL;
struct drm_connector *connector;
struct drm_connector_list_iter conn_iter;
int index = dcbe->connector;
int type, ret = 0;
bool dummy;
......@@ -1305,70 +1303,76 @@ nouveau_connector_create(struct drm_device *dev,
nv_connector->index = index;
INIT_WORK(&nv_connector->irq_work, nouveau_dp_irq);
/* attempt to parse vbios connector type and hotplug gpio */
nv_connector->dcb = olddcb_conn(dev, index);
if (nv_connector->dcb) {
u32 entry = ROM16(nv_connector->dcb[0]);
if (olddcb_conntab(dev)[3] >= 4)
entry |= (u32)ROM16(nv_connector->dcb[2]) << 16;
nv_connector->type = nv_connector->dcb[0];
if (drm_conntype_from_dcb(nv_connector->type) ==
DRM_MODE_CONNECTOR_Unknown) {
NV_WARN(drm, "unknown connector type %02x\n",
nv_connector->type);
nv_connector->type = DCB_CONNECTOR_NONE;
if (disp->disp.conn_mask & BIT(nv_connector->index)) {
ret = nvif_conn_ctor(&disp->disp, nv_connector->base.name, nv_connector->index,
&nv_connector->conn);
if (ret) {
kfree(nv_connector);
return ERR_PTR(ret);
}
/* Gigabyte NX85T */
if (nv_match_device(dev, 0x0421, 0x1458, 0x344c)) {
if (nv_connector->type == DCB_CONNECTOR_HDMI_1)
nv_connector->type = DCB_CONNECTOR_DVI_I;
switch (nv_connector->conn.info.type) {
case NVIF_CONN_VGA : type = DCB_CONNECTOR_VGA; break;
case NVIF_CONN_DVI_I : type = DCB_CONNECTOR_DVI_I; break;
case NVIF_CONN_DVI_D : type = DCB_CONNECTOR_DVI_D; break;
case NVIF_CONN_LVDS : type = DCB_CONNECTOR_LVDS; break;
case NVIF_CONN_LVDS_SPWG: type = DCB_CONNECTOR_LVDS_SPWG; break;
case NVIF_CONN_DP : type = DCB_CONNECTOR_DP; break;
case NVIF_CONN_EDP : type = DCB_CONNECTOR_eDP; break;
case NVIF_CONN_HDMI : type = DCB_CONNECTOR_HDMI_0; break;
default:
WARN_ON(1);
return NULL;
}
/* Gigabyte GV-NX86T512H */
if (nv_match_device(dev, 0x0402, 0x1458, 0x3455)) {
if (nv_connector->type == DCB_CONNECTOR_HDMI_1)
nv_connector->type = DCB_CONNECTOR_DVI_I;
}
nv_connector->type = type;
} else {
nv_connector->type = DCB_CONNECTOR_NONE;
}
u8 *dcb = olddcb_conn(dev, nv_connector->index);
/* no vbios data, or an unknown dcb connector type - attempt to
* figure out something suitable ourselves
*/
if (nv_connector->type == DCB_CONNECTOR_NONE) {
struct nouveau_drm *drm = nouveau_drm(dev);
struct dcb_table *dcbt = &drm->vbios.dcb;
u32 encoders = 0;
int i;
for (i = 0; i < dcbt->entries; i++) {
if (dcbt->entry[i].connector == nv_connector->index)
encoders |= (1 << dcbt->entry[i].type);
if (dcb)
nv_connector->type = dcb[0];
else
nv_connector->type = DCB_CONNECTOR_NONE;
/* attempt to parse vbios connector type and hotplug gpio */
if (nv_connector->type != DCB_CONNECTOR_NONE) {
if (drm_conntype_from_dcb(nv_connector->type) ==
DRM_MODE_CONNECTOR_Unknown) {
NV_WARN(drm, "unknown connector type %02x\n",
nv_connector->type);
nv_connector->type = DCB_CONNECTOR_NONE;
}
}
if (encoders & (1 << DCB_OUTPUT_DP)) {
if (encoders & (1 << DCB_OUTPUT_TMDS))
nv_connector->type = DCB_CONNECTOR_DP;
else
nv_connector->type = DCB_CONNECTOR_eDP;
} else
if (encoders & (1 << DCB_OUTPUT_TMDS)) {
if (encoders & (1 << DCB_OUTPUT_ANALOG))
nv_connector->type = DCB_CONNECTOR_DVI_I;
else
nv_connector->type = DCB_CONNECTOR_DVI_D;
} else
if (encoders & (1 << DCB_OUTPUT_ANALOG)) {
nv_connector->type = DCB_CONNECTOR_VGA;
} else
if (encoders & (1 << DCB_OUTPUT_LVDS)) {
nv_connector->type = DCB_CONNECTOR_LVDS;
} else
if (encoders & (1 << DCB_OUTPUT_TV)) {
nv_connector->type = DCB_CONNECTOR_TV_0;
/* no vbios data, or an unknown dcb connector type - attempt to
* figure out something suitable ourselves
*/
if (nv_connector->type == DCB_CONNECTOR_NONE &&
!WARN_ON(drm->client.device.info.family >= NV_DEVICE_INFO_V0_TESLA)) {
struct dcb_table *dcbt = &drm->vbios.dcb;
u32 encoders = 0;
int i;
for (i = 0; i < dcbt->entries; i++) {
if (dcbt->entry[i].connector == nv_connector->index)
encoders |= (1 << dcbt->entry[i].type);
}
if (encoders & (1 << DCB_OUTPUT_TMDS)) {
if (encoders & (1 << DCB_OUTPUT_ANALOG))
nv_connector->type = DCB_CONNECTOR_DVI_I;
else
nv_connector->type = DCB_CONNECTOR_DVI_D;
} else
if (encoders & (1 << DCB_OUTPUT_ANALOG)) {
nv_connector->type = DCB_CONNECTOR_VGA;
} else
if (encoders & (1 << DCB_OUTPUT_LVDS)) {
nv_connector->type = DCB_CONNECTOR_LVDS;
} else
if (encoders & (1 << DCB_OUTPUT_TV)) {
nv_connector->type = DCB_CONNECTOR_TV_0;
}
}
}
......@@ -1414,14 +1418,7 @@ nouveau_connector_create(struct drm_device *dev,
drm_connector_helper_add(connector, &nouveau_connector_helper_funcs);
connector->polled = DRM_CONNECTOR_POLL_CONNECT;
if (nv_connector->dcb && (disp->disp.conn_mask & BIT(nv_connector->index))) {
ret = nvif_conn_ctor(&disp->disp, nv_connector->base.name, nv_connector->index,
&nv_connector->conn);
if (ret) {
kfree(nv_connector);
return ERR_PTR(ret);
}
if (nvif_object_constructed(&nv_connector->conn.object)) {
ret = nvif_conn_event_ctor(&nv_connector->conn, "kmsHotplug",
nouveau_connector_hotplug,
NVIF_CONN_EVENT_V0_PLUG | NVIF_CONN_EVENT_V0_UNPLUG,
......
......@@ -121,7 +121,6 @@ struct nouveau_connector {
struct drm_connector base;
enum dcb_connector_type type;
u8 index;
u8 *dcb;
struct nvif_conn conn;
u64 hpd_pending;
......@@ -200,7 +199,7 @@ nouveau_crtc_connector_get(struct nouveau_crtc *nv_crtc)
}
struct drm_connector *
nouveau_connector_create(struct drm_device *, const struct dcb_output *);
nouveau_connector_create(struct drm_device *, int id);
void nouveau_connector_hpd(struct nouveau_connector *, u64 bits);
extern int nouveau_tv_disable;
......
......@@ -63,5 +63,25 @@ nvif_conn_ctor(struct nvif_disp *disp, const char *name, int id, struct nvif_con
ret = nvif_object_ctor(&disp->object, name ?: "nvifConn", id, NVIF_CLASS_CONN,
&args, sizeof(args), &conn->object);
NVIF_ERRON(ret, &disp->object, "[NEW conn id:%d]", id);
return ret;
if (ret)
return ret;
conn->id = id;
switch (args.type) {
case NVIF_CONN_V0_VGA : conn->info.type = NVIF_CONN_VGA; break;
case NVIF_CONN_V0_TV : conn->info.type = NVIF_CONN_TV; break;
case NVIF_CONN_V0_DVI_I : conn->info.type = NVIF_CONN_DVI_I; break;
case NVIF_CONN_V0_DVI_D : conn->info.type = NVIF_CONN_DVI_D; break;
case NVIF_CONN_V0_LVDS : conn->info.type = NVIF_CONN_LVDS; break;
case NVIF_CONN_V0_LVDS_SPWG: conn->info.type = NVIF_CONN_LVDS_SPWG; break;
case NVIF_CONN_V0_HDMI : conn->info.type = NVIF_CONN_HDMI; break;
case NVIF_CONN_V0_DP : conn->info.type = NVIF_CONN_DP; break;
case NVIF_CONN_V0_EDP : conn->info.type = NVIF_CONN_EDP; break;
default:
break;
}
return 0;
}
......@@ -142,6 +142,32 @@ nvkm_uconn_new(const struct nvkm_oclass *oclass, void *argv, u32 argc, struct nv
ret = -EBUSY;
spin_lock(&disp->client.lock);
if (!conn->object.func) {
switch (conn->info.type) {
case DCB_CONNECTOR_VGA : args->v0.type = NVIF_CONN_V0_VGA; break;
case DCB_CONNECTOR_TV_0 :
case DCB_CONNECTOR_TV_1 :
case DCB_CONNECTOR_TV_3 : args->v0.type = NVIF_CONN_V0_TV; break;
case DCB_CONNECTOR_DMS59_0 :
case DCB_CONNECTOR_DMS59_1 :
case DCB_CONNECTOR_DVI_I : args->v0.type = NVIF_CONN_V0_DVI_I; break;
case DCB_CONNECTOR_DVI_D : args->v0.type = NVIF_CONN_V0_DVI_D; break;
case DCB_CONNECTOR_LVDS : args->v0.type = NVIF_CONN_V0_LVDS; break;
case DCB_CONNECTOR_LVDS_SPWG: args->v0.type = NVIF_CONN_V0_LVDS_SPWG; break;
case DCB_CONNECTOR_DMS59_DP0:
case DCB_CONNECTOR_DMS59_DP1:
case DCB_CONNECTOR_DP :
case DCB_CONNECTOR_mDP :
case DCB_CONNECTOR_USB_C : args->v0.type = NVIF_CONN_V0_DP; break;
case DCB_CONNECTOR_eDP : args->v0.type = NVIF_CONN_V0_EDP; break;
case DCB_CONNECTOR_HDMI_0 :
case DCB_CONNECTOR_HDMI_1 :
case DCB_CONNECTOR_HDMI_C : args->v0.type = NVIF_CONN_V0_HDMI; break;
default:
WARN_ON(1);
ret = -EINVAL;
break;
}
nvkm_object_ctor(&nvkm_uconn, oclass, &conn->object);
*pobject = &conn->object;
ret = 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment