Commit 68baf833 authored by Krzysztof Kozlowski's avatar Krzysztof Kozlowski Committed by Dmitry Baryshkov
Browse files

drm/msm/dpu: Implement LM crossbar for v12.0 DPU



v12.0 DPU on SM8750 comes with new LM crossbar that requires each pipe
rectangle to be programmed separately in blend stage.  Implement support
for this along with a new CTL_LAYER_ACTIVE register and setting the
blend stage in layer mixer code.

Reviewed-by: default avatarDmitry Baryshkov <dmitry.baryshkov@linaro.org>
Signed-off-by: default avatarKrzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
Patchwork: https://patchwork.freedesktop.org/patch/659632/
Link: https://lore.kernel.org/r/20250618-b4-sm8750-display-v7-12-a591c609743d@linaro.org


Signed-off-by: default avatarDmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
parent b567e928
Loading
Loading
Loading
Loading
+16 −2
Original line number Diff line number Diff line
@@ -525,6 +525,7 @@ static void _dpu_crtc_blend_setup(struct drm_crtc *crtc)
	struct dpu_hw_ctl *ctl;
	struct dpu_hw_mixer *lm;
	struct dpu_hw_stage_cfg stage_cfg;
	DECLARE_BITMAP(active_lms, LM_MAX);
	int i;

	DRM_DEBUG_ATOMIC("%s\n", dpu_crtc->name);
@@ -538,10 +539,14 @@ static void _dpu_crtc_blend_setup(struct drm_crtc *crtc)
			mixer[i].lm_ctl->ops.set_active_fetch_pipes(mixer[i].lm_ctl, NULL);
		if (mixer[i].lm_ctl->ops.set_active_pipes)
			mixer[i].lm_ctl->ops.set_active_pipes(mixer[i].lm_ctl, NULL);

		if (mixer[i].hw_lm->ops.clear_all_blendstages)
			mixer[i].hw_lm->ops.clear_all_blendstages(mixer[i].hw_lm);
	}

	/* initialize stage cfg */
	memset(&stage_cfg, 0, sizeof(struct dpu_hw_stage_cfg));
	memset(active_lms, 0, sizeof(active_lms));

	_dpu_crtc_blend_setup_mixer(crtc, dpu_crtc, mixer, &stage_cfg);

@@ -555,13 +560,22 @@ static void _dpu_crtc_blend_setup(struct drm_crtc *crtc)
		ctl->ops.update_pending_flush_mixer(ctl,
			mixer[i].hw_lm->idx);

		set_bit(lm->idx, active_lms);
		if (ctl->ops.set_active_lms)
			ctl->ops.set_active_lms(ctl, active_lms);

		DRM_DEBUG_ATOMIC("lm %d, op_mode 0x%X, ctl %d\n",
			mixer[i].hw_lm->idx - LM_0,
			mixer[i].mixer_op_mode,
			ctl->idx - CTL_0);

		if (ctl->ops.setup_blendstage)
			ctl->ops.setup_blendstage(ctl, mixer[i].hw_lm->idx,
						  &stage_cfg);

		if (lm->ops.setup_blendstage)
			lm->ops.setup_blendstage(lm, mixer[i].hw_lm->idx,
						 &stage_cfg);
	}
}

+6 −0
Original line number Diff line number Diff line
@@ -2195,6 +2195,12 @@ static void dpu_encoder_helper_reset_mixers(struct dpu_encoder_phys *phys_enc)
		if (ctl->ops.setup_blendstage)
			ctl->ops.setup_blendstage(ctl, hw_mixer[i]->idx, NULL);

		if (hw_mixer[i]->ops.clear_all_blendstages)
			hw_mixer[i]->ops.clear_all_blendstages(hw_mixer[i]);

		if (ctl->ops.set_active_lms)
			ctl->ops.set_active_lms(ctl, NULL);

		if (ctl->ops.set_active_fetch_pipes)
			ctl->ops.set_active_fetch_pipes(ctl, NULL);

+26 −1
Original line number Diff line number Diff line
@@ -43,6 +43,7 @@
#define   CTL_CDM_FLUSH                0x114
#define   CTL_PERIPH_FLUSH              0x128
#define   CTL_PIPE_ACTIVE               0x12c
#define   CTL_LAYER_ACTIVE              0x130
#define   CTL_INTF_MASTER               0x134
#define   CTL_DSPP_n_FLUSH(n)           ((0x13C) + ((n) * 4))

@@ -65,6 +66,8 @@ static const u32 fetch_tbl[SSPP_MAX] = {CTL_INVALID_BIT, 16, 17, 18, 19,
	CTL_INVALID_BIT, CTL_INVALID_BIT, CTL_INVALID_BIT, CTL_INVALID_BIT, 0,
	1, 2, 3, 4, 5};

