diff options
-rw-r--r-- | drivers/gpu/drm/sun4i/sun4i_frontend.c | 54 | ||||
-rw-r--r-- | drivers/gpu/drm/sun4i/sun4i_frontend.h | 5 | ||||
-rw-r--r-- | drivers/gpu/drm/sun4i/sun4i_layer.c | 8 |
3 files changed, 66 insertions, 1 deletions
diff --git a/drivers/gpu/drm/sun4i/sun4i_frontend.c b/drivers/gpu/drm/sun4i/sun4i_frontend.c index f262069d348f..6219f5d0dc53 100644 --- a/drivers/gpu/drm/sun4i/sun4i_frontend.c +++ b/drivers/gpu/drm/sun4i/sun4i_frontend.c @@ -107,12 +107,27 @@ void sun4i_frontend_exit(struct sun4i_frontend *frontend) } EXPORT_SYMBOL(sun4i_frontend_exit); +static bool sun4i_frontend_format_chroma_requires_swap(uint32_t fmt) +{ + switch (fmt) { + case DRM_FORMAT_YVU411: + case DRM_FORMAT_YVU420: + case DRM_FORMAT_YVU422: + case DRM_FORMAT_YVU444: + return true; + + default: + return false; + } +} + void sun4i_frontend_update_buffer(struct sun4i_frontend *frontend, struct drm_plane *plane) { struct drm_plane_state *state = plane->state; struct drm_framebuffer *fb = state->fb; dma_addr_t paddr; + bool swap; /* Set the line width */ DRM_DEBUG_DRIVER("Frontend stride: %d bytes\n", fb->pitches[0]); @@ -123,6 +138,13 @@ void sun4i_frontend_update_buffer(struct sun4i_frontend *frontend, regmap_write(frontend->regs, SUN4I_FRONTEND_LINESTRD1_REG, fb->pitches[1]); + if (fb->format->num_planes > 2) + regmap_write(frontend->regs, SUN4I_FRONTEND_LINESTRD2_REG, + fb->pitches[2]); + + /* Some planar formats require chroma channel swapping by hand. */ + swap = sun4i_frontend_format_chroma_requires_swap(fb->format->format); + /* Set the physical address of the buffer in memory */ paddr = drm_fb_cma_get_gem_addr(fb, state, 0); paddr -= PHYS_OFFSET; @@ -130,12 +152,20 @@ void sun4i_frontend_update_buffer(struct sun4i_frontend *frontend, regmap_write(frontend->regs, SUN4I_FRONTEND_BUF_ADDR0_REG, paddr); if (fb->format->num_planes > 1) { - paddr = drm_fb_cma_get_gem_addr(fb, state, 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 (fb->format->num_planes > 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); @@ -145,10 +175,14 @@ sun4i_frontend_drm_format_to_input_fmt(const struct drm_format_info *format, { if (!format->is_yuv) *val = SUN4I_FRONTEND_INPUT_FMT_DATA_FMT_RGB; + else if (drm_format_info_is_yuv_sampling_411(format)) + *val = SUN4I_FRONTEND_INPUT_FMT_DATA_FMT_YUV411; else if (drm_format_info_is_yuv_sampling_420(format)) *val = SUN4I_FRONTEND_INPUT_FMT_DATA_FMT_YUV420; else if (drm_format_info_is_yuv_sampling_422(format)) *val = SUN4I_FRONTEND_INPUT_FMT_DATA_FMT_YUV422; + else if (drm_format_info_is_yuv_sampling_444(format)) + *val = SUN4I_FRONTEND_INPUT_FMT_DATA_FMT_YUV444; else return -EINVAL; @@ -168,6 +202,10 @@ sun4i_frontend_drm_format_to_input_mode(const struct drm_format_info *format, *val = SUN4I_FRONTEND_INPUT_FMT_DATA_MOD_SEMIPLANAR; return 0; + case 3: + *val = SUN4I_FRONTEND_INPUT_FMT_DATA_MOD_PLANAR; + return 0; + default: return -EINVAL; } @@ -177,6 +215,12 @@ static int sun4i_frontend_drm_format_to_input_sequence(const struct drm_format_info *format, u32 *val) { + /* Planar formats have an explicit input sequence. */ + if (drm_format_info_is_yuv_planar(format)) { + *val = 0; + return 0; + } + switch (format->format) { case DRM_FORMAT_BGRX8888: *val = SUN4I_FRONTEND_INPUT_FMT_DATA_PS_BGRX; @@ -248,7 +292,15 @@ static const uint32_t sun4i_frontend_formats[] = { DRM_FORMAT_UYVY, DRM_FORMAT_VYUY, DRM_FORMAT_XRGB8888, + DRM_FORMAT_YUV411, + DRM_FORMAT_YUV420, + DRM_FORMAT_YUV422, + DRM_FORMAT_YUV444, DRM_FORMAT_YUYV, + DRM_FORMAT_YVU411, + DRM_FORMAT_YVU420, + DRM_FORMAT_YVU422, + DRM_FORMAT_YVU444, DRM_FORMAT_YVYU, }; diff --git a/drivers/gpu/drm/sun4i/sun4i_frontend.h b/drivers/gpu/drm/sun4i/sun4i_frontend.h index 2f9e3f84e2ff..c62735c2dc4b 100644 --- a/drivers/gpu/drm/sun4i/sun4i_frontend.h +++ b/drivers/gpu/drm/sun4i/sun4i_frontend.h @@ -23,15 +23,20 @@ #define SUN4I_FRONTEND_BUF_ADDR0_REG 0x020 #define SUN4I_FRONTEND_BUF_ADDR1_REG 0x024 +#define SUN4I_FRONTEND_BUF_ADDR2_REG 0x028 #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_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_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_UYVY 0 #define SUN4I_FRONTEND_INPUT_FMT_DATA_PS_YUYV 1 diff --git a/drivers/gpu/drm/sun4i/sun4i_layer.c b/drivers/gpu/drm/sun4i/sun4i_layer.c index 185ef38649aa..8cf8ca997b1d 100644 --- a/drivers/gpu/drm/sun4i/sun4i_layer.c +++ b/drivers/gpu/drm/sun4i/sun4i_layer.c @@ -145,7 +145,15 @@ static const uint32_t sun4i_layer_formats[] = { DRM_FORMAT_UYVY, DRM_FORMAT_VYUY, DRM_FORMAT_XRGB8888, + DRM_FORMAT_YUV411, + DRM_FORMAT_YUV420, + DRM_FORMAT_YUV422, + DRM_FORMAT_YUV444, DRM_FORMAT_YUYV, + DRM_FORMAT_YVU411, + DRM_FORMAT_YVU420, + DRM_FORMAT_YVU422, + DRM_FORMAT_YVU444, DRM_FORMAT_YVYU, }; |