Răsfoiți Sursa

disp: msm: sde: adjust intf timing for widebus

From Lahaina onwards, widebus is enabled for compressed DSI stream.
This change adjusts interface timing parameters to account for widebus.

Change-Id: Ie6b739ed2cdb515064e3a94404b3e0fe07755d7e
Signed-off-by: Rajkumar Subbiah <[email protected]>
Rajkumar Subbiah 5 ani în urmă
părinte
comite
c0d4857a81

+ 8 - 1
msm/sde/sde_encoder.c

@@ -2635,7 +2635,6 @@ static void sde_encoder_virt_enable(struct drm_encoder *drm_enc)
 
 		phys->comp_type = comp_info->comp_type;
 		phys->comp_ratio = comp_info->comp_ratio;
-		phys->wide_bus_en = sde_enc->mode_info.wide_bus_en;
 		phys->frame_trigger_mode = sde_enc->frame_trigger_mode;
 		phys->poms_align_vsync = disp_info->poms_align_vsync;
 		if (phys->comp_type == MSM_DISPLAY_COMPRESSION_DSC) {
@@ -2643,7 +2642,15 @@ static void sde_encoder_virt_enable(struct drm_encoder *drm_enc)
 				comp_info->dsc_info.pclk_per_line;
 			phys->dsc_extra_disp_width =
 				comp_info->dsc_info.extra_width;
+			phys->dce_bytes_per_line =
+				comp_info->dsc_info.bytes_per_pkt *
+				comp_info->dsc_info.pkt_per_line;
+		} else if (phys->comp_type == MSM_DISPLAY_COMPRESSION_VDC) {
+			phys->dce_bytes_per_line =
+				comp_info->vdc_info.bytes_per_pkt *
+				comp_info->vdc_info.pkt_per_line;
 		}
