]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blame - drivers/gpu/drm/omapdrm/omap_plane.c
drm: omapdrm: Drop manual framebuffer pin handling
[mirror_ubuntu-artful-kernel.git] / drivers / gpu / drm / omapdrm / omap_plane.c
CommitLineData
bb5c2d9a 1/*
8bb0daff 2 * drivers/gpu/drm/omapdrm/omap_plane.c
bb5c2d9a
RC
3 *
4 * Copyright (C) 2011 Texas Instruments
5 * Author: Rob Clark <rob.clark@linaro.org>
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License version 2 as published by
9 * the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * more details.
15 *
16 * You should have received a copy of the GNU General Public License along with
17 * this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
69a12263 20#include <drm/drm_atomic_helper.h>
de8e4100 21#include <drm/drm_plane_helper.h>
69a12263 22
3c810c61 23#include "omap_dmm_tiler.h"
2d278f54 24#include "omap_drv.h"
bb5c2d9a
RC
25
26/* some hackery because omapdss has an 'enum omap_plane' (which would be
27 * better named omap_plane_id).. and compiler seems unhappy about having
28 * both a 'struct omap_plane' and 'enum omap_plane'
29 */
30#define omap_plane _omap_plane
31
32/*
33 * plane funcs
34 */
35
36#define to_omap_plane(x) container_of(x, struct omap_plane, base)
37
38struct omap_plane {
39 struct drm_plane base;
f5f9454c
RC
40 int id; /* TODO rename omap_plane -> omap_plane_id in omapdss so I can use the enum */
41 const char *name;
bb5c2d9a
RC
42 struct omap_overlay_info info;
43
3c810c61
RC
44 /* position/orientation of scanout within the fb: */
45 struct omap_drm_window win;
f5f9454c 46 bool enabled;
9a0774e0 47
a890e662
RC
48 uint32_t nformats;
49 uint32_t formats[32];
b33f34d3 50
f5f9454c 51 struct omap_drm_irq error_irq;
a890e662 52};
bb5c2d9a 53
de8e4100
LP
54static int __omap_plane_setup(struct omap_plane *omap_plane,
55 struct drm_crtc *crtc,
56 struct drm_framebuffer *fb)
bb5c2d9a 57{
a42133a7 58 struct omap_overlay_info *info = &omap_plane->info;
de8e4100 59 struct drm_device *dev = omap_plane->base.dev;
9a0774e0 60 int ret;
bb5c2d9a 61
a42133a7 62 DBG("%s, enabled=%d", omap_plane->name, omap_plane->enabled);
f5f9454c 63
a42133a7 64 if (!omap_plane->enabled) {
f5f9454c 65 dispc_ovl_enable(omap_plane->id, false);
de8e4100 66 return 0;
9a0774e0 67 }
bb5c2d9a 68
f5f9454c 69 /* update scanout: */
de8e4100 70 omap_framebuffer_update_scanout(fb, &omap_plane->win, info);
bb5c2d9a 71
f5f9454c
RC
72 DBG("%dx%d -> %dx%d (%d)", info->width, info->height,
73 info->out_width, info->out_height,
9a0774e0 74 info->screen_width);
2d31ca3a
RK
75 DBG("%d,%d %pad %pad", info->pos_x, info->pos_y,
76 &info->paddr, &info->p_uv_addr);
f5f9454c 77
a42133a7
LP
78 dispc_ovl_set_channel_out(omap_plane->id,
79 omap_crtc_channel(crtc));
2dd3887b 80
f5f9454c 81 /* and finally, update omapdss: */
9c660b7c
LP
82 ret = dispc_ovl_setup(omap_plane->id, info, false,
83 omap_crtc_timings(crtc), false);
f5f9454c
RC
84 if (ret) {
85 dev_err(dev->dev, "dispc_ovl_setup failed: %d\n", ret);
de8e4100 86 return ret;
f5f9454c
RC
87 }
88
89 dispc_ovl_enable(omap_plane->id, true);
f5f9454c 90
de8e4100
LP
91 return 0;
92}
93
94static int omap_plane_setup(struct omap_plane *omap_plane)
95{
96 struct drm_plane *plane = &omap_plane->base;
97 int ret;
98
de8e4100
LP
99 dispc_runtime_get();
100 ret = __omap_plane_setup(omap_plane, plane->crtc, plane->fb);
a42133a7 101 dispc_runtime_put();
de8e4100 102
a42133a7 103 return ret;
bb5c2d9a
RC
104}
105
a42133a7
LP
106int omap_plane_set_enable(struct drm_plane *plane, bool enable)
107{
108 struct omap_plane *omap_plane = to_omap_plane(plane);
109
110 if (enable == omap_plane->enabled)
111 return 0;
f5f9454c 112
a42133a7
LP
113 omap_plane->enabled = enable;
114 return omap_plane_setup(omap_plane);
bb5c2d9a
RC
115}
116
de8e4100
LP
117static int omap_plane_prepare_fb(struct drm_plane *plane,
118 struct drm_framebuffer *fb,
119 const struct drm_plane_state *new_state)
120{
121 return omap_framebuffer_pin(fb);
122}
123
124static void omap_plane_cleanup_fb(struct drm_plane *plane,
125 struct drm_framebuffer *fb,
126 const struct drm_plane_state *old_state)
127{
128 omap_framebuffer_unpin(fb);
129}
130
131static void omap_plane_atomic_update(struct drm_plane *plane,
132 struct drm_plane_state *old_state)
2f53700d 133{
f5f9454c 134 struct omap_plane *omap_plane = to_omap_plane(plane);
de8e4100
LP
135 struct omap_drm_window *win = &omap_plane->win;
136 struct drm_plane_state *state = plane->state;
137 uint32_t src_w;
138 uint32_t src_h;
a42133a7 139
de8e4100
LP
140 if (!state->fb || !state->crtc)
141 return;
b03e14fd 142
de8e4100 143 /* omap_framebuffer_update_scanout() takes adjusted src */
d4586604
GI
144 switch (omap_plane->win.rotation & 0xf) {
145 case BIT(DRM_ROTATE_90):
146 case BIT(DRM_ROTATE_270):
de8e4100
LP
147 src_w = state->src_h;
148 src_h = state->src_w;
149 break;
150 default:
151 src_w = state->src_w;
152 src_h = state->src_h;
d4586604
GI
153 break;
154 }
155
de8e4100
LP
156 /* src values are in Q16 fixed point, convert to integer. */
157 win->crtc_x = state->crtc_x;
158 win->crtc_y = state->crtc_y;
159 win->crtc_w = state->crtc_w;
160 win->crtc_h = state->crtc_h;
a42133a7 161
de8e4100
LP
162 win->src_x = state->src_x >> 16;
163 win->src_y = state->src_y >> 16;
164 win->src_w = src_w >> 16;
165 win->src_h = src_h >> 16;
166
167 omap_plane->enabled = true;
168 __omap_plane_setup(omap_plane, state->crtc, state->fb);
2f53700d
RC
169}
170
de8e4100
LP
171static void omap_plane_atomic_disable(struct drm_plane *plane,
172 struct drm_plane_state *old_state)
bb5c2d9a 173{
3c810c61 174 struct omap_plane *omap_plane = to_omap_plane(plane);
2debab97 175
3c810c61 176 omap_plane->win.rotation = BIT(DRM_ROTATE_0);
82e58855
LP
177 omap_plane->info.zorder = plane->type == DRM_PLANE_TYPE_PRIMARY
178 ? 0 : omap_plane->id;
179
a42133a7 180 if (!omap_plane->enabled)
de8e4100 181 return;
a42133a7 182
a42133a7 183 omap_plane->enabled = false;
de8e4100 184 __omap_plane_setup(omap_plane, NULL, NULL);
bb5c2d9a
RC
185}
186
de8e4100
LP
187static const struct drm_plane_helper_funcs omap_plane_helper_funcs = {
188 .prepare_fb = omap_plane_prepare_fb,
189 .cleanup_fb = omap_plane_cleanup_fb,
190 .atomic_update = omap_plane_atomic_update,
191 .atomic_disable = omap_plane_atomic_disable,
192};
193
bb5c2d9a
RC
194static void omap_plane_destroy(struct drm_plane *plane)
195{
196 struct omap_plane *omap_plane = to_omap_plane(plane);
f5f9454c
RC
197
198 DBG("%s", omap_plane->name);
199
200 omap_irq_unregister(plane->dev, &omap_plane->error_irq);
201
bb5c2d9a 202 drm_plane_cleanup(plane);
f5f9454c 203
bb5c2d9a
RC
204 kfree(omap_plane);
205}
206
3c810c61
RC
207/* helper to install properties which are common to planes and crtcs */
208void omap_plane_install_properties(struct drm_plane *plane,
209 struct drm_mode_object *obj)
210{
211 struct drm_device *dev = plane->dev;
212 struct omap_drm_private *priv = dev->dev_private;
3c810c61 213
c2a6a552 214 if (priv->has_dmm) {
e2cd09b2
LP
215 struct drm_property *prop = dev->mode_config.rotation_property;
216
c2a6a552 217 drm_object_attach_property(obj, prop, 0);
3c810c61 218 }
8451b5ad 219
e2cd09b2 220 drm_object_attach_property(obj, priv->zorder_prop, 0);
3c810c61
RC
221}
222
223int omap_plane_set_property(struct drm_plane *plane,
224 struct drm_property *property, uint64_t val)
225{
226 struct omap_plane *omap_plane = to_omap_plane(plane);
227 struct omap_drm_private *priv = plane->dev->dev_private;
a42133a7 228 int ret;
3c810c61 229
e2cd09b2 230 if (property == plane->dev->mode_config.rotation_property) {
f5f9454c 231 DBG("%s: rotation: %02x", omap_plane->name, (uint32_t)val);
3c810c61 232 omap_plane->win.rotation = val;
8451b5ad 233 } else if (property == priv->zorder_prop) {
f5f9454c 234 DBG("%s: zorder: %02x", omap_plane->name, (uint32_t)val);
8451b5ad 235 omap_plane->info.zorder = val;
a42133a7
LP
236 } else {
237 return -EINVAL;
3c810c61
RC
238 }
239
a42133a7
LP
240 /*
241 * We're done if the plane is disabled, properties will be applied the
242 * next time it becomes enabled.
243 */
244 if (!omap_plane->enabled)
245 return 0;
246
247 ret = omap_plane_setup(omap_plane);
248 if (ret < 0)
249 return ret;
250
251 return omap_crtc_flush(plane->crtc);
3c810c61
RC
252}
253
bb5c2d9a 254static const struct drm_plane_funcs omap_plane_funcs = {
cef77d40
LP
255 .update_plane = drm_atomic_helper_update_plane,
256 .disable_plane = drm_atomic_helper_disable_plane,
69a12263 257 .reset = drm_atomic_helper_plane_reset,
222025e4
LP
258 .destroy = omap_plane_destroy,
259 .set_property = omap_plane_set_property,
69a12263
LP
260 .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
261 .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
bb5c2d9a
RC
262};
263
f5f9454c
RC
264static void omap_plane_error_irq(struct omap_drm_irq *irq, uint32_t irqstatus)
265{
266 struct omap_plane *omap_plane =
267 container_of(irq, struct omap_plane, error_irq);
3b143fc8
TV
268 DRM_ERROR_RATELIMITED("%s: errors: %08x\n", omap_plane->name,
269 irqstatus);
f5f9454c
RC
270}
271
272static const char *plane_names[] = {
222025e4
LP
273 [OMAP_DSS_GFX] = "gfx",
274 [OMAP_DSS_VIDEO1] = "vid1",
275 [OMAP_DSS_VIDEO2] = "vid2",
276 [OMAP_DSS_VIDEO3] = "vid3",
f5f9454c
RC
277};
278
279static const uint32_t error_irqs[] = {
222025e4
LP
280 [OMAP_DSS_GFX] = DISPC_IRQ_GFX_FIFO_UNDERFLOW,
281 [OMAP_DSS_VIDEO1] = DISPC_IRQ_VID1_FIFO_UNDERFLOW,
282 [OMAP_DSS_VIDEO2] = DISPC_IRQ_VID2_FIFO_UNDERFLOW,
283 [OMAP_DSS_VIDEO3] = DISPC_IRQ_VID3_FIFO_UNDERFLOW,
f5f9454c
RC
284};
285
bb5c2d9a
RC
286/* initialize plane */
287struct drm_plane *omap_plane_init(struct drm_device *dev,
ef6b0e02 288 int id, enum drm_plane_type type)
bb5c2d9a 289{
f5f9454c 290 struct omap_drm_private *priv = dev->dev_private;
ef6b0e02 291 struct drm_plane *plane;
bb5c2d9a 292 struct omap_plane *omap_plane;
f5f9454c 293 struct omap_overlay_info *info;
ef6b0e02 294 int ret;
bb5c2d9a 295
ef6b0e02 296 DBG("%s: type=%d", plane_names[id], type);
b33f34d3 297
bb5c2d9a 298 omap_plane = kzalloc(sizeof(*omap_plane), GFP_KERNEL);
78110bb8 299 if (!omap_plane)
fb9a35f8 300 return ERR_PTR(-ENOMEM);
bb5c2d9a 301
a890e662
RC
302 omap_plane->nformats = omap_framebuffer_get_formats(
303 omap_plane->formats, ARRAY_SIZE(omap_plane->formats),
f5f9454c
RC
304 dss_feat_get_supported_color_modes(id));
305 omap_plane->id = id;
306 omap_plane->name = plane_names[id];
307
bb5c2d9a
RC
308 plane = &omap_plane->base;
309
f5f9454c
RC
310 omap_plane->error_irq.irqmask = error_irqs[id];
311 omap_plane->error_irq.irq = omap_plane_error_irq;
312 omap_irq_register(dev, &omap_plane->error_irq);
313
ef6b0e02
LP
314 ret = drm_universal_plane_init(dev, plane, (1 << priv->num_crtcs) - 1,
315 &omap_plane_funcs, omap_plane->formats,
316 omap_plane->nformats, type);
317 if (ret < 0)
318 goto error;
bb5c2d9a 319
de8e4100
LP
320 drm_plane_helper_add(plane, &omap_plane_helper_funcs);
321
3c810c61
RC
322 omap_plane_install_properties(plane, &plane->base);
323
bb5c2d9a
RC
324 /* get our starting configuration, set defaults for parameters
325 * we don't currently use, etc:
326 */
f5f9454c
RC
327 info = &omap_plane->info;
328 info->rotation_type = OMAP_DSS_ROT_DMA;
329 info->rotation = OMAP_DSS_ROT_0;
330 info->global_alpha = 0xff;
331 info->mirror = 0;
bb5c2d9a
RC
332
333 /* Set defaults depending on whether we are a CRTC or overlay
334 * layer.
335 * TODO add ioctl to give userspace an API to change this.. this
336 * will come in a subsequent patch.
337 */
ef6b0e02 338 if (type == DRM_PLANE_TYPE_PRIMARY)
bb5c2d9a
RC
339 omap_plane->info.zorder = 0;
340 else
f5f9454c 341 omap_plane->info.zorder = id;
bb5c2d9a
RC
342
343 return plane;
ef6b0e02
LP
344
345error:
346 omap_irq_unregister(plane->dev, &omap_plane->error_irq);
347 kfree(omap_plane);
348 return NULL;
bb5c2d9a 349}