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