Skip to content

Commit

Permalink
rockchip: close the PD center logic during suspend
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: Derek Basehore <[email protected]>
Signed-off-by: Caesar Wang <[email protected]>
  • Loading branch information
Caesar-github committed Oct 26, 2016
1 parent 2831bc3 commit 4c127e6
Show file tree
Hide file tree
Showing 5 changed files with 221 additions and 11 deletions.
88 changes: 88 additions & 0 deletions plat/rockchip/rk3399/drivers/pmu/plat_pmu_macros.S
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down Expand Up @@ -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
37 changes: 28 additions & 9 deletions plat/rockchip/rk3399/drivers/pmu/pmu.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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) |
Expand Down Expand Up @@ -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) |
Expand All @@ -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 */
Expand Down Expand Up @@ -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) |
Expand All @@ -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) |
Expand All @@ -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.
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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) |
Expand Down Expand Up @@ -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 */
Expand Down
4 changes: 4 additions & 0 deletions plat/rockchip/rk3399/drivers/pmu/pmu.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#define __PMU_H__

#include <pmu_regs.h>
#include <soc.h>

/* Allocate sp reginon in pmusram */
#define PSRAM_SP_SIZE 0x80
Expand Down Expand Up @@ -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__ */
99 changes: 97 additions & 2 deletions plat/rockchip/rk3399/drivers/soc/soc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
};
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down
4 changes: 4 additions & 0 deletions plat/rockchip/rk3399/drivers/soc/soc.h
Original file line number Diff line number Diff line change
Expand Up @@ -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__ */

0 comments on commit 4c127e6

Please sign in to comment.