blob: a2c6c50430ee7bee650caca00c3830703951e01e [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
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +020076struct mgr_priv_data {
Tomi Valkeinen58f255482011-11-04 09:48:54 +020077 /* 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 {
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +020092 struct ovl_priv_data ovl_priv_data_array[MAX_DSS_OVERLAYS];
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +020093 struct mgr_priv_data mgr_priv_data_array[MAX_DSS_MANAGERS];
Tomi Valkeinen58f255482011-11-04 09:48:54 +020094
95 bool irq_enabled;
96} dss_cache;
97
Tomi Valkeinen063fd702011-11-15 12:04:10 +020098/* protects dss_cache */
99static spinlock_t data_lock;
100
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200101static struct ovl_priv_data *get_ovl_priv(struct omap_overlay *ovl)
102{
103 return &dss_cache.ovl_priv_data_array[ovl->id];
104}
105
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200106static struct mgr_priv_data *get_mgr_priv(struct omap_overlay_manager *mgr)
107{
108 return &dss_cache.mgr_priv_data_array[mgr->id];
109}
110
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200111void dss_apply_init(void)
112{
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200113 spin_lock_init(&data_lock);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200114}
115
116static bool ovl_manual_update(struct omap_overlay *ovl)
117{
118 return ovl->manager->device->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE;
119}
120
121static bool mgr_manual_update(struct omap_overlay_manager *mgr)
122{
123 return mgr->device->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE;
124}
125
126static int overlay_enabled(struct omap_overlay *ovl)
127{
128 return ovl->info.enabled && ovl->manager && ovl->manager->device;
129}
130
131int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr)
132{
133 unsigned long timeout = msecs_to_jiffies(500);
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200134 struct mgr_priv_data *mp;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200135 u32 irq;
136 int r;
137 int i;
138 struct omap_dss_device *dssdev = mgr->device;
139
140 if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
141 return 0;
142
143 if (mgr_manual_update(mgr))
144 return 0;
145
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200146 irq = dispc_mgr_get_vsync_irq(mgr->id);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200147
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200148 mp = get_mgr_priv(mgr);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200149 i = 0;
150 while (1) {
151 unsigned long flags;
152 bool shadow_dirty, dirty;
153
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200154 spin_lock_irqsave(&data_lock, flags);
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200155 dirty = mp->dirty;
156 shadow_dirty = mp->shadow_dirty;
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200157 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200158
159 if (!dirty && !shadow_dirty) {
160 r = 0;
161 break;
162 }
163
164 /* 4 iterations is the worst case:
165 * 1 - initial iteration, dirty = true (between VFP and VSYNC)
166 * 2 - first VSYNC, dirty = true
167 * 3 - dirty = false, shadow_dirty = true
168 * 4 - shadow_dirty = false */
169 if (i++ == 3) {
170 DSSERR("mgr(%d)->wait_for_go() not finishing\n",
171 mgr->id);
172 r = 0;
173 break;
174 }
175
176 r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
177 if (r == -ERESTARTSYS)
178 break;
179
180 if (r) {
181 DSSERR("mgr(%d)->wait_for_go() timeout\n", mgr->id);
182 break;
183 }
184 }
185
186 return r;
187}
188
189int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl)
190{
191 unsigned long timeout = msecs_to_jiffies(500);
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200192 struct ovl_priv_data *op;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200193 struct omap_dss_device *dssdev;
194 u32 irq;
195 int r;
196 int i;
197
198 if (!ovl->manager)
199 return 0;
200
201 dssdev = ovl->manager->device;
202
203 if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
204 return 0;
205
206 if (ovl_manual_update(ovl))
207 return 0;
208
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200209 irq = dispc_mgr_get_vsync_irq(ovl->manager->id);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200210
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200211 op = get_ovl_priv(ovl);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200212 i = 0;
213 while (1) {
214 unsigned long flags;
215 bool shadow_dirty, dirty;
216
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200217 spin_lock_irqsave(&data_lock, flags);
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200218 dirty = op->dirty;
219 shadow_dirty = op->shadow_dirty;
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200220 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200221
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
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200252static int dss_ovl_write_regs(struct omap_overlay *ovl)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200253{
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200254 struct ovl_priv_data *op;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200255 struct omap_overlay_info *oi;
256 bool ilace, replication;
257 int r;
258
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200259 DSSDBGF("%d", ovl->id);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200260
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200261 op = get_ovl_priv(ovl);
262 oi = &op->info;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200263
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200264 if (!op->enabled) {
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200265 dispc_ovl_enable(ovl->id, 0);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200266 return 0;
267 }
268
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200269 replication = dss_use_replication(ovl->manager->device, oi->color_mode);
270
271 ilace = ovl->manager->device->type == OMAP_DISPLAY_TYPE_VENC;
272
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200273 dispc_ovl_set_channel_out(ovl->id, op->channel);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200274
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200275 r = dispc_ovl_setup(ovl->id, oi, ilace, replication);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200276 if (r) {
277 /* this shouldn't happen */
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200278 DSSERR("dispc_ovl_setup failed for ovl %d\n", ovl->id);
279 dispc_ovl_enable(ovl->id, 0);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200280 return r;
281 }
282
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200283 dispc_ovl_set_fifo_threshold(ovl->id, op->fifo_low, op->fifo_high);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200284
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200285 dispc_ovl_enable(ovl->id, 1);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200286
287 return 0;
288}
289
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200290static void dss_mgr_write_regs(struct omap_overlay_manager *mgr)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200291{
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200292 struct mgr_priv_data *mp;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200293 struct omap_overlay_manager_info *mi;
294
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200295 DSSDBGF("%d", mgr->id);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200296
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200297 mp = get_mgr_priv(mgr);
298 mi = &mp->info;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200299
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200300 dispc_mgr_setup(mgr->id, mi);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200301}
302
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200303/* dss_write_regs() tries to write values from cache to shadow registers.
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200304 * It writes only to those managers/overlays that are not busy.
305 * returns 0 if everything could be written to shadow registers.
306 * returns 1 if not everything could be written to shadow registers. */
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200307static int dss_write_regs(void)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200308{
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200309 struct omap_overlay *ovl;
310 struct omap_overlay_manager *mgr;
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200311 struct ovl_priv_data *op;
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200312 struct mgr_priv_data *mp;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200313 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) {
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200331 ovl = omap_dss_get_overlay(i);
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200332 op = get_ovl_priv(ovl);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200333
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200334 if (!op->dirty)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200335 continue;
336
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200337 mp = get_mgr_priv(ovl->manager);
338
339 if (mp->manual_update && !mp->do_manual_update)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200340 continue;
341
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200342 if (mgr_busy[op->channel]) {
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200343 busy = true;
344 continue;
345 }
346
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200347 r = dss_ovl_write_regs(ovl);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200348 if (r)
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200349 DSSERR("dss_ovl_write_regs %d failed\n", i);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200350
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200351 op->dirty = false;
352 op->shadow_dirty = true;
353 mgr_go[op->channel] = true;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200354 }
355
356 /* Commit manager settings */
357 for (i = 0; i < num_mgrs; ++i) {
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200358 mgr = omap_dss_get_overlay_manager(i);
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200359 mp = get_mgr_priv(mgr);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200360
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200361 if (!mp->dirty)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200362 continue;
363
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200364 if (mp->manual_update && !mp->do_manual_update)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200365 continue;
366
367 if (mgr_busy[i]) {
368 busy = true;
369 continue;
370 }
371
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200372 dss_mgr_write_regs(mgr);
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200373 mp->dirty = false;
374 mp->shadow_dirty = true;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200375 mgr_go[i] = true;
376 }
377
378 /* set GO */
379 for (i = 0; i < num_mgrs; ++i) {
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200380 mgr = omap_dss_get_overlay_manager(i);
381 mp = get_mgr_priv(mgr);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200382
383 if (!mgr_go[i])
384 continue;
385
386 /* We don't need GO with manual update display. LCD iface will
387 * always be turned off after frame, and new settings will be
388 * taken in to use at next update */
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200389 if (!mp->manual_update)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200390 dispc_mgr_go(i);
391 }
392
393 if (busy)
394 r = 1;
395 else
396 r = 0;
397
398 return r;
399}
400
401void dss_mgr_start_update(struct omap_overlay_manager *mgr)
402{
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200403 struct mgr_priv_data *mp = get_mgr_priv(mgr);
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200404 struct ovl_priv_data *op;
Tomi Valkeinen07e327c2011-11-05 10:59:59 +0200405 struct omap_overlay *ovl;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200406
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200407 mp->do_manual_update = true;
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200408 dss_write_regs();
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200409 mp->do_manual_update = false;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200410
Tomi Valkeinen07e327c2011-11-05 10:59:59 +0200411 list_for_each_entry(ovl, &mgr->overlays, list) {
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200412 op = get_ovl_priv(ovl);
413 op->shadow_dirty = false;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200414 }
415
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200416 mp->shadow_dirty = false;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200417
Tomi Valkeinen7797c6d2011-11-04 10:22:46 +0200418 dispc_mgr_enable(mgr->id, true);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200419}
420
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200421static void dss_apply_irq_handler(void *data, u32 mask);
422
423static void dss_register_vsync_isr(void)
424{
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200425 const int num_mgrs = dss_feat_get_num_mgrs();
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200426 u32 mask;
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200427 int r, i;
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200428
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200429 mask = 0;
430 for (i = 0; i < num_mgrs; ++i)
431 mask |= dispc_mgr_get_vsync_irq(i);
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200432
433 r = omap_dispc_register_isr(dss_apply_irq_handler, NULL, mask);
434 WARN_ON(r);
435
436 dss_cache.irq_enabled = true;
437}
438
439static void dss_unregister_vsync_isr(void)
440{
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200441 const int num_mgrs = dss_feat_get_num_mgrs();
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200442 u32 mask;
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200443 int r, i;
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200444
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200445 mask = 0;
446 for (i = 0; i < num_mgrs; ++i)
447 mask |= dispc_mgr_get_vsync_irq(i);
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200448
449 r = omap_dispc_unregister_isr(dss_apply_irq_handler, NULL, mask);
450 WARN_ON(r);
451
452 dss_cache.irq_enabled = false;
453}
454
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200455static void dss_apply_irq_handler(void *data, u32 mask)
456{
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200457 struct omap_overlay *ovl;
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200458 struct omap_overlay_manager *mgr;
459 struct mgr_priv_data *mp;
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200460 struct ovl_priv_data *op;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200461 const int num_ovls = dss_feat_get_num_ovls();
462 const int num_mgrs = dss_feat_get_num_mgrs();
463 int i, r;
464 bool mgr_busy[MAX_DSS_MANAGERS];
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200465
466 for (i = 0; i < num_mgrs; i++)
467 mgr_busy[i] = dispc_mgr_go_busy(i);
468
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200469 spin_lock(&data_lock);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200470
471 for (i = 0; i < num_ovls; ++i) {
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200472 ovl = omap_dss_get_overlay(i);
473 op = get_ovl_priv(ovl);
474 if (!mgr_busy[op->channel])
475 op->shadow_dirty = false;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200476 }
477
478 for (i = 0; i < num_mgrs; ++i) {
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200479 mgr = omap_dss_get_overlay_manager(i);
480 mp = get_mgr_priv(mgr);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200481 if (!mgr_busy[i])
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200482 mp->shadow_dirty = false;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200483 }
484
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200485 r = dss_write_regs();
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200486 if (r == 1)
487 goto end;
488
489 /* re-read busy flags */
490 for (i = 0; i < num_mgrs; i++)
491 mgr_busy[i] = dispc_mgr_go_busy(i);
492
493 /* keep running as long as there are busy managers, so that
494 * we can collect overlay-applied information */
495 for (i = 0; i < num_mgrs; ++i) {
496 if (mgr_busy[i])
497 goto end;
498 }
499
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200500 dss_unregister_vsync_isr();
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200501
502end:
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200503 spin_unlock(&data_lock);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200504}
505
506static int omap_dss_mgr_apply_ovl(struct omap_overlay *ovl)
507{
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200508 struct ovl_priv_data *op;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200509 struct omap_dss_device *dssdev;
510
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200511 op = get_ovl_priv(ovl);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200512
513 if (ovl->manager_changed) {
514 ovl->manager_changed = false;
515 ovl->info_dirty = true;
516 }
517
518 if (!overlay_enabled(ovl)) {
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200519 if (op->enabled) {
520 op->enabled = false;
521 op->dirty = true;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200522 }
523 return 0;
524 }
525
526 if (!ovl->info_dirty)
527 return 0;
528
529 dssdev = ovl->manager->device;
530
531 if (dss_check_overlay(ovl, dssdev)) {
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200532 if (op->enabled) {
533 op->enabled = false;
534 op->dirty = true;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200535 }
536 return -EINVAL;
537 }
538
539 ovl->info_dirty = false;
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200540 op->dirty = true;
541 op->info = ovl->info;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200542
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200543 op->channel = ovl->manager->id;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200544
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200545 op->enabled = true;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200546
547 return 0;
548}
549
550static void omap_dss_mgr_apply_mgr(struct omap_overlay_manager *mgr)
551{
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200552 struct mgr_priv_data *mp;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200553
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200554 mp = get_mgr_priv(mgr);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200555
556 if (mgr->device_changed) {
557 mgr->device_changed = false;
558 mgr->info_dirty = true;
559 }
560
561 if (!mgr->info_dirty)
562 return;
563
564 if (!mgr->device)
565 return;
566
567 mgr->info_dirty = false;
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200568 mp->dirty = true;
569 mp->info = mgr->info;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200570
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200571 mp->manual_update = mgr_manual_update(mgr);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200572}
573
574static void omap_dss_mgr_apply_ovl_fifos(struct omap_overlay *ovl)
575{
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200576 struct ovl_priv_data *op;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200577 struct omap_dss_device *dssdev;
578 u32 size, burst_size;
579
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200580 op = get_ovl_priv(ovl);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200581
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200582 if (!op->enabled)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200583 return;
584
585 dssdev = ovl->manager->device;
586
587 size = dispc_ovl_get_fifo_size(ovl->id);
588
589 burst_size = dispc_ovl_get_burst_size(ovl->id);
590
591 switch (dssdev->type) {
592 case OMAP_DISPLAY_TYPE_DPI:
593 case OMAP_DISPLAY_TYPE_DBI:
594 case OMAP_DISPLAY_TYPE_SDI:
595 case OMAP_DISPLAY_TYPE_VENC:
596 case OMAP_DISPLAY_TYPE_HDMI:
597 default_get_overlay_fifo_thresholds(ovl->id, size,
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200598 burst_size, &op->fifo_low,
599 &op->fifo_high);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200600 break;
601#ifdef CONFIG_OMAP2_DSS_DSI
602 case OMAP_DISPLAY_TYPE_DSI:
603 dsi_get_overlay_fifo_thresholds(ovl->id, size,
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200604 burst_size, &op->fifo_low,
605 &op->fifo_high);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200606 break;
607#endif
608 default:
609 BUG();
610 }
611}
612
613int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
614{
Tomi Valkeinen07e327c2011-11-05 10:59:59 +0200615 int r;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200616 unsigned long flags;
Tomi Valkeinen07e327c2011-11-05 10:59:59 +0200617 struct omap_overlay *ovl;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200618
619 DSSDBG("omap_dss_mgr_apply(%s)\n", mgr->name);
620
621 r = dispc_runtime_get();
622 if (r)
623 return r;
624
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200625 spin_lock_irqsave(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200626
627 /* Configure overlays */
Tomi Valkeinen07e327c2011-11-05 10:59:59 +0200628 list_for_each_entry(ovl, &mgr->overlays, list)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200629 omap_dss_mgr_apply_ovl(ovl);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200630
631 /* Configure manager */
632 omap_dss_mgr_apply_mgr(mgr);
633
634 /* Configure overlay fifos */
Tomi Valkeinen07e327c2011-11-05 10:59:59 +0200635 list_for_each_entry(ovl, &mgr->overlays, list)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200636 omap_dss_mgr_apply_ovl_fifos(ovl);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200637
638 r = 0;
Tomi Valkeinen04f66432011-11-07 15:04:01 +0200639 if (mgr->enabled && !mgr_manual_update(mgr)) {
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200640 if (!dss_cache.irq_enabled)
641 dss_register_vsync_isr();
Tomi Valkeinen18135ea2011-11-04 09:35:59 +0200642
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200643 dss_write_regs();
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200644 }
645
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200646 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200647
648 dispc_runtime_put();
649
650 return r;
651}
652
Tomi Valkeinen7797c6d2011-11-04 10:22:46 +0200653void dss_mgr_enable(struct omap_overlay_manager *mgr)
654{
655 dispc_mgr_enable(mgr->id, true);
Tomi Valkeinenbe729172011-11-04 10:30:47 +0200656 mgr->enabled = true;
Tomi Valkeinen7797c6d2011-11-04 10:22:46 +0200657}
658
659void dss_mgr_disable(struct omap_overlay_manager *mgr)
660{
661 dispc_mgr_enable(mgr->id, false);
Tomi Valkeinenbe729172011-11-04 10:30:47 +0200662 mgr->enabled = false;
Tomi Valkeinen7797c6d2011-11-04 10:22:46 +0200663}
664