blob: 5952f149c91a312675eb030b44e8b6da99250c91 [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 Valkeinen15502022012-10-10 13:59:07 +0300108
109 void (*framedone_handler)(void *);
110 void *framedone_handler_data;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200111};
112
113static struct {
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200114 struct ovl_priv_data ovl_priv_data_array[MAX_DSS_OVERLAYS];
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200115 struct mgr_priv_data mgr_priv_data_array[MAX_DSS_MANAGERS];
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200116
117 bool irq_enabled;
Tomi Valkeinend09c7aa2011-11-15 12:04:43 +0200118} dss_data;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200119
Tomi Valkeinend09c7aa2011-11-15 12:04:43 +0200120/* protects dss_data */
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200121static spinlock_t data_lock;
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200122/* lock for blocking functions */
123static DEFINE_MUTEX(apply_lock);
Tomi Valkeinenf1577ce2011-11-16 14:37:48 +0200124static DECLARE_COMPLETION(extra_updated_completion);
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200125
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200126static void dss_register_vsync_isr(void);
127
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200128static struct ovl_priv_data *get_ovl_priv(struct omap_overlay *ovl)
129{
Tomi Valkeinend09c7aa2011-11-15 12:04:43 +0200130 return &dss_data.ovl_priv_data_array[ovl->id];
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200131}
132
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200133static struct mgr_priv_data *get_mgr_priv(struct omap_overlay_manager *mgr)
134{
Tomi Valkeinend09c7aa2011-11-15 12:04:43 +0200135 return &dss_data.mgr_priv_data_array[mgr->id];
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200136}
137
Tomi Valkeinen8dd24912012-10-10 10:26:45 +0300138static void apply_init_priv(void)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200139{
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +0200140 const int num_ovls = dss_feat_get_num_ovls();
Archit Tanejaf476ae92012-06-29 14:37:03 +0530141 struct mgr_priv_data *mp;
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +0200142 int i;
143
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200144 spin_lock_init(&data_lock);
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +0200145
146 for (i = 0; i < num_ovls; ++i) {
147 struct ovl_priv_data *op;
148
149 op = &dss_data.ovl_priv_data_array[i];
150
151 op->info.global_alpha = 255;
152
153 switch (i) {
154 case 0:
155 op->info.zorder = 0;
156 break;
157 case 1:
158 op->info.zorder =
159 dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 3 : 0;
160 break;
161 case 2:
162 op->info.zorder =
163 dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 2 : 0;
164 break;
165 case 3:
166 op->info.zorder =
167 dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 1 : 0;
168 break;
169 }
170
171 op->user_info = op->info;
172 }
Archit Tanejaf476ae92012-06-29 14:37:03 +0530173
174 /*
175 * Initialize some of the lcd_config fields for TV manager, this lets
176 * us prevent checking if the manager is LCD or TV at some places
177 */
178 mp = &dss_data.mgr_priv_data_array[OMAP_DSS_CHANNEL_DIGIT];
179
180 mp->lcd_config.video_port_width = 24;
181 mp->lcd_config.clock_info.lck_div = 1;
182 mp->lcd_config.clock_info.pck_div = 1;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200183}
184
Archit Taneja75bac5d2012-05-24 15:08:54 +0530185/*
186 * A LCD manager's stallmode decides whether it is in manual or auto update. TV
187 * manager is always auto update, stallmode field for TV manager is false by
188 * default
189 */
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200190static bool ovl_manual_update(struct omap_overlay *ovl)
191{
Archit Taneja75bac5d2012-05-24 15:08:54 +0530192 struct mgr_priv_data *mp = get_mgr_priv(ovl->manager);
193
194 return mp->lcd_config.stallmode;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200195}
196
197static bool mgr_manual_update(struct omap_overlay_manager *mgr)
198{
Archit Taneja75bac5d2012-05-24 15:08:54 +0530199 struct mgr_priv_data *mp = get_mgr_priv(mgr);
200
201 return mp->lcd_config.stallmode;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200202}
203
Tomi Valkeinen39518352011-11-17 17:35:28 +0200204static int dss_check_settings_low(struct omap_overlay_manager *mgr,
Archit Taneja228b2132012-04-27 01:22:28 +0530205 bool applying)
Tomi Valkeinen39518352011-11-17 17:35:28 +0200206{
207 struct omap_overlay_info *oi;
208 struct omap_overlay_manager_info *mi;
209 struct omap_overlay *ovl;
210 struct omap_overlay_info *ois[MAX_DSS_OVERLAYS];
211 struct ovl_priv_data *op;
212 struct mgr_priv_data *mp;
213
214 mp = get_mgr_priv(mgr);
215
Archit Taneja5dd747e2012-05-08 18:19:15 +0530216 if (!mp->enabled)
217 return 0;
218
Tomi Valkeinen39518352011-11-17 17:35:28 +0200219 if (applying && mp->user_info_dirty)
220 mi = &mp->user_info;
221 else
222 mi = &mp->info;
223
224 /* collect the infos to be tested into the array */
225 list_for_each_entry(ovl, &mgr->overlays, list) {
226 op = get_ovl_priv(ovl);
227
Tomi Valkeinen82153ed2011-11-26 14:26:46 +0200228 if (!op->enabled && !op->enabling)
Tomi Valkeinen39518352011-11-17 17:35:28 +0200229 oi = NULL;
230 else if (applying && op->user_info_dirty)
231 oi = &op->user_info;
232 else
233 oi = &op->info;
234
235 ois[ovl->id] = oi;
236 }
237
Archit Taneja6e543592012-05-23 17:01:35 +0530238 return dss_mgr_check(mgr, mi, &mp->timings, &mp->lcd_config, ois);
Tomi Valkeinen39518352011-11-17 17:35:28 +0200239}
240
241/*
242 * check manager and overlay settings using overlay_info from data->info
243 */
Archit Taneja228b2132012-04-27 01:22:28 +0530244static int dss_check_settings(struct omap_overlay_manager *mgr)
Tomi Valkeinen39518352011-11-17 17:35:28 +0200245{
Archit Taneja228b2132012-04-27 01:22:28 +0530246 return dss_check_settings_low(mgr, false);
Tomi Valkeinen39518352011-11-17 17:35:28 +0200247}
248
249/*
250 * check manager and overlay settings using overlay_info from ovl->info if
251 * dirty and from data->info otherwise
252 */
Archit Taneja228b2132012-04-27 01:22:28 +0530253static int dss_check_settings_apply(struct omap_overlay_manager *mgr)
Tomi Valkeinen39518352011-11-17 17:35:28 +0200254{
Archit Taneja228b2132012-04-27 01:22:28 +0530255 return dss_check_settings_low(mgr, true);
Tomi Valkeinen39518352011-11-17 17:35:28 +0200256}
257
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200258static bool need_isr(void)
259{
260 const int num_mgrs = dss_feat_get_num_mgrs();
261 int i;
262
263 for (i = 0; i < num_mgrs; ++i) {
264 struct omap_overlay_manager *mgr;
265 struct mgr_priv_data *mp;
266 struct omap_overlay *ovl;
267
268 mgr = omap_dss_get_overlay_manager(i);
269 mp = get_mgr_priv(mgr);
270
271 if (!mp->enabled)
272 continue;
273
Tomi Valkeinen34861372011-11-18 15:43:29 +0200274 if (mgr_manual_update(mgr)) {
275 /* to catch FRAMEDONE */
276 if (mp->updating)
277 return true;
278 } else {
279 /* to catch GO bit going down */
280 if (mp->busy)
281 return true;
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200282
283 /* to write new values to registers */
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200284 if (mp->info_dirty)
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200285 return true;
Tomi Valkeinen34861372011-11-18 15:43:29 +0200286
Tomi Valkeinen9f808952011-11-25 17:26:13 +0200287 /* to set GO bit */
288 if (mp->shadow_info_dirty)
289 return true;
290
Archit Taneja45324a22012-04-26 19:31:22 +0530291 /*
292 * NOTE: we don't check extra_info flags for disabled
293 * managers, once the manager is enabled, the extra_info
294 * related manager changes will be taken in by HW.
295 */
296
297 /* to write new values to registers */
298 if (mp->extra_info_dirty)
299 return true;
300
301 /* to set GO bit */
302 if (mp->shadow_extra_info_dirty)
303 return true;
304
Tomi Valkeinen34861372011-11-18 15:43:29 +0200305 list_for_each_entry(ovl, &mgr->overlays, list) {
306 struct ovl_priv_data *op;
307
308 op = get_ovl_priv(ovl);
309
Tomi Valkeinen9f808952011-11-25 17:26:13 +0200310 /*
311 * NOTE: we check extra_info flags even for
312 * disabled overlays, as extra_infos need to be
313 * always written.
314 */
315
316 /* to write new values to registers */
317 if (op->extra_info_dirty)
318 return true;
319
320 /* to set GO bit */
321 if (op->shadow_extra_info_dirty)
322 return true;
323
Tomi Valkeinen34861372011-11-18 15:43:29 +0200324 if (!op->enabled)
325 continue;
326
327 /* to write new values to registers */
Tomi Valkeinen9f808952011-11-25 17:26:13 +0200328 if (op->info_dirty)
329 return true;
330
331 /* to set GO bit */
332 if (op->shadow_info_dirty)
Tomi Valkeinen34861372011-11-18 15:43:29 +0200333 return true;
334 }
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200335 }
336 }
337
338 return false;
339}
340
341static bool need_go(struct omap_overlay_manager *mgr)
342{
343 struct omap_overlay *ovl;
344 struct mgr_priv_data *mp;
345 struct ovl_priv_data *op;
346
347 mp = get_mgr_priv(mgr);
348
Archit Taneja45324a22012-04-26 19:31:22 +0530349 if (mp->shadow_info_dirty || mp->shadow_extra_info_dirty)
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200350 return true;
351
352 list_for_each_entry(ovl, &mgr->overlays, list) {
353 op = get_ovl_priv(ovl);
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200354 if (op->shadow_info_dirty || op->shadow_extra_info_dirty)
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200355 return true;
356 }
357
358 return false;
359}
360
Tomi Valkeinenf1577ce2011-11-16 14:37:48 +0200361/* returns true if an extra_info field is currently being updated */
362static bool extra_info_update_ongoing(void)
363{
Archit Taneja45324a22012-04-26 19:31:22 +0530364 const int num_mgrs = dss_feat_get_num_mgrs();
Tomi Valkeinenf1577ce2011-11-16 14:37:48 +0200365 int i;
Tomi Valkeinenf1577ce2011-11-16 14:37:48 +0200366
Archit Taneja45324a22012-04-26 19:31:22 +0530367 for (i = 0; i < num_mgrs; ++i) {
368 struct omap_overlay_manager *mgr;
369 struct omap_overlay *ovl;
370 struct mgr_priv_data *mp;
Tomi Valkeinenf1577ce2011-11-16 14:37:48 +0200371
Archit Taneja45324a22012-04-26 19:31:22 +0530372 mgr = omap_dss_get_overlay_manager(i);
373 mp = get_mgr_priv(mgr);
Tomi Valkeinenf1577ce2011-11-16 14:37:48 +0200374
375 if (!mp->enabled)
376 continue;
377
Tomi Valkeinen153b6e72011-11-25 17:35:35 +0200378 if (!mp->updating)
Tomi Valkeinenf1577ce2011-11-16 14:37:48 +0200379 continue;
380
Archit Taneja45324a22012-04-26 19:31:22 +0530381 if (mp->extra_info_dirty || mp->shadow_extra_info_dirty)
Tomi Valkeinen153b6e72011-11-25 17:35:35 +0200382 return true;
Archit Taneja45324a22012-04-26 19:31:22 +0530383
384 list_for_each_entry(ovl, &mgr->overlays, list) {
385 struct ovl_priv_data *op = get_ovl_priv(ovl);
386
387 if (op->extra_info_dirty || op->shadow_extra_info_dirty)
388 return true;
389 }
Tomi Valkeinenf1577ce2011-11-16 14:37:48 +0200390 }
391
392 return false;
393}
394
395/* wait until no extra_info updates are pending */
396static void wait_pending_extra_info_updates(void)
397{
398 bool updating;
399 unsigned long flags;
400 unsigned long t;
Tomi Valkeinen46146792012-02-23 12:21:09 +0200401 int r;
Tomi Valkeinenf1577ce2011-11-16 14:37:48 +0200402
403 spin_lock_irqsave(&data_lock, flags);
404
405 updating = extra_info_update_ongoing();
406
407 if (!updating) {
408 spin_unlock_irqrestore(&data_lock, flags);
409 return;
410 }
411
412 init_completion(&extra_updated_completion);
413
414 spin_unlock_irqrestore(&data_lock, flags);
415
416 t = msecs_to_jiffies(500);
Tomi Valkeinen46146792012-02-23 12:21:09 +0200417 r = wait_for_completion_timeout(&extra_updated_completion, t);
418 if (r == 0)
419 DSSWARN("timeout in wait_pending_extra_info_updates\n");
Tomi Valkeinenf1577ce2011-11-16 14:37:48 +0200420}
421
Tomi Valkeinen6abae7a2012-10-23 13:45:07 +0300422static inline struct omap_dss_device *dss_ovl_get_device(struct omap_overlay *ovl)
423{
424 return ovl->manager ?
425 (ovl->manager->output ? ovl->manager->output->device : NULL) :
426 NULL;
427}
428
Tomi Valkeinen0c49ff72012-10-23 13:44:12 +0300429static inline struct omap_dss_device *dss_mgr_get_device(struct omap_overlay_manager *mgr)
430{
431 return mgr->output ? mgr->output->device : NULL;
432}
433
434static int dss_mgr_wait_for_vsync(struct omap_overlay_manager *mgr)
435{
436 unsigned long timeout = msecs_to_jiffies(500);
437 struct omap_dss_device *dssdev = mgr->get_device(mgr);
438 u32 irq;
439 int r;
440
441 r = dispc_runtime_get();
442 if (r)
443 return r;
444
445 if (dssdev->type == OMAP_DISPLAY_TYPE_VENC)
446 irq = DISPC_IRQ_EVSYNC_ODD;
447 else if (dssdev->type == OMAP_DISPLAY_TYPE_HDMI)
448 irq = DISPC_IRQ_EVSYNC_EVEN;
449 else
450 irq = dispc_mgr_get_vsync_irq(mgr->id);
451
452 r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
453
454 dispc_runtime_put();
455
456 return r;
457}
458
459static int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200460{
461 unsigned long timeout = msecs_to_jiffies(500);
Archit Tanejafc22a842012-06-26 15:36:55 +0530462 struct mgr_priv_data *mp = get_mgr_priv(mgr);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200463 u32 irq;
Archit Tanejafc22a842012-06-26 15:36:55 +0530464 unsigned long flags;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200465 int r;
466 int i;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200467
Archit Tanejafc22a842012-06-26 15:36:55 +0530468 spin_lock_irqsave(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200469
Archit Tanejafc22a842012-06-26 15:36:55 +0530470 if (mgr_manual_update(mgr)) {
471 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200472 return 0;
Archit Tanejafc22a842012-06-26 15:36:55 +0530473 }
474
475 if (!mp->enabled) {
476 spin_unlock_irqrestore(&data_lock, flags);
477 return 0;
478 }
479
480 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200481
Lajos Molnar21e56f72012-02-22 12:23:16 +0530482 r = dispc_runtime_get();
483 if (r)
484 return r;
485
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200486 irq = dispc_mgr_get_vsync_irq(mgr->id);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200487
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200488 i = 0;
489 while (1) {
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200490 bool shadow_dirty, dirty;
491
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200492 spin_lock_irqsave(&data_lock, flags);
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200493 dirty = mp->info_dirty;
494 shadow_dirty = mp->shadow_info_dirty;
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200495 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200496
497 if (!dirty && !shadow_dirty) {
498 r = 0;
499 break;
500 }
501
502 /* 4 iterations is the worst case:
503 * 1 - initial iteration, dirty = true (between VFP and VSYNC)
504 * 2 - first VSYNC, dirty = true
505 * 3 - dirty = false, shadow_dirty = true
506 * 4 - shadow_dirty = false */
507 if (i++ == 3) {
508 DSSERR("mgr(%d)->wait_for_go() not finishing\n",
509 mgr->id);
510 r = 0;
511 break;
512 }
513
514 r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
515 if (r == -ERESTARTSYS)
516 break;
517
518 if (r) {
519 DSSERR("mgr(%d)->wait_for_go() timeout\n", mgr->id);
520 break;
521 }
522 }
523
Lajos Molnar21e56f72012-02-22 12:23:16 +0530524 dispc_runtime_put();
525
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200526 return r;
527}
528
Tomi Valkeinen6abae7a2012-10-23 13:45:07 +0300529static int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200530{
531 unsigned long timeout = msecs_to_jiffies(500);
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200532 struct ovl_priv_data *op;
Archit Tanejafc22a842012-06-26 15:36:55 +0530533 struct mgr_priv_data *mp;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200534 u32 irq;
Archit Tanejafc22a842012-06-26 15:36:55 +0530535 unsigned long flags;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200536 int r;
537 int i;
538
539 if (!ovl->manager)
540 return 0;
541
Archit Tanejafc22a842012-06-26 15:36:55 +0530542 mp = get_mgr_priv(ovl->manager);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200543
Archit Tanejafc22a842012-06-26 15:36:55 +0530544 spin_lock_irqsave(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200545
Archit Tanejafc22a842012-06-26 15:36:55 +0530546 if (ovl_manual_update(ovl)) {
547 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200548 return 0;
Archit Tanejafc22a842012-06-26 15:36:55 +0530549 }
550
551 if (!mp->enabled) {
552 spin_unlock_irqrestore(&data_lock, flags);
553 return 0;
554 }
555
556 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200557
Lajos Molnar21e56f72012-02-22 12:23:16 +0530558 r = dispc_runtime_get();
559 if (r)
560 return r;
561
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200562 irq = dispc_mgr_get_vsync_irq(ovl->manager->id);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200563
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200564 op = get_ovl_priv(ovl);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200565 i = 0;
566 while (1) {
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200567 bool shadow_dirty, dirty;
568
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200569 spin_lock_irqsave(&data_lock, flags);
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200570 dirty = op->info_dirty;
571 shadow_dirty = op->shadow_info_dirty;
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200572 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200573
574 if (!dirty && !shadow_dirty) {
575 r = 0;
576 break;
577 }
578
579 /* 4 iterations is the worst case:
580 * 1 - initial iteration, dirty = true (between VFP and VSYNC)
581 * 2 - first VSYNC, dirty = true
582 * 3 - dirty = false, shadow_dirty = true
583 * 4 - shadow_dirty = false */
584 if (i++ == 3) {
585 DSSERR("ovl(%d)->wait_for_go() not finishing\n",
586 ovl->id);
587 r = 0;
588 break;
589 }
590
591 r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
592 if (r == -ERESTARTSYS)
593 break;
594
595 if (r) {
596 DSSERR("ovl(%d)->wait_for_go() timeout\n", ovl->id);
597 break;
598 }
599 }
600
Lajos Molnar21e56f72012-02-22 12:23:16 +0530601 dispc_runtime_put();
602
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200603 return r;
604}
605
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200606static void dss_ovl_write_regs(struct omap_overlay *ovl)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200607{
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200608 struct ovl_priv_data *op = get_ovl_priv(ovl);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200609 struct omap_overlay_info *oi;
Archit Taneja8050cbe2012-06-06 16:25:52 +0530610 bool replication;
Tomi Valkeinen34861372011-11-18 15:43:29 +0200611 struct mgr_priv_data *mp;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200612 int r;
613
Chandrabhanu Mahapatra702d2672012-09-24 17:12:58 +0530614 DSSDBG("writing ovl %d regs", ovl->id);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200615
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200616 if (!op->enabled || !op->info_dirty)
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200617 return;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200618
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200619 oi = &op->info;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200620
Archit Taneja81ab95b2012-05-08 15:53:20 +0530621 mp = get_mgr_priv(ovl->manager);
622
Archit Taneja6c6f5102012-06-25 14:58:48 +0530623 replication = dss_ovl_use_replication(mp->lcd_config, oi->color_mode);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200624
Archit Taneja8ba85302012-09-26 17:00:37 +0530625 r = dispc_ovl_setup(ovl->id, oi, replication, &mp->timings, false);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200626 if (r) {
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200627 /*
628 * We can't do much here, as this function can be called from
629 * vsync interrupt.
630 */
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200631 DSSERR("dispc_ovl_setup failed for ovl %d\n", ovl->id);
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200632
633 /* This will leave fifo configurations in a nonoptimal state */
634 op->enabled = false;
635 dispc_ovl_enable(ovl->id, false);
636 return;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200637 }
638
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200639 op->info_dirty = false;
Tomi Valkeinen34861372011-11-18 15:43:29 +0200640 if (mp->updating)
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200641 op->shadow_info_dirty = true;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200642}
643
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200644static void dss_ovl_write_regs_extra(struct omap_overlay *ovl)
645{
646 struct ovl_priv_data *op = get_ovl_priv(ovl);
Tomi Valkeinen34861372011-11-18 15:43:29 +0200647 struct mgr_priv_data *mp;
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200648
Chandrabhanu Mahapatra702d2672012-09-24 17:12:58 +0530649 DSSDBG("writing ovl %d regs extra", ovl->id);
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200650
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200651 if (!op->extra_info_dirty)
652 return;
653
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200654 /* note: write also when op->enabled == false, so that the ovl gets
655 * disabled */
656
657 dispc_ovl_enable(ovl->id, op->enabled);
Tomi Valkeinen6dc802e2011-11-16 14:28:12 +0200658 dispc_ovl_set_fifo_threshold(ovl->id, op->fifo_low, op->fifo_high);
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200659
Tomi Valkeinen34861372011-11-18 15:43:29 +0200660 mp = get_mgr_priv(ovl->manager);
661
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200662 op->extra_info_dirty = false;
Tomi Valkeinen34861372011-11-18 15:43:29 +0200663 if (mp->updating)
664 op->shadow_extra_info_dirty = true;
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200665}
666
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200667static void dss_mgr_write_regs(struct omap_overlay_manager *mgr)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200668{
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200669 struct mgr_priv_data *mp = get_mgr_priv(mgr);
670 struct omap_overlay *ovl;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200671
Chandrabhanu Mahapatra702d2672012-09-24 17:12:58 +0530672 DSSDBG("writing mgr %d regs", mgr->id);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200673
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200674 if (!mp->enabled)
675 return;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200676
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200677 WARN_ON(mp->busy);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200678
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200679 /* Commit overlay settings */
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200680 list_for_each_entry(ovl, &mgr->overlays, list) {
681 dss_ovl_write_regs(ovl);
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200682 dss_ovl_write_regs_extra(ovl);
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200683 }
684
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200685 if (mp->info_dirty) {
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200686 dispc_mgr_setup(mgr->id, &mp->info);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200687
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200688 mp->info_dirty = false;
Tomi Valkeinen34861372011-11-18 15:43:29 +0200689 if (mp->updating)
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200690 mp->shadow_info_dirty = true;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200691 }
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200692}
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200693
Archit Taneja45324a22012-04-26 19:31:22 +0530694static void dss_mgr_write_regs_extra(struct omap_overlay_manager *mgr)
695{
696 struct mgr_priv_data *mp = get_mgr_priv(mgr);
697
Chandrabhanu Mahapatra702d2672012-09-24 17:12:58 +0530698 DSSDBG("writing mgr %d regs extra", mgr->id);
Archit Taneja45324a22012-04-26 19:31:22 +0530699
700 if (!mp->extra_info_dirty)
701 return;
702
703 dispc_mgr_set_timings(mgr->id, &mp->timings);
704
Archit Tanejaf476ae92012-06-29 14:37:03 +0530705 /* lcd_config parameters */
Tomi Valkeinenfb2cec12012-09-12 13:30:39 +0300706 if (dss_mgr_is_lcd(mgr->id))
707 dispc_mgr_set_lcd_config(mgr->id, &mp->lcd_config);
Archit Tanejaf476ae92012-06-29 14:37:03 +0530708
Archit Taneja45324a22012-04-26 19:31:22 +0530709 mp->extra_info_dirty = false;
710 if (mp->updating)
711 mp->shadow_extra_info_dirty = true;
712}
713
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200714static void dss_write_regs(void)
715{
716 const int num_mgrs = omap_dss_get_num_overlay_managers();
717 int i;
718
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200719 for (i = 0; i < num_mgrs; ++i) {
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200720 struct omap_overlay_manager *mgr;
721 struct mgr_priv_data *mp;
Tomi Valkeinen39518352011-11-17 17:35:28 +0200722 int r;
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200723
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200724 mgr = omap_dss_get_overlay_manager(i);
725 mp = get_mgr_priv(mgr);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200726
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200727 if (!mp->enabled || mgr_manual_update(mgr) || mp->busy)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200728 continue;
729
Archit Taneja228b2132012-04-27 01:22:28 +0530730 r = dss_check_settings(mgr);
Tomi Valkeinen39518352011-11-17 17:35:28 +0200731 if (r) {
732 DSSERR("cannot write registers for manager %s: "
733 "illegal configuration\n", mgr->name);
734 continue;
735 }
736
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200737 dss_mgr_write_regs(mgr);
Archit Taneja45324a22012-04-26 19:31:22 +0530738 dss_mgr_write_regs_extra(mgr);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200739 }
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200740}
741
Tomi Valkeinen3ab15b22011-11-25 17:32:20 +0200742static void dss_set_go_bits(void)
743{
744 const int num_mgrs = omap_dss_get_num_overlay_managers();
745 int i;
746
747 for (i = 0; i < num_mgrs; ++i) {
748 struct omap_overlay_manager *mgr;
749 struct mgr_priv_data *mp;
750
751 mgr = omap_dss_get_overlay_manager(i);
752 mp = get_mgr_priv(mgr);
753
754 if (!mp->enabled || mgr_manual_update(mgr) || mp->busy)
755 continue;
756
757 if (!need_go(mgr))
758 continue;
759
760 mp->busy = true;
761
762 if (!dss_data.irq_enabled && need_isr())
763 dss_register_vsync_isr();
764
765 dispc_mgr_go(mgr->id);
766 }
767
768}
769
Tomi Valkeinendf01d532012-03-07 10:28:48 +0200770static void mgr_clear_shadow_dirty(struct omap_overlay_manager *mgr)
771{
772 struct omap_overlay *ovl;
773 struct mgr_priv_data *mp;
774 struct ovl_priv_data *op;
775
776 mp = get_mgr_priv(mgr);
777 mp->shadow_info_dirty = false;
Archit Taneja45324a22012-04-26 19:31:22 +0530778 mp->shadow_extra_info_dirty = false;
Tomi Valkeinendf01d532012-03-07 10:28:48 +0200779
780 list_for_each_entry(ovl, &mgr->overlays, list) {
781 op = get_ovl_priv(ovl);
782 op->shadow_info_dirty = false;
783 op->shadow_extra_info_dirty = false;
784 }
785}
786
Tomi Valkeinen74b65ec2012-10-10 10:56:05 +0300787static void dss_mgr_start_update_compat(struct omap_overlay_manager *mgr)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200788{
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200789 struct mgr_priv_data *mp = get_mgr_priv(mgr);
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200790 unsigned long flags;
Tomi Valkeinen39518352011-11-17 17:35:28 +0200791 int r;
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200792
793 spin_lock_irqsave(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200794
Tomi Valkeinen34861372011-11-18 15:43:29 +0200795 WARN_ON(mp->updating);
796
Archit Taneja228b2132012-04-27 01:22:28 +0530797 r = dss_check_settings(mgr);
Tomi Valkeinen39518352011-11-17 17:35:28 +0200798 if (r) {
799 DSSERR("cannot start manual update: illegal configuration\n");
800 spin_unlock_irqrestore(&data_lock, flags);
801 return;
802 }
803
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200804 dss_mgr_write_regs(mgr);
Archit Taneja45324a22012-04-26 19:31:22 +0530805 dss_mgr_write_regs_extra(mgr);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200806
Tomi Valkeinen34861372011-11-18 15:43:29 +0200807 mp->updating = true;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200808
Tomi Valkeinen34861372011-11-18 15:43:29 +0200809 if (!dss_data.irq_enabled && need_isr())
810 dss_register_vsync_isr();
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200811
Tomi Valkeinen3a979f82012-10-19 14:14:38 +0300812 dispc_mgr_enable_sync(mgr->id);
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200813
814 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200815}
816
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200817static void dss_apply_irq_handler(void *data, u32 mask);
818
819static void dss_register_vsync_isr(void)
820{
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200821 const int num_mgrs = dss_feat_get_num_mgrs();
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200822 u32 mask;
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200823 int r, i;
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200824
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200825 mask = 0;
826 for (i = 0; i < num_mgrs; ++i)
827 mask |= dispc_mgr_get_vsync_irq(i);
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200828
Tomi Valkeinen34861372011-11-18 15:43:29 +0200829 for (i = 0; i < num_mgrs; ++i)
830 mask |= dispc_mgr_get_framedone_irq(i);
831
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200832 r = omap_dispc_register_isr(dss_apply_irq_handler, NULL, mask);
833 WARN_ON(r);
834
Tomi Valkeinend09c7aa2011-11-15 12:04:43 +0200835 dss_data.irq_enabled = true;
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200836}
837
838static void dss_unregister_vsync_isr(void)
839{
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200840 const int num_mgrs = dss_feat_get_num_mgrs();
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200841 u32 mask;
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200842 int r, i;
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200843
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200844 mask = 0;
845 for (i = 0; i < num_mgrs; ++i)
846 mask |= dispc_mgr_get_vsync_irq(i);
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200847
Tomi Valkeinen34861372011-11-18 15:43:29 +0200848 for (i = 0; i < num_mgrs; ++i)
849 mask |= dispc_mgr_get_framedone_irq(i);
850
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200851 r = omap_dispc_unregister_isr(dss_apply_irq_handler, NULL, mask);
852 WARN_ON(r);
853
Tomi Valkeinend09c7aa2011-11-15 12:04:43 +0200854 dss_data.irq_enabled = false;
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200855}
856
Tomi Valkeinen76098932011-11-16 12:03:22 +0200857static void dss_apply_irq_handler(void *data, u32 mask)
858{
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200859 const int num_mgrs = dss_feat_get_num_mgrs();
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200860 int i;
Tomi Valkeinenf1577ce2011-11-16 14:37:48 +0200861 bool extra_updating;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200862
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200863 spin_lock(&data_lock);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200864
Tomi Valkeinen76098932011-11-16 12:03:22 +0200865 /* clear busy, updating flags, shadow_dirty flags */
Tomi Valkeinen43a972d2011-11-15 15:04:25 +0200866 for (i = 0; i < num_mgrs; i++) {
Tomi Valkeinen76098932011-11-16 12:03:22 +0200867 struct omap_overlay_manager *mgr;
868 struct mgr_priv_data *mp;
869
Tomi Valkeinen43a972d2011-11-15 15:04:25 +0200870 mgr = omap_dss_get_overlay_manager(i);
871 mp = get_mgr_priv(mgr);
872
Tomi Valkeinen76098932011-11-16 12:03:22 +0200873 if (!mp->enabled)
Tomi Valkeinen43a972d2011-11-15 15:04:25 +0200874 continue;
875
Tomi Valkeinen76098932011-11-16 12:03:22 +0200876 mp->updating = dispc_mgr_is_enabled(i);
Tomi Valkeinen43a972d2011-11-15 15:04:25 +0200877
Tomi Valkeinen76098932011-11-16 12:03:22 +0200878 if (!mgr_manual_update(mgr)) {
Tomi Valkeinen5b214172011-11-25 17:27:45 +0200879 bool was_busy = mp->busy;
Tomi Valkeinen76098932011-11-16 12:03:22 +0200880 mp->busy = dispc_mgr_go_busy(i);
881
Tomi Valkeinen5b214172011-11-25 17:27:45 +0200882 if (was_busy && !mp->busy)
Tomi Valkeinen76098932011-11-16 12:03:22 +0200883 mgr_clear_shadow_dirty(mgr);
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200884 }
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200885 }
886
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200887 dss_write_regs();
Tomi Valkeinen3ab15b22011-11-25 17:32:20 +0200888 dss_set_go_bits();
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200889
Tomi Valkeinenf1577ce2011-11-16 14:37:48 +0200890 extra_updating = extra_info_update_ongoing();
891 if (!extra_updating)
892 complete_all(&extra_updated_completion);
893
Tomi Valkeinen15502022012-10-10 13:59:07 +0300894 /* call framedone handlers for manual update displays */
895 for (i = 0; i < num_mgrs; i++) {
896 struct omap_overlay_manager *mgr;
897 struct mgr_priv_data *mp;
898
899 mgr = omap_dss_get_overlay_manager(i);
900 mp = get_mgr_priv(mgr);
901
902 if (!mgr_manual_update(mgr) || !mp->framedone_handler)
903 continue;
904
905 if (mask & dispc_mgr_get_framedone_irq(i))
906 mp->framedone_handler(mp->framedone_handler_data);
907 }
908
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200909 if (!need_isr())
910 dss_unregister_vsync_isr();
Tomi Valkeinen43a972d2011-11-15 15:04:25 +0200911
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200912 spin_unlock(&data_lock);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200913}
914
Tomi Valkeinen5738b632011-11-15 13:37:33 +0200915static void omap_dss_mgr_apply_ovl(struct omap_overlay *ovl)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200916{
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200917 struct ovl_priv_data *op;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200918
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200919 op = get_ovl_priv(ovl);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200920
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +0200921 if (!op->user_info_dirty)
Tomi Valkeinen5738b632011-11-15 13:37:33 +0200922 return;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200923
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +0200924 op->user_info_dirty = false;
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200925 op->info_dirty = true;
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +0200926 op->info = op->user_info;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200927}
928
929static void omap_dss_mgr_apply_mgr(struct omap_overlay_manager *mgr)
930{
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200931 struct mgr_priv_data *mp;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200932
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200933 mp = get_mgr_priv(mgr);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200934
Tomi Valkeinen388c4c62011-11-16 13:58:07 +0200935 if (!mp->user_info_dirty)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200936 return;
937
Tomi Valkeinen388c4c62011-11-16 13:58:07 +0200938 mp->user_info_dirty = false;
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200939 mp->info_dirty = true;
Tomi Valkeinen388c4c62011-11-16 13:58:07 +0200940 mp->info = mp->user_info;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200941}
942
Tomi Valkeinen0c49ff72012-10-23 13:44:12 +0300943static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200944{
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200945 unsigned long flags;
Tomi Valkeinen07e327c2011-11-05 10:59:59 +0200946 struct omap_overlay *ovl;
Tomi Valkeinen39518352011-11-17 17:35:28 +0200947 int r;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200948
949 DSSDBG("omap_dss_mgr_apply(%s)\n", mgr->name);
950
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200951 spin_lock_irqsave(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200952
Archit Taneja228b2132012-04-27 01:22:28 +0530953 r = dss_check_settings_apply(mgr);
Tomi Valkeinen39518352011-11-17 17:35:28 +0200954 if (r) {
955 spin_unlock_irqrestore(&data_lock, flags);
956 DSSERR("failed to apply settings: illegal configuration.\n");
957 return r;
958 }
959
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200960 /* Configure overlays */
Tomi Valkeinen07e327c2011-11-05 10:59:59 +0200961 list_for_each_entry(ovl, &mgr->overlays, list)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200962 omap_dss_mgr_apply_ovl(ovl);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200963
964 /* Configure manager */
965 omap_dss_mgr_apply_mgr(mgr);
966
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200967 dss_write_regs();
Tomi Valkeinen3ab15b22011-11-25 17:32:20 +0200968 dss_set_go_bits();
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200969
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200970 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200971
Tomi Valkeinene70f98a2011-11-16 16:53:44 +0200972 return 0;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200973}
974
Tomi Valkeinen841c09c2011-11-16 15:25:53 +0200975static void dss_apply_ovl_enable(struct omap_overlay *ovl, bool enable)
976{
977 struct ovl_priv_data *op;
978
979 op = get_ovl_priv(ovl);
980
981 if (op->enabled == enable)
982 return;
983
984 op->enabled = enable;
985 op->extra_info_dirty = true;
986}
987
Tomi Valkeinen04576d42011-11-26 14:39:16 +0200988static void dss_apply_ovl_fifo_thresholds(struct omap_overlay *ovl,
989 u32 fifo_low, u32 fifo_high)
990{
991 struct ovl_priv_data *op = get_ovl_priv(ovl);
992
993 if (op->fifo_low == fifo_low && op->fifo_high == fifo_high)
994 return;
995
996 op->fifo_low = fifo_low;
997 op->fifo_high = fifo_high;
998 op->extra_info_dirty = true;
999}
1000
Tomi Valkeinenb3e93cb2012-08-06 16:50:14 +03001001static void dss_ovl_setup_fifo(struct omap_overlay *ovl)
Tomi Valkeinen6dc802e2011-11-16 14:28:12 +02001002{
1003 struct ovl_priv_data *op = get_ovl_priv(ovl);
Tomi Valkeinen6dc802e2011-11-16 14:28:12 +02001004 u32 fifo_low, fifo_high;
Tomi Valkeinenb3e93cb2012-08-06 16:50:14 +03001005 bool use_fifo_merge = false;
Tomi Valkeinen6dc802e2011-11-16 14:28:12 +02001006
Tomi Valkeinen75ae1182011-11-26 14:36:19 +02001007 if (!op->enabled && !op->enabling)
1008 return;
1009
Tomi Valkeinen83fa2f22012-01-13 13:17:01 +02001010 dispc_ovl_compute_fifo_thresholds(ovl->id, &fifo_low, &fifo_high,
Tomi Valkeinen3568f2a2012-05-15 15:31:01 +03001011 use_fifo_merge, ovl_manual_update(ovl));
Tomi Valkeinen6dc802e2011-11-16 14:28:12 +02001012
Tomi Valkeinen04576d42011-11-26 14:39:16 +02001013 dss_apply_ovl_fifo_thresholds(ovl, fifo_low, fifo_high);
Tomi Valkeinen6dc802e2011-11-16 14:28:12 +02001014}
1015
Tomi Valkeinenb3e93cb2012-08-06 16:50:14 +03001016static void dss_mgr_setup_fifos(struct omap_overlay_manager *mgr)
Tomi Valkeinen6dc802e2011-11-16 14:28:12 +02001017{
1018 struct omap_overlay *ovl;
Tomi Valkeinen6dc802e2011-11-16 14:28:12 +02001019 struct mgr_priv_data *mp;
1020
1021 mp = get_mgr_priv(mgr);
1022
1023 if (!mp->enabled)
1024 return;
1025
Tomi Valkeinen75ae1182011-11-26 14:36:19 +02001026 list_for_each_entry(ovl, &mgr->overlays, list)
Tomi Valkeinenb3e93cb2012-08-06 16:50:14 +03001027 dss_ovl_setup_fifo(ovl);
Tomi Valkeinen75ae1182011-11-26 14:36:19 +02001028}
1029
Tomi Valkeinenb3e93cb2012-08-06 16:50:14 +03001030static void dss_setup_fifos(void)
Tomi Valkeinen75ae1182011-11-26 14:36:19 +02001031{
1032 const int num_mgrs = omap_dss_get_num_overlay_managers();
1033 struct omap_overlay_manager *mgr;
1034 int i;
1035
1036 for (i = 0; i < num_mgrs; ++i) {
1037 mgr = omap_dss_get_overlay_manager(i);
Tomi Valkeinenb3e93cb2012-08-06 16:50:14 +03001038 dss_mgr_setup_fifos(mgr);
Tomi Valkeinen6dc802e2011-11-16 14:28:12 +02001039 }
1040}
1041
Tomi Valkeinen74b65ec2012-10-10 10:56:05 +03001042static int dss_mgr_enable_compat(struct omap_overlay_manager *mgr)
Tomi Valkeinen7797c6d2011-11-04 10:22:46 +02001043{
Tomi Valkeinenbf213522011-11-15 14:43:53 +02001044 struct mgr_priv_data *mp = get_mgr_priv(mgr);
1045 unsigned long flags;
Tomi Valkeinen39518352011-11-17 17:35:28 +02001046 int r;
Tomi Valkeinenbf213522011-11-15 14:43:53 +02001047
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001048 mutex_lock(&apply_lock);
1049
Tomi Valkeinene4f7ad72011-11-16 16:01:33 +02001050 if (mp->enabled)
1051 goto out;
1052
Tomi Valkeinenbf213522011-11-15 14:43:53 +02001053 spin_lock_irqsave(&data_lock, flags);
1054
1055 mp->enabled = true;
Tomi Valkeinena6b24f82011-11-26 14:29:39 +02001056
Archit Taneja228b2132012-04-27 01:22:28 +05301057 r = dss_check_settings(mgr);
Tomi Valkeinen39518352011-11-17 17:35:28 +02001058 if (r) {
1059 DSSERR("failed to enable manager %d: check_settings failed\n",
1060 mgr->id);
Tomi Valkeinen2a4ee7e2011-11-21 13:34:48 +02001061 goto err;
Tomi Valkeinen39518352011-11-17 17:35:28 +02001062 }
1063
Tomi Valkeinenb3e93cb2012-08-06 16:50:14 +03001064 dss_setup_fifos();
Tomi Valkeinen6dc802e2011-11-16 14:28:12 +02001065
Tomi Valkeinen75c94962011-11-15 18:25:23 +02001066 dss_write_regs();
Tomi Valkeinen3ab15b22011-11-25 17:32:20 +02001067 dss_set_go_bits();
Tomi Valkeinen75c94962011-11-15 18:25:23 +02001068
Tomi Valkeinen34861372011-11-18 15:43:29 +02001069 if (!mgr_manual_update(mgr))
1070 mp->updating = true;
1071
Tomi Valkeinend7b6b6b2012-08-10 14:17:47 +03001072 if (!dss_data.irq_enabled && need_isr())
1073 dss_register_vsync_isr();
1074
Tomi Valkeinenbf213522011-11-15 14:43:53 +02001075 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001076
Tomi Valkeinen75c94962011-11-15 18:25:23 +02001077 if (!mgr_manual_update(mgr))
Tomi Valkeinen3a979f82012-10-19 14:14:38 +03001078 dispc_mgr_enable_sync(mgr->id);
Tomi Valkeinen75c94962011-11-15 18:25:23 +02001079
Tomi Valkeinene4f7ad72011-11-16 16:01:33 +02001080out:
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001081 mutex_unlock(&apply_lock);
Tomi Valkeinen2a4ee7e2011-11-21 13:34:48 +02001082
1083 return 0;
1084
1085err:
Tomi Valkeinena6b24f82011-11-26 14:29:39 +02001086 mp->enabled = false;
Tomi Valkeinen2a4ee7e2011-11-21 13:34:48 +02001087 spin_unlock_irqrestore(&data_lock, flags);
1088 mutex_unlock(&apply_lock);
1089 return r;
Tomi Valkeinen7797c6d2011-11-04 10:22:46 +02001090}
1091
Tomi Valkeinen74b65ec2012-10-10 10:56:05 +03001092static void dss_mgr_disable_compat(struct omap_overlay_manager *mgr)
Tomi Valkeinen7797c6d2011-11-04 10:22:46 +02001093{
Tomi Valkeinenbf213522011-11-15 14:43:53 +02001094 struct mgr_priv_data *mp = get_mgr_priv(mgr);
1095 unsigned long flags;
1096
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001097 mutex_lock(&apply_lock);
1098
Tomi Valkeinene4f7ad72011-11-16 16:01:33 +02001099 if (!mp->enabled)
1100 goto out;
1101
Tomi Valkeinen9a147a62011-11-09 15:30:11 +02001102 if (!mgr_manual_update(mgr))
Tomi Valkeinen3a979f82012-10-19 14:14:38 +03001103 dispc_mgr_disable_sync(mgr->id);
Tomi Valkeinenbf213522011-11-15 14:43:53 +02001104
1105 spin_lock_irqsave(&data_lock, flags);
1106
Tomi Valkeinen34861372011-11-18 15:43:29 +02001107 mp->updating = false;
Tomi Valkeinenbf213522011-11-15 14:43:53 +02001108 mp->enabled = false;
1109
1110 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001111
Tomi Valkeinene4f7ad72011-11-16 16:01:33 +02001112out:
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001113 mutex_unlock(&apply_lock);
Tomi Valkeinen7797c6d2011-11-04 10:22:46 +02001114}
1115
Tomi Valkeinen0c49ff72012-10-23 13:44:12 +03001116static int dss_mgr_set_info(struct omap_overlay_manager *mgr,
Tomi Valkeineneb70d732011-11-15 12:15:18 +02001117 struct omap_overlay_manager_info *info)
1118{
Tomi Valkeinen388c4c62011-11-16 13:58:07 +02001119 struct mgr_priv_data *mp = get_mgr_priv(mgr);
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +02001120 unsigned long flags;
Tomi Valkeinenf17d04f2011-11-17 14:31:09 +02001121 int r;
1122
1123 r = dss_mgr_simple_check(mgr, info);
1124 if (r)
1125 return r;
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +02001126
1127 spin_lock_irqsave(&data_lock, flags);
1128
Tomi Valkeinen388c4c62011-11-16 13:58:07 +02001129 mp->user_info = *info;
1130 mp->user_info_dirty = true;
Tomi Valkeineneb70d732011-11-15 12:15:18 +02001131
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +02001132 spin_unlock_irqrestore(&data_lock, flags);
1133
Tomi Valkeineneb70d732011-11-15 12:15:18 +02001134 return 0;
1135}
1136
Tomi Valkeinen0c49ff72012-10-23 13:44:12 +03001137static void dss_mgr_get_info(struct omap_overlay_manager *mgr,
Tomi Valkeineneb70d732011-11-15 12:15:18 +02001138 struct omap_overlay_manager_info *info)
1139{
Tomi Valkeinen388c4c62011-11-16 13:58:07 +02001140 struct mgr_priv_data *mp = get_mgr_priv(mgr);
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +02001141 unsigned long flags;
1142
1143 spin_lock_irqsave(&data_lock, flags);
1144
Tomi Valkeinen388c4c62011-11-16 13:58:07 +02001145 *info = mp->user_info;
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +02001146
1147 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeineneb70d732011-11-15 12:15:18 +02001148}
1149
Tomi Valkeinen0c49ff72012-10-23 13:44:12 +03001150static int dss_mgr_set_output(struct omap_overlay_manager *mgr,
Archit Taneja97f01b32012-09-26 16:42:39 +05301151 struct omap_dss_output *output)
1152{
1153 int r;
1154
1155 mutex_lock(&apply_lock);
1156
1157 if (mgr->output) {
1158 DSSERR("manager %s is already connected to an output\n",
1159 mgr->name);
1160 r = -EINVAL;
1161 goto err;
1162 }
1163
1164 if ((mgr->supported_outputs & output->id) == 0) {
1165 DSSERR("output does not support manager %s\n",
1166 mgr->name);
1167 r = -EINVAL;
1168 goto err;
1169 }
1170
1171 output->manager = mgr;
1172 mgr->output = output;
1173
1174 mutex_unlock(&apply_lock);
1175
1176 return 0;
1177err:
1178 mutex_unlock(&apply_lock);
1179 return r;
1180}
1181
Tomi Valkeinen0c49ff72012-10-23 13:44:12 +03001182static int dss_mgr_unset_output(struct omap_overlay_manager *mgr)
Archit Taneja97f01b32012-09-26 16:42:39 +05301183{
1184 int r;
1185 struct mgr_priv_data *mp = get_mgr_priv(mgr);
1186 unsigned long flags;
1187
1188 mutex_lock(&apply_lock);
1189
1190 if (!mgr->output) {
1191 DSSERR("failed to unset output, output not set\n");
1192 r = -EINVAL;
1193 goto err;
1194 }
1195
1196 spin_lock_irqsave(&data_lock, flags);
1197
1198 if (mp->enabled) {
1199 DSSERR("output can't be unset when manager is enabled\n");
1200 r = -EINVAL;
1201 goto err1;
1202 }
1203
1204 spin_unlock_irqrestore(&data_lock, flags);
1205
1206 mgr->output->manager = NULL;
1207 mgr->output = NULL;
1208
1209 mutex_unlock(&apply_lock);
1210
1211 return 0;
1212err1:
1213 spin_unlock_irqrestore(&data_lock, flags);
1214err:
1215 mutex_unlock(&apply_lock);
1216
1217 return r;
1218}
1219
Archit Taneja45324a22012-04-26 19:31:22 +05301220static void dss_apply_mgr_timings(struct omap_overlay_manager *mgr,
Archit Taneja27dfddc2012-07-19 13:51:14 +05301221 const struct omap_video_timings *timings)
Archit Taneja45324a22012-04-26 19:31:22 +05301222{
1223 struct mgr_priv_data *mp = get_mgr_priv(mgr);
1224
1225 mp->timings = *timings;
1226 mp->extra_info_dirty = true;
1227}
1228
Tomi Valkeinen74b65ec2012-10-10 10:56:05 +03001229static void dss_mgr_set_timings_compat(struct omap_overlay_manager *mgr,
Archit Taneja27dfddc2012-07-19 13:51:14 +05301230 const struct omap_video_timings *timings)
Archit Taneja45324a22012-04-26 19:31:22 +05301231{
1232 unsigned long flags;
Tomi Valkeinenfed62e52012-08-09 18:13:13 +03001233 struct mgr_priv_data *mp = get_mgr_priv(mgr);
Archit Taneja45324a22012-04-26 19:31:22 +05301234
1235 spin_lock_irqsave(&data_lock, flags);
1236
Tomi Valkeinenfed62e52012-08-09 18:13:13 +03001237 if (mp->updating) {
1238 DSSERR("cannot set timings for %s: manager needs to be disabled\n",
1239 mgr->name);
1240 goto out;
1241 }
1242
Archit Taneja45324a22012-04-26 19:31:22 +05301243 dss_apply_mgr_timings(mgr, timings);
Tomi Valkeinenfed62e52012-08-09 18:13:13 +03001244out:
Archit Taneja45324a22012-04-26 19:31:22 +05301245 spin_unlock_irqrestore(&data_lock, flags);
Archit Taneja45324a22012-04-26 19:31:22 +05301246}
Tomi Valkeineneb70d732011-11-15 12:15:18 +02001247
Archit Tanejaf476ae92012-06-29 14:37:03 +05301248static void dss_apply_mgr_lcd_config(struct omap_overlay_manager *mgr,
1249 const struct dss_lcd_mgr_config *config)
1250{
1251 struct mgr_priv_data *mp = get_mgr_priv(mgr);
1252
1253 mp->lcd_config = *config;
1254 mp->extra_info_dirty = true;
1255}
1256
Tomi Valkeinen74b65ec2012-10-10 10:56:05 +03001257static void dss_mgr_set_lcd_config_compat(struct omap_overlay_manager *mgr,
Archit Tanejaf476ae92012-06-29 14:37:03 +05301258 const struct dss_lcd_mgr_config *config)
1259{
1260 unsigned long flags;
1261 struct mgr_priv_data *mp = get_mgr_priv(mgr);
1262
Tomi Valkeinenaba96572012-08-09 18:07:45 +03001263 spin_lock_irqsave(&data_lock, flags);
Archit Tanejaf476ae92012-06-29 14:37:03 +05301264
1265 if (mp->enabled) {
1266 DSSERR("cannot apply lcd config for %s: manager needs to be disabled\n",
1267 mgr->name);
1268 goto out;
1269 }
1270
Archit Tanejaf476ae92012-06-29 14:37:03 +05301271 dss_apply_mgr_lcd_config(mgr, config);
Archit Tanejaf476ae92012-06-29 14:37:03 +05301272out:
Tomi Valkeinenaba96572012-08-09 18:07:45 +03001273 spin_unlock_irqrestore(&data_lock, flags);
Archit Tanejaf476ae92012-06-29 14:37:03 +05301274}
1275
Tomi Valkeinen6abae7a2012-10-23 13:45:07 +03001276static int dss_ovl_set_info(struct omap_overlay *ovl,
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001277 struct omap_overlay_info *info)
1278{
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +02001279 struct ovl_priv_data *op = get_ovl_priv(ovl);
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +02001280 unsigned long flags;
Tomi Valkeinenfcc764d2011-11-17 14:26:48 +02001281 int r;
1282
1283 r = dss_ovl_simple_check(ovl, info);
1284 if (r)
1285 return r;
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +02001286
1287 spin_lock_irqsave(&data_lock, flags);
1288
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +02001289 op->user_info = *info;
1290 op->user_info_dirty = true;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001291
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +02001292 spin_unlock_irqrestore(&data_lock, flags);
1293
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001294 return 0;
1295}
1296
Tomi Valkeinen6abae7a2012-10-23 13:45:07 +03001297static void dss_ovl_get_info(struct omap_overlay *ovl,
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001298 struct omap_overlay_info *info)
1299{
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +02001300 struct ovl_priv_data *op = get_ovl_priv(ovl);
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +02001301 unsigned long flags;
1302
1303 spin_lock_irqsave(&data_lock, flags);
1304
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +02001305 *info = op->user_info;
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +02001306
1307 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001308}
1309
Tomi Valkeinen6abae7a2012-10-23 13:45:07 +03001310static int dss_ovl_set_manager(struct omap_overlay *ovl,
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001311 struct omap_overlay_manager *mgr)
1312{
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001313 struct ovl_priv_data *op = get_ovl_priv(ovl);
1314 unsigned long flags;
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001315 int r;
1316
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001317 if (!mgr)
1318 return -EINVAL;
1319
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001320 mutex_lock(&apply_lock);
1321
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001322 if (ovl->manager) {
1323 DSSERR("overlay '%s' already has a manager '%s'\n",
1324 ovl->name, ovl->manager->name);
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001325 r = -EINVAL;
1326 goto err;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001327 }
1328
Archit Taneja02b5ff12012-11-07 14:47:22 +05301329 r = dispc_runtime_get();
1330 if (r)
1331 goto err;
1332
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001333 spin_lock_irqsave(&data_lock, flags);
1334
1335 if (op->enabled) {
1336 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001337 DSSERR("overlay has to be disabled to change the manager\n");
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001338 r = -EINVAL;
Archit Taneja02b5ff12012-11-07 14:47:22 +05301339 goto err1;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001340 }
1341
Archit Taneja02b5ff12012-11-07 14:47:22 +05301342 dispc_ovl_set_channel_out(ovl->id, mgr->id);
Tomi Valkeinen5d5a97a2011-11-16 14:17:54 +02001343
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001344 ovl->manager = mgr;
1345 list_add_tail(&ovl->list, &mgr->overlays);
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001346
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001347 spin_unlock_irqrestore(&data_lock, flags);
1348
Archit Taneja02b5ff12012-11-07 14:47:22 +05301349 dispc_runtime_put();
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001350
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001351 mutex_unlock(&apply_lock);
1352
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001353 return 0;
Archit Taneja02b5ff12012-11-07 14:47:22 +05301354
1355err1:
1356 dispc_runtime_put();
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001357err:
1358 mutex_unlock(&apply_lock);
1359 return r;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001360}
1361
Tomi Valkeinen6abae7a2012-10-23 13:45:07 +03001362static int dss_ovl_unset_manager(struct omap_overlay *ovl)
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001363{
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001364 struct ovl_priv_data *op = get_ovl_priv(ovl);
1365 unsigned long flags;
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001366 int r;
1367
1368 mutex_lock(&apply_lock);
1369
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001370 if (!ovl->manager) {
1371 DSSERR("failed to detach overlay: manager not set\n");
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001372 r = -EINVAL;
1373 goto err;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001374 }
1375
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001376 spin_lock_irqsave(&data_lock, flags);
1377
1378 if (op->enabled) {
1379 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001380 DSSERR("overlay has to be disabled to unset the manager\n");
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001381 r = -EINVAL;
1382 goto err;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001383 }
1384
Tomi Valkeinenb2f59762012-09-06 16:10:28 +03001385 spin_unlock_irqrestore(&data_lock, flags);
1386
1387 /* wait for pending extra_info updates to ensure the ovl is disabled */
1388 wait_pending_extra_info_updates();
1389
Archit Taneja02b5ff12012-11-07 14:47:22 +05301390 /*
1391 * For a manual update display, there is no guarantee that the overlay
1392 * is really disabled in HW, we may need an extra update from this
1393 * manager before the configurations can go in. Return an error if the
1394 * overlay needed an update from the manager.
1395 *
1396 * TODO: Instead of returning an error, try to do a dummy manager update
1397 * here to disable the overlay in hardware. Use the *GATED fields in
1398 * the DISPC_CONFIG registers to do a dummy update.
1399 */
Tomi Valkeinenb2f59762012-09-06 16:10:28 +03001400 spin_lock_irqsave(&data_lock, flags);
1401
Archit Taneja02b5ff12012-11-07 14:47:22 +05301402 if (ovl_manual_update(ovl) && op->extra_info_dirty) {
1403 spin_unlock_irqrestore(&data_lock, flags);
1404 DSSERR("need an update to change the manager\n");
1405 r = -EINVAL;
1406 goto err;
1407 }
Tomi Valkeinen5d5a97a2011-11-16 14:17:54 +02001408
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001409 ovl->manager = NULL;
1410 list_del(&ovl->list);
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001411
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001412 spin_unlock_irqrestore(&data_lock, flags);
1413
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001414 mutex_unlock(&apply_lock);
1415
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001416 return 0;
Tomi Valkeinen5558db32011-11-15 14:28:48 +02001417err:
1418 mutex_unlock(&apply_lock);
1419 return r;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +02001420}
1421
Tomi Valkeinen6abae7a2012-10-23 13:45:07 +03001422static bool dss_ovl_is_enabled(struct omap_overlay *ovl)
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001423{
1424 struct ovl_priv_data *op = get_ovl_priv(ovl);
1425 unsigned long flags;
1426 bool e;
1427
1428 spin_lock_irqsave(&data_lock, flags);
1429
1430 e = op->enabled;
1431
1432 spin_unlock_irqrestore(&data_lock, flags);
1433
1434 return e;
1435}
1436
Tomi Valkeinen6abae7a2012-10-23 13:45:07 +03001437static int dss_ovl_enable(struct omap_overlay *ovl)
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001438{
1439 struct ovl_priv_data *op = get_ovl_priv(ovl);
1440 unsigned long flags;
1441 int r;
1442
1443 mutex_lock(&apply_lock);
1444
Tomi Valkeinene4f7ad72011-11-16 16:01:33 +02001445 if (op->enabled) {
1446 r = 0;
Tomi Valkeinen39518352011-11-17 17:35:28 +02001447 goto err1;
Tomi Valkeinene4f7ad72011-11-16 16:01:33 +02001448 }
1449
Archit Taneja0f0e4e32012-09-03 17:14:09 +05301450 if (ovl->manager == NULL || ovl->manager->output == NULL) {
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001451 r = -EINVAL;
Tomi Valkeinen39518352011-11-17 17:35:28 +02001452 goto err1;
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001453 }
1454
1455 spin_lock_irqsave(&data_lock, flags);
1456
Tomi Valkeinen82153ed2011-11-26 14:26:46 +02001457 op->enabling = true;
1458
Archit Taneja228b2132012-04-27 01:22:28 +05301459 r = dss_check_settings(ovl->manager);
Tomi Valkeinen39518352011-11-17 17:35:28 +02001460 if (r) {
1461 DSSERR("failed to enable overlay %d: check_settings failed\n",
1462 ovl->id);
1463 goto err2;
1464 }
1465
Tomi Valkeinenb3e93cb2012-08-06 16:50:14 +03001466 dss_setup_fifos();
Tomi Valkeinen6dc802e2011-11-16 14:28:12 +02001467
Tomi Valkeinen82153ed2011-11-26 14:26:46 +02001468 op->enabling = false;
1469 dss_apply_ovl_enable(ovl, true);
1470
Tomi Valkeinen75c94962011-11-15 18:25:23 +02001471 dss_write_regs();
Tomi Valkeinen3ab15b22011-11-25 17:32:20 +02001472 dss_set_go_bits();
Tomi Valkeinen75c94962011-11-15 18:25:23 +02001473
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001474 spin_unlock_irqrestore(&data_lock, flags);
1475
1476 mutex_unlock(&apply_lock);
1477
1478 return 0;
Tomi Valkeinen39518352011-11-17 17:35:28 +02001479err2:
Tomi Valkeinen82153ed2011-11-26 14:26:46 +02001480 op->enabling = false;
Tomi Valkeinen39518352011-11-17 17:35:28 +02001481 spin_unlock_irqrestore(&data_lock, flags);
1482err1:
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001483 mutex_unlock(&apply_lock);
1484 return r;
1485}
1486
Tomi Valkeinen6abae7a2012-10-23 13:45:07 +03001487static int dss_ovl_disable(struct omap_overlay *ovl)
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001488{
1489 struct ovl_priv_data *op = get_ovl_priv(ovl);
1490 unsigned long flags;
1491 int r;
1492
1493 mutex_lock(&apply_lock);
1494
Tomi Valkeinene4f7ad72011-11-16 16:01:33 +02001495 if (!op->enabled) {
1496 r = 0;
1497 goto err;
1498 }
1499
Archit Taneja0f0e4e32012-09-03 17:14:09 +05301500 if (ovl->manager == NULL || ovl->manager->output == NULL) {
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001501 r = -EINVAL;
1502 goto err;
1503 }
1504
1505 spin_lock_irqsave(&data_lock, flags);
1506
Tomi Valkeinen841c09c2011-11-16 15:25:53 +02001507 dss_apply_ovl_enable(ovl, false);
Tomi Valkeinen75c94962011-11-15 18:25:23 +02001508 dss_write_regs();
Tomi Valkeinen3ab15b22011-11-25 17:32:20 +02001509 dss_set_go_bits();
Tomi Valkeinen75c94962011-11-15 18:25:23 +02001510
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001511 spin_unlock_irqrestore(&data_lock, flags);
1512
1513 mutex_unlock(&apply_lock);
1514
1515 return 0;
1516
1517err:
1518 mutex_unlock(&apply_lock);
1519 return r;
1520}
1521
Tomi Valkeinen15502022012-10-10 13:59:07 +03001522static int dss_mgr_register_framedone_handler_compat(struct omap_overlay_manager *mgr,
1523 void (*handler)(void *), void *data)
1524{
1525 struct mgr_priv_data *mp = get_mgr_priv(mgr);
1526
1527 if (mp->framedone_handler)
1528 return -EBUSY;
1529
1530 mp->framedone_handler = handler;
1531 mp->framedone_handler_data = data;
1532
1533 return 0;
1534}
1535
1536static void dss_mgr_unregister_framedone_handler_compat(struct omap_overlay_manager *mgr,
1537 void (*handler)(void *), void *data)
1538{
1539 struct mgr_priv_data *mp = get_mgr_priv(mgr);
1540
1541 WARN_ON(mp->framedone_handler != handler ||
1542 mp->framedone_handler_data != data);
1543
1544 mp->framedone_handler = NULL;
1545 mp->framedone_handler_data = NULL;
1546}
1547
Tomi Valkeinen74b65ec2012-10-10 10:56:05 +03001548static const struct dss_mgr_ops apply_mgr_ops = {
1549 .start_update = dss_mgr_start_update_compat,
1550 .enable = dss_mgr_enable_compat,
1551 .disable = dss_mgr_disable_compat,
1552 .set_timings = dss_mgr_set_timings_compat,
1553 .set_lcd_config = dss_mgr_set_lcd_config_compat,
Tomi Valkeinen15502022012-10-10 13:59:07 +03001554 .register_framedone_handler = dss_mgr_register_framedone_handler_compat,
1555 .unregister_framedone_handler = dss_mgr_unregister_framedone_handler_compat,
Tomi Valkeinen74b65ec2012-10-10 10:56:05 +03001556};
1557
Tomi Valkeinen8dd24912012-10-10 10:26:45 +03001558static int compat_refcnt;
1559static DEFINE_MUTEX(compat_init_lock);
1560
1561int omapdss_compat_init(void)
1562{
Tomi Valkeinen23dfd1a2012-10-23 13:46:12 +03001563 struct platform_device *pdev = dss_get_core_pdev();
Tomi Valkeinen74b65ec2012-10-10 10:56:05 +03001564 int i, r;
Tomi Valkeinen23dfd1a2012-10-23 13:46:12 +03001565
Tomi Valkeinen8dd24912012-10-10 10:26:45 +03001566 mutex_lock(&compat_init_lock);
1567
1568 if (compat_refcnt++ > 0)
1569 goto out;
1570
1571 apply_init_priv();
1572
Tomi Valkeinen23dfd1a2012-10-23 13:46:12 +03001573 dss_init_overlay_managers(pdev);
1574 dss_init_overlays(pdev);
1575
Tomi Valkeinen0c49ff72012-10-23 13:44:12 +03001576 for (i = 0; i < omap_dss_get_num_overlay_managers(); i++) {
1577 struct omap_overlay_manager *mgr;
1578
1579 mgr = omap_dss_get_overlay_manager(i);
1580
1581 mgr->set_output = &dss_mgr_set_output;
1582 mgr->unset_output = &dss_mgr_unset_output;
1583 mgr->apply = &omap_dss_mgr_apply;
1584 mgr->set_manager_info = &dss_mgr_set_info;
1585 mgr->get_manager_info = &dss_mgr_get_info;
1586 mgr->wait_for_go = &dss_mgr_wait_for_go;
1587 mgr->wait_for_vsync = &dss_mgr_wait_for_vsync;
1588 mgr->get_device = &dss_mgr_get_device;
1589 }
1590
Tomi Valkeinen6abae7a2012-10-23 13:45:07 +03001591 for (i = 0; i < omap_dss_get_num_overlays(); i++) {
1592 struct omap_overlay *ovl = omap_dss_get_overlay(i);
1593
1594 ovl->is_enabled = &dss_ovl_is_enabled;
1595 ovl->enable = &dss_ovl_enable;
1596 ovl->disable = &dss_ovl_disable;
1597 ovl->set_manager = &dss_ovl_set_manager;
1598 ovl->unset_manager = &dss_ovl_unset_manager;
1599 ovl->set_overlay_info = &dss_ovl_set_info;
1600 ovl->get_overlay_info = &dss_ovl_get_info;
1601 ovl->wait_for_go = &dss_mgr_wait_for_go_ovl;
1602 ovl->get_device = &dss_ovl_get_device;
1603 }
1604
Tomi Valkeinen74b65ec2012-10-10 10:56:05 +03001605 r = dss_install_mgr_ops(&apply_mgr_ops);
1606 if (r)
1607 goto err_mgr_ops;
1608
Tomi Valkeinen8dd24912012-10-10 10:26:45 +03001609out:
1610 mutex_unlock(&compat_init_lock);
1611
1612 return 0;
Tomi Valkeinen74b65ec2012-10-10 10:56:05 +03001613
1614err_mgr_ops:
1615 dss_uninit_overlay_managers(pdev);
1616 dss_uninit_overlays(pdev);
1617
1618 compat_refcnt--;
1619
1620 mutex_unlock(&compat_init_lock);
1621
1622 return r;
Tomi Valkeinen8dd24912012-10-10 10:26:45 +03001623}
1624EXPORT_SYMBOL(omapdss_compat_init);
1625
1626void omapdss_compat_uninit(void)
1627{
Tomi Valkeinen23dfd1a2012-10-23 13:46:12 +03001628 struct platform_device *pdev = dss_get_core_pdev();
1629
Tomi Valkeinen8dd24912012-10-10 10:26:45 +03001630 mutex_lock(&compat_init_lock);
1631
1632 if (--compat_refcnt > 0)
1633 goto out;
1634
Tomi Valkeinen74b65ec2012-10-10 10:56:05 +03001635 dss_uninstall_mgr_ops();
1636
Tomi Valkeinen23dfd1a2012-10-23 13:46:12 +03001637 dss_uninit_overlay_managers(pdev);
1638 dss_uninit_overlays(pdev);
Tomi Valkeinen8dd24912012-10-10 10:26:45 +03001639out:
1640 mutex_unlock(&compat_init_lock);
1641}
1642EXPORT_SYMBOL(omapdss_compat_uninit);