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
{
83 enum omap_burst_size
{
89 #define REG_GET(idx, start, end) \
90 FLD_GET(dispc_read_reg(idx), start, end)
92 #define REG_FLD_MOD(idx, val, start, end) \
93 dispc_write_reg(idx, FLD_MOD(dispc_read_reg(idx), val, start, end))
95 struct dispc_irq_stats
{
96 unsigned long last_reset
;
102 struct platform_device
*pdev
;
110 u32 fifo_size
[MAX_DSS_OVERLAYS
];
114 struct omap_dispc_isr_data registered_isr
[DISPC_MAX_NR_ISRS
];
116 struct work_struct error_work
;
119 u32 ctx
[DISPC_SZ_REGS
/ sizeof(u32
)];
121 #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
122 spinlock_t irq_stats_lock
;
123 struct dispc_irq_stats irq_stats
;
127 enum omap_color_component
{
128 /* used for all color formats for OMAP3 and earlier
129 * and for RGB and Y color component on OMAP4
131 DISPC_COLOR_COMPONENT_RGB_Y
= 1 << 0,
132 /* used for UV component for
133 * OMAP_DSS_COLOR_YUV2, OMAP_DSS_COLOR_UYVY, OMAP_DSS_COLOR_NV12
134 * color formats on OMAP4
136 DISPC_COLOR_COMPONENT_UV
= 1 << 1,
139 static void _omap_dispc_set_irqs(void);
141 static inline void dispc_write_reg(const u16 idx
, u32 val
)
143 __raw_writel(val
, dispc
.base
+ idx
);
146 static inline u32
dispc_read_reg(const u16 idx
)
148 return __raw_readl(dispc
.base
+ idx
);
151 static int dispc_get_ctx_loss_count(void)
153 struct device
*dev
= &dispc
.pdev
->dev
;
154 struct omap_display_platform_data
*pdata
= dev
->platform_data
;
155 struct omap_dss_board_info
*board_data
= pdata
->board_data
;
158 if (!board_data
->get_context_loss_count
)
161 cnt
= board_data
->get_context_loss_count(dev
);
163 WARN_ONCE(cnt
< 0, "get_context_loss_count failed: %d\n", cnt
);
169 dispc.ctx[DISPC_##reg / sizeof(u32)] = dispc_read_reg(DISPC_##reg)
171 dispc_write_reg(DISPC_##reg, dispc.ctx[DISPC_##reg / sizeof(u32)])
173 static void dispc_save_context(void)
177 DSSDBG("dispc_save_context\n");
183 if (dss_has_feature(FEAT_ALPHA_FIXED_ZORDER
) ||
184 dss_has_feature(FEAT_ALPHA_FREE_ZORDER
))
186 if (dss_has_feature(FEAT_MGR_LCD2
)) {
191 for (i
= 0; i
< dss_feat_get_num_mgrs(); i
++) {
192 SR(DEFAULT_COLOR(i
));
195 if (i
== OMAP_DSS_CHANNEL_DIGIT
)
206 if (dss_has_feature(FEAT_CPR
)) {
213 for (i
= 0; i
< dss_feat_get_num_ovls(); i
++) {
218 SR(OVL_ATTRIBUTES(i
));
219 SR(OVL_FIFO_THRESHOLD(i
));
221 SR(OVL_PIXEL_INC(i
));
222 if (dss_has_feature(FEAT_PRELOAD
))
224 if (i
== OMAP_DSS_GFX
) {
225 SR(OVL_WINDOW_SKIP(i
));
230 SR(OVL_PICTURE_SIZE(i
));
234 for (j
= 0; j
< 8; j
++)
235 SR(OVL_FIR_COEF_H(i
, j
));
237 for (j
= 0; j
< 8; j
++)
238 SR(OVL_FIR_COEF_HV(i
, j
));
240 for (j
= 0; j
< 5; j
++)
241 SR(OVL_CONV_COEF(i
, j
));
243 if (dss_has_feature(FEAT_FIR_COEF_V
)) {
244 for (j
= 0; j
< 8; j
++)
245 SR(OVL_FIR_COEF_V(i
, j
));
248 if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE
)) {
255 for (j
= 0; j
< 8; j
++)
256 SR(OVL_FIR_COEF_H2(i
, j
));
258 for (j
= 0; j
< 8; j
++)
259 SR(OVL_FIR_COEF_HV2(i
, j
));
261 for (j
= 0; j
< 8; j
++)
262 SR(OVL_FIR_COEF_V2(i
, j
));
264 if (dss_has_feature(FEAT_ATTR2
))
265 SR(OVL_ATTRIBUTES2(i
));
268 if (dss_has_feature(FEAT_CORE_CLK_DIV
))
271 dispc
.ctx_loss_cnt
= dispc_get_ctx_loss_count();
272 dispc
.ctx_valid
= true;
274 DSSDBG("context saved, ctx_loss_count %d\n", dispc
.ctx_loss_cnt
);
277 static void dispc_restore_context(void)
281 DSSDBG("dispc_restore_context\n");
283 if (!dispc
.ctx_valid
)
286 ctx
= dispc_get_ctx_loss_count();
288 if (ctx
>= 0 && ctx
== dispc
.ctx_loss_cnt
)
291 DSSDBG("ctx_loss_count: saved %d, current %d\n",
292 dispc
.ctx_loss_cnt
, ctx
);
298 if (dss_has_feature(FEAT_ALPHA_FIXED_ZORDER
) ||
299 dss_has_feature(FEAT_ALPHA_FREE_ZORDER
))
301 if (dss_has_feature(FEAT_MGR_LCD2
))
304 for (i
= 0; i
< dss_feat_get_num_mgrs(); i
++) {
305 RR(DEFAULT_COLOR(i
));
308 if (i
== OMAP_DSS_CHANNEL_DIGIT
)
319 if (dss_has_feature(FEAT_CPR
)) {
326 for (i
= 0; i
< dss_feat_get_num_ovls(); i
++) {
331 RR(OVL_ATTRIBUTES(i
));
332 RR(OVL_FIFO_THRESHOLD(i
));
334 RR(OVL_PIXEL_INC(i
));
335 if (dss_has_feature(FEAT_PRELOAD
))
337 if (i
== OMAP_DSS_GFX
) {
338 RR(OVL_WINDOW_SKIP(i
));
343 RR(OVL_PICTURE_SIZE(i
));
347 for (j
= 0; j
< 8; j
++)
348 RR(OVL_FIR_COEF_H(i
, j
));
350 for (j
= 0; j
< 8; j
++)
351 RR(OVL_FIR_COEF_HV(i
, j
));
353 for (j
= 0; j
< 5; j
++)
354 RR(OVL_CONV_COEF(i
, j
));
356 if (dss_has_feature(FEAT_FIR_COEF_V
)) {
357 for (j
= 0; j
< 8; j
++)
358 RR(OVL_FIR_COEF_V(i
, j
));
361 if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE
)) {
368 for (j
= 0; j
< 8; j
++)
369 RR(OVL_FIR_COEF_H2(i
, j
));
371 for (j
= 0; j
< 8; j
++)
372 RR(OVL_FIR_COEF_HV2(i
, j
));
374 for (j
= 0; j
< 8; j
++)
375 RR(OVL_FIR_COEF_V2(i
, j
));
377 if (dss_has_feature(FEAT_ATTR2
))
378 RR(OVL_ATTRIBUTES2(i
));
381 if (dss_has_feature(FEAT_CORE_CLK_DIV
))
384 /* enable last, because LCD & DIGIT enable are here */
386 if (dss_has_feature(FEAT_MGR_LCD2
))
388 /* clear spurious SYNC_LOST_DIGIT interrupts */
389 dispc_write_reg(DISPC_IRQSTATUS
, DISPC_IRQ_SYNC_LOST_DIGIT
);
392 * enable last so IRQs won't trigger before
393 * the context is fully restored
397 DSSDBG("context restored\n");
403 int dispc_runtime_get(void)
407 DSSDBG("dispc_runtime_get\n");
409 r
= pm_runtime_get_sync(&dispc
.pdev
->dev
);
411 return r
< 0 ? r
: 0;
414 void dispc_runtime_put(void)
418 DSSDBG("dispc_runtime_put\n");
420 r
= pm_runtime_put(&dispc
.pdev
->dev
);
424 static inline bool dispc_mgr_is_lcd(enum omap_channel channel
)
426 if (channel
== OMAP_DSS_CHANNEL_LCD
||
427 channel
== OMAP_DSS_CHANNEL_LCD2
)
433 static struct omap_dss_device
*dispc_mgr_get_device(enum omap_channel channel
)
435 struct omap_overlay_manager
*mgr
=
436 omap_dss_get_overlay_manager(channel
);
438 return mgr
? mgr
->device
: NULL
;
441 bool dispc_mgr_go_busy(enum omap_channel channel
)
445 if (dispc_mgr_is_lcd(channel
))
448 bit
= 6; /* GODIGIT */
450 if (channel
== OMAP_DSS_CHANNEL_LCD2
)
451 return REG_GET(DISPC_CONTROL2
, bit
, bit
) == 1;
453 return REG_GET(DISPC_CONTROL
, bit
, bit
) == 1;
456 void dispc_mgr_go(enum omap_channel channel
)
459 bool enable_bit
, go_bit
;
461 if (dispc_mgr_is_lcd(channel
))
462 bit
= 0; /* LCDENABLE */
464 bit
= 1; /* DIGITALENABLE */
466 /* if the channel is not enabled, we don't need GO */
467 if (channel
== OMAP_DSS_CHANNEL_LCD2
)
468 enable_bit
= REG_GET(DISPC_CONTROL2
, bit
, bit
) == 1;
470 enable_bit
= REG_GET(DISPC_CONTROL
, bit
, bit
) == 1;
475 if (dispc_mgr_is_lcd(channel
))
478 bit
= 6; /* GODIGIT */
480 if (channel
== OMAP_DSS_CHANNEL_LCD2
)
481 go_bit
= REG_GET(DISPC_CONTROL2
, bit
, bit
) == 1;
483 go_bit
= REG_GET(DISPC_CONTROL
, bit
, bit
) == 1;
486 DSSERR("GO bit not down for channel %d\n", channel
);
490 DSSDBG("GO %s\n", channel
== OMAP_DSS_CHANNEL_LCD
? "LCD" :
491 (channel
== OMAP_DSS_CHANNEL_LCD2
? "LCD2" : "DIGIT"));
493 if (channel
== OMAP_DSS_CHANNEL_LCD2
)
494 REG_FLD_MOD(DISPC_CONTROL2
, 1, bit
, bit
);
496 REG_FLD_MOD(DISPC_CONTROL
, 1, bit
, bit
);
499 static void dispc_ovl_write_firh_reg(enum omap_plane plane
, int reg
, u32 value
)
501 dispc_write_reg(DISPC_OVL_FIR_COEF_H(plane
, reg
), value
);
504 static void dispc_ovl_write_firhv_reg(enum omap_plane plane
, int reg
, u32 value
)
506 dispc_write_reg(DISPC_OVL_FIR_COEF_HV(plane
, reg
), value
);
509 static void dispc_ovl_write_firv_reg(enum omap_plane plane
, int reg
, u32 value
)
511 dispc_write_reg(DISPC_OVL_FIR_COEF_V(plane
, reg
), value
);
514 static void dispc_ovl_write_firh2_reg(enum omap_plane plane
, int reg
, u32 value
)
516 BUG_ON(plane
== OMAP_DSS_GFX
);
518 dispc_write_reg(DISPC_OVL_FIR_COEF_H2(plane
, reg
), value
);
521 static void dispc_ovl_write_firhv2_reg(enum omap_plane plane
, int reg
,
524 BUG_ON(plane
== OMAP_DSS_GFX
);
526 dispc_write_reg(DISPC_OVL_FIR_COEF_HV2(plane
, reg
), value
);
529 static void dispc_ovl_write_firv2_reg(enum omap_plane plane
, int reg
, u32 value
)
531 BUG_ON(plane
== OMAP_DSS_GFX
);
533 dispc_write_reg(DISPC_OVL_FIR_COEF_V2(plane
, reg
), value
);
536 static void dispc_ovl_set_scale_coef(enum omap_plane plane
, int hscaleup
,
537 int vscaleup
, int five_taps
,
538 enum omap_color_component color_comp
)
540 /* Coefficients for horizontal up-sampling */
541 static const struct dispc_h_coef coef_hup
[8] = {
543 { -1, 13, 124, -8, 0 },
544 { -2, 30, 112, -11, -1 },
545 { -5, 51, 95, -11, -2 },
546 { 0, -9, 73, 73, -9 },
547 { -2, -11, 95, 51, -5 },
548 { -1, -11, 112, 30, -2 },
549 { 0, -8, 124, 13, -1 },
552 /* Coefficients for vertical up-sampling */
553 static const struct dispc_v_coef coef_vup_3tap
[8] = {
556 { 0, 12, 111, 5, 0 },
560 { 0, 5, 111, 12, 0 },
564 static const struct dispc_v_coef coef_vup_5tap
[8] = {
566 { -1, 13, 124, -8, 0 },
567 { -2, 30, 112, -11, -1 },
568 { -5, 51, 95, -11, -2 },
569 { 0, -9, 73, 73, -9 },
570 { -2, -11, 95, 51, -5 },
571 { -1, -11, 112, 30, -2 },
572 { 0, -8, 124, 13, -1 },
575 /* Coefficients for horizontal down-sampling */
576 static const struct dispc_h_coef coef_hdown
[8] = {
577 { 0, 36, 56, 36, 0 },
578 { 4, 40, 55, 31, -2 },
579 { 8, 44, 54, 27, -5 },
580 { 12, 48, 53, 22, -7 },
581 { -9, 17, 52, 51, 17 },
582 { -7, 22, 53, 48, 12 },
583 { -5, 27, 54, 44, 8 },
584 { -2, 31, 55, 40, 4 },
587 /* Coefficients for vertical down-sampling */
588 static const struct dispc_v_coef coef_vdown_3tap
[8] = {
589 { 0, 36, 56, 36, 0 },
590 { 0, 40, 57, 31, 0 },
591 { 0, 45, 56, 27, 0 },
592 { 0, 50, 55, 23, 0 },
593 { 0, 18, 55, 55, 0 },
594 { 0, 23, 55, 50, 0 },
595 { 0, 27, 56, 45, 0 },
596 { 0, 31, 57, 40, 0 },
599 static const struct dispc_v_coef coef_vdown_5tap
[8] = {
600 { 0, 36, 56, 36, 0 },
601 { 4, 40, 55, 31, -2 },
602 { 8, 44, 54, 27, -5 },
603 { 12, 48, 53, 22, -7 },
604 { -9, 17, 52, 51, 17 },
605 { -7, 22, 53, 48, 12 },
606 { -5, 27, 54, 44, 8 },
607 { -2, 31, 55, 40, 4 },
610 const struct dispc_h_coef
*h_coef
;
611 const struct dispc_v_coef
*v_coef
;
620 v_coef
= five_taps
? coef_vup_5tap
: coef_vup_3tap
;
622 v_coef
= five_taps
? coef_vdown_5tap
: coef_vdown_3tap
;
624 for (i
= 0; i
< 8; i
++) {
627 h
= FLD_VAL(h_coef
[i
].hc0
, 7, 0)
628 | FLD_VAL(h_coef
[i
].hc1
, 15, 8)
629 | FLD_VAL(h_coef
[i
].hc2
, 23, 16)
630 | FLD_VAL(h_coef
[i
].hc3
, 31, 24);
631 hv
= FLD_VAL(h_coef
[i
].hc4
, 7, 0)
632 | FLD_VAL(v_coef
[i
].vc0
, 15, 8)
633 | FLD_VAL(v_coef
[i
].vc1
, 23, 16)
634 | FLD_VAL(v_coef
[i
].vc2
, 31, 24);
636 if (color_comp
== DISPC_COLOR_COMPONENT_RGB_Y
) {
637 dispc_ovl_write_firh_reg(plane
, i
, h
);
638 dispc_ovl_write_firhv_reg(plane
, i
, hv
);
640 dispc_ovl_write_firh2_reg(plane
, i
, h
);
641 dispc_ovl_write_firhv2_reg(plane
, i
, hv
);
647 for (i
= 0; i
< 8; i
++) {
649 v
= FLD_VAL(v_coef
[i
].vc00
, 7, 0)
650 | FLD_VAL(v_coef
[i
].vc22
, 15, 8);
651 if (color_comp
== DISPC_COLOR_COMPONENT_RGB_Y
)
652 dispc_ovl_write_firv_reg(plane
, i
, v
);
654 dispc_ovl_write_firv2_reg(plane
, i
, v
);
659 static void _dispc_setup_color_conv_coef(void)
662 const struct color_conv_coef
{
663 int ry
, rcr
, rcb
, gy
, gcr
, gcb
, by
, bcr
, bcb
;
666 298, 409, 0, 298, -208, -100, 298, 0, 517, 0,
669 const struct color_conv_coef
*ct
;
671 #define CVAL(x, y) (FLD_VAL(x, 26, 16) | FLD_VAL(y, 10, 0))
675 for (i
= 1; i
< dss_feat_get_num_ovls(); i
++) {
676 dispc_write_reg(DISPC_OVL_CONV_COEF(i
, 0),
677 CVAL(ct
->rcr
, ct
->ry
));
678 dispc_write_reg(DISPC_OVL_CONV_COEF(i
, 1),
679 CVAL(ct
->gy
, ct
->rcb
));
680 dispc_write_reg(DISPC_OVL_CONV_COEF(i
, 2),
681 CVAL(ct
->gcb
, ct
->gcr
));
682 dispc_write_reg(DISPC_OVL_CONV_COEF(i
, 3),
683 CVAL(ct
->bcr
, ct
->by
));
684 dispc_write_reg(DISPC_OVL_CONV_COEF(i
, 4),
687 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(i
), ct
->full_range
,
695 static void dispc_ovl_set_ba0(enum omap_plane plane
, u32 paddr
)
697 dispc_write_reg(DISPC_OVL_BA0(plane
), paddr
);
700 static void dispc_ovl_set_ba1(enum omap_plane plane
, u32 paddr
)
702 dispc_write_reg(DISPC_OVL_BA1(plane
), paddr
);
705 static void dispc_ovl_set_ba0_uv(enum omap_plane plane
, u32 paddr
)
707 dispc_write_reg(DISPC_OVL_BA0_UV(plane
), paddr
);
710 static void dispc_ovl_set_ba1_uv(enum omap_plane plane
, u32 paddr
)
712 dispc_write_reg(DISPC_OVL_BA1_UV(plane
), paddr
);
715 static void dispc_ovl_set_pos(enum omap_plane plane
, int x
, int y
)
717 u32 val
= FLD_VAL(y
, 26, 16) | FLD_VAL(x
, 10, 0);
719 dispc_write_reg(DISPC_OVL_POSITION(plane
), val
);
722 static void dispc_ovl_set_pic_size(enum omap_plane plane
, int width
, int height
)
724 u32 val
= FLD_VAL(height
- 1, 26, 16) | FLD_VAL(width
- 1, 10, 0);
726 if (plane
== OMAP_DSS_GFX
)
727 dispc_write_reg(DISPC_OVL_SIZE(plane
), val
);
729 dispc_write_reg(DISPC_OVL_PICTURE_SIZE(plane
), val
);
732 static void dispc_ovl_set_vid_size(enum omap_plane plane
, int width
, int height
)
736 BUG_ON(plane
== OMAP_DSS_GFX
);
738 val
= FLD_VAL(height
- 1, 26, 16) | FLD_VAL(width
- 1, 10, 0);
740 dispc_write_reg(DISPC_OVL_SIZE(plane
), val
);
743 static void dispc_ovl_set_zorder(enum omap_plane plane
, u8 zorder
)
745 struct omap_overlay
*ovl
= omap_dss_get_overlay(plane
);
747 if ((ovl
->caps
& OMAP_DSS_OVL_CAP_ZORDER
) == 0)
750 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane
), zorder
, 27, 26);
753 static void dispc_ovl_enable_zorder_planes(void)
757 if (!dss_has_feature(FEAT_ALPHA_FREE_ZORDER
))
760 for (i
= 0; i
< dss_feat_get_num_ovls(); i
++)
761 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(i
), 1, 25, 25);
764 static void dispc_ovl_set_pre_mult_alpha(enum omap_plane plane
, bool enable
)
766 struct omap_overlay
*ovl
= omap_dss_get_overlay(plane
);
768 if ((ovl
->caps
& OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA
) == 0)
771 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane
), enable
? 1 : 0, 28, 28);
774 static void dispc_ovl_setup_global_alpha(enum omap_plane plane
, u8 global_alpha
)
776 static const unsigned shifts
[] = { 0, 8, 16, 24, };
778 struct omap_overlay
*ovl
= omap_dss_get_overlay(plane
);
780 if ((ovl
->caps
& OMAP_DSS_OVL_CAP_GLOBAL_ALPHA
) == 0)
783 shift
= shifts
[plane
];
784 REG_FLD_MOD(DISPC_GLOBAL_ALPHA
, global_alpha
, shift
+ 7, shift
);
787 static void dispc_ovl_set_pix_inc(enum omap_plane plane
, s32 inc
)
789 dispc_write_reg(DISPC_OVL_PIXEL_INC(plane
), inc
);
792 static void dispc_ovl_set_row_inc(enum omap_plane plane
, s32 inc
)
794 dispc_write_reg(DISPC_OVL_ROW_INC(plane
), inc
);
797 static void dispc_ovl_set_color_mode(enum omap_plane plane
,
798 enum omap_color_mode color_mode
)
801 if (plane
!= OMAP_DSS_GFX
) {
802 switch (color_mode
) {
803 case OMAP_DSS_COLOR_NV12
:
805 case OMAP_DSS_COLOR_RGB12U
:
807 case OMAP_DSS_COLOR_RGBA16
:
809 case OMAP_DSS_COLOR_RGBX16
:
811 case OMAP_DSS_COLOR_ARGB16
:
813 case OMAP_DSS_COLOR_RGB16
:
815 case OMAP_DSS_COLOR_ARGB16_1555
:
817 case OMAP_DSS_COLOR_RGB24U
:
819 case OMAP_DSS_COLOR_RGB24P
:
821 case OMAP_DSS_COLOR_YUV2
:
823 case OMAP_DSS_COLOR_UYVY
:
825 case OMAP_DSS_COLOR_ARGB32
:
827 case OMAP_DSS_COLOR_RGBA32
:
829 case OMAP_DSS_COLOR_RGBX32
:
831 case OMAP_DSS_COLOR_XRGB16_1555
:
837 switch (color_mode
) {
838 case OMAP_DSS_COLOR_CLUT1
:
840 case OMAP_DSS_COLOR_CLUT2
:
842 case OMAP_DSS_COLOR_CLUT4
:
844 case OMAP_DSS_COLOR_CLUT8
:
846 case OMAP_DSS_COLOR_RGB12U
:
848 case OMAP_DSS_COLOR_ARGB16
:
850 case OMAP_DSS_COLOR_RGB16
:
852 case OMAP_DSS_COLOR_ARGB16_1555
:
854 case OMAP_DSS_COLOR_RGB24U
:
856 case OMAP_DSS_COLOR_RGB24P
:
858 case OMAP_DSS_COLOR_YUV2
:
860 case OMAP_DSS_COLOR_UYVY
:
862 case OMAP_DSS_COLOR_ARGB32
:
864 case OMAP_DSS_COLOR_RGBA32
:
866 case OMAP_DSS_COLOR_RGBX32
:
868 case OMAP_DSS_COLOR_XRGB16_1555
:
875 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane
), m
, 4, 1);
878 static void dispc_ovl_set_channel_out(enum omap_plane plane
,
879 enum omap_channel channel
)
883 int chan
= 0, chan2
= 0;
889 case OMAP_DSS_VIDEO1
:
890 case OMAP_DSS_VIDEO2
:
891 case OMAP_DSS_VIDEO3
:
899 val
= dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane
));
900 if (dss_has_feature(FEAT_MGR_LCD2
)) {
902 case OMAP_DSS_CHANNEL_LCD
:
906 case OMAP_DSS_CHANNEL_DIGIT
:
910 case OMAP_DSS_CHANNEL_LCD2
:
918 val
= FLD_MOD(val
, chan
, shift
, shift
);
919 val
= FLD_MOD(val
, chan2
, 31, 30);
921 val
= FLD_MOD(val
, channel
, shift
, shift
);
923 dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane
), val
);
926 static void dispc_ovl_set_burst_size(enum omap_plane plane
,
927 enum omap_burst_size burst_size
)
929 static const unsigned shifts
[] = { 6, 14, 14, 14, };
932 shift
= shifts
[plane
];
933 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane
), burst_size
, shift
+ 1, shift
);
936 static void dispc_configure_burst_sizes(void)
939 const int burst_size
= BURST_SIZE_X8
;
941 /* Configure burst size always to maximum size */
942 for (i
= 0; i
< omap_dss_get_num_overlays(); ++i
)
943 dispc_ovl_set_burst_size(i
, burst_size
);
946 u32
dispc_ovl_get_burst_size(enum omap_plane plane
)
948 unsigned unit
= dss_feat_get_burst_size_unit();
949 /* burst multiplier is always x8 (see dispc_configure_burst_sizes()) */
953 void dispc_enable_gamma_table(bool enable
)
956 * This is partially implemented to support only disabling of
960 DSSWARN("Gamma table enabling for TV not yet supported");
964 REG_FLD_MOD(DISPC_CONFIG
, enable
, 9, 9);
967 void dispc_mgr_enable_cpr(enum omap_channel channel
, bool enable
)
971 if (channel
== OMAP_DSS_CHANNEL_LCD
)
973 else if (channel
== OMAP_DSS_CHANNEL_LCD2
)
978 REG_FLD_MOD(reg
, enable
, 15, 15);
981 void dispc_mgr_set_cpr_coef(enum omap_channel channel
,
982 struct omap_dss_cpr_coefs
*coefs
)
984 u32 coef_r
, coef_g
, coef_b
;
986 if (!dispc_mgr_is_lcd(channel
))
989 coef_r
= FLD_VAL(coefs
->rr
, 31, 22) | FLD_VAL(coefs
->rg
, 20, 11) |
990 FLD_VAL(coefs
->rb
, 9, 0);
991 coef_g
= FLD_VAL(coefs
->gr
, 31, 22) | FLD_VAL(coefs
->gg
, 20, 11) |
992 FLD_VAL(coefs
->gb
, 9, 0);
993 coef_b
= FLD_VAL(coefs
->br
, 31, 22) | FLD_VAL(coefs
->bg
, 20, 11) |
994 FLD_VAL(coefs
->bb
, 9, 0);
996 dispc_write_reg(DISPC_CPR_COEF_R(channel
), coef_r
);
997 dispc_write_reg(DISPC_CPR_COEF_G(channel
), coef_g
);
998 dispc_write_reg(DISPC_CPR_COEF_B(channel
), coef_b
);
1001 static void dispc_ovl_set_vid_color_conv(enum omap_plane plane
, bool enable
)
1005 BUG_ON(plane
== OMAP_DSS_GFX
);
1007 val
= dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane
));
1008 val
= FLD_MOD(val
, enable
, 9, 9);
1009 dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane
), val
);
1012 static void dispc_ovl_enable_replication(enum omap_plane plane
, bool enable
)
1014 static const unsigned shifts
[] = { 5, 10, 10, 10 };
1017 shift
= shifts
[plane
];
1018 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane
), enable
, shift
, shift
);
1021 void dispc_mgr_set_lcd_size(enum omap_channel channel
, u16 width
, u16 height
)
1024 BUG_ON((width
> (1 << 11)) || (height
> (1 << 11)));
1025 val
= FLD_VAL(height
- 1, 26, 16) | FLD_VAL(width
- 1, 10, 0);
1026 dispc_write_reg(DISPC_SIZE_MGR(channel
), val
);
1029 void dispc_set_digit_size(u16 width
, u16 height
)
1032 BUG_ON((width
> (1 << 11)) || (height
> (1 << 11)));
1033 val
= FLD_VAL(height
- 1, 26, 16) | FLD_VAL(width
- 1, 10, 0);
1034 dispc_write_reg(DISPC_SIZE_MGR(OMAP_DSS_CHANNEL_DIGIT
), val
);
1037 static void dispc_read_plane_fifo_sizes(void)
1044 unit
= dss_feat_get_buffer_size_unit();
1046 dss_feat_get_reg_field(FEAT_REG_FIFOSIZE
, &start
, &end
);
1048 for (plane
= 0; plane
< dss_feat_get_num_ovls(); ++plane
) {
1049 size
= REG_GET(DISPC_OVL_FIFO_SIZE_STATUS(plane
), start
, end
);
1051 dispc
.fifo_size
[plane
] = size
;
1055 u32
dispc_ovl_get_fifo_size(enum omap_plane plane
)
1057 return dispc
.fifo_size
[plane
];
1060 static void dispc_ovl_set_fifo_threshold(enum omap_plane plane
, u32 low
,
1063 u8 hi_start
, hi_end
, lo_start
, lo_end
;
1066 unit
= dss_feat_get_buffer_size_unit();
1068 WARN_ON(low
% unit
!= 0);
1069 WARN_ON(high
% unit
!= 0);
1074 dss_feat_get_reg_field(FEAT_REG_FIFOHIGHTHRESHOLD
, &hi_start
, &hi_end
);
1075 dss_feat_get_reg_field(FEAT_REG_FIFOLOWTHRESHOLD
, &lo_start
, &lo_end
);
1077 DSSDBG("fifo(%d) low/high old %u/%u, new %u/%u\n",
1079 REG_GET(DISPC_OVL_FIFO_THRESHOLD(plane
),
1081 REG_GET(DISPC_OVL_FIFO_THRESHOLD(plane
),
1085 dispc_write_reg(DISPC_OVL_FIFO_THRESHOLD(plane
),
1086 FLD_VAL(high
, hi_start
, hi_end
) |
1087 FLD_VAL(low
, lo_start
, lo_end
));
1090 void dispc_enable_fifomerge(bool enable
)
1092 DSSDBG("FIFO merge %s\n", enable
? "enabled" : "disabled");
1093 REG_FLD_MOD(DISPC_CONFIG
, enable
? 1 : 0, 14, 14);
1096 static void dispc_ovl_set_fir(enum omap_plane plane
,
1098 enum omap_color_component color_comp
)
1102 if (color_comp
== DISPC_COLOR_COMPONENT_RGB_Y
) {
1103 u8 hinc_start
, hinc_end
, vinc_start
, vinc_end
;
1105 dss_feat_get_reg_field(FEAT_REG_FIRHINC
,
1106 &hinc_start
, &hinc_end
);
1107 dss_feat_get_reg_field(FEAT_REG_FIRVINC
,
1108 &vinc_start
, &vinc_end
);
1109 val
= FLD_VAL(vinc
, vinc_start
, vinc_end
) |
1110 FLD_VAL(hinc
, hinc_start
, hinc_end
);
1112 dispc_write_reg(DISPC_OVL_FIR(plane
), val
);
1114 val
= FLD_VAL(vinc
, 28, 16) | FLD_VAL(hinc
, 12, 0);
1115 dispc_write_reg(DISPC_OVL_FIR2(plane
), val
);
1119 static void dispc_ovl_set_vid_accu0(enum omap_plane plane
, int haccu
, int vaccu
)
1122 u8 hor_start
, hor_end
, vert_start
, vert_end
;
1124 dss_feat_get_reg_field(FEAT_REG_HORIZONTALACCU
, &hor_start
, &hor_end
);
1125 dss_feat_get_reg_field(FEAT_REG_VERTICALACCU
, &vert_start
, &vert_end
);
1127 val
= FLD_VAL(vaccu
, vert_start
, vert_end
) |
1128 FLD_VAL(haccu
, hor_start
, hor_end
);
1130 dispc_write_reg(DISPC_OVL_ACCU0(plane
), val
);
1133 static void dispc_ovl_set_vid_accu1(enum omap_plane plane
, int haccu
, int vaccu
)
1136 u8 hor_start
, hor_end
, vert_start
, vert_end
;
1138 dss_feat_get_reg_field(FEAT_REG_HORIZONTALACCU
, &hor_start
, &hor_end
);
1139 dss_feat_get_reg_field(FEAT_REG_VERTICALACCU
, &vert_start
, &vert_end
);
1141 val
= FLD_VAL(vaccu
, vert_start
, vert_end
) |
1142 FLD_VAL(haccu
, hor_start
, hor_end
);
1144 dispc_write_reg(DISPC_OVL_ACCU1(plane
), val
);
1147 static void dispc_ovl_set_vid_accu2_0(enum omap_plane plane
, int haccu
,
1152 val
= FLD_VAL(vaccu
, 26, 16) | FLD_VAL(haccu
, 10, 0);
1153 dispc_write_reg(DISPC_OVL_ACCU2_0(plane
), val
);
1156 static void dispc_ovl_set_vid_accu2_1(enum omap_plane plane
, int haccu
,
1161 val
= FLD_VAL(vaccu
, 26, 16) | FLD_VAL(haccu
, 10, 0);
1162 dispc_write_reg(DISPC_OVL_ACCU2_1(plane
), val
);
1165 static void dispc_ovl_set_scale_param(enum omap_plane plane
,
1166 u16 orig_width
, u16 orig_height
,
1167 u16 out_width
, u16 out_height
,
1168 bool five_taps
, u8 rotation
,
1169 enum omap_color_component color_comp
)
1171 int fir_hinc
, fir_vinc
;
1172 int hscaleup
, vscaleup
;
1174 hscaleup
= orig_width
<= out_width
;
1175 vscaleup
= orig_height
<= out_height
;
1177 dispc_ovl_set_scale_coef(plane
, hscaleup
, vscaleup
, five_taps
,
1180 fir_hinc
= 1024 * orig_width
/ out_width
;
1181 fir_vinc
= 1024 * orig_height
/ out_height
;
1183 dispc_ovl_set_fir(plane
, fir_hinc
, fir_vinc
, color_comp
);
1186 static void dispc_ovl_set_scaling_common(enum omap_plane plane
,
1187 u16 orig_width
, u16 orig_height
,
1188 u16 out_width
, u16 out_height
,
1189 bool ilace
, bool five_taps
,
1190 bool fieldmode
, enum omap_color_mode color_mode
,
1197 dispc_ovl_set_scale_param(plane
, orig_width
, orig_height
,
1198 out_width
, out_height
, five_taps
,
1199 rotation
, DISPC_COLOR_COMPONENT_RGB_Y
);
1200 l
= dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane
));
1202 /* RESIZEENABLE and VERTICALTAPS */
1203 l
&= ~((0x3 << 5) | (0x1 << 21));
1204 l
|= (orig_width
!= out_width
) ? (1 << 5) : 0;
1205 l
|= (orig_height
!= out_height
) ? (1 << 6) : 0;
1206 l
|= five_taps
? (1 << 21) : 0;
1208 /* VRESIZECONF and HRESIZECONF */
1209 if (dss_has_feature(FEAT_RESIZECONF
)) {
1211 l
|= (orig_width
<= out_width
) ? 0 : (1 << 7);
1212 l
|= (orig_height
<= out_height
) ? 0 : (1 << 8);
1215 /* LINEBUFFERSPLIT */
1216 if (dss_has_feature(FEAT_LINEBUFFERSPLIT
)) {
1218 l
|= five_taps
? (1 << 22) : 0;
1221 dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane
), l
);
1224 * field 0 = even field = bottom field
1225 * field 1 = odd field = top field
1227 if (ilace
&& !fieldmode
) {
1229 accu0
= ((1024 * orig_height
/ out_height
) / 2) & 0x3ff;
1230 if (accu0
>= 1024/2) {
1236 dispc_ovl_set_vid_accu0(plane
, 0, accu0
);
1237 dispc_ovl_set_vid_accu1(plane
, 0, accu1
);
1240 static void dispc_ovl_set_scaling_uv(enum omap_plane plane
,
1241 u16 orig_width
, u16 orig_height
,
1242 u16 out_width
, u16 out_height
,
1243 bool ilace
, bool five_taps
,
1244 bool fieldmode
, enum omap_color_mode color_mode
,
1247 int scale_x
= out_width
!= orig_width
;
1248 int scale_y
= out_height
!= orig_height
;
1250 if (!dss_has_feature(FEAT_HANDLE_UV_SEPARATE
))
1252 if ((color_mode
!= OMAP_DSS_COLOR_YUV2
&&
1253 color_mode
!= OMAP_DSS_COLOR_UYVY
&&
1254 color_mode
!= OMAP_DSS_COLOR_NV12
)) {
1255 /* reset chroma resampling for RGB formats */
1256 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES2(plane
), 0, 8, 8);
1259 switch (color_mode
) {
1260 case OMAP_DSS_COLOR_NV12
:
1261 /* UV is subsampled by 2 vertically*/
1263 /* UV is subsampled by 2 horz.*/
1266 case OMAP_DSS_COLOR_YUV2
:
1267 case OMAP_DSS_COLOR_UYVY
:
1268 /*For YUV422 with 90/270 rotation,
1269 *we don't upsample chroma
1271 if (rotation
== OMAP_DSS_ROT_0
||
1272 rotation
== OMAP_DSS_ROT_180
)
1273 /* UV is subsampled by 2 hrz*/
1275 /* must use FIR for YUV422 if rotated */
1276 if (rotation
!= OMAP_DSS_ROT_0
)
1277 scale_x
= scale_y
= true;
1283 if (out_width
!= orig_width
)
1285 if (out_height
!= orig_height
)
1288 dispc_ovl_set_scale_param(plane
, orig_width
, orig_height
,
1289 out_width
, out_height
, five_taps
,
1290 rotation
, DISPC_COLOR_COMPONENT_UV
);
1292 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES2(plane
),
1293 (scale_x
|| scale_y
) ? 1 : 0, 8, 8);
1295 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane
), scale_x
? 1 : 0, 5, 5);
1297 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane
), scale_y
? 1 : 0, 6, 6);
1299 dispc_ovl_set_vid_accu2_0(plane
, 0x80, 0);
1300 dispc_ovl_set_vid_accu2_1(plane
, 0x80, 0);
1303 static void dispc_ovl_set_scaling(enum omap_plane plane
,
1304 u16 orig_width
, u16 orig_height
,
1305 u16 out_width
, u16 out_height
,
1306 bool ilace
, bool five_taps
,
1307 bool fieldmode
, enum omap_color_mode color_mode
,
1310 BUG_ON(plane
== OMAP_DSS_GFX
);
1312 dispc_ovl_set_scaling_common(plane
,
1313 orig_width
, orig_height
,
1314 out_width
, out_height
,
1316 fieldmode
, color_mode
,
1319 dispc_ovl_set_scaling_uv(plane
,
1320 orig_width
, orig_height
,
1321 out_width
, out_height
,
1323 fieldmode
, color_mode
,
1327 static void dispc_ovl_set_rotation_attrs(enum omap_plane plane
, u8 rotation
,
1328 bool mirroring
, enum omap_color_mode color_mode
)
1330 bool row_repeat
= false;
1333 if (color_mode
== OMAP_DSS_COLOR_YUV2
||
1334 color_mode
== OMAP_DSS_COLOR_UYVY
) {
1338 case OMAP_DSS_ROT_0
:
1341 case OMAP_DSS_ROT_90
:
1344 case OMAP_DSS_ROT_180
:
1347 case OMAP_DSS_ROT_270
:
1353 case OMAP_DSS_ROT_0
:
1356 case OMAP_DSS_ROT_90
:
1359 case OMAP_DSS_ROT_180
:
1362 case OMAP_DSS_ROT_270
:
1368 if (rotation
== OMAP_DSS_ROT_90
|| rotation
== OMAP_DSS_ROT_270
)
1374 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane
), vidrot
, 13, 12);
1375 if (dss_has_feature(FEAT_ROWREPEATENABLE
))
1376 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane
),
1377 row_repeat
? 1 : 0, 18, 18);
1380 static int color_mode_to_bpp(enum omap_color_mode color_mode
)
1382 switch (color_mode
) {
1383 case OMAP_DSS_COLOR_CLUT1
:
1385 case OMAP_DSS_COLOR_CLUT2
:
1387 case OMAP_DSS_COLOR_CLUT4
:
1389 case OMAP_DSS_COLOR_CLUT8
:
1390 case OMAP_DSS_COLOR_NV12
:
1392 case OMAP_DSS_COLOR_RGB12U
:
1393 case OMAP_DSS_COLOR_RGB16
:
1394 case OMAP_DSS_COLOR_ARGB16
:
1395 case OMAP_DSS_COLOR_YUV2
:
1396 case OMAP_DSS_COLOR_UYVY
:
1397 case OMAP_DSS_COLOR_RGBA16
:
1398 case OMAP_DSS_COLOR_RGBX16
:
1399 case OMAP_DSS_COLOR_ARGB16_1555
:
1400 case OMAP_DSS_COLOR_XRGB16_1555
:
1402 case OMAP_DSS_COLOR_RGB24P
:
1404 case OMAP_DSS_COLOR_RGB24U
:
1405 case OMAP_DSS_COLOR_ARGB32
:
1406 case OMAP_DSS_COLOR_RGBA32
:
1407 case OMAP_DSS_COLOR_RGBX32
:
1414 static s32
pixinc(int pixels
, u8 ps
)
1418 else if (pixels
> 1)
1419 return 1 + (pixels
- 1) * ps
;
1420 else if (pixels
< 0)
1421 return 1 - (-pixels
+ 1) * ps
;
1426 static void calc_vrfb_rotation_offset(u8 rotation
, bool mirror
,
1428 u16 width
, u16 height
,
1429 enum omap_color_mode color_mode
, bool fieldmode
,
1430 unsigned int field_offset
,
1431 unsigned *offset0
, unsigned *offset1
,
1432 s32
*row_inc
, s32
*pix_inc
)
1436 /* FIXME CLUT formats */
1437 switch (color_mode
) {
1438 case OMAP_DSS_COLOR_CLUT1
:
1439 case OMAP_DSS_COLOR_CLUT2
:
1440 case OMAP_DSS_COLOR_CLUT4
:
1441 case OMAP_DSS_COLOR_CLUT8
:
1444 case OMAP_DSS_COLOR_YUV2
:
1445 case OMAP_DSS_COLOR_UYVY
:
1449 ps
= color_mode_to_bpp(color_mode
) / 8;
1453 DSSDBG("calc_rot(%d): scrw %d, %dx%d\n", rotation
, screen_width
,
1457 * field 0 = even field = bottom field
1458 * field 1 = odd field = top field
1460 switch (rotation
+ mirror
* 4) {
1461 case OMAP_DSS_ROT_0
:
1462 case OMAP_DSS_ROT_180
:
1464 * If the pixel format is YUV or UYVY divide the width
1465 * of the image by 2 for 0 and 180 degree rotation.
1467 if (color_mode
== OMAP_DSS_COLOR_YUV2
||
1468 color_mode
== OMAP_DSS_COLOR_UYVY
)
1470 case OMAP_DSS_ROT_90
:
1471 case OMAP_DSS_ROT_270
:
1474 *offset0
= field_offset
* screen_width
* ps
;
1478 *row_inc
= pixinc(1 + (screen_width
- width
) +
1479 (fieldmode
? screen_width
: 0),
1481 *pix_inc
= pixinc(1, ps
);
1484 case OMAP_DSS_ROT_0
+ 4:
1485 case OMAP_DSS_ROT_180
+ 4:
1486 /* If the pixel format is YUV or UYVY divide the width
1487 * of the image by 2 for 0 degree and 180 degree
1489 if (color_mode
== OMAP_DSS_COLOR_YUV2
||
1490 color_mode
== OMAP_DSS_COLOR_UYVY
)
1492 case OMAP_DSS_ROT_90
+ 4:
1493 case OMAP_DSS_ROT_270
+ 4:
1496 *offset0
= field_offset
* screen_width
* ps
;
1499 *row_inc
= pixinc(1 - (screen_width
+ width
) -
1500 (fieldmode
? screen_width
: 0),
1502 *pix_inc
= pixinc(1, ps
);
1510 static void calc_dma_rotation_offset(u8 rotation
, bool mirror
,
1512 u16 width
, u16 height
,
1513 enum omap_color_mode color_mode
, bool fieldmode
,
1514 unsigned int field_offset
,
1515 unsigned *offset0
, unsigned *offset1
,
1516 s32
*row_inc
, s32
*pix_inc
)
1521 /* FIXME CLUT formats */
1522 switch (color_mode
) {
1523 case OMAP_DSS_COLOR_CLUT1
:
1524 case OMAP_DSS_COLOR_CLUT2
:
1525 case OMAP_DSS_COLOR_CLUT4
:
1526 case OMAP_DSS_COLOR_CLUT8
:
1530 ps
= color_mode_to_bpp(color_mode
) / 8;
1534 DSSDBG("calc_rot(%d): scrw %d, %dx%d\n", rotation
, screen_width
,
1537 /* width & height are overlay sizes, convert to fb sizes */
1539 if (rotation
== OMAP_DSS_ROT_0
|| rotation
== OMAP_DSS_ROT_180
) {
1548 * field 0 = even field = bottom field
1549 * field 1 = odd field = top field
1551 switch (rotation
+ mirror
* 4) {
1552 case OMAP_DSS_ROT_0
:
1555 *offset0
= *offset1
+ field_offset
* screen_width
* ps
;
1557 *offset0
= *offset1
;
1558 *row_inc
= pixinc(1 + (screen_width
- fbw
) +
1559 (fieldmode
? screen_width
: 0),
1561 *pix_inc
= pixinc(1, ps
);
1563 case OMAP_DSS_ROT_90
:
1564 *offset1
= screen_width
* (fbh
- 1) * ps
;
1566 *offset0
= *offset1
+ field_offset
* ps
;
1568 *offset0
= *offset1
;
1569 *row_inc
= pixinc(screen_width
* (fbh
- 1) + 1 +
1570 (fieldmode
? 1 : 0), ps
);
1571 *pix_inc
= pixinc(-screen_width
, ps
);
1573 case OMAP_DSS_ROT_180
:
1574 *offset1
= (screen_width
* (fbh
- 1) + fbw
- 1) * ps
;
1576 *offset0
= *offset1
- field_offset
* screen_width
* ps
;
1578 *offset0
= *offset1
;
1579 *row_inc
= pixinc(-1 -
1580 (screen_width
- fbw
) -
1581 (fieldmode
? screen_width
: 0),
1583 *pix_inc
= pixinc(-1, ps
);
1585 case OMAP_DSS_ROT_270
:
1586 *offset1
= (fbw
- 1) * ps
;
1588 *offset0
= *offset1
- field_offset
* ps
;
1590 *offset0
= *offset1
;
1591 *row_inc
= pixinc(-screen_width
* (fbh
- 1) - 1 -
1592 (fieldmode
? 1 : 0), ps
);
1593 *pix_inc
= pixinc(screen_width
, ps
);
1597 case OMAP_DSS_ROT_0
+ 4:
1598 *offset1
= (fbw
- 1) * ps
;
1600 *offset0
= *offset1
+ field_offset
* screen_width
* ps
;
1602 *offset0
= *offset1
;
1603 *row_inc
= pixinc(screen_width
* 2 - 1 +
1604 (fieldmode
? screen_width
: 0),
1606 *pix_inc
= pixinc(-1, ps
);
1609 case OMAP_DSS_ROT_90
+ 4:
1612 *offset0
= *offset1
+ field_offset
* ps
;
1614 *offset0
= *offset1
;
1615 *row_inc
= pixinc(-screen_width
* (fbh
- 1) + 1 +
1616 (fieldmode
? 1 : 0),
1618 *pix_inc
= pixinc(screen_width
, ps
);
1621 case OMAP_DSS_ROT_180
+ 4:
1622 *offset1
= screen_width
* (fbh
- 1) * ps
;
1624 *offset0
= *offset1
- field_offset
* screen_width
* ps
;
1626 *offset0
= *offset1
;
1627 *row_inc
= pixinc(1 - screen_width
* 2 -
1628 (fieldmode
? screen_width
: 0),
1630 *pix_inc
= pixinc(1, ps
);
1633 case OMAP_DSS_ROT_270
+ 4:
1634 *offset1
= (screen_width
* (fbh
- 1) + fbw
- 1) * ps
;
1636 *offset0
= *offset1
- field_offset
* ps
;
1638 *offset0
= *offset1
;
1639 *row_inc
= pixinc(screen_width
* (fbh
- 1) - 1 -
1640 (fieldmode
? 1 : 0),
1642 *pix_inc
= pixinc(-screen_width
, ps
);
1650 static unsigned long calc_fclk_five_taps(enum omap_channel channel
, u16 width
,
1651 u16 height
, u16 out_width
, u16 out_height
,
1652 enum omap_color_mode color_mode
)
1655 u64 tmp
, pclk
= dispc_mgr_pclk_rate(channel
);
1657 if (height
> out_height
) {
1658 struct omap_dss_device
*dssdev
= dispc_mgr_get_device(channel
);
1659 unsigned int ppl
= dssdev
->panel
.timings
.x_res
;
1661 tmp
= pclk
* height
* out_width
;
1662 do_div(tmp
, 2 * out_height
* ppl
);
1665 if (height
> 2 * out_height
) {
1666 if (ppl
== out_width
)
1669 tmp
= pclk
* (height
- 2 * out_height
) * out_width
;
1670 do_div(tmp
, 2 * out_height
* (ppl
- out_width
));
1671 fclk
= max(fclk
, (u32
) tmp
);
1675 if (width
> out_width
) {
1677 do_div(tmp
, out_width
);
1678 fclk
= max(fclk
, (u32
) tmp
);
1680 if (color_mode
== OMAP_DSS_COLOR_RGB24U
)
1687 static unsigned long calc_fclk(enum omap_channel channel
, u16 width
,
1688 u16 height
, u16 out_width
, u16 out_height
)
1690 unsigned int hf
, vf
;
1693 * FIXME how to determine the 'A' factor
1694 * for the no downscaling case ?
1697 if (width
> 3 * out_width
)
1699 else if (width
> 2 * out_width
)
1701 else if (width
> out_width
)
1706 if (height
> out_height
)
1711 return dispc_mgr_pclk_rate(channel
) * vf
* hf
;
1714 static int dispc_ovl_calc_scaling(enum omap_plane plane
,
1715 enum omap_channel channel
, u16 width
, u16 height
,
1716 u16 out_width
, u16 out_height
,
1717 enum omap_color_mode color_mode
, bool *five_taps
)
1719 struct omap_overlay
*ovl
= omap_dss_get_overlay(plane
);
1720 const int maxdownscale
= dss_feat_get_param_max(FEAT_PARAM_DOWNSCALE
);
1721 unsigned long fclk
= 0;
1723 if ((ovl
->caps
& OMAP_DSS_OVL_CAP_SCALE
) == 0) {
1724 if (width
!= out_width
|| height
!= out_height
)
1730 if (out_width
< width
/ maxdownscale
||
1731 out_width
> width
* 8)
1734 if (out_height
< height
/ maxdownscale
||
1735 out_height
> height
* 8)
1738 /* Must use 5-tap filter? */
1739 *five_taps
= height
> out_height
* 2;
1742 fclk
= calc_fclk(channel
, width
, height
, out_width
,
1745 /* Try 5-tap filter if 3-tap fclk is too high */
1746 if (cpu_is_omap34xx() && height
> out_height
&&
1747 fclk
> dispc_fclk_rate())
1751 if (width
> (2048 >> *five_taps
)) {
1752 DSSERR("failed to set up scaling, fclk too low\n");
1757 fclk
= calc_fclk_five_taps(channel
, width
, height
,
1758 out_width
, out_height
, color_mode
);
1760 DSSDBG("required fclk rate = %lu Hz\n", fclk
);
1761 DSSDBG("current fclk rate = %lu Hz\n", dispc_fclk_rate());
1763 if (!fclk
|| fclk
> dispc_fclk_rate()) {
1764 DSSERR("failed to set up scaling, "
1765 "required fclk rate = %lu Hz, "
1766 "current fclk rate = %lu Hz\n",
1767 fclk
, dispc_fclk_rate());
1774 int dispc_ovl_setup(enum omap_plane plane
, struct omap_overlay_info
*oi
,
1775 bool ilace
, enum omap_channel channel
, bool replication
,
1776 u32 fifo_low
, u32 fifo_high
)
1778 struct omap_overlay
*ovl
= omap_dss_get_overlay(plane
);
1779 bool five_taps
= false;
1782 unsigned offset0
, offset1
;
1785 u16 frame_height
= oi
->height
;
1786 unsigned int field_offset
= 0;
1788 DSSDBG("dispc_ovl_setup %d, pa %x, pa_uv %x, sw %d, %d,%d, %dx%d -> "
1789 "%dx%d, cmode %x, rot %d, mir %d, ilace %d chan %d repl %d "
1790 "fifo_low %d fifo high %d\n", plane
, oi
->paddr
, oi
->p_uv_addr
,
1791 oi
->screen_width
, oi
->pos_x
, oi
->pos_y
, oi
->width
, oi
->height
,
1792 oi
->out_width
, oi
->out_height
, oi
->color_mode
, oi
->rotation
,
1793 oi
->mirror
, ilace
, channel
, replication
, fifo_low
, fifo_high
);
1798 if (ilace
&& oi
->height
== oi
->out_height
)
1805 oi
->out_height
/= 2;
1807 DSSDBG("adjusting for ilace: height %d, pos_y %d, "
1809 oi
->height
, oi
->pos_y
, oi
->out_height
);
1812 if (!dss_feat_color_mode_supported(plane
, oi
->color_mode
))
1815 r
= dispc_ovl_calc_scaling(plane
, channel
, oi
->width
, oi
->height
,
1816 oi
->out_width
, oi
->out_height
, oi
->color_mode
,
1821 if (oi
->color_mode
== OMAP_DSS_COLOR_YUV2
||
1822 oi
->color_mode
== OMAP_DSS_COLOR_UYVY
||
1823 oi
->color_mode
== OMAP_DSS_COLOR_NV12
)
1826 if (ilace
&& !fieldmode
) {
1828 * when downscaling the bottom field may have to start several
1829 * source lines below the top field. Unfortunately ACCUI
1830 * registers will only hold the fractional part of the offset
1831 * so the integer part must be added to the base address of the
1834 if (!oi
->height
|| oi
->height
== oi
->out_height
)
1837 field_offset
= oi
->height
/ oi
->out_height
/ 2;
1840 /* Fields are independent but interleaved in memory. */
1844 if (oi
->rotation_type
== OMAP_DSS_ROT_DMA
)
1845 calc_dma_rotation_offset(oi
->rotation
, oi
->mirror
,
1846 oi
->screen_width
, oi
->width
, frame_height
,
1847 oi
->color_mode
, fieldmode
, field_offset
,
1848 &offset0
, &offset1
, &row_inc
, &pix_inc
);
1850 calc_vrfb_rotation_offset(oi
->rotation
, oi
->mirror
,
1851 oi
->screen_width
, oi
->width
, frame_height
,
1852 oi
->color_mode
, fieldmode
, field_offset
,
1853 &offset0
, &offset1
, &row_inc
, &pix_inc
);
1855 DSSDBG("offset0 %u, offset1 %u, row_inc %d, pix_inc %d\n",
1856 offset0
, offset1
, row_inc
, pix_inc
);
1858 dispc_ovl_set_color_mode(plane
, oi
->color_mode
);
1860 dispc_ovl_set_ba0(plane
, oi
->paddr
+ offset0
);
1861 dispc_ovl_set_ba1(plane
, oi
->paddr
+ offset1
);
1863 if (OMAP_DSS_COLOR_NV12
== oi
->color_mode
) {
1864 dispc_ovl_set_ba0_uv(plane
, oi
->p_uv_addr
+ offset0
);
1865 dispc_ovl_set_ba1_uv(plane
, oi
->p_uv_addr
+ offset1
);
1869 dispc_ovl_set_row_inc(plane
, row_inc
);
1870 dispc_ovl_set_pix_inc(plane
, pix_inc
);
1872 DSSDBG("%d,%d %dx%d -> %dx%d\n", oi
->pos_x
, oi
->pos_y
, oi
->width
,
1873 oi
->height
, oi
->out_width
, oi
->out_height
);
1875 dispc_ovl_set_pos(plane
, oi
->pos_x
, oi
->pos_y
);
1877 dispc_ovl_set_pic_size(plane
, oi
->width
, oi
->height
);
1879 if (ovl
->caps
& OMAP_DSS_OVL_CAP_SCALE
) {
1880 dispc_ovl_set_scaling(plane
, oi
->width
, oi
->height
,
1881 oi
->out_width
, oi
->out_height
,
1882 ilace
, five_taps
, fieldmode
,
1883 oi
->color_mode
, oi
->rotation
);
1884 dispc_ovl_set_vid_size(plane
, oi
->out_width
, oi
->out_height
);
1885 dispc_ovl_set_vid_color_conv(plane
, cconv
);
1888 dispc_ovl_set_rotation_attrs(plane
, oi
->rotation
, oi
->mirror
,
1891 dispc_ovl_set_zorder(plane
, oi
->zorder
);
1892 dispc_ovl_set_pre_mult_alpha(plane
, oi
->pre_mult_alpha
);
1893 dispc_ovl_setup_global_alpha(plane
, oi
->global_alpha
);
1895 dispc_ovl_set_channel_out(plane
, channel
);
1897 dispc_ovl_enable_replication(plane
, replication
);
1898 dispc_ovl_set_fifo_threshold(plane
, fifo_low
, fifo_high
);
1903 int dispc_ovl_enable(enum omap_plane plane
, bool enable
)
1905 DSSDBG("dispc_enable_plane %d, %d\n", plane
, enable
);
1907 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane
), enable
? 1 : 0, 0, 0);
1912 static void dispc_disable_isr(void *data
, u32 mask
)
1914 struct completion
*compl = data
;
1918 static void _enable_lcd_out(enum omap_channel channel
, bool enable
)
1920 if (channel
== OMAP_DSS_CHANNEL_LCD2
)
1921 REG_FLD_MOD(DISPC_CONTROL2
, enable
? 1 : 0, 0, 0);
1923 REG_FLD_MOD(DISPC_CONTROL
, enable
? 1 : 0, 0, 0);
1926 static void dispc_mgr_enable_lcd_out(enum omap_channel channel
, bool enable
)
1928 struct completion frame_done_completion
;
1933 /* When we disable LCD output, we need to wait until frame is done.
1934 * Otherwise the DSS is still working, and turning off the clocks
1935 * prevents DSS from going to OFF mode */
1936 is_on
= channel
== OMAP_DSS_CHANNEL_LCD2
?
1937 REG_GET(DISPC_CONTROL2
, 0, 0) :
1938 REG_GET(DISPC_CONTROL
, 0, 0);
1940 irq
= channel
== OMAP_DSS_CHANNEL_LCD2
? DISPC_IRQ_FRAMEDONE2
:
1941 DISPC_IRQ_FRAMEDONE
;
1943 if (!enable
&& is_on
) {
1944 init_completion(&frame_done_completion
);
1946 r
= omap_dispc_register_isr(dispc_disable_isr
,
1947 &frame_done_completion
, irq
);
1950 DSSERR("failed to register FRAMEDONE isr\n");
1953 _enable_lcd_out(channel
, enable
);
1955 if (!enable
&& is_on
) {
1956 if (!wait_for_completion_timeout(&frame_done_completion
,
1957 msecs_to_jiffies(100)))
1958 DSSERR("timeout waiting for FRAME DONE\n");
1960 r
= omap_dispc_unregister_isr(dispc_disable_isr
,
1961 &frame_done_completion
, irq
);
1964 DSSERR("failed to unregister FRAMEDONE isr\n");
1968 static void _enable_digit_out(bool enable
)
1970 REG_FLD_MOD(DISPC_CONTROL
, enable
? 1 : 0, 1, 1);
1973 static void dispc_mgr_enable_digit_out(bool enable
)
1975 struct completion frame_done_completion
;
1976 enum dss_hdmi_venc_clk_source_select src
;
1981 if (REG_GET(DISPC_CONTROL
, 1, 1) == enable
)
1984 src
= dss_get_hdmi_venc_clk_source();
1987 unsigned long flags
;
1988 /* When we enable digit output, we'll get an extra digit
1989 * sync lost interrupt, that we need to ignore */
1990 spin_lock_irqsave(&dispc
.irq_lock
, flags
);
1991 dispc
.irq_error_mask
&= ~DISPC_IRQ_SYNC_LOST_DIGIT
;
1992 _omap_dispc_set_irqs();
1993 spin_unlock_irqrestore(&dispc
.irq_lock
, flags
);
1996 /* When we disable digit output, we need to wait until fields are done.
1997 * Otherwise the DSS is still working, and turning off the clocks
1998 * prevents DSS from going to OFF mode. And when enabling, we need to
1999 * wait for the extra sync losts */
2000 init_completion(&frame_done_completion
);
2002 if (src
== DSS_HDMI_M_PCLK
&& enable
== false) {
2003 irq_mask
= DISPC_IRQ_FRAMEDONETV
;
2006 irq_mask
= DISPC_IRQ_EVSYNC_EVEN
| DISPC_IRQ_EVSYNC_ODD
;
2007 /* XXX I understand from TRM that we should only wait for the
2008 * current field to complete. But it seems we have to wait for
2013 r
= omap_dispc_register_isr(dispc_disable_isr
, &frame_done_completion
,
2016 DSSERR("failed to register %x isr\n", irq_mask
);
2018 _enable_digit_out(enable
);
2020 for (i
= 0; i
< num_irqs
; ++i
) {
2021 if (!wait_for_completion_timeout(&frame_done_completion
,
2022 msecs_to_jiffies(100)))
2023 DSSERR("timeout waiting for digit out to %s\n",
2024 enable
? "start" : "stop");
2027 r
= omap_dispc_unregister_isr(dispc_disable_isr
, &frame_done_completion
,
2030 DSSERR("failed to unregister %x isr\n", irq_mask
);
2033 unsigned long flags
;
2034 spin_lock_irqsave(&dispc
.irq_lock
, flags
);
2035 dispc
.irq_error_mask
|= DISPC_IRQ_SYNC_LOST_DIGIT
;
2036 dispc_write_reg(DISPC_IRQSTATUS
, DISPC_IRQ_SYNC_LOST_DIGIT
);
2037 _omap_dispc_set_irqs();
2038 spin_unlock_irqrestore(&dispc
.irq_lock
, flags
);
2042 bool dispc_mgr_is_enabled(enum omap_channel channel
)
2044 if (channel
== OMAP_DSS_CHANNEL_LCD
)
2045 return !!REG_GET(DISPC_CONTROL
, 0, 0);
2046 else if (channel
== OMAP_DSS_CHANNEL_DIGIT
)
2047 return !!REG_GET(DISPC_CONTROL
, 1, 1);
2048 else if (channel
== OMAP_DSS_CHANNEL_LCD2
)
2049 return !!REG_GET(DISPC_CONTROL2
, 0, 0);
2054 void dispc_mgr_enable(enum omap_channel channel
, bool enable
)
2056 if (dispc_mgr_is_lcd(channel
))
2057 dispc_mgr_enable_lcd_out(channel
, enable
);
2058 else if (channel
== OMAP_DSS_CHANNEL_DIGIT
)
2059 dispc_mgr_enable_digit_out(enable
);
2064 void dispc_lcd_enable_signal_polarity(bool act_high
)
2066 if (!dss_has_feature(FEAT_LCDENABLEPOL
))
2069 REG_FLD_MOD(DISPC_CONTROL
, act_high
? 1 : 0, 29, 29);
2072 void dispc_lcd_enable_signal(bool enable
)
2074 if (!dss_has_feature(FEAT_LCDENABLESIGNAL
))
2077 REG_FLD_MOD(DISPC_CONTROL
, enable
? 1 : 0, 28, 28);
2080 void dispc_pck_free_enable(bool enable
)
2082 if (!dss_has_feature(FEAT_PCKFREEENABLE
))
2085 REG_FLD_MOD(DISPC_CONTROL
, enable
? 1 : 0, 27, 27);
2088 void dispc_mgr_enable_fifohandcheck(enum omap_channel channel
, bool enable
)
2090 if (channel
== OMAP_DSS_CHANNEL_LCD2
)
2091 REG_FLD_MOD(DISPC_CONFIG2
, enable
? 1 : 0, 16, 16);
2093 REG_FLD_MOD(DISPC_CONFIG
, enable
? 1 : 0, 16, 16);
2097 void dispc_mgr_set_lcd_display_type(enum omap_channel channel
,
2098 enum omap_lcd_display_type type
)
2103 case OMAP_DSS_LCD_DISPLAY_STN
:
2107 case OMAP_DSS_LCD_DISPLAY_TFT
:
2116 if (channel
== OMAP_DSS_CHANNEL_LCD2
)
2117 REG_FLD_MOD(DISPC_CONTROL2
, mode
, 3, 3);
2119 REG_FLD_MOD(DISPC_CONTROL
, mode
, 3, 3);
2122 void dispc_set_loadmode(enum omap_dss_load_mode mode
)
2124 REG_FLD_MOD(DISPC_CONFIG
, mode
, 2, 1);
2128 void dispc_mgr_set_default_color(enum omap_channel channel
, u32 color
)
2130 dispc_write_reg(DISPC_DEFAULT_COLOR(channel
), color
);
2133 u32
dispc_mgr_get_default_color(enum omap_channel channel
)
2137 BUG_ON(channel
!= OMAP_DSS_CHANNEL_DIGIT
&&
2138 channel
!= OMAP_DSS_CHANNEL_LCD
&&
2139 channel
!= OMAP_DSS_CHANNEL_LCD2
);
2141 l
= dispc_read_reg(DISPC_DEFAULT_COLOR(channel
));
2146 void dispc_mgr_set_trans_key(enum omap_channel ch
,
2147 enum omap_dss_trans_key_type type
,
2150 if (ch
== OMAP_DSS_CHANNEL_LCD
)
2151 REG_FLD_MOD(DISPC_CONFIG
, type
, 11, 11);
2152 else if (ch
== OMAP_DSS_CHANNEL_DIGIT
)
2153 REG_FLD_MOD(DISPC_CONFIG
, type
, 13, 13);
2154 else /* OMAP_DSS_CHANNEL_LCD2 */
2155 REG_FLD_MOD(DISPC_CONFIG2
, type
, 11, 11);
2157 dispc_write_reg(DISPC_TRANS_COLOR(ch
), trans_key
);
2160 void dispc_mgr_get_trans_key(enum omap_channel ch
,
2161 enum omap_dss_trans_key_type
*type
,
2165 if (ch
== OMAP_DSS_CHANNEL_LCD
)
2166 *type
= REG_GET(DISPC_CONFIG
, 11, 11);
2167 else if (ch
== OMAP_DSS_CHANNEL_DIGIT
)
2168 *type
= REG_GET(DISPC_CONFIG
, 13, 13);
2169 else if (ch
== OMAP_DSS_CHANNEL_LCD2
)
2170 *type
= REG_GET(DISPC_CONFIG2
, 11, 11);
2176 *trans_key
= dispc_read_reg(DISPC_TRANS_COLOR(ch
));
2179 void dispc_mgr_enable_trans_key(enum omap_channel ch
, bool enable
)
2181 if (ch
== OMAP_DSS_CHANNEL_LCD
)
2182 REG_FLD_MOD(DISPC_CONFIG
, enable
, 10, 10);
2183 else if (ch
== OMAP_DSS_CHANNEL_DIGIT
)
2184 REG_FLD_MOD(DISPC_CONFIG
, enable
, 12, 12);
2185 else /* OMAP_DSS_CHANNEL_LCD2 */
2186 REG_FLD_MOD(DISPC_CONFIG2
, enable
, 10, 10);
2189 void dispc_mgr_enable_alpha_fixed_zorder(enum omap_channel ch
, bool enable
)
2191 if (!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER
))
2194 if (ch
== OMAP_DSS_CHANNEL_LCD
)
2195 REG_FLD_MOD(DISPC_CONFIG
, enable
, 18, 18);
2196 else if (ch
== OMAP_DSS_CHANNEL_DIGIT
)
2197 REG_FLD_MOD(DISPC_CONFIG
, enable
, 19, 19);
2200 bool dispc_mgr_alpha_fixed_zorder_enabled(enum omap_channel ch
)
2204 if (!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER
))
2207 if (ch
== OMAP_DSS_CHANNEL_LCD
)
2208 enabled
= REG_GET(DISPC_CONFIG
, 18, 18);
2209 else if (ch
== OMAP_DSS_CHANNEL_DIGIT
)
2210 enabled
= REG_GET(DISPC_CONFIG
, 19, 19);
2217 bool dispc_mgr_trans_key_enabled(enum omap_channel ch
)
2221 if (ch
== OMAP_DSS_CHANNEL_LCD
)
2222 enabled
= REG_GET(DISPC_CONFIG
, 10, 10);
2223 else if (ch
== OMAP_DSS_CHANNEL_DIGIT
)
2224 enabled
= REG_GET(DISPC_CONFIG
, 12, 12);
2225 else if (ch
== OMAP_DSS_CHANNEL_LCD2
)
2226 enabled
= REG_GET(DISPC_CONFIG2
, 10, 10);
2234 void dispc_mgr_set_tft_data_lines(enum omap_channel channel
, u8 data_lines
)
2238 switch (data_lines
) {
2256 if (channel
== OMAP_DSS_CHANNEL_LCD2
)
2257 REG_FLD_MOD(DISPC_CONTROL2
, code
, 9, 8);
2259 REG_FLD_MOD(DISPC_CONTROL
, code
, 9, 8);
2262 void dispc_mgr_set_io_pad_mode(enum dss_io_pad_mode mode
)
2268 case DSS_IO_PAD_MODE_RESET
:
2272 case DSS_IO_PAD_MODE_RFBI
:
2276 case DSS_IO_PAD_MODE_BYPASS
:
2285 l
= dispc_read_reg(DISPC_CONTROL
);
2286 l
= FLD_MOD(l
, gpout0
, 15, 15);
2287 l
= FLD_MOD(l
, gpout1
, 16, 16);
2288 dispc_write_reg(DISPC_CONTROL
, l
);
2291 void dispc_mgr_enable_stallmode(enum omap_channel channel
, bool enable
)
2293 if (channel
== OMAP_DSS_CHANNEL_LCD2
)
2294 REG_FLD_MOD(DISPC_CONTROL2
, enable
, 11, 11);
2296 REG_FLD_MOD(DISPC_CONTROL
, enable
, 11, 11);
2299 static bool _dispc_lcd_timings_ok(int hsw
, int hfp
, int hbp
,
2300 int vsw
, int vfp
, int vbp
)
2302 if (cpu_is_omap24xx() || omap_rev() < OMAP3430_REV_ES3_0
) {
2303 if (hsw
< 1 || hsw
> 64 ||
2304 hfp
< 1 || hfp
> 256 ||
2305 hbp
< 1 || hbp
> 256 ||
2306 vsw
< 1 || vsw
> 64 ||
2307 vfp
< 0 || vfp
> 255 ||
2308 vbp
< 0 || vbp
> 255)
2311 if (hsw
< 1 || hsw
> 256 ||
2312 hfp
< 1 || hfp
> 4096 ||
2313 hbp
< 1 || hbp
> 4096 ||
2314 vsw
< 1 || vsw
> 256 ||
2315 vfp
< 0 || vfp
> 4095 ||
2316 vbp
< 0 || vbp
> 4095)
2323 bool dispc_lcd_timings_ok(struct omap_video_timings
*timings
)
2325 return _dispc_lcd_timings_ok(timings
->hsw
, timings
->hfp
,
2326 timings
->hbp
, timings
->vsw
,
2327 timings
->vfp
, timings
->vbp
);
2330 static void _dispc_mgr_set_lcd_timings(enum omap_channel channel
, int hsw
,
2331 int hfp
, int hbp
, int vsw
, int vfp
, int vbp
)
2333 u32 timing_h
, timing_v
;
2335 if (cpu_is_omap24xx() || omap_rev() < OMAP3430_REV_ES3_0
) {
2336 timing_h
= FLD_VAL(hsw
-1, 5, 0) | FLD_VAL(hfp
-1, 15, 8) |
2337 FLD_VAL(hbp
-1, 27, 20);
2339 timing_v
= FLD_VAL(vsw
-1, 5, 0) | FLD_VAL(vfp
, 15, 8) |
2340 FLD_VAL(vbp
, 27, 20);
2342 timing_h
= FLD_VAL(hsw
-1, 7, 0) | FLD_VAL(hfp
-1, 19, 8) |
2343 FLD_VAL(hbp
-1, 31, 20);
2345 timing_v
= FLD_VAL(vsw
-1, 7, 0) | FLD_VAL(vfp
, 19, 8) |
2346 FLD_VAL(vbp
, 31, 20);
2349 dispc_write_reg(DISPC_TIMING_H(channel
), timing_h
);
2350 dispc_write_reg(DISPC_TIMING_V(channel
), timing_v
);
2353 /* change name to mode? */
2354 void dispc_mgr_set_lcd_timings(enum omap_channel channel
,
2355 struct omap_video_timings
*timings
)
2357 unsigned xtot
, ytot
;
2358 unsigned long ht
, vt
;
2360 if (!_dispc_lcd_timings_ok(timings
->hsw
, timings
->hfp
,
2361 timings
->hbp
, timings
->vsw
,
2362 timings
->vfp
, timings
->vbp
))
2365 _dispc_mgr_set_lcd_timings(channel
, timings
->hsw
, timings
->hfp
,
2366 timings
->hbp
, timings
->vsw
, timings
->vfp
,
2369 dispc_mgr_set_lcd_size(channel
, timings
->x_res
, timings
->y_res
);
2371 xtot
= timings
->x_res
+ timings
->hfp
+ timings
->hsw
+ timings
->hbp
;
2372 ytot
= timings
->y_res
+ timings
->vfp
+ timings
->vsw
+ timings
->vbp
;
2374 ht
= (timings
->pixel_clock
* 1000) / xtot
;
2375 vt
= (timings
->pixel_clock
* 1000) / xtot
/ ytot
;
2377 DSSDBG("channel %d xres %u yres %u\n", channel
, timings
->x_res
,
2379 DSSDBG("pck %u\n", timings
->pixel_clock
);
2380 DSSDBG("hsw %d hfp %d hbp %d vsw %d vfp %d vbp %d\n",
2381 timings
->hsw
, timings
->hfp
, timings
->hbp
,
2382 timings
->vsw
, timings
->vfp
, timings
->vbp
);
2384 DSSDBG("hsync %luHz, vsync %luHz\n", ht
, vt
);
2387 static void dispc_mgr_set_lcd_divisor(enum omap_channel channel
, u16 lck_div
,
2390 BUG_ON(lck_div
< 1);
2391 BUG_ON(pck_div
< 1);
2393 dispc_write_reg(DISPC_DIVISORo(channel
),
2394 FLD_VAL(lck_div
, 23, 16) | FLD_VAL(pck_div
, 7, 0));
2397 static void dispc_mgr_get_lcd_divisor(enum omap_channel channel
, int *lck_div
,
2401 l
= dispc_read_reg(DISPC_DIVISORo(channel
));
2402 *lck_div
= FLD_GET(l
, 23, 16);
2403 *pck_div
= FLD_GET(l
, 7, 0);
2406 unsigned long dispc_fclk_rate(void)
2408 struct platform_device
*dsidev
;
2409 unsigned long r
= 0;
2411 switch (dss_get_dispc_clk_source()) {
2412 case OMAP_DSS_CLK_SRC_FCK
:
2413 r
= clk_get_rate(dispc
.dss_clk
);
2415 case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC
:
2416 dsidev
= dsi_get_dsidev_from_id(0);
2417 r
= dsi_get_pll_hsdiv_dispc_rate(dsidev
);
2419 case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC
:
2420 dsidev
= dsi_get_dsidev_from_id(1);
2421 r
= dsi_get_pll_hsdiv_dispc_rate(dsidev
);
2430 unsigned long dispc_mgr_lclk_rate(enum omap_channel channel
)
2432 struct platform_device
*dsidev
;
2437 l
= dispc_read_reg(DISPC_DIVISORo(channel
));
2439 lcd
= FLD_GET(l
, 23, 16);
2441 switch (dss_get_lcd_clk_source(channel
)) {
2442 case OMAP_DSS_CLK_SRC_FCK
:
2443 r
= clk_get_rate(dispc
.dss_clk
);
2445 case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC
:
2446 dsidev
= dsi_get_dsidev_from_id(0);
2447 r
= dsi_get_pll_hsdiv_dispc_rate(dsidev
);
2449 case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC
:
2450 dsidev
= dsi_get_dsidev_from_id(1);
2451 r
= dsi_get_pll_hsdiv_dispc_rate(dsidev
);
2460 unsigned long dispc_mgr_pclk_rate(enum omap_channel channel
)
2464 if (dispc_mgr_is_lcd(channel
)) {
2468 l
= dispc_read_reg(DISPC_DIVISORo(channel
));
2470 pcd
= FLD_GET(l
, 7, 0);
2472 r
= dispc_mgr_lclk_rate(channel
);
2476 struct omap_dss_device
*dssdev
=
2477 dispc_mgr_get_device(channel
);
2479 switch (dssdev
->type
) {
2480 case OMAP_DISPLAY_TYPE_VENC
:
2481 return venc_get_pixel_clock();
2482 case OMAP_DISPLAY_TYPE_HDMI
:
2483 return hdmi_get_pixel_clock();
2490 void dispc_dump_clocks(struct seq_file
*s
)
2494 enum omap_dss_clk_source dispc_clk_src
= dss_get_dispc_clk_source();
2495 enum omap_dss_clk_source lcd_clk_src
;
2497 if (dispc_runtime_get())
2500 seq_printf(s
, "- DISPC -\n");
2502 seq_printf(s
, "dispc fclk source = %s (%s)\n",
2503 dss_get_generic_clk_source_name(dispc_clk_src
),
2504 dss_feat_get_clk_source_name(dispc_clk_src
));
2506 seq_printf(s
, "fck\t\t%-16lu\n", dispc_fclk_rate());
2508 if (dss_has_feature(FEAT_CORE_CLK_DIV
)) {
2509 seq_printf(s
, "- DISPC-CORE-CLK -\n");
2510 l
= dispc_read_reg(DISPC_DIVISOR
);
2511 lcd
= FLD_GET(l
, 23, 16);
2513 seq_printf(s
, "lck\t\t%-16lulck div\t%u\n",
2514 (dispc_fclk_rate()/lcd
), lcd
);
2516 seq_printf(s
, "- LCD1 -\n");
2518 lcd_clk_src
= dss_get_lcd_clk_source(OMAP_DSS_CHANNEL_LCD
);
2520 seq_printf(s
, "lcd1_clk source = %s (%s)\n",
2521 dss_get_generic_clk_source_name(lcd_clk_src
),
2522 dss_feat_get_clk_source_name(lcd_clk_src
));
2524 dispc_mgr_get_lcd_divisor(OMAP_DSS_CHANNEL_LCD
, &lcd
, &pcd
);
2526 seq_printf(s
, "lck\t\t%-16lulck div\t%u\n",
2527 dispc_mgr_lclk_rate(OMAP_DSS_CHANNEL_LCD
), lcd
);
2528 seq_printf(s
, "pck\t\t%-16lupck div\t%u\n",
2529 dispc_mgr_pclk_rate(OMAP_DSS_CHANNEL_LCD
), pcd
);
2530 if (dss_has_feature(FEAT_MGR_LCD2
)) {
2531 seq_printf(s
, "- LCD2 -\n");
2533 lcd_clk_src
= dss_get_lcd_clk_source(OMAP_DSS_CHANNEL_LCD2
);
2535 seq_printf(s
, "lcd2_clk source = %s (%s)\n",
2536 dss_get_generic_clk_source_name(lcd_clk_src
),
2537 dss_feat_get_clk_source_name(lcd_clk_src
));
2539 dispc_mgr_get_lcd_divisor(OMAP_DSS_CHANNEL_LCD2
, &lcd
, &pcd
);
2541 seq_printf(s
, "lck\t\t%-16lulck div\t%u\n",
2542 dispc_mgr_lclk_rate(OMAP_DSS_CHANNEL_LCD2
), lcd
);
2543 seq_printf(s
, "pck\t\t%-16lupck div\t%u\n",
2544 dispc_mgr_pclk_rate(OMAP_DSS_CHANNEL_LCD2
), pcd
);
2547 dispc_runtime_put();
2550 #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
2551 void dispc_dump_irqs(struct seq_file
*s
)
2553 unsigned long flags
;
2554 struct dispc_irq_stats stats
;
2556 spin_lock_irqsave(&dispc
.irq_stats_lock
, flags
);
2558 stats
= dispc
.irq_stats
;
2559 memset(&dispc
.irq_stats
, 0, sizeof(dispc
.irq_stats
));
2560 dispc
.irq_stats
.last_reset
= jiffies
;
2562 spin_unlock_irqrestore(&dispc
.irq_stats_lock
, flags
);
2564 seq_printf(s
, "period %u ms\n",
2565 jiffies_to_msecs(jiffies
- stats
.last_reset
));
2567 seq_printf(s
, "irqs %d\n", stats
.irq_count
);
2569 seq_printf(s, "%-20s %10d\n", #x, stats.irqs[ffs(DISPC_IRQ_##x)-1]);
2575 PIS(ACBIAS_COUNT_STAT
);
2577 PIS(GFX_FIFO_UNDERFLOW
);
2579 PIS(PAL_GAMMA_MASK
);
2581 PIS(VID1_FIFO_UNDERFLOW
);
2583 PIS(VID2_FIFO_UNDERFLOW
);
2585 if (dss_feat_get_num_ovls() > 3) {
2586 PIS(VID3_FIFO_UNDERFLOW
);
2590 PIS(SYNC_LOST_DIGIT
);
2592 if (dss_has_feature(FEAT_MGR_LCD2
)) {
2595 PIS(ACBIAS_COUNT_STAT2
);
2602 void dispc_dump_regs(struct seq_file
*s
)
2605 const char *mgr_names
[] = {
2606 [OMAP_DSS_CHANNEL_LCD
] = "LCD",
2607 [OMAP_DSS_CHANNEL_DIGIT
] = "TV",
2608 [OMAP_DSS_CHANNEL_LCD2
] = "LCD2",
2610 const char *ovl_names
[] = {
2611 [OMAP_DSS_GFX
] = "GFX",
2612 [OMAP_DSS_VIDEO1
] = "VID1",
2613 [OMAP_DSS_VIDEO2
] = "VID2",
2614 [OMAP_DSS_VIDEO3
] = "VID3",
2616 const char **p_names
;
2618 #define DUMPREG(r) seq_printf(s, "%-50s %08x\n", #r, dispc_read_reg(r))
2620 if (dispc_runtime_get())
2623 /* DISPC common registers */
2624 DUMPREG(DISPC_REVISION
);
2625 DUMPREG(DISPC_SYSCONFIG
);
2626 DUMPREG(DISPC_SYSSTATUS
);
2627 DUMPREG(DISPC_IRQSTATUS
);
2628 DUMPREG(DISPC_IRQENABLE
);
2629 DUMPREG(DISPC_CONTROL
);
2630 DUMPREG(DISPC_CONFIG
);
2631 DUMPREG(DISPC_CAPABLE
);
2632 DUMPREG(DISPC_LINE_STATUS
);
2633 DUMPREG(DISPC_LINE_NUMBER
);
2634 if (dss_has_feature(FEAT_ALPHA_FIXED_ZORDER
) ||
2635 dss_has_feature(FEAT_ALPHA_FREE_ZORDER
))
2636 DUMPREG(DISPC_GLOBAL_ALPHA
);
2637 if (dss_has_feature(FEAT_MGR_LCD2
)) {
2638 DUMPREG(DISPC_CONTROL2
);
2639 DUMPREG(DISPC_CONFIG2
);
2644 #define DISPC_REG(i, name) name(i)
2645 #define DUMPREG(i, r) seq_printf(s, "%s(%s)%*s %08x\n", #r, p_names[i], \
2646 48 - strlen(#r) - strlen(p_names[i]), " ", \
2647 dispc_read_reg(DISPC_REG(i, r)))
2649 p_names
= mgr_names
;
2651 /* DISPC channel specific registers */
2652 for (i
= 0; i
< dss_feat_get_num_mgrs(); i
++) {
2653 DUMPREG(i
, DISPC_DEFAULT_COLOR
);
2654 DUMPREG(i
, DISPC_TRANS_COLOR
);
2655 DUMPREG(i
, DISPC_SIZE_MGR
);
2657 if (i
== OMAP_DSS_CHANNEL_DIGIT
)
2660 DUMPREG(i
, DISPC_DEFAULT_COLOR
);
2661 DUMPREG(i
, DISPC_TRANS_COLOR
);
2662 DUMPREG(i
, DISPC_TIMING_H
);
2663 DUMPREG(i
, DISPC_TIMING_V
);
2664 DUMPREG(i
, DISPC_POL_FREQ
);
2665 DUMPREG(i
, DISPC_DIVISORo
);
2666 DUMPREG(i
, DISPC_SIZE_MGR
);
2668 DUMPREG(i
, DISPC_DATA_CYCLE1
);
2669 DUMPREG(i
, DISPC_DATA_CYCLE2
);
2670 DUMPREG(i
, DISPC_DATA_CYCLE3
);
2672 if (dss_has_feature(FEAT_CPR
)) {
2673 DUMPREG(i
, DISPC_CPR_COEF_R
);
2674 DUMPREG(i
, DISPC_CPR_COEF_G
);
2675 DUMPREG(i
, DISPC_CPR_COEF_B
);
2679 p_names
= ovl_names
;
2681 for (i
= 0; i
< dss_feat_get_num_ovls(); i
++) {
2682 DUMPREG(i
, DISPC_OVL_BA0
);
2683 DUMPREG(i
, DISPC_OVL_BA1
);
2684 DUMPREG(i
, DISPC_OVL_POSITION
);
2685 DUMPREG(i
, DISPC_OVL_SIZE
);
2686 DUMPREG(i
, DISPC_OVL_ATTRIBUTES
);
2687 DUMPREG(i
, DISPC_OVL_FIFO_THRESHOLD
);
2688 DUMPREG(i
, DISPC_OVL_FIFO_SIZE_STATUS
);
2689 DUMPREG(i
, DISPC_OVL_ROW_INC
);
2690 DUMPREG(i
, DISPC_OVL_PIXEL_INC
);
2691 if (dss_has_feature(FEAT_PRELOAD
))
2692 DUMPREG(i
, DISPC_OVL_PRELOAD
);
2694 if (i
== OMAP_DSS_GFX
) {
2695 DUMPREG(i
, DISPC_OVL_WINDOW_SKIP
);
2696 DUMPREG(i
, DISPC_OVL_TABLE_BA
);
2700 DUMPREG(i
, DISPC_OVL_FIR
);
2701 DUMPREG(i
, DISPC_OVL_PICTURE_SIZE
);
2702 DUMPREG(i
, DISPC_OVL_ACCU0
);
2703 DUMPREG(i
, DISPC_OVL_ACCU1
);
2704 if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE
)) {
2705 DUMPREG(i
, DISPC_OVL_BA0_UV
);
2706 DUMPREG(i
, DISPC_OVL_BA1_UV
);
2707 DUMPREG(i
, DISPC_OVL_FIR2
);
2708 DUMPREG(i
, DISPC_OVL_ACCU2_0
);
2709 DUMPREG(i
, DISPC_OVL_ACCU2_1
);
2711 if (dss_has_feature(FEAT_ATTR2
))
2712 DUMPREG(i
, DISPC_OVL_ATTRIBUTES2
);
2713 if (dss_has_feature(FEAT_PRELOAD
))
2714 DUMPREG(i
, DISPC_OVL_PRELOAD
);
2720 #define DISPC_REG(plane, name, i) name(plane, i)
2721 #define DUMPREG(plane, name, i) \
2722 seq_printf(s, "%s_%d(%s)%*s %08x\n", #name, i, p_names[plane], \
2723 46 - strlen(#name) - strlen(p_names[plane]), " ", \
2724 dispc_read_reg(DISPC_REG(plane, name, i)))
2726 /* Video pipeline coefficient registers */
2728 /* start from OMAP_DSS_VIDEO1 */
2729 for (i
= 1; i
< dss_feat_get_num_ovls(); i
++) {
2730 for (j
= 0; j
< 8; j
++)
2731 DUMPREG(i
, DISPC_OVL_FIR_COEF_H
, j
);
2733 for (j
= 0; j
< 8; j
++)
2734 DUMPREG(i
, DISPC_OVL_FIR_COEF_HV
, j
);
2736 for (j
= 0; j
< 5; j
++)
2737 DUMPREG(i
, DISPC_OVL_CONV_COEF
, j
);
2739 if (dss_has_feature(FEAT_FIR_COEF_V
)) {
2740 for (j
= 0; j
< 8; j
++)
2741 DUMPREG(i
, DISPC_OVL_FIR_COEF_V
, j
);
2744 if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE
)) {
2745 for (j
= 0; j
< 8; j
++)
2746 DUMPREG(i
, DISPC_OVL_FIR_COEF_H2
, j
);
2748 for (j
= 0; j
< 8; j
++)
2749 DUMPREG(i
, DISPC_OVL_FIR_COEF_HV2
, j
);
2751 for (j
= 0; j
< 8; j
++)
2752 DUMPREG(i
, DISPC_OVL_FIR_COEF_V2
, j
);
2756 dispc_runtime_put();
2762 static void _dispc_mgr_set_pol_freq(enum omap_channel channel
, bool onoff
,
2763 bool rf
, bool ieo
, bool ipc
, bool ihs
, bool ivs
, u8 acbi
,
2768 DSSDBG("onoff %d rf %d ieo %d ipc %d ihs %d ivs %d acbi %d acb %d\n",
2769 onoff
, rf
, ieo
, ipc
, ihs
, ivs
, acbi
, acb
);
2771 l
|= FLD_VAL(onoff
, 17, 17);
2772 l
|= FLD_VAL(rf
, 16, 16);
2773 l
|= FLD_VAL(ieo
, 15, 15);
2774 l
|= FLD_VAL(ipc
, 14, 14);
2775 l
|= FLD_VAL(ihs
, 13, 13);
2776 l
|= FLD_VAL(ivs
, 12, 12);
2777 l
|= FLD_VAL(acbi
, 11, 8);
2778 l
|= FLD_VAL(acb
, 7, 0);
2780 dispc_write_reg(DISPC_POL_FREQ(channel
), l
);
2783 void dispc_mgr_set_pol_freq(enum omap_channel channel
,
2784 enum omap_panel_config config
, u8 acbi
, u8 acb
)
2786 _dispc_mgr_set_pol_freq(channel
, (config
& OMAP_DSS_LCD_ONOFF
) != 0,
2787 (config
& OMAP_DSS_LCD_RF
) != 0,
2788 (config
& OMAP_DSS_LCD_IEO
) != 0,
2789 (config
& OMAP_DSS_LCD_IPC
) != 0,
2790 (config
& OMAP_DSS_LCD_IHS
) != 0,
2791 (config
& OMAP_DSS_LCD_IVS
) != 0,
2795 /* with fck as input clock rate, find dispc dividers that produce req_pck */
2796 void dispc_find_clk_divs(bool is_tft
, unsigned long req_pck
, unsigned long fck
,
2797 struct dispc_clock_info
*cinfo
)
2799 u16 pcd_min
, pcd_max
;
2800 unsigned long best_pck
;
2801 u16 best_ld
, cur_ld
;
2802 u16 best_pd
, cur_pd
;
2804 pcd_min
= dss_feat_get_param_min(FEAT_PARAM_DSS_PCD
);
2805 pcd_max
= dss_feat_get_param_max(FEAT_PARAM_DSS_PCD
);
2814 for (cur_ld
= 1; cur_ld
<= 255; ++cur_ld
) {
2815 unsigned long lck
= fck
/ cur_ld
;
2817 for (cur_pd
= pcd_min
; cur_pd
<= pcd_max
; ++cur_pd
) {
2818 unsigned long pck
= lck
/ cur_pd
;
2819 long old_delta
= abs(best_pck
- req_pck
);
2820 long new_delta
= abs(pck
- req_pck
);
2822 if (best_pck
== 0 || new_delta
< old_delta
) {
2835 if (lck
/ pcd_min
< req_pck
)
2840 cinfo
->lck_div
= best_ld
;
2841 cinfo
->pck_div
= best_pd
;
2842 cinfo
->lck
= fck
/ cinfo
->lck_div
;
2843 cinfo
->pck
= cinfo
->lck
/ cinfo
->pck_div
;
2846 /* calculate clock rates using dividers in cinfo */
2847 int dispc_calc_clock_rates(unsigned long dispc_fclk_rate
,
2848 struct dispc_clock_info
*cinfo
)
2850 if (cinfo
->lck_div
> 255 || cinfo
->lck_div
== 0)
2852 if (cinfo
->pck_div
< 1 || cinfo
->pck_div
> 255)
2855 cinfo
->lck
= dispc_fclk_rate
/ cinfo
->lck_div
;
2856 cinfo
->pck
= cinfo
->lck
/ cinfo
->pck_div
;
2861 int dispc_mgr_set_clock_div(enum omap_channel channel
,
2862 struct dispc_clock_info
*cinfo
)
2864 DSSDBG("lck = %lu (%u)\n", cinfo
->lck
, cinfo
->lck_div
);
2865 DSSDBG("pck = %lu (%u)\n", cinfo
->pck
, cinfo
->pck_div
);
2867 dispc_mgr_set_lcd_divisor(channel
, cinfo
->lck_div
, cinfo
->pck_div
);
2872 int dispc_mgr_get_clock_div(enum omap_channel channel
,
2873 struct dispc_clock_info
*cinfo
)
2877 fck
= dispc_fclk_rate();
2879 cinfo
->lck_div
= REG_GET(DISPC_DIVISORo(channel
), 23, 16);
2880 cinfo
->pck_div
= REG_GET(DISPC_DIVISORo(channel
), 7, 0);
2882 cinfo
->lck
= fck
/ cinfo
->lck_div
;
2883 cinfo
->pck
= cinfo
->lck
/ cinfo
->pck_div
;
2888 /* dispc.irq_lock has to be locked by the caller */
2889 static void _omap_dispc_set_irqs(void)
2894 struct omap_dispc_isr_data
*isr_data
;
2896 mask
= dispc
.irq_error_mask
;
2898 for (i
= 0; i
< DISPC_MAX_NR_ISRS
; i
++) {
2899 isr_data
= &dispc
.registered_isr
[i
];
2901 if (isr_data
->isr
== NULL
)
2904 mask
|= isr_data
->mask
;
2907 old_mask
= dispc_read_reg(DISPC_IRQENABLE
);
2908 /* clear the irqstatus for newly enabled irqs */
2909 dispc_write_reg(DISPC_IRQSTATUS
, (mask
^ old_mask
) & mask
);
2911 dispc_write_reg(DISPC_IRQENABLE
, mask
);
2914 int omap_dispc_register_isr(omap_dispc_isr_t isr
, void *arg
, u32 mask
)
2918 unsigned long flags
;
2919 struct omap_dispc_isr_data
*isr_data
;
2924 spin_lock_irqsave(&dispc
.irq_lock
, flags
);
2926 /* check for duplicate entry */
2927 for (i
= 0; i
< DISPC_MAX_NR_ISRS
; i
++) {
2928 isr_data
= &dispc
.registered_isr
[i
];
2929 if (isr_data
->isr
== isr
&& isr_data
->arg
== arg
&&
2930 isr_data
->mask
== mask
) {
2939 for (i
= 0; i
< DISPC_MAX_NR_ISRS
; i
++) {
2940 isr_data
= &dispc
.registered_isr
[i
];
2942 if (isr_data
->isr
!= NULL
)
2945 isr_data
->isr
= isr
;
2946 isr_data
->arg
= arg
;
2947 isr_data
->mask
= mask
;
2956 _omap_dispc_set_irqs();
2958 spin_unlock_irqrestore(&dispc
.irq_lock
, flags
);
2962 spin_unlock_irqrestore(&dispc
.irq_lock
, flags
);
2966 EXPORT_SYMBOL(omap_dispc_register_isr
);
2968 int omap_dispc_unregister_isr(omap_dispc_isr_t isr
, void *arg
, u32 mask
)
2971 unsigned long flags
;
2973 struct omap_dispc_isr_data
*isr_data
;
2975 spin_lock_irqsave(&dispc
.irq_lock
, flags
);
2977 for (i
= 0; i
< DISPC_MAX_NR_ISRS
; i
++) {
2978 isr_data
= &dispc
.registered_isr
[i
];
2979 if (isr_data
->isr
!= isr
|| isr_data
->arg
!= arg
||
2980 isr_data
->mask
!= mask
)
2983 /* found the correct isr */
2985 isr_data
->isr
= NULL
;
2986 isr_data
->arg
= NULL
;
2994 _omap_dispc_set_irqs();
2996 spin_unlock_irqrestore(&dispc
.irq_lock
, flags
);
3000 EXPORT_SYMBOL(omap_dispc_unregister_isr
);
3003 static void print_irq_status(u32 status
)
3005 if ((status
& dispc
.irq_error_mask
) == 0)
3008 printk(KERN_DEBUG
"DISPC IRQ: 0x%x: ", status
);
3011 if (status & DISPC_IRQ_##x) \
3013 PIS(GFX_FIFO_UNDERFLOW
);
3015 PIS(VID1_FIFO_UNDERFLOW
);
3016 PIS(VID2_FIFO_UNDERFLOW
);
3017 if (dss_feat_get_num_ovls() > 3)
3018 PIS(VID3_FIFO_UNDERFLOW
);
3020 PIS(SYNC_LOST_DIGIT
);
3021 if (dss_has_feature(FEAT_MGR_LCD2
))
3029 /* Called from dss.c. Note that we don't touch clocks here,
3030 * but we presume they are on because we got an IRQ. However,
3031 * an irq handler may turn the clocks off, so we may not have
3032 * clock later in the function. */
3033 static irqreturn_t
omap_dispc_irq_handler(int irq
, void *arg
)
3036 u32 irqstatus
, irqenable
;
3037 u32 handledirqs
= 0;
3038 u32 unhandled_errors
;
3039 struct omap_dispc_isr_data
*isr_data
;
3040 struct omap_dispc_isr_data registered_isr
[DISPC_MAX_NR_ISRS
];
3042 spin_lock(&dispc
.irq_lock
);
3044 irqstatus
= dispc_read_reg(DISPC_IRQSTATUS
);
3045 irqenable
= dispc_read_reg(DISPC_IRQENABLE
);
3047 /* IRQ is not for us */
3048 if (!(irqstatus
& irqenable
)) {
3049 spin_unlock(&dispc
.irq_lock
);
3053 #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
3054 spin_lock(&dispc
.irq_stats_lock
);
3055 dispc
.irq_stats
.irq_count
++;
3056 dss_collect_irq_stats(irqstatus
, dispc
.irq_stats
.irqs
);
3057 spin_unlock(&dispc
.irq_stats_lock
);
3062 print_irq_status(irqstatus
);
3064 /* Ack the interrupt. Do it here before clocks are possibly turned
3066 dispc_write_reg(DISPC_IRQSTATUS
, irqstatus
);
3067 /* flush posted write */
3068 dispc_read_reg(DISPC_IRQSTATUS
);
3070 /* make a copy and unlock, so that isrs can unregister
3072 memcpy(registered_isr
, dispc
.registered_isr
,
3073 sizeof(registered_isr
));
3075 spin_unlock(&dispc
.irq_lock
);
3077 for (i
= 0; i
< DISPC_MAX_NR_ISRS
; i
++) {
3078 isr_data
= ®istered_isr
[i
];
3083 if (isr_data
->mask
& irqstatus
) {
3084 isr_data
->isr(isr_data
->arg
, irqstatus
);
3085 handledirqs
|= isr_data
->mask
;
3089 spin_lock(&dispc
.irq_lock
);
3091 unhandled_errors
= irqstatus
& ~handledirqs
& dispc
.irq_error_mask
;
3093 if (unhandled_errors
) {
3094 dispc
.error_irqs
|= unhandled_errors
;
3096 dispc
.irq_error_mask
&= ~unhandled_errors
;
3097 _omap_dispc_set_irqs();
3099 schedule_work(&dispc
.error_work
);
3102 spin_unlock(&dispc
.irq_lock
);
3107 static void dispc_error_worker(struct work_struct
*work
)
3111 unsigned long flags
;
3112 static const unsigned fifo_underflow_bits
[] = {
3113 DISPC_IRQ_GFX_FIFO_UNDERFLOW
,
3114 DISPC_IRQ_VID1_FIFO_UNDERFLOW
,
3115 DISPC_IRQ_VID2_FIFO_UNDERFLOW
,
3116 DISPC_IRQ_VID3_FIFO_UNDERFLOW
,
3119 static const unsigned sync_lost_bits
[] = {
3120 DISPC_IRQ_SYNC_LOST
,
3121 DISPC_IRQ_SYNC_LOST_DIGIT
,
3122 DISPC_IRQ_SYNC_LOST2
,
3125 spin_lock_irqsave(&dispc
.irq_lock
, flags
);
3126 errors
= dispc
.error_irqs
;
3127 dispc
.error_irqs
= 0;
3128 spin_unlock_irqrestore(&dispc
.irq_lock
, flags
);
3130 dispc_runtime_get();
3132 for (i
= 0; i
< omap_dss_get_num_overlays(); ++i
) {
3133 struct omap_overlay
*ovl
;
3136 ovl
= omap_dss_get_overlay(i
);
3137 bit
= fifo_underflow_bits
[i
];
3140 DSSERR("FIFO UNDERFLOW on %s, disabling the overlay\n",
3142 dispc_ovl_enable(ovl
->id
, false);
3143 dispc_mgr_go(ovl
->manager
->id
);
3148 for (i
= 0; i
< omap_dss_get_num_overlay_managers(); ++i
) {
3149 struct omap_overlay_manager
*mgr
;
3152 mgr
= omap_dss_get_overlay_manager(i
);
3153 bit
= sync_lost_bits
[i
];
3156 struct omap_dss_device
*dssdev
= mgr
->device
;
3159 DSSERR("SYNC_LOST on channel %s, restarting the output "
3160 "with video overlays disabled\n",
3163 enable
= dssdev
->state
== OMAP_DSS_DISPLAY_ACTIVE
;
3164 dssdev
->driver
->disable(dssdev
);
3166 for (i
= 0; i
< omap_dss_get_num_overlays(); ++i
) {
3167 struct omap_overlay
*ovl
;
3168 ovl
= omap_dss_get_overlay(i
);
3170 if (ovl
->id
!= OMAP_DSS_GFX
&&
3171 ovl
->manager
== mgr
)
3172 dispc_ovl_enable(ovl
->id
, false);
3175 dispc_mgr_go(mgr
->id
);
3179 dssdev
->driver
->enable(dssdev
);
3183 if (errors
& DISPC_IRQ_OCP_ERR
) {
3184 DSSERR("OCP_ERR\n");
3185 for (i
= 0; i
< omap_dss_get_num_overlay_managers(); ++i
) {
3186 struct omap_overlay_manager
*mgr
;
3187 mgr
= omap_dss_get_overlay_manager(i
);
3188 mgr
->device
->driver
->disable(mgr
->device
);
3192 spin_lock_irqsave(&dispc
.irq_lock
, flags
);
3193 dispc
.irq_error_mask
|= errors
;
3194 _omap_dispc_set_irqs();
3195 spin_unlock_irqrestore(&dispc
.irq_lock
, flags
);
3197 dispc_runtime_put();
3200 int omap_dispc_wait_for_irq_timeout(u32 irqmask
, unsigned long timeout
)
3202 void dispc_irq_wait_handler(void *data
, u32 mask
)
3204 complete((struct completion
*)data
);
3208 DECLARE_COMPLETION_ONSTACK(completion
);
3210 r
= omap_dispc_register_isr(dispc_irq_wait_handler
, &completion
,
3216 timeout
= wait_for_completion_timeout(&completion
, timeout
);
3218 omap_dispc_unregister_isr(dispc_irq_wait_handler
, &completion
, irqmask
);
3223 if (timeout
== -ERESTARTSYS
)
3224 return -ERESTARTSYS
;
3229 int omap_dispc_wait_for_irq_interruptible_timeout(u32 irqmask
,
3230 unsigned long timeout
)
3232 void dispc_irq_wait_handler(void *data
, u32 mask
)
3234 complete((struct completion
*)data
);
3238 DECLARE_COMPLETION_ONSTACK(completion
);
3240 r
= omap_dispc_register_isr(dispc_irq_wait_handler
, &completion
,
3246 timeout
= wait_for_completion_interruptible_timeout(&completion
,
3249 omap_dispc_unregister_isr(dispc_irq_wait_handler
, &completion
, irqmask
);
3254 if (timeout
== -ERESTARTSYS
)
3255 return -ERESTARTSYS
;
3260 #ifdef CONFIG_OMAP2_DSS_FAKE_VSYNC
3261 void dispc_fake_vsync_irq(void)
3263 u32 irqstatus
= DISPC_IRQ_VSYNC
;
3266 WARN_ON(!in_interrupt());
3268 for (i
= 0; i
< DISPC_MAX_NR_ISRS
; i
++) {
3269 struct omap_dispc_isr_data
*isr_data
;
3270 isr_data
= &dispc
.registered_isr
[i
];
3275 if (isr_data
->mask
& irqstatus
)
3276 isr_data
->isr(isr_data
->arg
, irqstatus
);
3281 static void _omap_dispc_initialize_irq(void)
3283 unsigned long flags
;
3285 spin_lock_irqsave(&dispc
.irq_lock
, flags
);
3287 memset(dispc
.registered_isr
, 0, sizeof(dispc
.registered_isr
));
3289 dispc
.irq_error_mask
= DISPC_IRQ_MASK_ERROR
;
3290 if (dss_has_feature(FEAT_MGR_LCD2
))
3291 dispc
.irq_error_mask
|= DISPC_IRQ_SYNC_LOST2
;
3292 if (dss_feat_get_num_ovls() > 3)
3293 dispc
.irq_error_mask
|= DISPC_IRQ_VID3_FIFO_UNDERFLOW
;
3295 /* there's SYNC_LOST_DIGIT waiting after enabling the DSS,
3297 dispc_write_reg(DISPC_IRQSTATUS
, dispc_read_reg(DISPC_IRQSTATUS
));
3299 _omap_dispc_set_irqs();
3301 spin_unlock_irqrestore(&dispc
.irq_lock
, flags
);
3304 void dispc_enable_sidle(void)
3306 REG_FLD_MOD(DISPC_SYSCONFIG
, 2, 4, 3); /* SIDLEMODE: smart idle */
3309 void dispc_disable_sidle(void)
3311 REG_FLD_MOD(DISPC_SYSCONFIG
, 1, 4, 3); /* SIDLEMODE: no idle */
3314 static void _omap_dispc_initial_config(void)
3318 /* Exclusively enable DISPC_CORE_CLK and set divider to 1 */
3319 if (dss_has_feature(FEAT_CORE_CLK_DIV
)) {
3320 l
= dispc_read_reg(DISPC_DIVISOR
);
3321 /* Use DISPC_DIVISOR.LCD, instead of DISPC_DIVISOR1.LCD */
3322 l
= FLD_MOD(l
, 1, 0, 0);
3323 l
= FLD_MOD(l
, 1, 23, 16);
3324 dispc_write_reg(DISPC_DIVISOR
, l
);
3328 if (dss_has_feature(FEAT_FUNCGATED
))
3329 REG_FLD_MOD(DISPC_CONFIG
, 1, 9, 9);
3331 /* L3 firewall setting: enable access to OCM RAM */
3332 /* XXX this should be somewhere in plat-omap */
3333 if (cpu_is_omap24xx())
3334 __raw_writel(0x402000b0, OMAP2_L3_IO_ADDRESS(0x680050a0));
3336 _dispc_setup_color_conv_coef();
3338 dispc_set_loadmode(OMAP_DSS_LOAD_FRAME_ONLY
);
3340 dispc_read_plane_fifo_sizes();
3342 dispc_configure_burst_sizes();
3344 dispc_ovl_enable_zorder_planes();
3347 /* DISPC HW IP initialisation */
3348 static int omap_dispchw_probe(struct platform_device
*pdev
)
3352 struct resource
*dispc_mem
;
3357 clk
= clk_get(&pdev
->dev
, "fck");
3359 DSSERR("can't get fck\n");
3364 dispc
.dss_clk
= clk
;
3366 spin_lock_init(&dispc
.irq_lock
);
3368 #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
3369 spin_lock_init(&dispc
.irq_stats_lock
);
3370 dispc
.irq_stats
.last_reset
= jiffies
;
3373 INIT_WORK(&dispc
.error_work
, dispc_error_worker
);
3375 dispc_mem
= platform_get_resource(dispc
.pdev
, IORESOURCE_MEM
, 0);
3377 DSSERR("can't get IORESOURCE_MEM DISPC\n");
3381 dispc
.base
= ioremap(dispc_mem
->start
, resource_size(dispc_mem
));
3383 DSSERR("can't ioremap DISPC\n");
3387 dispc
.irq
= platform_get_irq(dispc
.pdev
, 0);
3388 if (dispc
.irq
< 0) {
3389 DSSERR("platform_get_irq failed\n");
3394 r
= request_irq(dispc
.irq
, omap_dispc_irq_handler
, IRQF_SHARED
,
3395 "OMAP DISPC", dispc
.pdev
);
3397 DSSERR("request_irq failed\n");
3401 pm_runtime_enable(&pdev
->dev
);
3403 r
= dispc_runtime_get();
3405 goto err_runtime_get
;
3407 _omap_dispc_initial_config();
3409 _omap_dispc_initialize_irq();
3411 rev
= dispc_read_reg(DISPC_REVISION
);
3412 dev_dbg(&pdev
->dev
, "OMAP DISPC rev %d.%d\n",
3413 FLD_GET(rev
, 7, 4), FLD_GET(rev
, 3, 0));
3415 dispc_runtime_put();
3420 pm_runtime_disable(&pdev
->dev
);
3421 free_irq(dispc
.irq
, dispc
.pdev
);
3423 iounmap(dispc
.base
);
3425 clk_put(dispc
.dss_clk
);
3430 static int omap_dispchw_remove(struct platform_device
*pdev
)
3432 pm_runtime_disable(&pdev
->dev
);
3434 clk_put(dispc
.dss_clk
);
3436 free_irq(dispc
.irq
, dispc
.pdev
);
3437 iounmap(dispc
.base
);
3441 static int dispc_runtime_suspend(struct device
*dev
)
3443 dispc_save_context();
3449 static int dispc_runtime_resume(struct device
*dev
)
3453 r
= dss_runtime_get();
3457 dispc_restore_context();
3462 static const struct dev_pm_ops dispc_pm_ops
= {
3463 .runtime_suspend
= dispc_runtime_suspend
,
3464 .runtime_resume
= dispc_runtime_resume
,
3467 static struct platform_driver omap_dispchw_driver
= {
3468 .probe
= omap_dispchw_probe
,
3469 .remove
= omap_dispchw_remove
,
3471 .name
= "omapdss_dispc",
3472 .owner
= THIS_MODULE
,
3473 .pm
= &dispc_pm_ops
,
3477 int dispc_init_platform_driver(void)
3479 return platform_driver_register(&omap_dispchw_driver
);
3482 void dispc_uninit_platform_driver(void)
3484 return platform_driver_unregister(&omap_dispchw_driver
);