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

Commit 8468632e authored by Prabhanjan Kandula's avatar Prabhanjan Kandula
Browse files

drm/msm/sde: add cwb support for single ctl path



MDSS hardware supports single CTL path starting SM8150 chipset.
It needs mux configuration update starting for this hardware due
to single CTL path. Change also includes ping-pong overflow irq
handling for the additional ping-pong blocks in SM8150.

Change-Id: I3f2ba272562b7f0967621b3b6aa029ef501b02db
Signed-off-by: default avatarPrabhanjan Kandula <pkandula@codeaurora.org>
parent 8dd0536e
Loading
Loading
Loading
Loading
+5 −1
Original line number Diff line number Diff line
@@ -202,7 +202,9 @@ struct sde_encoder_phys_ops {
 * @INTR_IDX_RDPTR:    Readpointer done unterrupt for cmd mode panel
 * @INTR_IDX_WB_DONE:  Writeback done interrupt for WB
 * @INTR_IDX_PP2_OVFL: Pingpong overflow interrupt on PP2 for Concurrent WB
 * @INTR_IDX_PP2_OVFL: Pingpong overflow interrupt on PP3 for Concurrent WB
 * @INTR_IDX_PP3_OVFL: Pingpong overflow interrupt on PP3 for Concurrent WB
 * @INTR_IDX_PP4_OVFL: Pingpong overflow interrupt on PP4 for Concurrent WB
 * @INTR_IDX_PP5_OVFL: Pingpong overflow interrupt on PP5 for Concurrent WB
 * @INTR_IDX_AUTOREFRESH_DONE:  Autorefresh done for cmd mode panel meaning
 *                              autorefresh has triggered a double buffer flip
 */
@@ -216,6 +218,8 @@ enum sde_intr_idx {
	INTR_IDX_WB_DONE,
	INTR_IDX_PP2_OVFL,
	INTR_IDX_PP3_OVFL,
	INTR_IDX_PP4_OVFL,
	INTR_IDX_PP5_OVFL,
	INTR_IDX_MAX,
};

+126 −21
Original line number Diff line number Diff line
@@ -33,6 +33,11 @@
#define TO_S15D16(_x_)	((_x_) << 7)

#define MULTIPLE_CONN_DETECTED(x) (x > 1)

static const u32 cwb_irq_tbl[PINGPONG_MAX] = {SDE_NONE, SDE_NONE,
	INTR_IDX_PP2_OVFL, INTR_IDX_PP3_OVFL, INTR_IDX_PP4_OVFL,
	INTR_IDX_PP5_OVFL, SDE_NONE, SDE_NONE};

/**
 * sde_rgb2yuv_601l - rgb to yuv color space conversion matrix
 *
@@ -471,26 +476,66 @@ static void _sde_encoder_phys_wb_setup_cwb(struct sde_encoder_phys *phys_enc,
{
	struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc);
	struct sde_hw_wb *hw_wb = wb_enc->hw_wb;
	struct sde_hw_intf_cfg *intf_cfg = &phys_enc->intf_cfg;
	struct sde_hw_ctl *hw_ctl = phys_enc->hw_ctl;
	struct sde_crtc *crtc = to_sde_crtc(wb_enc->crtc);
	struct sde_hw_pingpong *hw_pp = phys_enc->hw_pp;
	bool need_merge = crtc->num_mixers > 1 ? true : false;
	int i = 0;

	if (!phys_enc->in_clone_mode) {
		SDE_DEBUG("not in CWB mode. early return\n");
		return;
	}

	if (!hw_pp || !hw_ctl || !hw_wb || hw_pp->idx >= PINGPONG_MAX) {
		SDE_ERROR("invalid hw resources - return\n");
		return;
	}

	hw_ctl = crtc->mixers[0].hw_ctl;
	if (hw_ctl && hw_ctl->ops.setup_intf_cfg_v1 &&
			test_bit(SDE_WB_CWB_CTRL, &hw_wb->caps->features)) {
		struct sde_hw_intf_cfg_v1 intf_cfg = { 0, };

		for (i = 0; i < crtc->num_mixers; i++)
			intf_cfg.cwb[intf_cfg.cwb_count++] =
				(enum sde_cwb)(hw_pp->idx + i);

		if (enable && hw_pp->merge_3d && (intf_cfg.merge_3d_count <
				MAX_MERGE_3D_PER_CTL_V1) && need_merge)
			intf_cfg.merge_3d[intf_cfg.merge_3d_count++] =
				hw_pp->merge_3d->idx;

		if (hw_pp->ops.setup_3d_mode)
			hw_pp->ops.setup_3d_mode(hw_pp, (enable && need_merge) ?
					BLEND_3D_H_ROW_INT : 0);

		if (hw_wb->ops.bind_pingpong_blk)
			hw_wb->ops.bind_pingpong_blk(hw_wb, enable, hw_pp->idx);

		if (hw_ctl->ops.update_cwb_cfg) {
			hw_ctl->ops.update_cwb_cfg(hw_ctl, &intf_cfg);
			SDE_DEBUG("in CWB mode on CTL_%d PP-%d merge3d:%d\n",
					hw_ctl->idx - CTL_0,
					hw_pp->idx - PINGPONG_0,
					hw_pp->merge_3d ?
					hw_pp->merge_3d->idx - MERGE_3D_0 : -1);
		}
	} else {
		struct sde_hw_intf_cfg *intf_cfg = &phys_enc->intf_cfg;

		memset(intf_cfg, 0, sizeof(struct sde_hw_intf_cfg));
		intf_cfg->intf = SDE_NONE;
		intf_cfg->wb = hw_wb->idx;

	hw_ctl = crtc->mixers[0].hw_ctl;
		if (hw_ctl && hw_ctl->ops.update_wb_cfg) {
			hw_ctl->ops.update_wb_cfg(hw_ctl, intf_cfg, enable);
			SDE_DEBUG("in CWB mode adding WB for CTL_%d\n",
					hw_ctl->idx - CTL_0);
		}
	}
}

/**
 * sde_encoder_phys_wb_setup_cdp - setup chroma down prefetch block
 * @phys_enc:	Pointer to physical encoder
@@ -801,9 +846,15 @@ static void _sde_encoder_phys_wb_update_cwb_flush(
	struct sde_hw_wb *hw_wb;
	struct sde_hw_ctl *hw_ctl;
	struct sde_hw_cdm *hw_cdm;
	struct sde_hw_pingpong *hw_pp;
	struct sde_crtc *crtc;
	struct sde_crtc_state *crtc_state;
	int capture_point = 0;
	int i = 0;
	int cwb_capture_mode = 0;
	enum sde_cwb cwb_idx = 0;
	enum sde_cwb src_pp_idx = 0;
	bool dspp_out = false;
	bool need_merge = false;

	if (!phys_enc->in_clone_mode) {
		SDE_DEBUG("not in CWB mode. early return\n");
@@ -813,30 +864,59 @@ static void _sde_encoder_phys_wb_update_cwb_flush(
	wb_enc = to_sde_encoder_phys_wb(phys_enc);
	crtc = to_sde_crtc(wb_enc->crtc);
	crtc_state = to_sde_crtc_state(wb_enc->crtc->state);
	cwb_capture_mode = sde_crtc_get_property(crtc_state,
			CRTC_PROP_CAPTURE_OUTPUT);

	hw_pp = phys_enc->hw_pp;
	hw_wb = wb_enc->hw_wb;
	hw_cdm = phys_enc->hw_cdm;

	/* In CWB mode, program actual source master sde_hw_ctl from crtc */
	hw_ctl = crtc->mixers[0].hw_ctl;
	if (!hw_ctl) {
		SDE_DEBUG("[wb:%d] no ctl assigned for CWB\n",
				hw_wb->idx - WB_0);
	if (!hw_ctl || !hw_wb || !hw_pp) {
		SDE_ERROR("[wb] HW resource not available for CWB\n");
		return;
	}

	capture_point  = sde_crtc_get_property(crtc_state,
			CRTC_PROP_CAPTURE_OUTPUT);
	/* treating LM idx of primary display ctl path as source ping-pong idx*/
	src_pp_idx = (enum sde_cwb)crtc->mixers[0].hw_lm->idx;
	cwb_idx = (enum sde_cwb)hw_pp->idx;
	dspp_out = (cwb_capture_mode == CAPTURE_DSPP_OUT);
	need_merge = (crtc->num_mixers > 1) ? true : false;

	phys_enc->hw_mdptop->ops.set_cwb_ppb_cntl(phys_enc->hw_mdptop,
			crtc->num_mixers == CRTC_DUAL_MIXERS,
			capture_point == CAPTURE_DSPP_OUT);
	if (src_pp_idx > LM_0 ||  ((cwb_idx + crtc->num_mixers) > CWB_MAX)) {
		SDE_ERROR("invalid hw config for CWB\n");
		return;
	}

	if (hw_ctl->ops.update_bitmask_wb)
		hw_ctl->ops.update_bitmask_wb(hw_ctl, hw_wb->idx, 1);

	if (hw_ctl->ops.update_bitmask_cdm && hw_cdm)
		hw_ctl->ops.update_bitmask_cdm(hw_ctl, hw_cdm->idx, 1);

	if (test_bit(SDE_WB_CWB_CTRL, &hw_wb->caps->features)) {
		for (i = 0; i < crtc->num_mixers; i++) {
			cwb_idx = (enum sde_cwb) (hw_pp->idx + i);
			src_pp_idx = (enum sde_cwb) (src_pp_idx + i);

			if (hw_wb->ops.program_cwb_ctrl)
				hw_wb->ops.program_cwb_ctrl(hw_wb, cwb_idx,
						src_pp_idx, dspp_out);

			if (hw_ctl->ops.update_bitmask_cwb)
				hw_ctl->ops.update_bitmask_cwb(hw_ctl,
						cwb_idx, 1);
		}

		if (need_merge && hw_ctl->ops.update_bitmask_merge3d
				&& hw_pp && hw_pp->merge_3d)
			hw_ctl->ops.update_bitmask_merge3d(hw_ctl,
					hw_pp->merge_3d->idx, 1);
	} else {
		phys_enc->hw_mdptop->ops.set_cwb_ppb_cntl(phys_enc->hw_mdptop,
				need_merge, dspp_out);
	}
}

/**
@@ -1035,6 +1115,7 @@ static void sde_encoder_phys_wb_irq_ctrl(

	struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys);
	int index = 0;
	int pp = 0;

	if (!wb_enc)
		return;
@@ -1042,21 +1123,25 @@ static void sde_encoder_phys_wb_irq_ctrl(
	if (wb_enc->bypass_irqreg)
		return;

	pp = phys->hw_pp->idx - PINGPONG_0;
	if ((pp + CRTC_DUAL_MIXERS) >= PINGPONG_MAX) {
		SDE_ERROR("invalid pingpong index for WB or CWB\n");
		return;
	}

	if (enable) {
		sde_encoder_helper_register_irq(phys, INTR_IDX_WB_DONE);
		if (phys->in_clone_mode) {
			for (index = 0; index < CRTC_DUAL_MIXERS; index++)
				sde_encoder_helper_register_irq(phys,
						index ? INTR_IDX_PP3_OVFL
						: INTR_IDX_PP2_OVFL);
						cwb_irq_tbl[index + pp]);
		}
	} else {
		sde_encoder_helper_unregister_irq(phys, INTR_IDX_WB_DONE);
		if (phys->in_clone_mode) {
			for (index = 0; index < CRTC_DUAL_MIXERS; index++)
				sde_encoder_helper_unregister_irq(phys,
						index ? INTR_IDX_PP3_OVFL
						: INTR_IDX_PP2_OVFL);
						cwb_irq_tbl[index + pp]);
		}
	}
}
@@ -1733,6 +1818,26 @@ struct sde_encoder_phys *sde_encoder_phys_wb_init(
	irq->cb.arg = wb_enc;
	irq->cb.func = sde_encoder_phys_cwb_ovflow;

	irq = &phys_enc->irq[INTR_IDX_PP4_OVFL];
	INIT_LIST_HEAD(&irq->cb.list);
	irq->name = "pp4_overflow";
	irq->hw_idx = CWB_4;
	irq->irq_idx = -1;
	irq->intr_type = SDE_IRQ_TYPE_CWB_OVERFLOW;
	irq->intr_idx = INTR_IDX_PP4_OVFL;
	irq->cb.arg = wb_enc;
	irq->cb.func = sde_encoder_phys_cwb_ovflow;

	irq = &phys_enc->irq[INTR_IDX_PP5_OVFL];
	INIT_LIST_HEAD(&irq->cb.list);
	irq->name = "pp5_overflow";
	irq->hw_idx = CWB_5;
	irq->irq_idx = -1;
	irq->intr_type = SDE_IRQ_TYPE_CWB_OVERFLOW;
	irq->intr_idx = INTR_IDX_PP5_OVFL;
	irq->cb.arg = wb_enc;
	irq->cb.func = sde_encoder_phys_cwb_ovflow;

	/* create internal buffer for disable logic */
	if (_sde_encoder_phys_wb_init_internal_fb(wb_enc,
				DRM_FORMAT_RGB888, 2, 1, 6)) {
+5 −1
Original line number Diff line number Diff line
@@ -1876,8 +1876,11 @@ static int sde_wb_parse_dt(struct device_node *np, struct sde_mdss_cfg *sde_cfg)
		if (IS_SDE_CTL_REV_100(sde_cfg->ctl_rev))
			set_bit(SDE_WB_INPUT_CTRL, &wb->features);

		if (sde_cfg->has_cwb_support)
		if (sde_cfg->has_cwb_support) {
			set_bit(SDE_WB_HAS_CWB, &wb->features);
			if (IS_SDE_CTL_REV_100(sde_cfg->ctl_rev))
				set_bit(SDE_WB_CWB_CTRL, &wb->features);
		}

		for (j = 0; j < sde_cfg->mdp_count; j++) {
			sde_cfg->mdp[j].clk_ctrls[wb->clk_ctrl].reg_off =
@@ -3567,6 +3570,7 @@ static int _sde_hardware_pre_caps(struct sde_mdss_cfg *sde_cfg, uint32_t hw_rev)
		sde_cfg->vbif_qos_nlvl = 8;
		sde_cfg->ts_prefill_rev = 2;
	} else if (IS_SM8150_TARGET(hw_rev)) {
		sde_cfg->has_cwb_support = true;
		sde_cfg->has_wb_ubwc = true;
		sde_cfg->has_qsync = true;
		sde_cfg->perf.min_prefill_lines = 24;
+2 −0
Original line number Diff line number Diff line
@@ -329,6 +329,7 @@ enum {
 * @SDE_WB_INPUT_CTRL       Writeback supports from which pp block input pixel
 *                          data arrives.
 * @SDE_WB_HAS_CWB          Writeback block supports concurrent writeback
 * @SDE_WB_CWB_CTRL         Separate CWB control is available for configuring
 * @SDE_WB_MAX              maximum value
 */
enum {
@@ -349,6 +350,7 @@ enum {
	SDE_WB_CDP,
	SDE_WB_INPUT_CTRL,
	SDE_WB_HAS_CWB,
	SDE_WB_CWB_CTRL,
	SDE_WB_MAX
};

+34 −0
Original line number Diff line number Diff line
@@ -954,6 +954,39 @@ static int sde_hw_ctl_reset_post_te_disable(struct sde_hw_ctl *ctx,
	return 0;
}

static int sde_hw_ctl_update_cwb_cfg(struct sde_hw_ctl *ctx,
		struct sde_hw_intf_cfg_v1 *cfg)
{
	int i;
	u32 cwb_active = 0;
	u32 merge_3d_active = 0;
	u32 wb_active = 0;
	struct sde_hw_blk_reg_map *c;

	if (!ctx)
		return -EINVAL;

	c = &ctx->hw;
	cwb_active = SDE_REG_READ(c, CTL_CWB_ACTIVE);
	for (i = 0; i < cfg->cwb_count; i++) {
		if (cfg->cwb[i])
			cwb_active |= BIT(cfg->cwb[i] - CWB_0);
	}

	merge_3d_active = SDE_REG_READ(c, CTL_MERGE_3D_ACTIVE);
	for (i = 0; i < cfg->merge_3d_count; i++) {
		if (cfg->merge_3d[i])
			merge_3d_active |= BIT(cfg->merge_3d[i] - MERGE_3D_0);
	}

	wb_active = BIT(2);
	SDE_REG_WRITE(c, CTL_WB_ACTIVE, wb_active);
	SDE_REG_WRITE(c, CTL_MERGE_3D_ACTIVE, merge_3d_active);
	SDE_REG_WRITE(c, CTL_CWB_ACTIVE, cwb_active);

	return 0;
}

static int sde_hw_ctl_dsc_cfg(struct sde_hw_ctl *ctx,
		struct sde_ctl_dsc_cfg *cfg)
{
@@ -1098,6 +1131,7 @@ static void _setup_ctl_ops(struct sde_hw_ctl_ops *ops,
		ops->trigger_flush = sde_hw_ctl_trigger_flush_v1;

		ops->setup_intf_cfg_v1 = sde_hw_ctl_intf_cfg_v1;
		ops->update_cwb_cfg = sde_hw_ctl_update_cwb_cfg;
		ops->setup_dsc_cfg = sde_hw_ctl_dsc_cfg;

		ops->update_bitmask_cdm = sde_hw_ctl_update_bitmask_cdm_v1;
Loading