17480ba4dSJernej Skrabec /* 27480ba4dSJernej Skrabec * Copyright (C) Jernej Skrabec <jernej.skrabec@siol.net> 37480ba4dSJernej Skrabec * 47480ba4dSJernej Skrabec * This program is free software; you can redistribute it and/or 57480ba4dSJernej Skrabec * modify it under the terms of the GNU General Public License as 67480ba4dSJernej Skrabec * published by the Free Software Foundation; either version 2 of 77480ba4dSJernej Skrabec * the License, or (at your option) any later version. 87480ba4dSJernej Skrabec */ 97480ba4dSJernej Skrabec 107480ba4dSJernej Skrabec #include <drm/drm_atomic.h> 117480ba4dSJernej Skrabec #include <drm/drm_atomic_helper.h> 127480ba4dSJernej Skrabec #include <drm/drm_crtc.h> 137480ba4dSJernej Skrabec #include <drm/drm_crtc_helper.h> 147480ba4dSJernej Skrabec #include <drm/drm_fb_cma_helper.h> 157480ba4dSJernej Skrabec #include <drm/drm_gem_cma_helper.h> 167480ba4dSJernej Skrabec #include <drm/drm_plane_helper.h> 177480ba4dSJernej Skrabec #include <drm/drmP.h> 187480ba4dSJernej Skrabec 197480ba4dSJernej Skrabec #include "sun8i_vi_layer.h" 207480ba4dSJernej Skrabec #include "sun8i_mixer.h" 21b862a648SJernej Skrabec #include "sun8i_vi_scaler.h" 227480ba4dSJernej Skrabec 237480ba4dSJernej Skrabec static void sun8i_vi_layer_enable(struct sun8i_mixer *mixer, int channel, 24f88c5ee7SJernej Skrabec int overlay, bool enable, unsigned int zpos) 257480ba4dSJernej Skrabec { 267480ba4dSJernej Skrabec u32 val; 277480ba4dSJernej Skrabec 287480ba4dSJernej Skrabec DRM_DEBUG_DRIVER("%sabling VI channel %d overlay %d\n", 297480ba4dSJernej Skrabec enable ? "En" : "Dis", channel, overlay); 307480ba4dSJernej Skrabec 317480ba4dSJernej Skrabec if (enable) 327480ba4dSJernej Skrabec val = SUN8I_MIXER_CHAN_VI_LAYER_ATTR_EN; 337480ba4dSJernej Skrabec else 347480ba4dSJernej Skrabec val = 0; 357480ba4dSJernej Skrabec 367480ba4dSJernej Skrabec regmap_update_bits(mixer->engine.regs, 377480ba4dSJernej Skrabec SUN8I_MIXER_CHAN_VI_LAYER_ATTR(channel, overlay), 387480ba4dSJernej Skrabec SUN8I_MIXER_CHAN_VI_LAYER_ATTR_EN, val); 397480ba4dSJernej Skrabec 40f88c5ee7SJernej Skrabec if (enable) { 41f88c5ee7SJernej Skrabec val = SUN8I_MIXER_BLEND_PIPE_CTL_EN(zpos); 427480ba4dSJernej Skrabec 437480ba4dSJernej Skrabec regmap_update_bits(mixer->engine.regs, 44f88c5ee7SJernej Skrabec SUN8I_MIXER_BLEND_PIPE_CTL, val, val); 45f88c5ee7SJernej Skrabec 46f88c5ee7SJernej Skrabec val = channel << SUN8I_MIXER_BLEND_ROUTE_PIPE_SHIFT(zpos); 47f88c5ee7SJernej Skrabec 48f88c5ee7SJernej Skrabec regmap_update_bits(mixer->engine.regs, 49f88c5ee7SJernej Skrabec SUN8I_MIXER_BLEND_ROUTE, 50f88c5ee7SJernej Skrabec SUN8I_MIXER_BLEND_ROUTE_PIPE_MSK(zpos), 51f88c5ee7SJernej Skrabec val); 52f88c5ee7SJernej Skrabec } 537480ba4dSJernej Skrabec } 547480ba4dSJernej Skrabec 557480ba4dSJernej Skrabec static int sun8i_vi_layer_update_coord(struct sun8i_mixer *mixer, int channel, 56f88c5ee7SJernej Skrabec int overlay, struct drm_plane *plane, 57f88c5ee7SJernej Skrabec unsigned int zpos) 587480ba4dSJernej Skrabec { 597480ba4dSJernej Skrabec struct drm_plane_state *state = plane->state; 601343bd6cSJernej Skrabec const struct drm_format_info *format = state->fb->format; 61b862a648SJernej Skrabec u32 src_w, src_h, dst_w, dst_h; 62b862a648SJernej Skrabec u32 outsize, insize; 63b862a648SJernej Skrabec u32 hphase, vphase; 64e1ef9006SJernej Skrabec bool subsampled; 657480ba4dSJernej Skrabec 667480ba4dSJernej Skrabec DRM_DEBUG_DRIVER("Updating VI channel %d overlay %d\n", 677480ba4dSJernej Skrabec channel, overlay); 68b862a648SJernej Skrabec 69b862a648SJernej Skrabec src_w = drm_rect_width(&state->src) >> 16; 70b862a648SJernej Skrabec src_h = drm_rect_height(&state->src) >> 16; 71b862a648SJernej Skrabec dst_w = drm_rect_width(&state->dst); 72b862a648SJernej Skrabec dst_h = drm_rect_height(&state->dst); 73b862a648SJernej Skrabec 74b862a648SJernej Skrabec hphase = state->src.x1 & 0xffff; 75b862a648SJernej Skrabec vphase = state->src.y1 & 0xffff; 76b862a648SJernej Skrabec 77e1ef9006SJernej Skrabec /* make coordinates dividable by subsampling factor */ 78e1ef9006SJernej Skrabec if (format->hsub > 1) { 79e1ef9006SJernej Skrabec int mask, remainder; 80e1ef9006SJernej Skrabec 81e1ef9006SJernej Skrabec mask = format->hsub - 1; 82e1ef9006SJernej Skrabec remainder = (state->src.x1 >> 16) & mask; 83e1ef9006SJernej Skrabec src_w = (src_w + remainder) & ~mask; 84e1ef9006SJernej Skrabec hphase += remainder << 16; 85e1ef9006SJernej Skrabec } 86e1ef9006SJernej Skrabec 87e1ef9006SJernej Skrabec if (format->vsub > 1) { 88e1ef9006SJernej Skrabec int mask, remainder; 89e1ef9006SJernej Skrabec 90e1ef9006SJernej Skrabec mask = format->vsub - 1; 91e1ef9006SJernej Skrabec remainder = (state->src.y1 >> 16) & mask; 92e1ef9006SJernej Skrabec src_h = (src_h + remainder) & ~mask; 93e1ef9006SJernej Skrabec vphase += remainder << 16; 94e1ef9006SJernej Skrabec } 95e1ef9006SJernej Skrabec 96b862a648SJernej Skrabec insize = SUN8I_MIXER_SIZE(src_w, src_h); 97b862a648SJernej Skrabec outsize = SUN8I_MIXER_SIZE(dst_w, dst_h); 987480ba4dSJernej Skrabec 997480ba4dSJernej Skrabec /* Set height and width */ 100b862a648SJernej Skrabec DRM_DEBUG_DRIVER("Layer source offset X: %d Y: %d\n", 101e1ef9006SJernej Skrabec (state->src.x1 >> 16) & ~(format->hsub - 1), 102e1ef9006SJernej Skrabec (state->src.y1 >> 16) & ~(format->vsub - 1)); 103b862a648SJernej Skrabec DRM_DEBUG_DRIVER("Layer source size W: %d H: %d\n", src_w, src_h); 1047480ba4dSJernej Skrabec regmap_write(mixer->engine.regs, 1057480ba4dSJernej Skrabec SUN8I_MIXER_CHAN_VI_LAYER_SIZE(channel, overlay), 106b862a648SJernej Skrabec insize); 1077480ba4dSJernej Skrabec regmap_write(mixer->engine.regs, 1087480ba4dSJernej Skrabec SUN8I_MIXER_CHAN_VI_OVL_SIZE(channel), 109b862a648SJernej Skrabec insize); 110b862a648SJernej Skrabec 111e1ef9006SJernej Skrabec /* 112e1ef9006SJernej Skrabec * Scaler must be enabled for subsampled formats, so it scales 113e1ef9006SJernej Skrabec * chroma to same size as luma. 114e1ef9006SJernej Skrabec */ 115e1ef9006SJernej Skrabec subsampled = format->hsub > 1 || format->vsub > 1; 116e1ef9006SJernej Skrabec 117e1ef9006SJernej Skrabec if (insize != outsize || subsampled || hphase || vphase) { 118b862a648SJernej Skrabec u32 hscale, vscale; 119b862a648SJernej Skrabec 120b862a648SJernej Skrabec DRM_DEBUG_DRIVER("HW scaling is enabled\n"); 121b862a648SJernej Skrabec 122b862a648SJernej Skrabec hscale = state->src_w / state->crtc_w; 123b862a648SJernej Skrabec vscale = state->src_h / state->crtc_h; 124b862a648SJernej Skrabec 125b862a648SJernej Skrabec sun8i_vi_scaler_setup(mixer, channel, src_w, src_h, dst_w, 1261343bd6cSJernej Skrabec dst_h, hscale, vscale, hphase, vphase, 1271343bd6cSJernej Skrabec format); 128b862a648SJernej Skrabec sun8i_vi_scaler_enable(mixer, channel, true); 129b862a648SJernej Skrabec } else { 130b862a648SJernej Skrabec DRM_DEBUG_DRIVER("HW scaling is not needed\n"); 131b862a648SJernej Skrabec sun8i_vi_scaler_enable(mixer, channel, false); 132b862a648SJernej Skrabec } 1337480ba4dSJernej Skrabec 1347480ba4dSJernej Skrabec /* Set base coordinates */ 135b862a648SJernej Skrabec DRM_DEBUG_DRIVER("Layer destination coordinates X: %d Y: %d\n", 1367480ba4dSJernej Skrabec state->dst.x1, state->dst.y1); 137b862a648SJernej Skrabec DRM_DEBUG_DRIVER("Layer destination size W: %d H: %d\n", dst_w, dst_h); 1387480ba4dSJernej Skrabec regmap_write(mixer->engine.regs, 139f88c5ee7SJernej Skrabec SUN8I_MIXER_BLEND_ATTR_COORD(zpos), 1407480ba4dSJernej Skrabec SUN8I_MIXER_COORD(state->dst.x1, state->dst.y1)); 1417480ba4dSJernej Skrabec regmap_write(mixer->engine.regs, 142f88c5ee7SJernej Skrabec SUN8I_MIXER_BLEND_ATTR_INSIZE(zpos), 143b862a648SJernej Skrabec outsize); 1447480ba4dSJernej Skrabec 1457480ba4dSJernej Skrabec return 0; 1467480ba4dSJernej Skrabec } 1477480ba4dSJernej Skrabec 1487480ba4dSJernej Skrabec static int sun8i_vi_layer_update_formats(struct sun8i_mixer *mixer, int channel, 1497480ba4dSJernej Skrabec int overlay, struct drm_plane *plane) 1507480ba4dSJernej Skrabec { 1517480ba4dSJernej Skrabec struct drm_plane_state *state = plane->state; 1527480ba4dSJernej Skrabec const struct de2_fmt_info *fmt_info; 1537480ba4dSJernej Skrabec u32 val; 1547480ba4dSJernej Skrabec 1557480ba4dSJernej Skrabec fmt_info = sun8i_mixer_format_info(state->fb->format->format); 156e1ef9006SJernej Skrabec if (!fmt_info) { 1577480ba4dSJernej Skrabec DRM_DEBUG_DRIVER("Invalid format\n"); 1587480ba4dSJernej Skrabec return -EINVAL; 1597480ba4dSJernej Skrabec } 1607480ba4dSJernej Skrabec 1617480ba4dSJernej Skrabec val = fmt_info->de2_fmt << SUN8I_MIXER_CHAN_VI_LAYER_ATTR_FBFMT_OFFSET; 1627480ba4dSJernej Skrabec regmap_update_bits(mixer->engine.regs, 1637480ba4dSJernej Skrabec SUN8I_MIXER_CHAN_VI_LAYER_ATTR(channel, overlay), 164e1ef9006SJernej Skrabec SUN8I_MIXER_CHAN_VI_LAYER_ATTR_FBFMT_MASK, val); 165e1ef9006SJernej Skrabec 166e1ef9006SJernej Skrabec if (fmt_info->csc != SUN8I_CSC_MODE_OFF) { 167e1ef9006SJernej Skrabec sun8i_csc_set_ccsc_coefficients(mixer, channel, fmt_info->csc); 168e1ef9006SJernej Skrabec sun8i_csc_enable_ccsc(mixer, channel, true); 169e1ef9006SJernej Skrabec } else { 170e1ef9006SJernej Skrabec sun8i_csc_enable_ccsc(mixer, channel, false); 171e1ef9006SJernej Skrabec } 172e1ef9006SJernej Skrabec 173e1ef9006SJernej Skrabec if (fmt_info->rgb) 174e1ef9006SJernej Skrabec val = SUN8I_MIXER_CHAN_VI_LAYER_ATTR_RGB_MODE; 175e1ef9006SJernej Skrabec else 176e1ef9006SJernej Skrabec val = 0; 177e1ef9006SJernej Skrabec 178e1ef9006SJernej Skrabec regmap_update_bits(mixer->engine.regs, 179e1ef9006SJernej Skrabec SUN8I_MIXER_CHAN_VI_LAYER_ATTR(channel, overlay), 180e1ef9006SJernej Skrabec SUN8I_MIXER_CHAN_VI_LAYER_ATTR_RGB_MODE, val); 1817480ba4dSJernej Skrabec 1827480ba4dSJernej Skrabec return 0; 1837480ba4dSJernej Skrabec } 1847480ba4dSJernej Skrabec 1857480ba4dSJernej Skrabec static int sun8i_vi_layer_update_buffer(struct sun8i_mixer *mixer, int channel, 1867480ba4dSJernej Skrabec int overlay, struct drm_plane *plane) 1877480ba4dSJernej Skrabec { 1887480ba4dSJernej Skrabec struct drm_plane_state *state = plane->state; 1897480ba4dSJernej Skrabec struct drm_framebuffer *fb = state->fb; 190e1ef9006SJernej Skrabec const struct drm_format_info *format = fb->format; 1917480ba4dSJernej Skrabec struct drm_gem_cma_object *gem; 192e1ef9006SJernej Skrabec u32 dx, dy, src_x, src_y; 1937480ba4dSJernej Skrabec dma_addr_t paddr; 194e1ef9006SJernej Skrabec int i; 1957480ba4dSJernej Skrabec 196e1ef9006SJernej Skrabec /* Adjust x and y to be dividable by subsampling factor */ 197e1ef9006SJernej Skrabec src_x = (state->src.x1 >> 16) & ~(format->hsub - 1); 198e1ef9006SJernej Skrabec src_y = (state->src.y1 >> 16) & ~(format->vsub - 1); 199e1ef9006SJernej Skrabec 200e1ef9006SJernej Skrabec for (i = 0; i < format->num_planes; i++) { 2017480ba4dSJernej Skrabec /* Get the physical address of the buffer in memory */ 202e1ef9006SJernej Skrabec gem = drm_fb_cma_get_gem_obj(fb, i); 2037480ba4dSJernej Skrabec 2047480ba4dSJernej Skrabec DRM_DEBUG_DRIVER("Using GEM @ %pad\n", &gem->paddr); 2057480ba4dSJernej Skrabec 2067480ba4dSJernej Skrabec /* Compute the start of the displayed memory */ 207e1ef9006SJernej Skrabec paddr = gem->paddr + fb->offsets[i]; 208e1ef9006SJernej Skrabec 209e1ef9006SJernej Skrabec dx = src_x; 210e1ef9006SJernej Skrabec dy = src_y; 211e1ef9006SJernej Skrabec 212e1ef9006SJernej Skrabec if (i > 0) { 213e1ef9006SJernej Skrabec dx /= format->hsub; 214e1ef9006SJernej Skrabec dy /= format->vsub; 215e1ef9006SJernej Skrabec } 2167480ba4dSJernej Skrabec 2177480ba4dSJernej Skrabec /* Fixup framebuffer address for src coordinates */ 218e1ef9006SJernej Skrabec paddr += dx * format->cpp[i]; 219e1ef9006SJernej Skrabec paddr += dy * fb->pitches[i]; 2207480ba4dSJernej Skrabec 2217480ba4dSJernej Skrabec /* Set the line width */ 222e1ef9006SJernej Skrabec DRM_DEBUG_DRIVER("Layer %d. line width: %d bytes\n", 223e1ef9006SJernej Skrabec i + 1, fb->pitches[i]); 2247480ba4dSJernej Skrabec regmap_write(mixer->engine.regs, 225e1ef9006SJernej Skrabec SUN8I_MIXER_CHAN_VI_LAYER_PITCH(channel, 226e1ef9006SJernej Skrabec overlay, i), 227e1ef9006SJernej Skrabec fb->pitches[i]); 2287480ba4dSJernej Skrabec 229e1ef9006SJernej Skrabec DRM_DEBUG_DRIVER("Setting %d. buffer address to %pad\n", 230e1ef9006SJernej Skrabec i + 1, &paddr); 2317480ba4dSJernej Skrabec 2327480ba4dSJernej Skrabec regmap_write(mixer->engine.regs, 233e1ef9006SJernej Skrabec SUN8I_MIXER_CHAN_VI_LAYER_TOP_LADDR(channel, 234e1ef9006SJernej Skrabec overlay, i), 2357480ba4dSJernej Skrabec lower_32_bits(paddr)); 236e1ef9006SJernej Skrabec } 2377480ba4dSJernej Skrabec 2387480ba4dSJernej Skrabec return 0; 2397480ba4dSJernej Skrabec } 2407480ba4dSJernej Skrabec 2417480ba4dSJernej Skrabec static int sun8i_vi_layer_atomic_check(struct drm_plane *plane, 2427480ba4dSJernej Skrabec struct drm_plane_state *state) 2437480ba4dSJernej Skrabec { 244b862a648SJernej Skrabec struct sun8i_vi_layer *layer = plane_to_sun8i_vi_layer(plane); 2457480ba4dSJernej Skrabec struct drm_crtc *crtc = state->crtc; 2467480ba4dSJernej Skrabec struct drm_crtc_state *crtc_state; 247b862a648SJernej Skrabec int min_scale, max_scale; 2487480ba4dSJernej Skrabec 2497480ba4dSJernej Skrabec if (!crtc) 2507480ba4dSJernej Skrabec return 0; 2517480ba4dSJernej Skrabec 2527480ba4dSJernej Skrabec crtc_state = drm_atomic_get_existing_crtc_state(state->state, crtc); 2537480ba4dSJernej Skrabec if (WARN_ON(!crtc_state)) 2547480ba4dSJernej Skrabec return -EINVAL; 2557480ba4dSJernej Skrabec 256bc29489fSJernej Skrabec min_scale = DRM_PLANE_HELPER_NO_SCALING; 257bc29489fSJernej Skrabec max_scale = DRM_PLANE_HELPER_NO_SCALING; 258bc29489fSJernej Skrabec 259b862a648SJernej Skrabec if (layer->mixer->cfg->scaler_mask & BIT(layer->channel)) { 260b862a648SJernej Skrabec min_scale = SUN8I_VI_SCALER_SCALE_MIN; 261b862a648SJernej Skrabec max_scale = SUN8I_VI_SCALER_SCALE_MAX; 262b862a648SJernej Skrabec } 263b862a648SJernej Skrabec 26481af63a4SVille Syrjälä return drm_atomic_helper_check_plane_state(state, crtc_state, 265b862a648SJernej Skrabec min_scale, max_scale, 2667480ba4dSJernej Skrabec true, true); 2677480ba4dSJernej Skrabec } 2687480ba4dSJernej Skrabec 2697480ba4dSJernej Skrabec static void sun8i_vi_layer_atomic_disable(struct drm_plane *plane, 2707480ba4dSJernej Skrabec struct drm_plane_state *old_state) 2717480ba4dSJernej Skrabec { 2727480ba4dSJernej Skrabec struct sun8i_vi_layer *layer = plane_to_sun8i_vi_layer(plane); 2737480ba4dSJernej Skrabec struct sun8i_mixer *mixer = layer->mixer; 2747480ba4dSJernej Skrabec 275f88c5ee7SJernej Skrabec sun8i_vi_layer_enable(mixer, layer->channel, layer->overlay, false, 0); 2767480ba4dSJernej Skrabec } 2777480ba4dSJernej Skrabec 2787480ba4dSJernej Skrabec static void sun8i_vi_layer_atomic_update(struct drm_plane *plane, 2797480ba4dSJernej Skrabec struct drm_plane_state *old_state) 2807480ba4dSJernej Skrabec { 2817480ba4dSJernej Skrabec struct sun8i_vi_layer *layer = plane_to_sun8i_vi_layer(plane); 282f88c5ee7SJernej Skrabec unsigned int zpos = plane->state->normalized_zpos; 2837480ba4dSJernej Skrabec struct sun8i_mixer *mixer = layer->mixer; 2847480ba4dSJernej Skrabec 2857480ba4dSJernej Skrabec if (!plane->state->visible) { 2867480ba4dSJernej Skrabec sun8i_vi_layer_enable(mixer, layer->channel, 287f88c5ee7SJernej Skrabec layer->overlay, false, 0); 2887480ba4dSJernej Skrabec return; 2897480ba4dSJernej Skrabec } 2907480ba4dSJernej Skrabec 2917480ba4dSJernej Skrabec sun8i_vi_layer_update_coord(mixer, layer->channel, 292f88c5ee7SJernej Skrabec layer->overlay, plane, zpos); 2937480ba4dSJernej Skrabec sun8i_vi_layer_update_formats(mixer, layer->channel, 2947480ba4dSJernej Skrabec layer->overlay, plane); 2957480ba4dSJernej Skrabec sun8i_vi_layer_update_buffer(mixer, layer->channel, 2967480ba4dSJernej Skrabec layer->overlay, plane); 297f88c5ee7SJernej Skrabec sun8i_vi_layer_enable(mixer, layer->channel, layer->overlay, 298f88c5ee7SJernej Skrabec true, zpos); 2997480ba4dSJernej Skrabec } 3007480ba4dSJernej Skrabec 3017480ba4dSJernej Skrabec static struct drm_plane_helper_funcs sun8i_vi_layer_helper_funcs = { 3027480ba4dSJernej Skrabec .atomic_check = sun8i_vi_layer_atomic_check, 3037480ba4dSJernej Skrabec .atomic_disable = sun8i_vi_layer_atomic_disable, 3047480ba4dSJernej Skrabec .atomic_update = sun8i_vi_layer_atomic_update, 3057480ba4dSJernej Skrabec }; 3067480ba4dSJernej Skrabec 3077480ba4dSJernej Skrabec static const struct drm_plane_funcs sun8i_vi_layer_funcs = { 3087480ba4dSJernej Skrabec .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, 3097480ba4dSJernej Skrabec .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, 3107480ba4dSJernej Skrabec .destroy = drm_plane_cleanup, 3117480ba4dSJernej Skrabec .disable_plane = drm_atomic_helper_disable_plane, 3127480ba4dSJernej Skrabec .reset = drm_atomic_helper_plane_reset, 3137480ba4dSJernej Skrabec .update_plane = drm_atomic_helper_update_plane, 3147480ba4dSJernej Skrabec }; 3157480ba4dSJernej Skrabec 3167480ba4dSJernej Skrabec /* 3177480ba4dSJernej Skrabec * While all RGB formats are supported, VI planes don't support 3187480ba4dSJernej Skrabec * alpha blending, so there is no point having formats with alpha 3197480ba4dSJernej Skrabec * channel if their opaque analog exist. 3207480ba4dSJernej Skrabec */ 3217480ba4dSJernej Skrabec static const u32 sun8i_vi_layer_formats[] = { 3227480ba4dSJernej Skrabec DRM_FORMAT_ABGR1555, 3237480ba4dSJernej Skrabec DRM_FORMAT_ABGR4444, 3247480ba4dSJernej Skrabec DRM_FORMAT_ARGB1555, 3257480ba4dSJernej Skrabec DRM_FORMAT_ARGB4444, 3267480ba4dSJernej Skrabec DRM_FORMAT_BGR565, 3277480ba4dSJernej Skrabec DRM_FORMAT_BGR888, 3287480ba4dSJernej Skrabec DRM_FORMAT_BGRA5551, 3297480ba4dSJernej Skrabec DRM_FORMAT_BGRA4444, 3307480ba4dSJernej Skrabec DRM_FORMAT_BGRX8888, 3317480ba4dSJernej Skrabec DRM_FORMAT_RGB565, 3327480ba4dSJernej Skrabec DRM_FORMAT_RGB888, 3337480ba4dSJernej Skrabec DRM_FORMAT_RGBA4444, 3347480ba4dSJernej Skrabec DRM_FORMAT_RGBA5551, 3357480ba4dSJernej Skrabec DRM_FORMAT_RGBX8888, 3367480ba4dSJernej Skrabec DRM_FORMAT_XBGR8888, 3377480ba4dSJernej Skrabec DRM_FORMAT_XRGB8888, 338e1ef9006SJernej Skrabec 339e1ef9006SJernej Skrabec DRM_FORMAT_NV16, 340e1ef9006SJernej Skrabec DRM_FORMAT_NV12, 341e1ef9006SJernej Skrabec DRM_FORMAT_NV21, 342e1ef9006SJernej Skrabec DRM_FORMAT_NV61, 343e1ef9006SJernej Skrabec DRM_FORMAT_UYVY, 344e1ef9006SJernej Skrabec DRM_FORMAT_VYUY, 345e1ef9006SJernej Skrabec DRM_FORMAT_YUYV, 346e1ef9006SJernej Skrabec DRM_FORMAT_YVYU, 347e1ef9006SJernej Skrabec DRM_FORMAT_YUV411, 348e1ef9006SJernej Skrabec DRM_FORMAT_YUV420, 349e1ef9006SJernej Skrabec DRM_FORMAT_YUV422, 350e1ef9006SJernej Skrabec DRM_FORMAT_YUV444, 351e1ef9006SJernej Skrabec DRM_FORMAT_YVU411, 352e1ef9006SJernej Skrabec DRM_FORMAT_YVU420, 353e1ef9006SJernej Skrabec DRM_FORMAT_YVU422, 354e1ef9006SJernej Skrabec DRM_FORMAT_YVU444, 3557480ba4dSJernej Skrabec }; 3567480ba4dSJernej Skrabec 3577480ba4dSJernej Skrabec struct sun8i_vi_layer *sun8i_vi_layer_init_one(struct drm_device *drm, 3587480ba4dSJernej Skrabec struct sun8i_mixer *mixer, 3597480ba4dSJernej Skrabec int index) 3607480ba4dSJernej Skrabec { 3617480ba4dSJernej Skrabec struct sun8i_vi_layer *layer; 362f88c5ee7SJernej Skrabec unsigned int plane_cnt; 3637480ba4dSJernej Skrabec int ret; 3647480ba4dSJernej Skrabec 3657480ba4dSJernej Skrabec layer = devm_kzalloc(drm->dev, sizeof(*layer), GFP_KERNEL); 3667480ba4dSJernej Skrabec if (!layer) 3677480ba4dSJernej Skrabec return ERR_PTR(-ENOMEM); 3687480ba4dSJernej Skrabec 3697480ba4dSJernej Skrabec /* possible crtcs are set later */ 3707480ba4dSJernej Skrabec ret = drm_universal_plane_init(drm, &layer->plane, 0, 3717480ba4dSJernej Skrabec &sun8i_vi_layer_funcs, 3727480ba4dSJernej Skrabec sun8i_vi_layer_formats, 3737480ba4dSJernej Skrabec ARRAY_SIZE(sun8i_vi_layer_formats), 3747480ba4dSJernej Skrabec NULL, DRM_PLANE_TYPE_OVERLAY, NULL); 3757480ba4dSJernej Skrabec if (ret) { 3767480ba4dSJernej Skrabec dev_err(drm->dev, "Couldn't initialize layer\n"); 3777480ba4dSJernej Skrabec return ERR_PTR(ret); 3787480ba4dSJernej Skrabec } 3797480ba4dSJernej Skrabec 380f88c5ee7SJernej Skrabec plane_cnt = mixer->cfg->ui_num + mixer->cfg->vi_num; 381f88c5ee7SJernej Skrabec 382f88c5ee7SJernej Skrabec ret = drm_plane_create_zpos_property(&layer->plane, index, 383f88c5ee7SJernej Skrabec 0, plane_cnt - 1); 3847480ba4dSJernej Skrabec if (ret) { 3857480ba4dSJernej Skrabec dev_err(drm->dev, "Couldn't add zpos property\n"); 3867480ba4dSJernej Skrabec return ERR_PTR(ret); 3877480ba4dSJernej Skrabec } 3887480ba4dSJernej Skrabec 3897480ba4dSJernej Skrabec drm_plane_helper_add(&layer->plane, &sun8i_vi_layer_helper_funcs); 3907480ba4dSJernej Skrabec layer->mixer = mixer; 3917480ba4dSJernej Skrabec layer->channel = index; 3927480ba4dSJernej Skrabec layer->overlay = 0; 3937480ba4dSJernej Skrabec 3947480ba4dSJernej Skrabec return layer; 3957480ba4dSJernej Skrabec } 396