static const u32 lm_tbl[LM_MAX] = {CTL_INVALID_BIT, 0, 1, 2, 3, 4, 5, 6, 7};

static int _mixer_stages(const struct dpu_lm_cfg *mixer, int count,
		enum dpu_lm lm)
{
@@ -677,7 +680,11 @@ static void dpu_hw_ctl_reset_intf_cfg_v1(struct dpu_hw_ctl *ctx,
				merge3d_active);
	}

	dpu_hw_ctl_clear_all_blendstages(ctx);
	if (ctx->ops.clear_all_blendstages)
		ctx->ops.clear_all_blendstages(ctx);

	if (ctx->ops.set_active_lms)
		ctx->ops.set_active_lms(ctx, NULL);

	if (ctx->ops.set_active_fetch_pipes)
		ctx->ops.set_active_fetch_pipes(ctx, NULL);
@@ -758,6 +765,23 @@ static void dpu_hw_ctl_set_active_pipes(struct dpu_hw_ctl *ctx,
	DPU_REG_WRITE(&ctx->hw, CTL_PIPE_ACTIVE, val);
}

static void dpu_hw_ctl_set_active_lms(struct dpu_hw_ctl *ctx,
				      unsigned long *active_lms)
{
	int i;
	u32 val = 0;

	if (active_lms) {
		for (i = LM_0; i < LM_MAX; i++) {
			if (test_bit(i, active_lms) &&
			    lm_tbl[i] != CTL_INVALID_BIT)
				val |= BIT(lm_tbl[i]);
		}
	}

	DPU_REG_WRITE(&ctx->hw, CTL_LAYER_ACTIVE, val);
}

/**
 * dpu_hw_ctl_init() - Initializes the ctl_path hw driver object.
 * Should be called before accessing any ctl_path register.
@@ -826,6 +850,7 @@ struct dpu_hw_ctl *dpu_hw_ctl_init(struct drm_device *dev,
		c->ops.setup_blendstage = dpu_hw_ctl_setup_blendstage;
	} else {
		c->ops.set_active_pipes = dpu_hw_ctl_set_active_pipes;
		c->ops.set_active_lms = dpu_hw_ctl_set_active_lms;
	}
	c->ops.update_pending_flush_sspp = dpu_hw_ctl_update_pending_flush_sspp;
	c->ops.update_pending_flush_mixer = dpu_hw_ctl_update_pending_flush_mixer;
+9 −0
Original line number Diff line number Diff line
@@ -266,6 +266,15 @@ struct dpu_hw_ctl_ops {
	 */
	void (*set_active_pipes)(struct dpu_hw_ctl *ctx,
				 unsigned long *active_pipes);

	/**
	 * Set active layer mixers attached to this CTL
	 * @ctx: ctl path ctx pointer
	 * @active_lms: bitmap of enum dpu_lm
	 */
	void (*set_active_lms)(struct dpu_hw_ctl *ctx,
			       unsigned long *active_lms);

};

/**
+126 −0
Original line number Diff line number Diff line
@@ -28,11 +28,19 @@
#define LM_FG_COLOR_FILL_XY              0x14

/* >= v12 DPU */
#define LM_BG_SRC_SEL_V12                0x14
#define LM_BG_SRC_SEL_V12_RESET_VALUE    0x0000c0c0
#define LM_BORDER_COLOR_0_V12            0x1c
#define LM_BORDER_COLOR_1_V12            0x20

/* >= v12 DPU with offset to mixer base + stage base */
#define LM_BLEND0_FG_SRC_SEL_V12         0x04
#define LM_BLEND0_CONST_ALPHA_V12        0x08
#define LM_FG_COLOR_FILL_COLOR_0_V12     0x0c
#define LM_FG_COLOR_FILL_COLOR_1_V12     0x10
#define LM_FG_COLOR_FILL_SIZE_V12        0x14
#define LM_FG_COLOR_FILL_XY_V12          0x18

#define LM_BLEND0_FG_ALPHA               0x04
#define LM_BLEND0_BG_ALPHA               0x08

@@ -215,6 +223,122 @@ static void dpu_hw_lm_setup_color3_v12(struct dpu_hw_mixer *ctx,
	}
}

