Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 491b012c authored by Abhijit Kulkarni's avatar Abhijit Kulkarni
Browse files

drm/msm/sde: support split display using single control path



This change adds support in encoders to use single control path
for split display use cases. Physical interface use the virtual
encoder's helper api to update the control path. Each physical
encoder only updates the active configuration in the control
path.

Change-Id: I9dc7013f8f11488b0ee6537385a58eb604f55fdc
Signed-off-by: default avatarAbhijit Kulkarni <kabhijit@codeaurora.org>
parent 659a40bc
Loading
Loading
Loading
Loading
+150 −2
Original line number Diff line number Diff line
@@ -728,6 +728,65 @@ void sde_encoder_destroy(struct drm_encoder *drm_enc)
	kfree(sde_enc);
}

void sde_encoder_helper_update_intf_cfg(
		struct sde_encoder_phys *phys_enc)
{
	struct sde_encoder_virt *sde_enc;
	struct sde_hw_intf_cfg_v1 *intf_cfg;
	enum sde_3d_blend_mode mode_3d;

	if (!phys_enc) {
		SDE_ERROR("invalid arg, encoder %d\n", phys_enc != 0);
		return;
	}

	sde_enc = to_sde_encoder_virt(phys_enc->parent);
	intf_cfg = &sde_enc->cur_master->intf_cfg_v1;

	SDE_DEBUG_ENC(sde_enc,
			"intf_cfg updated for %d at idx %d\n",
			phys_enc->intf_idx,
			intf_cfg->intf_count);


	/* setup interface configuration */
	if (intf_cfg->intf_count >= MAX_INTF_PER_CTL_V1) {
		pr_err("invalid inf_count %d\n", intf_cfg->intf_count);
		return;
	}
	intf_cfg->intf[intf_cfg->intf_count++] = phys_enc->intf_idx;
	if (phys_enc == sde_enc->cur_master) {
		if (sde_enc->cur_master->intf_mode == INTF_MODE_CMD)
			intf_cfg->intf_mode_sel = SDE_CTL_MODE_SEL_CMD;
		else
			intf_cfg->intf_mode_sel = SDE_CTL_MODE_SEL_VID;
	}

	/* configure this interface as master for split display */
	if (phys_enc->split_role == ENC_ROLE_MASTER)
		intf_cfg->intf_master = phys_enc->hw_intf->idx;

	/* setup which pp blk will connect to this intf */
	if (phys_enc->hw_intf->ops.bind_pingpong_blk)
		phys_enc->hw_intf->ops.bind_pingpong_blk(
				phys_enc->hw_intf,
				true,
				phys_enc->hw_pp->idx);


	/*setup merge_3d configuration */
	mode_3d = sde_encoder_helper_get_3d_blend_mode(phys_enc);

	if (mode_3d && phys_enc->hw_pp->merge_3d &&
			intf_cfg->merge_3d_count < MAX_MERGE_3D_PER_CTL_V1)
		intf_cfg->merge_3d[intf_cfg->merge_3d_count++] =
			phys_enc->hw_pp->merge_3d->idx;

	if (phys_enc->hw_pp->ops.setup_3d_mode)
		phys_enc->hw_pp->ops.setup_3d_mode(phys_enc->hw_pp,
				mode_3d);
}

void sde_encoder_helper_split_config(
		struct sde_encoder_phys *phys_enc,
		enum sde_intf interface)
