18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) Icenowy Zheng <icenowy@aosc.io> 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Based on sun4i_layer.h, which is: 68c2ecf20Sopenharmony_ci * Copyright (C) 2015 Free Electrons 78c2ecf20Sopenharmony_ci * Copyright (C) 2015 NextThing Co 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Maxime Ripard <maxime.ripard@free-electrons.com> 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <drm/drm_atomic.h> 138c2ecf20Sopenharmony_ci#include <drm/drm_atomic_helper.h> 148c2ecf20Sopenharmony_ci#include <drm/drm_crtc.h> 158c2ecf20Sopenharmony_ci#include <drm/drm_fb_cma_helper.h> 168c2ecf20Sopenharmony_ci#include <drm/drm_fourcc.h> 178c2ecf20Sopenharmony_ci#include <drm/drm_gem_cma_helper.h> 188c2ecf20Sopenharmony_ci#include <drm/drm_gem_framebuffer_helper.h> 198c2ecf20Sopenharmony_ci#include <drm/drm_plane_helper.h> 208c2ecf20Sopenharmony_ci#include <drm/drm_probe_helper.h> 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#include "sun8i_mixer.h" 238c2ecf20Sopenharmony_ci#include "sun8i_ui_layer.h" 248c2ecf20Sopenharmony_ci#include "sun8i_ui_scaler.h" 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_cistatic void sun8i_ui_layer_enable(struct sun8i_mixer *mixer, int channel, 278c2ecf20Sopenharmony_ci int overlay, bool enable, unsigned int zpos, 288c2ecf20Sopenharmony_ci unsigned int old_zpos) 298c2ecf20Sopenharmony_ci{ 308c2ecf20Sopenharmony_ci u32 val, bld_base, ch_base; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci bld_base = sun8i_blender_base(mixer); 338c2ecf20Sopenharmony_ci ch_base = sun8i_channel_base(mixer, channel); 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci DRM_DEBUG_DRIVER("%sabling channel %d overlay %d\n", 368c2ecf20Sopenharmony_ci enable ? "En" : "Dis", channel, overlay); 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci if (enable) 398c2ecf20Sopenharmony_ci val = SUN8I_MIXER_CHAN_UI_LAYER_ATTR_EN; 408c2ecf20Sopenharmony_ci else 418c2ecf20Sopenharmony_ci val = 0; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci regmap_update_bits(mixer->engine.regs, 448c2ecf20Sopenharmony_ci SUN8I_MIXER_CHAN_UI_LAYER_ATTR(ch_base, overlay), 458c2ecf20Sopenharmony_ci SUN8I_MIXER_CHAN_UI_LAYER_ATTR_EN, val); 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci if (!enable || zpos != old_zpos) { 488c2ecf20Sopenharmony_ci regmap_update_bits(mixer->engine.regs, 498c2ecf20Sopenharmony_ci SUN8I_MIXER_BLEND_PIPE_CTL(bld_base), 508c2ecf20Sopenharmony_ci SUN8I_MIXER_BLEND_PIPE_CTL_EN(old_zpos), 518c2ecf20Sopenharmony_ci 0); 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci regmap_update_bits(mixer->engine.regs, 548c2ecf20Sopenharmony_ci SUN8I_MIXER_BLEND_ROUTE(bld_base), 558c2ecf20Sopenharmony_ci SUN8I_MIXER_BLEND_ROUTE_PIPE_MSK(old_zpos), 568c2ecf20Sopenharmony_ci 0); 578c2ecf20Sopenharmony_ci } 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci if (enable) { 608c2ecf20Sopenharmony_ci val = SUN8I_MIXER_BLEND_PIPE_CTL_EN(zpos); 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci regmap_update_bits(mixer->engine.regs, 638c2ecf20Sopenharmony_ci SUN8I_MIXER_BLEND_PIPE_CTL(bld_base), 648c2ecf20Sopenharmony_ci val, val); 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci val = channel << SUN8I_MIXER_BLEND_ROUTE_PIPE_SHIFT(zpos); 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci regmap_update_bits(mixer->engine.regs, 698c2ecf20Sopenharmony_ci SUN8I_MIXER_BLEND_ROUTE(bld_base), 708c2ecf20Sopenharmony_ci SUN8I_MIXER_BLEND_ROUTE_PIPE_MSK(zpos), 718c2ecf20Sopenharmony_ci val); 728c2ecf20Sopenharmony_ci } 738c2ecf20Sopenharmony_ci} 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_cistatic int sun8i_ui_layer_update_coord(struct sun8i_mixer *mixer, int channel, 768c2ecf20Sopenharmony_ci int overlay, struct drm_plane *plane, 778c2ecf20Sopenharmony_ci unsigned int zpos) 788c2ecf20Sopenharmony_ci{ 798c2ecf20Sopenharmony_ci struct drm_plane_state *state = plane->state; 808c2ecf20Sopenharmony_ci u32 src_w, src_h, dst_w, dst_h; 818c2ecf20Sopenharmony_ci u32 bld_base, ch_base; 828c2ecf20Sopenharmony_ci u32 outsize, insize; 838c2ecf20Sopenharmony_ci u32 hphase, vphase; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci DRM_DEBUG_DRIVER("Updating UI channel %d overlay %d\n", 868c2ecf20Sopenharmony_ci channel, overlay); 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci bld_base = sun8i_blender_base(mixer); 898c2ecf20Sopenharmony_ci ch_base = sun8i_channel_base(mixer, channel); 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci src_w = drm_rect_width(&state->src) >> 16; 928c2ecf20Sopenharmony_ci src_h = drm_rect_height(&state->src) >> 16; 938c2ecf20Sopenharmony_ci dst_w = drm_rect_width(&state->dst); 948c2ecf20Sopenharmony_ci dst_h = drm_rect_height(&state->dst); 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci hphase = state->src.x1 & 0xffff; 978c2ecf20Sopenharmony_ci vphase = state->src.y1 & 0xffff; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci insize = SUN8I_MIXER_SIZE(src_w, src_h); 1008c2ecf20Sopenharmony_ci outsize = SUN8I_MIXER_SIZE(dst_w, dst_h); 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci if (plane->type == DRM_PLANE_TYPE_PRIMARY) { 1038c2ecf20Sopenharmony_ci bool interlaced = false; 1048c2ecf20Sopenharmony_ci u32 val; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci DRM_DEBUG_DRIVER("Primary layer, updating global size W: %u H: %u\n", 1078c2ecf20Sopenharmony_ci dst_w, dst_h); 1088c2ecf20Sopenharmony_ci regmap_write(mixer->engine.regs, 1098c2ecf20Sopenharmony_ci SUN8I_MIXER_GLOBAL_SIZE, 1108c2ecf20Sopenharmony_ci outsize); 1118c2ecf20Sopenharmony_ci regmap_write(mixer->engine.regs, 1128c2ecf20Sopenharmony_ci SUN8I_MIXER_BLEND_OUTSIZE(bld_base), outsize); 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci if (state->crtc) 1158c2ecf20Sopenharmony_ci interlaced = state->crtc->state->adjusted_mode.flags 1168c2ecf20Sopenharmony_ci & DRM_MODE_FLAG_INTERLACE; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci if (interlaced) 1198c2ecf20Sopenharmony_ci val = SUN8I_MIXER_BLEND_OUTCTL_INTERLACED; 1208c2ecf20Sopenharmony_ci else 1218c2ecf20Sopenharmony_ci val = 0; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci regmap_update_bits(mixer->engine.regs, 1248c2ecf20Sopenharmony_ci SUN8I_MIXER_BLEND_OUTCTL(bld_base), 1258c2ecf20Sopenharmony_ci SUN8I_MIXER_BLEND_OUTCTL_INTERLACED, 1268c2ecf20Sopenharmony_ci val); 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci DRM_DEBUG_DRIVER("Switching display mixer interlaced mode %s\n", 1298c2ecf20Sopenharmony_ci interlaced ? "on" : "off"); 1308c2ecf20Sopenharmony_ci } 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci /* Set height and width */ 1338c2ecf20Sopenharmony_ci DRM_DEBUG_DRIVER("Layer source offset X: %d Y: %d\n", 1348c2ecf20Sopenharmony_ci state->src.x1 >> 16, state->src.y1 >> 16); 1358c2ecf20Sopenharmony_ci DRM_DEBUG_DRIVER("Layer source size W: %d H: %d\n", src_w, src_h); 1368c2ecf20Sopenharmony_ci regmap_write(mixer->engine.regs, 1378c2ecf20Sopenharmony_ci SUN8I_MIXER_CHAN_UI_LAYER_SIZE(ch_base, overlay), 1388c2ecf20Sopenharmony_ci insize); 1398c2ecf20Sopenharmony_ci regmap_write(mixer->engine.regs, 1408c2ecf20Sopenharmony_ci SUN8I_MIXER_CHAN_UI_OVL_SIZE(ch_base), 1418c2ecf20Sopenharmony_ci insize); 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci if (insize != outsize || hphase || vphase) { 1448c2ecf20Sopenharmony_ci u32 hscale, vscale; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci DRM_DEBUG_DRIVER("HW scaling is enabled\n"); 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci hscale = state->src_w / state->crtc_w; 1498c2ecf20Sopenharmony_ci vscale = state->src_h / state->crtc_h; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci sun8i_ui_scaler_setup(mixer, channel, src_w, src_h, dst_w, 1528c2ecf20Sopenharmony_ci dst_h, hscale, vscale, hphase, vphase); 1538c2ecf20Sopenharmony_ci sun8i_ui_scaler_enable(mixer, channel, true); 1548c2ecf20Sopenharmony_ci } else { 1558c2ecf20Sopenharmony_ci DRM_DEBUG_DRIVER("HW scaling is not needed\n"); 1568c2ecf20Sopenharmony_ci sun8i_ui_scaler_enable(mixer, channel, false); 1578c2ecf20Sopenharmony_ci } 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci /* Set base coordinates */ 1608c2ecf20Sopenharmony_ci DRM_DEBUG_DRIVER("Layer destination coordinates X: %d Y: %d\n", 1618c2ecf20Sopenharmony_ci state->dst.x1, state->dst.y1); 1628c2ecf20Sopenharmony_ci DRM_DEBUG_DRIVER("Layer destination size W: %d H: %d\n", dst_w, dst_h); 1638c2ecf20Sopenharmony_ci regmap_write(mixer->engine.regs, 1648c2ecf20Sopenharmony_ci SUN8I_MIXER_BLEND_ATTR_COORD(bld_base, zpos), 1658c2ecf20Sopenharmony_ci SUN8I_MIXER_COORD(state->dst.x1, state->dst.y1)); 1668c2ecf20Sopenharmony_ci regmap_write(mixer->engine.regs, 1678c2ecf20Sopenharmony_ci SUN8I_MIXER_BLEND_ATTR_INSIZE(bld_base, zpos), 1688c2ecf20Sopenharmony_ci outsize); 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci return 0; 1718c2ecf20Sopenharmony_ci} 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_cistatic int sun8i_ui_layer_update_formats(struct sun8i_mixer *mixer, int channel, 1748c2ecf20Sopenharmony_ci int overlay, struct drm_plane *plane) 1758c2ecf20Sopenharmony_ci{ 1768c2ecf20Sopenharmony_ci struct drm_plane_state *state = plane->state; 1778c2ecf20Sopenharmony_ci const struct drm_format_info *fmt; 1788c2ecf20Sopenharmony_ci u32 val, ch_base, hw_fmt; 1798c2ecf20Sopenharmony_ci int ret; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci ch_base = sun8i_channel_base(mixer, channel); 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci fmt = state->fb->format; 1848c2ecf20Sopenharmony_ci ret = sun8i_mixer_drm_format_to_hw(fmt->format, &hw_fmt); 1858c2ecf20Sopenharmony_ci if (ret || fmt->is_yuv) { 1868c2ecf20Sopenharmony_ci DRM_DEBUG_DRIVER("Invalid format\n"); 1878c2ecf20Sopenharmony_ci return -EINVAL; 1888c2ecf20Sopenharmony_ci } 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci val = hw_fmt << SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_OFFSET; 1918c2ecf20Sopenharmony_ci regmap_update_bits(mixer->engine.regs, 1928c2ecf20Sopenharmony_ci SUN8I_MIXER_CHAN_UI_LAYER_ATTR(ch_base, overlay), 1938c2ecf20Sopenharmony_ci SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_MASK, val); 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci return 0; 1968c2ecf20Sopenharmony_ci} 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_cistatic int sun8i_ui_layer_update_buffer(struct sun8i_mixer *mixer, int channel, 1998c2ecf20Sopenharmony_ci int overlay, struct drm_plane *plane) 2008c2ecf20Sopenharmony_ci{ 2018c2ecf20Sopenharmony_ci struct drm_plane_state *state = plane->state; 2028c2ecf20Sopenharmony_ci struct drm_framebuffer *fb = state->fb; 2038c2ecf20Sopenharmony_ci struct drm_gem_cma_object *gem; 2048c2ecf20Sopenharmony_ci dma_addr_t paddr; 2058c2ecf20Sopenharmony_ci u32 ch_base; 2068c2ecf20Sopenharmony_ci int bpp; 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci ch_base = sun8i_channel_base(mixer, channel); 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci /* Get the physical address of the buffer in memory */ 2118c2ecf20Sopenharmony_ci gem = drm_fb_cma_get_gem_obj(fb, 0); 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci DRM_DEBUG_DRIVER("Using GEM @ %pad\n", &gem->paddr); 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci /* Compute the start of the displayed memory */ 2168c2ecf20Sopenharmony_ci bpp = fb->format->cpp[0]; 2178c2ecf20Sopenharmony_ci paddr = gem->paddr + fb->offsets[0]; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci /* Fixup framebuffer address for src coordinates */ 2208c2ecf20Sopenharmony_ci paddr += (state->src.x1 >> 16) * bpp; 2218c2ecf20Sopenharmony_ci paddr += (state->src.y1 >> 16) * fb->pitches[0]; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci /* Set the line width */ 2248c2ecf20Sopenharmony_ci DRM_DEBUG_DRIVER("Layer line width: %d bytes\n", fb->pitches[0]); 2258c2ecf20Sopenharmony_ci regmap_write(mixer->engine.regs, 2268c2ecf20Sopenharmony_ci SUN8I_MIXER_CHAN_UI_LAYER_PITCH(ch_base, overlay), 2278c2ecf20Sopenharmony_ci fb->pitches[0]); 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci DRM_DEBUG_DRIVER("Setting buffer address to %pad\n", &paddr); 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci regmap_write(mixer->engine.regs, 2328c2ecf20Sopenharmony_ci SUN8I_MIXER_CHAN_UI_LAYER_TOP_LADDR(ch_base, overlay), 2338c2ecf20Sopenharmony_ci lower_32_bits(paddr)); 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci return 0; 2368c2ecf20Sopenharmony_ci} 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_cistatic int sun8i_ui_layer_atomic_check(struct drm_plane *plane, 2398c2ecf20Sopenharmony_ci struct drm_plane_state *state) 2408c2ecf20Sopenharmony_ci{ 2418c2ecf20Sopenharmony_ci struct sun8i_ui_layer *layer = plane_to_sun8i_ui_layer(plane); 2428c2ecf20Sopenharmony_ci struct drm_crtc *crtc = state->crtc; 2438c2ecf20Sopenharmony_ci struct drm_crtc_state *crtc_state; 2448c2ecf20Sopenharmony_ci int min_scale, max_scale; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci if (!crtc) 2478c2ecf20Sopenharmony_ci return 0; 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci crtc_state = drm_atomic_get_existing_crtc_state(state->state, crtc); 2508c2ecf20Sopenharmony_ci if (WARN_ON(!crtc_state)) 2518c2ecf20Sopenharmony_ci return -EINVAL; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci min_scale = DRM_PLANE_HELPER_NO_SCALING; 2548c2ecf20Sopenharmony_ci max_scale = DRM_PLANE_HELPER_NO_SCALING; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci if (layer->mixer->cfg->scaler_mask & BIT(layer->channel)) { 2578c2ecf20Sopenharmony_ci min_scale = SUN8I_UI_SCALER_SCALE_MIN; 2588c2ecf20Sopenharmony_ci max_scale = SUN8I_UI_SCALER_SCALE_MAX; 2598c2ecf20Sopenharmony_ci } 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci return drm_atomic_helper_check_plane_state(state, crtc_state, 2628c2ecf20Sopenharmony_ci min_scale, max_scale, 2638c2ecf20Sopenharmony_ci true, true); 2648c2ecf20Sopenharmony_ci} 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_cistatic void sun8i_ui_layer_atomic_disable(struct drm_plane *plane, 2678c2ecf20Sopenharmony_ci struct drm_plane_state *old_state) 2688c2ecf20Sopenharmony_ci{ 2698c2ecf20Sopenharmony_ci struct sun8i_ui_layer *layer = plane_to_sun8i_ui_layer(plane); 2708c2ecf20Sopenharmony_ci unsigned int old_zpos = old_state->normalized_zpos; 2718c2ecf20Sopenharmony_ci struct sun8i_mixer *mixer = layer->mixer; 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci sun8i_ui_layer_enable(mixer, layer->channel, layer->overlay, false, 0, 2748c2ecf20Sopenharmony_ci old_zpos); 2758c2ecf20Sopenharmony_ci} 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_cistatic void sun8i_ui_layer_atomic_update(struct drm_plane *plane, 2788c2ecf20Sopenharmony_ci struct drm_plane_state *old_state) 2798c2ecf20Sopenharmony_ci{ 2808c2ecf20Sopenharmony_ci struct sun8i_ui_layer *layer = plane_to_sun8i_ui_layer(plane); 2818c2ecf20Sopenharmony_ci unsigned int zpos = plane->state->normalized_zpos; 2828c2ecf20Sopenharmony_ci unsigned int old_zpos = old_state->normalized_zpos; 2838c2ecf20Sopenharmony_ci struct sun8i_mixer *mixer = layer->mixer; 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci if (!plane->state->visible) { 2868c2ecf20Sopenharmony_ci sun8i_ui_layer_enable(mixer, layer->channel, 2878c2ecf20Sopenharmony_ci layer->overlay, false, 0, old_zpos); 2888c2ecf20Sopenharmony_ci return; 2898c2ecf20Sopenharmony_ci } 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci sun8i_ui_layer_update_coord(mixer, layer->channel, 2928c2ecf20Sopenharmony_ci layer->overlay, plane, zpos); 2938c2ecf20Sopenharmony_ci sun8i_ui_layer_update_formats(mixer, layer->channel, 2948c2ecf20Sopenharmony_ci layer->overlay, plane); 2958c2ecf20Sopenharmony_ci sun8i_ui_layer_update_buffer(mixer, layer->channel, 2968c2ecf20Sopenharmony_ci layer->overlay, plane); 2978c2ecf20Sopenharmony_ci sun8i_ui_layer_enable(mixer, layer->channel, layer->overlay, 2988c2ecf20Sopenharmony_ci true, zpos, old_zpos); 2998c2ecf20Sopenharmony_ci} 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_cistatic const struct drm_plane_helper_funcs sun8i_ui_layer_helper_funcs = { 3028c2ecf20Sopenharmony_ci .prepare_fb = drm_gem_fb_prepare_fb, 3038c2ecf20Sopenharmony_ci .atomic_check = sun8i_ui_layer_atomic_check, 3048c2ecf20Sopenharmony_ci .atomic_disable = sun8i_ui_layer_atomic_disable, 3058c2ecf20Sopenharmony_ci .atomic_update = sun8i_ui_layer_atomic_update, 3068c2ecf20Sopenharmony_ci}; 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_cistatic const struct drm_plane_funcs sun8i_ui_layer_funcs = { 3098c2ecf20Sopenharmony_ci .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, 3108c2ecf20Sopenharmony_ci .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, 3118c2ecf20Sopenharmony_ci .destroy = drm_plane_cleanup, 3128c2ecf20Sopenharmony_ci .disable_plane = drm_atomic_helper_disable_plane, 3138c2ecf20Sopenharmony_ci .reset = drm_atomic_helper_plane_reset, 3148c2ecf20Sopenharmony_ci .update_plane = drm_atomic_helper_update_plane, 3158c2ecf20Sopenharmony_ci}; 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_cistatic const u32 sun8i_ui_layer_formats[] = { 3188c2ecf20Sopenharmony_ci DRM_FORMAT_ABGR1555, 3198c2ecf20Sopenharmony_ci DRM_FORMAT_ABGR4444, 3208c2ecf20Sopenharmony_ci DRM_FORMAT_ABGR8888, 3218c2ecf20Sopenharmony_ci DRM_FORMAT_ARGB1555, 3228c2ecf20Sopenharmony_ci DRM_FORMAT_ARGB4444, 3238c2ecf20Sopenharmony_ci DRM_FORMAT_ARGB8888, 3248c2ecf20Sopenharmony_ci DRM_FORMAT_BGR565, 3258c2ecf20Sopenharmony_ci DRM_FORMAT_BGR888, 3268c2ecf20Sopenharmony_ci DRM_FORMAT_BGRA5551, 3278c2ecf20Sopenharmony_ci DRM_FORMAT_BGRA4444, 3288c2ecf20Sopenharmony_ci DRM_FORMAT_BGRA8888, 3298c2ecf20Sopenharmony_ci DRM_FORMAT_BGRX8888, 3308c2ecf20Sopenharmony_ci DRM_FORMAT_RGB565, 3318c2ecf20Sopenharmony_ci DRM_FORMAT_RGB888, 3328c2ecf20Sopenharmony_ci DRM_FORMAT_RGBA4444, 3338c2ecf20Sopenharmony_ci DRM_FORMAT_RGBA5551, 3348c2ecf20Sopenharmony_ci DRM_FORMAT_RGBA8888, 3358c2ecf20Sopenharmony_ci DRM_FORMAT_RGBX8888, 3368c2ecf20Sopenharmony_ci DRM_FORMAT_XBGR8888, 3378c2ecf20Sopenharmony_ci DRM_FORMAT_XRGB8888, 3388c2ecf20Sopenharmony_ci}; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_cistruct sun8i_ui_layer *sun8i_ui_layer_init_one(struct drm_device *drm, 3418c2ecf20Sopenharmony_ci struct sun8i_mixer *mixer, 3428c2ecf20Sopenharmony_ci int index) 3438c2ecf20Sopenharmony_ci{ 3448c2ecf20Sopenharmony_ci enum drm_plane_type type = DRM_PLANE_TYPE_OVERLAY; 3458c2ecf20Sopenharmony_ci int channel = mixer->cfg->vi_num + index; 3468c2ecf20Sopenharmony_ci struct sun8i_ui_layer *layer; 3478c2ecf20Sopenharmony_ci unsigned int plane_cnt; 3488c2ecf20Sopenharmony_ci int ret; 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci layer = devm_kzalloc(drm->dev, sizeof(*layer), GFP_KERNEL); 3518c2ecf20Sopenharmony_ci if (!layer) 3528c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci if (index == 0) 3558c2ecf20Sopenharmony_ci type = DRM_PLANE_TYPE_PRIMARY; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci /* possible crtcs are set later */ 3588c2ecf20Sopenharmony_ci ret = drm_universal_plane_init(drm, &layer->plane, 0, 3598c2ecf20Sopenharmony_ci &sun8i_ui_layer_funcs, 3608c2ecf20Sopenharmony_ci sun8i_ui_layer_formats, 3618c2ecf20Sopenharmony_ci ARRAY_SIZE(sun8i_ui_layer_formats), 3628c2ecf20Sopenharmony_ci NULL, type, NULL); 3638c2ecf20Sopenharmony_ci if (ret) { 3648c2ecf20Sopenharmony_ci dev_err(drm->dev, "Couldn't initialize layer\n"); 3658c2ecf20Sopenharmony_ci return ERR_PTR(ret); 3668c2ecf20Sopenharmony_ci } 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci plane_cnt = mixer->cfg->ui_num + mixer->cfg->vi_num; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci ret = drm_plane_create_zpos_property(&layer->plane, channel, 3718c2ecf20Sopenharmony_ci 0, plane_cnt - 1); 3728c2ecf20Sopenharmony_ci if (ret) { 3738c2ecf20Sopenharmony_ci dev_err(drm->dev, "Couldn't add zpos property\n"); 3748c2ecf20Sopenharmony_ci return ERR_PTR(ret); 3758c2ecf20Sopenharmony_ci } 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci drm_plane_helper_add(&layer->plane, &sun8i_ui_layer_helper_funcs); 3788c2ecf20Sopenharmony_ci layer->mixer = mixer; 3798c2ecf20Sopenharmony_ci layer->channel = channel; 3808c2ecf20Sopenharmony_ci layer->overlay = 0; 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci return layer; 3838c2ecf20Sopenharmony_ci} 384