blob: d5505becd065dc3978d7e2d505e7478ce8862b62 [file] [log] [blame]
Tomi Valkeinen58f255482011-11-04 09:48:54 +02001/*
2 * Copyright (C) 2011 Texas Instruments
3 * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 as published by
7 * the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along with
15 * this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#define DSS_SUBSYS_NAME "APPLY"
19
20#include <linux/kernel.h>
21#include <linux/slab.h>
22#include <linux/spinlock.h>
23#include <linux/jiffies.h>
24
25#include <video/omapdss.h>
26
27#include "dss.h"
28#include "dss_features.h"
29
30/*
31 * We have 4 levels of cache for the dispc settings. First two are in SW and
32 * the latter two in HW.
33 *
34 * +--------------------+
35 * |overlay/manager_info|
36 * +--------------------+
37 * v
38 * apply()
39 * v
40 * +--------------------+
Tomi Valkeinend09c7aa2011-11-15 12:04:43 +020041 * | info |
Tomi Valkeinen58f255482011-11-04 09:48:54 +020042 * +--------------------+
43 * v
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +020044 * write_regs()
Tomi Valkeinen58f255482011-11-04 09:48:54 +020045 * v
46 * +--------------------+
47 * | shadow registers |
48 * +--------------------+
49 * v
50 * VFP or lcd/digit_enable
51 * v
52 * +--------------------+
53 * | registers |
54 * +--------------------+
55 */
56
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +020057struct ovl_priv_data {
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +020058
59 bool user_info_dirty;
60 struct omap_overlay_info user_info;
61
Tomi Valkeinen58f255482011-11-04 09:48:54 +020062 /* If true, cache changed, but not written to shadow registers. Set
63 * in apply(), cleared when registers written. */
64 bool dirty;
65 /* If true, shadow registers contain changed values not yet in real
66 * registers. Set when writing to shadow registers, cleared at
67 * VSYNC/EVSYNC */
68 bool shadow_dirty;
69
Tomi Valkeinen58f255482011-11-04 09:48:54 +020070 struct omap_overlay_info info;
71
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +020072 bool extra_info_dirty;
73 bool shadow_extra_info_dirty;
74
75 bool enabled;
Tomi Valkeinen5d5a97a2011-11-16 14:17:54 +020076 enum omap_channel channel;
Tomi Valkeinen6dc802e2011-11-16 14:28:12 +020077 u32 fifo_low, fifo_high;
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 Valkeinenc1a9feb2011-11-16 14:11:56 +0200132 const int num_ovls = dss_feat_get_num_ovls();
133 int i;
134
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200135 spin_lock_init(&data_lock);
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +0200136
137 for (i = 0; i < num_ovls; ++i) {
138 struct ovl_priv_data *op;
139
140 op = &dss_data.ovl_priv_data_array[i];
141
142 op->info.global_alpha = 255;
143
144 switch (i) {
145 case 0:
146 op->info.zorder = 0;
147 break;
148 case 1:
149 op->info.zorder =
150 dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 3 : 0;
151 break;
152 case 2:
153 op->info.zorder =
154 dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 2 : 0;
155 break;
156 case 3:
157 op->info.zorder =
158 dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 1 : 0;
159 break;
160 }
161
162 op->user_info = op->info;
163 }
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200164}
165
166static bool ovl_manual_update(struct omap_overlay *ovl)
167{
168 return ovl->manager->device->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE;
169}
170
171static bool mgr_manual_update(struct omap_overlay_manager *mgr)
172{
173 return mgr->device->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE;
174}
175
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200176static bool need_isr(void)
177{
178 const int num_mgrs = dss_feat_get_num_mgrs();
179 int i;
180
181 for (i = 0; i < num_mgrs; ++i) {
182 struct omap_overlay_manager *mgr;
183 struct mgr_priv_data *mp;
184 struct omap_overlay *ovl;
185
186 mgr = omap_dss_get_overlay_manager(i);
187 mp = get_mgr_priv(mgr);
188
189 if (!mp->enabled)
190 continue;
191
Tomi Valkeinen34861372011-11-18 15:43:29 +0200192 if (mgr_manual_update(mgr)) {
193 /* to catch FRAMEDONE */
194 if (mp->updating)
195 return true;
196 } else {
197 /* to catch GO bit going down */
198 if (mp->busy)
199 return true;
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200200
201 /* to write new values to registers */
Tomi Valkeinen34861372011-11-18 15:43:29 +0200202 if (mp->dirty)
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200203 return true;
Tomi Valkeinen34861372011-11-18 15:43:29 +0200204
205 list_for_each_entry(ovl, &mgr->overlays, list) {
206 struct ovl_priv_data *op;
207
208 op = get_ovl_priv(ovl);
209
210 if (!op->enabled)
211 continue;
212
213 /* to write new values to registers */
214 if (op->dirty || op->extra_info_dirty)
215 return true;
216 }
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200217 }
218 }
219
220 return false;
221}
222
223static bool need_go(struct omap_overlay_manager *mgr)
224{
225 struct omap_overlay *ovl;
226 struct mgr_priv_data *mp;
227 struct ovl_priv_data *op;
228
229 mp = get_mgr_priv(mgr);
230
231 if (mp->shadow_dirty)
232 return true;
233
234 list_for_each_entry(ovl, &mgr->overlays, list) {
235 op = get_ovl_priv(ovl);
236 if (op->shadow_dirty || op->shadow_extra_info_dirty)
237 return true;
238 }
239
240 return false;
241}
242
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200243int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr)
244{
245 unsigned long timeout = msecs_to_jiffies(500);
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200246 struct mgr_priv_data *mp;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200247 u32 irq;
248 int r;
249 int i;
250 struct omap_dss_device *dssdev = mgr->device;
251
252 if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
253 return 0;
254
255 if (mgr_manual_update(mgr))
256 return 0;
257
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200258 irq = dispc_mgr_get_vsync_irq(mgr->id);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200259
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200260 mp = get_mgr_priv(mgr);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200261 i = 0;
262 while (1) {
263 unsigned long flags;
264 bool shadow_dirty, dirty;
265
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200266 spin_lock_irqsave(&data_lock, flags);
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200267 dirty = mp->dirty;
268 shadow_dirty = mp->shadow_dirty;
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200269 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200270
271 if (!dirty && !shadow_dirty) {
272 r = 0;
273 break;
274 }
275
276 /* 4 iterations is the worst case:
277 * 1 - initial iteration, dirty = true (between VFP and VSYNC)
278 * 2 - first VSYNC, dirty = true
279 * 3 - dirty = false, shadow_dirty = true
280 * 4 - shadow_dirty = false */
281 if (i++ == 3) {
282 DSSERR("mgr(%d)->wait_for_go() not finishing\n",
283 mgr->id);
284 r = 0;
285 break;
286 }
287
288 r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
289 if (r == -ERESTARTSYS)
290 break;
291
292 if (r) {
293 DSSERR("mgr(%d)->wait_for_go() timeout\n", mgr->id);
294 break;
295 }
296 }
297
298 return r;
299}
300
301int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl)
302{
303 unsigned long timeout = msecs_to_jiffies(500);
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200304 struct ovl_priv_data *op;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200305 struct omap_dss_device *dssdev;
306 u32 irq;
307 int r;
308 int i;
309
310 if (!ovl->manager)
311 return 0;
312
313 dssdev = ovl->manager->device;
314
315 if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
316 return 0;
317
318 if (ovl_manual_update(ovl))
319 return 0;
320
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200321 irq = dispc_mgr_get_vsync_irq(ovl->manager->id);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200322
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200323 op = get_ovl_priv(ovl);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200324 i = 0;
325 while (1) {
326 unsigned long flags;
327 bool shadow_dirty, dirty;
328
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200329 spin_lock_irqsave(&data_lock, flags);
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200330 dirty = op->dirty;
331 shadow_dirty = op->shadow_dirty;
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200332 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200333
334 if (!dirty && !shadow_dirty) {
335 r = 0;
336 break;
337 }
338
339 /* 4 iterations is the worst case:
340 * 1 - initial iteration, dirty = true (between VFP and VSYNC)
341 * 2 - first VSYNC, dirty = true
342 * 3 - dirty = false, shadow_dirty = true
343 * 4 - shadow_dirty = false */
344 if (i++ == 3) {
345 DSSERR("ovl(%d)->wait_for_go() not finishing\n",
346 ovl->id);
347 r = 0;
348 break;
349 }
350
351 r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
352 if (r == -ERESTARTSYS)
353 break;
354
355 if (r) {
356 DSSERR("ovl(%d)->wait_for_go() timeout\n", ovl->id);
357 break;
358 }
359 }
360
361 return r;
362}
363
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200364static void dss_ovl_write_regs(struct omap_overlay *ovl)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200365{
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200366 struct ovl_priv_data *op = get_ovl_priv(ovl);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200367 struct omap_overlay_info *oi;
368 bool ilace, replication;
Tomi Valkeinen34861372011-11-18 15:43:29 +0200369 struct mgr_priv_data *mp;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200370 int r;
371
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200372 DSSDBGF("%d", ovl->id);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200373
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200374 if (!op->enabled || !op->dirty)
375 return;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200376
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200377 oi = &op->info;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200378
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200379 replication = dss_use_replication(ovl->manager->device, oi->color_mode);
380
381 ilace = ovl->manager->device->type == OMAP_DISPLAY_TYPE_VENC;
382
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200383 r = dispc_ovl_setup(ovl->id, oi, ilace, replication);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200384 if (r) {
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200385 /*
386 * We can't do much here, as this function can be called from
387 * vsync interrupt.
388 */
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200389 DSSERR("dispc_ovl_setup failed for ovl %d\n", ovl->id);
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200390
391 /* This will leave fifo configurations in a nonoptimal state */
392 op->enabled = false;
393 dispc_ovl_enable(ovl->id, false);
394 return;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200395 }
396
Tomi Valkeinen34861372011-11-18 15:43:29 +0200397 mp = get_mgr_priv(ovl->manager);
398
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200399 op->dirty = false;
Tomi Valkeinen34861372011-11-18 15:43:29 +0200400 if (mp->updating)
401 op->shadow_dirty = true;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200402}
403
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200404static void dss_ovl_write_regs_extra(struct omap_overlay *ovl)
405{
406 struct ovl_priv_data *op = get_ovl_priv(ovl);
Tomi Valkeinen34861372011-11-18 15:43:29 +0200407 struct mgr_priv_data *mp;
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200408
409 DSSDBGF("%d", ovl->id);
410
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200411 if (!op->extra_info_dirty)
412 return;
413
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200414 /* note: write also when op->enabled == false, so that the ovl gets
415 * disabled */
416
417 dispc_ovl_enable(ovl->id, op->enabled);
Tomi Valkeinen5d5a97a2011-11-16 14:17:54 +0200418 dispc_ovl_set_channel_out(ovl->id, op->channel);
Tomi Valkeinen6dc802e2011-11-16 14:28:12 +0200419 dispc_ovl_set_fifo_threshold(ovl->id, op->fifo_low, op->fifo_high);
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200420
Tomi Valkeinen34861372011-11-18 15:43:29 +0200421 mp = get_mgr_priv(ovl->manager);
422
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200423 op->extra_info_dirty = false;
Tomi Valkeinen34861372011-11-18 15:43:29 +0200424 if (mp->updating)
425 op->shadow_extra_info_dirty = true;
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200426}
427
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200428static void dss_mgr_write_regs(struct omap_overlay_manager *mgr)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200429{
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200430 struct mgr_priv_data *mp = get_mgr_priv(mgr);
431 struct omap_overlay *ovl;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200432
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200433 DSSDBGF("%d", mgr->id);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200434
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200435 if (!mp->enabled)
436 return;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200437
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200438 WARN_ON(mp->busy);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200439
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200440 /* Commit overlay settings */
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200441 list_for_each_entry(ovl, &mgr->overlays, list) {
442 dss_ovl_write_regs(ovl);
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200443 dss_ovl_write_regs_extra(ovl);
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200444 }
445
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200446 if (mp->dirty) {
447 dispc_mgr_setup(mgr->id, &mp->info);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200448
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200449 mp->dirty = false;
Tomi Valkeinen34861372011-11-18 15:43:29 +0200450 if (mp->updating)
451 mp->shadow_dirty = true;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200452 }
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200453}
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200454
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200455static void dss_write_regs(void)
456{
457 const int num_mgrs = omap_dss_get_num_overlay_managers();
458 int i;
459
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200460 for (i = 0; i < num_mgrs; ++i) {
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200461 struct omap_overlay_manager *mgr;
462 struct mgr_priv_data *mp;
463
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200464 mgr = omap_dss_get_overlay_manager(i);
465 mp = get_mgr_priv(mgr);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200466
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200467 if (!mp->enabled || mgr_manual_update(mgr) || mp->busy)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200468 continue;
469
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200470 dss_mgr_write_regs(mgr);
471
472 if (need_go(mgr)) {
Tomi Valkeinen43a972d2011-11-15 15:04:25 +0200473 mp->busy = true;
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200474
475 if (!dss_data.irq_enabled && need_isr())
476 dss_register_vsync_isr();
477
478 dispc_mgr_go(mgr->id);
Tomi Valkeinen43a972d2011-11-15 15:04:25 +0200479 }
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200480 }
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200481}
482
483void dss_mgr_start_update(struct omap_overlay_manager *mgr)
484{
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200485 struct mgr_priv_data *mp = get_mgr_priv(mgr);
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200486 unsigned long flags;
487
488 spin_lock_irqsave(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200489
Tomi Valkeinen34861372011-11-18 15:43:29 +0200490 WARN_ON(mp->updating);
491
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200492 dss_mgr_write_regs(mgr);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200493
Tomi Valkeinen34861372011-11-18 15:43:29 +0200494 mp->updating = true;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200495
Tomi Valkeinen34861372011-11-18 15:43:29 +0200496 if (!dss_data.irq_enabled && need_isr())
497 dss_register_vsync_isr();
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200498
Tomi Valkeinen7797c6d2011-11-04 10:22:46 +0200499 dispc_mgr_enable(mgr->id, true);
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200500
501 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200502}
503
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200504static void dss_apply_irq_handler(void *data, u32 mask);
505
506static void dss_register_vsync_isr(void)
507{
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200508 const int num_mgrs = dss_feat_get_num_mgrs();
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200509 u32 mask;
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200510 int r, i;
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200511
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200512 mask = 0;
513 for (i = 0; i < num_mgrs; ++i)
514 mask |= dispc_mgr_get_vsync_irq(i);
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200515
Tomi Valkeinen34861372011-11-18 15:43:29 +0200516 for (i = 0; i < num_mgrs; ++i)
517 mask |= dispc_mgr_get_framedone_irq(i);
518
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200519 r = omap_dispc_register_isr(dss_apply_irq_handler, NULL, mask);
520 WARN_ON(r);
521
Tomi Valkeinend09c7aa2011-11-15 12:04:43 +0200522 dss_data.irq_enabled = true;
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200523}
524
525static void dss_unregister_vsync_isr(void)
526{
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200527 const int num_mgrs = dss_feat_get_num_mgrs();
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200528 u32 mask;
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200529 int r, i;
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200530
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200531 mask = 0;
532 for (i = 0; i < num_mgrs; ++i)
533 mask |= dispc_mgr_get_vsync_irq(i);
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200534
Tomi Valkeinen34861372011-11-18 15:43:29 +0200535 for (i = 0; i < num_mgrs; ++i)
536 mask |= dispc_mgr_get_framedone_irq(i);
537
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200538 r = omap_dispc_unregister_isr(dss_apply_irq_handler, NULL, mask);
539 WARN_ON(r);
540
Tomi Valkeinend09c7aa2011-11-15 12:04:43 +0200541 dss_data.irq_enabled = false;
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200542}
543
Tomi Valkeinen76098932011-11-16 12:03:22 +0200544static void mgr_clear_shadow_dirty(struct omap_overlay_manager *mgr)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200545{
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200546 struct omap_overlay *ovl;
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200547 struct mgr_priv_data *mp;
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200548 struct ovl_priv_data *op;
Tomi Valkeinen76098932011-11-16 12:03:22 +0200549
550 mp = get_mgr_priv(mgr);
551 mp->shadow_dirty = false;
552
553 list_for_each_entry(ovl, &mgr->overlays, list) {
554 op = get_ovl_priv(ovl);
555 op->shadow_dirty = false;
556 op->shadow_extra_info_dirty = false;
557 }
558}
559
560static void dss_apply_irq_handler(void *data, u32 mask)
561{
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200562 const int num_mgrs = dss_feat_get_num_mgrs();
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200563 int i;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200564
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200565 spin_lock(&data_lock);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200566
Tomi Valkeinen76098932011-11-16 12:03:22 +0200567 /* clear busy, updating flags, shadow_dirty flags */
Tomi Valkeinen43a972d2011-11-15 15:04:25 +0200568 for (i = 0; i < num_mgrs; i++) {
Tomi Valkeinen76098932011-11-16 12:03:22 +0200569 struct omap_overlay_manager *mgr;
570 struct mgr_priv_data *mp;
571
Tomi Valkeinen43a972d2011-11-15 15:04:25 +0200572 mgr = omap_dss_get_overlay_manager(i);
573 mp = get_mgr_priv(mgr);
574
Tomi Valkeinen76098932011-11-16 12:03:22 +0200575 if (!mp->enabled)
Tomi Valkeinen43a972d2011-11-15 15:04:25 +0200576 continue;
577
Tomi Valkeinen76098932011-11-16 12:03:22 +0200578 mp->updating = dispc_mgr_is_enabled(i);
Tomi Valkeinen43a972d2011-11-15 15:04:25 +0200579
Tomi Valkeinen76098932011-11-16 12:03:22 +0200580 if (!mgr_manual_update(mgr)) {
581 mp->busy = dispc_mgr_go_busy(i);
582
583 if (!mp->busy)
584 mgr_clear_shadow_dirty(mgr);
585 } else {
586 if (!mp->updating)
587 mgr_clear_shadow_dirty(mgr);
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200588 }
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200589 }
590
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200591 dss_write_regs();
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200592
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200593 if (!need_isr())
594 dss_unregister_vsync_isr();
Tomi Valkeinen43a972d2011-11-15 15:04:25 +0200595
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200596 spin_unlock(&data_lock);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200597}
598
Tomi Valkeinen5738b632011-11-15 13:37:33 +0200599static void omap_dss_mgr_apply_ovl(struct omap_overlay *ovl)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200600{
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200601 struct ovl_priv_data *op;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200602
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200603 op = get_ovl_priv(ovl);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200604
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +0200605 if (!op->user_info_dirty)
Tomi Valkeinen5738b632011-11-15 13:37:33 +0200606 return;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200607
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +0200608 op->user_info_dirty = false;
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200609 op->dirty = true;
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +0200610 op->info = op->user_info;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200611}
612
613static void omap_dss_mgr_apply_mgr(struct omap_overlay_manager *mgr)
614{
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200615 struct mgr_priv_data *mp;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200616
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200617 mp = get_mgr_priv(mgr);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200618
619 if (mgr->device_changed) {
620 mgr->device_changed = false;
Tomi Valkeinen388c4c62011-11-16 13:58:07 +0200621 mp->user_info_dirty = true;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200622 }
623
Tomi Valkeinen388c4c62011-11-16 13:58:07 +0200624 if (!mp->user_info_dirty)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200625 return;
626
Tomi Valkeinen388c4c62011-11-16 13:58:07 +0200627 mp->user_info_dirty = false;
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200628 mp->dirty = true;
Tomi Valkeinen388c4c62011-11-16 13:58:07 +0200629 mp->info = mp->user_info;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200630}
631
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200632int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
633{
Tomi Valkeinen07e327c2011-11-05 10:59:59 +0200634 int r;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200635 unsigned long flags;
Tomi Valkeinen07e327c2011-11-05 10:59:59 +0200636 struct omap_overlay *ovl;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200637
638 DSSDBG("omap_dss_mgr_apply(%s)\n", mgr->name);
639
640 r = dispc_runtime_get();
641 if (r)
642 return r;
643
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200644 spin_lock_irqsave(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200645
646 /* Configure overlays */
Tomi Valkeinen07e327c2011-11-05 10:59:59 +0200647 list_for_each_entry(ovl, &mgr->overlays, list)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200648 omap_dss_mgr_apply_ovl(ovl);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200649
650 /* Configure manager */
651 omap_dss_mgr_apply_mgr(mgr);
652
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200653 dss_write_regs();
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200654
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200655 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200656
657 dispc_runtime_put();
658
659 return r;
660}
661
Tomi Valkeinen6dc802e2011-11-16 14:28:12 +0200662static void dss_ovl_setup_fifo(struct omap_overlay *ovl)
663{
664 struct ovl_priv_data *op = get_ovl_priv(ovl);
665 struct omap_dss_device *dssdev;
666 u32 size, burst_size;
667 u32 fifo_low, fifo_high;
668
669 dssdev = ovl->manager->device;
670
671 size = dispc_ovl_get_fifo_size(ovl->id);
672
673 burst_size = dispc_ovl_get_burst_size(ovl->id);
674
675 switch (dssdev->type) {
676 case OMAP_DISPLAY_TYPE_DPI:
677 case OMAP_DISPLAY_TYPE_DBI:
678 case OMAP_DISPLAY_TYPE_SDI:
679 case OMAP_DISPLAY_TYPE_VENC:
680 case OMAP_DISPLAY_TYPE_HDMI:
681 default_get_overlay_fifo_thresholds(ovl->id, size,
682 burst_size, &fifo_low, &fifo_high);
683 break;
684#ifdef CONFIG_OMAP2_DSS_DSI
685 case OMAP_DISPLAY_TYPE_DSI:
686 dsi_get_overlay_fifo_thresholds(ovl->id, size,
687 burst_size, &fifo_low, &fifo_high);
688 break;
689#endif
690 default:
691 BUG();
692 }
693
694 op->fifo_low = fifo_low;
695 op->fifo_high = fifo_high;
696 op->extra_info_dirty = true;
697}
698
699static void dss_mgr_setup_fifos(struct omap_overlay_manager *mgr)
700{
701 struct omap_overlay *ovl;
702 struct ovl_priv_data *op;
703 struct mgr_priv_data *mp;
704
705 mp = get_mgr_priv(mgr);
706
707 if (!mp->enabled)
708 return;
709
710 list_for_each_entry(ovl, &mgr->overlays, list) {
711 op = get_ovl_priv(ovl);
712
713 if (!op->enabled)
714 continue;
715
716 dss_ovl_setup_fifo(ovl);
717 }
718}
719
Tomi Valkeinen7797c6d2011-11-04 10:22:46 +0200720void dss_mgr_enable(struct omap_overlay_manager *mgr)
721{
Tomi Valkeinenbf213522011-11-15 14:43:53 +0200722 struct mgr_priv_data *mp = get_mgr_priv(mgr);
723 unsigned long flags;
724
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200725 mutex_lock(&apply_lock);
726
Tomi Valkeinenbf213522011-11-15 14:43:53 +0200727 spin_lock_irqsave(&data_lock, flags);
728
729 mp->enabled = true;
730
Tomi Valkeinen6dc802e2011-11-16 14:28:12 +0200731 dss_mgr_setup_fifos(mgr);
732
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200733 dss_write_regs();
734
Tomi Valkeinen34861372011-11-18 15:43:29 +0200735 if (!mgr_manual_update(mgr))
736 mp->updating = true;
737
Tomi Valkeinenbf213522011-11-15 14:43:53 +0200738 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200739
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200740 if (!mgr_manual_update(mgr))
741 dispc_mgr_enable(mgr->id, true);
742
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200743 mutex_unlock(&apply_lock);
Tomi Valkeinen7797c6d2011-11-04 10:22:46 +0200744}
745
746void dss_mgr_disable(struct omap_overlay_manager *mgr)
747{
Tomi Valkeinenbf213522011-11-15 14:43:53 +0200748 struct mgr_priv_data *mp = get_mgr_priv(mgr);
749 unsigned long flags;
750
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200751 mutex_lock(&apply_lock);
752
Tomi Valkeinen9a147a62011-11-09 15:30:11 +0200753 if (!mgr_manual_update(mgr))
754 dispc_mgr_enable(mgr->id, false);
Tomi Valkeinenbf213522011-11-15 14:43:53 +0200755
756 spin_lock_irqsave(&data_lock, flags);
757
Tomi Valkeinen34861372011-11-18 15:43:29 +0200758 mp->updating = false;
Tomi Valkeinenbf213522011-11-15 14:43:53 +0200759 mp->enabled = false;
760
761 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200762
763 mutex_unlock(&apply_lock);
Tomi Valkeinen7797c6d2011-11-04 10:22:46 +0200764}
765
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200766int dss_mgr_set_info(struct omap_overlay_manager *mgr,
767 struct omap_overlay_manager_info *info)
768{
Tomi Valkeinen388c4c62011-11-16 13:58:07 +0200769 struct mgr_priv_data *mp = get_mgr_priv(mgr);
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200770 unsigned long flags;
771
772 spin_lock_irqsave(&data_lock, flags);
773
Tomi Valkeinen388c4c62011-11-16 13:58:07 +0200774 mp->user_info = *info;
775 mp->user_info_dirty = true;
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200776
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200777 spin_unlock_irqrestore(&data_lock, flags);
778
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200779 return 0;
780}
781
782void dss_mgr_get_info(struct omap_overlay_manager *mgr,
783 struct omap_overlay_manager_info *info)
784{
Tomi Valkeinen388c4c62011-11-16 13:58:07 +0200785 struct mgr_priv_data *mp = get_mgr_priv(mgr);
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200786 unsigned long flags;
787
788 spin_lock_irqsave(&data_lock, flags);
789
Tomi Valkeinen388c4c62011-11-16 13:58:07 +0200790 *info = mp->user_info;
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200791
792 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200793}
794
795int dss_mgr_set_device(struct omap_overlay_manager *mgr,
796 struct omap_dss_device *dssdev)
797{
798 int r;
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200799
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200800 mutex_lock(&apply_lock);
801
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200802 if (dssdev->manager) {
803 DSSERR("display '%s' already has a manager '%s'\n",
804 dssdev->name, dssdev->manager->name);
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200805 r = -EINVAL;
806 goto err;
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200807 }
808
809 if ((mgr->supported_displays & dssdev->type) == 0) {
810 DSSERR("display '%s' does not support manager '%s'\n",
811 dssdev->name, mgr->name);
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200812 r = -EINVAL;
813 goto err;
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200814 }
815
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200816 dssdev->manager = mgr;
817 mgr->device = dssdev;
818 mgr->device_changed = true;
819
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200820 mutex_unlock(&apply_lock);
821
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200822 return 0;
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200823err:
824 mutex_unlock(&apply_lock);
825 return r;
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200826}
827
828int dss_mgr_unset_device(struct omap_overlay_manager *mgr)
829{
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200830 int r;
831
832 mutex_lock(&apply_lock);
833
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200834 if (!mgr->device) {
835 DSSERR("failed to unset display, display not set.\n");
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200836 r = -EINVAL;
837 goto err;
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200838 }
839
840 /*
841 * Don't allow currently enabled displays to have the overlay manager
842 * pulled out from underneath them
843 */
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200844 if (mgr->device->state != OMAP_DSS_DISPLAY_DISABLED) {
845 r = -EINVAL;
846 goto err;
847 }
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200848
849 mgr->device->manager = NULL;
850 mgr->device = NULL;
851 mgr->device_changed = true;
852
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200853 mutex_unlock(&apply_lock);
854
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200855 return 0;
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200856err:
857 mutex_unlock(&apply_lock);
858 return r;
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200859}
860
861
862
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200863int dss_ovl_set_info(struct omap_overlay *ovl,
864 struct omap_overlay_info *info)
865{
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +0200866 struct ovl_priv_data *op = get_ovl_priv(ovl);
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200867 unsigned long flags;
868
869 spin_lock_irqsave(&data_lock, flags);
870
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +0200871 op->user_info = *info;
872 op->user_info_dirty = true;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200873
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200874 spin_unlock_irqrestore(&data_lock, flags);
875
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200876 return 0;
877}
878
879void dss_ovl_get_info(struct omap_overlay *ovl,
880 struct omap_overlay_info *info)
881{
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +0200882 struct ovl_priv_data *op = get_ovl_priv(ovl);
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200883 unsigned long flags;
884
885 spin_lock_irqsave(&data_lock, flags);
886
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +0200887 *info = op->user_info;
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200888
889 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200890}
891
892int dss_ovl_set_manager(struct omap_overlay *ovl,
893 struct omap_overlay_manager *mgr)
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
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200899 if (!mgr)
900 return -EINVAL;
901
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200902 mutex_lock(&apply_lock);
903
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200904 if (ovl->manager) {
905 DSSERR("overlay '%s' already has a manager '%s'\n",
906 ovl->name, ovl->manager->name);
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200907 r = -EINVAL;
908 goto err;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200909 }
910
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200911 spin_lock_irqsave(&data_lock, flags);
912
913 if (op->enabled) {
914 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200915 DSSERR("overlay has to be disabled to change the manager\n");
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200916 r = -EINVAL;
917 goto err;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200918 }
919
Tomi Valkeinen5d5a97a2011-11-16 14:17:54 +0200920 op->channel = mgr->id;
921 op->extra_info_dirty = true;
922
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200923 ovl->manager = mgr;
924 list_add_tail(&ovl->list, &mgr->overlays);
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200925
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200926 spin_unlock_irqrestore(&data_lock, flags);
927
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200928 /* XXX: When there is an overlay on a DSI manual update display, and
929 * the overlay is first disabled, then moved to tv, and enabled, we
930 * seem to get SYNC_LOST_DIGIT error.
931 *
932 * Waiting doesn't seem to help, but updating the manual update display
933 * after disabling the overlay seems to fix this. This hints that the
934 * overlay is perhaps somehow tied to the LCD output until the output
935 * is updated.
936 *
937 * Userspace workaround for this is to update the LCD after disabling
938 * the overlay, but before moving the overlay to TV.
939 */
940
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200941 mutex_unlock(&apply_lock);
942
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200943 return 0;
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200944err:
945 mutex_unlock(&apply_lock);
946 return r;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200947}
948
949int dss_ovl_unset_manager(struct omap_overlay *ovl)
950{
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200951 struct ovl_priv_data *op = get_ovl_priv(ovl);
952 unsigned long flags;
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200953 int r;
954
955 mutex_lock(&apply_lock);
956
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200957 if (!ovl->manager) {
958 DSSERR("failed to detach overlay: manager not set\n");
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200959 r = -EINVAL;
960 goto err;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200961 }
962
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200963 spin_lock_irqsave(&data_lock, flags);
964
965 if (op->enabled) {
966 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200967 DSSERR("overlay has to be disabled to unset the manager\n");
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200968 r = -EINVAL;
969 goto err;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200970 }
971
Tomi Valkeinen5d5a97a2011-11-16 14:17:54 +0200972 op->channel = -1;
973
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200974 ovl->manager = NULL;
975 list_del(&ovl->list);
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200976
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200977 spin_unlock_irqrestore(&data_lock, flags);
978
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200979 mutex_unlock(&apply_lock);
980
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200981 return 0;
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200982err:
983 mutex_unlock(&apply_lock);
984 return r;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200985}
986
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200987bool dss_ovl_is_enabled(struct omap_overlay *ovl)
988{
989 struct ovl_priv_data *op = get_ovl_priv(ovl);
990 unsigned long flags;
991 bool e;
992
993 spin_lock_irqsave(&data_lock, flags);
994
995 e = op->enabled;
996
997 spin_unlock_irqrestore(&data_lock, flags);
998
999 return e;
1000}
1001
1002int dss_ovl_enable(struct omap_overlay *ovl)
1003{
1004 struct ovl_priv_data *op = get_ovl_priv(ovl);
1005 unsigned long flags;
1006 int r;
1007
1008 mutex_lock(&apply_lock);
1009
1010 if (ovl->manager == NULL || ovl->manager->device == NULL) {
1011 r = -EINVAL;
1012 goto err;
1013 }
1014
1015 spin_lock_irqsave(&data_lock, flags);
1016
1017 op->enabled = true;
1018 op->extra_info_dirty = true;
1019
Tomi Valkeinen6dc802e2011-11-16 14:28:12 +02001020 dss_ovl_setup_fifo(ovl);
1021
Tomi Valkeinen75c94962011-11-15 18:25:23 +02001022 dss_write_regs();
1023
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001024 spin_unlock_irqrestore(&data_lock, flags);
1025
1026 mutex_unlock(&apply_lock);
1027
1028 return 0;
1029err:
1030 mutex_unlock(&apply_lock);
1031 return r;
1032}
1033
1034int dss_ovl_disable(struct omap_overlay *ovl)
1035{
1036 struct ovl_priv_data *op = get_ovl_priv(ovl);
1037 unsigned long flags;
1038 int r;
1039
1040 mutex_lock(&apply_lock);
1041
1042 if (ovl->manager == NULL || ovl->manager->device == NULL) {
1043 r = -EINVAL;
1044 goto err;
1045 }
1046
1047 spin_lock_irqsave(&data_lock, flags);
1048
1049 op->enabled = false;
1050 op->extra_info_dirty = true;
1051
Tomi Valkeinen75c94962011-11-15 18:25:23 +02001052 dss_write_regs();
1053
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001054 spin_unlock_irqrestore(&data_lock, flags);
1055
1056 mutex_unlock(&apply_lock);
1057
1058 return 0;
1059
1060err:
1061 mutex_unlock(&apply_lock);
1062 return r;
1063}
1064