Merge branch 'stable-3.2' into pandora-3.2
[pandora-kernel.git] / drivers / video / omap2 / dss / overlay.c
1 /*
2  * linux/drivers/video/omap2/dss/overlay.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 "OVERLAY"
24
25 #include <linux/kernel.h>
26 #include <linux/module.h>
27 #include <linux/err.h>
28 #include <linux/sysfs.h>
29 #include <linux/kobject.h>
30 #include <linux/platform_device.h>
31 #include <linux/delay.h>
32 #include <linux/slab.h>
33
34 #include <video/omapdss.h>
35 #include <plat/cpu.h>
36
37 #include "dss.h"
38 #include "dss_features.h"
39
40 static int num_overlays;
41 static struct list_head overlay_list;
42
43 static ssize_t overlay_name_show(struct omap_overlay *ovl, char *buf)
44 {
45         return snprintf(buf, PAGE_SIZE, "%s\n", ovl->name);
46 }
47
48 static ssize_t overlay_manager_show(struct omap_overlay *ovl, char *buf)
49 {
50         return snprintf(buf, PAGE_SIZE, "%s\n",
51                         ovl->manager ? ovl->manager->name : "<none>");
52 }
53
54 static ssize_t overlay_manager_store(struct omap_overlay *ovl, const char *buf,
55                 size_t size)
56 {
57         int i, r;
58         struct omap_overlay_manager *mgr = NULL;
59         struct omap_overlay_manager *old_mgr;
60         int len = size;
61
62         if (buf[size-1] == '\n')
63                 --len;
64
65         if (len > 0) {
66                 for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
67                         mgr = omap_dss_get_overlay_manager(i);
68
69                         if (sysfs_streq(buf, mgr->name))
70                                 break;
71
72                         mgr = NULL;
73                 }
74         }
75
76         if (len > 0 && mgr == NULL)
77                 return -EINVAL;
78
79         if (mgr)
80                 DSSDBG("manager %s found\n", mgr->name);
81
82         if (mgr == ovl->manager)
83                 return size;
84
85         old_mgr = ovl->manager;
86
87         r = dispc_runtime_get();
88         if (r)
89                 return r;
90
91         /* detach old manager */
92         if (old_mgr) {
93                 r = ovl->unset_manager(ovl);
94                 if (r) {
95                         DSSERR("detach failed\n");
96                         goto err;
97                 }
98
99                 r = old_mgr->apply(old_mgr);
100                 if (r)
101                         goto err;
102         }
103
104         if (mgr) {
105                 r = ovl->set_manager(ovl, mgr);
106                 if (r) {
107                         DSSERR("Failed to attach overlay\n");
108                         goto err;
109                 }
110
111                 r = mgr->apply(mgr);
112                 if (r)
113                         goto err;
114         }
115
116         dispc_runtime_put();
117
118         return size;
119
120 err:
121         dispc_runtime_put();
122         return r;
123 }
124
125 static ssize_t overlay_input_size_show(struct omap_overlay *ovl, char *buf)
126 {
127         return snprintf(buf, PAGE_SIZE, "%d,%d\n",
128                         ovl->info.width, ovl->info.height);
129 }
130
131 static ssize_t overlay_screen_width_show(struct omap_overlay *ovl, char *buf)
132 {
133         return snprintf(buf, PAGE_SIZE, "%d\n", ovl->info.screen_width);
134 }
135
136 static ssize_t overlay_position_show(struct omap_overlay *ovl, char *buf)
137 {
138         return snprintf(buf, PAGE_SIZE, "%d,%d\n",
139                         ovl->info.pos_x, ovl->info.pos_y);
140 }
141
142 static ssize_t overlay_position_store(struct omap_overlay *ovl,
143                 const char *buf, size_t size)
144 {
145         int r;
146         char *last;
147         struct omap_overlay_info info;
148
149         ovl->get_overlay_info(ovl, &info);
150
151         info.pos_x = simple_strtoul(buf, &last, 10);
152         ++last;
153         if (last - buf >= size)
154                 return -EINVAL;
155
156         info.pos_y = simple_strtoul(last, &last, 10);
157
158         r = ovl->set_overlay_info(ovl, &info);
159         if (r)
160                 return r;
161
162         if (ovl->manager) {
163                 r = ovl->manager->apply(ovl->manager);
164                 if (r)
165                         return r;
166         }
167
168         return size;
169 }
170
171 static ssize_t overlay_output_size_show(struct omap_overlay *ovl, char *buf)
172 {
173         return snprintf(buf, PAGE_SIZE, "%d,%d\n",
174                         ovl->info.out_width, ovl->info.out_height);
175 }
176
177 static ssize_t overlay_output_size_store(struct omap_overlay *ovl,
178                 const char *buf, size_t size)
179 {
180         int r;
181         char *last;
182         struct omap_overlay_info info;
183
184         ovl->get_overlay_info(ovl, &info);
185
186         info.out_width = simple_strtoul(buf, &last, 10);
187         ++last;
188         if (last - buf >= size)
189                 return -EINVAL;
190
191         info.out_height = simple_strtoul(last, &last, 10);
192
193         r = ovl->set_overlay_info(ovl, &info);
194         if (r)
195                 return r;
196
197         if (ovl->manager) {
198                 r = ovl->manager->apply(ovl->manager);
199                 if (r)
200                         return r;
201         }
202
203         return size;
204 }
205
206 static ssize_t overlay_enabled_show(struct omap_overlay *ovl, char *buf)
207 {
208         return snprintf(buf, PAGE_SIZE, "%d\n", ovl->info.enabled);
209 }
210
211 static ssize_t overlay_enabled_store(struct omap_overlay *ovl, const char *buf,
212                 size_t size)
213 {
214         int r;
215         bool enable;
216         struct omap_overlay_info info;
217
218         ovl->get_overlay_info(ovl, &info);
219
220         r = strtobool(buf, &enable);
221         if (r)
222                 return r;
223
224         info.enabled = enable;
225
226         r = ovl->set_overlay_info(ovl, &info);
227         if (r)
228                 return r;
229
230         if (ovl->manager) {
231                 r = ovl->manager->apply(ovl->manager);
232                 if (r)
233                         return r;
234         }
235
236         return size;
237 }
238
239 static ssize_t overlay_global_alpha_show(struct omap_overlay *ovl, char *buf)
240 {
241         return snprintf(buf, PAGE_SIZE, "%d\n",
242                         ovl->info.global_alpha);
243 }
244
245 static ssize_t overlay_global_alpha_store(struct omap_overlay *ovl,
246                 const char *buf, size_t size)
247 {
248         int r;
249         u8 alpha;
250         struct omap_overlay_info info;
251
252         if ((ovl->caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) == 0)
253                 return -ENODEV;
254
255         r = kstrtou8(buf, 0, &alpha);
256         if (r)
257                 return r;
258
259         ovl->get_overlay_info(ovl, &info);
260
261         info.global_alpha = alpha;
262
263         r = ovl->set_overlay_info(ovl, &info);
264         if (r)
265                 return r;
266
267         if (ovl->manager) {
268                 r = ovl->manager->apply(ovl->manager);
269                 if (r)
270                         return r;
271         }
272
273         return size;
274 }
275
276 static ssize_t overlay_pre_mult_alpha_show(struct omap_overlay *ovl,
277                 char *buf)
278 {
279         return snprintf(buf, PAGE_SIZE, "%d\n",
280                         ovl->info.pre_mult_alpha);
281 }
282
283 static ssize_t overlay_pre_mult_alpha_store(struct omap_overlay *ovl,
284                 const char *buf, size_t size)
285 {
286         int r;
287         u8 alpha;
288         struct omap_overlay_info info;
289
290         if ((ovl->caps & OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA) == 0)
291                 return -ENODEV;
292
293         r = kstrtou8(buf, 0, &alpha);
294         if (r)
295                 return r;
296
297         ovl->get_overlay_info(ovl, &info);
298
299         info.pre_mult_alpha = alpha;
300
301         r = ovl->set_overlay_info(ovl, &info);
302         if (r)
303                 return r;
304
305         if (ovl->manager) {
306                 r = ovl->manager->apply(ovl->manager);
307                 if (r)
308                         return r;
309         }
310
311         return size;
312 }
313
314 static ssize_t overlay_zorder_show(struct omap_overlay *ovl, char *buf)
315 {
316         return snprintf(buf, PAGE_SIZE, "%d\n", ovl->info.zorder);
317 }
318
319 static ssize_t overlay_zorder_store(struct omap_overlay *ovl,
320                 const char *buf, size_t size)
321 {
322         int r;
323         u8 zorder;
324         struct omap_overlay_info info;
325
326         if ((ovl->caps & OMAP_DSS_OVL_CAP_ZORDER) == 0)
327                 return -ENODEV;
328
329         r = kstrtou8(buf, 0, &zorder);
330         if (r)
331                 return r;
332
333         ovl->get_overlay_info(ovl, &info);
334
335         info.zorder = zorder;
336
337         r = ovl->set_overlay_info(ovl, &info);
338         if (r)
339                 return r;
340
341         if (ovl->manager) {
342                 r = ovl->manager->apply(ovl->manager);
343                 if (r)
344                         return r;
345         }
346
347         return size;
348 }
349
350 static ssize_t overlay_filter_coef_show(struct omap_overlay *ovl, char *buf,
351                 int which)
352 {
353         ssize_t ret, len = 0;
354         int vals[5];
355         int i;
356
357         for (i = 0; i < 8; i++) {
358                 dispc_get_scale_coef_phase(ovl->id, which, i, vals);
359                 ret = snprintf(buf, PAGE_SIZE - len, "%3d %3d %3d %3d %3d\n",
360                                 vals[0], vals[1], vals[2], vals[3], vals[4]);
361                 buf += ret;
362                 len += ret;
363         }
364
365         return len;
366 }
367
368 static ssize_t overlay_filter_coef_store(struct omap_overlay *ovl,
369                 const char *buf, size_t size, int which)
370 {
371         const char *p;
372         int vals[8][5];
373         int i, ret;
374
375         p = buf;
376         for (i = 0; i < 8; i++) {
377                 ret = sscanf(p, "%d %d %d %d %d\n", &vals[i][0], &vals[i][1],
378                         &vals[i][2], &vals[i][3], &vals[i][4]);
379                 if (ret != 5) {
380                         DSSWARN("parse err, line %d, ret %d\n", i, ret);
381                         return -EINVAL;
382                 }
383
384                 while (*p != 0 && *p != '\n')
385                         p++;
386                 if (*p == '\n')
387                         p++;
388         }
389
390         for (i = 0; i < 8; i++)
391                 dispc_set_scale_coef_phase(ovl->id, which, i, &vals[i][0]);
392
393         if (ovl->manager && (ret = ovl->manager->apply(ovl->manager)))
394                 return ret;
395
396         return size;
397 }
398
399 static ssize_t overlay_filter_coef_up_h_show(struct omap_overlay *ovl, char *buf)
400 {
401         return overlay_filter_coef_show(ovl, buf, OMAP_DSS_FILTER_UP_H);
402 }
403
404 static ssize_t overlay_filter_coef_up_h_store(struct omap_overlay *ovl,
405                 const char *buf, size_t size)
406 {
407         return overlay_filter_coef_store(ovl, buf, size, OMAP_DSS_FILTER_UP_H);
408 }
409
410 static ssize_t overlay_filter_coef_up_v3_show(struct omap_overlay *ovl, char *buf)
411 {
412         return overlay_filter_coef_show(ovl, buf, OMAP_DSS_FILTER_UP_V3);
413 }
414
415 static ssize_t overlay_filter_coef_up_v3_store(struct omap_overlay *ovl,
416                 const char *buf, size_t size)
417 {
418         return overlay_filter_coef_store(ovl, buf, size, OMAP_DSS_FILTER_UP_V3);
419 }
420
421 static ssize_t overlay_filter_coef_up_v5_show(struct omap_overlay *ovl, char *buf)
422 {
423         return overlay_filter_coef_show(ovl, buf, OMAP_DSS_FILTER_UP_V5);
424 }
425
426 static ssize_t overlay_filter_coef_up_v5_store(struct omap_overlay *ovl,
427                 const char *buf, size_t size)
428 {
429         return overlay_filter_coef_store(ovl, buf, size, OMAP_DSS_FILTER_UP_V5);
430 }
431
432 struct overlay_attribute {
433         struct attribute attr;
434         ssize_t (*show)(struct omap_overlay *, char *);
435         ssize_t (*store)(struct omap_overlay *, const char *, size_t);
436 };
437
438 #define OVERLAY_ATTR(_name, _mode, _show, _store) \
439         struct overlay_attribute overlay_attr_##_name = \
440         __ATTR(_name, _mode, _show, _store)
441
442 static OVERLAY_ATTR(name, S_IRUGO, overlay_name_show, NULL);
443 static OVERLAY_ATTR(manager, S_IRUGO|S_IWUSR,
444                 overlay_manager_show, overlay_manager_store);
445 static OVERLAY_ATTR(input_size, S_IRUGO, overlay_input_size_show, NULL);
446 static OVERLAY_ATTR(screen_width, S_IRUGO, overlay_screen_width_show, NULL);
447 static OVERLAY_ATTR(position, S_IRUGO|S_IWUSR,
448                 overlay_position_show, overlay_position_store);
449 static OVERLAY_ATTR(output_size, S_IRUGO|S_IWUSR,
450                 overlay_output_size_show, overlay_output_size_store);
451 static OVERLAY_ATTR(enabled, S_IRUGO|S_IWUSR,
452                 overlay_enabled_show, overlay_enabled_store);
453 static OVERLAY_ATTR(global_alpha, S_IRUGO|S_IWUSR,
454                 overlay_global_alpha_show, overlay_global_alpha_store);
455 static OVERLAY_ATTR(pre_mult_alpha, S_IRUGO|S_IWUSR,
456                 overlay_pre_mult_alpha_show,
457                 overlay_pre_mult_alpha_store);
458 static OVERLAY_ATTR(zorder, S_IRUGO|S_IWUSR,
459                 overlay_zorder_show, overlay_zorder_store);
460 static OVERLAY_ATTR(filter_coef_up_h, S_IRUGO|S_IWUSR,
461                 overlay_filter_coef_up_h_show, overlay_filter_coef_up_h_store);
462 static OVERLAY_ATTR(filter_coef_up_v3, S_IRUGO|S_IWUSR,
463                 overlay_filter_coef_up_v3_show, overlay_filter_coef_up_v3_store);
464 static OVERLAY_ATTR(filter_coef_up_v5, S_IRUGO|S_IWUSR,
465                 overlay_filter_coef_up_v5_show, overlay_filter_coef_up_v5_store);
466
467 static struct attribute *overlay_sysfs_attrs[] = {
468         &overlay_attr_name.attr,
469         &overlay_attr_manager.attr,
470         &overlay_attr_input_size.attr,
471         &overlay_attr_screen_width.attr,
472         &overlay_attr_position.attr,
473         &overlay_attr_output_size.attr,
474         &overlay_attr_enabled.attr,
475         &overlay_attr_global_alpha.attr,
476         &overlay_attr_pre_mult_alpha.attr,
477         &overlay_attr_zorder.attr,
478         &overlay_attr_filter_coef_up_h.attr,
479         &overlay_attr_filter_coef_up_v3.attr,
480         &overlay_attr_filter_coef_up_v5.attr,
481         NULL
482 };
483
484 static ssize_t overlay_attr_show(struct kobject *kobj, struct attribute *attr,
485                 char *buf)
486 {
487         struct omap_overlay *overlay;
488         struct overlay_attribute *overlay_attr;
489
490         overlay = container_of(kobj, struct omap_overlay, kobj);
491         overlay_attr = container_of(attr, struct overlay_attribute, attr);
492
493         if (!overlay_attr->show)
494                 return -ENOENT;
495
496         return overlay_attr->show(overlay, buf);
497 }
498
499 static ssize_t overlay_attr_store(struct kobject *kobj, struct attribute *attr,
500                 const char *buf, size_t size)
501 {
502         struct omap_overlay *overlay;
503         struct overlay_attribute *overlay_attr;
504
505         overlay = container_of(kobj, struct omap_overlay, kobj);
506         overlay_attr = container_of(attr, struct overlay_attribute, attr);
507
508         if (!overlay_attr->store)
509                 return -ENOENT;
510
511         return overlay_attr->store(overlay, buf, size);
512 }
513
514 static const struct sysfs_ops overlay_sysfs_ops = {
515         .show = overlay_attr_show,
516         .store = overlay_attr_store,
517 };
518
519 static struct kobj_type overlay_ktype = {
520         .sysfs_ops = &overlay_sysfs_ops,
521         .default_attrs = overlay_sysfs_attrs,
522 };
523
524 /* Check if overlay parameters are compatible with display */
525 int dss_check_overlay(struct omap_overlay *ovl, struct omap_dss_device *dssdev)
526 {
527         struct omap_overlay_info *info;
528         u16 outw, outh;
529         u16 dw, dh;
530         int i;
531
532         if (!dssdev)
533                 return 0;
534
535         if (!ovl->info.enabled)
536                 return 0;
537
538         info = &ovl->info;
539
540         if (info->paddr == 0) {
541                 DSSERR("check_overlay failed: paddr 0\n");
542                 return -EINVAL;
543         }
544
545         dssdev->driver->get_resolution(dssdev, &dw, &dh);
546
547         DSSDBG("check_overlay %d: (%d,%d %dx%d -> %dx%d) disp (%dx%d)\n",
548                         ovl->id,
549                         info->pos_x, info->pos_y,
550                         info->width, info->height,
551                         info->out_width, info->out_height,
552                         dw, dh);
553
554         if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0) {
555                 outw = info->width;
556                 outh = info->height;
557         } else {
558                 if (info->out_width == 0)
559                         outw = info->width;
560                 else
561                         outw = info->out_width;
562
563                 if (info->out_height == 0)
564                         outh = info->height;
565                 else
566                         outh = info->out_height;
567         }
568
569         if (dw < info->pos_x + outw) {
570                 DSSERR("check_overlay failed 1: %d < %d + %d\n",
571                                 dw, info->pos_x, outw);
572                 return -EINVAL;
573         }
574
575         if (dh < info->pos_y + outh) {
576                 DSSERR("check_overlay failed 2: %d < %d + %d\n",
577                                 dh, info->pos_y, outh);
578                 return -EINVAL;
579         }
580
581         if ((ovl->supported_modes & info->color_mode) == 0) {
582                 DSSERR("overlay doesn't support mode %d\n", info->color_mode);
583                 return -EINVAL;
584         }
585
586         if (ovl->caps & OMAP_DSS_OVL_CAP_ZORDER) {
587                 if (info->zorder < 0 || info->zorder > 3) {
588                         DSSERR("zorder out of range: %d\n",
589                                 info->zorder);
590                         return -EINVAL;
591                 }
592                 /*
593                  * Check that zorder doesn't match with zorder of any other
594                  * overlay which is enabled and is also connected to the same
595                  * manager
596                  */
597                 for (i = 0; i < omap_dss_get_num_overlays(); i++) {
598                         struct omap_overlay *tmp_ovl = omap_dss_get_overlay(i);
599
600                         if (tmp_ovl->id != ovl->id &&
601                                         tmp_ovl->manager == ovl->manager &&
602                                         tmp_ovl->info.enabled == true &&
603                                         tmp_ovl->info.zorder == info->zorder) {
604                                 DSSERR("%s and %s have same zorder: %d\n",
605                                         ovl->name, tmp_ovl->name, info->zorder);
606                                 return -EINVAL;
607                         }
608                 }
609         }
610
611         return 0;
612 }
613
614 static int dss_ovl_set_overlay_info(struct omap_overlay *ovl,
615                 struct omap_overlay_info *info)
616 {
617         int r;
618         struct omap_overlay_info old_info;
619
620         old_info = ovl->info;
621         ovl->info = *info;
622
623         if (ovl->manager) {
624                 r = dss_check_overlay(ovl, ovl->manager->device);
625                 if (r) {
626                         ovl->info = old_info;
627                         return r;
628                 }
629         }
630
631         ovl->info_dirty = true;
632
633         return 0;
634 }
635
636 static void dss_ovl_get_overlay_info(struct omap_overlay *ovl,
637                 struct omap_overlay_info *info)
638 {
639         *info = ovl->info;
640 }
641
642 static int dss_ovl_wait_for_go(struct omap_overlay *ovl)
643 {
644         return dss_mgr_wait_for_go_ovl(ovl);
645 }
646
647 static int omap_dss_set_manager(struct omap_overlay *ovl,
648                 struct omap_overlay_manager *mgr)
649 {
650         if (!mgr)
651                 return -EINVAL;
652
653         if (ovl->manager) {
654                 DSSERR("overlay '%s' already has a manager '%s'\n",
655                                 ovl->name, ovl->manager->name);
656                 return -EINVAL;
657         }
658
659         if (ovl->info.enabled) {
660                 DSSERR("overlay has to be disabled to change the manager\n");
661                 return -EINVAL;
662         }
663
664         ovl->manager = mgr;
665         ovl->manager_changed = true;
666
667         /* XXX: When there is an overlay on a DSI manual update display, and
668          * the overlay is first disabled, then moved to tv, and enabled, we
669          * seem to get SYNC_LOST_DIGIT error.
670          *
671          * Waiting doesn't seem to help, but updating the manual update display
672          * after disabling the overlay seems to fix this. This hints that the
673          * overlay is perhaps somehow tied to the LCD output until the output
674          * is updated.
675          *
676          * Userspace workaround for this is to update the LCD after disabling
677          * the overlay, but before moving the overlay to TV.
678          */
679
680         return 0;
681 }
682
683 static int omap_dss_unset_manager(struct omap_overlay *ovl)
684 {
685         if (!ovl->manager) {
686                 DSSERR("failed to detach overlay: manager not set\n");
687                 return -EINVAL;
688         }
689
690         if (ovl->info.enabled) {
691                 DSSERR("overlay has to be disabled to unset the manager\n");
692                 return -EINVAL;
693         }
694
695         ovl->manager = NULL;
696         ovl->manager_changed = true;
697
698         return 0;
699 }
700
701 int omap_dss_get_num_overlays(void)
702 {
703         return num_overlays;
704 }
705 EXPORT_SYMBOL(omap_dss_get_num_overlays);
706
707 struct omap_overlay *omap_dss_get_overlay(int num)
708 {
709         int i = 0;
710         struct omap_overlay *ovl;
711
712         list_for_each_entry(ovl, &overlay_list, list) {
713                 if (i++ == num)
714                         return ovl;
715         }
716
717         return NULL;
718 }
719 EXPORT_SYMBOL(omap_dss_get_overlay);
720
721 static void omap_dss_add_overlay(struct omap_overlay *overlay)
722 {
723         ++num_overlays;
724         list_add_tail(&overlay->list, &overlay_list);
725 }
726
727 static struct omap_overlay *dispc_overlays[MAX_DSS_OVERLAYS];
728
729 void dss_overlay_setup_dispc_manager(struct omap_overlay_manager *mgr)
730 {
731         mgr->num_overlays = dss_feat_get_num_ovls();
732         mgr->overlays = dispc_overlays;
733 }
734
735 #ifdef L4_EXAMPLE
736 static struct omap_overlay *l4_overlays[1];
737 void dss_overlay_setup_l4_manager(struct omap_overlay_manager *mgr)
738 {
739         mgr->num_overlays = 1;
740         mgr->overlays = l4_overlays;
741 }
742 #endif
743
744 void dss_init_overlays(struct platform_device *pdev)
745 {
746         int i, r;
747
748         INIT_LIST_HEAD(&overlay_list);
749
750         num_overlays = 0;
751
752         for (i = 0; i < dss_feat_get_num_ovls(); ++i) {
753                 struct omap_overlay *ovl;
754                 ovl = kzalloc(sizeof(*ovl), GFP_KERNEL);
755
756                 BUG_ON(ovl == NULL);
757
758                 switch (i) {
759                 case 0:
760                         ovl->name = "gfx";
761                         ovl->id = OMAP_DSS_GFX;
762                         ovl->info.global_alpha = 255;
763                         ovl->info.zorder = 0;
764                         break;
765                 case 1:
766                         ovl->name = "vid1";
767                         ovl->id = OMAP_DSS_VIDEO1;
768                         ovl->info.global_alpha = 255;
769                         ovl->info.zorder =
770                                 dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 3 : 0;
771                         break;
772                 case 2:
773                         ovl->name = "vid2";
774                         ovl->id = OMAP_DSS_VIDEO2;
775                         ovl->info.global_alpha = 255;
776                         ovl->info.zorder =
777                                 dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 2 : 0;
778                         break;
779                 case 3:
780                         ovl->name = "vid3";
781                         ovl->id = OMAP_DSS_VIDEO3;
782                         ovl->info.global_alpha = 255;
783                         ovl->info.zorder =
784                                 dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 1 : 0;
785                         break;
786                 }
787
788                 ovl->set_manager = &omap_dss_set_manager;
789                 ovl->unset_manager = &omap_dss_unset_manager;
790                 ovl->set_overlay_info = &dss_ovl_set_overlay_info;
791                 ovl->get_overlay_info = &dss_ovl_get_overlay_info;
792                 ovl->wait_for_go = &dss_ovl_wait_for_go;
793
794                 ovl->caps = dss_feat_get_overlay_caps(ovl->id);
795                 ovl->supported_modes =
796                         dss_feat_get_supported_color_modes(ovl->id);
797
798                 omap_dss_add_overlay(ovl);
799
800                 r = kobject_init_and_add(&ovl->kobj, &overlay_ktype,
801                                 &pdev->dev.kobj, "overlay%d", i);
802
803                 if (r) {
804                         DSSERR("failed to create sysfs file\n");
805                         continue;
806                 }
807
808                 dispc_overlays[i] = ovl;
809         }
810
811 #ifdef L4_EXAMPLE
812         {
813                 struct omap_overlay *ovl;
814                 ovl = kzalloc(sizeof(*ovl), GFP_KERNEL);
815
816                 BUG_ON(ovl == NULL);
817
818                 ovl->name = "l4";
819                 ovl->supported_modes = OMAP_DSS_COLOR_RGB24U;
820
821                 ovl->set_manager = &omap_dss_set_manager;
822                 ovl->unset_manager = &omap_dss_unset_manager;
823                 ovl->set_overlay_info = &dss_ovl_set_overlay_info;
824                 ovl->get_overlay_info = &dss_ovl_get_overlay_info;
825
826                 omap_dss_add_overlay(ovl);
827
828                 r = kobject_init_and_add(&ovl->kobj, &overlay_ktype,
829                                 &pdev->dev.kobj, "overlayl4");
830
831                 if (r)
832                         DSSERR("failed to create sysfs file\n");
833
834                 l4_overlays[0] = ovl;
835         }
836 #endif
837 }
838
839 /* connect overlays to the new device, if not already connected. if force
840  * selected, connect always. */
841 void dss_recheck_connections(struct omap_dss_device *dssdev, bool force)
842 {
843         int i;
844         struct omap_overlay_manager *lcd_mgr;
845         struct omap_overlay_manager *tv_mgr;
846         struct omap_overlay_manager *lcd2_mgr = NULL;
847         struct omap_overlay_manager *mgr = NULL;
848
849         lcd_mgr = omap_dss_get_overlay_manager(OMAP_DSS_OVL_MGR_LCD);
850         tv_mgr = omap_dss_get_overlay_manager(OMAP_DSS_OVL_MGR_TV);
851         if (dss_has_feature(FEAT_MGR_LCD2))
852                 lcd2_mgr = omap_dss_get_overlay_manager(OMAP_DSS_OVL_MGR_LCD2);
853
854         if (dssdev->channel == OMAP_DSS_CHANNEL_LCD2) {
855                 if (!lcd2_mgr->device || force) {
856                         if (lcd2_mgr->device)
857                                 lcd2_mgr->unset_device(lcd2_mgr);
858                         lcd2_mgr->set_device(lcd2_mgr, dssdev);
859                         mgr = lcd2_mgr;
860                 }
861         } else if (dssdev->type != OMAP_DISPLAY_TYPE_VENC
862                         && dssdev->type != OMAP_DISPLAY_TYPE_HDMI) {
863                 if (!lcd_mgr->device || force) {
864                         if (lcd_mgr->device)
865                                 lcd_mgr->unset_device(lcd_mgr);
866                         lcd_mgr->set_device(lcd_mgr, dssdev);
867                         mgr = lcd_mgr;
868                 }
869         }
870
871         if (dssdev->type == OMAP_DISPLAY_TYPE_VENC
872                         || dssdev->type == OMAP_DISPLAY_TYPE_HDMI) {
873                 if (!tv_mgr->device || force) {
874                         if (tv_mgr->device)
875                                 tv_mgr->unset_device(tv_mgr);
876                         tv_mgr->set_device(tv_mgr, dssdev);
877                         mgr = tv_mgr;
878                 }
879         }
880
881         if (mgr) {
882                 dispc_runtime_get();
883
884                 for (i = 0; i < dss_feat_get_num_ovls(); i++) {
885                         struct omap_overlay *ovl;
886                         ovl = omap_dss_get_overlay(i);
887                         if (!ovl->manager || force) {
888                                 if (ovl->manager)
889                                         omap_dss_unset_manager(ovl);
890                                 omap_dss_set_manager(ovl, mgr);
891                         }
892                 }
893
894                 dispc_runtime_put();
895         }
896 }
897
898 void dss_uninit_overlays(struct platform_device *pdev)
899 {
900         struct omap_overlay *ovl;
901
902         while (!list_empty(&overlay_list)) {
903                 ovl = list_first_entry(&overlay_list,
904                                 struct omap_overlay, list);
905                 list_del(&ovl->list);
906                 kobject_del(&ovl->kobj);
907                 kobject_put(&ovl->kobj);
908                 kfree(ovl);
909         }
910
911         num_overlays = 0;
912 }
913