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 @@
#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,20 +168,48 @@ static void reduce_bus_freq_handler(struct work_struct *work)
spin_lock_irqsave(&freq_lock, flags);
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));
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));
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. */
/* 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;
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))
......@@ -188,11 +217,12 @@ static void reduce_bus_freq_handler(struct work_struct *work)
clk_set_parent(pll1_sw_clk, pll1);
/* Now change DDR freq while running from IRAM. */
mx6sl_ddr_freq_change_iram(LPAPM_CLK);
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,6 +300,7 @@ int set_high_bus_freq(int high_bus_freq)
clk_round_rate(axi_clk, LPAPM_CLK / 2));
clk_set_parent(periph_clk, pll2_400);
if (low_bus_freq_mode) {
/* Now move ARM to be sourced from PLL2_400 too. */
clk_set_parent(pll1_sw_clk, pll2_400);
......@@ -278,11 +308,10 @@ int set_high_bus_freq(int high_bus_freq)
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);
......
......@@ -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,
......
......@@ -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:
......@@ -215,20 +248,32 @@ mmdc_podf1:
ldr r4, =0x3FF
and r6, r6, r4
/* Original MU unit count * 2 */
mov r1, r6, LSL #1
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 */
* 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
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
......@@ -238,6 +283,16 @@ mmdc_podf1:
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
/*
......@@ -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. */
......
......@@ -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 */
......
......@@ -252,7 +252,14 @@ void arch_idle_single_core(void)
ca9_do_idle();
} else {
if (low_bus_freq_mode && cpu_is_mx6sl()) {
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
......@@ -260,10 +267,23 @@ void arch_idle_single_core(void)
*/
mx6sl_wfi_iram(org_arm_podf,
(unsigned long)mx6sl_wfi_iram_base);
/* Clear the chicken bit to allow memories
* to be powered down
} 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);
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
......
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