linux/drivers/gpu/drm/sun4i/sun4i_layer.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2015 Free Electrons
   3 * Copyright (C) 2015 NextThing Co
   4 *
   5 * Maxime Ripard <maxime.ripard@free-electrons.com>
   6 *
   7 * This program is free software; you can redistribute it and/or
   8 * modify it under the terms of the GNU General Public License as
   9 * published by the Free Software Foundation; either version 2 of
  10 * the License, or (at your option) any later version.
  11 */
  12
  13#include <drm/drm_atomic_helper.h>
  14#include <drm/drm_plane_helper.h>
  15#include <drm/drmP.h>
  16
  17#include "sun4i_backend.h"
  18#include "sun4i_frontend.h"
  19#include "sun4i_layer.h"
  20#include "sunxi_engine.h"
  21
  22static void sun4i_backend_layer_reset(struct drm_plane *plane)
  23{
  24        struct sun4i_layer *layer = plane_to_sun4i_layer(plane);
  25        struct sun4i_layer_state *state;
  26
  27        if (plane->state) {
  28                state = state_to_sun4i_layer_state(plane->state);
  29
  30                __drm_atomic_helper_plane_destroy_state(&state->state);
  31
  32                kfree(state);
  33                plane->state = NULL;
  34        }
  35
  36        state = kzalloc(sizeof(*state), GFP_KERNEL);
  37        if (state) {
  38                plane->state = &state->state;
  39                plane->state->plane = plane;
  40                plane->state->alpha = DRM_BLEND_ALPHA_OPAQUE;
  41                plane->state->zpos = layer->id;
  42        }
  43}
  44
  45static struct drm_plane_state *
  46sun4i_backend_layer_duplicate_state(struct drm_plane *plane)
  47{
  48        struct sun4i_layer_state *orig = state_to_sun4i_layer_state(plane->state);
  49        struct sun4i_layer_state *copy;
  50
  51        copy = kzalloc(sizeof(*copy), GFP_KERNEL);
  52        if (!copy)
  53                return NULL;
  54
  55        __drm_atomic_helper_plane_duplicate_state(plane, &copy->state);
  56        copy->uses_frontend = orig->uses_frontend;
  57
  58        return &copy->state;
  59}
  60
  61static void sun4i_backend_layer_destroy_state(struct drm_plane *plane,
  62                                              struct drm_plane_state *state)
  63{
  64        struct sun4i_layer_state *s_state = state_to_sun4i_layer_state(state);
  65
  66        __drm_atomic_helper_plane_destroy_state(state);
  67
  68        kfree(s_state);
  69}
  70
  71static void sun4i_backend_layer_atomic_disable(struct drm_plane *plane,
  72                                               struct drm_plane_state *old_state)
  73{
  74        struct sun4i_layer_state *layer_state = state_to_sun4i_layer_state(old_state);
  75        struct sun4i_layer *layer = plane_to_sun4i_layer(plane);
  76        struct sun4i_backend *backend = layer->backend;
  77
  78        sun4i_backend_layer_enable(backend, layer->id, false);
  79
  80        if (layer_state->uses_frontend) {
  81                unsigned long flags;
  82
  83                spin_lock_irqsave(&backend->frontend_lock, flags);
  84                backend->frontend_teardown = true;
  85                spin_unlock_irqrestore(&backend->frontend_lock, flags);
  86        }
  87}
  88
  89static void sun4i_backend_layer_atomic_update(struct drm_plane *plane,
  90                                              struct drm_plane_state *old_state)
  91{
  92        struct sun4i_layer_state *layer_state = state_to_sun4i_layer_state(plane->state);
  93        struct sun4i_layer *layer = plane_to_sun4i_layer(plane);
  94        struct sun4i_backend *backend = layer->backend;
  95        struct sun4i_frontend *frontend = backend->frontend;
  96
  97        if (layer_state->uses_frontend) {
  98                sun4i_frontend_init(frontend);
  99                sun4i_frontend_update_coord(frontend, plane);
 100                sun4i_frontend_update_buffer(frontend, plane);
 101                sun4i_frontend_update_formats(frontend, plane,
 102                                              DRM_FORMAT_ARGB8888);
 103                sun4i_backend_update_layer_frontend(backend, layer->id,
 104                                                    DRM_FORMAT_ARGB8888);
 105                sun4i_frontend_enable(frontend);
 106        } else {
 107                sun4i_backend_update_layer_formats(backend, layer->id, plane);
 108                sun4i_backend_update_layer_buffer(backend, layer->id, plane);
 109        }
 110
 111        sun4i_backend_update_layer_coord(backend, layer->id, plane);
 112        sun4i_backend_update_layer_zpos(backend, layer->id, plane);
 113        sun4i_backend_layer_enable(backend, layer->id, true);
 114}
 115
 116static const struct drm_plane_helper_funcs sun4i_backend_layer_helper_funcs = {
 117        .atomic_disable = sun4i_backend_layer_atomic_disable,
 118        .atomic_update  = sun4i_backend_layer_atomic_update,
 119};
 120
 121static const struct drm_plane_funcs sun4i_backend_layer_funcs = {
 122        .atomic_destroy_state   = sun4i_backend_layer_destroy_state,
 123        .atomic_duplicate_state = sun4i_backend_layer_duplicate_state,
 124        .destroy                = drm_plane_cleanup,
 125        .disable_plane          = drm_atomic_helper_disable_plane,
 126        .reset                  = sun4i_backend_layer_reset,
 127        .update_plane           = drm_atomic_helper_update_plane,
 128};
 129
 130static const uint32_t sun4i_backend_layer_formats[] = {
 131        DRM_FORMAT_ARGB8888,
 132        DRM_FORMAT_ARGB4444,
 133        DRM_FORMAT_ARGB1555,
 134        DRM_FORMAT_RGBA5551,
 135        DRM_FORMAT_RGBA4444,
 136        DRM_FORMAT_RGB888,
 137        DRM_FORMAT_RGB565,
 138        DRM_FORMAT_UYVY,
 139        DRM_FORMAT_VYUY,
 140        DRM_FORMAT_XRGB8888,
 141        DRM_FORMAT_YUYV,
 142        DRM_FORMAT_YVYU,
 143};
 144
 145static struct sun4i_layer *sun4i_layer_init_one(struct drm_device *drm,
 146                                                struct sun4i_backend *backend,
 147                                                enum drm_plane_type type)
 148{
 149        struct sun4i_layer *layer;
 150        int ret;
 151
 152        layer = devm_kzalloc(drm->dev, sizeof(*layer), GFP_KERNEL);
 153        if (!layer)
 154                return ERR_PTR(-ENOMEM);
 155
 156        /* possible crtcs are set later */
 157        ret = drm_universal_plane_init(drm, &layer->plane, 0,
 158                                       &sun4i_backend_layer_funcs,
 159                                       sun4i_backend_layer_formats,
 160                                       ARRAY_SIZE(sun4i_backend_layer_formats),
 161                                       NULL, type, NULL);
 162        if (ret) {
 163                dev_err(drm->dev, "Couldn't initialize layer\n");
 164                return ERR_PTR(ret);
 165        }
 166
 167        drm_plane_helper_add(&layer->plane,
 168                             &sun4i_backend_layer_helper_funcs);
 169        layer->backend = backend;
 170
 171        drm_plane_create_alpha_property(&layer->plane);
 172        drm_plane_create_zpos_property(&layer->plane, 0, 0,
 173                                       SUN4I_BACKEND_NUM_LAYERS - 1);
 174
 175        return layer;
 176}
 177
 178struct drm_plane **sun4i_layers_init(struct drm_device *drm,
 179                                     struct sunxi_engine *engine)
 180{
 181        struct drm_plane **planes;
 182        struct sun4i_backend *backend = engine_to_sun4i_backend(engine);
 183        int i;
 184
 185        /* We need to have a sentinel at the need, hence the overallocation */
 186        planes = devm_kcalloc(drm->dev, SUN4I_BACKEND_NUM_LAYERS + 1,
 187                              sizeof(*planes), GFP_KERNEL);
 188        if (!planes)
 189                return ERR_PTR(-ENOMEM);
 190
 191        for (i = 0; i < SUN4I_BACKEND_NUM_LAYERS; i++) {
 192                enum drm_plane_type type = i ? DRM_PLANE_TYPE_OVERLAY : DRM_PLANE_TYPE_PRIMARY;
 193                struct sun4i_layer *layer;
 194
 195                layer = sun4i_layer_init_one(drm, backend, type);
 196                if (IS_ERR(layer)) {
 197                        dev_err(drm->dev, "Couldn't initialize %s plane\n",
 198                                i ? "overlay" : "primary");
 199                        return ERR_CAST(layer);
 200                };
 201
 202                layer->id = i;
 203                planes[i] = &layer->plane;
 204        };
 205
 206        return planes;
 207}
 208