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 22 struct sun4i_plane_desc { 23 enum drm_plane_type type; 24 u8 pipe; 25 const uint32_t *formats; 26 uint32_t nformats; 27 }; 28 29 static int sun4i_backend_layer_atomic_check(struct drm_plane *plane, 30 struct drm_plane_state *state) 31 { 32 return 0; 33 } 34 35 static 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 45 static 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 58 static 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 64 static 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 73 static const uint32_t sun4i_backend_layer_formats_primary[] = { 74 DRM_FORMAT_ARGB8888, 75 DRM_FORMAT_RGB888, 76 DRM_FORMAT_RGB565, 77 DRM_FORMAT_XRGB8888, 78 }; 79 80 static const uint32_t sun4i_backend_layer_formats_overlay[] = { 81 DRM_FORMAT_ARGB8888, 82 DRM_FORMAT_ARGB4444, 83 DRM_FORMAT_ARGB1555, 84 DRM_FORMAT_RGBA5551, 85 DRM_FORMAT_RGBA4444, 86 DRM_FORMAT_RGB888, 87 DRM_FORMAT_RGB565, 88 DRM_FORMAT_XRGB8888, 89 }; 90 91 static const struct sun4i_plane_desc sun4i_backend_planes[] = { 92 { 93 .type = DRM_PLANE_TYPE_PRIMARY, 94 .pipe = 0, 95 .formats = sun4i_backend_layer_formats_primary, 96 .nformats = ARRAY_SIZE(sun4i_backend_layer_formats_primary), 97 }, 98 { 99 .type = DRM_PLANE_TYPE_OVERLAY, 100 .pipe = 1, 101 .formats = sun4i_backend_layer_formats_overlay, 102 .nformats = ARRAY_SIZE(sun4i_backend_layer_formats_overlay), 103 }, 104 }; 105 106 static struct sun4i_layer *sun4i_layer_init_one(struct drm_device *drm, 107 const struct sun4i_plane_desc *plane) 108 { 109 struct sun4i_drv *drv = drm->dev_private; 110 struct sun4i_layer *layer; 111 int ret; 112 113 layer = devm_kzalloc(drm->dev, sizeof(*layer), GFP_KERNEL); 114 if (!layer) 115 return ERR_PTR(-ENOMEM); 116 117 ret = drm_universal_plane_init(drm, &layer->plane, BIT(0), 118 &sun4i_backend_layer_funcs, 119 plane->formats, plane->nformats, 120 plane->type, NULL); 121 if (ret) { 122 dev_err(drm->dev, "Couldn't initialize layer\n"); 123 return ERR_PTR(ret); 124 } 125 126 drm_plane_helper_add(&layer->plane, 127 &sun4i_backend_layer_helper_funcs); 128 layer->drv = drv; 129 130 if (plane->type == DRM_PLANE_TYPE_PRIMARY) 131 drv->primary = &layer->plane; 132 133 return layer; 134 } 135 136 struct sun4i_layer **sun4i_layers_init(struct drm_device *drm) 137 { 138 struct sun4i_drv *drv = drm->dev_private; 139 struct sun4i_layer **layers; 140 int i; 141 142 layers = devm_kcalloc(drm->dev, ARRAY_SIZE(sun4i_backend_planes), 143 sizeof(**layers), GFP_KERNEL); 144 if (!layers) 145 return ERR_PTR(-ENOMEM); 146 147 /* 148 * The hardware is a bit unusual here. 149 * 150 * Even though it supports 4 layers, it does the composition 151 * in two separate steps. 152 * 153 * The first one is assigning a layer to one of its two 154 * pipes. If more that 1 layer is assigned to the same pipe, 155 * and if pixels overlaps, the pipe will take the pixel from 156 * the layer with the highest priority. 157 * 158 * The second step is the actual alpha blending, that takes 159 * the two pipes as input, and uses the eventual alpha 160 * component to do the transparency between the two. 161 * 162 * This two steps scenario makes us unable to guarantee a 163 * robust alpha blending between the 4 layers in all 164 * situations. So we just expose two layers, one per pipe. On 165 * SoCs that support it, sprites could fill the need for more 166 * layers. 167 */ 168 for (i = 0; i < ARRAY_SIZE(sun4i_backend_planes); i++) { 169 const struct sun4i_plane_desc *plane = &sun4i_backend_planes[i]; 170 struct sun4i_layer *layer = layers[i]; 171 172 layer = sun4i_layer_init_one(drm, plane); 173 if (IS_ERR(layer)) { 174 dev_err(drm->dev, "Couldn't initialize %s plane\n", 175 i ? "overlay" : "primary"); 176 return ERR_CAST(layer); 177 }; 178 179 DRM_DEBUG_DRIVER("Assigning %s plane to pipe %d\n", 180 i ? "overlay" : "primary", plane->pipe); 181 regmap_update_bits(drv->backend->regs, SUN4I_BACKEND_ATTCTL_REG0(i), 182 SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL_MASK, 183 SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL(plane->pipe)); 184 185 layer->id = i; 186 }; 187 188 return layers; 189 } 190