1*010d6ae3SXiaoDong Huang /* 2*010d6ae3SXiaoDong Huang * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. 3*010d6ae3SXiaoDong Huang * 4*010d6ae3SXiaoDong Huang * SPDX-License-Identifier: BSD-3-Clause 5*010d6ae3SXiaoDong Huang */ 6*010d6ae3SXiaoDong Huang 7*010d6ae3SXiaoDong Huang #include <assert.h> 8*010d6ae3SXiaoDong Huang #include <errno.h> 9*010d6ae3SXiaoDong Huang 10*010d6ae3SXiaoDong Huang #include <platform_def.h> 11*010d6ae3SXiaoDong Huang 12*010d6ae3SXiaoDong Huang #include <arch_helpers.h> 13*010d6ae3SXiaoDong Huang #include <bl31/bl31.h> 14*010d6ae3SXiaoDong Huang #include <common/debug.h> 15*010d6ae3SXiaoDong Huang #include <drivers/console.h> 16*010d6ae3SXiaoDong Huang #include <drivers/delay_timer.h> 17*010d6ae3SXiaoDong Huang #include <lib/bakery_lock.h> 18*010d6ae3SXiaoDong Huang #include <lib/mmio.h> 19*010d6ae3SXiaoDong Huang #include <plat/common/platform.h> 20*010d6ae3SXiaoDong Huang 21*010d6ae3SXiaoDong Huang #include <cpus_on_fixed_addr.h> 22*010d6ae3SXiaoDong Huang #include <plat_private.h> 23*010d6ae3SXiaoDong Huang #include <pmu.h> 24*010d6ae3SXiaoDong Huang #include <px30_def.h> 25*010d6ae3SXiaoDong Huang #include <soc.h> 26*010d6ae3SXiaoDong Huang 27*010d6ae3SXiaoDong Huang DEFINE_BAKERY_LOCK(rockchip_pd_lock); 28*010d6ae3SXiaoDong Huang #define rockchip_pd_lock_init() bakery_lock_init(&rockchip_pd_lock) 29*010d6ae3SXiaoDong Huang #define rockchip_pd_lock_get() bakery_lock_get(&rockchip_pd_lock) 30*010d6ae3SXiaoDong Huang #define rockchip_pd_lock_rls() bakery_lock_release(&rockchip_pd_lock) 31*010d6ae3SXiaoDong Huang 32*010d6ae3SXiaoDong Huang static struct psram_data_t *psram_boot_cfg = 33*010d6ae3SXiaoDong Huang (struct psram_data_t *)&sys_sleep_flag_sram; 34*010d6ae3SXiaoDong Huang 35*010d6ae3SXiaoDong Huang /* 36*010d6ae3SXiaoDong Huang * There are two ways to powering on or off on core. 37*010d6ae3SXiaoDong Huang * 1) Control it power domain into on or off in PMU_PWRDN_CON reg, 38*010d6ae3SXiaoDong Huang * it is core_pwr_pd mode 39*010d6ae3SXiaoDong Huang * 2) Enable the core power manage in PMU_CORE_PM_CON reg, 40*010d6ae3SXiaoDong Huang * then, if the core enter into wfi, it power domain will be 41*010d6ae3SXiaoDong Huang * powered off automatically. it is core_pwr_wfi or core_pwr_wfi_int mode 42*010d6ae3SXiaoDong Huang * so we need core_pm_cfg_info to distinguish which method be used now. 43*010d6ae3SXiaoDong Huang */ 44*010d6ae3SXiaoDong Huang 45*010d6ae3SXiaoDong Huang static uint32_t cores_pd_cfg_info[PLATFORM_CORE_COUNT] 46*010d6ae3SXiaoDong Huang #if USE_COHERENT_MEM 47*010d6ae3SXiaoDong Huang __attribute__ ((section("tzfw_coherent_mem"))) 48*010d6ae3SXiaoDong Huang #endif 49*010d6ae3SXiaoDong Huang ; 50*010d6ae3SXiaoDong Huang 51*010d6ae3SXiaoDong Huang struct px30_sleep_ddr_data { 52*010d6ae3SXiaoDong Huang uint32_t clk_sel0; 53*010d6ae3SXiaoDong Huang uint32_t cru_mode_save; 54*010d6ae3SXiaoDong Huang uint32_t cru_pmu_mode_save; 55*010d6ae3SXiaoDong Huang uint32_t ddrc_hwlpctl; 56*010d6ae3SXiaoDong Huang uint32_t ddrc_pwrctrl; 57*010d6ae3SXiaoDong Huang uint32_t ddrgrf_con0; 58*010d6ae3SXiaoDong Huang uint32_t ddrgrf_con1; 59*010d6ae3SXiaoDong Huang uint32_t ddrstdby_con0; 60*010d6ae3SXiaoDong Huang uint32_t gpio0b_iomux; 61*010d6ae3SXiaoDong Huang uint32_t gpio0c_iomux; 62*010d6ae3SXiaoDong Huang uint32_t pmu_pwrmd_core_l; 63*010d6ae3SXiaoDong Huang uint32_t pmu_pwrmd_core_h; 64*010d6ae3SXiaoDong Huang uint32_t pmu_pwrmd_cmm_l; 65*010d6ae3SXiaoDong Huang uint32_t pmu_pwrmd_cmm_h; 66*010d6ae3SXiaoDong Huang uint32_t pmu_wkup_cfg2_l; 67*010d6ae3SXiaoDong Huang uint32_t pmu_cru_clksel_con0; 68*010d6ae3SXiaoDong Huang uint32_t pmugrf_soc_con0; 69*010d6ae3SXiaoDong Huang uint32_t pmusgrf_soc_con0; 70*010d6ae3SXiaoDong Huang uint32_t pmic_slp_iomux; 71*010d6ae3SXiaoDong Huang uint32_t pgrf_pvtm_con[2]; 72*010d6ae3SXiaoDong Huang uint32_t cru_clk_gate[CRU_CLKGATES_CON_CNT]; 73*010d6ae3SXiaoDong Huang uint32_t cru_pmu_clk_gate[CRU_PMU_CLKGATE_CON_CNT]; 74*010d6ae3SXiaoDong Huang uint32_t cru_plls_con_save[END_PLL_ID][PLL_CON_CNT]; 75*010d6ae3SXiaoDong Huang uint32_t cpu_qos[CPU_AXI_QOS_NUM_REGS]; 76*010d6ae3SXiaoDong Huang uint32_t gpu_qos[CPU_AXI_QOS_NUM_REGS]; 77*010d6ae3SXiaoDong Huang uint32_t isp_128m_qos[CPU_AXI_QOS_NUM_REGS]; 78*010d6ae3SXiaoDong Huang uint32_t isp_rd_qos[CPU_AXI_QOS_NUM_REGS]; 79*010d6ae3SXiaoDong Huang uint32_t isp_wr_qos[CPU_AXI_QOS_NUM_REGS]; 80*010d6ae3SXiaoDong Huang uint32_t isp_m1_qos[CPU_AXI_QOS_NUM_REGS]; 81*010d6ae3SXiaoDong Huang uint32_t vip_qos[CPU_AXI_QOS_NUM_REGS]; 82*010d6ae3SXiaoDong Huang uint32_t rga_rd_qos[CPU_AXI_QOS_NUM_REGS]; 83*010d6ae3SXiaoDong Huang uint32_t rga_wr_qos[CPU_AXI_QOS_NUM_REGS]; 84*010d6ae3SXiaoDong Huang uint32_t vop_m0_qos[CPU_AXI_QOS_NUM_REGS]; 85*010d6ae3SXiaoDong Huang uint32_t vop_m1_qos[CPU_AXI_QOS_NUM_REGS]; 86*010d6ae3SXiaoDong Huang uint32_t vpu_qos[CPU_AXI_QOS_NUM_REGS]; 87*010d6ae3SXiaoDong Huang uint32_t vpu_r128_qos[CPU_AXI_QOS_NUM_REGS]; 88*010d6ae3SXiaoDong Huang uint32_t dcf_qos[CPU_AXI_QOS_NUM_REGS]; 89*010d6ae3SXiaoDong Huang uint32_t dmac_qos[CPU_AXI_QOS_NUM_REGS]; 90*010d6ae3SXiaoDong Huang uint32_t crypto_qos[CPU_AXI_QOS_NUM_REGS]; 91*010d6ae3SXiaoDong Huang uint32_t gmac_qos[CPU_AXI_QOS_NUM_REGS]; 92*010d6ae3SXiaoDong Huang uint32_t emmc_qos[CPU_AXI_QOS_NUM_REGS]; 93*010d6ae3SXiaoDong Huang uint32_t nand_qos[CPU_AXI_QOS_NUM_REGS]; 94*010d6ae3SXiaoDong Huang uint32_t sdio_qos[CPU_AXI_QOS_NUM_REGS]; 95*010d6ae3SXiaoDong Huang uint32_t sfc_qos[CPU_AXI_QOS_NUM_REGS]; 96*010d6ae3SXiaoDong Huang uint32_t sdmmc_qos[CPU_AXI_QOS_NUM_REGS]; 97*010d6ae3SXiaoDong Huang uint32_t usb_host_qos[CPU_AXI_QOS_NUM_REGS]; 98*010d6ae3SXiaoDong Huang uint32_t usb_otg_qos[CPU_AXI_QOS_NUM_REGS]; 99*010d6ae3SXiaoDong Huang }; 100*010d6ae3SXiaoDong Huang 101*010d6ae3SXiaoDong Huang static struct px30_sleep_ddr_data ddr_data 102*010d6ae3SXiaoDong Huang #if USE_COHERENT_MEM 103*010d6ae3SXiaoDong Huang __attribute__ ((section("tzfw_coherent_mem"))) 104*010d6ae3SXiaoDong Huang #endif 105*010d6ae3SXiaoDong Huang ; 106*010d6ae3SXiaoDong Huang 107*010d6ae3SXiaoDong Huang static inline uint32_t get_cpus_pwr_domain_cfg_info(uint32_t cpu_id) 108*010d6ae3SXiaoDong Huang { 109*010d6ae3SXiaoDong Huang assert(cpu_id < PLATFORM_CORE_COUNT); 110*010d6ae3SXiaoDong Huang return cores_pd_cfg_info[cpu_id]; 111*010d6ae3SXiaoDong Huang } 112*010d6ae3SXiaoDong Huang 113*010d6ae3SXiaoDong Huang static inline void set_cpus_pwr_domain_cfg_info(uint32_t cpu_id, uint32_t value) 114*010d6ae3SXiaoDong Huang { 115*010d6ae3SXiaoDong Huang assert(cpu_id < PLATFORM_CORE_COUNT); 116*010d6ae3SXiaoDong Huang cores_pd_cfg_info[cpu_id] = value; 117*010d6ae3SXiaoDong Huang #if !USE_COHERENT_MEM 118*010d6ae3SXiaoDong Huang flush_dcache_range((uintptr_t)&cores_pd_cfg_info[cpu_id], 119*010d6ae3SXiaoDong Huang sizeof(uint32_t)); 120*010d6ae3SXiaoDong Huang #endif 121*010d6ae3SXiaoDong Huang } 122*010d6ae3SXiaoDong Huang 123*010d6ae3SXiaoDong Huang static inline uint32_t pmu_power_domain_st(uint32_t pd) 124*010d6ae3SXiaoDong Huang { 125*010d6ae3SXiaoDong Huang return mmio_read_32(PMU_BASE + PMU_PWRDN_ST) & BIT(pd) ? 126*010d6ae3SXiaoDong Huang pmu_pd_off : 127*010d6ae3SXiaoDong Huang pmu_pd_on; 128*010d6ae3SXiaoDong Huang } 129*010d6ae3SXiaoDong Huang 130*010d6ae3SXiaoDong Huang static int pmu_power_domain_ctr(uint32_t pd, uint32_t pd_state) 131*010d6ae3SXiaoDong Huang { 132*010d6ae3SXiaoDong Huang uint32_t loop = 0; 133*010d6ae3SXiaoDong Huang int ret = 0; 134*010d6ae3SXiaoDong Huang 135*010d6ae3SXiaoDong Huang rockchip_pd_lock_get(); 136*010d6ae3SXiaoDong Huang 137*010d6ae3SXiaoDong Huang mmio_write_32(PMU_BASE + PMU_PWRDN_CON, 138*010d6ae3SXiaoDong Huang BITS_WITH_WMASK(pd_state, 0x1, pd)); 139*010d6ae3SXiaoDong Huang dsb(); 140*010d6ae3SXiaoDong Huang 141*010d6ae3SXiaoDong Huang while ((pmu_power_domain_st(pd) != pd_state) && (loop < PD_CTR_LOOP)) { 142*010d6ae3SXiaoDong Huang udelay(1); 143*010d6ae3SXiaoDong Huang loop++; 144*010d6ae3SXiaoDong Huang } 145*010d6ae3SXiaoDong Huang 146*010d6ae3SXiaoDong Huang if (pmu_power_domain_st(pd) != pd_state) { 147*010d6ae3SXiaoDong Huang WARN("%s: %d, %d, error!\n", __func__, pd, pd_state); 148*010d6ae3SXiaoDong Huang ret = -EINVAL; 149*010d6ae3SXiaoDong Huang } 150*010d6ae3SXiaoDong Huang 151*010d6ae3SXiaoDong Huang rockchip_pd_lock_rls(); 152*010d6ae3SXiaoDong Huang 153*010d6ae3SXiaoDong Huang return ret; 154*010d6ae3SXiaoDong Huang } 155*010d6ae3SXiaoDong Huang 156*010d6ae3SXiaoDong Huang static inline uint32_t pmu_bus_idle_st(uint32_t bus) 157*010d6ae3SXiaoDong Huang { 158*010d6ae3SXiaoDong Huang return !!((mmio_read_32(PMU_BASE + PMU_BUS_IDLE_ST) & BIT(bus)) && 159*010d6ae3SXiaoDong Huang (mmio_read_32(PMU_BASE + PMU_BUS_IDLE_ST) & BIT(bus + 16))); 160*010d6ae3SXiaoDong Huang } 161*010d6ae3SXiaoDong Huang 162*010d6ae3SXiaoDong Huang static void pmu_bus_idle_req(uint32_t bus, uint32_t state) 163*010d6ae3SXiaoDong Huang { 164*010d6ae3SXiaoDong Huang uint32_t wait_cnt = 0; 165*010d6ae3SXiaoDong Huang 166*010d6ae3SXiaoDong Huang mmio_write_32(PMU_BASE + PMU_BUS_IDLE_REQ, 167*010d6ae3SXiaoDong Huang BITS_WITH_WMASK(state, 0x1, bus)); 168*010d6ae3SXiaoDong Huang 169*010d6ae3SXiaoDong Huang while (pmu_bus_idle_st(bus) != state && 170*010d6ae3SXiaoDong Huang wait_cnt < BUS_IDLE_LOOP) { 171*010d6ae3SXiaoDong Huang udelay(1); 172*010d6ae3SXiaoDong Huang wait_cnt++; 173*010d6ae3SXiaoDong Huang } 174*010d6ae3SXiaoDong Huang 175*010d6ae3SXiaoDong Huang if (pmu_bus_idle_st(bus) != state) 176*010d6ae3SXiaoDong Huang WARN("%s:idle_st=0x%x, bus_id=%d\n", 177*010d6ae3SXiaoDong Huang __func__, mmio_read_32(PMU_BASE + PMU_BUS_IDLE_ST), bus); 178*010d6ae3SXiaoDong Huang } 179*010d6ae3SXiaoDong Huang 180*010d6ae3SXiaoDong Huang static void qos_save(void) 181*010d6ae3SXiaoDong Huang { 182*010d6ae3SXiaoDong Huang /* scu powerdomain will power off, so cpu qos should be saved */ 183*010d6ae3SXiaoDong Huang SAVE_QOS(ddr_data.cpu_qos, CPU); 184*010d6ae3SXiaoDong Huang 185*010d6ae3SXiaoDong Huang if (pmu_power_domain_st(PD_GPU) == pmu_pd_on) 186*010d6ae3SXiaoDong Huang SAVE_QOS(ddr_data.gpu_qos, GPU); 187*010d6ae3SXiaoDong Huang if (pmu_power_domain_st(PD_VI) == pmu_pd_on) { 188*010d6ae3SXiaoDong Huang SAVE_QOS(ddr_data.isp_128m_qos, ISP_128M); 189*010d6ae3SXiaoDong Huang SAVE_QOS(ddr_data.isp_rd_qos, ISP_RD); 190*010d6ae3SXiaoDong Huang SAVE_QOS(ddr_data.isp_wr_qos, ISP_WR); 191*010d6ae3SXiaoDong Huang SAVE_QOS(ddr_data.isp_m1_qos, ISP_M1); 192*010d6ae3SXiaoDong Huang SAVE_QOS(ddr_data.vip_qos, VIP); 193*010d6ae3SXiaoDong Huang } 194*010d6ae3SXiaoDong Huang if (pmu_power_domain_st(PD_VO) == pmu_pd_on) { 195*010d6ae3SXiaoDong Huang SAVE_QOS(ddr_data.rga_rd_qos, RGA_RD); 196*010d6ae3SXiaoDong Huang SAVE_QOS(ddr_data.rga_wr_qos, RGA_WR); 197*010d6ae3SXiaoDong Huang SAVE_QOS(ddr_data.vop_m0_qos, VOP_M0); 198*010d6ae3SXiaoDong Huang SAVE_QOS(ddr_data.vop_m1_qos, VOP_M1); 199*010d6ae3SXiaoDong Huang } 200*010d6ae3SXiaoDong Huang if (pmu_power_domain_st(PD_VPU) == pmu_pd_on) { 201*010d6ae3SXiaoDong Huang SAVE_QOS(ddr_data.vpu_qos, VPU); 202*010d6ae3SXiaoDong Huang SAVE_QOS(ddr_data.vpu_r128_qos, VPU_R128); 203*010d6ae3SXiaoDong Huang } 204*010d6ae3SXiaoDong Huang if (pmu_power_domain_st(PD_MMC_NAND) == pmu_pd_on) { 205*010d6ae3SXiaoDong Huang SAVE_QOS(ddr_data.emmc_qos, EMMC); 206*010d6ae3SXiaoDong Huang SAVE_QOS(ddr_data.nand_qos, NAND); 207*010d6ae3SXiaoDong Huang SAVE_QOS(ddr_data.sdio_qos, SDIO); 208*010d6ae3SXiaoDong Huang SAVE_QOS(ddr_data.sfc_qos, SFC); 209*010d6ae3SXiaoDong Huang } 210*010d6ae3SXiaoDong Huang if (pmu_power_domain_st(PD_GMAC) == pmu_pd_on) 211*010d6ae3SXiaoDong Huang SAVE_QOS(ddr_data.gmac_qos, GMAC); 212*010d6ae3SXiaoDong Huang if (pmu_power_domain_st(PD_CRYPTO) == pmu_pd_on) 213*010d6ae3SXiaoDong Huang SAVE_QOS(ddr_data.crypto_qos, CRYPTO); 214*010d6ae3SXiaoDong Huang if (pmu_power_domain_st(PD_SDCARD) == pmu_pd_on) 215*010d6ae3SXiaoDong Huang SAVE_QOS(ddr_data.sdmmc_qos, SDMMC); 216*010d6ae3SXiaoDong Huang if (pmu_power_domain_st(PD_USB) == pmu_pd_on) { 217*010d6ae3SXiaoDong Huang SAVE_QOS(ddr_data.usb_host_qos, USB_HOST); 218*010d6ae3SXiaoDong Huang SAVE_QOS(ddr_data.usb_otg_qos, USB_OTG); 219*010d6ae3SXiaoDong Huang } 220*010d6ae3SXiaoDong Huang } 221*010d6ae3SXiaoDong Huang 222*010d6ae3SXiaoDong Huang static void qos_restore(void) 223*010d6ae3SXiaoDong Huang { 224*010d6ae3SXiaoDong Huang RESTORE_QOS(ddr_data.cpu_qos, CPU); 225*010d6ae3SXiaoDong Huang 226*010d6ae3SXiaoDong Huang if (pmu_power_domain_st(PD_GPU) == pmu_pd_on) 227*010d6ae3SXiaoDong Huang RESTORE_QOS(ddr_data.gpu_qos, GPU); 228*010d6ae3SXiaoDong Huang if (pmu_power_domain_st(PD_VI) == pmu_pd_on) { 229*010d6ae3SXiaoDong Huang RESTORE_QOS(ddr_data.isp_128m_qos, ISP_128M); 230*010d6ae3SXiaoDong Huang RESTORE_QOS(ddr_data.isp_rd_qos, ISP_RD); 231*010d6ae3SXiaoDong Huang RESTORE_QOS(ddr_data.isp_wr_qos, ISP_WR); 232*010d6ae3SXiaoDong Huang RESTORE_QOS(ddr_data.isp_m1_qos, ISP_M1); 233*010d6ae3SXiaoDong Huang RESTORE_QOS(ddr_data.vip_qos, VIP); 234*010d6ae3SXiaoDong Huang } 235*010d6ae3SXiaoDong Huang if (pmu_power_domain_st(PD_VO) == pmu_pd_on) { 236*010d6ae3SXiaoDong Huang RESTORE_QOS(ddr_data.rga_rd_qos, RGA_RD); 237*010d6ae3SXiaoDong Huang RESTORE_QOS(ddr_data.rga_wr_qos, RGA_WR); 238*010d6ae3SXiaoDong Huang RESTORE_QOS(ddr_data.vop_m0_qos, VOP_M0); 239*010d6ae3SXiaoDong Huang RESTORE_QOS(ddr_data.vop_m1_qos, VOP_M1); 240*010d6ae3SXiaoDong Huang } 241*010d6ae3SXiaoDong Huang if (pmu_power_domain_st(PD_VPU) == pmu_pd_on) { 242*010d6ae3SXiaoDong Huang RESTORE_QOS(ddr_data.vpu_qos, VPU); 243*010d6ae3SXiaoDong Huang RESTORE_QOS(ddr_data.vpu_r128_qos, VPU_R128); 244*010d6ae3SXiaoDong Huang } 245*010d6ae3SXiaoDong Huang if (pmu_power_domain_st(PD_MMC_NAND) == pmu_pd_on) { 246*010d6ae3SXiaoDong Huang RESTORE_QOS(ddr_data.emmc_qos, EMMC); 247*010d6ae3SXiaoDong Huang RESTORE_QOS(ddr_data.nand_qos, NAND); 248*010d6ae3SXiaoDong Huang RESTORE_QOS(ddr_data.sdio_qos, SDIO); 249*010d6ae3SXiaoDong Huang RESTORE_QOS(ddr_data.sfc_qos, SFC); 250*010d6ae3SXiaoDong Huang } 251*010d6ae3SXiaoDong Huang if (pmu_power_domain_st(PD_GMAC) == pmu_pd_on) 252*010d6ae3SXiaoDong Huang RESTORE_QOS(ddr_data.gmac_qos, GMAC); 253*010d6ae3SXiaoDong Huang if (pmu_power_domain_st(PD_CRYPTO) == pmu_pd_on) 254*010d6ae3SXiaoDong Huang RESTORE_QOS(ddr_data.crypto_qos, CRYPTO); 255*010d6ae3SXiaoDong Huang if (pmu_power_domain_st(PD_SDCARD) == pmu_pd_on) 256*010d6ae3SXiaoDong Huang RESTORE_QOS(ddr_data.sdmmc_qos, SDMMC); 257*010d6ae3SXiaoDong Huang if (pmu_power_domain_st(PD_USB) == pmu_pd_on) { 258*010d6ae3SXiaoDong Huang RESTORE_QOS(ddr_data.usb_host_qos, USB_HOST); 259*010d6ae3SXiaoDong Huang RESTORE_QOS(ddr_data.usb_otg_qos, USB_OTG); 260*010d6ae3SXiaoDong Huang } 261*010d6ae3SXiaoDong Huang } 262*010d6ae3SXiaoDong Huang 263*010d6ae3SXiaoDong Huang static int pmu_set_power_domain(uint32_t pd_id, uint32_t pd_state) 264*010d6ae3SXiaoDong Huang { 265*010d6ae3SXiaoDong Huang uint32_t state; 266*010d6ae3SXiaoDong Huang 267*010d6ae3SXiaoDong Huang if (pmu_power_domain_st(pd_id) == pd_state) 268*010d6ae3SXiaoDong Huang goto out; 269*010d6ae3SXiaoDong Huang 270*010d6ae3SXiaoDong Huang if (pd_state == pmu_pd_on) 271*010d6ae3SXiaoDong Huang pmu_power_domain_ctr(pd_id, pd_state); 272*010d6ae3SXiaoDong Huang 273*010d6ae3SXiaoDong Huang state = (pd_state == pmu_pd_off) ? bus_idle : bus_active; 274*010d6ae3SXiaoDong Huang 275*010d6ae3SXiaoDong Huang switch (pd_id) { 276*010d6ae3SXiaoDong Huang case PD_GPU: 277*010d6ae3SXiaoDong Huang pmu_bus_idle_req(BUS_ID_GPU, state); 278*010d6ae3SXiaoDong Huang break; 279*010d6ae3SXiaoDong Huang case PD_VI: 280*010d6ae3SXiaoDong Huang pmu_bus_idle_req(BUS_ID_VI, state); 281*010d6ae3SXiaoDong Huang break; 282*010d6ae3SXiaoDong Huang case PD_VO: 283*010d6ae3SXiaoDong Huang pmu_bus_idle_req(BUS_ID_VO, state); 284*010d6ae3SXiaoDong Huang break; 285*010d6ae3SXiaoDong Huang case PD_VPU: 286*010d6ae3SXiaoDong Huang pmu_bus_idle_req(BUS_ID_VPU, state); 287*010d6ae3SXiaoDong Huang break; 288*010d6ae3SXiaoDong Huang case PD_MMC_NAND: 289*010d6ae3SXiaoDong Huang pmu_bus_idle_req(BUS_ID_MMC, state); 290*010d6ae3SXiaoDong Huang break; 291*010d6ae3SXiaoDong Huang case PD_GMAC: 292*010d6ae3SXiaoDong Huang pmu_bus_idle_req(BUS_ID_GMAC, state); 293*010d6ae3SXiaoDong Huang break; 294*010d6ae3SXiaoDong Huang case PD_CRYPTO: 295*010d6ae3SXiaoDong Huang pmu_bus_idle_req(BUS_ID_CRYPTO, state); 296*010d6ae3SXiaoDong Huang break; 297*010d6ae3SXiaoDong Huang case PD_SDCARD: 298*010d6ae3SXiaoDong Huang pmu_bus_idle_req(BUS_ID_SDCARD, state); 299*010d6ae3SXiaoDong Huang break; 300*010d6ae3SXiaoDong Huang case PD_USB: 301*010d6ae3SXiaoDong Huang pmu_bus_idle_req(BUS_ID_USB, state); 302*010d6ae3SXiaoDong Huang break; 303*010d6ae3SXiaoDong Huang default: 304*010d6ae3SXiaoDong Huang break; 305*010d6ae3SXiaoDong Huang } 306*010d6ae3SXiaoDong Huang 307*010d6ae3SXiaoDong Huang if (pd_state == pmu_pd_off) 308*010d6ae3SXiaoDong Huang pmu_power_domain_ctr(pd_id, pd_state); 309*010d6ae3SXiaoDong Huang 310*010d6ae3SXiaoDong Huang out: 311*010d6ae3SXiaoDong Huang return 0; 312*010d6ae3SXiaoDong Huang } 313*010d6ae3SXiaoDong Huang 314*010d6ae3SXiaoDong Huang static uint32_t pmu_powerdomain_state; 315*010d6ae3SXiaoDong Huang 316*010d6ae3SXiaoDong Huang static void pmu_power_domains_suspend(void) 317*010d6ae3SXiaoDong Huang { 318*010d6ae3SXiaoDong Huang uint32_t clkgt_save[CRU_CLKGATES_CON_CNT + CRU_PMU_CLKGATE_CON_CNT]; 319*010d6ae3SXiaoDong Huang 320*010d6ae3SXiaoDong Huang clk_gate_con_save(clkgt_save); 321*010d6ae3SXiaoDong Huang clk_gate_con_disable(); 322*010d6ae3SXiaoDong Huang qos_save(); 323*010d6ae3SXiaoDong Huang 324*010d6ae3SXiaoDong Huang pmu_powerdomain_state = mmio_read_32(PMU_BASE + PMU_PWRDN_ST); 325*010d6ae3SXiaoDong Huang pmu_set_power_domain(PD_GPU, pmu_pd_off); 326*010d6ae3SXiaoDong Huang pmu_set_power_domain(PD_VI, pmu_pd_off); 327*010d6ae3SXiaoDong Huang pmu_set_power_domain(PD_VO, pmu_pd_off); 328*010d6ae3SXiaoDong Huang pmu_set_power_domain(PD_VPU, pmu_pd_off); 329*010d6ae3SXiaoDong Huang pmu_set_power_domain(PD_MMC_NAND, pmu_pd_off); 330*010d6ae3SXiaoDong Huang pmu_set_power_domain(PD_GMAC, pmu_pd_off); 331*010d6ae3SXiaoDong Huang pmu_set_power_domain(PD_CRYPTO, pmu_pd_off); 332*010d6ae3SXiaoDong Huang pmu_set_power_domain(PD_SDCARD, pmu_pd_off); 333*010d6ae3SXiaoDong Huang pmu_set_power_domain(PD_USB, pmu_pd_off); 334*010d6ae3SXiaoDong Huang 335*010d6ae3SXiaoDong Huang clk_gate_con_restore(clkgt_save); 336*010d6ae3SXiaoDong Huang } 337*010d6ae3SXiaoDong Huang 338*010d6ae3SXiaoDong Huang static void pmu_power_domains_resume(void) 339*010d6ae3SXiaoDong Huang { 340*010d6ae3SXiaoDong Huang uint32_t clkgt_save[CRU_CLKGATES_CON_CNT + CRU_PMU_CLKGATE_CON_CNT]; 341*010d6ae3SXiaoDong Huang 342*010d6ae3SXiaoDong Huang clk_gate_con_save(clkgt_save); 343*010d6ae3SXiaoDong Huang clk_gate_con_disable(); 344*010d6ae3SXiaoDong Huang 345*010d6ae3SXiaoDong Huang if (!(pmu_powerdomain_state & BIT(PD_USB))) 346*010d6ae3SXiaoDong Huang pmu_set_power_domain(PD_USB, pmu_pd_on); 347*010d6ae3SXiaoDong Huang if (!(pmu_powerdomain_state & BIT(PD_SDCARD))) 348*010d6ae3SXiaoDong Huang pmu_set_power_domain(PD_SDCARD, pmu_pd_on); 349*010d6ae3SXiaoDong Huang if (!(pmu_powerdomain_state & BIT(PD_CRYPTO))) 350*010d6ae3SXiaoDong Huang pmu_set_power_domain(PD_CRYPTO, pmu_pd_on); 351*010d6ae3SXiaoDong Huang if (!(pmu_powerdomain_state & BIT(PD_GMAC))) 352*010d6ae3SXiaoDong Huang pmu_set_power_domain(PD_GMAC, pmu_pd_on); 353*010d6ae3SXiaoDong Huang if (!(pmu_powerdomain_state & BIT(PD_MMC_NAND))) 354*010d6ae3SXiaoDong Huang pmu_set_power_domain(PD_MMC_NAND, pmu_pd_on); 355*010d6ae3SXiaoDong Huang if (!(pmu_powerdomain_state & BIT(PD_VPU))) 356*010d6ae3SXiaoDong Huang pmu_set_power_domain(PD_VPU, pmu_pd_on); 357*010d6ae3SXiaoDong Huang if (!(pmu_powerdomain_state & BIT(PD_VO))) 358*010d6ae3SXiaoDong Huang pmu_set_power_domain(PD_VO, pmu_pd_on); 359*010d6ae3SXiaoDong Huang if (!(pmu_powerdomain_state & BIT(PD_VI))) 360*010d6ae3SXiaoDong Huang pmu_set_power_domain(PD_VI, pmu_pd_on); 361*010d6ae3SXiaoDong Huang if (!(pmu_powerdomain_state & BIT(PD_GPU))) 362*010d6ae3SXiaoDong Huang pmu_set_power_domain(PD_GPU, pmu_pd_on); 363*010d6ae3SXiaoDong Huang 364*010d6ae3SXiaoDong Huang qos_restore(); 365*010d6ae3SXiaoDong Huang clk_gate_con_restore(clkgt_save); 366*010d6ae3SXiaoDong Huang } 367*010d6ae3SXiaoDong Huang 368*010d6ae3SXiaoDong Huang static int check_cpu_wfie(uint32_t cpu) 369*010d6ae3SXiaoDong Huang { 370*010d6ae3SXiaoDong Huang uint32_t loop = 0, wfie_msk = CKECK_WFEI_MSK << cpu; 371*010d6ae3SXiaoDong Huang 372*010d6ae3SXiaoDong Huang while (!(mmio_read_32(GRF_BASE + GRF_CPU_STATUS1) & wfie_msk) && 373*010d6ae3SXiaoDong Huang (loop < WFEI_CHECK_LOOP)) { 374*010d6ae3SXiaoDong Huang udelay(1); 375*010d6ae3SXiaoDong Huang loop++; 376*010d6ae3SXiaoDong Huang } 377*010d6ae3SXiaoDong Huang 378*010d6ae3SXiaoDong Huang if ((mmio_read_32(GRF_BASE + GRF_CPU_STATUS1) & wfie_msk) == 0) { 379*010d6ae3SXiaoDong Huang WARN("%s: %d, %d, error!\n", __func__, cpu, wfie_msk); 380*010d6ae3SXiaoDong Huang return -EINVAL; 381*010d6ae3SXiaoDong Huang } 382*010d6ae3SXiaoDong Huang 383*010d6ae3SXiaoDong Huang return 0; 384*010d6ae3SXiaoDong Huang } 385*010d6ae3SXiaoDong Huang 386*010d6ae3SXiaoDong Huang static int cpus_power_domain_on(uint32_t cpu_id) 387*010d6ae3SXiaoDong Huang { 388*010d6ae3SXiaoDong Huang uint32_t cpu_pd, apm_value, cfg_info, loop = 0; 389*010d6ae3SXiaoDong Huang 390*010d6ae3SXiaoDong Huang cpu_pd = PD_CPU0 + cpu_id; 391*010d6ae3SXiaoDong Huang cfg_info = get_cpus_pwr_domain_cfg_info(cpu_id); 392*010d6ae3SXiaoDong Huang 393*010d6ae3SXiaoDong Huang if (cfg_info == core_pwr_pd) { 394*010d6ae3SXiaoDong Huang /* disable apm cfg */ 395*010d6ae3SXiaoDong Huang mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(cpu_id), 396*010d6ae3SXiaoDong Huang WITH_16BITS_WMSK(CORES_PM_DISABLE)); 397*010d6ae3SXiaoDong Huang if (pmu_power_domain_st(cpu_pd) == pmu_pd_on) { 398*010d6ae3SXiaoDong Huang mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(cpu_id), 399*010d6ae3SXiaoDong Huang WITH_16BITS_WMSK(CORES_PM_DISABLE)); 400*010d6ae3SXiaoDong Huang pmu_power_domain_ctr(cpu_pd, pmu_pd_off); 401*010d6ae3SXiaoDong Huang } 402*010d6ae3SXiaoDong Huang pmu_power_domain_ctr(cpu_pd, pmu_pd_on); 403*010d6ae3SXiaoDong Huang } else { 404*010d6ae3SXiaoDong Huang /* wait cpu down */ 405*010d6ae3SXiaoDong Huang while (pmu_power_domain_st(cpu_pd) == pmu_pd_on && loop < 100) { 406*010d6ae3SXiaoDong Huang udelay(2); 407*010d6ae3SXiaoDong Huang loop++; 408*010d6ae3SXiaoDong Huang } 409*010d6ae3SXiaoDong Huang 410*010d6ae3SXiaoDong Huang /* return error if can't wait cpu down */ 411*010d6ae3SXiaoDong Huang if (pmu_power_domain_st(cpu_pd) == pmu_pd_on) { 412*010d6ae3SXiaoDong Huang WARN("%s:can't wait cpu down\n", __func__); 413*010d6ae3SXiaoDong Huang return -EINVAL; 414*010d6ae3SXiaoDong Huang } 415*010d6ae3SXiaoDong Huang 416*010d6ae3SXiaoDong Huang /* power up cpu in power down state */ 417*010d6ae3SXiaoDong Huang apm_value = BIT(core_pm_sft_wakeup_en); 418*010d6ae3SXiaoDong Huang mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(cpu_id), 419*010d6ae3SXiaoDong Huang WITH_16BITS_WMSK(apm_value)); 420*010d6ae3SXiaoDong Huang } 421*010d6ae3SXiaoDong Huang 422*010d6ae3SXiaoDong Huang return 0; 423*010d6ae3SXiaoDong Huang } 424*010d6ae3SXiaoDong Huang 425*010d6ae3SXiaoDong Huang static int cpus_power_domain_off(uint32_t cpu_id, uint32_t pd_cfg) 426*010d6ae3SXiaoDong Huang { 427*010d6ae3SXiaoDong Huang uint32_t cpu_pd, apm_value; 428*010d6ae3SXiaoDong Huang 429*010d6ae3SXiaoDong Huang cpu_pd = PD_CPU0 + cpu_id; 430*010d6ae3SXiaoDong Huang if (pmu_power_domain_st(cpu_pd) == pmu_pd_off) 431*010d6ae3SXiaoDong Huang return 0; 432*010d6ae3SXiaoDong Huang 433*010d6ae3SXiaoDong Huang if (pd_cfg == core_pwr_pd) { 434*010d6ae3SXiaoDong Huang if (check_cpu_wfie(cpu_id)) 435*010d6ae3SXiaoDong Huang return -EINVAL; 436*010d6ae3SXiaoDong Huang /* disable apm cfg */ 437*010d6ae3SXiaoDong Huang mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(cpu_id), 438*010d6ae3SXiaoDong Huang WITH_16BITS_WMSK(CORES_PM_DISABLE)); 439*010d6ae3SXiaoDong Huang set_cpus_pwr_domain_cfg_info(cpu_id, pd_cfg); 440*010d6ae3SXiaoDong Huang pmu_power_domain_ctr(cpu_pd, pmu_pd_off); 441*010d6ae3SXiaoDong Huang } else { 442*010d6ae3SXiaoDong Huang set_cpus_pwr_domain_cfg_info(cpu_id, pd_cfg); 443*010d6ae3SXiaoDong Huang apm_value = BIT(core_pm_en) | BIT(core_pm_dis_int); 444*010d6ae3SXiaoDong Huang if (pd_cfg == core_pwr_wfi_int) 445*010d6ae3SXiaoDong Huang apm_value |= BIT(core_pm_int_wakeup_en); 446*010d6ae3SXiaoDong Huang mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(cpu_id), 447*010d6ae3SXiaoDong Huang WITH_16BITS_WMSK(apm_value)); 448*010d6ae3SXiaoDong Huang } 449*010d6ae3SXiaoDong Huang 450*010d6ae3SXiaoDong Huang return 0; 451*010d6ae3SXiaoDong Huang } 452*010d6ae3SXiaoDong Huang 453*010d6ae3SXiaoDong Huang static void nonboot_cpus_off(void) 454*010d6ae3SXiaoDong Huang { 455*010d6ae3SXiaoDong Huang uint32_t boot_cpu, cpu; 456*010d6ae3SXiaoDong Huang 457*010d6ae3SXiaoDong Huang boot_cpu = plat_my_core_pos(); 458*010d6ae3SXiaoDong Huang 459*010d6ae3SXiaoDong Huang for (cpu = 0; cpu < PLATFORM_CORE_COUNT; cpu++) { 460*010d6ae3SXiaoDong Huang if (cpu == boot_cpu) 461*010d6ae3SXiaoDong Huang continue; 462*010d6ae3SXiaoDong Huang cpus_power_domain_off(cpu, core_pwr_pd); 463*010d6ae3SXiaoDong Huang } 464*010d6ae3SXiaoDong Huang } 465*010d6ae3SXiaoDong Huang 466*010d6ae3SXiaoDong Huang int rockchip_soc_cores_pwr_dm_on(unsigned long mpidr, 467*010d6ae3SXiaoDong Huang uint64_t entrypoint) 468*010d6ae3SXiaoDong Huang { 469*010d6ae3SXiaoDong Huang uint32_t cpu_id = plat_core_pos_by_mpidr(mpidr); 470*010d6ae3SXiaoDong Huang 471*010d6ae3SXiaoDong Huang assert(cpu_id < PLATFORM_CORE_COUNT); 472*010d6ae3SXiaoDong Huang assert(cpuson_flags[cpu_id] == 0); 473*010d6ae3SXiaoDong Huang cpuson_flags[cpu_id] = PMU_CPU_HOTPLUG; 474*010d6ae3SXiaoDong Huang cpuson_entry_point[cpu_id] = entrypoint; 475*010d6ae3SXiaoDong Huang dsb(); 476*010d6ae3SXiaoDong Huang 477*010d6ae3SXiaoDong Huang cpus_power_domain_on(cpu_id); 478*010d6ae3SXiaoDong Huang 479*010d6ae3SXiaoDong Huang return PSCI_E_SUCCESS; 480*010d6ae3SXiaoDong Huang } 481*010d6ae3SXiaoDong Huang 482*010d6ae3SXiaoDong Huang int rockchip_soc_cores_pwr_dm_on_finish(void) 483*010d6ae3SXiaoDong Huang { 484*010d6ae3SXiaoDong Huang uint32_t cpu_id = plat_my_core_pos(); 485*010d6ae3SXiaoDong Huang 486*010d6ae3SXiaoDong Huang mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(cpu_id), 487*010d6ae3SXiaoDong Huang WITH_16BITS_WMSK(CORES_PM_DISABLE)); 488*010d6ae3SXiaoDong Huang return PSCI_E_SUCCESS; 489*010d6ae3SXiaoDong Huang } 490*010d6ae3SXiaoDong Huang 491*010d6ae3SXiaoDong Huang int rockchip_soc_cores_pwr_dm_off(void) 492*010d6ae3SXiaoDong Huang { 493*010d6ae3SXiaoDong Huang uint32_t cpu_id = plat_my_core_pos(); 494*010d6ae3SXiaoDong Huang 495*010d6ae3SXiaoDong Huang cpus_power_domain_off(cpu_id, core_pwr_wfi); 496*010d6ae3SXiaoDong Huang 497*010d6ae3SXiaoDong Huang return PSCI_E_SUCCESS; 498*010d6ae3SXiaoDong Huang } 499*010d6ae3SXiaoDong Huang 500*010d6ae3SXiaoDong Huang int rockchip_soc_cores_pwr_dm_suspend(void) 501*010d6ae3SXiaoDong Huang { 502*010d6ae3SXiaoDong Huang uint32_t cpu_id = plat_my_core_pos(); 503*010d6ae3SXiaoDong Huang 504*010d6ae3SXiaoDong Huang assert(cpu_id < PLATFORM_CORE_COUNT); 505*010d6ae3SXiaoDong Huang assert(cpuson_flags[cpu_id] == 0); 506*010d6ae3SXiaoDong Huang cpuson_flags[cpu_id] = PMU_CPU_AUTO_PWRDN; 507*010d6ae3SXiaoDong Huang cpuson_entry_point[cpu_id] = plat_get_sec_entrypoint(); 508*010d6ae3SXiaoDong Huang dsb(); 509*010d6ae3SXiaoDong Huang 510*010d6ae3SXiaoDong Huang cpus_power_domain_off(cpu_id, core_pwr_wfi_int); 511*010d6ae3SXiaoDong Huang 512*010d6ae3SXiaoDong Huang return PSCI_E_SUCCESS; 513*010d6ae3SXiaoDong Huang } 514*010d6ae3SXiaoDong Huang 515*010d6ae3SXiaoDong Huang int rockchip_soc_cores_pwr_dm_resume(void) 516*010d6ae3SXiaoDong Huang { 517*010d6ae3SXiaoDong Huang uint32_t cpu_id = plat_my_core_pos(); 518*010d6ae3SXiaoDong Huang 519*010d6ae3SXiaoDong Huang /* Disable core_pm */ 520*010d6ae3SXiaoDong Huang mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(cpu_id), 521*010d6ae3SXiaoDong Huang WITH_16BITS_WMSK(CORES_PM_DISABLE)); 522*010d6ae3SXiaoDong Huang 523*010d6ae3SXiaoDong Huang return PSCI_E_SUCCESS; 524*010d6ae3SXiaoDong Huang } 525*010d6ae3SXiaoDong Huang 526*010d6ae3SXiaoDong Huang #define CLK_MSK_GATING(msk, con) \ 527*010d6ae3SXiaoDong Huang mmio_write_32(CRU_BASE + (con), ((msk) << 16) | 0xffff) 528*010d6ae3SXiaoDong Huang #define CLK_MSK_UNGATING(msk, con) \ 529*010d6ae3SXiaoDong Huang mmio_write_32(CRU_BASE + (con), ((~(msk)) << 16) | 0xffff) 530*010d6ae3SXiaoDong Huang 531*010d6ae3SXiaoDong Huang static uint32_t clk_ungt_msk[CRU_CLKGATES_CON_CNT] = { 532*010d6ae3SXiaoDong Huang 0xe0ff, 0xffff, 0x0000, 0x0000, 533*010d6ae3SXiaoDong Huang 0x0000, 0x0380, 0x0000, 0x0000, 534*010d6ae3SXiaoDong Huang 0x07c0, 0x0000, 0x0000, 0x000f, 535*010d6ae3SXiaoDong Huang 0x0061, 0x1f02, 0x0440, 0x1801, 536*010d6ae3SXiaoDong Huang 0x004b, 0x0000 537*010d6ae3SXiaoDong Huang }; 538*010d6ae3SXiaoDong Huang 539*010d6ae3SXiaoDong Huang static uint32_t clk_pmu_ungt_msk[CRU_PMU_CLKGATE_CON_CNT] = { 540*010d6ae3SXiaoDong Huang 0xf1ff, 0x0310 541*010d6ae3SXiaoDong Huang }; 542*010d6ae3SXiaoDong Huang 543*010d6ae3SXiaoDong Huang void clk_gate_suspend(void) 544*010d6ae3SXiaoDong Huang { 545*010d6ae3SXiaoDong Huang int i; 546*010d6ae3SXiaoDong Huang 547*010d6ae3SXiaoDong Huang for (i = 0; i < CRU_CLKGATES_CON_CNT; i++) { 548*010d6ae3SXiaoDong Huang ddr_data.cru_clk_gate[i] = 549*010d6ae3SXiaoDong Huang mmio_read_32(CRU_BASE + CRU_CLKGATES_CON(i)); 550*010d6ae3SXiaoDong Huang mmio_write_32(CRU_BASE + CRU_CLKGATES_CON(i), 551*010d6ae3SXiaoDong Huang WITH_16BITS_WMSK(~clk_ungt_msk[i])); 552*010d6ae3SXiaoDong Huang } 553*010d6ae3SXiaoDong Huang 554*010d6ae3SXiaoDong Huang for (i = 0; i < CRU_PMU_CLKGATE_CON_CNT; i++) { 555*010d6ae3SXiaoDong Huang ddr_data.cru_pmu_clk_gate[i] = 556*010d6ae3SXiaoDong Huang mmio_read_32(PMUCRU_BASE + CRU_PMU_CLKGATES_CON(i)); 557*010d6ae3SXiaoDong Huang mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKGATES_CON(i), 558*010d6ae3SXiaoDong Huang WITH_16BITS_WMSK(~clk_pmu_ungt_msk[i])); 559*010d6ae3SXiaoDong Huang } 560*010d6ae3SXiaoDong Huang } 561*010d6ae3SXiaoDong Huang 562*010d6ae3SXiaoDong Huang void clk_gate_resume(void) 563*010d6ae3SXiaoDong Huang { 564*010d6ae3SXiaoDong Huang int i; 565*010d6ae3SXiaoDong Huang 566*010d6ae3SXiaoDong Huang for (i = 0; i < CRU_PMU_CLKGATE_CON_CNT; i++) 567*010d6ae3SXiaoDong Huang mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKGATES_CON(i), 568*010d6ae3SXiaoDong Huang WITH_16BITS_WMSK(ddr_data.cru_pmu_clk_gate[i])); 569*010d6ae3SXiaoDong Huang 570*010d6ae3SXiaoDong Huang for (i = 0; i < CRU_CLKGATES_CON_CNT; i++) 571*010d6ae3SXiaoDong Huang mmio_write_32(CRU_BASE + CRU_CLKGATES_CON(i), 572*010d6ae3SXiaoDong Huang WITH_16BITS_WMSK(ddr_data.cru_clk_gate[i])); 573*010d6ae3SXiaoDong Huang } 574*010d6ae3SXiaoDong Huang 575*010d6ae3SXiaoDong Huang static void pvtm_32k_config(void) 576*010d6ae3SXiaoDong Huang { 577*010d6ae3SXiaoDong Huang uint32_t pvtm_freq_khz, pvtm_div; 578*010d6ae3SXiaoDong Huang 579*010d6ae3SXiaoDong Huang ddr_data.pmu_cru_clksel_con0 = 580*010d6ae3SXiaoDong Huang mmio_read_32(PMUCRU_BASE + CRU_PMU_CLKSELS_CON(0)); 581*010d6ae3SXiaoDong Huang 582*010d6ae3SXiaoDong Huang ddr_data.pgrf_pvtm_con[0] = 583*010d6ae3SXiaoDong Huang mmio_read_32(PMUGRF_BASE + PMUGRF_PVTM_CON0); 584*010d6ae3SXiaoDong Huang ddr_data.pgrf_pvtm_con[1] = 585*010d6ae3SXiaoDong Huang mmio_read_32(PMUGRF_BASE + PMUGRF_PVTM_CON1); 586*010d6ae3SXiaoDong Huang 587*010d6ae3SXiaoDong Huang mmio_write_32(PMUGRF_BASE + PMUGRF_PVTM_CON0, 588*010d6ae3SXiaoDong Huang BITS_WITH_WMASK(0, 0x3, pgrf_pvtm_st)); 589*010d6ae3SXiaoDong Huang dsb(); 590*010d6ae3SXiaoDong Huang mmio_write_32(PMUGRF_BASE + PMUGRF_PVTM_CON0, 591*010d6ae3SXiaoDong Huang BITS_WITH_WMASK(1, 0x1, pgrf_pvtm_en)); 592*010d6ae3SXiaoDong Huang dsb(); 593*010d6ae3SXiaoDong Huang mmio_write_32(PMUGRF_BASE + PMUGRF_PVTM_CON1, PVTM_CALC_CNT); 594*010d6ae3SXiaoDong Huang dsb(); 595*010d6ae3SXiaoDong Huang 596*010d6ae3SXiaoDong Huang mmio_write_32(PMUGRF_BASE + PMUGRF_PVTM_CON0, 597*010d6ae3SXiaoDong Huang BITS_WITH_WMASK(1, 0x1, pgrf_pvtm_st)); 598*010d6ae3SXiaoDong Huang 599*010d6ae3SXiaoDong Huang /* pmugrf_pvtm_st0 will be clear after PVTM start, 600*010d6ae3SXiaoDong Huang * which will cost about 6 cycles of pvtm at least. 601*010d6ae3SXiaoDong Huang * So we wait 30 cycles of pvtm for security. 602*010d6ae3SXiaoDong Huang */ 603*010d6ae3SXiaoDong Huang while (mmio_read_32(PMUGRF_BASE + PMUGRF_PVTM_ST1) < 30) 604*010d6ae3SXiaoDong Huang ; 605*010d6ae3SXiaoDong Huang 606*010d6ae3SXiaoDong Huang dsb(); 607*010d6ae3SXiaoDong Huang while (!(mmio_read_32(PMUGRF_BASE + PMUGRF_PVTM_ST0) & 0x1)) 608*010d6ae3SXiaoDong Huang ; 609*010d6ae3SXiaoDong Huang 610*010d6ae3SXiaoDong Huang pvtm_freq_khz = 611*010d6ae3SXiaoDong Huang (mmio_read_32(PMUGRF_BASE + PMUGRF_PVTM_ST1) * 24000 + 612*010d6ae3SXiaoDong Huang PVTM_CALC_CNT / 2) / PVTM_CALC_CNT; 613*010d6ae3SXiaoDong Huang pvtm_div = (pvtm_freq_khz + 16) / 32; 614*010d6ae3SXiaoDong Huang 615*010d6ae3SXiaoDong Huang /* pvtm_div = div_factor << 2 + 1, 616*010d6ae3SXiaoDong Huang * so div_factor = (pvtm_div - 1) >> 2. 617*010d6ae3SXiaoDong Huang * But the operation ">> 2" will clear the low bit of pvtm_div, 618*010d6ae3SXiaoDong Huang * so we don't have to do "- 1" for compasation 619*010d6ae3SXiaoDong Huang */ 620*010d6ae3SXiaoDong Huang pvtm_div = pvtm_div >> 2; 621*010d6ae3SXiaoDong Huang if (pvtm_div > 0x3f) 622*010d6ae3SXiaoDong Huang pvtm_div = 0x3f; 623*010d6ae3SXiaoDong Huang 624*010d6ae3SXiaoDong Huang mmio_write_32(PMUGRF_BASE + PMUGRF_PVTM_CON0, 625*010d6ae3SXiaoDong Huang BITS_WITH_WMASK(pvtm_div, 0x3f, pgrf_pvtm_div)); 626*010d6ae3SXiaoDong Huang 627*010d6ae3SXiaoDong Huang /* select pvtm as 32k source */ 628*010d6ae3SXiaoDong Huang mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKSELS_CON(0), 629*010d6ae3SXiaoDong Huang BITS_WITH_WMASK(1, 0x3, 14)); 630*010d6ae3SXiaoDong Huang } 631*010d6ae3SXiaoDong Huang 632*010d6ae3SXiaoDong Huang static void pvtm_32k_config_restore(void) 633*010d6ae3SXiaoDong Huang { 634*010d6ae3SXiaoDong Huang mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKSELS_CON(0), 635*010d6ae3SXiaoDong Huang ddr_data.pmu_cru_clksel_con0 | BITS_WMSK(0x3, 14)); 636*010d6ae3SXiaoDong Huang 637*010d6ae3SXiaoDong Huang mmio_write_32(PMUGRF_BASE + PMUGRF_PVTM_CON0, 638*010d6ae3SXiaoDong Huang WITH_16BITS_WMSK(ddr_data.pgrf_pvtm_con[0])); 639*010d6ae3SXiaoDong Huang mmio_write_32(PMUGRF_BASE + PMUGRF_PVTM_CON1, 640*010d6ae3SXiaoDong Huang ddr_data.pgrf_pvtm_con[1]); 641*010d6ae3SXiaoDong Huang } 642*010d6ae3SXiaoDong Huang 643*010d6ae3SXiaoDong Huang static void ddr_sleep_config(void) 644*010d6ae3SXiaoDong Huang { 645*010d6ae3SXiaoDong Huang /* disable ddr pd, sr */ 646*010d6ae3SXiaoDong Huang ddr_data.ddrc_pwrctrl = mmio_read_32(DDR_UPCTL_BASE + 0x30); 647*010d6ae3SXiaoDong Huang mmio_write_32(DDR_UPCTL_BASE + 0x30, BITS_WITH_WMASK(0x0, 0x3, 0)); 648*010d6ae3SXiaoDong Huang 649*010d6ae3SXiaoDong Huang /* disable ddr auto gt */ 650*010d6ae3SXiaoDong Huang ddr_data.ddrgrf_con1 = mmio_read_32(DDRGRF_BASE + 0x4); 651*010d6ae3SXiaoDong Huang mmio_write_32(DDRGRF_BASE + 0x4, BITS_WITH_WMASK(0x0, 0x1f, 0)); 652*010d6ae3SXiaoDong Huang 653*010d6ae3SXiaoDong Huang /* disable ddr standby */ 654*010d6ae3SXiaoDong Huang ddr_data.ddrstdby_con0 = mmio_read_32(DDR_STDBY_BASE + 0x0); 655*010d6ae3SXiaoDong Huang mmio_write_32(DDR_STDBY_BASE + 0x0, BITS_WITH_WMASK(0x0, 0x1, 0)); 656*010d6ae3SXiaoDong Huang while ((mmio_read_32(DDR_UPCTL_BASE + 0x4) & 0x7) != 1) 657*010d6ae3SXiaoDong Huang ; 658*010d6ae3SXiaoDong Huang 659*010d6ae3SXiaoDong Huang /* ddr pmu ctrl */ 660*010d6ae3SXiaoDong Huang ddr_data.ddrgrf_con0 = mmio_read_32(DDRGRF_BASE + 0x0); 661*010d6ae3SXiaoDong Huang mmio_write_32(DDRGRF_BASE + 0x0, BITS_WITH_WMASK(0x0, 0x1, 5)); 662*010d6ae3SXiaoDong Huang dsb(); 663*010d6ae3SXiaoDong Huang mmio_write_32(DDRGRF_BASE + 0x0, BITS_WITH_WMASK(0x1, 0x1, 4)); 664*010d6ae3SXiaoDong Huang 665*010d6ae3SXiaoDong Huang /* ddr ret sel */ 666*010d6ae3SXiaoDong Huang ddr_data.pmugrf_soc_con0 = 667*010d6ae3SXiaoDong Huang mmio_read_32(PMUGRF_BASE + PMUGRF_SOC_CON(0)); 668*010d6ae3SXiaoDong Huang mmio_write_32(PMUGRF_BASE + PMUGRF_SOC_CON(0), 669*010d6ae3SXiaoDong Huang BITS_WITH_WMASK(0x0, 0x1, 12)); 670*010d6ae3SXiaoDong Huang } 671*010d6ae3SXiaoDong Huang 672*010d6ae3SXiaoDong Huang static void ddr_sleep_config_restore(void) 673*010d6ae3SXiaoDong Huang { 674*010d6ae3SXiaoDong Huang /* restore ddr ret sel */ 675*010d6ae3SXiaoDong Huang mmio_write_32(PMUGRF_BASE + PMUGRF_SOC_CON(0), 676*010d6ae3SXiaoDong Huang ddr_data.pmugrf_soc_con0 | BITS_WMSK(0x1, 12)); 677*010d6ae3SXiaoDong Huang 678*010d6ae3SXiaoDong Huang /* restore ddr pmu ctrl */ 679*010d6ae3SXiaoDong Huang mmio_write_32(DDRGRF_BASE + 0x0, 680*010d6ae3SXiaoDong Huang ddr_data.ddrgrf_con0 | BITS_WMSK(0x1, 4)); 681*010d6ae3SXiaoDong Huang dsb(); 682*010d6ae3SXiaoDong Huang mmio_write_32(DDRGRF_BASE + 0x0, 683*010d6ae3SXiaoDong Huang ddr_data.ddrgrf_con0 | BITS_WMSK(0x1, 5)); 684*010d6ae3SXiaoDong Huang 685*010d6ae3SXiaoDong Huang /* restore ddr standby */ 686*010d6ae3SXiaoDong Huang mmio_write_32(DDR_STDBY_BASE + 0x0, 687*010d6ae3SXiaoDong Huang ddr_data.ddrstdby_con0 | BITS_WMSK(0x1, 0)); 688*010d6ae3SXiaoDong Huang 689*010d6ae3SXiaoDong Huang /* restore ddr auto gt */ 690*010d6ae3SXiaoDong Huang mmio_write_32(DDRGRF_BASE + 0x4, 691*010d6ae3SXiaoDong Huang ddr_data.ddrgrf_con1 | BITS_WMSK(0x1f, 0)); 692*010d6ae3SXiaoDong Huang 693*010d6ae3SXiaoDong Huang /* restore ddr pd, sr */ 694*010d6ae3SXiaoDong Huang mmio_write_32(DDR_UPCTL_BASE + 0x30, 695*010d6ae3SXiaoDong Huang ddr_data.ddrc_pwrctrl | BITS_WMSK(0x3, 0)); 696*010d6ae3SXiaoDong Huang } 697*010d6ae3SXiaoDong Huang 698*010d6ae3SXiaoDong Huang static void pmu_sleep_config(void) 699*010d6ae3SXiaoDong Huang { 700*010d6ae3SXiaoDong Huang uint32_t pwrmd_core_lo, pwrmd_core_hi, pwrmd_com_lo, pwrmd_com_hi; 701*010d6ae3SXiaoDong Huang uint32_t pmu_wkup_cfg2_lo; 702*010d6ae3SXiaoDong Huang uint32_t clk_freq_khz; 703*010d6ae3SXiaoDong Huang 704*010d6ae3SXiaoDong Huang /* save pmic_sleep iomux gpio0_a4 */ 705*010d6ae3SXiaoDong Huang ddr_data.pmic_slp_iomux = mmio_read_32(PMUGRF_BASE + GPIO0A_IOMUX); 706*010d6ae3SXiaoDong Huang 707*010d6ae3SXiaoDong Huang ddr_data.pmu_pwrmd_core_l = 708*010d6ae3SXiaoDong Huang mmio_read_32(PMU_BASE + PMU_PWRMODE_CORE_LO); 709*010d6ae3SXiaoDong Huang ddr_data.pmu_pwrmd_core_h = 710*010d6ae3SXiaoDong Huang mmio_read_32(PMU_BASE + PMU_PWRMODE_CORE_HI); 711*010d6ae3SXiaoDong Huang ddr_data.pmu_pwrmd_cmm_l = 712*010d6ae3SXiaoDong Huang mmio_read_32(PMU_BASE + PMU_PWRMODE_COMMON_CON_LO); 713*010d6ae3SXiaoDong Huang ddr_data.pmu_pwrmd_cmm_h = 714*010d6ae3SXiaoDong Huang mmio_read_32(PMU_BASE + PMU_PWRMODE_COMMON_CON_HI); 715*010d6ae3SXiaoDong Huang ddr_data.pmu_wkup_cfg2_l = mmio_read_32(PMU_BASE + PMU_WKUP_CFG2_LO); 716*010d6ae3SXiaoDong Huang 717*010d6ae3SXiaoDong Huang pwrmd_core_lo = BIT(pmu_global_int_dis) | 718*010d6ae3SXiaoDong Huang BIT(pmu_core_src_gt) | 719*010d6ae3SXiaoDong Huang BIT(pmu_cpu0_pd) | 720*010d6ae3SXiaoDong Huang BIT(pmu_clr_core) | 721*010d6ae3SXiaoDong Huang BIT(pmu_scu_pd) | 722*010d6ae3SXiaoDong Huang BIT(pmu_l2_idle) | 723*010d6ae3SXiaoDong Huang BIT(pmu_l2_flush) | 724*010d6ae3SXiaoDong Huang BIT(pmu_clr_bus2main) | 725*010d6ae3SXiaoDong Huang BIT(pmu_clr_peri2msch); 726*010d6ae3SXiaoDong Huang 727*010d6ae3SXiaoDong Huang pwrmd_core_hi = BIT(pmu_dpll_pd_en) | 728*010d6ae3SXiaoDong Huang BIT(pmu_apll_pd_en) | 729*010d6ae3SXiaoDong Huang BIT(pmu_cpll_pd_en) | 730*010d6ae3SXiaoDong Huang BIT(pmu_gpll_pd_en) | 731*010d6ae3SXiaoDong Huang BIT(pmu_npll_pd_en); 732*010d6ae3SXiaoDong Huang 733*010d6ae3SXiaoDong Huang pwrmd_com_lo = BIT(pmu_mode_en) | 734*010d6ae3SXiaoDong Huang BIT(pmu_pll_pd) | 735*010d6ae3SXiaoDong Huang BIT(pmu_pmu_use_if) | 736*010d6ae3SXiaoDong Huang BIT(pmu_alive_use_if) | 737*010d6ae3SXiaoDong Huang BIT(pmu_osc_dis) | 738*010d6ae3SXiaoDong Huang BIT(pmu_sref_enter) | 739*010d6ae3SXiaoDong Huang BIT(pmu_ddrc_gt) | 740*010d6ae3SXiaoDong Huang BIT(pmu_clr_pmu) | 741*010d6ae3SXiaoDong Huang BIT(pmu_clr_peri_pmu); 742*010d6ae3SXiaoDong Huang 743*010d6ae3SXiaoDong Huang pwrmd_com_hi = BIT(pmu_clr_bus) | 744*010d6ae3SXiaoDong Huang BIT(pmu_clr_msch) | 745*010d6ae3SXiaoDong Huang BIT(pmu_wakeup_begin_cfg); 746*010d6ae3SXiaoDong Huang 747*010d6ae3SXiaoDong Huang pmu_wkup_cfg2_lo = BIT(pmu_cluster_wkup_en) | 748*010d6ae3SXiaoDong Huang BIT(pmu_gpio_wkup_en) | 749*010d6ae3SXiaoDong Huang BIT(pmu_timer_wkup_en); 750*010d6ae3SXiaoDong Huang 751*010d6ae3SXiaoDong Huang /* set pmic_sleep iomux gpio0_a4 */ 752*010d6ae3SXiaoDong Huang mmio_write_32(PMUGRF_BASE + GPIO0A_IOMUX, 753*010d6ae3SXiaoDong Huang BITS_WITH_WMASK(1, 0x3, 8)); 754*010d6ae3SXiaoDong Huang 755*010d6ae3SXiaoDong Huang clk_freq_khz = 32; 756*010d6ae3SXiaoDong Huang 757*010d6ae3SXiaoDong Huang mmio_write_32(PMU_BASE + PMU_OSC_CNT_LO, 758*010d6ae3SXiaoDong Huang WITH_16BITS_WMSK(clk_freq_khz * 32 & 0xffff)); 759*010d6ae3SXiaoDong Huang mmio_write_32(PMU_BASE + PMU_OSC_CNT_HI, 760*010d6ae3SXiaoDong Huang WITH_16BITS_WMSK(clk_freq_khz * 32 >> 16)); 761*010d6ae3SXiaoDong Huang 762*010d6ae3SXiaoDong Huang mmio_write_32(PMU_BASE + PMU_STABLE_CNT_LO, 763*010d6ae3SXiaoDong Huang WITH_16BITS_WMSK(clk_freq_khz * 32 & 0xffff)); 764*010d6ae3SXiaoDong Huang mmio_write_32(PMU_BASE + PMU_STABLE_CNT_HI, 765*010d6ae3SXiaoDong Huang WITH_16BITS_WMSK(clk_freq_khz * 32 >> 16)); 766*010d6ae3SXiaoDong Huang 767*010d6ae3SXiaoDong Huang mmio_write_32(PMU_BASE + PMU_WAKEUP_RST_CLR_LO, 768*010d6ae3SXiaoDong Huang WITH_16BITS_WMSK(clk_freq_khz * 2 & 0xffff)); 769*010d6ae3SXiaoDong Huang mmio_write_32(PMU_BASE + PMU_WAKEUP_RST_CLR_HI, 770*010d6ae3SXiaoDong Huang WITH_16BITS_WMSK(clk_freq_khz * 2 >> 16)); 771*010d6ae3SXiaoDong Huang 772*010d6ae3SXiaoDong Huang /* Pmu's clk has switched to 24M back When pmu FSM counts 773*010d6ae3SXiaoDong Huang * the follow counters, so we should use 24M to calculate 774*010d6ae3SXiaoDong Huang * these counters. 775*010d6ae3SXiaoDong Huang */ 776*010d6ae3SXiaoDong Huang mmio_write_32(PMU_BASE + PMU_SCU_PWRDN_CNT_LO, 777*010d6ae3SXiaoDong Huang WITH_16BITS_WMSK(24000 * 2 & 0xffff)); 778*010d6ae3SXiaoDong Huang mmio_write_32(PMU_BASE + PMU_SCU_PWRDN_CNT_HI, 779*010d6ae3SXiaoDong Huang WITH_16BITS_WMSK(24000 * 2 >> 16)); 780*010d6ae3SXiaoDong Huang 781*010d6ae3SXiaoDong Huang mmio_write_32(PMU_BASE + PMU_SCU_PWRUP_CNT_LO, 782*010d6ae3SXiaoDong Huang WITH_16BITS_WMSK(24000 * 2 & 0xffff)); 783*010d6ae3SXiaoDong Huang mmio_write_32(PMU_BASE + PMU_SCU_PWRUP_CNT_HI, 784*010d6ae3SXiaoDong Huang WITH_16BITS_WMSK(24000 * 2 >> 16)); 785*010d6ae3SXiaoDong Huang 786*010d6ae3SXiaoDong Huang mmio_write_32(PMU_BASE + PMU_PLLLOCK_CNT_LO, 787*010d6ae3SXiaoDong Huang WITH_16BITS_WMSK(24000 * 5 & 0xffff)); 788*010d6ae3SXiaoDong Huang mmio_write_32(PMU_BASE + PMU_PLLLOCK_CNT_HI, 789*010d6ae3SXiaoDong Huang WITH_16BITS_WMSK(24000 * 5 >> 16)); 790*010d6ae3SXiaoDong Huang 791*010d6ae3SXiaoDong Huang mmio_write_32(PMU_BASE + PMU_PLLRST_CNT_LO, 792*010d6ae3SXiaoDong Huang WITH_16BITS_WMSK(24000 * 2 & 0xffff)); 793*010d6ae3SXiaoDong Huang mmio_write_32(PMU_BASE + PMU_PLLRST_CNT_HI, 794*010d6ae3SXiaoDong Huang WITH_16BITS_WMSK(24000 * 2 >> 16)); 795*010d6ae3SXiaoDong Huang 796*010d6ae3SXiaoDong Huang /* Config pmu power mode and pmu wakeup source */ 797*010d6ae3SXiaoDong Huang mmio_write_32(PMU_BASE + PMU_PWRMODE_CORE_LO, 798*010d6ae3SXiaoDong Huang WITH_16BITS_WMSK(pwrmd_core_lo)); 799*010d6ae3SXiaoDong Huang mmio_write_32(PMU_BASE + PMU_PWRMODE_CORE_HI, 800*010d6ae3SXiaoDong Huang WITH_16BITS_WMSK(pwrmd_core_hi)); 801*010d6ae3SXiaoDong Huang 802*010d6ae3SXiaoDong Huang mmio_write_32(PMU_BASE + PMU_PWRMODE_COMMON_CON_LO, 803*010d6ae3SXiaoDong Huang WITH_16BITS_WMSK(pwrmd_com_lo)); 804*010d6ae3SXiaoDong Huang mmio_write_32(PMU_BASE + PMU_PWRMODE_COMMON_CON_HI, 805*010d6ae3SXiaoDong Huang WITH_16BITS_WMSK(pwrmd_com_hi)); 806*010d6ae3SXiaoDong Huang 807*010d6ae3SXiaoDong Huang mmio_write_32(PMU_BASE + PMU_WKUP_CFG2_LO, 808*010d6ae3SXiaoDong Huang WITH_16BITS_WMSK(pmu_wkup_cfg2_lo)); 809*010d6ae3SXiaoDong Huang } 810*010d6ae3SXiaoDong Huang 811*010d6ae3SXiaoDong Huang static void pmu_sleep_restore(void) 812*010d6ae3SXiaoDong Huang { 813*010d6ae3SXiaoDong Huang mmio_write_32(PMU_BASE + PMU_PWRMODE_CORE_LO, 814*010d6ae3SXiaoDong Huang WITH_16BITS_WMSK(ddr_data.pmu_pwrmd_core_l)); 815*010d6ae3SXiaoDong Huang mmio_write_32(PMU_BASE + PMU_PWRMODE_CORE_HI, 816*010d6ae3SXiaoDong Huang WITH_16BITS_WMSK(ddr_data.pmu_pwrmd_core_h)); 817*010d6ae3SXiaoDong Huang mmio_write_32(PMU_BASE + PMU_PWRMODE_COMMON_CON_LO, 818*010d6ae3SXiaoDong Huang WITH_16BITS_WMSK(ddr_data.pmu_pwrmd_cmm_l)); 819*010d6ae3SXiaoDong Huang mmio_write_32(PMU_BASE + PMU_PWRMODE_COMMON_CON_HI, 820*010d6ae3SXiaoDong Huang WITH_16BITS_WMSK(ddr_data.pmu_pwrmd_cmm_h)); 821*010d6ae3SXiaoDong Huang mmio_write_32(PMU_BASE + PMU_WKUP_CFG2_LO, 822*010d6ae3SXiaoDong Huang WITH_16BITS_WMSK(ddr_data.pmu_wkup_cfg2_l)); 823*010d6ae3SXiaoDong Huang 824*010d6ae3SXiaoDong Huang /* restore pmic_sleep iomux */ 825*010d6ae3SXiaoDong Huang mmio_write_32(PMUGRF_BASE + GPIO0A_IOMUX, 826*010d6ae3SXiaoDong Huang WITH_16BITS_WMSK(ddr_data.pmic_slp_iomux)); 827*010d6ae3SXiaoDong Huang } 828*010d6ae3SXiaoDong Huang 829*010d6ae3SXiaoDong Huang static void soc_sleep_config(void) 830*010d6ae3SXiaoDong Huang { 831*010d6ae3SXiaoDong Huang ddr_data.gpio0c_iomux = mmio_read_32(PMUGRF_BASE + GPIO0C_IOMUX); 832*010d6ae3SXiaoDong Huang 833*010d6ae3SXiaoDong Huang pmu_sleep_config(); 834*010d6ae3SXiaoDong Huang 835*010d6ae3SXiaoDong Huang ddr_sleep_config(); 836*010d6ae3SXiaoDong Huang 837*010d6ae3SXiaoDong Huang pvtm_32k_config(); 838*010d6ae3SXiaoDong Huang } 839*010d6ae3SXiaoDong Huang 840*010d6ae3SXiaoDong Huang static void soc_sleep_restore(void) 841*010d6ae3SXiaoDong Huang { 842*010d6ae3SXiaoDong Huang secure_timer_init(); 843*010d6ae3SXiaoDong Huang 844*010d6ae3SXiaoDong Huang pvtm_32k_config_restore(); 845*010d6ae3SXiaoDong Huang 846*010d6ae3SXiaoDong Huang ddr_sleep_config_restore(); 847*010d6ae3SXiaoDong Huang 848*010d6ae3SXiaoDong Huang pmu_sleep_restore(); 849*010d6ae3SXiaoDong Huang 850*010d6ae3SXiaoDong Huang mmio_write_32(PMUGRF_BASE + GPIO0C_IOMUX, 851*010d6ae3SXiaoDong Huang WITH_16BITS_WMSK(ddr_data.gpio0c_iomux)); 852*010d6ae3SXiaoDong Huang } 853*010d6ae3SXiaoDong Huang 854*010d6ae3SXiaoDong Huang static inline void pm_pll_wait_lock(uint32_t pll_base, uint32_t pll_id) 855*010d6ae3SXiaoDong Huang { 856*010d6ae3SXiaoDong Huang uint32_t delay = PLL_LOCKED_TIMEOUT; 857*010d6ae3SXiaoDong Huang 858*010d6ae3SXiaoDong Huang while (delay > 0) { 859*010d6ae3SXiaoDong Huang if (mmio_read_32(pll_base + PLL_CON(1)) & 860*010d6ae3SXiaoDong Huang PLL_LOCK_MSK) 861*010d6ae3SXiaoDong Huang break; 862*010d6ae3SXiaoDong Huang delay--; 863*010d6ae3SXiaoDong Huang } 864*010d6ae3SXiaoDong Huang 865*010d6ae3SXiaoDong Huang if (delay == 0) 866*010d6ae3SXiaoDong Huang ERROR("Can't wait pll:%d lock\n", pll_id); 867*010d6ae3SXiaoDong Huang } 868*010d6ae3SXiaoDong Huang 869*010d6ae3SXiaoDong Huang static inline void pll_pwr_ctr(uint32_t pll_base, uint32_t pll_id, uint32_t pd) 870*010d6ae3SXiaoDong Huang { 871*010d6ae3SXiaoDong Huang mmio_write_32(pll_base + PLL_CON(1), 872*010d6ae3SXiaoDong Huang BITS_WITH_WMASK(1, 1, 15)); 873*010d6ae3SXiaoDong Huang if (pd) 874*010d6ae3SXiaoDong Huang mmio_write_32(pll_base + PLL_CON(1), 875*010d6ae3SXiaoDong Huang BITS_WITH_WMASK(1, 1, 14)); 876*010d6ae3SXiaoDong Huang else 877*010d6ae3SXiaoDong Huang mmio_write_32(pll_base + PLL_CON(1), 878*010d6ae3SXiaoDong Huang BITS_WITH_WMASK(0, 1, 14)); 879*010d6ae3SXiaoDong Huang } 880*010d6ae3SXiaoDong Huang 881*010d6ae3SXiaoDong Huang static inline void pll_set_mode(uint32_t pll_id, uint32_t mode) 882*010d6ae3SXiaoDong Huang { 883*010d6ae3SXiaoDong Huang uint32_t val = BITS_WITH_WMASK(mode, 0x3, PLL_MODE_SHIFT(pll_id)); 884*010d6ae3SXiaoDong Huang 885*010d6ae3SXiaoDong Huang if (pll_id != GPLL_ID) 886*010d6ae3SXiaoDong Huang mmio_write_32(CRU_BASE + CRU_MODE, val); 887*010d6ae3SXiaoDong Huang else 888*010d6ae3SXiaoDong Huang mmio_write_32(PMUCRU_BASE + CRU_PMU_MODE, 889*010d6ae3SXiaoDong Huang BITS_WITH_WMASK(mode, 0x3, 0)); 890*010d6ae3SXiaoDong Huang } 891*010d6ae3SXiaoDong Huang 892*010d6ae3SXiaoDong Huang static inline void pll_suspend(uint32_t pll_id) 893*010d6ae3SXiaoDong Huang { 894*010d6ae3SXiaoDong Huang int i; 895*010d6ae3SXiaoDong Huang uint32_t pll_base; 896*010d6ae3SXiaoDong Huang 897*010d6ae3SXiaoDong Huang if (pll_id != GPLL_ID) 898*010d6ae3SXiaoDong Huang pll_base = CRU_BASE + CRU_PLL_CONS(pll_id, 0); 899*010d6ae3SXiaoDong Huang else 900*010d6ae3SXiaoDong Huang pll_base = PMUCRU_BASE + CRU_PLL_CONS(0, 0); 901*010d6ae3SXiaoDong Huang 902*010d6ae3SXiaoDong Huang /* save pll con */ 903*010d6ae3SXiaoDong Huang for (i = 0; i < PLL_CON_CNT; i++) 904*010d6ae3SXiaoDong Huang ddr_data.cru_plls_con_save[pll_id][i] = 905*010d6ae3SXiaoDong Huang mmio_read_32(pll_base + PLL_CON(i)); 906*010d6ae3SXiaoDong Huang 907*010d6ae3SXiaoDong Huang /* slow mode */ 908*010d6ae3SXiaoDong Huang pll_set_mode(pll_id, SLOW_MODE); 909*010d6ae3SXiaoDong Huang } 910*010d6ae3SXiaoDong Huang 911*010d6ae3SXiaoDong Huang static inline void pll_resume(uint32_t pll_id) 912*010d6ae3SXiaoDong Huang { 913*010d6ae3SXiaoDong Huang uint32_t mode, pll_base; 914*010d6ae3SXiaoDong Huang 915*010d6ae3SXiaoDong Huang if (pll_id != GPLL_ID) { 916*010d6ae3SXiaoDong Huang pll_base = CRU_BASE + CRU_PLL_CONS(pll_id, 0); 917*010d6ae3SXiaoDong Huang mode = (ddr_data.cru_mode_save >> PLL_MODE_SHIFT(pll_id)) & 0x3; 918*010d6ae3SXiaoDong Huang } else { 919*010d6ae3SXiaoDong Huang pll_base = PMUCRU_BASE + CRU_PLL_CONS(0, 0); 920*010d6ae3SXiaoDong Huang mode = ddr_data.cru_pmu_mode_save & 0x3; 921*010d6ae3SXiaoDong Huang } 922*010d6ae3SXiaoDong Huang 923*010d6ae3SXiaoDong Huang /* if pll locked before suspend, we should wait atfer resume */ 924*010d6ae3SXiaoDong Huang if (ddr_data.cru_plls_con_save[pll_id][1] & PLL_LOCK_MSK) 925*010d6ae3SXiaoDong Huang pm_pll_wait_lock(pll_base, pll_id); 926*010d6ae3SXiaoDong Huang 927*010d6ae3SXiaoDong Huang pll_set_mode(pll_id, mode); 928*010d6ae3SXiaoDong Huang } 929*010d6ae3SXiaoDong Huang 930*010d6ae3SXiaoDong Huang static void pm_plls_suspend(void) 931*010d6ae3SXiaoDong Huang { 932*010d6ae3SXiaoDong Huang ddr_data.cru_mode_save = mmio_read_32(CRU_BASE + CRU_MODE); 933*010d6ae3SXiaoDong Huang ddr_data.cru_pmu_mode_save = mmio_read_32(PMUCRU_BASE + CRU_PMU_MODE); 934*010d6ae3SXiaoDong Huang ddr_data.clk_sel0 = mmio_read_32(CRU_BASE + CRU_CLKSELS_CON(0)); 935*010d6ae3SXiaoDong Huang 936*010d6ae3SXiaoDong Huang pll_suspend(GPLL_ID); 937*010d6ae3SXiaoDong Huang pll_suspend(NPLL_ID); 938*010d6ae3SXiaoDong Huang pll_suspend(CPLL_ID); 939*010d6ae3SXiaoDong Huang pll_suspend(APLL_ID); 940*010d6ae3SXiaoDong Huang 941*010d6ae3SXiaoDong Huang /* core */ 942*010d6ae3SXiaoDong Huang mmio_write_32(CRU_BASE + CRU_CLKSELS_CON(0), 943*010d6ae3SXiaoDong Huang BITS_WITH_WMASK(0, 0xf, 0)); 944*010d6ae3SXiaoDong Huang 945*010d6ae3SXiaoDong Huang /* pclk_dbg */ 946*010d6ae3SXiaoDong Huang mmio_write_32(CRU_BASE + CRU_CLKSELS_CON(0), 947*010d6ae3SXiaoDong Huang BITS_WITH_WMASK(0, 0xf, 8)); 948*010d6ae3SXiaoDong Huang } 949*010d6ae3SXiaoDong Huang 950*010d6ae3SXiaoDong Huang static void pm_plls_resume(void) 951*010d6ae3SXiaoDong Huang { 952*010d6ae3SXiaoDong Huang /* pclk_dbg */ 953*010d6ae3SXiaoDong Huang mmio_write_32(CRU_BASE + CRU_CLKSELS_CON(0), 954*010d6ae3SXiaoDong Huang ddr_data.clk_sel0 | BITS_WMSK(0xf, 8)); 955*010d6ae3SXiaoDong Huang 956*010d6ae3SXiaoDong Huang /* core */ 957*010d6ae3SXiaoDong Huang mmio_write_32(CRU_BASE + CRU_CLKSELS_CON(0), 958*010d6ae3SXiaoDong Huang ddr_data.clk_sel0 | BITS_WMSK(0xf, 0)); 959*010d6ae3SXiaoDong Huang 960*010d6ae3SXiaoDong Huang pll_resume(APLL_ID); 961*010d6ae3SXiaoDong Huang pll_resume(CPLL_ID); 962*010d6ae3SXiaoDong Huang pll_resume(NPLL_ID); 963*010d6ae3SXiaoDong Huang pll_resume(GPLL_ID); 964*010d6ae3SXiaoDong Huang } 965*010d6ae3SXiaoDong Huang 966*010d6ae3SXiaoDong Huang int rockchip_soc_sys_pwr_dm_suspend(void) 967*010d6ae3SXiaoDong Huang { 968*010d6ae3SXiaoDong Huang pmu_power_domains_suspend(); 969*010d6ae3SXiaoDong Huang 970*010d6ae3SXiaoDong Huang clk_gate_suspend(); 971*010d6ae3SXiaoDong Huang 972*010d6ae3SXiaoDong Huang soc_sleep_config(); 973*010d6ae3SXiaoDong Huang 974*010d6ae3SXiaoDong Huang pm_plls_suspend(); 975*010d6ae3SXiaoDong Huang 976*010d6ae3SXiaoDong Huang psram_boot_cfg->pm_flag &= ~PM_WARM_BOOT_BIT; 977*010d6ae3SXiaoDong Huang 978*010d6ae3SXiaoDong Huang return 0; 979*010d6ae3SXiaoDong Huang } 980*010d6ae3SXiaoDong Huang 981*010d6ae3SXiaoDong Huang int rockchip_soc_sys_pwr_dm_resume(void) 982*010d6ae3SXiaoDong Huang { 983*010d6ae3SXiaoDong Huang psram_boot_cfg->pm_flag |= PM_WARM_BOOT_BIT; 984*010d6ae3SXiaoDong Huang 985*010d6ae3SXiaoDong Huang pm_plls_resume(); 986*010d6ae3SXiaoDong Huang 987*010d6ae3SXiaoDong Huang soc_sleep_restore(); 988*010d6ae3SXiaoDong Huang 989*010d6ae3SXiaoDong Huang clk_gate_resume(); 990*010d6ae3SXiaoDong Huang 991*010d6ae3SXiaoDong Huang pmu_power_domains_resume(); 992*010d6ae3SXiaoDong Huang 993*010d6ae3SXiaoDong Huang plat_rockchip_gic_cpuif_enable(); 994*010d6ae3SXiaoDong Huang 995*010d6ae3SXiaoDong Huang return 0; 996*010d6ae3SXiaoDong Huang } 997*010d6ae3SXiaoDong Huang 998*010d6ae3SXiaoDong Huang void __dead2 rockchip_soc_soft_reset(void) 999*010d6ae3SXiaoDong Huang { 1000*010d6ae3SXiaoDong Huang pll_set_mode(GPLL_ID, SLOW_MODE); 1001*010d6ae3SXiaoDong Huang pll_set_mode(CPLL_ID, SLOW_MODE); 1002*010d6ae3SXiaoDong Huang pll_set_mode(NPLL_ID, SLOW_MODE); 1003*010d6ae3SXiaoDong Huang pll_set_mode(APLL_ID, SLOW_MODE); 1004*010d6ae3SXiaoDong Huang dsb(); 1005*010d6ae3SXiaoDong Huang 1006*010d6ae3SXiaoDong Huang mmio_write_32(CRU_BASE + CRU_GLB_SRST_FST, CRU_GLB_SRST_FST_VALUE); 1007*010d6ae3SXiaoDong Huang dsb(); 1008*010d6ae3SXiaoDong Huang 1009*010d6ae3SXiaoDong Huang /* 1010*010d6ae3SXiaoDong Huang * Maybe the HW needs some times to reset the system, 1011*010d6ae3SXiaoDong Huang * so we do not hope the core to execute valid codes. 1012*010d6ae3SXiaoDong Huang */ 1013*010d6ae3SXiaoDong Huang psci_power_down_wfi(); 1014*010d6ae3SXiaoDong Huang } 1015*010d6ae3SXiaoDong Huang 1016*010d6ae3SXiaoDong Huang void __dead2 rockchip_soc_system_off(void) 1017*010d6ae3SXiaoDong Huang { 1018*010d6ae3SXiaoDong Huang uint32_t val; 1019*010d6ae3SXiaoDong Huang 1020*010d6ae3SXiaoDong Huang /* set pmic_sleep pin(gpio0_a4) to gpio mode */ 1021*010d6ae3SXiaoDong Huang mmio_write_32(PMUGRF_BASE + GPIO0A_IOMUX, BITS_WITH_WMASK(0, 0x3, 8)); 1022*010d6ae3SXiaoDong Huang 1023*010d6ae3SXiaoDong Huang /* config output */ 1024*010d6ae3SXiaoDong Huang val = mmio_read_32(GPIO0_BASE + SWPORTA_DDR); 1025*010d6ae3SXiaoDong Huang val |= BIT(4); 1026*010d6ae3SXiaoDong Huang mmio_write_32(GPIO0_BASE + SWPORTA_DDR, val); 1027*010d6ae3SXiaoDong Huang 1028*010d6ae3SXiaoDong Huang /* config output high level */ 1029*010d6ae3SXiaoDong Huang val = mmio_read_32(GPIO0_BASE); 1030*010d6ae3SXiaoDong Huang val |= BIT(4); 1031*010d6ae3SXiaoDong Huang mmio_write_32(GPIO0_BASE, val); 1032*010d6ae3SXiaoDong Huang dsb(); 1033*010d6ae3SXiaoDong Huang 1034*010d6ae3SXiaoDong Huang /* 1035*010d6ae3SXiaoDong Huang * Maybe the HW needs some times to reset the system, 1036*010d6ae3SXiaoDong Huang * so we do not hope the core to execute valid codes. 1037*010d6ae3SXiaoDong Huang */ 1038*010d6ae3SXiaoDong Huang psci_power_down_wfi(); 1039*010d6ae3SXiaoDong Huang } 1040*010d6ae3SXiaoDong Huang 1041*010d6ae3SXiaoDong Huang void rockchip_plat_mmu_el3(void) 1042*010d6ae3SXiaoDong Huang { 1043*010d6ae3SXiaoDong Huang /* TODO: support the el3 for px30 SoCs */ 1044*010d6ae3SXiaoDong Huang } 1045*010d6ae3SXiaoDong Huang 1046*010d6ae3SXiaoDong Huang void plat_rockchip_pmu_init(void) 1047*010d6ae3SXiaoDong Huang { 1048*010d6ae3SXiaoDong Huang uint32_t cpu; 1049*010d6ae3SXiaoDong Huang 1050*010d6ae3SXiaoDong Huang rockchip_pd_lock_init(); 1051*010d6ae3SXiaoDong Huang 1052*010d6ae3SXiaoDong Huang for (cpu = 0; cpu < PLATFORM_CORE_COUNT; cpu++) 1053*010d6ae3SXiaoDong Huang cpuson_flags[cpu] = 0; 1054*010d6ae3SXiaoDong Huang 1055*010d6ae3SXiaoDong Huang psram_boot_cfg->ddr_func = (uint64_t)0; 1056*010d6ae3SXiaoDong Huang psram_boot_cfg->ddr_data = (uint64_t)0; 1057*010d6ae3SXiaoDong Huang psram_boot_cfg->sp = PSRAM_SP_TOP; 1058*010d6ae3SXiaoDong Huang psram_boot_cfg->ddr_flag = 0x0; 1059*010d6ae3SXiaoDong Huang psram_boot_cfg->boot_mpidr = read_mpidr_el1() & 0xffff; 1060*010d6ae3SXiaoDong Huang psram_boot_cfg->pm_flag = PM_WARM_BOOT_BIT; 1061*010d6ae3SXiaoDong Huang 1062*010d6ae3SXiaoDong Huang nonboot_cpus_off(); 1063*010d6ae3SXiaoDong Huang 1064*010d6ae3SXiaoDong Huang /* Remap pmu_sram's base address to boot address */ 1065*010d6ae3SXiaoDong Huang mmio_write_32(PMUSGRF_BASE + PMUSGRF_SOC_CON(0), 1066*010d6ae3SXiaoDong Huang BITS_WITH_WMASK(1, 0x1, 13)); 1067*010d6ae3SXiaoDong Huang 1068*010d6ae3SXiaoDong Huang INFO("%s: pd status %x\n", 1069*010d6ae3SXiaoDong Huang __func__, mmio_read_32(PMU_BASE + PMU_PWRDN_ST)); 1070*010d6ae3SXiaoDong Huang } 1071