From ce4accc72588525423712978a5dd352b372f2f1e Mon Sep 17 00:00:00 2001 From: Mark Yao Date: Tue, 6 Sep 2016 17:18:38 +0800 Subject: [PATCH] drm/rockchip: vop: support csc convert for win0/1 Change-Id: I7be5dfb7d2711de5a5aeed730aea0ffd9e080945 Signed-off-by: Mark Yao --- drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 167 ++++++++++++++++++++ drivers/gpu/drm/rockchip/rockchip_drm_vop.h | 56 +++++++ drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 106 ++++++++++++- 3 files changed, 326 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index 7255232b5a28..fe4b96cbd420 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -72,6 +72,8 @@ #define VOP_WIN_SET(x, win, name, v) \ REG_SET(x, name, win->offset, VOP_WIN_NAME(win, name), v, true) +#define VOP_WIN_SET_EXT(x, win, ext, name, v) \ + REG_SET(x, name, win->offset, win->ext->name, v, true) #define VOP_SCL_SET(x, win, name, v) \ REG_SET(x, name, win->offset, win->phy->scl->name, v, true) #define VOP_SCL_SET_EXT(x, win, name, v) \ @@ -130,6 +132,9 @@ struct vop_plane_state { struct drm_rect dest; dma_addr_t yrgb_mst; dma_addr_t uv_mst; + const uint32_t *y2r_table; + const uint32_t *r2r_table; + const uint32_t *r2y_table; bool enable; }; @@ -142,6 +147,7 @@ struct vop_win { uint32_t offset; enum drm_plane_type type; const struct vop_win_phy *phy; + const struct vop_csc *csc; const uint32_t *data_formats; uint32_t nformats; struct vop *vop; @@ -258,6 +264,17 @@ static inline uint32_t vop_get_intr_type(struct vop *vop, return ret; } +static void vop_load_csc_table(struct vop *vop, u32 offset, const u32 *table) +{ + int i; + + if (!table) + return; + + for (i = 0; i < 8; i++) + vop_writel(vop, offset + i * 4, table[i]); +} + static inline void vop_cfg_done(struct vop *vop) { VOP_CTRL_SET(vop, cfg_done, 1); @@ -483,6 +500,140 @@ static void scl_vop_cal_scl_fac(struct vop *vop, struct vop_win *win, } } +/* + * rk3399 colorspace path: + * Input Win csc Output + * 1. YUV(2020) --> Y2R->2020To709->R2Y --> YUV_OUTPUT(601/709) + * RGB --> R2Y __/ + * + * 2. YUV(2020) --> bypasss --> YUV_OUTPUT(2020) + * RGB --> 709To2020->R2Y __/ + * + * 3. YUV(2020) --> Y2R->2020To709 --> RGB_OUTPUT(709) + * RGB --> R2Y __/ + * + * 4. YUV(601/709)-> Y2R->709To2020->R2Y --> YUV_OUTPUT(2020) + * RGB --> 709To2020->R2Y __/ + * + * 5. YUV(601/709)-> bypass --> YUV_OUTPUT(709) + * RGB --> R2Y __/ + * + * 6. YUV(601/709)-> bypass --> YUV_OUTPUT(601) + * RGB --> R2Y(601) __/ + * + * 7. YUV --> Y2R(709) --> RGB_OUTPUT(709) + * RGB --> bypass __/ + * + * 8. RGB --> 709To2020->R2Y --> YUV_OUTPUT(2020) + * + * 9. RGB --> R2Y(709) --> YUV_OUTPUT(709) + * + * 10. RGB --> R2Y(601) --> YUV_OUTPUT(601) + * + * 11. RGB --> bypass --> RGB_OUTPUT(709) + */ +static int vop_csc_setup(const struct vop_csc_table *csc_table, + bool is_input_yuv, bool is_output_yuv, + int input_csc, int output_csc, + const uint32_t **y2r_table, + const uint32_t **r2r_table, + const uint32_t **r2y_table) +{ + *y2r_table = NULL; + *r2r_table = NULL; + *r2y_table = NULL; + + if (is_output_yuv) { + if (output_csc == CSC_BT2020) { + if (is_input_yuv) { + if (input_csc == CSC_BT2020) + return 0; + *y2r_table = csc_table->y2r_bt709; + } + if (input_csc != CSC_BT2020) + *r2r_table = csc_table->r2r_bt709_to_bt2020; + *r2y_table = csc_table->r2y_bt2020; + } else { + if (is_input_yuv && input_csc == CSC_BT2020) + *y2r_table = csc_table->y2r_bt2020; + if (input_csc == CSC_BT2020) + *r2r_table = csc_table->r2r_bt2020_to_bt709; + if (!is_input_yuv || y2r_table) { + if (output_csc == CSC_BT709) + *r2y_table = csc_table->r2y_bt709; + else + *r2y_table = csc_table->r2y_bt601; + } + } + + } else { + if (!is_input_yuv) + return 0; + + /* + * is possible use bt2020 on rgb mode? + */ + if (WARN_ON(output_csc == CSC_BT2020)) + return -EINVAL; + + if (input_csc == CSC_BT2020) + *y2r_table = csc_table->y2r_bt2020; + else if (input_csc == CSC_BT709) + *y2r_table = csc_table->y2r_bt709; + else + *y2r_table = csc_table->y2r_bt601; + + if (input_csc == CSC_BT2020) + /* + * We don't have bt601 to bt709 table, force use bt709. + */ + *r2r_table = csc_table->r2r_bt2020_to_bt709; + } + + return 0; +} + +static int vop_csc_atomic_check(struct drm_crtc *crtc, + struct drm_crtc_state *crtc_state) +{ + struct vop *vop = to_vop(crtc); + struct drm_atomic_state *state = crtc_state->state; + const struct vop_csc_table *csc_table = vop->data->csc_table; + struct drm_plane_state *pstate; + struct drm_plane *plane; + bool is_yuv; + int ret; + + if (!csc_table) + return 0; + + drm_atomic_crtc_state_for_each_plane(plane, crtc_state) { + struct vop_plane_state *vop_plane_state; + + pstate = drm_atomic_get_plane_state(state, plane); + if (IS_ERR(pstate)) + return PTR_ERR(pstate); + vop_plane_state = to_vop_plane_state(pstate); + + if (!pstate->fb) + continue; + is_yuv = is_yuv_support(pstate->fb->pixel_format); + + /* + * TODO: force set input and output csc mode. + */ + ret = vop_csc_setup(csc_table, is_yuv, false, + CSC_BT709, CSC_BT709, + &vop_plane_state->y2r_table, + &vop_plane_state->r2r_table, + &vop_plane_state->r2y_table); + if (ret) + return ret; + } + + return 0; +} + static void vop_dsp_hold_valid_irq_enable(struct vop *vop) { unsigned long flags; @@ -774,6 +925,9 @@ static void vop_plane_atomic_update(struct drm_plane *plane, uint32_t act_info, dsp_info, dsp_st; struct drm_rect *src = &vop_plane_state->src; struct drm_rect *dest = &vop_plane_state->dest; + const uint32_t *y2r_table = vop_plane_state->y2r_table; + const uint32_t *r2r_table = vop_plane_state->r2r_table; + const uint32_t *r2y_table = vop_plane_state->r2y_table; int ymirror, xmirror; uint32_t val; bool rb_swap; @@ -843,6 +997,14 @@ static void vop_plane_atomic_update(struct drm_plane *plane, VOP_WIN_SET(vop, win, alpha_en, 0); } + if (win->csc) { + vop_load_csc_table(vop, win->csc->y2r_offset, y2r_table); + vop_load_csc_table(vop, win->csc->r2r_offset, r2r_table); + vop_load_csc_table(vop, win->csc->r2r_offset, r2y_table); + VOP_WIN_SET_EXT(vop, win, csc, y2r_en, !!y2r_table); + VOP_WIN_SET_EXT(vop, win, csc, r2r_en, !!r2r_table); + VOP_WIN_SET_EXT(vop, win, csc, r2y_en, !!r2y_table); + } VOP_WIN_SET(vop, win, enable, 1); spin_unlock(&vop->reg_lock); vop->is_iommu_needed = true; @@ -1164,6 +1326,10 @@ static int vop_crtc_atomic_check(struct drm_crtc *crtc, int dsp_layer_sel = 0; int i, j, cnt = 0, ret = 0; + ret = vop_csc_atomic_check(crtc, crtc_state); + if (ret) + return ret; + pzpos = kmalloc_array(vop_data->win_size, sizeof(*pzpos), GFP_KERNEL); if (!pzpos) return -ENOMEM; @@ -1576,6 +1742,7 @@ static int vop_win_init(struct vop *vop) continue; vop_win->phy = win_data->phy; + vop_win->csc = win_data->csc; vop_win->offset = win_data->base; vop_win->type = win_data->type; vop_win->data_formats = win_data->phy->data_formats; diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h index c2233ce31757..1731e184396c 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h @@ -23,6 +23,17 @@ #define VOP_MAJOR(version) ((version) >> 8) #define VOP_MINOR(version) ((version) & 0xff) +enum vop_csc_format { + CSC_BT601, + CSC_BT709, + CSC_BT2020, +}; + +enum vop_csc_mode { + CSC_RGB, + CSC_YUV, +}; + enum vop_data_format { VOP_FMT_ARGB8888 = 0, VOP_FMT_RGB888, @@ -47,6 +58,16 @@ struct vop_reg { uint32_t write_mask:1; }; +struct vop_csc { + struct vop_reg y2r_en; + struct vop_reg r2r_en; + struct vop_reg r2y_en; + + uint32_t y2r_offset; + uint32_t r2r_offset; + uint32_t r2y_offset; +}; + struct vop_ctrl { struct vop_reg standby; struct vop_reg htotal_pw; @@ -136,6 +157,39 @@ struct vop_scl_regs { struct vop_reg scale_cbcr_y; }; +struct vop_csc_table { + const uint32_t *y2r_bt601; + const uint32_t *y2r_bt601_12_235; + const uint32_t *y2r_bt601_10bit; + const uint32_t *y2r_bt601_10bit_12_235; + const uint32_t *r2y_bt601; + const uint32_t *r2y_bt601_12_235; + const uint32_t *r2y_bt601_10bit; + const uint32_t *r2y_bt601_10bit_12_235; + + const uint32_t *y2r_bt709; + const uint32_t *y2r_bt709_10bit; + const uint32_t *r2y_bt709; + const uint32_t *r2y_bt709_10bit; + + const uint32_t *y2r_bt2020; + const uint32_t *r2y_bt2020; + + const uint32_t *r2r_bt709_to_bt2020; + const uint32_t *r2r_bt2020_to_bt709; +}; + +enum { + VOP_CSC_Y2R_BT601, + VOP_CSC_Y2R_BT709, + VOP_CSC_Y2R_BT2020, + VOP_CSC_R2Y_BT601, + VOP_CSC_R2Y_BT709, + VOP_CSC_R2Y_BT2020, + VOP_CSC_R2R_BT2020_TO_BT709, + VOP_CSC_R2R_BT709_TO_2020, +}; + struct vop_win_phy { const struct vop_scl_regs *scl; const uint32_t *data_formats; @@ -168,6 +222,7 @@ struct vop_win_data { enum drm_plane_type type; const struct vop_win_phy *phy; const struct vop_win_phy **area; + const struct vop_csc *csc; unsigned int area_size; }; @@ -179,6 +234,7 @@ struct vop_data { const struct vop_ctrl *ctrl; const struct vop_intr *intr; const struct vop_win_data *win; + const struct vop_csc_table *csc_table; unsigned int win_size; uint32_t version; u64 feature; diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c index 4298e091350f..f77a6522e063 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c @@ -371,17 +371,116 @@ static const struct vop_data rk3366_vop = { .win_size = ARRAY_SIZE(rk3368_vop_win_data), }; +static const uint32_t vop_csc_y2r_bt601[] = { + 0x00000400, 0x0400059c, 0xfd25fea0, 0x07170400, + 0x00000000, 0xfffecab4, 0x00087932, 0xfff1d4f2, +}; + +static const uint32_t vop_csc_y2r_bt601_12_235[] = { + 0x000004a8, 0x04a80662, 0xfcbffe6f, 0x081204a8, + 0x00000000, 0xfff2134e, 0x00087b58, 0xffeeb4b0, +}; + +static const uint32_t vop_csc_r2y_bt601[] = { + 0x02590132, 0xff530075, 0x0200fead, 0xfe530200, + 0x0000ffad, 0x00000200, 0x00080200, 0x00080200, +}; + +static const uint32_t vop_csc_r2y_bt601_12_235[] = { + 0x02040107, 0xff680064, 0x01c2fed6, 0xffb7fe87, + 0x0000ffb7, 0x00010200, 0x00080200, 0x00080200, +}; + +static const uint32_t vop_csc_y2r_bt709[] = { + 0x000004a8, 0x04a8072c, 0xfddeff26, 0x087304a8, + 0x00000000, 0xfff08077, 0x0004cfed, 0xffedf1b8, +}; + +static const uint32_t vop_csc_r2y_bt709[] = { + 0x027500bb, 0xff99003f, 0x01c2fea5, 0xfe6801c2, + 0xffd7fe68, 0x00010200, 0x00080200, 0x00080200, +}; + +static const uint32_t vop_csc_y2r_bt2020[] = { + 0x000004a8, 0x04a806b6, 0xfd66ff40, 0x089004a8, + 0x00000000, 0xfff16bfc, 0x00058ae9, 0xffedb828, +}; + +static const uint32_t vop_csc_r2y_bt2020[] = { + 0x025300e6, 0xff830034, 0x01c1febd, 0xfe6401c1, + 0x0000ffdc, 0x00010200, 0x00080200, 0x00080200, +}; + +static const uint32_t vop_csc_r2r_bt709_to_bt2020[] = { + 0xfda606a4, 0xff80ffb5, 0xfff80488, 0xff99ffed, + 0x0000047a, 0x00000200, 0x00000200, 0x00000200, +}; + +static const uint32_t vop_csc_r2r_bt2020_to_bt709[] = { + 0x01510282, 0x0047002c, 0x000c03ae, 0x005a0011, + 0x00000394, 0x00000200, 0x00000200, 0x00000200, +}; + +static const struct vop_csc_table rk3399_csc_table = { + .y2r_bt601 = vop_csc_y2r_bt601, + .y2r_bt601_12_235 = vop_csc_y2r_bt601_12_235, + .r2y_bt601 = vop_csc_r2y_bt601, + .r2y_bt601_12_235 = vop_csc_r2y_bt601_12_235, + + .y2r_bt709 = vop_csc_y2r_bt709, + .r2y_bt709 = vop_csc_r2y_bt709, + + .y2r_bt2020 = vop_csc_y2r_bt2020, + .r2y_bt2020 = vop_csc_r2y_bt2020, + + .r2r_bt709_to_bt2020 = vop_csc_r2r_bt709_to_bt2020, + .r2r_bt2020_to_bt709 = vop_csc_r2r_bt2020_to_bt709, +}; + +static const struct vop_csc rk3399_win0_csc = { + .r2r_en = VOP_REG(RK3399_YUV2YUV_WIN, 0x1, 0), + .y2r_en = VOP_REG(RK3399_YUV2YUV_WIN, 0x1, 1), + .r2y_en = VOP_REG(RK3399_YUV2YUV_WIN, 0x1, 2), + .y2r_offset = RK3399_WIN0_YUV2YUV_Y2R, + .r2r_offset = RK3399_WIN0_YUV2YUV_3X3, + .r2y_offset = RK3399_WIN0_YUV2YUV_R2Y, +}; + +static const struct vop_csc rk3399_win1_csc = { + .r2r_en = VOP_REG(RK3399_YUV2YUV_WIN, 0x1, 8), + .y2r_en = VOP_REG(RK3399_YUV2YUV_WIN, 0x1, 9), + .r2y_en = VOP_REG(RK3399_YUV2YUV_WIN, 0x1, 10), + .y2r_offset = RK3399_WIN1_YUV2YUV_Y2R, + .r2r_offset = RK3399_WIN1_YUV2YUV_3X3, + .r2y_offset = RK3399_WIN1_YUV2YUV_R2Y, +}; + +static const struct vop_win_data rk3399_vop_win_data[] = { + { .base = 0x00, .phy = &rk3288_win01_data, .csc = &rk3399_win0_csc, + .type = DRM_PLANE_TYPE_PRIMARY }, + { .base = 0x40, .phy = &rk3288_win01_data, .csc = &rk3399_win1_csc, + .type = DRM_PLANE_TYPE_OVERLAY }, + { .base = 0x00, .phy = &rk3368_win23_data, + .type = DRM_PLANE_TYPE_OVERLAY, + .area = rk3368_area_data, + .area_size = ARRAY_SIZE(rk3368_area_data), }, + { .base = 0x50, .phy = &rk3368_win23_data, + .type = DRM_PLANE_TYPE_CURSOR, + .area = rk3368_area_data, + .area_size = ARRAY_SIZE(rk3368_area_data), }, +}; + static const struct vop_data rk3399_vop_big = { .version = VOP_VERSION(3, 5), .feature = VOP_FEATURE_OUTPUT_10BIT, .intr = &rk3366_vop_intr, .ctrl = &rk3288_ctrl_data, - .win = rk3368_vop_win_data, - .win_size = ARRAY_SIZE(rk3368_vop_win_data), + .win = rk3399_vop_win_data, + .win_size = ARRAY_SIZE(rk3399_vop_win_data), }; static const struct vop_win_data rk3399_vop_lit_win_data[] = { - { .base = 0x00, .phy = &rk3288_win01_data, + { .base = 0x00, .phy = &rk3288_win01_data, .csc = &rk3399_win0_csc, .type = DRM_PLANE_TYPE_PRIMARY }, { .phy = NULL }, { .base = 0x00, .phy = &rk3368_win23_data, @@ -394,6 +493,7 @@ static const struct vop_win_data rk3399_vop_lit_win_data[] = { static const struct vop_data rk3399_vop_lit = { .version = VOP_VERSION(3, 6), + .csc_table = &rk3399_csc_table, .intr = &rk3366_vop_intr, .ctrl = &rk3288_ctrl_data, .win = rk3399_vop_lit_win_data, -- 2.34.1