diff options
Diffstat (limited to 'drivers/gpu/drm/amd/display/amdgpu_dm')
4 files changed, 132 insertions, 56 deletions
| 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 1ce4c98385e3..63c67346d316 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -629,11 +629,13 @@ static int dm_resume(void *handle)  {  	struct amdgpu_device *adev = handle;  	struct amdgpu_display_manager *dm = &adev->dm; +	int ret = 0;  	/* power on hardware */  	dc_set_power_state(dm->dc, DC_ACPI_CM_POWER_STATE_D0); -	return 0; +	ret = amdgpu_dm_display_resume(adev); +	return ret;  }  int amdgpu_dm_display_resume(struct amdgpu_device *adev) @@ -1035,6 +1037,10 @@ static void handle_hpd_rx_irq(void *param)  			!is_mst_root_connector) {  		/* Downstream Port status changed. */  		if (dc_link_detect(dc_link, DETECT_REASON_HPDRX)) { + +			if (aconnector->fake_enable) +				aconnector->fake_enable = false; +  			amdgpu_dm_update_connector_after_detect(aconnector); @@ -2010,30 +2016,32 @@ static void update_stream_scaling_settings(const struct drm_display_mode *mode,  	dst.width = stream->timing.h_addressable;  	dst.height = stream->timing.v_addressable; -	rmx_type = dm_state->scaling; -	if (rmx_type == RMX_ASPECT || rmx_type == RMX_OFF) { -		if (src.width * dst.height < -				src.height * dst.width) { -			/* height needs less upscaling/more downscaling */ -			dst.width = src.width * -					dst.height / src.height; -		} else { -			/* width needs less upscaling/more downscaling */ -			dst.height = src.height * -					dst.width / src.width; +	if (dm_state) { +		rmx_type = dm_state->scaling; +		if (rmx_type == RMX_ASPECT || rmx_type == RMX_OFF) { +			if (src.width * dst.height < +					src.height * dst.width) { +				/* height needs less upscaling/more downscaling */ +				dst.width = src.width * +						dst.height / src.height; +			} else { +				/* width needs less upscaling/more downscaling */ +				dst.height = src.height * +						dst.width / src.width; +			} +		} else if (rmx_type == RMX_CENTER) { +			dst = src;  		} -	} else if (rmx_type == RMX_CENTER) { -		dst = src; -	} -	dst.x = (stream->timing.h_addressable - dst.width) / 2; -	dst.y = (stream->timing.v_addressable - dst.height) / 2; +		dst.x = (stream->timing.h_addressable - dst.width) / 2; +		dst.y = (stream->timing.v_addressable - dst.height) / 2; -	if (dm_state->underscan_enable) { -		dst.x += dm_state->underscan_hborder / 2; -		dst.y += dm_state->underscan_vborder / 2; -		dst.width -= dm_state->underscan_hborder; -		dst.height -= dm_state->underscan_vborder; +		if (dm_state->underscan_enable) { +			dst.x += dm_state->underscan_hborder / 2; +			dst.y += dm_state->underscan_vborder / 2; +			dst.width -= dm_state->underscan_hborder; +			dst.height -= dm_state->underscan_vborder; +		}  	}  	stream->src = src; @@ -2358,12 +2366,7 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector,  	if (aconnector == NULL) {  		DRM_ERROR("aconnector is NULL!\n"); -		goto drm_connector_null; -	} - -	if (dm_state == NULL) { -		DRM_ERROR("dm_state is NULL!\n"); -		goto dm_state_null; +		return stream;  	}  	drm_connector = &aconnector->base; @@ -2375,18 +2378,18 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector,  		 */  		if (aconnector->mst_port) {  			dm_dp_mst_dc_sink_create(drm_connector); -			goto mst_dc_sink_create_done; +			return stream;  		}  		if (create_fake_sink(aconnector)) -			goto stream_create_fail; +			return stream;  	}  	stream = dc_create_stream_for_sink(aconnector->dc_sink);  	if (stream == NULL) {  		DRM_ERROR("Failed to create stream for sink!\n"); -		goto stream_create_fail; +		return stream;  	}  	list_for_each_entry(preferred_mode, &aconnector->base.modes, head) { @@ -2412,9 +2415,12 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector,  	} else {  		decide_crtc_timing_for_drm_display_mode(  				&mode, preferred_mode, -				dm_state->scaling != RMX_OFF); +				dm_state ? (dm_state->scaling != RMX_OFF) : false);  	} +	if (!dm_state) +		drm_mode_set_crtcinfo(&mode, 0); +  	fill_stream_properties_from_drm_display_mode(stream,  			&mode, &aconnector->base);  	update_stream_scaling_settings(&mode, dm_state, stream); @@ -2424,10 +2430,8 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector,  		drm_connector,  		aconnector->dc_sink); -stream_create_fail: -dm_state_null: -drm_connector_null: -mst_dc_sink_create_done: +	update_stream_signal(stream); +  	return stream;  } @@ -2495,6 +2499,27 @@ dm_crtc_duplicate_state(struct drm_crtc *crtc)  	return &state->base;  } + +static inline int dm_set_vblank(struct drm_crtc *crtc, bool enable) +{ +	enum dc_irq_source irq_source; +	struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc); +	struct amdgpu_device *adev = crtc->dev->dev_private; + +	irq_source = IRQ_TYPE_VBLANK + acrtc->otg_inst; +	return dc_interrupt_set(adev->dm.dc, irq_source, enable) ? 0 : -EBUSY; +} + +static int dm_enable_vblank(struct drm_crtc *crtc) +{ +	return dm_set_vblank(crtc, true); +} + +static void dm_disable_vblank(struct drm_crtc *crtc) +{ +	dm_set_vblank(crtc, false); +} +  /* Implemented only the options currently availible for the driver */  static const struct drm_crtc_funcs amdgpu_dm_crtc_funcs = {  	.reset = dm_crtc_reset_state, @@ -2504,6 +2529,8 @@ static const struct drm_crtc_funcs amdgpu_dm_crtc_funcs = {  	.page_flip = drm_atomic_helper_page_flip,  	.atomic_duplicate_state = dm_crtc_duplicate_state,  	.atomic_destroy_state = dm_crtc_destroy_state, +	.enable_vblank = dm_enable_vblank, +	.disable_vblank = dm_disable_vblank,  };  static enum drm_connector_status @@ -2798,7 +2825,7 @@ int amdgpu_dm_connector_mode_valid(struct drm_connector *connector,  		goto fail;  	} -	stream = dc_create_stream_for_sink(dc_sink); +	stream = create_stream_for_sink(aconnector, mode, NULL);  	if (stream == NULL) {  		DRM_ERROR("Failed to create stream for sink!\n");  		goto fail; @@ -3058,6 +3085,9 @@ static int dm_plane_atomic_check(struct drm_plane *plane,  	if (!dm_plane_state->dc_state)  		return 0; +	if (!fill_rects_from_plane_state(state, dm_plane_state->dc_state)) +		return -EINVAL; +  	if (dc_validate_plane(dc, dm_plane_state->dc_state) == DC_OK)  		return 0; @@ -3104,8 +3134,6 @@ static int amdgpu_dm_plane_init(struct amdgpu_display_manager *dm,  	switch (aplane->base.type) {  	case DRM_PLANE_TYPE_PRIMARY: -		aplane->base.format_default = true; -  		res = drm_universal_plane_init(  				dm->adev->ddev,  				&aplane->base, @@ -4630,8 +4658,6 @@ static int dm_update_planes_state(struct dc *dc,  	bool pflip_needed  = !state->allow_modeset;  	int ret = 0; -	if (pflip_needed) -		return ret;  	/* Add new planes */  	for_each_oldnew_plane_in_state(state, plane, old_plane_state, new_plane_state, i) { @@ -4646,6 +4672,8 @@ static int dm_update_planes_state(struct dc *dc,  		/* Remove any changed/removed planes */  		if (!enable) { +			if (pflip_needed) +				continue;  			if (!old_plane_crtc)  				continue; @@ -4677,6 +4705,7 @@ static int dm_update_planes_state(struct dc *dc,  			*lock_and_validation_needed = true;  		} else { /* Add new planes */ +			struct dc_plane_state *dc_new_plane_state;  			if (drm_atomic_plane_disabling(plane->state, new_plane_state))  				continue; @@ -4690,38 +4719,50 @@ static int dm_update_planes_state(struct dc *dc,  			if (!dm_new_crtc_state->stream)  				continue; +			if (pflip_needed) +				continue;  			WARN_ON(dm_new_plane_state->dc_state); -			dm_new_plane_state->dc_state = dc_create_plane_state(dc); - -			DRM_DEBUG_DRIVER("Enabling DRM plane: %d on DRM crtc %d\n", -					plane->base.id, new_plane_crtc->base.id); - -			if (!dm_new_plane_state->dc_state) { +			dc_new_plane_state = dc_create_plane_state(dc); +			if (!dc_new_plane_state) {  				ret = -EINVAL;  				return ret;  			} +			DRM_DEBUG_DRIVER("Enabling DRM plane: %d on DRM crtc %d\n", +					plane->base.id, new_plane_crtc->base.id); +  			ret = fill_plane_attributes(  				new_plane_crtc->dev->dev_private, -				dm_new_plane_state->dc_state, +				dc_new_plane_state,  				new_plane_state,  				new_crtc_state); -			if (ret) +			if (ret) { +				dc_plane_state_release(dc_new_plane_state);  				return ret; +			} - +			/* +			 * Any atomic check errors that occur after this will +			 * not need a release. The plane state will be attached +			 * to the stream, and therefore part of the atomic +			 * state. It'll be released when the atomic state is +			 * cleaned. +			 */  			if (!dc_add_plane_to_context(  					dc,  					dm_new_crtc_state->stream, -					dm_new_plane_state->dc_state, +					dc_new_plane_state,  					dm_state->context)) { +				dc_plane_state_release(dc_new_plane_state);  				ret = -EINVAL;  				return ret;  			} +			dm_new_plane_state->dc_state = dc_new_plane_state; +  			/* Tell DC to do a full surface update every time there  			 * is a plane change. Inefficient, but works for now.  			 */ @@ -4735,6 +4776,33 @@ static int dm_update_planes_state(struct dc *dc,  	return ret;  } +static int dm_atomic_check_plane_state_fb(struct drm_atomic_state *state, +					  struct drm_crtc *crtc) +{ +	struct drm_plane *plane; +	struct drm_crtc_state *crtc_state; + +	WARN_ON(!drm_atomic_get_new_crtc_state(state, crtc)); + +	drm_for_each_plane_mask(plane, state->dev, crtc->state->plane_mask) { +		struct drm_plane_state *plane_state = +			drm_atomic_get_plane_state(state, plane); + +		if (IS_ERR(plane_state)) +			return -EDEADLK; + +		crtc_state = drm_atomic_get_crtc_state(plane_state->state, crtc); +		if (IS_ERR(crtc_state)) +			return PTR_ERR(crtc_state); + +		if (crtc->primary == plane && crtc_state->active) { +			if (!plane_state->fb) +				return -EINVAL; +		} +	} +	return 0; +} +  static int amdgpu_dm_atomic_check(struct drm_device *dev,  				  struct drm_atomic_state *state)  { @@ -4758,6 +4826,10 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev,  		goto fail;  	for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { +		ret = dm_atomic_check_plane_state_fb(state, crtc); +		if (ret) +			goto fail; +  		if (!drm_atomic_crtc_needs_modeset(new_crtc_state) &&  		    !new_crtc_state->color_mgmt_changed)  			continue; diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c index 9bd142f65f9b..e1acc10e35a2 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c @@ -109,7 +109,7 @@ enum dc_edid_status dm_helpers_parse_edid_caps(  		struct cea_sad *sad = &sads[i];  		edid_caps->audio_modes[i].format_code = sad->format; -		edid_caps->audio_modes[i].channel_count = sad->channels; +		edid_caps->audio_modes[i].channel_count = sad->channels + 1;  		edid_caps->audio_modes[i].sample_rate = sad->freq;  		edid_caps->audio_modes[i].sample_size = sad->byte2;  	} diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c index 1874b6cee6af..422055080df4 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c @@ -683,10 +683,8 @@ static const struct amdgpu_irq_src_funcs dm_hpd_irq_funcs = {  void amdgpu_dm_set_irq_funcs(struct amdgpu_device *adev)  { -	if (adev->mode_info.num_crtc > 0) -		adev->crtc_irq.num_types = AMDGPU_CRTC_IRQ_VLINE1 + adev->mode_info.num_crtc; -	else -		adev->crtc_irq.num_types = 0; + +	adev->crtc_irq.num_types = adev->mode_info.num_crtc;  	adev->crtc_irq.funcs = &dm_crtc_irq_funcs;  	adev->pageflip_irq.num_types = adev->mode_info.num_crtc; 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 f3d87f418d2e..93421dad21bd 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 @@ -189,6 +189,12 @@ void dm_dp_mst_dc_sink_create(struct drm_connector *connector)  			.link = aconnector->dc_link,  			.sink_signal = SIGNAL_TYPE_DISPLAY_PORT_MST }; +	/* +	 * TODO: Need to further figure out why ddc.algo is NULL while MST port exists +	 */ +	if (!aconnector->port || !aconnector->port->aux.ddc.algo) +		return; +  	edid = drm_dp_mst_get_edid(connector, &aconnector->mst_port->mst_mgr, aconnector->port);  	if (!edid) { | 

