rockchip: close the PD center logic during suspend
The RK3399 supports close the center logic enter power mode,
so we can close PD_CENTER to save more power during suspend.
Therefore, we need to support save/restore the DDR PHY and
controller registers during suspend/resume.
Also, need CL (http://crosreview.com/397399) to check disabling
center logic.
Change-Id: I288defd8e9caa3846d9fa663a33e4d51df1aaa5d
Signed-off-by: Xing Zheng <zhengxing@rock-chips.com>
Signed-off-by: Derek Basehore <dbasehore@chromium.org>
Signed-off-by: Caesar Wang <wxt@rock-chips.com>
diff --git a/plat/rockchip/rk3399/drivers/pmu/plat_pmu_macros.S b/plat/rockchip/rk3399/drivers/pmu/plat_pmu_macros.S
index 7241964..405e1d5 100644
--- a/plat/rockchip/rk3399/drivers/pmu/plat_pmu_macros.S
+++ b/plat/rockchip/rk3399/drivers/pmu/plat_pmu_macros.S
@@ -27,9 +27,25 @@
#include <arch.h>
#include <asm_macros.S>
#include <platform_def.h>
+#include <pmu_regs.h>
.globl clst_warmboot_data
+ .macro sram_func _name
+ .section .sram.text, "ax"
+ .type \_name, %function
+ .func \_name
+ \_name:
+ .endm
+
+#define CRU_CLKSEL_CON6 0x118
+
+#define DDRCTL0_C_SYSREQ_CFG 0x0100
+#define DDRCTL1_C_SYSREQ_CFG 0x1000
+
+#define DDRC0_SREF_DONE_EXT 0x01
+#define DDRC1_SREF_DONE_EXT 0x04
+
#define PLL_MODE_SHIFT (0x8)
#define PLL_NORMAL_MODE ((0x3 << (PLL_MODE_SHIFT + 16)) | \
(0x1 << PLL_MODE_SHIFT))
@@ -65,3 +81,75 @@
.word 0
.endr
.endm
+
+ /* -----------------------------------------------
+ * void sram_func_set_ddrctl_pll(uint32_t pll_src)
+ * Function to switch the PLL source for ddrctrl
+ * In: x0 - The PLL of the clk_ddrc clock source
+ * out: None
+ * Clobber list : x0 - x3, x5, x8 - x10
+ * -----------------------------------------------
+ */
+
+ .globl sram_func_set_ddrctl_pll
+
+sram_func sram_func_set_ddrctl_pll
+ /* backup parameter */
+ mov x8, x0
+
+ /* disable the MMU at EL3 */
+ mrs x9, sctlr_el3
+ bic x10, x9, #(SCTLR_M_BIT)
+ msr sctlr_el3, x10
+ isb
+ dsb sy
+
+ /* enable ddrctl0_1 idle request */
+ mov x5, PMU_BASE
+ ldr w0, [x5, #PMU_SFT_CON]
+ orr w0, w0, #DDRCTL0_C_SYSREQ_CFG
+ orr w0, w0, #DDRCTL1_C_SYSREQ_CFG
+ str w0, [x5, #PMU_SFT_CON]
+
+check_ddrc0_1_sref_enter:
+ ldr w1, [x5, #PMU_DDR_SREF_ST]
+ and w2, w1, #DDRC0_SREF_DONE_EXT
+ and w3, w1, #DDRC1_SREF_DONE_EXT
+ orr w2, w2, w3
+ cmp w2, #(DDRC0_SREF_DONE_EXT | DDRC1_SREF_DONE_EXT)
+ b.eq check_ddrc0_1_sref_enter
+
+ /*
+ * select a PLL for ddrctrl:
+ * x0 = 0: ALPLL
+ * x0 = 1: ABPLL
+ * x0 = 2: DPLL
+ * x0 = 3: GPLLL
+ */
+ mov x5, CRU_BASE
+ lsl w0, w8, #4
+ orr w0, w0, #0x00300000
+ str w0, [x5, #CRU_CLKSEL_CON6]
+
+ /* disable ddrctl0_1 idle request */
+ mov x5, PMU_BASE
+ ldr w0, [x5, #PMU_SFT_CON]
+ bic w0, w0, #DDRCTL0_C_SYSREQ_CFG
+ bic w0, w0, #DDRCTL1_C_SYSREQ_CFG
+ str w0, [x5, #PMU_SFT_CON]
+
+check_ddrc0_1_sref_exit:
+ ldr w1, [x5, #PMU_DDR_SREF_ST]
+ and w2, w1, #DDRC0_SREF_DONE_EXT
+ and w3, w1, #DDRC1_SREF_DONE_EXT
+ orr w2, w2, w3
+ cmp w2, #0x0
+ b.eq check_ddrc0_1_sref_exit
+
+ /* reenable the MMU at EL3 */
+ msr sctlr_el3, x9
+ isb
+ dsb sy
+
+ ret
+endfunc sram_func_set_ddrctl_pll
diff --git a/plat/rockchip/rk3399/drivers/pmu/pmu.c b/plat/rockchip/rk3399/drivers/pmu/pmu.c
index 8d3f482..5a385cb 100644
--- a/plat/rockchip/rk3399/drivers/pmu/pmu.c
+++ b/plat/rockchip/rk3399/drivers/pmu/pmu.c
@@ -46,9 +46,9 @@
#include <pmu.h>
#include <pmu_com.h>
#include <pwm.h>
-#include <soc.h>
#include <bl31.h>
#include <rk3399m0.h>
+#include <suspend.h>
DEFINE_BAKERY_LOCK(rockchip_pd_lock);
@@ -102,7 +102,6 @@
mmio_read_32(PMU_BASE + PMU_BUS_IDLE_ACK),
bus_ack);
}
-
}
struct pmu_slpdata_s pmu_slpdata;
@@ -818,10 +817,19 @@
mmio_write_32(PMU_BASE + PMU_GPU_PWRUP_CNT, CYCL_24M_CNT_US(1));
}
+static uint32_t clk_ddrc_save;
+
static void sys_slp_config(void)
{
uint32_t slp_mode_cfg = 0;
+ /* keep enabling clk_ddrc_bpll_src_en gate for DDRC */
+ clk_ddrc_save = mmio_read_32(CRU_BASE + CRU_CLKGATE_CON(3));
+ mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(3), WMSK_BIT(1));
+
+ prepare_abpll_for_ddrctrl();
+ sram_func_set_ddrctl_pll(ABPLL_ID);
+
mmio_write_32(GRF_BASE + GRF_SOC_CON4, CCI_FORCE_WAKEUP);
mmio_write_32(PMU_BASE + PMU_CCI500_CON,
BIT_WITH_WMSK(PMU_CLR_PREQ_CCI500_HW) |
@@ -849,6 +857,7 @@
BIT(PMU_DDRIO0_RET_EN) |
BIT(PMU_DDRIO1_RET_EN) |
BIT(PMU_DDRIO_RET_HW_DE_REQ) |
+ BIT(PMU_CENTER_PD_EN) |
BIT(PMU_PLL_PD_EN) |
BIT(PMU_CLK_CENTER_SRC_GATE_EN) |
BIT(PMU_OSC_DIS) |
@@ -857,7 +866,6 @@
mmio_setbits_32(PMU_BASE + PMU_WKUP_CFG4, BIT(PMU_GPIO_WKUP_EN));
mmio_write_32(PMU_BASE + PMU_PWRMODE_CON, slp_mode_cfg);
-
mmio_write_32(PMU_BASE + PMU_PLL_CON, PLL_PD_HW);
mmio_write_32(PMUGRF_BASE + PMUGRF_SOC_CON0, EXTERNAL_32K);
mmio_write_32(PMUGRF_BASE, IOMUX_CLK_32K); /* 32k iomux */
@@ -1094,6 +1102,9 @@
uint32_t wait_cnt = 0;
uint32_t status = 0;
+ dmc_save();
+ pmu_scu_b_pwrdn();
+
pmu_power_domains_suspend();
set_hw_idle(BIT(PMU_CLR_CENTER1) |
BIT(PMU_CLR_ALIVE) |
@@ -1114,8 +1125,6 @@
(PMUSRAM_BASE >> CPU_BOOT_ADDR_ALIGN) |
CPU_BOOT_ADDR_WMASK);
- pmu_scu_b_pwrdn();
-
mmio_write_32(PMU_BASE + PMU_ADB400_CON,
BIT_WITH_WMSK(PMU_PWRDWN_REQ_CORE_B_2GIC_SW) |
BIT_WITH_WMSK(PMU_PWRDWN_REQ_CORE_B_SW) |
@@ -1134,6 +1143,7 @@
}
}
mmio_setbits_32(PMU_BASE + PMU_PWRDN_CON, BIT(PMU_SCU_B_PWRDWN_EN));
+
/*
* Disabling PLLs/PWM/DVFS is approaching WFI which is
* the last steps in suspend.
@@ -1163,6 +1173,10 @@
enable_dvfs_plls();
plls_resume_finish();
+ /* restore clk_ddrc_bpll_src_en gate */
+ mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(3),
+ BITS_WITH_WMASK(clk_ddrc_save, 0xff, 0));
+
/*
* The wakeup status is not cleared by itself, we need to clear it
* manually. Otherwise we will alway query some interrupt next time.
@@ -1209,8 +1223,12 @@
pmu_sgrf_rst_hld_release();
pmu_scu_b_pwrup();
-
pmu_power_domains_resume();
+
+ restore_dpll();
+ sram_func_set_ddrctl_pll(DPLL_ID);
+ restore_abpll();
+
clr_hw_idle(BIT(PMU_CLR_CENTER1) |
BIT(PMU_CLR_ALIVE) |
BIT(PMU_CLR_MSCH0) |
@@ -1301,9 +1319,10 @@
for (cpu = 0; cpu < PLATFORM_CLUSTER_COUNT; cpu++)
clst_warmboot_data[cpu] = 0;
- psram_sleep_cfg->ddr_func = 0x00;
- psram_sleep_cfg->ddr_data = 0x00;
- psram_sleep_cfg->ddr_flag = 0x00;
+ psram_sleep_cfg->ddr_func = (uint64_t)dmc_restore;
+ psram_sleep_cfg->ddr_data = (uint64_t)&sdram_config;
+ psram_sleep_cfg->ddr_flag = 0x01;
+
psram_sleep_cfg->boot_mpidr = read_mpidr_el1() & 0xffff;
/* config cpu's warm boot address */
diff --git a/plat/rockchip/rk3399/drivers/pmu/pmu.h b/plat/rockchip/rk3399/drivers/pmu/pmu.h
index 3e1eb4a..22c8c63 100644
--- a/plat/rockchip/rk3399/drivers/pmu/pmu.h
+++ b/plat/rockchip/rk3399/drivers/pmu/pmu.h
@@ -32,6 +32,7 @@
#define __PMU_H__
#include <pmu_regs.h>
+#include <soc.h>
/* Allocate sp reginon in pmusram */
#define PSRAM_SP_SIZE 0x80
@@ -843,4 +844,7 @@
};
extern uint32_t clst_warmboot_data[PLATFORM_CLUSTER_COUNT];
+
+extern void sram_func_set_ddrctl_pll(uint32_t pll_src);
+
#endif /* __PMU_H__ */