2 * drivers/staging/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/>.
22 /* some hackery because omapdss has an 'enum omap_plane' (which would be
23 * better named omap_plane_id).. and compiler seems unhappy about having
24 * both a 'struct omap_plane' and 'enum omap_plane'
26 #define omap_plane _omap_plane
32 #define to_omap_plane(x) container_of(x, struct omap_plane, base)
35 struct drm_plane base
;
36 struct omap_overlay
*ovl
;
37 struct omap_overlay_info info
;
39 /* Source values, converted to integers because we don't support
40 * fractional positions:
42 unsigned int src_x
, src_y
;
44 /* last fb that we pinned: */
45 struct drm_framebuffer
*pinned_fb
;
49 /* push changes down to dss2 */
50 static int commit(struct drm_plane
*plane
)
52 struct drm_device
*dev
= plane
->dev
;
53 struct omap_plane
*omap_plane
= to_omap_plane(plane
);
54 struct omap_overlay
*ovl
= omap_plane
->ovl
;
55 struct omap_overlay_info
*info
= &omap_plane
->info
;
59 DBG("%dx%d -> %dx%d (%d)", info
->width
, info
->height
, info
->out_width
,
60 info
->out_height
, info
->screen_width
);
61 DBG("%d,%d %08x %08x", info
->pos_x
, info
->pos_y
,
62 info
->paddr
, info
->p_uv_addr
);
64 /* NOTE: do we want to do this at all here, or just wait
65 * for dpms(ON) since other CRTC's may not have their mode
66 * set yet, so fb dimensions may still change..
68 ret
= ovl
->set_overlay_info(ovl
, info
);
70 dev_err(dev
->dev
, "could not set overlay info\n");
74 /* our encoder doesn't necessarily get a commit() after this, in
75 * particular in the dpms() and mode_set_base() cases, so force the
78 * could this be in the encoder somehow?
81 ret
= ovl
->manager
->apply(ovl
->manager
);
83 dev_err(dev
->dev
, "could not apply settings\n");
88 if (ovl
->is_enabled(ovl
)) {
89 omap_framebuffer_flush(plane
->fb
, info
->pos_x
, info
->pos_y
,
90 info
->out_width
, info
->out_height
);
96 /* when CRTC that we are attached to has potentially changed, this checks
97 * if we are attached to proper manager, and if necessary updates.
99 static void update_manager(struct drm_plane
*plane
)
101 struct omap_drm_private
*priv
= plane
->dev
->dev_private
;
102 struct omap_plane
*omap_plane
= to_omap_plane(plane
);
103 struct omap_overlay
*ovl
= omap_plane
->ovl
;
104 struct omap_overlay_manager
*mgr
= NULL
;
108 for (i
= 0; i
< priv
->num_encoders
; i
++) {
109 struct drm_encoder
*encoder
= priv
->encoders
[i
];
110 if (encoder
->crtc
== plane
->crtc
) {
111 mgr
= omap_encoder_get_manager(encoder
);
117 if (ovl
->manager
!= mgr
) {
118 bool enabled
= ovl
->is_enabled(ovl
);
120 /* don't switch things around with enabled overlays: */
122 omap_plane_dpms(plane
, DRM_MODE_DPMS_OFF
);
125 DBG("disconnecting %s from %s", ovl
->name
,
127 ovl
->unset_manager(ovl
);
131 DBG("connecting %s to %s", ovl
->name
, mgr
->name
);
132 ovl
->set_manager(ovl
, mgr
);
136 omap_plane_dpms(plane
, DRM_MODE_DPMS_ON
);
140 /* update which fb (if any) is pinned for scanout */
141 static int update_pin(struct drm_plane
*plane
, struct drm_framebuffer
*fb
)
143 struct omap_plane
*omap_plane
= to_omap_plane(plane
);
146 if (omap_plane
->pinned_fb
!= fb
) {
147 if (omap_plane
->pinned_fb
)
148 omap_framebuffer_unpin(omap_plane
->pinned_fb
);
149 omap_plane
->pinned_fb
= fb
;
151 ret
= omap_framebuffer_pin(fb
);
157 /* update parameters that are dependent on the framebuffer dimensions and
158 * position within the fb that this plane scans out from. This is called
159 * when framebuffer or x,y base may have changed.
161 static void update_scanout(struct drm_plane
*plane
)
163 struct omap_plane
*omap_plane
= to_omap_plane(plane
);
164 struct omap_overlay_info
*info
= &omap_plane
->info
;
167 ret
= update_pin(plane
, plane
->fb
);
169 dev_err(plane
->dev
->dev
,
170 "could not pin fb: %d\n", ret
);
171 omap_plane_dpms(plane
, DRM_MODE_DPMS_OFF
);
175 omap_framebuffer_update_scanout(plane
->fb
,
176 omap_plane
->src_x
, omap_plane
->src_y
, info
);
178 DBG("%s: %d,%d: %08x %08x (%d)", omap_plane
->ovl
->name
,
179 omap_plane
->src_x
, omap_plane
->src_y
,
180 (u32
)info
->paddr
, (u32
)info
->p_uv_addr
,
184 int omap_plane_mode_set(struct drm_plane
*plane
,
185 struct drm_crtc
*crtc
, struct drm_framebuffer
*fb
,
186 int crtc_x
, int crtc_y
,
187 unsigned int crtc_w
, unsigned int crtc_h
,
188 uint32_t src_x
, uint32_t src_y
,
189 uint32_t src_w
, uint32_t src_h
)
191 struct omap_plane
*omap_plane
= to_omap_plane(plane
);
193 /* src values are in Q16 fixed point, convert to integer: */
199 omap_plane
->info
.pos_x
= crtc_x
;
200 omap_plane
->info
.pos_y
= crtc_y
;
201 omap_plane
->info
.out_width
= crtc_w
;
202 omap_plane
->info
.out_height
= crtc_h
;
203 omap_plane
->info
.width
= src_w
;
204 omap_plane
->info
.height
= src_h
;
205 omap_plane
->src_x
= src_x
;
206 omap_plane
->src_y
= src_y
;
208 /* note: this is done after this fxn returns.. but if we need
209 * to do a commit/update_scanout, etc before this returns we
210 * need the current value.
215 update_scanout(plane
);
216 update_manager(plane
);
221 static int omap_plane_update(struct drm_plane
*plane
,
222 struct drm_crtc
*crtc
, struct drm_framebuffer
*fb
,
223 int crtc_x
, int crtc_y
,
224 unsigned int crtc_w
, unsigned int crtc_h
,
225 uint32_t src_x
, uint32_t src_y
,
226 uint32_t src_w
, uint32_t src_h
)
228 omap_plane_mode_set(plane
, crtc
, fb
, crtc_x
, crtc_y
, crtc_w
, crtc_h
,
229 src_x
, src_y
, src_w
, src_h
);
230 return omap_plane_dpms(plane
, DRM_MODE_DPMS_ON
);
233 static int omap_plane_disable(struct drm_plane
*plane
)
235 return omap_plane_dpms(plane
, DRM_MODE_DPMS_OFF
);
238 static void omap_plane_destroy(struct drm_plane
*plane
)
240 struct omap_plane
*omap_plane
= to_omap_plane(plane
);
241 DBG("%s", omap_plane
->ovl
->name
);
242 omap_plane_disable(plane
);
243 drm_plane_cleanup(plane
);
247 int omap_plane_dpms(struct drm_plane
*plane
, int mode
)
249 struct omap_plane
*omap_plane
= to_omap_plane(plane
);
250 struct omap_overlay
*ovl
= omap_plane
->ovl
;
253 DBG("%s: %d", omap_plane
->ovl
->name
, mode
);
255 if (mode
== DRM_MODE_DPMS_ON
) {
256 update_scanout(plane
);
259 r
= ovl
->enable(ovl
);
261 r
= ovl
->disable(ovl
);
262 update_pin(plane
, NULL
);
268 static const struct drm_plane_funcs omap_plane_funcs
= {
269 .update_plane
= omap_plane_update
,
270 .disable_plane
= omap_plane_disable
,
271 .destroy
= omap_plane_destroy
,
274 static const uint32_t formats
[] = {
292 /* initialize plane */
293 struct drm_plane
*omap_plane_init(struct drm_device
*dev
,
294 struct omap_overlay
*ovl
, unsigned int possible_crtcs
,
297 struct drm_plane
*plane
= NULL
;
298 struct omap_plane
*omap_plane
;
300 DBG("%s: possible_crtcs=%08x, priv=%d", ovl
->name
,
301 possible_crtcs
, priv
);
303 omap_plane
= kzalloc(sizeof(*omap_plane
), GFP_KERNEL
);
305 dev_err(dev
->dev
, "could not allocate plane\n");
309 omap_plane
->ovl
= ovl
;
310 plane
= &omap_plane
->base
;
312 drm_plane_init(dev
, plane
, possible_crtcs
, &omap_plane_funcs
,
313 formats
, ARRAY_SIZE(formats
), priv
);
315 /* get our starting configuration, set defaults for parameters
316 * we don't currently use, etc:
318 ovl
->get_overlay_info(ovl
, &omap_plane
->info
);
319 omap_plane
->info
.rotation_type
= OMAP_DSS_ROT_DMA
;
320 omap_plane
->info
.rotation
= OMAP_DSS_ROT_0
;
321 omap_plane
->info
.global_alpha
= 0xff;
322 omap_plane
->info
.mirror
= 0;
323 omap_plane
->info
.mirror
= 0;
325 /* Set defaults depending on whether we are a CRTC or overlay
327 * TODO add ioctl to give userspace an API to change this.. this
328 * will come in a subsequent patch.
331 omap_plane
->info
.zorder
= 0;
333 omap_plane
->info
.zorder
= 1;
335 update_manager(plane
);
341 omap_plane_destroy(plane
);