summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCaesar Wang <wxt@rock-chips.com>2016-10-12 01:47:51 +0800
committerCaesar Wang <wxt@rock-chips.com>2016-10-25 03:29:58 +0800
commit7ac520067cd35c1f8754e8caa3c128715a56a4c3 (patch)
treee218d33c49708212e45fb65e067687b6fdaeb250
parent8382e17c4c6bffd15119dfce1ee4372e3c1a7890 (diff)
rockchip: clear the power mode status via M0
Due to the PMU design, the PMU may not clear the WAKEUP bit after wakeup, therefore, the state machine at the power mode may enter the infinite loop during WFI. There is a solution that we can use the M0 to monitor the WAKEUP bit and clear it during power mode, then the state machine will be recovered immediately. Then, the DUT can exit the WFI normally. Change-Id: I303628553b728c214bf2d436bd3122032b5e669c Signed-off-by: Xing Zheng <zhengxing@rock-chips.com> Signed-off-by: Caesar Wang <wxt@rock-chips.com>
-rw-r--r--plat/rockchip/common/plat_pm.c13
-rw-r--r--plat/rockchip/rk3399/drivers/pmu/pmu.c83
-rw-r--r--plat/rockchip/rk3399/drivers/soc/soc.c16
-rw-r--r--plat/rockchip/rk3399/drivers/soc/soc.h12
4 files changed, 67 insertions, 57 deletions
diff --git a/plat/rockchip/common/plat_pm.c b/plat/rockchip/common/plat_pm.c
index d28100d9..e926345b 100644
--- a/plat/rockchip/common/plat_pm.c
+++ b/plat/rockchip/common/plat_pm.c
@@ -317,18 +317,6 @@ static void __dead2 rockchip_system_poweroff(void)
rockchip_ops->system_off();
}
-static void
-__dead2 rockchip_pwr_domain_pwr_down_wfi(const psci_power_state_t *target_state)
-{
- if ((RK_CORE_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) &&
- (rockchip_ops)) {
- if (RK_SYSTEM_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE &&
- rockchip_ops->sys_pwr_down_wfi)
- rockchip_ops->sys_pwr_down_wfi(target_state);
- }
- psci_power_down_wfi();
-}
-
/*******************************************************************************
* Export the platform handlers via plat_rockchip_psci_pm_ops. The rockchip
* standard
@@ -341,7 +329,6 @@ const plat_psci_ops_t plat_rockchip_psci_pm_ops = {
.pwr_domain_suspend = rockchip_pwr_domain_suspend,
.pwr_domain_on_finish = rockchip_pwr_domain_on_finish,
.pwr_domain_suspend_finish = rockchip_pwr_domain_suspend_finish,
- .pwr_domain_pwr_down_wfi = rockchip_pwr_domain_pwr_down_wfi,
.system_reset = rockchip_system_reset,
.system_off = rockchip_system_poweroff,
.validate_power_state = rockchip_validate_power_state,
diff --git a/plat/rockchip/rk3399/drivers/pmu/pmu.c b/plat/rockchip/rk3399/drivers/pmu/pmu.c
index 4ae766ce..8d3f482f 100644
--- a/plat/rockchip/rk3399/drivers/pmu/pmu.c
+++ b/plat/rockchip/rk3399/drivers/pmu/pmu.c
@@ -48,6 +48,7 @@
#include <pwm.h>
#include <soc.h>
#include <bl31.h>
+#include <rk3399m0.h>
DEFINE_BAKERY_LOCK(rockchip_pd_lock);
@@ -840,8 +841,6 @@ static void sys_slp_config(void)
BIT(PMU_SCU_PD_EN) |
BIT(PMU_CCI_PD_EN) |
BIT(PMU_CLK_CORE_SRC_GATE_EN) |
- BIT(PMU_PERILP_PD_EN) |
- BIT(PMU_CLK_PERILP_SRC_GATE_EN) |
BIT(PMU_ALIVE_USE_LF) |
BIT(PMU_SREF0_ENTER_EN) |
BIT(PMU_SREF1_ENTER_EN) |
@@ -1058,6 +1057,38 @@ static void resume_gpio(void)
}
}
+static void m0_clock_init(void)
+{
+ /* enable clocks for M0 */
+ mmio_write_32(PMUCRU_BASE + PMUCRU_CLKGATE_CON2,
+ BITS_WITH_WMASK(0x0, 0x2f, 0));
+
+ /* switch the parent to xin24M and div == 1 */
+ mmio_write_32(PMUCRU_BASE + PMUCRU_CLKSEL_CON0,
+ BIT_WITH_WMSK(15) | BITS_WITH_WMASK(0x0, 0x1f, 8));
+
+ /* start M0 */
+ mmio_write_32(PMUCRU_BASE + PMUCRU_SOFTRST_CON0,
+ BITS_WITH_WMASK(0x0, 0x24, 0));
+
+ /* gating disable for M0 */
+ mmio_write_32(PMUCRU_BASE + PMUCRU_GATEDIS_CON0, BIT_WITH_WMSK(1));
+}
+
+static void m0_reset(void)
+{
+ /* stop M0 */
+ mmio_write_32(PMUCRU_BASE + PMUCRU_SOFTRST_CON0,
+ BITS_WITH_WMASK(0x24, 0x24, 0));
+
+ /* recover gating bit for M0 */
+ mmio_write_32(PMUCRU_BASE + PMUCRU_GATEDIS_CON0, WMSK_BIT(1));
+
+ /* disable clocks for M0 */
+ mmio_write_32(PMUCRU_BASE + PMUCRU_CLKGATE_CON2,
+ BITS_WITH_WMASK(0x2f, 0x2f, 0));
+}
+
static int sys_pwr_domain_suspend(void)
{
uint32_t wait_cnt = 0;
@@ -1071,12 +1102,12 @@ static int sys_pwr_domain_suspend(void)
BIT(PMU_CLR_CCIM0) |
BIT(PMU_CLR_CCIM1) |
BIT(PMU_CLR_CENTER) |
- BIT(PMU_CLR_PERILP) |
- BIT(PMU_CLR_PMU) |
- BIT(PMU_CLR_PERILPM0) |
BIT(PMU_CLR_GIC));
sys_slp_config();
+
+ m0_clock_init();
+
pmu_sgrf_rst_hld();
mmio_write_32(SGRF_BASE + SGRF_SOC_CON0_1(1),
@@ -1111,6 +1142,7 @@ static int sys_pwr_domain_suspend(void)
disable_dvfs_plls();
disable_pwms();
disable_nodvfs_plls();
+
suspend_apio();
suspend_gpio();
@@ -1186,12 +1218,12 @@ static int sys_pwr_domain_resume(void)
BIT(PMU_CLR_CCIM0) |
BIT(PMU_CLR_CCIM1) |
BIT(PMU_CLR_CENTER) |
- BIT(PMU_CLR_PERILP) |
- BIT(PMU_CLR_PMU) |
BIT(PMU_CLR_GIC));
plat_rockchip_gic_cpuif_enable();
+ m0_reset();
+
return 0;
}
@@ -1236,42 +1268,6 @@ void __dead2 soc_system_off(void)
while (1)
;
}
-static void __dead2 sys_pwr_down_wfi(const psci_power_state_t *target_state)
-{
- uint32_t wakeup_status;
-
- /*
- * Check wakeup status and abort suspend early if we see a wakeup
- * event.
- *
- * NOTE: technically I we're supposed to just execute a wfi here and
- * we'll either execute a normal suspend/resume or the wfi will be
- * treated as a no-op if a wake event was present and caused an abort
- * of the suspend/resume. For some reason that's not happening and if
- * we execute the wfi while a wake event is pending then the whole
- * system wedges.
- *
- * Until the above is solved this extra check prevents system wedges in
- * most cases but there is still a small race condition between checking
- * PMU_WAKEUP_STATUS and executing wfi. If a wake event happens in
- * there then we will die.
- */
- wakeup_status = mmio_read_32(PMU_BASE + PMU_WAKEUP_STATUS);
- if (wakeup_status) {
- WARN("early wake, will not enter power mode.\n");
-
- mmio_write_32(PMU_BASE + PMU_PWRMODE_CON, 0);
-
- disable_mmu_icache_el3();
- bl31_warm_entrypoint();
-
- while (1)
- ;
- } else {
- /* Enter WFI */
- psci_power_down_wfi();
- }
-}
static struct rockchip_pm_ops_cb pm_ops = {
.cores_pwr_dm_on = cores_pwr_domain_on,
@@ -1287,7 +1283,6 @@ static struct rockchip_pm_ops_cb pm_ops = {
.sys_pwr_dm_resume = sys_pwr_domain_resume,
.sys_gbl_soft_reset = soc_soft_reset,
.system_off = soc_system_off,
- .sys_pwr_down_wfi = sys_pwr_down_wfi,
};
void plat_rockchip_pmu_init(void)
diff --git a/plat/rockchip/rk3399/drivers/soc/soc.c b/plat/rockchip/rk3399/drivers/soc/soc.c
index 29bf6dda..2dc70ec2 100644
--- a/plat/rockchip/rk3399/drivers/soc/soc.c
+++ b/plat/rockchip/rk3399/drivers/soc/soc.c
@@ -35,6 +35,7 @@
#include <platform_def.h>
#include <plat_private.h>
#include <rk3399_def.h>
+#include <rk3399m0.h>
#include <soc.h>
/* Table of regions to map using the MMU. */
@@ -380,6 +381,20 @@ void __dead2 soc_global_soft_reset(void)
;
}
+static void soc_m0_init(void)
+{
+ /* secure config for pmu M0 */
+ mmio_write_32(SGRF_BASE + SGRF_PMU_CON(0), WMSK_BIT(7));
+
+ /* set the execute address for M0 */
+ mmio_write_32(SGRF_BASE + SGRF_PMU_CON(3),
+ BITS_WITH_WMASK((M0_BINCODE_BASE >> 12) & 0xffff,
+ 0xffff, 0));
+ mmio_write_32(SGRF_BASE + SGRF_PMU_CON(7),
+ BITS_WITH_WMASK((M0_BINCODE_BASE >> 28) & 0xf,
+ 0xf, 0));
+}
+
void plat_rockchip_soc_init(void)
{
secure_timer_init();
@@ -387,4 +402,5 @@ void plat_rockchip_soc_init(void)
sgrf_init();
soc_global_soft_reset_init();
plat_rockchip_gpio_init();
+ soc_m0_init();
}
diff --git a/plat/rockchip/rk3399/drivers/soc/soc.h b/plat/rockchip/rk3399/drivers/soc/soc.h
index 906452a3..da4cb54e 100644
--- a/plat/rockchip/rk3399/drivers/soc/soc.h
+++ b/plat/rockchip/rk3399/drivers/soc/soc.h
@@ -293,6 +293,18 @@ struct deepsleep_data_s {
#define GRF_DDRC1_CON0 0xe388
#define GRF_DDRC1_CON1 0xe38c
+#define PMUCRU_CLKSEL_CON0 0x0080
+#define PMUCRU_CLKGATE_CON2 0x0108
+#define PMUCRU_SOFTRST_CON0 0x0110
+#define PMUCRU_GATEDIS_CON0 0x0130
+
+#define SGRF_SOC_CON6 0x0e018
+#define SGRF_PERILP_CON0 0x08100
+#define SGRF_PERILP_CON(n) (SGRF_PERILP_CON0 + (n) * 4)
+#define SGRF_PMU_CON0 0x0c100
+#define SGRF_PMU_CON(n) (SGRF_PMU_CON0 + (n) * 4)
+#define PMUCRU_SOFTRST_CON(n) (PMUCRU_SOFTRST_CON0 + (n) * 4)
+
/*
* When system reset in running state, we want the cpus to be reboot
* from maskrom (system reboot),