[PATCH 07/10] drm/sun4i: Add support for YUV formats through the frontend

Maxime Ripard maxime.ripard at bootlin.com
Fri Mar 23 03:30:01 PDT 2018


On Wed, Mar 21, 2018 at 04:29:01PM +0100, Paul Kocialkowski wrote:
> The frontend supports many YUV formats as input and also contains a
> color-space converter (CSC) block that can convert YUV input into
> RGB output. It also allows scaling between the input and output for
> every possible combination of supported formats.
> 
> This adds support for all the (untiled) YUV video formats supported by
> the frontend, with associated changes in the backend and layer
> management.
> 
> A specific dumb GEM create function translates a hardware constraint,
> that the stride must be an even number, when allocating dumb (linear)
> buffers.

This should be in a separate, potentially preliminary, patch.

> Signed-off-by: Paul Kocialkowski <paul.kocialkowski at bootlin.com>
> ---
>  drivers/gpu/drm/sun4i/sun4i_backend.c  |  10 +-
>  drivers/gpu/drm/sun4i/sun4i_drv.c      |  11 +-
>  drivers/gpu/drm/sun4i/sun4i_drv.h      |   4 +
>  drivers/gpu/drm/sun4i/sun4i_frontend.c | 234 ++++++++++++++++++++++++++++-----
>  drivers/gpu/drm/sun4i/sun4i_frontend.h |  48 ++++++-
>  drivers/gpu/drm/sun4i/sun4i_layer.c    |  34 +++--
>  6 files changed, 293 insertions(+), 48 deletions(-)
> 
> diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c
> index e8af9f3cf20b..3de7f3a427c3 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_backend.c
> +++ b/drivers/gpu/drm/sun4i/sun4i_backend.c
> @@ -500,6 +500,11 @@ static int sun4i_backend_atomic_check(struct sunxi_engine *engine,
>  			layer_state->uses_frontend = true;
>  			num_frontend_planes++;
>  		} else {
> +			if (sun4i_format_is_yuv(fb->format->format)) {
> +				DRM_DEBUG_DRIVER("Plane FB format is YUV\n");
> +				num_yuv_planes++;
> +			}
> +
>  			layer_state->uses_frontend = false;
>  		}
>  
> @@ -510,11 +515,6 @@ static int sun4i_backend_atomic_check(struct sunxi_engine *engine,
>  		if (fb->format->has_alpha)
>  			num_alpha_planes++;
>  
> -		if (sun4i_format_is_yuv(fb->format->format)) {
> -			DRM_DEBUG_DRIVER("Plane FB format is YUV\n");
> -			num_yuv_planes++;
> -		}
> -

Why is this needed?

>  		DRM_DEBUG_DRIVER("Plane zpos is %d\n",
>  				 plane_state->normalized_zpos);
>  
> diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.c b/drivers/gpu/drm/sun4i/sun4i_drv.c
> index 3957c2ff6870..d374bb61c565 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_drv.c
> +++ b/drivers/gpu/drm/sun4i/sun4i_drv.c
> @@ -42,7 +42,7 @@ static struct drm_driver sun4i_drv_driver = {
>  	.minor			= 0,
>  
>  	/* GEM Operations */
> -	.dumb_create		= drm_gem_cma_dumb_create,
> +	.dumb_create		= drm_sun4i_gem_dumb_create,
>  	.gem_free_object_unlocked = drm_gem_cma_free_object,
>  	.gem_vm_ops		= &drm_gem_cma_vm_ops,
>  
> @@ -60,6 +60,15 @@ static struct drm_driver sun4i_drv_driver = {
>  	/* Frame Buffer Operations */
>  };
>  
> +int drm_sun4i_gem_dumb_create(struct drm_file *file_priv,
> +			      struct drm_device *drm,
> +			      struct drm_mode_create_dumb *args)
> +{
> +	args->pitch = ALIGN(DIV_ROUND_UP(args->width * args->bpp, 8), 2);
> +
> +	return drm_gem_cma_dumb_create_internal(file_priv, drm, args);
> +}
> +
>  static void sun4i_remove_framebuffers(void)
>  {
>  	struct apertures_struct *ap;
> diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.h b/drivers/gpu/drm/sun4i/sun4i_drv.h
> index 5750b8ce8b31..47969711a889 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_drv.h
> +++ b/drivers/gpu/drm/sun4i/sun4i_drv.h
> @@ -23,4 +23,8 @@ struct sun4i_drv {
>  	struct list_head	tcon_list;
>  };
>  
> +int drm_sun4i_gem_dumb_create(struct drm_file *file_priv,
> +			      struct drm_device *drm,
> +			      struct drm_mode_create_dumb *args);
> +

I'm not sure this is needed, you just need to move the function before
the structure definition.

>  #endif /* _SUN4I_DRV_H_ */
> diff --git a/drivers/gpu/drm/sun4i/sun4i_frontend.c b/drivers/gpu/drm/sun4i/sun4i_frontend.c
> index 2dc33383be22..d9e58e96119c 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_frontend.c
> +++ b/drivers/gpu/drm/sun4i/sun4i_frontend.c
> @@ -16,6 +16,7 @@
>  #include <linux/reset.h>
>  
>  #include "sun4i_drv.h"
> +#include "sun4i_format.h"
>  #include "sun4i_frontend.h"
>  
>  static const u32 sun4i_frontend_vert_coef[32] = {
> @@ -89,26 +90,135 @@ void sun4i_frontend_update_buffer(struct sun4i_frontend *frontend,
>  {
>  	struct drm_plane_state *state = plane->state;
>  	struct drm_framebuffer *fb = state->fb;
> +	uint32_t format = fb->format->format;
> +	uint32_t width, height;
> +	uint32_t stride, offset;
> +	bool swap;
>  	dma_addr_t paddr;
>  
> -	/* Set the line width */
> -	DRM_DEBUG_DRIVER("Frontend stride: %d bytes\n", fb->pitches[0]);

Keeping that debug message would be valuable.

> +	width = state->src_w >> 16;
> +	height = state->src_h >> 16;
> +

You don't seem to be using these values anywhere.

>  	regmap_write(frontend->regs, SUN4I_FRONTEND_LINESTRD0_REG,
>  		     fb->pitches[0]);
>  
> +	if (drm_format_num_planes(format) > 1)
> +		regmap_write(frontend->regs, SUN4I_FRONTEND_LINESTRD1_REG,
> +			     fb->pitches[1]);
> +
> +	if (drm_format_num_planes(format) > 2)
> +		regmap_write(frontend->regs, SUN4I_FRONTEND_LINESTRD2_REG,
> +			     fb->pitches[2]);
> +
>  	/* Set the physical address of the buffer in memory */
>  	paddr = drm_fb_cma_get_gem_addr(fb, state, 0);
>  	paddr -= PHYS_OFFSET;
> -	DRM_DEBUG_DRIVER("Setting buffer address to %pad\n", &paddr);
> +	DRM_DEBUG_DRIVER("Setting buffer #0 address to %pad\n", &paddr);
>  	regmap_write(frontend->regs, SUN4I_FRONTEND_BUF_ADDR0_REG, paddr);
> +
> +	/* Some planar formats require chroma channel swapping by hand. */
> +	swap = sun4i_frontend_format_chroma_requires_swap(format);
> +
> +	if (drm_format_num_planes(format) > 1) {
> +		paddr = drm_fb_cma_get_gem_addr(fb, state, swap ? 2 : 1);
> +		paddr -= PHYS_OFFSET;
> +		DRM_DEBUG_DRIVER("Setting buffer #1 address to %pad\n", &paddr);
> +		regmap_write(frontend->regs, SUN4I_FRONTEND_BUF_ADDR1_REG,
> +			     paddr);
> +	}
> +
> +	if (drm_format_num_planes(format) > 2) {
> +		paddr = drm_fb_cma_get_gem_addr(fb, state, swap ? 1 : 2);
> +		paddr -= PHYS_OFFSET;
> +		DRM_DEBUG_DRIVER("Setting buffer #2 address to %pad\n", &paddr);
> +		regmap_write(frontend->regs, SUN4I_FRONTEND_BUF_ADDR2_REG,
> +			     paddr);
> +	}
>  }
>  EXPORT_SYMBOL(sun4i_frontend_update_buffer);
>  
>  static int sun4i_frontend_drm_format_to_input_fmt(uint32_t fmt, u32 *val)
>  {
> +	if (sun4i_format_is_rgb(fmt))
> +		*val = SUN4I_FRONTEND_INPUT_FMT_DATA_FMT_RGB;
> +	else if (sun4i_format_is_yuv411(fmt))
> +		*val = SUN4I_FRONTEND_INPUT_FMT_DATA_FMT_YUV411;
> +	else if (sun4i_format_is_yuv420(fmt))
> +		*val = SUN4I_FRONTEND_INPUT_FMT_DATA_FMT_YUV420;
> +	else if (sun4i_format_is_yuv422(fmt))
> +		*val = SUN4I_FRONTEND_INPUT_FMT_DATA_FMT_YUV422;
> +	else if (sun4i_format_is_yuv444(fmt))
> +		*val = SUN4I_FRONTEND_INPUT_FMT_DATA_FMT_YUV444;
> +	else
> +		return -EINVAL;
> +
> +	return 0;
> +}
> +
> +static int sun4i_frontend_drm_format_to_input_mode(uint32_t fmt, u32 *val)
> +{
> +	if (sun4i_format_is_packed(fmt))
> +		*val = SUN4I_FRONTEND_INPUT_FMT_DATA_MOD_PACKED;
> +	else if (sun4i_format_is_semiplanar(fmt))
> +		*val = SUN4I_FRONTEND_INPUT_FMT_DATA_MOD_SEMIPLANAR;
> +	else if (sun4i_format_is_planar(fmt))
> +		*val = SUN4I_FRONTEND_INPUT_FMT_DATA_MOD_PLANAR;
> +	else
> +		return -EINVAL;
> +
> +	return 0;
> +}
> +
> +static int sun4i_frontend_drm_format_to_input_sequence(uint32_t fmt, u32 *val)
> +{
> +	/* Planar formats have an explicit input sequence. */
> +	if (sun4i_format_is_planar(fmt)) {
> +		*val = 0;
> +		return 0;
> +	}
> +
>  	switch (fmt) {
> +	/* RGB */
>  	case DRM_FORMAT_XRGB8888:
> -		*val = 5;
> +		*val = SUN4I_FRONTEND_INPUT_FMT_DATA_PS_XRGB;
> +		return 0;
> +
> +	case DRM_FORMAT_BGRX8888:
> +		*val = SUN4I_FRONTEND_INPUT_FMT_DATA_PS_BGRX;
> +		return 0;
> +
> +	/* YUV420 */
> +	case DRM_FORMAT_NV12:
> +		*val = SUN4I_FRONTEND_INPUT_FMT_DATA_PS_UV;
> +		return 0;
> +
> +	case DRM_FORMAT_NV21:
> +		*val = SUN4I_FRONTEND_INPUT_FMT_DATA_PS_VU;
> +		return 0;
> +
> +	/* YUV422 */
> +	case DRM_FORMAT_YUYV:
> +		*val = SUN4I_FRONTEND_INPUT_FMT_DATA_PS_YUYV;
> +		return 0;
> +
> +	case DRM_FORMAT_VYUY:
> +		*val = SUN4I_FRONTEND_INPUT_FMT_DATA_PS_VYUY;
> +		return 0;
> +
> +	case DRM_FORMAT_YVYU:
> +		*val = SUN4I_FRONTEND_INPUT_FMT_DATA_PS_YVYU;
> +		return 0;
> +
> +	case DRM_FORMAT_UYVY:
> +		*val = SUN4I_FRONTEND_INPUT_FMT_DATA_PS_UYVY;
> +		return 0;
> +
> +	case DRM_FORMAT_NV16:
> +		*val = SUN4I_FRONTEND_INPUT_FMT_DATA_PS_UV;
> +		return 0;
> +
> +	case DRM_FORMAT_NV61:
> +		*val = SUN4I_FRONTEND_INPUT_FMT_DATA_PS_VU;
>  		return 0;
>  
>  	default:
> @@ -120,7 +230,11 @@ static int sun4i_frontend_drm_format_to_output_fmt(uint32_t fmt, u32 *val)
>  {
>  	switch (fmt) {
>  	case DRM_FORMAT_XRGB8888:
> -		*val = 2;
> +		*val = SUN4I_FRONTEND_OUTPUT_FMT_DATA_FMT_XRGB8888;
> +		return 0;
> +
> +	case DRM_FORMAT_BGRX8888:
> +		*val = SUN4I_FRONTEND_OUTPUT_FMT_DATA_FMT_BGRX8888;
>  		return 0;

Are we using this anywhere?

>  
>  	default:
> @@ -172,22 +286,52 @@ bool sun4i_frontend_format_is_supported(uint32_t fmt)
>  	return true;
>  }
>  
> +bool sun4i_frontend_format_chroma_requires_swap(uint32_t fmt)
> +{
> +	switch (fmt) {
> +	case DRM_FORMAT_YVU444:
> +	case DRM_FORMAT_YVU422:
> +	case DRM_FORMAT_YVU420:
> +	case DRM_FORMAT_YVU411:
> +		return true;
> +
> +	default:
> +		return false;
> +	}
> +}
> +
>  int sun4i_frontend_update_formats(struct sun4i_frontend *frontend,
>  				  struct drm_plane *plane, uint32_t out_fmt)
>  {
>  	struct drm_plane_state *state = plane->state;
>  	struct drm_framebuffer *fb = state->fb;
> +	uint32_t format = fb->format->format;
>  	u32 out_fmt_val;
>  	u32 in_fmt_val;
> +	u32 in_mod_val;
> +	u32 in_ps_val;
> +	u32 bypass;
> +	unsigned int i;
>  	int ret;
>  
> -	ret = sun4i_frontend_drm_format_to_input_fmt(fb->format->format,
> -						     &in_fmt_val);
> +	ret = sun4i_frontend_drm_format_to_input_fmt(format, &in_fmt_val);
>  	if (ret) {
>  		DRM_DEBUG_DRIVER("Invalid input format\n");
>  		return ret;
>  	}
>  
> +	ret = sun4i_frontend_drm_format_to_input_mode(format, &in_mod_val);
> +	if (ret) {
> +		DRM_DEBUG_DRIVER("Invalid input mode\n");
> +		return ret;
> +	}
> +
> +	ret = sun4i_frontend_drm_format_to_input_sequence(format, &in_ps_val);
> +	if (ret) {
> +		DRM_DEBUG_DRIVER("Invalid pixel sequence\n");
> +		return ret;
> +	}
> +
>  	ret = sun4i_frontend_drm_format_to_output_fmt(out_fmt, &out_fmt_val);
>  	if (ret) {
>  		DRM_DEBUG_DRIVER("Invalid output format\n");
> @@ -205,10 +349,30 @@ int sun4i_frontend_update_formats(struct sun4i_frontend *frontend,
>  	regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_VERTPHASE1_REG, 0x400);
>  	regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_VERTPHASE1_REG, 0x400);
>  
> +	if (sun4i_format_is_yuv(format) &&
> +	    !sun4i_format_is_yuv(out_fmt)) {
> +		/* Setup the CSC engine for YUV to RGB conversion. */
> +
> +		for (i = 0; i < ARRAY_SIZE(sunxi_bt601_yuv2rgb_coef); i++)
> +			regmap_write(frontend->regs,
> +				     SUN4I_FRONTEND_CSC_COEF_REG(i),
> +				     sunxi_bt601_yuv2rgb_coef[i]);
> +
> +		regmap_update_bits(frontend->regs,
> +				   SUN4I_FRONTEND_FRM_CTRL_REG,
> +				   SUN4I_FRONTEND_FRM_CTRL_COEF_RDY,
> +				   SUN4I_FRONTEND_FRM_CTRL_COEF_RDY);
> +
> +		bypass = 0;
> +	} else {
> +		bypass = SUN4I_FRONTEND_BYPASS_CSC_EN;

I guess this is also something you introduce that should be in a
separate patch.

> +	}
> +
> +	regmap_update_bits(frontend->regs, SUN4I_FRONTEND_BYPASS_REG,
> +			   SUN4I_FRONTEND_BYPASS_CSC_EN, bypass);
> +
>  	regmap_write(frontend->regs, SUN4I_FRONTEND_INPUT_FMT_REG,
> -		     SUN4I_FRONTEND_INPUT_FMT_DATA_MOD(1) |
> -		     SUN4I_FRONTEND_INPUT_FMT_DATA_FMT(in_fmt_val) |
> -		     SUN4I_FRONTEND_INPUT_FMT_PS(1));
> +		     in_mod_val | in_fmt_val | in_ps_val);
>  
>  	/*
>  	 * TODO: It look like the A31 and A80 at least will need the
> @@ -216,7 +380,7 @@ int sun4i_frontend_update_formats(struct sun4i_frontend *frontend,
>  	 * ARGB8888).
>  	 */
>  	regmap_write(frontend->regs, SUN4I_FRONTEND_OUTPUT_FMT_REG,
> -		     SUN4I_FRONTEND_OUTPUT_FMT_DATA_FMT(out_fmt_val));
> +		     out_fmt_val);
>  
>  	return 0;
>  }
> @@ -226,31 +390,45 @@ void sun4i_frontend_update_coord(struct sun4i_frontend *frontend,
>  				 struct drm_plane *plane)
>  {
>  	struct drm_plane_state *state = plane->state;
> +	struct drm_framebuffer *fb = state->fb;
> +	uint32_t format = fb->format->format;
> +	uint32_t luma_width, luma_height;
> +	uint32_t chroma_width, chroma_height;
>  
>  	/* Set height and width */
> -	DRM_DEBUG_DRIVER("Frontend size W: %u H: %u\n",
> +	DRM_DEBUG_DRIVER("Frontend crtc size W: %u H: %u\n",

The frontend is not the CRTC

>  			 state->crtc_w, state->crtc_h);
> -	regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_INSIZE_REG,
> -		     SUN4I_FRONTEND_INSIZE(state->src_h >> 16,
> -					   state->src_w >> 16));
> -	regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_INSIZE_REG,
> -		     SUN4I_FRONTEND_INSIZE(state->src_h >> 16,
> -					   state->src_w >> 16));
>  
> +	luma_width = chroma_width = state->src_w >> 16;
> +	luma_height = chroma_height = state->src_h >> 16;
> +
> +	if (sun4i_format_is_yuv411(format)) {
> +		chroma_width = DIV_ROUND_UP(luma_width, 4);
> +	} else if (sun4i_format_is_yuv420(format)) {
> +		chroma_width = DIV_ROUND_UP(luma_width, 2);
> +		chroma_height = DIV_ROUND_UP(luma_height, 2);
> +	} else if (sun4i_format_is_yuv422(format)) {
> +		chroma_width = DIV_ROUND_UP(luma_width, 2);
> +	}
> +
> +	regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_INSIZE_REG,
> +		     SUN4I_FRONTEND_INSIZE(luma_height, luma_width));
>  	regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_OUTSIZE_REG,
>  		     SUN4I_FRONTEND_OUTSIZE(state->crtc_h, state->crtc_w));
> +	regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_HORZFACT_REG,
> +		     (luma_width << 16) / state->crtc_w);
> +	regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_VERTFACT_REG,
> +		     (luma_height << 16) / state->crtc_h);
> +
> +	/* These also have to be specified, even for interleaved formats. */
> +	regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_INSIZE_REG,
> +		     SUN4I_FRONTEND_INSIZE(chroma_height, chroma_width));
>  	regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_OUTSIZE_REG,
>  		     SUN4I_FRONTEND_OUTSIZE(state->crtc_h, state->crtc_w));
> -
> -	regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_HORZFACT_REG,
> -		     state->src_w / state->crtc_w);
>  	regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_HORZFACT_REG,
> -		     state->src_w / state->crtc_w);
> -
> -	regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_VERTFACT_REG,
> -		     state->src_h / state->crtc_h);
> +		     (chroma_width << 16) / state->crtc_w);
>  	regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_VERTFACT_REG,
> -		     state->src_h / state->crtc_h);
> +		     (chroma_height << 16) / state->crtc_h);
>  
>  	regmap_write_bits(frontend->regs, SUN4I_FRONTEND_FRM_CTRL_REG,
>  			  SUN4I_FRONTEND_FRM_CTRL_REG_RDY,
> @@ -382,10 +560,6 @@ static int sun4i_frontend_runtime_resume(struct device *dev)
>  			   SUN4I_FRONTEND_EN_EN,
>  			   SUN4I_FRONTEND_EN_EN);
>  
> -	regmap_update_bits(frontend->regs, SUN4I_FRONTEND_BYPASS_REG,
> -			   SUN4I_FRONTEND_BYPASS_CSC_EN,
> -			   SUN4I_FRONTEND_BYPASS_CSC_EN);
> -
>  	sun4i_frontend_scaler_init(frontend);
>  
>  	return 0;
> diff --git a/drivers/gpu/drm/sun4i/sun4i_frontend.h b/drivers/gpu/drm/sun4i/sun4i_frontend.h
> index a9cb908ced16..6dd1d18752f4 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_frontend.h
> +++ b/drivers/gpu/drm/sun4i/sun4i_frontend.h
> @@ -21,17 +21,56 @@
>  #define SUN4I_FRONTEND_BYPASS_REG		0x008
>  #define SUN4I_FRONTEND_BYPASS_CSC_EN			BIT(1)
>  
> +#define SUN4I_FRONTEND_AGTH_SEL_REG		0x00C
> +#define SUN4I_FRONTEND_AGTH_SEL_ORIGINAL		BIT(8)
> +
>  #define SUN4I_FRONTEND_BUF_ADDR0_REG		0x020
> +#define SUN4I_FRONTEND_BUF_ADDR1_REG		0x024
> +#define SUN4I_FRONTEND_BUF_ADDR2_REG		0x028
> +
> +#define SUN4I_FRONTEND_TB_OFF0_REG		0x030
> +#define SUN4I_FRONTEND_TB_OFF1_REG		0x034
> +#define SUN4I_FRONTEND_TB_OFF2_REG		0x038
> +
> +#define SUN4I_FRONTEND_TB_OFF_X1(x1)			((x1) << 16)
> +#define SUN4I_FRONTEND_TB_OFF_Y0(y0)			((y0) << 8)
> +#define SUN4I_FRONTEND_TB_OFF_X0(x0)			(x0)
>  
>  #define SUN4I_FRONTEND_LINESTRD0_REG		0x040
> +#define SUN4I_FRONTEND_LINESTRD1_REG		0x044
> +#define SUN4I_FRONTEND_LINESTRD2_REG		0x048
>  
>  #define SUN4I_FRONTEND_INPUT_FMT_REG		0x04c
> -#define SUN4I_FRONTEND_INPUT_FMT_DATA_MOD(mod)		((mod) << 8)
> -#define SUN4I_FRONTEND_INPUT_FMT_DATA_FMT(fmt)		((fmt) << 4)
> -#define SUN4I_FRONTEND_INPUT_FMT_PS(ps)			(ps)
> +
> +#define SUN4I_FRONTEND_INPUT_FMT_DATA_MOD_MASK			GENMASK(10, 8)
> +#define SUN4I_FRONTEND_INPUT_FMT_DATA_MOD_PLANAR		(0 << 8)
> +#define SUN4I_FRONTEND_INPUT_FMT_DATA_MOD_PACKED		(1 << 8)
> +#define SUN4I_FRONTEND_INPUT_FMT_DATA_MOD_SEMIPLANAR		(2 << 8)
> +#define SUN4I_FRONTEND_INPUT_FMT_DATA_MOD_MB32_PLANAR		(4 << 8)
> +#define SUN4I_FRONTEND_INPUT_FMT_DATA_MOD_MB32_SEMIPLANAR	(6 << 8)
> +
> +#define SUN4I_FRONTEND_INPUT_FMT_DATA_FMT_MASK			GENMASK(6, 4)
> +#define SUN4I_FRONTEND_INPUT_FMT_DATA_FMT_YUV444		(0 << 4)
> +#define SUN4I_FRONTEND_INPUT_FMT_DATA_FMT_YUV422		(1 << 4)
> +#define SUN4I_FRONTEND_INPUT_FMT_DATA_FMT_YUV420		(2 << 4)
> +#define SUN4I_FRONTEND_INPUT_FMT_DATA_FMT_YUV411		(3 << 4)
> +#define SUN4I_FRONTEND_INPUT_FMT_DATA_FMT_RGB			(5 << 4)
> +
> +#define SUN4I_FRONTEND_INPUT_FMT_DATA_PS_MASK			GENMASK(1, 0)
> +#define SUN4I_FRONTEND_INPUT_FMT_DATA_PS_UYVY			0
> +#define SUN4I_FRONTEND_INPUT_FMT_DATA_PS_YUYV			1
> +#define SUN4I_FRONTEND_INPUT_FMT_DATA_PS_VYUY			2
> +#define SUN4I_FRONTEND_INPUT_FMT_DATA_PS_YVYU			3
> +#define SUN4I_FRONTEND_INPUT_FMT_DATA_PS_UV			0
> +#define SUN4I_FRONTEND_INPUT_FMT_DATA_PS_VU			1
> +#define SUN4I_FRONTEND_INPUT_FMT_DATA_PS_XRGB			0
> +#define SUN4I_FRONTEND_INPUT_FMT_DATA_PS_BGRX			1
>  
>  #define SUN4I_FRONTEND_OUTPUT_FMT_REG		0x05c
> -#define SUN4I_FRONTEND_OUTPUT_FMT_DATA_FMT(fmt)		(fmt)
> +#define SUN4I_FRONTEND_OUTPUT_FMT_DATA_FMT_BGRX8888	1
> +#define SUN4I_FRONTEND_OUTPUT_FMT_DATA_FMT_XRGB8888	2
> +
> +#define SUN4I_FRONTEND_CSC_COEF_REG(c)		(0x070 + (0x4 * (c)))
>  
>  #define SUN4I_FRONTEND_CH0_INSIZE_REG		0x100
>  #define SUN4I_FRONTEND_INSIZE(h, w)			((((h) - 1) << 16) | (((w) - 1)))
> @@ -96,5 +135,6 @@ void sun4i_frontend_update_coord(struct sun4i_frontend *frontend,
>  int sun4i_frontend_update_formats(struct sun4i_frontend *frontend,
>  				  struct drm_plane *plane, uint32_t out_fmt);
>  bool sun4i_frontend_format_is_supported(uint32_t fmt);
> +bool sun4i_frontend_format_chroma_requires_swap(uint32_t fmt);
>  
>  #endif /* _SUN4I_FRONTEND_H_ */
> diff --git a/drivers/gpu/drm/sun4i/sun4i_layer.c b/drivers/gpu/drm/sun4i/sun4i_layer.c
> index 15238211a61a..a39eed6a0e75 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_layer.c
> +++ b/drivers/gpu/drm/sun4i/sun4i_layer.c
> @@ -128,19 +128,37 @@ static const struct drm_plane_funcs sun4i_backend_layer_funcs = {
>  	.update_plane		= drm_atomic_helper_update_plane,
>  };
>  
> -static const uint32_t sun4i_backend_layer_formats[] = {
> -	DRM_FORMAT_ARGB8888,
> +static const uint32_t sun4i_layer_formats[] = {
> +	/* RGB */
>  	DRM_FORMAT_ARGB4444,
> +	DRM_FORMAT_RGBA4444,
>  	DRM_FORMAT_ARGB1555,
>  	DRM_FORMAT_RGBA5551,
> -	DRM_FORMAT_RGBA4444,
> -	DRM_FORMAT_RGB888,
>  	DRM_FORMAT_RGB565,
> -	DRM_FORMAT_UYVY,
> -	DRM_FORMAT_VYUY,
> +	DRM_FORMAT_RGB888,
>  	DRM_FORMAT_XRGB8888,
> +	DRM_FORMAT_BGRX8888,
> +	DRM_FORMAT_ARGB8888,
> +	/* YUV444 */
> +	DRM_FORMAT_YUV444,
> +	DRM_FORMAT_YVU444,
> +	/* YUV422 */
>  	DRM_FORMAT_YUYV,
>  	DRM_FORMAT_YVYU,
> +	DRM_FORMAT_UYVY,
> +	DRM_FORMAT_VYUY,
> +	DRM_FORMAT_NV16,
> +	DRM_FORMAT_NV61,
> +	DRM_FORMAT_YUV422,
> +	DRM_FORMAT_YVU422,
> +	/* YUV420 */
> +	DRM_FORMAT_NV12,
> +	DRM_FORMAT_NV21,
> +	DRM_FORMAT_YUV420,
> +	DRM_FORMAT_YVU420,
> +	/* YUV411 */
> +	DRM_FORMAT_YUV411,
> +	DRM_FORMAT_YVU411,
>  };
>  
>  static struct sun4i_layer *sun4i_layer_init_one(struct drm_device *drm,
> @@ -157,8 +175,8 @@ static struct sun4i_layer *sun4i_layer_init_one(struct drm_device *drm,
>  	/* possible crtcs are set later */
>  	ret = drm_universal_plane_init(drm, &layer->plane, 0,
>  				       &sun4i_backend_layer_funcs,
> -				       sun4i_backend_layer_formats,
> -				       ARRAY_SIZE(sun4i_backend_layer_formats),
> +				       sun4i_layer_formats,
> +				       ARRAY_SIZE(sun4i_layer_formats),
>  				       NULL, type, NULL);

I stopped reviewing this, because it should be split in at least the
following commits, possibly more:
  - one to add the custom GEM allocator
  - one to move the yuv number check in atomic_check
  - one to enable the input sequence computation
  - one to enable the input mode computation
  - one to move the CSC bypass setting from the probe to the update_fomats function
  - one to introduce the interleaved YUV formats
  - one to introduce the multi-planar YUV formats
  - one to rename the sun4i_backend_layer_formats array

Maxime

-- 
Maxime Ripard, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
https://bootlin.com



More information about the linux-arm-kernel mailing list