diff mbox

[01/10] drm/rockchip: YUV overlays BT.601 color conversion.

Message ID 20180215053300.70482-2-dcastagna@chromium.org (mailing list archive)
State New, archived
Headers show

Commit Message

Daniele Castagna Feb. 15, 2018, 5:32 a.m. UTC
Currently NV12 hardware overlays scheduled with atomic interface are
converted to RGB using a color space conversion different than BT.601.

The result is that colors of NV12 buffers composited with Mali don't
match colors of YUV hardware overlays.

Running modetest with an NV12 plane also shows colors are incorrect
if compared to an RGB overlay that represents the same color pattern.

This CL adds support for YUV2YUV color space conversion (CSC) module on
rockchip and enables the YUV2RGB part that allows to specify a 4x3
matrix to convert the colors.

The matrix is set to BT.601 coefficients to align to Mali and to what
modetest expects.

TEST=modetest -M rockchip -s 34@30:2400x1600 -P 30:640x480+650+10@NV12 -P 30:640x480+10+10@XR24

Change-Id: Ia5a3b4793229e2c63f79f9f414d1cbe6ccc63fc1
Tested-by: Daniele Castagna <dcastagna@chromium.org>
Reviewed-by: Daniele Castagna <dcastagna@chromium.org>
Reviewed-by: Kristian H. Kristensen <hoegsberg@chromium.org>
---
 drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 40 ++++++++++++++++++++-
 drivers/gpu/drm/rockchip/rockchip_drm_vop.h |  9 +++++
 drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 39 ++++++++++++++++++--
 3 files changed, 85 insertions(+), 3 deletions(-)

Comments

kernel test robot Feb. 16, 2018, 5:55 p.m. UTC | #1
Hi Daniele,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on rockchip/for-next]
[also build test ERROR on v4.16-rc1 next-20180216]
[cannot apply to drm/drm-next]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Daniele-Castagna/drm-rockchip-YUV-overlays-BT-601-color-conversion/20180216-233006
base:   https://git.kernel.org/pub/scm/linux/kernel/git/mmind/linux-rockchip.git for-next
config: arm64-defconfig (attached as .config)
compiler: aarch64-linux-gnu-gcc (Debian 7.2.0-11) 7.2.0
reproduce:
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        make.cross ARCH=arm64 

All error/warnings (new ones prefixed by >>):

   drivers/gpu//drm/rockchip/rockchip_drm_vop.c: In function 'vop_plane_atomic_update':
>> drivers/gpu//drm/rockchip/rockchip_drm_vop.c:742:18: error: implicit declaration of function 'VOP_WIN_TO_INDEX'; did you mean 'CAP_TO_INDEX'? [-Werror=implicit-function-declaration]
     int win_index = VOP_WIN_TO_INDEX(vop_win);
                     ^~~~~~~~~~~~~~~~
                     CAP_TO_INDEX
   cc1: some warnings being treated as errors
--
>> drivers/gpu//drm/rockchip/rockchip_vop_reg.c:468:9: error: 'rk3399_vop_win_data' undeclared here (not in a function); did you mean 'rk3368_vop_win_data'?
     .win = rk3399_vop_win_data,
            ^~~~~~~~~~~~~~~~~~~
            rk3368_vop_win_data
   In file included from arch/arm64/include/asm/sysreg.h:669:0,
                    from arch/arm64/include/asm/cputype.h:116,
                    from arch/arm64/include/asm/cache.h:19,
                    from include/linux/cache.h:6,
                    from include/linux/printk.h:9,
                    from include/linux/kernel.h:14,
                    from include/linux/list.h:9,
                    from include/linux/agp_backend.h:33,
                    from include/drm/drmP.h:35,
                    from drivers/gpu//drm/rockchip/rockchip_vop_reg.c:15:
>> include/linux/build_bug.h:29:45: error: bit-field '<anonymous>' width not an integer constant
    #define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:(-!!(e)); }))
                                                ^
   include/linux/compiler-gcc.h:65:28: note: in expansion of macro 'BUILD_BUG_ON_ZERO'
    #define __must_be_array(a) BUILD_BUG_ON_ZERO(__same_type((a), &(a)[0]))
                               ^~~~~~~~~~~~~~~~~
   include/linux/kernel.h:71:59: note: in expansion of macro '__must_be_array'
    #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr))
                                                              ^~~~~~~~~~~~~~~
