mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-09 12:17:12 +09:00
rk29: add pm support
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
obj-y += timer.o io.o devices.o iomux.o clock.o rk29-pl330.o dma.o gpio.o ddr.o sram.o
|
||||
obj-$(CONFIG_PM) += pm.o
|
||||
obj-$(CONFIG_CPU_FREQ) += cpufreq.o
|
||||
obj-$(CONFIG_RK29_VPU) += vpu.o vpu_mem.o
|
||||
obj-$(CONFIG_MACH_RK29SDK) += board-rk29sdk.o board-rk29sdk-key.o board-rk29sdk-rfkill.o
|
||||
|
||||
@@ -33,48 +33,6 @@
|
||||
#include <mach/pmu.h>
|
||||
|
||||
|
||||
/* CRU PLL CON */
|
||||
#define PLL_HIGH_BAND (0x01 << 16)
|
||||
#define PLL_LOW_BAND (0x00 << 16)
|
||||
#define PLL_PD (0x01 << 15)
|
||||
|
||||
#define PLL_CLKR(i) ((((i) - 1) & 0x1f) << 10)
|
||||
#define PLL_NR(v) ((((v) >> 10) & 0x1f) + 1)
|
||||
|
||||
#define PLL_CLKF(i) ((((i) - 1) & 0x7f) << 3)
|
||||
#define PLL_NF(v) ((((v) >> 3) & 0x7f) + 1)
|
||||
#define PLL_NF2(v) (((((v) >> 3) & 0x7f) + 1) << 1)
|
||||
|
||||
#define PLL_CLKOD(i) (((i) & 0x03) << 1)
|
||||
#define PLL_NO_1 PLL_CLKOD(0)
|
||||
#define PLL_NO_2 PLL_CLKOD(1)
|
||||
#define PLL_NO_4 PLL_CLKOD(2)
|
||||
#define PLL_NO_8 PLL_CLKOD(3)
|
||||
#define PLL_NO_SHIFT(v) (((v) >> 1) & 0x03)
|
||||
|
||||
#define PLL_BYPASS (0x01)
|
||||
|
||||
/* CRU MODE CON */
|
||||
#define CRU_CPU_MODE_MASK (0x03u << 0)
|
||||
#define CRU_CPU_MODE_SLOW (0x00u << 0)
|
||||
#define CRU_CPU_MODE_NORMAL (0x01u << 0)
|
||||
#define CRU_CPU_MODE_SLOW27 (0x02u << 0)
|
||||
|
||||
#define CRU_GENERAL_MODE_MASK (0x03u << 2)
|
||||
#define CRU_GENERAL_MODE_SLOW (0x00u << 2)
|
||||
#define CRU_GENERAL_MODE_NORMAL (0x01u << 2)
|
||||
#define CRU_GENERAL_MODE_SLOW27 (0x02u << 2)
|
||||
|
||||
#define CRU_CODEC_MODE_MASK (0x03u << 4)
|
||||
#define CRU_CODEC_MODE_SLOW (0x00u << 4)
|
||||
#define CRU_CODEC_MODE_NORMAL (0x01u << 4)
|
||||
#define CRU_CODEC_MODE_SLOW27 (0x02u << 4)
|
||||
|
||||
#define CRU_DDR_MODE_MASK (0x03u << 6)
|
||||
#define CRU_DDR_MODE_SLOW (0x00u << 6)
|
||||
#define CRU_DDR_MODE_NORMAL (0x01u << 6)
|
||||
#define CRU_DDR_MODE_SLOW27 (0x02u << 6)
|
||||
|
||||
/* Clock flags */
|
||||
/* bit 0 is free */
|
||||
#define RATE_FIXED (1 << 1) /* Fixed clock rate */
|
||||
@@ -480,14 +438,16 @@ static struct clk ddr_pll_clk = {
|
||||
|
||||
static int codec_pll_clk_mode(struct clk *clk, int on)
|
||||
{
|
||||
u32 cpll = cru_readl(CRU_CPLL_CON);
|
||||
if (on) {
|
||||
cru_writel(cru_readl(CRU_CPLL_CON) & ~PLL_PD, CRU_CPLL_CON);
|
||||
cru_writel(cpll & ~(PLL_PD | PLL_BYPASS), CRU_CPLL_CON);
|
||||
delay_300us();
|
||||
pll_wait_lock(CODEC_PLL_IDX);
|
||||
cru_writel((cru_readl(CRU_MODE_CON) & ~CRU_CODEC_MODE_MASK) | CRU_CODEC_MODE_NORMAL, CRU_MODE_CON);
|
||||
} else {
|
||||
cru_writel((cru_readl(CRU_MODE_CON) & ~CRU_CODEC_MODE_MASK) | CRU_CODEC_MODE_SLOW, CRU_MODE_CON);
|
||||
cru_writel(cru_readl(CRU_CPLL_CON) | PLL_PD, CRU_CPLL_CON);
|
||||
cru_writel(cpll | PLL_BYPASS, CRU_CPLL_CON);
|
||||
cru_writel(cpll | PLL_PD | PLL_BYPASS, CRU_CPLL_CON);
|
||||
delay_500ns();
|
||||
}
|
||||
return 0;
|
||||
@@ -2241,10 +2201,10 @@ static void __init rk29_clock_common_init(void)
|
||||
/* codec pll */
|
||||
clk_set_rate_nolock(&codec_pll_clk, 552 * MHZ);
|
||||
clk_set_parent_nolock(&clk_gpu, &codec_pll_clk);
|
||||
clk_set_parent_nolock(&clk_mac_ref_div, &codec_pll_clk);
|
||||
|
||||
/* arm pll */
|
||||
clk_set_rate_nolock(&arm_pll_clk, armclk);
|
||||
clk_set_parent_nolock(&clk_mac_ref_div, &arm_pll_clk);
|
||||
}
|
||||
|
||||
static void __init clk_enable_init_clocks(void)
|
||||
|
||||
@@ -13,11 +13,26 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_CPU_FREQ_DEBUG
|
||||
#define DEBUG
|
||||
#endif
|
||||
#define pr_fmt(fmt) "cpufreq: %s: " fmt, __func__
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/cpufreq.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/suspend.h>
|
||||
|
||||
#define SLEEP_FREQ (800 * 1000) /* Use 800MHz when entering sleep */
|
||||
|
||||
/* additional symantics for "relation" in cpufreq with pm */
|
||||
#define DISABLE_FURTHER_CPUFREQ 0x10
|
||||
#define ENABLE_FURTHER_CPUFREQ 0x20
|
||||
#define MASK_FURTHER_CPUFREQ 0x30
|
||||
/* With 0x00(NOCHANGE), it depends on the previous "further" status */
|
||||
static int no_cpufreq_access;
|
||||
|
||||
static struct cpufreq_frequency_table freq_table[] = {
|
||||
// { .index = 950000, .frequency = 204000 },
|
||||
@@ -46,8 +61,28 @@ static int rk29_cpufreq_target(struct cpufreq_policy *policy, unsigned int targe
|
||||
|
||||
if (policy->cpu != 0)
|
||||
return -EINVAL;
|
||||
|
||||
if ((relation & ENABLE_FURTHER_CPUFREQ) &&
|
||||
(relation & DISABLE_FURTHER_CPUFREQ)) {
|
||||
/* Invalidate both if both marked */
|
||||
relation &= ~ENABLE_FURTHER_CPUFREQ;
|
||||
relation &= ~DISABLE_FURTHER_CPUFREQ;
|
||||
pr_err("denied marking FURTHER_CPUFREQ as both marked.\n");
|
||||
}
|
||||
if (relation & ENABLE_FURTHER_CPUFREQ)
|
||||
no_cpufreq_access--;
|
||||
if (no_cpufreq_access) {
|
||||
#ifdef CONFIG_PM_VERBOSE
|
||||
pr_err("denied access to %s as it is disabled temporarily\n", __func__);
|
||||
#endif
|
||||
return -EINVAL;
|
||||
}
|
||||
if (relation & DISABLE_FURTHER_CPUFREQ)
|
||||
no_cpufreq_access++;
|
||||
relation &= ~MASK_FURTHER_CPUFREQ;
|
||||
|
||||
if (cpufreq_frequency_table_target(policy, freq_table, target_freq, relation, &index)) {
|
||||
pr_err("cpufreq: invalid target_freq: %d\n", target_freq);
|
||||
pr_err("invalid target_freq: %d\n", target_freq);
|
||||
return -EINVAL;
|
||||
}
|
||||
freq = &freq_table[index];
|
||||
@@ -58,15 +93,13 @@ static int rk29_cpufreq_target(struct cpufreq_policy *policy, unsigned int targe
|
||||
freqs.old = policy->cur;
|
||||
freqs.new = freq->frequency;
|
||||
freqs.cpu = 0;
|
||||
#ifdef CONFIG_CPU_FREQ_DEBUG
|
||||
printk(KERN_DEBUG "%s %d r %d (%d-%d) selected %d (%duV)\n", __func__, target_freq, relation, policy->min, policy->max, freq->frequency, freq->index);
|
||||
#endif
|
||||
pr_debug("%d r %d (%d-%d) selected %d (%duV)\n", target_freq, relation, policy->min, policy->max, freq->frequency, freq->index);
|
||||
|
||||
#ifdef CONFIG_REGULATOR
|
||||
if (vcore && freqs.new > freqs.old) {
|
||||
err = regulator_set_voltage(vcore, freq->index, freq->index);
|
||||
if (err) {
|
||||
pr_err("cpufreq: fail to set vcore (%duV) for %dkHz: %d\n",
|
||||
pr_err("fail to set vcore (%duV) for %dkHz: %d\n",
|
||||
freq->index, freqs.new, err);
|
||||
goto err_vol;
|
||||
}
|
||||
@@ -82,7 +115,7 @@ static int rk29_cpufreq_target(struct cpufreq_policy *policy, unsigned int targe
|
||||
if (vcore && freqs.new < freqs.old) {
|
||||
err = regulator_set_voltage(vcore, freq->index, freq->index);
|
||||
if (err) {
|
||||
pr_err("cpufreq: fail to set vcore (%duV) for %dkHz: %d\n",
|
||||
pr_err("fail to set vcore (%duV) for %dkHz: %d\n",
|
||||
freq->index, freqs.new, err);
|
||||
}
|
||||
}
|
||||
@@ -106,7 +139,7 @@ static int __init rk29_cpufreq_init(struct cpufreq_policy *policy)
|
||||
#ifdef CONFIG_REGULATOR
|
||||
vcore = regulator_get(NULL, "vcore");
|
||||
if (IS_ERR(vcore)) {
|
||||
pr_err("cpufreq: fail to get regulator vcore: %ld\n", PTR_ERR(vcore));
|
||||
pr_err("fail to get regulator vcore: %ld\n", PTR_ERR(vcore));
|
||||
vcore = NULL;
|
||||
}
|
||||
#endif
|
||||
@@ -143,8 +176,35 @@ static struct cpufreq_driver rk29_cpufreq_driver = {
|
||||
.attr = rk29_cpufreq_attr,
|
||||
};
|
||||
|
||||
static int rk29_cpufreq_pm_notifier_event(struct notifier_block *this,
|
||||
unsigned long event, void *ptr)
|
||||
{
|
||||
int ret;
|
||||
|
||||
switch (event) {
|
||||
case PM_SUSPEND_PREPARE:
|
||||
ret = cpufreq_driver_target(cpufreq_cpu_get(0), SLEEP_FREQ,
|
||||
DISABLE_FURTHER_CPUFREQ);
|
||||
if (ret < 0)
|
||||
return NOTIFY_BAD;
|
||||
return NOTIFY_OK;
|
||||
case PM_POST_RESTORE:
|
||||
case PM_POST_SUSPEND:
|
||||
cpufreq_driver_target(cpufreq_cpu_get(0), SLEEP_FREQ,
|
||||
ENABLE_FURTHER_CPUFREQ);
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
static struct notifier_block rk29_cpufreq_pm_notifier = {
|
||||
.notifier_call = rk29_cpufreq_pm_notifier_event,
|
||||
};
|
||||
|
||||
static int __init rk29_cpufreq_register(void)
|
||||
{
|
||||
register_pm_notifier(&rk29_cpufreq_pm_notifier);
|
||||
|
||||
return cpufreq_register_driver(&rk29_cpufreq_driver);
|
||||
}
|
||||
|
||||
|
||||
@@ -137,6 +137,133 @@ enum cru_clk_gate
|
||||
CLK_GATE_MAX,
|
||||
};
|
||||
|
||||
enum cru_soft_reset {
|
||||
SOFT_RST_ARM_CORE = 0,
|
||||
SOFT_RST_CPU_SYSTEM_INTERCONNECT_1_AXI,
|
||||
SOFT_RST_CPU_SYSTEM_INTERCONNECT_1_AHB,
|
||||
SOFT_RST_CPU_SYSTEM_INTERCONNECT_1_APB,
|
||||
SOFT_RST_CPU_SYSTEM_INTERCONNECT_1_ATB,
|
||||
SOFT_RST_CPU_SYSTEM_INTERCONNECT_2,
|
||||
SOFT_RST_DMA0 = 7,
|
||||
SOFT_RST_GIC,
|
||||
SOFT_RST_INTERNAL_MEMORY,
|
||||
SOFT_RST_TZPC = 11,
|
||||
SOFT_RST_ROM,
|
||||
SOFT_RST_I2S0,
|
||||
SOFT_RST_I2S1,
|
||||
SOFT_RST_SPDIF,
|
||||
SOFT_RST_UART0,
|
||||
SOFT_RST_RTC,
|
||||
SOFT_RST_DDR_PHY,
|
||||
SOFT_RST_DDR_DLL_BYTE0,
|
||||
SOFT_RST_DDR_DLL_BYTE1,
|
||||
SOFT_RST_DDR_DLL_BYTE2,
|
||||
SOFT_RST_DDR_DLL_BYTE3,
|
||||
SOFT_RST_DDR_DLL_CMD,
|
||||
SOFT_RST_DDR_CONTROLLER,
|
||||
SOFT_RST_ARM_CORE_DEBUG,
|
||||
SOFT_RST_DAP_DBG,
|
||||
SOFT_RST_CPU_VODEC_A2A_AHB,
|
||||
SOFT_RST_CPU_DISPLAY_A2A_AHB,
|
||||
SOFT_RST_DAP_SYS,
|
||||
|
||||
SOFT_RST_PERI_SYSTEM_INTERCONNECT_1_AXI = 32,
|
||||
SOFT_RST_PERI_SYSTEM_INTERCONNECT_1_AHB,
|
||||
SOFT_RST_PERI_SYSTEM_INTERCONNECT_1_APB,
|
||||
SOFT_RST_PERIPH_EMEM = 32 + 4,
|
||||
SOFT_RST_PERIPH_USB,
|
||||
SOFT_RST_DMA1,
|
||||
SOFT_RST_MAC,
|
||||
SOFT_RST_HIF,
|
||||
SOFT_RST_NANDC,
|
||||
SOFT_RST_SMC,
|
||||
SOFT_RST_HSADC,
|
||||
SOFT_RST_SDMMC,
|
||||
SOFT_RST_SDIO,
|
||||
SOFT_RST_EMMC,
|
||||
SOFT_RST_USB_OTG_2_0_AHB_BUS,
|
||||
SOFT_RST_USB_OTG_2_0_PHY,
|
||||
SOFT_RST_USB_OTG_2_0_CONTROLLER,
|
||||
SOFT_RST_USB_HOST_2_0_AHB_BUS,
|
||||
SOFT_RST_USB_HOST_2_0_PHY,
|
||||
SOFT_RST_USB_HOST_2_0_CONTROLLER,
|
||||
SOFT_RST_UHOST,
|
||||
SOFT_RST_VIP,
|
||||
SOFT_RST_VIP_MATRIX_AHB,
|
||||
SOFT_RST_SPI0,
|
||||
SOFT_RST_SPI1,
|
||||
SOFT_RST_SARADC,
|
||||
SOFT_RST_UART1,
|
||||
SOFT_RST_UART2,
|
||||
SOFT_RST_UART3,
|
||||
SOFT_RST_PWM,
|
||||
|
||||
SOFT_RST_DISPLAY_INTERCONNECTOR_AXI = 64,
|
||||
SOFT_RST_DISPLAY_INTERCONNECTOR_AHB,
|
||||
SOFT_RST_LCDC,
|
||||
SOFT_RST_IPP,
|
||||
SOFT_RST_EBC,
|
||||
SOFT_RST_GPU = 64 + 7,
|
||||
SOFT_RST_DDR_REG_PORT,
|
||||
SOFT_RST_DDR_CPU_PORT,
|
||||
SOFT_RST_PERIPH_USED_CPU_AXI,
|
||||
SOFT_RST_DDR_PERIPH_PORT,
|
||||
SOFT_RST_DDR_LCDC_PORT,
|
||||
SOFT_RST_DDR_VCODEC_PORT = 64 + 15,
|
||||
SOFT_RST_DDR_GPU_PORT,
|
||||
SOFT_RST_PID_FILTER_AHB,
|
||||
SOFT_RST_VCODEC_AXI_BUS,
|
||||
SOFT_RST_VCODEC_AHB_BUS,
|
||||
SOFT_RST_TIMER0,
|
||||
SOFT_RST_TIMER1,
|
||||
SOFT_RST_TIMER2,
|
||||
SOFT_RST_TIMER3,
|
||||
|
||||
SOFT_RST_MAX,
|
||||
};
|
||||
|
||||
/* CRU MODE CON */
|
||||
#define CRU_CPU_MODE_MASK (0x03u << 0)
|
||||
#define CRU_CPU_MODE_SLOW (0x00u << 0)
|
||||
#define CRU_CPU_MODE_NORMAL (0x01u << 0)
|
||||
#define CRU_CPU_MODE_SLOW27 (0x02u << 0)
|
||||
|
||||
#define CRU_GENERAL_MODE_MASK (0x03u << 2)
|
||||
#define CRU_GENERAL_MODE_SLOW (0x00u << 2)
|
||||
#define CRU_GENERAL_MODE_NORMAL (0x01u << 2)
|
||||
#define CRU_GENERAL_MODE_SLOW27 (0x02u << 2)
|
||||
|
||||
#define CRU_CODEC_MODE_MASK (0x03u << 4)
|
||||
#define CRU_CODEC_MODE_SLOW (0x00u << 4)
|
||||
#define CRU_CODEC_MODE_NORMAL (0x01u << 4)
|
||||
#define CRU_CODEC_MODE_SLOW27 (0x02u << 4)
|
||||
|
||||
#define CRU_DDR_MODE_MASK (0x03u << 6)
|
||||
#define CRU_DDR_MODE_SLOW (0x00u << 6)
|
||||
#define CRU_DDR_MODE_NORMAL (0x01u << 6)
|
||||
#define CRU_DDR_MODE_SLOW27 (0x02u << 6)
|
||||
|
||||
/* CRU PLL CON */
|
||||
#define PLL_HIGH_BAND (0x01 << 16)
|
||||
#define PLL_LOW_BAND (0x00 << 16)
|
||||
#define PLL_PD (0x01 << 15)
|
||||
|
||||
#define PLL_CLKR(i) ((((i) - 1) & 0x1f) << 10)
|
||||
#define PLL_NR(v) ((((v) >> 10) & 0x1f) + 1)
|
||||
|
||||
#define PLL_CLKF(i) ((((i) - 1) & 0x7f) << 3)
|
||||
#define PLL_NF(v) ((((v) >> 3) & 0x7f) + 1)
|
||||
#define PLL_NF2(v) (((((v) >> 3) & 0x7f) + 1) << 1)
|
||||
|
||||
#define PLL_CLKOD(i) (((i) & 0x03) << 1)
|
||||
#define PLL_NO_1 PLL_CLKOD(0)
|
||||
#define PLL_NO_2 PLL_CLKOD(1)
|
||||
#define PLL_NO_4 PLL_CLKOD(2)
|
||||
#define PLL_NO_8 PLL_CLKOD(3)
|
||||
#define PLL_NO_SHIFT(v) (((v) >> 1) & 0x03)
|
||||
|
||||
#define PLL_BYPASS (0x01)
|
||||
|
||||
/* Register definitions */
|
||||
#define CRU_APLL_CON 0x00
|
||||
#define CRU_DPLL_CON 0x04
|
||||
@@ -169,4 +296,24 @@ enum cru_clk_gate
|
||||
#define CRU_SOFTRST1_CON 0x70
|
||||
#define CRU_SOFTRST2_CON 0x74
|
||||
|
||||
static inline void cru_set_soft_reset(enum cru_soft_reset idx, bool on)
|
||||
{
|
||||
unsigned long flags;
|
||||
u32 addr = RK29_CRU_BASE + CRU_SOFTRST0_CON + ((idx >> 5) << 2);
|
||||
u32 mask = 1 << (idx & 31);
|
||||
u32 v;
|
||||
|
||||
if (idx >= SOFT_RST_MAX)
|
||||
return;
|
||||
|
||||
local_irq_save(flags);
|
||||
v = readl(addr);
|
||||
if (on)
|
||||
v |= mask;
|
||||
else
|
||||
v &= ~mask;
|
||||
writel(v, addr);
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
196
arch/arm/mach-rk29/pm.c
Normal file
196
arch/arm/mach-rk29/pm.c
Normal file
@@ -0,0 +1,196 @@
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/suspend.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/wakelock.h>
|
||||
|
||||
#include <mach/rk29_iomap.h>
|
||||
#include <mach/cru.h>
|
||||
#include <mach/pmu.h>
|
||||
#include <mach/board.h>
|
||||
#include <mach/system.h>
|
||||
#include <mach/sram.h>
|
||||
|
||||
#define cru_readl(offset) readl(RK29_CRU_BASE + offset)
|
||||
#define cru_writel(v, offset) do { writel(v, RK29_CRU_BASE + offset); readl(RK29_CRU_BASE + offset); } while (0)
|
||||
#define pmu_readl(offset) readl(RK29_PMU_BASE + offset)
|
||||
#define pmu_writel(v, offset) do { writel(v, RK29_PMU_BASE + offset); readl(RK29_PMU_BASE + offset); } while (0)
|
||||
static unsigned long save_sp;
|
||||
|
||||
static inline void delay_500ns(void)
|
||||
{
|
||||
int delay = 12;
|
||||
while (delay--)
|
||||
barrier();
|
||||
}
|
||||
|
||||
static inline void delay_300us(void)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 600; i++)
|
||||
delay_500ns();
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
u32 clksel0, dpll, mode;
|
||||
|
||||
asm("dsb");
|
||||
ddr_suspend();
|
||||
|
||||
/* 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();
|
||||
|
||||
/* set arm clk 24MHz/32 = 750KHz */
|
||||
clksel0 = cru_readl(CRU_CLKSEL0_CON);
|
||||
cru_writel(clksel0 | 0x1F, CRU_CLKSEL0_CON);
|
||||
|
||||
asm("wfi");
|
||||
|
||||
/* resume arm clk */
|
||||
cru_writel(clksel0, CRU_CLKSEL0_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);
|
||||
|
||||
ddr_resume();
|
||||
}
|
||||
|
||||
static int rk29_pm_enter(suspend_state_t state)
|
||||
{
|
||||
u32 cpll, gpll, mode;
|
||||
|
||||
mode = cru_readl(CRU_MODE_CON);
|
||||
|
||||
/* suspend codec pll */
|
||||
cpll = cru_readl(CRU_CPLL_CON);
|
||||
cru_writel((cru_readl(CRU_MODE_CON) & ~CRU_CODEC_MODE_MASK) | CRU_CODEC_MODE_SLOW, CRU_MODE_CON);
|
||||
cru_writel(cpll | PLL_BYPASS, CRU_CPLL_CON);
|
||||
cru_writel(cpll | PLL_PD | PLL_BYPASS, CRU_CPLL_CON);
|
||||
delay_500ns();
|
||||
|
||||
/* suspend general pll */
|
||||
gpll = cru_readl(CRU_GPLL_CON);
|
||||
cru_writel((cru_readl(CRU_MODE_CON) & ~CRU_GENERAL_MODE_MASK) | CRU_GENERAL_MODE_SLOW, CRU_MODE_CON);
|
||||
cru_writel(gpll | PLL_BYPASS, CRU_GPLL_CON);
|
||||
cru_writel(gpll | PLL_PD | PLL_BYPASS, CRU_GPLL_CON);
|
||||
delay_500ns();
|
||||
|
||||
DDR_SAVE_SP(save_sp);
|
||||
rk29_pm_enter_ddr();
|
||||
DDR_RESTORE_SP(save_sp);
|
||||
|
||||
/* resume general pll */
|
||||
cru_writel(gpll, CRU_GPLL_CON);
|
||||
delay_300us();
|
||||
cru_writel((cru_readl(CRU_MODE_CON) & ~CRU_GENERAL_MODE_MASK) | (mode & CRU_GENERAL_MODE_MASK), CRU_MODE_CON);
|
||||
|
||||
/* 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);
|
||||
|
||||
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__);
|
||||
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 = {
|
||||
.enter = rk29_pm_enter,
|
||||
.valid = suspend_valid_only_mem,
|
||||
.prepare = rk29_pm_prepare,
|
||||
.finish = rk29_pm_finish,
|
||||
};
|
||||
|
||||
static void rk29_idle(void)
|
||||
{
|
||||
if (!need_resched()) {
|
||||
int allow_sleep = 1;
|
||||
#ifdef CONFIG_HAS_WAKELOCK
|
||||
allow_sleep = !has_wake_lock(WAKE_LOCK_IDLE);
|
||||
#endif
|
||||
if (allow_sleep) {
|
||||
u32 mode_con = cru_readl(CRU_MODE_CON);
|
||||
cru_writel((mode_con & ~CRU_CPU_MODE_MASK) | CRU_CPU_MODE_SLOW, CRU_MODE_CON);
|
||||
arch_idle();
|
||||
cru_writel((mode_con & ~CRU_CPU_MODE_MASK) | CRU_CPU_MODE_NORMAL, CRU_MODE_CON);
|
||||
} else {
|
||||
arch_idle();
|
||||
}
|
||||
}
|
||||
local_irq_enable();
|
||||
}
|
||||
|
||||
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 */
|
||||
pm_idle = rk29_idle;
|
||||
|
||||
return 0;
|
||||
}
|
||||
__initcall(rk29_pm_init);
|
||||
Reference in New Issue
Block a user