blob: 9916eb8e20d51cc070f3c86ca5d819b4128d2ce9 [file] [log] [blame]
Tomi Valkeinen58f255482011-11-04 09:48:54 +02001/*
2 * Copyright (C) 2011 Texas Instruments
3 * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 as published by
7 * the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along with
15 * this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#define DSS_SUBSYS_NAME "APPLY"
19
20#include <linux/kernel.h>
21#include <linux/slab.h>
22#include <linux/spinlock.h>
23#include <linux/jiffies.h>
24
25#include <video/omapdss.h>
26
27#include "dss.h"
28#include "dss_features.h"
29
30/*
31 * We have 4 levels of cache for the dispc settings. First two are in SW and
32 * the latter two in HW.
33 *
Tomi Valkeinen0b53f172011-11-16 14:31:58 +020034 * set_info()
35 * v
Tomi Valkeinen58f255482011-11-04 09:48:54 +020036 * +--------------------+
Tomi Valkeinen0b53f172011-11-16 14:31:58 +020037 * | user_info |
Tomi Valkeinen58f255482011-11-04 09:48:54 +020038 * +--------------------+
39 * v
40 * apply()
41 * v
42 * +--------------------+
Tomi Valkeinend09c7aa2011-11-15 12:04:43 +020043 * | info |
Tomi Valkeinen58f255482011-11-04 09:48:54 +020044 * +--------------------+
45 * v
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +020046 * write_regs()
Tomi Valkeinen58f255482011-11-04 09:48:54 +020047 * v
48 * +--------------------+
49 * | shadow registers |
50 * +--------------------+
51 * v
52 * VFP or lcd/digit_enable
53 * v
54 * +--------------------+
55 * | registers |
56 * +--------------------+
57 */
58
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +020059struct ovl_priv_data {
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +020060
61 bool user_info_dirty;
62 struct omap_overlay_info user_info;
63
Tomi Valkeinen0b53f172011-11-16 14:31:58 +020064 bool info_dirty;
Tomi Valkeinen58f255482011-11-04 09:48:54 +020065 struct omap_overlay_info info;
66
Tomi Valkeinen0b53f172011-11-16 14:31:58 +020067 bool shadow_info_dirty;
68
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +020069 bool extra_info_dirty;
70 bool shadow_extra_info_dirty;
71
72 bool enabled;
Tomi Valkeinen5d5a97a2011-11-16 14:17:54 +020073 enum omap_channel channel;
Tomi Valkeinen6dc802e2011-11-16 14:28:12 +020074 u32 fifo_low, fifo_high;
Tomi Valkeinen58f255482011-11-04 09:48:54 +020075};
76
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +020077struct mgr_priv_data {
Tomi Valkeinen388c4c62011-11-16 13:58:07 +020078
79 bool user_info_dirty;
80 struct omap_overlay_manager_info user_info;
81
Tomi Valkeinen0b53f172011-11-16 14:31:58 +020082 bool info_dirty;
Tomi Valkeinen58f255482011-11-04 09:48:54 +020083 struct omap_overlay_manager_info info;
84
Tomi Valkeinen0b53f172011-11-16 14:31:58 +020085 bool shadow_info_dirty;
86
Tomi Valkeinen43a972d2011-11-15 15:04:25 +020087 /* If true, GO bit is up and shadow registers cannot be written.
88 * Never true for manual update displays */
89 bool busy;
90
Tomi Valkeinen34861372011-11-18 15:43:29 +020091 /* If true, dispc output is enabled */
92 bool updating;
93
Tomi Valkeinenbf213522011-11-15 14:43:53 +020094 /* If true, a display is enabled using this manager */
95 bool enabled;
Tomi Valkeinen58f255482011-11-04 09:48:54 +020096};
97
98static struct {
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +020099 struct ovl_priv_data ovl_priv_data_array[MAX_DSS_OVERLAYS];
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200100 struct mgr_priv_data mgr_priv_data_array[MAX_DSS_MANAGERS];
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200101
102 bool irq_enabled;
Tomi Valkeinend09c7aa2011-11-15 12:04:43 +0200103} dss_data;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200104
Tomi Valkeinend09c7aa2011-11-15 12:04:43 +0200105/* protects dss_data */
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200106static spinlock_t data_lock;
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200107/* lock for blocking functions */
108static DEFINE_MUTEX(apply_lock);
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200109
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200110static void dss_register_vsync_isr(void);
111
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200112static struct ovl_priv_data *get_ovl_priv(struct omap_overlay *ovl)
113{
Tomi Valkeinend09c7aa2011-11-15 12:04:43 +0200114 return &dss_data.ovl_priv_data_array[ovl->id];
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200115}
116
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200117static struct mgr_priv_data *get_mgr_priv(struct omap_overlay_manager *mgr)
118{
Tomi Valkeinend09c7aa2011-11-15 12:04:43 +0200119 return &dss_data.mgr_priv_data_array[mgr->id];
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200120}
121
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200122void dss_apply_init(void)
123{
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +0200124 const int num_ovls = dss_feat_get_num_ovls();
125 int i;
126
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200127 spin_lock_init(&data_lock);
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +0200128
129 for (i = 0; i < num_ovls; ++i) {
130 struct ovl_priv_data *op;
131
132 op = &dss_data.ovl_priv_data_array[i];
133
134 op->info.global_alpha = 255;
135
136 switch (i) {
137 case 0:
138 op->info.zorder = 0;
139 break;
140 case 1:
141 op->info.zorder =
142 dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 3 : 0;
143 break;
144 case 2:
145 op->info.zorder =
146 dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 2 : 0;
147 break;
148 case 3:
149 op->info.zorder =
150 dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 1 : 0;
151 break;
152 }
153
154 op->user_info = op->info;
155 }
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200156}
157
158static bool ovl_manual_update(struct omap_overlay *ovl)
159{
160 return ovl->manager->device->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE;
161}
162
163static bool mgr_manual_update(struct omap_overlay_manager *mgr)
164{
165 return mgr->device->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE;
166}
167
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200168static bool need_isr(void)
169{
170 const int num_mgrs = dss_feat_get_num_mgrs();
171 int i;
172
173 for (i = 0; i < num_mgrs; ++i) {
174 struct omap_overlay_manager *mgr;
175 struct mgr_priv_data *mp;
176 struct omap_overlay *ovl;
177
178 mgr = omap_dss_get_overlay_manager(i);
179 mp = get_mgr_priv(mgr);
180
181 if (!mp->enabled)
182 continue;
183
Tomi Valkeinen34861372011-11-18 15:43:29 +0200184 if (mgr_manual_update(mgr)) {
185 /* to catch FRAMEDONE */
186 if (mp->updating)
187 return true;
188 } else {
189 /* to catch GO bit going down */
190 if (mp->busy)
191 return true;
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200192
193 /* to write new values to registers */
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200194 if (mp->info_dirty)
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200195 return true;
Tomi Valkeinen34861372011-11-18 15:43:29 +0200196
197 list_for_each_entry(ovl, &mgr->overlays, list) {
198 struct ovl_priv_data *op;
199
200 op = get_ovl_priv(ovl);
201
202 if (!op->enabled)
203 continue;
204
205 /* to write new values to registers */
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200206 if (op->info_dirty || op->extra_info_dirty)
Tomi Valkeinen34861372011-11-18 15:43:29 +0200207 return true;
208 }
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200209 }
210 }
211
212 return false;
213}
214
215static bool need_go(struct omap_overlay_manager *mgr)
216{
217 struct omap_overlay *ovl;
218 struct mgr_priv_data *mp;
219 struct ovl_priv_data *op;
220
221 mp = get_mgr_priv(mgr);
222
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200223 if (mp->shadow_info_dirty)
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200224 return true;
225
226 list_for_each_entry(ovl, &mgr->overlays, list) {
227 op = get_ovl_priv(ovl);
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200228 if (op->shadow_info_dirty || op->shadow_extra_info_dirty)
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200229 return true;
230 }
231
232 return false;
233}
234
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200235int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr)
236{
237 unsigned long timeout = msecs_to_jiffies(500);
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200238 struct mgr_priv_data *mp;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200239 u32 irq;
240 int r;
241 int i;
242 struct omap_dss_device *dssdev = mgr->device;
243
244 if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
245 return 0;
246
247 if (mgr_manual_update(mgr))
248 return 0;
249
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200250 irq = dispc_mgr_get_vsync_irq(mgr->id);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200251
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200252 mp = get_mgr_priv(mgr);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200253 i = 0;
254 while (1) {
255 unsigned long flags;
256 bool shadow_dirty, dirty;
257
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200258 spin_lock_irqsave(&data_lock, flags);
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200259 dirty = mp->info_dirty;
260 shadow_dirty = mp->shadow_info_dirty;
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200261 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200262
263 if (!dirty && !shadow_dirty) {
264 r = 0;
265 break;
266 }
267
268 /* 4 iterations is the worst case:
269 * 1 - initial iteration, dirty = true (between VFP and VSYNC)
270 * 2 - first VSYNC, dirty = true
271 * 3 - dirty = false, shadow_dirty = true
272 * 4 - shadow_dirty = false */
273 if (i++ == 3) {
274 DSSERR("mgr(%d)->wait_for_go() not finishing\n",
275 mgr->id);
276 r = 0;
277 break;
278 }
279
280 r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
281 if (r == -ERESTARTSYS)
282 break;
283
284 if (r) {
285 DSSERR("mgr(%d)->wait_for_go() timeout\n", mgr->id);
286 break;
287 }
288 }
289
290 return r;
291}
292
293int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl)
294{
295 unsigned long timeout = msecs_to_jiffies(500);
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200296 struct ovl_priv_data *op;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200297 struct omap_dss_device *dssdev;
298 u32 irq;
299 int r;
300 int i;
301
302 if (!ovl->manager)
303 return 0;
304
305 dssdev = ovl->manager->device;
306
307 if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
308 return 0;
309
310 if (ovl_manual_update(ovl))
311 return 0;
312
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200313 irq = dispc_mgr_get_vsync_irq(ovl->manager->id);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200314
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200315 op = get_ovl_priv(ovl);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200316 i = 0;
317 while (1) {
318 unsigned long flags;
319 bool shadow_dirty, dirty;
320
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200321 spin_lock_irqsave(&data_lock, flags);
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200322 dirty = op->info_dirty;
323 shadow_dirty = op->shadow_info_dirty;
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200324 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200325
326 if (!dirty && !shadow_dirty) {
327 r = 0;
328 break;
329 }
330
331 /* 4 iterations is the worst case:
332 * 1 - initial iteration, dirty = true (between VFP and VSYNC)
333 * 2 - first VSYNC, dirty = true
334 * 3 - dirty = false, shadow_dirty = true
335 * 4 - shadow_dirty = false */
336 if (i++ == 3) {
337 DSSERR("ovl(%d)->wait_for_go() not finishing\n",
338 ovl->id);
339 r = 0;
340 break;
341 }
342
343 r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
344 if (r == -ERESTARTSYS)
345 break;
346
347 if (r) {
348 DSSERR("ovl(%d)->wait_for_go() timeout\n", ovl->id);
349 break;
350 }
351 }
352
353 return r;
354}
355
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200356static void dss_ovl_write_regs(struct omap_overlay *ovl)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200357{
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200358 struct ovl_priv_data *op = get_ovl_priv(ovl);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200359 struct omap_overlay_info *oi;
360 bool ilace, replication;
Tomi Valkeinen34861372011-11-18 15:43:29 +0200361 struct mgr_priv_data *mp;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200362 int r;
363
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200364 DSSDBGF("%d", ovl->id);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200365
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200366 if (!op->enabled || !op->info_dirty)
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200367 return;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200368
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200369 oi = &op->info;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200370
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200371 replication = dss_use_replication(ovl->manager->device, oi->color_mode);
372
373 ilace = ovl->manager->device->type == OMAP_DISPLAY_TYPE_VENC;
374
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200375 r = dispc_ovl_setup(ovl->id, oi, ilace, replication);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200376 if (r) {
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200377 /*
378 * We can't do much here, as this function can be called from
379 * vsync interrupt.
380 */
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200381 DSSERR("dispc_ovl_setup failed for ovl %d\n", ovl->id);
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200382
383 /* This will leave fifo configurations in a nonoptimal state */
384 op->enabled = false;
385 dispc_ovl_enable(ovl->id, false);
386 return;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200387 }
388
Tomi Valkeinen34861372011-11-18 15:43:29 +0200389 mp = get_mgr_priv(ovl->manager);
390
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200391 op->info_dirty = false;
Tomi Valkeinen34861372011-11-18 15:43:29 +0200392 if (mp->updating)
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200393 op->shadow_info_dirty = true;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200394}
395
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200396static void dss_ovl_write_regs_extra(struct omap_overlay *ovl)
397{
398 struct ovl_priv_data *op = get_ovl_priv(ovl);
Tomi Valkeinen34861372011-11-18 15:43:29 +0200399 struct mgr_priv_data *mp;
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200400
401 DSSDBGF("%d", ovl->id);
402
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200403 if (!op->extra_info_dirty)
404 return;
405
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200406 /* note: write also when op->enabled == false, so that the ovl gets
407 * disabled */
408
409 dispc_ovl_enable(ovl->id, op->enabled);
Tomi Valkeinen5d5a97a2011-11-16 14:17:54 +0200410 dispc_ovl_set_channel_out(ovl->id, op->channel);
Tomi Valkeinen6dc802e2011-11-16 14:28:12 +0200411 dispc_ovl_set_fifo_threshold(ovl->id, op->fifo_low, op->fifo_high);
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200412
Tomi Valkeinen34861372011-11-18 15:43:29 +0200413 mp = get_mgr_priv(ovl->manager);
414
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200415 op->extra_info_dirty = false;
Tomi Valkeinen34861372011-11-18 15:43:29 +0200416 if (mp->updating)
417 op->shadow_extra_info_dirty = true;
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200418}
419
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200420static void dss_mgr_write_regs(struct omap_overlay_manager *mgr)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200421{
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200422 struct mgr_priv_data *mp = get_mgr_priv(mgr);
423 struct omap_overlay *ovl;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200424
Tomi Valkeinenf6a5e082011-11-15 11:47:39 +0200425 DSSDBGF("%d", mgr->id);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200426
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200427 if (!mp->enabled)
428 return;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200429
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200430 WARN_ON(mp->busy);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200431
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200432 /* Commit overlay settings */
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200433 list_for_each_entry(ovl, &mgr->overlays, list) {
434 dss_ovl_write_regs(ovl);
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200435 dss_ovl_write_regs_extra(ovl);
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200436 }
437
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200438 if (mp->info_dirty) {
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200439 dispc_mgr_setup(mgr->id, &mp->info);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200440
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200441 mp->info_dirty = false;
Tomi Valkeinen34861372011-11-18 15:43:29 +0200442 if (mp->updating)
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200443 mp->shadow_info_dirty = true;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200444 }
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200445}
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200446
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200447static void dss_write_regs(void)
448{
449 const int num_mgrs = omap_dss_get_num_overlay_managers();
450 int i;
451
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200452 for (i = 0; i < num_mgrs; ++i) {
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200453 struct omap_overlay_manager *mgr;
454 struct mgr_priv_data *mp;
455
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200456 mgr = omap_dss_get_overlay_manager(i);
457 mp = get_mgr_priv(mgr);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200458
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200459 if (!mp->enabled || mgr_manual_update(mgr) || mp->busy)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200460 continue;
461
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200462 dss_mgr_write_regs(mgr);
463
464 if (need_go(mgr)) {
Tomi Valkeinen43a972d2011-11-15 15:04:25 +0200465 mp->busy = true;
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200466
467 if (!dss_data.irq_enabled && need_isr())
468 dss_register_vsync_isr();
469
470 dispc_mgr_go(mgr->id);
Tomi Valkeinen43a972d2011-11-15 15:04:25 +0200471 }
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200472 }
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200473}
474
475void dss_mgr_start_update(struct omap_overlay_manager *mgr)
476{
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200477 struct mgr_priv_data *mp = get_mgr_priv(mgr);
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200478 unsigned long flags;
479
480 spin_lock_irqsave(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200481
Tomi Valkeinen34861372011-11-18 15:43:29 +0200482 WARN_ON(mp->updating);
483
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200484 dss_mgr_write_regs(mgr);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200485
Tomi Valkeinen34861372011-11-18 15:43:29 +0200486 mp->updating = true;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200487
Tomi Valkeinen34861372011-11-18 15:43:29 +0200488 if (!dss_data.irq_enabled && need_isr())
489 dss_register_vsync_isr();
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200490
Tomi Valkeinen7797c6d2011-11-04 10:22:46 +0200491 dispc_mgr_enable(mgr->id, true);
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200492
493 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200494}
495
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200496static void dss_apply_irq_handler(void *data, u32 mask);
497
498static void dss_register_vsync_isr(void)
499{
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200500 const int num_mgrs = dss_feat_get_num_mgrs();
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200501 u32 mask;
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200502 int r, i;
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200503
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200504 mask = 0;
505 for (i = 0; i < num_mgrs; ++i)
506 mask |= dispc_mgr_get_vsync_irq(i);
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200507
Tomi Valkeinen34861372011-11-18 15:43:29 +0200508 for (i = 0; i < num_mgrs; ++i)
509 mask |= dispc_mgr_get_framedone_irq(i);
510
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200511 r = omap_dispc_register_isr(dss_apply_irq_handler, NULL, mask);
512 WARN_ON(r);
513
Tomi Valkeinend09c7aa2011-11-15 12:04:43 +0200514 dss_data.irq_enabled = true;
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200515}
516
517static void dss_unregister_vsync_isr(void)
518{
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200519 const int num_mgrs = dss_feat_get_num_mgrs();
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200520 u32 mask;
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200521 int r, i;
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200522
Tomi Valkeinenbc1a9512011-11-15 11:20:13 +0200523 mask = 0;
524 for (i = 0; i < num_mgrs; ++i)
525 mask |= dispc_mgr_get_vsync_irq(i);
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200526
Tomi Valkeinen34861372011-11-18 15:43:29 +0200527 for (i = 0; i < num_mgrs; ++i)
528 mask |= dispc_mgr_get_framedone_irq(i);
529
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200530 r = omap_dispc_unregister_isr(dss_apply_irq_handler, NULL, mask);
531 WARN_ON(r);
532
Tomi Valkeinend09c7aa2011-11-15 12:04:43 +0200533 dss_data.irq_enabled = false;
Tomi Valkeinendbce0162011-11-15 11:18:12 +0200534}
535
Tomi Valkeinen76098932011-11-16 12:03:22 +0200536static void mgr_clear_shadow_dirty(struct omap_overlay_manager *mgr)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200537{
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200538 struct omap_overlay *ovl;
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200539 struct mgr_priv_data *mp;
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200540 struct ovl_priv_data *op;
Tomi Valkeinen76098932011-11-16 12:03:22 +0200541
542 mp = get_mgr_priv(mgr);
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200543 mp->shadow_info_dirty = false;
Tomi Valkeinen76098932011-11-16 12:03:22 +0200544
545 list_for_each_entry(ovl, &mgr->overlays, list) {
546 op = get_ovl_priv(ovl);
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200547 op->shadow_info_dirty = false;
Tomi Valkeinen76098932011-11-16 12:03:22 +0200548 op->shadow_extra_info_dirty = false;
549 }
550}
551
552static void dss_apply_irq_handler(void *data, u32 mask)
553{
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200554 const int num_mgrs = dss_feat_get_num_mgrs();
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200555 int i;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200556
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200557 spin_lock(&data_lock);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200558
Tomi Valkeinen76098932011-11-16 12:03:22 +0200559 /* clear busy, updating flags, shadow_dirty flags */
Tomi Valkeinen43a972d2011-11-15 15:04:25 +0200560 for (i = 0; i < num_mgrs; i++) {
Tomi Valkeinen76098932011-11-16 12:03:22 +0200561 struct omap_overlay_manager *mgr;
562 struct mgr_priv_data *mp;
563
Tomi Valkeinen43a972d2011-11-15 15:04:25 +0200564 mgr = omap_dss_get_overlay_manager(i);
565 mp = get_mgr_priv(mgr);
566
Tomi Valkeinen76098932011-11-16 12:03:22 +0200567 if (!mp->enabled)
Tomi Valkeinen43a972d2011-11-15 15:04:25 +0200568 continue;
569
Tomi Valkeinen76098932011-11-16 12:03:22 +0200570 mp->updating = dispc_mgr_is_enabled(i);
Tomi Valkeinen43a972d2011-11-15 15:04:25 +0200571
Tomi Valkeinen76098932011-11-16 12:03:22 +0200572 if (!mgr_manual_update(mgr)) {
573 mp->busy = dispc_mgr_go_busy(i);
574
575 if (!mp->busy)
576 mgr_clear_shadow_dirty(mgr);
577 } else {
578 if (!mp->updating)
579 mgr_clear_shadow_dirty(mgr);
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200580 }
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200581 }
582
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200583 dss_write_regs();
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200584
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200585 if (!need_isr())
586 dss_unregister_vsync_isr();
Tomi Valkeinen43a972d2011-11-15 15:04:25 +0200587
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200588 spin_unlock(&data_lock);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200589}
590
Tomi Valkeinen5738b632011-11-15 13:37:33 +0200591static void omap_dss_mgr_apply_ovl(struct omap_overlay *ovl)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200592{
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200593 struct ovl_priv_data *op;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200594
Tomi Valkeinenc10c6f02011-11-15 11:56:57 +0200595 op = get_ovl_priv(ovl);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200596
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +0200597 if (!op->user_info_dirty)
Tomi Valkeinen5738b632011-11-15 13:37:33 +0200598 return;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200599
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +0200600 op->user_info_dirty = false;
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200601 op->info_dirty = true;
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +0200602 op->info = op->user_info;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200603}
604
605static void omap_dss_mgr_apply_mgr(struct omap_overlay_manager *mgr)
606{
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200607 struct mgr_priv_data *mp;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200608
Tomi Valkeinenaf3d64b2011-11-15 12:02:03 +0200609 mp = get_mgr_priv(mgr);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200610
611 if (mgr->device_changed) {
612 mgr->device_changed = false;
Tomi Valkeinen388c4c62011-11-16 13:58:07 +0200613 mp->user_info_dirty = true;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200614 }
615
Tomi Valkeinen388c4c62011-11-16 13:58:07 +0200616 if (!mp->user_info_dirty)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200617 return;
618
Tomi Valkeinen388c4c62011-11-16 13:58:07 +0200619 mp->user_info_dirty = false;
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200620 mp->info_dirty = true;
Tomi Valkeinen388c4c62011-11-16 13:58:07 +0200621 mp->info = mp->user_info;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200622}
623
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200624int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
625{
Tomi Valkeinen07e327c2011-11-05 10:59:59 +0200626 int r;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200627 unsigned long flags;
Tomi Valkeinen07e327c2011-11-05 10:59:59 +0200628 struct omap_overlay *ovl;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200629
630 DSSDBG("omap_dss_mgr_apply(%s)\n", mgr->name);
631
632 r = dispc_runtime_get();
633 if (r)
634 return r;
635
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200636 spin_lock_irqsave(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200637
638 /* Configure overlays */
Tomi Valkeinen07e327c2011-11-05 10:59:59 +0200639 list_for_each_entry(ovl, &mgr->overlays, list)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200640 omap_dss_mgr_apply_ovl(ovl);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200641
642 /* Configure manager */
643 omap_dss_mgr_apply_mgr(mgr);
644
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200645 dss_write_regs();
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200646
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200647 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200648
649 dispc_runtime_put();
650
651 return r;
652}
653
Tomi Valkeinen6dc802e2011-11-16 14:28:12 +0200654static void dss_ovl_setup_fifo(struct omap_overlay *ovl)
655{
656 struct ovl_priv_data *op = get_ovl_priv(ovl);
657 struct omap_dss_device *dssdev;
658 u32 size, burst_size;
659 u32 fifo_low, fifo_high;
660
661 dssdev = ovl->manager->device;
662
663 size = dispc_ovl_get_fifo_size(ovl->id);
664
665 burst_size = dispc_ovl_get_burst_size(ovl->id);
666
667 switch (dssdev->type) {
668 case OMAP_DISPLAY_TYPE_DPI:
669 case OMAP_DISPLAY_TYPE_DBI:
670 case OMAP_DISPLAY_TYPE_SDI:
671 case OMAP_DISPLAY_TYPE_VENC:
672 case OMAP_DISPLAY_TYPE_HDMI:
673 default_get_overlay_fifo_thresholds(ovl->id, size,
674 burst_size, &fifo_low, &fifo_high);
675 break;
676#ifdef CONFIG_OMAP2_DSS_DSI
677 case OMAP_DISPLAY_TYPE_DSI:
678 dsi_get_overlay_fifo_thresholds(ovl->id, size,
679 burst_size, &fifo_low, &fifo_high);
680 break;
681#endif
682 default:
683 BUG();
684 }
685
686 op->fifo_low = fifo_low;
687 op->fifo_high = fifo_high;
688 op->extra_info_dirty = true;
689}
690
691static void dss_mgr_setup_fifos(struct omap_overlay_manager *mgr)
692{
693 struct omap_overlay *ovl;
694 struct ovl_priv_data *op;
695 struct mgr_priv_data *mp;
696
697 mp = get_mgr_priv(mgr);
698
699 if (!mp->enabled)
700 return;
701
702 list_for_each_entry(ovl, &mgr->overlays, list) {
703 op = get_ovl_priv(ovl);
704
705 if (!op->enabled)
706 continue;
707
708 dss_ovl_setup_fifo(ovl);
709 }
710}
711
Tomi Valkeinen7797c6d2011-11-04 10:22:46 +0200712void dss_mgr_enable(struct omap_overlay_manager *mgr)
713{
Tomi Valkeinenbf213522011-11-15 14:43:53 +0200714 struct mgr_priv_data *mp = get_mgr_priv(mgr);
715 unsigned long flags;
716
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200717 mutex_lock(&apply_lock);
718
Tomi Valkeinenbf213522011-11-15 14:43:53 +0200719 spin_lock_irqsave(&data_lock, flags);
720
721 mp->enabled = true;
722
Tomi Valkeinen6dc802e2011-11-16 14:28:12 +0200723 dss_mgr_setup_fifos(mgr);
724
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200725 dss_write_regs();
726
Tomi Valkeinen34861372011-11-18 15:43:29 +0200727 if (!mgr_manual_update(mgr))
728 mp->updating = true;
729
Tomi Valkeinenbf213522011-11-15 14:43:53 +0200730 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200731
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200732 if (!mgr_manual_update(mgr))
733 dispc_mgr_enable(mgr->id, true);
734
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200735 mutex_unlock(&apply_lock);
Tomi Valkeinen7797c6d2011-11-04 10:22:46 +0200736}
737
738void dss_mgr_disable(struct omap_overlay_manager *mgr)
739{
Tomi Valkeinenbf213522011-11-15 14:43:53 +0200740 struct mgr_priv_data *mp = get_mgr_priv(mgr);
741 unsigned long flags;
742
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200743 mutex_lock(&apply_lock);
744
Tomi Valkeinen9a147a62011-11-09 15:30:11 +0200745 if (!mgr_manual_update(mgr))
746 dispc_mgr_enable(mgr->id, false);
Tomi Valkeinenbf213522011-11-15 14:43:53 +0200747
748 spin_lock_irqsave(&data_lock, flags);
749
Tomi Valkeinen34861372011-11-18 15:43:29 +0200750 mp->updating = false;
Tomi Valkeinenbf213522011-11-15 14:43:53 +0200751 mp->enabled = false;
752
753 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200754
755 mutex_unlock(&apply_lock);
Tomi Valkeinen7797c6d2011-11-04 10:22:46 +0200756}
757
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200758int dss_mgr_set_info(struct omap_overlay_manager *mgr,
759 struct omap_overlay_manager_info *info)
760{
Tomi Valkeinen388c4c62011-11-16 13:58:07 +0200761 struct mgr_priv_data *mp = get_mgr_priv(mgr);
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200762 unsigned long flags;
763
764 spin_lock_irqsave(&data_lock, flags);
765
Tomi Valkeinen388c4c62011-11-16 13:58:07 +0200766 mp->user_info = *info;
767 mp->user_info_dirty = true;
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200768
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200769 spin_unlock_irqrestore(&data_lock, flags);
770
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200771 return 0;
772}
773
774void dss_mgr_get_info(struct omap_overlay_manager *mgr,
775 struct omap_overlay_manager_info *info)
776{
Tomi Valkeinen388c4c62011-11-16 13:58:07 +0200777 struct mgr_priv_data *mp = get_mgr_priv(mgr);
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200778 unsigned long flags;
779
780 spin_lock_irqsave(&data_lock, flags);
781
Tomi Valkeinen388c4c62011-11-16 13:58:07 +0200782 *info = mp->user_info;
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200783
784 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200785}
786
787int dss_mgr_set_device(struct omap_overlay_manager *mgr,
788 struct omap_dss_device *dssdev)
789{
790 int r;
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200791
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200792 mutex_lock(&apply_lock);
793
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200794 if (dssdev->manager) {
795 DSSERR("display '%s' already has a manager '%s'\n",
796 dssdev->name, dssdev->manager->name);
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200797 r = -EINVAL;
798 goto err;
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200799 }
800
801 if ((mgr->supported_displays & dssdev->type) == 0) {
802 DSSERR("display '%s' does not support manager '%s'\n",
803 dssdev->name, mgr->name);
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200804 r = -EINVAL;
805 goto err;
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200806 }
807
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200808 dssdev->manager = mgr;
809 mgr->device = dssdev;
810 mgr->device_changed = true;
811
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200812 mutex_unlock(&apply_lock);
813
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200814 return 0;
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200815err:
816 mutex_unlock(&apply_lock);
817 return r;
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200818}
819
820int dss_mgr_unset_device(struct omap_overlay_manager *mgr)
821{
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200822 int r;
823
824 mutex_lock(&apply_lock);
825
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200826 if (!mgr->device) {
827 DSSERR("failed to unset display, display not set.\n");
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200828 r = -EINVAL;
829 goto err;
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200830 }
831
832 /*
833 * Don't allow currently enabled displays to have the overlay manager
834 * pulled out from underneath them
835 */
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200836 if (mgr->device->state != OMAP_DSS_DISPLAY_DISABLED) {
837 r = -EINVAL;
838 goto err;
839 }
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200840
841 mgr->device->manager = NULL;
842 mgr->device = NULL;
843 mgr->device_changed = true;
844
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200845 mutex_unlock(&apply_lock);
846
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200847 return 0;
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200848err:
849 mutex_unlock(&apply_lock);
850 return r;
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200851}
852
853
854
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200855int dss_ovl_set_info(struct omap_overlay *ovl,
856 struct omap_overlay_info *info)
857{
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +0200858 struct ovl_priv_data *op = get_ovl_priv(ovl);
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200859 unsigned long flags;
860
861 spin_lock_irqsave(&data_lock, flags);
862
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +0200863 op->user_info = *info;
864 op->user_info_dirty = true;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200865
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200866 spin_unlock_irqrestore(&data_lock, flags);
867
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200868 return 0;
869}
870
871void dss_ovl_get_info(struct omap_overlay *ovl,
872 struct omap_overlay_info *info)
873{
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +0200874 struct ovl_priv_data *op = get_ovl_priv(ovl);
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200875 unsigned long flags;
876
877 spin_lock_irqsave(&data_lock, flags);
878
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +0200879 *info = op->user_info;
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200880
881 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200882}
883
884int dss_ovl_set_manager(struct omap_overlay *ovl,
885 struct omap_overlay_manager *mgr)
886{
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200887 struct ovl_priv_data *op = get_ovl_priv(ovl);
888 unsigned long flags;
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200889 int r;
890
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200891 if (!mgr)
892 return -EINVAL;
893
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200894 mutex_lock(&apply_lock);
895
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200896 if (ovl->manager) {
897 DSSERR("overlay '%s' already has a manager '%s'\n",
898 ovl->name, ovl->manager->name);
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200899 r = -EINVAL;
900 goto err;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200901 }
902
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200903 spin_lock_irqsave(&data_lock, flags);
904
905 if (op->enabled) {
906 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200907 DSSERR("overlay has to be disabled to change the manager\n");
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200908 r = -EINVAL;
909 goto err;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200910 }
911
Tomi Valkeinen5d5a97a2011-11-16 14:17:54 +0200912 op->channel = mgr->id;
913 op->extra_info_dirty = true;
914
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200915 ovl->manager = mgr;
916 list_add_tail(&ovl->list, &mgr->overlays);
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200917
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200918 spin_unlock_irqrestore(&data_lock, flags);
919
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200920 /* XXX: When there is an overlay on a DSI manual update display, and
921 * the overlay is first disabled, then moved to tv, and enabled, we
922 * seem to get SYNC_LOST_DIGIT error.
923 *
924 * Waiting doesn't seem to help, but updating the manual update display
925 * after disabling the overlay seems to fix this. This hints that the
926 * overlay is perhaps somehow tied to the LCD output until the output
927 * is updated.
928 *
929 * Userspace workaround for this is to update the LCD after disabling
930 * the overlay, but before moving the overlay to TV.
931 */
932
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200933 mutex_unlock(&apply_lock);
934
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200935 return 0;
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200936err:
937 mutex_unlock(&apply_lock);
938 return r;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200939}
940
941int dss_ovl_unset_manager(struct omap_overlay *ovl)
942{
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200943 struct ovl_priv_data *op = get_ovl_priv(ovl);
944 unsigned long flags;
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200945 int r;
946
947 mutex_lock(&apply_lock);
948
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200949 if (!ovl->manager) {
950 DSSERR("failed to detach overlay: manager not set\n");
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200951 r = -EINVAL;
952 goto err;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200953 }
954
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200955 spin_lock_irqsave(&data_lock, flags);
956
957 if (op->enabled) {
958 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200959 DSSERR("overlay has to be disabled to unset the manager\n");
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200960 r = -EINVAL;
961 goto err;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200962 }
963
Tomi Valkeinen5d5a97a2011-11-16 14:17:54 +0200964 op->channel = -1;
965
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200966 ovl->manager = NULL;
967 list_del(&ovl->list);
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200968
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200969 spin_unlock_irqrestore(&data_lock, flags);
970
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200971 mutex_unlock(&apply_lock);
972
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200973 return 0;
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200974err:
975 mutex_unlock(&apply_lock);
976 return r;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200977}
978
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200979bool dss_ovl_is_enabled(struct omap_overlay *ovl)
980{
981 struct ovl_priv_data *op = get_ovl_priv(ovl);
982 unsigned long flags;
983 bool e;
984
985 spin_lock_irqsave(&data_lock, flags);
986
987 e = op->enabled;
988
989 spin_unlock_irqrestore(&data_lock, flags);
990
991 return e;
992}
993
994int dss_ovl_enable(struct omap_overlay *ovl)
995{
996 struct ovl_priv_data *op = get_ovl_priv(ovl);
997 unsigned long flags;
998 int r;
999
1000 mutex_lock(&apply_lock);
1001
1002 if (ovl->manager == NULL || ovl->manager->device == NULL) {
1003 r = -EINVAL;
1004 goto err;
1005 }
1006
1007 spin_lock_irqsave(&data_lock, flags);
1008
1009 op->enabled = true;
1010 op->extra_info_dirty = true;
1011
Tomi Valkeinen6dc802e2011-11-16 14:28:12 +02001012 dss_ovl_setup_fifo(ovl);
1013
Tomi Valkeinen75c94962011-11-15 18:25:23 +02001014 dss_write_regs();
1015
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001016 spin_unlock_irqrestore(&data_lock, flags);
1017
1018 mutex_unlock(&apply_lock);
1019
1020 return 0;
1021err:
1022 mutex_unlock(&apply_lock);
1023 return r;
1024}
1025
1026int dss_ovl_disable(struct omap_overlay *ovl)
1027{
1028 struct ovl_priv_data *op = get_ovl_priv(ovl);
1029 unsigned long flags;
1030 int r;
1031
1032 mutex_lock(&apply_lock);
1033
1034 if (ovl->manager == NULL || ovl->manager->device == NULL) {
1035 r = -EINVAL;
1036 goto err;
1037 }
1038
1039 spin_lock_irqsave(&data_lock, flags);
1040
1041 op->enabled = false;
1042 op->extra_info_dirty = true;
1043
Tomi Valkeinen75c94962011-11-15 18:25:23 +02001044 dss_write_regs();
1045
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001046 spin_unlock_irqrestore(&data_lock, flags);
1047
1048 mutex_unlock(&apply_lock);
1049
1050 return 0;
1051
1052err:
1053 mutex_unlock(&apply_lock);
1054 return r;
1055}
1056