Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7f612d87 authored by Ben Skeggs's avatar Ben Skeggs
Browse files

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: default avatarBen Skeggs <bskeggs@redhat.com>
parent dc5bc4ed
Loading
Loading
Loading
Loading
+54 −33
Original line number Diff line number Diff line
@@ -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");

	nv_connector = kzalloc(sizeof(*nv_connector), GFP_KERNEL);
	if (!nv_connector)
		return -ENOMEM;
	nv_connector->dcb = nouveau_bios_connector_entry(dev, index);
	connector = &nv_connector->base;

	switch (type) {
	case DRM_MODE_CONNECTOR_VGA:
	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 DRM_MODE_CONNECTOR_DVID:
		NV_INFO(dev, "Detected a DVI-D connector\n");
	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 DRM_MODE_CONNECTOR_DVII:
	case DCB_CONNECTOR_DVI_I:
		NV_INFO(dev, "Detected a DVI-I connector\n");
		type = DRM_MODE_CONNECTOR_DVII;
		break;
	case DRM_MODE_CONNECTOR_LVDS:
		NV_INFO(dev, "Detected a LVDS connector\n");
	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 DRM_MODE_CONNECTOR_TV:
		NV_INFO(dev, "Detected a TV connector\n");
	case DCB_CONNECTOR_LVDS:
		NV_INFO(dev, "Detected a LVDS connector\n");
		type = DRM_MODE_CONNECTOR_LVDS;
		break;
	case DRM_MODE_CONNECTOR_DisplayPort:
	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, this is not good.\n");
		break;
		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 = dcb;
	connector = &nv_connector->base;

	/* 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) {
+2 −1
Original line number Diff line number Diff line
@@ -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__ */
+2 −45
Original line number Diff line number Diff line
@@ -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);
+4 −36
Original line number Diff line number Diff line
@@ -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)))
			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)
	for (i = 0 ; i < dcb->connector.entries; i++) {
		if (i != 0 && dcb->connector.entry[i].index ==
			      dcb->connector.entry[i - 1].index)
			continue;

		nouveau_connector_create(dev, entry->connector, type);
		nouveau_connector_create(dev, &dcb->connector.entry[i]);
	}

	ret = nv50_display_init(dev);