blob: 3fd2ea163f0552c3df42b735f08c96d3ea514fbf [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
Tomi Valkeinen58f255482011-11-04 09:48:54 +020072 u32 fifo_low;
73 u32 fifo_high;
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +020074
75 bool extra_info_dirty;
76 bool shadow_extra_info_dirty;
77
78 bool enabled;
Tomi Valkeinen5d5a97a2011-11-16 14:17:54 +020079 enum omap_channel channel;
Tomi Valkeinen58f255482011-11-04 09:48:54 +020080};
81
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +020082struct mgr_priv_data {
Tomi Valkeinen388c4c62011-11-16 13:58:07 +020083
84 bool user_info_dirty;
85 struct omap_overlay_manager_info user_info;
86
Tomi Valkeinen58f255482011-11-04 09:48:54 +020087 /* If true, cache changed, but not written to shadow registers. Set
88 * in apply(), cleared when registers written. */
89 bool dirty;
90 /* If true, shadow registers contain changed values not yet in real
91 * registers. Set when writing to shadow registers, cleared at
92 * VSYNC/EVSYNC */
93 bool shadow_dirty;
94
95 struct omap_overlay_manager_info info;
96
Tomi Valkeinen43a972d2011-11-15 15:04:25 +020097 /* If true, GO bit is up and shadow registers cannot be written.
98 * Never true for manual update displays */
99 bool busy;
100
Tomi Valkeinen34861372011-11-18 15:43:29 +0200101 /* If true, dispc output is enabled */
102 bool updating;
103
Tomi Valkeinenbf213522011-11-15 14:43:53 +0200104 /* If true, a display is enabled using this manager */
105 bool enabled;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200106};
107
108static struct {
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200109 struct ovl_priv_data ovl_priv_data_array[MAX_DSS_OVERLAYS];
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200110 struct mgr_priv_data mgr_priv_data_array[MAX_DSS_MANAGERS];
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200111
112 bool irq_enabled;
Tomi Valkeinend09c7aa2011-11-15 12:04:43 +0200113} dss_data;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200114
Tomi Valkeinend09c7aa2011-11-15 12:04:43 +0200115/* protects dss_data */
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200116static spinlock_t data_lock;
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200117/* lock for blocking functions */
118static DEFINE_MUTEX(apply_lock);
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200119
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200120static void dss_register_vsync_isr(void);
121
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200122static struct ovl_priv_data *get_ovl_priv(struct omap_overlay *ovl)
123{
Tomi Valkeinend09c7aa2011-11-15 12:04:43 +0200124 return &dss_data.ovl_priv_data_array[ovl->id];
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200125}
126
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200127static struct mgr_priv_data *get_mgr_priv(struct omap_overlay_manager *mgr)
128{
Tomi Valkeinend09c7aa2011-11-15 12:04:43 +0200129 return &dss_data.mgr_priv_data_array[mgr->id];
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200130}
131
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200132void dss_apply_init(void)
133{
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +0200134 const int num_ovls = dss_feat_get_num_ovls();
135 int i;
136
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200137 spin_lock_init(&data_lock);
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +0200138
139 for (i = 0; i < num_ovls; ++i) {
140 struct ovl_priv_data *op;
141
142 op = &dss_data.ovl_priv_data_array[i];
143
144 op->info.global_alpha = 255;
145
146 switch (i) {
147 case 0:
148 op->info.zorder = 0;
149 break;
150 case 1:
151 op->info.zorder =
152 dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 3 : 0;
153 break;
154 case 2:
155 op->info.zorder =
156 dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 2 : 0;
157 break;
158 case 3:
159 op->info.zorder =
160 dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 1 : 0;
161 break;
162 }
163
164 op->user_info = op->info;
165 }
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200166}
167
168static bool ovl_manual_update(struct omap_overlay *ovl)
169{
170 return ovl->manager->device->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE;
171}
172
173static bool mgr_manual_update(struct omap_overlay_manager *mgr)
174{
175 return mgr->device->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE;
176}
177
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200178static bool need_isr(void)
179{
180 const int num_mgrs = dss_feat_get_num_mgrs();
181 int i;
182
183 for (i = 0; i < num_mgrs; ++i) {
184 struct omap_overlay_manager *mgr;
185 struct mgr_priv_data *mp;
186 struct omap_overlay *ovl;
187
188 mgr = omap_dss_get_overlay_manager(i);
189 mp = get_mgr_priv(mgr);
190
191 if (!mp->enabled)
192 continue;
193
Tomi Valkeinen34861372011-11-18 15:43:29 +0200194 if (mgr_manual_update(mgr)) {
195 /* to catch FRAMEDONE */
196 if (mp->updating)
197 return true;
198 } else {
199 /* to catch GO bit going down */
200 if (mp->busy)
201 return true;
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200202
203 /* to write new values to registers */
Tomi Valkeinen34861372011-11-18 15:43:29 +0200204 if (mp->dirty)
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200205 return true;
Tomi Valkeinen34861372011-11-18 15:43:29 +0200206
207 list_for_each_entry(ovl, &mgr->overlays, list) {
208 struct ovl_priv_data *op;
209
210 op = get_ovl_priv(ovl);
211
212 if (!op->enabled)
213 continue;
214
215 /* to write new values to registers */
216 if (op->dirty || op->extra_info_dirty)
217 return true;
218 }
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200219 }
220 }
221
222 return false;
223}
224
225static bool need_go(struct omap_overlay_manager *mgr)
226{
227 struct omap_overlay *ovl;
228 struct mgr_priv_data *mp;
229 struct ovl_priv_data *op;
230
231 mp = get_mgr_priv(mgr);
232
233 if (mp->shadow_dirty)
234 return true;
235
236 list_for_each_entry(ovl, &mgr->overlays, list) {
237 op = get_ovl_priv(ovl);
238 if (op->shadow_dirty || op->shadow_extra_info_dirty)
239 return true;
240 }
241
242 return false;
243}
244
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200245int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr)
246{
247 unsigned long timeout = msecs_to_jiffies(500);
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200248 struct mgr_priv_data *mp;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200249 u32 irq;
250 int r;
251 int i;
252 struct omap_dss_device *dssdev = mgr->device;
253
254 if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
255 return 0;
256
257 if (mgr_manual_update(mgr))
258 return 0;
259
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200260 irq = dispc_mgr_get_vsync_irq(mgr->id);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200261
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200262 mp = get_mgr_priv(mgr);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200263 i = 0;
264 while (1) {
265 unsigned long flags;
266 bool shadow_dirty, dirty;
267
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200268 spin_lock_irqsave(&data_lock, flags);
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200269 dirty = mp->dirty;
270 shadow_dirty = mp->shadow_dirty;
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200271 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200272
273 if (!dirty && !shadow_dirty) {
274 r = 0;
275 break;
276 }
277
278 /* 4 iterations is the worst case:
279 * 1 - initial iteration, dirty = true (between VFP and VSYNC)
280 * 2 - first VSYNC, dirty = true
281 * 3 - dirty = false, shadow_dirty = true
282 * 4 - shadow_dirty = false */
283 if (i++ == 3) {
284 DSSERR("mgr(%d)->wait_for_go() not finishing\n",
285 mgr->id);
286 r = 0;
287 break;
288 }
289
290 r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
291 if (r == -ERESTARTSYS)
292 break;
293
294 if (r) {
295 DSSERR("mgr(%d)->wait_for_go() timeout\n", mgr->id);
296 break;
297 }
298 }
299
300 return r;
301}
302
303int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl)
304{
305 unsigned long timeout = msecs_to_jiffies(500);
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200306 struct ovl_priv_data *op;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200307 struct omap_dss_device *dssdev;
308 u32 irq;
309 int r;
310 int i;
311
312 if (!ovl->manager)
313 return 0;
314
315 dssdev = ovl->manager->device;
316
317 if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
318 return 0;
319
320 if (ovl_manual_update(ovl))
321 return 0;
322
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200323 irq = dispc_mgr_get_vsync_irq(ovl->manager->id);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200324
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200325 op = get_ovl_priv(ovl);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200326 i = 0;
327 while (1) {
328 unsigned long flags;
329 bool shadow_dirty, dirty;
330
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200331 spin_lock_irqsave(&data_lock, flags);
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200332 dirty = op->dirty;
333 shadow_dirty = op->shadow_dirty;
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200334 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200335
336 if (!dirty && !shadow_dirty) {
337 r = 0;
338 break;
339 }
340
341 /* 4 iterations is the worst case:
342 * 1 - initial iteration, dirty = true (between VFP and VSYNC)
343 * 2 - first VSYNC, dirty = true
344 * 3 - dirty = false, shadow_dirty = true
345 * 4 - shadow_dirty = false */
346 if (i++ == 3) {
347 DSSERR("ovl(%d)->wait_for_go() not finishing\n",
348 ovl->id);
349 r = 0;
350 break;
351 }
352
353 r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
354 if (r == -ERESTARTSYS)
355 break;
356
357 if (r) {
358 DSSERR("ovl(%d)->wait_for_go() timeout\n", ovl->id);
359 break;
360 }
361 }
362
363 return r;
364}
365
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200366static void dss_ovl_write_regs(struct omap_overlay *ovl)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200367{
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200368 struct ovl_priv_data *op = get_ovl_priv(ovl);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200369 struct omap_overlay_info *oi;
370 bool ilace, replication;
Tomi Valkeinen34861372011-11-18 15:43:29 +0200371 struct mgr_priv_data *mp;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200372 int r;
373
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200374 DSSDBGF("%d", ovl->id);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200375
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200376 if (!op->enabled || !op->dirty)
377 return;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200378
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200379 oi = &op->info;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200380
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200381 replication = dss_use_replication(ovl->manager->device, oi->color_mode);
382
383 ilace = ovl->manager->device->type == OMAP_DISPLAY_TYPE_VENC;
384
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200385 r = dispc_ovl_setup(ovl->id, oi, ilace, replication);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200386 if (r) {
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200387 /*
388 * We can't do much here, as this function can be called from
389 * vsync interrupt.
390 */
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200391 DSSERR("dispc_ovl_setup failed for ovl %d\n", ovl->id);
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200392
393 /* This will leave fifo configurations in a nonoptimal state */
394 op->enabled = false;
395 dispc_ovl_enable(ovl->id, false);
396 return;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200397 }
398
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200399 dispc_ovl_set_fifo_threshold(ovl->id, op->fifo_low, op->fifo_high);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200400
Tomi Valkeinen34861372011-11-18 15:43:29 +0200401 mp = get_mgr_priv(ovl->manager);
402
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200403 op->dirty = false;
Tomi Valkeinen34861372011-11-18 15:43:29 +0200404 if (mp->updating)
405 op->shadow_dirty = true;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200406}
407
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200408static void dss_ovl_write_regs_extra(struct omap_overlay *ovl)
409{
410 struct ovl_priv_data *op = get_ovl_priv(ovl);
Tomi Valkeinen34861372011-11-18 15:43:29 +0200411 struct mgr_priv_data *mp;
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200412
413 DSSDBGF("%d", ovl->id);
414
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200415 if (!op->extra_info_dirty)
416 return;
417
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200418 /* note: write also when op->enabled == false, so that the ovl gets
419 * disabled */
420
421 dispc_ovl_enable(ovl->id, op->enabled);
Tomi Valkeinen5d5a97a2011-11-16 14:17:54 +0200422 dispc_ovl_set_channel_out(ovl->id, op->channel);
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200423
Tomi Valkeinen34861372011-11-18 15:43:29 +0200424 mp = get_mgr_priv(ovl->manager);
425
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200426 op->extra_info_dirty = false;
Tomi Valkeinen34861372011-11-18 15:43:29 +0200427 if (mp->updating)
428 op->shadow_extra_info_dirty = true;
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200429}
430
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200431static void dss_mgr_write_regs(struct omap_overlay_manager *mgr)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200432{
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200433 struct mgr_priv_data *mp = get_mgr_priv(mgr);
434 struct omap_overlay *ovl;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200435
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200436 DSSDBGF("%d", mgr->id);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200437
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200438 if (!mp->enabled)
439 return;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200440
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200441 WARN_ON(mp->busy);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200442
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200443 /* Commit overlay settings */
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200444 list_for_each_entry(ovl, &mgr->overlays, list) {
445 dss_ovl_write_regs(ovl);
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200446 dss_ovl_write_regs_extra(ovl);
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200447 }
448
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200449 if (mp->dirty) {
450 dispc_mgr_setup(mgr->id, &mp->info);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200451
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200452 mp->dirty = false;
Tomi Valkeinen34861372011-11-18 15:43:29 +0200453 if (mp->updating)
454 mp->shadow_dirty = true;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200455 }
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200456}
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200457
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200458static void dss_write_regs(void)
459{
460 const int num_mgrs = omap_dss_get_num_overlay_managers();
461 int i;
462
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200463 for (i = 0; i < num_mgrs; ++i) {
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200464 struct omap_overlay_manager *mgr;
465 struct mgr_priv_data *mp;
466
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200467 mgr = omap_dss_get_overlay_manager(i);
468 mp = get_mgr_priv(mgr);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200469
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200470 if (!mp->enabled || mgr_manual_update(mgr) || mp->busy)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200471 continue;
472
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200473 dss_mgr_write_regs(mgr);
474
475 if (need_go(mgr)) {
Tomi Valkeinen43a972d2011-11-15 15:04:25 +0200476 mp->busy = true;
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200477
478 if (!dss_data.irq_enabled && need_isr())
479 dss_register_vsync_isr();
480
481 dispc_mgr_go(mgr->id);
Tomi Valkeinen43a972d2011-11-15 15:04:25 +0200482 }
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200483 }
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200484}
485
486void dss_mgr_start_update(struct omap_overlay_manager *mgr)
487{
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200488 struct mgr_priv_data *mp = get_mgr_priv(mgr);
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200489 unsigned long flags;
490
491 spin_lock_irqsave(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200492
Tomi Valkeinen34861372011-11-18 15:43:29 +0200493 WARN_ON(mp->updating);
494
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200495 dss_mgr_write_regs(mgr);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200496
Tomi Valkeinen34861372011-11-18 15:43:29 +0200497 mp->updating = true;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200498
Tomi Valkeinen34861372011-11-18 15:43:29 +0200499 if (!dss_data.irq_enabled && need_isr())
500 dss_register_vsync_isr();
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200501
Tomi Valkeinen7797c6d2011-11-04 10:22:46 +0200502 dispc_mgr_enable(mgr->id, true);
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200503
504 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200505}
506
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200507static void dss_apply_irq_handler(void *data, u32 mask);
508
509static void dss_register_vsync_isr(void)
510{
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200511 const int num_mgrs = dss_feat_get_num_mgrs();
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200512 u32 mask;
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200513 int r, i;
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200514
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200515 mask = 0;
516 for (i = 0; i < num_mgrs; ++i)
517 mask |= dispc_mgr_get_vsync_irq(i);
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200518
Tomi Valkeinen34861372011-11-18 15:43:29 +0200519 for (i = 0; i < num_mgrs; ++i)
520 mask |= dispc_mgr_get_framedone_irq(i);
521
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200522 r = omap_dispc_register_isr(dss_apply_irq_handler, NULL, mask);
523 WARN_ON(r);
524
Tomi Valkeinend09c7aa2011-11-15 12:04:43 +0200525 dss_data.irq_enabled = true;
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200526}
527
528static void dss_unregister_vsync_isr(void)
529{
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200530 const int num_mgrs = dss_feat_get_num_mgrs();
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200531 u32 mask;
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200532 int r, i;
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200533
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200534 mask = 0;
535 for (i = 0; i < num_mgrs; ++i)
536 mask |= dispc_mgr_get_vsync_irq(i);
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200537
Tomi Valkeinen34861372011-11-18 15:43:29 +0200538 for (i = 0; i < num_mgrs; ++i)
539 mask |= dispc_mgr_get_framedone_irq(i);
540
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200541 r = omap_dispc_unregister_isr(dss_apply_irq_handler, NULL, mask);
542 WARN_ON(r);
543
Tomi Valkeinend09c7aa2011-11-15 12:04:43 +0200544 dss_data.irq_enabled = false;
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200545}
546
Tomi Valkeinen76098932011-11-16 12:03:22 +0200547static void mgr_clear_shadow_dirty(struct omap_overlay_manager *mgr)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200548{
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200549 struct omap_overlay *ovl;
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200550 struct mgr_priv_data *mp;
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200551 struct ovl_priv_data *op;
Tomi Valkeinen76098932011-11-16 12:03:22 +0200552
553 mp = get_mgr_priv(mgr);
554 mp->shadow_dirty = false;
555
556 list_for_each_entry(ovl, &mgr->overlays, list) {
557 op = get_ovl_priv(ovl);
558 op->shadow_dirty = false;
559 op->shadow_extra_info_dirty = false;
560 }
561}
562
563static void dss_apply_irq_handler(void *data, u32 mask)
564{
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200565 const int num_mgrs = dss_feat_get_num_mgrs();
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200566 int i;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200567
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200568 spin_lock(&data_lock);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200569
Tomi Valkeinen76098932011-11-16 12:03:22 +0200570 /* clear busy, updating flags, shadow_dirty flags */
Tomi Valkeinen43a972d2011-11-15 15:04:25 +0200571 for (i = 0; i < num_mgrs; i++) {
Tomi Valkeinen76098932011-11-16 12:03:22 +0200572 struct omap_overlay_manager *mgr;
573 struct mgr_priv_data *mp;
574
Tomi Valkeinen43a972d2011-11-15 15:04:25 +0200575 mgr = omap_dss_get_overlay_manager(i);
576 mp = get_mgr_priv(mgr);
577
Tomi Valkeinen76098932011-11-16 12:03:22 +0200578 if (!mp->enabled)
Tomi Valkeinen43a972d2011-11-15 15:04:25 +0200579 continue;
580
Tomi Valkeinen76098932011-11-16 12:03:22 +0200581 mp->updating = dispc_mgr_is_enabled(i);
Tomi Valkeinen43a972d2011-11-15 15:04:25 +0200582
Tomi Valkeinen76098932011-11-16 12:03:22 +0200583 if (!mgr_manual_update(mgr)) {
584 mp->busy = dispc_mgr_go_busy(i);
585
586 if (!mp->busy)
587 mgr_clear_shadow_dirty(mgr);
588 } else {
589 if (!mp->updating)
590 mgr_clear_shadow_dirty(mgr);
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200591 }
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200592 }
593
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200594 dss_write_regs();
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200595
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200596 if (!need_isr())
597 dss_unregister_vsync_isr();
Tomi Valkeinen43a972d2011-11-15 15:04:25 +0200598
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200599 spin_unlock(&data_lock);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200600}
601
Tomi Valkeinen5738b632011-11-15 13:37:33 +0200602static void omap_dss_mgr_apply_ovl(struct omap_overlay *ovl)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200603{
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200604 struct ovl_priv_data *op;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200605
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200606 op = get_ovl_priv(ovl);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200607
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +0200608 if (!op->user_info_dirty)
Tomi Valkeinen5738b632011-11-15 13:37:33 +0200609 return;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200610
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +0200611 op->user_info_dirty = false;
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200612 op->dirty = true;
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +0200613 op->info = op->user_info;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200614}
615
616static void omap_dss_mgr_apply_mgr(struct omap_overlay_manager *mgr)
617{
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200618 struct mgr_priv_data *mp;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200619
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200620 mp = get_mgr_priv(mgr);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200621
622 if (mgr->device_changed) {
623 mgr->device_changed = false;
Tomi Valkeinen388c4c62011-11-16 13:58:07 +0200624 mp->user_info_dirty = true;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200625 }
626
Tomi Valkeinen388c4c62011-11-16 13:58:07 +0200627 if (!mp->user_info_dirty)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200628 return;
629
Tomi Valkeinen388c4c62011-11-16 13:58:07 +0200630 mp->user_info_dirty = false;
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200631 mp->dirty = true;
Tomi Valkeinen388c4c62011-11-16 13:58:07 +0200632 mp->info = mp->user_info;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200633}
634
635static void omap_dss_mgr_apply_ovl_fifos(struct omap_overlay *ovl)
636{
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200637 struct ovl_priv_data *op;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200638 struct omap_dss_device *dssdev;
639 u32 size, burst_size;
640
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200641 op = get_ovl_priv(ovl);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200642
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200643 dssdev = ovl->manager->device;
644
645 size = dispc_ovl_get_fifo_size(ovl->id);
646
647 burst_size = dispc_ovl_get_burst_size(ovl->id);
648
649 switch (dssdev->type) {
650 case OMAP_DISPLAY_TYPE_DPI:
651 case OMAP_DISPLAY_TYPE_DBI:
652 case OMAP_DISPLAY_TYPE_SDI:
653 case OMAP_DISPLAY_TYPE_VENC:
654 case OMAP_DISPLAY_TYPE_HDMI:
655 default_get_overlay_fifo_thresholds(ovl->id, size,
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200656 burst_size, &op->fifo_low,
657 &op->fifo_high);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200658 break;
659#ifdef CONFIG_OMAP2_DSS_DSI
660 case OMAP_DISPLAY_TYPE_DSI:
661 dsi_get_overlay_fifo_thresholds(ovl->id, size,
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200662 burst_size, &op->fifo_low,
663 &op->fifo_high);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200664 break;
665#endif
666 default:
667 BUG();
668 }
669}
670
671int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
672{
Tomi Valkeinen07e327c2011-11-05 10:59:59 +0200673 int r;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200674 unsigned long flags;
Tomi Valkeinen07e327c2011-11-05 10:59:59 +0200675 struct omap_overlay *ovl;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200676
677 DSSDBG("omap_dss_mgr_apply(%s)\n", mgr->name);
678
679 r = dispc_runtime_get();
680 if (r)
681 return r;
682
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200683 spin_lock_irqsave(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200684
685 /* Configure overlays */
Tomi Valkeinen07e327c2011-11-05 10:59:59 +0200686 list_for_each_entry(ovl, &mgr->overlays, list)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200687 omap_dss_mgr_apply_ovl(ovl);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200688
689 /* Configure manager */
690 omap_dss_mgr_apply_mgr(mgr);
691
692 /* Configure overlay fifos */
Tomi Valkeinen07e327c2011-11-05 10:59:59 +0200693 list_for_each_entry(ovl, &mgr->overlays, list)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200694 omap_dss_mgr_apply_ovl_fifos(ovl);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200695
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200696 dss_write_regs();
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200697
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200698 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200699
700 dispc_runtime_put();
701
702 return r;
703}
704
Tomi Valkeinen7797c6d2011-11-04 10:22:46 +0200705void dss_mgr_enable(struct omap_overlay_manager *mgr)
706{
Tomi Valkeinenbf213522011-11-15 14:43:53 +0200707 struct mgr_priv_data *mp = get_mgr_priv(mgr);
708 unsigned long flags;
709
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200710 mutex_lock(&apply_lock);
711
Tomi Valkeinenbf213522011-11-15 14:43:53 +0200712 spin_lock_irqsave(&data_lock, flags);
713
714 mp->enabled = true;
715
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200716 dss_write_regs();
717
Tomi Valkeinen34861372011-11-18 15:43:29 +0200718 if (!mgr_manual_update(mgr))
719 mp->updating = true;
720
Tomi Valkeinenbf213522011-11-15 14:43:53 +0200721 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200722
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200723 if (!mgr_manual_update(mgr))
724 dispc_mgr_enable(mgr->id, true);
725
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200726 mutex_unlock(&apply_lock);
Tomi Valkeinen7797c6d2011-11-04 10:22:46 +0200727}
728
729void dss_mgr_disable(struct omap_overlay_manager *mgr)
730{
Tomi Valkeinenbf213522011-11-15 14:43:53 +0200731 struct mgr_priv_data *mp = get_mgr_priv(mgr);
732 unsigned long flags;
733
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200734 mutex_lock(&apply_lock);
735
Tomi Valkeinen9a147a62011-11-09 15:30:11 +0200736 if (!mgr_manual_update(mgr))
737 dispc_mgr_enable(mgr->id, false);
Tomi Valkeinenbf213522011-11-15 14:43:53 +0200738
739 spin_lock_irqsave(&data_lock, flags);
740
Tomi Valkeinen34861372011-11-18 15:43:29 +0200741 mp->updating = false;
Tomi Valkeinenbf213522011-11-15 14:43:53 +0200742 mp->enabled = false;
743
744 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200745
746 mutex_unlock(&apply_lock);
Tomi Valkeinen7797c6d2011-11-04 10:22:46 +0200747}
748
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200749int dss_mgr_set_info(struct omap_overlay_manager *mgr,
750 struct omap_overlay_manager_info *info)
751{
Tomi Valkeinen388c4c62011-11-16 13:58:07 +0200752 struct mgr_priv_data *mp = get_mgr_priv(mgr);
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200753 unsigned long flags;
754
755 spin_lock_irqsave(&data_lock, flags);
756
Tomi Valkeinen388c4c62011-11-16 13:58:07 +0200757 mp->user_info = *info;
758 mp->user_info_dirty = true;
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200759
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200760 spin_unlock_irqrestore(&data_lock, flags);
761
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200762 return 0;
763}
764
765void dss_mgr_get_info(struct omap_overlay_manager *mgr,
766 struct omap_overlay_manager_info *info)
767{
Tomi Valkeinen388c4c62011-11-16 13:58:07 +0200768 struct mgr_priv_data *mp = get_mgr_priv(mgr);
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200769 unsigned long flags;
770
771 spin_lock_irqsave(&data_lock, flags);
772
Tomi Valkeinen388c4c62011-11-16 13:58:07 +0200773 *info = mp->user_info;
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200774
775 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200776}
777
778int dss_mgr_set_device(struct omap_overlay_manager *mgr,
779 struct omap_dss_device *dssdev)
780{
781 int r;
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200782
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200783 mutex_lock(&apply_lock);
784
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200785 if (dssdev->manager) {
786 DSSERR("display '%s' already has a manager '%s'\n",
787 dssdev->name, dssdev->manager->name);
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200788 r = -EINVAL;
789 goto err;
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200790 }
791
792 if ((mgr->supported_displays & dssdev->type) == 0) {
793 DSSERR("display '%s' does not support manager '%s'\n",
794 dssdev->name, mgr->name);
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200795 r = -EINVAL;
796 goto err;
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200797 }
798
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200799 dssdev->manager = mgr;
800 mgr->device = dssdev;
801 mgr->device_changed = true;
802
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200803 mutex_unlock(&apply_lock);
804
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200805 return 0;
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200806err:
807 mutex_unlock(&apply_lock);
808 return r;
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200809}
810
811int dss_mgr_unset_device(struct omap_overlay_manager *mgr)
812{
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200813 int r;
814
815 mutex_lock(&apply_lock);
816
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200817 if (!mgr->device) {
818 DSSERR("failed to unset display, display not set.\n");
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200819 r = -EINVAL;
820 goto err;
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200821 }
822
823 /*
824 * Don't allow currently enabled displays to have the overlay manager
825 * pulled out from underneath them
826 */
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200827 if (mgr->device->state != OMAP_DSS_DISPLAY_DISABLED) {
828 r = -EINVAL;
829 goto err;
830 }
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200831
832 mgr->device->manager = NULL;
833 mgr->device = NULL;
834 mgr->device_changed = true;
835
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200836 mutex_unlock(&apply_lock);
837
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200838 return 0;
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200839err:
840 mutex_unlock(&apply_lock);
841 return r;
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200842}
843
844
845
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200846int dss_ovl_set_info(struct omap_overlay *ovl,
847 struct omap_overlay_info *info)
848{
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +0200849 struct ovl_priv_data *op = get_ovl_priv(ovl);
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200850 unsigned long flags;
851
852 spin_lock_irqsave(&data_lock, flags);
853
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +0200854 op->user_info = *info;
855 op->user_info_dirty = true;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200856
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200857 spin_unlock_irqrestore(&data_lock, flags);
858
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200859 return 0;
860}
861
862void dss_ovl_get_info(struct omap_overlay *ovl,
863 struct omap_overlay_info *info)
864{
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +0200865 struct ovl_priv_data *op = get_ovl_priv(ovl);
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200866 unsigned long flags;
867
868 spin_lock_irqsave(&data_lock, flags);
869
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +0200870 *info = op->user_info;
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200871
872 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200873}
874
875int dss_ovl_set_manager(struct omap_overlay *ovl,
876 struct omap_overlay_manager *mgr)
877{
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200878 struct ovl_priv_data *op = get_ovl_priv(ovl);
879 unsigned long flags;
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200880 int r;
881
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200882 if (!mgr)
883 return -EINVAL;
884
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200885 mutex_lock(&apply_lock);
886
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200887 if (ovl->manager) {
888 DSSERR("overlay '%s' already has a manager '%s'\n",
889 ovl->name, ovl->manager->name);
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200890 r = -EINVAL;
891 goto err;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200892 }
893
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200894 spin_lock_irqsave(&data_lock, flags);
895
896 if (op->enabled) {
897 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200898 DSSERR("overlay has to be disabled to change the manager\n");
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200899 r = -EINVAL;
900 goto err;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200901 }
902
Tomi Valkeinen5d5a97a2011-11-16 14:17:54 +0200903 op->channel = mgr->id;
904 op->extra_info_dirty = true;
905
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200906 ovl->manager = mgr;
907 list_add_tail(&ovl->list, &mgr->overlays);
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200908
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200909 spin_unlock_irqrestore(&data_lock, flags);
910
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200911 /* XXX: When there is an overlay on a DSI manual update display, and
912 * the overlay is first disabled, then moved to tv, and enabled, we
913 * seem to get SYNC_LOST_DIGIT error.
914 *
915 * Waiting doesn't seem to help, but updating the manual update display
916 * after disabling the overlay seems to fix this. This hints that the
917 * overlay is perhaps somehow tied to the LCD output until the output
918 * is updated.
919 *
920 * Userspace workaround for this is to update the LCD after disabling
921 * the overlay, but before moving the overlay to TV.
922 */
923
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200924 mutex_unlock(&apply_lock);
925
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200926 return 0;
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200927err:
928 mutex_unlock(&apply_lock);
929 return r;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200930}
931
932int dss_ovl_unset_manager(struct omap_overlay *ovl)
933{
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200934 struct ovl_priv_data *op = get_ovl_priv(ovl);
935 unsigned long flags;
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200936 int r;
937
938 mutex_lock(&apply_lock);
939
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200940 if (!ovl->manager) {
941 DSSERR("failed to detach overlay: manager not set\n");
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200942 r = -EINVAL;
943 goto err;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200944 }
945
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200946 spin_lock_irqsave(&data_lock, flags);
947
948 if (op->enabled) {
949 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200950 DSSERR("overlay has to be disabled to unset the manager\n");
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200951 r = -EINVAL;
952 goto err;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200953 }
954
Tomi Valkeinen5d5a97a2011-11-16 14:17:54 +0200955 op->channel = -1;
956
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200957 ovl->manager = NULL;
958 list_del(&ovl->list);
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200959
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200960 spin_unlock_irqrestore(&data_lock, flags);
961
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200962 mutex_unlock(&apply_lock);
963
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200964 return 0;
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200965err:
966 mutex_unlock(&apply_lock);
967 return r;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200968}
969
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200970bool dss_ovl_is_enabled(struct omap_overlay *ovl)
971{
972 struct ovl_priv_data *op = get_ovl_priv(ovl);
973 unsigned long flags;
974 bool e;
975
976 spin_lock_irqsave(&data_lock, flags);
977
978 e = op->enabled;
979
980 spin_unlock_irqrestore(&data_lock, flags);
981
982 return e;
983}
984
985int dss_ovl_enable(struct omap_overlay *ovl)
986{
987 struct ovl_priv_data *op = get_ovl_priv(ovl);
988 unsigned long flags;
989 int r;
990
991 mutex_lock(&apply_lock);
992
993 if (ovl->manager == NULL || ovl->manager->device == NULL) {
994 r = -EINVAL;
995 goto err;
996 }
997
998 spin_lock_irqsave(&data_lock, flags);
999
1000 op->enabled = true;
1001 op->extra_info_dirty = true;
1002
Tomi Valkeinen75c94962011-11-15 18:25:23 +02001003 dss_write_regs();
1004
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001005 spin_unlock_irqrestore(&data_lock, flags);
1006
1007 mutex_unlock(&apply_lock);
1008
1009 return 0;
1010err:
1011 mutex_unlock(&apply_lock);
1012 return r;
1013}
1014
1015int dss_ovl_disable(struct omap_overlay *ovl)
1016{
1017 struct ovl_priv_data *op = get_ovl_priv(ovl);
1018 unsigned long flags;
1019 int r;
1020
1021 mutex_lock(&apply_lock);
1022
1023 if (ovl->manager == NULL || ovl->manager->device == NULL) {
1024 r = -EINVAL;
1025 goto err;
1026 }
1027
1028 spin_lock_irqsave(&data_lock, flags);
1029
1030 op->enabled = false;
1031 op->extra_info_dirty = true;
1032
Tomi Valkeinen75c94962011-11-15 18:25:23 +02001033 dss_write_regs();
1034
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001035 spin_unlock_irqrestore(&data_lock, flags);
1036
1037 mutex_unlock(&apply_lock);
1038
1039 return 0;
1040
1041err:
1042 mutex_unlock(&apply_lock);
1043 return r;
1044}
1045