瀏覽代碼

disp: msm: sde: adjust DSC encoders to support all 4LM topologies

Add support for all 4LM topologies in new DCE encoder framework.
This change also aligns with the new way of checking topology
information.

Change-Id: I20785c96569fd07cbd8016d244a7e4c929bfa071
Signed-off-by: Amine Najahi <[email protected]>
Amine Najahi 5 年之前
父節點
當前提交
6a50aedbfa
共有 11 個文件被更改,包括 185 次插入59 次删除
  1. 6 0
      msm/msm_drv.h
  2. 8 20
      msm/sde/sde_crtc.c
  3. 23 19
      msm/sde/sde_encoder.c
  4. 1 1
      msm/sde/sde_encoder.h
  5. 25 13
      msm/sde/sde_encoder_dce.c
  6. 16 4
      msm/sde/sde_encoder_phys.h
  7. 1 1
      msm/sde/sde_hw_catalog.h
  8. 10 1
      msm/sde/sde_hw_dsc_1_2.c
  9. 57 0
      msm/sde/sde_rm.c
  10. 26 0
      msm/sde/sde_rm.h
  11. 12 0
      msm/sde_dsc_helper.c

+ 6 - 0
msm/msm_drv.h

@@ -364,6 +364,9 @@ struct msm_roi_caps {
  * @det_thresh_flatness:     Flatness threshold.
  * @extra_width:             Extra width required in timing calculations.
  * @pps_delay_ms:            Post PPS command delay in milliseconds.
+ * @dsc_4hsmerge_en:         Using DSC 4HS merge topology
+ * @dsc_4hsmerge_padding     4HS merge DSC pair padding value in bytes
+ * @dsc_4hsmerge_alignment   4HS merge DSC alignment value in bytes
  */
 struct msm_display_dsc_info {
 	struct drm_dsc_config config;
@@ -382,6 +385,9 @@ struct msm_display_dsc_info {
 	int det_thresh_flatness;
 	u32 extra_width;
 	u32 pps_delay_ms;
+	bool dsc_4hsmerge_en;
+	u32 dsc_4hsmerge_padding;
+	u32 dsc_4hsmerge_alignment;
 };
 
 

+ 8 - 20
msm/sde/sde_crtc.c

@@ -678,25 +678,6 @@ static int _sde_crtc_set_roi_v1(struct drm_crtc_state *state,
 	return 0;
 }
 
-static bool _sde_crtc_setup_is_3dmux_dsc(struct drm_crtc_state *state)
-{
-	int i;
-	struct sde_crtc_state *cstate;
-	bool is_3dmux_dsc = false;
-
-	cstate = to_sde_crtc_state(state);
-
-	for (i = 0; i < cstate->num_connectors; i++) {
-		struct drm_connector *conn = cstate->connectors[i];
-
-		if (sde_connector_get_topology_name(conn) ==
-				SDE_RM_TOPOLOGY_DUALPIPE_3DMERGE_DSC)
-			is_3dmux_dsc = true;
-	}
-
-	return is_3dmux_dsc;
-}
-
 static int _sde_crtc_set_crtc_roi(struct drm_crtc *crtc,
 		struct drm_crtc_state *state)
 {
@@ -836,6 +817,7 @@ static int _sde_crtc_check_autorefresh(struct drm_crtc *crtc,
 static int _sde_crtc_set_lm_roi(struct drm_crtc *crtc,
 		struct drm_crtc_state *state, int lm_idx)
 {
+	struct sde_kms *sde_kms;
 	struct sde_crtc *sde_crtc;
 	struct sde_crtc_state *crtc_state;
 	const struct sde_rect *crtc_roi;
@@ -845,6 +827,12 @@ static int _sde_crtc_set_lm_roi(struct drm_crtc *crtc,
 	if (!crtc || !state || lm_idx >= ARRAY_SIZE(crtc_state->lm_bounds))
 		return -EINVAL;
 
+	sde_kms = _sde_crtc_get_kms(crtc);
+	if (!sde_kms || !sde_kms->catalog) {
+		SDE_ERROR("invalid parameters\n");
+		return -EINVAL;
+	}
+
 	sde_crtc = to_sde_crtc(crtc);
 	crtc_state = to_sde_crtc_state(state);
 	crtc_roi = &crtc_state->crtc_roi;
@@ -864,7 +852,7 @@ static int _sde_crtc_set_lm_roi(struct drm_crtc *crtc,
 	 * hence, crtc roi must match the mixer dimensions.
 	 */
 	if (crtc_state->num_ds_enabled ||
-		_sde_crtc_setup_is_3dmux_dsc(state)) {
+		sde_rm_topology_is_3dmux_dsc(&sde_kms->rm, state)) {
 		if (memcmp(lm_roi, lm_bounds, sizeof(struct sde_rect))) {
 			SDE_ERROR("Unsupported: Dest scaler/3d mux DSC + PU\n");
 			return -EINVAL;

+ 23 - 19
msm/sde/sde_encoder.c

@@ -71,12 +71,6 @@
 /* Maximum number of VSYNC wait attempts for RSC state transition */
 #define MAX_RSC_WAIT	5
 
-#define TOPOLOGY_DUALPIPE_MERGE_MODE(x) \
-		(((x) == SDE_RM_TOPOLOGY_DUALPIPE_DSCMERGE) || \
-		((x) == SDE_RM_TOPOLOGY_DUALPIPE_3DMERGE) || \
-		((x) == SDE_RM_TOPOLOGY_DUALPIPE_3DMERGE_VDC) || \
-		((x) == SDE_RM_TOPOLOGY_DUALPIPE_3DMERGE_DSC))
-
 /**
  * enum sde_enc_rc_events - events for resource control state machine
  * @SDE_ENC_RC_EVENT_KICKOFF:
@@ -2220,6 +2214,7 @@ static void sde_encoder_virt_mode_set(struct drm_encoder *drm_enc,
 	struct sde_kms *sde_kms;
 	struct drm_connector *conn;
 	int i = 0, ret;
+	int num_lm, num_intf, num_pp_per_intf;
 
 	if (!drm_enc) {
 		SDE_ERROR("invalid encoder\n");
@@ -2281,17 +2276,25 @@ static void sde_encoder_virt_mode_set(struct drm_encoder *drm_enc,
 	/* assign the reserved HW blocks to this encoder */
 	_sde_encoder_virt_populate_hw_res(drm_enc);
 
+	/* determine left HW PP block to map to INTF */
+	num_lm = sde_enc->mode_info.topology.num_lm;
+	num_intf = sde_enc->mode_info.topology.num_intf;
+	num_pp_per_intf = num_lm / num_intf;
+	if (!num_pp_per_intf)
+		num_pp_per_intf = 1;
+
 	/* perform mode_set on phys_encs */
 	for (i = 0; i < sde_enc->num_phys_encs; i++) {
 		struct sde_encoder_phys *phys = sde_enc->phys_encs[i];
 
 		if (phys) {
-			if (!sde_enc->hw_pp[i] && sde_enc->topology.num_intf) {
-				SDE_ERROR_ENC(sde_enc,
-				    "invalid pingpong block for the encoder\n");
+			if (!sde_enc->hw_pp[i * num_pp_per_intf] &&
+				sde_enc->topology.num_intf) {
+				SDE_ERROR_ENC(sde_enc, "invalid hw_pp[%d]\n",
+						i * num_pp_per_intf);
 				return;
 			}
-			phys->hw_pp = sde_enc->hw_pp[i];
+			phys->hw_pp = sde_enc->hw_pp[i * num_pp_per_intf];
 			phys->connector = conn->state->connector;
 			if (phys->ops.mode_set)
 				phys->ops.mode_set(phys, mode, adj_mode);
@@ -2498,6 +2501,7 @@ static void _sde_encoder_virt_enable_helper(struct drm_encoder *drm_enc)
 
 static void _sde_encoder_setup_dither(struct sde_encoder_phys *phys)
 {
+	struct sde_kms *sde_kms;
 	void *dither_cfg = NULL;
 	int ret = 0, i = 0;
 	size_t len = 0;
@@ -2507,11 +2511,16 @@ static void _sde_encoder_setup_dither(struct sde_encoder_phys *phys)
 	struct sde_encoder_virt *sde_enc;
 	struct sde_hw_pingpong *hw_pp;
 	u32 bpp, bpc;
+	int num_lm;
 
 	if (!phys || !phys->connector || !phys->hw_pp ||
 			!phys->hw_pp->ops.setup_dither || !phys->parent)
 		return;
 
+	sde_kms = sde_encoder_get_kms(phys->parent);
+	if (!sde_kms)
+		return;
+
 	topology = sde_connector_get_topology_name(phys->connector);
 	if ((topology == SDE_RM_TOPOLOGY_PPSPLIT) &&
 			(phys->split_role == ENC_ROLE_SLAVE))
@@ -2538,15 +2547,10 @@ static void _sde_encoder_setup_dither(struct sde_encoder_phys *phys)
 	if (ret && ret == -ENODATA)
 		return;
 
-	if (TOPOLOGY_DUALPIPE_MERGE_MODE(topology)) {
-		for (i = 0; i < MAX_CHANNELS_PER_ENC; i++) {
-			hw_pp = sde_enc->hw_pp[i];
-			phys->hw_pp->ops.setup_dither(hw_pp,
-					dither_cfg, len);
-		}
-
-	} else {
-		phys->hw_pp->ops.setup_dither(phys->hw_pp,
+	num_lm = sde_rm_topology_get_num_lm(&sde_kms->rm, topology);
+	for (i = 0; i < num_lm; i++) {
+		hw_pp = sde_enc->hw_pp[i];
+		phys->hw_pp->ops.setup_dither(hw_pp,
 				dither_cfg, len);
 	}
 }

+ 1 - 1
msm/sde/sde_encoder.h

@@ -38,7 +38,7 @@
 #define MAX_PHYS_ENCODERS_PER_VIRTUAL \
 	(MAX_H_TILES_PER_DISPLAY * NUM_PHYS_ENCODER_TYPES)
 
-#define MAX_CHANNELS_PER_ENC 2
+#define MAX_CHANNELS_PER_ENC 4
 
 #define SDE_ENCODER_FRAME_EVENT_DONE			BIT(0)
 #define SDE_ENCODER_FRAME_EVENT_ERROR			BIT(1)

+ 25 - 13
msm/sde/sde_encoder_dce.c

@@ -306,7 +306,8 @@ static int _dce_dsc_setup_single(struct sde_encoder_virt *sde_enc,
 		unsigned long affected_displays, int index,
 		const struct sde_rect *roi, int dsc_common_mode,
 		bool merge_3d, bool disable_merge_3d, bool mode_3d,
-		bool half_panel_partial_update, int ich_res)
+		bool dsc_4hsmerge, bool half_panel_partial_update,
+		int ich_res)
 {
 	struct sde_hw_ctl *hw_ctl;
 	struct sde_hw_dsc *hw_dsc;
@@ -338,8 +339,9 @@ static int _dce_dsc_setup_single(struct sde_encoder_virt *sde_enc,
 		return -EINVAL;
 	}
 
-	SDE_EVT32(DRMID(&sde_enc->base), roi->w, roi->h, dsc_common_mode,
-			index, active, merge_3d, disable_merge_3d);
+	SDE_EVT32(DRMID(&sde_enc->base), roi->w, roi->h,
+			dsc_common_mode, index, active, merge_3d,
+			disable_merge_3d, dsc_4hsmerge);
 
 	_dce_dsc_pipe_cfg(hw_dsc, hw_pp, dsc, dsc_common_mode, ich_res,
 			hw_dsc_pp, mode_3d, disable_merge_3d, active);
@@ -393,15 +395,15 @@ static int _dce_dsc_setup_helper(struct sde_encoder_virt *sde_enc,
 	const struct sde_rm_topology_def *def;
 	const struct sde_rect *roi;
 	enum sde_3d_blend_mode mode_3d;
-	bool half_panel_partial_update, dsc_merge, merge_3d;
+	bool half_panel_partial_update, dsc_merge, merge_3d, dsc_4hsmerge;
 	bool disable_merge_3d = false;
 	int this_frame_slices;
 	int intf_ip_w, enc_ip_w;
 	int num_intf, num_dsc, num_lm;
 	int ich_res;
+	int dsc_pic_width;
 	int dsc_common_mode = 0;
-	int i;
-	int rc = 0;
+	int i, rc = 0;
 
 	sde_kms = sde_encoder_get_kms(&sde_enc->base);
 
@@ -412,33 +414,43 @@ static int _dce_dsc_setup_helper(struct sde_encoder_virt *sde_enc,
 	enc_master = sde_enc->cur_master;
 	roi = &sde_enc->cur_conn_roi;
 	dsc = &sde_enc->mode_info.comp_info.dsc_info;
+	num_lm = def->num_lm;
 	num_dsc = def->num_comp_enc;
 	num_intf = def->num_intf;
-	mode_3d = (topology == SDE_RM_TOPOLOGY_DUALPIPE_3DMERGE_DSC) ?
-			BLEND_3D_H_ROW_INT : BLEND_3D_NONE;
-	num_lm = def->num_lm;
+	mode_3d = (num_lm > num_dsc) ? BLEND_3D_H_ROW_INT : BLEND_3D_NONE;
+	merge_3d = (mode_3d != BLEND_3D_NONE) ? true : false;
 
 	half_panel_partial_update = _dce_check_half_panel_update(num_lm,
 			affected_displays);
-	merge_3d = (mode_3d != BLEND_3D_NONE) ? true : false;
 	dsc_merge = ((num_dsc > num_intf) && !half_panel_partial_update) ?
 			true : false;
 	disable_merge_3d = (merge_3d && half_panel_partial_update) ?
 			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.
 	 */
-	_dce_dsc_update_pic_dim(dsc, roi->w, roi->h);
+	if (num_dsc > 2) {
+		dsc_pic_width = roi->w / 2;
+		dsc->dsc_4hsmerge_en = dsc_4hsmerge;
+	} else
+		dsc_pic_width = roi->w;
+
+	_dce_dsc_update_pic_dim(dsc, dsc_pic_width, roi->h);
 
 	this_frame_slices = roi->w / dsc->config.slice_width;
 	intf_ip_w = this_frame_slices * dsc->config.slice_width;
 	enc_ip_w = intf_ip_w;
 
 	if (!half_panel_partial_update)
-		intf_ip_w /= def->num_intf;
+		intf_ip_w /= num_intf;
 	if (!half_panel_partial_update && (num_dsc > 1))
 		dsc_common_mode |= DSC_MODE_SPLIT_PANEL;
 	if (dsc_merge) {
@@ -470,7 +482,7 @@ static int _dce_dsc_setup_helper(struct sde_encoder_virt *sde_enc,
 	for (i = 0; i < num_dsc; i++) {
 		rc = _dce_dsc_setup_single(sde_enc, dsc, affected_displays, i,
 				roi, dsc_common_mode, merge_3d,
-				disable_merge_3d, mode_3d,
+				disable_merge_3d, mode_3d, dsc_4hsmerge,
 				half_panel_partial_update, ich_res);
 		if (rc)
 			break;

+ 16 - 4
msm/sde/sde_encoder_phys.h

@@ -603,16 +603,28 @@ void sde_encoder_helper_hw_reset(struct sde_encoder_phys *phys_enc);
 static inline enum sde_3d_blend_mode sde_encoder_helper_get_3d_blend_mode(
 		struct sde_encoder_phys *phys_enc)
 {
+	struct sde_kms *sde_kms;
 	enum sde_rm_topology_name topology;
+	const struct sde_rm_topology_def *def;
+	enum sde_enc_split_role split_role;
+	int num_lm;
+	bool mode_3d;
 
 	if (!phys_enc || phys_enc->enable_state == SDE_ENC_DISABLING)
 		return BLEND_3D_NONE;
 
+	sde_kms = sde_encoder_get_kms(phys_enc->parent);
 	topology = sde_connector_get_topology_name(phys_enc->connector);
-	if (phys_enc->split_role == ENC_ROLE_SOLO &&
-			(topology == SDE_RM_TOPOLOGY_DUALPIPE_3DMERGE ||
-			 topology == SDE_RM_TOPOLOGY_DUALPIPE_3DMERGE_DSC ||
-			topology == SDE_RM_TOPOLOGY_DUALPIPE_3DMERGE_VDC))
+	def = sde_rm_topology_get_topology_def(&sde_kms->rm, topology);
+	num_lm = def->num_lm;
+	mode_3d = (num_lm > def->num_comp_enc) ? true : false;
+	split_role = phys_enc->split_role;
+
+	if (split_role == ENC_ROLE_SOLO && num_lm == 2 && mode_3d)
+		return BLEND_3D_H_ROW_INT;
+
+	if ((split_role == ENC_ROLE_MASTER || split_role == ENC_ROLE_SLAVE)
+			&& num_lm == 4 && mode_3d)
 		return BLEND_3D_H_ROW_INT;
 
 	return BLEND_3D_NONE;

+ 1 - 1
msm/sde/sde_hw_catalog.h

@@ -87,7 +87,7 @@
 
 #define SDE_CTL_CFG_VERSION_1_0_0       0x100
 #define MAX_INTF_PER_CTL_V1                 2
-#define MAX_DSC_PER_CTL_V1                  2
+#define MAX_DSC_PER_CTL_V1                  4
 #define MAX_CWB_PER_CTL_V1                  2
 #define MAX_MERGE_3D_PER_CTL_V1             2
 #define MAX_WB_PER_CTL_V1                   1

+ 10 - 1
msm/sde/sde_hw_dsc_1_2.c

@@ -141,7 +141,11 @@ static void sde_hw_dsc_config(struct sde_hw_dsc *hw_dsc,
 		data |= BIT(0);
 
 	if (mode & DSC_MODE_MULTIPLEX) {
-		slice_count_per_enc = dsc->config.slice_count >> 1;
+		if (dsc->dsc_4hsmerge_en)
+			slice_count_per_enc = dsc->config.slice_count >> 2;
+		else
+			slice_count_per_enc = dsc->config.slice_count >> 1;
+
 		data |= BIT(1);
 	}
 
@@ -253,6 +257,11 @@ static void sde_hw_dsc_config(struct sde_hw_dsc *hw_dsc,
 		data |= BIT(13);
 	if (!(mode & DSC_MODE_VIDEO))
 		data |= BIT(17);
+	if (dsc->dsc_4hsmerge_en) {
+		data |= dsc->dsc_4hsmerge_padding << 18;
+		data |= dsc->dsc_4hsmerge_alignment << 22;
+		data |= BIT(16);
+	}
 
 	SDE_REG_WRITE(dsc_c, DSC_CFG + idx, data);
 }

+ 57 - 0
msm/sde/sde_rm.c

@@ -2133,6 +2133,63 @@ bool sde_rm_topology_is_quad_pipe(struct sde_rm *rm,
 	return false;
 }
 
+bool sde_rm_topology_is_dual_pipe(struct sde_rm *rm,
+		struct drm_crtc_state *state)
+{
+	int i;
+	struct sde_crtc_state *cstate;
+	uint64_t topology = SDE_RM_TOPOLOGY_NONE;
+
+	if ((!rm) || (!state)) {
+		pr_err("invalid arguments: rm:%d state:%d\n",
+				rm == NULL, state == NULL);
+		return false;
+	}
+
+	cstate = to_sde_crtc_state(state);
+
+	for (i = 0; i < cstate->num_connectors; i++) {
+		struct drm_connector *conn = cstate->connectors[i];
+
+		topology = sde_connector_get_topology_name(conn);
+		if (TOPOLOGY_DUALPIPE_MERGE_MODE(topology))
+			return true;
+	}
+
+	return false;
+}
+
+bool sde_rm_topology_is_3dmux_dsc(struct sde_rm *rm,
+		struct drm_crtc_state *state)
+{
+	int i;
+	struct sde_crtc_state *cstate;
+	uint64_t topology = SDE_RM_TOPOLOGY_NONE;
+	const struct sde_rm_topology_def *def;
+	int num_lm, num_enc;
+
+	if ((!rm) || (!state)) {
+		pr_err("invalid arguments: rm:%d state:%d\n",
+				rm == NULL, state == NULL);
+		return false;
+	}
+
+	cstate = to_sde_crtc_state(state);
+
+	for (i = 0; i < cstate->num_connectors; i++) {
+		struct drm_connector *conn = cstate->connectors[i];
+
+		topology = sde_connector_get_topology_name(conn);
+		def = sde_rm_topology_get_topology_def(rm, topology);
+		num_lm = def->num_lm;
+		num_enc = def->num_comp_enc;
+		if (num_lm > num_enc && num_enc)
+			return true;
+	}
+
+	return false;
+}
+
 /**
  * _sde_rm_release_rsvp - release resources and release a reservation
  * @rm:	KMS handle

+ 26 - 0
msm/sde/sde_rm.h

@@ -20,6 +20,12 @@
 		x == SDE_RM_TOPOLOGY_QUADPIPE_DSCMERGE ||\
 		x == SDE_RM_TOPOLOGY_QUADPIPE_DSC4HSMERGE)
 
+#define TOPOLOGY_DUALPIPE_MERGE_MODE(x) \
+	(x == SDE_RM_TOPOLOGY_DUALPIPE_DSCMERGE || \
+		x == SDE_RM_TOPOLOGY_DUALPIPE_3DMERGE || \
+		x == SDE_RM_TOPOLOGY_DUALPIPE_3DMERGE_VDC || \
+		x == SDE_RM_TOPOLOGY_DUALPIPE_3DMERGE_DSC)
+
 /**
  * enum sde_rm_topology_name - HW resource use case in use by connector
  * @SDE_RM_TOPOLOGY_NONE:                 No topology in use currently
@@ -343,6 +349,26 @@ static inline int sde_rm_topology_get_num_lm(struct sde_rm *rm,
 	return rm->topology_tbl[topology].num_lm;
 }
 
+/**
+ * sde_rm_topology_is_dual_pipe - check if the topology used
+ *	is a dual-pipe mode one
+ * @rm: SDE Resource Manager handle
+ * @state: drm state of the crtc
+ * @return: true if attached connector is in dual-pipe mode
+ */
+bool sde_rm_topology_is_dual_pipe(struct sde_rm *rm,
+		struct drm_crtc_state *state);
+
+/**
+ * sde_rm_topology_is_3dmux_dsc - check if the topology used
+ *	is a 3dmerge dsc mode one
+ * @rm: SDE Resource Manager handle
+ * @state: drm state of the crtc
+ * @return: true if attached connector is in 3DMERGE DSC mode
+ */
+bool sde_rm_topology_is_3dmux_dsc(struct sde_rm *rm,
+		struct drm_crtc_state *state);
+
 /**
  * sde_rm_topology_is_quad_pipe - check if the topology used
  *	is a quad-pipe mode one

+ 12 - 0
msm/sde_dsc_helper.c

@@ -295,6 +295,8 @@ int sde_dsc_populate_dsc_private_params(struct msm_display_dsc_info *dsc_info,
 	int slice_per_pkt, slice_per_intf;
 	int bytes_in_slice, total_bytes_per_intf;
 	u16 bpp;
+	u32 bytes_in_dsc_pair;
+	u32 total_bytes_in_dsc_pair;
 
 	if (!dsc_info || !dsc_info->config.slice_width ||
 			!dsc_info->config.slice_height ||
@@ -346,6 +348,16 @@ int sde_dsc_populate_dsc_private_params(struct msm_display_dsc_info *dsc_info,
 	dsc_info->bytes_per_pkt = bytes_in_slice * slice_per_pkt;
 	dsc_info->pkt_per_line = slice_per_intf / slice_per_pkt;
 
+	bytes_in_dsc_pair = DIV_ROUND_UP(bytes_in_slice * 2, 3);
+	if (bytes_in_dsc_pair % 8) {
+		dsc_info->dsc_4hsmerge_padding = 8 - (bytes_in_dsc_pair % 8);
+		total_bytes_in_dsc_pair = bytes_in_dsc_pair +
+				dsc_info->dsc_4hsmerge_padding;
+		if (total_bytes_in_dsc_pair % 16)
+			dsc_info->dsc_4hsmerge_alignment = 16 -
+					(total_bytes_in_dsc_pair % 16);
+	}
+
 	return 0;
 }