From c32a7f8a2ca5a6e5ffc0e67d8e0e646dc491d925 Mon Sep 17 00:00:00 2001 From: Algea Cao Date: Fri, 19 Jan 2024 10:41:31 +0800 Subject: [PATCH] drm/rockchip: vop3: Support rk3576 DCI DCI mainly completes the dynamic adjustment of the brightness and contrast of the picture according to the brightness distribution of the current picture, so that the picture appears more transparent. Only cluster0 supports DCI, suitable for minimum resolution of 128 x 128 and maximum resolution of 4096 x 2160. Change-Id: I1836d2d317172859b7df971ce4f4fb5dfb1b4c83 Signed-off-by: Algea Cao --- drivers/gpu/drm/rockchip/rockchip_drm_drv.h | 15 ++ drivers/gpu/drm/rockchip/rockchip_drm_vop.h | 23 ++ drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 238 ++++++++++++++++--- drivers/gpu/drm/rockchip/rockchip_vop2_reg.c | 36 ++- drivers/gpu/drm/rockchip/rockchip_vop_reg.h | 10 + 5 files changed, 287 insertions(+), 35 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h index e8c521ff6cbb..46320fb659d8 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h @@ -231,6 +231,21 @@ struct post_csc { u16 csc_enable; }; +#define ROCKCHIP_VOP_DCI_LUT_LENGTH 5632 + +struct dci_data { + u32 plat; /* Reserved to distinguish later platform */ + u8 dci_lut_data[ROCKCHIP_VOP_DCI_LUT_LENGTH]; + u32 blk_size_h_ratio; + u32 blk_size_v_ratio; + u32 dci_act_w; + u32 dci_act_h; + u32 adj0; + u32 adj1; + u32 uv_adj; + u32 dci_en; +}; + struct rockchip_crtc_state { struct drm_crtc_state base; int vp_id; diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h index 6497d6e6dce7..16aaa3e04aaf 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h @@ -717,6 +717,28 @@ struct vop2_cluster_regs { struct vop_reg scl_lb_mode; struct vop_reg frm_reset_en; + struct vop_reg blk_size_h; + struct vop_reg blk_size_v; + struct vop_reg blk_offset_h; + struct vop_reg blk_offset_v; + struct vop_reg blk_size_fix; + struct vop_reg pix_region_start_h; + struct vop_reg pix_region_start_v; + struct vop_reg sat_adj_zero; + struct vop_reg sat_adj_thr; + struct vop_reg sat_adj_k; + struct vop_reg sat_w; + struct vop_reg dci_en; + struct vop_reg uv_adjust_en; + struct vop_reg csc_range; + struct vop_reg dma_rid; + struct vop_reg dma_rlen; + struct vop_reg dci_dma_mst; + struct vop_reg debug_point_h; + struct vop_reg debug_point_v; + struct vop_reg debug_mode; + struct vop_reg debug_en; + struct vop_reg src_color_ctrl; struct vop_reg dst_color_ctrl; struct vop_reg src_alpha_ctrl; @@ -1055,6 +1077,7 @@ struct vop2_win_data { uint8_t axi_yrgb_id; uint8_t axi_uv_id; uint8_t possible_crtcs; + uint8_t dci_rid_id; uint32_t base; enum drm_plane_type type; diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c index e9e3772f9980..ebf9ffde941b 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c @@ -375,6 +375,8 @@ struct vop2_plane_state { int pdaf_data_type; bool async_commit; struct vop_dump_list *planlist; + + struct drm_property_blob *dci_data; }; struct vop2_win { @@ -488,6 +490,14 @@ struct vop2_win { struct drm_property *color_key_prop; struct drm_property *scale_prop; struct drm_property *name_prop; + /** + * @dci_data_prop: dci data interaction with userspace + */ + struct drm_property *dci_data_prop; + /** + * @dci_lut_gem_obj: gem obj to store dci lut + */ + struct rockchip_gem_object *dci_lut_gem_obj; }; struct vop2_cluster { @@ -1905,6 +1915,10 @@ static void vop2_win_disable(struct vop2_win *win, bool skip_splice_win) if (!win->parent && (win->feature & WIN_FEATURE_MULTI_AREA)) vop2_win_multi_area_disable(win); + /* disable post dci */ + if (win->feature & WIN_FEATURE_DCI) + VOP_CLUSTER_SET(vop2, win, dci_en, 0); + if (win->pd) { /* @@ -2886,6 +2900,25 @@ static void vop2_setup_scale(struct vop2 *vop2, struct vop2_win *win, } } +static bool vop2_is_full_range_csc_mode(int csc_mode) +{ + switch (csc_mode) { + case CSC_BT601L: + case CSC_BT709L: + case CSC_BT709L_13BIT: + case CSC_BT2020L_13BIT: + case CSC_BT2020L: + return false; + case CSC_BT601F: + case CSC_BT709F_13BIT: + case CSC_BT2020F_13BIT: + return true; + default: + DRM_ERROR("Unsupported csc mode:%d\n", csc_mode); + return true; + } +} + static enum vop_csc_format vop2_convert_csc_mode(enum drm_color_encoding color_encoding, enum drm_color_range color_range, int bit_depth) @@ -5361,6 +5394,102 @@ static const char *modifier_to_string(uint64_t modifier) } } +static void vop3_dci_config(struct vop2_win *win, struct vop2_plane_state *vpstate) +{ + struct vop2 *vop2 = win->vop2; + const struct vop2_data *vop2_data = vop2->data; + const struct vop2_win_data *win_data = &vop2_data->win[win->win_id]; + struct rockchip_gem_object *dci_gem_obj; + struct dci_data *dci_data; + struct drm_rect *src = &vpstate->src; + u32 *dci_lut_kvaddr; + dma_addr_t dci_lut_mst; + u16 blk_size_h, blk_size_v; + u16 blk_offset_h, blk_offset_v; + u16 pix_region_start_h, pix_region_start_v; + u32 blk_size_fix; + u32 blk_size_hor_half, blk_size_ver_half; + u8 dw, dh; + + if (!vpstate->dci_data || !vpstate->dci_data->data) { + VOP_CLUSTER_SET(vop2, win, dci_en, 0); + return; + } + + if (!win->dci_lut_gem_obj) { + dci_gem_obj = rockchip_gem_create_object(win->vop2->drm_dev, + ROCKCHIP_VOP_DCI_LUT_LENGTH, true, 0); + if (IS_ERR(dci_gem_obj)) { + DRM_ERROR("create dci lut obj failed\n"); + return; + } + win->dci_lut_gem_obj = dci_gem_obj; + } + + dci_data = (struct dci_data *)vpstate->dci_data->data; + + if (!dci_data->dci_en) { + VOP_CLUSTER_SET(vop2, win, dci_en, 0); + return; + } + + dw = src->x1; + dh = src->y1; + blk_size_h = (dci_data->blk_size_h_ratio * dci_data->dci_act_w + 512) >> 10; + blk_size_v = (dci_data->blk_size_v_ratio * dci_data->dci_act_h + 512) >> 10; + + blk_size_fix = DIV_ROUND_CLOSEST((1 << 25), ((blk_size_h - 1) * (blk_size_v - 1))); + blk_size_hor_half = DIV_ROUND_CLOSEST(blk_size_h, 2); + blk_size_ver_half = DIV_ROUND_CLOSEST(blk_size_v, 2); + + if (dw < blk_size_hor_half) + pix_region_start_h = 0; + else + pix_region_start_h = + DIV_ROUND_DOWN_ULL((u64)(dw - blk_size_hor_half), blk_size_h) + 1; + + if (dh < blk_size_ver_half) + pix_region_start_v = 0; + else + pix_region_start_v = + DIV_ROUND_DOWN_ULL((u64)(dh - blk_size_ver_half), blk_size_v) + 1; + + blk_offset_h = dw - blk_size_hor_half - ((pix_region_start_h - 1) * blk_size_h); + blk_offset_v = dh - blk_size_ver_half - ((pix_region_start_v - 1) * blk_size_v); + + dci_lut_kvaddr = (u32 *)win->dci_lut_gem_obj->kvaddr; + dci_lut_mst = win->dci_lut_gem_obj->dma_addr; + + memcpy(dci_lut_kvaddr, dci_data->dci_lut_data, ROCKCHIP_VOP_DCI_LUT_LENGTH); + + VOP_CLUSTER_SET(vop2, win, dci_dma_mst, dci_lut_mst); + /* dci dma rid */ + VOP_CLUSTER_SET(vop2, win, dma_rid, win_data->dci_rid_id); + VOP_CLUSTER_SET(vop2, win, dma_rlen, 0); + + VOP_CLUSTER_SET(vop2, win, blk_size_h, blk_size_h); + VOP_CLUSTER_SET(vop2, win, blk_size_v, blk_size_v); + + VOP_CLUSTER_SET(vop2, win, blk_offset_h, blk_offset_h); + VOP_CLUSTER_SET(vop2, win, blk_offset_v, blk_offset_v); + + VOP_CLUSTER_SET(vop2, win, pix_region_start_h, pix_region_start_h); + VOP_CLUSTER_SET(vop2, win, pix_region_start_v, pix_region_start_v); + + VOP_CLUSTER_SET(vop2, win, blk_size_fix, blk_size_fix); + + VOP_CLUSTER_SET(vop2, win, sat_adj_zero, dci_data->adj0 & 0xffff); + VOP_CLUSTER_SET(vop2, win, sat_adj_thr, (dci_data->adj0 >> 16) & 0xffff); + VOP_CLUSTER_SET(vop2, win, sat_adj_k, dci_data->adj1 & 0xffff); + VOP_CLUSTER_SET(vop2, win, sat_w, (dci_data->adj1 >> 16) & 0x7f); + + VOP_CLUSTER_SET(vop2, win, uv_adjust_en, dci_data->uv_adj); + VOP_CLUSTER_SET(vop2, win, csc_range, vop2_is_full_range_csc_mode(vpstate->csc_mode)); + VOP_CLUSTER_SET(vop2, win, dci_en, 1); + + VOP_CTRL_SET(vop2, lut_dma_en, 1); +} + static void vop2_win_atomic_update(struct vop2_win *win, struct drm_rect *src, struct drm_rect *dst, struct drm_plane_state *pstate) { @@ -5488,6 +5617,8 @@ static void vop2_win_atomic_update(struct vop2_win *win, struct drm_rect *src, s } vop2_setup_csc_mode(vp, vpstate); + if (win->feature & WIN_FEATURE_DCI) + vop3_dci_config(win, vpstate); afbc_half_block_en = vop2_afbc_half_block_enable(vpstate); @@ -5941,6 +6072,9 @@ static struct drm_plane_state *vop2_atomic_plane_duplicate_state(struct drm_plan vpstate->hdr_in = 0; vpstate->hdr2sdr_en = 0; + if (vpstate->dci_data) + drm_property_blob_get(vpstate->dci_data); + __drm_atomic_helper_plane_duplicate_state(plane, &vpstate->base); return &vpstate->base; @@ -5951,19 +6085,56 @@ static void vop2_atomic_plane_destroy_state(struct drm_plane *plane, { struct vop2_plane_state *vpstate = to_vop2_plane_state(state); + drm_property_blob_put(vpstate->dci_data); __drm_atomic_helper_plane_destroy_state(state); kfree(vpstate); } +/* copied from drm_atomic.c */ +static int +vop2_atomic_replace_property_blob_from_id(struct drm_device *dev, + struct drm_property_blob **blob, + uint64_t blob_id, + ssize_t expected_size, + ssize_t expected_elem_size, + bool *replaced) +{ + struct drm_property_blob *new_blob = NULL; + + if (blob_id != 0) { + new_blob = drm_property_lookup_blob(dev, blob_id); + if (new_blob == NULL) + return -EINVAL; + + if (expected_size > 0 && + new_blob->length != expected_size) { + drm_property_blob_put(new_blob); + return -EINVAL; + } + if (expected_elem_size > 0 && new_blob->length % expected_elem_size != 0) { + drm_property_blob_put(new_blob); + return -EINVAL; + } + } + + *replaced |= drm_property_replace_blob(blob, new_blob); + drm_property_blob_put(new_blob); + + return 0; +} + static int vop2_atomic_plane_set_property(struct drm_plane *plane, struct drm_plane_state *state, struct drm_property *property, uint64_t val) { + struct drm_device *drm_dev = plane->dev; struct rockchip_drm_private *private = plane->dev->dev_private; struct vop2_plane_state *vpstate = to_vop2_plane_state(state); struct vop2_win *win = to_vop2_win(plane); + int ret; + bool replaced = false; if (property == private->eotf_prop) { vpstate->eotf = val; @@ -5980,6 +6151,15 @@ static int vop2_atomic_plane_set_property(struct drm_plane *plane, return 0; } + if (property == win->dci_data_prop) { + ret = vop2_atomic_replace_property_blob_from_id(drm_dev, + &vpstate->dci_data, + val, + sizeof(struct dci_data), -1, + &replaced); + return ret; + } + DRM_ERROR("failed to set vop2 plane property id:%d, name:%s\n", property->base.id, property->name); @@ -6022,6 +6202,11 @@ static int vop2_atomic_plane_get_property(struct drm_plane *plane, return 0; } + if (property == win->dci_data_prop) { + *val = vpstate->dci_data ? vpstate->dci_data->base.id : 0; + return 0; + } + DRM_ERROR("failed to get vop2 plane property id:%d, name:%s\n", property->base.id, property->name); @@ -10931,40 +11116,6 @@ static int vop2_crtc_atomic_get_property(struct drm_crtc *crtc, return -EINVAL; } -/* copied from drm_atomic.c */ -static int -vop2_atomic_replace_property_blob_from_id(struct drm_device *dev, - struct drm_property_blob **blob, - uint64_t blob_id, - ssize_t expected_size, - ssize_t expected_elem_size, - bool *replaced) -{ - struct drm_property_blob *new_blob = NULL; - - if (blob_id != 0) { - new_blob = drm_property_lookup_blob(dev, blob_id); - if (new_blob == NULL) - return -EINVAL; - - if (expected_size > 0 && - new_blob->length != expected_size) { - drm_property_blob_put(new_blob); - return -EINVAL; - } - if (expected_elem_size > 0 && - new_blob->length % expected_elem_size != 0) { - drm_property_blob_put(new_blob); - return -EINVAL; - } - } - - *replaced |= drm_property_replace_blob(blob, new_blob); - drm_property_blob_put(new_blob); - - return 0; -} - static int vop2_crtc_atomic_set_property(struct drm_crtc *crtc, struct drm_crtc_state *state, struct drm_property *property, @@ -11556,6 +11707,22 @@ static int vop2_plane_create_feature_property(struct vop2 *vop2, struct vop2_win return 0; } +static int vop2_plane_create_dci_property(struct vop2 *vop2, struct vop2_win *win) +{ + struct drm_property *prop; + + prop = drm_property_create(vop2->drm_dev, DRM_MODE_PROP_BLOB, "DCI_DATA", 0); + if (!prop) { + DRM_DEV_ERROR(vop2->dev, "create dci data prop for win%d failed\n", + win->win_id); + return -ENOMEM; + } + win->dci_data_prop = prop; + drm_object_attach_property(&win->base.base, win->dci_data_prop, 0); + + return 0; +} + static bool vop3_ignore_plane(struct vop2 *vop2, struct vop2_win *win) { if (!is_vop3(vop2)) @@ -11673,6 +11840,9 @@ static int vop2_plane_init(struct vop2 *vop2, struct vop2_win *win, unsigned lon drm_plane_create_zpos_property(&win->base, win->win_id, 0, vop2->registered_num_wins - 1); vop2_plane_create_name_property(vop2, win); vop2_plane_create_feature_property(vop2, win); + if (win->feature & WIN_FEATURE_DCI) + vop2_plane_create_dci_property(vop2, win); + max_width = vop2->data->max_input.width; max_height = vop2->data->max_input.height; if (win->feature & WIN_FEATURE_CLUSTER_SUB) diff --git a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c index 9671b894b2a1..0004ec5a680d 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c +++ b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c @@ -2372,6 +2372,39 @@ static const struct vop2_cluster_regs rk3568_vop_cluster1 = { .dst_alpha_ctrl = VOP_REG(RK3568_CLUSTER1_MIX_DST_ALPHA_CTRL, 0xffffffff, 0), }; +static const struct vop2_cluster_regs rk3576_vop_cluster0 = { + .afbc_enable = VOP_REG(RK3568_CLUSTER0_CTRL, 0x1, 1), + .enable = VOP_REG(RK3568_CLUSTER0_CTRL, 1, 0), + .lb_mode = VOP_REG(RK3568_CLUSTER0_CTRL, 0xf, 4), + .scl_lb_mode = VOP_REG(RK3568_CLUSTER0_CTRL, 0x3, 9), + .frm_reset_en = VOP_REG(RK3568_CLUSTER0_CTRL, 1, 31), + .blk_size_h = VOP_REG(RK3576_CLUSTER0_DCI_BLK_SIZE, 0x1ff, 0), + .blk_size_v = VOP_REG(RK3576_CLUSTER0_DCI_BLK_SIZE, 0x1ff, 16), + .blk_offset_h = VOP_REG(RK3576_CLUSTER0_DCI_BLK_OFFSET, 0x1ff, 0), + .blk_offset_v = VOP_REG(RK3576_CLUSTER0_DCI_BLK_OFFSET, 0x1ff, 16), + .blk_size_fix = VOP_REG(RK3576_CLUSTER0_DCI_PIX_REGION, 0xfffff, 0), + .pix_region_start_h = VOP_REG(RK3576_CLUSTER0_DCI_PIX_REGION, 0x1f, 20), + .pix_region_start_v = VOP_REG(RK3576_CLUSTER0_DCI_PIX_REGION, 0x1f, 26), + .sat_adj_zero = VOP_REG(RK3576_CLUSTER0_DCI_LUMA_SAT_ADJ_0, 0xffff, 0), + .sat_adj_thr = VOP_REG(RK3576_CLUSTER0_DCI_LUMA_SAT_ADJ_0, 0xffff, 16), + .sat_adj_k = VOP_REG(RK3576_CLUSTER0_DCI_LUMA_SAT_ADJ_1, 0xffff, 0), + .sat_w = VOP_REG(RK3576_CLUSTER0_DCI_LUMA_SAT_ADJ_1, 0x7f, 16), + .dci_en = VOP_REG(RK3576_CLUSTER0_DCI_CTRL, 1, 0), + .uv_adjust_en = VOP_REG(RK3576_CLUSTER0_DCI_CTRL, 1, 1), + .csc_range = VOP_REG(RK3576_CLUSTER0_DCI_CTRL, 1, 2), + .dma_rid = VOP_REG(RK3576_CLUSTER0_DCI_CTRL, 0x1f, 4), + .dma_rlen = VOP_REG(RK3576_CLUSTER0_DCI_CTRL, 0x3, 12), + .dci_dma_mst = VOP_REG(RK3576_CLUSTER0_DCI_LUT_MST, 0xffffffff, 0), + .debug_point_h = VOP_REG(RK3576_CLUSTER0_DCI_DBG_CTRL, 0x1fff, 0), + .debug_point_v = VOP_REG(RK3576_CLUSTER0_DCI_DBG_CTRL, 0x1fff, 16), + .debug_mode = VOP_REG(RK3576_CLUSTER0_DCI_DBG_CTRL, 1, 30), + .debug_en = VOP_REG(RK3576_CLUSTER0_DCI_DBG_CTRL, 1, 31), + .src_color_ctrl = VOP_REG(RK3528_CLUSTER0_MIX_SRC_COLOR_CTRL, 0xffffffff, 0), + .dst_color_ctrl = VOP_REG(RK3528_CLUSTER0_MIX_DST_COLOR_CTRL, 0xffffffff, 0), + .src_alpha_ctrl = VOP_REG(RK3528_CLUSTER0_MIX_SRC_ALPHA_CTRL, 0xffffffff, 0), + .dst_alpha_ctrl = VOP_REG(RK3528_CLUSTER0_MIX_DST_ALPHA_CTRL, 0xffffffff, 0), +}; + static const struct vop2_cluster_regs rk3576_vop_cluster1 = { .afbc_enable = VOP_REG(RK3568_CLUSTER1_CTRL, 0x1, 1), .enable = VOP_REG(RK3568_CLUSTER1_CTRL, 1, 0), @@ -3417,7 +3450,7 @@ static const struct vop2_scl_regs rk3576_cluster0_win_scl = { static const struct vop2_win_regs rk3576_cluster0_win_data = { .scl = &rk3576_cluster0_win_scl, .afbc = &rk3576_cluster0_afbc, - .cluster = &rk3528_vop_cluster0, + .cluster = &rk3576_vop_cluster0, .enable = VOP_REG(RK3568_CLUSTER0_WIN0_CTRL0, 0x1, 0), .format = VOP_REG(RK3568_CLUSTER0_WIN0_CTRL0, 0x3f, 1), .tile_mode = VOP_REG(RK3568_CLUSTER0_WIN0_CTRL0, 0x1, 7), @@ -3651,6 +3684,7 @@ static const struct vop2_win_data rk3576_vop_win_data[] = { .pd_id = VOP2_PD_CLUSTER, .axi_yrgb_id = 0x02, .axi_uv_id = 0x03, + .dci_rid_id = 0x13, .possible_crtcs = 0x3,/* vp0 or vp1 */ .max_upscale_factor = 8, .max_downscale_factor = 8, diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.h b/drivers/gpu/drm/rockchip/rockchip_vop_reg.h index 19dbfedc04f6..c60dec668e2f 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.h +++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.h @@ -1399,6 +1399,16 @@ #define RK3576_CLUSTER0_WIN1_PLD_PTR_RANGE 0x10FC #define RK3568_CLUSTER0_CTRL 0x1100 +#define RK3576_CLUSTER0_DCI_BLK_SIZE 0x1104 +#define RK3576_CLUSTER0_DCI_BLK_OFFSET 0x1108 +#define RK3576_CLUSTER0_DCI_PIX_REGION 0x110C +#define RK3576_CLUSTER0_DCI_LUMA_SAT_ADJ_0 0x1110 +#define RK3576_CLUSTER0_DCI_LUMA_SAT_ADJ_1 0x1114 +#define RK3576_CLUSTER0_DCI_CTRL 0x1118 +#define RK3576_CLUSTER0_DCI_LUT_MST 0x111C +#define RK3576_CLUSTER0_DCI_DBG_CTRL 0x1120 +#define RK3576_CLUSTER0_DCI_DBG_PIX 0x1130 + #define RK3576_CLUSTER0_PORT_SEL_IMD 0x11F4 #define RK3576_CLUSTER0_DLY_NUM 0x11F8