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