diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-01-13 19:39:14 +0100 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-01-13 19:39:14 +0100 |
commit | d33a6291c1c577ff2272edab7416a0f7308e1cef (patch) | |
tree | 9efd2f6f2fbb0586af72531110acdf9e769285ab /drivers/video/omap2/dss | |
parent | Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tiw... (diff) | |
parent | video: move SH_MIPI_DSI/SH_LCD_MIPI_DSI to the top of menu (diff) | |
download | linux-d33a6291c1c577ff2272edab7416a0f7308e1cef.tar.xz linux-d33a6291c1c577ff2272edab7416a0f7308e1cef.zip |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/lethal/fbdev-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/lethal/fbdev-2.6: (29 commits)
video: move SH_MIPI_DSI/SH_LCD_MIPI_DSI to the top of menu
fbdev: Implement simple blanking in pseudocolor modes for vt8500lcdfb
video: imx: Update the manufacturer's name
nuc900fb: don't treat NULL clk as an error
s3c2410fb: don't treat NULL clk as an error
video: tidy up modedb formatting.
video: matroxfb: Correct video option in comments and kernel config help.
fbdev: sh_mobile_hdmi: simplify pointer handling
fbdev: sh_mobile_hdmi: framebuffer notifiers have to be registered
fbdev: sh_mobile_hdmi: add command line option to use the preferred EDID mode
OMAP: DSS2: Introduce omap_channel as an omap_dss_device parameter, add new overlay manager.
OMAP: DSS2: Use dss_features to handle DISPC bits removed on OMAP4
OMAP: DSS2: LCD2 Channel Changes for DISPC
OMAP: DSS2: Change remaining DISPC functions for new omap_channel argument
OMAP: DSS2: Introduce omap_channel argument to DISPC functions used by interface drivers
OMAP: DSS2: Represent DISPC register defines with channel as parameter
OMAP: DSS2: Add dss_features for omap4 and overlay manager related features
OMAP: DSS2: Clean up DISPC color mode validation checks
OMAP: DSS2: Add back authors of panel-generic.c based drivers
OMAP: DSS2: remove generic DPI panel driver duplicated panel drivers
...
Diffstat (limited to 'drivers/video/omap2/dss')
-rw-r--r-- | drivers/video/omap2/dss/dispc.c | 636 | ||||
-rw-r--r-- | drivers/video/omap2/dss/dpi.c | 40 | ||||
-rw-r--r-- | drivers/video/omap2/dss/dsi.c | 27 | ||||
-rw-r--r-- | drivers/video/omap2/dss/dss.h | 35 | ||||
-rw-r--r-- | drivers/video/omap2/dss/dss_features.c | 66 | ||||
-rw-r--r-- | drivers/video/omap2/dss/dss_features.h | 10 | ||||
-rw-r--r-- | drivers/video/omap2/dss/manager.c | 80 | ||||
-rw-r--r-- | drivers/video/omap2/dss/overlay.c | 55 | ||||
-rw-r--r-- | drivers/video/omap2/dss/rfbi.c | 20 | ||||
-rw-r--r-- | drivers/video/omap2/dss/sdi.c | 24 |
10 files changed, 673 insertions, 320 deletions
diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c index fa40fa59a9ac..9f8c69f16e61 100644 --- a/drivers/video/omap2/dss/dispc.c +++ b/drivers/video/omap2/dss/dispc.c @@ -44,34 +44,40 @@ /* DISPC */ #define DISPC_BASE 0x48050400 -#define DISPC_SZ_REGS SZ_1K +#define DISPC_SZ_REGS SZ_4K struct dispc_reg { u16 idx; }; #define DISPC_REG(idx) ((const struct dispc_reg) { idx }) -/* DISPC common */ +/* + * DISPC common registers and + * DISPC channel registers , ch = 0 for LCD, ch = 1 for + * DIGIT, and ch = 2 for LCD2 + */ #define DISPC_REVISION DISPC_REG(0x0000) #define DISPC_SYSCONFIG DISPC_REG(0x0010) #define DISPC_SYSSTATUS DISPC_REG(0x0014) #define DISPC_IRQSTATUS DISPC_REG(0x0018) #define DISPC_IRQENABLE DISPC_REG(0x001C) #define DISPC_CONTROL DISPC_REG(0x0040) +#define DISPC_CONTROL2 DISPC_REG(0x0238) #define DISPC_CONFIG DISPC_REG(0x0044) +#define DISPC_CONFIG2 DISPC_REG(0x0620) #define DISPC_CAPABLE DISPC_REG(0x0048) -#define DISPC_DEFAULT_COLOR0 DISPC_REG(0x004C) -#define DISPC_DEFAULT_COLOR1 DISPC_REG(0x0050) -#define DISPC_TRANS_COLOR0 DISPC_REG(0x0054) -#define DISPC_TRANS_COLOR1 DISPC_REG(0x0058) +#define DISPC_DEFAULT_COLOR(ch) DISPC_REG(ch == 0 ? 0x004C : \ + (ch == 1 ? 0x0050 : 0x03AC)) +#define DISPC_TRANS_COLOR(ch) DISPC_REG(ch == 0 ? 0x0054 : \ + (ch == 1 ? 0x0058 : 0x03B0)) #define DISPC_LINE_STATUS DISPC_REG(0x005C) #define DISPC_LINE_NUMBER DISPC_REG(0x0060) -#define DISPC_TIMING_H DISPC_REG(0x0064) -#define DISPC_TIMING_V DISPC_REG(0x0068) -#define DISPC_POL_FREQ DISPC_REG(0x006C) -#define DISPC_DIVISOR DISPC_REG(0x0070) +#define DISPC_TIMING_H(ch) DISPC_REG(ch != 2 ? 0x0064 : 0x0400) +#define DISPC_TIMING_V(ch) DISPC_REG(ch != 2 ? 0x0068 : 0x0404) +#define DISPC_POL_FREQ(ch) DISPC_REG(ch != 2 ? 0x006C : 0x0408) +#define DISPC_DIVISOR(ch) DISPC_REG(ch != 2 ? 0x0070 : 0x040C) #define DISPC_GLOBAL_ALPHA DISPC_REG(0x0074) #define DISPC_SIZE_DIG DISPC_REG(0x0078) -#define DISPC_SIZE_LCD DISPC_REG(0x007C) +#define DISPC_SIZE_LCD(ch) DISPC_REG(ch != 2 ? 0x007C : 0x03CC) /* DISPC GFX plane */ #define DISPC_GFX_BA0 DISPC_REG(0x0080) @@ -86,13 +92,12 @@ struct dispc_reg { u16 idx; }; #define DISPC_GFX_WINDOW_SKIP DISPC_REG(0x00B4) #define DISPC_GFX_TABLE_BA DISPC_REG(0x00B8) -#define DISPC_DATA_CYCLE1 DISPC_REG(0x01D4) -#define DISPC_DATA_CYCLE2 DISPC_REG(0x01D8) -#define DISPC_DATA_CYCLE3 DISPC_REG(0x01DC) - -#define DISPC_CPR_COEF_R DISPC_REG(0x0220) -#define DISPC_CPR_COEF_G DISPC_REG(0x0224) -#define DISPC_CPR_COEF_B DISPC_REG(0x0228) +#define DISPC_DATA_CYCLE1(ch) DISPC_REG(ch != 2 ? 0x01D4 : 0x03C0) +#define DISPC_DATA_CYCLE2(ch) DISPC_REG(ch != 2 ? 0x01D8 : 0x03C4) +#define DISPC_DATA_CYCLE3(ch) DISPC_REG(ch != 2 ? 0x01DC : 0x03C8) +#define DISPC_CPR_COEF_R(ch) DISPC_REG(ch != 2 ? 0x0220 : 0x03BC) +#define DISPC_CPR_COEF_G(ch) DISPC_REG(ch != 2 ? 0x0224 : 0x03B8) +#define DISPC_CPR_COEF_B(ch) DISPC_REG(ch != 2 ? 0x0228 : 0x03B4) #define DISPC_GFX_PRELOAD DISPC_REG(0x022C) @@ -217,18 +222,29 @@ void dispc_save_context(void) SR(IRQENABLE); SR(CONTROL); SR(CONFIG); - SR(DEFAULT_COLOR0); - SR(DEFAULT_COLOR1); - SR(TRANS_COLOR0); - SR(TRANS_COLOR1); + SR(DEFAULT_COLOR(0)); + SR(DEFAULT_COLOR(1)); + SR(TRANS_COLOR(0)); + SR(TRANS_COLOR(1)); SR(LINE_NUMBER); - SR(TIMING_H); - SR(TIMING_V); - SR(POL_FREQ); - SR(DIVISOR); + SR(TIMING_H(0)); + SR(TIMING_V(0)); + SR(POL_FREQ(0)); + SR(DIVISOR(0)); SR(GLOBAL_ALPHA); SR(SIZE_DIG); - SR(SIZE_LCD); + SR(SIZE_LCD(0)); + if (dss_has_feature(FEAT_MGR_LCD2)) { + SR(CONTROL2); + SR(DEFAULT_COLOR(2)); + SR(TRANS_COLOR(2)); + SR(SIZE_LCD(2)); + SR(TIMING_H(2)); + SR(TIMING_V(2)); + SR(POL_FREQ(2)); + SR(DIVISOR(2)); + SR(CONFIG2); + } SR(GFX_BA0); SR(GFX_BA1); @@ -241,13 +257,22 @@ void dispc_save_context(void) SR(GFX_WINDOW_SKIP); SR(GFX_TABLE_BA); - SR(DATA_CYCLE1); - SR(DATA_CYCLE2); - SR(DATA_CYCLE3); - - SR(CPR_COEF_R); - SR(CPR_COEF_G); - SR(CPR_COEF_B); + SR(DATA_CYCLE1(0)); + SR(DATA_CYCLE2(0)); + SR(DATA_CYCLE3(0)); + + SR(CPR_COEF_R(0)); + SR(CPR_COEF_G(0)); + SR(CPR_COEF_B(0)); + if (dss_has_feature(FEAT_MGR_LCD2)) { + SR(CPR_COEF_B(2)); + SR(CPR_COEF_G(2)); + SR(CPR_COEF_R(2)); + + SR(DATA_CYCLE1(2)); + SR(DATA_CYCLE2(2)); + SR(DATA_CYCLE3(2)); + } SR(GFX_PRELOAD); @@ -356,18 +381,28 @@ void dispc_restore_context(void) /*RR(IRQENABLE);*/ /*RR(CONTROL);*/ RR(CONFIG); - RR(DEFAULT_COLOR0); - RR(DEFAULT_COLOR1); - RR(TRANS_COLOR0); - RR(TRANS_COLOR1); + RR(DEFAULT_COLOR(0)); + RR(DEFAULT_COLOR(1)); + RR(TRANS_COLOR(0)); + RR(TRANS_COLOR(1)); RR(LINE_NUMBER); - RR(TIMING_H); - RR(TIMING_V); - RR(POL_FREQ); - RR(DIVISOR); + RR(TIMING_H(0)); + RR(TIMING_V(0)); + RR(POL_FREQ(0)); + RR(DIVISOR(0)); RR(GLOBAL_ALPHA); RR(SIZE_DIG); - RR(SIZE_LCD); + RR(SIZE_LCD(0)); + if (dss_has_feature(FEAT_MGR_LCD2)) { + RR(DEFAULT_COLOR(2)); + RR(TRANS_COLOR(2)); + RR(SIZE_LCD(2)); + RR(TIMING_H(2)); + RR(TIMING_V(2)); + RR(POL_FREQ(2)); + RR(DIVISOR(2)); + RR(CONFIG2); + } RR(GFX_BA0); RR(GFX_BA1); @@ -380,13 +415,22 @@ void dispc_restore_context(void) RR(GFX_WINDOW_SKIP); RR(GFX_TABLE_BA); - RR(DATA_CYCLE1); - RR(DATA_CYCLE2); - RR(DATA_CYCLE3); - - RR(CPR_COEF_R); - RR(CPR_COEF_G); - RR(CPR_COEF_B); + RR(DATA_CYCLE1(0)); + RR(DATA_CYCLE2(0)); + RR(DATA_CYCLE3(0)); + + RR(CPR_COEF_R(0)); + RR(CPR_COEF_G(0)); + RR(CPR_COEF_B(0)); + if (dss_has_feature(FEAT_MGR_LCD2)) { + RR(DATA_CYCLE1(2)); + RR(DATA_CYCLE2(2)); + RR(DATA_CYCLE3(2)); + + RR(CPR_COEF_B(2)); + RR(CPR_COEF_G(2)); + RR(CPR_COEF_R(2)); + } RR(GFX_PRELOAD); @@ -490,7 +534,8 @@ void dispc_restore_context(void) /* enable last, because LCD & DIGIT enable are here */ RR(CONTROL); - + if (dss_has_feature(FEAT_MGR_LCD2)) + RR(CONTROL2); /* clear spurious SYNC_LOST_DIGIT interrupts */ dispc_write_reg(DISPC_IRQSTATUS, DISPC_IRQ_SYNC_LOST_DIGIT); @@ -516,42 +561,63 @@ bool dispc_go_busy(enum omap_channel channel) { int bit; - if (channel == OMAP_DSS_CHANNEL_LCD) + if (channel == OMAP_DSS_CHANNEL_LCD || + channel == OMAP_DSS_CHANNEL_LCD2) bit = 5; /* GOLCD */ else bit = 6; /* GODIGIT */ - return REG_GET(DISPC_CONTROL, bit, bit) == 1; + if (channel == OMAP_DSS_CHANNEL_LCD2) + return REG_GET(DISPC_CONTROL2, bit, bit) == 1; + else + return REG_GET(DISPC_CONTROL, bit, bit) == 1; } void dispc_go(enum omap_channel channel) { int bit; + bool enable_bit, go_bit; enable_clocks(1); - if (channel == OMAP_DSS_CHANNEL_LCD) + if (channel == OMAP_DSS_CHANNEL_LCD || + channel == OMAP_DSS_CHANNEL_LCD2) bit = 0; /* LCDENABLE */ else bit = 1; /* DIGITALENABLE */ /* if the channel is not enabled, we don't need GO */ - if (REG_GET(DISPC_CONTROL, bit, bit) == 0) + if (channel == OMAP_DSS_CHANNEL_LCD2) + enable_bit = REG_GET(DISPC_CONTROL2, bit, bit) == 1; + else + enable_bit = REG_GET(DISPC_CONTROL, bit, bit) == 1; + + if (!enable_bit) goto end; - if (channel == OMAP_DSS_CHANNEL_LCD) + if (channel == OMAP_DSS_CHANNEL_LCD || + channel == OMAP_DSS_CHANNEL_LCD2) bit = 5; /* GOLCD */ else bit = 6; /* GODIGIT */ - if (REG_GET(DISPC_CONTROL, bit, bit) == 1) { + if (channel == OMAP_DSS_CHANNEL_LCD2) + go_bit = REG_GET(DISPC_CONTROL2, bit, bit) == 1; + else + go_bit = REG_GET(DISPC_CONTROL, bit, bit) == 1; + + if (go_bit) { DSSERR("GO bit not down for channel %d\n", channel); goto end; } - DSSDBG("GO %s\n", channel == OMAP_DSS_CHANNEL_LCD ? "LCD" : "DIGIT"); + DSSDBG("GO %s\n", channel == OMAP_DSS_CHANNEL_LCD ? "LCD" : + (channel == OMAP_DSS_CHANNEL_LCD2 ? "LCD2" : "DIGIT")); - REG_FLD_MOD(DISPC_CONTROL, 1, bit, bit); + if (channel == OMAP_DSS_CHANNEL_LCD2) + REG_FLD_MOD(DISPC_CONTROL2, 1, bit, bit); + else + REG_FLD_MOD(DISPC_CONTROL, 1, bit, bit); end: enable_clocks(0); } @@ -773,13 +839,26 @@ static void _dispc_set_vid_size(enum omap_plane plane, int width, int height) dispc_write_reg(vsi_reg[plane-1], val); } +static void _dispc_set_pre_mult_alpha(enum omap_plane plane, bool enable) +{ + if (!dss_has_feature(FEAT_PRE_MULT_ALPHA)) + return; + + if (!dss_has_feature(FEAT_GLOBAL_ALPHA_VID1) && + plane == OMAP_DSS_VIDEO1) + return; + + REG_FLD_MOD(dispc_reg_att[plane], enable ? 1 : 0, 28, 28); +} + static void _dispc_setup_global_alpha(enum omap_plane plane, u8 global_alpha) { if (!dss_has_feature(FEAT_GLOBAL_ALPHA)) return; - BUG_ON(!dss_has_feature(FEAT_GLOBAL_ALPHA_VID1) && - plane == OMAP_DSS_VIDEO1); + if (!dss_has_feature(FEAT_GLOBAL_ALPHA_VID1) && + plane == OMAP_DSS_VIDEO1) + return; if (plane == OMAP_DSS_GFX) REG_FLD_MOD(DISPC_GLOBAL_ALPHA, global_alpha, 7, 0); @@ -851,6 +930,7 @@ static void _dispc_set_channel_out(enum omap_plane plane, { int shift; u32 val; + int chan = 0, chan2 = 0; switch (plane) { case OMAP_DSS_GFX: @@ -866,7 +946,29 @@ static void _dispc_set_channel_out(enum omap_plane plane, } val = dispc_read_reg(dispc_reg_att[plane]); - val = FLD_MOD(val, channel, shift, shift); + if (dss_has_feature(FEAT_MGR_LCD2)) { + switch (channel) { + case OMAP_DSS_CHANNEL_LCD: + chan = 0; + chan2 = 0; + break; + case OMAP_DSS_CHANNEL_DIGIT: + chan = 1; + chan2 = 0; + break; + case OMAP_DSS_CHANNEL_LCD2: + chan = 0; + chan2 = 1; + break; + default: + BUG(); + } + + val = FLD_MOD(val, chan, shift, shift); + val = FLD_MOD(val, chan2, 31, 30); + } else { + val = FLD_MOD(val, channel, shift, shift); + } dispc_write_reg(dispc_reg_att[plane], val); } @@ -923,13 +1025,13 @@ void dispc_enable_replication(enum omap_plane plane, bool enable) enable_clocks(0); } -void dispc_set_lcd_size(u16 width, u16 height) +void dispc_set_lcd_size(enum omap_channel channel, u16 width, u16 height) { u32 val; BUG_ON((width > (1 << 11)) || (height > (1 << 11))); val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0); enable_clocks(1); - dispc_write_reg(DISPC_SIZE_LCD, val); + dispc_write_reg(DISPC_SIZE_LCD(channel), val); enable_clocks(0); } @@ -1426,12 +1528,13 @@ static void calc_dma_rotation_offset(u8 rotation, bool mirror, } } -static unsigned long calc_fclk_five_taps(u16 width, u16 height, - u16 out_width, u16 out_height, enum omap_color_mode color_mode) +static unsigned long calc_fclk_five_taps(enum omap_channel channel, u16 width, + u16 height, u16 out_width, u16 out_height, + enum omap_color_mode color_mode) { u32 fclk = 0; /* FIXME venc pclk? */ - u64 tmp, pclk = dispc_pclk_rate(); + u64 tmp, pclk = dispc_pclk_rate(channel); if (height > out_height) { /* FIXME get real display PPL */ @@ -1463,8 +1566,8 @@ static unsigned long calc_fclk_five_taps(u16 width, u16 height, return fclk; } -static unsigned long calc_fclk(u16 width, u16 height, - u16 out_width, u16 out_height) +static unsigned long calc_fclk(enum omap_channel channel, u16 width, + u16 height, u16 out_width, u16 out_height) { unsigned int hf, vf; @@ -1488,7 +1591,7 @@ static unsigned long calc_fclk(u16 width, u16 height, vf = 1; /* FIXME venc pclk? */ - return dispc_pclk_rate() * vf * hf; + return dispc_pclk_rate(channel) * vf * hf; } void dispc_set_channel_out(enum omap_plane plane, enum omap_channel channel_out) @@ -1507,7 +1610,8 @@ static int _dispc_setup_plane(enum omap_plane plane, bool ilace, enum omap_dss_rotation_type rotation_type, u8 rotation, int mirror, - u8 global_alpha) + u8 global_alpha, u8 pre_mult_alpha, + enum omap_channel channel) { const int maxdownscale = cpu_is_omap34xx() ? 4 : 2; bool five_taps = 0; @@ -1536,29 +1640,12 @@ static int _dispc_setup_plane(enum omap_plane plane, height, pos_y, out_height); } + if (!dss_feat_color_mode_supported(plane, color_mode)) + return -EINVAL; + if (plane == OMAP_DSS_GFX) { if (width != out_width || height != out_height) return -EINVAL; - - switch (color_mode) { - case OMAP_DSS_COLOR_ARGB16: - case OMAP_DSS_COLOR_ARGB32: - case OMAP_DSS_COLOR_RGBA32: - if (!dss_has_feature(FEAT_GLOBAL_ALPHA)) - return -EINVAL; - case OMAP_DSS_COLOR_RGBX32: - if (cpu_is_omap24xx()) - return -EINVAL; - /* fall through */ - case OMAP_DSS_COLOR_RGB12U: - case OMAP_DSS_COLOR_RGB16: - case OMAP_DSS_COLOR_RGB24P: - case OMAP_DSS_COLOR_RGB24U: - break; - - default: - return -EINVAL; - } } else { /* video plane */ @@ -1572,42 +1659,16 @@ static int _dispc_setup_plane(enum omap_plane plane, out_height > height * 8) return -EINVAL; - switch (color_mode) { - case OMAP_DSS_COLOR_RGBX32: - case OMAP_DSS_COLOR_RGB12U: - if (cpu_is_omap24xx()) - return -EINVAL; - /* fall through */ - case OMAP_DSS_COLOR_RGB16: - case OMAP_DSS_COLOR_RGB24P: - case OMAP_DSS_COLOR_RGB24U: - break; - - case OMAP_DSS_COLOR_ARGB16: - case OMAP_DSS_COLOR_ARGB32: - case OMAP_DSS_COLOR_RGBA32: - if (!dss_has_feature(FEAT_GLOBAL_ALPHA)) - return -EINVAL; - if (!dss_has_feature(FEAT_GLOBAL_ALPHA_VID1) && - plane == OMAP_DSS_VIDEO1) - return -EINVAL; - break; - - case OMAP_DSS_COLOR_YUV2: - case OMAP_DSS_COLOR_UYVY: + if (color_mode == OMAP_DSS_COLOR_YUV2 || + color_mode == OMAP_DSS_COLOR_UYVY) cconv = 1; - break; - - default: - return -EINVAL; - } /* Must use 5-tap filter? */ five_taps = height > out_height * 2; if (!five_taps) { - fclk = calc_fclk(width, height, - out_width, out_height); + fclk = calc_fclk(channel, width, height, out_width, + out_height); /* Try 5-tap filter if 3-tap fclk is too high */ if (cpu_is_omap34xx() && height > out_height && @@ -1621,7 +1682,7 @@ static int _dispc_setup_plane(enum omap_plane plane, } if (five_taps) - fclk = calc_fclk_five_taps(width, height, + fclk = calc_fclk_five_taps(channel, width, height, out_width, out_height, color_mode); DSSDBG("required fclk rate = %lu Hz\n", fclk); @@ -1693,8 +1754,8 @@ static int _dispc_setup_plane(enum omap_plane plane, _dispc_set_rotation_attrs(plane, rotation, mirror, color_mode); - if (plane != OMAP_DSS_VIDEO1) - _dispc_setup_global_alpha(plane, global_alpha); + _dispc_set_pre_mult_alpha(plane, pre_mult_alpha); + _dispc_setup_global_alpha(plane, global_alpha); return 0; } @@ -1710,36 +1771,44 @@ static void dispc_disable_isr(void *data, u32 mask) complete(compl); } -static void _enable_lcd_out(bool enable) +static void _enable_lcd_out(enum omap_channel channel, bool enable) { - REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 0, 0); + if (channel == OMAP_DSS_CHANNEL_LCD2) + REG_FLD_MOD(DISPC_CONTROL2, enable ? 1 : 0, 0, 0); + else + REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 0, 0); } -static void dispc_enable_lcd_out(bool enable) +static void dispc_enable_lcd_out(enum omap_channel channel, bool enable) { struct completion frame_done_completion; bool is_on; int r; + u32 irq; enable_clocks(1); /* When we disable LCD output, we need to wait until frame is done. * Otherwise the DSS is still working, and turning off the clocks * prevents DSS from going to OFF mode */ - is_on = REG_GET(DISPC_CONTROL, 0, 0); + is_on = channel == OMAP_DSS_CHANNEL_LCD2 ? + REG_GET(DISPC_CONTROL2, 0, 0) : + REG_GET(DISPC_CONTROL, 0, 0); + + irq = channel == OMAP_DSS_CHANNEL_LCD2 ? DISPC_IRQ_FRAMEDONE2 : + DISPC_IRQ_FRAMEDONE; if (!enable && is_on) { init_completion(&frame_done_completion); r = omap_dispc_register_isr(dispc_disable_isr, - &frame_done_completion, - DISPC_IRQ_FRAMEDONE); + &frame_done_completion, irq); if (r) DSSERR("failed to register FRAMEDONE isr\n"); } - _enable_lcd_out(enable); + _enable_lcd_out(channel, enable); if (!enable && is_on) { if (!wait_for_completion_timeout(&frame_done_completion, @@ -1747,8 +1816,7 @@ static void dispc_enable_lcd_out(bool enable) DSSERR("timeout waiting for FRAME DONE\n"); r = omap_dispc_unregister_isr(dispc_disable_isr, - &frame_done_completion, - DISPC_IRQ_FRAMEDONE); + &frame_done_completion, irq); if (r) DSSERR("failed to unregister FRAMEDONE isr\n"); @@ -1818,6 +1886,8 @@ static void dispc_enable_digit_out(bool enable) unsigned long flags; spin_lock_irqsave(&dispc.irq_lock, flags); dispc.irq_error_mask = DISPC_IRQ_MASK_ERROR; + if (dss_has_feature(FEAT_MGR_LCD2)) + dispc.irq_error_mask |= DISPC_IRQ_SYNC_LOST2; dispc_write_reg(DISPC_IRQSTATUS, DISPC_IRQ_SYNC_LOST_DIGIT); _omap_dispc_set_irqs(); spin_unlock_irqrestore(&dispc.irq_lock, flags); @@ -1832,14 +1902,17 @@ bool dispc_is_channel_enabled(enum omap_channel channel) return !!REG_GET(DISPC_CONTROL, 0, 0); else if (channel == OMAP_DSS_CHANNEL_DIGIT) return !!REG_GET(DISPC_CONTROL, 1, 1); + else if (channel == OMAP_DSS_CHANNEL_LCD2) + return !!REG_GET(DISPC_CONTROL2, 0, 0); else BUG(); } void dispc_enable_channel(enum omap_channel channel, bool enable) { - if (channel == OMAP_DSS_CHANNEL_LCD) - dispc_enable_lcd_out(enable); + if (channel == OMAP_DSS_CHANNEL_LCD || + channel == OMAP_DSS_CHANNEL_LCD2) + dispc_enable_lcd_out(channel, enable); else if (channel == OMAP_DSS_CHANNEL_DIGIT) dispc_enable_digit_out(enable); else @@ -1848,6 +1921,9 @@ void dispc_enable_channel(enum omap_channel channel, bool enable) void dispc_lcd_enable_signal_polarity(bool act_high) { + if (!dss_has_feature(FEAT_LCDENABLEPOL)) + return; + enable_clocks(1); REG_FLD_MOD(DISPC_CONTROL, act_high ? 1 : 0, 29, 29); enable_clocks(0); @@ -1855,6 +1931,9 @@ void dispc_lcd_enable_signal_polarity(bool act_high) void dispc_lcd_enable_signal(bool enable) { + if (!dss_has_feature(FEAT_LCDENABLESIGNAL)) + return; + enable_clocks(1); REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 28, 28); enable_clocks(0); @@ -1862,20 +1941,27 @@ void dispc_lcd_enable_signal(bool enable) void dispc_pck_free_enable(bool enable) { + if (!dss_has_feature(FEAT_PCKFREEENABLE)) + return; + enable_clocks(1); REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 27, 27); enable_clocks(0); } -void dispc_enable_fifohandcheck(bool enable) +void dispc_enable_fifohandcheck(enum omap_channel channel, bool enable) { enable_clocks(1); - REG_FLD_MOD(DISPC_CONFIG, enable ? 1 : 0, 16, 16); + if (channel == OMAP_DSS_CHANNEL_LCD2) + REG_FLD_MOD(DISPC_CONFIG2, enable ? 1 : 0, 16, 16); + else + REG_FLD_MOD(DISPC_CONFIG, enable ? 1 : 0, 16, 16); enable_clocks(0); } -void dispc_set_lcd_display_type(enum omap_lcd_display_type type) +void dispc_set_lcd_display_type(enum omap_channel channel, + enum omap_lcd_display_type type) { int mode; @@ -1894,7 +1980,10 @@ void dispc_set_lcd_display_type(enum omap_lcd_display_type type) } enable_clocks(1); - REG_FLD_MOD(DISPC_CONTROL, mode, 3, 3); + if (channel == OMAP_DSS_CHANNEL_LCD2) + REG_FLD_MOD(DISPC_CONTROL2, mode, 3, 3); + else + REG_FLD_MOD(DISPC_CONTROL, mode, 3, 3); enable_clocks(0); } @@ -1908,25 +1997,21 @@ void dispc_set_loadmode(enum omap_dss_load_mode mode) void dispc_set_default_color(enum omap_channel channel, u32 color) { - const struct dispc_reg def_reg[] = { DISPC_DEFAULT_COLOR0, - DISPC_DEFAULT_COLOR1 }; - enable_clocks(1); - dispc_write_reg(def_reg[channel], color); + dispc_write_reg(DISPC_DEFAULT_COLOR(channel), color); enable_clocks(0); } u32 dispc_get_default_color(enum omap_channel channel) { - const struct dispc_reg def_reg[] = { DISPC_DEFAULT_COLOR0, - DISPC_DEFAULT_COLOR1 }; u32 l; BUG_ON(channel != OMAP_DSS_CHANNEL_DIGIT && - channel != OMAP_DSS_CHANNEL_LCD); + channel != OMAP_DSS_CHANNEL_LCD && + channel != OMAP_DSS_CHANNEL_LCD2); enable_clocks(1); - l = dispc_read_reg(def_reg[channel]); + l = dispc_read_reg(DISPC_DEFAULT_COLOR(channel)); enable_clocks(0); return l; @@ -1936,16 +2021,15 @@ void dispc_set_trans_key(enum omap_channel ch, enum omap_dss_trans_key_type type, u32 trans_key) { - const struct dispc_reg tr_reg[] = { - DISPC_TRANS_COLOR0, DISPC_TRANS_COLOR1 }; - enable_clocks(1); if (ch == OMAP_DSS_CHANNEL_LCD) REG_FLD_MOD(DISPC_CONFIG, type, 11, 11); - else /* OMAP_DSS_CHANNEL_DIGIT */ + else if (ch == OMAP_DSS_CHANNEL_DIGIT) REG_FLD_MOD(DISPC_CONFIG, type, 13, 13); + else /* OMAP_DSS_CHANNEL_LCD2 */ + REG_FLD_MOD(DISPC_CONFIG2, type, 11, 11); - dispc_write_reg(tr_reg[ch], trans_key); + dispc_write_reg(DISPC_TRANS_COLOR(ch), trans_key); enable_clocks(0); } @@ -1953,21 +2037,20 @@ void dispc_get_trans_key(enum omap_channel ch, enum omap_dss_trans_key_type *type, u32 *trans_key) { - const struct dispc_reg tr_reg[] = { - DISPC_TRANS_COLOR0, DISPC_TRANS_COLOR1 }; - enable_clocks(1); if (type) { if (ch == OMAP_DSS_CHANNEL_LCD) *type = REG_GET(DISPC_CONFIG, 11, 11); else if (ch == OMAP_DSS_CHANNEL_DIGIT) *type = REG_GET(DISPC_CONFIG, 13, 13); + else if (ch == OMAP_DSS_CHANNEL_LCD2) + *type = REG_GET(DISPC_CONFIG2, 11, 11); else BUG(); } if (trans_key) - *trans_key = dispc_read_reg(tr_reg[ch]); + *trans_key = dispc_read_reg(DISPC_TRANS_COLOR(ch)); enable_clocks(0); } @@ -1976,8 +2059,10 @@ void dispc_enable_trans_key(enum omap_channel ch, bool enable) enable_clocks(1); if (ch == OMAP_DSS_CHANNEL_LCD) REG_FLD_MOD(DISPC_CONFIG, enable, 10, 10); - else /* OMAP_DSS_CHANNEL_DIGIT */ + else if (ch == OMAP_DSS_CHANNEL_DIGIT) REG_FLD_MOD(DISPC_CONFIG, enable, 12, 12); + else /* OMAP_DSS_CHANNEL_LCD2 */ + REG_FLD_MOD(DISPC_CONFIG2, enable, 10, 10); enable_clocks(0); } void dispc_enable_alpha_blending(enum omap_channel ch, bool enable) @@ -1988,8 +2073,10 @@ void dispc_enable_alpha_blending(enum omap_channel ch, bool enable) enable_clocks(1); if (ch == OMAP_DSS_CHANNEL_LCD) REG_FLD_MOD(DISPC_CONFIG, enable, 18, 18); - else /* OMAP_DSS_CHANNEL_DIGIT */ + else if (ch == OMAP_DSS_CHANNEL_DIGIT) REG_FLD_MOD(DISPC_CONFIG, enable, 19, 19); + else /* OMAP_DSS_CHANNEL_LCD2 */ + REG_FLD_MOD(DISPC_CONFIG2, enable, 18, 18); enable_clocks(0); } bool dispc_alpha_blending_enabled(enum omap_channel ch) @@ -2003,13 +2090,14 @@ bool dispc_alpha_blending_enabled(enum omap_channel ch) if (ch == OMAP_DSS_CHANNEL_LCD) enabled = REG_GET(DISPC_CONFIG, 18, 18); else if (ch == OMAP_DSS_CHANNEL_DIGIT) - enabled = REG_GET(DISPC_CONFIG, 18, 18); + enabled = REG_GET(DISPC_CONFIG, 19, 19); + else if (ch == OMAP_DSS_CHANNEL_LCD2) + enabled = REG_GET(DISPC_CONFIG2, 18, 18); else BUG(); enable_clocks(0); return enabled; - } @@ -2022,6 +2110,8 @@ bool dispc_trans_key_enabled(enum omap_channel ch) enabled = REG_GET(DISPC_CONFIG, 10, 10); else if (ch == OMAP_DSS_CHANNEL_DIGIT) enabled = REG_GET(DISPC_CONFIG, 12, 12); + else if (ch == OMAP_DSS_CHANNEL_LCD2) + enabled = REG_GET(DISPC_CONFIG2, 10, 10); else BUG(); enable_clocks(0); @@ -2030,7 +2120,7 @@ bool dispc_trans_key_enabled(enum omap_channel ch) } -void dispc_set_tft_data_lines(u8 data_lines) +void dispc_set_tft_data_lines(enum omap_channel channel, u8 data_lines) { int code; @@ -2053,11 +2143,15 @@ void dispc_set_tft_data_lines(u8 data_lines) } enable_clocks(1); - REG_FLD_MOD(DISPC_CONTROL, code, 9, 8); + if (channel == OMAP_DSS_CHANNEL_LCD2) + REG_FLD_MOD(DISPC_CONTROL2, code, 9, 8); + else + REG_FLD_MOD(DISPC_CONTROL, code, 9, 8); enable_clocks(0); } -void dispc_set_parallel_interface_mode(enum omap_parallel_interface_mode mode) +void dispc_set_parallel_interface_mode(enum omap_channel channel, + enum omap_parallel_interface_mode mode) { u32 l; int stallmode; @@ -2087,13 +2181,17 @@ void dispc_set_parallel_interface_mode(enum omap_parallel_interface_mode mode) enable_clocks(1); - l = dispc_read_reg(DISPC_CONTROL); - - l = FLD_MOD(l, stallmode, 11, 11); - l = FLD_MOD(l, gpout0, 15, 15); - l = FLD_MOD(l, gpout1, 16, 16); - - dispc_write_reg(DISPC_CONTROL, l); + if (channel == OMAP_DSS_CHANNEL_LCD2) { + l = dispc_read_reg(DISPC_CONTROL2); + l = FLD_MOD(l, stallmode, 11, 11); + dispc_write_reg(DISPC_CONTROL2, l); + } else { + l = dispc_read_reg(DISPC_CONTROL); + l = FLD_MOD(l, stallmode, 11, 11); + l = FLD_MOD(l, gpout0, 15, 15); + l = FLD_MOD(l, gpout1, 16, 16); + dispc_write_reg(DISPC_CONTROL, l); + } enable_clocks(0); } @@ -2129,8 +2227,8 @@ bool dispc_lcd_timings_ok(struct omap_video_timings *timings) timings->vfp, timings->vbp); } -static void _dispc_set_lcd_timings(int hsw, int hfp, int hbp, - int vsw, int vfp, int vbp) +static void _dispc_set_lcd_timings(enum omap_channel channel, int hsw, + int hfp, int hbp, int vsw, int vfp, int vbp) { u32 timing_h, timing_v; @@ -2149,13 +2247,14 @@ static void _dispc_set_lcd_timings(int hsw, int hfp, int hbp, } enable_clocks(1); - dispc_write_reg(DISPC_TIMING_H, timing_h); - dispc_write_reg(DISPC_TIMING_V, timing_v); + dispc_write_reg(DISPC_TIMING_H(channel), timing_h); + dispc_write_reg(DISPC_TIMING_V(channel), timing_v); enable_clocks(0); } /* change name to mode? */ -void dispc_set_lcd_timings(struct omap_video_timings *timings) +void dispc_set_lcd_timings(enum omap_channel channel, + struct omap_video_timings *timings) { unsigned xtot, ytot; unsigned long ht, vt; @@ -2165,10 +2264,11 @@ void dispc_set_lcd_timings(struct omap_video_timings *timings) timings->vfp, timings->vbp)) BUG(); - _dispc_set_lcd_timings(timings->hsw, timings->hfp, timings->hbp, - timings->vsw, timings->vfp, timings->vbp); + _dispc_set_lcd_timings(channel, timings->hsw, timings->hfp, + timings->hbp, timings->vsw, timings->vfp, + timings->vbp); - dispc_set_lcd_size(timings->x_res, timings->y_res); + dispc_set_lcd_size(channel, timings->x_res, timings->y_res); xtot = timings->x_res + timings->hfp + timings->hsw + timings->hbp; ytot = timings->y_res + timings->vfp + timings->vsw + timings->vbp; @@ -2176,7 +2276,8 @@ void dispc_set_lcd_timings(struct omap_video_timings *timings) ht = (timings->pixel_clock * 1000) / xtot; vt = (timings->pixel_clock * 1000) / xtot / ytot; - DSSDBG("xres %u yres %u\n", timings->x_res, timings->y_res); + DSSDBG("channel %d xres %u yres %u\n", channel, timings->x_res, + timings->y_res); DSSDBG("pck %u\n", timings->pixel_clock); DSSDBG("hsw %d hfp %d hbp %d vsw %d vfp %d vbp %d\n", timings->hsw, timings->hfp, timings->hbp, @@ -2185,21 +2286,23 @@ void dispc_set_lcd_timings(struct omap_video_timings *timings) DSSDBG("hsync %luHz, vsync %luHz\n", ht, vt); } -static void dispc_set_lcd_divisor(u16 lck_div, u16 pck_div) +static void dispc_set_lcd_divisor(enum omap_channel channel, u16 lck_div, + u16 pck_div) { BUG_ON(lck_div < 1); BUG_ON(pck_div < 2); enable_clocks(1); - dispc_write_reg(DISPC_DIVISOR, + dispc_write_reg(DISPC_DIVISOR(channel), FLD_VAL(lck_div, 23, 16) | FLD_VAL(pck_div, 7, 0)); enable_clocks(0); } -static void dispc_get_lcd_divisor(int *lck_div, int *pck_div) +static void dispc_get_lcd_divisor(enum omap_channel channel, int *lck_div, + int *pck_div) { u32 l; - l = dispc_read_reg(DISPC_DIVISOR); + l = dispc_read_reg(DISPC_DIVISOR(channel)); *lck_div = FLD_GET(l, 23, 16); *pck_div = FLD_GET(l, 7, 0); } @@ -2219,13 +2322,13 @@ unsigned long dispc_fclk_rate(void) return r; } -unsigned long dispc_lclk_rate(void) +unsigned long dispc_lclk_rate(enum omap_channel channel) { int lcd; unsigned long r; u32 l; - l = dispc_read_reg(DISPC_DIVISOR); + l = dispc_read_reg(DISPC_DIVISOR(channel)); lcd = FLD_GET(l, 23, 16); @@ -2234,13 +2337,13 @@ unsigned long dispc_lclk_rate(void) return r / lcd; } -unsigned long dispc_pclk_rate(void) +unsigned long dispc_pclk_rate(enum omap_channel channel) { int lcd, pcd; unsigned long r; u32 l; - l = dispc_read_reg(DISPC_DIVISOR); + l = dispc_read_reg(DISPC_DIVISOR(channel)); lcd = FLD_GET(l, 23, 16); pcd = FLD_GET(l, 7, 0); @@ -2256,8 +2359,6 @@ void dispc_dump_clocks(struct seq_file *s) enable_clocks(1); - dispc_get_lcd_divisor(&lcd, &pcd); - seq_printf(s, "- DISPC -\n"); seq_printf(s, "dispc fclk source = %s\n", @@ -2265,9 +2366,25 @@ void dispc_dump_clocks(struct seq_file *s) "dss1_alwon_fclk" : "dsi1_pll_fclk"); seq_printf(s, "fck\t\t%-16lu\n", dispc_fclk_rate()); - seq_printf(s, "lck\t\t%-16lulck div\t%u\n", dispc_lclk_rate(), lcd); - seq_printf(s, "pck\t\t%-16lupck div\t%u\n", dispc_pclk_rate(), pcd); + seq_printf(s, "- LCD1 -\n"); + + dispc_get_lcd_divisor(OMAP_DSS_CHANNEL_LCD, &lcd, &pcd); + + seq_printf(s, "lck\t\t%-16lulck div\t%u\n", + dispc_lclk_rate(OMAP_DSS_CHANNEL_LCD), lcd); + seq_printf(s, "pck\t\t%-16lupck div\t%u\n", + dispc_pclk_rate(OMAP_DSS_CHANNEL_LCD), pcd); + if (dss_has_feature(FEAT_MGR_LCD2)) { + seq_printf(s, "- LCD2 -\n"); + + dispc_get_lcd_divisor(OMAP_DSS_CHANNEL_LCD2, &lcd, &pcd); + + seq_printf(s, "lck\t\t%-16lulck div\t%u\n", + dispc_lclk_rate(OMAP_DSS_CHANNEL_LCD2), lcd); + seq_printf(s, "pck\t\t%-16lupck div\t%u\n", + dispc_pclk_rate(OMAP_DSS_CHANNEL_LCD2), pcd); + } enable_clocks(0); } @@ -2309,6 +2426,12 @@ void dispc_dump_irqs(struct seq_file *s) PIS(SYNC_LOST); PIS(SYNC_LOST_DIGIT); PIS(WAKEUP); + if (dss_has_feature(FEAT_MGR_LCD2)) { + PIS(FRAMEDONE2); + PIS(VSYNC2); + PIS(ACBIAS_COUNT_STAT2); + PIS(SYNC_LOST2); + } #undef PIS } #endif @@ -2327,19 +2450,30 @@ void dispc_dump_regs(struct seq_file *s) DUMPREG(DISPC_CONTROL); DUMPREG(DISPC_CONFIG); DUMPREG(DISPC_CAPABLE); - DUMPREG(DISPC_DEFAULT_COLOR0); - DUMPREG(DISPC_DEFAULT_COLOR1); - DUMPREG(DISPC_TRANS_COLOR0); - DUMPREG(DISPC_TRANS_COLOR1); + DUMPREG(DISPC_DEFAULT_COLOR(0)); + DUMPREG(DISPC_DEFAULT_COLOR(1)); + DUMPREG(DISPC_TRANS_COLOR(0)); + DUMPREG(DISPC_TRANS_COLOR(1)); DUMPREG(DISPC_LINE_STATUS); DUMPREG(DISPC_LINE_NUMBER); - DUMPREG(DISPC_TIMING_H); - DUMPREG(DISPC_TIMING_V); - DUMPREG(DISPC_POL_FREQ); - DUMPREG(DISPC_DIVISOR); + DUMPREG(DISPC_TIMING_H(0)); + DUMPREG(DISPC_TIMING_V(0)); + DUMPREG(DISPC_POL_FREQ(0)); + DUMPREG(DISPC_DIVISOR(0)); DUMPREG(DISPC_GLOBAL_ALPHA); DUMPREG(DISPC_SIZE_DIG); - DUMPREG(DISPC_SIZE_LCD); + DUMPREG(DISPC_SIZE_LCD(0)); + if (dss_has_feature(FEAT_MGR_LCD2)) { + DUMPREG(DISPC_CONTROL2); + DUMPREG(DISPC_CONFIG2); + DUMPREG(DISPC_DEFAULT_COLOR(2)); + DUMPREG(DISPC_TRANS_COLOR(2)); + DUMPREG(DISPC_TIMING_H(2)); + DUMPREG(DISPC_TIMING_V(2)); + DUMPREG(DISPC_POL_FREQ(2)); + DUMPREG(DISPC_DIVISOR(2)); + DUMPREG(DISPC_SIZE_LCD(2)); + } DUMPREG(DISPC_GFX_BA0); DUMPREG(DISPC_GFX_BA1); @@ -2353,13 +2487,22 @@ void dispc_dump_regs(struct seq_file *s) DUMPREG(DISPC_GFX_WINDOW_SKIP); DUMPREG(DISPC_GFX_TABLE_BA); - DUMPREG(DISPC_DATA_CYCLE1); - DUMPREG(DISPC_DATA_CYCLE2); - DUMPREG(DISPC_DATA_CYCLE3); - - DUMPREG(DISPC_CPR_COEF_R); - DUMPREG(DISPC_CPR_COEF_G); - DUMPREG(DISPC_CPR_COEF_B); + DUMPREG(DISPC_DATA_CYCLE1(0)); + DUMPREG(DISPC_DATA_CYCLE2(0)); + DUMPREG(DISPC_DATA_CYCLE3(0)); + + DUMPREG(DISPC_CPR_COEF_R(0)); + DUMPREG(DISPC_CPR_COEF_G(0)); + DUMPREG(DISPC_CPR_COEF_B(0)); + if (dss_has_feature(FEAT_MGR_LCD2)) { + DUMPREG(DISPC_DATA_CYCLE1(2)); + DUMPREG(DISPC_DATA_CYCLE2(2)); + DUMPREG(DISPC_DATA_CYCLE3(2)); + + DUMPREG(DISPC_CPR_COEF_R(2)); + DUMPREG(DISPC_CPR_COEF_G(2)); + DUMPREG(DISPC_CPR_COEF_B(2)); + } DUMPREG(DISPC_GFX_PRELOAD); @@ -2458,8 +2601,8 @@ void dispc_dump_regs(struct seq_file *s) #undef DUMPREG } -static void _dispc_set_pol_freq(bool onoff, bool rf, bool ieo, bool ipc, - bool ihs, bool ivs, u8 acbi, u8 acb) +static void _dispc_set_pol_freq(enum omap_channel channel, bool onoff, bool rf, + bool ieo, bool ipc, bool ihs, bool ivs, u8 acbi, u8 acb) { u32 l = 0; @@ -2476,13 +2619,14 @@ static void _dispc_set_pol_freq(bool onoff, bool rf, bool ieo, bool ipc, l |= FLD_VAL(acb, 7, 0); enable_clocks(1); - dispc_write_reg(DISPC_POL_FREQ, l); + dispc_write_reg(DISPC_POL_FREQ(channel), l); enable_clocks(0); } -void dispc_set_pol_freq(enum omap_panel_config config, u8 acbi, u8 acb) +void dispc_set_pol_freq(enum omap_channel channel, + enum omap_panel_config config, u8 acbi, u8 acb) { - _dispc_set_pol_freq((config & OMAP_DSS_LCD_ONOFF) != 0, + _dispc_set_pol_freq(channel, (config & OMAP_DSS_LCD_ONOFF) != 0, (config & OMAP_DSS_LCD_RF) != 0, (config & OMAP_DSS_LCD_IEO) != 0, (config & OMAP_DSS_LCD_IPC) != 0, @@ -2551,24 +2695,26 @@ int dispc_calc_clock_rates(unsigned long dispc_fclk_rate, return 0; } -int dispc_set_clock_div(struct dispc_clock_info *cinfo) +int dispc_set_clock_div(enum omap_channel channel, + struct dispc_clock_info *cinfo) { DSSDBG("lck = %lu (%u)\n", cinfo->lck, cinfo->lck_div); DSSDBG("pck = %lu (%u)\n", cinfo->pck, cinfo->pck_div); - dispc_set_lcd_divisor(cinfo->lck_div, cinfo->pck_div); + dispc_set_lcd_divisor(channel, cinfo->lck_div, cinfo->pck_div); return 0; } -int dispc_get_clock_div(struct dispc_clock_info *cinfo) +int dispc_get_clock_div(enum omap_channel channel, + struct dispc_clock_info *cinfo) { unsigned long fck; fck = dispc_fclk_rate(); - cinfo->lck_div = REG_GET(DISPC_DIVISOR, 23, 16); - cinfo->pck_div = REG_GET(DISPC_DIVISOR, 7, 0); + cinfo->lck_div = REG_GET(DISPC_DIVISOR(channel), 23, 16); + cinfo->pck_div = REG_GET(DISPC_DIVISOR(channel), 7, 0); cinfo->lck = fck / cinfo->lck_div; cinfo->pck = cinfo->lck / cinfo->pck_div; @@ -2708,6 +2854,8 @@ static void print_irq_status(u32 status) PIS(VID2_FIFO_UNDERFLOW); PIS(SYNC_LOST); PIS(SYNC_LOST_DIGIT); + if (dss_has_feature(FEAT_MGR_LCD2)) + PIS(SYNC_LOST2); #undef PIS printk("\n"); @@ -2926,6 +3074,45 @@ static void dispc_error_worker(struct work_struct *work) } } + if (errors & DISPC_IRQ_SYNC_LOST2) { + struct omap_overlay_manager *manager = NULL; + bool enable = false; + + DSSERR("SYNC_LOST for LCD2, disabling LCD2\n"); + + for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) { + struct omap_overlay_manager *mgr; + mgr = omap_dss_get_overlay_manager(i); + + if (mgr->id == OMAP_DSS_CHANNEL_LCD2) { + manager = mgr; + enable = mgr->device->state == + OMAP_DSS_DISPLAY_ACTIVE; + mgr->device->driver->disable(mgr->device); + break; + } + } + + if (manager) { + struct omap_dss_device *dssdev = manager->device; + for (i = 0; i < omap_dss_get_num_overlays(); ++i) { + struct omap_overlay *ovl; + ovl = omap_dss_get_overlay(i); + + if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC)) + continue; + + if (ovl->id != 0 && ovl->manager == manager) + dispc_enable_plane(ovl->id, 0); + } + + dispc_go(manager->id); + mdelay(50); + if (enable) + dssdev->driver->enable(dssdev); + } + } + if (errors & DISPC_IRQ_OCP_ERR) { DSSERR("OCP_ERR\n"); for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) { @@ -3033,6 +3220,8 @@ static void _omap_dispc_initialize_irq(void) memset(dispc.registered_isr, 0, sizeof(dispc.registered_isr)); dispc.irq_error_mask = DISPC_IRQ_MASK_ERROR; + if (dss_has_feature(FEAT_MGR_LCD2)) + dispc.irq_error_mask |= DISPC_IRQ_SYNC_LOST2; /* there's SYNC_LOST_DIGIT waiting after enabling the DSS, * so clear it */ @@ -3065,7 +3254,8 @@ static void _omap_dispc_initial_config(void) dispc_write_reg(DISPC_SYSCONFIG, l); /* FUNCGATED */ - REG_FLD_MOD(DISPC_CONFIG, 1, 9, 9); + if (dss_has_feature(FEAT_FUNCGATED)) + REG_FLD_MOD(DISPC_CONFIG, 1, 9, 9); /* L3 firewall setting: enable access to OCM RAM */ /* XXX this should be somewhere in plat-omap */ @@ -3139,17 +3329,18 @@ int dispc_setup_plane(enum omap_plane plane, enum omap_color_mode color_mode, bool ilace, enum omap_dss_rotation_type rotation_type, - u8 rotation, bool mirror, u8 global_alpha) + u8 rotation, bool mirror, u8 global_alpha, + u8 pre_mult_alpha, enum omap_channel channel) { int r = 0; DSSDBG("dispc_setup_plane %d, pa %x, sw %d, %d,%d, %dx%d -> " - "%dx%d, ilace %d, cmode %x, rot %d, mir %d\n", + "%dx%d, ilace %d, cmode %x, rot %d, mir %d chan %d\n", plane, paddr, screen_width, pos_x, pos_y, width, height, out_width, out_height, ilace, color_mode, - rotation, mirror); + rotation, mirror, channel); enable_clocks(1); @@ -3161,7 +3352,8 @@ int dispc_setup_plane(enum omap_plane plane, color_mode, ilace, rotation_type, rotation, mirror, - global_alpha); + global_alpha, + pre_mult_alpha, channel); enable_clocks(0); diff --git a/drivers/video/omap2/dss/dpi.c b/drivers/video/omap2/dss/dpi.c index 960e977a8bf0..75fb0a515430 100644 --- a/drivers/video/omap2/dss/dpi.c +++ b/drivers/video/omap2/dss/dpi.c @@ -40,8 +40,9 @@ static struct { } dpi; #ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL -static int dpi_set_dsi_clk(bool is_tft, unsigned long pck_req, - unsigned long *fck, int *lck_div, int *pck_div) +static int dpi_set_dsi_clk(struct omap_dss_device *dssdev, bool is_tft, + unsigned long pck_req, unsigned long *fck, int *lck_div, + int *pck_div) { struct dsi_clock_info dsi_cinfo; struct dispc_clock_info dispc_cinfo; @@ -58,7 +59,7 @@ static int dpi_set_dsi_clk(bool is_tft, unsigned long pck_req, dss_select_dispc_clk_source(DSS_SRC_DSI1_PLL_FCLK); - r = dispc_set_clock_div(&dispc_cinfo); + r = dispc_set_clock_div(dssdev->manager->id, &dispc_cinfo); if (r) return r; @@ -69,8 +70,9 @@ static int dpi_set_dsi_clk(bool is_tft, unsigned long pck_req, return 0; } #else -static int dpi_set_dispc_clk(bool is_tft, unsigned long pck_req, - unsigned long *fck, int *lck_div, int *pck_div) +static int dpi_set_dispc_clk(struct omap_dss_device *dssdev, bool is_tft, + unsigned long pck_req, unsigned long *fck, int *lck_div, + int *pck_div) { struct dss_clock_info dss_cinfo; struct dispc_clock_info dispc_cinfo; @@ -84,7 +86,7 @@ static int dpi_set_dispc_clk(bool is_tft, unsigned long pck_req, if (r) return r; - r = dispc_set_clock_div(&dispc_cinfo); + r = dispc_set_clock_div(dssdev->manager->id, &dispc_cinfo); if (r) return r; @@ -107,17 +109,17 @@ static int dpi_set_mode(struct omap_dss_device *dssdev) dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1); - dispc_set_pol_freq(dssdev->panel.config, dssdev->panel.acbi, - dssdev->panel.acb); + dispc_set_pol_freq(dssdev->manager->id, dssdev->panel.config, + dssdev->panel.acbi, dssdev->panel.acb); is_tft = (dssdev->panel.config & OMAP_DSS_LCD_TFT) != 0; #ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL - r = dpi_set_dsi_clk(is_tft, t->pixel_clock * 1000, - &fck, &lck_div, &pck_div); + r = dpi_set_dsi_clk(dssdev, is_tft, t->pixel_clock * 1000, &fck, + &lck_div, &pck_div); #else - r = dpi_set_dispc_clk(is_tft, t->pixel_clock * 1000, - &fck, &lck_div, &pck_div); + r = dpi_set_dispc_clk(dssdev, is_tft, t->pixel_clock * 1000, &fck, + &lck_div, &pck_div); #endif if (r) goto err0; @@ -132,7 +134,7 @@ static int dpi_set_mode(struct omap_dss_device *dssdev) t->pixel_clock = pck; } - dispc_set_lcd_timings(t); + dispc_set_lcd_timings(dssdev->manager->id, t); err0: dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1); @@ -145,10 +147,12 @@ static int dpi_basic_init(struct omap_dss_device *dssdev) is_tft = (dssdev->panel.config & OMAP_DSS_LCD_TFT) != 0; - dispc_set_parallel_interface_mode(OMAP_DSS_PARALLELMODE_BYPASS); - dispc_set_lcd_display_type(is_tft ? OMAP_DSS_LCD_DISPLAY_TFT : - OMAP_DSS_LCD_DISPLAY_STN); - dispc_set_tft_data_lines(dssdev->phy.dpi.data_lines); + dispc_set_parallel_interface_mode(dssdev->manager->id, + OMAP_DSS_PARALLELMODE_BYPASS); + dispc_set_lcd_display_type(dssdev->manager->id, is_tft ? + OMAP_DSS_LCD_DISPLAY_TFT : OMAP_DSS_LCD_DISPLAY_STN); + dispc_set_tft_data_lines(dssdev->manager->id, + dssdev->phy.dpi.data_lines); return 0; } @@ -234,7 +238,7 @@ void dpi_set_timings(struct omap_dss_device *dssdev, dssdev->panel.timings = *timings; if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) { dpi_set_mode(dssdev); - dispc_go(OMAP_DSS_CHANNEL_LCD); + dispc_go(dssdev->manager->id); } } EXPORT_SYMBOL(dpi_set_timings); diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index aa4f7a5fae29..ddf3a0560822 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c @@ -792,7 +792,8 @@ static int dsi_pll_power(enum dsi_pll_power_state state) } /* calculate clock rates using dividers in cinfo */ -static int dsi_calc_clock_rates(struct dsi_clock_info *cinfo) +static int dsi_calc_clock_rates(struct omap_dss_device *dssdev, + struct dsi_clock_info *cinfo) { if (cinfo->regn == 0 || cinfo->regn > REGN_MAX) return -EINVAL; @@ -812,7 +813,7 @@ static int dsi_calc_clock_rates(struct dsi_clock_info *cinfo) * with DSS2_FCK source also */ cinfo->highfreq = 0; } else { - cinfo->clkin = dispc_pclk_rate(); + cinfo->clkin = dispc_pclk_rate(dssdev->manager->id); if (cinfo->clkin < 32000000) cinfo->highfreq = 0; @@ -1206,8 +1207,8 @@ void dsi_dump_clocks(struct seq_file *s) seq_printf(s, "VP_CLK\t\t%lu\n" "VP_PCLK\t\t%lu\n", - dispc_lclk_rate(), - dispc_pclk_rate()); + dispc_lclk_rate(OMAP_DSS_CHANNEL_LCD), + dispc_pclk_rate(OMAP_DSS_CHANNEL_LCD)); enable_clocks(0); } @@ -2888,7 +2889,7 @@ int omap_dsi_prepare_update(struct omap_dss_device *dssdev, if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) { dss_setup_partial_planes(dssdev, x, y, w, h, enlarge_update_area); - dispc_set_lcd_size(*w, *h); + dispc_set_lcd_size(dssdev->manager->id, *w, *h); } return 0; @@ -2947,12 +2948,14 @@ static int dsi_display_init_dispc(struct omap_dss_device *dssdev) return r; } - dispc_set_lcd_display_type(OMAP_DSS_LCD_DISPLAY_TFT); + dispc_set_lcd_display_type(dssdev->manager->id, + OMAP_DSS_LCD_DISPLAY_TFT); - dispc_set_parallel_interface_mode(OMAP_DSS_PARALLELMODE_DSI); - dispc_enable_fifohandcheck(1); + dispc_set_parallel_interface_mode(dssdev->manager->id, + OMAP_DSS_PARALLELMODE_DSI); + dispc_enable_fifohandcheck(dssdev->manager->id, 1); - dispc_set_tft_data_lines(dssdev->ctrl.pixel_size); + dispc_set_tft_data_lines(dssdev->manager->id, dssdev->ctrl.pixel_size); { struct omap_video_timings timings = { @@ -2964,7 +2967,7 @@ static int dsi_display_init_dispc(struct omap_dss_device *dssdev) .vbp = 0, }; - dispc_set_lcd_timings(&timings); + dispc_set_lcd_timings(dssdev->manager->id, &timings); } return 0; @@ -2987,7 +2990,7 @@ static int dsi_configure_dsi_clocks(struct omap_dss_device *dssdev) cinfo.regm = dssdev->phy.dsi.div.regm; cinfo.regm3 = dssdev->phy.dsi.div.regm3; cinfo.regm4 = dssdev->phy.dsi.div.regm4; - r = dsi_calc_clock_rates(&cinfo); + r = dsi_calc_clock_rates(dssdev, &cinfo); if (r) { DSSERR("Failed to calc dsi clocks\n"); return r; @@ -3019,7 +3022,7 @@ static int dsi_configure_dispc_clocks(struct omap_dss_device *dssdev) return r; } - r = dispc_set_clock_div(&dispc_cinfo); + r = dispc_set_clock_div(dssdev->manager->id, &dispc_cinfo); if (r) { DSSERR("Failed to set dispc clocks\n"); return r; diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h index 5c7940d5f282..b394951120ac 100644 --- a/drivers/video/omap2/dss/dss.h +++ b/drivers/video/omap2/dss/dss.h @@ -333,9 +333,9 @@ void dispc_disable_sidle(void); void dispc_lcd_enable_signal_polarity(bool act_high); void dispc_lcd_enable_signal(bool enable); void dispc_pck_free_enable(bool enable); -void dispc_enable_fifohandcheck(bool enable); +void dispc_enable_fifohandcheck(enum omap_channel channel, bool enable); -void dispc_set_lcd_size(u16 width, u16 height); +void dispc_set_lcd_size(enum omap_channel channel, u16 width, u16 height); void dispc_set_digit_size(u16 width, u16 height); u32 dispc_get_plane_fifo_size(enum omap_plane plane); void dispc_setup_plane_fifo(enum omap_plane plane, u32 low, u32 high); @@ -359,7 +359,8 @@ int dispc_setup_plane(enum omap_plane plane, bool ilace, enum omap_dss_rotation_type rotation_type, u8 rotation, bool mirror, - u8 global_alpha); + u8 global_alpha, u8 pre_mult_alpha, + enum omap_channel channel); bool dispc_go_busy(enum omap_channel channel); void dispc_go(enum omap_channel channel); @@ -368,9 +369,11 @@ bool dispc_is_channel_enabled(enum omap_channel channel); int dispc_enable_plane(enum omap_plane plane, bool enable); void dispc_enable_replication(enum omap_plane plane, bool enable); -void dispc_set_parallel_interface_mode(enum omap_parallel_interface_mode mode); -void dispc_set_tft_data_lines(u8 data_lines); -void dispc_set_lcd_display_type(enum omap_lcd_display_type type); +void dispc_set_parallel_interface_mode(enum omap_channel channel, + enum omap_parallel_interface_mode mode); +void dispc_set_tft_data_lines(enum omap_channel channel, u8 data_lines); +void dispc_set_lcd_display_type(enum omap_channel channel, + enum omap_lcd_display_type type); void dispc_set_loadmode(enum omap_dss_load_mode mode); void dispc_set_default_color(enum omap_channel channel, u32 color); @@ -387,17 +390,21 @@ bool dispc_trans_key_enabled(enum omap_channel ch); bool dispc_alpha_blending_enabled(enum omap_channel ch); bool dispc_lcd_timings_ok(struct omap_video_timings *timings); -void dispc_set_lcd_timings(struct omap_video_timings *timings); +void dispc_set_lcd_timings(enum omap_channel channel, + struct omap_video_timings *timings); unsigned long dispc_fclk_rate(void); -unsigned long dispc_lclk_rate(void); -unsigned long dispc_pclk_rate(void); -void dispc_set_pol_freq(enum omap_panel_config config, u8 acbi, u8 acb); +unsigned long dispc_lclk_rate(enum omap_channel channel); +unsigned long dispc_pclk_rate(enum omap_channel channel); +void dispc_set_pol_freq(enum omap_channel channel, + enum omap_panel_config config, u8 acbi, u8 acb); void dispc_find_clk_divs(bool is_tft, unsigned long req_pck, unsigned long fck, struct dispc_clock_info *cinfo); int dispc_calc_clock_rates(unsigned long dispc_fclk_rate, struct dispc_clock_info *cinfo); -int dispc_set_clock_div(struct dispc_clock_info *cinfo); -int dispc_get_clock_div(struct dispc_clock_info *cinfo); +int dispc_set_clock_div(enum omap_channel channel, + struct dispc_clock_info *cinfo); +int dispc_get_clock_div(enum omap_channel channel, + struct dispc_clock_info *cinfo); /* VENC */ @@ -424,8 +431,8 @@ void rfbi_dump_regs(struct seq_file *s); int rfbi_configure(int rfbi_module, int bpp, int lines); void rfbi_enable_rfbi(bool enable); -void rfbi_transfer_area(u16 width, u16 height, - void (callback)(void *data), void *data); +void rfbi_transfer_area(struct omap_dss_device *dssdev, u16 width, + u16 height, void (callback)(void *data), void *data); void rfbi_set_timings(int rfbi_module, struct rfbi_timings *t); unsigned long rfbi_get_max_tx_rate(void); int rfbi_init_display(struct omap_dss_device *display); diff --git a/drivers/video/omap2/dss/dss_features.c b/drivers/video/omap2/dss/dss_features.c index 867f68de125f..cf3ef696e141 100644 --- a/drivers/video/omap2/dss/dss_features.c +++ b/drivers/video/omap2/dss/dss_features.c @@ -82,6 +82,18 @@ static const enum omap_display_type omap3_dss_supported_displays[] = { OMAP_DISPLAY_TYPE_VENC, }; +static const enum omap_display_type omap4_dss_supported_displays[] = { + /* OMAP_DSS_CHANNEL_LCD */ + OMAP_DISPLAY_TYPE_DBI | OMAP_DISPLAY_TYPE_DSI, + + /* OMAP_DSS_CHANNEL_DIGIT */ + OMAP_DISPLAY_TYPE_VENC, + + /* OMAP_DSS_CHANNEL_LCD2 */ + OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI | + OMAP_DISPLAY_TYPE_DSI, +}; + static const enum omap_color_mode omap2_dss_supported_color_modes[] = { /* OMAP_DSS_GFX */ OMAP_DSS_COLOR_CLUT1 | OMAP_DSS_COLOR_CLUT2 | @@ -127,6 +139,10 @@ static struct omap_dss_features omap2_dss_features = { .reg_fields = omap2_dss_reg_fields, .num_reg_fields = ARRAY_SIZE(omap2_dss_reg_fields), + .has_feature = + FEAT_LCDENABLEPOL | FEAT_LCDENABLESIGNAL | + FEAT_PCKFREEENABLE | FEAT_FUNCGATED, + .num_mgrs = 2, .num_ovls = 3, .supported_displays = omap2_dss_supported_displays, @@ -134,11 +150,29 @@ static struct omap_dss_features omap2_dss_features = { }; /* OMAP3 DSS Features */ -static struct omap_dss_features omap3_dss_features = { +static struct omap_dss_features omap3430_dss_features = { + .reg_fields = omap3_dss_reg_fields, + .num_reg_fields = ARRAY_SIZE(omap3_dss_reg_fields), + + .has_feature = + FEAT_GLOBAL_ALPHA | FEAT_LCDENABLEPOL | + FEAT_LCDENABLESIGNAL | FEAT_PCKFREEENABLE | + FEAT_FUNCGATED, + + .num_mgrs = 2, + .num_ovls = 3, + .supported_displays = omap3_dss_supported_displays, + .supported_color_modes = omap3_dss_supported_color_modes, +}; + +static struct omap_dss_features omap3630_dss_features = { .reg_fields = omap3_dss_reg_fields, .num_reg_fields = ARRAY_SIZE(omap3_dss_reg_fields), - .has_feature = FEAT_GLOBAL_ALPHA, + .has_feature = + FEAT_GLOBAL_ALPHA | FEAT_LCDENABLEPOL | + FEAT_LCDENABLESIGNAL | FEAT_PCKFREEENABLE | + FEAT_PRE_MULT_ALPHA | FEAT_FUNCGATED, .num_mgrs = 2, .num_ovls = 3, @@ -146,6 +180,21 @@ static struct omap_dss_features omap3_dss_features = { .supported_color_modes = omap3_dss_supported_color_modes, }; +/* OMAP4 DSS Features */ +static struct omap_dss_features omap4_dss_features = { + .reg_fields = omap3_dss_reg_fields, + .num_reg_fields = ARRAY_SIZE(omap3_dss_reg_fields), + + .has_feature = + FEAT_GLOBAL_ALPHA | FEAT_PRE_MULT_ALPHA | + FEAT_MGR_LCD2, + + .num_mgrs = 3, + .num_ovls = 3, + .supported_displays = omap4_dss_supported_displays, + .supported_color_modes = omap3_dss_supported_color_modes, +}; + /* Functions returning values related to a DSS feature */ int dss_feat_get_num_mgrs(void) { @@ -167,6 +216,13 @@ enum omap_color_mode dss_feat_get_supported_color_modes(enum omap_plane plane) return omap_current_dss_features->supported_color_modes[plane]; } +bool dss_feat_color_mode_supported(enum omap_plane plane, + enum omap_color_mode color_mode) +{ + return omap_current_dss_features->supported_color_modes[plane] & + color_mode; +} + /* DSS has_feature check */ bool dss_has_feature(enum dss_feat_id id) { @@ -186,6 +242,10 @@ void dss_features_init(void) { if (cpu_is_omap24xx()) omap_current_dss_features = &omap2_dss_features; + else if (cpu_is_omap3630()) + omap_current_dss_features = &omap3630_dss_features; + else if (cpu_is_omap34xx()) + omap_current_dss_features = &omap3430_dss_features; else - omap_current_dss_features = &omap3_dss_features; + omap_current_dss_features = &omap4_dss_features; } diff --git a/drivers/video/omap2/dss/dss_features.h b/drivers/video/omap2/dss/dss_features.h index cb231eaa9b31..b9c70be92588 100644 --- a/drivers/video/omap2/dss/dss_features.h +++ b/drivers/video/omap2/dss/dss_features.h @@ -20,13 +20,19 @@ #ifndef __OMAP2_DSS_FEATURES_H #define __OMAP2_DSS_FEATURES_H -#define MAX_DSS_MANAGERS 2 +#define MAX_DSS_MANAGERS 3 #define MAX_DSS_OVERLAYS 3 /* DSS has feature id */ enum dss_feat_id { FEAT_GLOBAL_ALPHA = 1 << 0, FEAT_GLOBAL_ALPHA_VID1 = 1 << 1, + FEAT_PRE_MULT_ALPHA = 1 << 2, + FEAT_LCDENABLEPOL = 1 << 3, + FEAT_LCDENABLESIGNAL = 1 << 4, + FEAT_PCKFREEENABLE = 1 << 5, + FEAT_FUNCGATED = 1 << 6, + FEAT_MGR_LCD2 = 1 << 7, }; /* DSS register field id */ @@ -43,6 +49,8 @@ int dss_feat_get_num_mgrs(void); int dss_feat_get_num_ovls(void); enum omap_display_type dss_feat_get_supported_displays(enum omap_channel channel); enum omap_color_mode dss_feat_get_supported_color_modes(enum omap_plane plane); +bool dss_feat_color_mode_supported(enum omap_plane plane, + enum omap_color_mode color_mode); bool dss_has_feature(enum dss_feat_id id); void dss_feat_get_reg_field(enum dss_feat_reg_field id, u8 *start, u8 *end); diff --git a/drivers/video/omap2/dss/manager.c b/drivers/video/omap2/dss/manager.c index 545e9b9a4d92..172d4e697309 100644 --- a/drivers/video/omap2/dss/manager.c +++ b/drivers/video/omap2/dss/manager.c @@ -406,6 +406,7 @@ struct overlay_cache_data { u16 out_width; /* if 0, out_width == width */ u16 out_height; /* if 0, out_height == height */ u8 global_alpha; + u8 pre_mult_alpha; enum omap_channel channel; bool replication; @@ -512,11 +513,14 @@ static int dss_mgr_wait_for_vsync(struct omap_overlay_manager *mgr) unsigned long timeout = msecs_to_jiffies(500); u32 irq; - if (mgr->device->type == OMAP_DISPLAY_TYPE_VENC) + if (mgr->device->type == OMAP_DISPLAY_TYPE_VENC) { irq = DISPC_IRQ_EVSYNC_ODD; - else - irq = DISPC_IRQ_VSYNC; - + } else { + if (mgr->id == OMAP_DSS_CHANNEL_LCD) + irq = DISPC_IRQ_VSYNC; + else + irq = DISPC_IRQ_VSYNC2; + } return omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout); } @@ -524,7 +528,6 @@ static int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr) { unsigned long timeout = msecs_to_jiffies(500); struct manager_cache_data *mc; - enum omap_channel channel; u32 irq; int r; int i; @@ -535,7 +538,6 @@ static int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr) if (dssdev->type == OMAP_DISPLAY_TYPE_VENC) { irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN; - channel = OMAP_DSS_CHANNEL_DIGIT; } else { if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) { enum omap_dss_update_mode mode; @@ -543,11 +545,14 @@ static int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr) if (mode != OMAP_DSS_UPDATE_AUTO) return 0; - irq = DISPC_IRQ_FRAMEDONE; + irq = (dssdev->manager->id == OMAP_DSS_CHANNEL_LCD) ? + DISPC_IRQ_FRAMEDONE + : DISPC_IRQ_FRAMEDONE2; } else { - irq = DISPC_IRQ_VSYNC; + irq = (dssdev->manager->id == OMAP_DSS_CHANNEL_LCD) ? + DISPC_IRQ_VSYNC + : DISPC_IRQ_VSYNC2; } - channel = OMAP_DSS_CHANNEL_LCD; } mc = &dss_cache.manager_cache[mgr->id]; @@ -594,7 +599,6 @@ static int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr) int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl) { unsigned long timeout = msecs_to_jiffies(500); - enum omap_channel channel; struct overlay_cache_data *oc; struct omap_dss_device *dssdev; u32 irq; @@ -611,7 +615,6 @@ int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl) if (dssdev->type == OMAP_DISPLAY_TYPE_VENC) { irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN; - channel = OMAP_DSS_CHANNEL_DIGIT; } else { if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) { enum omap_dss_update_mode mode; @@ -619,11 +622,14 @@ int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl) if (mode != OMAP_DSS_UPDATE_AUTO) return 0; - irq = DISPC_IRQ_FRAMEDONE; + irq = (dssdev->manager->id == OMAP_DSS_CHANNEL_LCD) ? + DISPC_IRQ_FRAMEDONE + : DISPC_IRQ_FRAMEDONE2; } else { - irq = DISPC_IRQ_VSYNC; + irq = (dssdev->manager->id == OMAP_DSS_CHANNEL_LCD) ? + DISPC_IRQ_VSYNC + : DISPC_IRQ_VSYNC2; } - channel = OMAP_DSS_CHANNEL_LCD; } oc = &dss_cache.overlay_cache[ovl->id]; @@ -842,7 +848,9 @@ static int configure_overlay(enum omap_plane plane) c->rotation_type, c->rotation, c->mirror, - c->global_alpha); + c->global_alpha, + c->pre_mult_alpha, + c->channel); if (r) { /* this shouldn't happen */ @@ -894,10 +902,10 @@ static int configure_dispc(void) r = 0; busy = false; - mgr_busy[0] = dispc_go_busy(0); - mgr_busy[1] = dispc_go_busy(1); - mgr_go[0] = false; - mgr_go[1] = false; + for (i = 0; i < num_mgrs; i++) { + mgr_busy[i] = dispc_go_busy(i); + mgr_go[i] = false; + } /* Commit overlay settings */ for (i = 0; i < num_ovls; ++i) { @@ -1156,9 +1164,10 @@ static void dss_apply_irq_handler(void *data, u32 mask) const int num_mgrs = dss_feat_get_num_mgrs(); int i, r; bool mgr_busy[MAX_DSS_MANAGERS]; + u32 irq_mask; - mgr_busy[0] = dispc_go_busy(0); - mgr_busy[1] = dispc_go_busy(1); + for (i = 0; i < num_mgrs; i++) + mgr_busy[i] = dispc_go_busy(i); spin_lock(&dss_cache.lock); @@ -1179,8 +1188,8 @@ static void dss_apply_irq_handler(void *data, u32 mask) goto end; /* re-read busy flags */ - mgr_busy[0] = dispc_go_busy(0); - mgr_busy[1] = dispc_go_busy(1); + for (i = 0; i < num_mgrs; i++) + mgr_busy[i] = dispc_go_busy(i); /* keep running as long as there are busy managers, so that * we can collect overlay-applied information */ @@ -1189,9 +1198,12 @@ static void dss_apply_irq_handler(void *data, u32 mask) goto end; } - omap_dispc_unregister_isr(dss_apply_irq_handler, NULL, - DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_ODD | - DISPC_IRQ_EVSYNC_EVEN); + irq_mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_ODD | + DISPC_IRQ_EVSYNC_EVEN; + if (dss_has_feature(FEAT_MGR_LCD2)) + irq_mask |= DISPC_IRQ_VSYNC2; + + omap_dispc_unregister_isr(dss_apply_irq_handler, NULL, irq_mask); dss_cache.irq_enabled = false; end: @@ -1265,6 +1277,7 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr) oc->out_width = ovl->info.out_width; oc->out_height = ovl->info.out_height; oc->global_alpha = ovl->info.global_alpha; + oc->pre_mult_alpha = ovl->info.pre_mult_alpha; oc->replication = dss_use_replication(dssdev, ovl->info.color_mode); @@ -1383,9 +1396,14 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr) r = 0; dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1); if (!dss_cache.irq_enabled) { - r = omap_dispc_register_isr(dss_apply_irq_handler, NULL, - DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_ODD | - DISPC_IRQ_EVSYNC_EVEN); + u32 mask; + + mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_ODD | + DISPC_IRQ_EVSYNC_EVEN; + if (dss_has_feature(FEAT_MGR_LCD2)) + mask |= DISPC_IRQ_VSYNC2; + + r = omap_dispc_register_isr(dss_apply_irq_handler, NULL, mask); dss_cache.irq_enabled = true; } configure_dispc(); @@ -1477,6 +1495,10 @@ int dss_init_overlay_managers(struct platform_device *pdev) mgr->name = "tv"; mgr->id = OMAP_DSS_CHANNEL_DIGIT; break; + case 2: + mgr->name = "lcd2"; + mgr->id = OMAP_DSS_CHANNEL_LCD2; + break; } mgr->set_device = &omap_dss_set_device; diff --git a/drivers/video/omap2/dss/overlay.c b/drivers/video/omap2/dss/overlay.c index 75642c22cac7..456efef03c20 100644 --- a/drivers/video/omap2/dss/overlay.c +++ b/drivers/video/omap2/dss/overlay.c @@ -257,6 +257,43 @@ static ssize_t overlay_global_alpha_store(struct omap_overlay *ovl, return size; } +static ssize_t overlay_pre_mult_alpha_show(struct omap_overlay *ovl, + char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%d\n", + ovl->info.pre_mult_alpha); +} + +static ssize_t overlay_pre_mult_alpha_store(struct omap_overlay *ovl, + const char *buf, size_t size) +{ + int r; + struct omap_overlay_info info; + + ovl->get_overlay_info(ovl, &info); + + /* only GFX and Video2 plane support pre alpha multiplied + * set zero for Video1 plane + */ + if (!dss_has_feature(FEAT_GLOBAL_ALPHA_VID1) && + ovl->id == OMAP_DSS_VIDEO1) + info.pre_mult_alpha = 0; + else + info.pre_mult_alpha = simple_strtoul(buf, NULL, 10); + + r = ovl->set_overlay_info(ovl, &info); + if (r) + return r; + + if (ovl->manager) { + r = ovl->manager->apply(ovl->manager); + if (r) + return r; + } + + return size; +} + struct overlay_attribute { struct attribute attr; ssize_t (*show)(struct omap_overlay *, char *); @@ -280,6 +317,9 @@ static OVERLAY_ATTR(enabled, S_IRUGO|S_IWUSR, overlay_enabled_show, overlay_enabled_store); static OVERLAY_ATTR(global_alpha, S_IRUGO|S_IWUSR, overlay_global_alpha_show, overlay_global_alpha_store); +static OVERLAY_ATTR(pre_mult_alpha, S_IRUGO|S_IWUSR, + overlay_pre_mult_alpha_show, + overlay_pre_mult_alpha_store); static struct attribute *overlay_sysfs_attrs[] = { &overlay_attr_name.attr, @@ -290,6 +330,7 @@ static struct attribute *overlay_sysfs_attrs[] = { &overlay_attr_output_size.attr, &overlay_attr_enabled.attr, &overlay_attr_global_alpha.attr, + &overlay_attr_pre_mult_alpha.attr, NULL }; @@ -623,12 +664,22 @@ void dss_recheck_connections(struct omap_dss_device *dssdev, bool force) int i; struct omap_overlay_manager *lcd_mgr; struct omap_overlay_manager *tv_mgr; + struct omap_overlay_manager *lcd2_mgr = NULL; struct omap_overlay_manager *mgr = NULL; lcd_mgr = omap_dss_get_overlay_manager(OMAP_DSS_OVL_MGR_LCD); tv_mgr = omap_dss_get_overlay_manager(OMAP_DSS_OVL_MGR_TV); - - if (dssdev->type != OMAP_DISPLAY_TYPE_VENC) { + if (dss_has_feature(FEAT_MGR_LCD2)) + lcd2_mgr = omap_dss_get_overlay_manager(OMAP_DSS_OVL_MGR_LCD2); + + if (dssdev->channel == OMAP_DSS_CHANNEL_LCD2) { + if (!lcd2_mgr->device || force) { + if (lcd2_mgr->device) + lcd2_mgr->unset_device(lcd2_mgr); + lcd2_mgr->set_device(lcd2_mgr, dssdev); + mgr = lcd2_mgr; + } + } else if (dssdev->type != OMAP_DISPLAY_TYPE_VENC) { if (!lcd_mgr->device || force) { if (lcd_mgr->device) lcd_mgr->unset_device(lcd_mgr); diff --git a/drivers/video/omap2/dss/rfbi.c b/drivers/video/omap2/dss/rfbi.c index bbe62464e92d..10a2ffe02882 100644 --- a/drivers/video/omap2/dss/rfbi.c +++ b/drivers/video/omap2/dss/rfbi.c @@ -301,8 +301,8 @@ void omap_rfbi_write_pixels(const void __iomem *buf, int scr_width, } EXPORT_SYMBOL(omap_rfbi_write_pixels); -void rfbi_transfer_area(u16 width, u16 height, - void (callback)(void *data), void *data) +void rfbi_transfer_area(struct omap_dss_device *dssdev, u16 width, + u16 height, void (*callback)(void *data), void *data) { u32 l; @@ -311,9 +311,9 @@ void rfbi_transfer_area(u16 width, u16 height, DSSDBG("rfbi_transfer_area %dx%d\n", width, height); - dispc_set_lcd_size(width, height); + dispc_set_lcd_size(dssdev->manager->id, width, height); - dispc_enable_channel(OMAP_DSS_CHANNEL_LCD, true); + dispc_enable_channel(dssdev->manager->id, true); rfbi.framedone_callback = callback; rfbi.framedone_callback_data = data; @@ -887,7 +887,7 @@ int omap_rfbi_prepare_update(struct omap_dss_device *dssdev, if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) { dss_setup_partial_planes(dssdev, x, y, w, h, true); - dispc_set_lcd_size(*w, *h); + dispc_set_lcd_size(dssdev->manager->id, *w, *h); } return 0; @@ -899,7 +899,7 @@ int omap_rfbi_update(struct omap_dss_device *dssdev, void (*callback)(void *), void *data) { if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) { - rfbi_transfer_area(w, h, callback, data); + rfbi_transfer_area(dssdev, w, h, callback, data); } else { struct omap_overlay *ovl; void __iomem *addr; @@ -1018,11 +1018,13 @@ int omapdss_rfbi_display_enable(struct omap_dss_device *dssdev) goto err1; } - dispc_set_lcd_display_type(OMAP_DSS_LCD_DISPLAY_TFT); + dispc_set_lcd_display_type(dssdev->manager->id, + OMAP_DSS_LCD_DISPLAY_TFT); - dispc_set_parallel_interface_mode(OMAP_DSS_PARALLELMODE_RFBI); + dispc_set_parallel_interface_mode(dssdev->manager->id, + OMAP_DSS_PARALLELMODE_RFBI); - dispc_set_tft_data_lines(dssdev->ctrl.pixel_size); + dispc_set_tft_data_lines(dssdev->manager->id, dssdev->ctrl.pixel_size); rfbi_configure(dssdev->phy.rfbi.channel, dssdev->ctrl.pixel_size, diff --git a/drivers/video/omap2/dss/sdi.c b/drivers/video/omap2/dss/sdi.c index ee07a3cc22ef..b64adf7dfc88 100644 --- a/drivers/video/omap2/dss/sdi.c +++ b/drivers/video/omap2/dss/sdi.c @@ -35,12 +35,16 @@ static struct { struct regulator *vdds_sdi_reg; } sdi; -static void sdi_basic_init(void) +static void sdi_basic_init(struct omap_dss_device *dssdev) + { - dispc_set_parallel_interface_mode(OMAP_DSS_PARALLELMODE_BYPASS); + dispc_set_parallel_interface_mode(dssdev->manager->id, + OMAP_DSS_PARALLELMODE_BYPASS); + + dispc_set_lcd_display_type(dssdev->manager->id, + OMAP_DSS_LCD_DISPLAY_TFT); - dispc_set_lcd_display_type(OMAP_DSS_LCD_DISPLAY_TFT); - dispc_set_tft_data_lines(24); + dispc_set_tft_data_lines(dssdev->manager->id, 24); dispc_lcd_enable_signal_polarity(1); } @@ -68,20 +72,20 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev) if (!sdi.skip_init) dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1); - sdi_basic_init(); + sdi_basic_init(dssdev); /* 15.5.9.1.2 */ dssdev->panel.config |= OMAP_DSS_LCD_RF | OMAP_DSS_LCD_ONOFF; - dispc_set_pol_freq(dssdev->panel.config, dssdev->panel.acbi, - dssdev->panel.acb); + dispc_set_pol_freq(dssdev->manager->id, dssdev->panel.config, + dssdev->panel.acbi, dssdev->panel.acb); if (!sdi.skip_init) { r = dss_calc_clock_div(1, t->pixel_clock * 1000, &dss_cinfo, &dispc_cinfo); } else { r = dss_get_clock_div(&dss_cinfo); - r = dispc_get_clock_div(&dispc_cinfo); + r = dispc_get_clock_div(dssdev->manager->id, &dispc_cinfo); } if (r) @@ -102,13 +106,13 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev) } - dispc_set_lcd_timings(t); + dispc_set_lcd_timings(dssdev->manager->id, t); r = dss_set_clock_div(&dss_cinfo); if (r) goto err2; - r = dispc_set_clock_div(&dispc_cinfo); + r = dispc_set_clock_div(dssdev->manager->id, &dispc_cinfo); if (r) goto err2; |