blob: debd37aa9128508aee55012272f06a41fad5f724 [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 * +--------------------+
Tomi Valkeinend09c7aa2011-11-15 12:04:43 +020041 * | info |
Tomi Valkeinen58f255482011-11-04 09:48:54 +020042 * +--------------------+
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 Valkeinenc1a9feb2011-11-16 14:11:56 +020058
59 bool user_info_dirty;
60 struct omap_overlay_info user_info;
61
Tomi Valkeinen58f255482011-11-04 09:48:54 +020062 /* If true, cache changed, but not written to shadow registers. Set
63 * in apply(), cleared when registers written. */
64 bool dirty;
65 /* If true, shadow registers contain changed values not yet in real
66 * registers. Set when writing to shadow registers, cleared at
67 * VSYNC/EVSYNC */
68 bool shadow_dirty;
69
Tomi Valkeinen58f255482011-11-04 09:48:54 +020070 struct omap_overlay_info info;
71
72 enum omap_channel channel;
73
74 u32 fifo_low;
75 u32 fifo_high;
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +020076
77 bool extra_info_dirty;
78 bool shadow_extra_info_dirty;
79
80 bool enabled;
81
Tomi Valkeinen58f255482011-11-04 09:48:54 +020082};
83
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +020084struct mgr_priv_data {
Tomi Valkeinen388c4c62011-11-16 13:58:07 +020085
86 bool user_info_dirty;
87 struct omap_overlay_manager_info user_info;
88
Tomi Valkeinen58f255482011-11-04 09:48:54 +020089 /* If true, cache changed, but not written to shadow registers. Set
90 * in apply(), cleared when registers written. */
91 bool dirty;
92 /* If true, shadow registers contain changed values not yet in real
93 * registers. Set when writing to shadow registers, cleared at
94 * VSYNC/EVSYNC */
95 bool shadow_dirty;
96
97 struct omap_overlay_manager_info info;
98
Tomi Valkeinen43a972d2011-11-15 15:04:25 +020099 /* If true, GO bit is up and shadow registers cannot be written.
100 * Never true for manual update displays */
101 bool busy;
102
Tomi Valkeinen34861372011-11-18 15:43:29 +0200103 /* If true, dispc output is enabled */
104 bool updating;
105
Tomi Valkeinenbf213522011-11-15 14:43:53 +0200106 /* If true, a display is enabled using this manager */
107 bool enabled;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200108};
109
110static struct {
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200111 struct ovl_priv_data ovl_priv_data_array[MAX_DSS_OVERLAYS];
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200112 struct mgr_priv_data mgr_priv_data_array[MAX_DSS_MANAGERS];
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200113
114 bool irq_enabled;
Tomi Valkeinend09c7aa2011-11-15 12:04:43 +0200115} dss_data;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200116
Tomi Valkeinend09c7aa2011-11-15 12:04:43 +0200117/* protects dss_data */
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200118static spinlock_t data_lock;
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200119/* lock for blocking functions */
120static DEFINE_MUTEX(apply_lock);
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200121
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200122static void dss_register_vsync_isr(void);
123
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200124static struct ovl_priv_data *get_ovl_priv(struct omap_overlay *ovl)
125{
Tomi Valkeinend09c7aa2011-11-15 12:04:43 +0200126 return &dss_data.ovl_priv_data_array[ovl->id];
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200127}
128
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200129static struct mgr_priv_data *get_mgr_priv(struct omap_overlay_manager *mgr)
130{
Tomi Valkeinend09c7aa2011-11-15 12:04:43 +0200131 return &dss_data.mgr_priv_data_array[mgr->id];
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200132}
133
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200134void dss_apply_init(void)
135{
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +0200136 const int num_ovls = dss_feat_get_num_ovls();
137 int i;
138
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200139 spin_lock_init(&data_lock);
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +0200140
141 for (i = 0; i < num_ovls; ++i) {
142 struct ovl_priv_data *op;
143
144 op = &dss_data.ovl_priv_data_array[i];
145
146 op->info.global_alpha = 255;
147
148 switch (i) {
149 case 0:
150 op->info.zorder = 0;
151 break;
152 case 1:
153 op->info.zorder =
154 dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 3 : 0;
155 break;
156 case 2:
157 op->info.zorder =
158 dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 2 : 0;
159 break;
160 case 3:
161 op->info.zorder =
162 dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 1 : 0;
163 break;
164 }
165
166 op->user_info = op->info;
167 }
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200168}
169
170static bool ovl_manual_update(struct omap_overlay *ovl)
171{
172 return ovl->manager->device->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE;
173}
174
175static bool mgr_manual_update(struct omap_overlay_manager *mgr)
176{
177 return mgr->device->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE;
178}
179
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200180static bool need_isr(void)
181{
182 const int num_mgrs = dss_feat_get_num_mgrs();
183 int i;
184
185 for (i = 0; i < num_mgrs; ++i) {
186 struct omap_overlay_manager *mgr;
187 struct mgr_priv_data *mp;
188 struct omap_overlay *ovl;
189
190 mgr = omap_dss_get_overlay_manager(i);
191 mp = get_mgr_priv(mgr);
192
193 if (!mp->enabled)
194 continue;
195
Tomi Valkeinen34861372011-11-18 15:43:29 +0200196 if (mgr_manual_update(mgr)) {
197 /* to catch FRAMEDONE */
198 if (mp->updating)
199 return true;
200 } else {
201 /* to catch GO bit going down */
202 if (mp->busy)
203 return true;
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200204
205 /* to write new values to registers */
Tomi Valkeinen34861372011-11-18 15:43:29 +0200206 if (mp->dirty)
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200207 return true;
Tomi Valkeinen34861372011-11-18 15:43:29 +0200208
209 list_for_each_entry(ovl, &mgr->overlays, list) {
210 struct ovl_priv_data *op;
211
212 op = get_ovl_priv(ovl);
213
214 if (!op->enabled)
215 continue;
216
217 /* to write new values to registers */
218 if (op->dirty || op->extra_info_dirty)
219 return true;
220 }
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200221 }
222 }
223
224 return false;
225}
226
227static bool need_go(struct omap_overlay_manager *mgr)
228{
229 struct omap_overlay *ovl;
230 struct mgr_priv_data *mp;
231 struct ovl_priv_data *op;
232
233 mp = get_mgr_priv(mgr);
234
235 if (mp->shadow_dirty)
236 return true;
237
238 list_for_each_entry(ovl, &mgr->overlays, list) {
239 op = get_ovl_priv(ovl);
240 if (op->shadow_dirty || op->shadow_extra_info_dirty)
241 return true;
242 }
243
244 return false;
245}
246
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200247int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr)
248{
249 unsigned long timeout = msecs_to_jiffies(500);
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200250 struct mgr_priv_data *mp;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200251 u32 irq;
252 int r;
253 int i;
254 struct omap_dss_device *dssdev = mgr->device;
255
256 if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
257 return 0;
258
259 if (mgr_manual_update(mgr))
260 return 0;
261
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200262 irq = dispc_mgr_get_vsync_irq(mgr->id);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200263
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200264 mp = get_mgr_priv(mgr);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200265 i = 0;
266 while (1) {
267 unsigned long flags;
268 bool shadow_dirty, dirty;
269
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200270 spin_lock_irqsave(&data_lock, flags);
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200271 dirty = mp->dirty;
272 shadow_dirty = mp->shadow_dirty;
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200273 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200274
275 if (!dirty && !shadow_dirty) {
276 r = 0;
277 break;
278 }
279
280 /* 4 iterations is the worst case:
281 * 1 - initial iteration, dirty = true (between VFP and VSYNC)
282 * 2 - first VSYNC, dirty = true
283 * 3 - dirty = false, shadow_dirty = true
284 * 4 - shadow_dirty = false */
285 if (i++ == 3) {
286 DSSERR("mgr(%d)->wait_for_go() not finishing\n",
287 mgr->id);
288 r = 0;
289 break;
290 }
291
292 r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
293 if (r == -ERESTARTSYS)
294 break;
295
296 if (r) {
297 DSSERR("mgr(%d)->wait_for_go() timeout\n", mgr->id);
298 break;
299 }
300 }
301
302 return r;
303}
304
305int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl)
306{
307 unsigned long timeout = msecs_to_jiffies(500);
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200308 struct ovl_priv_data *op;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200309 struct omap_dss_device *dssdev;
310 u32 irq;
311 int r;
312 int i;
313
314 if (!ovl->manager)
315 return 0;
316
317 dssdev = ovl->manager->device;
318
319 if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
320 return 0;
321
322 if (ovl_manual_update(ovl))
323 return 0;
324
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200325 irq = dispc_mgr_get_vsync_irq(ovl->manager->id);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200326
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200327 op = get_ovl_priv(ovl);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200328 i = 0;
329 while (1) {
330 unsigned long flags;
331 bool shadow_dirty, dirty;
332
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200333 spin_lock_irqsave(&data_lock, flags);
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200334 dirty = op->dirty;
335 shadow_dirty = op->shadow_dirty;
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200336 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200337
338 if (!dirty && !shadow_dirty) {
339 r = 0;
340 break;
341 }
342
343 /* 4 iterations is the worst case:
344 * 1 - initial iteration, dirty = true (between VFP and VSYNC)
345 * 2 - first VSYNC, dirty = true
346 * 3 - dirty = false, shadow_dirty = true
347 * 4 - shadow_dirty = false */
348 if (i++ == 3) {
349 DSSERR("ovl(%d)->wait_for_go() not finishing\n",
350 ovl->id);
351 r = 0;
352 break;
353 }
354
355 r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
356 if (r == -ERESTARTSYS)
357 break;
358
359 if (r) {
360 DSSERR("ovl(%d)->wait_for_go() timeout\n", ovl->id);
361 break;
362 }
363 }
364
365 return r;
366}
367
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200368static void dss_ovl_write_regs(struct omap_overlay *ovl)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200369{
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200370 struct ovl_priv_data *op = get_ovl_priv(ovl);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200371 struct omap_overlay_info *oi;
372 bool ilace, replication;
Tomi Valkeinen34861372011-11-18 15:43:29 +0200373 struct mgr_priv_data *mp;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200374 int r;
375
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200376 DSSDBGF("%d", ovl->id);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200377
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200378 if (!op->enabled || !op->dirty)
379 return;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200380
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200381 oi = &op->info;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200382
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200383 replication = dss_use_replication(ovl->manager->device, oi->color_mode);
384
385 ilace = ovl->manager->device->type == OMAP_DISPLAY_TYPE_VENC;
386
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200387 dispc_ovl_set_channel_out(ovl->id, op->channel);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200388
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200389 r = dispc_ovl_setup(ovl->id, oi, ilace, replication);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200390 if (r) {
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200391 /*
392 * We can't do much here, as this function can be called from
393 * vsync interrupt.
394 */
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200395 DSSERR("dispc_ovl_setup failed for ovl %d\n", ovl->id);
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200396
397 /* This will leave fifo configurations in a nonoptimal state */
398 op->enabled = false;
399 dispc_ovl_enable(ovl->id, false);
400 return;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200401 }
402
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200403 dispc_ovl_set_fifo_threshold(ovl->id, op->fifo_low, op->fifo_high);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200404
Tomi Valkeinen34861372011-11-18 15:43:29 +0200405 mp = get_mgr_priv(ovl->manager);
406
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200407 op->dirty = false;
Tomi Valkeinen34861372011-11-18 15:43:29 +0200408 if (mp->updating)
409 op->shadow_dirty = true;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200410}
411
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200412static void dss_ovl_write_regs_extra(struct omap_overlay *ovl)
413{
414 struct ovl_priv_data *op = get_ovl_priv(ovl);
Tomi Valkeinen34861372011-11-18 15:43:29 +0200415 struct mgr_priv_data *mp;
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200416
417 DSSDBGF("%d", ovl->id);
418
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200419 if (!op->extra_info_dirty)
420 return;
421
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200422 /* note: write also when op->enabled == false, so that the ovl gets
423 * disabled */
424
425 dispc_ovl_enable(ovl->id, op->enabled);
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200426
Tomi Valkeinen34861372011-11-18 15:43:29 +0200427 mp = get_mgr_priv(ovl->manager);
428
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200429 op->extra_info_dirty = false;
Tomi Valkeinen34861372011-11-18 15:43:29 +0200430 if (mp->updating)
431 op->shadow_extra_info_dirty = true;
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200432}
433
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200434static void dss_mgr_write_regs(struct omap_overlay_manager *mgr)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200435{
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200436 struct mgr_priv_data *mp = get_mgr_priv(mgr);
437 struct omap_overlay *ovl;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200438
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200439 DSSDBGF("%d", mgr->id);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200440
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200441 if (!mp->enabled)
442 return;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200443
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200444 WARN_ON(mp->busy);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200445
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200446 /* Commit overlay settings */
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200447 list_for_each_entry(ovl, &mgr->overlays, list) {
448 dss_ovl_write_regs(ovl);
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200449 dss_ovl_write_regs_extra(ovl);
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200450 }
451
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200452 if (mp->dirty) {
453 dispc_mgr_setup(mgr->id, &mp->info);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200454
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200455 mp->dirty = false;
Tomi Valkeinen34861372011-11-18 15:43:29 +0200456 if (mp->updating)
457 mp->shadow_dirty = true;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200458 }
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200459}
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200460
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200461static void dss_write_regs(void)
462{
463 const int num_mgrs = omap_dss_get_num_overlay_managers();
464 int i;
465
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200466 for (i = 0; i < num_mgrs; ++i) {
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200467 struct omap_overlay_manager *mgr;
468 struct mgr_priv_data *mp;
469
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200470 mgr = omap_dss_get_overlay_manager(i);
471 mp = get_mgr_priv(mgr);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200472
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200473 if (!mp->enabled || mgr_manual_update(mgr) || mp->busy)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200474 continue;
475
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200476 dss_mgr_write_regs(mgr);
477
478 if (need_go(mgr)) {
Tomi Valkeinen43a972d2011-11-15 15:04:25 +0200479 mp->busy = true;
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200480
481 if (!dss_data.irq_enabled && need_isr())
482 dss_register_vsync_isr();
483
484 dispc_mgr_go(mgr->id);
Tomi Valkeinen43a972d2011-11-15 15:04:25 +0200485 }
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200486 }
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200487}
488
489void dss_mgr_start_update(struct omap_overlay_manager *mgr)
490{
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200491 struct mgr_priv_data *mp = get_mgr_priv(mgr);
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200492 unsigned long flags;
493
494 spin_lock_irqsave(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200495
Tomi Valkeinen34861372011-11-18 15:43:29 +0200496 WARN_ON(mp->updating);
497
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200498 dss_mgr_write_regs(mgr);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200499
Tomi Valkeinen34861372011-11-18 15:43:29 +0200500 mp->updating = true;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200501
Tomi Valkeinen34861372011-11-18 15:43:29 +0200502 if (!dss_data.irq_enabled && need_isr())
503 dss_register_vsync_isr();
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200504
Tomi Valkeinen7797c6d2011-11-04 10:22:46 +0200505 dispc_mgr_enable(mgr->id, true);
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200506
507 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200508}
509
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200510static void dss_apply_irq_handler(void *data, u32 mask);
511
512static void dss_register_vsync_isr(void)
513{
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200514 const int num_mgrs = dss_feat_get_num_mgrs();
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200515 u32 mask;
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200516 int r, i;
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200517
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200518 mask = 0;
519 for (i = 0; i < num_mgrs; ++i)
520 mask |= dispc_mgr_get_vsync_irq(i);
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200521
Tomi Valkeinen34861372011-11-18 15:43:29 +0200522 for (i = 0; i < num_mgrs; ++i)
523 mask |= dispc_mgr_get_framedone_irq(i);
524
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200525 r = omap_dispc_register_isr(dss_apply_irq_handler, NULL, mask);
526 WARN_ON(r);
527
Tomi Valkeinend09c7aa2011-11-15 12:04:43 +0200528 dss_data.irq_enabled = true;
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200529}
530
531static void dss_unregister_vsync_isr(void)
532{
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200533 const int num_mgrs = dss_feat_get_num_mgrs();
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200534 u32 mask;
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200535 int r, i;
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200536
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200537 mask = 0;
538 for (i = 0; i < num_mgrs; ++i)
539 mask |= dispc_mgr_get_vsync_irq(i);
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200540
Tomi Valkeinen34861372011-11-18 15:43:29 +0200541 for (i = 0; i < num_mgrs; ++i)
542 mask |= dispc_mgr_get_framedone_irq(i);
543
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200544 r = omap_dispc_unregister_isr(dss_apply_irq_handler, NULL, mask);
545 WARN_ON(r);
546
Tomi Valkeinend09c7aa2011-11-15 12:04:43 +0200547 dss_data.irq_enabled = false;
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200548}
549
Tomi Valkeinen76098932011-11-16 12:03:22 +0200550static void mgr_clear_shadow_dirty(struct omap_overlay_manager *mgr)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200551{
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200552 struct omap_overlay *ovl;
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200553 struct mgr_priv_data *mp;
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200554 struct ovl_priv_data *op;
Tomi Valkeinen76098932011-11-16 12:03:22 +0200555
556 mp = get_mgr_priv(mgr);
557 mp->shadow_dirty = false;
558
559 list_for_each_entry(ovl, &mgr->overlays, list) {
560 op = get_ovl_priv(ovl);
561 op->shadow_dirty = false;
562 op->shadow_extra_info_dirty = false;
563 }
564}
565
566static void dss_apply_irq_handler(void *data, u32 mask)
567{
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200568 const int num_mgrs = dss_feat_get_num_mgrs();
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200569 int i;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200570
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200571 spin_lock(&data_lock);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200572
Tomi Valkeinen76098932011-11-16 12:03:22 +0200573 /* clear busy, updating flags, shadow_dirty flags */
Tomi Valkeinen43a972d2011-11-15 15:04:25 +0200574 for (i = 0; i < num_mgrs; i++) {
Tomi Valkeinen76098932011-11-16 12:03:22 +0200575 struct omap_overlay_manager *mgr;
576 struct mgr_priv_data *mp;
577
Tomi Valkeinen43a972d2011-11-15 15:04:25 +0200578 mgr = omap_dss_get_overlay_manager(i);
579 mp = get_mgr_priv(mgr);
580
Tomi Valkeinen76098932011-11-16 12:03:22 +0200581 if (!mp->enabled)
Tomi Valkeinen43a972d2011-11-15 15:04:25 +0200582 continue;
583
Tomi Valkeinen76098932011-11-16 12:03:22 +0200584 mp->updating = dispc_mgr_is_enabled(i);
Tomi Valkeinen43a972d2011-11-15 15:04:25 +0200585
Tomi Valkeinen76098932011-11-16 12:03:22 +0200586 if (!mgr_manual_update(mgr)) {
587 mp->busy = dispc_mgr_go_busy(i);
588
589 if (!mp->busy)
590 mgr_clear_shadow_dirty(mgr);
591 } else {
592 if (!mp->updating)
593 mgr_clear_shadow_dirty(mgr);
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200594 }
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200595 }
596
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200597 dss_write_regs();
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200598
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200599 if (!need_isr())
600 dss_unregister_vsync_isr();
Tomi Valkeinen43a972d2011-11-15 15:04:25 +0200601
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200602 spin_unlock(&data_lock);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200603}
604
Tomi Valkeinen5738b632011-11-15 13:37:33 +0200605static void omap_dss_mgr_apply_ovl(struct omap_overlay *ovl)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200606{
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200607 struct ovl_priv_data *op;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200608
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200609 op = get_ovl_priv(ovl);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200610
611 if (ovl->manager_changed) {
612 ovl->manager_changed = false;
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +0200613 op->user_info_dirty = true;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200614 }
615
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +0200616 if (!op->user_info_dirty)
Tomi Valkeinen5738b632011-11-15 13:37:33 +0200617 return;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200618
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +0200619 op->user_info_dirty = false;
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200620 op->dirty = true;
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +0200621 op->info = op->user_info;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200622
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200623 op->channel = ovl->manager->id;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200624}
625
626static void omap_dss_mgr_apply_mgr(struct omap_overlay_manager *mgr)
627{
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200628 struct mgr_priv_data *mp;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200629
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200630 mp = get_mgr_priv(mgr);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200631
632 if (mgr->device_changed) {
633 mgr->device_changed = false;
Tomi Valkeinen388c4c62011-11-16 13:58:07 +0200634 mp->user_info_dirty = true;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200635 }
636
Tomi Valkeinen388c4c62011-11-16 13:58:07 +0200637 if (!mp->user_info_dirty)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200638 return;
639
Tomi Valkeinen388c4c62011-11-16 13:58:07 +0200640 mp->user_info_dirty = false;
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200641 mp->dirty = true;
Tomi Valkeinen388c4c62011-11-16 13:58:07 +0200642 mp->info = mp->user_info;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200643}
644
645static void omap_dss_mgr_apply_ovl_fifos(struct omap_overlay *ovl)
646{
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200647 struct ovl_priv_data *op;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200648 struct omap_dss_device *dssdev;
649 u32 size, burst_size;
650
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200651 op = get_ovl_priv(ovl);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200652
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200653 dssdev = ovl->manager->device;
654
655 size = dispc_ovl_get_fifo_size(ovl->id);
656
657 burst_size = dispc_ovl_get_burst_size(ovl->id);
658
659 switch (dssdev->type) {
660 case OMAP_DISPLAY_TYPE_DPI:
661 case OMAP_DISPLAY_TYPE_DBI:
662 case OMAP_DISPLAY_TYPE_SDI:
663 case OMAP_DISPLAY_TYPE_VENC:
664 case OMAP_DISPLAY_TYPE_HDMI:
665 default_get_overlay_fifo_thresholds(ovl->id, size,
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200666 burst_size, &op->fifo_low,
667 &op->fifo_high);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200668 break;
669#ifdef CONFIG_OMAP2_DSS_DSI
670 case OMAP_DISPLAY_TYPE_DSI:
671 dsi_get_overlay_fifo_thresholds(ovl->id, size,
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200672 burst_size, &op->fifo_low,
673 &op->fifo_high);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200674 break;
675#endif
676 default:
677 BUG();
678 }
679}
680
681int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
682{
Tomi Valkeinen07e327c2011-11-05 10:59:59 +0200683 int r;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200684 unsigned long flags;
Tomi Valkeinen07e327c2011-11-05 10:59:59 +0200685 struct omap_overlay *ovl;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200686
687 DSSDBG("omap_dss_mgr_apply(%s)\n", mgr->name);
688
689 r = dispc_runtime_get();
690 if (r)
691 return r;
692
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200693 spin_lock_irqsave(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200694
695 /* Configure overlays */
Tomi Valkeinen07e327c2011-11-05 10:59:59 +0200696 list_for_each_entry(ovl, &mgr->overlays, list)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200697 omap_dss_mgr_apply_ovl(ovl);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200698
699 /* Configure manager */
700 omap_dss_mgr_apply_mgr(mgr);
701
702 /* Configure overlay fifos */
Tomi Valkeinen07e327c2011-11-05 10:59:59 +0200703 list_for_each_entry(ovl, &mgr->overlays, list)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200704 omap_dss_mgr_apply_ovl_fifos(ovl);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200705
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200706 dss_write_regs();
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200707
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200708 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200709
710 dispc_runtime_put();
711
712 return r;
713}
714
Tomi Valkeinen7797c6d2011-11-04 10:22:46 +0200715void dss_mgr_enable(struct omap_overlay_manager *mgr)
716{
Tomi Valkeinenbf213522011-11-15 14:43:53 +0200717 struct mgr_priv_data *mp = get_mgr_priv(mgr);
718 unsigned long flags;
719
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200720 mutex_lock(&apply_lock);
721
Tomi Valkeinenbf213522011-11-15 14:43:53 +0200722 spin_lock_irqsave(&data_lock, flags);
723
724 mp->enabled = true;
725
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200726 dss_write_regs();
727
Tomi Valkeinen34861372011-11-18 15:43:29 +0200728 if (!mgr_manual_update(mgr))
729 mp->updating = true;
730
Tomi Valkeinenbf213522011-11-15 14:43:53 +0200731 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200732
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200733 if (!mgr_manual_update(mgr))
734 dispc_mgr_enable(mgr->id, true);
735
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200736 mutex_unlock(&apply_lock);
Tomi Valkeinen7797c6d2011-11-04 10:22:46 +0200737}
738
739void dss_mgr_disable(struct omap_overlay_manager *mgr)
740{
Tomi Valkeinenbf213522011-11-15 14:43:53 +0200741 struct mgr_priv_data *mp = get_mgr_priv(mgr);
742 unsigned long flags;
743
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200744 mutex_lock(&apply_lock);
745
Tomi Valkeinen9a147a62011-11-09 15:30:11 +0200746 if (!mgr_manual_update(mgr))
747 dispc_mgr_enable(mgr->id, false);
Tomi Valkeinenbf213522011-11-15 14:43:53 +0200748
749 spin_lock_irqsave(&data_lock, flags);
750
Tomi Valkeinen34861372011-11-18 15:43:29 +0200751 mp->updating = false;
Tomi Valkeinenbf213522011-11-15 14:43:53 +0200752 mp->enabled = false;
753
754 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200755
756 mutex_unlock(&apply_lock);
Tomi Valkeinen7797c6d2011-11-04 10:22:46 +0200757}
758
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200759int dss_mgr_set_info(struct omap_overlay_manager *mgr,
760 struct omap_overlay_manager_info *info)
761{
Tomi Valkeinen388c4c62011-11-16 13:58:07 +0200762 struct mgr_priv_data *mp = get_mgr_priv(mgr);
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200763 unsigned long flags;
764
765 spin_lock_irqsave(&data_lock, flags);
766
Tomi Valkeinen388c4c62011-11-16 13:58:07 +0200767 mp->user_info = *info;
768 mp->user_info_dirty = true;
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200769
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200770 spin_unlock_irqrestore(&data_lock, flags);
771
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200772 return 0;
773}
774
775void dss_mgr_get_info(struct omap_overlay_manager *mgr,
776 struct omap_overlay_manager_info *info)
777{
Tomi Valkeinen388c4c62011-11-16 13:58:07 +0200778 struct mgr_priv_data *mp = get_mgr_priv(mgr);
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200779 unsigned long flags;
780
781 spin_lock_irqsave(&data_lock, flags);
782
Tomi Valkeinen388c4c62011-11-16 13:58:07 +0200783 *info = mp->user_info;
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200784
785 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200786}
787
788int dss_mgr_set_device(struct omap_overlay_manager *mgr,
789 struct omap_dss_device *dssdev)
790{
791 int r;
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200792
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200793 mutex_lock(&apply_lock);
794
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200795 if (dssdev->manager) {
796 DSSERR("display '%s' already has a manager '%s'\n",
797 dssdev->name, dssdev->manager->name);
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200798 r = -EINVAL;
799 goto err;
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200800 }
801
802 if ((mgr->supported_displays & dssdev->type) == 0) {
803 DSSERR("display '%s' does not support manager '%s'\n",
804 dssdev->name, mgr->name);
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200805 r = -EINVAL;
806 goto err;
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200807 }
808
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200809 dssdev->manager = mgr;
810 mgr->device = dssdev;
811 mgr->device_changed = true;
812
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200813 mutex_unlock(&apply_lock);
814
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200815 return 0;
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200816err:
817 mutex_unlock(&apply_lock);
818 return r;
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200819}
820
821int dss_mgr_unset_device(struct omap_overlay_manager *mgr)
822{
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200823 int r;
824
825 mutex_lock(&apply_lock);
826
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200827 if (!mgr->device) {
828 DSSERR("failed to unset display, display not set.\n");
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200829 r = -EINVAL;
830 goto err;
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200831 }
832
833 /*
834 * Don't allow currently enabled displays to have the overlay manager
835 * pulled out from underneath them
836 */
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200837 if (mgr->device->state != OMAP_DSS_DISPLAY_DISABLED) {
838 r = -EINVAL;
839 goto err;
840 }
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200841
842 mgr->device->manager = NULL;
843 mgr->device = NULL;
844 mgr->device_changed = true;
845
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200846 mutex_unlock(&apply_lock);
847
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200848 return 0;
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200849err:
850 mutex_unlock(&apply_lock);
851 return r;
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200852}
853
854
855
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200856int dss_ovl_set_info(struct omap_overlay *ovl,
857 struct omap_overlay_info *info)
858{
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +0200859 struct ovl_priv_data *op = get_ovl_priv(ovl);
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200860 unsigned long flags;
861
862 spin_lock_irqsave(&data_lock, flags);
863
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +0200864 op->user_info = *info;
865 op->user_info_dirty = true;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200866
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200867 spin_unlock_irqrestore(&data_lock, flags);
868
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200869 return 0;
870}
871
872void dss_ovl_get_info(struct omap_overlay *ovl,
873 struct omap_overlay_info *info)
874{
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +0200875 struct ovl_priv_data *op = get_ovl_priv(ovl);
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200876 unsigned long flags;
877
878 spin_lock_irqsave(&data_lock, flags);
879
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +0200880 *info = op->user_info;
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200881
882 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200883}
884
885int dss_ovl_set_manager(struct omap_overlay *ovl,
886 struct omap_overlay_manager *mgr)
887{
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200888 struct ovl_priv_data *op = get_ovl_priv(ovl);
889 unsigned long flags;
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200890 int r;
891
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200892 if (!mgr)
893 return -EINVAL;
894
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200895 mutex_lock(&apply_lock);
896
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200897 if (ovl->manager) {
898 DSSERR("overlay '%s' already has a manager '%s'\n",
899 ovl->name, ovl->manager->name);
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200900 r = -EINVAL;
901 goto err;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200902 }
903
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200904 spin_lock_irqsave(&data_lock, flags);
905
906 if (op->enabled) {
907 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200908 DSSERR("overlay has to be disabled to change the manager\n");
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200909 r = -EINVAL;
910 goto err;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200911 }
912
913 ovl->manager = mgr;
914 list_add_tail(&ovl->list, &mgr->overlays);
915 ovl->manager_changed = true;
916
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200917 spin_unlock_irqrestore(&data_lock, flags);
918
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200919 /* XXX: When there is an overlay on a DSI manual update display, and
920 * the overlay is first disabled, then moved to tv, and enabled, we
921 * seem to get SYNC_LOST_DIGIT error.
922 *
923 * Waiting doesn't seem to help, but updating the manual update display
924 * after disabling the overlay seems to fix this. This hints that the
925 * overlay is perhaps somehow tied to the LCD output until the output
926 * is updated.
927 *
928 * Userspace workaround for this is to update the LCD after disabling
929 * the overlay, but before moving the overlay to TV.
930 */
931
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200932 mutex_unlock(&apply_lock);
933
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200934 return 0;
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200935err:
936 mutex_unlock(&apply_lock);
937 return r;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200938}
939
940int dss_ovl_unset_manager(struct omap_overlay *ovl)
941{
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200942 struct ovl_priv_data *op = get_ovl_priv(ovl);
943 unsigned long flags;
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200944 int r;
945
946 mutex_lock(&apply_lock);
947
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200948 if (!ovl->manager) {
949 DSSERR("failed to detach overlay: manager not set\n");
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200950 r = -EINVAL;
951 goto err;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200952 }
953
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200954 spin_lock_irqsave(&data_lock, flags);
955
956 if (op->enabled) {
957 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200958 DSSERR("overlay has to be disabled to unset the manager\n");
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200959 r = -EINVAL;
960 goto err;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200961 }
962
963 ovl->manager = NULL;
964 list_del(&ovl->list);
965 ovl->manager_changed = true;
966
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200967 spin_unlock_irqrestore(&data_lock, flags);
968
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200969 mutex_unlock(&apply_lock);
970
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200971 return 0;
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200972err:
973 mutex_unlock(&apply_lock);
974 return r;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200975}
976
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200977bool dss_ovl_is_enabled(struct omap_overlay *ovl)
978{
979 struct ovl_priv_data *op = get_ovl_priv(ovl);
980 unsigned long flags;
981 bool e;
982
983 spin_lock_irqsave(&data_lock, flags);
984
985 e = op->enabled;
986
987 spin_unlock_irqrestore(&data_lock, flags);
988
989 return e;
990}
991
992int dss_ovl_enable(struct omap_overlay *ovl)
993{
994 struct ovl_priv_data *op = get_ovl_priv(ovl);
995 unsigned long flags;
996 int r;
997
998 mutex_lock(&apply_lock);
999
1000 if (ovl->manager == NULL || ovl->manager->device == NULL) {
1001 r = -EINVAL;
1002 goto err;
1003 }
1004
1005 spin_lock_irqsave(&data_lock, flags);
1006
1007 op->enabled = true;
1008 op->extra_info_dirty = true;
1009
Tomi Valkeinen75c94962011-11-15 18:25:23 +02001010 dss_write_regs();
1011
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001012 spin_unlock_irqrestore(&data_lock, flags);
1013
1014 mutex_unlock(&apply_lock);
1015
1016 return 0;
1017err:
1018 mutex_unlock(&apply_lock);
1019 return r;
1020}
1021
1022int dss_ovl_disable(struct omap_overlay *ovl)
1023{
1024 struct ovl_priv_data *op = get_ovl_priv(ovl);
1025 unsigned long flags;
1026 int r;
1027
1028 mutex_lock(&apply_lock);
1029
1030 if (ovl->manager == NULL || ovl->manager->device == NULL) {
1031 r = -EINVAL;
1032 goto err;
1033 }
1034
1035 spin_lock_irqsave(&data_lock, flags);
1036
1037 op->enabled = false;
1038 op->extra_info_dirty = true;
1039
Tomi Valkeinen75c94962011-11-15 18:25:23 +02001040 dss_write_regs();
1041
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001042 spin_unlock_irqrestore(&data_lock, flags);
1043
1044 mutex_unlock(&apply_lock);
1045
1046 return 0;
1047
1048err:
1049 mutex_unlock(&apply_lock);
1050 return r;
1051}
1052