Commit e1ef9006 authored by Jernej Skrabec's avatar Jernej Skrabec Committed by Maxime Ripard

drm/sun4i: Wire in DE2 YUV support

Now that we have all required bits, add support for YUV formats.

DRM subsystem doesn't know YUV411 semi-planar format, so leave that out
for now.
Signed-off-by: default avatarJernej Skrabec <jernej.skrabec@siol.net>
Signed-off-by: default avatarMaxime Ripard <maxime.ripard@free-electrons.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20171201060550.10392-27-jernej.skrabec@siol.net
parent 1343bd6c
...@@ -55,6 +55,7 @@ static int sun8i_vi_layer_update_coord(struct sun8i_mixer *mixer, int channel, ...@@ -55,6 +55,7 @@ static int sun8i_vi_layer_update_coord(struct sun8i_mixer *mixer, int channel,
u32 src_w, src_h, dst_w, dst_h; u32 src_w, src_h, dst_w, dst_h;
u32 outsize, insize; u32 outsize, insize;
u32 hphase, vphase; u32 hphase, vphase;
bool subsampled;
DRM_DEBUG_DRIVER("Updating VI channel %d overlay %d\n", DRM_DEBUG_DRIVER("Updating VI channel %d overlay %d\n",
channel, overlay); channel, overlay);
...@@ -67,12 +68,32 @@ static int sun8i_vi_layer_update_coord(struct sun8i_mixer *mixer, int channel, ...@@ -67,12 +68,32 @@ static int sun8i_vi_layer_update_coord(struct sun8i_mixer *mixer, int channel,
hphase = state->src.x1 & 0xffff; hphase = state->src.x1 & 0xffff;
vphase = state->src.y1 & 0xffff; vphase = state->src.y1 & 0xffff;
/* make coordinates dividable by subsampling factor */
if (format->hsub > 1) {
int mask, remainder;
mask = format->hsub - 1;
remainder = (state->src.x1 >> 16) & mask;
src_w = (src_w + remainder) & ~mask;
hphase += remainder << 16;
}
if (format->vsub > 1) {
int mask, remainder;
mask = format->vsub - 1;
remainder = (state->src.y1 >> 16) & mask;
src_h = (src_h + remainder) & ~mask;
vphase += remainder << 16;
}
insize = SUN8I_MIXER_SIZE(src_w, src_h); insize = SUN8I_MIXER_SIZE(src_w, src_h);
outsize = SUN8I_MIXER_SIZE(dst_w, dst_h); outsize = SUN8I_MIXER_SIZE(dst_w, dst_h);
/* Set height and width */ /* Set height and width */
DRM_DEBUG_DRIVER("Layer source offset X: %d Y: %d\n", DRM_DEBUG_DRIVER("Layer source offset X: %d Y: %d\n",
state->src.x1 >> 16, state->src.y1 >> 16); (state->src.x1 >> 16) & ~(format->hsub - 1),
(state->src.y1 >> 16) & ~(format->vsub - 1));
DRM_DEBUG_DRIVER("Layer source size W: %d H: %d\n", src_w, src_h); DRM_DEBUG_DRIVER("Layer source size W: %d H: %d\n", src_w, src_h);
regmap_write(mixer->engine.regs, regmap_write(mixer->engine.regs,
SUN8I_MIXER_CHAN_VI_LAYER_SIZE(channel, overlay), SUN8I_MIXER_CHAN_VI_LAYER_SIZE(channel, overlay),
...@@ -81,7 +102,13 @@ static int sun8i_vi_layer_update_coord(struct sun8i_mixer *mixer, int channel, ...@@ -81,7 +102,13 @@ static int sun8i_vi_layer_update_coord(struct sun8i_mixer *mixer, int channel,
SUN8I_MIXER_CHAN_VI_OVL_SIZE(channel), SUN8I_MIXER_CHAN_VI_OVL_SIZE(channel),
insize); insize);
if (insize != outsize || hphase || vphase) { /*
* Scaler must be enabled for subsampled formats, so it scales
* chroma to same size as luma.
*/
subsampled = format->hsub > 1 || format->vsub > 1;
if (insize != outsize || subsampled || hphase || vphase) {
u32 hscale, vscale; u32 hscale, vscale;
DRM_DEBUG_DRIVER("HW scaling is enabled\n"); DRM_DEBUG_DRIVER("HW scaling is enabled\n");
...@@ -120,7 +147,7 @@ static int sun8i_vi_layer_update_formats(struct sun8i_mixer *mixer, int channel, ...@@ -120,7 +147,7 @@ static int sun8i_vi_layer_update_formats(struct sun8i_mixer *mixer, int channel,
u32 val; u32 val;
fmt_info = sun8i_mixer_format_info(state->fb->format->format); fmt_info = sun8i_mixer_format_info(state->fb->format->format);
if (!fmt_info || !fmt_info->rgb) { if (!fmt_info) {
DRM_DEBUG_DRIVER("Invalid format\n"); DRM_DEBUG_DRIVER("Invalid format\n");
return -EINVAL; return -EINVAL;
} }
...@@ -128,9 +155,23 @@ static int sun8i_vi_layer_update_formats(struct sun8i_mixer *mixer, int channel, ...@@ -128,9 +155,23 @@ static int sun8i_vi_layer_update_formats(struct sun8i_mixer *mixer, int channel,
val = fmt_info->de2_fmt << SUN8I_MIXER_CHAN_VI_LAYER_ATTR_FBFMT_OFFSET; val = fmt_info->de2_fmt << SUN8I_MIXER_CHAN_VI_LAYER_ATTR_FBFMT_OFFSET;
regmap_update_bits(mixer->engine.regs, regmap_update_bits(mixer->engine.regs,
SUN8I_MIXER_CHAN_VI_LAYER_ATTR(channel, overlay), SUN8I_MIXER_CHAN_VI_LAYER_ATTR(channel, overlay),
SUN8I_MIXER_CHAN_VI_LAYER_ATTR_FBFMT_MASK | SUN8I_MIXER_CHAN_VI_LAYER_ATTR_FBFMT_MASK, val);
SUN8I_MIXER_CHAN_VI_LAYER_ATTR_RGB_MODE,
val | SUN8I_MIXER_CHAN_VI_LAYER_ATTR_RGB_MODE); if (fmt_info->csc != SUN8I_CSC_MODE_OFF) {
sun8i_csc_set_ccsc_coefficients(mixer, channel, fmt_info->csc);
sun8i_csc_enable_ccsc(mixer, channel, true);
} else {
sun8i_csc_enable_ccsc(mixer, channel, false);
}
if (fmt_info->rgb)
val = SUN8I_MIXER_CHAN_VI_LAYER_ATTR_RGB_MODE;
else
val = 0;
regmap_update_bits(mixer->engine.regs,
SUN8I_MIXER_CHAN_VI_LAYER_ATTR(channel, overlay),
SUN8I_MIXER_CHAN_VI_LAYER_ATTR_RGB_MODE, val);
return 0; return 0;
} }
...@@ -140,34 +181,53 @@ static int sun8i_vi_layer_update_buffer(struct sun8i_mixer *mixer, int channel, ...@@ -140,34 +181,53 @@ static int sun8i_vi_layer_update_buffer(struct sun8i_mixer *mixer, int channel,
{ {
struct drm_plane_state *state = plane->state; struct drm_plane_state *state = plane->state;
struct drm_framebuffer *fb = state->fb; struct drm_framebuffer *fb = state->fb;
const struct drm_format_info *format = fb->format;
struct drm_gem_cma_object *gem; struct drm_gem_cma_object *gem;
u32 dx, dy, src_x, src_y;
dma_addr_t paddr; dma_addr_t paddr;
int bpp; int i;
/* Adjust x and y to be dividable by subsampling factor */
src_x = (state->src.x1 >> 16) & ~(format->hsub - 1);
src_y = (state->src.y1 >> 16) & ~(format->vsub - 1);
for (i = 0; i < format->num_planes; i++) {
/* Get the physical address of the buffer in memory */ /* Get the physical address of the buffer in memory */
gem = drm_fb_cma_get_gem_obj(fb, 0); gem = drm_fb_cma_get_gem_obj(fb, i);
DRM_DEBUG_DRIVER("Using GEM @ %pad\n", &gem->paddr); DRM_DEBUG_DRIVER("Using GEM @ %pad\n", &gem->paddr);
/* Compute the start of the displayed memory */ /* Compute the start of the displayed memory */
bpp = fb->format->cpp[0]; paddr = gem->paddr + fb->offsets[i];
paddr = gem->paddr + fb->offsets[0];
dx = src_x;
dy = src_y;
if (i > 0) {
dx /= format->hsub;
dy /= format->vsub;
}
/* Fixup framebuffer address for src coordinates */ /* Fixup framebuffer address for src coordinates */
paddr += (state->src.x1 >> 16) * bpp; paddr += dx * format->cpp[i];
paddr += (state->src.y1 >> 16) * fb->pitches[0]; paddr += dy * fb->pitches[i];
/* Set the line width */ /* Set the line width */
DRM_DEBUG_DRIVER("Layer line width: %d bytes\n", fb->pitches[0]); DRM_DEBUG_DRIVER("Layer %d. line width: %d bytes\n",
i + 1, fb->pitches[i]);
regmap_write(mixer->engine.regs, regmap_write(mixer->engine.regs,
SUN8I_MIXER_CHAN_VI_LAYER_PITCH(channel, overlay, 0), SUN8I_MIXER_CHAN_VI_LAYER_PITCH(channel,
fb->pitches[0]); overlay, i),
fb->pitches[i]);
DRM_DEBUG_DRIVER("Setting buffer address to %pad\n", &paddr); DRM_DEBUG_DRIVER("Setting %d. buffer address to %pad\n",
i + 1, &paddr);
regmap_write(mixer->engine.regs, regmap_write(mixer->engine.regs,
SUN8I_MIXER_CHAN_VI_LAYER_TOP_LADDR(channel, overlay, 0), SUN8I_MIXER_CHAN_VI_LAYER_TOP_LADDR(channel,
overlay, i),
lower_32_bits(paddr)); lower_32_bits(paddr));
}
return 0; return 0;
} }
...@@ -270,6 +330,23 @@ static const u32 sun8i_vi_layer_formats[] = { ...@@ -270,6 +330,23 @@ static const u32 sun8i_vi_layer_formats[] = {
DRM_FORMAT_RGBX8888, DRM_FORMAT_RGBX8888,
DRM_FORMAT_XBGR8888, DRM_FORMAT_XBGR8888,
DRM_FORMAT_XRGB8888, DRM_FORMAT_XRGB8888,
DRM_FORMAT_NV16,
DRM_FORMAT_NV12,
DRM_FORMAT_NV21,
DRM_FORMAT_NV61,
DRM_FORMAT_UYVY,
DRM_FORMAT_VYUY,
DRM_FORMAT_YUYV,
DRM_FORMAT_YVYU,
DRM_FORMAT_YUV411,
DRM_FORMAT_YUV420,
DRM_FORMAT_YUV422,
DRM_FORMAT_YUV444,
DRM_FORMAT_YVU411,
DRM_FORMAT_YVU420,
DRM_FORMAT_YVU422,
DRM_FORMAT_YVU444,
}; };
struct sun8i_vi_layer *sun8i_vi_layer_init_one(struct drm_device *drm, struct sun8i_vi_layer *sun8i_vi_layer_init_one(struct drm_device *drm,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment