diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 40 | ||||
-rw-r--r-- | drivers/gpu/drm/rockchip/rockchip_drm_vop.h | 13 | ||||
-rw-r--r-- | drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 36 |
3 files changed, 88 insertions, 1 deletions
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index 26ec62ef2dbd..9c7267b49a4a 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -54,6 +54,18 @@ vop_reg_set(vop, &win->phy->scl->ext->name, \ win->base, ~0, v, #name) +#define VOP_WIN_YUV2YUV_SET(x, win_yuv2yuv, name, v) \ + do { \ + if (win_yuv2yuv && win_yuv2yuv->name.mask) \ + vop_reg_set(vop, &win_yuv2yuv->name, 0, ~0, v, #name); \ + } while (0) + +#define VOP_WIN_YUV2YUV_COEFFICIENT_SET(x, win_yuv2yuv, name, v) \ + do { \ + if (win_yuv2yuv && win_yuv2yuv->phy->name.mask) \ + vop_reg_set(vop, &win_yuv2yuv->phy->name, win_yuv2yuv->base, ~0, v, #name); \ + } while (0) + #define VOP_INTR_SET_MASK(vop, name, mask, v) \ vop_reg_set(vop, &vop->data->intr->name, 0, mask, v, #name) @@ -86,6 +98,18 @@ #define to_vop(x) container_of(x, struct vop, crtc) #define to_vop_win(x) container_of(x, struct vop_win, base) +/* + * The coefficients of the following matrix are all fixed points. + * The format is S2.10 for the 3x3 part of the matrix, and S9.12 for the offsets. + * They are all represented in two's complement. + */ +static const uint32_t bt601_yuv2rgb[] = { + 0x4A8, 0x0, 0x662, + 0x4A8, 0x1E6F, 0x1CBF, + 0x4A8, 0x812, 0x0, + 0x321168, 0x0877CF, 0x2EB127 +}; + enum vop_pending { VOP_PENDING_FB_UNREF, }; @@ -93,6 +117,7 @@ enum vop_pending { struct vop_win { struct drm_plane base; const struct vop_win_data *data; + const struct vop_win_yuv2yuv_data *yuv2yuv_data; struct vop *vop; }; @@ -714,6 +739,7 @@ static void vop_plane_atomic_update(struct drm_plane *plane, struct drm_crtc *crtc = state->crtc; struct vop_win *vop_win = to_vop_win(plane); const struct vop_win_data *win = vop_win->data; + const struct vop_win_yuv2yuv_data *win_yuv2yuv = vop_win->yuv2yuv_data; struct vop *vop = to_vop(state->crtc); struct drm_framebuffer *fb = state->fb; unsigned int actual_w, actual_h; @@ -729,6 +755,8 @@ static void vop_plane_atomic_update(struct drm_plane *plane, bool rb_swap; int win_index = VOP_WIN_TO_INDEX(vop_win); int format; + int is_yuv = fb->format->is_yuv; + int i; /* * can't update plane when vop is disabled. @@ -769,7 +797,9 @@ static void vop_plane_atomic_update(struct drm_plane *plane, VOP_WIN_SET(vop, win, format, format); VOP_WIN_SET(vop, win, yrgb_vir, DIV_ROUND_UP(fb->pitches[0], 4)); VOP_WIN_SET(vop, win, yrgb_mst, dma_addr); - if (fb->format->is_yuv) { + VOP_WIN_YUV2YUV_SET(vop, win_yuv2yuv, y2r_en, is_yuv); + + if (is_yuv) { int hsub = drm_format_horz_chroma_subsampling(fb->format->format); int vsub = drm_format_vert_chroma_subsampling(fb->format->format); int bpp = fb->format->cpp[1]; @@ -783,6 +813,13 @@ static void vop_plane_atomic_update(struct drm_plane *plane, dma_addr = rk_uv_obj->dma_addr + offset + fb->offsets[1]; VOP_WIN_SET(vop, win, uv_vir, DIV_ROUND_UP(fb->pitches[1], 4)); VOP_WIN_SET(vop, win, uv_mst, dma_addr); + + for (i = 0; i < NUM_YUV2YUV_COEFFICIENTS; i++) { + VOP_WIN_YUV2YUV_COEFFICIENT_SET(vop, + win_yuv2yuv, + y2r_coefficients[i], + bt601_yuv2rgb[i]); + } } if (win->phy->scl) @@ -1605,6 +1642,7 @@ static void vop_win_init(struct vop *vop) vop_win->data = win_data; vop_win->vop = vop; + vop_win->yuv2yuv_data = &vop_data->win_yuv2yuv[i]; } } diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h index 0fe40e1983d9..aed467cd81b9 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h @@ -23,6 +23,8 @@ #define VOP_MAJOR(version) ((version) >> 8) #define VOP_MINOR(version) ((version) & 0xff) +#define NUM_YUV2YUV_COEFFICIENTS 12 + enum vop_data_format { VOP_FMT_ARGB8888 = 0, VOP_FMT_RGB888, @@ -124,6 +126,10 @@ struct vop_scl_regs { struct vop_reg scale_cbcr_y; }; +struct vop_yuv2yuv_phy { + struct vop_reg y2r_coefficients[NUM_YUV2YUV_COEFFICIENTS]; +}; + struct vop_win_phy { const struct vop_scl_regs *scl; const uint32_t *data_formats; @@ -146,6 +152,12 @@ struct vop_win_phy { struct vop_reg channel; }; +struct vop_win_yuv2yuv_data { + uint32_t base; + const struct vop_yuv2yuv_phy *phy; + struct vop_reg y2r_en; +}; + struct vop_win_data { uint32_t base; const struct vop_win_phy *phy; @@ -159,6 +171,7 @@ struct vop_data { const struct vop_misc *misc; const struct vop_modeset *modeset; const struct vop_output *output; + const struct vop_win_yuv2yuv_data *win_yuv2yuv; const struct vop_win_data *win; unsigned int win_size; diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c index 08fc40af52c8..fe752df4e038 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c @@ -637,6 +637,34 @@ static const struct vop_output rk3399_output = { .mipi_dual_channel_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 3), }; +static const struct vop_yuv2yuv_phy rk3399_yuv2yuv_win01_data = { + .y2r_coefficients = { + VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 0, 0xffff, 0), + VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 0, 0xffff, 16), + VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 4, 0xffff, 0), + VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 4, 0xffff, 16), + VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 8, 0xffff, 0), + VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 8, 0xffff, 16), + VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 12, 0xffff, 0), + VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 12, 0xffff, 16), + VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 16, 0xffff, 0), + VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 20, 0xffffffff, 0), + VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 24, 0xffffffff, 0), + VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 28, 0xffffffff, 0), + }, +}; + +static const struct vop_yuv2yuv_phy rk3399_yuv2yuv_win23_data = { }; + +static const struct vop_win_yuv2yuv_data rk3399_vop_big_win_yuv2yuv_data[] = { + { .base = 0x00, .phy = &rk3399_yuv2yuv_win01_data, + .y2r_en = VOP_REG(RK3399_YUV2YUV_WIN, 0x1, 1) }, + { .base = 0x60, .phy = &rk3399_yuv2yuv_win01_data, + .y2r_en = VOP_REG(RK3399_YUV2YUV_WIN, 0x1, 9) }, + { .base = 0xC0, .phy = &rk3399_yuv2yuv_win23_data }, + { .base = 0x120, .phy = &rk3399_yuv2yuv_win23_data }, +}; + static const struct vop_data rk3399_vop_big = { .version = VOP_VERSION(3, 5), .feature = VOP_FEATURE_OUTPUT_RGB10, @@ -647,6 +675,7 @@ static const struct vop_data rk3399_vop_big = { .misc = &rk3368_misc, .win = rk3368_vop_win_data, .win_size = ARRAY_SIZE(rk3368_vop_win_data), + .win_yuv2yuv = rk3399_vop_big_win_yuv2yuv_data, }; static const struct vop_win_data rk3399_vop_lit_win_data[] = { @@ -656,6 +685,12 @@ static const struct vop_win_data rk3399_vop_lit_win_data[] = { .type = DRM_PLANE_TYPE_CURSOR}, }; +static const struct vop_win_yuv2yuv_data rk3399_vop_lit_win_yuv2yuv_data[] = { + { .base = 0x00, .phy = &rk3399_yuv2yuv_win01_data, + .y2r_en = VOP_REG(RK3399_YUV2YUV_WIN, 0x1, 1)}, + { .base = 0x60, .phy = &rk3399_yuv2yuv_win23_data }, +}; + static const struct vop_data rk3399_vop_lit = { .version = VOP_VERSION(3, 6), .intr = &rk3366_vop_intr, @@ -665,6 +700,7 @@ static const struct vop_data rk3399_vop_lit = { .misc = &rk3368_misc, .win = rk3399_vop_lit_win_data, .win_size = ARRAY_SIZE(rk3399_vop_lit_win_data), + .win_yuv2yuv = rk3399_vop_lit_win_yuv2yuv_data, }; static const struct vop_win_data rk3228_vop_win_data[] = { |