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