blob: c73742e3b43dd658a18493fd2f0f0e32bc4543a3 [file] [log] [blame]
Tomi Valkeinen58f255482011-11-04 09:48:54 +02001/*
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
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +020044 * write_regs()
Tomi Valkeinen58f255482011-11-04 09:48:54 +020045 * v
46 * +--------------------+
47 * | shadow registers |
48 * +--------------------+
49 * v
50 * VFP or lcd/digit_enable
51 * v
52 * +--------------------+
53 * | registers |
54 * +--------------------+
55 */
56
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +020057struct ovl_priv_data {
Tomi Valkeinen58f255482011-11-04 09:48:54 +020058 /* 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;
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +020093 struct ovl_priv_data ovl_priv_data_array[MAX_DSS_OVERLAYS];
Tomi Valkeinen58f255482011-11-04 09:48:54 +020094 struct manager_cache_data manager_cache[MAX_DSS_MANAGERS];
95
96 bool irq_enabled;
97} dss_cache;
98
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +020099static struct ovl_priv_data *get_ovl_priv(struct omap_overlay *ovl)
100{
101 return &dss_cache.ovl_priv_data_array[ovl->id];
102}
103
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200104void dss_apply_init(void)
105{
106 spin_lock_init(&dss_cache.lock);
107}
108
109static bool ovl_manual_update(struct omap_overlay *ovl)
110{
111 return ovl->manager->device->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE;
112}
113
114static bool mgr_manual_update(struct omap_overlay_manager *mgr)
115{
116 return mgr->device->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE;
117}
118
119static int overlay_enabled(struct omap_overlay *ovl)
120{
121 return ovl->info.enabled && ovl->manager && ovl->manager->device;
122}
123
124int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr)
125{
126 unsigned long timeout = msecs_to_jiffies(500);
127 struct manager_cache_data *mc;
128 u32 irq;
129 int r;
130 int i;
131 struct omap_dss_device *dssdev = mgr->device;
132
133 if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
134 return 0;
135
136 if (mgr_manual_update(mgr))
137 return 0;
138
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200139 irq = dispc_mgr_get_vsync_irq(mgr->id);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200140
141 mc = &dss_cache.manager_cache[mgr->id];
142 i = 0;
143 while (1) {
144 unsigned long flags;
145 bool shadow_dirty, dirty;
146
147 spin_lock_irqsave(&dss_cache.lock, flags);
148 dirty = mc->dirty;
149 shadow_dirty = mc->shadow_dirty;
150 spin_unlock_irqrestore(&dss_cache.lock, flags);
151
152 if (!dirty && !shadow_dirty) {
153 r = 0;
154 break;
155 }
156
157 /* 4 iterations is the worst case:
158 * 1 - initial iteration, dirty = true (between VFP and VSYNC)
159 * 2 - first VSYNC, dirty = true
160 * 3 - dirty = false, shadow_dirty = true
161 * 4 - shadow_dirty = false */
162 if (i++ == 3) {
163 DSSERR("mgr(%d)->wait_for_go() not finishing\n",
164 mgr->id);
165 r = 0;
166 break;
167 }
168
169 r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
170 if (r == -ERESTARTSYS)
171 break;
172
173 if (r) {
174 DSSERR("mgr(%d)->wait_for_go() timeout\n", mgr->id);
175 break;
176 }
177 }
178
179 return r;
180}
181
182int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl)
183{
184 unsigned long timeout = msecs_to_jiffies(500);
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200185 struct ovl_priv_data *op;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200186 struct omap_dss_device *dssdev;
187 u32 irq;
188 int r;
189 int i;
190
191 if (!ovl->manager)
192 return 0;
193
194 dssdev = ovl->manager->device;
195
196 if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
197 return 0;
198
199 if (ovl_manual_update(ovl))
200 return 0;
201
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200202 irq = dispc_mgr_get_vsync_irq(ovl->manager->id);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200203
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200204 op = get_ovl_priv(ovl);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200205 i = 0;
206 while (1) {
207 unsigned long flags;
208 bool shadow_dirty, dirty;
209
210 spin_lock_irqsave(&dss_cache.lock, flags);
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200211 dirty = op->dirty;
212 shadow_dirty = op->shadow_dirty;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200213 spin_unlock_irqrestore(&dss_cache.lock, flags);
214
215 if (!dirty && !shadow_dirty) {
216 r = 0;
217 break;
218 }
219
220 /* 4 iterations is the worst case:
221 * 1 - initial iteration, dirty = true (between VFP and VSYNC)
222 * 2 - first VSYNC, dirty = true
223 * 3 - dirty = false, shadow_dirty = true
224 * 4 - shadow_dirty = false */
225 if (i++ == 3) {
226 DSSERR("ovl(%d)->wait_for_go() not finishing\n",
227 ovl->id);
228 r = 0;
229 break;
230 }
231
232 r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
233 if (r == -ERESTARTSYS)
234 break;
235
236 if (r) {
237 DSSERR("ovl(%d)->wait_for_go() timeout\n", ovl->id);
238 break;
239 }
240 }
241
242 return r;
243}
244
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200245static int dss_ovl_write_regs(struct omap_overlay *ovl)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200246{
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200247 struct ovl_priv_data *op;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200248 struct omap_overlay_info *oi;
249 bool ilace, replication;
250 int r;
251
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200252 DSSDBGF("%d", ovl->id);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200253
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200254 op = get_ovl_priv(ovl);
255 oi = &op->info;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200256
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200257 if (!op->enabled) {
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200258 dispc_ovl_enable(ovl->id, 0);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200259 return 0;
260 }
261
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200262 replication = dss_use_replication(ovl->manager->device, oi->color_mode);
263
264 ilace = ovl->manager->device->type == OMAP_DISPLAY_TYPE_VENC;
265
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200266 dispc_ovl_set_channel_out(ovl->id, op->channel);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200267
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200268 r = dispc_ovl_setup(ovl->id, oi, ilace, replication);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200269 if (r) {
270 /* this shouldn't happen */
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200271 DSSERR("dispc_ovl_setup failed for ovl %d\n", ovl->id);
272 dispc_ovl_enable(ovl->id, 0);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200273 return r;
274 }
275
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200276 dispc_ovl_set_fifo_threshold(ovl->id, op->fifo_low, op->fifo_high);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200277
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200278 dispc_ovl_enable(ovl->id, 1);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200279
280 return 0;
281}
282
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200283static void dss_mgr_write_regs(struct omap_overlay_manager *mgr)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200284{
285 struct omap_overlay_manager_info *mi;
286
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200287 DSSDBGF("%d", mgr->id);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200288
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200289 mi = &dss_cache.manager_cache[mgr->id].info;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200290
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200291 dispc_mgr_setup(mgr->id, mi);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200292}
293
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200294/* dss_write_regs() tries to write values from cache to shadow registers.
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200295 * It writes only to those managers/overlays that are not busy.
296 * returns 0 if everything could be written to shadow registers.
297 * returns 1 if not everything could be written to shadow registers. */
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200298static int dss_write_regs(void)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200299{
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200300 struct omap_overlay *ovl;
301 struct omap_overlay_manager *mgr;
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200302 struct ovl_priv_data *op;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200303 struct manager_cache_data *mc;
304 const int num_ovls = dss_feat_get_num_ovls();
305 const int num_mgrs = dss_feat_get_num_mgrs();
306 int i;
307 int r;
308 bool mgr_busy[MAX_DSS_MANAGERS];
309 bool mgr_go[MAX_DSS_MANAGERS];
310 bool busy;
311
312 r = 0;
313 busy = false;
314
315 for (i = 0; i < num_mgrs; i++) {
316 mgr_busy[i] = dispc_mgr_go_busy(i);
317 mgr_go[i] = false;
318 }
319
320 /* Commit overlay settings */
321 for (i = 0; i < num_ovls; ++i) {
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200322 ovl = omap_dss_get_overlay(i);
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200323 op = get_ovl_priv(ovl);
324 mc = &dss_cache.manager_cache[op->channel];
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200325
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200326 if (!op->dirty)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200327 continue;
328
329 if (mc->manual_update && !mc->do_manual_update)
330 continue;
331
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200332 if (mgr_busy[op->channel]) {
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200333 busy = true;
334 continue;
335 }
336
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200337 r = dss_ovl_write_regs(ovl);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200338 if (r)
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200339 DSSERR("dss_ovl_write_regs %d failed\n", i);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200340
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200341 op->dirty = false;
342 op->shadow_dirty = true;
343 mgr_go[op->channel] = true;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200344 }
345
346 /* Commit manager settings */
347 for (i = 0; i < num_mgrs; ++i) {
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200348 mgr = omap_dss_get_overlay_manager(i);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200349 mc = &dss_cache.manager_cache[i];
350
351 if (!mc->dirty)
352 continue;
353
354 if (mc->manual_update && !mc->do_manual_update)
355 continue;
356
357 if (mgr_busy[i]) {
358 busy = true;
359 continue;
360 }
361
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200362 dss_mgr_write_regs(mgr);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200363 mc->dirty = false;
364 mc->shadow_dirty = true;
365 mgr_go[i] = true;
366 }
367
368 /* set GO */
369 for (i = 0; i < num_mgrs; ++i) {
370 mc = &dss_cache.manager_cache[i];
371
372 if (!mgr_go[i])
373 continue;
374
375 /* We don't need GO with manual update display. LCD iface will
376 * always be turned off after frame, and new settings will be
377 * taken in to use at next update */
378 if (!mc->manual_update)
379 dispc_mgr_go(i);
380 }
381
382 if (busy)
383 r = 1;
384 else
385 r = 0;
386
387 return r;
388}
389
390void dss_mgr_start_update(struct omap_overlay_manager *mgr)
391{
392 struct manager_cache_data *mc;
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200393 struct ovl_priv_data *op;
Tomi Valkeinen07e327c2011-11-05 10:59:59 +0200394 struct omap_overlay *ovl;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200395
396 mc = &dss_cache.manager_cache[mgr->id];
397
398 mc->do_manual_update = true;
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200399 dss_write_regs();
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200400 mc->do_manual_update = false;
401
Tomi Valkeinen07e327c2011-11-05 10:59:59 +0200402 list_for_each_entry(ovl, &mgr->overlays, list) {
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200403 op = get_ovl_priv(ovl);
404 op->shadow_dirty = false;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200405 }
406
Tomi Valkeinen6e53ca92011-11-01 13:58:50 +0200407 mc = &dss_cache.manager_cache[mgr->id];
408 mc->shadow_dirty = false;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200409
Tomi Valkeinen7797c6d2011-11-04 10:22:46 +0200410 dispc_mgr_enable(mgr->id, true);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200411}
412
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200413static void dss_apply_irq_handler(void *data, u32 mask);
414
415static void dss_register_vsync_isr(void)
416{
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200417 const int num_mgrs = dss_feat_get_num_mgrs();
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200418 u32 mask;
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200419 int r, i;
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200420
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200421 mask = 0;
422 for (i = 0; i < num_mgrs; ++i)
423 mask |= dispc_mgr_get_vsync_irq(i);
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200424
425 r = omap_dispc_register_isr(dss_apply_irq_handler, NULL, mask);
426 WARN_ON(r);
427
428 dss_cache.irq_enabled = true;
429}
430
431static void dss_unregister_vsync_isr(void)
432{
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200433 const int num_mgrs = dss_feat_get_num_mgrs();
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200434 u32 mask;
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200435 int r, i;
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200436
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200437 mask = 0;
438 for (i = 0; i < num_mgrs; ++i)
439 mask |= dispc_mgr_get_vsync_irq(i);
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200440
441 r = omap_dispc_unregister_isr(dss_apply_irq_handler, NULL, mask);
442 WARN_ON(r);
443
444 dss_cache.irq_enabled = false;
445}
446
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200447static void dss_apply_irq_handler(void *data, u32 mask)
448{
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200449 struct omap_overlay *ovl;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200450 struct manager_cache_data *mc;
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200451 struct ovl_priv_data *op;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200452 const int num_ovls = dss_feat_get_num_ovls();
453 const int num_mgrs = dss_feat_get_num_mgrs();
454 int i, r;
455 bool mgr_busy[MAX_DSS_MANAGERS];
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200456
457 for (i = 0; i < num_mgrs; i++)
458 mgr_busy[i] = dispc_mgr_go_busy(i);
459
460 spin_lock(&dss_cache.lock);
461
462 for (i = 0; i < num_ovls; ++i) {
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200463 ovl = omap_dss_get_overlay(i);
464 op = get_ovl_priv(ovl);
465 if (!mgr_busy[op->channel])
466 op->shadow_dirty = false;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200467 }
468
469 for (i = 0; i < num_mgrs; ++i) {
470 mc = &dss_cache.manager_cache[i];
471 if (!mgr_busy[i])
472 mc->shadow_dirty = false;
473 }
474
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200475 r = dss_write_regs();
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200476 if (r == 1)
477 goto end;
478
479 /* re-read busy flags */
480 for (i = 0; i < num_mgrs; i++)
481 mgr_busy[i] = dispc_mgr_go_busy(i);
482
483 /* keep running as long as there are busy managers, so that
484 * we can collect overlay-applied information */
485 for (i = 0; i < num_mgrs; ++i) {
486 if (mgr_busy[i])
487 goto end;
488 }
489
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200490 dss_unregister_vsync_isr();
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200491
492end:
493 spin_unlock(&dss_cache.lock);
494}
495
496static int omap_dss_mgr_apply_ovl(struct omap_overlay *ovl)
497{
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200498 struct ovl_priv_data *op;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200499 struct omap_dss_device *dssdev;
500
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200501 op = get_ovl_priv(ovl);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200502
503 if (ovl->manager_changed) {
504 ovl->manager_changed = false;
505 ovl->info_dirty = true;
506 }
507
508 if (!overlay_enabled(ovl)) {
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200509 if (op->enabled) {
510 op->enabled = false;
511 op->dirty = true;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200512 }
513 return 0;
514 }
515
516 if (!ovl->info_dirty)
517 return 0;
518
519 dssdev = ovl->manager->device;
520
521 if (dss_check_overlay(ovl, dssdev)) {
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200522 if (op->enabled) {
523 op->enabled = false;
524 op->dirty = true;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200525 }
526 return -EINVAL;
527 }
528
529 ovl->info_dirty = false;
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200530 op->dirty = true;
531 op->info = ovl->info;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200532
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200533 op->channel = ovl->manager->id;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200534
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200535 op->enabled = true;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200536
537 return 0;
538}
539
540static void omap_dss_mgr_apply_mgr(struct omap_overlay_manager *mgr)
541{
542 struct manager_cache_data *mc;
543
544 mc = &dss_cache.manager_cache[mgr->id];
545
546 if (mgr->device_changed) {
547 mgr->device_changed = false;
548 mgr->info_dirty = true;
549 }
550
551 if (!mgr->info_dirty)
552 return;
553
554 if (!mgr->device)
555 return;
556
557 mgr->info_dirty = false;
558 mc->dirty = true;
559 mc->info = mgr->info;
560
561 mc->manual_update = mgr_manual_update(mgr);
562}
563
564static void omap_dss_mgr_apply_ovl_fifos(struct omap_overlay *ovl)
565{
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200566 struct ovl_priv_data *op;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200567 struct omap_dss_device *dssdev;
568 u32 size, burst_size;
569
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200570 op = get_ovl_priv(ovl);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200571
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200572 if (!op->enabled)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200573 return;
574
575 dssdev = ovl->manager->device;
576
577 size = dispc_ovl_get_fifo_size(ovl->id);
578
579 burst_size = dispc_ovl_get_burst_size(ovl->id);
580
581 switch (dssdev->type) {
582 case OMAP_DISPLAY_TYPE_DPI:
583 case OMAP_DISPLAY_TYPE_DBI:
584 case OMAP_DISPLAY_TYPE_SDI:
585 case OMAP_DISPLAY_TYPE_VENC:
586 case OMAP_DISPLAY_TYPE_HDMI:
587 default_get_overlay_fifo_thresholds(ovl->id, size,
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200588 burst_size, &op->fifo_low,
589 &op->fifo_high);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200590 break;
591#ifdef CONFIG_OMAP2_DSS_DSI
592 case OMAP_DISPLAY_TYPE_DSI:
593 dsi_get_overlay_fifo_thresholds(ovl->id, size,
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200594 burst_size, &op->fifo_low,
595 &op->fifo_high);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200596 break;
597#endif
598 default:
599 BUG();
600 }
601}
602
603int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
604{
Tomi Valkeinen07e327c2011-11-05 10:59:59 +0200605 int r;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200606 unsigned long flags;
Tomi Valkeinen07e327c2011-11-05 10:59:59 +0200607 struct omap_overlay *ovl;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200608
609 DSSDBG("omap_dss_mgr_apply(%s)\n", mgr->name);
610
611 r = dispc_runtime_get();
612 if (r)
613 return r;
614
615 spin_lock_irqsave(&dss_cache.lock, flags);
616
617 /* Configure overlays */
Tomi Valkeinen07e327c2011-11-05 10:59:59 +0200618 list_for_each_entry(ovl, &mgr->overlays, list)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200619 omap_dss_mgr_apply_ovl(ovl);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200620
621 /* Configure manager */
622 omap_dss_mgr_apply_mgr(mgr);
623
624 /* Configure overlay fifos */
Tomi Valkeinen07e327c2011-11-05 10:59:59 +0200625 list_for_each_entry(ovl, &mgr->overlays, list)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200626 omap_dss_mgr_apply_ovl_fifos(ovl);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200627
628 r = 0;
Tomi Valkeinen04f66432011-11-07 15:04:01 +0200629 if (mgr->enabled && !mgr_manual_update(mgr)) {
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200630 if (!dss_cache.irq_enabled)
631 dss_register_vsync_isr();
Tomi Valkeinen18135ea2011-11-04 09:35:59 +0200632
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200633 dss_write_regs();
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200634 }
635
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200636 spin_unlock_irqrestore(&dss_cache.lock, flags);
637
638 dispc_runtime_put();
639
640 return r;
641}
642
Tomi Valkeinen7797c6d2011-11-04 10:22:46 +0200643void dss_mgr_enable(struct omap_overlay_manager *mgr)
644{
645 dispc_mgr_enable(mgr->id, true);
Tomi Valkeinenbe729172011-11-04 10:30:47 +0200646 mgr->enabled = true;
Tomi Valkeinen7797c6d2011-11-04 10:22:46 +0200647}
648
649void dss_mgr_disable(struct omap_overlay_manager *mgr)
650{
651 dispc_mgr_enable(mgr->id, false);
Tomi Valkeinenbe729172011-11-04 10:30:47 +0200652 mgr->enabled = false;
Tomi Valkeinen7797c6d2011-11-04 10:22:46 +0200653}
654