Commit d3f7f366 authored by Ranjani Vaidyanathan's avatar Ranjani Vaidyanathan

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: default avatarRanjani Vaidyanathan <ra5478@freescale.com>
parent df63a57d
...@@ -47,6 +47,7 @@ ...@@ -47,6 +47,7 @@
#include <linux/suspend.h> #include <linux/suspend.h>
#define LPAPM_CLK 24000000 #define LPAPM_CLK 24000000
#define DDR_AUDIO_CLK 50000000
#define DDR_MED_CLK 400000000 #define DDR_MED_CLK 400000000
#define DDR3_NORMAL_CLK 528000000 #define DDR3_NORMAL_CLK 528000000
#define GPC_PGC_GPU_PGCR_OFFSET 0x260 #define GPC_PGC_GPU_PGCR_OFFSET 0x260
...@@ -81,7 +82,7 @@ void (*mx6sl_wfi_iram)(int arm_podf, unsigned long wfi_iram_addr) = NULL; ...@@ -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); extern void mx6sl_wait (int arm_podf, unsigned long wfi_iram_addr);
void *mx6sl_ddr_freq_base; 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 void mx6sl_ddr_iram(int ddr_freq);
extern int init_mmdc_settings(void); extern int init_mmdc_settings(void);
...@@ -140,13 +141,13 @@ static void reduce_bus_freq_handler(struct work_struct *work) ...@@ -140,13 +141,13 @@ static void reduce_bus_freq_handler(struct work_struct *work)
if (lp_audio_freq) { if (lp_audio_freq) {
/* Need to ensure that PLL2_PFD_400M is kept ON. */ /* Need to ensure that PLL2_PFD_400M is kept ON. */
clk_enable(pll2_400); clk_enable(pll2_400);
update_ddr_freq(50000000); update_ddr_freq(DDR_AUDIO_CLK);
/* Make sure periph clk's parent also got updated */ /* Make sure periph clk's parent also got updated */
clk_set_parent(periph_clk, pll2_200); clk_set_parent(periph_clk, pll2_200);
audio_bus_freq_mode = 1; audio_bus_freq_mode = 1;
low_bus_freq_mode = 0; low_bus_freq_mode = 0;
} else { } else {
update_ddr_freq(24000000); update_ddr_freq(LPAPM_CLK);
/* Make sure periph clk's parent also got updated */ /* Make sure periph clk's parent also got updated */
clk_set_parent(periph_clk, osc_clk); clk_set_parent(periph_clk, osc_clk);
if (audio_bus_freq_mode) if (audio_bus_freq_mode)
...@@ -167,32 +168,61 @@ static void reduce_bus_freq_handler(struct work_struct *work) ...@@ -167,32 +168,61 @@ static void reduce_bus_freq_handler(struct work_struct *work)
spin_lock_irqsave(&freq_lock, flags); spin_lock_irqsave(&freq_lock, flags);
/* Set periph_clk to be sourced from OSC_CLK */ if (high_bus_freq_mode) {
/* Set AXI to 24MHz. */ /* Set periph_clk to be sourced from OSC_CLK */
clk_set_parent(periph_clk, osc_clk); /* Set AXI to 24MHz. */
clk_set_rate(axi_clk, clk_round_rate(axi_clk, LPAPM_CLK)); clk_set_parent(periph_clk, osc_clk);
/* Set AHB to 24MHz. */ clk_set_rate(axi_clk,
clk_set_rate(ahb_clk, clk_round_rate(ahb_clk, LPAPM_CLK)); clk_round_rate(axi_clk, LPAPM_CLK));
/* Set AHB to 24MHz. */
/* Set MMDC clk to 24MHz. */ clk_set_rate(ahb_clk,
/* Since we are going to set PLL2 in bypass mode, clk_round_rate(ahb_clk, LPAPM_CLK));
* move the CPU clock off PLL2. }
*/ if (lp_audio_freq) {
/* Ensure that the clock will be at lowest possible freq. */ /* PLL2 is on in this mode, as DDR is at 50MHz. */
org_arm_podf = __raw_readl(MXC_CCM_CACRR); /* Now change DDR freq while running from IRAM. */
div = clk_get_rate(pll1) / cpu_op_tbl[cpu_op_nr - 1].cpu_rate; mx6sl_ddr_freq_change_iram(DDR_AUDIO_CLK,
low_bus_freq_mode);
reg = __raw_writel(div - 1, MXC_CCM_CACRR);
while (__raw_readl(MXC_CCM_CDHIPR)) if (low_bus_freq_mode) {
; /* Swtich ARM to run off PLL2_PFD2_400MHz
clk_set_parent(pll1_sw_clk, pll1); * 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. */ reg = __raw_writel(div - 1, MXC_CCM_CACRR);
mx6sl_ddr_freq_change_iram(LPAPM_CLK); while (__raw_readl(MXC_CCM_CDHIPR))
;
clk_set_parent(pll1_sw_clk, pll1);
low_bus_freq_mode = 1; /* Now change DDR freq while running from IRAM. */
audio_bus_freq_mode = 0; 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); spin_unlock_irqrestore(&freq_lock, flags);
} }
high_bus_freq_mode = 0; high_bus_freq_mode = 0;
...@@ -258,9 +288,8 @@ int set_high_bus_freq(int high_bus_freq) ...@@ -258,9 +288,8 @@ int set_high_bus_freq(int high_bus_freq)
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&freq_lock, flags); spin_lock_irqsave(&freq_lock, flags);
/* Change DDR freq in IRAM. */ /* 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 */ /* Set periph_clk to be sourced from pll2_pfd2_400M */
/* First need to set the divider before changing the */ /* First need to set the divider before changing the */
...@@ -271,18 +300,18 @@ int set_high_bus_freq(int high_bus_freq) ...@@ -271,18 +300,18 @@ int set_high_bus_freq(int high_bus_freq)
clk_round_rate(axi_clk, LPAPM_CLK / 2)); clk_round_rate(axi_clk, LPAPM_CLK / 2));
clk_set_parent(periph_clk, pll2_400); clk_set_parent(periph_clk, pll2_400);
/* Now move ARM to be sourced from PLL2_400 too. */ if (low_bus_freq_mode) {
clk_set_parent(pll1_sw_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))
;
/* 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; high_bus_freq_mode = 1;
low_bus_freq_mode = 0; low_bus_freq_mode = 0;
audio_bus_freq_mode = 0; audio_bus_freq_mode = 0;
spin_unlock_irqrestore(&freq_lock, flags); spin_unlock_irqrestore(&freq_lock, flags);
} else { } else {
clk_enable(pll3); clk_enable(pll3);
......
...@@ -1236,6 +1236,7 @@ static int _clk_arm_set_rate(struct clk *clk, unsigned long rate) ...@@ -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.disable(&pll1_sys_main_clk);
pll1_sys_main_clk.usecount = 0; pll1_sys_main_clk.usecount = 0;
} }
spin_unlock_irqrestore(&mx6sl_clk_lock, flags); spin_unlock_irqrestore(&mx6sl_clk_lock, flags);
return 0; return 0;
...@@ -2451,7 +2452,7 @@ static struct clk ssi1_clk = { ...@@ -2451,7 +2452,7 @@ static struct clk ssi1_clk = {
#else #else
.secondary = &mmdc_ch1_axi_clk[0], .secondary = &mmdc_ch1_axi_clk[0],
#endif #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) static unsigned long _clk_ssi2_get_rate(struct clk *clk)
...@@ -2525,7 +2526,7 @@ static struct clk ssi2_clk = { ...@@ -2525,7 +2526,7 @@ static struct clk ssi2_clk = {
#else #else
.secondary = &mmdc_ch1_axi_clk[0], .secondary = &mmdc_ch1_axi_clk[0],
#endif #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) static unsigned long _clk_ssi3_get_rate(struct clk *clk)
...@@ -2598,7 +2599,7 @@ static struct clk ssi3_clk = { ...@@ -2598,7 +2599,7 @@ static struct clk ssi3_clk = {
#else #else
.secondary = &mmdc_ch1_axi_clk[0], .secondary = &mmdc_ch1_axi_clk[0],
#endif #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, static unsigned long _clk_epdc_lcdif_pix_round_rate(struct clk *clk,
......
...@@ -102,10 +102,27 @@ periph2_clk_switch3: ...@@ -102,10 +102,27 @@ periph2_clk_switch3:
cmp r6, #0 cmp r6, #0
bne periph2_clk_switch3 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 .endm
.macro ddr_switch_400MHz .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. */ /* Set MMDC divider first, in case PLL3 is at 480MHz. */
ldr r6, [r3, #0x10] ldr r6, [r3, #0x10]
and r6, r6, #0x10000 and r6, r6, #0x10000
...@@ -191,10 +208,26 @@ periph2_clk_switch6: ...@@ -191,10 +208,26 @@ periph2_clk_switch6:
cmp r6, #0 cmp r6, #0
bne periph2_clk_switch6 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] ldr r6, [r2, #0x14]
bic r6, r6, #0x38 bic r6, r6, #0x38
orr r6, r6, r4
str r6, [r2, #0x14] str r6, [r2, #0x14]
mmdc_podf1: mmdc_podf1:
...@@ -204,41 +237,63 @@ mmdc_podf1: ...@@ -204,41 +237,63 @@ mmdc_podf1:
.endm .endm
.macro mmdc_clk_lower_100MHz .macro mmdc_clk_lower_100MHz
/* Prior to reducing the DDR frequency (at 528/400 MHz), /* Prior to reducing the DDR frequency (at 528/400 MHz),
read the Measure unit count bits (MU_UNIT_DEL_NUM) */ read the Measure unit count bits (MU_UNIT_DEL_NUM) */
ldr r5, =0x8B8 ldr r5, =0x8B8
ldr r6, [r8, r5] ldr r6, [r8, r5]
/* Original MU unit count */ /* Original MU unit count */
mov r6, r6, LSR #16 mov r6, r6, LSR #16
ldr r4, =0x3FF ldr r4, =0x3FF
and r6, r6, r4 and r6, r6, r4
/* Original MU unit count * 2 */ /* Original MU unit count * 2 */
mov r1, r6, LSL #1 mov r7, r6, LSL #1
/* Bypass the automatic measure unit when below 100 MHz /* Bypass the automatic measure unit when below 100 MHz
by setting the Measure unit bypass enable bit (MU_BYP_EN) */ by setting the Measure unit bypass enable bit (MU_BYP_EN) */
ldr r6, [r8, r5] ldr r6, [r8, r5]
orr r6, r6, #0x400 orr r6, r6, #0x400
str r6, [r8, r5] str r6, [r8, r5]
/* Double the measure count value read in step 1 and program it in the /* 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 * measurement bypass bits (MU_BYP_VAL) of the MMDC PHY Measure Unit
Register for the reduced frequency operation below 100 MHz */ * Register for the reduced frequency operation below 100 MHz
ldr r6, [r8, r5] */
ldr r4, =0x3FF ldr r6, [r8, r5]
bic r6, r6, r4 ldr r4, =0x3FF
orr r6, r6, r1 bic r6, r6, r4
str r6, [r8, r5] orr r6, r6, r7
.endm str r6, [r8, r5]
/* Now perform a Force Measurement. */
.macro mmdc_clk_above_100MHz ldr r6, [r8, r5]
orr r6, r6, #0x800
/* Make sure that the PHY measurement unit is NOT in bypass mode */ str r6, [r8, r5]
ldr r5, =0x8B8 /* Wait for FRC_MSR to clear. */
ldr r6, [r8, r5] force_measure:
bic r6, r6, #0x400 ldr r6, [r8, r5]
str r6, [r8, r5] and r6, r6, #0x800
.endm 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 * mx6sl_ddr_iram
...@@ -247,6 +302,7 @@ mmdc_podf1: ...@@ -247,6 +302,7 @@ mmdc_podf1:
* Make sure DDR is in self-refresh. * Make sure DDR is in self-refresh.
* IRQs are already disabled. * IRQs are already disabled.
* r0 : DDR freq. * r0 : DDR freq.
* r1: low_bus_freq_mode flag
*/ */
ENTRY(mx6sl_ddr_iram) ENTRY(mx6sl_ddr_iram)
...@@ -285,7 +341,7 @@ mx6sl_ddr_freq_change: ...@@ -285,7 +341,7 @@ mx6sl_ddr_freq_change:
str r6, [r8, #0x4] str r6, [r8, #0x4]
/* Delay for a while */ /* Delay for a while */
ldr r1, =10 ldr r10, =10
delay1: delay1:
ldr r7, =0 ldr r7, =0
cont1: cont1:
...@@ -293,8 +349,8 @@ cont1: ...@@ -293,8 +349,8 @@ cont1:
add r7, r7, #4 add r7, r7, #4
cmp r7, #16 cmp r7, #16
bne cont1 bne cont1
sub r1, r1, #1 sub r10, r10, #1
cmp r1, #0 cmp r10, #0
bgt delay1 bgt delay1
/* Make the DDR explicitly enter self-refresh. */ /* Make the DDR explicitly enter self-refresh. */
...@@ -313,16 +369,24 @@ poll_dvfs_set_1: ...@@ -313,16 +369,24 @@ poll_dvfs_set_1:
orr r6, r6, #0x100 orr r6, r6, #0x100
str r6, [r8, #0x410] str r6, [r8, #0x410]
ldr r1, =24000000 ldr r10, =100000000
cmp r0, r1 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 beq set_to_24MHz
mmdc_clk_above_100MHz
ddr_switch_400MHz ddr_switch_400MHz
ldr r10, =100000000
cmp r0, r10
blt done
mmdc_clk_above_100MHz
b done b done
set_to_24MHz: set_to_24MHz:
mmdc_clk_lower_100MHz
mx6sl_switch_to_24MHz mx6sl_switch_to_24MHz
done: done:
...@@ -342,8 +406,8 @@ poll_dvfs_clear_1: ...@@ -342,8 +406,8 @@ poll_dvfs_clear_1:
bic r6, r6, #0x01 bic r6, r6, #0x01
str r6, [r8, #0x404] str r6, [r8, #0x404]
ldr r1, =24000000 ldr r10, =24000000
cmp r0, r1 cmp r0, r10
beq skip_power_down beq skip_power_down
/* Enable MMDC power down timer. */ /* Enable MMDC power down timer. */
......
...@@ -201,6 +201,11 @@ poll_dvfs_set_1: ...@@ -201,6 +201,11 @@ poll_dvfs_set_1:
cmp r6, #0x2000000 cmp r6, #0x2000000
bne poll_dvfs_set_1 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. */ /* Now set DDR rate to 1MHz. */
/* DDR is from bypassed PLL2 on periph2_clk2 path. /* DDR is from bypassed PLL2 on periph2_clk2 path.
* Set the periph2_clk2_podf to divide by 8. * Set the periph2_clk2_podf to divide by 8.
...@@ -215,6 +220,12 @@ poll_dvfs_set_1: ...@@ -215,6 +220,12 @@ poll_dvfs_set_1:
orr r6, r6, #0x10 orr r6, r6, #0x10
str r6, [r2, #0x14] 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. */ /* Set the DDR IO in LPM state. */
sl_ddr_io_set_lpm sl_ddr_io_set_lpm
...@@ -321,6 +332,11 @@ ahb_podf1: ...@@ -321,6 +332,11 @@ ahb_podf1:
bic r6, r6, #0x3f bic r6, r6, #0x3f
str r6, [r2, #0x14] str r6, [r2, #0x14]
mmdc_podf1:
ldr r6, [r2, #0x48]
cmp r6, #0x0
bne mmdc_podf1
/* clear DVFS - exit from self refresh mode */ /* clear DVFS - exit from self refresh mode */
ldr r6, [r8, #0x404] ldr r6, [r8, #0x404]
bic r6, r6, #0x200000 bic r6, r6, #0x200000
...@@ -337,6 +353,12 @@ poll_dvfs_clear_1: ...@@ -337,6 +353,12 @@ poll_dvfs_clear_1:
bic r6, r6, #0x01 bic r6, r6, #0x01
str r6, [r8, #0x404] 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} pop {r4,r5, r6, r7, r8, r9, r10}
/* Restore registers */ /* Restore registers */
......
...@@ -252,18 +252,38 @@ void arch_idle_single_core(void) ...@@ -252,18 +252,38 @@ void arch_idle_single_core(void)
ca9_do_idle(); ca9_do_idle();
} else { } else {
if (low_bus_freq_mode && cpu_is_mx6sl()) { if (low_bus_freq_mode || audio_bus_freq_mode) {
u32 org_arm_podf = __raw_readl(MXC_CCM_CACRR); 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 /* Need to run WFI code from IRAM so that
* we can lower DDR freq. * we can lower DDR freq.
*/ */
mx6sl_wfi_iram(org_arm_podf, mx6sl_wfi_iram(org_arm_podf,
(unsigned long)mx6sl_wfi_iram_base); (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 ca9_do_idle();
* to be powered down
*/ reg |= MXC_CCM_CCSR_PLL1_SW_CLK_SEL;
__raw_writel(reg, MXC_CCM_CCSR);
}
} else { } else {
/* /*
* Implement the 12:5 ARM:IPG_CLK ratio * Implement the 12:5 ARM:IPG_CLK ratio
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment