DRM驱动代码分析:色彩管理

高通PQ有哪些子模块?

/**
 * 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:

配置gamma表

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);
}

通过dma:

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),
			&reg, 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,
		&reg, 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, &reg, 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

猜你喜欢

转载自blog.csdn.net/yuuu_cheer/article/details/129805418