diff options
Diffstat (limited to 'drivers/gpu/drm/amd/display/amdgpu_dm')
5 files changed, 103 insertions, 16 deletions
| diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile b/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile index 4699e47aa76b..2b72009844f8 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile @@ -1,4 +1,25 @@  # +# Copyright 2017 Advanced Micro Devices, Inc. +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL +# THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +# +#  # Makefile for the 'dm' sub-component of DAL.  # It provides the control and status of dm blocks. diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 889ed24084e8..bb5fa895fb64 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -520,7 +520,8 @@ static int detect_mst_link_for_all_connectors(struct drm_device *dev)  	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {  		aconnector = to_amdgpu_dm_connector(connector); -		if (aconnector->dc_link->type == dc_connection_mst_branch) { +		if (aconnector->dc_link->type == dc_connection_mst_branch && +		    aconnector->mst_mgr.aux) {  			DRM_DEBUG_DRIVER("DM_MST: starting TM on aconnector: %p [id: %d]\n",  					aconnector, aconnector->base.base.id); @@ -677,6 +678,10 @@ int amdgpu_dm_display_resume(struct amdgpu_device *adev)  		mutex_lock(&aconnector->hpd_lock);  		dc_link_detect(aconnector->dc_link, DETECT_REASON_HPD); + +		if (aconnector->fake_enable && aconnector->dc_link->local_sink) +			aconnector->fake_enable = false; +  		aconnector->dc_sink = NULL;  		amdgpu_dm_update_connector_after_detect(aconnector);  		mutex_unlock(&aconnector->hpd_lock); @@ -711,7 +716,6 @@ int amdgpu_dm_display_resume(struct amdgpu_device *adev)  	ret = drm_atomic_helper_resume(ddev, adev->dm.cached_state); -	drm_atomic_state_put(adev->dm.cached_state);  	adev->dm.cached_state = NULL;  	amdgpu_dm_irq_resume_late(adev); @@ -2332,7 +2336,7 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector,  		       const struct dm_connector_state *dm_state)  {  	struct drm_display_mode *preferred_mode = NULL; -	const struct drm_connector *drm_connector; +	struct drm_connector *drm_connector;  	struct dc_stream_state *stream = NULL;  	struct drm_display_mode mode = *drm_mode;  	bool native_mode_found = false; @@ -2351,11 +2355,13 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector,  	if (!aconnector->dc_sink) {  		/* -		 * Exclude MST from creating fake_sink -		 * TODO: need to enable MST into fake_sink feature +		 * Create dc_sink when necessary to MST +		 * Don't apply fake_sink to MST  		 */ -		if (aconnector->mst_port) -			goto stream_create_fail; +		if (aconnector->mst_port) { +			dm_dp_mst_dc_sink_create(drm_connector); +			goto mst_dc_sink_create_done; +		}  		if (create_fake_sink(aconnector))  			goto stream_create_fail; @@ -2406,6 +2412,7 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector,  stream_create_fail:  dm_state_null:  drm_connector_null: +mst_dc_sink_create_done:  	return stream;  } @@ -2704,7 +2711,7 @@ static void create_eml_sink(struct amdgpu_dm_connector *aconnector)  			.link = aconnector->dc_link,  			.sink_signal = SIGNAL_TYPE_VIRTUAL  	}; -	struct edid *edid = (struct edid *) aconnector->base.edid_blob_ptr->data; +	struct edid *edid;  	if (!aconnector->base.edid_blob_ptr ||  		!aconnector->base.edid_blob_ptr->data) { @@ -2716,6 +2723,8 @@ static void create_eml_sink(struct amdgpu_dm_connector *aconnector)  		return;  	} +	edid = (struct edid *) aconnector->base.edid_blob_ptr->data; +  	aconnector->edid = edid;  	aconnector->dc_em_sink = dc_link_add_remote_sink( @@ -4193,13 +4202,13 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)  		update_stream_scaling_settings(&dm_new_con_state->base.crtc->mode,  				dm_new_con_state, (struct dc_stream_state *)dm_new_crtc_state->stream); +		if (!dm_new_crtc_state->stream) +			continue; +  		status = dc_stream_get_status(dm_new_crtc_state->stream);  		WARN_ON(!status);  		WARN_ON(!status->plane_count); -		if (!dm_new_crtc_state->stream) -			continue; -  		/*TODO How it works with MPO ?*/  		if (!dc_commit_planes_to_stream(  				dm->dc, @@ -4253,7 +4262,7 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)  	drm_atomic_helper_commit_hw_done(state);  	if (wait_for_vblank) -		drm_atomic_helper_wait_for_vblanks(dev, state); +		drm_atomic_helper_wait_for_flip_done(dev, state);  	drm_atomic_helper_cleanup_planes(dev, state);  } @@ -4332,9 +4341,11 @@ void dm_restore_drm_connector_state(struct drm_device *dev,  		return;  	disconnected_acrtc = to_amdgpu_crtc(connector->encoder->crtc); -	acrtc_state = to_dm_crtc_state(disconnected_acrtc->base.state); +	if (!disconnected_acrtc) +		return; -	if (!disconnected_acrtc || !acrtc_state->stream) +	acrtc_state = to_dm_crtc_state(disconnected_acrtc->base.state); +	if (!acrtc_state->stream)  		return;  	/* @@ -4455,7 +4466,7 @@ static int dm_update_crtcs_state(struct dc *dc,  			}  		} -		if (dc_is_stream_unchanged(new_stream, dm_old_crtc_state->stream) && +		if (enable && dc_is_stream_unchanged(new_stream, dm_old_crtc_state->stream) &&  				dc_is_stream_scaling_unchanged(new_stream, dm_old_crtc_state->stream)) {  			new_crtc_state->mode_changed = false; @@ -4709,7 +4720,8 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev,  		}  	} else {  		for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { -			if (!drm_atomic_crtc_needs_modeset(new_crtc_state)) +			if (!drm_atomic_crtc_needs_modeset(new_crtc_state) && +					!new_crtc_state->color_mgmt_changed)  				continue;  			if (!new_crtc_state->enable) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h index 117521c6a6ed..0230250a1164 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h @@ -189,6 +189,8 @@ struct amdgpu_dm_connector {  	struct mutex hpd_lock;  	bool fake_enable; + +	bool mst_connected;  };  #define to_amdgpu_dm_connector(x) container_of(x, struct amdgpu_dm_connector, base) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c index f8efb98b1fa7..638c2c2b5cd7 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c @@ -185,6 +185,42 @@ static int dm_connector_update_modes(struct drm_connector *connector,  	return ret;  } +void dm_dp_mst_dc_sink_create(struct drm_connector *connector) +{ +	struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector); +	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; +	} + +	aconnector->edid = edid; + +	dc_sink = dc_link_add_remote_sink( +		aconnector->dc_link, +		(uint8_t *)aconnector->edid, +		(aconnector->edid->extensions + 1) * EDID_LENGTH, +		&init_params); + +	dc_sink->priv = aconnector; +	aconnector->dc_sink = dc_sink; + +	amdgpu_dm_add_sink_to_freesync_module( +			connector, aconnector->edid); + +	drm_mode_connector_update_edid_property( +					&aconnector->base, aconnector->edid); +} +  static int dm_dp_mst_get_modes(struct drm_connector *connector)  {  	struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector); @@ -311,6 +347,7 @@ dm_dp_add_mst_connector(struct drm_dp_mst_topology_mgr *mgr,  			drm_mode_connector_set_path_property(connector, pathprop);  			drm_connector_list_iter_end(&conn_iter); +			aconnector->mst_connected = true;  			return &aconnector->base;  		}  	} @@ -363,6 +400,8 @@ dm_dp_add_mst_connector(struct drm_dp_mst_topology_mgr *mgr,  	 */  	amdgpu_dm_connector_funcs_reset(connector); +	aconnector->mst_connected = true; +  	DRM_INFO("DM_MST: added connector: %p [id: %d] [master: %p]\n",  			aconnector, connector->base.id, aconnector->mst_port); @@ -394,6 +433,8 @@ static void dm_dp_destroy_mst_connector(struct drm_dp_mst_topology_mgr *mgr,  	drm_mode_connector_update_edid_property(  			&aconnector->base,  			NULL); + +	aconnector->mst_connected = false;  }  static void dm_dp_mst_hotplug(struct drm_dp_mst_topology_mgr *mgr) @@ -404,10 +445,18 @@ static void dm_dp_mst_hotplug(struct drm_dp_mst_topology_mgr *mgr)  	drm_kms_helper_hotplug_event(dev);  } +static void dm_dp_mst_link_status_reset(struct drm_connector *connector) +{ +	mutex_lock(&connector->dev->mode_config.mutex); +	drm_mode_connector_set_link_status_property(connector, DRM_MODE_LINK_STATUS_BAD); +	mutex_unlock(&connector->dev->mode_config.mutex); +} +  static void dm_dp_mst_register_connector(struct drm_connector *connector)  {  	struct drm_device *dev = connector->dev;  	struct amdgpu_device *adev = dev->dev_private; +	struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector);  	if (adev->mode_info.rfbdev)  		drm_fb_helper_add_one_connector(&adev->mode_info.rfbdev->helper, connector); @@ -416,6 +465,8 @@ static void dm_dp_mst_register_connector(struct drm_connector *connector)  	drm_connector_register(connector); +	if (aconnector->mst_connected) +		dm_dp_mst_link_status_reset(connector);  }  static const struct drm_dp_mst_topology_cbs dm_mst_cbs = { diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h index 2da851b40042..8cf51da26657 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h @@ -31,5 +31,6 @@ struct amdgpu_dm_connector;  void amdgpu_dm_initialize_dp_connector(struct amdgpu_display_manager *dm,  				       struct amdgpu_dm_connector *aconnector); +void dm_dp_mst_dc_sink_create(struct drm_connector *connector);  #endif |