]> git.baikalelectronics.ru Git - arm-tf.git/commitdiff
rockchip: close the PD center logic during suspend
authorCaesar Wang <wxt@rock-chips.com>
Wed, 26 Oct 2016 17:13:34 +0000 (01:13 +0800)
committerCaesar Wang <wxt@rock-chips.com>
Wed, 26 Oct 2016 23:14:42 +0000 (07:14 +0800)
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>
plat/rockchip/rk3399/drivers/pmu/plat_pmu_macros.S
plat/rockchip/rk3399/drivers/pmu/pmu.c
plat/rockchip/rk3399/drivers/pmu/pmu.h
plat/rockchip/rk3399/drivers/soc/soc.c
plat/rockchip/rk3399/drivers/soc/soc.h

index 72419648b12fd5301587b4e18e0cb158640b9c33..405e1d5e009806c3ce965ee7a5ae177a35f6fc2b 100644 (file)
 #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 @@ clst_warmboot_data:
        .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
index 8d3f482f44e76f5ff0fc5c034477fbfb9205eeeb..5a385cb34b444f07cd91192fbeb23a28eee0a8ae 100644 (file)
@@ -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 @@ static void pmu_bus_idle_req(uint32_t bus, uint32_t state)
                     mmio_read_32(PMU_BASE + PMU_BUS_IDLE_ACK),
                     bus_ack);
        }
-
 }
 
 struct pmu_slpdata_s pmu_slpdata;
@@ -818,10 +817,19 @@ static void init_pmu_counts(void)
        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 @@ static void sys_slp_config(void)
                       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 @@ static void sys_slp_config(void)
        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 @@ static int sys_pwr_domain_suspend(void)
        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 @@ static int sys_pwr_domain_suspend(void)
                      (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 @@ static int sys_pwr_domain_suspend(void)
                }
        }
        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 @@ static int sys_pwr_domain_resume(void)
        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 @@ static int sys_pwr_domain_resume(void)
 
        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 @@ void plat_rockchip_pmu_init(void)
        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 */
index 3e1eb4a128e62896989fcd4368e0b7b6d5eccdfa..22c8c63749325747a04d6081bc8afcd5442bc122 100644 (file)
@@ -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 @@ struct pmu_slpdata_s {
 };
 
 extern uint32_t clst_warmboot_data[PLATFORM_CLUSTER_COUNT];
+
+extern void sram_func_set_ddrctl_pll(uint32_t pll_src);
+
 #endif /* __PMU_H__ */
index 2f6e67af60fe805f9ddc479bd4fdd5d1158df983..9529cb25fb9390641c5873509cdc1e7ea7ae217e 100644 (file)
@@ -43,6 +43,8 @@
 const mmap_region_t plat_rk_mmap[] = {
        MAP_REGION_FLAT(RK3399_DEV_RNG0_BASE, RK3399_DEV_RNG0_SIZE,
                        MT_DEVICE | MT_RW | MT_SECURE),
+       MAP_REGION_FLAT(PMUSRAM_BASE, PMUSRAM_SIZE,
+                       MT_MEMORY | MT_RW | MT_SECURE),
 
        { 0 }
 };
@@ -238,21 +240,105 @@ static void _pll_suspend(uint32_t pll_id)
        set_pll_bypass(pll_id);
 }
 
+/**
+ * disable_dvfs_plls - To suspend the specific PLLs
+ *
+ * When we close the center logic, the DPLL will be closed,
+ * so we need to keep the ABPLL and switch to it to supply
+ * clock for DDR during suspend, then we should not close
+ * the ABPLL and exclude ABPLL_ID.
+ */
 void disable_dvfs_plls(void)
 {
        _pll_suspend(CPLL_ID);
        _pll_suspend(NPLL_ID);
        _pll_suspend(VPLL_ID);
        _pll_suspend(GPLL_ID);
-       _pll_suspend(ABPLL_ID);
        _pll_suspend(ALPLL_ID);
 }
 
+/**
+ * disable_nodvfs_plls - To suspend the PPLL
+ */
 void disable_nodvfs_plls(void)
 {
        _pll_suspend(PPLL_ID);
 }
 
