blob: 931c7776e901c1e503d4ec037e34f06756a9ec7f [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 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
Tomi Valkeinen58f255482011-11-04 09:48:54 +020066 struct omap_overlay_info info;
67
68 enum omap_channel channel;
69
70 u32 fifo_low;
71 u32 fifo_high;
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +020072
73 bool extra_info_dirty;
74 bool shadow_extra_info_dirty;
75
76 bool enabled;
77
Tomi Valkeinen58f255482011-11-04 09:48:54 +020078};
79
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +020080struct mgr_priv_data {
Tomi Valkeinen58f255482011-11-04 09:48:54 +020081 /* If true, cache changed, but not written to shadow registers. Set
82 * in apply(), cleared when registers written. */
83 bool dirty;
84 /* If true, shadow registers contain changed values not yet in real
85 * registers. Set when writing to shadow registers, cleared at
86 * VSYNC/EVSYNC */
87 bool shadow_dirty;
88
89 struct omap_overlay_manager_info info;
90
Tomi Valkeinen43a972d2011-11-15 15:04:25 +020091 /* If true, GO bit is up and shadow registers cannot be written.
92 * Never true for manual update displays */
93 bool busy;
94
Tomi Valkeinenbf213522011-11-15 14:43:53 +020095 /* If true, a display is enabled using this manager */
96 bool enabled;
Tomi Valkeinen58f255482011-11-04 09:48:54 +020097};
98
99static struct {
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200100 struct ovl_priv_data ovl_priv_data_array[MAX_DSS_OVERLAYS];
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200101 struct mgr_priv_data mgr_priv_data_array[MAX_DSS_MANAGERS];
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200102
103 bool irq_enabled;
Tomi Valkeinend09c7aa2011-11-15 12:04:43 +0200104} dss_data;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200105
Tomi Valkeinend09c7aa2011-11-15 12:04:43 +0200106/* protects dss_data */
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200107static spinlock_t data_lock;
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200108/* lock for blocking functions */
109static DEFINE_MUTEX(apply_lock);
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200110
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200111static void dss_register_vsync_isr(void);
112
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200113static struct ovl_priv_data *get_ovl_priv(struct omap_overlay *ovl)
114{
Tomi Valkeinend09c7aa2011-11-15 12:04:43 +0200115 return &dss_data.ovl_priv_data_array[ovl->id];
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200116}
117
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200118static struct mgr_priv_data *get_mgr_priv(struct omap_overlay_manager *mgr)
119{
Tomi Valkeinend09c7aa2011-11-15 12:04:43 +0200120 return &dss_data.mgr_priv_data_array[mgr->id];
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200121}
122
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200123void dss_apply_init(void)
124{
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200125 spin_lock_init(&data_lock);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200126}
127
128static bool ovl_manual_update(struct omap_overlay *ovl)
129{
130 return ovl->manager->device->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE;
131}
132
133static bool mgr_manual_update(struct omap_overlay_manager *mgr)
134{
135 return mgr->device->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE;
136}
137
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200138static bool need_isr(void)
139{
140 const int num_mgrs = dss_feat_get_num_mgrs();
141 int i;
142
143 for (i = 0; i < num_mgrs; ++i) {
144 struct omap_overlay_manager *mgr;
145 struct mgr_priv_data *mp;
146 struct omap_overlay *ovl;
147
148 mgr = omap_dss_get_overlay_manager(i);
149 mp = get_mgr_priv(mgr);
150
151 if (!mp->enabled)
152 continue;
153
154 if (mgr_manual_update(mgr))
155 continue;
156
157 /* to catch GO bit going down */
158 if (mp->busy)
159 return true;
160
161 /* to write new values to registers */
162 if (mp->dirty)
163 return true;
164
165 list_for_each_entry(ovl, &mgr->overlays, list) {
166 struct ovl_priv_data *op;
167
168 op = get_ovl_priv(ovl);
169
170 if (!op->enabled)
171 continue;
172
173 /* to write new values to registers */
174 if (op->dirty || op->extra_info_dirty)
175 return true;
176 }
177 }
178
179 return false;
180}
181
182static bool need_go(struct omap_overlay_manager *mgr)
183{
184 struct omap_overlay *ovl;
185 struct mgr_priv_data *mp;
186 struct ovl_priv_data *op;
187
188 mp = get_mgr_priv(mgr);
189
190 if (mp->shadow_dirty)
191 return true;
192
193 list_for_each_entry(ovl, &mgr->overlays, list) {
194 op = get_ovl_priv(ovl);
195 if (op->shadow_dirty || op->shadow_extra_info_dirty)
196 return true;
197 }
198
199 return false;
200}
201
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200202int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr)
203{
204 unsigned long timeout = msecs_to_jiffies(500);
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200205 struct mgr_priv_data *mp;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200206 u32 irq;
207 int r;
208 int i;
209 struct omap_dss_device *dssdev = mgr->device;
210
211 if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
212 return 0;
213
214 if (mgr_manual_update(mgr))
215 return 0;
216
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200217 irq = dispc_mgr_get_vsync_irq(mgr->id);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200218
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200219 mp = get_mgr_priv(mgr);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200220 i = 0;
221 while (1) {
222 unsigned long flags;
223 bool shadow_dirty, dirty;
224
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200225 spin_lock_irqsave(&data_lock, flags);
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200226 dirty = mp->dirty;
227 shadow_dirty = mp->shadow_dirty;
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200228 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200229
230 if (!dirty && !shadow_dirty) {
231 r = 0;
232 break;
233 }
234
235 /* 4 iterations is the worst case:
236 * 1 - initial iteration, dirty = true (between VFP and VSYNC)
237 * 2 - first VSYNC, dirty = true
238 * 3 - dirty = false, shadow_dirty = true
239 * 4 - shadow_dirty = false */
240 if (i++ == 3) {
241 DSSERR("mgr(%d)->wait_for_go() not finishing\n",
242 mgr->id);
243 r = 0;
244 break;
245 }
246
247 r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
248 if (r == -ERESTARTSYS)
249 break;
250
251 if (r) {
252 DSSERR("mgr(%d)->wait_for_go() timeout\n", mgr->id);
253 break;
254 }
255 }
256
257 return r;
258}
259
260int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl)
261{
262 unsigned long timeout = msecs_to_jiffies(500);
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200263 struct ovl_priv_data *op;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200264 struct omap_dss_device *dssdev;
265 u32 irq;
266 int r;
267 int i;
268
269 if (!ovl->manager)
270 return 0;
271
272 dssdev = ovl->manager->device;
273
274 if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
275 return 0;
276
277 if (ovl_manual_update(ovl))
278 return 0;
279
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200280 irq = dispc_mgr_get_vsync_irq(ovl->manager->id);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200281
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200282 op = get_ovl_priv(ovl);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200283 i = 0;
284 while (1) {
285 unsigned long flags;
286 bool shadow_dirty, dirty;
287
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200288 spin_lock_irqsave(&data_lock, flags);
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200289 dirty = op->dirty;
290 shadow_dirty = op->shadow_dirty;
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200291 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200292
293 if (!dirty && !shadow_dirty) {
294 r = 0;
295 break;
296 }
297
298 /* 4 iterations is the worst case:
299 * 1 - initial iteration, dirty = true (between VFP and VSYNC)
300 * 2 - first VSYNC, dirty = true
301 * 3 - dirty = false, shadow_dirty = true
302 * 4 - shadow_dirty = false */
303 if (i++ == 3) {
304 DSSERR("ovl(%d)->wait_for_go() not finishing\n",
305 ovl->id);
306 r = 0;
307 break;
308 }
309
310 r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
311 if (r == -ERESTARTSYS)
312 break;
313
314 if (r) {
315 DSSERR("ovl(%d)->wait_for_go() timeout\n", ovl->id);
316 break;
317 }
318 }
319
320 return r;
321}
322
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200323static void dss_ovl_write_regs(struct omap_overlay *ovl)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200324{
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200325 struct ovl_priv_data *op = get_ovl_priv(ovl);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200326 struct omap_overlay_info *oi;
327 bool ilace, replication;
328 int r;
329
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200330 DSSDBGF("%d", ovl->id);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200331
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200332 if (!op->enabled || !op->dirty)
333 return;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200334
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200335 oi = &op->info;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200336
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200337 replication = dss_use_replication(ovl->manager->device, oi->color_mode);
338
339 ilace = ovl->manager->device->type == OMAP_DISPLAY_TYPE_VENC;
340
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200341 dispc_ovl_set_channel_out(ovl->id, op->channel);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200342
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200343 r = dispc_ovl_setup(ovl->id, oi, ilace, replication);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200344 if (r) {
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200345 /*
346 * We can't do much here, as this function can be called from
347 * vsync interrupt.
348 */
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200349 DSSERR("dispc_ovl_setup failed for ovl %d\n", ovl->id);
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200350
351 /* This will leave fifo configurations in a nonoptimal state */
352 op->enabled = false;
353 dispc_ovl_enable(ovl->id, false);
354 return;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200355 }
356
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200357 dispc_ovl_set_fifo_threshold(ovl->id, op->fifo_low, op->fifo_high);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200358
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200359 op->dirty = false;
360 op->shadow_dirty = true;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200361}
362
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200363static void dss_ovl_write_regs_extra(struct omap_overlay *ovl)
364{
365 struct ovl_priv_data *op = get_ovl_priv(ovl);
366
367 DSSDBGF("%d", ovl->id);
368
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200369 if (!op->extra_info_dirty)
370 return;
371
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200372 /* note: write also when op->enabled == false, so that the ovl gets
373 * disabled */
374
375 dispc_ovl_enable(ovl->id, op->enabled);
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200376
377 op->extra_info_dirty = false;
378 op->shadow_extra_info_dirty = true;
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200379}
380
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200381static void dss_mgr_write_regs(struct omap_overlay_manager *mgr)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200382{
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200383 struct mgr_priv_data *mp = get_mgr_priv(mgr);
384 struct omap_overlay *ovl;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200385
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200386 DSSDBGF("%d", mgr->id);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200387
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200388 if (!mp->enabled)
389 return;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200390
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200391 WARN_ON(mp->busy);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200392
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200393 /* Commit overlay settings */
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200394 list_for_each_entry(ovl, &mgr->overlays, list) {
395 dss_ovl_write_regs(ovl);
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200396 dss_ovl_write_regs_extra(ovl);
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200397 }
398
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200399 if (mp->dirty) {
400 dispc_mgr_setup(mgr->id, &mp->info);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200401
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200402 mp->dirty = false;
403 mp->shadow_dirty = true;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200404 }
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200405}
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200406
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200407static void dss_write_regs(void)
408{
409 const int num_mgrs = omap_dss_get_num_overlay_managers();
410 int i;
411
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200412 for (i = 0; i < num_mgrs; ++i) {
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200413 struct omap_overlay_manager *mgr;
414 struct mgr_priv_data *mp;
415
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200416 mgr = omap_dss_get_overlay_manager(i);
417 mp = get_mgr_priv(mgr);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200418
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200419 if (!mp->enabled || mgr_manual_update(mgr) || mp->busy)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200420 continue;
421
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200422 dss_mgr_write_regs(mgr);
423
424 if (need_go(mgr)) {
Tomi Valkeinen43a972d2011-11-15 15:04:25 +0200425 mp->busy = true;
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200426
427 if (!dss_data.irq_enabled && need_isr())
428 dss_register_vsync_isr();
429
430 dispc_mgr_go(mgr->id);
Tomi Valkeinen43a972d2011-11-15 15:04:25 +0200431 }
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200432 }
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200433}
434
435void dss_mgr_start_update(struct omap_overlay_manager *mgr)
436{
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200437 struct mgr_priv_data *mp = get_mgr_priv(mgr);
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200438 struct ovl_priv_data *op;
Tomi Valkeinen07e327c2011-11-05 10:59:59 +0200439 struct omap_overlay *ovl;
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200440 unsigned long flags;
441
442 spin_lock_irqsave(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200443
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200444 dss_mgr_write_regs(mgr);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200445
Tomi Valkeinen07e327c2011-11-05 10:59:59 +0200446 list_for_each_entry(ovl, &mgr->overlays, list) {
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200447 op = get_ovl_priv(ovl);
448 op->shadow_dirty = false;
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200449 op->shadow_extra_info_dirty = false;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200450 }
451
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200452 mp->shadow_dirty = false;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200453
Tomi Valkeinen7797c6d2011-11-04 10:22:46 +0200454 dispc_mgr_enable(mgr->id, true);
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200455
456 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200457}
458
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200459static void dss_apply_irq_handler(void *data, u32 mask);
460
461static void dss_register_vsync_isr(void)
462{
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200463 const int num_mgrs = dss_feat_get_num_mgrs();
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200464 u32 mask;
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200465 int r, i;
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200466
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200467 mask = 0;
468 for (i = 0; i < num_mgrs; ++i)
469 mask |= dispc_mgr_get_vsync_irq(i);
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200470
471 r = omap_dispc_register_isr(dss_apply_irq_handler, NULL, mask);
472 WARN_ON(r);
473
Tomi Valkeinend09c7aa2011-11-15 12:04:43 +0200474 dss_data.irq_enabled = true;
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200475}
476
477static void dss_unregister_vsync_isr(void)
478{
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200479 const int num_mgrs = dss_feat_get_num_mgrs();
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200480 u32 mask;
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200481 int r, i;
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200482
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200483 mask = 0;
484 for (i = 0; i < num_mgrs; ++i)
485 mask |= dispc_mgr_get_vsync_irq(i);
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200486
487 r = omap_dispc_unregister_isr(dss_apply_irq_handler, NULL, mask);
488 WARN_ON(r);
489
Tomi Valkeinend09c7aa2011-11-15 12:04:43 +0200490 dss_data.irq_enabled = false;
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200491}
492
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200493static void dss_apply_irq_handler(void *data, u32 mask)
494{
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200495 struct omap_overlay *ovl;
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200496 struct omap_overlay_manager *mgr;
497 struct mgr_priv_data *mp;
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200498 struct ovl_priv_data *op;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200499 const int num_ovls = dss_feat_get_num_ovls();
500 const int num_mgrs = dss_feat_get_num_mgrs();
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200501 int i;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200502
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200503 spin_lock(&data_lock);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200504
Tomi Valkeinen43a972d2011-11-15 15:04:25 +0200505 for (i = 0; i < num_mgrs; i++) {
506 mgr = omap_dss_get_overlay_manager(i);
507 mp = get_mgr_priv(mgr);
508
509 mp->busy = dispc_mgr_go_busy(i);
510 }
511
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200512 for (i = 0; i < num_ovls; ++i) {
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200513 ovl = omap_dss_get_overlay(i);
514 op = get_ovl_priv(ovl);
Tomi Valkeinen43a972d2011-11-15 15:04:25 +0200515
516 if (!op->enabled)
517 continue;
518
519 mp = get_mgr_priv(ovl->manager);
520
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200521 if (!mp->busy) {
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200522 op->shadow_dirty = false;
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200523 op->shadow_extra_info_dirty = false;
524 }
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200525 }
526
527 for (i = 0; i < num_mgrs; ++i) {
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200528 mgr = omap_dss_get_overlay_manager(i);
529 mp = get_mgr_priv(mgr);
Tomi Valkeinen43a972d2011-11-15 15:04:25 +0200530
531 if (!mp->busy)
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200532 mp->shadow_dirty = false;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200533 }
534
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200535 dss_write_regs();
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200536
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200537 if (!need_isr())
538 dss_unregister_vsync_isr();
Tomi Valkeinen43a972d2011-11-15 15:04:25 +0200539
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200540 spin_unlock(&data_lock);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200541}
542
Tomi Valkeinen5738b632011-11-15 13:37:33 +0200543static void omap_dss_mgr_apply_ovl(struct omap_overlay *ovl)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200544{
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200545 struct ovl_priv_data *op;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200546
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200547 op = get_ovl_priv(ovl);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200548
549 if (ovl->manager_changed) {
550 ovl->manager_changed = false;
551 ovl->info_dirty = true;
552 }
553
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200554 if (!ovl->info_dirty)
Tomi Valkeinen5738b632011-11-15 13:37:33 +0200555 return;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200556
557 ovl->info_dirty = false;
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200558 op->dirty = true;
559 op->info = ovl->info;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200560
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200561 op->channel = ovl->manager->id;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200562}
563
564static void omap_dss_mgr_apply_mgr(struct omap_overlay_manager *mgr)
565{
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200566 struct mgr_priv_data *mp;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200567
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200568 mp = get_mgr_priv(mgr);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200569
570 if (mgr->device_changed) {
571 mgr->device_changed = false;
572 mgr->info_dirty = true;
573 }
574
575 if (!mgr->info_dirty)
576 return;
577
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200578 mgr->info_dirty = false;
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200579 mp->dirty = true;
580 mp->info = mgr->info;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200581}
582
583static void omap_dss_mgr_apply_ovl_fifos(struct omap_overlay *ovl)
584{
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200585 struct ovl_priv_data *op;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200586 struct omap_dss_device *dssdev;
587 u32 size, burst_size;
588
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200589 op = get_ovl_priv(ovl);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200590
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200591 dssdev = ovl->manager->device;
592
593 size = dispc_ovl_get_fifo_size(ovl->id);
594
595 burst_size = dispc_ovl_get_burst_size(ovl->id);
596
597 switch (dssdev->type) {
598 case OMAP_DISPLAY_TYPE_DPI:
599 case OMAP_DISPLAY_TYPE_DBI:
600 case OMAP_DISPLAY_TYPE_SDI:
601 case OMAP_DISPLAY_TYPE_VENC:
602 case OMAP_DISPLAY_TYPE_HDMI:
603 default_get_overlay_fifo_thresholds(ovl->id, size,
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200604 burst_size, &op->fifo_low,
605 &op->fifo_high);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200606 break;
607#ifdef CONFIG_OMAP2_DSS_DSI
608 case OMAP_DISPLAY_TYPE_DSI:
609 dsi_get_overlay_fifo_thresholds(ovl->id, size,
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200610 burst_size, &op->fifo_low,
611 &op->fifo_high);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200612 break;
613#endif
614 default:
615 BUG();
616 }
617}
618
619int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
620{
Tomi Valkeinen07e327c2011-11-05 10:59:59 +0200621 int r;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200622 unsigned long flags;
Tomi Valkeinen07e327c2011-11-05 10:59:59 +0200623 struct omap_overlay *ovl;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200624
625 DSSDBG("omap_dss_mgr_apply(%s)\n", mgr->name);
626
627 r = dispc_runtime_get();
628 if (r)
629 return r;
630
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200631 spin_lock_irqsave(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200632
633 /* Configure overlays */
Tomi Valkeinen07e327c2011-11-05 10:59:59 +0200634 list_for_each_entry(ovl, &mgr->overlays, list)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200635 omap_dss_mgr_apply_ovl(ovl);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200636
637 /* Configure manager */
638 omap_dss_mgr_apply_mgr(mgr);
639
640 /* Configure overlay fifos */
Tomi Valkeinen07e327c2011-11-05 10:59:59 +0200641 list_for_each_entry(ovl, &mgr->overlays, list)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200642 omap_dss_mgr_apply_ovl_fifos(ovl);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200643
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200644 dss_write_regs();
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200645
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200646 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200647
648 dispc_runtime_put();
649
650 return r;
651}
652
Tomi Valkeinen7797c6d2011-11-04 10:22:46 +0200653void dss_mgr_enable(struct omap_overlay_manager *mgr)
654{
Tomi Valkeinenbf213522011-11-15 14:43:53 +0200655 struct mgr_priv_data *mp = get_mgr_priv(mgr);
656 unsigned long flags;
657
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200658 mutex_lock(&apply_lock);
659
Tomi Valkeinenbf213522011-11-15 14:43:53 +0200660 spin_lock_irqsave(&data_lock, flags);
661
662 mp->enabled = true;
663
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200664 dss_write_regs();
665
Tomi Valkeinenbf213522011-11-15 14:43:53 +0200666 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200667
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200668 if (!mgr_manual_update(mgr))
669 dispc_mgr_enable(mgr->id, true);
670
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200671 mutex_unlock(&apply_lock);
Tomi Valkeinen7797c6d2011-11-04 10:22:46 +0200672}
673
674void dss_mgr_disable(struct omap_overlay_manager *mgr)
675{
Tomi Valkeinenbf213522011-11-15 14:43:53 +0200676 struct mgr_priv_data *mp = get_mgr_priv(mgr);
677 unsigned long flags;
678
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200679 mutex_lock(&apply_lock);
680
Tomi Valkeinen9a147a62011-11-09 15:30:11 +0200681 if (!mgr_manual_update(mgr))
682 dispc_mgr_enable(mgr->id, false);
Tomi Valkeinenbf213522011-11-15 14:43:53 +0200683
684 spin_lock_irqsave(&data_lock, flags);
685
686 mp->enabled = false;
687
688 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200689
690 mutex_unlock(&apply_lock);
Tomi Valkeinen7797c6d2011-11-04 10:22:46 +0200691}
692
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200693int dss_mgr_set_info(struct omap_overlay_manager *mgr,
694 struct omap_overlay_manager_info *info)
695{
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200696 unsigned long flags;
697
698 spin_lock_irqsave(&data_lock, flags);
699
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200700 mgr->info = *info;
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200701 mgr->info_dirty = true;
702
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200703 spin_unlock_irqrestore(&data_lock, flags);
704
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200705 return 0;
706}
707
708void dss_mgr_get_info(struct omap_overlay_manager *mgr,
709 struct omap_overlay_manager_info *info)
710{
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200711 unsigned long flags;
712
713 spin_lock_irqsave(&data_lock, flags);
714
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200715 *info = mgr->info;
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200716
717 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200718}
719
720int dss_mgr_set_device(struct omap_overlay_manager *mgr,
721 struct omap_dss_device *dssdev)
722{
723 int r;
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200724
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200725 mutex_lock(&apply_lock);
726
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200727 if (dssdev->manager) {
728 DSSERR("display '%s' already has a manager '%s'\n",
729 dssdev->name, dssdev->manager->name);
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200730 r = -EINVAL;
731 goto err;
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200732 }
733
734 if ((mgr->supported_displays & dssdev->type) == 0) {
735 DSSERR("display '%s' does not support manager '%s'\n",
736 dssdev->name, mgr->name);
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200737 r = -EINVAL;
738 goto err;
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200739 }
740
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200741 dssdev->manager = mgr;
742 mgr->device = dssdev;
743 mgr->device_changed = true;
744
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200745 mutex_unlock(&apply_lock);
746
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200747 return 0;
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200748err:
749 mutex_unlock(&apply_lock);
750 return r;
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200751}
752
753int dss_mgr_unset_device(struct omap_overlay_manager *mgr)
754{
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200755 int r;
756
757 mutex_lock(&apply_lock);
758
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200759 if (!mgr->device) {
760 DSSERR("failed to unset display, display not set.\n");
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200761 r = -EINVAL;
762 goto err;
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200763 }
764
765 /*
766 * Don't allow currently enabled displays to have the overlay manager
767 * pulled out from underneath them
768 */
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200769 if (mgr->device->state != OMAP_DSS_DISPLAY_DISABLED) {
770 r = -EINVAL;
771 goto err;
772 }
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200773
774 mgr->device->manager = NULL;
775 mgr->device = NULL;
776 mgr->device_changed = true;
777
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200778 mutex_unlock(&apply_lock);
779
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200780 return 0;
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200781err:
782 mutex_unlock(&apply_lock);
783 return r;
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200784}
785
786
787
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200788int dss_ovl_set_info(struct omap_overlay *ovl,
789 struct omap_overlay_info *info)
790{
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200791 unsigned long flags;
792
793 spin_lock_irqsave(&data_lock, flags);
794
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200795 ovl->info = *info;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200796 ovl->info_dirty = true;
797
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200798 spin_unlock_irqrestore(&data_lock, flags);
799
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200800 return 0;
801}
802
803void dss_ovl_get_info(struct omap_overlay *ovl,
804 struct omap_overlay_info *info)
805{
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200806 unsigned long flags;
807
808 spin_lock_irqsave(&data_lock, flags);
809
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200810 *info = ovl->info;
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200811
812 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200813}
814
815int dss_ovl_set_manager(struct omap_overlay *ovl,
816 struct omap_overlay_manager *mgr)
817{
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200818 struct ovl_priv_data *op = get_ovl_priv(ovl);
819 unsigned long flags;
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200820 int r;
821
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200822 if (!mgr)
823 return -EINVAL;
824
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200825 mutex_lock(&apply_lock);
826
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200827 if (ovl->manager) {
828 DSSERR("overlay '%s' already has a manager '%s'\n",
829 ovl->name, ovl->manager->name);
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200830 r = -EINVAL;
831 goto err;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200832 }
833
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200834 spin_lock_irqsave(&data_lock, flags);
835
836 if (op->enabled) {
837 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200838 DSSERR("overlay has to be disabled to change the manager\n");
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200839 r = -EINVAL;
840 goto err;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200841 }
842
843 ovl->manager = mgr;
844 list_add_tail(&ovl->list, &mgr->overlays);
845 ovl->manager_changed = true;
846
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200847 spin_unlock_irqrestore(&data_lock, flags);
848
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200849 /* XXX: When there is an overlay on a DSI manual update display, and
850 * the overlay is first disabled, then moved to tv, and enabled, we
851 * seem to get SYNC_LOST_DIGIT error.
852 *
853 * Waiting doesn't seem to help, but updating the manual update display
854 * after disabling the overlay seems to fix this. This hints that the
855 * overlay is perhaps somehow tied to the LCD output until the output
856 * is updated.
857 *
858 * Userspace workaround for this is to update the LCD after disabling
859 * the overlay, but before moving the overlay to TV.
860 */
861
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200862 mutex_unlock(&apply_lock);
863
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200864 return 0;
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200865err:
866 mutex_unlock(&apply_lock);
867 return r;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200868}
869
870int dss_ovl_unset_manager(struct omap_overlay *ovl)
871{
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200872 struct ovl_priv_data *op = get_ovl_priv(ovl);
873 unsigned long flags;
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200874 int r;
875
876 mutex_lock(&apply_lock);
877
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200878 if (!ovl->manager) {
879 DSSERR("failed to detach overlay: manager not set\n");
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200880 r = -EINVAL;
881 goto err;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200882 }
883
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200884 spin_lock_irqsave(&data_lock, flags);
885
886 if (op->enabled) {
887 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200888 DSSERR("overlay has to be disabled to unset the manager\n");
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200889 r = -EINVAL;
890 goto err;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200891 }
892
893 ovl->manager = NULL;
894 list_del(&ovl->list);
895 ovl->manager_changed = true;
896
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200897 spin_unlock_irqrestore(&data_lock, flags);
898
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200899 mutex_unlock(&apply_lock);
900
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200901 return 0;
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200902err:
903 mutex_unlock(&apply_lock);
904 return r;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200905}
906
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200907bool dss_ovl_is_enabled(struct omap_overlay *ovl)
908{
909 struct ovl_priv_data *op = get_ovl_priv(ovl);
910 unsigned long flags;
911 bool e;
912
913 spin_lock_irqsave(&data_lock, flags);
914
915 e = op->enabled;
916
917 spin_unlock_irqrestore(&data_lock, flags);
918
919 return e;
920}
921
922int dss_ovl_enable(struct omap_overlay *ovl)
923{
924 struct ovl_priv_data *op = get_ovl_priv(ovl);
925 unsigned long flags;
926 int r;
927
928 mutex_lock(&apply_lock);
929
930 if (ovl->manager == NULL || ovl->manager->device == NULL) {
931 r = -EINVAL;
932 goto err;
933 }
934
935 spin_lock_irqsave(&data_lock, flags);
936
937 op->enabled = true;
938 op->extra_info_dirty = true;
939
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200940 dss_write_regs();
941
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200942 spin_unlock_irqrestore(&data_lock, flags);
943
944 mutex_unlock(&apply_lock);
945
946 return 0;
947err:
948 mutex_unlock(&apply_lock);
949 return r;
950}
951
952int dss_ovl_disable(struct omap_overlay *ovl)
953{
954 struct ovl_priv_data *op = get_ovl_priv(ovl);
955 unsigned long flags;
956 int r;
957
958 mutex_lock(&apply_lock);
959
960 if (ovl->manager == NULL || ovl->manager->device == NULL) {
961 r = -EINVAL;
962 goto err;
963 }
964
965 spin_lock_irqsave(&data_lock, flags);
966
967 op->enabled = false;
968 op->extra_info_dirty = true;
969
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200970 dss_write_regs();
971
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200972 spin_unlock_irqrestore(&data_lock, flags);
973
974 mutex_unlock(&apply_lock);
975
976 return 0;
977
978err:
979 mutex_unlock(&apply_lock);
980 return r;
981}
982