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