[PATCH v1 13/14] drm/msm/disp/dpu1: add dsc supporting functions to dpu encoder

Neil Armstrong neil.armstrong at linaro.org
Wed Jan 25 09:01:07 UTC 2023


On 23/01/2023 19:24, Kuogee Hsieh wrote:
> Since display Port is an external peripheral, runtime compression
> detection is added to handle plug in and unplugged events. Currently
> only DSC compression supported. Once DSC compression detected, topology
> is static added and used to allocate system resources to accommodate
> DSC requirement. DSC related parameters are calculated and committed to
> DSC encoder. Also compression information are propagated to phy and
> committed to timing engine at video mode. This patch completes DSC
> implementation.
> 
> Signed-off-by: Kuogee Hsieh <quic_khsieh at quicinc.com>
> ---
>   drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c        | 314 ++++++++++++++++-----
>   drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h   |   5 +-
>   .../gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c   |  34 ++-
>   drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.h    |   3 +
>   drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c             |  10 +-
>   5 files changed, 292 insertions(+), 74 deletions(-)
> 
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
> index d2625b3..d7f5f93 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
> @@ -15,6 +15,7 @@
>   #include <drm/drm_crtc.h>
>   #include <drm/drm_file.h>
>   #include <drm/drm_probe_helper.h>
> +#include <drm/drm_bridge.h>
>   
>   #include "msm_drv.h"
>   #include "dpu_kms.h"
> @@ -30,6 +31,7 @@
>   #include "dpu_crtc.h"
>   #include "dpu_trace.h"
>   #include "dpu_core_irq.h"
> +#include "dpu_dsc_helper.h"
>   #include "disp/msm_disp_snapshot.h"
>   
>   #define DPU_DEBUG_ENC(e, fmt, ...) DRM_DEBUG_ATOMIC("enc%d " fmt,\
> @@ -542,12 +544,12 @@ bool dpu_encoder_use_dsc_merge(struct drm_encoder *drm_enc)
>   	return (num_dsc > 0) && (num_dsc > intf_count);
>   }
>   
> -static struct msm_display_topology dpu_encoder_get_topology(
> +static void dpu_encoder_get_topology(
>   			struct dpu_encoder_virt *dpu_enc,
>   			struct dpu_kms *dpu_kms,
> -			struct drm_display_mode *mode)
> +			struct drm_display_mode *mode,
> +			struct msm_display_topology *topology)
>   {
> -	struct msm_display_topology topology = {0};
>   	int i, intf_count = 0;
>   
>   	for (i = 0; i < MAX_PHYS_ENCODERS_PER_VIRTUAL; i++)
> @@ -567,19 +569,19 @@ static struct msm_display_topology dpu_encoder_get_topology(
>   	 * sufficient number
>   	 */
>   	if (intf_count == 2)
> -		topology.num_lm = 2;
> +		topology->num_lm = 2;
>   	else if (!dpu_kms->catalog->caps->has_3d_merge)
> -		topology.num_lm = 1;
> +		topology->num_lm = 1;
>   	else
> -		topology.num_lm = (mode->hdisplay > MAX_HDISPLAY_SPLIT) ? 2 : 1;
> +		topology->num_lm = (mode->hdisplay > MAX_HDISPLAY_SPLIT) ? 2 : 1;
>   
>   	if (dpu_enc->disp_info.intf_type == DRM_MODE_ENCODER_DSI) {
>   		if (dpu_kms->catalog->dspp &&
> -			(dpu_kms->catalog->dspp_count >= topology.num_lm))
> -			topology.num_dspp = topology.num_lm;
> +			(dpu_kms->catalog->dspp_count >= topology->num_lm))
> +			topology->num_dspp = topology->num_lm;
>   	}
>   
> -	topology.num_intf = intf_count;
> +	topology->num_intf = intf_count;
>   
>   	if (dpu_enc->dsc) {
>   		/*
> @@ -588,12 +590,31 @@ static struct msm_display_topology dpu_encoder_get_topology(
>   		 * this is power optimal and can drive up to (including) 4k
>   		 * screens
>   		 */
> -		topology.num_dsc = 2;
> -		topology.num_lm = 2;
> -		topology.num_intf = 1;
> +		topology->num_dsc = 2;
> +		topology->num_intf = 1;
> +		topology->num_lm = 2;
>   	}
>   
> -	return topology;
> +	/*
> +	 * default topology for display port DSC implementation.
> +	 * TODO:
> +	 *	change to runtime resource calculation
> +	 */
> +	if (dpu_enc->disp_info.intf_type == DRM_MODE_ENCODER_TMDS) {
> +		topology->num_dsc = 0;
> +		topology->num_intf = intf_count;
> +
> +		if (dpu_enc->comp_info) {
> +			/* In case of Display Stream Compression (DSC), we would use
> +			 * 2 encoders, 2 layer mixers and 1 interface
> +			 * this is power optimal and can drive up to (including) 4k
> +			 * screens
> +			 */
> +			topology->num_dsc = 1;
> +			topology->num_intf = 1;
> +			topology->num_lm = 1;
> +		}
> +	}
>   }
>   
>   static int dpu_encoder_virt_atomic_check(
> @@ -605,7 +626,7 @@ static int dpu_encoder_virt_atomic_check(
>   	struct msm_drm_private *priv;
>   	struct dpu_kms *dpu_kms;
>   	struct drm_display_mode *adj_mode;
> -	struct msm_display_topology topology;
> +	struct msm_display_topology *topology;
>   	struct dpu_global_state *global_state;
>   	int i = 0;
>   	int ret = 0;
> @@ -642,7 +663,27 @@ static int dpu_encoder_virt_atomic_check(
>   		}
>   	}
>   
> -	topology = dpu_encoder_get_topology(dpu_enc, dpu_kms, adj_mode);
> +	/*
> +	 * For display port, at this moment we know panel had been plugged in
> +	 * and dsc supported is detected.
> +	 * however we do not know the details of resolution will be used
> +	 * until mode_set had been done.
> +	 *
> +	 * use default topology to reserve system resource for dsc
> +	 *
> +	 * TODO: run time calculation of topology instead of hardcode it now
> +	 */
> +	if (dpu_enc->disp_info.intf_type == DRM_MODE_ENCODER_TMDS) {
> +		struct drm_bridge *bridge;
> +
> +		if (!dpu_enc->comp_info) {
> +			bridge = drm_bridge_chain_get_first_bridge(drm_enc);
> +			dpu_enc->comp_info = msm_dp_bridge_get_compression(bridge);
> +		}
> +	}
> +
> +	topology = &dpu_enc->topology;
> +	dpu_encoder_get_topology(dpu_enc, dpu_kms, adj_mode, topology);
>   
>   	/* Reserve dynamic resources now. */
>   	if (!ret) {
> @@ -655,7 +696,7 @@ static int dpu_encoder_virt_atomic_check(
>   
>   			if (!crtc_state->active_changed || crtc_state->active)
>   				ret = dpu_rm_reserve(&dpu_kms->rm, global_state,
> -						drm_enc, crtc_state, topology);
> +						drm_enc, crtc_state, *topology);
>   		}
>   	}
>   
> @@ -1009,7 +1050,37 @@ void dpu_encoder_cleanup_wb_job(struct drm_encoder *drm_enc,
>   
>   		if (phys->ops.cleanup_wb_job)
>   			phys->ops.cleanup_wb_job(phys, job);
> +	}
> +}
> +
> +static void dpu_encoder_populate_encoder_phys(struct drm_encoder *drm_enc,
> +					struct dpu_encoder_virt *dpu_enc)
> +{
> +	struct msm_compression_info *comp_info;
> +	struct msm_display_dsc_info *dsc_info;
> +	int i;
> +
> +	if (!dpu_enc->comp_info)
> +		return;
> +
> +	comp_info = dpu_enc->comp_info;
> +	dsc_info = &comp_info->msm_dsc_info;
> +
> +	for (i = 0; i < dpu_enc->num_phys_encs; i++) {
> +		struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i];
> +
> +		if (!phys)
> +			continue;
> +
> +		phys->comp_type = comp_info->comp_type;
> +		phys->comp_ratio = comp_info->comp_ratio;
>   
> +		if (phys->comp_type == MSM_DISPLAY_COMPRESSION_DSC) {
> +			phys->dsc_extra_pclk_cycle_cnt = dsc_info->pclk_per_line;
> +			phys->dsc_extra_disp_width = dsc_info->extra_width;
> +			phys->dce_bytes_per_line =
> +				dsc_info->bytes_per_pkt * dsc_info->pkt_per_line;
> +		}
>   	}
>   }
>   
> @@ -1050,6 +1121,24 @@ static void dpu_encoder_virt_atomic_mode_set(struct drm_encoder *drm_enc,
>   
>   	trace_dpu_enc_mode_set(DRMID(drm_enc));
>   
> +	/*
> +	 * For display port, msm_dp_bridge_mode_set() will conver panel info
> +	 * into dp_mode. This including detail dsc information if it is enabled.
> +	 * after that, msm_dp_bridge_get_compression() will return detail
> +	 * dsc compression info
> +	 */
> +	if (dpu_enc->disp_info.intf_type == DRM_MODE_ENCODER_TMDS) {
> +		struct drm_display_mode *mode, *adjusted_mode;
> +		struct drm_bridge *bridge;
> +
> +		mode = &crtc_state->mode;
> +		adjusted_mode = &crtc_state->adjusted_mode;
> +		bridge = drm_bridge_chain_get_first_bridge(drm_enc);
> +		msm_dp_bridge_mode_set(bridge, mode, adjusted_mode);
> +
> +		dpu_enc->comp_info = msm_dp_bridge_get_compression(bridge);
> +	}
> +
>   	/* Query resource that have been reserved in atomic check step. */
>   	num_pp = dpu_rm_get_assigned_resources(&dpu_kms->rm, global_state,
>   		drm_enc->base.id, DPU_HW_BLK_PINGPONG, hw_pp,
> @@ -1061,19 +1150,18 @@ static void dpu_encoder_virt_atomic_mode_set(struct drm_encoder *drm_enc,
>   	dpu_rm_get_assigned_resources(&dpu_kms->rm, global_state,
>   		drm_enc->base.id, DPU_HW_BLK_DSPP, hw_dspp,
>   		ARRAY_SIZE(hw_dspp));
> +	num_dsc = dpu_rm_get_assigned_resources(&dpu_kms->rm, global_state,
> +		drm_enc->base.id, DPU_HW_BLK_DSC,
> +		hw_dsc, ARRAY_SIZE(hw_dsc));
>   
>   	for (i = 0; i < MAX_CHANNELS_PER_ENC; i++)
>   		dpu_enc->hw_pp[i] = i < num_pp ? to_dpu_hw_pingpong(hw_pp[i])
>   						: NULL;
>   
> -	if (dpu_enc->dsc) {
> -		num_dsc = dpu_rm_get_assigned_resources(&dpu_kms->rm, global_state,
> -							drm_enc->base.id, DPU_HW_BLK_DSC,
> -							hw_dsc, ARRAY_SIZE(hw_dsc));
> -		for (i = 0; i < num_dsc; i++) {
> -			dpu_enc->hw_dsc[i] = to_dpu_hw_dsc(hw_dsc[i]);
> -			dsc_mask |= BIT(dpu_enc->hw_dsc[i]->idx - DSC_0);
> -		}
> +	for (i = 0; i < num_dsc; i++) {
> +		dpu_enc->hw_dsc[i] = to_dpu_hw_dsc(hw_dsc[i]);
> +		dpu_enc->hw_pp[i]->dsc = dpu_enc->hw_dsc[i]; /* bind dsc to pp */
> +		dsc_mask |= BIT(dpu_enc->hw_dsc[i]->idx - DSC_0);
>   	}
>   
>   	dpu_enc->dsc_mask = dsc_mask;
> @@ -1110,10 +1198,22 @@ static void dpu_encoder_virt_atomic_mode_set(struct drm_encoder *drm_enc,
>   		phys->hw_pp = dpu_enc->hw_pp[i];
>   		phys->hw_ctl = to_dpu_hw_ctl(hw_ctl[i]);
>   
> +		if (phys->intf_idx >= INTF_0 && phys->intf_idx < INTF_MAX)
> +			phys->hw_intf = dpu_rm_get_intf(&dpu_kms->rm, phys->intf_idx);
> +
> +		/* phys->hw_intf populated at dpu_encoder_setup_display() */
> +		if (!phys->hw_intf) {
> +			DPU_ERROR_ENC(dpu_enc,
> +				"no intf block assigned at idx: %d\n", i);
> +			return;
> +		}
> +
>   		phys->cached_mode = crtc_state->adjusted_mode;
>   		if (phys->ops.atomic_mode_set)
>   			phys->ops.atomic_mode_set(phys, crtc_state, conn_state);
>   	}
> +
> +	dpu_encoder_populate_encoder_phys(drm_enc, dpu_enc);
>   }
>   
>   static void _dpu_encoder_virt_enable_helper(struct drm_encoder *drm_enc)
> @@ -1208,6 +1308,8 @@ static void dpu_encoder_virt_enable(struct drm_encoder *drm_enc)
>   	mutex_unlock(&dpu_enc->enc_lock);
>   }
>   
> +static void dpu_encoder_unprep_dsc(struct dpu_encoder_virt *dpu_enc);
> +
>   static void dpu_encoder_virt_disable(struct drm_encoder *drm_enc)
>   {
>   	struct dpu_encoder_virt *dpu_enc = NULL;
> @@ -1233,6 +1335,10 @@ static void dpu_encoder_virt_disable(struct drm_encoder *drm_enc)
>   			phys->ops.disable(phys);
>   	}
>   
> +	if (dpu_enc->comp_info && (dpu_enc->disp_info.intf_type == DRM_MODE_ENCODER_TMDS)) {
> +		dpu_encoder_unprep_dsc(dpu_enc);
> +		dpu_enc->comp_info = NULL;
> +	}
>   
>   	/* after phys waits for frame-done, should be no more frames pending */
>   	if (atomic_xchg(&dpu_enc->frame_done_timeout_ms, 0)) {
> @@ -1795,40 +1901,16 @@ static void dpu_encoder_vsync_event_work_handler(struct kthread_work *work)
>   			nsecs_to_jiffies(ktime_to_ns(wakeup_time)));
>   }
>   
> -static u32
> -dpu_encoder_dsc_initial_line_calc(struct drm_dsc_config *dsc,
> -				  u32 enc_ip_width)
> -{
> -	int ssm_delay, total_pixels, soft_slice_per_enc;
> -
> -	soft_slice_per_enc = enc_ip_width / dsc->slice_width;
> -
> -	/*
> -	 * minimum number of initial line pixels is a sum of:
> -	 * 1. sub-stream multiplexer delay (83 groups for 8bpc,
> -	 *    91 for 10 bpc) * 3
> -	 * 2. for two soft slice cases, add extra sub-stream multiplexer * 3
> -	 * 3. the initial xmit delay
> -	 * 4. total pipeline delay through the "lock step" of encoder (47)
> -	 * 5. 6 additional pixels as the output of the rate buffer is
> -	 *    48 bits wide
> -	 */
> -	ssm_delay = ((dsc->bits_per_component < 10) ? 84 : 92);
> -	total_pixels = ssm_delay * 3 + dsc->initial_xmit_delay + 47;
> -	if (soft_slice_per_enc > 1)
> -		total_pixels += (ssm_delay * 3);
> -	return DIV_ROUND_UP(total_pixels, dsc->slice_width);
> -}
> -
>   static void dpu_encoder_dsc_pipe_cfg(struct dpu_encoder_virt *dpu_enc,
>   				     struct dpu_hw_dsc *hw_dsc,
>   				     struct dpu_hw_pingpong *hw_pp,
> -				     struct drm_dsc_config *dsc,
> +				     struct msm_display_dsc_info *dsc_info,
>   				     u32 common_mode,
>   				     u32 initial_lines)
>   {
>   	struct dpu_encoder_phys *cur_master = dpu_enc->cur_master;
>   	struct dpu_hw_ctl *ctl;
> +	struct drm_dsc_config *dsc = &dsc_info->drm_dsc;
>   
>   	ctl = cur_master->hw_ctl;
>   
> @@ -1852,51 +1934,137 @@ static void dpu_encoder_dsc_pipe_cfg(struct dpu_encoder_virt *dpu_enc,
>   
>   }
>   
> +static void dpu_encoder_dsc_disable(struct dpu_encoder_virt *dpu_enc,
> +				     struct dpu_hw_dsc *hw_dsc,
> +				     struct dpu_hw_pingpong *hw_pp)
> +{
> +	struct dpu_encoder_phys *cur_master = dpu_enc->cur_master;
> +	struct dpu_hw_ctl *ctl;
> +
> +	ctl = cur_master->hw_ctl;
> +
> +	if (hw_dsc->ops.dsc_disable)
> +		hw_dsc->ops.dsc_disable(hw_dsc);
> +
> +	if (hw_pp->ops.disable_dsc)
> +		hw_pp->ops.disable_dsc(hw_pp);
> +
> +}
> +
>   static void dpu_encoder_prep_dsc(struct dpu_encoder_virt *dpu_enc,
> -				 struct drm_dsc_config *dsc)
> +				 struct msm_display_dsc_info *dsc_info)
>   {
>   	/* coding only for 2LM, 2enc, 1 dsc config */
>   	struct dpu_encoder_phys *enc_master = dpu_enc->cur_master;
>   	struct dpu_hw_dsc *hw_dsc[MAX_CHANNELS_PER_ENC];
>   	struct dpu_hw_pingpong *hw_pp[MAX_CHANNELS_PER_ENC];
> +	struct msm_display_topology *topology = &dpu_enc->topology;
> +	enum dpu_3d_blend_mode mode_3d;
>   	int this_frame_slices;
>   	int intf_ip_w, enc_ip_w;
> -	int dsc_common_mode;
> -	int pic_width;
> -	u32 initial_lines;
> +	int dsc_common_mode = 0;
> +	int dsc_pic_width;
> +	int num_lm, num_dsc, num_intf;
> +	bool dsc_merge, merge_3d, dsc_4hsmerge;
> +	bool disable_merge_3d = false;
> +	int ich_res;
>   	int i;
>   
>   	for (i = 0; i < MAX_CHANNELS_PER_ENC; i++) {
>   		hw_pp[i] = dpu_enc->hw_pp[i];
>   		hw_dsc[i] = dpu_enc->hw_dsc[i];
> +	}
>   
> -		if (!hw_pp[i] || !hw_dsc[i]) {
> -			DPU_ERROR_ENC(dpu_enc, "invalid params for DSC\n");
> -			return;
> -		}
> +	num_lm = topology->num_lm;
> +	num_dsc = topology->num_dsc;
> +	num_intf = topology->num_intf;
> +
> +
> +	mode_3d = (num_lm > num_dsc) ? BLEND_3D_H_ROW_INT : BLEND_3D_NONE;
> +	merge_3d = ((mode_3d != BLEND_3D_NONE) && !(enc_master->hw_intf->cfg.split_link_en)) ?
> +			true : false;
> +
> +	dsc_merge = ((num_dsc > num_intf) && !dsc_info->half_panel_pu &&
> +			!(enc_master->hw_intf->cfg.split_link_en)) ? true : false;
> +	disable_merge_3d = (merge_3d && dsc_info->half_panel_pu) ?  false : true;
> +	dsc_4hsmerge = (dsc_merge && num_dsc == 4 && num_intf == 1) ?  true : false;
> +
> +	/*
> +	 * If this encoder is driving more than one DSC encoder, they
> +	 * operate in tandem, same pic dimension needs to be used by
> +	 * each of them.(pp-split is assumed to be not supported)
> +	 *
> +	 * If encoder is driving more than 2 DSCs, each DSC pair will operate
> +	 * on half of the picture in tandem.
> +	 */
> +	dsc_pic_width = dsc_info->drm_dsc.pic_width;
> +
> +	if (num_dsc > 2) {
> +		dsc_pic_width /= 2;
> +		dsc_info->dsc_4hsmerge_en = dsc_4hsmerge;
>   	}
>   
> -	dsc_common_mode = 0;
> -	pic_width = dsc->pic_width;
> +	this_frame_slices = dsc_pic_width / dsc_info->drm_dsc.slice_width;
> +	intf_ip_w = this_frame_slices * dsc_info->drm_dsc.slice_width;
> +	enc_ip_w = intf_ip_w;
> +
> +	if (!dsc_info->half_panel_pu)
> +		intf_ip_w /= num_intf;
> +	if (!dsc_info->half_panel_pu && (num_dsc > 1))
> +		dsc_common_mode |= DSC_MODE_SPLIT_PANEL;
> +	if (dsc_merge) {
> +		dsc_common_mode |= DSC_MODE_MULTIPLEX;
> +		/*
> +		 * in dsc merge case: when using 2 encoders for the same
> +		 * stream, no. of slices need to be same on both the
> +		 * encoders.
> +		 */
> +		enc_ip_w = intf_ip_w / 2;
> +	}
>   
> -	dsc_common_mode = DSC_MODE_MULTIPLEX | DSC_MODE_SPLIT_PANEL;
>   	if (enc_master->intf_mode == INTF_MODE_VIDEO)
>   		dsc_common_mode |= DSC_MODE_VIDEO;
>   
> -	this_frame_slices = pic_width / dsc->slice_width;
> -	intf_ip_w = this_frame_slices * dsc->slice_width;
> +	dsc_info->num_active_ss_per_enc = dsc_info->drm_dsc.slice_count;
> +
> +	if (dsc_info->dsc_4hsmerge_en)
> +		dsc_info->num_active_ss_per_enc = dsc_info->drm_dsc.slice_count >> 2;
> +	else if ((dsc_common_mode & DSC_MODE_MULTIPLEX) || (dsc_info->half_panel_pu))
> +		dsc_info->num_active_ss_per_enc = dsc_info->drm_dsc.slice_count >> 1;
> +
> +	dpu_dsc_populate_dsc_private_params(dsc_info, intf_ip_w);
> +
> +	dpu_dsc_initial_line_calc(dsc_info, enc_ip_w, dsc_common_mode);
>   
>   	/*
>   	 * dsc merge case: when using 2 encoders for the same stream,
>   	 * no. of slices need to be same on both the encoders.
>   	 */
> -	enc_ip_w = intf_ip_w / 2;
> -	initial_lines = dpu_encoder_dsc_initial_line_calc(dsc, enc_ip_w);
> +	ich_res = dpu_dsc_ich_reset_override_needed(dsc_info->half_panel_pu, dsc_info);
> +
> +	for (i = 0; i < num_dsc; i++) {
> +		dpu_encoder_dsc_pipe_cfg(dpu_enc, hw_dsc[i], hw_pp[i], dsc_info,
> +					dsc_common_mode, 0);
> +	}
> +}
> +
> +static void dpu_encoder_unprep_dsc(struct dpu_encoder_virt *dpu_enc)
> +{
> +	/* coding only for 2LM, 2enc, 1 dsc config */
> +	struct dpu_hw_dsc *hw_dsc[MAX_CHANNELS_PER_ENC];
> +	struct dpu_hw_pingpong *hw_pp[MAX_CHANNELS_PER_ENC];
> +	struct msm_display_topology *topology = &dpu_enc->topology;
> +	int i, num_dsc;
>   
>   	for (i = 0; i < MAX_CHANNELS_PER_ENC; i++) {
> -		dpu_encoder_dsc_pipe_cfg(dpu_enc, hw_dsc[i], hw_pp[i], dsc,
> -					dsc_common_mode, initial_lines);
> +		hw_pp[i] = dpu_enc->hw_pp[i];
> +		hw_dsc[i] = dpu_enc->hw_dsc[i];
>   	}
> +
> +	num_dsc = topology->num_dsc;
> +
> +	for (i = 0; i < num_dsc; i++)
> +		dpu_encoder_dsc_disable(dpu_enc, hw_dsc[i], hw_pp[i]);
>   }
>   
>   void dpu_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc)
> @@ -1904,6 +2072,7 @@ void dpu_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc)
>   	struct dpu_encoder_virt *dpu_enc;
>   	struct dpu_encoder_phys *phys;
>   	bool needs_hw_reset = false;
> +	bool needs_phy_enable = false;
>   	unsigned int i;
>   
>   	dpu_enc = to_dpu_encoder_virt(drm_enc);
> @@ -1918,6 +2087,9 @@ void dpu_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc)
>   			phys->ops.prepare_for_kickoff(phys);
>   		if (phys->enable_state == DPU_ENC_ERR_NEEDS_HW_RESET)
>   			needs_hw_reset = true;
> +
> +		if (phys->enable_state == DPU_ENC_ENABLING)
> +			needs_phy_enable = true;
>   	}
>   	DPU_ATRACE_END("enc_prepare_for_kickoff");
>   
> @@ -1931,8 +2103,10 @@ void dpu_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc)
>   		}
>   	}
>   
> -	if (dpu_enc->dsc)
> -		dpu_encoder_prep_dsc(dpu_enc, dpu_enc->dsc);
> +	if (needs_phy_enable && dpu_enc->comp_info)
> +		dpu_encoder_prep_dsc(dpu_enc, &dpu_enc->comp_info->msm_dsc_info);
> +
> +
>   }
>   
>   bool dpu_encoder_is_valid_for_commit(struct drm_encoder *drm_enc)
> @@ -2295,7 +2469,7 @@ static int dpu_encoder_setup_display(struct dpu_encoder_virt *dpu_enc,
>   				dpu_kms->catalog->caps->has_idle_pc;
>   
>   	dpu_enc->comp_info = disp_info->comp_info;
> -	if (dpu_enc->comp_info)
> +	if (dpu_enc->comp_info && dpu_enc->comp_info->enabled)
>   		dpu_enc->dsc = &dpu_enc->comp_info->msm_dsc_info.drm_dsc;
>   
>   	mutex_lock(&dpu_enc->enc_lock);
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
> index 0569b36..ae4f6a8 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
> @@ -1,6 +1,6 @@
>   /* SPDX-License-Identifier: GPL-2.0-only */
>   /*
> - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
> + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
>    * Copyright (c) 2015-2018 The Linux Foundation. All rights reserved.
>    */
>   
> @@ -202,6 +202,9 @@ struct dpu_encoder_phys {
>   	int irq[INTR_IDX_MAX];
>   	enum msm_display_compression_type comp_type;
>   	u32 comp_ratio;
> +	u32 dsc_extra_pclk_cycle_cnt;
> +	u32 dsc_extra_disp_width;
> +	u32 dce_bytes_per_line;
>   };
>   
>   static inline int dpu_encoder_phys_inc_pending(struct dpu_encoder_phys *phys)
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
> index 3330e185..6c7d791 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
> @@ -86,6 +86,11 @@ static void drm_mode_to_intf_timing_params(
>   	timing->underflow_clr = 0xff;
>   	timing->hsync_skew = mode->hskew;
>   
> +	if (phys_enc->comp_type != MSM_DISPLAY_COMPRESSION_NONE) {
> +		timing->compression_en = true;
> +		timing->dce_bytes_per_line = phys_enc->dce_bytes_per_line;
> +	}
> +
>   	/* DSI controller cannot handle active-low sync signals. */
>   	if (phys_enc->hw_intf->cap->type == INTF_DSI) {
>   		timing->hsync_polarity = 0;
> @@ -104,14 +109,36 @@ static void drm_mode_to_intf_timing_params(
>   
>   	/*
>   	 * for DP, divide the horizonal parameters by 2 when
> -	 * widebus is enabled
> +	 * widebus or compression is enabled, irrespective of
> +	 * compression ratio
>   	 */
> -	if (phys_enc->hw_intf->cap->type == INTF_DP && timing->wide_bus_en) {
> +	if (phys_enc->hw_intf->cap->type == INTF_DP &&
> +		(timing->wide_bus_en || (phys_enc->comp_ratio > 1))) {
>   		timing->width = timing->width >> 1;
>   		timing->xres = timing->xres >> 1;
>   		timing->h_back_porch = timing->h_back_porch >> 1;
>   		timing->h_front_porch = timing->h_front_porch >> 1;
>   		timing->hsync_pulse_width = timing->hsync_pulse_width >> 1;
> +
> +		if (phys_enc->comp_type == MSM_DISPLAY_COMPRESSION_DSC &&
> +				(phys_enc->comp_ratio > 1)) {
> +			timing->extra_dto_cycles =
> +					phys_enc->dsc_extra_pclk_cycle_cnt;
> +			timing->width += phys_enc->dsc_extra_disp_width;
> +			timing->h_back_porch +=
> +					phys_enc->dsc_extra_disp_width;
> +		}
> +	}
> +
> +	/*
> +	 * for DSI, if compression is enabled, then divide the horizonal active
> +	 * timing parameters by compression ratio.
> +	 */
> +	if ((phys_enc->hw_intf->cap->type != INTF_DP) &&
> +			((phys_enc->comp_type == MSM_DISPLAY_COMPRESSION_DSC))) {
> +		// adjust active dimensions
> +		timing->width = DIV_ROUND_UP(timing->width, phys_enc->comp_ratio);
> +		timing->xres = DIV_ROUND_UP(timing->xres, phys_enc->comp_ratio);
>   	}
>   }
>   
> @@ -281,6 +308,9 @@ static void dpu_encoder_phys_vid_setup_timing_engine(
>   
>   	phys_enc->hw_intf->hw_rev = phys_enc->dpu_kms->core_rev;
>   
> +	if (phys_enc->hw_pp->dsc)
> +		intf_cfg.dsc_num = phys_enc->hw_pp->dsc->idx;

Why ??? it breaks when in multiplex mode and we have multiple DSCs !

> +
>   	spin_lock_irqsave(phys_enc->enc_spinlock, lock_flags);
>   	phys_enc->hw_intf->ops.setup_timing_gen(phys_enc->hw_intf,
>   			&timing_params, fmt);
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.h
> index c002234..ee71cee 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.h
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.h
> @@ -1,5 +1,6 @@
>   /* SPDX-License-Identifier: GPL-2.0-only */
>   /* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
> + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
>    */
>   
>   #ifndef _DPU_HW_PINGPONG_H
> @@ -8,6 +9,7 @@
>   #include "dpu_hw_catalog.h"
>   #include "dpu_hw_mdss.h"
>   #include "dpu_hw_util.h"
> +#include "dpu_hw_dsc.h"
>   
>   #define DITHER_MATRIX_SZ 16
>   
> @@ -149,6 +151,7 @@ struct dpu_hw_pingpong {
>   	enum dpu_pingpong idx;
>   	const struct dpu_pingpong_cfg *caps;
>   	struct dpu_hw_merge_3d *merge_3d;
> +	struct dpu_hw_dsc *dsc;
>   
>   	/* ops */
>   	struct dpu_hw_pingpong_ops ops;
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
> index 396429e..bb22ec8 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
> @@ -1,6 +1,7 @@
>   // SPDX-License-Identifier: GPL-2.0-only
>   /*
>    * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
> + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
>    */
>   
>   #define pr_fmt(fmt)	"[drm:%s] " fmt, __func__
> @@ -246,6 +247,11 @@ int dpu_rm_init(struct dpu_rm *rm,
>   		struct dpu_hw_dsc *hw;
>   		const struct dpu_dsc_cfg *dsc = &cat->dsc[i];
>   
> +		if (dsc->id < DSC_0 || dsc->id >= DSC_MAX) {
> +			DPU_ERROR("skip dsc %d with invalid id\n", dsc->id);
> +			continue;
> +		}
> +
>   		hw = dpu_hw_dsc_init(dsc->id, mmio, cat);
>   		if (IS_ERR_OR_NULL(hw)) {
>   			rc = PTR_ERR(hw);
> @@ -535,8 +541,10 @@ static int _dpu_rm_make_reservation(
>   	}
>   
>   	ret  = _dpu_rm_reserve_dsc(rm, global_state, enc, &reqs->topology);
> -	if (ret)
> +	if (ret) {
> +		DPU_ERROR("unable to find appropriate DSC\n");
>   		return ret;
> +	}
>   
>   	return ret;
>   }



More information about the dri-devel mailing list