]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
ENGR00180185: MX6-Add support for low power audio playback
authorRanjani Vaidyanathan <ra5478@freescale.com>
Wed, 18 Apr 2012 04:05:43 +0000 (23:05 -0500)
committerLothar Waßmann <LW@KARO-electronics.de>
Fri, 24 May 2013 06:34:29 +0000 (08:34 +0200)
The DDR frequency needs to be at 50MHz for low power audio
playback. So added a new low power mode for audio.
Set the AHB to 25MHz, AXI to 50MHz and DDR to 50MHz in this
mode.

Signed-off-by: Ranjani Vaidyanathan <ra5478@freescale.com>
arch/arm/mach-mx6/bus_freq.c
arch/arm/mach-mx6/clock.c
arch/arm/mach-mx6/mx6_ddr_freq.S
arch/arm/plat-mxc/clock.c
arch/arm/plat-mxc/include/mach/clock.h

index e4244afe7ae748c19f7974df356f3287a74b60f3..75b9ebdcc7e3197289031ec96ee82eed8dd1dc9a 100644 (file)
@@ -53,6 +53,7 @@
 DEFINE_SPINLOCK(ddr_freq_lock);
 
 int low_bus_freq_mode;
+int audio_bus_freq_mode;
 int high_bus_freq_mode;
 int med_bus_freq_mode;
 
@@ -65,6 +66,7 @@ int bus_freq_scaling_is_active;
 
 int lp_high_freq;
 int lp_med_freq;
+int lp_audio_freq;
 unsigned int ddr_low_rate;
 unsigned int ddr_med_rate;
 unsigned int ddr_normal_rate;
@@ -97,6 +99,9 @@ static void reduce_bus_freq_handler(struct work_struct *work)
        if (low_bus_freq_mode || !low_freq_bus_used())
                return;
 
+       if (audio_bus_freq_mode && lp_audio_freq)
+               return;
+
        while (!mutex_trylock(&bus_freq_mutex))
                msleep(1);
 
@@ -106,15 +111,29 @@ static void reduce_bus_freq_handler(struct work_struct *work)
                mutex_unlock(&bus_freq_mutex);
                return;
        }
-       clk_enable(pll3);
-
+       if (audio_bus_freq_mode && lp_audio_freq) {
+               mutex_unlock(&bus_freq_mutex);
+               return;
+       }
 
-       update_ddr_freq(24000000);
+       clk_enable(pll3);
 
+       if (lp_audio_freq) {
+               /* Need to ensure that PLL2_PFD_400M is kept ON. */
+               clk_enable(pll2_400);
+               update_ddr_freq(50000000);
+               audio_bus_freq_mode = 1;
+               low_bus_freq_mode = 0;
+       } else {
+               update_ddr_freq(24000000);
+               if (audio_bus_freq_mode)
+                       clk_disable(pll2_400);
+               low_bus_freq_mode = 1;
+               audio_bus_freq_mode = 0;
+       }
        if (med_bus_freq_mode)
                clk_disable(pll2_400);
 
-       low_bus_freq_mode = 1;
        high_bus_freq_mode = 0;
        med_bus_freq_mode = 0;
 
@@ -183,16 +202,18 @@ int set_high_bus_freq(int high_bus_freq)
                update_ddr_freq(ddr_normal_rate);
                if (med_bus_freq_mode)
                        clk_disable(pll2_400);
-               low_bus_freq_mode = 0;
                high_bus_freq_mode = 1;
                med_bus_freq_mode = 0;
        } else {
                clk_enable(pll2_400);
                update_ddr_freq(ddr_med_rate);
-               low_bus_freq_mode = 0;
                high_bus_freq_mode = 0;
                med_bus_freq_mode = 1;
        }
+       if (audio_bus_freq_mode)
+               clk_disable(pll2_400);
+       low_bus_freq_mode = 0;
+       audio_bus_freq_mode = 0;
 
        mutex_unlock(&bus_freq_mutex);
        clk_disable(pll3);
index 259ebac1d5cd283674ed9bbe57f8f0ae63d7d86a..7ee0f3e9c6435a020ea40601c8e402da7f34348c 100644 (file)
@@ -47,6 +47,7 @@ extern struct regulator *cpu_regulator;
 extern struct cpu_op *(*get_cpu_op)(int *op);
 extern int lp_high_freq;
 extern int lp_med_freq;
+extern int lp_audio_freq;
 
 void __iomem *apll_base;
 static struct clk pll1_sys_main_clk;
@@ -2555,6 +2556,7 @@ static struct clk ssi1_clk = {
 #else
         .secondary = &mmdc_ch0_axi_clk[0],
 #endif
+       .flags  = AHB_AUDIO_SET_POINT | CPU_FREQ_TRIG_UPDATE,
 };
 
 static unsigned long _clk_ssi2_get_rate(struct clk *clk)
