drm: Plumb modifiers through plane init
[linux-2.6-block.git] / drivers / gpu / drm / omapdrm / omap_plane.c
CommitLineData
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
33struct omap_plane {
34 struct drm_plane base;
694c99cf 35 enum omap_plane_id id;
f5f9454c 36 const char *name;
a890e662 37};
bb5c2d9a 38
11ffd031 39static 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
48static 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
55static 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
95static 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
108static 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
144static 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
152static 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 */
164void 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
187static 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
203static 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
218static 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 233static 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 245static 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
252static 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 */
260struct 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
305error:
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}