aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video')
-rw-r--r--drivers/video/omap2/dss/Makefile3
-rw-r--r--drivers/video/omap2/dss/apply.c656
-rw-r--r--drivers/video/omap2/dss/core.c2
-rw-r--r--drivers/video/omap2/dss/dss.h9
-rw-r--r--drivers/video/omap2/dss/manager.c621
5 files changed, 667 insertions, 624 deletions
diff --git a/drivers/video/omap2/dss/Makefile b/drivers/video/omap2/dss/Makefile
index bd34ac5b2026..8594522184d9 100644
--- a/drivers/video/omap2/dss/Makefile
+++ b/drivers/video/omap2/dss/Makefile
@@ -1,5 +1,6 @@
1obj-$(CONFIG_OMAP2_DSS) += omapdss.o 1obj-$(CONFIG_OMAP2_DSS) += omapdss.o
2omapdss-y := core.o dss.o dss_features.o dispc.o display.o manager.o overlay.o 2omapdss-y := core.o dss.o dss_features.o dispc.o display.o manager.o overlay.o \
3 apply.o
3omapdss-$(CONFIG_OMAP2_DSS_DPI) += dpi.o 4omapdss-$(CONFIG_OMAP2_DSS_DPI) += dpi.o
4omapdss-$(CONFIG_OMAP2_DSS_RFBI) += rfbi.o 5omapdss-$(CONFIG_OMAP2_DSS_RFBI) += rfbi.o
5omapdss-$(CONFIG_OMAP2_DSS_VENC) += venc.o 6omapdss-$(CONFIG_OMAP2_DSS_VENC) += venc.o
diff --git a/drivers/video/omap2/dss/apply.c b/drivers/video/omap2/dss/apply.c
new file mode 100644
index 000000000000..c634c986293d
--- /dev/null
+++ b/drivers/video/omap2/dss/apply.c
@@ -0,0 +1,656 @@
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>
21#include <linux/slab.h>
22#include <linux/spinlock.h>
23#include <linux/jiffies.h>
24
25#include <video/omapdss.h>
26
27#include "dss.h"
28#include "dss_features.h"
29
30/*
31 * We have 4 levels of cache for the dispc settings. First two are in SW and
32 * the latter two in HW.
33 *
34 * +--------------------+
35 * |overlay/manager_info|
36 * +--------------------+
37 * v
38 * apply()
39 * v
40 * +--------------------+
41 * | dss_cache |
42 * +--------------------+
43 * v
44 * configure()
45 * v
46 * +--------------------+
47 * | shadow registers |
48 * +--------------------+
49 * v
50 * VFP or lcd/digit_enable
51 * v
52 * +--------------------+
53 * | registers |
54 * +--------------------+
55 */
56
57struct overlay_cache_data {
58 /* If true, cache changed, but not written to shadow registers. Set
59 * in apply(), cleared when registers written. */
60 bool dirty;
61 /* If true, shadow registers contain changed values not yet in real
62 * registers. Set when writing to shadow registers, cleared at
63 * VSYNC/EVSYNC */
64 bool shadow_dirty;
65
66 bool enabled;
67
68 struct omap_overlay_info info;
69
70 enum omap_channel channel;
71
72 u32 fifo_low;
73 u32 fifo_high;
74};
75
76struct manager_cache_data {
77 /* If true, cache changed, but not written to shadow registers. Set
78 * in apply(), cleared when registers written. */
79 bool dirty;
80 /* If true, shadow registers contain changed values not yet in real
81 * registers. Set when writing to shadow registers, cleared at
82 * VSYNC/EVSYNC */
83 bool shadow_dirty;
84
85 struct omap_overlay_manager_info info;
86
87 bool manual_update;
88 bool do_manual_update;
89};
90
91static struct {
92 spinlock_t lock;
93 struct overlay_cache_data overlay_cache[MAX_DSS_OVERLAYS];
94 struct manager_cache_data manager_cache[MAX_DSS_MANAGERS];
95
96 bool irq_enabled;
97} dss_cache;
98
99void dss_apply_init(void)
100{
101 spin_lock_init(&dss_cache.lock);
102}
103
104static bool ovl_manual_update(struct omap_overlay *ovl)
105{
106 return ovl->manager->device->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE;
107}
108
109static bool mgr_manual_update(struct omap_overlay_manager *mgr)
110{
111 return mgr->device->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE;
112}
113
114static int overlay_enabled(struct omap_overlay *ovl)
115{
116 return ovl->info.enabled && ovl->manager && ovl->manager->device;
117}
118
119int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr)
120{
121 unsigned long timeout = msecs_to_jiffies(500);
122 struct manager_cache_data *mc;
123 u32 irq;
124 int r;
125 int i;
126 struct omap_dss_device *dssdev = mgr->device;
127
128 if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
129 return 0;
130
131 if (mgr_manual_update(mgr))
132 return 0;
133
134 if (dssdev->type == OMAP_DISPLAY_TYPE_VENC
135 || dssdev->type == OMAP_DISPLAY_TYPE_HDMI) {
136 irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN;
137 } else {
138 irq = (dssdev->manager->id == OMAP_DSS_CHANNEL_LCD) ?
139 DISPC_IRQ_VSYNC : DISPC_IRQ_VSYNC2;
140 }
141
142 mc = &dss_cache.manager_cache[mgr->id];
143 i = 0;
144 while (1) {
145 unsigned long flags;
146 bool shadow_dirty, dirty;
147
148 spin_lock_irqsave(&dss_cache.lock, flags);
149 dirty = mc->dirty;
150 shadow_dirty = mc->shadow_dirty;
151 spin_unlock_irqrestore(&dss_cache.lock, flags);
152
153 if (!dirty && !shadow_dirty) {
154 r = 0;
155 break;
156 }
157
158 /* 4 iterations is the worst case:
159 * 1 - initial iteration, dirty = true (between VFP and VSYNC)
160 * 2 - first VSYNC, dirty = true
161 * 3 - dirty = false, shadow_dirty = true
162 * 4 - shadow_dirty = false */
163 if (i++ == 3) {
164 DSSERR("mgr(%d)->wait_for_go() not finishing\n",
165 mgr->id);
166 r = 0;
167 break;
168 }
169
170 r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
171 if (r == -ERESTARTSYS)
172 break;
173
174 if (r) {
175 DSSERR("mgr(%d)->wait_for_go() timeout\n", mgr->id);
176 break;
177 }
178 }
179
180 return r;
181}
182
183int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl)
184{
185 unsigned long timeout = msecs_to_jiffies(500);
186 struct overlay_cache_data *oc;
187 struct omap_dss_device *dssdev;
188 u32 irq;
189 int r;
190 int i;
191
192 if (!ovl->manager)
193 return 0;
194
195 dssdev = ovl->manager->device;
196
197 if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
198 return 0;
199
200 if (ovl_manual_update(ovl))
201 return 0;
202
203 if (dssdev->type == OMAP_DISPLAY_TYPE_VENC
204 || dssdev->type == OMAP_DISPLAY_TYPE_HDMI) {
205 irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN;
206 } else {
207 irq = (dssdev->manager->id == OMAP_DSS_CHANNEL_LCD) ?
208 DISPC_IRQ_VSYNC : DISPC_IRQ_VSYNC2;
209 }
210
211 oc = &dss_cache.overlay_cache[ovl->id];
212 i = 0;
213 while (1) {
214 unsigned long flags;
215 bool shadow_dirty, dirty;
216
217 spin_lock_irqsave(&dss_cache.lock, flags);
218 dirty = oc->dirty;
219 shadow_dirty = oc->shadow_dirty;
220 spin_unlock_irqrestore(&dss_cache.lock, flags);
221
222 if (!dirty && !shadow_dirty) {
223 r = 0;
224 break;
225 }
226
227 /* 4 iterations is the worst case:
228 * 1 - initial iteration, dirty = true (between VFP and VSYNC)
229 * 2 - first VSYNC, dirty = true
230 * 3 - dirty = false, shadow_dirty = true
231 * 4 - shadow_dirty = false */
232 if (i++ == 3) {
233 DSSERR("ovl(%d)->wait_for_go() not finishing\n",
234 ovl->id);
235 r = 0;
236 break;
237 }
238
239 r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
240 if (r == -ERESTARTSYS)
241 break;
242
243 if (r) {
244 DSSERR("ovl(%d)->wait_for_go() timeout\n", ovl->id);
245 break;
246 }
247 }
248
249 return r;
250}
251
252static int configure_overlay(enum omap_plane plane)
253{
254 struct omap_overlay *ovl;
255 struct overlay_cache_data *c;
256 struct omap_overlay_info *oi;
257 bool ilace, replication;
258 int r;
259
260 DSSDBGF("%d", plane);
261
262 c = &dss_cache.overlay_cache[plane];
263 oi = &c->info;
264
265 if (!c->enabled) {
266 dispc_ovl_enable(plane, 0);
267 return 0;
268 }
269
270 ovl = omap_dss_get_overlay(plane);
271
272 replication = dss_use_replication(ovl->manager->device, oi->color_mode);
273
274 ilace = ovl->manager->device->type == OMAP_DISPLAY_TYPE_VENC;
275
276 dispc_ovl_set_channel_out(plane, c->channel);
277
278 r = dispc_ovl_setup(plane, oi, ilace, replication);
279 if (r) {
280 /* this shouldn't happen */
281 DSSERR("dispc_ovl_setup failed for ovl %d\n", plane);
282 dispc_ovl_enable(plane, 0);
283 return r;
284 }
285
286 dispc_ovl_set_fifo_threshold(plane, c->fifo_low, c->fifo_high);
287
288 dispc_ovl_enable(plane, 1);
289
290 return 0;
291}
292
293static void configure_manager(enum omap_channel channel)
294{
295 struct omap_overlay_manager_info *mi;
296
297 DSSDBGF("%d", channel);
298
299 /* picking info from the cache */
300 mi = &dss_cache.manager_cache[channel].info;
301
302 dispc_mgr_setup(channel, mi);
303}
304
305/* configure_dispc() tries to write values from cache to shadow registers.
306 * It writes only to those managers/overlays that are not busy.
307 * returns 0 if everything could be written to shadow registers.
308 * returns 1 if not everything could be written to shadow registers. */
309static int configure_dispc(void)
310{
311 struct overlay_cache_data *oc;
312 struct manager_cache_data *mc;
313 const int num_ovls = dss_feat_get_num_ovls();
314 const int num_mgrs = dss_feat_get_num_mgrs();
315 int i;
316 int r;
317 bool mgr_busy[MAX_DSS_MANAGERS];
318 bool mgr_go[MAX_DSS_MANAGERS];
319 bool busy;
320
321 r = 0;
322 busy = false;
323
324 for (i = 0; i < num_mgrs; i++) {
325 mgr_busy[i] = dispc_mgr_go_busy(i);
326 mgr_go[i] = false;
327 }
328
329 /* Commit overlay settings */
330 for (i = 0; i < num_ovls; ++i) {
331 oc = &dss_cache.overlay_cache[i];
332 mc = &dss_cache.manager_cache[oc->channel];
333
334 if (!oc->dirty)
335 continue;
336
337 if (mc->manual_update && !mc->do_manual_update)
338 continue;
339
340 if (mgr_busy[oc->channel]) {
341 busy = true;
342 continue;
343 }
344
345 r = configure_overlay(i);
346 if (r)
347 DSSERR("configure_overlay %d failed\n", i);
348
349 oc->dirty = false;
350 oc->shadow_dirty = true;
351 mgr_go[oc->channel] = true;
352 }
353
354 /* Commit manager settings */
355 for (i = 0; i < num_mgrs; ++i) {
356 mc = &dss_cache.manager_cache[i];
357
358 if (!mc->dirty)
359 continue;
360
361 if (mc->manual_update && !mc->do_manual_update)
362 continue;
363
364 if (mgr_busy[i]) {
365 busy = true;
366 continue;
367 }
368
369 configure_manager(i);
370 mc->dirty = false;
371 mc->shadow_dirty = true;
372 mgr_go[i] = true;
373 }
374
375 /* set GO */
376 for (i = 0; i < num_mgrs; ++i) {
377 mc = &dss_cache.manager_cache[i];
378
379 if (!mgr_go[i])
380 continue;
381
382 /* We don't need GO with manual update display. LCD iface will
383 * always be turned off after frame, and new settings will be
384 * taken in to use at next update */
385 if (!mc->manual_update)
386 dispc_mgr_go(i);
387 }
388
389 if (busy)
390 r = 1;
391 else
392 r = 0;
393
394 return r;
395}
396
397void dss_mgr_start_update(struct omap_overlay_manager *mgr)
398{
399 struct manager_cache_data *mc;
400 struct overlay_cache_data *oc;
401 const int num_ovls = dss_feat_get_num_ovls();
402 const int num_mgrs = dss_feat_get_num_mgrs();
403 int i;
404
405 mc = &dss_cache.manager_cache[mgr->id];
406
407 mc->do_manual_update = true;
408 configure_dispc();
409 mc->do_manual_update = false;
410
411 for (i = 0; i < num_ovls; ++i) {
412 oc = &dss_cache.overlay_cache[i];
413 if (oc->channel != mgr->id)
414 continue;
415
416 oc->shadow_dirty = false;
417 }
418
419 for (i = 0; i < num_mgrs; ++i) {
420 mc = &dss_cache.manager_cache[i];
421 if (mgr->id != i)
422 continue;
423
424 mc->shadow_dirty = false;
425 }
426
427 mgr->enable(mgr);
428}
429
430static void dss_apply_irq_handler(void *data, u32 mask)
431{
432 struct manager_cache_data *mc;
433 struct overlay_cache_data *oc;
434 const int num_ovls = dss_feat_get_num_ovls();
435 const int num_mgrs = dss_feat_get_num_mgrs();
436 int i, r;
437 bool mgr_busy[MAX_DSS_MANAGERS];
438 u32 irq_mask;
439
440 for (i = 0; i < num_mgrs; i++)
441 mgr_busy[i] = dispc_mgr_go_busy(i);
442
443 spin_lock(&dss_cache.lock);
444
445 for (i = 0; i < num_ovls; ++i) {
446 oc = &dss_cache.overlay_cache[i];
447 if (!mgr_busy[oc->channel])
448 oc->shadow_dirty = false;
449 }
450
451 for (i = 0; i < num_mgrs; ++i) {
452 mc = &dss_cache.manager_cache[i];
453 if (!mgr_busy[i])
454 mc->shadow_dirty = false;
455 }
456
457 r = configure_dispc();
458 if (r == 1)
459 goto end;
460
461 /* re-read busy flags */
462 for (i = 0; i < num_mgrs; i++)
463 mgr_busy[i] = dispc_mgr_go_busy(i);
464
465 /* keep running as long as there are busy managers, so that
466 * we can collect overlay-applied information */
467 for (i = 0; i < num_mgrs; ++i) {
468 if (mgr_busy[i])
469 goto end;
470 }
471
472 irq_mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_ODD |
473 DISPC_IRQ_EVSYNC_EVEN;
474 if (dss_has_feature(FEAT_MGR_LCD2))
475 irq_mask |= DISPC_IRQ_VSYNC2;
476
477 omap_dispc_unregister_isr(dss_apply_irq_handler, NULL, irq_mask);
478 dss_cache.irq_enabled = false;
479
480end:
481 spin_unlock(&dss_cache.lock);
482}
483
484static int omap_dss_mgr_apply_ovl(struct omap_overlay *ovl)
485{
486 struct overlay_cache_data *oc;
487 struct omap_dss_device *dssdev;
488
489 oc = &dss_cache.overlay_cache[ovl->id];
490
491 if (ovl->manager_changed) {
492 ovl->manager_changed = false;
493 ovl->info_dirty = true;
494 }
495
496 if (!overlay_enabled(ovl)) {
497 if (oc->enabled) {
498 oc->enabled = false;
499 oc->dirty = true;
500 }
501 return 0;
502 }
503
504 if (!ovl->info_dirty)
505 return 0;
506
507 dssdev = ovl->manager->device;
508
509 if (dss_check_overlay(ovl, dssdev)) {
510 if (oc->enabled) {
511 oc->enabled = false;
512 oc->dirty = true;
513 }
514 return -EINVAL;
515 }
516
517 ovl->info_dirty = false;
518 oc->dirty = true;
519 oc->info = ovl->info;
520
521 oc->channel = ovl->manager->id;
522
523 oc->enabled = true;
524
525 return 0;
526}
527
528static void omap_dss_mgr_apply_mgr(struct omap_overlay_manager *mgr)
529{
530 struct manager_cache_data *mc;
531
532 mc = &dss_cache.manager_cache[mgr->id];
533
534 if (mgr->device_changed) {
535 mgr->device_changed = false;
536 mgr->info_dirty = true;
537 }
538
539 if (!mgr->info_dirty)
540 return;
541
542 if (!mgr->device)
543 return;
544
545 mgr->info_dirty = false;
546 mc->dirty = true;
547 mc->info = mgr->info;
548
549 mc->manual_update = mgr_manual_update(mgr);
550}
551
552static void omap_dss_mgr_apply_ovl_fifos(struct omap_overlay *ovl)
553{
554 struct overlay_cache_data *oc;
555 struct omap_dss_device *dssdev;
556 u32 size, burst_size;
557
558 oc = &dss_cache.overlay_cache[ovl->id];
559
560 if (!oc->enabled)
561 return;
562
563 dssdev = ovl->manager->device;
564
565 size = dispc_ovl_get_fifo_size(ovl->id);
566
567 burst_size = dispc_ovl_get_burst_size(ovl->id);
568
569 switch (dssdev->type) {
570 case OMAP_DISPLAY_TYPE_DPI:
571 case OMAP_DISPLAY_TYPE_DBI:
572 case OMAP_DISPLAY_TYPE_SDI:
573 case OMAP_DISPLAY_TYPE_VENC:
574 case OMAP_DISPLAY_TYPE_HDMI:
575 default_get_overlay_fifo_thresholds(ovl->id, size,
576 burst_size, &oc->fifo_low,
577 &oc->fifo_high);
578 break;
579#ifdef CONFIG_OMAP2_DSS_DSI
580 case OMAP_DISPLAY_TYPE_DSI:
581 dsi_get_overlay_fifo_thresholds(ovl->id, size,
582 burst_size, &oc->fifo_low,
583 &oc->fifo_high);
584 break;
585#endif
586 default:
587 BUG();
588 }
589}
590
591int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
592{
593 int i, r;
594 unsigned long flags;
595
596 DSSDBG("omap_dss_mgr_apply(%s)\n", mgr->name);
597
598 r = dispc_runtime_get();
599 if (r)
600 return r;
601
602 spin_lock_irqsave(&dss_cache.lock, flags);
603
604 /* Configure overlays */
605 for (i = 0; i < mgr->num_overlays; ++i) {
606 struct omap_overlay *ovl;
607
608 ovl = mgr->overlays[i];
609
610 if (ovl->manager != mgr)
611 continue;
612
613 omap_dss_mgr_apply_ovl(ovl);
614 }
615
616 /* Configure manager */
617 omap_dss_mgr_apply_mgr(mgr);
618
619 /* Configure overlay fifos */
620 for (i = 0; i < mgr->num_overlays; ++i) {
621 struct omap_overlay *ovl;
622
623 ovl = mgr->overlays[i];
624
625 if (ovl->manager != mgr)
626 continue;
627
628 omap_dss_mgr_apply_ovl_fifos(ovl);
629 }
630
631 r = 0;
632 if (!dss_cache.irq_enabled) {
633 u32 mask;
634
635 mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_ODD |
636 DISPC_IRQ_EVSYNC_EVEN;
637 if (dss_has_feature(FEAT_MGR_LCD2))
638 mask |= DISPC_IRQ_VSYNC2;
639
640 r = omap_dispc_register_isr(dss_apply_irq_handler, NULL, mask);
641
642 if (r)
643 DSSERR("failed to register apply isr\n");
644
645 dss_cache.irq_enabled = true;
646 }
647
648 configure_dispc();
649
650 spin_unlock_irqrestore(&dss_cache.lock, flags);
651
652 dispc_runtime_put();
653
654 return r;
655}
656
diff --git a/drivers/video/omap2/dss/core.c b/drivers/video/omap2/dss/core.c
index 86ec12e16c7c..5c464304cc8d 100644
--- a/drivers/video/omap2/dss/core.c
+++ b/drivers/video/omap2/dss/core.c
@@ -178,6 +178,8 @@ static int omap_dss_probe(struct platform_device *pdev)
178 178
179 dss_features_init(); 179 dss_features_init();
180 180
181 dss_apply_init();
182
181 dss_init_overlay_managers(pdev); 183 dss_init_overlay_managers(pdev);
182 dss_init_overlays(pdev); 184 dss_init_overlays(pdev);
183 185
diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h
index 5ac72433be57..e6f961aa4362 100644
--- a/drivers/video/omap2/dss/dss.h
+++ b/drivers/video/omap2/dss/dss.h
@@ -163,6 +163,13 @@ struct bus_type *dss_get_bus(void);
163struct regulator *dss_get_vdds_dsi(void); 163struct regulator *dss_get_vdds_dsi(void);
164struct regulator *dss_get_vdds_sdi(void); 164struct regulator *dss_get_vdds_sdi(void);
165 165
166/* apply */
167void dss_apply_init(void);
168int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr);
169int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl);
170void dss_mgr_start_update(struct omap_overlay_manager *mgr);
171int omap_dss_mgr_apply(struct omap_overlay_manager *mgr);
172
166/* display */ 173/* display */
167int dss_suspend_all_devices(void); 174int dss_suspend_all_devices(void);
168int dss_resume_all_devices(void); 175int dss_resume_all_devices(void);
@@ -181,8 +188,6 @@ void default_get_overlay_fifo_thresholds(enum omap_plane plane,
181/* manager */ 188/* manager */
182int dss_init_overlay_managers(struct platform_device *pdev); 189int dss_init_overlay_managers(struct platform_device *pdev);
183void dss_uninit_overlay_managers(struct platform_device *pdev); 190void dss_uninit_overlay_managers(struct platform_device *pdev);
184int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl);
185void dss_mgr_start_update(struct omap_overlay_manager *mgr);
186 191
187/* overlay */ 192/* overlay */
188void dss_init_overlays(struct platform_device *pdev); 193void dss_init_overlays(struct platform_device *pdev);
diff --git a/drivers/video/omap2/dss/manager.c b/drivers/video/omap2/dss/manager.c
index d2bdd652d595..f9e691b4ba4a 100644
--- a/drivers/video/omap2/dss/manager.c
+++ b/drivers/video/omap2/dss/manager.c
@@ -26,11 +26,9 @@
26#include <linux/slab.h> 26#include <linux/slab.h>
27#include <linux/module.h> 27#include <linux/module.h>
28#include <linux/platform_device.h> 28#include <linux/platform_device.h>
29#include <linux/spinlock.h>
30#include <linux/jiffies.h> 29#include <linux/jiffies.h>
31 30
32#include <video/omapdss.h> 31#include <video/omapdss.h>
33#include <plat/cpu.h>
34 32
35#include "dss.h" 33#include "dss.h"
36#include "dss_features.h" 34#include "dss_features.h"
@@ -469,85 +467,6 @@ static struct kobj_type manager_ktype = {
469 .default_attrs = manager_sysfs_attrs, 467 .default_attrs = manager_sysfs_attrs,
470}; 468};
471 469
472/*
473 * We have 4 levels of cache for the dispc settings. First two are in SW and
474 * the latter two in HW.
475 *
476 * +--------------------+
477 * |overlay/manager_info|
478 * +--------------------+
479 * v
480 * apply()
481 * v
482 * +--------------------+
483 * | dss_cache |
484 * +--------------------+
485 * v
486 * configure()
487 * v
488 * +--------------------+
489 * | shadow registers |
490 * +--------------------+
491 * v
492 * VFP or lcd/digit_enable
493 * v
494 * +--------------------+
495 * | registers |
496 * +--------------------+
497 */
498
499struct overlay_cache_data {
500 /* If true, cache changed, but not written to shadow registers. Set
501 * in apply(), cleared when registers written. */
502 bool dirty;
503 /* If true, shadow registers contain changed values not yet in real
504 * registers. Set when writing to shadow registers, cleared at
505 * VSYNC/EVSYNC */
506 bool shadow_dirty;
507
508 bool enabled;
509
510 struct omap_overlay_info info;
511
512 enum omap_channel channel;
513
514 u32 fifo_low;
515 u32 fifo_high;
516};
517
518struct manager_cache_data {
519 /* If true, cache changed, but not written to shadow registers. Set
520 * in apply(), cleared when registers written. */
521 bool dirty;
522 /* If true, shadow registers contain changed values not yet in real
523 * registers. Set when writing to shadow registers, cleared at
524 * VSYNC/EVSYNC */
525 bool shadow_dirty;
526
527 struct omap_overlay_manager_info info;
528
529 bool manual_update;
530 bool do_manual_update;
531};
532
533static struct {
534 spinlock_t lock;
535 struct overlay_cache_data overlay_cache[MAX_DSS_OVERLAYS];
536 struct manager_cache_data manager_cache[MAX_DSS_MANAGERS];
537
538 bool irq_enabled;
539} dss_cache;
540
541static bool ovl_manual_update(struct omap_overlay *ovl)
542{
543 return ovl->manager->device->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE;
544}
545
546static bool mgr_manual_update(struct omap_overlay_manager *mgr)
547{
548 return mgr->device->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE;
549}
550
551static int omap_dss_set_device(struct omap_overlay_manager *mgr, 470static int omap_dss_set_device(struct omap_overlay_manager *mgr,
552 struct omap_dss_device *dssdev) 471 struct omap_dss_device *dssdev)
553{ 472{
@@ -623,544 +542,6 @@ static int dss_mgr_wait_for_vsync(struct omap_overlay_manager *mgr)
623 return omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout); 542 return omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
624} 543}
625 544
626static int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr)
627{
628 unsigned long timeout = msecs_to_jiffies(500);
629 struct manager_cache_data *mc;
630 u32 irq;
631 int r;
632 int i;
633 struct omap_dss_device *dssdev = mgr->device;
634
635 if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
636 return 0;
637
638 if (mgr_manual_update(mgr))
639 return 0;
640
641 if (dssdev->type == OMAP_DISPLAY_TYPE_VENC
642 || dssdev->type == OMAP_DISPLAY_TYPE_HDMI) {
643 irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN;
644 } else {
645 irq = (dssdev->manager->id == OMAP_DSS_CHANNEL_LCD) ?
646 DISPC_IRQ_VSYNC : DISPC_IRQ_VSYNC2;
647 }
648
649 mc = &dss_cache.manager_cache[mgr->id];
650 i = 0;
651 while (1) {
652 unsigned long flags;
653 bool shadow_dirty, dirty;
654
655 spin_lock_irqsave(&dss_cache.lock, flags);
656 dirty = mc->dirty;
657 shadow_dirty = mc->shadow_dirty;
658 spin_unlock_irqrestore(&dss_cache.lock, flags);
659
660 if (!dirty && !shadow_dirty) {
661 r = 0;
662 break;
663 }
664
665 /* 4 iterations is the worst case:
666 * 1 - initial iteration, dirty = true (between VFP and VSYNC)
667 * 2 - first VSYNC, dirty = true
668 * 3 - dirty = false, shadow_dirty = true
669 * 4 - shadow_dirty = false */
670 if (i++ == 3) {
671 DSSERR("mgr(%d)->wait_for_go() not finishing\n",
672 mgr->id);
673 r = 0;
674 break;
675 }
676
677 r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
678 if (r == -ERESTARTSYS)
679 break;
680
681 if (r) {
682 DSSERR("mgr(%d)->wait_for_go() timeout\n", mgr->id);
683 break;
684 }
685 }
686
687 return r;
688}
689
690int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl)
691{
692 unsigned long timeout = msecs_to_jiffies(500);
693 struct overlay_cache_data *oc;
694 struct omap_dss_device *dssdev;
695 u32 irq;
696 int r;
697 int i;
698
699 if (!ovl->manager)
700 return 0;
701
702 dssdev = ovl->manager->device;
703
704 if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
705 return 0;
706
707 if (ovl_manual_update(ovl))
708 return 0;
709
710 if (dssdev->type == OMAP_DISPLAY_TYPE_VENC
711 || dssdev->type == OMAP_DISPLAY_TYPE_HDMI) {
712 irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN;
713 } else {
714 irq = (dssdev->manager->id == OMAP_DSS_CHANNEL_LCD) ?
715 DISPC_IRQ_VSYNC : DISPC_IRQ_VSYNC2;
716 }
717
718 oc = &dss_cache.overlay_cache[ovl->id];
719 i = 0;
720 while (1) {
721 unsigned long flags;
722 bool shadow_dirty, dirty;
723
724 spin_lock_irqsave(&dss_cache.lock, flags);
725 dirty = oc->dirty;
726 shadow_dirty = oc->shadow_dirty;
727 spin_unlock_irqrestore(&dss_cache.lock, flags);
728
729 if (!dirty && !shadow_dirty) {
730 r = 0;
731 break;
732 }
733
734 /* 4 iterations is the worst case:
735 * 1 - initial iteration, dirty = true (between VFP and VSYNC)
736 * 2 - first VSYNC, dirty = true
737 * 3 - dirty = false, shadow_dirty = true
738 * 4 - shadow_dirty = false */
739 if (i++ == 3) {
740 DSSERR("ovl(%d)->wait_for_go() not finishing\n",
741 ovl->id);
742 r = 0;
743 break;
744 }
745
746 r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
747 if (r == -ERESTARTSYS)
748 break;
749
750 if (r) {
751 DSSERR("ovl(%d)->wait_for_go() timeout\n", ovl->id);
752 break;
753 }
754 }
755
756 return r;
757}
758
759static int overlay_enabled(struct omap_overlay *ovl)
760{
761 return ovl->info.enabled && ovl->manager && ovl->manager->device;
762}
763
764static int configure_overlay(enum omap_plane plane)
765{
766 struct omap_overlay *ovl;
767 struct overlay_cache_data *c;
768 struct omap_overlay_info *oi;
769 bool ilace, replication;
770 int r;
771
772 DSSDBGF("%d", plane);
773
774 c = &dss_cache.overlay_cache[plane];
775 oi = &c->info;
776
777 if (!c->enabled) {
778 dispc_ovl_enable(plane, 0);
779 return 0;
780 }
781
782 ovl = omap_dss_get_overlay(plane);
783
784 replication = dss_use_replication(ovl->manager->device, oi->color_mode);
785
786 ilace = ovl->manager->device->type == OMAP_DISPLAY_TYPE_VENC;
787
788 dispc_ovl_set_channel_out(plane, c->channel);
789
790 r = dispc_ovl_setup(plane, oi, ilace, replication);
791 if (r) {
792 /* this shouldn't happen */
793 DSSERR("dispc_ovl_setup failed for ovl %d\n", plane);
794 dispc_ovl_enable(plane, 0);
795 return r;
796 }
797
798 dispc_ovl_set_fifo_threshold(plane, c->fifo_low, c->fifo_high);
799
800 dispc_ovl_enable(plane, 1);
801
802 return 0;
803}
804
805static void configure_manager(enum omap_channel channel)
806{
807 struct omap_overlay_manager_info *mi;
808
809 DSSDBGF("%d", channel);
810
811 /* picking info from the cache */
812 mi = &dss_cache.manager_cache[channel].info;
813
814 dispc_mgr_setup(channel, mi);
815}
816
817/* configure_dispc() tries to write values from cache to shadow registers.
818 * It writes only to those managers/overlays that are not busy.
819 * returns 0 if everything could be written to shadow registers.
820 * returns 1 if not everything could be written to shadow registers. */
821static int configure_dispc(void)
822{
823 struct overlay_cache_data *oc;
824 struct manager_cache_data *mc;
825 const int num_ovls = dss_feat_get_num_ovls();
826 const int num_mgrs = dss_feat_get_num_mgrs();
827 int i;
828 int r;
829 bool mgr_busy[MAX_DSS_MANAGERS];
830 bool mgr_go[MAX_DSS_MANAGERS];
831 bool busy;
832
833 r = 0;
834 busy = false;
835
836 for (i = 0; i < num_mgrs; i++) {
837 mgr_busy[i] = dispc_mgr_go_busy(i);
838 mgr_go[i] = false;
839 }
840
841 /* Commit overlay settings */
842 for (i = 0; i < num_ovls; ++i) {
843 oc = &dss_cache.overlay_cache[i];
844 mc = &dss_cache.manager_cache[oc->channel];
845
846 if (!oc->dirty)
847 continue;
848
849 if (mc->manual_update && !mc->do_manual_update)
850 continue;
851
852 if (mgr_busy[oc->channel]) {
853 busy = true;
854 continue;
855 }
856
857 r = configure_overlay(i);
858 if (r)
859 DSSERR("configure_overlay %d failed\n", i);
860
861 oc->dirty = false;
862 oc->shadow_dirty = true;
863 mgr_go[oc->channel] = true;
864 }
865
866 /* Commit manager settings */
867 for (i = 0; i < num_mgrs; ++i) {
868 mc = &dss_cache.manager_cache[i];
869
870 if (!mc->dirty)
871 continue;
872
873 if (mc->manual_update && !mc->do_manual_update)
874 continue;
875
876 if (mgr_busy[i]) {
877 busy = true;
878 continue;
879 }
880
881 configure_manager(i);
882 mc->dirty = false;
883 mc->shadow_dirty = true;
884 mgr_go[i] = true;
885 }
886
887 /* set GO */
888 for (i = 0; i < num_mgrs; ++i) {
889 mc = &dss_cache.manager_cache[i];
890
891 if (!mgr_go[i])
892 continue;
893
894 /* We don't need GO with manual update display. LCD iface will
895 * always be turned off after frame, and new settings will be
896 * taken in to use at next update */
897 if (!mc->manual_update)
898 dispc_mgr_go(i);
899 }
900
901 if (busy)
902 r = 1;
903 else
904 r = 0;
905
906 return r;
907}
908
909void dss_mgr_start_update(struct omap_overlay_manager *mgr)
910{
911 struct manager_cache_data *mc;
912 struct overlay_cache_data *oc;
913 const int num_ovls = dss_feat_get_num_ovls();
914 const int num_mgrs = dss_feat_get_num_mgrs();
915 int i;
916
917 mc = &dss_cache.manager_cache[mgr->id];
918
919 mc->do_manual_update = true;
920 configure_dispc();
921 mc->do_manual_update = false;
922
923 for (i = 0; i < num_ovls; ++i) {
924 oc = &dss_cache.overlay_cache[i];
925 if (oc->channel != mgr->id)
926 continue;
927
928 oc->shadow_dirty = false;
929 }
930
931 for (i = 0; i < num_mgrs; ++i) {
932 mc = &dss_cache.manager_cache[i];
933 if (mgr->id != i)
934 continue;
935
936 mc->shadow_dirty = false;
937 }
938
939 mgr->enable(mgr);
940}
941
942static void dss_apply_irq_handler(void *data, u32 mask)
943{
944 struct manager_cache_data *mc;
945 struct overlay_cache_data *oc;
946 const int num_ovls = dss_feat_get_num_ovls();
947 const int num_mgrs = dss_feat_get_num_mgrs();
948 int i, r;
949 bool mgr_busy[MAX_DSS_MANAGERS];
950 u32 irq_mask;
951
952 for (i = 0; i < num_mgrs; i++)
953 mgr_busy[i] = dispc_mgr_go_busy(i);
954
955 spin_lock(&dss_cache.lock);
956
957 for (i = 0; i < num_ovls; ++i) {
958 oc = &dss_cache.overlay_cache[i];
959 if (!mgr_busy[oc->channel])
960 oc->shadow_dirty = false;
961 }
962
963 for (i = 0; i < num_mgrs; ++i) {
964 mc = &dss_cache.manager_cache[i];
965 if (!mgr_busy[i])
966 mc->shadow_dirty = false;
967 }
968
969 r = configure_dispc();
970 if (r == 1)
971 goto end;
972
973 /* re-read busy flags */
974 for (i = 0; i < num_mgrs; i++)
975 mgr_busy[i] = dispc_mgr_go_busy(i);
976
977 /* keep running as long as there are busy managers, so that
978 * we can collect overlay-applied information */
979 for (i = 0; i < num_mgrs; ++i) {
980 if (mgr_busy[i])
981 goto end;
982 }
983
984 irq_mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_ODD |
985 DISPC_IRQ_EVSYNC_EVEN;
986 if (dss_has_feature(FEAT_MGR_LCD2))
987 irq_mask |= DISPC_IRQ_VSYNC2;
988
989 omap_dispc_unregister_isr(dss_apply_irq_handler, NULL, irq_mask);
990 dss_cache.irq_enabled = false;
991
992end:
993 spin_unlock(&dss_cache.lock);
994}
995
996static int omap_dss_mgr_apply_ovl(struct omap_overlay *ovl)
997{
998 struct overlay_cache_data *oc;
999 struct omap_dss_device *dssdev;
1000
1001 oc = &dss_cache.overlay_cache[ovl->id];
1002
1003 if (ovl->manager_changed) {
1004 ovl->manager_changed = false;
1005 ovl->info_dirty = true;
1006 }
1007
1008 if (!overlay_enabled(ovl)) {
1009 if (oc->enabled) {
1010 oc->enabled = false;
1011 oc->dirty = true;
1012 }
1013 return 0;
1014 }
1015
1016 if (!ovl->info_dirty)
1017 return 0;
1018
1019 dssdev = ovl->manager->device;
1020
1021 if (dss_check_overlay(ovl, dssdev)) {
1022 if (oc->enabled) {
1023 oc->enabled = false;
1024 oc->dirty = true;
1025 }
1026 return -EINVAL;
1027 }
1028
1029 ovl->info_dirty = false;
1030 oc->dirty = true;
1031 oc->info = ovl->info;
1032
1033 oc->channel = ovl->manager->id;
1034
1035 oc->enabled = true;
1036
1037 return 0;
1038}
1039
1040static void omap_dss_mgr_apply_mgr(struct omap_overlay_manager *mgr)
1041{
1042 struct manager_cache_data *mc;
1043
1044 mc = &dss_cache.manager_cache[mgr->id];
1045
1046 if (mgr->device_changed) {
1047 mgr->device_changed = false;
1048 mgr->info_dirty = true;
1049 }
1050
1051 if (!mgr->info_dirty)
1052 return;
1053
1054 if (!mgr->device)
1055 return;
1056
1057 mgr->info_dirty = false;
1058 mc->dirty = true;
1059 mc->info = mgr->info;
1060
1061 mc->manual_update = mgr_manual_update(mgr);
1062}
1063
1064static void omap_dss_mgr_apply_ovl_fifos(struct omap_overlay *ovl)
1065{
1066 struct overlay_cache_data *oc;
1067 struct omap_dss_device *dssdev;
1068 u32 size, burst_size;
1069
1070 oc = &dss_cache.overlay_cache[ovl->id];
1071
1072 if (!oc->enabled)
1073 return;
1074
1075 dssdev = ovl->manager->device;
1076
1077 size = dispc_ovl_get_fifo_size(ovl->id);
1078
1079 burst_size = dispc_ovl_get_burst_size(ovl->id);
1080
1081 switch (dssdev->type) {
1082 case OMAP_DISPLAY_TYPE_DPI:
1083 case OMAP_DISPLAY_TYPE_DBI:
1084 case OMAP_DISPLAY_TYPE_SDI:
1085 case OMAP_DISPLAY_TYPE_VENC:
1086 case OMAP_DISPLAY_TYPE_HDMI:
1087 default_get_overlay_fifo_thresholds(ovl->id, size,
1088 burst_size, &oc->fifo_low,
1089 &oc->fifo_high);
1090 break;
1091#ifdef CONFIG_OMAP2_DSS_DSI
1092 case OMAP_DISPLAY_TYPE_DSI:
1093 dsi_get_overlay_fifo_thresholds(ovl->id, size,
1094 burst_size, &oc->fifo_low,
1095 &oc->fifo_high);
1096 break;
1097#endif
1098 default:
1099 BUG();
1100 }
1101}
1102
1103static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
1104{
1105 int i, r;
1106 unsigned long flags;
1107
1108 DSSDBG("omap_dss_mgr_apply(%s)\n", mgr->name);
1109
1110 r = dispc_runtime_get();
1111 if (r)
1112 return r;
1113
1114 spin_lock_irqsave(&dss_cache.lock, flags);
1115
1116 /* Configure overlays */
1117 for (i = 0; i < mgr->num_overlays; ++i) {
1118 struct omap_overlay *ovl;
1119
1120 ovl = mgr->overlays[i];
1121
1122 if (ovl->manager != mgr)
1123 continue;
1124
1125 omap_dss_mgr_apply_ovl(ovl);
1126 }
1127
1128 /* Configure manager */
1129 omap_dss_mgr_apply_mgr(mgr);
1130
1131 /* Configure overlay fifos */
1132 for (i = 0; i < mgr->num_overlays; ++i) {
1133 struct omap_overlay *ovl;
1134
1135 ovl = mgr->overlays[i];
1136
1137 if (ovl->manager != mgr)
1138 continue;
1139
1140 omap_dss_mgr_apply_ovl_fifos(ovl);
1141 }
1142
1143 r = 0;
1144 if (!dss_cache.irq_enabled) {
1145 u32 mask;
1146
1147 mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_ODD |
1148 DISPC_IRQ_EVSYNC_EVEN;
1149 if (dss_has_feature(FEAT_MGR_LCD2))
1150 mask |= DISPC_IRQ_VSYNC2;
1151
1152 r = omap_dispc_register_isr(dss_apply_irq_handler, NULL, mask);
1153 dss_cache.irq_enabled = true;
1154 }
1155 configure_dispc();
1156
1157 spin_unlock_irqrestore(&dss_cache.lock, flags);
1158
1159 dispc_runtime_put();
1160
1161 return r;
1162}
1163
1164static int dss_check_manager(struct omap_overlay_manager *mgr) 545static int dss_check_manager(struct omap_overlay_manager *mgr)
1165{ 546{
1166 if (dss_has_feature(FEAT_ALPHA_FIXED_ZORDER)) { 547 if (dss_has_feature(FEAT_ALPHA_FIXED_ZORDER)) {
@@ -1226,8 +607,6 @@ int dss_init_overlay_managers(struct platform_device *pdev)
1226{ 607{
1227 int i, r; 608 int i, r;
1228 609
1229 spin_lock_init(&dss_cache.lock);
1230
1231 INIT_LIST_HEAD(&manager_list); 610 INIT_LIST_HEAD(&manager_list);
1232 611
1233 num_managers = 0; 612 num_managers = 0;