From patchwork Thu Jun 9 13:56:42 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tomi Valkeinen X-Patchwork-Id: 865362 X-Patchwork-Delegate: tomi.valkeinen@nokia.com Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter1.kernel.org (8.14.4/8.14.4) with ESMTP id p59Dv5mK009936 for ; Thu, 9 Jun 2011 13:58:12 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1758135Ab1FIN5y (ORCPT ); Thu, 9 Jun 2011 09:57:54 -0400 Received: from na3sys009aog108.obsmtp.com ([74.125.149.199]:41419 "EHLO na3sys009aog108.obsmtp.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1758130Ab1FIN5v (ORCPT ); Thu, 9 Jun 2011 09:57:51 -0400 Received: from mail-fx0-f47.google.com ([209.85.161.47]) (using TLSv1) by na3sys009aob108.postini.com ([74.125.148.12]) with SMTP ID DSNKTfDRXa0/M5vrND6zN0C99skCsJ96owLk@postini.com; Thu, 09 Jun 2011 06:57:50 PDT Received: by fxm19 with SMTP id 19so1615858fxm.34 for ; Thu, 09 Jun 2011 06:57:48 -0700 (PDT) Received: by 10.223.17.142 with SMTP id s14mr819076faa.145.1307627868118; Thu, 09 Jun 2011 06:57:48 -0700 (PDT) Received: from localhost.localdomain (a62-248-131-233.elisa-laajakaista.fi [62.248.131.233]) by mx.google.com with ESMTPS id q10sm669900fan.8.2011.06.09.06.57.44 (version=SSLv3 cipher=OTHER); Thu, 09 Jun 2011 06:57:46 -0700 (PDT) From: Tomi Valkeinen To: linux-omap@vger.kernel.org, linux-fbdev@vger.kernel.org Cc: b-cousson@ti.com, paul@pwsan.com, khilman@ti.com, Tomi Valkeinen Subject: [PATCHv2 20/28] OMAP: DSS2: Use PM runtime & HWMOD support Date: Thu, 9 Jun 2011 16:56:42 +0300 Message-Id: <1307627810-3768-21-git-send-email-tomi.valkeinen@ti.com> X-Mailer: git-send-email 1.7.4.1 In-Reply-To: <1307627810-3768-1-git-send-email-tomi.valkeinen@ti.com> References: <1307627810-3768-1-git-send-email-tomi.valkeinen@ti.com> Sender: linux-omap-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-omap@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.6 (demeter1.kernel.org [140.211.167.41]); Thu, 09 Jun 2011 13:58:12 +0000 (UTC) Use PM runtime and HWMOD support to handle enabling and disabling of DSS modules. Each DSS module will have get and put functions which can be used to enable and disable that module. The functions use pm_runtime and hwmod opt-clocks to enable the hardware. Signed-off-by: Tomi Valkeinen Acked-by: Kevin Hilman --- drivers/video/omap2/dss/dispc.c | 326 ++++++++++++++++++++++---------- drivers/video/omap2/dss/dpi.c | 70 +++++--- drivers/video/omap2/dss/dsi.c | 244 +++++++++++++++--------- drivers/video/omap2/dss/dss.c | 376 ++++++++----------------------------- drivers/video/omap2/dss/dss.h | 33 ++-- drivers/video/omap2/dss/hdmi.c | 161 ++++++++++++---- drivers/video/omap2/dss/manager.c | 8 +- drivers/video/omap2/dss/overlay.c | 24 ++- drivers/video/omap2/dss/rfbi.c | 110 +++++++++-- drivers/video/omap2/dss/sdi.c | 40 +++-- drivers/video/omap2/dss/venc.c | 165 ++++++++++++++--- 11 files changed, 923 insertions(+), 634 deletions(-) diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c index ee2052f..3f2265f 100644 --- a/drivers/video/omap2/dss/dispc.c +++ b/drivers/video/omap2/dss/dispc.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -93,7 +94,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]; @@ -140,13 +145,12 @@ static inline u32 dispc_read_reg(const u16 idx) #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); @@ -314,10 +318,12 @@ void dispc_save_context(void) SR(DIVISOR); } -void dispc_restore_context(void) +static void dispc_restore_context(void) { int i; - RR(SYSCONFIG); + + DSSDBG("dispc_restore_context\n"); + /*RR(IRQENABLE);*/ /*RR(CONTROL);*/ RR(CONFIG); @@ -501,14 +507,82 @@ void dispc_restore_context(void) #undef SR #undef RR -static inline void enable_clocks(bool enable) +static void dispc_init_ctx_loss_count(void) { - if (enable) - dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK); - else - dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK); + 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 = 0; + + /* + * get_context_loss_count returns negative on error. We'll ignore the + * error and store the error to ctx_loss_cnt, which will cause + * dispc_need_ctx_restore() call to return true. + */ + + if (board_data->get_context_loss_count) + cnt = board_data->get_context_loss_count(dev); + + WARN_ON(cnt < 0); + + dispc.ctx_loss_cnt = cnt; + + DSSDBG("initial ctx_loss_cnt %u\n", cnt); +} + +static bool dispc_need_ctx_restore(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 get_context_loss_count is not available, assume that we need + * context restore always. + */ + if (!board_data->get_context_loss_count) + return true; + + cnt = board_data->get_context_loss_count(dev); + if (cnt < 0) { + dev_err(dev, "getting context loss count failed, will force " + "context restore\n"); + dispc.ctx_loss_cnt = cnt; + return true; + } + + if (cnt == dispc.ctx_loss_cnt) + return false; + + DSSDBG("ctx_loss_cnt %d -> %d\n", dispc.ctx_loss_cnt, cnt); + dispc.ctx_loss_cnt = cnt; + + return true; +} + +int dispc_runtime_get(void) +{ + 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; @@ -530,7 +604,7 @@ void dispc_go(enum omap_channel channel) int bit; bool enable_bit, go_bit; - enable_clocks(1); + dispc_runtime_get(); if (channel == OMAP_DSS_CHANNEL_LCD || channel == OMAP_DSS_CHANNEL_LCD2) @@ -571,7 +645,7 @@ void dispc_go(enum omap_channel channel) else REG_FLD_MOD(DISPC_CONTROL, 1, bit, bit); end: - enable_clocks(0); + dispc_runtime_put(); } static void _dispc_write_firh_reg(enum omap_plane plane, int reg, u32 value) @@ -998,7 +1072,7 @@ void dispc_set_burst_size(enum omap_plane plane, int shift; u32 val; - enable_clocks(1); + dispc_runtime_get(); switch (plane) { case OMAP_DSS_GFX: @@ -1017,7 +1091,7 @@ void dispc_set_burst_size(enum omap_plane plane, val = FLD_MOD(val, burst_size, shift+1, shift); dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), val); - enable_clocks(0); + dispc_runtime_put(); } void dispc_enable_gamma_table(bool enable) @@ -1054,9 +1128,9 @@ void dispc_enable_replication(enum omap_plane plane, bool enable) else bit = 10; - enable_clocks(1); + dispc_runtime_get(); REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable, bit, bit); - enable_clocks(0); + dispc_runtime_put(); } void dispc_set_lcd_size(enum omap_channel channel, u16 width, u16 height) @@ -1064,9 +1138,9 @@ 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_runtime_get(); dispc_write_reg(DISPC_SIZE_MGR(channel), val); - enable_clocks(0); + dispc_runtime_put(); } void dispc_set_digit_size(u16 width, u16 height) @@ -1074,9 +1148,9 @@ 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_runtime_get(); dispc_write_reg(DISPC_SIZE_MGR(OMAP_DSS_CHANNEL_DIGIT), val); - enable_clocks(0); + dispc_runtime_put(); } static void dispc_read_plane_fifo_sizes(void) @@ -1085,7 +1159,7 @@ static void dispc_read_plane_fifo_sizes(void) int plane; u8 start, end; - enable_clocks(1); + dispc_runtime_get(); dss_feat_get_reg_field(FEAT_REG_FIFOSIZE, &start, &end); @@ -1095,7 +1169,7 @@ static void dispc_read_plane_fifo_sizes(void) dispc.fifo_size[plane] = size; } - enable_clocks(0); + dispc_runtime_put(); } u32 dispc_get_plane_fifo_size(enum omap_plane plane) @@ -1110,7 +1184,7 @@ 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); + dispc_runtime_get(); DSSDBG("fifo(%d) low/high old %u/%u, new %u/%u\n", plane, @@ -1124,17 +1198,17 @@ void dispc_setup_plane_fifo(enum omap_plane plane, u32 low, u32 high) FLD_VAL(high, hi_start, hi_end) | FLD_VAL(low, lo_start, lo_end)); - enable_clocks(0); + dispc_runtime_put(); } void dispc_enable_fifomerge(bool enable) { - enable_clocks(1); + dispc_runtime_get(); DSSDBG("FIFO merge %s\n", enable ? "enabled" : "disabled"); REG_FLD_MOD(DISPC_CONFIG, enable ? 1 : 0, 14, 14); - enable_clocks(0); + dispc_runtime_put(); } static void _dispc_set_fir(enum omap_plane plane, @@ -1756,9 +1830,9 @@ static unsigned long calc_fclk(enum omap_channel channel, u16 width, void dispc_set_channel_out(enum omap_plane plane, enum omap_channel channel_out) { - enable_clocks(1); + dispc_runtime_get(); _dispc_set_channel_out(plane, channel_out); - enable_clocks(0); + dispc_runtime_put(); } static int _dispc_setup_plane(enum omap_plane plane, @@ -1954,7 +2028,7 @@ static void dispc_enable_lcd_out(enum omap_channel channel, bool enable) int r; u32 irq; - enable_clocks(1); + dispc_runtime_get(); /* When we disable LCD output, we need to wait until frame is done. * Otherwise the DSS is still working, and turning off the clocks @@ -1990,7 +2064,7 @@ static void dispc_enable_lcd_out(enum omap_channel channel, bool enable) DSSERR("failed to unregister FRAMEDONE isr\n"); } - enable_clocks(0); + dispc_runtime_put(); } static void _enable_digit_out(bool enable) @@ -2003,10 +2077,10 @@ static void dispc_enable_digit_out(bool enable) struct completion frame_done_completion; int r; - enable_clocks(1); + dispc_runtime_get(); if (REG_GET(DISPC_CONTROL, 1, 1) == enable) { - enable_clocks(0); + dispc_runtime_put(); return; } @@ -2061,7 +2135,7 @@ static void dispc_enable_digit_out(bool enable) spin_unlock_irqrestore(&dispc.irq_lock, flags); } - enable_clocks(0); + dispc_runtime_put(); } bool dispc_is_channel_enabled(enum omap_channel channel) @@ -2092,9 +2166,9 @@ void dispc_lcd_enable_signal_polarity(bool act_high) if (!dss_has_feature(FEAT_LCDENABLEPOL)) return; - enable_clocks(1); + dispc_runtime_get(); REG_FLD_MOD(DISPC_CONTROL, act_high ? 1 : 0, 29, 29); - enable_clocks(0); + dispc_runtime_put(); } void dispc_lcd_enable_signal(bool enable) @@ -2102,9 +2176,9 @@ void dispc_lcd_enable_signal(bool enable) if (!dss_has_feature(FEAT_LCDENABLESIGNAL)) return; - enable_clocks(1); + dispc_runtime_get(); REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 28, 28); - enable_clocks(0); + dispc_runtime_put(); } void dispc_pck_free_enable(bool enable) @@ -2112,19 +2186,19 @@ void dispc_pck_free_enable(bool enable) if (!dss_has_feature(FEAT_PCKFREEENABLE)) return; - enable_clocks(1); + dispc_runtime_get(); REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 27, 27); - enable_clocks(0); + dispc_runtime_put(); } void dispc_enable_fifohandcheck(enum omap_channel channel, bool enable) { - enable_clocks(1); + dispc_runtime_get(); 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); + dispc_runtime_put(); } @@ -2147,27 +2221,27 @@ void dispc_set_lcd_display_type(enum omap_channel channel, return; } - enable_clocks(1); + dispc_runtime_get(); 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); + dispc_runtime_put(); } void dispc_set_loadmode(enum omap_dss_load_mode mode) { - enable_clocks(1); + dispc_runtime_get(); REG_FLD_MOD(DISPC_CONFIG, mode, 2, 1); - enable_clocks(0); + dispc_runtime_put(); } void dispc_set_default_color(enum omap_channel channel, u32 color) { - enable_clocks(1); + dispc_runtime_get(); dispc_write_reg(DISPC_DEFAULT_COLOR(channel), color); - enable_clocks(0); + dispc_runtime_put(); } u32 dispc_get_default_color(enum omap_channel channel) @@ -2178,9 +2252,9 @@ u32 dispc_get_default_color(enum omap_channel channel) channel != OMAP_DSS_CHANNEL_LCD && channel != OMAP_DSS_CHANNEL_LCD2); - enable_clocks(1); + dispc_runtime_get(); l = dispc_read_reg(DISPC_DEFAULT_COLOR(channel)); - enable_clocks(0); + dispc_runtime_put(); return l; } @@ -2189,7 +2263,7 @@ void dispc_set_trans_key(enum omap_channel ch, enum omap_dss_trans_key_type type, u32 trans_key) { - enable_clocks(1); + dispc_runtime_get(); if (ch == OMAP_DSS_CHANNEL_LCD) REG_FLD_MOD(DISPC_CONFIG, type, 11, 11); else if (ch == OMAP_DSS_CHANNEL_DIGIT) @@ -2198,14 +2272,14 @@ 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); + dispc_runtime_put(); } void dispc_get_trans_key(enum omap_channel ch, enum omap_dss_trans_key_type *type, u32 *trans_key) { - enable_clocks(1); + dispc_runtime_get(); if (type) { if (ch == OMAP_DSS_CHANNEL_LCD) *type = REG_GET(DISPC_CONFIG, 11, 11); @@ -2219,33 +2293,33 @@ void dispc_get_trans_key(enum omap_channel ch, if (trans_key) *trans_key = dispc_read_reg(DISPC_TRANS_COLOR(ch)); - enable_clocks(0); + dispc_runtime_put(); } void dispc_enable_trans_key(enum omap_channel ch, bool enable) { - enable_clocks(1); + dispc_runtime_get(); 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); + dispc_runtime_put(); } void dispc_enable_alpha_blending(enum omap_channel ch, bool enable) { if (!dss_has_feature(FEAT_GLOBAL_ALPHA)) return; - enable_clocks(1); + dispc_runtime_get(); 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); + dispc_runtime_put(); } bool dispc_alpha_blending_enabled(enum omap_channel ch) { @@ -2254,7 +2328,7 @@ bool dispc_alpha_blending_enabled(enum omap_channel ch) if (!dss_has_feature(FEAT_GLOBAL_ALPHA)) return false; - enable_clocks(1); + dispc_runtime_get(); if (ch == OMAP_DSS_CHANNEL_LCD) enabled = REG_GET(DISPC_CONFIG, 18, 18); else if (ch == OMAP_DSS_CHANNEL_DIGIT) @@ -2263,7 +2337,7 @@ bool dispc_alpha_blending_enabled(enum omap_channel ch) enabled = REG_GET(DISPC_CONFIG2, 18, 18); else BUG(); - enable_clocks(0); + dispc_runtime_put(); return enabled; } @@ -2273,7 +2347,7 @@ bool dispc_trans_key_enabled(enum omap_channel ch) { bool enabled; - enable_clocks(1); + dispc_runtime_get(); if (ch == OMAP_DSS_CHANNEL_LCD) enabled = REG_GET(DISPC_CONFIG, 10, 10); else if (ch == OMAP_DSS_CHANNEL_DIGIT) @@ -2282,7 +2356,7 @@ bool dispc_trans_key_enabled(enum omap_channel ch) enabled = REG_GET(DISPC_CONFIG2, 10, 10); else BUG(); - enable_clocks(0); + dispc_runtime_put(); return enabled; } @@ -2310,12 +2384,12 @@ void dispc_set_tft_data_lines(enum omap_channel channel, u8 data_lines) return; } - enable_clocks(1); + dispc_runtime_get(); 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); + dispc_runtime_put(); } void dispc_set_parallel_interface_mode(enum omap_channel channel, @@ -2347,7 +2421,7 @@ void dispc_set_parallel_interface_mode(enum omap_channel channel, return; } - enable_clocks(1); + dispc_runtime_get(); if (channel == OMAP_DSS_CHANNEL_LCD2) { l = dispc_read_reg(DISPC_CONTROL2); @@ -2361,7 +2435,7 @@ void dispc_set_parallel_interface_mode(enum omap_channel channel, dispc_write_reg(DISPC_CONTROL, l); } - enable_clocks(0); + dispc_runtime_put(); } static bool _dispc_lcd_timings_ok(int hsw, int hfp, int hbp, @@ -2414,10 +2488,10 @@ static void _dispc_set_lcd_timings(enum omap_channel channel, int hsw, FLD_VAL(vbp, 31, 20); } - enable_clocks(1); + dispc_runtime_get(); dispc_write_reg(DISPC_TIMING_H(channel), timing_h); dispc_write_reg(DISPC_TIMING_V(channel), timing_v); - enable_clocks(0); + dispc_runtime_put(); } /* change name to mode? */ @@ -2460,10 +2534,10 @@ 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_runtime_get(); dispc_write_reg(DISPC_DIVISORo(channel), FLD_VAL(lck_div, 23, 16) | FLD_VAL(pck_div, 7, 0)); - enable_clocks(0); + dispc_runtime_put(); } static void dispc_get_lcd_divisor(enum omap_channel channel, int *lck_div, @@ -2482,7 +2556,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); @@ -2512,7 +2586,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); @@ -2551,7 +2625,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"); @@ -2599,7 +2674,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 @@ -2654,7 +2730,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); @@ -2899,7 +2976,7 @@ void dispc_dump_regs(struct seq_file *s) DUMPREG(DISPC_OVL_PRELOAD(OMAP_DSS_VIDEO2)); } - dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK); + dispc_runtime_put(); #undef DUMPREG } @@ -2920,9 +2997,9 @@ 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_runtime_get(); dispc_write_reg(DISPC_POL_FREQ(channel), l); - enable_clocks(0); + dispc_runtime_put(); } void dispc_set_pol_freq(enum omap_channel channel, @@ -3043,7 +3120,7 @@ static void _omap_dispc_set_irqs(void) mask |= isr_data->mask; } - enable_clocks(1); + dispc_runtime_get(); old_mask = dispc_read_reg(DISPC_IRQENABLE); /* clear the irqstatus for newly enabled irqs */ @@ -3051,7 +3128,7 @@ static void _omap_dispc_set_irqs(void) dispc_write_reg(DISPC_IRQENABLE, mask); - enable_clocks(0); + dispc_runtime_put(); } int omap_dispc_register_isr(omap_dispc_isr_t isr, void *arg, u32 mask) @@ -3560,13 +3637,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); @@ -3596,9 +3666,9 @@ int dispc_enable_plane(enum omap_plane plane, bool enable) { DSSDBG("dispc_enable_plane %d, %d\n", plane, enable); - enable_clocks(1); + dispc_runtime_get(); _dispc_enable_plane(plane, enable); - enable_clocks(0); + dispc_runtime_put(); return 0; } @@ -3625,7 +3695,7 @@ int dispc_setup_plane(enum omap_plane plane, ilace, color_mode, rotation, mirror, channel); - enable_clocks(1); + dispc_runtime_get(); r = _dispc_setup_plane(plane, paddr, screen_width, @@ -3639,7 +3709,7 @@ int dispc_setup_plane(enum omap_plane plane, pre_mult_alpha, channel, puv_addr); - enable_clocks(0); + dispc_runtime_put(); return r; } @@ -3650,9 +3720,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, "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 @@ -3666,62 +3746,106 @@ 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); + dispc_init_ctx_loss_count(); + + 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); + if (dispc_need_ctx_restore()) + 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, }, }; diff --git a/drivers/video/omap2/dss/dpi.c b/drivers/video/omap2/dss/dpi.c index bab55cd..f053b18 100644 --- a/drivers/video/omap2/dss/dpi.c +++ b/drivers/video/omap2/dss/dpi.c @@ -23,7 +23,6 @@ #define DSS_SUBSYS_NAME "DPI" #include -#include #include #include #include @@ -130,8 +129,6 @@ static int dpi_set_mode(struct omap_dss_device *dssdev) bool is_tft; int r = 0; - dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK); - dispc_set_pol_freq(dssdev->manager->id, dssdev->panel.config, dssdev->panel.acbi, dssdev->panel.acb); @@ -144,7 +141,7 @@ static int dpi_set_mode(struct omap_dss_device *dssdev) r = dpi_set_dispc_clk(dssdev, is_tft, t->pixel_clock * 1000, &fck, &lck_div, &pck_div); if (r) - goto err0; + return r; pck = fck / lck_div / pck_div / 1000; @@ -158,12 +155,10 @@ static int dpi_set_mode(struct omap_dss_device *dssdev) dispc_set_lcd_timings(dssdev->manager->id, t); -err0: - dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK); - return r; + return 0; } -static int dpi_basic_init(struct omap_dss_device *dssdev) +static void dpi_basic_init(struct omap_dss_device *dssdev) { bool is_tft; @@ -175,8 +170,6 @@ static int dpi_basic_init(struct omap_dss_device *dssdev) OMAP_DSS_LCD_DISPLAY_TFT : OMAP_DSS_LCD_DISPLAY_STN); dispc_set_tft_data_lines(dssdev->manager->id, dssdev->phy.dpi.data_lines); - - return 0; } int omapdss_dpi_display_enable(struct omap_dss_device *dssdev) @@ -186,30 +179,38 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev) r = omap_dss_start_device(dssdev); if (r) { DSSERR("failed to start device\n"); - goto err0; + goto err_start_dev; } if (cpu_is_omap34xx()) { r = regulator_enable(dpi.vdds_dsi_reg); if (r) - goto err1; + goto err_reg_enable; } - dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK); + r = dss_runtime_get(); + if (r) + goto err_get_dss; - r = dpi_basic_init(dssdev); + r = dispc_runtime_get(); if (r) - goto err2; + goto err_get_dispc; + + dpi_basic_init(dssdev); if (dpi_use_dsi_pll(dssdev)) { + r = dsi_runtime_get(dpi.dsidev); + if (r) + goto err_get_dsi; + r = dsi_pll_init(dpi.dsidev, 0, 1); if (r) - goto err2; + goto err_dsi_pll_init; } r = dpi_set_mode(dssdev); if (r) - goto err3; + goto err_set_mode; mdelay(2); @@ -217,16 +218,22 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev) return 0; -err3: +err_set_mode: if (dpi_use_dsi_pll(dssdev)) dsi_pll_uninit(dpi.dsidev, true); -err2: - dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK); +err_dsi_pll_init: + if (dpi_use_dsi_pll(dssdev)) + dsi_runtime_put(dpi.dsidev); +err_get_dsi: + dispc_runtime_put(); +err_get_dispc: + dss_runtime_put(); +err_get_dss: if (cpu_is_omap34xx()) regulator_disable(dpi.vdds_dsi_reg); -err1: +err_reg_enable: omap_dss_stop_device(dssdev); -err0: +err_start_dev: return r; } EXPORT_SYMBOL(omapdss_dpi_display_enable); @@ -238,9 +245,11 @@ void omapdss_dpi_display_disable(struct omap_dss_device *dssdev) if (dpi_use_dsi_pll(dssdev)) { dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK); dsi_pll_uninit(dpi.dsidev, true); + dsi_runtime_put(dpi.dsidev); } - dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK); + dispc_runtime_put(); + dss_runtime_put(); if (cpu_is_omap34xx()) regulator_disable(dpi.vdds_dsi_reg); @@ -252,11 +261,26 @@ EXPORT_SYMBOL(omapdss_dpi_display_disable); void dpi_set_timings(struct omap_dss_device *dssdev, struct omap_video_timings *timings) { + int r; + DSSDBG("dpi_set_timings\n"); dssdev->panel.timings = *timings; if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) { + r = dss_runtime_get(); + if (r) + return; + + r = dispc_runtime_get(); + if (r) { + dss_runtime_put(); + return; + } + dpi_set_mode(dssdev); dispc_go(dssdev->manager->id); + + dispc_runtime_put(); + dss_runtime_put(); } } EXPORT_SYMBOL(dpi_set_timings); diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index 0609885..b6a57bb 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c @@ -36,6 +36,7 @@ #include #include #include +#include #include