>> drivers/gpu//drm/rockchip/rockchip_vop_reg.c:469:14: note: in expansion of macro 'ARRAY_SIZE'
     .win_size = ARRAY_SIZE(rk3399_vop_win_data),
                 ^~~~~~~~~~
--
   drivers/gpu/drm/rockchip/rockchip_vop_reg.c:468:9: error: 'rk3399_vop_win_data' undeclared here (not in a function); did you mean 'rk3368_vop_win_data'?
     .win = rk3399_vop_win_data,
            ^~~~~~~~~~~~~~~~~~~
            rk3368_vop_win_data
   In file included from arch/arm64/include/asm/sysreg.h:669:0,
                    from arch/arm64/include/asm/cputype.h:116,
                    from arch/arm64/include/asm/cache.h:19,
                    from include/linux/cache.h:6,
                    from include/linux/printk.h:9,
                    from include/linux/kernel.h:14,
                    from include/linux/list.h:9,
                    from include/linux/agp_backend.h:33,
                    from include/drm/drmP.h:35,
                    from drivers/gpu/drm/rockchip/rockchip_vop_reg.c:15:
>> include/linux/build_bug.h:29:45: error: bit-field '<anonymous>' width not an integer constant
    #define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:(-!!(e)); }))
                                                ^
   include/linux/compiler-gcc.h:65:28: note: in expansion of macro 'BUILD_BUG_ON_ZERO'
    #define __must_be_array(a) BUILD_BUG_ON_ZERO(__same_type((a), &(a)[0]))
                               ^~~~~~~~~~~~~~~~~
   include/linux/kernel.h:71:59: note: in expansion of macro '__must_be_array'
    #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr))
                                                              ^~~~~~~~~~~~~~~
   drivers/gpu/drm/rockchip/rockchip_vop_reg.c:469:14: note: in expansion of macro 'ARRAY_SIZE'
     .win_size = ARRAY_SIZE(rk3399_vop_win_data),
                 ^~~~~~~~~~

