summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRanjani Vaidyanathan <ra5478@freescale.com>2012-04-17 23:05:43 -0500
committerRanjani Vaidyanathan <ra5478@freescale.com>2012-04-26 11:08:23 -0500
commitbc7144148d171d00f406ccc98b8ee12bcda83f84 (patch)
treee36ded01865829f35b391b547d4b66e652a0f941
parentd602fc1b9692a2daf1e2503d392cbc8d00d595d8 (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.c33
-rw-r--r--arch/arm/mach-mx6/clock.c6
-rw-r--r--arch/arm/mach-mx6/mx6_ddr_freq.S6
-rwxr-xr-xarch/arm/plat-mxc/clock.c14
-rwxr-xr-xarch/arm/plat-mxc/include/mach/clock.h3
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);