+
 		if (phys != sde_enc->cur_master) {
 			/**
 			 * on DMS request, the encoder will be enabled

+ 16 - 0
msm/sde/sde_encoder.h

@@ -550,4 +550,20 @@ static inline struct sde_kms *sde_encoder_get_kms(struct drm_encoder *drm_enc)
 
 	return to_sde_kms(priv->kms);
 }
+
+/*
+ * sde_encoder_is_widebus_enabled - check if widebus is enabled for current mode
+ * @drm_enc:    Pointer to drm encoder structure
+ * @Return: true if widebus is enabled for current mode
+ */
+static inline bool sde_encoder_is_widebus_enabled(struct drm_encoder *drm_enc)
+{
+	struct sde_encoder_virt *sde_enc;
+
+	if (!drm_enc)
+		return false;
+
+	sde_enc = to_sde_encoder_virt(drm_enc);
+	return sde_enc->mode_info.wide_bus_en;
+}
 #endif /* __SDE_ENCODER_H__ */

+ 4 - 2
msm/sde/sde_encoder_phys.h

@@ -270,8 +270,8 @@ struct sde_encoder_irq {
  * @comp_ratio:		Compression ratio
  * @dsc_extra_pclk_cycle_cnt: Extra pclk cycle count for DSC over DP
  * @dsc_extra_disp_width: Additional display width for DSC over DP
- * @wide_bus_en:	Wide-bus configuraiton
  * @poms_align_vsync:   poms with vsync aligned
+ * @dce_bytes_per_line:	Compressed bytes per line
  * @enc_spinlock:	Virtual-Encoder-Wide Spin Lock for IRQ purposes
  * @enable_state:	Enable state tracking
  * @vblank_refcount:	Reference count of vblank request
@@ -317,8 +317,8 @@ struct sde_encoder_phys {
 	u32 comp_ratio;
 	u32 dsc_extra_pclk_cycle_cnt;
 	u32 dsc_extra_disp_width;
-	bool wide_bus_en;
 	bool poms_align_vsync;
+	u32 dce_bytes_per_line;
 	spinlock_t *enc_spinlock;
 	enum sde_enc_enable_state enable_state;
 	struct mutex *vblank_ctl_lock;
@@ -758,6 +758,7 @@ void sde_encoder_helper_phys_disable(struct sde_encoder_phys *phys_enc,
 
 /**
  * sde_encoder_helper_setup_misr - helper function to setup misr
+ * @phys_enc: Pointer to physical encoder structure
  * @enable: enable/disable flag
  * @frame_count: frame count for misr
  */
@@ -766,6 +767,7 @@ void sde_encoder_helper_setup_misr(struct sde_encoder_phys *phys_enc,
 
 /**
  * sde_encoder_helper_collect_misr - helper function to collect misr
+ * @phys_enc: Pointer to physical encoder structure
  * @nonblock:  blocking/non-blocking flag
  * @misr_value:  pointer to misr value
  * @Return: zero on success

+ 4 - 0
msm/sde/sde_encoder_phys_cmd.c

@@ -1146,6 +1146,10 @@ static void sde_encoder_phys_cmd_enable_helper(
 				(phys_enc->comp_type !=
 				 MSM_DISPLAY_COMPRESSION_NONE), false);
 
+	if (hw_intf->ops.enable_wide_bus)
+		hw_intf->ops.enable_wide_bus(hw_intf,
+			sde_encoder_is_widebus_enabled(phys_enc->parent));
+
 	/*
 	 * For pp-split, skip setting the flush bit for the slave intf, since
 	 * both intfs use same ctl and HW will only flush the master.

+ 22 - 12
msm/sde/sde_encoder_phys_vid.c

@@ -78,17 +78,8 @@ static void drm_mode_to_intf_timing_params(
 	 * <----------------- [hv]sync_end ------->
 	 * <---------------------------- [hv]total ------------->
 	 */
-	timing->width = mode->hdisplay;	/* active width */
-
-	if (phys_enc->hw_intf->cap->type != INTF_DP) {
-		if ((vid_enc->base.comp_type == MSM_DISPLAY_COMPRESSION_DSC) ||
-				(vid_enc->base.comp_type ==
-				MSM_DISPLAY_COMPRESSION_VDC))
-			timing->width = DIV_ROUND_UP(timing->width,
-					vid_enc->base.comp_ratio);
-	}
-
 	timing->poms_align_vsync = phys_enc->poms_align_vsync;
+	timing->width = mode->hdisplay;	/* active width */
 	timing->height = mode->vdisplay;	/* active height */
 	timing->xres = timing->width;
 	timing->yres = timing->height;
@@ -104,8 +95,11 @@ static void drm_mode_to_intf_timing_params(
 	timing->underflow_clr = 0xff;
 	timing->hsync_skew = mode->hskew;
 	timing->v_front_porch_fixed = vid_enc->base.vfp_cached;
-	if (vid_enc->base.comp_type != MSM_DISPLAY_COMPRESSION_NONE)
+
+	if (vid_enc->base.comp_type != MSM_DISPLAY_COMPRESSION_NONE) {
 		timing->compression_en = true;
+		timing->dce_bytes_per_line = vid_enc->base.dce_bytes_per_line;
+	}
 
 	/* DSI controller cannot handle active-low sync signals. */
 	if (phys_enc->hw_intf->cap->type == INTF_DSI) {
@@ -122,7 +116,7 @@ static void drm_mode_to_intf_timing_params(
 		timing->v_front_porch = 0;
 	}
 
-	timing->wide_bus_en = vid_enc->base.wide_bus_en;
+	timing->wide_bus_en = sde_encoder_is_widebus_enabled(phys_enc->parent);
 
 	/*
 	 * for DP, divide the horizonal parameters by 2 when
@@ -148,6 +142,22 @@ static void drm_mode_to_intf_timing_params(
 		}
 	}
 
+	/*
+	 * 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) &&
+			((vid_enc->base.comp_type ==
+			MSM_DISPLAY_COMPRESSION_DSC) ||
+			(vid_enc->base.comp_type ==
+			MSM_DISPLAY_COMPRESSION_VDC))) {
+		// adjust active dimensions
+		timing->width = DIV_ROUND_UP(timing->width,
+			vid_enc->base.comp_ratio);
+		timing->xres = DIV_ROUND_UP(timing->xres,
+			vid_enc->base.comp_ratio);
+	}
+
 	/*
 	 * For edp only:
 	 * DISPLAY_V_START = (VBP * HCYCLE) + HBP

+ 87 - 44
msm/sde/sde_hw_intf.c

@@ -197,88 +197,112 @@ static void sde_hw_intf_setup_timing_engine(struct sde_hw_intf *ctx,
 	u32 hsync_period, vsync_period;
 	u32 display_v_start, display_v_end;
 	u32 hsync_start_x, hsync_end_x;
+	u32 hsync_data_start_x, hsync_data_end_x;
 	u32 active_h_start, active_h_end;
 	u32 active_v_start, active_v_end;
 	u32 active_hctl, display_hctl, hsync_ctl;
 	u32 polarity_ctl, den_polarity, hsync_polarity, vsync_polarity;
 	u32 panel_format;
-	u32 intf_cfg, intf_cfg2;
+	u32 intf_cfg, intf_cfg2 = 0;
 	u32 display_data_hctl = 0, active_data_hctl = 0;
+	u32 data_width;
 	bool dp_intf = false;
 
 	/* read interface_cfg */
 	intf_cfg = SDE_REG_READ(c, INTF_CONFIG);
+
+	if (ctx->cap->type == INTF_EDP || ctx->cap->type == INTF_DP)
+		dp_intf = true;
+
 	hsync_period = p->hsync_pulse_width + p->h_back_porch + p->width +
-	p->h_front_porch;
+			p->h_front_porch;
 	vsync_period = p->vsync_pulse_width + p->v_back_porch + p->height +
-	p->v_front_porch;
+			p->v_front_porch;
 
 	display_v_start = ((p->vsync_pulse_width + p->v_back_porch) *
-	hsync_period) + p->hsync_skew;
+			hsync_period) + p->hsync_skew;
 	display_v_end = ((vsync_period - p->v_front_porch) * hsync_period) +
-	p->hsync_skew - 1;
+			p->hsync_skew - 1;
+
+	hsync_ctl = (hsync_period << 16) | p->hsync_pulse_width;
 
 	hsync_start_x = p->h_back_porch + p->hsync_pulse_width;
 	hsync_end_x = hsync_period - p->h_front_porch - 1;
 
-	if (ctx->cap->type == INTF_EDP || ctx->cap->type == INTF_DP)
-		dp_intf = true;
+	/*
+	 * DATA_HCTL_EN controls data timing which can be different from
+	 * video timing. It is recommended to enable it for all cases, except
+	 * if compression is enabled in 1 pixel per clock mode
+	 */
+	if (!p->compression_en || p->wide_bus_en)
+		intf_cfg2 |= BIT(4);
 
-	if (p->width != p->xres) {
-		active_h_start = hsync_start_x;
-		active_h_end = active_h_start + p->xres - 1;
-	} else {
-		active_h_start = 0;
-		active_h_end = 0;
-	}
+	if (p->wide_bus_en)
+		intf_cfg2 |= BIT(0);
 
-	if (p->height != p->yres) {
-		active_v_start = display_v_start;
-		active_v_end = active_v_start + (p->yres * hsync_period) - 1;
-	} else {
-		active_v_start = 0;
-		active_v_end = 0;
-	}
+	/*
+	 * If widebus is disabled:
+	 * For uncompressed stream, the data is valid for the entire active
+	 * window period.
+	 * For compressed stream, data is valid for a shorter time period
+	 * inside the active window depending on the compression ratio.
+	 *
+	 * If widebus is enabled:
+	 * For uncompressed stream, data is valid for only half the active
+	 * window, since the data rate is doubled in this mode.
+	 * p->width holds the adjusted width for DP but unadjusted width for DSI
+	 * For compressed stream, data validity window needs to be adjusted for
+	 * compression ratio and then further halved.
+	 */
+	data_width = p->width;
+
+	if (p->compression_en) {
+		data_width = DIV_ROUND_UP(p->dce_bytes_per_line, 3);
 
-	if (active_h_end) {
-		active_hctl = (active_h_end << 16) | active_h_start;
-		intf_cfg |= BIT(29);	/* ACTIVE_H_ENABLE */
+		if (p->wide_bus_en)
+			data_width >>= 1;
+	} else if (!dp_intf && p->wide_bus_en) {
+		data_width = p->width >> 1;
 	} else {
-		active_hctl = 0;
+		data_width = p->width;
 	}
 
-	if (active_v_end)
-		intf_cfg |= BIT(30); /* ACTIVE_V_ENABLE */
+	hsync_data_start_x = hsync_start_x;
+	hsync_data_end_x =  hsync_start_x + data_width - 1;
 
-	hsync_ctl = (hsync_period << 16) | p->hsync_pulse_width;
 	display_hctl = (hsync_end_x << 16) | hsync_start_x;
+	display_data_hctl = (hsync_data_end_x << 16) | hsync_data_start_x;
 
 	if (dp_intf) {
-		active_h_start = hsync_start_x;
-		active_h_end = active_h_start + p->xres - 1;
-		active_v_start = display_v_start;
-		active_v_end = active_v_start + (p->yres * hsync_period) - 1;
-
+		// DP timing adjustment
 		display_v_start += p->hsync_pulse_width + p->h_back_porch;
-
-		active_hctl = (active_h_end << 16) | active_h_start;
-		display_hctl = active_hctl;
+		display_v_end   -= p->h_front_porch;
 	}
 
-	intf_cfg2 = 0;
+	intf_cfg |= BIT(29);	/* ACTIVE_H_ENABLE */
+	intf_cfg |= BIT(30);	/* ACTIVE_V_ENABLE */
+	active_h_start = hsync_start_x;
+	active_h_end = active_h_start + p->xres - 1;
+	active_v_start = display_v_start;
+	active_v_end = active_v_start + (p->yres * hsync_period) - 1;
 
-	_check_and_set_comp_bit(ctx, p->dsc_4hs_merge, p->compression_en,
-			&intf_cfg2);
+	active_hctl = (active_h_end << 16) | active_h_start;
 
-	if (dp_intf && p->compression_en) {
-		active_data_hctl = (hsync_start_x + p->extra_dto_cycles) << 16;
-		active_data_hctl += hsync_start_x;
+	if (dp_intf) {
+		display_hctl = active_hctl;
 
-		display_data_hctl = active_data_hctl;
+		if (p->compression_en) {
+			active_data_hctl = (hsync_start_x +
+					 p->extra_dto_cycles) << 16;
+			active_data_hctl += hsync_start_x;
 
-		intf_cfg2 |= BIT(4);
+			display_data_hctl = active_data_hctl;
+		}
 	}
 
+	_check_and_set_comp_bit(ctx, p->dsc_4hs_merge, p->compression_en,
+			&intf_cfg2);
+
 	den_polarity = 0;
 	if (ctx->cap->type == INTF_HDMI) {
 		hsync_polarity = p->yres >= 720 ? 0 : 1;
@@ -730,6 +754,24 @@ static void sde_hw_intf_enable_compressed_input(struct sde_hw_intf *intf,
 	SDE_REG_WRITE(c, INTF_CONFIG2, intf_cfg2);
 }
 
+static void sde_hw_intf_enable_wide_bus(struct sde_hw_intf *intf,
+		bool enable)
+{
+	struct sde_hw_blk_reg_map *c;
+	u32 intf_cfg2;
+
+	if (!intf)
+		return;
+
+	c = &intf->hw;
+	intf_cfg2 = SDE_REG_READ(c, INTF_CONFIG2);
+	intf_cfg2 &= ~BIT(0);
+
+	intf_cfg2 |= enable ? BIT(0) : 0;
+
+	SDE_REG_WRITE(c, INTF_CONFIG2, intf_cfg2);
+}
+
 static void _setup_intf_ops(struct sde_hw_intf_ops *ops,
 		unsigned long cap)
 {
@@ -745,6 +787,7 @@ static void _setup_intf_ops(struct sde_hw_intf_ops *ops,
 	ops->avr_trigger = sde_hw_intf_avr_trigger;
 	ops->avr_ctrl = sde_hw_intf_avr_ctrl;
 	ops->enable_compressed_input = sde_hw_intf_enable_compressed_input;
+	ops->enable_wide_bus = sde_hw_intf_enable_wide_bus;
 
 	if (cap & BIT(SDE_INTF_INPUT_CTRL))
 		ops->bind_pingpong_blk = sde_hw_intf_bind_pingpong_blk;

+ 7 - 1
msm/sde/sde_hw_intf.h

@@ -33,11 +33,12 @@ struct intf_timing_params {
 	u32 underflow_clr;
 	u32 hsync_skew;
 	u32 v_front_porch_fixed;
-	bool wide_bus_en;	/* for DP only */
+	bool wide_bus_en;
 	bool compression_en;
 	u32 extra_dto_cycles;	/* for DP only */
 	bool dsc_4hs_merge;	/* DSC 4HS merge */
 	bool poms_align_vsync;	/* poms with vsync aligned */
+	u32 dce_bytes_per_line;
 };
 
 struct intf_prog_fetch {
@@ -199,6 +200,11 @@ struct sde_hw_intf_ops {
 	 */
 	int (*check_and_reset_tearcheck)(struct sde_hw_intf *intf,
 			struct intf_tear_status *status);
+
+	/**
+	 * Enable processing of 2 pixels per clock
+	 */
+	void (*enable_wide_bus)(struct sde_hw_intf *intf, bool enable);
 };
 
 struct sde_hw_intf {