2 * linux/drivers/video/omap2/dss/manager.c
4 * Copyright (C) 2009 Nokia Corporation
5 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
7 * Some code and ideas taken from drivers/video/omap/ driver
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.
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
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/>.
23 #define DSS_SUBSYS_NAME "MANAGER"
25 #include <linux/kernel.h>
26 #include <linux/slab.h>
27 #include <linux/module.h>
28 #include <linux/platform_device.h>
29 #include <linux/spinlock.h>
30 #include <linux/jiffies.h>
32 #include <plat/display.h>
37 static int num_managers
;
38 static struct list_head manager_list
;
40 static ssize_t
manager_name_show(struct omap_overlay_manager
*mgr
, char *buf
)
42 return snprintf(buf
, PAGE_SIZE
, "%s\n", mgr
->name
);
45 static ssize_t
manager_display_show(struct omap_overlay_manager
*mgr
, char *buf
)
47 return snprintf(buf
, PAGE_SIZE
, "%s\n",
48 mgr
->device
? mgr
->device
->name
: "<none>");
51 static ssize_t
manager_display_store(struct omap_overlay_manager
*mgr
,
52 const char *buf
, size_t size
)
56 struct omap_dss_device
*dssdev
= NULL
;
58 int match(struct omap_dss_device
*dssdev
, void *data
)
60 const char *str
= data
;
61 return sysfs_streq(dssdev
->name
, str
);
64 if (buf
[size
-1] == '\n')
68 dssdev
= omap_dss_find_device((void *)buf
, match
);
70 if (len
> 0 && dssdev
== NULL
)
74 DSSDBG("display %s found\n", dssdev
->name
);
77 r
= mgr
->unset_device(mgr
);
79 DSSERR("failed to unset display\n");
85 r
= mgr
->set_device(mgr
, dssdev
);
87 DSSERR("failed to set manager\n");
93 DSSERR("failed to apply dispc config\n");
100 omap_dss_put_device(dssdev
);
105 static ssize_t
manager_default_color_show(struct omap_overlay_manager
*mgr
,
108 return snprintf(buf
, PAGE_SIZE
, "%d\n", mgr
->info
.default_color
);
111 static ssize_t
manager_default_color_store(struct omap_overlay_manager
*mgr
,
112 const char *buf
, size_t size
)
114 struct omap_overlay_manager_info info
;
118 if (sscanf(buf
, "%d", &color
) != 1)
121 mgr
->get_manager_info(mgr
, &info
);
123 info
.default_color
= color
;
125 r
= mgr
->set_manager_info(mgr
, &info
);
136 static const char *trans_key_type_str
[] = {
141 static ssize_t
manager_trans_key_type_show(struct omap_overlay_manager
*mgr
,
144 enum omap_dss_trans_key_type key_type
;
146 key_type
= mgr
->info
.trans_key_type
;
147 BUG_ON(key_type
>= ARRAY_SIZE(trans_key_type_str
));
149 return snprintf(buf
, PAGE_SIZE
, "%s\n", trans_key_type_str
[key_type
]);
152 static ssize_t
manager_trans_key_type_store(struct omap_overlay_manager
*mgr
,
153 const char *buf
, size_t size
)
155 enum omap_dss_trans_key_type key_type
;
156 struct omap_overlay_manager_info info
;
159 for (key_type
= OMAP_DSS_COLOR_KEY_GFX_DST
;
160 key_type
< ARRAY_SIZE(trans_key_type_str
); key_type
++) {
161 if (sysfs_streq(buf
, trans_key_type_str
[key_type
]))
165 if (key_type
== ARRAY_SIZE(trans_key_type_str
))
168 mgr
->get_manager_info(mgr
, &info
);
170 info
.trans_key_type
= key_type
;
172 r
= mgr
->set_manager_info(mgr
, &info
);
183 static ssize_t
manager_trans_key_value_show(struct omap_overlay_manager
*mgr
,
186 return snprintf(buf
, PAGE_SIZE
, "%d\n", mgr
->info
.trans_key
);
189 static ssize_t
manager_trans_key_value_store(struct omap_overlay_manager
*mgr
,
190 const char *buf
, size_t size
)
192 struct omap_overlay_manager_info info
;
196 if (sscanf(buf
, "%d", &key_value
) != 1)
199 mgr
->get_manager_info(mgr
, &info
);
201 info
.trans_key
= key_value
;
203 r
= mgr
->set_manager_info(mgr
, &info
);
214 static ssize_t
manager_trans_key_enabled_show(struct omap_overlay_manager
*mgr
,
217 return snprintf(buf
, PAGE_SIZE
, "%d\n", mgr
->info
.trans_enabled
);
220 static ssize_t
manager_trans_key_enabled_store(struct omap_overlay_manager
*mgr
,
221 const char *buf
, size_t size
)
223 struct omap_overlay_manager_info info
;
227 if (sscanf(buf
, "%d", &enable
) != 1)
230 mgr
->get_manager_info(mgr
, &info
);
232 info
.trans_enabled
= enable
? true : false;
234 r
= mgr
->set_manager_info(mgr
, &info
);
245 static ssize_t
manager_alpha_blending_enabled_show(
246 struct omap_overlay_manager
*mgr
, char *buf
)
248 return snprintf(buf
, PAGE_SIZE
, "%d\n", mgr
->info
.alpha_enabled
);
251 static ssize_t
manager_alpha_blending_enabled_store(
252 struct omap_overlay_manager
*mgr
,
253 const char *buf
, size_t size
)
255 struct omap_overlay_manager_info info
;
259 if (sscanf(buf
, "%d", &enable
) != 1)
262 mgr
->get_manager_info(mgr
, &info
);
264 info
.alpha_enabled
= enable
? true : false;
266 r
= mgr
->set_manager_info(mgr
, &info
);
277 struct manager_attribute
{
278 struct attribute attr
;
279 ssize_t (*show
)(struct omap_overlay_manager
*, char *);
280 ssize_t (*store
)(struct omap_overlay_manager
*, const char *, size_t);
283 #define MANAGER_ATTR(_name, _mode, _show, _store) \
284 struct manager_attribute manager_attr_##_name = \
285 __ATTR(_name, _mode, _show, _store)
287 static MANAGER_ATTR(name
, S_IRUGO
, manager_name_show
, NULL
);
288 static MANAGER_ATTR(display
, S_IRUGO
|S_IWUSR
,
289 manager_display_show
, manager_display_store
);
290 static MANAGER_ATTR(default_color
, S_IRUGO
|S_IWUSR
,
291 manager_default_color_show
, manager_default_color_store
);
292 static MANAGER_ATTR(trans_key_type
, S_IRUGO
|S_IWUSR
,
293 manager_trans_key_type_show
, manager_trans_key_type_store
);
294 static MANAGER_ATTR(trans_key_value
, S_IRUGO
|S_IWUSR
,
295 manager_trans_key_value_show
, manager_trans_key_value_store
);
296 static MANAGER_ATTR(trans_key_enabled
, S_IRUGO
|S_IWUSR
,
297 manager_trans_key_enabled_show
,
298 manager_trans_key_enabled_store
);
299 static MANAGER_ATTR(alpha_blending_enabled
, S_IRUGO
|S_IWUSR
,
300 manager_alpha_blending_enabled_show
,
301 manager_alpha_blending_enabled_store
);
304 static struct attribute
*manager_sysfs_attrs
[] = {
305 &manager_attr_name
.attr
,
306 &manager_attr_display
.attr
,
307 &manager_attr_default_color
.attr
,
308 &manager_attr_trans_key_type
.attr
,
309 &manager_attr_trans_key_value
.attr
,
310 &manager_attr_trans_key_enabled
.attr
,
311 &manager_attr_alpha_blending_enabled
.attr
,
315 static ssize_t
manager_attr_show(struct kobject
*kobj
, struct attribute
*attr
,
318 struct omap_overlay_manager
*manager
;
319 struct manager_attribute
*manager_attr
;
321 manager
= container_of(kobj
, struct omap_overlay_manager
, kobj
);
322 manager_attr
= container_of(attr
, struct manager_attribute
, attr
);
324 if (!manager_attr
->show
)
327 return manager_attr
->show(manager
, buf
);
330 static ssize_t
manager_attr_store(struct kobject
*kobj
, struct attribute
*attr
,
331 const char *buf
, size_t size
)
333 struct omap_overlay_manager
*manager
;
334 struct manager_attribute
*manager_attr
;
336 manager
= container_of(kobj
, struct omap_overlay_manager
, kobj
);
337 manager_attr
= container_of(attr
, struct manager_attribute
, attr
);
339 if (!manager_attr
->store
)
342 return manager_attr
->store(manager
, buf
, size
);
345 static const struct sysfs_ops manager_sysfs_ops
= {
346 .show
= manager_attr_show
,
347 .store
= manager_attr_store
,
350 static struct kobj_type manager_ktype
= {
351 .sysfs_ops
= &manager_sysfs_ops
,
352 .default_attrs
= manager_sysfs_attrs
,
356 * We have 4 levels of cache for the dispc settings. First two are in SW and
357 * the latter two in HW.
359 * +--------------------+
360 * |overlay/manager_info|
361 * +--------------------+
365 * +--------------------+
367 * +--------------------+
371 * +--------------------+
372 * | shadow registers |
373 * +--------------------+
375 * VFP or lcd/digit_enable
377 * +--------------------+
379 * +--------------------+
382 struct overlay_cache_data
{
383 /* If true, cache changed, but not written to shadow registers. Set
384 * in apply(), cleared when registers written. */
386 /* If true, shadow registers contain changed values not yet in real
387 * registers. Set when writing to shadow registers, cleared at
398 enum omap_color_mode color_mode
;
400 enum omap_dss_rotation_type rotation_type
;
405 u16 out_width
; /* if 0, out_width == width */
406 u16 out_height
; /* if 0, out_height == height */
409 enum omap_channel channel
;
413 enum omap_burst_size burst_size
;
420 struct manager_cache_data
{
421 /* If true, cache changed, but not written to shadow registers. Set
422 * in apply(), cleared when registers written. */
424 /* If true, shadow registers contain changed values not yet in real
425 * registers. Set when writing to shadow registers, cleared at
431 enum omap_dss_trans_key_type trans_key_type
;
437 bool manual_upd_display
;
439 bool do_manual_update
;
441 /* manual update region */
447 struct overlay_cache_data overlay_cache
[3];
448 struct manager_cache_data manager_cache
[2];
455 static int omap_dss_set_device(struct omap_overlay_manager
*mgr
,
456 struct omap_dss_device
*dssdev
)
461 if (dssdev
->manager
) {
462 DSSERR("display '%s' already has a manager '%s'\n",
463 dssdev
->name
, dssdev
->manager
->name
);
467 if ((mgr
->supported_displays
& dssdev
->type
) == 0) {
468 DSSERR("display '%s' does not support manager '%s'\n",
469 dssdev
->name
, mgr
->name
);
473 for (i
= 0; i
< mgr
->num_overlays
; i
++) {
474 struct omap_overlay
*ovl
= mgr
->overlays
[i
];
476 if (ovl
->manager
!= mgr
|| !ovl
->info
.enabled
)
479 r
= dss_check_overlay(ovl
, dssdev
);
484 dssdev
->manager
= mgr
;
485 mgr
->device
= dssdev
;
486 mgr
->device_changed
= true;
491 static int omap_dss_unset_device(struct omap_overlay_manager
*mgr
)
494 DSSERR("failed to unset display, display not set.\n");
498 mgr
->device
->manager
= NULL
;
500 mgr
->device_changed
= true;
505 static int dss_mgr_wait_for_vsync(struct omap_overlay_manager
*mgr
)
507 unsigned long timeout
= msecs_to_jiffies(500);
510 if (mgr
->device
->type
== OMAP_DISPLAY_TYPE_VENC
)
511 irq
= DISPC_IRQ_EVSYNC_ODD
;
513 irq
= DISPC_IRQ_VSYNC
;
515 return omap_dispc_wait_for_irq_interruptible_timeout(irq
, timeout
);
518 static int dss_mgr_wait_for_go(struct omap_overlay_manager
*mgr
)
520 unsigned long timeout
= msecs_to_jiffies(500);
521 struct manager_cache_data
*mc
;
522 enum omap_channel channel
;
526 struct omap_dss_device
*dssdev
= mgr
->device
;
531 if (dssdev
->type
== OMAP_DISPLAY_TYPE_VENC
) {
532 irq
= DISPC_IRQ_EVSYNC_ODD
| DISPC_IRQ_EVSYNC_EVEN
;
533 channel
= OMAP_DSS_CHANNEL_DIGIT
;
535 if (dssdev
->caps
& OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE
) {
536 enum omap_dss_update_mode mode
;
537 mode
= dssdev
->driver
->get_update_mode(dssdev
);
538 if (mode
!= OMAP_DSS_UPDATE_AUTO
)
541 irq
= DISPC_IRQ_FRAMEDONE
;
543 irq
= DISPC_IRQ_VSYNC
;
545 channel
= OMAP_DSS_CHANNEL_LCD
;
548 mc
= &dss_cache
.manager_cache
[mgr
->id
];
552 bool shadow_dirty
, dirty
;
554 spin_lock_irqsave(&dss_cache
.lock
, flags
);
556 shadow_dirty
= mc
->shadow_dirty
;
557 spin_unlock_irqrestore(&dss_cache
.lock
, flags
);
559 if (!dirty
&& !shadow_dirty
) {
564 /* 4 iterations is the worst case:
565 * 1 - initial iteration, dirty = true (between VFP and VSYNC)
566 * 2 - first VSYNC, dirty = true
567 * 3 - dirty = false, shadow_dirty = true
568 * 4 - shadow_dirty = false */
570 DSSERR("mgr(%d)->wait_for_go() not finishing\n",
576 r
= omap_dispc_wait_for_irq_interruptible_timeout(irq
, timeout
);
577 if (r
== -ERESTARTSYS
)
581 DSSERR("mgr(%d)->wait_for_go() timeout\n", mgr
->id
);
589 int dss_mgr_wait_for_go_ovl(struct omap_overlay
*ovl
)
591 unsigned long timeout
= msecs_to_jiffies(500);
592 enum omap_channel channel
;
593 struct overlay_cache_data
*oc
;
594 struct omap_dss_device
*dssdev
;
599 if (!ovl
->manager
|| !ovl
->manager
->device
)
602 dssdev
= ovl
->manager
->device
;
604 if (dssdev
->type
== OMAP_DISPLAY_TYPE_VENC
) {
605 irq
= DISPC_IRQ_EVSYNC_ODD
| DISPC_IRQ_EVSYNC_EVEN
;
606 channel
= OMAP_DSS_CHANNEL_DIGIT
;
608 if (dssdev
->caps
& OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE
) {
609 enum omap_dss_update_mode mode
;
610 mode
= dssdev
->driver
->get_update_mode(dssdev
);
611 if (mode
!= OMAP_DSS_UPDATE_AUTO
)
614 irq
= DISPC_IRQ_FRAMEDONE
;
616 irq
= DISPC_IRQ_VSYNC
;
618 channel
= OMAP_DSS_CHANNEL_LCD
;
621 oc
= &dss_cache
.overlay_cache
[ovl
->id
];
625 bool shadow_dirty
, dirty
;
627 spin_lock_irqsave(&dss_cache
.lock
, flags
);
629 shadow_dirty
= oc
->shadow_dirty
;
630 spin_unlock_irqrestore(&dss_cache
.lock
, flags
);
632 if (!dirty
&& !shadow_dirty
) {
637 /* 4 iterations is the worst case:
638 * 1 - initial iteration, dirty = true (between VFP and VSYNC)
639 * 2 - first VSYNC, dirty = true
640 * 3 - dirty = false, shadow_dirty = true
641 * 4 - shadow_dirty = false */
643 DSSERR("ovl(%d)->wait_for_go() not finishing\n",
649 r
= omap_dispc_wait_for_irq_interruptible_timeout(irq
, timeout
);
650 if (r
== -ERESTARTSYS
)
654 DSSERR("ovl(%d)->wait_for_go() timeout\n", ovl
->id
);
662 static int overlay_enabled(struct omap_overlay
*ovl
)
664 return ovl
->info
.enabled
&& ovl
->manager
&& ovl
->manager
->device
;
667 /* Is rect1 a subset of rect2? */
668 static bool rectangle_subset(int x1
, int y1
, int w1
, int h1
,
669 int x2
, int y2
, int w2
, int h2
)
671 if (x1
< x2
|| y1
< y2
)
674 if (x1
+ w1
> x2
+ w2
)
677 if (y1
+ h1
> y2
+ h2
)
683 /* Do rect1 and rect2 overlap? */
684 static bool rectangle_intersects(int x1
, int y1
, int w1
, int h1
,
685 int x2
, int y2
, int w2
, int h2
)
702 static bool dispc_is_overlay_scaled(struct overlay_cache_data
*oc
)
704 if (oc
->out_width
!= 0 && oc
->width
!= oc
->out_width
)
707 if (oc
->out_height
!= 0 && oc
->height
!= oc
->out_height
)
713 static int configure_overlay(enum omap_plane plane
)
715 struct overlay_cache_data
*c
;
716 struct manager_cache_data
*mc
;
722 DSSDBGF("%d", plane
);
724 c
= &dss_cache
.overlay_cache
[plane
];
727 dispc_enable_plane(plane
, 0);
731 mc
= &dss_cache
.manager_cache
[c
->channel
];
737 outw
= c
->out_width
== 0 ? c
->width
: c
->out_width
;
738 outh
= c
->out_height
== 0 ? c
->height
: c
->out_height
;
741 if (c
->manual_update
&& mc
->do_manual_update
) {
743 /* If the overlay is outside the update region, disable it */
744 if (!rectangle_intersects(mc
->x
, mc
->y
, mc
->w
, mc
->h
,
746 dispc_enable_plane(plane
, 0);
750 switch (c
->color_mode
) {
751 case OMAP_DSS_COLOR_RGB16
:
752 case OMAP_DSS_COLOR_ARGB16
:
753 case OMAP_DSS_COLOR_YUV2
:
754 case OMAP_DSS_COLOR_UYVY
:
758 case OMAP_DSS_COLOR_RGB24P
:
762 case OMAP_DSS_COLOR_RGB24U
:
763 case OMAP_DSS_COLOR_ARGB32
:
764 case OMAP_DSS_COLOR_RGBA32
:
765 case OMAP_DSS_COLOR_RGBX32
:
773 if (dispc_is_overlay_scaled(c
)) {
774 /* If the overlay is scaled, the update area has
775 * already been enlarged to cover the whole overlay. We
776 * only need to adjust x/y here */
777 x
= c
->pos_x
- mc
->x
;
778 y
= c
->pos_y
- mc
->y
;
780 if (mc
->x
> c
->pos_x
) {
782 w
-= (mc
->x
- c
->pos_x
);
783 paddr
+= (mc
->x
- c
->pos_x
) * bpp
/ 8;
785 x
= c
->pos_x
- mc
->x
;
788 if (mc
->y
> c
->pos_y
) {
790 h
-= (mc
->y
- c
->pos_y
);
791 paddr
+= (mc
->y
- c
->pos_y
) * c
->screen_width
*
794 y
= c
->pos_y
- mc
->y
;
798 w
-= (x
+w
) - (mc
->w
);
801 h
-= (y
+h
) - (mc
->h
);
808 r
= dispc_setup_plane(plane
,
822 /* this shouldn't happen */
823 DSSERR("dispc_setup_plane failed for ovl %d\n", plane
);
824 dispc_enable_plane(plane
, 0);
828 dispc_enable_replication(plane
, c
->replication
);
830 dispc_set_burst_size(plane
, c
->burst_size
);
831 dispc_setup_plane_fifo(plane
, c
->fifo_low
, c
->fifo_high
);
833 dispc_enable_plane(plane
, 1);
838 static void configure_manager(enum omap_channel channel
)
840 struct manager_cache_data
*c
;
842 DSSDBGF("%d", channel
);
844 c
= &dss_cache
.manager_cache
[channel
];
846 dispc_set_trans_key(channel
, c
->trans_key_type
, c
->trans_key
);
847 dispc_enable_trans_key(channel
, c
->trans_enabled
);
848 dispc_enable_alpha_blending(channel
, c
->alpha_enabled
);
851 /* configure_dispc() tries to write values from cache to shadow registers.
852 * It writes only to those managers/overlays that are not busy.
853 * returns 0 if everything could be written to shadow registers.
854 * returns 1 if not everything could be written to shadow registers. */
855 static int configure_dispc(void)
857 struct overlay_cache_data
*oc
;
858 struct manager_cache_data
*mc
;
859 const int num_ovls
= ARRAY_SIZE(dss_cache
.overlay_cache
);
860 const int num_mgrs
= ARRAY_SIZE(dss_cache
.manager_cache
);
870 mgr_busy
[0] = dispc_go_busy(0);
871 mgr_busy
[1] = dispc_go_busy(1);
875 /* Commit overlay settings */
876 for (i
= 0; i
< num_ovls
; ++i
) {
877 oc
= &dss_cache
.overlay_cache
[i
];
878 mc
= &dss_cache
.manager_cache
[oc
->channel
];
883 if (oc
->manual_update
&& !mc
->do_manual_update
)
886 if (mgr_busy
[oc
->channel
]) {
891 r
= configure_overlay(i
);
893 DSSERR("configure_overlay %d failed\n", i
);
896 oc
->shadow_dirty
= true;
897 mgr_go
[oc
->channel
] = true;
900 /* Commit manager settings */
901 for (i
= 0; i
< num_mgrs
; ++i
) {
902 mc
= &dss_cache
.manager_cache
[i
];
907 if (mc
->manual_update
&& !mc
->do_manual_update
)
915 configure_manager(i
);
917 mc
->shadow_dirty
= true;
922 for (i
= 0; i
< num_mgrs
; ++i
) {
923 mc
= &dss_cache
.manager_cache
[i
];
928 /* We don't need GO with manual update display. LCD iface will
929 * always be turned off after frame, and new settings will be
930 * taken in to use at next update */
931 if (!mc
->manual_upd_display
)
943 /* Configure dispc for partial update. Return possibly modified update
945 void dss_setup_partial_planes(struct omap_dss_device
*dssdev
,
946 u16
*xi
, u16
*yi
, u16
*wi
, u16
*hi
)
948 struct overlay_cache_data
*oc
;
949 struct manager_cache_data
*mc
;
950 const int num_ovls
= ARRAY_SIZE(dss_cache
.overlay_cache
);
951 struct omap_overlay_manager
*mgr
;
961 DSSDBG("dispc_setup_partial_planes %d,%d %dx%d\n",
964 mgr
= dssdev
->manager
;
967 DSSDBG("no manager\n");
971 spin_lock_irqsave(&dss_cache
.lock
, flags
);
973 /* We need to show the whole overlay if it is scaled. So look for
974 * those, and make the update area larger if found.
975 * Also mark the overlay cache dirty */
976 for (i
= 0; i
< num_ovls
; ++i
) {
977 unsigned x1
, y1
, x2
, y2
;
980 oc
= &dss_cache
.overlay_cache
[i
];
982 if (oc
->channel
!= mgr
->id
)
990 if (!dispc_is_overlay_scaled(oc
))
993 outw
= oc
->out_width
== 0 ? oc
->width
: oc
->out_width
;
994 outh
= oc
->out_height
== 0 ? oc
->height
: oc
->out_height
;
996 /* is the overlay outside the update region? */
997 if (!rectangle_intersects(x
, y
, w
, h
,
998 oc
->pos_x
, oc
->pos_y
,
1002 /* if the overlay totally inside the update region? */
1003 if (rectangle_subset(oc
->pos_x
, oc
->pos_y
, outw
, outh
,
1017 if ((x
+ w
) < (oc
->pos_x
+ outw
))
1018 x2
= oc
->pos_x
+ outw
;
1022 if ((y
+ h
) < (oc
->pos_y
+ outh
))
1023 y2
= oc
->pos_y
+ outh
;
1032 DSSDBG("changing upd area due to ovl(%d) scaling %d,%d %dx%d\n",
1036 mc
= &dss_cache
.manager_cache
[mgr
->id
];
1037 mc
->do_manual_update
= true;
1045 mc
->do_manual_update
= false;
1047 spin_unlock_irqrestore(&dss_cache
.lock
, flags
);
1055 void dss_start_update(struct omap_dss_device
*dssdev
)
1057 struct manager_cache_data
*mc
;
1058 struct overlay_cache_data
*oc
;
1059 const int num_ovls
= ARRAY_SIZE(dss_cache
.overlay_cache
);
1060 const int num_mgrs
= ARRAY_SIZE(dss_cache
.manager_cache
);
1061 struct omap_overlay_manager
*mgr
;
1064 mgr
= dssdev
->manager
;
1066 for (i
= 0; i
< num_ovls
; ++i
) {
1067 oc
= &dss_cache
.overlay_cache
[i
];
1068 if (oc
->channel
!= mgr
->id
)
1071 oc
->shadow_dirty
= false;
1074 for (i
= 0; i
< num_mgrs
; ++i
) {
1075 mc
= &dss_cache
.manager_cache
[i
];
1079 mc
->shadow_dirty
= false;
1082 dssdev
->manager
->enable(dssdev
->manager
);
1085 static void dss_apply_irq_handler(void *data
, u32 mask
)
1087 struct manager_cache_data
*mc
;
1088 struct overlay_cache_data
*oc
;
1089 const int num_ovls
= ARRAY_SIZE(dss_cache
.overlay_cache
);
1090 const int num_mgrs
= ARRAY_SIZE(dss_cache
.manager_cache
);
1094 mgr_busy
[0] = dispc_go_busy(0);
1095 mgr_busy
[1] = dispc_go_busy(1);
1097 spin_lock(&dss_cache
.lock
);
1099 for (i
= 0; i
< num_ovls
; ++i
) {
1100 oc
= &dss_cache
.overlay_cache
[i
];
1101 if (!mgr_busy
[oc
->channel
])
1102 oc
->shadow_dirty
= false;
1105 for (i
= 0; i
< num_mgrs
; ++i
) {
1106 mc
= &dss_cache
.manager_cache
[i
];
1108 mc
->shadow_dirty
= false;
1111 r
= configure_dispc();
1115 /* re-read busy flags */
1116 mgr_busy
[0] = dispc_go_busy(0);
1117 mgr_busy
[1] = dispc_go_busy(1);
1119 /* keep running as long as there are busy managers, so that
1120 * we can collect overlay-applied information */
1121 for (i
= 0; i
< num_mgrs
; ++i
) {
1126 omap_dispc_unregister_isr(dss_apply_irq_handler
, NULL
,
1127 DISPC_IRQ_VSYNC
| DISPC_IRQ_EVSYNC_ODD
|
1128 DISPC_IRQ_EVSYNC_EVEN
);
1129 dss_cache
.irq_enabled
= false;
1132 spin_unlock(&dss_cache
.lock
);
1135 static int omap_dss_mgr_apply(struct omap_overlay_manager
*mgr
)
1137 struct overlay_cache_data
*oc
;
1138 struct manager_cache_data
*mc
;
1140 struct omap_overlay
*ovl
;
1141 int num_planes_enabled
= 0;
1143 unsigned long flags
;
1146 DSSDBG("omap_dss_mgr_apply(%s)\n", mgr
->name
);
1148 spin_lock_irqsave(&dss_cache
.lock
, flags
);
1150 /* Configure overlays */
1151 for (i
= 0; i
< omap_dss_get_num_overlays(); ++i
) {
1152 struct omap_dss_device
*dssdev
;
1154 ovl
= omap_dss_get_overlay(i
);
1156 if (!(ovl
->caps
& OMAP_DSS_OVL_CAP_DISPC
))
1159 oc
= &dss_cache
.overlay_cache
[ovl
->id
];
1161 if (!overlay_enabled(ovl
)) {
1163 oc
->enabled
= false;
1169 if (!ovl
->info_dirty
) {
1171 ++num_planes_enabled
;
1175 dssdev
= ovl
->manager
->device
;
1177 if (dss_check_overlay(ovl
, dssdev
)) {
1179 oc
->enabled
= false;
1185 ovl
->info_dirty
= false;
1188 oc
->paddr
= ovl
->info
.paddr
;
1189 oc
->vaddr
= ovl
->info
.vaddr
;
1190 oc
->screen_width
= ovl
->info
.screen_width
;
1191 oc
->width
= ovl
->info
.width
;
1192 oc
->height
= ovl
->info
.height
;
1193 oc
->color_mode
= ovl
->info
.color_mode
;
1194 oc
->rotation
= ovl
->info
.rotation
;
1195 oc
->rotation_type
= ovl
->info
.rotation_type
;
1196 oc
->mirror
= ovl
->info
.mirror
;
1197 oc
->pos_x
= ovl
->info
.pos_x
;
1198 oc
->pos_y
= ovl
->info
.pos_y
;
1199 oc
->out_width
= ovl
->info
.out_width
;
1200 oc
->out_height
= ovl
->info
.out_height
;
1201 oc
->global_alpha
= ovl
->info
.global_alpha
;
1204 dss_use_replication(dssdev
, ovl
->info
.color_mode
);
1206 oc
->ilace
= dssdev
->type
== OMAP_DISPLAY_TYPE_VENC
;
1208 oc
->channel
= ovl
->manager
->id
;
1213 dssdev
->caps
& OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE
&&
1214 dssdev
->driver
->get_update_mode(dssdev
) !=
1215 OMAP_DSS_UPDATE_AUTO
;
1217 ++num_planes_enabled
;
1220 /* Configure managers */
1221 list_for_each_entry(mgr
, &manager_list
, list
) {
1222 struct omap_dss_device
*dssdev
;
1224 if (!(mgr
->caps
& OMAP_DSS_OVL_MGR_CAP_DISPC
))
1227 mc
= &dss_cache
.manager_cache
[mgr
->id
];
1229 if (mgr
->device_changed
) {
1230 mgr
->device_changed
= false;
1231 mgr
->info_dirty
= true;
1234 if (!mgr
->info_dirty
)
1240 dssdev
= mgr
->device
;
1242 mgr
->info_dirty
= false;
1245 mc
->default_color
= mgr
->info
.default_color
;
1246 mc
->trans_key_type
= mgr
->info
.trans_key_type
;
1247 mc
->trans_key
= mgr
->info
.trans_key
;
1248 mc
->trans_enabled
= mgr
->info
.trans_enabled
;
1249 mc
->alpha_enabled
= mgr
->info
.alpha_enabled
;
1251 mc
->manual_upd_display
=
1252 dssdev
->caps
& OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE
;
1255 dssdev
->caps
& OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE
&&
1256 dssdev
->driver
->get_update_mode(dssdev
) !=
1257 OMAP_DSS_UPDATE_AUTO
;
1260 /* XXX TODO: Try to get fifomerge working. The problem is that it
1261 * affects both managers, not individually but at the same time. This
1262 * means the change has to be well synchronized. I guess the proper way
1263 * is to have a two step process for fifo merge:
1265 * 1. disable other planes, leaving one plane enabled
1266 * 2. wait until the planes are disabled on HW
1267 * 3. config merged fifo thresholds, enable fifomerge
1268 * fifomerge disable:
1269 * 1. config unmerged fifo thresholds, disable fifomerge
1270 * 2. wait until fifo changes are in HW
1273 use_fifomerge
= false;
1275 /* Configure overlay fifos */
1276 for (i
= 0; i
< omap_dss_get_num_overlays(); ++i
) {
1277 struct omap_dss_device
*dssdev
;
1280 ovl
= omap_dss_get_overlay(i
);
1282 if (!(ovl
->caps
& OMAP_DSS_OVL_CAP_DISPC
))
1285 oc
= &dss_cache
.overlay_cache
[ovl
->id
];
1290 dssdev
= ovl
->manager
->device
;
1292 size
= dispc_get_plane_fifo_size(ovl
->id
);
1296 switch (dssdev
->type
) {
1297 case OMAP_DISPLAY_TYPE_DPI
:
1298 case OMAP_DISPLAY_TYPE_DBI
:
1299 case OMAP_DISPLAY_TYPE_SDI
:
1300 case OMAP_DISPLAY_TYPE_VENC
:
1301 default_get_overlay_fifo_thresholds(ovl
->id
, size
,
1302 &oc
->burst_size
, &oc
->fifo_low
,
1305 #ifdef CONFIG_OMAP2_DSS_DSI
1306 case OMAP_DISPLAY_TYPE_DSI
:
1307 dsi_get_overlay_fifo_thresholds(ovl
->id
, size
,
1308 &oc
->burst_size
, &oc
->fifo_low
,
1318 dss_clk_enable(DSS_CLK_ICK
| DSS_CLK_FCK1
);
1319 if (!dss_cache
.irq_enabled
) {
1320 r
= omap_dispc_register_isr(dss_apply_irq_handler
, NULL
,
1321 DISPC_IRQ_VSYNC
| DISPC_IRQ_EVSYNC_ODD
|
1322 DISPC_IRQ_EVSYNC_EVEN
);
1323 dss_cache
.irq_enabled
= true;
1326 dss_clk_disable(DSS_CLK_ICK
| DSS_CLK_FCK1
);
1328 spin_unlock_irqrestore(&dss_cache
.lock
, flags
);
1333 static int dss_check_manager(struct omap_overlay_manager
*mgr
)
1335 /* OMAP supports only graphics source transparency color key and alpha
1336 * blending simultaneously. See TRM 15.4.2.4.2.2 Alpha Mode */
1338 if (mgr
->info
.alpha_enabled
&& mgr
->info
.trans_enabled
&&
1339 mgr
->info
.trans_key_type
!= OMAP_DSS_COLOR_KEY_GFX_DST
)
1345 static int omap_dss_mgr_set_info(struct omap_overlay_manager
*mgr
,
1346 struct omap_overlay_manager_info
*info
)
1349 struct omap_overlay_manager_info old_info
;
1351 old_info
= mgr
->info
;
1354 r
= dss_check_manager(mgr
);
1356 mgr
->info
= old_info
;
1360 mgr
->info_dirty
= true;
1365 static void omap_dss_mgr_get_info(struct omap_overlay_manager
*mgr
,
1366 struct omap_overlay_manager_info
*info
)
1371 static int dss_mgr_enable(struct omap_overlay_manager
*mgr
)
1373 dispc_enable_channel(mgr
->id
, 1);
1377 static int dss_mgr_disable(struct omap_overlay_manager
*mgr
)
1379 dispc_enable_channel(mgr
->id
, 0);
1383 static void omap_dss_add_overlay_manager(struct omap_overlay_manager
*manager
)
1386 list_add_tail(&manager
->list
, &manager_list
);
1389 int dss_init_overlay_managers(struct platform_device
*pdev
)
1393 spin_lock_init(&dss_cache
.lock
);
1395 INIT_LIST_HEAD(&manager_list
);
1399 for (i
= 0; i
< 2; ++i
) {
1400 struct omap_overlay_manager
*mgr
;
1401 mgr
= kzalloc(sizeof(*mgr
), GFP_KERNEL
);
1403 BUG_ON(mgr
== NULL
);
1408 mgr
->id
= OMAP_DSS_CHANNEL_LCD
;
1409 mgr
->supported_displays
=
1410 OMAP_DISPLAY_TYPE_DPI
| OMAP_DISPLAY_TYPE_DBI
|
1411 OMAP_DISPLAY_TYPE_SDI
| OMAP_DISPLAY_TYPE_DSI
;
1415 mgr
->id
= OMAP_DSS_CHANNEL_DIGIT
;
1416 mgr
->supported_displays
= OMAP_DISPLAY_TYPE_VENC
;
1420 mgr
->set_device
= &omap_dss_set_device
;
1421 mgr
->unset_device
= &omap_dss_unset_device
;
1422 mgr
->apply
= &omap_dss_mgr_apply
;
1423 mgr
->set_manager_info
= &omap_dss_mgr_set_info
;
1424 mgr
->get_manager_info
= &omap_dss_mgr_get_info
;
1425 mgr
->wait_for_go
= &dss_mgr_wait_for_go
;
1426 mgr
->wait_for_vsync
= &dss_mgr_wait_for_vsync
;
1428 mgr
->enable
= &dss_mgr_enable
;
1429 mgr
->disable
= &dss_mgr_disable
;
1431 mgr
->caps
= OMAP_DSS_OVL_MGR_CAP_DISPC
;
1433 dss_overlay_setup_dispc_manager(mgr
);
1435 omap_dss_add_overlay_manager(mgr
);
1437 r
= kobject_init_and_add(&mgr
->kobj
, &manager_ktype
,
1438 &pdev
->dev
.kobj
, "manager%d", i
);
1441 DSSERR("failed to create sysfs file\n");
1448 int omap_dss_mgr_apply_l4(struct omap_overlay_manager
*mgr
)
1450 DSSDBG("omap_dss_mgr_apply_l4(%s)\n", mgr
->name
);
1455 struct omap_overlay_manager
*mgr
;
1456 mgr
= kzalloc(sizeof(*mgr
), GFP_KERNEL
);
1458 BUG_ON(mgr
== NULL
);
1461 mgr
->supported_displays
=
1462 OMAP_DISPLAY_TYPE_DBI
| OMAP_DISPLAY_TYPE_DSI
;
1464 mgr
->set_device
= &omap_dss_set_device
;
1465 mgr
->unset_device
= &omap_dss_unset_device
;
1466 mgr
->apply
= &omap_dss_mgr_apply_l4
;
1467 mgr
->set_manager_info
= &omap_dss_mgr_set_info
;
1468 mgr
->get_manager_info
= &omap_dss_mgr_get_info
;
1470 dss_overlay_setup_l4_manager(mgr
);
1472 omap_dss_add_overlay_manager(mgr
);
1474 r
= kobject_init_and_add(&mgr
->kobj
, &manager_ktype
,
1475 &pdev
->dev
.kobj
, "managerl4");
1478 DSSERR("failed to create sysfs file\n");
1485 void dss_uninit_overlay_managers(struct platform_device
*pdev
)
1487 struct omap_overlay_manager
*mgr
;
1489 while (!list_empty(&manager_list
)) {
1490 mgr
= list_first_entry(&manager_list
,
1491 struct omap_overlay_manager
, list
);
1492 list_del(&mgr
->list
);
1493 kobject_del(&mgr
->kobj
);
1494 kobject_put(&mgr
->kobj
);
1501 int omap_dss_get_num_overlay_managers(void)
1503 return num_managers
;
1505 EXPORT_SYMBOL(omap_dss_get_num_overlay_managers
);
1507 struct omap_overlay_manager
*omap_dss_get_overlay_manager(int num
)
1510 struct omap_overlay_manager
*mgr
;
1512 list_for_each_entry(mgr
, &manager_list
, list
) {
1519 EXPORT_SYMBOL(omap_dss_get_overlay_manager
);