blob: ec21837216425038e54b5b7cc6e38e1056477e1d [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
Tomi Valkeinen388c4c62011-11-16 13:58:07 +0200611 if (!mp->user_info_dirty)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200612 return;
613
Tomi Valkeinen388c4c62011-11-16 13:58:07 +0200614 mp->user_info_dirty = false;
Tomi Valkeinen0b53f172011-11-16 14:31:58 +0200615 mp->info_dirty = true;
Tomi Valkeinen388c4c62011-11-16 13:58:07 +0200616 mp->info = mp->user_info;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200617}
618
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200619int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
620{
Tomi Valkeinen07e327c2011-11-05 10:59:59 +0200621 int r;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200622 unsigned long flags;
Tomi Valkeinen07e327c2011-11-05 10:59:59 +0200623 struct omap_overlay *ovl;
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200624
625 DSSDBG("omap_dss_mgr_apply(%s)\n", mgr->name);
626
627 r = dispc_runtime_get();
628 if (r)
629 return r;
630
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200631 spin_lock_irqsave(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200632
633 /* Configure overlays */
Tomi Valkeinen07e327c2011-11-05 10:59:59 +0200634 list_for_each_entry(ovl, &mgr->overlays, list)
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200635 omap_dss_mgr_apply_ovl(ovl);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200636
637 /* Configure manager */
638 omap_dss_mgr_apply_mgr(mgr);
639
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200640 dss_write_regs();
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200641
Tomi Valkeinen063fd702011-11-15 12:04:10 +0200642 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen58f255482011-11-04 09:48:54 +0200643
644 dispc_runtime_put();
645
646 return r;
647}
648
Tomi Valkeinen841c09c2011-11-16 15:25:53 +0200649static void dss_apply_ovl_enable(struct omap_overlay *ovl, bool enable)
650{
651 struct ovl_priv_data *op;
652
653 op = get_ovl_priv(ovl);
654
655 if (op->enabled == enable)
656 return;
657
658 op->enabled = enable;
659 op->extra_info_dirty = true;
660}
661
Tomi Valkeinen6dc802e2011-11-16 14:28:12 +0200662static void dss_ovl_setup_fifo(struct omap_overlay *ovl)
663{
664 struct ovl_priv_data *op = get_ovl_priv(ovl);
665 struct omap_dss_device *dssdev;
666 u32 size, burst_size;
667 u32 fifo_low, fifo_high;
668
669 dssdev = ovl->manager->device;
670
671 size = dispc_ovl_get_fifo_size(ovl->id);
672
673 burst_size = dispc_ovl_get_burst_size(ovl->id);
674
675 switch (dssdev->type) {
676 case OMAP_DISPLAY_TYPE_DPI:
677 case OMAP_DISPLAY_TYPE_DBI:
678 case OMAP_DISPLAY_TYPE_SDI:
679 case OMAP_DISPLAY_TYPE_VENC:
680 case OMAP_DISPLAY_TYPE_HDMI:
681 default_get_overlay_fifo_thresholds(ovl->id, size,
682 burst_size, &fifo_low, &fifo_high);
683 break;
684#ifdef CONFIG_OMAP2_DSS_DSI
685 case OMAP_DISPLAY_TYPE_DSI:
686 dsi_get_overlay_fifo_thresholds(ovl->id, size,
687 burst_size, &fifo_low, &fifo_high);
688 break;
689#endif
690 default:
691 BUG();
692 }
693
694 op->fifo_low = fifo_low;
695 op->fifo_high = fifo_high;
696 op->extra_info_dirty = true;
697}
698
699static void dss_mgr_setup_fifos(struct omap_overlay_manager *mgr)
700{
701 struct omap_overlay *ovl;
702 struct ovl_priv_data *op;
703 struct mgr_priv_data *mp;
704
705 mp = get_mgr_priv(mgr);
706
707 if (!mp->enabled)
708 return;
709
710 list_for_each_entry(ovl, &mgr->overlays, list) {
711 op = get_ovl_priv(ovl);
712
713 if (!op->enabled)
714 continue;
715
716 dss_ovl_setup_fifo(ovl);
717 }
718}
719
Tomi Valkeinen7797c6d2011-11-04 10:22:46 +0200720void dss_mgr_enable(struct omap_overlay_manager *mgr)
721{
Tomi Valkeinenbf213522011-11-15 14:43:53 +0200722 struct mgr_priv_data *mp = get_mgr_priv(mgr);
723 unsigned long flags;
724
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200725 mutex_lock(&apply_lock);
726
Tomi Valkeinenbf213522011-11-15 14:43:53 +0200727 spin_lock_irqsave(&data_lock, flags);
728
729 mp->enabled = true;
730
Tomi Valkeinen6dc802e2011-11-16 14:28:12 +0200731 dss_mgr_setup_fifos(mgr);
732
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200733 dss_write_regs();
734
Tomi Valkeinen34861372011-11-18 15:43:29 +0200735 if (!mgr_manual_update(mgr))
736 mp->updating = true;
737
Tomi Valkeinenbf213522011-11-15 14:43:53 +0200738 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200739
Tomi Valkeinen75c94962011-11-15 18:25:23 +0200740 if (!mgr_manual_update(mgr))
741 dispc_mgr_enable(mgr->id, true);
742
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200743 mutex_unlock(&apply_lock);
Tomi Valkeinen7797c6d2011-11-04 10:22:46 +0200744}
745
746void dss_mgr_disable(struct omap_overlay_manager *mgr)
747{
Tomi Valkeinenbf213522011-11-15 14:43:53 +0200748 struct mgr_priv_data *mp = get_mgr_priv(mgr);
749 unsigned long flags;
750
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200751 mutex_lock(&apply_lock);
752
Tomi Valkeinen9a147a62011-11-09 15:30:11 +0200753 if (!mgr_manual_update(mgr))
754 dispc_mgr_enable(mgr->id, false);
Tomi Valkeinenbf213522011-11-15 14:43:53 +0200755
756 spin_lock_irqsave(&data_lock, flags);
757
Tomi Valkeinen34861372011-11-18 15:43:29 +0200758 mp->updating = false;
Tomi Valkeinenbf213522011-11-15 14:43:53 +0200759 mp->enabled = false;
760
761 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200762
763 mutex_unlock(&apply_lock);
Tomi Valkeinen7797c6d2011-11-04 10:22:46 +0200764}
765
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200766int dss_mgr_set_info(struct omap_overlay_manager *mgr,
767 struct omap_overlay_manager_info *info)
768{
Tomi Valkeinen388c4c62011-11-16 13:58:07 +0200769 struct mgr_priv_data *mp = get_mgr_priv(mgr);
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200770 unsigned long flags;
771
772 spin_lock_irqsave(&data_lock, flags);
773
Tomi Valkeinen388c4c62011-11-16 13:58:07 +0200774 mp->user_info = *info;
775 mp->user_info_dirty = true;
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200776
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200777 spin_unlock_irqrestore(&data_lock, flags);
778
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200779 return 0;
780}
781
782void dss_mgr_get_info(struct omap_overlay_manager *mgr,
783 struct omap_overlay_manager_info *info)
784{
Tomi Valkeinen388c4c62011-11-16 13:58:07 +0200785 struct mgr_priv_data *mp = get_mgr_priv(mgr);
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200786 unsigned long flags;
787
788 spin_lock_irqsave(&data_lock, flags);
789
Tomi Valkeinen388c4c62011-11-16 13:58:07 +0200790 *info = mp->user_info;
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200791
792 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200793}
794
795int dss_mgr_set_device(struct omap_overlay_manager *mgr,
796 struct omap_dss_device *dssdev)
797{
798 int r;
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200799
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200800 mutex_lock(&apply_lock);
801
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200802 if (dssdev->manager) {
803 DSSERR("display '%s' already has a manager '%s'\n",
804 dssdev->name, dssdev->manager->name);
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200805 r = -EINVAL;
806 goto err;
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200807 }
808
809 if ((mgr->supported_displays & dssdev->type) == 0) {
810 DSSERR("display '%s' does not support manager '%s'\n",
811 dssdev->name, mgr->name);
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200812 r = -EINVAL;
813 goto err;
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200814 }
815
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200816 dssdev->manager = mgr;
817 mgr->device = dssdev;
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200818
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200819 mutex_unlock(&apply_lock);
820
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200821 return 0;
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200822err:
823 mutex_unlock(&apply_lock);
824 return r;
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200825}
826
827int dss_mgr_unset_device(struct omap_overlay_manager *mgr)
828{
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200829 int r;
830
831 mutex_lock(&apply_lock);
832
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200833 if (!mgr->device) {
834 DSSERR("failed to unset display, display not set.\n");
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200835 r = -EINVAL;
836 goto err;
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200837 }
838
839 /*
840 * Don't allow currently enabled displays to have the overlay manager
841 * pulled out from underneath them
842 */
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200843 if (mgr->device->state != OMAP_DSS_DISPLAY_DISABLED) {
844 r = -EINVAL;
845 goto err;
846 }
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200847
848 mgr->device->manager = NULL;
849 mgr->device = NULL;
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200850
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200851 mutex_unlock(&apply_lock);
852
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200853 return 0;
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200854err:
855 mutex_unlock(&apply_lock);
856 return r;
Tomi Valkeineneb70d732011-11-15 12:15:18 +0200857}
858
859
860
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200861int dss_ovl_set_info(struct omap_overlay *ovl,
862 struct omap_overlay_info *info)
863{
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +0200864 struct ovl_priv_data *op = get_ovl_priv(ovl);
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200865 unsigned long flags;
866
867 spin_lock_irqsave(&data_lock, flags);
868
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +0200869 op->user_info = *info;
870 op->user_info_dirty = true;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200871
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200872 spin_unlock_irqrestore(&data_lock, flags);
873
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200874 return 0;
875}
876
877void dss_ovl_get_info(struct omap_overlay *ovl,
878 struct omap_overlay_info *info)
879{
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +0200880 struct ovl_priv_data *op = get_ovl_priv(ovl);
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200881 unsigned long flags;
882
883 spin_lock_irqsave(&data_lock, flags);
884
Tomi Valkeinenc1a9feb2011-11-16 14:11:56 +0200885 *info = op->user_info;
Tomi Valkeinene0a2aa5b2011-11-15 14:32:57 +0200886
887 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200888}
889
890int dss_ovl_set_manager(struct omap_overlay *ovl,
891 struct omap_overlay_manager *mgr)
892{
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200893 struct ovl_priv_data *op = get_ovl_priv(ovl);
894 unsigned long flags;
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200895 int r;
896
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200897 if (!mgr)
898 return -EINVAL;
899
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200900 mutex_lock(&apply_lock);
901
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200902 if (ovl->manager) {
903 DSSERR("overlay '%s' already has a manager '%s'\n",
904 ovl->name, ovl->manager->name);
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200905 r = -EINVAL;
906 goto err;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200907 }
908
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200909 spin_lock_irqsave(&data_lock, flags);
910
911 if (op->enabled) {
912 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200913 DSSERR("overlay has to be disabled to change the manager\n");
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200914 r = -EINVAL;
915 goto err;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200916 }
917
Tomi Valkeinen5d5a97a2011-11-16 14:17:54 +0200918 op->channel = mgr->id;
919 op->extra_info_dirty = true;
920
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200921 ovl->manager = mgr;
922 list_add_tail(&ovl->list, &mgr->overlays);
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200923
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200924 spin_unlock_irqrestore(&data_lock, flags);
925
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200926 /* XXX: When there is an overlay on a DSI manual update display, and
927 * the overlay is first disabled, then moved to tv, and enabled, we
928 * seem to get SYNC_LOST_DIGIT error.
929 *
930 * Waiting doesn't seem to help, but updating the manual update display
931 * after disabling the overlay seems to fix this. This hints that the
932 * overlay is perhaps somehow tied to the LCD output until the output
933 * is updated.
934 *
935 * Userspace workaround for this is to update the LCD after disabling
936 * the overlay, but before moving the overlay to TV.
937 */
938
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200939 mutex_unlock(&apply_lock);
940
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200941 return 0;
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200942err:
943 mutex_unlock(&apply_lock);
944 return r;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200945}
946
947int dss_ovl_unset_manager(struct omap_overlay *ovl)
948{
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200949 struct ovl_priv_data *op = get_ovl_priv(ovl);
950 unsigned long flags;
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200951 int r;
952
953 mutex_lock(&apply_lock);
954
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200955 if (!ovl->manager) {
956 DSSERR("failed to detach overlay: manager not set\n");
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200957 r = -EINVAL;
958 goto err;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200959 }
960
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200961 spin_lock_irqsave(&data_lock, flags);
962
963 if (op->enabled) {
964 spin_unlock_irqrestore(&data_lock, flags);
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200965 DSSERR("overlay has to be disabled to unset the manager\n");
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200966 r = -EINVAL;
967 goto err;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200968 }
969
Tomi Valkeinen5d5a97a2011-11-16 14:17:54 +0200970 op->channel = -1;
971
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200972 ovl->manager = NULL;
973 list_del(&ovl->list);
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200974
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200975 spin_unlock_irqrestore(&data_lock, flags);
976
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200977 mutex_unlock(&apply_lock);
978
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200979 return 0;
Tomi Valkeinen5558db32011-11-15 14:28:48 +0200980err:
981 mutex_unlock(&apply_lock);
982 return r;
Tomi Valkeinenf77b3072011-11-15 12:11:11 +0200983}
984
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200985bool dss_ovl_is_enabled(struct omap_overlay *ovl)
986{
987 struct ovl_priv_data *op = get_ovl_priv(ovl);
988 unsigned long flags;
989 bool e;
990
991 spin_lock_irqsave(&data_lock, flags);
992
993 e = op->enabled;
994
995 spin_unlock_irqrestore(&data_lock, flags);
996
997 return e;
998}
999
1000int dss_ovl_enable(struct omap_overlay *ovl)
1001{
1002 struct ovl_priv_data *op = get_ovl_priv(ovl);
1003 unsigned long flags;
1004 int r;
1005
1006 mutex_lock(&apply_lock);
1007
1008 if (ovl->manager == NULL || ovl->manager->device == NULL) {
1009 r = -EINVAL;
1010 goto err;
1011 }
1012
1013 spin_lock_irqsave(&data_lock, flags);
1014
Tomi Valkeinen841c09c2011-11-16 15:25:53 +02001015 dss_apply_ovl_enable(ovl, true);
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001016
Tomi Valkeinen6dc802e2011-11-16 14:28:12 +02001017 dss_ovl_setup_fifo(ovl);
1018
Tomi Valkeinen75c94962011-11-15 18:25:23 +02001019 dss_write_regs();
1020
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001021 spin_unlock_irqrestore(&data_lock, flags);
1022
1023 mutex_unlock(&apply_lock);
1024
1025 return 0;
1026err:
1027 mutex_unlock(&apply_lock);
1028 return r;
1029}
1030
1031int dss_ovl_disable(struct omap_overlay *ovl)
1032{
1033 struct ovl_priv_data *op = get_ovl_priv(ovl);
1034 unsigned long flags;
1035 int r;
1036
1037 mutex_lock(&apply_lock);
1038
1039 if (ovl->manager == NULL || ovl->manager->device == NULL) {
1040 r = -EINVAL;
1041 goto err;
1042 }
1043
1044 spin_lock_irqsave(&data_lock, flags);
1045
Tomi Valkeinen841c09c2011-11-16 15:25:53 +02001046 dss_apply_ovl_enable(ovl, false);
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001047
Tomi Valkeinen75c94962011-11-15 18:25:23 +02001048 dss_write_regs();
1049
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001050 spin_unlock_irqrestore(&data_lock, flags);
1051
1052 mutex_unlock(&apply_lock);
1053
1054 return 0;
1055
1056err:
1057 mutex_unlock(&apply_lock);
1058 return r;
1059}
1060