Re: [PATCH 07/10] drm/sun4i: Add support for YUV formats through the frontend
From: Maxime Ripard
Date: Fri Mar 23 2018 - 06:30:24 EST
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@xxxxxxxxxxx>
> ---
> 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