/**
* DSPP sub-blocks
* @SDE_DSPP_IGC DSPP Inverse gamma correction block
* @SDE_DSPP_PCC Panel color correction block
* @SDE_DSPP_GC Gamma correction block
* @SDE_DSPP_HSIC Global HSIC block
* @SDE_DSPP_MEMCOLOR Memory Color block
* @SDE_DSPP_SIXZONE Six zone block
* @SDE_DSPP_GAMUT Gamut block
* @SDE_DSPP_DITHER Dither block
* @SDE_DSPP_HIST Histogram block
* @SDE_DSPP_VLUT PA VLUT block
* @SDE_DSPP_AD AD block
* @SDE_DSPP_LTM LTM block
* @SDE_DSPP_SPR SPR block
* @SDE_DSPP_DEMURA Demura block
* @SDE_DSPP_RC RC block
* @SDE_DSPP_SB SB LUT DMA
* @SDE_DSPP_MAX maximum value
*/
Inverse gamma correction:反向gamma校正
HSIC: 色相(Hue)、饱和度(Saturation)、亮度(Intensity)、对比度(Contrast)
Memory Color:记忆色。(人们记忆中的颜色,可能存在某种程度上的偏好强化)
Six zone:Sixzone HSV。和HSV有什么区别?
Gamut:3d gamut
Dither:抖动,有1个4x4的矩阵
Histogram:直方图
PA VLUT:
AD:
TFT显示屏功耗控制方向——AD显示
AD显示是方案硬件平台(高通,MTK,展锐等)支持一种显示增强型技术。
实现原理:
1)根据环境光感度实时调整单像素的亮度。
2)模拟人视觉系统做单像素调节,修正对比度。
3)依据光线传感器ALS上报LUX值来确定AD调节强度和LCD亮度。
4)与CABC可并用。
来源:LCD这样设计可以多用半天
LTM:local tone mapping
SPR:
Demura:
RC:圆角
SB LUT:
vendor\qcom\opensource\display-drivers\msm\sde\sde_color_processing.c
static void _dspp_gc_install_property(struct drm_crtc *crtc)
snprintf(feature_name, ARRAY_SIZE(feature_name), "%s%d", "SDE_DSPP_GC_V", version);
_sde_cp_crtc_install_blob_property(crtc, feature_name, SDE_CP_CRTC_DSPP_GC, sizeof(struct drm_msm_pgc_lut));
struct drm_msm_pgc_lut {
__u64 flags;
__u32 c0[PGC_TBL_LEN];
__u32 c1[PGC_TBL_LEN];
__u32 c2[PGC_TBL_LEN];
};
定义了一个SDE_CP_CRTC_DSPP_GC property,用来传递gamma lut。
vendor\qcom\opensource\display-drivers\msm\msm_atomic.c
static void complete_commit(struct msm_commit *c)
drm_atomic_helper_commit_planes(dev, state, DRM_PLANE_COMMIT_ACTIVE_ONLY);
drivers\gpu\drm\drm_atomic_helper.c
void drm_atomic_helper_commit_planes(struct drm_device *dev, struct drm_atomic_state *old_state, uint32_t flags)
const struct drm_crtc_helper_funcs *funcs;
funcs = crtc->helper_private;
funcs->atomic_begin(crtc, old_state);
vendor\qcom\opensource\display-drivers\msm\sde\sde_crtc.c
static void sde_crtc_atomic_begin(struct drm_crtc *crtc, struct drm_crtc_state *old_state)
if (sde_kms_is_cp_operation_allowed(sde_kms))
sde_cp_crtc_apply_properties(crtc);
vendor\qcom\opensource\display-drivers\msm\sde\sde_color_processing.c
void sde_cp_crtc_apply_properties(struct drm_crtc *crtc)
list_for_each_entry_safe(prop_node, n, &sde_crtc->cp_dirty_list, cp_dirty_list) {
_sde_cp_crtc_commit_feature(prop_node, sde_crtc);
}
vendor\qcom\opensource\display-drivers\msm\sde\sde_color_processing.c
static void _sde_cp_crtc_commit_feature(struct sde_cp_node *prop_node, struct sde_crtc *sde_crtc)
memset(&hw_cfg, 0, sizeof(hw_cfg));
_sde_cp_get_cached_payload(prop_node, &hw_cfg, &feature_enabled);----------------------1
feature_wrapper commit_feature = set_crtc_feature_wrappers[prop_node->feature];
ret = commit_feature(hw_dspp, &hw_cfg, sde_crtc);
将blob->data赋给hw_cfg->payload。
feature_wrapper set_crtc_feature_wrappers[SDE_CP_CRTC_MAX_FEATURES];
#define setup_set_crtc_feature_wrappers(wrappers) \
do { \
memset(wrappers, 0, sizeof(wrappers)); \
wrappers[SDE_CP_CRTC_DSPP_VLUT] = _set_dspp_vlut_feature; \
wrappers[SDE_CP_CRTC_DSPP_PCC] = _set_dspp_pcc_feature; \
wrappers[SDE_CP_CRTC_DSPP_IGC] = _set_dspp_igc_feature; \
wrappers[SDE_CP_CRTC_DSPP_GC] = _set_dspp_gc_feature; \
wrappers[SDE_CP_CRTC_DSPP_HSIC] =\
_set_dspp_hsic_feature; \
wrappers[SDE_CP_CRTC_DSPP_MEMCOL_SKIN] = _set_dspp_memcol_skin_feature; \
wrappers[SDE_CP_CRTC_DSPP_MEMCOL_SKY] =\
_set_dspp_memcol_sky_feature; \
wrappers[SDE_CP_CRTC_DSPP_MEMCOL_FOLIAGE] =\
_set_dspp_memcol_foliage_feature; \
wrappers[SDE_CP_CRTC_DSPP_MEMCOL_PROT] = _set_dspp_memcol_prot_feature; \
wrappers[SDE_CP_CRTC_DSPP_SIXZONE] = _set_dspp_sixzone_feature; \
wrappers[SDE_CP_CRTC_DSPP_GAMUT] = _set_dspp_gamut_feature; \
wrappers[SDE_CP_CRTC_DSPP_DITHER] = _set_dspp_dither_feature; \
wrappers[SDE_CP_CRTC_DSPP_HIST_CTRL] = _set_dspp_hist_ctrl_feature; \
wrappers[SDE_CP_CRTC_DSPP_HIST_IRQ] = _set_dspp_hist_irq_feature; \
wrappers[SDE_CP_CRTC_DSPP_AD_MODE] = _set_dspp_ad_mode_feature; \
wrappers[SDE_CP_CRTC_DSPP_AD_INIT] = _set_dspp_ad_init_feature; \
wrappers[SDE_CP_CRTC_DSPP_AD_CFG] = _set_dspp_ad_cfg_feature; \
wrappers[SDE_CP_CRTC_DSPP_AD_INPUT] = _set_dspp_ad_input_feature; \
wrappers[SDE_CP_CRTC_DSPP_AD_ASSERTIVENESS] =\
_set_dspp_ad_assertive_feature; \
wrappers[SDE_CP_CRTC_DSPP_AD_BACKLIGHT] =\
_set_dspp_ad_backlight_feature; \
wrappers[SDE_CP_CRTC_DSPP_AD_STRENGTH] = _set_dspp_ad_strength_feature; \
wrappers[SDE_CP_CRTC_DSPP_AD_ROI] = _set_dspp_ad_roi_feature; \
wrappers[SDE_CP_CRTC_LM_GC] = _set_lm_gc_feature; \
wrappers[SDE_CP_CRTC_DSPP_LTM_INIT] = _set_ltm_init_feature; \
wrappers[SDE_CP_CRTC_DSPP_LTM_ROI] = _set_ltm_roi_feature; \
wrappers[SDE_CP_CRTC_DSPP_LTM_VLUT] = _set_ltm_vlut_feature; \
wrappers[SDE_CP_CRTC_DSPP_LTM_HIST_THRESH] = _set_ltm_thresh_feature; \
wrappers[SDE_CP_CRTC_DSPP_LTM_SET_BUF] = _set_ltm_buffers_feature; \
wrappers[SDE_CP_CRTC_DSPP_LTM_QUEUE_BUF] = _set_ltm_queue_buf_feature; \
wrappers[SDE_CP_CRTC_DSPP_LTM_QUEUE_BUF2] = _set_ltm_queue_buf_feature; \
wrappers[SDE_CP_CRTC_DSPP_LTM_QUEUE_BUF3] = _set_ltm_queue_buf_feature; \
wrappers[SDE_CP_CRTC_DSPP_LTM_HIST_CTL] = _set_ltm_hist_crtl_feature; \
wrappers[SDE_CP_CRTC_DSPP_RC_MASK] = _set_rc_mask_feature; \
wrappers[SDE_CP_CRTC_DSPP_SPR_INIT] = _set_spr_init_feature; \
wrappers[SDE_CP_CRTC_DSPP_DEMURA_INIT] = _set_demura_feature; \
} while (0)
static int _set_dspp_gc_feature(struct sde_hw_dspp *hw_dspp,
struct sde_hw_cp_cfg *hw_cfg, struct sde_crtc *hw_crtc)
hw_dspp->ops.setup_gc(hw_dspp, hw_cfg);
vendor\qcom\opensource\display-drivers\msm\sde\sde_hw_dspp.c
static void dspp_gc(struct sde_hw_dspp *c)
{
int ret = 0;
if (c->cap->sblk->gc.version == SDE_COLOR_PROCESS_VER(0x1, 8)) {
ret = reg_dmav1_init_dspp_op_v4(SDE_DSPP_GC, c->idx);
if (!ret)
c->ops.setup_gc = reg_dmav1_setup_dspp_gcv18;-------------------1
else
c->ops.setup_gc = sde_setup_dspp_gc_v1_7;-----------------------2
}
}
两种设置gamma lut的方式:
1.通过dma
2.直接写寄存器
vendor\qcom\opensource\display-drivers\msm\sde\sde_hw_color_processing_v1_7.c
void sde_setup_dspp_gc_v1_7(struct sde_hw_dspp *ctx, void *cfg)
{
struct drm_msm_pgc_lut *payload = NULL;
struct sde_hw_cp_cfg *hw_cfg = cfg;
u32 c0_off, c1_off, c2_off, i;
...
if (!hw_cfg->payload) {
DRM_DEBUG_DRIVER("Disable pgc feature\n");
SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->gc.base, 0);
return;
}
payload = hw_cfg->payload;
/* Initialize index offsets */
c0_off = ctx->cap->sblk->gc.base + PGC_C0_INDEX_OFF;
c1_off = c0_off + (sizeof(u32) * 2);
c2_off = c1_off + (sizeof(u32) * 2);
SDE_REG_WRITE(&ctx->hw, c0_off, 0);
SDE_REG_WRITE(&ctx->hw, c1_off, 0);
SDE_REG_WRITE(&ctx->hw, c2_off, 0);
/* Initialize table offsets */
c0_off = ctx->cap->sblk->gc.base + PGC_C0_OFF;
c1_off = c0_off + (sizeof(u32) * 2);
c2_off = c1_off + (sizeof(u32) * 2);
for (i = 0; i < PGC_TBL_LEN; i++) {
SDE_REG_WRITE(&ctx->hw, c0_off, payload->c0[i]);
SDE_REG_WRITE(&ctx->hw, c1_off, payload->c1[i]);
SDE_REG_WRITE(&ctx->hw, c2_off, payload->c2[i]);
}
SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->gc.base + PGC_LUT_SWAP_OFF, BIT(0));
i = BIT(0) | ((payload->flags & PGC_8B_ROUND) ? BIT(1) : 0);
SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->gc.base, i);
}
vendor\qcom\opensource\display-drivers\msm\sde\sde_hw_reg_dma_v1_color_proc.c
void reg_dmav1_setup_dspp_gcv18(struct sde_hw_dspp *ctx, void *cfg)
{
struct drm_msm_pgc_lut *lut_cfg;
struct sde_hw_reg_dma_ops *dma_ops;
struct sde_reg_dma_kickoff_cfg kick_off;
struct sde_hw_cp_cfg *hw_cfg = cfg;
...
if (!hw_cfg->payload) {
DRM_DEBUG_DRIVER("disable pgc feature\n");
LOG_FEATURE_OFF;
SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->gc.base, 0);
return;
}
lut_cfg = hw_cfg->payload;----------------------------------------------------------1
REG_DMA_INIT_OPS(dma_write_cfg, blk, GC, dspp_buf[GC][ctx->idx]);-------------------2
REG_DMA_SETUP_OPS(dma_write_cfg, 0, NULL, 0, HW_BLK_SELECT, 0, 0, 0);---------------3
rc = dma_ops->setup_payload(&dma_write_cfg);----------------------------------------4
if (rc) {
DRM_ERROR("write decode select failed ret %d\n", rc);
return;
}
addr[0] = lut_cfg->c0;
addr[1] = lut_cfg->c1;
addr[2] = lut_cfg->c2;
for (i = 0; i < GC_TBL_NUM; i++) {
reg = 0;
REG_DMA_SETUP_OPS(dma_write_cfg, ctx->cap->sblk->gc.base + GC_C0_INDEX_OFF + (i * sizeof(u32) * 2),
®, sizeof(reg), REG_SINGLE_WRITE, 0, 0, 0);--------------------------------5
rc = dma_ops->setup_payload(&dma_write_cfg);------------------------------------6
if (rc) {
DRM_ERROR("index init failed ret %d\n", rc);
return;
}
REG_DMA_SETUP_OPS(dma_write_cfg, ctx->cap->sblk->gc.base + GC_C0_OFF + (i * sizeof(u32) * 2),
addr[i], PGC_TBL_LEN * sizeof(u32), REG_BLK_WRITE_INC, 0, 0, 0);--------------7
rc = dma_ops->setup_payload(&dma_write_cfg);------------------------------------8
if (rc) {
DRM_ERROR("lut write failed ret %d\n", rc);
return;
}
}
reg = BIT(0);
REG_DMA_SETUP_OPS(dma_write_cfg, ctx->cap->sblk->gc.base + GC_LUT_SWAP_OFF,
®, sizeof(reg), REG_SINGLE_WRITE, 0, 0, 0);--------------------------------9
rc = dma_ops->setup_payload(&dma_write_cfg);------------------------------------10
if (rc) {
DRM_ERROR("setting swap offset failed ret %d\n", rc);
return;
}
reg = GC_EN | ((lut_cfg->flags & PGC_8B_ROUND) ? GC_8B_ROUND_EN : 0);
REG_DMA_SETUP_OPS(dma_write_cfg, ctx->cap->sblk->gc.base, ®, sizeof(reg),
REG_SINGLE_WRITE, 0, 0, 0);---------------------------------------11
rc = dma_ops->setup_payload(&dma_write_cfg);-----------------------------------12
if (rc) {
DRM_ERROR("enabling gamma correction failed ret %d\n", rc);
return;
}
REG_DMA_SETUP_KICKOFF(kick_off, hw_cfg->ctl, dspp_buf[GC][ctx->idx],
REG_DMA_WRITE, DMA_CTL_QUEUE0, WRITE_IMMEDIATE, GC);----------------------13
LOG_FEATURE_ON;
rc = dma_ops->kick_off(&kick_off);---------------------------------------------14
if (rc) {
DRM_ERROR("failed to kick off ret %d\n", rc);
return;
}
}
static struct sde_hw_reg_dma *reg_dma;
struct sde_hw_reg_dma {
struct drm_device *drm_dev;
u32 reg_dma_count;
const struct sde_reg_dma_cfg *caps;
struct sde_hw_reg_dma_ops ops;
void __iomem *addr;
};
reg_dma->ops.check_support = check_support_v1;
reg_dma->ops.setup_payload = setup_payload_v1;
reg_dma->ops.kick_off = kick_off_v1;
reg_dma->ops.reset = reset_v1;
reg_dma->ops.alloc_reg_dma_buf = alloc_reg_dma_buf_v1;
reg_dma->ops.dealloc_reg_dma = dealloc_reg_dma_v1;
reg_dma->ops.reset_reg_dma_buf = reset_reg_dma_buffer_v1;
reg_dma->ops.last_command = last_cmd_v1;
reg_dma->ops.dump_regs = dump_regs_v1;
1:lut_cfg 的值是通过property传下来的
2,3:对dma_write_cfg赋值
.blk = blk; .feature = GC; .dma_buf = dspp_buf[GC][ctx->idx];
.ops = HW_BLK_SELECT; .blk_offset = 0; .data_size = 0; .data = NULL; .inc = 0; wrap_size = 0; .mask = 0;
4:write decode select,不知道这个decode是什么
5:对dma_write_cfg赋值
.ops = REG_SINGLE_WRITE; .blk_offset = ctx->cap->sblk->gc.base + GC_C0_INDEX_OFF + (i * sizeof(u32) * 2);
.data_size = sizeof(reg); .data = ® .inc = 0; .wrap_size = 0; mask = 0;
6:往dma buffer写值
7:对dma_write_cfg赋值
.ops = REG_BLK_WRITE_INC; .blk_offset = ctx->cap->sblk->gc.base + GC_C0_OFF + (i * sizeof(u32) * 2);
.data_size = PGC_TBL_LEN * sizeof(u32); .data = addr[i]; .inc = 0; .wrap_size = 0; .mask = 0;
8:把gamma lut表拷贝到dma buffer
13:对dma_write_cfg赋值
.ctl = hw_cfg->ctl; .dma_buf = dspp_buf[GC][ctx->idx]; .op = REG_DMA_WRITE; .dma_type = REG_DMA_TYPE_DB;
.queue_select = DMA_CTL_QUEUE0; .trigger_mode = WRITE_IMMEDIATE; .feature = GC;
14:将dma buf的地址配到寄存器
缩写
DSPP: Destination Surface Processor
PA:picture adjustment