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_XRGB8888, 77 }; 78 79 static const uint32_t sun4i_backend_layer_formats_overlay[] = { 80 DRM_FORMAT_ARGB8888, 81 DRM_FORMAT_RGB888, 82 DRM_FORMAT_XRGB8888, 83 }; 84 85 static 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 100 static 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 130 struct 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