blob: eb28a7f178dd694d1ad9b43ad82fe4abf180bdf2 [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
91 bool manual_update;
92 bool do_manual_update;
Tomi Valkeinenbf213522011-11-15 14:43:53 +020093
Tomi Valkeinen43a972d2011-11-15 15:04:25 +020094 /* If true, GO bit is up and shadow registers cannot be written.
95 * Never true for manual update displays */
96 bool busy;
97
Tomi Valkeinenbf213522011-11-15 14:43:53 +020098 /* If true, a display is enabled using this manager */
99 bool enabled;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200100};
101
102static struct {
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200103 struct ovl_priv_data ovl_priv_data_array[MAX_DSS_OVERLAYS];
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200104 struct mgr_priv_data mgr_priv_data_array[MAX_DSS_MANAGERS];
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200105
106 bool irq_enabled;
Tomi Valkeinend09c7aa2011-11-15 12:04:43 +0200107} dss_data;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200108
Tomi Valkeinend09c7aa2011-11-15 12:04:43 +0200109/* protects dss_data */
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200110static spinlock_t data_lock;
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200111/* lock for blocking functions */
112static DEFINE_MUTEX(apply_lock);
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200113
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200114static struct ovl_priv_data *get_ovl_priv(struct omap_overlay *ovl)
115{
Tomi Valkeinend09c7aa2011-11-15 12:04:43 +0200116 return &dss_data.ovl_priv_data_array[ovl->id];
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200117}
118
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200119static struct mgr_priv_data *get_mgr_priv(struct omap_overlay_manager *mgr)
120{
Tomi Valkeinend09c7aa2011-11-15 12:04:43 +0200121 return &dss_data.mgr_priv_data_array[mgr->id];
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200122}
123
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200124void dss_apply_init(void)
125{
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200126 spin_lock_init(&data_lock);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200127}
128
129static bool ovl_manual_update(struct omap_overlay *ovl)
130{
131 return ovl->manager->device->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE;
132}
133
134static bool mgr_manual_update(struct omap_overlay_manager *mgr)
135{
136 return mgr->device->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE;
137}
138
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200139int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr)
140{
141 unsigned long timeout = msecs_to_jiffies(500);
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200142 struct mgr_priv_data *mp;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200143 u32 irq;
144 int r;
145 int i;
146 struct omap_dss_device *dssdev = mgr->device;
147
148 if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
149 return 0;
150
151 if (mgr_manual_update(mgr))
152 return 0;
153
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200154 irq = dispc_mgr_get_vsync_irq(mgr->id);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200155
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200156 mp = get_mgr_priv(mgr);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200157 i = 0;
158 while (1) {
159 unsigned long flags;
160 bool shadow_dirty, dirty;
161
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200162 spin_lock_irqsave(&data_lock, flags);
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200163 dirty = mp->dirty;
164 shadow_dirty = mp->shadow_dirty;
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200165 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200166
167 if (!dirty && !shadow_dirty) {
168 r = 0;
169 break;
170 }
171
172 /* 4 iterations is the worst case:
173 * 1 - initial iteration, dirty = true (between VFP and VSYNC)
174 * 2 - first VSYNC, dirty = true
175 * 3 - dirty = false, shadow_dirty = true
176 * 4 - shadow_dirty = false */
177 if (i++ == 3) {
178 DSSERR("mgr(%d)->wait_for_go() not finishing\n",
179 mgr->id);
180 r = 0;
181 break;
182 }
183
184 r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
185 if (r == -ERESTARTSYS)
186 break;
187
188 if (r) {
189 DSSERR("mgr(%d)->wait_for_go() timeout\n", mgr->id);
190 break;
191 }
192 }
193
194 return r;
195}
196
197int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl)
198{
199 unsigned long timeout = msecs_to_jiffies(500);
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200200 struct ovl_priv_data *op;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200201 struct omap_dss_device *dssdev;
202 u32 irq;
203 int r;
204 int i;
205
206 if (!ovl->manager)
207 return 0;
208
209 dssdev = ovl->manager->device;
210
211 if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
212 return 0;
213
214 if (ovl_manual_update(ovl))
215 return 0;
216
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200217 irq = dispc_mgr_get_vsync_irq(ovl->manager->id);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200218
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200219 op = get_ovl_priv(ovl);
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 Valkeinenc10c6f02011-11-15 11:56:57 +0200226 dirty = op->dirty;
227 shadow_dirty = op->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("ovl(%d)->wait_for_go() not finishing\n",
242 ovl->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("ovl(%d)->wait_for_go() timeout\n", ovl->id);
253 break;
254 }
255 }
256
257 return r;
258}
259
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200260static int dss_ovl_write_regs(struct omap_overlay *ovl)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200261{
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200262 struct ovl_priv_data *op;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200263 struct omap_overlay_info *oi;
264 bool ilace, replication;
265 int r;
266
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200267 DSSDBGF("%d", ovl->id);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200268
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200269 op = get_ovl_priv(ovl);
270 oi = &op->info;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200271
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200272 if (!op->enabled)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200273 return 0;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200274
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200275 replication = dss_use_replication(ovl->manager->device, oi->color_mode);
276
277 ilace = ovl->manager->device->type == OMAP_DISPLAY_TYPE_VENC;
278
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200279 dispc_ovl_set_channel_out(ovl->id, op->channel);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200280
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200281 r = dispc_ovl_setup(ovl->id, oi, ilace, replication);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200282 if (r) {
283 /* this shouldn't happen */
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200284 DSSERR("dispc_ovl_setup failed for ovl %d\n", ovl->id);
285 dispc_ovl_enable(ovl->id, 0);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200286 return r;
287 }
288
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200289 dispc_ovl_set_fifo_threshold(ovl->id, op->fifo_low, op->fifo_high);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200290
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200291 return 0;
292}
293
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200294static void dss_ovl_write_regs_extra(struct omap_overlay *ovl)
295{
296 struct ovl_priv_data *op = get_ovl_priv(ovl);
297
298 DSSDBGF("%d", ovl->id);
299
300 /* note: write also when op->enabled == false, so that the ovl gets
301 * disabled */
302
303 dispc_ovl_enable(ovl->id, op->enabled);
304}
305
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200306static void dss_mgr_write_regs(struct omap_overlay_manager *mgr)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200307{
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200308 struct mgr_priv_data *mp;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200309 struct omap_overlay_manager_info *mi;
310
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200311 DSSDBGF("%d", mgr->id);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200312
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200313 mp = get_mgr_priv(mgr);
314 mi = &mp->info;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200315
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200316 dispc_mgr_setup(mgr->id, mi);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200317}
318
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200319/* dss_write_regs() tries to write values from cache to shadow registers.
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200320 * It writes only to those managers/overlays that are not busy.
321 * returns 0 if everything could be written to shadow registers.
322 * returns 1 if not everything could be written to shadow registers. */
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200323static int dss_write_regs(void)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200324{
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200325 struct omap_overlay *ovl;
326 struct omap_overlay_manager *mgr;
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200327 struct ovl_priv_data *op;
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200328 struct mgr_priv_data *mp;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200329 const int num_ovls = dss_feat_get_num_ovls();
330 const int num_mgrs = dss_feat_get_num_mgrs();
331 int i;
332 int r;
Tomi Valkeinen43a972d2011-11-15 15:04:25 +0200333 bool mgr_go[MAX_DSS_MANAGERS] = { false };
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200334 bool busy;
335
336 r = 0;
337 busy = false;
338
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200339 /* Commit overlay settings */
340 for (i = 0; i < num_ovls; ++i) {
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200341 ovl = omap_dss_get_overlay(i);
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200342 op = get_ovl_priv(ovl);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200343
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200344 if (!op->dirty)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200345 continue;
346
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200347 mp = get_mgr_priv(ovl->manager);
348
349 if (mp->manual_update && !mp->do_manual_update)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200350 continue;
351
Tomi Valkeinen43a972d2011-11-15 15:04:25 +0200352 if (mp->busy) {
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200353 busy = true;
354 continue;
355 }
356
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200357 r = dss_ovl_write_regs(ovl);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200358 if (r)
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200359 DSSERR("dss_ovl_write_regs %d failed\n", i);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200360
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200361 op->dirty = false;
362 op->shadow_dirty = true;
363 mgr_go[op->channel] = true;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200364 }
365
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200366 for (i = 0; i < num_ovls; ++i) {
367 ovl = omap_dss_get_overlay(i);
368 op = get_ovl_priv(ovl);
369
370 if (!op->extra_info_dirty)
371 continue;
372
373 mp = get_mgr_priv(ovl->manager);
374
375 if (mp->manual_update && !mp->do_manual_update)
376 continue;
377
378 if (mp->busy) {
379 busy = true;
380 continue;
381 }
382
383 dss_ovl_write_regs_extra(ovl);
384
385 op->extra_info_dirty = false;
386 op->shadow_extra_info_dirty = true;
387 mgr_go[op->channel] = true;
388 }
389
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200390 /* Commit manager settings */
391 for (i = 0; i < num_mgrs; ++i) {
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200392 mgr = omap_dss_get_overlay_manager(i);
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200393 mp = get_mgr_priv(mgr);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200394
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200395 if (!mp->dirty)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200396 continue;
397
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200398 if (mp->manual_update && !mp->do_manual_update)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200399 continue;
400
Tomi Valkeinen43a972d2011-11-15 15:04:25 +0200401 if (mp->busy) {
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200402 busy = true;
403 continue;
404 }
405
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200406 dss_mgr_write_regs(mgr);
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200407 mp->dirty = false;
408 mp->shadow_dirty = true;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200409 mgr_go[i] = true;
410 }
411
412 /* set GO */
413 for (i = 0; i < num_mgrs; ++i) {
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200414 mgr = omap_dss_get_overlay_manager(i);
415 mp = get_mgr_priv(mgr);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200416
417 if (!mgr_go[i])
418 continue;
419
420 /* We don't need GO with manual update display. LCD iface will
421 * always be turned off after frame, and new settings will be
422 * taken in to use at next update */
Tomi Valkeinen43a972d2011-11-15 15:04:25 +0200423 if (!mp->manual_update) {
424 mp->busy = true;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200425 dispc_mgr_go(i);
Tomi Valkeinen43a972d2011-11-15 15:04:25 +0200426 }
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200427 }
428
429 if (busy)
430 r = 1;
431 else
432 r = 0;
433
434 return r;
435}
436
437void dss_mgr_start_update(struct omap_overlay_manager *mgr)
438{
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200439 struct mgr_priv_data *mp = get_mgr_priv(mgr);
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200440 struct ovl_priv_data *op;
Tomi Valkeinen07e327c2011-11-05 10:59:59 +0200441 struct omap_overlay *ovl;
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200442 unsigned long flags;
443
444 spin_lock_irqsave(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200445
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200446 mp->do_manual_update = true;
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200447 dss_write_regs();
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200448 mp->do_manual_update = false;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200449
Tomi Valkeinen07e327c2011-11-05 10:59:59 +0200450 list_for_each_entry(ovl, &mgr->overlays, list) {
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200451 op = get_ovl_priv(ovl);
452 op->shadow_dirty = false;
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200453 op->shadow_extra_info_dirty = false;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200454 }
455
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200456 mp->shadow_dirty = false;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200457
Tomi Valkeinen7797c6d2011-11-04 10:22:46 +0200458 dispc_mgr_enable(mgr->id, true);
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200459
460 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200461}
462
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200463static void dss_apply_irq_handler(void *data, u32 mask);
464
465static void dss_register_vsync_isr(void)
466{
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200467 const int num_mgrs = dss_feat_get_num_mgrs();
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200468 u32 mask;
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200469 int r, i;
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200470
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200471 mask = 0;
472 for (i = 0; i < num_mgrs; ++i)
473 mask |= dispc_mgr_get_vsync_irq(i);
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200474
475 r = omap_dispc_register_isr(dss_apply_irq_handler, NULL, mask);
476 WARN_ON(r);
477
Tomi Valkeinend09c7aa2011-11-15 12:04:43 +0200478 dss_data.irq_enabled = true;
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200479}
480
481static void dss_unregister_vsync_isr(void)
482{
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200483 const int num_mgrs = dss_feat_get_num_mgrs();
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200484 u32 mask;
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200485 int r, i;
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200486
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200487 mask = 0;
488 for (i = 0; i < num_mgrs; ++i)
489 mask |= dispc_mgr_get_vsync_irq(i);
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200490
491 r = omap_dispc_unregister_isr(dss_apply_irq_handler, NULL, mask);
492 WARN_ON(r);
493
Tomi Valkeinend09c7aa2011-11-15 12:04:43 +0200494 dss_data.irq_enabled = false;
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200495}
496
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200497static void dss_apply_irq_handler(void *data, u32 mask)
498{
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200499 struct omap_overlay *ovl;
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200500 struct omap_overlay_manager *mgr;
501 struct mgr_priv_data *mp;
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200502 struct ovl_priv_data *op;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200503 const int num_ovls = dss_feat_get_num_ovls();
504 const int num_mgrs = dss_feat_get_num_mgrs();
505 int i, r;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200506
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200507 spin_lock(&data_lock);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200508
Tomi Valkeinen43a972d2011-11-15 15:04:25 +0200509 for (i = 0; i < num_mgrs; i++) {
510 mgr = omap_dss_get_overlay_manager(i);
511 mp = get_mgr_priv(mgr);
512
513 mp->busy = dispc_mgr_go_busy(i);
514 }
515
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200516 for (i = 0; i < num_ovls; ++i) {
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200517 ovl = omap_dss_get_overlay(i);
518 op = get_ovl_priv(ovl);
Tomi Valkeinen43a972d2011-11-15 15:04:25 +0200519
520 if (!op->enabled)
521 continue;
522
523 mp = get_mgr_priv(ovl->manager);
524
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200525 if (!mp->busy) {
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200526 op->shadow_dirty = false;
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200527 op->shadow_extra_info_dirty = false;
528 }
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200529 }
530
531 for (i = 0; i < num_mgrs; ++i) {
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200532 mgr = omap_dss_get_overlay_manager(i);
533 mp = get_mgr_priv(mgr);
Tomi Valkeinen43a972d2011-11-15 15:04:25 +0200534
535 if (!mp->busy)
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200536 mp->shadow_dirty = false;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200537 }
538
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200539 r = dss_write_regs();
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200540 if (r == 1)
541 goto end;
542
543 /* re-read busy flags */
Tomi Valkeinen43a972d2011-11-15 15:04:25 +0200544 for (i = 0; i < num_mgrs; i++) {
545 mgr = omap_dss_get_overlay_manager(i);
546 mp = get_mgr_priv(mgr);
547
548 mp->busy = dispc_mgr_go_busy(i);
549 }
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200550
551 /* keep running as long as there are busy managers, so that
552 * we can collect overlay-applied information */
553 for (i = 0; i < num_mgrs; ++i) {
Tomi Valkeinen43a972d2011-11-15 15:04:25 +0200554 mgr = omap_dss_get_overlay_manager(i);
555 mp = get_mgr_priv(mgr);
556
557 if (mp->busy)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200558 goto end;
559 }
560
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200561 dss_unregister_vsync_isr();
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200562
563end:
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200564 spin_unlock(&data_lock);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200565}
566
Tomi Valkeinen5738b632011-11-15 13:37:33 +0200567static void omap_dss_mgr_apply_ovl(struct omap_overlay *ovl)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200568{
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200569 struct ovl_priv_data *op;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200570
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200571 op = get_ovl_priv(ovl);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200572
573 if (ovl->manager_changed) {
574 ovl->manager_changed = false;
575 ovl->info_dirty = true;
576 }
577
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200578 if (!ovl->info_dirty)
Tomi Valkeinen5738b632011-11-15 13:37:33 +0200579 return;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200580
581 ovl->info_dirty = false;
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200582 op->dirty = true;
583 op->info = ovl->info;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200584
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200585 op->channel = ovl->manager->id;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200586}
587
588static void omap_dss_mgr_apply_mgr(struct omap_overlay_manager *mgr)
589{
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200590 struct mgr_priv_data *mp;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200591
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200592 mp = get_mgr_priv(mgr);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200593
594 if (mgr->device_changed) {
595 mgr->device_changed = false;
596 mgr->info_dirty = true;
597 }
598
599 if (!mgr->info_dirty)
600 return;
601
602 if (!mgr->device)
603 return;
604
605 mgr->info_dirty = false;
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200606 mp->dirty = true;
607 mp->info = mgr->info;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200608
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200609 mp->manual_update = mgr_manual_update(mgr);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200610}
611
612static void omap_dss_mgr_apply_ovl_fifos(struct omap_overlay *ovl)
613{
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200614 struct ovl_priv_data *op;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200615 struct omap_dss_device *dssdev;
616 u32 size, burst_size;
617
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200618 op = get_ovl_priv(ovl);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200619
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200620 dssdev = ovl->manager->device;
621
622 size = dispc_ovl_get_fifo_size(ovl->id);
623
624 burst_size = dispc_ovl_get_burst_size(ovl->id);
625
626 switch (dssdev->type) {
627 case OMAP_DISPLAY_TYPE_DPI:
628 case OMAP_DISPLAY_TYPE_DBI:
629 case OMAP_DISPLAY_TYPE_SDI:
630 case OMAP_DISPLAY_TYPE_VENC:
631 case OMAP_DISPLAY_TYPE_HDMI:
632 default_get_overlay_fifo_thresholds(ovl->id, size,
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200633 burst_size, &op->fifo_low,
634 &op->fifo_high);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200635 break;
636#ifdef CONFIG_OMAP2_DSS_DSI
637 case OMAP_DISPLAY_TYPE_DSI:
638 dsi_get_overlay_fifo_thresholds(ovl->id, size,
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200639 burst_size, &op->fifo_low,
640 &op->fifo_high);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200641 break;
642#endif
643 default:
644 BUG();
645 }
646}
647
648int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
649{
Tomi Valkeinen07e327c2011-11-05 10:59:59 +0200650 int r;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200651 unsigned long flags;
Tomi Valkeinen07e327c2011-11-05 10:59:59 +0200652 struct omap_overlay *ovl;
Tomi Valkeinenbf213522011-11-15 14:43:53 +0200653 struct mgr_priv_data *mp = get_mgr_priv(mgr);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200654
655 DSSDBG("omap_dss_mgr_apply(%s)\n", mgr->name);
656
657 r = dispc_runtime_get();
658 if (r)
659 return r;
660
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200661 spin_lock_irqsave(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200662
663 /* Configure overlays */
Tomi Valkeinen07e327c2011-11-05 10:59:59 +0200664 list_for_each_entry(ovl, &mgr->overlays, list)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200665 omap_dss_mgr_apply_ovl(ovl);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200666
667 /* Configure manager */
668 omap_dss_mgr_apply_mgr(mgr);
669
670 /* Configure overlay fifos */
Tomi Valkeinen07e327c2011-11-05 10:59:59 +0200671 list_for_each_entry(ovl, &mgr->overlays, list)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200672 omap_dss_mgr_apply_ovl_fifos(ovl);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200673
674 r = 0;
Tomi Valkeinenbf213522011-11-15 14:43:53 +0200675 if (mp->enabled && !mgr_manual_update(mgr)) {
Tomi Valkeinend09c7aa2011-11-15 12:04:43 +0200676 if (!dss_data.irq_enabled)
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200677 dss_register_vsync_isr();
Tomi Valkeinen18135ea2011-11-04 09:35:59 +0200678
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200679 dss_write_regs();
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200680 }
681
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200682 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200683
684 dispc_runtime_put();
685
686 return r;
687}
688
Tomi Valkeinen7797c6d2011-11-04 10:22:46 +0200689void dss_mgr_enable(struct omap_overlay_manager *mgr)
690{
Tomi Valkeinenbf213522011-11-15 14:43:53 +0200691 struct mgr_priv_data *mp = get_mgr_priv(mgr);
692 unsigned long flags;
693
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200694 mutex_lock(&apply_lock);
695
Tomi Valkeinen9a147a62011-11-09 15:30:11 +0200696 if (!mgr_manual_update(mgr))
697 dispc_mgr_enable(mgr->id, true);
Tomi Valkeinenbf213522011-11-15 14:43:53 +0200698
699 spin_lock_irqsave(&data_lock, flags);
700
701 mp->enabled = true;
702
703 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200704
705 mutex_unlock(&apply_lock);
Tomi Valkeinen7797c6d2011-11-04 10:22:46 +0200706}
707
708void dss_mgr_disable(struct omap_overlay_manager *mgr)
709{
Tomi Valkeinenbf213522011-11-15 14:43:53 +0200710 struct mgr_priv_data *mp = get_mgr_priv(mgr);
711 unsigned long flags;
712
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200713 mutex_lock(&apply_lock);
714
Tomi Valkeinen9a147a62011-11-09 15:30:11 +0200715 if (!mgr_manual_update(mgr))
716 dispc_mgr_enable(mgr->id, false);
Tomi Valkeinenbf213522011-11-15 14:43:53 +0200717
718 spin_lock_irqsave(&data_lock, flags);
719
720 mp->enabled = false;
721
722 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200723
724 mutex_unlock(&apply_lock);
Tomi Valkeinen7797c6d2011-11-04 10:22:46 +0200725}
726
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200727int dss_mgr_set_info(struct omap_overlay_manager *mgr,
728 struct omap_overlay_manager_info *info)
729{
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200730 unsigned long flags;
731
732 spin_lock_irqsave(&data_lock, flags);
733
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200734 mgr->info = *info;
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200735 mgr->info_dirty = true;
736
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200737 spin_unlock_irqrestore(&data_lock, flags);
738
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200739 return 0;
740}
741
742void dss_mgr_get_info(struct omap_overlay_manager *mgr,
743 struct omap_overlay_manager_info *info)
744{
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200745 unsigned long flags;
746
747 spin_lock_irqsave(&data_lock, flags);
748
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200749 *info = mgr->info;
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200750
751 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200752}
753
754int dss_mgr_set_device(struct omap_overlay_manager *mgr,
755 struct omap_dss_device *dssdev)
756{
757 int r;
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200758
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200759 mutex_lock(&apply_lock);
760
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200761 if (dssdev->manager) {
762 DSSERR("display '%s' already has a manager '%s'\n",
763 dssdev->name, dssdev->manager->name);
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200764 r = -EINVAL;
765 goto err;
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200766 }
767
768 if ((mgr->supported_displays & dssdev->type) == 0) {
769 DSSERR("display '%s' does not support manager '%s'\n",
770 dssdev->name, mgr->name);
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200771 r = -EINVAL;
772 goto err;
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200773 }
774
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200775 dssdev->manager = mgr;
776 mgr->device = dssdev;
777 mgr->device_changed = true;
778
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200779 mutex_unlock(&apply_lock);
780
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200781 return 0;
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200782err:
783 mutex_unlock(&apply_lock);
784 return r;
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200785}
786
787int dss_mgr_unset_device(struct omap_overlay_manager *mgr)
788{
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200789 int r;
790
791 mutex_lock(&apply_lock);
792
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200793 if (!mgr->device) {
794 DSSERR("failed to unset display, display not set.\n");
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200795 r = -EINVAL;
796 goto err;
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200797 }
798
799 /*
800 * Don't allow currently enabled displays to have the overlay manager
801 * pulled out from underneath them
802 */
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200803 if (mgr->device->state != OMAP_DSS_DISPLAY_DISABLED) {
804 r = -EINVAL;
805 goto err;
806 }
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200807
808 mgr->device->manager = NULL;
809 mgr->device = NULL;
810 mgr->device_changed = true;
811
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200812 mutex_unlock(&apply_lock);
813
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200814 return 0;
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200815err:
816 mutex_unlock(&apply_lock);
817 return r;
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200818}
819
820
821
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200822int dss_ovl_set_info(struct omap_overlay *ovl,
823 struct omap_overlay_info *info)
824{
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200825 unsigned long flags;
826
827 spin_lock_irqsave(&data_lock, flags);
828
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200829 ovl->info = *info;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200830 ovl->info_dirty = true;
831
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200832 spin_unlock_irqrestore(&data_lock, flags);
833
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200834 return 0;
835}
836
837void dss_ovl_get_info(struct omap_overlay *ovl,
838 struct omap_overlay_info *info)
839{
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200840 unsigned long flags;
841
842 spin_lock_irqsave(&data_lock, flags);
843
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200844 *info = ovl->info;
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200845
846 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200847}
848
849int dss_ovl_set_manager(struct omap_overlay *ovl,
850 struct omap_overlay_manager *mgr)
851{
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200852 struct ovl_priv_data *op = get_ovl_priv(ovl);
853 unsigned long flags;
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200854 int r;
855
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200856 if (!mgr)
857 return -EINVAL;
858
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200859 mutex_lock(&apply_lock);
860
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200861 if (ovl->manager) {
862 DSSERR("overlay '%s' already has a manager '%s'\n",
863 ovl->name, ovl->manager->name);
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200864 r = -EINVAL;
865 goto err;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200866 }
867
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200868 spin_lock_irqsave(&data_lock, flags);
869
870 if (op->enabled) {
871 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200872 DSSERR("overlay has to be disabled to change the manager\n");
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200873 r = -EINVAL;
874 goto err;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200875 }
876
877 ovl->manager = mgr;
878 list_add_tail(&ovl->list, &mgr->overlays);
879 ovl->manager_changed = true;
880
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200881 spin_unlock_irqrestore(&data_lock, flags);
882
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200883 /* XXX: When there is an overlay on a DSI manual update display, and
884 * the overlay is first disabled, then moved to tv, and enabled, we
885 * seem to get SYNC_LOST_DIGIT error.
886 *
887 * Waiting doesn't seem to help, but updating the manual update display
888 * after disabling the overlay seems to fix this. This hints that the
889 * overlay is perhaps somehow tied to the LCD output until the output
890 * is updated.
891 *
892 * Userspace workaround for this is to update the LCD after disabling
893 * the overlay, but before moving the overlay to TV.
894 */
895
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200896 mutex_unlock(&apply_lock);
897
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200898 return 0;
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200899err:
900 mutex_unlock(&apply_lock);
901 return r;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200902}
903
904int dss_ovl_unset_manager(struct omap_overlay *ovl)
905{
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200906 struct ovl_priv_data *op = get_ovl_priv(ovl);
907 unsigned long flags;
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200908 int r;
909
910 mutex_lock(&apply_lock);
911
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200912 if (!ovl->manager) {
913 DSSERR("failed to detach overlay: manager not set\n");
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200914 r = -EINVAL;
915 goto err;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200916 }
917
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200918 spin_lock_irqsave(&data_lock, flags);
919
920 if (op->enabled) {
921 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200922 DSSERR("overlay has to be disabled to unset the manager\n");
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200923 r = -EINVAL;
924 goto err;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200925 }
926
927 ovl->manager = NULL;
928 list_del(&ovl->list);
929 ovl->manager_changed = true;
930
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200931 spin_unlock_irqrestore(&data_lock, flags);
932
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200933 mutex_unlock(&apply_lock);
934
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200935 return 0;
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200936err:
937 mutex_unlock(&apply_lock);
938 return r;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200939}
940
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200941bool dss_ovl_is_enabled(struct omap_overlay *ovl)
942{
943 struct ovl_priv_data *op = get_ovl_priv(ovl);
944 unsigned long flags;
945 bool e;
946
947 spin_lock_irqsave(&data_lock, flags);
948
949 e = op->enabled;
950
951 spin_unlock_irqrestore(&data_lock, flags);
952
953 return e;
954}
955
956int dss_ovl_enable(struct omap_overlay *ovl)
957{
958 struct ovl_priv_data *op = get_ovl_priv(ovl);
959 unsigned long flags;
960 int r;
961
962 mutex_lock(&apply_lock);
963
964 if (ovl->manager == NULL || ovl->manager->device == NULL) {
965 r = -EINVAL;
966 goto err;
967 }
968
969 spin_lock_irqsave(&data_lock, flags);
970
971 op->enabled = true;
972 op->extra_info_dirty = true;
973
974 spin_unlock_irqrestore(&data_lock, flags);
975
976 mutex_unlock(&apply_lock);
977
978 return 0;
979err:
980 mutex_unlock(&apply_lock);
981 return r;
982}
983
984int dss_ovl_disable(struct omap_overlay *ovl)
985{
986 struct ovl_priv_data *op = get_ovl_priv(ovl);
987 unsigned long flags;
988 int r;
989
990 mutex_lock(&apply_lock);
991
992 if (ovl->manager == NULL || ovl->manager->device == NULL) {
993 r = -EINVAL;
994 goto err;
995 }
996
997 spin_lock_irqsave(&data_lock, flags);
998
999 op->enabled = false;
1000 op->extra_info_dirty = true;
1001
1002 spin_unlock_irqrestore(&data_lock, flags);
1003
1004 mutex_unlock(&apply_lock);
1005
1006 return 0;
1007
1008err:
1009 mutex_unlock(&apply_lock);
1010 return r;
1011}
1012