blob: 62319b8328da7f91de4ac30f830764cd46c901c4 [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 Valkeinen388c4c62011-11-16 13:58:07 +020081
82 bool user_info_dirty;
83 struct omap_overlay_manager_info user_info;
84
Tomi Valkeinen58f255482011-11-04 09:48:54 +020085 /* If true, cache changed, but not written to shadow registers. Set
86 * in apply(), cleared when registers written. */
87 bool dirty;
88 /* If true, shadow registers contain changed values not yet in real
89 * registers. Set when writing to shadow registers, cleared at
90 * VSYNC/EVSYNC */
91 bool shadow_dirty;
92
93 struct omap_overlay_manager_info info;
94
Tomi Valkeinen43a972d2011-11-15 15:04:25 +020095 /* If true, GO bit is up and shadow registers cannot be written.
96 * Never true for manual update displays */
97 bool busy;
98
Tomi Valkeinen34861372011-11-18 15:43:29 +020099 /* If true, dispc output is enabled */
100 bool updating;
101
Tomi Valkeinenbf213522011-11-15 14:43:53 +0200102 /* If true, a display is enabled using this manager */
103 bool enabled;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200104};
105
106static struct {
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200107 struct ovl_priv_data ovl_priv_data_array[MAX_DSS_OVERLAYS];
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200108 struct mgr_priv_data mgr_priv_data_array[MAX_DSS_MANAGERS];
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200109
110 bool irq_enabled;
Tomi Valkeinend09c7aa2011-11-15 12:04:43 +0200111} dss_data;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200112
Tomi Valkeinend09c7aa2011-11-15 12:04:43 +0200113/* protects dss_data */
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200114static spinlock_t data_lock;
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200115/* lock for blocking functions */
116static DEFINE_MUTEX(apply_lock);
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200117
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200118static void dss_register_vsync_isr(void);
119
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200120static struct ovl_priv_data *get_ovl_priv(struct omap_overlay *ovl)
121{
Tomi Valkeinend09c7aa2011-11-15 12:04:43 +0200122 return &dss_data.ovl_priv_data_array[ovl->id];
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200123}
124
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200125static struct mgr_priv_data *get_mgr_priv(struct omap_overlay_manager *mgr)
126{
Tomi Valkeinend09c7aa2011-11-15 12:04:43 +0200127 return &dss_data.mgr_priv_data_array[mgr->id];
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200128}
129
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200130void dss_apply_init(void)
131{
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200132 spin_lock_init(&data_lock);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200133}
134
135static bool ovl_manual_update(struct omap_overlay *ovl)
136{
137 return ovl->manager->device->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE;
138}
139
140static bool mgr_manual_update(struct omap_overlay_manager *mgr)
141{
142 return mgr->device->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE;
143}
144
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200145static bool need_isr(void)
146{
147 const int num_mgrs = dss_feat_get_num_mgrs();
148 int i;
149
150 for (i = 0; i < num_mgrs; ++i) {
151 struct omap_overlay_manager *mgr;
152 struct mgr_priv_data *mp;
153 struct omap_overlay *ovl;
154
155 mgr = omap_dss_get_overlay_manager(i);
156 mp = get_mgr_priv(mgr);
157
158 if (!mp->enabled)
159 continue;
160
Tomi Valkeinen34861372011-11-18 15:43:29 +0200161 if (mgr_manual_update(mgr)) {
162 /* to catch FRAMEDONE */
163 if (mp->updating)
164 return true;
165 } else {
166 /* to catch GO bit going down */
167 if (mp->busy)
168 return true;
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200169
170 /* to write new values to registers */
Tomi Valkeinen34861372011-11-18 15:43:29 +0200171 if (mp->dirty)
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200172 return true;
Tomi Valkeinen34861372011-11-18 15:43:29 +0200173
174 list_for_each_entry(ovl, &mgr->overlays, list) {
175 struct ovl_priv_data *op;
176
177 op = get_ovl_priv(ovl);
178
179 if (!op->enabled)
180 continue;
181
182 /* to write new values to registers */
183 if (op->dirty || op->extra_info_dirty)
184 return true;
185 }
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200186 }
187 }
188
189 return false;
190}
191
192static bool need_go(struct omap_overlay_manager *mgr)
193{
194 struct omap_overlay *ovl;
195 struct mgr_priv_data *mp;
196 struct ovl_priv_data *op;
197
198 mp = get_mgr_priv(mgr);
199
200 if (mp->shadow_dirty)
201 return true;
202
203 list_for_each_entry(ovl, &mgr->overlays, list) {
204 op = get_ovl_priv(ovl);
205 if (op->shadow_dirty || op->shadow_extra_info_dirty)
206 return true;
207 }
208
209 return false;
210}
211
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200212int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr)
213{
214 unsigned long timeout = msecs_to_jiffies(500);
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200215 struct mgr_priv_data *mp;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200216 u32 irq;
217 int r;
218 int i;
219 struct omap_dss_device *dssdev = mgr->device;
220
221 if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
222 return 0;
223
224 if (mgr_manual_update(mgr))
225 return 0;
226
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200227 irq = dispc_mgr_get_vsync_irq(mgr->id);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200228
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200229 mp = get_mgr_priv(mgr);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200230 i = 0;
231 while (1) {
232 unsigned long flags;
233 bool shadow_dirty, dirty;
234
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200235 spin_lock_irqsave(&data_lock, flags);
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200236 dirty = mp->dirty;
237 shadow_dirty = mp->shadow_dirty;
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200238 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200239
240 if (!dirty && !shadow_dirty) {
241 r = 0;
242 break;
243 }
244
245 /* 4 iterations is the worst case:
246 * 1 - initial iteration, dirty = true (between VFP and VSYNC)
247 * 2 - first VSYNC, dirty = true
248 * 3 - dirty = false, shadow_dirty = true
249 * 4 - shadow_dirty = false */
250 if (i++ == 3) {
251 DSSERR("mgr(%d)->wait_for_go() not finishing\n",
252 mgr->id);
253 r = 0;
254 break;
255 }
256
257 r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
258 if (r == -ERESTARTSYS)
259 break;
260
261 if (r) {
262 DSSERR("mgr(%d)->wait_for_go() timeout\n", mgr->id);
263 break;
264 }
265 }
266
267 return r;
268}
269
270int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl)
271{
272 unsigned long timeout = msecs_to_jiffies(500);
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200273 struct ovl_priv_data *op;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200274 struct omap_dss_device *dssdev;
275 u32 irq;
276 int r;
277 int i;
278
279 if (!ovl->manager)
280 return 0;
281
282 dssdev = ovl->manager->device;
283
284 if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
285 return 0;
286
287 if (ovl_manual_update(ovl))
288 return 0;
289
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200290 irq = dispc_mgr_get_vsync_irq(ovl->manager->id);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200291
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200292 op = get_ovl_priv(ovl);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200293 i = 0;
294 while (1) {
295 unsigned long flags;
296 bool shadow_dirty, dirty;
297
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200298 spin_lock_irqsave(&data_lock, flags);
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200299 dirty = op->dirty;
300 shadow_dirty = op->shadow_dirty;
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200301 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200302
303 if (!dirty && !shadow_dirty) {
304 r = 0;
305 break;
306 }
307
308 /* 4 iterations is the worst case:
309 * 1 - initial iteration, dirty = true (between VFP and VSYNC)
310 * 2 - first VSYNC, dirty = true
311 * 3 - dirty = false, shadow_dirty = true
312 * 4 - shadow_dirty = false */
313 if (i++ == 3) {
314 DSSERR("ovl(%d)->wait_for_go() not finishing\n",
315 ovl->id);
316 r = 0;
317 break;
318 }
319
320 r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
321 if (r == -ERESTARTSYS)
322 break;
323
324 if (r) {
325 DSSERR("ovl(%d)->wait_for_go() timeout\n", ovl->id);
326 break;
327 }
328 }
329
330 return r;
331}
332
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200333static void dss_ovl_write_regs(struct omap_overlay *ovl)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200334{
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200335 struct ovl_priv_data *op = get_ovl_priv(ovl);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200336 struct omap_overlay_info *oi;
337 bool ilace, replication;
Tomi Valkeinen34861372011-11-18 15:43:29 +0200338 struct mgr_priv_data *mp;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200339 int r;
340
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200341 DSSDBGF("%d", ovl->id);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200342
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200343 if (!op->enabled || !op->dirty)
344 return;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200345
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200346 oi = &op->info;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200347
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200348 replication = dss_use_replication(ovl->manager->device, oi->color_mode);
349
350 ilace = ovl->manager->device->type == OMAP_DISPLAY_TYPE_VENC;
351
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200352 dispc_ovl_set_channel_out(ovl->id, op->channel);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200353
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200354 r = dispc_ovl_setup(ovl->id, oi, ilace, replication);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200355 if (r) {
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200356 /*
357 * We can't do much here, as this function can be called from
358 * vsync interrupt.
359 */
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200360 DSSERR("dispc_ovl_setup failed for ovl %d\n", ovl->id);
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200361
362 /* This will leave fifo configurations in a nonoptimal state */
363 op->enabled = false;
364 dispc_ovl_enable(ovl->id, false);
365 return;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200366 }
367
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200368 dispc_ovl_set_fifo_threshold(ovl->id, op->fifo_low, op->fifo_high);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200369
Tomi Valkeinen34861372011-11-18 15:43:29 +0200370 mp = get_mgr_priv(ovl->manager);
371
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200372 op->dirty = false;
Tomi Valkeinen34861372011-11-18 15:43:29 +0200373 if (mp->updating)
374 op->shadow_dirty = true;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200375}
376
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200377static void dss_ovl_write_regs_extra(struct omap_overlay *ovl)
378{
379 struct ovl_priv_data *op = get_ovl_priv(ovl);
Tomi Valkeinen34861372011-11-18 15:43:29 +0200380 struct mgr_priv_data *mp;
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200381
382 DSSDBGF("%d", ovl->id);
383
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200384 if (!op->extra_info_dirty)
385 return;
386
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200387 /* note: write also when op->enabled == false, so that the ovl gets
388 * disabled */
389
390 dispc_ovl_enable(ovl->id, op->enabled);
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200391
Tomi Valkeinen34861372011-11-18 15:43:29 +0200392 mp = get_mgr_priv(ovl->manager);
393
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200394 op->extra_info_dirty = false;
Tomi Valkeinen34861372011-11-18 15:43:29 +0200395 if (mp->updating)
396 op->shadow_extra_info_dirty = true;
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200397}
398
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200399static void dss_mgr_write_regs(struct omap_overlay_manager *mgr)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200400{
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200401 struct mgr_priv_data *mp = get_mgr_priv(mgr);
402 struct omap_overlay *ovl;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200403
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200404 DSSDBGF("%d", mgr->id);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200405
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200406 if (!mp->enabled)
407 return;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200408
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200409 WARN_ON(mp->busy);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200410
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200411 /* Commit overlay settings */
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200412 list_for_each_entry(ovl, &mgr->overlays, list) {
413 dss_ovl_write_regs(ovl);
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200414 dss_ovl_write_regs_extra(ovl);
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200415 }
416
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200417 if (mp->dirty) {
418 dispc_mgr_setup(mgr->id, &mp->info);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200419
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200420 mp->dirty = false;
Tomi Valkeinen34861372011-11-18 15:43:29 +0200421 if (mp->updating)
422 mp->shadow_dirty = true;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200423 }
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200424}
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200425
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200426static void dss_write_regs(void)
427{
428 const int num_mgrs = omap_dss_get_num_overlay_managers();
429 int i;
430
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200431 for (i = 0; i < num_mgrs; ++i) {
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200432 struct omap_overlay_manager *mgr;
433 struct mgr_priv_data *mp;
434
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200435 mgr = omap_dss_get_overlay_manager(i);
436 mp = get_mgr_priv(mgr);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200437
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200438 if (!mp->enabled || mgr_manual_update(mgr) || mp->busy)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200439 continue;
440
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200441 dss_mgr_write_regs(mgr);
442
443 if (need_go(mgr)) {
Tomi Valkeinen43a972d2011-11-15 15:04:25 +0200444 mp->busy = true;
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200445
446 if (!dss_data.irq_enabled && need_isr())
447 dss_register_vsync_isr();
448
449 dispc_mgr_go(mgr->id);
Tomi Valkeinen43a972d2011-11-15 15:04:25 +0200450 }
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200451 }
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200452}
453
454void dss_mgr_start_update(struct omap_overlay_manager *mgr)
455{
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200456 struct mgr_priv_data *mp = get_mgr_priv(mgr);
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200457 unsigned long flags;
458
459 spin_lock_irqsave(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200460
Tomi Valkeinen34861372011-11-18 15:43:29 +0200461 WARN_ON(mp->updating);
462
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200463 dss_mgr_write_regs(mgr);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200464
Tomi Valkeinen34861372011-11-18 15:43:29 +0200465 mp->updating = true;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200466
Tomi Valkeinen34861372011-11-18 15:43:29 +0200467 if (!dss_data.irq_enabled && need_isr())
468 dss_register_vsync_isr();
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200469
Tomi Valkeinen7797c6d2011-11-04 10:22:46 +0200470 dispc_mgr_enable(mgr->id, true);
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200471
472 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200473}
474
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200475static void dss_apply_irq_handler(void *data, u32 mask);
476
477static void dss_register_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
Tomi Valkeinen34861372011-11-18 15:43:29 +0200487 for (i = 0; i < num_mgrs; ++i)
488 mask |= dispc_mgr_get_framedone_irq(i);
489
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200490 r = omap_dispc_register_isr(dss_apply_irq_handler, NULL, mask);
491 WARN_ON(r);
492
Tomi Valkeinend09c7aa2011-11-15 12:04:43 +0200493 dss_data.irq_enabled = true;
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200494}
495
496static void dss_unregister_vsync_isr(void)
497{
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200498 const int num_mgrs = dss_feat_get_num_mgrs();
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200499 u32 mask;
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200500 int r, i;
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200501
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200502 mask = 0;
503 for (i = 0; i < num_mgrs; ++i)
504 mask |= dispc_mgr_get_vsync_irq(i);
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200505
Tomi Valkeinen34861372011-11-18 15:43:29 +0200506 for (i = 0; i < num_mgrs; ++i)
507 mask |= dispc_mgr_get_framedone_irq(i);
508
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200509 r = omap_dispc_unregister_isr(dss_apply_irq_handler, NULL, mask);
510 WARN_ON(r);
511
Tomi Valkeinend09c7aa2011-11-15 12:04:43 +0200512 dss_data.irq_enabled = false;
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200513}
514
Tomi Valkeinen76098932011-11-16 12:03:22 +0200515static void mgr_clear_shadow_dirty(struct omap_overlay_manager *mgr)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200516{
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200517 struct omap_overlay *ovl;
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200518 struct mgr_priv_data *mp;
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200519 struct ovl_priv_data *op;
Tomi Valkeinen76098932011-11-16 12:03:22 +0200520
521 mp = get_mgr_priv(mgr);
522 mp->shadow_dirty = false;
523
524 list_for_each_entry(ovl, &mgr->overlays, list) {
525 op = get_ovl_priv(ovl);
526 op->shadow_dirty = false;
527 op->shadow_extra_info_dirty = false;
528 }
529}
530
531static void dss_apply_irq_handler(void *data, u32 mask)
532{
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200533 const int num_mgrs = dss_feat_get_num_mgrs();
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200534 int i;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200535
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200536 spin_lock(&data_lock);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200537
Tomi Valkeinen76098932011-11-16 12:03:22 +0200538 /* clear busy, updating flags, shadow_dirty flags */
Tomi Valkeinen43a972d2011-11-15 15:04:25 +0200539 for (i = 0; i < num_mgrs; i++) {
Tomi Valkeinen76098932011-11-16 12:03:22 +0200540 struct omap_overlay_manager *mgr;
541 struct mgr_priv_data *mp;
542
Tomi Valkeinen43a972d2011-11-15 15:04:25 +0200543 mgr = omap_dss_get_overlay_manager(i);
544 mp = get_mgr_priv(mgr);
545
Tomi Valkeinen76098932011-11-16 12:03:22 +0200546 if (!mp->enabled)
Tomi Valkeinen43a972d2011-11-15 15:04:25 +0200547 continue;
548
Tomi Valkeinen76098932011-11-16 12:03:22 +0200549 mp->updating = dispc_mgr_is_enabled(i);
Tomi Valkeinen43a972d2011-11-15 15:04:25 +0200550
Tomi Valkeinen76098932011-11-16 12:03:22 +0200551 if (!mgr_manual_update(mgr)) {
552 mp->busy = dispc_mgr_go_busy(i);
553
554 if (!mp->busy)
555 mgr_clear_shadow_dirty(mgr);
556 } else {
557 if (!mp->updating)
558 mgr_clear_shadow_dirty(mgr);
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200559 }
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200560 }
561
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200562 dss_write_regs();
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200563
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200564 if (!need_isr())
565 dss_unregister_vsync_isr();
Tomi Valkeinen43a972d2011-11-15 15:04:25 +0200566
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200567 spin_unlock(&data_lock);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200568}
569
Tomi Valkeinen5738b632011-11-15 13:37:33 +0200570static void omap_dss_mgr_apply_ovl(struct omap_overlay *ovl)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200571{
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200572 struct ovl_priv_data *op;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200573
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200574 op = get_ovl_priv(ovl);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200575
576 if (ovl->manager_changed) {
577 ovl->manager_changed = false;
578 ovl->info_dirty = true;
579 }
580
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200581 if (!ovl->info_dirty)
Tomi Valkeinen5738b632011-11-15 13:37:33 +0200582 return;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200583
584 ovl->info_dirty = false;
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200585 op->dirty = true;
586 op->info = ovl->info;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200587
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200588 op->channel = ovl->manager->id;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200589}
590
591static void omap_dss_mgr_apply_mgr(struct omap_overlay_manager *mgr)
592{
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200593 struct mgr_priv_data *mp;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200594
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200595 mp = get_mgr_priv(mgr);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200596
597 if (mgr->device_changed) {
598 mgr->device_changed = false;
Tomi Valkeinen388c4c62011-11-16 13:58:07 +0200599 mp->user_info_dirty = true;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200600 }
601
Tomi Valkeinen388c4c62011-11-16 13:58:07 +0200602 if (!mp->user_info_dirty)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200603 return;
604
Tomi Valkeinen388c4c62011-11-16 13:58:07 +0200605 mp->user_info_dirty = false;
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200606 mp->dirty = true;
Tomi Valkeinen388c4c62011-11-16 13:58:07 +0200607 mp->info = mp->user_info;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200608}
609
610static void omap_dss_mgr_apply_ovl_fifos(struct omap_overlay *ovl)
611{
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200612 struct ovl_priv_data *op;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200613 struct omap_dss_device *dssdev;
614 u32 size, burst_size;
615
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200616 op = get_ovl_priv(ovl);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200617
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200618 dssdev = ovl->manager->device;
619
620 size = dispc_ovl_get_fifo_size(ovl->id);
621
622 burst_size = dispc_ovl_get_burst_size(ovl->id);
623
624 switch (dssdev->type) {
625 case OMAP_DISPLAY_TYPE_DPI:
626 case OMAP_DISPLAY_TYPE_DBI:
627 case OMAP_DISPLAY_TYPE_SDI:
628 case OMAP_DISPLAY_TYPE_VENC:
629 case OMAP_DISPLAY_TYPE_HDMI:
630 default_get_overlay_fifo_thresholds(ovl->id, size,
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200631 burst_size, &op->fifo_low,
632 &op->fifo_high);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200633 break;
634#ifdef CONFIG_OMAP2_DSS_DSI
635 case OMAP_DISPLAY_TYPE_DSI:
636 dsi_get_overlay_fifo_thresholds(ovl->id, size,
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200637 burst_size, &op->fifo_low,
638 &op->fifo_high);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200639 break;
640#endif
641 default:
642 BUG();
643 }
644}
645
646int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
647{
Tomi Valkeinen07e327c2011-11-05 10:59:59 +0200648 int r;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200649 unsigned long flags;
Tomi Valkeinen07e327c2011-11-05 10:59:59 +0200650 struct omap_overlay *ovl;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200651
652 DSSDBG("omap_dss_mgr_apply(%s)\n", mgr->name);
653
654 r = dispc_runtime_get();
655 if (r)
656 return r;
657
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200658 spin_lock_irqsave(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200659
660 /* Configure overlays */
Tomi Valkeinen07e327c2011-11-05 10:59:59 +0200661 list_for_each_entry(ovl, &mgr->overlays, list)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200662 omap_dss_mgr_apply_ovl(ovl);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200663
664 /* Configure manager */
665 omap_dss_mgr_apply_mgr(mgr);
666
667 /* Configure overlay fifos */
Tomi Valkeinen07e327c2011-11-05 10:59:59 +0200668 list_for_each_entry(ovl, &mgr->overlays, list)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200669 omap_dss_mgr_apply_ovl_fifos(ovl);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200670
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200671 dss_write_regs();
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200672
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200673 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200674
675 dispc_runtime_put();
676
677 return r;
678}
679
Tomi Valkeinen7797c6d2011-11-04 10:22:46 +0200680void dss_mgr_enable(struct omap_overlay_manager *mgr)
681{
Tomi Valkeinenbf213522011-11-15 14:43:53 +0200682 struct mgr_priv_data *mp = get_mgr_priv(mgr);
683 unsigned long flags;
684
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200685 mutex_lock(&apply_lock);
686
Tomi Valkeinenbf213522011-11-15 14:43:53 +0200687 spin_lock_irqsave(&data_lock, flags);
688
689 mp->enabled = true;
690
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200691 dss_write_regs();
692
Tomi Valkeinen34861372011-11-18 15:43:29 +0200693 if (!mgr_manual_update(mgr))
694 mp->updating = true;
695
Tomi Valkeinenbf213522011-11-15 14:43:53 +0200696 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200697
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200698 if (!mgr_manual_update(mgr))
699 dispc_mgr_enable(mgr->id, true);
700
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200701 mutex_unlock(&apply_lock);
Tomi Valkeinen7797c6d2011-11-04 10:22:46 +0200702}
703
704void dss_mgr_disable(struct omap_overlay_manager *mgr)
705{
Tomi Valkeinenbf213522011-11-15 14:43:53 +0200706 struct mgr_priv_data *mp = get_mgr_priv(mgr);
707 unsigned long flags;
708
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200709 mutex_lock(&apply_lock);
710
Tomi Valkeinen9a147a62011-11-09 15:30:11 +0200711 if (!mgr_manual_update(mgr))
712 dispc_mgr_enable(mgr->id, false);
Tomi Valkeinenbf213522011-11-15 14:43:53 +0200713
714 spin_lock_irqsave(&data_lock, flags);
715
Tomi Valkeinen34861372011-11-18 15:43:29 +0200716 mp->updating = false;
Tomi Valkeinenbf213522011-11-15 14:43:53 +0200717 mp->enabled = false;
718
719 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200720
721 mutex_unlock(&apply_lock);
Tomi Valkeinen7797c6d2011-11-04 10:22:46 +0200722}
723
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200724int dss_mgr_set_info(struct omap_overlay_manager *mgr,
725 struct omap_overlay_manager_info *info)
726{
Tomi Valkeinen388c4c62011-11-16 13:58:07 +0200727 struct mgr_priv_data *mp = get_mgr_priv(mgr);
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200728 unsigned long flags;
729
730 spin_lock_irqsave(&data_lock, flags);
731
Tomi Valkeinen388c4c62011-11-16 13:58:07 +0200732 mp->user_info = *info;
733 mp->user_info_dirty = true;
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200734
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200735 spin_unlock_irqrestore(&data_lock, flags);
736
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200737 return 0;
738}
739
740void dss_mgr_get_info(struct omap_overlay_manager *mgr,
741 struct omap_overlay_manager_info *info)
742{
Tomi Valkeinen388c4c62011-11-16 13:58:07 +0200743 struct mgr_priv_data *mp = get_mgr_priv(mgr);
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200744 unsigned long flags;
745
746 spin_lock_irqsave(&data_lock, flags);
747
Tomi Valkeinen388c4c62011-11-16 13:58:07 +0200748 *info = mp->user_info;
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200749
750 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200751}
752
753int dss_mgr_set_device(struct omap_overlay_manager *mgr,
754 struct omap_dss_device *dssdev)
755{
756 int r;
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200757
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200758 mutex_lock(&apply_lock);
759
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200760 if (dssdev->manager) {
761 DSSERR("display '%s' already has a manager '%s'\n",
762 dssdev->name, dssdev->manager->name);
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200763 r = -EINVAL;
764 goto err;
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200765 }
766
767 if ((mgr->supported_displays & dssdev->type) == 0) {
768 DSSERR("display '%s' does not support manager '%s'\n",
769 dssdev->name, mgr->name);
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200770 r = -EINVAL;
771 goto err;
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200772 }
773
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200774 dssdev->manager = mgr;
775 mgr->device = dssdev;
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
786int dss_mgr_unset_device(struct omap_overlay_manager *mgr)
787{
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200788 int r;
789
790 mutex_lock(&apply_lock);
791
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200792 if (!mgr->device) {
793 DSSERR("failed to unset display, display not set.\n");
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200794 r = -EINVAL;
795 goto err;
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200796 }
797
798 /*
799 * Don't allow currently enabled displays to have the overlay manager
800 * pulled out from underneath them
801 */
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200802 if (mgr->device->state != OMAP_DSS_DISPLAY_DISABLED) {
803 r = -EINVAL;
804 goto err;
805 }
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200806
807 mgr->device->manager = NULL;
808 mgr->device = NULL;
809 mgr->device_changed = true;
810
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200811 mutex_unlock(&apply_lock);
812
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200813 return 0;
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200814err:
815 mutex_unlock(&apply_lock);
816 return r;
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200817}
818
819
820
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200821int dss_ovl_set_info(struct omap_overlay *ovl,
822 struct omap_overlay_info *info)
823{
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200824 unsigned long flags;
825
826 spin_lock_irqsave(&data_lock, flags);
827
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200828 ovl->info = *info;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200829 ovl->info_dirty = true;
830
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200831 spin_unlock_irqrestore(&data_lock, flags);
832
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200833 return 0;
834}
835
836void dss_ovl_get_info(struct omap_overlay *ovl,
837 struct omap_overlay_info *info)
838{
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200839 unsigned long flags;
840
841 spin_lock_irqsave(&data_lock, flags);
842
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200843 *info = ovl->info;
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200844
845 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200846}
847
848int dss_ovl_set_manager(struct omap_overlay *ovl,
849 struct omap_overlay_manager *mgr)
850{
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200851 struct ovl_priv_data *op = get_ovl_priv(ovl);
852 unsigned long flags;
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200853 int r;
854
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200855 if (!mgr)
856 return -EINVAL;
857
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200858 mutex_lock(&apply_lock);
859
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200860 if (ovl->manager) {
861 DSSERR("overlay '%s' already has a manager '%s'\n",
862 ovl->name, ovl->manager->name);
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200863 r = -EINVAL;
864 goto err;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200865 }
866
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200867 spin_lock_irqsave(&data_lock, flags);
868
869 if (op->enabled) {
870 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200871 DSSERR("overlay has to be disabled to change the manager\n");
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200872 r = -EINVAL;
873 goto err;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200874 }
875
876 ovl->manager = mgr;
877 list_add_tail(&ovl->list, &mgr->overlays);
878 ovl->manager_changed = true;
879
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200880 spin_unlock_irqrestore(&data_lock, flags);
881
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200882 /* XXX: When there is an overlay on a DSI manual update display, and
883 * the overlay is first disabled, then moved to tv, and enabled, we
884 * seem to get SYNC_LOST_DIGIT error.
885 *
886 * Waiting doesn't seem to help, but updating the manual update display
887 * after disabling the overlay seems to fix this. This hints that the
888 * overlay is perhaps somehow tied to the LCD output until the output
889 * is updated.
890 *
891 * Userspace workaround for this is to update the LCD after disabling
892 * the overlay, but before moving the overlay to TV.
893 */
894
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200895 mutex_unlock(&apply_lock);
896
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200897 return 0;
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200898err:
899 mutex_unlock(&apply_lock);
900 return r;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200901}
902
903int dss_ovl_unset_manager(struct omap_overlay *ovl)
904{
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200905 struct ovl_priv_data *op = get_ovl_priv(ovl);
906 unsigned long flags;
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200907 int r;
908
909 mutex_lock(&apply_lock);
910
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200911 if (!ovl->manager) {
912 DSSERR("failed to detach overlay: manager not set\n");
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200913 r = -EINVAL;
914 goto err;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200915 }
916
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200917 spin_lock_irqsave(&data_lock, flags);
918
919 if (op->enabled) {
920 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200921 DSSERR("overlay has to be disabled to unset the manager\n");
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200922 r = -EINVAL;
923 goto err;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200924 }
925
926 ovl->manager = NULL;
927 list_del(&ovl->list);
928 ovl->manager_changed = true;
929
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200930 spin_unlock_irqrestore(&data_lock, flags);
931
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200932 mutex_unlock(&apply_lock);
933
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200934 return 0;
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200935err:
936 mutex_unlock(&apply_lock);
937 return r;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200938}
939
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200940bool dss_ovl_is_enabled(struct omap_overlay *ovl)
941{
942 struct ovl_priv_data *op = get_ovl_priv(ovl);
943 unsigned long flags;
944 bool e;
945
946 spin_lock_irqsave(&data_lock, flags);
947
948 e = op->enabled;
949
950 spin_unlock_irqrestore(&data_lock, flags);
951
952 return e;
953}
954
955int dss_ovl_enable(struct omap_overlay *ovl)
956{
957 struct ovl_priv_data *op = get_ovl_priv(ovl);
958 unsigned long flags;
959 int r;
960
961 mutex_lock(&apply_lock);
962
963 if (ovl->manager == NULL || ovl->manager->device == NULL) {
964 r = -EINVAL;
965 goto err;
966 }
967
968 spin_lock_irqsave(&data_lock, flags);
969
970 op->enabled = true;
971 op->extra_info_dirty = true;
972
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200973 dss_write_regs();
974
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200975 spin_unlock_irqrestore(&data_lock, flags);
976
977 mutex_unlock(&apply_lock);
978
979 return 0;
980err:
981 mutex_unlock(&apply_lock);
982 return r;
983}
984
985int dss_ovl_disable(struct omap_overlay *ovl)
986{
987 struct ovl_priv_data *op = get_ovl_priv(ovl);
988 unsigned long flags;
989 int r;
990
991 mutex_lock(&apply_lock);
992
993 if (ovl->manager == NULL || ovl->manager->device == NULL) {
994 r = -EINVAL;
995 goto err;
996 }
997
998 spin_lock_irqsave(&data_lock, flags);
999
1000 op->enabled = false;
1001 op->extra_info_dirty = true;
1002
Tomi Valkeinen75c94962011-11-15 18:25:23 +02001003 dss_write_regs();
1004
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001005 spin_unlock_irqrestore(&data_lock, flags);
1006
1007 mutex_unlock(&apply_lock);
1008
1009 return 0;
1010
1011err:
1012 mutex_unlock(&apply_lock);
1013 return r;
1014}
1015