1*036935a8SXiaoDong Huang // SPDX-License-Identifier: BSD-3-Clause 2*036935a8SXiaoDong Huang /* 3*036935a8SXiaoDong Huang * Copyright (c) 2025, Rockchip Electronics Co., Ltd. 4*036935a8SXiaoDong Huang */ 5*036935a8SXiaoDong Huang 6*036935a8SXiaoDong Huang #include <assert.h> 7*036935a8SXiaoDong Huang #include <errno.h> 8*036935a8SXiaoDong Huang 9*036935a8SXiaoDong Huang #include <arch_helpers.h> 10*036935a8SXiaoDong Huang #include <bl31/bl31.h> 11*036935a8SXiaoDong Huang #include <common/debug.h> 12*036935a8SXiaoDong Huang #include <drivers/console.h> 13*036935a8SXiaoDong Huang #include <drivers/delay_timer.h> 14*036935a8SXiaoDong Huang #include <lib/mmio.h> 15*036935a8SXiaoDong Huang #include <plat/common/platform.h> 16*036935a8SXiaoDong Huang #include <platform_def.h> 17*036935a8SXiaoDong Huang #include <pmu.h> 18*036935a8SXiaoDong Huang 19*036935a8SXiaoDong Huang #include <cpus_on_fixed_addr.h> 20*036935a8SXiaoDong Huang #include <dmc_rk3576.h> 21*036935a8SXiaoDong Huang #include <plat_pm_helpers.h> 22*036935a8SXiaoDong Huang #include <plat_private.h> 23*036935a8SXiaoDong Huang #include <pm_pd_regs.h> 24*036935a8SXiaoDong Huang #include <secure.h> 25*036935a8SXiaoDong Huang #include <soc.h> 26*036935a8SXiaoDong Huang 27*036935a8SXiaoDong Huang static struct psram_data_t *psram_sleep_cfg = 28*036935a8SXiaoDong Huang (struct psram_data_t *)&sys_sleep_flag_sram; 29*036935a8SXiaoDong Huang 30*036935a8SXiaoDong Huang struct rk3576_sleep_ddr_data { 31*036935a8SXiaoDong Huang uint32_t cru_mode_con, secure_cru_mode; 32*036935a8SXiaoDong Huang uint32_t gpio0a_iomux_l, gpio0a_iomux_h, gpio0b_iomux_l; 33*036935a8SXiaoDong Huang uint32_t pmu2_bisr_glb_con; 34*036935a8SXiaoDong Huang uint32_t pmu2_c0_ack_sel_con0, pmu2_c1_ack_sel_con0, pmu2_c2_ack_sel_con0; 35*036935a8SXiaoDong Huang uint32_t pmu2_fast_pwr_con, pmu2_pwrgt_sft_con0; 36*036935a8SXiaoDong Huang uint32_t pmu0grf_soc_con0, pmu0grf_soc_con1, pmu0grf_soc_con5; 37*036935a8SXiaoDong Huang uint32_t pmu_pd_st, bus_idle_st; 38*036935a8SXiaoDong Huang uint32_t sys_sgrf_soc_con0; 39*036935a8SXiaoDong Huang uint32_t ddrgrf_cha_con2, ddrgrf_chb_con2; 40*036935a8SXiaoDong Huang }; 41*036935a8SXiaoDong Huang 42*036935a8SXiaoDong Huang static struct rk3576_sleep_ddr_data ddr_data; 43*036935a8SXiaoDong Huang 44*036935a8SXiaoDong Huang void rockchip_plat_mmu_el3(void) 45*036935a8SXiaoDong Huang { 46*036935a8SXiaoDong Huang #ifdef PLAT_EXTRA_LD_SCRIPT 47*036935a8SXiaoDong Huang size_t sram_size; 48*036935a8SXiaoDong Huang 49*036935a8SXiaoDong Huang sram_size = (char *)&__bl31_pmusram_text_end - 50*036935a8SXiaoDong Huang (char *)PMUSRAM_BASE; 51*036935a8SXiaoDong Huang mmap_add_region(PMUSRAM_BASE, PMUSRAM_BASE, 52*036935a8SXiaoDong Huang sram_size, MT_MEMORY | MT_RO | MT_SECURE); 53*036935a8SXiaoDong Huang 54*036935a8SXiaoDong Huang sram_size = (char *)&__bl31_pmusram_data_end - 55*036935a8SXiaoDong Huang (char *)&__bl31_pmusram_data_start; 56*036935a8SXiaoDong Huang mmap_add_region((unsigned long)&__bl31_pmusram_data_start, 57*036935a8SXiaoDong Huang (unsigned long)&__bl31_pmusram_data_start, 58*036935a8SXiaoDong Huang sram_size, MT_DEVICE | MT_RW | MT_SECURE); 59*036935a8SXiaoDong Huang #endif 60*036935a8SXiaoDong Huang } 61*036935a8SXiaoDong Huang 62*036935a8SXiaoDong Huang static int check_cpu_wfie(uint32_t cpu) 63*036935a8SXiaoDong Huang { 64*036935a8SXiaoDong Huang uint32_t loop = 0; 65*036935a8SXiaoDong Huang 66*036935a8SXiaoDong Huang while ((mmio_read_32(SYS_GRF_BASE + SYSGRF_STATUS0) & BIT(cpu + 12)) == 0 && 67*036935a8SXiaoDong Huang (mmio_read_32(PMU_BASE + PMU2_CLUSTER_PWR_ST) & BIT(cpu)) == 0 && 68*036935a8SXiaoDong Huang (loop < WFEI_CHECK_LOOP)) { 69*036935a8SXiaoDong Huang udelay(1); 70*036935a8SXiaoDong Huang loop++; 71*036935a8SXiaoDong Huang } 72*036935a8SXiaoDong Huang 73*036935a8SXiaoDong Huang if (loop >= WFEI_CHECK_LOOP) { 74*036935a8SXiaoDong Huang WARN("%s: error, cpu%d (0x%x 0x%x)!\n", __func__, cpu, 75*036935a8SXiaoDong Huang mmio_read_32(SYS_GRF_BASE + SYSGRF_STATUS0), 76*036935a8SXiaoDong Huang mmio_read_32(PMU_BASE + PMU2_CLUSTER_PWR_ST)); 77*036935a8SXiaoDong Huang return -EINVAL; 78*036935a8SXiaoDong Huang } 79*036935a8SXiaoDong Huang 80*036935a8SXiaoDong Huang return 0; 81*036935a8SXiaoDong Huang } 82*036935a8SXiaoDong Huang 83*036935a8SXiaoDong Huang static inline uint32_t cpu_power_domain_st(uint32_t cpu) 84*036935a8SXiaoDong Huang { 85*036935a8SXiaoDong Huang return !!(mmio_read_32(PMU_BASE + PMU2_CLUSTER_PWR_ST) & 86*036935a8SXiaoDong Huang BIT(cpu + 16)); 87*036935a8SXiaoDong Huang } 88*036935a8SXiaoDong Huang 89*036935a8SXiaoDong Huang static int cpu_power_domain_ctr(uint32_t cpu, uint32_t pd_state) 90*036935a8SXiaoDong Huang { 91*036935a8SXiaoDong Huang uint32_t loop = 0; 92*036935a8SXiaoDong Huang int ret = 0; 93*036935a8SXiaoDong Huang 94*036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_CPU_PWR_SFTCON(cpu), 95*036935a8SXiaoDong Huang BITS_WITH_WMASK(pd_state, 0x1, 0)); 96*036935a8SXiaoDong Huang 97*036935a8SXiaoDong Huang dsb(); 98*036935a8SXiaoDong Huang while ((cpu_power_domain_st(cpu) != pd_state) && (loop < PD_CTR_LOOP)) { 99*036935a8SXiaoDong Huang udelay(1); 100*036935a8SXiaoDong Huang loop++; 101*036935a8SXiaoDong Huang } 102*036935a8SXiaoDong Huang 103*036935a8SXiaoDong Huang if (cpu_power_domain_st(cpu) != pd_state) { 104*036935a8SXiaoDong Huang WARN("%s: %d, %d, error!\n", __func__, cpu, pd_state); 105*036935a8SXiaoDong Huang ret = -EINVAL; 106*036935a8SXiaoDong Huang } 107*036935a8SXiaoDong Huang 108*036935a8SXiaoDong Huang return ret; 109*036935a8SXiaoDong Huang } 110*036935a8SXiaoDong Huang 111*036935a8SXiaoDong Huang static inline uint32_t get_cpus_pwr_domain_cfg_info(uint32_t cpu_id) 112*036935a8SXiaoDong Huang { 113*036935a8SXiaoDong Huang uint32_t val; 114*036935a8SXiaoDong Huang 115*036935a8SXiaoDong Huang if ((mmio_read_32(PMU_BASE + PMU2_CPU_PWR_SFTCON(cpu_id)) & BIT(0)) != 0) 116*036935a8SXiaoDong Huang return core_pwr_pd; 117*036935a8SXiaoDong Huang 118*036935a8SXiaoDong Huang val = mmio_read_32(PMU_BASE + PMU2_CPU_AUTO_PWR_CON(cpu_id)); 119*036935a8SXiaoDong Huang if ((val & BIT(pmu_cpu_pm_en)) != 0) { 120*036935a8SXiaoDong Huang if ((val & BIT(core_pwr_wfi_int)) != 0) 121*036935a8SXiaoDong Huang return core_pwr_wfi_int; 122*036935a8SXiaoDong Huang else if ((val & BIT(pmu_cpu_pm_sft_wakeup_en)) != 0) 123*036935a8SXiaoDong Huang return core_pwr_wfi_reset; 124*036935a8SXiaoDong Huang else 125*036935a8SXiaoDong Huang return core_pwr_wfi; 126*036935a8SXiaoDong Huang } else { 127*036935a8SXiaoDong Huang return -1; 128*036935a8SXiaoDong Huang } 129*036935a8SXiaoDong Huang } 130*036935a8SXiaoDong Huang 131*036935a8SXiaoDong Huang static inline void set_cpus_pwr_domain_cfg_info(uint32_t cpu_id, uint32_t value) 132*036935a8SXiaoDong Huang { 133*036935a8SXiaoDong Huang } 134*036935a8SXiaoDong Huang 135*036935a8SXiaoDong Huang static int cpus_power_domain_on(uint32_t cpu_id) 136*036935a8SXiaoDong Huang { 137*036935a8SXiaoDong Huang uint32_t cfg_info; 138*036935a8SXiaoDong Huang /* 139*036935a8SXiaoDong Huang * There are two ways to powering on or off on core. 140*036935a8SXiaoDong Huang * 1) Control it power domain into on or off in PMU_PWRDN_CON reg 141*036935a8SXiaoDong Huang * 2) Enable the core power manage in PMU_CORE_PM_CON reg, 142*036935a8SXiaoDong Huang * then, if the core enter into wfi, it power domain will be 143*036935a8SXiaoDong Huang * powered off automatically. 144*036935a8SXiaoDong Huang */ 145*036935a8SXiaoDong Huang 146*036935a8SXiaoDong Huang cfg_info = get_cpus_pwr_domain_cfg_info(cpu_id); 147*036935a8SXiaoDong Huang 148*036935a8SXiaoDong Huang if (cfg_info == core_pwr_pd) { 149*036935a8SXiaoDong Huang /* disable core_pm cfg */ 150*036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_CPU_AUTO_PWR_CON(cpu_id), 151*036935a8SXiaoDong Huang BITS_WITH_WMASK(0, 0xf, 0)); 152*036935a8SXiaoDong Huang /* if the cores have be on, power off it firstly */ 153*036935a8SXiaoDong Huang if (cpu_power_domain_st(cpu_id) == pmu_pd_on) 154*036935a8SXiaoDong Huang cpu_power_domain_ctr(cpu_id, pmu_pd_off); 155*036935a8SXiaoDong Huang 156*036935a8SXiaoDong Huang cpu_power_domain_ctr(cpu_id, pmu_pd_on); 157*036935a8SXiaoDong Huang } else { 158*036935a8SXiaoDong Huang if (cpu_power_domain_st(cpu_id) == pmu_pd_on) { 159*036935a8SXiaoDong Huang WARN("%s: cpu%d is not in off,!\n", __func__, cpu_id); 160*036935a8SXiaoDong Huang return -EINVAL; 161*036935a8SXiaoDong Huang } 162*036935a8SXiaoDong Huang 163*036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_CPU_AUTO_PWR_CON(cpu_id), 164*036935a8SXiaoDong Huang BITS_WITH_WMASK(1, 0x1, pmu_cpu_pm_sft_wakeup_en)); 165*036935a8SXiaoDong Huang dsb(); 166*036935a8SXiaoDong Huang } 167*036935a8SXiaoDong Huang 168*036935a8SXiaoDong Huang return 0; 169*036935a8SXiaoDong Huang } 170*036935a8SXiaoDong Huang 171*036935a8SXiaoDong Huang static int cpus_power_domain_off(uint32_t cpu_id, uint32_t pd_cfg) 172*036935a8SXiaoDong Huang { 173*036935a8SXiaoDong Huang uint32_t core_pm_value; 174*036935a8SXiaoDong Huang 175*036935a8SXiaoDong Huang if (cpu_power_domain_st(cpu_id) == pmu_pd_off) 176*036935a8SXiaoDong Huang return 0; 177*036935a8SXiaoDong Huang 178*036935a8SXiaoDong Huang if (pd_cfg == core_pwr_pd) { 179*036935a8SXiaoDong Huang if (check_cpu_wfie(cpu_id)) 180*036935a8SXiaoDong Huang return -EINVAL; 181*036935a8SXiaoDong Huang 182*036935a8SXiaoDong Huang /* disable core_pm cfg */ 183*036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_CPU_AUTO_PWR_CON(cpu_id), 184*036935a8SXiaoDong Huang BITS_WITH_WMASK(0, 0xf, 0)); 185*036935a8SXiaoDong Huang 186*036935a8SXiaoDong Huang set_cpus_pwr_domain_cfg_info(cpu_id, pd_cfg); 187*036935a8SXiaoDong Huang cpu_power_domain_ctr(cpu_id, pmu_pd_off); 188*036935a8SXiaoDong Huang } else { 189*036935a8SXiaoDong Huang set_cpus_pwr_domain_cfg_info(cpu_id, pd_cfg); 190*036935a8SXiaoDong Huang 191*036935a8SXiaoDong Huang core_pm_value = BIT(pmu_cpu_pm_en) | BIT(pmu_cpu_pm_dis_int); 192*036935a8SXiaoDong Huang if (pd_cfg == core_pwr_wfi_int) 193*036935a8SXiaoDong Huang core_pm_value |= BIT(pmu_cpu_pm_int_wakeup_en); 194*036935a8SXiaoDong Huang else if (pd_cfg == core_pwr_wfi_reset) 195*036935a8SXiaoDong Huang core_pm_value |= BIT(pmu_cpu_pm_sft_wakeup_en); 196*036935a8SXiaoDong Huang 197*036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_CPU_AUTO_PWR_CON(cpu_id), 198*036935a8SXiaoDong Huang BITS_WITH_WMASK(core_pm_value, 0xf, 0)); 199*036935a8SXiaoDong Huang dsb(); 200*036935a8SXiaoDong Huang } 201*036935a8SXiaoDong Huang 202*036935a8SXiaoDong Huang return 0; 203*036935a8SXiaoDong Huang } 204*036935a8SXiaoDong Huang 205*036935a8SXiaoDong Huang int rockchip_soc_cores_pwr_dm_on(unsigned long mpidr, uint64_t entrypoint) 206*036935a8SXiaoDong Huang { 207*036935a8SXiaoDong Huang uint32_t cpu_id = plat_core_pos_by_mpidr(mpidr); 208*036935a8SXiaoDong Huang 209*036935a8SXiaoDong Huang assert(cpu_id < PLATFORM_CORE_COUNT); 210*036935a8SXiaoDong Huang assert(cpuson_flags[cpu_id] == 0); 211*036935a8SXiaoDong Huang cpuson_flags[cpu_id] = PMU_CPU_HOTPLUG; 212*036935a8SXiaoDong Huang cpuson_entry_point[cpu_id] = entrypoint; 213*036935a8SXiaoDong Huang dsb(); 214*036935a8SXiaoDong Huang 215*036935a8SXiaoDong Huang cpus_power_domain_on(cpu_id); 216*036935a8SXiaoDong Huang 217*036935a8SXiaoDong Huang return PSCI_E_SUCCESS; 218*036935a8SXiaoDong Huang } 219*036935a8SXiaoDong Huang 220*036935a8SXiaoDong Huang int rockchip_soc_cores_pwr_dm_off(void) 221*036935a8SXiaoDong Huang { 222*036935a8SXiaoDong Huang uint32_t cpu_id = plat_my_core_pos(); 223*036935a8SXiaoDong Huang 224*036935a8SXiaoDong Huang cpus_power_domain_off(cpu_id, core_pwr_wfi); 225*036935a8SXiaoDong Huang 226*036935a8SXiaoDong Huang return PSCI_E_SUCCESS; 227*036935a8SXiaoDong Huang } 228*036935a8SXiaoDong Huang 229*036935a8SXiaoDong Huang int rockchip_soc_cores_pwr_dm_on_finish(void) 230*036935a8SXiaoDong Huang { 231*036935a8SXiaoDong Huang uint32_t cpu_id = plat_my_core_pos(); 232*036935a8SXiaoDong Huang 233*036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_CPU_AUTO_PWR_CON(cpu_id), 234*036935a8SXiaoDong Huang BITS_WITH_WMASK(0, 0xf, 0)); 235*036935a8SXiaoDong Huang 236*036935a8SXiaoDong Huang return PSCI_E_SUCCESS; 237*036935a8SXiaoDong Huang } 238*036935a8SXiaoDong Huang 239*036935a8SXiaoDong Huang int rockchip_soc_cores_pwr_dm_suspend(void) 240*036935a8SXiaoDong Huang { 241*036935a8SXiaoDong Huang uint32_t cpu_id = plat_my_core_pos(); 242*036935a8SXiaoDong Huang 243*036935a8SXiaoDong Huang assert(cpu_id < PLATFORM_CORE_COUNT); 244*036935a8SXiaoDong Huang assert(cpuson_flags[cpu_id] == 0); 245*036935a8SXiaoDong Huang cpuson_flags[cpu_id] = PMU_CPU_AUTO_PWRDN; 246*036935a8SXiaoDong Huang cpuson_entry_point[cpu_id] = plat_get_sec_entrypoint(); 247*036935a8SXiaoDong Huang dsb(); 248*036935a8SXiaoDong Huang 249*036935a8SXiaoDong Huang cpus_power_domain_off(cpu_id, core_pwr_wfi_int); 250*036935a8SXiaoDong Huang 251*036935a8SXiaoDong Huang return PSCI_E_SUCCESS; 252*036935a8SXiaoDong Huang } 253*036935a8SXiaoDong Huang 254*036935a8SXiaoDong Huang int rockchip_soc_cores_pwr_dm_resume(void) 255*036935a8SXiaoDong Huang { 256*036935a8SXiaoDong Huang uint32_t cpu_id = plat_my_core_pos(); 257*036935a8SXiaoDong Huang 258*036935a8SXiaoDong Huang /* Disable core_pm */ 259*036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_CPU_AUTO_PWR_CON(cpu_id), 260*036935a8SXiaoDong Huang BITS_WITH_WMASK(0, 0xf, 0)); 261*036935a8SXiaoDong Huang 262*036935a8SXiaoDong Huang return PSCI_E_SUCCESS; 263*036935a8SXiaoDong Huang } 264*036935a8SXiaoDong Huang 265*036935a8SXiaoDong Huang void nonboot_cpus_off(void) 266*036935a8SXiaoDong Huang { 267*036935a8SXiaoDong Huang uint32_t boot_cpu, cpu; 268*036935a8SXiaoDong Huang 269*036935a8SXiaoDong Huang boot_cpu = plat_my_core_pos(); 270*036935a8SXiaoDong Huang 271*036935a8SXiaoDong Huang /* turn off noboot cpus */ 272*036935a8SXiaoDong Huang for (cpu = 0; cpu < PLATFORM_CORE_COUNT; cpu++) { 273*036935a8SXiaoDong Huang if (cpu == boot_cpu) 274*036935a8SXiaoDong Huang continue; 275*036935a8SXiaoDong Huang 276*036935a8SXiaoDong Huang cpus_power_domain_off(cpu, core_pwr_pd); 277*036935a8SXiaoDong Huang } 278*036935a8SXiaoDong Huang } 279*036935a8SXiaoDong Huang 280*036935a8SXiaoDong Huang static __pmusramfunc void ddr_resume(void) 281*036935a8SXiaoDong Huang { 282*036935a8SXiaoDong Huang uint32_t key_upd_msk = 283*036935a8SXiaoDong Huang mmio_read_32(PMU_BASE + PMU2_PWR_GATE_ST) & BIT(pmu_pd_vop) ? 0x3 : 0x7; 284*036935a8SXiaoDong Huang 285*036935a8SXiaoDong Huang /* hptimer is 24M here */ 286*036935a8SXiaoDong Huang write_cntfrq_el0(24000000); 287*036935a8SXiaoDong Huang 288*036935a8SXiaoDong Huang /* release cpu1~cpu7 to make pmu1_fsm exit */ 289*036935a8SXiaoDong Huang mmio_write_32(CCI_GRF_BASE + CCIGRF_CON(4), 0xffffffff); 290*036935a8SXiaoDong Huang mmio_write_32(LITCORE_GRF_BASE + COREGRF_CPU_CON(1), 291*036935a8SXiaoDong Huang BITS_WITH_WMASK(0x77, 0xff, 4)); 292*036935a8SXiaoDong Huang 293*036935a8SXiaoDong Huang /* wait pmu1 fsm over */ 294*036935a8SXiaoDong Huang while ((mmio_read_32(PMU_BASE + PMU1_PWR_FSM) & 0xf) != 0) 295*036935a8SXiaoDong Huang ; 296*036935a8SXiaoDong Huang 297*036935a8SXiaoDong Huang /* SOC_CON19.vop/center/cci_ddr_hash_key_update_en */ 298*036935a8SXiaoDong Huang mmio_write_32(SYS_SGRF_BASE + SYSSGRF_SOC_CON(19), 0x00070000); 299*036935a8SXiaoDong Huang dsb(); 300*036935a8SXiaoDong Huang 301*036935a8SXiaoDong Huang /* SOC_CON19.vop/center/cci_ddr_hash_key_update_en */ 302*036935a8SXiaoDong Huang mmio_write_32(SYS_SGRF_BASE + SYSSGRF_SOC_CON(19), 0x00070000 | key_upd_msk); 303*036935a8SXiaoDong Huang 304*036935a8SXiaoDong Huang /* SOC_STATUS.center/cci_ddr_hash_key_shift_ready */ 305*036935a8SXiaoDong Huang while (((mmio_read_32(SYS_SGRF_BASE + SYSSGRF_SOC_STATUS) >> 12) & key_upd_msk) != key_upd_msk) 306*036935a8SXiaoDong Huang ; 307*036935a8SXiaoDong Huang 308*036935a8SXiaoDong Huang /* CCI_BASE.ctrl_override_reg Attr:W1C addrmap strobe */ 309*036935a8SXiaoDong Huang mmio_setbits_32(CCI_BASE + 0x0, 0x1 << 29); 310*036935a8SXiaoDong Huang 311*036935a8SXiaoDong Huang /* SOC_CON19.vop/center/cci_ddr_hash_key_auto_update_en */ 312*036935a8SXiaoDong Huang mmio_write_32(SYS_SGRF_BASE + SYSSGRF_SOC_CON(19), 0x00700070); 313*036935a8SXiaoDong Huang } 314*036935a8SXiaoDong Huang 315*036935a8SXiaoDong Huang static uint32_t clk_save[CRU_CLKGATE_CON_CNT + PHP_CRU_CLKGATE_CON_CNT + 316*036935a8SXiaoDong Huang SECURE_CRU_CLKGATE_CON_CNT + SECURE_SCRU_CLKGATE_CON_CNT + 317*036935a8SXiaoDong Huang PMU1CRU_CLKGATE_CON_CNT + PMU1SCRU_CLKGATE_CON_CNT]; 318*036935a8SXiaoDong Huang 319*036935a8SXiaoDong Huang void clk_gate_con_disable(void) 320*036935a8SXiaoDong Huang { 321*036935a8SXiaoDong Huang int i; 322*036935a8SXiaoDong Huang 323*036935a8SXiaoDong Huang for (i = 0; i < CRU_CLKGATE_CON_CNT; i++) { 324*036935a8SXiaoDong Huang /* Don't open wdt0 clk (cru_gate16[7:8] */ 325*036935a8SXiaoDong Huang if (i == 16) { 326*036935a8SXiaoDong Huang mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(i), 327*036935a8SXiaoDong Huang 0xfe7f0000); 328*036935a8SXiaoDong Huang } else { 329*036935a8SXiaoDong Huang mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(i), 330*036935a8SXiaoDong Huang 0xffff0000); 331*036935a8SXiaoDong Huang } 332*036935a8SXiaoDong Huang } 333*036935a8SXiaoDong Huang 334*036935a8SXiaoDong Huang for (i = 0; i < PHP_CRU_CLKGATE_CON_CNT; i++) 335*036935a8SXiaoDong Huang mmio_write_32(PHP_CRU_BASE + PHP_CRU_CLKGATE_CON(i), 0xffff0000); 336*036935a8SXiaoDong Huang 337*036935a8SXiaoDong Huang for (i = 0; i < SECURE_CRU_CLKGATE_CON_CNT; i++) 338*036935a8SXiaoDong Huang mmio_write_32(SECURE_CRU_BASE + SECURE_CRU_CLKGATE_CON(i), 0xffff0000); 339*036935a8SXiaoDong Huang 340*036935a8SXiaoDong Huang for (i = 0; i < SECURE_SCRU_CLKGATE_CON_CNT; i++) 341*036935a8SXiaoDong Huang mmio_write_32(SECURE_CRU_BASE + SECURE_SCRU_CLKGATE_CON(i), 0xffff0000); 342*036935a8SXiaoDong Huang 343*036935a8SXiaoDong Huang for (i = 0; i < PMU1CRU_CLKGATE_CON_CNT; i++) 344*036935a8SXiaoDong Huang mmio_write_32(PMU1_CRU_BASE + PMU1CRU_CLKGATE_CON(i), 0xffff0000); 345*036935a8SXiaoDong Huang 346*036935a8SXiaoDong Huang for (i = 0; i < PMU1SCRU_CLKGATE_CON_CNT; i++) 347*036935a8SXiaoDong Huang mmio_write_32(PMU1_CRU_BASE + PMU1SCRU_CLKGATE_CON(i), 0xffff0000); 348*036935a8SXiaoDong Huang } 349*036935a8SXiaoDong Huang 350*036935a8SXiaoDong Huang void clk_gate_con_save(void) 351*036935a8SXiaoDong Huang { 352*036935a8SXiaoDong Huang int i, j = 0; 353*036935a8SXiaoDong Huang 354*036935a8SXiaoDong Huang for (i = 0; i < CRU_CLKGATE_CON_CNT; i++, j++) 355*036935a8SXiaoDong Huang clk_save[j] = mmio_read_32(CRU_BASE + CRU_CLKGATE_CON(i)); 356*036935a8SXiaoDong Huang 357*036935a8SXiaoDong Huang for (i = 0; i < PHP_CRU_CLKGATE_CON_CNT; i++, j++) 358*036935a8SXiaoDong Huang clk_save[j] = mmio_read_32(PHP_CRU_BASE + PHP_CRU_CLKGATE_CON(i)); 359*036935a8SXiaoDong Huang 360*036935a8SXiaoDong Huang for (i = 0; i < SECURE_CRU_CLKGATE_CON_CNT; i++, j++) 361*036935a8SXiaoDong Huang clk_save[j] = mmio_read_32(SECURE_CRU_BASE + SECURE_CRU_CLKGATE_CON(i)); 362*036935a8SXiaoDong Huang 363*036935a8SXiaoDong Huang for (i = 0; i < SECURE_SCRU_CLKGATE_CON_CNT; i++, j++) 364*036935a8SXiaoDong Huang clk_save[j] = mmio_read_32(SECURE_CRU_BASE + SECURE_SCRU_CLKGATE_CON(i)); 365*036935a8SXiaoDong Huang 366*036935a8SXiaoDong Huang for (i = 0; i < PMU1CRU_CLKGATE_CON_CNT; i++, j++) 367*036935a8SXiaoDong Huang clk_save[j] = mmio_read_32(PMU1_CRU_BASE + PMU1CRU_CLKGATE_CON(i)); 368*036935a8SXiaoDong Huang 369*036935a8SXiaoDong Huang for (i = 0; i < PMU1SCRU_CLKGATE_CON_CNT; i++, j++) 370*036935a8SXiaoDong Huang clk_save[j] = mmio_read_32(PMU1_CRU_BASE + PMU1SCRU_CLKGATE_CON(i)); 371*036935a8SXiaoDong Huang } 372*036935a8SXiaoDong Huang 373*036935a8SXiaoDong Huang void clk_gate_con_restore(void) 374*036935a8SXiaoDong Huang { 375*036935a8SXiaoDong Huang int i, j = 0; 376*036935a8SXiaoDong Huang 377*036935a8SXiaoDong Huang for (i = 0; i < CRU_CLKGATE_CON_CNT; i++, j++) 378*036935a8SXiaoDong Huang mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(i), 379*036935a8SXiaoDong Huang WITH_16BITS_WMSK(clk_save[j])); 380*036935a8SXiaoDong Huang 381*036935a8SXiaoDong Huang for (i = 0; i < PHP_CRU_CLKGATE_CON_CNT; i++, j++) 382*036935a8SXiaoDong Huang mmio_write_32(PHP_CRU_BASE + PHP_CRU_CLKGATE_CON(i), 383*036935a8SXiaoDong Huang WITH_16BITS_WMSK(clk_save[j])); 384*036935a8SXiaoDong Huang 385*036935a8SXiaoDong Huang for (i = 0; i < SECURE_CRU_CLKGATE_CON_CNT; i++, j++) 386*036935a8SXiaoDong Huang mmio_write_32(SECURE_CRU_BASE + SECURE_CRU_CLKGATE_CON(i), 387*036935a8SXiaoDong Huang WITH_16BITS_WMSK(clk_save[j])); 388*036935a8SXiaoDong Huang 389*036935a8SXiaoDong Huang for (i = 0; i < SECURE_SCRU_CLKGATE_CON_CNT; i++, j++) 390*036935a8SXiaoDong Huang mmio_write_32(SECURE_CRU_BASE + SECURE_SCRU_CLKGATE_CON(i), 391*036935a8SXiaoDong Huang WITH_16BITS_WMSK(clk_save[j])); 392*036935a8SXiaoDong Huang 393*036935a8SXiaoDong Huang for (i = 0; i < PMU1CRU_CLKGATE_CON_CNT; i++, j++) 394*036935a8SXiaoDong Huang mmio_write_32(PMU1_CRU_BASE + PMU1CRU_CLKGATE_CON(i), 395*036935a8SXiaoDong Huang WITH_16BITS_WMSK(clk_save[j])); 396*036935a8SXiaoDong Huang 397*036935a8SXiaoDong Huang for (i = 0; i < PMU1SCRU_CLKGATE_CON_CNT; i++, j++) 398*036935a8SXiaoDong Huang mmio_write_32(PMU1_CRU_BASE + PMU1SCRU_CLKGATE_CON(i), 399*036935a8SXiaoDong Huang WITH_16BITS_WMSK(clk_save[j])); 400*036935a8SXiaoDong Huang } 401*036935a8SXiaoDong Huang 402*036935a8SXiaoDong Huang void pmu_bus_idle_req(uint32_t bus, uint32_t state) 403*036935a8SXiaoDong Huang { 404*036935a8SXiaoDong Huang uint32_t wait_cnt = 0; 405*036935a8SXiaoDong Huang 406*036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_BUS_IDLE_SFTCON(bus / 16), 407*036935a8SXiaoDong Huang BITS_WITH_WMASK(state, 0x1, bus % 16)); 408*036935a8SXiaoDong Huang 409*036935a8SXiaoDong Huang while (pmu_bus_idle_st(bus) != state || 410*036935a8SXiaoDong Huang pmu_bus_idle_ack(bus) != state) { 411*036935a8SXiaoDong Huang if (++wait_cnt > BUS_IDLE_LOOP) 412*036935a8SXiaoDong Huang break; 413*036935a8SXiaoDong Huang udelay(1); 414*036935a8SXiaoDong Huang } 415*036935a8SXiaoDong Huang 416*036935a8SXiaoDong Huang if (wait_cnt > BUS_IDLE_LOOP) 417*036935a8SXiaoDong Huang WARN("%s: can't wait state %d for bus %d (0x%x)\n", 418*036935a8SXiaoDong Huang __func__, state, bus, 419*036935a8SXiaoDong Huang mmio_read_32(PMU_BASE + PMU2_BUS_IDLE_ST)); 420*036935a8SXiaoDong Huang } 421*036935a8SXiaoDong Huang 422*036935a8SXiaoDong Huang static inline uint32_t pmu_power_domain_st(uint32_t pd) 423*036935a8SXiaoDong Huang { 424*036935a8SXiaoDong Huang return mmio_read_32(PMU_BASE + PMU2_PWR_GATE_ST) & BIT(pd) ? 425*036935a8SXiaoDong Huang pmu_pd_off : 426*036935a8SXiaoDong Huang pmu_pd_on; 427*036935a8SXiaoDong Huang } 428*036935a8SXiaoDong Huang 429*036935a8SXiaoDong Huang int pmu_power_domain_ctr(uint32_t pd, uint32_t pd_state) 430*036935a8SXiaoDong Huang { 431*036935a8SXiaoDong Huang uint32_t loop = 0; 432*036935a8SXiaoDong Huang int ret = 0; 433*036935a8SXiaoDong Huang 434*036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_PWR_GATE_SFTCON(pd / 16), 435*036935a8SXiaoDong Huang BITS_WITH_WMASK(pd_state, 0x1, pd % 16)); 436*036935a8SXiaoDong Huang dsb(); 437*036935a8SXiaoDong Huang 438*036935a8SXiaoDong Huang while ((pmu_power_domain_st(pd) != pd_state) && (loop < PD_CTR_LOOP)) { 439*036935a8SXiaoDong Huang udelay(1); 440*036935a8SXiaoDong Huang loop++; 441*036935a8SXiaoDong Huang } 442*036935a8SXiaoDong Huang 443*036935a8SXiaoDong Huang if (pmu_power_domain_st(pd) != pd_state) { 444*036935a8SXiaoDong Huang WARN("%s: %d, %d, (0x%x) error!\n", __func__, pd, pd_state, 445*036935a8SXiaoDong Huang mmio_read_32(PMU_BASE + PMU2_PWR_GATE_ST)); 446*036935a8SXiaoDong Huang ret = -EINVAL; 447*036935a8SXiaoDong Huang } 448*036935a8SXiaoDong Huang 449*036935a8SXiaoDong Huang return ret; 450*036935a8SXiaoDong Huang } 451*036935a8SXiaoDong Huang 452*036935a8SXiaoDong Huang static int pmu_set_power_domain(uint32_t pd_id, uint32_t pd_state) 453*036935a8SXiaoDong Huang { 454*036935a8SXiaoDong Huang uint32_t state; 455*036935a8SXiaoDong Huang 456*036935a8SXiaoDong Huang if (pmu_power_domain_st(pd_id) == pd_state) 457*036935a8SXiaoDong Huang goto out; 458*036935a8SXiaoDong Huang 459*036935a8SXiaoDong Huang if (pd_state == pmu_pd_on) 460*036935a8SXiaoDong Huang pmu_power_domain_ctr(pd_id, pd_state); 461*036935a8SXiaoDong Huang 462*036935a8SXiaoDong Huang state = (pd_state == pmu_pd_off) ? pmu_bus_idle : pmu_bus_active; 463*036935a8SXiaoDong Huang 464*036935a8SXiaoDong Huang switch (pd_id) { 465*036935a8SXiaoDong Huang case pmu_pd_npu: 466*036935a8SXiaoDong Huang pmu_bus_idle_req(pmu_bus_id_npusys, state); 467*036935a8SXiaoDong Huang break; 468*036935a8SXiaoDong Huang case pmu_pd_secure: 469*036935a8SXiaoDong Huang pmu_bus_idle_req(pmu_bus_id_secure, state); 470*036935a8SXiaoDong Huang break; 471*036935a8SXiaoDong Huang case pmu_pd_nvm: 472*036935a8SXiaoDong Huang pmu_bus_idle_req(pmu_bus_id_nvm, state); 473*036935a8SXiaoDong Huang break; 474*036935a8SXiaoDong Huang case pmu_pd_sd_gmac: 475*036935a8SXiaoDong Huang pmu_bus_idle_req(pmu_bus_id_gmac, state); 476*036935a8SXiaoDong Huang break; 477*036935a8SXiaoDong Huang case pmu_pd_audio: 478*036935a8SXiaoDong Huang pmu_bus_idle_req(pmu_bus_id_audio, state); 479*036935a8SXiaoDong Huang break; 480*036935a8SXiaoDong Huang case pmu_pd_php: 481*036935a8SXiaoDong Huang pmu_bus_idle_req(pmu_bus_id_php, state); 482*036935a8SXiaoDong Huang break; 483*036935a8SXiaoDong Huang case pmu_pd_subphp: 484*036935a8SXiaoDong Huang break; 485*036935a8SXiaoDong Huang case pmu_pd_vop: 486*036935a8SXiaoDong Huang pmu_bus_idle_req(pmu_bus_id_vop, state); 487*036935a8SXiaoDong Huang break; 488*036935a8SXiaoDong Huang case pmu_pd_vop_smart: 489*036935a8SXiaoDong Huang break; 490*036935a8SXiaoDong Huang case pmu_pd_vop_clst: 491*036935a8SXiaoDong Huang break; 492*036935a8SXiaoDong Huang case pmu_pd_vo1: 493*036935a8SXiaoDong Huang pmu_bus_idle_req(pmu_bus_id_vo1, state); 494*036935a8SXiaoDong Huang break; 495*036935a8SXiaoDong Huang case pmu_pd_vo0: 496*036935a8SXiaoDong Huang pmu_bus_idle_req(pmu_bus_id_vo0, state); 497*036935a8SXiaoDong Huang break; 498*036935a8SXiaoDong Huang case pmu_pd_usb: 499*036935a8SXiaoDong Huang pmu_bus_idle_req(pmu_bus_id_usb, state); 500*036935a8SXiaoDong Huang break; 501*036935a8SXiaoDong Huang case pmu_pd_vi: 502*036935a8SXiaoDong Huang pmu_bus_idle_req(pmu_bus_id_vi, state); 503*036935a8SXiaoDong Huang break; 504*036935a8SXiaoDong Huang case pmu_pd_vepu0: 505*036935a8SXiaoDong Huang pmu_bus_idle_req(pmu_bus_id_vepu0, state); 506*036935a8SXiaoDong Huang break; 507*036935a8SXiaoDong Huang case pmu_pd_vepu1: 508*036935a8SXiaoDong Huang pmu_bus_idle_req(pmu_bus_id_vepu1, state); 509*036935a8SXiaoDong Huang break; 510*036935a8SXiaoDong Huang case pmu_pd_vdec: 511*036935a8SXiaoDong Huang pmu_bus_idle_req(pmu_bus_id_vdec, state); 512*036935a8SXiaoDong Huang break; 513*036935a8SXiaoDong Huang case pmu_pd_vpu: 514*036935a8SXiaoDong Huang pmu_bus_idle_req(pmu_bus_id_vpu, state); 515*036935a8SXiaoDong Huang break; 516*036935a8SXiaoDong Huang case pmu_pd_nputop: 517*036935a8SXiaoDong Huang pmu_bus_idle_req(pmu_bus_id_nputop, state); 518*036935a8SXiaoDong Huang break; 519*036935a8SXiaoDong Huang case pmu_pd_npu0: 520*036935a8SXiaoDong Huang pmu_bus_idle_req(pmu_bus_id_npu0, state); 521*036935a8SXiaoDong Huang break; 522*036935a8SXiaoDong Huang case pmu_pd_npu1: 523*036935a8SXiaoDong Huang pmu_bus_idle_req(pmu_bus_id_npu1, state); 524*036935a8SXiaoDong Huang break; 525*036935a8SXiaoDong Huang case pmu_pd_gpu: 526*036935a8SXiaoDong Huang pmu_bus_idle_req(pmu_bus_id_gpu, state); 527*036935a8SXiaoDong Huang break; 528*036935a8SXiaoDong Huang default: 529*036935a8SXiaoDong Huang break; 530*036935a8SXiaoDong Huang } 531*036935a8SXiaoDong Huang 532*036935a8SXiaoDong Huang if (pd_state == pmu_pd_off) 533*036935a8SXiaoDong Huang pmu_power_domain_ctr(pd_id, pd_state); 534*036935a8SXiaoDong Huang 535*036935a8SXiaoDong Huang out: 536*036935a8SXiaoDong Huang return 0; 537*036935a8SXiaoDong Huang } 538*036935a8SXiaoDong Huang 539*036935a8SXiaoDong Huang static void pmu_power_domains_suspend(void) 540*036935a8SXiaoDong Huang { 541*036935a8SXiaoDong Huang ddr_data.pmu_pd_st = mmio_read_32(PMU_BASE + PMU2_PWR_GATE_ST); 542*036935a8SXiaoDong Huang ddr_data.bus_idle_st = mmio_read_32(PMU_BASE + PMU2_BUS_IDLE_ST); 543*036935a8SXiaoDong Huang ddr_data.pmu2_pwrgt_sft_con0 = mmio_read_32(PMU_BASE + PMU2_PWR_GATE_SFTCON(0)); 544*036935a8SXiaoDong Huang 545*036935a8SXiaoDong Huang qos_save(); 546*036935a8SXiaoDong Huang 547*036935a8SXiaoDong Huang pd_usb2phy_save(); 548*036935a8SXiaoDong Huang 549*036935a8SXiaoDong Huang if ((ddr_data.pmu_pd_st & BIT(pmu_pd_php)) == 0) 550*036935a8SXiaoDong Huang pd_php_save(); 551*036935a8SXiaoDong Huang } 552*036935a8SXiaoDong Huang 553*036935a8SXiaoDong Huang static void pmu_power_domains_resume(void) 554*036935a8SXiaoDong Huang { 555*036935a8SXiaoDong Huang int i; 556*036935a8SXiaoDong Huang 557*036935a8SXiaoDong Huang for (i = 0; i < pmu_pd_id_max; i++) { 558*036935a8SXiaoDong Huang /* vop smart/clst pd is not controlled by pmu */ 559*036935a8SXiaoDong Huang if (i == pmu_pd_vop_smart || i == pmu_pd_vop_clst) 560*036935a8SXiaoDong Huang continue; 561*036935a8SXiaoDong Huang 562*036935a8SXiaoDong Huang pmu_set_power_domain(i, !!(ddr_data.pmu_pd_st & BIT(i))); 563*036935a8SXiaoDong Huang } 564*036935a8SXiaoDong Huang 565*036935a8SXiaoDong Huang /* restore vop smart/clst pd of pmu2_pwrgt_sft_con0 */ 566*036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_PWR_GATE_SFTCON(0), 567*036935a8SXiaoDong Huang 0x30000000 | ddr_data.pmu2_pwrgt_sft_con0); 568*036935a8SXiaoDong Huang 569*036935a8SXiaoDong Huang for (i = pmu_bus_id_max - 1; i >= 0; i--) 570*036935a8SXiaoDong Huang pmu_bus_idle_req(i, !!(ddr_data.bus_idle_st & BIT(i))); 571*036935a8SXiaoDong Huang 572*036935a8SXiaoDong Huang if ((ddr_data.pmu_pd_st & BIT(pmu_pd_php)) == 0) 573*036935a8SXiaoDong Huang pd_php_restore(); 574*036935a8SXiaoDong Huang 575*036935a8SXiaoDong Huang pd_usb2phy_restore(); 576*036935a8SXiaoDong Huang 577*036935a8SXiaoDong Huang qos_restore(); 578*036935a8SXiaoDong Huang } 579*036935a8SXiaoDong Huang 580*036935a8SXiaoDong Huang static void ddr_sleep_config(void) 581*036935a8SXiaoDong Huang { 582*036935a8SXiaoDong Huang ddr_data.ddrgrf_cha_con2 = 583*036935a8SXiaoDong Huang mmio_read_32(DDR_GRF_BASE + DDRGRF_CHA_CON(2)); 584*036935a8SXiaoDong Huang ddr_data.ddrgrf_chb_con2 = 585*036935a8SXiaoDong Huang mmio_read_32(DDR_GRF_BASE + DDRGRF_CHB_CON(2)); 586*036935a8SXiaoDong Huang 587*036935a8SXiaoDong Huang mmio_write_32(DDR_GRF_BASE + DDRGRF_CHA_CON(2), 0x0a000a00); 588*036935a8SXiaoDong Huang mmio_write_32(DDR_GRF_BASE + DDRGRF_CHB_CON(2), 0x0a000a00); 589*036935a8SXiaoDong Huang } 590*036935a8SXiaoDong Huang 591*036935a8SXiaoDong Huang static void ddr_sleep_config_restore(void) 592*036935a8SXiaoDong Huang { 593*036935a8SXiaoDong Huang mmio_write_32(DDR_GRF_BASE + DDRGRF_CHA_CON(2), 594*036935a8SXiaoDong Huang WITH_16BITS_WMSK(ddr_data.ddrgrf_cha_con2)); 595*036935a8SXiaoDong Huang mmio_write_32(DDR_GRF_BASE + DDRGRF_CHB_CON(2), 596*036935a8SXiaoDong Huang WITH_16BITS_WMSK(ddr_data.ddrgrf_chb_con2)); 597*036935a8SXiaoDong Huang } 598*036935a8SXiaoDong Huang 599*036935a8SXiaoDong Huang static void sleep_pin_config(void) 600*036935a8SXiaoDong Huang { 601*036935a8SXiaoDong Huang /* pwr0 sleep: gpio0_a3 */ 602*036935a8SXiaoDong Huang mmio_write_32(PMU0_GRF_BASE + PMU0GRF_SOC_CON(1), 603*036935a8SXiaoDong Huang BITS_WITH_WMASK(0x7, 0xf, 0)); 604*036935a8SXiaoDong Huang mmio_write_32(PMU0_GRF_BASE + PMU0GRF_SOC_CON(0), 605*036935a8SXiaoDong Huang BITS_WITH_WMASK(0, 0x1, 7)); 606*036935a8SXiaoDong Huang mmio_write_32(PMU0_IOC_BASE + PMUIO0_IOC_GPIO0A_IOMUX_SEL_L, 607*036935a8SXiaoDong Huang BITS_WITH_WMASK(9, 0xfu, 12)); 608*036935a8SXiaoDong Huang } 609*036935a8SXiaoDong Huang 610*036935a8SXiaoDong Huang static void pmu_sleep_config(void) 611*036935a8SXiaoDong Huang { 612*036935a8SXiaoDong Huang uint32_t pmu1_wkup_int_con; 613*036935a8SXiaoDong Huang uint32_t pmu1_pwr_con, pmu1_ddr_pwr_con, pmu1cru_pwr_con, pmu1_pll_pd_con; 614*036935a8SXiaoDong Huang uint32_t pmu2_bus_idle_con[2], pmu2_pwr_gt_con[2]; 615*036935a8SXiaoDong Huang uint32_t key_upd_msk = ddr_data.pmu_pd_st & BIT(pmu_pd_vop) ? 0x3 : 0x7; 616*036935a8SXiaoDong Huang uint32_t fw_lkp_upd_msk = ddr_data.pmu_pd_st & BIT(pmu_pd_npu) ? 0x3 : 0x7; 617*036935a8SXiaoDong Huang uint32_t fw_ddr_upd_msk = key_upd_msk; 618*036935a8SXiaoDong Huang uint32_t pmu_pd_st = mmio_read_32(PMU_BASE + PMU2_PWR_GATE_ST); 619*036935a8SXiaoDong Huang uint32_t bus_idle_st = mmio_read_32(PMU_BASE + PMU2_BUS_IDLE_ST); 620*036935a8SXiaoDong Huang 621*036935a8SXiaoDong Huang ddr_data.pmu2_bisr_glb_con = mmio_read_32(PMU_BASE + PMU2_BISR_GLB_CON); 622*036935a8SXiaoDong Huang 623*036935a8SXiaoDong Huang ddr_data.pmu2_fast_pwr_con = 624*036935a8SXiaoDong Huang mmio_read_32(PMU_BASE + PMU2_FAST_POWER_CON); 625*036935a8SXiaoDong Huang 626*036935a8SXiaoDong Huang ddr_data.pmu2_c0_ack_sel_con0 = 627*036935a8SXiaoDong Huang mmio_read_32(PMU_BASE + PMU2_C0_PWRACK_BYPASS_CON(0)); 628*036935a8SXiaoDong Huang ddr_data.pmu2_c1_ack_sel_con0 = 629*036935a8SXiaoDong Huang mmio_read_32(PMU_BASE + PMU2_C1_PWRACK_BYPASS_CON(0)); 630*036935a8SXiaoDong Huang ddr_data.pmu2_c2_ack_sel_con0 = 631*036935a8SXiaoDong Huang mmio_read_32(PMU_BASE + PMU2_C2_PWRACK_BYPASS_CON(0)); 632*036935a8SXiaoDong Huang ddr_data.pmu0grf_soc_con5 = 633*036935a8SXiaoDong Huang mmio_read_32(PMU0_GRF_BASE + PMU0GRF_SOC_CON(5)); 634*036935a8SXiaoDong Huang 635*036935a8SXiaoDong Huang /* set tsadc_shut_m0 pin iomux to gpio */ 636*036935a8SXiaoDong Huang mmio_write_32(PMU0_IOC_BASE + PMUIO0_IOC_GPIO0A_IOMUX_SEL_L, 637*036935a8SXiaoDong Huang BITS_WITH_WMASK(0, 0xf, 4)); 638*036935a8SXiaoDong Huang 639*036935a8SXiaoDong Huang pmu1_wkup_int_con = 640*036935a8SXiaoDong Huang BIT(pmu_wkup_cpu0_int) | 641*036935a8SXiaoDong Huang BIT(pmu_wkup_gpio0_int); 642*036935a8SXiaoDong Huang 643*036935a8SXiaoDong Huang pmu1_pwr_con = 644*036935a8SXiaoDong Huang BIT(pmu_powermode_en) | 645*036935a8SXiaoDong Huang /* BIT(pmu_scu0_byp) | */ 646*036935a8SXiaoDong Huang /* BIT(pmu_scu1_byp) | */ 647*036935a8SXiaoDong Huang /* BIT(pmu_cci_byp) | */ 648*036935a8SXiaoDong Huang /* BIT(pmu_bus_byp) | */ 649*036935a8SXiaoDong Huang /* BIT(pmu_ddr_byp) | */ 650*036935a8SXiaoDong Huang /* BIT(pmu_pwrgt_byp) | */ 651*036935a8SXiaoDong Huang /* BIT(pmu_cru_byp) | */ 652*036935a8SXiaoDong Huang BIT(pmu_qch_byp) | 653*036935a8SXiaoDong Huang /* BIT(pmu_wfi_byp) | */ 654*036935a8SXiaoDong Huang BIT(pmu_slp_cnt_en); 655*036935a8SXiaoDong Huang 656*036935a8SXiaoDong Huang pmu1_ddr_pwr_con = 0; 657*036935a8SXiaoDong Huang 658*036935a8SXiaoDong Huang pmu1_pll_pd_con = 659*036935a8SXiaoDong Huang BIT(pmu_bpll_pd_en) | 660*036935a8SXiaoDong Huang BIT(pmu_lpll_pd_en) | 661*036935a8SXiaoDong Huang BIT(pmu_spll_pd_en) | 662*036935a8SXiaoDong Huang BIT(pmu_gpll_pd_en) | 663*036935a8SXiaoDong Huang BIT(pmu_cpll_pd_en) | 664*036935a8SXiaoDong Huang BIT(pmu_ppll_pd_en) | 665*036935a8SXiaoDong Huang BIT(pmu_aupll_pd_en) | 666*036935a8SXiaoDong Huang BIT(pmu_vpll_pd_en); 667*036935a8SXiaoDong Huang 668*036935a8SXiaoDong Huang pmu1cru_pwr_con = 669*036935a8SXiaoDong Huang BIT(pmu_alive_osc_mode_en) | 670*036935a8SXiaoDong Huang BIT(pmu_io_sleep_en) | 671*036935a8SXiaoDong Huang BIT(pmu_power_off_en); 672*036935a8SXiaoDong Huang 673*036935a8SXiaoDong Huang pmu2_bus_idle_con[0] = 0xffff & ~(bus_idle_st & 0xffff); 674*036935a8SXiaoDong Huang pmu2_bus_idle_con[1] = 0x3fff & ~(bus_idle_st >> 16); 675*036935a8SXiaoDong Huang 676*036935a8SXiaoDong Huang pmu2_pwr_gt_con[0] = 0xffff & ~(pmu_pd_st & 0xffff); 677*036935a8SXiaoDong Huang pmu2_pwr_gt_con[1] = 0x03ff & ~(pmu_pd_st >> 16); 678*036935a8SXiaoDong Huang 679*036935a8SXiaoDong Huang pmu2_pwr_gt_con[0] &= 680*036935a8SXiaoDong Huang ~(BIT(pmu_pd_secure) | 681*036935a8SXiaoDong Huang BIT(pmu_pd_bus) | 682*036935a8SXiaoDong Huang BIT(pmu_pd_center) | 683*036935a8SXiaoDong Huang BIT(pmu_pd_ddr)); 684*036935a8SXiaoDong Huang 685*036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_BUS_IDLEACK_BYPASS_CON, 0x00030003); 686*036935a8SXiaoDong Huang mmio_write_32(SYS_SGRF_FW_BASE + FW_SGRF_KEYUPD_CON0, 0x03ff0000); 687*036935a8SXiaoDong Huang 688*036935a8SXiaoDong Huang /* disable repair */ 689*036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_BISR_GLB_CON, 0x00010000); 690*036935a8SXiaoDong Huang 691*036935a8SXiaoDong Huang /* disable ddr_hash_key update. 692*036935a8SXiaoDong Huang * enable disable ddr_hash_key auto update. 693*036935a8SXiaoDong Huang * wait ddr_hash_key auto update. 694*036935a8SXiaoDong Huang */ 695*036935a8SXiaoDong Huang mmio_write_32(SYS_SGRF_BASE + SYSSGRF_SOC_CON(19), 696*036935a8SXiaoDong Huang BITS_WITH_WMASK(key_upd_msk, 0x7, 8)); 697*036935a8SXiaoDong Huang mmio_write_32(SYS_SGRF_FW_BASE + FW_SGRF_KEYUPD_CON1, 698*036935a8SXiaoDong Huang BITS_WITH_WMASK(fw_lkp_upd_msk, 0x7, 10)); 699*036935a8SXiaoDong Huang mmio_write_32(SYS_SGRF_FW_BASE + FW_SGRF_KEYUPD_CON1, 700*036935a8SXiaoDong Huang BITS_WITH_WMASK(fw_ddr_upd_msk, 0x7u, 13)); 701*036935a8SXiaoDong Huang 702*036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU0_PMIC_STABLE_CNT_THRES, 24000 * 5); 703*036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU0_OSC_STABLE_CNT_THRES, 24000 * 5); 704*036935a8SXiaoDong Huang 705*036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU1_OSC_STABLE_CNT_THRESH, 24000 * 5); 706*036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU1_STABLE_CNT_THRESH, 24000 * 5); 707*036935a8SXiaoDong Huang 708*036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU1_SLEEP_CNT_THRESH, 24000 * 15); 709*036935a8SXiaoDong Huang 710*036935a8SXiaoDong Huang /* Pmu's clk has switched to 24M back When pmu FSM counts 711*036935a8SXiaoDong Huang * the follow counters, so we should use 24M to calculate 712*036935a8SXiaoDong Huang * these counters. 713*036935a8SXiaoDong Huang */ 714*036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU0_WAKEUP_RST_CLR_CNT_THRES, 12000); 715*036935a8SXiaoDong Huang 716*036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU1_WAKEUP_RST_CLR_CNT_THRESH, 12000); 717*036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU1_PLL_LOCK_CNT_THRESH, 12000); 718*036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU1_PWM_SWITCH_CNT_THRESH, 719*036935a8SXiaoDong Huang 24000 * 2); 720*036935a8SXiaoDong Huang 721*036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_SCU0_PWRUP_CNT_THRESH, 0); 722*036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_SCU0_PWRDN_CNT_THRESH, 0); 723*036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_SCU0_STABLE_CNT_THRESH, 0); 724*036935a8SXiaoDong Huang 725*036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_FAST_PWRUP_CNT_THRESH_0, 0); 726*036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_FAST_PWRDN_CNT_THRESH_0, 0); 727*036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_FAST_PWRUP_CNT_THRESH_1, 0); 728*036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_FAST_PWRDN_CNT_THRESH_1, 0); 729*036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_FAST_PWRUP_CNT_THRESH_2, 0); 730*036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_FAST_PWRDN_CNT_THRESH_2, 0); 731*036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_FAST_POWER_CON, 0xffff0007); 732*036935a8SXiaoDong Huang 733*036935a8SXiaoDong Huang /* pmu_clst_idle_con */ 734*036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_CLUSTER0_IDLE_CON, 0xffff0007); 735*036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_CLUSTER1_IDLE_CON, 0xffff0007); 736*036935a8SXiaoDong Huang 737*036935a8SXiaoDong Huang /* pmu_scu_pwr_con */ 738*036935a8SXiaoDong Huang /* L2's flush and idle by hardware, so need to enable wfil2 bypass */ 739*036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_SCU0_PWR_CON, 0xffff020f); 740*036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_SCU1_PWR_CON, 0xffff020f); 741*036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_SCU0_AUTO_PWR_CON, 0x00070000); 742*036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_SCU1_AUTO_PWR_CON, 0x00070000); 743*036935a8SXiaoDong Huang 744*036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_CCI_PWR_CON, 0xffff0009); 745*036935a8SXiaoDong Huang 746*036935a8SXiaoDong Huang /* pmu_int_msk_con */ 747*036935a8SXiaoDong Huang /* mmio_write_32(PMU_BASE + PMU1_INT_MASK_CON, BITS_WITH_WMASK(1, 0x1, 0)); */ 748*036935a8SXiaoDong Huang 749*036935a8SXiaoDong Huang /* pmu_pwr_con */ 750*036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU1_PWR_CON, WITH_16BITS_WMSK(pmu1_pwr_con)); 751*036935a8SXiaoDong Huang 752*036935a8SXiaoDong Huang /* pmu_cru_pwr_conx */ 753*036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU1_CRU_PWR_CON(0), WITH_16BITS_WMSK(pmu1cru_pwr_con)); 754*036935a8SXiaoDong Huang 755*036935a8SXiaoDong Huang /* pmu_ddr_pwr_con */ 756*036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU0_DDR_RET_CON(1), 0xffff0000); 757*036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU1_DDR_PWR_CON(0), WITH_16BITS_WMSK(pmu1_ddr_pwr_con)); 758*036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU1_DDR_PWR_CON(1), WITH_16BITS_WMSK(pmu1_ddr_pwr_con)); 759*036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU1_DDR_AXIPWR_CON(0), 0x03ff03ff); 760*036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU1_DDR_AXIPWR_CON(1), 0x03ff03ff); 761*036935a8SXiaoDong Huang 762*036935a8SXiaoDong Huang /* pll_pd */ 763*036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU1_PLLPD_CON(0), WITH_16BITS_WMSK(pmu1_pll_pd_con)); 764*036935a8SXiaoDong Huang 765*036935a8SXiaoDong Huang /* bus idle */ 766*036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_BUS_IDLE_CON(0), WITH_16BITS_WMSK(pmu2_bus_idle_con[0])); 767*036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_BUS_IDLE_CON(1), WITH_16BITS_WMSK(pmu2_bus_idle_con[1])); 768*036935a8SXiaoDong Huang 769*036935a8SXiaoDong Huang /* power gate */ 770*036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_PWR_GATE_CON(0), WITH_16BITS_WMSK(pmu2_pwr_gt_con[0])); 771*036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_PWR_GATE_CON(1), WITH_16BITS_WMSK(pmu2_pwr_gt_con[1])); 772*036935a8SXiaoDong Huang 773*036935a8SXiaoDong Huang /* vol gate */ 774*036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_VOL_GATE_SFTCON(0), 0xffff0031); 775*036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_VOL_GATE_SFTCON(1), 0xffff0200); 776*036935a8SXiaoDong Huang 777*036935a8SXiaoDong Huang /* wakeup source */ 778*036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU1_WAKEUP_INT_CON, pmu1_wkup_int_con); 779*036935a8SXiaoDong Huang 780*036935a8SXiaoDong Huang /* ppll clamp */ 781*036935a8SXiaoDong Huang mmio_write_32(PMU0_GRF_BASE + PMU0GRF_SOC_CON(5), 0x00400040); 782*036935a8SXiaoDong Huang 783*036935a8SXiaoDong Huang /* usbphy clamp */ 784*036935a8SXiaoDong Huang mmio_write_32(PMU0_GRF_BASE + PMU0GRF_SOC_CON(5), 785*036935a8SXiaoDong Huang BITS_WITH_WMASK(0x9, 0x9, 2)); 786*036935a8SXiaoDong Huang 787*036935a8SXiaoDong Huang /* big core pwr ack bypass */ 788*036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_C0_PWRACK_BYPASS_CON(0), 0x01000100); 789*036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_C1_PWRACK_BYPASS_CON(0), 0x01000100); 790*036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_C2_PWRACK_BYPASS_CON(0), 0x01000100); 791*036935a8SXiaoDong Huang } 792*036935a8SXiaoDong Huang 793*036935a8SXiaoDong Huang static void pmu_sleep_restore(void) 794*036935a8SXiaoDong Huang { 795*036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU0_INFO_TX_CON, 0xffff0000); 796*036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_DEBUG_INFO_SEL, 0xffff0000); 797*036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_CLUSTER0_IDLE_CON, 0xffff0000); 798*036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_SCU0_PWR_CON, 0xffff0000); 799*036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_CCI_PWR_CON, 0xffff0000); 800*036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU1_INT_MASK_CON, 0xffff0000); 801*036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU1_PWR_CON, 0xffff0000); 802*036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU1_CRU_PWR_CON(0), 0xffff0000); 803*036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU1_DDR_PWR_CON(0), 0xffff0000); 804*036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU1_DDR_PWR_CON(1), 0xffff0000); 805*036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU1_DDR_AXIPWR_CON(0), 0xffff0000); 806*036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU1_DDR_AXIPWR_CON(1), 0xffff0000); 807*036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU1_PLLPD_CON(0), 0xffff0000); 808*036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_BUS_IDLE_CON(0), 0xffff0000); 809*036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_BUS_IDLE_CON(1), 0xffff0000); 810*036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_PWR_GATE_CON(0), 0xffff0000); 811*036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_PWR_GATE_CON(1), 0xffff0000); 812*036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_VOL_GATE_SFTCON(0), 0xffff0000); 813*036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_VOL_GATE_SFTCON(1), 0xffff0000); 814*036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_BUS_IDLEACK_BYPASS_CON, 0xffff0000); 815*036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU1_WAKEUP_INT_CON, 0); 816*036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_FAST_POWER_CON, 817*036935a8SXiaoDong Huang WITH_16BITS_WMSK(ddr_data.pmu2_fast_pwr_con)); 818*036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_BISR_GLB_CON, 819*036935a8SXiaoDong Huang WITH_16BITS_WMSK(ddr_data.pmu2_bisr_glb_con)); 820*036935a8SXiaoDong Huang 821*036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_C0_PWRACK_BYPASS_CON(0), 822*036935a8SXiaoDong Huang WITH_16BITS_WMSK(ddr_data.pmu2_c0_ack_sel_con0)); 823*036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_C1_PWRACK_BYPASS_CON(0), 824*036935a8SXiaoDong Huang WITH_16BITS_WMSK(ddr_data.pmu2_c1_ack_sel_con0)); 825*036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_C2_PWRACK_BYPASS_CON(0), 826*036935a8SXiaoDong Huang WITH_16BITS_WMSK(ddr_data.pmu2_c2_ack_sel_con0)); 827*036935a8SXiaoDong Huang 828*036935a8SXiaoDong Huang mmio_write_32(PMU0_GRF_BASE + PMU0GRF_SOC_CON(5), 829*036935a8SXiaoDong Huang WITH_16BITS_WMSK(ddr_data.pmu0grf_soc_con5)); 830*036935a8SXiaoDong Huang } 831*036935a8SXiaoDong Huang 832*036935a8SXiaoDong Huang static void secure_watchdog_disable(void) 833*036935a8SXiaoDong Huang { 834*036935a8SXiaoDong Huang ddr_data.sys_sgrf_soc_con0 = 835*036935a8SXiaoDong Huang mmio_read_32(SYS_SGRF_BASE + SYSSGRF_SOC_CON(0)); 836*036935a8SXiaoDong Huang 837*036935a8SXiaoDong Huang /* pause wdt_s */ 838*036935a8SXiaoDong Huang mmio_write_32(SYS_SGRF_BASE + SYSSGRF_SOC_CON(0), 839*036935a8SXiaoDong Huang BITS_WITH_WMASK(1, 0x1, 14)); 840*036935a8SXiaoDong Huang } 841*036935a8SXiaoDong Huang 842*036935a8SXiaoDong Huang static void secure_watchdog_restore(void) 843*036935a8SXiaoDong Huang { 844*036935a8SXiaoDong Huang mmio_write_32(SYS_SGRF_BASE + SYSSGRF_SOC_CON(0), 845*036935a8SXiaoDong Huang ddr_data.sys_sgrf_soc_con0 | 846*036935a8SXiaoDong Huang BITS_WMSK(0x1, 14)); 847*036935a8SXiaoDong Huang 848*036935a8SXiaoDong Huang if (mmio_read_32(WDT_S_BASE + WDT_CR) & WDT_EN) 849*036935a8SXiaoDong Huang mmio_write_32(WDT_S_BASE + WDT_CRR, 0x76); 850*036935a8SXiaoDong Huang } 851*036935a8SXiaoDong Huang 852*036935a8SXiaoDong Huang static void soc_sleep_config(void) 853*036935a8SXiaoDong Huang { 854*036935a8SXiaoDong Huang ddr_data.pmu0grf_soc_con0 = 855*036935a8SXiaoDong Huang mmio_read_32(PMU0_GRF_BASE + PMU0GRF_SOC_CON(0)); 856*036935a8SXiaoDong Huang ddr_data.pmu0grf_soc_con1 = 857*036935a8SXiaoDong Huang mmio_read_32(PMU0_GRF_BASE + PMU0GRF_SOC_CON(1)); 858*036935a8SXiaoDong Huang 859*036935a8SXiaoDong Huang ddr_data.gpio0a_iomux_l = 860*036935a8SXiaoDong Huang mmio_read_32(PMU0_IOC_BASE + PMUIO0_IOC_GPIO0A_IOMUX_SEL_L); 861*036935a8SXiaoDong Huang ddr_data.gpio0a_iomux_h = 862*036935a8SXiaoDong Huang mmio_read_32(PMU0_IOC_BASE + PMUIO0_IOC_GPIO0A_IOMUX_SEL_H); 863*036935a8SXiaoDong Huang ddr_data.gpio0b_iomux_l = 864*036935a8SXiaoDong Huang mmio_read_32(PMU0_IOC_BASE + PMUIO0_IOC_GPIO0B_IOMUX_SEL_L); 865*036935a8SXiaoDong Huang 866*036935a8SXiaoDong Huang sleep_pin_config(); 867*036935a8SXiaoDong Huang pmu_sleep_config(); 868*036935a8SXiaoDong Huang ddr_sleep_config(); 869*036935a8SXiaoDong Huang secure_watchdog_disable(); 870*036935a8SXiaoDong Huang } 871*036935a8SXiaoDong Huang 872*036935a8SXiaoDong Huang static void soc_sleep_restore(void) 873*036935a8SXiaoDong Huang { 874*036935a8SXiaoDong Huang secure_watchdog_restore(); 875*036935a8SXiaoDong Huang ddr_sleep_config_restore(); 876*036935a8SXiaoDong Huang pmu_sleep_restore(); 877*036935a8SXiaoDong Huang 878*036935a8SXiaoDong Huang mmio_write_32(PMU0_IOC_BASE + PMUIO0_IOC_GPIO0A_IOMUX_SEL_L, 879*036935a8SXiaoDong Huang WITH_16BITS_WMSK(ddr_data.gpio0a_iomux_l)); 880*036935a8SXiaoDong Huang mmio_write_32(PMU0_IOC_BASE + PMUIO0_IOC_GPIO0A_IOMUX_SEL_H, 881*036935a8SXiaoDong Huang WITH_16BITS_WMSK(ddr_data.gpio0a_iomux_h)); 882*036935a8SXiaoDong Huang mmio_write_32(PMU0_IOC_BASE + PMUIO0_IOC_GPIO0B_IOMUX_SEL_L, 883*036935a8SXiaoDong Huang WITH_16BITS_WMSK(ddr_data.gpio0b_iomux_l)); 884*036935a8SXiaoDong Huang 885*036935a8SXiaoDong Huang mmio_write_32(PMU0_GRF_BASE + PMU0GRF_SOC_CON(1), 886*036935a8SXiaoDong Huang WITH_16BITS_WMSK(ddr_data.pmu0grf_soc_con1)); 887*036935a8SXiaoDong Huang mmio_write_32(PMU0_GRF_BASE + PMU0GRF_SOC_CON(0), 888*036935a8SXiaoDong Huang WITH_16BITS_WMSK(ddr_data.pmu0grf_soc_con0)); 889*036935a8SXiaoDong Huang } 890*036935a8SXiaoDong Huang 891*036935a8SXiaoDong Huang static void pm_pll_suspend(void) 892*036935a8SXiaoDong Huang { 893*036935a8SXiaoDong Huang ddr_data.cru_mode_con = mmio_read_32(CRU_BASE + 0x280); 894*036935a8SXiaoDong Huang ddr_data.secure_cru_mode = mmio_read_32(SECURE_CRU_BASE + 0x4280); 895*036935a8SXiaoDong Huang 896*036935a8SXiaoDong Huang /* bpll gpll vpll aupll cpll spll switch to slow mode */ 897*036935a8SXiaoDong Huang mmio_write_32(CRU_BASE + 0x280, 0x03ff0000); 898*036935a8SXiaoDong Huang mmio_write_32(SECURE_CRU_BASE + 0x4280, 0x00030000); 899*036935a8SXiaoDong Huang 900*036935a8SXiaoDong Huang /* hclk_pmu_cm0_root_i_sel to 24M */ 901*036935a8SXiaoDong Huang mmio_write_32(PMU1_CRU_BASE + PMU1CRU_CLKSEL_CON(4), 902*036935a8SXiaoDong Huang BITS_WITH_WMASK(0x3, 0x3, 2)); 903*036935a8SXiaoDong Huang } 904*036935a8SXiaoDong Huang 905*036935a8SXiaoDong Huang static void pm_pll_restore(void) 906*036935a8SXiaoDong Huang { 907*036935a8SXiaoDong Huang mmio_write_32(CRU_BASE + 0x280, WITH_16BITS_WMSK(ddr_data.cru_mode_con)); 908*036935a8SXiaoDong Huang mmio_write_32(SECURE_CRU_BASE + 0x4280, 909*036935a8SXiaoDong Huang WITH_16BITS_WMSK(ddr_data.secure_cru_mode)); 910*036935a8SXiaoDong Huang } 911*036935a8SXiaoDong Huang 912*036935a8SXiaoDong Huang int rockchip_soc_sys_pwr_dm_suspend(void) 913*036935a8SXiaoDong Huang { 914*036935a8SXiaoDong Huang psram_sleep_cfg->pm_flag &= ~PM_WARM_BOOT_BIT; 915*036935a8SXiaoDong Huang 916*036935a8SXiaoDong Huang clk_gate_con_save(); 917*036935a8SXiaoDong Huang clk_gate_con_disable(); 918*036935a8SXiaoDong Huang dmc_save(); 919*036935a8SXiaoDong Huang pmu_power_domains_suspend(); 920*036935a8SXiaoDong Huang soc_sleep_config(); 921*036935a8SXiaoDong Huang pm_pll_suspend(); 922*036935a8SXiaoDong Huang pd_core_save(); 923*036935a8SXiaoDong Huang 924*036935a8SXiaoDong Huang return 0; 925*036935a8SXiaoDong Huang } 926*036935a8SXiaoDong Huang 927*036935a8SXiaoDong Huang int rockchip_soc_sys_pwr_dm_resume(void) 928*036935a8SXiaoDong Huang { 929*036935a8SXiaoDong Huang pd_core_restore(); 930*036935a8SXiaoDong Huang pm_pll_restore(); 931*036935a8SXiaoDong Huang soc_sleep_restore(); 932*036935a8SXiaoDong Huang pmu_power_domains_resume(); 933*036935a8SXiaoDong Huang plat_rockchip_gic_cpuif_enable(); 934*036935a8SXiaoDong Huang dmc_restore(); 935*036935a8SXiaoDong Huang clk_gate_con_restore(); 936*036935a8SXiaoDong Huang 937*036935a8SXiaoDong Huang psram_sleep_cfg->pm_flag |= PM_WARM_BOOT_BIT; 938*036935a8SXiaoDong Huang 939*036935a8SXiaoDong Huang return 0; 940*036935a8SXiaoDong Huang } 941*036935a8SXiaoDong Huang 942*036935a8SXiaoDong Huang void __dead2 rockchip_soc_cores_pd_pwr_dn_wfi(const 943*036935a8SXiaoDong Huang psci_power_state_t *target_state) 944*036935a8SXiaoDong Huang { 945*036935a8SXiaoDong Huang psci_power_down_wfi(); 946*036935a8SXiaoDong Huang /* should never reach here */ 947*036935a8SXiaoDong Huang panic(); 948*036935a8SXiaoDong Huang } 949*036935a8SXiaoDong Huang 950*036935a8SXiaoDong Huang void __dead2 rockchip_soc_sys_pd_pwr_dn_wfi(void) 951*036935a8SXiaoDong Huang { 952*036935a8SXiaoDong Huang psci_power_down_wfi(); 953*036935a8SXiaoDong Huang /* should never reach here */ 954*036935a8SXiaoDong Huang panic(); 955*036935a8SXiaoDong Huang } 956*036935a8SXiaoDong Huang 957*036935a8SXiaoDong Huang static int rockchip_reboot_is_rbrom(void) 958*036935a8SXiaoDong Huang { 959*036935a8SXiaoDong Huang return mmio_read_32(PMU0_GRF_BASE + PMU0GRF_OS_REG(16)) == 960*036935a8SXiaoDong Huang BOOT_BROM_DOWNLOAD; 961*036935a8SXiaoDong Huang } 962*036935a8SXiaoDong Huang 963*036935a8SXiaoDong Huang static void rockchip_soc_soft_reset_check_rstout(void) 964*036935a8SXiaoDong Huang { 965*036935a8SXiaoDong Huang /* 966*036935a8SXiaoDong Huang * Maskrom enter maskrom-usb mode according to os_reg0 which 967*036935a8SXiaoDong Huang * will be reset by NPOR. So disable tsadc_shut_m0 if we want 968*036935a8SXiaoDong Huang * to maskrom-usb mode. 969*036935a8SXiaoDong Huang */ 970*036935a8SXiaoDong Huang if (rockchip_reboot_is_rbrom() != 0) { 971*036935a8SXiaoDong Huang /* write BOOT_BROM_DOWNLOAD to os_reg0 */ 972*036935a8SXiaoDong Huang mmio_write_32(PMU1_GRF_BASE + PMU1GRF_OS_REG(0), BOOT_BROM_DOWNLOAD); 973*036935a8SXiaoDong Huang 974*036935a8SXiaoDong Huang /* disable first/tsadc/wdt reset output */ 975*036935a8SXiaoDong Huang mmio_write_32(PMU1SGRF_BASE + PMU1SGRF_SOC_CON(0), 0x00070000); 976*036935a8SXiaoDong Huang 977*036935a8SXiaoDong Huang /* clear reset hold */ 978*036935a8SXiaoDong Huang mmio_write_32(PMU0SGRF_BASE + PMU0SGRF_SOC_CON(1), 0xffff0000); 979*036935a8SXiaoDong Huang mmio_write_32(PMU1SGRF_BASE + PMU1SGRF_SOC_CON(16), 0xffff0000); 980*036935a8SXiaoDong Huang mmio_write_32(PMU1SGRF_BASE + PMU1SGRF_SOC_CON(17), 0xffff0000); 981*036935a8SXiaoDong Huang } 982*036935a8SXiaoDong Huang } 983*036935a8SXiaoDong Huang 984*036935a8SXiaoDong Huang void __dead2 rockchip_soc_soft_reset(void) 985*036935a8SXiaoDong Huang { 986*036935a8SXiaoDong Huang rockchip_soc_soft_reset_check_rstout(); 987*036935a8SXiaoDong Huang 988*036935a8SXiaoDong Huang /* pll slow mode */ 989*036935a8SXiaoDong Huang mmio_write_32(CRU_BASE + CRU_MODE_CON, 0x003f0000); 990*036935a8SXiaoDong Huang 991*036935a8SXiaoDong Huang dsb(); 992*036935a8SXiaoDong Huang isb(); 993*036935a8SXiaoDong Huang 994*036935a8SXiaoDong Huang INFO("system reset......\n"); 995*036935a8SXiaoDong Huang mmio_write_32(CRU_BASE + CRU_GLB_SRST_FST, GLB_SRST_FST_CFG_VAL); 996*036935a8SXiaoDong Huang 997*036935a8SXiaoDong Huang /* 998*036935a8SXiaoDong Huang * Maybe the HW needs some times to reset the system, 999*036935a8SXiaoDong Huang * so we do not hope the core to execute valid codes. 1000*036935a8SXiaoDong Huang */ 1001*036935a8SXiaoDong Huang psci_power_down_wfi(); 1002*036935a8SXiaoDong Huang /* should never reach here */ 1003*036935a8SXiaoDong Huang panic(); 1004*036935a8SXiaoDong Huang } 1005*036935a8SXiaoDong Huang 1006*036935a8SXiaoDong Huang void __dead2 rockchip_soc_system_off(void) 1007*036935a8SXiaoDong Huang { 1008*036935a8SXiaoDong Huang INFO("system poweroff......\n"); 1009*036935a8SXiaoDong Huang 1010*036935a8SXiaoDong Huang /* gpio0_a3 config output */ 1011*036935a8SXiaoDong Huang mmio_write_32(GPIO0_BASE + GPIO_SWPORT_DDR_L, 1012*036935a8SXiaoDong Huang BITS_WITH_WMASK(1, 0x1, 3)); 1013*036935a8SXiaoDong Huang 1014*036935a8SXiaoDong Huang /* gpio0_a3 config output high level */ 1015*036935a8SXiaoDong Huang mmio_write_32(GPIO0_BASE + GPIO_SWPORT_DR_L, 1016*036935a8SXiaoDong Huang BITS_WITH_WMASK(1, 0x1, 3)); 1017*036935a8SXiaoDong Huang dsb(); 1018*036935a8SXiaoDong Huang 1019*036935a8SXiaoDong Huang /* 1020*036935a8SXiaoDong Huang * Maybe the HW needs some times to reset the system, 1021*036935a8SXiaoDong Huang * so we do not hope the core to execute valid codes. 1022*036935a8SXiaoDong Huang */ 1023*036935a8SXiaoDong Huang psci_power_down_wfi(); 1024*036935a8SXiaoDong Huang /* should never reach here */ 1025*036935a8SXiaoDong Huang panic(); 1026*036935a8SXiaoDong Huang } 1027*036935a8SXiaoDong Huang 1028*036935a8SXiaoDong Huang static void rockchip_pmu_pd_repair_init(void) 1029*036935a8SXiaoDong Huang { 1030*036935a8SXiaoDong Huang INFO("enable memory repair\n"); 1031*036935a8SXiaoDong Huang /* Enable gpu and npu repair */ 1032*036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_BISR_PDGEN_CON(1), 1033*036935a8SXiaoDong Huang BITS_WITH_WMASK(0xf, 0xf, 6)); 1034*036935a8SXiaoDong Huang } 1035*036935a8SXiaoDong Huang 1036*036935a8SXiaoDong Huang void plat_rockchip_pmu_init(void) 1037*036935a8SXiaoDong Huang { 1038*036935a8SXiaoDong Huang int cpu; 1039*036935a8SXiaoDong Huang 1040*036935a8SXiaoDong Huang for (cpu = 0; cpu < PLATFORM_CORE_COUNT; cpu++) 1041*036935a8SXiaoDong Huang cpuson_flags[cpu] = 0; 1042*036935a8SXiaoDong Huang 1043*036935a8SXiaoDong Huang psram_sleep_cfg->sp = PSRAM_SP_TOP; 1044*036935a8SXiaoDong Huang psram_sleep_cfg->ddr_func = (uint64_t)ddr_resume; 1045*036935a8SXiaoDong Huang psram_sleep_cfg->ddr_data = 0; 1046*036935a8SXiaoDong Huang psram_sleep_cfg->ddr_flag = 0; 1047*036935a8SXiaoDong Huang psram_sleep_cfg->boot_mpidr = read_mpidr_el1() & 0xffff; 1048*036935a8SXiaoDong Huang psram_sleep_cfg->pm_flag = PM_WARM_BOOT_BIT; 1049*036935a8SXiaoDong Huang 1050*036935a8SXiaoDong Huang nonboot_cpus_off(); 1051*036935a8SXiaoDong Huang 1052*036935a8SXiaoDong Huang /* 1053*036935a8SXiaoDong Huang * When perform idle operation, corresponding clock can be 1054*036935a8SXiaoDong Huang * opened or gated automatically. 1055*036935a8SXiaoDong Huang */ 1056*036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_NOC_AUTO_CON(0), 0xffffffff); 1057*036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_NOC_AUTO_CON(1), 0xffffffff); 1058*036935a8SXiaoDong Huang 1059*036935a8SXiaoDong Huang /* remap pmusram to 0x00000000 */ 1060*036935a8SXiaoDong Huang mmio_write_32(PMU0SGRF_BASE + PMU0SGRF_SOC_CON(2), BITS_WITH_WMASK(1, 0x3, 0)); 1061*036935a8SXiaoDong Huang 1062*036935a8SXiaoDong Huang /* enable power off VD_NPU by hrdware */ 1063*036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_VOL_GATE_SFTCON(0), 1064*036935a8SXiaoDong Huang BITS_WITH_WMASK(0x1, 0x1, 0)); 1065*036935a8SXiaoDong Huang 1066*036935a8SXiaoDong Huang rockchip_pmu_pd_repair_init(); 1067*036935a8SXiaoDong Huang 1068*036935a8SXiaoDong Huang pm_reg_rgns_init(); 1069*036935a8SXiaoDong Huang } 1070