blob: c38c015d60e28d4c060b16d3399acdf1542f73d0 [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 Valkeinen6dc802e2011-11-16 14:28:12 +0200956static void dss_ovl_setup_fifo(struct omap_overlay *ovl)
957{
958 struct ovl_priv_data *op = get_ovl_priv(ovl);
959 struct omap_dss_device *dssdev;
960 u32 size, burst_size;
961 u32 fifo_low, fifo_high;
962
963 dssdev = ovl->manager->device;
964
965 size = dispc_ovl_get_fifo_size(ovl->id);
966
967 burst_size = dispc_ovl_get_burst_size(ovl->id);
968
969 switch (dssdev->type) {
970 case OMAP_DISPLAY_TYPE_DPI:
971 case OMAP_DISPLAY_TYPE_DBI:
972 case OMAP_DISPLAY_TYPE_SDI:
973 case OMAP_DISPLAY_TYPE_VENC:
974 case OMAP_DISPLAY_TYPE_HDMI:
975 default_get_overlay_fifo_thresholds(ovl->id, size,
976 burst_size, &fifo_low, &fifo_high);
977 break;
978#ifdef CONFIG_OMAP2_DSS_DSI
979 case OMAP_DISPLAY_TYPE_DSI:
980 dsi_get_overlay_fifo_thresholds(ovl->id, size,
981 burst_size, &fifo_low, &fifo_high);
982 break;
983#endif
984 default:
985 BUG();
986 }
987
988 op->fifo_low = fifo_low;
989 op->fifo_high = fifo_high;
990 op->extra_info_dirty = true;
991}
992
993static void dss_mgr_setup_fifos(struct omap_overlay_manager *mgr)
994{
995 struct omap_overlay *ovl;
996 struct ovl_priv_data *op;
997 struct mgr_priv_data *mp;
998
999 mp = get_mgr_priv(mgr);
1000
1001 if (!mp->enabled)
1002 return;
1003
1004 list_for_each_entry(ovl, &mgr->overlays, list) {
1005 op = get_ovl_priv(ovl);
1006
Tomi Valkeinen82153ed2011-11-26 14:26:46 +02001007 if (!op->enabled && !op->enabling)
Tomi Valkeinen6dc802e2011-11-16 14:28:12 +02001008 continue;
1009
1010 dss_ovl_setup_fifo(ovl);
1011 }
1012}
1013
Tomi Valkeinen2a4ee7e2011-11-21 13:34:48 +02001014int dss_mgr_enable(struct omap_overlay_manager *mgr)
Tomi Valkeinen7797c6d2011-11-04 10:22:46 +02001015{
Tomi Valkeinenbf213522011-11-15 14:43:53 +02001016 struct mgr_priv_data *mp = get_mgr_priv(mgr);
1017 unsigned long flags;
Tomi Valkeinen39518352011-11-17 17:35:28 +02001018 int r;
Tomi Valkeinenbf213522011-11-15 14:43:53 +02001019
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001020 mutex_lock(&apply_lock);
1021
Tomi Valkeinene4f7ad72011-11-16 16:01:33 +02001022 if (mp->enabled)
1023 goto out;
1024
Tomi Valkeinenbf213522011-11-15 14:43:53 +02001025 spin_lock_irqsave(&data_lock, flags);
1026
1027 mp->enabled = true;
Tomi Valkeinen39518352011-11-17 17:35:28 +02001028 r = dss_check_settings(mgr, mgr->device);
1029 mp->enabled = false;
1030 if (r) {
1031 DSSERR("failed to enable manager %d: check_settings failed\n",
1032 mgr->id);
Tomi Valkeinen2a4ee7e2011-11-21 13:34:48 +02001033 goto err;
Tomi Valkeinen39518352011-11-17 17:35:28 +02001034 }
1035
1036 mp->enabled = true;
Tomi Valkeinenbf213522011-11-15 14:43:53 +02001037
Tomi Valkeinen6dc802e2011-11-16 14:28:12 +02001038 dss_mgr_setup_fifos(mgr);
1039
Tomi Valkeinen75c94962011-11-15 18:25:23 +02001040 dss_write_regs();
Tomi Valkeinen3ab15b22011-11-25 17:32:20 +02001041 dss_set_go_bits();
Tomi Valkeinen75c94962011-11-15 18:25:23 +02001042
Tomi Valkeinen34861372011-11-18 15:43:29 +02001043 if (!mgr_manual_update(mgr))
1044 mp->updating = true;
1045
Tomi Valkeinenbf213522011-11-15 14:43:53 +02001046 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001047
Tomi Valkeinen75c94962011-11-15 18:25:23 +02001048 if (!mgr_manual_update(mgr))
1049 dispc_mgr_enable(mgr->id, true);
1050
Tomi Valkeinene4f7ad72011-11-16 16:01:33 +02001051out:
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001052 mutex_unlock(&apply_lock);
Tomi Valkeinen2a4ee7e2011-11-21 13:34:48 +02001053
1054 return 0;
1055
1056err:
1057 spin_unlock_irqrestore(&data_lock, flags);
1058 mutex_unlock(&apply_lock);
1059 return r;
Tomi Valkeinen7797c6d2011-11-04 10:22:46 +02001060}
1061
1062void dss_mgr_disable(struct omap_overlay_manager *mgr)
1063{
Tomi Valkeinenbf213522011-11-15 14:43:53 +02001064 struct mgr_priv_data *mp = get_mgr_priv(mgr);
1065 unsigned long flags;
1066
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001067 mutex_lock(&apply_lock);
1068
Tomi Valkeinene4f7ad72011-11-16 16:01:33 +02001069 if (!mp->enabled)
1070 goto out;
1071
Tomi Valkeinen9a147a62011-11-09 15:30:11 +02001072 if (!mgr_manual_update(mgr))
1073 dispc_mgr_enable(mgr->id, false);
Tomi Valkeinenbf213522011-11-15 14:43:53 +02001074
1075 spin_lock_irqsave(&data_lock, flags);
1076
Tomi Valkeinen34861372011-11-18 15:43:29 +02001077 mp->updating = false;
Tomi Valkeinenbf213522011-11-15 14:43:53 +02001078 mp->enabled = false;
1079
1080 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001081
Tomi Valkeinene4f7ad72011-11-16 16:01:33 +02001082out:
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001083 mutex_unlock(&apply_lock);
Tomi Valkeinen7797c6d2011-11-04 10:22:46 +02001084}
1085
Tomi Valkeinenf17d04f2011-11-17 14:31:09 +02001086static int dss_mgr_simple_check(struct omap_overlay_manager *mgr,
1087 const struct omap_overlay_manager_info *info)
1088{
1089 if (dss_has_feature(FEAT_ALPHA_FIXED_ZORDER)) {
1090 /*
1091 * OMAP3 supports only graphics source transparency color key
1092 * and alpha blending simultaneously. See TRM 15.4.2.4.2.2
1093 * Alpha Mode.
1094 */
1095 if (info->partial_alpha_enabled && info->trans_enabled
1096 && info->trans_key_type != OMAP_DSS_COLOR_KEY_GFX_DST) {
1097 DSSERR("check_manager: illegal transparency key\n");
1098 return -EINVAL;
1099 }
1100 }
1101
1102 return 0;
1103}
1104
Tomi Valkeineneb70d732011-11-15 12:15:18 +02001105int dss_mgr_set_info(struct omap_overlay_manager *mgr,
1106 struct omap_overlay_manager_info *info)
1107{
Tomi Valkeinen388c4c62011-11-16 13:58:07 +02001108 struct mgr_priv_data *mp = get_mgr_priv(mgr);
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +02001109 unsigned long flags;
Tomi Valkeinenf17d04f2011-11-17 14:31:09 +02001110 int r;
1111
1112 r = dss_mgr_simple_check(mgr, info);
1113 if (r)
1114 return r;
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +02001115
1116 spin_lock_irqsave(&data_lock, flags);
1117
Tomi Valkeinen388c4c62011-11-16 13:58:07 +02001118 mp->user_info = *info;
1119 mp->user_info_dirty = true;
Tomi Valkeineneb70d732011-11-15 12:15:18 +02001120
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +02001121 spin_unlock_irqrestore(&data_lock, flags);
1122
Tomi Valkeineneb70d732011-11-15 12:15:18 +02001123 return 0;
1124}
1125
1126void dss_mgr_get_info(struct omap_overlay_manager *mgr,
1127 struct omap_overlay_manager_info *info)
1128{
Tomi Valkeinen388c4c62011-11-16 13:58:07 +02001129 struct mgr_priv_data *mp = get_mgr_priv(mgr);
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +02001130 unsigned long flags;
1131
1132 spin_lock_irqsave(&data_lock, flags);
1133
Tomi Valkeinen388c4c62011-11-16 13:58:07 +02001134 *info = mp->user_info;
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +02001135
1136 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeineneb70d732011-11-15 12:15:18 +02001137}
1138
1139int dss_mgr_set_device(struct omap_overlay_manager *mgr,
1140 struct omap_dss_device *dssdev)
1141{
1142 int r;
Tomi Valkeineneb70d732011-11-15 12:15:18 +02001143
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001144 mutex_lock(&apply_lock);
1145
Tomi Valkeineneb70d732011-11-15 12:15:18 +02001146 if (dssdev->manager) {
1147 DSSERR("display '%s' already has a manager '%s'\n",
1148 dssdev->name, dssdev->manager->name);
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001149 r = -EINVAL;
1150 goto err;
Tomi Valkeineneb70d732011-11-15 12:15:18 +02001151 }
1152
1153 if ((mgr->supported_displays & dssdev->type) == 0) {
1154 DSSERR("display '%s' does not support manager '%s'\n",
1155 dssdev->name, mgr->name);
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001156 r = -EINVAL;
1157 goto err;
Tomi Valkeineneb70d732011-11-15 12:15:18 +02001158 }
1159
Tomi Valkeineneb70d732011-11-15 12:15:18 +02001160 dssdev->manager = mgr;
1161 mgr->device = dssdev;
Tomi Valkeineneb70d732011-11-15 12:15:18 +02001162
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001163 mutex_unlock(&apply_lock);
1164
Tomi Valkeineneb70d732011-11-15 12:15:18 +02001165 return 0;
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001166err:
1167 mutex_unlock(&apply_lock);
1168 return r;
Tomi Valkeineneb70d732011-11-15 12:15:18 +02001169}
1170
1171int dss_mgr_unset_device(struct omap_overlay_manager *mgr)
1172{
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001173 int r;
1174
1175 mutex_lock(&apply_lock);
1176
Tomi Valkeineneb70d732011-11-15 12:15:18 +02001177 if (!mgr->device) {
1178 DSSERR("failed to unset display, display not set.\n");
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001179 r = -EINVAL;
1180 goto err;
Tomi Valkeineneb70d732011-11-15 12:15:18 +02001181 }
1182
1183 /*
1184 * Don't allow currently enabled displays to have the overlay manager
1185 * pulled out from underneath them
1186 */
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001187 if (mgr->device->state != OMAP_DSS_DISPLAY_DISABLED) {
1188 r = -EINVAL;
1189 goto err;
1190 }
Tomi Valkeineneb70d732011-11-15 12:15:18 +02001191
1192 mgr->device->manager = NULL;
1193 mgr->device = NULL;
Tomi Valkeineneb70d732011-11-15 12:15:18 +02001194
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001195 mutex_unlock(&apply_lock);
1196
Tomi Valkeineneb70d732011-11-15 12:15:18 +02001197 return 0;
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001198err:
1199 mutex_unlock(&apply_lock);
1200 return r;
Tomi Valkeineneb70d732011-11-15 12:15:18 +02001201}
1202
1203
Tomi Valkeinenfcc764d2011-11-17 14:26:48 +02001204static int dss_ovl_simple_check(struct omap_overlay *ovl,
1205 const struct omap_overlay_info *info)
1206{
1207 if (info->paddr == 0) {
1208 DSSERR("check_overlay: paddr cannot be 0\n");
1209 return -EINVAL;
1210 }
1211
1212 if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0) {
1213 if (info->out_width != 0 && info->width != info->out_width) {
1214 DSSERR("check_overlay: overlay %d doesn't support "
1215 "scaling\n", ovl->id);
1216 return -EINVAL;
1217 }
1218
1219 if (info->out_height != 0 && info->height != info->out_height) {
1220 DSSERR("check_overlay: overlay %d doesn't support "
1221 "scaling\n", ovl->id);
1222 return -EINVAL;
1223 }
1224 }
1225
1226 if ((ovl->supported_modes & info->color_mode) == 0) {
1227 DSSERR("check_overlay: overlay %d doesn't support mode %d\n",
1228 ovl->id, info->color_mode);
1229 return -EINVAL;
1230 }
1231
1232 if (info->zorder >= omap_dss_get_num_overlays()) {
1233 DSSERR("check_overlay: zorder %d too high\n", info->zorder);
1234 return -EINVAL;
1235 }
1236
1237 return 0;
1238}
Tomi Valkeineneb70d732011-11-15 12:15:18 +02001239
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001240int dss_ovl_set_info(struct omap_overlay *ovl,
1241 struct omap_overlay_info *info)
1242{
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +02001243 struct ovl_priv_data *op = get_ovl_priv(ovl);
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +02001244 unsigned long flags;
Tomi Valkeinenfcc764d2011-11-17 14:26:48 +02001245 int r;
1246
1247 r = dss_ovl_simple_check(ovl, info);
1248 if (r)
1249 return r;
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +02001250
1251 spin_lock_irqsave(&data_lock, flags);
1252
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +02001253 op->user_info = *info;
1254 op->user_info_dirty = true;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001255
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +02001256 spin_unlock_irqrestore(&data_lock, flags);
1257
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001258 return 0;
1259}
1260
1261void dss_ovl_get_info(struct omap_overlay *ovl,
1262 struct omap_overlay_info *info)
1263{
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +02001264 struct ovl_priv_data *op = get_ovl_priv(ovl);
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +02001265 unsigned long flags;
1266
1267 spin_lock_irqsave(&data_lock, flags);
1268
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +02001269 *info = op->user_info;
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +02001270
1271 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001272}
1273
1274int dss_ovl_set_manager(struct omap_overlay *ovl,
1275 struct omap_overlay_manager *mgr)
1276{
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001277 struct ovl_priv_data *op = get_ovl_priv(ovl);
1278 unsigned long flags;
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001279 int r;
1280
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001281 if (!mgr)
1282 return -EINVAL;
1283
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001284 mutex_lock(&apply_lock);
1285
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001286 if (ovl->manager) {
1287 DSSERR("overlay '%s' already has a manager '%s'\n",
1288 ovl->name, ovl->manager->name);
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001289 r = -EINVAL;
1290 goto err;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001291 }
1292
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001293 spin_lock_irqsave(&data_lock, flags);
1294
1295 if (op->enabled) {
1296 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001297 DSSERR("overlay has to be disabled to change the manager\n");
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001298 r = -EINVAL;
1299 goto err;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001300 }
1301
Tomi Valkeinen5d5a97a2011-11-16 14:17:54 +02001302 op->channel = mgr->id;
1303 op->extra_info_dirty = true;
1304
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001305 ovl->manager = mgr;
1306 list_add_tail(&ovl->list, &mgr->overlays);
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001307
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001308 spin_unlock_irqrestore(&data_lock, flags);
1309
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001310 /* XXX: When there is an overlay on a DSI manual update display, and
1311 * the overlay is first disabled, then moved to tv, and enabled, we
1312 * seem to get SYNC_LOST_DIGIT error.
1313 *
1314 * Waiting doesn't seem to help, but updating the manual update display
1315 * after disabling the overlay seems to fix this. This hints that the
1316 * overlay is perhaps somehow tied to the LCD output until the output
1317 * is updated.
1318 *
1319 * Userspace workaround for this is to update the LCD after disabling
1320 * the overlay, but before moving the overlay to TV.
1321 */
1322
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001323 mutex_unlock(&apply_lock);
1324
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001325 return 0;
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001326err:
1327 mutex_unlock(&apply_lock);
1328 return r;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001329}
1330
1331int dss_ovl_unset_manager(struct omap_overlay *ovl)
1332{
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001333 struct ovl_priv_data *op = get_ovl_priv(ovl);
1334 unsigned long flags;
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001335 int r;
1336
1337 mutex_lock(&apply_lock);
1338
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001339 if (!ovl->manager) {
1340 DSSERR("failed to detach overlay: manager not set\n");
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001341 r = -EINVAL;
1342 goto err;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001343 }
1344
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001345 spin_lock_irqsave(&data_lock, flags);
1346
1347 if (op->enabled) {
1348 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001349 DSSERR("overlay has to be disabled to unset the manager\n");
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001350 r = -EINVAL;
1351 goto err;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001352 }
1353
Tomi Valkeinen5d5a97a2011-11-16 14:17:54 +02001354 op->channel = -1;
1355
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001356 ovl->manager = NULL;
1357 list_del(&ovl->list);
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001358
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001359 spin_unlock_irqrestore(&data_lock, flags);
1360
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001361 mutex_unlock(&apply_lock);
1362
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001363 return 0;
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001364err:
1365 mutex_unlock(&apply_lock);
1366 return r;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001367}
1368
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001369bool dss_ovl_is_enabled(struct omap_overlay *ovl)
1370{
1371 struct ovl_priv_data *op = get_ovl_priv(ovl);
1372 unsigned long flags;
1373 bool e;
1374
1375 spin_lock_irqsave(&data_lock, flags);
1376
1377 e = op->enabled;
1378
1379 spin_unlock_irqrestore(&data_lock, flags);
1380
1381 return e;
1382}
1383
1384int dss_ovl_enable(struct omap_overlay *ovl)
1385{
1386 struct ovl_priv_data *op = get_ovl_priv(ovl);
1387 unsigned long flags;
1388 int r;
1389
1390 mutex_lock(&apply_lock);
1391
Tomi Valkeinene4f7ad72011-11-16 16:01:33 +02001392 if (op->enabled) {
1393 r = 0;
Tomi Valkeinen39518352011-11-17 17:35:28 +02001394 goto err1;
Tomi Valkeinene4f7ad72011-11-16 16:01:33 +02001395 }
1396
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001397 if (ovl->manager == NULL || ovl->manager->device == NULL) {
1398 r = -EINVAL;
Tomi Valkeinen39518352011-11-17 17:35:28 +02001399 goto err1;
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001400 }
1401
1402 spin_lock_irqsave(&data_lock, flags);
1403
Tomi Valkeinen82153ed2011-11-26 14:26:46 +02001404 op->enabling = true;
1405
Tomi Valkeinen39518352011-11-17 17:35:28 +02001406 r = dss_check_settings(ovl->manager, ovl->manager->device);
Tomi Valkeinen39518352011-11-17 17:35:28 +02001407 if (r) {
1408 DSSERR("failed to enable overlay %d: check_settings failed\n",
1409 ovl->id);
1410 goto err2;
1411 }
1412
Tomi Valkeinen6dc802e2011-11-16 14:28:12 +02001413 dss_ovl_setup_fifo(ovl);
1414
Tomi Valkeinen82153ed2011-11-26 14:26:46 +02001415 op->enabling = false;
1416 dss_apply_ovl_enable(ovl, true);
1417
Tomi Valkeinen75c94962011-11-15 18:25:23 +02001418 dss_write_regs();
Tomi Valkeinen3ab15b22011-11-25 17:32:20 +02001419 dss_set_go_bits();
Tomi Valkeinen75c94962011-11-15 18:25:23 +02001420
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001421 spin_unlock_irqrestore(&data_lock, flags);
1422
1423 mutex_unlock(&apply_lock);
1424
1425 return 0;
Tomi Valkeinen39518352011-11-17 17:35:28 +02001426err2:
Tomi Valkeinen82153ed2011-11-26 14:26:46 +02001427 op->enabling = false;
Tomi Valkeinen39518352011-11-17 17:35:28 +02001428 spin_unlock_irqrestore(&data_lock, flags);
1429err1:
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001430 mutex_unlock(&apply_lock);
1431 return r;
1432}
1433
1434int dss_ovl_disable(struct omap_overlay *ovl)
1435{
1436 struct ovl_priv_data *op = get_ovl_priv(ovl);
1437 unsigned long flags;
1438 int r;
1439
1440 mutex_lock(&apply_lock);
1441
Tomi Valkeinene4f7ad72011-11-16 16:01:33 +02001442 if (!op->enabled) {
1443 r = 0;
1444 goto err;
1445 }
1446
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001447 if (ovl->manager == NULL || ovl->manager->device == NULL) {
1448 r = -EINVAL;
1449 goto err;
1450 }
1451
1452 spin_lock_irqsave(&data_lock, flags);
1453
Tomi Valkeinen841c09c2011-11-16 15:25:53 +02001454 dss_apply_ovl_enable(ovl, false);
Tomi Valkeinen75c94962011-11-15 18:25:23 +02001455 dss_write_regs();
Tomi Valkeinen3ab15b22011-11-25 17:32:20 +02001456 dss_set_go_bits();
Tomi Valkeinen75c94962011-11-15 18:25:23 +02001457
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001458 spin_unlock_irqrestore(&data_lock, flags);
1459
1460 mutex_unlock(&apply_lock);
1461
1462 return 0;
1463
1464err:
1465 mutex_unlock(&apply_lock);
1466 return r;
1467}
1468