Commit | Line | Data |
---|---|---|
58f25548 TV |
1 | /* |
2 | * Copyright (C) 2011 Texas Instruments | |
3 | * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> | |
4 | * | |
5 | * This program is free software; you can redistribute it and/or modify it | |
6 | * under the terms of the GNU General Public License version 2 as published by | |
7 | * the Free Software Foundation. | |
8 | * | |
9 | * This program is distributed in the hope that it will be useful, but WITHOUT | |
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
12 | * more details. | |
13 | * | |
14 | * You should have received a copy of the GNU General Public License along with | |
15 | * this program. If not, see <http://www.gnu.org/licenses/>. | |
16 | */ | |
17 | ||
18 | #define DSS_SUBSYS_NAME "APPLY" | |
19 | ||
20 | #include <linux/kernel.h> | |
8dd2491a | 21 | #include <linux/module.h> |
58f25548 TV |
22 | #include <linux/slab.h> |
23 | #include <linux/spinlock.h> | |
24 | #include <linux/jiffies.h> | |
25 | ||
26 | #include <video/omapdss.h> | |
27 | ||
28 | #include "dss.h" | |
29 | #include "dss_features.h" | |
bb398134 | 30 | #include "dispc-compat.h" |
58f25548 TV |
31 | |
32 | /* | |
33 | * We have 4 levels of cache for the dispc settings. First two are in SW and | |
34 | * the latter two in HW. | |
35 | * | |
0b53f179 TV |
36 | * set_info() |
37 | * v | |
58f25548 | 38 | * +--------------------+ |
0b53f179 | 39 | * | user_info | |
58f25548 TV |
40 | * +--------------------+ |
41 | * v | |
42 | * apply() | |
43 | * v | |
44 | * +--------------------+ | |
d09c7aa8 | 45 | * | info | |
58f25548 TV |
46 | * +--------------------+ |
47 | * v | |
f6a5e087 | 48 | * write_regs() |
58f25548 TV |
49 | * v |
50 | * +--------------------+ | |
51 | * | shadow registers | | |
52 | * +--------------------+ | |
53 | * v | |
54 | * VFP or lcd/digit_enable | |
55 | * v | |
56 | * +--------------------+ | |
57 | * | registers | | |
58 | * +--------------------+ | |
59 | */ | |
60 | ||
c10c6f04 | 61 | struct ovl_priv_data { |
c1a9febf TV |
62 | |
63 | bool user_info_dirty; | |
64 | struct omap_overlay_info user_info; | |
65 | ||
0b53f179 | 66 | bool info_dirty; |
58f25548 TV |
67 | struct omap_overlay_info info; |
68 | ||
0b53f179 TV |
69 | bool shadow_info_dirty; |
70 | ||
aaa874a9 TV |
71 | bool extra_info_dirty; |
72 | bool shadow_extra_info_dirty; | |
73 | ||
74 | bool enabled; | |
6dc802e2 | 75 | u32 fifo_low, fifo_high; |
82153eda TV |
76 | |
77 | /* | |
78 | * True if overlay is to be enabled. Used to check and calculate configs | |
79 | * for the overlay before it is enabled in the HW. | |
80 | */ | |
81 | bool enabling; | |
58f25548 TV |
82 | }; |
83 | ||
af3d64b2 | 84 | struct mgr_priv_data { |
388c4c6c TV |
85 | |
86 | bool user_info_dirty; | |
87 | struct omap_overlay_manager_info user_info; | |
88 | ||
0b53f179 | 89 | bool info_dirty; |
58f25548 TV |
90 | struct omap_overlay_manager_info info; |
91 | ||
0b53f179 TV |
92 | bool shadow_info_dirty; |
93 | ||
43a972d9 TV |
94 | /* If true, GO bit is up and shadow registers cannot be written. |
95 | * Never true for manual update displays */ | |
96 | bool busy; | |
97 | ||
34861378 TV |
98 | /* If true, dispc output is enabled */ |
99 | bool updating; | |
100 | ||
bf213523 TV |
101 | /* If true, a display is enabled using this manager */ |
102 | bool enabled; | |
45324a26 AT |
103 | |
104 | bool extra_info_dirty; | |
105 | bool shadow_extra_info_dirty; | |
106 | ||
107 | struct omap_video_timings timings; | |
f476ae9d | 108 | struct dss_lcd_mgr_config lcd_config; |
1550202d TV |
109 | |
110 | void (*framedone_handler)(void *); | |
111 | void *framedone_handler_data; | |
58f25548 TV |
112 | }; |
113 | ||
114 | static struct { | |
c10c6f04 | 115 | struct ovl_priv_data ovl_priv_data_array[MAX_DSS_OVERLAYS]; |
af3d64b2 | 116 | struct mgr_priv_data mgr_priv_data_array[MAX_DSS_MANAGERS]; |
58f25548 TV |
117 | |
118 | bool irq_enabled; | |
d09c7aa8 | 119 | } dss_data; |
58f25548 | 120 | |
d09c7aa8 | 121 | /* protects dss_data */ |
063fd701 | 122 | static spinlock_t data_lock; |
5558db3f TV |
123 | /* lock for blocking functions */ |
124 | static DEFINE_MUTEX(apply_lock); | |
f1577ce1 | 125 | static DECLARE_COMPLETION(extra_updated_completion); |
063fd701 | 126 | |
75c94965 TV |
127 | static void dss_register_vsync_isr(void); |
128 | ||
c10c6f04 TV |
129 | static struct ovl_priv_data *get_ovl_priv(struct omap_overlay *ovl) |
130 | { | |
d09c7aa8 | 131 | return &dss_data.ovl_priv_data_array[ovl->id]; |
c10c6f04 TV |
132 | } |
133 | ||
af3d64b2 TV |
134 | static struct mgr_priv_data *get_mgr_priv(struct omap_overlay_manager *mgr) |
135 | { | |
d09c7aa8 | 136 | return &dss_data.mgr_priv_data_array[mgr->id]; |
af3d64b2 TV |
137 | } |
138 | ||
8dd2491a | 139 | static void apply_init_priv(void) |
58f25548 | 140 | { |
c1a9febf | 141 | const int num_ovls = dss_feat_get_num_ovls(); |
f476ae9d | 142 | struct mgr_priv_data *mp; |
c1a9febf TV |
143 | int i; |
144 | ||
063fd701 | 145 | spin_lock_init(&data_lock); |
c1a9febf TV |
146 | |
147 | for (i = 0; i < num_ovls; ++i) { | |
148 | struct ovl_priv_data *op; | |
149 | ||
150 | op = &dss_data.ovl_priv_data_array[i]; | |
151 | ||
7a53df2c TV |
152 | op->info.color_mode = OMAP_DSS_COLOR_RGB16; |
153 | op->info.rotation_type = OMAP_DSS_ROT_DMA; | |
154 | ||
c1a9febf TV |
155 | op->info.global_alpha = 255; |
156 | ||
157 | switch (i) { | |
158 | case 0: | |
159 | op->info.zorder = 0; | |
160 | break; | |
161 | case 1: | |
162 | op->info.zorder = | |
163 | dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 3 : 0; | |
164 | break; | |
165 | case 2: | |
166 | op->info.zorder = | |
167 | dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 2 : 0; | |
168 | break; | |
169 | case 3: | |
170 | op->info.zorder = | |
171 | dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 1 : 0; | |
172 | break; | |
173 | } | |
174 | ||
175 | op->user_info = op->info; | |
176 | } | |
f476ae9d AT |
177 | |
178 | /* | |
179 | * Initialize some of the lcd_config fields for TV manager, this lets | |
180 | * us prevent checking if the manager is LCD or TV at some places | |
181 | */ | |
182 | mp = &dss_data.mgr_priv_data_array[OMAP_DSS_CHANNEL_DIGIT]; | |
183 | ||
184 | mp->lcd_config.video_port_width = 24; | |
185 | mp->lcd_config.clock_info.lck_div = 1; | |
186 | mp->lcd_config.clock_info.pck_div = 1; | |
58f25548 TV |
187 | } |
188 | ||
75bac5d1 AT |
189 | /* |
190 | * A LCD manager's stallmode decides whether it is in manual or auto update. TV | |
191 | * manager is always auto update, stallmode field for TV manager is false by | |
192 | * default | |
193 | */ | |
58f25548 TV |
194 | static bool ovl_manual_update(struct omap_overlay *ovl) |
195 | { | |
75bac5d1 AT |
196 | struct mgr_priv_data *mp = get_mgr_priv(ovl->manager); |
197 | ||
198 | return mp->lcd_config.stallmode; | |
58f25548 TV |
199 | } |
200 | ||
201 | static bool mgr_manual_update(struct omap_overlay_manager *mgr) | |
202 | { | |
75bac5d1 AT |
203 | struct mgr_priv_data *mp = get_mgr_priv(mgr); |
204 | ||
205 | return mp->lcd_config.stallmode; | |
58f25548 TV |
206 | } |
207 | ||
39518356 | 208 | static int dss_check_settings_low(struct omap_overlay_manager *mgr, |
228b2134 | 209 | bool applying) |
39518356 TV |
210 | { |
211 | struct omap_overlay_info *oi; | |
212 | struct omap_overlay_manager_info *mi; | |
213 | struct omap_overlay *ovl; | |
214 | struct omap_overlay_info *ois[MAX_DSS_OVERLAYS]; | |
215 | struct ovl_priv_data *op; | |
216 | struct mgr_priv_data *mp; | |
217 | ||
218 | mp = get_mgr_priv(mgr); | |
219 | ||
5dd747e8 AT |
220 | if (!mp->enabled) |
221 | return 0; | |
222 | ||
39518356 TV |
223 | if (applying && mp->user_info_dirty) |
224 | mi = &mp->user_info; | |
225 | else | |
226 | mi = &mp->info; | |
227 | ||
228 | /* collect the infos to be tested into the array */ | |
229 | list_for_each_entry(ovl, &mgr->overlays, list) { | |
230 | op = get_ovl_priv(ovl); | |
231 | ||
82153eda | 232 | if (!op->enabled && !op->enabling) |
39518356 TV |
233 | oi = NULL; |
234 | else if (applying && op->user_info_dirty) | |
235 | oi = &op->user_info; | |
236 | else | |
237 | oi = &op->info; | |
238 | ||
239 | ois[ovl->id] = oi; | |
240 | } | |
241 | ||
6e543595 | 242 | return dss_mgr_check(mgr, mi, &mp->timings, &mp->lcd_config, ois); |
39518356 TV |
243 | } |
244 | ||
245 | /* | |
246 | * check manager and overlay settings using overlay_info from data->info | |
247 | */ | |
228b2134 | 248 | static int dss_check_settings(struct omap_overlay_manager *mgr) |
39518356 | 249 | { |
228b2134 | 250 | return dss_check_settings_low(mgr, false); |
39518356 TV |
251 | } |
252 | ||
253 | /* | |
254 | * check manager and overlay settings using overlay_info from ovl->info if | |
255 | * dirty and from data->info otherwise | |
256 | */ | |
228b2134 | 257 | static int dss_check_settings_apply(struct omap_overlay_manager *mgr) |
39518356 | 258 | { |
228b2134 | 259 | return dss_check_settings_low(mgr, true); |
39518356 TV |
260 | } |
261 | ||
75c94965 TV |
262 | static bool need_isr(void) |
263 | { | |
264 | const int num_mgrs = dss_feat_get_num_mgrs(); | |
265 | int i; | |
266 | ||
267 | for (i = 0; i < num_mgrs; ++i) { | |
268 | struct omap_overlay_manager *mgr; | |
269 | struct mgr_priv_data *mp; | |
270 | struct omap_overlay *ovl; | |
271 | ||
272 | mgr = omap_dss_get_overlay_manager(i); | |
273 | mp = get_mgr_priv(mgr); | |
274 | ||
275 | if (!mp->enabled) | |
276 | continue; | |
277 | ||
34861378 TV |
278 | if (mgr_manual_update(mgr)) { |
279 | /* to catch FRAMEDONE */ | |
280 | if (mp->updating) | |
281 | return true; | |
282 | } else { | |
283 | /* to catch GO bit going down */ | |
284 | if (mp->busy) | |
285 | return true; | |
75c94965 | 286 | |
34861378 | 287 | /* to write new values to registers */ |
0b53f179 | 288 | if (mp->info_dirty) |
34861378 | 289 | return true; |
75c94965 | 290 | |
9f808956 TV |
291 | /* to set GO bit */ |
292 | if (mp->shadow_info_dirty) | |
293 | return true; | |
294 | ||
45324a26 AT |
295 | /* |
296 | * NOTE: we don't check extra_info flags for disabled | |
297 | * managers, once the manager is enabled, the extra_info | |
298 | * related manager changes will be taken in by HW. | |
299 | */ | |
300 | ||
301 | /* to write new values to registers */ | |
302 | if (mp->extra_info_dirty) | |
303 | return true; | |
304 | ||
305 | /* to set GO bit */ | |
306 | if (mp->shadow_extra_info_dirty) | |
307 | return true; | |
308 | ||
34861378 TV |
309 | list_for_each_entry(ovl, &mgr->overlays, list) { |
310 | struct ovl_priv_data *op; | |
75c94965 | 311 | |
34861378 | 312 | op = get_ovl_priv(ovl); |
75c94965 | 313 | |
9f808956 TV |
314 | /* |
315 | * NOTE: we check extra_info flags even for | |
316 | * disabled overlays, as extra_infos need to be | |
317 | * always written. | |
318 | */ | |
319 | ||
320 | /* to write new values to registers */ | |
321 | if (op->extra_info_dirty) | |
322 | return true; | |
323 | ||
324 | /* to set GO bit */ | |
325 | if (op->shadow_extra_info_dirty) | |
326 | return true; | |
327 | ||
34861378 TV |
328 | if (!op->enabled) |
329 | continue; | |
75c94965 | 330 | |
34861378 | 331 | /* to write new values to registers */ |
9f808956 TV |
332 | if (op->info_dirty) |
333 | return true; | |
334 | ||
335 | /* to set GO bit */ | |
336 | if (op->shadow_info_dirty) | |
34861378 TV |
337 | return true; |
338 | } | |
75c94965 TV |
339 | } |
340 | } | |
341 | ||
342 | return false; | |
343 | } | |
344 | ||
345 | static bool need_go(struct omap_overlay_manager *mgr) | |
346 | { | |
347 | struct omap_overlay *ovl; | |
348 | struct mgr_priv_data *mp; | |
349 | struct ovl_priv_data *op; | |
350 | ||
351 | mp = get_mgr_priv(mgr); | |
352 | ||
45324a26 | 353 | if (mp->shadow_info_dirty || mp->shadow_extra_info_dirty) |
75c94965 TV |
354 | return true; |
355 | ||
356 | list_for_each_entry(ovl, &mgr->overlays, list) { | |
357 | op = get_ovl_priv(ovl); | |
0b53f179 | 358 | if (op->shadow_info_dirty || op->shadow_extra_info_dirty) |
75c94965 TV |
359 | return true; |
360 | } | |
361 | ||
362 | return false; | |
363 | } | |
364 | ||
f1577ce1 TV |
365 | /* returns true if an extra_info field is currently being updated */ |
366 | static bool extra_info_update_ongoing(void) | |
367 | { | |
45324a26 | 368 | const int num_mgrs = dss_feat_get_num_mgrs(); |
f1577ce1 | 369 | int i; |
f1577ce1 | 370 | |
45324a26 AT |
371 | for (i = 0; i < num_mgrs; ++i) { |
372 | struct omap_overlay_manager *mgr; | |
373 | struct omap_overlay *ovl; | |
374 | struct mgr_priv_data *mp; | |
1f3f53ae | 375 | |
45324a26 AT |
376 | mgr = omap_dss_get_overlay_manager(i); |
377 | mp = get_mgr_priv(mgr); | |
f1577ce1 TV |
378 | |
379 | if (!mp->enabled) | |
380 | continue; | |
381 | ||
153b6e73 | 382 | if (!mp->updating) |
f1577ce1 TV |
383 | continue; |
384 | ||
45324a26 | 385 | if (mp->extra_info_dirty || mp->shadow_extra_info_dirty) |
153b6e73 | 386 | return true; |
45324a26 AT |
387 | |
388 | list_for_each_entry(ovl, &mgr->overlays, list) { | |
389 | struct ovl_priv_data *op = get_ovl_priv(ovl); | |
390 | ||
391 | if (op->extra_info_dirty || op->shadow_extra_info_dirty) | |
392 | return true; | |
393 | } | |
f1577ce1 TV |
394 | } |
395 | ||
396 | return false; | |
397 | } | |
398 | ||
399 | /* wait until no extra_info updates are pending */ | |
400 | static void wait_pending_extra_info_updates(void) | |
401 | { | |
402 | bool updating; | |
403 | unsigned long flags; | |
404 | unsigned long t; | |
4614679c | 405 | int r; |
f1577ce1 TV |
406 | |
407 | spin_lock_irqsave(&data_lock, flags); | |
408 | ||
409 | updating = extra_info_update_ongoing(); | |
410 | ||
411 | if (!updating) { | |
412 | spin_unlock_irqrestore(&data_lock, flags); | |
413 | return; | |
414 | } | |
415 | ||
416 | init_completion(&extra_updated_completion); | |
417 | ||
418 | spin_unlock_irqrestore(&data_lock, flags); | |
419 | ||
420 | t = msecs_to_jiffies(500); | |
4614679c TV |
421 | r = wait_for_completion_timeout(&extra_updated_completion, t); |
422 | if (r == 0) | |
423 | DSSWARN("timeout in wait_pending_extra_info_updates\n"); | |
f1577ce1 TV |
424 | } |
425 | ||
e7243664 | 426 | static struct omap_dss_device *dss_mgr_get_device(struct omap_overlay_manager *mgr) |
6abae7a1 | 427 | { |
efedce14 TV |
428 | struct omap_dss_device *dssdev; |
429 | ||
430 | dssdev = mgr->output; | |
431 | if (dssdev == NULL) | |
432 | return NULL; | |
433 | ||
9560dc10 TV |
434 | while (dssdev->dst) |
435 | dssdev = dssdev->dst; | |
efedce14 TV |
436 | |
437 | if (dssdev->driver) | |
438 | return dssdev; | |
439 | else | |
440 | return NULL; | |
6abae7a1 TV |
441 | } |
442 | ||
e7243664 | 443 | static struct omap_dss_device *dss_ovl_get_device(struct omap_overlay *ovl) |
0c49ff74 | 444 | { |
e7243664 | 445 | return ovl->manager ? dss_mgr_get_device(ovl->manager) : NULL; |
0c49ff74 TV |
446 | } |
447 | ||
448 | static int dss_mgr_wait_for_vsync(struct omap_overlay_manager *mgr) | |
449 | { | |
450 | unsigned long timeout = msecs_to_jiffies(500); | |
0c49ff74 TV |
451 | u32 irq; |
452 | int r; | |
453 | ||
346f1e07 TV |
454 | if (mgr->output == NULL) |
455 | return -ENODEV; | |
456 | ||
0c49ff74 TV |
457 | r = dispc_runtime_get(); |
458 | if (r) | |
459 | return r; | |
460 | ||
346f1e07 TV |
461 | switch (mgr->output->id) { |
462 | case OMAP_DSS_OUTPUT_VENC: | |
0c49ff74 | 463 | irq = DISPC_IRQ_EVSYNC_ODD; |
346f1e07 TV |
464 | break; |
465 | case OMAP_DSS_OUTPUT_HDMI: | |
0c49ff74 | 466 | irq = DISPC_IRQ_EVSYNC_EVEN; |
346f1e07 TV |
467 | break; |
468 | default: | |
0c49ff74 | 469 | irq = dispc_mgr_get_vsync_irq(mgr->id); |
346f1e07 TV |
470 | break; |
471 | } | |
0c49ff74 TV |
472 | |
473 | r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout); | |
474 | ||
475 | dispc_runtime_put(); | |
476 | ||
477 | return r; | |
478 | } | |
479 | ||
480 | static int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr) | |
58f25548 TV |
481 | { |
482 | unsigned long timeout = msecs_to_jiffies(500); | |
fc22a843 | 483 | struct mgr_priv_data *mp = get_mgr_priv(mgr); |
58f25548 | 484 | u32 irq; |
fc22a843 | 485 | unsigned long flags; |
58f25548 TV |
486 | int r; |
487 | int i; | |
58f25548 | 488 | |
fc22a843 AT |
489 | spin_lock_irqsave(&data_lock, flags); |
490 | ||
491 | if (mgr_manual_update(mgr)) { | |
492 | spin_unlock_irqrestore(&data_lock, flags); | |
58f25548 | 493 | return 0; |
fc22a843 | 494 | } |
58f25548 | 495 | |
fc22a843 AT |
496 | if (!mp->enabled) { |
497 | spin_unlock_irqrestore(&data_lock, flags); | |
58f25548 | 498 | return 0; |
fc22a843 AT |
499 | } |
500 | ||
501 | spin_unlock_irqrestore(&data_lock, flags); | |
58f25548 | 502 | |
21e56f79 LM |
503 | r = dispc_runtime_get(); |
504 | if (r) | |
505 | return r; | |
506 | ||
bc1a9518 | 507 | irq = dispc_mgr_get_vsync_irq(mgr->id); |
58f25548 | 508 | |
58f25548 TV |
509 | i = 0; |
510 | while (1) { | |
58f25548 TV |
511 | bool shadow_dirty, dirty; |
512 | ||
063fd701 | 513 | spin_lock_irqsave(&data_lock, flags); |
0b53f179 TV |
514 | dirty = mp->info_dirty; |
515 | shadow_dirty = mp->shadow_info_dirty; | |
063fd701 | 516 | spin_unlock_irqrestore(&data_lock, flags); |
58f25548 TV |
517 | |
518 | if (!dirty && !shadow_dirty) { | |
519 | r = 0; | |
520 | break; | |
521 | } | |
522 | ||
523 | /* 4 iterations is the worst case: | |
524 | * 1 - initial iteration, dirty = true (between VFP and VSYNC) | |
525 | * 2 - first VSYNC, dirty = true | |
526 | * 3 - dirty = false, shadow_dirty = true | |
527 | * 4 - shadow_dirty = false */ | |
528 | if (i++ == 3) { | |
529 | DSSERR("mgr(%d)->wait_for_go() not finishing\n", | |
530 | mgr->id); | |
531 | r = 0; | |
532 | break; | |
533 | } | |
534 | ||
535 | r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout); | |
536 | if (r == -ERESTARTSYS) | |
537 | break; | |
538 | ||
539 | if (r) { | |
540 | DSSERR("mgr(%d)->wait_for_go() timeout\n", mgr->id); | |
541 | break; | |
542 | } | |
543 | } | |
544 | ||
21e56f79 LM |
545 | dispc_runtime_put(); |
546 | ||
58f25548 TV |
547 | return r; |
548 | } | |
549 | ||
6abae7a1 | 550 | static int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl) |
58f25548 TV |
551 | { |
552 | unsigned long timeout = msecs_to_jiffies(500); | |
c10c6f04 | 553 | struct ovl_priv_data *op; |
fc22a843 | 554 | struct mgr_priv_data *mp; |
58f25548 | 555 | u32 irq; |
fc22a843 | 556 | unsigned long flags; |
58f25548 TV |
557 | int r; |
558 | int i; | |
559 | ||
560 | if (!ovl->manager) | |
561 | return 0; | |
562 | ||
fc22a843 | 563 | mp = get_mgr_priv(ovl->manager); |
58f25548 | 564 | |
fc22a843 AT |
565 | spin_lock_irqsave(&data_lock, flags); |
566 | ||
567 | if (ovl_manual_update(ovl)) { | |
568 | spin_unlock_irqrestore(&data_lock, flags); | |
58f25548 | 569 | return 0; |
fc22a843 | 570 | } |
58f25548 | 571 | |
fc22a843 AT |
572 | if (!mp->enabled) { |
573 | spin_unlock_irqrestore(&data_lock, flags); | |
58f25548 | 574 | return 0; |
fc22a843 AT |
575 | } |
576 | ||
577 | spin_unlock_irqrestore(&data_lock, flags); | |
58f25548 | 578 | |
21e56f79 LM |
579 | r = dispc_runtime_get(); |
580 | if (r) | |
581 | return r; | |
582 | ||
bc1a9518 | 583 | irq = dispc_mgr_get_vsync_irq(ovl->manager->id); |
58f25548 | 584 | |
c10c6f04 | 585 | op = get_ovl_priv(ovl); |
58f25548 TV |
586 | i = 0; |
587 | while (1) { | |
58f25548 TV |
588 | bool shadow_dirty, dirty; |
589 | ||
063fd701 | 590 | spin_lock_irqsave(&data_lock, flags); |
0b53f179 TV |
591 | dirty = op->info_dirty; |
592 | shadow_dirty = op->shadow_info_dirty; | |
063fd701 | 593 | spin_unlock_irqrestore(&data_lock, flags); |
58f25548 TV |
594 | |
595 | if (!dirty && !shadow_dirty) { | |
596 | r = 0; | |
597 | break; | |
598 | } | |
599 | ||
600 | /* 4 iterations is the worst case: | |
601 | * 1 - initial iteration, dirty = true (between VFP and VSYNC) | |
602 | * 2 - first VSYNC, dirty = true | |
603 | * 3 - dirty = false, shadow_dirty = true | |
604 | * 4 - shadow_dirty = false */ | |
605 | if (i++ == 3) { | |
606 | DSSERR("ovl(%d)->wait_for_go() not finishing\n", | |
607 | ovl->id); | |
608 | r = 0; | |
609 | break; | |
610 | } | |
611 | ||
612 | r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout); | |
613 | if (r == -ERESTARTSYS) | |
614 | break; | |
615 | ||
616 | if (r) { | |
617 | DSSERR("ovl(%d)->wait_for_go() timeout\n", ovl->id); | |
618 | break; | |
619 | } | |
620 | } | |
621 | ||
21e56f79 LM |
622 | dispc_runtime_put(); |
623 | ||
58f25548 TV |
624 | return r; |
625 | } | |
626 | ||
75c94965 | 627 | static void dss_ovl_write_regs(struct omap_overlay *ovl) |
58f25548 | 628 | { |
75c94965 | 629 | struct ovl_priv_data *op = get_ovl_priv(ovl); |
58f25548 | 630 | struct omap_overlay_info *oi; |
8050cbe4 | 631 | bool replication; |
34861378 | 632 | struct mgr_priv_data *mp; |
58f25548 TV |
633 | int r; |
634 | ||
ac9f2421 | 635 | DSSDBG("writing ovl %d regs\n", ovl->id); |
58f25548 | 636 | |
0b53f179 | 637 | if (!op->enabled || !op->info_dirty) |
75c94965 | 638 | return; |
58f25548 | 639 | |
75c94965 | 640 | oi = &op->info; |
58f25548 | 641 | |
81ab95b7 AT |
642 | mp = get_mgr_priv(ovl->manager); |
643 | ||
6c6f510a | 644 | replication = dss_ovl_use_replication(mp->lcd_config, oi->color_mode); |
58f25548 | 645 | |
8ba85306 | 646 | r = dispc_ovl_setup(ovl->id, oi, replication, &mp->timings, false); |
58f25548 | 647 | if (r) { |
75c94965 TV |
648 | /* |
649 | * We can't do much here, as this function can be called from | |
650 | * vsync interrupt. | |
651 | */ | |
f6a5e087 | 652 | DSSERR("dispc_ovl_setup failed for ovl %d\n", ovl->id); |
75c94965 TV |
653 | |
654 | /* This will leave fifo configurations in a nonoptimal state */ | |
655 | op->enabled = false; | |
656 | dispc_ovl_enable(ovl->id, false); | |
657 | return; | |
58f25548 TV |
658 | } |
659 | ||
0b53f179 | 660 | op->info_dirty = false; |
34861378 | 661 | if (mp->updating) |
0b53f179 | 662 | op->shadow_info_dirty = true; |
58f25548 TV |
663 | } |
664 | ||
aaa874a9 TV |
665 | static void dss_ovl_write_regs_extra(struct omap_overlay *ovl) |
666 | { | |
667 | struct ovl_priv_data *op = get_ovl_priv(ovl); | |
34861378 | 668 | struct mgr_priv_data *mp; |
aaa874a9 | 669 | |
ac9f2421 | 670 | DSSDBG("writing ovl %d regs extra\n", ovl->id); |
aaa874a9 | 671 | |
75c94965 TV |
672 | if (!op->extra_info_dirty) |
673 | return; | |
674 | ||
aaa874a9 TV |
675 | /* note: write also when op->enabled == false, so that the ovl gets |
676 | * disabled */ | |
677 | ||
678 | dispc_ovl_enable(ovl->id, op->enabled); | |
6dc802e2 | 679 | dispc_ovl_set_fifo_threshold(ovl->id, op->fifo_low, op->fifo_high); |
75c94965 | 680 | |
34861378 TV |
681 | mp = get_mgr_priv(ovl->manager); |
682 | ||
75c94965 | 683 | op->extra_info_dirty = false; |
34861378 TV |
684 | if (mp->updating) |
685 | op->shadow_extra_info_dirty = true; | |
aaa874a9 TV |
686 | } |
687 | ||
f6a5e087 | 688 | static void dss_mgr_write_regs(struct omap_overlay_manager *mgr) |
58f25548 | 689 | { |
75c94965 TV |
690 | struct mgr_priv_data *mp = get_mgr_priv(mgr); |
691 | struct omap_overlay *ovl; | |
58f25548 | 692 | |
ac9f2421 | 693 | DSSDBG("writing mgr %d regs\n", mgr->id); |
58f25548 | 694 | |
75c94965 TV |
695 | if (!mp->enabled) |
696 | return; | |
58f25548 | 697 | |
75c94965 | 698 | WARN_ON(mp->busy); |
58f25548 | 699 | |
58f25548 | 700 | /* Commit overlay settings */ |
75c94965 TV |
701 | list_for_each_entry(ovl, &mgr->overlays, list) { |
702 | dss_ovl_write_regs(ovl); | |
aaa874a9 | 703 | dss_ovl_write_regs_extra(ovl); |
aaa874a9 TV |
704 | } |
705 | ||
0b53f179 | 706 | if (mp->info_dirty) { |
75c94965 | 707 | dispc_mgr_setup(mgr->id, &mp->info); |
58f25548 | 708 | |
0b53f179 | 709 | mp->info_dirty = false; |
34861378 | 710 | if (mp->updating) |
0b53f179 | 711 | mp->shadow_info_dirty = true; |
58f25548 | 712 | } |
75c94965 TV |
713 | } |
714 | ||
45324a26 AT |
715 | static void dss_mgr_write_regs_extra(struct omap_overlay_manager *mgr) |
716 | { | |
717 | struct mgr_priv_data *mp = get_mgr_priv(mgr); | |
718 | ||
ac9f2421 | 719 | DSSDBG("writing mgr %d regs extra\n", mgr->id); |
45324a26 AT |
720 | |
721 | if (!mp->extra_info_dirty) | |
722 | return; | |
723 | ||
724 | dispc_mgr_set_timings(mgr->id, &mp->timings); | |
725 | ||
f476ae9d | 726 | /* lcd_config parameters */ |
fb2cec1f TV |
727 | if (dss_mgr_is_lcd(mgr->id)) |
728 | dispc_mgr_set_lcd_config(mgr->id, &mp->lcd_config); | |
f476ae9d | 729 | |
45324a26 AT |
730 | mp->extra_info_dirty = false; |
731 | if (mp->updating) | |
732 | mp->shadow_extra_info_dirty = true; | |
733 | } | |
734 | ||
75c94965 TV |
735 | static void dss_write_regs(void) |
736 | { | |
737 | const int num_mgrs = omap_dss_get_num_overlay_managers(); | |
738 | int i; | |
58f25548 | 739 | |
58f25548 | 740 | for (i = 0; i < num_mgrs; ++i) { |
75c94965 TV |
741 | struct omap_overlay_manager *mgr; |
742 | struct mgr_priv_data *mp; | |
39518356 | 743 | int r; |
75c94965 | 744 | |
af3d64b2 TV |
745 | mgr = omap_dss_get_overlay_manager(i); |
746 | mp = get_mgr_priv(mgr); | |
58f25548 | 747 | |
75c94965 | 748 | if (!mp->enabled || mgr_manual_update(mgr) || mp->busy) |
58f25548 TV |
749 | continue; |
750 | ||
228b2134 | 751 | r = dss_check_settings(mgr); |
39518356 TV |
752 | if (r) { |
753 | DSSERR("cannot write registers for manager %s: " | |
754 | "illegal configuration\n", mgr->name); | |
755 | continue; | |
756 | } | |
757 | ||
75c94965 | 758 | dss_mgr_write_regs(mgr); |
45324a26 | 759 | dss_mgr_write_regs_extra(mgr); |
3ab15b2a TV |
760 | } |
761 | } | |
75c94965 | 762 | |
3ab15b2a TV |
763 | static void dss_set_go_bits(void) |
764 | { | |
765 | const int num_mgrs = omap_dss_get_num_overlay_managers(); | |
766 | int i; | |
58f25548 | 767 | |
3ab15b2a TV |
768 | for (i = 0; i < num_mgrs; ++i) { |
769 | struct omap_overlay_manager *mgr; | |
770 | struct mgr_priv_data *mp; | |
58f25548 | 771 | |
3ab15b2a TV |
772 | mgr = omap_dss_get_overlay_manager(i); |
773 | mp = get_mgr_priv(mgr); | |
774 | ||
775 | if (!mp->enabled || mgr_manual_update(mgr) || mp->busy) | |
776 | continue; | |
777 | ||
778 | if (!need_go(mgr)) | |
779 | continue; | |
780 | ||
781 | mp->busy = true; | |
782 | ||
783 | if (!dss_data.irq_enabled && need_isr()) | |
784 | dss_register_vsync_isr(); | |
785 | ||
786 | dispc_mgr_go(mgr->id); | |
75c94965 | 787 | } |
3ab15b2a | 788 | |
58f25548 TV |
789 | } |
790 | ||
df01d530 TV |
791 | static void mgr_clear_shadow_dirty(struct omap_overlay_manager *mgr) |
792 | { | |
793 | struct omap_overlay *ovl; | |
794 | struct mgr_priv_data *mp; | |
795 | struct ovl_priv_data *op; | |
796 | ||
797 | mp = get_mgr_priv(mgr); | |
798 | mp->shadow_info_dirty = false; | |
45324a26 | 799 | mp->shadow_extra_info_dirty = false; |
df01d530 TV |
800 | |
801 | list_for_each_entry(ovl, &mgr->overlays, list) { | |
802 | op = get_ovl_priv(ovl); | |
803 | op->shadow_info_dirty = false; | |
804 | op->shadow_extra_info_dirty = false; | |
805 | } | |
806 | } | |
807 | ||
a7e71e7f | 808 | static int dss_mgr_connect_compat(struct omap_overlay_manager *mgr, |
1f68d9c4 | 809 | struct omap_dss_device *dst) |
a7e71e7f TV |
810 | { |
811 | return mgr->set_output(mgr, dst); | |
812 | } | |
813 | ||
814 | static void dss_mgr_disconnect_compat(struct omap_overlay_manager *mgr, | |
1f68d9c4 | 815 | struct omap_dss_device *dst) |
a7e71e7f TV |
816 | { |
817 | mgr->unset_output(mgr); | |
818 | } | |
819 | ||
74b65ec2 | 820 | static void dss_mgr_start_update_compat(struct omap_overlay_manager *mgr) |
58f25548 | 821 | { |
af3d64b2 | 822 | struct mgr_priv_data *mp = get_mgr_priv(mgr); |
e0a2aa5b | 823 | unsigned long flags; |
39518356 | 824 | int r; |
e0a2aa5b TV |
825 | |
826 | spin_lock_irqsave(&data_lock, flags); | |
58f25548 | 827 | |
34861378 TV |
828 | WARN_ON(mp->updating); |
829 | ||
228b2134 | 830 | r = dss_check_settings(mgr); |
39518356 TV |
831 | if (r) { |
832 | DSSERR("cannot start manual update: illegal configuration\n"); | |
833 | spin_unlock_irqrestore(&data_lock, flags); | |
834 | return; | |
835 | } | |
836 | ||
75c94965 | 837 | dss_mgr_write_regs(mgr); |
45324a26 | 838 | dss_mgr_write_regs_extra(mgr); |
58f25548 | 839 | |
34861378 | 840 | mp->updating = true; |
58f25548 | 841 | |
34861378 TV |
842 | if (!dss_data.irq_enabled && need_isr()) |
843 | dss_register_vsync_isr(); | |
58f25548 | 844 | |
3a979f8a | 845 | dispc_mgr_enable_sync(mgr->id); |
e0a2aa5b TV |
846 | |
847 | spin_unlock_irqrestore(&data_lock, flags); | |
58f25548 TV |
848 | } |
849 | ||
dbce0160 TV |
850 | static void dss_apply_irq_handler(void *data, u32 mask); |
851 | ||
852 | static void dss_register_vsync_isr(void) | |
853 | { | |
bc1a9518 | 854 | const int num_mgrs = dss_feat_get_num_mgrs(); |
dbce0160 | 855 | u32 mask; |
bc1a9518 | 856 | int r, i; |
dbce0160 | 857 | |
bc1a9518 TV |
858 | mask = 0; |
859 | for (i = 0; i < num_mgrs; ++i) | |
860 | mask |= dispc_mgr_get_vsync_irq(i); | |
dbce0160 | 861 | |
34861378 TV |
862 | for (i = 0; i < num_mgrs; ++i) |
863 | mask |= dispc_mgr_get_framedone_irq(i); | |
864 | ||
dbce0160 TV |
865 | r = omap_dispc_register_isr(dss_apply_irq_handler, NULL, mask); |
866 | WARN_ON(r); | |
867 | ||
d09c7aa8 | 868 | dss_data.irq_enabled = true; |
dbce0160 TV |
869 | } |
870 | ||
871 | static void dss_unregister_vsync_isr(void) | |
872 | { | |
bc1a9518 | 873 | const int num_mgrs = dss_feat_get_num_mgrs(); |
dbce0160 | 874 | u32 mask; |
bc1a9518 | 875 | int r, i; |
dbce0160 | 876 | |
bc1a9518 TV |
877 | mask = 0; |
878 | for (i = 0; i < num_mgrs; ++i) | |
879 | mask |= dispc_mgr_get_vsync_irq(i); | |
dbce0160 | 880 | |
34861378 TV |
881 | for (i = 0; i < num_mgrs; ++i) |
882 | mask |= dispc_mgr_get_framedone_irq(i); | |
883 | ||
dbce0160 TV |
884 | r = omap_dispc_unregister_isr(dss_apply_irq_handler, NULL, mask); |
885 | WARN_ON(r); | |
886 | ||
d09c7aa8 | 887 | dss_data.irq_enabled = false; |
dbce0160 TV |
888 | } |
889 | ||
7609893c TV |
890 | static void dss_apply_irq_handler(void *data, u32 mask) |
891 | { | |
58f25548 | 892 | const int num_mgrs = dss_feat_get_num_mgrs(); |
75c94965 | 893 | int i; |
f1577ce1 | 894 | bool extra_updating; |
58f25548 | 895 | |
063fd701 | 896 | spin_lock(&data_lock); |
58f25548 | 897 | |
7609893c | 898 | /* clear busy, updating flags, shadow_dirty flags */ |
43a972d9 | 899 | for (i = 0; i < num_mgrs; i++) { |
7609893c TV |
900 | struct omap_overlay_manager *mgr; |
901 | struct mgr_priv_data *mp; | |
902 | ||
43a972d9 TV |
903 | mgr = omap_dss_get_overlay_manager(i); |
904 | mp = get_mgr_priv(mgr); | |
905 | ||
7609893c | 906 | if (!mp->enabled) |
43a972d9 TV |
907 | continue; |
908 | ||
7609893c | 909 | mp->updating = dispc_mgr_is_enabled(i); |
58f25548 | 910 | |
7609893c | 911 | if (!mgr_manual_update(mgr)) { |
5b214171 | 912 | bool was_busy = mp->busy; |
7609893c | 913 | mp->busy = dispc_mgr_go_busy(i); |
43a972d9 | 914 | |
5b214171 | 915 | if (was_busy && !mp->busy) |
7609893c | 916 | mgr_clear_shadow_dirty(mgr); |
7609893c | 917 | } |
58f25548 TV |
918 | } |
919 | ||
75c94965 | 920 | dss_write_regs(); |
3ab15b2a | 921 | dss_set_go_bits(); |
58f25548 | 922 | |
f1577ce1 TV |
923 | extra_updating = extra_info_update_ongoing(); |
924 | if (!extra_updating) | |
925 | complete_all(&extra_updated_completion); | |
926 | ||
1550202d TV |
927 | /* call framedone handlers for manual update displays */ |
928 | for (i = 0; i < num_mgrs; i++) { | |
929 | struct omap_overlay_manager *mgr; | |
930 | struct mgr_priv_data *mp; | |
931 | ||
932 | mgr = omap_dss_get_overlay_manager(i); | |
933 | mp = get_mgr_priv(mgr); | |
934 | ||
935 | if (!mgr_manual_update(mgr) || !mp->framedone_handler) | |
936 | continue; | |
937 | ||
938 | if (mask & dispc_mgr_get_framedone_irq(i)) | |
939 | mp->framedone_handler(mp->framedone_handler_data); | |
940 | } | |
941 | ||
75c94965 TV |
942 | if (!need_isr()) |
943 | dss_unregister_vsync_isr(); | |
58f25548 | 944 | |
063fd701 | 945 | spin_unlock(&data_lock); |
58f25548 TV |
946 | } |
947 | ||
5738b633 | 948 | static void omap_dss_mgr_apply_ovl(struct omap_overlay *ovl) |
58f25548 | 949 | { |
c10c6f04 | 950 | struct ovl_priv_data *op; |
58f25548 | 951 | |
c10c6f04 | 952 | op = get_ovl_priv(ovl); |
58f25548 | 953 | |
c1a9febf | 954 | if (!op->user_info_dirty) |
5738b633 | 955 | return; |
58f25548 | 956 | |
c1a9febf | 957 | op->user_info_dirty = false; |
0b53f179 | 958 | op->info_dirty = true; |
c1a9febf | 959 | op->info = op->user_info; |
58f25548 TV |
960 | } |
961 | ||
962 | static void omap_dss_mgr_apply_mgr(struct omap_overlay_manager *mgr) | |
963 | { | |
af3d64b2 | 964 | struct mgr_priv_data *mp; |
58f25548 | 965 | |
af3d64b2 | 966 | mp = get_mgr_priv(mgr); |
58f25548 | 967 | |
388c4c6c | 968 | if (!mp->user_info_dirty) |
58f25548 TV |
969 | return; |
970 | ||
388c4c6c | 971 | mp->user_info_dirty = false; |
0b53f179 | 972 | mp->info_dirty = true; |
388c4c6c | 973 | mp->info = mp->user_info; |
58f25548 TV |
974 | } |
975 | ||
0c49ff74 | 976 | static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr) |
58f25548 | 977 | { |
6dc802e2 TV |
978 | unsigned long flags; |
979 | struct omap_overlay *ovl; | |
39518356 | 980 | int r; |
6dc802e2 TV |
981 | |
982 | DSSDBG("omap_dss_mgr_apply(%s)\n", mgr->name); | |
983 | ||
6dc802e2 TV |
984 | spin_lock_irqsave(&data_lock, flags); |
985 | ||
228b2134 | 986 | r = dss_check_settings_apply(mgr); |
39518356 TV |
987 | if (r) { |
988 | spin_unlock_irqrestore(&data_lock, flags); | |
989 | DSSERR("failed to apply settings: illegal configuration.\n"); | |
990 | return r; | |
991 | } | |
992 | ||
6dc802e2 TV |
993 | /* Configure overlays */ |
994 | list_for_each_entry(ovl, &mgr->overlays, list) | |
995 | omap_dss_mgr_apply_ovl(ovl); | |
996 | ||
997 | /* Configure manager */ | |
998 | omap_dss_mgr_apply_mgr(mgr); | |
999 | ||
1000 | dss_write_regs(); | |
3ab15b2a | 1001 | dss_set_go_bits(); |
6dc802e2 TV |
1002 | |
1003 | spin_unlock_irqrestore(&data_lock, flags); | |
1004 | ||
e70f98ac | 1005 | return 0; |
6dc802e2 TV |
1006 | } |
1007 | ||
841c09c7 TV |
1008 | static void dss_apply_ovl_enable(struct omap_overlay *ovl, bool enable) |
1009 | { | |
1010 | struct ovl_priv_data *op; | |
1011 | ||
1012 | op = get_ovl_priv(ovl); | |
1013 | ||
1014 | if (op->enabled == enable) | |
1015 | return; | |
1016 | ||
1017 | op->enabled = enable; | |
1018 | op->extra_info_dirty = true; | |
1019 | } | |
1020 | ||
04576d41 TV |
1021 | static void dss_apply_ovl_fifo_thresholds(struct omap_overlay *ovl, |
1022 | u32 fifo_low, u32 fifo_high) | |
1023 | { | |
1024 | struct ovl_priv_data *op = get_ovl_priv(ovl); | |
1025 | ||
1026 | if (op->fifo_low == fifo_low && op->fifo_high == fifo_high) | |
1027 | return; | |
1028 | ||
1029 | op->fifo_low = fifo_low; | |
1030 | op->fifo_high = fifo_high; | |
1031 | op->extra_info_dirty = true; | |
1032 | } | |
1033 | ||
b3e93cbd | 1034 | static void dss_ovl_setup_fifo(struct omap_overlay *ovl) |
6dc802e2 TV |
1035 | { |
1036 | struct ovl_priv_data *op = get_ovl_priv(ovl); | |
6dc802e2 | 1037 | u32 fifo_low, fifo_high; |
b3e93cbd | 1038 | bool use_fifo_merge = false; |
58f25548 | 1039 | |
75ae118a TV |
1040 | if (!op->enabled && !op->enabling) |
1041 | return; | |
1042 | ||
83fa2f2e | 1043 | dispc_ovl_compute_fifo_thresholds(ovl->id, &fifo_low, &fifo_high, |
3568f2a4 | 1044 | use_fifo_merge, ovl_manual_update(ovl)); |
6dc802e2 | 1045 | |
04576d41 | 1046 | dss_apply_ovl_fifo_thresholds(ovl, fifo_low, fifo_high); |
58f25548 TV |
1047 | } |
1048 | ||
b3e93cbd | 1049 | static void dss_mgr_setup_fifos(struct omap_overlay_manager *mgr) |
58f25548 | 1050 | { |
07e327c9 | 1051 | struct omap_overlay *ovl; |
6dc802e2 | 1052 | struct mgr_priv_data *mp; |
58f25548 | 1053 | |
6dc802e2 | 1054 | mp = get_mgr_priv(mgr); |
58f25548 | 1055 | |
6dc802e2 TV |
1056 | if (!mp->enabled) |
1057 | return; | |
58f25548 | 1058 | |
75ae118a | 1059 | list_for_each_entry(ovl, &mgr->overlays, list) |
b3e93cbd | 1060 | dss_ovl_setup_fifo(ovl); |
75ae118a | 1061 | } |
58f25548 | 1062 | |
b3e93cbd | 1063 | static void dss_setup_fifos(void) |
75ae118a TV |
1064 | { |
1065 | const int num_mgrs = omap_dss_get_num_overlay_managers(); | |
1066 | struct omap_overlay_manager *mgr; | |
1067 | int i; | |
58f25548 | 1068 | |
75ae118a TV |
1069 | for (i = 0; i < num_mgrs; ++i) { |
1070 | mgr = omap_dss_get_overlay_manager(i); | |
b3e93cbd | 1071 | dss_mgr_setup_fifos(mgr); |
6dc802e2 | 1072 | } |
58f25548 TV |
1073 | } |
1074 | ||
74b65ec2 | 1075 | static int dss_mgr_enable_compat(struct omap_overlay_manager *mgr) |
7797c6da | 1076 | { |
bf213523 TV |
1077 | struct mgr_priv_data *mp = get_mgr_priv(mgr); |
1078 | unsigned long flags; | |
39518356 | 1079 | int r; |
bf213523 | 1080 | |
5558db3f TV |
1081 | mutex_lock(&apply_lock); |
1082 | ||
e4f7ad70 TV |
1083 | if (mp->enabled) |
1084 | goto out; | |
1085 | ||
bf213523 TV |
1086 | spin_lock_irqsave(&data_lock, flags); |
1087 | ||
39518356 | 1088 | mp->enabled = true; |
a6b24f83 | 1089 | |
228b2134 | 1090 | r = dss_check_settings(mgr); |
39518356 TV |
1091 | if (r) { |
1092 | DSSERR("failed to enable manager %d: check_settings failed\n", | |
1093 | mgr->id); | |
2a4ee7ee | 1094 | goto err; |
39518356 TV |
1095 | } |
1096 | ||
b3e93cbd | 1097 | dss_setup_fifos(); |
6dc802e2 | 1098 | |
75c94965 | 1099 | dss_write_regs(); |
3ab15b2a | 1100 | dss_set_go_bits(); |
75c94965 | 1101 | |
34861378 TV |
1102 | if (!mgr_manual_update(mgr)) |
1103 | mp->updating = true; | |
1104 | ||
d7b6b6b1 TV |
1105 | if (!dss_data.irq_enabled && need_isr()) |
1106 | dss_register_vsync_isr(); | |
1107 | ||
bf213523 | 1108 | spin_unlock_irqrestore(&data_lock, flags); |
5558db3f | 1109 | |
75c94965 | 1110 | if (!mgr_manual_update(mgr)) |
3a979f8a | 1111 | dispc_mgr_enable_sync(mgr->id); |
75c94965 | 1112 | |
e4f7ad70 | 1113 | out: |
5558db3f | 1114 | mutex_unlock(&apply_lock); |
2a4ee7ee TV |
1115 | |
1116 | return 0; | |
1117 | ||
1118 | err: | |
a6b24f83 | 1119 | mp->enabled = false; |
2a4ee7ee TV |
1120 | spin_unlock_irqrestore(&data_lock, flags); |
1121 | mutex_unlock(&apply_lock); | |
1122 | return r; | |
7797c6da TV |
1123 | } |
1124 | ||
74b65ec2 | 1125 | static void dss_mgr_disable_compat(struct omap_overlay_manager *mgr) |
7797c6da | 1126 | { |
bf213523 TV |
1127 | struct mgr_priv_data *mp = get_mgr_priv(mgr); |
1128 | unsigned long flags; | |
1129 | ||
5558db3f TV |
1130 | mutex_lock(&apply_lock); |
1131 | ||
e4f7ad70 TV |
1132 | if (!mp->enabled) |
1133 | goto out; | |
1134 | ||
9a147a65 | 1135 | if (!mgr_manual_update(mgr)) |
3a979f8a | 1136 | dispc_mgr_disable_sync(mgr->id); |
bf213523 TV |
1137 | |
1138 | spin_lock_irqsave(&data_lock, flags); | |
1139 | ||
34861378 | 1140 | mp->updating = false; |
bf213523 TV |
1141 | mp->enabled = false; |
1142 | ||
1143 | spin_unlock_irqrestore(&data_lock, flags); | |
5558db3f | 1144 | |
e4f7ad70 | 1145 | out: |
5558db3f | 1146 | mutex_unlock(&apply_lock); |
7797c6da TV |
1147 | } |
1148 | ||
0c49ff74 | 1149 | static int dss_mgr_set_info(struct omap_overlay_manager *mgr, |
eb70d739 TV |
1150 | struct omap_overlay_manager_info *info) |
1151 | { | |
388c4c6c | 1152 | struct mgr_priv_data *mp = get_mgr_priv(mgr); |
e0a2aa5b | 1153 | unsigned long flags; |
f17d04fb TV |
1154 | int r; |
1155 | ||
1156 | r = dss_mgr_simple_check(mgr, info); | |
1157 | if (r) | |
1158 | return r; | |
e0a2aa5b TV |
1159 | |
1160 | spin_lock_irqsave(&data_lock, flags); | |
1161 | ||
388c4c6c TV |
1162 | mp->user_info = *info; |
1163 | mp->user_info_dirty = true; | |
eb70d739 | 1164 | |
e0a2aa5b TV |
1165 | spin_unlock_irqrestore(&data_lock, flags); |
1166 | ||
eb70d739 TV |
1167 | return 0; |
1168 | } | |
1169 | ||
0c49ff74 | 1170 | static void dss_mgr_get_info(struct omap_overlay_manager *mgr, |
eb70d739 TV |
1171 | struct omap_overlay_manager_info *info) |
1172 | { | |
388c4c6c | 1173 | struct mgr_priv_data *mp = get_mgr_priv(mgr); |
e0a2aa5b TV |
1174 | unsigned long flags; |
1175 | ||
1176 | spin_lock_irqsave(&data_lock, flags); | |
1177 | ||
388c4c6c | 1178 | *info = mp->user_info; |
e0a2aa5b TV |
1179 | |
1180 | spin_unlock_irqrestore(&data_lock, flags); | |
eb70d739 TV |
1181 | } |
1182 | ||
0c49ff74 | 1183 | static int dss_mgr_set_output(struct omap_overlay_manager *mgr, |
1f68d9c4 | 1184 | struct omap_dss_device *output) |
97f01b3a AT |
1185 | { |
1186 | int r; | |
1187 | ||
1188 | mutex_lock(&apply_lock); | |
1189 | ||
1190 | if (mgr->output) { | |
1191 | DSSERR("manager %s is already connected to an output\n", | |
1192 | mgr->name); | |
1193 | r = -EINVAL; | |
1194 | goto err; | |
1195 | } | |
1196 | ||
1197 | if ((mgr->supported_outputs & output->id) == 0) { | |
1198 | DSSERR("output does not support manager %s\n", | |
1199 | mgr->name); | |
1200 | r = -EINVAL; | |
1201 | goto err; | |
1202 | } | |
1203 | ||
1204 | output->manager = mgr; | |
1205 | mgr->output = output; | |
1206 | ||
1207 | mutex_unlock(&apply_lock); | |
1208 | ||
1209 | return 0; | |
1210 | err: | |
1211 | mutex_unlock(&apply_lock); | |
1212 | return r; | |
1213 | } | |
1214 | ||
0c49ff74 | 1215 | static int dss_mgr_unset_output(struct omap_overlay_manager *mgr) |
97f01b3a AT |
1216 | { |
1217 | int r; | |
1218 | struct mgr_priv_data *mp = get_mgr_priv(mgr); | |
1219 | unsigned long flags; | |
1220 | ||
1221 | mutex_lock(&apply_lock); | |
1222 | ||
1223 | if (!mgr->output) { | |
1224 | DSSERR("failed to unset output, output not set\n"); | |
1225 | r = -EINVAL; | |
1226 | goto err; | |
1227 | } | |
1228 | ||
1229 | spin_lock_irqsave(&data_lock, flags); | |
1230 | ||
1231 | if (mp->enabled) { | |
1232 | DSSERR("output can't be unset when manager is enabled\n"); | |
1233 | r = -EINVAL; | |
1234 | goto err1; | |
1235 | } | |
1236 | ||
1237 | spin_unlock_irqrestore(&data_lock, flags); | |
1238 | ||
1239 | mgr->output->manager = NULL; | |
1240 | mgr->output = NULL; | |
1241 | ||
1242 | mutex_unlock(&apply_lock); | |
1243 | ||
1244 | return 0; | |
1245 | err1: | |
1246 | spin_unlock_irqrestore(&data_lock, flags); | |
1247 | err: | |
1248 | mutex_unlock(&apply_lock); | |
1249 | ||
1250 | return r; | |
1251 | } | |
1252 | ||
45324a26 | 1253 | static void dss_apply_mgr_timings(struct omap_overlay_manager *mgr, |
27dfddc7 | 1254 | const struct omap_video_timings *timings) |
45324a26 AT |
1255 | { |
1256 | struct mgr_priv_data *mp = get_mgr_priv(mgr); | |
1257 | ||
1258 | mp->timings = *timings; | |
1259 | mp->extra_info_dirty = true; | |
1260 | } | |
1261 | ||
74b65ec2 | 1262 | static void dss_mgr_set_timings_compat(struct omap_overlay_manager *mgr, |
27dfddc7 | 1263 | const struct omap_video_timings *timings) |
45324a26 AT |
1264 | { |
1265 | unsigned long flags; | |
fed62e54 | 1266 | struct mgr_priv_data *mp = get_mgr_priv(mgr); |
45324a26 AT |
1267 | |
1268 | spin_lock_irqsave(&data_lock, flags); | |
1269 | ||
fed62e54 TV |
1270 | if (mp->updating) { |
1271 | DSSERR("cannot set timings for %s: manager needs to be disabled\n", | |
1272 | mgr->name); | |
1273 | goto out; | |
1274 | } | |
45324a26 | 1275 | |
fed62e54 TV |
1276 | dss_apply_mgr_timings(mgr, timings); |
1277 | out: | |
45324a26 | 1278 | spin_unlock_irqrestore(&data_lock, flags); |
45324a26 | 1279 | } |
eb70d739 | 1280 | |
f476ae9d AT |
1281 | static void dss_apply_mgr_lcd_config(struct omap_overlay_manager *mgr, |
1282 | const struct dss_lcd_mgr_config *config) | |
1283 | { | |
1284 | struct mgr_priv_data *mp = get_mgr_priv(mgr); | |
1285 | ||
1286 | mp->lcd_config = *config; | |
1287 | mp->extra_info_dirty = true; | |
1288 | } | |
1289 | ||
74b65ec2 | 1290 | static void dss_mgr_set_lcd_config_compat(struct omap_overlay_manager *mgr, |
f476ae9d AT |
1291 | const struct dss_lcd_mgr_config *config) |
1292 | { | |
1293 | unsigned long flags; | |
1294 | struct mgr_priv_data *mp = get_mgr_priv(mgr); | |
1295 | ||
aba96570 | 1296 | spin_lock_irqsave(&data_lock, flags); |
f476ae9d AT |
1297 | |
1298 | if (mp->enabled) { | |
1299 | DSSERR("cannot apply lcd config for %s: manager needs to be disabled\n", | |
1300 | mgr->name); | |
1301 | goto out; | |
1302 | } | |
1303 | ||
f476ae9d | 1304 | dss_apply_mgr_lcd_config(mgr, config); |
f476ae9d | 1305 | out: |
aba96570 | 1306 | spin_unlock_irqrestore(&data_lock, flags); |
f476ae9d AT |
1307 | } |
1308 | ||
6abae7a1 | 1309 | static int dss_ovl_set_info(struct omap_overlay *ovl, |
f77b3070 TV |
1310 | struct omap_overlay_info *info) |
1311 | { | |
c1a9febf | 1312 | struct ovl_priv_data *op = get_ovl_priv(ovl); |
e0a2aa5b | 1313 | unsigned long flags; |
fcc764dc TV |
1314 | int r; |
1315 | ||
1316 | r = dss_ovl_simple_check(ovl, info); | |
1317 | if (r) | |
1318 | return r; | |
e0a2aa5b TV |
1319 | |
1320 | spin_lock_irqsave(&data_lock, flags); | |
1321 | ||
c1a9febf TV |
1322 | op->user_info = *info; |
1323 | op->user_info_dirty = true; | |
f77b3070 | 1324 | |
e0a2aa5b TV |
1325 | spin_unlock_irqrestore(&data_lock, flags); |
1326 | ||
f77b3070 TV |
1327 | return 0; |
1328 | } | |
1329 | ||
6abae7a1 | 1330 | static void dss_ovl_get_info(struct omap_overlay *ovl, |
f77b3070 TV |
1331 | struct omap_overlay_info *info) |
1332 | { | |
c1a9febf | 1333 | struct ovl_priv_data *op = get_ovl_priv(ovl); |
e0a2aa5b TV |
1334 | unsigned long flags; |
1335 | ||
1336 | spin_lock_irqsave(&data_lock, flags); | |
1337 | ||
c1a9febf | 1338 | *info = op->user_info; |
e0a2aa5b TV |
1339 | |
1340 | spin_unlock_irqrestore(&data_lock, flags); | |
f77b3070 TV |
1341 | } |
1342 | ||
6abae7a1 | 1343 | static int dss_ovl_set_manager(struct omap_overlay *ovl, |
f77b3070 TV |
1344 | struct omap_overlay_manager *mgr) |
1345 | { | |
aaa874a9 TV |
1346 | struct ovl_priv_data *op = get_ovl_priv(ovl); |
1347 | unsigned long flags; | |
5558db3f TV |
1348 | int r; |
1349 | ||
f77b3070 TV |
1350 | if (!mgr) |
1351 | return -EINVAL; | |
1352 | ||
5558db3f TV |
1353 | mutex_lock(&apply_lock); |
1354 | ||
f77b3070 TV |
1355 | if (ovl->manager) { |
1356 | DSSERR("overlay '%s' already has a manager '%s'\n", | |
1357 | ovl->name, ovl->manager->name); | |
5558db3f TV |
1358 | r = -EINVAL; |
1359 | goto err; | |
f77b3070 TV |
1360 | } |
1361 | ||
02b5ff1a AT |
1362 | r = dispc_runtime_get(); |
1363 | if (r) | |
1364 | goto err; | |
1365 | ||
aaa874a9 TV |
1366 | spin_lock_irqsave(&data_lock, flags); |
1367 | ||
1368 | if (op->enabled) { | |
1369 | spin_unlock_irqrestore(&data_lock, flags); | |
f77b3070 | 1370 | DSSERR("overlay has to be disabled to change the manager\n"); |
5558db3f | 1371 | r = -EINVAL; |
02b5ff1a | 1372 | goto err1; |
f77b3070 TV |
1373 | } |
1374 | ||
02b5ff1a | 1375 | dispc_ovl_set_channel_out(ovl->id, mgr->id); |
5d5a97a6 | 1376 | |
f77b3070 TV |
1377 | ovl->manager = mgr; |
1378 | list_add_tail(&ovl->list, &mgr->overlays); | |
f77b3070 | 1379 | |
aaa874a9 TV |
1380 | spin_unlock_irqrestore(&data_lock, flags); |
1381 | ||
02b5ff1a | 1382 | dispc_runtime_put(); |
f77b3070 | 1383 | |
5558db3f TV |
1384 | mutex_unlock(&apply_lock); |
1385 | ||
f77b3070 | 1386 | return 0; |
02b5ff1a AT |
1387 | |
1388 | err1: | |
1389 | dispc_runtime_put(); | |
5558db3f TV |
1390 | err: |
1391 | mutex_unlock(&apply_lock); | |
1392 | return r; | |
f77b3070 TV |
1393 | } |
1394 | ||
6abae7a1 | 1395 | static int dss_ovl_unset_manager(struct omap_overlay *ovl) |
f77b3070 | 1396 | { |
aaa874a9 TV |
1397 | struct ovl_priv_data *op = get_ovl_priv(ovl); |
1398 | unsigned long flags; | |
5558db3f TV |
1399 | int r; |
1400 | ||
1401 | mutex_lock(&apply_lock); | |
1402 | ||
f77b3070 TV |
1403 | if (!ovl->manager) { |
1404 | DSSERR("failed to detach overlay: manager not set\n"); | |
5558db3f TV |
1405 | r = -EINVAL; |
1406 | goto err; | |
f77b3070 TV |
1407 | } |
1408 | ||
aaa874a9 TV |
1409 | spin_lock_irqsave(&data_lock, flags); |
1410 | ||
1411 | if (op->enabled) { | |
1412 | spin_unlock_irqrestore(&data_lock, flags); | |
f77b3070 | 1413 | DSSERR("overlay has to be disabled to unset the manager\n"); |
5558db3f TV |
1414 | r = -EINVAL; |
1415 | goto err; | |
f77b3070 TV |
1416 | } |
1417 | ||
b2f5976c TV |
1418 | spin_unlock_irqrestore(&data_lock, flags); |
1419 | ||
1420 | /* wait for pending extra_info updates to ensure the ovl is disabled */ | |
1421 | wait_pending_extra_info_updates(); | |
1422 | ||
02b5ff1a AT |
1423 | /* |
1424 | * For a manual update display, there is no guarantee that the overlay | |
1425 | * is really disabled in HW, we may need an extra update from this | |
1426 | * manager before the configurations can go in. Return an error if the | |
1427 | * overlay needed an update from the manager. | |
1428 | * | |
1429 | * TODO: Instead of returning an error, try to do a dummy manager update | |
1430 | * here to disable the overlay in hardware. Use the *GATED fields in | |
1431 | * the DISPC_CONFIG registers to do a dummy update. | |
1432 | */ | |
b2f5976c TV |
1433 | spin_lock_irqsave(&data_lock, flags); |
1434 | ||
02b5ff1a AT |
1435 | if (ovl_manual_update(ovl) && op->extra_info_dirty) { |
1436 | spin_unlock_irqrestore(&data_lock, flags); | |
1437 | DSSERR("need an update to change the manager\n"); | |
1438 | r = -EINVAL; | |
1439 | goto err; | |
1440 | } | |
5d5a97a6 | 1441 | |
f77b3070 TV |
1442 | ovl->manager = NULL; |
1443 | list_del(&ovl->list); | |
f77b3070 | 1444 | |
aaa874a9 TV |
1445 | spin_unlock_irqrestore(&data_lock, flags); |
1446 | ||
1447 | mutex_unlock(&apply_lock); | |
1448 | ||
1449 | return 0; | |
1450 | err: | |
1451 | mutex_unlock(&apply_lock); | |
1452 | return r; | |
1453 | } | |
1454 | ||
6abae7a1 | 1455 | static bool dss_ovl_is_enabled(struct omap_overlay *ovl) |
aaa874a9 TV |
1456 | { |
1457 | struct ovl_priv_data *op = get_ovl_priv(ovl); | |
1458 | unsigned long flags; | |
1459 | bool e; | |
1460 | ||
1461 | spin_lock_irqsave(&data_lock, flags); | |
1462 | ||
1463 | e = op->enabled; | |
1464 | ||
1465 | spin_unlock_irqrestore(&data_lock, flags); | |
1466 | ||
1467 | return e; | |
1468 | } | |
1469 | ||
6abae7a1 | 1470 | static int dss_ovl_enable(struct omap_overlay *ovl) |
aaa874a9 TV |
1471 | { |
1472 | struct ovl_priv_data *op = get_ovl_priv(ovl); | |
1473 | unsigned long flags; | |
1474 | int r; | |
1475 | ||
1476 | mutex_lock(&apply_lock); | |
1477 | ||
e4f7ad70 TV |
1478 | if (op->enabled) { |
1479 | r = 0; | |
39518356 | 1480 | goto err1; |
e4f7ad70 TV |
1481 | } |
1482 | ||
0f0e4e3c | 1483 | if (ovl->manager == NULL || ovl->manager->output == NULL) { |
aaa874a9 | 1484 | r = -EINVAL; |
39518356 | 1485 | goto err1; |
aaa874a9 TV |
1486 | } |
1487 | ||
1488 | spin_lock_irqsave(&data_lock, flags); | |
1489 | ||
82153eda TV |
1490 | op->enabling = true; |
1491 | ||
228b2134 | 1492 | r = dss_check_settings(ovl->manager); |
39518356 TV |
1493 | if (r) { |
1494 | DSSERR("failed to enable overlay %d: check_settings failed\n", | |
1495 | ovl->id); | |
1496 | goto err2; | |
1497 | } | |
1498 | ||
b3e93cbd | 1499 | dss_setup_fifos(); |
6dc802e2 | 1500 | |
82153eda TV |
1501 | op->enabling = false; |
1502 | dss_apply_ovl_enable(ovl, true); | |
1503 | ||
75c94965 | 1504 | dss_write_regs(); |
3ab15b2a | 1505 | dss_set_go_bits(); |
75c94965 | 1506 | |
aaa874a9 TV |
1507 | spin_unlock_irqrestore(&data_lock, flags); |
1508 | ||
1509 | mutex_unlock(&apply_lock); | |
1510 | ||
1511 | return 0; | |
39518356 | 1512 | err2: |
82153eda | 1513 | op->enabling = false; |
39518356 TV |
1514 | spin_unlock_irqrestore(&data_lock, flags); |
1515 | err1: | |
aaa874a9 TV |
1516 | mutex_unlock(&apply_lock); |
1517 | return r; | |
1518 | } | |
1519 | ||
6abae7a1 | 1520 | static int dss_ovl_disable(struct omap_overlay *ovl) |
aaa874a9 TV |
1521 | { |
1522 | struct ovl_priv_data *op = get_ovl_priv(ovl); | |
1523 | unsigned long flags; | |
1524 | int r; | |
1525 | ||
1526 | mutex_lock(&apply_lock); | |
1527 | ||
e4f7ad70 TV |
1528 | if (!op->enabled) { |
1529 | r = 0; | |
1530 | goto err; | |
1531 | } | |
1532 | ||
0f0e4e3c | 1533 | if (ovl->manager == NULL || ovl->manager->output == NULL) { |
aaa874a9 TV |
1534 | r = -EINVAL; |
1535 | goto err; | |
1536 | } | |
1537 | ||
1538 | spin_lock_irqsave(&data_lock, flags); | |
1539 | ||
841c09c7 | 1540 | dss_apply_ovl_enable(ovl, false); |
75c94965 | 1541 | dss_write_regs(); |
3ab15b2a | 1542 | dss_set_go_bits(); |
75c94965 | 1543 | |
aaa874a9 TV |
1544 | spin_unlock_irqrestore(&data_lock, flags); |
1545 | ||
5558db3f TV |
1546 | mutex_unlock(&apply_lock); |
1547 | ||
f77b3070 | 1548 | return 0; |
aaa874a9 | 1549 | |
5558db3f TV |
1550 | err: |
1551 | mutex_unlock(&apply_lock); | |
1552 | return r; | |
f77b3070 TV |
1553 | } |
1554 | ||
1550202d TV |
1555 | static int dss_mgr_register_framedone_handler_compat(struct omap_overlay_manager *mgr, |
1556 | void (*handler)(void *), void *data) | |
1557 | { | |
1558 | struct mgr_priv_data *mp = get_mgr_priv(mgr); | |
1559 | ||
1560 | if (mp->framedone_handler) | |
1561 | return -EBUSY; | |
1562 | ||
1563 | mp->framedone_handler = handler; | |
1564 | mp->framedone_handler_data = data; | |
1565 | ||
1566 | return 0; | |
1567 | } | |
1568 | ||
1569 | static void dss_mgr_unregister_framedone_handler_compat(struct omap_overlay_manager *mgr, | |
1570 | void (*handler)(void *), void *data) | |
1571 | { | |
1572 | struct mgr_priv_data *mp = get_mgr_priv(mgr); | |
1573 | ||
1574 | WARN_ON(mp->framedone_handler != handler || | |
1575 | mp->framedone_handler_data != data); | |
1576 | ||
1577 | mp->framedone_handler = NULL; | |
1578 | mp->framedone_handler_data = NULL; | |
1579 | } | |
1580 | ||
74b65ec2 | 1581 | static const struct dss_mgr_ops apply_mgr_ops = { |
a7e71e7f TV |
1582 | .connect = dss_mgr_connect_compat, |
1583 | .disconnect = dss_mgr_disconnect_compat, | |
74b65ec2 TV |
1584 | .start_update = dss_mgr_start_update_compat, |
1585 | .enable = dss_mgr_enable_compat, | |
1586 | .disable = dss_mgr_disable_compat, | |
1587 | .set_timings = dss_mgr_set_timings_compat, | |
1588 | .set_lcd_config = dss_mgr_set_lcd_config_compat, | |
1550202d TV |
1589 | .register_framedone_handler = dss_mgr_register_framedone_handler_compat, |
1590 | .unregister_framedone_handler = dss_mgr_unregister_framedone_handler_compat, | |
74b65ec2 TV |
1591 | }; |
1592 | ||
8dd2491a TV |
1593 | static int compat_refcnt; |
1594 | static DEFINE_MUTEX(compat_init_lock); | |
1595 | ||
1596 | int omapdss_compat_init(void) | |
1597 | { | |
23dfd1ac | 1598 | struct platform_device *pdev = dss_get_core_pdev(); |
74b65ec2 | 1599 | int i, r; |
23dfd1ac | 1600 | |
8dd2491a TV |
1601 | mutex_lock(&compat_init_lock); |
1602 | ||
1603 | if (compat_refcnt++ > 0) | |
1604 | goto out; | |
1605 | ||
1606 | apply_init_priv(); | |
1607 | ||
7f7cdbd6 | 1608 | dss_init_overlay_managers_sysfs(pdev); |
23dfd1ac TV |
1609 | dss_init_overlays(pdev); |
1610 | ||
0c49ff74 TV |
1611 | for (i = 0; i < omap_dss_get_num_overlay_managers(); i++) { |
1612 | struct omap_overlay_manager *mgr; | |
1613 | ||
1614 | mgr = omap_dss_get_overlay_manager(i); | |
1615 | ||
1616 | mgr->set_output = &dss_mgr_set_output; | |
1617 | mgr->unset_output = &dss_mgr_unset_output; | |
1618 | mgr->apply = &omap_dss_mgr_apply; | |
1619 | mgr->set_manager_info = &dss_mgr_set_info; | |
1620 | mgr->get_manager_info = &dss_mgr_get_info; | |
1621 | mgr->wait_for_go = &dss_mgr_wait_for_go; | |
1622 | mgr->wait_for_vsync = &dss_mgr_wait_for_vsync; | |
1623 | mgr->get_device = &dss_mgr_get_device; | |
1624 | } | |
1625 | ||
6abae7a1 TV |
1626 | for (i = 0; i < omap_dss_get_num_overlays(); i++) { |
1627 | struct omap_overlay *ovl = omap_dss_get_overlay(i); | |
1628 | ||
1629 | ovl->is_enabled = &dss_ovl_is_enabled; | |
1630 | ovl->enable = &dss_ovl_enable; | |
1631 | ovl->disable = &dss_ovl_disable; | |
1632 | ovl->set_manager = &dss_ovl_set_manager; | |
1633 | ovl->unset_manager = &dss_ovl_unset_manager; | |
1634 | ovl->set_overlay_info = &dss_ovl_set_info; | |
1635 | ovl->get_overlay_info = &dss_ovl_get_info; | |
1636 | ovl->wait_for_go = &dss_mgr_wait_for_go_ovl; | |
1637 | ovl->get_device = &dss_ovl_get_device; | |
1638 | } | |
1639 | ||
74b65ec2 TV |
1640 | r = dss_install_mgr_ops(&apply_mgr_ops); |
1641 | if (r) | |
1642 | goto err_mgr_ops; | |
1643 | ||
94140f0d TV |
1644 | r = display_init_sysfs(pdev); |
1645 | if (r) | |
1646 | goto err_disp_sysfs; | |
09e82ba7 | 1647 | |
96e2e637 TV |
1648 | dispc_runtime_get(); |
1649 | ||
1650 | r = dss_dispc_initialize_irq(); | |
1651 | if (r) | |
1652 | goto err_init_irq; | |
1653 | ||
1654 | dispc_runtime_put(); | |
1655 | ||
8dd2491a TV |
1656 | out: |
1657 | mutex_unlock(&compat_init_lock); | |
1658 | ||
1659 | return 0; | |
74b65ec2 | 1660 | |
96e2e637 TV |
1661 | err_init_irq: |
1662 | dispc_runtime_put(); | |
94140f0d | 1663 | display_uninit_sysfs(pdev); |
09e82ba7 TV |
1664 | |
1665 | err_disp_sysfs: | |
96e2e637 TV |
1666 | dss_uninstall_mgr_ops(); |
1667 | ||
74b65ec2 | 1668 | err_mgr_ops: |
7f7cdbd6 | 1669 | dss_uninit_overlay_managers_sysfs(pdev); |
74b65ec2 TV |
1670 | dss_uninit_overlays(pdev); |
1671 | ||
1672 | compat_refcnt--; | |
1673 | ||
1674 | mutex_unlock(&compat_init_lock); | |
1675 | ||
1676 | return r; | |
8dd2491a TV |
1677 | } |
1678 | EXPORT_SYMBOL(omapdss_compat_init); | |
1679 | ||
1680 | void omapdss_compat_uninit(void) | |
1681 | { | |
23dfd1ac TV |
1682 | struct platform_device *pdev = dss_get_core_pdev(); |
1683 | ||
8dd2491a TV |
1684 | mutex_lock(&compat_init_lock); |
1685 | ||
1686 | if (--compat_refcnt > 0) | |
1687 | goto out; | |
1688 | ||
96e2e637 TV |
1689 | dss_dispc_uninitialize_irq(); |
1690 | ||
94140f0d | 1691 | display_uninit_sysfs(pdev); |
09e82ba7 | 1692 | |
74b65ec2 TV |
1693 | dss_uninstall_mgr_ops(); |
1694 | ||
7f7cdbd6 | 1695 | dss_uninit_overlay_managers_sysfs(pdev); |
23dfd1ac | 1696 | dss_uninit_overlays(pdev); |
8dd2491a TV |
1697 | out: |
1698 | mutex_unlock(&compat_init_lock); | |
1699 | } | |
1700 | EXPORT_SYMBOL(omapdss_compat_uninit); |