Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6
[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
410         enum omap_channel channel;
411         bool replication;
412         bool ilace;
413
414         enum omap_burst_size burst_size;
415         u32 fifo_low;
416         u32 fifo_high;
417
418         bool manual_update;
419 };
420
421 struct manager_cache_data {
422         /* If true, cache changed, but not written to shadow registers. Set
423          * in apply(), cleared when registers written. */
424         bool dirty;
425         /* If true, shadow registers contain changed values not yet in real
426          * registers. Set when writing to shadow registers, cleared at
427          * VSYNC/EVSYNC */
428         bool shadow_dirty;
429
430         u32 default_color;
431
432         enum omap_dss_trans_key_type trans_key_type;
433         u32 trans_key;
434         bool trans_enabled;
435
436         bool alpha_enabled;
437
438         bool manual_upd_display;
439         bool manual_update;
440         bool do_manual_update;
441
442         /* manual update region */
443         u16 x, y, w, h;
444
445         /* enlarge the update area if the update area contains scaled
446          * overlays */
447         bool enlarge_update_area;
448 };
449
450 static struct {
451         spinlock_t lock;
452         struct overlay_cache_data overlay_cache[MAX_DSS_OVERLAYS];
453         struct manager_cache_data manager_cache[MAX_DSS_MANAGERS];
454
455         bool irq_enabled;
456 } dss_cache;
457
458
459
460 static int omap_dss_set_device(struct omap_overlay_manager *mgr,
461                 struct omap_dss_device *dssdev)
462 {
463         int i;
464         int r;
465
466         if (dssdev->manager) {
467                 DSSERR("display '%s' already has a manager '%s'\n",
468                                dssdev->name, dssdev->manager->name);
469                 return -EINVAL;
470         }
471
472         if ((mgr->supported_displays & dssdev->type) == 0) {
473                 DSSERR("display '%s' does not support manager '%s'\n",
474                                dssdev->name, mgr->name);
475                 return -EINVAL;
476         }
477
478         for (i = 0; i < mgr->num_overlays; i++) {
479                 struct omap_overlay *ovl = mgr->overlays[i];
480
481                 if (ovl->manager != mgr || !ovl->info.enabled)
482                         continue;
483
484                 r = dss_check_overlay(ovl, dssdev);
485                 if (r)
486                         return r;
487         }
488
489         dssdev->manager = mgr;
490         mgr->device = dssdev;
491         mgr->device_changed = true;
492
493         return 0;
494 }
495
496 static int omap_dss_unset_device(struct omap_overlay_manager *mgr)
497 {
498         if (!mgr->device) {
499                 DSSERR("failed to unset display, display not set.\n");
500                 return -EINVAL;
501         }
502
503         mgr->device->manager = NULL;
504         mgr->device = NULL;
505         mgr->device_changed = true;
506
507         return 0;
508 }
509
510 static int dss_mgr_wait_for_vsync(struct omap_overlay_manager *mgr)
511 {
512         unsigned long timeout = msecs_to_jiffies(500);
513         u32 irq;
514
515         if (mgr->device->type == OMAP_DISPLAY_TYPE_VENC)
516                 irq = DISPC_IRQ_EVSYNC_ODD;
517         else
518                 irq = DISPC_IRQ_VSYNC;
519
520         return omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
521 }
522
523 static int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr)
524 {
525         unsigned long timeout = msecs_to_jiffies(500);
526         struct manager_cache_data *mc;
527         enum omap_channel channel;
528         u32 irq;
529         int r;
530         int i;
531         struct omap_dss_device *dssdev = mgr->device;
532
533         if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
534                 return 0;
535
536         if (dssdev->type == OMAP_DISPLAY_TYPE_VENC) {
537                 irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN;
538                 channel = OMAP_DSS_CHANNEL_DIGIT;
539         } else {
540                 if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) {
541                         enum omap_dss_update_mode mode;
542                         mode = dssdev->driver->get_update_mode(dssdev);
543                         if (mode != OMAP_DSS_UPDATE_AUTO)
544                                 return 0;
545
546                         irq = DISPC_IRQ_FRAMEDONE;
547                 } else {
548                         irq = DISPC_IRQ_VSYNC;
549                 }
550                 channel = OMAP_DSS_CHANNEL_LCD;
551         }
552
553         mc = &dss_cache.manager_cache[mgr->id];
554         i = 0;
555         while (1) {
556                 unsigned long flags;
557                 bool shadow_dirty, dirty;
558
559                 spin_lock_irqsave(&dss_cache.lock, flags);
560                 dirty = mc->dirty;
561                 shadow_dirty = mc->shadow_dirty;
562                 spin_unlock_irqrestore(&dss_cache.lock, flags);
563
564                 if (!dirty && !shadow_dirty) {
565                         r = 0;
566                         break;
567                 }
568
569                 /* 4 iterations is the worst case:
570                  * 1 - initial iteration, dirty = true (between VFP and VSYNC)
571                  * 2 - first VSYNC, dirty = true
572                  * 3 - dirty = false, shadow_dirty = true
573                  * 4 - shadow_dirty = false */
574                 if (i++ == 3) {
575                         DSSERR("mgr(%d)->wait_for_go() not finishing\n",
576                                         mgr->id);
577                         r = 0;
578                         break;
579                 }
580
581                 r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
582                 if (r == -ERESTARTSYS)
583                         break;
584
585                 if (r) {
586                         DSSERR("mgr(%d)->wait_for_go() timeout\n", mgr->id);
587                         break;
588                 }
589         }
590
591         return r;
592 }
593
594 int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl)
595 {
596         unsigned long timeout = msecs_to_jiffies(500);
597         enum omap_channel channel;
598         struct overlay_cache_data *oc;
599         struct omap_dss_device *dssdev;
600         u32 irq;
601         int r;
602         int i;
603
604         if (!ovl->manager)
605                 return 0;
606
607         dssdev = ovl->manager->device;
608
609         if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
610                 return 0;
611
612         if (dssdev->type == OMAP_DISPLAY_TYPE_VENC) {
613                 irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN;
614                 channel = OMAP_DSS_CHANNEL_DIGIT;
615         } else {
616                 if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) {
617                         enum omap_dss_update_mode mode;
618                         mode = dssdev->driver->get_update_mode(dssdev);
619                         if (mode != OMAP_DSS_UPDATE_AUTO)
620                                 return 0;
621
622                         irq = DISPC_IRQ_FRAMEDONE;
623                 } else {
624                         irq = DISPC_IRQ_VSYNC;
625                 }
626                 channel = OMAP_DSS_CHANNEL_LCD;
627         }
628
629         oc = &dss_cache.overlay_cache[ovl->id];
630         i = 0;
631         while (1) {
632                 unsigned long flags;
633                 bool shadow_dirty, dirty;
634
635                 spin_lock_irqsave(&dss_cache.lock, flags);
636                 dirty = oc->dirty;
637                 shadow_dirty = oc->shadow_dirty;
638                 spin_unlock_irqrestore(&dss_cache.lock, flags);
639
640                 if (!dirty && !shadow_dirty) {
641                         r = 0;
642                         break;
643                 }
644
645                 /* 4 iterations is the worst case:
646                  * 1 - initial iteration, dirty = true (between VFP and VSYNC)
647                  * 2 - first VSYNC, dirty = true
648                  * 3 - dirty = false, shadow_dirty = true
649                  * 4 - shadow_dirty = false */
650                 if (i++ == 3) {
651                         DSSERR("ovl(%d)->wait_for_go() not finishing\n",
652                                         ovl->id);
653                         r = 0;
654                         break;
655                 }
656
657                 r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
658                 if (r == -ERESTARTSYS)
659                         break;
660
661                 if (r) {
662                         DSSERR("ovl(%d)->wait_for_go() timeout\n", ovl->id);
663                         break;
664                 }
665         }
666
667         return r;
668 }
669
670 static int overlay_enabled(struct omap_overlay *ovl)
671 {
672         return ovl->info.enabled && ovl->manager && ovl->manager->device;
673 }
674
675 /* Is rect1 a subset of rect2? */
676 static bool rectangle_subset(int x1, int y1, int w1, int h1,
677                 int x2, int y2, int w2, int h2)
678 {
679         if (x1 < x2 || y1 < y2)
680                 return false;
681
682         if (x1 + w1 > x2 + w2)
683                 return false;
684
685         if (y1 + h1 > y2 + h2)
686                 return false;
687
688         return true;
689 }
690
691 /* Do rect1 and rect2 overlap? */
692 static bool rectangle_intersects(int x1, int y1, int w1, int h1,
693                 int x2, int y2, int w2, int h2)
694 {
695         if (x1 >= x2 + w2)
696                 return false;
697
698         if (x2 >= x1 + w1)
699                 return false;
700
701         if (y1 >= y2 + h2)
702                 return false;
703
704         if (y2 >= y1 + h1)
705                 return false;
706
707         return true;
708 }
709
710 static bool dispc_is_overlay_scaled(struct overlay_cache_data *oc)
711 {
712         if (oc->out_width != 0 && oc->width != oc->out_width)
713                 return true;
714
715         if (oc->out_height != 0 && oc->height != oc->out_height)
716                 return true;
717
718         return false;
719 }
720
721 static int configure_overlay(enum omap_plane plane)
722 {
723         struct overlay_cache_data *c;
724         struct manager_cache_data *mc;
725         u16 outw, outh;
726         u16 x, y, w, h;
727         u32 paddr;
728         int r;
729         u16 orig_w, orig_h, orig_outw, orig_outh;
730
731         DSSDBGF("%d", plane);
732
733         c = &dss_cache.overlay_cache[plane];
734
735         if (!c->enabled) {
736                 dispc_enable_plane(plane, 0);
737                 return 0;
738         }
739
740         mc = &dss_cache.manager_cache[c->channel];
741
742         x = c->pos_x;
743         y = c->pos_y;
744         w = c->width;
745         h = c->height;
746         outw = c->out_width == 0 ? c->width : c->out_width;
747         outh = c->out_height == 0 ? c->height : c->out_height;
748         paddr = c->paddr;
749
750         orig_w = w;
751         orig_h = h;
752         orig_outw = outw;
753         orig_outh = outh;
754
755         if (c->manual_update && mc->do_manual_update) {
756                 unsigned bpp;
757                 unsigned scale_x_m = w, scale_x_d = outw;
758                 unsigned scale_y_m = h, scale_y_d = outh;
759
760                 /* If the overlay is outside the update region, disable it */
761                 if (!rectangle_intersects(mc->x, mc->y, mc->w, mc->h,
762                                         x, y, outw, outh)) {
763                         dispc_enable_plane(plane, 0);
764                         return 0;
765                 }
766
767                 switch (c->color_mode) {
768                 case OMAP_DSS_COLOR_RGB16:
769                 case OMAP_DSS_COLOR_ARGB16:
770                 case OMAP_DSS_COLOR_YUV2:
771                 case OMAP_DSS_COLOR_UYVY:
772                         bpp = 16;
773                         break;
774
775                 case OMAP_DSS_COLOR_RGB24P:
776                         bpp = 24;
777                         break;
778
779                 case OMAP_DSS_COLOR_RGB24U:
780                 case OMAP_DSS_COLOR_ARGB32:
781                 case OMAP_DSS_COLOR_RGBA32:
782                 case OMAP_DSS_COLOR_RGBX32:
783                         bpp = 32;
784                         break;
785
786                 default:
787                         BUG();
788                 }
789
790                 if (mc->x > c->pos_x) {
791                         x = 0;
792                         outw -= (mc->x - c->pos_x);
793                         paddr += (mc->x - c->pos_x) *
794                                 scale_x_m / scale_x_d * bpp / 8;
795                 } else {
796                         x = c->pos_x - mc->x;
797                 }
798
799                 if (mc->y > c->pos_y) {
800                         y = 0;
801                         outh -= (mc->y - c->pos_y);
802                         paddr += (mc->y - c->pos_y) *
803                                 scale_y_m / scale_y_d *
804                                 c->screen_width * bpp / 8;
805                 } else {
806                         y = c->pos_y - mc->y;
807                 }
808
809                 if (mc->w < (x + outw))
810                         outw -= (x + outw) - (mc->w);
811
812                 if (mc->h < (y + outh))
813                         outh -= (y + outh) - (mc->h);
814
815                 w = w * outw / orig_outw;
816                 h = h * outh / orig_outh;
817
818                 /* YUV mode overlay's input width has to be even and the
819                  * algorithm above may adjust the width to be odd.
820                  *
821                  * Here we adjust the width if needed, preferring to increase
822                  * the width if the original width was bigger.
823                  */
824                 if ((w & 1) &&
825                                 (c->color_mode == OMAP_DSS_COLOR_YUV2 ||
826                                  c->color_mode == OMAP_DSS_COLOR_UYVY)) {
827                         if (orig_w > w)
828                                 w += 1;
829                         else
830                                 w -= 1;
831                 }
832         }
833
834         r = dispc_setup_plane(plane,
835                         paddr,
836                         c->screen_width,
837                         x, y,
838                         w, h,
839                         outw, outh,
840                         c->color_mode,
841                         c->ilace,
842                         c->rotation_type,
843                         c->rotation,
844                         c->mirror,
845                         c->global_alpha);
846
847         if (r) {
848                 /* this shouldn't happen */
849                 DSSERR("dispc_setup_plane failed for ovl %d\n", plane);
850                 dispc_enable_plane(plane, 0);
851                 return r;
852         }
853
854         dispc_enable_replication(plane, c->replication);
855
856         dispc_set_burst_size(plane, c->burst_size);
857         dispc_setup_plane_fifo(plane, c->fifo_low, c->fifo_high);
858
859         dispc_enable_plane(plane, 1);
860
861         return 0;
862 }
863
864 static void configure_manager(enum omap_channel channel)
865 {
866         struct manager_cache_data *c;
867
868         DSSDBGF("%d", channel);
869
870         c = &dss_cache.manager_cache[channel];
871
872         dispc_set_default_color(channel, c->default_color);
873         dispc_set_trans_key(channel, c->trans_key_type, c->trans_key);
874         dispc_enable_trans_key(channel, c->trans_enabled);
875         dispc_enable_alpha_blending(channel, c->alpha_enabled);
876 }
877
878 /* configure_dispc() tries to write values from cache to shadow registers.
879  * It writes only to those managers/overlays that are not busy.
880  * returns 0 if everything could be written to shadow registers.
881  * returns 1 if not everything could be written to shadow registers. */
882 static int configure_dispc(void)
883 {
884         struct overlay_cache_data *oc;
885         struct manager_cache_data *mc;
886         const int num_ovls = dss_feat_get_num_ovls();
887         const int num_mgrs = dss_feat_get_num_mgrs();
888         int i;
889         int r;
890         bool mgr_busy[MAX_DSS_MANAGERS];
891         bool mgr_go[MAX_DSS_MANAGERS];
892         bool busy;
893
894         r = 0;
895         busy = false;
896
897         mgr_busy[0] = dispc_go_busy(0);
898         mgr_busy[1] = dispc_go_busy(1);
899         mgr_go[0] = false;
900         mgr_go[1] = false;
901
902         /* Commit overlay settings */
903         for (i = 0; i < num_ovls; ++i) {
904                 oc = &dss_cache.overlay_cache[i];
905                 mc = &dss_cache.manager_cache[oc->channel];
906
907                 if (!oc->dirty)
908                         continue;
909
910                 if (oc->manual_update && !mc->do_manual_update)
911                         continue;
912
913                 if (mgr_busy[oc->channel]) {
914                         busy = true;
915                         continue;
916                 }
917
918                 r = configure_overlay(i);
919                 if (r)
920                         DSSERR("configure_overlay %d failed\n", i);
921
922                 oc->dirty = false;
923                 oc->shadow_dirty = true;
924                 mgr_go[oc->channel] = true;
925         }
926
927         /* Commit manager settings */
928         for (i = 0; i < num_mgrs; ++i) {
929                 mc = &dss_cache.manager_cache[i];
930
931                 if (!mc->dirty)
932                         continue;
933
934                 if (mc->manual_update && !mc->do_manual_update)
935                         continue;
936
937                 if (mgr_busy[i]) {
938                         busy = true;
939                         continue;
940                 }
941
942                 configure_manager(i);
943                 mc->dirty = false;
944                 mc->shadow_dirty = true;
945                 mgr_go[i] = true;
946         }
947
948         /* set GO */
949         for (i = 0; i < num_mgrs; ++i) {
950                 mc = &dss_cache.manager_cache[i];
951
952                 if (!mgr_go[i])
953                         continue;
954
955                 /* We don't need GO with manual update display. LCD iface will
956                  * always be turned off after frame, and new settings will be
957                  * taken in to use at next update */
958                 if (!mc->manual_upd_display)
959                         dispc_go(i);
960         }
961
962         if (busy)
963                 r = 1;
964         else
965                 r = 0;
966
967         return r;
968 }
969
970 /* Make the coordinates even. There are some strange problems with OMAP and
971  * partial DSI update when the update widths are odd. */
972 static void make_even(u16 *x, u16 *w)
973 {
974         u16 x1, x2;
975
976         x1 = *x;
977         x2 = *x + *w;
978
979         x1 &= ~1;
980         x2 = ALIGN(x2, 2);
981
982         *x = x1;
983         *w = x2 - x1;
984 }
985
986 /* Configure dispc for partial update. Return possibly modified update
987  * area */
988 void dss_setup_partial_planes(struct omap_dss_device *dssdev,
989                 u16 *xi, u16 *yi, u16 *wi, u16 *hi, bool enlarge_update_area)
990 {
991         struct overlay_cache_data *oc;
992         struct manager_cache_data *mc;
993         const int num_ovls = dss_feat_get_num_ovls();
994         struct omap_overlay_manager *mgr;
995         int i;
996         u16 x, y, w, h;
997         unsigned long flags;
998         bool area_changed;
999
1000         x = *xi;
1001         y = *yi;
1002         w = *wi;
1003         h = *hi;
1004
1005         DSSDBG("dispc_setup_partial_planes %d,%d %dx%d\n",
1006                 *xi, *yi, *wi, *hi);
1007
1008         mgr = dssdev->manager;
1009
1010         if (!mgr) {
1011                 DSSDBG("no manager\n");
1012                 return;
1013         }
1014
1015         make_even(&x, &w);
1016
1017         spin_lock_irqsave(&dss_cache.lock, flags);
1018
1019         /*
1020          * Execute the outer loop until the inner loop has completed
1021          * once without increasing the update area. This will ensure that
1022          * all scaled overlays end up completely within the update area.
1023          */
1024         do {
1025                 area_changed = false;
1026
1027                 /* We need to show the whole overlay if it is scaled. So look
1028                  * for those, and make the update area larger if found.
1029                  * Also mark the overlay cache dirty */
1030                 for (i = 0; i < num_ovls; ++i) {
1031                         unsigned x1, y1, x2, y2;
1032                         unsigned outw, outh;
1033
1034                         oc = &dss_cache.overlay_cache[i];
1035
1036                         if (oc->channel != mgr->id)
1037                                 continue;
1038
1039                         oc->dirty = true;
1040
1041                         if (!enlarge_update_area)
1042                                 continue;
1043
1044                         if (!oc->enabled)
1045                                 continue;
1046
1047                         if (!dispc_is_overlay_scaled(oc))
1048                                 continue;
1049
1050                         outw = oc->out_width == 0 ?
1051                                 oc->width : oc->out_width;
1052                         outh = oc->out_height == 0 ?
1053                                 oc->height : oc->out_height;
1054
1055                         /* is the overlay outside the update region? */
1056                         if (!rectangle_intersects(x, y, w, h,
1057                                                 oc->pos_x, oc->pos_y,
1058                                                 outw, outh))
1059                                 continue;
1060
1061                         /* if the overlay totally inside the update region? */
1062                         if (rectangle_subset(oc->pos_x, oc->pos_y, outw, outh,
1063                                                 x, y, w, h))
1064                                 continue;
1065
1066                         if (x > oc->pos_x)
1067                                 x1 = oc->pos_x;
1068                         else
1069                                 x1 = x;
1070
1071                         if (y > oc->pos_y)
1072                                 y1 = oc->pos_y;
1073                         else
1074                                 y1 = y;
1075
1076                         if ((x + w) < (oc->pos_x + outw))
1077                                 x2 = oc->pos_x + outw;
1078                         else
1079                                 x2 = x + w;
1080
1081                         if ((y + h) < (oc->pos_y + outh))
1082                                 y2 = oc->pos_y + outh;
1083                         else
1084                                 y2 = y + h;
1085
1086                         x = x1;
1087                         y = y1;
1088                         w = x2 - x1;
1089                         h = y2 - y1;
1090
1091                         make_even(&x, &w);
1092
1093                         DSSDBG("changing upd area due to ovl(%d) "
1094                                "scaling %d,%d %dx%d\n",
1095                                 i, x, y, w, h);
1096
1097                         area_changed = true;
1098                 }
1099         } while (area_changed);
1100
1101         mc = &dss_cache.manager_cache[mgr->id];
1102         mc->do_manual_update = true;
1103         mc->enlarge_update_area = enlarge_update_area;
1104         mc->x = x;
1105         mc->y = y;
1106         mc->w = w;
1107         mc->h = h;
1108
1109         configure_dispc();
1110
1111         mc->do_manual_update = false;
1112
1113         spin_unlock_irqrestore(&dss_cache.lock, flags);
1114
1115         *xi = x;
1116         *yi = y;
1117         *wi = w;
1118         *hi = h;
1119 }
1120
1121 void dss_start_update(struct omap_dss_device *dssdev)
1122 {
1123         struct manager_cache_data *mc;
1124         struct overlay_cache_data *oc;
1125         const int num_ovls = dss_feat_get_num_ovls();
1126         const int num_mgrs = dss_feat_get_num_mgrs();
1127         struct omap_overlay_manager *mgr;
1128         int i;
1129
1130         mgr = dssdev->manager;
1131
1132         for (i = 0; i < num_ovls; ++i) {
1133                 oc = &dss_cache.overlay_cache[i];
1134                 if (oc->channel != mgr->id)
1135                         continue;
1136
1137                 oc->shadow_dirty = false;
1138         }
1139
1140         for (i = 0; i < num_mgrs; ++i) {
1141                 mc = &dss_cache.manager_cache[i];
1142                 if (mgr->id != i)
1143                         continue;
1144
1145                 mc->shadow_dirty = false;
1146         }
1147
1148         dssdev->manager->enable(dssdev->manager);
1149 }
1150
1151 static void dss_apply_irq_handler(void *data, u32 mask)
1152 {
1153         struct manager_cache_data *mc;
1154         struct overlay_cache_data *oc;
1155         const int num_ovls = dss_feat_get_num_ovls();
1156         const int num_mgrs = dss_feat_get_num_mgrs();
1157         int i, r;
1158         bool mgr_busy[MAX_DSS_MANAGERS];
1159
1160         mgr_busy[0] = dispc_go_busy(0);
1161         mgr_busy[1] = dispc_go_busy(1);
1162
1163         spin_lock(&dss_cache.lock);
1164
1165         for (i = 0; i < num_ovls; ++i) {
1166                 oc = &dss_cache.overlay_cache[i];
1167                 if (!mgr_busy[oc->channel])
1168                         oc->shadow_dirty = false;
1169         }
1170
1171         for (i = 0; i < num_mgrs; ++i) {
1172                 mc = &dss_cache.manager_cache[i];
1173                 if (!mgr_busy[i])
1174                         mc->shadow_dirty = false;
1175         }
1176
1177         r = configure_dispc();
1178         if (r == 1)
1179                 goto end;
1180
1181         /* re-read busy flags */
1182         mgr_busy[0] = dispc_go_busy(0);
1183         mgr_busy[1] = dispc_go_busy(1);
1184
1185         /* keep running as long as there are busy managers, so that
1186          * we can collect overlay-applied information */
1187         for (i = 0; i < num_mgrs; ++i) {
1188                 if (mgr_busy[i])
1189                         goto end;
1190         }
1191
1192         omap_dispc_unregister_isr(dss_apply_irq_handler, NULL,
1193                         DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_ODD |
1194                         DISPC_IRQ_EVSYNC_EVEN);
1195         dss_cache.irq_enabled = false;
1196
1197 end:
1198         spin_unlock(&dss_cache.lock);
1199 }
1200
1201 static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
1202 {
1203         struct overlay_cache_data *oc;
1204         struct manager_cache_data *mc;
1205         int i;
1206         struct omap_overlay *ovl;
1207         int num_planes_enabled = 0;
1208         bool use_fifomerge;
1209         unsigned long flags;
1210         int r;
1211
1212         DSSDBG("omap_dss_mgr_apply(%s)\n", mgr->name);
1213
1214         spin_lock_irqsave(&dss_cache.lock, flags);
1215
1216         /* Configure overlays */
1217         for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
1218                 struct omap_dss_device *dssdev;
1219
1220                 ovl = omap_dss_get_overlay(i);
1221
1222                 if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC))
1223                         continue;
1224
1225                 oc = &dss_cache.overlay_cache[ovl->id];
1226
1227                 if (!overlay_enabled(ovl)) {
1228                         if (oc->enabled) {
1229                                 oc->enabled = false;
1230                                 oc->dirty = true;
1231                         }
1232                         continue;
1233                 }
1234
1235                 if (!ovl->info_dirty) {
1236                         if (oc->enabled)
1237                                 ++num_planes_enabled;
1238                         continue;
1239                 }
1240
1241                 dssdev = ovl->manager->device;
1242
1243                 if (dss_check_overlay(ovl, dssdev)) {
1244                         if (oc->enabled) {
1245                                 oc->enabled = false;
1246                                 oc->dirty = true;
1247                         }
1248                         continue;
1249                 }
1250
1251                 ovl->info_dirty = false;
1252                 oc->dirty = true;
1253
1254                 oc->paddr = ovl->info.paddr;
1255                 oc->vaddr = ovl->info.vaddr;
1256                 oc->screen_width = ovl->info.screen_width;
1257                 oc->width = ovl->info.width;
1258                 oc->height = ovl->info.height;
1259                 oc->color_mode = ovl->info.color_mode;
1260                 oc->rotation = ovl->info.rotation;
1261                 oc->rotation_type = ovl->info.rotation_type;
1262                 oc->mirror = ovl->info.mirror;
1263                 oc->pos_x = ovl->info.pos_x;
1264                 oc->pos_y = ovl->info.pos_y;
1265                 oc->out_width = ovl->info.out_width;
1266                 oc->out_height = ovl->info.out_height;
1267                 oc->global_alpha = ovl->info.global_alpha;
1268
1269                 oc->replication =
1270                         dss_use_replication(dssdev, ovl->info.color_mode);
1271
1272                 oc->ilace = dssdev->type == OMAP_DISPLAY_TYPE_VENC;
1273
1274                 oc->channel = ovl->manager->id;
1275
1276                 oc->enabled = true;
1277
1278                 oc->manual_update =
1279                         dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE &&
1280                         dssdev->driver->get_update_mode(dssdev) !=
1281                                 OMAP_DSS_UPDATE_AUTO;
1282
1283                 ++num_planes_enabled;
1284         }
1285
1286         /* Configure managers */
1287         list_for_each_entry(mgr, &manager_list, list) {
1288                 struct omap_dss_device *dssdev;
1289
1290                 if (!(mgr->caps & OMAP_DSS_OVL_MGR_CAP_DISPC))
1291                         continue;
1292
1293                 mc = &dss_cache.manager_cache[mgr->id];
1294
1295                 if (mgr->device_changed) {
1296                         mgr->device_changed = false;
1297                         mgr->info_dirty  = true;
1298                 }
1299
1300                 if (!mgr->info_dirty)
1301                         continue;
1302
1303                 if (!mgr->device)
1304                         continue;
1305
1306                 dssdev = mgr->device;
1307
1308                 mgr->info_dirty = false;
1309                 mc->dirty = true;
1310
1311                 mc->default_color = mgr->info.default_color;
1312                 mc->trans_key_type = mgr->info.trans_key_type;
1313                 mc->trans_key = mgr->info.trans_key;
1314                 mc->trans_enabled = mgr->info.trans_enabled;
1315                 mc->alpha_enabled = mgr->info.alpha_enabled;
1316
1317                 mc->manual_upd_display =
1318                         dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE;
1319
1320                 mc->manual_update =
1321                         dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE &&
1322                         dssdev->driver->get_update_mode(dssdev) !=
1323                                 OMAP_DSS_UPDATE_AUTO;
1324         }
1325
1326         /* XXX TODO: Try to get fifomerge working. The problem is that it
1327          * affects both managers, not individually but at the same time. This
1328          * means the change has to be well synchronized. I guess the proper way
1329          * is to have a two step process for fifo merge:
1330          *        fifomerge enable:
1331          *             1. disable other planes, leaving one plane enabled
1332          *             2. wait until the planes are disabled on HW
1333          *             3. config merged fifo thresholds, enable fifomerge
1334          *        fifomerge disable:
1335          *             1. config unmerged fifo thresholds, disable fifomerge
1336          *             2. wait until fifo changes are in HW
1337          *             3. enable planes
1338          */
1339         use_fifomerge = false;
1340
1341         /* Configure overlay fifos */
1342         for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
1343                 struct omap_dss_device *dssdev;
1344                 u32 size;
1345
1346                 ovl = omap_dss_get_overlay(i);
1347
1348                 if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC))
1349                         continue;
1350
1351                 oc = &dss_cache.overlay_cache[ovl->id];
1352
1353                 if (!oc->enabled)
1354                         continue;
1355
1356                 dssdev = ovl->manager->device;
1357
1358                 size = dispc_get_plane_fifo_size(ovl->id);
1359                 if (use_fifomerge)
1360                         size *= 3;
1361
1362                 switch (dssdev->type) {
1363                 case OMAP_DISPLAY_TYPE_DPI:
1364                 case OMAP_DISPLAY_TYPE_DBI:
1365                 case OMAP_DISPLAY_TYPE_SDI:
1366                 case OMAP_DISPLAY_TYPE_VENC:
1367                         default_get_overlay_fifo_thresholds(ovl->id, size,
1368                                         &oc->burst_size, &oc->fifo_low,
1369                                         &oc->fifo_high);
1370                         break;
1371 #ifdef CONFIG_OMAP2_DSS_DSI
1372                 case OMAP_DISPLAY_TYPE_DSI:
1373                         dsi_get_overlay_fifo_thresholds(ovl->id, size,
1374                                         &oc->burst_size, &oc->fifo_low,
1375                                         &oc->fifo_high);
1376                         break;
1377 #endif
1378                 default:
1379                         BUG();
1380                 }
1381         }
1382
1383         r = 0;
1384         dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
1385         if (!dss_cache.irq_enabled) {
1386                 r = omap_dispc_register_isr(dss_apply_irq_handler, NULL,
1387                                 DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_ODD |
1388                                 DISPC_IRQ_EVSYNC_EVEN);
1389                 dss_cache.irq_enabled = true;
1390         }
1391         configure_dispc();
1392         dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
1393
1394         spin_unlock_irqrestore(&dss_cache.lock, flags);
1395
1396         return r;
1397 }
1398
1399 static int dss_check_manager(struct omap_overlay_manager *mgr)
1400 {
1401         /* OMAP supports only graphics source transparency color key and alpha
1402          * blending simultaneously. See TRM 15.4.2.4.2.2 Alpha Mode */
1403
1404         if (mgr->info.alpha_enabled && mgr->info.trans_enabled &&
1405                         mgr->info.trans_key_type != OMAP_DSS_COLOR_KEY_GFX_DST)
1406                 return -EINVAL;
1407
1408         return 0;
1409 }
1410
1411 static int omap_dss_mgr_set_info(struct omap_overlay_manager *mgr,
1412                 struct omap_overlay_manager_info *info)
1413 {
1414         int r;
1415         struct omap_overlay_manager_info old_info;
1416
1417         old_info = mgr->info;
1418         mgr->info = *info;
1419
1420         r = dss_check_manager(mgr);
1421         if (r) {
1422                 mgr->info = old_info;
1423                 return r;
1424         }
1425
1426         mgr->info_dirty = true;
1427
1428         return 0;
1429 }
1430
1431 static void omap_dss_mgr_get_info(struct omap_overlay_manager *mgr,
1432                 struct omap_overlay_manager_info *info)
1433 {
1434         *info = mgr->info;
1435 }
1436
1437 static int dss_mgr_enable(struct omap_overlay_manager *mgr)
1438 {
1439         dispc_enable_channel(mgr->id, 1);
1440         return 0;
1441 }
1442
1443 static int dss_mgr_disable(struct omap_overlay_manager *mgr)
1444 {
1445         dispc_enable_channel(mgr->id, 0);
1446         return 0;
1447 }
1448
1449 static void omap_dss_add_overlay_manager(struct omap_overlay_manager *manager)
1450 {
1451         ++num_managers;
1452         list_add_tail(&manager->list, &manager_list);
1453 }
1454
1455 int dss_init_overlay_managers(struct platform_device *pdev)
1456 {
1457         int i, r;
1458
1459         spin_lock_init(&dss_cache.lock);
1460
1461         INIT_LIST_HEAD(&manager_list);
1462
1463         num_managers = 0;
1464
1465         for (i = 0; i < dss_feat_get_num_mgrs(); ++i) {
1466                 struct omap_overlay_manager *mgr;
1467                 mgr = kzalloc(sizeof(*mgr), GFP_KERNEL);
1468
1469                 BUG_ON(mgr == NULL);
1470
1471                 switch (i) {
1472                 case 0:
1473                         mgr->name = "lcd";
1474                         mgr->id = OMAP_DSS_CHANNEL_LCD;
1475                         break;
1476                 case 1:
1477                         mgr->name = "tv";
1478                         mgr->id = OMAP_DSS_CHANNEL_DIGIT;
1479                         break;
1480                 }
1481
1482                 mgr->set_device = &omap_dss_set_device;
1483                 mgr->unset_device = &omap_dss_unset_device;
1484                 mgr->apply = &omap_dss_mgr_apply;
1485                 mgr->set_manager_info = &omap_dss_mgr_set_info;
1486                 mgr->get_manager_info = &omap_dss_mgr_get_info;
1487                 mgr->wait_for_go = &dss_mgr_wait_for_go;
1488                 mgr->wait_for_vsync = &dss_mgr_wait_for_vsync;
1489
1490                 mgr->enable = &dss_mgr_enable;
1491                 mgr->disable = &dss_mgr_disable;
1492
1493                 mgr->caps = OMAP_DSS_OVL_MGR_CAP_DISPC;
1494                 mgr->supported_displays =
1495                         dss_feat_get_supported_displays(mgr->id);
1496
1497                 dss_overlay_setup_dispc_manager(mgr);
1498
1499                 omap_dss_add_overlay_manager(mgr);
1500
1501                 r = kobject_init_and_add(&mgr->kobj, &manager_ktype,
1502                                 &pdev->dev.kobj, "manager%d", i);
1503
1504                 if (r) {
1505                         DSSERR("failed to create sysfs file\n");
1506                         continue;
1507                 }
1508         }
1509
1510 #ifdef L4_EXAMPLE
1511         {
1512                 int omap_dss_mgr_apply_l4(struct omap_overlay_manager *mgr)
1513                 {
1514                         DSSDBG("omap_dss_mgr_apply_l4(%s)\n", mgr->name);
1515
1516                         return 0;
1517                 }
1518
1519                 struct omap_overlay_manager *mgr;
1520                 mgr = kzalloc(sizeof(*mgr), GFP_KERNEL);
1521
1522                 BUG_ON(mgr == NULL);
1523
1524                 mgr->name = "l4";
1525                 mgr->supported_displays =
1526                         OMAP_DISPLAY_TYPE_DBI | OMAP_DISPLAY_TYPE_DSI;
1527
1528                 mgr->set_device = &omap_dss_set_device;
1529                 mgr->unset_device = &omap_dss_unset_device;
1530                 mgr->apply = &omap_dss_mgr_apply_l4;
1531                 mgr->set_manager_info = &omap_dss_mgr_set_info;
1532                 mgr->get_manager_info = &omap_dss_mgr_get_info;
1533
1534                 dss_overlay_setup_l4_manager(mgr);
1535
1536                 omap_dss_add_overlay_manager(mgr);
1537
1538                 r = kobject_init_and_add(&mgr->kobj, &manager_ktype,
1539                                 &pdev->dev.kobj, "managerl4");
1540
1541                 if (r)
1542                         DSSERR("failed to create sysfs file\n");
1543         }
1544 #endif
1545
1546         return 0;
1547 }
1548
1549 void dss_uninit_overlay_managers(struct platform_device *pdev)
1550 {
1551         struct omap_overlay_manager *mgr;
1552
1553         while (!list_empty(&manager_list)) {
1554                 mgr = list_first_entry(&manager_list,
1555                                 struct omap_overlay_manager, list);
1556                 list_del(&mgr->list);
1557                 kobject_del(&mgr->kobj);
1558                 kobject_put(&mgr->kobj);
1559                 kfree(mgr);
1560         }
1561
1562         num_managers = 0;
1563 }
1564
1565 int omap_dss_get_num_overlay_managers(void)
1566 {
1567         return num_managers;
1568 }
1569 EXPORT_SYMBOL(omap_dss_get_num_overlay_managers);
1570
1571 struct omap_overlay_manager *omap_dss_get_overlay_manager(int num)
1572 {
1573         int i = 0;
1574         struct omap_overlay_manager *mgr;
1575
1576         list_for_each_entry(mgr, &manager_list, list) {
1577                 if (i++ == num)
1578                         return mgr;
1579         }
1580
1581         return NULL;
1582 }
1583 EXPORT_SYMBOL(omap_dss_get_overlay_manager);
1584