aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging
diff options
context:
space:
mode:
authorRob Clark <rob@ti.com>2012-01-16 13:51:16 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-02-08 17:14:11 -0500
commitbb5c2d9aaaa26a55e684c175c431df95aa178233 (patch)
tree4441d1b8c9f04577ff21fa578fa16aad667cc9e6 /drivers/staging
parentae43d7ca4047b126adedcf7028c1ff99ed18703c (diff)
staging: drm/omap: add drm_plane support
Because framebuffer layer and overlay scanout video pipes are basically thing in OMAP display subsystem (the only difference being that the first video pipe does not support scaling or YUV formats), much of the CRTC code is pulled into the plane implementation, and a private plane object is used by the CRTC object. This avoids code duplication between the plane and CRTC. Signed-off-by: Rob Clark <rob@ti.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/staging')
-rw-r--r--drivers/staging/omapdrm/Makefile1
-rw-r--r--drivers/staging/omapdrm/omap_crtc.c189
-rw-r--r--drivers/staging/omapdrm/omap_drv.c53
-rw-r--r--drivers/staging/omapdrm/omap_drv.h8
-rw-r--r--drivers/staging/omapdrm/omap_plane.c308
-rw-r--r--drivers/staging/omapdrm/omap_priv.h12
6 files changed, 403 insertions, 168 deletions
diff --git a/drivers/staging/omapdrm/Makefile b/drivers/staging/omapdrm/Makefile
index 592cf69020cd..d9cdc120d122 100644
--- a/drivers/staging/omapdrm/Makefile
+++ b/drivers/staging/omapdrm/Makefile
@@ -7,6 +7,7 @@ ccflags-y := -Iinclude/drm -Werror
7omapdrm-y := omap_drv.o \ 7omapdrm-y := omap_drv.o \
8 omap_debugfs.o \ 8 omap_debugfs.o \
9 omap_crtc.o \ 9 omap_crtc.o \
10 omap_plane.o \
10 omap_encoder.o \ 11 omap_encoder.o \
11 omap_connector.o \ 12 omap_connector.o \
12 omap_fb.o \ 13 omap_fb.o \
diff --git a/drivers/staging/omapdrm/omap_crtc.c b/drivers/staging/omapdrm/omap_crtc.c
index cffdf5e12394..a91c78898019 100644
--- a/drivers/staging/omapdrm/omap_crtc.c
+++ b/drivers/staging/omapdrm/omap_crtc.c
@@ -27,196 +27,95 @@
27 27
28struct omap_crtc { 28struct omap_crtc {
29 struct drm_crtc base; 29 struct drm_crtc base;
30 struct omap_overlay *ovl; 30 struct drm_plane *plane;
31 struct omap_overlay_info info; 31 const char *name;
32 int id; 32 int id;
33 33
34 /* if there is a pending flip, this will be non-null: */ 34 /* if there is a pending flip, these will be non-null: */
35 struct drm_pending_vblank_event *event; 35 struct drm_pending_vblank_event *event;
36 struct drm_framebuffer *old_fb;
36}; 37};
37 38
38/* push changes down to dss2 */
39static int commit(struct drm_crtc *crtc)
40{
41 struct drm_device *dev = crtc->dev;
42 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
43 struct omap_overlay *ovl = omap_crtc->ovl;
44 struct omap_overlay_info *info = &omap_crtc->info;
45 int ret;
46
47 DBG("%s", omap_crtc->ovl->name);
48 DBG("%dx%d -> %dx%d (%d)", info->width, info->height, info->out_width,
49 info->out_height, info->screen_width);
50 DBG("%d,%d %08x", info->pos_x, info->pos_y, info->paddr);
51
52 /* NOTE: do we want to do this at all here, or just wait
53 * for dpms(ON) since other CRTC's may not have their mode
54 * set yet, so fb dimensions may still change..
55 */
56 ret = ovl->set_overlay_info(ovl, info);
57 if (ret) {
58 dev_err(dev->dev, "could not set overlay info\n");
59 return ret;
60 }
61
62 /* our encoder doesn't necessarily get a commit() after this, in
63 * particular in the dpms() and mode_set_base() cases, so force the
64 * manager to update:
65 *
66 * could this be in the encoder somehow?
67 */
68 if (ovl->manager) {
69 ret = ovl->manager->apply(ovl->manager);
70 if (ret) {
71 dev_err(dev->dev, "could not apply settings\n");
72 return ret;
73 }
74 }
75
76 if (info->enabled) {
77 omap_framebuffer_flush(crtc->fb, crtc->x, crtc->y,
78 crtc->fb->width, crtc->fb->height);
79 }
80
81 return 0;
82}
83
84/* update parameters that are dependent on the framebuffer dimensions and
85 * position within the fb that this crtc scans out from. This is called
86 * when framebuffer dimensions or x,y base may have changed, either due
87 * to our mode, or a change in another crtc that is scanning out of the
88 * same fb.
89 */
90static void update_scanout(struct drm_crtc *crtc)
91{
92 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
93 dma_addr_t paddr;
94 unsigned int screen_width;
95
96 omap_framebuffer_get_buffer(crtc->fb, crtc->x, crtc->y,
97 NULL, &paddr, &screen_width);
98
99 DBG("%s: %d,%d: %08x (%d)", omap_crtc->ovl->name,
100 crtc->x, crtc->y, (u32)paddr, screen_width);
101
102 omap_crtc->info.paddr = paddr;
103 omap_crtc->info.screen_width = screen_width;
104}
105
106static void omap_crtc_gamma_set(struct drm_crtc *crtc, 39static void omap_crtc_gamma_set(struct drm_crtc *crtc,
107 u16 *red, u16 *green, u16 *blue, uint32_t start, uint32_t size) 40 u16 *red, u16 *green, u16 *blue, uint32_t start, uint32_t size)
108{ 41{
109 struct omap_crtc *omap_crtc = to_omap_crtc(crtc); 42 /* not supported.. at least not yet */
110 DBG("%s", omap_crtc->ovl->name);
111} 43}
112 44
113static void omap_crtc_destroy(struct drm_crtc *crtc) 45static void omap_crtc_destroy(struct drm_crtc *crtc)
114{ 46{
115 struct omap_crtc *omap_crtc = to_omap_crtc(crtc); 47 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
116 DBG("%s", omap_crtc->ovl->name); 48 omap_crtc->plane->funcs->destroy(omap_crtc->plane);
117 drm_crtc_cleanup(crtc); 49 drm_crtc_cleanup(crtc);
118 kfree(omap_crtc); 50 kfree(omap_crtc);
119} 51}
120 52
121static void omap_crtc_dpms(struct drm_crtc *crtc, int mode) 53static void omap_crtc_dpms(struct drm_crtc *crtc, int mode)
122{ 54{
55 struct omap_drm_private *priv = crtc->dev->dev_private;
123 struct omap_crtc *omap_crtc = to_omap_crtc(crtc); 56 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
57 int i;
124 58
125 DBG("%s: %d", omap_crtc->ovl->name, mode); 59 WARN_ON(omap_plane_dpms(omap_crtc->plane, mode));
126 60
127 if (mode == DRM_MODE_DPMS_ON) { 61 for (i = 0; i < priv->num_planes; i++) {
128 update_scanout(crtc); 62 struct drm_plane *plane = priv->planes[i];
129 omap_crtc->info.enabled = true; 63 if (plane->crtc == crtc)
130 } else { 64 WARN_ON(omap_plane_dpms(plane, mode));
131 omap_crtc->info.enabled = false;
132 } 65 }
133
134 WARN_ON(commit(crtc));
135} 66}
136 67
137static bool omap_crtc_mode_fixup(struct drm_crtc *crtc, 68static bool omap_crtc_mode_fixup(struct drm_crtc *crtc,
138 struct drm_display_mode *mode, 69 struct drm_display_mode *mode,
139 struct drm_display_mode *adjusted_mode) 70 struct drm_display_mode *adjusted_mode)
140{ 71{
141 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
142 DBG("%s", omap_crtc->ovl->name);
143 return true; 72 return true;
144} 73}
145 74
146static int omap_crtc_mode_set(struct drm_crtc *crtc, 75static int omap_crtc_mode_set(struct drm_crtc *crtc,
147 struct drm_display_mode *mode, 76 struct drm_display_mode *mode,
148 struct drm_display_mode *adjusted_mode, 77 struct drm_display_mode *adjusted_mode,
149 int x, int y, 78 int x, int y,
150 struct drm_framebuffer *old_fb) 79 struct drm_framebuffer *old_fb)
151{ 80{
152 struct omap_crtc *omap_crtc = to_omap_crtc(crtc); 81 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
82 struct drm_plane *plane = omap_crtc->plane;
153 83
154 DBG("%s: %d,%d: %dx%d", omap_crtc->ovl->name, x, y, 84 return plane->funcs->update_plane(plane, crtc, crtc->fb,
155 mode->hdisplay, mode->vdisplay); 85 0, 0, mode->hdisplay, mode->vdisplay,
156 86 x << 16, y << 16,
157 /* just use adjusted mode */ 87 mode->hdisplay << 16, mode->vdisplay << 16);
158 mode = adjusted_mode;
159
160 omap_crtc->info.width = mode->hdisplay;
161 omap_crtc->info.height = mode->vdisplay;
162 omap_crtc->info.out_width = mode->hdisplay;
163 omap_crtc->info.out_height = mode->vdisplay;
164 omap_crtc->info.color_mode = OMAP_DSS_COLOR_RGB24U;
165 omap_crtc->info.rotation_type = OMAP_DSS_ROT_DMA;
166 omap_crtc->info.rotation = OMAP_DSS_ROT_0;
167 omap_crtc->info.global_alpha = 0xff;
168 omap_crtc->info.mirror = 0;
169 omap_crtc->info.mirror = 0;
170 omap_crtc->info.pos_x = 0;
171 omap_crtc->info.pos_y = 0;
172#if 0 /* re-enable when these are available in DSS2 driver */
173 omap_crtc->info.zorder = 3; /* GUI in the front, video behind */
174 omap_crtc->info.min_x_decim = 1;
175 omap_crtc->info.max_x_decim = 1;
176 omap_crtc->info.min_y_decim = 1;
177 omap_crtc->info.max_y_decim = 1;
178#endif
179
180 update_scanout(crtc);
181
182 return 0;
183} 88}
184 89
185static void omap_crtc_prepare(struct drm_crtc *crtc) 90static void omap_crtc_prepare(struct drm_crtc *crtc)
186{ 91{
187 struct omap_crtc *omap_crtc = to_omap_crtc(crtc); 92 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
188 struct omap_overlay *ovl = omap_crtc->ovl; 93 DBG("%s", omap_crtc->name);
189
190 DBG("%s", omap_crtc->ovl->name);
191
192 ovl->get_overlay_info(ovl, &omap_crtc->info);
193
194 omap_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); 94 omap_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
195} 95}
196 96
197static void omap_crtc_commit(struct drm_crtc *crtc) 97static void omap_crtc_commit(struct drm_crtc *crtc)
198{ 98{
199 struct omap_crtc *omap_crtc = to_omap_crtc(crtc); 99 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
200 DBG("%s", omap_crtc->ovl->name); 100 DBG("%s", omap_crtc->name);
201 omap_crtc_dpms(crtc, DRM_MODE_DPMS_ON); 101 omap_crtc_dpms(crtc, DRM_MODE_DPMS_ON);
202} 102}
203 103
204static int omap_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, 104static int omap_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
205 struct drm_framebuffer *old_fb) 105 struct drm_framebuffer *old_fb)
206{ 106{
207 struct omap_crtc *omap_crtc = to_omap_crtc(crtc); 107 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
108 struct drm_plane *plane = omap_crtc->plane;
109 struct drm_display_mode *mode = &crtc->mode;
208 110
209 DBG("%s %d,%d: fb=%p", omap_crtc->ovl->name, x, y, old_fb); 111 return plane->funcs->update_plane(plane, crtc, crtc->fb,
210 112 0, 0, mode->hdisplay, mode->vdisplay,
211 update_scanout(crtc); 113 x << 16, y << 16,
212 114 mode->hdisplay << 16, mode->vdisplay << 16);
213 return commit(crtc);
214} 115}
215 116
216static void omap_crtc_load_lut(struct drm_crtc *crtc) 117static void omap_crtc_load_lut(struct drm_crtc *crtc)
217{ 118{
218 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
219 DBG("%s", omap_crtc->ovl->name);
220} 119}
221 120
222static void page_flip_cb(void *arg) 121static void page_flip_cb(void *arg)
@@ -225,15 +124,16 @@ static void page_flip_cb(void *arg)
225 struct drm_device *dev = crtc->dev; 124 struct drm_device *dev = crtc->dev;
226 struct omap_crtc *omap_crtc = to_omap_crtc(crtc); 125 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
227 struct drm_pending_vblank_event *event = omap_crtc->event; 126 struct drm_pending_vblank_event *event = omap_crtc->event;
127 struct drm_framebuffer *old_fb = omap_crtc->old_fb;
228 struct timeval now; 128 struct timeval now;
229 unsigned long flags; 129 unsigned long flags;
230 130
231 WARN_ON(!event); 131 WARN_ON(!event);
232 132
233 omap_crtc->event = NULL; 133 omap_crtc->event = NULL;
134 omap_crtc->old_fb = NULL;
234 135
235 update_scanout(crtc); 136 omap_crtc_mode_set_base(crtc, crtc->x, crtc->y, old_fb);
236 WARN_ON(commit(crtc));
237 137
238 /* wakeup userspace */ 138 /* wakeup userspace */
239 /* TODO: this should happen *after* flip in vsync IRQ handler */ 139 /* TODO: this should happen *after* flip in vsync IRQ handler */
@@ -264,8 +164,9 @@ static int omap_crtc_page_flip_locked(struct drm_crtc *crtc,
264 return -EINVAL; 164 return -EINVAL;
265 } 165 }
266 166
267 crtc->fb = fb; 167 omap_crtc->old_fb = crtc->fb;
268 omap_crtc->event = event; 168 omap_crtc->event = event;
169 crtc->fb = fb;
269 170
270 omap_gem_op_async(omap_framebuffer_bo(fb), OMAP_GEM_READ, 171 omap_gem_op_async(omap_framebuffer_bo(fb), OMAP_GEM_READ,
271 page_flip_cb, crtc); 172 page_flip_cb, crtc);
@@ -290,12 +191,6 @@ static const struct drm_crtc_helper_funcs omap_crtc_helper_funcs = {
290 .load_lut = omap_crtc_load_lut, 191 .load_lut = omap_crtc_load_lut,
291}; 192};
292 193
293struct omap_overlay *omap_crtc_get_overlay(struct drm_crtc *crtc)
294{
295 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
296 return omap_crtc->ovl;
297}
298
299/* initialize crtc */ 194/* initialize crtc */
300struct drm_crtc *omap_crtc_init(struct drm_device *dev, 195struct drm_crtc *omap_crtc_init(struct drm_device *dev,
301 struct omap_overlay *ovl, int id) 196 struct omap_overlay *ovl, int id)
@@ -310,9 +205,13 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev,
310 goto fail; 205 goto fail;
311 } 206 }
312 207
313 omap_crtc->ovl = ovl;
314 omap_crtc->id = id;
315 crtc = &omap_crtc->base; 208 crtc = &omap_crtc->base;
209
210 omap_crtc->plane = omap_plane_init(dev, ovl, (1 << id), true);
211 omap_crtc->plane->crtc = crtc;
212 omap_crtc->name = ovl->name;
213 omap_crtc->id = id;
214
316 drm_crtc_init(dev, crtc, &omap_crtc_funcs); 215 drm_crtc_init(dev, crtc, &omap_crtc_funcs);
317 drm_crtc_helper_add(crtc, &omap_crtc_helper_funcs); 216 drm_crtc_helper_add(crtc, &omap_crtc_helper_funcs);
318 217
diff --git a/drivers/staging/omapdrm/omap_drv.c b/drivers/staging/omapdrm/omap_drv.c
index 4db40f717b94..2de99ffecc51 100644
--- a/drivers/staging/omapdrm/omap_drv.c
+++ b/drivers/staging/omapdrm/omap_drv.c
@@ -204,12 +204,6 @@ static int create_crtc(struct drm_device *dev, struct omap_overlay *ovl,
204 struct omap_overlay_manager *mgr = NULL; 204 struct omap_overlay_manager *mgr = NULL;
205 struct drm_crtc *crtc; 205 struct drm_crtc *crtc;
206 206
207 if (ovl->manager) {
208 DBG("disconnecting %s from %s", ovl->name,
209 ovl->manager->name);
210 ovl->unset_manager(ovl);
211 }
212
213 /* find next best connector, ones with detected connection first 207 /* find next best connector, ones with detected connection first
214 */ 208 */
215 while (*j < priv->num_connectors && !mgr) { 209 while (*j < priv->num_connectors && !mgr) {
@@ -245,11 +239,6 @@ static int create_crtc(struct drm_device *dev, struct omap_overlay *ovl,
245 (*j)++; 239 (*j)++;
246 } 240 }
247 241
248 if (mgr) {
249 DBG("connecting %s to %s", ovl->name, mgr->name);
250 ovl->set_manager(ovl, mgr);
251 }
252
253 crtc = omap_crtc_init(dev, ovl, priv->num_crtcs); 242 crtc = omap_crtc_init(dev, ovl, priv->num_crtcs);
254 243
255 if (!crtc) { 244 if (!crtc) {
@@ -265,6 +254,26 @@ static int create_crtc(struct drm_device *dev, struct omap_overlay *ovl,
265 return 0; 254 return 0;
266} 255}
267 256
257static int create_plane(struct drm_device *dev, struct omap_overlay *ovl,
258 unsigned int possible_crtcs)
259{
260 struct omap_drm_private *priv = dev->dev_private;
261 struct drm_plane *plane =
262 omap_plane_init(dev, ovl, possible_crtcs, false);
263
264 if (!plane) {
265 dev_err(dev->dev, "could not create plane: %s\n",
266 ovl->name);
267 return -ENOMEM;
268 }
269
270 BUG_ON(priv->num_planes >= ARRAY_SIZE(priv->planes));
271
272 priv->planes[priv->num_planes++] = plane;
273
274 return 0;
275}
276
268static int match_dev_name(struct omap_dss_device *dssdev, void *data) 277static int match_dev_name(struct omap_dss_device *dssdev, void *data)
269{ 278{
270 return !strcmp(dssdev->name, data); 279 return !strcmp(dssdev->name, data);
@@ -332,6 +341,12 @@ static int omap_modeset_init(struct drm_device *dev)
332 omap_dss_get_overlay(kms_pdata->ovl_ids[i]); 341 omap_dss_get_overlay(kms_pdata->ovl_ids[i]);
333 create_crtc(dev, ovl, &j, connected_connectors); 342 create_crtc(dev, ovl, &j, connected_connectors);
334 } 343 }
344
345 for (i = 0; i < kms_pdata->pln_cnt; i++) {
346 struct omap_overlay *ovl =
347 omap_dss_get_overlay(kms_pdata->pln_ids[i]);
348 create_plane(dev, ovl, (1 << priv->num_crtcs) - 1);
349 }
335 } else { 350 } else {
336 /* otherwise just grab up to CONFIG_DRM_OMAP_NUM_CRTCS and try 351 /* otherwise just grab up to CONFIG_DRM_OMAP_NUM_CRTCS and try
337 * to make educated guesses about everything else 352 * to make educated guesses about everything else
@@ -353,6 +368,12 @@ static int omap_modeset_init(struct drm_device *dev)
353 create_crtc(dev, omap_dss_get_overlay(i), 368 create_crtc(dev, omap_dss_get_overlay(i),
354 &j, connected_connectors); 369 &j, connected_connectors);
355 } 370 }
371
372 /* use any remaining overlays as drm planes */
373 for (; i < omap_dss_get_num_overlays(); i++) {
374 struct omap_overlay *ovl = omap_dss_get_overlay(i);
375 create_plane(dev, ovl, (1 << priv->num_crtcs) - 1);
376 }
356 } 377 }
357 378
358 /* for now keep the mapping of CRTCs and encoders static.. */ 379 /* for now keep the mapping of CRTCs and encoders static.. */
@@ -361,15 +382,7 @@ static int omap_modeset_init(struct drm_device *dev)
361 struct omap_overlay_manager *mgr = 382 struct omap_overlay_manager *mgr =
362 omap_encoder_get_manager(encoder); 383 omap_encoder_get_manager(encoder);
363 384
364 encoder->possible_crtcs = 0; 385 encoder->possible_crtcs = (1 << priv->num_crtcs) - 1;
365
366 for (j = 0; j < priv->num_crtcs; j++) {
367 struct omap_overlay *ovl =
368 omap_crtc_get_overlay(priv->crtcs[j]);
369 if (ovl->manager == mgr) {
370 encoder->possible_crtcs |= (1 << j);
371 }
372 }
373 386
374 DBG("%s: possible_crtcs=%08x", mgr->name, 387 DBG("%s: possible_crtcs=%08x", mgr->name,
375 encoder->possible_crtcs); 388 encoder->possible_crtcs);
diff --git a/drivers/staging/omapdrm/omap_drv.h b/drivers/staging/omapdrm/omap_drv.h
index 4ad2ae55ec43..e2b1b553e8b6 100644
--- a/drivers/staging/omapdrm/omap_drv.h
+++ b/drivers/staging/omapdrm/omap_drv.h
@@ -42,6 +42,8 @@
42struct omap_drm_private { 42struct omap_drm_private {
43 unsigned int num_crtcs; 43 unsigned int num_crtcs;
44 struct drm_crtc *crtcs[8]; 44 struct drm_crtc *crtcs[8];
45 unsigned int num_planes;
46 struct drm_plane *planes[8];
45 unsigned int num_encoders; 47 unsigned int num_encoders;
46 struct drm_encoder *encoders[8]; 48 struct drm_encoder *encoders[8];
47 unsigned int num_connectors; 49 unsigned int num_connectors;
@@ -62,7 +64,11 @@ void omap_fbdev_free(struct drm_device *dev);
62 64
63struct drm_crtc *omap_crtc_init(struct drm_device *dev, 65struct drm_crtc *omap_crtc_init(struct drm_device *dev,
64 struct omap_overlay *ovl, int id); 66 struct omap_overlay *ovl, int id);
65struct omap_overlay *omap_crtc_get_overlay(struct drm_crtc *crtc); 67
68struct drm_plane *omap_plane_init(struct drm_device *dev,
69 struct omap_overlay *ovl, unsigned int possible_crtcs,
70 bool priv);
71int omap_plane_dpms(struct drm_plane *plane, int mode);
66 72
67struct drm_encoder *omap_encoder_init(struct drm_device *dev, 73struct drm_encoder *omap_encoder_init(struct drm_device *dev,
68 struct omap_overlay_manager *mgr); 74 struct omap_overlay_manager *mgr);
diff --git a/drivers/staging/omapdrm/omap_plane.c b/drivers/staging/omapdrm/omap_plane.c
new file mode 100644
index 000000000000..a1d948c45ab6
--- /dev/null
+++ b/drivers/staging/omapdrm/omap_plane.c
@@ -0,0 +1,308 @@
1/*
2 * drivers/staging/omapdrm/omap_plane.c
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
20#include "omap_drv.h"
21
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'
25 */
26#define omap_plane _omap_plane
27
28/*
29 * plane funcs
30 */
31
32#define to_omap_plane(x) container_of(x, struct omap_plane, base)
33
34struct omap_plane {
35 struct drm_plane base;
36 struct omap_overlay *ovl;
37 struct omap_overlay_info info;
38
39 /* Source values, converted to integers because we don't support
40 * fractional positions:
41 */
42 unsigned int src_x, src_y;
43};
44
45
46/* push changes down to dss2 */
47static int commit(struct drm_plane *plane)
48{
49 struct drm_device *dev = plane->dev;
50 struct omap_plane *omap_plane = to_omap_plane(plane);
51 struct omap_overlay *ovl = omap_plane->ovl;
52 struct omap_overlay_info *info = &omap_plane->info;
53 int ret;
54
55 DBG("%s", ovl->name);
56 DBG("%dx%d -> %dx%d (%d)", info->width, info->height, info->out_width,
57 info->out_height, info->screen_width);
58 DBG("%d,%d %08x", info->pos_x, info->pos_y, info->paddr);
59
60 /* NOTE: do we want to do this at all here, or just wait
61 * for dpms(ON) since other CRTC's may not have their mode
62 * set yet, so fb dimensions may still change..
63 */
64 ret = ovl->set_overlay_info(ovl, info);
65 if (ret) {
66 dev_err(dev->dev, "could not set overlay info\n");
67 return ret;
68 }
69
70 /* our encoder doesn't necessarily get a commit() after this, in
71 * particular in the dpms() and mode_set_base() cases, so force the
72 * manager to update:
73 *
74 * could this be in the encoder somehow?
75 */
76 if (ovl->manager) {
77 ret = ovl->manager->apply(ovl->manager);
78 if (ret) {
79 dev_err(dev->dev, "could not apply settings\n");
80 return ret;
81 }
82 }
83
84 if (info->enabled) {
85 omap_framebuffer_flush(plane->fb, info->pos_x, info->pos_y,
86 info->out_width, info->out_height);
87 }
88
89 return 0;
90}
91
92/* when CRTC that we are attached to has potentially changed, this checks
93 * if we are attached to proper manager, and if necessary updates.
94 */
95static void update_manager(struct drm_plane *plane)
96{
97 struct omap_drm_private *priv = plane->dev->dev_private;
98 struct omap_plane *omap_plane = to_omap_plane(plane);
99 struct omap_overlay *ovl = omap_plane->ovl;
100 struct omap_overlay_manager *mgr = NULL;
101 int i;
102
103 if (plane->crtc) {
104 for (i = 0; i < priv->num_encoders; i++) {
105 struct drm_encoder *encoder = priv->encoders[i];
106 if (encoder->crtc == plane->crtc) {
107 mgr = omap_encoder_get_manager(encoder);
108 break;
109 }
110 }
111 }
112
113 if (ovl->manager != mgr) {
114 bool enabled = omap_plane->info.enabled;
115
116 /* don't switch things around with enabled overlays: */
117 if (enabled)
118 omap_plane_dpms(plane, DRM_MODE_DPMS_OFF);
119
120 if (ovl->manager) {
121 DBG("disconnecting %s from %s", ovl->name,
122 ovl->manager->name);
123 ovl->unset_manager(ovl);
124 }
125
126 if (mgr) {
127 DBG("connecting %s to %s", ovl->name, mgr->name);
128 ovl->set_manager(ovl, mgr);
129 }
130
131 if (enabled && mgr)
132 omap_plane_dpms(plane, DRM_MODE_DPMS_ON);
133 }
134}
135
136/* update parameters that are dependent on the framebuffer dimensions and
137 * position within the fb that this plane scans out from. This is called
138 * when framebuffer or x,y base may have changed.
139 */
140static void update_scanout(struct drm_plane *plane)
141{
142 struct omap_plane *omap_plane = to_omap_plane(plane);
143 unsigned int screen_width; /* really means "pitch" */
144 dma_addr_t paddr;
145
146 omap_framebuffer_get_buffer(plane->fb,
147 omap_plane->src_x, omap_plane->src_y,
148 NULL, &paddr, &screen_width);
149
150 DBG("%s: %d,%d: %08x (%d)", omap_plane->ovl->name,
151 omap_plane->src_x, omap_plane->src_y,
152 (u32)paddr, screen_width);
153
154 omap_plane->info.paddr = paddr;
155 omap_plane->info.screen_width = screen_width;
156}
157
158static int omap_plane_update(struct drm_plane *plane,
159 struct drm_crtc *crtc, struct drm_framebuffer *fb,
160 int crtc_x, int crtc_y,
161 unsigned int crtc_w, unsigned int crtc_h,
162 uint32_t src_x, uint32_t src_y,
163 uint32_t src_w, uint32_t src_h)
164{
165 struct omap_plane *omap_plane = to_omap_plane(plane);
166
167 /* src values are in Q16 fixed point, convert to integer: */
168 src_x = src_x >> 16;
169 src_y = src_y >> 16;
170 src_w = src_w >> 16;
171 src_h = src_h >> 16;
172
173 omap_plane->info.enabled = true;
174 omap_plane->info.pos_x = crtc_x;
175 omap_plane->info.pos_y = crtc_y;
176 omap_plane->info.out_width = crtc_w;
177 omap_plane->info.out_height = crtc_h;
178 omap_plane->info.width = src_w;
179 omap_plane->info.height = src_h;
180 omap_plane->src_x = src_x;
181 omap_plane->src_y = src_y;
182
183 /* note: this is done after this fxn returns.. but if we need
184 * to do a commit/update_scanout, etc before this returns we
185 * need the current value.
186 */
187 plane->fb = fb;
188 plane->crtc = crtc;
189
190 update_scanout(plane);
191 update_manager(plane);
192 commit(plane);
193
194 return 0;
195}
196
197static int omap_plane_disable(struct drm_plane *plane)
198{
199 return omap_plane_dpms(plane, DRM_MODE_DPMS_OFF);
200}
201
202static void omap_plane_destroy(struct drm_plane *plane)
203{
204 struct omap_plane *omap_plane = to_omap_plane(plane);
205 DBG("%s", omap_plane->ovl->name);
206 omap_plane_disable(plane);
207 drm_plane_cleanup(plane);
208 kfree(omap_plane);
209}
210
211int omap_plane_dpms(struct drm_plane *plane, int mode)
212{
213 struct omap_plane *omap_plane = to_omap_plane(plane);
214
215 DBG("%s: %d", omap_plane->ovl->name, mode);
216
217 if (mode == DRM_MODE_DPMS_ON) {
218 update_scanout(plane);
219 omap_plane->info.enabled = true;
220 } else {
221 omap_plane->info.enabled = false;
222 }
223
224 return commit(plane);
225}
226
227static const struct drm_plane_funcs omap_plane_funcs = {
228 .update_plane = omap_plane_update,
229 .disable_plane = omap_plane_disable,
230 .destroy = omap_plane_destroy,
231};
232
233static const uint32_t formats[] = {
234 DRM_FORMAT_RGB565,
235 DRM_FORMAT_RGBX4444,
236 DRM_FORMAT_XRGB4444,
237 DRM_FORMAT_RGBA4444,
238 DRM_FORMAT_ABGR4444,
239 DRM_FORMAT_XRGB1555,
240 DRM_FORMAT_ARGB1555,
241 DRM_FORMAT_RGB888,
242 DRM_FORMAT_RGBX8888,
243 DRM_FORMAT_XRGB8888,
244 DRM_FORMAT_RGBA8888,
245 DRM_FORMAT_ARGB8888,
246 DRM_FORMAT_NV12,
247 DRM_FORMAT_YUYV,
248 DRM_FORMAT_UYVY,
249};
250
251/* initialize plane */
252struct drm_plane *omap_plane_init(struct drm_device *dev,
253 struct omap_overlay *ovl, unsigned int possible_crtcs,
254 bool priv)
255{
256 struct drm_plane *plane = NULL;
257 struct omap_plane *omap_plane;
258
259 DBG("%s: possible_crtcs=%08x, priv=%d", ovl->name,
260 possible_crtcs, priv);
261
262 omap_plane = kzalloc(sizeof(*omap_plane), GFP_KERNEL);
263 if (!omap_plane) {
264 dev_err(dev->dev, "could not allocate plane\n");
265 goto fail;
266 }
267
268 omap_plane->ovl = ovl;
269 plane = &omap_plane->base;
270
271 drm_plane_init(dev, plane, possible_crtcs, &omap_plane_funcs,
272 formats, ARRAY_SIZE(formats), priv);
273
274 /* get our starting configuration, set defaults for parameters
275 * we don't currently use, etc:
276 */
277 ovl->get_overlay_info(ovl, &omap_plane->info);
278 omap_plane->info.rotation_type = OMAP_DSS_ROT_DMA;
279 omap_plane->info.rotation = OMAP_DSS_ROT_0;
280 omap_plane->info.global_alpha = 0xff;
281 omap_plane->info.mirror = 0;
282 omap_plane->info.mirror = 0;
283
284 /* Set defaults depending on whether we are a CRTC or overlay
285 * layer.
286 * TODO add ioctl to give userspace an API to change this.. this
287 * will come in a subsequent patch.
288 */
289 if (priv)
290 omap_plane->info.zorder = 0;
291 else
292 omap_plane->info.zorder = 1;
293
294 /* TODO color mode should come from fb.. this will come in a
295 * subsequent patch
296 */
297 omap_plane->info.color_mode = OMAP_DSS_COLOR_RGB24U;
298
299 update_manager(plane);
300
301 return plane;
302
303fail:
304 if (plane) {
305 omap_plane_destroy(plane);
306 }
307 return NULL;
308}
diff --git a/drivers/staging/omapdrm/omap_priv.h b/drivers/staging/omapdrm/omap_priv.h
index c324709aa9a1..ef6441447147 100644
--- a/drivers/staging/omapdrm/omap_priv.h
+++ b/drivers/staging/omapdrm/omap_priv.h
@@ -27,14 +27,22 @@
27 * pipes/overlays/CRTCs are used.. if this is not provided, then instead the 27 * pipes/overlays/CRTCs are used.. if this is not provided, then instead the
28 * first CONFIG_DRM_OMAP_NUM_CRTCS are used, and they are each connected to 28 * first CONFIG_DRM_OMAP_NUM_CRTCS are used, and they are each connected to
29 * one manager, with priority given to managers that are connected to 29 * one manager, with priority given to managers that are connected to
30 * detected devices. This should be a good default behavior for most cases, 30 * detected devices. Remaining overlays are used as video planes. This
31 * but yet there still might be times when you wish to do something different. 31 * should be a good default behavior for most cases, but yet there still
32 * might be times when you wish to do something different.
32 */ 33 */
33struct omap_kms_platform_data { 34struct omap_kms_platform_data {
35 /* overlays to use as CRTCs: */
34 int ovl_cnt; 36 int ovl_cnt;
35 const int *ovl_ids; 37 const int *ovl_ids;
38
39 /* overlays to use as video planes: */
40 int pln_cnt;
41 const int *pln_ids;
42
36 int mgr_cnt; 43 int mgr_cnt;
37 const int *mgr_ids; 44 const int *mgr_ids;
45
38 int dev_cnt; 46 int dev_cnt;
39 const char **dev_names; 47 const char **dev_names;
40}; 48};