blob: c616f850eaf86895e2b3c00483ad8b419e8815af [file] [log] [blame]
Tomi Valkeineneed07e02009-08-07 13:43:20 +03001/*
2 * linux/drivers/video/omap2/dss/manager.c
3 *
4 * Copyright (C) 2009 Nokia Corporation
5 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
6 *
7 * Some code and ideas taken from drivers/video/omap/ driver
8 * by Imre Deak.
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License version 2 as published by
12 * the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17 * more details.
18 *
19 * You should have received a copy of the GNU General Public License along with
20 * this program. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23#define DSS_SUBSYS_NAME "MANAGER"
24
25#include <linux/kernel.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090026#include <linux/slab.h>
Tomi Valkeineneed07e02009-08-07 13:43:20 +030027#include <linux/module.h>
28#include <linux/platform_device.h>
29#include <linux/spinlock.h>
30#include <linux/jiffies.h>
31
Tomi Valkeinena0b38cc2011-05-11 14:05:07 +030032#include <video/omapdss.h>
Tomi Valkeineneed07e02009-08-07 13:43:20 +030033#include <plat/cpu.h>
34
35#include "dss.h"
Archit Tanejaa0acb552010-09-15 19:20:00 +053036#include "dss_features.h"
Tomi Valkeineneed07e02009-08-07 13:43:20 +030037
38static int num_managers;
39static struct list_head manager_list;
40
41static ssize_t manager_name_show(struct omap_overlay_manager *mgr, char *buf)
42{
43 return snprintf(buf, PAGE_SIZE, "%s\n", mgr->name);
44}
45
46static ssize_t manager_display_show(struct omap_overlay_manager *mgr, char *buf)
47{
48 return snprintf(buf, PAGE_SIZE, "%s\n",
49 mgr->device ? mgr->device->name : "<none>");
50}
51
52static ssize_t manager_display_store(struct omap_overlay_manager *mgr,
53 const char *buf, size_t size)
54{
55 int r = 0;
56 size_t len = size;
57 struct omap_dss_device *dssdev = NULL;
58
59 int match(struct omap_dss_device *dssdev, void *data)
60 {
61 const char *str = data;
62 return sysfs_streq(dssdev->name, str);
63 }
64
65 if (buf[size-1] == '\n')
66 --len;
67
68 if (len > 0)
69 dssdev = omap_dss_find_device((void *)buf, match);
70
71 if (len > 0 && dssdev == NULL)
72 return -EINVAL;
73
74 if (dssdev)
75 DSSDBG("display %s found\n", dssdev->name);
76
77 if (mgr->device) {
78 r = mgr->unset_device(mgr);
79 if (r) {
80 DSSERR("failed to unset display\n");
81 goto put_device;
82 }
83 }
84
85 if (dssdev) {
86 r = mgr->set_device(mgr, dssdev);
87 if (r) {
88 DSSERR("failed to set manager\n");
89 goto put_device;
90 }
91
92 r = mgr->apply(mgr);
93 if (r) {
94 DSSERR("failed to apply dispc config\n");
95 goto put_device;
96 }
97 }
98
99put_device:
100 if (dssdev)
101 omap_dss_put_device(dssdev);
102
103 return r ? r : size;
104}
105
106static ssize_t manager_default_color_show(struct omap_overlay_manager *mgr,
107 char *buf)
108{
Tomi Valkeinene3a26ae2011-08-15 15:55:55 +0300109 return snprintf(buf, PAGE_SIZE, "%#x\n", mgr->info.default_color);
Tomi Valkeineneed07e02009-08-07 13:43:20 +0300110}
111
112static ssize_t manager_default_color_store(struct omap_overlay_manager *mgr,
113 const char *buf, size_t size)
114{
115 struct omap_overlay_manager_info info;
116 u32 color;
117 int r;
118
Tomi Valkeinene3a26ae2011-08-15 15:55:55 +0300119 r = kstrtouint(buf, 0, &color);
120 if (r)
121 return r;
Tomi Valkeineneed07e02009-08-07 13:43:20 +0300122
123 mgr->get_manager_info(mgr, &info);
124
125 info.default_color = color;
126
127 r = mgr->set_manager_info(mgr, &info);
128 if (r)
129 return r;
130
131 r = mgr->apply(mgr);
132 if (r)
133 return r;
134
135 return size;
136}
137
138static const char *trans_key_type_str[] = {
139 "gfx-destination",
140 "video-source",
141};
142
143static ssize_t manager_trans_key_type_show(struct omap_overlay_manager *mgr,
144 char *buf)
145{
146 enum omap_dss_trans_key_type key_type;
147
148 key_type = mgr->info.trans_key_type;
149 BUG_ON(key_type >= ARRAY_SIZE(trans_key_type_str));
150
151 return snprintf(buf, PAGE_SIZE, "%s\n", trans_key_type_str[key_type]);
152}
153
154static ssize_t manager_trans_key_type_store(struct omap_overlay_manager *mgr,
155 const char *buf, size_t size)
156{
157 enum omap_dss_trans_key_type key_type;
158 struct omap_overlay_manager_info info;
159 int r;
160
161 for (key_type = OMAP_DSS_COLOR_KEY_GFX_DST;
162 key_type < ARRAY_SIZE(trans_key_type_str); key_type++) {
163 if (sysfs_streq(buf, trans_key_type_str[key_type]))
164 break;
165 }
166
167 if (key_type == ARRAY_SIZE(trans_key_type_str))
168 return -EINVAL;
169
170 mgr->get_manager_info(mgr, &info);
171
172 info.trans_key_type = key_type;
173
174 r = mgr->set_manager_info(mgr, &info);
175 if (r)
176 return r;
177
178 r = mgr->apply(mgr);
179 if (r)
180 return r;
181
182 return size;
183}
184
185static ssize_t manager_trans_key_value_show(struct omap_overlay_manager *mgr,
186 char *buf)
187{
Tomi Valkeinene3a26ae2011-08-15 15:55:55 +0300188 return snprintf(buf, PAGE_SIZE, "%#x\n", mgr->info.trans_key);
Tomi Valkeineneed07e02009-08-07 13:43:20 +0300189}
190
191static ssize_t manager_trans_key_value_store(struct omap_overlay_manager *mgr,
192 const char *buf, size_t size)
193{
194 struct omap_overlay_manager_info info;
195 u32 key_value;
196 int r;
197
Tomi Valkeinene3a26ae2011-08-15 15:55:55 +0300198 r = kstrtouint(buf, 0, &key_value);
199 if (r)
200 return r;
Tomi Valkeineneed07e02009-08-07 13:43:20 +0300201
202 mgr->get_manager_info(mgr, &info);
203
204 info.trans_key = key_value;
205
206 r = mgr->set_manager_info(mgr, &info);
207 if (r)
208 return r;
209
210 r = mgr->apply(mgr);
211 if (r)
212 return r;
213
214 return size;
215}
216
217static ssize_t manager_trans_key_enabled_show(struct omap_overlay_manager *mgr,
218 char *buf)
219{
220 return snprintf(buf, PAGE_SIZE, "%d\n", mgr->info.trans_enabled);
221}
222
223static ssize_t manager_trans_key_enabled_store(struct omap_overlay_manager *mgr,
224 const char *buf, size_t size)
225{
226 struct omap_overlay_manager_info info;
Tomi Valkeinene3a26ae2011-08-15 15:55:55 +0300227 bool enable;
Tomi Valkeineneed07e02009-08-07 13:43:20 +0300228 int r;
229
Tomi Valkeinene3a26ae2011-08-15 15:55:55 +0300230 r = strtobool(buf, &enable);
231 if (r)
232 return r;
Tomi Valkeineneed07e02009-08-07 13:43:20 +0300233
234 mgr->get_manager_info(mgr, &info);
235
Tomi Valkeinene3a26ae2011-08-15 15:55:55 +0300236 info.trans_enabled = enable;
Tomi Valkeineneed07e02009-08-07 13:43:20 +0300237
238 r = mgr->set_manager_info(mgr, &info);
239 if (r)
240 return r;
241
242 r = mgr->apply(mgr);
243 if (r)
244 return r;
245
246 return size;
247}
248
249static ssize_t manager_alpha_blending_enabled_show(
250 struct omap_overlay_manager *mgr, char *buf)
251{
Archit Taneja11354dd2011-09-26 11:47:29 +0530252 WARN_ON(!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER));
253
254 return snprintf(buf, PAGE_SIZE, "%d\n",
255 mgr->info.partial_alpha_enabled);
Tomi Valkeineneed07e02009-08-07 13:43:20 +0300256}
257
258static ssize_t manager_alpha_blending_enabled_store(
259 struct omap_overlay_manager *mgr,
260 const char *buf, size_t size)
261{
262 struct omap_overlay_manager_info info;
Tomi Valkeinene3a26ae2011-08-15 15:55:55 +0300263 bool enable;
Tomi Valkeineneed07e02009-08-07 13:43:20 +0300264 int r;
265
Archit Taneja11354dd2011-09-26 11:47:29 +0530266 WARN_ON(!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER));
267
Tomi Valkeinene3a26ae2011-08-15 15:55:55 +0300268 r = strtobool(buf, &enable);
269 if (r)
270 return r;
Tomi Valkeineneed07e02009-08-07 13:43:20 +0300271
272 mgr->get_manager_info(mgr, &info);
273
Archit Taneja11354dd2011-09-26 11:47:29 +0530274 info.partial_alpha_enabled = enable;
Tomi Valkeineneed07e02009-08-07 13:43:20 +0300275
276 r = mgr->set_manager_info(mgr, &info);
277 if (r)
278 return r;
279
280 r = mgr->apply(mgr);
281 if (r)
282 return r;
283
284 return size;
285}
286
Tomi Valkeinen3c07cae2011-06-21 09:34:30 +0300287static ssize_t manager_cpr_enable_show(struct omap_overlay_manager *mgr,
288 char *buf)
289{
290 return snprintf(buf, PAGE_SIZE, "%d\n", mgr->info.cpr_enable);
291}
292
293static ssize_t manager_cpr_enable_store(struct omap_overlay_manager *mgr,
294 const char *buf, size_t size)
295{
296 struct omap_overlay_manager_info info;
Tomi Valkeinen3c07cae2011-06-21 09:34:30 +0300297 int r;
298 bool enable;
299
300 if (!dss_has_feature(FEAT_CPR))
301 return -ENODEV;
302
Tomi Valkeinene3a26ae2011-08-15 15:55:55 +0300303 r = strtobool(buf, &enable);
Tomi Valkeinen3c07cae2011-06-21 09:34:30 +0300304 if (r)
305 return r;
306
Tomi Valkeinen3c07cae2011-06-21 09:34:30 +0300307 mgr->get_manager_info(mgr, &info);
308
309 if (info.cpr_enable == enable)
310 return size;
311
312 info.cpr_enable = enable;
313
314 r = mgr->set_manager_info(mgr, &info);
315 if (r)
316 return r;
317
318 r = mgr->apply(mgr);
319 if (r)
320 return r;
321
322 return size;
323}
324
325static ssize_t manager_cpr_coef_show(struct omap_overlay_manager *mgr,
326 char *buf)
327{
328 struct omap_overlay_manager_info info;
329
330 mgr->get_manager_info(mgr, &info);
331
332 return snprintf(buf, PAGE_SIZE,
333 "%d %d %d %d %d %d %d %d %d\n",
334 info.cpr_coefs.rr,
335 info.cpr_coefs.rg,
336 info.cpr_coefs.rb,
337 info.cpr_coefs.gr,
338 info.cpr_coefs.gg,
339 info.cpr_coefs.gb,
340 info.cpr_coefs.br,
341 info.cpr_coefs.bg,
342 info.cpr_coefs.bb);
343}
344
345static ssize_t manager_cpr_coef_store(struct omap_overlay_manager *mgr,
346 const char *buf, size_t size)
347{
348 struct omap_overlay_manager_info info;
349 struct omap_dss_cpr_coefs coefs;
350 int r, i;
351 s16 *arr;
352
353 if (!dss_has_feature(FEAT_CPR))
354 return -ENODEV;
355
356 if (sscanf(buf, "%hd %hd %hd %hd %hd %hd %hd %hd %hd",
357 &coefs.rr, &coefs.rg, &coefs.rb,
358 &coefs.gr, &coefs.gg, &coefs.gb,
359 &coefs.br, &coefs.bg, &coefs.bb) != 9)
360 return -EINVAL;
361
362 arr = (s16[]){ coefs.rr, coefs.rg, coefs.rb,
363 coefs.gr, coefs.gg, coefs.gb,
364 coefs.br, coefs.bg, coefs.bb };
365
366 for (i = 0; i < 9; ++i) {
367 if (arr[i] < -512 || arr[i] > 511)
368 return -EINVAL;
369 }
370
371 mgr->get_manager_info(mgr, &info);
372
373 info.cpr_coefs = coefs;
374
375 r = mgr->set_manager_info(mgr, &info);
376 if (r)
377 return r;
378
379 r = mgr->apply(mgr);
380 if (r)
381 return r;
382
383 return size;
384}
385
Tomi Valkeineneed07e02009-08-07 13:43:20 +0300386struct manager_attribute {
387 struct attribute attr;
388 ssize_t (*show)(struct omap_overlay_manager *, char *);
389 ssize_t (*store)(struct omap_overlay_manager *, const char *, size_t);
390};
391
392#define MANAGER_ATTR(_name, _mode, _show, _store) \
393 struct manager_attribute manager_attr_##_name = \
394 __ATTR(_name, _mode, _show, _store)
395
396static MANAGER_ATTR(name, S_IRUGO, manager_name_show, NULL);
397static MANAGER_ATTR(display, S_IRUGO|S_IWUSR,
398 manager_display_show, manager_display_store);
399static MANAGER_ATTR(default_color, S_IRUGO|S_IWUSR,
400 manager_default_color_show, manager_default_color_store);
401static MANAGER_ATTR(trans_key_type, S_IRUGO|S_IWUSR,
402 manager_trans_key_type_show, manager_trans_key_type_store);
403static MANAGER_ATTR(trans_key_value, S_IRUGO|S_IWUSR,
404 manager_trans_key_value_show, manager_trans_key_value_store);
405static MANAGER_ATTR(trans_key_enabled, S_IRUGO|S_IWUSR,
406 manager_trans_key_enabled_show,
407 manager_trans_key_enabled_store);
408static MANAGER_ATTR(alpha_blending_enabled, S_IRUGO|S_IWUSR,
409 manager_alpha_blending_enabled_show,
410 manager_alpha_blending_enabled_store);
Tomi Valkeinen3c07cae2011-06-21 09:34:30 +0300411static MANAGER_ATTR(cpr_enable, S_IRUGO|S_IWUSR,
412 manager_cpr_enable_show,
413 manager_cpr_enable_store);
414static MANAGER_ATTR(cpr_coef, S_IRUGO|S_IWUSR,
415 manager_cpr_coef_show,
416 manager_cpr_coef_store);
Tomi Valkeineneed07e02009-08-07 13:43:20 +0300417
418
419static struct attribute *manager_sysfs_attrs[] = {
420 &manager_attr_name.attr,
421 &manager_attr_display.attr,
422 &manager_attr_default_color.attr,
423 &manager_attr_trans_key_type.attr,
424 &manager_attr_trans_key_value.attr,
425 &manager_attr_trans_key_enabled.attr,
426 &manager_attr_alpha_blending_enabled.attr,
Tomi Valkeinen3c07cae2011-06-21 09:34:30 +0300427 &manager_attr_cpr_enable.attr,
428 &manager_attr_cpr_coef.attr,
Tomi Valkeineneed07e02009-08-07 13:43:20 +0300429 NULL
430};
431
432static ssize_t manager_attr_show(struct kobject *kobj, struct attribute *attr,
433 char *buf)
434{
435 struct omap_overlay_manager *manager;
436 struct manager_attribute *manager_attr;
437
438 manager = container_of(kobj, struct omap_overlay_manager, kobj);
439 manager_attr = container_of(attr, struct manager_attribute, attr);
440
441 if (!manager_attr->show)
442 return -ENOENT;
443
444 return manager_attr->show(manager, buf);
445}
446
447static ssize_t manager_attr_store(struct kobject *kobj, struct attribute *attr,
448 const char *buf, size_t size)
449{
450 struct omap_overlay_manager *manager;
451 struct manager_attribute *manager_attr;
452
453 manager = container_of(kobj, struct omap_overlay_manager, kobj);
454 manager_attr = container_of(attr, struct manager_attribute, attr);
455
456 if (!manager_attr->store)
457 return -ENOENT;
458
459 return manager_attr->store(manager, buf, size);
460}
461
Emese Revfy52cf25d2010-01-19 02:58:23 +0100462static const struct sysfs_ops manager_sysfs_ops = {
Tomi Valkeineneed07e02009-08-07 13:43:20 +0300463 .show = manager_attr_show,
464 .store = manager_attr_store,
465};
466
467static struct kobj_type manager_ktype = {
468 .sysfs_ops = &manager_sysfs_ops,
469 .default_attrs = manager_sysfs_attrs,
470};
471
472/*
473 * We have 4 levels of cache for the dispc settings. First two are in SW and
474 * the latter two in HW.
475 *
476 * +--------------------+
477 * |overlay/manager_info|
478 * +--------------------+
479 * v
480 * apply()
481 * v
482 * +--------------------+
483 * | dss_cache |
484 * +--------------------+
485 * v
486 * configure()
487 * v
488 * +--------------------+
489 * | shadow registers |
490 * +--------------------+
491 * v
492 * VFP or lcd/digit_enable
493 * v
494 * +--------------------+
495 * | registers |
496 * +--------------------+
497 */
498
499struct overlay_cache_data {
500 /* If true, cache changed, but not written to shadow registers. Set
501 * in apply(), cleared when registers written. */
502 bool dirty;
503 /* If true, shadow registers contain changed values not yet in real
504 * registers. Set when writing to shadow registers, cleared at
505 * VSYNC/EVSYNC */
506 bool shadow_dirty;
507
508 bool enabled;
509
Nishant Kamat4df9d102011-06-20 20:39:28 +0530510 struct omap_overlay_info info;
Tomi Valkeineneed07e02009-08-07 13:43:20 +0300511
512 enum omap_channel channel;
513 bool replication;
514 bool ilace;
515
Tomi Valkeineneed07e02009-08-07 13:43:20 +0300516 u32 fifo_low;
517 u32 fifo_high;
Tomi Valkeineneed07e02009-08-07 13:43:20 +0300518};
519
520struct manager_cache_data {
521 /* If true, cache changed, but not written to shadow registers. Set
522 * in apply(), cleared when registers written. */
523 bool dirty;
524 /* If true, shadow registers contain changed values not yet in real
525 * registers. Set when writing to shadow registers, cleared at
526 * VSYNC/EVSYNC */
527 bool shadow_dirty;
528
Nishant Kamat4df9d102011-06-20 20:39:28 +0530529 struct omap_overlay_manager_info info;
Tomi Valkeineneed07e02009-08-07 13:43:20 +0300530
Tomi Valkeineneed07e02009-08-07 13:43:20 +0300531 bool manual_update;
532 bool do_manual_update;
Tomi Valkeineneed07e02009-08-07 13:43:20 +0300533};
534
535static struct {
536 spinlock_t lock;
Archit Tanejaa0acb552010-09-15 19:20:00 +0530537 struct overlay_cache_data overlay_cache[MAX_DSS_OVERLAYS];
538 struct manager_cache_data manager_cache[MAX_DSS_MANAGERS];
Tomi Valkeineneed07e02009-08-07 13:43:20 +0300539
540 bool irq_enabled;
541} dss_cache;
542
543
544
545static int omap_dss_set_device(struct omap_overlay_manager *mgr,
546 struct omap_dss_device *dssdev)
547{
548 int i;
549 int r;
550
551 if (dssdev->manager) {
552 DSSERR("display '%s' already has a manager '%s'\n",
553 dssdev->name, dssdev->manager->name);
554 return -EINVAL;
555 }
556
557 if ((mgr->supported_displays & dssdev->type) == 0) {
558 DSSERR("display '%s' does not support manager '%s'\n",
559 dssdev->name, mgr->name);
560 return -EINVAL;
561 }
562
563 for (i = 0; i < mgr->num_overlays; i++) {
564 struct omap_overlay *ovl = mgr->overlays[i];
565
566 if (ovl->manager != mgr || !ovl->info.enabled)
567 continue;
568
569 r = dss_check_overlay(ovl, dssdev);
570 if (r)
571 return r;
572 }
573
574 dssdev->manager = mgr;
575 mgr->device = dssdev;
576 mgr->device_changed = true;
577
578 return 0;
579}
580
581static int omap_dss_unset_device(struct omap_overlay_manager *mgr)
582{
583 if (!mgr->device) {
584 DSSERR("failed to unset display, display not set.\n");
585 return -EINVAL;
586 }
587
Daniel Morsing0f770b42011-08-03 22:10:51 +0200588 /*
589 * Don't allow currently enabled displays to have the overlay manager
590 * pulled out from underneath them
591 */
592 if (mgr->device->state != OMAP_DSS_DISPLAY_DISABLED)
593 return -EINVAL;
594
Tomi Valkeineneed07e02009-08-07 13:43:20 +0300595 mgr->device->manager = NULL;
596 mgr->device = NULL;
597 mgr->device_changed = true;
598
599 return 0;
600}
601
Tomi Valkeinen3f71cbe2010-01-08 17:06:04 +0200602static int dss_mgr_wait_for_vsync(struct omap_overlay_manager *mgr)
603{
604 unsigned long timeout = msecs_to_jiffies(500);
605 u32 irq;
606
Sumit Semwal18faa1b2010-12-02 11:27:14 +0000607 if (mgr->device->type == OMAP_DISPLAY_TYPE_VENC) {
Tomi Valkeinen3f71cbe2010-01-08 17:06:04 +0200608 irq = DISPC_IRQ_EVSYNC_ODD;
Mythri P Kb1196012011-03-08 17:15:54 +0530609 } else if (mgr->device->type == OMAP_DISPLAY_TYPE_HDMI) {
610 irq = DISPC_IRQ_EVSYNC_EVEN;
Sumit Semwal18faa1b2010-12-02 11:27:14 +0000611 } else {
612 if (mgr->id == OMAP_DSS_CHANNEL_LCD)
613 irq = DISPC_IRQ_VSYNC;
614 else
615 irq = DISPC_IRQ_VSYNC2;
616 }
Tomi Valkeinen3f71cbe2010-01-08 17:06:04 +0200617 return omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
618}
619
Tomi Valkeineneed07e02009-08-07 13:43:20 +0300620static int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr)
621{
622 unsigned long timeout = msecs_to_jiffies(500);
623 struct manager_cache_data *mc;
Tomi Valkeineneed07e02009-08-07 13:43:20 +0300624 u32 irq;
625 int r;
626 int i;
Tomi Valkeinen446f7bf2010-01-11 16:12:31 +0200627 struct omap_dss_device *dssdev = mgr->device;
Tomi Valkeineneed07e02009-08-07 13:43:20 +0300628
Ville Syrjäläa74b2602010-03-04 16:03:56 +0200629 if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
Tomi Valkeineneed07e02009-08-07 13:43:20 +0300630 return 0;
631
Tomi Valkeinen8cff88c2011-04-30 14:09:53 +0300632 if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE)
633 return 0;
634
Mythri P Kb1196012011-03-08 17:15:54 +0530635 if (dssdev->type == OMAP_DISPLAY_TYPE_VENC
636 || dssdev->type == OMAP_DISPLAY_TYPE_HDMI) {
Tomi Valkeineneed07e02009-08-07 13:43:20 +0300637 irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN;
Tomi Valkeineneed07e02009-08-07 13:43:20 +0300638 } else {
Tomi Valkeinen8cff88c2011-04-30 14:09:53 +0300639 irq = (dssdev->manager->id == OMAP_DSS_CHANNEL_LCD) ?
640 DISPC_IRQ_VSYNC : DISPC_IRQ_VSYNC2;
Tomi Valkeineneed07e02009-08-07 13:43:20 +0300641 }
642
643 mc = &dss_cache.manager_cache[mgr->id];
644 i = 0;
645 while (1) {
646 unsigned long flags;
647 bool shadow_dirty, dirty;
648
649 spin_lock_irqsave(&dss_cache.lock, flags);
650 dirty = mc->dirty;
651 shadow_dirty = mc->shadow_dirty;
652 spin_unlock_irqrestore(&dss_cache.lock, flags);
653
654 if (!dirty && !shadow_dirty) {
655 r = 0;
656 break;
657 }
658
659 /* 4 iterations is the worst case:
660 * 1 - initial iteration, dirty = true (between VFP and VSYNC)
661 * 2 - first VSYNC, dirty = true
662 * 3 - dirty = false, shadow_dirty = true
663 * 4 - shadow_dirty = false */
664 if (i++ == 3) {
665 DSSERR("mgr(%d)->wait_for_go() not finishing\n",
666 mgr->id);
667 r = 0;
668 break;
669 }
670
671 r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
672 if (r == -ERESTARTSYS)
673 break;
674
675 if (r) {
676 DSSERR("mgr(%d)->wait_for_go() timeout\n", mgr->id);
677 break;
678 }
679 }
680
681 return r;
682}
683
684int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl)
685{
686 unsigned long timeout = msecs_to_jiffies(500);
Tomi Valkeineneed07e02009-08-07 13:43:20 +0300687 struct overlay_cache_data *oc;
688 struct omap_dss_device *dssdev;
689 u32 irq;
690 int r;
691 int i;
692
Ville Syrjäläa74b2602010-03-04 16:03:56 +0200693 if (!ovl->manager)
Tomi Valkeineneed07e02009-08-07 13:43:20 +0300694 return 0;
695
696 dssdev = ovl->manager->device;
697
Ville Syrjäläa74b2602010-03-04 16:03:56 +0200698 if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
699 return 0;
700
Tomi Valkeinen8cff88c2011-04-30 14:09:53 +0300701 if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE)
702 return 0;
703
Mythri P Kb1196012011-03-08 17:15:54 +0530704 if (dssdev->type == OMAP_DISPLAY_TYPE_VENC
705 || dssdev->type == OMAP_DISPLAY_TYPE_HDMI) {
Tomi Valkeineneed07e02009-08-07 13:43:20 +0300706 irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN;
Tomi Valkeineneed07e02009-08-07 13:43:20 +0300707 } else {
Tomi Valkeinen8cff88c2011-04-30 14:09:53 +0300708 irq = (dssdev->manager->id == OMAP_DSS_CHANNEL_LCD) ?
709 DISPC_IRQ_VSYNC : DISPC_IRQ_VSYNC2;
Tomi Valkeineneed07e02009-08-07 13:43:20 +0300710 }
711
712 oc = &dss_cache.overlay_cache[ovl->id];
713 i = 0;
714 while (1) {
715 unsigned long flags;
716 bool shadow_dirty, dirty;
717
718 spin_lock_irqsave(&dss_cache.lock, flags);
719 dirty = oc->dirty;
720 shadow_dirty = oc->shadow_dirty;
721 spin_unlock_irqrestore(&dss_cache.lock, flags);
722
723 if (!dirty && !shadow_dirty) {
724 r = 0;
725 break;
726 }
727
728 /* 4 iterations is the worst case:
729 * 1 - initial iteration, dirty = true (between VFP and VSYNC)
730 * 2 - first VSYNC, dirty = true
731 * 3 - dirty = false, shadow_dirty = true
732 * 4 - shadow_dirty = false */
733 if (i++ == 3) {
734 DSSERR("ovl(%d)->wait_for_go() not finishing\n",
735 ovl->id);
736 r = 0;
737 break;
738 }
739
740 r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
741 if (r == -ERESTARTSYS)
742 break;
743
744 if (r) {
745 DSSERR("ovl(%d)->wait_for_go() timeout\n", ovl->id);
746 break;
747 }
748 }
749
750 return r;
751}
752
753static int overlay_enabled(struct omap_overlay *ovl)
754{
755 return ovl->info.enabled && ovl->manager && ovl->manager->device;
756}
757
Tomi Valkeineneed07e02009-08-07 13:43:20 +0300758static int configure_overlay(enum omap_plane plane)
759{
760 struct overlay_cache_data *c;
Tomi Valkeinen8760db52011-11-03 16:17:37 +0200761 struct omap_overlay_info *oi;
Tomi Valkeineneed07e02009-08-07 13:43:20 +0300762 int r;
763
764 DSSDBGF("%d", plane);
765
766 c = &dss_cache.overlay_cache[plane];
Nishant Kamat4df9d102011-06-20 20:39:28 +0530767 oi = &c->info;
Tomi Valkeineneed07e02009-08-07 13:43:20 +0300768
769 if (!c->enabled) {
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +0300770 dispc_ovl_enable(plane, 0);
Tomi Valkeineneed07e02009-08-07 13:43:20 +0300771 return 0;
772 }
773
Tomi Valkeinen8760db52011-11-03 16:17:37 +0200774 r = dispc_ovl_setup(plane, oi, c->ilace, c->channel,
Archit Tanejac3d925292011-09-14 11:52:54 +0530775 c->replication, c->fifo_low, c->fifo_high);
Tomi Valkeineneed07e02009-08-07 13:43:20 +0300776 if (r) {
777 /* this shouldn't happen */
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +0300778 DSSERR("dispc_ovl_setup failed for ovl %d\n", plane);
779 dispc_ovl_enable(plane, 0);
Tomi Valkeineneed07e02009-08-07 13:43:20 +0300780 return r;
781 }
782
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +0300783 dispc_ovl_enable(plane, 1);
Tomi Valkeineneed07e02009-08-07 13:43:20 +0300784
785 return 0;
786}
787
788static void configure_manager(enum omap_channel channel)
789{
Nishant Kamat4df9d102011-06-20 20:39:28 +0530790 struct omap_overlay_manager_info *mi;
Tomi Valkeineneed07e02009-08-07 13:43:20 +0300791
792 DSSDBGF("%d", channel);
793
Nishant Kamat4df9d102011-06-20 20:39:28 +0530794 /* picking info from the cache */
795 mi = &dss_cache.manager_cache[channel].info;
Tomi Valkeineneed07e02009-08-07 13:43:20 +0300796
Tomi Valkeinen26d9dd02011-08-16 13:45:15 +0300797 dispc_mgr_set_default_color(channel, mi->default_color);
798 dispc_mgr_set_trans_key(channel, mi->trans_key_type, mi->trans_key);
799 dispc_mgr_enable_trans_key(channel, mi->trans_enabled);
Archit Taneja11354dd2011-09-26 11:47:29 +0530800 dispc_mgr_enable_alpha_fixed_zorder(channel, mi->partial_alpha_enabled);
Tomi Valkeinen3c07cae2011-06-21 09:34:30 +0300801 if (dss_has_feature(FEAT_CPR)) {
Tomi Valkeinen26d9dd02011-08-16 13:45:15 +0300802 dispc_mgr_enable_cpr(channel, mi->cpr_enable);
803 dispc_mgr_set_cpr_coef(channel, &mi->cpr_coefs);
Tomi Valkeinen3c07cae2011-06-21 09:34:30 +0300804 }
Tomi Valkeineneed07e02009-08-07 13:43:20 +0300805}
806
807/* configure_dispc() tries to write values from cache to shadow registers.
808 * It writes only to those managers/overlays that are not busy.
809 * returns 0 if everything could be written to shadow registers.
810 * returns 1 if not everything could be written to shadow registers. */
811static int configure_dispc(void)
812{
813 struct overlay_cache_data *oc;
814 struct manager_cache_data *mc;
Archit Tanejaa0acb552010-09-15 19:20:00 +0530815 const int num_ovls = dss_feat_get_num_ovls();
816 const int num_mgrs = dss_feat_get_num_mgrs();
Tomi Valkeineneed07e02009-08-07 13:43:20 +0300817 int i;
818 int r;
Archit Tanejaa0acb552010-09-15 19:20:00 +0530819 bool mgr_busy[MAX_DSS_MANAGERS];
820 bool mgr_go[MAX_DSS_MANAGERS];
Tomi Valkeineneed07e02009-08-07 13:43:20 +0300821 bool busy;
822
823 r = 0;
824 busy = false;
825
Sumit Semwal18faa1b2010-12-02 11:27:14 +0000826 for (i = 0; i < num_mgrs; i++) {
Tomi Valkeinen26d9dd02011-08-16 13:45:15 +0300827 mgr_busy[i] = dispc_mgr_go_busy(i);
Sumit Semwal18faa1b2010-12-02 11:27:14 +0000828 mgr_go[i] = false;
829 }
Tomi Valkeineneed07e02009-08-07 13:43:20 +0300830
831 /* Commit overlay settings */
832 for (i = 0; i < num_ovls; ++i) {
833 oc = &dss_cache.overlay_cache[i];
834 mc = &dss_cache.manager_cache[oc->channel];
835
836 if (!oc->dirty)
837 continue;
838
Tomi Valkeinen8cff88c2011-04-30 14:09:53 +0300839 if (mc->manual_update && !mc->do_manual_update)
Tomi Valkeineneed07e02009-08-07 13:43:20 +0300840 continue;
841
842 if (mgr_busy[oc->channel]) {
843 busy = true;
844 continue;
845 }
846
847 r = configure_overlay(i);
848 if (r)
849 DSSERR("configure_overlay %d failed\n", i);
850
851 oc->dirty = false;
852 oc->shadow_dirty = true;
853 mgr_go[oc->channel] = true;
854 }
855
856 /* Commit manager settings */
857 for (i = 0; i < num_mgrs; ++i) {
858 mc = &dss_cache.manager_cache[i];
859
860 if (!mc->dirty)
861 continue;
862
863 if (mc->manual_update && !mc->do_manual_update)
864 continue;
865
866 if (mgr_busy[i]) {
867 busy = true;
868 continue;
869 }
870
871 configure_manager(i);
872 mc->dirty = false;
873 mc->shadow_dirty = true;
874 mgr_go[i] = true;
875 }
876
877 /* set GO */
878 for (i = 0; i < num_mgrs; ++i) {
879 mc = &dss_cache.manager_cache[i];
880
881 if (!mgr_go[i])
882 continue;
883
884 /* We don't need GO with manual update display. LCD iface will
885 * always be turned off after frame, and new settings will be
886 * taken in to use at next update */
Tomi Valkeinen8cff88c2011-04-30 14:09:53 +0300887 if (!mc->manual_update)
Tomi Valkeinen26d9dd02011-08-16 13:45:15 +0300888 dispc_mgr_go(i);
Tomi Valkeineneed07e02009-08-07 13:43:20 +0300889 }
890
891 if (busy)
892 r = 1;
893 else
894 r = 0;
895
896 return r;
897}
898
Tomi Valkeineneed07e02009-08-07 13:43:20 +0300899void dss_start_update(struct omap_dss_device *dssdev)
900{
901 struct manager_cache_data *mc;
902 struct overlay_cache_data *oc;
Archit Tanejaa0acb552010-09-15 19:20:00 +0530903 const int num_ovls = dss_feat_get_num_ovls();
904 const int num_mgrs = dss_feat_get_num_mgrs();
Tomi Valkeineneed07e02009-08-07 13:43:20 +0300905 struct omap_overlay_manager *mgr;
906 int i;
907
908 mgr = dssdev->manager;
909
Tomi Valkeinen8760db52011-11-03 16:17:37 +0200910 mc = &dss_cache.manager_cache[mgr->id];
911
912 mc->do_manual_update = true;
913 configure_dispc();
914 mc->do_manual_update = false;
915
Tomi Valkeineneed07e02009-08-07 13:43:20 +0300916 for (i = 0; i < num_ovls; ++i) {
917 oc = &dss_cache.overlay_cache[i];
918 if (oc->channel != mgr->id)
919 continue;
920
921 oc->shadow_dirty = false;
922 }
923
924 for (i = 0; i < num_mgrs; ++i) {
925 mc = &dss_cache.manager_cache[i];
926 if (mgr->id != i)
927 continue;
928
929 mc->shadow_dirty = false;
930 }
931
Tomi Valkeinena2faee82010-01-08 17:14:53 +0200932 dssdev->manager->enable(dssdev->manager);
Tomi Valkeineneed07e02009-08-07 13:43:20 +0300933}
934
935static void dss_apply_irq_handler(void *data, u32 mask)
936{
937 struct manager_cache_data *mc;
938 struct overlay_cache_data *oc;
Archit Tanejaa0acb552010-09-15 19:20:00 +0530939 const int num_ovls = dss_feat_get_num_ovls();
940 const int num_mgrs = dss_feat_get_num_mgrs();
Tomi Valkeineneed07e02009-08-07 13:43:20 +0300941 int i, r;
Archit Tanejaa0acb552010-09-15 19:20:00 +0530942 bool mgr_busy[MAX_DSS_MANAGERS];
Sumit Semwal18faa1b2010-12-02 11:27:14 +0000943 u32 irq_mask;
Tomi Valkeineneed07e02009-08-07 13:43:20 +0300944
Sumit Semwal18faa1b2010-12-02 11:27:14 +0000945 for (i = 0; i < num_mgrs; i++)
Tomi Valkeinen26d9dd02011-08-16 13:45:15 +0300946 mgr_busy[i] = dispc_mgr_go_busy(i);
Tomi Valkeineneed07e02009-08-07 13:43:20 +0300947
948 spin_lock(&dss_cache.lock);
949
950 for (i = 0; i < num_ovls; ++i) {
951 oc = &dss_cache.overlay_cache[i];
952 if (!mgr_busy[oc->channel])
953 oc->shadow_dirty = false;
954 }
955
956 for (i = 0; i < num_mgrs; ++i) {
957 mc = &dss_cache.manager_cache[i];
958 if (!mgr_busy[i])
959 mc->shadow_dirty = false;
960 }
961
962 r = configure_dispc();
963 if (r == 1)
964 goto end;
965
966 /* re-read busy flags */
Sumit Semwal18faa1b2010-12-02 11:27:14 +0000967 for (i = 0; i < num_mgrs; i++)
Tomi Valkeinen26d9dd02011-08-16 13:45:15 +0300968 mgr_busy[i] = dispc_mgr_go_busy(i);
Tomi Valkeineneed07e02009-08-07 13:43:20 +0300969
970 /* keep running as long as there are busy managers, so that
971 * we can collect overlay-applied information */
972 for (i = 0; i < num_mgrs; ++i) {
973 if (mgr_busy[i])
974 goto end;
975 }
976
Sumit Semwal18faa1b2010-12-02 11:27:14 +0000977 irq_mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_ODD |
978 DISPC_IRQ_EVSYNC_EVEN;
979 if (dss_has_feature(FEAT_MGR_LCD2))
980 irq_mask |= DISPC_IRQ_VSYNC2;
981
982 omap_dispc_unregister_isr(dss_apply_irq_handler, NULL, irq_mask);
Tomi Valkeineneed07e02009-08-07 13:43:20 +0300983 dss_cache.irq_enabled = false;
984
985end:
986 spin_unlock(&dss_cache.lock);
987}
988
989static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
990{
991 struct overlay_cache_data *oc;
992 struct manager_cache_data *mc;
993 int i;
994 struct omap_overlay *ovl;
Tomi Valkeineneed07e02009-08-07 13:43:20 +0300995 unsigned long flags;
996 int r;
997
998 DSSDBG("omap_dss_mgr_apply(%s)\n", mgr->name);
999
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03001000 r = dispc_runtime_get();
1001 if (r)
1002 return r;
1003
Tomi Valkeineneed07e02009-08-07 13:43:20 +03001004 spin_lock_irqsave(&dss_cache.lock, flags);
1005
1006 /* Configure overlays */
1007 for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
1008 struct omap_dss_device *dssdev;
1009
1010 ovl = omap_dss_get_overlay(i);
1011
Tomi Valkeineneed07e02009-08-07 13:43:20 +03001012 oc = &dss_cache.overlay_cache[ovl->id];
1013
Tomi Valkeinen8fa80312011-08-16 12:56:19 +03001014 if (ovl->manager_changed) {
1015 ovl->manager_changed = false;
1016 ovl->info_dirty = true;
1017 }
1018
Tomi Valkeineneed07e02009-08-07 13:43:20 +03001019 if (!overlay_enabled(ovl)) {
1020 if (oc->enabled) {
1021 oc->enabled = false;
1022 oc->dirty = true;
1023 }
1024 continue;
1025 }
1026
Tomi Valkeinen714ad3a2011-10-27 13:11:31 +03001027 if (!ovl->info_dirty)
Tomi Valkeineneed07e02009-08-07 13:43:20 +03001028 continue;
Tomi Valkeineneed07e02009-08-07 13:43:20 +03001029
1030 dssdev = ovl->manager->device;
1031
1032 if (dss_check_overlay(ovl, dssdev)) {
1033 if (oc->enabled) {
1034 oc->enabled = false;
1035 oc->dirty = true;
1036 }
1037 continue;
1038 }
1039
1040 ovl->info_dirty = false;
1041 oc->dirty = true;
Nishant Kamat4df9d102011-06-20 20:39:28 +05301042 oc->info = ovl->info;
Tomi Valkeineneed07e02009-08-07 13:43:20 +03001043
1044 oc->replication =
1045 dss_use_replication(dssdev, ovl->info.color_mode);
1046
1047 oc->ilace = dssdev->type == OMAP_DISPLAY_TYPE_VENC;
1048
1049 oc->channel = ovl->manager->id;
1050
1051 oc->enabled = true;
Tomi Valkeineneed07e02009-08-07 13:43:20 +03001052 }
1053
1054 /* Configure managers */
1055 list_for_each_entry(mgr, &manager_list, list) {
1056 struct omap_dss_device *dssdev;
1057
Tomi Valkeineneed07e02009-08-07 13:43:20 +03001058 mc = &dss_cache.manager_cache[mgr->id];
1059
1060 if (mgr->device_changed) {
1061 mgr->device_changed = false;
1062 mgr->info_dirty = true;
1063 }
1064
1065 if (!mgr->info_dirty)
1066 continue;
1067
1068 if (!mgr->device)
1069 continue;
1070
1071 dssdev = mgr->device;
1072
1073 mgr->info_dirty = false;
1074 mc->dirty = true;
Nishant Kamat4df9d102011-06-20 20:39:28 +05301075 mc->info = mgr->info;
Tomi Valkeineneed07e02009-08-07 13:43:20 +03001076
Tomi Valkeineneed07e02009-08-07 13:43:20 +03001077 mc->manual_update =
Tomi Valkeinen8cff88c2011-04-30 14:09:53 +03001078 dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE;
Tomi Valkeineneed07e02009-08-07 13:43:20 +03001079 }
1080
Tomi Valkeineneed07e02009-08-07 13:43:20 +03001081 /* Configure overlay fifos */
1082 for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
1083 struct omap_dss_device *dssdev;
Tomi Valkeinen5ed8cf52011-06-21 09:35:36 +03001084 u32 size, burst_size;
Tomi Valkeineneed07e02009-08-07 13:43:20 +03001085
1086 ovl = omap_dss_get_overlay(i);
1087
Tomi Valkeineneed07e02009-08-07 13:43:20 +03001088 oc = &dss_cache.overlay_cache[ovl->id];
1089
1090 if (!oc->enabled)
1091 continue;
1092
1093 dssdev = ovl->manager->device;
1094
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +03001095 size = dispc_ovl_get_fifo_size(ovl->id);
Tomi Valkeineneed07e02009-08-07 13:43:20 +03001096
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +03001097 burst_size = dispc_ovl_get_burst_size(ovl->id);
Tomi Valkeinen5ed8cf52011-06-21 09:35:36 +03001098
Tomi Valkeineneed07e02009-08-07 13:43:20 +03001099 switch (dssdev->type) {
1100 case OMAP_DISPLAY_TYPE_DPI:
1101 case OMAP_DISPLAY_TYPE_DBI:
1102 case OMAP_DISPLAY_TYPE_SDI:
1103 case OMAP_DISPLAY_TYPE_VENC:
Mythri P Kb1196012011-03-08 17:15:54 +05301104 case OMAP_DISPLAY_TYPE_HDMI:
Tomi Valkeineneed07e02009-08-07 13:43:20 +03001105 default_get_overlay_fifo_thresholds(ovl->id, size,
Tomi Valkeinen5ed8cf52011-06-21 09:35:36 +03001106 burst_size, &oc->fifo_low,
Tomi Valkeineneed07e02009-08-07 13:43:20 +03001107 &oc->fifo_high);
1108 break;
1109#ifdef CONFIG_OMAP2_DSS_DSI
1110 case OMAP_DISPLAY_TYPE_DSI:
1111 dsi_get_overlay_fifo_thresholds(ovl->id, size,
Tomi Valkeinen5ed8cf52011-06-21 09:35:36 +03001112 burst_size, &oc->fifo_low,
Tomi Valkeineneed07e02009-08-07 13:43:20 +03001113 &oc->fifo_high);
1114 break;
1115#endif
1116 default:
1117 BUG();
1118 }
1119 }
1120
1121 r = 0;
Tomi Valkeineneed07e02009-08-07 13:43:20 +03001122 if (!dss_cache.irq_enabled) {
Sumit Semwal18faa1b2010-12-02 11:27:14 +00001123 u32 mask;
1124
1125 mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_ODD |
1126 DISPC_IRQ_EVSYNC_EVEN;
1127 if (dss_has_feature(FEAT_MGR_LCD2))
1128 mask |= DISPC_IRQ_VSYNC2;
1129
1130 r = omap_dispc_register_isr(dss_apply_irq_handler, NULL, mask);
Tomi Valkeineneed07e02009-08-07 13:43:20 +03001131 dss_cache.irq_enabled = true;
1132 }
1133 configure_dispc();
Tomi Valkeineneed07e02009-08-07 13:43:20 +03001134
1135 spin_unlock_irqrestore(&dss_cache.lock, flags);
1136
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03001137 dispc_runtime_put();
1138
Tomi Valkeineneed07e02009-08-07 13:43:20 +03001139 return r;
1140}
1141
1142static int dss_check_manager(struct omap_overlay_manager *mgr)
1143{
Archit Taneja11354dd2011-09-26 11:47:29 +05301144 if (dss_has_feature(FEAT_ALPHA_FIXED_ZORDER)) {
1145 /*
1146 * OMAP3 supports only graphics source transparency color key
1147 * and alpha blending simultaneously. See TRM 15.4.2.4.2.2
1148 * Alpha Mode
1149 */
1150 if (mgr->info.partial_alpha_enabled && mgr->info.trans_enabled
1151 && mgr->info.trans_key_type !=
1152 OMAP_DSS_COLOR_KEY_GFX_DST)
1153 return -EINVAL;
1154 }
Tomi Valkeineneed07e02009-08-07 13:43:20 +03001155
1156 return 0;
1157}
1158
1159static int omap_dss_mgr_set_info(struct omap_overlay_manager *mgr,
1160 struct omap_overlay_manager_info *info)
1161{
1162 int r;
1163 struct omap_overlay_manager_info old_info;
1164
1165 old_info = mgr->info;
1166 mgr->info = *info;
1167
1168 r = dss_check_manager(mgr);
1169 if (r) {
1170 mgr->info = old_info;
1171 return r;
1172 }
1173
1174 mgr->info_dirty = true;
1175
1176 return 0;
1177}
1178
1179static void omap_dss_mgr_get_info(struct omap_overlay_manager *mgr,
1180 struct omap_overlay_manager_info *info)
1181{
1182 *info = mgr->info;
1183}
1184
Tomi Valkeinena2faee82010-01-08 17:14:53 +02001185static int dss_mgr_enable(struct omap_overlay_manager *mgr)
1186{
Tomi Valkeinen26d9dd02011-08-16 13:45:15 +03001187 dispc_mgr_enable(mgr->id, 1);
Tomi Valkeinena2faee82010-01-08 17:14:53 +02001188 return 0;
1189}
1190
1191static int dss_mgr_disable(struct omap_overlay_manager *mgr)
1192{
Tomi Valkeinen26d9dd02011-08-16 13:45:15 +03001193 dispc_mgr_enable(mgr->id, 0);
Tomi Valkeinena2faee82010-01-08 17:14:53 +02001194 return 0;
1195}
1196
Tomi Valkeineneed07e02009-08-07 13:43:20 +03001197static void omap_dss_add_overlay_manager(struct omap_overlay_manager *manager)
1198{
1199 ++num_managers;
1200 list_add_tail(&manager->list, &manager_list);
1201}
1202
1203int dss_init_overlay_managers(struct platform_device *pdev)
1204{
1205 int i, r;
1206
1207 spin_lock_init(&dss_cache.lock);
1208
1209 INIT_LIST_HEAD(&manager_list);
1210
1211 num_managers = 0;
1212
Archit Tanejaa0acb552010-09-15 19:20:00 +05301213 for (i = 0; i < dss_feat_get_num_mgrs(); ++i) {
Tomi Valkeineneed07e02009-08-07 13:43:20 +03001214 struct omap_overlay_manager *mgr;
1215 mgr = kzalloc(sizeof(*mgr), GFP_KERNEL);
1216
1217 BUG_ON(mgr == NULL);
1218
1219 switch (i) {
1220 case 0:
1221 mgr->name = "lcd";
1222 mgr->id = OMAP_DSS_CHANNEL_LCD;
Tomi Valkeineneed07e02009-08-07 13:43:20 +03001223 break;
1224 case 1:
1225 mgr->name = "tv";
1226 mgr->id = OMAP_DSS_CHANNEL_DIGIT;
Tomi Valkeineneed07e02009-08-07 13:43:20 +03001227 break;
Sumit Semwal18faa1b2010-12-02 11:27:14 +00001228 case 2:
1229 mgr->name = "lcd2";
1230 mgr->id = OMAP_DSS_CHANNEL_LCD2;
1231 break;
Tomi Valkeineneed07e02009-08-07 13:43:20 +03001232 }
1233
1234 mgr->set_device = &omap_dss_set_device;
1235 mgr->unset_device = &omap_dss_unset_device;
1236 mgr->apply = &omap_dss_mgr_apply;
1237 mgr->set_manager_info = &omap_dss_mgr_set_info;
1238 mgr->get_manager_info = &omap_dss_mgr_get_info;
1239 mgr->wait_for_go = &dss_mgr_wait_for_go;
Tomi Valkeinen3f71cbe2010-01-08 17:06:04 +02001240 mgr->wait_for_vsync = &dss_mgr_wait_for_vsync;
Tomi Valkeineneed07e02009-08-07 13:43:20 +03001241
Tomi Valkeinena2faee82010-01-08 17:14:53 +02001242 mgr->enable = &dss_mgr_enable;
1243 mgr->disable = &dss_mgr_disable;
1244
Tomi Valkeinen4a9e78a2011-08-15 11:22:21 +03001245 mgr->caps = 0;
Archit Tanejaa0acb552010-09-15 19:20:00 +05301246 mgr->supported_displays =
1247 dss_feat_get_supported_displays(mgr->id);
Tomi Valkeineneed07e02009-08-07 13:43:20 +03001248
1249 dss_overlay_setup_dispc_manager(mgr);
1250
1251 omap_dss_add_overlay_manager(mgr);
1252
1253 r = kobject_init_and_add(&mgr->kobj, &manager_ktype,
1254 &pdev->dev.kobj, "manager%d", i);
1255
1256 if (r) {
1257 DSSERR("failed to create sysfs file\n");
1258 continue;
1259 }
1260 }
1261
Tomi Valkeineneed07e02009-08-07 13:43:20 +03001262 return 0;
1263}
1264
1265void dss_uninit_overlay_managers(struct platform_device *pdev)
1266{
1267 struct omap_overlay_manager *mgr;
1268
1269 while (!list_empty(&manager_list)) {
1270 mgr = list_first_entry(&manager_list,
1271 struct omap_overlay_manager, list);
1272 list_del(&mgr->list);
1273 kobject_del(&mgr->kobj);
1274 kobject_put(&mgr->kobj);
1275 kfree(mgr);
1276 }
1277
1278 num_managers = 0;
1279}
1280
1281int omap_dss_get_num_overlay_managers(void)
1282{
1283 return num_managers;
1284}
1285EXPORT_SYMBOL(omap_dss_get_num_overlay_managers);
1286
1287struct omap_overlay_manager *omap_dss_get_overlay_manager(int num)
1288{
1289 int i = 0;
1290 struct omap_overlay_manager *mgr;
1291
1292 list_for_each_entry(mgr, &manager_list, list) {
1293 if (i++ == num)
1294 return mgr;
1295 }
1296
1297 return NULL;
1298}
1299EXPORT_SYMBOL(omap_dss_get_overlay_manager);
1300