diff options
Diffstat (limited to 'drivers/gpu/drm/amd/display')
28 files changed, 371 insertions, 191 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) { diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index 35e84ed031de..12868c769606 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -1358,13 +1358,13 @@ enum dc_irq_source dc_interrupt_to_irq_source(  	return dal_irq_service_to_irq_source(dc->res_pool->irqs, src_id, ext_id);  } -void dc_interrupt_set(struct dc *dc, enum dc_irq_source src, bool enable) +bool dc_interrupt_set(struct dc *dc, enum dc_irq_source src, bool enable)  {  	if (dc == NULL) -		return; +		return false; -	dal_irq_service_set(dc->res_pool->irqs, src, enable); +	return dal_irq_service_set(dc->res_pool->irqs, src, enable);  }  void dc_interrupt_ack(struct dc *dc, enum dc_irq_source src) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link.c b/drivers/gpu/drm/amd/display/dc/core/dc_link.c index a37428271573..be5546181fa8 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c @@ -1749,8 +1749,7 @@ static void enable_link_hdmi(struct pipe_ctx *pipe_ctx)  			link->link_enc,  			pipe_ctx->clock_source->id,  			display_color_depth, -			pipe_ctx->stream->signal == SIGNAL_TYPE_HDMI_TYPE_A, -			pipe_ctx->stream->signal == SIGNAL_TYPE_DVI_DUAL_LINK, +			pipe_ctx->stream->signal,  			stream->phy_pix_clk);  	if (pipe_ctx->stream->signal == SIGNAL_TYPE_HDMI_TYPE_A) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c index 61e8c3e02d16..639421a00ab6 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c @@ -718,7 +718,7 @@ static enum link_training_result perform_channel_equalization_sequence(  	uint32_t retries_ch_eq;  	enum dc_lane_count lane_count = lt_settings->link_settings.lane_count;  	union lane_align_status_updated dpcd_lane_status_updated = {{0}}; -	union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {{{0}}};; +	union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {{{0}}};  	hw_tr_pattern = get_supported_tp(link); @@ -1465,7 +1465,7 @@ void decide_link_settings(struct dc_stream_state *stream,  	/* MST doesn't perform link training for now  	 * TODO: add MST specific link training routine  	 */ -	if (is_mst_supported(link)) { +	if (stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) {  		*link_setting = link->verified_link_cap;  		return;  	} diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c index 95b8dd0e53c6..4d07ffebfd31 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c @@ -1360,9 +1360,6 @@ bool dc_is_stream_scaling_unchanged(  	return true;  } -/* Maximum TMDS single link pixel clock 165MHz */ -#define TMDS_MAX_PIXEL_CLOCK_IN_KHZ 165000 -  static void update_stream_engine_usage(  		struct resource_context *res_ctx,  		const struct resource_pool *pool, diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c index 261811e0c094..cd5819789d76 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c @@ -33,8 +33,7 @@  /*******************************************************************************   * Private functions   ******************************************************************************/ -#define TMDS_MAX_PIXEL_CLOCK_IN_KHZ_UPMOST 297000 -static void update_stream_signal(struct dc_stream_state *stream) +void update_stream_signal(struct dc_stream_state *stream)  {  	struct dc_sink *dc_sink = stream->sink; @@ -45,8 +44,9 @@ static void update_stream_signal(struct dc_stream_state *stream)  		stream->signal = dc_sink->sink_signal;  	if (dc_is_dvi_signal(stream->signal)) { -		if (stream->timing.pix_clk_khz > TMDS_MAX_PIXEL_CLOCK_IN_KHZ_UPMOST && -			stream->sink->sink_signal != SIGNAL_TYPE_DVI_SINGLE_LINK) +		if (stream->ctx->dc->caps.dual_link_dvi && +		    stream->timing.pix_clk_khz > TMDS_MAX_PIXEL_CLOCK && +		    stream->sink->sink_signal != SIGNAL_TYPE_DVI_SINGLE_LINK)  			stream->signal = SIGNAL_TYPE_DVI_DUAL_LINK;  		else  			stream->signal = SIGNAL_TYPE_DVI_SINGLE_LINK; @@ -193,44 +193,20 @@ bool dc_stream_set_cursor_attributes(  	core_dc = stream->ctx->dc;  	res_ctx = &core_dc->current_state->res_ctx; +	stream->cursor_attributes = *attributes;  	for (i = 0; i < MAX_PIPES; i++) {  		struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[i]; -		if (pipe_ctx->stream != stream || (!pipe_ctx->plane_res.xfm && !pipe_ctx->plane_res.dpp)) +		if (pipe_ctx->stream != stream || (!pipe_ctx->plane_res.xfm && +		    !pipe_ctx->plane_res.dpp) || !pipe_ctx->plane_res.ipp)  			continue;  		if (pipe_ctx->top_pipe && pipe_ctx->plane_state != pipe_ctx->top_pipe->plane_state)  			continue; -		if (pipe_ctx->plane_res.ipp->funcs->ipp_cursor_set_attributes != NULL) -			pipe_ctx->plane_res.ipp->funcs->ipp_cursor_set_attributes( -						pipe_ctx->plane_res.ipp, attributes); - -		if (pipe_ctx->plane_res.hubp != NULL && -				pipe_ctx->plane_res.hubp->funcs->set_cursor_attributes != NULL) -			pipe_ctx->plane_res.hubp->funcs->set_cursor_attributes( -					pipe_ctx->plane_res.hubp, attributes); - -		if (pipe_ctx->plane_res.mi != NULL && -				pipe_ctx->plane_res.mi->funcs->set_cursor_attributes != NULL) -			pipe_ctx->plane_res.mi->funcs->set_cursor_attributes( -					pipe_ctx->plane_res.mi, attributes); - - -		if (pipe_ctx->plane_res.xfm != NULL && -				pipe_ctx->plane_res.xfm->funcs->set_cursor_attributes != NULL) -			pipe_ctx->plane_res.xfm->funcs->set_cursor_attributes( -				pipe_ctx->plane_res.xfm, attributes); - -		if (pipe_ctx->plane_res.dpp != NULL && -				pipe_ctx->plane_res.dpp->funcs->set_cursor_attributes != NULL) -			pipe_ctx->plane_res.dpp->funcs->set_cursor_attributes( -				pipe_ctx->plane_res.dpp, attributes->color_format); +		core_dc->hwss.set_cursor_attribute(pipe_ctx);  	} - -	stream->cursor_attributes = *attributes; -  	return true;  } @@ -254,55 +230,21 @@ bool dc_stream_set_cursor_position(  	core_dc = stream->ctx->dc;  	res_ctx = &core_dc->current_state->res_ctx; +	stream->cursor_position = *position;  	for (i = 0; i < MAX_PIPES; i++) {  		struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[i]; -		struct input_pixel_processor *ipp = pipe_ctx->plane_res.ipp; -		struct mem_input *mi = pipe_ctx->plane_res.mi; -		struct hubp *hubp = pipe_ctx->plane_res.hubp; -		struct dpp *dpp = pipe_ctx->plane_res.dpp; -		struct dc_cursor_position pos_cpy = *position; -		struct dc_cursor_mi_param param = { -			.pixel_clk_khz = stream->timing.pix_clk_khz, -			.ref_clk_khz = core_dc->res_pool->ref_clock_inKhz, -			.viewport_x_start = pipe_ctx->plane_res.scl_data.viewport.x, -			.viewport_width = pipe_ctx->plane_res.scl_data.viewport.width, -			.h_scale_ratio = pipe_ctx->plane_res.scl_data.ratios.horz -		};  		if (pipe_ctx->stream != stream ||  				(!pipe_ctx->plane_res.mi  && !pipe_ctx->plane_res.hubp) ||  				!pipe_ctx->plane_state || -				(!pipe_ctx->plane_res.xfm && !pipe_ctx->plane_res.dpp)) -			continue; - -		if (pipe_ctx->plane_state->address.type -				== PLN_ADDR_TYPE_VIDEO_PROGRESSIVE) -			pos_cpy.enable = false; - -		if (pipe_ctx->top_pipe && pipe_ctx->plane_state != pipe_ctx->top_pipe->plane_state) -			pos_cpy.enable = false; - - -		if (ipp != NULL && ipp->funcs->ipp_cursor_set_position != NULL) -			ipp->funcs->ipp_cursor_set_position(ipp, &pos_cpy, ¶m); - -		if (mi != NULL && mi->funcs->set_cursor_position != NULL) -			mi->funcs->set_cursor_position(mi, &pos_cpy, ¶m); - -		if (!hubp) +				(!pipe_ctx->plane_res.xfm && !pipe_ctx->plane_res.dpp) || +				!pipe_ctx->plane_res.ipp)  			continue; -		if (hubp->funcs->set_cursor_position != NULL) -			hubp->funcs->set_cursor_position(hubp, &pos_cpy, ¶m); - -		if (dpp != NULL && dpp->funcs->set_cursor_position != NULL) -			dpp->funcs->set_cursor_position(dpp, &pos_cpy, ¶m, hubp->curs_attr.width); - +		core_dc->hwss.set_cursor_position(pipe_ctx);  	} -	stream->cursor_position = *position; -  	return true;  } diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index e2e3c9df79ea..d6d56611604e 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -62,6 +62,7 @@ struct dc_caps {  	bool dcc_const_color;  	bool dynamic_audio;  	bool is_apu; +	bool dual_link_dvi;  };  struct dc_dcc_surface_param { @@ -672,7 +673,7 @@ enum dc_irq_source dc_interrupt_to_irq_source(  		struct dc *dc,  		uint32_t src_id,  		uint32_t ext_id); -void dc_interrupt_set(struct dc *dc, enum dc_irq_source src, bool enable); +bool dc_interrupt_set(struct dc *dc, enum dc_irq_source src, bool enable);  void dc_interrupt_ack(struct dc *dc, enum dc_irq_source src);  enum dc_irq_source dc_get_hpd_irq_source_at_index(  		struct dc *dc, uint32_t link_index); diff --git a/drivers/gpu/drm/amd/display/dc/dc_stream.h b/drivers/gpu/drm/amd/display/dc/dc_stream.h index 01c60f11b2bd..456e4d29eadd 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_stream.h +++ b/drivers/gpu/drm/amd/display/dc/dc_stream.h @@ -237,6 +237,8 @@ enum surface_update_type dc_check_update_surfaces_for_stream(   */  struct dc_stream_state *dc_create_stream_for_sink(struct dc_sink *dc_sink); +void update_stream_signal(struct dc_stream_state *stream); +  void dc_stream_retain(struct dc_stream_state *dc_stream);  void dc_stream_release(struct dc_stream_state *dc_stream); diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h b/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h index b73db9e78437..f11f17fe08f9 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h @@ -236,6 +236,7 @@  	SR(D2VGA_CONTROL), \  	SR(D3VGA_CONTROL), \  	SR(D4VGA_CONTROL), \ +	SR(VGA_TEST_CONTROL), \  	SR(DC_IP_REQUEST_CNTL), \  	BL_REG_LIST() @@ -337,6 +338,7 @@ struct dce_hwseq_registers {  	uint32_t D2VGA_CONTROL;  	uint32_t D3VGA_CONTROL;  	uint32_t D4VGA_CONTROL; +	uint32_t VGA_TEST_CONTROL;  	/* MMHUB registers. read only. temporary hack */  	uint32_t VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_HI32;  	uint32_t VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_LO32; @@ -493,6 +495,12 @@ struct dce_hwseq_registers {  	HWS_SF(, DOMAIN6_PG_STATUS, DOMAIN6_PGFSM_PWR_STATUS, mask_sh), \  	HWS_SF(, DOMAIN7_PG_STATUS, DOMAIN7_PGFSM_PWR_STATUS, mask_sh), \  	HWS_SF(, DC_IP_REQUEST_CNTL, IP_REQUEST_EN, mask_sh), \ +	HWS_SF(, D1VGA_CONTROL, D1VGA_MODE_ENABLE, mask_sh),\ +	HWS_SF(, D2VGA_CONTROL, D2VGA_MODE_ENABLE, mask_sh),\ +	HWS_SF(, D3VGA_CONTROL, D3VGA_MODE_ENABLE, mask_sh),\ +	HWS_SF(, D4VGA_CONTROL, D4VGA_MODE_ENABLE, mask_sh),\ +	HWS_SF(, VGA_TEST_CONTROL, VGA_TEST_ENABLE, mask_sh),\ +	HWS_SF(, VGA_TEST_CONTROL, VGA_TEST_RENDER_START, mask_sh),\  	HWS_SF(, LVTMA_PWRSEQ_CNTL, LVTMA_BLON, mask_sh), \  	HWS_SF(, LVTMA_PWRSEQ_STATE, LVTMA_PWRSEQ_TARGET_STATE_R, mask_sh) @@ -583,7 +591,13 @@ struct dce_hwseq_registers {  	type DCFCLK_GATE_DIS; \  	type DCHUBBUB_GLOBAL_TIMER_REFDIV; \  	type DENTIST_DPPCLK_WDIVIDER; \ -	type DENTIST_DISPCLK_WDIVIDER; +	type DENTIST_DISPCLK_WDIVIDER; \ +	type VGA_TEST_ENABLE; \ +	type VGA_TEST_RENDER_START; \ +	type D1VGA_MODE_ENABLE; \ +	type D2VGA_MODE_ENABLE; \ +	type D3VGA_MODE_ENABLE; \ +	type D4VGA_MODE_ENABLE;  struct dce_hwseq_shift {  	HWSEQ_REG_FIELD_LIST(uint8_t) diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c index a266e3f5e75f..e4741f1a2b01 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c @@ -82,13 +82,6 @@  #define DCE110_DIG_FE_SOURCE_SELECT_DIGF 0x20  #define DCE110_DIG_FE_SOURCE_SELECT_DIGG 0x40 -/* Minimum pixel clock, in KHz. For TMDS signal is 25.00 MHz */ -#define TMDS_MIN_PIXEL_CLOCK 25000 -/* Maximum pixel clock, in KHz. For TMDS signal is 165.00 MHz */ -#define TMDS_MAX_PIXEL_CLOCK 165000 -/* For current ASICs pixel clock - 600MHz */ -#define MAX_ENCODER_CLOCK 600000 -  enum {  	DP_MST_UPDATE_MAX_RETRY = 50  }; @@ -683,6 +676,7 @@ void dce110_link_encoder_construct(  {  	struct bp_encoder_cap_info bp_cap_info = {0};  	const struct dc_vbios_funcs *bp_funcs = init_data->ctx->dc_bios->funcs; +	enum bp_result result = BP_RESULT_OK;  	enc110->base.funcs = &dce110_lnk_enc_funcs;  	enc110->base.ctx = init_data->ctx; @@ -757,15 +751,24 @@ void dce110_link_encoder_construct(  		enc110->base.preferred_engine = ENGINE_ID_UNKNOWN;  	} +	/* default to one to mirror Windows behavior */ +	enc110->base.features.flags.bits.HDMI_6GB_EN = 1; + +	result = bp_funcs->get_encoder_cap_info(enc110->base.ctx->dc_bios, +						enc110->base.id, &bp_cap_info); +  	/* Override features with DCE-specific values */ -	if (BP_RESULT_OK == bp_funcs->get_encoder_cap_info( -			enc110->base.ctx->dc_bios, enc110->base.id, -			&bp_cap_info)) { +	if (BP_RESULT_OK == result) {  		enc110->base.features.flags.bits.IS_HBR2_CAPABLE =  				bp_cap_info.DP_HBR2_EN;  		enc110->base.features.flags.bits.IS_HBR3_CAPABLE =  				bp_cap_info.DP_HBR3_EN;  		enc110->base.features.flags.bits.HDMI_6GB_EN = bp_cap_info.HDMI_6GB_EN; +	} else { +		dm_logger_write(enc110->base.ctx->logger, LOG_WARNING, +				"%s: Failed to get encoder_cap_info from VBIOS with error code %d!\n", +				__func__, +				result);  	}  } @@ -904,8 +907,7 @@ void dce110_link_encoder_enable_tmds_output(  	struct link_encoder *enc,  	enum clock_source_id clock_source,  	enum dc_color_depth color_depth, -	bool hdmi, -	bool dual_link, +	enum signal_type signal,  	uint32_t pixel_clock)  {  	struct dce110_link_encoder *enc110 = TO_DCE110_LINK_ENC(enc); @@ -919,16 +921,12 @@ void dce110_link_encoder_enable_tmds_output(  	cntl.engine_id = enc->preferred_engine;  	cntl.transmitter = enc110->base.transmitter;  	cntl.pll_id = clock_source; -	if (hdmi) { -		cntl.signal = SIGNAL_TYPE_HDMI_TYPE_A; -		cntl.lanes_number = 4; -	} else if (dual_link) { -		cntl.signal = SIGNAL_TYPE_DVI_DUAL_LINK; +	cntl.signal = signal; +	if (cntl.signal == SIGNAL_TYPE_DVI_DUAL_LINK)  		cntl.lanes_number = 8; -	} else { -		cntl.signal = SIGNAL_TYPE_DVI_SINGLE_LINK; +	else  		cntl.lanes_number = 4; -	} +  	cntl.hpd_sel = enc110->base.hpd_source;  	cntl.pixel_clock = pixel_clock; diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.h b/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.h index 8ca9afe47a2b..0ec3433d34b6 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.h +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.h @@ -210,8 +210,7 @@ void dce110_link_encoder_enable_tmds_output(  	struct link_encoder *enc,  	enum clock_source_id clock_source,  	enum dc_color_depth color_depth, -	bool hdmi, -	bool dual_link, +	enum signal_type signal,  	uint32_t pixel_clock);  /* enables DP PHY output */ diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_opp.c b/drivers/gpu/drm/amd/display/dc/dce/dce_opp.c index 3931412ab6d3..87093894ea9e 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_opp.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_opp.c @@ -128,23 +128,22 @@ static void set_truncation(  		return;  	}  	/* on other format-to do */ -	if (params->flags.TRUNCATE_ENABLED == 0 || -			params->flags.TRUNCATE_DEPTH == 2) +	if (params->flags.TRUNCATE_ENABLED == 0)  		return;  	/*Set truncation depth and Enable truncation*/  	REG_UPDATE_3(FMT_BIT_DEPTH_CONTROL,  				FMT_TRUNCATE_EN, 1,  				FMT_TRUNCATE_DEPTH, -				params->flags.TRUNCATE_MODE, +				params->flags.TRUNCATE_DEPTH,  				FMT_TRUNCATE_MODE, -				params->flags.TRUNCATE_DEPTH); +				params->flags.TRUNCATE_MODE);  }  /**   *	set_spatial_dither   *	1) set spatial dithering mode: pattern of seed - *	2) set spatical dithering depth: 0 for 18bpp or 1 for 24bpp + *	2) set spatial dithering depth: 0 for 18bpp or 1 for 24bpp   *	3) set random seed   *	4) set random mode   *		lfsr is reset every frame or not reset diff --git a/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c b/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c index 3ea43e2a9450..442dd2d93618 100644 --- a/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c @@ -852,6 +852,7 @@ static bool construct(  	dc->caps.max_downscale_ratio = 200;  	dc->caps.i2c_speed_in_khz = 40;  	dc->caps.max_cursor_size = 128; +	dc->caps.dual_link_dvi = true;  	for (i = 0; i < pool->base.pipe_count; i++) {  		pool->base.timing_generators[i] = diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c index 86cdd7b4811f..6f382a3ac90f 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c @@ -688,15 +688,22 @@ void dce110_enable_stream(struct pipe_ctx *pipe_ctx)  	struct dc_crtc_timing *timing = &pipe_ctx->stream->timing;  	struct dc_link *link = pipe_ctx->stream->sink->link; -	/* 1. update AVI info frame (HDMI, DP) -	 * we always need to update info frame -	*/ +  	uint32_t active_total_with_borders;  	uint32_t early_control = 0;  	struct timing_generator *tg = pipe_ctx->stream_res.tg; -	/* TODOFPGA may change to hwss.update_info_frame */ +	/* For MST, there are multiply stream go to only one link. +	 * connect DIG back_end to front_end while enable_stream and +	 * disconnect them during disable_stream +	 * BY this, it is logic clean to separate stream and link */ +	link->link_enc->funcs->connect_dig_be_to_fe(link->link_enc, +						    pipe_ctx->stream_res.stream_enc->id, true); + +	/* update AVI info frame (HDMI, DP)*/ +	/* TODO: FPGA may change to hwss.update_info_frame */  	dce110_update_info_frame(pipe_ctx); +  	/* enable early control to avoid corruption on DP monitor*/  	active_total_with_borders =  			timing->h_addressable @@ -717,12 +724,8 @@ void dce110_enable_stream(struct pipe_ctx *pipe_ctx)  			pipe_ctx->stream_res.stream_enc->funcs->dp_audio_enable(pipe_ctx->stream_res.stream_enc);  	} -	/* For MST, there are multiply stream go to only one link. -	 * connect DIG back_end to front_end while enable_stream and -	 * disconnect them during disable_stream -	 * BY this, it is logic clean to separate stream and link */ -	link->link_enc->funcs->connect_dig_be_to_fe(link->link_enc, -						    pipe_ctx->stream_res.stream_enc->id, true); + +  } @@ -1690,9 +1693,13 @@ static void apply_min_clocks(   *  Check if FBC can be enabled   */  static bool should_enable_fbc(struct dc *dc, -			      struct dc_state *context) +			      struct dc_state *context, +			      uint32_t *pipe_idx)  { -	struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[0]; +	uint32_t i; +	struct pipe_ctx *pipe_ctx = NULL; +	struct resource_context *res_ctx = &context->res_ctx; +  	ASSERT(dc->fbc_compressor); @@ -1704,6 +1711,14 @@ static bool should_enable_fbc(struct dc *dc,  	if (context->stream_count != 1)  		return false; +	for (i = 0; i < dc->res_pool->pipe_count; i++) { +		if (res_ctx->pipe_ctx[i].stream) { +			pipe_ctx = &res_ctx->pipe_ctx[i]; +			*pipe_idx = i; +			break; +		} +	} +  	/* Only supports eDP */  	if (pipe_ctx->stream->sink->link->connector_signal != SIGNAL_TYPE_EDP)  		return false; @@ -1729,11 +1744,14 @@ static bool should_enable_fbc(struct dc *dc,  static void enable_fbc(struct dc *dc,  		       struct dc_state *context)  { -	if (should_enable_fbc(dc, context)) { +	uint32_t pipe_idx = 0; + +	if (should_enable_fbc(dc, context, &pipe_idx)) {  		/* Program GRPH COMPRESSED ADDRESS and PITCH */  		struct compr_addr_and_pitch_params params = {0, 0, 0};  		struct compressor *compr = dc->fbc_compressor; -		struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[0]; +		struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[pipe_idx]; +  		params.source_view_width = pipe_ctx->stream->timing.h_addressable;  		params.source_view_height = pipe_ctx->stream->timing.v_addressable; @@ -2915,6 +2933,49 @@ static void program_csc_matrix(struct pipe_ctx *pipe_ctx,  	}  } +void dce110_set_cursor_position(struct pipe_ctx *pipe_ctx) +{ +	struct dc_cursor_position pos_cpy = pipe_ctx->stream->cursor_position; +	struct input_pixel_processor *ipp = pipe_ctx->plane_res.ipp; +	struct mem_input *mi = pipe_ctx->plane_res.mi; +	struct dc_cursor_mi_param param = { +		.pixel_clk_khz = pipe_ctx->stream->timing.pix_clk_khz, +		.ref_clk_khz = pipe_ctx->stream->ctx->dc->res_pool->ref_clock_inKhz, +		.viewport_x_start = pipe_ctx->plane_res.scl_data.viewport.x, +		.viewport_width = pipe_ctx->plane_res.scl_data.viewport.width, +		.h_scale_ratio = pipe_ctx->plane_res.scl_data.ratios.horz +	}; + +	if (pipe_ctx->plane_state->address.type +			== PLN_ADDR_TYPE_VIDEO_PROGRESSIVE) +		pos_cpy.enable = false; + +	if (pipe_ctx->top_pipe && pipe_ctx->plane_state != pipe_ctx->top_pipe->plane_state) +		pos_cpy.enable = false; + +	if (ipp->funcs->ipp_cursor_set_position) +		ipp->funcs->ipp_cursor_set_position(ipp, &pos_cpy, ¶m); +	if (mi->funcs->set_cursor_position) +		mi->funcs->set_cursor_position(mi, &pos_cpy, ¶m); +} + +void dce110_set_cursor_attribute(struct pipe_ctx *pipe_ctx) +{ +	struct dc_cursor_attributes *attributes = &pipe_ctx->stream->cursor_attributes; + +	if (pipe_ctx->plane_res.ipp->funcs->ipp_cursor_set_attributes) +		pipe_ctx->plane_res.ipp->funcs->ipp_cursor_set_attributes( +				pipe_ctx->plane_res.ipp, attributes); + +	if (pipe_ctx->plane_res.mi->funcs->set_cursor_attributes) +		pipe_ctx->plane_res.mi->funcs->set_cursor_attributes( +				pipe_ctx->plane_res.mi, attributes); + +	if (pipe_ctx->plane_res.xfm->funcs->set_cursor_attributes) +		pipe_ctx->plane_res.xfm->funcs->set_cursor_attributes( +				pipe_ctx->plane_res.xfm, attributes); +} +  static void ready_shared_resources(struct dc *dc, struct dc_state *context) {}  static void optimize_shared_resources(struct dc *dc) {} @@ -2957,6 +3018,8 @@ static const struct hw_sequencer_funcs dce110_funcs = {  	.edp_backlight_control = hwss_edp_backlight_control,  	.edp_power_control = hwss_edp_power_control,  	.edp_wait_for_hpd_ready = hwss_edp_wait_for_hpd_ready, +	.set_cursor_position = dce110_set_cursor_position, +	.set_cursor_attribute = dce110_set_cursor_attribute  };  void dce110_hw_sequencer_construct(struct dc *dc) diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c index 7c4779578fb7..00f18c485e1e 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c @@ -846,6 +846,16 @@ static bool dce110_validate_bandwidth(  	return result;  } +enum dc_status dce110_validate_plane(const struct dc_plane_state *plane_state, +				     struct dc_caps *caps) +{ +	if (((plane_state->dst_rect.width * 2) < plane_state->src_rect.width) || +	    ((plane_state->dst_rect.height * 2) < plane_state->src_rect.height)) +		return DC_FAIL_SURFACE_VALIDATE; + +	return DC_OK; +} +  static bool dce110_validate_surface_sets(  		struct dc_state *context)  { @@ -869,6 +879,13 @@ static bool dce110_validate_surface_sets(  					plane->src_rect.height > 1080))  					return false; +				/* we don't have the logic to support underlay +				 * only yet so block the use case where we get +				 * NV12 plane as top layer +				 */ +				if (j == 0) +					return false; +  				/* irrespective of plane format,  				 * stream should be RGB encoded  				 */ @@ -1021,6 +1038,7 @@ static const struct resource_funcs dce110_res_pool_funcs = {  	.link_enc_create = dce110_link_encoder_create,  	.validate_guaranteed = dce110_validate_guaranteed,  	.validate_bandwidth = dce110_validate_bandwidth, +	.validate_plane = dce110_validate_plane,  	.acquire_idle_pipe_for_layer = dce110_acquire_underlay,  	.add_stream_to_ctx = dce110_add_stream_to_ctx,  	.validate_global = dce110_validate_global diff --git a/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c b/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c index 663e0a047a4b..98d9cd0109e1 100644 --- a/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c @@ -1103,6 +1103,8 @@ static bool construct(  	dc->caps.max_downscale_ratio = 200;  	dc->caps.i2c_speed_in_khz = 100;  	dc->caps.max_cursor_size = 128; +	dc->caps.dual_link_dvi = true; +  	/*************************************************  	 *  Create resources                             * diff --git a/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c b/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c index 57cd67359567..5aab01db28ee 100644 --- a/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c @@ -835,6 +835,8 @@ static bool construct(  	dc->caps.max_downscale_ratio = 200;  	dc->caps.i2c_speed_in_khz = 100;  	dc->caps.max_cursor_size = 128; +	dc->caps.dual_link_dvi = true; +  	dc->debug = debug_defaults;  	/************************************************* diff --git a/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c b/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c index 8f2bd56f3461..25d7eb1567ae 100644 --- a/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c @@ -793,6 +793,7 @@ static bool dce80_construct(  	dc->caps.max_downscale_ratio = 200;  	dc->caps.i2c_speed_in_khz = 40;  	dc->caps.max_cursor_size = 128; +	dc->caps.dual_link_dvi = true;  	/*************************************************  	 *  Create resources                             * diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c index 82572863acab..dc1e010725c1 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c @@ -238,10 +238,34 @@ static void enable_power_gating_plane(  static void disable_vga(  	struct dce_hwseq *hws)  { +	unsigned int in_vga1_mode = 0; +	unsigned int in_vga2_mode = 0; +	unsigned int in_vga3_mode = 0; +	unsigned int in_vga4_mode = 0; + +	REG_GET(D1VGA_CONTROL, D1VGA_MODE_ENABLE, &in_vga1_mode); +	REG_GET(D2VGA_CONTROL, D2VGA_MODE_ENABLE, &in_vga2_mode); +	REG_GET(D3VGA_CONTROL, D3VGA_MODE_ENABLE, &in_vga3_mode); +	REG_GET(D4VGA_CONTROL, D4VGA_MODE_ENABLE, &in_vga4_mode); + +	if (in_vga1_mode == 0 && in_vga2_mode == 0 && +			in_vga3_mode == 0 && in_vga4_mode == 0) +		return; +  	REG_WRITE(D1VGA_CONTROL, 0);  	REG_WRITE(D2VGA_CONTROL, 0);  	REG_WRITE(D3VGA_CONTROL, 0);  	REG_WRITE(D4VGA_CONTROL, 0); + +	/* HW Engineer's Notes: +	 *  During switch from vga->extended, if we set the VGA_TEST_ENABLE and +	 *  then hit the VGA_TEST_RENDER_START, then the DCHUBP timing gets updated correctly. +	 * +	 *  Then vBIOS will have it poll for the VGA_TEST_RENDER_DONE and unset +	 *  VGA_TEST_ENABLE, to leave it in the same state as before. +	 */ +	REG_UPDATE(VGA_TEST_CONTROL, VGA_TEST_ENABLE, 1); +	REG_UPDATE(VGA_TEST_CONTROL, VGA_TEST_RENDER_START, 1);  }  static void dpp_pg_control( @@ -1761,6 +1785,11 @@ static void update_dchubp_dpp(  			&pipe_ctx->plane_res.scl_data.viewport_c);  	} +	if (pipe_ctx->stream->cursor_attributes.address.quad_part != 0) { +		dc->hwss.set_cursor_position(pipe_ctx); +		dc->hwss.set_cursor_attribute(pipe_ctx); +	} +  	if (plane_state->update_flags.bits.full_update) {  		/*gamut remap*/  		program_gamut_remap(pipe_ctx); @@ -2296,7 +2325,7 @@ static bool dcn10_dummy_display_power_gating(  	return true;  } -void dcn10_update_pending_status(struct pipe_ctx *pipe_ctx) +static void dcn10_update_pending_status(struct pipe_ctx *pipe_ctx)  {  	struct dc_plane_state *plane_state = pipe_ctx->plane_state;  	struct timing_generator *tg = pipe_ctx->stream_res.tg; @@ -2316,12 +2345,46 @@ void dcn10_update_pending_status(struct pipe_ctx *pipe_ctx)  	}  } -void dcn10_update_dchub(struct dce_hwseq *hws, struct dchub_init_data *dh_data) +static void dcn10_update_dchub(struct dce_hwseq *hws, struct dchub_init_data *dh_data)  {  	if (hws->ctx->dc->res_pool->hubbub != NULL)  		hubbub1_update_dchub(hws->ctx->dc->res_pool->hubbub, dh_data);  } +static void dcn10_set_cursor_position(struct pipe_ctx *pipe_ctx) +{ +	struct dc_cursor_position pos_cpy = pipe_ctx->stream->cursor_position; +	struct hubp *hubp = pipe_ctx->plane_res.hubp; +	struct dpp *dpp = pipe_ctx->plane_res.dpp; +	struct dc_cursor_mi_param param = { +		.pixel_clk_khz = pipe_ctx->stream->timing.pix_clk_khz, +		.ref_clk_khz = pipe_ctx->stream->ctx->dc->res_pool->ref_clock_inKhz, +		.viewport_x_start = pipe_ctx->plane_res.scl_data.viewport.x, +		.viewport_width = pipe_ctx->plane_res.scl_data.viewport.width, +		.h_scale_ratio = pipe_ctx->plane_res.scl_data.ratios.horz +	}; + +	if (pipe_ctx->plane_state->address.type +			== PLN_ADDR_TYPE_VIDEO_PROGRESSIVE) +		pos_cpy.enable = false; + +	if (pipe_ctx->top_pipe && pipe_ctx->plane_state != pipe_ctx->top_pipe->plane_state) +		pos_cpy.enable = false; + +	hubp->funcs->set_cursor_position(hubp, &pos_cpy, ¶m); +	dpp->funcs->set_cursor_position(dpp, &pos_cpy, ¶m, hubp->curs_attr.width); +} + +static void dcn10_set_cursor_attribute(struct pipe_ctx *pipe_ctx) +{ +	struct dc_cursor_attributes *attributes = &pipe_ctx->stream->cursor_attributes; + +	pipe_ctx->plane_res.hubp->funcs->set_cursor_attributes( +			pipe_ctx->plane_res.hubp, attributes); +	pipe_ctx->plane_res.dpp->funcs->set_cursor_attributes( +		pipe_ctx->plane_res.dpp, attributes->color_format); +} +  static const struct hw_sequencer_funcs dcn10_funcs = {  	.program_gamut_remap = program_gamut_remap,  	.program_csc_matrix = program_csc_matrix, @@ -2362,6 +2425,8 @@ static const struct hw_sequencer_funcs dcn10_funcs = {  	.edp_backlight_control = hwss_edp_backlight_control,  	.edp_power_control = hwss_edp_power_control,  	.edp_wait_for_hpd_ready = hwss_edp_wait_for_hpd_ready, +	.set_cursor_position = dcn10_set_cursor_position, +	.set_cursor_attribute = dcn10_set_cursor_attribute  }; diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h b/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h index 0fd329deacd8..54d8a1386142 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h @@ -123,8 +123,7 @@ struct link_encoder_funcs {  	void (*enable_tmds_output)(struct link_encoder *enc,  		enum clock_source_id clock_source,  		enum dc_color_depth color_depth, -		bool hdmi, -		bool dual_link, +		enum signal_type signal,  		uint32_t pixel_clock);  	void (*enable_dp_output)(struct link_encoder *enc,  		const struct dc_link_settings *link_settings, diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h b/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h index 4c0aa56f7bae..379c6ecd271a 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h @@ -198,6 +198,9 @@ struct hw_sequencer_funcs {  			bool enable);  	void (*edp_wait_for_hpd_ready)(struct dc_link *link, bool power_up); +	void (*set_cursor_position)(struct pipe_ctx *pipe); +	void (*set_cursor_attribute)(struct pipe_ctx *pipe); +  };  void color_space_to_black_color( diff --git a/drivers/gpu/drm/amd/display/dc/irq/dce110/irq_service_dce110.c b/drivers/gpu/drm/amd/display/dc/irq/dce110/irq_service_dce110.c index f7e40b292dfb..d3e1923b01a8 100644 --- a/drivers/gpu/drm/amd/display/dc/irq/dce110/irq_service_dce110.c +++ b/drivers/gpu/drm/amd/display/dc/irq/dce110/irq_service_dce110.c @@ -217,7 +217,7 @@ bool dce110_vblank_set(  			core_dc->current_state->res_ctx.pipe_ctx[pipe_offset].stream_res.tg;  	if (enable) { -		if (!tg->funcs->arm_vert_intr(tg, 2)) { +		if (!tg || !tg->funcs->arm_vert_intr(tg, 2)) {  			DC_ERROR("Failed to get VBLANK!\n");  			return false;  		} diff --git a/drivers/gpu/drm/amd/display/dc/virtual/virtual_link_encoder.c b/drivers/gpu/drm/amd/display/dc/virtual/virtual_link_encoder.c index 57a54a7b89e5..1c079ba37c30 100644 --- a/drivers/gpu/drm/amd/display/dc/virtual/virtual_link_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/virtual/virtual_link_encoder.c @@ -42,8 +42,7 @@ static void virtual_link_encoder_enable_tmds_output(  	struct link_encoder *enc,  	enum clock_source_id clock_source,  	enum dc_color_depth color_depth, -	bool hdmi, -	bool dual_link, +	enum signal_type signal,  	uint32_t pixel_clock) {}  static void virtual_link_encoder_enable_dp_output( diff --git a/drivers/gpu/drm/amd/display/include/grph_object_ctrl_defs.h b/drivers/gpu/drm/amd/display/include/grph_object_ctrl_defs.h index 7a9b43f84a31..36bbad594267 100644 --- a/drivers/gpu/drm/amd/display/include/grph_object_ctrl_defs.h +++ b/drivers/gpu/drm/amd/display/include/grph_object_ctrl_defs.h @@ -419,11 +419,6 @@ struct bios_event_info {  	bool backlight_changed;  }; -enum { -	HDMI_PIXEL_CLOCK_IN_KHZ_297 = 297000, -	TMDS_PIXEL_CLOCK_IN_KHZ_165 = 165000 -}; -  /*   * DFS-bypass flag   */ diff --git a/drivers/gpu/drm/amd/display/include/signal_types.h b/drivers/gpu/drm/amd/display/include/signal_types.h index b5ebde642207..199c5db67cbc 100644 --- a/drivers/gpu/drm/amd/display/include/signal_types.h +++ b/drivers/gpu/drm/amd/display/include/signal_types.h @@ -26,6 +26,11 @@  #ifndef __DC_SIGNAL_TYPES_H__  #define __DC_SIGNAL_TYPES_H__ +/* Minimum pixel clock, in KHz. For TMDS signal is 25.00 MHz */ +#define TMDS_MIN_PIXEL_CLOCK 25000 +/* Maximum pixel clock, in KHz. For TMDS signal is 165.00 MHz */ +#define TMDS_MAX_PIXEL_CLOCK 165000 +  enum signal_type {  	SIGNAL_TYPE_NONE		= 0L,		/* no signal */  	SIGNAL_TYPE_DVI_SINGLE_LINK	= (1 << 0),  | 