+/**
+ * restore_pll - Copy PLL settings from memory to a PLL.
+ *
+ * This will copy PLL settings from an array in memory to the memory mapped
+ * registers for a PLL.
+ *
+ * Note that: above the PLL exclude PPLL.
+ *
+ * pll_id: One of the values from enum plls_id
+ * src: Pointer to the array of values to restore from
+ */
+static void restore_pll(int pll_id, uint32_t *src)
+{
+       /* Nice to have PLL off while configuring */
+       mmio_write_32((CRU_BASE + CRU_PLL_CON(pll_id, 3)), PLL_SLOW_MODE);
+
+       mmio_write_32(CRU_BASE + CRU_PLL_CON(pll_id, 0), src[0] | REG_SOC_WMSK);
+       mmio_write_32(CRU_BASE + CRU_PLL_CON(pll_id, 1), src[1] | REG_SOC_WMSK);
+       mmio_write_32(CRU_BASE + CRU_PLL_CON(pll_id, 2), src[2]);
+       mmio_write_32(CRU_BASE + CRU_PLL_CON(pll_id, 4), src[4] | REG_SOC_WMSK);
+       mmio_write_32(CRU_BASE + CRU_PLL_CON(pll_id, 5), src[5] | REG_SOC_WMSK);
+
+       /* Do PLL_CON3 since that will enable things */
+       mmio_write_32(CRU_BASE + CRU_PLL_CON(pll_id, 3), src[3] | REG_SOC_WMSK);
+
+       /* Wait for PLL lock done */
+       while ((mmio_read_32(CRU_BASE + CRU_PLL_CON(pll_id, 2)) &
+               0x80000000) == 0x0)
+               ;
+}
+
+/**
+ * save_pll - Copy PLL settings a PLL to memory
+ *
+ * This will copy PLL settings from the memory mapped registers for a PLL to
+ * an array in memory.
+ *
+ * Note that: above the PLL exclude PPLL.
+ *
+ * pll_id: One of the values from enum plls_id
+ * src: Pointer to the array of values to save to.
+ */
+static void save_pll(uint32_t *dst, int pll_id)
+{
+       int i;
+
+       for (i = 0; i < PLL_CON_COUNT; i++)
+               dst[i] = mmio_read_32(CRU_BASE + CRU_PLL_CON(pll_id, i));
+}
+
+/**
+ * prepare_abpll_for_ddrctrl - Copy DPLL settings to ABPLL
+ *
+ * This will copy DPLL settings from the memory mapped registers for a PLL to
+ * an array in memory.
+ */
+void prepare_abpll_for_ddrctrl(void)
+{
+       save_pll(slp_data.plls_con[ABPLL_ID], ABPLL_ID);
+       save_pll(slp_data.plls_con[DPLL_ID], DPLL_ID);
+
+       restore_pll(ABPLL_ID, slp_data.plls_con[DPLL_ID]);
+}
+
+void restore_abpll(void)
+{
+       restore_pll(ABPLL_ID, slp_data.plls_con[ABPLL_ID]);
+}
+
+void restore_dpll(void)
+{
+       restore_pll(DPLL_ID, slp_data.plls_con[DPLL_ID]);
+}
+
 void plls_suspend_prepare(void)
 {
        uint32_t i, pll_id;
@@ -343,16 +429,25 @@ void plls_resume_finish(void)
                              REG_SOC_WMSK | slp_data.pmucru_clksel_con[i]);
 }
 
+/**
+ * enable_dvfs_plls - To resume the specific PLLs
+ *
+ * Please see the comment at the disable_dvfs_plls()
+ * we don't suspend the ABPLL, so don't need resume
+ * it too.
+ */
 void enable_dvfs_plls(void)
 {
        _pll_resume(ALPLL_ID);
-       _pll_resume(ABPLL_ID);
        _pll_resume(GPLL_ID);
        _pll_resume(VPLL_ID);
        _pll_resume(NPLL_ID);
        _pll_resume(CPLL_ID);
 }
 
+/**
+ * enable_nodvfs_plls - To resume the PPLL
+ */
 void enable_nodvfs_plls(void)
 {
        _pll_resume(PPLL_ID);
index 4804be620fd9d648cc85a3c4f4f70a8e9c7eba18..16897cc5b1cecdeba2c9748ffc68730f69fad42c 100644 (file)
@@ -336,7 +336,11 @@ 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);
+void restore_abpll(void);
+void restore_dpll(void);
 void clk_gate_con_save(void);
 void clk_gate_con_disable(void);
 void clk_gate_con_restore(void);
+void sgrf_init(void);
 #endif /* __SOC_H__ */