diff options
Diffstat (limited to 'drivers/gpu/drm/amd/display')
25 files changed, 323 insertions, 219 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 f7c5cdc10a70..28e651b173ab 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -441,7 +441,7 @@ static void dm_vupdate_high_irq(void *interrupt_params)  /**   * dm_crtc_high_irq() - Handles CRTC interrupt - * @interrupt_params: ignored + * @interrupt_params: used for determining the CRTC instance   *   * Handles the CRTC/VSYNC interrupt by notfying DRM's VBLANK   * event handler. @@ -455,70 +455,6 @@ static void dm_crtc_high_irq(void *interrupt_params)  	unsigned long flags;  	acrtc = get_crtc_by_otg_inst(adev, irq_params->irq_src - IRQ_TYPE_VBLANK); - -	if (acrtc) { -		acrtc_state = to_dm_crtc_state(acrtc->base.state); - -		DRM_DEBUG_VBL("crtc:%d, vupdate-vrr:%d\n", -			      acrtc->crtc_id, -			      amdgpu_dm_vrr_active(acrtc_state)); - -		/* Core vblank handling at start of front-porch is only possible -		 * in non-vrr mode, as only there vblank timestamping will give -		 * valid results while done in front-porch. Otherwise defer it -		 * to dm_vupdate_high_irq after end of front-porch. -		 */ -		if (!amdgpu_dm_vrr_active(acrtc_state)) -			drm_crtc_handle_vblank(&acrtc->base); - -		/* Following stuff must happen at start of vblank, for crc -		 * computation and below-the-range btr support in vrr mode. -		 */ -		amdgpu_dm_crtc_handle_crc_irq(&acrtc->base); - -		if (acrtc_state->stream && adev->family >= AMDGPU_FAMILY_AI && -		    acrtc_state->vrr_params.supported && -		    acrtc_state->freesync_config.state == VRR_STATE_ACTIVE_VARIABLE) { -			spin_lock_irqsave(&adev->ddev->event_lock, flags); -			mod_freesync_handle_v_update( -				adev->dm.freesync_module, -				acrtc_state->stream, -				&acrtc_state->vrr_params); - -			dc_stream_adjust_vmin_vmax( -				adev->dm.dc, -				acrtc_state->stream, -				&acrtc_state->vrr_params.adjust); -			spin_unlock_irqrestore(&adev->ddev->event_lock, flags); -		} -	} -} - -#if defined(CONFIG_DRM_AMD_DC_DCN) -/** - * dm_dcn_crtc_high_irq() - Handles VStartup interrupt for DCN generation ASICs - * @interrupt params - interrupt parameters - * - * Notify DRM's vblank event handler at VSTARTUP - * - * Unlike DCE hardware, we trigger the handler at VSTARTUP. at which: - * * We are close enough to VUPDATE - the point of no return for hw - * * We are in the fixed portion of variable front porch when vrr is enabled - * * We are before VUPDATE, where double-buffered vrr registers are swapped - * - * It is therefore the correct place to signal vblank, send user flip events, - * and update VRR. - */ -static void dm_dcn_crtc_high_irq(void *interrupt_params) -{ -	struct common_irq_params *irq_params = interrupt_params; -	struct amdgpu_device *adev = irq_params->adev; -	struct amdgpu_crtc *acrtc; -	struct dm_crtc_state *acrtc_state; -	unsigned long flags; - -	acrtc = get_crtc_by_otg_inst(adev, irq_params->irq_src - IRQ_TYPE_VBLANK); -  	if (!acrtc)  		return; @@ -528,22 +464,35 @@ static void dm_dcn_crtc_high_irq(void *interrupt_params)  			 amdgpu_dm_vrr_active(acrtc_state),  			 acrtc_state->active_planes); +	/** +	 * Core vblank handling at start of front-porch is only possible +	 * in non-vrr mode, as only there vblank timestamping will give +	 * valid results while done in front-porch. Otherwise defer it +	 * to dm_vupdate_high_irq after end of front-porch. +	 */ +	if (!amdgpu_dm_vrr_active(acrtc_state)) +		drm_crtc_handle_vblank(&acrtc->base); + +	/** +	 * Following stuff must happen at start of vblank, for crc +	 * computation and below-the-range btr support in vrr mode. +	 */  	amdgpu_dm_crtc_handle_crc_irq(&acrtc->base); -	drm_crtc_handle_vblank(&acrtc->base); + +	/* BTR updates need to happen before VUPDATE on Vega and above. */ +	if (adev->family < AMDGPU_FAMILY_AI) +		return;  	spin_lock_irqsave(&adev->ddev->event_lock, flags); -	if (acrtc_state->vrr_params.supported && +	if (acrtc_state->stream && acrtc_state->vrr_params.supported &&  	    acrtc_state->freesync_config.state == VRR_STATE_ACTIVE_VARIABLE) { -		mod_freesync_handle_v_update( -		adev->dm.freesync_module, -		acrtc_state->stream, -		&acrtc_state->vrr_params); +		mod_freesync_handle_v_update(adev->dm.freesync_module, +					     acrtc_state->stream, +					     &acrtc_state->vrr_params); -		dc_stream_adjust_vmin_vmax( -			adev->dm.dc, -			acrtc_state->stream, -			&acrtc_state->vrr_params.adjust); +		dc_stream_adjust_vmin_vmax(adev->dm.dc, acrtc_state->stream, +					   &acrtc_state->vrr_params.adjust);  	}  	/* @@ -556,7 +505,8 @@ static void dm_dcn_crtc_high_irq(void *interrupt_params)  	 * avoid race conditions between flip programming and completion,  	 * which could cause too early flip completion events.  	 */ -	if (acrtc->pflip_status == AMDGPU_FLIP_SUBMITTED && +	if (adev->family >= AMDGPU_FAMILY_RV && +	    acrtc->pflip_status == AMDGPU_FLIP_SUBMITTED &&  	    acrtc_state->active_planes == 0) {  		if (acrtc->event) {  			drm_crtc_send_vblank_event(&acrtc->base, acrtc->event); @@ -568,7 +518,6 @@ static void dm_dcn_crtc_high_irq(void *interrupt_params)  	spin_unlock_irqrestore(&adev->ddev->event_lock, flags);  } -#endif  static int dm_set_clockgating_state(void *handle,  		  enum amd_clockgating_state state) @@ -2008,17 +1957,22 @@ void amdgpu_dm_update_connector_after_detect(  		dc_sink_retain(aconnector->dc_sink);  		if (sink->dc_edid.length == 0) {  			aconnector->edid = NULL; -			drm_dp_cec_unset_edid(&aconnector->dm_dp_aux.aux); +			if (aconnector->dc_link->aux_mode) { +				drm_dp_cec_unset_edid( +					&aconnector->dm_dp_aux.aux); +			}  		} else {  			aconnector->edid = -				(struct edid *) sink->dc_edid.raw_edid; - +				(struct edid *)sink->dc_edid.raw_edid;  			drm_connector_update_edid_property(connector, -					aconnector->edid); -			drm_dp_cec_set_edid(&aconnector->dm_dp_aux.aux, -					    aconnector->edid); +							   aconnector->edid); + +			if (aconnector->dc_link->aux_mode) +				drm_dp_cec_set_edid(&aconnector->dm_dp_aux.aux, +						    aconnector->edid);  		} +  		amdgpu_dm_update_freesync_caps(connector, aconnector->edid);  		update_connector_ext_caps(aconnector);  	} else { @@ -2440,8 +2394,36 @@ static int dcn10_register_irq_handlers(struct amdgpu_device *adev)  		c_irq_params->adev = adev;  		c_irq_params->irq_src = int_params.irq_source; +		amdgpu_dm_irq_register_interrupt( +			adev, &int_params, dm_crtc_high_irq, c_irq_params); +	} + +	/* Use VUPDATE_NO_LOCK interrupt on DCN, which seems to correspond to +	 * the regular VUPDATE interrupt on DCE. We want DC_IRQ_SOURCE_VUPDATEx +	 * to trigger at end of each vblank, regardless of state of the lock, +	 * matching DCE behaviour. +	 */ +	for (i = DCN_1_0__SRCID__OTG0_IHC_V_UPDATE_NO_LOCK_INTERRUPT; +	     i <= DCN_1_0__SRCID__OTG0_IHC_V_UPDATE_NO_LOCK_INTERRUPT + adev->mode_info.num_crtc - 1; +	     i++) { +		r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_DCE, i, &adev->vupdate_irq); + +		if (r) { +			DRM_ERROR("Failed to add vupdate irq id!\n"); +			return r; +		} + +		int_params.int_context = INTERRUPT_HIGH_IRQ_CONTEXT; +		int_params.irq_source = +			dc_interrupt_to_irq_source(dc, i, 0); + +		c_irq_params = &adev->dm.vupdate_params[int_params.irq_source - DC_IRQ_SOURCE_VUPDATE1]; + +		c_irq_params->adev = adev; +		c_irq_params->irq_src = int_params.irq_source; +  		amdgpu_dm_irq_register_interrupt(adev, &int_params, -				dm_dcn_crtc_high_irq, c_irq_params); +				dm_vupdate_high_irq, c_irq_params);  	}  	/* Use GRPH_PFLIP interrupt */ @@ -3340,7 +3322,8 @@ fill_plane_dcc_attributes(struct amdgpu_device *adev,  			  const union dc_tiling_info *tiling_info,  			  const uint64_t info,  			  struct dc_plane_dcc_param *dcc, -			  struct dc_plane_address *address) +			  struct dc_plane_address *address, +			  bool force_disable_dcc)  {  	struct dc *dc = adev->dm.dc;  	struct dc_dcc_surface_param input; @@ -3352,6 +3335,9 @@ fill_plane_dcc_attributes(struct amdgpu_device *adev,  	memset(&input, 0, sizeof(input));  	memset(&output, 0, sizeof(output)); +	if (force_disable_dcc) +		return 0; +  	if (!offset)  		return 0; @@ -3401,7 +3387,8 @@ fill_plane_buffer_attributes(struct amdgpu_device *adev,  			     union dc_tiling_info *tiling_info,  			     struct plane_size *plane_size,  			     struct dc_plane_dcc_param *dcc, -			     struct dc_plane_address *address) +			     struct dc_plane_address *address, +			     bool force_disable_dcc)  {  	const struct drm_framebuffer *fb = &afb->base;  	int ret; @@ -3507,7 +3494,8 @@ fill_plane_buffer_attributes(struct amdgpu_device *adev,  		ret = fill_plane_dcc_attributes(adev, afb, format, rotation,  						plane_size, tiling_info, -						tiling_flags, dcc, address); +						tiling_flags, dcc, address, +						force_disable_dcc);  		if (ret)  			return ret;  	} @@ -3599,7 +3587,8 @@ fill_dc_plane_info_and_addr(struct amdgpu_device *adev,  			    const struct drm_plane_state *plane_state,  			    const uint64_t tiling_flags,  			    struct dc_plane_info *plane_info, -			    struct dc_plane_address *address) +			    struct dc_plane_address *address, +			    bool force_disable_dcc)  {  	const struct drm_framebuffer *fb = plane_state->fb;  	const struct amdgpu_framebuffer *afb = @@ -3681,7 +3670,8 @@ fill_dc_plane_info_and_addr(struct amdgpu_device *adev,  					   plane_info->rotation, tiling_flags,  					   &plane_info->tiling_info,  					   &plane_info->plane_size, -					   &plane_info->dcc, address); +					   &plane_info->dcc, address, +					   force_disable_dcc);  	if (ret)  		return ret; @@ -3704,6 +3694,7 @@ static int fill_dc_plane_attributes(struct amdgpu_device *adev,  	struct dc_plane_info plane_info;  	uint64_t tiling_flags;  	int ret; +	bool force_disable_dcc = false;  	ret = fill_dc_scaling_info(plane_state, &scaling_info);  	if (ret) @@ -3718,9 +3709,11 @@ static int fill_dc_plane_attributes(struct amdgpu_device *adev,  	if (ret)  		return ret; +	force_disable_dcc = adev->asic_type == CHIP_RAVEN && adev->in_suspend;  	ret = fill_dc_plane_info_and_addr(adev, plane_state, tiling_flags,  					  &plane_info, -					  &dc_plane_state->address); +					  &dc_plane_state->address, +					  force_disable_dcc);  	if (ret)  		return ret; @@ -4437,10 +4430,6 @@ static inline int dm_set_vupdate_irq(struct drm_crtc *crtc, bool enable)  	struct amdgpu_device *adev = crtc->dev->dev_private;  	int rc; -	/* Do not set vupdate for DCN hardware */ -	if (adev->family > AMDGPU_FAMILY_AI) -		return 0; -  	irq_source = IRQ_TYPE_VUPDATE + acrtc->otg_inst;  	rc = dc_interrupt_set(adev->dm.dc, irq_source, enable) ? 0 : -EBUSY; @@ -4664,6 +4653,7 @@ static void amdgpu_dm_connector_destroy(struct drm_connector *connector)  		i2c_del_adapter(&aconnector->i2c->base);  		kfree(aconnector->i2c);  	} +	kfree(aconnector->dm_dp_aux.aux.name);  	kfree(connector);  } @@ -4723,10 +4713,19 @@ amdgpu_dm_connector_atomic_duplicate_state(struct drm_connector *connector)  static int  amdgpu_dm_connector_late_register(struct drm_connector *connector)  { -#if defined(CONFIG_DEBUG_FS)  	struct amdgpu_dm_connector *amdgpu_dm_connector =  		to_amdgpu_dm_connector(connector); +	int r; +	if ((connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort) || +	    (connector->connector_type == DRM_MODE_CONNECTOR_eDP)) { +		amdgpu_dm_connector->dm_dp_aux.aux.dev = connector->kdev; +		r = drm_dp_aux_register(&amdgpu_dm_connector->dm_dp_aux.aux); +		if (r) +			return r; +	} + +#if defined(CONFIG_DEBUG_FS)  	connector_debugfs_init(amdgpu_dm_connector);  #endif @@ -5332,6 +5331,7 @@ static int dm_plane_helper_prepare_fb(struct drm_plane *plane,  	uint64_t tiling_flags;  	uint32_t domain;  	int r; +	bool force_disable_dcc = false;  	dm_plane_state_old = to_dm_plane_state(plane->state);  	dm_plane_state_new = to_dm_plane_state(new_state); @@ -5390,11 +5390,13 @@ static int dm_plane_helper_prepare_fb(struct drm_plane *plane,  			dm_plane_state_old->dc_state != dm_plane_state_new->dc_state) {  		struct dc_plane_state *plane_state = dm_plane_state_new->dc_state; +		force_disable_dcc = adev->asic_type == CHIP_RAVEN && adev->in_suspend;  		fill_plane_buffer_attributes(  			adev, afb, plane_state->format, plane_state->rotation,  			tiling_flags, &plane_state->tiling_info,  			&plane_state->plane_size, &plane_state->dcc, -			&plane_state->address); +			&plane_state->address, +			force_disable_dcc);  	}  	return 0; @@ -6092,7 +6094,7 @@ static int amdgpu_dm_connector_init(struct amdgpu_display_manager *dm,  	if (connector_type == DRM_MODE_CONNECTOR_DisplayPort  		|| connector_type == DRM_MODE_CONNECTOR_eDP) -		amdgpu_dm_initialize_dp_connector(dm, aconnector); +		amdgpu_dm_initialize_dp_connector(dm, aconnector, link->link_index);  out_free:  	if (res) { @@ -6666,7 +6668,12 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,  		fill_dc_plane_info_and_addr(  			dm->adev, new_plane_state, tiling_flags,  			&bundle->plane_infos[planes_count], -			&bundle->flip_addrs[planes_count].address); +			&bundle->flip_addrs[planes_count].address, +			false); + +		DRM_DEBUG_DRIVER("plane: id=%d dcc_en=%d\n", +				 new_plane_state->plane->index, +				 bundle->plane_infos[planes_count].dcc.enable);  		bundle->surface_updates[planes_count].plane_info =  			&bundle->plane_infos[planes_count]; @@ -7848,6 +7855,7 @@ static int dm_update_plane_state(struct dc *dc,  	struct drm_crtc_state *old_crtc_state, *new_crtc_state;  	struct dm_crtc_state *dm_new_crtc_state, *dm_old_crtc_state;  	struct dm_plane_state *dm_new_plane_state, *dm_old_plane_state; +	struct amdgpu_crtc *new_acrtc;  	bool needs_reset;  	int ret = 0; @@ -7857,9 +7865,30 @@ static int dm_update_plane_state(struct dc *dc,  	dm_new_plane_state = to_dm_plane_state(new_plane_state);  	dm_old_plane_state = to_dm_plane_state(old_plane_state); -	/*TODO Implement atomic check for cursor plane */ -	if (plane->type == DRM_PLANE_TYPE_CURSOR) +	/*TODO Implement better atomic check for cursor plane */ +	if (plane->type == DRM_PLANE_TYPE_CURSOR) { +		if (!enable || !new_plane_crtc || +			drm_atomic_plane_disabling(plane->state, new_plane_state)) +			return 0; + +		new_acrtc = to_amdgpu_crtc(new_plane_crtc); + +		if ((new_plane_state->crtc_w > new_acrtc->max_cursor_width) || +			(new_plane_state->crtc_h > new_acrtc->max_cursor_height)) { +			DRM_DEBUG_ATOMIC("Bad cursor size %d x %d\n", +							 new_plane_state->crtc_w, new_plane_state->crtc_h); +			return -EINVAL; +		} + +		if (new_plane_state->crtc_x <= -new_acrtc->max_cursor_width || +			new_plane_state->crtc_y <= -new_acrtc->max_cursor_height) { +			DRM_DEBUG_ATOMIC("Bad cursor position %d, %d\n", +							 new_plane_state->crtc_x, new_plane_state->crtc_y); +			return -EINVAL; +		} +  		return 0; +	}  	needs_reset = should_reset_plane(state, plane, old_plane_state,  					 new_plane_state); @@ -8086,7 +8115,8 @@ dm_determine_update_type_for_commit(struct amdgpu_display_manager *dm,  				ret = fill_dc_plane_info_and_addr(  					dm->adev, new_plane_state, tiling_flags,  					plane_info, -					&flip_addr->address); +					&flip_addr->address, +					false);  				if (ret)  					goto cleanup; diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c index 78e1c11d4ae5..dcf84a61de37 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c @@ -398,15 +398,15 @@ static void update_config(void *handle, struct cp_psp_stream_config *config)  	struct mod_hdcp_display *display = &hdcp_work[link_index].display;  	struct mod_hdcp_link *link = &hdcp_work[link_index].link; -	memset(display, 0, sizeof(*display)); -	memset(link, 0, sizeof(*link)); - -	display->index = aconnector->base.index; -  	if (config->dpms_off) {  		hdcp_remove_display(hdcp_work, link_index, aconnector);  		return;  	} + +	memset(display, 0, sizeof(*display)); +	memset(link, 0, sizeof(*link)); + +	display->index = aconnector->base.index;  	display->state = MOD_HDCP_DISPLAY_ACTIVE;  	if (aconnector->dc_sink != NULL) 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 fabbe78d5aef..d2917759b7ab 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 @@ -156,16 +156,16 @@ amdgpu_dm_mst_connector_late_register(struct drm_connector *connector)  		to_amdgpu_dm_connector(connector);  	int r; -	amdgpu_dm_connector->dm_dp_aux.aux.dev = connector->kdev; -	r = drm_dp_aux_register(&amdgpu_dm_connector->dm_dp_aux.aux); -	if (r) +	r = drm_dp_mst_connector_late_register(connector, +					       amdgpu_dm_connector->port); +	if (r < 0)  		return r;  #if defined(CONFIG_DEBUG_FS)  	connector_debugfs_init(amdgpu_dm_connector);  #endif -	return r; +	return 0;  }  static void @@ -472,9 +472,12 @@ static const struct drm_dp_mst_topology_cbs dm_mst_cbs = {  };  void amdgpu_dm_initialize_dp_connector(struct amdgpu_display_manager *dm, -				       struct amdgpu_dm_connector *aconnector) +				       struct amdgpu_dm_connector *aconnector, +				       int link_index)  { -	aconnector->dm_dp_aux.aux.name = "dmdc"; +	aconnector->dm_dp_aux.aux.name = +		kasprintf(GFP_KERNEL, "AMDGPU DM aux hw bus %d", +			  link_index);  	aconnector->dm_dp_aux.aux.transfer = dm_dp_aux_transfer;  	aconnector->dm_dp_aux.ddc_service = aconnector->dc_link->ddc; 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 d6813ce67bbd..d2c56579a2cc 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 @@ -32,7 +32,8 @@ struct amdgpu_dm_connector;  int dm_mst_get_pbn_divider(struct dc_link *link);  void amdgpu_dm_initialize_dp_connector(struct amdgpu_display_manager *dm, -				       struct amdgpu_dm_connector *aconnector); +				       struct amdgpu_dm_connector *aconnector, +				       int link_index);  #if defined(CONFIG_DRM_AMD_DC_DCN)  bool compute_mst_dsc_configs_for_state(struct drm_atomic_state *state, diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index 8489f1e56892..47431ca6986d 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -834,11 +834,10 @@ static void disable_dangling_plane(struct dc *dc, struct dc_state *context)  static void wait_for_no_pipes_pending(struct dc *dc, struct dc_state *context)  {  	int i; -	int count = 0; -	struct pipe_ctx *pipe;  	PERF_TRACE();  	for (i = 0; i < MAX_PIPES; i++) { -		pipe = &context->res_ctx.pipe_ctx[i]; +		int count = 0; +		struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];  		if (!pipe->plane_state)  			continue; 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 7cbb1efb4f68..27a7d2a58079 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 @@ -2911,6 +2911,12 @@ bool dc_link_handle_hpd_rx_irq(struct dc_link *link, union hpd_irq_data *out_hpd  		for (i = 0; i < MAX_PIPES; i++) {  			pipe_ctx = &link->dc->current_state->res_ctx.pipe_ctx[i];  			if (pipe_ctx && pipe_ctx->stream && pipe_ctx->stream->link == link) +				link->dc->hwss.blank_stream(pipe_ctx); +		} + +		for (i = 0; i < MAX_PIPES; i++) { +			pipe_ctx = &link->dc->current_state->res_ctx.pipe_ctx[i]; +			if (pipe_ctx && pipe_ctx->stream && pipe_ctx->stream->link == link)  				break;  		} @@ -2927,6 +2933,12 @@ bool dc_link_handle_hpd_rx_irq(struct dc_link *link, union hpd_irq_data *out_hpd  		if (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST)  			dc_link_reallocate_mst_payload(link); +		for (i = 0; i < MAX_PIPES; i++) { +			pipe_ctx = &link->dc->current_state->res_ctx.pipe_ctx[i]; +			if (pipe_ctx && pipe_ctx->stream && pipe_ctx->stream->link == link) +				link->dc->hwss.unblank_stream(pipe_ctx, &previous_link_settings); +		} +  		status = false;  		if (out_link_loss)  			*out_link_loss = true; @@ -4227,6 +4239,21 @@ void dp_set_fec_enable(struct dc_link *link, bool enable)  void dpcd_set_source_specific_data(struct dc_link *link)  {  	const uint32_t post_oui_delay = 30; // 30ms +	uint8_t dspc = 0; +	enum dc_status ret = DC_ERROR_UNEXPECTED; + +	ret = core_link_read_dpcd(link, DP_DOWN_STREAM_PORT_COUNT, &dspc, +				  sizeof(dspc)); + +	if (ret != DC_OK) { +		DC_LOG_ERROR("Error in DP aux read transaction," +			     " not writing source specific data\n"); +		return; +	} + +	/* Return if OUI unsupported */ +	if (!(dspc & DP_OUI_SUPPORT)) +		return;  	if (!link->dc->vendor_signature.is_valid) {  		struct dpcd_amd_signature amd_signature; 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 6ddbb00ed37a..4f0e7203dba4 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c @@ -231,34 +231,6 @@ struct dc_stream_status *dc_stream_get_status(  	return dc_stream_get_status_from_state(dc->current_state, stream);  } -static void delay_cursor_until_vupdate(struct pipe_ctx *pipe_ctx, struct dc *dc) -{ -#if defined(CONFIG_DRM_AMD_DC_DCN) -	unsigned int vupdate_line; -	unsigned int lines_to_vupdate, us_to_vupdate, vpos, nvpos; -	struct dc_stream_state *stream = pipe_ctx->stream; -	unsigned int us_per_line; - -	if (stream->ctx->asic_id.chip_family == FAMILY_RV && -			ASICREV_IS_RAVEN(stream->ctx->asic_id.hw_internal_rev)) { - -		vupdate_line = dc->hwss.get_vupdate_offset_from_vsync(pipe_ctx); -		if (!dc_stream_get_crtc_position(dc, &stream, 1, &vpos, &nvpos)) -			return; - -		if (vpos >= vupdate_line) -			return; - -		us_per_line = stream->timing.h_total * 10000 / stream->timing.pix_clk_100hz; -		lines_to_vupdate = vupdate_line - vpos; -		us_to_vupdate = lines_to_vupdate * us_per_line; - -		/* 70 us is a conservative estimate of cursor update time*/ -		if (us_to_vupdate < 70) -			udelay(us_to_vupdate); -	} -#endif -}  /**   * dc_stream_set_cursor_attributes() - Update cursor attributes and set cursor surface address @@ -298,9 +270,7 @@ bool dc_stream_set_cursor_attributes(  		if (!pipe_to_program) {  			pipe_to_program = pipe_ctx; - -			delay_cursor_until_vupdate(pipe_ctx, dc); -			dc->hwss.pipe_control_lock(dc, pipe_to_program, true); +			dc->hwss.cursor_lock(dc, pipe_to_program, true);  		}  		dc->hwss.set_cursor_attribute(pipe_ctx); @@ -309,7 +279,7 @@ bool dc_stream_set_cursor_attributes(  	}  	if (pipe_to_program) -		dc->hwss.pipe_control_lock(dc, pipe_to_program, false); +		dc->hwss.cursor_lock(dc, pipe_to_program, false);  	return true;  } @@ -349,16 +319,14 @@ bool dc_stream_set_cursor_position(  		if (!pipe_to_program) {  			pipe_to_program = pipe_ctx; - -			delay_cursor_until_vupdate(pipe_ctx, dc); -			dc->hwss.pipe_control_lock(dc, pipe_to_program, true); +			dc->hwss.cursor_lock(dc, pipe_to_program, true);  		}  		dc->hwss.set_cursor_position(pipe_ctx);  	}  	if (pipe_to_program) -		dc->hwss.pipe_control_lock(dc, pipe_to_program, false); +		dc->hwss.cursor_lock(dc, pipe_to_program, false);  	return true;  } 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 c279982947e1..10527593868c 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 @@ -2757,6 +2757,7 @@ static const struct hw_sequencer_funcs dce110_funcs = {  	.disable_plane = dce110_power_down_fe,  	.pipe_control_lock = dce_pipe_control_lock,  	.interdependent_update_lock = NULL, +	.cursor_lock = dce_pipe_control_lock,  	.prepare_bandwidth = dce110_prepare_bandwidth,  	.optimize_bandwidth = dce110_optimize_bandwidth,  	.set_drr = set_drr, 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 b0357546471b..085c1a39b313 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 @@ -1625,6 +1625,16 @@ void dcn10_pipe_control_lock(  		hws->funcs.verify_allow_pstate_change_high(dc);  } +void dcn10_cursor_lock(struct dc *dc, struct pipe_ctx *pipe, bool lock) +{ +	/* cursor lock is per MPCC tree, so only need to lock one pipe per stream */ +	if (!pipe || pipe->top_pipe) +		return; + +	dc->res_pool->mpc->funcs->cursor_lock(dc->res_pool->mpc, +			pipe->stream_res.opp->inst, lock); +} +  static bool wait_for_reset_trigger_to_occur(  	struct dc_context *dc_ctx,  	struct timing_generator *tg) diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.h index 16a50e05ffbf..af51424315d5 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.h @@ -49,6 +49,7 @@ void dcn10_pipe_control_lock(  	struct dc *dc,  	struct pipe_ctx *pipe,  	bool lock); +void dcn10_cursor_lock(struct dc *dc, struct pipe_ctx *pipe, bool lock);  void dcn10_blank_pixel_data(  		struct dc *dc,  		struct pipe_ctx *pipe_ctx, diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_init.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_init.c index dd02d3983695..700509bdf503 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_init.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_init.c @@ -50,6 +50,7 @@ static const struct hw_sequencer_funcs dcn10_funcs = {  	.disable_audio_stream = dce110_disable_audio_stream,  	.disable_plane = dcn10_disable_plane,  	.pipe_control_lock = dcn10_pipe_control_lock, +	.cursor_lock = dcn10_cursor_lock,  	.interdependent_update_lock = dcn10_lock_all_pipes,  	.prepare_bandwidth = dcn10_prepare_bandwidth,  	.optimize_bandwidth = dcn10_optimize_bandwidth, diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_mpc.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_mpc.c index 04f863499cfb..3fcd408e9103 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_mpc.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_mpc.c @@ -223,6 +223,9 @@ struct mpcc *mpc1_insert_plane(  	REG_SET(MPCC_TOP_SEL[mpcc_id], 0, MPCC_TOP_SEL, dpp_id);  	REG_SET(MPCC_OPP_ID[mpcc_id], 0, MPCC_OPP_ID, tree->opp_id); +	/* Configure VUPDATE lock set for this MPCC to map to the OPP */ +	REG_SET(MPCC_UPDATE_LOCK_SEL[mpcc_id], 0, MPCC_UPDATE_LOCK_SEL, tree->opp_id); +  	/* update mpc tree mux setting */  	if (tree->opp_list == insert_above_mpcc) {  		/* insert the toppest mpcc */ @@ -318,6 +321,7 @@ void mpc1_remove_mpcc(  		REG_SET(MPCC_TOP_SEL[mpcc_id], 0, MPCC_TOP_SEL, 0xf);  		REG_SET(MPCC_BOT_SEL[mpcc_id], 0, MPCC_BOT_SEL, 0xf);  		REG_SET(MPCC_OPP_ID[mpcc_id],  0, MPCC_OPP_ID,  0xf); +		REG_SET(MPCC_UPDATE_LOCK_SEL[mpcc_id], 0, MPCC_UPDATE_LOCK_SEL, 0xf);  		/* mark this mpcc as not in use */  		mpc10->mpcc_in_use_mask &= ~(1 << mpcc_id); @@ -328,6 +332,7 @@ void mpc1_remove_mpcc(  		REG_SET(MPCC_TOP_SEL[mpcc_id], 0, MPCC_TOP_SEL, 0xf);  		REG_SET(MPCC_BOT_SEL[mpcc_id], 0, MPCC_BOT_SEL, 0xf);  		REG_SET(MPCC_OPP_ID[mpcc_id],  0, MPCC_OPP_ID,  0xf); +		REG_SET(MPCC_UPDATE_LOCK_SEL[mpcc_id], 0, MPCC_UPDATE_LOCK_SEL, 0xf);  	}  } @@ -361,6 +366,7 @@ void mpc1_mpc_init(struct mpc *mpc)  		REG_SET(MPCC_TOP_SEL[mpcc_id], 0, MPCC_TOP_SEL, 0xf);  		REG_SET(MPCC_BOT_SEL[mpcc_id], 0, MPCC_BOT_SEL, 0xf);  		REG_SET(MPCC_OPP_ID[mpcc_id],  0, MPCC_OPP_ID,  0xf); +		REG_SET(MPCC_UPDATE_LOCK_SEL[mpcc_id], 0, MPCC_UPDATE_LOCK_SEL, 0xf);  		mpc1_init_mpcc(&(mpc->mpcc_array[mpcc_id]), mpcc_id);  	} @@ -381,6 +387,7 @@ void mpc1_mpc_init_single_inst(struct mpc *mpc, unsigned int mpcc_id)  	REG_SET(MPCC_TOP_SEL[mpcc_id], 0, MPCC_TOP_SEL, 0xf);  	REG_SET(MPCC_BOT_SEL[mpcc_id], 0, MPCC_BOT_SEL, 0xf);  	REG_SET(MPCC_OPP_ID[mpcc_id],  0, MPCC_OPP_ID,  0xf); +	REG_SET(MPCC_UPDATE_LOCK_SEL[mpcc_id], 0, MPCC_UPDATE_LOCK_SEL, 0xf);  	mpc1_init_mpcc(&(mpc->mpcc_array[mpcc_id]), mpcc_id); @@ -453,6 +460,13 @@ void mpc1_read_mpcc_state(  			MPCC_BUSY, &s->busy);  } +void mpc1_cursor_lock(struct mpc *mpc, int opp_id, bool lock) +{ +	struct dcn10_mpc *mpc10 = TO_DCN10_MPC(mpc); + +	REG_SET(CUR[opp_id], 0, CUR_VUPDATE_LOCK_SET, lock ? 1 : 0); +} +  static const struct mpc_funcs dcn10_mpc_funcs = {  	.read_mpcc_state = mpc1_read_mpcc_state,  	.insert_plane = mpc1_insert_plane, @@ -464,6 +478,7 @@ static const struct mpc_funcs dcn10_mpc_funcs = {  	.assert_mpcc_idle_before_connect = mpc1_assert_mpcc_idle_before_connect,  	.init_mpcc_list_from_hw = mpc1_init_mpcc_list_from_hw,  	.update_blending = mpc1_update_blending, +	.cursor_lock = mpc1_cursor_lock,  	.set_denorm = NULL,  	.set_denorm_clamp = NULL,  	.set_output_csc = NULL, diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_mpc.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_mpc.h index 962a68e322ee..66a4719c22a0 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_mpc.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_mpc.h @@ -39,11 +39,12 @@  	SRII(MPCC_BG_G_Y, MPCC, inst),\  	SRII(MPCC_BG_R_CR, MPCC, inst),\  	SRII(MPCC_BG_B_CB, MPCC, inst),\ -	SRII(MPCC_BG_B_CB, MPCC, inst),\ -	SRII(MPCC_SM_CONTROL, MPCC, inst) +	SRII(MPCC_SM_CONTROL, MPCC, inst),\ +	SRII(MPCC_UPDATE_LOCK_SEL, MPCC, inst)  #define MPC_OUT_MUX_COMMON_REG_LIST_DCN1_0(inst) \ -	SRII(MUX, MPC_OUT, inst) +	SRII(MUX, MPC_OUT, inst),\ +	VUPDATE_SRII(CUR, VUPDATE_LOCK_SET, inst)  #define MPC_COMMON_REG_VARIABLE_LIST \  	uint32_t MPCC_TOP_SEL[MAX_MPCC]; \ @@ -55,7 +56,9 @@  	uint32_t MPCC_BG_R_CR[MAX_MPCC]; \  	uint32_t MPCC_BG_B_CB[MAX_MPCC]; \  	uint32_t MPCC_SM_CONTROL[MAX_MPCC]; \ -	uint32_t MUX[MAX_OPP]; +	uint32_t MUX[MAX_OPP]; \ +	uint32_t MPCC_UPDATE_LOCK_SEL[MAX_MPCC]; \ +	uint32_t CUR[MAX_OPP];  #define MPC_COMMON_MASK_SH_LIST_DCN1_0(mask_sh)\  	SF(MPCC0_MPCC_TOP_SEL, MPCC_TOP_SEL, mask_sh),\ @@ -78,7 +81,8 @@  	SF(MPCC0_MPCC_SM_CONTROL, MPCC_SM_FIELD_ALT, mask_sh),\  	SF(MPCC0_MPCC_SM_CONTROL, MPCC_SM_FORCE_NEXT_FRAME_POL, mask_sh),\  	SF(MPCC0_MPCC_SM_CONTROL, MPCC_SM_FORCE_NEXT_TOP_POL, mask_sh),\ -	SF(MPC_OUT0_MUX, MPC_OUT_MUX, mask_sh) +	SF(MPC_OUT0_MUX, MPC_OUT_MUX, mask_sh),\ +	SF(MPCC0_MPCC_UPDATE_LOCK_SEL, MPCC_UPDATE_LOCK_SEL, mask_sh)  #define MPC_REG_FIELD_LIST(type) \  	type MPCC_TOP_SEL;\ @@ -101,7 +105,9 @@  	type MPCC_SM_FIELD_ALT;\  	type MPCC_SM_FORCE_NEXT_FRAME_POL;\  	type MPCC_SM_FORCE_NEXT_TOP_POL;\ -	type MPC_OUT_MUX; +	type MPC_OUT_MUX;\ +	type MPCC_UPDATE_LOCK_SEL;\ +	type CUR_VUPDATE_LOCK_SET;  struct dcn_mpc_registers {  	MPC_COMMON_REG_VARIABLE_LIST @@ -192,4 +198,6 @@ void mpc1_read_mpcc_state(  		int mpcc_inst,  		struct mpcc_state *s); +void mpc1_cursor_lock(struct mpc *mpc, int opp_id, bool lock); +  #endif diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c index 07265ca7d28c..ba849aa31e6e 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c @@ -181,6 +181,14 @@ enum dcn10_clk_src_array_id {  	.reg_name[id] = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \  					mm ## block ## id ## _ ## reg_name +#define VUPDATE_SRII(reg_name, block, id)\ +	.reg_name[id] = BASE(mm ## reg_name ## 0 ## _ ## block ## id ## _BASE_IDX) + \ +					mm ## reg_name ## 0 ## _ ## block ## id + +/* set field/register/bitfield name */ +#define SFRB(field_name, reg_name, bitfield, post_fix)\ +	.field_name = reg_name ## __ ## bitfield ## post_fix +  /* NBIO */  #define NBIO_BASE_INNER(seg) \  	NBIF_BASE__INST0_SEG ## seg @@ -419,11 +427,13 @@ static const struct dcn_mpc_registers mpc_regs = {  };  static const struct dcn_mpc_shift mpc_shift = { -	MPC_COMMON_MASK_SH_LIST_DCN1_0(__SHIFT) +	MPC_COMMON_MASK_SH_LIST_DCN1_0(__SHIFT),\ +	SFRB(CUR_VUPDATE_LOCK_SET, CUR0_VUPDATE_LOCK_SET0, CUR0_VUPDATE_LOCK_SET, __SHIFT)  };  static const struct dcn_mpc_mask mpc_mask = { -	MPC_COMMON_MASK_SH_LIST_DCN1_0(_MASK), +	MPC_COMMON_MASK_SH_LIST_DCN1_0(_MASK),\ +	SFRB(CUR_VUPDATE_LOCK_SET, CUR0_VUPDATE_LOCK_SET0, CUR0_VUPDATE_LOCK_SET, _MASK)  };  #define tg_regs(id)\ diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c index 22f421e82733..a023a4d59f41 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c @@ -2294,7 +2294,8 @@ void dcn20_fpga_init_hw(struct dc *dc)  	REG_UPDATE(DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_REFDIV, 2);  	REG_UPDATE(DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_ENABLE, 1); -	REG_WRITE(REFCLK_CNTL, 0); +	if (REG(REFCLK_CNTL)) +		REG_WRITE(REFCLK_CNTL, 0);  	// diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_init.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_init.c index 1e73357eda34..6a21228893ee 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_init.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_init.c @@ -52,6 +52,7 @@ static const struct hw_sequencer_funcs dcn20_funcs = {  	.disable_plane = dcn20_disable_plane,  	.pipe_control_lock = dcn20_pipe_control_lock,  	.interdependent_update_lock = dcn10_lock_all_pipes, +	.cursor_lock = dcn10_cursor_lock,  	.prepare_bandwidth = dcn20_prepare_bandwidth,  	.optimize_bandwidth = dcn20_optimize_bandwidth,  	.update_bandwidth = dcn20_update_bandwidth, diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_mpc.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_mpc.c index de9c857ab3e9..570dfd9a243f 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_mpc.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_mpc.c @@ -545,6 +545,7 @@ const struct mpc_funcs dcn20_mpc_funcs = {  	.mpc_init = mpc1_mpc_init,  	.mpc_init_single_inst = mpc1_mpc_init_single_inst,  	.update_blending = mpc2_update_blending, +	.cursor_lock = mpc1_cursor_lock,  	.get_mpcc_for_dpp = mpc2_get_mpcc_for_dpp,  	.wait_for_idle = mpc2_assert_idle_mpcc,  	.assert_mpcc_idle_before_connect = mpc2_assert_mpcc_idle_before_connect, diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_mpc.h b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_mpc.h index c78fd5123497..496658f420db 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_mpc.h +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_mpc.h @@ -179,7 +179,8 @@  	SF(MPC_OUT0_DENORM_CLAMP_G_Y, MPC_OUT_DENORM_CLAMP_MAX_G_Y, mask_sh),\  	SF(MPC_OUT0_DENORM_CLAMP_G_Y, MPC_OUT_DENORM_CLAMP_MIN_G_Y, mask_sh),\  	SF(MPC_OUT0_DENORM_CLAMP_B_CB, MPC_OUT_DENORM_CLAMP_MAX_B_CB, mask_sh),\ -	SF(MPC_OUT0_DENORM_CLAMP_B_CB, MPC_OUT_DENORM_CLAMP_MIN_B_CB, mask_sh) +	SF(MPC_OUT0_DENORM_CLAMP_B_CB, MPC_OUT_DENORM_CLAMP_MIN_B_CB, mask_sh),\ +	SF(CUR_VUPDATE_LOCK_SET0, CUR_VUPDATE_LOCK_SET, mask_sh)  /*   *	DCN2 MPC_OCSC debug status register: diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c index 5cdbba0cd873..e4348e3b6389 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c @@ -508,6 +508,10 @@ enum dcn20_clk_src_array_id {  	.block ## _ ## reg_name[id] = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \  					mm ## block ## id ## _ ## reg_name +#define VUPDATE_SRII(reg_name, block, id)\ +	.reg_name[id] = BASE(mm ## reg_name ## _ ## block ## id ## _BASE_IDX) + \ +					mm ## reg_name ## _ ## block ## id +  /* NBIO */  #define NBIO_BASE_INNER(seg) \  	NBIO_BASE__INST0_SEG ## seg @@ -3064,25 +3068,32 @@ validate_out:  	return out;  } - -bool dcn20_validate_bandwidth(struct dc *dc, struct dc_state *context, -		bool fast_validate) +/* + * This must be noinline to ensure anything that deals with FP registers + * is contained within this call; previously our compiling with hard-float + * would result in fp instructions being emitted outside of the boundaries + * of the DC_FP_START/END macros, which makes sense as the compiler has no + * idea about what is wrapped and what is not + * + * This is largely just a workaround to avoid breakage introduced with 5.6, + * ideally all fp-using code should be moved into its own file, only that + * should be compiled with hard-float, and all code exported from there + * should be strictly wrapped with DC_FP_START/END + */ +static noinline bool dcn20_validate_bandwidth_fp(struct dc *dc, +		struct dc_state *context, bool fast_validate)  {  	bool voltage_supported = false;  	bool full_pstate_supported = false;  	bool dummy_pstate_supported = false;  	double p_state_latency_us; -	DC_FP_START();  	p_state_latency_us = context->bw_ctx.dml.soc.dram_clock_change_latency_us;  	context->bw_ctx.dml.soc.disable_dram_clock_change_vactive_support =  		dc->debug.disable_dram_clock_change_vactive_support;  	if (fast_validate) { -		voltage_supported = dcn20_validate_bandwidth_internal(dc, context, true); - -		DC_FP_END(); -		return voltage_supported; +		return dcn20_validate_bandwidth_internal(dc, context, true);  	}  	// Best case, we support full UCLK switch latency @@ -3111,7 +3122,15 @@ bool dcn20_validate_bandwidth(struct dc *dc, struct dc_state *context,  restore_dml_state:  	context->bw_ctx.dml.soc.dram_clock_change_latency_us = p_state_latency_us; +	return voltage_supported; +} +bool dcn20_validate_bandwidth(struct dc *dc, struct dc_state *context, +		bool fast_validate) +{ +	bool voltage_supported = false; +	DC_FP_START(); +	voltage_supported = dcn20_validate_bandwidth_fp(dc, context, fast_validate);  	DC_FP_END();  	return voltage_supported;  } diff --git a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_init.c b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_init.c index b9ff9767e08f..707ce0f28fab 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_init.c +++ b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_init.c @@ -53,6 +53,7 @@ static const struct hw_sequencer_funcs dcn21_funcs = {  	.disable_plane = dcn20_disable_plane,  	.pipe_control_lock = dcn20_pipe_control_lock,  	.interdependent_update_lock = dcn10_lock_all_pipes, +	.cursor_lock = dcn10_cursor_lock,  	.prepare_bandwidth = dcn20_prepare_bandwidth,  	.optimize_bandwidth = dcn20_optimize_bandwidth,  	.update_bandwidth = dcn20_update_bandwidth, diff --git a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c index b25484aa8222..a721bb401ef0 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c @@ -284,7 +284,7 @@ struct _vcs_dpi_soc_bounding_box_st dcn2_1_soc = {  	.dram_channel_width_bytes = 4,  	.fabric_datapath_to_dcn_data_return_bytes = 32,  	.dcn_downspread_percent = 0.5, -	.downspread_percent = 0.5, +	.downspread_percent = 0.38,  	.dram_page_open_time_ns = 50.0,  	.dram_rw_turnaround_time_ns = 17.5,  	.dram_return_buffer_per_channel_bytes = 8192, @@ -340,6 +340,10 @@ struct _vcs_dpi_soc_bounding_box_st dcn2_1_soc = {  	.block ## _ ## reg_name[id] = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \  					mm ## block ## id ## _ ## reg_name +#define VUPDATE_SRII(reg_name, block, id)\ +	.reg_name[id] = BASE(mm ## reg_name ## _ ## block ## id ## _BASE_IDX) + \ +					mm ## reg_name ## _ ## block ## id +  /* NBIO */  #define NBIO_BASE_INNER(seg) \  	NBIF0_BASE__INST0_SEG ## seg @@ -1374,64 +1378,49 @@ static void update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_param  {  	struct dcn21_resource_pool *pool = TO_DCN21_RES_POOL(dc->res_pool);  	struct clk_limit_table *clk_table = &bw_params->clk_table; -	unsigned int i, j, k; -	int closest_clk_lvl; +	struct _vcs_dpi_voltage_scaling_st clock_limits[DC__VOLTAGE_STATES]; +	unsigned int i, j, closest_clk_lvl;  	// Default clock levels are used for diags, which may lead to overclocking. -	if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment) && !IS_DIAG_DC(dc->ctx->dce_environment)) { +	if (!IS_DIAG_DC(dc->ctx->dce_environment)) {  		dcn2_1_ip.max_num_otg = pool->base.res_cap->num_timing_generator;  		dcn2_1_ip.max_num_dpp = pool->base.pipe_count;  		dcn2_1_soc.num_chans = bw_params->num_channels; -		/* Vmin: leave lowest DCN clocks, override with dcfclk, fclk, memclk from fuse */ -		dcn2_1_soc.clock_limits[0].state = 0; -		dcn2_1_soc.clock_limits[0].dcfclk_mhz = clk_table->entries[0].dcfclk_mhz; -		dcn2_1_soc.clock_limits[0].fabricclk_mhz = clk_table->entries[0].fclk_mhz; -		dcn2_1_soc.clock_limits[0].socclk_mhz = clk_table->entries[0].socclk_mhz; -		dcn2_1_soc.clock_limits[0].dram_speed_mts = clk_table->entries[0].memclk_mhz * 2; - -		/* -		 * Other levels: find closest DCN clocks that fit the given clock limit using dcfclk -		 * as indicator -		 */ - -		closest_clk_lvl = -1; -		/* index currently being filled */ -		k = 1; -		for (i = 1; i < clk_table->num_entries; i++) { -			/* loop backwards, skip duplicate state*/ -			for (j = dcn2_1_soc.num_states - 1; j >= k; j--) { +		ASSERT(clk_table->num_entries); +		for (i = 0; i < clk_table->num_entries; i++) { +			/* loop backwards*/ +			for (closest_clk_lvl = 0, j = dcn2_1_soc.num_states - 1; j >= 0; j--) {  				if ((unsigned int) dcn2_1_soc.clock_limits[j].dcfclk_mhz <= clk_table->entries[i].dcfclk_mhz) {  					closest_clk_lvl = j;  					break;  				}  			} -			/* if found a lvl that fits, use the DCN clks from it, if not, go to next clk limit*/ -			if (closest_clk_lvl != -1) { -				dcn2_1_soc.clock_limits[k].state = i; -				dcn2_1_soc.clock_limits[k].dcfclk_mhz = clk_table->entries[i].dcfclk_mhz; -				dcn2_1_soc.clock_limits[k].fabricclk_mhz = clk_table->entries[i].fclk_mhz; -				dcn2_1_soc.clock_limits[k].socclk_mhz = clk_table->entries[i].socclk_mhz; -				dcn2_1_soc.clock_limits[k].dram_speed_mts = clk_table->entries[i].memclk_mhz * 2; - -				dcn2_1_soc.clock_limits[k].dispclk_mhz = dcn2_1_soc.clock_limits[closest_clk_lvl].dispclk_mhz; -				dcn2_1_soc.clock_limits[k].dppclk_mhz = dcn2_1_soc.clock_limits[closest_clk_lvl].dppclk_mhz; -				dcn2_1_soc.clock_limits[k].dram_bw_per_chan_gbps = dcn2_1_soc.clock_limits[closest_clk_lvl].dram_bw_per_chan_gbps; -				dcn2_1_soc.clock_limits[k].dscclk_mhz = dcn2_1_soc.clock_limits[closest_clk_lvl].dscclk_mhz; -				dcn2_1_soc.clock_limits[k].dtbclk_mhz = dcn2_1_soc.clock_limits[closest_clk_lvl].dtbclk_mhz; -				dcn2_1_soc.clock_limits[k].phyclk_d18_mhz = dcn2_1_soc.clock_limits[closest_clk_lvl].phyclk_d18_mhz; -				dcn2_1_soc.clock_limits[k].phyclk_mhz = dcn2_1_soc.clock_limits[closest_clk_lvl].phyclk_mhz; -				k++; -			} +			clock_limits[i].state = i; +			clock_limits[i].dcfclk_mhz = clk_table->entries[i].dcfclk_mhz; +			clock_limits[i].fabricclk_mhz = clk_table->entries[i].fclk_mhz; +			clock_limits[i].socclk_mhz = clk_table->entries[i].socclk_mhz; +			clock_limits[i].dram_speed_mts = clk_table->entries[i].memclk_mhz * 2; + +			clock_limits[i].dispclk_mhz = dcn2_1_soc.clock_limits[closest_clk_lvl].dispclk_mhz; +			clock_limits[i].dppclk_mhz = dcn2_1_soc.clock_limits[closest_clk_lvl].dppclk_mhz; +			clock_limits[i].dram_bw_per_chan_gbps = dcn2_1_soc.clock_limits[closest_clk_lvl].dram_bw_per_chan_gbps; +			clock_limits[i].dscclk_mhz = dcn2_1_soc.clock_limits[closest_clk_lvl].dscclk_mhz; +			clock_limits[i].dtbclk_mhz = dcn2_1_soc.clock_limits[closest_clk_lvl].dtbclk_mhz; +			clock_limits[i].phyclk_d18_mhz = dcn2_1_soc.clock_limits[closest_clk_lvl].phyclk_d18_mhz; +			clock_limits[i].phyclk_mhz = dcn2_1_soc.clock_limits[closest_clk_lvl].phyclk_mhz; +		} +		for (i = 0; i < clk_table->num_entries; i++) +			dcn2_1_soc.clock_limits[i] = clock_limits[i]; +		if (clk_table->num_entries) { +			dcn2_1_soc.num_states = clk_table->num_entries; +			/* duplicate last level */ +			dcn2_1_soc.clock_limits[dcn2_1_soc.num_states] = dcn2_1_soc.clock_limits[dcn2_1_soc.num_states - 1]; +			dcn2_1_soc.clock_limits[dcn2_1_soc.num_states].state = dcn2_1_soc.num_states;  		} -		dcn2_1_soc.num_states = k;  	} -	/* duplicate last level */ -	dcn2_1_soc.clock_limits[dcn2_1_soc.num_states] = dcn2_1_soc.clock_limits[dcn2_1_soc.num_states - 1]; -	dcn2_1_soc.clock_limits[dcn2_1_soc.num_states].state = dcn2_1_soc.num_states; -  	dml_init_instance(&dc->dml, &dcn2_1_soc, &dcn2_1_ip, DML_PROJECT_DCN21);  } diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn21/display_rq_dlg_calc_21.c b/drivers/gpu/drm/amd/display/dc/dml/dcn21/display_rq_dlg_calc_21.c index a38baa73d484..b8ec08e3b7a3 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn21/display_rq_dlg_calc_21.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn21/display_rq_dlg_calc_21.c @@ -1200,7 +1200,7 @@ static void dml_rq_dlg_get_dlg_params(  	min_hratio_fact_l = 1.0;  	min_hratio_fact_c = 1.0; -	if (htaps_l <= 1) +	if (hratio_l <= 1)  		min_hratio_fact_l = 2.0;  	else if (htaps_l <= 6) {  		if ((hratio_l * 2.0) > 4.0) @@ -1216,7 +1216,7 @@ static void dml_rq_dlg_get_dlg_params(  	hscale_pixel_rate_l = min_hratio_fact_l * dppclk_freq_in_mhz; -	if (htaps_c <= 1) +	if (hratio_c <= 1)  		min_hratio_fact_c = 2.0;  	else if (htaps_c <= 6) {  		if ((hratio_c * 2.0) > 4.0) @@ -1522,8 +1522,8 @@ static void dml_rq_dlg_get_dlg_params(  	disp_dlg_regs->refcyc_per_vm_group_vblank   = get_refcyc_per_vm_group_vblank(mode_lib, e2e_pipe_param, num_pipes, pipe_idx) * refclk_freq_in_mhz;  	disp_dlg_regs->refcyc_per_vm_group_flip     = get_refcyc_per_vm_group_flip(mode_lib, e2e_pipe_param, num_pipes, pipe_idx) * refclk_freq_in_mhz; -	disp_dlg_regs->refcyc_per_vm_req_vblank     = get_refcyc_per_vm_req_vblank(mode_lib, e2e_pipe_param, num_pipes, pipe_idx) * refclk_freq_in_mhz; -	disp_dlg_regs->refcyc_per_vm_req_flip       = get_refcyc_per_vm_req_flip(mode_lib, e2e_pipe_param, num_pipes, pipe_idx) * refclk_freq_in_mhz; +	disp_dlg_regs->refcyc_per_vm_req_vblank     = get_refcyc_per_vm_req_vblank(mode_lib, e2e_pipe_param, num_pipes, pipe_idx) * refclk_freq_in_mhz * dml_pow(2, 10); +	disp_dlg_regs->refcyc_per_vm_req_flip       = get_refcyc_per_vm_req_flip(mode_lib, e2e_pipe_param, num_pipes, pipe_idx) * refclk_freq_in_mhz * dml_pow(2, 10);  	// Clamp to max for now  	if (disp_dlg_regs->refcyc_per_vm_group_vblank >= (unsigned int)dml_pow(2, 23)) diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/mpc.h b/drivers/gpu/drm/amd/display/dc/inc/hw/mpc.h index 094afc4c8173..50ee8aa7ec3b 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/mpc.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/mpc.h @@ -210,6 +210,22 @@ struct mpc_funcs {  		struct mpcc_blnd_cfg *blnd_cfg,  		int mpcc_id); +	/* +	 * Lock cursor updates for the specified OPP. +	 * OPP defines the set of MPCC that are locked together for cursor. +	 * +	 * Parameters: +	 * [in] 	mpc		- MPC context. +	 * [in]     opp_id	- The OPP to lock cursor updates on +	 * [in]		lock	- lock/unlock the OPP +	 * +	 * Return:  void +	 */ +	void (*cursor_lock)( +			struct mpc *mpc, +			int opp_id, +			bool lock); +  	struct mpcc* (*get_mpcc_for_dpp)(  			struct mpc_tree *tree,  			int dpp_id); 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 d4c1fb242c63..e57467d99d66 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h @@ -86,6 +86,7 @@ struct hw_sequencer_funcs {  			struct dc_state *context, bool lock);  	void (*set_flip_control_gsl)(struct pipe_ctx *pipe_ctx,  			bool flip_immediate); +	void (*cursor_lock)(struct dc *dc, struct pipe_ctx *pipe, bool lock);  	/* Timing Related */  	void (*get_position)(struct pipe_ctx **pipe_ctx, int num_pipes, diff --git a/drivers/gpu/drm/amd/display/dc/os_types.h b/drivers/gpu/drm/amd/display/dc/os_types.h index c34eba19860a..6d7bca562eec 100644 --- a/drivers/gpu/drm/amd/display/dc/os_types.h +++ b/drivers/gpu/drm/amd/display/dc/os_types.h @@ -108,7 +108,7 @@  #define ASSERT(expr) ASSERT_CRITICAL(expr)  #else -#define ASSERT(expr) WARN_ON(!(expr)) +#define ASSERT(expr) WARN_ON_ONCE(!(expr))  #endif  #define BREAK_TO_DEBUGGER() ASSERT(0) |