aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-rockchip
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-rockchip')
-rw-r--r--arch/arm/mach-rockchip/platsmp.c56
-rw-r--r--arch/arm/mach-rockchip/pm.c78
-rw-r--r--arch/arm/mach-rockchip/pm.h12
3 files changed, 104 insertions, 42 deletions
diff --git a/arch/arm/mach-rockchip/platsmp.c b/arch/arm/mach-rockchip/platsmp.c
index 8fcec1cc101e..3e7a4b761a95 100644
--- a/arch/arm/mach-rockchip/platsmp.c
+++ b/arch/arm/mach-rockchip/platsmp.c
@@ -72,29 +72,22 @@ static struct reset_control *rockchip_get_core_reset(int cpu)
static int pmu_set_power_domain(int pd, bool on)
{
u32 val = (on) ? 0 : BIT(pd);
+ struct reset_control *rstc = rockchip_get_core_reset(pd);
int ret;
+ if (IS_ERR(rstc) && read_cpuid_part() != ARM_CPU_PART_CORTEX_A9) {
+ pr_err("%s: could not get reset control for core %d\n",
+ __func__, pd);
+ return PTR_ERR(rstc);
+ }
+
/*
* We need to soft reset the cpu when we turn off the cpu power domain,
* or else the active processors might be stalled when the individual
* processor is powered down.
*/
- if (read_cpuid_part() != ARM_CPU_PART_CORTEX_A9) {
- struct reset_control *rstc = rockchip_get_core_reset(pd);
-
- if (IS_ERR(rstc)) {
- pr_err("%s: could not get reset control for core %d\n",
- __func__, pd);
- return PTR_ERR(rstc);
- }
-
- if (on)
- reset_control_deassert(rstc);
- else
- reset_control_assert(rstc);
-
- reset_control_put(rstc);
- }
+ if (!IS_ERR(rstc) && !on)
+ reset_control_assert(rstc);
ret = regmap_update_bits(pmu, PMU_PWRDN_CON, BIT(pd), val);
if (ret < 0) {
@@ -107,11 +100,17 @@ static int pmu_set_power_domain(int pd, bool on)
ret = pmu_power_domain_is_on(pd);
if (ret < 0) {
pr_err("%s: could not read power domain state\n",
- __func__);
+ __func__);
return ret;
}
}
+ if (!IS_ERR(rstc)) {
+ if (on)
+ reset_control_deassert(rstc);
+ reset_control_put(rstc);
+ }
+
return 0;
}
@@ -130,7 +129,7 @@ static int rockchip_boot_secondary(unsigned int cpu, struct task_struct *idle)
if (cpu >= ncores) {
pr_err("%s: cpu %d outside maximum number of cpus %d\n",
- __func__, cpu, ncores);
+ __func__, cpu, ncores);
return -ENXIO;
}
@@ -140,14 +139,19 @@ static int rockchip_boot_secondary(unsigned int cpu, struct task_struct *idle)
return ret;
if (read_cpuid_part() != ARM_CPU_PART_CORTEX_A9) {
- /* We communicate with the bootrom to active the cpus other
+ /*
+ * We communicate with the bootrom to active the cpus other
* than cpu0, after a blob of initialize code, they will
* stay at wfe state, once they are actived, they will check
* the mailbox:
* sram_base_addr + 4: 0xdeadbeaf
* sram_base_addr + 8: start address for pc
- * */
- udelay(10);
+ * The cpu0 need to wait the other cpus other than cpu0 entering
+ * the wfe state.The wait time is affected by many aspects.
+ * (e.g: cpu frequency, bootrom frequency, sram frequency, ...)
+ */
+ mdelay(1); /* ensure the cpus other than cpu0 to startup */
+
writel(virt_to_phys(secondary_startup), sram_base_addr + 8);
writel(0xDEADBEAF, sram_base_addr + 4);
dsb_sev();
@@ -317,6 +321,13 @@ static void __init rockchip_smp_prepare_cpus(unsigned int max_cpus)
#ifdef CONFIG_HOTPLUG_CPU
static int rockchip_cpu_kill(unsigned int cpu)
{
+ /*
+ * We need a delay here to ensure that the dying CPU can finish
+ * executing v7_coherency_exit() and reach the WFI/WFE state
+ * prior to having the power domain disabled.
+ */
+ mdelay(1);
+
pmu_set_power_domain(0 + cpu, false);
return 1;
}
@@ -324,7 +335,7 @@ static int rockchip_cpu_kill(unsigned int cpu)
static void rockchip_cpu_die(unsigned int cpu)
{
v7_exit_coherency_flush(louis);
- while(1)
+ while (1)
cpu_do_idle();
}
#endif
@@ -337,4 +348,5 @@ static struct smp_operations rockchip_smp_ops __initdata = {
.cpu_die = rockchip_cpu_die,
#endif
};
+
CPU_METHOD_OF_DECLARE(rk3066_smp, "rockchip,rk3066-smp", &rockchip_smp_ops);
diff --git a/arch/arm/mach-rockchip/pm.c b/arch/arm/mach-rockchip/pm.c
index b0dcbe28f78c..bee8c8051929 100644
--- a/arch/arm/mach-rockchip/pm.c
+++ b/arch/arm/mach-rockchip/pm.c
@@ -45,9 +45,11 @@ static phys_addr_t rk3288_bootram_phy;
static struct regmap *pmu_regmap;
static struct regmap *sgrf_regmap;
+static struct regmap *grf_regmap;
static u32 rk3288_pmu_pwr_mode_con;
static u32 rk3288_sgrf_soc_con0;
+static u32 rk3288_sgrf_cpu_con0;
static inline u32 rk3288_l2_config(void)
{
@@ -66,10 +68,37 @@ static void rk3288_config_bootdata(void)
rkpm_bootdata_l2ctlr = rk3288_l2_config();
}
+#define GRF_UOC0_CON0 0x320
+#define GRF_UOC1_CON0 0x334
+#define GRF_UOC2_CON0 0x348
+#define GRF_SIDDQ BIT(13)
+
+static bool rk3288_slp_disable_osc(void)
+{
+ static const u32 reg_offset[] = { GRF_UOC0_CON0, GRF_UOC1_CON0,
+ GRF_UOC2_CON0 };
+ u32 reg, i;
+
+ /*
+ * if any usb phy is still on(GRF_SIDDQ==0), that means we need the
+ * function of usb wakeup, so do not switch to 32khz, since the usb phy
+ * clk does not connect to 32khz osc
+ */
+ for (i = 0; i < ARRAY_SIZE(reg_offset); i++) {
+ regmap_read(grf_regmap, reg_offset[i], &reg);
+ if (!(reg & GRF_SIDDQ))
+ return false;
+ }
+
+ return true;
+}
+
static void rk3288_slp_mode_set(int level)
{
u32 mode_set, mode_set1;
+ bool osc_disable = rk3288_slp_disable_osc();
+ regmap_read(sgrf_regmap, RK3288_SGRF_CPU_CON0, &rk3288_sgrf_cpu_con0);
regmap_read(sgrf_regmap, RK3288_SGRF_SOC_CON0, &rk3288_sgrf_soc_con0);
regmap_read(pmu_regmap, RK3288_PMU_PWRMODE_CON,
@@ -94,9 +123,6 @@ static void rk3288_slp_mode_set(int level)
regmap_write(sgrf_regmap, RK3288_SGRF_FAST_BOOT_ADDR,
rk3288_bootram_phy);
- regmap_write(pmu_regmap, RK3288_PMU_WAKEUP_CFG1,
- PMU_ARMINT_WAKEUP_EN);
-
mode_set = BIT(PMU_GLOBAL_INT_DISABLE) | BIT(PMU_L2FLUSH_EN) |
BIT(PMU_SREF0_ENTER_EN) | BIT(PMU_SREF1_ENTER_EN) |
BIT(PMU_DDR0_GATING_EN) | BIT(PMU_DDR1_GATING_EN) |
@@ -107,13 +133,31 @@ static void rk3288_slp_mode_set(int level)
if (level == ROCKCHIP_ARM_OFF_LOGIC_DEEP) {
/* arm off, logic deep sleep */
- mode_set |= BIT(PMU_BUS_PD_EN) |
+ mode_set |= BIT(PMU_BUS_PD_EN) | BIT(PMU_PMU_USE_LF) |
BIT(PMU_DDR1IO_RET_EN) | BIT(PMU_DDR0IO_RET_EN) |
- BIT(PMU_OSC_24M_DIS) | BIT(PMU_PMU_USE_LF) |
BIT(PMU_ALIVE_USE_LF) | BIT(PMU_PLL_PD_EN);
+ if (osc_disable)
+ mode_set |= BIT(PMU_OSC_24M_DIS);
+
mode_set1 |= BIT(PMU_CLR_ALIVE) | BIT(PMU_CLR_BUS) |
BIT(PMU_CLR_PERI) | BIT(PMU_CLR_DMA);
+
+ regmap_write(pmu_regmap, RK3288_PMU_WAKEUP_CFG1,
+ PMU_ARMINT_WAKEUP_EN);
+
+ /*
+ * In deep suspend we use PMU_PMU_USE_LF to let the rk3288
+ * switch its main clock supply to the alternative 32kHz
+ * source. Therefore set 30ms on a 32kHz clock for pmic
+ * stabilization. Similar 30ms on 24MHz for the other
+ * mode below.
+ */
+ regmap_write(pmu_regmap, RK3288_PMU_STABL_CNT, 32 * 30);
+
+ /* only wait for stabilization, if we turned the osc off */
+ regmap_write(pmu_regmap, RK3288_PMU_OSC_CNT,
+ osc_disable ? 32 * 30 : 0);
} else {
/*
* arm off, logic normal
@@ -121,6 +165,15 @@ static void rk3288_slp_mode_set(int level)
* wakeup will be error
*/
mode_set |= BIT(PMU_CLK_CORE_SRC_GATE_EN);
+
+ regmap_write(pmu_regmap, RK3288_PMU_WAKEUP_CFG1,
+ PMU_ARMINT_WAKEUP_EN | PMU_GPIOINT_WAKEUP_EN);
+
+ /* 30ms on a 24MHz clock for pmic stabilization */
+ regmap_write(pmu_regmap, RK3288_PMU_STABL_CNT, 24000 * 30);
+
+ /* oscillator is still running, so no need to wait */
+ regmap_write(pmu_regmap, RK3288_PMU_OSC_CNT, 0);
}
regmap_write(pmu_regmap, RK3288_PMU_PWRMODE_CON, mode_set);
@@ -129,6 +182,9 @@ static void rk3288_slp_mode_set(int level)
static void rk3288_slp_mode_set_resume(void)
{
+ regmap_write(sgrf_regmap, RK3288_SGRF_CPU_CON0,
+ rk3288_sgrf_cpu_con0 | SGRF_DAPDEVICEEN_WRITE);
+
regmap_write(pmu_regmap, RK3288_PMU_PWRMODE_CON,
rk3288_pmu_pwr_mode_con);
@@ -190,7 +246,14 @@ static int rk3288_suspend_init(struct device_node *np)
"rockchip,rk3288-sgrf");
if (IS_ERR(sgrf_regmap)) {
pr_err("%s: could not find sgrf regmap\n", __func__);
- return PTR_ERR(pmu_regmap);
+ return PTR_ERR(sgrf_regmap);
+ }
+
+ grf_regmap = syscon_regmap_lookup_by_compatible(
+ "rockchip,rk3288-grf");
+ if (IS_ERR(grf_regmap)) {
+ pr_err("%s: could not find grf regmap\n", __func__);
+ return PTR_ERR(grf_regmap);
}
sram_np = of_find_compatible_node(NULL, NULL,
@@ -221,9 +284,6 @@ static int rk3288_suspend_init(struct device_node *np)
memcpy(rk3288_bootram_base, rockchip_slp_cpu_resume,
rk3288_bootram_sz);
- regmap_write(pmu_regmap, RK3288_PMU_OSC_CNT, OSC_STABL_CNT_THRESH);
- regmap_write(pmu_regmap, RK3288_PMU_STABL_CNT, PMU_STABL_CNT_THRESH);
-
return 0;
}
diff --git a/arch/arm/mach-rockchip/pm.h b/arch/arm/mach-rockchip/pm.h
index 3e8d39c0c3d5..b5af26f8336e 100644
--- a/arch/arm/mach-rockchip/pm.h
+++ b/arch/arm/mach-rockchip/pm.h
@@ -59,19 +59,9 @@ static inline void rockchip_suspend_init(void)
#define SGRF_DAPDEVICEEN BIT(0)
#define SGRF_DAPDEVICEEN_WRITE BIT(16)
-#define RK3288_CRU_MODE_CON 0x50
-#define RK3288_CRU_SEL0_CON 0x60
-#define RK3288_CRU_SEL1_CON 0x64
-#define RK3288_CRU_SEL10_CON 0x88
-#define RK3288_CRU_SEL33_CON 0xe4
-#define RK3288_CRU_SEL37_CON 0xf4
-
/* PMU_WAKEUP_CFG1 bits */
#define PMU_ARMINT_WAKEUP_EN BIT(0)
-
-/* wait 30ms for OSC stable and 30ms for pmic stable */
-#define OSC_STABL_CNT_THRESH (32 * 30)
-#define PMU_STABL_CNT_THRESH (32 * 30)
+#define PMU_GPIOINT_WAKEUP_EN BIT(3)
enum rk3288_pwr_mode_con {
PMU_PWR_MODE_EN = 0,