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