From f6d1c63b4d8eefc99e38c38cf7014060b0ff3b25 Mon Sep 17 00:00:00 2001 From: Sandy Huang Date: Thu, 28 Jan 2021 17:15:37 +0800 Subject: [PATCH] drm/rockchip: vop2: add support cubic lut Change-Id: Iebf89a10b4bdfe630212b393019e926b6dde0e22 Signed-off-by: Sandy Huang --- drivers/gpu/drm/rockchip/rockchip_drm_vop.h | 7 ++ drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 124 +++++++++++++++++++ drivers/gpu/drm/rockchip/rockchip_vop2_reg.c | 6 + drivers/gpu/drm/rockchip/rockchip_vop_reg.h | 3 + 4 files changed, 140 insertions(+) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h index 4a716e8e4d59..7661bf3e155d 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h @@ -601,6 +601,11 @@ struct vop2_video_port_regs { struct vop_reg bcsh_y2r_en; struct vop_reg bcsh_out_mode; struct vop_reg bcsh_en; + + /* 3d lut */ + struct vop_reg cubic_lut_en; + struct vop_reg cubic_lut_update_en; + struct vop_reg cubic_lut_mst; }; struct vop2_wb_regs { @@ -675,6 +680,7 @@ struct vop2_video_port_data { uint32_t feature; uint64_t soc_id[VOP2_SOC_VARIANT]; uint16_t gamma_lut_len; + uint16_t cubic_lut_len; struct vop_rect max_output; const u8 pre_scan_max_dly[4]; const struct vop_intr *intr; @@ -747,6 +753,7 @@ struct vop2_ctrl { struct vop_reg version; struct vop_reg standby; struct vop_reg dma_stop; + struct vop_reg lut_dma_en; struct vop_reg axi_outstanding_max_num; struct vop_reg axi_max_outstanding_en; struct vop_reg hdmi_dclk_out_en; diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c index 605b71ac1a3b..5f0681a0f585 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c @@ -454,6 +454,21 @@ struct vop2_video_port { * @gamma_lut: atomic gamma look up table */ struct drm_color_lut *gamma_lut; + + /** + * @cubic_lut_len: cubic look up table size + */ + u32 cubic_lut_len; + + /** + * @cubic_lut_gem_obj: gem obj to store cubic lut + */ + struct rockchip_gem_object *cubic_lut_gem_obj; + + /** + * @cubic_lut: cubic look up table + */ + struct drm_color_lut *cubic_lut; }; struct vop2 { @@ -2058,6 +2073,60 @@ static int vop2_crtc_atomic_gamma_set(struct drm_crtc *crtc, return 0; } +static int vop2_crtc_atomic_cubic_lut_set(struct drm_crtc *crtc, + struct drm_crtc_state *old_state) +{ + struct vop2_video_port *vp = to_vop2_video_port(crtc); + struct drm_color_lut *lut = vp->cubic_lut; + struct vop2 *vop2 = vp->vop2; + u32 *cubic_lut_kvaddr; + dma_addr_t cubic_lut_mst; + unsigned int i; + + if (!vp->cubic_lut_len) { + DRM_ERROR("Video Port%d unsupported 3D lut\n", vp->id); + return -ENODEV; + } + + if (!vp->cubic_lut_gem_obj) { + size_t size = (vp->cubic_lut_len + 1) / 2 * 16; + + vp->cubic_lut_gem_obj = rockchip_gem_create_object(crtc->dev, size, true, 0); + if (IS_ERR(vp->cubic_lut_gem_obj)) + return -ENOMEM; + } + + cubic_lut_kvaddr = (u32 *)vp->cubic_lut_gem_obj->kvaddr; + cubic_lut_mst = vp->cubic_lut_gem_obj->dma_addr; + for (i = 0; i < vp->cubic_lut_len / 2; i++) { + *cubic_lut_kvaddr++ = (lut[2 * i].red & 0xfff) + + ((lut[2 * i].green & 0xfff) << 12) + + ((lut[2 * i].blue & 0xff) << 24); + *cubic_lut_kvaddr++ = ((lut[2 * i].blue & 0xf00) >> 8) + + ((lut[2 * i + 1].red & 0xfff) << 4) + + ((lut[2 * i + 1].green & 0xfff) << 16) + + ((lut[2 * i + 1].blue & 0xf) << 28); + *cubic_lut_kvaddr++ = (lut[2 * i + 1].blue & 0xff0) >> 4; + *cubic_lut_kvaddr++ = 0; + } + + if (vp->cubic_lut_len % 2) { + *cubic_lut_kvaddr++ = (lut[2 * i].red & 0xfff) + + ((lut[2 * i].green & 0xfff) << 12) + + ((lut[2 * i].blue & 0xff) << 24); + *cubic_lut_kvaddr++ = (lut[2 * i].blue & 0xf00) >> 8; + *cubic_lut_kvaddr++ = 0; + *cubic_lut_kvaddr = 0; + } + + VOP_MODULE_SET(vop2, vp, cubic_lut_mst, cubic_lut_mst); + VOP_MODULE_SET(vop2, vp, cubic_lut_update_en, 1); + VOP_MODULE_SET(vop2, vp, cubic_lut_en, 1); + VOP_CTRL_SET(vop2, lut_dma_en, 1); + + return 0; +} + static int vop2_core_clks_prepare_enable(struct vop2 *vop2) { int ret; @@ -3303,10 +3372,37 @@ static int vop2_gamma_show(struct seq_file *s, void *data) return 0; } +static int vop2_cubic_lut_show(struct seq_file *s, void *data) +{ + struct drm_info_node *node = s->private; + struct vop2 *vop2 = node->info_ent->data; + int i, j; + + for (i = 0; i < vop2->data->nr_vps; i++) { + struct vop2_video_port *vp = &vop2->vps[i]; + + if (!vp->cubic_lut_gem_obj || !vp->cubic_lut || !vp->crtc.state->enable) { + DEBUG_PRINT("Video port%d cubic lut disabled\n", vp->id); + continue; + } + DEBUG_PRINT("Video port%d cubic lut:\n", vp->id); + for (j = 0; j < vp->cubic_lut_len; j++) { + DEBUG_PRINT("%04d: 0x%04x 0x%04x 0x%04x\n", j, + vp->cubic_lut[j].red, + vp->cubic_lut[j].green, + vp->cubic_lut[j].blue); + } + DEBUG_PRINT("\n"); + } + + return 0; +} + #undef DEBUG_PRINT static struct drm_info_list vop2_debugfs_files[] = { { "gamma_lut", vop2_gamma_show, 0, NULL }, + { "cubic_lut", vop2_cubic_lut_show, 0, NULL }, }; static int vop2_crtc_debugfs_init(struct drm_minor *minor, struct drm_crtc *crtc) @@ -4707,6 +4803,14 @@ static void vop2_crtc_atomic_flush(struct drm_crtc *crtc, struct drm_crtc_state vp->gamma_lut = crtc->state->gamma_lut->data; vop2_crtc_atomic_gamma_set(crtc, crtc->state); } + + if (crtc->state->cubic_lut || vp->cubic_lut) { + if (crtc->state->cubic_lut) + vp->cubic_lut = crtc->state->cubic_lut->data; + vop2_crtc_atomic_cubic_lut_set(crtc, crtc->state); + } + } else { + VOP_MODULE_SET(vop2, vp, cubic_lut_update_en, 0); } spin_lock_irqsave(&vop2->irq_lock, flags); @@ -5312,6 +5416,25 @@ static int vop2_gamma_init(struct vop2 *vop2) return 0; } +static void vop2_cubic_lut_init(struct vop2 *vop2) +{ + const struct vop2_data *vop2_data = vop2->data; + const struct vop2_video_port_data *vp_data; + struct vop2_video_port *vp; + struct drm_crtc *crtc; + int i; + + for (i = 0; i < vop2_data->nr_vps; i++) { + vp = &vop2->vps[i]; + crtc = &vp->crtc; + vp_data = &vop2_data->vp[vp->id]; + vp->cubic_lut_len = vp_data->cubic_lut_len; + + if (vp->cubic_lut_len) + drm_crtc_enable_cubic_lut(crtc, vp->cubic_lut_len); + } +} + static int vop2_create_crtc(struct vop2 *vop2) { const struct vop2_data *vop2_data = vop2->data; @@ -5672,6 +5795,7 @@ static int vop2_bind(struct device *dev, struct device *master, void *data) ret = vop2_gamma_init(vop2); if (ret) return ret; + vop2_cubic_lut_init(vop2); vop2_wb_connector_init(vop2); pm_runtime_enable(&pdev->dev); diff --git a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c index 7a7915323b44..c1f1c78a1314 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c +++ b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c @@ -501,6 +501,10 @@ static const struct vop2_video_port_regs rk3568_vop_vp0_regs = { .bcsh_y2r_csc_mode = VOP_REG(RK3568_VP0_BCSH_CTRL, 0x3, 2), .bcsh_y2r_en = VOP_REG(RK3568_VP0_BCSH_CTRL, 0x1, 0), .bcsh_en = VOP_REG(RK3568_VP0_BCSH_COLOR_BAR, 0x1, 31), + + .cubic_lut_en = VOP_REG(RK3568_VP0_3D_LUT_CTRL, 0x1, 0), + .cubic_lut_update_en = VOP_REG(RK3568_VP0_3D_LUT_CTRL, 0x1, 2), + .cubic_lut_mst = VOP_REG(RK3568_VP0_3D_LUT_MST, 0xffffffff, 0), }; static const struct vop2_video_port_regs rk3568_vop_vp1_regs = { @@ -607,6 +611,7 @@ static const struct vop2_video_port_data rk3568_vop_video_ports[] = { .soc_id = { 0x3568, 0x3566 }, .feature = VOP_FEATURE_OUTPUT_10BIT, .gamma_lut_len = 1024, + .cubic_lut_len = 729, /* 9x9x9 */ .max_output = { 4096, 2304 }, .pre_scan_max_dly = { 69, 53, 53, 42 }, .intr = &rk3568_vp0_intr, @@ -1157,6 +1162,7 @@ static const struct vop2_ctrl rk3568_vop_ctrl = { .ovl_port_mux_cfg_done_imd = VOP_REG(RK3568_OVL_CTRL, 0x1, 28), .if_ctrl_cfg_done_imd = VOP_REG(RK3568_DSP_IF_POL, 0x1, 28), .version = VOP_REG(RK3568_VERSION_INFO, 0xffff, 16), + .lut_dma_en = VOP_REG(RK3568_SYS_AXI_LUT_CTRL, 0x1, 0), .cluster0_src_color_ctrl = VOP_REG(RK3568_CLUSTER0_MIX_SRC_COLOR_CTRL, 0xffffffff, 0), .cluster0_dst_color_ctrl = VOP_REG(RK3568_CLUSTER0_MIX_DST_COLOR_CTRL, 0xffffffff, 0), .cluster0_src_alpha_ctrl = VOP_REG(RK3568_CLUSTER0_MIX_SRC_ALPHA_CTRL, 0xffffffff, 0), diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.h b/drivers/gpu/drm/rockchip/rockchip_vop_reg.h index 2c8d1d2e935c..b1bcd0b0cb79 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.h +++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.h @@ -1054,6 +1054,7 @@ #define RK3568_VOP2_GLB_CFG_DONE_EN BIT(15) #define RK3568_VERSION_INFO 0x004 #define RK3568_SYS_AUTO_GATING_CTRL 0x008 +#define RK3568_SYS_AXI_LUT_CTRL 0x024 #define RK3568_DSP_IF_EN 0x028 #define RK3568_DSP_IF_CTRL 0x02c #define RK3568_DSP_IF_POL 0x030 @@ -1087,6 +1088,8 @@ #define RK3568_VP0_DSP_CTRL 0xC00 #define RK3568_VP0_MIPI_CTRL 0xC04 #define RK3568_VP0_COLOR_BAR_CTRL 0xC08 +#define RK3568_VP0_3D_LUT_CTRL 0xC10 +#define RK3568_VP0_3D_LUT_MST 0xC20 #define RK3568_VP0_DSP_BG 0xC2C #define RK3568_VP0_PRE_SCAN_HTIMING 0xC30 #define RK3568_VP0_POST_DSP_HACT_INFO 0xC34