Commit | Line | Data |
---|---|---|
eed07e0e TV |
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 | ||
33 | #include <plat/display.h> | |
34 | #include <plat/cpu.h> | |
35 | ||
36 | #include "dss.h" | |
37 | ||
38 | static int num_overlays; | |
39 | static struct list_head overlay_list; | |
40 | ||
41 | static ssize_t overlay_name_show(struct omap_overlay *ovl, char *buf) | |
42 | { | |
43 | return snprintf(buf, PAGE_SIZE, "%s\n", ovl->name); | |
44 | } | |
45 | ||
46 | static ssize_t overlay_manager_show(struct omap_overlay *ovl, char *buf) | |
47 | { | |
48 | return snprintf(buf, PAGE_SIZE, "%s\n", | |
49 | ovl->manager ? ovl->manager->name : "<none>"); | |
50 | } | |
51 | ||
52 | static ssize_t overlay_manager_store(struct omap_overlay *ovl, const char *buf, | |
53 | size_t size) | |
54 | { | |
55 | int i, r; | |
56 | struct omap_overlay_manager *mgr = NULL; | |
57 | struct omap_overlay_manager *old_mgr; | |
58 | int len = size; | |
59 | ||
60 | if (buf[size-1] == '\n') | |
61 | --len; | |
62 | ||
63 | if (len > 0) { | |
64 | for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) { | |
65 | mgr = omap_dss_get_overlay_manager(i); | |
66 | ||
67 | if (strncmp(buf, mgr->name, len) == 0) | |
68 | break; | |
69 | ||
70 | mgr = NULL; | |
71 | } | |
72 | } | |
73 | ||
74 | if (len > 0 && mgr == NULL) | |
75 | return -EINVAL; | |
76 | ||
77 | if (mgr) | |
78 | DSSDBG("manager %s found\n", mgr->name); | |
79 | ||
80 | if (mgr == ovl->manager) | |
81 | return size; | |
82 | ||
83 | old_mgr = ovl->manager; | |
84 | ||
85 | /* detach old manager */ | |
86 | if (old_mgr) { | |
87 | r = ovl->unset_manager(ovl); | |
88 | if (r) { | |
89 | DSSERR("detach failed\n"); | |
90 | return r; | |
91 | } | |
92 | ||
93 | r = old_mgr->apply(old_mgr); | |
94 | if (r) | |
95 | return r; | |
96 | } | |
97 | ||
98 | if (mgr) { | |
99 | r = ovl->set_manager(ovl, mgr); | |
100 | if (r) { | |
101 | DSSERR("Failed to attach overlay\n"); | |
102 | return r; | |
103 | } | |
104 | ||
105 | r = mgr->apply(mgr); | |
106 | if (r) | |
107 | return r; | |
108 | } | |
109 | ||
110 | return size; | |
111 | } | |
112 | ||
113 | static ssize_t overlay_input_size_show(struct omap_overlay *ovl, char *buf) | |
114 | { | |
115 | return snprintf(buf, PAGE_SIZE, "%d,%d\n", | |
116 | ovl->info.width, ovl->info.height); | |
117 | } | |
118 | ||
119 | static ssize_t overlay_screen_width_show(struct omap_overlay *ovl, char *buf) | |
120 | { | |
121 | return snprintf(buf, PAGE_SIZE, "%d\n", ovl->info.screen_width); | |
122 | } | |
123 | ||
124 | static ssize_t overlay_position_show(struct omap_overlay *ovl, char *buf) | |
125 | { | |
126 | return snprintf(buf, PAGE_SIZE, "%d,%d\n", | |
127 | ovl->info.pos_x, ovl->info.pos_y); | |
128 | } | |
129 | ||
130 | static ssize_t overlay_position_store(struct omap_overlay *ovl, | |
131 | const char *buf, size_t size) | |
132 | { | |
133 | int r; | |
134 | char *last; | |
135 | struct omap_overlay_info info; | |
136 | ||
137 | ovl->get_overlay_info(ovl, &info); | |
138 | ||
139 | info.pos_x = simple_strtoul(buf, &last, 10); | |
140 | ++last; | |
141 | if (last - buf >= size) | |
142 | return -EINVAL; | |
143 | ||
144 | info.pos_y = simple_strtoul(last, &last, 10); | |
145 | ||
146 | r = ovl->set_overlay_info(ovl, &info); | |
147 | if (r) | |
148 | return r; | |
149 | ||
150 | if (ovl->manager) { | |
151 | r = ovl->manager->apply(ovl->manager); | |
152 | if (r) | |
153 | return r; | |
154 | } | |
155 | ||
156 | return size; | |
157 | } | |
158 | ||
159 | static ssize_t overlay_output_size_show(struct omap_overlay *ovl, char *buf) | |
160 | { | |
161 | return snprintf(buf, PAGE_SIZE, "%d,%d\n", | |
162 | ovl->info.out_width, ovl->info.out_height); | |
163 | } | |
164 | ||
165 | static ssize_t overlay_output_size_store(struct omap_overlay *ovl, | |
166 | const char *buf, size_t size) | |
167 | { | |
168 | int r; | |
169 | char *last; | |
170 | struct omap_overlay_info info; | |
171 | ||
172 | ovl->get_overlay_info(ovl, &info); | |
173 | ||
174 | info.out_width = simple_strtoul(buf, &last, 10); | |
175 | ++last; | |
176 | if (last - buf >= size) | |
177 | return -EINVAL; | |
178 | ||
179 | info.out_height = simple_strtoul(last, &last, 10); | |
180 | ||
181 | r = ovl->set_overlay_info(ovl, &info); | |
182 | if (r) | |
183 | return r; | |
184 | ||
185 | if (ovl->manager) { | |
186 | r = ovl->manager->apply(ovl->manager); | |
187 | if (r) | |
188 | return r; | |
189 | } | |
190 | ||
191 | return size; | |
192 | } | |
193 | ||
194 | static ssize_t overlay_enabled_show(struct omap_overlay *ovl, char *buf) | |
195 | { | |
196 | return snprintf(buf, PAGE_SIZE, "%d\n", ovl->info.enabled); | |
197 | } | |
198 | ||
199 | static ssize_t overlay_enabled_store(struct omap_overlay *ovl, const char *buf, | |
200 | size_t size) | |
201 | { | |
202 | int r; | |
203 | struct omap_overlay_info info; | |
204 | ||
205 | ovl->get_overlay_info(ovl, &info); | |
206 | ||
207 | info.enabled = simple_strtoul(buf, NULL, 10); | |
208 | ||
209 | r = ovl->set_overlay_info(ovl, &info); | |
210 | if (r) | |
211 | return r; | |
212 | ||
213 | if (ovl->manager) { | |
214 | r = ovl->manager->apply(ovl->manager); | |
215 | if (r) | |
216 | return r; | |
217 | } | |
218 | ||
219 | return size; | |
220 | } | |
221 | ||
222 | static ssize_t overlay_global_alpha_show(struct omap_overlay *ovl, char *buf) | |
223 | { | |
224 | return snprintf(buf, PAGE_SIZE, "%d\n", | |
225 | ovl->info.global_alpha); | |
226 | } | |
227 | ||
228 | static ssize_t overlay_global_alpha_store(struct omap_overlay *ovl, | |
229 | const char *buf, size_t size) | |
230 | { | |
231 | int r; | |
232 | struct omap_overlay_info info; | |
233 | ||
234 | ovl->get_overlay_info(ovl, &info); | |
235 | ||
236 | /* Video1 plane does not support global alpha | |
237 | * to always make it 255 completely opaque | |
238 | */ | |
239 | if (ovl->id == OMAP_DSS_VIDEO1) | |
240 | info.global_alpha = 255; | |
241 | else | |
242 | info.global_alpha = simple_strtoul(buf, NULL, 10); | |
243 | ||
244 | r = ovl->set_overlay_info(ovl, &info); | |
245 | if (r) | |
246 | return r; | |
247 | ||
248 | if (ovl->manager) { | |
249 | r = ovl->manager->apply(ovl->manager); | |
250 | if (r) | |
251 | return r; | |
252 | } | |
253 | ||
254 | return size; | |
255 | } | |
256 | ||
257 | struct overlay_attribute { | |
258 | struct attribute attr; | |
259 | ssize_t (*show)(struct omap_overlay *, char *); | |
260 | ssize_t (*store)(struct omap_overlay *, const char *, size_t); | |
261 | }; | |
262 | ||
263 | #define OVERLAY_ATTR(_name, _mode, _show, _store) \ | |
264 | struct overlay_attribute overlay_attr_##_name = \ | |
265 | __ATTR(_name, _mode, _show, _store) | |
266 | ||
267 | static OVERLAY_ATTR(name, S_IRUGO, overlay_name_show, NULL); | |
268 | static OVERLAY_ATTR(manager, S_IRUGO|S_IWUSR, | |
269 | overlay_manager_show, overlay_manager_store); | |
270 | static OVERLAY_ATTR(input_size, S_IRUGO, overlay_input_size_show, NULL); | |
271 | static OVERLAY_ATTR(screen_width, S_IRUGO, overlay_screen_width_show, NULL); | |
272 | static OVERLAY_ATTR(position, S_IRUGO|S_IWUSR, | |
273 | overlay_position_show, overlay_position_store); | |
274 | static OVERLAY_ATTR(output_size, S_IRUGO|S_IWUSR, | |
275 | overlay_output_size_show, overlay_output_size_store); | |
276 | static OVERLAY_ATTR(enabled, S_IRUGO|S_IWUSR, | |
277 | overlay_enabled_show, overlay_enabled_store); | |
278 | static OVERLAY_ATTR(global_alpha, S_IRUGO|S_IWUSR, | |
279 | overlay_global_alpha_show, overlay_global_alpha_store); | |
280 | ||
281 | static struct attribute *overlay_sysfs_attrs[] = { | |
282 | &overlay_attr_name.attr, | |
283 | &overlay_attr_manager.attr, | |
284 | &overlay_attr_input_size.attr, | |
285 | &overlay_attr_screen_width.attr, | |
286 | &overlay_attr_position.attr, | |
287 | &overlay_attr_output_size.attr, | |
288 | &overlay_attr_enabled.attr, | |
289 | &overlay_attr_global_alpha.attr, | |
290 | NULL | |
291 | }; | |
292 | ||
293 | static ssize_t overlay_attr_show(struct kobject *kobj, struct attribute *attr, | |
294 | char *buf) | |
295 | { | |
296 | struct omap_overlay *overlay; | |
297 | struct overlay_attribute *overlay_attr; | |
298 | ||
299 | overlay = container_of(kobj, struct omap_overlay, kobj); | |
300 | overlay_attr = container_of(attr, struct overlay_attribute, attr); | |
301 | ||
302 | if (!overlay_attr->show) | |
303 | return -ENOENT; | |
304 | ||
305 | return overlay_attr->show(overlay, buf); | |
306 | } | |
307 | ||
308 | static ssize_t overlay_attr_store(struct kobject *kobj, struct attribute *attr, | |
309 | const char *buf, size_t size) | |
310 | { | |
311 | struct omap_overlay *overlay; | |
312 | struct overlay_attribute *overlay_attr; | |
313 | ||
314 | overlay = container_of(kobj, struct omap_overlay, kobj); | |
315 | overlay_attr = container_of(attr, struct overlay_attribute, attr); | |
316 | ||
317 | if (!overlay_attr->store) | |
318 | return -ENOENT; | |
319 | ||
320 | return overlay_attr->store(overlay, buf, size); | |
321 | } | |
322 | ||
52cf25d0 | 323 | static const struct sysfs_ops overlay_sysfs_ops = { |
eed07e0e TV |
324 | .show = overlay_attr_show, |
325 | .store = overlay_attr_store, | |
326 | }; | |
327 | ||
328 | static struct kobj_type overlay_ktype = { | |
329 | .sysfs_ops = &overlay_sysfs_ops, | |
330 | .default_attrs = overlay_sysfs_attrs, | |
331 | }; | |
332 | ||
333 | /* Check if overlay parameters are compatible with display */ | |
334 | int dss_check_overlay(struct omap_overlay *ovl, struct omap_dss_device *dssdev) | |
335 | { | |
336 | struct omap_overlay_info *info; | |
337 | u16 outw, outh; | |
338 | u16 dw, dh; | |
339 | ||
340 | if (!dssdev) | |
341 | return 0; | |
342 | ||
343 | if (!ovl->info.enabled) | |
344 | return 0; | |
345 | ||
346 | info = &ovl->info; | |
347 | ||
348 | if (info->paddr == 0) { | |
349 | DSSDBG("check_overlay failed: paddr 0\n"); | |
350 | return -EINVAL; | |
351 | } | |
352 | ||
96adcece | 353 | dssdev->driver->get_resolution(dssdev, &dw, &dh); |
eed07e0e TV |
354 | |
355 | DSSDBG("check_overlay %d: (%d,%d %dx%d -> %dx%d) disp (%dx%d)\n", | |
356 | ovl->id, | |
357 | info->pos_x, info->pos_y, | |
358 | info->width, info->height, | |
359 | info->out_width, info->out_height, | |
360 | dw, dh); | |
361 | ||
362 | if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0) { | |
363 | outw = info->width; | |
364 | outh = info->height; | |
365 | } else { | |
366 | if (info->out_width == 0) | |
367 | outw = info->width; | |
368 | else | |
369 | outw = info->out_width; | |
370 | ||
371 | if (info->out_height == 0) | |
372 | outh = info->height; | |
373 | else | |
374 | outh = info->out_height; | |
375 | } | |
376 | ||
377 | if (dw < info->pos_x + outw) { | |
378 | DSSDBG("check_overlay failed 1: %d < %d + %d\n", | |
379 | dw, info->pos_x, outw); | |
380 | return -EINVAL; | |
381 | } | |
382 | ||
383 | if (dh < info->pos_y + outh) { | |
384 | DSSDBG("check_overlay failed 2: %d < %d + %d\n", | |
385 | dh, info->pos_y, outh); | |
386 | return -EINVAL; | |
387 | } | |
388 | ||
389 | if ((ovl->supported_modes & info->color_mode) == 0) { | |
390 | DSSERR("overlay doesn't support mode %d\n", info->color_mode); | |
391 | return -EINVAL; | |
392 | } | |
393 | ||
394 | return 0; | |
395 | } | |
396 | ||
397 | static int dss_ovl_set_overlay_info(struct omap_overlay *ovl, | |
398 | struct omap_overlay_info *info) | |
399 | { | |
400 | int r; | |
401 | struct omap_overlay_info old_info; | |
402 | ||
403 | old_info = ovl->info; | |
404 | ovl->info = *info; | |
405 | ||
406 | if (ovl->manager) { | |
407 | r = dss_check_overlay(ovl, ovl->manager->device); | |
408 | if (r) { | |
409 | ovl->info = old_info; | |
410 | return r; | |
411 | } | |
412 | } | |
413 | ||
414 | ovl->info_dirty = true; | |
415 | ||
416 | return 0; | |
417 | } | |
418 | ||
419 | static void dss_ovl_get_overlay_info(struct omap_overlay *ovl, | |
420 | struct omap_overlay_info *info) | |
421 | { | |
422 | *info = ovl->info; | |
423 | } | |
424 | ||
425 | static int dss_ovl_wait_for_go(struct omap_overlay *ovl) | |
426 | { | |
427 | return dss_mgr_wait_for_go_ovl(ovl); | |
428 | } | |
429 | ||
430 | static int omap_dss_set_manager(struct omap_overlay *ovl, | |
431 | struct omap_overlay_manager *mgr) | |
432 | { | |
433 | if (!mgr) | |
434 | return -EINVAL; | |
435 | ||
436 | if (ovl->manager) { | |
437 | DSSERR("overlay '%s' already has a manager '%s'\n", | |
438 | ovl->name, ovl->manager->name); | |
439 | return -EINVAL; | |
440 | } | |
441 | ||
442 | if (ovl->info.enabled) { | |
443 | DSSERR("overlay has to be disabled to change the manager\n"); | |
444 | return -EINVAL; | |
445 | } | |
446 | ||
447 | ovl->manager = mgr; | |
448 | ||
449 | dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1); | |
450 | /* XXX: on manual update display, in auto update mode, a bug happens | |
451 | * here. When an overlay is first enabled on LCD, then it's disabled, | |
452 | * and the manager is changed to TV, we sometimes get SYNC_LOST_DIGIT | |
453 | * errors. Waiting before changing the channel_out fixes it. I'm | |
454 | * guessing that the overlay is still somehow being used for the LCD, | |
455 | * but I don't understand how or why. */ | |
456 | msleep(40); | |
457 | dispc_set_channel_out(ovl->id, mgr->id); | |
458 | dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1); | |
459 | ||
460 | return 0; | |
461 | } | |
462 | ||
463 | static int omap_dss_unset_manager(struct omap_overlay *ovl) | |
464 | { | |
465 | int r; | |
466 | ||
467 | if (!ovl->manager) { | |
468 | DSSERR("failed to detach overlay: manager not set\n"); | |
469 | return -EINVAL; | |
470 | } | |
471 | ||
472 | if (ovl->info.enabled) { | |
473 | DSSERR("overlay has to be disabled to unset the manager\n"); | |
474 | return -EINVAL; | |
475 | } | |
476 | ||
477 | r = ovl->wait_for_go(ovl); | |
478 | if (r) | |
479 | return r; | |
480 | ||
481 | ovl->manager = NULL; | |
482 | ||
483 | return 0; | |
484 | } | |
485 | ||
486 | int omap_dss_get_num_overlays(void) | |
487 | { | |
488 | return num_overlays; | |
489 | } | |
490 | EXPORT_SYMBOL(omap_dss_get_num_overlays); | |
491 | ||
492 | struct omap_overlay *omap_dss_get_overlay(int num) | |
493 | { | |
494 | int i = 0; | |
495 | struct omap_overlay *ovl; | |
496 | ||
497 | list_for_each_entry(ovl, &overlay_list, list) { | |
498 | if (i++ == num) | |
499 | return ovl; | |
500 | } | |
501 | ||
502 | return NULL; | |
503 | } | |
504 | EXPORT_SYMBOL(omap_dss_get_overlay); | |
505 | ||
506 | static void omap_dss_add_overlay(struct omap_overlay *overlay) | |
507 | { | |
508 | ++num_overlays; | |
509 | list_add_tail(&overlay->list, &overlay_list); | |
510 | } | |
511 | ||
512 | static struct omap_overlay *dispc_overlays[3]; | |
513 | ||
514 | void dss_overlay_setup_dispc_manager(struct omap_overlay_manager *mgr) | |
515 | { | |
516 | mgr->num_overlays = 3; | |
517 | mgr->overlays = dispc_overlays; | |
518 | } | |
519 | ||
520 | #ifdef L4_EXAMPLE | |
521 | static struct omap_overlay *l4_overlays[1]; | |
522 | void dss_overlay_setup_l4_manager(struct omap_overlay_manager *mgr) | |
523 | { | |
524 | mgr->num_overlays = 1; | |
525 | mgr->overlays = l4_overlays; | |
526 | } | |
527 | #endif | |
528 | ||
529 | void dss_init_overlays(struct platform_device *pdev) | |
530 | { | |
531 | int i, r; | |
532 | ||
533 | INIT_LIST_HEAD(&overlay_list); | |
534 | ||
535 | num_overlays = 0; | |
536 | ||
537 | for (i = 0; i < 3; ++i) { | |
538 | struct omap_overlay *ovl; | |
539 | ovl = kzalloc(sizeof(*ovl), GFP_KERNEL); | |
540 | ||
541 | BUG_ON(ovl == NULL); | |
542 | ||
543 | switch (i) { | |
544 | case 0: | |
545 | ovl->name = "gfx"; | |
546 | ovl->id = OMAP_DSS_GFX; | |
547 | ovl->supported_modes = cpu_is_omap34xx() ? | |
548 | OMAP_DSS_COLOR_GFX_OMAP3 : | |
549 | OMAP_DSS_COLOR_GFX_OMAP2; | |
550 | ovl->caps = OMAP_DSS_OVL_CAP_DISPC; | |
551 | ovl->info.global_alpha = 255; | |
552 | break; | |
553 | case 1: | |
554 | ovl->name = "vid1"; | |
555 | ovl->id = OMAP_DSS_VIDEO1; | |
556 | ovl->supported_modes = cpu_is_omap34xx() ? | |
557 | OMAP_DSS_COLOR_VID1_OMAP3 : | |
558 | OMAP_DSS_COLOR_VID_OMAP2; | |
559 | ovl->caps = OMAP_DSS_OVL_CAP_SCALE | | |
560 | OMAP_DSS_OVL_CAP_DISPC; | |
561 | ovl->info.global_alpha = 255; | |
562 | break; | |
563 | case 2: | |
564 | ovl->name = "vid2"; | |
565 | ovl->id = OMAP_DSS_VIDEO2; | |
566 | ovl->supported_modes = cpu_is_omap34xx() ? | |
567 | OMAP_DSS_COLOR_VID2_OMAP3 : | |
568 | OMAP_DSS_COLOR_VID_OMAP2; | |
569 | ovl->caps = OMAP_DSS_OVL_CAP_SCALE | | |
570 | OMAP_DSS_OVL_CAP_DISPC; | |
571 | ovl->info.global_alpha = 255; | |
572 | break; | |
573 | } | |
574 | ||
575 | ovl->set_manager = &omap_dss_set_manager; | |
576 | ovl->unset_manager = &omap_dss_unset_manager; | |
577 | ovl->set_overlay_info = &dss_ovl_set_overlay_info; | |
578 | ovl->get_overlay_info = &dss_ovl_get_overlay_info; | |
579 | ovl->wait_for_go = &dss_ovl_wait_for_go; | |
580 | ||
581 | omap_dss_add_overlay(ovl); | |
582 | ||
583 | r = kobject_init_and_add(&ovl->kobj, &overlay_ktype, | |
584 | &pdev->dev.kobj, "overlay%d", i); | |
585 | ||
586 | if (r) { | |
587 | DSSERR("failed to create sysfs file\n"); | |
588 | continue; | |
589 | } | |
590 | ||
591 | dispc_overlays[i] = ovl; | |
592 | } | |
593 | ||
594 | #ifdef L4_EXAMPLE | |
595 | { | |
596 | struct omap_overlay *ovl; | |
597 | ovl = kzalloc(sizeof(*ovl), GFP_KERNEL); | |
598 | ||
599 | BUG_ON(ovl == NULL); | |
600 | ||
601 | ovl->name = "l4"; | |
602 | ovl->supported_modes = OMAP_DSS_COLOR_RGB24U; | |
603 | ||
604 | ovl->set_manager = &omap_dss_set_manager; | |
605 | ovl->unset_manager = &omap_dss_unset_manager; | |
606 | ovl->set_overlay_info = &dss_ovl_set_overlay_info; | |
607 | ovl->get_overlay_info = &dss_ovl_get_overlay_info; | |
608 | ||
609 | omap_dss_add_overlay(ovl); | |
610 | ||
611 | r = kobject_init_and_add(&ovl->kobj, &overlay_ktype, | |
612 | &pdev->dev.kobj, "overlayl4"); | |
613 | ||
614 | if (r) | |
615 | DSSERR("failed to create sysfs file\n"); | |
616 | ||
617 | l4_overlays[0] = ovl; | |
618 | } | |
619 | #endif | |
620 | } | |
621 | ||
622 | /* connect overlays to the new device, if not already connected. if force | |
623 | * selected, connect always. */ | |
624 | void dss_recheck_connections(struct omap_dss_device *dssdev, bool force) | |
625 | { | |
626 | int i; | |
627 | struct omap_overlay_manager *lcd_mgr; | |
628 | struct omap_overlay_manager *tv_mgr; | |
629 | struct omap_overlay_manager *mgr = NULL; | |
630 | ||
631 | lcd_mgr = omap_dss_get_overlay_manager(OMAP_DSS_OVL_MGR_LCD); | |
632 | tv_mgr = omap_dss_get_overlay_manager(OMAP_DSS_OVL_MGR_TV); | |
633 | ||
634 | if (dssdev->type != OMAP_DISPLAY_TYPE_VENC) { | |
635 | if (!lcd_mgr->device || force) { | |
636 | if (lcd_mgr->device) | |
637 | lcd_mgr->unset_device(lcd_mgr); | |
638 | lcd_mgr->set_device(lcd_mgr, dssdev); | |
639 | mgr = lcd_mgr; | |
640 | } | |
641 | } | |
642 | ||
643 | if (dssdev->type == OMAP_DISPLAY_TYPE_VENC) { | |
644 | if (!tv_mgr->device || force) { | |
645 | if (tv_mgr->device) | |
646 | tv_mgr->unset_device(tv_mgr); | |
647 | tv_mgr->set_device(tv_mgr, dssdev); | |
648 | mgr = tv_mgr; | |
649 | } | |
650 | } | |
651 | ||
652 | if (mgr) { | |
653 | for (i = 0; i < 3; i++) { | |
654 | struct omap_overlay *ovl; | |
655 | ovl = omap_dss_get_overlay(i); | |
656 | if (!ovl->manager || force) { | |
657 | if (ovl->manager) | |
658 | omap_dss_unset_manager(ovl); | |
659 | omap_dss_set_manager(ovl, mgr); | |
660 | } | |
661 | } | |
662 | } | |
663 | } | |
664 | ||
665 | void dss_uninit_overlays(struct platform_device *pdev) | |
666 | { | |
667 | struct omap_overlay *ovl; | |
668 | ||
669 | while (!list_empty(&overlay_list)) { | |
670 | ovl = list_first_entry(&overlay_list, | |
671 | struct omap_overlay, list); | |
672 | list_del(&ovl->list); | |
673 | kobject_del(&ovl->kobj); | |
674 | kobject_put(&ovl->kobj); | |
675 | kfree(ovl); | |
676 | } | |
677 | ||
678 | num_overlays = 0; | |
679 | } | |
680 |