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