diff options
Diffstat (limited to 'drivers/video/omap2/dss/dispc.c')
-rw-r--r-- | drivers/video/omap2/dss/dispc.c | 1935 |
1 files changed, 1191 insertions, 744 deletions
diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c index 7a9a2e7..c5eaf90 100644 --- a/drivers/video/omap2/dss/dispc.c +++ b/drivers/video/omap2/dss/dispc.c @@ -33,12 +33,17 @@ #include <linux/workqueue.h> #include <linux/hardirq.h> #include <linux/interrupt.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <linux/ratelimit.h> #include <plat/sram.h> #include <plat/clock.h> - +#include <mach/tiler.h> +#include <plat/omap-pm.h> #include <video/omapdss.h> +#include "../clockdomain.h" #include "dss.h" #include "dss_features.h" #include "dispc.h" @@ -55,26 +60,20 @@ #define DISPC_MAX_NR_ISRS 8 +static struct clockdomain *l3_1_clkdm, *l3_2_clkdm; + struct omap_dispc_isr_data { omap_dispc_isr_t isr; void *arg; u32 mask; }; -struct dispc_h_coef { - s8 hc4; - s8 hc3; - u8 hc2; - s8 hc1; - s8 hc0; -}; - -struct dispc_v_coef { - s8 vc22; - s8 vc2; - u8 vc1; - s8 vc0; - s8 vc00; +struct dispc_hv_coef { + s8 hc0_vc00; + s8 hc1_vc0; + u8 hc2_vc1; + s8 hc3_vc2; + s8 hc4_vc22; }; #define REG_GET(idx, start, end) \ @@ -92,9 +91,17 @@ struct dispc_irq_stats { static struct { struct platform_device *pdev; void __iomem *base; + + int ctx_loss_cnt; + struct mutex runtime_lock; + int runtime_count; + int irq; + struct clk *dss_clk; + + u32 fifo_size[MAX_DSS_OVERLAYS]; - u32 fifo_size[3]; + u32 channel_irq[3]; /* Max channels hardcoded to 3*/ spinlock_t irq_lock; u32 irq_error_mask; @@ -102,6 +109,7 @@ static struct { u32 error_irqs; struct work_struct error_work; + bool ctx_valid; u32 ctx[DISPC_SZ_REGS / sizeof(u32)]; #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS @@ -134,18 +142,34 @@ static inline u32 dispc_read_reg(const u16 idx) return __raw_readl(dispc.base + idx); } +static int dispc_get_ctx_loss_count(void) +{ + struct device *dev = &dispc.pdev->dev; + struct omap_display_platform_data *pdata = dev->platform_data; + struct omap_dss_board_info *board_data = pdata->board_data; + int cnt; + + if (!board_data->get_context_loss_count) + return -ENOENT; + + cnt = board_data->get_context_loss_count(dev); + + WARN_ONCE(cnt < 0, "get_context_loss_count failed: %d\n", cnt); + + return cnt; +} + #define SR(reg) \ dispc.ctx[DISPC_##reg / sizeof(u32)] = dispc_read_reg(DISPC_##reg) #define RR(reg) \ dispc_write_reg(DISPC_##reg, dispc.ctx[DISPC_##reg / sizeof(u32)]) -void dispc_save_context(void) +static void dispc_save_context(void) { - int i; - if (cpu_is_omap24xx()) - return; + int i, o; + + DSSDBG("dispc_save_context\n"); - SR(SYSCONFIG); SR(IRQENABLE); SR(CONTROL); SR(CONFIG); @@ -158,7 +182,8 @@ void dispc_save_context(void) SR(TIMING_V(OMAP_DSS_CHANNEL_LCD)); SR(POL_FREQ(OMAP_DSS_CHANNEL_LCD)); SR(DIVISORo(OMAP_DSS_CHANNEL_LCD)); - SR(GLOBAL_ALPHA); + if (dss_has_feature(FEAT_GLOBAL_ALPHA)) + SR(GLOBAL_ALPHA); SR(SIZE_MGR(OMAP_DSS_CHANNEL_DIGIT)); SR(SIZE_MGR(OMAP_DSS_CHANNEL_LCD)); if (dss_has_feature(FEAT_MGR_LCD2)) { @@ -188,123 +213,108 @@ void dispc_save_context(void) SR(DATA_CYCLE2(OMAP_DSS_CHANNEL_LCD)); SR(DATA_CYCLE3(OMAP_DSS_CHANNEL_LCD)); - SR(CPR_COEF_R(OMAP_DSS_CHANNEL_LCD)); - SR(CPR_COEF_G(OMAP_DSS_CHANNEL_LCD)); - SR(CPR_COEF_B(OMAP_DSS_CHANNEL_LCD)); + if (dss_has_feature(FEAT_CPR)) { + SR(CPR_COEF_R(OMAP_DSS_CHANNEL_LCD)); + SR(CPR_COEF_G(OMAP_DSS_CHANNEL_LCD)); + SR(CPR_COEF_B(OMAP_DSS_CHANNEL_LCD)); + } if (dss_has_feature(FEAT_MGR_LCD2)) { - SR(CPR_COEF_B(OMAP_DSS_CHANNEL_LCD2)); - SR(CPR_COEF_G(OMAP_DSS_CHANNEL_LCD2)); - SR(CPR_COEF_R(OMAP_DSS_CHANNEL_LCD2)); + if (dss_has_feature(FEAT_CPR)) { + SR(CPR_COEF_B(OMAP_DSS_CHANNEL_LCD2)); + SR(CPR_COEF_G(OMAP_DSS_CHANNEL_LCD2)); + SR(CPR_COEF_R(OMAP_DSS_CHANNEL_LCD2)); + } SR(DATA_CYCLE1(OMAP_DSS_CHANNEL_LCD2)); SR(DATA_CYCLE2(OMAP_DSS_CHANNEL_LCD2)); SR(DATA_CYCLE3(OMAP_DSS_CHANNEL_LCD2)); } - SR(OVL_PRELOAD(OMAP_DSS_GFX)); + if (dss_has_feature(FEAT_PRELOAD)) + SR(OVL_PRELOAD(OMAP_DSS_GFX)); - /* VID1 */ - SR(OVL_BA0(OMAP_DSS_VIDEO1)); - SR(OVL_BA1(OMAP_DSS_VIDEO1)); - SR(OVL_POSITION(OMAP_DSS_VIDEO1)); - SR(OVL_SIZE(OMAP_DSS_VIDEO1)); - SR(OVL_ATTRIBUTES(OMAP_DSS_VIDEO1)); - SR(OVL_FIFO_THRESHOLD(OMAP_DSS_VIDEO1)); - SR(OVL_ROW_INC(OMAP_DSS_VIDEO1)); - SR(OVL_PIXEL_INC(OMAP_DSS_VIDEO1)); - SR(OVL_FIR(OMAP_DSS_VIDEO1)); - SR(OVL_PICTURE_SIZE(OMAP_DSS_VIDEO1)); - SR(OVL_ACCU0(OMAP_DSS_VIDEO1)); - SR(OVL_ACCU1(OMAP_DSS_VIDEO1)); + /* VID1-3 */ + for (o = OMAP_DSS_VIDEO1; o <= OMAP_DSS_VIDEO3; o++) { + if (o == OMAP_DSS_VIDEO3 && !dss_has_feature(FEAT_OVL_VID3)) + continue; - for (i = 0; i < 8; i++) - SR(OVL_FIR_COEF_H(OMAP_DSS_VIDEO1, i)); + SR(OVL_BA0(o)); + SR(OVL_BA1(o)); + SR(OVL_POSITION(o)); + SR(OVL_SIZE(o)); + SR(OVL_ATTRIBUTES(o)); + SR(OVL_FIFO_THRESHOLD(o)); + SR(OVL_ROW_INC(o)); + SR(OVL_PIXEL_INC(o)); + SR(OVL_FIR(o)); + SR(OVL_PICTURE_SIZE(o)); + SR(OVL_ACCU0(o)); + SR(OVL_ACCU1(o)); - for (i = 0; i < 8; i++) - SR(OVL_FIR_COEF_HV(OMAP_DSS_VIDEO1, i)); + for (i = 0; i < 8; i++) + SR(OVL_FIR_COEF_H(o, i)); - for (i = 0; i < 5; i++) - SR(OVL_CONV_COEF(OMAP_DSS_VIDEO1, i)); + for (i = 0; i < 8; i++) + SR(OVL_FIR_COEF_HV(o, i)); - for (i = 0; i < 8; i++) - SR(OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, i)); + for (i = 0; i < 5; i++) + SR(OVL_CONV_COEF(o, i)); - if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) { - SR(OVL_BA0_UV(OMAP_DSS_VIDEO1)); - SR(OVL_BA1_UV(OMAP_DSS_VIDEO1)); - SR(OVL_FIR2(OMAP_DSS_VIDEO1)); - SR(OVL_ACCU2_0(OMAP_DSS_VIDEO1)); - SR(OVL_ACCU2_1(OMAP_DSS_VIDEO1)); + if (dss_has_feature(FEAT_FIR_COEF_V)) { + for (i = 0; i < 8; i++) + SR(OVL_FIR_COEF_V(o, i)); + } - for (i = 0; i < 8; i++) - SR(OVL_FIR_COEF_H2(OMAP_DSS_VIDEO1, i)); + if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) { + SR(OVL_BA0_UV(o)); + SR(OVL_BA1_UV(o)); + SR(OVL_FIR2(o)); + SR(OVL_ACCU2_0(o)); + SR(OVL_ACCU2_1(o)); - for (i = 0; i < 8; i++) - SR(OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO1, i)); + for (i = 0; i < 8; i++) + SR(OVL_FIR_COEF_H2(o, i)); - for (i = 0; i < 8; i++) - SR(OVL_FIR_COEF_V2(OMAP_DSS_VIDEO1, i)); - } - if (dss_has_feature(FEAT_ATTR2)) - SR(OVL_ATTRIBUTES2(OMAP_DSS_VIDEO1)); + for (i = 0; i < 8; i++) + SR(OVL_FIR_COEF_HV2(o, i)); - SR(OVL_PRELOAD(OMAP_DSS_VIDEO1)); - - /* VID2 */ - SR(OVL_BA0(OMAP_DSS_VIDEO2)); - SR(OVL_BA1(OMAP_DSS_VIDEO2)); - SR(OVL_POSITION(OMAP_DSS_VIDEO2)); - SR(OVL_SIZE(OMAP_DSS_VIDEO2)); - SR(OVL_ATTRIBUTES(OMAP_DSS_VIDEO2)); - SR(OVL_FIFO_THRESHOLD(OMAP_DSS_VIDEO2)); - SR(OVL_ROW_INC(OMAP_DSS_VIDEO2)); - SR(OVL_PIXEL_INC(OMAP_DSS_VIDEO2)); - SR(OVL_FIR(OMAP_DSS_VIDEO2)); - SR(OVL_PICTURE_SIZE(OMAP_DSS_VIDEO2)); - SR(OVL_ACCU0(OMAP_DSS_VIDEO2)); - SR(OVL_ACCU1(OMAP_DSS_VIDEO2)); + for (i = 0; i < 8; i++) + SR(OVL_FIR_COEF_V2(o, i)); + } + if (dss_has_feature(FEAT_ATTR2)) + SR(OVL_ATTRIBUTES2(o)); - for (i = 0; i < 8; i++) - SR(OVL_FIR_COEF_H(OMAP_DSS_VIDEO2, i)); + if (dss_has_feature(FEAT_PRELOAD)) + SR(OVL_PRELOAD(o)); + } - for (i = 0; i < 8; i++) - SR(OVL_FIR_COEF_HV(OMAP_DSS_VIDEO2, i)); + if (dss_has_feature(FEAT_CORE_CLK_DIV)) + SR(DIVISOR); - for (i = 0; i < 5; i++) - SR(OVL_CONV_COEF(OMAP_DSS_VIDEO2, i)); + dispc.ctx_loss_cnt = dispc_get_ctx_loss_count(); + dispc.ctx_valid = true; - for (i = 0; i < 8; i++) - SR(OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, i)); + DSSDBG("context saved, ctx_loss_count %d\n", dispc.ctx_loss_cnt); +} - if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) { - SR(OVL_BA0_UV(OMAP_DSS_VIDEO2)); - SR(OVL_BA1_UV(OMAP_DSS_VIDEO2)); - SR(OVL_FIR2(OMAP_DSS_VIDEO2)); - SR(OVL_ACCU2_0(OMAP_DSS_VIDEO2)); - SR(OVL_ACCU2_1(OMAP_DSS_VIDEO2)); +static void dispc_restore_context(void) +{ + struct device *dev = &dispc.pdev->dev; + int i, o, ctx; - for (i = 0; i < 8; i++) - SR(OVL_FIR_COEF_H2(OMAP_DSS_VIDEO2, i)); + DSSDBG("dispc_restore_context\n"); - for (i = 0; i < 8; i++) - SR(OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO2, i)); + if (!dispc.ctx_valid) + return; - for (i = 0; i < 8; i++) - SR(OVL_FIR_COEF_V2(OMAP_DSS_VIDEO2, i)); - } - if (dss_has_feature(FEAT_ATTR2)) - SR(OVL_ATTRIBUTES2(OMAP_DSS_VIDEO2)); + ctx = dispc_get_ctx_loss_count(); - SR(OVL_PRELOAD(OMAP_DSS_VIDEO2)); + if (!omap_pm_was_context_lost(dev)) + return; - if (dss_has_feature(FEAT_CORE_CLK_DIV)) - SR(DIVISOR); -} + DSSDBG("ctx_loss_count: saved %d, current %d\n", + dispc.ctx_loss_cnt, ctx); -void dispc_restore_context(void) -{ - int i; - RR(SYSCONFIG); /*RR(IRQENABLE);*/ /*RR(CONTROL);*/ RR(CONFIG); @@ -317,7 +327,8 @@ void dispc_restore_context(void) RR(TIMING_V(OMAP_DSS_CHANNEL_LCD)); RR(POL_FREQ(OMAP_DSS_CHANNEL_LCD)); RR(DIVISORo(OMAP_DSS_CHANNEL_LCD)); - RR(GLOBAL_ALPHA); + if (dss_has_feature(FEAT_GLOBAL_ALPHA)) + RR(GLOBAL_ALPHA); RR(SIZE_MGR(OMAP_DSS_CHANNEL_DIGIT)); RR(SIZE_MGR(OMAP_DSS_CHANNEL_LCD)); if (dss_has_feature(FEAT_MGR_LCD2)) { @@ -347,114 +358,81 @@ void dispc_restore_context(void) RR(DATA_CYCLE2(OMAP_DSS_CHANNEL_LCD)); RR(DATA_CYCLE3(OMAP_DSS_CHANNEL_LCD)); - RR(CPR_COEF_R(OMAP_DSS_CHANNEL_LCD)); - RR(CPR_COEF_G(OMAP_DSS_CHANNEL_LCD)); - RR(CPR_COEF_B(OMAP_DSS_CHANNEL_LCD)); + if (dss_has_feature(FEAT_CPR)) { + RR(CPR_COEF_R(OMAP_DSS_CHANNEL_LCD)); + RR(CPR_COEF_G(OMAP_DSS_CHANNEL_LCD)); + RR(CPR_COEF_B(OMAP_DSS_CHANNEL_LCD)); + } if (dss_has_feature(FEAT_MGR_LCD2)) { RR(DATA_CYCLE1(OMAP_DSS_CHANNEL_LCD2)); RR(DATA_CYCLE2(OMAP_DSS_CHANNEL_LCD2)); RR(DATA_CYCLE3(OMAP_DSS_CHANNEL_LCD2)); - RR(CPR_COEF_B(OMAP_DSS_CHANNEL_LCD2)); - RR(CPR_COEF_G(OMAP_DSS_CHANNEL_LCD2)); - RR(CPR_COEF_R(OMAP_DSS_CHANNEL_LCD2)); + if (dss_has_feature(FEAT_CPR)) { + RR(CPR_COEF_B(OMAP_DSS_CHANNEL_LCD2)); + RR(CPR_COEF_G(OMAP_DSS_CHANNEL_LCD2)); + RR(CPR_COEF_R(OMAP_DSS_CHANNEL_LCD2)); + } } - RR(OVL_PRELOAD(OMAP_DSS_GFX)); - - /* VID1 */ - RR(OVL_BA0(OMAP_DSS_VIDEO1)); - RR(OVL_BA1(OMAP_DSS_VIDEO1)); - RR(OVL_POSITION(OMAP_DSS_VIDEO1)); - RR(OVL_SIZE(OMAP_DSS_VIDEO1)); - RR(OVL_ATTRIBUTES(OMAP_DSS_VIDEO1)); - RR(OVL_FIFO_THRESHOLD(OMAP_DSS_VIDEO1)); - RR(OVL_ROW_INC(OMAP_DSS_VIDEO1)); - RR(OVL_PIXEL_INC(OMAP_DSS_VIDEO1)); - RR(OVL_FIR(OMAP_DSS_VIDEO1)); - RR(OVL_PICTURE_SIZE(OMAP_DSS_VIDEO1)); - RR(OVL_ACCU0(OMAP_DSS_VIDEO1)); - RR(OVL_ACCU1(OMAP_DSS_VIDEO1)); - - for (i = 0; i < 8; i++) - RR(OVL_FIR_COEF_H(OMAP_DSS_VIDEO1, i)); - - for (i = 0; i < 8; i++) - RR(OVL_FIR_COEF_HV(OMAP_DSS_VIDEO1, i)); + if (dss_has_feature(FEAT_PRELOAD)) + RR(OVL_PRELOAD(OMAP_DSS_GFX)); - for (i = 0; i < 5; i++) - RR(OVL_CONV_COEF(OMAP_DSS_VIDEO1, i)); - for (i = 0; i < 8; i++) - RR(OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, i)); - - if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) { - RR(OVL_BA0_UV(OMAP_DSS_VIDEO1)); - RR(OVL_BA1_UV(OMAP_DSS_VIDEO1)); - RR(OVL_FIR2(OMAP_DSS_VIDEO1)); - RR(OVL_ACCU2_0(OMAP_DSS_VIDEO1)); - RR(OVL_ACCU2_1(OMAP_DSS_VIDEO1)); + /* VID1-3 */ + for (o = OMAP_DSS_VIDEO1; o <= OMAP_DSS_VIDEO3; o++) { + if (o == OMAP_DSS_VIDEO3 && !dss_has_feature(FEAT_OVL_VID3)) + continue; - for (i = 0; i < 8; i++) - RR(OVL_FIR_COEF_H2(OMAP_DSS_VIDEO1, i)); + RR(OVL_BA0(o)); + RR(OVL_BA1(o)); + RR(OVL_POSITION(o)); + RR(OVL_SIZE(o)); + RR(OVL_ATTRIBUTES(o)); + RR(OVL_FIFO_THRESHOLD(o)); + RR(OVL_ROW_INC(o)); + RR(OVL_PIXEL_INC(o)); + RR(OVL_FIR(o)); + RR(OVL_PICTURE_SIZE(o)); + RR(OVL_ACCU0(o)); + RR(OVL_ACCU1(o)); for (i = 0; i < 8; i++) - RR(OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO1, i)); + RR(OVL_FIR_COEF_H(o, i)); for (i = 0; i < 8; i++) - RR(OVL_FIR_COEF_V2(OMAP_DSS_VIDEO1, i)); - } - if (dss_has_feature(FEAT_ATTR2)) - RR(OVL_ATTRIBUTES2(OMAP_DSS_VIDEO1)); - - RR(OVL_PRELOAD(OMAP_DSS_VIDEO1)); - - /* VID2 */ - RR(OVL_BA0(OMAP_DSS_VIDEO2)); - RR(OVL_BA1(OMAP_DSS_VIDEO2)); - RR(OVL_POSITION(OMAP_DSS_VIDEO2)); - RR(OVL_SIZE(OMAP_DSS_VIDEO2)); - RR(OVL_ATTRIBUTES(OMAP_DSS_VIDEO2)); - RR(OVL_FIFO_THRESHOLD(OMAP_DSS_VIDEO2)); - RR(OVL_ROW_INC(OMAP_DSS_VIDEO2)); - RR(OVL_PIXEL_INC(OMAP_DSS_VIDEO2)); - RR(OVL_FIR(OMAP_DSS_VIDEO2)); - RR(OVL_PICTURE_SIZE(OMAP_DSS_VIDEO2)); - RR(OVL_ACCU0(OMAP_DSS_VIDEO2)); - RR(OVL_ACCU1(OMAP_DSS_VIDEO2)); + RR(OVL_FIR_COEF_HV(o, i)); - for (i = 0; i < 8; i++) - RR(OVL_FIR_COEF_H(OMAP_DSS_VIDEO2, i)); + for (i = 0; i < 5; i++) + RR(OVL_CONV_COEF(o, i)); - for (i = 0; i < 8; i++) - RR(OVL_FIR_COEF_HV(OMAP_DSS_VIDEO2, i)); - - for (i = 0; i < 5; i++) - RR(OVL_CONV_COEF(OMAP_DSS_VIDEO2, i)); + if (dss_has_feature(FEAT_FIR_COEF_V)) { + for (i = 0; i < 8; i++) + RR(OVL_FIR_COEF_V(o, i)); + } - for (i = 0; i < 8; i++) - RR(OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, i)); + if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) { + RR(OVL_BA0_UV(o)); + RR(OVL_BA1_UV(o)); + RR(OVL_FIR2(o)); + RR(OVL_ACCU2_0(o)); + RR(OVL_ACCU2_1(o)); - if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) { - RR(OVL_BA0_UV(OMAP_DSS_VIDEO2)); - RR(OVL_BA1_UV(OMAP_DSS_VIDEO2)); - RR(OVL_FIR2(OMAP_DSS_VIDEO2)); - RR(OVL_ACCU2_0(OMAP_DSS_VIDEO2)); - RR(OVL_ACCU2_1(OMAP_DSS_VIDEO2)); + for (i = 0; i < 8; i++) + RR(OVL_FIR_COEF_H2(o, i)); - for (i = 0; i < 8; i++) - RR(OVL_FIR_COEF_H2(OMAP_DSS_VIDEO2, i)); + for (i = 0; i < 8; i++) + RR(OVL_FIR_COEF_HV2(o, i)); - for (i = 0; i < 8; i++) - RR(OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO2, i)); + for (i = 0; i < 8; i++) + RR(OVL_FIR_COEF_V2(o, i)); + } + if (dss_has_feature(FEAT_ATTR2)) + RR(OVL_ATTRIBUTES2(o)); - for (i = 0; i < 8; i++) - RR(OVL_FIR_COEF_V2(OMAP_DSS_VIDEO2, i)); + if (dss_has_feature(FEAT_PRELOAD)) + RR(OVL_PRELOAD(o)); } - if (dss_has_feature(FEAT_ATTR2)) - RR(OVL_ATTRIBUTES2(OMAP_DSS_VIDEO2)); - - RR(OVL_PRELOAD(OMAP_DSS_VIDEO2)); if (dss_has_feature(FEAT_CORE_CLK_DIV)) RR(DIVISOR); @@ -471,19 +449,176 @@ void dispc_restore_context(void) * the context is fully restored */ RR(IRQENABLE); + + DSSDBG("context restored\n"); } #undef SR #undef RR -static inline void enable_clocks(bool enable) +static u32 dispc_calculate_threshold(enum omap_plane plane, u32 paddr, + u32 puv_addr, u16 width, u16 height, + s32 row_inc, s32 pix_inc) { - if (enable) - dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK); - else - dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK); + int shift; + u32 channel_no = plane; + u32 val, burstsize, doublestride; + u32 rotation, bursttype, color_mode; + struct dispc_config dispc_reg_config; + + if (width >= 1920) + return 1500; + + /* Get the burst size */ + shift = (plane == OMAP_DSS_GFX) ? 6 : 14; + val = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane)); + burstsize = FLD_GET(val, shift + 1, shift); + doublestride = FLD_GET(val, 22, 22); + rotation = FLD_GET(val, 13, 12); + bursttype = FLD_GET(val, 29, 29); + color_mode = FLD_GET(val, 4, 1); + + /* base address for frame (Luma frame in case of YUV420) */ + dispc_reg_config.ba = paddr; + /* base address for Chroma frame in case of YUV420 */ + dispc_reg_config.bacbcr = puv_addr; + /* OrgSizeX for frame */ + dispc_reg_config.sizex = width - 1; + /* OrgSizeY for frame */ + dispc_reg_config.sizey = height - 1; + /* burst size */ + dispc_reg_config.burstsize = burstsize; + /* pixel increment */ + dispc_reg_config.pixelinc = pix_inc; + /* row increment */ + dispc_reg_config.rowinc = row_inc; + /* burst type: 1D/2D */ + dispc_reg_config.bursttype = bursttype; + /* chroma DoubleStride when in YUV420 format */ + dispc_reg_config.doublestride = doublestride; + /* Pixcel format of the frame.*/ + dispc_reg_config.format = color_mode; + /* Rotation of frame */ + dispc_reg_config.rotation = rotation; + + /* DMA buffer allications - assuming reset values */ + dispc_reg_config.gfx_top_buffer = 0; + dispc_reg_config.gfx_bottom_buffer = 0; + dispc_reg_config.vid1_top_buffer = 1; + dispc_reg_config.vid1_bottom_buffer = 1; + dispc_reg_config.vid2_top_buffer = 2; + dispc_reg_config.vid2_bottom_buffer = 2; + dispc_reg_config.vid3_top_buffer = 3; + dispc_reg_config.vid3_bottom_buffer = 3; + dispc_reg_config.wb_top_buffer = 4; + dispc_reg_config.wb_bottom_buffer = 4; + + /* antiFlicker is off */ + dispc_reg_config.antiflicker = 0; + + return sa_calc_wrap(&dispc_reg_config, channel_no); } +int dispc_runtime_get(void) +{ + int r; + + mutex_lock(&dispc.runtime_lock); + + if (dispc.runtime_count++ == 0) { + DSSDBG("dispc_runtime_get\n"); + + /* + * OMAP4 ERRATUM xxxx: Mstandby and disconnect protocol issue + * Impacts: all OMAP4 devices + * Simplfied Description: + * issue #1: The handshake between IP modules on L3_1 and L3_2 + * peripherals with PRCM has a limitation in a certain time + * window of L4 clock cycle. Due to the fact that a wrong + * variant of stall signal was used in circuit of PRCM, the + * intitator-interconnect protocol is broken when the time + * window is hit where the PRCM requires the interconnect to go + * to idle while intitator asks to wakeup. + * Issue #2: DISPC asserts a sub-mstandby signal for a short + * period. In this time interval, IP block requests + * disconnection of Master port, and results in Mstandby and + * wait request to PRCM. In parallel, if mstandby is de-asserted + * by DISPC simultaneously, interconnect requests for a + * reconnect for one cycle alone resulting in a disconnect + * protocol violation and a deadlock of the system. + * + * Workaround: + * L3_1 clock domain must not be programmed in HW_AUTO if + * Static dependency with DSS is enabled and DSS clock domain + * is ON. Same for L3_2. + */ + if (cpu_is_omap44xx()) { + clkdm_deny_idle(l3_1_clkdm); + clkdm_deny_idle(l3_2_clkdm); + } + + r = dss_runtime_get(); + if (r) + goto err_dss_get; + + /* XXX dispc fclk can also come from DSI PLL */ + clk_enable(dispc.dss_clk); + + r = pm_runtime_get_sync(&dispc.pdev->dev); + WARN_ON(r); + if (r < 0) + goto err_runtime_get; + + dispc_restore_context(); + } + + mutex_unlock(&dispc.runtime_lock); + + return 0; + +err_runtime_get: + clk_disable(dispc.dss_clk); + dss_runtime_put(); +err_dss_get: + mutex_unlock(&dispc.runtime_lock); + + return r; +} + +void dispc_runtime_put(void) +{ + mutex_lock(&dispc.runtime_lock); + + if (--dispc.runtime_count == 0) { + int r; + + DSSDBG("dispc_runtime_put\n"); + + dispc_save_context(); + + r = pm_runtime_put_sync(&dispc.pdev->dev); + WARN_ON(r); + + clk_disable(dispc.dss_clk); + + dss_runtime_put(); + + /* + * OMAP4 ERRATUM xxxx: Mstandby and disconnect protocol issue + * Workaround: + * Restore L3_1 amd L3_2 CD to HW_AUTO, when DSS module idles. + */ + if (cpu_is_omap44xx()) { + clkdm_allow_idle(l3_1_clkdm); + clkdm_allow_idle(l3_2_clkdm); + } + + } + + mutex_unlock(&dispc.runtime_lock); +} + + bool dispc_go_busy(enum omap_channel channel) { int bit; @@ -505,8 +640,6 @@ void dispc_go(enum omap_channel channel) int bit; bool enable_bit, go_bit; - enable_clocks(1); - if (channel == OMAP_DSS_CHANNEL_LCD || channel == OMAP_DSS_CHANNEL_LCD2) bit = 0; /* LCDENABLE */ @@ -520,7 +653,7 @@ void dispc_go(enum omap_channel channel) enable_bit = REG_GET(DISPC_CONTROL, bit, bit) == 1; if (!enable_bit) - goto end; + return; if (channel == OMAP_DSS_CHANNEL_LCD || channel == OMAP_DSS_CHANNEL_LCD2) @@ -535,7 +668,7 @@ void dispc_go(enum omap_channel channel) if (go_bit) { DSSERR("GO bit not down for channel %d\n", channel); - goto end; + return; } DSSDBG("GO %s\n", channel == OMAP_DSS_CHANNEL_LCD ? "LCD" : @@ -545,8 +678,6 @@ void dispc_go(enum omap_channel channel) REG_FLD_MOD(DISPC_CONTROL2, 1, bit, bit); else REG_FLD_MOD(DISPC_CONTROL, 1, bit, bit); -end: - enable_clocks(0); } static void _dispc_write_firh_reg(enum omap_plane plane, int reg, u32 value) @@ -585,105 +716,227 @@ static void _dispc_write_firv2_reg(enum omap_plane plane, int reg, u32 value) dispc_write_reg(DISPC_OVL_FIR_COEF_V2(plane, reg), value); } -static void _dispc_set_scale_coef(enum omap_plane plane, int hscaleup, - int vscaleup, int five_taps, - enum omap_color_component color_comp) +static const struct dispc_hv_coef * +dispc_get_scaling_coef(u32 inc, bool five_taps) { - /* Coefficients for horizontal up-sampling */ - static const struct dispc_h_coef coef_hup[8] = { - { 0, 0, 128, 0, 0 }, - { -1, 13, 124, -8, 0 }, - { -2, 30, 112, -11, -1 }, - { -5, 51, 95, -11, -2 }, - { 0, -9, 73, 73, -9 }, - { -2, -11, 95, 51, -5 }, - { -1, -11, 112, 30, -2 }, - { 0, -8, 124, 13, -1 }, + static const struct dispc_hv_coef coef3_M8[8] = { + { 0, 0, 128, 0, 0 }, + { 0, 2, 123, 3, 0 }, + { 0, 5, 111, 12, 0 }, + { 0, 7, 89, 32, 0 }, + { 0, 64, 64, 0, 0 }, + { 0, 32, 89, 7, 0 }, + { 0, 12, 111, 5, 0 }, + { 0, 3, 123, 2, 0 }, }; - /* Coefficients for vertical up-sampling */ - static const struct dispc_v_coef coef_vup_3tap[8] = { - { 0, 0, 128, 0, 0 }, - { 0, 3, 123, 2, 0 }, - { 0, 12, 111, 5, 0 }, - { 0, 32, 89, 7, 0 }, - { 0, 0, 64, 64, 0 }, - { 0, 7, 89, 32, 0 }, - { 0, 5, 111, 12, 0 }, - { 0, 2, 123, 3, 0 }, + static const struct dispc_hv_coef coef3_M16[8] = { + { 0, 36, 56, 36, 0 }, + { 0, 31, 57, 40, 0 }, + { 0, 27, 56, 45, 0 }, + { 0, 23, 55, 50, 0 }, + { 0, 55, 55, 18, 0 }, + { 0, 50, 55, 23, 0 }, + { 0, 45, 56, 27, 0 }, + { 0, 40, 57, 31, 0 }, }; - static const struct dispc_v_coef coef_vup_5tap[8] = { - { 0, 0, 128, 0, 0 }, - { -1, 13, 124, -8, 0 }, - { -2, 30, 112, -11, -1 }, - { -5, 51, 95, -11, -2 }, - { 0, -9, 73, 73, -9 }, - { -2, -11, 95, 51, -5 }, - { -1, -11, 112, 30, -2 }, - { 0, -8, 124, 13, -1 }, + static const struct dispc_hv_coef coef_M8[8] = { + { 0, 0, 128, 0, 0 }, + { 0, -8, 124, 13, -1 }, + { -1, -11, 112, 30, -2 }, + { -2, -11, 95, 51, -5 }, + { -9, 73, 73, -9, 0 }, + { -5, 51, 95, -11, -2 }, + { -2, 30, 112, -11, -1 }, + { -1, 13, 124, -8, 0 }, }; - /* Coefficients for horizontal down-sampling */ - static const struct dispc_h_coef coef_hdown[8] = { - { 0, 36, 56, 36, 0 }, - { 4, 40, 55, 31, -2 }, - { 8, 44, 54, 27, -5 }, - { 12, 48, 53, 22, -7 }, - { -9, 17, 52, 51, 17 }, - { -7, 22, 53, 48, 12 }, - { -5, 27, 54, 44, 8 }, - { -2, 31, 55, 40, 4 }, + static const struct dispc_hv_coef coef_M9[8] = { + { 8, -8, 128, -8, 8 }, + { 14, -21, 126, 8, 1 }, + { 17, -27, 117, 30, -9 }, + { 17, -30, 103, 56, -18 }, + { -26, 83, 83, -26, 14 }, + { -18, 56, 103, -30, 17 }, + { -9, 30, 117, -27, 17 }, + { 1, 8, 126, -21, 14 }, }; - /* Coefficients for vertical down-sampling */ - static const struct dispc_v_coef coef_vdown_3tap[8] = { - { 0, 36, 56, 36, 0 }, - { 0, 40, 57, 31, 0 }, - { 0, 45, 56, 27, 0 }, - { 0, 50, 55, 23, 0 }, - { 0, 18, 55, 55, 0 }, - { 0, 23, 55, 50, 0 }, - { 0, 27, 56, 45, 0 }, - { 0, 31, 57, 40, 0 }, + static const struct dispc_hv_coef coef_M10[8] = { + { -2, 2, 128, 2, -2 }, + { 5, -12, 125, 20, -10 }, + { 11, -22, 116, 41, -18 }, + { 15, -27, 102, 62, -24 }, + { -28, 83, 83, -28, 18 }, + { -24, 62, 102, -27, 15 }, + { -18, 41, 116, -22, 11 }, + { -10, 20, 125, -12, 5 }, }; - static const struct dispc_v_coef coef_vdown_5tap[8] = { - { 0, 36, 56, 36, 0 }, - { 4, 40, 55, 31, -2 }, - { 8, 44, 54, 27, -5 }, - { 12, 48, 53, 22, -7 }, - { -9, 17, 52, 51, 17 }, - { -7, 22, 53, 48, 12 }, - { -5, 27, 54, 44, 8 }, - { -2, 31, 55, 40, 4 }, + static const struct dispc_hv_coef coef_M11[8] = { + { -12, 12, 128, 12, -12 }, + { -4, -3, 124, 30, -19 }, + { 3, -15, 115, 49, -24 }, + { 9, -22, 101, 67, -27 }, + { -26, 83, 83, -26, 14 }, + { -27, 67, 101, -22, 9 }, + { -24, 49, 115, -15, 3 }, + { -19, 30, 124, -3, -4 }, }; - const struct dispc_h_coef *h_coef; - const struct dispc_v_coef *v_coef; - int i; + static const struct dispc_hv_coef coef_M12[8] = { + { -19, 21, 124, 21, -19 }, + { -12, 6, 120, 38, -24 }, + { -6, -7, 112, 55, -26 }, + { 1, -16, 98, 70, -25 }, + { -21, 82, 82, -21, 6 }, + { -25, 70, 98, -16, 1 }, + { -26, 55, 112, -7, -6 }, + { -24, 38, 120, 6, -12 }, + }; - if (hscaleup) - h_coef = coef_hup; - else - h_coef = coef_hdown; + static const struct dispc_hv_coef coef_M13[8] = { + { -22, 27, 118, 27, -22 }, + { -18, 13, 115, 43, -25 }, + { -12, 0, 107, 58, -25 }, + { -6, -10, 95, 71, -22 }, + { -17, 81, 81, -17, 0 }, + { -22, 71, 95, -10, -6 }, + { -25, 58, 107, 0, -12 }, + { -25, 43, 115, 13, -18 }, + }; - if (vscaleup) - v_coef = five_taps ? coef_vup_5tap : coef_vup_3tap; - else - v_coef = five_taps ? coef_vdown_5tap : coef_vdown_3tap; + static const struct dispc_hv_coef coef_M14[8] = { + { -23, 32, 110, 32, -23 }, + { -20, 18, 108, 46, -24 }, + { -16, 6, 101, 59, -22 }, + { -11, -4, 91, 70, -18 }, + { -11, 78, 78, -11, -6 }, + { -18, 70, 91, -4, -11 }, + { -22, 59, 101, 6, -16 }, + { -24, 46, 108, 18, -20 }, + }; + + static const struct dispc_hv_coef coef_M16[8] = { + { -20, 37, 94, 37, -20 }, + { -21, 26, 93, 48, -18 }, + { -19, 15, 88, 58, -14 }, + { -17, 6, 82, 66, -9 }, + { -2, 73, 73, -2, -14 }, + { -9, 66, 82, 6, -17 }, + { -14, 58, 88, 15, -19 }, + { -18, 48, 93, 26, -21 }, + }; + + static const struct dispc_hv_coef coef_M19[8] = { + { -12, 38, 76, 38, -12 }, + { -14, 31, 72, 47, -8 }, + { -16, 22, 73, 53, -4 }, + { -16, 15, 69, 59, 1 }, + { 8, 64, 64, 8, -16 }, + { 1, 59, 69, 15, -16 }, + { -4, 53, 73, 22, -16 }, + { -9, 47, 72, 31, -13 }, + }; + + static const struct dispc_hv_coef coef_M22[8] = { + { -6, 37, 66, 37, -6 }, + { -8, 32, 61, 44, -1 }, + { -11, 25, 63, 48, 3 }, + { -13, 19, 61, 53, 8 }, + { 13, 58, 58, 13, -14 }, + { 8, 53, 61, 19, -13 }, + { 3, 48, 63, 25, -11 }, + { -2, 44, 61, 32, -7 }, + }; + + static const struct dispc_hv_coef coef_M26[8] = { + { 1, 36, 54, 36, 1 }, + { -2, 31, 55, 40, 4 }, + { -5, 27, 54, 44, 8 }, + { -8, 22, 53, 48, 13 }, + { 18, 51, 51, 18, -10 }, + { 13, 48, 53, 22, -8 }, + { 8, 44, 54, 27, -5 }, + { 4, 40, 55, 31, -2 }, + }; + + static const struct dispc_hv_coef coef_M32[8] = { + { 7, 34, 46, 34, 7 }, + { 4, 31, 46, 37, 10 }, + { 1, 27, 46, 39, 14 }, + { -1, 24, 46, 42, 17 }, + { 21, 45, 45, 21, -4 }, + { 17, 42, 46, 24, -1 }, + { 14, 39, 46, 28, 1 }, + { 10, 37, 46, 31, 4 }, + }; + + inc >>= 7; /* /= 128 */ + if (five_taps) { + if (inc > 26) + return coef_M32; + if (inc > 22) + return coef_M26; + if (inc > 19) + return coef_M22; + if (inc > 16) + return coef_M19; + if (inc > 14) + return coef_M16; + if (inc > 13) + return coef_M14; + if (inc > 12) + return coef_M13; + if (inc > 11) + return coef_M12; + if (inc > 10) + return coef_M11; + if (inc > 9) + return coef_M10; + if (inc > 8) + return coef_M9; + /* reduce blockiness when upscaling much */ + if (inc > 3) + return coef_M8; + if (inc > 2) + return coef_M11; + if (inc > 1) + return coef_M16; + return coef_M19; + } else { + if (inc > 14) + return coef3_M16; + /* reduce blockiness when upscaling much */ + if (inc > 3) + return coef3_M8; + return coef3_M16; + } +} + +static void _dispc_set_scale_coef(enum omap_plane plane, int hinc, + int vinc, bool five_taps, + enum omap_color_component color_comp) +{ + const struct dispc_hv_coef *h_coef; + const struct dispc_hv_coef *v_coef; + int i; + + h_coef = dispc_get_scaling_coef(hinc, true); + v_coef = dispc_get_scaling_coef(vinc, five_taps); for (i = 0; i < 8; i++) { u32 h, hv; - h = FLD_VAL(h_coef[i].hc0, 7, 0) - | FLD_VAL(h_coef[i].hc1, 15, 8) - | FLD_VAL(h_coef[i].hc2, 23, 16) - | FLD_VAL(h_coef[i].hc3, 31, 24); - hv = FLD_VAL(h_coef[i].hc4, 7, 0) - | FLD_VAL(v_coef[i].vc0, 15, 8) - | FLD_VAL(v_coef[i].vc1, 23, 16) - | FLD_VAL(v_coef[i].vc2, 31, 24); + h = FLD_VAL(h_coef[i].hc0_vc00, 7, 0) + | FLD_VAL(h_coef[i].hc1_vc0, 15, 8) + | FLD_VAL(h_coef[i].hc2_vc1, 23, 16) + | FLD_VAL(h_coef[i].hc3_vc2, 31, 24); + hv = FLD_VAL(h_coef[i].hc4_vc22, 7, 0) + | FLD_VAL(v_coef[i].hc1_vc0, 15, 8) + | FLD_VAL(v_coef[i].hc2_vc1, 23, 16) + | FLD_VAL(v_coef[i].hc3_vc2, 31, 24); if (color_comp == DISPC_COLOR_COMPONENT_RGB_Y) { _dispc_write_firh_reg(plane, i, h); @@ -692,14 +945,13 @@ static void _dispc_set_scale_coef(enum omap_plane plane, int hscaleup, _dispc_write_firh2_reg(plane, i, h); _dispc_write_firhv2_reg(plane, i, hv); } - } if (five_taps) { for (i = 0; i < 8; i++) { u32 v; - v = FLD_VAL(v_coef[i].vc00, 7, 0) - | FLD_VAL(v_coef[i].vc22, 15, 8); + v = FLD_VAL(v_coef[i].hc0_vc00, 7, 0) + | FLD_VAL(v_coef[i].hc4_vc22, 15, 8); if (color_comp == DISPC_COLOR_COMPONENT_RGB_Y) _dispc_write_firv_reg(plane, i, v); else @@ -708,49 +960,22 @@ static void _dispc_set_scale_coef(enum omap_plane plane, int hscaleup, } } -static void _dispc_setup_color_conv_coef(void) +void _dispc_setup_color_conv_coef(enum omap_plane plane, + const struct omap_dss_cconv_coefs *ct) { - const struct color_conv_coef { - int ry, rcr, rcb, gy, gcr, gcb, by, bcr, bcb; - int full_range; - } ctbl_bt601_5 = { - 298, 409, 0, 298, -208, -100, 298, 0, 517, 0, - }; - - const struct color_conv_coef *ct; + BUG_ON(plane < OMAP_DSS_VIDEO1 || plane > OMAP_DSS_VIDEO3); #define CVAL(x, y) (FLD_VAL(x, 26, 16) | FLD_VAL(y, 10, 0)) - ct = &ctbl_bt601_5; - - dispc_write_reg(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 0), - CVAL(ct->rcr, ct->ry)); - dispc_write_reg(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 1), - CVAL(ct->gy, ct->rcb)); - dispc_write_reg(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 2), - CVAL(ct->gcb, ct->gcr)); - dispc_write_reg(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 3), - CVAL(ct->bcr, ct->by)); - dispc_write_reg(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 4), - CVAL(0, ct->bcb)); - - dispc_write_reg(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 0), - CVAL(ct->rcr, ct->ry)); - dispc_write_reg(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 1), - CVAL(ct->gy, ct->rcb)); - dispc_write_reg(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 2), - CVAL(ct->gcb, ct->gcr)); - dispc_write_reg(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 3), - CVAL(ct->bcr, ct->by)); - dispc_write_reg(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 4), - CVAL(0, ct->bcb)); + dispc_write_reg(DISPC_OVL_CONV_COEF(plane, 0), CVAL(ct->rcr, ct->ry)); + dispc_write_reg(DISPC_OVL_CONV_COEF(plane, 1), CVAL(ct->gy, ct->rcb)); + dispc_write_reg(DISPC_OVL_CONV_COEF(plane, 2), CVAL(ct->gcb, ct->gcr)); + dispc_write_reg(DISPC_OVL_CONV_COEF(plane, 3), CVAL(ct->bcr, ct->by)); + dispc_write_reg(DISPC_OVL_CONV_COEF(plane, 4), CVAL(0, ct->bcb)); #undef CVAL - REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(OMAP_DSS_VIDEO1), - ct->full_range, 11, 11); - REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(OMAP_DSS_VIDEO2), - ct->full_range, 11, 11); + REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), ct->full_range, 11, 11); } @@ -825,8 +1050,12 @@ static void _dispc_setup_global_alpha(enum omap_plane plane, u8 global_alpha) if (plane == OMAP_DSS_GFX) REG_FLD_MOD(DISPC_GLOBAL_ALPHA, global_alpha, 7, 0); + else if (plane == OMAP_DSS_VIDEO1) + REG_FLD_MOD(DISPC_GLOBAL_ALPHA, global_alpha, 15, 8); else if (plane == OMAP_DSS_VIDEO2) REG_FLD_MOD(DISPC_GLOBAL_ALPHA, global_alpha, 23, 16); + else if (plane == OMAP_DSS_VIDEO3) + REG_FLD_MOD(DISPC_GLOBAL_ALPHA, global_alpha, 31, 24); } static void _dispc_set_pix_inc(enum omap_plane plane, s32 inc) @@ -847,11 +1076,11 @@ static void _dispc_set_color_mode(enum omap_plane plane, switch (color_mode) { case OMAP_DSS_COLOR_NV12: m = 0x0; break; - case OMAP_DSS_COLOR_RGB12U: + case OMAP_DSS_COLOR_RGBX16: m = 0x1; break; case OMAP_DSS_COLOR_RGBA16: m = 0x2; break; - case OMAP_DSS_COLOR_RGBX16: + case OMAP_DSS_COLOR_RGB12U: m = 0x4; break; case OMAP_DSS_COLOR_ARGB16: m = 0x5; break; @@ -901,8 +1130,10 @@ static void _dispc_set_color_mode(enum omap_plane plane, case OMAP_DSS_COLOR_RGB24P: m = 0x9; break; case OMAP_DSS_COLOR_YUV2: + case OMAP_DSS_COLOR_RGBX16: m = 0xa; break; case OMAP_DSS_COLOR_UYVY: + case OMAP_DSS_COLOR_RGBA16: m = 0xb; break; case OMAP_DSS_COLOR_ARGB32: m = 0xc; break; @@ -920,7 +1151,7 @@ static void _dispc_set_color_mode(enum omap_plane plane, REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), m, 4, 1); } -static void _dispc_set_channel_out(enum omap_plane plane, +void dispc_set_channel_out(enum omap_plane plane, enum omap_channel channel) { int shift; @@ -933,6 +1164,7 @@ static void _dispc_set_channel_out(enum omap_plane plane, break; case OMAP_DSS_VIDEO1: case OMAP_DSS_VIDEO2: + case OMAP_DSS_VIDEO3: shift = 16; break; default: @@ -973,14 +1205,13 @@ void dispc_set_burst_size(enum omap_plane plane, int shift; u32 val; - enable_clocks(1); - switch (plane) { case OMAP_DSS_GFX: shift = 6; break; case OMAP_DSS_VIDEO1: case OMAP_DSS_VIDEO2: + case OMAP_DSS_VIDEO3: shift = 14; break; default: @@ -991,8 +1222,6 @@ void dispc_set_burst_size(enum omap_plane plane, val = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane)); val = FLD_MOD(val, burst_size, shift+1, shift); dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), val); - - enable_clocks(0); } void dispc_enable_gamma_table(bool enable) @@ -1009,6 +1238,63 @@ void dispc_enable_gamma_table(bool enable) REG_FLD_MOD(DISPC_CONFIG, enable, 9, 9); } +void dispc_set_zorder(enum omap_plane plane, + enum omap_overlay_zorder zorder) +{ + u32 val; + + if (!dss_has_feature(FEAT_OVL_ZORDER)) + return; + val = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane)); + val = FLD_MOD(val, zorder, 27, 26); + dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), val); +} + +void dispc_enable_zorder(enum omap_plane plane, bool enable) +{ + u32 val; + + if (!dss_has_feature(FEAT_OVL_ZORDER)) + return; + val = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane)); + val = FLD_MOD(val, enable, 25, 25); + dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), val); +} + +void dispc_enable_cpr(enum omap_channel channel, bool enable) +{ + u16 reg; + + if (channel == OMAP_DSS_CHANNEL_LCD) + reg = DISPC_CONFIG; + else if (channel == OMAP_DSS_CHANNEL_LCD2) + reg = DISPC_CONFIG2; + else + return; + + REG_FLD_MOD(reg, enable, 15, 15); +} + +void dispc_set_cpr_coef(enum omap_channel channel, + struct omap_dss_cpr_coefs *coefs) +{ + u32 coef_r, coef_g, coef_b; + + if (channel != OMAP_DSS_CHANNEL_LCD && channel != OMAP_DSS_CHANNEL_LCD2) + return; + + coef_r = FLD_VAL(coefs->rr, 31, 22) | FLD_VAL(coefs->rg, 20, 11) | + FLD_VAL(coefs->rb, 9, 0); + coef_g = FLD_VAL(coefs->gr, 31, 22) | FLD_VAL(coefs->gg, 20, 11) | + FLD_VAL(coefs->gb, 9, 0); + coef_b = FLD_VAL(coefs->br, 31, 22) | FLD_VAL(coefs->bg, 20, 11) | + FLD_VAL(coefs->bb, 9, 0); + + dispc_write_reg(DISPC_CPR_COEF_R(channel), coef_r); + dispc_write_reg(DISPC_CPR_COEF_G(channel), coef_g); + dispc_write_reg(DISPC_CPR_COEF_B(channel), coef_b); +} + static void _dispc_set_vid_color_conv(enum omap_plane plane, bool enable) { u32 val; @@ -1029,9 +1315,7 @@ void dispc_enable_replication(enum omap_plane plane, bool enable) else bit = 10; - enable_clocks(1); REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable, bit, bit); - enable_clocks(0); } void dispc_set_lcd_size(enum omap_channel channel, u16 width, u16 height) @@ -1039,9 +1323,7 @@ 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_MGR(channel), val); - enable_clocks(0); } void dispc_set_digit_size(u16 width, u16 height) @@ -1049,9 +1331,7 @@ void dispc_set_digit_size(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_MGR(OMAP_DSS_CHANNEL_DIGIT), val); - enable_clocks(0); } static void dispc_read_plane_fifo_sizes(void) @@ -1060,8 +1340,6 @@ static void dispc_read_plane_fifo_sizes(void) int plane; u8 start, end; - enable_clocks(1); - dss_feat_get_reg_field(FEAT_REG_FIFOSIZE, &start, &end); for (plane = 0; plane < ARRAY_SIZE(dispc.fifo_size); ++plane) { @@ -1069,8 +1347,6 @@ static void dispc_read_plane_fifo_sizes(void) start, end); dispc.fifo_size[plane] = size; } - - enable_clocks(0); } u32 dispc_get_plane_fifo_size(enum omap_plane plane) @@ -1085,8 +1361,6 @@ void dispc_setup_plane_fifo(enum omap_plane plane, u32 low, u32 high) dss_feat_get_reg_field(FEAT_REG_FIFOHIGHTHRESHOLD, &hi_start, &hi_end); dss_feat_get_reg_field(FEAT_REG_FIFOLOWTHRESHOLD, &lo_start, &lo_end); - enable_clocks(1); - DSSDBG("fifo(%d) low/high old %u/%u, new %u/%u\n", plane, REG_GET(DISPC_OVL_FIFO_THRESHOLD(plane), @@ -1095,21 +1369,18 @@ void dispc_setup_plane_fifo(enum omap_plane plane, u32 low, u32 high) hi_start, hi_end), low, high); + /* preload to high threshold to avoid FIFO underflow */ + dispc_write_reg(DISPC_OVL_PRELOAD(plane), min(high, 0xfffu)); + dispc_write_reg(DISPC_OVL_FIFO_THRESHOLD(plane), FLD_VAL(high, hi_start, hi_end) | FLD_VAL(low, lo_start, lo_end)); - - enable_clocks(0); } void dispc_enable_fifomerge(bool enable) { - enable_clocks(1); - DSSDBG("FIFO merge %s\n", enable ? "enabled" : "disabled"); REG_FLD_MOD(DISPC_CONFIG, enable ? 1 : 0, 14, 14); - - enable_clocks(0); } static void _dispc_set_fir(enum omap_plane plane, @@ -1209,8 +1480,9 @@ static void _dispc_set_scaling_common(enum omap_plane plane, int accu0 = 0; int accu1 = 0; u32 l; + u16 y_adjust = color_mode == OMAP_DSS_COLOR_NV12 ? 2 : 0; - _dispc_set_scale_param(plane, orig_width, orig_height, + _dispc_set_scale_param(plane, orig_width, orig_height - y_adjust, out_width, out_height, five_taps, rotation, DISPC_COLOR_COMPONENT_RGB_Y); l = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane)); @@ -1262,6 +1534,7 @@ static void _dispc_set_scaling_uv(enum omap_plane plane, { int scale_x = out_width != orig_width; int scale_y = out_height != orig_height; + u16 y_adjust = 0; if (!dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) return; @@ -1278,6 +1551,7 @@ static void _dispc_set_scaling_uv(enum omap_plane plane, orig_height >>= 1; /* UV is subsampled by 2 horz.*/ orig_width >>= 1; + y_adjust = 1; break; case OMAP_DSS_COLOR_YUV2: case OMAP_DSS_COLOR_UYVY: @@ -1301,7 +1575,7 @@ static void _dispc_set_scaling_uv(enum omap_plane plane, if (out_height != orig_height) scale_y = true; - _dispc_set_scale_param(plane, orig_width, orig_height, + _dispc_set_scale_param(plane, orig_width, orig_height - y_adjust, out_width, out_height, five_taps, rotation, DISPC_COLOR_COMPONENT_UV); @@ -1341,7 +1615,8 @@ static void _dispc_set_scaling(enum omap_plane plane, } static void _dispc_set_rotation_attrs(enum omap_plane plane, u8 rotation, - bool mirroring, enum omap_color_mode color_mode) + bool mirroring, enum omap_color_mode color_mode, + enum omap_dss_rotation_type type) { bool row_repeat = false; int vidrot = 0; @@ -1391,6 +1666,16 @@ static void _dispc_set_rotation_attrs(enum omap_plane plane, u8 rotation, if (dss_has_feature(FEAT_ROWREPEATENABLE)) REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), row_repeat ? 1 : 0, 18, 18); + + if (color_mode == OMAP_DSS_COLOR_NV12) { + /* this will never happen for GFX */ + /* 1D NV12 buffer is always non-rotated or vert. mirrored */ + bool doublestride = (rotation == OMAP_DSS_ROT_0 || + rotation == OMAP_DSS_ROT_180) && + type == OMAP_DSS_ROT_TILER; + /* DOUBLESTRIDE */ + REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), doublestride, 22, 22); + } } static int color_mode_to_bpp(enum omap_color_mode color_mode) @@ -1439,6 +1724,28 @@ static s32 pixinc(int pixels, u8 ps) BUG(); } +static void calc_tiler_row_rotation(struct tiler_view_t *view, + u16 width, int bpp, int y_decim, + s32 *row_inc, unsigned *offset1, bool ilace) +{ + /* assume TB. We worry about swapping top/bottom outside of this call */ + + if (ilace) { + /* even and odd frames are interleaved */ + + /* offset1 is always at an odd line */ + *offset1 = view->v_inc * (y_decim | 1); + y_decim *= 2; + } + *row_inc = view->v_inc * y_decim + 1 - width * bpp; + + DSSDBG(" ps: %d/%d, width: %d/%d, offset1: %d," + " height: %d, row_inc:%d\n", view->bpp, bpp, + view->width, width, *offset1, view->height, *row_inc); + + return; +} + static void calc_vrfb_rotation_offset(u8 rotation, bool mirror, u16 screen_width, u16 width, u16 height, @@ -1529,7 +1836,7 @@ static void calc_dma_rotation_offset(u8 rotation, bool mirror, enum omap_color_mode color_mode, bool fieldmode, unsigned int field_offset, unsigned *offset0, unsigned *offset1, - s32 *row_inc, s32 *pix_inc) + s32 *row_inc, s32 *pix_inc, int x_decim, int y_decim) { u8 ps; u16 fbw, fbh; @@ -1542,6 +1849,15 @@ static void calc_dma_rotation_offset(u8 rotation, bool mirror, case OMAP_DSS_COLOR_CLUT8: BUG(); return; + case OMAP_DSS_COLOR_YUV2: + case OMAP_DSS_COLOR_UYVY: + if (cpu_is_omap44xx()) { + /* on OMAP4 YUYV is handled as 32-bit data */ + ps = 4; + screen_width /= 2; + break; + } + /* fall through */ default: ps = color_mode_to_bpp(color_mode) / 8; break; @@ -1571,10 +1887,10 @@ static void calc_dma_rotation_offset(u8 rotation, bool mirror, *offset0 = *offset1 + field_offset * screen_width * ps; else *offset0 = *offset1; - *row_inc = pixinc(1 + (screen_width - fbw) + + *row_inc = pixinc(1 + (y_decim * screen_width - fbw * x_decim) + (fieldmode ? screen_width : 0), ps); - *pix_inc = pixinc(1, ps); + *pix_inc = pixinc(x_decim, ps); break; case OMAP_DSS_ROT_90: *offset1 = screen_width * (fbh - 1) * ps; @@ -1671,6 +1987,18 @@ static unsigned long calc_fclk_five_taps(enum omap_channel channel, u16 width, /* FIXME venc pclk? */ u64 tmp, pclk = dispc_pclk_rate(channel); + if (cpu_is_omap44xx()) { + /* do conservative TRM value on OMAP4 ES1.0 */ + if (omap_rev() == OMAP4430_REV_ES1_0) + return pclk * DIV_ROUND_UP(width, out_width) * + DIV_ROUND_UP(height, out_height); + + /* since 4430 ES2.0, fclk requirement only depends on width */ + pclk *= max(width, out_width); + do_div(pclk, out_width); + return pclk; + } + if (height > out_height) { /* FIXME get real display PPL */ unsigned int ppl = 800; @@ -1706,6 +2034,11 @@ static unsigned long calc_fclk(enum omap_channel channel, u16 width, { unsigned int hf, vf; + /* on OMAP4 three-tap and five-tap clock requirements are the same */ + if (cpu_is_omap44xx()) + return calc_fclk_five_taps(channel, width, height, out_width, + out_height, 0); + /* * FIXME how to determine the 'A' factor * for the no downscaling case ? @@ -1729,27 +2062,188 @@ static unsigned long calc_fclk(enum omap_channel channel, u16 width, return dispc_pclk_rate(channel) * vf * hf; } -void dispc_set_channel_out(enum omap_plane plane, enum omap_channel channel_out) +int dispc_scaling_decision(u16 width, u16 height, + u16 out_width, u16 out_height, + enum omap_plane plane, + enum omap_color_mode color_mode, + enum omap_channel channel, u8 rotation, + enum omap_dss_rotation_type type, + u16 min_x_decim, u16 max_x_decim, + u16 min_y_decim, u16 max_y_decim, + u16 *x_decim, u16 *y_decim, bool *five_taps) { - enable_clocks(1); - _dispc_set_channel_out(plane, channel_out); - enable_clocks(0); + int maxdownscale = cpu_is_omap24xx() ? 2 : 4; + int bpp = color_mode_to_bpp(color_mode); + + /* + * For now only whole byte formats on OMAP4 can be predecimated. + * Later SDMA decimation support may be added + */ + bool can_decimate_x = cpu_is_omap44xx() && !(bpp & 7); + bool can_decimate_y = can_decimate_x; + + bool can_scale = plane != OMAP_DSS_GFX; + + u16 in_width, in_height; + unsigned long fclk = 0, fclk5 = 0; + int min_factor, max_factor; /* decimation search limits */ + int x, y; /* decimation search variables */ + unsigned long fclk_max = dispc_fclk_rate(); + u16 y_decim_limit = type == OMAP_DSS_ROT_TILER ? 2 : 16; + + /* No decimation for bitmap formats */ + if (color_mode == OMAP_DSS_COLOR_CLUT1 || + color_mode == OMAP_DSS_COLOR_CLUT2 || + color_mode == OMAP_DSS_COLOR_CLUT4 || + color_mode == OMAP_DSS_COLOR_CLUT8) { + *x_decim = 1; + *y_decim = 1; + *five_taps = false; + return 0; + } + + /* restrict search region based on whether we can decimate */ + if (!can_decimate_x) { + if (min_x_decim > 1) + return -EINVAL; + min_x_decim = max_x_decim = 1; + } else { + if (max_x_decim > 16) + max_x_decim = 16; + } + + if (!can_decimate_y) { + if (min_y_decim > 1) + return -EINVAL; + min_y_decim = max_y_decim = 1; + } else { + if (max_y_decim > y_decim_limit) + max_y_decim = y_decim_limit; + } + + /* + * Find best supported quality. In the search algorithm, we make use + * of the fact, that increased decimation in either direction will have + * lower quality. However, we do not differentiate horizontal and + * vertical decimation even though they may affect quality differently + * given the exact geometry involved. + * + * Also, since the clock calculations are abstracted, we cannot make + * assumptions on how decimation affects the clock rates in our search. + * + * We search the whole search region in increasing layers from + * min_factor to max_factor. In each layer we search in increasing + * factors alternating between x and y axis: + * + * x: 1 2 3 + * y: + * 1 1st | 3rd | 6th | + * ----+ | | + * 2 2nd 4th | 8th | + * ------------+ | + * 3 5th 7th 9th | + * --------------------+ + */ + min_factor = min(min_x_decim, min_y_decim); + max_factor = max(max_x_decim, max_y_decim); + x = min_x_decim; + y = min_y_decim; + while (1) { + if (x < min_x_decim || x > max_x_decim || + y < min_y_decim || y > max_y_decim) + goto loop; + + in_width = DIV_ROUND_UP(width, x); + in_height = DIV_ROUND_UP(height, y); + + if (in_width == out_width && in_height == out_height) + break; + + if (!can_scale) + goto loop; + + if (out_width * maxdownscale < in_width || + out_height * maxdownscale < in_height) + goto loop; + + /* Use 5-tap filter unless must use 3-tap */ + if (!cpu_is_omap44xx()) + *five_taps = in_width <= 1024; + else if (omap_rev() == OMAP4430_REV_ES1_0) + *five_taps = in_width <= 1280; + else + *five_taps = true; + + /* + * Predecimation on OMAP4 still fetches the whole lines + * :TODO: How does it affect the required clock speed? + */ + fclk = calc_fclk(channel, in_width, in_height, + out_width, out_height); + fclk5 = *five_taps ? + calc_fclk_five_taps(channel, in_width, in_height, + out_width, out_height, color_mode) : 0; + + DSSDBG("%d*%d,%d*%d->%d,%d requires %lu(3T), %lu(5T) Hz\n", + in_width, x, in_height, y, out_width, out_height, + fclk, fclk5); + + /* for now we always use 5-tap unless 3-tap is required */ + if (*five_taps) + fclk = fclk5; + + /* OMAP2/3 has a scaler size limitation */ + if (!cpu_is_omap44xx() && in_width > (1024 << !*five_taps)) + goto loop; + + DSSDBG("required fclk rate = %lu Hz\n", fclk); + DSSDBG("current fclk rate = %lu Hz\n", fclk_max); + + if (fclk > fclk_max) + goto loop; + break; + +loop: + /* err if exhausted search region */ + if (x == max_x_decim && y == max_y_decim) { + DSSERR("failed to set up scaling %u*%u to %u*%u, " + "required fclk rate = %lu Hz, " + "current = %lu Hz\n", + width, height, out_width, out_height, + fclk, fclk_max); + return -EINVAL; + } + + /* get to next factor */ + if (x == y) { + x = min_factor; + y++; + } else { + swap(x, y); + if (x < y) + x++; + } + } + + *x_decim = x; + *y_decim = y; + return 0; } -static int _dispc_setup_plane(enum omap_plane plane, +int dispc_setup_plane(enum omap_plane plane, u32 paddr, u16 screen_width, u16 pos_x, u16 pos_y, u16 width, u16 height, u16 out_width, u16 out_height, enum omap_color_mode color_mode, bool ilace, + int x_decim, int y_decim, bool five_taps, enum omap_dss_rotation_type rotation_type, - u8 rotation, int mirror, + u8 rotation, bool mirror, u8 global_alpha, u8 pre_mult_alpha, enum omap_channel channel, u32 puv_addr) { - const int maxdownscale = cpu_is_omap34xx() ? 4 : 2; - bool five_taps = 0; + const int maxdownscale = cpu_is_omap24xx() ? 2 : 4; bool fieldmode = 0; int cconv = 0; unsigned offset0, offset1; @@ -1757,6 +2251,18 @@ static int _dispc_setup_plane(enum omap_plane plane, s32 pix_inc; u16 frame_height = height; unsigned int field_offset = 0; + int pixpg = (color_mode & + (OMAP_DSS_COLOR_YUV2 | OMAP_DSS_COLOR_UYVY)) ? 2 : 1; + unsigned long tiler_width, tiler_height; + u32 fifo_high, fifo_low; + + DSSDBG("dispc_setup_plane %d, pa %x, sw %d, %d,%d, %d/%dx%d/%d -> " + "%dx%d, ilace %d, cmode %x, rot %d, mir %d chan %d %dtap\n", + plane, paddr, screen_width, pos_x, pos_y, + width, x_decim, height, y_decim, + out_width, out_height, + ilace, color_mode, + rotation, mirror, channel, five_taps ? 5 : 3); if (paddr == 0) return -EINVAL; @@ -1778,59 +2284,41 @@ static int _dispc_setup_plane(enum omap_plane plane, if (!dss_feat_color_mode_supported(plane, color_mode)) return -EINVAL; + /* predecimate */ + + /* adjust for group-of-pixels*/ + if (rotation & 1) + height /= pixpg; + else + width /= pixpg; + + /* remember tiler block's size as we are reconstructing it */ + tiler_width = width; + tiler_height = height; + + width = DIV_ROUND_UP(width, x_decim); + height = DIV_ROUND_UP(height, y_decim); + + /* NV12 width has to be even (height apparently does not) */ + if (color_mode == OMAP_DSS_COLOR_NV12) + width &= ~1; + if (plane == OMAP_DSS_GFX) { if (width != out_width || height != out_height) return -EINVAL; } else { /* video plane */ - unsigned long fclk = 0; - - if (out_width < width / maxdownscale || - out_width > width * 8) + if (out_width < width / maxdownscale) return -EINVAL; - if (out_height < height / maxdownscale || - out_height > height * 8) + if (out_height < height / maxdownscale) return -EINVAL; if (color_mode == OMAP_DSS_COLOR_YUV2 || color_mode == OMAP_DSS_COLOR_UYVY || color_mode == OMAP_DSS_COLOR_NV12) cconv = 1; - - /* Must use 5-tap filter? */ - five_taps = height > out_height * 2; - - if (!five_taps) { - 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 && - fclk > dispc_fclk_rate()) - five_taps = true; - } - - if (width > (2048 >> five_taps)) { - DSSERR("failed to set up scaling, fclk too low\n"); - return -EINVAL; - } - - if (five_taps) - fclk = calc_fclk_five_taps(channel, width, height, - out_width, out_height, color_mode); - - DSSDBG("required fclk rate = %lu Hz\n", fclk); - DSSDBG("current fclk rate = %lu Hz\n", dispc_fclk_rate()); - - if (!fclk || fclk > dispc_fclk_rate()) { - DSSERR("failed to set up scaling, " - "required fclk rate = %lu Hz, " - "current fclk rate = %lu Hz\n", - fclk, dispc_fclk_rate()); - return -EINVAL; - } } if (ilace && !fieldmode) { @@ -1851,17 +2339,69 @@ static int _dispc_setup_plane(enum omap_plane plane, if (fieldmode) field_offset = 1; - if (rotation_type == OMAP_DSS_ROT_DMA) + /* default values */ + row_inc = pix_inc = 0x1; + offset0 = offset1 = 0x0; + + /* + * :HACK: we piggy back on UV separate feature for TILER to avoid + * having to keep rebase our FEAT_ enum until they add TILER. + */ + if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) { + /* set BURSTTYPE */ + bool use_tiler = rotation_type == OMAP_DSS_ROT_TILER; + REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), use_tiler, 29, 29); + } + + if (rotation_type == OMAP_DSS_ROT_TILER) { + struct tiler_view_t view = {0}; + int bpp = color_mode_to_bpp(color_mode) / 8; + /* tiler needs 0-degree width & height */ + if (rotation & 1) + swap(tiler_width, tiler_height); + + if (color_mode == OMAP_DSS_COLOR_YUV2 || + color_mode == OMAP_DSS_COLOR_UYVY) + tiler_width /= 2; + + tilview_create(&view, paddr, tiler_width, tiler_height); + tilview_rotate(&view, rotation * 90); + tilview_flip(&view, mirror, false); + paddr = view.tsptr; + + /* we cannot do TB field interlaced in rotated view */ + pix_inc = 1 + (x_decim - 1) * bpp * pixpg; + calc_tiler_row_rotation(&view, width * x_decim, bpp * pixpg, + y_decim, &row_inc, &offset1, ilace); + + DSSDBG("w, h = %ld %ld\n", tiler_width, tiler_height); + + if (puv_addr) { + tilview_create(&view, puv_addr, tiler_width / 2, + tiler_height / 2); + tilview_rotate(&view, rotation * 90); + tilview_flip(&view, mirror, false); + puv_addr = view.tsptr; + } + + } else if (rotation_type == OMAP_DSS_ROT_DMA) { calc_dma_rotation_offset(rotation, mirror, screen_width, width, frame_height, color_mode, fieldmode, field_offset, - &offset0, &offset1, &row_inc, &pix_inc); - else + &offset0, &offset1, &row_inc, &pix_inc, + x_decim, y_decim); + } else { calc_vrfb_rotation_offset(rotation, mirror, screen_width, width, frame_height, color_mode, fieldmode, field_offset, &offset0, &offset1, &row_inc, &pix_inc); + } + /* adjust back to pixels */ + if (rotation & 1) + height *= pixpg; + else + width *= pixpg; DSSDBG("offset0 %u, offset1 %u, row_inc %d, pix_inc %d\n", offset0, offset1, row_inc, pix_inc); @@ -1879,8 +2419,8 @@ static int _dispc_setup_plane(enum omap_plane plane, _dispc_set_row_inc(plane, row_inc); _dispc_set_pix_inc(plane, pix_inc); - DSSDBG("%d,%d %dx%d -> %dx%d\n", pos_x, pos_y, width, height, - out_width, out_height); + DSSDBG("%d,%d %d*%dx%d*%d -> %dx%d\n", pos_x, pos_y, width, x_decim, + height, y_decim, out_width, out_height); _dispc_set_plane_pos(plane, pos_x, pos_y); @@ -1895,17 +2435,30 @@ static int _dispc_setup_plane(enum omap_plane plane, _dispc_set_vid_color_conv(plane, cconv); } - _dispc_set_rotation_attrs(plane, rotation, mirror, color_mode); + _dispc_set_rotation_attrs(plane, rotation, mirror, color_mode, + rotation_type); _dispc_set_pre_mult_alpha(plane, pre_mult_alpha); _dispc_setup_global_alpha(plane, global_alpha); + if (cpu_is_omap44xx()) { + fifo_low = dispc_calculate_threshold(plane, paddr + offset0, + puv_addr + offset0, width, height, + row_inc, pix_inc); + fifo_high = dispc_get_plane_fifo_size(plane) - 1; + dispc_setup_plane_fifo(plane, fifo_low, fifo_high); + } + return 0; } -static void _dispc_enable_plane(enum omap_plane plane, bool enable) +int dispc_enable_plane(enum omap_plane plane, bool enable) { + DSSDBG("dispc_enable_plane %d, %d\n", plane, enable); + REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable ? 1 : 0, 0, 0); + + return 0; } static void dispc_disable_isr(void *data, u32 mask) @@ -1922,6 +2475,17 @@ static void _enable_lcd_out(enum omap_channel channel, bool enable) REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 0, 0); } +void omap_dispc_set_irq_type(int channel, enum omap_dispc_irq_type type) +{ + if (type == OMAP_DISPC_IRQ_TYPE_VSYNC) { + dispc.channel_irq[channel] = channel == OMAP_DSS_CHANNEL_LCD2 ? + DISPC_IRQ_VSYNC2 : DISPC_IRQ_VSYNC; + } else { + dispc.channel_irq[channel] = channel == OMAP_DSS_CHANNEL_LCD2 ? + DISPC_IRQ_FRAMEDONE2 : DISPC_IRQ_FRAMEDONE; + } +} + static void dispc_enable_lcd_out(enum omap_channel channel, bool enable) { struct completion frame_done_completion; @@ -1929,8 +2493,6 @@ static void dispc_enable_lcd_out(enum omap_channel channel, bool enable) 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 */ @@ -1938,8 +2500,7 @@ static void dispc_enable_lcd_out(enum omap_channel channel, bool enable) REG_GET(DISPC_CONTROL2, 0, 0) : REG_GET(DISPC_CONTROL, 0, 0); - irq = channel == OMAP_DSS_CHANNEL_LCD2 ? DISPC_IRQ_FRAMEDONE2 : - DISPC_IRQ_FRAMEDONE; + irq = dispc.channel_irq[channel]; if (!enable && is_on) { init_completion(&frame_done_completion); @@ -1964,8 +2525,6 @@ static void dispc_enable_lcd_out(enum omap_channel channel, bool enable) if (r) DSSERR("failed to unregister FRAMEDONE isr\n"); } - - enable_clocks(0); } static void _enable_digit_out(bool enable) @@ -1973,17 +2532,13 @@ static void _enable_digit_out(bool enable) REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 1, 1); } -static void dispc_enable_digit_out(bool enable) +static void dispc_enable_digit_out(enum omap_display_type type, bool enable) { struct completion frame_done_completion; int r; - enable_clocks(1); - - if (REG_GET(DISPC_CONTROL, 1, 1) == enable) { - enable_clocks(0); + if (REG_GET(DISPC_CONTROL, 1, 1) == enable) return; - } if (enable) { unsigned long flags; @@ -2002,7 +2557,8 @@ static void dispc_enable_digit_out(bool enable) init_completion(&frame_done_completion); r = omap_dispc_register_isr(dispc_disable_isr, &frame_done_completion, - DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD); + DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD + | DISPC_IRQ_FRAMEDONETV); if (r) DSSERR("failed to register EVSYNC isr\n"); @@ -2015,13 +2571,17 @@ static void dispc_enable_digit_out(bool enable) msecs_to_jiffies(100))) DSSERR("timeout waiting for EVSYNC\n"); - if (!wait_for_completion_timeout(&frame_done_completion, - msecs_to_jiffies(100))) - DSSERR("timeout waiting for EVSYNC\n"); + /* Don't wait for the odd field in the case of HDMI */ + if (type != OMAP_DISPLAY_TYPE_HDMI) { + if (!wait_for_completion_timeout(&frame_done_completion, + msecs_to_jiffies(100))) + DSSERR("timeout waiting for EVSYNC\n"); + } r = omap_dispc_unregister_isr(dispc_disable_isr, &frame_done_completion, - DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD); + DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD + | DISPC_IRQ_FRAMEDONETV); if (r) DSSERR("failed to unregister EVSYNC isr\n"); @@ -2031,12 +2591,12 @@ static void dispc_enable_digit_out(bool enable) dispc.irq_error_mask = DISPC_IRQ_MASK_ERROR; if (dss_has_feature(FEAT_MGR_LCD2)) dispc.irq_error_mask |= DISPC_IRQ_SYNC_LOST2; + if (dss_has_feature(FEAT_OVL_VID3)) + dispc.irq_error_mask |= DISPC_IRQ_VID3_FIFO_UNDERFLOW; dispc_write_reg(DISPC_IRQSTATUS, DISPC_IRQ_SYNC_LOST_DIGIT); _omap_dispc_set_irqs(); spin_unlock_irqrestore(&dispc.irq_lock, flags); } - - enable_clocks(0); } bool dispc_is_channel_enabled(enum omap_channel channel) @@ -2051,13 +2611,14 @@ bool dispc_is_channel_enabled(enum omap_channel channel) BUG(); } -void dispc_enable_channel(enum omap_channel channel, bool enable) +void dispc_enable_channel(enum omap_channel channel, + enum omap_display_type type, bool 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); + dispc_enable_digit_out(type, enable); else BUG(); } @@ -2067,9 +2628,7 @@ 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); } void dispc_lcd_enable_signal(bool enable) @@ -2077,9 +2636,7 @@ 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); } void dispc_pck_free_enable(bool enable) @@ -2087,19 +2644,15 @@ 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(enum omap_channel channel, bool enable) { - enable_clocks(1); 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); } @@ -2122,27 +2675,21 @@ void dispc_set_lcd_display_type(enum omap_channel channel, return; } - enable_clocks(1); 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); } void dispc_set_loadmode(enum omap_dss_load_mode mode) { - enable_clocks(1); REG_FLD_MOD(DISPC_CONFIG, mode, 2, 1); - enable_clocks(0); } void dispc_set_default_color(enum omap_channel channel, u32 color) { - enable_clocks(1); dispc_write_reg(DISPC_DEFAULT_COLOR(channel), color); - enable_clocks(0); } u32 dispc_get_default_color(enum omap_channel channel) @@ -2153,9 +2700,7 @@ u32 dispc_get_default_color(enum omap_channel channel) channel != OMAP_DSS_CHANNEL_LCD && channel != OMAP_DSS_CHANNEL_LCD2); - enable_clocks(1); l = dispc_read_reg(DISPC_DEFAULT_COLOR(channel)); - enable_clocks(0); return l; } @@ -2164,7 +2709,6 @@ void dispc_set_trans_key(enum omap_channel ch, enum omap_dss_trans_key_type type, u32 trans_key) { - enable_clocks(1); if (ch == OMAP_DSS_CHANNEL_LCD) REG_FLD_MOD(DISPC_CONFIG, type, 11, 11); else if (ch == OMAP_DSS_CHANNEL_DIGIT) @@ -2173,14 +2717,12 @@ void dispc_set_trans_key(enum omap_channel ch, REG_FLD_MOD(DISPC_CONFIG2, type, 11, 11); dispc_write_reg(DISPC_TRANS_COLOR(ch), trans_key); - enable_clocks(0); } void dispc_get_trans_key(enum omap_channel ch, enum omap_dss_trans_key_type *type, u32 *trans_key) { - enable_clocks(1); if (type) { if (ch == OMAP_DSS_CHANNEL_LCD) *type = REG_GET(DISPC_CONFIG, 11, 11); @@ -2194,33 +2736,27 @@ void dispc_get_trans_key(enum omap_channel ch, if (trans_key) *trans_key = dispc_read_reg(DISPC_TRANS_COLOR(ch)); - enable_clocks(0); } 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 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) { if (!dss_has_feature(FEAT_GLOBAL_ALPHA)) return; - enable_clocks(1); + /* :NOTE: compatibility mode is not supported on LCD2 */ if (ch == OMAP_DSS_CHANNEL_LCD) REG_FLD_MOD(DISPC_CONFIG, enable, 18, 18); 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) { @@ -2229,16 +2765,14 @@ bool dispc_alpha_blending_enabled(enum omap_channel ch) if (!dss_has_feature(FEAT_GLOBAL_ALPHA)) return false; - enable_clocks(1); 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, 19, 19); else if (ch == OMAP_DSS_CHANNEL_LCD2) - enabled = REG_GET(DISPC_CONFIG2, 18, 18); + enabled = false; else BUG(); - enable_clocks(0); return enabled; } @@ -2248,7 +2782,6 @@ bool dispc_trans_key_enabled(enum omap_channel ch) { bool enabled; - enable_clocks(1); if (ch == OMAP_DSS_CHANNEL_LCD) enabled = REG_GET(DISPC_CONFIG, 10, 10); else if (ch == OMAP_DSS_CHANNEL_DIGIT) @@ -2257,7 +2790,6 @@ bool dispc_trans_key_enabled(enum omap_channel ch) enabled = REG_GET(DISPC_CONFIG2, 10, 10); else BUG(); - enable_clocks(0); return enabled; } @@ -2285,12 +2817,10 @@ void dispc_set_tft_data_lines(enum omap_channel channel, u8 data_lines) return; } - enable_clocks(1); 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_channel channel, @@ -2322,8 +2852,6 @@ void dispc_set_parallel_interface_mode(enum omap_channel channel, return; } - enable_clocks(1); - if (channel == OMAP_DSS_CHANNEL_LCD2) { l = dispc_read_reg(DISPC_CONTROL2); l = FLD_MOD(l, stallmode, 11, 11); @@ -2335,8 +2863,6 @@ void dispc_set_parallel_interface_mode(enum omap_channel channel, l = FLD_MOD(l, gpout1, 16, 16); dispc_write_reg(DISPC_CONTROL, l); } - - enable_clocks(0); } static bool _dispc_lcd_timings_ok(int hsw, int hfp, int hbp, @@ -2389,10 +2915,8 @@ static void _dispc_set_lcd_timings(enum omap_channel channel, int hsw, FLD_VAL(vbp, 31, 20); } - enable_clocks(1); 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? */ @@ -2435,10 +2959,8 @@ static void dispc_set_lcd_divisor(enum omap_channel channel, u16 lck_div, BUG_ON(lck_div < 1); BUG_ON(pck_div < 2); - enable_clocks(1); dispc_write_reg(DISPC_DIVISORo(channel), FLD_VAL(lck_div, 23, 16) | FLD_VAL(pck_div, 7, 0)); - enable_clocks(0); } static void dispc_get_lcd_divisor(enum omap_channel channel, int *lck_div, @@ -2457,7 +2979,7 @@ unsigned long dispc_fclk_rate(void) switch (dss_get_dispc_clk_source()) { case OMAP_DSS_CLK_SRC_FCK: - r = dss_clk_get_rate(DSS_CLK_FCK); + r = clk_get_rate(dispc.dss_clk); break; case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC: dsidev = dsi_get_dsidev_from_id(0); @@ -2487,7 +3009,7 @@ unsigned long dispc_lclk_rate(enum omap_channel channel) switch (dss_get_lcd_clk_source(channel)) { case OMAP_DSS_CLK_SRC_FCK: - r = dss_clk_get_rate(DSS_CLK_FCK); + r = clk_get_rate(dispc.dss_clk); break; case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC: dsidev = dsi_get_dsidev_from_id(0); @@ -2510,13 +3032,23 @@ unsigned long dispc_pclk_rate(enum omap_channel channel) unsigned long r; u32 l; - l = dispc_read_reg(DISPC_DIVISORo(channel)); + if (channel == OMAP_DSS_CHANNEL_LCD || + channel == OMAP_DSS_CHANNEL_LCD2) { + l = dispc_read_reg(DISPC_DIVISORo(channel)); + + pcd = FLD_GET(l, 7, 0); - pcd = FLD_GET(l, 7, 0); + r = dispc_lclk_rate(channel); - r = dispc_lclk_rate(channel); + return r / pcd; + } else { + struct omap_overlay_manager *mgr; + mgr = omap_dss_get_overlay_manager(channel); + if (!mgr || !mgr->device) + return 0; - return r / pcd; + return mgr->device->panel.timings.pixel_clock * 1000; + } } void dispc_dump_clocks(struct seq_file *s) @@ -2526,7 +3058,8 @@ void dispc_dump_clocks(struct seq_file *s) enum omap_dss_clk_source dispc_clk_src = dss_get_dispc_clk_source(); enum omap_dss_clk_source lcd_clk_src; - enable_clocks(1); + if (dispc_runtime_get()) + return; seq_printf(s, "- DISPC -\n"); @@ -2574,7 +3107,8 @@ void dispc_dump_clocks(struct seq_file *s) seq_printf(s, "pck\t\t%-16lupck div\t%u\n", dispc_pclk_rate(OMAP_DSS_CHANNEL_LCD2), pcd); } - enable_clocks(0); + + dispc_runtime_put(); } #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS @@ -2612,6 +3146,10 @@ void dispc_dump_irqs(struct seq_file *s) PIS(VID1_END_WIN); PIS(VID2_FIFO_UNDERFLOW); PIS(VID2_END_WIN); + if (dss_has_feature(FEAT_OVL_VID3)) { + PIS(VID3_FIFO_UNDERFLOW); + PIS(VID3_END_WIN); + } PIS(SYNC_LOST); PIS(SYNC_LOST_DIGIT); PIS(WAKEUP); @@ -2627,9 +3165,11 @@ void dispc_dump_irqs(struct seq_file *s) void dispc_dump_regs(struct seq_file *s) { + int i, o; #define DUMPREG(r) seq_printf(s, "%-50s %08x\n", #r, dispc_read_reg(r)) - dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK); + if (dispc_runtime_get()) + return; DUMPREG(DISPC_REVISION); DUMPREG(DISPC_SYSCONFIG); @@ -2649,7 +3189,8 @@ void dispc_dump_regs(struct seq_file *s) DUMPREG(DISPC_TIMING_V(OMAP_DSS_CHANNEL_LCD)); DUMPREG(DISPC_POL_FREQ(OMAP_DSS_CHANNEL_LCD)); DUMPREG(DISPC_DIVISORo(OMAP_DSS_CHANNEL_LCD)); - DUMPREG(DISPC_GLOBAL_ALPHA); + if (dss_has_feature(FEAT_GLOBAL_ALPHA)) + DUMPREG(DISPC_GLOBAL_ALPHA); DUMPREG(DISPC_SIZE_MGR(OMAP_DSS_CHANNEL_DIGIT)); DUMPREG(DISPC_SIZE_MGR(OMAP_DSS_CHANNEL_LCD)); if (dss_has_feature(FEAT_MGR_LCD2)) { @@ -2680,188 +3221,82 @@ void dispc_dump_regs(struct seq_file *s) DUMPREG(DISPC_DATA_CYCLE2(OMAP_DSS_CHANNEL_LCD)); DUMPREG(DISPC_DATA_CYCLE3(OMAP_DSS_CHANNEL_LCD)); - DUMPREG(DISPC_CPR_COEF_R(OMAP_DSS_CHANNEL_LCD)); - DUMPREG(DISPC_CPR_COEF_G(OMAP_DSS_CHANNEL_LCD)); - DUMPREG(DISPC_CPR_COEF_B(OMAP_DSS_CHANNEL_LCD)); + if (dss_has_feature(FEAT_CPR)) { + DUMPREG(DISPC_CPR_COEF_R(OMAP_DSS_CHANNEL_LCD)); + DUMPREG(DISPC_CPR_COEF_G(OMAP_DSS_CHANNEL_LCD)); + DUMPREG(DISPC_CPR_COEF_B(OMAP_DSS_CHANNEL_LCD)); + } if (dss_has_feature(FEAT_MGR_LCD2)) { DUMPREG(DISPC_DATA_CYCLE1(OMAP_DSS_CHANNEL_LCD2)); DUMPREG(DISPC_DATA_CYCLE2(OMAP_DSS_CHANNEL_LCD2)); DUMPREG(DISPC_DATA_CYCLE3(OMAP_DSS_CHANNEL_LCD2)); - DUMPREG(DISPC_CPR_COEF_R(OMAP_DSS_CHANNEL_LCD2)); - DUMPREG(DISPC_CPR_COEF_G(OMAP_DSS_CHANNEL_LCD2)); - DUMPREG(DISPC_CPR_COEF_B(OMAP_DSS_CHANNEL_LCD2)); - } - - DUMPREG(DISPC_OVL_PRELOAD(OMAP_DSS_GFX)); - - DUMPREG(DISPC_OVL_BA0(OMAP_DSS_VIDEO1)); - DUMPREG(DISPC_OVL_BA1(OMAP_DSS_VIDEO1)); - DUMPREG(DISPC_OVL_POSITION(OMAP_DSS_VIDEO1)); - DUMPREG(DISPC_OVL_SIZE(OMAP_DSS_VIDEO1)); - DUMPREG(DISPC_OVL_ATTRIBUTES(OMAP_DSS_VIDEO1)); - DUMPREG(DISPC_OVL_FIFO_THRESHOLD(OMAP_DSS_VIDEO1)); - DUMPREG(DISPC_OVL_FIFO_SIZE_STATUS(OMAP_DSS_VIDEO1)); - DUMPREG(DISPC_OVL_ROW_INC(OMAP_DSS_VIDEO1)); - DUMPREG(DISPC_OVL_PIXEL_INC(OMAP_DSS_VIDEO1)); - DUMPREG(DISPC_OVL_FIR(OMAP_DSS_VIDEO1)); - DUMPREG(DISPC_OVL_PICTURE_SIZE(OMAP_DSS_VIDEO1)); - DUMPREG(DISPC_OVL_ACCU0(OMAP_DSS_VIDEO1)); - DUMPREG(DISPC_OVL_ACCU1(OMAP_DSS_VIDEO1)); - - DUMPREG(DISPC_OVL_BA0(OMAP_DSS_VIDEO2)); - DUMPREG(DISPC_OVL_BA1(OMAP_DSS_VIDEO2)); - DUMPREG(DISPC_OVL_POSITION(OMAP_DSS_VIDEO2)); - DUMPREG(DISPC_OVL_SIZE(OMAP_DSS_VIDEO2)); - DUMPREG(DISPC_OVL_ATTRIBUTES(OMAP_DSS_VIDEO2)); - DUMPREG(DISPC_OVL_FIFO_THRESHOLD(OMAP_DSS_VIDEO2)); - DUMPREG(DISPC_OVL_FIFO_SIZE_STATUS(OMAP_DSS_VIDEO2)); - DUMPREG(DISPC_OVL_ROW_INC(OMAP_DSS_VIDEO2)); - DUMPREG(DISPC_OVL_PIXEL_INC(OMAP_DSS_VIDEO2)); - DUMPREG(DISPC_OVL_FIR(OMAP_DSS_VIDEO2)); - DUMPREG(DISPC_OVL_PICTURE_SIZE(OMAP_DSS_VIDEO2)); - DUMPREG(DISPC_OVL_ACCU0(OMAP_DSS_VIDEO2)); - DUMPREG(DISPC_OVL_ACCU1(OMAP_DSS_VIDEO2)); - - DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO1, 0)); - DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO1, 1)); - DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO1, 2)); - DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO1, 3)); - DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO1, 4)); - DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO1, 5)); - DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO1, 6)); - DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO1, 7)); - DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO1, 0)); - DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO1, 1)); - DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO1, 2)); - DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO1, 3)); - DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO1, 4)); - DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO1, 5)); - DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO1, 6)); - DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO1, 7)); - DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 0)); - DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 1)); - DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 2)); - DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 3)); - DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 4)); - DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 0)); - DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 1)); - DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 2)); - DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 3)); - DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 4)); - DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 5)); - DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 6)); - DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 7)); + if (dss_has_feature(FEAT_CPR)) { + DUMPREG(DISPC_CPR_COEF_R(OMAP_DSS_CHANNEL_LCD2)); + DUMPREG(DISPC_CPR_COEF_G(OMAP_DSS_CHANNEL_LCD2)); + DUMPREG(DISPC_CPR_COEF_B(OMAP_DSS_CHANNEL_LCD2)); + } + } - if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) { - DUMPREG(DISPC_OVL_BA0_UV(OMAP_DSS_VIDEO1)); - DUMPREG(DISPC_OVL_BA1_UV(OMAP_DSS_VIDEO1)); - DUMPREG(DISPC_OVL_FIR2(OMAP_DSS_VIDEO1)); - DUMPREG(DISPC_OVL_ACCU2_0(OMAP_DSS_VIDEO1)); - DUMPREG(DISPC_OVL_ACCU2_1(OMAP_DSS_VIDEO1)); - - DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO1, 0)); - DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO1, 1)); - DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO1, 2)); - DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO1, 3)); - DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO1, 4)); - DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO1, 5)); - DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO1, 6)); - DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO1, 7)); - - DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO1, 0)); - DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO1, 1)); - DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO1, 2)); - DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO1, 3)); - DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO1, 4)); - DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO1, 5)); - DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO1, 6)); - DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO1, 7)); - - DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO1, 0)); - DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO1, 1)); - DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO1, 2)); - DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO1, 3)); - DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO1, 4)); - DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO1, 5)); - DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO1, 6)); - DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO1, 7)); - } - if (dss_has_feature(FEAT_ATTR2)) - DUMPREG(DISPC_OVL_ATTRIBUTES2(OMAP_DSS_VIDEO1)); - - - DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO2, 0)); - DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO2, 1)); - DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO2, 2)); - DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO2, 3)); - DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO2, 4)); - DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO2, 5)); - DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO2, 6)); - DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO2, 7)); - DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO2, 0)); - DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO2, 1)); - DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO2, 2)); - DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO2, 3)); - DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO2, 4)); - DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO2, 5)); - DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO2, 6)); - DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO2, 7)); - DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 0)); - DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 1)); - DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 2)); - DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 3)); - DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 4)); - DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 0)); - DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 1)); - DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 2)); - DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 3)); - DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 4)); - DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 5)); - DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 6)); - DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 7)); + if (dss_has_feature(FEAT_PRELOAD)) + DUMPREG(DISPC_OVL_PRELOAD(OMAP_DSS_GFX)); - if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) { - DUMPREG(DISPC_OVL_BA0_UV(OMAP_DSS_VIDEO2)); - DUMPREG(DISPC_OVL_BA1_UV(OMAP_DSS_VIDEO2)); - DUMPREG(DISPC_OVL_FIR2(OMAP_DSS_VIDEO2)); - DUMPREG(DISPC_OVL_ACCU2_0(OMAP_DSS_VIDEO2)); - DUMPREG(DISPC_OVL_ACCU2_1(OMAP_DSS_VIDEO2)); - - DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO2, 0)); - DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO2, 1)); - DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO2, 2)); - DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO2, 3)); - DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO2, 4)); - DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO2, 5)); - DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO2, 6)); - DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO2, 7)); - - DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO2, 0)); - DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO2, 1)); - DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO2, 2)); - DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO2, 3)); - DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO2, 4)); - DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO2, 5)); - DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO2, 6)); - DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO2, 7)); - - DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO2, 0)); - DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO2, 1)); - DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO2, 2)); - DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO2, 3)); - DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO2, 4)); - DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO2, 5)); - DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO2, 6)); - DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO2, 7)); - } - if (dss_has_feature(FEAT_ATTR2)) - DUMPREG(DISPC_OVL_ATTRIBUTES2(OMAP_DSS_VIDEO2)); - - DUMPREG(DISPC_OVL_PRELOAD(OMAP_DSS_VIDEO1)); - DUMPREG(DISPC_OVL_PRELOAD(OMAP_DSS_VIDEO2)); - - dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK); + for (o = OMAP_DSS_VIDEO1; o <= OMAP_DSS_VIDEO3; o++) { + if (o == OMAP_DSS_VIDEO3 && !dss_has_feature(FEAT_OVL_VID3)) + continue; + + DUMPREG(DISPC_OVL_BA0(o)); + DUMPREG(DISPC_OVL_BA1(o)); + DUMPREG(DISPC_OVL_POSITION(o)); + DUMPREG(DISPC_OVL_SIZE(o)); + DUMPREG(DISPC_OVL_ATTRIBUTES(o)); + DUMPREG(DISPC_OVL_FIFO_THRESHOLD(o)); + DUMPREG(DISPC_OVL_FIFO_SIZE_STATUS(o)); + DUMPREG(DISPC_OVL_ROW_INC(o)); + DUMPREG(DISPC_OVL_PIXEL_INC(o)); + DUMPREG(DISPC_OVL_FIR(o)); + DUMPREG(DISPC_OVL_PICTURE_SIZE(o)); + DUMPREG(DISPC_OVL_ACCU0(o)); + DUMPREG(DISPC_OVL_ACCU1(o)); + + for (i = 0; i < 8; i++) + DUMPREG(DISPC_OVL_FIR_COEF_H(o, i)); + + for (i = 0; i < 8; i++) + DUMPREG(DISPC_OVL_FIR_COEF_HV(o, i)); + + for (i = 0; i < 5; i++) + DUMPREG(DISPC_OVL_CONV_COEF(o, i)); + + if (dss_has_feature(FEAT_FIR_COEF_V)) { + for (i = 0; i < 8; i++) + DUMPREG(DISPC_OVL_FIR_COEF_V(o, i)); + } + + if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) { + DUMPREG(DISPC_OVL_BA0_UV(o)); + DUMPREG(DISPC_OVL_BA1_UV(o)); + DUMPREG(DISPC_OVL_FIR2(o)); + DUMPREG(DISPC_OVL_ACCU2_0(o)); + DUMPREG(DISPC_OVL_ACCU2_1(o)); + + for (i = 0; i < 8; i++) + DUMPREG(DISPC_OVL_FIR_COEF_H2(o, i)); + + for (i = 0; i < 8; i++) + DUMPREG(DISPC_OVL_FIR_COEF_HV2(o, i)); + + for (i = 0; i < 8; i++) + DUMPREG(DISPC_OVL_FIR_COEF_V2(o, i)); + } + if (dss_has_feature(FEAT_ATTR2)) + DUMPREG(DISPC_OVL_ATTRIBUTES2(o)); + + if (dss_has_feature(FEAT_PRELOAD)) + DUMPREG(DISPC_OVL_PRELOAD(o)); + } + + dispc_runtime_put(); #undef DUMPREG } @@ -2882,9 +3317,7 @@ static void _dispc_set_pol_freq(enum omap_channel channel, bool onoff, bool rf, l |= FLD_VAL(acbi, 11, 8); l |= FLD_VAL(acb, 7, 0); - enable_clocks(1); dispc_write_reg(DISPC_POL_FREQ(channel), l); - enable_clocks(0); } void dispc_set_pol_freq(enum omap_channel channel, @@ -3005,15 +3438,11 @@ static void _omap_dispc_set_irqs(void) mask |= isr_data->mask; } - enable_clocks(1); - old_mask = dispc_read_reg(DISPC_IRQENABLE); /* clear the irqstatus for newly enabled irqs */ dispc_write_reg(DISPC_IRQSTATUS, (mask ^ old_mask) & mask); dispc_write_reg(DISPC_IRQENABLE, mask); - - enable_clocks(0); } int omap_dispc_register_isr(omap_dispc_isr_t isr, void *arg, u32 mask) @@ -3119,6 +3548,8 @@ static void print_irq_status(u32 status) PIS(OCP_ERR); PIS(VID1_FIFO_UNDERFLOW); PIS(VID2_FIFO_UNDERFLOW); + if (dss_has_feature(FEAT_OVL_VID3)) + PIS(VID3_FIFO_UNDERFLOW); PIS(SYNC_LOST); PIS(SYNC_LOST_DIGIT); if (dss_has_feature(FEAT_MGR_LCD2)) @@ -3218,6 +3649,8 @@ static void dispc_error_worker(struct work_struct *work) dispc.error_irqs = 0; spin_unlock_irqrestore(&dispc.irq_lock, flags); + dispc_runtime_get(); + if (errors & DISPC_IRQ_GFX_FIFO_UNDERFLOW) { DSSERR("GFX_FIFO_UNDERFLOW, disabling GFX\n"); for (i = 0; i < omap_dss_get_num_overlays(); ++i) { @@ -3272,6 +3705,24 @@ static void dispc_error_worker(struct work_struct *work) } } + if (errors & DISPC_IRQ_VID3_FIFO_UNDERFLOW) { + DSSERR("VID3_FIFO_UNDERFLOW, disabling VID3\n"); + 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 == 3) { + dispc_enable_plane(ovl->id, 0); + dispc_go(ovl->manager->id); + mdelay(50); + break; + } + } + } + if (errors & DISPC_IRQ_SYNC_LOST) { struct omap_overlay_manager *manager = NULL; bool enable = false; @@ -3283,6 +3734,11 @@ static void dispc_error_worker(struct work_struct *work) mgr = omap_dss_get_overlay_manager(i); if (mgr->id == OMAP_DSS_CHANNEL_LCD) { + if(!mgr->device->first_vsync){ + DSSERR("First SYNC_LOST.. ignoring \n"); + break; + } + manager = mgr; enable = mgr->device->state == OMAP_DSS_DISPLAY_ACTIVE; @@ -3315,17 +3771,23 @@ static void dispc_error_worker(struct work_struct *work) struct omap_overlay_manager *manager = NULL; bool enable = false; - DSSERR("SYNC_LOST_DIGIT, disabling TV\n"); + pr_err_ratelimited("SYNC_LOST_DIGIT, disabling TV\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_DIGIT) { + if(!mgr->device->first_vsync){ + DSSERR("First SYNC_LOST..TV ignoring\n"); + } + manager = mgr; enable = mgr->device->state == OMAP_DSS_DISPLAY_ACTIVE; + mgr->device->sync_lost_error = 1; mgr->device->driver->disable(mgr->device); + mgr->device->sync_lost_error = 0; break; } } @@ -3361,6 +3823,11 @@ static void dispc_error_worker(struct work_struct *work) mgr = omap_dss_get_overlay_manager(i); if (mgr->id == OMAP_DSS_CHANNEL_LCD2) { + if(!mgr->device->first_vsync){ + DSSERR("First SYNC_LOST.. ignoring \n"); + break; + } + manager = mgr; enable = mgr->device->state == OMAP_DSS_DISPLAY_ACTIVE; @@ -3404,6 +3871,8 @@ static void dispc_error_worker(struct work_struct *work) dispc.irq_error_mask |= errors; _omap_dispc_set_irqs(); spin_unlock_irqrestore(&dispc.irq_lock, flags); + + dispc_runtime_put(); } int omap_dispc_wait_for_irq_timeout(u32 irqmask, unsigned long timeout) @@ -3446,11 +3915,15 @@ int omap_dispc_wait_for_irq_interruptible_timeout(u32 irqmask, int r; DECLARE_COMPLETION_ONSTACK(completion); + r = dispc_runtime_get(); + if (r) + return r; + r = omap_dispc_register_isr(dispc_irq_wait_handler, &completion, irqmask); if (r) - return r; + goto done; timeout = wait_for_completion_interruptible_timeout(&completion, timeout); @@ -3458,12 +3931,14 @@ int omap_dispc_wait_for_irq_interruptible_timeout(u32 irqmask, omap_dispc_unregister_isr(dispc_irq_wait_handler, &completion, irqmask); if (timeout == 0) - return -ETIMEDOUT; + r = -ETIMEDOUT; + else if (timeout == -ERESTARTSYS) + r = timeout; - if (timeout == -ERESTARTSYS) - return -ERESTARTSYS; +done: + dispc_runtime_put(); - return 0; + return r; } #ifdef CONFIG_OMAP2_DSS_FAKE_VSYNC @@ -3498,7 +3973,8 @@ static void _omap_dispc_initialize_irq(void) dispc.irq_error_mask = DISPC_IRQ_MASK_ERROR; if (dss_has_feature(FEAT_MGR_LCD2)) dispc.irq_error_mask |= DISPC_IRQ_SYNC_LOST2; - + if (dss_has_feature(FEAT_OVL_VID3)) + dispc.irq_error_mask |= DISPC_IRQ_VID3_FIFO_UNDERFLOW; /* there's SYNC_LOST_DIGIT waiting after enabling the DSS, * so clear it */ dispc_write_reg(DISPC_IRQSTATUS, dispc_read_reg(DISPC_IRQSTATUS)); @@ -3522,13 +3998,6 @@ static void _omap_dispc_initial_config(void) { u32 l; - l = dispc_read_reg(DISPC_SYSCONFIG); - l = FLD_MOD(l, 2, 13, 12); /* MIDLEMODE: smart standby */ - l = FLD_MOD(l, 2, 4, 3); /* SIDLEMODE: smart idle */ - l = FLD_MOD(l, 1, 2, 2); /* ENWAKEUP */ - l = FLD_MOD(l, 1, 0, 0); /* AUTOIDLE */ - dispc_write_reg(DISPC_SYSCONFIG, l); - /* Exclusively enable DISPC_CORE_CLK and set divider to 1 */ if (dss_has_feature(FEAT_CORE_CLK_DIV)) { l = dispc_read_reg(DISPC_DIVISOR); @@ -3538,83 +4007,47 @@ static void _omap_dispc_initial_config(void) dispc_write_reg(DISPC_DIVISOR, l); } + /* for OMAP4 ERRATUM xxxx: Mstandby and disconnect protocol issue */ + if (cpu_is_omap44xx()) { + l3_1_clkdm = clkdm_lookup("l3_1_clkdm"); + l3_2_clkdm = clkdm_lookup("l3_2_clkdm"); + } + /* FUNCGATED */ if (dss_has_feature(FEAT_FUNCGATED)) REG_FLD_MOD(DISPC_CONFIG, 1, 9, 9); + REG_FLD_MOD(DISPC_CONFIG, 1, 17, 17); + /* L3 firewall setting: enable access to OCM RAM */ /* XXX this should be somewhere in plat-omap */ if (cpu_is_omap24xx()) __raw_writel(0x402000b0, OMAP2_L3_IO_ADDRESS(0x680050a0)); - _dispc_setup_color_conv_coef(); - dispc_set_loadmode(OMAP_DSS_LOAD_FRAME_ONLY); dispc_read_plane_fifo_sizes(); } -int dispc_enable_plane(enum omap_plane plane, bool enable) -{ - DSSDBG("dispc_enable_plane %d, %d\n", plane, enable); - - enable_clocks(1); - _dispc_enable_plane(plane, enable); - enable_clocks(0); - - return 0; -} - -int dispc_setup_plane(enum omap_plane plane, - u32 paddr, u16 screen_width, - u16 pos_x, u16 pos_y, - u16 width, u16 height, - u16 out_width, u16 out_height, - enum omap_color_mode color_mode, - bool ilace, - enum omap_dss_rotation_type rotation_type, - u8 rotation, bool mirror, u8 global_alpha, - u8 pre_mult_alpha, enum omap_channel channel, - u32 puv_addr) -{ - 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 chan %d\n", - plane, paddr, screen_width, pos_x, pos_y, - width, height, - out_width, out_height, - ilace, color_mode, - rotation, mirror, channel); - - enable_clocks(1); - - r = _dispc_setup_plane(plane, - paddr, screen_width, - pos_x, pos_y, - width, height, - out_width, out_height, - color_mode, ilace, - rotation_type, - rotation, mirror, - global_alpha, - pre_mult_alpha, - channel, puv_addr); - - enable_clocks(0); - - return r; -} - /* DISPC HW IP initialisation */ static int omap_dispchw_probe(struct platform_device *pdev) { u32 rev; int r = 0; struct resource *dispc_mem; + struct clk *clk; dispc.pdev = pdev; + clk = clk_get(&pdev->dev, "dss_clk"); + if (IS_ERR(clk)) { + DSSERR("can't get dss_clk\n"); + r = PTR_ERR(clk); + goto err_get_clk; + } + + dispc.dss_clk = clk; + spin_lock_init(&dispc.irq_lock); #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS @@ -3628,51 +4061,65 @@ static int omap_dispchw_probe(struct platform_device *pdev) if (!dispc_mem) { DSSERR("can't get IORESOURCE_MEM DISPC\n"); r = -EINVAL; - goto fail0; + goto err_ioremap; } dispc.base = ioremap(dispc_mem->start, resource_size(dispc_mem)); if (!dispc.base) { DSSERR("can't ioremap DISPC\n"); r = -ENOMEM; - goto fail0; + goto err_ioremap; } dispc.irq = platform_get_irq(dispc.pdev, 0); if (dispc.irq < 0) { DSSERR("platform_get_irq failed\n"); r = -ENODEV; - goto fail1; + goto err_irq; } r = request_irq(dispc.irq, omap_dispc_irq_handler, IRQF_SHARED, "OMAP DISPC", dispc.pdev); if (r < 0) { DSSERR("request_irq failed\n"); - goto fail1; + goto err_irq; } - enable_clocks(1); + mutex_init(&dispc.runtime_lock); + + pm_runtime_enable(&pdev->dev); + + r = dispc_runtime_get(); + if (r) + goto err_runtime_get; _omap_dispc_initial_config(); _omap_dispc_initialize_irq(); - dispc_save_context(); - rev = dispc_read_reg(DISPC_REVISION); dev_dbg(&pdev->dev, "OMAP DISPC rev %d.%d\n", FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0)); - enable_clocks(0); + dispc_runtime_put(); return 0; -fail1: + +err_runtime_get: + pm_runtime_disable(&pdev->dev); + free_irq(dispc.irq, dispc.pdev); +err_irq: iounmap(dispc.base); -fail0: +err_ioremap: + clk_put(dispc.dss_clk); +err_get_clk: return r; } static int omap_dispchw_remove(struct platform_device *pdev) { + pm_runtime_disable(&pdev->dev); + + clk_put(dispc.dss_clk); + free_irq(dispc.irq, dispc.pdev); iounmap(dispc.base); return 0; |