static int _set_staged_sspp(u32 stage, struct dpu_hw_stage_cfg *stage_cfg,
			    int pipes_per_stage, u32 *value)
{
	int i;
	u32 pipe_type = 0, pipe_id = 0, rec_id = 0;
	u32 src_sel[PIPES_PER_STAGE];

	*value = LM_BG_SRC_SEL_V12_RESET_VALUE;
	if (!stage_cfg || !pipes_per_stage)
		return 0;

	for (i = 0; i < pipes_per_stage; i++) {
		enum dpu_sspp pipe = stage_cfg->stage[stage][i];
		enum dpu_sspp_multirect_index rect_index = stage_cfg->multirect_index[stage][i];

		src_sel[i] = LM_BG_SRC_SEL_V12_RESET_VALUE;

		if (!pipe)
			continue;

		/* translate pipe data to SWI pipe_type, pipe_id */
		if (pipe >= SSPP_DMA0 && pipe <= SSPP_DMA5) {
			pipe_type = 0;
			pipe_id = pipe - SSPP_DMA0;
		} else if (pipe >= SSPP_VIG0 && pipe <= SSPP_VIG3) {
			pipe_type = 1;
			pipe_id = pipe - SSPP_VIG0;
		} else {
			DPU_ERROR("invalid rec-%d pipe:%d\n", i, pipe);
			return -EINVAL;
		}

		/* translate rec data to SWI rec_id */
		if (rect_index == DPU_SSPP_RECT_SOLO || rect_index == DPU_SSPP_RECT_0) {
			rec_id = 0;
		} else if (rect_index == DPU_SSPP_RECT_1) {
			rec_id = 1;
		} else {
			DPU_ERROR("invalid rec-%d rect_index:%d\n", i, rect_index);
			rec_id = 0;
		}

		/* calculate SWI value for rec-0 and rec-1 and store it temporary buffer */
		src_sel[i] = (((pipe_type & 0x3) << 6) | ((rec_id & 0x3) << 4) | (pipe_id & 0xf));
	}

	/* calculate final SWI register value for rec-0 and rec-1 */
	*value = 0;
	for (i = 0; i < pipes_per_stage; i++)
		*value |= src_sel[i] << (i * 8);

	return 0;
}

static int dpu_hw_lm_setup_blendstage(struct dpu_hw_mixer *ctx, enum dpu_lm lm,
				      struct dpu_hw_stage_cfg *stage_cfg)
{
	struct dpu_hw_blk_reg_map *c = &ctx->hw;
	int i, ret, stages, stage_off, pipes_per_stage;
	u32 value;

	stages = ctx->cap->sblk->maxblendstages;
	if (stages <= 0)
		return -EINVAL;

	if (test_bit(DPU_MIXER_SOURCESPLIT, &ctx->cap->features))
		pipes_per_stage = PIPES_PER_STAGE;
	else
		pipes_per_stage = 1;

	/*
	 * When stage configuration is empty, we can enable the
	 * border color by setting the corresponding LAYER_ACTIVE bit
	 * and un-staging all the pipes from the layer mixer.
	 */
	if (!stage_cfg)
		DPU_REG_WRITE(c, LM_BG_SRC_SEL_V12, LM_BG_SRC_SEL_V12_RESET_VALUE);

	for (i = DPU_STAGE_0; i <= stages; i++) {
		stage_off = _stage_offset(ctx, i);
		if (stage_off < 0)
			return stage_off;

		ret = _set_staged_sspp(i, stage_cfg, pipes_per_stage, &value);
		if (ret)
			return ret;

		DPU_REG_WRITE(c, LM_BLEND0_FG_SRC_SEL_V12 + stage_off, value);
	}

	return 0;
}

static int dpu_hw_lm_clear_all_blendstages(struct dpu_hw_mixer *ctx)
{
	struct dpu_hw_blk_reg_map *c = &ctx->hw;
	int i, stages, stage_off;

	stages = ctx->cap->sblk->maxblendstages;
	if (stages <= 0)
		return -EINVAL;

	DPU_REG_WRITE(c, LM_BG_SRC_SEL_V12, LM_BG_SRC_SEL_V12_RESET_VALUE);

	for (i = DPU_STAGE_0; i <= stages; i++) {
		stage_off = _stage_offset(ctx, i);
		if (stage_off < 0)
			return stage_off;

		DPU_REG_WRITE(c, LM_BLEND0_FG_SRC_SEL_V12 + stage_off,
			      LM_BG_SRC_SEL_V12_RESET_VALUE);
	}

	return 0;
}

/**
 * dpu_hw_lm_init() - Initializes the mixer hw driver object.
 * should be called once before accessing every mixer.
@@ -257,6 +381,8 @@ struct dpu_hw_mixer *dpu_hw_lm_init(struct drm_device *dev,
		c->ops.setup_border_color = dpu_hw_lm_setup_border_color;
	} else {
		c->ops.setup_alpha_out = dpu_hw_lm_setup_color3_v12;
		c->ops.setup_blendstage = dpu_hw_lm_setup_blendstage;
		c->ops.clear_all_blendstages = dpu_hw_lm_clear_all_blendstages;
		c->ops.setup_border_color = dpu_hw_lm_setup_border_color_v12;
	}
	c->ops.setup_misr = dpu_hw_lm_setup_misr;
Loading