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_crtc.h>
  15#include <drm/drm_plane_helper.h>
  16#include <drm/drmP.h>
  17
  18#include "sun4i_backend.h"
  19#include "sun4i_drv.h"
  20#include "sun4i_layer.h"
  21
  22struct sun4i_plane_desc {
  23               enum drm_plane_type     type;
  24               u8                      pipe;
  25               const uint32_t          *formats;
  26               uint32_t                nformats;
  27};
  28
  29static int sun4i_backend_layer_atomic_check(struct drm_plane *plane,
  30                                            struct drm_plane_state *state)
  31{
  32        return 0;
  33}
  34
  35static void sun4i_backend_layer_atomic_disable(struct drm_plane *plane,
  36                                               struct drm_plane_state *old_state)
  37{
  38        struct sun4i_layer *layer = plane_to_sun4i_layer(plane);
  39        struct sun4i_drv *drv = layer->drv;
  40        struct sun4i_backend *backend = drv->backend;
  41
  42        sun4i_backend_layer_enable(backend, layer->id, false);
  43}
  44
  45static void sun4i_backend_layer_atomic_update(struct drm_plane *plane,
  46                                              struct drm_plane_state *old_state)
  47{
  48        struct sun4i_layer *layer = plane_to_sun4i_layer(plane);
  49        struct sun4i_drv *drv = layer->drv;
  50        struct sun4i_backend *backend = drv->backend;
  51
  52        sun4i_backend_update_layer_coord(backend, layer->id, plane);
  53        sun4i_backend_update_layer_formats(backend, layer->id, plane);
  54        sun4i_backend_update_layer_buffer(backend, layer->id, plane);
  55        sun4i_backend_layer_enable(backend, layer->id, true);
  56}
  57
  58static struct drm_plane_helper_funcs sun4i_backend_layer_helper_funcs = {
  59        .atomic_check   = sun4i_backend_layer_atomic_check,
  60        .atomic_disable = sun4i_backend_layer_atomic_disable,
  61        .atomic_update  = sun4i_backend_layer_atomic_update,
  62};
  63
  64static const struct drm_plane_funcs sun4i_backend_layer_funcs = {
  65        .atomic_destroy_state   = drm_atomic_helper_plane_destroy_state,
  66        .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
  67        .destroy                = drm_plane_cleanup,
  68        .disable_plane          = drm_atomic_helper_disable_plane,
  69        .reset                  = drm_atomic_helper_plane_reset,
  70        .update_plane           = drm_atomic_helper_update_plane,
  71};
  72
  73static const uint32_t sun4i_backend_layer_formats_primary[] = {
  74        DRM_FORMAT_ARGB8888,
  75        DRM_FORMAT_RGB888,
  76        DRM_FORMAT_XRGB8888,
  77};
  78
  79static const uint32_t sun4i_backend_layer_formats_overlay[] = {
  80        DRM_FORMAT_ARGB8888,
  81        DRM_FORMAT_RGB888,
  82        DRM_FORMAT_XRGB8888,
  83};
  84
  85static const struct sun4i_plane_desc sun4i_backend_planes[] = {
  86        {
  87                .type = DRM_PLANE_TYPE_PRIMARY,
  88                .pipe = 0,
  89                .formats = sun4i_backend_layer_formats_primary,
  90                .nformats = ARRAY_SIZE(sun4i_backend_layer_formats_primary),
  91        },
  92        {
  93                .type = DRM_PLANE_TYPE_OVERLAY,
  94                .pipe = 1,
  95                .formats = sun4i_backend_layer_formats_overlay,
  96                .nformats = ARRAY_SIZE(sun4i_backend_layer_formats_overlay),
  97        },
  98};
  99
 100static struct sun4i_layer *sun4i_layer_init_one(struct drm_device *drm,
 101                                                const struct sun4i_plane_desc *plane)
 102{
 103        struct sun4i_drv *drv = drm->dev_private;
 104        struct sun4i_layer *layer;
 105        int ret;
 106
 107        layer = devm_kzalloc(drm->dev, sizeof(*layer), GFP_KERNEL);
 108        if (!layer)
 109                return ERR_PTR(-ENOMEM);
 110
 111        ret = drm_universal_plane_init(drm, &layer->plane, BIT(0),
 112                                       &sun4i_backend_layer_funcs,
 113                                       plane->formats, plane->nformats,
 114                                       plane->type, NULL);
 115        if (ret) {
 116                dev_err(drm->dev, "Couldn't initialize layer\n");
 117                return ERR_PTR(ret);
 118        }
 119
 120        drm_plane_helper_add(&layer->plane,
 121                             &sun4i_backend_layer_helper_funcs);
 122        layer->drv = drv;
 123
 124        if (plane->type == DRM_PLANE_TYPE_PRIMARY)
 125                drv->primary = &layer->plane;
 126
 127        return layer;
 128}
 129
 130struct sun4i_layer **sun4i_layers_init(struct drm_device *drm)
 131{
 132        struct sun4i_drv *drv = drm->dev_private;
 133        struct sun4i_layer **layers;
 134        int i;
 135
 136        layers = devm_kcalloc(drm->dev, ARRAY_SIZE(sun4i_backend_planes),
 137                              sizeof(**layers), GFP_KERNEL);
 138        if (!layers)
 139                return ERR_PTR(-ENOMEM);
 140
 141        /*
 142         * The hardware is a bit unusual here.
 143         *
 144         * Even though it supports 4 layers, it does the composition
 145         * in two separate steps.
 146         *
 147         * The first one is assigning a layer to one of its two
 148         * pipes. If more that 1 layer is assigned to the same pipe,
 149         * and if pixels overlaps, the pipe will take the pixel from
 150         * the layer with the highest priority.
 151         *
 152         * The second step is the actual alpha blending, that takes
 153         * the two pipes as input, and uses the eventual alpha
 154         * component to do the transparency between the two.
 155         *
 156         * This two steps scenario makes us unable to guarantee a
 157         * robust alpha blending between the 4 layers in all
 158         * situations. So we just expose two layers, one per pipe. On
 159         * SoCs that support it, sprites could fill the need for more
 160         * layers.
 161         */
 162        for (i = 0; i < ARRAY_SIZE(sun4i_backend_planes); i++) {
 163                const struct sun4i_plane_desc *plane = &sun4i_backend_planes[i];
 164                struct sun4i_layer *layer = layers[i];
 165
 166                layer = sun4i_layer_init_one(drm, plane);
 167                if (IS_ERR(layer)) {
 168                        dev_err(drm->dev, "Couldn't initialize %s plane\n",
 169                                i ? "overlay" : "primary");
 170                        return ERR_CAST(layer);
 171                };
 172
 173                DRM_DEBUG_DRIVER("Assigning %s plane to pipe %d\n",
 174                                 i ? "overlay" : "primary", plane->pipe);
 175                regmap_update_bits(drv->backend->regs, SUN4I_BACKEND_ATTCTL_REG0(i),
 176                                   SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL_MASK,
 177                                   SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL(plane->pipe));
 178
 179                layer->id = i;
 180        };
 181
 182        return layers;
 183}
 184