blob: 98cebe30318aa461e892c34442706360bc6d1467 [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 Valkeinen0c49ff72012-10-23 13:44:12 +0300419static inline struct omap_dss_device *dss_mgr_get_device(struct omap_overlay_manager *mgr)
420{
421 return mgr->output ? mgr->output->device : NULL;
422}
423
424static int dss_mgr_wait_for_vsync(struct omap_overlay_manager *mgr)
425{
426 unsigned long timeout = msecs_to_jiffies(500);
427 struct omap_dss_device *dssdev = mgr->get_device(mgr);
428 u32 irq;
429 int r;
430
431 r = dispc_runtime_get();
432 if (r)
433 return r;
434
435 if (dssdev->type == OMAP_DISPLAY_TYPE_VENC)
436 irq = DISPC_IRQ_EVSYNC_ODD;
437 else if (dssdev->type == OMAP_DISPLAY_TYPE_HDMI)
438 irq = DISPC_IRQ_EVSYNC_EVEN;
439 else
440 irq = dispc_mgr_get_vsync_irq(mgr->id);
441
442 r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
443
444 dispc_runtime_put();
445
446 return r;
447}
448
449static int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200450{
451 unsigned long timeout = msecs_to_jiffies(500);
Archit Tanejafc22a842012-06-26 15:36:55 +0530452 struct mgr_priv_data *mp = get_mgr_priv(mgr);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200453 u32 irq;
Archit Tanejafc22a842012-06-26 15:36:55 +0530454 unsigned long flags;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200455 int r;
456 int i;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200457
Archit Tanejafc22a842012-06-26 15:36:55 +0530458 spin_lock_irqsave(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200459
Archit Tanejafc22a842012-06-26 15:36:55 +0530460 if (mgr_manual_update(mgr)) {
461 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200462 return 0;
Archit Tanejafc22a842012-06-26 15:36:55 +0530463 }
464
465 if (!mp->enabled) {
466 spin_unlock_irqrestore(&data_lock, flags);
467 return 0;
468 }
469
470 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200471
Lajos Molnar21e56f72012-02-22 12:23:16 +0530472 r = dispc_runtime_get();
473 if (r)
474 return r;
475
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200476 irq = dispc_mgr_get_vsync_irq(mgr->id);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200477
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200478 i = 0;
479 while (1) {
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200480 bool shadow_dirty, dirty;
481
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200482 spin_lock_irqsave(&data_lock, flags);
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200483 dirty = mp->info_dirty;
484 shadow_dirty = mp->shadow_info_dirty;
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200485 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200486
487 if (!dirty && !shadow_dirty) {
488 r = 0;
489 break;
490 }
491
492 /* 4 iterations is the worst case:
493 * 1 - initial iteration, dirty = true (between VFP and VSYNC)
494 * 2 - first VSYNC, dirty = true
495 * 3 - dirty = false, shadow_dirty = true
496 * 4 - shadow_dirty = false */
497 if (i++ == 3) {
498 DSSERR("mgr(%d)->wait_for_go() not finishing\n",
499 mgr->id);
500 r = 0;
501 break;
502 }
503
504 r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
505 if (r == -ERESTARTSYS)
506 break;
507
508 if (r) {
509 DSSERR("mgr(%d)->wait_for_go() timeout\n", mgr->id);
510 break;
511 }
512 }
513
Lajos Molnar21e56f72012-02-22 12:23:16 +0530514 dispc_runtime_put();
515
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200516 return r;
517}
518
519int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl)
520{
521 unsigned long timeout = msecs_to_jiffies(500);
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200522 struct ovl_priv_data *op;
Archit Tanejafc22a842012-06-26 15:36:55 +0530523 struct mgr_priv_data *mp;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200524 u32 irq;
Archit Tanejafc22a842012-06-26 15:36:55 +0530525 unsigned long flags;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200526 int r;
527 int i;
528
529 if (!ovl->manager)
530 return 0;
531
Archit Tanejafc22a842012-06-26 15:36:55 +0530532 mp = get_mgr_priv(ovl->manager);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200533
Archit Tanejafc22a842012-06-26 15:36:55 +0530534 spin_lock_irqsave(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200535
Archit Tanejafc22a842012-06-26 15:36:55 +0530536 if (ovl_manual_update(ovl)) {
537 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200538 return 0;
Archit Tanejafc22a842012-06-26 15:36:55 +0530539 }
540
541 if (!mp->enabled) {
542 spin_unlock_irqrestore(&data_lock, flags);
543 return 0;
544 }
545
546 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200547
Lajos Molnar21e56f72012-02-22 12:23:16 +0530548 r = dispc_runtime_get();
549 if (r)
550 return r;
551
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200552 irq = dispc_mgr_get_vsync_irq(ovl->manager->id);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200553
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200554 op = get_ovl_priv(ovl);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200555 i = 0;
556 while (1) {
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200557 bool shadow_dirty, dirty;
558
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200559 spin_lock_irqsave(&data_lock, flags);
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200560 dirty = op->info_dirty;
561 shadow_dirty = op->shadow_info_dirty;
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200562 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200563
564 if (!dirty && !shadow_dirty) {
565 r = 0;
566 break;
567 }
568
569 /* 4 iterations is the worst case:
570 * 1 - initial iteration, dirty = true (between VFP and VSYNC)
571 * 2 - first VSYNC, dirty = true
572 * 3 - dirty = false, shadow_dirty = true
573 * 4 - shadow_dirty = false */
574 if (i++ == 3) {
575 DSSERR("ovl(%d)->wait_for_go() not finishing\n",
576 ovl->id);
577 r = 0;
578 break;
579 }
580
581 r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
582 if (r == -ERESTARTSYS)
583 break;
584
585 if (r) {
586 DSSERR("ovl(%d)->wait_for_go() timeout\n", ovl->id);
587 break;
588 }
589 }
590
Lajos Molnar21e56f72012-02-22 12:23:16 +0530591 dispc_runtime_put();
592
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200593 return r;
594}
595
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200596static void dss_ovl_write_regs(struct omap_overlay *ovl)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200597{
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200598 struct ovl_priv_data *op = get_ovl_priv(ovl);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200599 struct omap_overlay_info *oi;
Archit Taneja8050cbe2012-06-06 16:25:52 +0530600 bool replication;
Tomi Valkeinen34861372011-11-18 15:43:29 +0200601 struct mgr_priv_data *mp;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200602 int r;
603
Chandrabhanu Mahapatra702d2672012-09-24 17:12:58 +0530604 DSSDBG("writing ovl %d regs", ovl->id);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200605
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200606 if (!op->enabled || !op->info_dirty)
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200607 return;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200608
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200609 oi = &op->info;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200610
Archit Taneja81ab95b2012-05-08 15:53:20 +0530611 mp = get_mgr_priv(ovl->manager);
612
Archit Taneja6c6f5102012-06-25 14:58:48 +0530613 replication = dss_ovl_use_replication(mp->lcd_config, oi->color_mode);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200614
Archit Taneja8ba85302012-09-26 17:00:37 +0530615 r = dispc_ovl_setup(ovl->id, oi, replication, &mp->timings, false);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200616 if (r) {
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200617 /*
618 * We can't do much here, as this function can be called from
619 * vsync interrupt.
620 */
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200621 DSSERR("dispc_ovl_setup failed for ovl %d\n", ovl->id);
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200622
623 /* This will leave fifo configurations in a nonoptimal state */
624 op->enabled = false;
625 dispc_ovl_enable(ovl->id, false);
626 return;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200627 }
628
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200629 op->info_dirty = false;
Tomi Valkeinen34861372011-11-18 15:43:29 +0200630 if (mp->updating)
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200631 op->shadow_info_dirty = true;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200632}
633
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200634static void dss_ovl_write_regs_extra(struct omap_overlay *ovl)
635{
636 struct ovl_priv_data *op = get_ovl_priv(ovl);
Tomi Valkeinen34861372011-11-18 15:43:29 +0200637 struct mgr_priv_data *mp;
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200638
Chandrabhanu Mahapatra702d2672012-09-24 17:12:58 +0530639 DSSDBG("writing ovl %d regs extra", ovl->id);
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200640
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200641 if (!op->extra_info_dirty)
642 return;
643
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200644 /* note: write also when op->enabled == false, so that the ovl gets
645 * disabled */
646
647 dispc_ovl_enable(ovl->id, op->enabled);
Tomi Valkeinen6dc802e2011-11-16 14:28:12 +0200648 dispc_ovl_set_fifo_threshold(ovl->id, op->fifo_low, op->fifo_high);
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200649
Tomi Valkeinen34861372011-11-18 15:43:29 +0200650 mp = get_mgr_priv(ovl->manager);
651
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200652 op->extra_info_dirty = false;
Tomi Valkeinen34861372011-11-18 15:43:29 +0200653 if (mp->updating)
654 op->shadow_extra_info_dirty = true;
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200655}
656
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200657static void dss_mgr_write_regs(struct omap_overlay_manager *mgr)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200658{
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200659 struct mgr_priv_data *mp = get_mgr_priv(mgr);
660 struct omap_overlay *ovl;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200661
Chandrabhanu Mahapatra702d2672012-09-24 17:12:58 +0530662 DSSDBG("writing mgr %d regs", mgr->id);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200663
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200664 if (!mp->enabled)
665 return;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200666
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200667 WARN_ON(mp->busy);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200668
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200669 /* Commit overlay settings */
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200670 list_for_each_entry(ovl, &mgr->overlays, list) {
671 dss_ovl_write_regs(ovl);
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200672 dss_ovl_write_regs_extra(ovl);
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200673 }
674
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200675 if (mp->info_dirty) {
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200676 dispc_mgr_setup(mgr->id, &mp->info);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200677
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200678 mp->info_dirty = false;
Tomi Valkeinen34861372011-11-18 15:43:29 +0200679 if (mp->updating)
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200680 mp->shadow_info_dirty = true;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200681 }
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200682}
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200683
Archit Taneja45324a22012-04-26 19:31:22 +0530684static void dss_mgr_write_regs_extra(struct omap_overlay_manager *mgr)
685{
686 struct mgr_priv_data *mp = get_mgr_priv(mgr);
687
Chandrabhanu Mahapatra702d2672012-09-24 17:12:58 +0530688 DSSDBG("writing mgr %d regs extra", mgr->id);
Archit Taneja45324a22012-04-26 19:31:22 +0530689
690 if (!mp->extra_info_dirty)
691 return;
692
693 dispc_mgr_set_timings(mgr->id, &mp->timings);
694
Archit Tanejaf476ae92012-06-29 14:37:03 +0530695 /* lcd_config parameters */
Tomi Valkeinenfb2cec12012-09-12 13:30:39 +0300696 if (dss_mgr_is_lcd(mgr->id))
697 dispc_mgr_set_lcd_config(mgr->id, &mp->lcd_config);
Archit Tanejaf476ae92012-06-29 14:37:03 +0530698
Archit Taneja45324a22012-04-26 19:31:22 +0530699 mp->extra_info_dirty = false;
700 if (mp->updating)
701 mp->shadow_extra_info_dirty = true;
702}
703
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200704static void dss_write_regs(void)
705{
706 const int num_mgrs = omap_dss_get_num_overlay_managers();
707 int i;
708
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200709 for (i = 0; i < num_mgrs; ++i) {
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200710 struct omap_overlay_manager *mgr;
711 struct mgr_priv_data *mp;
Tomi Valkeinen39518352011-11-17 17:35:28 +0200712 int r;
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200713
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200714 mgr = omap_dss_get_overlay_manager(i);
715 mp = get_mgr_priv(mgr);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200716
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200717 if (!mp->enabled || mgr_manual_update(mgr) || mp->busy)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200718 continue;
719
Archit Taneja228b2132012-04-27 01:22:28 +0530720 r = dss_check_settings(mgr);
Tomi Valkeinen39518352011-11-17 17:35:28 +0200721 if (r) {
722 DSSERR("cannot write registers for manager %s: "
723 "illegal configuration\n", mgr->name);
724 continue;
725 }
726
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200727 dss_mgr_write_regs(mgr);
Archit Taneja45324a22012-04-26 19:31:22 +0530728 dss_mgr_write_regs_extra(mgr);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200729 }
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200730}
731
Tomi Valkeinen3ab15b22011-11-25 17:32:20 +0200732static void dss_set_go_bits(void)
733{
734 const int num_mgrs = omap_dss_get_num_overlay_managers();
735 int i;
736
737 for (i = 0; i < num_mgrs; ++i) {
738 struct omap_overlay_manager *mgr;
739 struct mgr_priv_data *mp;
740
741 mgr = omap_dss_get_overlay_manager(i);
742 mp = get_mgr_priv(mgr);
743
744 if (!mp->enabled || mgr_manual_update(mgr) || mp->busy)
745 continue;
746
747 if (!need_go(mgr))
748 continue;
749
750 mp->busy = true;
751
752 if (!dss_data.irq_enabled && need_isr())
753 dss_register_vsync_isr();
754
755 dispc_mgr_go(mgr->id);
756 }
757
758}
759
Tomi Valkeinendf01d532012-03-07 10:28:48 +0200760static void mgr_clear_shadow_dirty(struct omap_overlay_manager *mgr)
761{
762 struct omap_overlay *ovl;
763 struct mgr_priv_data *mp;
764 struct ovl_priv_data *op;
765
766 mp = get_mgr_priv(mgr);
767 mp->shadow_info_dirty = false;
Archit Taneja45324a22012-04-26 19:31:22 +0530768 mp->shadow_extra_info_dirty = false;
Tomi Valkeinendf01d532012-03-07 10:28:48 +0200769
770 list_for_each_entry(ovl, &mgr->overlays, list) {
771 op = get_ovl_priv(ovl);
772 op->shadow_info_dirty = false;
773 op->shadow_extra_info_dirty = false;
774 }
775}
776
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200777void dss_mgr_start_update(struct omap_overlay_manager *mgr)
778{
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200779 struct mgr_priv_data *mp = get_mgr_priv(mgr);
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200780 unsigned long flags;
Tomi Valkeinen39518352011-11-17 17:35:28 +0200781 int r;
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200782
783 spin_lock_irqsave(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200784
Tomi Valkeinen34861372011-11-18 15:43:29 +0200785 WARN_ON(mp->updating);
786
Archit Taneja228b2132012-04-27 01:22:28 +0530787 r = dss_check_settings(mgr);
Tomi Valkeinen39518352011-11-17 17:35:28 +0200788 if (r) {
789 DSSERR("cannot start manual update: illegal configuration\n");
790 spin_unlock_irqrestore(&data_lock, flags);
791 return;
792 }
793
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200794 dss_mgr_write_regs(mgr);
Archit Taneja45324a22012-04-26 19:31:22 +0530795 dss_mgr_write_regs_extra(mgr);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200796
Tomi Valkeinen34861372011-11-18 15:43:29 +0200797 mp->updating = true;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200798
Tomi Valkeinen34861372011-11-18 15:43:29 +0200799 if (!dss_data.irq_enabled && need_isr())
800 dss_register_vsync_isr();
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200801
Tomi Valkeinen3a979f82012-10-19 14:14:38 +0300802 dispc_mgr_enable_sync(mgr->id);
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200803
804 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200805}
806
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200807static void dss_apply_irq_handler(void *data, u32 mask);
808
809static void dss_register_vsync_isr(void)
810{
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200811 const int num_mgrs = dss_feat_get_num_mgrs();
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200812 u32 mask;
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200813 int r, i;
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200814
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200815 mask = 0;
816 for (i = 0; i < num_mgrs; ++i)
817 mask |= dispc_mgr_get_vsync_irq(i);
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200818
Tomi Valkeinen34861372011-11-18 15:43:29 +0200819 for (i = 0; i < num_mgrs; ++i)
820 mask |= dispc_mgr_get_framedone_irq(i);
821
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200822 r = omap_dispc_register_isr(dss_apply_irq_handler, NULL, mask);
823 WARN_ON(r);
824
Tomi Valkeinend09c7aa2011-11-15 12:04:43 +0200825 dss_data.irq_enabled = true;
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200826}
827
828static void dss_unregister_vsync_isr(void)
829{
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200830 const int num_mgrs = dss_feat_get_num_mgrs();
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200831 u32 mask;
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200832 int r, i;
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200833
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200834 mask = 0;
835 for (i = 0; i < num_mgrs; ++i)
836 mask |= dispc_mgr_get_vsync_irq(i);
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200837
Tomi Valkeinen34861372011-11-18 15:43:29 +0200838 for (i = 0; i < num_mgrs; ++i)
839 mask |= dispc_mgr_get_framedone_irq(i);
840
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200841 r = omap_dispc_unregister_isr(dss_apply_irq_handler, NULL, mask);
842 WARN_ON(r);
843
Tomi Valkeinend09c7aa2011-11-15 12:04:43 +0200844 dss_data.irq_enabled = false;
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200845}
846
Tomi Valkeinen76098932011-11-16 12:03:22 +0200847static void dss_apply_irq_handler(void *data, u32 mask)
848{
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200849 const int num_mgrs = dss_feat_get_num_mgrs();
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200850 int i;
Tomi Valkeinenf1577ce2011-11-16 14:37:48 +0200851 bool extra_updating;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200852
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200853 spin_lock(&data_lock);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200854
Tomi Valkeinen76098932011-11-16 12:03:22 +0200855 /* clear busy, updating flags, shadow_dirty flags */
Tomi Valkeinen43a972d2011-11-15 15:04:25 +0200856 for (i = 0; i < num_mgrs; i++) {
Tomi Valkeinen76098932011-11-16 12:03:22 +0200857 struct omap_overlay_manager *mgr;
858 struct mgr_priv_data *mp;
859
Tomi Valkeinen43a972d2011-11-15 15:04:25 +0200860 mgr = omap_dss_get_overlay_manager(i);
861 mp = get_mgr_priv(mgr);
862
Tomi Valkeinen76098932011-11-16 12:03:22 +0200863 if (!mp->enabled)
Tomi Valkeinen43a972d2011-11-15 15:04:25 +0200864 continue;
865
Tomi Valkeinen76098932011-11-16 12:03:22 +0200866 mp->updating = dispc_mgr_is_enabled(i);
Tomi Valkeinen43a972d2011-11-15 15:04:25 +0200867
Tomi Valkeinen76098932011-11-16 12:03:22 +0200868 if (!mgr_manual_update(mgr)) {
Tomi Valkeinen5b214172011-11-25 17:27:45 +0200869 bool was_busy = mp->busy;
Tomi Valkeinen76098932011-11-16 12:03:22 +0200870 mp->busy = dispc_mgr_go_busy(i);
871
Tomi Valkeinen5b214172011-11-25 17:27:45 +0200872 if (was_busy && !mp->busy)
Tomi Valkeinen76098932011-11-16 12:03:22 +0200873 mgr_clear_shadow_dirty(mgr);
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200874 }
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200875 }
876
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200877 dss_write_regs();
Tomi Valkeinen3ab15b22011-11-25 17:32:20 +0200878 dss_set_go_bits();
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200879
Tomi Valkeinenf1577ce2011-11-16 14:37:48 +0200880 extra_updating = extra_info_update_ongoing();
881 if (!extra_updating)
882 complete_all(&extra_updated_completion);
883
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200884 if (!need_isr())
885 dss_unregister_vsync_isr();
Tomi Valkeinen43a972d2011-11-15 15:04:25 +0200886
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200887 spin_unlock(&data_lock);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200888}
889
Tomi Valkeinen5738b632011-11-15 13:37:33 +0200890static void omap_dss_mgr_apply_ovl(struct omap_overlay *ovl)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200891{
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200892 struct ovl_priv_data *op;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200893
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200894 op = get_ovl_priv(ovl);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200895
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +0200896 if (!op->user_info_dirty)
Tomi Valkeinen5738b632011-11-15 13:37:33 +0200897 return;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200898
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +0200899 op->user_info_dirty = false;
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200900 op->info_dirty = true;
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +0200901 op->info = op->user_info;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200902}
903
904static void omap_dss_mgr_apply_mgr(struct omap_overlay_manager *mgr)
905{
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200906 struct mgr_priv_data *mp;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200907
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200908 mp = get_mgr_priv(mgr);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200909
Tomi Valkeinen388c4c62011-11-16 13:58:07 +0200910 if (!mp->user_info_dirty)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200911 return;
912
Tomi Valkeinen388c4c62011-11-16 13:58:07 +0200913 mp->user_info_dirty = false;
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200914 mp->info_dirty = true;
Tomi Valkeinen388c4c62011-11-16 13:58:07 +0200915 mp->info = mp->user_info;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200916}
917
Tomi Valkeinen0c49ff72012-10-23 13:44:12 +0300918static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200919{
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200920 unsigned long flags;
Tomi Valkeinen07e327c2011-11-05 10:59:59 +0200921 struct omap_overlay *ovl;
Tomi Valkeinen39518352011-11-17 17:35:28 +0200922 int r;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200923
924 DSSDBG("omap_dss_mgr_apply(%s)\n", mgr->name);
925
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200926 spin_lock_irqsave(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200927
Archit Taneja228b2132012-04-27 01:22:28 +0530928 r = dss_check_settings_apply(mgr);
Tomi Valkeinen39518352011-11-17 17:35:28 +0200929 if (r) {
930 spin_unlock_irqrestore(&data_lock, flags);
931 DSSERR("failed to apply settings: illegal configuration.\n");
932 return r;
933 }
934
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200935 /* Configure overlays */
Tomi Valkeinen07e327c2011-11-05 10:59:59 +0200936 list_for_each_entry(ovl, &mgr->overlays, list)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200937 omap_dss_mgr_apply_ovl(ovl);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200938
939 /* Configure manager */
940 omap_dss_mgr_apply_mgr(mgr);
941
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200942 dss_write_regs();
Tomi Valkeinen3ab15b22011-11-25 17:32:20 +0200943 dss_set_go_bits();
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200944
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200945 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200946
Tomi Valkeinene70f98a2011-11-16 16:53:44 +0200947 return 0;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200948}
949
Tomi Valkeinen841c09c2011-11-16 15:25:53 +0200950static void dss_apply_ovl_enable(struct omap_overlay *ovl, bool enable)
951{
952 struct ovl_priv_data *op;
953
954 op = get_ovl_priv(ovl);
955
956 if (op->enabled == enable)
957 return;
958
959 op->enabled = enable;
960 op->extra_info_dirty = true;
961}
962
Tomi Valkeinen04576d42011-11-26 14:39:16 +0200963static void dss_apply_ovl_fifo_thresholds(struct omap_overlay *ovl,
964 u32 fifo_low, u32 fifo_high)
965{
966 struct ovl_priv_data *op = get_ovl_priv(ovl);
967
968 if (op->fifo_low == fifo_low && op->fifo_high == fifo_high)
969 return;
970
971 op->fifo_low = fifo_low;
972 op->fifo_high = fifo_high;
973 op->extra_info_dirty = true;
974}
975
Tomi Valkeinenb3e93cb2012-08-06 16:50:14 +0300976static void dss_ovl_setup_fifo(struct omap_overlay *ovl)
Tomi Valkeinen6dc802e2011-11-16 14:28:12 +0200977{
978 struct ovl_priv_data *op = get_ovl_priv(ovl);
Tomi Valkeinen6dc802e2011-11-16 14:28:12 +0200979 u32 fifo_low, fifo_high;
Tomi Valkeinenb3e93cb2012-08-06 16:50:14 +0300980 bool use_fifo_merge = false;
Tomi Valkeinen6dc802e2011-11-16 14:28:12 +0200981
Tomi Valkeinen75ae1182011-11-26 14:36:19 +0200982 if (!op->enabled && !op->enabling)
983 return;
984
Tomi Valkeinen83fa2f22012-01-13 13:17:01 +0200985 dispc_ovl_compute_fifo_thresholds(ovl->id, &fifo_low, &fifo_high,
Tomi Valkeinen3568f2a2012-05-15 15:31:01 +0300986 use_fifo_merge, ovl_manual_update(ovl));
Tomi Valkeinen6dc802e2011-11-16 14:28:12 +0200987
Tomi Valkeinen04576d42011-11-26 14:39:16 +0200988 dss_apply_ovl_fifo_thresholds(ovl, fifo_low, fifo_high);
Tomi Valkeinen6dc802e2011-11-16 14:28:12 +0200989}
990
Tomi Valkeinenb3e93cb2012-08-06 16:50:14 +0300991static void dss_mgr_setup_fifos(struct omap_overlay_manager *mgr)
Tomi Valkeinen6dc802e2011-11-16 14:28:12 +0200992{
993 struct omap_overlay *ovl;
Tomi Valkeinen6dc802e2011-11-16 14:28:12 +0200994 struct mgr_priv_data *mp;
995
996 mp = get_mgr_priv(mgr);
997
998 if (!mp->enabled)
999 return;
1000
Tomi Valkeinen75ae1182011-11-26 14:36:19 +02001001 list_for_each_entry(ovl, &mgr->overlays, list)
Tomi Valkeinenb3e93cb2012-08-06 16:50:14 +03001002 dss_ovl_setup_fifo(ovl);
Tomi Valkeinen75ae1182011-11-26 14:36:19 +02001003}
1004
Tomi Valkeinenb3e93cb2012-08-06 16:50:14 +03001005static void dss_setup_fifos(void)
Tomi Valkeinen75ae1182011-11-26 14:36:19 +02001006{
1007 const int num_mgrs = omap_dss_get_num_overlay_managers();
1008 struct omap_overlay_manager *mgr;
1009 int i;
1010
1011 for (i = 0; i < num_mgrs; ++i) {
1012 mgr = omap_dss_get_overlay_manager(i);
Tomi Valkeinenb3e93cb2012-08-06 16:50:14 +03001013 dss_mgr_setup_fifos(mgr);
Tomi Valkeinen6dc802e2011-11-16 14:28:12 +02001014 }
1015}
1016
Tomi Valkeinen2a4ee7e2011-11-21 13:34:48 +02001017int dss_mgr_enable(struct omap_overlay_manager *mgr)
Tomi Valkeinen7797c6d2011-11-04 10:22:46 +02001018{
Tomi Valkeinenbf213522011-11-15 14:43:53 +02001019 struct mgr_priv_data *mp = get_mgr_priv(mgr);
1020 unsigned long flags;
Tomi Valkeinen39518352011-11-17 17:35:28 +02001021 int r;
Tomi Valkeinenbf213522011-11-15 14:43:53 +02001022
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001023 mutex_lock(&apply_lock);
1024
Tomi Valkeinene4f7ad72011-11-16 16:01:33 +02001025 if (mp->enabled)
1026 goto out;
1027
Tomi Valkeinenbf213522011-11-15 14:43:53 +02001028 spin_lock_irqsave(&data_lock, flags);
1029
1030 mp->enabled = true;
Tomi Valkeinena6b24f82011-11-26 14:29:39 +02001031
Archit Taneja228b2132012-04-27 01:22:28 +05301032 r = dss_check_settings(mgr);
Tomi Valkeinen39518352011-11-17 17:35:28 +02001033 if (r) {
1034 DSSERR("failed to enable manager %d: check_settings failed\n",
1035 mgr->id);
Tomi Valkeinen2a4ee7e2011-11-21 13:34:48 +02001036 goto err;
Tomi Valkeinen39518352011-11-17 17:35:28 +02001037 }
1038
Tomi Valkeinenb3e93cb2012-08-06 16:50:14 +03001039 dss_setup_fifos();
Tomi Valkeinen6dc802e2011-11-16 14:28:12 +02001040
Tomi Valkeinen75c94962011-11-15 18:25:23 +02001041 dss_write_regs();
Tomi Valkeinen3ab15b22011-11-25 17:32:20 +02001042 dss_set_go_bits();
Tomi Valkeinen75c94962011-11-15 18:25:23 +02001043
Tomi Valkeinen34861372011-11-18 15:43:29 +02001044 if (!mgr_manual_update(mgr))
1045 mp->updating = true;
1046
Tomi Valkeinend7b6b6b2012-08-10 14:17:47 +03001047 if (!dss_data.irq_enabled && need_isr())
1048 dss_register_vsync_isr();
1049
Tomi Valkeinenbf213522011-11-15 14:43:53 +02001050 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001051
Tomi Valkeinen75c94962011-11-15 18:25:23 +02001052 if (!mgr_manual_update(mgr))
Tomi Valkeinen3a979f82012-10-19 14:14:38 +03001053 dispc_mgr_enable_sync(mgr->id);
Tomi Valkeinen75c94962011-11-15 18:25:23 +02001054
Tomi Valkeinene4f7ad72011-11-16 16:01:33 +02001055out:
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001056 mutex_unlock(&apply_lock);
Tomi Valkeinen2a4ee7e2011-11-21 13:34:48 +02001057
1058 return 0;
1059
1060err:
Tomi Valkeinena6b24f82011-11-26 14:29:39 +02001061 mp->enabled = false;
Tomi Valkeinen2a4ee7e2011-11-21 13:34:48 +02001062 spin_unlock_irqrestore(&data_lock, flags);
1063 mutex_unlock(&apply_lock);
1064 return r;
Tomi Valkeinen7797c6d2011-11-04 10:22:46 +02001065}
1066
1067void dss_mgr_disable(struct omap_overlay_manager *mgr)
1068{
Tomi Valkeinenbf213522011-11-15 14:43:53 +02001069 struct mgr_priv_data *mp = get_mgr_priv(mgr);
1070 unsigned long flags;
1071
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001072 mutex_lock(&apply_lock);
1073
Tomi Valkeinene4f7ad72011-11-16 16:01:33 +02001074 if (!mp->enabled)
1075 goto out;
1076
Tomi Valkeinen9a147a62011-11-09 15:30:11 +02001077 if (!mgr_manual_update(mgr))
Tomi Valkeinen3a979f82012-10-19 14:14:38 +03001078 dispc_mgr_disable_sync(mgr->id);
Tomi Valkeinenbf213522011-11-15 14:43:53 +02001079
1080 spin_lock_irqsave(&data_lock, flags);
1081
Tomi Valkeinen34861372011-11-18 15:43:29 +02001082 mp->updating = false;
Tomi Valkeinenbf213522011-11-15 14:43:53 +02001083 mp->enabled = false;
1084
1085 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001086
Tomi Valkeinene4f7ad72011-11-16 16:01:33 +02001087out:
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001088 mutex_unlock(&apply_lock);
Tomi Valkeinen7797c6d2011-11-04 10:22:46 +02001089}
1090
Tomi Valkeinen0c49ff72012-10-23 13:44:12 +03001091static int dss_mgr_set_info(struct omap_overlay_manager *mgr,
Tomi Valkeineneb70d732011-11-15 12:15:18 +02001092 struct omap_overlay_manager_info *info)
1093{
Tomi Valkeinen388c4c62011-11-16 13:58:07 +02001094 struct mgr_priv_data *mp = get_mgr_priv(mgr);
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +02001095 unsigned long flags;
Tomi Valkeinenf17d04f2011-11-17 14:31:09 +02001096 int r;
1097
1098 r = dss_mgr_simple_check(mgr, info);
1099 if (r)
1100 return r;
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +02001101
1102 spin_lock_irqsave(&data_lock, flags);
1103
Tomi Valkeinen388c4c62011-11-16 13:58:07 +02001104 mp->user_info = *info;
1105 mp->user_info_dirty = true;
Tomi Valkeineneb70d732011-11-15 12:15:18 +02001106
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +02001107 spin_unlock_irqrestore(&data_lock, flags);
1108
Tomi Valkeineneb70d732011-11-15 12:15:18 +02001109 return 0;
1110}
1111
Tomi Valkeinen0c49ff72012-10-23 13:44:12 +03001112static void dss_mgr_get_info(struct omap_overlay_manager *mgr,
Tomi Valkeineneb70d732011-11-15 12:15:18 +02001113 struct omap_overlay_manager_info *info)
1114{
Tomi Valkeinen388c4c62011-11-16 13:58:07 +02001115 struct mgr_priv_data *mp = get_mgr_priv(mgr);
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +02001116 unsigned long flags;
1117
1118 spin_lock_irqsave(&data_lock, flags);
1119
Tomi Valkeinen388c4c62011-11-16 13:58:07 +02001120 *info = mp->user_info;
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +02001121
1122 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeineneb70d732011-11-15 12:15:18 +02001123}
1124
Tomi Valkeinen0c49ff72012-10-23 13:44:12 +03001125static int dss_mgr_set_output(struct omap_overlay_manager *mgr,
Archit Taneja97f01b32012-09-26 16:42:39 +05301126 struct omap_dss_output *output)
1127{
1128 int r;
1129
1130 mutex_lock(&apply_lock);
1131
1132 if (mgr->output) {
1133 DSSERR("manager %s is already connected to an output\n",
1134 mgr->name);
1135 r = -EINVAL;
1136 goto err;
1137 }
1138
1139 if ((mgr->supported_outputs & output->id) == 0) {
1140 DSSERR("output does not support manager %s\n",
1141 mgr->name);
1142 r = -EINVAL;
1143 goto err;
1144 }
1145
1146 output->manager = mgr;
1147 mgr->output = output;
1148
1149 mutex_unlock(&apply_lock);
1150
1151 return 0;
1152err:
1153 mutex_unlock(&apply_lock);
1154 return r;
1155}
1156
Tomi Valkeinen0c49ff72012-10-23 13:44:12 +03001157static int dss_mgr_unset_output(struct omap_overlay_manager *mgr)
Archit Taneja97f01b32012-09-26 16:42:39 +05301158{
1159 int r;
1160 struct mgr_priv_data *mp = get_mgr_priv(mgr);
1161 unsigned long flags;
1162
1163 mutex_lock(&apply_lock);
1164
1165 if (!mgr->output) {
1166 DSSERR("failed to unset output, output not set\n");
1167 r = -EINVAL;
1168 goto err;
1169 }
1170
1171 spin_lock_irqsave(&data_lock, flags);
1172
1173 if (mp->enabled) {
1174 DSSERR("output can't be unset when manager is enabled\n");
1175 r = -EINVAL;
1176 goto err1;
1177 }
1178
1179 spin_unlock_irqrestore(&data_lock, flags);
1180
1181 mgr->output->manager = NULL;
1182 mgr->output = NULL;
1183
1184 mutex_unlock(&apply_lock);
1185
1186 return 0;
1187err1:
1188 spin_unlock_irqrestore(&data_lock, flags);
1189err:
1190 mutex_unlock(&apply_lock);
1191
1192 return r;
1193}
1194
Archit Taneja45324a22012-04-26 19:31:22 +05301195static void dss_apply_mgr_timings(struct omap_overlay_manager *mgr,
Archit Taneja27dfddc2012-07-19 13:51:14 +05301196 const struct omap_video_timings *timings)
Archit Taneja45324a22012-04-26 19:31:22 +05301197{
1198 struct mgr_priv_data *mp = get_mgr_priv(mgr);
1199
1200 mp->timings = *timings;
1201 mp->extra_info_dirty = true;
1202}
1203
1204void dss_mgr_set_timings(struct omap_overlay_manager *mgr,
Archit Taneja27dfddc2012-07-19 13:51:14 +05301205 const struct omap_video_timings *timings)
Archit Taneja45324a22012-04-26 19:31:22 +05301206{
1207 unsigned long flags;
Tomi Valkeinenfed62e52012-08-09 18:13:13 +03001208 struct mgr_priv_data *mp = get_mgr_priv(mgr);
Archit Taneja45324a22012-04-26 19:31:22 +05301209
1210 spin_lock_irqsave(&data_lock, flags);
1211
Tomi Valkeinenfed62e52012-08-09 18:13:13 +03001212 if (mp->updating) {
1213 DSSERR("cannot set timings for %s: manager needs to be disabled\n",
1214 mgr->name);
1215 goto out;
1216 }
1217
Archit Taneja45324a22012-04-26 19:31:22 +05301218 dss_apply_mgr_timings(mgr, timings);
Tomi Valkeinenfed62e52012-08-09 18:13:13 +03001219out:
Archit Taneja45324a22012-04-26 19:31:22 +05301220 spin_unlock_irqrestore(&data_lock, flags);
Archit Taneja45324a22012-04-26 19:31:22 +05301221}
Tomi Valkeineneb70d732011-11-15 12:15:18 +02001222
Archit Tanejaf476ae92012-06-29 14:37:03 +05301223static void dss_apply_mgr_lcd_config(struct omap_overlay_manager *mgr,
1224 const struct dss_lcd_mgr_config *config)
1225{
1226 struct mgr_priv_data *mp = get_mgr_priv(mgr);
1227
1228 mp->lcd_config = *config;
1229 mp->extra_info_dirty = true;
1230}
1231
1232void dss_mgr_set_lcd_config(struct omap_overlay_manager *mgr,
1233 const struct dss_lcd_mgr_config *config)
1234{
1235 unsigned long flags;
1236 struct mgr_priv_data *mp = get_mgr_priv(mgr);
1237
Tomi Valkeinenaba96572012-08-09 18:07:45 +03001238 spin_lock_irqsave(&data_lock, flags);
Archit Tanejaf476ae92012-06-29 14:37:03 +05301239
1240 if (mp->enabled) {
1241 DSSERR("cannot apply lcd config for %s: manager needs to be disabled\n",
1242 mgr->name);
1243 goto out;
1244 }
1245
Archit Tanejaf476ae92012-06-29 14:37:03 +05301246 dss_apply_mgr_lcd_config(mgr, config);
Archit Tanejaf476ae92012-06-29 14:37:03 +05301247out:
Tomi Valkeinenaba96572012-08-09 18:07:45 +03001248 spin_unlock_irqrestore(&data_lock, flags);
Archit Tanejaf476ae92012-06-29 14:37:03 +05301249}
1250
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001251int dss_ovl_set_info(struct omap_overlay *ovl,
1252 struct omap_overlay_info *info)
1253{
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +02001254 struct ovl_priv_data *op = get_ovl_priv(ovl);
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +02001255 unsigned long flags;
Tomi Valkeinenfcc764d2011-11-17 14:26:48 +02001256 int r;
1257
1258 r = dss_ovl_simple_check(ovl, info);
1259 if (r)
1260 return r;
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +02001261
1262 spin_lock_irqsave(&data_lock, flags);
1263
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +02001264 op->user_info = *info;
1265 op->user_info_dirty = true;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001266
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +02001267 spin_unlock_irqrestore(&data_lock, flags);
1268
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001269 return 0;
1270}
1271
1272void dss_ovl_get_info(struct omap_overlay *ovl,
1273 struct omap_overlay_info *info)
1274{
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +02001275 struct ovl_priv_data *op = get_ovl_priv(ovl);
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +02001276 unsigned long flags;
1277
1278 spin_lock_irqsave(&data_lock, flags);
1279
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +02001280 *info = op->user_info;
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +02001281
1282 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001283}
1284
1285int dss_ovl_set_manager(struct omap_overlay *ovl,
1286 struct omap_overlay_manager *mgr)
1287{
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001288 struct ovl_priv_data *op = get_ovl_priv(ovl);
1289 unsigned long flags;
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001290 int r;
1291
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001292 if (!mgr)
1293 return -EINVAL;
1294
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001295 mutex_lock(&apply_lock);
1296
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001297 if (ovl->manager) {
1298 DSSERR("overlay '%s' already has a manager '%s'\n",
1299 ovl->name, ovl->manager->name);
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001300 r = -EINVAL;
1301 goto err;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001302 }
1303
Archit Taneja02b5ff12012-11-07 14:47:22 +05301304 r = dispc_runtime_get();
1305 if (r)
1306 goto err;
1307
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001308 spin_lock_irqsave(&data_lock, flags);
1309
1310 if (op->enabled) {
1311 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001312 DSSERR("overlay has to be disabled to change the manager\n");
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001313 r = -EINVAL;
Archit Taneja02b5ff12012-11-07 14:47:22 +05301314 goto err1;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001315 }
1316
Archit Taneja02b5ff12012-11-07 14:47:22 +05301317 dispc_ovl_set_channel_out(ovl->id, mgr->id);
Tomi Valkeinen5d5a97a2011-11-16 14:17:54 +02001318
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001319 ovl->manager = mgr;
1320 list_add_tail(&ovl->list, &mgr->overlays);
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001321
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001322 spin_unlock_irqrestore(&data_lock, flags);
1323
Archit Taneja02b5ff12012-11-07 14:47:22 +05301324 dispc_runtime_put();
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001325
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001326 mutex_unlock(&apply_lock);
1327
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001328 return 0;
Archit Taneja02b5ff12012-11-07 14:47:22 +05301329
1330err1:
1331 dispc_runtime_put();
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001332err:
1333 mutex_unlock(&apply_lock);
1334 return r;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001335}
1336
1337int dss_ovl_unset_manager(struct omap_overlay *ovl)
1338{
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001339 struct ovl_priv_data *op = get_ovl_priv(ovl);
1340 unsigned long flags;
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001341 int r;
1342
1343 mutex_lock(&apply_lock);
1344
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001345 if (!ovl->manager) {
1346 DSSERR("failed to detach overlay: manager not set\n");
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001347 r = -EINVAL;
1348 goto err;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001349 }
1350
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001351 spin_lock_irqsave(&data_lock, flags);
1352
1353 if (op->enabled) {
1354 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001355 DSSERR("overlay has to be disabled to unset the manager\n");
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001356 r = -EINVAL;
1357 goto err;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001358 }
1359
Tomi Valkeinenb2f59762012-09-06 16:10:28 +03001360 spin_unlock_irqrestore(&data_lock, flags);
1361
1362 /* wait for pending extra_info updates to ensure the ovl is disabled */
1363 wait_pending_extra_info_updates();
1364
Archit Taneja02b5ff12012-11-07 14:47:22 +05301365 /*
1366 * For a manual update display, there is no guarantee that the overlay
1367 * is really disabled in HW, we may need an extra update from this
1368 * manager before the configurations can go in. Return an error if the
1369 * overlay needed an update from the manager.
1370 *
1371 * TODO: Instead of returning an error, try to do a dummy manager update
1372 * here to disable the overlay in hardware. Use the *GATED fields in
1373 * the DISPC_CONFIG registers to do a dummy update.
1374 */
Tomi Valkeinenb2f59762012-09-06 16:10:28 +03001375 spin_lock_irqsave(&data_lock, flags);
1376
Archit Taneja02b5ff12012-11-07 14:47:22 +05301377 if (ovl_manual_update(ovl) && op->extra_info_dirty) {
1378 spin_unlock_irqrestore(&data_lock, flags);
1379 DSSERR("need an update to change the manager\n");
1380 r = -EINVAL;
1381 goto err;
1382 }
Tomi Valkeinen5d5a97a2011-11-16 14:17:54 +02001383
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001384 ovl->manager = NULL;
1385 list_del(&ovl->list);
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001386
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001387 spin_unlock_irqrestore(&data_lock, flags);
1388
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001389 mutex_unlock(&apply_lock);
1390
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001391 return 0;
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001392err:
1393 mutex_unlock(&apply_lock);
1394 return r;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001395}
1396
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001397bool dss_ovl_is_enabled(struct omap_overlay *ovl)
1398{
1399 struct ovl_priv_data *op = get_ovl_priv(ovl);
1400 unsigned long flags;
1401 bool e;
1402
1403 spin_lock_irqsave(&data_lock, flags);
1404
1405 e = op->enabled;
1406
1407 spin_unlock_irqrestore(&data_lock, flags);
1408
1409 return e;
1410}
1411
1412int dss_ovl_enable(struct omap_overlay *ovl)
1413{
1414 struct ovl_priv_data *op = get_ovl_priv(ovl);
1415 unsigned long flags;
1416 int r;
1417
1418 mutex_lock(&apply_lock);
1419
Tomi Valkeinene4f7ad72011-11-16 16:01:33 +02001420 if (op->enabled) {
1421 r = 0;
Tomi Valkeinen39518352011-11-17 17:35:28 +02001422 goto err1;
Tomi Valkeinene4f7ad72011-11-16 16:01:33 +02001423 }
1424
Archit Taneja0f0e4e32012-09-03 17:14:09 +05301425 if (ovl->manager == NULL || ovl->manager->output == NULL) {
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001426 r = -EINVAL;
Tomi Valkeinen39518352011-11-17 17:35:28 +02001427 goto err1;
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001428 }
1429
1430 spin_lock_irqsave(&data_lock, flags);
1431
Tomi Valkeinen82153ed2011-11-26 14:26:46 +02001432 op->enabling = true;
1433
Archit Taneja228b2132012-04-27 01:22:28 +05301434 r = dss_check_settings(ovl->manager);
Tomi Valkeinen39518352011-11-17 17:35:28 +02001435 if (r) {
1436 DSSERR("failed to enable overlay %d: check_settings failed\n",
1437 ovl->id);
1438 goto err2;
1439 }
1440
Tomi Valkeinenb3e93cb2012-08-06 16:50:14 +03001441 dss_setup_fifos();
Tomi Valkeinen6dc802e2011-11-16 14:28:12 +02001442
Tomi Valkeinen82153ed2011-11-26 14:26:46 +02001443 op->enabling = false;
1444 dss_apply_ovl_enable(ovl, true);
1445
Tomi Valkeinen75c94962011-11-15 18:25:23 +02001446 dss_write_regs();
Tomi Valkeinen3ab15b22011-11-25 17:32:20 +02001447 dss_set_go_bits();
Tomi Valkeinen75c94962011-11-15 18:25:23 +02001448
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001449 spin_unlock_irqrestore(&data_lock, flags);
1450
1451 mutex_unlock(&apply_lock);
1452
1453 return 0;
Tomi Valkeinen39518352011-11-17 17:35:28 +02001454err2:
Tomi Valkeinen82153ed2011-11-26 14:26:46 +02001455 op->enabling = false;
Tomi Valkeinen39518352011-11-17 17:35:28 +02001456 spin_unlock_irqrestore(&data_lock, flags);
1457err1:
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001458 mutex_unlock(&apply_lock);
1459 return r;
1460}
1461
1462int dss_ovl_disable(struct omap_overlay *ovl)
1463{
1464 struct ovl_priv_data *op = get_ovl_priv(ovl);
1465 unsigned long flags;
1466 int r;
1467
1468 mutex_lock(&apply_lock);
1469
Tomi Valkeinene4f7ad72011-11-16 16:01:33 +02001470 if (!op->enabled) {
1471 r = 0;
1472 goto err;
1473 }
1474
Archit Taneja0f0e4e32012-09-03 17:14:09 +05301475 if (ovl->manager == NULL || ovl->manager->output == NULL) {
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001476 r = -EINVAL;
1477 goto err;
1478 }
1479
1480 spin_lock_irqsave(&data_lock, flags);
1481
Tomi Valkeinen841c09c2011-11-16 15:25:53 +02001482 dss_apply_ovl_enable(ovl, false);
Tomi Valkeinen75c94962011-11-15 18:25:23 +02001483 dss_write_regs();
Tomi Valkeinen3ab15b22011-11-25 17:32:20 +02001484 dss_set_go_bits();
Tomi Valkeinen75c94962011-11-15 18:25:23 +02001485
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001486 spin_unlock_irqrestore(&data_lock, flags);
1487
1488 mutex_unlock(&apply_lock);
1489
1490 return 0;
1491
1492err:
1493 mutex_unlock(&apply_lock);
1494 return r;
1495}
1496
Tomi Valkeinen8dd24912012-10-10 10:26:45 +03001497static int compat_refcnt;
1498static DEFINE_MUTEX(compat_init_lock);
1499
1500int omapdss_compat_init(void)
1501{
Tomi Valkeinen23dfd1a2012-10-23 13:46:12 +03001502 struct platform_device *pdev = dss_get_core_pdev();
Tomi Valkeinen0c49ff72012-10-23 13:44:12 +03001503 int i;
Tomi Valkeinen23dfd1a2012-10-23 13:46:12 +03001504
Tomi Valkeinen8dd24912012-10-10 10:26:45 +03001505 mutex_lock(&compat_init_lock);
1506
1507 if (compat_refcnt++ > 0)
1508 goto out;
1509
1510 apply_init_priv();
1511
Tomi Valkeinen23dfd1a2012-10-23 13:46:12 +03001512 dss_init_overlay_managers(pdev);
1513 dss_init_overlays(pdev);
1514
Tomi Valkeinen0c49ff72012-10-23 13:44:12 +03001515 for (i = 0; i < omap_dss_get_num_overlay_managers(); i++) {
1516 struct omap_overlay_manager *mgr;
1517
1518 mgr = omap_dss_get_overlay_manager(i);
1519
1520 mgr->set_output = &dss_mgr_set_output;
1521 mgr->unset_output = &dss_mgr_unset_output;
1522 mgr->apply = &omap_dss_mgr_apply;
1523 mgr->set_manager_info = &dss_mgr_set_info;
1524 mgr->get_manager_info = &dss_mgr_get_info;
1525 mgr->wait_for_go = &dss_mgr_wait_for_go;
1526 mgr->wait_for_vsync = &dss_mgr_wait_for_vsync;
1527 mgr->get_device = &dss_mgr_get_device;
1528 }
1529
Tomi Valkeinen8dd24912012-10-10 10:26:45 +03001530out:
1531 mutex_unlock(&compat_init_lock);
1532
1533 return 0;
1534}
1535EXPORT_SYMBOL(omapdss_compat_init);
1536
1537void omapdss_compat_uninit(void)
1538{
Tomi Valkeinen23dfd1a2012-10-23 13:46:12 +03001539 struct platform_device *pdev = dss_get_core_pdev();
1540
Tomi Valkeinen8dd24912012-10-10 10:26:45 +03001541 mutex_lock(&compat_init_lock);
1542
1543 if (--compat_refcnt > 0)
1544 goto out;
1545
Tomi Valkeinen23dfd1a2012-10-23 13:46:12 +03001546 dss_uninit_overlay_managers(pdev);
1547 dss_uninit_overlays(pdev);
Tomi Valkeinen8dd24912012-10-10 10:26:45 +03001548out:
1549 mutex_unlock(&compat_init_lock);
1550}
1551EXPORT_SYMBOL(omapdss_compat_uninit);