From b0aee76e42f2297a1340ad4e6ada138f2fa38df4 Mon Sep 17 00:00:00 2001 From: =?utf8?q?=E9=BB=84=E6=B6=9B?= Date: Mon, 28 Feb 2011 11:36:15 +0800 Subject: [PATCH] rk29: pm: set core voltage after ddr suspend --- arch/arm/mach-rk29/ddr.c | 4 +- arch/arm/mach-rk29/pm.c | 229 ++++++++++++++++++++++++++------------- 2 files changed, 158 insertions(+), 75 deletions(-) diff --git a/arch/arm/mach-rk29/ddr.c b/arch/arm/mach-rk29/ddr.c index 42991ca2151e..60b44cee43e0 100644 --- a/arch/arm/mach-rk29/ddr.c +++ b/arch/arm/mach-rk29/ddr.c @@ -1031,7 +1031,7 @@ void __sramfunc DDR_EnterSelfRefresh(void) { EnterDDRSelfRefresh(); #if 1 - pSCU_Reg->CRU_CLKGATE_CON[0] |= (0x1<<18); //close DDR PHY clock + pSCU_Reg->CRU_CLKGATE_CON[0] |= (0x7<<18); //close DDR PHY clock / DDR CPU AXI clock / DDR REG AXI clock delayus(10); // ddr slow pSCU_Reg->CRU_MODE_CON &=~(0x3<<6); @@ -1060,7 +1060,7 @@ void __sramfunc DDR_ExitSelfRefresh(void) pSCU_Reg->CRU_MODE_CON &=~(0x3<<6); pSCU_Reg->CRU_MODE_CON |= 0x1<<6; delayus(10); - pSCU_Reg->CRU_CLKGATE_CON[0] &= ~(0x1<<18); //enable DDR PHY clock + pSCU_Reg->CRU_CLKGATE_CON[0] &= ~(0x7<<18); //enable DDR PHY clock / DDR CPU AXI clock / DDR REG AXI clock delayus(10); #endif ExitDDRSelfRefresh(); diff --git a/arch/arm/mach-rk29/pm.c b/arch/arm/mach-rk29/pm.c index 09128ab22dd9..0702e7ddf65c 100644 --- a/arch/arm/mach-rk29/pm.c +++ b/arch/arm/mach-rk29/pm.c @@ -1,3 +1,5 @@ +#define DEBUG + #include #include #include @@ -5,7 +7,7 @@ #include #include #include -#include +#include #include #include @@ -22,71 +24,157 @@ #define pmu_writel(v, offset) do { writel(v, RK29_PMU_BASE + offset); readl(RK29_PMU_BASE + offset); } while (0) static unsigned long save_sp; +#define LOOPS_PER_USEC 13 +#define LOOP(loops) do { int i = loops; barrier(); while (i--) barrier(); } while (0) + static inline void delay_500ns(void) { - int delay = 12; - while (delay--) - barrier(); + LOOP(LOOPS_PER_USEC); } static inline void delay_300us(void) { - int i; - for (i = 0; i < 600; i++) - delay_500ns(); + LOOP(300 * LOOPS_PER_USEC); } -static u32 apll; -static u32 lpj; -static struct regulator *vcore; -static int vcore_uV; - extern void ddr_suspend(void); extern void ddr_resume(void); -static void __sramfunc rk29_pm_enter_ddr(void) +#ifdef DEBUG +static void inline printch(char byte) { - u32 clksel0, dpll, mode, clkgate0; + unsigned long flags; + unsigned int delay; + u32 gate1, gate2; + + local_irq_save(flags); + gate1 = cru_readl(CRU_CLKGATE1_CON); + gate2 = cru_readl(CRU_CLKGATE2_CON); + cru_writel(gate1 & ~((1 << CLK_GATE_PCLK_PEIRPH % 32) | (1 << CLK_GATE_ACLK_PEIRPH % 32) | (1 << CLK_GATE_ACLK_CPU_PERI % 32)), CRU_CLKGATE1_CON); + cru_writel(gate2 & ~(1 << CLK_GATE_UART1 % 32), CRU_CLKGATE2_CON); + delay_500ns(); - asm("dsb"); - ddr_suspend(); + writel(byte, RK29_UART1_BASE); - /* suspend ddr pll */ - mode = cru_readl(CRU_MODE_CON); - dpll = cru_readl(CRU_DPLL_CON); - cru_writel((cru_readl(CRU_MODE_CON) & ~CRU_DDR_MODE_MASK) | CRU_DDR_MODE_SLOW, CRU_MODE_CON); - cru_writel(dpll | PLL_BYPASS, CRU_DPLL_CON); - cru_writel(dpll | PLL_PD | PLL_BYPASS, CRU_DPLL_CON); - delay_500ns(); + delay = (cru_readl(CRU_MODE_CON) & CRU_CPU_MODE_MASK) ? 10 : 1; + while (delay--) + delay_300us(); - /* disable ddr clock */ - clkgate0 = cru_readl(CRU_CLKGATE0_CON); - cru_writel(clkgate0 | (1 << CLK_GATE_DDR_PHY) | (1 << CLK_GATE_DDR_REG) | (1 << CLK_GATE_DDR_CPU), CRU_CLKGATE0_CON); + cru_writel(gate2, CRU_CLKGATE2_CON); + cru_writel(gate1, CRU_CLKGATE1_CON); + local_irq_restore(flags); + if (byte == '\n') + printch('\r'); +} - /* set arm clk 24MHz/32 = 750KHz */ +static void inline printascii(const char *s) +{ + while (*s) { + printch(*s); + s++; + } +} + +static void inline printhex(unsigned int hex) +{ + int i = 8; + printch('0'); + printch('x'); + while (i--) { + unsigned char c = (hex & 0xF0000000) >> 28; + printch(c < 0xa ? c + '0' : c - 0xa + 'a'); + hex <<= 4; + } +} +#else +static void inline printch(char byte) {} +static void inline printascii(const char *s) {} +static void inline printhex(unsigned int hex) {} +#endif /* DEBUG */ + +#ifdef CONFIG_RK29_PWM_REGULATOR +#define pwm_write_reg(addr, val) __raw_writel(val, addr + (RK29_PWM_BASE + 2*0x10)) +#define pwm_read_reg(addr) __raw_readl(addr + (RK29_PWM_BASE + 2*0x10)) + +static u32 __sramdata pwm_lrc, pwm_hrc; +static void __sramfunc rk29_set_core_voltage(int uV) +{ + u32 gate1; + + gate1 = cru_readl(CRU_CLKGATE1_CON); + cru_writel(gate1 & ~((1 << CLK_GATE_PCLK_PEIRPH % 32) | (1 << CLK_GATE_ACLK_PEIRPH % 32) | (1 << CLK_GATE_ACLK_CPU_PERI % 32)), CRU_CLKGATE1_CON); + + /* iomux pwm2 */ + writel((readl(RK29_GRF_BASE + 0x58) & ~(0x3<<6)) | (0x2<<6), RK29_GRF_BASE + 0x58); + + if (uV) { + pwm_lrc = pwm_read_reg(PWM_REG_LRC); + pwm_hrc = pwm_read_reg(PWM_REG_HRC); + } + + pwm_write_reg(PWM_REG_CTRL, PWM_DIV|PWM_RESET); + if (uV == 1000000) { + pwm_write_reg(PWM_REG_LRC, 12); + pwm_write_reg(PWM_REG_HRC, 10); + } else { + pwm_write_reg(PWM_REG_LRC, pwm_lrc); + pwm_write_reg(PWM_REG_HRC, pwm_hrc); + } + pwm_write_reg(PWM_REG_CNTR, 0); + pwm_write_reg(PWM_REG_CTRL, PWM_DIV|PWM_ENABLE|PWM_TimeEN); + + LOOP(5 * 1000 * LOOPS_PER_USEC); /* delay 5ms */ + + cru_writel(gate1, CRU_CLKGATE1_CON); +} +#endif /* CONFIG_RK29_PWM_REGULATOR */ + +static void __sramfunc rk29_sram_suspend(void) +{ + u32 clksel0; + + printch('5'); + ddr_suspend(); + + printch('6'); + rk29_set_core_voltage(1000000); + + printch('7'); clksel0 = cru_readl(CRU_CLKSEL0_CON); + /* set arm clk 24MHz/32 = 750KHz */ cru_writel(clksel0 | 0x1F, CRU_CLKSEL0_CON); asm("wfi"); /* resume arm clk */ cru_writel(clksel0, CRU_CLKSEL0_CON); + printch('7'); - /* enable ddr clock */ - cru_writel(clkgate0, CRU_CLKGATE0_CON); - - /* resume ddr pll */ - cru_writel(dpll, CRU_DPLL_CON); - delay_300us(); - cru_writel((cru_readl(CRU_MODE_CON) & ~CRU_DDR_MODE_MASK) | (mode & CRU_DDR_MODE_MASK), CRU_MODE_CON); + rk29_set_core_voltage(0); + printch('6'); ddr_resume(); + printch('5'); +} + +static void noinline rk29_suspend(void) +{ + DDR_SAVE_SP(save_sp); + rk29_sram_suspend(); + DDR_RESTORE_SP(save_sp); } static int rk29_pm_enter(suspend_state_t state) { - u32 cpll, gpll, mode; + u32 apll, cpll, gpll, mode, clksel0; u32 clkgate[4]; + printch('0'); + +#ifdef CONFIG_RK29_PWM_REGULATOR + /* touch TLB */ + readl(RK29_PWM_BASE); + readl(RK29_GRF_BASE); +#endif /* disable clock */ clkgate[0] = cru_readl(CRU_CLKGATE0_CON); @@ -116,8 +204,20 @@ static int rk29_pm_enter(suspend_state_t state) | (1 << CLK_GATE_PWM % 32) ) | clkgate[2], CRU_CLKGATE2_CON); cru_writel(~0, CRU_CLKGATE3_CON); + printch('1'); mode = cru_readl(CRU_MODE_CON); + clksel0 = cru_readl(CRU_CLKSEL0_CON); + + /* suspend arm pll */ + apll = cru_readl(CRU_APLL_CON); + cru_writel((cru_readl(CRU_MODE_CON) & ~CRU_CPU_MODE_MASK) | CRU_CPU_MODE_SLOW, CRU_MODE_CON); + cru_writel(apll | PLL_BYPASS, CRU_APLL_CON); + cru_writel(apll | PLL_PD | PLL_BYPASS, CRU_APLL_CON); + delay_500ns(); + /* set core = aclk_cpu = hclk_cpu = pclk_cpu = 24MHz */ + cru_writel(clksel0 & 0xFFFFF000, CRU_CLKSEL0_CON); + printch('2'); /* suspend codec pll */ cpll = cru_readl(CRU_CPLL_CON); @@ -125,6 +225,7 @@ static int rk29_pm_enter(suspend_state_t state) cru_writel(cpll | PLL_BYPASS, CRU_CPLL_CON); cru_writel(cpll | PLL_PD | PLL_BYPASS, CRU_CPLL_CON); delay_500ns(); + printch('3'); /* suspend general pll */ gpll = cru_readl(CRU_GPLL_CON); @@ -132,67 +233,55 @@ static int rk29_pm_enter(suspend_state_t state) cru_writel(gpll | PLL_BYPASS, CRU_GPLL_CON); cru_writel(gpll | PLL_PD | PLL_BYPASS, CRU_GPLL_CON); delay_500ns(); + /* set aclk_periph = hclk_periph = pclk_periph = 24MHz */ + cru_writel(clksel0 & ~0x7FC000, CRU_CLKSEL0_CON); - DDR_SAVE_SP(save_sp); - rk29_pm_enter_ddr(); - DDR_RESTORE_SP(save_sp); + printch('4'); + rk29_suspend(); + printch('4'); /* resume general pll */ cru_writel(gpll, CRU_GPLL_CON); delay_300us(); + /* restore aclk_periph/hclk_periph/pclk_periph */ + cru_writel(cru_readl(CRU_CLKSEL0_CON) | (clksel0 & 0x7FC000), CRU_CLKSEL0_CON); cru_writel((cru_readl(CRU_MODE_CON) & ~CRU_GENERAL_MODE_MASK) | (mode & CRU_GENERAL_MODE_MASK), CRU_MODE_CON); + printch('3'); /* resume codec pll */ cru_writel(cpll, CRU_CPLL_CON); delay_300us(); cru_writel((cru_readl(CRU_MODE_CON) & ~CRU_CODEC_MODE_MASK) | (mode & CRU_CODEC_MODE_MASK), CRU_MODE_CON); + printch('2'); + + /* resume arm pll */ + cru_writel(apll, CRU_APLL_CON); + delay_300us(); + /* restore core/aclk_cpu/hclk_cpu/pclk_cpu */ + cru_writel(cru_readl(CRU_CLKSEL0_CON) | (clksel0 & 0xFFF), CRU_CLKSEL0_CON); + cru_writel((cru_readl(CRU_MODE_CON) & ~CRU_CPU_MODE_MASK) | (mode & CRU_CPU_MODE_MASK), CRU_MODE_CON); + printch('1'); /* enable clock */ cru_writel(clkgate[0], CRU_CLKGATE0_CON); cru_writel(clkgate[1], CRU_CLKGATE1_CON); cru_writel(clkgate[2], CRU_CLKGATE2_CON); cru_writel(clkgate[3], CRU_CLKGATE3_CON); + printascii("0\n"); return 0; } static int rk29_pm_prepare(void) { - printk("+%s\n", __func__); - disable_hlt(); // disable entering rk29_idle() by disable_hlt() - - /* suspend arm pll */ - apll = cru_readl(CRU_APLL_CON); - cru_writel((cru_readl(CRU_MODE_CON) & ~CRU_CPU_MODE_MASK) | CRU_CPU_MODE_SLOW, CRU_MODE_CON); - cru_writel(apll | PLL_BYPASS, CRU_APLL_CON); - cru_writel(apll | PLL_PD | PLL_BYPASS, CRU_APLL_CON); - delay_500ns(); - lpj = loops_per_jiffy; - loops_per_jiffy = 120000; // make udelay/mdelay correct - - if (vcore) { - vcore_uV = regulator_get_voltage(vcore); - regulator_set_voltage(vcore, 1000000, 1000000); - } - printk("-%s\n", __func__); + /* disable entering rk29_idle() by disable_hlt() */ + disable_hlt(); return 0; } static void rk29_pm_finish(void) { - printk("+%s\n", __func__); - if (vcore) { - regulator_set_voltage(vcore, vcore_uV, vcore_uV); - } - - /* resume arm pll */ - loops_per_jiffy = lpj; - cru_writel(apll, CRU_APLL_CON); - delay_300us(); - cru_writel((cru_readl(CRU_MODE_CON) & ~CRU_CPU_MODE_MASK) | CRU_CPU_MODE_NORMAL, CRU_MODE_CON); - enable_hlt(); - printk("-%s\n", __func__); } static struct platform_suspend_ops rk29_pm_ops = { @@ -223,12 +312,6 @@ static void rk29_idle(void) static int __init rk29_pm_init(void) { - vcore = regulator_get(NULL, "vcore"); - if (IS_ERR(vcore)) { - pr_err("pm: fail to get regulator vcore: %ld\n", PTR_ERR(vcore)); - vcore = NULL; - } - suspend_set_ops(&rk29_pm_ops); /* set idle function */ -- 2.34.1