blob: 267c3f40d6c36ae81e5097b0f003d35c64ac6b84 [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
Tomi Valkeinenfb011972011-11-16 15:00:22 +0200108 bool fifo_merge_dirty;
109 bool fifo_merge;
110
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200111 bool irq_enabled;
Tomi Valkeinend09c7aa2011-11-15 12:04:43 +0200112} dss_data;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200113
Tomi Valkeinend09c7aa2011-11-15 12:04:43 +0200114/* protects dss_data */
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200115static spinlock_t data_lock;
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200116/* lock for blocking functions */
117static DEFINE_MUTEX(apply_lock);
Tomi Valkeinenf1577ce2011-11-16 14:37:48 +0200118static DECLARE_COMPLETION(extra_updated_completion);
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200119
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200120static void dss_register_vsync_isr(void);
121
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200122static struct ovl_priv_data *get_ovl_priv(struct omap_overlay *ovl)
123{
Tomi Valkeinend09c7aa2011-11-15 12:04:43 +0200124 return &dss_data.ovl_priv_data_array[ovl->id];
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200125}
126
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200127static struct mgr_priv_data *get_mgr_priv(struct omap_overlay_manager *mgr)
128{
Tomi Valkeinend09c7aa2011-11-15 12:04:43 +0200129 return &dss_data.mgr_priv_data_array[mgr->id];
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200130}
131
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200132void dss_apply_init(void)
133{
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +0200134 const int num_ovls = dss_feat_get_num_ovls();
135 int i;
136
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200137 spin_lock_init(&data_lock);
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +0200138
139 for (i = 0; i < num_ovls; ++i) {
140 struct ovl_priv_data *op;
141
142 op = &dss_data.ovl_priv_data_array[i];
143
144 op->info.global_alpha = 255;
145
146 switch (i) {
147 case 0:
148 op->info.zorder = 0;
149 break;
150 case 1:
151 op->info.zorder =
152 dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 3 : 0;
153 break;
154 case 2:
155 op->info.zorder =
156 dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 2 : 0;
157 break;
158 case 3:
159 op->info.zorder =
160 dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 1 : 0;
161 break;
162 }
163
164 op->user_info = op->info;
165 }
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200166}
167
168static bool ovl_manual_update(struct omap_overlay *ovl)
169{
170 return ovl->manager->device->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE;
171}
172
173static bool mgr_manual_update(struct omap_overlay_manager *mgr)
174{
175 return mgr->device->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE;
176}
177
Tomi Valkeinen39518352011-11-17 17:35:28 +0200178static int dss_check_settings_low(struct omap_overlay_manager *mgr,
179 struct omap_dss_device *dssdev, bool applying)
180{
181 struct omap_overlay_info *oi;
182 struct omap_overlay_manager_info *mi;
183 struct omap_overlay *ovl;
184 struct omap_overlay_info *ois[MAX_DSS_OVERLAYS];
185 struct ovl_priv_data *op;
186 struct mgr_priv_data *mp;
187
188 mp = get_mgr_priv(mgr);
189
190 if (applying && mp->user_info_dirty)
191 mi = &mp->user_info;
192 else
193 mi = &mp->info;
194
195 /* collect the infos to be tested into the array */
196 list_for_each_entry(ovl, &mgr->overlays, list) {
197 op = get_ovl_priv(ovl);
198
Tomi Valkeinen82153ed2011-11-26 14:26:46 +0200199 if (!op->enabled && !op->enabling)
Tomi Valkeinen39518352011-11-17 17:35:28 +0200200 oi = NULL;
201 else if (applying && op->user_info_dirty)
202 oi = &op->user_info;
203 else
204 oi = &op->info;
205
206 ois[ovl->id] = oi;
207 }
208
209 return dss_mgr_check(mgr, dssdev, mi, ois);
210}
211
212/*
213 * check manager and overlay settings using overlay_info from data->info
214 */
215static int dss_check_settings(struct omap_overlay_manager *mgr,
216 struct omap_dss_device *dssdev)
217{
218 return dss_check_settings_low(mgr, dssdev, false);
219}
220
221/*
222 * check manager and overlay settings using overlay_info from ovl->info if
223 * dirty and from data->info otherwise
224 */
225static int dss_check_settings_apply(struct omap_overlay_manager *mgr,
226 struct omap_dss_device *dssdev)
227{
228 return dss_check_settings_low(mgr, dssdev, true);
229}
230
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200231static bool need_isr(void)
232{
233 const int num_mgrs = dss_feat_get_num_mgrs();
234 int i;
235
236 for (i = 0; i < num_mgrs; ++i) {
237 struct omap_overlay_manager *mgr;
238 struct mgr_priv_data *mp;
239 struct omap_overlay *ovl;
240
241 mgr = omap_dss_get_overlay_manager(i);
242 mp = get_mgr_priv(mgr);
243
244 if (!mp->enabled)
245 continue;
246
Tomi Valkeinen34861372011-11-18 15:43:29 +0200247 if (mgr_manual_update(mgr)) {
248 /* to catch FRAMEDONE */
249 if (mp->updating)
250 return true;
251 } else {
252 /* to catch GO bit going down */
253 if (mp->busy)
254 return true;
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200255
256 /* to write new values to registers */
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200257 if (mp->info_dirty)
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200258 return true;
Tomi Valkeinen34861372011-11-18 15:43:29 +0200259
Tomi Valkeinen9f808952011-11-25 17:26:13 +0200260 /* to set GO bit */
261 if (mp->shadow_info_dirty)
262 return true;
263
Tomi Valkeinen34861372011-11-18 15:43:29 +0200264 list_for_each_entry(ovl, &mgr->overlays, list) {
265 struct ovl_priv_data *op;
266
267 op = get_ovl_priv(ovl);
268
Tomi Valkeinen9f808952011-11-25 17:26:13 +0200269 /*
270 * NOTE: we check extra_info flags even for
271 * disabled overlays, as extra_infos need to be
272 * always written.
273 */
274
275 /* to write new values to registers */
276 if (op->extra_info_dirty)
277 return true;
278
279 /* to set GO bit */
280 if (op->shadow_extra_info_dirty)
281 return true;
282
Tomi Valkeinen34861372011-11-18 15:43:29 +0200283 if (!op->enabled)
284 continue;
285
286 /* to write new values to registers */
Tomi Valkeinen9f808952011-11-25 17:26:13 +0200287 if (op->info_dirty)
288 return true;
289
290 /* to set GO bit */
291 if (op->shadow_info_dirty)
Tomi Valkeinen34861372011-11-18 15:43:29 +0200292 return true;
293 }
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200294 }
295 }
296
297 return false;
298}
299
300static bool need_go(struct omap_overlay_manager *mgr)
301{
302 struct omap_overlay *ovl;
303 struct mgr_priv_data *mp;
304 struct ovl_priv_data *op;
305
306 mp = get_mgr_priv(mgr);
307
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200308 if (mp->shadow_info_dirty)
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200309 return true;
310
311 list_for_each_entry(ovl, &mgr->overlays, list) {
312 op = get_ovl_priv(ovl);
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200313 if (op->shadow_info_dirty || op->shadow_extra_info_dirty)
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200314 return true;
315 }
316
317 return false;
318}
319
Tomi Valkeinenf1577ce2011-11-16 14:37:48 +0200320/* returns true if an extra_info field is currently being updated */
321static bool extra_info_update_ongoing(void)
322{
323 const int num_ovls = omap_dss_get_num_overlays();
324 struct ovl_priv_data *op;
325 struct omap_overlay *ovl;
326 struct mgr_priv_data *mp;
327 int i;
Tomi Valkeinenf1577ce2011-11-16 14:37:48 +0200328
329 for (i = 0; i < num_ovls; ++i) {
330 ovl = omap_dss_get_overlay(i);
331 op = get_ovl_priv(ovl);
332
Rob Clark1f3f53a2011-12-17 13:28:52 -0600333 if (!ovl->manager)
334 continue;
335
Tomi Valkeinenf1577ce2011-11-16 14:37:48 +0200336 mp = get_mgr_priv(ovl->manager);
337
338 if (!mp->enabled)
339 continue;
340
Tomi Valkeinen153b6e72011-11-25 17:35:35 +0200341 if (!mp->updating)
Tomi Valkeinenf1577ce2011-11-16 14:37:48 +0200342 continue;
343
Tomi Valkeinen153b6e72011-11-25 17:35:35 +0200344 if (op->extra_info_dirty || op->shadow_extra_info_dirty)
345 return true;
Tomi Valkeinenf1577ce2011-11-16 14:37:48 +0200346 }
347
348 return false;
349}
350
351/* wait until no extra_info updates are pending */
352static void wait_pending_extra_info_updates(void)
353{
354 bool updating;
355 unsigned long flags;
356 unsigned long t;
Tomi Valkeinen46146792012-02-23 12:21:09 +0200357 int r;
Tomi Valkeinenf1577ce2011-11-16 14:37:48 +0200358
359 spin_lock_irqsave(&data_lock, flags);
360
361 updating = extra_info_update_ongoing();
362
363 if (!updating) {
364 spin_unlock_irqrestore(&data_lock, flags);
365 return;
366 }
367
368 init_completion(&extra_updated_completion);
369
370 spin_unlock_irqrestore(&data_lock, flags);
371
372 t = msecs_to_jiffies(500);
Tomi Valkeinen46146792012-02-23 12:21:09 +0200373 r = wait_for_completion_timeout(&extra_updated_completion, t);
374 if (r == 0)
375 DSSWARN("timeout in wait_pending_extra_info_updates\n");
376 else if (r < 0)
377 DSSERR("wait_pending_extra_info_updates failed: %d\n", r);
Tomi Valkeinenf1577ce2011-11-16 14:37:48 +0200378}
379
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200380int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr)
381{
382 unsigned long timeout = msecs_to_jiffies(500);
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200383 struct mgr_priv_data *mp;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200384 u32 irq;
385 int r;
386 int i;
387 struct omap_dss_device *dssdev = mgr->device;
388
389 if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
390 return 0;
391
392 if (mgr_manual_update(mgr))
393 return 0;
394
Lajos Molnar21e56f72012-02-22 12:23:16 +0530395 r = dispc_runtime_get();
396 if (r)
397 return r;
398
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200399 irq = dispc_mgr_get_vsync_irq(mgr->id);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200400
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200401 mp = get_mgr_priv(mgr);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200402 i = 0;
403 while (1) {
404 unsigned long flags;
405 bool shadow_dirty, dirty;
406
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200407 spin_lock_irqsave(&data_lock, flags);
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200408 dirty = mp->info_dirty;
409 shadow_dirty = mp->shadow_info_dirty;
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200410 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200411
412 if (!dirty && !shadow_dirty) {
413 r = 0;
414 break;
415 }
416
417 /* 4 iterations is the worst case:
418 * 1 - initial iteration, dirty = true (between VFP and VSYNC)
419 * 2 - first VSYNC, dirty = true
420 * 3 - dirty = false, shadow_dirty = true
421 * 4 - shadow_dirty = false */
422 if (i++ == 3) {
423 DSSERR("mgr(%d)->wait_for_go() not finishing\n",
424 mgr->id);
425 r = 0;
426 break;
427 }
428
429 r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
430 if (r == -ERESTARTSYS)
431 break;
432
433 if (r) {
434 DSSERR("mgr(%d)->wait_for_go() timeout\n", mgr->id);
435 break;
436 }
437 }
438
Lajos Molnar21e56f72012-02-22 12:23:16 +0530439 dispc_runtime_put();
440
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200441 return r;
442}
443
444int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl)
445{
446 unsigned long timeout = msecs_to_jiffies(500);
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200447 struct ovl_priv_data *op;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200448 struct omap_dss_device *dssdev;
449 u32 irq;
450 int r;
451 int i;
452
453 if (!ovl->manager)
454 return 0;
455
456 dssdev = ovl->manager->device;
457
458 if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
459 return 0;
460
461 if (ovl_manual_update(ovl))
462 return 0;
463
Lajos Molnar21e56f72012-02-22 12:23:16 +0530464 r = dispc_runtime_get();
465 if (r)
466 return r;
467
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200468 irq = dispc_mgr_get_vsync_irq(ovl->manager->id);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200469
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200470 op = get_ovl_priv(ovl);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200471 i = 0;
472 while (1) {
473 unsigned long flags;
474 bool shadow_dirty, dirty;
475
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200476 spin_lock_irqsave(&data_lock, flags);
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200477 dirty = op->info_dirty;
478 shadow_dirty = op->shadow_info_dirty;
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200479 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200480
481 if (!dirty && !shadow_dirty) {
482 r = 0;
483 break;
484 }
485
486 /* 4 iterations is the worst case:
487 * 1 - initial iteration, dirty = true (between VFP and VSYNC)
488 * 2 - first VSYNC, dirty = true
489 * 3 - dirty = false, shadow_dirty = true
490 * 4 - shadow_dirty = false */
491 if (i++ == 3) {
492 DSSERR("ovl(%d)->wait_for_go() not finishing\n",
493 ovl->id);
494 r = 0;
495 break;
496 }
497
498 r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
499 if (r == -ERESTARTSYS)
500 break;
501
502 if (r) {
503 DSSERR("ovl(%d)->wait_for_go() timeout\n", ovl->id);
504 break;
505 }
506 }
507
Lajos Molnar21e56f72012-02-22 12:23:16 +0530508 dispc_runtime_put();
509
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200510 return r;
511}
512
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200513static void dss_ovl_write_regs(struct omap_overlay *ovl)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200514{
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200515 struct ovl_priv_data *op = get_ovl_priv(ovl);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200516 struct omap_overlay_info *oi;
517 bool ilace, replication;
Tomi Valkeinen34861372011-11-18 15:43:29 +0200518 struct mgr_priv_data *mp;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200519 int r;
520
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200521 DSSDBGF("%d", ovl->id);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200522
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200523 if (!op->enabled || !op->info_dirty)
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200524 return;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200525
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200526 oi = &op->info;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200527
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200528 replication = dss_use_replication(ovl->manager->device, oi->color_mode);
529
530 ilace = ovl->manager->device->type == OMAP_DISPLAY_TYPE_VENC;
531
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200532 r = dispc_ovl_setup(ovl->id, oi, ilace, replication);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200533 if (r) {
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200534 /*
535 * We can't do much here, as this function can be called from
536 * vsync interrupt.
537 */
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200538 DSSERR("dispc_ovl_setup failed for ovl %d\n", ovl->id);
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200539
540 /* This will leave fifo configurations in a nonoptimal state */
541 op->enabled = false;
542 dispc_ovl_enable(ovl->id, false);
543 return;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200544 }
545
Tomi Valkeinen34861372011-11-18 15:43:29 +0200546 mp = get_mgr_priv(ovl->manager);
547
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200548 op->info_dirty = false;
Tomi Valkeinen34861372011-11-18 15:43:29 +0200549 if (mp->updating)
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200550 op->shadow_info_dirty = true;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200551}
552
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200553static void dss_ovl_write_regs_extra(struct omap_overlay *ovl)
554{
555 struct ovl_priv_data *op = get_ovl_priv(ovl);
Tomi Valkeinen34861372011-11-18 15:43:29 +0200556 struct mgr_priv_data *mp;
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200557
558 DSSDBGF("%d", ovl->id);
559
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200560 if (!op->extra_info_dirty)
561 return;
562
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200563 /* note: write also when op->enabled == false, so that the ovl gets
564 * disabled */
565
566 dispc_ovl_enable(ovl->id, op->enabled);
Tomi Valkeinen5d5a97a2011-11-16 14:17:54 +0200567 dispc_ovl_set_channel_out(ovl->id, op->channel);
Tomi Valkeinen6dc802e2011-11-16 14:28:12 +0200568 dispc_ovl_set_fifo_threshold(ovl->id, op->fifo_low, op->fifo_high);
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200569
Tomi Valkeinen34861372011-11-18 15:43:29 +0200570 mp = get_mgr_priv(ovl->manager);
571
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200572 op->extra_info_dirty = false;
Tomi Valkeinen34861372011-11-18 15:43:29 +0200573 if (mp->updating)
574 op->shadow_extra_info_dirty = true;
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200575}
576
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200577static void dss_mgr_write_regs(struct omap_overlay_manager *mgr)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200578{
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200579 struct mgr_priv_data *mp = get_mgr_priv(mgr);
580 struct omap_overlay *ovl;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200581
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200582 DSSDBGF("%d", mgr->id);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200583
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200584 if (!mp->enabled)
585 return;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200586
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200587 WARN_ON(mp->busy);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200588
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200589 /* Commit overlay settings */
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200590 list_for_each_entry(ovl, &mgr->overlays, list) {
591 dss_ovl_write_regs(ovl);
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200592 dss_ovl_write_regs_extra(ovl);
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200593 }
594
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200595 if (mp->info_dirty) {
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200596 dispc_mgr_setup(mgr->id, &mp->info);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200597
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200598 mp->info_dirty = false;
Tomi Valkeinen34861372011-11-18 15:43:29 +0200599 if (mp->updating)
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200600 mp->shadow_info_dirty = true;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200601 }
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200602}
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200603
Tomi Valkeinenfb011972011-11-16 15:00:22 +0200604static void dss_write_regs_common(void)
605{
606 const int num_mgrs = omap_dss_get_num_overlay_managers();
607 int i;
608
609 if (!dss_data.fifo_merge_dirty)
610 return;
611
612 for (i = 0; i < num_mgrs; ++i) {
613 struct omap_overlay_manager *mgr;
614 struct mgr_priv_data *mp;
615
616 mgr = omap_dss_get_overlay_manager(i);
617 mp = get_mgr_priv(mgr);
618
619 if (mp->enabled) {
620 if (dss_data.fifo_merge_dirty) {
621 dispc_enable_fifomerge(dss_data.fifo_merge);
622 dss_data.fifo_merge_dirty = false;
623 }
624
625 if (mp->updating)
626 mp->shadow_info_dirty = true;
627 }
628 }
629}
630
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200631static void dss_write_regs(void)
632{
633 const int num_mgrs = omap_dss_get_num_overlay_managers();
634 int i;
635
Tomi Valkeinenfb011972011-11-16 15:00:22 +0200636 dss_write_regs_common();
637
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200638 for (i = 0; i < num_mgrs; ++i) {
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200639 struct omap_overlay_manager *mgr;
640 struct mgr_priv_data *mp;
Tomi Valkeinen39518352011-11-17 17:35:28 +0200641 int r;
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200642
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200643 mgr = omap_dss_get_overlay_manager(i);
644 mp = get_mgr_priv(mgr);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200645
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200646 if (!mp->enabled || mgr_manual_update(mgr) || mp->busy)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200647 continue;
648
Tomi Valkeinen39518352011-11-17 17:35:28 +0200649 r = dss_check_settings(mgr, mgr->device);
650 if (r) {
651 DSSERR("cannot write registers for manager %s: "
652 "illegal configuration\n", mgr->name);
653 continue;
654 }
655
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200656 dss_mgr_write_regs(mgr);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200657 }
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200658}
659
Tomi Valkeinen3ab15b22011-11-25 17:32:20 +0200660static void dss_set_go_bits(void)
661{
662 const int num_mgrs = omap_dss_get_num_overlay_managers();
663 int i;
664
665 for (i = 0; i < num_mgrs; ++i) {
666 struct omap_overlay_manager *mgr;
667 struct mgr_priv_data *mp;
668
669 mgr = omap_dss_get_overlay_manager(i);
670 mp = get_mgr_priv(mgr);
671
672 if (!mp->enabled || mgr_manual_update(mgr) || mp->busy)
673 continue;
674
675 if (!need_go(mgr))
676 continue;
677
678 mp->busy = true;
679
680 if (!dss_data.irq_enabled && need_isr())
681 dss_register_vsync_isr();
682
683 dispc_mgr_go(mgr->id);
684 }
685
686}
687
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200688void dss_mgr_start_update(struct omap_overlay_manager *mgr)
689{
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200690 struct mgr_priv_data *mp = get_mgr_priv(mgr);
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200691 unsigned long flags;
Tomi Valkeinen39518352011-11-17 17:35:28 +0200692 int r;
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200693
694 spin_lock_irqsave(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200695
Tomi Valkeinen34861372011-11-18 15:43:29 +0200696 WARN_ON(mp->updating);
697
Tomi Valkeinen39518352011-11-17 17:35:28 +0200698 r = dss_check_settings(mgr, mgr->device);
699 if (r) {
700 DSSERR("cannot start manual update: illegal configuration\n");
701 spin_unlock_irqrestore(&data_lock, flags);
702 return;
703 }
704
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200705 dss_mgr_write_regs(mgr);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200706
Tomi Valkeinenfb011972011-11-16 15:00:22 +0200707 dss_write_regs_common();
708
Tomi Valkeinen34861372011-11-18 15:43:29 +0200709 mp->updating = true;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200710
Tomi Valkeinen34861372011-11-18 15:43:29 +0200711 if (!dss_data.irq_enabled && need_isr())
712 dss_register_vsync_isr();
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200713
Tomi Valkeinen7797c6d2011-11-04 10:22:46 +0200714 dispc_mgr_enable(mgr->id, true);
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200715
716 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200717}
718
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200719static void dss_apply_irq_handler(void *data, u32 mask);
720
721static void dss_register_vsync_isr(void)
722{
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200723 const int num_mgrs = dss_feat_get_num_mgrs();
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200724 u32 mask;
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200725 int r, i;
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200726
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200727 mask = 0;
728 for (i = 0; i < num_mgrs; ++i)
729 mask |= dispc_mgr_get_vsync_irq(i);
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200730
Tomi Valkeinen34861372011-11-18 15:43:29 +0200731 for (i = 0; i < num_mgrs; ++i)
732 mask |= dispc_mgr_get_framedone_irq(i);
733
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200734 r = omap_dispc_register_isr(dss_apply_irq_handler, NULL, mask);
735 WARN_ON(r);
736
Tomi Valkeinend09c7aa2011-11-15 12:04:43 +0200737 dss_data.irq_enabled = true;
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200738}
739
740static void dss_unregister_vsync_isr(void)
741{
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200742 const int num_mgrs = dss_feat_get_num_mgrs();
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200743 u32 mask;
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200744 int r, i;
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200745
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200746 mask = 0;
747 for (i = 0; i < num_mgrs; ++i)
748 mask |= dispc_mgr_get_vsync_irq(i);
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200749
Tomi Valkeinen34861372011-11-18 15:43:29 +0200750 for (i = 0; i < num_mgrs; ++i)
751 mask |= dispc_mgr_get_framedone_irq(i);
752
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200753 r = omap_dispc_unregister_isr(dss_apply_irq_handler, NULL, mask);
754 WARN_ON(r);
755
Tomi Valkeinend09c7aa2011-11-15 12:04:43 +0200756 dss_data.irq_enabled = false;
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200757}
758
Tomi Valkeinen76098932011-11-16 12:03:22 +0200759static void mgr_clear_shadow_dirty(struct omap_overlay_manager *mgr)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200760{
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200761 struct omap_overlay *ovl;
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200762 struct mgr_priv_data *mp;
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200763 struct ovl_priv_data *op;
Tomi Valkeinen76098932011-11-16 12:03:22 +0200764
765 mp = get_mgr_priv(mgr);
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200766 mp->shadow_info_dirty = false;
Tomi Valkeinen76098932011-11-16 12:03:22 +0200767
768 list_for_each_entry(ovl, &mgr->overlays, list) {
769 op = get_ovl_priv(ovl);
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200770 op->shadow_info_dirty = false;
Tomi Valkeinen76098932011-11-16 12:03:22 +0200771 op->shadow_extra_info_dirty = false;
772 }
773}
774
775static void dss_apply_irq_handler(void *data, u32 mask)
776{
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200777 const int num_mgrs = dss_feat_get_num_mgrs();
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200778 int i;
Tomi Valkeinenf1577ce2011-11-16 14:37:48 +0200779 bool extra_updating;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200780
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200781 spin_lock(&data_lock);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200782
Tomi Valkeinen76098932011-11-16 12:03:22 +0200783 /* clear busy, updating flags, shadow_dirty flags */
Tomi Valkeinen43a972d2011-11-15 15:04:25 +0200784 for (i = 0; i < num_mgrs; i++) {
Tomi Valkeinen76098932011-11-16 12:03:22 +0200785 struct omap_overlay_manager *mgr;
786 struct mgr_priv_data *mp;
Tomi Valkeinen5b214172011-11-25 17:27:45 +0200787 bool was_updating;
Tomi Valkeinen76098932011-11-16 12:03:22 +0200788
Tomi Valkeinen43a972d2011-11-15 15:04:25 +0200789 mgr = omap_dss_get_overlay_manager(i);
790 mp = get_mgr_priv(mgr);
791
Tomi Valkeinen76098932011-11-16 12:03:22 +0200792 if (!mp->enabled)
Tomi Valkeinen43a972d2011-11-15 15:04:25 +0200793 continue;
794
Tomi Valkeinen5b214172011-11-25 17:27:45 +0200795 was_updating = mp->updating;
Tomi Valkeinen76098932011-11-16 12:03:22 +0200796 mp->updating = dispc_mgr_is_enabled(i);
Tomi Valkeinen43a972d2011-11-15 15:04:25 +0200797
Tomi Valkeinen76098932011-11-16 12:03:22 +0200798 if (!mgr_manual_update(mgr)) {
Tomi Valkeinen5b214172011-11-25 17:27:45 +0200799 bool was_busy = mp->busy;
Tomi Valkeinen76098932011-11-16 12:03:22 +0200800 mp->busy = dispc_mgr_go_busy(i);
801
Tomi Valkeinen5b214172011-11-25 17:27:45 +0200802 if (was_busy && !mp->busy)
Tomi Valkeinen76098932011-11-16 12:03:22 +0200803 mgr_clear_shadow_dirty(mgr);
804 } else {
Tomi Valkeinen5b214172011-11-25 17:27:45 +0200805 if (was_updating && !mp->updating)
Tomi Valkeinen76098932011-11-16 12:03:22 +0200806 mgr_clear_shadow_dirty(mgr);
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200807 }
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200808 }
809
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200810 dss_write_regs();
Tomi Valkeinen3ab15b22011-11-25 17:32:20 +0200811 dss_set_go_bits();
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200812
Tomi Valkeinenf1577ce2011-11-16 14:37:48 +0200813 extra_updating = extra_info_update_ongoing();
814 if (!extra_updating)
815 complete_all(&extra_updated_completion);
816
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200817 if (!need_isr())
818 dss_unregister_vsync_isr();
Tomi Valkeinen43a972d2011-11-15 15:04:25 +0200819
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200820 spin_unlock(&data_lock);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200821}
822
Tomi Valkeinen5738b632011-11-15 13:37:33 +0200823static void omap_dss_mgr_apply_ovl(struct omap_overlay *ovl)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200824{
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200825 struct ovl_priv_data *op;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200826
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200827 op = get_ovl_priv(ovl);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200828
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +0200829 if (!op->user_info_dirty)
Tomi Valkeinen5738b632011-11-15 13:37:33 +0200830 return;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200831
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +0200832 op->user_info_dirty = false;
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200833 op->info_dirty = true;
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +0200834 op->info = op->user_info;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200835}
836
837static void omap_dss_mgr_apply_mgr(struct omap_overlay_manager *mgr)
838{
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200839 struct mgr_priv_data *mp;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200840
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200841 mp = get_mgr_priv(mgr);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200842
Tomi Valkeinen388c4c62011-11-16 13:58:07 +0200843 if (!mp->user_info_dirty)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200844 return;
845
Tomi Valkeinen388c4c62011-11-16 13:58:07 +0200846 mp->user_info_dirty = false;
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200847 mp->info_dirty = true;
Tomi Valkeinen388c4c62011-11-16 13:58:07 +0200848 mp->info = mp->user_info;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200849}
850
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200851int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
852{
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200853 unsigned long flags;
Tomi Valkeinen07e327c2011-11-05 10:59:59 +0200854 struct omap_overlay *ovl;
Tomi Valkeinen39518352011-11-17 17:35:28 +0200855 int r;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200856
857 DSSDBG("omap_dss_mgr_apply(%s)\n", mgr->name);
858
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200859 spin_lock_irqsave(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200860
Tomi Valkeinen39518352011-11-17 17:35:28 +0200861 r = dss_check_settings_apply(mgr, mgr->device);
862 if (r) {
863 spin_unlock_irqrestore(&data_lock, flags);
864 DSSERR("failed to apply settings: illegal configuration.\n");
865 return r;
866 }
867
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200868 /* Configure overlays */
Tomi Valkeinen07e327c2011-11-05 10:59:59 +0200869 list_for_each_entry(ovl, &mgr->overlays, list)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200870 omap_dss_mgr_apply_ovl(ovl);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200871
872 /* Configure manager */
873 omap_dss_mgr_apply_mgr(mgr);
874
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200875 dss_write_regs();
Tomi Valkeinen3ab15b22011-11-25 17:32:20 +0200876 dss_set_go_bits();
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200877
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200878 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200879
Tomi Valkeinene70f98a2011-11-16 16:53:44 +0200880 return 0;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200881}
882
Tomi Valkeinen841c09c2011-11-16 15:25:53 +0200883static void dss_apply_ovl_enable(struct omap_overlay *ovl, bool enable)
884{
885 struct ovl_priv_data *op;
886
887 op = get_ovl_priv(ovl);
888
889 if (op->enabled == enable)
890 return;
891
892 op->enabled = enable;
893 op->extra_info_dirty = true;
894}
895
Tomi Valkeinen04576d42011-11-26 14:39:16 +0200896static void dss_apply_ovl_fifo_thresholds(struct omap_overlay *ovl,
897 u32 fifo_low, u32 fifo_high)
898{
899 struct ovl_priv_data *op = get_ovl_priv(ovl);
900
901 if (op->fifo_low == fifo_low && op->fifo_high == fifo_high)
902 return;
903
904 op->fifo_low = fifo_low;
905 op->fifo_high = fifo_high;
906 op->extra_info_dirty = true;
907}
908
Tomi Valkeinenfb011972011-11-16 15:00:22 +0200909static void dss_apply_fifo_merge(bool use_fifo_merge)
910{
911 if (dss_data.fifo_merge == use_fifo_merge)
912 return;
913
914 dss_data.fifo_merge = use_fifo_merge;
915 dss_data.fifo_merge_dirty = true;
916}
917
Tomi Valkeinen1d71f422011-11-16 16:44:08 +0200918static void dss_ovl_setup_fifo(struct omap_overlay *ovl,
919 bool use_fifo_merge)
Tomi Valkeinen6dc802e2011-11-16 14:28:12 +0200920{
921 struct ovl_priv_data *op = get_ovl_priv(ovl);
922 struct omap_dss_device *dssdev;
Tomi Valkeinen6dc802e2011-11-16 14:28:12 +0200923 u32 fifo_low, fifo_high;
924
Tomi Valkeinen75ae1182011-11-26 14:36:19 +0200925 if (!op->enabled && !op->enabling)
926 return;
927
Tomi Valkeinen6dc802e2011-11-16 14:28:12 +0200928 dssdev = ovl->manager->device;
929
Tomi Valkeinen83fa2f22012-01-13 13:17:01 +0200930 dispc_ovl_compute_fifo_thresholds(ovl->id, &fifo_low, &fifo_high,
931 use_fifo_merge);
Tomi Valkeinen6dc802e2011-11-16 14:28:12 +0200932
Tomi Valkeinen04576d42011-11-26 14:39:16 +0200933 dss_apply_ovl_fifo_thresholds(ovl, fifo_low, fifo_high);
Tomi Valkeinen6dc802e2011-11-16 14:28:12 +0200934}
935
Tomi Valkeinen1d71f422011-11-16 16:44:08 +0200936static void dss_mgr_setup_fifos(struct omap_overlay_manager *mgr,
937 bool use_fifo_merge)
Tomi Valkeinen6dc802e2011-11-16 14:28:12 +0200938{
939 struct omap_overlay *ovl;
Tomi Valkeinen6dc802e2011-11-16 14:28:12 +0200940 struct mgr_priv_data *mp;
941
942 mp = get_mgr_priv(mgr);
943
944 if (!mp->enabled)
945 return;
946
Tomi Valkeinen75ae1182011-11-26 14:36:19 +0200947 list_for_each_entry(ovl, &mgr->overlays, list)
Tomi Valkeinen1d71f422011-11-16 16:44:08 +0200948 dss_ovl_setup_fifo(ovl, use_fifo_merge);
Tomi Valkeinen75ae1182011-11-26 14:36:19 +0200949}
950
Tomi Valkeinen1d71f422011-11-16 16:44:08 +0200951static void dss_setup_fifos(bool use_fifo_merge)
Tomi Valkeinen75ae1182011-11-26 14:36:19 +0200952{
953 const int num_mgrs = omap_dss_get_num_overlay_managers();
954 struct omap_overlay_manager *mgr;
955 int i;
956
957 for (i = 0; i < num_mgrs; ++i) {
958 mgr = omap_dss_get_overlay_manager(i);
Tomi Valkeinen1d71f422011-11-16 16:44:08 +0200959 dss_mgr_setup_fifos(mgr, use_fifo_merge);
Tomi Valkeinen6dc802e2011-11-16 14:28:12 +0200960 }
961}
962
Tomi Valkeinen1d71f422011-11-16 16:44:08 +0200963static int get_num_used_managers(void)
964{
965 const int num_mgrs = omap_dss_get_num_overlay_managers();
966 struct omap_overlay_manager *mgr;
967 struct mgr_priv_data *mp;
968 int i;
969 int enabled_mgrs;
970
971 enabled_mgrs = 0;
972
973 for (i = 0; i < num_mgrs; ++i) {
974 mgr = omap_dss_get_overlay_manager(i);
975 mp = get_mgr_priv(mgr);
976
977 if (!mp->enabled)
978 continue;
979
980 enabled_mgrs++;
981 }
982
983 return enabled_mgrs;
984}
985
986static int get_num_used_overlays(void)
987{
988 const int num_ovls = omap_dss_get_num_overlays();
989 struct omap_overlay *ovl;
990 struct ovl_priv_data *op;
991 struct mgr_priv_data *mp;
992 int i;
993 int enabled_ovls;
994
995 enabled_ovls = 0;
996
997 for (i = 0; i < num_ovls; ++i) {
998 ovl = omap_dss_get_overlay(i);
999 op = get_ovl_priv(ovl);
1000
1001 if (!op->enabled && !op->enabling)
1002 continue;
1003
1004 mp = get_mgr_priv(ovl->manager);
1005
1006 if (!mp->enabled)
1007 continue;
1008
1009 enabled_ovls++;
1010 }
1011
1012 return enabled_ovls;
1013}
1014
1015static bool get_use_fifo_merge(void)
1016{
1017 int enabled_mgrs = get_num_used_managers();
1018 int enabled_ovls = get_num_used_overlays();
1019
1020 if (!dss_has_feature(FEAT_FIFO_MERGE))
1021 return false;
1022
1023 /*
1024 * In theory the only requirement for fifomerge is enabled_ovls <= 1.
1025 * However, if we have two managers enabled and set/unset the fifomerge,
1026 * we need to set the GO bits in particular sequence for the managers,
1027 * and wait in between.
1028 *
1029 * This is rather difficult as new apply calls can happen at any time,
1030 * so we simplify the problem by requiring also that enabled_mgrs <= 1.
1031 * In practice this shouldn't matter, because when only one overlay is
1032 * enabled, most likely only one output is enabled.
1033 */
1034
1035 return enabled_mgrs <= 1 && enabled_ovls <= 1;
1036}
1037
Tomi Valkeinen2a4ee7e2011-11-21 13:34:48 +02001038int dss_mgr_enable(struct omap_overlay_manager *mgr)
Tomi Valkeinen7797c6d2011-11-04 10:22:46 +02001039{
Tomi Valkeinenbf213522011-11-15 14:43:53 +02001040 struct mgr_priv_data *mp = get_mgr_priv(mgr);
1041 unsigned long flags;
Tomi Valkeinen39518352011-11-17 17:35:28 +02001042 int r;
Tomi Valkeinen1d71f422011-11-16 16:44:08 +02001043 bool fifo_merge;
Tomi Valkeinenbf213522011-11-15 14:43:53 +02001044
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001045 mutex_lock(&apply_lock);
1046
Tomi Valkeinene4f7ad72011-11-16 16:01:33 +02001047 if (mp->enabled)
1048 goto out;
1049
Tomi Valkeinenbf213522011-11-15 14:43:53 +02001050 spin_lock_irqsave(&data_lock, flags);
1051
1052 mp->enabled = true;
Tomi Valkeinena6b24f82011-11-26 14:29:39 +02001053
Tomi Valkeinen39518352011-11-17 17:35:28 +02001054 r = dss_check_settings(mgr, mgr->device);
Tomi Valkeinen39518352011-11-17 17:35:28 +02001055 if (r) {
1056 DSSERR("failed to enable manager %d: check_settings failed\n",
1057 mgr->id);
Tomi Valkeinen2a4ee7e2011-11-21 13:34:48 +02001058 goto err;
Tomi Valkeinen39518352011-11-17 17:35:28 +02001059 }
1060
Tomi Valkeinen1d71f422011-11-16 16:44:08 +02001061 /* step 1: setup fifos/fifomerge before enabling the manager */
1062
1063 fifo_merge = get_use_fifo_merge();
1064 dss_setup_fifos(fifo_merge);
1065 dss_apply_fifo_merge(fifo_merge);
Tomi Valkeinen6dc802e2011-11-16 14:28:12 +02001066
Tomi Valkeinen75c94962011-11-15 18:25:23 +02001067 dss_write_regs();
Tomi Valkeinen3ab15b22011-11-25 17:32:20 +02001068 dss_set_go_bits();
Tomi Valkeinen75c94962011-11-15 18:25:23 +02001069
Tomi Valkeinen1d71f422011-11-16 16:44:08 +02001070 spin_unlock_irqrestore(&data_lock, flags);
1071
1072 /* wait until fifo config is in */
1073 wait_pending_extra_info_updates();
1074
1075 /* step 2: enable the manager */
1076 spin_lock_irqsave(&data_lock, flags);
1077
Tomi Valkeinen34861372011-11-18 15:43:29 +02001078 if (!mgr_manual_update(mgr))
1079 mp->updating = true;
1080
Tomi Valkeinenbf213522011-11-15 14:43:53 +02001081 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001082
Tomi Valkeinen75c94962011-11-15 18:25:23 +02001083 if (!mgr_manual_update(mgr))
1084 dispc_mgr_enable(mgr->id, true);
1085
Tomi Valkeinene4f7ad72011-11-16 16:01:33 +02001086out:
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001087 mutex_unlock(&apply_lock);
Tomi Valkeinen2a4ee7e2011-11-21 13:34:48 +02001088
1089 return 0;
1090
1091err:
Tomi Valkeinena6b24f82011-11-26 14:29:39 +02001092 mp->enabled = false;
Tomi Valkeinen2a4ee7e2011-11-21 13:34:48 +02001093 spin_unlock_irqrestore(&data_lock, flags);
1094 mutex_unlock(&apply_lock);
1095 return r;
Tomi Valkeinen7797c6d2011-11-04 10:22:46 +02001096}
1097
1098void dss_mgr_disable(struct omap_overlay_manager *mgr)
1099{
Tomi Valkeinenbf213522011-11-15 14:43:53 +02001100 struct mgr_priv_data *mp = get_mgr_priv(mgr);
1101 unsigned long flags;
Tomi Valkeinen1d71f422011-11-16 16:44:08 +02001102 bool fifo_merge;
Tomi Valkeinenbf213522011-11-15 14:43:53 +02001103
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001104 mutex_lock(&apply_lock);
1105
Tomi Valkeinene4f7ad72011-11-16 16:01:33 +02001106 if (!mp->enabled)
1107 goto out;
1108
Tomi Valkeinen9a147a62011-11-09 15:30:11 +02001109 if (!mgr_manual_update(mgr))
1110 dispc_mgr_enable(mgr->id, false);
Tomi Valkeinenbf213522011-11-15 14:43:53 +02001111
1112 spin_lock_irqsave(&data_lock, flags);
1113
Tomi Valkeinen34861372011-11-18 15:43:29 +02001114 mp->updating = false;
Tomi Valkeinenbf213522011-11-15 14:43:53 +02001115 mp->enabled = false;
1116
Tomi Valkeinen1d71f422011-11-16 16:44:08 +02001117 fifo_merge = get_use_fifo_merge();
1118 dss_setup_fifos(fifo_merge);
1119 dss_apply_fifo_merge(fifo_merge);
1120
1121 dss_write_regs();
1122 dss_set_go_bits();
1123
Tomi Valkeinenbf213522011-11-15 14:43:53 +02001124 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001125
Tomi Valkeinen1d71f422011-11-16 16:44:08 +02001126 wait_pending_extra_info_updates();
Tomi Valkeinene4f7ad72011-11-16 16:01:33 +02001127out:
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001128 mutex_unlock(&apply_lock);
Tomi Valkeinen7797c6d2011-11-04 10:22:46 +02001129}
1130
Tomi Valkeineneb70d732011-11-15 12:15:18 +02001131int dss_mgr_set_info(struct omap_overlay_manager *mgr,
1132 struct omap_overlay_manager_info *info)
1133{
Tomi Valkeinen388c4c62011-11-16 13:58:07 +02001134 struct mgr_priv_data *mp = get_mgr_priv(mgr);
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +02001135 unsigned long flags;
Tomi Valkeinenf17d04f2011-11-17 14:31:09 +02001136 int r;
1137
1138 r = dss_mgr_simple_check(mgr, info);
1139 if (r)
1140 return r;
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +02001141
1142 spin_lock_irqsave(&data_lock, flags);
1143
Tomi Valkeinen388c4c62011-11-16 13:58:07 +02001144 mp->user_info = *info;
1145 mp->user_info_dirty = true;
Tomi Valkeineneb70d732011-11-15 12:15:18 +02001146
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +02001147 spin_unlock_irqrestore(&data_lock, flags);
1148
Tomi Valkeineneb70d732011-11-15 12:15:18 +02001149 return 0;
1150}
1151
1152void dss_mgr_get_info(struct omap_overlay_manager *mgr,
1153 struct omap_overlay_manager_info *info)
1154{
Tomi Valkeinen388c4c62011-11-16 13:58:07 +02001155 struct mgr_priv_data *mp = get_mgr_priv(mgr);
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +02001156 unsigned long flags;
1157
1158 spin_lock_irqsave(&data_lock, flags);
1159
Tomi Valkeinen388c4c62011-11-16 13:58:07 +02001160 *info = mp->user_info;
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +02001161
1162 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeineneb70d732011-11-15 12:15:18 +02001163}
1164
1165int dss_mgr_set_device(struct omap_overlay_manager *mgr,
1166 struct omap_dss_device *dssdev)
1167{
1168 int r;
Tomi Valkeineneb70d732011-11-15 12:15:18 +02001169
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001170 mutex_lock(&apply_lock);
1171
Tomi Valkeineneb70d732011-11-15 12:15:18 +02001172 if (dssdev->manager) {
1173 DSSERR("display '%s' already has a manager '%s'\n",
1174 dssdev->name, dssdev->manager->name);
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001175 r = -EINVAL;
1176 goto err;
Tomi Valkeineneb70d732011-11-15 12:15:18 +02001177 }
1178
1179 if ((mgr->supported_displays & dssdev->type) == 0) {
1180 DSSERR("display '%s' does not support manager '%s'\n",
1181 dssdev->name, mgr->name);
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001182 r = -EINVAL;
1183 goto err;
Tomi Valkeineneb70d732011-11-15 12:15:18 +02001184 }
1185
Tomi Valkeineneb70d732011-11-15 12:15:18 +02001186 dssdev->manager = mgr;
1187 mgr->device = dssdev;
Tomi Valkeineneb70d732011-11-15 12:15:18 +02001188
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001189 mutex_unlock(&apply_lock);
1190
Tomi Valkeineneb70d732011-11-15 12:15:18 +02001191 return 0;
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001192err:
1193 mutex_unlock(&apply_lock);
1194 return r;
Tomi Valkeineneb70d732011-11-15 12:15:18 +02001195}
1196
1197int dss_mgr_unset_device(struct omap_overlay_manager *mgr)
1198{
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001199 int r;
1200
1201 mutex_lock(&apply_lock);
1202
Tomi Valkeineneb70d732011-11-15 12:15:18 +02001203 if (!mgr->device) {
1204 DSSERR("failed to unset display, display not set.\n");
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001205 r = -EINVAL;
1206 goto err;
Tomi Valkeineneb70d732011-11-15 12:15:18 +02001207 }
1208
1209 /*
1210 * Don't allow currently enabled displays to have the overlay manager
1211 * pulled out from underneath them
1212 */
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001213 if (mgr->device->state != OMAP_DSS_DISPLAY_DISABLED) {
1214 r = -EINVAL;
1215 goto err;
1216 }
Tomi Valkeineneb70d732011-11-15 12:15:18 +02001217
1218 mgr->device->manager = NULL;
1219 mgr->device = NULL;
Tomi Valkeineneb70d732011-11-15 12:15:18 +02001220
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001221 mutex_unlock(&apply_lock);
1222
Tomi Valkeineneb70d732011-11-15 12:15:18 +02001223 return 0;
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001224err:
1225 mutex_unlock(&apply_lock);
1226 return r;
Tomi Valkeineneb70d732011-11-15 12:15:18 +02001227}
1228
1229
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001230int dss_ovl_set_info(struct omap_overlay *ovl,
1231 struct omap_overlay_info *info)
1232{
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +02001233 struct ovl_priv_data *op = get_ovl_priv(ovl);
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +02001234 unsigned long flags;
Tomi Valkeinenfcc764d2011-11-17 14:26:48 +02001235 int r;
1236
1237 r = dss_ovl_simple_check(ovl, info);
1238 if (r)
1239 return r;
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +02001240
1241 spin_lock_irqsave(&data_lock, flags);
1242
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +02001243 op->user_info = *info;
1244 op->user_info_dirty = true;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001245
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +02001246 spin_unlock_irqrestore(&data_lock, flags);
1247
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001248 return 0;
1249}
1250
1251void dss_ovl_get_info(struct omap_overlay *ovl,
1252 struct omap_overlay_info *info)
1253{
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +02001254 struct ovl_priv_data *op = get_ovl_priv(ovl);
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +02001255 unsigned long flags;
1256
1257 spin_lock_irqsave(&data_lock, flags);
1258
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +02001259 *info = op->user_info;
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +02001260
1261 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001262}
1263
1264int dss_ovl_set_manager(struct omap_overlay *ovl,
1265 struct omap_overlay_manager *mgr)
1266{
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001267 struct ovl_priv_data *op = get_ovl_priv(ovl);
1268 unsigned long flags;
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001269 int r;
1270
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001271 if (!mgr)
1272 return -EINVAL;
1273
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001274 mutex_lock(&apply_lock);
1275
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001276 if (ovl->manager) {
1277 DSSERR("overlay '%s' already has a manager '%s'\n",
1278 ovl->name, ovl->manager->name);
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001279 r = -EINVAL;
1280 goto err;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001281 }
1282
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001283 spin_lock_irqsave(&data_lock, flags);
1284
1285 if (op->enabled) {
1286 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001287 DSSERR("overlay has to be disabled to change the manager\n");
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001288 r = -EINVAL;
1289 goto err;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001290 }
1291
Tomi Valkeinen5d5a97a2011-11-16 14:17:54 +02001292 op->channel = mgr->id;
1293 op->extra_info_dirty = true;
1294
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001295 ovl->manager = mgr;
1296 list_add_tail(&ovl->list, &mgr->overlays);
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001297
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001298 spin_unlock_irqrestore(&data_lock, flags);
1299
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001300 /* XXX: When there is an overlay on a DSI manual update display, and
1301 * the overlay is first disabled, then moved to tv, and enabled, we
1302 * seem to get SYNC_LOST_DIGIT error.
1303 *
1304 * Waiting doesn't seem to help, but updating the manual update display
1305 * after disabling the overlay seems to fix this. This hints that the
1306 * overlay is perhaps somehow tied to the LCD output until the output
1307 * is updated.
1308 *
1309 * Userspace workaround for this is to update the LCD after disabling
1310 * the overlay, but before moving the overlay to TV.
1311 */
1312
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001313 mutex_unlock(&apply_lock);
1314
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001315 return 0;
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001316err:
1317 mutex_unlock(&apply_lock);
1318 return r;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001319}
1320
1321int dss_ovl_unset_manager(struct omap_overlay *ovl)
1322{
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001323 struct ovl_priv_data *op = get_ovl_priv(ovl);
1324 unsigned long flags;
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001325 int r;
1326
1327 mutex_lock(&apply_lock);
1328
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001329 if (!ovl->manager) {
1330 DSSERR("failed to detach overlay: manager not set\n");
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001331 r = -EINVAL;
1332 goto err;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001333 }
1334
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001335 spin_lock_irqsave(&data_lock, flags);
1336
1337 if (op->enabled) {
1338 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001339 DSSERR("overlay has to be disabled to unset the manager\n");
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001340 r = -EINVAL;
1341 goto err;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001342 }
1343
Tomi Valkeinen5d5a97a2011-11-16 14:17:54 +02001344 op->channel = -1;
1345
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001346 ovl->manager = NULL;
1347 list_del(&ovl->list);
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001348
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001349 spin_unlock_irqrestore(&data_lock, flags);
1350
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001351 mutex_unlock(&apply_lock);
1352
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001353 return 0;
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001354err:
1355 mutex_unlock(&apply_lock);
1356 return r;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001357}
1358
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001359bool dss_ovl_is_enabled(struct omap_overlay *ovl)
1360{
1361 struct ovl_priv_data *op = get_ovl_priv(ovl);
1362 unsigned long flags;
1363 bool e;
1364
1365 spin_lock_irqsave(&data_lock, flags);
1366
1367 e = op->enabled;
1368
1369 spin_unlock_irqrestore(&data_lock, flags);
1370
1371 return e;
1372}
1373
1374int dss_ovl_enable(struct omap_overlay *ovl)
1375{
1376 struct ovl_priv_data *op = get_ovl_priv(ovl);
1377 unsigned long flags;
Tomi Valkeinen1d71f422011-11-16 16:44:08 +02001378 bool fifo_merge;
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001379 int r;
1380
1381 mutex_lock(&apply_lock);
1382
Tomi Valkeinene4f7ad72011-11-16 16:01:33 +02001383 if (op->enabled) {
1384 r = 0;
Tomi Valkeinen39518352011-11-17 17:35:28 +02001385 goto err1;
Tomi Valkeinene4f7ad72011-11-16 16:01:33 +02001386 }
1387
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001388 if (ovl->manager == NULL || ovl->manager->device == NULL) {
1389 r = -EINVAL;
Tomi Valkeinen39518352011-11-17 17:35:28 +02001390 goto err1;
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001391 }
1392
1393 spin_lock_irqsave(&data_lock, flags);
1394
Tomi Valkeinen82153ed2011-11-26 14:26:46 +02001395 op->enabling = true;
1396
Tomi Valkeinen39518352011-11-17 17:35:28 +02001397 r = dss_check_settings(ovl->manager, ovl->manager->device);
Tomi Valkeinen39518352011-11-17 17:35:28 +02001398 if (r) {
1399 DSSERR("failed to enable overlay %d: check_settings failed\n",
1400 ovl->id);
1401 goto err2;
1402 }
1403
Tomi Valkeinen1d71f422011-11-16 16:44:08 +02001404 /* step 1: configure fifos/fifomerge for currently enabled ovls */
1405
1406 fifo_merge = get_use_fifo_merge();
1407 dss_setup_fifos(fifo_merge);
1408 dss_apply_fifo_merge(fifo_merge);
1409
1410 dss_write_regs();
1411 dss_set_go_bits();
1412
1413 spin_unlock_irqrestore(&data_lock, flags);
1414
1415 /* wait for fifo configs to go in */
1416 wait_pending_extra_info_updates();
1417
1418 /* step 2: enable the overlay */
1419 spin_lock_irqsave(&data_lock, flags);
Tomi Valkeinen6dc802e2011-11-16 14:28:12 +02001420
Tomi Valkeinen82153ed2011-11-26 14:26:46 +02001421 op->enabling = false;
1422 dss_apply_ovl_enable(ovl, true);
1423
Tomi Valkeinen75c94962011-11-15 18:25:23 +02001424 dss_write_regs();
Tomi Valkeinen3ab15b22011-11-25 17:32:20 +02001425 dss_set_go_bits();
Tomi Valkeinen75c94962011-11-15 18:25:23 +02001426
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001427 spin_unlock_irqrestore(&data_lock, flags);
1428
Tomi Valkeinen1d71f422011-11-16 16:44:08 +02001429 /* wait for overlay to be enabled */
1430 wait_pending_extra_info_updates();
1431
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001432 mutex_unlock(&apply_lock);
1433
1434 return 0;
Tomi Valkeinen39518352011-11-17 17:35:28 +02001435err2:
Tomi Valkeinen82153ed2011-11-26 14:26:46 +02001436 op->enabling = false;
Tomi Valkeinen39518352011-11-17 17:35:28 +02001437 spin_unlock_irqrestore(&data_lock, flags);
1438err1:
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001439 mutex_unlock(&apply_lock);
1440 return r;
1441}
1442
1443int dss_ovl_disable(struct omap_overlay *ovl)
1444{
1445 struct ovl_priv_data *op = get_ovl_priv(ovl);
1446 unsigned long flags;
Tomi Valkeinen1d71f422011-11-16 16:44:08 +02001447 bool fifo_merge;
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001448 int r;
1449
1450 mutex_lock(&apply_lock);
1451
Tomi Valkeinene4f7ad72011-11-16 16:01:33 +02001452 if (!op->enabled) {
1453 r = 0;
1454 goto err;
1455 }
1456
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001457 if (ovl->manager == NULL || ovl->manager->device == NULL) {
1458 r = -EINVAL;
1459 goto err;
1460 }
1461
Tomi Valkeinen1d71f422011-11-16 16:44:08 +02001462 /* step 1: disable the overlay */
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001463 spin_lock_irqsave(&data_lock, flags);
1464
Tomi Valkeinen841c09c2011-11-16 15:25:53 +02001465 dss_apply_ovl_enable(ovl, false);
Tomi Valkeinen1d71f422011-11-16 16:44:08 +02001466
Tomi Valkeinen75c94962011-11-15 18:25:23 +02001467 dss_write_regs();
Tomi Valkeinen3ab15b22011-11-25 17:32:20 +02001468 dss_set_go_bits();
Tomi Valkeinen75c94962011-11-15 18:25:23 +02001469
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001470 spin_unlock_irqrestore(&data_lock, flags);
1471
Tomi Valkeinen1d71f422011-11-16 16:44:08 +02001472 /* wait for the overlay to be disabled */
1473 wait_pending_extra_info_updates();
1474
1475 /* step 2: configure fifos/fifomerge */
1476 spin_lock_irqsave(&data_lock, flags);
1477
1478 fifo_merge = get_use_fifo_merge();
1479 dss_setup_fifos(fifo_merge);
1480 dss_apply_fifo_merge(fifo_merge);
1481
1482 dss_write_regs();
1483 dss_set_go_bits();
1484
1485 spin_unlock_irqrestore(&data_lock, flags);
1486
1487 /* wait for fifo config to go in */
1488 wait_pending_extra_info_updates();
1489
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001490 mutex_unlock(&apply_lock);
1491
1492 return 0;
1493
1494err:
1495 mutex_unlock(&apply_lock);
1496 return r;
1497}
1498