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