263 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Copyright (C) 2015 Free Electrons4 * Copyright (C) 2015 NextThing Co5 *6 * Maxime Ripard <maxime.ripard@free-electrons.com>7 */8 9#include <drm/drm_atomic.h>10#include <drm/drm_atomic_helper.h>11#include <drm/drm_blend.h>12#include <drm/drm_gem_atomic_helper.h>13 14#include "sun4i_backend.h"15#include "sun4i_frontend.h"16#include "sun4i_layer.h"17#include "sunxi_engine.h"18 19static void sun4i_backend_layer_reset(struct drm_plane *plane)20{21 struct sun4i_layer_state *state;22 23 if (plane->state) {24 state = state_to_sun4i_layer_state(plane->state);25 26 __drm_atomic_helper_plane_destroy_state(&state->state);27 28 kfree(state);29 plane->state = NULL;30 }31 32 state = kzalloc(sizeof(*state), GFP_KERNEL);33 if (state)34 __drm_atomic_helper_plane_reset(plane, &state->state);35}36 37static struct drm_plane_state *38sun4i_backend_layer_duplicate_state(struct drm_plane *plane)39{40 struct sun4i_layer_state *orig = state_to_sun4i_layer_state(plane->state);41 struct sun4i_layer_state *copy;42 43 copy = kzalloc(sizeof(*copy), GFP_KERNEL);44 if (!copy)45 return NULL;46 47 __drm_atomic_helper_plane_duplicate_state(plane, ©->state);48 copy->uses_frontend = orig->uses_frontend;49 50 return ©->state;51}52 53static void sun4i_backend_layer_destroy_state(struct drm_plane *plane,54 struct drm_plane_state *state)55{56 struct sun4i_layer_state *s_state = state_to_sun4i_layer_state(state);57 58 __drm_atomic_helper_plane_destroy_state(state);59 60 kfree(s_state);61}62 63static void sun4i_backend_layer_atomic_disable(struct drm_plane *plane,64 struct drm_atomic_state *state)65{66 struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state,67 plane);68 struct sun4i_layer_state *layer_state = state_to_sun4i_layer_state(old_state);69 struct sun4i_layer *layer = plane_to_sun4i_layer(plane);70 struct sun4i_backend *backend = layer->backend;71 72 sun4i_backend_layer_enable(backend, layer->id, false);73 74 if (layer_state->uses_frontend) {75 unsigned long flags;76 77 spin_lock_irqsave(&backend->frontend_lock, flags);78 backend->frontend_teardown = true;79 spin_unlock_irqrestore(&backend->frontend_lock, flags);80 }81}82 83static void sun4i_backend_layer_atomic_update(struct drm_plane *plane,84 struct drm_atomic_state *state)85{86 struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,87 plane);88 struct sun4i_layer_state *layer_state = state_to_sun4i_layer_state(new_state);89 struct sun4i_layer *layer = plane_to_sun4i_layer(plane);90 struct sun4i_backend *backend = layer->backend;91 struct sun4i_frontend *frontend = backend->frontend;92 93 sun4i_backend_cleanup_layer(backend, layer->id);94 95 if (layer_state->uses_frontend) {96 sun4i_frontend_init(frontend);97 sun4i_frontend_update_coord(frontend, plane);98 sun4i_frontend_update_buffer(frontend, plane);99 sun4i_frontend_update_formats(frontend, plane,100 DRM_FORMAT_XRGB8888);101 sun4i_backend_update_layer_frontend(backend, layer->id,102 DRM_FORMAT_XRGB8888);103 sun4i_frontend_enable(frontend);104 } else {105 sun4i_backend_update_layer_formats(backend, layer->id, plane);106 sun4i_backend_update_layer_buffer(backend, layer->id, plane);107 }108 109 sun4i_backend_update_layer_coord(backend, layer->id, plane);110 sun4i_backend_update_layer_zpos(backend, layer->id, plane);111 sun4i_backend_layer_enable(backend, layer->id, true);112}113 114static bool sun4i_layer_format_mod_supported(struct drm_plane *plane,115 uint32_t format, uint64_t modifier)116{117 struct sun4i_layer *layer = plane_to_sun4i_layer(plane);118 119 if (IS_ERR_OR_NULL(layer->backend->frontend))120 return sun4i_backend_format_is_supported(format, modifier);121 122 return sun4i_backend_format_is_supported(format, modifier) ||123 sun4i_frontend_format_is_supported(format, modifier);124}125 126static const struct drm_plane_helper_funcs sun4i_backend_layer_helper_funcs = {127 .atomic_disable = sun4i_backend_layer_atomic_disable,128 .atomic_update = sun4i_backend_layer_atomic_update,129};130 131static const struct drm_plane_funcs sun4i_backend_layer_funcs = {132 .atomic_destroy_state = sun4i_backend_layer_destroy_state,133 .atomic_duplicate_state = sun4i_backend_layer_duplicate_state,134 .destroy = drm_plane_cleanup,135 .disable_plane = drm_atomic_helper_disable_plane,136 .reset = sun4i_backend_layer_reset,137 .update_plane = drm_atomic_helper_update_plane,138 .format_mod_supported = sun4i_layer_format_mod_supported,139};140 141static const uint32_t sun4i_layer_formats[] = {142 DRM_FORMAT_ARGB8888,143 DRM_FORMAT_ARGB4444,144 DRM_FORMAT_ARGB1555,145 DRM_FORMAT_BGRX8888,146 DRM_FORMAT_RGBA5551,147 DRM_FORMAT_RGBA4444,148 DRM_FORMAT_RGB888,149 DRM_FORMAT_RGB565,150 DRM_FORMAT_NV12,151 DRM_FORMAT_NV16,152 DRM_FORMAT_NV21,153 DRM_FORMAT_NV61,154 DRM_FORMAT_UYVY,155 DRM_FORMAT_VYUY,156 DRM_FORMAT_XRGB8888,157 DRM_FORMAT_YUV411,158 DRM_FORMAT_YUV420,159 DRM_FORMAT_YUV422,160 DRM_FORMAT_YUV444,161 DRM_FORMAT_YUYV,162 DRM_FORMAT_YVU411,163 DRM_FORMAT_YVU420,164 DRM_FORMAT_YVU422,165 DRM_FORMAT_YVU444,166 DRM_FORMAT_YVYU,167};168 169static const uint32_t sun4i_backend_layer_formats[] = {170 DRM_FORMAT_ARGB8888,171 DRM_FORMAT_ARGB4444,172 DRM_FORMAT_ARGB1555,173 DRM_FORMAT_RGBA5551,174 DRM_FORMAT_RGBA4444,175 DRM_FORMAT_RGB888,176 DRM_FORMAT_RGB565,177 DRM_FORMAT_UYVY,178 DRM_FORMAT_VYUY,179 DRM_FORMAT_XRGB8888,180 DRM_FORMAT_YUYV,181 DRM_FORMAT_YVYU,182};183 184static const uint64_t sun4i_layer_modifiers[] = {185 DRM_FORMAT_MOD_LINEAR,186 DRM_FORMAT_MOD_ALLWINNER_TILED,187 DRM_FORMAT_MOD_INVALID188};189 190static struct sun4i_layer *sun4i_layer_init_one(struct drm_device *drm,191 struct sun4i_backend *backend,192 enum drm_plane_type type,193 unsigned int id)194{195 const uint64_t *modifiers = sun4i_layer_modifiers;196 const uint32_t *formats = sun4i_layer_formats;197 unsigned int formats_len = ARRAY_SIZE(sun4i_layer_formats);198 struct sun4i_layer *layer;199 int ret;200 201 layer = devm_kzalloc(drm->dev, sizeof(*layer), GFP_KERNEL);202 if (!layer)203 return ERR_PTR(-ENOMEM);204 205 layer->id = id;206 layer->backend = backend;207 208 if (IS_ERR_OR_NULL(backend->frontend)) {209 formats = sun4i_backend_layer_formats;210 formats_len = ARRAY_SIZE(sun4i_backend_layer_formats);211 modifiers = NULL;212 }213 214 /* possible crtcs are set later */215 ret = drm_universal_plane_init(drm, &layer->plane, 0,216 &sun4i_backend_layer_funcs,217 formats, formats_len,218 modifiers, type, NULL);219 if (ret) {220 dev_err(drm->dev, "Couldn't initialize layer\n");221 return ERR_PTR(ret);222 }223 224 drm_plane_helper_add(&layer->plane,225 &sun4i_backend_layer_helper_funcs);226 227 drm_plane_create_alpha_property(&layer->plane);228 drm_plane_create_zpos_property(&layer->plane, layer->id,229 0, SUN4I_BACKEND_NUM_LAYERS - 1);230 231 return layer;232}233 234struct drm_plane **sun4i_layers_init(struct drm_device *drm,235 struct sunxi_engine *engine)236{237 struct drm_plane **planes;238 struct sun4i_backend *backend = engine_to_sun4i_backend(engine);239 int i;240 241 /* We need to have a sentinel at the need, hence the overallocation */242 planes = devm_kcalloc(drm->dev, SUN4I_BACKEND_NUM_LAYERS + 1,243 sizeof(*planes), GFP_KERNEL);244 if (!planes)245 return ERR_PTR(-ENOMEM);246 247 for (i = 0; i < SUN4I_BACKEND_NUM_LAYERS; i++) {248 enum drm_plane_type type = i ? DRM_PLANE_TYPE_OVERLAY : DRM_PLANE_TYPE_PRIMARY;249 struct sun4i_layer *layer;250 251 layer = sun4i_layer_init_one(drm, backend, type, i);252 if (IS_ERR(layer)) {253 dev_err(drm->dev, "Couldn't initialize %s plane\n",254 i ? "overlay" : "primary");255 return ERR_CAST(layer);256 }257 258 planes[i] = &layer->plane;259 }260 261 return planes;262}263