blob: 7813e48b6896d0863e9b436dce1fd7f907f57140 [file] [log] [blame]
Rob Clarkbb5c2d92012-01-16 12:51:16 -06001/*
Rob Clark8bb0daf2013-02-11 12:43:09 -05002 * drivers/gpu/drm/omapdrm/omap_plane.c
Rob Clarkbb5c2d92012-01-16 12:51:16 -06003 *
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
Laurent Pinchart69a12262015-03-05 21:38:16 +020020#include <drm/drm_atomic_helper.h>
Laurent Pinchartde8e4102015-03-05 13:39:56 +020021#include <drm/drm_plane_helper.h>
Laurent Pinchart69a12262015-03-05 21:38:16 +020022
Rob Clark3c810c62012-08-15 15:18:01 -050023#include "omap_dmm_tiler.h"
Laurent Pinchart2d278f52015-03-05 21:31:37 +020024#include "omap_drv.h"
Rob Clarkbb5c2d92012-01-16 12:51:16 -060025
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;
Rob Clarkf5f94542012-12-04 13:59:12 -060040 int id; /* TODO rename omap_plane -> omap_plane_id in omapdss so I can use the enum */
41 const char *name;
Rob Clarkbb5c2d92012-01-16 12:51:16 -060042 struct omap_overlay_info info;
43
Rob Clark3c810c62012-08-15 15:18:01 -050044 /* position/orientation of scanout within the fb: */
45 struct omap_drm_window win;
Rob Clarkf5f94542012-12-04 13:59:12 -060046 bool enabled;
Rob Clark9a0774e2012-01-16 12:51:17 -060047
Rob Clarka890e662012-03-05 10:48:31 -060048 uint32_t nformats;
49 uint32_t formats[32];
Rob Clarkb33f34d2012-03-05 10:48:35 -060050
Rob Clarkf5f94542012-12-04 13:59:12 -060051 struct omap_drm_irq error_irq;
Rob Clarka890e662012-03-05 10:48:31 -060052};
Rob Clarkbb5c2d92012-01-16 12:51:16 -060053
Laurent Pinchartde8e4102015-03-05 13:39:56 +020054static int __omap_plane_setup(struct omap_plane *omap_plane,
55 struct drm_crtc *crtc,
56 struct drm_framebuffer *fb)
Rob Clarkbb5c2d92012-01-16 12:51:16 -060057{
Laurent Pincharta42133a2015-01-17 19:09:26 +020058 struct omap_overlay_info *info = &omap_plane->info;
Laurent Pinchartde8e4102015-03-05 13:39:56 +020059 struct drm_device *dev = omap_plane->base.dev;
Rob Clark9a0774e2012-01-16 12:51:17 -060060 int ret;
Rob Clarkbb5c2d92012-01-16 12:51:16 -060061
Laurent Pincharta42133a2015-01-17 19:09:26 +020062 DBG("%s, enabled=%d", omap_plane->name, omap_plane->enabled);
Rob Clarkf5f94542012-12-04 13:59:12 -060063
Laurent Pincharta42133a2015-01-17 19:09:26 +020064 if (!omap_plane->enabled) {
Rob Clarkf5f94542012-12-04 13:59:12 -060065 dispc_ovl_enable(omap_plane->id, false);
Laurent Pinchartde8e4102015-03-05 13:39:56 +020066 return 0;
Rob Clark9a0774e2012-01-16 12:51:17 -060067 }
68
Rob Clarkf5f94542012-12-04 13:59:12 -060069 /* update scanout: */
Laurent Pinchartde8e4102015-03-05 13:39:56 +020070 omap_framebuffer_update_scanout(fb, &omap_plane->win, info);
Rob Clark9a0774e2012-01-16 12:51:17 -060071
Rob Clarkf5f94542012-12-04 13:59:12 -060072 DBG("%dx%d -> %dx%d (%d)", info->width, info->height,
73 info->out_width, info->out_height,
Rob Clark9a0774e2012-01-16 12:51:17 -060074 info->screen_width);
Russell King2d31ca32014-07-12 10:53:41 +010075 DBG("%d,%d %pad %pad", info->pos_x, info->pos_y,
76 &info->paddr, &info->p_uv_addr);
Rob Clarkf5f94542012-12-04 13:59:12 -060077
Laurent Pincharta42133a2015-01-17 19:09:26 +020078 dispc_ovl_set_channel_out(omap_plane->id,
79 omap_crtc_channel(crtc));
Tomi Valkeinen2dd38872014-10-03 15:14:08 +000080
Rob Clarkf5f94542012-12-04 13:59:12 -060081 /* and finally, update omapdss: */
Laurent Pinchart9c660b72015-01-12 16:44:03 +020082 ret = dispc_ovl_setup(omap_plane->id, info, false,
83 omap_crtc_timings(crtc), false);
Rob Clarkf5f94542012-12-04 13:59:12 -060084 if (ret) {
85 dev_err(dev->dev, "dispc_ovl_setup failed: %d\n", ret);
Laurent Pinchartde8e4102015-03-05 13:39:56 +020086 return ret;
Rob Clarkf5f94542012-12-04 13:59:12 -060087 }
88
89 dispc_ovl_enable(omap_plane->id, true);
Rob Clarkf5f94542012-12-04 13:59:12 -060090
Laurent Pinchartde8e4102015-03-05 13:39:56 +020091 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
Laurent Pinchartde8e4102015-03-05 13:39:56 +020099 dispc_runtime_get();
100 ret = __omap_plane_setup(omap_plane, plane->crtc, plane->fb);
Laurent Pincharta42133a2015-01-17 19:09:26 +0200101 dispc_runtime_put();
Laurent Pinchartde8e4102015-03-05 13:39:56 +0200102
Laurent Pincharta42133a2015-01-17 19:09:26 +0200103 return ret;
Rob Clarkbb5c2d92012-01-16 12:51:16 -0600104}
105
Laurent Pincharta42133a2015-01-17 19:09:26 +0200106int omap_plane_set_enable(struct drm_plane *plane, bool enable)
107{
108 struct omap_plane *omap_plane = to_omap_plane(plane);
Rob Clarkf5f94542012-12-04 13:59:12 -0600109
Laurent Pincharta42133a2015-01-17 19:09:26 +0200110 if (enable == omap_plane->enabled)
111 return 0;
112
113 omap_plane->enabled = enable;
114 return omap_plane_setup(omap_plane);
Rob Clarkbb5c2d92012-01-16 12:51:16 -0600115}
116
Laurent Pinchartde8e4102015-03-05 13:39:56 +0200117static 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)
Rob Clark2f537002012-01-16 12:51:18 -0600133{
Rob Clarkf5f94542012-12-04 13:59:12 -0600134 struct omap_plane *omap_plane = to_omap_plane(plane);
Laurent Pinchartde8e4102015-03-05 13:39:56 +0200135 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;
Laurent Pincharta42133a2015-01-17 19:09:26 +0200139
Laurent Pinchartde8e4102015-03-05 13:39:56 +0200140 if (!state->fb || !state->crtc)
141 return;
Archit Tanejab03e14f2013-04-09 15:26:00 +0300142
Laurent Pinchartde8e4102015-03-05 13:39:56 +0200143 /* omap_framebuffer_update_scanout() takes adjusted src */
Grazvydas Ignotasd4586602014-04-05 21:33:51 +0300144 switch (omap_plane->win.rotation & 0xf) {
145 case BIT(DRM_ROTATE_90):
146 case BIT(DRM_ROTATE_270):
Laurent Pinchartde8e4102015-03-05 13:39:56 +0200147 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;
Grazvydas Ignotasd4586602014-04-05 21:33:51 +0300153 break;
154 }
155
Laurent Pinchartde8e4102015-03-05 13:39:56 +0200156 /* 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;
Laurent Pinchartef6b0e02015-01-11 00:11:18 +0200161
Laurent Pinchartde8e4102015-03-05 13:39:56 +0200162 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;
Laurent Pincharta42133a2015-01-17 19:09:26 +0200166
Laurent Pinchartde8e4102015-03-05 13:39:56 +0200167 omap_plane->enabled = true;
168 __omap_plane_setup(omap_plane, state->crtc, state->fb);
Rob Clark2f537002012-01-16 12:51:18 -0600169}
170
Laurent Pinchartde8e4102015-03-05 13:39:56 +0200171static void omap_plane_atomic_disable(struct drm_plane *plane,
172 struct drm_plane_state *old_state)
Rob Clarkbb5c2d92012-01-16 12:51:16 -0600173{
Rob Clark3c810c62012-08-15 15:18:01 -0500174 struct omap_plane *omap_plane = to_omap_plane(plane);
Laurent Pinchart2debab92015-01-12 22:38:16 +0200175
Rob Clark3c810c62012-08-15 15:18:01 -0500176 omap_plane->win.rotation = BIT(DRM_ROTATE_0);
Laurent Pinchart82e588552015-01-12 23:56:57 +0200177 omap_plane->info.zorder = plane->type == DRM_PLANE_TYPE_PRIMARY
178 ? 0 : omap_plane->id;
179
Laurent Pincharta42133a2015-01-17 19:09:26 +0200180 if (!omap_plane->enabled)
Laurent Pinchartde8e4102015-03-05 13:39:56 +0200181 return;
Laurent Pincharta42133a2015-01-17 19:09:26 +0200182
Laurent Pincharta42133a2015-01-17 19:09:26 +0200183 omap_plane->enabled = false;
Laurent Pinchartde8e4102015-03-05 13:39:56 +0200184 __omap_plane_setup(omap_plane, NULL, NULL);
Rob Clarkbb5c2d92012-01-16 12:51:16 -0600185}
186
Laurent Pinchartde8e4102015-03-05 13:39:56 +0200187static 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
Rob Clarkbb5c2d92012-01-16 12:51:16 -0600194static void omap_plane_destroy(struct drm_plane *plane)
195{
196 struct omap_plane *omap_plane = to_omap_plane(plane);
Rob Clarkf5f94542012-12-04 13:59:12 -0600197
198 DBG("%s", omap_plane->name);
199
200 omap_irq_unregister(plane->dev, &omap_plane->error_irq);
201
Rob Clarkbb5c2d92012-01-16 12:51:16 -0600202 drm_plane_cleanup(plane);
Rob Clarkf5f94542012-12-04 13:59:12 -0600203
Rob Clarkbb5c2d92012-01-16 12:51:16 -0600204 kfree(omap_plane);
205}
206
Rob Clark3c810c62012-08-15 15:18:01 -0500207/* 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;
Rob Clark3c810c62012-08-15 15:18:01 -0500213
Rob Clarkc2a6a552012-10-25 17:14:13 -0500214 if (priv->has_dmm) {
Laurent Pincharte2cd09b2015-03-06 17:16:43 +0200215 struct drm_property *prop = dev->mode_config.rotation_property;
216
Rob Clarkc2a6a552012-10-25 17:14:13 -0500217 drm_object_attach_property(obj, prop, 0);
Rob Clark3c810c62012-08-15 15:18:01 -0500218 }
Andre Renaud8451b5a2012-08-15 15:18:02 -0500219
Laurent Pincharte2cd09b2015-03-06 17:16:43 +0200220 drm_object_attach_property(obj, priv->zorder_prop, 0);
Rob Clark3c810c62012-08-15 15:18:01 -0500221}
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;
Laurent Pincharta42133a2015-01-17 19:09:26 +0200228 int ret;
Rob Clark3c810c62012-08-15 15:18:01 -0500229
Laurent Pincharte2cd09b2015-03-06 17:16:43 +0200230 if (property == plane->dev->mode_config.rotation_property) {
Rob Clarkf5f94542012-12-04 13:59:12 -0600231 DBG("%s: rotation: %02x", omap_plane->name, (uint32_t)val);
Rob Clark3c810c62012-08-15 15:18:01 -0500232 omap_plane->win.rotation = val;
Andre Renaud8451b5a2012-08-15 15:18:02 -0500233 } else if (property == priv->zorder_prop) {
Rob Clarkf5f94542012-12-04 13:59:12 -0600234 DBG("%s: zorder: %02x", omap_plane->name, (uint32_t)val);
Andre Renaud8451b5a2012-08-15 15:18:02 -0500235 omap_plane->info.zorder = val;
Laurent Pincharta42133a2015-01-17 19:09:26 +0200236 } else {
237 return -EINVAL;
Rob Clark3c810c62012-08-15 15:18:01 -0500238 }
239
Laurent Pincharta42133a2015-01-17 19:09:26 +0200240 /*
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);
Rob Clark3c810c62012-08-15 15:18:01 -0500252}
253
Rob Clarkbb5c2d92012-01-16 12:51:16 -0600254static const struct drm_plane_funcs omap_plane_funcs = {
Laurent Pinchartcef77d42015-03-05 21:50:00 +0200255 .update_plane = drm_atomic_helper_update_plane,
256 .disable_plane = drm_atomic_helper_disable_plane,
Laurent Pinchart69a12262015-03-05 21:38:16 +0200257 .reset = drm_atomic_helper_plane_reset,
Laurent Pinchart222025e2015-01-11 00:02:07 +0200258 .destroy = omap_plane_destroy,
259 .set_property = omap_plane_set_property,
Laurent Pinchart69a12262015-03-05 21:38:16 +0200260 .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
261 .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
Rob Clarkbb5c2d92012-01-16 12:51:16 -0600262};
263
Rob Clarkf5f94542012-12-04 13:59:12 -0600264static 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);
Tomi Valkeinen3b143fc2014-11-19 12:50:13 +0200268 DRM_ERROR_RATELIMITED("%s: errors: %08x\n", omap_plane->name,
269 irqstatus);
Rob Clarkf5f94542012-12-04 13:59:12 -0600270}
271
272static const char *plane_names[] = {
Laurent Pinchart222025e2015-01-11 00:02:07 +0200273 [OMAP_DSS_GFX] = "gfx",
274 [OMAP_DSS_VIDEO1] = "vid1",
275 [OMAP_DSS_VIDEO2] = "vid2",
276 [OMAP_DSS_VIDEO3] = "vid3",
Rob Clarkf5f94542012-12-04 13:59:12 -0600277};
278
279static const uint32_t error_irqs[] = {
Laurent Pinchart222025e2015-01-11 00:02:07 +0200280 [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,
Rob Clarkf5f94542012-12-04 13:59:12 -0600284};
285
Rob Clarkbb5c2d92012-01-16 12:51:16 -0600286/* initialize plane */
287struct drm_plane *omap_plane_init(struct drm_device *dev,
Laurent Pinchartef6b0e02015-01-11 00:11:18 +0200288 int id, enum drm_plane_type type)
Rob Clarkbb5c2d92012-01-16 12:51:16 -0600289{
Rob Clarkf5f94542012-12-04 13:59:12 -0600290 struct omap_drm_private *priv = dev->dev_private;
Laurent Pinchartef6b0e02015-01-11 00:11:18 +0200291 struct drm_plane *plane;
Rob Clarkbb5c2d92012-01-16 12:51:16 -0600292 struct omap_plane *omap_plane;
Rob Clarkf5f94542012-12-04 13:59:12 -0600293 struct omap_overlay_info *info;
Laurent Pinchartef6b0e02015-01-11 00:11:18 +0200294 int ret;
Rob Clarkbb5c2d92012-01-16 12:51:16 -0600295
Laurent Pinchartef6b0e02015-01-11 00:11:18 +0200296 DBG("%s: type=%d", plane_names[id], type);
Rob Clarkb33f34d2012-03-05 10:48:35 -0600297
Rob Clarkbb5c2d92012-01-16 12:51:16 -0600298 omap_plane = kzalloc(sizeof(*omap_plane), GFP_KERNEL);
Joe Perches78110bb2013-02-11 09:41:29 -0800299 if (!omap_plane)
Laurent Pinchartfb9a35f2015-01-11 16:30:44 +0200300 return ERR_PTR(-ENOMEM);
Rob Clarkbb5c2d92012-01-16 12:51:16 -0600301
Rob Clarka890e662012-03-05 10:48:31 -0600302 omap_plane->nformats = omap_framebuffer_get_formats(
303 omap_plane->formats, ARRAY_SIZE(omap_plane->formats),
Rob Clarkf5f94542012-12-04 13:59:12 -0600304 dss_feat_get_supported_color_modes(id));
305 omap_plane->id = id;
306 omap_plane->name = plane_names[id];
307
Rob Clarkbb5c2d92012-01-16 12:51:16 -0600308 plane = &omap_plane->base;
309
Rob Clarkf5f94542012-12-04 13:59:12 -0600310 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
Laurent Pinchartef6b0e02015-01-11 00:11:18 +0200314 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;
Rob Clarkbb5c2d92012-01-16 12:51:16 -0600319
Laurent Pinchartde8e4102015-03-05 13:39:56 +0200320 drm_plane_helper_add(plane, &omap_plane_helper_funcs);
321
Rob Clark3c810c62012-08-15 15:18:01 -0500322 omap_plane_install_properties(plane, &plane->base);
323
Rob Clarkbb5c2d92012-01-16 12:51:16 -0600324 /* get our starting configuration, set defaults for parameters
325 * we don't currently use, etc:
326 */
Rob Clarkf5f94542012-12-04 13:59:12 -0600327 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;
Rob Clarkbb5c2d92012-01-16 12:51:16 -0600332
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 */
Laurent Pinchartef6b0e02015-01-11 00:11:18 +0200338 if (type == DRM_PLANE_TYPE_PRIMARY)
Rob Clarkbb5c2d92012-01-16 12:51:16 -0600339 omap_plane->info.zorder = 0;
340 else
Rob Clarkf5f94542012-12-04 13:59:12 -0600341 omap_plane->info.zorder = id;
Rob Clarkbb5c2d92012-01-16 12:51:16 -0600342
343 return plane;
Laurent Pinchartef6b0e02015-01-11 00:11:18 +0200344
345error:
346 omap_irq_unregister(plane->dev, &omap_plane->error_irq);
347 kfree(omap_plane);
348 return NULL;
Rob Clarkbb5c2d92012-01-16 12:51:16 -0600349}