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 const struct drm_plane_state
*new_state
)
68 return omap_framebuffer_pin(new_state
->fb
);
71 static void omap_plane_cleanup_fb(struct drm_plane
*plane
,
72 const struct drm_plane_state
*old_state
)
75 omap_framebuffer_unpin(old_state
->fb
);
78 static void omap_plane_atomic_update(struct drm_plane
*plane
,
79 struct drm_plane_state
*old_state
)
81 struct omap_plane
*omap_plane
= to_omap_plane(plane
);
82 struct drm_plane_state
*state
= plane
->state
;
83 struct omap_plane_state
*omap_state
= to_omap_plane_state(state
);
84 struct omap_overlay_info info
;
85 struct omap_drm_window win
;
88 DBG("%s, crtc=%p fb=%p", omap_plane
->name
, state
->crtc
, state
->fb
);
90 memset(&info
, 0, sizeof(info
));
91 info
.rotation_type
= OMAP_DSS_ROT_DMA
;
92 info
.rotation
= OMAP_DSS_ROT_0
;
93 info
.global_alpha
= 0xff;
95 info
.zorder
= omap_state
->zorder
;
97 memset(&win
, 0, sizeof(win
));
98 win
.rotation
= state
->rotation
;
99 win
.crtc_x
= state
->crtc_x
;
100 win
.crtc_y
= state
->crtc_y
;
101 win
.crtc_w
= state
->crtc_w
;
102 win
.crtc_h
= state
->crtc_h
;
105 * src values are in Q16 fixed point, convert to integer.
106 * omap_framebuffer_update_scanout() takes adjusted src.
108 win
.src_x
= state
->src_x
>> 16;
109 win
.src_y
= state
->src_y
>> 16;
111 switch (state
->rotation
& DRM_ROTATE_MASK
) {
112 case BIT(DRM_ROTATE_90
):
113 case BIT(DRM_ROTATE_270
):
114 win
.src_w
= state
->src_h
>> 16;
115 win
.src_h
= state
->src_w
>> 16;
118 win
.src_w
= state
->src_w
>> 16;
119 win
.src_h
= state
->src_h
>> 16;
123 /* update scanout: */
124 omap_framebuffer_update_scanout(state
->fb
, &win
, &info
);
126 DBG("%dx%d -> %dx%d (%d)", info
.width
, info
.height
,
127 info
.out_width
, info
.out_height
,
129 DBG("%d,%d %pad %pad", info
.pos_x
, info
.pos_y
,
130 &info
.paddr
, &info
.p_uv_addr
);
132 dispc_ovl_set_channel_out(omap_plane
->id
,
133 omap_crtc_channel(state
->crtc
));
135 /* and finally, update omapdss: */
136 ret
= dispc_ovl_setup(omap_plane
->id
, &info
, false,
137 omap_crtc_timings(state
->crtc
), false);
139 dispc_ovl_enable(omap_plane
->id
, false);
143 dispc_ovl_enable(omap_plane
->id
, true);
146 static void omap_plane_atomic_disable(struct drm_plane
*plane
,
147 struct drm_plane_state
*old_state
)
149 struct omap_plane_state
*omap_state
= to_omap_plane_state(plane
->state
);
150 struct omap_plane
*omap_plane
= to_omap_plane(plane
);
152 plane
->state
->rotation
= BIT(DRM_ROTATE_0
);
153 omap_state
->zorder
= plane
->type
== DRM_PLANE_TYPE_PRIMARY
154 ? 0 : omap_plane
->id
;
156 dispc_ovl_enable(omap_plane
->id
, false);
159 static int omap_plane_atomic_check(struct drm_plane
*plane
,
160 struct drm_plane_state
*state
)
162 struct drm_crtc_state
*crtc_state
;
167 crtc_state
= drm_atomic_get_crtc_state(state
->state
, state
->crtc
);
168 if (IS_ERR(crtc_state
))
169 return PTR_ERR(crtc_state
);
171 if (state
->crtc_x
< 0 || state
->crtc_y
< 0)
174 if (state
->crtc_x
+ state
->crtc_w
> crtc_state
->adjusted_mode
.hdisplay
)
177 if (state
->crtc_y
+ state
->crtc_h
> crtc_state
->adjusted_mode
.vdisplay
)
183 static const struct drm_plane_helper_funcs omap_plane_helper_funcs
= {
184 .prepare_fb
= omap_plane_prepare_fb
,
185 .cleanup_fb
= omap_plane_cleanup_fb
,
186 .atomic_check
= omap_plane_atomic_check
,
187 .atomic_update
= omap_plane_atomic_update
,
188 .atomic_disable
= omap_plane_atomic_disable
,
191 static void omap_plane_destroy(struct drm_plane
*plane
)
193 struct omap_plane
*omap_plane
= to_omap_plane(plane
);
195 DBG("%s", omap_plane
->name
);
197 omap_irq_unregister(plane
->dev
, &omap_plane
->error_irq
);
199 drm_plane_cleanup(plane
);
204 /* helper to install properties which are common to planes and crtcs */
205 void omap_plane_install_properties(struct drm_plane
*plane
,
206 struct drm_mode_object
*obj
)
208 struct drm_device
*dev
= plane
->dev
;
209 struct omap_drm_private
*priv
= dev
->dev_private
;
212 struct drm_property
*prop
= dev
->mode_config
.rotation_property
;
214 drm_object_attach_property(obj
, prop
, 0);
217 drm_object_attach_property(obj
, priv
->zorder_prop
, 0);
220 static struct drm_plane_state
*
221 omap_plane_atomic_duplicate_state(struct drm_plane
*plane
)
223 struct omap_plane_state
*state
;
224 struct omap_plane_state
*copy
;
226 if (WARN_ON(!plane
->state
))
229 state
= to_omap_plane_state(plane
->state
);
230 copy
= kmemdup(state
, sizeof(*state
), GFP_KERNEL
);
234 __drm_atomic_helper_plane_duplicate_state(plane
, ©
->base
);
239 static void omap_plane_atomic_destroy_state(struct drm_plane
*plane
,
240 struct drm_plane_state
*state
)
242 __drm_atomic_helper_plane_destroy_state(plane
, state
);
243 kfree(to_omap_plane_state(state
));
246 static void omap_plane_reset(struct drm_plane
*plane
)
248 struct omap_plane
*omap_plane
= to_omap_plane(plane
);
249 struct omap_plane_state
*omap_state
;
252 omap_plane_atomic_destroy_state(plane
, plane
->state
);
256 omap_state
= kzalloc(sizeof(*omap_state
), GFP_KERNEL
);
257 if (omap_state
== NULL
)
261 * Set defaults depending on whether we are a primary or overlay
264 omap_state
->zorder
= plane
->type
== DRM_PLANE_TYPE_PRIMARY
265 ? 0 : omap_plane
->id
;
266 omap_state
->base
.rotation
= BIT(DRM_ROTATE_0
);
268 plane
->state
= &omap_state
->base
;
269 plane
->state
->plane
= plane
;
272 static int omap_plane_atomic_set_property(struct drm_plane
*plane
,
273 struct drm_plane_state
*state
,
274 struct drm_property
*property
,
277 struct omap_drm_private
*priv
= plane
->dev
->dev_private
;
278 struct omap_plane_state
*omap_state
= to_omap_plane_state(state
);
280 if (property
== priv
->zorder_prop
)
281 omap_state
->zorder
= val
;
288 static int omap_plane_atomic_get_property(struct drm_plane
*plane
,
289 const struct drm_plane_state
*state
,
290 struct drm_property
*property
,
293 struct omap_drm_private
*priv
= plane
->dev
->dev_private
;
294 const struct omap_plane_state
*omap_state
=
295 container_of(state
, const struct omap_plane_state
, base
);
297 if (property
== priv
->zorder_prop
)
298 *val
= omap_state
->zorder
;
305 static const struct drm_plane_funcs omap_plane_funcs
= {
306 .update_plane
= drm_atomic_helper_update_plane
,
307 .disable_plane
= drm_atomic_helper_disable_plane
,
308 .reset
= omap_plane_reset
,
309 .destroy
= omap_plane_destroy
,
310 .set_property
= drm_atomic_helper_plane_set_property
,
311 .atomic_duplicate_state
= omap_plane_atomic_duplicate_state
,
312 .atomic_destroy_state
= omap_plane_atomic_destroy_state
,
313 .atomic_set_property
= omap_plane_atomic_set_property
,
314 .atomic_get_property
= omap_plane_atomic_get_property
,
317 static void omap_plane_error_irq(struct omap_drm_irq
*irq
, uint32_t irqstatus
)
319 struct omap_plane
*omap_plane
=
320 container_of(irq
, struct omap_plane
, error_irq
);
321 DRM_ERROR_RATELIMITED("%s: errors: %08x\n", omap_plane
->name
,
325 static const char *plane_names
[] = {
326 [OMAP_DSS_GFX
] = "gfx",
327 [OMAP_DSS_VIDEO1
] = "vid1",
328 [OMAP_DSS_VIDEO2
] = "vid2",
329 [OMAP_DSS_VIDEO3
] = "vid3",
332 static const uint32_t error_irqs
[] = {
333 [OMAP_DSS_GFX
] = DISPC_IRQ_GFX_FIFO_UNDERFLOW
,
334 [OMAP_DSS_VIDEO1
] = DISPC_IRQ_VID1_FIFO_UNDERFLOW
,
335 [OMAP_DSS_VIDEO2
] = DISPC_IRQ_VID2_FIFO_UNDERFLOW
,
336 [OMAP_DSS_VIDEO3
] = DISPC_IRQ_VID3_FIFO_UNDERFLOW
,
339 /* initialize plane */
340 struct drm_plane
*omap_plane_init(struct drm_device
*dev
,
341 int id
, enum drm_plane_type type
)
343 struct omap_drm_private
*priv
= dev
->dev_private
;
344 struct drm_plane
*plane
;
345 struct omap_plane
*omap_plane
;
348 DBG("%s: type=%d", plane_names
[id
], type
);
350 omap_plane
= kzalloc(sizeof(*omap_plane
), GFP_KERNEL
);
352 return ERR_PTR(-ENOMEM
);
354 omap_plane
->nformats
= omap_framebuffer_get_formats(
355 omap_plane
->formats
, ARRAY_SIZE(omap_plane
->formats
),
356 dss_feat_get_supported_color_modes(id
));
358 omap_plane
->name
= plane_names
[id
];
360 plane
= &omap_plane
->base
;
362 omap_plane
->error_irq
.irqmask
= error_irqs
[id
];
363 omap_plane
->error_irq
.irq
= omap_plane_error_irq
;
364 omap_irq_register(dev
, &omap_plane
->error_irq
);
366 ret
= drm_universal_plane_init(dev
, plane
, (1 << priv
->num_crtcs
) - 1,
367 &omap_plane_funcs
, omap_plane
->formats
,
368 omap_plane
->nformats
, type
, NULL
);
372 drm_plane_helper_add(plane
, &omap_plane_helper_funcs
);
374 omap_plane_install_properties(plane
, &plane
->base
);
379 omap_irq_unregister(plane
->dev
, &omap_plane
->error_irq
);