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