blob: a3c75f582e1f22c5255b342893baa0aa8a10cbe3 [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 *
Tomi Valkeinen0b53f172011-11-16 14:31:58 +020034 * set_info()
35 * v
Tomi Valkeinen58f255482011-11-04 09:48:54 +020036 * +--------------------+
Tomi Valkeinen0b53f172011-11-16 14:31:58 +020037 * | user_info |
Tomi Valkeinen58f255482011-11-04 09:48:54 +020038 * +--------------------+
39 * v
40 * apply()
41 * v
42 * +--------------------+
Tomi Valkeinend09c7aa2011-11-15 12:04:43 +020043 * | info |
Tomi Valkeinen58f255482011-11-04 09:48:54 +020044 * +--------------------+
45 * v
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +020046 * write_regs()
Tomi Valkeinen58f255482011-11-04 09:48:54 +020047 * v
48 * +--------------------+
49 * | shadow registers |
50 * +--------------------+
51 * v
52 * VFP or lcd/digit_enable
53 * v
54 * +--------------------+
55 * | registers |
56 * +--------------------+
57 */
58
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +020059struct ovl_priv_data {
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +020060
61 bool user_info_dirty;
62 struct omap_overlay_info user_info;
63
Tomi Valkeinen0b53f172011-11-16 14:31:58 +020064 bool info_dirty;
Tomi Valkeinen58f255482011-11-04 09:48:54 +020065 struct omap_overlay_info info;
66
Tomi Valkeinen0b53f172011-11-16 14:31:58 +020067 bool shadow_info_dirty;
68
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +020069 bool extra_info_dirty;
70 bool shadow_extra_info_dirty;
71
72 bool enabled;
Tomi Valkeinen5d5a97a2011-11-16 14:17:54 +020073 enum omap_channel channel;
Tomi Valkeinen6dc802e2011-11-16 14:28:12 +020074 u32 fifo_low, fifo_high;
Tomi Valkeinen82153ed2011-11-26 14:26:46 +020075
76 /*
77 * True if overlay is to be enabled. Used to check and calculate configs
78 * for the overlay before it is enabled in the HW.
79 */
80 bool enabling;
Tomi Valkeinen58f255482011-11-04 09:48:54 +020081};
82
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +020083struct mgr_priv_data {
Tomi Valkeinen388c4c62011-11-16 13:58:07 +020084
85 bool user_info_dirty;
86 struct omap_overlay_manager_info user_info;
87
Tomi Valkeinen0b53f172011-11-16 14:31:58 +020088 bool info_dirty;
Tomi Valkeinen58f255482011-11-04 09:48:54 +020089 struct omap_overlay_manager_info info;
90
Tomi Valkeinen0b53f172011-11-16 14:31:58 +020091 bool shadow_info_dirty;
92
Tomi Valkeinen43a972d2011-11-15 15:04:25 +020093 /* If true, GO bit is up and shadow registers cannot be written.
94 * Never true for manual update displays */
95 bool busy;
96
Tomi Valkeinen34861372011-11-18 15:43:29 +020097 /* If true, dispc output is enabled */
98 bool updating;
99
Tomi Valkeinenbf213522011-11-15 14:43:53 +0200100 /* If true, a display is enabled using this manager */
101 bool enabled;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200102};
103
104static struct {
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200105 struct ovl_priv_data ovl_priv_data_array[MAX_DSS_OVERLAYS];
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200106 struct mgr_priv_data mgr_priv_data_array[MAX_DSS_MANAGERS];
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200107
108 bool irq_enabled;
Tomi Valkeinend09c7aa2011-11-15 12:04:43 +0200109} dss_data;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200110
Tomi Valkeinend09c7aa2011-11-15 12:04:43 +0200111/* protects dss_data */
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200112static spinlock_t data_lock;
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200113/* lock for blocking functions */
114static DEFINE_MUTEX(apply_lock);
Tomi Valkeinenf1577ce2011-11-16 14:37:48 +0200115static DECLARE_COMPLETION(extra_updated_completion);
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200116
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200117static void dss_register_vsync_isr(void);
118
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200119static struct ovl_priv_data *get_ovl_priv(struct omap_overlay *ovl)
120{
Tomi Valkeinend09c7aa2011-11-15 12:04:43 +0200121 return &dss_data.ovl_priv_data_array[ovl->id];
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200122}
123
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200124static struct mgr_priv_data *get_mgr_priv(struct omap_overlay_manager *mgr)
125{
Tomi Valkeinend09c7aa2011-11-15 12:04:43 +0200126 return &dss_data.mgr_priv_data_array[mgr->id];
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200127}
128
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200129void dss_apply_init(void)
130{
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +0200131 const int num_ovls = dss_feat_get_num_ovls();
132 int i;
133
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200134 spin_lock_init(&data_lock);
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +0200135
136 for (i = 0; i < num_ovls; ++i) {
137 struct ovl_priv_data *op;
138
139 op = &dss_data.ovl_priv_data_array[i];
140
141 op->info.global_alpha = 255;
142
143 switch (i) {
144 case 0:
145 op->info.zorder = 0;
146 break;
147 case 1:
148 op->info.zorder =
149 dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 3 : 0;
150 break;
151 case 2:
152 op->info.zorder =
153 dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 2 : 0;
154 break;
155 case 3:
156 op->info.zorder =
157 dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 1 : 0;
158 break;
159 }
160
161 op->user_info = op->info;
162 }
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200163}
164
165static bool ovl_manual_update(struct omap_overlay *ovl)
166{
167 return ovl->manager->device->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE;
168}
169
170static bool mgr_manual_update(struct omap_overlay_manager *mgr)
171{
172 return mgr->device->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE;
173}
174
Tomi Valkeinen39518352011-11-17 17:35:28 +0200175/* Check if overlay parameters are compatible with display */
176static int dss_ovl_check(struct omap_overlay *ovl,
177 struct omap_overlay_info *info, struct omap_dss_device *dssdev)
178{
179 u16 outw, outh;
180 u16 dw, dh;
181
182 if (dssdev == NULL)
183 return 0;
184
185 dssdev->driver->get_resolution(dssdev, &dw, &dh);
186
187 if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0) {
188 outw = info->width;
189 outh = info->height;
190 } else {
191 if (info->out_width == 0)
192 outw = info->width;
193 else
194 outw = info->out_width;
195
196 if (info->out_height == 0)
197 outh = info->height;
198 else
199 outh = info->out_height;
200 }
201
202 if (dw < info->pos_x + outw) {
203 DSSERR("overlay %d horizontally not inside the display area "
204 "(%d + %d >= %d)\n",
205 ovl->id, info->pos_x, outw, dw);
206 return -EINVAL;
207 }
208
209 if (dh < info->pos_y + outh) {
210 DSSERR("overlay %d vertically not inside the display area "
211 "(%d + %d >= %d)\n",
212 ovl->id, info->pos_y, outh, dh);
213 return -EINVAL;
214 }
215
216 return 0;
217}
218
219static int dss_mgr_check_zorder(struct omap_overlay_manager *mgr,
220 struct omap_overlay_info **overlay_infos)
221{
222 struct omap_overlay *ovl1, *ovl2;
223 struct ovl_priv_data *op1, *op2;
224 struct omap_overlay_info *info1, *info2;
225
226 list_for_each_entry(ovl1, &mgr->overlays, list) {
227 op1 = get_ovl_priv(ovl1);
228 info1 = overlay_infos[ovl1->id];
229
230 if (info1 == NULL)
231 continue;
232
233 list_for_each_entry(ovl2, &mgr->overlays, list) {
234 if (ovl1 == ovl2)
235 continue;
236
237 op2 = get_ovl_priv(ovl2);
238 info2 = overlay_infos[ovl2->id];
239
240 if (info2 == NULL)
241 continue;
242
243 if (info1->zorder == info2->zorder) {
244 DSSERR("overlays %d and %d have the same "
245 "zorder %d\n",
246 ovl1->id, ovl2->id, info1->zorder);
247 return -EINVAL;
248 }
249 }
250 }
251
252 return 0;
253}
254
255static int dss_mgr_check(struct omap_overlay_manager *mgr,
256 struct omap_dss_device *dssdev,
257 struct omap_overlay_manager_info *info,
258 struct omap_overlay_info **overlay_infos)
259{
260 struct omap_overlay *ovl;
261 int r;
262
263 if (dss_has_feature(FEAT_ALPHA_FREE_ZORDER)) {
264 r = dss_mgr_check_zorder(mgr, overlay_infos);
265 if (r)
266 return r;
267 }
268
269 list_for_each_entry(ovl, &mgr->overlays, list) {
270 struct omap_overlay_info *oi;
271 int r;
272
273 oi = overlay_infos[ovl->id];
274
275 if (oi == NULL)
276 continue;
277
278 r = dss_ovl_check(ovl, oi, dssdev);
279 if (r)
280 return r;
281 }
282
283 return 0;
284}
285static int dss_check_settings_low(struct omap_overlay_manager *mgr,
286 struct omap_dss_device *dssdev, bool applying)
287{
288 struct omap_overlay_info *oi;
289 struct omap_overlay_manager_info *mi;
290 struct omap_overlay *ovl;
291 struct omap_overlay_info *ois[MAX_DSS_OVERLAYS];
292 struct ovl_priv_data *op;
293 struct mgr_priv_data *mp;
294
295 mp = get_mgr_priv(mgr);
296
297 if (applying && mp->user_info_dirty)
298 mi = &mp->user_info;
299 else
300 mi = &mp->info;
301
302 /* collect the infos to be tested into the array */
303 list_for_each_entry(ovl, &mgr->overlays, list) {
304 op = get_ovl_priv(ovl);
305
Tomi Valkeinen82153ed2011-11-26 14:26:46 +0200306 if (!op->enabled && !op->enabling)
Tomi Valkeinen39518352011-11-17 17:35:28 +0200307 oi = NULL;
308 else if (applying && op->user_info_dirty)
309 oi = &op->user_info;
310 else
311 oi = &op->info;
312
313 ois[ovl->id] = oi;
314 }
315
316 return dss_mgr_check(mgr, dssdev, mi, ois);
317}
318
319/*
320 * check manager and overlay settings using overlay_info from data->info
321 */
322static int dss_check_settings(struct omap_overlay_manager *mgr,
323 struct omap_dss_device *dssdev)
324{
325 return dss_check_settings_low(mgr, dssdev, false);
326}
327
328/*
329 * check manager and overlay settings using overlay_info from ovl->info if
330 * dirty and from data->info otherwise
331 */
332static int dss_check_settings_apply(struct omap_overlay_manager *mgr,
333 struct omap_dss_device *dssdev)
334{
335 return dss_check_settings_low(mgr, dssdev, true);
336}
337
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200338static bool need_isr(void)
339{
340 const int num_mgrs = dss_feat_get_num_mgrs();
341 int i;
342
343 for (i = 0; i < num_mgrs; ++i) {
344 struct omap_overlay_manager *mgr;
345 struct mgr_priv_data *mp;
346 struct omap_overlay *ovl;
347
348 mgr = omap_dss_get_overlay_manager(i);
349 mp = get_mgr_priv(mgr);
350
351 if (!mp->enabled)
352 continue;
353
Tomi Valkeinen34861372011-11-18 15:43:29 +0200354 if (mgr_manual_update(mgr)) {
355 /* to catch FRAMEDONE */
356 if (mp->updating)
357 return true;
358 } else {
359 /* to catch GO bit going down */
360 if (mp->busy)
361 return true;
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200362
363 /* to write new values to registers */
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200364 if (mp->info_dirty)
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200365 return true;
Tomi Valkeinen34861372011-11-18 15:43:29 +0200366
Tomi Valkeinen9f808952011-11-25 17:26:13 +0200367 /* to set GO bit */
368 if (mp->shadow_info_dirty)
369 return true;
370
Tomi Valkeinen34861372011-11-18 15:43:29 +0200371 list_for_each_entry(ovl, &mgr->overlays, list) {
372 struct ovl_priv_data *op;
373
374 op = get_ovl_priv(ovl);
375
Tomi Valkeinen9f808952011-11-25 17:26:13 +0200376 /*
377 * NOTE: we check extra_info flags even for
378 * disabled overlays, as extra_infos need to be
379 * always written.
380 */
381
382 /* to write new values to registers */
383 if (op->extra_info_dirty)
384 return true;
385
386 /* to set GO bit */
387 if (op->shadow_extra_info_dirty)
388 return true;
389
Tomi Valkeinen34861372011-11-18 15:43:29 +0200390 if (!op->enabled)
391 continue;
392
393 /* to write new values to registers */
Tomi Valkeinen9f808952011-11-25 17:26:13 +0200394 if (op->info_dirty)
395 return true;
396
397 /* to set GO bit */
398 if (op->shadow_info_dirty)
Tomi Valkeinen34861372011-11-18 15:43:29 +0200399 return true;
400 }
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200401 }
402 }
403
404 return false;
405}
406
407static bool need_go(struct omap_overlay_manager *mgr)
408{
409 struct omap_overlay *ovl;
410 struct mgr_priv_data *mp;
411 struct ovl_priv_data *op;
412
413 mp = get_mgr_priv(mgr);
414
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200415 if (mp->shadow_info_dirty)
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200416 return true;
417
418 list_for_each_entry(ovl, &mgr->overlays, list) {
419 op = get_ovl_priv(ovl);
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200420 if (op->shadow_info_dirty || op->shadow_extra_info_dirty)
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200421 return true;
422 }
423
424 return false;
425}
426
Tomi Valkeinenf1577ce2011-11-16 14:37:48 +0200427/* returns true if an extra_info field is currently being updated */
428static bool extra_info_update_ongoing(void)
429{
430 const int num_ovls = omap_dss_get_num_overlays();
431 struct ovl_priv_data *op;
432 struct omap_overlay *ovl;
433 struct mgr_priv_data *mp;
434 int i;
Tomi Valkeinenf1577ce2011-11-16 14:37:48 +0200435
436 for (i = 0; i < num_ovls; ++i) {
437 ovl = omap_dss_get_overlay(i);
438 op = get_ovl_priv(ovl);
439
Tomi Valkeinenf1577ce2011-11-16 14:37:48 +0200440 mp = get_mgr_priv(ovl->manager);
441
442 if (!mp->enabled)
443 continue;
444
Tomi Valkeinen153b6e72011-11-25 17:35:35 +0200445 if (!mp->updating)
Tomi Valkeinenf1577ce2011-11-16 14:37:48 +0200446 continue;
447
Tomi Valkeinen153b6e72011-11-25 17:35:35 +0200448 if (op->extra_info_dirty || op->shadow_extra_info_dirty)
449 return true;
Tomi Valkeinenf1577ce2011-11-16 14:37:48 +0200450 }
451
452 return false;
453}
454
455/* wait until no extra_info updates are pending */
456static void wait_pending_extra_info_updates(void)
457{
458 bool updating;
459 unsigned long flags;
460 unsigned long t;
461
462 spin_lock_irqsave(&data_lock, flags);
463
464 updating = extra_info_update_ongoing();
465
466 if (!updating) {
467 spin_unlock_irqrestore(&data_lock, flags);
468 return;
469 }
470
471 init_completion(&extra_updated_completion);
472
473 spin_unlock_irqrestore(&data_lock, flags);
474
475 t = msecs_to_jiffies(500);
476 wait_for_completion_timeout(&extra_updated_completion, t);
477
478 updating = extra_info_update_ongoing();
479
480 WARN_ON(updating);
481}
482
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200483int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr)
484{
485 unsigned long timeout = msecs_to_jiffies(500);
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200486 struct mgr_priv_data *mp;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200487 u32 irq;
488 int r;
489 int i;
490 struct omap_dss_device *dssdev = mgr->device;
491
492 if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
493 return 0;
494
495 if (mgr_manual_update(mgr))
496 return 0;
497
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200498 irq = dispc_mgr_get_vsync_irq(mgr->id);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200499
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200500 mp = get_mgr_priv(mgr);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200501 i = 0;
502 while (1) {
503 unsigned long flags;
504 bool shadow_dirty, dirty;
505
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200506 spin_lock_irqsave(&data_lock, flags);
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200507 dirty = mp->info_dirty;
508 shadow_dirty = mp->shadow_info_dirty;
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200509 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200510
511 if (!dirty && !shadow_dirty) {
512 r = 0;
513 break;
514 }
515
516 /* 4 iterations is the worst case:
517 * 1 - initial iteration, dirty = true (between VFP and VSYNC)
518 * 2 - first VSYNC, dirty = true
519 * 3 - dirty = false, shadow_dirty = true
520 * 4 - shadow_dirty = false */
521 if (i++ == 3) {
522 DSSERR("mgr(%d)->wait_for_go() not finishing\n",
523 mgr->id);
524 r = 0;
525 break;
526 }
527
528 r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
529 if (r == -ERESTARTSYS)
530 break;
531
532 if (r) {
533 DSSERR("mgr(%d)->wait_for_go() timeout\n", mgr->id);
534 break;
535 }
536 }
537
538 return r;
539}
540
541int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl)
542{
543 unsigned long timeout = msecs_to_jiffies(500);
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200544 struct ovl_priv_data *op;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200545 struct omap_dss_device *dssdev;
546 u32 irq;
547 int r;
548 int i;
549
550 if (!ovl->manager)
551 return 0;
552
553 dssdev = ovl->manager->device;
554
555 if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
556 return 0;
557
558 if (ovl_manual_update(ovl))
559 return 0;
560
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200561 irq = dispc_mgr_get_vsync_irq(ovl->manager->id);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200562
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200563 op = get_ovl_priv(ovl);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200564 i = 0;
565 while (1) {
566 unsigned long flags;
567 bool shadow_dirty, dirty;
568
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200569 spin_lock_irqsave(&data_lock, flags);
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200570 dirty = op->info_dirty;
571 shadow_dirty = op->shadow_info_dirty;
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200572 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200573
574 if (!dirty && !shadow_dirty) {
575 r = 0;
576 break;
577 }
578
579 /* 4 iterations is the worst case:
580 * 1 - initial iteration, dirty = true (between VFP and VSYNC)
581 * 2 - first VSYNC, dirty = true
582 * 3 - dirty = false, shadow_dirty = true
583 * 4 - shadow_dirty = false */
584 if (i++ == 3) {
585 DSSERR("ovl(%d)->wait_for_go() not finishing\n",
586 ovl->id);
587 r = 0;
588 break;
589 }
590
591 r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
592 if (r == -ERESTARTSYS)
593 break;
594
595 if (r) {
596 DSSERR("ovl(%d)->wait_for_go() timeout\n", ovl->id);
597 break;
598 }
599 }
600
601 return r;
602}
603
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200604static void dss_ovl_write_regs(struct omap_overlay *ovl)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200605{
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200606 struct ovl_priv_data *op = get_ovl_priv(ovl);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200607 struct omap_overlay_info *oi;
608 bool ilace, replication;
Tomi Valkeinen34861372011-11-18 15:43:29 +0200609 struct mgr_priv_data *mp;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200610 int r;
611
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200612 DSSDBGF("%d", ovl->id);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200613
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200614 if (!op->enabled || !op->info_dirty)
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200615 return;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200616
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200617 oi = &op->info;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200618
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200619 replication = dss_use_replication(ovl->manager->device, oi->color_mode);
620
621 ilace = ovl->manager->device->type == OMAP_DISPLAY_TYPE_VENC;
622
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200623 r = dispc_ovl_setup(ovl->id, oi, ilace, replication);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200624 if (r) {
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200625 /*
626 * We can't do much here, as this function can be called from
627 * vsync interrupt.
628 */
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200629 DSSERR("dispc_ovl_setup failed for ovl %d\n", ovl->id);
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200630
631 /* This will leave fifo configurations in a nonoptimal state */
632 op->enabled = false;
633 dispc_ovl_enable(ovl->id, false);
634 return;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200635 }
636
Tomi Valkeinen34861372011-11-18 15:43:29 +0200637 mp = get_mgr_priv(ovl->manager);
638
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200639 op->info_dirty = false;
Tomi Valkeinen34861372011-11-18 15:43:29 +0200640 if (mp->updating)
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200641 op->shadow_info_dirty = true;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200642}
643
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200644static void dss_ovl_write_regs_extra(struct omap_overlay *ovl)
645{
646 struct ovl_priv_data *op = get_ovl_priv(ovl);
Tomi Valkeinen34861372011-11-18 15:43:29 +0200647 struct mgr_priv_data *mp;
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200648
649 DSSDBGF("%d", ovl->id);
650
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200651 if (!op->extra_info_dirty)
652 return;
653
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200654 /* note: write also when op->enabled == false, so that the ovl gets
655 * disabled */
656
657 dispc_ovl_enable(ovl->id, op->enabled);
Tomi Valkeinen5d5a97a2011-11-16 14:17:54 +0200658 dispc_ovl_set_channel_out(ovl->id, op->channel);
Tomi Valkeinen6dc802e2011-11-16 14:28:12 +0200659 dispc_ovl_set_fifo_threshold(ovl->id, op->fifo_low, op->fifo_high);
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200660
Tomi Valkeinen34861372011-11-18 15:43:29 +0200661 mp = get_mgr_priv(ovl->manager);
662
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200663 op->extra_info_dirty = false;
Tomi Valkeinen34861372011-11-18 15:43:29 +0200664 if (mp->updating)
665 op->shadow_extra_info_dirty = true;
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200666}
667
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200668static void dss_mgr_write_regs(struct omap_overlay_manager *mgr)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200669{
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200670 struct mgr_priv_data *mp = get_mgr_priv(mgr);
671 struct omap_overlay *ovl;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200672
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200673 DSSDBGF("%d", mgr->id);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200674
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200675 if (!mp->enabled)
676 return;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200677
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200678 WARN_ON(mp->busy);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200679
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200680 /* Commit overlay settings */
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200681 list_for_each_entry(ovl, &mgr->overlays, list) {
682 dss_ovl_write_regs(ovl);
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200683 dss_ovl_write_regs_extra(ovl);
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200684 }
685
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200686 if (mp->info_dirty) {
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200687 dispc_mgr_setup(mgr->id, &mp->info);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200688
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200689 mp->info_dirty = false;
Tomi Valkeinen34861372011-11-18 15:43:29 +0200690 if (mp->updating)
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200691 mp->shadow_info_dirty = true;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200692 }
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200693}
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200694
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200695static void dss_write_regs(void)
696{
697 const int num_mgrs = omap_dss_get_num_overlay_managers();
698 int i;
699
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200700 for (i = 0; i < num_mgrs; ++i) {
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200701 struct omap_overlay_manager *mgr;
702 struct mgr_priv_data *mp;
Tomi Valkeinen39518352011-11-17 17:35:28 +0200703 int r;
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200704
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200705 mgr = omap_dss_get_overlay_manager(i);
706 mp = get_mgr_priv(mgr);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200707
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200708 if (!mp->enabled || mgr_manual_update(mgr) || mp->busy)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200709 continue;
710
Tomi Valkeinen39518352011-11-17 17:35:28 +0200711 r = dss_check_settings(mgr, mgr->device);
712 if (r) {
713 DSSERR("cannot write registers for manager %s: "
714 "illegal configuration\n", mgr->name);
715 continue;
716 }
717
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200718 dss_mgr_write_regs(mgr);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200719 }
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200720}
721
Tomi Valkeinen3ab15b22011-11-25 17:32:20 +0200722static void dss_set_go_bits(void)
723{
724 const int num_mgrs = omap_dss_get_num_overlay_managers();
725 int i;
726
727 for (i = 0; i < num_mgrs; ++i) {
728 struct omap_overlay_manager *mgr;
729 struct mgr_priv_data *mp;
730
731 mgr = omap_dss_get_overlay_manager(i);
732 mp = get_mgr_priv(mgr);
733
734 if (!mp->enabled || mgr_manual_update(mgr) || mp->busy)
735 continue;
736
737 if (!need_go(mgr))
738 continue;
739
740 mp->busy = true;
741
742 if (!dss_data.irq_enabled && need_isr())
743 dss_register_vsync_isr();
744
745 dispc_mgr_go(mgr->id);
746 }
747
748}
749
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200750void dss_mgr_start_update(struct omap_overlay_manager *mgr)
751{
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200752 struct mgr_priv_data *mp = get_mgr_priv(mgr);
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200753 unsigned long flags;
Tomi Valkeinen39518352011-11-17 17:35:28 +0200754 int r;
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200755
756 spin_lock_irqsave(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200757
Tomi Valkeinen34861372011-11-18 15:43:29 +0200758 WARN_ON(mp->updating);
759
Tomi Valkeinen39518352011-11-17 17:35:28 +0200760 r = dss_check_settings(mgr, mgr->device);
761 if (r) {
762 DSSERR("cannot start manual update: illegal configuration\n");
763 spin_unlock_irqrestore(&data_lock, flags);
764 return;
765 }
766
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200767 dss_mgr_write_regs(mgr);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200768
Tomi Valkeinen34861372011-11-18 15:43:29 +0200769 mp->updating = true;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200770
Tomi Valkeinen34861372011-11-18 15:43:29 +0200771 if (!dss_data.irq_enabled && need_isr())
772 dss_register_vsync_isr();
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200773
Tomi Valkeinen7797c6d2011-11-04 10:22:46 +0200774 dispc_mgr_enable(mgr->id, true);
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200775
776 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200777}
778
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200779static void dss_apply_irq_handler(void *data, u32 mask);
780
781static void dss_register_vsync_isr(void)
782{
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200783 const int num_mgrs = dss_feat_get_num_mgrs();
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200784 u32 mask;
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200785 int r, i;
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200786
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200787 mask = 0;
788 for (i = 0; i < num_mgrs; ++i)
789 mask |= dispc_mgr_get_vsync_irq(i);
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200790
Tomi Valkeinen34861372011-11-18 15:43:29 +0200791 for (i = 0; i < num_mgrs; ++i)
792 mask |= dispc_mgr_get_framedone_irq(i);
793
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200794 r = omap_dispc_register_isr(dss_apply_irq_handler, NULL, mask);
795 WARN_ON(r);
796
Tomi Valkeinend09c7aa2011-11-15 12:04:43 +0200797 dss_data.irq_enabled = true;
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200798}
799
800static void dss_unregister_vsync_isr(void)
801{
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200802 const int num_mgrs = dss_feat_get_num_mgrs();
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200803 u32 mask;
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200804 int r, i;
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200805
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200806 mask = 0;
807 for (i = 0; i < num_mgrs; ++i)
808 mask |= dispc_mgr_get_vsync_irq(i);
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200809
Tomi Valkeinen34861372011-11-18 15:43:29 +0200810 for (i = 0; i < num_mgrs; ++i)
811 mask |= dispc_mgr_get_framedone_irq(i);
812
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200813 r = omap_dispc_unregister_isr(dss_apply_irq_handler, NULL, mask);
814 WARN_ON(r);
815
Tomi Valkeinend09c7aa2011-11-15 12:04:43 +0200816 dss_data.irq_enabled = false;
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200817}
818
Tomi Valkeinen76098932011-11-16 12:03:22 +0200819static void mgr_clear_shadow_dirty(struct omap_overlay_manager *mgr)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200820{
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200821 struct omap_overlay *ovl;
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200822 struct mgr_priv_data *mp;
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200823 struct ovl_priv_data *op;
Tomi Valkeinen76098932011-11-16 12:03:22 +0200824
825 mp = get_mgr_priv(mgr);
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200826 mp->shadow_info_dirty = false;
Tomi Valkeinen76098932011-11-16 12:03:22 +0200827
828 list_for_each_entry(ovl, &mgr->overlays, list) {
829 op = get_ovl_priv(ovl);
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200830 op->shadow_info_dirty = false;
Tomi Valkeinen76098932011-11-16 12:03:22 +0200831 op->shadow_extra_info_dirty = false;
832 }
833}
834
835static void dss_apply_irq_handler(void *data, u32 mask)
836{
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200837 const int num_mgrs = dss_feat_get_num_mgrs();
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200838 int i;
Tomi Valkeinenf1577ce2011-11-16 14:37:48 +0200839 bool extra_updating;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200840
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200841 spin_lock(&data_lock);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200842
Tomi Valkeinen76098932011-11-16 12:03:22 +0200843 /* clear busy, updating flags, shadow_dirty flags */
Tomi Valkeinen43a972d2011-11-15 15:04:25 +0200844 for (i = 0; i < num_mgrs; i++) {
Tomi Valkeinen76098932011-11-16 12:03:22 +0200845 struct omap_overlay_manager *mgr;
846 struct mgr_priv_data *mp;
Tomi Valkeinen5b214172011-11-25 17:27:45 +0200847 bool was_updating;
Tomi Valkeinen76098932011-11-16 12:03:22 +0200848
Tomi Valkeinen43a972d2011-11-15 15:04:25 +0200849 mgr = omap_dss_get_overlay_manager(i);
850 mp = get_mgr_priv(mgr);
851
Tomi Valkeinen76098932011-11-16 12:03:22 +0200852 if (!mp->enabled)
Tomi Valkeinen43a972d2011-11-15 15:04:25 +0200853 continue;
854
Tomi Valkeinen5b214172011-11-25 17:27:45 +0200855 was_updating = mp->updating;
Tomi Valkeinen76098932011-11-16 12:03:22 +0200856 mp->updating = dispc_mgr_is_enabled(i);
Tomi Valkeinen43a972d2011-11-15 15:04:25 +0200857
Tomi Valkeinen76098932011-11-16 12:03:22 +0200858 if (!mgr_manual_update(mgr)) {
Tomi Valkeinen5b214172011-11-25 17:27:45 +0200859 bool was_busy = mp->busy;
Tomi Valkeinen76098932011-11-16 12:03:22 +0200860 mp->busy = dispc_mgr_go_busy(i);
861
Tomi Valkeinen5b214172011-11-25 17:27:45 +0200862 if (was_busy && !mp->busy)
Tomi Valkeinen76098932011-11-16 12:03:22 +0200863 mgr_clear_shadow_dirty(mgr);
864 } else {
Tomi Valkeinen5b214172011-11-25 17:27:45 +0200865 if (was_updating && !mp->updating)
Tomi Valkeinen76098932011-11-16 12:03:22 +0200866 mgr_clear_shadow_dirty(mgr);
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200867 }
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200868 }
869
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200870 dss_write_regs();
Tomi Valkeinen3ab15b22011-11-25 17:32:20 +0200871 dss_set_go_bits();
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200872
Tomi Valkeinenf1577ce2011-11-16 14:37:48 +0200873 extra_updating = extra_info_update_ongoing();
874 if (!extra_updating)
875 complete_all(&extra_updated_completion);
876
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200877 if (!need_isr())
878 dss_unregister_vsync_isr();
Tomi Valkeinen43a972d2011-11-15 15:04:25 +0200879
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200880 spin_unlock(&data_lock);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200881}
882
Tomi Valkeinen5738b632011-11-15 13:37:33 +0200883static void omap_dss_mgr_apply_ovl(struct omap_overlay *ovl)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200884{
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200885 struct ovl_priv_data *op;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200886
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200887 op = get_ovl_priv(ovl);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200888
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +0200889 if (!op->user_info_dirty)
Tomi Valkeinen5738b632011-11-15 13:37:33 +0200890 return;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200891
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +0200892 op->user_info_dirty = false;
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200893 op->info_dirty = true;
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +0200894 op->info = op->user_info;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200895}
896
897static void omap_dss_mgr_apply_mgr(struct omap_overlay_manager *mgr)
898{
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200899 struct mgr_priv_data *mp;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200900
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200901 mp = get_mgr_priv(mgr);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200902
Tomi Valkeinen388c4c62011-11-16 13:58:07 +0200903 if (!mp->user_info_dirty)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200904 return;
905
Tomi Valkeinen388c4c62011-11-16 13:58:07 +0200906 mp->user_info_dirty = false;
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200907 mp->info_dirty = true;
Tomi Valkeinen388c4c62011-11-16 13:58:07 +0200908 mp->info = mp->user_info;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200909}
910
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200911int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
912{
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200913 unsigned long flags;
Tomi Valkeinen07e327c2011-11-05 10:59:59 +0200914 struct omap_overlay *ovl;
Tomi Valkeinen39518352011-11-17 17:35:28 +0200915 int r;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200916
917 DSSDBG("omap_dss_mgr_apply(%s)\n", mgr->name);
918
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200919 spin_lock_irqsave(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200920
Tomi Valkeinen39518352011-11-17 17:35:28 +0200921 r = dss_check_settings_apply(mgr, mgr->device);
922 if (r) {
923 spin_unlock_irqrestore(&data_lock, flags);
924 DSSERR("failed to apply settings: illegal configuration.\n");
925 return r;
926 }
927
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200928 /* Configure overlays */
Tomi Valkeinen07e327c2011-11-05 10:59:59 +0200929 list_for_each_entry(ovl, &mgr->overlays, list)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200930 omap_dss_mgr_apply_ovl(ovl);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200931
932 /* Configure manager */
933 omap_dss_mgr_apply_mgr(mgr);
934
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200935 dss_write_regs();
Tomi Valkeinen3ab15b22011-11-25 17:32:20 +0200936 dss_set_go_bits();
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200937
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200938 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200939
Tomi Valkeinene70f98a2011-11-16 16:53:44 +0200940 return 0;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200941}
942
Tomi Valkeinen841c09c2011-11-16 15:25:53 +0200943static void dss_apply_ovl_enable(struct omap_overlay *ovl, bool enable)
944{
945 struct ovl_priv_data *op;
946
947 op = get_ovl_priv(ovl);
948
949 if (op->enabled == enable)
950 return;
951
952 op->enabled = enable;
953 op->extra_info_dirty = true;
954}
955
Tomi Valkeinen04576d42011-11-26 14:39:16 +0200956static void dss_apply_ovl_fifo_thresholds(struct omap_overlay *ovl,
957 u32 fifo_low, u32 fifo_high)
958{
959 struct ovl_priv_data *op = get_ovl_priv(ovl);
960
961 if (op->fifo_low == fifo_low && op->fifo_high == fifo_high)
962 return;
963
964 op->fifo_low = fifo_low;
965 op->fifo_high = fifo_high;
966 op->extra_info_dirty = true;
967}
968
Tomi Valkeinen6dc802e2011-11-16 14:28:12 +0200969static void dss_ovl_setup_fifo(struct omap_overlay *ovl)
970{
971 struct ovl_priv_data *op = get_ovl_priv(ovl);
972 struct omap_dss_device *dssdev;
973 u32 size, burst_size;
974 u32 fifo_low, fifo_high;
975
Tomi Valkeinen75ae1182011-11-26 14:36:19 +0200976 if (!op->enabled && !op->enabling)
977 return;
978
Tomi Valkeinen6dc802e2011-11-16 14:28:12 +0200979 dssdev = ovl->manager->device;
980
981 size = dispc_ovl_get_fifo_size(ovl->id);
982
983 burst_size = dispc_ovl_get_burst_size(ovl->id);
984
985 switch (dssdev->type) {
986 case OMAP_DISPLAY_TYPE_DPI:
987 case OMAP_DISPLAY_TYPE_DBI:
988 case OMAP_DISPLAY_TYPE_SDI:
989 case OMAP_DISPLAY_TYPE_VENC:
990 case OMAP_DISPLAY_TYPE_HDMI:
991 default_get_overlay_fifo_thresholds(ovl->id, size,
992 burst_size, &fifo_low, &fifo_high);
993 break;
994#ifdef CONFIG_OMAP2_DSS_DSI
995 case OMAP_DISPLAY_TYPE_DSI:
996 dsi_get_overlay_fifo_thresholds(ovl->id, size,
997 burst_size, &fifo_low, &fifo_high);
998 break;
999#endif
1000 default:
1001 BUG();
1002 }
1003
Tomi Valkeinen04576d42011-11-26 14:39:16 +02001004 dss_apply_ovl_fifo_thresholds(ovl, fifo_low, fifo_high);
Tomi Valkeinen6dc802e2011-11-16 14:28:12 +02001005}
1006
1007static void dss_mgr_setup_fifos(struct omap_overlay_manager *mgr)
1008{
1009 struct omap_overlay *ovl;
Tomi Valkeinen6dc802e2011-11-16 14:28:12 +02001010 struct mgr_priv_data *mp;
1011
1012 mp = get_mgr_priv(mgr);
1013
1014 if (!mp->enabled)
1015 return;
1016
Tomi Valkeinen75ae1182011-11-26 14:36:19 +02001017 list_for_each_entry(ovl, &mgr->overlays, list)
Tomi Valkeinen6dc802e2011-11-16 14:28:12 +02001018 dss_ovl_setup_fifo(ovl);
Tomi Valkeinen75ae1182011-11-26 14:36:19 +02001019}
1020
1021static void dss_setup_fifos(void)
1022{
1023 const int num_mgrs = omap_dss_get_num_overlay_managers();
1024 struct omap_overlay_manager *mgr;
1025 int i;
1026
1027 for (i = 0; i < num_mgrs; ++i) {
1028 mgr = omap_dss_get_overlay_manager(i);
1029 dss_mgr_setup_fifos(mgr);
Tomi Valkeinen6dc802e2011-11-16 14:28:12 +02001030 }
1031}
1032
Tomi Valkeinen2a4ee7e2011-11-21 13:34:48 +02001033int dss_mgr_enable(struct omap_overlay_manager *mgr)
Tomi Valkeinen7797c6d2011-11-04 10:22:46 +02001034{
Tomi Valkeinenbf213522011-11-15 14:43:53 +02001035 struct mgr_priv_data *mp = get_mgr_priv(mgr);
1036 unsigned long flags;
Tomi Valkeinen39518352011-11-17 17:35:28 +02001037 int r;
Tomi Valkeinenbf213522011-11-15 14:43:53 +02001038
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001039 mutex_lock(&apply_lock);
1040
Tomi Valkeinene4f7ad72011-11-16 16:01:33 +02001041 if (mp->enabled)
1042 goto out;
1043
Tomi Valkeinenbf213522011-11-15 14:43:53 +02001044 spin_lock_irqsave(&data_lock, flags);
1045
1046 mp->enabled = true;
Tomi Valkeinena6b24f82011-11-26 14:29:39 +02001047
Tomi Valkeinen39518352011-11-17 17:35:28 +02001048 r = dss_check_settings(mgr, mgr->device);
Tomi Valkeinen39518352011-11-17 17:35:28 +02001049 if (r) {
1050 DSSERR("failed to enable manager %d: check_settings failed\n",
1051 mgr->id);
Tomi Valkeinen2a4ee7e2011-11-21 13:34:48 +02001052 goto err;
Tomi Valkeinen39518352011-11-17 17:35:28 +02001053 }
1054
Tomi Valkeinen75ae1182011-11-26 14:36:19 +02001055 dss_setup_fifos();
Tomi Valkeinen6dc802e2011-11-16 14:28:12 +02001056
Tomi Valkeinen75c94962011-11-15 18:25:23 +02001057 dss_write_regs();
Tomi Valkeinen3ab15b22011-11-25 17:32:20 +02001058 dss_set_go_bits();
Tomi Valkeinen75c94962011-11-15 18:25:23 +02001059
Tomi Valkeinen34861372011-11-18 15:43:29 +02001060 if (!mgr_manual_update(mgr))
1061 mp->updating = true;
1062
Tomi Valkeinenbf213522011-11-15 14:43:53 +02001063 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001064
Tomi Valkeinen75c94962011-11-15 18:25:23 +02001065 if (!mgr_manual_update(mgr))
1066 dispc_mgr_enable(mgr->id, true);
1067
Tomi Valkeinene4f7ad72011-11-16 16:01:33 +02001068out:
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001069 mutex_unlock(&apply_lock);
Tomi Valkeinen2a4ee7e2011-11-21 13:34:48 +02001070
1071 return 0;
1072
1073err:
Tomi Valkeinena6b24f82011-11-26 14:29:39 +02001074 mp->enabled = false;
Tomi Valkeinen2a4ee7e2011-11-21 13:34:48 +02001075 spin_unlock_irqrestore(&data_lock, flags);
1076 mutex_unlock(&apply_lock);
1077 return r;
Tomi Valkeinen7797c6d2011-11-04 10:22:46 +02001078}
1079
1080void dss_mgr_disable(struct omap_overlay_manager *mgr)
1081{
Tomi Valkeinenbf213522011-11-15 14:43:53 +02001082 struct mgr_priv_data *mp = get_mgr_priv(mgr);
1083 unsigned long flags;
1084
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001085 mutex_lock(&apply_lock);
1086
Tomi Valkeinene4f7ad72011-11-16 16:01:33 +02001087 if (!mp->enabled)
1088 goto out;
1089
Tomi Valkeinen9a147a62011-11-09 15:30:11 +02001090 if (!mgr_manual_update(mgr))
1091 dispc_mgr_enable(mgr->id, false);
Tomi Valkeinenbf213522011-11-15 14:43:53 +02001092
1093 spin_lock_irqsave(&data_lock, flags);
1094
Tomi Valkeinen34861372011-11-18 15:43:29 +02001095 mp->updating = false;
Tomi Valkeinenbf213522011-11-15 14:43:53 +02001096 mp->enabled = false;
1097
1098 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001099
Tomi Valkeinene4f7ad72011-11-16 16:01:33 +02001100out:
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001101 mutex_unlock(&apply_lock);
Tomi Valkeinen7797c6d2011-11-04 10:22:46 +02001102}
1103
Tomi Valkeinenf17d04f2011-11-17 14:31:09 +02001104static int dss_mgr_simple_check(struct omap_overlay_manager *mgr,
1105 const struct omap_overlay_manager_info *info)
1106{
1107 if (dss_has_feature(FEAT_ALPHA_FIXED_ZORDER)) {
1108 /*
1109 * OMAP3 supports only graphics source transparency color key
1110 * and alpha blending simultaneously. See TRM 15.4.2.4.2.2
1111 * Alpha Mode.
1112 */
1113 if (info->partial_alpha_enabled && info->trans_enabled
1114 && info->trans_key_type != OMAP_DSS_COLOR_KEY_GFX_DST) {
1115 DSSERR("check_manager: illegal transparency key\n");
1116 return -EINVAL;
1117 }
1118 }
1119
1120 return 0;
1121}
1122
Tomi Valkeineneb70d732011-11-15 12:15:18 +02001123int dss_mgr_set_info(struct omap_overlay_manager *mgr,
1124 struct omap_overlay_manager_info *info)
1125{
Tomi Valkeinen388c4c62011-11-16 13:58:07 +02001126 struct mgr_priv_data *mp = get_mgr_priv(mgr);
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +02001127 unsigned long flags;
Tomi Valkeinenf17d04f2011-11-17 14:31:09 +02001128 int r;
1129
1130 r = dss_mgr_simple_check(mgr, info);
1131 if (r)
1132 return r;
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +02001133
1134 spin_lock_irqsave(&data_lock, flags);
1135
Tomi Valkeinen388c4c62011-11-16 13:58:07 +02001136 mp->user_info = *info;
1137 mp->user_info_dirty = true;
Tomi Valkeineneb70d732011-11-15 12:15:18 +02001138
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +02001139 spin_unlock_irqrestore(&data_lock, flags);
1140
Tomi Valkeineneb70d732011-11-15 12:15:18 +02001141 return 0;
1142}
1143
1144void dss_mgr_get_info(struct omap_overlay_manager *mgr,
1145 struct omap_overlay_manager_info *info)
1146{
Tomi Valkeinen388c4c62011-11-16 13:58:07 +02001147 struct mgr_priv_data *mp = get_mgr_priv(mgr);
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +02001148 unsigned long flags;
1149
1150 spin_lock_irqsave(&data_lock, flags);
1151
Tomi Valkeinen388c4c62011-11-16 13:58:07 +02001152 *info = mp->user_info;
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +02001153
1154 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeineneb70d732011-11-15 12:15:18 +02001155}
1156
1157int dss_mgr_set_device(struct omap_overlay_manager *mgr,
1158 struct omap_dss_device *dssdev)
1159{
1160 int r;
Tomi Valkeineneb70d732011-11-15 12:15:18 +02001161
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001162 mutex_lock(&apply_lock);
1163
Tomi Valkeineneb70d732011-11-15 12:15:18 +02001164 if (dssdev->manager) {
1165 DSSERR("display '%s' already has a manager '%s'\n",
1166 dssdev->name, dssdev->manager->name);
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001167 r = -EINVAL;
1168 goto err;
Tomi Valkeineneb70d732011-11-15 12:15:18 +02001169 }
1170
1171 if ((mgr->supported_displays & dssdev->type) == 0) {
1172 DSSERR("display '%s' does not support manager '%s'\n",
1173 dssdev->name, mgr->name);
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001174 r = -EINVAL;
1175 goto err;
Tomi Valkeineneb70d732011-11-15 12:15:18 +02001176 }
1177
Tomi Valkeineneb70d732011-11-15 12:15:18 +02001178 dssdev->manager = mgr;
1179 mgr->device = dssdev;
Tomi Valkeineneb70d732011-11-15 12:15:18 +02001180
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001181 mutex_unlock(&apply_lock);
1182
Tomi Valkeineneb70d732011-11-15 12:15:18 +02001183 return 0;
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001184err:
1185 mutex_unlock(&apply_lock);
1186 return r;
Tomi Valkeineneb70d732011-11-15 12:15:18 +02001187}
1188
1189int dss_mgr_unset_device(struct omap_overlay_manager *mgr)
1190{
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001191 int r;
1192
1193 mutex_lock(&apply_lock);
1194
Tomi Valkeineneb70d732011-11-15 12:15:18 +02001195 if (!mgr->device) {
1196 DSSERR("failed to unset display, display not set.\n");
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001197 r = -EINVAL;
1198 goto err;
Tomi Valkeineneb70d732011-11-15 12:15:18 +02001199 }
1200
1201 /*
1202 * Don't allow currently enabled displays to have the overlay manager
1203 * pulled out from underneath them
1204 */
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001205 if (mgr->device->state != OMAP_DSS_DISPLAY_DISABLED) {
1206 r = -EINVAL;
1207 goto err;
1208 }
Tomi Valkeineneb70d732011-11-15 12:15:18 +02001209
1210 mgr->device->manager = NULL;
1211 mgr->device = NULL;
Tomi Valkeineneb70d732011-11-15 12:15:18 +02001212
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001213 mutex_unlock(&apply_lock);
1214
Tomi Valkeineneb70d732011-11-15 12:15:18 +02001215 return 0;
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001216err:
1217 mutex_unlock(&apply_lock);
1218 return r;
Tomi Valkeineneb70d732011-11-15 12:15:18 +02001219}
1220
1221
Tomi Valkeinenfcc764d2011-11-17 14:26:48 +02001222static int dss_ovl_simple_check(struct omap_overlay *ovl,
1223 const struct omap_overlay_info *info)
1224{
1225 if (info->paddr == 0) {
1226 DSSERR("check_overlay: paddr cannot be 0\n");
1227 return -EINVAL;
1228 }
1229
1230 if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0) {
1231 if (info->out_width != 0 && info->width != info->out_width) {
1232 DSSERR("check_overlay: overlay %d doesn't support "
1233 "scaling\n", ovl->id);
1234 return -EINVAL;
1235 }
1236
1237 if (info->out_height != 0 && info->height != info->out_height) {
1238 DSSERR("check_overlay: overlay %d doesn't support "
1239 "scaling\n", ovl->id);
1240 return -EINVAL;
1241 }
1242 }
1243
1244 if ((ovl->supported_modes & info->color_mode) == 0) {
1245 DSSERR("check_overlay: overlay %d doesn't support mode %d\n",
1246 ovl->id, info->color_mode);
1247 return -EINVAL;
1248 }
1249
1250 if (info->zorder >= omap_dss_get_num_overlays()) {
1251 DSSERR("check_overlay: zorder %d too high\n", info->zorder);
1252 return -EINVAL;
1253 }
1254
1255 return 0;
1256}
Tomi Valkeineneb70d732011-11-15 12:15:18 +02001257
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001258int dss_ovl_set_info(struct omap_overlay *ovl,
1259 struct omap_overlay_info *info)
1260{
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +02001261 struct ovl_priv_data *op = get_ovl_priv(ovl);
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +02001262 unsigned long flags;
Tomi Valkeinenfcc764d2011-11-17 14:26:48 +02001263 int r;
1264
1265 r = dss_ovl_simple_check(ovl, info);
1266 if (r)
1267 return r;
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +02001268
1269 spin_lock_irqsave(&data_lock, flags);
1270
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +02001271 op->user_info = *info;
1272 op->user_info_dirty = true;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001273
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +02001274 spin_unlock_irqrestore(&data_lock, flags);
1275
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001276 return 0;
1277}
1278
1279void dss_ovl_get_info(struct omap_overlay *ovl,
1280 struct omap_overlay_info *info)
1281{
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +02001282 struct ovl_priv_data *op = get_ovl_priv(ovl);
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +02001283 unsigned long flags;
1284
1285 spin_lock_irqsave(&data_lock, flags);
1286
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +02001287 *info = op->user_info;
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +02001288
1289 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001290}
1291
1292int dss_ovl_set_manager(struct omap_overlay *ovl,
1293 struct omap_overlay_manager *mgr)
1294{
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001295 struct ovl_priv_data *op = get_ovl_priv(ovl);
1296 unsigned long flags;
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001297 int r;
1298
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001299 if (!mgr)
1300 return -EINVAL;
1301
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001302 mutex_lock(&apply_lock);
1303
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001304 if (ovl->manager) {
1305 DSSERR("overlay '%s' already has a manager '%s'\n",
1306 ovl->name, ovl->manager->name);
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001307 r = -EINVAL;
1308 goto err;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001309 }
1310
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001311 spin_lock_irqsave(&data_lock, flags);
1312
1313 if (op->enabled) {
1314 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001315 DSSERR("overlay has to be disabled to change the manager\n");
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001316 r = -EINVAL;
1317 goto err;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001318 }
1319
Tomi Valkeinen5d5a97a2011-11-16 14:17:54 +02001320 op->channel = mgr->id;
1321 op->extra_info_dirty = true;
1322
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001323 ovl->manager = mgr;
1324 list_add_tail(&ovl->list, &mgr->overlays);
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001325
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001326 spin_unlock_irqrestore(&data_lock, flags);
1327
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001328 /* XXX: When there is an overlay on a DSI manual update display, and
1329 * the overlay is first disabled, then moved to tv, and enabled, we
1330 * seem to get SYNC_LOST_DIGIT error.
1331 *
1332 * Waiting doesn't seem to help, but updating the manual update display
1333 * after disabling the overlay seems to fix this. This hints that the
1334 * overlay is perhaps somehow tied to the LCD output until the output
1335 * is updated.
1336 *
1337 * Userspace workaround for this is to update the LCD after disabling
1338 * the overlay, but before moving the overlay to TV.
1339 */
1340
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001341 mutex_unlock(&apply_lock);
1342
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001343 return 0;
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001344err:
1345 mutex_unlock(&apply_lock);
1346 return r;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001347}
1348
1349int dss_ovl_unset_manager(struct omap_overlay *ovl)
1350{
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001351 struct ovl_priv_data *op = get_ovl_priv(ovl);
1352 unsigned long flags;
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001353 int r;
1354
1355 mutex_lock(&apply_lock);
1356
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001357 if (!ovl->manager) {
1358 DSSERR("failed to detach overlay: manager not set\n");
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001359 r = -EINVAL;
1360 goto err;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001361 }
1362
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001363 spin_lock_irqsave(&data_lock, flags);
1364
1365 if (op->enabled) {
1366 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001367 DSSERR("overlay has to be disabled to unset the manager\n");
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001368 r = -EINVAL;
1369 goto err;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001370 }
1371
Tomi Valkeinen5d5a97a2011-11-16 14:17:54 +02001372 op->channel = -1;
1373
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001374 ovl->manager = NULL;
1375 list_del(&ovl->list);
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001376
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001377 spin_unlock_irqrestore(&data_lock, flags);
1378
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001379 mutex_unlock(&apply_lock);
1380
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001381 return 0;
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001382err:
1383 mutex_unlock(&apply_lock);
1384 return r;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001385}
1386
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001387bool dss_ovl_is_enabled(struct omap_overlay *ovl)
1388{
1389 struct ovl_priv_data *op = get_ovl_priv(ovl);
1390 unsigned long flags;
1391 bool e;
1392
1393 spin_lock_irqsave(&data_lock, flags);
1394
1395 e = op->enabled;
1396
1397 spin_unlock_irqrestore(&data_lock, flags);
1398
1399 return e;
1400}
1401
1402int dss_ovl_enable(struct omap_overlay *ovl)
1403{
1404 struct ovl_priv_data *op = get_ovl_priv(ovl);
1405 unsigned long flags;
1406 int r;
1407
1408 mutex_lock(&apply_lock);
1409
Tomi Valkeinene4f7ad72011-11-16 16:01:33 +02001410 if (op->enabled) {
1411 r = 0;
Tomi Valkeinen39518352011-11-17 17:35:28 +02001412 goto err1;
Tomi Valkeinene4f7ad72011-11-16 16:01:33 +02001413 }
1414
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001415 if (ovl->manager == NULL || ovl->manager->device == NULL) {
1416 r = -EINVAL;
Tomi Valkeinen39518352011-11-17 17:35:28 +02001417 goto err1;
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001418 }
1419
1420 spin_lock_irqsave(&data_lock, flags);
1421
Tomi Valkeinen82153ed2011-11-26 14:26:46 +02001422 op->enabling = true;
1423
Tomi Valkeinen39518352011-11-17 17:35:28 +02001424 r = dss_check_settings(ovl->manager, ovl->manager->device);
Tomi Valkeinen39518352011-11-17 17:35:28 +02001425 if (r) {
1426 DSSERR("failed to enable overlay %d: check_settings failed\n",
1427 ovl->id);
1428 goto err2;
1429 }
1430
Tomi Valkeinen75ae1182011-11-26 14:36:19 +02001431 dss_setup_fifos();
Tomi Valkeinen6dc802e2011-11-16 14:28:12 +02001432
Tomi Valkeinen82153ed2011-11-26 14:26:46 +02001433 op->enabling = false;
1434 dss_apply_ovl_enable(ovl, true);
1435
Tomi Valkeinen75c94962011-11-15 18:25:23 +02001436 dss_write_regs();
Tomi Valkeinen3ab15b22011-11-25 17:32:20 +02001437 dss_set_go_bits();
Tomi Valkeinen75c94962011-11-15 18:25:23 +02001438
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001439 spin_unlock_irqrestore(&data_lock, flags);
1440
1441 mutex_unlock(&apply_lock);
1442
1443 return 0;
Tomi Valkeinen39518352011-11-17 17:35:28 +02001444err2:
Tomi Valkeinen82153ed2011-11-26 14:26:46 +02001445 op->enabling = false;
Tomi Valkeinen39518352011-11-17 17:35:28 +02001446 spin_unlock_irqrestore(&data_lock, flags);
1447err1:
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001448 mutex_unlock(&apply_lock);
1449 return r;
1450}
1451
1452int dss_ovl_disable(struct omap_overlay *ovl)
1453{
1454 struct ovl_priv_data *op = get_ovl_priv(ovl);
1455 unsigned long flags;
1456 int r;
1457
1458 mutex_lock(&apply_lock);
1459
Tomi Valkeinene4f7ad72011-11-16 16:01:33 +02001460 if (!op->enabled) {
1461 r = 0;
1462 goto err;
1463 }
1464
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001465 if (ovl->manager == NULL || ovl->manager->device == NULL) {
1466 r = -EINVAL;
1467 goto err;
1468 }
1469
1470 spin_lock_irqsave(&data_lock, flags);
1471
Tomi Valkeinen841c09c2011-11-16 15:25:53 +02001472 dss_apply_ovl_enable(ovl, false);
Tomi Valkeinen75c94962011-11-15 18:25:23 +02001473 dss_write_regs();
Tomi Valkeinen3ab15b22011-11-25 17:32:20 +02001474 dss_set_go_bits();
Tomi Valkeinen75c94962011-11-15 18:25:23 +02001475
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001476 spin_unlock_irqrestore(&data_lock, flags);
1477
1478 mutex_unlock(&apply_lock);
1479
1480 return 0;
1481
1482err:
1483 mutex_unlock(&apply_lock);
1484 return r;
1485}
1486