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