Merge branch 'stable-3.2' into pandora-3.2
[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 = msecs_to_jiffies(500);
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 = msecs_to_jiffies(500);
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                 mgr_busy[i] = dispc_mgr_go_busy(i);
1024                 mgr_go[i] = false;
1025         }
1026
1027         /* Commit overlay settings */
1028         for (i = 0; i < num_ovls; ++i) {
1029                 oc = &dss_cache.overlay_cache[i];
1030                 mc = &dss_cache.manager_cache[oc->channel];
1031
1032                 if (!oc->dirty)
1033                         continue;
1034
1035                 if (mc->manual_update && !mc->do_manual_update)
1036                         continue;
1037
1038                 if (mgr_busy[oc->channel]) {
1039                         busy = true;
1040                         continue;
1041                 }
1042
1043                 r = configure_overlay(i);
1044                 if (r)
1045                         DSSERR("configure_overlay %d failed\n", i);
1046
1047                 oc->dirty = false;
1048                 oc->shadow_dirty = true;
1049                 mgr_go[oc->channel] = true;
1050         }
1051
1052         /* Commit manager settings */
1053         for (i = 0; i < num_mgrs; ++i) {
1054                 mc = &dss_cache.manager_cache[i];
1055
1056                 if (!mc->dirty)
1057                         continue;
1058
1059                 if (mc->manual_update && !mc->do_manual_update)
1060                         continue;
1061
1062                 if (mgr_busy[i]) {
1063                         busy = true;
1064                         continue;
1065                 }
1066
1067                 configure_manager(i);
1068                 mc->dirty = false;
1069                 mc->shadow_dirty = true;
1070                 mgr_go[i] = true;
1071         }
1072
1073         /* set GO */
1074         for (i = 0; i < num_mgrs; ++i) {
1075                 mc = &dss_cache.manager_cache[i];
1076
1077                 if (!mgr_go[i])
1078                         continue;
1079
1080                 /* We don't need GO with manual update display. LCD iface will
1081                  * always be turned off after frame, and new settings will be
1082                  * taken in to use at next update */
1083                 if (!mc->manual_update)
1084                         dispc_mgr_go(i);
1085         }
1086
1087         if (busy)
1088                 r = 1;
1089         else
1090                 r = 0;
1091
1092         return r;
1093 }
1094
1095 /* Make the coordinates even. There are some strange problems with OMAP and
1096  * partial DSI update when the update widths are odd. */
1097 static void make_even(u16 *x, u16 *w)
1098 {
1099         u16 x1, x2;
1100
1101         x1 = *x;
1102         x2 = *x + *w;
1103
1104         x1 &= ~1;
1105         x2 = ALIGN(x2, 2);
1106
1107         *x = x1;
1108         *w = x2 - x1;
1109 }
1110
1111 /* Configure dispc for partial update. Return possibly modified update
1112  * area */
1113 void dss_setup_partial_planes(struct omap_dss_device *dssdev,
1114                 u16 *xi, u16 *yi, u16 *wi, u16 *hi, bool enlarge_update_area)
1115 {
1116         struct overlay_cache_data *oc;
1117         struct manager_cache_data *mc;
1118         struct omap_overlay_info *oi;
1119         const int num_ovls = dss_feat_get_num_ovls();
1120         struct omap_overlay_manager *mgr;
1121         int i;
1122         u16 x, y, w, h;
1123         unsigned long flags;
1124         bool area_changed;
1125
1126         x = *xi;
1127         y = *yi;
1128         w = *wi;
1129         h = *hi;
1130
1131         DSSDBG("dispc_setup_partial_planes %d,%d %dx%d\n",
1132                 *xi, *yi, *wi, *hi);
1133
1134         mgr = dssdev->manager;
1135
1136         if (!mgr) {
1137                 DSSDBG("no manager\n");
1138                 return;
1139         }
1140
1141         make_even(&x, &w);
1142
1143         spin_lock_irqsave(&dss_cache.lock, flags);
1144
1145         /*
1146          * Execute the outer loop until the inner loop has completed
1147          * once without increasing the update area. This will ensure that
1148          * all scaled overlays end up completely within the update area.
1149          */
1150         do {
1151                 area_changed = false;
1152
1153                 /* We need to show the whole overlay if it is scaled. So look
1154                  * for those, and make the update area larger if found.
1155                  * Also mark the overlay cache dirty */
1156                 for (i = 0; i < num_ovls; ++i) {
1157                         unsigned x1, y1, x2, y2;
1158                         unsigned outw, outh;
1159
1160                         oc = &dss_cache.overlay_cache[i];
1161                         oi = &oc->info;
1162
1163                         if (oc->channel != mgr->id)
1164                                 continue;
1165
1166                         oc->dirty = true;
1167
1168                         if (!enlarge_update_area)
1169                                 continue;
1170
1171                         if (!oc->enabled)
1172                                 continue;
1173
1174                         if (!dispc_is_overlay_scaled(oc))
1175                                 continue;
1176
1177                         outw = oi->out_width == 0 ?
1178                                 oi->width : oi->out_width;
1179                         outh = oi->out_height == 0 ?
1180                                 oi->height : oi->out_height;
1181
1182                         /* is the overlay outside the update region? */
1183                         if (!rectangle_intersects(x, y, w, h,
1184                                                 oi->pos_x, oi->pos_y,
1185                                                 outw, outh))
1186                                 continue;
1187
1188                         /* if the overlay totally inside the update region? */
1189                         if (rectangle_subset(oi->pos_x, oi->pos_y, outw, outh,
1190                                                 x, y, w, h))
1191                                 continue;
1192
1193                         if (x > oi->pos_x)
1194                                 x1 = oi->pos_x;
1195                         else
1196                                 x1 = x;
1197
1198                         if (y > oi->pos_y)
1199                                 y1 = oi->pos_y;
1200                         else
1201                                 y1 = y;
1202
1203                         if ((x + w) < (oi->pos_x + outw))
1204                                 x2 = oi->pos_x + outw;
1205                         else
1206                                 x2 = x + w;
1207
1208                         if ((y + h) < (oi->pos_y + outh))
1209                                 y2 = oi->pos_y + outh;
1210                         else
1211                                 y2 = y + h;
1212
1213                         x = x1;
1214                         y = y1;
1215                         w = x2 - x1;
1216                         h = y2 - y1;
1217
1218                         make_even(&x, &w);
1219
1220                         DSSDBG("changing upd area due to ovl(%d) "
1221                                "scaling %d,%d %dx%d\n",
1222                                 i, x, y, w, h);
1223
1224                         area_changed = true;
1225                 }
1226         } while (area_changed);
1227
1228         mc = &dss_cache.manager_cache[mgr->id];
1229         mc->do_manual_update = true;
1230         mc->enlarge_update_area = enlarge_update_area;
1231         mc->x = x;
1232         mc->y = y;
1233         mc->w = w;
1234         mc->h = h;
1235
1236         configure_dispc();
1237
1238         mc->do_manual_update = false;
1239
1240         spin_unlock_irqrestore(&dss_cache.lock, flags);
1241
1242         *xi = x;
1243         *yi = y;
1244         *wi = w;
1245         *hi = h;
1246 }
1247
1248 void dss_start_update(struct omap_dss_device *dssdev)
1249 {
1250         struct manager_cache_data *mc;
1251         struct overlay_cache_data *oc;
1252         const int num_ovls = dss_feat_get_num_ovls();
1253         const int num_mgrs = dss_feat_get_num_mgrs();
1254         struct omap_overlay_manager *mgr;
1255         int i;
1256
1257         mgr = dssdev->manager;
1258
1259         for (i = 0; i < num_ovls; ++i) {
1260                 oc = &dss_cache.overlay_cache[i];
1261                 if (oc->channel != mgr->id)
1262                         continue;
1263
1264                 oc->shadow_dirty = false;
1265         }
1266
1267         for (i = 0; i < num_mgrs; ++i) {
1268                 mc = &dss_cache.manager_cache[i];
1269                 if (mgr->id != i)
1270                         continue;
1271
1272                 mc->shadow_dirty = false;
1273         }
1274
1275         dssdev->manager->enable(dssdev->manager);
1276 }
1277
1278 static void dss_apply_irq_handler(void *data, u32 mask)
1279 {
1280         struct manager_cache_data *mc;
1281         struct overlay_cache_data *oc;
1282         const int num_ovls = dss_feat_get_num_ovls();
1283         const int num_mgrs = dss_feat_get_num_mgrs();
1284         int i, r;
1285         bool mgr_busy[MAX_DSS_MANAGERS];
1286         u32 irq_mask;
1287
1288         for (i = 0; i < num_mgrs; i++)
1289                 mgr_busy[i] = dispc_mgr_go_busy(i);
1290
1291         spin_lock(&dss_cache.lock);
1292
1293         for (i = 0; i < num_ovls; ++i) {
1294                 oc = &dss_cache.overlay_cache[i];
1295                 if (!mgr_busy[oc->channel])
1296                         oc->shadow_dirty = false;
1297         }
1298
1299         for (i = 0; i < num_mgrs; ++i) {
1300                 mc = &dss_cache.manager_cache[i];
1301                 if (!mgr_busy[i])
1302                         mc->shadow_dirty = false;
1303         }
1304
1305         r = configure_dispc();
1306         if (r == 1)
1307                 goto end;
1308
1309         /* re-read busy flags */
1310         for (i = 0; i < num_mgrs; i++)
1311                 mgr_busy[i] = dispc_mgr_go_busy(i);
1312
1313         /* keep running as long as there are busy managers, so that
1314          * we can collect overlay-applied information */
1315         for (i = 0; i < num_mgrs; ++i) {
1316                 if (mgr_busy[i])
1317                         goto end;
1318         }
1319
1320         irq_mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_ODD |
1321                         DISPC_IRQ_EVSYNC_EVEN;
1322         if (dss_has_feature(FEAT_MGR_LCD2))
1323                 irq_mask |= DISPC_IRQ_VSYNC2;
1324
1325         omap_dispc_unregister_isr(dss_apply_irq_handler, NULL, irq_mask);
1326         dss_cache.irq_enabled = false;
1327
1328 end:
1329         spin_unlock(&dss_cache.lock);
1330 }
1331
1332 static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
1333 {
1334         struct overlay_cache_data *oc;
1335         struct manager_cache_data *mc;
1336         int i;
1337         struct omap_overlay *ovl;
1338         int num_planes_enabled = 0;
1339         bool use_fifomerge;
1340         unsigned long flags;
1341         int r;
1342
1343         DSSDBG("omap_dss_mgr_apply(%s)\n", mgr->name);
1344
1345         r = dispc_runtime_get();
1346         if (r)
1347                 return r;
1348
1349         spin_lock_irqsave(&dss_cache.lock, flags);
1350
1351         /* Configure overlays */
1352         for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
1353                 struct omap_dss_device *dssdev;
1354
1355                 ovl = omap_dss_get_overlay(i);
1356
1357                 oc = &dss_cache.overlay_cache[ovl->id];
1358
1359                 if (ovl->manager_changed) {
1360                         ovl->manager_changed = false;
1361                         ovl->info_dirty  = true;
1362                 }
1363
1364                 if (!overlay_enabled(ovl)) {
1365                         if (oc->enabled) {
1366                                 oc->enabled = false;
1367                                 oc->dirty = true;
1368                         }
1369                         continue;
1370                 }
1371
1372                 if (!ovl->info_dirty) {
1373                         if (oc->enabled)
1374                                 ++num_planes_enabled;
1375                         continue;
1376                 }
1377
1378                 dssdev = ovl->manager->device;
1379
1380                 if (dss_check_overlay(ovl, dssdev)) {
1381                         if (oc->enabled) {
1382                                 oc->enabled = false;
1383                                 oc->dirty = true;
1384                         }
1385                         continue;
1386                 }
1387
1388                 ovl->info_dirty = false;
1389                 oc->dirty = true;
1390                 oc->info = ovl->info;
1391
1392                 oc->replication =
1393                         dss_use_replication(dssdev, ovl->info.color_mode);
1394
1395                 oc->ilace = dssdev->type == OMAP_DISPLAY_TYPE_VENC;
1396
1397                 oc->channel = ovl->manager->id;
1398
1399                 oc->enabled = true;
1400
1401                 ++num_planes_enabled;
1402         }
1403
1404         /* Configure managers */
1405         list_for_each_entry(mgr, &manager_list, list) {
1406                 struct omap_dss_device *dssdev;
1407
1408                 mc = &dss_cache.manager_cache[mgr->id];
1409
1410                 if (mgr->device_changed) {
1411                         mgr->device_changed = false;
1412                         mgr->info_dirty  = true;
1413                 }
1414
1415                 if (!mgr->info_dirty)
1416                         continue;
1417
1418                 if (!mgr->device)
1419                         continue;
1420
1421                 dssdev = mgr->device;
1422
1423                 mgr->info_dirty = false;
1424                 mc->dirty = true;
1425                 mc->info = mgr->info;
1426
1427                 mc->manual_update =
1428                         dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE;
1429         }
1430
1431         /* XXX TODO: Try to get fifomerge working. The problem is that it
1432          * affects both managers, not individually but at the same time. This
1433          * means the change has to be well synchronized. I guess the proper way
1434          * is to have a two step process for fifo merge:
1435          *        fifomerge enable:
1436          *             1. disable other planes, leaving one plane enabled
1437          *             2. wait until the planes are disabled on HW
1438          *             3. config merged fifo thresholds, enable fifomerge
1439          *        fifomerge disable:
1440          *             1. config unmerged fifo thresholds, disable fifomerge
1441          *             2. wait until fifo changes are in HW
1442          *             3. enable planes
1443          */
1444         use_fifomerge = false;
1445
1446         /* Configure overlay fifos */
1447         for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
1448                 struct omap_dss_device *dssdev;
1449                 u32 size, burst_size;
1450
1451                 ovl = omap_dss_get_overlay(i);
1452
1453                 oc = &dss_cache.overlay_cache[ovl->id];
1454
1455                 if (!oc->enabled)
1456                         continue;
1457
1458                 dssdev = ovl->manager->device;
1459
1460                 size = dispc_ovl_get_fifo_size(ovl->id);
1461                 if (use_fifomerge)
1462                         size *= 3;
1463
1464                 burst_size = dispc_ovl_get_burst_size(ovl->id);
1465
1466                 switch (dssdev->type) {
1467                 case OMAP_DISPLAY_TYPE_DPI:
1468                 case OMAP_DISPLAY_TYPE_DBI:
1469                 case OMAP_DISPLAY_TYPE_SDI:
1470                 case OMAP_DISPLAY_TYPE_VENC:
1471                 case OMAP_DISPLAY_TYPE_HDMI:
1472                         default_get_overlay_fifo_thresholds(ovl->id, size,
1473                                         burst_size, &oc->fifo_low,
1474                                         &oc->fifo_high);
1475                         break;
1476 #ifdef CONFIG_OMAP2_DSS_DSI
1477                 case OMAP_DISPLAY_TYPE_DSI:
1478                         dsi_get_overlay_fifo_thresholds(ovl->id, size,
1479                                         burst_size, &oc->fifo_low,
1480                                         &oc->fifo_high);
1481                         break;
1482 #endif
1483                 default:
1484                         BUG();
1485                 }
1486         }
1487
1488         r = 0;
1489         if (!dss_cache.irq_enabled) {
1490                 u32 mask;
1491
1492                 mask = DISPC_IRQ_VSYNC  | DISPC_IRQ_EVSYNC_ODD |
1493                         DISPC_IRQ_EVSYNC_EVEN;
1494                 if (dss_has_feature(FEAT_MGR_LCD2))
1495                         mask |= DISPC_IRQ_VSYNC2;
1496
1497                 r = omap_dispc_register_isr(dss_apply_irq_handler, NULL, mask);
1498                 dss_cache.irq_enabled = true;
1499         }
1500         configure_dispc();
1501
1502         spin_unlock_irqrestore(&dss_cache.lock, flags);
1503
1504         dispc_runtime_put();
1505
1506         return r;
1507 }
1508
1509 static int dss_check_manager(struct omap_overlay_manager *mgr)
1510 {
1511         if (dss_has_feature(FEAT_ALPHA_FIXED_ZORDER)) {
1512                 /*
1513                  * OMAP3 supports only graphics source transparency color key
1514                  * and alpha blending simultaneously. See TRM 15.4.2.4.2.2
1515                  * Alpha Mode
1516                  */
1517                 if (mgr->info.partial_alpha_enabled && mgr->info.trans_enabled
1518                         && mgr->info.trans_key_type !=
1519                                 OMAP_DSS_COLOR_KEY_GFX_DST)
1520                         return -EINVAL;
1521         }
1522
1523         return 0;
1524 }
1525
1526 static int omap_dss_mgr_set_info(struct omap_overlay_manager *mgr,
1527                 struct omap_overlay_manager_info *info)
1528 {
1529         int r;
1530         struct omap_overlay_manager_info old_info;
1531
1532         old_info = mgr->info;
1533         mgr->info = *info;
1534
1535         r = dss_check_manager(mgr);
1536         if (r) {
1537                 mgr->info = old_info;
1538                 return r;
1539         }
1540
1541         mgr->info_dirty = true;
1542
1543         return 0;
1544 }
1545
1546 static void omap_dss_mgr_get_info(struct omap_overlay_manager *mgr,
1547                 struct omap_overlay_manager_info *info)
1548 {
1549         *info = mgr->info;
1550 }
1551
1552 static int dss_mgr_enable(struct omap_overlay_manager *mgr)
1553 {
1554         dispc_mgr_enable(mgr->id, 1);
1555         return 0;
1556 }
1557
1558 static int dss_mgr_disable(struct omap_overlay_manager *mgr)
1559 {
1560         dispc_mgr_enable(mgr->id, 0);
1561         return 0;
1562 }
1563
1564 static void omap_dss_add_overlay_manager(struct omap_overlay_manager *manager)
1565 {
1566         ++num_managers;
1567         list_add_tail(&manager->list, &manager_list);
1568 }
1569
1570 int dss_init_overlay_managers(struct platform_device *pdev)
1571 {
1572         int i, r;
1573
1574         spin_lock_init(&dss_cache.lock);
1575
1576         INIT_LIST_HEAD(&manager_list);
1577
1578         num_managers = 0;
1579
1580         for (i = 0; i < dss_feat_get_num_mgrs(); ++i) {
1581                 struct omap_overlay_manager *mgr;
1582                 mgr = kzalloc(sizeof(*mgr), GFP_KERNEL);
1583
1584                 BUG_ON(mgr == NULL);
1585
1586                 switch (i) {
1587                 case 0:
1588                         mgr->name = "lcd";
1589                         mgr->id = OMAP_DSS_CHANNEL_LCD;
1590                         break;
1591                 case 1:
1592                         mgr->name = "tv";
1593                         mgr->id = OMAP_DSS_CHANNEL_DIGIT;
1594                         break;
1595                 case 2:
1596                         mgr->name = "lcd2";
1597                         mgr->id = OMAP_DSS_CHANNEL_LCD2;
1598                         break;
1599                 }
1600
1601                 mgr->set_device = &omap_dss_set_device;
1602                 mgr->unset_device = &omap_dss_unset_device;
1603                 mgr->apply = &omap_dss_mgr_apply;
1604                 mgr->set_manager_info = &omap_dss_mgr_set_info;
1605                 mgr->get_manager_info = &omap_dss_mgr_get_info;
1606                 mgr->wait_for_go = &dss_mgr_wait_for_go;
1607                 mgr->wait_for_vsync = &dss_mgr_wait_for_vsync;
1608
1609                 mgr->enable = &dss_mgr_enable;
1610                 mgr->disable = &dss_mgr_disable;
1611
1612                 mgr->caps = 0;
1613                 mgr->supported_displays =
1614                         dss_feat_get_supported_displays(mgr->id);
1615
1616                 dss_overlay_setup_dispc_manager(mgr);
1617
1618                 omap_dss_add_overlay_manager(mgr);
1619
1620                 r = kobject_init_and_add(&mgr->kobj, &manager_ktype,
1621                                 &pdev->dev.kobj, "manager%d", i);
1622
1623                 if (r) {
1624                         DSSERR("failed to create sysfs file\n");
1625                         continue;
1626                 }
1627         }
1628
1629         return 0;
1630 }
1631
1632 void dss_uninit_overlay_managers(struct platform_device *pdev)
1633 {
1634         struct omap_overlay_manager *mgr;
1635
1636         while (!list_empty(&manager_list)) {
1637                 mgr = list_first_entry(&manager_list,
1638                                 struct omap_overlay_manager, list);
1639                 list_del(&mgr->list);
1640                 kobject_del(&mgr->kobj);
1641                 kobject_put(&mgr->kobj);
1642                 kfree(mgr);
1643         }
1644
1645         num_managers = 0;
1646 }
1647
1648 int omap_dss_get_num_overlay_managers(void)
1649 {
1650         return num_managers;
1651 }
1652 EXPORT_SYMBOL(omap_dss_get_num_overlay_managers);
1653
1654 struct omap_overlay_manager *omap_dss_get_overlay_manager(int num)
1655 {
1656         int i = 0;
1657         struct omap_overlay_manager *mgr;
1658
1659         list_for_each_entry(mgr, &manager_list, list) {
1660                 if (i++ == num)
1661                         return mgr;
1662         }
1663
1664         return NULL;
1665 }
1666 EXPORT_SYMBOL(omap_dss_get_overlay_manager);
1667