blob: 6f60d0e0b7ee5edd490436e86332bcb1fa165275 [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>
Tomi Valkeinen8dd24912012-10-10 10:26:45 +030021#include <linux/module.h>
Tomi Valkeinen58f255482011-11-04 09:48:54 +020022#include <linux/slab.h>
23#include <linux/spinlock.h>
24#include <linux/jiffies.h>
25
26#include <video/omapdss.h>
27
28#include "dss.h"
29#include "dss_features.h"
30
31/*
32 * We have 4 levels of cache for the dispc settings. First two are in SW and
33 * the latter two in HW.
34 *
Tomi Valkeinen0b53f172011-11-16 14:31:58 +020035 * set_info()
36 * v
Tomi Valkeinen58f255482011-11-04 09:48:54 +020037 * +--------------------+
Tomi Valkeinen0b53f172011-11-16 14:31:58 +020038 * | user_info |
Tomi Valkeinen58f255482011-11-04 09:48:54 +020039 * +--------------------+
40 * v
41 * apply()
42 * v
43 * +--------------------+
Tomi Valkeinend09c7aa2011-11-15 12:04:43 +020044 * | info |
Tomi Valkeinen58f255482011-11-04 09:48:54 +020045 * +--------------------+
46 * v
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +020047 * write_regs()
Tomi Valkeinen58f255482011-11-04 09:48:54 +020048 * v
49 * +--------------------+
50 * | shadow registers |
51 * +--------------------+
52 * v
53 * VFP or lcd/digit_enable
54 * v
55 * +--------------------+
56 * | registers |
57 * +--------------------+
58 */
59
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +020060struct ovl_priv_data {
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +020061
62 bool user_info_dirty;
63 struct omap_overlay_info user_info;
64
Tomi Valkeinen0b53f172011-11-16 14:31:58 +020065 bool info_dirty;
Tomi Valkeinen58f255482011-11-04 09:48:54 +020066 struct omap_overlay_info info;
67
Tomi Valkeinen0b53f172011-11-16 14:31:58 +020068 bool shadow_info_dirty;
69
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +020070 bool extra_info_dirty;
71 bool shadow_extra_info_dirty;
72
73 bool enabled;
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;
Archit Taneja45324a22012-04-26 19:31:22 +0530102
103 bool extra_info_dirty;
104 bool shadow_extra_info_dirty;
105
106 struct omap_video_timings timings;
Archit Tanejaf476ae92012-06-29 14:37:03 +0530107 struct dss_lcd_mgr_config lcd_config;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200108};
109
110static struct {
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200111 struct ovl_priv_data ovl_priv_data_array[MAX_DSS_OVERLAYS];
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200112 struct mgr_priv_data mgr_priv_data_array[MAX_DSS_MANAGERS];
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200113
114 bool irq_enabled;
Tomi Valkeinend09c7aa2011-11-15 12:04:43 +0200115} dss_data;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200116
Tomi Valkeinend09c7aa2011-11-15 12:04:43 +0200117/* protects dss_data */
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200118static spinlock_t data_lock;
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200119/* lock for blocking functions */
120static DEFINE_MUTEX(apply_lock);
Tomi Valkeinenf1577ce2011-11-16 14:37:48 +0200121static DECLARE_COMPLETION(extra_updated_completion);
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200122
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200123static void dss_register_vsync_isr(void);
124
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200125static struct ovl_priv_data *get_ovl_priv(struct omap_overlay *ovl)
126{
Tomi Valkeinend09c7aa2011-11-15 12:04:43 +0200127 return &dss_data.ovl_priv_data_array[ovl->id];
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200128}
129
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200130static struct mgr_priv_data *get_mgr_priv(struct omap_overlay_manager *mgr)
131{
Tomi Valkeinend09c7aa2011-11-15 12:04:43 +0200132 return &dss_data.mgr_priv_data_array[mgr->id];
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200133}
134
Tomi Valkeinen8dd24912012-10-10 10:26:45 +0300135static void apply_init_priv(void)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200136{
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +0200137 const int num_ovls = dss_feat_get_num_ovls();
Archit Tanejaf476ae92012-06-29 14:37:03 +0530138 struct mgr_priv_data *mp;
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +0200139 int i;
140
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200141 spin_lock_init(&data_lock);
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +0200142
143 for (i = 0; i < num_ovls; ++i) {
144 struct ovl_priv_data *op;
145
146 op = &dss_data.ovl_priv_data_array[i];
147
148 op->info.global_alpha = 255;
149
150 switch (i) {
151 case 0:
152 op->info.zorder = 0;
153 break;
154 case 1:
155 op->info.zorder =
156 dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 3 : 0;
157 break;
158 case 2:
159 op->info.zorder =
160 dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 2 : 0;
161 break;
162 case 3:
163 op->info.zorder =
164 dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 1 : 0;
165 break;
166 }
167
168 op->user_info = op->info;
169 }
Archit Tanejaf476ae92012-06-29 14:37:03 +0530170
171 /*
172 * Initialize some of the lcd_config fields for TV manager, this lets
173 * us prevent checking if the manager is LCD or TV at some places
174 */
175 mp = &dss_data.mgr_priv_data_array[OMAP_DSS_CHANNEL_DIGIT];
176
177 mp->lcd_config.video_port_width = 24;
178 mp->lcd_config.clock_info.lck_div = 1;
179 mp->lcd_config.clock_info.pck_div = 1;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200180}
181
Archit Taneja75bac5d2012-05-24 15:08:54 +0530182/*
183 * A LCD manager's stallmode decides whether it is in manual or auto update. TV
184 * manager is always auto update, stallmode field for TV manager is false by
185 * default
186 */
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200187static bool ovl_manual_update(struct omap_overlay *ovl)
188{
Archit Taneja75bac5d2012-05-24 15:08:54 +0530189 struct mgr_priv_data *mp = get_mgr_priv(ovl->manager);
190
191 return mp->lcd_config.stallmode;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200192}
193
194static bool mgr_manual_update(struct omap_overlay_manager *mgr)
195{
Archit Taneja75bac5d2012-05-24 15:08:54 +0530196 struct mgr_priv_data *mp = get_mgr_priv(mgr);
197
198 return mp->lcd_config.stallmode;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200199}
200
Tomi Valkeinen39518352011-11-17 17:35:28 +0200201static int dss_check_settings_low(struct omap_overlay_manager *mgr,
Archit Taneja228b2132012-04-27 01:22:28 +0530202 bool applying)
Tomi Valkeinen39518352011-11-17 17:35:28 +0200203{
204 struct omap_overlay_info *oi;
205 struct omap_overlay_manager_info *mi;
206 struct omap_overlay *ovl;
207 struct omap_overlay_info *ois[MAX_DSS_OVERLAYS];
208 struct ovl_priv_data *op;
209 struct mgr_priv_data *mp;
210
211 mp = get_mgr_priv(mgr);
212
Archit Taneja5dd747e2012-05-08 18:19:15 +0530213 if (!mp->enabled)
214 return 0;
215
Tomi Valkeinen39518352011-11-17 17:35:28 +0200216 if (applying && mp->user_info_dirty)
217 mi = &mp->user_info;
218 else
219 mi = &mp->info;
220
221 /* collect the infos to be tested into the array */
222 list_for_each_entry(ovl, &mgr->overlays, list) {
223 op = get_ovl_priv(ovl);
224
Tomi Valkeinen82153ed2011-11-26 14:26:46 +0200225 if (!op->enabled && !op->enabling)
Tomi Valkeinen39518352011-11-17 17:35:28 +0200226 oi = NULL;
227 else if (applying && op->user_info_dirty)
228 oi = &op->user_info;
229 else
230 oi = &op->info;
231
232 ois[ovl->id] = oi;
233 }
234
Archit Taneja6e543592012-05-23 17:01:35 +0530235 return dss_mgr_check(mgr, mi, &mp->timings, &mp->lcd_config, ois);
Tomi Valkeinen39518352011-11-17 17:35:28 +0200236}
237
238/*
239 * check manager and overlay settings using overlay_info from data->info
240 */
Archit Taneja228b2132012-04-27 01:22:28 +0530241static int dss_check_settings(struct omap_overlay_manager *mgr)
Tomi Valkeinen39518352011-11-17 17:35:28 +0200242{
Archit Taneja228b2132012-04-27 01:22:28 +0530243 return dss_check_settings_low(mgr, false);
Tomi Valkeinen39518352011-11-17 17:35:28 +0200244}
245
246/*
247 * check manager and overlay settings using overlay_info from ovl->info if
248 * dirty and from data->info otherwise
249 */
Archit Taneja228b2132012-04-27 01:22:28 +0530250static int dss_check_settings_apply(struct omap_overlay_manager *mgr)
Tomi Valkeinen39518352011-11-17 17:35:28 +0200251{
Archit Taneja228b2132012-04-27 01:22:28 +0530252 return dss_check_settings_low(mgr, true);
Tomi Valkeinen39518352011-11-17 17:35:28 +0200253}
254
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200255static bool need_isr(void)
256{
257 const int num_mgrs = dss_feat_get_num_mgrs();
258 int i;
259
260 for (i = 0; i < num_mgrs; ++i) {
261 struct omap_overlay_manager *mgr;
262 struct mgr_priv_data *mp;
263 struct omap_overlay *ovl;
264
265 mgr = omap_dss_get_overlay_manager(i);
266 mp = get_mgr_priv(mgr);
267
268 if (!mp->enabled)
269 continue;
270
Tomi Valkeinen34861372011-11-18 15:43:29 +0200271 if (mgr_manual_update(mgr)) {
272 /* to catch FRAMEDONE */
273 if (mp->updating)
274 return true;
275 } else {
276 /* to catch GO bit going down */
277 if (mp->busy)
278 return true;
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200279
280 /* to write new values to registers */
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200281 if (mp->info_dirty)
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200282 return true;
Tomi Valkeinen34861372011-11-18 15:43:29 +0200283
Tomi Valkeinen9f808952011-11-25 17:26:13 +0200284 /* to set GO bit */
285 if (mp->shadow_info_dirty)
286 return true;
287
Archit Taneja45324a22012-04-26 19:31:22 +0530288 /*
289 * NOTE: we don't check extra_info flags for disabled
290 * managers, once the manager is enabled, the extra_info
291 * related manager changes will be taken in by HW.
292 */
293
294 /* to write new values to registers */
295 if (mp->extra_info_dirty)
296 return true;
297
298 /* to set GO bit */
299 if (mp->shadow_extra_info_dirty)
300 return true;
301
Tomi Valkeinen34861372011-11-18 15:43:29 +0200302 list_for_each_entry(ovl, &mgr->overlays, list) {
303 struct ovl_priv_data *op;
304
305 op = get_ovl_priv(ovl);
306
Tomi Valkeinen9f808952011-11-25 17:26:13 +0200307 /*
308 * NOTE: we check extra_info flags even for
309 * disabled overlays, as extra_infos need to be
310 * always written.
311 */
312
313 /* to write new values to registers */
314 if (op->extra_info_dirty)
315 return true;
316
317 /* to set GO bit */
318 if (op->shadow_extra_info_dirty)
319 return true;
320
Tomi Valkeinen34861372011-11-18 15:43:29 +0200321 if (!op->enabled)
322 continue;
323
324 /* to write new values to registers */
Tomi Valkeinen9f808952011-11-25 17:26:13 +0200325 if (op->info_dirty)
326 return true;
327
328 /* to set GO bit */
329 if (op->shadow_info_dirty)
Tomi Valkeinen34861372011-11-18 15:43:29 +0200330 return true;
331 }
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200332 }
333 }
334
335 return false;
336}
337
338static bool need_go(struct omap_overlay_manager *mgr)
339{
340 struct omap_overlay *ovl;
341 struct mgr_priv_data *mp;
342 struct ovl_priv_data *op;
343
344 mp = get_mgr_priv(mgr);
345
Archit Taneja45324a22012-04-26 19:31:22 +0530346 if (mp->shadow_info_dirty || mp->shadow_extra_info_dirty)
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200347 return true;
348
349 list_for_each_entry(ovl, &mgr->overlays, list) {
350 op = get_ovl_priv(ovl);
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200351 if (op->shadow_info_dirty || op->shadow_extra_info_dirty)
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200352 return true;
353 }
354
355 return false;
356}
357
Tomi Valkeinenf1577ce2011-11-16 14:37:48 +0200358/* returns true if an extra_info field is currently being updated */
359static bool extra_info_update_ongoing(void)
360{
Archit Taneja45324a22012-04-26 19:31:22 +0530361 const int num_mgrs = dss_feat_get_num_mgrs();
Tomi Valkeinenf1577ce2011-11-16 14:37:48 +0200362 int i;
Tomi Valkeinenf1577ce2011-11-16 14:37:48 +0200363
Archit Taneja45324a22012-04-26 19:31:22 +0530364 for (i = 0; i < num_mgrs; ++i) {
365 struct omap_overlay_manager *mgr;
366 struct omap_overlay *ovl;
367 struct mgr_priv_data *mp;
Tomi Valkeinenf1577ce2011-11-16 14:37:48 +0200368
Archit Taneja45324a22012-04-26 19:31:22 +0530369 mgr = omap_dss_get_overlay_manager(i);
370 mp = get_mgr_priv(mgr);
Tomi Valkeinenf1577ce2011-11-16 14:37:48 +0200371
372 if (!mp->enabled)
373 continue;
374
Tomi Valkeinen153b6e72011-11-25 17:35:35 +0200375 if (!mp->updating)
Tomi Valkeinenf1577ce2011-11-16 14:37:48 +0200376 continue;
377
Archit Taneja45324a22012-04-26 19:31:22 +0530378 if (mp->extra_info_dirty || mp->shadow_extra_info_dirty)
Tomi Valkeinen153b6e72011-11-25 17:35:35 +0200379 return true;
Archit Taneja45324a22012-04-26 19:31:22 +0530380
381 list_for_each_entry(ovl, &mgr->overlays, list) {
382 struct ovl_priv_data *op = get_ovl_priv(ovl);
383
384 if (op->extra_info_dirty || op->shadow_extra_info_dirty)
385 return true;
386 }
Tomi Valkeinenf1577ce2011-11-16 14:37:48 +0200387 }
388
389 return false;
390}
391
392/* wait until no extra_info updates are pending */
393static void wait_pending_extra_info_updates(void)
394{
395 bool updating;
396 unsigned long flags;
397 unsigned long t;
Tomi Valkeinen46146792012-02-23 12:21:09 +0200398 int r;
Tomi Valkeinenf1577ce2011-11-16 14:37:48 +0200399
400 spin_lock_irqsave(&data_lock, flags);
401
402 updating = extra_info_update_ongoing();
403
404 if (!updating) {
405 spin_unlock_irqrestore(&data_lock, flags);
406 return;
407 }
408
409 init_completion(&extra_updated_completion);
410
411 spin_unlock_irqrestore(&data_lock, flags);
412
413 t = msecs_to_jiffies(500);
Tomi Valkeinen46146792012-02-23 12:21:09 +0200414 r = wait_for_completion_timeout(&extra_updated_completion, t);
415 if (r == 0)
416 DSSWARN("timeout in wait_pending_extra_info_updates\n");
Tomi Valkeinenf1577ce2011-11-16 14:37:48 +0200417}
418
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200419int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr)
420{
421 unsigned long timeout = msecs_to_jiffies(500);
Archit Tanejafc22a842012-06-26 15:36:55 +0530422 struct mgr_priv_data *mp = get_mgr_priv(mgr);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200423 u32 irq;
Archit Tanejafc22a842012-06-26 15:36:55 +0530424 unsigned long flags;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200425 int r;
426 int i;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200427
Archit Tanejafc22a842012-06-26 15:36:55 +0530428 spin_lock_irqsave(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200429
Archit Tanejafc22a842012-06-26 15:36:55 +0530430 if (mgr_manual_update(mgr)) {
431 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200432 return 0;
Archit Tanejafc22a842012-06-26 15:36:55 +0530433 }
434
435 if (!mp->enabled) {
436 spin_unlock_irqrestore(&data_lock, flags);
437 return 0;
438 }
439
440 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200441
Lajos Molnar21e56f72012-02-22 12:23:16 +0530442 r = dispc_runtime_get();
443 if (r)
444 return r;
445
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200446 irq = dispc_mgr_get_vsync_irq(mgr->id);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200447
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200448 i = 0;
449 while (1) {
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200450 bool shadow_dirty, dirty;
451
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200452 spin_lock_irqsave(&data_lock, flags);
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200453 dirty = mp->info_dirty;
454 shadow_dirty = mp->shadow_info_dirty;
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200455 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200456
457 if (!dirty && !shadow_dirty) {
458 r = 0;
459 break;
460 }
461
462 /* 4 iterations is the worst case:
463 * 1 - initial iteration, dirty = true (between VFP and VSYNC)
464 * 2 - first VSYNC, dirty = true
465 * 3 - dirty = false, shadow_dirty = true
466 * 4 - shadow_dirty = false */
467 if (i++ == 3) {
468 DSSERR("mgr(%d)->wait_for_go() not finishing\n",
469 mgr->id);
470 r = 0;
471 break;
472 }
473
474 r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
475 if (r == -ERESTARTSYS)
476 break;
477
478 if (r) {
479 DSSERR("mgr(%d)->wait_for_go() timeout\n", mgr->id);
480 break;
481 }
482 }
483
Lajos Molnar21e56f72012-02-22 12:23:16 +0530484 dispc_runtime_put();
485
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200486 return r;
487}
488
489int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl)
490{
491 unsigned long timeout = msecs_to_jiffies(500);
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200492 struct ovl_priv_data *op;
Archit Tanejafc22a842012-06-26 15:36:55 +0530493 struct mgr_priv_data *mp;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200494 u32 irq;
Archit Tanejafc22a842012-06-26 15:36:55 +0530495 unsigned long flags;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200496 int r;
497 int i;
498
499 if (!ovl->manager)
500 return 0;
501
Archit Tanejafc22a842012-06-26 15:36:55 +0530502 mp = get_mgr_priv(ovl->manager);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200503
Archit Tanejafc22a842012-06-26 15:36:55 +0530504 spin_lock_irqsave(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200505
Archit Tanejafc22a842012-06-26 15:36:55 +0530506 if (ovl_manual_update(ovl)) {
507 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200508 return 0;
Archit Tanejafc22a842012-06-26 15:36:55 +0530509 }
510
511 if (!mp->enabled) {
512 spin_unlock_irqrestore(&data_lock, flags);
513 return 0;
514 }
515
516 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200517
Lajos Molnar21e56f72012-02-22 12:23:16 +0530518 r = dispc_runtime_get();
519 if (r)
520 return r;
521
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200522 irq = dispc_mgr_get_vsync_irq(ovl->manager->id);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200523
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200524 op = get_ovl_priv(ovl);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200525 i = 0;
526 while (1) {
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200527 bool shadow_dirty, dirty;
528
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200529 spin_lock_irqsave(&data_lock, flags);
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200530 dirty = op->info_dirty;
531 shadow_dirty = op->shadow_info_dirty;
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200532 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200533
534 if (!dirty && !shadow_dirty) {
535 r = 0;
536 break;
537 }
538
539 /* 4 iterations is the worst case:
540 * 1 - initial iteration, dirty = true (between VFP and VSYNC)
541 * 2 - first VSYNC, dirty = true
542 * 3 - dirty = false, shadow_dirty = true
543 * 4 - shadow_dirty = false */
544 if (i++ == 3) {
545 DSSERR("ovl(%d)->wait_for_go() not finishing\n",
546 ovl->id);
547 r = 0;
548 break;
549 }
550
551 r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
552 if (r == -ERESTARTSYS)
553 break;
554
555 if (r) {
556 DSSERR("ovl(%d)->wait_for_go() timeout\n", ovl->id);
557 break;
558 }
559 }
560
Lajos Molnar21e56f72012-02-22 12:23:16 +0530561 dispc_runtime_put();
562
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200563 return r;
564}
565
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200566static void dss_ovl_write_regs(struct omap_overlay *ovl)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200567{
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200568 struct ovl_priv_data *op = get_ovl_priv(ovl);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200569 struct omap_overlay_info *oi;
Archit Taneja8050cbe2012-06-06 16:25:52 +0530570 bool replication;
Tomi Valkeinen34861372011-11-18 15:43:29 +0200571 struct mgr_priv_data *mp;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200572 int r;
573
Chandrabhanu Mahapatra702d2672012-09-24 17:12:58 +0530574 DSSDBG("writing ovl %d regs", ovl->id);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200575
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200576 if (!op->enabled || !op->info_dirty)
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200577 return;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200578
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200579 oi = &op->info;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200580
Archit Taneja81ab95b2012-05-08 15:53:20 +0530581 mp = get_mgr_priv(ovl->manager);
582
Archit Taneja6c6f5102012-06-25 14:58:48 +0530583 replication = dss_ovl_use_replication(mp->lcd_config, oi->color_mode);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200584
Archit Taneja8ba85302012-09-26 17:00:37 +0530585 r = dispc_ovl_setup(ovl->id, oi, replication, &mp->timings, false);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200586 if (r) {
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200587 /*
588 * We can't do much here, as this function can be called from
589 * vsync interrupt.
590 */
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200591 DSSERR("dispc_ovl_setup failed for ovl %d\n", ovl->id);
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200592
593 /* This will leave fifo configurations in a nonoptimal state */
594 op->enabled = false;
595 dispc_ovl_enable(ovl->id, false);
596 return;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200597 }
598
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200599 op->info_dirty = false;
Tomi Valkeinen34861372011-11-18 15:43:29 +0200600 if (mp->updating)
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200601 op->shadow_info_dirty = true;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200602}
603
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200604static void dss_ovl_write_regs_extra(struct omap_overlay *ovl)
605{
606 struct ovl_priv_data *op = get_ovl_priv(ovl);
Tomi Valkeinen34861372011-11-18 15:43:29 +0200607 struct mgr_priv_data *mp;
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200608
Chandrabhanu Mahapatra702d2672012-09-24 17:12:58 +0530609 DSSDBG("writing ovl %d regs extra", ovl->id);
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200610
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200611 if (!op->extra_info_dirty)
612 return;
613
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200614 /* note: write also when op->enabled == false, so that the ovl gets
615 * disabled */
616
617 dispc_ovl_enable(ovl->id, op->enabled);
Tomi Valkeinen6dc802e2011-11-16 14:28:12 +0200618 dispc_ovl_set_fifo_threshold(ovl->id, op->fifo_low, op->fifo_high);
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200619
Tomi Valkeinen34861372011-11-18 15:43:29 +0200620 mp = get_mgr_priv(ovl->manager);
621
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200622 op->extra_info_dirty = false;
Tomi Valkeinen34861372011-11-18 15:43:29 +0200623 if (mp->updating)
624 op->shadow_extra_info_dirty = true;
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200625}
626
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200627static void dss_mgr_write_regs(struct omap_overlay_manager *mgr)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200628{
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200629 struct mgr_priv_data *mp = get_mgr_priv(mgr);
630 struct omap_overlay *ovl;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200631
Chandrabhanu Mahapatra702d2672012-09-24 17:12:58 +0530632 DSSDBG("writing mgr %d regs", mgr->id);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200633
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200634 if (!mp->enabled)
635 return;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200636
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200637 WARN_ON(mp->busy);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200638
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200639 /* Commit overlay settings */
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200640 list_for_each_entry(ovl, &mgr->overlays, list) {
641 dss_ovl_write_regs(ovl);
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200642 dss_ovl_write_regs_extra(ovl);
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200643 }
644
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200645 if (mp->info_dirty) {
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200646 dispc_mgr_setup(mgr->id, &mp->info);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200647
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200648 mp->info_dirty = false;
Tomi Valkeinen34861372011-11-18 15:43:29 +0200649 if (mp->updating)
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200650 mp->shadow_info_dirty = true;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200651 }
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200652}
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200653
Archit Taneja45324a22012-04-26 19:31:22 +0530654static void dss_mgr_write_regs_extra(struct omap_overlay_manager *mgr)
655{
656 struct mgr_priv_data *mp = get_mgr_priv(mgr);
657
Chandrabhanu Mahapatra702d2672012-09-24 17:12:58 +0530658 DSSDBG("writing mgr %d regs extra", mgr->id);
Archit Taneja45324a22012-04-26 19:31:22 +0530659
660 if (!mp->extra_info_dirty)
661 return;
662
663 dispc_mgr_set_timings(mgr->id, &mp->timings);
664
Archit Tanejaf476ae92012-06-29 14:37:03 +0530665 /* lcd_config parameters */
Tomi Valkeinenfb2cec12012-09-12 13:30:39 +0300666 if (dss_mgr_is_lcd(mgr->id))
667 dispc_mgr_set_lcd_config(mgr->id, &mp->lcd_config);
Archit Tanejaf476ae92012-06-29 14:37:03 +0530668
Archit Taneja45324a22012-04-26 19:31:22 +0530669 mp->extra_info_dirty = false;
670 if (mp->updating)
671 mp->shadow_extra_info_dirty = true;
672}
673
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200674static void dss_write_regs(void)
675{
676 const int num_mgrs = omap_dss_get_num_overlay_managers();
677 int i;
678
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200679 for (i = 0; i < num_mgrs; ++i) {
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200680 struct omap_overlay_manager *mgr;
681 struct mgr_priv_data *mp;
Tomi Valkeinen39518352011-11-17 17:35:28 +0200682 int r;
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200683
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200684 mgr = omap_dss_get_overlay_manager(i);
685 mp = get_mgr_priv(mgr);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200686
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200687 if (!mp->enabled || mgr_manual_update(mgr) || mp->busy)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200688 continue;
689
Archit Taneja228b2132012-04-27 01:22:28 +0530690 r = dss_check_settings(mgr);
Tomi Valkeinen39518352011-11-17 17:35:28 +0200691 if (r) {
692 DSSERR("cannot write registers for manager %s: "
693 "illegal configuration\n", mgr->name);
694 continue;
695 }
696
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200697 dss_mgr_write_regs(mgr);
Archit Taneja45324a22012-04-26 19:31:22 +0530698 dss_mgr_write_regs_extra(mgr);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200699 }
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200700}
701
Tomi Valkeinen3ab15b22011-11-25 17:32:20 +0200702static void dss_set_go_bits(void)
703{
704 const int num_mgrs = omap_dss_get_num_overlay_managers();
705 int i;
706
707 for (i = 0; i < num_mgrs; ++i) {
708 struct omap_overlay_manager *mgr;
709 struct mgr_priv_data *mp;
710
711 mgr = omap_dss_get_overlay_manager(i);
712 mp = get_mgr_priv(mgr);
713
714 if (!mp->enabled || mgr_manual_update(mgr) || mp->busy)
715 continue;
716
717 if (!need_go(mgr))
718 continue;
719
720 mp->busy = true;
721
722 if (!dss_data.irq_enabled && need_isr())
723 dss_register_vsync_isr();
724
725 dispc_mgr_go(mgr->id);
726 }
727
728}
729
Tomi Valkeinendf01d532012-03-07 10:28:48 +0200730static void mgr_clear_shadow_dirty(struct omap_overlay_manager *mgr)
731{
732 struct omap_overlay *ovl;
733 struct mgr_priv_data *mp;
734 struct ovl_priv_data *op;
735
736 mp = get_mgr_priv(mgr);
737 mp->shadow_info_dirty = false;
Archit Taneja45324a22012-04-26 19:31:22 +0530738 mp->shadow_extra_info_dirty = false;
Tomi Valkeinendf01d532012-03-07 10:28:48 +0200739
740 list_for_each_entry(ovl, &mgr->overlays, list) {
741 op = get_ovl_priv(ovl);
742 op->shadow_info_dirty = false;
743 op->shadow_extra_info_dirty = false;
744 }
745}
746
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200747void dss_mgr_start_update(struct omap_overlay_manager *mgr)
748{
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200749 struct mgr_priv_data *mp = get_mgr_priv(mgr);
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200750 unsigned long flags;
Tomi Valkeinen39518352011-11-17 17:35:28 +0200751 int r;
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200752
753 spin_lock_irqsave(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200754
Tomi Valkeinen34861372011-11-18 15:43:29 +0200755 WARN_ON(mp->updating);
756
Archit Taneja228b2132012-04-27 01:22:28 +0530757 r = dss_check_settings(mgr);
Tomi Valkeinen39518352011-11-17 17:35:28 +0200758 if (r) {
759 DSSERR("cannot start manual update: illegal configuration\n");
760 spin_unlock_irqrestore(&data_lock, flags);
761 return;
762 }
763
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200764 dss_mgr_write_regs(mgr);
Archit Taneja45324a22012-04-26 19:31:22 +0530765 dss_mgr_write_regs_extra(mgr);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200766
Tomi Valkeinen34861372011-11-18 15:43:29 +0200767 mp->updating = true;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200768
Tomi Valkeinen34861372011-11-18 15:43:29 +0200769 if (!dss_data.irq_enabled && need_isr())
770 dss_register_vsync_isr();
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200771
Tomi Valkeinen3a979f82012-10-19 14:14:38 +0300772 dispc_mgr_enable_sync(mgr->id);
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200773
774 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200775}
776
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200777static void dss_apply_irq_handler(void *data, u32 mask);
778
779static void dss_register_vsync_isr(void)
780{
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200781 const int num_mgrs = dss_feat_get_num_mgrs();
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200782 u32 mask;
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200783 int r, i;
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200784
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200785 mask = 0;
786 for (i = 0; i < num_mgrs; ++i)
787 mask |= dispc_mgr_get_vsync_irq(i);
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200788
Tomi Valkeinen34861372011-11-18 15:43:29 +0200789 for (i = 0; i < num_mgrs; ++i)
790 mask |= dispc_mgr_get_framedone_irq(i);
791
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200792 r = omap_dispc_register_isr(dss_apply_irq_handler, NULL, mask);
793 WARN_ON(r);
794
Tomi Valkeinend09c7aa2011-11-15 12:04:43 +0200795 dss_data.irq_enabled = true;
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200796}
797
798static void dss_unregister_vsync_isr(void)
799{
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200800 const int num_mgrs = dss_feat_get_num_mgrs();
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200801 u32 mask;
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200802 int r, i;
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200803
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200804 mask = 0;
805 for (i = 0; i < num_mgrs; ++i)
806 mask |= dispc_mgr_get_vsync_irq(i);
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200807
Tomi Valkeinen34861372011-11-18 15:43:29 +0200808 for (i = 0; i < num_mgrs; ++i)
809 mask |= dispc_mgr_get_framedone_irq(i);
810
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200811 r = omap_dispc_unregister_isr(dss_apply_irq_handler, NULL, mask);
812 WARN_ON(r);
813
Tomi Valkeinend09c7aa2011-11-15 12:04:43 +0200814 dss_data.irq_enabled = false;
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200815}
816
Tomi Valkeinen76098932011-11-16 12:03:22 +0200817static void dss_apply_irq_handler(void *data, u32 mask)
818{
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200819 const int num_mgrs = dss_feat_get_num_mgrs();
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200820 int i;
Tomi Valkeinenf1577ce2011-11-16 14:37:48 +0200821 bool extra_updating;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200822
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200823 spin_lock(&data_lock);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200824
Tomi Valkeinen76098932011-11-16 12:03:22 +0200825 /* clear busy, updating flags, shadow_dirty flags */
Tomi Valkeinen43a972d2011-11-15 15:04:25 +0200826 for (i = 0; i < num_mgrs; i++) {
Tomi Valkeinen76098932011-11-16 12:03:22 +0200827 struct omap_overlay_manager *mgr;
828 struct mgr_priv_data *mp;
829
Tomi Valkeinen43a972d2011-11-15 15:04:25 +0200830 mgr = omap_dss_get_overlay_manager(i);
831 mp = get_mgr_priv(mgr);
832
Tomi Valkeinen76098932011-11-16 12:03:22 +0200833 if (!mp->enabled)
Tomi Valkeinen43a972d2011-11-15 15:04:25 +0200834 continue;
835
Tomi Valkeinen76098932011-11-16 12:03:22 +0200836 mp->updating = dispc_mgr_is_enabled(i);
Tomi Valkeinen43a972d2011-11-15 15:04:25 +0200837
Tomi Valkeinen76098932011-11-16 12:03:22 +0200838 if (!mgr_manual_update(mgr)) {
Tomi Valkeinen5b214172011-11-25 17:27:45 +0200839 bool was_busy = mp->busy;
Tomi Valkeinen76098932011-11-16 12:03:22 +0200840 mp->busy = dispc_mgr_go_busy(i);
841
Tomi Valkeinen5b214172011-11-25 17:27:45 +0200842 if (was_busy && !mp->busy)
Tomi Valkeinen76098932011-11-16 12:03:22 +0200843 mgr_clear_shadow_dirty(mgr);
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200844 }
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200845 }
846
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200847 dss_write_regs();
Tomi Valkeinen3ab15b22011-11-25 17:32:20 +0200848 dss_set_go_bits();
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200849
Tomi Valkeinenf1577ce2011-11-16 14:37:48 +0200850 extra_updating = extra_info_update_ongoing();
851 if (!extra_updating)
852 complete_all(&extra_updated_completion);
853
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200854 if (!need_isr())
855 dss_unregister_vsync_isr();
Tomi Valkeinen43a972d2011-11-15 15:04:25 +0200856
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200857 spin_unlock(&data_lock);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200858}
859
Tomi Valkeinen5738b632011-11-15 13:37:33 +0200860static void omap_dss_mgr_apply_ovl(struct omap_overlay *ovl)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200861{
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200862 struct ovl_priv_data *op;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200863
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200864 op = get_ovl_priv(ovl);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200865
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +0200866 if (!op->user_info_dirty)
Tomi Valkeinen5738b632011-11-15 13:37:33 +0200867 return;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200868
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +0200869 op->user_info_dirty = false;
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200870 op->info_dirty = true;
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +0200871 op->info = op->user_info;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200872}
873
874static void omap_dss_mgr_apply_mgr(struct omap_overlay_manager *mgr)
875{
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200876 struct mgr_priv_data *mp;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200877
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200878 mp = get_mgr_priv(mgr);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200879
Tomi Valkeinen388c4c62011-11-16 13:58:07 +0200880 if (!mp->user_info_dirty)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200881 return;
882
Tomi Valkeinen388c4c62011-11-16 13:58:07 +0200883 mp->user_info_dirty = false;
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200884 mp->info_dirty = true;
Tomi Valkeinen388c4c62011-11-16 13:58:07 +0200885 mp->info = mp->user_info;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200886}
887
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200888int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
889{
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200890 unsigned long flags;
Tomi Valkeinen07e327c2011-11-05 10:59:59 +0200891 struct omap_overlay *ovl;
Tomi Valkeinen39518352011-11-17 17:35:28 +0200892 int r;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200893
894 DSSDBG("omap_dss_mgr_apply(%s)\n", mgr->name);
895
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200896 spin_lock_irqsave(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200897
Archit Taneja228b2132012-04-27 01:22:28 +0530898 r = dss_check_settings_apply(mgr);
Tomi Valkeinen39518352011-11-17 17:35:28 +0200899 if (r) {
900 spin_unlock_irqrestore(&data_lock, flags);
901 DSSERR("failed to apply settings: illegal configuration.\n");
902 return r;
903 }
904
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200905 /* Configure overlays */
Tomi Valkeinen07e327c2011-11-05 10:59:59 +0200906 list_for_each_entry(ovl, &mgr->overlays, list)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200907 omap_dss_mgr_apply_ovl(ovl);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200908
909 /* Configure manager */
910 omap_dss_mgr_apply_mgr(mgr);
911
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200912 dss_write_regs();
Tomi Valkeinen3ab15b22011-11-25 17:32:20 +0200913 dss_set_go_bits();
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200914
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200915 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200916
Tomi Valkeinene70f98a2011-11-16 16:53:44 +0200917 return 0;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200918}
919
Tomi Valkeinen841c09c2011-11-16 15:25:53 +0200920static void dss_apply_ovl_enable(struct omap_overlay *ovl, bool enable)
921{
922 struct ovl_priv_data *op;
923
924 op = get_ovl_priv(ovl);
925
926 if (op->enabled == enable)
927 return;
928
929 op->enabled = enable;
930 op->extra_info_dirty = true;
931}
932
Tomi Valkeinen04576d42011-11-26 14:39:16 +0200933static void dss_apply_ovl_fifo_thresholds(struct omap_overlay *ovl,
934 u32 fifo_low, u32 fifo_high)
935{
936 struct ovl_priv_data *op = get_ovl_priv(ovl);
937
938 if (op->fifo_low == fifo_low && op->fifo_high == fifo_high)
939 return;
940
941 op->fifo_low = fifo_low;
942 op->fifo_high = fifo_high;
943 op->extra_info_dirty = true;
944}
945
Tomi Valkeinenb3e93cb2012-08-06 16:50:14 +0300946static void dss_ovl_setup_fifo(struct omap_overlay *ovl)
Tomi Valkeinen6dc802e2011-11-16 14:28:12 +0200947{
948 struct ovl_priv_data *op = get_ovl_priv(ovl);
Tomi Valkeinen6dc802e2011-11-16 14:28:12 +0200949 u32 fifo_low, fifo_high;
Tomi Valkeinenb3e93cb2012-08-06 16:50:14 +0300950 bool use_fifo_merge = false;
Tomi Valkeinen6dc802e2011-11-16 14:28:12 +0200951
Tomi Valkeinen75ae1182011-11-26 14:36:19 +0200952 if (!op->enabled && !op->enabling)
953 return;
954
Tomi Valkeinen83fa2f22012-01-13 13:17:01 +0200955 dispc_ovl_compute_fifo_thresholds(ovl->id, &fifo_low, &fifo_high,
Tomi Valkeinen3568f2a2012-05-15 15:31:01 +0300956 use_fifo_merge, ovl_manual_update(ovl));
Tomi Valkeinen6dc802e2011-11-16 14:28:12 +0200957
Tomi Valkeinen04576d42011-11-26 14:39:16 +0200958 dss_apply_ovl_fifo_thresholds(ovl, fifo_low, fifo_high);
Tomi Valkeinen6dc802e2011-11-16 14:28:12 +0200959}
960
Tomi Valkeinenb3e93cb2012-08-06 16:50:14 +0300961static void dss_mgr_setup_fifos(struct omap_overlay_manager *mgr)
Tomi Valkeinen6dc802e2011-11-16 14:28:12 +0200962{
963 struct omap_overlay *ovl;
Tomi Valkeinen6dc802e2011-11-16 14:28:12 +0200964 struct mgr_priv_data *mp;
965
966 mp = get_mgr_priv(mgr);
967
968 if (!mp->enabled)
969 return;
970
Tomi Valkeinen75ae1182011-11-26 14:36:19 +0200971 list_for_each_entry(ovl, &mgr->overlays, list)
Tomi Valkeinenb3e93cb2012-08-06 16:50:14 +0300972 dss_ovl_setup_fifo(ovl);
Tomi Valkeinen75ae1182011-11-26 14:36:19 +0200973}
974
Tomi Valkeinenb3e93cb2012-08-06 16:50:14 +0300975static void dss_setup_fifos(void)
Tomi Valkeinen75ae1182011-11-26 14:36:19 +0200976{
977 const int num_mgrs = omap_dss_get_num_overlay_managers();
978 struct omap_overlay_manager *mgr;
979 int i;
980
981 for (i = 0; i < num_mgrs; ++i) {
982 mgr = omap_dss_get_overlay_manager(i);
Tomi Valkeinenb3e93cb2012-08-06 16:50:14 +0300983 dss_mgr_setup_fifos(mgr);
Tomi Valkeinen6dc802e2011-11-16 14:28:12 +0200984 }
985}
986
Tomi Valkeinen2a4ee7e2011-11-21 13:34:48 +0200987int dss_mgr_enable(struct omap_overlay_manager *mgr)
Tomi Valkeinen7797c6d2011-11-04 10:22:46 +0200988{
Tomi Valkeinenbf213522011-11-15 14:43:53 +0200989 struct mgr_priv_data *mp = get_mgr_priv(mgr);
990 unsigned long flags;
Tomi Valkeinen39518352011-11-17 17:35:28 +0200991 int r;
Tomi Valkeinenbf213522011-11-15 14:43:53 +0200992
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200993 mutex_lock(&apply_lock);
994
Tomi Valkeinene4f7ad72011-11-16 16:01:33 +0200995 if (mp->enabled)
996 goto out;
997
Tomi Valkeinenbf213522011-11-15 14:43:53 +0200998 spin_lock_irqsave(&data_lock, flags);
999
1000 mp->enabled = true;
Tomi Valkeinena6b24f82011-11-26 14:29:39 +02001001
Archit Taneja228b2132012-04-27 01:22:28 +05301002 r = dss_check_settings(mgr);
Tomi Valkeinen39518352011-11-17 17:35:28 +02001003 if (r) {
1004 DSSERR("failed to enable manager %d: check_settings failed\n",
1005 mgr->id);
Tomi Valkeinen2a4ee7e2011-11-21 13:34:48 +02001006 goto err;
Tomi Valkeinen39518352011-11-17 17:35:28 +02001007 }
1008
Tomi Valkeinenb3e93cb2012-08-06 16:50:14 +03001009 dss_setup_fifos();
Tomi Valkeinen6dc802e2011-11-16 14:28:12 +02001010
Tomi Valkeinen75c94962011-11-15 18:25:23 +02001011 dss_write_regs();
Tomi Valkeinen3ab15b22011-11-25 17:32:20 +02001012 dss_set_go_bits();
Tomi Valkeinen75c94962011-11-15 18:25:23 +02001013
Tomi Valkeinen34861372011-11-18 15:43:29 +02001014 if (!mgr_manual_update(mgr))
1015 mp->updating = true;
1016
Tomi Valkeinend7b6b6b2012-08-10 14:17:47 +03001017 if (!dss_data.irq_enabled && need_isr())
1018 dss_register_vsync_isr();
1019
Tomi Valkeinenbf213522011-11-15 14:43:53 +02001020 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001021
Tomi Valkeinen75c94962011-11-15 18:25:23 +02001022 if (!mgr_manual_update(mgr))
Tomi Valkeinen3a979f82012-10-19 14:14:38 +03001023 dispc_mgr_enable_sync(mgr->id);
Tomi Valkeinen75c94962011-11-15 18:25:23 +02001024
Tomi Valkeinene4f7ad72011-11-16 16:01:33 +02001025out:
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001026 mutex_unlock(&apply_lock);
Tomi Valkeinen2a4ee7e2011-11-21 13:34:48 +02001027
1028 return 0;
1029
1030err:
Tomi Valkeinena6b24f82011-11-26 14:29:39 +02001031 mp->enabled = false;
Tomi Valkeinen2a4ee7e2011-11-21 13:34:48 +02001032 spin_unlock_irqrestore(&data_lock, flags);
1033 mutex_unlock(&apply_lock);
1034 return r;
Tomi Valkeinen7797c6d2011-11-04 10:22:46 +02001035}
1036
1037void dss_mgr_disable(struct omap_overlay_manager *mgr)
1038{
Tomi Valkeinenbf213522011-11-15 14:43:53 +02001039 struct mgr_priv_data *mp = get_mgr_priv(mgr);
1040 unsigned long flags;
1041
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001042 mutex_lock(&apply_lock);
1043
Tomi Valkeinene4f7ad72011-11-16 16:01:33 +02001044 if (!mp->enabled)
1045 goto out;
1046
Tomi Valkeinen9a147a62011-11-09 15:30:11 +02001047 if (!mgr_manual_update(mgr))
Tomi Valkeinen3a979f82012-10-19 14:14:38 +03001048 dispc_mgr_disable_sync(mgr->id);
Tomi Valkeinenbf213522011-11-15 14:43:53 +02001049
1050 spin_lock_irqsave(&data_lock, flags);
1051
Tomi Valkeinen34861372011-11-18 15:43:29 +02001052 mp->updating = false;
Tomi Valkeinenbf213522011-11-15 14:43:53 +02001053 mp->enabled = false;
1054
1055 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001056
Tomi Valkeinene4f7ad72011-11-16 16:01:33 +02001057out:
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001058 mutex_unlock(&apply_lock);
Tomi Valkeinen7797c6d2011-11-04 10:22:46 +02001059}
1060
Tomi Valkeineneb70d732011-11-15 12:15:18 +02001061int dss_mgr_set_info(struct omap_overlay_manager *mgr,
1062 struct omap_overlay_manager_info *info)
1063{
Tomi Valkeinen388c4c62011-11-16 13:58:07 +02001064 struct mgr_priv_data *mp = get_mgr_priv(mgr);
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +02001065 unsigned long flags;
Tomi Valkeinenf17d04f2011-11-17 14:31:09 +02001066 int r;
1067
1068 r = dss_mgr_simple_check(mgr, info);
1069 if (r)
1070 return r;
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +02001071
1072 spin_lock_irqsave(&data_lock, flags);
1073
Tomi Valkeinen388c4c62011-11-16 13:58:07 +02001074 mp->user_info = *info;
1075 mp->user_info_dirty = true;
Tomi Valkeineneb70d732011-11-15 12:15:18 +02001076
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +02001077 spin_unlock_irqrestore(&data_lock, flags);
1078
Tomi Valkeineneb70d732011-11-15 12:15:18 +02001079 return 0;
1080}
1081
1082void dss_mgr_get_info(struct omap_overlay_manager *mgr,
1083 struct omap_overlay_manager_info *info)
1084{
Tomi Valkeinen388c4c62011-11-16 13:58:07 +02001085 struct mgr_priv_data *mp = get_mgr_priv(mgr);
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +02001086 unsigned long flags;
1087
1088 spin_lock_irqsave(&data_lock, flags);
1089
Tomi Valkeinen388c4c62011-11-16 13:58:07 +02001090 *info = mp->user_info;
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +02001091
1092 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeineneb70d732011-11-15 12:15:18 +02001093}
1094
Archit Taneja97f01b32012-09-26 16:42:39 +05301095int dss_mgr_set_output(struct omap_overlay_manager *mgr,
1096 struct omap_dss_output *output)
1097{
1098 int r;
1099
1100 mutex_lock(&apply_lock);
1101
1102 if (mgr->output) {
1103 DSSERR("manager %s is already connected to an output\n",
1104 mgr->name);
1105 r = -EINVAL;
1106 goto err;
1107 }
1108
1109 if ((mgr->supported_outputs & output->id) == 0) {
1110 DSSERR("output does not support manager %s\n",
1111 mgr->name);
1112 r = -EINVAL;
1113 goto err;
1114 }
1115
1116 output->manager = mgr;
1117 mgr->output = output;
1118
1119 mutex_unlock(&apply_lock);
1120
1121 return 0;
1122err:
1123 mutex_unlock(&apply_lock);
1124 return r;
1125}
1126
1127int dss_mgr_unset_output(struct omap_overlay_manager *mgr)
1128{
1129 int r;
1130 struct mgr_priv_data *mp = get_mgr_priv(mgr);
1131 unsigned long flags;
1132
1133 mutex_lock(&apply_lock);
1134
1135 if (!mgr->output) {
1136 DSSERR("failed to unset output, output not set\n");
1137 r = -EINVAL;
1138 goto err;
1139 }
1140
1141 spin_lock_irqsave(&data_lock, flags);
1142
1143 if (mp->enabled) {
1144 DSSERR("output can't be unset when manager is enabled\n");
1145 r = -EINVAL;
1146 goto err1;
1147 }
1148
1149 spin_unlock_irqrestore(&data_lock, flags);
1150
1151 mgr->output->manager = NULL;
1152 mgr->output = NULL;
1153
1154 mutex_unlock(&apply_lock);
1155
1156 return 0;
1157err1:
1158 spin_unlock_irqrestore(&data_lock, flags);
1159err:
1160 mutex_unlock(&apply_lock);
1161
1162 return r;
1163}
1164
Archit Taneja45324a22012-04-26 19:31:22 +05301165static void dss_apply_mgr_timings(struct omap_overlay_manager *mgr,
Archit Taneja27dfddc2012-07-19 13:51:14 +05301166 const struct omap_video_timings *timings)
Archit Taneja45324a22012-04-26 19:31:22 +05301167{
1168 struct mgr_priv_data *mp = get_mgr_priv(mgr);
1169
1170 mp->timings = *timings;
1171 mp->extra_info_dirty = true;
1172}
1173
1174void dss_mgr_set_timings(struct omap_overlay_manager *mgr,
Archit Taneja27dfddc2012-07-19 13:51:14 +05301175 const struct omap_video_timings *timings)
Archit Taneja45324a22012-04-26 19:31:22 +05301176{
1177 unsigned long flags;
Tomi Valkeinenfed62e52012-08-09 18:13:13 +03001178 struct mgr_priv_data *mp = get_mgr_priv(mgr);
Archit Taneja45324a22012-04-26 19:31:22 +05301179
1180 spin_lock_irqsave(&data_lock, flags);
1181
Tomi Valkeinenfed62e52012-08-09 18:13:13 +03001182 if (mp->updating) {
1183 DSSERR("cannot set timings for %s: manager needs to be disabled\n",
1184 mgr->name);
1185 goto out;
1186 }
1187
Archit Taneja45324a22012-04-26 19:31:22 +05301188 dss_apply_mgr_timings(mgr, timings);
Tomi Valkeinenfed62e52012-08-09 18:13:13 +03001189out:
Archit Taneja45324a22012-04-26 19:31:22 +05301190 spin_unlock_irqrestore(&data_lock, flags);
Archit Taneja45324a22012-04-26 19:31:22 +05301191}
Tomi Valkeineneb70d732011-11-15 12:15:18 +02001192
Archit Tanejaf476ae92012-06-29 14:37:03 +05301193static void dss_apply_mgr_lcd_config(struct omap_overlay_manager *mgr,
1194 const struct dss_lcd_mgr_config *config)
1195{
1196 struct mgr_priv_data *mp = get_mgr_priv(mgr);
1197
1198 mp->lcd_config = *config;
1199 mp->extra_info_dirty = true;
1200}
1201
1202void dss_mgr_set_lcd_config(struct omap_overlay_manager *mgr,
1203 const struct dss_lcd_mgr_config *config)
1204{
1205 unsigned long flags;
1206 struct mgr_priv_data *mp = get_mgr_priv(mgr);
1207
Tomi Valkeinenaba96572012-08-09 18:07:45 +03001208 spin_lock_irqsave(&data_lock, flags);
Archit Tanejaf476ae92012-06-29 14:37:03 +05301209
1210 if (mp->enabled) {
1211 DSSERR("cannot apply lcd config for %s: manager needs to be disabled\n",
1212 mgr->name);
1213 goto out;
1214 }
1215
Archit Tanejaf476ae92012-06-29 14:37:03 +05301216 dss_apply_mgr_lcd_config(mgr, config);
Archit Tanejaf476ae92012-06-29 14:37:03 +05301217out:
Tomi Valkeinenaba96572012-08-09 18:07:45 +03001218 spin_unlock_irqrestore(&data_lock, flags);
Archit Tanejaf476ae92012-06-29 14:37:03 +05301219}
1220
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001221int dss_ovl_set_info(struct omap_overlay *ovl,
1222 struct omap_overlay_info *info)
1223{
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +02001224 struct ovl_priv_data *op = get_ovl_priv(ovl);
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +02001225 unsigned long flags;
Tomi Valkeinenfcc764d2011-11-17 14:26:48 +02001226 int r;
1227
1228 r = dss_ovl_simple_check(ovl, info);
1229 if (r)
1230 return r;
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +02001231
1232 spin_lock_irqsave(&data_lock, flags);
1233
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +02001234 op->user_info = *info;
1235 op->user_info_dirty = true;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001236
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +02001237 spin_unlock_irqrestore(&data_lock, flags);
1238
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001239 return 0;
1240}
1241
1242void dss_ovl_get_info(struct omap_overlay *ovl,
1243 struct omap_overlay_info *info)
1244{
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +02001245 struct ovl_priv_data *op = get_ovl_priv(ovl);
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +02001246 unsigned long flags;
1247
1248 spin_lock_irqsave(&data_lock, flags);
1249
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +02001250 *info = op->user_info;
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +02001251
1252 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001253}
1254
1255int dss_ovl_set_manager(struct omap_overlay *ovl,
1256 struct omap_overlay_manager *mgr)
1257{
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001258 struct ovl_priv_data *op = get_ovl_priv(ovl);
1259 unsigned long flags;
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001260 int r;
1261
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001262 if (!mgr)
1263 return -EINVAL;
1264
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001265 mutex_lock(&apply_lock);
1266
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001267 if (ovl->manager) {
1268 DSSERR("overlay '%s' already has a manager '%s'\n",
1269 ovl->name, ovl->manager->name);
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001270 r = -EINVAL;
1271 goto err;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001272 }
1273
Archit Taneja02b5ff12012-11-07 14:47:22 +05301274 r = dispc_runtime_get();
1275 if (r)
1276 goto err;
1277
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001278 spin_lock_irqsave(&data_lock, flags);
1279
1280 if (op->enabled) {
1281 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001282 DSSERR("overlay has to be disabled to change the manager\n");
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001283 r = -EINVAL;
Archit Taneja02b5ff12012-11-07 14:47:22 +05301284 goto err1;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001285 }
1286
Archit Taneja02b5ff12012-11-07 14:47:22 +05301287 dispc_ovl_set_channel_out(ovl->id, mgr->id);
Tomi Valkeinen5d5a97a2011-11-16 14:17:54 +02001288
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001289 ovl->manager = mgr;
1290 list_add_tail(&ovl->list, &mgr->overlays);
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001291
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001292 spin_unlock_irqrestore(&data_lock, flags);
1293
Archit Taneja02b5ff12012-11-07 14:47:22 +05301294 dispc_runtime_put();
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001295
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001296 mutex_unlock(&apply_lock);
1297
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001298 return 0;
Archit Taneja02b5ff12012-11-07 14:47:22 +05301299
1300err1:
1301 dispc_runtime_put();
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001302err:
1303 mutex_unlock(&apply_lock);
1304 return r;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001305}
1306
1307int dss_ovl_unset_manager(struct omap_overlay *ovl)
1308{
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001309 struct ovl_priv_data *op = get_ovl_priv(ovl);
1310 unsigned long flags;
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001311 int r;
1312
1313 mutex_lock(&apply_lock);
1314
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001315 if (!ovl->manager) {
1316 DSSERR("failed to detach overlay: manager not set\n");
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001317 r = -EINVAL;
1318 goto err;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001319 }
1320
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001321 spin_lock_irqsave(&data_lock, flags);
1322
1323 if (op->enabled) {
1324 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001325 DSSERR("overlay has to be disabled to unset the manager\n");
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001326 r = -EINVAL;
1327 goto err;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001328 }
1329
Tomi Valkeinenb2f59762012-09-06 16:10:28 +03001330 spin_unlock_irqrestore(&data_lock, flags);
1331
1332 /* wait for pending extra_info updates to ensure the ovl is disabled */
1333 wait_pending_extra_info_updates();
1334
Archit Taneja02b5ff12012-11-07 14:47:22 +05301335 /*
1336 * For a manual update display, there is no guarantee that the overlay
1337 * is really disabled in HW, we may need an extra update from this
1338 * manager before the configurations can go in. Return an error if the
1339 * overlay needed an update from the manager.
1340 *
1341 * TODO: Instead of returning an error, try to do a dummy manager update
1342 * here to disable the overlay in hardware. Use the *GATED fields in
1343 * the DISPC_CONFIG registers to do a dummy update.
1344 */
Tomi Valkeinenb2f59762012-09-06 16:10:28 +03001345 spin_lock_irqsave(&data_lock, flags);
1346
Archit Taneja02b5ff12012-11-07 14:47:22 +05301347 if (ovl_manual_update(ovl) && op->extra_info_dirty) {
1348 spin_unlock_irqrestore(&data_lock, flags);
1349 DSSERR("need an update to change the manager\n");
1350 r = -EINVAL;
1351 goto err;
1352 }
Tomi Valkeinen5d5a97a2011-11-16 14:17:54 +02001353
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001354 ovl->manager = NULL;
1355 list_del(&ovl->list);
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001356
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001357 spin_unlock_irqrestore(&data_lock, flags);
1358
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001359 mutex_unlock(&apply_lock);
1360
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001361 return 0;
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001362err:
1363 mutex_unlock(&apply_lock);
1364 return r;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001365}
1366
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001367bool dss_ovl_is_enabled(struct omap_overlay *ovl)
1368{
1369 struct ovl_priv_data *op = get_ovl_priv(ovl);
1370 unsigned long flags;
1371 bool e;
1372
1373 spin_lock_irqsave(&data_lock, flags);
1374
1375 e = op->enabled;
1376
1377 spin_unlock_irqrestore(&data_lock, flags);
1378
1379 return e;
1380}
1381
1382int dss_ovl_enable(struct omap_overlay *ovl)
1383{
1384 struct ovl_priv_data *op = get_ovl_priv(ovl);
1385 unsigned long flags;
1386 int r;
1387
1388 mutex_lock(&apply_lock);
1389
Tomi Valkeinene4f7ad72011-11-16 16:01:33 +02001390 if (op->enabled) {
1391 r = 0;
Tomi Valkeinen39518352011-11-17 17:35:28 +02001392 goto err1;
Tomi Valkeinene4f7ad72011-11-16 16:01:33 +02001393 }
1394
Archit Taneja0f0e4e32012-09-03 17:14:09 +05301395 if (ovl->manager == NULL || ovl->manager->output == NULL) {
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001396 r = -EINVAL;
Tomi Valkeinen39518352011-11-17 17:35:28 +02001397 goto err1;
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001398 }
1399
1400 spin_lock_irqsave(&data_lock, flags);
1401
Tomi Valkeinen82153ed2011-11-26 14:26:46 +02001402 op->enabling = true;
1403
Archit Taneja228b2132012-04-27 01:22:28 +05301404 r = dss_check_settings(ovl->manager);
Tomi Valkeinen39518352011-11-17 17:35:28 +02001405 if (r) {
1406 DSSERR("failed to enable overlay %d: check_settings failed\n",
1407 ovl->id);
1408 goto err2;
1409 }
1410
Tomi Valkeinenb3e93cb2012-08-06 16:50:14 +03001411 dss_setup_fifos();
Tomi Valkeinen6dc802e2011-11-16 14:28:12 +02001412
Tomi Valkeinen82153ed2011-11-26 14:26:46 +02001413 op->enabling = false;
1414 dss_apply_ovl_enable(ovl, true);
1415
Tomi Valkeinen75c94962011-11-15 18:25:23 +02001416 dss_write_regs();
Tomi Valkeinen3ab15b22011-11-25 17:32:20 +02001417 dss_set_go_bits();
Tomi Valkeinen75c94962011-11-15 18:25:23 +02001418
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001419 spin_unlock_irqrestore(&data_lock, flags);
1420
1421 mutex_unlock(&apply_lock);
1422
1423 return 0;
Tomi Valkeinen39518352011-11-17 17:35:28 +02001424err2:
Tomi Valkeinen82153ed2011-11-26 14:26:46 +02001425 op->enabling = false;
Tomi Valkeinen39518352011-11-17 17:35:28 +02001426 spin_unlock_irqrestore(&data_lock, flags);
1427err1:
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001428 mutex_unlock(&apply_lock);
1429 return r;
1430}
1431
1432int dss_ovl_disable(struct omap_overlay *ovl)
1433{
1434 struct ovl_priv_data *op = get_ovl_priv(ovl);
1435 unsigned long flags;
1436 int r;
1437
1438 mutex_lock(&apply_lock);
1439
Tomi Valkeinene4f7ad72011-11-16 16:01:33 +02001440 if (!op->enabled) {
1441 r = 0;
1442 goto err;
1443 }
1444
Archit Taneja0f0e4e32012-09-03 17:14:09 +05301445 if (ovl->manager == NULL || ovl->manager->output == NULL) {
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001446 r = -EINVAL;
1447 goto err;
1448 }
1449
1450 spin_lock_irqsave(&data_lock, flags);
1451
Tomi Valkeinen841c09c2011-11-16 15:25:53 +02001452 dss_apply_ovl_enable(ovl, false);
Tomi Valkeinen75c94962011-11-15 18:25:23 +02001453 dss_write_regs();
Tomi Valkeinen3ab15b22011-11-25 17:32:20 +02001454 dss_set_go_bits();
Tomi Valkeinen75c94962011-11-15 18:25:23 +02001455
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001456 spin_unlock_irqrestore(&data_lock, flags);
1457
1458 mutex_unlock(&apply_lock);
1459
1460 return 0;
1461
1462err:
1463 mutex_unlock(&apply_lock);
1464 return r;
1465}
1466
Tomi Valkeinen8dd24912012-10-10 10:26:45 +03001467static int compat_refcnt;
1468static DEFINE_MUTEX(compat_init_lock);
1469
1470int omapdss_compat_init(void)
1471{
Tomi Valkeinen23dfd1a2012-10-23 13:46:12 +03001472 struct platform_device *pdev = dss_get_core_pdev();
1473
Tomi Valkeinen8dd24912012-10-10 10:26:45 +03001474 mutex_lock(&compat_init_lock);
1475
1476 if (compat_refcnt++ > 0)
1477 goto out;
1478
1479 apply_init_priv();
1480
Tomi Valkeinen23dfd1a2012-10-23 13:46:12 +03001481 dss_init_overlay_managers(pdev);
1482 dss_init_overlays(pdev);
1483
Tomi Valkeinen8dd24912012-10-10 10:26:45 +03001484out:
1485 mutex_unlock(&compat_init_lock);
1486
1487 return 0;
1488}
1489EXPORT_SYMBOL(omapdss_compat_init);
1490
1491void omapdss_compat_uninit(void)
1492{
Tomi Valkeinen23dfd1a2012-10-23 13:46:12 +03001493 struct platform_device *pdev = dss_get_core_pdev();
1494
Tomi Valkeinen8dd24912012-10-10 10:26:45 +03001495 mutex_lock(&compat_init_lock);
1496
1497 if (--compat_refcnt > 0)
1498 goto out;
1499
Tomi Valkeinen23dfd1a2012-10-23 13:46:12 +03001500 dss_uninit_overlay_managers(pdev);
1501 dss_uninit_overlays(pdev);
Tomi Valkeinen8dd24912012-10-10 10:26:45 +03001502out:
1503 mutex_unlock(&compat_init_lock);
1504}
1505EXPORT_SYMBOL(omapdss_compat_uninit);