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

Commit 7ade4114 authored by Samantha Tran's avatar Samantha Tran
Browse files

drm/msm/sde: Add 1D LUT IGC support for LUT_LAST



Adjust igc setup to include LUT_LAST for version 6.
The LUT_LAST entry is used to program the final lut entry. This
change also creates a common function for version 5 and 6 to
call to avoid repeating code.

Change-Id: I0ca9be1a65b6889afa7e16016b7094ad90930d57
Signed-off-by: default avatarSamantha Tran <samtran@codeaurora.org>
parent 14b40d78
Loading
Loading
Loading
Loading
+121 −47
Original line number Diff line number Diff line
@@ -88,6 +88,7 @@
#define DMA_1D_LUT_IGC_DITHER_OFF 0x408
#define VIG_1D_LUT_IGC_LEN 128
#define VIG_IGC_DATA_MASK (BIT(10) - 1)
#define VIG_IGC_DATA_MASK_V6 (BIT(12) - 1)

/* SDE_SCALER_QSEED3 */
#define QSEED3_DE_OFFSET                       0x24
@@ -1888,54 +1889,27 @@ static void vig_igcv5_off(struct sde_hw_pipe *ctx, void *cfg)
		DRM_ERROR("failed to kick off ret %d\n", rc);
}

void reg_dmav1_setup_vig_igcv5(struct sde_hw_pipe *ctx, void *cfg)
static int reg_dmav1_setup_vig_igc_common(struct sde_hw_reg_dma_ops *dma_ops,
				struct sde_reg_dma_setup_ops_cfg *dma_write_cfg,
				struct sde_hw_pipe *ctx,
				struct sde_hw_cp_cfg *hw_cfg, u32 mask,
				struct drm_msm_igc_lut *igc_lut)
{
	int rc;
	int rc = 0;
	u32 i = 0, j = 0, reg = 0, index = 0;
	u32 offset = 0;
	u32 lut_sel = 0, lut_enable = 0;
	u32 *data = NULL, *data_ptr = NULL;
	struct drm_msm_igc_lut *igc_lut;
	struct sde_hw_cp_cfg *hw_cfg = cfg;
	struct sde_hw_reg_dma_ops *dma_ops;
	struct sde_reg_dma_setup_ops_cfg dma_write_cfg;
	struct sde_reg_dma_kickoff_cfg kick_off;
	u32 igc_base = ctx->cap->sblk->igc_blk[0].base - REG_DMA_VIG_SWI_DIFF;
	enum sde_sspp_multirect_index idx = SDE_SSPP_RECT_0;

	rc = reg_dma_sspp_check(ctx, cfg, IGC, idx);
	if (rc)
		return;

	igc_lut = hw_cfg->payload;
	if (!igc_lut) {
		DRM_DEBUG_DRIVER("disable igc feature\n");
		vig_igcv5_off(ctx, cfg);
		return;
	}

	if (hw_cfg->len != sizeof(struct drm_msm_igc_lut)) {
		DRM_ERROR("invalid size of payload len %d exp %zd\n",
				hw_cfg->len, sizeof(struct drm_msm_igc_lut));
		return;
	}

	dma_ops = sde_reg_dma_get_ops();
	dma_ops->reset_reg_dma_buf(sspp_buf[idx][IGC][ctx->idx]);

	REG_DMA_INIT_OPS(dma_write_cfg, sspp_mapping[ctx->idx], IGC,
			sspp_buf[idx][IGC][ctx->idx]);

	REG_DMA_SETUP_OPS(dma_write_cfg, 0, NULL, 0, HW_BLK_SELECT, 0, 0, 0);
	rc = dma_ops->setup_payload(&dma_write_cfg);
	if (rc) {
		DRM_ERROR("write decode select failed ret %d\n", rc);
		return;
	}

	data = kzalloc(VIG_1D_LUT_IGC_LEN * sizeof(u32), GFP_KERNEL);
	if (!data)
		return;
		return -ENOMEM;

