include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit...
[pandora-kernel.git] / drivers / video / omap2 / dss / manager.c
1 /*
2  * linux/drivers/video/omap2/dss/manager.c
3  *
4  * Copyright (C) 2009 Nokia Corporation
5  * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
6  *
7  * Some code and ideas taken from drivers/video/omap/ driver
8  * by Imre Deak.
9  *
10  * This program is free software; you can redistribute it and/or modify it
11  * under the terms of the GNU General Public License version 2 as published by
12  * the Free Software Foundation.
13  *
14  * This program is distributed in the hope that it will be useful, but WITHOUT
15  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
17  * more details.
18  *
19  * You should have received a copy of the GNU General Public License along with
20  * this program.  If not, see <http://www.gnu.org/licenses/>.
21  */
22
23 #define DSS_SUBSYS_NAME "MANAGER"
24
25 #include <linux/kernel.h>
26 #include <linux/slab.h>
27 #include <linux/module.h>
28 #include <linux/platform_device.h>
29 #include <linux/spinlock.h>
30 #include <linux/jiffies.h>
31
32 #include <plat/display.h>
33 #include <plat/cpu.h>
34
35 #include "dss.h"
36
37 static int num_managers;
38 static struct list_head manager_list;
39
40 static ssize_t manager_name_show(struct omap_overlay_manager *mgr, char *buf)
41 {
42         return snprintf(buf, PAGE_SIZE, "%s\n", mgr->name);
43 }
44
45 static ssize_t manager_display_show(struct omap_overlay_manager *mgr, char *buf)
46 {
47         return snprintf(buf, PAGE_SIZE, "%s\n",
48                         mgr->device ? mgr->device->name : "<none>");
49 }
50
51 static ssize_t manager_display_store(struct omap_overlay_manager *mgr,
52                 const char *buf, size_t size)
53 {
54         int r = 0;
55         size_t len = size;
56         struct omap_dss_device *dssdev = NULL;
57
58         int match(struct omap_dss_device *dssdev, void *data)
59         {
60                 const char *str = data;
61                 return sysfs_streq(dssdev->name, str);
62         }
63
64         if (buf[size-1] == '\n')
65                 --len;
66
67         if (len > 0)
68                 dssdev = omap_dss_find_device((void *)buf, match);
69
70         if (len > 0 && dssdev == NULL)
71                 return -EINVAL;
72
73         if (dssdev)
74                 DSSDBG("display %s found\n", dssdev->name);
75
76         if (mgr->device) {
77                 r = mgr->unset_device(mgr);
78                 if (r) {
79                         DSSERR("failed to unset display\n");
80                         goto put_device;
81                 }
82         }
83
84         if (dssdev) {
85                 r = mgr->set_device(mgr, dssdev);
86                 if (r) {
87                         DSSERR("failed to set manager\n");
88                         goto put_device;
89                 }
90
91                 r = mgr->apply(mgr);
92                 if (r) {
93                         DSSERR("failed to apply dispc config\n");
94                         goto put_device;
95                 }
96         }
97
98 put_device:
99         if (dssdev)
100                 omap_dss_put_device(dssdev);
101
102         return r ? r : size;
103 }
104
105 static ssize_t manager_default_color_show(struct omap_overlay_manager *mgr,
106                                           char *buf)
107 {
108         return snprintf(buf, PAGE_SIZE, "%d\n", mgr->info.default_color);
109 }
110
111 static ssize_t manager_default_color_store(struct omap_overlay_manager *mgr,
112                                            const char *buf, size_t size)
113 {
114         struct omap_overlay_manager_info info;
115         u32 color;
116         int r;
117
118         if (sscanf(buf, "%d", &color) != 1)
119                 return -EINVAL;
120
121         mgr->get_manager_info(mgr, &info);
122
123         info.default_color = color;
124
125         r = mgr->set_manager_info(mgr, &info);
126         if (r)
127                 return r;
128
129         r = mgr->apply(mgr);
130         if (r)
131                 return r;
132
133         return size;
134 }
135
136 static const char *trans_key_type_str[] = {
137         "gfx-destination",
138         "video-source",
139 };
140
141 static ssize_t manager_trans_key_type_show(struct omap_overlay_manager *mgr,
142                                            char *buf)
143 {
144         enum omap_dss_trans_key_type key_type;
145
146         key_type = mgr->info.trans_key_type;
147         BUG_ON(key_type >= ARRAY_SIZE(trans_key_type_str));
148
149         return snprintf(buf, PAGE_SIZE, "%s\n", trans_key_type_str[key_type]);
150 }
151
152 static ssize_t manager_trans_key_type_store(struct omap_overlay_manager *mgr,
153                                             const char *buf, size_t size)
154 {
155         enum omap_dss_trans_key_type key_type;
156         struct omap_overlay_manager_info info;
157         int r;
158
159         for (key_type = OMAP_DSS_COLOR_KEY_GFX_DST;
160                         key_type < ARRAY_SIZE(trans_key_type_str); key_type++) {
161                 if (sysfs_streq(buf, trans_key_type_str[key_type]))
162                         break;
163         }
164
165         if (key_type == ARRAY_SIZE(trans_key_type_str))
166                 return -EINVAL;
167
168         mgr->get_manager_info(mgr, &info);
169
170         info.trans_key_type = key_type;
171
172         r = mgr->set_manager_info(mgr, &info);
173         if (r)
174                 return r;
175
176         r = mgr->apply(mgr);
177         if (r)
178                 return r;
179
180         return size;
181 }
182
183 static ssize_t manager_trans_key_value_show(struct omap_overlay_manager *mgr,
184                                             char *buf)
185 {
186         return snprintf(buf, PAGE_SIZE, "%d\n", mgr->info.trans_key);
187 }
188
189 static ssize_t manager_trans_key_value_store(struct omap_overlay_manager *mgr,
190                                              const char *buf, size_t size)
191 {
192         struct omap_overlay_manager_info info;
193         u32 key_value;
194         int r;
195
196         if (sscanf(buf, "%d", &key_value) != 1)
197                 return -EINVAL;
198
199         mgr->get_manager_info(mgr, &info);
200
201         info.trans_key = key_value;
202
203         r = mgr->set_manager_info(mgr, &info);
204         if (r)
205                 return r;
206
207         r = mgr->apply(mgr);
208         if (r)
209                 return r;
210
211         return size;
212 }
213
214 static ssize_t manager_trans_key_enabled_show(struct omap_overlay_manager *mgr,
215                                               char *buf)
216 {
217         return snprintf(buf, PAGE_SIZE, "%d\n", mgr->info.trans_enabled);
218 }
219
220 static ssize_t manager_trans_key_enabled_store(struct omap_overlay_manager *mgr,
221                                                const char *buf, size_t size)
222 {
223         struct omap_overlay_manager_info info;
224         int enable;
225         int r;
226
227         if (sscanf(buf, "%d", &enable) != 1)
228                 return -EINVAL;
229
230         mgr->get_manager_info(mgr, &info);
231
232         info.trans_enabled = enable ? true : false;
233
234         r = mgr->set_manager_info(mgr, &info);
235         if (r)
236                 return r;
237
238         r = mgr->apply(mgr);
239         if (r)
240                 return r;
241
242         return size;
243 }
244
245 static ssize_t manager_alpha_blending_enabled_show(
246                 struct omap_overlay_manager *mgr, char *buf)
247 {
248         return snprintf(buf, PAGE_SIZE, "%d\n", mgr->info.alpha_enabled);
249 }
250
251 static ssize_t manager_alpha_blending_enabled_store(
252                 struct omap_overlay_manager *mgr,
253                 const char *buf, size_t size)
254 {
255         struct omap_overlay_manager_info info;
256         int enable;
257         int r;
258
259         if (sscanf(buf, "%d", &enable) != 1)
260                 return -EINVAL;
261
262         mgr->get_manager_info(mgr, &info);
263
264         info.alpha_enabled = enable ? true : false;
265
266         r = mgr->set_manager_info(mgr, &info);
267         if (r)
268                 return r;
269
270         r = mgr->apply(mgr);
271         if (r)
272                 return r;
273
274         return size;
275 }
276
277 struct manager_attribute {
278         struct attribute attr;
279         ssize_t (*show)(struct omap_overlay_manager *, char *);
280         ssize_t (*store)(struct omap_overlay_manager *, const char *, size_t);
281 };
282
283 #define MANAGER_ATTR(_name, _mode, _show, _store) \
284         struct manager_attribute manager_attr_##_name = \
285         __ATTR(_name, _mode, _show, _store)
286
287 static MANAGER_ATTR(name, S_IRUGO, manager_name_show, NULL);
288 static MANAGER_ATTR(display, S_IRUGO|S_IWUSR,
289                 manager_display_show, manager_display_store);
290 static MANAGER_ATTR(default_color, S_IRUGO|S_IWUSR,
291                 manager_default_color_show, manager_default_color_store);
292 static MANAGER_ATTR(trans_key_type, S_IRUGO|S_IWUSR,
293                 manager_trans_key_type_show, manager_trans_key_type_store);
294 static MANAGER_ATTR(trans_key_value, S_IRUGO|S_IWUSR,
295                 manager_trans_key_value_show, manager_trans_key_value_store);
296 static MANAGER_ATTR(trans_key_enabled, S_IRUGO|S_IWUSR,
297                 manager_trans_key_enabled_show,
298                 manager_trans_key_enabled_store);
299 static MANAGER_ATTR(alpha_blending_enabled, S_IRUGO|S_IWUSR,
300                 manager_alpha_blending_enabled_show,
301                 manager_alpha_blending_enabled_store);
302
303
304 static struct attribute *manager_sysfs_attrs[] = {
305         &manager_attr_name.attr,
306         &manager_attr_display.attr,
307         &manager_attr_default_color.attr,
308         &manager_attr_trans_key_type.attr,
309         &manager_attr_trans_key_value.attr,
310         &manager_attr_trans_key_enabled.attr,
311         &manager_attr_alpha_blending_enabled.attr,
312         NULL
313 };
314
315 static ssize_t manager_attr_show(struct kobject *kobj, struct attribute *attr,
316                 char *buf)
317 {
318         struct omap_overlay_manager *manager;
319         struct manager_attribute *manager_attr;
320
321         manager = container_of(kobj, struct omap_overlay_manager, kobj);
322         manager_attr = container_of(attr, struct manager_attribute, attr);
323
324         if (!manager_attr->show)
325                 return -ENOENT;
326
327         return manager_attr->show(manager, buf);
328 }
329
330 static ssize_t manager_attr_store(struct kobject *kobj, struct attribute *attr,
331                 const char *buf, size_t size)
332 {
333         struct omap_overlay_manager *manager;
334         struct manager_attribute *manager_attr;
335
336         manager = container_of(kobj, struct omap_overlay_manager, kobj);
337         manager_attr = container_of(attr, struct manager_attribute, attr);
338
339         if (!manager_attr->store)
340                 return -ENOENT;
341
342         return manager_attr->store(manager, buf, size);
343 }
344
345 static const struct sysfs_ops manager_sysfs_ops = {
346         .show = manager_attr_show,
347         .store = manager_attr_store,
348 };
349
350 static struct kobj_type manager_ktype = {
351         .sysfs_ops = &manager_sysfs_ops,
352         .default_attrs = manager_sysfs_attrs,
353 };
354
355 /*
356  * We have 4 levels of cache for the dispc settings. First two are in SW and
357  * the latter two in HW.
358  *
359  * +--------------------+
360  * |overlay/manager_info|
361  * +--------------------+
362  *          v
363  *        apply()
364  *          v
365  * +--------------------+
366  * |     dss_cache      |
367  * +--------------------+
368  *          v
369  *      configure()
370  *          v
371  * +--------------------+
372  * |  shadow registers  |
373  * +--------------------+
374  *          v
375  * VFP or lcd/digit_enable
376  *          v
377  * +--------------------+
378  * |      registers     |
379  * +--------------------+
380  */
381
382 struct overlay_cache_data {
383         /* If true, cache changed, but not written to shadow registers. Set
384          * in apply(), cleared when registers written. */
385         bool dirty;
386         /* If true, shadow registers contain changed values not yet in real
387          * registers. Set when writing to shadow registers, cleared at
388          * VSYNC/EVSYNC */
389         bool shadow_dirty;
390
391         bool enabled;
392
393         u32 paddr;
394         void __iomem *vaddr;
395         u16 screen_width;
396         u16 width;
397         u16 height;
398         enum omap_color_mode color_mode;
399         u8 rotation;
400         enum omap_dss_rotation_type rotation_type;
401         bool mirror;
402
403         u16 pos_x;
404         u16 pos_y;
405         u16 out_width;  /* if 0, out_width == width */
406         u16 out_height; /* if 0, out_height == height */
407         u8 global_alpha;
408
409         enum omap_channel channel;
410         bool replication;
411         bool ilace;
412
413         enum omap_burst_size burst_size;
414         u32 fifo_low;
415         u32 fifo_high;
416
417         bool manual_update;
418 };
419
420 struct manager_cache_data {
421         /* If true, cache changed, but not written to shadow registers. Set
422          * in apply(), cleared when registers written. */
423         bool dirty;
424         /* If true, shadow registers contain changed values not yet in real
425          * registers. Set when writing to shadow registers, cleared at
426          * VSYNC/EVSYNC */
427         bool shadow_dirty;
428
429         u32 default_color;
430
431         enum omap_dss_trans_key_type trans_key_type;
432         u32 trans_key;
433         bool trans_enabled;
434
435         bool alpha_enabled;
436
437         bool manual_upd_display;
438         bool manual_update;
439         bool do_manual_update;
440
441         /* manual update region */
442         u16 x, y, w, h;
443 };
444
445 static struct {
446         spinlock_t lock;
447         struct overlay_cache_data overlay_cache[3];
448         struct manager_cache_data manager_cache[2];
449
450         bool irq_enabled;
451 } dss_cache;
452
453
454
455 static int omap_dss_set_device(struct omap_overlay_manager *mgr,
456                 struct omap_dss_device *dssdev)
457 {
458         int i;
459         int r;
460
461         if (dssdev->manager) {
462                 DSSERR("display '%s' already has a manager '%s'\n",
463                                dssdev->name, dssdev->manager->name);
464                 return -EINVAL;
465         }
466
467         if ((mgr->supported_displays & dssdev->type) == 0) {
468                 DSSERR("display '%s' does not support manager '%s'\n",
469                                dssdev->name, mgr->name);
470                 return -EINVAL;
471         }
472
473         for (i = 0; i < mgr->num_overlays; i++) {
474                 struct omap_overlay *ovl = mgr->overlays[i];
475
476                 if (ovl->manager != mgr || !ovl->info.enabled)
477                         continue;
478
479                 r = dss_check_overlay(ovl, dssdev);
480                 if (r)
481                         return r;
482         }
483
484         dssdev->manager = mgr;
485         mgr->device = dssdev;
486         mgr->device_changed = true;
487
488         return 0;
489 }
490
491 static int omap_dss_unset_device(struct omap_overlay_manager *mgr)
492 {
493         if (!mgr->device) {
494                 DSSERR("failed to unset display, display not set.\n");
495                 return -EINVAL;
496         }
497
498         mgr->device->manager = NULL;
499         mgr->device = NULL;
500         mgr->device_changed = true;
501
502         return 0;
503 }
504
505 static int dss_mgr_wait_for_vsync(struct omap_overlay_manager *mgr)
506 {
507         unsigned long timeout = msecs_to_jiffies(500);
508         u32 irq;
509
510         if (mgr->device->type == OMAP_DISPLAY_TYPE_VENC)
511                 irq = DISPC_IRQ_EVSYNC_ODD;
512         else
513                 irq = DISPC_IRQ_VSYNC;
514
515         return omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
516 }
517
518 static int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr)
519 {
520         unsigned long timeout = msecs_to_jiffies(500);
521         struct manager_cache_data *mc;
522         enum omap_channel channel;
523         u32 irq;
524         int r;
525         int i;
526         struct omap_dss_device *dssdev = mgr->device;
527
528         if (!dssdev)
529                 return 0;
530
531         if (dssdev->type == OMAP_DISPLAY_TYPE_VENC) {
532                 irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN;
533                 channel = OMAP_DSS_CHANNEL_DIGIT;
534         } else {
535                 if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) {
536                         enum omap_dss_update_mode mode;
537                         mode = dssdev->driver->get_update_mode(dssdev);
538                         if (mode != OMAP_DSS_UPDATE_AUTO)
539                                 return 0;
540
541                         irq = DISPC_IRQ_FRAMEDONE;
542                 } else {
543                         irq = DISPC_IRQ_VSYNC;
544                 }
545                 channel = OMAP_DSS_CHANNEL_LCD;
546         }
547
548         mc = &dss_cache.manager_cache[mgr->id];
549         i = 0;
550         while (1) {
551                 unsigned long flags;
552                 bool shadow_dirty, dirty;
553
554                 spin_lock_irqsave(&dss_cache.lock, flags);
555                 dirty = mc->dirty;
556                 shadow_dirty = mc->shadow_dirty;
557                 spin_unlock_irqrestore(&dss_cache.lock, flags);
558
559                 if (!dirty && !shadow_dirty) {
560                         r = 0;
561                         break;
562                 }
563
564                 /* 4 iterations is the worst case:
565                  * 1 - initial iteration, dirty = true (between VFP and VSYNC)
566                  * 2 - first VSYNC, dirty = true
567                  * 3 - dirty = false, shadow_dirty = true
568                  * 4 - shadow_dirty = false */
569                 if (i++ == 3) {
570                         DSSERR("mgr(%d)->wait_for_go() not finishing\n",
571                                         mgr->id);
572                         r = 0;
573                         break;
574                 }
575
576                 r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
577                 if (r == -ERESTARTSYS)
578                         break;
579
580                 if (r) {
581                         DSSERR("mgr(%d)->wait_for_go() timeout\n", mgr->id);
582                         break;
583                 }
584         }
585
586         return r;
587 }
588
589 int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl)
590 {
591         unsigned long timeout = msecs_to_jiffies(500);
592         enum omap_channel channel;
593         struct overlay_cache_data *oc;
594         struct omap_dss_device *dssdev;
595         u32 irq;
596         int r;
597         int i;
598
599         if (!ovl->manager || !ovl->manager->device)
600                 return 0;
601
602         dssdev = ovl->manager->device;
603
604         if (dssdev->type == OMAP_DISPLAY_TYPE_VENC) {
605                 irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN;
606                 channel = OMAP_DSS_CHANNEL_DIGIT;
607         } else {
608                 if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) {
609                         enum omap_dss_update_mode mode;
610                         mode = dssdev->driver->get_update_mode(dssdev);
611                         if (mode != OMAP_DSS_UPDATE_AUTO)
612                                 return 0;
613
614                         irq = DISPC_IRQ_FRAMEDONE;
615                 } else {
616                         irq = DISPC_IRQ_VSYNC;
617                 }
618                 channel = OMAP_DSS_CHANNEL_LCD;
619         }
620
621         oc = &dss_cache.overlay_cache[ovl->id];
622         i = 0;
623         while (1) {
624                 unsigned long flags;
625                 bool shadow_dirty, dirty;
626
627                 spin_lock_irqsave(&dss_cache.lock, flags);
628                 dirty = oc->dirty;
629                 shadow_dirty = oc->shadow_dirty;
630                 spin_unlock_irqrestore(&dss_cache.lock, flags);
631
632                 if (!dirty && !shadow_dirty) {
633                         r = 0;
634                         break;
635                 }
636
637                 /* 4 iterations is the worst case:
638                  * 1 - initial iteration, dirty = true (between VFP and VSYNC)
639                  * 2 - first VSYNC, dirty = true
640                  * 3 - dirty = false, shadow_dirty = true
641                  * 4 - shadow_dirty = false */
642                 if (i++ == 3) {
643                         DSSERR("ovl(%d)->wait_for_go() not finishing\n",
644                                         ovl->id);
645                         r = 0;
646                         break;
647                 }
648
649                 r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
650                 if (r == -ERESTARTSYS)
651                         break;
652
653                 if (r) {
654                         DSSERR("ovl(%d)->wait_for_go() timeout\n", ovl->id);
655                         break;
656                 }
657         }
658
659         return r;
660 }
661
662 static int overlay_enabled(struct omap_overlay *ovl)
663 {
664         return ovl->info.enabled && ovl->manager && ovl->manager->device;
665 }
666
667 /* Is rect1 a subset of rect2? */
668 static bool rectangle_subset(int x1, int y1, int w1, int h1,
669                 int x2, int y2, int w2, int h2)
670 {
671         if (x1 < x2 || y1 < y2)
672                 return false;
673
674         if (x1 + w1 > x2 + w2)
675                 return false;
676
677         if (y1 + h1 > y2 + h2)
678                 return false;
679
680         return true;
681 }
682
683 /* Do rect1 and rect2 overlap? */
684 static bool rectangle_intersects(int x1, int y1, int w1, int h1,
685                 int x2, int y2, int w2, int h2)
686 {
687         if (x1 >= x2 + w2)
688                 return false;
689
690         if (x2 >= x1 + w1)
691                 return false;
692
693         if (y1 >= y2 + h2)
694                 return false;
695
696         if (y2 >= y1 + h1)
697                 return false;
698
699         return true;
700 }
701
702 static bool dispc_is_overlay_scaled(struct overlay_cache_data *oc)
703 {
704         if (oc->out_width != 0 && oc->width != oc->out_width)
705                 return true;
706
707         if (oc->out_height != 0 && oc->height != oc->out_height)
708                 return true;
709
710         return false;
711 }
712
713 static int configure_overlay(enum omap_plane plane)
714 {
715         struct overlay_cache_data *c;
716         struct manager_cache_data *mc;
717         u16 outw, outh;
718         u16 x, y, w, h;
719         u32 paddr;
720         int r;
721
722         DSSDBGF("%d", plane);
723
724         c = &dss_cache.overlay_cache[plane];
725
726         if (!c->enabled) {
727                 dispc_enable_plane(plane, 0);
728                 return 0;
729         }
730
731         mc = &dss_cache.manager_cache[c->channel];
732
733         x = c->pos_x;
734         y = c->pos_y;
735         w = c->width;
736         h = c->height;
737         outw = c->out_width == 0 ? c->width : c->out_width;
738         outh = c->out_height == 0 ? c->height : c->out_height;
739         paddr = c->paddr;
740
741         if (c->manual_update && mc->do_manual_update) {
742                 unsigned bpp;
743                 /* If the overlay is outside the update region, disable it */
744                 if (!rectangle_intersects(mc->x, mc->y, mc->w, mc->h,
745                                         x, y, outw, outh)) {
746                         dispc_enable_plane(plane, 0);
747                         return 0;
748                 }
749
750                 switch (c->color_mode) {
751                 case OMAP_DSS_COLOR_RGB16:
752                 case OMAP_DSS_COLOR_ARGB16:
753                 case OMAP_DSS_COLOR_YUV2:
754                 case OMAP_DSS_COLOR_UYVY:
755                         bpp = 16;
756                         break;
757
758                 case OMAP_DSS_COLOR_RGB24P:
759                         bpp = 24;
760                         break;
761
762                 case OMAP_DSS_COLOR_RGB24U:
763                 case OMAP_DSS_COLOR_ARGB32:
764                 case OMAP_DSS_COLOR_RGBA32:
765                 case OMAP_DSS_COLOR_RGBX32:
766                         bpp = 32;
767                         break;
768
769                 default:
770                         BUG();
771                 }
772
773                 if (dispc_is_overlay_scaled(c)) {
774                         /* If the overlay is scaled, the update area has
775                          * already been enlarged to cover the whole overlay. We
776                          * only need to adjust x/y here */
777                         x = c->pos_x - mc->x;
778                         y = c->pos_y - mc->y;
779                 } else {
780                         if (mc->x > c->pos_x) {
781                                 x = 0;
782                                 w -= (mc->x - c->pos_x);
783                                 paddr += (mc->x - c->pos_x) * bpp / 8;
784                         } else {
785                                 x = c->pos_x - mc->x;
786                         }
787
788                         if (mc->y > c->pos_y) {
789                                 y = 0;
790                                 h -= (mc->y - c->pos_y);
791                                 paddr += (mc->y - c->pos_y) * c->screen_width *
792                                         bpp / 8;
793                         } else {
794                                 y = c->pos_y - mc->y;
795                         }
796
797                         if (mc->w < (x+w))
798                                 w -= (x+w) - (mc->w);
799
800                         if (mc->h < (y+h))
801                                 h -= (y+h) - (mc->h);
802
803                         outw = w;
804                         outh = h;
805                 }
806         }
807
808         r = dispc_setup_plane(plane,
809                         paddr,
810                         c->screen_width,
811                         x, y,
812                         w, h,
813                         outw, outh,
814                         c->color_mode,
815                         c->ilace,
816                         c->rotation_type,
817                         c->rotation,
818                         c->mirror,
819                         c->global_alpha);
820
821         if (r) {
822                 /* this shouldn't happen */
823                 DSSERR("dispc_setup_plane failed for ovl %d\n", plane);
824                 dispc_enable_plane(plane, 0);
825                 return r;
826         }
827
828         dispc_enable_replication(plane, c->replication);
829
830         dispc_set_burst_size(plane, c->burst_size);
831         dispc_setup_plane_fifo(plane, c->fifo_low, c->fifo_high);
832
833         dispc_enable_plane(plane, 1);
834
835         return 0;
836 }
837
838 static void configure_manager(enum omap_channel channel)
839 {
840         struct manager_cache_data *c;
841
842         DSSDBGF("%d", channel);
843
844         c = &dss_cache.manager_cache[channel];
845
846         dispc_set_trans_key(channel, c->trans_key_type, c->trans_key);
847         dispc_enable_trans_key(channel, c->trans_enabled);
848         dispc_enable_alpha_blending(channel, c->alpha_enabled);
849 }
850
851 /* configure_dispc() tries to write values from cache to shadow registers.
852  * It writes only to those managers/overlays that are not busy.
853  * returns 0 if everything could be written to shadow registers.
854  * returns 1 if not everything could be written to shadow registers. */
855 static int configure_dispc(void)
856 {
857         struct overlay_cache_data *oc;
858         struct manager_cache_data *mc;
859         const int num_ovls = ARRAY_SIZE(dss_cache.overlay_cache);
860         const int num_mgrs = ARRAY_SIZE(dss_cache.manager_cache);
861         int i;
862         int r;
863         bool mgr_busy[2];
864         bool mgr_go[2];
865         bool busy;
866
867         r = 0;
868         busy = false;
869
870         mgr_busy[0] = dispc_go_busy(0);
871         mgr_busy[1] = dispc_go_busy(1);
872         mgr_go[0] = false;
873         mgr_go[1] = false;
874
875         /* Commit overlay settings */
876         for (i = 0; i < num_ovls; ++i) {
877                 oc = &dss_cache.overlay_cache[i];
878                 mc = &dss_cache.manager_cache[oc->channel];
879
880                 if (!oc->dirty)
881                         continue;
882
883                 if (oc->manual_update && !mc->do_manual_update)
884                         continue;
885
886                 if (mgr_busy[oc->channel]) {
887                         busy = true;
888                         continue;
889                 }
890
891                 r = configure_overlay(i);
892                 if (r)
893                         DSSERR("configure_overlay %d failed\n", i);
894
895                 oc->dirty = false;
896                 oc->shadow_dirty = true;
897                 mgr_go[oc->channel] = true;
898         }
899
900         /* Commit manager settings */
901         for (i = 0; i < num_mgrs; ++i) {
902                 mc = &dss_cache.manager_cache[i];
903
904                 if (!mc->dirty)
905                         continue;
906
907                 if (mc->manual_update && !mc->do_manual_update)
908                         continue;
909
910                 if (mgr_busy[i]) {
911                         busy = true;
912                         continue;
913                 }
914
915                 configure_manager(i);
916                 mc->dirty = false;
917                 mc->shadow_dirty = true;
918                 mgr_go[i] = true;
919         }
920
921         /* set GO */
922         for (i = 0; i < num_mgrs; ++i) {
923                 mc = &dss_cache.manager_cache[i];
924
925                 if (!mgr_go[i])
926                         continue;
927
928                 /* We don't need GO with manual update display. LCD iface will
929                  * always be turned off after frame, and new settings will be
930                  * taken in to use at next update */
931                 if (!mc->manual_upd_display)
932                         dispc_go(i);
933         }
934
935         if (busy)
936                 r = 1;
937         else
938                 r = 0;
939
940         return r;
941 }
942
943 /* Configure dispc for partial update. Return possibly modified update
944  * area */
945 void dss_setup_partial_planes(struct omap_dss_device *dssdev,
946                 u16 *xi, u16 *yi, u16 *wi, u16 *hi)
947 {
948         struct overlay_cache_data *oc;
949         struct manager_cache_data *mc;
950         const int num_ovls = ARRAY_SIZE(dss_cache.overlay_cache);
951         struct omap_overlay_manager *mgr;
952         int i;
953         u16 x, y, w, h;
954         unsigned long flags;
955
956         x = *xi;
957         y = *yi;
958         w = *wi;
959         h = *hi;
960
961         DSSDBG("dispc_setup_partial_planes %d,%d %dx%d\n",
962                 *xi, *yi, *wi, *hi);
963
964         mgr = dssdev->manager;
965
966         if (!mgr) {
967                 DSSDBG("no manager\n");
968                 return;
969         }
970
971         spin_lock_irqsave(&dss_cache.lock, flags);
972
973         /* We need to show the whole overlay if it is scaled. So look for
974          * those, and make the update area larger if found.
975          * Also mark the overlay cache dirty */
976         for (i = 0; i < num_ovls; ++i) {
977                 unsigned x1, y1, x2, y2;
978                 unsigned outw, outh;
979
980                 oc = &dss_cache.overlay_cache[i];
981
982                 if (oc->channel != mgr->id)
983                         continue;
984
985                 oc->dirty = true;
986
987                 if (!oc->enabled)
988                         continue;
989
990                 if (!dispc_is_overlay_scaled(oc))
991                         continue;
992
993                 outw = oc->out_width == 0 ? oc->width : oc->out_width;
994                 outh = oc->out_height == 0 ? oc->height : oc->out_height;
995
996                 /* is the overlay outside the update region? */
997                 if (!rectangle_intersects(x, y, w, h,
998                                         oc->pos_x, oc->pos_y,
999                                         outw, outh))
1000                         continue;
1001
1002                 /* if the overlay totally inside the update region? */
1003                 if (rectangle_subset(oc->pos_x, oc->pos_y, outw, outh,
1004                                         x, y, w, h))
1005                         continue;
1006
1007                 if (x > oc->pos_x)
1008                         x1 = oc->pos_x;
1009                 else
1010                         x1 = x;
1011
1012                 if (y > oc->pos_y)
1013                         y1 = oc->pos_y;
1014                 else
1015                         y1 = y;
1016
1017                 if ((x + w) < (oc->pos_x + outw))
1018                         x2 = oc->pos_x + outw;
1019                 else
1020                         x2 = x + w;
1021
1022                 if ((y + h) < (oc->pos_y + outh))
1023                         y2 = oc->pos_y + outh;
1024                 else
1025                         y2 = y + h;
1026
1027                 x = x1;
1028                 y = y1;
1029                 w = x2 - x1;
1030                 h = y2 - y1;
1031
1032                 DSSDBG("changing upd area due to ovl(%d) scaling %d,%d %dx%d\n",
1033                                 i, x, y, w, h);
1034         }
1035
1036         mc = &dss_cache.manager_cache[mgr->id];
1037         mc->do_manual_update = true;
1038         mc->x = x;
1039         mc->y = y;
1040         mc->w = w;
1041         mc->h = h;
1042
1043         configure_dispc();
1044
1045         mc->do_manual_update = false;
1046
1047         spin_unlock_irqrestore(&dss_cache.lock, flags);
1048
1049         *xi = x;
1050         *yi = y;
1051         *wi = w;
1052         *hi = h;
1053 }
1054
1055 void dss_start_update(struct omap_dss_device *dssdev)
1056 {
1057         struct manager_cache_data *mc;
1058         struct overlay_cache_data *oc;
1059         const int num_ovls = ARRAY_SIZE(dss_cache.overlay_cache);
1060         const int num_mgrs = ARRAY_SIZE(dss_cache.manager_cache);
1061         struct omap_overlay_manager *mgr;
1062         int i;
1063
1064         mgr = dssdev->manager;
1065
1066         for (i = 0; i < num_ovls; ++i) {
1067                 oc = &dss_cache.overlay_cache[i];
1068                 if (oc->channel != mgr->id)
1069                         continue;
1070
1071                 oc->shadow_dirty = false;
1072         }
1073
1074         for (i = 0; i < num_mgrs; ++i) {
1075                 mc = &dss_cache.manager_cache[i];
1076                 if (mgr->id != i)
1077                         continue;
1078
1079                 mc->shadow_dirty = false;
1080         }
1081
1082         dssdev->manager->enable(dssdev->manager);
1083 }
1084
1085 static void dss_apply_irq_handler(void *data, u32 mask)
1086 {
1087         struct manager_cache_data *mc;
1088         struct overlay_cache_data *oc;
1089         const int num_ovls = ARRAY_SIZE(dss_cache.overlay_cache);
1090         const int num_mgrs = ARRAY_SIZE(dss_cache.manager_cache);
1091         int i, r;
1092         bool mgr_busy[2];
1093
1094         mgr_busy[0] = dispc_go_busy(0);
1095         mgr_busy[1] = dispc_go_busy(1);
1096
1097         spin_lock(&dss_cache.lock);
1098
1099         for (i = 0; i < num_ovls; ++i) {
1100                 oc = &dss_cache.overlay_cache[i];
1101                 if (!mgr_busy[oc->channel])
1102                         oc->shadow_dirty = false;
1103         }
1104
1105         for (i = 0; i < num_mgrs; ++i) {
1106                 mc = &dss_cache.manager_cache[i];
1107                 if (!mgr_busy[i])
1108                         mc->shadow_dirty = false;
1109         }
1110
1111         r = configure_dispc();
1112         if (r == 1)
1113                 goto end;
1114
1115         /* re-read busy flags */
1116         mgr_busy[0] = dispc_go_busy(0);
1117         mgr_busy[1] = dispc_go_busy(1);
1118
1119         /* keep running as long as there are busy managers, so that
1120          * we can collect overlay-applied information */
1121         for (i = 0; i < num_mgrs; ++i) {
1122                 if (mgr_busy[i])
1123                         goto end;
1124         }
1125
1126         omap_dispc_unregister_isr(dss_apply_irq_handler, NULL,
1127                         DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_ODD |
1128                         DISPC_IRQ_EVSYNC_EVEN);
1129         dss_cache.irq_enabled = false;
1130
1131 end:
1132         spin_unlock(&dss_cache.lock);
1133 }
1134
1135 static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
1136 {
1137         struct overlay_cache_data *oc;
1138         struct manager_cache_data *mc;
1139         int i;
1140         struct omap_overlay *ovl;
1141         int num_planes_enabled = 0;
1142         bool use_fifomerge;
1143         unsigned long flags;
1144         int r;
1145
1146         DSSDBG("omap_dss_mgr_apply(%s)\n", mgr->name);
1147
1148         spin_lock_irqsave(&dss_cache.lock, flags);
1149
1150         /* Configure overlays */
1151         for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
1152                 struct omap_dss_device *dssdev;
1153
1154                 ovl = omap_dss_get_overlay(i);
1155
1156                 if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC))
1157                         continue;
1158
1159                 oc = &dss_cache.overlay_cache[ovl->id];
1160
1161                 if (!overlay_enabled(ovl)) {
1162                         if (oc->enabled) {
1163                                 oc->enabled = false;
1164                                 oc->dirty = true;
1165                         }
1166                         continue;
1167                 }
1168
1169                 if (!ovl->info_dirty) {
1170                         if (oc->enabled)
1171                                 ++num_planes_enabled;
1172                         continue;
1173                 }
1174
1175                 dssdev = ovl->manager->device;
1176
1177                 if (dss_check_overlay(ovl, dssdev)) {
1178                         if (oc->enabled) {
1179                                 oc->enabled = false;
1180                                 oc->dirty = true;
1181                         }
1182                         continue;
1183                 }
1184
1185                 ovl->info_dirty = false;
1186                 oc->dirty = true;
1187
1188                 oc->paddr = ovl->info.paddr;
1189                 oc->vaddr = ovl->info.vaddr;
1190                 oc->screen_width = ovl->info.screen_width;
1191                 oc->width = ovl->info.width;
1192                 oc->height = ovl->info.height;
1193                 oc->color_mode = ovl->info.color_mode;
1194                 oc->rotation = ovl->info.rotation;
1195                 oc->rotation_type = ovl->info.rotation_type;
1196                 oc->mirror = ovl->info.mirror;
1197                 oc->pos_x = ovl->info.pos_x;
1198                 oc->pos_y = ovl->info.pos_y;
1199                 oc->out_width = ovl->info.out_width;
1200                 oc->out_height = ovl->info.out_height;
1201                 oc->global_alpha = ovl->info.global_alpha;
1202
1203                 oc->replication =
1204                         dss_use_replication(dssdev, ovl->info.color_mode);
1205
1206                 oc->ilace = dssdev->type == OMAP_DISPLAY_TYPE_VENC;
1207
1208                 oc->channel = ovl->manager->id;
1209
1210                 oc->enabled = true;
1211
1212                 oc->manual_update =
1213                         dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE &&
1214                         dssdev->driver->get_update_mode(dssdev) !=
1215                                 OMAP_DSS_UPDATE_AUTO;
1216
1217                 ++num_planes_enabled;
1218         }
1219
1220         /* Configure managers */
1221         list_for_each_entry(mgr, &manager_list, list) {
1222                 struct omap_dss_device *dssdev;
1223
1224                 if (!(mgr->caps & OMAP_DSS_OVL_MGR_CAP_DISPC))
1225                         continue;
1226
1227                 mc = &dss_cache.manager_cache[mgr->id];
1228
1229                 if (mgr->device_changed) {
1230                         mgr->device_changed = false;
1231                         mgr->info_dirty  = true;
1232                 }
1233
1234                 if (!mgr->info_dirty)
1235                         continue;
1236
1237                 if (!mgr->device)
1238                         continue;
1239
1240                 dssdev = mgr->device;
1241
1242                 mgr->info_dirty = false;
1243                 mc->dirty = true;
1244
1245                 mc->default_color = mgr->info.default_color;
1246                 mc->trans_key_type = mgr->info.trans_key_type;
1247                 mc->trans_key = mgr->info.trans_key;
1248                 mc->trans_enabled = mgr->info.trans_enabled;
1249                 mc->alpha_enabled = mgr->info.alpha_enabled;
1250
1251                 mc->manual_upd_display =
1252                         dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE;
1253
1254                 mc->manual_update =
1255                         dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE &&
1256                         dssdev->driver->get_update_mode(dssdev) !=
1257                                 OMAP_DSS_UPDATE_AUTO;
1258         }
1259
1260         /* XXX TODO: Try to get fifomerge working. The problem is that it
1261          * affects both managers, not individually but at the same time. This
1262          * means the change has to be well synchronized. I guess the proper way
1263          * is to have a two step process for fifo merge:
1264          *        fifomerge enable:
1265          *             1. disable other planes, leaving one plane enabled
1266          *             2. wait until the planes are disabled on HW
1267          *             3. config merged fifo thresholds, enable fifomerge
1268          *        fifomerge disable:
1269          *             1. config unmerged fifo thresholds, disable fifomerge
1270          *             2. wait until fifo changes are in HW
1271          *             3. enable planes
1272          */
1273         use_fifomerge = false;
1274
1275         /* Configure overlay fifos */
1276         for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
1277                 struct omap_dss_device *dssdev;
1278                 u32 size;
1279
1280                 ovl = omap_dss_get_overlay(i);
1281
1282                 if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC))
1283                         continue;
1284
1285                 oc = &dss_cache.overlay_cache[ovl->id];
1286
1287                 if (!oc->enabled)
1288                         continue;
1289
1290                 dssdev = ovl->manager->device;
1291
1292                 size = dispc_get_plane_fifo_size(ovl->id);
1293                 if (use_fifomerge)
1294                         size *= 3;
1295
1296                 switch (dssdev->type) {
1297                 case OMAP_DISPLAY_TYPE_DPI:
1298                 case OMAP_DISPLAY_TYPE_DBI:
1299                 case OMAP_DISPLAY_TYPE_SDI:
1300                 case OMAP_DISPLAY_TYPE_VENC:
1301                         default_get_overlay_fifo_thresholds(ovl->id, size,
1302                                         &oc->burst_size, &oc->fifo_low,
1303                                         &oc->fifo_high);
1304                         break;
1305 #ifdef CONFIG_OMAP2_DSS_DSI
1306                 case OMAP_DISPLAY_TYPE_DSI:
1307                         dsi_get_overlay_fifo_thresholds(ovl->id, size,
1308                                         &oc->burst_size, &oc->fifo_low,
1309                                         &oc->fifo_high);
1310                         break;
1311 #endif
1312                 default:
1313                         BUG();
1314                 }
1315         }
1316
1317         r = 0;
1318         dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
1319         if (!dss_cache.irq_enabled) {
1320                 r = omap_dispc_register_isr(dss_apply_irq_handler, NULL,
1321                                 DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_ODD |
1322                                 DISPC_IRQ_EVSYNC_EVEN);
1323                 dss_cache.irq_enabled = true;
1324         }
1325         configure_dispc();
1326         dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
1327
1328         spin_unlock_irqrestore(&dss_cache.lock, flags);
1329
1330         return r;
1331 }
1332
1333 static int dss_check_manager(struct omap_overlay_manager *mgr)
1334 {
1335         /* OMAP supports only graphics source transparency color key and alpha
1336          * blending simultaneously. See TRM 15.4.2.4.2.2 Alpha Mode */
1337
1338         if (mgr->info.alpha_enabled && mgr->info.trans_enabled &&
1339                         mgr->info.trans_key_type != OMAP_DSS_COLOR_KEY_GFX_DST)
1340                 return -EINVAL;
1341
1342         return 0;
1343 }
1344
1345 static int omap_dss_mgr_set_info(struct omap_overlay_manager *mgr,
1346                 struct omap_overlay_manager_info *info)
1347 {
1348         int r;
1349         struct omap_overlay_manager_info old_info;
1350
1351         old_info = mgr->info;
1352         mgr->info = *info;
1353
1354         r = dss_check_manager(mgr);
1355         if (r) {
1356                 mgr->info = old_info;
1357                 return r;
1358         }
1359
1360         mgr->info_dirty = true;
1361
1362         return 0;
1363 }
1364
1365 static void omap_dss_mgr_get_info(struct omap_overlay_manager *mgr,
1366                 struct omap_overlay_manager_info *info)
1367 {
1368         *info = mgr->info;
1369 }
1370
1371 static int dss_mgr_enable(struct omap_overlay_manager *mgr)
1372 {
1373         dispc_enable_channel(mgr->id, 1);
1374         return 0;
1375 }
1376
1377 static int dss_mgr_disable(struct omap_overlay_manager *mgr)
1378 {
1379         dispc_enable_channel(mgr->id, 0);
1380         return 0;
1381 }
1382
1383 static void omap_dss_add_overlay_manager(struct omap_overlay_manager *manager)
1384 {
1385         ++num_managers;
1386         list_add_tail(&manager->list, &manager_list);
1387 }
1388
1389 int dss_init_overlay_managers(struct platform_device *pdev)
1390 {
1391         int i, r;
1392
1393         spin_lock_init(&dss_cache.lock);
1394
1395         INIT_LIST_HEAD(&manager_list);
1396
1397         num_managers = 0;
1398
1399         for (i = 0; i < 2; ++i) {
1400                 struct omap_overlay_manager *mgr;
1401                 mgr = kzalloc(sizeof(*mgr), GFP_KERNEL);
1402
1403                 BUG_ON(mgr == NULL);
1404
1405                 switch (i) {
1406                 case 0:
1407                         mgr->name = "lcd";
1408                         mgr->id = OMAP_DSS_CHANNEL_LCD;
1409                         mgr->supported_displays =
1410                                 OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI |
1411                                 OMAP_DISPLAY_TYPE_SDI | OMAP_DISPLAY_TYPE_DSI;
1412                         break;
1413                 case 1:
1414                         mgr->name = "tv";
1415                         mgr->id = OMAP_DSS_CHANNEL_DIGIT;
1416                         mgr->supported_displays = OMAP_DISPLAY_TYPE_VENC;
1417                         break;
1418                 }
1419
1420                 mgr->set_device = &omap_dss_set_device;
1421                 mgr->unset_device = &omap_dss_unset_device;
1422                 mgr->apply = &omap_dss_mgr_apply;
1423                 mgr->set_manager_info = &omap_dss_mgr_set_info;
1424                 mgr->get_manager_info = &omap_dss_mgr_get_info;
1425                 mgr->wait_for_go = &dss_mgr_wait_for_go;
1426                 mgr->wait_for_vsync = &dss_mgr_wait_for_vsync;
1427
1428                 mgr->enable = &dss_mgr_enable;
1429                 mgr->disable = &dss_mgr_disable;
1430
1431                 mgr->caps = OMAP_DSS_OVL_MGR_CAP_DISPC;
1432
1433                 dss_overlay_setup_dispc_manager(mgr);
1434
1435                 omap_dss_add_overlay_manager(mgr);
1436
1437                 r = kobject_init_and_add(&mgr->kobj, &manager_ktype,
1438                                 &pdev->dev.kobj, "manager%d", i);
1439
1440                 if (r) {
1441                         DSSERR("failed to create sysfs file\n");
1442                         continue;
1443                 }
1444         }
1445
1446 #ifdef L4_EXAMPLE
1447         {
1448                 int omap_dss_mgr_apply_l4(struct omap_overlay_manager *mgr)
1449                 {
1450                         DSSDBG("omap_dss_mgr_apply_l4(%s)\n", mgr->name);
1451
1452                         return 0;
1453                 }
1454
1455                 struct omap_overlay_manager *mgr;
1456                 mgr = kzalloc(sizeof(*mgr), GFP_KERNEL);
1457
1458                 BUG_ON(mgr == NULL);
1459
1460                 mgr->name = "l4";
1461                 mgr->supported_displays =
1462                         OMAP_DISPLAY_TYPE_DBI | OMAP_DISPLAY_TYPE_DSI;
1463
1464                 mgr->set_device = &omap_dss_set_device;
1465                 mgr->unset_device = &omap_dss_unset_device;
1466                 mgr->apply = &omap_dss_mgr_apply_l4;
1467                 mgr->set_manager_info = &omap_dss_mgr_set_info;
1468                 mgr->get_manager_info = &omap_dss_mgr_get_info;
1469
1470                 dss_overlay_setup_l4_manager(mgr);
1471
1472                 omap_dss_add_overlay_manager(mgr);
1473
1474                 r = kobject_init_and_add(&mgr->kobj, &manager_ktype,
1475                                 &pdev->dev.kobj, "managerl4");
1476
1477                 if (r)
1478                         DSSERR("failed to create sysfs file\n");
1479         }
1480 #endif
1481
1482         return 0;
1483 }
1484
1485 void dss_uninit_overlay_managers(struct platform_device *pdev)
1486 {
1487         struct omap_overlay_manager *mgr;
1488
1489         while (!list_empty(&manager_list)) {
1490                 mgr = list_first_entry(&manager_list,
1491                                 struct omap_overlay_manager, list);
1492                 list_del(&mgr->list);
1493                 kobject_del(&mgr->kobj);
1494                 kobject_put(&mgr->kobj);
1495                 kfree(mgr);
1496         }
1497
1498         num_managers = 0;
1499 }
1500
1501 int omap_dss_get_num_overlay_managers(void)
1502 {
1503         return num_managers;
1504 }
1505 EXPORT_SYMBOL(omap_dss_get_num_overlay_managers);
1506
1507 struct omap_overlay_manager *omap_dss_get_overlay_manager(int num)
1508 {
1509         int i = 0;
1510         struct omap_overlay_manager *mgr;
1511
1512         list_for_each_entry(mgr, &manager_list, list) {
1513                 if (i++ == num)
1514                         return mgr;
1515         }
1516
1517         return NULL;
1518 }
1519 EXPORT_SYMBOL(omap_dss_get_overlay_manager);
1520