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

Commit 54427651 authored by Jerry Zuo's avatar Jerry Zuo Committed by Alex Deucher
Browse files

drm/amd/display: Fix MST daisy chain SST not light up



In SST daisy chain scenario, edid is getting read in mst hotplug
routine. It is getting conflict with drm send_enum_path_resources
kernel thread in terms of i2c bus which is getting locked up in
such case.

Have edid being read in get_mode hook, instead of in hotplug
routine.

Signed-off-by: default avatarJerry Zuo <Jerry.Zuo@amd.com>
Reviewed-by: default avatarRoman Li <Roman.Li@amd.com>
Acked-by: default avatarHarry Wentland <Harry.Wentland@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 56e6ed45
Loading
Loading
Loading
Loading
+49 −61
Original line number Diff line number Diff line
@@ -174,14 +174,60 @@ static const struct drm_connector_funcs dm_dp_mst_connector_funcs = {
	.atomic_get_property = amdgpu_dm_connector_atomic_get_property
};

static int dm_connector_update_modes(struct drm_connector *connector,
				struct edid *edid)
{
	int ret;

	ret = drm_add_edid_modes(connector, edid);
	drm_edid_to_eld(connector, edid);

	return ret;
}

static int dm_dp_mst_get_modes(struct drm_connector *connector)
{
	struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector);
	int ret = 0;

	ret = drm_add_edid_modes(&aconnector->base, aconnector->edid);
	if (!aconnector)
		return dm_connector_update_modes(connector, NULL);

	if (!aconnector->edid) {
		struct edid *edid;
		struct dc_sink *dc_sink;
		struct dc_sink_init_data init_params = {
				.link = aconnector->dc_link,
				.sink_signal = SIGNAL_TYPE_DISPLAY_PORT_MST };
		edid = drm_dp_mst_get_edid(connector, &aconnector->mst_port->mst_mgr, aconnector->port);

		if (!edid) {
			drm_mode_connector_update_edid_property(
				&aconnector->base,
				NULL);
			return ret;
		}

		aconnector->edid = edid;

	drm_edid_to_eld(&aconnector->base, aconnector->edid);
		dc_sink = dc_link_add_remote_sink(
			aconnector->dc_link,
			(uint8_t *)edid,
			(edid->extensions + 1) * EDID_LENGTH,
			&init_params);

		dc_sink->priv = aconnector;
		aconnector->dc_sink = dc_sink;

		if (aconnector->dc_sink)
			amdgpu_dm_add_sink_to_freesync_module(
					connector, edid);

		drm_mode_connector_update_edid_property(
						&aconnector->base, edid);
	}

	ret = dm_connector_update_modes(connector, aconnector->edid);

	return ret;
}
@@ -343,66 +389,8 @@ static void dm_dp_mst_hotplug(struct drm_dp_mst_topology_mgr *mgr)
{
	struct amdgpu_dm_connector *master = container_of(mgr, struct amdgpu_dm_connector, mst_mgr);
	struct drm_device *dev = master->base.dev;
	struct amdgpu_device *adev = dev->dev_private;
	struct drm_connector *connector;
	struct amdgpu_dm_connector *aconnector;
	struct edid *edid;
	struct dc_sink *dc_sink;

	drm_modeset_lock_all(dev);
	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
		aconnector = to_amdgpu_dm_connector(connector);
		if (aconnector->port &&
				aconnector->port->pdt != DP_PEER_DEVICE_NONE &&
				aconnector->port->pdt != DP_PEER_DEVICE_MST_BRANCHING &&
				!aconnector->dc_sink) {
			/*
			 * This is plug in case, where port has been created but
			 * sink hasn't been created yet
			 */
			if (!aconnector->edid) {
				struct dc_sink_init_data init_params = {
						.link = aconnector->dc_link,
						.sink_signal = SIGNAL_TYPE_DISPLAY_PORT_MST};
				edid = drm_dp_mst_get_edid(connector, &aconnector->mst_port->mst_mgr, aconnector->port);

				if (!edid) {
					drm_mode_connector_update_edid_property(
						&aconnector->base,
						NULL);
					continue;
				}

				aconnector->edid = edid;

				dc_sink = dc_link_add_remote_sink(
					aconnector->dc_link,
					(uint8_t *)edid,
					(edid->extensions + 1) * EDID_LENGTH,
					&init_params);

				dc_sink->priv = aconnector;
				aconnector->dc_sink = dc_sink;

				if (aconnector->dc_sink)
					amdgpu_dm_add_sink_to_freesync_module(
							connector,
							edid);

				dm_restore_drm_connector_state(connector->dev, connector);
			} else
				edid = aconnector->edid;

			DRM_DEBUG_KMS("edid retrieved %p\n", edid);

			drm_mode_connector_update_edid_property(
				&aconnector->base,
				aconnector->edid);
		}
	}
	drm_modeset_unlock_all(dev);

	schedule_work(&adev->dm.mst_hotplug_work);
	drm_kms_helper_hotplug_event(dev);
}

static void dm_dp_mst_register_connector(struct drm_connector *connector)