	reg = SDE_REG_READ(&ctx->hw, ctx->cap->sblk->igc_blk[0].base);
	lut_enable = (reg >> 8) & BIT(0);
@@ -1947,9 +1921,9 @@ void reg_dmav1_setup_vig_igcv5(struct sde_hw_pipe *ctx, void *cfg)
	for (i = 0; i < IGC_TBL_NUM; i++) {
		/* write 0 to the index register */
		index = 0;
		REG_DMA_SETUP_OPS(dma_write_cfg, igc_base + 0x1B0,
		REG_DMA_SETUP_OPS(*dma_write_cfg, igc_base + 0x1B0,
			&index, sizeof(index), REG_SINGLE_WRITE, 0, 0, 0);
		rc = dma_ops->setup_payload(&dma_write_cfg);
		rc = dma_ops->setup_payload(dma_write_cfg);
		if (rc) {
			DRM_ERROR("VIG IGC index write failed ret %d\n", rc);
			goto exit;
@@ -1958,39 +1932,141 @@ void reg_dmav1_setup_vig_igcv5(struct sde_hw_pipe *ctx, void *cfg)
		offset = igc_base + 0x1B4 + i * sizeof(u32);
		data_ptr = igc_lut->c0 + (ARRAY_SIZE(igc_lut->c0) * i);
		for (j = 0; j < VIG_1D_LUT_IGC_LEN; j++)
			data[j] = (data_ptr[2 * j] & VIG_IGC_DATA_MASK) |
				(data_ptr[2 * j + 1] & VIG_IGC_DATA_MASK) << 16;
			data[j] = (data_ptr[2 * j] & mask) |
				(data_ptr[2 * j + 1] & mask) << 16;

		REG_DMA_SETUP_OPS(dma_write_cfg, offset, data,
		REG_DMA_SETUP_OPS(*dma_write_cfg, offset, data,
				VIG_1D_LUT_IGC_LEN * sizeof(u32),
				REG_BLK_WRITE_INC, 0, 0, 0);
		rc = dma_ops->setup_payload(&dma_write_cfg);
		rc = dma_ops->setup_payload(dma_write_cfg);
		if (rc) {
			DRM_ERROR("lut write failed ret %d\n", rc);
			goto exit;
		}
	}

	if (igc_lut->flags & IGC_DITHER_ENABLE) {
		reg = igc_lut->strength & IGC_DITHER_DATA_MASK;
		reg |= BIT(4);
	} else {
		reg = 0;
	}
	REG_DMA_SETUP_OPS(dma_write_cfg, igc_base + 0x1C0,
	REG_DMA_SETUP_OPS(*dma_write_cfg, igc_base + 0x1C0,
			&reg, sizeof(reg), REG_SINGLE_WRITE, 0, 0, 0);
	rc = dma_ops->setup_payload(&dma_write_cfg);
	rc = dma_ops->setup_payload(dma_write_cfg);
	if (rc) {
		DRM_ERROR("dither strength failed ret %d\n", rc);
		goto exit;
	}

	reg = BIT(8) | (lut_sel << 9);
	REG_DMA_SETUP_OPS(dma_write_cfg, igc_base, &reg, sizeof(reg),
	REG_DMA_SETUP_OPS(*dma_write_cfg, igc_base, &reg, sizeof(reg),
		REG_SINGLE_MODIFY, 0, 0, REG_DMA_VIG_IGC_OP_MASK);
	rc = dma_ops->setup_payload(dma_write_cfg);
	if (rc)
		DRM_ERROR("setting opcode failed ret %d\n", rc);
exit:
	kfree(data);
	return rc;
}

void reg_dmav1_setup_vig_igcv5(struct sde_hw_pipe *ctx, void *cfg)
{
	int rc;
	struct sde_hw_reg_dma_ops *dma_ops;
	struct sde_reg_dma_kickoff_cfg kick_off;
	struct drm_msm_igc_lut *igc_lut;
	struct sde_hw_cp_cfg *hw_cfg = cfg;
	enum sde_sspp_multirect_index idx = SDE_SSPP_RECT_0;
	struct sde_reg_dma_setup_ops_cfg dma_write_cfg;

	rc = reg_dma_sspp_check(ctx, hw_cfg, IGC, idx);
	if (rc)
		return;

	igc_lut = hw_cfg->payload;
	if (!igc_lut) {
		DRM_DEBUG_DRIVER("disable igc feature\n");
		vig_igcv5_off(ctx, hw_cfg);
	}

	dma_ops = sde_reg_dma_get_ops();
	dma_ops->reset_reg_dma_buf(sspp_buf[idx][IGC][ctx->idx]);

	REG_DMA_INIT_OPS(dma_write_cfg, sspp_mapping[ctx->idx], IGC,
			sspp_buf[idx][IGC][ctx->idx]);

	REG_DMA_SETUP_OPS(dma_write_cfg, 0, NULL, 0, HW_BLK_SELECT, 0, 0, 0);
	rc = dma_ops->setup_payload(&dma_write_cfg);
	if (rc) {
		DRM_ERROR("setting opcode failed ret %d\n", rc);
		goto exit;
		DRM_ERROR("write decode select failed ret %d\n", rc);
		return;
	}

	rc = reg_dmav1_setup_vig_igc_common(dma_ops, &dma_write_cfg,
			ctx, cfg, VIG_IGC_DATA_MASK, igc_lut);
	if (rc) {
		DRM_ERROR("setup_vig_igc_common failed\n");
		return;
	}

	REG_DMA_SETUP_KICKOFF(kick_off, hw_cfg->ctl,
			sspp_buf[idx][IGC][ctx->idx], REG_DMA_WRITE,
			DMA_CTL_QUEUE0, WRITE_IMMEDIATE);
	rc = dma_ops->kick_off(&kick_off);
	if (rc)
		DRM_ERROR("failed to kick off ret %d\n", rc);
}

void reg_dmav1_setup_vig_igcv6(struct sde_hw_pipe *ctx, void *cfg)
{
	int rc;
	struct sde_hw_reg_dma_ops *dma_ops;
	struct sde_reg_dma_kickoff_cfg kick_off;
	struct sde_hw_cp_cfg *hw_cfg = cfg;
	u32 igc_base = ctx->cap->sblk->igc_blk[0].base - REG_DMA_VIG_SWI_DIFF;
	enum sde_sspp_multirect_index idx = SDE_SSPP_RECT_0;
	struct drm_msm_igc_lut *igc_lut;
	struct sde_reg_dma_setup_ops_cfg dma_write_cfg;

	rc = reg_dma_sspp_check(ctx, hw_cfg, IGC, idx);
	if (rc)
		return;

	igc_lut = hw_cfg->payload;
	if (!igc_lut) {
		DRM_DEBUG_DRIVER("disable igc feature\n");
		/* Both v5 and v6 call same igcv5_off */
		vig_igcv5_off(ctx, hw_cfg);
	}

	dma_ops = sde_reg_dma_get_ops();
	dma_ops->reset_reg_dma_buf(sspp_buf[idx][IGC][ctx->idx]);

	REG_DMA_INIT_OPS(dma_write_cfg, sspp_mapping[ctx->idx], IGC,
			sspp_buf[idx][IGC][ctx->idx]);

	REG_DMA_SETUP_OPS(dma_write_cfg, 0, NULL, 0, HW_BLK_SELECT, 0, 0, 0);
	rc = dma_ops->setup_payload(&dma_write_cfg);
	if (rc) {
		DRM_ERROR("write decode select failed ret %d\n", rc);
		return;
	}

	rc = reg_dmav1_setup_vig_igc_common(dma_ops, &dma_write_cfg,
			ctx, cfg, VIG_IGC_DATA_MASK_V6, igc_lut);
	if (rc) {
		DRM_ERROR("setup_vig_igcv6 failed\n");
		return;
	}

	/* Perform LAST_LUT required for v6*/
	REG_DMA_SETUP_OPS(dma_write_cfg, igc_base + 0x1C4, &igc_lut->c0_last,
		sizeof(u32) * 3, REG_BLK_WRITE_SINGLE, 0, 0, 0);
	rc = dma_ops->setup_payload(&dma_write_cfg);
	if (rc) {
		DRM_ERROR("c_last failed ret %d", rc);
		return;
	}

	REG_DMA_SETUP_KICKOFF(kick_off, hw_cfg->ctl,
@@ -1999,8 +2075,6 @@ void reg_dmav1_setup_vig_igcv5(struct sde_hw_pipe *ctx, void *cfg)
	rc = dma_ops->kick_off(&kick_off);
	if (rc)
		DRM_ERROR("failed to kick off ret %d\n", rc);
exit:
	kfree(data);
}

static void dma_igcv5_off(struct sde_hw_pipe *ctx, void *cfg,
+8 −0
Original line number Diff line number Diff line
@@ -144,6 +144,14 @@ void reg_dmav1_setup_vig_igcv5(struct sde_hw_pipe *ctx, void *cfg);
 */
void reg_dmav1_setup_dma_igcv5(struct sde_hw_pipe *ctx, void *cfg,
			enum sde_sspp_multirect_index idx);
/**
 * reg_dmav1_setup_vig_igcv6() - VIG ID lut IGC v6 implementation
 *				 using reg dma v1.
 * @ctx: sspp ctx info
 * @cfg: pointer to struct sde_hw_cp_cfg
 */
void reg_dmav1_setup_vig_igcv6(struct sde_hw_pipe *ctx, void *cfg);

/**
 * reg_dmav1_setup_dma_gcv5() - DMA 1D lut GC v5 implementation
 *                              using reg dma v1.
+11 −0
Original line number Diff line number Diff line
@@ -1027,6 +1027,17 @@ static void _setup_layer_ops_colorproc(struct sde_hw_pipe *c,
			else
				c->ops.setup_vig_igc = NULL;
		}

		if (c->cap->sblk->igc_blk[0].version ==
			(SDE_COLOR_PROCESS_VER(0x6, 0x0))) {
			ret = reg_dmav1_init_sspp_op_v4(SDE_SSPP_VIG_IGC,
							c->idx);
			if (!ret)
				c->ops.setup_vig_igc =
					reg_dmav1_setup_vig_igcv6;
			else
				c->ops.setup_vig_igc = NULL;
		}
	}

	if (test_bit(SDE_SSPP_DMA_IGC, &features)) {
+7 −0
Original line number Diff line number Diff line
@@ -238,6 +238,9 @@ struct drm_msm_pgc_lut {
 * @c2: color2 component lut
 * @strength: dither strength, considered valid when IGC_DITHER_ENABLE
 *            is set in flags. Strength value based on source bit width.
 * @c0_last: color0 lut_last component
 * @c1_last: color1 lut_last component
 * @c2_last: color2 lut_last component
 */
struct drm_msm_igc_lut {
	__u64 flags;
@@ -245,7 +248,11 @@ struct drm_msm_igc_lut {
	__u32 c1[IGC_TBL_LEN];
	__u32 c2[IGC_TBL_LEN];
	__u32 strength;
	__u32 c0_last;
	__u32 c1_last;
	__u32 c2_last;
};
#define LAST_LUT 2

#define HIST_V_SIZE 256
/**