diff --git a/msm/sde/sde_color_processing.c b/msm/sde/sde_color_processing.c index e85be847..2e6d9eb0 100644 --- a/msm/sde/sde_color_processing.c +++ b/msm/sde/sde_color_processing.c @@ -2937,6 +2937,7 @@ static void _dspp_sixzone_install_property(struct drm_crtc *crtc) version = catalog->dspp[0].sblk->sixzone.version >> 16; switch (version) { case 1: + case 2: snprintf(feature_name, ARRAY_SIZE(feature_name), "%s%d", "SDE_DSPP_PA_SIXZONE_V", version); _sde_cp_crtc_install_blob_property(crtc, feature_name, diff --git a/msm/sde/sde_hw_color_proc_common_v4.h b/msm/sde/sde_hw_color_proc_common_v4.h index b6367160..62c1d784 100644 --- a/msm/sde/sde_hw_color_proc_common_v4.h +++ b/msm/sde/sde_hw_color_proc_common_v4.h @@ -99,6 +99,7 @@ enum { #define PA_SIXZONE_HUE_EN BIT(29) #define PA_SIXZONE_SAT_EN BIT(30) #define PA_SIXZONE_VAL_EN BIT(31) +#define PA_SIXZONE_SV_EN BIT(0) #define PA_HIST_EN BIT(16) @@ -127,6 +128,11 @@ enum { #define SIXZONE_ADJ_CURVE_P1_OFF 0x4 #define SIXZONE_THRESHOLDS_OFF 0x8 +#define SIXZONE_ADJ_PWL0_OFF 0xC +#define SIXZONE_ADJ_PWL1_OFF 0x10 +#define SIXZONE_SAT_PWL0_OFF 0x14 +#define SIXZONE_SAT_PWL1_OFF 0x18 +#define SIXZONE_SV_CTL_OFF 0x20 #define MEMCOL_SIZE0 20 #define MEMCOL_SIZE1 8 diff --git a/msm/sde/sde_hw_dspp.c b/msm/sde/sde_hw_dspp.c index b7de02e9..9d54a479 100644 --- a/msm/sde/sde_hw_dspp.c +++ b/msm/sde/sde_hw_dspp.c @@ -151,6 +151,12 @@ static void dspp_sixzone(struct sde_hw_dspp *c) c->ops.setup_sixzone = reg_dmav1_setup_dspp_sixzonev17; else c->ops.setup_sixzone = sde_setup_dspp_sixzone_v17; + } else if (c->cap->sblk->sixzone.version == + SDE_COLOR_PROCESS_VER(0x2, 0x0)) { + c->ops.setup_sixzone = NULL; + ret = reg_dmav2_init_dspp_op_v4(SDE_DSPP_SIXZONE, c->idx); + if (!ret) + c->ops.setup_sixzone = reg_dmav2_setup_dspp_sixzonev2; } } diff --git a/msm/sde/sde_hw_reg_dma_v1.c b/msm/sde/sde_hw_reg_dma_v1.c index 2d08e657..010bf583 100644 --- a/msm/sde/sde_hw_reg_dma_v1.c +++ b/msm/sde/sde_hw_reg_dma_v1.c @@ -443,7 +443,8 @@ static int validate_blk_lut_write(struct sde_reg_dma_setup_ops_cfg *cfg) if (cfg->table_sel >= LUTBUS_TABLE_SELECT_MAX || cfg->block_sel >= LUTBUS_BLOCK_MAX || (cfg->trans_size != LUTBUS_IGC_TRANS_SIZE && - cfg->trans_size != LUTBUS_GAMUT_TRANS_SIZE)) { + cfg->trans_size != LUTBUS_GAMUT_TRANS_SIZE && + cfg->trans_size != LUTBUS_SIXZONE_TRANS_SIZE)) { DRM_ERROR("invalid table_sel %d block_sel %d trans_size %d\n", cfg->table_sel, cfg->block_sel, cfg->trans_size); diff --git a/msm/sde/sde_hw_reg_dma_v1_color_proc.c b/msm/sde/sde_hw_reg_dma_v1_color_proc.c index 43e707d1..faca545b 100644 --- a/msm/sde/sde_hw_reg_dma_v1_color_proc.c +++ b/msm/sde/sde_hw_reg_dma_v1_color_proc.c @@ -262,6 +262,10 @@ static int reg_dma_sspp_check(struct sde_hw_pipe *ctx, void *cfg, enum sde_sspp_multirect_index idx); static int reg_dma_ltm_check(struct sde_hw_dspp *ctx, void *cfg, enum sde_reg_dma_features feature); +static void _perform_sbdma_kickoff(struct sde_hw_dspp *ctx, + struct sde_hw_cp_cfg *hw_cfg, + struct sde_hw_reg_dma_ops *dma_ops, + u32 blk, enum sde_reg_dma_features feature); static int reg_dma_buf_init(struct sde_reg_dma_buffer **buf, u32 size) { @@ -1766,6 +1770,198 @@ void reg_dmav1_setup_dspp_sixzonev17(struct sde_hw_dspp *ctx, void *cfg) DRM_ERROR("failed to kick off ret %d\n", rc); } +void reg_dmav2_setup_dspp_sixzonev2(struct sde_hw_dspp *ctx, void *cfg) +{ + struct sde_hw_reg_dma_ops *dma_ops; + struct sde_hw_cp_cfg *hw_cfg = cfg; + struct sde_reg_dma_setup_ops_cfg dma_write_cfg; + struct drm_msm_sixzone *sixzone; + struct sde_hw_dspp *dspp_list[DSPP_MAX]; + u32 local_opcode = 0, local_hold = 0, sv_ctl = 0; + u32 num_of_mixers, blk = 0, len, transfer_size_bytes; + u16 *data = NULL; + int i, rc, j, k; + + rc = reg_dma_validate_sixzone_config(ctx, cfg, &num_of_mixers, &blk, dspp_list); + if (rc) { + return; + } + + sixzone = hw_cfg->payload; + + dma_ops = sde_reg_dma_get_ops(); + dma_ops->reset_reg_dma_buf(dspp_buf[SIX_ZONE][ctx->idx]); + + REG_DMA_INIT_OPS(dma_write_cfg, blk, SIX_ZONE, + dspp_buf[SIX_ZONE][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 for sixzone failed ret %d\n", rc); + return; + } + + /* 384 LUT entries * 5 components (hue, sat_low, sat_med, sat_high, value) + * 16 bit per LUT entry */ + len = SIXZONE_LUT_SIZE * 5 * sizeof(u16); + /* Data size must be aligned with word size AND LUT transfer size */ + transfer_size_bytes = LUTBUS_SIXZONE_TRANS_SIZE * sizeof(u32); + if (len % transfer_size_bytes) + len = len + (transfer_size_bytes - len % transfer_size_bytes); + + data = kvzalloc(len, GFP_KERNEL); + if (!data) { + DRM_ERROR("Allocating memory for sixzone data failed!"); + return; + } + + for (j = 0, k = 0; j < SIXZONE_LUT_SIZE; j++) { + /* p0 --> hue, p1 --> sat_low/value, p2 --> sat_mid/sat_high */ + /* 16 bit per LUT entry and MSB aligned to allow expansion, + * hence, sw need to left shift 4 bits before sending to HW. + */ + data[k++] = (u16) (sixzone->curve[j].p0 << 4); + data[k++] = (u16) ((sixzone->curve[j].p1 >> 16) << 4); + data[k++] = (u16) (sixzone->curve_p2[j] << 4); + data[k++] = (u16) ((sixzone->curve_p2[j] >> 16) << 4); + data[k++] = (u16) (sixzone->curve[j].p1 << 4); + } + + REG_DMA_SETUP_OPS(dma_write_cfg, 0, (u32 *)data, len, + REG_BLK_LUT_WRITE, 0, 0, 0); + /* table select is only relevant to SSPP Gamut */ + dma_write_cfg.table_sel = 0; + dma_write_cfg.block_sel = LUTBUS_BLOCK_SIXZONE; + dma_write_cfg.trans_size = LUTBUS_SIXZONE_TRANS_SIZE; + dma_write_cfg.lut_size = len / transfer_size_bytes; + + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("lut write for sixzone failed ret %d\n", rc); + goto exit; + } + + REG_DMA_SETUP_OPS(dma_write_cfg, + ctx->cap->sblk->sixzone.base + SIXZONE_THRESHOLDS_OFF, + &sixzone->threshold, sizeof(u32), + REG_SINGLE_WRITE, 0, 0, 0); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("write sixzone threshold failed ret %d\n", rc); + goto exit; + } + + REG_DMA_SETUP_OPS(dma_write_cfg, + ctx->cap->sblk->sixzone.base + SIXZONE_ADJ_PWL0_OFF, + &sixzone->adjust_p0, sizeof(u32), + REG_SINGLE_WRITE, 0, 0, 0); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("write sixzone adjust p0 failed ret %d\n", rc); + goto exit; + } + + REG_DMA_SETUP_OPS(dma_write_cfg, + ctx->cap->sblk->sixzone.base + SIXZONE_ADJ_PWL1_OFF, + &sixzone->adjust_p1, sizeof(u32), + REG_SINGLE_WRITE, 0, 0, 0); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("write sixzone adjust p1 failed ret %d\n", rc); + goto exit; + } + + REG_DMA_SETUP_OPS(dma_write_cfg, + ctx->cap->sblk->sixzone.base + SIXZONE_SAT_PWL0_OFF, + &sixzone->sat_adjust_p0, sizeof(u32), + REG_SINGLE_WRITE, 0, 0, 0); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("write sixzone saturation adjust p0 failed ret %d\n", rc); + goto exit; + } + + REG_DMA_SETUP_OPS(dma_write_cfg, + ctx->cap->sblk->sixzone.base + SIXZONE_SAT_PWL1_OFF, + &sixzone->sat_adjust_p1, sizeof(u32), + REG_SINGLE_WRITE, 0, 0, 0); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("write sixzone saturation adjust p1 failed ret %d\n", rc); + goto exit; + } + + if (sixzone->flags & SIXZONE_SV_ENABLE) { + sv_ctl |= PA_SIXZONE_SV_EN; + } + + REG_DMA_SETUP_OPS(dma_write_cfg, + ctx->cap->sblk->sixzone.base + SIXZONE_SV_CTL_OFF, + &sv_ctl, sizeof(sv_ctl), REG_SINGLE_WRITE, 0, 0, 0); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("sv enable write failed for sixzone ret %d\n", rc); + goto exit; + } + + local_hold = ((sixzone->sat_hold & REG_MASK(2)) << 12); + local_hold |= ((sixzone->val_hold & REG_MASK(2)) << 14); + if (sixzone->flags & SIXZONE_HUE_ENABLE) + local_opcode |= PA_SIXZONE_HUE_EN; + if (sixzone->flags & SIXZONE_SAT_ENABLE) + local_opcode |= PA_SIXZONE_SAT_EN; + if (sixzone->flags & SIXZONE_VAL_ENABLE) + local_opcode |= PA_SIXZONE_VAL_EN; + + if (local_opcode) { + local_opcode |= PA_EN; + } else { + DRM_ERROR("Invalid six zone config 0x%x\n", local_opcode); + goto exit; + } + + for (i = 0; i < num_of_mixers; i++) { + blk = dspp_mapping[dspp_list[i]->idx]; + REG_DMA_INIT_OPS(dma_write_cfg, blk, SIX_ZONE, + dspp_buf[SIX_ZONE][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 for sixzone ret %d\n", rc); + goto exit; + } + + REG_DMA_SETUP_OPS(dma_write_cfg, + ctx->cap->sblk->hsic.base + PA_PWL_HOLD_OFF, &local_hold, + sizeof(local_hold), REG_SINGLE_MODIFY, 0, 0, + REG_DMA_PA_PWL_HOLD_SZONE_MASK); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("setting local_hold failed for sixzone ret %d\n", rc); + goto exit; + } + + REG_DMA_SETUP_OPS(dma_write_cfg, + ctx->cap->sblk->hsic.base, &local_opcode, + sizeof(local_opcode), REG_SINGLE_MODIFY, 0, 0, + REG_DMA_PA_MODE_SZONE_MASK); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("setting local_opcode failed for sixzone ret %d\n", rc); + goto exit; + } + } + + LOG_FEATURE_ON; + _perform_sbdma_kickoff(ctx, hw_cfg, dma_ops, blk, SIX_ZONE); + +exit: + kvfree(data); +} + int reg_dmav1_deinit_dspp_ops(enum sde_dspp idx) { int i; @@ -4097,7 +4293,6 @@ int reg_dmav2_init_dspp_op_v4(int feature, enum sde_dspp idx) return rc; } - /* Attempt to submit a feature buffer to SB DMA. * Note that if SB DMA is not supported, this function * will quitely attempt to fallback to DB DMA @@ -4110,7 +4305,7 @@ static void _perform_sbdma_kickoff(struct sde_hw_dspp *ctx, int rc, i; struct sde_reg_dma_kickoff_cfg kick_off; - if ((feature != GAMUT && feature != IGC) || + if ((feature != GAMUT && feature != IGC && feature != SIX_ZONE) || !(blk & (DSPP0 | DSPP1 | DSPP2 | DSPP3))) { DRM_ERROR("SB DMA invalid for feature / block - %d/%d\n", feature, blk); diff --git a/msm/sde/sde_hw_reg_dma_v1_color_proc.h b/msm/sde/sde_hw_reg_dma_v1_color_proc.h index d25cf03f..81297014 100644 --- a/msm/sde/sde_hw_reg_dma_v1_color_proc.h +++ b/msm/sde/sde_hw_reg_dma_v1_color_proc.h @@ -91,6 +91,13 @@ void reg_dmav1_setup_dspp_pa_hsicv17(struct sde_hw_dspp *ctx, void *cfg); */ void reg_dmav1_setup_dspp_sixzonev17(struct sde_hw_dspp *ctx, void *cfg); +/** + * reg_dmav2_setup_dspp_sixzonev2() - sixzone v2 impl using reg dma v2. + * @ctx: dspp ctx info + * @cfg: pointer to struct sde_hw_cp_cfg + */ +void reg_dmav2_setup_dspp_sixzonev2(struct sde_hw_dspp *ctx, void *cfg); + /** * reg_dmav1_setup_dspp_memcol_skinv17() - memcol skin v17 impl using * reg dma v1. diff --git a/msm/sde/sde_reg_dma.h b/msm/sde/sde_reg_dma.h index e02e4d3c..7533c966 100644 --- a/msm/sde/sde_reg_dma.h +++ b/msm/sde/sde_reg_dma.h @@ -102,16 +102,19 @@ enum sde_reg_dma_queue { #define LUTBUS_TABLE_SELECT_MAX 2 #define LUTBUS_IGC_TRANS_SIZE 3 #define LUTBUS_GAMUT_TRANS_SIZE 6 +#define LUTBUS_SIXZONE_TRANS_SIZE 5 /** * enum sde_reg_dma_lutbus_block - block select values for lutbus op * @LUTBUS_BLOCK_IGC: select IGC block * @LUTBUS_BLOCK_GAMUT: select GAMUT block + * @LUTBUS_BLOCK_SIXZONE: select SIXZONE block * @LUTBUS_BLOCK_MAX: invalid selection */ enum sde_reg_dma_lutbus_block { LUTBUS_BLOCK_IGC = 0, LUTBUS_BLOCK_GAMUT, + LUTBUS_BLOCK_SIXZONE = 3, LUTBUS_BLOCK_MAX, };