2 * linux/drivers/video/omap2/dss/dispc.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 "DISPC"
25 #include <linux/kernel.h>
26 #include <linux/dma-mapping.h>
27 #include <linux/vmalloc.h>
28 #include <linux/export.h>
29 #include <linux/clk.h>
31 #include <linux/jiffies.h>
32 #include <linux/seq_file.h>
33 #include <linux/delay.h>
34 #include <linux/workqueue.h>
35 #include <linux/hardirq.h>
36 #include <linux/interrupt.h>
37 #include <linux/platform_device.h>
38 #include <linux/pm_runtime.h>
40 #include <plat/sram.h>
41 #include <plat/clock.h>
43 #include <video/omapdss.h>
46 #include "dss_features.h"
50 #define DISPC_SZ_REGS SZ_4K
52 #define DISPC_IRQ_MASK_ERROR (DISPC_IRQ_GFX_FIFO_UNDERFLOW | \
54 DISPC_IRQ_VID1_FIFO_UNDERFLOW | \
55 DISPC_IRQ_VID2_FIFO_UNDERFLOW | \
56 DISPC_IRQ_SYNC_LOST | \
57 DISPC_IRQ_SYNC_LOST_DIGIT)
59 #define DISPC_MAX_NR_ISRS 8
61 struct omap_dispc_isr_data
{
67 enum omap_burst_size
{
73 #define REG_GET(idx, start, end) \
74 FLD_GET(dispc_read_reg(idx), start, end)
76 #define REG_FLD_MOD(idx, val, start, end) \
77 dispc_write_reg(idx, FLD_MOD(dispc_read_reg(idx), val, start, end))
79 struct dispc_irq_stats
{
80 unsigned long last_reset
;
86 struct platform_device
*pdev
;
94 u32 fifo_size
[MAX_DSS_OVERLAYS
];
98 struct omap_dispc_isr_data registered_isr
[DISPC_MAX_NR_ISRS
];
100 struct work_struct error_work
;
103 u32 ctx
[DISPC_SZ_REGS
/ sizeof(u32
)];
105 #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
106 spinlock_t irq_stats_lock
;
107 struct dispc_irq_stats irq_stats
;
111 enum omap_color_component
{
112 /* used for all color formats for OMAP3 and earlier
113 * and for RGB and Y color component on OMAP4
115 DISPC_COLOR_COMPONENT_RGB_Y
= 1 << 0,
116 /* used for UV component for
117 * OMAP_DSS_COLOR_YUV2, OMAP_DSS_COLOR_UYVY, OMAP_DSS_COLOR_NV12
118 * color formats on OMAP4
120 DISPC_COLOR_COMPONENT_UV
= 1 << 1,
123 static void _omap_dispc_set_irqs(void);
125 static inline void dispc_write_reg(const u16 idx
, u32 val
)
127 __raw_writel(val
, dispc
.base
+ idx
);
130 static inline u32
dispc_read_reg(const u16 idx
)
132 return __raw_readl(dispc
.base
+ idx
);
135 static int dispc_get_ctx_loss_count(void)
137 struct device
*dev
= &dispc
.pdev
->dev
;
138 struct omap_display_platform_data
*pdata
= dev
->platform_data
;
139 struct omap_dss_board_info
*board_data
= pdata
->board_data
;
142 if (!board_data
->get_context_loss_count
)
145 cnt
= board_data
->get_context_loss_count(dev
);
147 WARN_ONCE(cnt
< 0, "get_context_loss_count failed: %d\n", cnt
);
153 dispc.ctx[DISPC_##reg / sizeof(u32)] = dispc_read_reg(DISPC_##reg)
155 dispc_write_reg(DISPC_##reg, dispc.ctx[DISPC_##reg / sizeof(u32)])
157 static void dispc_save_context(void)
161 DSSDBG("dispc_save_context\n");
167 if (dss_has_feature(FEAT_ALPHA_FIXED_ZORDER
) ||
168 dss_has_feature(FEAT_ALPHA_FREE_ZORDER
))
170 if (dss_has_feature(FEAT_MGR_LCD2
)) {
175 for (i
= 0; i
< dss_feat_get_num_mgrs(); i
++) {
176 SR(DEFAULT_COLOR(i
));
179 if (i
== OMAP_DSS_CHANNEL_DIGIT
)
190 if (dss_has_feature(FEAT_CPR
)) {
197 for (i
= 0; i
< dss_feat_get_num_ovls(); i
++) {
202 SR(OVL_ATTRIBUTES(i
));
203 SR(OVL_FIFO_THRESHOLD(i
));
205 SR(OVL_PIXEL_INC(i
));
206 if (dss_has_feature(FEAT_PRELOAD
))
208 if (i
== OMAP_DSS_GFX
) {
209 SR(OVL_WINDOW_SKIP(i
));
214 SR(OVL_PICTURE_SIZE(i
));
218 for (j
= 0; j
< 8; j
++)
219 SR(OVL_FIR_COEF_H(i
, j
));
221 for (j
= 0; j
< 8; j
++)
222 SR(OVL_FIR_COEF_HV(i
, j
));
224 for (j
= 0; j
< 5; j
++)
225 SR(OVL_CONV_COEF(i
, j
));
227 if (dss_has_feature(FEAT_FIR_COEF_V
)) {
228 for (j
= 0; j
< 8; j
++)
229 SR(OVL_FIR_COEF_V(i
, j
));
232 if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE
)) {
239 for (j
= 0; j
< 8; j
++)
240 SR(OVL_FIR_COEF_H2(i
, j
));
242 for (j
= 0; j
< 8; j
++)
243 SR(OVL_FIR_COEF_HV2(i
, j
));
245 for (j
= 0; j
< 8; j
++)
246 SR(OVL_FIR_COEF_V2(i
, j
));
248 if (dss_has_feature(FEAT_ATTR2
))
249 SR(OVL_ATTRIBUTES2(i
));
252 if (dss_has_feature(FEAT_CORE_CLK_DIV
))
255 dispc
.ctx_loss_cnt
= dispc_get_ctx_loss_count();
256 dispc
.ctx_valid
= true;
258 DSSDBG("context saved, ctx_loss_count %d\n", dispc
.ctx_loss_cnt
);
261 static void dispc_restore_context(void)
265 DSSDBG("dispc_restore_context\n");
267 if (!dispc
.ctx_valid
)
270 ctx
= dispc_get_ctx_loss_count();
272 if (ctx
>= 0 && ctx
== dispc
.ctx_loss_cnt
)
275 DSSDBG("ctx_loss_count: saved %d, current %d\n",
276 dispc
.ctx_loss_cnt
, ctx
);
282 if (dss_has_feature(FEAT_ALPHA_FIXED_ZORDER
) ||
283 dss_has_feature(FEAT_ALPHA_FREE_ZORDER
))
285 if (dss_has_feature(FEAT_MGR_LCD2
))
288 for (i
= 0; i
< dss_feat_get_num_mgrs(); i
++) {
289 RR(DEFAULT_COLOR(i
));
292 if (i
== OMAP_DSS_CHANNEL_DIGIT
)
303 if (dss_has_feature(FEAT_CPR
)) {
310 for (i
= 0; i
< dss_feat_get_num_ovls(); i
++) {
315 RR(OVL_ATTRIBUTES(i
));
316 RR(OVL_FIFO_THRESHOLD(i
));
318 RR(OVL_PIXEL_INC(i
));
319 if (dss_has_feature(FEAT_PRELOAD
))
321 if (i
== OMAP_DSS_GFX
) {
322 RR(OVL_WINDOW_SKIP(i
));
327 RR(OVL_PICTURE_SIZE(i
));
331 for (j
= 0; j
< 8; j
++)
332 RR(OVL_FIR_COEF_H(i
, j
));
334 for (j
= 0; j
< 8; j
++)
335 RR(OVL_FIR_COEF_HV(i
, j
));
337 for (j
= 0; j
< 5; j
++)
338 RR(OVL_CONV_COEF(i
, j
));
340 if (dss_has_feature(FEAT_FIR_COEF_V
)) {
341 for (j
= 0; j
< 8; j
++)
342 RR(OVL_FIR_COEF_V(i
, j
));
345 if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE
)) {
352 for (j
= 0; j
< 8; j
++)
353 RR(OVL_FIR_COEF_H2(i
, j
));
355 for (j
= 0; j
< 8; j
++)
356 RR(OVL_FIR_COEF_HV2(i
, j
));
358 for (j
= 0; j
< 8; j
++)
359 RR(OVL_FIR_COEF_V2(i
, j
));
361 if (dss_has_feature(FEAT_ATTR2
))
362 RR(OVL_ATTRIBUTES2(i
));
365 if (dss_has_feature(FEAT_CORE_CLK_DIV
))
368 /* enable last, because LCD & DIGIT enable are here */
370 if (dss_has_feature(FEAT_MGR_LCD2
))
372 /* clear spurious SYNC_LOST_DIGIT interrupts */
373 dispc_write_reg(DISPC_IRQSTATUS
, DISPC_IRQ_SYNC_LOST_DIGIT
);
376 * enable last so IRQs won't trigger before
377 * the context is fully restored
381 DSSDBG("context restored\n");
387 int dispc_runtime_get(void)
391 DSSDBG("dispc_runtime_get\n");
393 r
= pm_runtime_get_sync(&dispc
.pdev
->dev
);
395 return r
< 0 ? r
: 0;
398 void dispc_runtime_put(void)
402 DSSDBG("dispc_runtime_put\n");
404 r
= pm_runtime_put_sync(&dispc
.pdev
->dev
);
408 static inline bool dispc_mgr_is_lcd(enum omap_channel channel
)
410 if (channel
== OMAP_DSS_CHANNEL_LCD
||
411 channel
== OMAP_DSS_CHANNEL_LCD2
)
417 static struct omap_dss_device
*dispc_mgr_get_device(enum omap_channel channel
)
419 struct omap_overlay_manager
*mgr
=
420 omap_dss_get_overlay_manager(channel
);
422 return mgr
? mgr
->device
: NULL
;
425 u32
dispc_mgr_get_vsync_irq(enum omap_channel channel
)
428 case OMAP_DSS_CHANNEL_LCD
:
429 return DISPC_IRQ_VSYNC
;
430 case OMAP_DSS_CHANNEL_LCD2
:
431 return DISPC_IRQ_VSYNC2
;
432 case OMAP_DSS_CHANNEL_DIGIT
:
433 return DISPC_IRQ_EVSYNC_ODD
| DISPC_IRQ_EVSYNC_EVEN
;
439 u32
dispc_mgr_get_framedone_irq(enum omap_channel channel
)
442 case OMAP_DSS_CHANNEL_LCD
:
443 return DISPC_IRQ_FRAMEDONE
;
444 case OMAP_DSS_CHANNEL_LCD2
:
445 return DISPC_IRQ_FRAMEDONE2
;
446 case OMAP_DSS_CHANNEL_DIGIT
:
453 bool dispc_mgr_go_busy(enum omap_channel channel
)
457 if (dispc_mgr_is_lcd(channel
))
460 bit
= 6; /* GODIGIT */
462 if (channel
== OMAP_DSS_CHANNEL_LCD2
)
463 return REG_GET(DISPC_CONTROL2
, bit
, bit
) == 1;
465 return REG_GET(DISPC_CONTROL
, bit
, bit
) == 1;
468 void dispc_mgr_go(enum omap_channel channel
)
471 bool enable_bit
, go_bit
;
473 if (dispc_mgr_is_lcd(channel
))
474 bit
= 0; /* LCDENABLE */
476 bit
= 1; /* DIGITALENABLE */
478 /* if the channel is not enabled, we don't need GO */
479 if (channel
== OMAP_DSS_CHANNEL_LCD2
)
480 enable_bit
= REG_GET(DISPC_CONTROL2
, bit
, bit
) == 1;
482 enable_bit
= REG_GET(DISPC_CONTROL
, bit
, bit
) == 1;
487 if (dispc_mgr_is_lcd(channel
))
490 bit
= 6; /* GODIGIT */
492 if (channel
== OMAP_DSS_CHANNEL_LCD2
)
493 go_bit
= REG_GET(DISPC_CONTROL2
, bit
, bit
) == 1;
495 go_bit
= REG_GET(DISPC_CONTROL
, bit
, bit
) == 1;
498 DSSERR("GO bit not down for channel %d\n", channel
);
502 DSSDBG("GO %s\n", channel
== OMAP_DSS_CHANNEL_LCD
? "LCD" :
503 (channel
== OMAP_DSS_CHANNEL_LCD2
? "LCD2" : "DIGIT"));
505 if (channel
== OMAP_DSS_CHANNEL_LCD2
)
506 REG_FLD_MOD(DISPC_CONTROL2
, 1, bit
, bit
);
508 REG_FLD_MOD(DISPC_CONTROL
, 1, bit
, bit
);
511 static void dispc_ovl_write_firh_reg(enum omap_plane plane
, int reg
, u32 value
)
513 dispc_write_reg(DISPC_OVL_FIR_COEF_H(plane
, reg
), value
);
516 static void dispc_ovl_write_firhv_reg(enum omap_plane plane
, int reg
, u32 value
)
518 dispc_write_reg(DISPC_OVL_FIR_COEF_HV(plane
, reg
), value
);
521 static void dispc_ovl_write_firv_reg(enum omap_plane plane
, int reg
, u32 value
)
523 dispc_write_reg(DISPC_OVL_FIR_COEF_V(plane
, reg
), value
);
526 static void dispc_ovl_write_firh2_reg(enum omap_plane plane
, int reg
, u32 value
)
528 BUG_ON(plane
== OMAP_DSS_GFX
);
530 dispc_write_reg(DISPC_OVL_FIR_COEF_H2(plane
, reg
), value
);
533 static void dispc_ovl_write_firhv2_reg(enum omap_plane plane
, int reg
,
536 BUG_ON(plane
== OMAP_DSS_GFX
);
538 dispc_write_reg(DISPC_OVL_FIR_COEF_HV2(plane
, reg
), value
);
541 static void dispc_ovl_write_firv2_reg(enum omap_plane plane
, int reg
, u32 value
)
543 BUG_ON(plane
== OMAP_DSS_GFX
);
545 dispc_write_reg(DISPC_OVL_FIR_COEF_V2(plane
, reg
), value
);
548 static void dispc_ovl_set_scale_coef(enum omap_plane plane
, int fir_hinc
,
549 int fir_vinc
, int five_taps
,
550 enum omap_color_component color_comp
)
552 const struct dispc_coef
*h_coef
, *v_coef
;
555 h_coef
= dispc_ovl_get_scale_coef(fir_hinc
, true);
556 v_coef
= dispc_ovl_get_scale_coef(fir_vinc
, five_taps
);
558 for (i
= 0; i
< 8; i
++) {
561 h
= FLD_VAL(h_coef
[i
].hc0_vc00
, 7, 0)
562 | FLD_VAL(h_coef
[i
].hc1_vc0
, 15, 8)
563 | FLD_VAL(h_coef
[i
].hc2_vc1
, 23, 16)
564 | FLD_VAL(h_coef
[i
].hc3_vc2
, 31, 24);
565 hv
= FLD_VAL(h_coef
[i
].hc4_vc22
, 7, 0)
566 | FLD_VAL(v_coef
[i
].hc1_vc0
, 15, 8)
567 | FLD_VAL(v_coef
[i
].hc2_vc1
, 23, 16)
568 | FLD_VAL(v_coef
[i
].hc3_vc2
, 31, 24);
570 if (color_comp
== DISPC_COLOR_COMPONENT_RGB_Y
) {
571 dispc_ovl_write_firh_reg(plane
, i
, h
);
572 dispc_ovl_write_firhv_reg(plane
, i
, hv
);
574 dispc_ovl_write_firh2_reg(plane
, i
, h
);
575 dispc_ovl_write_firhv2_reg(plane
, i
, hv
);
581 for (i
= 0; i
< 8; i
++) {
583 v
= FLD_VAL(v_coef
[i
].hc0_vc00
, 7, 0)
584 | FLD_VAL(v_coef
[i
].hc4_vc22
, 15, 8);
585 if (color_comp
== DISPC_COLOR_COMPONENT_RGB_Y
)
586 dispc_ovl_write_firv_reg(plane
, i
, v
);
588 dispc_ovl_write_firv2_reg(plane
, i
, v
);
593 static void _dispc_setup_color_conv_coef(void)
596 const struct color_conv_coef
{
597 int ry
, rcr
, rcb
, gy
, gcr
, gcb
, by
, bcr
, bcb
;
600 298, 409, 0, 298, -208, -100, 298, 0, 517, 0,
603 const struct color_conv_coef
*ct
;
605 #define CVAL(x, y) (FLD_VAL(x, 26, 16) | FLD_VAL(y, 10, 0))
609 for (i
= 1; i
< dss_feat_get_num_ovls(); i
++) {
610 dispc_write_reg(DISPC_OVL_CONV_COEF(i
, 0),
611 CVAL(ct
->rcr
, ct
->ry
));
612 dispc_write_reg(DISPC_OVL_CONV_COEF(i
, 1),
613 CVAL(ct
->gy
, ct
->rcb
));
614 dispc_write_reg(DISPC_OVL_CONV_COEF(i
, 2),
615 CVAL(ct
->gcb
, ct
->gcr
));
616 dispc_write_reg(DISPC_OVL_CONV_COEF(i
, 3),
617 CVAL(ct
->bcr
, ct
->by
));
618 dispc_write_reg(DISPC_OVL_CONV_COEF(i
, 4),
621 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(i
), ct
->full_range
,
629 static void dispc_ovl_set_ba0(enum omap_plane plane
, u32 paddr
)
631 dispc_write_reg(DISPC_OVL_BA0(plane
), paddr
);
634 static void dispc_ovl_set_ba1(enum omap_plane plane
, u32 paddr
)
636 dispc_write_reg(DISPC_OVL_BA1(plane
), paddr
);
639 static void dispc_ovl_set_ba0_uv(enum omap_plane plane
, u32 paddr
)
641 dispc_write_reg(DISPC_OVL_BA0_UV(plane
), paddr
);
644 static void dispc_ovl_set_ba1_uv(enum omap_plane plane
, u32 paddr
)
646 dispc_write_reg(DISPC_OVL_BA1_UV(plane
), paddr
);
649 static void dispc_ovl_set_pos(enum omap_plane plane
, int x
, int y
)
651 u32 val
= FLD_VAL(y
, 26, 16) | FLD_VAL(x
, 10, 0);
653 dispc_write_reg(DISPC_OVL_POSITION(plane
), val
);
656 static void dispc_ovl_set_pic_size(enum omap_plane plane
, int width
, int height
)
658 u32 val
= FLD_VAL(height
- 1, 26, 16) | FLD_VAL(width
- 1, 10, 0);
660 if (plane
== OMAP_DSS_GFX
)
661 dispc_write_reg(DISPC_OVL_SIZE(plane
), val
);
663 dispc_write_reg(DISPC_OVL_PICTURE_SIZE(plane
), val
);
666 static void dispc_ovl_set_vid_size(enum omap_plane plane
, int width
, int height
)
670 BUG_ON(plane
== OMAP_DSS_GFX
);
672 val
= FLD_VAL(height
- 1, 26, 16) | FLD_VAL(width
- 1, 10, 0);
674 dispc_write_reg(DISPC_OVL_SIZE(plane
), val
);
677 static void dispc_ovl_set_zorder(enum omap_plane plane
, u8 zorder
)
679 struct omap_overlay
*ovl
= omap_dss_get_overlay(plane
);
681 if ((ovl
->caps
& OMAP_DSS_OVL_CAP_ZORDER
) == 0)
684 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane
), zorder
, 27, 26);
687 static void dispc_ovl_enable_zorder_planes(void)
691 if (!dss_has_feature(FEAT_ALPHA_FREE_ZORDER
))
694 for (i
= 0; i
< dss_feat_get_num_ovls(); i
++)
695 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(i
), 1, 25, 25);
698 static void dispc_ovl_set_pre_mult_alpha(enum omap_plane plane
, bool enable
)
700 struct omap_overlay
*ovl
= omap_dss_get_overlay(plane
);
702 if ((ovl
->caps
& OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA
) == 0)
705 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane
), enable
? 1 : 0, 28, 28);
708 static void dispc_ovl_setup_global_alpha(enum omap_plane plane
, u8 global_alpha
)
710 static const unsigned shifts
[] = { 0, 8, 16, 24, };
712 struct omap_overlay
*ovl
= omap_dss_get_overlay(plane
);
714 if ((ovl
->caps
& OMAP_DSS_OVL_CAP_GLOBAL_ALPHA
) == 0)
717 shift
= shifts
[plane
];
718 REG_FLD_MOD(DISPC_GLOBAL_ALPHA
, global_alpha
, shift
+ 7, shift
);
721 static void dispc_ovl_set_pix_inc(enum omap_plane plane
, s32 inc
)
723 dispc_write_reg(DISPC_OVL_PIXEL_INC(plane
), inc
);
726 static void dispc_ovl_set_row_inc(enum omap_plane plane
, s32 inc
)
728 dispc_write_reg(DISPC_OVL_ROW_INC(plane
), inc
);
731 static void dispc_ovl_set_color_mode(enum omap_plane plane
,
732 enum omap_color_mode color_mode
)
735 if (plane
!= OMAP_DSS_GFX
) {
736 switch (color_mode
) {
737 case OMAP_DSS_COLOR_NV12
:
739 case OMAP_DSS_COLOR_RGB12U
:
741 case OMAP_DSS_COLOR_RGBA16
:
743 case OMAP_DSS_COLOR_RGBX16
:
745 case OMAP_DSS_COLOR_ARGB16
:
747 case OMAP_DSS_COLOR_RGB16
:
749 case OMAP_DSS_COLOR_ARGB16_1555
:
751 case OMAP_DSS_COLOR_RGB24U
:
753 case OMAP_DSS_COLOR_RGB24P
:
755 case OMAP_DSS_COLOR_YUV2
:
757 case OMAP_DSS_COLOR_UYVY
:
759 case OMAP_DSS_COLOR_ARGB32
:
761 case OMAP_DSS_COLOR_RGBA32
:
763 case OMAP_DSS_COLOR_RGBX32
:
765 case OMAP_DSS_COLOR_XRGB16_1555
:
771 switch (color_mode
) {
772 case OMAP_DSS_COLOR_CLUT1
:
774 case OMAP_DSS_COLOR_CLUT2
:
776 case OMAP_DSS_COLOR_CLUT4
:
778 case OMAP_DSS_COLOR_CLUT8
:
780 case OMAP_DSS_COLOR_RGB12U
:
782 case OMAP_DSS_COLOR_ARGB16
:
784 case OMAP_DSS_COLOR_RGB16
:
786 case OMAP_DSS_COLOR_ARGB16_1555
:
788 case OMAP_DSS_COLOR_RGB24U
:
790 case OMAP_DSS_COLOR_RGB24P
:
792 case OMAP_DSS_COLOR_YUV2
:
794 case OMAP_DSS_COLOR_UYVY
:
796 case OMAP_DSS_COLOR_ARGB32
:
798 case OMAP_DSS_COLOR_RGBA32
:
800 case OMAP_DSS_COLOR_RGBX32
:
802 case OMAP_DSS_COLOR_XRGB16_1555
:
809 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane
), m
, 4, 1);
812 void dispc_ovl_set_channel_out(enum omap_plane plane
, enum omap_channel channel
)
816 int chan
= 0, chan2
= 0;
822 case OMAP_DSS_VIDEO1
:
823 case OMAP_DSS_VIDEO2
:
824 case OMAP_DSS_VIDEO3
:
832 val
= dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane
));
833 if (dss_has_feature(FEAT_MGR_LCD2
)) {
835 case OMAP_DSS_CHANNEL_LCD
:
839 case OMAP_DSS_CHANNEL_DIGIT
:
843 case OMAP_DSS_CHANNEL_LCD2
:
851 val
= FLD_MOD(val
, chan
, shift
, shift
);
852 val
= FLD_MOD(val
, chan2
, 31, 30);
854 val
= FLD_MOD(val
, channel
, shift
, shift
);
856 dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane
), val
);
859 static enum omap_channel
dispc_ovl_get_channel_out(enum omap_plane plane
)
863 enum omap_channel channel
;
869 case OMAP_DSS_VIDEO1
:
870 case OMAP_DSS_VIDEO2
:
871 case OMAP_DSS_VIDEO3
:
878 val
= dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane
));
880 if (dss_has_feature(FEAT_MGR_LCD2
)) {
881 if (FLD_GET(val
, 31, 30) == 0)
882 channel
= FLD_GET(val
, shift
, shift
);
884 channel
= OMAP_DSS_CHANNEL_LCD2
;
886 channel
= FLD_GET(val
, shift
, shift
);
892 static void dispc_ovl_set_burst_size(enum omap_plane plane
,
893 enum omap_burst_size burst_size
)
895 static const unsigned shifts
[] = { 6, 14, 14, 14, };
898 shift
= shifts
[plane
];
899 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane
), burst_size
, shift
+ 1, shift
);
902 static void dispc_configure_burst_sizes(void)
905 const int burst_size
= BURST_SIZE_X8
;
907 /* Configure burst size always to maximum size */
908 for (i
= 0; i
< omap_dss_get_num_overlays(); ++i
)
909 dispc_ovl_set_burst_size(i
, burst_size
);
912 u32
dispc_ovl_get_burst_size(enum omap_plane plane
)
914 unsigned unit
= dss_feat_get_burst_size_unit();
915 /* burst multiplier is always x8 (see dispc_configure_burst_sizes()) */
919 void dispc_enable_gamma_table(bool enable
)
922 * This is partially implemented to support only disabling of
926 DSSWARN("Gamma table enabling for TV not yet supported");
930 REG_FLD_MOD(DISPC_CONFIG
, enable
, 9, 9);
933 static void dispc_mgr_enable_cpr(enum omap_channel channel
, bool enable
)
937 if (channel
== OMAP_DSS_CHANNEL_LCD
)
939 else if (channel
== OMAP_DSS_CHANNEL_LCD2
)
944 REG_FLD_MOD(reg
, enable
, 15, 15);
947 static void dispc_mgr_set_cpr_coef(enum omap_channel channel
,
948 struct omap_dss_cpr_coefs
*coefs
)
950 u32 coef_r
, coef_g
, coef_b
;
952 if (!dispc_mgr_is_lcd(channel
))
955 coef_r
= FLD_VAL(coefs
->rr
, 31, 22) | FLD_VAL(coefs
->rg
, 20, 11) |
956 FLD_VAL(coefs
->rb
, 9, 0);
957 coef_g
= FLD_VAL(coefs
->gr
, 31, 22) | FLD_VAL(coefs
->gg
, 20, 11) |
958 FLD_VAL(coefs
->gb
, 9, 0);
959 coef_b
= FLD_VAL(coefs
->br
, 31, 22) | FLD_VAL(coefs
->bg
, 20, 11) |
960 FLD_VAL(coefs
->bb
, 9, 0);
962 dispc_write_reg(DISPC_CPR_COEF_R(channel
), coef_r
);
963 dispc_write_reg(DISPC_CPR_COEF_G(channel
), coef_g
);
964 dispc_write_reg(DISPC_CPR_COEF_B(channel
), coef_b
);
967 static void dispc_ovl_set_vid_color_conv(enum omap_plane plane
, bool enable
)
971 BUG_ON(plane
== OMAP_DSS_GFX
);
973 val
= dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane
));
974 val
= FLD_MOD(val
, enable
, 9, 9);
975 dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane
), val
);
978 static void dispc_ovl_enable_replication(enum omap_plane plane
, bool enable
)
980 static const unsigned shifts
[] = { 5, 10, 10, 10 };
983 shift
= shifts
[plane
];
984 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane
), enable
, shift
, shift
);
987 void dispc_mgr_set_lcd_size(enum omap_channel channel
, u16 width
, u16 height
)
990 BUG_ON((width
> (1 << 11)) || (height
> (1 << 11)));
991 val
= FLD_VAL(height
- 1, 26, 16) | FLD_VAL(width
- 1, 10, 0);
992 dispc_write_reg(DISPC_SIZE_MGR(channel
), val
);
995 void dispc_set_digit_size(u16 width
, u16 height
)
998 BUG_ON((width
> (1 << 11)) || (height
> (1 << 11)));
999 val
= FLD_VAL(height
- 1, 26, 16) | FLD_VAL(width
- 1, 10, 0);
1000 dispc_write_reg(DISPC_SIZE_MGR(OMAP_DSS_CHANNEL_DIGIT
), val
);
1003 static void dispc_read_plane_fifo_sizes(void)
1010 unit
= dss_feat_get_buffer_size_unit();
1012 dss_feat_get_reg_field(FEAT_REG_FIFOSIZE
, &start
, &end
);
1014 for (plane
= 0; plane
< dss_feat_get_num_ovls(); ++plane
) {
1015 size
= REG_GET(DISPC_OVL_FIFO_SIZE_STATUS(plane
), start
, end
);
1017 dispc
.fifo_size
[plane
] = size
;
1021 u32
dispc_ovl_get_fifo_size(enum omap_plane plane
)
1023 return dispc
.fifo_size
[plane
];
1026 void dispc_ovl_set_fifo_threshold(enum omap_plane plane
, u32 low
, u32 high
)
1028 u8 hi_start
, hi_end
, lo_start
, lo_end
;
1031 unit
= dss_feat_get_buffer_size_unit();
1033 WARN_ON(low
% unit
!= 0);
1034 WARN_ON(high
% unit
!= 0);
1039 dss_feat_get_reg_field(FEAT_REG_FIFOHIGHTHRESHOLD
, &hi_start
, &hi_end
);
1040 dss_feat_get_reg_field(FEAT_REG_FIFOLOWTHRESHOLD
, &lo_start
, &lo_end
);
1042 DSSDBG("fifo(%d) low/high old %u/%u, new %u/%u\n",
1044 REG_GET(DISPC_OVL_FIFO_THRESHOLD(plane
),
1046 REG_GET(DISPC_OVL_FIFO_THRESHOLD(plane
),
1050 dispc_write_reg(DISPC_OVL_FIFO_THRESHOLD(plane
),
1051 FLD_VAL(high
, hi_start
, hi_end
) |
1052 FLD_VAL(low
, lo_start
, lo_end
));
1055 void dispc_enable_fifomerge(bool enable
)
1057 DSSDBG("FIFO merge %s\n", enable
? "enabled" : "disabled");
1058 REG_FLD_MOD(DISPC_CONFIG
, enable
? 1 : 0, 14, 14);
1061 static void dispc_ovl_set_fir(enum omap_plane plane
,
1063 enum omap_color_component color_comp
)
1067 if (color_comp
== DISPC_COLOR_COMPONENT_RGB_Y
) {
1068 u8 hinc_start
, hinc_end
, vinc_start
, vinc_end
;
1070 dss_feat_get_reg_field(FEAT_REG_FIRHINC
,
1071 &hinc_start
, &hinc_end
);
1072 dss_feat_get_reg_field(FEAT_REG_FIRVINC
,
1073 &vinc_start
, &vinc_end
);
1074 val
= FLD_VAL(vinc
, vinc_start
, vinc_end
) |
1075 FLD_VAL(hinc
, hinc_start
, hinc_end
);
1077 dispc_write_reg(DISPC_OVL_FIR(plane
), val
);
1079 val
= FLD_VAL(vinc
, 28, 16) | FLD_VAL(hinc
, 12, 0);
1080 dispc_write_reg(DISPC_OVL_FIR2(plane
), val
);
1084 static void dispc_ovl_set_vid_accu0(enum omap_plane plane
, int haccu
, int vaccu
)
1087 u8 hor_start
, hor_end
, vert_start
, vert_end
;
1089 dss_feat_get_reg_field(FEAT_REG_HORIZONTALACCU
, &hor_start
, &hor_end
);
1090 dss_feat_get_reg_field(FEAT_REG_VERTICALACCU
, &vert_start
, &vert_end
);
1092 val
= FLD_VAL(vaccu
, vert_start
, vert_end
) |
1093 FLD_VAL(haccu
, hor_start
, hor_end
);
1095 dispc_write_reg(DISPC_OVL_ACCU0(plane
), val
);
1098 static void dispc_ovl_set_vid_accu1(enum omap_plane plane
, int haccu
, int vaccu
)
1101 u8 hor_start
, hor_end
, vert_start
, vert_end
;
1103 dss_feat_get_reg_field(FEAT_REG_HORIZONTALACCU
, &hor_start
, &hor_end
);
1104 dss_feat_get_reg_field(FEAT_REG_VERTICALACCU
, &vert_start
, &vert_end
);
1106 val
= FLD_VAL(vaccu
, vert_start
, vert_end
) |
1107 FLD_VAL(haccu
, hor_start
, hor_end
);
1109 dispc_write_reg(DISPC_OVL_ACCU1(plane
), val
);
1112 static void dispc_ovl_set_vid_accu2_0(enum omap_plane plane
, int haccu
,
1117 val
= FLD_VAL(vaccu
, 26, 16) | FLD_VAL(haccu
, 10, 0);
1118 dispc_write_reg(DISPC_OVL_ACCU2_0(plane
), val
);
1121 static void dispc_ovl_set_vid_accu2_1(enum omap_plane plane
, int haccu
,
1126 val
= FLD_VAL(vaccu
, 26, 16) | FLD_VAL(haccu
, 10, 0);
1127 dispc_write_reg(DISPC_OVL_ACCU2_1(plane
), val
);
1130 static void dispc_ovl_set_scale_param(enum omap_plane plane
,
1131 u16 orig_width
, u16 orig_height
,
1132 u16 out_width
, u16 out_height
,
1133 bool five_taps
, u8 rotation
,
1134 enum omap_color_component color_comp
)
1136 int fir_hinc
, fir_vinc
;
1138 fir_hinc
= 1024 * orig_width
/ out_width
;
1139 fir_vinc
= 1024 * orig_height
/ out_height
;
1141 dispc_ovl_set_scale_coef(plane
, fir_hinc
, fir_vinc
, five_taps
,
1143 dispc_ovl_set_fir(plane
, fir_hinc
, fir_vinc
, color_comp
);
1146 static void dispc_ovl_set_scaling_common(enum omap_plane plane
,
1147 u16 orig_width
, u16 orig_height
,
1148 u16 out_width
, u16 out_height
,
1149 bool ilace
, bool five_taps
,
1150 bool fieldmode
, enum omap_color_mode color_mode
,
1157 dispc_ovl_set_scale_param(plane
, orig_width
, orig_height
,
1158 out_width
, out_height
, five_taps
,
1159 rotation
, DISPC_COLOR_COMPONENT_RGB_Y
);
1160 l
= dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane
));
1162 /* RESIZEENABLE and VERTICALTAPS */
1163 l
&= ~((0x3 << 5) | (0x1 << 21));
1164 l
|= (orig_width
!= out_width
) ? (1 << 5) : 0;
1165 l
|= (orig_height
!= out_height
) ? (1 << 6) : 0;
1166 l
|= five_taps
? (1 << 21) : 0;
1168 /* VRESIZECONF and HRESIZECONF */
1169 if (dss_has_feature(FEAT_RESIZECONF
)) {
1171 l
|= (orig_width
<= out_width
) ? 0 : (1 << 7);
1172 l
|= (orig_height
<= out_height
) ? 0 : (1 << 8);
1175 /* LINEBUFFERSPLIT */
1176 if (dss_has_feature(FEAT_LINEBUFFERSPLIT
)) {
1178 l
|= five_taps
? (1 << 22) : 0;
1181 dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane
), l
);
1184 * field 0 = even field = bottom field
1185 * field 1 = odd field = top field
1187 if (ilace
&& !fieldmode
) {
1189 accu0
= ((1024 * orig_height
/ out_height
) / 2) & 0x3ff;
1190 if (accu0
>= 1024/2) {
1196 dispc_ovl_set_vid_accu0(plane
, 0, accu0
);
1197 dispc_ovl_set_vid_accu1(plane
, 0, accu1
);
1200 static void dispc_ovl_set_scaling_uv(enum omap_plane plane
,
1201 u16 orig_width
, u16 orig_height
,
1202 u16 out_width
, u16 out_height
,
1203 bool ilace
, bool five_taps
,
1204 bool fieldmode
, enum omap_color_mode color_mode
,
1207 int scale_x
= out_width
!= orig_width
;
1208 int scale_y
= out_height
!= orig_height
;
1210 if (!dss_has_feature(FEAT_HANDLE_UV_SEPARATE
))
1212 if ((color_mode
!= OMAP_DSS_COLOR_YUV2
&&
1213 color_mode
!= OMAP_DSS_COLOR_UYVY
&&
1214 color_mode
!= OMAP_DSS_COLOR_NV12
)) {
1215 /* reset chroma resampling for RGB formats */
1216 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES2(plane
), 0, 8, 8);
1219 switch (color_mode
) {
1220 case OMAP_DSS_COLOR_NV12
:
1221 /* UV is subsampled by 2 vertically*/
1223 /* UV is subsampled by 2 horz.*/
1226 case OMAP_DSS_COLOR_YUV2
:
1227 case OMAP_DSS_COLOR_UYVY
:
1228 /*For YUV422 with 90/270 rotation,
1229 *we don't upsample chroma
1231 if (rotation
== OMAP_DSS_ROT_0
||
1232 rotation
== OMAP_DSS_ROT_180
)
1233 /* UV is subsampled by 2 hrz*/
1235 /* must use FIR for YUV422 if rotated */
1236 if (rotation
!= OMAP_DSS_ROT_0
)
1237 scale_x
= scale_y
= true;
1243 if (out_width
!= orig_width
)
1245 if (out_height
!= orig_height
)
1248 dispc_ovl_set_scale_param(plane
, orig_width
, orig_height
,
1249 out_width
, out_height
, five_taps
,
1250 rotation
, DISPC_COLOR_COMPONENT_UV
);
1252 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES2(plane
),
1253 (scale_x
|| scale_y
) ? 1 : 0, 8, 8);
1255 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane
), scale_x
? 1 : 0, 5, 5);
1257 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane
), scale_y
? 1 : 0, 6, 6);
1259 dispc_ovl_set_vid_accu2_0(plane
, 0x80, 0);
1260 dispc_ovl_set_vid_accu2_1(plane
, 0x80, 0);
1263 static void dispc_ovl_set_scaling(enum omap_plane plane
,
1264 u16 orig_width
, u16 orig_height
,
1265 u16 out_width
, u16 out_height
,
1266 bool ilace
, bool five_taps
,
1267 bool fieldmode
, enum omap_color_mode color_mode
,
1270 BUG_ON(plane
== OMAP_DSS_GFX
);
1272 dispc_ovl_set_scaling_common(plane
,
1273 orig_width
, orig_height
,
1274 out_width
, out_height
,
1276 fieldmode
, color_mode
,
1279 dispc_ovl_set_scaling_uv(plane
,
1280 orig_width
, orig_height
,
1281 out_width
, out_height
,
1283 fieldmode
, color_mode
,
1287 static void dispc_ovl_set_rotation_attrs(enum omap_plane plane
, u8 rotation
,
1288 bool mirroring
, enum omap_color_mode color_mode
)
1290 bool row_repeat
= false;
1293 if (color_mode
== OMAP_DSS_COLOR_YUV2
||
1294 color_mode
== OMAP_DSS_COLOR_UYVY
) {
1298 case OMAP_DSS_ROT_0
:
1301 case OMAP_DSS_ROT_90
:
1304 case OMAP_DSS_ROT_180
:
1307 case OMAP_DSS_ROT_270
:
1313 case OMAP_DSS_ROT_0
:
1316 case OMAP_DSS_ROT_90
:
1319 case OMAP_DSS_ROT_180
:
1322 case OMAP_DSS_ROT_270
:
1328 if (rotation
== OMAP_DSS_ROT_90
|| rotation
== OMAP_DSS_ROT_270
)
1334 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane
), vidrot
, 13, 12);
1335 if (dss_has_feature(FEAT_ROWREPEATENABLE
))
1336 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane
),
1337 row_repeat
? 1 : 0, 18, 18);
1340 static int color_mode_to_bpp(enum omap_color_mode color_mode
)
1342 switch (color_mode
) {
1343 case OMAP_DSS_COLOR_CLUT1
:
1345 case OMAP_DSS_COLOR_CLUT2
:
1347 case OMAP_DSS_COLOR_CLUT4
:
1349 case OMAP_DSS_COLOR_CLUT8
:
1350 case OMAP_DSS_COLOR_NV12
:
1352 case OMAP_DSS_COLOR_RGB12U
:
1353 case OMAP_DSS_COLOR_RGB16
:
1354 case OMAP_DSS_COLOR_ARGB16
:
1355 case OMAP_DSS_COLOR_YUV2
:
1356 case OMAP_DSS_COLOR_UYVY
:
1357 case OMAP_DSS_COLOR_RGBA16
:
1358 case OMAP_DSS_COLOR_RGBX16
:
1359 case OMAP_DSS_COLOR_ARGB16_1555
:
1360 case OMAP_DSS_COLOR_XRGB16_1555
:
1362 case OMAP_DSS_COLOR_RGB24P
:
1364 case OMAP_DSS_COLOR_RGB24U
:
1365 case OMAP_DSS_COLOR_ARGB32
:
1366 case OMAP_DSS_COLOR_RGBA32
:
1367 case OMAP_DSS_COLOR_RGBX32
:
1374 static s32
pixinc(int pixels
, u8 ps
)
1378 else if (pixels
> 1)
1379 return 1 + (pixels
- 1) * ps
;
1380 else if (pixels
< 0)
1381 return 1 - (-pixels
+ 1) * ps
;
1386 static void calc_vrfb_rotation_offset(u8 rotation
, bool mirror
,
1388 u16 width
, u16 height
,
1389 enum omap_color_mode color_mode
, bool fieldmode
,
1390 unsigned int field_offset
,
1391 unsigned *offset0
, unsigned *offset1
,
1392 s32
*row_inc
, s32
*pix_inc
)
1396 /* FIXME CLUT formats */
1397 switch (color_mode
) {
1398 case OMAP_DSS_COLOR_CLUT1
:
1399 case OMAP_DSS_COLOR_CLUT2
:
1400 case OMAP_DSS_COLOR_CLUT4
:
1401 case OMAP_DSS_COLOR_CLUT8
:
1404 case OMAP_DSS_COLOR_YUV2
:
1405 case OMAP_DSS_COLOR_UYVY
:
1409 ps
= color_mode_to_bpp(color_mode
) / 8;
1413 DSSDBG("calc_rot(%d): scrw %d, %dx%d\n", rotation
, screen_width
,
1417 * field 0 = even field = bottom field
1418 * field 1 = odd field = top field
1420 switch (rotation
+ mirror
* 4) {
1421 case OMAP_DSS_ROT_0
:
1422 case OMAP_DSS_ROT_180
:
1424 * If the pixel format is YUV or UYVY divide the width
1425 * of the image by 2 for 0 and 180 degree rotation.
1427 if (color_mode
== OMAP_DSS_COLOR_YUV2
||
1428 color_mode
== OMAP_DSS_COLOR_UYVY
)
1430 case OMAP_DSS_ROT_90
:
1431 case OMAP_DSS_ROT_270
:
1434 *offset0
= field_offset
* screen_width
* ps
;
1438 *row_inc
= pixinc(1 + (screen_width
- width
) +
1439 (fieldmode
? screen_width
: 0),
1441 *pix_inc
= pixinc(1, ps
);
1444 case OMAP_DSS_ROT_0
+ 4:
1445 case OMAP_DSS_ROT_180
+ 4:
1446 /* If the pixel format is YUV or UYVY divide the width
1447 * of the image by 2 for 0 degree and 180 degree
1449 if (color_mode
== OMAP_DSS_COLOR_YUV2
||
1450 color_mode
== OMAP_DSS_COLOR_UYVY
)
1452 case OMAP_DSS_ROT_90
+ 4:
1453 case OMAP_DSS_ROT_270
+ 4:
1456 *offset0
= field_offset
* screen_width
* ps
;
1459 *row_inc
= pixinc(1 - (screen_width
+ width
) -
1460 (fieldmode
? screen_width
: 0),
1462 *pix_inc
= pixinc(1, ps
);
1470 static void calc_dma_rotation_offset(u8 rotation
, bool mirror
,
1472 u16 width
, u16 height
,
1473 enum omap_color_mode color_mode
, bool fieldmode
,
1474 unsigned int field_offset
,
1475 unsigned *offset0
, unsigned *offset1
,
1476 s32
*row_inc
, s32
*pix_inc
)
1481 /* FIXME CLUT formats */
1482 switch (color_mode
) {
1483 case OMAP_DSS_COLOR_CLUT1
:
1484 case OMAP_DSS_COLOR_CLUT2
:
1485 case OMAP_DSS_COLOR_CLUT4
:
1486 case OMAP_DSS_COLOR_CLUT8
:
1490 ps
= color_mode_to_bpp(color_mode
) / 8;
1494 DSSDBG("calc_rot(%d): scrw %d, %dx%d\n", rotation
, screen_width
,
1497 /* width & height are overlay sizes, convert to fb sizes */
1499 if (rotation
== OMAP_DSS_ROT_0
|| rotation
== OMAP_DSS_ROT_180
) {
1508 * field 0 = even field = bottom field
1509 * field 1 = odd field = top field
1511 switch (rotation
+ mirror
* 4) {
1512 case OMAP_DSS_ROT_0
:
1515 *offset0
= *offset1
+ field_offset
* screen_width
* ps
;
1517 *offset0
= *offset1
;
1518 *row_inc
= pixinc(1 + (screen_width
- fbw
) +
1519 (fieldmode
? screen_width
: 0),
1521 *pix_inc
= pixinc(1, ps
);
1523 case OMAP_DSS_ROT_90
:
1524 *offset1
= screen_width
* (fbh
- 1) * ps
;
1526 *offset0
= *offset1
+ field_offset
* ps
;
1528 *offset0
= *offset1
;
1529 *row_inc
= pixinc(screen_width
* (fbh
- 1) + 1 +
1530 (fieldmode
? 1 : 0), ps
);
1531 *pix_inc
= pixinc(-screen_width
, ps
);
1533 case OMAP_DSS_ROT_180
:
1534 *offset1
= (screen_width
* (fbh
- 1) + fbw
- 1) * ps
;
1536 *offset0
= *offset1
- field_offset
* screen_width
* ps
;
1538 *offset0
= *offset1
;
1539 *row_inc
= pixinc(-1 -
1540 (screen_width
- fbw
) -
1541 (fieldmode
? screen_width
: 0),
1543 *pix_inc
= pixinc(-1, ps
);
1545 case OMAP_DSS_ROT_270
:
1546 *offset1
= (fbw
- 1) * ps
;
1548 *offset0
= *offset1
- field_offset
* ps
;
1550 *offset0
= *offset1
;
1551 *row_inc
= pixinc(-screen_width
* (fbh
- 1) - 1 -
1552 (fieldmode
? 1 : 0), ps
);
1553 *pix_inc
= pixinc(screen_width
, ps
);
1557 case OMAP_DSS_ROT_0
+ 4:
1558 *offset1
= (fbw
- 1) * ps
;
1560 *offset0
= *offset1
+ field_offset
* screen_width
* ps
;
1562 *offset0
= *offset1
;
1563 *row_inc
= pixinc(screen_width
* 2 - 1 +
1564 (fieldmode
? screen_width
: 0),
1566 *pix_inc
= pixinc(-1, ps
);
1569 case OMAP_DSS_ROT_90
+ 4:
1572 *offset0
= *offset1
+ field_offset
* ps
;
1574 *offset0
= *offset1
;
1575 *row_inc
= pixinc(-screen_width
* (fbh
- 1) + 1 +
1576 (fieldmode
? 1 : 0),
1578 *pix_inc
= pixinc(screen_width
, ps
);
1581 case OMAP_DSS_ROT_180
+ 4:
1582 *offset1
= screen_width
* (fbh
- 1) * ps
;
1584 *offset0
= *offset1
- field_offset
* screen_width
* ps
;
1586 *offset0
= *offset1
;
1587 *row_inc
= pixinc(1 - screen_width
* 2 -
1588 (fieldmode
? screen_width
: 0),
1590 *pix_inc
= pixinc(1, ps
);
1593 case OMAP_DSS_ROT_270
+ 4:
1594 *offset1
= (screen_width
* (fbh
- 1) + fbw
- 1) * ps
;
1596 *offset0
= *offset1
- field_offset
* ps
;
1598 *offset0
= *offset1
;
1599 *row_inc
= pixinc(screen_width
* (fbh
- 1) - 1 -
1600 (fieldmode
? 1 : 0),
1602 *pix_inc
= pixinc(-screen_width
, ps
);
1610 static unsigned long calc_fclk_five_taps(enum omap_channel channel
, u16 width
,
1611 u16 height
, u16 out_width
, u16 out_height
,
1612 enum omap_color_mode color_mode
)
1615 u64 tmp
, pclk
= dispc_mgr_pclk_rate(channel
);
1617 if (height
<= out_height
&& width
<= out_width
)
1618 return (unsigned long) pclk
;
1620 if (height
> out_height
) {
1621 struct omap_dss_device
*dssdev
= dispc_mgr_get_device(channel
);
1622 unsigned int ppl
= dssdev
->panel
.timings
.x_res
;
1624 tmp
= pclk
* height
* out_width
;
1625 do_div(tmp
, 2 * out_height
* ppl
);
1628 if (height
> 2 * out_height
) {
1629 if (ppl
== out_width
)
1632 tmp
= pclk
* (height
- 2 * out_height
) * out_width
;
1633 do_div(tmp
, 2 * out_height
* (ppl
- out_width
));
1634 fclk
= max(fclk
, (u32
) tmp
);
1638 if (width
> out_width
) {
1640 do_div(tmp
, out_width
);
1641 fclk
= max(fclk
, (u32
) tmp
);
1643 if (color_mode
== OMAP_DSS_COLOR_RGB24U
)
1650 static unsigned long calc_fclk(enum omap_channel channel
, u16 width
,
1651 u16 height
, u16 out_width
, u16 out_height
)
1653 unsigned int hf
, vf
;
1656 * FIXME how to determine the 'A' factor
1657 * for the no downscaling case ?
1660 if (width
> 3 * out_width
)
1662 else if (width
> 2 * out_width
)
1664 else if (width
> out_width
)
1669 if (height
> out_height
)
1674 if (cpu_is_omap24xx()) {
1675 if (vf
> 1 && hf
> 1)
1676 return dispc_mgr_pclk_rate(channel
) * 4;
1678 return dispc_mgr_pclk_rate(channel
) * 2;
1679 } else if (cpu_is_omap34xx()) {
1680 return dispc_mgr_pclk_rate(channel
) * vf
* hf
;
1682 return dispc_mgr_pclk_rate(channel
) * hf
;
1686 static int dispc_ovl_calc_scaling(enum omap_plane plane
,
1687 enum omap_channel channel
, u16 width
, u16 height
,
1688 u16 out_width
, u16 out_height
,
1689 enum omap_color_mode color_mode
, bool *five_taps
)
1691 struct omap_overlay
*ovl
= omap_dss_get_overlay(plane
);
1692 const int maxdownscale
= dss_feat_get_param_max(FEAT_PARAM_DOWNSCALE
);
1693 const int maxsinglelinewidth
=
1694 dss_feat_get_param_max(FEAT_PARAM_LINEWIDTH
);
1695 unsigned long fclk
= 0;
1697 if (width
== out_width
&& height
== out_height
)
1700 if ((ovl
->caps
& OMAP_DSS_OVL_CAP_SCALE
) == 0)
1703 if (out_width
< width
/ maxdownscale
||
1704 out_width
> width
* 8)
1707 if (out_height
< height
/ maxdownscale
||
1708 out_height
> height
* 8)
1711 if (cpu_is_omap24xx()) {
1712 if (width
> maxsinglelinewidth
)
1713 DSSERR("Cannot scale max input width exceeded");
1715 fclk
= calc_fclk(channel
, width
, height
, out_width
,
1717 } else if (cpu_is_omap34xx()) {
1718 if (width
> (maxsinglelinewidth
* 2)) {
1719 DSSERR("Cannot setup scaling");
1720 DSSERR("width exceeds maximum width possible");
1723 fclk
= calc_fclk_five_taps(channel
, width
, height
, out_width
,
1724 out_height
, color_mode
);
1725 if (width
> maxsinglelinewidth
) {
1726 if (height
> out_height
&& height
< out_height
* 2)
1729 DSSERR("cannot setup scaling with five taps");
1734 fclk
= calc_fclk(channel
, width
, height
, out_width
,
1737 if (width
> maxsinglelinewidth
) {
1738 DSSERR("Cannot scale width exceeds max line width");
1741 fclk
= calc_fclk(channel
, width
, height
, out_width
,
1745 DSSDBG("required fclk rate = %lu Hz\n", fclk
);
1746 DSSDBG("current fclk rate = %lu Hz\n", dispc_fclk_rate());
1748 if (!fclk
|| fclk
> dispc_fclk_rate()) {
1749 DSSERR("failed to set up scaling, "
1750 "required fclk rate = %lu Hz, "
1751 "current fclk rate = %lu Hz\n",
1752 fclk
, dispc_fclk_rate());
1759 int dispc_ovl_setup(enum omap_plane plane
, struct omap_overlay_info
*oi
,
1760 bool ilace
, bool replication
)
1762 struct omap_overlay
*ovl
= omap_dss_get_overlay(plane
);
1763 bool five_taps
= true;
1766 unsigned offset0
, offset1
;
1769 u16 frame_height
= oi
->height
;
1770 unsigned int field_offset
= 0;
1772 enum omap_channel channel
;
1774 channel
= dispc_ovl_get_channel_out(plane
);
1776 DSSDBG("dispc_ovl_setup %d, pa %x, pa_uv %x, sw %d, %d,%d, %dx%d -> "
1777 "%dx%d, cmode %x, rot %d, mir %d, ilace %d chan %d repl %d\n",
1778 plane
, oi
->paddr
, oi
->p_uv_addr
,
1779 oi
->screen_width
, oi
->pos_x
, oi
->pos_y
, oi
->width
, oi
->height
,
1780 oi
->out_width
, oi
->out_height
, oi
->color_mode
, oi
->rotation
,
1781 oi
->mirror
, ilace
, channel
, replication
);
1786 outw
= oi
->out_width
== 0 ? oi
->width
: oi
->out_width
;
1787 outh
= oi
->out_height
== 0 ? oi
->height
: oi
->out_height
;
1789 if (ilace
&& oi
->height
== outh
)
1798 DSSDBG("adjusting for ilace: height %d, pos_y %d, "
1800 oi
->height
, oi
->pos_y
, outh
);
1803 if (!dss_feat_color_mode_supported(plane
, oi
->color_mode
))
1806 r
= dispc_ovl_calc_scaling(plane
, channel
, oi
->width
, oi
->height
,
1807 outw
, outh
, oi
->color_mode
,
1812 if (oi
->color_mode
== OMAP_DSS_COLOR_YUV2
||
1813 oi
->color_mode
== OMAP_DSS_COLOR_UYVY
||
1814 oi
->color_mode
== OMAP_DSS_COLOR_NV12
)
1817 if (ilace
&& !fieldmode
) {
1819 * when downscaling the bottom field may have to start several
1820 * source lines below the top field. Unfortunately ACCUI
1821 * registers will only hold the fractional part of the offset
1822 * so the integer part must be added to the base address of the
1825 if (!oi
->height
|| oi
->height
== outh
)
1828 field_offset
= oi
->height
/ outh
/ 2;
1831 /* Fields are independent but interleaved in memory. */
1835 if (oi
->rotation_type
== OMAP_DSS_ROT_DMA
)
1836 calc_dma_rotation_offset(oi
->rotation
, oi
->mirror
,
1837 oi
->screen_width
, oi
->width
, frame_height
,
1838 oi
->color_mode
, fieldmode
, field_offset
,
1839 &offset0
, &offset1
, &row_inc
, &pix_inc
);
1841 calc_vrfb_rotation_offset(oi
->rotation
, oi
->mirror
,
1842 oi
->screen_width
, oi
->width
, frame_height
,
1843 oi
->color_mode
, fieldmode
, field_offset
,
1844 &offset0
, &offset1
, &row_inc
, &pix_inc
);
1846 DSSDBG("offset0 %u, offset1 %u, row_inc %d, pix_inc %d\n",
1847 offset0
, offset1
, row_inc
, pix_inc
);
1849 dispc_ovl_set_color_mode(plane
, oi
->color_mode
);
1851 dispc_ovl_set_ba0(plane
, oi
->paddr
+ offset0
);
1852 dispc_ovl_set_ba1(plane
, oi
->paddr
+ offset1
);
1854 if (OMAP_DSS_COLOR_NV12
== oi
->color_mode
) {
1855 dispc_ovl_set_ba0_uv(plane
, oi
->p_uv_addr
+ offset0
);
1856 dispc_ovl_set_ba1_uv(plane
, oi
->p_uv_addr
+ offset1
);
1860 dispc_ovl_set_row_inc(plane
, row_inc
);
1861 dispc_ovl_set_pix_inc(plane
, pix_inc
);
1863 DSSDBG("%d,%d %dx%d -> %dx%d\n", oi
->pos_x
, oi
->pos_y
, oi
->width
,
1864 oi
->height
, outw
, outh
);
1866 dispc_ovl_set_pos(plane
, oi
->pos_x
, oi
->pos_y
);
1868 dispc_ovl_set_pic_size(plane
, oi
->width
, oi
->height
);
1870 if (ovl
->caps
& OMAP_DSS_OVL_CAP_SCALE
) {
1871 dispc_ovl_set_scaling(plane
, oi
->width
, oi
->height
,
1873 ilace
, five_taps
, fieldmode
,
1874 oi
->color_mode
, oi
->rotation
);
1875 dispc_ovl_set_vid_size(plane
, outw
, outh
);
1876 dispc_ovl_set_vid_color_conv(plane
, cconv
);
1879 dispc_ovl_set_rotation_attrs(plane
, oi
->rotation
, oi
->mirror
,
1882 dispc_ovl_set_zorder(plane
, oi
->zorder
);
1883 dispc_ovl_set_pre_mult_alpha(plane
, oi
->pre_mult_alpha
);
1884 dispc_ovl_setup_global_alpha(plane
, oi
->global_alpha
);
1886 dispc_ovl_enable_replication(plane
, replication
);
1891 int dispc_ovl_enable(enum omap_plane plane
, bool enable
)
1893 DSSDBG("dispc_enable_plane %d, %d\n", plane
, enable
);
1895 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane
), enable
? 1 : 0, 0, 0);
1900 static void dispc_disable_isr(void *data
, u32 mask
)
1902 struct completion
*compl = data
;
1906 static void _enable_lcd_out(enum omap_channel channel
, bool enable
)
1908 if (channel
== OMAP_DSS_CHANNEL_LCD2
) {
1909 REG_FLD_MOD(DISPC_CONTROL2
, enable
? 1 : 0, 0, 0);
1910 /* flush posted write */
1911 dispc_read_reg(DISPC_CONTROL2
);
1913 REG_FLD_MOD(DISPC_CONTROL
, enable
? 1 : 0, 0, 0);
1914 dispc_read_reg(DISPC_CONTROL
);
1918 static void dispc_mgr_enable_lcd_out(enum omap_channel channel
, bool enable
)
1920 struct completion frame_done_completion
;
1925 /* When we disable LCD output, we need to wait until frame is done.
1926 * Otherwise the DSS is still working, and turning off the clocks
1927 * prevents DSS from going to OFF mode */
1928 is_on
= channel
== OMAP_DSS_CHANNEL_LCD2
?
1929 REG_GET(DISPC_CONTROL2
, 0, 0) :
1930 REG_GET(DISPC_CONTROL
, 0, 0);
1932 irq
= channel
== OMAP_DSS_CHANNEL_LCD2
? DISPC_IRQ_FRAMEDONE2
:
1933 DISPC_IRQ_FRAMEDONE
;
1935 if (!enable
&& is_on
) {
1936 init_completion(&frame_done_completion
);
1938 r
= omap_dispc_register_isr(dispc_disable_isr
,
1939 &frame_done_completion
, irq
);
1942 DSSERR("failed to register FRAMEDONE isr\n");
1945 _enable_lcd_out(channel
, enable
);
1947 if (!enable
&& is_on
) {
1948 if (!wait_for_completion_timeout(&frame_done_completion
,
1949 msecs_to_jiffies(100)))
1950 DSSERR("timeout waiting for FRAME DONE\n");
1952 r
= omap_dispc_unregister_isr(dispc_disable_isr
,
1953 &frame_done_completion
, irq
);
1956 DSSERR("failed to unregister FRAMEDONE isr\n");
1960 static void _enable_digit_out(bool enable
)
1962 REG_FLD_MOD(DISPC_CONTROL
, enable
? 1 : 0, 1, 1);
1963 /* flush posted write */
1964 dispc_read_reg(DISPC_CONTROL
);
1967 static void dispc_mgr_enable_digit_out(bool enable
)
1969 struct completion frame_done_completion
;
1970 enum dss_hdmi_venc_clk_source_select src
;
1975 if (REG_GET(DISPC_CONTROL
, 1, 1) == enable
)
1978 src
= dss_get_hdmi_venc_clk_source();
1981 unsigned long flags
;
1982 /* When we enable digit output, we'll get an extra digit
1983 * sync lost interrupt, that we need to ignore */
1984 spin_lock_irqsave(&dispc
.irq_lock
, flags
);
1985 dispc
.irq_error_mask
&= ~DISPC_IRQ_SYNC_LOST_DIGIT
;
1986 _omap_dispc_set_irqs();
1987 spin_unlock_irqrestore(&dispc
.irq_lock
, flags
);
1990 /* When we disable digit output, we need to wait until fields are done.
1991 * Otherwise the DSS is still working, and turning off the clocks
1992 * prevents DSS from going to OFF mode. And when enabling, we need to
1993 * wait for the extra sync losts */
1994 init_completion(&frame_done_completion
);
1996 if (src
== DSS_HDMI_M_PCLK
&& enable
== false) {
1997 irq_mask
= DISPC_IRQ_FRAMEDONETV
;
2000 irq_mask
= DISPC_IRQ_EVSYNC_EVEN
| DISPC_IRQ_EVSYNC_ODD
;
2001 /* XXX I understand from TRM that we should only wait for the
2002 * current field to complete. But it seems we have to wait for
2007 r
= omap_dispc_register_isr(dispc_disable_isr
, &frame_done_completion
,
2010 DSSERR("failed to register %x isr\n", irq_mask
);
2012 _enable_digit_out(enable
);
2014 for (i
= 0; i
< num_irqs
; ++i
) {
2015 if (!wait_for_completion_timeout(&frame_done_completion
,
2016 msecs_to_jiffies(100)))
2017 DSSERR("timeout waiting for digit out to %s\n",
2018 enable
? "start" : "stop");
2021 r
= omap_dispc_unregister_isr(dispc_disable_isr
, &frame_done_completion
,
2024 DSSERR("failed to unregister %x isr\n", irq_mask
);
2027 unsigned long flags
;
2028 spin_lock_irqsave(&dispc
.irq_lock
, flags
);
2029 dispc
.irq_error_mask
|= DISPC_IRQ_SYNC_LOST_DIGIT
;
2030 dispc_write_reg(DISPC_IRQSTATUS
, DISPC_IRQ_SYNC_LOST_DIGIT
);
2031 _omap_dispc_set_irqs();
2032 spin_unlock_irqrestore(&dispc
.irq_lock
, flags
);
2036 bool dispc_mgr_is_enabled(enum omap_channel channel
)
2038 if (channel
== OMAP_DSS_CHANNEL_LCD
)
2039 return !!REG_GET(DISPC_CONTROL
, 0, 0);
2040 else if (channel
== OMAP_DSS_CHANNEL_DIGIT
)
2041 return !!REG_GET(DISPC_CONTROL
, 1, 1);
2042 else if (channel
== OMAP_DSS_CHANNEL_LCD2
)
2043 return !!REG_GET(DISPC_CONTROL2
, 0, 0);
2048 void dispc_mgr_enable(enum omap_channel channel
, bool enable
)
2050 if (dispc_mgr_is_lcd(channel
))
2051 dispc_mgr_enable_lcd_out(channel
, enable
);
2052 else if (channel
== OMAP_DSS_CHANNEL_DIGIT
)
2053 dispc_mgr_enable_digit_out(enable
);
2058 void dispc_lcd_enable_signal_polarity(bool act_high
)
2060 if (!dss_has_feature(FEAT_LCDENABLEPOL
))
2063 REG_FLD_MOD(DISPC_CONTROL
, act_high
? 1 : 0, 29, 29);
2066 void dispc_lcd_enable_signal(bool enable
)
2068 if (!dss_has_feature(FEAT_LCDENABLESIGNAL
))
2071 REG_FLD_MOD(DISPC_CONTROL
, enable
? 1 : 0, 28, 28);
2074 void dispc_pck_free_enable(bool enable
)
2076 if (!dss_has_feature(FEAT_PCKFREEENABLE
))
2079 REG_FLD_MOD(DISPC_CONTROL
, enable
? 1 : 0, 27, 27);
2082 void dispc_mgr_enable_fifohandcheck(enum omap_channel channel
, bool enable
)
2084 if (channel
== OMAP_DSS_CHANNEL_LCD2
)
2085 REG_FLD_MOD(DISPC_CONFIG2
, enable
? 1 : 0, 16, 16);
2087 REG_FLD_MOD(DISPC_CONFIG
, enable
? 1 : 0, 16, 16);
2091 void dispc_mgr_set_lcd_display_type(enum omap_channel channel
,
2092 enum omap_lcd_display_type type
)
2097 case OMAP_DSS_LCD_DISPLAY_STN
:
2101 case OMAP_DSS_LCD_DISPLAY_TFT
:
2110 if (channel
== OMAP_DSS_CHANNEL_LCD2
)
2111 REG_FLD_MOD(DISPC_CONTROL2
, mode
, 3, 3);
2113 REG_FLD_MOD(DISPC_CONTROL
, mode
, 3, 3);
2116 void dispc_set_loadmode(enum omap_dss_load_mode mode
)
2118 REG_FLD_MOD(DISPC_CONFIG
, mode
, 2, 1);
2122 static void dispc_mgr_set_default_color(enum omap_channel channel
, u32 color
)
2124 dispc_write_reg(DISPC_DEFAULT_COLOR(channel
), color
);
2127 static void dispc_mgr_set_trans_key(enum omap_channel ch
,
2128 enum omap_dss_trans_key_type type
,
2131 if (ch
== OMAP_DSS_CHANNEL_LCD
)
2132 REG_FLD_MOD(DISPC_CONFIG
, type
, 11, 11);
2133 else if (ch
== OMAP_DSS_CHANNEL_DIGIT
)
2134 REG_FLD_MOD(DISPC_CONFIG
, type
, 13, 13);
2135 else /* OMAP_DSS_CHANNEL_LCD2 */
2136 REG_FLD_MOD(DISPC_CONFIG2
, type
, 11, 11);
2138 dispc_write_reg(DISPC_TRANS_COLOR(ch
), trans_key
);
2141 static void dispc_mgr_enable_trans_key(enum omap_channel ch
, bool enable
)
2143 if (ch
== OMAP_DSS_CHANNEL_LCD
)
2144 REG_FLD_MOD(DISPC_CONFIG
, enable
, 10, 10);
2145 else if (ch
== OMAP_DSS_CHANNEL_DIGIT
)
2146 REG_FLD_MOD(DISPC_CONFIG
, enable
, 12, 12);
2147 else /* OMAP_DSS_CHANNEL_LCD2 */
2148 REG_FLD_MOD(DISPC_CONFIG2
, enable
, 10, 10);
2151 static void dispc_mgr_enable_alpha_fixed_zorder(enum omap_channel ch
,
2154 if (!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER
))
2157 if (ch
== OMAP_DSS_CHANNEL_LCD
)
2158 REG_FLD_MOD(DISPC_CONFIG
, enable
, 18, 18);
2159 else if (ch
== OMAP_DSS_CHANNEL_DIGIT
)
2160 REG_FLD_MOD(DISPC_CONFIG
, enable
, 19, 19);
2163 void dispc_mgr_setup(enum omap_channel channel
,
2164 struct omap_overlay_manager_info
*info
)
2166 dispc_mgr_set_default_color(channel
, info
->default_color
);
2167 dispc_mgr_set_trans_key(channel
, info
->trans_key_type
, info
->trans_key
);
2168 dispc_mgr_enable_trans_key(channel
, info
->trans_enabled
);
2169 dispc_mgr_enable_alpha_fixed_zorder(channel
,
2170 info
->partial_alpha_enabled
);
2171 if (dss_has_feature(FEAT_CPR
)) {
2172 dispc_mgr_enable_cpr(channel
, info
->cpr_enable
);
2173 dispc_mgr_set_cpr_coef(channel
, &info
->cpr_coefs
);
2177 void dispc_mgr_set_tft_data_lines(enum omap_channel channel
, u8 data_lines
)
2181 switch (data_lines
) {
2199 if (channel
== OMAP_DSS_CHANNEL_LCD2
)
2200 REG_FLD_MOD(DISPC_CONTROL2
, code
, 9, 8);
2202 REG_FLD_MOD(DISPC_CONTROL
, code
, 9, 8);
2205 void dispc_mgr_set_io_pad_mode(enum dss_io_pad_mode mode
)
2211 case DSS_IO_PAD_MODE_RESET
:
2215 case DSS_IO_PAD_MODE_RFBI
:
2219 case DSS_IO_PAD_MODE_BYPASS
:
2228 l
= dispc_read_reg(DISPC_CONTROL
);
2229 l
= FLD_MOD(l
, gpout0
, 15, 15);
2230 l
= FLD_MOD(l
, gpout1
, 16, 16);
2231 dispc_write_reg(DISPC_CONTROL
, l
);
2234 void dispc_mgr_enable_stallmode(enum omap_channel channel
, bool enable
)
2236 if (channel
== OMAP_DSS_CHANNEL_LCD2
)
2237 REG_FLD_MOD(DISPC_CONTROL2
, enable
, 11, 11);
2239 REG_FLD_MOD(DISPC_CONTROL
, enable
, 11, 11);
2242 static bool _dispc_lcd_timings_ok(int hsw
, int hfp
, int hbp
,
2243 int vsw
, int vfp
, int vbp
)
2245 if (cpu_is_omap24xx() || omap_rev() < OMAP3430_REV_ES3_0
) {
2246 if (hsw
< 1 || hsw
> 64 ||
2247 hfp
< 1 || hfp
> 256 ||
2248 hbp
< 1 || hbp
> 256 ||
2249 vsw
< 1 || vsw
> 64 ||
2250 vfp
< 0 || vfp
> 255 ||
2251 vbp
< 0 || vbp
> 255)
2254 if (hsw
< 1 || hsw
> 256 ||
2255 hfp
< 1 || hfp
> 4096 ||
2256 hbp
< 1 || hbp
> 4096 ||
2257 vsw
< 1 || vsw
> 256 ||
2258 vfp
< 0 || vfp
> 4095 ||
2259 vbp
< 0 || vbp
> 4095)
2266 bool dispc_lcd_timings_ok(struct omap_video_timings
*timings
)
2268 return _dispc_lcd_timings_ok(timings
->hsw
, timings
->hfp
,
2269 timings
->hbp
, timings
->vsw
,
2270 timings
->vfp
, timings
->vbp
);
2273 static void _dispc_mgr_set_lcd_timings(enum omap_channel channel
, int hsw
,
2274 int hfp
, int hbp
, int vsw
, int vfp
, int vbp
)
2276 u32 timing_h
, timing_v
;
2278 if (cpu_is_omap24xx() || omap_rev() < OMAP3430_REV_ES3_0
) {
2279 timing_h
= FLD_VAL(hsw
-1, 5, 0) | FLD_VAL(hfp
-1, 15, 8) |
2280 FLD_VAL(hbp
-1, 27, 20);
2282 timing_v
= FLD_VAL(vsw
-1, 5, 0) | FLD_VAL(vfp
, 15, 8) |
2283 FLD_VAL(vbp
, 27, 20);
2285 timing_h
= FLD_VAL(hsw
-1, 7, 0) | FLD_VAL(hfp
-1, 19, 8) |
2286 FLD_VAL(hbp
-1, 31, 20);
2288 timing_v
= FLD_VAL(vsw
-1, 7, 0) | FLD_VAL(vfp
, 19, 8) |
2289 FLD_VAL(vbp
, 31, 20);
2292 dispc_write_reg(DISPC_TIMING_H(channel
), timing_h
);
2293 dispc_write_reg(DISPC_TIMING_V(channel
), timing_v
);
2296 /* change name to mode? */
2297 void dispc_mgr_set_lcd_timings(enum omap_channel channel
,
2298 struct omap_video_timings
*timings
)
2300 unsigned xtot
, ytot
;
2301 unsigned long ht
, vt
;
2303 if (!_dispc_lcd_timings_ok(timings
->hsw
, timings
->hfp
,
2304 timings
->hbp
, timings
->vsw
,
2305 timings
->vfp
, timings
->vbp
))
2308 _dispc_mgr_set_lcd_timings(channel
, timings
->hsw
, timings
->hfp
,
2309 timings
->hbp
, timings
->vsw
, timings
->vfp
,
2312 dispc_mgr_set_lcd_size(channel
, timings
->x_res
, timings
->y_res
);
2314 xtot
= timings
->x_res
+ timings
->hfp
+ timings
->hsw
+ timings
->hbp
;
2315 ytot
= timings
->y_res
+ timings
->vfp
+ timings
->vsw
+ timings
->vbp
;
2317 ht
= (timings
->pixel_clock
* 1000) / xtot
;
2318 vt
= (timings
->pixel_clock
* 1000) / xtot
/ ytot
;
2320 DSSDBG("channel %d xres %u yres %u\n", channel
, timings
->x_res
,
2322 DSSDBG("pck %u\n", timings
->pixel_clock
);
2323 DSSDBG("hsw %d hfp %d hbp %d vsw %d vfp %d vbp %d\n",
2324 timings
->hsw
, timings
->hfp
, timings
->hbp
,
2325 timings
->vsw
, timings
->vfp
, timings
->vbp
);
2327 DSSDBG("hsync %luHz, vsync %luHz\n", ht
, vt
);
2330 static void dispc_mgr_set_lcd_divisor(enum omap_channel channel
, u16 lck_div
,
2333 BUG_ON(lck_div
< 1);
2334 BUG_ON(pck_div
< 1);
2336 dispc_write_reg(DISPC_DIVISORo(channel
),
2337 FLD_VAL(lck_div
, 23, 16) | FLD_VAL(pck_div
, 7, 0));
2340 static void dispc_mgr_get_lcd_divisor(enum omap_channel channel
, int *lck_div
,
2344 l
= dispc_read_reg(DISPC_DIVISORo(channel
));
2345 *lck_div
= FLD_GET(l
, 23, 16);
2346 *pck_div
= FLD_GET(l
, 7, 0);
2349 unsigned long dispc_fclk_rate(void)
2351 struct platform_device
*dsidev
;
2352 unsigned long r
= 0;
2354 switch (dss_get_dispc_clk_source()) {
2355 case OMAP_DSS_CLK_SRC_FCK
:
2356 r
= clk_get_rate(dispc
.dss_clk
);
2358 case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC
:
2359 dsidev
= dsi_get_dsidev_from_id(0);
2360 r
= dsi_get_pll_hsdiv_dispc_rate(dsidev
);
2362 case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC
:
2363 dsidev
= dsi_get_dsidev_from_id(1);
2364 r
= dsi_get_pll_hsdiv_dispc_rate(dsidev
);
2373 unsigned long dispc_mgr_lclk_rate(enum omap_channel channel
)
2375 struct platform_device
*dsidev
;
2380 l
= dispc_read_reg(DISPC_DIVISORo(channel
));
2382 lcd
= FLD_GET(l
, 23, 16);
2384 switch (dss_get_lcd_clk_source(channel
)) {
2385 case OMAP_DSS_CLK_SRC_FCK
:
2386 r
= clk_get_rate(dispc
.dss_clk
);
2388 case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC
:
2389 dsidev
= dsi_get_dsidev_from_id(0);
2390 r
= dsi_get_pll_hsdiv_dispc_rate(dsidev
);
2392 case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC
:
2393 dsidev
= dsi_get_dsidev_from_id(1);
2394 r
= dsi_get_pll_hsdiv_dispc_rate(dsidev
);
2403 unsigned long dispc_mgr_pclk_rate(enum omap_channel channel
)
2407 if (dispc_mgr_is_lcd(channel
)) {
2411 l
= dispc_read_reg(DISPC_DIVISORo(channel
));
2413 pcd
= FLD_GET(l
, 7, 0);
2415 r
= dispc_mgr_lclk_rate(channel
);
2419 struct omap_dss_device
*dssdev
=
2420 dispc_mgr_get_device(channel
);
2422 switch (dssdev
->type
) {
2423 case OMAP_DISPLAY_TYPE_VENC
:
2424 return venc_get_pixel_clock();
2425 case OMAP_DISPLAY_TYPE_HDMI
:
2426 return hdmi_get_pixel_clock();
2433 void dispc_dump_clocks(struct seq_file
*s
)
2437 enum omap_dss_clk_source dispc_clk_src
= dss_get_dispc_clk_source();
2438 enum omap_dss_clk_source lcd_clk_src
;
2440 if (dispc_runtime_get())
2443 seq_printf(s
, "- DISPC -\n");
2445 seq_printf(s
, "dispc fclk source = %s (%s)\n",
2446 dss_get_generic_clk_source_name(dispc_clk_src
),
2447 dss_feat_get_clk_source_name(dispc_clk_src
));
2449 seq_printf(s
, "fck\t\t%-16lu\n", dispc_fclk_rate());
2451 if (dss_has_feature(FEAT_CORE_CLK_DIV
)) {
2452 seq_printf(s
, "- DISPC-CORE-CLK -\n");
2453 l
= dispc_read_reg(DISPC_DIVISOR
);
2454 lcd
= FLD_GET(l
, 23, 16);
2456 seq_printf(s
, "lck\t\t%-16lulck div\t%u\n",
2457 (dispc_fclk_rate()/lcd
), lcd
);
2459 seq_printf(s
, "- LCD1 -\n");
2461 lcd_clk_src
= dss_get_lcd_clk_source(OMAP_DSS_CHANNEL_LCD
);
2463 seq_printf(s
, "lcd1_clk source = %s (%s)\n",
2464 dss_get_generic_clk_source_name(lcd_clk_src
),
2465 dss_feat_get_clk_source_name(lcd_clk_src
));
2467 dispc_mgr_get_lcd_divisor(OMAP_DSS_CHANNEL_LCD
, &lcd
, &pcd
);
2469 seq_printf(s
, "lck\t\t%-16lulck div\t%u\n",
2470 dispc_mgr_lclk_rate(OMAP_DSS_CHANNEL_LCD
), lcd
);
2471 seq_printf(s
, "pck\t\t%-16lupck div\t%u\n",
2472 dispc_mgr_pclk_rate(OMAP_DSS_CHANNEL_LCD
), pcd
);
2473 if (dss_has_feature(FEAT_MGR_LCD2
)) {
2474 seq_printf(s
, "- LCD2 -\n");
2476 lcd_clk_src
= dss_get_lcd_clk_source(OMAP_DSS_CHANNEL_LCD2
);
2478 seq_printf(s
, "lcd2_clk source = %s (%s)\n",
2479 dss_get_generic_clk_source_name(lcd_clk_src
),
2480 dss_feat_get_clk_source_name(lcd_clk_src
));
2482 dispc_mgr_get_lcd_divisor(OMAP_DSS_CHANNEL_LCD2
, &lcd
, &pcd
);
2484 seq_printf(s
, "lck\t\t%-16lulck div\t%u\n",
2485 dispc_mgr_lclk_rate(OMAP_DSS_CHANNEL_LCD2
), lcd
);
2486 seq_printf(s
, "pck\t\t%-16lupck div\t%u\n",
2487 dispc_mgr_pclk_rate(OMAP_DSS_CHANNEL_LCD2
), pcd
);
2490 dispc_runtime_put();
2493 #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
2494 void dispc_dump_irqs(struct seq_file
*s
)
2496 unsigned long flags
;
2497 struct dispc_irq_stats stats
;
2499 spin_lock_irqsave(&dispc
.irq_stats_lock
, flags
);
2501 stats
= dispc
.irq_stats
;
2502 memset(&dispc
.irq_stats
, 0, sizeof(dispc
.irq_stats
));
2503 dispc
.irq_stats
.last_reset
= jiffies
;
2505 spin_unlock_irqrestore(&dispc
.irq_stats_lock
, flags
);
2507 seq_printf(s
, "period %u ms\n",
2508 jiffies_to_msecs(jiffies
- stats
.last_reset
));
2510 seq_printf(s
, "irqs %d\n", stats
.irq_count
);
2512 seq_printf(s, "%-20s %10d\n", #x, stats.irqs[ffs(DISPC_IRQ_##x)-1]);
2518 PIS(ACBIAS_COUNT_STAT
);
2520 PIS(GFX_FIFO_UNDERFLOW
);
2522 PIS(PAL_GAMMA_MASK
);
2524 PIS(VID1_FIFO_UNDERFLOW
);
2526 PIS(VID2_FIFO_UNDERFLOW
);
2528 if (dss_feat_get_num_ovls() > 3) {
2529 PIS(VID3_FIFO_UNDERFLOW
);
2533 PIS(SYNC_LOST_DIGIT
);
2535 if (dss_has_feature(FEAT_MGR_LCD2
)) {
2538 PIS(ACBIAS_COUNT_STAT2
);
2545 void dispc_dump_regs(struct seq_file
*s
)
2548 const char *mgr_names
[] = {
2549 [OMAP_DSS_CHANNEL_LCD
] = "LCD",
2550 [OMAP_DSS_CHANNEL_DIGIT
] = "TV",
2551 [OMAP_DSS_CHANNEL_LCD2
] = "LCD2",
2553 const char *ovl_names
[] = {
2554 [OMAP_DSS_GFX
] = "GFX",
2555 [OMAP_DSS_VIDEO1
] = "VID1",
2556 [OMAP_DSS_VIDEO2
] = "VID2",
2557 [OMAP_DSS_VIDEO3
] = "VID3",
2559 const char **p_names
;
2561 #define DUMPREG(r) seq_printf(s, "%-50s %08x\n", #r, dispc_read_reg(r))
2563 if (dispc_runtime_get())
2566 /* DISPC common registers */
2567 DUMPREG(DISPC_REVISION
);
2568 DUMPREG(DISPC_SYSCONFIG
);
2569 DUMPREG(DISPC_SYSSTATUS
);
2570 DUMPREG(DISPC_IRQSTATUS
);
2571 DUMPREG(DISPC_IRQENABLE
);
2572 DUMPREG(DISPC_CONTROL
);
2573 DUMPREG(DISPC_CONFIG
);
2574 DUMPREG(DISPC_CAPABLE
);
2575 DUMPREG(DISPC_LINE_STATUS
);
2576 DUMPREG(DISPC_LINE_NUMBER
);
2577 if (dss_has_feature(FEAT_ALPHA_FIXED_ZORDER
) ||
2578 dss_has_feature(FEAT_ALPHA_FREE_ZORDER
))
2579 DUMPREG(DISPC_GLOBAL_ALPHA
);
2580 if (dss_has_feature(FEAT_MGR_LCD2
)) {
2581 DUMPREG(DISPC_CONTROL2
);
2582 DUMPREG(DISPC_CONFIG2
);
2587 #define DISPC_REG(i, name) name(i)
2588 #define DUMPREG(i, r) seq_printf(s, "%s(%s)%*s %08x\n", #r, p_names[i], \
2589 48 - strlen(#r) - strlen(p_names[i]), " ", \
2590 dispc_read_reg(DISPC_REG(i, r)))
2592 p_names
= mgr_names
;
2594 /* DISPC channel specific registers */
2595 for (i
= 0; i
< dss_feat_get_num_mgrs(); i
++) {
2596 DUMPREG(i
, DISPC_DEFAULT_COLOR
);
2597 DUMPREG(i
, DISPC_TRANS_COLOR
);
2598 DUMPREG(i
, DISPC_SIZE_MGR
);
2600 if (i
== OMAP_DSS_CHANNEL_DIGIT
)
2603 DUMPREG(i
, DISPC_DEFAULT_COLOR
);
2604 DUMPREG(i
, DISPC_TRANS_COLOR
);
2605 DUMPREG(i
, DISPC_TIMING_H
);
2606 DUMPREG(i
, DISPC_TIMING_V
);
2607 DUMPREG(i
, DISPC_POL_FREQ
);
2608 DUMPREG(i
, DISPC_DIVISORo
);
2609 DUMPREG(i
, DISPC_SIZE_MGR
);
2611 DUMPREG(i
, DISPC_DATA_CYCLE1
);
2612 DUMPREG(i
, DISPC_DATA_CYCLE2
);
2613 DUMPREG(i
, DISPC_DATA_CYCLE3
);
2615 if (dss_has_feature(FEAT_CPR
)) {
2616 DUMPREG(i
, DISPC_CPR_COEF_R
);
2617 DUMPREG(i
, DISPC_CPR_COEF_G
);
2618 DUMPREG(i
, DISPC_CPR_COEF_B
);
2622 p_names
= ovl_names
;
2624 for (i
= 0; i
< dss_feat_get_num_ovls(); i
++) {
2625 DUMPREG(i
, DISPC_OVL_BA0
);
2626 DUMPREG(i
, DISPC_OVL_BA1
);
2627 DUMPREG(i
, DISPC_OVL_POSITION
);
2628 DUMPREG(i
, DISPC_OVL_SIZE
);
2629 DUMPREG(i
, DISPC_OVL_ATTRIBUTES
);
2630 DUMPREG(i
, DISPC_OVL_FIFO_THRESHOLD
);
2631 DUMPREG(i
, DISPC_OVL_FIFO_SIZE_STATUS
);
2632 DUMPREG(i
, DISPC_OVL_ROW_INC
);
2633 DUMPREG(i
, DISPC_OVL_PIXEL_INC
);
2634 if (dss_has_feature(FEAT_PRELOAD
))
2635 DUMPREG(i
, DISPC_OVL_PRELOAD
);
2637 if (i
== OMAP_DSS_GFX
) {
2638 DUMPREG(i
, DISPC_OVL_WINDOW_SKIP
);
2639 DUMPREG(i
, DISPC_OVL_TABLE_BA
);
2643 DUMPREG(i
, DISPC_OVL_FIR
);
2644 DUMPREG(i
, DISPC_OVL_PICTURE_SIZE
);
2645 DUMPREG(i
, DISPC_OVL_ACCU0
);
2646 DUMPREG(i
, DISPC_OVL_ACCU1
);
2647 if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE
)) {
2648 DUMPREG(i
, DISPC_OVL_BA0_UV
);
2649 DUMPREG(i
, DISPC_OVL_BA1_UV
);
2650 DUMPREG(i
, DISPC_OVL_FIR2
);
2651 DUMPREG(i
, DISPC_OVL_ACCU2_0
);
2652 DUMPREG(i
, DISPC_OVL_ACCU2_1
);
2654 if (dss_has_feature(FEAT_ATTR2
))
2655 DUMPREG(i
, DISPC_OVL_ATTRIBUTES2
);
2656 if (dss_has_feature(FEAT_PRELOAD
))
2657 DUMPREG(i
, DISPC_OVL_PRELOAD
);
2663 #define DISPC_REG(plane, name, i) name(plane, i)
2664 #define DUMPREG(plane, name, i) \
2665 seq_printf(s, "%s_%d(%s)%*s %08x\n", #name, i, p_names[plane], \
2666 46 - strlen(#name) - strlen(p_names[plane]), " ", \
2667 dispc_read_reg(DISPC_REG(plane, name, i)))
2669 /* Video pipeline coefficient registers */
2671 /* start from OMAP_DSS_VIDEO1 */
2672 for (i
= 1; i
< dss_feat_get_num_ovls(); i
++) {
2673 for (j
= 0; j
< 8; j
++)
2674 DUMPREG(i
, DISPC_OVL_FIR_COEF_H
, j
);
2676 for (j
= 0; j
< 8; j
++)
2677 DUMPREG(i
, DISPC_OVL_FIR_COEF_HV
, j
);
2679 for (j
= 0; j
< 5; j
++)
2680 DUMPREG(i
, DISPC_OVL_CONV_COEF
, j
);
2682 if (dss_has_feature(FEAT_FIR_COEF_V
)) {
2683 for (j
= 0; j
< 8; j
++)
2684 DUMPREG(i
, DISPC_OVL_FIR_COEF_V
, j
);
2687 if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE
)) {
2688 for (j
= 0; j
< 8; j
++)
2689 DUMPREG(i
, DISPC_OVL_FIR_COEF_H2
, j
);
2691 for (j
= 0; j
< 8; j
++)
2692 DUMPREG(i
, DISPC_OVL_FIR_COEF_HV2
, j
);
2694 for (j
= 0; j
< 8; j
++)
2695 DUMPREG(i
, DISPC_OVL_FIR_COEF_V2
, j
);
2699 dispc_runtime_put();
2705 static void _dispc_mgr_set_pol_freq(enum omap_channel channel
, bool onoff
,
2706 bool rf
, bool ieo
, bool ipc
, bool ihs
, bool ivs
, u8 acbi
,
2711 DSSDBG("onoff %d rf %d ieo %d ipc %d ihs %d ivs %d acbi %d acb %d\n",
2712 onoff
, rf
, ieo
, ipc
, ihs
, ivs
, acbi
, acb
);
2714 l
|= FLD_VAL(onoff
, 17, 17);
2715 l
|= FLD_VAL(rf
, 16, 16);
2716 l
|= FLD_VAL(ieo
, 15, 15);
2717 l
|= FLD_VAL(ipc
, 14, 14);
2718 l
|= FLD_VAL(ihs
, 13, 13);
2719 l
|= FLD_VAL(ivs
, 12, 12);
2720 l
|= FLD_VAL(acbi
, 11, 8);
2721 l
|= FLD_VAL(acb
, 7, 0);
2723 dispc_write_reg(DISPC_POL_FREQ(channel
), l
);
2726 void dispc_mgr_set_pol_freq(enum omap_channel channel
,
2727 enum omap_panel_config config
, u8 acbi
, u8 acb
)
2729 _dispc_mgr_set_pol_freq(channel
, (config
& OMAP_DSS_LCD_ONOFF
) != 0,
2730 (config
& OMAP_DSS_LCD_RF
) != 0,
2731 (config
& OMAP_DSS_LCD_IEO
) != 0,
2732 (config
& OMAP_DSS_LCD_IPC
) != 0,
2733 (config
& OMAP_DSS_LCD_IHS
) != 0,
2734 (config
& OMAP_DSS_LCD_IVS
) != 0,
2738 /* with fck as input clock rate, find dispc dividers that produce req_pck */
2739 void dispc_find_clk_divs(bool is_tft
, unsigned long req_pck
, unsigned long fck
,
2740 struct dispc_clock_info
*cinfo
)
2742 u16 pcd_min
, pcd_max
;
2743 unsigned long best_pck
;
2744 u16 best_ld
, cur_ld
;
2745 u16 best_pd
, cur_pd
;
2747 pcd_min
= dss_feat_get_param_min(FEAT_PARAM_DSS_PCD
);
2748 pcd_max
= dss_feat_get_param_max(FEAT_PARAM_DSS_PCD
);
2757 for (cur_ld
= 1; cur_ld
<= 255; ++cur_ld
) {
2758 unsigned long lck
= fck
/ cur_ld
;
2760 for (cur_pd
= pcd_min
; cur_pd
<= pcd_max
; ++cur_pd
) {
2761 unsigned long pck
= lck
/ cur_pd
;
2762 long old_delta
= abs(best_pck
- req_pck
);
2763 long new_delta
= abs(pck
- req_pck
);
2765 if (best_pck
== 0 || new_delta
< old_delta
) {
2778 if (lck
/ pcd_min
< req_pck
)
2783 cinfo
->lck_div
= best_ld
;
2784 cinfo
->pck_div
= best_pd
;
2785 cinfo
->lck
= fck
/ cinfo
->lck_div
;
2786 cinfo
->pck
= cinfo
->lck
/ cinfo
->pck_div
;
2789 /* calculate clock rates using dividers in cinfo */
2790 int dispc_calc_clock_rates(unsigned long dispc_fclk_rate
,
2791 struct dispc_clock_info
*cinfo
)
2793 if (cinfo
->lck_div
> 255 || cinfo
->lck_div
== 0)
2795 if (cinfo
->pck_div
< 1 || cinfo
->pck_div
> 255)
2798 cinfo
->lck
= dispc_fclk_rate
/ cinfo
->lck_div
;
2799 cinfo
->pck
= cinfo
->lck
/ cinfo
->pck_div
;
2804 int dispc_mgr_set_clock_div(enum omap_channel channel
,
2805 struct dispc_clock_info
*cinfo
)
2807 DSSDBG("lck = %lu (%u)\n", cinfo
->lck
, cinfo
->lck_div
);
2808 DSSDBG("pck = %lu (%u)\n", cinfo
->pck
, cinfo
->pck_div
);
2810 dispc_mgr_set_lcd_divisor(channel
, cinfo
->lck_div
, cinfo
->pck_div
);
2815 int dispc_mgr_get_clock_div(enum omap_channel channel
,
2816 struct dispc_clock_info
*cinfo
)
2820 fck
= dispc_fclk_rate();
2822 cinfo
->lck_div
= REG_GET(DISPC_DIVISORo(channel
), 23, 16);
2823 cinfo
->pck_div
= REG_GET(DISPC_DIVISORo(channel
), 7, 0);
2825 cinfo
->lck
= fck
/ cinfo
->lck_div
;
2826 cinfo
->pck
= cinfo
->lck
/ cinfo
->pck_div
;
2831 /* dispc.irq_lock has to be locked by the caller */
2832 static void _omap_dispc_set_irqs(void)
2837 struct omap_dispc_isr_data
*isr_data
;
2839 mask
= dispc
.irq_error_mask
;
2841 for (i
= 0; i
< DISPC_MAX_NR_ISRS
; i
++) {
2842 isr_data
= &dispc
.registered_isr
[i
];
2844 if (isr_data
->isr
== NULL
)
2847 mask
|= isr_data
->mask
;
2850 old_mask
= dispc_read_reg(DISPC_IRQENABLE
);
2851 /* clear the irqstatus for newly enabled irqs */
2852 dispc_write_reg(DISPC_IRQSTATUS
, (mask
^ old_mask
) & mask
);
2854 dispc_write_reg(DISPC_IRQENABLE
, mask
);
2857 int omap_dispc_register_isr(omap_dispc_isr_t isr
, void *arg
, u32 mask
)
2861 unsigned long flags
;
2862 struct omap_dispc_isr_data
*isr_data
;
2867 spin_lock_irqsave(&dispc
.irq_lock
, flags
);
2869 /* check for duplicate entry */
2870 for (i
= 0; i
< DISPC_MAX_NR_ISRS
; i
++) {
2871 isr_data
= &dispc
.registered_isr
[i
];
2872 if (isr_data
->isr
== isr
&& isr_data
->arg
== arg
&&
2873 isr_data
->mask
== mask
) {
2882 for (i
= 0; i
< DISPC_MAX_NR_ISRS
; i
++) {
2883 isr_data
= &dispc
.registered_isr
[i
];
2885 if (isr_data
->isr
!= NULL
)
2888 isr_data
->isr
= isr
;
2889 isr_data
->arg
= arg
;
2890 isr_data
->mask
= mask
;
2899 _omap_dispc_set_irqs();
2901 spin_unlock_irqrestore(&dispc
.irq_lock
, flags
);
2905 spin_unlock_irqrestore(&dispc
.irq_lock
, flags
);
2909 EXPORT_SYMBOL(omap_dispc_register_isr
);
2911 int omap_dispc_unregister_isr(omap_dispc_isr_t isr
, void *arg
, u32 mask
)
2914 unsigned long flags
;
2916 struct omap_dispc_isr_data
*isr_data
;
2918 spin_lock_irqsave(&dispc
.irq_lock
, flags
);
2920 for (i
= 0; i
< DISPC_MAX_NR_ISRS
; i
++) {
2921 isr_data
= &dispc
.registered_isr
[i
];
2922 if (isr_data
->isr
!= isr
|| isr_data
->arg
!= arg
||
2923 isr_data
->mask
!= mask
)
2926 /* found the correct isr */
2928 isr_data
->isr
= NULL
;
2929 isr_data
->arg
= NULL
;
2937 _omap_dispc_set_irqs();
2939 spin_unlock_irqrestore(&dispc
.irq_lock
, flags
);
2943 EXPORT_SYMBOL(omap_dispc_unregister_isr
);
2946 static void print_irq_status(u32 status
)
2948 if ((status
& dispc
.irq_error_mask
) == 0)
2951 printk(KERN_DEBUG
"DISPC IRQ: 0x%x: ", status
);
2954 if (status & DISPC_IRQ_##x) \
2956 PIS(GFX_FIFO_UNDERFLOW
);
2958 PIS(VID1_FIFO_UNDERFLOW
);
2959 PIS(VID2_FIFO_UNDERFLOW
);
2960 if (dss_feat_get_num_ovls() > 3)
2961 PIS(VID3_FIFO_UNDERFLOW
);
2963 PIS(SYNC_LOST_DIGIT
);
2964 if (dss_has_feature(FEAT_MGR_LCD2
))
2972 /* Called from dss.c. Note that we don't touch clocks here,
2973 * but we presume they are on because we got an IRQ. However,
2974 * an irq handler may turn the clocks off, so we may not have
2975 * clock later in the function. */
2976 static irqreturn_t
omap_dispc_irq_handler(int irq
, void *arg
)
2979 u32 irqstatus
, irqenable
;
2980 u32 handledirqs
= 0;
2981 u32 unhandled_errors
;
2982 struct omap_dispc_isr_data
*isr_data
;
2983 struct omap_dispc_isr_data registered_isr
[DISPC_MAX_NR_ISRS
];
2985 spin_lock(&dispc
.irq_lock
);
2987 irqstatus
= dispc_read_reg(DISPC_IRQSTATUS
);
2988 irqenable
= dispc_read_reg(DISPC_IRQENABLE
);
2990 /* IRQ is not for us */
2991 if (!(irqstatus
& irqenable
)) {
2992 spin_unlock(&dispc
.irq_lock
);
2996 #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
2997 spin_lock(&dispc
.irq_stats_lock
);
2998 dispc
.irq_stats
.irq_count
++;
2999 dss_collect_irq_stats(irqstatus
, dispc
.irq_stats
.irqs
);
3000 spin_unlock(&dispc
.irq_stats_lock
);
3005 print_irq_status(irqstatus
);
3007 /* Ack the interrupt. Do it here before clocks are possibly turned
3009 dispc_write_reg(DISPC_IRQSTATUS
, irqstatus
);
3010 /* flush posted write */
3011 dispc_read_reg(DISPC_IRQSTATUS
);
3013 /* make a copy and unlock, so that isrs can unregister
3015 memcpy(registered_isr
, dispc
.registered_isr
,
3016 sizeof(registered_isr
));
3018 spin_unlock(&dispc
.irq_lock
);
3020 for (i
= 0; i
< DISPC_MAX_NR_ISRS
; i
++) {
3021 isr_data
= ®istered_isr
[i
];
3026 if (isr_data
->mask
& irqstatus
) {
3027 isr_data
->isr(isr_data
->arg
, irqstatus
);
3028 handledirqs
|= isr_data
->mask
;
3032 spin_lock(&dispc
.irq_lock
);
3034 unhandled_errors
= irqstatus
& ~handledirqs
& dispc
.irq_error_mask
;
3036 if (unhandled_errors
) {
3037 dispc
.error_irqs
|= unhandled_errors
;
3039 dispc
.irq_error_mask
&= ~unhandled_errors
;
3040 _omap_dispc_set_irqs();
3042 schedule_work(&dispc
.error_work
);
3045 spin_unlock(&dispc
.irq_lock
);
3050 static void dispc_error_worker(struct work_struct
*work
)
3054 unsigned long flags
;
3055 static const unsigned fifo_underflow_bits
[] = {
3056 DISPC_IRQ_GFX_FIFO_UNDERFLOW
,
3057 DISPC_IRQ_VID1_FIFO_UNDERFLOW
,
3058 DISPC_IRQ_VID2_FIFO_UNDERFLOW
,
3059 DISPC_IRQ_VID3_FIFO_UNDERFLOW
,
3062 static const unsigned sync_lost_bits
[] = {
3063 DISPC_IRQ_SYNC_LOST
,
3064 DISPC_IRQ_SYNC_LOST_DIGIT
,
3065 DISPC_IRQ_SYNC_LOST2
,
3068 spin_lock_irqsave(&dispc
.irq_lock
, flags
);
3069 errors
= dispc
.error_irqs
;
3070 dispc
.error_irqs
= 0;
3071 spin_unlock_irqrestore(&dispc
.irq_lock
, flags
);
3073 dispc_runtime_get();
3075 for (i
= 0; i
< omap_dss_get_num_overlays(); ++i
) {
3076 struct omap_overlay
*ovl
;
3079 ovl
= omap_dss_get_overlay(i
);
3080 bit
= fifo_underflow_bits
[i
];
3083 DSSERR("FIFO UNDERFLOW on %s, disabling the overlay\n",
3085 dispc_ovl_enable(ovl
->id
, false);
3086 dispc_mgr_go(ovl
->manager
->id
);
3091 for (i
= 0; i
< omap_dss_get_num_overlay_managers(); ++i
) {
3092 struct omap_overlay_manager
*mgr
;
3095 mgr
= omap_dss_get_overlay_manager(i
);
3096 bit
= sync_lost_bits
[i
];
3099 struct omap_dss_device
*dssdev
= mgr
->device
;
3102 DSSERR("SYNC_LOST on channel %s, restarting the output "
3103 "with video overlays disabled\n",
3106 enable
= dssdev
->state
== OMAP_DSS_DISPLAY_ACTIVE
;
3107 dssdev
->driver
->disable(dssdev
);
3109 for (i
= 0; i
< omap_dss_get_num_overlays(); ++i
) {
3110 struct omap_overlay
*ovl
;
3111 ovl
= omap_dss_get_overlay(i
);
3113 if (ovl
->id
!= OMAP_DSS_GFX
&&
3114 ovl
->manager
== mgr
)
3115 dispc_ovl_enable(ovl
->id
, false);
3118 dispc_mgr_go(mgr
->id
);
3122 dssdev
->driver
->enable(dssdev
);
3126 if (errors
& DISPC_IRQ_OCP_ERR
) {
3127 DSSERR("OCP_ERR\n");
3128 for (i
= 0; i
< omap_dss_get_num_overlay_managers(); ++i
) {
3129 struct omap_overlay_manager
*mgr
;
3130 mgr
= omap_dss_get_overlay_manager(i
);
3131 if (mgr
->device
&& mgr
->device
->driver
)
3132 mgr
->device
->driver
->disable(mgr
->device
);
3136 spin_lock_irqsave(&dispc
.irq_lock
, flags
);
3137 dispc
.irq_error_mask
|= errors
;
3138 _omap_dispc_set_irqs();
3139 spin_unlock_irqrestore(&dispc
.irq_lock
, flags
);
3141 dispc_runtime_put();
3144 int omap_dispc_wait_for_irq_timeout(u32 irqmask
, unsigned long timeout
)
3146 void dispc_irq_wait_handler(void *data
, u32 mask
)
3148 complete((struct completion
*)data
);
3152 DECLARE_COMPLETION_ONSTACK(completion
);
3154 r
= omap_dispc_register_isr(dispc_irq_wait_handler
, &completion
,
3160 timeout
= wait_for_completion_timeout(&completion
, timeout
);
3162 omap_dispc_unregister_isr(dispc_irq_wait_handler
, &completion
, irqmask
);
3167 if (timeout
== -ERESTARTSYS
)
3168 return -ERESTARTSYS
;
3173 int omap_dispc_wait_for_irq_interruptible_timeout(u32 irqmask
,
3174 unsigned long timeout
)
3176 void dispc_irq_wait_handler(void *data
, u32 mask
)
3178 complete((struct completion
*)data
);
3182 DECLARE_COMPLETION_ONSTACK(completion
);
3184 r
= omap_dispc_register_isr(dispc_irq_wait_handler
, &completion
,
3190 timeout
= wait_for_completion_interruptible_timeout(&completion
,
3193 omap_dispc_unregister_isr(dispc_irq_wait_handler
, &completion
, irqmask
);
3198 if (timeout
== -ERESTARTSYS
)
3199 return -ERESTARTSYS
;
3204 #ifdef CONFIG_OMAP2_DSS_FAKE_VSYNC
3205 void dispc_fake_vsync_irq(void)
3207 u32 irqstatus
= DISPC_IRQ_VSYNC
;
3210 WARN_ON(!in_interrupt());
3212 for (i
= 0; i
< DISPC_MAX_NR_ISRS
; i
++) {
3213 struct omap_dispc_isr_data
*isr_data
;
3214 isr_data
= &dispc
.registered_isr
[i
];
3219 if (isr_data
->mask
& irqstatus
)
3220 isr_data
->isr(isr_data
->arg
, irqstatus
);
3225 static void _omap_dispc_initialize_irq(void)
3227 unsigned long flags
;
3229 spin_lock_irqsave(&dispc
.irq_lock
, flags
);
3231 memset(dispc
.registered_isr
, 0, sizeof(dispc
.registered_isr
));
3233 dispc
.irq_error_mask
= DISPC_IRQ_MASK_ERROR
;
3234 if (dss_has_feature(FEAT_MGR_LCD2
))
3235 dispc
.irq_error_mask
|= DISPC_IRQ_SYNC_LOST2
;
3236 if (dss_feat_get_num_ovls() > 3)
3237 dispc
.irq_error_mask
|= DISPC_IRQ_VID3_FIFO_UNDERFLOW
;
3239 /* there's SYNC_LOST_DIGIT waiting after enabling the DSS,
3241 dispc_write_reg(DISPC_IRQSTATUS
, dispc_read_reg(DISPC_IRQSTATUS
));
3243 _omap_dispc_set_irqs();
3245 spin_unlock_irqrestore(&dispc
.irq_lock
, flags
);
3248 void dispc_enable_sidle(void)
3250 REG_FLD_MOD(DISPC_SYSCONFIG
, 2, 4, 3); /* SIDLEMODE: smart idle */
3253 void dispc_disable_sidle(void)
3255 REG_FLD_MOD(DISPC_SYSCONFIG
, 1, 4, 3); /* SIDLEMODE: no idle */
3258 static void _omap_dispc_initial_config(void)
3262 /* Exclusively enable DISPC_CORE_CLK and set divider to 1 */
3263 if (dss_has_feature(FEAT_CORE_CLK_DIV
)) {
3264 l
= dispc_read_reg(DISPC_DIVISOR
);
3265 /* Use DISPC_DIVISOR.LCD, instead of DISPC_DIVISOR1.LCD */
3266 l
= FLD_MOD(l
, 1, 0, 0);
3267 l
= FLD_MOD(l
, 1, 23, 16);
3268 dispc_write_reg(DISPC_DIVISOR
, l
);
3272 if (dss_has_feature(FEAT_FUNCGATED
))
3273 REG_FLD_MOD(DISPC_CONFIG
, 1, 9, 9);
3275 /* L3 firewall setting: enable access to OCM RAM */
3276 /* XXX this should be somewhere in plat-omap */
3277 if (cpu_is_omap24xx())
3278 __raw_writel(0x402000b0, OMAP2_L3_IO_ADDRESS(0x680050a0));
3280 _dispc_setup_color_conv_coef();
3282 dispc_set_loadmode(OMAP_DSS_LOAD_FRAME_ONLY
);
3284 dispc_read_plane_fifo_sizes();
3286 dispc_configure_burst_sizes();
3288 dispc_ovl_enable_zorder_planes();
3291 /* DISPC HW IP initialisation */
3292 static int omap_dispchw_probe(struct platform_device
*pdev
)
3296 struct resource
*dispc_mem
;
3301 clk
= clk_get(&pdev
->dev
, "fck");
3303 DSSERR("can't get fck\n");
3308 dispc
.dss_clk
= clk
;
3310 spin_lock_init(&dispc
.irq_lock
);
3312 #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
3313 spin_lock_init(&dispc
.irq_stats_lock
);
3314 dispc
.irq_stats
.last_reset
= jiffies
;
3317 INIT_WORK(&dispc
.error_work
, dispc_error_worker
);
3319 dispc_mem
= platform_get_resource(dispc
.pdev
, IORESOURCE_MEM
, 0);
3321 DSSERR("can't get IORESOURCE_MEM DISPC\n");
3325 dispc
.base
= ioremap(dispc_mem
->start
, resource_size(dispc_mem
));
3327 DSSERR("can't ioremap DISPC\n");
3331 dispc
.irq
= platform_get_irq(dispc
.pdev
, 0);
3332 if (dispc
.irq
< 0) {
3333 DSSERR("platform_get_irq failed\n");
3338 r
= request_irq(dispc
.irq
, omap_dispc_irq_handler
, IRQF_SHARED
,
3339 "OMAP DISPC", dispc
.pdev
);
3341 DSSERR("request_irq failed\n");
3345 pm_runtime_enable(&pdev
->dev
);
3347 r
= dispc_runtime_get();
3349 goto err_runtime_get
;
3351 _omap_dispc_initial_config();
3353 _omap_dispc_initialize_irq();
3355 rev
= dispc_read_reg(DISPC_REVISION
);
3356 dev_dbg(&pdev
->dev
, "OMAP DISPC rev %d.%d\n",
3357 FLD_GET(rev
, 7, 4), FLD_GET(rev
, 3, 0));
3359 dispc_runtime_put();
3364 pm_runtime_disable(&pdev
->dev
);
3365 free_irq(dispc
.irq
, dispc
.pdev
);
3367 iounmap(dispc
.base
);
3369 clk_put(dispc
.dss_clk
);
3374 static int omap_dispchw_remove(struct platform_device
*pdev
)
3376 pm_runtime_disable(&pdev
->dev
);
3378 clk_put(dispc
.dss_clk
);
3380 free_irq(dispc
.irq
, dispc
.pdev
);
3381 iounmap(dispc
.base
);
3385 static int dispc_runtime_suspend(struct device
*dev
)
3387 dispc_save_context();
3393 static int dispc_runtime_resume(struct device
*dev
)
3397 r
= dss_runtime_get();
3401 dispc_restore_context();
3406 static const struct dev_pm_ops dispc_pm_ops
= {
3407 .runtime_suspend
= dispc_runtime_suspend
,
3408 .runtime_resume
= dispc_runtime_resume
,
3411 static struct platform_driver omap_dispchw_driver
= {
3412 .probe
= omap_dispchw_probe
,
3413 .remove
= omap_dispchw_remove
,
3415 .name
= "omapdss_dispc",
3416 .owner
= THIS_MODULE
,
3417 .pm
= &dispc_pm_ops
,
3421 int dispc_init_platform_driver(void)
3423 return platform_driver_register(&omap_dispchw_driver
);
3426 void dispc_uninit_platform_driver(void)
3428 return platform_driver_unregister(&omap_dispchw_driver
);