浏览代码

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

qctecmdr 5 年之前
父节点
当前提交
8975496690
共有 11 个文件被更改,包括 189 次插入62 次删除
  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. 20 7
      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:
@@ -2215,6 +2209,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");
@@ -2276,17 +2271,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);
@@ -2493,6 +2496,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;
@@ -2502,11 +2506,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))
@@ -2533,15 +2542,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

@@ -313,7 +313,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;
@@ -345,8 +346,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,
@@ -401,15 +403,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);
 
@@ -420,33 +422,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) {
@@ -478,7 +490,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;

+ 20 - 7
msm/sde/sde_encoder_phys.h

@@ -603,16 +603,29 @@ 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)
 {
-	enum sde_rm_topology_name topology;
+	struct msm_display_topology def;
+	enum sde_enc_split_role split_role;
+	int ret, num_lm;
+	bool mode_3d;
 
-	if (!phys_enc || phys_enc->enable_state == SDE_ENC_DISABLING)
+	if (!phys_enc || phys_enc->enable_state == SDE_ENC_DISABLING ||
+			!phys_enc->connector || !phys_enc->connector->state)
 		return BLEND_3D_NONE;
 
-	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))
+	ret = sde_connector_state_get_topology
+			(phys_enc->connector->state, &def);
+	if (ret)
+		return BLEND_3D_NONE;
+
+	num_lm = def.num_lm;
+	mode_3d = (num_lm > def.num_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

@@ -2142,6 +2142,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

@@ -309,6 +309,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 ||
@@ -360,6 +362,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;
 }