blob: 3bb5149b3a2824bde834ac56df97e187d2c05b3c [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 Valkeinen34861372011-11-18 15:43:29 +020095 /* If true, dispc output is enabled */
96 bool updating;
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 Valkeinen75c94962011-11-15 18:25:23 +0200114static void dss_register_vsync_isr(void);
115
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200116static struct ovl_priv_data *get_ovl_priv(struct omap_overlay *ovl)
117{
Tomi Valkeinend09c7aa2011-11-15 12:04:43 +0200118 return &dss_data.ovl_priv_data_array[ovl->id];
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200119}
120
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200121static struct mgr_priv_data *get_mgr_priv(struct omap_overlay_manager *mgr)
122{
Tomi Valkeinend09c7aa2011-11-15 12:04:43 +0200123 return &dss_data.mgr_priv_data_array[mgr->id];
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200124}
125
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200126void dss_apply_init(void)
127{
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200128 spin_lock_init(&data_lock);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200129}
130
131static bool ovl_manual_update(struct omap_overlay *ovl)
132{
133 return ovl->manager->device->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE;
134}
135
136static bool mgr_manual_update(struct omap_overlay_manager *mgr)
137{
138 return mgr->device->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE;
139}
140
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200141static bool need_isr(void)
142{
143 const int num_mgrs = dss_feat_get_num_mgrs();
144 int i;
145
146 for (i = 0; i < num_mgrs; ++i) {
147 struct omap_overlay_manager *mgr;
148 struct mgr_priv_data *mp;
149 struct omap_overlay *ovl;
150
151 mgr = omap_dss_get_overlay_manager(i);
152 mp = get_mgr_priv(mgr);
153
154 if (!mp->enabled)
155 continue;
156
Tomi Valkeinen34861372011-11-18 15:43:29 +0200157 if (mgr_manual_update(mgr)) {
158 /* to catch FRAMEDONE */
159 if (mp->updating)
160 return true;
161 } else {
162 /* to catch GO bit going down */
163 if (mp->busy)
164 return true;
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200165
166 /* to write new values to registers */
Tomi Valkeinen34861372011-11-18 15:43:29 +0200167 if (mp->dirty)
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200168 return true;
Tomi Valkeinen34861372011-11-18 15:43:29 +0200169
170 list_for_each_entry(ovl, &mgr->overlays, list) {
171 struct ovl_priv_data *op;
172
173 op = get_ovl_priv(ovl);
174
175 if (!op->enabled)
176 continue;
177
178 /* to write new values to registers */
179 if (op->dirty || op->extra_info_dirty)
180 return true;
181 }
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200182 }
183 }
184
185 return false;
186}
187
188static bool need_go(struct omap_overlay_manager *mgr)
189{
190 struct omap_overlay *ovl;
191 struct mgr_priv_data *mp;
192 struct ovl_priv_data *op;
193
194 mp = get_mgr_priv(mgr);
195
196 if (mp->shadow_dirty)
197 return true;
198
199 list_for_each_entry(ovl, &mgr->overlays, list) {
200 op = get_ovl_priv(ovl);
201 if (op->shadow_dirty || op->shadow_extra_info_dirty)
202 return true;
203 }
204
205 return false;
206}
207
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200208int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr)
209{
210 unsigned long timeout = msecs_to_jiffies(500);
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200211 struct mgr_priv_data *mp;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200212 u32 irq;
213 int r;
214 int i;
215 struct omap_dss_device *dssdev = mgr->device;
216
217 if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
218 return 0;
219
220 if (mgr_manual_update(mgr))
221 return 0;
222
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200223 irq = dispc_mgr_get_vsync_irq(mgr->id);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200224
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200225 mp = get_mgr_priv(mgr);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200226 i = 0;
227 while (1) {
228 unsigned long flags;
229 bool shadow_dirty, dirty;
230
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200231 spin_lock_irqsave(&data_lock, flags);
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200232 dirty = mp->dirty;
233 shadow_dirty = mp->shadow_dirty;
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200234 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200235
236 if (!dirty && !shadow_dirty) {
237 r = 0;
238 break;
239 }
240
241 /* 4 iterations is the worst case:
242 * 1 - initial iteration, dirty = true (between VFP and VSYNC)
243 * 2 - first VSYNC, dirty = true
244 * 3 - dirty = false, shadow_dirty = true
245 * 4 - shadow_dirty = false */
246 if (i++ == 3) {
247 DSSERR("mgr(%d)->wait_for_go() not finishing\n",
248 mgr->id);
249 r = 0;
250 break;
251 }
252
253 r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
254 if (r == -ERESTARTSYS)
255 break;
256
257 if (r) {
258 DSSERR("mgr(%d)->wait_for_go() timeout\n", mgr->id);
259 break;
260 }
261 }
262
263 return r;
264}
265
266int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl)
267{
268 unsigned long timeout = msecs_to_jiffies(500);
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200269 struct ovl_priv_data *op;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200270 struct omap_dss_device *dssdev;
271 u32 irq;
272 int r;
273 int i;
274
275 if (!ovl->manager)
276 return 0;
277
278 dssdev = ovl->manager->device;
279
280 if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
281 return 0;
282
283 if (ovl_manual_update(ovl))
284 return 0;
285
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200286 irq = dispc_mgr_get_vsync_irq(ovl->manager->id);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200287
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200288 op = get_ovl_priv(ovl);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200289 i = 0;
290 while (1) {
291 unsigned long flags;
292 bool shadow_dirty, dirty;
293
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200294 spin_lock_irqsave(&data_lock, flags);
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200295 dirty = op->dirty;
296 shadow_dirty = op->shadow_dirty;
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200297 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200298
299 if (!dirty && !shadow_dirty) {
300 r = 0;
301 break;
302 }
303
304 /* 4 iterations is the worst case:
305 * 1 - initial iteration, dirty = true (between VFP and VSYNC)
306 * 2 - first VSYNC, dirty = true
307 * 3 - dirty = false, shadow_dirty = true
308 * 4 - shadow_dirty = false */
309 if (i++ == 3) {
310 DSSERR("ovl(%d)->wait_for_go() not finishing\n",
311 ovl->id);
312 r = 0;
313 break;
314 }
315
316 r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
317 if (r == -ERESTARTSYS)
318 break;
319
320 if (r) {
321 DSSERR("ovl(%d)->wait_for_go() timeout\n", ovl->id);
322 break;
323 }
324 }
325
326 return r;
327}
328
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200329static void dss_ovl_write_regs(struct omap_overlay *ovl)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200330{
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200331 struct ovl_priv_data *op = get_ovl_priv(ovl);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200332 struct omap_overlay_info *oi;
333 bool ilace, replication;
Tomi Valkeinen34861372011-11-18 15:43:29 +0200334 struct mgr_priv_data *mp;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200335 int r;
336
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200337 DSSDBGF("%d", ovl->id);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200338
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200339 if (!op->enabled || !op->dirty)
340 return;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200341
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200342 oi = &op->info;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200343
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200344 replication = dss_use_replication(ovl->manager->device, oi->color_mode);
345
346 ilace = ovl->manager->device->type == OMAP_DISPLAY_TYPE_VENC;
347
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200348 dispc_ovl_set_channel_out(ovl->id, op->channel);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200349
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200350 r = dispc_ovl_setup(ovl->id, oi, ilace, replication);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200351 if (r) {
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200352 /*
353 * We can't do much here, as this function can be called from
354 * vsync interrupt.
355 */
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200356 DSSERR("dispc_ovl_setup failed for ovl %d\n", ovl->id);
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200357
358 /* This will leave fifo configurations in a nonoptimal state */
359 op->enabled = false;
360 dispc_ovl_enable(ovl->id, false);
361 return;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200362 }
363
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200364 dispc_ovl_set_fifo_threshold(ovl->id, op->fifo_low, op->fifo_high);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200365
Tomi Valkeinen34861372011-11-18 15:43:29 +0200366 mp = get_mgr_priv(ovl->manager);
367
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200368 op->dirty = false;
Tomi Valkeinen34861372011-11-18 15:43:29 +0200369 if (mp->updating)
370 op->shadow_dirty = true;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200371}
372
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200373static void dss_ovl_write_regs_extra(struct omap_overlay *ovl)
374{
375 struct ovl_priv_data *op = get_ovl_priv(ovl);
Tomi Valkeinen34861372011-11-18 15:43:29 +0200376 struct mgr_priv_data *mp;
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200377
378 DSSDBGF("%d", ovl->id);
379
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200380 if (!op->extra_info_dirty)
381 return;
382
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200383 /* note: write also when op->enabled == false, so that the ovl gets
384 * disabled */
385
386 dispc_ovl_enable(ovl->id, op->enabled);
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200387
Tomi Valkeinen34861372011-11-18 15:43:29 +0200388 mp = get_mgr_priv(ovl->manager);
389
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200390 op->extra_info_dirty = false;
Tomi Valkeinen34861372011-11-18 15:43:29 +0200391 if (mp->updating)
392 op->shadow_extra_info_dirty = true;
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200393}
394
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200395static void dss_mgr_write_regs(struct omap_overlay_manager *mgr)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200396{
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200397 struct mgr_priv_data *mp = get_mgr_priv(mgr);
398 struct omap_overlay *ovl;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200399
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200400 DSSDBGF("%d", mgr->id);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200401
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200402 if (!mp->enabled)
403 return;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200404
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200405 WARN_ON(mp->busy);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200406
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200407 /* Commit overlay settings */
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200408 list_for_each_entry(ovl, &mgr->overlays, list) {
409 dss_ovl_write_regs(ovl);
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200410 dss_ovl_write_regs_extra(ovl);
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200411 }
412
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200413 if (mp->dirty) {
414 dispc_mgr_setup(mgr->id, &mp->info);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200415
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200416 mp->dirty = false;
Tomi Valkeinen34861372011-11-18 15:43:29 +0200417 if (mp->updating)
418 mp->shadow_dirty = true;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200419 }
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200420}
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200421
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200422static void dss_write_regs(void)
423{
424 const int num_mgrs = omap_dss_get_num_overlay_managers();
425 int i;
426
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200427 for (i = 0; i < num_mgrs; ++i) {
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200428 struct omap_overlay_manager *mgr;
429 struct mgr_priv_data *mp;
430
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200431 mgr = omap_dss_get_overlay_manager(i);
432 mp = get_mgr_priv(mgr);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200433
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200434 if (!mp->enabled || mgr_manual_update(mgr) || mp->busy)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200435 continue;
436
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200437 dss_mgr_write_regs(mgr);
438
439 if (need_go(mgr)) {
Tomi Valkeinen43a972d2011-11-15 15:04:25 +0200440 mp->busy = true;
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200441
442 if (!dss_data.irq_enabled && need_isr())
443 dss_register_vsync_isr();
444
445 dispc_mgr_go(mgr->id);
Tomi Valkeinen43a972d2011-11-15 15:04:25 +0200446 }
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200447 }
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200448}
449
450void dss_mgr_start_update(struct omap_overlay_manager *mgr)
451{
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200452 struct mgr_priv_data *mp = get_mgr_priv(mgr);
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200453 unsigned long flags;
454
455 spin_lock_irqsave(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200456
Tomi Valkeinen34861372011-11-18 15:43:29 +0200457 WARN_ON(mp->updating);
458
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200459 dss_mgr_write_regs(mgr);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200460
Tomi Valkeinen34861372011-11-18 15:43:29 +0200461 mp->updating = true;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200462
Tomi Valkeinen34861372011-11-18 15:43:29 +0200463 if (!dss_data.irq_enabled && need_isr())
464 dss_register_vsync_isr();
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200465
Tomi Valkeinen7797c6d2011-11-04 10:22:46 +0200466 dispc_mgr_enable(mgr->id, true);
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200467
468 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200469}
470
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200471static void dss_apply_irq_handler(void *data, u32 mask);
472
473static void dss_register_vsync_isr(void)
474{
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200475 const int num_mgrs = dss_feat_get_num_mgrs();
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200476 u32 mask;
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200477 int r, i;
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200478
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200479 mask = 0;
480 for (i = 0; i < num_mgrs; ++i)
481 mask |= dispc_mgr_get_vsync_irq(i);
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200482
Tomi Valkeinen34861372011-11-18 15:43:29 +0200483 for (i = 0; i < num_mgrs; ++i)
484 mask |= dispc_mgr_get_framedone_irq(i);
485
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200486 r = omap_dispc_register_isr(dss_apply_irq_handler, NULL, mask);
487 WARN_ON(r);
488
Tomi Valkeinend09c7aa2011-11-15 12:04:43 +0200489 dss_data.irq_enabled = true;
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200490}
491
492static void dss_unregister_vsync_isr(void)
493{
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200494 const int num_mgrs = dss_feat_get_num_mgrs();
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200495 u32 mask;
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200496 int r, i;
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200497
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200498 mask = 0;
499 for (i = 0; i < num_mgrs; ++i)
500 mask |= dispc_mgr_get_vsync_irq(i);
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200501
Tomi Valkeinen34861372011-11-18 15:43:29 +0200502 for (i = 0; i < num_mgrs; ++i)
503 mask |= dispc_mgr_get_framedone_irq(i);
504
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200505 r = omap_dispc_unregister_isr(dss_apply_irq_handler, NULL, mask);
506 WARN_ON(r);
507
Tomi Valkeinend09c7aa2011-11-15 12:04:43 +0200508 dss_data.irq_enabled = false;
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200509}
510
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200511static void dss_apply_irq_handler(void *data, u32 mask)
512{
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200513 struct omap_overlay *ovl;
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200514 struct omap_overlay_manager *mgr;
515 struct mgr_priv_data *mp;
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200516 struct ovl_priv_data *op;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200517 const int num_ovls = dss_feat_get_num_ovls();
518 const int num_mgrs = dss_feat_get_num_mgrs();
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200519 int i;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200520
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200521 spin_lock(&data_lock);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200522
Tomi Valkeinen43a972d2011-11-15 15:04:25 +0200523 for (i = 0; i < num_mgrs; i++) {
524 mgr = omap_dss_get_overlay_manager(i);
525 mp = get_mgr_priv(mgr);
526
527 mp->busy = dispc_mgr_go_busy(i);
Tomi Valkeinen34861372011-11-18 15:43:29 +0200528 mp->updating = dispc_mgr_is_enabled(i);
Tomi Valkeinen43a972d2011-11-15 15:04:25 +0200529 }
530
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200531 for (i = 0; i < num_ovls; ++i) {
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200532 ovl = omap_dss_get_overlay(i);
533 op = get_ovl_priv(ovl);
Tomi Valkeinen43a972d2011-11-15 15:04:25 +0200534
535 if (!op->enabled)
536 continue;
537
538 mp = get_mgr_priv(ovl->manager);
539
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200540 if (!mp->busy) {
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200541 op->shadow_dirty = false;
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200542 op->shadow_extra_info_dirty = false;
543 }
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200544 }
545
546 for (i = 0; i < num_mgrs; ++i) {
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200547 mgr = omap_dss_get_overlay_manager(i);
548 mp = get_mgr_priv(mgr);
Tomi Valkeinen43a972d2011-11-15 15:04:25 +0200549
550 if (!mp->busy)
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200551 mp->shadow_dirty = false;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200552 }
553
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200554 dss_write_regs();
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200555
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200556 if (!need_isr())
557 dss_unregister_vsync_isr();
Tomi Valkeinen43a972d2011-11-15 15:04:25 +0200558
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200559 spin_unlock(&data_lock);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200560}
561
Tomi Valkeinen5738b632011-11-15 13:37:33 +0200562static void omap_dss_mgr_apply_ovl(struct omap_overlay *ovl)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200563{
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200564 struct ovl_priv_data *op;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200565
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200566 op = get_ovl_priv(ovl);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200567
568 if (ovl->manager_changed) {
569 ovl->manager_changed = false;
570 ovl->info_dirty = true;
571 }
572
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200573 if (!ovl->info_dirty)
Tomi Valkeinen5738b632011-11-15 13:37:33 +0200574 return;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200575
576 ovl->info_dirty = false;
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200577 op->dirty = true;
578 op->info = ovl->info;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200579
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200580 op->channel = ovl->manager->id;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200581}
582
583static void omap_dss_mgr_apply_mgr(struct omap_overlay_manager *mgr)
584{
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200585 struct mgr_priv_data *mp;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200586
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200587 mp = get_mgr_priv(mgr);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200588
589 if (mgr->device_changed) {
590 mgr->device_changed = false;
591 mgr->info_dirty = true;
592 }
593
594 if (!mgr->info_dirty)
595 return;
596
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200597 mgr->info_dirty = false;
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200598 mp->dirty = true;
599 mp->info = mgr->info;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200600}
601
602static void omap_dss_mgr_apply_ovl_fifos(struct omap_overlay *ovl)
603{
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200604 struct ovl_priv_data *op;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200605 struct omap_dss_device *dssdev;
606 u32 size, burst_size;
607
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200608 op = get_ovl_priv(ovl);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200609
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200610 dssdev = ovl->manager->device;
611
612 size = dispc_ovl_get_fifo_size(ovl->id);
613
614 burst_size = dispc_ovl_get_burst_size(ovl->id);
615
616 switch (dssdev->type) {
617 case OMAP_DISPLAY_TYPE_DPI:
618 case OMAP_DISPLAY_TYPE_DBI:
619 case OMAP_DISPLAY_TYPE_SDI:
620 case OMAP_DISPLAY_TYPE_VENC:
621 case OMAP_DISPLAY_TYPE_HDMI:
622 default_get_overlay_fifo_thresholds(ovl->id, size,
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200623 burst_size, &op->fifo_low,
624 &op->fifo_high);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200625 break;
626#ifdef CONFIG_OMAP2_DSS_DSI
627 case OMAP_DISPLAY_TYPE_DSI:
628 dsi_get_overlay_fifo_thresholds(ovl->id, size,
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200629 burst_size, &op->fifo_low,
630 &op->fifo_high);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200631 break;
632#endif
633 default:
634 BUG();
635 }
636}
637
638int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
639{
Tomi Valkeinen07e327c2011-11-05 10:59:59 +0200640 int r;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200641 unsigned long flags;
Tomi Valkeinen07e327c2011-11-05 10:59:59 +0200642 struct omap_overlay *ovl;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200643
644 DSSDBG("omap_dss_mgr_apply(%s)\n", mgr->name);
645
646 r = dispc_runtime_get();
647 if (r)
648 return r;
649
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200650 spin_lock_irqsave(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200651
652 /* Configure overlays */
Tomi Valkeinen07e327c2011-11-05 10:59:59 +0200653 list_for_each_entry(ovl, &mgr->overlays, list)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200654 omap_dss_mgr_apply_ovl(ovl);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200655
656 /* Configure manager */
657 omap_dss_mgr_apply_mgr(mgr);
658
659 /* Configure overlay fifos */
Tomi Valkeinen07e327c2011-11-05 10:59:59 +0200660 list_for_each_entry(ovl, &mgr->overlays, list)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200661 omap_dss_mgr_apply_ovl_fifos(ovl);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200662
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200663 dss_write_regs();
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200664
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200665 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200666
667 dispc_runtime_put();
668
669 return r;
670}
671
Tomi Valkeinen7797c6d2011-11-04 10:22:46 +0200672void dss_mgr_enable(struct omap_overlay_manager *mgr)
673{
Tomi Valkeinenbf213522011-11-15 14:43:53 +0200674 struct mgr_priv_data *mp = get_mgr_priv(mgr);
675 unsigned long flags;
676
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200677 mutex_lock(&apply_lock);
678
Tomi Valkeinenbf213522011-11-15 14:43:53 +0200679 spin_lock_irqsave(&data_lock, flags);
680
681 mp->enabled = true;
682
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200683 dss_write_regs();
684
Tomi Valkeinen34861372011-11-18 15:43:29 +0200685 if (!mgr_manual_update(mgr))
686 mp->updating = true;
687
Tomi Valkeinenbf213522011-11-15 14:43:53 +0200688 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200689
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200690 if (!mgr_manual_update(mgr))
691 dispc_mgr_enable(mgr->id, true);
692
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200693 mutex_unlock(&apply_lock);
Tomi Valkeinen7797c6d2011-11-04 10:22:46 +0200694}
695
696void dss_mgr_disable(struct omap_overlay_manager *mgr)
697{
Tomi Valkeinenbf213522011-11-15 14:43:53 +0200698 struct mgr_priv_data *mp = get_mgr_priv(mgr);
699 unsigned long flags;
700
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200701 mutex_lock(&apply_lock);
702
Tomi Valkeinen9a147a62011-11-09 15:30:11 +0200703 if (!mgr_manual_update(mgr))
704 dispc_mgr_enable(mgr->id, false);
Tomi Valkeinenbf213522011-11-15 14:43:53 +0200705
706 spin_lock_irqsave(&data_lock, flags);
707
Tomi Valkeinen34861372011-11-18 15:43:29 +0200708 mp->updating = false;
Tomi Valkeinenbf213522011-11-15 14:43:53 +0200709 mp->enabled = false;
710
711 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200712
713 mutex_unlock(&apply_lock);
Tomi Valkeinen7797c6d2011-11-04 10:22:46 +0200714}
715
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200716int dss_mgr_set_info(struct omap_overlay_manager *mgr,
717 struct omap_overlay_manager_info *info)
718{
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200719 unsigned long flags;
720
721 spin_lock_irqsave(&data_lock, flags);
722
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200723 mgr->info = *info;
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200724 mgr->info_dirty = true;
725
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200726 spin_unlock_irqrestore(&data_lock, flags);
727
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200728 return 0;
729}
730
731void dss_mgr_get_info(struct omap_overlay_manager *mgr,
732 struct omap_overlay_manager_info *info)
733{
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200734 unsigned long flags;
735
736 spin_lock_irqsave(&data_lock, flags);
737
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200738 *info = mgr->info;
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200739
740 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200741}
742
743int dss_mgr_set_device(struct omap_overlay_manager *mgr,
744 struct omap_dss_device *dssdev)
745{
746 int r;
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200747
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200748 mutex_lock(&apply_lock);
749
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200750 if (dssdev->manager) {
751 DSSERR("display '%s' already has a manager '%s'\n",
752 dssdev->name, dssdev->manager->name);
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200753 r = -EINVAL;
754 goto err;
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200755 }
756
757 if ((mgr->supported_displays & dssdev->type) == 0) {
758 DSSERR("display '%s' does not support manager '%s'\n",
759 dssdev->name, mgr->name);
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200760 r = -EINVAL;
761 goto err;
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200762 }
763
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200764 dssdev->manager = mgr;
765 mgr->device = dssdev;
766 mgr->device_changed = true;
767
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200768 mutex_unlock(&apply_lock);
769
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200770 return 0;
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200771err:
772 mutex_unlock(&apply_lock);
773 return r;
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200774}
775
776int dss_mgr_unset_device(struct omap_overlay_manager *mgr)
777{
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200778 int r;
779
780 mutex_lock(&apply_lock);
781
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200782 if (!mgr->device) {
783 DSSERR("failed to unset display, display not set.\n");
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200784 r = -EINVAL;
785 goto err;
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200786 }
787
788 /*
789 * Don't allow currently enabled displays to have the overlay manager
790 * pulled out from underneath them
791 */
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200792 if (mgr->device->state != OMAP_DSS_DISPLAY_DISABLED) {
793 r = -EINVAL;
794 goto err;
795 }
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200796
797 mgr->device->manager = NULL;
798 mgr->device = NULL;
799 mgr->device_changed = true;
800
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200801 mutex_unlock(&apply_lock);
802
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200803 return 0;
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200804err:
805 mutex_unlock(&apply_lock);
806 return r;
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200807}
808
809
810
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200811int dss_ovl_set_info(struct omap_overlay *ovl,
812 struct omap_overlay_info *info)
813{
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200814 unsigned long flags;
815
816 spin_lock_irqsave(&data_lock, flags);
817
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200818 ovl->info = *info;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200819 ovl->info_dirty = true;
820
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200821 spin_unlock_irqrestore(&data_lock, flags);
822
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200823 return 0;
824}
825
826void dss_ovl_get_info(struct omap_overlay *ovl,
827 struct omap_overlay_info *info)
828{
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200829 unsigned long flags;
830
831 spin_lock_irqsave(&data_lock, flags);
832
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200833 *info = ovl->info;
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200834
835 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200836}
837
838int dss_ovl_set_manager(struct omap_overlay *ovl,
839 struct omap_overlay_manager *mgr)
840{
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200841 struct ovl_priv_data *op = get_ovl_priv(ovl);
842 unsigned long flags;
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200843 int r;
844
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200845 if (!mgr)
846 return -EINVAL;
847
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200848 mutex_lock(&apply_lock);
849
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200850 if (ovl->manager) {
851 DSSERR("overlay '%s' already has a manager '%s'\n",
852 ovl->name, ovl->manager->name);
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200853 r = -EINVAL;
854 goto err;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200855 }
856
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200857 spin_lock_irqsave(&data_lock, flags);
858
859 if (op->enabled) {
860 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200861 DSSERR("overlay has to be disabled to change the manager\n");
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200862 r = -EINVAL;
863 goto err;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200864 }
865
866 ovl->manager = mgr;
867 list_add_tail(&ovl->list, &mgr->overlays);
868 ovl->manager_changed = true;
869
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200870 spin_unlock_irqrestore(&data_lock, flags);
871
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200872 /* XXX: When there is an overlay on a DSI manual update display, and
873 * the overlay is first disabled, then moved to tv, and enabled, we
874 * seem to get SYNC_LOST_DIGIT error.
875 *
876 * Waiting doesn't seem to help, but updating the manual update display
877 * after disabling the overlay seems to fix this. This hints that the
878 * overlay is perhaps somehow tied to the LCD output until the output
879 * is updated.
880 *
881 * Userspace workaround for this is to update the LCD after disabling
882 * the overlay, but before moving the overlay to TV.
883 */
884
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200885 mutex_unlock(&apply_lock);
886
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200887 return 0;
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200888err:
889 mutex_unlock(&apply_lock);
890 return r;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200891}
892
893int dss_ovl_unset_manager(struct omap_overlay *ovl)
894{
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200895 struct ovl_priv_data *op = get_ovl_priv(ovl);
896 unsigned long flags;
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200897 int r;
898
899 mutex_lock(&apply_lock);
900
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200901 if (!ovl->manager) {
902 DSSERR("failed to detach overlay: manager not set\n");
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200903 r = -EINVAL;
904 goto err;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200905 }
906
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200907 spin_lock_irqsave(&data_lock, flags);
908
909 if (op->enabled) {
910 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200911 DSSERR("overlay has to be disabled to unset the manager\n");
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200912 r = -EINVAL;
913 goto err;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200914 }
915
916 ovl->manager = NULL;
917 list_del(&ovl->list);
918 ovl->manager_changed = true;
919
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200920 spin_unlock_irqrestore(&data_lock, flags);
921
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200922 mutex_unlock(&apply_lock);
923
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200924 return 0;
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200925err:
926 mutex_unlock(&apply_lock);
927 return r;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200928}
929
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200930bool dss_ovl_is_enabled(struct omap_overlay *ovl)
931{
932 struct ovl_priv_data *op = get_ovl_priv(ovl);
933 unsigned long flags;
934 bool e;
935
936 spin_lock_irqsave(&data_lock, flags);
937
938 e = op->enabled;
939
940 spin_unlock_irqrestore(&data_lock, flags);
941
942 return e;
943}
944
945int dss_ovl_enable(struct omap_overlay *ovl)
946{
947 struct ovl_priv_data *op = get_ovl_priv(ovl);
948 unsigned long flags;
949 int r;
950
951 mutex_lock(&apply_lock);
952
953 if (ovl->manager == NULL || ovl->manager->device == NULL) {
954 r = -EINVAL;
955 goto err;
956 }
957
958 spin_lock_irqsave(&data_lock, flags);
959
960 op->enabled = true;
961 op->extra_info_dirty = true;
962
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200963 dss_write_regs();
964
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200965 spin_unlock_irqrestore(&data_lock, flags);
966
967 mutex_unlock(&apply_lock);
968
969 return 0;
970err:
971 mutex_unlock(&apply_lock);
972 return r;
973}
974
975int dss_ovl_disable(struct omap_overlay *ovl)
976{
977 struct ovl_priv_data *op = get_ovl_priv(ovl);
978 unsigned long flags;
979 int r;
980
981 mutex_lock(&apply_lock);
982
983 if (ovl->manager == NULL || ovl->manager->device == NULL) {
984 r = -EINVAL;
985 goto err;
986 }
987
988 spin_lock_irqsave(&data_lock, flags);
989
990 op->enabled = false;
991 op->extra_info_dirty = true;
992
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200993 dss_write_regs();
994
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200995 spin_unlock_irqrestore(&data_lock, flags);
996
997 mutex_unlock(&apply_lock);
998
999 return 0;
1000
1001err:
1002 mutex_unlock(&apply_lock);
1003 return r;
1004}
1005