@@ -1086,6 +1145,9 @@ static void _sde_encoder_dsc_pipe_cfg(struct sde_hw_dsc *hw_dsc,
	if (hw_pp->ops.setup_dsc)
		hw_pp->ops.setup_dsc(hw_pp);

	if (hw_dsc->ops.bind_pingpong_blk)
		hw_dsc->ops.bind_pingpong_blk(hw_dsc, true, hw_pp->idx);

	if (hw_pp->ops.enable_dsc)
		hw_pp->ops.enable_dsc(hw_pp);
}
@@ -1121,6 +1183,8 @@ static int _sde_encoder_dsc_n_lm_1_enc_1_intf(struct sde_encoder_virt *sde_enc)
	const struct sde_rect *roi = &sde_enc->cur_conn_roi;
	struct msm_mode_info mode_info;
	struct msm_display_dsc_info *dsc = NULL;
	struct sde_hw_ctl *hw_ctl = enc_master->hw_ctl;
	struct sde_ctl_dsc_cfg cfg;
	int rc;

	if (hw_dsc == NULL || hw_pp == NULL || !enc_master) {
@@ -1134,8 +1198,8 @@ static int _sde_encoder_dsc_n_lm_1_enc_1_intf(struct sde_encoder_virt *sde_enc)
		return -EINVAL;
	}

	memset(&cfg, 0, sizeof(cfg));
	dsc = &mode_info.comp_info.dsc_info;

	_sde_encoder_dsc_update_pic_dim(dsc, roi->w, roi->h);

	this_frame_slices = roi->w / dsc->slice_width;
@@ -1156,6 +1220,25 @@ static int _sde_encoder_dsc_n_lm_1_enc_1_intf(struct sde_encoder_virt *sde_enc)

	_sde_encoder_dsc_pipe_cfg(hw_dsc, hw_pp, dsc, dsc_common_mode,
			ich_res, true);
	if (cfg.dsc_count >= MAX_DSC_PER_CTL_V1) {
		pr_err("Invalid dsc count:%d\n", cfg.dsc_count);
		return -EINVAL;
	}
	cfg.dsc[cfg.dsc_count++] = hw_dsc->idx;

	/* setup dsc active configuration in the control path */
	if (hw_ctl->ops.setup_dsc_cfg) {
		hw_ctl->ops.setup_dsc_cfg(hw_ctl, &cfg);
		SDE_DEBUG_ENC(sde_enc,
				"setup dsc_cfg hw_ctl[%d], count:%d,dsc[0]:%d, dsc[1]:%d\n",
				hw_ctl->idx,
				cfg.dsc_count,
				cfg.dsc[0],
				cfg.dsc[1]);
	}

	if (hw_ctl->ops.update_bitmask_dsc)
		hw_ctl->ops.update_bitmask_dsc(hw_ctl, hw_dsc->idx, 1);

	return 0;
}
@@ -1174,8 +1257,12 @@ static int _sde_encoder_dsc_2_lm_2_enc_2_intf(struct sde_encoder_virt *sde_enc,
	struct msm_display_dsc_info dsc[MAX_CHANNELS_PER_ENC];
	struct msm_mode_info mode_info;
	bool half_panel_partial_update;
	struct sde_hw_ctl *hw_ctl = enc_master->hw_ctl;
	struct sde_ctl_dsc_cfg cfg;
	int i, rc;

	memset(&cfg, 0, sizeof(cfg));

	for (i = 0; i < MAX_CHANNELS_PER_ENC; i++) {
		hw_pp[i] = sde_enc->hw_pp[i];
		hw_dsc[i] = sde_enc->hw_dsc[i];
@@ -1249,8 +1336,32 @@ static int _sde_encoder_dsc_2_lm_2_enc_2_intf(struct sde_encoder_virt *sde_enc,
				dsc_common_mode, i, active);
		_sde_encoder_dsc_pipe_cfg(hw_dsc[i], hw_pp[i], &dsc[i],
				dsc_common_mode, ich_res, active);

		if (active) {
			if (cfg.dsc_count >= MAX_DSC_PER_CTL_V1) {
				pr_err("Invalid dsc count:%d\n",
						cfg.dsc_count);
				return -EINVAL;
			}
			cfg.dsc[i] = hw_dsc[i]->idx;
			cfg.dsc_count++;

			if (hw_ctl->ops.update_bitmask_dsc)
				hw_ctl->ops.update_bitmask_dsc(hw_ctl,
						hw_dsc[i]->idx, 1);
		}
	}

	/* setup dsc active configuration in the control path */
	if (hw_ctl->ops.setup_dsc_cfg) {
		hw_ctl->ops.setup_dsc_cfg(hw_ctl, &cfg);
		SDE_DEBUG_ENC(sde_enc,
				"setup dsc_cfg hw_ctl[%d], count:%d,dsc[0]:%d, dsc[1]:%d\n",
				hw_ctl->idx,
				cfg.dsc_count,
				cfg.dsc[0],
				cfg.dsc[1]);
	}
	return 0;
}

