Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Copyright (C) 2015 Free Electrons
0004  * Copyright (C) 2015 NextThing Co
0005  *
0006  * Maxime Ripard <maxime.ripard@free-electrons.com>
0007  */
0008 
0009 #include <drm/drm_atomic.h>
0010 #include <drm/drm_atomic_helper.h>
0011 #include <drm/drm_blend.h>
0012 #include <drm/drm_gem_atomic_helper.h>
0013 #include <drm/drm_plane_helper.h>
0014 
0015 #include "sun4i_backend.h"
0016 #include "sun4i_frontend.h"
0017 #include "sun4i_layer.h"
0018 #include "sunxi_engine.h"
0019 
0020 static void sun4i_backend_layer_reset(struct drm_plane *plane)
0021 {
0022     struct sun4i_layer_state *state;
0023 
0024     if (plane->state) {
0025         state = state_to_sun4i_layer_state(plane->state);
0026 
0027         __drm_atomic_helper_plane_destroy_state(&state->state);
0028 
0029         kfree(state);
0030         plane->state = NULL;
0031     }
0032 
0033     state = kzalloc(sizeof(*state), GFP_KERNEL);
0034     if (state)
0035         __drm_atomic_helper_plane_reset(plane, &state->state);
0036 }
0037 
0038 static struct drm_plane_state *
0039 sun4i_backend_layer_duplicate_state(struct drm_plane *plane)
0040 {
0041     struct sun4i_layer_state *orig = state_to_sun4i_layer_state(plane->state);
0042     struct sun4i_layer_state *copy;
0043 
0044     copy = kzalloc(sizeof(*copy), GFP_KERNEL);
0045     if (!copy)
0046         return NULL;
0047 
0048     __drm_atomic_helper_plane_duplicate_state(plane, &copy->state);
0049     copy->uses_frontend = orig->uses_frontend;
0050 
0051     return &copy->state;
0052 }
0053 
0054 static void sun4i_backend_layer_destroy_state(struct drm_plane *plane,
0055                           struct drm_plane_state *state)
0056 {
0057     struct sun4i_layer_state *s_state = state_to_sun4i_layer_state(state);
0058 
0059     __drm_atomic_helper_plane_destroy_state(state);
0060 
0061     kfree(s_state);
0062 }
0063 
0064 static void sun4i_backend_layer_atomic_disable(struct drm_plane *plane,
0065                            struct drm_atomic_state *state)
0066 {
0067     struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state,
0068                                        plane);
0069     struct sun4i_layer_state *layer_state = state_to_sun4i_layer_state(old_state);
0070     struct sun4i_layer *layer = plane_to_sun4i_layer(plane);
0071     struct sun4i_backend *backend = layer->backend;
0072 
0073     sun4i_backend_layer_enable(backend, layer->id, false);
0074 
0075     if (layer_state->uses_frontend) {
0076         unsigned long flags;
0077 
0078         spin_lock_irqsave(&backend->frontend_lock, flags);
0079         backend->frontend_teardown = true;
0080         spin_unlock_irqrestore(&backend->frontend_lock, flags);
0081     }
0082 }
0083 
0084 static void sun4i_backend_layer_atomic_update(struct drm_plane *plane,
0085                           struct drm_atomic_state *state)
0086 {
0087     struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
0088                                        plane);
0089     struct sun4i_layer_state *layer_state = state_to_sun4i_layer_state(new_state);
0090     struct sun4i_layer *layer = plane_to_sun4i_layer(plane);
0091     struct sun4i_backend *backend = layer->backend;
0092     struct sun4i_frontend *frontend = backend->frontend;
0093 
0094     sun4i_backend_cleanup_layer(backend, layer->id);
0095 
0096     if (layer_state->uses_frontend) {
0097         sun4i_frontend_init(frontend);
0098         sun4i_frontend_update_coord(frontend, plane);
0099         sun4i_frontend_update_buffer(frontend, plane);
0100         sun4i_frontend_update_formats(frontend, plane,
0101                           DRM_FORMAT_XRGB8888);
0102         sun4i_backend_update_layer_frontend(backend, layer->id,
0103                             DRM_FORMAT_XRGB8888);
0104         sun4i_frontend_enable(frontend);
0105     } else {
0106         sun4i_backend_update_layer_formats(backend, layer->id, plane);
0107         sun4i_backend_update_layer_buffer(backend, layer->id, plane);
0108     }
0109 
0110     sun4i_backend_update_layer_coord(backend, layer->id, plane);
0111     sun4i_backend_update_layer_zpos(backend, layer->id, plane);
0112     sun4i_backend_layer_enable(backend, layer->id, true);
0113 }
0114 
0115 static bool sun4i_layer_format_mod_supported(struct drm_plane *plane,
0116                          uint32_t format, uint64_t modifier)
0117 {
0118     struct sun4i_layer *layer = plane_to_sun4i_layer(plane);
0119 
0120     if (IS_ERR_OR_NULL(layer->backend->frontend))
0121         return sun4i_backend_format_is_supported(format, modifier);
0122 
0123     return sun4i_backend_format_is_supported(format, modifier) ||
0124            sun4i_frontend_format_is_supported(format, modifier);
0125 }
0126 
0127 static const struct drm_plane_helper_funcs sun4i_backend_layer_helper_funcs = {
0128     .atomic_disable = sun4i_backend_layer_atomic_disable,
0129     .atomic_update  = sun4i_backend_layer_atomic_update,
0130 };
0131 
0132 static const struct drm_plane_funcs sun4i_backend_layer_funcs = {
0133     .atomic_destroy_state   = sun4i_backend_layer_destroy_state,
0134     .atomic_duplicate_state = sun4i_backend_layer_duplicate_state,
0135     .destroy        = drm_plane_cleanup,
0136     .disable_plane      = drm_atomic_helper_disable_plane,
0137     .reset          = sun4i_backend_layer_reset,
0138     .update_plane       = drm_atomic_helper_update_plane,
0139     .format_mod_supported   = sun4i_layer_format_mod_supported,
0140 };
0141 
0142 static const uint32_t sun4i_layer_formats[] = {
0143     DRM_FORMAT_ARGB8888,
0144     DRM_FORMAT_ARGB4444,
0145     DRM_FORMAT_ARGB1555,
0146     DRM_FORMAT_BGRX8888,
0147     DRM_FORMAT_RGBA5551,
0148     DRM_FORMAT_RGBA4444,
0149     DRM_FORMAT_RGB888,
0150     DRM_FORMAT_RGB565,
0151     DRM_FORMAT_NV12,
0152     DRM_FORMAT_NV16,
0153     DRM_FORMAT_NV21,
0154     DRM_FORMAT_NV61,
0155     DRM_FORMAT_UYVY,
0156     DRM_FORMAT_VYUY,
0157     DRM_FORMAT_XRGB8888,
0158     DRM_FORMAT_YUV411,
0159     DRM_FORMAT_YUV420,
0160     DRM_FORMAT_YUV422,
0161     DRM_FORMAT_YUV444,
0162     DRM_FORMAT_YUYV,
0163     DRM_FORMAT_YVU411,
0164     DRM_FORMAT_YVU420,
0165     DRM_FORMAT_YVU422,
0166     DRM_FORMAT_YVU444,
0167     DRM_FORMAT_YVYU,
0168 };
0169 
0170 static const uint32_t sun4i_backend_layer_formats[] = {
0171     DRM_FORMAT_ARGB8888,
0172     DRM_FORMAT_ARGB4444,
0173     DRM_FORMAT_ARGB1555,
0174     DRM_FORMAT_RGBA5551,
0175     DRM_FORMAT_RGBA4444,
0176     DRM_FORMAT_RGB888,
0177     DRM_FORMAT_RGB565,
0178     DRM_FORMAT_UYVY,
0179     DRM_FORMAT_VYUY,
0180     DRM_FORMAT_XRGB8888,
0181     DRM_FORMAT_YUYV,
0182     DRM_FORMAT_YVYU,
0183 };
0184 
0185 static const uint64_t sun4i_layer_modifiers[] = {
0186     DRM_FORMAT_MOD_LINEAR,
0187     DRM_FORMAT_MOD_ALLWINNER_TILED,
0188     DRM_FORMAT_MOD_INVALID
0189 };
0190 
0191 static struct sun4i_layer *sun4i_layer_init_one(struct drm_device *drm,
0192                         struct sun4i_backend *backend,
0193                         enum drm_plane_type type,
0194                         unsigned int id)
0195 {
0196     const uint64_t *modifiers = sun4i_layer_modifiers;
0197     const uint32_t *formats = sun4i_layer_formats;
0198     unsigned int formats_len = ARRAY_SIZE(sun4i_layer_formats);
0199     struct sun4i_layer *layer;
0200     int ret;
0201 
0202     layer = devm_kzalloc(drm->dev, sizeof(*layer), GFP_KERNEL);
0203     if (!layer)
0204         return ERR_PTR(-ENOMEM);
0205 
0206     layer->id = id;
0207     layer->backend = backend;
0208 
0209     if (IS_ERR_OR_NULL(backend->frontend)) {
0210         formats = sun4i_backend_layer_formats;
0211         formats_len = ARRAY_SIZE(sun4i_backend_layer_formats);
0212         modifiers = NULL;
0213     }
0214 
0215     /* possible crtcs are set later */
0216     ret = drm_universal_plane_init(drm, &layer->plane, 0,
0217                        &sun4i_backend_layer_funcs,
0218                        formats, formats_len,
0219                        modifiers, type, NULL);
0220     if (ret) {
0221         dev_err(drm->dev, "Couldn't initialize layer\n");
0222         return ERR_PTR(ret);
0223     }
0224 
0225     drm_plane_helper_add(&layer->plane,
0226                  &sun4i_backend_layer_helper_funcs);
0227 
0228     drm_plane_create_alpha_property(&layer->plane);
0229     drm_plane_create_zpos_property(&layer->plane, layer->id,
0230                        0, SUN4I_BACKEND_NUM_LAYERS - 1);
0231 
0232     return layer;
0233 }
0234 
0235 struct drm_plane **sun4i_layers_init(struct drm_device *drm,
0236                      struct sunxi_engine *engine)
0237 {
0238     struct drm_plane **planes;
0239     struct sun4i_backend *backend = engine_to_sun4i_backend(engine);
0240     int i;
0241 
0242     /* We need to have a sentinel at the need, hence the overallocation */
0243     planes = devm_kcalloc(drm->dev, SUN4I_BACKEND_NUM_LAYERS + 1,
0244                   sizeof(*planes), GFP_KERNEL);
0245     if (!planes)
0246         return ERR_PTR(-ENOMEM);
0247 
0248     for (i = 0; i < SUN4I_BACKEND_NUM_LAYERS; i++) {
0249         enum drm_plane_type type = i ? DRM_PLANE_TYPE_OVERLAY : DRM_PLANE_TYPE_PRIMARY;
0250         struct sun4i_layer *layer;
0251 
0252         layer = sun4i_layer_init_one(drm, backend, type, i);
0253         if (IS_ERR(layer)) {
0254             dev_err(drm->dev, "Couldn't initialize %s plane\n",
0255                 i ? "overlay" : "primary");
0256             return ERR_CAST(layer);
0257         }
0258 
0259         planes[i] = &layer->plane;
0260     }
0261 
0262     return planes;
0263 }