2 * drivers/gpu/drm/omapdrm/omap_plane.c
4 * Copyright (C) 2011 Texas Instruments
5 * Author: Rob Clark <rob.clark@linaro.org>
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.
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
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/>.
20 #include <drm/drm_atomic.h>
21 #include <drm/drm_atomic_helper.h>
22 #include <drm/drm_plane_helper.h>
24 #include "omap_dmm_tiler.h"
27 /* some hackery because omapdss has an 'enum omap_plane' (which would be
28 * better named omap_plane_id).. and compiler seems unhappy about having
29 * both a 'struct omap_plane' and 'enum omap_plane'
31 #define omap_plane _omap_plane
37 #define to_omap_plane(x) container_of(x, struct omap_plane, base)
40 struct drm_plane base
;
41 int id
; /* TODO rename omap_plane -> omap_plane_id in omapdss so I can use the enum */
47 struct omap_drm_irq error_irq
;
50 struct omap_plane_state
{
51 struct drm_plane_state base
;
56 static inline struct omap_plane_state
*
57 to_omap_plane_state(struct drm_plane_state
*state
)
59 return container_of(state
, struct omap_plane_state
, base
);
62 static int omap_plane_prepare_fb(struct drm_plane
*plane
,
63 struct drm_framebuffer
*fb
,
64 const struct drm_plane_state
*new_state
)
66 return omap_framebuffer_pin(fb
);
69 static void omap_plane_cleanup_fb(struct drm_plane
*plane
,
70 struct drm_framebuffer
*fb
,
71 const struct drm_plane_state
*old_state
)
73 omap_framebuffer_unpin(fb
);
76 static void omap_plane_atomic_update(struct drm_plane
*plane
,
77 struct drm_plane_state
*old_state
)
79 struct omap_plane
*omap_plane
= to_omap_plane(plane
);
80 struct drm_plane_state
*state
= plane
->state
;
81 struct omap_plane_state
*omap_state
= to_omap_plane_state(state
);
82 struct omap_overlay_info info
;
83 struct omap_drm_window win
;
86 DBG("%s, crtc=%p fb=%p", omap_plane
->name
, state
->crtc
, state
->fb
);
88 memset(&info
, 0, sizeof(info
));
89 info
.rotation_type
= OMAP_DSS_ROT_DMA
;
90 info
.rotation
= OMAP_DSS_ROT_0
;
91 info
.global_alpha
= 0xff;
93 info
.zorder
= omap_state
->zorder
;
95 memset(&win
, 0, sizeof(win
));
96 win
.rotation
= state
->rotation
;
97 win
.crtc_x
= state
->crtc_x
;
98 win
.crtc_y
= state
->crtc_y
;
99 win
.crtc_w
= state
->crtc_w
;
100 win
.crtc_h
= state
->crtc_h
;
103 * src values are in Q16 fixed point, convert to integer.
104 * omap_framebuffer_update_scanout() takes adjusted src.
106 win
.src_x
= state
->src_x
>> 16;
107 win
.src_y
= state
->src_y
>> 16;
109 switch (state
->rotation
& 0xf) {
110 case BIT(DRM_ROTATE_90
):
111 case BIT(DRM_ROTATE_270
):
112 win
.src_w
= state
->src_h
>> 16;
113 win
.src_h
= state
->src_w
>> 16;
116 win
.src_w
= state
->src_w
>> 16;
117 win
.src_h
= state
->src_h
>> 16;
121 /* update scanout: */
122 omap_framebuffer_update_scanout(state
->fb
, &win
, &info
);
124 DBG("%dx%d -> %dx%d (%d)", info
.width
, info
.height
,
125 info
.out_width
, info
.out_height
,
127 DBG("%d,%d %pad %pad", info
.pos_x
, info
.pos_y
,
128 &info
.paddr
, &info
.p_uv_addr
);
130 dispc_ovl_set_channel_out(omap_plane
->id
,
131 omap_crtc_channel(state
->crtc
));
133 /* and finally, update omapdss: */
134 ret
= dispc_ovl_setup(omap_plane
->id
, &info
, false,
135 omap_crtc_timings(state
->crtc
), false);
137 dispc_ovl_enable(omap_plane
->id
, false);
141 dispc_ovl_enable(omap_plane
->id
, true);
144 static void omap_plane_atomic_disable(struct drm_plane
*plane
,
145 struct drm_plane_state
*old_state
)
147 struct omap_plane_state
*omap_state
= to_omap_plane_state(plane
->state
);
148 struct omap_plane
*omap_plane
= to_omap_plane(plane
);
150 plane
->state
->rotation
= BIT(DRM_ROTATE_0
);
151 omap_state
->zorder
= plane
->type
== DRM_PLANE_TYPE_PRIMARY
152 ? 0 : omap_plane
->id
;
154 dispc_ovl_enable(omap_plane
->id
, false);
157 static int omap_plane_atomic_check(struct drm_plane
*plane
,
158 struct drm_plane_state
*state
)
160 struct drm_crtc_state
*crtc_state
;
165 crtc_state
= drm_atomic_get_crtc_state(state
->state
, state
->crtc
);
166 if (IS_ERR(crtc_state
))
167 return PTR_ERR(crtc_state
);
169 if (state
->crtc_x
< 0 || state
->crtc_y
< 0)
172 if (state
->crtc_x
+ state
->crtc_w
> crtc_state
->adjusted_mode
.hdisplay
)
175 if (state
->crtc_y
+ state
->crtc_h
> crtc_state
->adjusted_mode
.vdisplay
)
181 static const struct drm_plane_helper_funcs omap_plane_helper_funcs
= {
182 .prepare_fb
= omap_plane_prepare_fb
,
183 .cleanup_fb
= omap_plane_cleanup_fb
,
184 .atomic_check
= omap_plane_atomic_check
,
185 .atomic_update
= omap_plane_atomic_update
,
186 .atomic_disable
= omap_plane_atomic_disable
,
189 static void omap_plane_reset(struct drm_plane
*plane
)
191 struct omap_plane
*omap_plane
= to_omap_plane(plane
);
192 struct omap_plane_state
*omap_state
;
194 if (plane
->state
&& plane
->state
->fb
)
195 drm_framebuffer_unreference(plane
->state
->fb
);
200 omap_state
= kzalloc(sizeof(*omap_state
), GFP_KERNEL
);
201 if (omap_state
== NULL
)
205 * Set defaults depending on whether we are a primary or overlay
208 omap_state
->zorder
= plane
->type
== DRM_PLANE_TYPE_PRIMARY
209 ? 0 : omap_plane
->id
;
210 omap_state
->base
.rotation
= BIT(DRM_ROTATE_0
);
212 plane
->state
= &omap_state
->base
;
213 plane
->state
->plane
= plane
;
216 static void omap_plane_destroy(struct drm_plane
*plane
)
218 struct omap_plane
*omap_plane
= to_omap_plane(plane
);
220 DBG("%s", omap_plane
->name
);
222 omap_irq_unregister(plane
->dev
, &omap_plane
->error_irq
);
224 drm_plane_cleanup(plane
);
229 /* helper to install properties which are common to planes and crtcs */
230 void omap_plane_install_properties(struct drm_plane
*plane
,
231 struct drm_mode_object
*obj
)
233 struct drm_device
*dev
= plane
->dev
;
234 struct omap_drm_private
*priv
= dev
->dev_private
;
237 struct drm_property
*prop
= dev
->mode_config
.rotation_property
;
239 drm_object_attach_property(obj
, prop
, 0);
242 drm_object_attach_property(obj
, priv
->zorder_prop
, 0);
245 static struct drm_plane_state
*
246 omap_plane_atomic_duplicate_state(struct drm_plane
*plane
)
248 struct omap_plane_state
*state
;
249 struct omap_plane_state
*copy
;
251 if (WARN_ON(!plane
->state
))
254 state
= to_omap_plane_state(plane
->state
);
255 copy
= kmemdup(state
, sizeof(*state
), GFP_KERNEL
);
259 __drm_atomic_helper_plane_duplicate_state(plane
, ©
->base
);
264 static void omap_plane_atomic_destroy_state(struct drm_plane
*plane
,
265 struct drm_plane_state
*state
)
267 __drm_atomic_helper_plane_destroy_state(plane
, state
);
268 kfree(to_omap_plane_state(state
));
271 static int omap_plane_atomic_set_property(struct drm_plane
*plane
,
272 struct drm_plane_state
*state
,
273 struct drm_property
*property
,
276 struct omap_drm_private
*priv
= plane
->dev
->dev_private
;
277 struct omap_plane_state
*omap_state
= to_omap_plane_state(state
);
279 if (property
== priv
->zorder_prop
)
280 omap_state
->zorder
= val
;
287 static int omap_plane_atomic_get_property(struct drm_plane
*plane
,
288 const struct drm_plane_state
*state
,
289 struct drm_property
*property
,
292 struct omap_drm_private
*priv
= plane
->dev
->dev_private
;
293 const struct omap_plane_state
*omap_state
=
294 container_of(state
, const struct omap_plane_state
, base
);
296 if (property
== priv
->zorder_prop
)
297 *val
= omap_state
->zorder
;
304 static const struct drm_plane_funcs omap_plane_funcs
= {
305 .update_plane
= drm_atomic_helper_update_plane
,
306 .disable_plane
= drm_atomic_helper_disable_plane
,
307 .reset
= omap_plane_reset
,
308 .destroy
= omap_plane_destroy
,
309 .set_property
= drm_atomic_helper_plane_set_property
,
310 .atomic_duplicate_state
= omap_plane_atomic_duplicate_state
,
311 .atomic_destroy_state
= omap_plane_atomic_destroy_state
,
312 .atomic_set_property
= omap_plane_atomic_set_property
,
313 .atomic_get_property
= omap_plane_atomic_get_property
,
316 static void omap_plane_error_irq(struct omap_drm_irq
*irq
, uint32_t irqstatus
)
318 struct omap_plane
*omap_plane
=
319 container_of(irq
, struct omap_plane
, error_irq
);
320 DRM_ERROR_RATELIMITED("%s: errors: %08x\n", omap_plane
->name
,
324 static const char *plane_names
[] = {
325 [OMAP_DSS_GFX
] = "gfx",
326 [OMAP_DSS_VIDEO1
] = "vid1",
327 [OMAP_DSS_VIDEO2
] = "vid2",
328 [OMAP_DSS_VIDEO3
] = "vid3",
331 static const uint32_t error_irqs
[] = {
332 [OMAP_DSS_GFX
] = DISPC_IRQ_GFX_FIFO_UNDERFLOW
,
333 [OMAP_DSS_VIDEO1
] = DISPC_IRQ_VID1_FIFO_UNDERFLOW
,
334 [OMAP_DSS_VIDEO2
] = DISPC_IRQ_VID2_FIFO_UNDERFLOW
,
335 [OMAP_DSS_VIDEO3
] = DISPC_IRQ_VID3_FIFO_UNDERFLOW
,
338 /* initialize plane */
339 struct drm_plane
*omap_plane_init(struct drm_device
*dev
,
340 int id
, enum drm_plane_type type
)
342 struct omap_drm_private
*priv
= dev
->dev_private
;
343 struct drm_plane
*plane
;
344 struct omap_plane
*omap_plane
;
347 DBG("%s: type=%d", plane_names
[id
], type
);
349 omap_plane
= kzalloc(sizeof(*omap_plane
), GFP_KERNEL
);
351 return ERR_PTR(-ENOMEM
);
353 omap_plane
->nformats
= omap_framebuffer_get_formats(
354 omap_plane
->formats
, ARRAY_SIZE(omap_plane
->formats
),
355 dss_feat_get_supported_color_modes(id
));
357 omap_plane
->name
= plane_names
[id
];
359 plane
= &omap_plane
->base
;
361 omap_plane
->error_irq
.irqmask
= error_irqs
[id
];
362 omap_plane
->error_irq
.irq
= omap_plane_error_irq
;
363 omap_irq_register(dev
, &omap_plane
->error_irq
);
365 ret
= drm_universal_plane_init(dev
, plane
, (1 << priv
->num_crtcs
) - 1,
366 &omap_plane_funcs
, omap_plane
->formats
,
367 omap_plane
->nformats
, type
);
371 drm_plane_helper_add(plane
, &omap_plane_helper_funcs
);
373 omap_plane_install_properties(plane
, &plane
->base
);
378 omap_irq_unregister(plane
->dev
, &omap_plane
->error_irq
);