drm/nouveau: use dcb connector table for creating drm connectors
This makes this code common to both the nv04 and nv50 paths. For the moment, we keep the previous behaviour with HDMI/eDP connectors and report them as DVI-D/DP instead. This will be fixed once the rest of the code has been fixed to deal with those types. Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
This commit is contained in:
parent
dc5bc4ed38
commit
7f612d87f8
4 changed files with 69 additions and 122 deletions
|
@ -742,46 +742,60 @@ nouveau_connector_create_lvds(struct drm_device *dev,
|
|||
}
|
||||
|
||||
int
|
||||
nouveau_connector_create(struct drm_device *dev, int index, int type)
|
||||
nouveau_connector_create(struct drm_device *dev,
|
||||
struct dcb_connector_table_entry *dcb)
|
||||
{
|
||||
struct drm_nouveau_private *dev_priv = dev->dev_private;
|
||||
struct nouveau_connector *nv_connector = NULL;
|
||||
struct drm_connector *connector;
|
||||
struct drm_encoder *encoder;
|
||||
int ret;
|
||||
int ret, type;
|
||||
|
||||
NV_DEBUG_KMS(dev, "\n");
|
||||
|
||||
switch (dcb->type) {
|
||||
case DCB_CONNECTOR_NONE:
|
||||
return 0;
|
||||
case DCB_CONNECTOR_VGA:
|
||||
NV_INFO(dev, "Detected a VGA connector\n");
|
||||
type = DRM_MODE_CONNECTOR_VGA;
|
||||
break;
|
||||
case DCB_CONNECTOR_TV_0:
|
||||
case DCB_CONNECTOR_TV_1:
|
||||
case DCB_CONNECTOR_TV_3:
|
||||
NV_INFO(dev, "Detected a TV connector\n");
|
||||
type = DRM_MODE_CONNECTOR_TV;
|
||||
break;
|
||||
case DCB_CONNECTOR_DVI_I:
|
||||
NV_INFO(dev, "Detected a DVI-I connector\n");
|
||||
type = DRM_MODE_CONNECTOR_DVII;
|
||||
break;
|
||||
case DCB_CONNECTOR_DVI_D:
|
||||
case DCB_CONNECTOR_HDMI_0:
|
||||
case DCB_CONNECTOR_HDMI_1:
|
||||
NV_INFO(dev, "Detected a DVI-D connector\n");
|
||||
type = DRM_MODE_CONNECTOR_DVID;
|
||||
break;
|
||||
case DCB_CONNECTOR_LVDS:
|
||||
NV_INFO(dev, "Detected a LVDS connector\n");
|
||||
type = DRM_MODE_CONNECTOR_LVDS;
|
||||
break;
|
||||
case DCB_CONNECTOR_DP:
|
||||
case DCB_CONNECTOR_eDP:
|
||||
NV_INFO(dev, "Detected a DisplayPort connector\n");
|
||||
type = DRM_MODE_CONNECTOR_DisplayPort;
|
||||
break;
|
||||
default:
|
||||
NV_ERROR(dev, "unknown connector type: 0x%02x!!\n", dcb->type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
nv_connector = kzalloc(sizeof(*nv_connector), GFP_KERNEL);
|
||||
if (!nv_connector)
|
||||
return -ENOMEM;
|
||||
nv_connector->dcb = nouveau_bios_connector_entry(dev, index);
|
||||
nv_connector->dcb = dcb;
|
||||
connector = &nv_connector->base;
|
||||
|
||||
switch (type) {
|
||||
case DRM_MODE_CONNECTOR_VGA:
|
||||
NV_INFO(dev, "Detected a VGA connector\n");
|
||||
break;
|
||||
case DRM_MODE_CONNECTOR_DVID:
|
||||
NV_INFO(dev, "Detected a DVI-D connector\n");
|
||||
break;
|
||||
case DRM_MODE_CONNECTOR_DVII:
|
||||
NV_INFO(dev, "Detected a DVI-I connector\n");
|
||||
break;
|
||||
case DRM_MODE_CONNECTOR_LVDS:
|
||||
NV_INFO(dev, "Detected a LVDS connector\n");
|
||||
break;
|
||||
case DRM_MODE_CONNECTOR_TV:
|
||||
NV_INFO(dev, "Detected a TV connector\n");
|
||||
break;
|
||||
case DRM_MODE_CONNECTOR_DisplayPort:
|
||||
NV_INFO(dev, "Detected a DisplayPort connector\n");
|
||||
break;
|
||||
default:
|
||||
NV_ERROR(dev, "Unknown connector, this is not good.\n");
|
||||
break;
|
||||
}
|
||||
|
||||
/* defaults, will get overridden in detect() */
|
||||
connector->interlace_allowed = false;
|
||||
connector->doublescan_allowed = false;
|
||||
|
@ -789,6 +803,26 @@ nouveau_connector_create(struct drm_device *dev, int index, int type)
|
|||
drm_connector_init(dev, connector, &nouveau_connector_funcs, type);
|
||||
drm_connector_helper_add(connector, &nouveau_connector_helper_funcs);
|
||||
|
||||
/* attach encoders */
|
||||
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
|
||||
struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
|
||||
|
||||
if (nv_encoder->dcb->connector != dcb->index)
|
||||
continue;
|
||||
|
||||
if (get_slave_funcs(nv_encoder))
|
||||
get_slave_funcs(nv_encoder)->create_resources(encoder, connector);
|
||||
|
||||
drm_mode_connector_attach_encoder(connector, encoder);
|
||||
}
|
||||
|
||||
if (!connector->encoder_ids[0]) {
|
||||
NV_WARN(dev, " no encoders, ignoring\n");
|
||||
drm_connector_cleanup(connector);
|
||||
kfree(connector);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Init DVI-I specific properties */
|
||||
if (type == DRM_MODE_CONNECTOR_DVII) {
|
||||
drm_mode_create_dvi_i_properties(dev);
|
||||
|
@ -822,19 +856,6 @@ nouveau_connector_create(struct drm_device *dev, int index, int type)
|
|||
}
|
||||
}
|
||||
|
||||
/* attach encoders */
|
||||
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
|
||||
struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
|
||||
|
||||
if (nv_encoder->dcb->connector != index)
|
||||
continue;
|
||||
|
||||
if (get_slave_funcs(nv_encoder))
|
||||
get_slave_funcs(nv_encoder)->create_resources(encoder, connector);
|
||||
|
||||
drm_mode_connector_attach_encoder(connector, encoder);
|
||||
}
|
||||
|
||||
drm_sysfs_connector_add(connector);
|
||||
|
||||
if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS) {
|
||||
|
|
|
@ -49,6 +49,7 @@ static inline struct nouveau_connector *nouveau_connector(
|
|||
return container_of(con, struct nouveau_connector, base);
|
||||
}
|
||||
|
||||
int nouveau_connector_create(struct drm_device *dev, int i2c_index, int type);
|
||||
int nouveau_connector_create(struct drm_device *,
|
||||
struct dcb_connector_table_entry *);
|
||||
|
||||
#endif /* __NOUVEAU_CONNECTOR_H__ */
|
||||
|
|
|
@ -96,7 +96,6 @@ nv04_display_create(struct drm_device *dev)
|
|||
struct dcb_table *dcb = &dev_priv->vbios.dcb;
|
||||
struct drm_encoder *encoder;
|
||||
struct drm_crtc *crtc;
|
||||
uint16_t connector[16] = { 0 };
|
||||
int i, ret;
|
||||
|
||||
NV_DEBUG_KMS(dev, "\n");
|
||||
|
@ -154,52 +153,10 @@ nv04_display_create(struct drm_device *dev)
|
|||
|
||||
if (ret)
|
||||
continue;
|
||||
|
||||
connector[dcbent->connector] |= (1 << dcbent->type);
|
||||
}
|
||||
|
||||
for (i = 0; i < dcb->entries; i++) {
|
||||
struct dcb_entry *dcbent = &dcb->entry[i];
|
||||
uint16_t encoders;
|
||||
int type;
|
||||
|
||||
encoders = connector[dcbent->connector];
|
||||
if (!(encoders & (1 << dcbent->type)))
|
||||
continue;
|
||||
connector[dcbent->connector] = 0;
|
||||
|
||||
switch (dcbent->type) {
|
||||
case OUTPUT_ANALOG:
|
||||
if (!MULTIPLE_ENCODERS(encoders))
|
||||
type = DRM_MODE_CONNECTOR_VGA;
|
||||
else
|
||||
type = DRM_MODE_CONNECTOR_DVII;
|
||||
break;
|
||||
case OUTPUT_TMDS:
|
||||
if (!MULTIPLE_ENCODERS(encoders))
|
||||
type = DRM_MODE_CONNECTOR_DVID;
|
||||
else
|
||||
type = DRM_MODE_CONNECTOR_DVII;
|
||||
break;
|
||||
case OUTPUT_LVDS:
|
||||
type = DRM_MODE_CONNECTOR_LVDS;
|
||||
#if 0
|
||||
/* don't create i2c adapter when lvds ddc not allowed */
|
||||
if (dcbent->lvdsconf.use_straps_for_mode ||
|
||||
dev_priv->vbios->fp_no_ddc)
|
||||
i2c_index = 0xf;
|
||||
#endif
|
||||
break;
|
||||
case OUTPUT_TV:
|
||||
type = DRM_MODE_CONNECTOR_TV;
|
||||
break;
|
||||
default:
|
||||
type = DRM_MODE_CONNECTOR_Unknown;
|
||||
continue;
|
||||
}
|
||||
|
||||
nouveau_connector_create(dev, dcbent->connector, type);
|
||||
}
|
||||
for (i = 0; i < dcb->connector.entries; i++)
|
||||
nouveau_connector_create(dev, &dcb->connector.entry[i]);
|
||||
|
||||
/* Save previous state */
|
||||
NVLockVgaCrtcs(dev, false);
|
||||
|
|
|
@ -466,7 +466,6 @@ int nv50_display_create(struct drm_device *dev)
|
|||
{
|
||||
struct drm_nouveau_private *dev_priv = dev->dev_private;
|
||||
struct dcb_table *dcb = &dev_priv->vbios.dcb;
|
||||
uint32_t connector[16] = {};
|
||||
int ret, i;
|
||||
|
||||
NV_DEBUG_KMS(dev, "\n");
|
||||
|
@ -522,44 +521,13 @@ int nv50_display_create(struct drm_device *dev)
|
|||
NV_WARN(dev, "DCB encoder %d unknown\n", entry->type);
|
||||
continue;
|
||||
}
|
||||
|
||||
connector[entry->connector] |= (1 << entry->type);
|
||||
}
|
||||
|
||||
/* It appears that DCB 3.0+ vbios has a connector table, however,
|
||||
* I'm not 100% certain how to decode it correctly yet so just
|
||||
* look at what encoders are present on each connector index and
|
||||
* attempt to derive the connector type from that.
|
||||
*/
|
||||
for (i = 0 ; i < dcb->entries; i++) {
|
||||
struct dcb_entry *entry = &dcb->entry[i];
|
||||
uint16_t encoders;
|
||||
int type;
|
||||
|
||||
encoders = connector[entry->connector];
|
||||
if (!(encoders & (1 << entry->type)))
|
||||
for (i = 0 ; i < dcb->connector.entries; i++) {
|
||||
if (i != 0 && dcb->connector.entry[i].index ==
|
||||
dcb->connector.entry[i - 1].index)
|
||||
continue;
|
||||
connector[entry->connector] = 0;
|
||||
|
||||
if (encoders & (1 << OUTPUT_DP)) {
|
||||
type = DRM_MODE_CONNECTOR_DisplayPort;
|
||||
} else if (encoders & (1 << OUTPUT_TMDS)) {
|
||||
if (encoders & (1 << OUTPUT_ANALOG))
|
||||
type = DRM_MODE_CONNECTOR_DVII;
|
||||
else
|
||||
type = DRM_MODE_CONNECTOR_DVID;
|
||||
} else if (encoders & (1 << OUTPUT_ANALOG)) {
|
||||
type = DRM_MODE_CONNECTOR_VGA;
|
||||
} else if (encoders & (1 << OUTPUT_LVDS)) {
|
||||
type = DRM_MODE_CONNECTOR_LVDS;
|
||||
} else {
|
||||
type = DRM_MODE_CONNECTOR_Unknown;
|
||||
}
|
||||
|
||||
if (type == DRM_MODE_CONNECTOR_Unknown)
|
||||
continue;
|
||||
|
||||
nouveau_connector_create(dev, entry->connector, type);
|
||||
nouveau_connector_create(dev, &dcb->connector.entry[i]);
|
||||
}
|
||||
|
||||
ret = nv50_display_init(dev);
|
||||
|
|
Loading…
Reference in a new issue