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

Commit abf1ad2f authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge changes I62597a9d,I934af39c,I0ca9be1a into dev/msm-4.14-display

* changes:
  disp: msm: sde: Update gamut non-uniform support
  drm/msm/sde: Add 3D gamut support for version 6
  drm/msm/sde: Add 1D LUT IGC support for LUT_LAST
parents 14127938 460684e1
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -171,6 +171,18 @@ static void _setup_dspp_ops(struct sde_hw_dspp *c, unsigned long features)
					c->ops.setup_gamut =
					    sde_setup_dspp_3d_gamutv41;
				}
			} else if (c->cap->sblk->gamut.version ==
					SDE_COLOR_PROCESS_VER(0x4, 2)) {
				ret = reg_dmav1_init_dspp_op_v4(
					SDE_DSPP_GAMUT, c->idx);
				c->ops.setup_gamut = NULL;
				if (!ret) {
					c->ops.setup_gamut =
					    reg_dmav1_setup_dspp_3d_gamutv42;
				} else {
					c->ops.setup_gamut =
					    sde_setup_dspp_3d_gamutv41;
				}
			}
			break;
		case SDE_DSPP_GC:
+170 −48
Original line number Diff line number Diff line
/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -72,6 +72,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
@@ -614,6 +615,46 @@ void reg_dmav1_setup_dspp_3d_gamutv41(struct sde_hw_dspp *ctx, void *cfg)
		GAMUT_SCALE_OFF_LEN);
}

void reg_dmav1_setup_dspp_3d_gamutv42(struct sde_hw_dspp *ctx, void *cfg)
{
	struct sde_hw_cp_cfg *hw_cfg = cfg;
	struct drm_msm_3d_gamut *payload = NULL;
	uint32_t i, j, tmp;
	uint32_t scale_off[GAMUT_3D_SCALE_OFF_TBL_NUM][GAMUT_3D_SCALE_OFF_SZ];
	int rc;

	rc = reg_dma_dspp_check(ctx, cfg, GAMUT);
	if (rc)
		return;
	if (hw_cfg->payload && hw_cfg->len != sizeof(struct drm_msm_3d_gamut)) {
		DRM_ERROR("invalid payload len actual %d expected %zd",
				hw_cfg->len, sizeof(struct drm_msm_3d_gamut));
		return;
	}

	payload = hw_cfg->payload;
	if (payload && (payload->flags & GAMUT_3D_MAP_EN)) {
		for (i = 0; i < GAMUT_3D_SCALE_OFF_TBL_NUM; i++) {
			for (j = 0; j < GAMUT_3D_SCALE_OFF_SZ; j++) {
				scale_off[i][j] = payload->scale_off[i][j];
				tmp = payload->scale_off[i][j] & 0x1ffff000;
				payload->scale_off[i][j] &= 0xfff;
				tmp = tmp << 3;
				payload->scale_off[i][j] =
					tmp | payload->scale_off[i][j];
			}
		}
	}
	reg_dmav1_setup_dspp_3d_gamutv4_common(ctx, cfg, GAMUT_SCALE_OFF_LEN,
		GAMUT_SCALE_OFF_LEN);
	if (payload && (payload->flags & GAMUT_3D_MAP_EN)) {
		for (i = 0; i < GAMUT_3D_SCALE_OFF_TBL_NUM; i++) {
			for (j = 0; j < GAMUT_3D_SCALE_OFF_SZ; j++)
				payload->scale_off[i][j] = scale_off[i][j];
		}
	}
}

void reg_dmav1_setup_dspp_gcv18(struct sde_hw_dspp *ctx, void *cfg)
{
	struct drm_msm_pgc_lut *lut_cfg;
@@ -1712,6 +1753,7 @@ void reg_dmav1_setup_vig_gamutv5(struct sde_hw_pipe *ctx, void *cfg)

	if (!hw_cfg->payload) {
		DRM_DEBUG_DRIVER("disable gamut feature\n");
		/* v5 and v6 call the same off version */
		vig_gamutv5_off(ctx, cfg);
		return;
	}
@@ -1803,6 +1845,11 @@ void reg_dmav1_setup_vig_gamutv5(struct sde_hw_pipe *ctx, void *cfg)
		DRM_ERROR("failed to kick off ret %d\n", rc);
}

void reg_dmav1_setup_vig_gamutv6(struct sde_hw_pipe *ctx, void *cfg)
{
	reg_dmav1_setup_vig_gamutv5(ctx, cfg);
}

static void vig_igcv5_off(struct sde_hw_pipe *ctx, void *cfg)
{
	int rc;
@@ -1843,54 +1890,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);
@@ -1902,9 +1922,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;
@@ -1913,39 +1933,143 @@ 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);
		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("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);
		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;
	}

	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,
@@ -1954,8 +2078,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,
+25 −1
Original line number Diff line number Diff line
/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -46,6 +46,13 @@ void reg_dmav1_setup_dspp_3d_gamutv4(struct sde_hw_dspp *ctx, void *cfg);
 */
void reg_dmav1_setup_dspp_3d_gamutv41(struct sde_hw_dspp *ctx, void *cfg);

/**
 * reg_dmav1_setup_3d_gamutv42() - gamut v4_2 implementation using reg dma v1.
 * @ctx: dspp ctx info
 * @cfg: pointer to struct sde_hw_cp_cfg
 */
void reg_dmav1_setup_dspp_3d_gamutv42(struct sde_hw_dspp *ctx, void *cfg);

/**
 * reg_dmav1_setup_dspp_gcv18() - gc v18 implementation using reg dma v1.
 * @ctx: dspp ctx info
@@ -134,6 +141,14 @@ int reg_dmav1_init_sspp_op_v4(int feature, enum sde_sspp idx);
 */
void reg_dmav1_setup_vig_gamutv5(struct sde_hw_pipe *ctx, void *cfg);

/**
 * reg_dmav1_setup_vig_gamutv6() - VIG 3D lut gamut v6 implementation
 *                                 using reg dma v1.
 * @ctx: sspp ctx info
 * @cfg: pointer to struct sde_hw_cp_cfg
 */
void reg_dmav1_setup_vig_gamutv6(struct sde_hw_pipe *ctx, void *cfg);

/**
 * reg_dmav1_setup_vig_igcv5() - VIG 1D lut IGC v5 implementation
 *                               using reg dma v1.
@@ -151,6 +166,15 @@ 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.
+22 −0
Original line number Diff line number Diff line
@@ -1032,6 +1032,17 @@ static void _setup_layer_ops_colorproc(struct sde_hw_pipe *c,
			else
				c->ops.setup_vig_gamut = NULL;
		}

		if (c->cap->sblk->gamut_blk.version ==
			(SDE_COLOR_PROCESS_VER(0x6, 0x0))) {
			ret = reg_dmav1_init_sspp_op_v4(SDE_SSPP_VIG_GAMUT,
							c->idx);
			if (!ret)
				c->ops.setup_vig_gamut =
					reg_dmav1_setup_vig_gamutv6;
			else
				c->ops.setup_vig_gamut = NULL;
		}
	}

	if (test_bit(SDE_SSPP_VIG_IGC, &features)) {
@@ -1045,6 +1056,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
@@ -233,6 +233,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;
@@ -240,7 +243,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
/**