@@ -2628,6 +2630,7 @@ static struct clk ssi2_clk = {
 #else
         .secondary = &mmdc_ch0_axi_clk[0],
 #endif
+       .flags  = AHB_AUDIO_SET_POINT | CPU_FREQ_TRIG_UPDATE,
 };
 
 static unsigned long _clk_ssi3_get_rate(struct clk *clk)
@@ -2700,6 +2703,7 @@ static struct clk ssi3_clk = {
 #else
         .secondary = &mmdc_ch0_axi_clk[0],
 #endif
+       .flags  = AHB_AUDIO_SET_POINT | CPU_FREQ_TRIG_UPDATE,
 };
 
 static unsigned long _clk_ldb_di_round_rate(struct clk *clk,
@@ -5342,6 +5346,7 @@ int __init mx6_clocks_init(unsigned long ckil, unsigned long osc,
 
        lp_high_freq = 0;
        lp_med_freq = 0;
+       lp_audio_freq = 0;
 
        /* Turn OFF all unnecessary PHYs. */
        if (cpu_is_mx6q()) {
index 766d867ee1c4003e1a1a00e4090b37be14b66336..d73394dd3dc2ca8d0e8496e76e165d3b5a05c208 100644 (file)
@@ -191,16 +191,16 @@ switch_pre_periph_clk_50:
        orr     r0, r0, #0xC0000
        str     r0, [r6, #0x18]
 
-       /* Set the MMDC_DIV=4, AXI_DIV = 4, AHB_DIV=6 (need to maintain GPT divider). */
+       /* Set the MMDC_DIV=4, AXI_DIV = 4, AHB_DIV=8 (need to maintain GPT divider). */
        ldr     r0, [r6, #0x14]
        ldr     r2, =0x3F1C00
        bic     r0, r0, r2
 
        orr     r0, r0, #0x180000
-       orr     r0, r0, #0x10000
+       orr     r0, r0, #0x30000
 
        /* If changing AHB divider remember to change the IPGPER divider too below. */
-        orr     r0, r0, #0xC00
+        orr     r0, r0, #0x1C00
         str     r0, [r6, #0x14]
 
 wait_div_update_50:
index f6e14a3cf2f5f0a72b270495e5e2040a86f0907a..43d33376b52ddf11ba04e140a67549bf3e19c1a6 100755 (executable)
@@ -47,6 +47,8 @@
 extern int dvfs_core_is_active;
 extern int lp_high_freq;
 extern int lp_med_freq;
+extern int lp_audio_freq;
+extern int audio_bus_freq_mode;
 extern int low_bus_freq_mode;
 extern int high_bus_freq_mode;
 extern int med_bus_freq_mode;
@@ -115,13 +117,19 @@ int clk_enable(struct clk *clk)
                lp_high_freq++;
        else if (clk->flags & AHB_MED_SET_POINT)
                lp_med_freq++;
+       else if (clk->flags & AHB_AUDIO_SET_POINT)
+               lp_audio_freq++;
 
        if ((clk->flags & CPU_FREQ_TRIG_UPDATE)
                        && (clk_get_usecount(clk) == 0)) {
                if (!(clk->flags &
                        (AHB_HIGH_SET_POINT | AHB_MED_SET_POINT)))  {
-                       if (low_freq_bus_used() && !low_bus_freq_mode)
-                               set_low_bus_freq();
+                       if (low_freq_bus_used()) {
+                               if ((clk->flags & AHB_AUDIO_SET_POINT) & !audio_bus_freq_mode)
+                                       set_low_bus_freq();
+                               else if (!low_bus_freq_mode)
+                                       set_low_bus_freq();
+                       }
                } else {
                        if ((clk->flags & AHB_MED_SET_POINT)
                                && !med_bus_freq_mode)
@@ -164,6 +172,8 @@ void clk_disable(struct clk *clk)
                lp_high_freq--;
        else if (clk->flags & AHB_MED_SET_POINT)
                lp_med_freq--;
+       else if (clk->flags & AHB_AUDIO_SET_POINT)
+               lp_audio_freq--;
 
        mutex_lock(&clocks_mutex);
        __clk_disable(clk);
index a66b0018c94449c515455404e2ab5bcfb8063a89..e150579e5cedd9015abaeff1f792da8e8b0b07c2 100755 (executable)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2005-2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2005-2012 Freescale Semiconductor, Inc.
  * Copyright 2008 Juergen Beisert, kernel@pengutronix.de
  *
  * This program is free software; you can redistribute it and/or
@@ -71,6 +71,7 @@ int clk_get_usecount(struct clk *clk);
 #define CPU_FREQ_TRIG_UPDATE   (1 << 3)        /* CPUFREQ trig update */
 #define AHB_HIGH_SET_POINT     (1 << 4)        /* Requires max AHB clock */
 #define AHB_MED_SET_POINT      (1 << 5)        /* Requires med AHB clock */
+#define AHB_AUDIO_SET_POINT    (1 << 6)        /* Requires LOW AHB, but higher DDR clock */
 
 unsigned long mxc_decode_pll(unsigned int pll, u32 f_ref);