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_plane_state
*new_state
)
68 return omap_framebuffer_pin(new_state
->fb
);
71 static void omap_plane_cleanup_fb(struct drm_plane
*plane
,
72 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
) {
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
= 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
)
181 if (state
->rotation
!= DRM_ROTATE_0
&&
182 !omap_framebuffer_supports_rotation(state
->fb
))
189 static const struct drm_plane_helper_funcs omap_plane_helper_funcs
= {
190 .prepare_fb
= omap_plane_prepare_fb
,
191 .cleanup_fb
= omap_plane_cleanup_fb
,
192 .atomic_check
= omap_plane_atomic_check
,
193 .atomic_update
= omap_plane_atomic_update
,
194 .atomic_disable
= omap_plane_atomic_disable
,
197 static void omap_plane_destroy(struct drm_plane
*plane
)
199 struct omap_plane
*omap_plane
= to_omap_plane(plane
);
201 DBG("%s", omap_plane
->name
);
203 omap_irq_unregister(plane
->dev
, &omap_plane
->error_irq
);
205 drm_plane_cleanup(plane
);
210 /* helper to install properties which are common to planes and crtcs */
211 void omap_plane_install_properties(struct drm_plane
*plane
,
212 struct drm_mode_object
*obj
)
214 struct drm_device
*dev
= plane
->dev
;
215 struct omap_drm_private
*priv
= dev
->dev_private
;
218 struct drm_property
*prop
= dev
->mode_config
.rotation_property
;
220 drm_object_attach_property(obj
, prop
, 0);
223 drm_object_attach_property(obj
, priv
->zorder_prop
, 0);
226 static struct drm_plane_state
*
227 omap_plane_atomic_duplicate_state(struct drm_plane
*plane
)
229 struct omap_plane_state
*state
;
230 struct omap_plane_state
*copy
;
232 if (WARN_ON(!plane
->state
))
235 state
= to_omap_plane_state(plane
->state
);
236 copy
= kmemdup(state
, sizeof(*state
), GFP_KERNEL
);
240 __drm_atomic_helper_plane_duplicate_state(plane
, ©
->base
);
245 static void omap_plane_atomic_destroy_state(struct drm_plane
*plane
,
246 struct drm_plane_state
*state
)
248 __drm_atomic_helper_plane_destroy_state(state
);
249 kfree(to_omap_plane_state(state
));
252 static void omap_plane_reset(struct drm_plane
*plane
)
254 struct omap_plane
*omap_plane
= to_omap_plane(plane
);
255 struct omap_plane_state
*omap_state
;
258 omap_plane_atomic_destroy_state(plane
, plane
->state
);
262 omap_state
= kzalloc(sizeof(*omap_state
), GFP_KERNEL
);
263 if (omap_state
== NULL
)
267 * Set defaults depending on whether we are a primary or overlay
270 omap_state
->zorder
= plane
->type
== DRM_PLANE_TYPE_PRIMARY
271 ? 0 : omap_plane
->id
;
272 omap_state
->base
.rotation
= DRM_ROTATE_0
;
274 plane
->state
= &omap_state
->base
;
275 plane
->state
->plane
= plane
;
278 static int omap_plane_atomic_set_property(struct drm_plane
*plane
,
279 struct drm_plane_state
*state
,
280 struct drm_property
*property
,
283 struct omap_drm_private
*priv
= plane
->dev
->dev_private
;
284 struct omap_plane_state
*omap_state
= to_omap_plane_state(state
);
286 if (property
== priv
->zorder_prop
)
287 omap_state
->zorder
= val
;
294 static int omap_plane_atomic_get_property(struct drm_plane
*plane
,
295 const struct drm_plane_state
*state
,
296 struct drm_property
*property
,
299 struct omap_drm_private
*priv
= plane
->dev
->dev_private
;
300 const struct omap_plane_state
*omap_state
=
301 container_of(state
, const struct omap_plane_state
, base
);
303 if (property
== priv
->zorder_prop
)
304 *val
= omap_state
->zorder
;
311 static const struct drm_plane_funcs omap_plane_funcs
= {
312 .update_plane
= drm_atomic_helper_update_plane
,
313 .disable_plane
= drm_atomic_helper_disable_plane
,
314 .reset
= omap_plane_reset
,
315 .destroy
= omap_plane_destroy
,
316 .set_property
= drm_atomic_helper_plane_set_property
,
317 .atomic_duplicate_state
= omap_plane_atomic_duplicate_state
,
318 .atomic_destroy_state
= omap_plane_atomic_destroy_state
,
319 .atomic_set_property
= omap_plane_atomic_set_property
,
320 .atomic_get_property
= omap_plane_atomic_get_property
,
323 static void omap_plane_error_irq(struct omap_drm_irq
*irq
, uint32_t irqstatus
)
325 struct omap_plane
*omap_plane
=
326 container_of(irq
, struct omap_plane
, error_irq
);
327 DRM_ERROR_RATELIMITED("%s: errors: %08x\n", omap_plane
->name
,
331 static const char *plane_names
[] = {
332 [OMAP_DSS_GFX
] = "gfx",
333 [OMAP_DSS_VIDEO1
] = "vid1",
334 [OMAP_DSS_VIDEO2
] = "vid2",
335 [OMAP_DSS_VIDEO3
] = "vid3",
338 static const uint32_t error_irqs
[] = {
339 [OMAP_DSS_GFX
] = DISPC_IRQ_GFX_FIFO_UNDERFLOW
,
340 [OMAP_DSS_VIDEO1
] = DISPC_IRQ_VID1_FIFO_UNDERFLOW
,
341 [OMAP_DSS_VIDEO2
] = DISPC_IRQ_VID2_FIFO_UNDERFLOW
,
342 [OMAP_DSS_VIDEO3
] = DISPC_IRQ_VID3_FIFO_UNDERFLOW
,
345 /* initialize plane */
346 struct drm_plane
*omap_plane_init(struct drm_device
*dev
,
347 int id
, enum drm_plane_type type
)
349 struct omap_drm_private
*priv
= dev
->dev_private
;
350 struct drm_plane
*plane
;
351 struct omap_plane
*omap_plane
;
354 DBG("%s: type=%d", plane_names
[id
], type
);
356 omap_plane
= kzalloc(sizeof(*omap_plane
), GFP_KERNEL
);
358 return ERR_PTR(-ENOMEM
);
360 omap_plane
->nformats
= omap_framebuffer_get_formats(
361 omap_plane
->formats
, ARRAY_SIZE(omap_plane
->formats
),
362 dss_feat_get_supported_color_modes(id
));
364 omap_plane
->name
= plane_names
[id
];
366 plane
= &omap_plane
->base
;
368 omap_plane
->error_irq
.irqmask
= error_irqs
[id
];
369 omap_plane
->error_irq
.irq
= omap_plane_error_irq
;
370 omap_irq_register(dev
, &omap_plane
->error_irq
);
372 ret
= drm_universal_plane_init(dev
, plane
, (1 << priv
->num_crtcs
) - 1,
373 &omap_plane_funcs
, omap_plane
->formats
,
374 omap_plane
->nformats
, type
, NULL
);
378 drm_plane_helper_add(plane
, &omap_plane_helper_funcs
);
380 omap_plane_install_properties(plane
, &plane
->base
);
385 omap_irq_unregister(plane
->dev
, &omap_plane
->error_irq
);