diff options
author | Ranjani Vaidyanathan <ra5478@freescale.com> | 2012-04-17 23:05:43 -0500 |
---|---|---|
committer | Ranjani Vaidyanathan <ra5478@freescale.com> | 2012-04-26 11:08:23 -0500 |
commit | bc7144148d171d00f406ccc98b8ee12bcda83f84 (patch) | |
tree | e36ded01865829f35b391b547d4b66e652a0f941 | |
parent | d602fc1b9692a2daf1e2503d392cbc8d00d595d8 (diff) |
ENGR00180185: MX6-Add support for low power audio playback
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>
-rw-r--r-- | arch/arm/mach-mx6/bus_freq.c | 33 | ||||
-rw-r--r-- | arch/arm/mach-mx6/clock.c | 6 | ||||
-rw-r--r-- | arch/arm/mach-mx6/mx6_ddr_freq.S | 6 | ||||
-rwxr-xr-x | arch/arm/plat-mxc/clock.c | 14 | ||||
-rwxr-xr-x | arch/arm/plat-mxc/include/mach/clock.h | 3 |
5 files changed, 49 insertions, 13 deletions
diff --git a/arch/arm/mach-mx6/bus_freq.c b/arch/arm/mach-mx6/bus_freq.c index e4244afe7ae7..75b9ebdcc7e3 100644 --- a/arch/arm/mach-mx6/bus_freq.c +++ b/arch/arm/mach-mx6/bus_freq.c @@ -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); diff --git a/arch/arm/mach-mx6/clock.c b/arch/arm/mach-mx6/clock.c index ce6de1e275f7..41b74f5bbfd2 100644 --- a/arch/arm/mach-mx6/clock.c +++ b/arch/arm/mach-mx6/clock.c @@ -47,7 +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 mx6q_revision(void); +extern int lp_audio_freq; void __iomem *apll_base; static struct clk pll1_sys_main_clk; @@ -2556,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) @@ -2629,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) @@ -2701,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, @@ -5302,6 +5305,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()) { diff --git a/arch/arm/mach-mx6/mx6_ddr_freq.S b/arch/arm/mach-mx6/mx6_ddr_freq.S index 766d867ee1c4..d73394dd3dc2 100644 --- a/arch/arm/mach-mx6/mx6_ddr_freq.S +++ b/arch/arm/mach-mx6/mx6_ddr_freq.S @@ -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: diff --git a/arch/arm/plat-mxc/clock.c b/arch/arm/plat-mxc/clock.c index f6e14a3cf2f5..43d33376b52d 100755 --- a/arch/arm/plat-mxc/clock.c +++ b/arch/arm/plat-mxc/clock.c @@ -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); diff --git a/arch/arm/plat-mxc/include/mach/clock.h b/arch/arm/plat-mxc/include/mach/clock.h index a66b0018c944..e150579e5ced 100755 --- a/arch/arm/plat-mxc/include/mach/clock.h +++ b/arch/arm/plat-mxc/include/mach/clock.h @@ -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); |