From b7618fd33c611de77a7c34bada9c24596f89f19d Mon Sep 17 00:00:00 2001 From: Sandy Huang Date: Fri, 13 Jul 2018 10:17:35 +0800 Subject: [PATCH] drm/rockchip: rk3399 vop: add support win csc support rgb2yuv for yuv output, the csc matrix maybe bt601,bt601l,bt709 and bt2020, depend on connect output color space. Change-Id: Ibd8defc9a2519f850d8f3af7ee350022e5ee2ee4 Signed-off-by: Sandy Huang --- drivers/video/drm/rockchip_display.h | 1 + drivers/video/drm/rockchip_vop.c | 52 ++++++++++++++++++++++++++++ drivers/video/drm/rockchip_vop.h | 23 ++++++++++++ drivers/video/drm/rockchip_vop_reg.c | 40 +++++++++++++++++++++ 4 files changed, 116 insertions(+) diff --git a/drivers/video/drm/rockchip_display.h b/drivers/video/drm/rockchip_display.h index bd11805fe7..9d613abeaf 100644 --- a/drivers/video/drm/rockchip_display.h +++ b/drivers/video/drm/rockchip_display.h @@ -82,6 +82,7 @@ struct crtc_state { int crtc_y; int crtc_w; int crtc_h; + bool yuv_overlay; struct rockchip_mcu_timing mcu_timing; }; diff --git a/drivers/video/drm/rockchip_vop.c b/drivers/video/drm/rockchip_vop.c index 28dc622fbd..0d20bf1b53 100644 --- a/drivers/video/drm/rockchip_vop.c +++ b/drivers/video/drm/rockchip_vop.c @@ -236,6 +236,8 @@ static int rockchip_vop_init(struct display_state *state) vop->grf_ctrl = vop_data->grf_ctrl; vop->line_flag = vop_data->line_flag; + vop->csc_table = vop_data->csc_table; + vop->win_csc = vop_data->win_csc; vop->version = vop_data->version; vop->max_output = vop_data->max_output; @@ -388,6 +390,7 @@ static int rockchip_vop_init(struct display_state *state) post_r2y_en = true; } + crtc_state->yuv_overlay = yuv_overlay; post_csc_mode = to_vop_csc_mode(conn_state->color_space); VOP_CTRL_SET(vop, bcsh_r2y_en, post_r2y_en); VOP_CTRL_SET(vop, bcsh_y2r_en, post_y2r_en); @@ -584,6 +587,54 @@ static void scl_vop_cal_scl_fac(struct vop *vop, } } +static void vop_load_csc_table(struct vop *vop, u32 offset, const u32 *table) +{ + int i; + + /* + * so far the csc offset is not 0 and in the feature the csc offset + * impossible be 0, so when the offset is 0, should return here. + */ + if (!table || offset == 0) + return; + + for (i = 0; i < 8; i++) + vop_writel(vop, offset + i * 4, table[i]); +} + +static int rockchip_vop_setup_csc_table(struct display_state *state) +{ + struct crtc_state *crtc_state = &state->crtc_state; + struct connector_state *conn_state = &state->conn_state; + struct vop *vop = crtc_state->private; + const uint32_t *csc_table = NULL; + + if (!vop->csc_table || !crtc_state->yuv_overlay) + return 0; + /* todo: only implement r2y*/ + switch (conn_state->color_space) { + case V4L2_COLORSPACE_SMPTE170M: + csc_table = vop->csc_table->r2y_bt601_12_235; + break; + case V4L2_COLORSPACE_REC709: + case V4L2_COLORSPACE_DEFAULT: + case V4L2_COLORSPACE_JPEG: + csc_table = vop->csc_table->r2y_bt709; + break; + case V4L2_COLORSPACE_BT2020: + csc_table = vop->csc_table->r2y_bt2020; + break; + default: + csc_table = vop->csc_table->r2y_bt601; + break; + } + + vop_load_csc_table(vop, vop->win_csc->r2y_offset, csc_table); + VOP_WIN_CSC_SET(vop, r2y_en, 1); + + return 0; +} + static int rockchip_vop_set_plane(struct display_state *state) { struct crtc_state *crtc_state = &state->crtc_state; @@ -630,6 +681,7 @@ static int rockchip_vop_set_plane(struct display_state *state) VOP_WIN_SET(vop, src_alpha_ctl, 0); + rockchip_vop_setup_csc_table(state); VOP_WIN_SET(vop, enable, 1); vop_cfg_done(vop); diff --git a/drivers/video/drm/rockchip_vop.h b/drivers/video/drm/rockchip_vop.h index 03c48e4c7d..130e2a1cd6 100644 --- a/drivers/video/drm/rockchip_vop.h +++ b/drivers/video/drm/rockchip_vop.h @@ -58,6 +58,8 @@ REG_SET(x, name, 0, (x)->ctrl->name, v) #define VOP_LINE_FLAG_SET(x, name, v) \ REG_SET(x, name, 0, (x)->line_flag->name, v) +#define VOP_WIN_CSC_SET(x, name, v) \ + REG_SET(x, name, 0, (x)->win_csc->name, v) #define VOP_CTRL_GET(x, name) \ vop_read_reg(x, 0, &vop->ctrl->name) @@ -429,6 +431,23 @@ struct vop_rect { int height; }; +struct vop_csc_table { + const uint32_t *r2y_bt601; + const uint32_t *r2y_bt601_12_235; + const uint32_t *r2y_bt709; + const uint32_t *r2y_bt2020; +}; + +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; +}; + #define VOP_FEATURE_OUTPUT_10BIT BIT(0) struct vop_data { @@ -437,6 +456,8 @@ struct vop_data { const struct vop_win *win; const struct vop_line_flag *line_flag; const struct vop_grf_ctrl *grf_ctrl; + const struct vop_csc_table *csc_table; + const struct vop_csc *win_csc; int win_offset; int reg_len; u64 feature; @@ -453,6 +474,8 @@ struct vop { const struct vop_win *win; const struct vop_line_flag *line_flag; const struct vop_grf_ctrl *grf_ctrl; + const struct vop_csc_table *csc_table; + const struct vop_csc *win_csc; int win_offset; struct vop_rect max_output; }; diff --git a/drivers/video/drm/rockchip_vop_reg.c b/drivers/video/drm/rockchip_vop_reg.c index 66c9713e26..eed6d5b8b2 100644 --- a/drivers/video/drm/rockchip_vop_reg.c +++ b/drivers/video/drm/rockchip_vop_reg.c @@ -235,6 +235,42 @@ const struct vop_data rk3366_vop = { .reg_len = RK3366_DSP_VACT_ST_END_F1 * 4, }; +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_r2y_bt709[] = { + 0x027500bb, 0xff99003f, 0x01c2fea5, 0xfe6801c2, + 0x0000ffd7, 0x00010200, 0x00080200, 0x00080200, +}; + +static const uint32_t vop_csc_r2y_bt2020[] = { + 0x025300e6, 0xff830034, 0x01c1febd, 0xfe6401c1, + 0x0000ffdc, 0x00010200, 0x00080200, 0x00080200, +}; + +static const struct vop_csc_table rk3399_csc_table = { + .r2y_bt601 = vop_csc_r2y_bt601, + .r2y_bt601_12_235 = vop_csc_r2y_bt601_12_235, + .r2y_bt709 = vop_csc_r2y_bt709, + .r2y_bt2020 = vop_csc_r2y_bt2020, +}; + +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, +}; + const struct vop_data rk3399_vop_big = { .version = VOP_VERSION(3, 5), .max_output = {4096, 2160}, @@ -242,6 +278,8 @@ const struct vop_data rk3399_vop_big = { .ctrl = &rk3288_ctrl_data, .win = &rk3288_win01_data, .line_flag = &rk3366_vop_line_flag, + .csc_table = &rk3399_csc_table, + .win_csc = &rk3399_win0_csc, .reg_len = RK3399_DSP_VACT_ST_END_F1 * 4, }; @@ -251,6 +289,8 @@ const struct vop_data rk3399_vop_lit = { .ctrl = &rk3288_ctrl_data, .win = &rk3288_win01_data, .line_flag = &rk3366_vop_line_flag, + .csc_table = &rk3399_csc_table, + .win_csc = &rk3399_win0_csc, .reg_len = RK3399_DSP_VACT_ST_END_F1 * 4, };