]> pilppa.com Git - linux-2.6-omap-h63xx.git/commitdiff
ARM: OMAP2: fb: clock refcounting for dynamic sleep mode
authorImre Deak <imre.deak@solidboot.com>
Thu, 14 Sep 2006 11:13:30 +0000 (14:13 +0300)
committerJuha Yrjola <juha.yrjola@solidboot.com>
Thu, 14 Sep 2006 12:21:03 +0000 (15:21 +0300)
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 <imre.deak@solidboot.com>
Signed-off-by: Juha Yrjola <juha.yrjola@solidboot.com>
drivers/video/omap/dispc.c
drivers/video/omap/rfbi.c

index c7bd1e0c73cb1cfe9df0c3c51d7de7876e45a737..ecc785d362ce75013303ba37d7e2c554dfe56e65 100644 (file)
@@ -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();
 }
 
index 5347e9b9d22d29185ba8a8e606f06eb690fbde5b..ebb317623b56e4f09e0328e6a5adb73a20ff8262 100644 (file)
@@ -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 = {