vim +742 drivers/gpu//drm/rockchip/rockchip_drm_vop.c

   719	
   720	static void vop_plane_atomic_update(struct drm_plane *plane,
   721			struct drm_plane_state *old_state)
   722	{
   723		struct drm_plane_state *state = plane->state;
   724		struct drm_crtc *crtc = state->crtc;
   725		struct vop_win *vop_win = to_vop_win(plane);
   726		const struct vop_win_data *win = vop_win->data;
   727		struct vop *vop = to_vop(state->crtc);
   728		struct drm_framebuffer *fb = state->fb;
   729		unsigned int actual_w, actual_h;
   730		unsigned int dsp_stx, dsp_sty;
   731		uint32_t act_info, dsp_info, dsp_st;
   732		struct drm_rect *src = &state->src;
   733		struct drm_rect *dest = &state->dst;
   734		struct drm_gem_object *obj, *uv_obj;
   735		struct rockchip_gem_object *rk_obj, *rk_uv_obj;
   736		unsigned long offset;
   737		dma_addr_t dma_addr;
   738		uint32_t val;
   739		bool rb_swap;
   740		int format;
   741		int is_yuv = is_yuv_support(fb->format->format);
 > 742		int win_index = VOP_WIN_TO_INDEX(vop_win);
   743		int i;
   744	
   745		/*
   746		 * can't update plane when vop is disabled.
   747		 */
   748		if (WARN_ON(!crtc))
   749			return;
   750	
   751		if (WARN_ON(!vop->is_enabled))
   752			return;
   753	
   754		if (!state->visible) {
   755			vop_plane_atomic_disable(plane, old_state);
   756			return;
   757		}
   758	
   759		obj = rockchip_fb_get_gem_obj(fb, 0);
   760		rk_obj = to_rockchip_obj(obj);
   761	
   762		actual_w = drm_rect_width(src) >> 16;
   763		actual_h = drm_rect_height(src) >> 16;
   764		act_info = (actual_h - 1) << 16 | ((actual_w - 1) & 0xffff);
   765	
   766		dsp_info = (drm_rect_height(dest) - 1) << 16;
   767		dsp_info |= (drm_rect_width(dest) - 1) & 0xffff;
   768	
   769		dsp_stx = dest->x1 + crtc->mode.htotal - crtc->mode.hsync_start;
   770		dsp_sty = dest->y1 + crtc->mode.vtotal - crtc->mode.vsync_start;
   771		dsp_st = dsp_sty << 16 | (dsp_stx & 0xffff);
   772	
   773		offset = (src->x1 >> 16) * fb->format->cpp[0];
   774		offset += (src->y1 >> 16) * fb->pitches[0];
   775		dma_addr = rk_obj->dma_addr + offset + fb->offsets[0];
   776	
   777		format = vop_convert_format(fb->format->format);
   778	
   779		spin_lock(&vop->reg_lock);
   780	
   781		VOP_WIN_SET(vop, win, format, format);
   782		VOP_WIN_SET(vop, win, yrgb_vir, DIV_ROUND_UP(fb->pitches[0], 4));
   783		VOP_WIN_SET(vop, win, yrgb_mst, dma_addr);
   784	
   785		if (!win_index) {
   786			VOP_YUV2YUV_SET(vop, win0_y2r_en, is_yuv);
   787		} else if (win_index == 1) {
   788			VOP_YUV2YUV_SET(vop, win1_y2r_en, is_yuv);
   789		}
   790	
   791		if (is_yuv) {
   792			int hsub = drm_format_horz_chroma_subsampling(fb->format->format);
   793			int vsub = drm_format_vert_chroma_subsampling(fb->format->format);
   794			int bpp = fb->format->cpp[1];
   795	
   796			uv_obj = rockchip_fb_get_gem_obj(fb, 1);
   797			rk_uv_obj = to_rockchip_obj(uv_obj);
   798	
   799			offset = (src->x1 >> 16) * bpp / hsub;
   800			offset += (src->y1 >> 16) * fb->pitches[1] / vsub;
   801	
   802			dma_addr = rk_uv_obj->dma_addr + offset + fb->offsets[1];
   803			VOP_WIN_SET(vop, win, uv_vir, DIV_ROUND_UP(fb->pitches[1], 4));
   804			VOP_WIN_SET(vop, win, uv_mst, dma_addr);
   805	
   806			for (i = 0; i < 12; i++) {
   807				if (!win_index) {
   808					VOP_YUV2YUV_SET(vop,
   809							win0_y2r_coefficients[i],
   810							bt601_yuv2rgb[i]);
   811				} else {
   812					VOP_YUV2YUV_SET(vop,
   813							win1_y2r_coefficients[i],
   814							bt601_yuv2rgb[i]);
   815				}
   816			}
   817		}
   818	
   819		if (win->phy->scl)
   820			scl_vop_cal_scl_fac(vop, win, actual_w, actual_h,
   821					    drm_rect_width(dest), drm_rect_height(dest),
   822					    fb->format->format);
   823	
   824		VOP_WIN_SET(vop, win, act_info, act_info);
   825		VOP_WIN_SET(vop, win, dsp_info, dsp_info);
   826		VOP_WIN_SET(vop, win, dsp_st, dsp_st);
   827	
   828		rb_swap = has_rb_swapped(fb->format->format);
   829		VOP_WIN_SET(vop, win, rb_swap, rb_swap);
   830	
   831		if (is_alpha_support(fb->format->format)) {
   832			VOP_WIN_SET(vop, win, dst_alpha_ctl,
   833				    DST_FACTOR_M0(ALPHA_SRC_INVERSE));
   834			val = SRC_ALPHA_EN(1) | SRC_COLOR_M0(ALPHA_SRC_PRE_MUL) |
   835				SRC_ALPHA_M0(ALPHA_STRAIGHT) |
   836				SRC_BLEND_M0(ALPHA_PER_PIX) |
   837				SRC_ALPHA_CAL_M0(ALPHA_NO_SATURATION) |
   838				SRC_FACTOR_M0(ALPHA_ONE);
   839			VOP_WIN_SET(vop, win, src_alpha_ctl, val);
   840		} else {
   841			VOP_WIN_SET(vop, win, src_alpha_ctl, SRC_ALPHA_EN(0));
   842		}
   843	
   844		VOP_WIN_SET(vop, win, enable, 1);
   845		spin_unlock(&vop->reg_lock);
   846	}
   847	

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation
Sean Paul Feb. 27, 2018, 3:03 p.m. UTC | #2
On Thu, Feb 15, 2018 at 12:32:51AM -0500, Daniele Castagna wrote:
> Currently NV12 hardware overlays scheduled with atomic interface are
> converted to RGB using a color space conversion different than BT.601.
> 
> The result is that colors of NV12 buffers composited with Mali don't
> match colors of YUV hardware overlays.
> 
> Running modetest with an NV12 plane also shows colors are incorrect
> if compared to an RGB overlay that represents the same color pattern.
> 
> This CL adds support for YUV2YUV color space conversion (CSC) module on
> rockchip and enables the YUV2RGB part that allows to specify a 4x3
> matrix to convert the colors.
> 
> The matrix is set to BT.601 coefficients to align to Mali and to what
> modetest expects.

