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