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