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