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