diff options
Diffstat (limited to 'drivers/video/omap2/dss/dispc.c')
-rw-r--r-- | drivers/video/omap2/dss/dispc.c | 562 |
1 files changed, 322 insertions, 240 deletions
diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c index 7a9a2e7d9685..0f3961a1ce26 100644 --- a/drivers/video/omap2/dss/dispc.c +++ b/drivers/video/omap2/dss/dispc.c @@ -33,6 +33,8 @@ #include <linux/workqueue.h> #include <linux/hardirq.h> #include <linux/interrupt.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> #include <plat/sram.h> #include <plat/clock.h> @@ -77,6 +79,12 @@ struct dispc_v_coef { s8 vc00; }; +enum omap_burst_size { + BURST_SIZE_X2 = 0, + BURST_SIZE_X4 = 1, + BURST_SIZE_X8 = 2, +}; + #define REG_GET(idx, start, end) \ FLD_GET(dispc_read_reg(idx), start, end) @@ -92,7 +100,11 @@ struct dispc_irq_stats { static struct { struct platform_device *pdev; void __iomem *base; + + int ctx_loss_cnt; + int irq; + struct clk *dss_clk; u32 fifo_size[3]; @@ -102,6 +114,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 +147,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; - SR(SYSCONFIG); + DSSDBG("dispc_save_context\n"); + SR(IRQENABLE); SR(CONTROL); SR(CONFIG); @@ -158,7 +187,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,20 +218,25 @@ 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)); @@ -226,8 +261,10 @@ void dispc_save_context(void) for (i = 0; i < 5; i++) SR(OVL_CONV_COEF(OMAP_DSS_VIDEO1, i)); - for (i = 0; i < 8; i++) - SR(OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, i)); + if (dss_has_feature(FEAT_FIR_COEF_V)) { + for (i = 0; i < 8; i++) + SR(OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, i)); + } if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) { SR(OVL_BA0_UV(OMAP_DSS_VIDEO1)); @@ -248,7 +285,8 @@ void dispc_save_context(void) if (dss_has_feature(FEAT_ATTR2)) SR(OVL_ATTRIBUTES2(OMAP_DSS_VIDEO1)); - SR(OVL_PRELOAD(OMAP_DSS_VIDEO1)); + if (dss_has_feature(FEAT_PRELOAD)) + SR(OVL_PRELOAD(OMAP_DSS_VIDEO1)); /* VID2 */ SR(OVL_BA0(OMAP_DSS_VIDEO2)); @@ -273,8 +311,10 @@ void dispc_save_context(void) for (i = 0; i < 5; i++) SR(OVL_CONV_COEF(OMAP_DSS_VIDEO2, i)); - for (i = 0; i < 8; i++) - SR(OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, i)); + if (dss_has_feature(FEAT_FIR_COEF_V)) { + for (i = 0; i < 8; i++) + SR(OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, i)); + } if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) { SR(OVL_BA0_UV(OMAP_DSS_VIDEO2)); @@ -295,16 +335,35 @@ void dispc_save_context(void) if (dss_has_feature(FEAT_ATTR2)) SR(OVL_ATTRIBUTES2(OMAP_DSS_VIDEO2)); - SR(OVL_PRELOAD(OMAP_DSS_VIDEO2)); + if (dss_has_feature(FEAT_PRELOAD)) + SR(OVL_PRELOAD(OMAP_DSS_VIDEO2)); if (dss_has_feature(FEAT_CORE_CLK_DIV)) SR(DIVISOR); + + dispc.ctx_loss_cnt = dispc_get_ctx_loss_count(); + dispc.ctx_valid = true; + + DSSDBG("context saved, ctx_loss_count %d\n", dispc.ctx_loss_cnt); } -void dispc_restore_context(void) +static void dispc_restore_context(void) { - int i; - RR(SYSCONFIG); + int i, ctx; + + DSSDBG("dispc_restore_context\n"); + + if (!dispc.ctx_valid) + return; + + ctx = dispc_get_ctx_loss_count(); + + if (ctx >= 0 && ctx == dispc.ctx_loss_cnt) + return; + + DSSDBG("ctx_loss_count: saved %d, current %d\n", + dispc.ctx_loss_cnt, ctx); + /*RR(IRQENABLE);*/ /*RR(CONTROL);*/ RR(CONFIG); @@ -317,7 +376,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,20 +407,25 @@ 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)); + if (dss_has_feature(FEAT_PRELOAD)) + RR(OVL_PRELOAD(OMAP_DSS_GFX)); /* VID1 */ RR(OVL_BA0(OMAP_DSS_VIDEO1)); @@ -385,8 +450,10 @@ void dispc_restore_context(void) 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_FIR_COEF_V)) { + 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)); @@ -407,7 +474,8 @@ void dispc_restore_context(void) if (dss_has_feature(FEAT_ATTR2)) RR(OVL_ATTRIBUTES2(OMAP_DSS_VIDEO1)); - RR(OVL_PRELOAD(OMAP_DSS_VIDEO1)); + if (dss_has_feature(FEAT_PRELOAD)) + RR(OVL_PRELOAD(OMAP_DSS_VIDEO1)); /* VID2 */ RR(OVL_BA0(OMAP_DSS_VIDEO2)); @@ -432,8 +500,10 @@ void dispc_restore_context(void) for (i = 0; i < 5; i++) RR(OVL_CONV_COEF(OMAP_DSS_VIDEO2, i)); - for (i = 0; i < 8; i++) - RR(OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, i)); + if (dss_has_feature(FEAT_FIR_COEF_V)) { + 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(OMAP_DSS_VIDEO2)); @@ -454,7 +524,8 @@ void dispc_restore_context(void) if (dss_has_feature(FEAT_ATTR2)) RR(OVL_ATTRIBUTES2(OMAP_DSS_VIDEO2)); - RR(OVL_PRELOAD(OMAP_DSS_VIDEO2)); + if (dss_has_feature(FEAT_PRELOAD)) + RR(OVL_PRELOAD(OMAP_DSS_VIDEO2)); if (dss_has_feature(FEAT_CORE_CLK_DIV)) RR(DIVISOR); @@ -471,19 +542,35 @@ 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) +int dispc_runtime_get(void) { - if (enable) - dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK); - else - dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK); + int r; + + DSSDBG("dispc_runtime_get\n"); + + r = pm_runtime_get_sync(&dispc.pdev->dev); + WARN_ON(r < 0); + return r < 0 ? r : 0; } +void dispc_runtime_put(void) +{ + int r; + + DSSDBG("dispc_runtime_put\n"); + + r = pm_runtime_put(&dispc.pdev->dev); + WARN_ON(r < 0); +} + + bool dispc_go_busy(enum omap_channel channel) { int bit; @@ -505,8 +592,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 +605,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 +620,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 +630,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) @@ -920,7 +1003,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; @@ -967,13 +1050,10 @@ static void _dispc_set_channel_out(enum omap_plane plane, dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), val); } -void dispc_set_burst_size(enum omap_plane plane, +static void dispc_set_burst_size(enum omap_plane plane, enum omap_burst_size burst_size) { int shift; - u32 val; - - enable_clocks(1); switch (plane) { case OMAP_DSS_GFX: @@ -988,11 +1068,24 @@ void dispc_set_burst_size(enum omap_plane plane, return; } - 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); + REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), burst_size, shift + 1, shift); +} - enable_clocks(0); +static void dispc_configure_burst_sizes(void) +{ + int i; + const int burst_size = BURST_SIZE_X8; + + /* Configure burst size always to maximum size */ + for (i = 0; i < omap_dss_get_num_overlays(); ++i) + dispc_set_burst_size(i, burst_size); +} + +u32 dispc_get_burst_size(enum omap_plane plane) +{ + unsigned unit = dss_feat_get_burst_size_unit(); + /* burst multiplier is always x8 (see dispc_configure_burst_sizes()) */ + return unit * 8; } void dispc_enable_gamma_table(bool enable) @@ -1009,6 +1102,40 @@ void dispc_enable_gamma_table(bool enable) REG_FLD_MOD(DISPC_CONFIG, enable, 9, 9); } +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 +1156,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 +1164,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 +1172,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) @@ -1059,18 +1180,17 @@ static void dispc_read_plane_fifo_sizes(void) u32 size; int plane; u8 start, end; + u32 unit; - enable_clocks(1); + unit = dss_feat_get_buffer_size_unit(); dss_feat_get_reg_field(FEAT_REG_FIFOSIZE, &start, &end); for (plane = 0; plane < ARRAY_SIZE(dispc.fifo_size); ++plane) { - size = FLD_GET(dispc_read_reg(DISPC_OVL_FIFO_SIZE_STATUS(plane)), - start, end); + size = REG_GET(DISPC_OVL_FIFO_SIZE_STATUS(plane), start, end); + size *= unit; dispc.fifo_size[plane] = size; } - - enable_clocks(0); } u32 dispc_get_plane_fifo_size(enum omap_plane plane) @@ -1078,15 +1198,22 @@ u32 dispc_get_plane_fifo_size(enum omap_plane plane) return dispc.fifo_size[plane]; } -void dispc_setup_plane_fifo(enum omap_plane plane, u32 low, u32 high) +void dispc_set_fifo_threshold(enum omap_plane plane, u32 low, u32 high) { u8 hi_start, hi_end, lo_start, lo_end; + u32 unit; + + unit = dss_feat_get_buffer_size_unit(); + + WARN_ON(low % unit != 0); + WARN_ON(high % unit != 0); + + low /= unit; + high /= unit; 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), @@ -1098,18 +1225,12 @@ void dispc_setup_plane_fifo(enum omap_plane plane, u32 low, u32 high) 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, @@ -1729,14 +1850,7 @@ 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) -{ - enable_clocks(1); - _dispc_set_channel_out(plane, channel_out); - enable_clocks(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, @@ -1744,7 +1858,7 @@ static 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, int mirror, + u8 rotation, bool mirror, u8 global_alpha, u8 pre_mult_alpha, enum omap_channel channel, u32 puv_addr) { @@ -1758,6 +1872,14 @@ static int _dispc_setup_plane(enum omap_plane plane, u16 frame_height = height; unsigned int field_offset = 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); + if (paddr == 0) return -EINVAL; @@ -1903,9 +2025,13 @@ static int _dispc_setup_plane(enum omap_plane plane, 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) @@ -1929,8 +2055,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 */ @@ -1964,8 +2088,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) @@ -1978,12 +2100,8 @@ static void dispc_enable_digit_out(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; @@ -2035,8 +2153,6 @@ static void dispc_enable_digit_out(bool enable) _omap_dispc_set_irqs(); spin_unlock_irqrestore(&dispc.irq_lock, flags); } - - enable_clocks(0); } bool dispc_is_channel_enabled(enum omap_channel channel) @@ -2067,9 +2183,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 +2191,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 +2199,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 +2230,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 +2255,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 +2264,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 +2272,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 +2291,28 @@ 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); 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,7 +2321,6 @@ 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) @@ -2238,7 +2329,6 @@ bool dispc_alpha_blending_enabled(enum omap_channel ch) enabled = REG_GET(DISPC_CONFIG2, 18, 18); else BUG(); - enable_clocks(0); return enabled; } @@ -2248,7 +2338,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 +2346,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 +2373,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 +2408,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 +2419,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 +2471,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 +2515,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 +2535,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 +2565,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); @@ -2526,7 +2604,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 +2653,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 @@ -2629,7 +2709,8 @@ void dispc_dump_regs(struct seq_file *s) { #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 +2730,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,20 +2762,25 @@ 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)); + 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)); + } } - DUMPREG(DISPC_OVL_PRELOAD(OMAP_DSS_GFX)); + if (dss_has_feature(FEAT_PRELOAD)) + DUMPREG(DISPC_OVL_PRELOAD(OMAP_DSS_GFX)); DUMPREG(DISPC_OVL_BA0(OMAP_DSS_VIDEO1)); DUMPREG(DISPC_OVL_BA1(OMAP_DSS_VIDEO1)); @@ -2744,14 +2831,16 @@ void dispc_dump_regs(struct seq_file *s) 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_FIR_COEF_V)) { + 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_HANDLE_UV_SEPARATE)) { DUMPREG(DISPC_OVL_BA0_UV(OMAP_DSS_VIDEO1)); @@ -2812,14 +2901,17 @@ void dispc_dump_regs(struct seq_file *s) 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_FIR_COEF_V)) { + 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_HANDLE_UV_SEPARATE)) { DUMPREG(DISPC_OVL_BA0_UV(OMAP_DSS_VIDEO2)); @@ -2858,10 +2950,12 @@ void dispc_dump_regs(struct seq_file *s) 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)); + if (dss_has_feature(FEAT_PRELOAD)) { + DUMPREG(DISPC_OVL_PRELOAD(OMAP_DSS_VIDEO1)); + DUMPREG(DISPC_OVL_PRELOAD(OMAP_DSS_VIDEO2)); + } - dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK); + dispc_runtime_put(); #undef DUMPREG } @@ -2882,9 +2976,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 +3097,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) @@ -3522,13 +3610,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); @@ -3552,58 +3633,8 @@ static void _omap_dispc_initial_config(void) 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_configure_burst_sizes(); } /* DISPC HW IP initialisation */ @@ -3612,9 +3643,19 @@ 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, "fck"); + if (IS_ERR(clk)) { + DSSERR("can't get fck\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,62 +3669,103 @@ 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); + 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; } +static int dispc_runtime_suspend(struct device *dev) +{ + dispc_save_context(); + clk_disable(dispc.dss_clk); + dss_runtime_put(); + + return 0; +} + +static int dispc_runtime_resume(struct device *dev) +{ + int r; + + r = dss_runtime_get(); + if (r < 0) + return r; + + clk_enable(dispc.dss_clk); + dispc_restore_context(); + + return 0; +} + +static const struct dev_pm_ops dispc_pm_ops = { + .runtime_suspend = dispc_runtime_suspend, + .runtime_resume = dispc_runtime_resume, +}; + static struct platform_driver omap_dispchw_driver = { .probe = omap_dispchw_probe, .remove = omap_dispchw_remove, .driver = { .name = "omapdss_dispc", .owner = THIS_MODULE, + .pm = &dispc_pm_ops, }, }; |