xref: /rk3399_ARM-atf/plat/rockchip/rk3328/drivers/pmu/pmu.c (revision c3e70be1c1ad2a9d1d3aee187231f5088a880ae1)
10d5ec955Stony.xie /*
20d5ec955Stony.xie  * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
30d5ec955Stony.xie  *
4*c3e70be1Sdp-arm  * SPDX-License-Identifier: BSD-3-Clause
50d5ec955Stony.xie  */
60d5ec955Stony.xie 
70d5ec955Stony.xie #include <arch_helpers.h>
80d5ec955Stony.xie #include <debug.h>
90d5ec955Stony.xie #include <assert.h>
100d5ec955Stony.xie #include <bakery_lock.h>
110d5ec955Stony.xie #include <bl31.h>
120d5ec955Stony.xie #include <console.h>
130d5ec955Stony.xie #include <delay_timer.h>
140d5ec955Stony.xie #include <errno.h>
150d5ec955Stony.xie #include <mmio.h>
160d5ec955Stony.xie #include <platform.h>
170d5ec955Stony.xie #include <platform_def.h>
180d5ec955Stony.xie #include <plat_private.h>
190d5ec955Stony.xie #include <pmu_sram.h>
200d5ec955Stony.xie #include <pmu.h>
210d5ec955Stony.xie #include <rk3328_def.h>
220d5ec955Stony.xie #include <pmu_com.h>
230d5ec955Stony.xie 
240d5ec955Stony.xie DEFINE_BAKERY_LOCK(rockchip_pd_lock);
250d5ec955Stony.xie 
260d5ec955Stony.xie static struct psram_data_t *psram_sleep_cfg =
270d5ec955Stony.xie 		(struct psram_data_t *)PSRAM_DT_BASE;
280d5ec955Stony.xie 
290d5ec955Stony.xie static struct rk3328_sleep_ddr_data ddr_data;
300d5ec955Stony.xie static __sramdata struct rk3328_sleep_sram_data sram_data;
310d5ec955Stony.xie 
320d5ec955Stony.xie static uint32_t cpu_warm_boot_addr;
330d5ec955Stony.xie 
340d5ec955Stony.xie #pragma weak rk3328_pmic_suspend
350d5ec955Stony.xie #pragma weak rk3328_pmic_resume
360d5ec955Stony.xie 
370d5ec955Stony.xie void plat_rockchip_pmusram_prepare(void)
380d5ec955Stony.xie {
390d5ec955Stony.xie 	uint32_t *sram_dst, *sram_src;
400d5ec955Stony.xie 	size_t sram_size = 2;
410d5ec955Stony.xie 	/*
420d5ec955Stony.xie 	 * pmu sram code and data prepare
430d5ec955Stony.xie 	 */
440d5ec955Stony.xie 	sram_dst = (uint32_t *)PMUSRAM_BASE;
450d5ec955Stony.xie 	sram_src = (uint32_t *)&pmu_cpuson_entrypoint_start;
460d5ec955Stony.xie 	sram_size = (uint32_t *)&pmu_cpuson_entrypoint_end -
470d5ec955Stony.xie 		    (uint32_t *)sram_src;
480d5ec955Stony.xie 	u32_align_cpy(sram_dst, sram_src, sram_size);
490d5ec955Stony.xie 
500d5ec955Stony.xie 	psram_sleep_cfg->sp = PSRAM_DT_BASE;
510d5ec955Stony.xie }
520d5ec955Stony.xie 
530d5ec955Stony.xie static inline uint32_t get_cpus_pwr_domain_cfg_info(uint32_t cpu_id)
540d5ec955Stony.xie {
550d5ec955Stony.xie 	uint32_t pd_reg, apm_reg;
560d5ec955Stony.xie 
570d5ec955Stony.xie 	pd_reg = mmio_read_32(PMU_BASE + PMU_PWRDN_CON) & BIT(cpu_id);
580d5ec955Stony.xie 	apm_reg = mmio_read_32(PMU_BASE + PMU_CPUAPM_CON(cpu_id)) &
590d5ec955Stony.xie 			       BIT(core_pm_en);
600d5ec955Stony.xie 
610d5ec955Stony.xie 	if (pd_reg && !apm_reg)
620d5ec955Stony.xie 		return core_pwr_pd;
630d5ec955Stony.xie 	else if (!pd_reg && apm_reg)
640d5ec955Stony.xie 		return core_pwr_wfi;
650d5ec955Stony.xie 
660d5ec955Stony.xie 	ERROR("%s: 0x%x, 0x%x\n", __func__, pd_reg, apm_reg);
670d5ec955Stony.xie 	while (1)
680d5ec955Stony.xie 	;
690d5ec955Stony.xie }
700d5ec955Stony.xie 
710d5ec955Stony.xie static int cpus_power_domain_on(uint32_t cpu_id)
720d5ec955Stony.xie {
730d5ec955Stony.xie 	uint32_t cpu_pd, cfg_info;
740d5ec955Stony.xie 
750d5ec955Stony.xie 	cpu_pd = PD_CPU0 + cpu_id;
760d5ec955Stony.xie 	cfg_info = get_cpus_pwr_domain_cfg_info(cpu_id);
770d5ec955Stony.xie 
780d5ec955Stony.xie 	if (cfg_info == core_pwr_pd) {
790d5ec955Stony.xie 		/* disable apm cfg */
800d5ec955Stony.xie 		mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(cpu_id),
810d5ec955Stony.xie 			      CORES_PM_DISABLE);
820d5ec955Stony.xie 
830d5ec955Stony.xie 		/* if the cores have be on, power off it firstly */
840d5ec955Stony.xie 		if (pmu_power_domain_st(cpu_pd) == pmu_pd_on) {
850d5ec955Stony.xie 			mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(cpu_id),
860d5ec955Stony.xie 				      CORES_PM_DISABLE);
870d5ec955Stony.xie 			pmu_power_domain_ctr(cpu_pd, pmu_pd_off);
880d5ec955Stony.xie 		}
890d5ec955Stony.xie 		pmu_power_domain_ctr(cpu_pd, pmu_pd_on);
900d5ec955Stony.xie 	} else {
910d5ec955Stony.xie 		if (pmu_power_domain_st(cpu_pd) == pmu_pd_on) {
920d5ec955Stony.xie 			WARN("%s: cpu%d is not in off,!\n", __func__, cpu_id);
930d5ec955Stony.xie 			return -EINVAL;
940d5ec955Stony.xie 		}
950d5ec955Stony.xie 
960d5ec955Stony.xie 		mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(cpu_id),
970d5ec955Stony.xie 			      BIT(core_pm_sft_wakeup_en));
980d5ec955Stony.xie 	}
990d5ec955Stony.xie 
1000d5ec955Stony.xie 	return 0;
1010d5ec955Stony.xie }
1020d5ec955Stony.xie 
1030d5ec955Stony.xie static int cpus_power_domain_off(uint32_t cpu_id, uint32_t pd_cfg)
1040d5ec955Stony.xie {
1050d5ec955Stony.xie 	uint32_t cpu_pd, core_pm_value;
1060d5ec955Stony.xie 
1070d5ec955Stony.xie 	cpu_pd = PD_CPU0 + cpu_id;
1080d5ec955Stony.xie 	if (pmu_power_domain_st(cpu_pd) == pmu_pd_off)
1090d5ec955Stony.xie 		return 0;
1100d5ec955Stony.xie 
1110d5ec955Stony.xie 	if (pd_cfg == core_pwr_pd) {
1120d5ec955Stony.xie 		if (check_cpu_wfie(cpu_id, CKECK_WFEI_MSK))
1130d5ec955Stony.xie 			return -EINVAL;
1140d5ec955Stony.xie 		/* disable apm cfg */
1150d5ec955Stony.xie 		mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(cpu_id),
1160d5ec955Stony.xie 			      CORES_PM_DISABLE);
1170d5ec955Stony.xie 		pmu_power_domain_ctr(cpu_pd, pmu_pd_off);
1180d5ec955Stony.xie 	} else {
1190d5ec955Stony.xie 		core_pm_value = BIT(core_pm_en) | BIT(core_pm_dis_int);
1200d5ec955Stony.xie 		if (pd_cfg == core_pwr_wfi_int)
1210d5ec955Stony.xie 			core_pm_value |= BIT(core_pm_int_wakeup_en);
1220d5ec955Stony.xie 
1230d5ec955Stony.xie 		mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(cpu_id),
1240d5ec955Stony.xie 			      core_pm_value);
1250d5ec955Stony.xie 	}
1260d5ec955Stony.xie 
1270d5ec955Stony.xie 	return 0;
1280d5ec955Stony.xie }
1290d5ec955Stony.xie 
1300d5ec955Stony.xie static void nonboot_cpus_off(void)
1310d5ec955Stony.xie {
1320d5ec955Stony.xie 	uint32_t boot_cpu, cpu;
1330d5ec955Stony.xie 
1340d5ec955Stony.xie 	/* turn off noboot cpus */
1350d5ec955Stony.xie 	boot_cpu = plat_my_core_pos();
1360d5ec955Stony.xie 	for (cpu = 0; cpu < PLATFORM_CORE_COUNT; cpu++) {
1370d5ec955Stony.xie 		if (cpu == boot_cpu)
1380d5ec955Stony.xie 			continue;
1390d5ec955Stony.xie 		cpus_power_domain_off(cpu, core_pwr_pd);
1400d5ec955Stony.xie 	}
1410d5ec955Stony.xie }
1420d5ec955Stony.xie 
1430d5ec955Stony.xie int rockchip_soc_cores_pwr_dm_on(unsigned long mpidr, uint64_t entrypoint)
1440d5ec955Stony.xie {
1450d5ec955Stony.xie 	uint32_t cpu_id = plat_core_pos_by_mpidr(mpidr);
1460d5ec955Stony.xie 
1470d5ec955Stony.xie 	assert(cpuson_flags[cpu_id] == 0);
1480d5ec955Stony.xie 	cpuson_flags[cpu_id] = PMU_CPU_HOTPLUG;
1490d5ec955Stony.xie 	cpuson_entry_point[cpu_id] = entrypoint;
1500d5ec955Stony.xie 	dsb();
1510d5ec955Stony.xie 
1520d5ec955Stony.xie 	cpus_power_domain_on(cpu_id);
1530d5ec955Stony.xie 
1540d5ec955Stony.xie 	return 0;
1550d5ec955Stony.xie }
1560d5ec955Stony.xie 
1570d5ec955Stony.xie int rockchip_soc_cores_pwr_dm_off(void)
1580d5ec955Stony.xie {
1590d5ec955Stony.xie 	uint32_t cpu_id = plat_my_core_pos();
1600d5ec955Stony.xie 
1610d5ec955Stony.xie 	cpus_power_domain_off(cpu_id, core_pwr_wfi);
1620d5ec955Stony.xie 
1630d5ec955Stony.xie 	return 0;
1640d5ec955Stony.xie }
1650d5ec955Stony.xie 
1660d5ec955Stony.xie int rockchip_soc_cores_pwr_dm_suspend(void)
1670d5ec955Stony.xie {
1680d5ec955Stony.xie 	uint32_t cpu_id = plat_my_core_pos();
1690d5ec955Stony.xie 
1700d5ec955Stony.xie 	assert(cpuson_flags[cpu_id] == 0);
1710d5ec955Stony.xie 	cpuson_flags[cpu_id] = PMU_CPU_AUTO_PWRDN;
1720d5ec955Stony.xie 	cpuson_entry_point[cpu_id] = (uintptr_t)plat_get_sec_entrypoint();
1730d5ec955Stony.xie 	dsb();
1740d5ec955Stony.xie 
1750d5ec955Stony.xie 	cpus_power_domain_off(cpu_id, core_pwr_wfi_int);
1760d5ec955Stony.xie 
1770d5ec955Stony.xie 	return 0;
1780d5ec955Stony.xie }
1790d5ec955Stony.xie 
1800d5ec955Stony.xie int rockchip_soc_cores_pwr_dm_on_finish(void)
1810d5ec955Stony.xie {
1820d5ec955Stony.xie 	uint32_t cpu_id = plat_my_core_pos();
1830d5ec955Stony.xie 
1840d5ec955Stony.xie 	mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(cpu_id), CORES_PM_DISABLE);
1850d5ec955Stony.xie 
1860d5ec955Stony.xie 	return 0;
1870d5ec955Stony.xie }
1880d5ec955Stony.xie 
1890d5ec955Stony.xie int rockchip_soc_cores_pwr_dm_resume(void)
1900d5ec955Stony.xie {
1910d5ec955Stony.xie 	uint32_t cpu_id = plat_my_core_pos();
1920d5ec955Stony.xie 
1930d5ec955Stony.xie 	mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(cpu_id), CORES_PM_DISABLE);
1940d5ec955Stony.xie 
1950d5ec955Stony.xie 	return 0;
1960d5ec955Stony.xie }
1970d5ec955Stony.xie 
1980d5ec955Stony.xie void __dead2 rockchip_soc_soft_reset(void)
1990d5ec955Stony.xie {
2000d5ec955Stony.xie 	mmio_write_32(CRU_BASE + CRU_CRU_MODE, PLL_SLOW_MODE(CPLL_ID));
2010d5ec955Stony.xie 	mmio_write_32(CRU_BASE + CRU_CRU_MODE, PLL_SLOW_MODE(GPLL_ID));
2020d5ec955Stony.xie 	mmio_write_32(CRU_BASE + CRU_CRU_MODE, PLL_SLOW_MODE(NPLL_ID));
2030d5ec955Stony.xie 	mmio_write_32(CRU_BASE + CRU_CRU_MODE, PLL_SLOW_MODE(APLL_ID));
2040d5ec955Stony.xie 	dsb();
2050d5ec955Stony.xie 
2060d5ec955Stony.xie 	mmio_write_32(CRU_BASE + CRU_GLB_SRST_FST, CRU_GLB_SRST_FST_VALUE);
2070d5ec955Stony.xie 	dsb();
2080d5ec955Stony.xie 	/*
2090d5ec955Stony.xie 	 * Maybe the HW needs some times to reset the system,
2100d5ec955Stony.xie 	 * so we do not hope the core to excute valid codes.
2110d5ec955Stony.xie 	 */
2120d5ec955Stony.xie 	while (1)
2130d5ec955Stony.xie 		;
2140d5ec955Stony.xie }
2150d5ec955Stony.xie 
2160d5ec955Stony.xie /*
2170d5ec955Stony.xie  * For PMIC RK805, its sleep pin is connect with gpio2_d2 from rk3328.
2180d5ec955Stony.xie  * If the PMIC is configed for responding the sleep pin to power off it,
2190d5ec955Stony.xie  * once the pin is output high,  it will get the pmic power off.
2200d5ec955Stony.xie  */
2210d5ec955Stony.xie void __dead2 rockchip_soc_system_off(void)
2220d5ec955Stony.xie {
2230d5ec955Stony.xie 	uint32_t val;
2240d5ec955Stony.xie 
2250d5ec955Stony.xie 	/* gpio config */
2260d5ec955Stony.xie 	val = mmio_read_32(GRF_BASE + GRF_GPIO2D_IOMUX);
2270d5ec955Stony.xie 	val &= ~GPIO2_D2_GPIO_MODE;
2280d5ec955Stony.xie 	mmio_write_32(GRF_BASE + GRF_GPIO2D_IOMUX, val);
2290d5ec955Stony.xie 
2300d5ec955Stony.xie 	/* config output */
2310d5ec955Stony.xie 	val = mmio_read_32(GPIO2_BASE + SWPORTA_DDR);
2320d5ec955Stony.xie 	val |= GPIO2_D2;
2330d5ec955Stony.xie 	mmio_write_32(GPIO2_BASE + SWPORTA_DDR, val);
2340d5ec955Stony.xie 
2350d5ec955Stony.xie 	/* config output high level */
2360d5ec955Stony.xie 	val = mmio_read_32(GPIO2_BASE);
2370d5ec955Stony.xie 	val |= GPIO2_D2;
2380d5ec955Stony.xie 	mmio_write_32(GPIO2_BASE, val);
2390d5ec955Stony.xie 	dsb();
2400d5ec955Stony.xie 
2410d5ec955Stony.xie 	while (1)
2420d5ec955Stony.xie 		;
2430d5ec955Stony.xie }
2440d5ec955Stony.xie 
2450d5ec955Stony.xie static uint32_t clk_ungt_msk[CRU_CLKGATE_NUMS] = {
2460d5ec955Stony.xie 	0x187f, 0x0000, 0x010c, 0x0000, 0x0200,
2470d5ec955Stony.xie 	0x0010, 0x0000, 0x0017, 0x001f, 0x0000,
2480d5ec955Stony.xie 	0x0000, 0x0000, 0x0000, 0x0003, 0x0000,
2490d5ec955Stony.xie 	0xf001, 0x27c0, 0x04D9, 0x03ff, 0x0000,
2500d5ec955Stony.xie 	0x0000, 0x0000, 0x0010, 0x0000, 0x0000,
2510d5ec955Stony.xie 	0x0000, 0x0000, 0x0003, 0x0008
2520d5ec955Stony.xie };
2530d5ec955Stony.xie 
2540d5ec955Stony.xie static void clks_gating_suspend(uint32_t *ungt_msk)
2550d5ec955Stony.xie {
2560d5ec955Stony.xie 	int i;
2570d5ec955Stony.xie 
2580d5ec955Stony.xie 	for (i = 0; i < CRU_CLKGATE_NUMS; i++) {
2590d5ec955Stony.xie 		ddr_data.clk_ungt_save[i] =
2600d5ec955Stony.xie 			mmio_read_32(CRU_BASE + CRU_CLKGATE_CON(i));
2610d5ec955Stony.xie 		mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(i),
2620d5ec955Stony.xie 			      ((~ungt_msk[i]) << 16) | 0xffff);
2630d5ec955Stony.xie 	}
2640d5ec955Stony.xie }
2650d5ec955Stony.xie 
2660d5ec955Stony.xie static void clks_gating_resume(void)
2670d5ec955Stony.xie {
2680d5ec955Stony.xie 	int i;
2690d5ec955Stony.xie 
2700d5ec955Stony.xie 	for (i = 0; i < CRU_CLKGATE_NUMS; i++)
2710d5ec955Stony.xie 		mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(i),
2720d5ec955Stony.xie 			      ddr_data.clk_ungt_save[i] | 0xffff0000);
2730d5ec955Stony.xie }
2740d5ec955Stony.xie 
2750d5ec955Stony.xie static inline void pm_pll_wait_lock(uint32_t pll_id)
2760d5ec955Stony.xie {
2770d5ec955Stony.xie 	uint32_t delay = PLL_LOCKED_TIMEOUT;
2780d5ec955Stony.xie 
2790d5ec955Stony.xie 	while (delay > 0) {
2800d5ec955Stony.xie 		if (mmio_read_32(CRU_BASE + PLL_CONS(pll_id, 1)) &
2810d5ec955Stony.xie 		    PLL_IS_LOCKED)
2820d5ec955Stony.xie 			break;
2830d5ec955Stony.xie 		delay--;
2840d5ec955Stony.xie 	}
2850d5ec955Stony.xie 	if (delay == 0)
2860d5ec955Stony.xie 		ERROR("lock-pll: %d\n", pll_id);
2870d5ec955Stony.xie }
2880d5ec955Stony.xie 
2890d5ec955Stony.xie static inline void pll_pwr_dwn(uint32_t pll_id, uint32_t pd)
2900d5ec955Stony.xie {
2910d5ec955Stony.xie 	mmio_write_32(CRU_BASE + PLL_CONS(pll_id, 1),
2920d5ec955Stony.xie 		      BITS_WITH_WMASK(1, 1, 15));
2930d5ec955Stony.xie 	if (pd)
2940d5ec955Stony.xie 		mmio_write_32(CRU_BASE + PLL_CONS(pll_id, 1),
2950d5ec955Stony.xie 			      BITS_WITH_WMASK(1, 1, 14));
2960d5ec955Stony.xie 	else
2970d5ec955Stony.xie 		mmio_write_32(CRU_BASE + PLL_CONS(pll_id, 1),
2980d5ec955Stony.xie 			      BITS_WITH_WMASK(0, 1, 14));
2990d5ec955Stony.xie }
3000d5ec955Stony.xie 
3010d5ec955Stony.xie static __sramfunc void dpll_suspend(void)
3020d5ec955Stony.xie {
3030d5ec955Stony.xie 	int i;
3040d5ec955Stony.xie 
3050d5ec955Stony.xie 	/* slow mode */
3060d5ec955Stony.xie 	mmio_write_32(CRU_BASE + CRU_CRU_MODE, PLL_SLOW_MODE(DPLL_ID));
3070d5ec955Stony.xie 
3080d5ec955Stony.xie 	/* save pll con */
3090d5ec955Stony.xie 	for (i = 0; i < CRU_PLL_CON_NUMS; i++)
3100d5ec955Stony.xie 		sram_data.dpll_con_save[i] =
3110d5ec955Stony.xie 				mmio_read_32(CRU_BASE + PLL_CONS(DPLL_ID, i));
3120d5ec955Stony.xie 	mmio_write_32(CRU_BASE + PLL_CONS(DPLL_ID, 1),
3130d5ec955Stony.xie 		      BITS_WITH_WMASK(1, 1, 15));
3140d5ec955Stony.xie 	mmio_write_32(CRU_BASE + PLL_CONS(DPLL_ID, 1),
3150d5ec955Stony.xie 		      BITS_WITH_WMASK(1, 1, 14));
3160d5ec955Stony.xie }
3170d5ec955Stony.xie 
3180d5ec955Stony.xie static __sramfunc void dpll_resume(void)
3190d5ec955Stony.xie {
3200d5ec955Stony.xie 	uint32_t delay = PLL_LOCKED_TIMEOUT;
3210d5ec955Stony.xie 
3220d5ec955Stony.xie 	mmio_write_32(CRU_BASE + PLL_CONS(DPLL_ID, 1),
3230d5ec955Stony.xie 		      BITS_WITH_WMASK(1, 1, 15));
3240d5ec955Stony.xie 	mmio_write_32(CRU_BASE + PLL_CONS(DPLL_ID, 1),
3250d5ec955Stony.xie 		      BITS_WITH_WMASK(0, 1, 14));
3260d5ec955Stony.xie 	mmio_write_32(CRU_BASE + PLL_CONS(DPLL_ID, 1),
3270d5ec955Stony.xie 		      sram_data.dpll_con_save[1] | 0xc0000000);
3280d5ec955Stony.xie 
3290d5ec955Stony.xie 	dsb();
3300d5ec955Stony.xie 
3310d5ec955Stony.xie 	while (delay > 0) {
3320d5ec955Stony.xie 		if (mmio_read_32(CRU_BASE + PLL_CONS(DPLL_ID, 1)) &
3330d5ec955Stony.xie 				 PLL_IS_LOCKED)
3340d5ec955Stony.xie 			break;
3350d5ec955Stony.xie 		delay--;
3360d5ec955Stony.xie 	}
3370d5ec955Stony.xie 	if (delay == 0)
3380d5ec955Stony.xie 		while (1)
3390d5ec955Stony.xie 			;
3400d5ec955Stony.xie 
3410d5ec955Stony.xie 	mmio_write_32(CRU_BASE + CRU_CRU_MODE,
3420d5ec955Stony.xie 		      PLL_NORM_MODE(DPLL_ID));
3430d5ec955Stony.xie }
3440d5ec955Stony.xie 
3450d5ec955Stony.xie static inline void pll_suspend(uint32_t pll_id)
3460d5ec955Stony.xie {
3470d5ec955Stony.xie 	int i;
3480d5ec955Stony.xie 
3490d5ec955Stony.xie 	/* slow mode */
3500d5ec955Stony.xie 	mmio_write_32(CRU_BASE + CRU_CRU_MODE, PLL_SLOW_MODE(pll_id));
3510d5ec955Stony.xie 
3520d5ec955Stony.xie 	/* save pll con */
3530d5ec955Stony.xie 	for (i = 0; i < CRU_PLL_CON_NUMS; i++)
3540d5ec955Stony.xie 		ddr_data.cru_plls_con_save[pll_id][i] =
3550d5ec955Stony.xie 				mmio_read_32(CRU_BASE + PLL_CONS(pll_id, i));
3560d5ec955Stony.xie 
3570d5ec955Stony.xie 	/* powerdown pll */
3580d5ec955Stony.xie 	pll_pwr_dwn(pll_id, pmu_pd_off);
3590d5ec955Stony.xie }
3600d5ec955Stony.xie 
3610d5ec955Stony.xie static inline void pll_resume(uint32_t pll_id)
3620d5ec955Stony.xie {
3630d5ec955Stony.xie 	mmio_write_32(CRU_BASE + PLL_CONS(pll_id, 1),
3640d5ec955Stony.xie 		      ddr_data.cru_plls_con_save[pll_id][1] | 0xc0000000);
3650d5ec955Stony.xie 
3660d5ec955Stony.xie 	pm_pll_wait_lock(pll_id);
3670d5ec955Stony.xie 
3680d5ec955Stony.xie 	if (PLL_IS_NORM_MODE(ddr_data.cru_mode_save, pll_id))
3690d5ec955Stony.xie 		mmio_write_32(CRU_BASE + CRU_CRU_MODE,
3700d5ec955Stony.xie 			      PLL_NORM_MODE(pll_id));
3710d5ec955Stony.xie }
3720d5ec955Stony.xie 
3730d5ec955Stony.xie static void pm_plls_suspend(void)
3740d5ec955Stony.xie {
3750d5ec955Stony.xie 	ddr_data.cru_mode_save = mmio_read_32(CRU_BASE + CRU_CRU_MODE);
3760d5ec955Stony.xie 	ddr_data.clk_sel0 = mmio_read_32(CRU_BASE + CRU_CLKSEL_CON(0));
3770d5ec955Stony.xie 	ddr_data.clk_sel1 = mmio_read_32(CRU_BASE + CRU_CLKSEL_CON(1));
3780d5ec955Stony.xie 	ddr_data.clk_sel18 = mmio_read_32(CRU_BASE + CRU_CLKSEL_CON(18));
3790d5ec955Stony.xie 	ddr_data.clk_sel20 = mmio_read_32(CRU_BASE + CRU_CLKSEL_CON(20));
3800d5ec955Stony.xie 	ddr_data.clk_sel24 = mmio_read_32(CRU_BASE + CRU_CLKSEL_CON(24));
3810d5ec955Stony.xie 	ddr_data.clk_sel38 = mmio_read_32(CRU_BASE + CRU_CLKSEL_CON(38));
3820d5ec955Stony.xie 	pll_suspend(NPLL_ID);
3830d5ec955Stony.xie 	pll_suspend(CPLL_ID);
3840d5ec955Stony.xie 	pll_suspend(GPLL_ID);
3850d5ec955Stony.xie 	pll_suspend(APLL_ID);
3860d5ec955Stony.xie 
3870d5ec955Stony.xie 	/* core */
3880d5ec955Stony.xie 	mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(0),
3890d5ec955Stony.xie 		      BITS_WITH_WMASK(0, 0x1f, 0));
3900d5ec955Stony.xie 
3910d5ec955Stony.xie 	/* pclk_dbg */
3920d5ec955Stony.xie 	mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(1),
3930d5ec955Stony.xie 		      BITS_WITH_WMASK(0, 0xf, 0));
3940d5ec955Stony.xie 
3950d5ec955Stony.xie 	/* crypto */
3960d5ec955Stony.xie 	mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(20),
3970d5ec955Stony.xie 		      BITS_WITH_WMASK(0, 0x1f, 0));
3980d5ec955Stony.xie 
3990d5ec955Stony.xie 	/* pwm0 */
4000d5ec955Stony.xie 	mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(24),
4010d5ec955Stony.xie 		      BITS_WITH_WMASK(0, 0x7f, 8));
4020d5ec955Stony.xie 
4030d5ec955Stony.xie 	/* uart2 from 24M */
4040d5ec955Stony.xie 	mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(18),
4050d5ec955Stony.xie 		      BITS_WITH_WMASK(2, 0x3, 8));
4060d5ec955Stony.xie 
4070d5ec955Stony.xie 	/* clk_rtc32k */
4080d5ec955Stony.xie 	mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(38),
4090d5ec955Stony.xie 		      BITS_WITH_WMASK(767, 0x3fff, 0) |
4100d5ec955Stony.xie 		      BITS_WITH_WMASK(2, 0x3, 14));
4110d5ec955Stony.xie }
4120d5ec955Stony.xie 
4130d5ec955Stony.xie static void pm_plls_resume(void)
4140d5ec955Stony.xie {
4150d5ec955Stony.xie 	/* clk_rtc32k */
4160d5ec955Stony.xie 	mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(38),
4170d5ec955Stony.xie 		      ddr_data.clk_sel38 |
4180d5ec955Stony.xie 		      BITS_WMSK(0x3fff, 0) |
4190d5ec955Stony.xie 		      BITS_WMSK(0x3, 14));
4200d5ec955Stony.xie 
4210d5ec955Stony.xie 	/* uart2 */
4220d5ec955Stony.xie 	mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(18),
4230d5ec955Stony.xie 		      ddr_data.clk_sel18 | BITS_WMSK(0x3, 8));
4240d5ec955Stony.xie 
4250d5ec955Stony.xie 	/* pwm0 */
4260d5ec955Stony.xie 	mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(24),
4270d5ec955Stony.xie 		      ddr_data.clk_sel24 | BITS_WMSK(0x7f, 8));
4280d5ec955Stony.xie 
4290d5ec955Stony.xie 	/* crypto */
4300d5ec955Stony.xie 	mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(20),
4310d5ec955Stony.xie 		      ddr_data.clk_sel20 | BITS_WMSK(0x1f, 0));
4320d5ec955Stony.xie 
4330d5ec955Stony.xie 	/* pclk_dbg */
4340d5ec955Stony.xie 	mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(1),
4350d5ec955Stony.xie 		      ddr_data.clk_sel1 | BITS_WMSK(0xf, 0));
4360d5ec955Stony.xie 
4370d5ec955Stony.xie 	/* core */
4380d5ec955Stony.xie 	mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(0),
4390d5ec955Stony.xie 		      ddr_data.clk_sel0 | BITS_WMSK(0x1f, 0));
4400d5ec955Stony.xie 
4410d5ec955Stony.xie 	pll_pwr_dwn(APLL_ID, pmu_pd_on);
4420d5ec955Stony.xie 	pll_pwr_dwn(GPLL_ID, pmu_pd_on);
4430d5ec955Stony.xie 	pll_pwr_dwn(CPLL_ID, pmu_pd_on);
4440d5ec955Stony.xie 	pll_pwr_dwn(NPLL_ID, pmu_pd_on);
4450d5ec955Stony.xie 
4460d5ec955Stony.xie 	pll_resume(APLL_ID);
4470d5ec955Stony.xie 	pll_resume(GPLL_ID);
4480d5ec955Stony.xie 	pll_resume(CPLL_ID);
4490d5ec955Stony.xie 	pll_resume(NPLL_ID);
4500d5ec955Stony.xie }
4510d5ec955Stony.xie 
4520d5ec955Stony.xie #define ARCH_TIMER_TICKS_PER_US (SYS_COUNTER_FREQ_IN_TICKS / 1000000)
4530d5ec955Stony.xie 
4540d5ec955Stony.xie static __sramfunc void sram_udelay(uint32_t us)
4550d5ec955Stony.xie {
4560d5ec955Stony.xie 	uint64_t pct_orig, pct_now;
4570d5ec955Stony.xie 	uint64_t to_wait = ARCH_TIMER_TICKS_PER_US * us;
4580d5ec955Stony.xie 
4590d5ec955Stony.xie 	isb();
4600d5ec955Stony.xie 	pct_orig = read_cntpct_el0();
4610d5ec955Stony.xie 
4620d5ec955Stony.xie 	do {
4630d5ec955Stony.xie 		isb();
4640d5ec955Stony.xie 		pct_now = read_cntpct_el0();
4650d5ec955Stony.xie 	} while ((pct_now - pct_orig) <= to_wait);
4660d5ec955Stony.xie }
4670d5ec955Stony.xie 
4680d5ec955Stony.xie /*
4690d5ec955Stony.xie  * For PMIC RK805, its sleep pin is connect with gpio2_d2 from rk3328.
4700d5ec955Stony.xie  * If the PMIC is configed for responding the sleep pin
4710d5ec955Stony.xie  * to get it into sleep mode,
4720d5ec955Stony.xie  * once the pin is output high,  it will get the pmic into sleep mode.
4730d5ec955Stony.xie  */
4740d5ec955Stony.xie __sramfunc void rk3328_pmic_suspend(void)
4750d5ec955Stony.xie {
4760d5ec955Stony.xie 	sram_data.pmic_sleep_save = mmio_read_32(GRF_BASE + PMIC_SLEEP_REG);
4770d5ec955Stony.xie 	sram_data.pmic_sleep_gpio_save[1] = mmio_read_32(GPIO2_BASE + 4);
4780d5ec955Stony.xie 	sram_data.pmic_sleep_gpio_save[0] = mmio_read_32(GPIO2_BASE);
4790d5ec955Stony.xie 	mmio_write_32(GRF_BASE + PMIC_SLEEP_REG, BITS_WITH_WMASK(0, 0x3, 4));
4800d5ec955Stony.xie 	mmio_write_32(GPIO2_BASE + 4,
4810d5ec955Stony.xie 		      sram_data.pmic_sleep_gpio_save[1] | BIT(26));
4820d5ec955Stony.xie 	mmio_write_32(GPIO2_BASE,
4830d5ec955Stony.xie 		      sram_data.pmic_sleep_gpio_save[0] | BIT(26));
4840d5ec955Stony.xie }
4850d5ec955Stony.xie 
4860d5ec955Stony.xie __sramfunc void  rk3328_pmic_resume(void)
4870d5ec955Stony.xie {
4880d5ec955Stony.xie 	mmio_write_32(GPIO2_BASE, sram_data.pmic_sleep_gpio_save[0]);
4890d5ec955Stony.xie 	mmio_write_32(GPIO2_BASE + 4, sram_data.pmic_sleep_gpio_save[1]);
4900d5ec955Stony.xie 	mmio_write_32(GRF_BASE + PMIC_SLEEP_REG,
4910d5ec955Stony.xie 		      sram_data.pmic_sleep_save | BITS_WMSK(0xffff, 0));
4920d5ec955Stony.xie 	/* Resuming volt need a lot of time */
4930d5ec955Stony.xie 	sram_udelay(100);
4940d5ec955Stony.xie }
4950d5ec955Stony.xie 
4960d5ec955Stony.xie static inline void rockchip_set_sram_sp(uint64_t set_sp)
4970d5ec955Stony.xie {
4980d5ec955Stony.xie 	__asm volatile("mov sp, %0\n"::"r" (set_sp) : "sp");
4990d5ec955Stony.xie }
5000d5ec955Stony.xie 
5010d5ec955Stony.xie static __sramfunc void ddr_suspend(void)
5020d5ec955Stony.xie {
5030d5ec955Stony.xie 	sram_data.pd_sr_idle_save = mmio_read_32(DDR_UPCTL_BASE +
5040d5ec955Stony.xie 						 DDR_PCTL2_PWRCTL);
5050d5ec955Stony.xie 	sram_data.pd_sr_idle_save &= SELFREF_EN;
5060d5ec955Stony.xie 
5070d5ec955Stony.xie 	mmio_clrbits_32(DDR_UPCTL_BASE + DDR_PCTL2_PWRCTL, SELFREF_EN);
5080d5ec955Stony.xie 	sram_data.ddr_grf_con0 = mmio_read_32(DDR_GRF_BASE +
5090d5ec955Stony.xie 					      DDRGRF_SOC_CON(0));
5100d5ec955Stony.xie 	mmio_write_32(DDR_GRF_BASE, BIT_WITH_WMSK(14) | WMSK_BIT(15));
5110d5ec955Stony.xie 
5120d5ec955Stony.xie 	/*
5130d5ec955Stony.xie 	 * Override csysreq from ddrc and
5140d5ec955Stony.xie 	 * send valid csysreq signal to PMU,
5150d5ec955Stony.xie 	 * csysreq is controlled by ddrc only
5160d5ec955Stony.xie 	 */
5170d5ec955Stony.xie 
5180d5ec955Stony.xie 	/* in self-refresh */
5190d5ec955Stony.xie 	mmio_setbits_32(PMU_BASE + PMU_SFT_CON, BIT(0));
5200d5ec955Stony.xie 	while ((mmio_read_32(DDR_GRF_BASE + DDRGRF_SOC_STATUS(1)) &
5210d5ec955Stony.xie 	       (0x03 << 12)) !=  (0x02 << 12))
5220d5ec955Stony.xie 		;
5230d5ec955Stony.xie 	/* ddr retention */
5240d5ec955Stony.xie 	mmio_setbits_32(PMU_BASE + PMU_SFT_CON, BIT(2));
5250d5ec955Stony.xie 
5260d5ec955Stony.xie 	/* ddr gating */
5270d5ec955Stony.xie 	mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(0),
5280d5ec955Stony.xie 		      BITS_WITH_WMASK(0x7, 0x7, 4));
5290d5ec955Stony.xie 	mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(7),
5300d5ec955Stony.xie 		      BITS_WITH_WMASK(1, 1, 4));
5310d5ec955Stony.xie 	mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(18),
5320d5ec955Stony.xie 		      BITS_WITH_WMASK(0x1ff, 0x1ff, 1));
5330d5ec955Stony.xie 	mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(27),
5340d5ec955Stony.xie 		      BITS_WITH_WMASK(0x3, 0x3, 0));
5350d5ec955Stony.xie 
5360d5ec955Stony.xie 	dpll_suspend();
5370d5ec955Stony.xie }
5380d5ec955Stony.xie 
5390d5ec955Stony.xie static __sramfunc  void ddr_resume(void)
5400d5ec955Stony.xie {
5410d5ec955Stony.xie 	dpll_resume();
5420d5ec955Stony.xie 
5430d5ec955Stony.xie 	/* ddr gating */
5440d5ec955Stony.xie 	mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(0),
5450d5ec955Stony.xie 		      BITS_WITH_WMASK(0, 0x7, 4));
5460d5ec955Stony.xie 	mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(7),
5470d5ec955Stony.xie 		      BITS_WITH_WMASK(0, 1, 4));
5480d5ec955Stony.xie 	mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(18),
5490d5ec955Stony.xie 		      BITS_WITH_WMASK(0, 0x1ff, 1));
5500d5ec955Stony.xie 	mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(27),
5510d5ec955Stony.xie 		      BITS_WITH_WMASK(0, 0x3, 0));
5520d5ec955Stony.xie 
5530d5ec955Stony.xie 	/* ddr de_retention */
5540d5ec955Stony.xie 	mmio_clrbits_32(PMU_BASE + PMU_SFT_CON, BIT(2));
5550d5ec955Stony.xie 	/* exit self-refresh */
5560d5ec955Stony.xie 	mmio_clrbits_32(PMU_BASE + PMU_SFT_CON, BIT(0));
5570d5ec955Stony.xie 	while ((mmio_read_32(DDR_GRF_BASE + DDRGRF_SOC_STATUS(1)) &
5580d5ec955Stony.xie 		(0x03 << 12)) !=  (0x00 << 12))
5590d5ec955Stony.xie 		;
5600d5ec955Stony.xie 
5610d5ec955Stony.xie 	mmio_write_32(DDR_GRF_BASE, sram_data.ddr_grf_con0 | 0xc0000000);
5620d5ec955Stony.xie 	if (sram_data.pd_sr_idle_save)
5630d5ec955Stony.xie 		mmio_setbits_32(DDR_UPCTL_BASE + DDR_PCTL2_PWRCTL,
5640d5ec955Stony.xie 				SELFREF_EN);
5650d5ec955Stony.xie }
5660d5ec955Stony.xie 
5670d5ec955Stony.xie static __sramfunc void sram_dbg_uart_suspend(void)
5680d5ec955Stony.xie {
5690d5ec955Stony.xie 	sram_data.uart2_ier = mmio_read_32(UART2_BASE + UART_IER);
5700d5ec955Stony.xie 	mmio_write_32(UART2_BASE + UART_IER, UART_INT_DISABLE);
5710d5ec955Stony.xie 	mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(16), 0x20002000);
5720d5ec955Stony.xie 	mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(2), 0x00040004);
5730d5ec955Stony.xie }
5740d5ec955Stony.xie 
5750d5ec955Stony.xie static __sramfunc void sram_dbg_uart_resume(void)
5760d5ec955Stony.xie {
5770d5ec955Stony.xie 	/* restore uart clk and reset fifo */
5780d5ec955Stony.xie 	mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(16), 0x20000000);
5790d5ec955Stony.xie 	mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(2), 0x00040000);
5800d5ec955Stony.xie 	mmio_write_32(UART2_BASE + UART_FCR, UART_FIFO_RESET);
5810d5ec955Stony.xie 	mmio_write_32(UART2_BASE + UART_IER, sram_data.uart2_ier);
5820d5ec955Stony.xie }
5830d5ec955Stony.xie 
5840d5ec955Stony.xie static __sramfunc void sram_soc_enter_lp(void)
5850d5ec955Stony.xie {
5860d5ec955Stony.xie 	uint32_t apm_value;
5870d5ec955Stony.xie 
5880d5ec955Stony.xie 	apm_value = BIT(core_pm_en) |
5890d5ec955Stony.xie 		    BIT(core_pm_dis_int) |
5900d5ec955Stony.xie 		    BIT(core_pm_int_wakeup_en);
5910d5ec955Stony.xie 	mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(PD_CPU0), apm_value);
5920d5ec955Stony.xie 
5930d5ec955Stony.xie 	dsb();
5940d5ec955Stony.xie 	isb();
5950d5ec955Stony.xie err_loop:
5960d5ec955Stony.xie 	wfi();
5970d5ec955Stony.xie 	/*
5980d5ec955Stony.xie 	 *Soc will enter low power mode and
5990d5ec955Stony.xie 	 *do not return to here.
6000d5ec955Stony.xie 	 */
6010d5ec955Stony.xie 	goto err_loop;
6020d5ec955Stony.xie }
6030d5ec955Stony.xie 
6040d5ec955Stony.xie __sramfunc void sram_suspend(void)
6050d5ec955Stony.xie {
6060d5ec955Stony.xie 	/* disable mmu and icache */
6070d5ec955Stony.xie 	tlbialle3();
6080d5ec955Stony.xie 	disable_mmu_icache_el3();
6090d5ec955Stony.xie 
6100d5ec955Stony.xie 	mmio_write_32(SGRF_BASE + SGRF_SOC_CON(1),
6110d5ec955Stony.xie 		      (PMUSRAM_BASE >> CPU_BOOT_ADDR_ALIGN) |
6120d5ec955Stony.xie 		      CPU_BOOT_ADDR_WMASK);
6130d5ec955Stony.xie 
6140d5ec955Stony.xie 	/* ddr self-refresh and gating phy */
6150d5ec955Stony.xie 	ddr_suspend();
6160d5ec955Stony.xie 
6170d5ec955Stony.xie 	rk3328_pmic_suspend();
6180d5ec955Stony.xie 
6190d5ec955Stony.xie 	sram_dbg_uart_suspend();
6200d5ec955Stony.xie 
6210d5ec955Stony.xie 	sram_soc_enter_lp();
6220d5ec955Stony.xie }
6230d5ec955Stony.xie 
6240d5ec955Stony.xie static __sramfunc void sys_resume_first(void)
6250d5ec955Stony.xie {
6260d5ec955Stony.xie 	sram_dbg_uart_resume();
6270d5ec955Stony.xie 
6280d5ec955Stony.xie 	rk3328_pmic_resume();
6290d5ec955Stony.xie 
6300d5ec955Stony.xie 	/* ddr self-refresh exit */
6310d5ec955Stony.xie 	ddr_resume();
6320d5ec955Stony.xie 
6330d5ec955Stony.xie 	/* disable apm cfg */
6340d5ec955Stony.xie 	mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(0), CORES_PM_DISABLE);
6350d5ec955Stony.xie 
6360d5ec955Stony.xie 	/* the warm booting address of cpus */
6370d5ec955Stony.xie 	mmio_write_32(SGRF_BASE + SGRF_SOC_CON(1),
6380d5ec955Stony.xie 		      (cpu_warm_boot_addr >> CPU_BOOT_ADDR_ALIGN) |
6390d5ec955Stony.xie 		      CPU_BOOT_ADDR_WMASK);
6400d5ec955Stony.xie }
6410d5ec955Stony.xie 
6420d5ec955Stony.xie void __dead2 rockchip_soc_sys_pd_pwr_dn_wfi(void)
6430d5ec955Stony.xie {
6440d5ec955Stony.xie 	rockchip_set_sram_sp(PSRAM_DT_BASE);
6450d5ec955Stony.xie 
6460d5ec955Stony.xie 	sram_suspend();
6470d5ec955Stony.xie 
6480d5ec955Stony.xie 	/* should never reach here */
6490d5ec955Stony.xie 	psci_power_down_wfi();
6500d5ec955Stony.xie }
6510d5ec955Stony.xie 
6520d5ec955Stony.xie int rockchip_soc_sys_pwr_dm_suspend(void)
6530d5ec955Stony.xie {
6540d5ec955Stony.xie 	clks_gating_suspend(clk_ungt_msk);
6550d5ec955Stony.xie 
6560d5ec955Stony.xie 	pm_plls_suspend();
6570d5ec955Stony.xie 
6580d5ec955Stony.xie 	return 0;
6590d5ec955Stony.xie }
6600d5ec955Stony.xie 
6610d5ec955Stony.xie int rockchip_soc_sys_pwr_dm_resume(void)
6620d5ec955Stony.xie {
6630d5ec955Stony.xie 	pm_plls_resume();
6640d5ec955Stony.xie 
6650d5ec955Stony.xie 	clks_gating_resume();
6660d5ec955Stony.xie 
6670d5ec955Stony.xie 	plat_rockchip_gic_cpuif_enable();
6680d5ec955Stony.xie 
6690d5ec955Stony.xie 	return 0;
6700d5ec955Stony.xie }
6710d5ec955Stony.xie 
6720d5ec955Stony.xie void plat_rockchip_pmu_init(void)
6730d5ec955Stony.xie {
6740d5ec955Stony.xie 	uint32_t cpu;
6750d5ec955Stony.xie 
6760d5ec955Stony.xie 	for (cpu = 0; cpu < PLATFORM_CORE_COUNT; cpu++)
6770d5ec955Stony.xie 		cpuson_flags[cpu] = 0;
6780d5ec955Stony.xie 
6790d5ec955Stony.xie 	cpu_warm_boot_addr = (uint64_t)platform_cpu_warmboot;
6800d5ec955Stony.xie 	psram_sleep_cfg->ddr_func = (uint64_t)sys_resume_first;
6810d5ec955Stony.xie 	psram_sleep_cfg->ddr_data = 0x00;
6820d5ec955Stony.xie 	psram_sleep_cfg->ddr_flag = 0x01;
6830d5ec955Stony.xie 	psram_sleep_cfg->boot_mpidr = read_mpidr_el1() & 0xffff;
6840d5ec955Stony.xie 
6850d5ec955Stony.xie 	/* the warm booting address of cpus */
6860d5ec955Stony.xie 	mmio_write_32(SGRF_BASE + SGRF_SOC_CON(1),
6870d5ec955Stony.xie 		      (cpu_warm_boot_addr >> CPU_BOOT_ADDR_ALIGN) |
6880d5ec955Stony.xie 		      CPU_BOOT_ADDR_WMASK);
6890d5ec955Stony.xie 
6900d5ec955Stony.xie 	nonboot_cpus_off();
6910d5ec955Stony.xie 
6920d5ec955Stony.xie 	INFO("%s: pd status 0x%x\n",
6930d5ec955Stony.xie 	     __func__, mmio_read_32(PMU_BASE + PMU_PWRDN_ST));
6940d5ec955Stony.xie }
695