1010d6ae3SXiaoDong Huang /* 2010d6ae3SXiaoDong Huang * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. 3010d6ae3SXiaoDong Huang * 4010d6ae3SXiaoDong Huang * SPDX-License-Identifier: BSD-3-Clause 5010d6ae3SXiaoDong Huang */ 6010d6ae3SXiaoDong Huang 7010d6ae3SXiaoDong Huang #include <assert.h> 8010d6ae3SXiaoDong Huang #include <errno.h> 9010d6ae3SXiaoDong Huang 10010d6ae3SXiaoDong Huang #include <platform_def.h> 11010d6ae3SXiaoDong Huang 12010d6ae3SXiaoDong Huang #include <arch_helpers.h> 13010d6ae3SXiaoDong Huang #include <bl31/bl31.h> 14010d6ae3SXiaoDong Huang #include <common/debug.h> 15010d6ae3SXiaoDong Huang #include <drivers/console.h> 16010d6ae3SXiaoDong Huang #include <drivers/delay_timer.h> 17010d6ae3SXiaoDong Huang #include <lib/bakery_lock.h> 18010d6ae3SXiaoDong Huang #include <lib/mmio.h> 19010d6ae3SXiaoDong Huang #include <plat/common/platform.h> 20010d6ae3SXiaoDong Huang 21010d6ae3SXiaoDong Huang #include <cpus_on_fixed_addr.h> 22010d6ae3SXiaoDong Huang #include <plat_private.h> 23010d6ae3SXiaoDong Huang #include <pmu.h> 24010d6ae3SXiaoDong Huang #include <px30_def.h> 25*d2483afaSHeiko Stuebner #include <secure.h> 26010d6ae3SXiaoDong Huang #include <soc.h> 27010d6ae3SXiaoDong Huang 28010d6ae3SXiaoDong Huang DEFINE_BAKERY_LOCK(rockchip_pd_lock); 29010d6ae3SXiaoDong Huang #define rockchip_pd_lock_init() bakery_lock_init(&rockchip_pd_lock) 30010d6ae3SXiaoDong Huang #define rockchip_pd_lock_get() bakery_lock_get(&rockchip_pd_lock) 31010d6ae3SXiaoDong Huang #define rockchip_pd_lock_rls() bakery_lock_release(&rockchip_pd_lock) 32010d6ae3SXiaoDong Huang 33010d6ae3SXiaoDong Huang static struct psram_data_t *psram_boot_cfg = 34010d6ae3SXiaoDong Huang (struct psram_data_t *)&sys_sleep_flag_sram; 35010d6ae3SXiaoDong Huang 36010d6ae3SXiaoDong Huang /* 37010d6ae3SXiaoDong Huang * There are two ways to powering on or off on core. 38010d6ae3SXiaoDong Huang * 1) Control it power domain into on or off in PMU_PWRDN_CON reg, 39010d6ae3SXiaoDong Huang * it is core_pwr_pd mode 40010d6ae3SXiaoDong Huang * 2) Enable the core power manage in PMU_CORE_PM_CON reg, 41010d6ae3SXiaoDong Huang * then, if the core enter into wfi, it power domain will be 42010d6ae3SXiaoDong Huang * powered off automatically. it is core_pwr_wfi or core_pwr_wfi_int mode 43010d6ae3SXiaoDong Huang * so we need core_pm_cfg_info to distinguish which method be used now. 44010d6ae3SXiaoDong Huang */ 45010d6ae3SXiaoDong Huang 46010d6ae3SXiaoDong Huang static uint32_t cores_pd_cfg_info[PLATFORM_CORE_COUNT] 47010d6ae3SXiaoDong Huang #if USE_COHERENT_MEM 48010d6ae3SXiaoDong Huang __attribute__ ((section("tzfw_coherent_mem"))) 49010d6ae3SXiaoDong Huang #endif 50010d6ae3SXiaoDong Huang ; 51010d6ae3SXiaoDong Huang 52010d6ae3SXiaoDong Huang struct px30_sleep_ddr_data { 53010d6ae3SXiaoDong Huang uint32_t clk_sel0; 54010d6ae3SXiaoDong Huang uint32_t cru_mode_save; 55010d6ae3SXiaoDong Huang uint32_t cru_pmu_mode_save; 56010d6ae3SXiaoDong Huang uint32_t ddrc_hwlpctl; 57010d6ae3SXiaoDong Huang uint32_t ddrc_pwrctrl; 58010d6ae3SXiaoDong Huang uint32_t ddrgrf_con0; 59010d6ae3SXiaoDong Huang uint32_t ddrgrf_con1; 60010d6ae3SXiaoDong Huang uint32_t ddrstdby_con0; 61010d6ae3SXiaoDong Huang uint32_t gpio0b_iomux; 62010d6ae3SXiaoDong Huang uint32_t gpio0c_iomux; 63010d6ae3SXiaoDong Huang uint32_t pmu_pwrmd_core_l; 64010d6ae3SXiaoDong Huang uint32_t pmu_pwrmd_core_h; 65010d6ae3SXiaoDong Huang uint32_t pmu_pwrmd_cmm_l; 66010d6ae3SXiaoDong Huang uint32_t pmu_pwrmd_cmm_h; 67010d6ae3SXiaoDong Huang uint32_t pmu_wkup_cfg2_l; 68010d6ae3SXiaoDong Huang uint32_t pmu_cru_clksel_con0; 69010d6ae3SXiaoDong Huang uint32_t pmugrf_soc_con0; 70010d6ae3SXiaoDong Huang uint32_t pmusgrf_soc_con0; 71010d6ae3SXiaoDong Huang uint32_t pmic_slp_iomux; 72010d6ae3SXiaoDong Huang uint32_t pgrf_pvtm_con[2]; 73010d6ae3SXiaoDong Huang uint32_t cru_clk_gate[CRU_CLKGATES_CON_CNT]; 74010d6ae3SXiaoDong Huang uint32_t cru_pmu_clk_gate[CRU_PMU_CLKGATE_CON_CNT]; 75010d6ae3SXiaoDong Huang uint32_t cru_plls_con_save[END_PLL_ID][PLL_CON_CNT]; 76010d6ae3SXiaoDong Huang uint32_t cpu_qos[CPU_AXI_QOS_NUM_REGS]; 77010d6ae3SXiaoDong Huang uint32_t gpu_qos[CPU_AXI_QOS_NUM_REGS]; 78010d6ae3SXiaoDong Huang uint32_t isp_128m_qos[CPU_AXI_QOS_NUM_REGS]; 79010d6ae3SXiaoDong Huang uint32_t isp_rd_qos[CPU_AXI_QOS_NUM_REGS]; 80010d6ae3SXiaoDong Huang uint32_t isp_wr_qos[CPU_AXI_QOS_NUM_REGS]; 81010d6ae3SXiaoDong Huang uint32_t isp_m1_qos[CPU_AXI_QOS_NUM_REGS]; 82010d6ae3SXiaoDong Huang uint32_t vip_qos[CPU_AXI_QOS_NUM_REGS]; 83010d6ae3SXiaoDong Huang uint32_t rga_rd_qos[CPU_AXI_QOS_NUM_REGS]; 84010d6ae3SXiaoDong Huang uint32_t rga_wr_qos[CPU_AXI_QOS_NUM_REGS]; 85010d6ae3SXiaoDong Huang uint32_t vop_m0_qos[CPU_AXI_QOS_NUM_REGS]; 86010d6ae3SXiaoDong Huang uint32_t vop_m1_qos[CPU_AXI_QOS_NUM_REGS]; 87010d6ae3SXiaoDong Huang uint32_t vpu_qos[CPU_AXI_QOS_NUM_REGS]; 88010d6ae3SXiaoDong Huang uint32_t vpu_r128_qos[CPU_AXI_QOS_NUM_REGS]; 89010d6ae3SXiaoDong Huang uint32_t dcf_qos[CPU_AXI_QOS_NUM_REGS]; 90010d6ae3SXiaoDong Huang uint32_t dmac_qos[CPU_AXI_QOS_NUM_REGS]; 91010d6ae3SXiaoDong Huang uint32_t crypto_qos[CPU_AXI_QOS_NUM_REGS]; 92010d6ae3SXiaoDong Huang uint32_t gmac_qos[CPU_AXI_QOS_NUM_REGS]; 93010d6ae3SXiaoDong Huang uint32_t emmc_qos[CPU_AXI_QOS_NUM_REGS]; 94010d6ae3SXiaoDong Huang uint32_t nand_qos[CPU_AXI_QOS_NUM_REGS]; 95010d6ae3SXiaoDong Huang uint32_t sdio_qos[CPU_AXI_QOS_NUM_REGS]; 96010d6ae3SXiaoDong Huang uint32_t sfc_qos[CPU_AXI_QOS_NUM_REGS]; 97010d6ae3SXiaoDong Huang uint32_t sdmmc_qos[CPU_AXI_QOS_NUM_REGS]; 98010d6ae3SXiaoDong Huang uint32_t usb_host_qos[CPU_AXI_QOS_NUM_REGS]; 99010d6ae3SXiaoDong Huang uint32_t usb_otg_qos[CPU_AXI_QOS_NUM_REGS]; 100010d6ae3SXiaoDong Huang }; 101010d6ae3SXiaoDong Huang 102010d6ae3SXiaoDong Huang static struct px30_sleep_ddr_data ddr_data 103010d6ae3SXiaoDong Huang #if USE_COHERENT_MEM 104010d6ae3SXiaoDong Huang __attribute__ ((section("tzfw_coherent_mem"))) 105010d6ae3SXiaoDong Huang #endif 106010d6ae3SXiaoDong Huang ; 107010d6ae3SXiaoDong Huang 108010d6ae3SXiaoDong Huang static inline uint32_t get_cpus_pwr_domain_cfg_info(uint32_t cpu_id) 109010d6ae3SXiaoDong Huang { 110010d6ae3SXiaoDong Huang assert(cpu_id < PLATFORM_CORE_COUNT); 111010d6ae3SXiaoDong Huang return cores_pd_cfg_info[cpu_id]; 112010d6ae3SXiaoDong Huang } 113010d6ae3SXiaoDong Huang 114010d6ae3SXiaoDong Huang static inline void set_cpus_pwr_domain_cfg_info(uint32_t cpu_id, uint32_t value) 115010d6ae3SXiaoDong Huang { 116010d6ae3SXiaoDong Huang assert(cpu_id < PLATFORM_CORE_COUNT); 117010d6ae3SXiaoDong Huang cores_pd_cfg_info[cpu_id] = value; 118010d6ae3SXiaoDong Huang #if !USE_COHERENT_MEM 119010d6ae3SXiaoDong Huang flush_dcache_range((uintptr_t)&cores_pd_cfg_info[cpu_id], 120010d6ae3SXiaoDong Huang sizeof(uint32_t)); 121010d6ae3SXiaoDong Huang #endif 122010d6ae3SXiaoDong Huang } 123010d6ae3SXiaoDong Huang 124010d6ae3SXiaoDong Huang static inline uint32_t pmu_power_domain_st(uint32_t pd) 125010d6ae3SXiaoDong Huang { 126010d6ae3SXiaoDong Huang return mmio_read_32(PMU_BASE + PMU_PWRDN_ST) & BIT(pd) ? 127010d6ae3SXiaoDong Huang pmu_pd_off : 128010d6ae3SXiaoDong Huang pmu_pd_on; 129010d6ae3SXiaoDong Huang } 130010d6ae3SXiaoDong Huang 131010d6ae3SXiaoDong Huang static int pmu_power_domain_ctr(uint32_t pd, uint32_t pd_state) 132010d6ae3SXiaoDong Huang { 133010d6ae3SXiaoDong Huang uint32_t loop = 0; 134010d6ae3SXiaoDong Huang int ret = 0; 135010d6ae3SXiaoDong Huang 136010d6ae3SXiaoDong Huang rockchip_pd_lock_get(); 137010d6ae3SXiaoDong Huang 138010d6ae3SXiaoDong Huang mmio_write_32(PMU_BASE + PMU_PWRDN_CON, 139010d6ae3SXiaoDong Huang BITS_WITH_WMASK(pd_state, 0x1, pd)); 140010d6ae3SXiaoDong Huang dsb(); 141010d6ae3SXiaoDong Huang 142010d6ae3SXiaoDong Huang while ((pmu_power_domain_st(pd) != pd_state) && (loop < PD_CTR_LOOP)) { 143010d6ae3SXiaoDong Huang udelay(1); 144010d6ae3SXiaoDong Huang loop++; 145010d6ae3SXiaoDong Huang } 146010d6ae3SXiaoDong Huang 147010d6ae3SXiaoDong Huang if (pmu_power_domain_st(pd) != pd_state) { 148010d6ae3SXiaoDong Huang WARN("%s: %d, %d, error!\n", __func__, pd, pd_state); 149010d6ae3SXiaoDong Huang ret = -EINVAL; 150010d6ae3SXiaoDong Huang } 151010d6ae3SXiaoDong Huang 152010d6ae3SXiaoDong Huang rockchip_pd_lock_rls(); 153010d6ae3SXiaoDong Huang 154010d6ae3SXiaoDong Huang return ret; 155010d6ae3SXiaoDong Huang } 156010d6ae3SXiaoDong Huang 157010d6ae3SXiaoDong Huang static inline uint32_t pmu_bus_idle_st(uint32_t bus) 158010d6ae3SXiaoDong Huang { 159010d6ae3SXiaoDong Huang return !!((mmio_read_32(PMU_BASE + PMU_BUS_IDLE_ST) & BIT(bus)) && 160010d6ae3SXiaoDong Huang (mmio_read_32(PMU_BASE + PMU_BUS_IDLE_ST) & BIT(bus + 16))); 161010d6ae3SXiaoDong Huang } 162010d6ae3SXiaoDong Huang 163010d6ae3SXiaoDong Huang static void pmu_bus_idle_req(uint32_t bus, uint32_t state) 164010d6ae3SXiaoDong Huang { 165010d6ae3SXiaoDong Huang uint32_t wait_cnt = 0; 166010d6ae3SXiaoDong Huang 167010d6ae3SXiaoDong Huang mmio_write_32(PMU_BASE + PMU_BUS_IDLE_REQ, 168010d6ae3SXiaoDong Huang BITS_WITH_WMASK(state, 0x1, bus)); 169010d6ae3SXiaoDong Huang 170010d6ae3SXiaoDong Huang while (pmu_bus_idle_st(bus) != state && 171010d6ae3SXiaoDong Huang wait_cnt < BUS_IDLE_LOOP) { 172010d6ae3SXiaoDong Huang udelay(1); 173010d6ae3SXiaoDong Huang wait_cnt++; 174010d6ae3SXiaoDong Huang } 175010d6ae3SXiaoDong Huang 176010d6ae3SXiaoDong Huang if (pmu_bus_idle_st(bus) != state) 177010d6ae3SXiaoDong Huang WARN("%s:idle_st=0x%x, bus_id=%d\n", 178010d6ae3SXiaoDong Huang __func__, mmio_read_32(PMU_BASE + PMU_BUS_IDLE_ST), bus); 179010d6ae3SXiaoDong Huang } 180010d6ae3SXiaoDong Huang 181010d6ae3SXiaoDong Huang static void qos_save(void) 182010d6ae3SXiaoDong Huang { 183010d6ae3SXiaoDong Huang /* scu powerdomain will power off, so cpu qos should be saved */ 184010d6ae3SXiaoDong Huang SAVE_QOS(ddr_data.cpu_qos, CPU); 185010d6ae3SXiaoDong Huang 186010d6ae3SXiaoDong Huang if (pmu_power_domain_st(PD_GPU) == pmu_pd_on) 187010d6ae3SXiaoDong Huang SAVE_QOS(ddr_data.gpu_qos, GPU); 188010d6ae3SXiaoDong Huang if (pmu_power_domain_st(PD_VI) == pmu_pd_on) { 189010d6ae3SXiaoDong Huang SAVE_QOS(ddr_data.isp_128m_qos, ISP_128M); 190010d6ae3SXiaoDong Huang SAVE_QOS(ddr_data.isp_rd_qos, ISP_RD); 191010d6ae3SXiaoDong Huang SAVE_QOS(ddr_data.isp_wr_qos, ISP_WR); 192010d6ae3SXiaoDong Huang SAVE_QOS(ddr_data.isp_m1_qos, ISP_M1); 193010d6ae3SXiaoDong Huang SAVE_QOS(ddr_data.vip_qos, VIP); 194010d6ae3SXiaoDong Huang } 195010d6ae3SXiaoDong Huang if (pmu_power_domain_st(PD_VO) == pmu_pd_on) { 196010d6ae3SXiaoDong Huang SAVE_QOS(ddr_data.rga_rd_qos, RGA_RD); 197010d6ae3SXiaoDong Huang SAVE_QOS(ddr_data.rga_wr_qos, RGA_WR); 198010d6ae3SXiaoDong Huang SAVE_QOS(ddr_data.vop_m0_qos, VOP_M0); 199010d6ae3SXiaoDong Huang SAVE_QOS(ddr_data.vop_m1_qos, VOP_M1); 200010d6ae3SXiaoDong Huang } 201010d6ae3SXiaoDong Huang if (pmu_power_domain_st(PD_VPU) == pmu_pd_on) { 202010d6ae3SXiaoDong Huang SAVE_QOS(ddr_data.vpu_qos, VPU); 203010d6ae3SXiaoDong Huang SAVE_QOS(ddr_data.vpu_r128_qos, VPU_R128); 204010d6ae3SXiaoDong Huang } 205010d6ae3SXiaoDong Huang if (pmu_power_domain_st(PD_MMC_NAND) == pmu_pd_on) { 206010d6ae3SXiaoDong Huang SAVE_QOS(ddr_data.emmc_qos, EMMC); 207010d6ae3SXiaoDong Huang SAVE_QOS(ddr_data.nand_qos, NAND); 208010d6ae3SXiaoDong Huang SAVE_QOS(ddr_data.sdio_qos, SDIO); 209010d6ae3SXiaoDong Huang SAVE_QOS(ddr_data.sfc_qos, SFC); 210010d6ae3SXiaoDong Huang } 211010d6ae3SXiaoDong Huang if (pmu_power_domain_st(PD_GMAC) == pmu_pd_on) 212010d6ae3SXiaoDong Huang SAVE_QOS(ddr_data.gmac_qos, GMAC); 213010d6ae3SXiaoDong Huang if (pmu_power_domain_st(PD_CRYPTO) == pmu_pd_on) 214010d6ae3SXiaoDong Huang SAVE_QOS(ddr_data.crypto_qos, CRYPTO); 215010d6ae3SXiaoDong Huang if (pmu_power_domain_st(PD_SDCARD) == pmu_pd_on) 216010d6ae3SXiaoDong Huang SAVE_QOS(ddr_data.sdmmc_qos, SDMMC); 217010d6ae3SXiaoDong Huang if (pmu_power_domain_st(PD_USB) == pmu_pd_on) { 218010d6ae3SXiaoDong Huang SAVE_QOS(ddr_data.usb_host_qos, USB_HOST); 219010d6ae3SXiaoDong Huang SAVE_QOS(ddr_data.usb_otg_qos, USB_OTG); 220010d6ae3SXiaoDong Huang } 221010d6ae3SXiaoDong Huang } 222010d6ae3SXiaoDong Huang 223010d6ae3SXiaoDong Huang static void qos_restore(void) 224010d6ae3SXiaoDong Huang { 225010d6ae3SXiaoDong Huang RESTORE_QOS(ddr_data.cpu_qos, CPU); 226010d6ae3SXiaoDong Huang 227010d6ae3SXiaoDong Huang if (pmu_power_domain_st(PD_GPU) == pmu_pd_on) 228010d6ae3SXiaoDong Huang RESTORE_QOS(ddr_data.gpu_qos, GPU); 229010d6ae3SXiaoDong Huang if (pmu_power_domain_st(PD_VI) == pmu_pd_on) { 230010d6ae3SXiaoDong Huang RESTORE_QOS(ddr_data.isp_128m_qos, ISP_128M); 231010d6ae3SXiaoDong Huang RESTORE_QOS(ddr_data.isp_rd_qos, ISP_RD); 232010d6ae3SXiaoDong Huang RESTORE_QOS(ddr_data.isp_wr_qos, ISP_WR); 233010d6ae3SXiaoDong Huang RESTORE_QOS(ddr_data.isp_m1_qos, ISP_M1); 234010d6ae3SXiaoDong Huang RESTORE_QOS(ddr_data.vip_qos, VIP); 235010d6ae3SXiaoDong Huang } 236010d6ae3SXiaoDong Huang if (pmu_power_domain_st(PD_VO) == pmu_pd_on) { 237010d6ae3SXiaoDong Huang RESTORE_QOS(ddr_data.rga_rd_qos, RGA_RD); 238010d6ae3SXiaoDong Huang RESTORE_QOS(ddr_data.rga_wr_qos, RGA_WR); 239010d6ae3SXiaoDong Huang RESTORE_QOS(ddr_data.vop_m0_qos, VOP_M0); 240010d6ae3SXiaoDong Huang RESTORE_QOS(ddr_data.vop_m1_qos, VOP_M1); 241010d6ae3SXiaoDong Huang } 242010d6ae3SXiaoDong Huang if (pmu_power_domain_st(PD_VPU) == pmu_pd_on) { 243010d6ae3SXiaoDong Huang RESTORE_QOS(ddr_data.vpu_qos, VPU); 244010d6ae3SXiaoDong Huang RESTORE_QOS(ddr_data.vpu_r128_qos, VPU_R128); 245010d6ae3SXiaoDong Huang } 246010d6ae3SXiaoDong Huang if (pmu_power_domain_st(PD_MMC_NAND) == pmu_pd_on) { 247010d6ae3SXiaoDong Huang RESTORE_QOS(ddr_data.emmc_qos, EMMC); 248010d6ae3SXiaoDong Huang RESTORE_QOS(ddr_data.nand_qos, NAND); 249010d6ae3SXiaoDong Huang RESTORE_QOS(ddr_data.sdio_qos, SDIO); 250010d6ae3SXiaoDong Huang RESTORE_QOS(ddr_data.sfc_qos, SFC); 251010d6ae3SXiaoDong Huang } 252010d6ae3SXiaoDong Huang if (pmu_power_domain_st(PD_GMAC) == pmu_pd_on) 253010d6ae3SXiaoDong Huang RESTORE_QOS(ddr_data.gmac_qos, GMAC); 254010d6ae3SXiaoDong Huang if (pmu_power_domain_st(PD_CRYPTO) == pmu_pd_on) 255010d6ae3SXiaoDong Huang RESTORE_QOS(ddr_data.crypto_qos, CRYPTO); 256010d6ae3SXiaoDong Huang if (pmu_power_domain_st(PD_SDCARD) == pmu_pd_on) 257010d6ae3SXiaoDong Huang RESTORE_QOS(ddr_data.sdmmc_qos, SDMMC); 258010d6ae3SXiaoDong Huang if (pmu_power_domain_st(PD_USB) == pmu_pd_on) { 259010d6ae3SXiaoDong Huang RESTORE_QOS(ddr_data.usb_host_qos, USB_HOST); 260010d6ae3SXiaoDong Huang RESTORE_QOS(ddr_data.usb_otg_qos, USB_OTG); 261010d6ae3SXiaoDong Huang } 262010d6ae3SXiaoDong Huang } 263010d6ae3SXiaoDong Huang 264010d6ae3SXiaoDong Huang static int pmu_set_power_domain(uint32_t pd_id, uint32_t pd_state) 265010d6ae3SXiaoDong Huang { 266010d6ae3SXiaoDong Huang uint32_t state; 267010d6ae3SXiaoDong Huang 268010d6ae3SXiaoDong Huang if (pmu_power_domain_st(pd_id) == pd_state) 269010d6ae3SXiaoDong Huang goto out; 270010d6ae3SXiaoDong Huang 271010d6ae3SXiaoDong Huang if (pd_state == pmu_pd_on) 272010d6ae3SXiaoDong Huang pmu_power_domain_ctr(pd_id, pd_state); 273010d6ae3SXiaoDong Huang 274010d6ae3SXiaoDong Huang state = (pd_state == pmu_pd_off) ? bus_idle : bus_active; 275010d6ae3SXiaoDong Huang 276010d6ae3SXiaoDong Huang switch (pd_id) { 277010d6ae3SXiaoDong Huang case PD_GPU: 278010d6ae3SXiaoDong Huang pmu_bus_idle_req(BUS_ID_GPU, state); 279010d6ae3SXiaoDong Huang break; 280010d6ae3SXiaoDong Huang case PD_VI: 281010d6ae3SXiaoDong Huang pmu_bus_idle_req(BUS_ID_VI, state); 282010d6ae3SXiaoDong Huang break; 283010d6ae3SXiaoDong Huang case PD_VO: 284010d6ae3SXiaoDong Huang pmu_bus_idle_req(BUS_ID_VO, state); 285010d6ae3SXiaoDong Huang break; 286010d6ae3SXiaoDong Huang case PD_VPU: 287010d6ae3SXiaoDong Huang pmu_bus_idle_req(BUS_ID_VPU, state); 288010d6ae3SXiaoDong Huang break; 289010d6ae3SXiaoDong Huang case PD_MMC_NAND: 290010d6ae3SXiaoDong Huang pmu_bus_idle_req(BUS_ID_MMC, state); 291010d6ae3SXiaoDong Huang break; 292010d6ae3SXiaoDong Huang case PD_GMAC: 293010d6ae3SXiaoDong Huang pmu_bus_idle_req(BUS_ID_GMAC, state); 294010d6ae3SXiaoDong Huang break; 295010d6ae3SXiaoDong Huang case PD_CRYPTO: 296010d6ae3SXiaoDong Huang pmu_bus_idle_req(BUS_ID_CRYPTO, state); 297010d6ae3SXiaoDong Huang break; 298010d6ae3SXiaoDong Huang case PD_SDCARD: 299010d6ae3SXiaoDong Huang pmu_bus_idle_req(BUS_ID_SDCARD, state); 300010d6ae3SXiaoDong Huang break; 301010d6ae3SXiaoDong Huang case PD_USB: 302010d6ae3SXiaoDong Huang pmu_bus_idle_req(BUS_ID_USB, state); 303010d6ae3SXiaoDong Huang break; 304010d6ae3SXiaoDong Huang default: 305010d6ae3SXiaoDong Huang break; 306010d6ae3SXiaoDong Huang } 307010d6ae3SXiaoDong Huang 308010d6ae3SXiaoDong Huang if (pd_state == pmu_pd_off) 309010d6ae3SXiaoDong Huang pmu_power_domain_ctr(pd_id, pd_state); 310010d6ae3SXiaoDong Huang 311010d6ae3SXiaoDong Huang out: 312010d6ae3SXiaoDong Huang return 0; 313010d6ae3SXiaoDong Huang } 314010d6ae3SXiaoDong Huang 315010d6ae3SXiaoDong Huang static uint32_t pmu_powerdomain_state; 316010d6ae3SXiaoDong Huang 317010d6ae3SXiaoDong Huang static void pmu_power_domains_suspend(void) 318010d6ae3SXiaoDong Huang { 319010d6ae3SXiaoDong Huang uint32_t clkgt_save[CRU_CLKGATES_CON_CNT + CRU_PMU_CLKGATE_CON_CNT]; 320010d6ae3SXiaoDong Huang 321010d6ae3SXiaoDong Huang clk_gate_con_save(clkgt_save); 322010d6ae3SXiaoDong Huang clk_gate_con_disable(); 323010d6ae3SXiaoDong Huang qos_save(); 324010d6ae3SXiaoDong Huang 325010d6ae3SXiaoDong Huang pmu_powerdomain_state = mmio_read_32(PMU_BASE + PMU_PWRDN_ST); 326010d6ae3SXiaoDong Huang pmu_set_power_domain(PD_GPU, pmu_pd_off); 327010d6ae3SXiaoDong Huang pmu_set_power_domain(PD_VI, pmu_pd_off); 328010d6ae3SXiaoDong Huang pmu_set_power_domain(PD_VO, pmu_pd_off); 329010d6ae3SXiaoDong Huang pmu_set_power_domain(PD_VPU, pmu_pd_off); 330010d6ae3SXiaoDong Huang pmu_set_power_domain(PD_MMC_NAND, pmu_pd_off); 331010d6ae3SXiaoDong Huang pmu_set_power_domain(PD_GMAC, pmu_pd_off); 332010d6ae3SXiaoDong Huang pmu_set_power_domain(PD_CRYPTO, pmu_pd_off); 333010d6ae3SXiaoDong Huang pmu_set_power_domain(PD_SDCARD, pmu_pd_off); 334010d6ae3SXiaoDong Huang pmu_set_power_domain(PD_USB, pmu_pd_off); 335010d6ae3SXiaoDong Huang 336010d6ae3SXiaoDong Huang clk_gate_con_restore(clkgt_save); 337010d6ae3SXiaoDong Huang } 338010d6ae3SXiaoDong Huang 339010d6ae3SXiaoDong Huang static void pmu_power_domains_resume(void) 340010d6ae3SXiaoDong Huang { 341010d6ae3SXiaoDong Huang uint32_t clkgt_save[CRU_CLKGATES_CON_CNT + CRU_PMU_CLKGATE_CON_CNT]; 342010d6ae3SXiaoDong Huang 343010d6ae3SXiaoDong Huang clk_gate_con_save(clkgt_save); 344010d6ae3SXiaoDong Huang clk_gate_con_disable(); 345010d6ae3SXiaoDong Huang 346010d6ae3SXiaoDong Huang if (!(pmu_powerdomain_state & BIT(PD_USB))) 347010d6ae3SXiaoDong Huang pmu_set_power_domain(PD_USB, pmu_pd_on); 348010d6ae3SXiaoDong Huang if (!(pmu_powerdomain_state & BIT(PD_SDCARD))) 349010d6ae3SXiaoDong Huang pmu_set_power_domain(PD_SDCARD, pmu_pd_on); 350010d6ae3SXiaoDong Huang if (!(pmu_powerdomain_state & BIT(PD_CRYPTO))) 351010d6ae3SXiaoDong Huang pmu_set_power_domain(PD_CRYPTO, pmu_pd_on); 352010d6ae3SXiaoDong Huang if (!(pmu_powerdomain_state & BIT(PD_GMAC))) 353010d6ae3SXiaoDong Huang pmu_set_power_domain(PD_GMAC, pmu_pd_on); 354010d6ae3SXiaoDong Huang if (!(pmu_powerdomain_state & BIT(PD_MMC_NAND))) 355010d6ae3SXiaoDong Huang pmu_set_power_domain(PD_MMC_NAND, pmu_pd_on); 356010d6ae3SXiaoDong Huang if (!(pmu_powerdomain_state & BIT(PD_VPU))) 357010d6ae3SXiaoDong Huang pmu_set_power_domain(PD_VPU, pmu_pd_on); 358010d6ae3SXiaoDong Huang if (!(pmu_powerdomain_state & BIT(PD_VO))) 359010d6ae3SXiaoDong Huang pmu_set_power_domain(PD_VO, pmu_pd_on); 360010d6ae3SXiaoDong Huang if (!(pmu_powerdomain_state & BIT(PD_VI))) 361010d6ae3SXiaoDong Huang pmu_set_power_domain(PD_VI, pmu_pd_on); 362010d6ae3SXiaoDong Huang if (!(pmu_powerdomain_state & BIT(PD_GPU))) 363010d6ae3SXiaoDong Huang pmu_set_power_domain(PD_GPU, pmu_pd_on); 364010d6ae3SXiaoDong Huang 365010d6ae3SXiaoDong Huang qos_restore(); 366010d6ae3SXiaoDong Huang clk_gate_con_restore(clkgt_save); 367010d6ae3SXiaoDong Huang } 368010d6ae3SXiaoDong Huang 369010d6ae3SXiaoDong Huang static int check_cpu_wfie(uint32_t cpu) 370010d6ae3SXiaoDong Huang { 371010d6ae3SXiaoDong Huang uint32_t loop = 0, wfie_msk = CKECK_WFEI_MSK << cpu; 372010d6ae3SXiaoDong Huang 373010d6ae3SXiaoDong Huang while (!(mmio_read_32(GRF_BASE + GRF_CPU_STATUS1) & wfie_msk) && 374010d6ae3SXiaoDong Huang (loop < WFEI_CHECK_LOOP)) { 375010d6ae3SXiaoDong Huang udelay(1); 376010d6ae3SXiaoDong Huang loop++; 377010d6ae3SXiaoDong Huang } 378010d6ae3SXiaoDong Huang 379010d6ae3SXiaoDong Huang if ((mmio_read_32(GRF_BASE + GRF_CPU_STATUS1) & wfie_msk) == 0) { 380010d6ae3SXiaoDong Huang WARN("%s: %d, %d, error!\n", __func__, cpu, wfie_msk); 381010d6ae3SXiaoDong Huang return -EINVAL; 382010d6ae3SXiaoDong Huang } 383010d6ae3SXiaoDong Huang 384010d6ae3SXiaoDong Huang return 0; 385010d6ae3SXiaoDong Huang } 386010d6ae3SXiaoDong Huang 387010d6ae3SXiaoDong Huang static int cpus_power_domain_on(uint32_t cpu_id) 388010d6ae3SXiaoDong Huang { 389010d6ae3SXiaoDong Huang uint32_t cpu_pd, apm_value, cfg_info, loop = 0; 390010d6ae3SXiaoDong Huang 391010d6ae3SXiaoDong Huang cpu_pd = PD_CPU0 + cpu_id; 392010d6ae3SXiaoDong Huang cfg_info = get_cpus_pwr_domain_cfg_info(cpu_id); 393010d6ae3SXiaoDong Huang 394010d6ae3SXiaoDong Huang if (cfg_info == core_pwr_pd) { 395010d6ae3SXiaoDong Huang /* disable apm cfg */ 396010d6ae3SXiaoDong Huang mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(cpu_id), 397010d6ae3SXiaoDong Huang WITH_16BITS_WMSK(CORES_PM_DISABLE)); 398010d6ae3SXiaoDong Huang if (pmu_power_domain_st(cpu_pd) == pmu_pd_on) { 399010d6ae3SXiaoDong Huang mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(cpu_id), 400010d6ae3SXiaoDong Huang WITH_16BITS_WMSK(CORES_PM_DISABLE)); 401010d6ae3SXiaoDong Huang pmu_power_domain_ctr(cpu_pd, pmu_pd_off); 402010d6ae3SXiaoDong Huang } 403010d6ae3SXiaoDong Huang pmu_power_domain_ctr(cpu_pd, pmu_pd_on); 404010d6ae3SXiaoDong Huang } else { 405010d6ae3SXiaoDong Huang /* wait cpu down */ 406010d6ae3SXiaoDong Huang while (pmu_power_domain_st(cpu_pd) == pmu_pd_on && loop < 100) { 407010d6ae3SXiaoDong Huang udelay(2); 408010d6ae3SXiaoDong Huang loop++; 409010d6ae3SXiaoDong Huang } 410010d6ae3SXiaoDong Huang 411010d6ae3SXiaoDong Huang /* return error if can't wait cpu down */ 412010d6ae3SXiaoDong Huang if (pmu_power_domain_st(cpu_pd) == pmu_pd_on) { 413010d6ae3SXiaoDong Huang WARN("%s:can't wait cpu down\n", __func__); 414010d6ae3SXiaoDong Huang return -EINVAL; 415010d6ae3SXiaoDong Huang } 416010d6ae3SXiaoDong Huang 417010d6ae3SXiaoDong Huang /* power up cpu in power down state */ 418010d6ae3SXiaoDong Huang apm_value = BIT(core_pm_sft_wakeup_en); 419010d6ae3SXiaoDong Huang mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(cpu_id), 420010d6ae3SXiaoDong Huang WITH_16BITS_WMSK(apm_value)); 421010d6ae3SXiaoDong Huang } 422010d6ae3SXiaoDong Huang 423010d6ae3SXiaoDong Huang return 0; 424010d6ae3SXiaoDong Huang } 425010d6ae3SXiaoDong Huang 426010d6ae3SXiaoDong Huang static int cpus_power_domain_off(uint32_t cpu_id, uint32_t pd_cfg) 427010d6ae3SXiaoDong Huang { 428010d6ae3SXiaoDong Huang uint32_t cpu_pd, apm_value; 429010d6ae3SXiaoDong Huang 430010d6ae3SXiaoDong Huang cpu_pd = PD_CPU0 + cpu_id; 431010d6ae3SXiaoDong Huang if (pmu_power_domain_st(cpu_pd) == pmu_pd_off) 432010d6ae3SXiaoDong Huang return 0; 433010d6ae3SXiaoDong Huang 434010d6ae3SXiaoDong Huang if (pd_cfg == core_pwr_pd) { 435010d6ae3SXiaoDong Huang if (check_cpu_wfie(cpu_id)) 436010d6ae3SXiaoDong Huang return -EINVAL; 437010d6ae3SXiaoDong Huang /* disable apm cfg */ 438010d6ae3SXiaoDong Huang mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(cpu_id), 439010d6ae3SXiaoDong Huang WITH_16BITS_WMSK(CORES_PM_DISABLE)); 440010d6ae3SXiaoDong Huang set_cpus_pwr_domain_cfg_info(cpu_id, pd_cfg); 441010d6ae3SXiaoDong Huang pmu_power_domain_ctr(cpu_pd, pmu_pd_off); 442010d6ae3SXiaoDong Huang } else { 443010d6ae3SXiaoDong Huang set_cpus_pwr_domain_cfg_info(cpu_id, pd_cfg); 444010d6ae3SXiaoDong Huang apm_value = BIT(core_pm_en) | BIT(core_pm_dis_int); 445010d6ae3SXiaoDong Huang if (pd_cfg == core_pwr_wfi_int) 446010d6ae3SXiaoDong Huang apm_value |= BIT(core_pm_int_wakeup_en); 447010d6ae3SXiaoDong Huang mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(cpu_id), 448010d6ae3SXiaoDong Huang WITH_16BITS_WMSK(apm_value)); 449010d6ae3SXiaoDong Huang } 450010d6ae3SXiaoDong Huang 451010d6ae3SXiaoDong Huang return 0; 452010d6ae3SXiaoDong Huang } 453010d6ae3SXiaoDong Huang 454010d6ae3SXiaoDong Huang static void nonboot_cpus_off(void) 455010d6ae3SXiaoDong Huang { 456010d6ae3SXiaoDong Huang uint32_t boot_cpu, cpu; 457010d6ae3SXiaoDong Huang 458010d6ae3SXiaoDong Huang boot_cpu = plat_my_core_pos(); 459010d6ae3SXiaoDong Huang 460010d6ae3SXiaoDong Huang for (cpu = 0; cpu < PLATFORM_CORE_COUNT; cpu++) { 461010d6ae3SXiaoDong Huang if (cpu == boot_cpu) 462010d6ae3SXiaoDong Huang continue; 463010d6ae3SXiaoDong Huang cpus_power_domain_off(cpu, core_pwr_pd); 464010d6ae3SXiaoDong Huang } 465010d6ae3SXiaoDong Huang } 466010d6ae3SXiaoDong Huang 467010d6ae3SXiaoDong Huang int rockchip_soc_cores_pwr_dm_on(unsigned long mpidr, 468010d6ae3SXiaoDong Huang uint64_t entrypoint) 469010d6ae3SXiaoDong Huang { 470010d6ae3SXiaoDong Huang uint32_t cpu_id = plat_core_pos_by_mpidr(mpidr); 471010d6ae3SXiaoDong Huang 472010d6ae3SXiaoDong Huang assert(cpu_id < PLATFORM_CORE_COUNT); 473010d6ae3SXiaoDong Huang assert(cpuson_flags[cpu_id] == 0); 474010d6ae3SXiaoDong Huang cpuson_flags[cpu_id] = PMU_CPU_HOTPLUG; 475010d6ae3SXiaoDong Huang cpuson_entry_point[cpu_id] = entrypoint; 476010d6ae3SXiaoDong Huang dsb(); 477010d6ae3SXiaoDong Huang 478010d6ae3SXiaoDong Huang cpus_power_domain_on(cpu_id); 479010d6ae3SXiaoDong Huang 480010d6ae3SXiaoDong Huang return PSCI_E_SUCCESS; 481010d6ae3SXiaoDong Huang } 482010d6ae3SXiaoDong Huang 483010d6ae3SXiaoDong Huang int rockchip_soc_cores_pwr_dm_on_finish(void) 484010d6ae3SXiaoDong Huang { 485010d6ae3SXiaoDong Huang uint32_t cpu_id = plat_my_core_pos(); 486010d6ae3SXiaoDong Huang 487010d6ae3SXiaoDong Huang mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(cpu_id), 488010d6ae3SXiaoDong Huang WITH_16BITS_WMSK(CORES_PM_DISABLE)); 489010d6ae3SXiaoDong Huang return PSCI_E_SUCCESS; 490010d6ae3SXiaoDong Huang } 491010d6ae3SXiaoDong Huang 492010d6ae3SXiaoDong Huang int rockchip_soc_cores_pwr_dm_off(void) 493010d6ae3SXiaoDong Huang { 494010d6ae3SXiaoDong Huang uint32_t cpu_id = plat_my_core_pos(); 495010d6ae3SXiaoDong Huang 496010d6ae3SXiaoDong Huang cpus_power_domain_off(cpu_id, core_pwr_wfi); 497010d6ae3SXiaoDong Huang 498010d6ae3SXiaoDong Huang return PSCI_E_SUCCESS; 499010d6ae3SXiaoDong Huang } 500010d6ae3SXiaoDong Huang 501010d6ae3SXiaoDong Huang int rockchip_soc_cores_pwr_dm_suspend(void) 502010d6ae3SXiaoDong Huang { 503010d6ae3SXiaoDong Huang uint32_t cpu_id = plat_my_core_pos(); 504010d6ae3SXiaoDong Huang 505010d6ae3SXiaoDong Huang assert(cpu_id < PLATFORM_CORE_COUNT); 506010d6ae3SXiaoDong Huang assert(cpuson_flags[cpu_id] == 0); 507010d6ae3SXiaoDong Huang cpuson_flags[cpu_id] = PMU_CPU_AUTO_PWRDN; 508010d6ae3SXiaoDong Huang cpuson_entry_point[cpu_id] = plat_get_sec_entrypoint(); 509010d6ae3SXiaoDong Huang dsb(); 510010d6ae3SXiaoDong Huang 511010d6ae3SXiaoDong Huang cpus_power_domain_off(cpu_id, core_pwr_wfi_int); 512010d6ae3SXiaoDong Huang 513010d6ae3SXiaoDong Huang return PSCI_E_SUCCESS; 514010d6ae3SXiaoDong Huang } 515010d6ae3SXiaoDong Huang 516010d6ae3SXiaoDong Huang int rockchip_soc_cores_pwr_dm_resume(void) 517010d6ae3SXiaoDong Huang { 518010d6ae3SXiaoDong Huang uint32_t cpu_id = plat_my_core_pos(); 519010d6ae3SXiaoDong Huang 520010d6ae3SXiaoDong Huang /* Disable core_pm */ 521010d6ae3SXiaoDong Huang mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(cpu_id), 522010d6ae3SXiaoDong Huang WITH_16BITS_WMSK(CORES_PM_DISABLE)); 523010d6ae3SXiaoDong Huang 524010d6ae3SXiaoDong Huang return PSCI_E_SUCCESS; 525010d6ae3SXiaoDong Huang } 526010d6ae3SXiaoDong Huang 527010d6ae3SXiaoDong Huang #define CLK_MSK_GATING(msk, con) \ 528010d6ae3SXiaoDong Huang mmio_write_32(CRU_BASE + (con), ((msk) << 16) | 0xffff) 529010d6ae3SXiaoDong Huang #define CLK_MSK_UNGATING(msk, con) \ 530010d6ae3SXiaoDong Huang mmio_write_32(CRU_BASE + (con), ((~(msk)) << 16) | 0xffff) 531010d6ae3SXiaoDong Huang 532010d6ae3SXiaoDong Huang static uint32_t clk_ungt_msk[CRU_CLKGATES_CON_CNT] = { 533010d6ae3SXiaoDong Huang 0xe0ff, 0xffff, 0x0000, 0x0000, 534010d6ae3SXiaoDong Huang 0x0000, 0x0380, 0x0000, 0x0000, 535010d6ae3SXiaoDong Huang 0x07c0, 0x0000, 0x0000, 0x000f, 536010d6ae3SXiaoDong Huang 0x0061, 0x1f02, 0x0440, 0x1801, 537010d6ae3SXiaoDong Huang 0x004b, 0x0000 538010d6ae3SXiaoDong Huang }; 539010d6ae3SXiaoDong Huang 540010d6ae3SXiaoDong Huang static uint32_t clk_pmu_ungt_msk[CRU_PMU_CLKGATE_CON_CNT] = { 541010d6ae3SXiaoDong Huang 0xf1ff, 0x0310 542010d6ae3SXiaoDong Huang }; 543010d6ae3SXiaoDong Huang 544010d6ae3SXiaoDong Huang void clk_gate_suspend(void) 545010d6ae3SXiaoDong Huang { 546010d6ae3SXiaoDong Huang int i; 547010d6ae3SXiaoDong Huang 548010d6ae3SXiaoDong Huang for (i = 0; i < CRU_CLKGATES_CON_CNT; i++) { 549010d6ae3SXiaoDong Huang ddr_data.cru_clk_gate[i] = 550010d6ae3SXiaoDong Huang mmio_read_32(CRU_BASE + CRU_CLKGATES_CON(i)); 551010d6ae3SXiaoDong Huang mmio_write_32(CRU_BASE + CRU_CLKGATES_CON(i), 552010d6ae3SXiaoDong Huang WITH_16BITS_WMSK(~clk_ungt_msk[i])); 553010d6ae3SXiaoDong Huang } 554010d6ae3SXiaoDong Huang 555010d6ae3SXiaoDong Huang for (i = 0; i < CRU_PMU_CLKGATE_CON_CNT; i++) { 556010d6ae3SXiaoDong Huang ddr_data.cru_pmu_clk_gate[i] = 557010d6ae3SXiaoDong Huang mmio_read_32(PMUCRU_BASE + CRU_PMU_CLKGATES_CON(i)); 558010d6ae3SXiaoDong Huang mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKGATES_CON(i), 559010d6ae3SXiaoDong Huang WITH_16BITS_WMSK(~clk_pmu_ungt_msk[i])); 560010d6ae3SXiaoDong Huang } 561010d6ae3SXiaoDong Huang } 562010d6ae3SXiaoDong Huang 563010d6ae3SXiaoDong Huang void clk_gate_resume(void) 564010d6ae3SXiaoDong Huang { 565010d6ae3SXiaoDong Huang int i; 566010d6ae3SXiaoDong Huang 567010d6ae3SXiaoDong Huang for (i = 0; i < CRU_PMU_CLKGATE_CON_CNT; i++) 568010d6ae3SXiaoDong Huang mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKGATES_CON(i), 569010d6ae3SXiaoDong Huang WITH_16BITS_WMSK(ddr_data.cru_pmu_clk_gate[i])); 570010d6ae3SXiaoDong Huang 571010d6ae3SXiaoDong Huang for (i = 0; i < CRU_CLKGATES_CON_CNT; i++) 572010d6ae3SXiaoDong Huang mmio_write_32(CRU_BASE + CRU_CLKGATES_CON(i), 573010d6ae3SXiaoDong Huang WITH_16BITS_WMSK(ddr_data.cru_clk_gate[i])); 574010d6ae3SXiaoDong Huang } 575010d6ae3SXiaoDong Huang 576010d6ae3SXiaoDong Huang static void pvtm_32k_config(void) 577010d6ae3SXiaoDong Huang { 578010d6ae3SXiaoDong Huang uint32_t pvtm_freq_khz, pvtm_div; 579010d6ae3SXiaoDong Huang 580010d6ae3SXiaoDong Huang ddr_data.pmu_cru_clksel_con0 = 581010d6ae3SXiaoDong Huang mmio_read_32(PMUCRU_BASE + CRU_PMU_CLKSELS_CON(0)); 582010d6ae3SXiaoDong Huang 583010d6ae3SXiaoDong Huang ddr_data.pgrf_pvtm_con[0] = 584010d6ae3SXiaoDong Huang mmio_read_32(PMUGRF_BASE + PMUGRF_PVTM_CON0); 585010d6ae3SXiaoDong Huang ddr_data.pgrf_pvtm_con[1] = 586010d6ae3SXiaoDong Huang mmio_read_32(PMUGRF_BASE + PMUGRF_PVTM_CON1); 587010d6ae3SXiaoDong Huang 588010d6ae3SXiaoDong Huang mmio_write_32(PMUGRF_BASE + PMUGRF_PVTM_CON0, 589010d6ae3SXiaoDong Huang BITS_WITH_WMASK(0, 0x3, pgrf_pvtm_st)); 590010d6ae3SXiaoDong Huang dsb(); 591010d6ae3SXiaoDong Huang mmio_write_32(PMUGRF_BASE + PMUGRF_PVTM_CON0, 592010d6ae3SXiaoDong Huang BITS_WITH_WMASK(1, 0x1, pgrf_pvtm_en)); 593010d6ae3SXiaoDong Huang dsb(); 594010d6ae3SXiaoDong Huang mmio_write_32(PMUGRF_BASE + PMUGRF_PVTM_CON1, PVTM_CALC_CNT); 595010d6ae3SXiaoDong Huang dsb(); 596010d6ae3SXiaoDong Huang 597010d6ae3SXiaoDong Huang mmio_write_32(PMUGRF_BASE + PMUGRF_PVTM_CON0, 598010d6ae3SXiaoDong Huang BITS_WITH_WMASK(1, 0x1, pgrf_pvtm_st)); 599010d6ae3SXiaoDong Huang 600010d6ae3SXiaoDong Huang /* pmugrf_pvtm_st0 will be clear after PVTM start, 601010d6ae3SXiaoDong Huang * which will cost about 6 cycles of pvtm at least. 602010d6ae3SXiaoDong Huang * So we wait 30 cycles of pvtm for security. 603010d6ae3SXiaoDong Huang */ 604010d6ae3SXiaoDong Huang while (mmio_read_32(PMUGRF_BASE + PMUGRF_PVTM_ST1) < 30) 605010d6ae3SXiaoDong Huang ; 606010d6ae3SXiaoDong Huang 607010d6ae3SXiaoDong Huang dsb(); 608010d6ae3SXiaoDong Huang while (!(mmio_read_32(PMUGRF_BASE + PMUGRF_PVTM_ST0) & 0x1)) 609010d6ae3SXiaoDong Huang ; 610010d6ae3SXiaoDong Huang 611010d6ae3SXiaoDong Huang pvtm_freq_khz = 612010d6ae3SXiaoDong Huang (mmio_read_32(PMUGRF_BASE + PMUGRF_PVTM_ST1) * 24000 + 613010d6ae3SXiaoDong Huang PVTM_CALC_CNT / 2) / PVTM_CALC_CNT; 614010d6ae3SXiaoDong Huang pvtm_div = (pvtm_freq_khz + 16) / 32; 615010d6ae3SXiaoDong Huang 616010d6ae3SXiaoDong Huang /* pvtm_div = div_factor << 2 + 1, 617010d6ae3SXiaoDong Huang * so div_factor = (pvtm_div - 1) >> 2. 618010d6ae3SXiaoDong Huang * But the operation ">> 2" will clear the low bit of pvtm_div, 619010d6ae3SXiaoDong Huang * so we don't have to do "- 1" for compasation 620010d6ae3SXiaoDong Huang */ 621010d6ae3SXiaoDong Huang pvtm_div = pvtm_div >> 2; 622010d6ae3SXiaoDong Huang if (pvtm_div > 0x3f) 623010d6ae3SXiaoDong Huang pvtm_div = 0x3f; 624010d6ae3SXiaoDong Huang 625010d6ae3SXiaoDong Huang mmio_write_32(PMUGRF_BASE + PMUGRF_PVTM_CON0, 626010d6ae3SXiaoDong Huang BITS_WITH_WMASK(pvtm_div, 0x3f, pgrf_pvtm_div)); 627010d6ae3SXiaoDong Huang 628010d6ae3SXiaoDong Huang /* select pvtm as 32k source */ 629010d6ae3SXiaoDong Huang mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKSELS_CON(0), 6308a079e88SAmbroise Vincent BITS_WITH_WMASK(1, 0x3U, 14)); 631010d6ae3SXiaoDong Huang } 632010d6ae3SXiaoDong Huang 633010d6ae3SXiaoDong Huang static void pvtm_32k_config_restore(void) 634010d6ae3SXiaoDong Huang { 635010d6ae3SXiaoDong Huang mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKSELS_CON(0), 6368a079e88SAmbroise Vincent ddr_data.pmu_cru_clksel_con0 | BITS_WMSK(0x3U, 14)); 637010d6ae3SXiaoDong Huang 638010d6ae3SXiaoDong Huang mmio_write_32(PMUGRF_BASE + PMUGRF_PVTM_CON0, 639010d6ae3SXiaoDong Huang WITH_16BITS_WMSK(ddr_data.pgrf_pvtm_con[0])); 640010d6ae3SXiaoDong Huang mmio_write_32(PMUGRF_BASE + PMUGRF_PVTM_CON1, 641010d6ae3SXiaoDong Huang ddr_data.pgrf_pvtm_con[1]); 642010d6ae3SXiaoDong Huang } 643010d6ae3SXiaoDong Huang 644010d6ae3SXiaoDong Huang static void ddr_sleep_config(void) 645010d6ae3SXiaoDong Huang { 646010d6ae3SXiaoDong Huang /* disable ddr pd, sr */ 647010d6ae3SXiaoDong Huang ddr_data.ddrc_pwrctrl = mmio_read_32(DDR_UPCTL_BASE + 0x30); 648010d6ae3SXiaoDong Huang mmio_write_32(DDR_UPCTL_BASE + 0x30, BITS_WITH_WMASK(0x0, 0x3, 0)); 649010d6ae3SXiaoDong Huang 650010d6ae3SXiaoDong Huang /* disable ddr auto gt */ 651010d6ae3SXiaoDong Huang ddr_data.ddrgrf_con1 = mmio_read_32(DDRGRF_BASE + 0x4); 652010d6ae3SXiaoDong Huang mmio_write_32(DDRGRF_BASE + 0x4, BITS_WITH_WMASK(0x0, 0x1f, 0)); 653010d6ae3SXiaoDong Huang 654010d6ae3SXiaoDong Huang /* disable ddr standby */ 655010d6ae3SXiaoDong Huang ddr_data.ddrstdby_con0 = mmio_read_32(DDR_STDBY_BASE + 0x0); 656010d6ae3SXiaoDong Huang mmio_write_32(DDR_STDBY_BASE + 0x0, BITS_WITH_WMASK(0x0, 0x1, 0)); 657010d6ae3SXiaoDong Huang while ((mmio_read_32(DDR_UPCTL_BASE + 0x4) & 0x7) != 1) 658010d6ae3SXiaoDong Huang ; 659010d6ae3SXiaoDong Huang 660010d6ae3SXiaoDong Huang /* ddr pmu ctrl */ 661010d6ae3SXiaoDong Huang ddr_data.ddrgrf_con0 = mmio_read_32(DDRGRF_BASE + 0x0); 662010d6ae3SXiaoDong Huang mmio_write_32(DDRGRF_BASE + 0x0, BITS_WITH_WMASK(0x0, 0x1, 5)); 663010d6ae3SXiaoDong Huang dsb(); 664010d6ae3SXiaoDong Huang mmio_write_32(DDRGRF_BASE + 0x0, BITS_WITH_WMASK(0x1, 0x1, 4)); 665010d6ae3SXiaoDong Huang 666010d6ae3SXiaoDong Huang /* ddr ret sel */ 667010d6ae3SXiaoDong Huang ddr_data.pmugrf_soc_con0 = 668010d6ae3SXiaoDong Huang mmio_read_32(PMUGRF_BASE + PMUGRF_SOC_CON(0)); 669010d6ae3SXiaoDong Huang mmio_write_32(PMUGRF_BASE + PMUGRF_SOC_CON(0), 670010d6ae3SXiaoDong Huang BITS_WITH_WMASK(0x0, 0x1, 12)); 671010d6ae3SXiaoDong Huang } 672010d6ae3SXiaoDong Huang 673010d6ae3SXiaoDong Huang static void ddr_sleep_config_restore(void) 674010d6ae3SXiaoDong Huang { 675010d6ae3SXiaoDong Huang /* restore ddr ret sel */ 676010d6ae3SXiaoDong Huang mmio_write_32(PMUGRF_BASE + PMUGRF_SOC_CON(0), 677010d6ae3SXiaoDong Huang ddr_data.pmugrf_soc_con0 | BITS_WMSK(0x1, 12)); 678010d6ae3SXiaoDong Huang 679010d6ae3SXiaoDong Huang /* restore ddr pmu ctrl */ 680010d6ae3SXiaoDong Huang mmio_write_32(DDRGRF_BASE + 0x0, 681010d6ae3SXiaoDong Huang ddr_data.ddrgrf_con0 | BITS_WMSK(0x1, 4)); 682010d6ae3SXiaoDong Huang dsb(); 683010d6ae3SXiaoDong Huang mmio_write_32(DDRGRF_BASE + 0x0, 684010d6ae3SXiaoDong Huang ddr_data.ddrgrf_con0 | BITS_WMSK(0x1, 5)); 685010d6ae3SXiaoDong Huang 686010d6ae3SXiaoDong Huang /* restore ddr standby */ 687010d6ae3SXiaoDong Huang mmio_write_32(DDR_STDBY_BASE + 0x0, 688010d6ae3SXiaoDong Huang ddr_data.ddrstdby_con0 | BITS_WMSK(0x1, 0)); 689010d6ae3SXiaoDong Huang 690010d6ae3SXiaoDong Huang /* restore ddr auto gt */ 691010d6ae3SXiaoDong Huang mmio_write_32(DDRGRF_BASE + 0x4, 692010d6ae3SXiaoDong Huang ddr_data.ddrgrf_con1 | BITS_WMSK(0x1f, 0)); 693010d6ae3SXiaoDong Huang 694010d6ae3SXiaoDong Huang /* restore ddr pd, sr */ 695010d6ae3SXiaoDong Huang mmio_write_32(DDR_UPCTL_BASE + 0x30, 696010d6ae3SXiaoDong Huang ddr_data.ddrc_pwrctrl | BITS_WMSK(0x3, 0)); 697010d6ae3SXiaoDong Huang } 698010d6ae3SXiaoDong Huang 699010d6ae3SXiaoDong Huang static void pmu_sleep_config(void) 700010d6ae3SXiaoDong Huang { 701010d6ae3SXiaoDong Huang uint32_t pwrmd_core_lo, pwrmd_core_hi, pwrmd_com_lo, pwrmd_com_hi; 702010d6ae3SXiaoDong Huang uint32_t pmu_wkup_cfg2_lo; 703010d6ae3SXiaoDong Huang uint32_t clk_freq_khz; 704010d6ae3SXiaoDong Huang 705010d6ae3SXiaoDong Huang /* save pmic_sleep iomux gpio0_a4 */ 706010d6ae3SXiaoDong Huang ddr_data.pmic_slp_iomux = mmio_read_32(PMUGRF_BASE + GPIO0A_IOMUX); 707010d6ae3SXiaoDong Huang 708010d6ae3SXiaoDong Huang ddr_data.pmu_pwrmd_core_l = 709010d6ae3SXiaoDong Huang mmio_read_32(PMU_BASE + PMU_PWRMODE_CORE_LO); 710010d6ae3SXiaoDong Huang ddr_data.pmu_pwrmd_core_h = 711010d6ae3SXiaoDong Huang mmio_read_32(PMU_BASE + PMU_PWRMODE_CORE_HI); 712010d6ae3SXiaoDong Huang ddr_data.pmu_pwrmd_cmm_l = 713010d6ae3SXiaoDong Huang mmio_read_32(PMU_BASE + PMU_PWRMODE_COMMON_CON_LO); 714010d6ae3SXiaoDong Huang ddr_data.pmu_pwrmd_cmm_h = 715010d6ae3SXiaoDong Huang mmio_read_32(PMU_BASE + PMU_PWRMODE_COMMON_CON_HI); 716010d6ae3SXiaoDong Huang ddr_data.pmu_wkup_cfg2_l = mmio_read_32(PMU_BASE + PMU_WKUP_CFG2_LO); 717010d6ae3SXiaoDong Huang 718010d6ae3SXiaoDong Huang pwrmd_core_lo = BIT(pmu_global_int_dis) | 719010d6ae3SXiaoDong Huang BIT(pmu_core_src_gt) | 720010d6ae3SXiaoDong Huang BIT(pmu_cpu0_pd) | 721010d6ae3SXiaoDong Huang BIT(pmu_clr_core) | 722010d6ae3SXiaoDong Huang BIT(pmu_scu_pd) | 723010d6ae3SXiaoDong Huang BIT(pmu_l2_idle) | 724010d6ae3SXiaoDong Huang BIT(pmu_l2_flush) | 725010d6ae3SXiaoDong Huang BIT(pmu_clr_bus2main) | 726010d6ae3SXiaoDong Huang BIT(pmu_clr_peri2msch); 727010d6ae3SXiaoDong Huang 728010d6ae3SXiaoDong Huang pwrmd_core_hi = BIT(pmu_dpll_pd_en) | 729010d6ae3SXiaoDong Huang BIT(pmu_apll_pd_en) | 730010d6ae3SXiaoDong Huang BIT(pmu_cpll_pd_en) | 731010d6ae3SXiaoDong Huang BIT(pmu_gpll_pd_en) | 732010d6ae3SXiaoDong Huang BIT(pmu_npll_pd_en); 733010d6ae3SXiaoDong Huang 734010d6ae3SXiaoDong Huang pwrmd_com_lo = BIT(pmu_mode_en) | 735010d6ae3SXiaoDong Huang BIT(pmu_pll_pd) | 736010d6ae3SXiaoDong Huang BIT(pmu_pmu_use_if) | 737010d6ae3SXiaoDong Huang BIT(pmu_alive_use_if) | 738010d6ae3SXiaoDong Huang BIT(pmu_osc_dis) | 739010d6ae3SXiaoDong Huang BIT(pmu_sref_enter) | 740010d6ae3SXiaoDong Huang BIT(pmu_ddrc_gt) | 741010d6ae3SXiaoDong Huang BIT(pmu_clr_pmu) | 742010d6ae3SXiaoDong Huang BIT(pmu_clr_peri_pmu); 743010d6ae3SXiaoDong Huang 744010d6ae3SXiaoDong Huang pwrmd_com_hi = BIT(pmu_clr_bus) | 745010d6ae3SXiaoDong Huang BIT(pmu_clr_msch) | 746010d6ae3SXiaoDong Huang BIT(pmu_wakeup_begin_cfg); 747010d6ae3SXiaoDong Huang 748010d6ae3SXiaoDong Huang pmu_wkup_cfg2_lo = BIT(pmu_cluster_wkup_en) | 749010d6ae3SXiaoDong Huang BIT(pmu_gpio_wkup_en) | 750010d6ae3SXiaoDong Huang BIT(pmu_timer_wkup_en); 751010d6ae3SXiaoDong Huang 752010d6ae3SXiaoDong Huang /* set pmic_sleep iomux gpio0_a4 */ 753010d6ae3SXiaoDong Huang mmio_write_32(PMUGRF_BASE + GPIO0A_IOMUX, 754010d6ae3SXiaoDong Huang BITS_WITH_WMASK(1, 0x3, 8)); 755010d6ae3SXiaoDong Huang 756010d6ae3SXiaoDong Huang clk_freq_khz = 32; 757010d6ae3SXiaoDong Huang 758010d6ae3SXiaoDong Huang mmio_write_32(PMU_BASE + PMU_OSC_CNT_LO, 759010d6ae3SXiaoDong Huang WITH_16BITS_WMSK(clk_freq_khz * 32 & 0xffff)); 760010d6ae3SXiaoDong Huang mmio_write_32(PMU_BASE + PMU_OSC_CNT_HI, 761010d6ae3SXiaoDong Huang WITH_16BITS_WMSK(clk_freq_khz * 32 >> 16)); 762010d6ae3SXiaoDong Huang 763010d6ae3SXiaoDong Huang mmio_write_32(PMU_BASE + PMU_STABLE_CNT_LO, 764010d6ae3SXiaoDong Huang WITH_16BITS_WMSK(clk_freq_khz * 32 & 0xffff)); 765010d6ae3SXiaoDong Huang mmio_write_32(PMU_BASE + PMU_STABLE_CNT_HI, 766010d6ae3SXiaoDong Huang WITH_16BITS_WMSK(clk_freq_khz * 32 >> 16)); 767010d6ae3SXiaoDong Huang 768010d6ae3SXiaoDong Huang mmio_write_32(PMU_BASE + PMU_WAKEUP_RST_CLR_LO, 769010d6ae3SXiaoDong Huang WITH_16BITS_WMSK(clk_freq_khz * 2 & 0xffff)); 770010d6ae3SXiaoDong Huang mmio_write_32(PMU_BASE + PMU_WAKEUP_RST_CLR_HI, 771010d6ae3SXiaoDong Huang WITH_16BITS_WMSK(clk_freq_khz * 2 >> 16)); 772010d6ae3SXiaoDong Huang 773010d6ae3SXiaoDong Huang /* Pmu's clk has switched to 24M back When pmu FSM counts 774010d6ae3SXiaoDong Huang * the follow counters, so we should use 24M to calculate 775010d6ae3SXiaoDong Huang * these counters. 776010d6ae3SXiaoDong Huang */ 777010d6ae3SXiaoDong Huang mmio_write_32(PMU_BASE + PMU_SCU_PWRDN_CNT_LO, 778010d6ae3SXiaoDong Huang WITH_16BITS_WMSK(24000 * 2 & 0xffff)); 779010d6ae3SXiaoDong Huang mmio_write_32(PMU_BASE + PMU_SCU_PWRDN_CNT_HI, 780010d6ae3SXiaoDong Huang WITH_16BITS_WMSK(24000 * 2 >> 16)); 781010d6ae3SXiaoDong Huang 782010d6ae3SXiaoDong Huang mmio_write_32(PMU_BASE + PMU_SCU_PWRUP_CNT_LO, 783010d6ae3SXiaoDong Huang WITH_16BITS_WMSK(24000 * 2 & 0xffff)); 784010d6ae3SXiaoDong Huang mmio_write_32(PMU_BASE + PMU_SCU_PWRUP_CNT_HI, 785010d6ae3SXiaoDong Huang WITH_16BITS_WMSK(24000 * 2 >> 16)); 786010d6ae3SXiaoDong Huang 787010d6ae3SXiaoDong Huang mmio_write_32(PMU_BASE + PMU_PLLLOCK_CNT_LO, 788010d6ae3SXiaoDong Huang WITH_16BITS_WMSK(24000 * 5 & 0xffff)); 789010d6ae3SXiaoDong Huang mmio_write_32(PMU_BASE + PMU_PLLLOCK_CNT_HI, 790010d6ae3SXiaoDong Huang WITH_16BITS_WMSK(24000 * 5 >> 16)); 791010d6ae3SXiaoDong Huang 792010d6ae3SXiaoDong Huang mmio_write_32(PMU_BASE + PMU_PLLRST_CNT_LO, 793010d6ae3SXiaoDong Huang WITH_16BITS_WMSK(24000 * 2 & 0xffff)); 794010d6ae3SXiaoDong Huang mmio_write_32(PMU_BASE + PMU_PLLRST_CNT_HI, 795010d6ae3SXiaoDong Huang WITH_16BITS_WMSK(24000 * 2 >> 16)); 796010d6ae3SXiaoDong Huang 797010d6ae3SXiaoDong Huang /* Config pmu power mode and pmu wakeup source */ 798010d6ae3SXiaoDong Huang mmio_write_32(PMU_BASE + PMU_PWRMODE_CORE_LO, 799010d6ae3SXiaoDong Huang WITH_16BITS_WMSK(pwrmd_core_lo)); 800010d6ae3SXiaoDong Huang mmio_write_32(PMU_BASE + PMU_PWRMODE_CORE_HI, 801010d6ae3SXiaoDong Huang WITH_16BITS_WMSK(pwrmd_core_hi)); 802010d6ae3SXiaoDong Huang 803010d6ae3SXiaoDong Huang mmio_write_32(PMU_BASE + PMU_PWRMODE_COMMON_CON_LO, 804010d6ae3SXiaoDong Huang WITH_16BITS_WMSK(pwrmd_com_lo)); 805010d6ae3SXiaoDong Huang mmio_write_32(PMU_BASE + PMU_PWRMODE_COMMON_CON_HI, 806010d6ae3SXiaoDong Huang WITH_16BITS_WMSK(pwrmd_com_hi)); 807010d6ae3SXiaoDong Huang 808010d6ae3SXiaoDong Huang mmio_write_32(PMU_BASE + PMU_WKUP_CFG2_LO, 809010d6ae3SXiaoDong Huang WITH_16BITS_WMSK(pmu_wkup_cfg2_lo)); 810010d6ae3SXiaoDong Huang } 811010d6ae3SXiaoDong Huang 812010d6ae3SXiaoDong Huang static void pmu_sleep_restore(void) 813010d6ae3SXiaoDong Huang { 814010d6ae3SXiaoDong Huang mmio_write_32(PMU_BASE + PMU_PWRMODE_CORE_LO, 815010d6ae3SXiaoDong Huang WITH_16BITS_WMSK(ddr_data.pmu_pwrmd_core_l)); 816010d6ae3SXiaoDong Huang mmio_write_32(PMU_BASE + PMU_PWRMODE_CORE_HI, 817010d6ae3SXiaoDong Huang WITH_16BITS_WMSK(ddr_data.pmu_pwrmd_core_h)); 818010d6ae3SXiaoDong Huang mmio_write_32(PMU_BASE + PMU_PWRMODE_COMMON_CON_LO, 819010d6ae3SXiaoDong Huang WITH_16BITS_WMSK(ddr_data.pmu_pwrmd_cmm_l)); 820010d6ae3SXiaoDong Huang mmio_write_32(PMU_BASE + PMU_PWRMODE_COMMON_CON_HI, 821010d6ae3SXiaoDong Huang WITH_16BITS_WMSK(ddr_data.pmu_pwrmd_cmm_h)); 822010d6ae3SXiaoDong Huang mmio_write_32(PMU_BASE + PMU_WKUP_CFG2_LO, 823010d6ae3SXiaoDong Huang WITH_16BITS_WMSK(ddr_data.pmu_wkup_cfg2_l)); 824010d6ae3SXiaoDong Huang 825010d6ae3SXiaoDong Huang /* restore pmic_sleep iomux */ 826010d6ae3SXiaoDong Huang mmio_write_32(PMUGRF_BASE + GPIO0A_IOMUX, 827010d6ae3SXiaoDong Huang WITH_16BITS_WMSK(ddr_data.pmic_slp_iomux)); 828010d6ae3SXiaoDong Huang } 829010d6ae3SXiaoDong Huang 830010d6ae3SXiaoDong Huang static void soc_sleep_config(void) 831010d6ae3SXiaoDong Huang { 832010d6ae3SXiaoDong Huang ddr_data.gpio0c_iomux = mmio_read_32(PMUGRF_BASE + GPIO0C_IOMUX); 833010d6ae3SXiaoDong Huang 834010d6ae3SXiaoDong Huang pmu_sleep_config(); 835010d6ae3SXiaoDong Huang 836010d6ae3SXiaoDong Huang ddr_sleep_config(); 837010d6ae3SXiaoDong Huang 838010d6ae3SXiaoDong Huang pvtm_32k_config(); 839010d6ae3SXiaoDong Huang } 840010d6ae3SXiaoDong Huang 841010d6ae3SXiaoDong Huang static void soc_sleep_restore(void) 842010d6ae3SXiaoDong Huang { 843010d6ae3SXiaoDong Huang secure_timer_init(); 844010d6ae3SXiaoDong Huang 845010d6ae3SXiaoDong Huang pvtm_32k_config_restore(); 846010d6ae3SXiaoDong Huang 847010d6ae3SXiaoDong Huang ddr_sleep_config_restore(); 848010d6ae3SXiaoDong Huang 849010d6ae3SXiaoDong Huang pmu_sleep_restore(); 850010d6ae3SXiaoDong Huang 851010d6ae3SXiaoDong Huang mmio_write_32(PMUGRF_BASE + GPIO0C_IOMUX, 852010d6ae3SXiaoDong Huang WITH_16BITS_WMSK(ddr_data.gpio0c_iomux)); 853010d6ae3SXiaoDong Huang } 854010d6ae3SXiaoDong Huang 855010d6ae3SXiaoDong Huang static inline void pm_pll_wait_lock(uint32_t pll_base, uint32_t pll_id) 856010d6ae3SXiaoDong Huang { 857010d6ae3SXiaoDong Huang uint32_t delay = PLL_LOCKED_TIMEOUT; 858010d6ae3SXiaoDong Huang 859010d6ae3SXiaoDong Huang while (delay > 0) { 860010d6ae3SXiaoDong Huang if (mmio_read_32(pll_base + PLL_CON(1)) & 861010d6ae3SXiaoDong Huang PLL_LOCK_MSK) 862010d6ae3SXiaoDong Huang break; 863010d6ae3SXiaoDong Huang delay--; 864010d6ae3SXiaoDong Huang } 865010d6ae3SXiaoDong Huang 866010d6ae3SXiaoDong Huang if (delay == 0) 867010d6ae3SXiaoDong Huang ERROR("Can't wait pll:%d lock\n", pll_id); 868010d6ae3SXiaoDong Huang } 869010d6ae3SXiaoDong Huang 870010d6ae3SXiaoDong Huang static inline void pll_pwr_ctr(uint32_t pll_base, uint32_t pll_id, uint32_t pd) 871010d6ae3SXiaoDong Huang { 872010d6ae3SXiaoDong Huang mmio_write_32(pll_base + PLL_CON(1), 8738a079e88SAmbroise Vincent BITS_WITH_WMASK(1, 1U, 15)); 874010d6ae3SXiaoDong Huang if (pd) 875010d6ae3SXiaoDong Huang mmio_write_32(pll_base + PLL_CON(1), 876010d6ae3SXiaoDong Huang BITS_WITH_WMASK(1, 1, 14)); 877010d6ae3SXiaoDong Huang else 878010d6ae3SXiaoDong Huang mmio_write_32(pll_base + PLL_CON(1), 879010d6ae3SXiaoDong Huang BITS_WITH_WMASK(0, 1, 14)); 880010d6ae3SXiaoDong Huang } 881010d6ae3SXiaoDong Huang 882010d6ae3SXiaoDong Huang static inline void pll_set_mode(uint32_t pll_id, uint32_t mode) 883010d6ae3SXiaoDong Huang { 884010d6ae3SXiaoDong Huang uint32_t val = BITS_WITH_WMASK(mode, 0x3, PLL_MODE_SHIFT(pll_id)); 885010d6ae3SXiaoDong Huang 886010d6ae3SXiaoDong Huang if (pll_id != GPLL_ID) 887010d6ae3SXiaoDong Huang mmio_write_32(CRU_BASE + CRU_MODE, val); 888010d6ae3SXiaoDong Huang else 889010d6ae3SXiaoDong Huang mmio_write_32(PMUCRU_BASE + CRU_PMU_MODE, 890010d6ae3SXiaoDong Huang BITS_WITH_WMASK(mode, 0x3, 0)); 891010d6ae3SXiaoDong Huang } 892010d6ae3SXiaoDong Huang 893010d6ae3SXiaoDong Huang static inline void pll_suspend(uint32_t pll_id) 894010d6ae3SXiaoDong Huang { 895010d6ae3SXiaoDong Huang int i; 896010d6ae3SXiaoDong Huang uint32_t pll_base; 897010d6ae3SXiaoDong Huang 898010d6ae3SXiaoDong Huang if (pll_id != GPLL_ID) 899010d6ae3SXiaoDong Huang pll_base = CRU_BASE + CRU_PLL_CONS(pll_id, 0); 900010d6ae3SXiaoDong Huang else 901010d6ae3SXiaoDong Huang pll_base = PMUCRU_BASE + CRU_PLL_CONS(0, 0); 902010d6ae3SXiaoDong Huang 903010d6ae3SXiaoDong Huang /* save pll con */ 904010d6ae3SXiaoDong Huang for (i = 0; i < PLL_CON_CNT; i++) 905010d6ae3SXiaoDong Huang ddr_data.cru_plls_con_save[pll_id][i] = 906010d6ae3SXiaoDong Huang mmio_read_32(pll_base + PLL_CON(i)); 907010d6ae3SXiaoDong Huang 908010d6ae3SXiaoDong Huang /* slow mode */ 909010d6ae3SXiaoDong Huang pll_set_mode(pll_id, SLOW_MODE); 910010d6ae3SXiaoDong Huang } 911010d6ae3SXiaoDong Huang 912010d6ae3SXiaoDong Huang static inline void pll_resume(uint32_t pll_id) 913010d6ae3SXiaoDong Huang { 914010d6ae3SXiaoDong Huang uint32_t mode, pll_base; 915010d6ae3SXiaoDong Huang 916010d6ae3SXiaoDong Huang if (pll_id != GPLL_ID) { 917010d6ae3SXiaoDong Huang pll_base = CRU_BASE + CRU_PLL_CONS(pll_id, 0); 918010d6ae3SXiaoDong Huang mode = (ddr_data.cru_mode_save >> PLL_MODE_SHIFT(pll_id)) & 0x3; 919010d6ae3SXiaoDong Huang } else { 920010d6ae3SXiaoDong Huang pll_base = PMUCRU_BASE + CRU_PLL_CONS(0, 0); 921010d6ae3SXiaoDong Huang mode = ddr_data.cru_pmu_mode_save & 0x3; 922010d6ae3SXiaoDong Huang } 923010d6ae3SXiaoDong Huang 924010d6ae3SXiaoDong Huang /* if pll locked before suspend, we should wait atfer resume */ 925010d6ae3SXiaoDong Huang if (ddr_data.cru_plls_con_save[pll_id][1] & PLL_LOCK_MSK) 926010d6ae3SXiaoDong Huang pm_pll_wait_lock(pll_base, pll_id); 927010d6ae3SXiaoDong Huang 928010d6ae3SXiaoDong Huang pll_set_mode(pll_id, mode); 929010d6ae3SXiaoDong Huang } 930010d6ae3SXiaoDong Huang 931010d6ae3SXiaoDong Huang static void pm_plls_suspend(void) 932010d6ae3SXiaoDong Huang { 933010d6ae3SXiaoDong Huang ddr_data.cru_mode_save = mmio_read_32(CRU_BASE + CRU_MODE); 934010d6ae3SXiaoDong Huang ddr_data.cru_pmu_mode_save = mmio_read_32(PMUCRU_BASE + CRU_PMU_MODE); 935010d6ae3SXiaoDong Huang ddr_data.clk_sel0 = mmio_read_32(CRU_BASE + CRU_CLKSELS_CON(0)); 936010d6ae3SXiaoDong Huang 937010d6ae3SXiaoDong Huang pll_suspend(GPLL_ID); 938010d6ae3SXiaoDong Huang pll_suspend(NPLL_ID); 939010d6ae3SXiaoDong Huang pll_suspend(CPLL_ID); 940010d6ae3SXiaoDong Huang pll_suspend(APLL_ID); 941010d6ae3SXiaoDong Huang 942010d6ae3SXiaoDong Huang /* core */ 943010d6ae3SXiaoDong Huang mmio_write_32(CRU_BASE + CRU_CLKSELS_CON(0), 944010d6ae3SXiaoDong Huang BITS_WITH_WMASK(0, 0xf, 0)); 945010d6ae3SXiaoDong Huang 946010d6ae3SXiaoDong Huang /* pclk_dbg */ 947010d6ae3SXiaoDong Huang mmio_write_32(CRU_BASE + CRU_CLKSELS_CON(0), 948010d6ae3SXiaoDong Huang BITS_WITH_WMASK(0, 0xf, 8)); 949010d6ae3SXiaoDong Huang } 950010d6ae3SXiaoDong Huang 951010d6ae3SXiaoDong Huang static void pm_plls_resume(void) 952010d6ae3SXiaoDong Huang { 953010d6ae3SXiaoDong Huang /* pclk_dbg */ 954010d6ae3SXiaoDong Huang mmio_write_32(CRU_BASE + CRU_CLKSELS_CON(0), 955010d6ae3SXiaoDong Huang ddr_data.clk_sel0 | BITS_WMSK(0xf, 8)); 956010d6ae3SXiaoDong Huang 957010d6ae3SXiaoDong Huang /* core */ 958010d6ae3SXiaoDong Huang mmio_write_32(CRU_BASE + CRU_CLKSELS_CON(0), 959010d6ae3SXiaoDong Huang ddr_data.clk_sel0 | BITS_WMSK(0xf, 0)); 960010d6ae3SXiaoDong Huang 961010d6ae3SXiaoDong Huang pll_resume(APLL_ID); 962010d6ae3SXiaoDong Huang pll_resume(CPLL_ID); 963010d6ae3SXiaoDong Huang pll_resume(NPLL_ID); 964010d6ae3SXiaoDong Huang pll_resume(GPLL_ID); 965010d6ae3SXiaoDong Huang } 966010d6ae3SXiaoDong Huang 967010d6ae3SXiaoDong Huang int rockchip_soc_sys_pwr_dm_suspend(void) 968010d6ae3SXiaoDong Huang { 969010d6ae3SXiaoDong Huang pmu_power_domains_suspend(); 970010d6ae3SXiaoDong Huang 971010d6ae3SXiaoDong Huang clk_gate_suspend(); 972010d6ae3SXiaoDong Huang 973010d6ae3SXiaoDong Huang soc_sleep_config(); 974010d6ae3SXiaoDong Huang 975010d6ae3SXiaoDong Huang pm_plls_suspend(); 976010d6ae3SXiaoDong Huang 977010d6ae3SXiaoDong Huang psram_boot_cfg->pm_flag &= ~PM_WARM_BOOT_BIT; 978010d6ae3SXiaoDong Huang 979010d6ae3SXiaoDong Huang return 0; 980010d6ae3SXiaoDong Huang } 981010d6ae3SXiaoDong Huang 982010d6ae3SXiaoDong Huang int rockchip_soc_sys_pwr_dm_resume(void) 983010d6ae3SXiaoDong Huang { 984010d6ae3SXiaoDong Huang psram_boot_cfg->pm_flag |= PM_WARM_BOOT_BIT; 985010d6ae3SXiaoDong Huang 986010d6ae3SXiaoDong Huang pm_plls_resume(); 987010d6ae3SXiaoDong Huang 988010d6ae3SXiaoDong Huang soc_sleep_restore(); 989010d6ae3SXiaoDong Huang 990010d6ae3SXiaoDong Huang clk_gate_resume(); 991010d6ae3SXiaoDong Huang 992010d6ae3SXiaoDong Huang pmu_power_domains_resume(); 993010d6ae3SXiaoDong Huang 994010d6ae3SXiaoDong Huang plat_rockchip_gic_cpuif_enable(); 995010d6ae3SXiaoDong Huang 996010d6ae3SXiaoDong Huang return 0; 997010d6ae3SXiaoDong Huang } 998010d6ae3SXiaoDong Huang 999010d6ae3SXiaoDong Huang void __dead2 rockchip_soc_soft_reset(void) 1000010d6ae3SXiaoDong Huang { 1001010d6ae3SXiaoDong Huang pll_set_mode(GPLL_ID, SLOW_MODE); 1002010d6ae3SXiaoDong Huang pll_set_mode(CPLL_ID, SLOW_MODE); 1003010d6ae3SXiaoDong Huang pll_set_mode(NPLL_ID, SLOW_MODE); 1004010d6ae3SXiaoDong Huang pll_set_mode(APLL_ID, SLOW_MODE); 1005010d6ae3SXiaoDong Huang dsb(); 1006010d6ae3SXiaoDong Huang 1007010d6ae3SXiaoDong Huang mmio_write_32(CRU_BASE + CRU_GLB_SRST_FST, CRU_GLB_SRST_FST_VALUE); 1008010d6ae3SXiaoDong Huang dsb(); 1009010d6ae3SXiaoDong Huang 1010010d6ae3SXiaoDong Huang /* 1011010d6ae3SXiaoDong Huang * Maybe the HW needs some times to reset the system, 1012010d6ae3SXiaoDong Huang * so we do not hope the core to execute valid codes. 1013010d6ae3SXiaoDong Huang */ 1014010d6ae3SXiaoDong Huang psci_power_down_wfi(); 1015010d6ae3SXiaoDong Huang } 1016010d6ae3SXiaoDong Huang 1017010d6ae3SXiaoDong Huang void __dead2 rockchip_soc_system_off(void) 1018010d6ae3SXiaoDong Huang { 1019010d6ae3SXiaoDong Huang uint32_t val; 1020010d6ae3SXiaoDong Huang 1021010d6ae3SXiaoDong Huang /* set pmic_sleep pin(gpio0_a4) to gpio mode */ 1022010d6ae3SXiaoDong Huang mmio_write_32(PMUGRF_BASE + GPIO0A_IOMUX, BITS_WITH_WMASK(0, 0x3, 8)); 1023010d6ae3SXiaoDong Huang 1024010d6ae3SXiaoDong Huang /* config output */ 1025010d6ae3SXiaoDong Huang val = mmio_read_32(GPIO0_BASE + SWPORTA_DDR); 1026010d6ae3SXiaoDong Huang val |= BIT(4); 1027010d6ae3SXiaoDong Huang mmio_write_32(GPIO0_BASE + SWPORTA_DDR, val); 1028010d6ae3SXiaoDong Huang 1029010d6ae3SXiaoDong Huang /* config output high level */ 1030010d6ae3SXiaoDong Huang val = mmio_read_32(GPIO0_BASE); 1031010d6ae3SXiaoDong Huang val |= BIT(4); 1032010d6ae3SXiaoDong Huang mmio_write_32(GPIO0_BASE, val); 1033010d6ae3SXiaoDong Huang dsb(); 1034010d6ae3SXiaoDong Huang 1035010d6ae3SXiaoDong Huang /* 1036010d6ae3SXiaoDong Huang * Maybe the HW needs some times to reset the system, 1037010d6ae3SXiaoDong Huang * so we do not hope the core to execute valid codes. 1038010d6ae3SXiaoDong Huang */ 1039010d6ae3SXiaoDong Huang psci_power_down_wfi(); 1040010d6ae3SXiaoDong Huang } 1041010d6ae3SXiaoDong Huang 1042010d6ae3SXiaoDong Huang void rockchip_plat_mmu_el3(void) 1043010d6ae3SXiaoDong Huang { 1044010d6ae3SXiaoDong Huang /* TODO: support the el3 for px30 SoCs */ 1045010d6ae3SXiaoDong Huang } 1046010d6ae3SXiaoDong Huang 1047010d6ae3SXiaoDong Huang void plat_rockchip_pmu_init(void) 1048010d6ae3SXiaoDong Huang { 1049010d6ae3SXiaoDong Huang uint32_t cpu; 1050010d6ae3SXiaoDong Huang 1051010d6ae3SXiaoDong Huang rockchip_pd_lock_init(); 1052010d6ae3SXiaoDong Huang 1053010d6ae3SXiaoDong Huang for (cpu = 0; cpu < PLATFORM_CORE_COUNT; cpu++) 1054010d6ae3SXiaoDong Huang cpuson_flags[cpu] = 0; 1055010d6ae3SXiaoDong Huang 1056010d6ae3SXiaoDong Huang psram_boot_cfg->ddr_func = (uint64_t)0; 1057010d6ae3SXiaoDong Huang psram_boot_cfg->ddr_data = (uint64_t)0; 1058010d6ae3SXiaoDong Huang psram_boot_cfg->sp = PSRAM_SP_TOP; 1059010d6ae3SXiaoDong Huang psram_boot_cfg->ddr_flag = 0x0; 1060010d6ae3SXiaoDong Huang psram_boot_cfg->boot_mpidr = read_mpidr_el1() & 0xffff; 1061010d6ae3SXiaoDong Huang psram_boot_cfg->pm_flag = PM_WARM_BOOT_BIT; 1062010d6ae3SXiaoDong Huang 1063010d6ae3SXiaoDong Huang nonboot_cpus_off(); 1064010d6ae3SXiaoDong Huang 1065010d6ae3SXiaoDong Huang /* Remap pmu_sram's base address to boot address */ 1066010d6ae3SXiaoDong Huang mmio_write_32(PMUSGRF_BASE + PMUSGRF_SOC_CON(0), 1067010d6ae3SXiaoDong Huang BITS_WITH_WMASK(1, 0x1, 13)); 1068010d6ae3SXiaoDong Huang 1069010d6ae3SXiaoDong Huang INFO("%s: pd status %x\n", 1070010d6ae3SXiaoDong Huang __func__, mmio_read_32(PMU_BASE + PMU_PWRDN_ST)); 1071010d6ae3SXiaoDong Huang } 1072