blob: 6f7b213e096ee9bfdf33d6fee605d99a58769f7e [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;
357
358 spin_lock_irqsave(&data_lock, flags);
359
360 updating = extra_info_update_ongoing();
361
362 if (!updating) {
363 spin_unlock_irqrestore(&data_lock, flags);
364 return;
365 }
366
367 init_completion(&extra_updated_completion);
368
369 spin_unlock_irqrestore(&data_lock, flags);
370
371 t = msecs_to_jiffies(500);
372 wait_for_completion_timeout(&extra_updated_completion, t);
373
374 updating = extra_info_update_ongoing();
375
376 WARN_ON(updating);
377}
378
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200379int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr)
380{
381 unsigned long timeout = msecs_to_jiffies(500);
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200382 struct mgr_priv_data *mp;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200383 u32 irq;
384 int r;
385 int i;
386 struct omap_dss_device *dssdev = mgr->device;
387
388 if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
389 return 0;
390
391 if (mgr_manual_update(mgr))
392 return 0;
393
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200394 irq = dispc_mgr_get_vsync_irq(mgr->id);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200395
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200396 mp = get_mgr_priv(mgr);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200397 i = 0;
398 while (1) {
399 unsigned long flags;
400 bool shadow_dirty, dirty;
401
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200402 spin_lock_irqsave(&data_lock, flags);
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200403 dirty = mp->info_dirty;
404 shadow_dirty = mp->shadow_info_dirty;
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200405 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200406
407 if (!dirty && !shadow_dirty) {
408 r = 0;
409 break;
410 }
411
412 /* 4 iterations is the worst case:
413 * 1 - initial iteration, dirty = true (between VFP and VSYNC)
414 * 2 - first VSYNC, dirty = true
415 * 3 - dirty = false, shadow_dirty = true
416 * 4 - shadow_dirty = false */
417 if (i++ == 3) {
418 DSSERR("mgr(%d)->wait_for_go() not finishing\n",
419 mgr->id);
420 r = 0;
421 break;
422 }
423
424 r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
425 if (r == -ERESTARTSYS)
426 break;
427
428 if (r) {
429 DSSERR("mgr(%d)->wait_for_go() timeout\n", mgr->id);
430 break;
431 }
432 }
433
434 return r;
435}
436
437int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl)
438{
439 unsigned long timeout = msecs_to_jiffies(500);
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200440 struct ovl_priv_data *op;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200441 struct omap_dss_device *dssdev;
442 u32 irq;
443 int r;
444 int i;
445
446 if (!ovl->manager)
447 return 0;
448
449 dssdev = ovl->manager->device;
450
451 if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
452 return 0;
453
454 if (ovl_manual_update(ovl))
455 return 0;
456
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200457 irq = dispc_mgr_get_vsync_irq(ovl->manager->id);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200458
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200459 op = get_ovl_priv(ovl);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200460 i = 0;
461 while (1) {
462 unsigned long flags;
463 bool shadow_dirty, dirty;
464
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200465 spin_lock_irqsave(&data_lock, flags);
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200466 dirty = op->info_dirty;
467 shadow_dirty = op->shadow_info_dirty;
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200468 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200469
470 if (!dirty && !shadow_dirty) {
471 r = 0;
472 break;
473 }
474
475 /* 4 iterations is the worst case:
476 * 1 - initial iteration, dirty = true (between VFP and VSYNC)
477 * 2 - first VSYNC, dirty = true
478 * 3 - dirty = false, shadow_dirty = true
479 * 4 - shadow_dirty = false */
480 if (i++ == 3) {
481 DSSERR("ovl(%d)->wait_for_go() not finishing\n",
482 ovl->id);
483 r = 0;
484 break;
485 }
486
487 r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
488 if (r == -ERESTARTSYS)
489 break;
490
491 if (r) {
492 DSSERR("ovl(%d)->wait_for_go() timeout\n", ovl->id);
493 break;
494 }
495 }
496
497 return r;
498}
499
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200500static void dss_ovl_write_regs(struct omap_overlay *ovl)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200501{
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200502 struct ovl_priv_data *op = get_ovl_priv(ovl);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200503 struct omap_overlay_info *oi;
504 bool ilace, replication;
Tomi Valkeinen34861372011-11-18 15:43:29 +0200505 struct mgr_priv_data *mp;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200506 int r;
507
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200508 DSSDBGF("%d", ovl->id);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200509
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200510 if (!op->enabled || !op->info_dirty)
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200511 return;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200512
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200513 oi = &op->info;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200514
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200515 replication = dss_use_replication(ovl->manager->device, oi->color_mode);
516
517 ilace = ovl->manager->device->type == OMAP_DISPLAY_TYPE_VENC;
518
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200519 r = dispc_ovl_setup(ovl->id, oi, ilace, replication);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200520 if (r) {
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200521 /*
522 * We can't do much here, as this function can be called from
523 * vsync interrupt.
524 */
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200525 DSSERR("dispc_ovl_setup failed for ovl %d\n", ovl->id);
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200526
527 /* This will leave fifo configurations in a nonoptimal state */
528 op->enabled = false;
529 dispc_ovl_enable(ovl->id, false);
530 return;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200531 }
532
Tomi Valkeinen34861372011-11-18 15:43:29 +0200533 mp = get_mgr_priv(ovl->manager);
534
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200535 op->info_dirty = false;
Tomi Valkeinen34861372011-11-18 15:43:29 +0200536 if (mp->updating)
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200537 op->shadow_info_dirty = true;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200538}
539
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200540static void dss_ovl_write_regs_extra(struct omap_overlay *ovl)
541{
542 struct ovl_priv_data *op = get_ovl_priv(ovl);
Tomi Valkeinen34861372011-11-18 15:43:29 +0200543 struct mgr_priv_data *mp;
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200544
545 DSSDBGF("%d", ovl->id);
546
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200547 if (!op->extra_info_dirty)
548 return;
549
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200550 /* note: write also when op->enabled == false, so that the ovl gets
551 * disabled */
552
553 dispc_ovl_enable(ovl->id, op->enabled);
Tomi Valkeinen5d5a97a2011-11-16 14:17:54 +0200554 dispc_ovl_set_channel_out(ovl->id, op->channel);
Tomi Valkeinen6dc802e2011-11-16 14:28:12 +0200555 dispc_ovl_set_fifo_threshold(ovl->id, op->fifo_low, op->fifo_high);
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200556
Tomi Valkeinen34861372011-11-18 15:43:29 +0200557 mp = get_mgr_priv(ovl->manager);
558
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200559 op->extra_info_dirty = false;
Tomi Valkeinen34861372011-11-18 15:43:29 +0200560 if (mp->updating)
561 op->shadow_extra_info_dirty = true;
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200562}
563
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200564static void dss_mgr_write_regs(struct omap_overlay_manager *mgr)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200565{
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200566 struct mgr_priv_data *mp = get_mgr_priv(mgr);
567 struct omap_overlay *ovl;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200568
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200569 DSSDBGF("%d", mgr->id);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200570
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200571 if (!mp->enabled)
572 return;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200573
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200574 WARN_ON(mp->busy);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200575
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200576 /* Commit overlay settings */
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200577 list_for_each_entry(ovl, &mgr->overlays, list) {
578 dss_ovl_write_regs(ovl);
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200579 dss_ovl_write_regs_extra(ovl);
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200580 }
581
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200582 if (mp->info_dirty) {
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200583 dispc_mgr_setup(mgr->id, &mp->info);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200584
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200585 mp->info_dirty = false;
Tomi Valkeinen34861372011-11-18 15:43:29 +0200586 if (mp->updating)
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200587 mp->shadow_info_dirty = true;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200588 }
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200589}
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200590
Tomi Valkeinenfb011972011-11-16 15:00:22 +0200591static void dss_write_regs_common(void)
592{
593 const int num_mgrs = omap_dss_get_num_overlay_managers();
594 int i;
595
596 if (!dss_data.fifo_merge_dirty)
597 return;
598
599 for (i = 0; i < num_mgrs; ++i) {
600 struct omap_overlay_manager *mgr;
601 struct mgr_priv_data *mp;
602
603 mgr = omap_dss_get_overlay_manager(i);
604 mp = get_mgr_priv(mgr);
605
606 if (mp->enabled) {
607 if (dss_data.fifo_merge_dirty) {
608 dispc_enable_fifomerge(dss_data.fifo_merge);
609 dss_data.fifo_merge_dirty = false;
610 }
611
612 if (mp->updating)
613 mp->shadow_info_dirty = true;
614 }
615 }
616}
617
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200618static void dss_write_regs(void)
619{
620 const int num_mgrs = omap_dss_get_num_overlay_managers();
621 int i;
622
Tomi Valkeinenfb011972011-11-16 15:00:22 +0200623 dss_write_regs_common();
624
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200625 for (i = 0; i < num_mgrs; ++i) {
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200626 struct omap_overlay_manager *mgr;
627 struct mgr_priv_data *mp;
Tomi Valkeinen39518352011-11-17 17:35:28 +0200628 int r;
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200629
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200630 mgr = omap_dss_get_overlay_manager(i);
631 mp = get_mgr_priv(mgr);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200632
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200633 if (!mp->enabled || mgr_manual_update(mgr) || mp->busy)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200634 continue;
635
Tomi Valkeinen39518352011-11-17 17:35:28 +0200636 r = dss_check_settings(mgr, mgr->device);
637 if (r) {
638 DSSERR("cannot write registers for manager %s: "
639 "illegal configuration\n", mgr->name);
640 continue;
641 }
642
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200643 dss_mgr_write_regs(mgr);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200644 }
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200645}
646
Tomi Valkeinen3ab15b22011-11-25 17:32:20 +0200647static void dss_set_go_bits(void)
648{
649 const int num_mgrs = omap_dss_get_num_overlay_managers();
650 int i;
651
652 for (i = 0; i < num_mgrs; ++i) {
653 struct omap_overlay_manager *mgr;
654 struct mgr_priv_data *mp;
655
656 mgr = omap_dss_get_overlay_manager(i);
657 mp = get_mgr_priv(mgr);
658
659 if (!mp->enabled || mgr_manual_update(mgr) || mp->busy)
660 continue;
661
662 if (!need_go(mgr))
663 continue;
664
665 mp->busy = true;
666
667 if (!dss_data.irq_enabled && need_isr())
668 dss_register_vsync_isr();
669
670 dispc_mgr_go(mgr->id);
671 }
672
673}
674
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200675void dss_mgr_start_update(struct omap_overlay_manager *mgr)
676{
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200677 struct mgr_priv_data *mp = get_mgr_priv(mgr);
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200678 unsigned long flags;
Tomi Valkeinen39518352011-11-17 17:35:28 +0200679 int r;
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200680
681 spin_lock_irqsave(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200682
Tomi Valkeinen34861372011-11-18 15:43:29 +0200683 WARN_ON(mp->updating);
684
Tomi Valkeinen39518352011-11-17 17:35:28 +0200685 r = dss_check_settings(mgr, mgr->device);
686 if (r) {
687 DSSERR("cannot start manual update: illegal configuration\n");
688 spin_unlock_irqrestore(&data_lock, flags);
689 return;
690 }
691
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200692 dss_mgr_write_regs(mgr);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200693
Tomi Valkeinenfb011972011-11-16 15:00:22 +0200694 dss_write_regs_common();
695
Tomi Valkeinen34861372011-11-18 15:43:29 +0200696 mp->updating = true;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200697
Tomi Valkeinen34861372011-11-18 15:43:29 +0200698 if (!dss_data.irq_enabled && need_isr())
699 dss_register_vsync_isr();
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200700
Tomi Valkeinen7797c6d2011-11-04 10:22:46 +0200701 dispc_mgr_enable(mgr->id, true);
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200702
703 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200704}
705
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200706static void dss_apply_irq_handler(void *data, u32 mask);
707
708static void dss_register_vsync_isr(void)
709{
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200710 const int num_mgrs = dss_feat_get_num_mgrs();
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200711 u32 mask;
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200712 int r, i;
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200713
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200714 mask = 0;
715 for (i = 0; i < num_mgrs; ++i)
716 mask |= dispc_mgr_get_vsync_irq(i);
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200717
Tomi Valkeinen34861372011-11-18 15:43:29 +0200718 for (i = 0; i < num_mgrs; ++i)
719 mask |= dispc_mgr_get_framedone_irq(i);
720
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200721 r = omap_dispc_register_isr(dss_apply_irq_handler, NULL, mask);
722 WARN_ON(r);
723
Tomi Valkeinend09c7aa2011-11-15 12:04:43 +0200724 dss_data.irq_enabled = true;
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200725}
726
727static void dss_unregister_vsync_isr(void)
728{
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200729 const int num_mgrs = dss_feat_get_num_mgrs();
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200730 u32 mask;
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200731 int r, i;
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200732
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200733 mask = 0;
734 for (i = 0; i < num_mgrs; ++i)
735 mask |= dispc_mgr_get_vsync_irq(i);
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200736
Tomi Valkeinen34861372011-11-18 15:43:29 +0200737 for (i = 0; i < num_mgrs; ++i)
738 mask |= dispc_mgr_get_framedone_irq(i);
739
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200740 r = omap_dispc_unregister_isr(dss_apply_irq_handler, NULL, mask);
741 WARN_ON(r);
742
Tomi Valkeinend09c7aa2011-11-15 12:04:43 +0200743 dss_data.irq_enabled = false;
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200744}
745
Tomi Valkeinen76098932011-11-16 12:03:22 +0200746static void mgr_clear_shadow_dirty(struct omap_overlay_manager *mgr)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200747{
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200748 struct omap_overlay *ovl;
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200749 struct mgr_priv_data *mp;
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200750 struct ovl_priv_data *op;
Tomi Valkeinen76098932011-11-16 12:03:22 +0200751
752 mp = get_mgr_priv(mgr);
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200753 mp->shadow_info_dirty = false;
Tomi Valkeinen76098932011-11-16 12:03:22 +0200754
755 list_for_each_entry(ovl, &mgr->overlays, list) {
756 op = get_ovl_priv(ovl);
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200757 op->shadow_info_dirty = false;
Tomi Valkeinen76098932011-11-16 12:03:22 +0200758 op->shadow_extra_info_dirty = false;
759 }
760}
761
762static void dss_apply_irq_handler(void *data, u32 mask)
763{
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200764 const int num_mgrs = dss_feat_get_num_mgrs();
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200765 int i;
Tomi Valkeinenf1577ce2011-11-16 14:37:48 +0200766 bool extra_updating;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200767
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200768 spin_lock(&data_lock);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200769
Tomi Valkeinen76098932011-11-16 12:03:22 +0200770 /* clear busy, updating flags, shadow_dirty flags */
Tomi Valkeinen43a972d2011-11-15 15:04:25 +0200771 for (i = 0; i < num_mgrs; i++) {
Tomi Valkeinen76098932011-11-16 12:03:22 +0200772 struct omap_overlay_manager *mgr;
773 struct mgr_priv_data *mp;
Tomi Valkeinen5b214172011-11-25 17:27:45 +0200774 bool was_updating;
Tomi Valkeinen76098932011-11-16 12:03:22 +0200775
Tomi Valkeinen43a972d2011-11-15 15:04:25 +0200776 mgr = omap_dss_get_overlay_manager(i);
777 mp = get_mgr_priv(mgr);
778
Tomi Valkeinen76098932011-11-16 12:03:22 +0200779 if (!mp->enabled)
Tomi Valkeinen43a972d2011-11-15 15:04:25 +0200780 continue;
781
Tomi Valkeinen5b214172011-11-25 17:27:45 +0200782 was_updating = mp->updating;
Tomi Valkeinen76098932011-11-16 12:03:22 +0200783 mp->updating = dispc_mgr_is_enabled(i);
Tomi Valkeinen43a972d2011-11-15 15:04:25 +0200784
Tomi Valkeinen76098932011-11-16 12:03:22 +0200785 if (!mgr_manual_update(mgr)) {
Tomi Valkeinen5b214172011-11-25 17:27:45 +0200786 bool was_busy = mp->busy;
Tomi Valkeinen76098932011-11-16 12:03:22 +0200787 mp->busy = dispc_mgr_go_busy(i);
788
Tomi Valkeinen5b214172011-11-25 17:27:45 +0200789 if (was_busy && !mp->busy)
Tomi Valkeinen76098932011-11-16 12:03:22 +0200790 mgr_clear_shadow_dirty(mgr);
791 } else {
Tomi Valkeinen5b214172011-11-25 17:27:45 +0200792 if (was_updating && !mp->updating)
Tomi Valkeinen76098932011-11-16 12:03:22 +0200793 mgr_clear_shadow_dirty(mgr);
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200794 }
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200795 }
796
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200797 dss_write_regs();
Tomi Valkeinen3ab15b22011-11-25 17:32:20 +0200798 dss_set_go_bits();
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200799
Tomi Valkeinenf1577ce2011-11-16 14:37:48 +0200800 extra_updating = extra_info_update_ongoing();
801 if (!extra_updating)
802 complete_all(&extra_updated_completion);
803
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200804 if (!need_isr())
805 dss_unregister_vsync_isr();
Tomi Valkeinen43a972d2011-11-15 15:04:25 +0200806
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200807 spin_unlock(&data_lock);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200808}
809
Tomi Valkeinen5738b632011-11-15 13:37:33 +0200810static void omap_dss_mgr_apply_ovl(struct omap_overlay *ovl)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200811{
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200812 struct ovl_priv_data *op;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200813
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200814 op = get_ovl_priv(ovl);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200815
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +0200816 if (!op->user_info_dirty)
Tomi Valkeinen5738b632011-11-15 13:37:33 +0200817 return;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200818
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +0200819 op->user_info_dirty = false;
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200820 op->info_dirty = true;
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +0200821 op->info = op->user_info;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200822}
823
824static void omap_dss_mgr_apply_mgr(struct omap_overlay_manager *mgr)
825{
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200826 struct mgr_priv_data *mp;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200827
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200828 mp = get_mgr_priv(mgr);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200829
Tomi Valkeinen388c4c62011-11-16 13:58:07 +0200830 if (!mp->user_info_dirty)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200831 return;
832
Tomi Valkeinen388c4c62011-11-16 13:58:07 +0200833 mp->user_info_dirty = false;
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200834 mp->info_dirty = true;
Tomi Valkeinen388c4c62011-11-16 13:58:07 +0200835 mp->info = mp->user_info;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200836}
837
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200838int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
839{
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200840 unsigned long flags;
Tomi Valkeinen07e327c2011-11-05 10:59:59 +0200841 struct omap_overlay *ovl;
Tomi Valkeinen39518352011-11-17 17:35:28 +0200842 int r;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200843
844 DSSDBG("omap_dss_mgr_apply(%s)\n", mgr->name);
845
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200846 spin_lock_irqsave(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200847
Tomi Valkeinen39518352011-11-17 17:35:28 +0200848 r = dss_check_settings_apply(mgr, mgr->device);
849 if (r) {
850 spin_unlock_irqrestore(&data_lock, flags);
851 DSSERR("failed to apply settings: illegal configuration.\n");
852 return r;
853 }
854
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200855 /* Configure overlays */
Tomi Valkeinen07e327c2011-11-05 10:59:59 +0200856 list_for_each_entry(ovl, &mgr->overlays, list)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200857 omap_dss_mgr_apply_ovl(ovl);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200858
859 /* Configure manager */
860 omap_dss_mgr_apply_mgr(mgr);
861
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200862 dss_write_regs();
Tomi Valkeinen3ab15b22011-11-25 17:32:20 +0200863 dss_set_go_bits();
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200864
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200865 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200866
Tomi Valkeinene70f98a2011-11-16 16:53:44 +0200867 return 0;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200868}
869
Tomi Valkeinen841c09c2011-11-16 15:25:53 +0200870static void dss_apply_ovl_enable(struct omap_overlay *ovl, bool enable)
871{
872 struct ovl_priv_data *op;
873
874 op = get_ovl_priv(ovl);
875
876 if (op->enabled == enable)
877 return;
878
879 op->enabled = enable;
880 op->extra_info_dirty = true;
881}
882
Tomi Valkeinen04576d42011-11-26 14:39:16 +0200883static void dss_apply_ovl_fifo_thresholds(struct omap_overlay *ovl,
884 u32 fifo_low, u32 fifo_high)
885{
886 struct ovl_priv_data *op = get_ovl_priv(ovl);
887
888 if (op->fifo_low == fifo_low && op->fifo_high == fifo_high)
889 return;
890
891 op->fifo_low = fifo_low;
892 op->fifo_high = fifo_high;
893 op->extra_info_dirty = true;
894}
895
Tomi Valkeinenfb011972011-11-16 15:00:22 +0200896static void dss_apply_fifo_merge(bool use_fifo_merge)
897{
898 if (dss_data.fifo_merge == use_fifo_merge)
899 return;
900
901 dss_data.fifo_merge = use_fifo_merge;
902 dss_data.fifo_merge_dirty = true;
903}
904
Tomi Valkeinen1d71f422011-11-16 16:44:08 +0200905static void dss_ovl_setup_fifo(struct omap_overlay *ovl,
906 bool use_fifo_merge)
Tomi Valkeinen6dc802e2011-11-16 14:28:12 +0200907{
908 struct ovl_priv_data *op = get_ovl_priv(ovl);
909 struct omap_dss_device *dssdev;
910 u32 size, burst_size;
911 u32 fifo_low, fifo_high;
912
Tomi Valkeinen75ae1182011-11-26 14:36:19 +0200913 if (!op->enabled && !op->enabling)
914 return;
915
Tomi Valkeinen6dc802e2011-11-16 14:28:12 +0200916 dssdev = ovl->manager->device;
917
Tomi Valkeinen1d71f422011-11-16 16:44:08 +0200918 if (use_fifo_merge) {
919 int i;
920
921 size = 0;
922
923 for (i = 0; i < omap_dss_get_num_overlays(); ++i)
924 size += dispc_ovl_get_fifo_size(i);
925 } else {
926 size = dispc_ovl_get_fifo_size(ovl->id);
927 }
Tomi Valkeinen6dc802e2011-11-16 14:28:12 +0200928
929 burst_size = dispc_ovl_get_burst_size(ovl->id);
930
931 switch (dssdev->type) {
932 case OMAP_DISPLAY_TYPE_DPI:
933 case OMAP_DISPLAY_TYPE_DBI:
934 case OMAP_DISPLAY_TYPE_SDI:
935 case OMAP_DISPLAY_TYPE_VENC:
936 case OMAP_DISPLAY_TYPE_HDMI:
937 default_get_overlay_fifo_thresholds(ovl->id, size,
938 burst_size, &fifo_low, &fifo_high);
939 break;
940#ifdef CONFIG_OMAP2_DSS_DSI
941 case OMAP_DISPLAY_TYPE_DSI:
942 dsi_get_overlay_fifo_thresholds(ovl->id, size,
943 burst_size, &fifo_low, &fifo_high);
944 break;
945#endif
946 default:
947 BUG();
948 }
949
Tomi Valkeinen04576d42011-11-26 14:39:16 +0200950 dss_apply_ovl_fifo_thresholds(ovl, fifo_low, fifo_high);
Tomi Valkeinen6dc802e2011-11-16 14:28:12 +0200951}
952
Tomi Valkeinen1d71f422011-11-16 16:44:08 +0200953static void dss_mgr_setup_fifos(struct omap_overlay_manager *mgr,
954 bool use_fifo_merge)
Tomi Valkeinen6dc802e2011-11-16 14:28:12 +0200955{
956 struct omap_overlay *ovl;
Tomi Valkeinen6dc802e2011-11-16 14:28:12 +0200957 struct mgr_priv_data *mp;
958
959 mp = get_mgr_priv(mgr);
960
961 if (!mp->enabled)
962 return;
963
Tomi Valkeinen75ae1182011-11-26 14:36:19 +0200964 list_for_each_entry(ovl, &mgr->overlays, list)
Tomi Valkeinen1d71f422011-11-16 16:44:08 +0200965 dss_ovl_setup_fifo(ovl, use_fifo_merge);
Tomi Valkeinen75ae1182011-11-26 14:36:19 +0200966}
967
Tomi Valkeinen1d71f422011-11-16 16:44:08 +0200968static void dss_setup_fifos(bool use_fifo_merge)
Tomi Valkeinen75ae1182011-11-26 14:36:19 +0200969{
970 const int num_mgrs = omap_dss_get_num_overlay_managers();
971 struct omap_overlay_manager *mgr;
972 int i;
973
974 for (i = 0; i < num_mgrs; ++i) {
975 mgr = omap_dss_get_overlay_manager(i);
Tomi Valkeinen1d71f422011-11-16 16:44:08 +0200976 dss_mgr_setup_fifos(mgr, use_fifo_merge);
Tomi Valkeinen6dc802e2011-11-16 14:28:12 +0200977 }
978}
979
Tomi Valkeinen1d71f422011-11-16 16:44:08 +0200980static int get_num_used_managers(void)
981{
982 const int num_mgrs = omap_dss_get_num_overlay_managers();
983 struct omap_overlay_manager *mgr;
984 struct mgr_priv_data *mp;
985 int i;
986 int enabled_mgrs;
987
988 enabled_mgrs = 0;
989
990 for (i = 0; i < num_mgrs; ++i) {
991 mgr = omap_dss_get_overlay_manager(i);
992 mp = get_mgr_priv(mgr);
993
994 if (!mp->enabled)
995 continue;
996
997 enabled_mgrs++;
998 }
999
1000 return enabled_mgrs;
1001}
1002
1003static int get_num_used_overlays(void)
1004{
1005 const int num_ovls = omap_dss_get_num_overlays();
1006 struct omap_overlay *ovl;
1007 struct ovl_priv_data *op;
1008 struct mgr_priv_data *mp;
1009 int i;
1010 int enabled_ovls;
1011
1012 enabled_ovls = 0;
1013
1014 for (i = 0; i < num_ovls; ++i) {
1015 ovl = omap_dss_get_overlay(i);
1016 op = get_ovl_priv(ovl);
1017
1018 if (!op->enabled && !op->enabling)
1019 continue;
1020
1021 mp = get_mgr_priv(ovl->manager);
1022
1023 if (!mp->enabled)
1024 continue;
1025
1026 enabled_ovls++;
1027 }
1028
1029 return enabled_ovls;
1030}
1031
1032static bool get_use_fifo_merge(void)
1033{
1034 int enabled_mgrs = get_num_used_managers();
1035 int enabled_ovls = get_num_used_overlays();
1036
1037 if (!dss_has_feature(FEAT_FIFO_MERGE))
1038 return false;
1039
1040 /*
1041 * In theory the only requirement for fifomerge is enabled_ovls <= 1.
1042 * However, if we have two managers enabled and set/unset the fifomerge,
1043 * we need to set the GO bits in particular sequence for the managers,
1044 * and wait in between.
1045 *
1046 * This is rather difficult as new apply calls can happen at any time,
1047 * so we simplify the problem by requiring also that enabled_mgrs <= 1.
1048 * In practice this shouldn't matter, because when only one overlay is
1049 * enabled, most likely only one output is enabled.
1050 */
1051
1052 return enabled_mgrs <= 1 && enabled_ovls <= 1;
1053}
1054
Tomi Valkeinen2a4ee7e2011-11-21 13:34:48 +02001055int dss_mgr_enable(struct omap_overlay_manager *mgr)
Tomi Valkeinen7797c6d2011-11-04 10:22:46 +02001056{
Tomi Valkeinenbf213522011-11-15 14:43:53 +02001057 struct mgr_priv_data *mp = get_mgr_priv(mgr);
1058 unsigned long flags;
Tomi Valkeinen39518352011-11-17 17:35:28 +02001059 int r;
Tomi Valkeinen1d71f422011-11-16 16:44:08 +02001060 bool fifo_merge;
Tomi Valkeinenbf213522011-11-15 14:43:53 +02001061
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001062 mutex_lock(&apply_lock);
1063
Tomi Valkeinene4f7ad72011-11-16 16:01:33 +02001064 if (mp->enabled)
1065 goto out;
1066
Tomi Valkeinenbf213522011-11-15 14:43:53 +02001067 spin_lock_irqsave(&data_lock, flags);
1068
1069 mp->enabled = true;
Tomi Valkeinena6b24f82011-11-26 14:29:39 +02001070
Tomi Valkeinen39518352011-11-17 17:35:28 +02001071 r = dss_check_settings(mgr, mgr->device);
Tomi Valkeinen39518352011-11-17 17:35:28 +02001072 if (r) {
1073 DSSERR("failed to enable manager %d: check_settings failed\n",
1074 mgr->id);
Tomi Valkeinen2a4ee7e2011-11-21 13:34:48 +02001075 goto err;
Tomi Valkeinen39518352011-11-17 17:35:28 +02001076 }
1077
Tomi Valkeinen1d71f422011-11-16 16:44:08 +02001078 /* step 1: setup fifos/fifomerge before enabling the manager */
1079
1080 fifo_merge = get_use_fifo_merge();
1081 dss_setup_fifos(fifo_merge);
1082 dss_apply_fifo_merge(fifo_merge);
Tomi Valkeinen6dc802e2011-11-16 14:28:12 +02001083
Tomi Valkeinen75c94962011-11-15 18:25:23 +02001084 dss_write_regs();
Tomi Valkeinen3ab15b22011-11-25 17:32:20 +02001085 dss_set_go_bits();
Tomi Valkeinen75c94962011-11-15 18:25:23 +02001086
Tomi Valkeinen1d71f422011-11-16 16:44:08 +02001087 spin_unlock_irqrestore(&data_lock, flags);
1088
1089 /* wait until fifo config is in */
1090 wait_pending_extra_info_updates();
1091
1092 /* step 2: enable the manager */
1093 spin_lock_irqsave(&data_lock, flags);
1094
Tomi Valkeinen34861372011-11-18 15:43:29 +02001095 if (!mgr_manual_update(mgr))
1096 mp->updating = true;
1097
Tomi Valkeinenbf213522011-11-15 14:43:53 +02001098 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001099
Tomi Valkeinen75c94962011-11-15 18:25:23 +02001100 if (!mgr_manual_update(mgr))
1101 dispc_mgr_enable(mgr->id, true);
1102
Tomi Valkeinene4f7ad72011-11-16 16:01:33 +02001103out:
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001104 mutex_unlock(&apply_lock);
Tomi Valkeinen2a4ee7e2011-11-21 13:34:48 +02001105
1106 return 0;
1107
1108err:
Tomi Valkeinena6b24f82011-11-26 14:29:39 +02001109 mp->enabled = false;
Tomi Valkeinen2a4ee7e2011-11-21 13:34:48 +02001110 spin_unlock_irqrestore(&data_lock, flags);
1111 mutex_unlock(&apply_lock);
1112 return r;
Tomi Valkeinen7797c6d2011-11-04 10:22:46 +02001113}
1114
1115void dss_mgr_disable(struct omap_overlay_manager *mgr)
1116{
Tomi Valkeinenbf213522011-11-15 14:43:53 +02001117 struct mgr_priv_data *mp = get_mgr_priv(mgr);
1118 unsigned long flags;
Tomi Valkeinen1d71f422011-11-16 16:44:08 +02001119 bool fifo_merge;
Tomi Valkeinenbf213522011-11-15 14:43:53 +02001120
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001121 mutex_lock(&apply_lock);
1122
Tomi Valkeinene4f7ad72011-11-16 16:01:33 +02001123 if (!mp->enabled)
1124 goto out;
1125
Tomi Valkeinen9a147a62011-11-09 15:30:11 +02001126 if (!mgr_manual_update(mgr))
1127 dispc_mgr_enable(mgr->id, false);
Tomi Valkeinenbf213522011-11-15 14:43:53 +02001128
1129 spin_lock_irqsave(&data_lock, flags);
1130
Tomi Valkeinen34861372011-11-18 15:43:29 +02001131 mp->updating = false;
Tomi Valkeinenbf213522011-11-15 14:43:53 +02001132 mp->enabled = false;
1133
Tomi Valkeinen1d71f422011-11-16 16:44:08 +02001134 fifo_merge = get_use_fifo_merge();
1135 dss_setup_fifos(fifo_merge);
1136 dss_apply_fifo_merge(fifo_merge);
1137
1138 dss_write_regs();
1139 dss_set_go_bits();
1140
Tomi Valkeinenbf213522011-11-15 14:43:53 +02001141 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001142
Tomi Valkeinen1d71f422011-11-16 16:44:08 +02001143 wait_pending_extra_info_updates();
Tomi Valkeinene4f7ad72011-11-16 16:01:33 +02001144out:
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001145 mutex_unlock(&apply_lock);
Tomi Valkeinen7797c6d2011-11-04 10:22:46 +02001146}
1147
Tomi Valkeineneb70d732011-11-15 12:15:18 +02001148int dss_mgr_set_info(struct omap_overlay_manager *mgr,
1149 struct omap_overlay_manager_info *info)
1150{
Tomi Valkeinen388c4c62011-11-16 13:58:07 +02001151 struct mgr_priv_data *mp = get_mgr_priv(mgr);
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +02001152 unsigned long flags;
Tomi Valkeinenf17d04f2011-11-17 14:31:09 +02001153 int r;
1154
1155 r = dss_mgr_simple_check(mgr, info);
1156 if (r)
1157 return r;
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +02001158
1159 spin_lock_irqsave(&data_lock, flags);
1160
Tomi Valkeinen388c4c62011-11-16 13:58:07 +02001161 mp->user_info = *info;
1162 mp->user_info_dirty = true;
Tomi Valkeineneb70d732011-11-15 12:15:18 +02001163
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +02001164 spin_unlock_irqrestore(&data_lock, flags);
1165
Tomi Valkeineneb70d732011-11-15 12:15:18 +02001166 return 0;
1167}
1168
1169void dss_mgr_get_info(struct omap_overlay_manager *mgr,
1170 struct omap_overlay_manager_info *info)
1171{
Tomi Valkeinen388c4c62011-11-16 13:58:07 +02001172 struct mgr_priv_data *mp = get_mgr_priv(mgr);
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +02001173 unsigned long flags;
1174
1175 spin_lock_irqsave(&data_lock, flags);
1176
Tomi Valkeinen388c4c62011-11-16 13:58:07 +02001177 *info = mp->user_info;
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +02001178
1179 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeineneb70d732011-11-15 12:15:18 +02001180}
1181
1182int dss_mgr_set_device(struct omap_overlay_manager *mgr,
1183 struct omap_dss_device *dssdev)
1184{
1185 int r;
Tomi Valkeineneb70d732011-11-15 12:15:18 +02001186
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001187 mutex_lock(&apply_lock);
1188
Tomi Valkeineneb70d732011-11-15 12:15:18 +02001189 if (dssdev->manager) {
1190 DSSERR("display '%s' already has a manager '%s'\n",
1191 dssdev->name, dssdev->manager->name);
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001192 r = -EINVAL;
1193 goto err;
Tomi Valkeineneb70d732011-11-15 12:15:18 +02001194 }
1195
1196 if ((mgr->supported_displays & dssdev->type) == 0) {
1197 DSSERR("display '%s' does not support manager '%s'\n",
1198 dssdev->name, mgr->name);
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001199 r = -EINVAL;
1200 goto err;
Tomi Valkeineneb70d732011-11-15 12:15:18 +02001201 }
1202
Tomi Valkeineneb70d732011-11-15 12:15:18 +02001203 dssdev->manager = mgr;
1204 mgr->device = dssdev;
Tomi Valkeineneb70d732011-11-15 12:15:18 +02001205
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001206 mutex_unlock(&apply_lock);
1207
Tomi Valkeineneb70d732011-11-15 12:15:18 +02001208 return 0;
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001209err:
1210 mutex_unlock(&apply_lock);
1211 return r;
Tomi Valkeineneb70d732011-11-15 12:15:18 +02001212}
1213
1214int dss_mgr_unset_device(struct omap_overlay_manager *mgr)
1215{
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001216 int r;
1217
1218 mutex_lock(&apply_lock);
1219
Tomi Valkeineneb70d732011-11-15 12:15:18 +02001220 if (!mgr->device) {
1221 DSSERR("failed to unset display, display not set.\n");
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001222 r = -EINVAL;
1223 goto err;
Tomi Valkeineneb70d732011-11-15 12:15:18 +02001224 }
1225
1226 /*
1227 * Don't allow currently enabled displays to have the overlay manager
1228 * pulled out from underneath them
1229 */
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001230 if (mgr->device->state != OMAP_DSS_DISPLAY_DISABLED) {
1231 r = -EINVAL;
1232 goto err;
1233 }
Tomi Valkeineneb70d732011-11-15 12:15:18 +02001234
1235 mgr->device->manager = NULL;
1236 mgr->device = NULL;
Tomi Valkeineneb70d732011-11-15 12:15:18 +02001237
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001238 mutex_unlock(&apply_lock);
1239
Tomi Valkeineneb70d732011-11-15 12:15:18 +02001240 return 0;
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001241err:
1242 mutex_unlock(&apply_lock);
1243 return r;
Tomi Valkeineneb70d732011-11-15 12:15:18 +02001244}
1245
1246
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001247int dss_ovl_set_info(struct omap_overlay *ovl,
1248 struct omap_overlay_info *info)
1249{
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +02001250 struct ovl_priv_data *op = get_ovl_priv(ovl);
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +02001251 unsigned long flags;
Tomi Valkeinenfcc764d2011-11-17 14:26:48 +02001252 int r;
1253
1254 r = dss_ovl_simple_check(ovl, info);
1255 if (r)
1256 return r;
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +02001257
1258 spin_lock_irqsave(&data_lock, flags);
1259
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +02001260 op->user_info = *info;
1261 op->user_info_dirty = true;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001262
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +02001263 spin_unlock_irqrestore(&data_lock, flags);
1264
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001265 return 0;
1266}
1267
1268void dss_ovl_get_info(struct omap_overlay *ovl,
1269 struct omap_overlay_info *info)
1270{
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +02001271 struct ovl_priv_data *op = get_ovl_priv(ovl);
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +02001272 unsigned long flags;
1273
1274 spin_lock_irqsave(&data_lock, flags);
1275
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +02001276 *info = op->user_info;
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +02001277
1278 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001279}
1280
1281int dss_ovl_set_manager(struct omap_overlay *ovl,
1282 struct omap_overlay_manager *mgr)
1283{
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001284 struct ovl_priv_data *op = get_ovl_priv(ovl);
1285 unsigned long flags;
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001286 int r;
1287
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001288 if (!mgr)
1289 return -EINVAL;
1290
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001291 mutex_lock(&apply_lock);
1292
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001293 if (ovl->manager) {
1294 DSSERR("overlay '%s' already has a manager '%s'\n",
1295 ovl->name, ovl->manager->name);
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001296 r = -EINVAL;
1297 goto err;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001298 }
1299
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001300 spin_lock_irqsave(&data_lock, flags);
1301
1302 if (op->enabled) {
1303 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001304 DSSERR("overlay has to be disabled to change the manager\n");
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001305 r = -EINVAL;
1306 goto err;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001307 }
1308
Tomi Valkeinen5d5a97a2011-11-16 14:17:54 +02001309 op->channel = mgr->id;
1310 op->extra_info_dirty = true;
1311
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001312 ovl->manager = mgr;
1313 list_add_tail(&ovl->list, &mgr->overlays);
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001314
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001315 spin_unlock_irqrestore(&data_lock, flags);
1316
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001317 /* XXX: When there is an overlay on a DSI manual update display, and
1318 * the overlay is first disabled, then moved to tv, and enabled, we
1319 * seem to get SYNC_LOST_DIGIT error.
1320 *
1321 * Waiting doesn't seem to help, but updating the manual update display
1322 * after disabling the overlay seems to fix this. This hints that the
1323 * overlay is perhaps somehow tied to the LCD output until the output
1324 * is updated.
1325 *
1326 * Userspace workaround for this is to update the LCD after disabling
1327 * the overlay, but before moving the overlay to TV.
1328 */
1329
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001330 mutex_unlock(&apply_lock);
1331
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001332 return 0;
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001333err:
1334 mutex_unlock(&apply_lock);
1335 return r;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001336}
1337
1338int dss_ovl_unset_manager(struct omap_overlay *ovl)
1339{
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001340 struct ovl_priv_data *op = get_ovl_priv(ovl);
1341 unsigned long flags;
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001342 int r;
1343
1344 mutex_lock(&apply_lock);
1345
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001346 if (!ovl->manager) {
1347 DSSERR("failed to detach overlay: manager not set\n");
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001348 r = -EINVAL;
1349 goto err;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001350 }
1351
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001352 spin_lock_irqsave(&data_lock, flags);
1353
1354 if (op->enabled) {
1355 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001356 DSSERR("overlay has to be disabled to unset the manager\n");
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001357 r = -EINVAL;
1358 goto err;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001359 }
1360
Tomi Valkeinen5d5a97a2011-11-16 14:17:54 +02001361 op->channel = -1;
1362
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001363 ovl->manager = NULL;
1364 list_del(&ovl->list);
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001365
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001366 spin_unlock_irqrestore(&data_lock, flags);
1367
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001368 mutex_unlock(&apply_lock);
1369
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001370 return 0;
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001371err:
1372 mutex_unlock(&apply_lock);
1373 return r;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001374}
1375
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001376bool dss_ovl_is_enabled(struct omap_overlay *ovl)
1377{
1378 struct ovl_priv_data *op = get_ovl_priv(ovl);
1379 unsigned long flags;
1380 bool e;
1381
1382 spin_lock_irqsave(&data_lock, flags);
1383
1384 e = op->enabled;
1385
1386 spin_unlock_irqrestore(&data_lock, flags);
1387
1388 return e;
1389}
1390
1391int dss_ovl_enable(struct omap_overlay *ovl)
1392{
1393 struct ovl_priv_data *op = get_ovl_priv(ovl);
1394 unsigned long flags;
Tomi Valkeinen1d71f422011-11-16 16:44:08 +02001395 bool fifo_merge;
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001396 int r;
1397
1398 mutex_lock(&apply_lock);
1399
Tomi Valkeinene4f7ad72011-11-16 16:01:33 +02001400 if (op->enabled) {
1401 r = 0;
Tomi Valkeinen39518352011-11-17 17:35:28 +02001402 goto err1;
Tomi Valkeinene4f7ad72011-11-16 16:01:33 +02001403 }
1404
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001405 if (ovl->manager == NULL || ovl->manager->device == NULL) {
1406 r = -EINVAL;
Tomi Valkeinen39518352011-11-17 17:35:28 +02001407 goto err1;
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001408 }
1409
1410 spin_lock_irqsave(&data_lock, flags);
1411
Tomi Valkeinen82153ed2011-11-26 14:26:46 +02001412 op->enabling = true;
1413
Tomi Valkeinen39518352011-11-17 17:35:28 +02001414 r = dss_check_settings(ovl->manager, ovl->manager->device);
Tomi Valkeinen39518352011-11-17 17:35:28 +02001415 if (r) {
1416 DSSERR("failed to enable overlay %d: check_settings failed\n",
1417 ovl->id);
1418 goto err2;
1419 }
1420
Tomi Valkeinen1d71f422011-11-16 16:44:08 +02001421 /* step 1: configure fifos/fifomerge for currently enabled ovls */
1422
1423 fifo_merge = get_use_fifo_merge();
1424 dss_setup_fifos(fifo_merge);
1425 dss_apply_fifo_merge(fifo_merge);
1426
1427 dss_write_regs();
1428 dss_set_go_bits();
1429
1430 spin_unlock_irqrestore(&data_lock, flags);
1431
1432 /* wait for fifo configs to go in */
1433 wait_pending_extra_info_updates();
1434
1435 /* step 2: enable the overlay */
1436 spin_lock_irqsave(&data_lock, flags);
Tomi Valkeinen6dc802e2011-11-16 14:28:12 +02001437
Tomi Valkeinen82153ed2011-11-26 14:26:46 +02001438 op->enabling = false;
1439 dss_apply_ovl_enable(ovl, true);
1440
Tomi Valkeinen75c94962011-11-15 18:25:23 +02001441 dss_write_regs();
Tomi Valkeinen3ab15b22011-11-25 17:32:20 +02001442 dss_set_go_bits();
Tomi Valkeinen75c94962011-11-15 18:25:23 +02001443
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001444 spin_unlock_irqrestore(&data_lock, flags);
1445
Tomi Valkeinen1d71f422011-11-16 16:44:08 +02001446 /* wait for overlay to be enabled */
1447 wait_pending_extra_info_updates();
1448
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001449 mutex_unlock(&apply_lock);
1450
1451 return 0;
Tomi Valkeinen39518352011-11-17 17:35:28 +02001452err2:
Tomi Valkeinen82153ed2011-11-26 14:26:46 +02001453 op->enabling = false;
Tomi Valkeinen39518352011-11-17 17:35:28 +02001454 spin_unlock_irqrestore(&data_lock, flags);
1455err1:
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001456 mutex_unlock(&apply_lock);
1457 return r;
1458}
1459
1460int dss_ovl_disable(struct omap_overlay *ovl)
1461{
1462 struct ovl_priv_data *op = get_ovl_priv(ovl);
1463 unsigned long flags;
Tomi Valkeinen1d71f422011-11-16 16:44:08 +02001464 bool fifo_merge;
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001465 int r;
1466
1467 mutex_lock(&apply_lock);
1468
Tomi Valkeinene4f7ad72011-11-16 16:01:33 +02001469 if (!op->enabled) {
1470 r = 0;
1471 goto err;
1472 }
1473
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001474 if (ovl->manager == NULL || ovl->manager->device == NULL) {
1475 r = -EINVAL;
1476 goto err;
1477 }
1478
Tomi Valkeinen1d71f422011-11-16 16:44:08 +02001479 /* step 1: disable the overlay */
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001480 spin_lock_irqsave(&data_lock, flags);
1481
Tomi Valkeinen841c09c2011-11-16 15:25:53 +02001482 dss_apply_ovl_enable(ovl, false);
Tomi Valkeinen1d71f422011-11-16 16:44:08 +02001483
Tomi Valkeinen75c94962011-11-15 18:25:23 +02001484 dss_write_regs();
Tomi Valkeinen3ab15b22011-11-25 17:32:20 +02001485 dss_set_go_bits();
Tomi Valkeinen75c94962011-11-15 18:25:23 +02001486
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001487 spin_unlock_irqrestore(&data_lock, flags);
1488
Tomi Valkeinen1d71f422011-11-16 16:44:08 +02001489 /* wait for the overlay to be disabled */
1490 wait_pending_extra_info_updates();
1491
1492 /* step 2: configure fifos/fifomerge */
1493 spin_lock_irqsave(&data_lock, flags);
1494
1495 fifo_merge = get_use_fifo_merge();
1496 dss_setup_fifos(fifo_merge);
1497 dss_apply_fifo_merge(fifo_merge);
1498
1499 dss_write_regs();
1500 dss_set_go_bits();
1501
1502 spin_unlock_irqrestore(&data_lock, flags);
1503
1504 /* wait for fifo config to go in */
1505 wait_pending_extra_info_updates();
1506
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001507 mutex_unlock(&apply_lock);
1508
1509 return 0;
1510
1511err:
1512 mutex_unlock(&apply_lock);
1513 return r;
1514}
1515