]> git.karo-electronics.de Git - mv-sheeva.git/blob - drivers/video/omap2/dss/manager.c
OMAP: DSS2: remove update_mode from omapdss
[mv-sheeva.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 <video/omapdss.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         u32 p_uv_addr; /* relevant for NV12 format only */
397         u16 screen_width;
398         u16 width;
399         u16 height;
400         enum omap_color_mode color_mode;
401         u8 rotation;
402         enum omap_dss_rotation_type rotation_type;
403         bool mirror;
404
405         u16 pos_x;
406         u16 pos_y;
407         u16 out_width;  /* if 0, out_width == width */
408         u16 out_height; /* if 0, out_height == height */
409         u8 global_alpha;
410         u8 pre_mult_alpha;
411
412         enum omap_channel channel;
413         bool replication;
414         bool ilace;
415
416         enum omap_burst_size burst_size;
417         u32 fifo_low;
418         u32 fifo_high;
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_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[MAX_DSS_OVERLAYS];
452         struct manager_cache_data manager_cache[MAX_DSS_MANAGERS];
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 if (mgr->device->type == OMAP_DISPLAY_TYPE_HDMI) {
517                 irq = DISPC_IRQ_EVSYNC_EVEN;
518         } else {
519                 if (mgr->id == OMAP_DSS_CHANNEL_LCD)
520                         irq = DISPC_IRQ_VSYNC;
521                 else
522                         irq = DISPC_IRQ_VSYNC2;
523         }
524         return omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
525 }
526
527 static int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr)
528 {
529         unsigned long timeout = msecs_to_jiffies(500);
530         struct manager_cache_data *mc;
531         u32 irq;
532         int r;
533         int i;
534         struct omap_dss_device *dssdev = mgr->device;
535
536         if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
537                 return 0;
538
539         if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE)
540                 return 0;
541
542         if (dssdev->type == OMAP_DISPLAY_TYPE_VENC
543                         || dssdev->type == OMAP_DISPLAY_TYPE_HDMI) {
544                 irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN;
545         } else {
546                 irq = (dssdev->manager->id == OMAP_DSS_CHANNEL_LCD) ?
547                         DISPC_IRQ_VSYNC : DISPC_IRQ_VSYNC2;
548         }
549
550         mc = &dss_cache.manager_cache[mgr->id];
551         i = 0;
552         while (1) {
553                 unsigned long flags;
554                 bool shadow_dirty, dirty;
555
556                 spin_lock_irqsave(&dss_cache.lock, flags);
557                 dirty = mc->dirty;
558                 shadow_dirty = mc->shadow_dirty;
559                 spin_unlock_irqrestore(&dss_cache.lock, flags);
560
561                 if (!dirty && !shadow_dirty) {
562                         r = 0;
563                         break;
564                 }
565
566                 /* 4 iterations is the worst case:
567                  * 1 - initial iteration, dirty = true (between VFP and VSYNC)
568                  * 2 - first VSYNC, dirty = true
569                  * 3 - dirty = false, shadow_dirty = true
570                  * 4 - shadow_dirty = false */
571                 if (i++ == 3) {
572                         DSSERR("mgr(%d)->wait_for_go() not finishing\n",
573                                         mgr->id);
574                         r = 0;
575                         break;
576                 }
577
578                 r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
579                 if (r == -ERESTARTSYS)
580                         break;
581
582                 if (r) {
583                         DSSERR("mgr(%d)->wait_for_go() timeout\n", mgr->id);
584                         break;
585                 }
586         }
587
588         return r;
589 }
590
591 int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl)
592 {
593         unsigned long timeout = msecs_to_jiffies(500);
594         struct overlay_cache_data *oc;
595         struct omap_dss_device *dssdev;
596         u32 irq;
597         int r;
598         int i;
599
600         if (!ovl->manager)
601                 return 0;
602
603         dssdev = ovl->manager->device;
604
605         if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
606                 return 0;
607
608         if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE)
609                 return 0;
610
611         if (dssdev->type == OMAP_DISPLAY_TYPE_VENC
612                         || dssdev->type == OMAP_DISPLAY_TYPE_HDMI) {
613                 irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN;
614         } else {
615                 irq = (dssdev->manager->id == OMAP_DSS_CHANNEL_LCD) ?
616                         DISPC_IRQ_VSYNC : DISPC_IRQ_VSYNC2;
617         }
618
619         oc = &dss_cache.overlay_cache[ovl->id];
620         i = 0;
621         while (1) {
622                 unsigned long flags;
623                 bool shadow_dirty, dirty;
624
625                 spin_lock_irqsave(&dss_cache.lock, flags);
626                 dirty = oc->dirty;
627                 shadow_dirty = oc->shadow_dirty;
628                 spin_unlock_irqrestore(&dss_cache.lock, flags);
629
630                 if (!dirty && !shadow_dirty) {
631                         r = 0;
632                         break;
633                 }
634
635                 /* 4 iterations is the worst case:
636                  * 1 - initial iteration, dirty = true (between VFP and VSYNC)
637                  * 2 - first VSYNC, dirty = true
638                  * 3 - dirty = false, shadow_dirty = true
639                  * 4 - shadow_dirty = false */
640                 if (i++ == 3) {
641                         DSSERR("ovl(%d)->wait_for_go() not finishing\n",
642                                         ovl->id);
643                         r = 0;
644                         break;
645                 }
646
647                 r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
648                 if (r == -ERESTARTSYS)
649                         break;
650
651                 if (r) {
652                         DSSERR("ovl(%d)->wait_for_go() timeout\n", ovl->id);
653                         break;
654                 }
655         }
656
657         return r;
658 }
659
660 static int overlay_enabled(struct omap_overlay *ovl)
661 {
662         return ovl->info.enabled && ovl->manager && ovl->manager->device;
663 }
664
665 /* Is rect1 a subset of rect2? */
666 static bool rectangle_subset(int x1, int y1, int w1, int h1,
667                 int x2, int y2, int w2, int h2)
668 {
669         if (x1 < x2 || y1 < y2)
670                 return false;
671
672         if (x1 + w1 > x2 + w2)
673                 return false;
674
675         if (y1 + h1 > y2 + h2)
676                 return false;
677
678         return true;
679 }
680
681 /* Do rect1 and rect2 overlap? */
682 static bool rectangle_intersects(int x1, int y1, int w1, int h1,
683                 int x2, int y2, int w2, int h2)
684 {
685         if (x1 >= x2 + w2)
686                 return false;
687
688         if (x2 >= x1 + w1)
689                 return false;
690
691         if (y1 >= y2 + h2)
692                 return false;
693
694         if (y2 >= y1 + h1)
695                 return false;
696
697         return true;
698 }
699
700 static bool dispc_is_overlay_scaled(struct overlay_cache_data *oc)
701 {
702         if (oc->out_width != 0 && oc->width != oc->out_width)
703                 return true;
704
705         if (oc->out_height != 0 && oc->height != oc->out_height)
706                 return true;
707
708         return false;
709 }
710
711 static int configure_overlay(enum omap_plane plane)
712 {
713         struct overlay_cache_data *c;
714         struct manager_cache_data *mc;
715         u16 outw, outh;
716         u16 x, y, w, h;
717         u32 paddr;
718         int r;
719         u16 orig_w, orig_h, orig_outw, orig_outh;
720
721         DSSDBGF("%d", plane);
722
723         c = &dss_cache.overlay_cache[plane];
724
725         if (!c->enabled) {
726                 dispc_enable_plane(plane, 0);
727                 return 0;
728         }
729
730         mc = &dss_cache.manager_cache[c->channel];
731
732         x = c->pos_x;
733         y = c->pos_y;
734         w = c->width;
735         h = c->height;
736         outw = c->out_width == 0 ? c->width : c->out_width;
737         outh = c->out_height == 0 ? c->height : c->out_height;
738         paddr = c->paddr;
739
740         orig_w = w;
741         orig_h = h;
742         orig_outw = outw;
743         orig_outh = outh;
744
745         if (mc->manual_update && mc->do_manual_update) {
746                 unsigned bpp;
747                 unsigned scale_x_m = w, scale_x_d = outw;
748                 unsigned scale_y_m = h, scale_y_d = outh;
749
750                 /* If the overlay is outside the update region, disable it */
751                 if (!rectangle_intersects(mc->x, mc->y, mc->w, mc->h,
752                                         x, y, outw, outh)) {
753                         dispc_enable_plane(plane, 0);
754                         return 0;
755                 }
756
757                 switch (c->color_mode) {
758                 case OMAP_DSS_COLOR_NV12:
759                         bpp = 8;
760                         break;
761                 case OMAP_DSS_COLOR_RGB16:
762                 case OMAP_DSS_COLOR_ARGB16:
763                 case OMAP_DSS_COLOR_YUV2:
764                 case OMAP_DSS_COLOR_UYVY:
765                 case OMAP_DSS_COLOR_RGBA16:
766                 case OMAP_DSS_COLOR_RGBX16:
767                 case OMAP_DSS_COLOR_ARGB16_1555:
768                 case OMAP_DSS_COLOR_XRGB16_1555:
769                         bpp = 16;
770                         break;
771
772                 case OMAP_DSS_COLOR_RGB24P:
773                         bpp = 24;
774                         break;
775
776                 case OMAP_DSS_COLOR_RGB24U:
777                 case OMAP_DSS_COLOR_ARGB32:
778                 case OMAP_DSS_COLOR_RGBA32:
779                 case OMAP_DSS_COLOR_RGBX32:
780                         bpp = 32;
781                         break;
782
783                 default:
784                         BUG();
785                 }
786
787                 if (mc->x > c->pos_x) {
788                         x = 0;
789                         outw -= (mc->x - c->pos_x);
790                         paddr += (mc->x - c->pos_x) *
791                                 scale_x_m / scale_x_d * bpp / 8;
792                 } else {
793                         x = c->pos_x - mc->x;
794                 }
795
796                 if (mc->y > c->pos_y) {
797                         y = 0;
798                         outh -= (mc->y - c->pos_y);
799                         paddr += (mc->y - c->pos_y) *
800                                 scale_y_m / scale_y_d *
801                                 c->screen_width * bpp / 8;
802                 } else {
803                         y = c->pos_y - mc->y;
804                 }
805
806                 if (mc->w < (x + outw))
807                         outw -= (x + outw) - (mc->w);
808
809                 if (mc->h < (y + outh))
810                         outh -= (y + outh) - (mc->h);
811
812                 w = w * outw / orig_outw;
813                 h = h * outh / orig_outh;
814
815                 /* YUV mode overlay's input width has to be even and the
816                  * algorithm above may adjust the width to be odd.
817                  *
818                  * Here we adjust the width if needed, preferring to increase
819                  * the width if the original width was bigger.
820                  */
821                 if ((w & 1) &&
822                                 (c->color_mode == OMAP_DSS_COLOR_YUV2 ||
823                                  c->color_mode == OMAP_DSS_COLOR_UYVY)) {
824                         if (orig_w > w)
825                                 w += 1;
826                         else
827                                 w -= 1;
828                 }
829         }
830
831         r = dispc_setup_plane(plane,
832                         paddr,
833                         c->screen_width,
834                         x, y,
835                         w, h,
836                         outw, outh,
837                         c->color_mode,
838                         c->ilace,
839                         c->rotation_type,
840                         c->rotation,
841                         c->mirror,
842                         c->global_alpha,
843                         c->pre_mult_alpha,
844                         c->channel,
845                         c->p_uv_addr);
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         for (i = 0; i < num_mgrs; i++) {
898                 mgr_busy[i] = dispc_go_busy(i);
899                 mgr_go[i] = false;
900         }
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 (mc->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_update)
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         u32 irq_mask;
1160
1161         for (i = 0; i < num_mgrs; i++)
1162                 mgr_busy[i] = dispc_go_busy(i);
1163
1164         spin_lock(&dss_cache.lock);
1165
1166         for (i = 0; i < num_ovls; ++i) {
1167                 oc = &dss_cache.overlay_cache[i];
1168                 if (!mgr_busy[oc->channel])
1169                         oc->shadow_dirty = false;
1170         }
1171
1172         for (i = 0; i < num_mgrs; ++i) {
1173                 mc = &dss_cache.manager_cache[i];
1174                 if (!mgr_busy[i])
1175                         mc->shadow_dirty = false;
1176         }
1177
1178         r = configure_dispc();
1179         if (r == 1)
1180                 goto end;
1181
1182         /* re-read busy flags */
1183         for (i = 0; i < num_mgrs; i++)
1184                 mgr_busy[i] = dispc_go_busy(i);
1185
1186         /* keep running as long as there are busy managers, so that
1187          * we can collect overlay-applied information */
1188         for (i = 0; i < num_mgrs; ++i) {
1189                 if (mgr_busy[i])
1190                         goto end;
1191         }
1192
1193         irq_mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_ODD |
1194                         DISPC_IRQ_EVSYNC_EVEN;
1195         if (dss_has_feature(FEAT_MGR_LCD2))
1196                 irq_mask |= DISPC_IRQ_VSYNC2;
1197
1198         omap_dispc_unregister_isr(dss_apply_irq_handler, NULL, irq_mask);
1199         dss_cache.irq_enabled = false;
1200
1201 end:
1202         spin_unlock(&dss_cache.lock);
1203 }
1204
1205 static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
1206 {
1207         struct overlay_cache_data *oc;
1208         struct manager_cache_data *mc;
1209         int i;
1210         struct omap_overlay *ovl;
1211         int num_planes_enabled = 0;
1212         bool use_fifomerge;
1213         unsigned long flags;
1214         int r;
1215
1216         DSSDBG("omap_dss_mgr_apply(%s)\n", mgr->name);
1217
1218         spin_lock_irqsave(&dss_cache.lock, flags);
1219
1220         /* Configure overlays */
1221         for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
1222                 struct omap_dss_device *dssdev;
1223
1224                 ovl = omap_dss_get_overlay(i);
1225
1226                 if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC))
1227                         continue;
1228
1229                 oc = &dss_cache.overlay_cache[ovl->id];
1230
1231                 if (!overlay_enabled(ovl)) {
1232                         if (oc->enabled) {
1233                                 oc->enabled = false;
1234                                 oc->dirty = true;
1235                         }
1236                         continue;
1237                 }
1238
1239                 if (!ovl->info_dirty) {
1240                         if (oc->enabled)
1241                                 ++num_planes_enabled;
1242                         continue;
1243                 }
1244
1245                 dssdev = ovl->manager->device;
1246
1247                 if (dss_check_overlay(ovl, dssdev)) {
1248                         if (oc->enabled) {
1249                                 oc->enabled = false;
1250                                 oc->dirty = true;
1251                         }
1252                         continue;
1253                 }
1254
1255                 ovl->info_dirty = false;
1256                 oc->dirty = true;
1257
1258                 oc->paddr = ovl->info.paddr;
1259                 oc->vaddr = ovl->info.vaddr;
1260                 oc->p_uv_addr = ovl->info.p_uv_addr;
1261                 oc->screen_width = ovl->info.screen_width;
1262                 oc->width = ovl->info.width;
1263                 oc->height = ovl->info.height;
1264                 oc->color_mode = ovl->info.color_mode;
1265                 oc->rotation = ovl->info.rotation;
1266                 oc->rotation_type = ovl->info.rotation_type;
1267                 oc->mirror = ovl->info.mirror;
1268                 oc->pos_x = ovl->info.pos_x;
1269                 oc->pos_y = ovl->info.pos_y;
1270                 oc->out_width = ovl->info.out_width;
1271                 oc->out_height = ovl->info.out_height;
1272                 oc->global_alpha = ovl->info.global_alpha;
1273                 oc->pre_mult_alpha = ovl->info.pre_mult_alpha;
1274
1275                 oc->replication =
1276                         dss_use_replication(dssdev, ovl->info.color_mode);
1277
1278                 oc->ilace = dssdev->type == OMAP_DISPLAY_TYPE_VENC;
1279
1280                 oc->channel = ovl->manager->id;
1281
1282                 oc->enabled = true;
1283
1284                 ++num_planes_enabled;
1285         }
1286
1287         /* Configure managers */
1288         list_for_each_entry(mgr, &manager_list, list) {
1289                 struct omap_dss_device *dssdev;
1290
1291                 if (!(mgr->caps & OMAP_DSS_OVL_MGR_CAP_DISPC))
1292                         continue;
1293
1294                 mc = &dss_cache.manager_cache[mgr->id];
1295
1296                 if (mgr->device_changed) {
1297                         mgr->device_changed = false;
1298                         mgr->info_dirty  = true;
1299                 }
1300
1301                 if (!mgr->info_dirty)
1302                         continue;
1303
1304                 if (!mgr->device)
1305                         continue;
1306
1307                 dssdev = mgr->device;
1308
1309                 mgr->info_dirty = false;
1310                 mc->dirty = true;
1311
1312                 mc->default_color = mgr->info.default_color;
1313                 mc->trans_key_type = mgr->info.trans_key_type;
1314                 mc->trans_key = mgr->info.trans_key;
1315                 mc->trans_enabled = mgr->info.trans_enabled;
1316                 mc->alpha_enabled = mgr->info.alpha_enabled;
1317
1318                 mc->manual_update =
1319                         dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE;
1320         }
1321
1322         /* XXX TODO: Try to get fifomerge working. The problem is that it
1323          * affects both managers, not individually but at the same time. This
1324          * means the change has to be well synchronized. I guess the proper way
1325          * is to have a two step process for fifo merge:
1326          *        fifomerge enable:
1327          *             1. disable other planes, leaving one plane enabled
1328          *             2. wait until the planes are disabled on HW
1329          *             3. config merged fifo thresholds, enable fifomerge
1330          *        fifomerge disable:
1331          *             1. config unmerged fifo thresholds, disable fifomerge
1332          *             2. wait until fifo changes are in HW
1333          *             3. enable planes
1334          */
1335         use_fifomerge = false;
1336
1337         /* Configure overlay fifos */
1338         for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
1339                 struct omap_dss_device *dssdev;
1340                 u32 size;
1341
1342                 ovl = omap_dss_get_overlay(i);
1343
1344                 if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC))
1345                         continue;
1346
1347                 oc = &dss_cache.overlay_cache[ovl->id];
1348
1349                 if (!oc->enabled)
1350                         continue;
1351
1352                 dssdev = ovl->manager->device;
1353
1354                 size = dispc_get_plane_fifo_size(ovl->id);
1355                 if (use_fifomerge)
1356                         size *= 3;
1357
1358                 switch (dssdev->type) {
1359                 case OMAP_DISPLAY_TYPE_DPI:
1360                 case OMAP_DISPLAY_TYPE_DBI:
1361                 case OMAP_DISPLAY_TYPE_SDI:
1362                 case OMAP_DISPLAY_TYPE_VENC:
1363                 case OMAP_DISPLAY_TYPE_HDMI:
1364                         default_get_overlay_fifo_thresholds(ovl->id, size,
1365                                         &oc->burst_size, &oc->fifo_low,
1366                                         &oc->fifo_high);
1367                         break;
1368 #ifdef CONFIG_OMAP2_DSS_DSI
1369                 case OMAP_DISPLAY_TYPE_DSI:
1370                         dsi_get_overlay_fifo_thresholds(ovl->id, size,
1371                                         &oc->burst_size, &oc->fifo_low,
1372                                         &oc->fifo_high);
1373                         break;
1374 #endif
1375                 default:
1376                         BUG();
1377                 }
1378         }
1379
1380         r = 0;
1381         dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
1382         if (!dss_cache.irq_enabled) {
1383                 u32 mask;
1384
1385                 mask = DISPC_IRQ_VSYNC  | DISPC_IRQ_EVSYNC_ODD |
1386                         DISPC_IRQ_EVSYNC_EVEN;
1387                 if (dss_has_feature(FEAT_MGR_LCD2))
1388                         mask |= DISPC_IRQ_VSYNC2;
1389
1390                 r = omap_dispc_register_isr(dss_apply_irq_handler, NULL, mask);
1391                 dss_cache.irq_enabled = true;
1392         }
1393         configure_dispc();
1394         dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
1395
1396         spin_unlock_irqrestore(&dss_cache.lock, flags);
1397
1398         return r;
1399 }
1400
1401 static int dss_check_manager(struct omap_overlay_manager *mgr)
1402 {
1403         /* OMAP supports only graphics source transparency color key and alpha
1404          * blending simultaneously. See TRM 15.4.2.4.2.2 Alpha Mode */
1405
1406         if (mgr->info.alpha_enabled && mgr->info.trans_enabled &&
1407                         mgr->info.trans_key_type != OMAP_DSS_COLOR_KEY_GFX_DST)
1408                 return -EINVAL;
1409
1410         return 0;
1411 }
1412
1413 static int omap_dss_mgr_set_info(struct omap_overlay_manager *mgr,
1414                 struct omap_overlay_manager_info *info)
1415 {
1416         int r;
1417         struct omap_overlay_manager_info old_info;
1418
1419         old_info = mgr->info;
1420         mgr->info = *info;
1421
1422         r = dss_check_manager(mgr);
1423         if (r) {
1424                 mgr->info = old_info;
1425                 return r;
1426         }
1427
1428         mgr->info_dirty = true;
1429
1430         return 0;
1431 }
1432
1433 static void omap_dss_mgr_get_info(struct omap_overlay_manager *mgr,
1434                 struct omap_overlay_manager_info *info)
1435 {
1436         *info = mgr->info;
1437 }
1438
1439 static int dss_mgr_enable(struct omap_overlay_manager *mgr)
1440 {
1441         dispc_enable_channel(mgr->id, 1);
1442         return 0;
1443 }
1444
1445 static int dss_mgr_disable(struct omap_overlay_manager *mgr)
1446 {
1447         dispc_enable_channel(mgr->id, 0);
1448         return 0;
1449 }
1450
1451 static void omap_dss_add_overlay_manager(struct omap_overlay_manager *manager)
1452 {
1453         ++num_managers;
1454         list_add_tail(&manager->list, &manager_list);
1455 }
1456
1457 int dss_init_overlay_managers(struct platform_device *pdev)
1458 {
1459         int i, r;
1460
1461         spin_lock_init(&dss_cache.lock);
1462
1463         INIT_LIST_HEAD(&manager_list);
1464
1465         num_managers = 0;
1466
1467         for (i = 0; i < dss_feat_get_num_mgrs(); ++i) {
1468                 struct omap_overlay_manager *mgr;
1469                 mgr = kzalloc(sizeof(*mgr), GFP_KERNEL);
1470
1471                 BUG_ON(mgr == NULL);
1472
1473                 switch (i) {
1474                 case 0:
1475                         mgr->name = "lcd";
1476                         mgr->id = OMAP_DSS_CHANNEL_LCD;
1477                         break;
1478                 case 1:
1479                         mgr->name = "tv";
1480                         mgr->id = OMAP_DSS_CHANNEL_DIGIT;
1481                         break;
1482                 case 2:
1483                         mgr->name = "lcd2";
1484                         mgr->id = OMAP_DSS_CHANNEL_LCD2;
1485                         break;
1486                 }
1487
1488                 mgr->set_device = &omap_dss_set_device;
1489                 mgr->unset_device = &omap_dss_unset_device;
1490                 mgr->apply = &omap_dss_mgr_apply;
1491                 mgr->set_manager_info = &omap_dss_mgr_set_info;
1492                 mgr->get_manager_info = &omap_dss_mgr_get_info;
1493                 mgr->wait_for_go = &dss_mgr_wait_for_go;
1494                 mgr->wait_for_vsync = &dss_mgr_wait_for_vsync;
1495
1496                 mgr->enable = &dss_mgr_enable;
1497                 mgr->disable = &dss_mgr_disable;
1498
1499                 mgr->caps = OMAP_DSS_OVL_MGR_CAP_DISPC;
1500                 mgr->supported_displays =
1501                         dss_feat_get_supported_displays(mgr->id);
1502
1503                 dss_overlay_setup_dispc_manager(mgr);
1504
1505                 omap_dss_add_overlay_manager(mgr);
1506
1507                 r = kobject_init_and_add(&mgr->kobj, &manager_ktype,
1508                                 &pdev->dev.kobj, "manager%d", i);
1509
1510                 if (r) {
1511                         DSSERR("failed to create sysfs file\n");
1512                         continue;
1513                 }
1514         }
1515
1516 #ifdef L4_EXAMPLE
1517         {
1518                 int omap_dss_mgr_apply_l4(struct omap_overlay_manager *mgr)
1519                 {
1520                         DSSDBG("omap_dss_mgr_apply_l4(%s)\n", mgr->name);
1521
1522                         return 0;
1523                 }
1524
1525                 struct omap_overlay_manager *mgr;
1526                 mgr = kzalloc(sizeof(*mgr), GFP_KERNEL);
1527
1528                 BUG_ON(mgr == NULL);
1529
1530                 mgr->name = "l4";
1531                 mgr->supported_displays =
1532                         OMAP_DISPLAY_TYPE_DBI | OMAP_DISPLAY_TYPE_DSI;
1533
1534                 mgr->set_device = &omap_dss_set_device;
1535                 mgr->unset_device = &omap_dss_unset_device;
1536                 mgr->apply = &omap_dss_mgr_apply_l4;
1537                 mgr->set_manager_info = &omap_dss_mgr_set_info;
1538                 mgr->get_manager_info = &omap_dss_mgr_get_info;
1539
1540                 dss_overlay_setup_l4_manager(mgr);
1541
1542                 omap_dss_add_overlay_manager(mgr);
1543
1544                 r = kobject_init_and_add(&mgr->kobj, &manager_ktype,
1545                                 &pdev->dev.kobj, "managerl4");
1546
1547                 if (r)
1548                         DSSERR("failed to create sysfs file\n");
1549         }
1550 #endif
1551
1552         return 0;
1553 }
1554
1555 void dss_uninit_overlay_managers(struct platform_device *pdev)
1556 {
1557         struct omap_overlay_manager *mgr;
1558
1559         while (!list_empty(&manager_list)) {
1560                 mgr = list_first_entry(&manager_list,
1561                                 struct omap_overlay_manager, list);
1562                 list_del(&mgr->list);
1563                 kobject_del(&mgr->kobj);
1564                 kobject_put(&mgr->kobj);
1565                 kfree(mgr);
1566         }
1567
1568         num_managers = 0;
1569 }
1570
1571 int omap_dss_get_num_overlay_managers(void)
1572 {
1573         return num_managers;
1574 }
1575 EXPORT_SYMBOL(omap_dss_get_num_overlay_managers);
1576
1577 struct omap_overlay_manager *omap_dss_get_overlay_manager(int num)
1578 {
1579         int i = 0;
1580         struct omap_overlay_manager *mgr;
1581
1582         list_for_each_entry(mgr, &manager_list, list) {
1583                 if (i++ == num)
1584                         return mgr;
1585         }
1586
1587         return NULL;
1588 }
1589 EXPORT_SYMBOL(omap_dss_get_overlay_manager);
1590