blob: 9c035e272e19e9f7751dd7f487abd21506f85723 [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 {
92 spinlock_t lock;
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +020093 struct ovl_priv_data ovl_priv_data_array[MAX_DSS_OVERLAYS];
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +020094 struct mgr_priv_data mgr_priv_data_array[MAX_DSS_MANAGERS];
Tomi Valkeinen58f255482011-11-04 09:48:54 +020095
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 Valkeinenaf3d64b2011-11-15 12:02:03 +0200104static struct mgr_priv_data *get_mgr_priv(struct omap_overlay_manager *mgr)
105{
106 return &dss_cache.mgr_priv_data_array[mgr->id];
107}
108
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200109void dss_apply_init(void)
110{
111 spin_lock_init(&dss_cache.lock);
112}
113
114static bool ovl_manual_update(struct omap_overlay *ovl)
115{
116 return ovl->manager->device->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE;
117}
118
119static bool mgr_manual_update(struct omap_overlay_manager *mgr)
120{
121 return mgr->device->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE;
122}
123
124static int overlay_enabled(struct omap_overlay *ovl)
125{
126 return ovl->info.enabled && ovl->manager && ovl->manager->device;
127}
128
129int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr)
130{
131 unsigned long timeout = msecs_to_jiffies(500);
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200132 struct mgr_priv_data *mp;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200133 u32 irq;
134 int r;
135 int i;
136 struct omap_dss_device *dssdev = mgr->device;
137
138 if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
139 return 0;
140
141 if (mgr_manual_update(mgr))
142 return 0;
143
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200144 irq = dispc_mgr_get_vsync_irq(mgr->id);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200145
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200146 mp = get_mgr_priv(mgr);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200147 i = 0;
148 while (1) {
149 unsigned long flags;
150 bool shadow_dirty, dirty;
151
152 spin_lock_irqsave(&dss_cache.lock, flags);
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200153 dirty = mp->dirty;
154 shadow_dirty = mp->shadow_dirty;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200155 spin_unlock_irqrestore(&dss_cache.lock, flags);
156
157 if (!dirty && !shadow_dirty) {
158 r = 0;
159 break;
160 }
161
162 /* 4 iterations is the worst case:
163 * 1 - initial iteration, dirty = true (between VFP and VSYNC)
164 * 2 - first VSYNC, dirty = true
165 * 3 - dirty = false, shadow_dirty = true
166 * 4 - shadow_dirty = false */
167 if (i++ == 3) {
168 DSSERR("mgr(%d)->wait_for_go() not finishing\n",
169 mgr->id);
170 r = 0;
171 break;
172 }
173
174 r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
175 if (r == -ERESTARTSYS)
176 break;
177
178 if (r) {
179 DSSERR("mgr(%d)->wait_for_go() timeout\n", mgr->id);
180 break;
181 }
182 }
183
184 return r;
185}
186
187int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl)
188{
189 unsigned long timeout = msecs_to_jiffies(500);
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200190 struct ovl_priv_data *op;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200191 struct omap_dss_device *dssdev;
192 u32 irq;
193 int r;
194 int i;
195
196 if (!ovl->manager)
197 return 0;
198
199 dssdev = ovl->manager->device;
200
201 if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
202 return 0;
203
204 if (ovl_manual_update(ovl))
205 return 0;
206
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200207 irq = dispc_mgr_get_vsync_irq(ovl->manager->id);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200208
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200209 op = get_ovl_priv(ovl);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200210 i = 0;
211 while (1) {
212 unsigned long flags;
213 bool shadow_dirty, dirty;
214
215 spin_lock_irqsave(&dss_cache.lock, flags);
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200216 dirty = op->dirty;
217 shadow_dirty = op->shadow_dirty;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200218 spin_unlock_irqrestore(&dss_cache.lock, flags);
219
220 if (!dirty && !shadow_dirty) {
221 r = 0;
222 break;
223 }
224
225 /* 4 iterations is the worst case:
226 * 1 - initial iteration, dirty = true (between VFP and VSYNC)
227 * 2 - first VSYNC, dirty = true
228 * 3 - dirty = false, shadow_dirty = true
229 * 4 - shadow_dirty = false */
230 if (i++ == 3) {
231 DSSERR("ovl(%d)->wait_for_go() not finishing\n",
232 ovl->id);
233 r = 0;
234 break;
235 }
236
237 r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
238 if (r == -ERESTARTSYS)
239 break;
240
241 if (r) {
242 DSSERR("ovl(%d)->wait_for_go() timeout\n", ovl->id);
243 break;
244 }
245 }
246
247 return r;
248}
249
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200250static int dss_ovl_write_regs(struct omap_overlay *ovl)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200251{
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200252 struct ovl_priv_data *op;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200253 struct omap_overlay_info *oi;
254 bool ilace, replication;
255 int r;
256
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200257 DSSDBGF("%d", ovl->id);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200258
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200259 op = get_ovl_priv(ovl);
260 oi = &op->info;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200261
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200262 if (!op->enabled) {
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200263 dispc_ovl_enable(ovl->id, 0);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200264 return 0;
265 }
266
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200267 replication = dss_use_replication(ovl->manager->device, oi->color_mode);
268
269 ilace = ovl->manager->device->type == OMAP_DISPLAY_TYPE_VENC;
270
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200271 dispc_ovl_set_channel_out(ovl->id, op->channel);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200272
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200273 r = dispc_ovl_setup(ovl->id, oi, ilace, replication);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200274 if (r) {
275 /* this shouldn't happen */
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200276 DSSERR("dispc_ovl_setup failed for ovl %d\n", ovl->id);
277 dispc_ovl_enable(ovl->id, 0);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200278 return r;
279 }
280
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200281 dispc_ovl_set_fifo_threshold(ovl->id, op->fifo_low, op->fifo_high);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200282
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200283 dispc_ovl_enable(ovl->id, 1);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200284
285 return 0;
286}
287
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200288static void dss_mgr_write_regs(struct omap_overlay_manager *mgr)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200289{
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200290 struct mgr_priv_data *mp;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200291 struct omap_overlay_manager_info *mi;
292
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200293 DSSDBGF("%d", mgr->id);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200294
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200295 mp = get_mgr_priv(mgr);
296 mi = &mp->info;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200297
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200298 dispc_mgr_setup(mgr->id, mi);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200299}
300
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200301/* dss_write_regs() tries to write values from cache to shadow registers.
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200302 * It writes only to those managers/overlays that are not busy.
303 * returns 0 if everything could be written to shadow registers.
304 * returns 1 if not everything could be written to shadow registers. */
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200305static int dss_write_regs(void)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200306{
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200307 struct omap_overlay *ovl;
308 struct omap_overlay_manager *mgr;
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200309 struct ovl_priv_data *op;
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200310 struct mgr_priv_data *mp;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200311 const int num_ovls = dss_feat_get_num_ovls();
312 const int num_mgrs = dss_feat_get_num_mgrs();
313 int i;
314 int r;
315 bool mgr_busy[MAX_DSS_MANAGERS];
316 bool mgr_go[MAX_DSS_MANAGERS];
317 bool busy;
318
319 r = 0;
320 busy = false;
321
322 for (i = 0; i < num_mgrs; i++) {
323 mgr_busy[i] = dispc_mgr_go_busy(i);
324 mgr_go[i] = false;
325 }
326
327 /* Commit overlay settings */
328 for (i = 0; i < num_ovls; ++i) {
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200329 ovl = omap_dss_get_overlay(i);
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200330 op = get_ovl_priv(ovl);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200331
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200332 if (!op->dirty)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200333 continue;
334
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200335 mp = get_mgr_priv(ovl->manager);
336
337 if (mp->manual_update && !mp->do_manual_update)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200338 continue;
339
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200340 if (mgr_busy[op->channel]) {
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200341 busy = true;
342 continue;
343 }
344
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200345 r = dss_ovl_write_regs(ovl);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200346 if (r)
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200347 DSSERR("dss_ovl_write_regs %d failed\n", i);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200348
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200349 op->dirty = false;
350 op->shadow_dirty = true;
351 mgr_go[op->channel] = true;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200352 }
353
354 /* Commit manager settings */
355 for (i = 0; i < num_mgrs; ++i) {
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200356 mgr = omap_dss_get_overlay_manager(i);
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200357 mp = get_mgr_priv(mgr);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200358
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200359 if (!mp->dirty)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200360 continue;
361
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200362 if (mp->manual_update && !mp->do_manual_update)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200363 continue;
364
365 if (mgr_busy[i]) {
366 busy = true;
367 continue;
368 }
369
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200370 dss_mgr_write_regs(mgr);
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200371 mp->dirty = false;
372 mp->shadow_dirty = true;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200373 mgr_go[i] = true;
374 }
375
376 /* set GO */
377 for (i = 0; i < num_mgrs; ++i) {
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200378 mgr = omap_dss_get_overlay_manager(i);
379 mp = get_mgr_priv(mgr);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200380
381 if (!mgr_go[i])
382 continue;
383
384 /* We don't need GO with manual update display. LCD iface will
385 * always be turned off after frame, and new settings will be
386 * taken in to use at next update */
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200387 if (!mp->manual_update)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200388 dispc_mgr_go(i);
389 }
390
391 if (busy)
392 r = 1;
393 else
394 r = 0;
395
396 return r;
397}
398
399void dss_mgr_start_update(struct omap_overlay_manager *mgr)
400{
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200401 struct mgr_priv_data *mp = get_mgr_priv(mgr);
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200402 struct ovl_priv_data *op;
Tomi Valkeinen07e327c2011-11-05 10:59:59 +0200403 struct omap_overlay *ovl;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200404
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200405 mp->do_manual_update = true;
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200406 dss_write_regs();
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200407 mp->do_manual_update = false;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200408
Tomi Valkeinen07e327c2011-11-05 10:59:59 +0200409 list_for_each_entry(ovl, &mgr->overlays, list) {
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200410 op = get_ovl_priv(ovl);
411 op->shadow_dirty = false;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200412 }
413
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200414 mp->shadow_dirty = false;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200415
Tomi Valkeinen7797c6d2011-11-04 10:22:46 +0200416 dispc_mgr_enable(mgr->id, true);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200417}
418
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200419static void dss_apply_irq_handler(void *data, u32 mask);
420
421static void dss_register_vsync_isr(void)
422{
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200423 const int num_mgrs = dss_feat_get_num_mgrs();
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200424 u32 mask;
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200425 int r, i;
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200426
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200427 mask = 0;
428 for (i = 0; i < num_mgrs; ++i)
429 mask |= dispc_mgr_get_vsync_irq(i);
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200430
431 r = omap_dispc_register_isr(dss_apply_irq_handler, NULL, mask);
432 WARN_ON(r);
433
434 dss_cache.irq_enabled = true;
435}
436
437static void dss_unregister_vsync_isr(void)
438{
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200439 const int num_mgrs = dss_feat_get_num_mgrs();
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200440 u32 mask;
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200441 int r, i;
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200442
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200443 mask = 0;
444 for (i = 0; i < num_mgrs; ++i)
445 mask |= dispc_mgr_get_vsync_irq(i);
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200446
447 r = omap_dispc_unregister_isr(dss_apply_irq_handler, NULL, mask);
448 WARN_ON(r);
449
450 dss_cache.irq_enabled = false;
451}
452
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200453static void dss_apply_irq_handler(void *data, u32 mask)
454{
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200455 struct omap_overlay *ovl;
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200456 struct omap_overlay_manager *mgr;
457 struct mgr_priv_data *mp;
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200458 struct ovl_priv_data *op;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200459 const int num_ovls = dss_feat_get_num_ovls();
460 const int num_mgrs = dss_feat_get_num_mgrs();
461 int i, r;
462 bool mgr_busy[MAX_DSS_MANAGERS];
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200463
464 for (i = 0; i < num_mgrs; i++)
465 mgr_busy[i] = dispc_mgr_go_busy(i);
466
467 spin_lock(&dss_cache.lock);
468
469 for (i = 0; i < num_ovls; ++i) {
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200470 ovl = omap_dss_get_overlay(i);
471 op = get_ovl_priv(ovl);
472 if (!mgr_busy[op->channel])
473 op->shadow_dirty = false;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200474 }
475
476 for (i = 0; i < num_mgrs; ++i) {
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200477 mgr = omap_dss_get_overlay_manager(i);
478 mp = get_mgr_priv(mgr);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200479 if (!mgr_busy[i])
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200480 mp->shadow_dirty = false;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200481 }
482
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200483 r = dss_write_regs();
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200484 if (r == 1)
485 goto end;
486
487 /* re-read busy flags */
488 for (i = 0; i < num_mgrs; i++)
489 mgr_busy[i] = dispc_mgr_go_busy(i);
490
491 /* keep running as long as there are busy managers, so that
492 * we can collect overlay-applied information */
493 for (i = 0; i < num_mgrs; ++i) {
494 if (mgr_busy[i])
495 goto end;
496 }
497
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200498 dss_unregister_vsync_isr();
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200499
500end:
501 spin_unlock(&dss_cache.lock);
502}
503
504static int omap_dss_mgr_apply_ovl(struct omap_overlay *ovl)
505{
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200506 struct ovl_priv_data *op;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200507 struct omap_dss_device *dssdev;
508
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200509 op = get_ovl_priv(ovl);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200510
511 if (ovl->manager_changed) {
512 ovl->manager_changed = false;
513 ovl->info_dirty = true;
514 }
515
516 if (!overlay_enabled(ovl)) {
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200517 if (op->enabled) {
518 op->enabled = false;
519 op->dirty = true;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200520 }
521 return 0;
522 }
523
524 if (!ovl->info_dirty)
525 return 0;
526
527 dssdev = ovl->manager->device;
528
529 if (dss_check_overlay(ovl, dssdev)) {
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200530 if (op->enabled) {
531 op->enabled = false;
532 op->dirty = true;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200533 }
534 return -EINVAL;
535 }
536
537 ovl->info_dirty = false;
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200538 op->dirty = true;
539 op->info = ovl->info;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200540
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200541 op->channel = ovl->manager->id;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200542
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200543 op->enabled = true;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200544
545 return 0;
546}
547
548static void omap_dss_mgr_apply_mgr(struct omap_overlay_manager *mgr)
549{
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200550 struct mgr_priv_data *mp;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200551
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200552 mp = get_mgr_priv(mgr);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200553
554 if (mgr->device_changed) {
555 mgr->device_changed = false;
556 mgr->info_dirty = true;
557 }
558
559 if (!mgr->info_dirty)
560 return;
561
562 if (!mgr->device)
563 return;
564
565 mgr->info_dirty = false;
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200566 mp->dirty = true;
567 mp->info = mgr->info;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200568
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200569 mp->manual_update = mgr_manual_update(mgr);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200570}
571
572static void omap_dss_mgr_apply_ovl_fifos(struct omap_overlay *ovl)
573{
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200574 struct ovl_priv_data *op;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200575 struct omap_dss_device *dssdev;
576 u32 size, burst_size;
577
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200578 op = get_ovl_priv(ovl);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200579
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200580 if (!op->enabled)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200581 return;
582
583 dssdev = ovl->manager->device;
584
585 size = dispc_ovl_get_fifo_size(ovl->id);
586
587 burst_size = dispc_ovl_get_burst_size(ovl->id);
588
589 switch (dssdev->type) {
590 case OMAP_DISPLAY_TYPE_DPI:
591 case OMAP_DISPLAY_TYPE_DBI:
592 case OMAP_DISPLAY_TYPE_SDI:
593 case OMAP_DISPLAY_TYPE_VENC:
594 case OMAP_DISPLAY_TYPE_HDMI:
595 default_get_overlay_fifo_thresholds(ovl->id, size,
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200596 burst_size, &op->fifo_low,
597 &op->fifo_high);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200598 break;
599#ifdef CONFIG_OMAP2_DSS_DSI
600 case OMAP_DISPLAY_TYPE_DSI:
601 dsi_get_overlay_fifo_thresholds(ovl->id, size,
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200602 burst_size, &op->fifo_low,
603 &op->fifo_high);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200604 break;
605#endif
606 default:
607 BUG();
608 }
609}
610
611int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
612{
Tomi Valkeinen07e327c2011-11-05 10:59:59 +0200613 int r;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200614 unsigned long flags;
Tomi Valkeinen07e327c2011-11-05 10:59:59 +0200615 struct omap_overlay *ovl;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200616
617 DSSDBG("omap_dss_mgr_apply(%s)\n", mgr->name);
618
619 r = dispc_runtime_get();
620 if (r)
621 return r;
622
623 spin_lock_irqsave(&dss_cache.lock, flags);
624
625 /* Configure overlays */
Tomi Valkeinen07e327c2011-11-05 10:59:59 +0200626 list_for_each_entry(ovl, &mgr->overlays, list)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200627 omap_dss_mgr_apply_ovl(ovl);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200628
629 /* Configure manager */
630 omap_dss_mgr_apply_mgr(mgr);
631
632 /* Configure overlay fifos */
Tomi Valkeinen07e327c2011-11-05 10:59:59 +0200633 list_for_each_entry(ovl, &mgr->overlays, list)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200634 omap_dss_mgr_apply_ovl_fifos(ovl);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200635
636 r = 0;
Tomi Valkeinen04f66432011-11-07 15:04:01 +0200637 if (mgr->enabled && !mgr_manual_update(mgr)) {
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200638 if (!dss_cache.irq_enabled)
639 dss_register_vsync_isr();
Tomi Valkeinen18135ea2011-11-04 09:35:59 +0200640
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200641 dss_write_regs();
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200642 }
643
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200644 spin_unlock_irqrestore(&dss_cache.lock, flags);
645
646 dispc_runtime_put();
647
648 return r;
649}
650
Tomi Valkeinen7797c6d2011-11-04 10:22:46 +0200651void dss_mgr_enable(struct omap_overlay_manager *mgr)
652{
653 dispc_mgr_enable(mgr->id, true);
Tomi Valkeinenbe729172011-11-04 10:30:47 +0200654 mgr->enabled = true;
Tomi Valkeinen7797c6d2011-11-04 10:22:46 +0200655}
656
657void dss_mgr_disable(struct omap_overlay_manager *mgr)
658{
659 dispc_mgr_enable(mgr->id, false);
Tomi Valkeinenbe729172011-11-04 10:30:47 +0200660 mgr->enabled = false;
Tomi Valkeinen7797c6d2011-11-04 10:22:46 +0200661}
662