@@ -1268,8 +1379,12 @@ static int _sde_encoder_dsc_2_lm_2_enc_1_intf(struct sde_encoder_virt *sde_enc,
	struct msm_display_dsc_info *dsc = NULL;
	struct msm_mode_info mode_info;
	bool half_panel_partial_update;
	struct sde_hw_ctl *hw_ctl = enc_master->hw_ctl;
	struct sde_ctl_dsc_cfg cfg;
	int i, rc;

	memset(&cfg, 0, sizeof(cfg));

	for (i = 0; i < MAX_CHANNELS_PER_ENC; i++) {
		hw_pp[i] = sde_enc->hw_pp[i];
		hw_dsc[i] = sde_enc->hw_dsc[i];
@@ -1320,9 +1435,31 @@ static int _sde_encoder_dsc_2_lm_2_enc_1_intf(struct sde_encoder_virt *sde_enc,

	_sde_encoder_dsc_pipe_cfg(hw_dsc[0], hw_pp[0], dsc, dsc_common_mode,
			ich_res, true);
	cfg.dsc[0] = hw_dsc[0]->idx;
	cfg.dsc_count++;
	if (hw_ctl->ops.update_bitmask_dsc)
		hw_ctl->ops.update_bitmask_dsc(hw_ctl, hw_dsc[0]->idx, 1);


	_sde_encoder_dsc_pipe_cfg(hw_dsc[1], hw_pp[1], dsc, dsc_common_mode,
			ich_res, !half_panel_partial_update);

	if (!half_panel_partial_update) {
		cfg.dsc[1] = hw_dsc[1]->idx;
		cfg.dsc_count++;
		if (hw_ctl->ops.update_bitmask_dsc)
			hw_ctl->ops.update_bitmask_dsc(hw_ctl, hw_dsc[1]->idx,
					1);
	}
	/* setup dsc active configuration in the control path */
	if (hw_ctl->ops.setup_dsc_cfg) {
		hw_ctl->ops.setup_dsc_cfg(hw_ctl, &cfg);
		SDE_DEBUG_ENC(sde_enc,
				"setup_dsc_cfg hw_ctl[%d], count:%d,dsc[0]:%d, dsc[1]:%d\n",
				hw_ctl->idx,
				cfg.dsc_count,
				cfg.dsc[0],
				cfg.dsc[1]);
	}
	return 0;
}

@@ -2480,6 +2617,12 @@ static void _sde_encoder_virt_enable_helper(struct drm_encoder *drm_enc)
				sde_enc->cur_master->hw_mdptop,
				sde_kms->catalog);

	if (sde_enc->cur_master->hw_ctl &&
			sde_enc->cur_master->hw_ctl->ops.setup_intf_cfg_v1)
		sde_enc->cur_master->hw_ctl->ops.setup_intf_cfg_v1(
				sde_enc->cur_master->hw_ctl,
				&sde_enc->cur_master->intf_cfg_v1);

	_sde_encoder_update_vsync_source(sde_enc, &sde_enc->disp_info, false);
	sde_encoder_control_te(drm_enc, true);

@@ -2497,6 +2640,8 @@ void sde_encoder_virt_restore(struct drm_encoder *drm_enc)
		return;
	}
	sde_enc = to_sde_encoder_virt(drm_enc);
	memset(&sde_enc->cur_master->intf_cfg_v1, 0,
			sizeof(sde_enc->cur_master->intf_cfg_v1));

	for (i = 0; i < sde_enc->num_phys_encs; i++) {
		struct sde_encoder_phys *phys = sde_enc->phys_encs[i];
@@ -2575,6 +2720,9 @@ static void sde_encoder_virt_enable(struct drm_encoder *drm_enc)
		return;
	}

	memset(&sde_enc->cur_master->intf_cfg_v1, 0,
			sizeof(sde_enc->cur_master->intf_cfg_v1));

	for (i = 0; i < sde_enc->num_phys_encs; i++) {
		struct sde_encoder_phys *phys = sde_enc->phys_encs[i];

+15 −7
Original line number Diff line number Diff line
@@ -236,6 +236,7 @@ struct sde_encoder_irq {
 * @parent_ops:		Callbacks exposed by the parent to the phys_enc
 * @hw_mdptop:		Hardware interface to the top registers
 * @hw_ctl:		Hardware interface to the ctl registers
 * @hw_intf:		Hardware interface to INTF registers
 * @hw_cdm:		Hardware interface to the cdm registers
 * @cdm_cfg:		Chroma-down hardware configuration
 * @hw_pp:		Hardware interface to the ping pong registers
@@ -245,6 +246,9 @@ struct sde_encoder_irq {
 * @split_role:		Role to play in a split-panel configuration
 * @intf_mode:		Interface mode
 * @intf_idx:		Interface index on sde hardware
 * @intf_cfg:		Interface hardware configuration
 * @intf_cfg_v1:        Interface hardware configuration to be used if control
 *                      path supports SDE_CTL_ACTIVE_CFG
 * @comp_type:      Type of compression supported
 * @enc_spinlock:	Virtual-Encoder-Wide Spin Lock for IRQ purposes
 * @enable_state:	Enable state tracking
@@ -269,6 +273,7 @@ struct sde_encoder_phys {
	struct sde_encoder_virt_ops parent_ops;
	struct sde_hw_mdp *hw_mdptop;
	struct sde_hw_ctl *hw_ctl;
	struct sde_hw_intf *hw_intf;
	struct sde_hw_cdm *hw_cdm;
	struct sde_hw_cdm_cfg cdm_cfg;
	struct sde_hw_pingpong *hw_pp;
@@ -277,6 +282,8 @@ struct sde_encoder_phys {
	enum sde_enc_split_role split_role;
	enum sde_intf_mode intf_mode;
	enum sde_intf intf_idx;
	struct sde_hw_intf_cfg intf_cfg;
	struct sde_hw_intf_cfg_v1 intf_cfg_v1;
	enum msm_display_compression_type comp_type;
	spinlock_t *enc_spinlock;
	enum sde_enc_enable_state enable_state;
@@ -300,7 +307,6 @@ static inline int sde_encoder_phys_inc_pending(struct sde_encoder_phys *phys)
 * struct sde_encoder_phys_vid - sub-class of sde_encoder_phys to handle video
 *	mode specific operations
 * @base:	Baseclass physical encoder structure
 * @hw_intf:	Hardware interface to the intf registers
 * @timing_params: Current timing parameter
 * @rot_fetch:	Prefill for inline rotation
 * @error_count: Number of consecutive kickoffs that experienced an error
@@ -308,7 +314,6 @@ static inline int sde_encoder_phys_inc_pending(struct sde_encoder_phys *phys)
 */
struct sde_encoder_phys_vid {
	struct sde_encoder_phys base;
	struct sde_hw_intf *hw_intf;
	struct intf_timing_params timing_params;
	struct intf_prog_fetch rot_fetch;
	int error_count;
@@ -366,9 +371,6 @@ struct sde_encoder_phys_cmd {
 * @wbdone_complete:	for wbdone irq synchronization
 * @wb_cfg:		Writeback hardware configuration
 * @cdp_cfg:		Writeback CDP configuration
 * @intf_cfg:		Interface hardware configuration
 * @intf_cfg_v1:        Interface hardware configuration to be used if control
 *                      path supports SDE_CTL_ACTIVE_CFG
 * @wb_roi:		Writeback region-of-interest
 * @wb_fmt:		Writeback pixel format
 * @wb_fb:		Pointer to current writeback framebuffer
@@ -393,8 +395,6 @@ struct sde_encoder_phys_wb {
	struct completion wbdone_complete;
	struct sde_hw_wb_cfg wb_cfg;
	struct sde_hw_wb_cdp_cfg cdp_cfg;
	struct sde_hw_intf_cfg intf_cfg;
	struct sde_hw_intf_cfg_v1 intf_cfg_v1;
	struct sde_rect wb_roi;
	const struct sde_format *wb_fmt;
	struct drm_framebuffer *wb_fb;
@@ -596,4 +596,12 @@ int sde_encoder_helper_register_irq(struct sde_encoder_phys *phys_enc,
int sde_encoder_helper_unregister_irq(struct sde_encoder_phys *phys_enc,
		enum sde_intr_idx intr_idx);

/**
 * sde_encoder_helper_update_intf_cfg - update interface configuration for
 *                                      single control path.
 * @phys_enc: Pointer to physical encoder structure
 */
void sde_encoder_helper_update_intf_cfg(
		struct sde_encoder_phys *phys_enc);

#endif /* __sde_encoder_phys_H__ */
+50 −17
Original line number Diff line number Diff line
@@ -123,19 +123,37 @@ static void _sde_encoder_phys_cmd_config_autorefresh(
static void _sde_encoder_phys_cmd_update_flush_mask(
		struct sde_encoder_phys *phys_enc)
{
	struct sde_encoder_phys_cmd *cmd_enc =
			to_sde_encoder_phys_cmd(phys_enc);
	struct sde_encoder_phys_cmd *cmd_enc;
	struct sde_hw_ctl *ctl;
	bool merge_3d_enable = false;

	if (!phys_enc)
	if (!phys_enc && !phys_enc->hw_intf && !phys_enc->hw_pp)
		return;

	cmd_enc = to_sde_encoder_phys_cmd(phys_enc);
	ctl = phys_enc->hw_ctl;
	if (!ctl || !ctl->ops.update_bitmask_intf)

	if (!ctl)
		return;

	if (!ctl->ops.update_bitmask_intf ||
		(test_bit(SDE_CTL_ACTIVE_CFG, &ctl->caps->features) &&
		!ctl->ops.update_bitmask_merge3d)) {
		SDE_ERROR("invalid hw_ctl ops %d\n", ctl->idx);
		return;
	}

	if (sde_encoder_helper_get_3d_blend_mode(phys_enc) != BLEND_3D_NONE)
		merge_3d_enable = true;

	ctl->ops.update_bitmask_intf(ctl, phys_enc->intf_idx, 1);


	if (test_bit(SDE_CTL_ACTIVE_CFG, &ctl->caps->features) &&
			phys_enc->hw_pp->merge_3d)
		ctl->ops.update_bitmask_merge3d(ctl,
			phys_enc->hw_pp->merge_3d->idx, merge_3d_enable);

	SDE_DEBUG_CMDENC(cmd_enc, "update pending flush ctl %d intf_idx %x\n",
			ctl->idx - CTL_0, phys_enc->intf_idx);
}
@@ -146,20 +164,26 @@ static void _sde_encoder_phys_cmd_update_intf_cfg(
	struct sde_encoder_phys_cmd *cmd_enc =
			to_sde_encoder_phys_cmd(phys_enc);
	struct sde_hw_ctl *ctl;
	struct sde_hw_intf_cfg intf_cfg = { 0 };

	if (!phys_enc)
		return;

	ctl = phys_enc->hw_ctl;
	if (!ctl || !ctl->ops.setup_intf_cfg)
	if (!ctl)
		return;

	if (ctl->ops.setup_intf_cfg) {
		struct sde_hw_intf_cfg intf_cfg = { 0 };

		intf_cfg.intf = phys_enc->intf_idx;
		intf_cfg.intf_mode_sel = SDE_CTL_MODE_SEL_CMD;
		intf_cfg.stream_sel = cmd_enc->stream_sel;
	intf_cfg.mode_3d = sde_encoder_helper_get_3d_blend_mode(phys_enc);
		intf_cfg.mode_3d =
			sde_encoder_helper_get_3d_blend_mode(phys_enc);
		ctl->ops.setup_intf_cfg(ctl, &intf_cfg);
	} else if (test_bit(SDE_CTL_ACTIVE_CFG, &ctl->caps->features)) {
		sde_encoder_helper_update_intf_cfg(phys_enc);
	}
}

static void sde_encoder_phys_cmd_pp_tx_done_irq(void *arg, int irq_idx)
@@ -417,6 +441,19 @@ static void sde_encoder_phys_cmd_mode_set(
		return;
	}

	sde_rm_init_hw_iter(&iter, phys_enc->parent->base.id, SDE_HW_BLK_INTF);
	for (i = 0; i <= instance; i++) {
		if (sde_rm_get_hw(rm, &iter))
			phys_enc->hw_intf = (struct sde_hw_intf *)iter.hw;
	}

	if (IS_ERR_OR_NULL(phys_enc->hw_intf)) {
		SDE_ERROR_CMDENC(cmd_enc, "failed to init intf: %ld\n",
				PTR_ERR(phys_enc->hw_intf));
		phys_enc->hw_intf = NULL;
		return;
	}

	_sde_encoder_phys_cmd_setup_irq_hw_idx(phys_enc);
}

@@ -831,8 +868,7 @@ static void _sde_encoder_phys_cmd_pingpong_config(
	struct sde_encoder_phys_cmd *cmd_enc =
		to_sde_encoder_phys_cmd(phys_enc);

	if (!phys_enc || !phys_enc->hw_ctl || !phys_enc->hw_pp
			|| !phys_enc->hw_ctl->ops.setup_intf_cfg) {
	if (!phys_enc || !phys_enc->hw_ctl || !phys_enc->hw_pp) {
		SDE_ERROR("invalid arg(s), enc %d\n", phys_enc != 0);
		return;
	}
@@ -858,8 +894,6 @@ static bool sde_encoder_phys_cmd_needs_single_flush(
static void sde_encoder_phys_cmd_enable_helper(
		struct sde_encoder_phys *phys_enc)
{
	struct sde_hw_ctl *ctl;

	if (!phys_enc || !phys_enc->hw_ctl || !phys_enc->hw_pp) {
		SDE_ERROR("invalid arg(s), encoder %d\n", phys_enc != 0);
		return;
@@ -877,8 +911,7 @@ static void sde_encoder_phys_cmd_enable_helper(
		!sde_encoder_phys_cmd_is_master(phys_enc))
		goto skip_flush;

	ctl = phys_enc->hw_ctl;
	ctl->ops.update_bitmask_intf(ctl, phys_enc->intf_idx, 1);
	_sde_encoder_phys_cmd_update_flush_mask(phys_enc);

skip_flush:
	return;
+90 −87

File changed.

Preview size limit exceeded, changes collapsed.

+2 −2
Original line number Diff line number Diff line
@@ -423,7 +423,7 @@ static void sde_encoder_phys_wb_setup_cdp(struct sde_encoder_phys *phys_enc,
	if (test_bit(SDE_CTL_ACTIVE_CFG, &ctl->caps->features) &&
		(phys_enc->hw_ctl &&
		 phys_enc->hw_ctl->ops.setup_intf_cfg_v1)) {
		struct sde_hw_intf_cfg_v1 *intf_cfg_v1 = &wb_enc->intf_cfg_v1;
		struct sde_hw_intf_cfg_v1 *intf_cfg_v1 = &phys_enc->intf_cfg_v1;
		struct sde_hw_pingpong *hw_pp = phys_enc->hw_pp;
		enum sde_3d_blend_mode mode_3d;

@@ -454,7 +454,7 @@ static void sde_encoder_phys_wb_setup_cdp(struct sde_encoder_phys *phys_enc,
		phys_enc->hw_ctl->ops.setup_intf_cfg_v1(phys_enc->hw_ctl,
				intf_cfg_v1);
	} else if (phys_enc->hw_ctl && phys_enc->hw_ctl->ops.setup_intf_cfg) {
		struct sde_hw_intf_cfg *intf_cfg = &wb_enc->intf_cfg;
		struct sde_hw_intf_cfg *intf_cfg = &phys_enc->intf_cfg;

		memset(intf_cfg, 0, sizeof(struct sde_hw_intf_cfg));

Loading