2 * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
3 * Author: Rob Clark <rob.clark@linaro.org>
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 as published by
7 * the Free Software Foundation.
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * You should have received a copy of the GNU General Public License along with
15 * this program. If not, see <http://www.gnu.org/licenses/>.
18 #include <drm/drm_atomic.h>
19 #include <drm/drm_atomic_helper.h>
20 #include <drm/drm_plane_helper.h>
22 #include "omap_dmm_tiler.h"
29 #define to_omap_plane(x) container_of(x, struct omap_plane, base)
32 struct drm_plane base
;
33 enum omap_plane_id id
;
37 static int omap_plane_prepare_fb(struct drm_plane
*plane
,
38 struct drm_plane_state
*new_state
)
43 return omap_framebuffer_pin(new_state
->fb
);
46 static void omap_plane_cleanup_fb(struct drm_plane
*plane
,
47 struct drm_plane_state
*old_state
)
50 omap_framebuffer_unpin(old_state
->fb
);
53 static void omap_plane_atomic_update(struct drm_plane
*plane
,
54 struct drm_plane_state
*old_state
)
56 struct omap_drm_private
*priv
= plane
->dev
->dev_private
;
57 struct omap_plane
*omap_plane
= to_omap_plane(plane
);
58 struct drm_plane_state
*state
= plane
->state
;
59 struct omap_overlay_info info
;
62 DBG("%s, crtc=%p fb=%p", omap_plane
->name
, state
->crtc
, state
->fb
);
64 memset(&info
, 0, sizeof(info
));
65 info
.rotation_type
= OMAP_DSS_ROT_NONE
;
66 info
.rotation
= DRM_MODE_ROTATE_0
;
67 info
.global_alpha
= 0xff;
68 info
.zorder
= state
->zpos
;
71 omap_framebuffer_update_scanout(state
->fb
, state
, &info
);
73 DBG("%dx%d -> %dx%d (%d)", info
.width
, info
.height
,
74 info
.out_width
, info
.out_height
,
76 DBG("%d,%d %pad %pad", info
.pos_x
, info
.pos_y
,
77 &info
.paddr
, &info
.p_uv_addr
);
79 /* and finally, update omapdss: */
80 ret
= priv
->dispc_ops
->ovl_setup(omap_plane
->id
, &info
,
81 omap_crtc_timings(state
->crtc
), false,
82 omap_crtc_channel(state
->crtc
));
84 dev_err(plane
->dev
->dev
, "Failed to setup plane %s\n",
86 priv
->dispc_ops
->ovl_enable(omap_plane
->id
, false);
90 priv
->dispc_ops
->ovl_enable(omap_plane
->id
, true);
93 static void omap_plane_atomic_disable(struct drm_plane
*plane
,
94 struct drm_plane_state
*old_state
)
96 struct omap_drm_private
*priv
= plane
->dev
->dev_private
;
97 struct omap_plane
*omap_plane
= to_omap_plane(plane
);
99 plane
->state
->rotation
= DRM_MODE_ROTATE_0
;
100 plane
->state
->zpos
= plane
->type
== DRM_PLANE_TYPE_PRIMARY
101 ? 0 : omap_plane
->id
;
103 priv
->dispc_ops
->ovl_enable(omap_plane
->id
, false);
106 static int omap_plane_atomic_check(struct drm_plane
*plane
,
107 struct drm_plane_state
*state
)
109 struct drm_crtc_state
*crtc_state
;
114 /* crtc should only be NULL when disabling (i.e., !state->fb) */
115 if (WARN_ON(!state
->crtc
))
118 crtc_state
= drm_atomic_get_existing_crtc_state(state
->state
, state
->crtc
);
119 /* we should have a crtc state if the plane is attached to a crtc */
120 if (WARN_ON(!crtc_state
))
123 if (!crtc_state
->enable
)
126 if (state
->crtc_x
< 0 || state
->crtc_y
< 0)
129 if (state
->crtc_x
+ state
->crtc_w
> crtc_state
->adjusted_mode
.hdisplay
)
132 if (state
->crtc_y
+ state
->crtc_h
> crtc_state
->adjusted_mode
.vdisplay
)
135 if (state
->rotation
!= DRM_MODE_ROTATE_0
&&
136 !omap_framebuffer_supports_rotation(state
->fb
))
142 static const struct drm_plane_helper_funcs omap_plane_helper_funcs
= {
143 .prepare_fb
= omap_plane_prepare_fb
,
144 .cleanup_fb
= omap_plane_cleanup_fb
,
145 .atomic_check
= omap_plane_atomic_check
,
146 .atomic_update
= omap_plane_atomic_update
,
147 .atomic_disable
= omap_plane_atomic_disable
,
150 static void omap_plane_destroy(struct drm_plane
*plane
)
152 struct omap_plane
*omap_plane
= to_omap_plane(plane
);
154 DBG("%s", omap_plane
->name
);
156 drm_plane_cleanup(plane
);
161 /* helper to install properties which are common to planes and crtcs */
162 void omap_plane_install_properties(struct drm_plane
*plane
,
163 struct drm_mode_object
*obj
)
165 struct drm_device
*dev
= plane
->dev
;
166 struct omap_drm_private
*priv
= dev
->dev_private
;
169 if (!plane
->rotation_property
)
170 drm_plane_create_rotation_property(plane
,
172 DRM_MODE_ROTATE_0
| DRM_MODE_ROTATE_90
|
173 DRM_MODE_ROTATE_180
| DRM_MODE_ROTATE_270
|
174 DRM_MODE_REFLECT_X
| DRM_MODE_REFLECT_Y
);
176 /* Attach the rotation property also to the crtc object */
177 if (plane
->rotation_property
&& obj
!= &plane
->base
)
178 drm_object_attach_property(obj
, plane
->rotation_property
,
182 drm_object_attach_property(obj
, priv
->zorder_prop
, 0);
185 static void omap_plane_reset(struct drm_plane
*plane
)
187 struct omap_plane
*omap_plane
= to_omap_plane(plane
);
189 drm_atomic_helper_plane_reset(plane
);
194 * Set the zpos default depending on whether we are a primary or overlay
197 plane
->state
->zpos
= plane
->type
== DRM_PLANE_TYPE_PRIMARY
198 ? 0 : omap_plane
->id
;
201 static int omap_plane_atomic_set_property(struct drm_plane
*plane
,
202 struct drm_plane_state
*state
,
203 struct drm_property
*property
,
206 struct omap_drm_private
*priv
= plane
->dev
->dev_private
;
208 if (property
== priv
->zorder_prop
)
216 static int omap_plane_atomic_get_property(struct drm_plane
*plane
,
217 const struct drm_plane_state
*state
,
218 struct drm_property
*property
,
221 struct omap_drm_private
*priv
= plane
->dev
->dev_private
;
223 if (property
== priv
->zorder_prop
)
231 static const struct drm_plane_funcs omap_plane_funcs
= {
232 .update_plane
= drm_atomic_helper_update_plane
,
233 .disable_plane
= drm_atomic_helper_disable_plane
,
234 .reset
= omap_plane_reset
,
235 .destroy
= omap_plane_destroy
,
236 .atomic_duplicate_state
= drm_atomic_helper_plane_duplicate_state
,
237 .atomic_destroy_state
= drm_atomic_helper_plane_destroy_state
,
238 .atomic_set_property
= omap_plane_atomic_set_property
,
239 .atomic_get_property
= omap_plane_atomic_get_property
,
242 static const char *plane_id_to_name
[] = {
243 [OMAP_DSS_GFX
] = "gfx",
244 [OMAP_DSS_VIDEO1
] = "vid1",
245 [OMAP_DSS_VIDEO2
] = "vid2",
246 [OMAP_DSS_VIDEO3
] = "vid3",
249 static const enum omap_plane_id plane_idx_to_id
[] = {
256 /* initialize plane */
257 struct drm_plane
*omap_plane_init(struct drm_device
*dev
,
258 int idx
, enum drm_plane_type type
,
261 struct omap_drm_private
*priv
= dev
->dev_private
;
262 unsigned int num_planes
= priv
->dispc_ops
->get_num_ovls();
263 struct drm_plane
*plane
;
264 struct omap_plane
*omap_plane
;
265 enum omap_plane_id id
;
270 if (WARN_ON(idx
>= ARRAY_SIZE(plane_idx_to_id
)))
271 return ERR_PTR(-EINVAL
);
273 id
= plane_idx_to_id
[idx
];
275 DBG("%s: type=%d", plane_id_to_name
[id
], type
);
277 omap_plane
= kzalloc(sizeof(*omap_plane
), GFP_KERNEL
);
279 return ERR_PTR(-ENOMEM
);
281 formats
= priv
->dispc_ops
->ovl_get_color_modes(id
);
282 for (nformats
= 0; formats
[nformats
]; ++nformats
)
285 omap_plane
->name
= plane_id_to_name
[id
];
287 plane
= &omap_plane
->base
;
289 ret
= drm_universal_plane_init(dev
, plane
, possible_crtcs
,
290 &omap_plane_funcs
, formats
,
291 nformats
, NULL
, type
, NULL
);
295 drm_plane_helper_add(plane
, &omap_plane_helper_funcs
);
297 omap_plane_install_properties(plane
, &plane
->base
);
298 drm_plane_create_zpos_property(plane
, 0, 0, num_planes
- 1);
303 dev_err(dev
->dev
, "%s(): could not create plane: %s\n",
304 __func__
, plane_id_to_name
[id
]);