From a14e09162172e016ce3586ec4048bc7614d4bf1f Mon Sep 17 00:00:00 2001 From: Caesar Wang Date: Fri, 4 Nov 2016 21:13:01 +0800 Subject: [PATCH 1/2] rockchip: disable watchdog during suspend The CA53 and CM0 WDT clock gating in rk3399 SGRF, and ATF is in charge of it because the kernel can't touch SGRF. Basically the WDT didn't stop at suspend time, it just switched from the 24M to the 32k clock. That meant that the WDT would fire if you slept for long enough. In other word, the watchdog timer over count will increase to 750 (24*1000/32) times. The RK3399 HW watchdog interval is 21 seconds. When machine enters the suspend, the watchdog will reset the system after 35.7 (750/21) hours. BUG=chrome-os-partner:59257 TEST=daisydog checked and set value, powerd_dbus_suspend to verify. Change-Id: I88bb2a05b7d67d5ffd292f9d05d033ae9a6a3593 Signed-off-by: Caesar Wang --- plat/rockchip/rk3399/drivers/pmu/pmu.c | 4 ++++ plat/rockchip/rk3399/drivers/soc/soc.c | 22 ++++++++++++++++++++++ plat/rockchip/rk3399/drivers/soc/soc.h | 18 ++++++++++++++++++ 3 files changed, 44 insertions(+) diff --git a/plat/rockchip/rk3399/drivers/pmu/pmu.c b/plat/rockchip/rk3399/drivers/pmu/pmu.c index 5a385cb34..3631a3045 100644 --- a/plat/rockchip/rk3399/drivers/pmu/pmu.c +++ b/plat/rockchip/rk3399/drivers/pmu/pmu.c @@ -1144,6 +1144,8 @@ static int sys_pwr_domain_suspend(void) } mmio_setbits_32(PMU_BASE + PMU_PWRDN_CON, BIT(PMU_SCU_B_PWRDWN_EN)); + secure_watchdog_disable(); + /* * Disabling PLLs/PWM/DVFS is approaching WFI which is * the last steps in suspend. @@ -1173,6 +1175,8 @@ static int sys_pwr_domain_resume(void) enable_dvfs_plls(); plls_resume_finish(); + secure_watchdog_restore(); + /* restore clk_ddrc_bpll_src_en gate */ mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(3), BITS_WITH_WMASK(clk_ddrc_save, 0xff, 0)); diff --git a/plat/rockchip/rk3399/drivers/soc/soc.c b/plat/rockchip/rk3399/drivers/soc/soc.c index 9529cb25f..f77b74f24 100644 --- a/plat/rockchip/rk3399/drivers/soc/soc.c +++ b/plat/rockchip/rk3399/drivers/soc/soc.c @@ -192,6 +192,28 @@ static void dma_secure_cfg(uint32_t secure) /* pll suspend */ struct deepsleep_data_s slp_data; +void secure_watchdog_disable(void) +{ + slp_data.sgrf_con[3] = mmio_read_32(SGRF_BASE + SGRF_SOC_CON3_7(3)); + + /* disable CA53 wdt pclk */ + mmio_write_32(SGRF_BASE + SGRF_SOC_CON3_7(3), + BITS_WITH_WMASK(WDT_CA53_DIS, WDT_CA53_1BIT_MASK, + PCLK_WDT_CA53_GATE_SHIFT)); + /* disable CM0 wdt pclk */ + mmio_write_32(SGRF_BASE + SGRF_SOC_CON3_7(3), + BITS_WITH_WMASK(WDT_CM0_DIS, WDT_CM0_1BIT_MASK, + PCLK_WDT_CM0_GATE_SHIFT)); +} + +void secure_watchdog_restore(void) +{ + mmio_write_32(SGRF_BASE + SGRF_SOC_CON3_7(3), + slp_data.sgrf_con[3] | + WMSK_BIT(PCLK_WDT_CA53_GATE_SHIFT) | + WMSK_BIT(PCLK_WDT_CM0_GATE_SHIFT)); +} + static void pll_suspend_prepare(uint32_t pll_id) { int i; diff --git a/plat/rockchip/rk3399/drivers/soc/soc.h b/plat/rockchip/rk3399/drivers/soc/soc.h index 16897cc5b..bbca7bc08 100644 --- a/plat/rockchip/rk3399/drivers/soc/soc.h +++ b/plat/rockchip/rk3399/drivers/soc/soc.h @@ -73,6 +73,7 @@ #define REG_SOC_WMSK 0xffff0000 #define CLK_GATE_MASK 0x01 +#define SGRF_SOC_COUNT 0x17 #define PMUCRU_GATE_COUNT 0x03 #define CRU_GATE_COUNT 0x23 #define PMUCRU_GATE_CON(n) (0x100 + (n) * 4) @@ -111,6 +112,7 @@ struct deepsleep_data_s { uint32_t cru_clksel_con[CRU_CLKSEL_COUNT]; uint32_t cru_gate_con[CRU_GATE_COUNT]; uint32_t pmucru_gate_con[PMUCRU_GATE_COUNT]; + uint32_t sgrf_con[SGRF_SOC_COUNT]; }; /************************************************** @@ -172,6 +174,20 @@ struct deepsleep_data_s { #define TIMER_FMODE (0x0 << 1) #define TIMER_RMODE (0x1 << 1) +/************************************************** + * secure WDT + **************************************************/ +#define WDT_CM0_EN 0x0 +#define WDT_CM0_DIS 0x1 +#define WDT_CA53_EN 0x0 +#define WDT_CA53_DIS 0x1 + +#define PCLK_WDT_CA53_GATE_SHIFT 8 +#define PCLK_WDT_CM0_GATE_SHIFT 10 + +#define WDT_CA53_1BIT_MASK 0x1 +#define WDT_CM0_1BIT_MASK 0x1 + /************************************************** * cru reg, offset **************************************************/ @@ -330,6 +346,8 @@ static inline void pmu_sgrf_rst_hld(void) /* funciton*/ void __dead2 soc_global_soft_reset(void); +void secure_watchdog_disable(); +void secure_watchdog_restore(); void plls_suspend_prepare(void); void disable_dvfs_plls(void); void disable_nodvfs_plls(void); From 06077161e9be0a007dbb02c8d04f4b08805d89e0 Mon Sep 17 00:00:00 2001 From: Caesar Wang Date: Tue, 25 Oct 2016 17:14:40 -0700 Subject: [PATCH 2/2] rockchip: remove no needed code for rk3399 We have do something for clocks gate. Fox example as the below: susped: clk_gate_con_save(); clk_gate_con_disable(); resume: clk_gate_con_restore(); -- SO, add the plls_suspend_prepare() and plls_resume_finish() are not necessary to S2R, that will save S2R time if remove them. BRANCH=none BUG=chrome-os-partner:58870,chrome-os-partner:55934 TEST=build kevin, two dogfooders with suspend_stress_test passing 3000 cycles and still going on. Change-Id: Icfbabc0b3ea8d2b5108d4f3de99a803b6d459669 Signed-off-by: Caesar Wang --- plat/rockchip/rk3399/drivers/pmu/pmu.c | 2 - plat/rockchip/rk3399/drivers/soc/soc.c | 51 -------------------------- plat/rockchip/rk3399/drivers/soc/soc.h | 2 - 3 files changed, 55 deletions(-) diff --git a/plat/rockchip/rk3399/drivers/pmu/pmu.c b/plat/rockchip/rk3399/drivers/pmu/pmu.c index 3631a3045..05ca7fdd2 100644 --- a/plat/rockchip/rk3399/drivers/pmu/pmu.c +++ b/plat/rockchip/rk3399/drivers/pmu/pmu.c @@ -1150,7 +1150,6 @@ static int sys_pwr_domain_suspend(void) * Disabling PLLs/PWM/DVFS is approaching WFI which is * the last steps in suspend. */ - plls_suspend_prepare(); disable_dvfs_plls(); disable_pwms(); disable_nodvfs_plls(); @@ -1173,7 +1172,6 @@ static int sys_pwr_domain_resume(void) /* PWM regulators take time to come up; give 300us to be safe. */ udelay(300); enable_dvfs_plls(); - plls_resume_finish(); secure_watchdog_restore(); diff --git a/plat/rockchip/rk3399/drivers/soc/soc.c b/plat/rockchip/rk3399/drivers/soc/soc.c index f77b74f24..c769b73bb 100644 --- a/plat/rockchip/rk3399/drivers/soc/soc.c +++ b/plat/rockchip/rk3399/drivers/soc/soc.c @@ -214,20 +214,6 @@ void secure_watchdog_restore(void) WMSK_BIT(PCLK_WDT_CM0_GATE_SHIFT)); } -static void pll_suspend_prepare(uint32_t pll_id) -{ - int i; - - if (pll_id == PPLL_ID) - for (i = 0; i < PLL_CON_COUNT; i++) - slp_data.plls_con[pll_id][i] = - mmio_read_32(PMUCRU_BASE + PMUCRU_PPLL_CON(i)); - else - for (i = 0; i < PLL_CON_COUNT; i++) - slp_data.plls_con[pll_id][i] = - mmio_read_32(CRU_BASE + CRU_PLL_CON(pll_id, i)); -} - static void set_pll_slow_mode(uint32_t pll_id) { if (pll_id == PPLL_ID) @@ -361,23 +347,6 @@ void restore_dpll(void) restore_pll(DPLL_ID, slp_data.plls_con[DPLL_ID]); } -void plls_suspend_prepare(void) -{ - uint32_t i, pll_id; - - for (pll_id = ALPLL_ID; pll_id < END_PLL_ID; pll_id++) - pll_suspend_prepare(pll_id); - - for (i = 0; i < CRU_CLKSEL_COUNT; i++) - slp_data.cru_clksel_con[i] = - mmio_read_32(CRU_BASE + CRU_CLKSEL_CON(i)); - - for (i = 0; i < PMUCRU_CLKSEL_CONUT; i++) - slp_data.pmucru_clksel_con[i] = - mmio_read_32(PMUCRU_BASE + - PMUCRU_CLKSEL_OFFSET + i * REG_SIZE); -} - void clk_gate_con_save(void) { uint32_t i = 0; @@ -431,26 +400,6 @@ static void _pll_resume(uint32_t pll_id) set_pll_normal_mode(pll_id); } -void plls_resume_finish(void) -{ - int i; - - for (i = 0; i < CRU_CLKSEL_COUNT; i++) { - /* CRU_CLKSEL_CON96~107 the high 16-bit isb't write_mask */ - if (i > 95) - mmio_write_32((CRU_BASE + CRU_CLKSEL_CON(i)), - slp_data.cru_clksel_con[i]); - else - mmio_write_32((CRU_BASE + CRU_CLKSEL_CON(i)), - REG_SOC_WMSK | - slp_data.cru_clksel_con[i]); - } - for (i = 0; i < PMUCRU_CLKSEL_CONUT; i++) - mmio_write_32((PMUCRU_BASE + - PMUCRU_CLKSEL_OFFSET + i * REG_SIZE), - REG_SOC_WMSK | slp_data.pmucru_clksel_con[i]); -} - /** * enable_dvfs_plls - To resume the specific PLLs * diff --git a/plat/rockchip/rk3399/drivers/soc/soc.h b/plat/rockchip/rk3399/drivers/soc/soc.h index bbca7bc08..742bb7b7c 100644 --- a/plat/rockchip/rk3399/drivers/soc/soc.h +++ b/plat/rockchip/rk3399/drivers/soc/soc.h @@ -348,10 +348,8 @@ static inline void pmu_sgrf_rst_hld(void) void __dead2 soc_global_soft_reset(void); void secure_watchdog_disable(); void secure_watchdog_restore(); -void plls_suspend_prepare(void); void disable_dvfs_plls(void); void disable_nodvfs_plls(void); -void plls_resume_finish(void); void enable_dvfs_plls(void); void enable_nodvfs_plls(void); void prepare_abpll_for_ddrctrl(void);