162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) Icenowy Zheng <icenowy@aosc.io> 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Based on sun4i_layer.h, which is: 662306a36Sopenharmony_ci * Copyright (C) 2015 Free Electrons 762306a36Sopenharmony_ci * Copyright (C) 2015 NextThing Co 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * Maxime Ripard <maxime.ripard@free-electrons.com> 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include <drm/drm_atomic.h> 1362306a36Sopenharmony_ci#include <drm/drm_atomic_helper.h> 1462306a36Sopenharmony_ci#include <drm/drm_blend.h> 1562306a36Sopenharmony_ci#include <drm/drm_crtc.h> 1662306a36Sopenharmony_ci#include <drm/drm_fb_dma_helper.h> 1762306a36Sopenharmony_ci#include <drm/drm_fourcc.h> 1862306a36Sopenharmony_ci#include <drm/drm_framebuffer.h> 1962306a36Sopenharmony_ci#include <drm/drm_gem_atomic_helper.h> 2062306a36Sopenharmony_ci#include <drm/drm_gem_dma_helper.h> 2162306a36Sopenharmony_ci#include <drm/drm_probe_helper.h> 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#include "sun8i_mixer.h" 2462306a36Sopenharmony_ci#include "sun8i_ui_layer.h" 2562306a36Sopenharmony_ci#include "sun8i_ui_scaler.h" 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_cistatic void sun8i_ui_layer_enable(struct sun8i_mixer *mixer, int channel, 2862306a36Sopenharmony_ci int overlay, bool enable, unsigned int zpos, 2962306a36Sopenharmony_ci unsigned int old_zpos) 3062306a36Sopenharmony_ci{ 3162306a36Sopenharmony_ci u32 val, bld_base, ch_base; 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci bld_base = sun8i_blender_base(mixer); 3462306a36Sopenharmony_ci ch_base = sun8i_channel_base(mixer, channel); 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci DRM_DEBUG_DRIVER("%sabling channel %d overlay %d\n", 3762306a36Sopenharmony_ci enable ? "En" : "Dis", channel, overlay); 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci if (enable) 4062306a36Sopenharmony_ci val = SUN8I_MIXER_CHAN_UI_LAYER_ATTR_EN; 4162306a36Sopenharmony_ci else 4262306a36Sopenharmony_ci val = 0; 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci regmap_update_bits(mixer->engine.regs, 4562306a36Sopenharmony_ci SUN8I_MIXER_CHAN_UI_LAYER_ATTR(ch_base, overlay), 4662306a36Sopenharmony_ci SUN8I_MIXER_CHAN_UI_LAYER_ATTR_EN, val); 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci if (!enable || zpos != old_zpos) { 4962306a36Sopenharmony_ci regmap_update_bits(mixer->engine.regs, 5062306a36Sopenharmony_ci SUN8I_MIXER_BLEND_PIPE_CTL(bld_base), 5162306a36Sopenharmony_ci SUN8I_MIXER_BLEND_PIPE_CTL_EN(old_zpos), 5262306a36Sopenharmony_ci 0); 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci regmap_update_bits(mixer->engine.regs, 5562306a36Sopenharmony_ci SUN8I_MIXER_BLEND_ROUTE(bld_base), 5662306a36Sopenharmony_ci SUN8I_MIXER_BLEND_ROUTE_PIPE_MSK(old_zpos), 5762306a36Sopenharmony_ci 0); 5862306a36Sopenharmony_ci } 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci if (enable) { 6162306a36Sopenharmony_ci val = SUN8I_MIXER_BLEND_PIPE_CTL_EN(zpos); 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci regmap_update_bits(mixer->engine.regs, 6462306a36Sopenharmony_ci SUN8I_MIXER_BLEND_PIPE_CTL(bld_base), 6562306a36Sopenharmony_ci val, val); 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci val = channel << SUN8I_MIXER_BLEND_ROUTE_PIPE_SHIFT(zpos); 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci regmap_update_bits(mixer->engine.regs, 7062306a36Sopenharmony_ci SUN8I_MIXER_BLEND_ROUTE(bld_base), 7162306a36Sopenharmony_ci SUN8I_MIXER_BLEND_ROUTE_PIPE_MSK(zpos), 7262306a36Sopenharmony_ci val); 7362306a36Sopenharmony_ci } 7462306a36Sopenharmony_ci} 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_cistatic void sun8i_ui_layer_update_alpha(struct sun8i_mixer *mixer, int channel, 7762306a36Sopenharmony_ci int overlay, struct drm_plane *plane) 7862306a36Sopenharmony_ci{ 7962306a36Sopenharmony_ci u32 mask, val, ch_base; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci ch_base = sun8i_channel_base(mixer, channel); 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci mask = SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MODE_MASK | 8462306a36Sopenharmony_ci SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MASK; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci val = SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA(plane->state->alpha >> 8); 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci val |= (plane->state->alpha == DRM_BLEND_ALPHA_OPAQUE) ? 8962306a36Sopenharmony_ci SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MODE_PIXEL : 9062306a36Sopenharmony_ci SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MODE_COMBINED; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci regmap_update_bits(mixer->engine.regs, 9362306a36Sopenharmony_ci SUN8I_MIXER_CHAN_UI_LAYER_ATTR(ch_base, overlay), 9462306a36Sopenharmony_ci mask, val); 9562306a36Sopenharmony_ci} 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_cistatic int sun8i_ui_layer_update_coord(struct sun8i_mixer *mixer, int channel, 9862306a36Sopenharmony_ci int overlay, struct drm_plane *plane, 9962306a36Sopenharmony_ci unsigned int zpos) 10062306a36Sopenharmony_ci{ 10162306a36Sopenharmony_ci struct drm_plane_state *state = plane->state; 10262306a36Sopenharmony_ci u32 src_w, src_h, dst_w, dst_h; 10362306a36Sopenharmony_ci u32 bld_base, ch_base; 10462306a36Sopenharmony_ci u32 outsize, insize; 10562306a36Sopenharmony_ci u32 hphase, vphase; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci DRM_DEBUG_DRIVER("Updating UI channel %d overlay %d\n", 10862306a36Sopenharmony_ci channel, overlay); 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci bld_base = sun8i_blender_base(mixer); 11162306a36Sopenharmony_ci ch_base = sun8i_channel_base(mixer, channel); 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci src_w = drm_rect_width(&state->src) >> 16; 11462306a36Sopenharmony_ci src_h = drm_rect_height(&state->src) >> 16; 11562306a36Sopenharmony_ci dst_w = drm_rect_width(&state->dst); 11662306a36Sopenharmony_ci dst_h = drm_rect_height(&state->dst); 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci hphase = state->src.x1 & 0xffff; 11962306a36Sopenharmony_ci vphase = state->src.y1 & 0xffff; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci insize = SUN8I_MIXER_SIZE(src_w, src_h); 12262306a36Sopenharmony_ci outsize = SUN8I_MIXER_SIZE(dst_w, dst_h); 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci /* Set height and width */ 12562306a36Sopenharmony_ci DRM_DEBUG_DRIVER("Layer source offset X: %d Y: %d\n", 12662306a36Sopenharmony_ci state->src.x1 >> 16, state->src.y1 >> 16); 12762306a36Sopenharmony_ci DRM_DEBUG_DRIVER("Layer source size W: %d H: %d\n", src_w, src_h); 12862306a36Sopenharmony_ci regmap_write(mixer->engine.regs, 12962306a36Sopenharmony_ci SUN8I_MIXER_CHAN_UI_LAYER_SIZE(ch_base, overlay), 13062306a36Sopenharmony_ci insize); 13162306a36Sopenharmony_ci regmap_write(mixer->engine.regs, 13262306a36Sopenharmony_ci SUN8I_MIXER_CHAN_UI_OVL_SIZE(ch_base), 13362306a36Sopenharmony_ci insize); 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci if (insize != outsize || hphase || vphase) { 13662306a36Sopenharmony_ci u32 hscale, vscale; 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci DRM_DEBUG_DRIVER("HW scaling is enabled\n"); 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci hscale = state->src_w / state->crtc_w; 14162306a36Sopenharmony_ci vscale = state->src_h / state->crtc_h; 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci sun8i_ui_scaler_setup(mixer, channel, src_w, src_h, dst_w, 14462306a36Sopenharmony_ci dst_h, hscale, vscale, hphase, vphase); 14562306a36Sopenharmony_ci sun8i_ui_scaler_enable(mixer, channel, true); 14662306a36Sopenharmony_ci } else { 14762306a36Sopenharmony_ci DRM_DEBUG_DRIVER("HW scaling is not needed\n"); 14862306a36Sopenharmony_ci sun8i_ui_scaler_enable(mixer, channel, false); 14962306a36Sopenharmony_ci } 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci /* Set base coordinates */ 15262306a36Sopenharmony_ci DRM_DEBUG_DRIVER("Layer destination coordinates X: %d Y: %d\n", 15362306a36Sopenharmony_ci state->dst.x1, state->dst.y1); 15462306a36Sopenharmony_ci DRM_DEBUG_DRIVER("Layer destination size W: %d H: %d\n", dst_w, dst_h); 15562306a36Sopenharmony_ci regmap_write(mixer->engine.regs, 15662306a36Sopenharmony_ci SUN8I_MIXER_BLEND_ATTR_COORD(bld_base, zpos), 15762306a36Sopenharmony_ci SUN8I_MIXER_COORD(state->dst.x1, state->dst.y1)); 15862306a36Sopenharmony_ci regmap_write(mixer->engine.regs, 15962306a36Sopenharmony_ci SUN8I_MIXER_BLEND_ATTR_INSIZE(bld_base, zpos), 16062306a36Sopenharmony_ci outsize); 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci return 0; 16362306a36Sopenharmony_ci} 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_cistatic int sun8i_ui_layer_update_formats(struct sun8i_mixer *mixer, int channel, 16662306a36Sopenharmony_ci int overlay, struct drm_plane *plane) 16762306a36Sopenharmony_ci{ 16862306a36Sopenharmony_ci struct drm_plane_state *state = plane->state; 16962306a36Sopenharmony_ci const struct drm_format_info *fmt; 17062306a36Sopenharmony_ci u32 val, ch_base, hw_fmt; 17162306a36Sopenharmony_ci int ret; 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci ch_base = sun8i_channel_base(mixer, channel); 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci fmt = state->fb->format; 17662306a36Sopenharmony_ci ret = sun8i_mixer_drm_format_to_hw(fmt->format, &hw_fmt); 17762306a36Sopenharmony_ci if (ret || fmt->is_yuv) { 17862306a36Sopenharmony_ci DRM_DEBUG_DRIVER("Invalid format\n"); 17962306a36Sopenharmony_ci return -EINVAL; 18062306a36Sopenharmony_ci } 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci val = hw_fmt << SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_OFFSET; 18362306a36Sopenharmony_ci regmap_update_bits(mixer->engine.regs, 18462306a36Sopenharmony_ci SUN8I_MIXER_CHAN_UI_LAYER_ATTR(ch_base, overlay), 18562306a36Sopenharmony_ci SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_MASK, val); 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci return 0; 18862306a36Sopenharmony_ci} 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_cistatic int sun8i_ui_layer_update_buffer(struct sun8i_mixer *mixer, int channel, 19162306a36Sopenharmony_ci int overlay, struct drm_plane *plane) 19262306a36Sopenharmony_ci{ 19362306a36Sopenharmony_ci struct drm_plane_state *state = plane->state; 19462306a36Sopenharmony_ci struct drm_framebuffer *fb = state->fb; 19562306a36Sopenharmony_ci struct drm_gem_dma_object *gem; 19662306a36Sopenharmony_ci dma_addr_t dma_addr; 19762306a36Sopenharmony_ci u32 ch_base; 19862306a36Sopenharmony_ci int bpp; 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci ch_base = sun8i_channel_base(mixer, channel); 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci /* Get the physical address of the buffer in memory */ 20362306a36Sopenharmony_ci gem = drm_fb_dma_get_gem_obj(fb, 0); 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci DRM_DEBUG_DRIVER("Using GEM @ %pad\n", &gem->dma_addr); 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci /* Compute the start of the displayed memory */ 20862306a36Sopenharmony_ci bpp = fb->format->cpp[0]; 20962306a36Sopenharmony_ci dma_addr = gem->dma_addr + fb->offsets[0]; 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci /* Fixup framebuffer address for src coordinates */ 21262306a36Sopenharmony_ci dma_addr += (state->src.x1 >> 16) * bpp; 21362306a36Sopenharmony_ci dma_addr += (state->src.y1 >> 16) * fb->pitches[0]; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci /* Set the line width */ 21662306a36Sopenharmony_ci DRM_DEBUG_DRIVER("Layer line width: %d bytes\n", fb->pitches[0]); 21762306a36Sopenharmony_ci regmap_write(mixer->engine.regs, 21862306a36Sopenharmony_ci SUN8I_MIXER_CHAN_UI_LAYER_PITCH(ch_base, overlay), 21962306a36Sopenharmony_ci fb->pitches[0]); 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci DRM_DEBUG_DRIVER("Setting buffer address to %pad\n", &dma_addr); 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci regmap_write(mixer->engine.regs, 22462306a36Sopenharmony_ci SUN8I_MIXER_CHAN_UI_LAYER_TOP_LADDR(ch_base, overlay), 22562306a36Sopenharmony_ci lower_32_bits(dma_addr)); 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci return 0; 22862306a36Sopenharmony_ci} 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_cistatic int sun8i_ui_layer_atomic_check(struct drm_plane *plane, 23162306a36Sopenharmony_ci struct drm_atomic_state *state) 23262306a36Sopenharmony_ci{ 23362306a36Sopenharmony_ci struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, 23462306a36Sopenharmony_ci plane); 23562306a36Sopenharmony_ci struct sun8i_ui_layer *layer = plane_to_sun8i_ui_layer(plane); 23662306a36Sopenharmony_ci struct drm_crtc *crtc = new_plane_state->crtc; 23762306a36Sopenharmony_ci struct drm_crtc_state *crtc_state; 23862306a36Sopenharmony_ci int min_scale, max_scale; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci if (!crtc) 24162306a36Sopenharmony_ci return 0; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci crtc_state = drm_atomic_get_existing_crtc_state(state, 24462306a36Sopenharmony_ci crtc); 24562306a36Sopenharmony_ci if (WARN_ON(!crtc_state)) 24662306a36Sopenharmony_ci return -EINVAL; 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci min_scale = DRM_PLANE_NO_SCALING; 24962306a36Sopenharmony_ci max_scale = DRM_PLANE_NO_SCALING; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci if (layer->mixer->cfg->scaler_mask & BIT(layer->channel)) { 25262306a36Sopenharmony_ci min_scale = SUN8I_UI_SCALER_SCALE_MIN; 25362306a36Sopenharmony_ci max_scale = SUN8I_UI_SCALER_SCALE_MAX; 25462306a36Sopenharmony_ci } 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci return drm_atomic_helper_check_plane_state(new_plane_state, 25762306a36Sopenharmony_ci crtc_state, 25862306a36Sopenharmony_ci min_scale, max_scale, 25962306a36Sopenharmony_ci true, true); 26062306a36Sopenharmony_ci} 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_cistatic void sun8i_ui_layer_atomic_disable(struct drm_plane *plane, 26362306a36Sopenharmony_ci struct drm_atomic_state *state) 26462306a36Sopenharmony_ci{ 26562306a36Sopenharmony_ci struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state, 26662306a36Sopenharmony_ci plane); 26762306a36Sopenharmony_ci struct sun8i_ui_layer *layer = plane_to_sun8i_ui_layer(plane); 26862306a36Sopenharmony_ci unsigned int old_zpos = old_state->normalized_zpos; 26962306a36Sopenharmony_ci struct sun8i_mixer *mixer = layer->mixer; 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci sun8i_ui_layer_enable(mixer, layer->channel, layer->overlay, false, 0, 27262306a36Sopenharmony_ci old_zpos); 27362306a36Sopenharmony_ci} 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_cistatic void sun8i_ui_layer_atomic_update(struct drm_plane *plane, 27662306a36Sopenharmony_ci struct drm_atomic_state *state) 27762306a36Sopenharmony_ci{ 27862306a36Sopenharmony_ci struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state, 27962306a36Sopenharmony_ci plane); 28062306a36Sopenharmony_ci struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, 28162306a36Sopenharmony_ci plane); 28262306a36Sopenharmony_ci struct sun8i_ui_layer *layer = plane_to_sun8i_ui_layer(plane); 28362306a36Sopenharmony_ci unsigned int zpos = new_state->normalized_zpos; 28462306a36Sopenharmony_ci unsigned int old_zpos = old_state->normalized_zpos; 28562306a36Sopenharmony_ci struct sun8i_mixer *mixer = layer->mixer; 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci if (!new_state->visible) { 28862306a36Sopenharmony_ci sun8i_ui_layer_enable(mixer, layer->channel, 28962306a36Sopenharmony_ci layer->overlay, false, 0, old_zpos); 29062306a36Sopenharmony_ci return; 29162306a36Sopenharmony_ci } 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci sun8i_ui_layer_update_coord(mixer, layer->channel, 29462306a36Sopenharmony_ci layer->overlay, plane, zpos); 29562306a36Sopenharmony_ci sun8i_ui_layer_update_alpha(mixer, layer->channel, 29662306a36Sopenharmony_ci layer->overlay, plane); 29762306a36Sopenharmony_ci sun8i_ui_layer_update_formats(mixer, layer->channel, 29862306a36Sopenharmony_ci layer->overlay, plane); 29962306a36Sopenharmony_ci sun8i_ui_layer_update_buffer(mixer, layer->channel, 30062306a36Sopenharmony_ci layer->overlay, plane); 30162306a36Sopenharmony_ci sun8i_ui_layer_enable(mixer, layer->channel, layer->overlay, 30262306a36Sopenharmony_ci true, zpos, old_zpos); 30362306a36Sopenharmony_ci} 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_cistatic const struct drm_plane_helper_funcs sun8i_ui_layer_helper_funcs = { 30662306a36Sopenharmony_ci .atomic_check = sun8i_ui_layer_atomic_check, 30762306a36Sopenharmony_ci .atomic_disable = sun8i_ui_layer_atomic_disable, 30862306a36Sopenharmony_ci .atomic_update = sun8i_ui_layer_atomic_update, 30962306a36Sopenharmony_ci}; 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_cistatic const struct drm_plane_funcs sun8i_ui_layer_funcs = { 31262306a36Sopenharmony_ci .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, 31362306a36Sopenharmony_ci .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, 31462306a36Sopenharmony_ci .destroy = drm_plane_cleanup, 31562306a36Sopenharmony_ci .disable_plane = drm_atomic_helper_disable_plane, 31662306a36Sopenharmony_ci .reset = drm_atomic_helper_plane_reset, 31762306a36Sopenharmony_ci .update_plane = drm_atomic_helper_update_plane, 31862306a36Sopenharmony_ci}; 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_cistatic const u32 sun8i_ui_layer_formats[] = { 32162306a36Sopenharmony_ci DRM_FORMAT_ABGR1555, 32262306a36Sopenharmony_ci DRM_FORMAT_ABGR4444, 32362306a36Sopenharmony_ci DRM_FORMAT_ABGR8888, 32462306a36Sopenharmony_ci DRM_FORMAT_ARGB1555, 32562306a36Sopenharmony_ci DRM_FORMAT_ARGB4444, 32662306a36Sopenharmony_ci DRM_FORMAT_ARGB8888, 32762306a36Sopenharmony_ci DRM_FORMAT_BGR565, 32862306a36Sopenharmony_ci DRM_FORMAT_BGR888, 32962306a36Sopenharmony_ci DRM_FORMAT_BGRA5551, 33062306a36Sopenharmony_ci DRM_FORMAT_BGRA4444, 33162306a36Sopenharmony_ci DRM_FORMAT_BGRA8888, 33262306a36Sopenharmony_ci DRM_FORMAT_BGRX8888, 33362306a36Sopenharmony_ci DRM_FORMAT_RGB565, 33462306a36Sopenharmony_ci DRM_FORMAT_RGB888, 33562306a36Sopenharmony_ci DRM_FORMAT_RGBA4444, 33662306a36Sopenharmony_ci DRM_FORMAT_RGBA5551, 33762306a36Sopenharmony_ci DRM_FORMAT_RGBA8888, 33862306a36Sopenharmony_ci DRM_FORMAT_RGBX8888, 33962306a36Sopenharmony_ci DRM_FORMAT_XBGR8888, 34062306a36Sopenharmony_ci DRM_FORMAT_XRGB8888, 34162306a36Sopenharmony_ci}; 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_cistatic const uint64_t sun8i_layer_modifiers[] = { 34462306a36Sopenharmony_ci DRM_FORMAT_MOD_LINEAR, 34562306a36Sopenharmony_ci DRM_FORMAT_MOD_INVALID 34662306a36Sopenharmony_ci}; 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_cistruct sun8i_ui_layer *sun8i_ui_layer_init_one(struct drm_device *drm, 34962306a36Sopenharmony_ci struct sun8i_mixer *mixer, 35062306a36Sopenharmony_ci int index) 35162306a36Sopenharmony_ci{ 35262306a36Sopenharmony_ci enum drm_plane_type type = DRM_PLANE_TYPE_OVERLAY; 35362306a36Sopenharmony_ci int channel = mixer->cfg->vi_num + index; 35462306a36Sopenharmony_ci struct sun8i_ui_layer *layer; 35562306a36Sopenharmony_ci unsigned int plane_cnt; 35662306a36Sopenharmony_ci int ret; 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci layer = devm_kzalloc(drm->dev, sizeof(*layer), GFP_KERNEL); 35962306a36Sopenharmony_ci if (!layer) 36062306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci if (index == 0) 36362306a36Sopenharmony_ci type = DRM_PLANE_TYPE_PRIMARY; 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci /* possible crtcs are set later */ 36662306a36Sopenharmony_ci ret = drm_universal_plane_init(drm, &layer->plane, 0, 36762306a36Sopenharmony_ci &sun8i_ui_layer_funcs, 36862306a36Sopenharmony_ci sun8i_ui_layer_formats, 36962306a36Sopenharmony_ci ARRAY_SIZE(sun8i_ui_layer_formats), 37062306a36Sopenharmony_ci sun8i_layer_modifiers, type, NULL); 37162306a36Sopenharmony_ci if (ret) { 37262306a36Sopenharmony_ci dev_err(drm->dev, "Couldn't initialize layer\n"); 37362306a36Sopenharmony_ci return ERR_PTR(ret); 37462306a36Sopenharmony_ci } 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci plane_cnt = mixer->cfg->ui_num + mixer->cfg->vi_num; 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci ret = drm_plane_create_alpha_property(&layer->plane); 37962306a36Sopenharmony_ci if (ret) { 38062306a36Sopenharmony_ci dev_err(drm->dev, "Couldn't add alpha property\n"); 38162306a36Sopenharmony_ci return ERR_PTR(ret); 38262306a36Sopenharmony_ci } 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci ret = drm_plane_create_zpos_property(&layer->plane, channel, 38562306a36Sopenharmony_ci 0, plane_cnt - 1); 38662306a36Sopenharmony_ci if (ret) { 38762306a36Sopenharmony_ci dev_err(drm->dev, "Couldn't add zpos property\n"); 38862306a36Sopenharmony_ci return ERR_PTR(ret); 38962306a36Sopenharmony_ci } 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci drm_plane_helper_add(&layer->plane, &sun8i_ui_layer_helper_funcs); 39262306a36Sopenharmony_ci layer->mixer = mixer; 39362306a36Sopenharmony_ci layer->channel = channel; 39462306a36Sopenharmony_ci layer->overlay = 0; 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci return layer; 39762306a36Sopenharmony_ci} 398