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