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