From 829702a4980b5c13dc14f4556c513bc62e4aaec1 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Thu, 14 Sep 2006 14:13:30 +0300 Subject: [PATCH] ARM: OMAP2: fb: clock refcounting for dynamic sleep mode Hold reference counts on related clocks only for the duration when they are needed, so that dynamic sleep logic can enter the most ideal power state. Signed-off-by: Imre Deak Signed-off-by: Juha Yrjola --- drivers/video/omap/dispc.c | 67 +++++++++++++++++++++++++++++++++----- drivers/video/omap/rfbi.c | 64 +++++++++++++++++++++++++++++++----- 2 files changed, 114 insertions(+), 17 deletions(-) diff --git a/drivers/video/omap/dispc.c b/drivers/video/omap/dispc.c index c7bd1e0c73c..ecc785d362c 100644 --- a/drivers/video/omap/dispc.c +++ b/drivers/video/omap/dispc.c @@ -162,6 +162,8 @@ static struct { struct omapfb_color_key color_key; } dispc; +static void enable_lcd_clocks(int enable); + static void inline dispc_write_reg(int idx, u32 val) { __raw_writel(val, dispc.base + idx); @@ -231,16 +233,20 @@ static void set_load_mode(int mode) void omap_dispc_set_lcd_size(int x, int y) { BUG_ON((x > (1 << 11)) || (y > (1 << 11))); + enable_lcd_clocks(1); MOD_REG_FLD(DISPC_SIZE_LCD, FLD_MASK(16, 11) | FLD_MASK(0, 11), ((y - 1) << 16) | (x - 1)); + enable_lcd_clocks(0); } EXPORT_SYMBOL(omap_dispc_set_lcd_size); void omap_dispc_set_digit_size(int x, int y) { BUG_ON((x > (1 << 11)) || (y > (1 << 11))); + enable_lcd_clocks(1); MOD_REG_FLD(DISPC_SIZE_DIG, FLD_MASK(16, 11) | FLD_MASK(0, 11), ((y - 1) << 16) | (x - 1)); + enable_lcd_clocks(0); } EXPORT_SYMBOL(omap_dispc_set_digit_size); @@ -272,13 +278,17 @@ static void setup_plane_fifo(int plane, int ext_mode) void omap_dispc_enable_lcd_out(int enable) { + enable_lcd_clocks(1); MOD_REG_FLD(DISPC_CONTROL, 1, enable ? 1 : 0); + enable_lcd_clocks(0); } EXPORT_SYMBOL(omap_dispc_enable_lcd_out); void omap_dispc_enable_digit_out(int enable) { + enable_lcd_clocks(1); MOD_REG_FLD(DISPC_CONTROL, 1 << 1, enable ? 1 << 1 : 0); + enable_lcd_clocks(0); } EXPORT_SYMBOL(omap_dispc_enable_digit_out); @@ -414,13 +424,17 @@ static int omap_dispc_setup_plane(int plane, int channel_out, int color_mode) { u32 paddr; + int r; if ((unsigned)plane > dispc.mem_desc.region_cnt) return -EINVAL; paddr = dispc.mem_desc.region[plane].paddr + offset; - return _setup_plane(plane, channel_out, paddr, + enable_lcd_clocks(1); + r = _setup_plane(plane, channel_out, paddr, screen_width, pos_x, pos_y, width, height, color_mode); + enable_lcd_clocks(0); + return r; } static void write_firh_reg(int plane, int reg, u32 value) @@ -487,18 +501,23 @@ static int omap_dispc_set_scale(int plane, (out_width != orig_width || out_height != orig_height)) return -EINVAL; + enable_lcd_clocks(1); if (orig_width < out_width) { /* Upsampling. * Currently you can only scale both dimensions in one way. */ if (orig_height > out_height || orig_width * 8 < out_width || - orig_height * 8 < out_height) + orig_height * 8 < out_height) { + enable_lcd_clocks(0); return -EINVAL; + } set_upsampling_coef_table(plane); } else if (orig_width > out_width) { /* Downsampling not yet supported */ + + enable_lcd_clocks(0); return -EINVAL; } if (!orig_width || orig_width == out_width) @@ -532,6 +551,7 @@ static int omap_dispc_set_scale(int plane, l |= fir_vinc ? (1 << 6) : 0; dispc_write_reg(at_reg[plane], l); + enable_lcd_clocks(0); return 0; } @@ -542,7 +562,10 @@ static int omap_dispc_enable_plane(int plane, int enable) DISPC_VID2_BASE + DISPC_VID_ATTRIBUTES }; if ((unsigned int)plane > dispc.mem_desc.region_cnt) return -EINVAL; + + enable_lcd_clocks(1); MOD_REG_FLD(at_reg[plane], 1, enable ? 1 : 0); + enable_lcd_clocks(0); return 0; } @@ -579,11 +602,13 @@ static int omap_dispc_set_color_key(struct omapfb_color_key *ck) default: return -EINVAL; } + enable_lcd_clocks(1); MOD_REG_FLD(DISPC_CONFIG, FLD_MASK(shift, 2), val << shift); if (val != 0) dispc_write_reg(tr_reg, ck->trans_key); dispc_write_reg(df_reg, ck->background); + enable_lcd_clocks(0); dispc.color_key = *ck; @@ -608,6 +633,7 @@ static int omap_dispc_set_update_mode(enum omapfb_update_mode mode) switch (mode) { case OMAPFB_AUTO_UPDATE: case OMAPFB_MANUAL_UPDATE: + enable_lcd_clocks(1); omap_dispc_enable_lcd_out(1); dispc.update_mode = mode; break; @@ -620,6 +646,7 @@ static int omap_dispc_set_update_mode(enum omapfb_update_mode mode) "timeout waiting for FRAME DONE\n"); } dispc.update_mode = mode; + enable_lcd_clocks(0); break; default: r = -EINVAL; @@ -775,25 +802,31 @@ EXPORT_SYMBOL(omap_dispc_request_irq); void omap_dispc_enable_irqs(int irq_mask) { + enable_lcd_clocks(1); dispc.enabled_irqs = irq_mask; irq_mask |= DISPC_IRQ_MASK_ERROR; MOD_REG_FLD(DISPC_IRQENABLE, 0x7fff, irq_mask); + enable_lcd_clocks(0); } EXPORT_SYMBOL(omap_dispc_enable_irqs); void omap_dispc_disable_irqs(int irq_mask) { + enable_lcd_clocks(1); dispc.enabled_irqs &= ~irq_mask; irq_mask &= ~DISPC_IRQ_MASK_ERROR; MOD_REG_FLD(DISPC_IRQENABLE, 0x7fff, irq_mask); + enable_lcd_clocks(0); } EXPORT_SYMBOL(omap_dispc_disable_irqs); void omap_dispc_free_irq(void) { + enable_lcd_clocks(1); omap_dispc_disable_irqs(DISPC_IRQ_MASK_ALL); dispc.irq_callback = NULL; dispc.irq_callback_data = NULL; + enable_lcd_clocks(0); } EXPORT_SYMBOL(omap_dispc_free_irq); @@ -856,13 +889,18 @@ static void put_dss_clocks(void) static void enable_lcd_clocks(int enable) { - if (enable) { - clk_enable(dispc.dss_ick); + if (enable) clk_enable(dispc.dss1_fck); - } else { + else clk_disable(dispc.dss1_fck); +} + +static void enable_interface_clocks(int enable) +{ + if (enable) + clk_enable(dispc.dss_ick); + else clk_disable(dispc.dss_ick); - } } static void enable_digit_clocks(int enable) @@ -891,8 +929,10 @@ static void omap_dispc_resume(void) { if (dispc.update_mode == OMAPFB_AUTO_UPDATE) { enable_lcd_clocks(1); - set_lcd_timings(); - load_palette(); + if (!dispc.ext_mode) { + set_lcd_timings(); + load_palette(); + } omap_dispc_enable_lcd_out(1); } } @@ -1040,6 +1080,7 @@ static int omap_dispc_init(struct omapfb_device *fbdev, int ext_mode, if ((r = get_dss_clocks()) < 0) return r; + enable_interface_clocks(1); enable_lcd_clocks(1); #ifdef CONFIG_FB_OMAP_BOOTLOADER_INIT @@ -1122,6 +1163,7 @@ static int omap_dispc_init(struct omapfb_device *fbdev, int ext_mode, l = dispc_read_reg(DISPC_REVISION); pr_info("omapfb: DISPC version %d.%d initialized\n", l >> 4 & 0x0f, l & 0x0f); + enable_lcd_clocks(0); return 0; fail3: @@ -1130,6 +1172,7 @@ fail2: free_irq(INT_24XX_DSS_IRQ, fbdev); fail1: enable_lcd_clocks(0); + enable_interface_clocks(0); put_dss_clocks(); return r; @@ -1137,10 +1180,16 @@ fail1: static void omap_dispc_cleanup(void) { + int i; + + omap_dispc_set_update_mode(OMAPFB_UPDATE_DISABLED); + /* This will also disable clocks that are on */ + for (i = 0; i < dispc.mem_desc.region_cnt; i++) + omap_dispc_enable_plane(i, 0); cleanup_fbmem(); free_palette_ram(); free_irq(INT_24XX_DSS_IRQ, dispc.fbdev); - enable_lcd_clocks(0); + enable_interface_clocks(0); put_dss_clocks(); } diff --git a/drivers/video/omap/rfbi.c b/drivers/video/omap/rfbi.c index 5347e9b9d22..ebb317623b5 100644 --- a/drivers/video/omap/rfbi.c +++ b/drivers/video/omap/rfbi.c @@ -65,6 +65,8 @@ static struct { unsigned long l4_khz; int bits_per_cycle; struct omapfb_device *fbdev; + struct clk *dss_ick; + struct clk *dss1_fck; } rfbi; static inline void rfbi_write_reg(int idx, u32 val) @@ -77,6 +79,40 @@ static inline u32 rfbi_read_reg(int idx) return __raw_readl(rfbi.base + idx); } +static int rfbi_get_clocks(void) +{ + if (IS_ERR((rfbi.dss_ick = clk_get(rfbi.fbdev->dev, "dss_ick")))) { + dev_err(rfbi.fbdev->dev, "can't get dss_ick"); + return PTR_ERR(rfbi.dss_ick); + } + + if (IS_ERR((rfbi.dss1_fck = clk_get(rfbi.fbdev->dev, "dss1_fck")))) { + dev_err(rfbi.fbdev->dev, "can't get dss1_fck"); + clk_put(rfbi.dss_ick); + return PTR_ERR(rfbi.dss1_fck); + } + + return 0; +} + +static void rfbi_put_clocks(void) +{ + clk_put(rfbi.dss1_fck); + clk_put(rfbi.dss_ick); +} + +static void rfbi_enable_clocks(int enable) +{ + if (enable) { + clk_enable(rfbi.dss_ick); + clk_enable(rfbi.dss1_fck); + } else { + clk_disable(rfbi.dss1_fck); + clk_disable(rfbi.dss_ick); + } +} + + #ifdef VERBOSE static void rfbi_print_timings(void) { @@ -113,6 +149,7 @@ static void rfbi_set_timings(const struct extif_timings *t) BUG_ON(!t->converted); + rfbi_enable_clocks(1); rfbi_write_reg(RFBI_ONOFF_TIME0, t->tim[0]); rfbi_write_reg(RFBI_CYCLE_TIME0, t->tim[1]); @@ -122,6 +159,7 @@ static void rfbi_set_timings(const struct extif_timings *t) rfbi_write_reg(RFBI_CONFIG0, l); rfbi_print_timings(); + rfbi_enable_clocks(0); } static void rfbi_get_clk_info(u32 *clk_period, u32 *max_clk_div) @@ -233,6 +271,7 @@ static int rfbi_convert_timings(struct extif_timings *t) static void rfbi_write_command(const void *buf, unsigned int len) { + rfbi_enable_clocks(1); if (rfbi.bits_per_cycle == 16) { const u16 *w = buf; BUG_ON(len & 1); @@ -244,10 +283,12 @@ static void rfbi_write_command(const void *buf, unsigned int len) for (; len; len--) rfbi_write_reg(RFBI_CMD, *b++); } + rfbi_enable_clocks(0); } static void rfbi_read_data(void *buf, unsigned int len) { + rfbi_enable_clocks(1); if (rfbi.bits_per_cycle == 16) { u16 *w = buf; BUG_ON(len & ~1); @@ -263,10 +304,12 @@ static void rfbi_read_data(void *buf, unsigned int len) *b++ = rfbi_read_reg(RFBI_READ); } } + rfbi_enable_clocks(0); } static void rfbi_write_data(const void *buf, unsigned int len) { + rfbi_enable_clocks(1); if (rfbi.bits_per_cycle == 16) { const u16 *w = buf; BUG_ON(len & 1); @@ -278,6 +321,7 @@ static void rfbi_write_data(const void *buf, unsigned int len) for (; len; len--) rfbi_write_reg(RFBI_PARAM, *b++); } + rfbi_enable_clocks(0); } static void rfbi_transfer_area(int width, int height, @@ -287,6 +331,7 @@ static void rfbi_transfer_area(int width, int height, BUG_ON(callback == NULL); + rfbi_enable_clocks(1); omap_dispc_set_lcd_size(width, height); rfbi.lcdc_callback = callback; @@ -307,6 +352,7 @@ static inline void _stop_transfer(void) w = rfbi_read_reg(RFBI_CONTROL); rfbi_write_reg(RFBI_CONTROL, w & ~(1 << 0)); + rfbi_enable_clocks(0); } static void rfbi_dma_callback(void *data) @@ -319,6 +365,7 @@ static void rfbi_set_bits_per_cycle(int bpc) { u32 l; + rfbi_enable_clocks(1); l = rfbi_read_reg(RFBI_CONFIG0); l &= ~(0x03 << 0); switch (bpc) @@ -333,25 +380,22 @@ static void rfbi_set_bits_per_cycle(int bpc) } rfbi_write_reg(RFBI_CONFIG0, l); rfbi.bits_per_cycle = bpc; + rfbi_enable_clocks(0); } static int rfbi_init(struct omapfb_device *fbdev) { u32 l; int r; - struct clk *dss_ick; rfbi.fbdev = fbdev; rfbi.base = io_p2v(RFBI_BASE); - dss_ick = clk_get(NULL, "dss_ick"); - if (IS_ERR(dss_ick)) { - dev_err(fbdev->dev, "can't get dss_ick\n"); - return PTR_ERR(dss_ick); - } + if ((r = rfbi_get_clocks()) < 0) + return r; + rfbi_enable_clocks(1); - rfbi.l4_khz = clk_get_rate(dss_ick) / 1000; - clk_put(dss_ick); + rfbi.l4_khz = clk_get_rate(rfbi.dss_ick) / 1000; /* Reset */ rfbi_write_reg(RFBI_SYSCONFIG, 1 << 1); @@ -376,6 +420,7 @@ static int rfbi_init(struct omapfb_device *fbdev) if ((r = omap_dispc_request_irq(rfbi_dma_callback, NULL)) < 0) { dev_err(fbdev->dev, "can't get DISPC irq\n"); + rfbi_enable_clocks(0); return r; } @@ -383,12 +428,15 @@ static int rfbi_init(struct omapfb_device *fbdev) pr_info("omapfb: RFBI version %d.%d initialized\n", (l >> 4) & 0x0f, l & 0x0f); + rfbi_enable_clocks(0); + return 0; } static void rfbi_cleanup(void) { omap_dispc_free_irq(); + rfbi_put_clocks(); } const struct lcd_ctrl_extif omap2_ext_if = { -- 2.41.1