Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ericvh...
[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_default_color(channel, c->default_color);
847         dispc_set_trans_key(channel, c->trans_key_type, c->trans_key);
848         dispc_enable_trans_key(channel, c->trans_enabled);
849         dispc_enable_alpha_blending(channel, c->alpha_enabled);
850 }
851
852 /* configure_dispc() tries to write values from cache to shadow registers.
853  * It writes only to those managers/overlays that are not busy.
854  * returns 0 if everything could be written to shadow registers.
855  * returns 1 if not everything could be written to shadow registers. */
856 static int configure_dispc(void)
857 {
858         struct overlay_cache_data *oc;
859         struct manager_cache_data *mc;
860         const int num_ovls = ARRAY_SIZE(dss_cache.overlay_cache);
861         const int num_mgrs = ARRAY_SIZE(dss_cache.manager_cache);
862         int i;
863         int r;
864         bool mgr_busy[2];
865         bool mgr_go[2];
866         bool busy;
867
868         r = 0;
869         busy = false;
870
871         mgr_busy[0] = dispc_go_busy(0);
872         mgr_busy[1] = dispc_go_busy(1);
873         mgr_go[0] = false;
874         mgr_go[1] = false;
875
876         /* Commit overlay settings */
877         for (i = 0; i < num_ovls; ++i) {
878                 oc = &dss_cache.overlay_cache[i];
879                 mc = &dss_cache.manager_cache[oc->channel];
880
881                 if (!oc->dirty)
882                         continue;
883
884                 if (oc->manual_update && !mc->do_manual_update)
885                         continue;
886
887                 if (mgr_busy[oc->channel]) {
888                         busy = true;
889                         continue;
890                 }
891
892                 r = configure_overlay(i);
893                 if (r)
894                         DSSERR("configure_overlay %d failed\n", i);
895
896                 oc->dirty = false;
897                 oc->shadow_dirty = true;
898                 mgr_go[oc->channel] = true;
899         }
900
901         /* Commit manager settings */
902         for (i = 0; i < num_mgrs; ++i) {
903                 mc = &dss_cache.manager_cache[i];
904
905                 if (!mc->dirty)
906                         continue;
907
908                 if (mc->manual_update && !mc->do_manual_update)
909                         continue;
910
911                 if (mgr_busy[i]) {
912                         busy = true;
913                         continue;
914                 }
915
916                 configure_manager(i);
917                 mc->dirty = false;
918                 mc->shadow_dirty = true;
919                 mgr_go[i] = true;
920         }
921
922         /* set GO */
923         for (i = 0; i < num_mgrs; ++i) {
924                 mc = &dss_cache.manager_cache[i];
925
926                 if (!mgr_go[i])
927                         continue;
928
929                 /* We don't need GO with manual update display. LCD iface will
930                  * always be turned off after frame, and new settings will be
931                  * taken in to use at next update */
932                 if (!mc->manual_upd_display)
933                         dispc_go(i);
934         }
935
936         if (busy)
937                 r = 1;
938         else
939                 r = 0;
940
941         return r;
942 }
943
944 /* Make the coordinates even. There are some strange problems with OMAP and
945  * partial DSI update when the update widths are odd. */
946 static void make_even(u16 *x, u16 *w)
947 {
948         u16 x1, x2;
949
950         x1 = *x;
951         x2 = *x + *w;
952
953         x1 &= ~1;
954         x2 = ALIGN(x2, 2);
955
956         *x = x1;
957         *w = x2 - x1;
958 }
959
960 /* Configure dispc for partial update. Return possibly modified update
961  * area */
962 void dss_setup_partial_planes(struct omap_dss_device *dssdev,
963                 u16 *xi, u16 *yi, u16 *wi, u16 *hi)
964 {
965         struct overlay_cache_data *oc;
966         struct manager_cache_data *mc;
967         const int num_ovls = ARRAY_SIZE(dss_cache.overlay_cache);
968         struct omap_overlay_manager *mgr;
969         int i;
970         u16 x, y, w, h;
971         unsigned long flags;
972
973         x = *xi;
974         y = *yi;
975         w = *wi;
976         h = *hi;
977
978         DSSDBG("dispc_setup_partial_planes %d,%d %dx%d\n",
979                 *xi, *yi, *wi, *hi);
980
981         mgr = dssdev->manager;
982
983         if (!mgr) {
984                 DSSDBG("no manager\n");
985                 return;
986         }
987
988         make_even(&x, &w);
989
990         spin_lock_irqsave(&dss_cache.lock, flags);
991
992         /* We need to show the whole overlay if it is scaled. So look for
993          * those, and make the update area larger if found.
994          * Also mark the overlay cache dirty */
995         for (i = 0; i < num_ovls; ++i) {
996                 unsigned x1, y1, x2, y2;
997                 unsigned outw, outh;
998
999                 oc = &dss_cache.overlay_cache[i];
1000
1001                 if (oc->channel != mgr->id)
1002                         continue;
1003
1004                 oc->dirty = true;
1005
1006                 if (!oc->enabled)
1007                         continue;
1008
1009                 if (!dispc_is_overlay_scaled(oc))
1010                         continue;
1011
1012                 outw = oc->out_width == 0 ? oc->width : oc->out_width;
1013                 outh = oc->out_height == 0 ? oc->height : oc->out_height;
1014
1015                 /* is the overlay outside the update region? */
1016                 if (!rectangle_intersects(x, y, w, h,
1017                                         oc->pos_x, oc->pos_y,
1018                                         outw, outh))
1019                         continue;
1020
1021                 /* if the overlay totally inside the update region? */
1022                 if (rectangle_subset(oc->pos_x, oc->pos_y, outw, outh,
1023                                         x, y, w, h))
1024                         continue;
1025
1026                 if (x > oc->pos_x)
1027                         x1 = oc->pos_x;
1028                 else
1029                         x1 = x;
1030
1031                 if (y > oc->pos_y)
1032                         y1 = oc->pos_y;
1033                 else
1034                         y1 = y;
1035
1036                 if ((x + w) < (oc->pos_x + outw))
1037                         x2 = oc->pos_x + outw;
1038                 else
1039                         x2 = x + w;
1040
1041                 if ((y + h) < (oc->pos_y + outh))
1042                         y2 = oc->pos_y + outh;
1043                 else
1044                         y2 = y + h;
1045
1046                 x = x1;
1047                 y = y1;
1048                 w = x2 - x1;
1049                 h = y2 - y1;
1050
1051                 make_even(&x, &w);
1052
1053                 DSSDBG("changing upd area due to ovl(%d) scaling %d,%d %dx%d\n",
1054                                 i, x, y, w, h);
1055         }
1056
1057         mc = &dss_cache.manager_cache[mgr->id];
1058         mc->do_manual_update = true;
1059         mc->x = x;
1060         mc->y = y;
1061         mc->w = w;
1062         mc->h = h;
1063
1064         configure_dispc();
1065
1066         mc->do_manual_update = false;
1067
1068         spin_unlock_irqrestore(&dss_cache.lock, flags);
1069
1070         *xi = x;
1071         *yi = y;
1072         *wi = w;
1073         *hi = h;
1074 }
1075
1076 void dss_start_update(struct omap_dss_device *dssdev)
1077 {
1078         struct manager_cache_data *mc;
1079         struct overlay_cache_data *oc;
1080         const int num_ovls = ARRAY_SIZE(dss_cache.overlay_cache);
1081         const int num_mgrs = ARRAY_SIZE(dss_cache.manager_cache);
1082         struct omap_overlay_manager *mgr;
1083         int i;
1084
1085         mgr = dssdev->manager;
1086
1087         for (i = 0; i < num_ovls; ++i) {
1088                 oc = &dss_cache.overlay_cache[i];
1089                 if (oc->channel != mgr->id)
1090                         continue;
1091
1092                 oc->shadow_dirty = false;
1093         }
1094
1095         for (i = 0; i < num_mgrs; ++i) {
1096                 mc = &dss_cache.manager_cache[i];
1097                 if (mgr->id != i)
1098                         continue;
1099
1100                 mc->shadow_dirty = false;
1101         }
1102
1103         dssdev->manager->enable(dssdev->manager);
1104 }
1105
1106 static void dss_apply_irq_handler(void *data, u32 mask)
1107 {
1108         struct manager_cache_data *mc;
1109         struct overlay_cache_data *oc;
1110         const int num_ovls = ARRAY_SIZE(dss_cache.overlay_cache);
1111         const int num_mgrs = ARRAY_SIZE(dss_cache.manager_cache);
1112         int i, r;
1113         bool mgr_busy[2];
1114
1115         mgr_busy[0] = dispc_go_busy(0);
1116         mgr_busy[1] = dispc_go_busy(1);
1117
1118         spin_lock(&dss_cache.lock);
1119
1120         for (i = 0; i < num_ovls; ++i) {
1121                 oc = &dss_cache.overlay_cache[i];
1122                 if (!mgr_busy[oc->channel])
1123                         oc->shadow_dirty = false;
1124         }
1125
1126         for (i = 0; i < num_mgrs; ++i) {
1127                 mc = &dss_cache.manager_cache[i];
1128                 if (!mgr_busy[i])
1129                         mc->shadow_dirty = false;
1130         }
1131
1132         r = configure_dispc();
1133         if (r == 1)
1134                 goto end;
1135
1136         /* re-read busy flags */
1137         mgr_busy[0] = dispc_go_busy(0);
1138         mgr_busy[1] = dispc_go_busy(1);
1139
1140         /* keep running as long as there are busy managers, so that
1141          * we can collect overlay-applied information */
1142         for (i = 0; i < num_mgrs; ++i) {
1143                 if (mgr_busy[i])
1144                         goto end;
1145         }
1146
1147         omap_dispc_unregister_isr(dss_apply_irq_handler, NULL,
1148                         DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_ODD |
1149                         DISPC_IRQ_EVSYNC_EVEN);
1150         dss_cache.irq_enabled = false;
1151
1152 end:
1153         spin_unlock(&dss_cache.lock);
1154 }
1155
1156 static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
1157 {
1158         struct overlay_cache_data *oc;
1159         struct manager_cache_data *mc;
1160         int i;
1161         struct omap_overlay *ovl;
1162         int num_planes_enabled = 0;
1163         bool use_fifomerge;
1164         unsigned long flags;
1165         int r;
1166
1167         DSSDBG("omap_dss_mgr_apply(%s)\n", mgr->name);
1168
1169         spin_lock_irqsave(&dss_cache.lock, flags);
1170
1171         /* Configure overlays */
1172         for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
1173                 struct omap_dss_device *dssdev;
1174
1175                 ovl = omap_dss_get_overlay(i);
1176
1177                 if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC))
1178                         continue;
1179
1180                 oc = &dss_cache.overlay_cache[ovl->id];
1181
1182                 if (!overlay_enabled(ovl)) {
1183                         if (oc->enabled) {
1184                                 oc->enabled = false;
1185                                 oc->dirty = true;
1186                         }
1187                         continue;
1188                 }
1189
1190                 if (!ovl->info_dirty) {
1191                         if (oc->enabled)
1192                                 ++num_planes_enabled;
1193                         continue;
1194                 }
1195
1196                 dssdev = ovl->manager->device;
1197
1198                 if (dss_check_overlay(ovl, dssdev)) {
1199                         if (oc->enabled) {
1200                                 oc->enabled = false;
1201                                 oc->dirty = true;
1202                         }
1203                         continue;
1204                 }
1205
1206                 ovl->info_dirty = false;
1207                 oc->dirty = true;
1208
1209                 oc->paddr = ovl->info.paddr;
1210                 oc->vaddr = ovl->info.vaddr;
1211                 oc->screen_width = ovl->info.screen_width;
1212                 oc->width = ovl->info.width;
1213                 oc->height = ovl->info.height;
1214                 oc->color_mode = ovl->info.color_mode;
1215                 oc->rotation = ovl->info.rotation;
1216                 oc->rotation_type = ovl->info.rotation_type;
1217                 oc->mirror = ovl->info.mirror;
1218                 oc->pos_x = ovl->info.pos_x;
1219                 oc->pos_y = ovl->info.pos_y;
1220                 oc->out_width = ovl->info.out_width;
1221                 oc->out_height = ovl->info.out_height;
1222                 oc->global_alpha = ovl->info.global_alpha;
1223
1224                 oc->replication =
1225                         dss_use_replication(dssdev, ovl->info.color_mode);
1226
1227                 oc->ilace = dssdev->type == OMAP_DISPLAY_TYPE_VENC;
1228
1229                 oc->channel = ovl->manager->id;
1230
1231                 oc->enabled = true;
1232
1233                 oc->manual_update =
1234                         dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE &&
1235                         dssdev->driver->get_update_mode(dssdev) !=
1236                                 OMAP_DSS_UPDATE_AUTO;
1237
1238                 ++num_planes_enabled;
1239         }
1240
1241         /* Configure managers */
1242         list_for_each_entry(mgr, &manager_list, list) {
1243                 struct omap_dss_device *dssdev;
1244
1245                 if (!(mgr->caps & OMAP_DSS_OVL_MGR_CAP_DISPC))
1246                         continue;
1247
1248                 mc = &dss_cache.manager_cache[mgr->id];
1249
1250                 if (mgr->device_changed) {
1251                         mgr->device_changed = false;
1252                         mgr->info_dirty  = true;
1253                 }
1254
1255                 if (!mgr->info_dirty)
1256                         continue;
1257
1258                 if (!mgr->device)
1259                         continue;
1260
1261                 dssdev = mgr->device;
1262
1263                 mgr->info_dirty = false;
1264                 mc->dirty = true;
1265
1266                 mc->default_color = mgr->info.default_color;
1267                 mc->trans_key_type = mgr->info.trans_key_type;
1268                 mc->trans_key = mgr->info.trans_key;
1269                 mc->trans_enabled = mgr->info.trans_enabled;
1270                 mc->alpha_enabled = mgr->info.alpha_enabled;
1271
1272                 mc->manual_upd_display =
1273                         dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE;
1274
1275                 mc->manual_update =
1276                         dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE &&
1277                         dssdev->driver->get_update_mode(dssdev) !=
1278                                 OMAP_DSS_UPDATE_AUTO;
1279         }
1280
1281         /* XXX TODO: Try to get fifomerge working. The problem is that it
1282          * affects both managers, not individually but at the same time. This
1283          * means the change has to be well synchronized. I guess the proper way
1284          * is to have a two step process for fifo merge:
1285          *        fifomerge enable:
1286          *             1. disable other planes, leaving one plane enabled
1287          *             2. wait until the planes are disabled on HW
1288          *             3. config merged fifo thresholds, enable fifomerge
1289          *        fifomerge disable:
1290          *             1. config unmerged fifo thresholds, disable fifomerge
1291          *             2. wait until fifo changes are in HW
1292          *             3. enable planes
1293          */
1294         use_fifomerge = false;
1295
1296         /* Configure overlay fifos */
1297         for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
1298                 struct omap_dss_device *dssdev;
1299                 u32 size;
1300
1301                 ovl = omap_dss_get_overlay(i);
1302
1303                 if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC))
1304                         continue;
1305
1306                 oc = &dss_cache.overlay_cache[ovl->id];
1307
1308                 if (!oc->enabled)
1309                         continue;
1310
1311                 dssdev = ovl->manager->device;
1312
1313                 size = dispc_get_plane_fifo_size(ovl->id);
1314                 if (use_fifomerge)
1315                         size *= 3;
1316
1317                 switch (dssdev->type) {
1318                 case OMAP_DISPLAY_TYPE_DPI:
1319                 case OMAP_DISPLAY_TYPE_DBI:
1320                 case OMAP_DISPLAY_TYPE_SDI:
1321                 case OMAP_DISPLAY_TYPE_VENC:
1322                         default_get_overlay_fifo_thresholds(ovl->id, size,
1323                                         &oc->burst_size, &oc->fifo_low,
1324                                         &oc->fifo_high);
1325                         break;
1326 #ifdef CONFIG_OMAP2_DSS_DSI
1327                 case OMAP_DISPLAY_TYPE_DSI:
1328                         dsi_get_overlay_fifo_thresholds(ovl->id, size,
1329                                         &oc->burst_size, &oc->fifo_low,
1330                                         &oc->fifo_high);
1331                         break;
1332 #endif
1333                 default:
1334                         BUG();
1335                 }
1336         }
1337
1338         r = 0;
1339         dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
1340         if (!dss_cache.irq_enabled) {
1341                 r = omap_dispc_register_isr(dss_apply_irq_handler, NULL,
1342                                 DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_ODD |
1343                                 DISPC_IRQ_EVSYNC_EVEN);
1344                 dss_cache.irq_enabled = true;
1345         }
1346         configure_dispc();
1347         dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
1348
1349         spin_unlock_irqrestore(&dss_cache.lock, flags);
1350
1351         return r;
1352 }
1353
1354 static int dss_check_manager(struct omap_overlay_manager *mgr)
1355 {
1356         /* OMAP supports only graphics source transparency color key and alpha
1357          * blending simultaneously. See TRM 15.4.2.4.2.2 Alpha Mode */
1358
1359         if (mgr->info.alpha_enabled && mgr->info.trans_enabled &&
1360                         mgr->info.trans_key_type != OMAP_DSS_COLOR_KEY_GFX_DST)
1361                 return -EINVAL;
1362
1363         return 0;
1364 }
1365
1366 static int omap_dss_mgr_set_info(struct omap_overlay_manager *mgr,
1367                 struct omap_overlay_manager_info *info)
1368 {
1369         int r;
1370         struct omap_overlay_manager_info old_info;
1371
1372         old_info = mgr->info;
1373         mgr->info = *info;
1374
1375         r = dss_check_manager(mgr);
1376         if (r) {
1377                 mgr->info = old_info;
1378                 return r;
1379         }
1380
1381         mgr->info_dirty = true;
1382
1383         return 0;
1384 }
1385
1386 static void omap_dss_mgr_get_info(struct omap_overlay_manager *mgr,
1387                 struct omap_overlay_manager_info *info)
1388 {
1389         *info = mgr->info;
1390 }
1391
1392 static int dss_mgr_enable(struct omap_overlay_manager *mgr)
1393 {
1394         dispc_enable_channel(mgr->id, 1);
1395         return 0;
1396 }
1397
1398 static int dss_mgr_disable(struct omap_overlay_manager *mgr)
1399 {
1400         dispc_enable_channel(mgr->id, 0);
1401         return 0;
1402 }
1403
1404 static void omap_dss_add_overlay_manager(struct omap_overlay_manager *manager)
1405 {
1406         ++num_managers;
1407         list_add_tail(&manager->list, &manager_list);
1408 }
1409
1410 int dss_init_overlay_managers(struct platform_device *pdev)
1411 {
1412         int i, r;
1413
1414         spin_lock_init(&dss_cache.lock);
1415
1416         INIT_LIST_HEAD(&manager_list);
1417
1418         num_managers = 0;
1419
1420         for (i = 0; i < 2; ++i) {
1421                 struct omap_overlay_manager *mgr;
1422                 mgr = kzalloc(sizeof(*mgr), GFP_KERNEL);
1423
1424                 BUG_ON(mgr == NULL);
1425
1426                 switch (i) {
1427                 case 0:
1428                         mgr->name = "lcd";
1429                         mgr->id = OMAP_DSS_CHANNEL_LCD;
1430                         mgr->supported_displays =
1431                                 OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI |
1432                                 OMAP_DISPLAY_TYPE_SDI | OMAP_DISPLAY_TYPE_DSI;
1433                         break;
1434                 case 1:
1435                         mgr->name = "tv";
1436                         mgr->id = OMAP_DSS_CHANNEL_DIGIT;
1437                         mgr->supported_displays = OMAP_DISPLAY_TYPE_VENC;
1438                         break;
1439                 }
1440
1441                 mgr->set_device = &omap_dss_set_device;
1442                 mgr->unset_device = &omap_dss_unset_device;
1443                 mgr->apply = &omap_dss_mgr_apply;
1444                 mgr->set_manager_info = &omap_dss_mgr_set_info;
1445                 mgr->get_manager_info = &omap_dss_mgr_get_info;
1446                 mgr->wait_for_go = &dss_mgr_wait_for_go;
1447                 mgr->wait_for_vsync = &dss_mgr_wait_for_vsync;
1448
1449                 mgr->enable = &dss_mgr_enable;
1450                 mgr->disable = &dss_mgr_disable;
1451
1452                 mgr->caps = OMAP_DSS_OVL_MGR_CAP_DISPC;
1453
1454                 dss_overlay_setup_dispc_manager(mgr);
1455
1456                 omap_dss_add_overlay_manager(mgr);
1457
1458                 r = kobject_init_and_add(&mgr->kobj, &manager_ktype,
1459                                 &pdev->dev.kobj, "manager%d", i);
1460
1461                 if (r) {
1462                         DSSERR("failed to create sysfs file\n");
1463                         continue;
1464                 }
1465         }
1466
1467 #ifdef L4_EXAMPLE
1468         {
1469                 int omap_dss_mgr_apply_l4(struct omap_overlay_manager *mgr)
1470                 {
1471                         DSSDBG("omap_dss_mgr_apply_l4(%s)\n", mgr->name);
1472
1473                         return 0;
1474                 }
1475
1476                 struct omap_overlay_manager *mgr;
1477                 mgr = kzalloc(sizeof(*mgr), GFP_KERNEL);
1478
1479                 BUG_ON(mgr == NULL);
1480
1481                 mgr->name = "l4";
1482                 mgr->supported_displays =
1483                         OMAP_DISPLAY_TYPE_DBI | OMAP_DISPLAY_TYPE_DSI;
1484
1485                 mgr->set_device = &omap_dss_set_device;
1486                 mgr->unset_device = &omap_dss_unset_device;
1487                 mgr->apply = &omap_dss_mgr_apply_l4;
1488                 mgr->set_manager_info = &omap_dss_mgr_set_info;
1489                 mgr->get_manager_info = &omap_dss_mgr_get_info;
1490
1491                 dss_overlay_setup_l4_manager(mgr);
1492
1493                 omap_dss_add_overlay_manager(mgr);
1494
1495                 r = kobject_init_and_add(&mgr->kobj, &manager_ktype,
1496                                 &pdev->dev.kobj, "managerl4");
1497
1498                 if (r)
1499                         DSSERR("failed to create sysfs file\n");
1500         }
1501 #endif
1502
1503         return 0;
1504 }
1505
1506 void dss_uninit_overlay_managers(struct platform_device *pdev)
1507 {
1508         struct omap_overlay_manager *mgr;
1509
1510         while (!list_empty(&manager_list)) {
1511                 mgr = list_first_entry(&manager_list,
1512                                 struct omap_overlay_manager, list);
1513                 list_del(&mgr->list);
1514                 kobject_del(&mgr->kobj);
1515                 kobject_put(&mgr->kobj);
1516                 kfree(mgr);
1517         }
1518
1519         num_managers = 0;
1520 }
1521
1522 int omap_dss_get_num_overlay_managers(void)
1523 {
1524         return num_managers;
1525 }
1526 EXPORT_SYMBOL(omap_dss_get_num_overlay_managers);
1527
1528 struct omap_overlay_manager *omap_dss_get_overlay_manager(int num)
1529 {
1530         int i = 0;
1531         struct omap_overlay_manager *mgr;
1532
1533         list_for_each_entry(mgr, &manager_list, list) {
1534                 if (i++ == num)
1535                         return mgr;
1536         }
1537
1538         return NULL;
1539 }
1540 EXPORT_SYMBOL(omap_dss_get_overlay_manager);
1541