summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRanjani Vaidyanathan <ra5478@freescale.com>2012-08-22 13:26:11 -0500
committerRanjani Vaidyanathan <ra5478@freescale.com>2012-08-26 14:57:13 -0500
commitd3f7f366becf5e31225dbe1aaceef84813f7ccb8 (patch)
treeb04618dfc6168ea7563cd5d260407fc26df43ec5
parentdf63a57d034f77674d2fce9949f0eef6570e02f0 (diff)
ENGR00221161 [MX6SL]- Add audio bus freq mode support.
Set DDR to 50MHz in low power audio playback. AHB/AXI are at 24MHz. Also fix correct usecount for PLL1 main clock. If not it causes issues when pll1_sw_clk's parent is changed. Signed-off-by: Ranjani Vaidyanathan <ra5478@freescale.com>
-rw-r--r--arch/arm/mach-mx6/bus_freq.c101
-rwxr-xr-xarch/arm/mach-mx6/clock_mx6sl.c7
-rw-r--r--arch/arm/mach-mx6/mx6sl_ddr.S156
-rw-r--r--arch/arm/mach-mx6/mx6sl_wfi.S22
-rw-r--r--arch/arm/mach-mx6/system.c40
5 files changed, 231 insertions, 95 deletions
diff --git a/arch/arm/mach-mx6/bus_freq.c b/arch/arm/mach-mx6/bus_freq.c
index 53a65fb893f6..8c04e51d8827 100644
--- a/arch/arm/mach-mx6/bus_freq.c
+++ b/arch/arm/mach-mx6/bus_freq.c
@@ -47,6 +47,7 @@
#include <linux/suspend.h>
#define LPAPM_CLK 24000000
+#define DDR_AUDIO_CLK 50000000
#define DDR_MED_CLK 400000000
#define DDR3_NORMAL_CLK 528000000
#define GPC_PGC_GPU_PGCR_OFFSET 0x260
@@ -81,7 +82,7 @@ void (*mx6sl_wfi_iram)(int arm_podf, unsigned long wfi_iram_addr) = NULL;
extern void mx6sl_wait (int arm_podf, unsigned long wfi_iram_addr);
void *mx6sl_ddr_freq_base;
-void (*mx6sl_ddr_freq_change_iram)(int ddr_freq) = NULL;
+void (*mx6sl_ddr_freq_change_iram)(int ddr_freq, int low_bus_freq_mode) = NULL;
extern void mx6sl_ddr_iram(int ddr_freq);
extern int init_mmdc_settings(void);
@@ -140,13 +141,13 @@ static void reduce_bus_freq_handler(struct work_struct *work)
if (lp_audio_freq) {
/* Need to ensure that PLL2_PFD_400M is kept ON. */
clk_enable(pll2_400);
- update_ddr_freq(50000000);
+ update_ddr_freq(DDR_AUDIO_CLK);
/* Make sure periph clk's parent also got updated */
clk_set_parent(periph_clk, pll2_200);
audio_bus_freq_mode = 1;
low_bus_freq_mode = 0;
} else {
- update_ddr_freq(24000000);
+ update_ddr_freq(LPAPM_CLK);
/* Make sure periph clk's parent also got updated */
clk_set_parent(periph_clk, osc_clk);
if (audio_bus_freq_mode)
@@ -167,32 +168,61 @@ static void reduce_bus_freq_handler(struct work_struct *work)
spin_lock_irqsave(&freq_lock, flags);
- /* Set periph_clk to be sourced from OSC_CLK */
- /* Set AXI to 24MHz. */
- clk_set_parent(periph_clk, osc_clk);
- clk_set_rate(axi_clk, clk_round_rate(axi_clk, LPAPM_CLK));
- /* Set AHB to 24MHz. */
- clk_set_rate(ahb_clk, clk_round_rate(ahb_clk, LPAPM_CLK));
-
- /* Set MMDC clk to 24MHz. */
- /* Since we are going to set PLL2 in bypass mode,
- * move the CPU clock off PLL2.
- */
- /* Ensure that the clock will be at lowest possible freq. */
- org_arm_podf = __raw_readl(MXC_CCM_CACRR);
- div = clk_get_rate(pll1) / cpu_op_tbl[cpu_op_nr - 1].cpu_rate;
-
- reg = __raw_writel(div - 1, MXC_CCM_CACRR);
- while (__raw_readl(MXC_CCM_CDHIPR))
- ;
- clk_set_parent(pll1_sw_clk, pll1);
+ if (high_bus_freq_mode) {
+ /* Set periph_clk to be sourced from OSC_CLK */
+ /* Set AXI to 24MHz. */
+ clk_set_parent(periph_clk, osc_clk);
+ clk_set_rate(axi_clk,
+ clk_round_rate(axi_clk, LPAPM_CLK));
+ /* Set AHB to 24MHz. */
+ clk_set_rate(ahb_clk,
+ clk_round_rate(ahb_clk, LPAPM_CLK));
+ }
+ if (lp_audio_freq) {
+ /* PLL2 is on in this mode, as DDR is at 50MHz. */
+ /* Now change DDR freq while running from IRAM. */
+ mx6sl_ddr_freq_change_iram(DDR_AUDIO_CLK,
+ low_bus_freq_mode);
+
+ if (low_bus_freq_mode) {
+ /* Swtich ARM to run off PLL2_PFD2_400MHz
+ * since DDR is anway at 50MHz.
+ */
+ clk_set_parent(pll1_sw_clk, pll2_400);
+
+ /* Ensure that the clock will be
+ * at original speed.
+ */
+ reg = __raw_writel(org_arm_podf, MXC_CCM_CACRR);
+ while (__raw_readl(MXC_CCM_CDHIPR))
+ ;
+ }
+ low_bus_freq_mode = 0;
+ audio_bus_freq_mode = 1;
+ } else {
+ /* Set MMDC clk to 24MHz. */
+ /* Since we are going to set PLL2 in bypass mode,
+ * move the CPU clock off PLL2.
+ */
+ /* Ensure that the clock will be at
+ * lowest possible freq.
+ */
+ org_arm_podf = __raw_readl(MXC_CCM_CACRR);
+ div = clk_get_rate(pll1) /
+ cpu_op_tbl[cpu_op_nr - 1].cpu_rate;
- /* Now change DDR freq while running from IRAM. */
- mx6sl_ddr_freq_change_iram(LPAPM_CLK);
+ reg = __raw_writel(div - 1, MXC_CCM_CACRR);
+ while (__raw_readl(MXC_CCM_CDHIPR))
+ ;
+ clk_set_parent(pll1_sw_clk, pll1);
- low_bus_freq_mode = 1;
- audio_bus_freq_mode = 0;
+ /* Now change DDR freq while running from IRAM. */
+ mx6sl_ddr_freq_change_iram(LPAPM_CLK,
+ low_bus_freq_mode);
+ low_bus_freq_mode = 1;
+ audio_bus_freq_mode = 0;
+ }
spin_unlock_irqrestore(&freq_lock, flags);
}
high_bus_freq_mode = 0;
@@ -258,9 +288,8 @@ int set_high_bus_freq(int high_bus_freq)
unsigned long flags;
spin_lock_irqsave(&freq_lock, flags);
-
/* Change DDR freq in IRAM. */
- mx6sl_ddr_freq_change_iram(ddr_normal_rate);
+ mx6sl_ddr_freq_change_iram(ddr_normal_rate, low_bus_freq_mode);
/* Set periph_clk to be sourced from pll2_pfd2_400M */
/* First need to set the divider before changing the */
@@ -271,18 +300,18 @@ int set_high_bus_freq(int high_bus_freq)
clk_round_rate(axi_clk, LPAPM_CLK / 2));
clk_set_parent(periph_clk, pll2_400);
- /* Now move ARM to be sourced from PLL2_400 too. */
- clk_set_parent(pll1_sw_clk, pll2_400);
-
- /* Ensure that the clock will be at original speed. */
- reg = __raw_writel(org_arm_podf, MXC_CCM_CACRR);
- while (__raw_readl(MXC_CCM_CDHIPR))
- ;
+ if (low_bus_freq_mode) {
+ /* Now move ARM to be sourced from PLL2_400 too. */
+ clk_set_parent(pll1_sw_clk, pll2_400);
+ /* Ensure that the clock will be at original speed. */
+ reg = __raw_writel(org_arm_podf, MXC_CCM_CACRR);
+ while (__raw_readl(MXC_CCM_CDHIPR))
+ ;
+ }
high_bus_freq_mode = 1;
low_bus_freq_mode = 0;
audio_bus_freq_mode = 0;
-
spin_unlock_irqrestore(&freq_lock, flags);
} else {
clk_enable(pll3);
diff --git a/arch/arm/mach-mx6/clock_mx6sl.c b/arch/arm/mach-mx6/clock_mx6sl.c
index d93320d59dd8..4839f1542b3a 100755
--- a/arch/arm/mach-mx6/clock_mx6sl.c
+++ b/arch/arm/mach-mx6/clock_mx6sl.c
@@ -1236,6 +1236,7 @@ static int _clk_arm_set_rate(struct clk *clk, unsigned long rate)
pll1_sys_main_clk.disable(&pll1_sys_main_clk);
pll1_sys_main_clk.usecount = 0;
}
+
spin_unlock_irqrestore(&mx6sl_clk_lock, flags);
return 0;
@@ -2451,7 +2452,7 @@ static struct clk ssi1_clk = {
#else
.secondary = &mmdc_ch1_axi_clk[0],
#endif
- .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE,
+ .flags = AHB_AUDIO_SET_POINT | CPU_FREQ_TRIG_UPDATE,
};
static unsigned long _clk_ssi2_get_rate(struct clk *clk)
@@ -2525,7 +2526,7 @@ static struct clk ssi2_clk = {
#else
.secondary = &mmdc_ch1_axi_clk[0],
#endif
- .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE,
+ .flags = AHB_AUDIO_SET_POINT | CPU_FREQ_TRIG_UPDATE,
};
static unsigned long _clk_ssi3_get_rate(struct clk *clk)
@@ -2598,7 +2599,7 @@ static struct clk ssi3_clk = {
#else
.secondary = &mmdc_ch1_axi_clk[0],
#endif
- .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE,
+ .flags = AHB_AUDIO_SET_POINT | CPU_FREQ_TRIG_UPDATE,
};
static unsigned long _clk_epdc_lcdif_pix_round_rate(struct clk *clk,
diff --git a/arch/arm/mach-mx6/mx6sl_ddr.S b/arch/arm/mach-mx6/mx6sl_ddr.S
index 78208c192b39..3059f3aa3c8c 100644
--- a/arch/arm/mach-mx6/mx6sl_ddr.S
+++ b/arch/arm/mach-mx6/mx6sl_ddr.S
@@ -102,10 +102,27 @@ periph2_clk_switch3:
cmp r6, #0
bne periph2_clk_switch3
+ /* Now set the MMDC PODF back to 1.*/
+ ldr r6, [r2, #0x14]
+ bic r6, r6, #0x38
+ str r6, [r2, #0x14]
+
+mmdc_podf0:
+ ldr r6, [r2, #0x48]
+ cmp r6, #0
+ bne mmdc_podf0
+
.endm
.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
@@ -191,10 +208,26 @@ periph2_clk_switch6:
cmp r6, #0
bne periph2_clk_switch6
- /* Now set the MMDC PODF back to 1.*/
-
+change_divider_only:
+ /* Calculate the MMDC divider
+ * based on the requested freq.
+ */
+ ldr r6, =400000000
+ ldr r4, =0
+Loop2:
+ sub r6, r6, r0
+ cmp r6, r0
+ blt Div_Found
+ add r4, r4, #1
+ bgt Loop2
+
+ /* Shift divider into correct offset. */
+ lsl r4, r4, #3
+Div_Found:
+ /* Set the MMDC PODF. */
ldr r6, [r2, #0x14]
bic r6, r6, #0x38
+ orr r6, r6, r4
str r6, [r2, #0x14]
mmdc_podf1:
@@ -204,41 +237,63 @@ mmdc_podf1:
.endm
- .macro mmdc_clk_lower_100MHz
-
- /* Prior to reducing the DDR frequency (at 528/400 MHz),
- read the Measure unit count bits (MU_UNIT_DEL_NUM) */
- ldr r5, =0x8B8
- ldr r6, [r8, r5]
- /* Original MU unit count */
- mov r6, r6, LSR #16
- ldr r4, =0x3FF
- and r6, r6, r4
- /* Original MU unit count * 2 */
- mov r1, r6, LSL #1
- /* Bypass the automatic measure unit when below 100 MHz
- by setting the Measure unit bypass enable bit (MU_BYP_EN) */
- ldr r6, [r8, r5]
- orr r6, r6, #0x400
- str r6, [r8, r5]
- /* Double the measure count value read in step 1 and program it in the
- measurement bypass bits (MU_BYP_VAL) of the MMDC PHY Measure Unit
- Register for the reduced frequency operation below 100 MHz */
- ldr r6, [r8, r5]
- ldr r4, =0x3FF
- bic r6, r6, r4
- orr r6, r6, r1
- str r6, [r8, r5]
- .endm
-
- .macro mmdc_clk_above_100MHz
-
- /* Make sure that the PHY measurement unit is NOT in bypass mode */
- ldr r5, =0x8B8
- ldr r6, [r8, r5]
- bic r6, r6, #0x400
- str r6, [r8, r5]
- .endm
+ .macro mmdc_clk_lower_100MHz
+
+ /* Prior to reducing the DDR frequency (at 528/400 MHz),
+ read the Measure unit count bits (MU_UNIT_DEL_NUM) */
+ ldr r5, =0x8B8
+ ldr r6, [r8, r5]
+ /* Original MU unit count */
+ mov r6, r6, LSR #16
+ ldr r4, =0x3FF
+ and r6, r6, r4
+ /* Original MU unit count * 2 */
+ mov r7, r6, LSL #1
+ /* Bypass the automatic measure unit when below 100 MHz
+ by setting the Measure unit bypass enable bit (MU_BYP_EN) */
+ ldr r6, [r8, r5]
+ orr r6, r6, #0x400
+ str r6, [r8, r5]
+ /* Double the measure count value read in step 1 and program it in the
+ * measurement bypass bits (MU_BYP_VAL) of the MMDC PHY Measure Unit
+ * Register for the reduced frequency operation below 100 MHz
+ */
+ ldr r6, [r8, r5]
+ ldr r4, =0x3FF
+ bic r6, r6, r4
+ orr r6, r6, r7
+ str r6, [r8, r5]
+ /* Now perform a Force Measurement. */
+ ldr r6, [r8, r5]
+ orr r6, r6, #0x800
+ str r6, [r8, r5]
+ /* Wait for FRC_MSR to clear. */
+force_measure:
+ ldr r6, [r8, r5]
+ and r6, r6, #0x800
+ cmp r6, #0x0
+ bne force_measure
+
+ .endm
+
+ .macro mmdc_clk_above_100MHz
+
+ /* Make sure that the PHY measurement unit is NOT in bypass mode */
+ ldr r5, =0x8B8
+ ldr r6, [r8, r5]
+ bic r6, r6, #0x400
+ str r6, [r8, r5]
+ /* Now perform a Force Measurement. */
+ ldr r6, [r8, r5]
+ orr r6, r6, #0x800
+ str r6, [r8, r5]
+ /* Wait for FRC_MSR to clear. */
+force_measure1:
+ ldr r6, [r8, r5]
+ and r6, r6, #0x800
+ cmp r6, #0x0
+ bne force_measure1
+ .endm
/*
* mx6sl_ddr_iram
@@ -247,6 +302,7 @@ mmdc_podf1:
* Make sure DDR is in self-refresh.
* IRQs are already disabled.
* r0 : DDR freq.
+ * r1: low_bus_freq_mode flag
*/
ENTRY(mx6sl_ddr_iram)
@@ -285,7 +341,7 @@ mx6sl_ddr_freq_change:
str r6, [r8, #0x4]
/* Delay for a while */
- ldr r1, =10
+ ldr r10, =10
delay1:
ldr r7, =0
cont1:
@@ -293,8 +349,8 @@ cont1:
add r7, r7, #4
cmp r7, #16
bne cont1
- sub r1, r1, #1
- cmp r1, #0
+ sub r10, r10, #1
+ cmp r10, #0
bgt delay1
/* Make the DDR explicitly enter self-refresh. */
@@ -313,16 +369,24 @@ poll_dvfs_set_1:
orr r6, r6, #0x100
str r6, [r8, #0x410]
- ldr r1, =24000000
- cmp r0, r1
+ ldr r10, =100000000
+ cmp r0, r10
+ bgt set_ddr_mu_above_100
+ mmdc_clk_lower_100MHz
+
+set_ddr_mu_above_100:
+ ldr r10, =24000000
+ cmp r0, r10
beq set_to_24MHz
- mmdc_clk_above_100MHz
ddr_switch_400MHz
+ ldr r10, =100000000
+ cmp r0, r10
+ blt done
+ mmdc_clk_above_100MHz
b done
set_to_24MHz:
- mmdc_clk_lower_100MHz
mx6sl_switch_to_24MHz
done:
@@ -342,8 +406,8 @@ poll_dvfs_clear_1:
bic r6, r6, #0x01
str r6, [r8, #0x404]
- ldr r1, =24000000
- cmp r0, r1
+ ldr r10, =24000000
+ cmp r0, r10
beq skip_power_down
/* Enable MMDC power down timer. */
diff --git a/arch/arm/mach-mx6/mx6sl_wfi.S b/arch/arm/mach-mx6/mx6sl_wfi.S
index 610a57f13730..d2d910383cb7 100644
--- a/arch/arm/mach-mx6/mx6sl_wfi.S
+++ b/arch/arm/mach-mx6/mx6sl_wfi.S
@@ -201,6 +201,11 @@ poll_dvfs_set_1:
cmp r6, #0x2000000
bne poll_dvfs_set_1
+ /* set SBS step-by-step mode */
+ ldr r6, [r8, #0x410]
+ orr r6, r6, #0x100
+ str r6, [r8, #0x410]
+
/* Now set DDR rate to 1MHz. */
/* DDR is from bypassed PLL2 on periph2_clk2 path.
* Set the periph2_clk2_podf to divide by 8.
@@ -215,6 +220,12 @@ poll_dvfs_set_1:
orr r6, r6, #0x10
str r6, [r2, #0x14]
+ /* Loop till podf is accepted. */
+mmdc_podf:
+ ldr r6, [r2, #0x48]
+ cmp r6, #0x0
+ bne mmdc_podf
+
/* Set the DDR IO in LPM state. */
sl_ddr_io_set_lpm
@@ -321,6 +332,11 @@ ahb_podf1:
bic r6, r6, #0x3f
str r6, [r2, #0x14]
+mmdc_podf1:
+ ldr r6, [r2, #0x48]
+ cmp r6, #0x0
+ bne mmdc_podf1
+
/* clear DVFS - exit from self refresh mode */
ldr r6, [r8, #0x404]
bic r6, r6, #0x200000
@@ -337,6 +353,12 @@ poll_dvfs_clear_1:
bic r6, r6, #0x01
str r6, [r8, #0x404]
+ /* clear SBS - unblock DDR accesses */
+ ldr r6, [r8, #0x410]
+ bic r6, r6, #0x100
+ str r6, [r8, #0x410]
+
+
pop {r4,r5, r6, r7, r8, r9, r10}
/* Restore registers */
diff --git a/arch/arm/mach-mx6/system.c b/arch/arm/mach-mx6/system.c
index 75701dc6485a..686c58c1e0e5 100644
--- a/arch/arm/mach-mx6/system.c
+++ b/arch/arm/mach-mx6/system.c
@@ -252,18 +252,38 @@ void arch_idle_single_core(void)
ca9_do_idle();
} else {
- if (low_bus_freq_mode && cpu_is_mx6sl()) {
- u32 org_arm_podf = __raw_readl(MXC_CCM_CACRR);
+ if (low_bus_freq_mode || audio_bus_freq_mode) {
+ if (cpu_is_mx6sl() && low_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
+ * at 24MHz. It will also set DDR to 1MHz to
+ * reduce power.
+ */
+ u32 org_arm_podf = __raw_readl(MXC_CCM_CACRR);
- /* Need to run WFI code from IRAM so that
- * we can lower DDR freq.
- */
- mx6sl_wfi_iram(org_arm_podf,
- (unsigned long)mx6sl_wfi_iram_base);
+ /* Need to run WFI code from IRAM so that
+ * we can lower DDR freq.
+ */
+ mx6sl_wfi_iram(org_arm_podf,
+ (unsigned long)mx6sl_wfi_iram_base);
+ } else {
+ /* Need to set ARM to run at 24MHz since IPG
+ * is at 12MHz. This is valid for audio mode on
+ * MX6SL, and all low power modes on MX6DLS.
+ */
+ /* PLL1_SW_CLK is sourced from PLL2_PFD2400MHz
+ * at this point. Move it to bypassed PLL1.
+ */
+ reg = __raw_readl(MXC_CCM_CCSR);
+ reg &= ~MXC_CCM_CCSR_PLL1_SW_CLK_SEL;
+ __raw_writel(reg, MXC_CCM_CCSR);
- /* Clear the chicken bit to allow memories
- * to be powered down
- */
+ ca9_do_idle();
+
+ reg |= MXC_CCM_CCSR_PLL1_SW_CLK_SEL;
+ __raw_writel(reg, MXC_CCM_CCSR);
+ }
} else {
/*
* Implement the 12:5 ARM:IPG_CLK ratio