Commit | Line | Data |
---|---|---|
bb5c2d9a | 1 | /* |
8bb0daff | 2 | * drivers/gpu/drm/omapdrm/omap_plane.c |
bb5c2d9a RC |
3 | * |
4 | * Copyright (C) 2011 Texas Instruments | |
5 | * Author: Rob Clark <rob.clark@linaro.org> | |
6 | * | |
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. | |
10 | * | |
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 | |
14 | * more details. | |
15 | * | |
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/>. | |
18 | */ | |
19 | ||
c423bc85 | 20 | #include <drm/drm_atomic.h> |
69a12263 | 21 | #include <drm/drm_atomic_helper.h> |
de8e4100 | 22 | #include <drm/drm_plane_helper.h> |
69a12263 | 23 | |
3c810c61 | 24 | #include "omap_dmm_tiler.h" |
2d278f54 | 25 | #include "omap_drv.h" |
bb5c2d9a | 26 | |
bb5c2d9a RC |
27 | /* |
28 | * plane funcs | |
29 | */ | |
30 | ||
31 | #define to_omap_plane(x) container_of(x, struct omap_plane, base) | |
32 | ||
33 | struct omap_plane { | |
34 | struct drm_plane base; | |
694c99cf | 35 | enum omap_plane_id id; |
f5f9454c | 36 | const char *name; |
a890e662 | 37 | }; |
bb5c2d9a | 38 | |
11ffd031 | 39 | static int omap_plane_prepare_fb(struct drm_plane *plane, |
1832040d | 40 | struct drm_plane_state *new_state) |
11ffd031 | 41 | { |
844f9111 ML |
42 | if (!new_state->fb) |
43 | return 0; | |
44 | ||
45 | return omap_framebuffer_pin(new_state->fb); | |
11ffd031 TV |
46 | } |
47 | ||
48 | static void omap_plane_cleanup_fb(struct drm_plane *plane, | |
1832040d | 49 | struct drm_plane_state *old_state) |
11ffd031 | 50 | { |
844f9111 ML |
51 | if (old_state->fb) |
52 | omap_framebuffer_unpin(old_state->fb); | |
11ffd031 TV |
53 | } |
54 | ||
55 | static void omap_plane_atomic_update(struct drm_plane *plane, | |
56 | struct drm_plane_state *old_state) | |
afc34932 | 57 | { |
9f759225 | 58 | struct omap_drm_private *priv = plane->dev->dev_private; |
edc72557 LP |
59 | struct omap_plane *omap_plane = to_omap_plane(plane); |
60 | struct drm_plane_state *state = plane->state; | |
fb730c9b | 61 | struct omap_overlay_info info; |
9a0774e0 | 62 | int ret; |
bb5c2d9a | 63 | |
edc72557 | 64 | DBG("%s, crtc=%p fb=%p", omap_plane->name, state->crtc, state->fb); |
f5f9454c | 65 | |
fb730c9b | 66 | memset(&info, 0, sizeof(info)); |
517a8a95 | 67 | info.rotation_type = OMAP_DSS_ROT_NONE; |
0bd97c42 | 68 | info.rotation = DRM_MODE_ROTATE_0; |
fb730c9b | 69 | info.global_alpha = 0xff; |
ba527c13 | 70 | info.zorder = state->zpos; |
fb730c9b | 71 | |
f5f9454c | 72 | /* update scanout: */ |
218ed535 | 73 | omap_framebuffer_update_scanout(state->fb, state, &info); |
bb5c2d9a | 74 | |
fb730c9b LP |
75 | DBG("%dx%d -> %dx%d (%d)", info.width, info.height, |
76 | info.out_width, info.out_height, | |
77 | info.screen_width); | |
78 | DBG("%d,%d %pad %pad", info.pos_x, info.pos_y, | |
79 | &info.paddr, &info.p_uv_addr); | |
f5f9454c | 80 | |
f5f9454c | 81 | /* and finally, update omapdss: */ |
be2d68c6 | 82 | ret = priv->dispc_ops->ovl_setup(omap_plane->id, &info, |
49a3057a TV |
83 | omap_crtc_timings(state->crtc), false, |
84 | omap_crtc_channel(state->crtc)); | |
cfb73f20 TV |
85 | if (ret) { |
86 | dev_err(plane->dev->dev, "Failed to setup plane %s\n", | |
87 | omap_plane->name); | |
9f759225 | 88 | priv->dispc_ops->ovl_enable(omap_plane->id, false); |
d9157dfd | 89 | return; |
794a65ff | 90 | } |
f5f9454c | 91 | |
9f759225 | 92 | priv->dispc_ops->ovl_enable(omap_plane->id, true); |
de8e4100 LP |
93 | } |
94 | ||
de8e4100 LP |
95 | static void omap_plane_atomic_disable(struct drm_plane *plane, |
96 | struct drm_plane_state *old_state) | |
bb5c2d9a | 97 | { |
9f759225 | 98 | struct omap_drm_private *priv = plane->dev->dev_private; |
3c810c61 | 99 | struct omap_plane *omap_plane = to_omap_plane(plane); |
2debab97 | 100 | |
c2c446ad | 101 | plane->state->rotation = DRM_MODE_ROTATE_0; |
ba527c13 | 102 | plane->state->zpos = plane->type == DRM_PLANE_TYPE_PRIMARY |
afc34932 | 103 | ? 0 : omap_plane->id; |
82e58855 | 104 | |
9f759225 | 105 | priv->dispc_ops->ovl_enable(omap_plane->id, false); |
bb5c2d9a RC |
106 | } |
107 | ||
c423bc85 TV |
108 | static int omap_plane_atomic_check(struct drm_plane *plane, |
109 | struct drm_plane_state *state) | |
110 | { | |
111 | struct drm_crtc_state *crtc_state; | |
112 | ||
70dd2a62 | 113 | if (!state->fb) |
c423bc85 TV |
114 | return 0; |
115 | ||
70dd2a62 TV |
116 | /* crtc should only be NULL when disabling (i.e., !state->fb) */ |
117 | if (WARN_ON(!state->crtc)) | |
118 | return 0; | |
119 | ||
120 | crtc_state = drm_atomic_get_existing_crtc_state(state->state, state->crtc); | |
121 | /* we should have a crtc state if the plane is attached to a crtc */ | |
122 | if (WARN_ON(!crtc_state)) | |
123 | return 0; | |
c423bc85 | 124 | |
aaf7642e TV |
125 | if (!crtc_state->enable) |
126 | return 0; | |
127 | ||
c423bc85 TV |
128 | if (state->crtc_x < 0 || state->crtc_y < 0) |
129 | return -EINVAL; | |
130 | ||
131 | if (state->crtc_x + state->crtc_w > crtc_state->adjusted_mode.hdisplay) | |
132 | return -EINVAL; | |
133 | ||
134 | if (state->crtc_y + state->crtc_h > crtc_state->adjusted_mode.vdisplay) | |
135 | return -EINVAL; | |
136 | ||
c2c446ad | 137 | if (state->rotation != DRM_MODE_ROTATE_0 && |
70dd2a62 TV |
138 | !omap_framebuffer_supports_rotation(state->fb)) |
139 | return -EINVAL; | |
bfeece55 | 140 | |
c423bc85 TV |
141 | return 0; |
142 | } | |
143 | ||
de8e4100 LP |
144 | static const struct drm_plane_helper_funcs omap_plane_helper_funcs = { |
145 | .prepare_fb = omap_plane_prepare_fb, | |
146 | .cleanup_fb = omap_plane_cleanup_fb, | |
c423bc85 | 147 | .atomic_check = omap_plane_atomic_check, |
de8e4100 LP |
148 | .atomic_update = omap_plane_atomic_update, |
149 | .atomic_disable = omap_plane_atomic_disable, | |
150 | }; | |
151 | ||
bb5c2d9a RC |
152 | static void omap_plane_destroy(struct drm_plane *plane) |
153 | { | |
154 | struct omap_plane *omap_plane = to_omap_plane(plane); | |
f5f9454c RC |
155 | |
156 | DBG("%s", omap_plane->name); | |
157 | ||
bb5c2d9a | 158 | drm_plane_cleanup(plane); |
f5f9454c | 159 | |
bb5c2d9a RC |
160 | kfree(omap_plane); |
161 | } | |
162 | ||
3c810c61 RC |
163 | /* helper to install properties which are common to planes and crtcs */ |
164 | void omap_plane_install_properties(struct drm_plane *plane, | |
165 | struct drm_mode_object *obj) | |
166 | { | |
167 | struct drm_device *dev = plane->dev; | |
168 | struct omap_drm_private *priv = dev->dev_private; | |
3c810c61 | 169 | |
c2a6a552 | 170 | if (priv->has_dmm) { |
0da88db1 VS |
171 | if (!plane->rotation_property) |
172 | drm_plane_create_rotation_property(plane, | |
c2c446ad RF |
173 | DRM_MODE_ROTATE_0, |
174 | DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_90 | | |
175 | DRM_MODE_ROTATE_180 | DRM_MODE_ROTATE_270 | | |
176 | DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y); | |
0da88db1 VS |
177 | |
178 | /* Attach the rotation property also to the crtc object */ | |
179 | if (plane->rotation_property && obj != &plane->base) | |
180 | drm_object_attach_property(obj, plane->rotation_property, | |
c2c446ad | 181 | DRM_MODE_ROTATE_0); |
3c810c61 | 182 | } |
8451b5ad | 183 | |
e2cd09b2 | 184 | drm_object_attach_property(obj, priv->zorder_prop, 0); |
3c810c61 RC |
185 | } |
186 | ||
e07323cf TV |
187 | static void omap_plane_reset(struct drm_plane *plane) |
188 | { | |
189 | struct omap_plane *omap_plane = to_omap_plane(plane); | |
e07323cf | 190 | |
d980278b LP |
191 | drm_atomic_helper_plane_reset(plane); |
192 | if (!plane->state) | |
e07323cf TV |
193 | return; |
194 | ||
195 | /* | |
ba527c13 | 196 | * Set the zpos default depending on whether we are a primary or overlay |
e07323cf TV |
197 | * plane. |
198 | */ | |
d980278b LP |
199 | plane->state->zpos = plane->type == DRM_PLANE_TYPE_PRIMARY |
200 | ? 0 : omap_plane->id; | |
e07323cf TV |
201 | } |
202 | ||
afc34932 LP |
203 | static int omap_plane_atomic_set_property(struct drm_plane *plane, |
204 | struct drm_plane_state *state, | |
205 | struct drm_property *property, | |
206 | uint64_t val) | |
3c810c61 | 207 | { |
3c810c61 | 208 | struct omap_drm_private *priv = plane->dev->dev_private; |
3c810c61 | 209 | |
afc34932 | 210 | if (property == priv->zorder_prop) |
ba527c13 | 211 | state->zpos = val; |
afc34932 | 212 | else |
a42133a7 | 213 | return -EINVAL; |
3c810c61 | 214 | |
afc34932 LP |
215 | return 0; |
216 | } | |
a42133a7 | 217 | |
afc34932 LP |
218 | static int omap_plane_atomic_get_property(struct drm_plane *plane, |
219 | const struct drm_plane_state *state, | |
220 | struct drm_property *property, | |
221 | uint64_t *val) | |
222 | { | |
223 | struct omap_drm_private *priv = plane->dev->dev_private; | |
afc34932 LP |
224 | |
225 | if (property == priv->zorder_prop) | |
ba527c13 | 226 | *val = state->zpos; |
afc34932 LP |
227 | else |
228 | return -EINVAL; | |
a42133a7 | 229 | |
afc34932 | 230 | return 0; |
3c810c61 RC |
231 | } |
232 | ||
bb5c2d9a | 233 | static const struct drm_plane_funcs omap_plane_funcs = { |
cef77d40 LP |
234 | .update_plane = drm_atomic_helper_update_plane, |
235 | .disable_plane = drm_atomic_helper_disable_plane, | |
afc34932 | 236 | .reset = omap_plane_reset, |
222025e4 | 237 | .destroy = omap_plane_destroy, |
afc34932 | 238 | .set_property = drm_atomic_helper_plane_set_property, |
d980278b LP |
239 | .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, |
240 | .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, | |
afc34932 LP |
241 | .atomic_set_property = omap_plane_atomic_set_property, |
242 | .atomic_get_property = omap_plane_atomic_get_property, | |
bb5c2d9a RC |
243 | }; |
244 | ||
e8e13b15 | 245 | static const char *plane_id_to_name[] = { |
222025e4 LP |
246 | [OMAP_DSS_GFX] = "gfx", |
247 | [OMAP_DSS_VIDEO1] = "vid1", | |
248 | [OMAP_DSS_VIDEO2] = "vid2", | |
249 | [OMAP_DSS_VIDEO3] = "vid3", | |
f5f9454c RC |
250 | }; |
251 | ||
e8e13b15 JS |
252 | static const enum omap_plane_id plane_idx_to_id[] = { |
253 | OMAP_DSS_GFX, | |
254 | OMAP_DSS_VIDEO1, | |
255 | OMAP_DSS_VIDEO2, | |
256 | OMAP_DSS_VIDEO3, | |
257 | }; | |
258 | ||
bb5c2d9a RC |
259 | /* initialize plane */ |
260 | struct drm_plane *omap_plane_init(struct drm_device *dev, | |
e8e13b15 | 261 | int idx, enum drm_plane_type type, |
e43f2c33 | 262 | u32 possible_crtcs) |
bb5c2d9a | 263 | { |
9f759225 | 264 | struct omap_drm_private *priv = dev->dev_private; |
dff6c246 | 265 | unsigned int num_planes = priv->dispc_ops->get_num_ovls(); |
ef6b0e02 | 266 | struct drm_plane *plane; |
bb5c2d9a | 267 | struct omap_plane *omap_plane; |
e8e13b15 | 268 | enum omap_plane_id id; |
ef6b0e02 | 269 | int ret; |
eecad437 TV |
270 | u32 nformats; |
271 | const u32 *formats; | |
bb5c2d9a | 272 | |
e8e13b15 JS |
273 | if (WARN_ON(idx >= ARRAY_SIZE(plane_idx_to_id))) |
274 | return ERR_PTR(-EINVAL); | |
275 | ||
276 | id = plane_idx_to_id[idx]; | |
277 | ||
278 | DBG("%s: type=%d", plane_id_to_name[id], type); | |
b33f34d3 | 279 | |
bb5c2d9a | 280 | omap_plane = kzalloc(sizeof(*omap_plane), GFP_KERNEL); |
78110bb8 | 281 | if (!omap_plane) |
fb9a35f8 | 282 | return ERR_PTR(-ENOMEM); |
bb5c2d9a | 283 | |
eecad437 TV |
284 | formats = priv->dispc_ops->ovl_get_color_modes(id); |
285 | for (nformats = 0; formats[nformats]; ++nformats) | |
286 | ; | |
f5f9454c | 287 | omap_plane->id = id; |
e8e13b15 | 288 | omap_plane->name = plane_id_to_name[id]; |
f5f9454c | 289 | |
bb5c2d9a RC |
290 | plane = &omap_plane->base; |
291 | ||
e43f2c33 | 292 | ret = drm_universal_plane_init(dev, plane, possible_crtcs, |
eecad437 | 293 | &omap_plane_funcs, formats, |
e6fc3b68 | 294 | nformats, NULL, type, NULL); |
ef6b0e02 LP |
295 | if (ret < 0) |
296 | goto error; | |
bb5c2d9a | 297 | |
de8e4100 LP |
298 | drm_plane_helper_add(plane, &omap_plane_helper_funcs); |
299 | ||
3c810c61 | 300 | omap_plane_install_properties(plane, &plane->base); |
dff6c246 | 301 | drm_plane_create_zpos_property(plane, 0, 0, num_planes - 1); |
3c810c61 | 302 | |
bb5c2d9a | 303 | return plane; |
ef6b0e02 LP |
304 | |
305 | error: | |
e8e13b15 JS |
306 | dev_err(dev->dev, "%s(): could not create plane: %s\n", |
307 | __func__, plane_id_to_name[id]); | |
308 | ||
ef6b0e02 LP |
309 | kfree(omap_plane); |
310 | return NULL; | |
bb5c2d9a | 311 | } |