Hey Daniele,
Apologies for missing this set. 

> 
> TEST=modetest -M rockchip -s 34@30:2400x1600 -P 30:640x480+650+10@NV12 -P 30:640x480+10+10@XR24
> 
> Change-Id: Ia5a3b4793229e2c63f79f9f414d1cbe6ccc63fc1

It's usually good form to strip out the gerrit Change-Id from the commit
message.

> Tested-by: Daniele Castagna <dcastagna@chromium.org>
> Reviewed-by: Daniele Castagna <dcastagna@chromium.org>
> Reviewed-by: Kristian H. Kristensen <hoegsberg@chromium.org>
> ---
>  drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 40 ++++++++++++++++++++-
>  drivers/gpu/drm/rockchip/rockchip_drm_vop.h |  9 +++++
>  drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 39 ++++++++++++++++++--
>  3 files changed, 85 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
> index ba7505292b786..ea43ab797f555 100644
> --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
> +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
> @@ -50,6 +50,10 @@
>  		vop_reg_set(vop, &win->phy->scl->ext->name, \
>  			    win->base, ~0, v, #name)
>  
> +#define VOP_YUV2YUV_SET(x, name, v) \
> +		if ((x)->data->yuv2yuv) \
> +			vop_reg_set(vop, &vop->data->yuv2yuv->name, 0, ~0, v, #name)
> +
>  #define VOP_INTR_SET_MASK(vop, name, mask, v) \
>  		vop_reg_set(vop, &vop->data->intr->name, 0, mask, v, #name)
>  
> @@ -79,6 +83,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,
>  };
> @@ -722,6 +738,9 @@ static void vop_plane_atomic_update(struct drm_plane *plane,
>  	uint32_t val;
>  	bool rb_swap;
>  	int format;
> +	int is_yuv = is_yuv_support(fb->format->format);
> +	int win_index = VOP_WIN_TO_INDEX(vop_win);
> +	int i;
>  
>  	/*
>  	 * can't update plane when vop is disabled.
> @@ -762,7 +781,14 @@ 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 (is_yuv_support(fb->format->format)) {
> +
> +	if (!win_index) {
> +		VOP_YUV2YUV_SET(vop, win0_y2r_en, is_yuv);
> +	} else if (win_index == 1) {
> +		VOP_YUV2YUV_SET(vop, win1_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];
> @@ -776,6 +802,18 @@ 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 < 12; i++) {
> +			if (!win_index) {
> +				VOP_YUV2YUV_SET(vop,
> +						win0_y2r_coefficients[i],
> +						bt601_yuv2rgb[i]);
> +			} else {
> +				VOP_YUV2YUV_SET(vop,
> +						win1_y2r_coefficients[i],
> +						bt601_yuv2rgb[i]);
> +			}
> +		}
>  	}
>  
>  	if (win->phy->scl)
> diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
> index 56bbd2e2a8efb..aa8a5d2690376 100644
> --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
> +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
> @@ -79,6 +79,14 @@ struct vop_misc {
>  	struct vop_reg global_regdone_en;
>  };
>  
> +struct vop_yuv2yuv {
> +	struct vop_reg win0_y2r_en;
> +	struct vop_reg win0_y2r_coefficients[12];
> +
> +	struct vop_reg win1_y2r_en;
> +	struct vop_reg win1_y2r_coefficients[12];
> +};

struct vop_yuv2yuv {
        struct {
                struct vop_reg y2r_en;
                struct vop_reg y2r_coefficients[12];
        } regs[2];
};

Then add win_index to the macro above and you can avoid the if (!win_index)
checks everywhere.

Bonus points if you #define the '2' and '12' as something more meaningful

> +
>  struct vop_intr {
>  	const int *intrs;
>  	uint32_t nintrs;
> @@ -157,6 +165,7 @@ struct vop_data {
>  	const struct vop_misc *misc;
>  	const struct vop_modeset *modeset;
>  	const struct vop_output *output;
> +	const struct vop_yuv2yuv *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 2e4eea3459fe6..be9c414e2e4bc 100644
> --- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
> +++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
> @@ -422,6 +422,40 @@ static const struct vop_output rk3399_output = {
>  	.mipi_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 15),
>  };
>  
> +static const struct vop_yuv2yuv rk3399_vop_yuv2yuv = {
> +	.win0_y2r_en = VOP_REG(RK3399_YUV2YUV_WIN, 0x1, 1),
> +	.win0_y2r_coefficients = {
> +		VOP_REG(RK3399_WIN1_YUV2YUV_Y2R + 0, 0xffff, 0),
> +		VOP_REG(RK3399_WIN1_YUV2YUV_Y2R + 0, 0xffff, 16),
> +		VOP_REG(RK3399_WIN1_YUV2YUV_Y2R + 4, 0xffff, 0),
> +		VOP_REG(RK3399_WIN1_YUV2YUV_Y2R + 4, 0xffff, 16),
> +		VOP_REG(RK3399_WIN1_YUV2YUV_Y2R + 8, 0xffff, 0),
> +		VOP_REG(RK3399_WIN1_YUV2YUV_Y2R + 8, 0xffff, 16),
> +		VOP_REG(RK3399_WIN1_YUV2YUV_Y2R + 12, 0xffff, 0),
> +		VOP_REG(RK3399_WIN1_YUV2YUV_Y2R + 12, 0xffff, 16),
> +		VOP_REG(RK3399_WIN1_YUV2YUV_Y2R + 16, 0xffff, 0),
> +		VOP_REG(RK3399_WIN1_YUV2YUV_Y2R + 20, 0xffffffff, 0),
> +		VOP_REG(RK3399_WIN1_YUV2YUV_Y2R + 24, 0xffffffff, 0),
> +		VOP_REG(RK3399_WIN1_YUV2YUV_Y2R + 28, 0xffffffff, 0),
> +	},
> +
> +	.win1_y2r_en = VOP_REG(RK3399_YUV2YUV_WIN, 0x1, 9),
> +	.win1_y2r_coefficients = {
> +		VOP_REG(RK3399_WIN1_YUV2YUV_Y2R + 0, 0xffff, 0),
> +		VOP_REG(RK3399_WIN1_YUV2YUV_Y2R + 0, 0xffff, 16),
> +		VOP_REG(RK3399_WIN1_YUV2YUV_Y2R + 4, 0xffff, 0),
> +		VOP_REG(RK3399_WIN1_YUV2YUV_Y2R + 4, 0xffff, 16),
> +		VOP_REG(RK3399_WIN1_YUV2YUV_Y2R + 8, 0xffff, 0),
> +		VOP_REG(RK3399_WIN1_YUV2YUV_Y2R + 8, 0xffff, 16),
> +		VOP_REG(RK3399_WIN1_YUV2YUV_Y2R + 12, 0xffff, 0),
> +		VOP_REG(RK3399_WIN1_YUV2YUV_Y2R + 12, 0xffff, 16),
> +		VOP_REG(RK3399_WIN1_YUV2YUV_Y2R + 16, 0xffff, 0),
> +		VOP_REG(RK3399_WIN1_YUV2YUV_Y2R + 20, 0xffffffff, 0),
> +		VOP_REG(RK3399_WIN1_YUV2YUV_Y2R + 24, 0xffffffff, 0),
> +		VOP_REG(RK3399_WIN1_YUV2YUV_Y2R + 28, 0xffffffff, 0),
> +	},
> +};
> +
>  static const struct vop_data rk3399_vop_big = {
>  	.version = VOP_VERSION(3, 5),
>  	.feature = VOP_FEATURE_OUTPUT_RGB10,
> @@ -430,8 +464,9 @@ static const struct vop_data rk3399_vop_big = {
>  	.modeset = &rk3288_modeset,
>  	.output = &rk3399_output,
>  	.misc = &rk3368_misc,
> -	.win = rk3368_vop_win_data,
> -	.win_size = ARRAY_SIZE(rk3368_vop_win_data),
> +	.yuv2yuv = &rk3399_vop_yuv2yuv,
> +	.win = rk3399_vop_win_data,
> +	.win_size = ARRAY_SIZE(rk3399_vop_win_data),
>  };
>  
>  static const struct vop_win_data rk3399_vop_lit_win_data[] = {
> -- 
> 2.16.1.291.g4437f3f132-goog
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel
diff mbox

Patch

diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
index ba7505292b786..ea43ab797f555 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
@@ -50,6 +50,10 @@ 
 		vop_reg_set(vop, &win->phy->scl->ext->name, \
 			    win->base, ~0, v, #name)
 
+#define VOP_YUV2YUV_SET(x, name, v) \
+		if ((x)->data->yuv2yuv) \
+			vop_reg_set(vop, &vop->data->yuv2yuv->name, 0, ~0, v, #name)
+
 #define VOP_INTR_SET_MASK(vop, name, mask, v) \
 		vop_reg_set(vop, &vop->data->intr->name, 0, mask, v, #name)
 
@@ -79,6 +83,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,
 };
@@ -722,6 +738,9 @@  static void vop_plane_atomic_update(struct drm_plane *plane,
 	uint32_t val;
 	bool rb_swap;
 	int format;
+	int is_yuv = is_yuv_support(fb->format->format);
+	int win_index = VOP_WIN_TO_INDEX(vop_win);
+	int i;
 
 	/*
 	 * can't update plane when vop is disabled.
@@ -762,7 +781,14 @@  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 (is_yuv_support(fb->format->format)) {
+
+	if (!win_index) {
+		VOP_YUV2YUV_SET(vop, win0_y2r_en, is_yuv);
+	} else if (win_index == 1) {
+		VOP_YUV2YUV_SET(vop, win1_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];
@@ -776,6 +802,18 @@  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 < 12; i++) {
+			if (!win_index) {
+				VOP_YUV2YUV_SET(vop,
+						win0_y2r_coefficients[i],
+						bt601_yuv2rgb[i]);
+			} else {
+				VOP_YUV2YUV_SET(vop,
+						win1_y2r_coefficients[i],
+						bt601_yuv2rgb[i]);
+			}
+		}
 	}
 
 	if (win->phy->scl)
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
index 56bbd2e2a8efb..aa8a5d2690376 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
@@ -79,6 +79,14 @@  struct vop_misc {
 	struct vop_reg global_regdone_en;
 };
 
+struct vop_yuv2yuv {
+	struct vop_reg win0_y2r_en;
+	struct vop_reg win0_y2r_coefficients[12];
+
+	struct vop_reg win1_y2r_en;
+	struct vop_reg win1_y2r_coefficients[12];
+};
+
 struct vop_intr {
 	const int *intrs;
 	uint32_t nintrs;
@@ -157,6 +165,7 @@  struct vop_data {
 	const struct vop_misc *misc;
 	const struct vop_modeset *modeset;
 	const struct vop_output *output;
+	const struct vop_yuv2yuv *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 2e4eea3459fe6..be9c414e2e4bc 100644
--- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
+++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
@@ -422,6 +422,40 @@  static const struct vop_output rk3399_output = {
 	.mipi_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 15),
 };
 
+static const struct vop_yuv2yuv rk3399_vop_yuv2yuv = {
+	.win0_y2r_en = VOP_REG(RK3399_YUV2YUV_WIN, 0x1, 1),
+	.win0_y2r_coefficients = {
+		VOP_REG(RK3399_WIN1_YUV2YUV_Y2R + 0, 0xffff, 0),
+		VOP_REG(RK3399_WIN1_YUV2YUV_Y2R + 0, 0xffff, 16),
+		VOP_REG(RK3399_WIN1_YUV2YUV_Y2R + 4, 0xffff, 0),
+		VOP_REG(RK3399_WIN1_YUV2YUV_Y2R + 4, 0xffff, 16),
+		VOP_REG(RK3399_WIN1_YUV2YUV_Y2R + 8, 0xffff, 0),
+		VOP_REG(RK3399_WIN1_YUV2YUV_Y2R + 8, 0xffff, 16),
+		VOP_REG(RK3399_WIN1_YUV2YUV_Y2R + 12, 0xffff, 0),
+		VOP_REG(RK3399_WIN1_YUV2YUV_Y2R + 12, 0xffff, 16),
+		VOP_REG(RK3399_WIN1_YUV2YUV_Y2R + 16, 0xffff, 0),
+		VOP_REG(RK3399_WIN1_YUV2YUV_Y2R + 20, 0xffffffff, 0),
+		VOP_REG(RK3399_WIN1_YUV2YUV_Y2R + 24, 0xffffffff, 0),
+		VOP_REG(RK3399_WIN1_YUV2YUV_Y2R + 28, 0xffffffff, 0),
+	},
+
+	.win1_y2r_en = VOP_REG(RK3399_YUV2YUV_WIN, 0x1, 9),
+	.win1_y2r_coefficients = {
+		VOP_REG(RK3399_WIN1_YUV2YUV_Y2R + 0, 0xffff, 0),
+		VOP_REG(RK3399_WIN1_YUV2YUV_Y2R + 0, 0xffff, 16),
+		VOP_REG(RK3399_WIN1_YUV2YUV_Y2R + 4, 0xffff, 0),
+		VOP_REG(RK3399_WIN1_YUV2YUV_Y2R + 4, 0xffff, 16),
+		VOP_REG(RK3399_WIN1_YUV2YUV_Y2R + 8, 0xffff, 0),
+		VOP_REG(RK3399_WIN1_YUV2YUV_Y2R + 8, 0xffff, 16),
+		VOP_REG(RK3399_WIN1_YUV2YUV_Y2R + 12, 0xffff, 0),
+		VOP_REG(RK3399_WIN1_YUV2YUV_Y2R + 12, 0xffff, 16),
+		VOP_REG(RK3399_WIN1_YUV2YUV_Y2R + 16, 0xffff, 0),
+		VOP_REG(RK3399_WIN1_YUV2YUV_Y2R + 20, 0xffffffff, 0),
+		VOP_REG(RK3399_WIN1_YUV2YUV_Y2R + 24, 0xffffffff, 0),
+		VOP_REG(RK3399_WIN1_YUV2YUV_Y2R + 28, 0xffffffff, 0),
+	},
+};
+
 static const struct vop_data rk3399_vop_big = {
 	.version = VOP_VERSION(3, 5),
 	.feature = VOP_FEATURE_OUTPUT_RGB10,
@@ -430,8 +464,9 @@  static const struct vop_data rk3399_vop_big = {
 	.modeset = &rk3288_modeset,
 	.output = &rk3399_output,
 	.misc = &rk3368_misc,
-	.win = rk3368_vop_win_data,
-	.win_size = ARRAY_SIZE(rk3368_vop_win_data),
+	.yuv2yuv = &rk3399_vop_yuv2yuv,
+	.win = rk3399_vop_win_data,
+	.win_size = ARRAY_SIZE(rk3399_vop_win_data),
 };
 
 static const struct vop_win_data rk3399_vop_lit_win_data[] = {