blob: 268704bc6c39958c7ec0aadd80f35c9b77c27df5 [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 Valkeinen1cb00172011-11-18 11:14:01 +0200899void dss_mgr_start_update(struct omap_overlay_manager *mgr)
Tomi Valkeineneed07e02009-08-07 13:43:20 +0300900{
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 int i;
906
Tomi Valkeinen8760db52011-11-03 16:17:37 +0200907 mc = &dss_cache.manager_cache[mgr->id];
908
909 mc->do_manual_update = true;
910 configure_dispc();
911 mc->do_manual_update = false;
912
Tomi Valkeineneed07e02009-08-07 13:43:20 +0300913 for (i = 0; i < num_ovls; ++i) {
914 oc = &dss_cache.overlay_cache[i];
915 if (oc->channel != mgr->id)
916 continue;
917
918 oc->shadow_dirty = false;
919 }
920
921 for (i = 0; i < num_mgrs; ++i) {
922 mc = &dss_cache.manager_cache[i];
923 if (mgr->id != i)
924 continue;
925
926 mc->shadow_dirty = false;
927 }
928
Tomi Valkeinen1cb00172011-11-18 11:14:01 +0200929 mgr->enable(mgr);
Tomi Valkeineneed07e02009-08-07 13:43:20 +0300930}
931
932static void dss_apply_irq_handler(void *data, u32 mask)
933{
934 struct manager_cache_data *mc;
935 struct overlay_cache_data *oc;
Archit Tanejaa0acb552010-09-15 19:20:00 +0530936 const int num_ovls = dss_feat_get_num_ovls();
937 const int num_mgrs = dss_feat_get_num_mgrs();
Tomi Valkeineneed07e02009-08-07 13:43:20 +0300938 int i, r;
Archit Tanejaa0acb552010-09-15 19:20:00 +0530939 bool mgr_busy[MAX_DSS_MANAGERS];
Sumit Semwal18faa1b2010-12-02 11:27:14 +0000940 u32 irq_mask;
Tomi Valkeineneed07e02009-08-07 13:43:20 +0300941
Sumit Semwal18faa1b2010-12-02 11:27:14 +0000942 for (i = 0; i < num_mgrs; i++)
Tomi Valkeinen26d9dd02011-08-16 13:45:15 +0300943 mgr_busy[i] = dispc_mgr_go_busy(i);
Tomi Valkeineneed07e02009-08-07 13:43:20 +0300944
945 spin_lock(&dss_cache.lock);
946
947 for (i = 0; i < num_ovls; ++i) {
948 oc = &dss_cache.overlay_cache[i];
949 if (!mgr_busy[oc->channel])
950 oc->shadow_dirty = false;
951 }
952
953 for (i = 0; i < num_mgrs; ++i) {
954 mc = &dss_cache.manager_cache[i];
955 if (!mgr_busy[i])
956 mc->shadow_dirty = false;
957 }
958
959 r = configure_dispc();
960 if (r == 1)
961 goto end;
962
963 /* re-read busy flags */
Sumit Semwal18faa1b2010-12-02 11:27:14 +0000964 for (i = 0; i < num_mgrs; i++)
Tomi Valkeinen26d9dd02011-08-16 13:45:15 +0300965 mgr_busy[i] = dispc_mgr_go_busy(i);
Tomi Valkeineneed07e02009-08-07 13:43:20 +0300966
967 /* keep running as long as there are busy managers, so that
968 * we can collect overlay-applied information */
969 for (i = 0; i < num_mgrs; ++i) {
970 if (mgr_busy[i])
971 goto end;
972 }
973
Sumit Semwal18faa1b2010-12-02 11:27:14 +0000974 irq_mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_ODD |
975 DISPC_IRQ_EVSYNC_EVEN;
976 if (dss_has_feature(FEAT_MGR_LCD2))
977 irq_mask |= DISPC_IRQ_VSYNC2;
978
979 omap_dispc_unregister_isr(dss_apply_irq_handler, NULL, irq_mask);
Tomi Valkeineneed07e02009-08-07 13:43:20 +0300980 dss_cache.irq_enabled = false;
981
982end:
983 spin_unlock(&dss_cache.lock);
984}
985
986static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
987{
988 struct overlay_cache_data *oc;
989 struct manager_cache_data *mc;
990 int i;
991 struct omap_overlay *ovl;
Tomi Valkeineneed07e02009-08-07 13:43:20 +0300992 unsigned long flags;
993 int r;
994
995 DSSDBG("omap_dss_mgr_apply(%s)\n", mgr->name);
996
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +0300997 r = dispc_runtime_get();
998 if (r)
999 return r;
1000
Tomi Valkeineneed07e02009-08-07 13:43:20 +03001001 spin_lock_irqsave(&dss_cache.lock, flags);
1002
1003 /* Configure overlays */
1004 for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
1005 struct omap_dss_device *dssdev;
1006
1007 ovl = omap_dss_get_overlay(i);
1008
Tomi Valkeineneed07e02009-08-07 13:43:20 +03001009 oc = &dss_cache.overlay_cache[ovl->id];
1010
Tomi Valkeinen8fa80312011-08-16 12:56:19 +03001011 if (ovl->manager_changed) {
1012 ovl->manager_changed = false;
1013 ovl->info_dirty = true;
1014 }
1015
Tomi Valkeineneed07e02009-08-07 13:43:20 +03001016 if (!overlay_enabled(ovl)) {
1017 if (oc->enabled) {
1018 oc->enabled = false;
1019 oc->dirty = true;
1020 }
1021 continue;
1022 }
1023
Tomi Valkeinen714ad3a2011-10-27 13:11:31 +03001024 if (!ovl->info_dirty)
Tomi Valkeineneed07e02009-08-07 13:43:20 +03001025 continue;
Tomi Valkeineneed07e02009-08-07 13:43:20 +03001026
1027 dssdev = ovl->manager->device;
1028
1029 if (dss_check_overlay(ovl, dssdev)) {
1030 if (oc->enabled) {
1031 oc->enabled = false;
1032 oc->dirty = true;
1033 }
1034 continue;
1035 }
1036
1037 ovl->info_dirty = false;
1038 oc->dirty = true;
Nishant Kamat4df9d102011-06-20 20:39:28 +05301039 oc->info = ovl->info;
Tomi Valkeineneed07e02009-08-07 13:43:20 +03001040
1041 oc->replication =
1042 dss_use_replication(dssdev, ovl->info.color_mode);
1043
1044 oc->ilace = dssdev->type == OMAP_DISPLAY_TYPE_VENC;
1045
1046 oc->channel = ovl->manager->id;
1047
1048 oc->enabled = true;
Tomi Valkeineneed07e02009-08-07 13:43:20 +03001049 }
1050
1051 /* Configure managers */
1052 list_for_each_entry(mgr, &manager_list, list) {
1053 struct omap_dss_device *dssdev;
1054
Tomi Valkeineneed07e02009-08-07 13:43:20 +03001055 mc = &dss_cache.manager_cache[mgr->id];
1056
1057 if (mgr->device_changed) {
1058 mgr->device_changed = false;
1059 mgr->info_dirty = true;
1060 }
1061
1062 if (!mgr->info_dirty)
1063 continue;
1064
1065 if (!mgr->device)
1066 continue;
1067
1068 dssdev = mgr->device;
1069
1070 mgr->info_dirty = false;
1071 mc->dirty = true;
Nishant Kamat4df9d102011-06-20 20:39:28 +05301072 mc->info = mgr->info;
Tomi Valkeineneed07e02009-08-07 13:43:20 +03001073
Tomi Valkeineneed07e02009-08-07 13:43:20 +03001074 mc->manual_update =
Tomi Valkeinen8cff88c2011-04-30 14:09:53 +03001075 dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE;
Tomi Valkeineneed07e02009-08-07 13:43:20 +03001076 }
1077
Tomi Valkeineneed07e02009-08-07 13:43:20 +03001078 /* Configure overlay fifos */
1079 for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
1080 struct omap_dss_device *dssdev;
Tomi Valkeinen5ed8cf52011-06-21 09:35:36 +03001081 u32 size, burst_size;
Tomi Valkeineneed07e02009-08-07 13:43:20 +03001082
1083 ovl = omap_dss_get_overlay(i);
1084
Tomi Valkeineneed07e02009-08-07 13:43:20 +03001085 oc = &dss_cache.overlay_cache[ovl->id];
1086
1087 if (!oc->enabled)
1088 continue;
1089
1090 dssdev = ovl->manager->device;
1091
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +03001092 size = dispc_ovl_get_fifo_size(ovl->id);
Tomi Valkeineneed07e02009-08-07 13:43:20 +03001093
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +03001094 burst_size = dispc_ovl_get_burst_size(ovl->id);
Tomi Valkeinen5ed8cf52011-06-21 09:35:36 +03001095
Tomi Valkeineneed07e02009-08-07 13:43:20 +03001096 switch (dssdev->type) {
1097 case OMAP_DISPLAY_TYPE_DPI:
1098 case OMAP_DISPLAY_TYPE_DBI:
1099 case OMAP_DISPLAY_TYPE_SDI:
1100 case OMAP_DISPLAY_TYPE_VENC:
Mythri P Kb1196012011-03-08 17:15:54 +05301101 case OMAP_DISPLAY_TYPE_HDMI:
Tomi Valkeineneed07e02009-08-07 13:43:20 +03001102 default_get_overlay_fifo_thresholds(ovl->id, size,
Tomi Valkeinen5ed8cf52011-06-21 09:35:36 +03001103 burst_size, &oc->fifo_low,
Tomi Valkeineneed07e02009-08-07 13:43:20 +03001104 &oc->fifo_high);
1105 break;
1106#ifdef CONFIG_OMAP2_DSS_DSI
1107 case OMAP_DISPLAY_TYPE_DSI:
1108 dsi_get_overlay_fifo_thresholds(ovl->id, size,
Tomi Valkeinen5ed8cf52011-06-21 09:35:36 +03001109 burst_size, &oc->fifo_low,
Tomi Valkeineneed07e02009-08-07 13:43:20 +03001110 &oc->fifo_high);
1111 break;
1112#endif
1113 default:
1114 BUG();
1115 }
1116 }
1117
1118 r = 0;
Tomi Valkeineneed07e02009-08-07 13:43:20 +03001119 if (!dss_cache.irq_enabled) {
Sumit Semwal18faa1b2010-12-02 11:27:14 +00001120 u32 mask;
1121
1122 mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_ODD |
1123 DISPC_IRQ_EVSYNC_EVEN;
1124 if (dss_has_feature(FEAT_MGR_LCD2))
1125 mask |= DISPC_IRQ_VSYNC2;
1126
1127 r = omap_dispc_register_isr(dss_apply_irq_handler, NULL, mask);
Tomi Valkeineneed07e02009-08-07 13:43:20 +03001128 dss_cache.irq_enabled = true;
1129 }
1130 configure_dispc();
Tomi Valkeineneed07e02009-08-07 13:43:20 +03001131
1132 spin_unlock_irqrestore(&dss_cache.lock, flags);
1133
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03001134 dispc_runtime_put();
1135
Tomi Valkeineneed07e02009-08-07 13:43:20 +03001136 return r;
1137}
1138
1139static int dss_check_manager(struct omap_overlay_manager *mgr)
1140{
Archit Taneja11354dd2011-09-26 11:47:29 +05301141 if (dss_has_feature(FEAT_ALPHA_FIXED_ZORDER)) {
1142 /*
1143 * OMAP3 supports only graphics source transparency color key
1144 * and alpha blending simultaneously. See TRM 15.4.2.4.2.2
1145 * Alpha Mode
1146 */
1147 if (mgr->info.partial_alpha_enabled && mgr->info.trans_enabled
1148 && mgr->info.trans_key_type !=
1149 OMAP_DSS_COLOR_KEY_GFX_DST)
1150 return -EINVAL;
1151 }
Tomi Valkeineneed07e02009-08-07 13:43:20 +03001152
1153 return 0;
1154}
1155
1156static int omap_dss_mgr_set_info(struct omap_overlay_manager *mgr,
1157 struct omap_overlay_manager_info *info)
1158{
1159 int r;
1160 struct omap_overlay_manager_info old_info;
1161
1162 old_info = mgr->info;
1163 mgr->info = *info;
1164
1165 r = dss_check_manager(mgr);
1166 if (r) {
1167 mgr->info = old_info;
1168 return r;
1169 }
1170
1171 mgr->info_dirty = true;
1172
1173 return 0;
1174}
1175
1176static void omap_dss_mgr_get_info(struct omap_overlay_manager *mgr,
1177 struct omap_overlay_manager_info *info)
1178{
1179 *info = mgr->info;
1180}
1181
Tomi Valkeinena2faee82010-01-08 17:14:53 +02001182static int dss_mgr_enable(struct omap_overlay_manager *mgr)
1183{
Tomi Valkeinen26d9dd02011-08-16 13:45:15 +03001184 dispc_mgr_enable(mgr->id, 1);
Tomi Valkeinena2faee82010-01-08 17:14:53 +02001185 return 0;
1186}
1187
1188static int dss_mgr_disable(struct omap_overlay_manager *mgr)
1189{
Tomi Valkeinen26d9dd02011-08-16 13:45:15 +03001190 dispc_mgr_enable(mgr->id, 0);
Tomi Valkeinena2faee82010-01-08 17:14:53 +02001191 return 0;
1192}
1193
Tomi Valkeineneed07e02009-08-07 13:43:20 +03001194static void omap_dss_add_overlay_manager(struct omap_overlay_manager *manager)
1195{
1196 ++num_managers;
1197 list_add_tail(&manager->list, &manager_list);
1198}
1199
1200int dss_init_overlay_managers(struct platform_device *pdev)
1201{
1202 int i, r;
1203
1204 spin_lock_init(&dss_cache.lock);
1205
1206 INIT_LIST_HEAD(&manager_list);
1207
1208 num_managers = 0;
1209
Archit Tanejaa0acb552010-09-15 19:20:00 +05301210 for (i = 0; i < dss_feat_get_num_mgrs(); ++i) {
Tomi Valkeineneed07e02009-08-07 13:43:20 +03001211 struct omap_overlay_manager *mgr;
1212 mgr = kzalloc(sizeof(*mgr), GFP_KERNEL);
1213
1214 BUG_ON(mgr == NULL);
1215
1216 switch (i) {
1217 case 0:
1218 mgr->name = "lcd";
1219 mgr->id = OMAP_DSS_CHANNEL_LCD;
Tomi Valkeineneed07e02009-08-07 13:43:20 +03001220 break;
1221 case 1:
1222 mgr->name = "tv";
1223 mgr->id = OMAP_DSS_CHANNEL_DIGIT;
Tomi Valkeineneed07e02009-08-07 13:43:20 +03001224 break;
Sumit Semwal18faa1b2010-12-02 11:27:14 +00001225 case 2:
1226 mgr->name = "lcd2";
1227 mgr->id = OMAP_DSS_CHANNEL_LCD2;
1228 break;
Tomi Valkeineneed07e02009-08-07 13:43:20 +03001229 }
1230
1231 mgr->set_device = &omap_dss_set_device;
1232 mgr->unset_device = &omap_dss_unset_device;
1233 mgr->apply = &omap_dss_mgr_apply;
1234 mgr->set_manager_info = &omap_dss_mgr_set_info;
1235 mgr->get_manager_info = &omap_dss_mgr_get_info;
1236 mgr->wait_for_go = &dss_mgr_wait_for_go;
Tomi Valkeinen3f71cbe2010-01-08 17:06:04 +02001237 mgr->wait_for_vsync = &dss_mgr_wait_for_vsync;
Tomi Valkeineneed07e02009-08-07 13:43:20 +03001238
Tomi Valkeinena2faee82010-01-08 17:14:53 +02001239 mgr->enable = &dss_mgr_enable;
1240 mgr->disable = &dss_mgr_disable;
1241
Tomi Valkeinen4a9e78a2011-08-15 11:22:21 +03001242 mgr->caps = 0;
Archit Tanejaa0acb552010-09-15 19:20:00 +05301243 mgr->supported_displays =
1244 dss_feat_get_supported_displays(mgr->id);
Tomi Valkeineneed07e02009-08-07 13:43:20 +03001245
1246 dss_overlay_setup_dispc_manager(mgr);
1247
1248 omap_dss_add_overlay_manager(mgr);
1249
1250 r = kobject_init_and_add(&mgr->kobj, &manager_ktype,
1251 &pdev->dev.kobj, "manager%d", i);
1252
1253 if (r) {
1254 DSSERR("failed to create sysfs file\n");
1255 continue;
1256 }
1257 }
1258
Tomi Valkeineneed07e02009-08-07 13:43:20 +03001259 return 0;
1260}
1261
1262void dss_uninit_overlay_managers(struct platform_device *pdev)
1263{
1264 struct omap_overlay_manager *mgr;
1265
1266 while (!list_empty(&manager_list)) {
1267 mgr = list_first_entry(&manager_list,
1268 struct omap_overlay_manager, list);
1269 list_del(&mgr->list);
1270 kobject_del(&mgr->kobj);
1271 kobject_put(&mgr->kobj);
1272 kfree(mgr);
1273 }
1274
1275 num_managers = 0;
1276}
1277
1278int omap_dss_get_num_overlay_managers(void)
1279{
1280 return num_managers;
1281}
1282EXPORT_SYMBOL(omap_dss_get_num_overlay_managers);
1283
1284struct omap_overlay_manager *omap_dss_get_overlay_manager(int num)
1285{
1286 int i = 0;
1287 struct omap_overlay_manager *mgr;
1288
1289 list_for_each_entry(mgr, &manager_list, list) {
1290 if (i++ == num)
1291 return mgr;
1292 }
1293
1294 return NULL;
1295}
1296EXPORT_SYMBOL(omap_dss_get_overlay_manager);
1297