summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/arm/configs/imx6s_defconfig1
-rwxr-xr-xarch/arm/mach-mx6/board-mx6sl_arm2.c4
-rw-r--r--arch/arm/mach-mx6/board-mx6sl_evk.c12
-rw-r--r--arch/arm/mach-mx6/bus_freq.c13
-rwxr-xr-xarch/arm/mach-mx6/clock_mx6sl.c82
-rw-r--r--arch/arm/mach-mx6/mx6sl_ddr.S53
-rw-r--r--arch/arm/mach-mx6/mx6sl_wfi.S71
-rw-r--r--arch/arm/mach-mx6/system.c10
8 files changed, 183 insertions, 63 deletions
diff --git a/arch/arm/configs/imx6s_defconfig b/arch/arm/configs/imx6s_defconfig
index 7620cab69c61..17440cee6911 100644
--- a/arch/arm/configs/imx6s_defconfig
+++ b/arch/arm/configs/imx6s_defconfig
@@ -1818,6 +1818,7 @@ CONFIG_SND_SOC=y
CONFIG_SND_SOC_AC97_BUS=y
CONFIG_SND_IMX_SOC=y
CONFIG_SND_MXC_SOC_MX2=y
+CONFIG_SND_MXC_SOC_IRAM=y
CONFIG_SND_MXC_SOC_SPDIF_DAI=y
CONFIG_SND_SOC_IMX_SGTL5000=y
CONFIG_SND_SOC_IMX_WM8958=y
diff --git a/arch/arm/mach-mx6/board-mx6sl_arm2.c b/arch/arm/mach-mx6/board-mx6sl_arm2.c
index 66868c614e82..b6f3382c00cf 100755
--- a/arch/arm/mach-mx6/board-mx6sl_arm2.c
+++ b/arch/arm/mach-mx6/board-mx6sl_arm2.c
@@ -484,8 +484,8 @@ static int mxc_wm8962_init(void)
clk_set_parent(extern_audio_root, pll4);
- rate = clk_round_rate(extern_audio_root, 26000000);
- clk_set_rate(extern_audio_root, rate);
+ rate = 24000000;
+ clk_set_rate(extern_audio_root, 24000000);
wm8962_data.sysclk = rate;
diff --git a/arch/arm/mach-mx6/board-mx6sl_evk.c b/arch/arm/mach-mx6/board-mx6sl_evk.c
index a2dfd4109977..3ae48c6e6d10 100644
--- a/arch/arm/mach-mx6/board-mx6sl_evk.c
+++ b/arch/arm/mach-mx6/board-mx6sl_evk.c
@@ -539,8 +539,16 @@ static int mxc_wm8962_init(void)
return PTR_ERR(extern_audio_root);
}
- rate = clk_round_rate(extern_audio_root, 24000000);
- clk_set_rate(extern_audio_root, rate);
+ pll4 = clk_get(NULL, "pll4");
+ if (IS_ERR(pll4)) {
+ pr_err("can't get pll4 clock.\n");
+ return PTR_ERR(pll4);
+ }
+
+ clk_set_parent(extern_audio_root, pll4);
+
+ rate = 24000000;
+ clk_set_rate(extern_audio_root, 24000000);
wm8962_data.sysclk = rate;
/* set AUDMUX pads to 1.8v */
diff --git a/arch/arm/mach-mx6/bus_freq.c b/arch/arm/mach-mx6/bus_freq.c
index 1f429f9e0656..ba2636785232 100644
--- a/arch/arm/mach-mx6/bus_freq.c
+++ b/arch/arm/mach-mx6/bus_freq.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011-2012 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright (C) 2011-2013 Freescale Semiconductor, Inc. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -47,7 +47,7 @@
#include <linux/suspend.h>
#define LPAPM_CLK 24000000
-#define DDR_AUDIO_CLK 50000000
+#define DDR_AUDIO_CLK 100000000
#define DDR_MED_CLK 400000000
#define DDR3_NORMAL_CLK 528000000
#define GPC_PGC_GPU_PGCR_OFFSET 0x260
@@ -78,7 +78,8 @@ unsigned int ddr_normal_rate;
int low_freq_bus_used(void);
void set_ddr_freq(int ddr_freq);
void *mx6sl_wfi_iram_base;
-void (*mx6sl_wfi_iram)(int arm_podf, unsigned long wfi_iram_addr) = NULL;
+void (*mx6sl_wfi_iram)(int arm_podf, unsigned long wfi_iram_addr,\
+ int audio_mode) = NULL;
extern void mx6sl_wait (int arm_podf, unsigned long wfi_iram_addr);
void *mx6sl_ddr_freq_base;
@@ -169,6 +170,10 @@ void reduce_bus_freq(void)
/* PLL2 is on in this mode, as DDR is at 50MHz. */
/* Now change DDR freq while running from IRAM. */
+ /* Set AHB to 24MHz. */
+ clk_set_rate(ahb_clk,
+ clk_round_rate(ahb_clk, LPAPM_CLK / 3));
+
spin_lock_irqsave(&freq_lock, flags);
mx6sl_ddr_freq_change_iram(DDR_AUDIO_CLK,
low_bus_freq_mode);
@@ -269,7 +274,7 @@ int set_low_bus_freq(void)
if (!bus_freq_scaling_initialized || !bus_freq_scaling_is_active)
return 0;
- /* Check to see if we need to got from
+ /* Check to see if we need to get from
* low bus freq mode to audio bus freq mode.
* If so, the change needs to be done immediately.
*/
diff --git a/arch/arm/mach-mx6/clock_mx6sl.c b/arch/arm/mach-mx6/clock_mx6sl.c
index c6b08cbce8cb..65ea38f6d872 100755
--- a/arch/arm/mach-mx6/clock_mx6sl.c
+++ b/arch/arm/mach-mx6/clock_mx6sl.c
@@ -73,6 +73,7 @@ static struct cpu_op *cpu_op_tbl;
static int cpu_op_nr;
static bool pll1_enabled;
static bool arm_needs_pll2_400;
+static bool audio_pll_bypass;
DEFINE_SPINLOCK(mx6sl_clk_lock);
#define SPIN_DELAY 1200000 /* in nanoseconds */
@@ -429,7 +430,8 @@ static int _clk_pll_enable(struct clk *clk)
pllbase = _get_pll_base(clk);
reg = __raw_readl(pllbase);
- reg &= ~ANADIG_PLL_POWER_DOWN;
+ if (clk != &pll4_audio_main_clk || !audio_pll_bypass)
+ reg &= ~ANADIG_PLL_POWER_DOWN;
/* The 480MHz PLLs have the opposite definition for power bit. */
if (clk == &pll3_usb_otg_main_clk || clk == &pll7_usb_host_main_clk)
@@ -442,14 +444,18 @@ static int _clk_pll_enable(struct clk *clk)
__raw_writel(BM_ANADIG_ANA_MISC2_CONTROL0, apll_base + HW_ANADIG_ANA_MISC2_CLR);
/* Wait for PLL to lock */
- if (!WAIT((__raw_readl(pllbase) & ANADIG_PLL_LOCK),
- SPIN_DELAY))
- panic("pll enable failed\n");
-
+ if (clk != &pll4_audio_main_clk || !audio_pll_bypass) {
+ if (!WAIT((__raw_readl(pllbase) & ANADIG_PLL_LOCK),
+ SPIN_DELAY))
+ panic("pll enable failed\n");
+ }
/* Enable the PLL output now*/
reg = __raw_readl(pllbase);
- reg &= ~ANADIG_PLL_BYPASS;
- reg |= ANADIG_PLL_ENABLE;
+ if (clk != &pll4_audio_main_clk || !audio_pll_bypass)
+ reg &= ~ANADIG_PLL_BYPASS;
+ else
+ reg |= ANADIG_PLL_ENABLE;
+
__raw_writel(reg, pllbase);
return 0;
@@ -874,6 +880,9 @@ static unsigned long _clk_audio_video_get_rate(struct clk *clk)
pllbase = _get_pll_base(clk);
+ if (__raw_readl(pllbase) & ANADIG_PLL_BYPASS)
+ return 24000000;
+
test_div_sel = (__raw_readl(pllbase)
& ANADIG_PLL_AV_TEST_DIV_SEL_MASK)
>> ANADIG_PLL_AV_TEST_DIV_SEL_OFFSET;
@@ -917,6 +926,16 @@ static int _clk_audio_video_set_rate(struct clk *clk, unsigned long rate)
u32 test_div_sel = 2;
u32 control3 = 0;
+ pllbase = _get_pll_base(clk);
+
+ if (clk == &pll4_audio_main_clk && audio_pll_bypass) {
+ reg = __raw_readl(pllbase)
+ & ~ANADIG_PLL_SYS_DIV_SELECT_MASK
+ & ~ANADIG_PLL_AV_TEST_DIV_SEL_MASK;
+ __raw_writel(reg, pllbase);
+ return 0;
+ }
+
if (clk == &pll4_audio_main_clk)
min_clk_rate = AUDIO_VIDEO_MIN_CLK_FREQ / 4;
else
@@ -925,8 +944,6 @@ static int _clk_audio_video_set_rate(struct clk *clk, unsigned long rate)
if ((rate < min_clk_rate) || (rate > AUDIO_VIDEO_MAX_CLK_FREQ))
return -EINVAL;
- pllbase = _get_pll_base(clk);
-
pre_div_rate = rate;
while (pre_div_rate < AUDIO_VIDEO_MIN_CLK_FREQ) {
pre_div_rate *= 2;
@@ -986,6 +1003,9 @@ static unsigned long _clk_audio_video_round_rate(struct clk *clk,
u32 control3 = 0;
unsigned long final_rate;
+ if (clk == &pll4_audio_main_clk && audio_pll_bypass)
+ return 24000000;
+
if (clk == &pll4_audio_main_clk)
min_clk_rate = AUDIO_VIDEO_MIN_CLK_FREQ / 4;
else
@@ -2376,14 +2396,23 @@ static int _clk_extern_audio_set_rate(struct clk *clk, unsigned long rate)
u32 reg, div, pre, post;
u32 parent_rate = clk_get_rate(clk->parent);
- div = parent_rate / rate;
- if (div == 0)
- div++;
- if (((parent_rate / div) != rate) || div > 64)
- return -EINVAL;
+ if (rate == 24000000 && clk->parent == &pll4_audio_main_clk) {
+ /* If the requested rate is 24MHz,
+ * set the PLL4 to bypass mode.
+ */
+ audio_pll_bypass = 1;
+ pre = post = 1;
+ } else {
+ div = parent_rate / rate;
+ if (div == 0)
+ div++;
+ if (((parent_rate / div) != rate) || div > 64)
+ return -EINVAL;
- __calc_pre_post_dividers(1 << 3, div, &pre, &post);
+ audio_pll_bypass = 0;
+ __calc_pre_post_dividers(1 << 3, div, &pre, &post);
+ }
reg = __raw_readl(MXC_CCM_CS1CDR);
reg &= ~(MXC_CCM_CS1CDR_ESAI_CLK_PRED_MASK|
MXC_CCM_CS1CDR_ESAI_CLK_PODF_MASK);
@@ -2442,15 +2471,10 @@ static struct clk ssi1_clk[] = {
.flags = AHB_AUDIO_SET_POINT | CPU_FREQ_TRIG_UPDATE,
#ifndef CONFIG_SND_MXC_SOC_IRAM
.secondary = &mmdc_ch1_axi_clk[0],
- },
#else
- .secondary = &ssi1_clk[1],
- },
- {
- .parent = &mmdc_ch1_axi_clk[0],
.secondary = &ocram_clk,
- },
#endif
+ },
};
static unsigned long _clk_ssi2_get_rate(struct clk *clk)
@@ -2523,15 +2547,10 @@ static struct clk ssi2_clk[] = {
.flags = AHB_AUDIO_SET_POINT | CPU_FREQ_TRIG_UPDATE,
#ifndef CONFIG_SND_MXC_SOC_IRAM
.secondary = &mmdc_ch1_axi_clk[0],
- },
#else
- .secondary = &ssi2_clk[1],
- },
- {
- .parent = &mmdc_ch1_axi_clk[0],
.secondary = &ocram_clk,
- },
#endif
+ },
};
static unsigned long _clk_ssi3_get_rate(struct clk *clk)
@@ -2603,15 +2622,10 @@ static struct clk ssi3_clk[] = {
.flags = AHB_AUDIO_SET_POINT | CPU_FREQ_TRIG_UPDATE,
#ifndef CONFIG_SND_MXC_SOC_IRAM
.secondary = &mmdc_ch1_axi_clk[0],
- },
#else
- .secondary = &ssi3_clk[1],
- },
- {
- .parent = &mmdc_ch1_axi_clk[0],
.secondary = &ocram_clk,
- },
#endif
+ },
};
static unsigned long _clk_epdc_lcdif_pix_round_rate(struct clk *clk,
@@ -4118,6 +4132,8 @@ int __init mx6sl_clocks_init(unsigned long ckil, unsigned long osc,
/* lcdif pix - PLL5 as parent */
clk_set_parent(&lcdif_pix_clk, &pll5_video_main_clk);
+ clk_set_parent(&ssi2_clk[0], &pll4_audio_main_clk);
+
lp_high_freq = 0;
lp_med_freq = 0;
diff --git a/arch/arm/mach-mx6/mx6sl_ddr.S b/arch/arm/mach-mx6/mx6sl_ddr.S
index 1567f724c2bb..9e83985ed0f8 100644
--- a/arch/arm/mach-mx6/mx6sl_ddr.S
+++ b/arch/arm/mach-mx6/mx6sl_ddr.S
@@ -116,13 +116,6 @@ mmdc_podf0:
.macro ddr_switch_400MHz
- /* Check if we are switching between
- * 400Mhz <-> 50MHz. If so, we only need to
- * update MMDC divider.
- */
- cmp r1, #0
- beq change_divider_only
-
/* Set MMDC divider first, in case PLL3 is at 480MHz. */
ldr r6, [r3, #0x10]
and r6, r6, #0x10000
@@ -141,6 +134,13 @@ mmdc_podf:
pll3_in_bypass:
+ /* Check if we are switching between
+ * 400Mhz <-> 100MHz.If so, we should
+ * try to source MMDC from PLL2_200M.
+ */
+ cmp r1, #0
+ beq not_low_bus_freq
+
/* Ensure that MMDC is sourced from PLL2 mux first. */
ldr r6, [r2, #0x14]
bic r6, r6, #0x4000000
@@ -151,6 +151,7 @@ periph2_clk_switch4:
cmp r6, #0
bne periph2_clk_switch4
+not_low_bus_freq:
/* Now ensure periph2_clk2_sel mux is set to PLL3 */
ldr r6, [r2, #0x18]
bic r6, r6, #0x100000
@@ -166,6 +167,12 @@ periph2_clk_switch5:
cmp r6, #0
bne periph2_clk_switch5
+ /* Check if PLL2 is already unlocked.
+ * If so do nothing with PLL2.
+ */
+ cmp r1, #0
+ beq pll2_already_on
+
/* Now power up PLL2 and unbypass it. */
ldr r6, [r3, #0x30]
bic r6, r6, #0x1000
@@ -192,27 +199,43 @@ wait_for_pll_lock:
bic r6, r6, #0x800000
str r6, [r3, #0x100]
+pll2_already_on:
/* Now switch MMDC clk back to pll2_mux option. */
/* Ensure pre_periph2_clk2 is set to pll2_pfd_400M */
+ /* If switching to audio DDR freq, set the
+ * pre_periph2_clk2 to PLL2_PFD_200M
+ */
+ ldr r6, =400000000
+ cmp r6, r0
+ bne use_pll2_pfd_200M
+
ldr r6, [r2, #0x18]
bic r6, r6, #0x600000
orr r6, r6, #0x200000
str r6, [r2, #0x18]
+ ldr r6, =400000000
+ b cont2
- ldr r6, [r2, #0x14]
- bic r6, r6, #0x4000000
- str r6, [r2, #0x14]
+use_pll2_pfd_200M:
+ ldr r6, [r2, #0x18]
+ orr r6, r6, #0x600000
+ str r6, [r2, #0x18]
+ ldr r6, =200000000
+
+cont2:
+ ldr r4, [r2, #0x14]
+ bic r4, r4, #0x4000000
+ str r4, [r2, #0x14]
periph2_clk_switch6:
- ldr r6, [r2, #0x48]
- cmp r6, #0
+ ldr r4, [r2, #0x48]
+ cmp r4, #0
bne periph2_clk_switch6
change_divider_only:
/* Calculate the MMDC divider
* based on the requested freq.
*/
- ldr r6, =400000000
ldr r4, =0
Loop2:
sub r6, r6, r0
@@ -306,7 +329,7 @@ force_measure1:
*/
ENTRY(mx6sl_ddr_iram)
- push {r4, r5, r6, r7, r8, r9, r10 }
+ push {r4-r10}
mx6sl_ddr_freq_change:
ldr r3, =ANATOP_BASE_ADDR
@@ -436,7 +459,7 @@ skip_power_down:
bic r6, r6, #0x100
str r6, [r8, #0x410]
- pop {r4,r5, r6, r7, r8, r9, r10}
+ pop {r4-r10}
/* Restore registers */
mov pc, lr
diff --git a/arch/arm/mach-mx6/mx6sl_wfi.S b/arch/arm/mach-mx6/mx6sl_wfi.S
index 7ee467025e2a..bd5a00c67828 100644
--- a/arch/arm/mach-mx6/mx6sl_wfi.S
+++ b/arch/arm/mach-mx6/mx6sl_wfi.S
@@ -158,9 +158,11 @@ fifo_reset2_wait:
*/
ENTRY(mx6sl_wait)
- push {r4, r5, r6, r7, r8, r9, r10}
+ push {r4-r11}
mx6sl_lpm_wfi:
+ mov r11, r2
+
/* Get the IRAM data storage address. */
mov r10, r1
mov r9, r1 /* get suspend_iram_base */
@@ -231,6 +233,9 @@ poll_dvfs_set_1:
orr r6, r6, #0x100
str r6, [r8, #0x410]
+ cmp r11, #1
+ beq audio_mode
+
/* Now set DDR rate to 1MHz. */
/* DDR is from bypassed PLL2 on periph2_clk2 path.
* Set the periph2_clk2_podf to divide by 8.
@@ -244,6 +249,15 @@ poll_dvfs_set_1:
bic r6, r6, #0x38
orr r6, r6, #0x10
str r6, [r2, #0x14]
+ b mmdc_podf
+
+audio_mode:
+ /* MMDC is from PLL2_200M.
+ * Set the mmdc_podf to div by 8.
+ */
+ ldr r6, [r2, #0x14]
+ orr r6, r6, #0x38
+ str r6, [r2, #0x14]
/* Loop till podf is accepted. */
mmdc_podf:
@@ -254,6 +268,9 @@ mmdc_podf:
/* Set the DDR IO in LPM state. */
sl_ddr_io_set_lpm
+ cmp r11, #1
+ beq do_audio_arm_clk
+
/* Check if none of the PLLs are
* locked, except PLL1 which will get
* bypassed below.
@@ -394,6 +411,30 @@ podf_loop:
orr r6, r6, #0x1
str r6, [r3, #0x150]
+ b do_wfi
+
+do_audio_arm_clk:
+ /* ARM is from PLL2_PFD2_400M here.
+ * Switch ARM to bypassed PLL1.
+ */
+ ldr r6, [r2, #0xC]
+ bic r6, r6, #0x4
+ str r6, [r2, #0xC]
+
+ /* Set the ARM_PODF to divide by 2
+ * as IPG is at 4MHz, we cannot run
+ * ARM_CLK above 9.6MHz when
+ * system enters WAIT mode.
+ */
+ ldr r6, =0x2
+ str r6, [r2, #0x10]
+
+ /* Loop till podf is accepted. */
+podf_loop_audio:
+ ldr r6, [r2, #0x48]
+ cmp r6, #0x0
+ bne podf_loop_audio
+
do_wfi:
/* Now do WFI. */
wfi
@@ -407,6 +448,9 @@ podf_loop1:
cmp r6, #0x0
bne podf_loop1
+ cmp r11, #1
+ beq audio_arm_clk_restore
+
/* Check if powered down
* analog components.
*/
@@ -489,12 +533,24 @@ ahb_podf1:
cmp r6, #0x0
bne podf_loop1
- mov r9, r10 /* get suspend_iram_base */
+ b wfi_restore
+
+audio_arm_clk_restore:
+ /* Move ARM back to PLL2_PFD2_400M */
+ ldr r6, [r2, #0xC]
+ orr r6, r6, #0x4
+ str r6, [r2, #0xC]
+
+wfi_restore:
+ mov r9, r10 /* get suspend_iram_base */
add r9, r9, #IRAM_WAIT_SIZE /* 4K */
/* Restore the DDR IO before exiting self-refresh. */
sl_ddr_io_restore
+ cmp r11, #1
+ beq mmdc_audio_restore
+
/* Set MMDC back to 24MHz. */
/* Set periph2_clk2_podf to divide by 1. */
/* Now set MMDC PODF to divide by 1. */
@@ -502,6 +558,15 @@ ahb_podf1:
bic r6, r6, #0x3f
str r6, [r2, #0x14]
+ b mmdc_podf1
+
+mmdc_audio_restore:
+ /* Set MMDC back to 100MHz. */
+ ldr r6, [r2, #0x14]
+ bic r6, r6, #0x38
+ orr r6, r6, #0x8
+ str r6, [r2, $0x14]
+
mmdc_podf1:
ldr r6, [r2, #0x48]
cmp r6, #0x0
@@ -565,7 +630,7 @@ poll_dvfs_clear_1:
str r6, [r8, #0x410]
- pop {r4,r5, r6, r7, r8, r9, r10}
+ pop {r4-r11}
/* Restore registers */
mov pc, lr
diff --git a/arch/arm/mach-mx6/system.c b/arch/arm/mach-mx6/system.c
index 11038d66caaf..f1c2e2927362 100644
--- a/arch/arm/mach-mx6/system.c
+++ b/arch/arm/mach-mx6/system.c
@@ -61,7 +61,8 @@ bool enet_is_active;
void arch_idle_with_workaround(int cpu);
extern void *mx6sl_wfi_iram_base;
-extern void (*mx6sl_wfi_iram)(int arm_podf, unsigned long wfi_iram_addr);
+extern void (*mx6sl_wfi_iram)(int arm_podf, unsigned long wfi_iram_addr, \
+ int audio_mode);
extern void mx6_wait(void *num_cpu_idle_lock, void *num_cpu_idle, \
int wait_arm_podf, int cur_arm_podf);
extern bool enable_wait_mode;
@@ -276,8 +277,8 @@ void arch_idle_single_core(void)
if ((mmdc_ch0_axi != NULL))
ddr_usecount = clk_get_usecount(mmdc_ch0_axi);
- if (cpu_is_mx6sl() && low_bus_freq_mode
- && ddr_usecount == 1) {
+ if (cpu_is_mx6sl() && (ddr_usecount == 1) &&
+ (low_bus_freq_mode || audio_bus_freq_mode)) {
/* In this mode PLL2 i already in bypass,
* ARM is sourced from PLL1. The code in IRAM
* will set ARM to be sourced from STEP_CLK
@@ -290,7 +291,8 @@ void arch_idle_single_core(void)
* we can lower DDR freq.
*/
mx6sl_wfi_iram(org_arm_podf,
- (unsigned long)mx6sl_wfi_iram_base);
+ (unsigned long)mx6sl_wfi_iram_base,
+ audio_bus_freq_mode);
} else {
/* Need to set ARM to run at 24MHz since IPG
* is at 12MHz. This is valid for audio mode on