1036935a8SXiaoDong Huang // SPDX-License-Identifier: BSD-3-Clause 2036935a8SXiaoDong Huang /* 3036935a8SXiaoDong Huang * Copyright (c) 2025, Rockchip Electronics Co., Ltd. 4036935a8SXiaoDong Huang */ 5036935a8SXiaoDong Huang 6036935a8SXiaoDong Huang #include <assert.h> 7036935a8SXiaoDong Huang #include <errno.h> 8036935a8SXiaoDong Huang 9036935a8SXiaoDong Huang #include <arch_helpers.h> 10036935a8SXiaoDong Huang #include <bl31/bl31.h> 11036935a8SXiaoDong Huang #include <common/debug.h> 12036935a8SXiaoDong Huang #include <drivers/console.h> 13036935a8SXiaoDong Huang #include <drivers/delay_timer.h> 14036935a8SXiaoDong Huang #include <lib/mmio.h> 15036935a8SXiaoDong Huang #include <plat/common/platform.h> 16036935a8SXiaoDong Huang #include <platform_def.h> 17036935a8SXiaoDong Huang #include <pmu.h> 18036935a8SXiaoDong Huang 19036935a8SXiaoDong Huang #include <cpus_on_fixed_addr.h> 20036935a8SXiaoDong Huang #include <dmc_rk3576.h> 21036935a8SXiaoDong Huang #include <plat_pm_helpers.h> 22036935a8SXiaoDong Huang #include <plat_private.h> 23036935a8SXiaoDong Huang #include <pm_pd_regs.h> 24036935a8SXiaoDong Huang #include <secure.h> 25036935a8SXiaoDong Huang #include <soc.h> 26036935a8SXiaoDong Huang 27036935a8SXiaoDong Huang static struct psram_data_t *psram_sleep_cfg = 28036935a8SXiaoDong Huang (struct psram_data_t *)&sys_sleep_flag_sram; 29036935a8SXiaoDong Huang 30036935a8SXiaoDong Huang struct rk3576_sleep_ddr_data { 31036935a8SXiaoDong Huang uint32_t cru_mode_con, secure_cru_mode; 32036935a8SXiaoDong Huang uint32_t gpio0a_iomux_l, gpio0a_iomux_h, gpio0b_iomux_l; 33036935a8SXiaoDong Huang uint32_t pmu2_bisr_glb_con; 34036935a8SXiaoDong Huang uint32_t pmu2_c0_ack_sel_con0, pmu2_c1_ack_sel_con0, pmu2_c2_ack_sel_con0; 35036935a8SXiaoDong Huang uint32_t pmu2_fast_pwr_con, pmu2_pwrgt_sft_con0; 36036935a8SXiaoDong Huang uint32_t pmu0grf_soc_con0, pmu0grf_soc_con1, pmu0grf_soc_con5; 37036935a8SXiaoDong Huang uint32_t pmu_pd_st, bus_idle_st; 38036935a8SXiaoDong Huang uint32_t sys_sgrf_soc_con0; 39036935a8SXiaoDong Huang uint32_t ddrgrf_cha_con2, ddrgrf_chb_con2; 40036935a8SXiaoDong Huang }; 41036935a8SXiaoDong Huang 42036935a8SXiaoDong Huang static struct rk3576_sleep_ddr_data ddr_data; 43036935a8SXiaoDong Huang 44036935a8SXiaoDong Huang void rockchip_plat_mmu_el3(void) 45036935a8SXiaoDong Huang { 46036935a8SXiaoDong Huang #ifdef PLAT_EXTRA_LD_SCRIPT 47036935a8SXiaoDong Huang size_t sram_size; 48036935a8SXiaoDong Huang 49036935a8SXiaoDong Huang sram_size = (char *)&__bl31_pmusram_text_end - 50036935a8SXiaoDong Huang (char *)PMUSRAM_BASE; 51036935a8SXiaoDong Huang mmap_add_region(PMUSRAM_BASE, PMUSRAM_BASE, 52036935a8SXiaoDong Huang sram_size, MT_MEMORY | MT_RO | MT_SECURE); 53036935a8SXiaoDong Huang 54036935a8SXiaoDong Huang sram_size = (char *)&__bl31_pmusram_data_end - 55036935a8SXiaoDong Huang (char *)&__bl31_pmusram_data_start; 56036935a8SXiaoDong Huang mmap_add_region((unsigned long)&__bl31_pmusram_data_start, 57036935a8SXiaoDong Huang (unsigned long)&__bl31_pmusram_data_start, 58036935a8SXiaoDong Huang sram_size, MT_DEVICE | MT_RW | MT_SECURE); 59036935a8SXiaoDong Huang #endif 60036935a8SXiaoDong Huang } 61036935a8SXiaoDong Huang 62036935a8SXiaoDong Huang static int check_cpu_wfie(uint32_t cpu) 63036935a8SXiaoDong Huang { 64036935a8SXiaoDong Huang uint32_t loop = 0; 65036935a8SXiaoDong Huang 66036935a8SXiaoDong Huang while ((mmio_read_32(SYS_GRF_BASE + SYSGRF_STATUS0) & BIT(cpu + 12)) == 0 && 67036935a8SXiaoDong Huang (mmio_read_32(PMU_BASE + PMU2_CLUSTER_PWR_ST) & BIT(cpu)) == 0 && 68036935a8SXiaoDong Huang (loop < WFEI_CHECK_LOOP)) { 69036935a8SXiaoDong Huang udelay(1); 70036935a8SXiaoDong Huang loop++; 71036935a8SXiaoDong Huang } 72036935a8SXiaoDong Huang 73036935a8SXiaoDong Huang if (loop >= WFEI_CHECK_LOOP) { 74036935a8SXiaoDong Huang WARN("%s: error, cpu%d (0x%x 0x%x)!\n", __func__, cpu, 75036935a8SXiaoDong Huang mmio_read_32(SYS_GRF_BASE + SYSGRF_STATUS0), 76036935a8SXiaoDong Huang mmio_read_32(PMU_BASE + PMU2_CLUSTER_PWR_ST)); 77036935a8SXiaoDong Huang return -EINVAL; 78036935a8SXiaoDong Huang } 79036935a8SXiaoDong Huang 80036935a8SXiaoDong Huang return 0; 81036935a8SXiaoDong Huang } 82036935a8SXiaoDong Huang 83036935a8SXiaoDong Huang static inline uint32_t cpu_power_domain_st(uint32_t cpu) 84036935a8SXiaoDong Huang { 85036935a8SXiaoDong Huang return !!(mmio_read_32(PMU_BASE + PMU2_CLUSTER_PWR_ST) & 86036935a8SXiaoDong Huang BIT(cpu + 16)); 87036935a8SXiaoDong Huang } 88036935a8SXiaoDong Huang 89036935a8SXiaoDong Huang static int cpu_power_domain_ctr(uint32_t cpu, uint32_t pd_state) 90036935a8SXiaoDong Huang { 91036935a8SXiaoDong Huang uint32_t loop = 0; 92036935a8SXiaoDong Huang int ret = 0; 93036935a8SXiaoDong Huang 94036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_CPU_PWR_SFTCON(cpu), 95036935a8SXiaoDong Huang BITS_WITH_WMASK(pd_state, 0x1, 0)); 96036935a8SXiaoDong Huang 97036935a8SXiaoDong Huang dsb(); 98036935a8SXiaoDong Huang while ((cpu_power_domain_st(cpu) != pd_state) && (loop < PD_CTR_LOOP)) { 99036935a8SXiaoDong Huang udelay(1); 100036935a8SXiaoDong Huang loop++; 101036935a8SXiaoDong Huang } 102036935a8SXiaoDong Huang 103036935a8SXiaoDong Huang if (cpu_power_domain_st(cpu) != pd_state) { 104036935a8SXiaoDong Huang WARN("%s: %d, %d, error!\n", __func__, cpu, pd_state); 105036935a8SXiaoDong Huang ret = -EINVAL; 106036935a8SXiaoDong Huang } 107036935a8SXiaoDong Huang 108036935a8SXiaoDong Huang return ret; 109036935a8SXiaoDong Huang } 110036935a8SXiaoDong Huang 111036935a8SXiaoDong Huang static inline uint32_t get_cpus_pwr_domain_cfg_info(uint32_t cpu_id) 112036935a8SXiaoDong Huang { 113036935a8SXiaoDong Huang uint32_t val; 114036935a8SXiaoDong Huang 115036935a8SXiaoDong Huang if ((mmio_read_32(PMU_BASE + PMU2_CPU_PWR_SFTCON(cpu_id)) & BIT(0)) != 0) 116036935a8SXiaoDong Huang return core_pwr_pd; 117036935a8SXiaoDong Huang 118036935a8SXiaoDong Huang val = mmio_read_32(PMU_BASE + PMU2_CPU_AUTO_PWR_CON(cpu_id)); 119036935a8SXiaoDong Huang if ((val & BIT(pmu_cpu_pm_en)) != 0) { 120036935a8SXiaoDong Huang if ((val & BIT(core_pwr_wfi_int)) != 0) 121036935a8SXiaoDong Huang return core_pwr_wfi_int; 122036935a8SXiaoDong Huang else if ((val & BIT(pmu_cpu_pm_sft_wakeup_en)) != 0) 123036935a8SXiaoDong Huang return core_pwr_wfi_reset; 124036935a8SXiaoDong Huang else 125036935a8SXiaoDong Huang return core_pwr_wfi; 126036935a8SXiaoDong Huang } else { 127036935a8SXiaoDong Huang return -1; 128036935a8SXiaoDong Huang } 129036935a8SXiaoDong Huang } 130036935a8SXiaoDong Huang 131036935a8SXiaoDong Huang static inline void set_cpus_pwr_domain_cfg_info(uint32_t cpu_id, uint32_t value) 132036935a8SXiaoDong Huang { 133036935a8SXiaoDong Huang } 134036935a8SXiaoDong Huang 135036935a8SXiaoDong Huang static int cpus_power_domain_on(uint32_t cpu_id) 136036935a8SXiaoDong Huang { 137036935a8SXiaoDong Huang uint32_t cfg_info; 138036935a8SXiaoDong Huang /* 139036935a8SXiaoDong Huang * There are two ways to powering on or off on core. 140036935a8SXiaoDong Huang * 1) Control it power domain into on or off in PMU_PWRDN_CON reg 141036935a8SXiaoDong Huang * 2) Enable the core power manage in PMU_CORE_PM_CON reg, 142036935a8SXiaoDong Huang * then, if the core enter into wfi, it power domain will be 143036935a8SXiaoDong Huang * powered off automatically. 144036935a8SXiaoDong Huang */ 145036935a8SXiaoDong Huang 146036935a8SXiaoDong Huang cfg_info = get_cpus_pwr_domain_cfg_info(cpu_id); 147036935a8SXiaoDong Huang 148036935a8SXiaoDong Huang if (cfg_info == core_pwr_pd) { 149036935a8SXiaoDong Huang /* disable core_pm cfg */ 150036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_CPU_AUTO_PWR_CON(cpu_id), 151036935a8SXiaoDong Huang BITS_WITH_WMASK(0, 0xf, 0)); 152036935a8SXiaoDong Huang /* if the cores have be on, power off it firstly */ 153036935a8SXiaoDong Huang if (cpu_power_domain_st(cpu_id) == pmu_pd_on) 154036935a8SXiaoDong Huang cpu_power_domain_ctr(cpu_id, pmu_pd_off); 155036935a8SXiaoDong Huang 156036935a8SXiaoDong Huang cpu_power_domain_ctr(cpu_id, pmu_pd_on); 157036935a8SXiaoDong Huang } else { 158036935a8SXiaoDong Huang if (cpu_power_domain_st(cpu_id) == pmu_pd_on) { 159036935a8SXiaoDong Huang WARN("%s: cpu%d is not in off,!\n", __func__, cpu_id); 160036935a8SXiaoDong Huang return -EINVAL; 161036935a8SXiaoDong Huang } 162036935a8SXiaoDong Huang 163036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_CPU_AUTO_PWR_CON(cpu_id), 164036935a8SXiaoDong Huang BITS_WITH_WMASK(1, 0x1, pmu_cpu_pm_sft_wakeup_en)); 165036935a8SXiaoDong Huang dsb(); 166036935a8SXiaoDong Huang } 167036935a8SXiaoDong Huang 168036935a8SXiaoDong Huang return 0; 169036935a8SXiaoDong Huang } 170036935a8SXiaoDong Huang 171036935a8SXiaoDong Huang static int cpus_power_domain_off(uint32_t cpu_id, uint32_t pd_cfg) 172036935a8SXiaoDong Huang { 173036935a8SXiaoDong Huang uint32_t core_pm_value; 174036935a8SXiaoDong Huang 175036935a8SXiaoDong Huang if (cpu_power_domain_st(cpu_id) == pmu_pd_off) 176036935a8SXiaoDong Huang return 0; 177036935a8SXiaoDong Huang 178036935a8SXiaoDong Huang if (pd_cfg == core_pwr_pd) { 179036935a8SXiaoDong Huang if (check_cpu_wfie(cpu_id)) 180036935a8SXiaoDong Huang return -EINVAL; 181036935a8SXiaoDong Huang 182036935a8SXiaoDong Huang /* disable core_pm cfg */ 183036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_CPU_AUTO_PWR_CON(cpu_id), 184036935a8SXiaoDong Huang BITS_WITH_WMASK(0, 0xf, 0)); 185036935a8SXiaoDong Huang 186036935a8SXiaoDong Huang set_cpus_pwr_domain_cfg_info(cpu_id, pd_cfg); 187036935a8SXiaoDong Huang cpu_power_domain_ctr(cpu_id, pmu_pd_off); 188036935a8SXiaoDong Huang } else { 189036935a8SXiaoDong Huang set_cpus_pwr_domain_cfg_info(cpu_id, pd_cfg); 190036935a8SXiaoDong Huang 191036935a8SXiaoDong Huang core_pm_value = BIT(pmu_cpu_pm_en) | BIT(pmu_cpu_pm_dis_int); 192036935a8SXiaoDong Huang if (pd_cfg == core_pwr_wfi_int) 193036935a8SXiaoDong Huang core_pm_value |= BIT(pmu_cpu_pm_int_wakeup_en); 194036935a8SXiaoDong Huang else if (pd_cfg == core_pwr_wfi_reset) 195036935a8SXiaoDong Huang core_pm_value |= BIT(pmu_cpu_pm_sft_wakeup_en); 196036935a8SXiaoDong Huang 197036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_CPU_AUTO_PWR_CON(cpu_id), 198036935a8SXiaoDong Huang BITS_WITH_WMASK(core_pm_value, 0xf, 0)); 199036935a8SXiaoDong Huang dsb(); 200036935a8SXiaoDong Huang } 201036935a8SXiaoDong Huang 202036935a8SXiaoDong Huang return 0; 203036935a8SXiaoDong Huang } 204036935a8SXiaoDong Huang 205036935a8SXiaoDong Huang int rockchip_soc_cores_pwr_dm_on(unsigned long mpidr, uint64_t entrypoint) 206036935a8SXiaoDong Huang { 207036935a8SXiaoDong Huang uint32_t cpu_id = plat_core_pos_by_mpidr(mpidr); 208036935a8SXiaoDong Huang 209036935a8SXiaoDong Huang assert(cpu_id < PLATFORM_CORE_COUNT); 210036935a8SXiaoDong Huang assert(cpuson_flags[cpu_id] == 0); 211036935a8SXiaoDong Huang cpuson_flags[cpu_id] = PMU_CPU_HOTPLUG; 212036935a8SXiaoDong Huang cpuson_entry_point[cpu_id] = entrypoint; 213036935a8SXiaoDong Huang dsb(); 214036935a8SXiaoDong Huang 215036935a8SXiaoDong Huang cpus_power_domain_on(cpu_id); 216036935a8SXiaoDong Huang 217036935a8SXiaoDong Huang return PSCI_E_SUCCESS; 218036935a8SXiaoDong Huang } 219036935a8SXiaoDong Huang 220036935a8SXiaoDong Huang int rockchip_soc_cores_pwr_dm_off(void) 221036935a8SXiaoDong Huang { 222036935a8SXiaoDong Huang uint32_t cpu_id = plat_my_core_pos(); 223036935a8SXiaoDong Huang 224036935a8SXiaoDong Huang cpus_power_domain_off(cpu_id, core_pwr_wfi); 225036935a8SXiaoDong Huang 226036935a8SXiaoDong Huang return PSCI_E_SUCCESS; 227036935a8SXiaoDong Huang } 228036935a8SXiaoDong Huang 229036935a8SXiaoDong Huang int rockchip_soc_cores_pwr_dm_on_finish(void) 230036935a8SXiaoDong Huang { 231036935a8SXiaoDong Huang uint32_t cpu_id = plat_my_core_pos(); 232036935a8SXiaoDong Huang 233036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_CPU_AUTO_PWR_CON(cpu_id), 234036935a8SXiaoDong Huang BITS_WITH_WMASK(0, 0xf, 0)); 235036935a8SXiaoDong Huang 236036935a8SXiaoDong Huang return PSCI_E_SUCCESS; 237036935a8SXiaoDong Huang } 238036935a8SXiaoDong Huang 239036935a8SXiaoDong Huang int rockchip_soc_cores_pwr_dm_suspend(void) 240036935a8SXiaoDong Huang { 241036935a8SXiaoDong Huang uint32_t cpu_id = plat_my_core_pos(); 242036935a8SXiaoDong Huang 243036935a8SXiaoDong Huang assert(cpu_id < PLATFORM_CORE_COUNT); 244036935a8SXiaoDong Huang assert(cpuson_flags[cpu_id] == 0); 245036935a8SXiaoDong Huang cpuson_flags[cpu_id] = PMU_CPU_AUTO_PWRDN; 246036935a8SXiaoDong Huang cpuson_entry_point[cpu_id] = plat_get_sec_entrypoint(); 247036935a8SXiaoDong Huang dsb(); 248036935a8SXiaoDong Huang 249036935a8SXiaoDong Huang cpus_power_domain_off(cpu_id, core_pwr_wfi_int); 250036935a8SXiaoDong Huang 251036935a8SXiaoDong Huang return PSCI_E_SUCCESS; 252036935a8SXiaoDong Huang } 253036935a8SXiaoDong Huang 254036935a8SXiaoDong Huang int rockchip_soc_cores_pwr_dm_resume(void) 255036935a8SXiaoDong Huang { 256036935a8SXiaoDong Huang uint32_t cpu_id = plat_my_core_pos(); 257036935a8SXiaoDong Huang 258036935a8SXiaoDong Huang /* Disable core_pm */ 259036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_CPU_AUTO_PWR_CON(cpu_id), 260036935a8SXiaoDong Huang BITS_WITH_WMASK(0, 0xf, 0)); 261036935a8SXiaoDong Huang 262036935a8SXiaoDong Huang return PSCI_E_SUCCESS; 263036935a8SXiaoDong Huang } 264036935a8SXiaoDong Huang 265036935a8SXiaoDong Huang void nonboot_cpus_off(void) 266036935a8SXiaoDong Huang { 267036935a8SXiaoDong Huang uint32_t boot_cpu, cpu; 268036935a8SXiaoDong Huang 269036935a8SXiaoDong Huang boot_cpu = plat_my_core_pos(); 270036935a8SXiaoDong Huang 271036935a8SXiaoDong Huang /* turn off noboot cpus */ 272036935a8SXiaoDong Huang for (cpu = 0; cpu < PLATFORM_CORE_COUNT; cpu++) { 273036935a8SXiaoDong Huang if (cpu == boot_cpu) 274036935a8SXiaoDong Huang continue; 275036935a8SXiaoDong Huang 276036935a8SXiaoDong Huang cpus_power_domain_off(cpu, core_pwr_pd); 277036935a8SXiaoDong Huang } 278036935a8SXiaoDong Huang } 279036935a8SXiaoDong Huang 280036935a8SXiaoDong Huang static __pmusramfunc void ddr_resume(void) 281036935a8SXiaoDong Huang { 282036935a8SXiaoDong Huang uint32_t key_upd_msk = 283036935a8SXiaoDong Huang mmio_read_32(PMU_BASE + PMU2_PWR_GATE_ST) & BIT(pmu_pd_vop) ? 0x3 : 0x7; 284036935a8SXiaoDong Huang 285036935a8SXiaoDong Huang /* hptimer is 24M here */ 286036935a8SXiaoDong Huang write_cntfrq_el0(24000000); 287036935a8SXiaoDong Huang 288036935a8SXiaoDong Huang /* release cpu1~cpu7 to make pmu1_fsm exit */ 289036935a8SXiaoDong Huang mmio_write_32(CCI_GRF_BASE + CCIGRF_CON(4), 0xffffffff); 290036935a8SXiaoDong Huang mmio_write_32(LITCORE_GRF_BASE + COREGRF_CPU_CON(1), 291036935a8SXiaoDong Huang BITS_WITH_WMASK(0x77, 0xff, 4)); 292036935a8SXiaoDong Huang 293036935a8SXiaoDong Huang /* wait pmu1 fsm over */ 294036935a8SXiaoDong Huang while ((mmio_read_32(PMU_BASE + PMU1_PWR_FSM) & 0xf) != 0) 295036935a8SXiaoDong Huang ; 296036935a8SXiaoDong Huang 297036935a8SXiaoDong Huang /* SOC_CON19.vop/center/cci_ddr_hash_key_update_en */ 298036935a8SXiaoDong Huang mmio_write_32(SYS_SGRF_BASE + SYSSGRF_SOC_CON(19), 0x00070000); 299036935a8SXiaoDong Huang dsb(); 300036935a8SXiaoDong Huang 301036935a8SXiaoDong Huang /* SOC_CON19.vop/center/cci_ddr_hash_key_update_en */ 302036935a8SXiaoDong Huang mmio_write_32(SYS_SGRF_BASE + SYSSGRF_SOC_CON(19), 0x00070000 | key_upd_msk); 303036935a8SXiaoDong Huang 304036935a8SXiaoDong Huang /* SOC_STATUS.center/cci_ddr_hash_key_shift_ready */ 305036935a8SXiaoDong Huang while (((mmio_read_32(SYS_SGRF_BASE + SYSSGRF_SOC_STATUS) >> 12) & key_upd_msk) != key_upd_msk) 306036935a8SXiaoDong Huang ; 307036935a8SXiaoDong Huang 308036935a8SXiaoDong Huang /* CCI_BASE.ctrl_override_reg Attr:W1C addrmap strobe */ 309036935a8SXiaoDong Huang mmio_setbits_32(CCI_BASE + 0x0, 0x1 << 29); 310036935a8SXiaoDong Huang 311036935a8SXiaoDong Huang /* SOC_CON19.vop/center/cci_ddr_hash_key_auto_update_en */ 312036935a8SXiaoDong Huang mmio_write_32(SYS_SGRF_BASE + SYSSGRF_SOC_CON(19), 0x00700070); 313036935a8SXiaoDong Huang } 314036935a8SXiaoDong Huang 315036935a8SXiaoDong Huang static uint32_t clk_save[CRU_CLKGATE_CON_CNT + PHP_CRU_CLKGATE_CON_CNT + 316036935a8SXiaoDong Huang SECURE_CRU_CLKGATE_CON_CNT + SECURE_SCRU_CLKGATE_CON_CNT + 317036935a8SXiaoDong Huang PMU1CRU_CLKGATE_CON_CNT + PMU1SCRU_CLKGATE_CON_CNT]; 318036935a8SXiaoDong Huang 319036935a8SXiaoDong Huang void clk_gate_con_disable(void) 320036935a8SXiaoDong Huang { 321036935a8SXiaoDong Huang int i; 322036935a8SXiaoDong Huang 323036935a8SXiaoDong Huang for (i = 0; i < CRU_CLKGATE_CON_CNT; i++) { 324036935a8SXiaoDong Huang /* Don't open wdt0 clk (cru_gate16[7:8] */ 325036935a8SXiaoDong Huang if (i == 16) { 326036935a8SXiaoDong Huang mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(i), 327036935a8SXiaoDong Huang 0xfe7f0000); 328036935a8SXiaoDong Huang } else { 329036935a8SXiaoDong Huang mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(i), 330036935a8SXiaoDong Huang 0xffff0000); 331036935a8SXiaoDong Huang } 332036935a8SXiaoDong Huang } 333036935a8SXiaoDong Huang 334036935a8SXiaoDong Huang for (i = 0; i < PHP_CRU_CLKGATE_CON_CNT; i++) 335036935a8SXiaoDong Huang mmio_write_32(PHP_CRU_BASE + PHP_CRU_CLKGATE_CON(i), 0xffff0000); 336036935a8SXiaoDong Huang 337036935a8SXiaoDong Huang for (i = 0; i < SECURE_CRU_CLKGATE_CON_CNT; i++) 338036935a8SXiaoDong Huang mmio_write_32(SECURE_CRU_BASE + SECURE_CRU_CLKGATE_CON(i), 0xffff0000); 339036935a8SXiaoDong Huang 340036935a8SXiaoDong Huang for (i = 0; i < SECURE_SCRU_CLKGATE_CON_CNT; i++) 341036935a8SXiaoDong Huang mmio_write_32(SECURE_CRU_BASE + SECURE_SCRU_CLKGATE_CON(i), 0xffff0000); 342036935a8SXiaoDong Huang 343036935a8SXiaoDong Huang for (i = 0; i < PMU1CRU_CLKGATE_CON_CNT; i++) 344036935a8SXiaoDong Huang mmio_write_32(PMU1_CRU_BASE + PMU1CRU_CLKGATE_CON(i), 0xffff0000); 345036935a8SXiaoDong Huang 346036935a8SXiaoDong Huang for (i = 0; i < PMU1SCRU_CLKGATE_CON_CNT; i++) 347036935a8SXiaoDong Huang mmio_write_32(PMU1_CRU_BASE + PMU1SCRU_CLKGATE_CON(i), 0xffff0000); 348036935a8SXiaoDong Huang } 349036935a8SXiaoDong Huang 350036935a8SXiaoDong Huang void clk_gate_con_save(void) 351036935a8SXiaoDong Huang { 352036935a8SXiaoDong Huang int i, j = 0; 353036935a8SXiaoDong Huang 354036935a8SXiaoDong Huang for (i = 0; i < CRU_CLKGATE_CON_CNT; i++, j++) 355036935a8SXiaoDong Huang clk_save[j] = mmio_read_32(CRU_BASE + CRU_CLKGATE_CON(i)); 356036935a8SXiaoDong Huang 357036935a8SXiaoDong Huang for (i = 0; i < PHP_CRU_CLKGATE_CON_CNT; i++, j++) 358036935a8SXiaoDong Huang clk_save[j] = mmio_read_32(PHP_CRU_BASE + PHP_CRU_CLKGATE_CON(i)); 359036935a8SXiaoDong Huang 360036935a8SXiaoDong Huang for (i = 0; i < SECURE_CRU_CLKGATE_CON_CNT; i++, j++) 361036935a8SXiaoDong Huang clk_save[j] = mmio_read_32(SECURE_CRU_BASE + SECURE_CRU_CLKGATE_CON(i)); 362036935a8SXiaoDong Huang 363036935a8SXiaoDong Huang for (i = 0; i < SECURE_SCRU_CLKGATE_CON_CNT; i++, j++) 364036935a8SXiaoDong Huang clk_save[j] = mmio_read_32(SECURE_CRU_BASE + SECURE_SCRU_CLKGATE_CON(i)); 365036935a8SXiaoDong Huang 366036935a8SXiaoDong Huang for (i = 0; i < PMU1CRU_CLKGATE_CON_CNT; i++, j++) 367036935a8SXiaoDong Huang clk_save[j] = mmio_read_32(PMU1_CRU_BASE + PMU1CRU_CLKGATE_CON(i)); 368036935a8SXiaoDong Huang 369036935a8SXiaoDong Huang for (i = 0; i < PMU1SCRU_CLKGATE_CON_CNT; i++, j++) 370036935a8SXiaoDong Huang clk_save[j] = mmio_read_32(PMU1_CRU_BASE + PMU1SCRU_CLKGATE_CON(i)); 371036935a8SXiaoDong Huang } 372036935a8SXiaoDong Huang 373036935a8SXiaoDong Huang void clk_gate_con_restore(void) 374036935a8SXiaoDong Huang { 375036935a8SXiaoDong Huang int i, j = 0; 376036935a8SXiaoDong Huang 377036935a8SXiaoDong Huang for (i = 0; i < CRU_CLKGATE_CON_CNT; i++, j++) 378036935a8SXiaoDong Huang mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(i), 379036935a8SXiaoDong Huang WITH_16BITS_WMSK(clk_save[j])); 380036935a8SXiaoDong Huang 381036935a8SXiaoDong Huang for (i = 0; i < PHP_CRU_CLKGATE_CON_CNT; i++, j++) 382036935a8SXiaoDong Huang mmio_write_32(PHP_CRU_BASE + PHP_CRU_CLKGATE_CON(i), 383036935a8SXiaoDong Huang WITH_16BITS_WMSK(clk_save[j])); 384036935a8SXiaoDong Huang 385036935a8SXiaoDong Huang for (i = 0; i < SECURE_CRU_CLKGATE_CON_CNT; i++, j++) 386036935a8SXiaoDong Huang mmio_write_32(SECURE_CRU_BASE + SECURE_CRU_CLKGATE_CON(i), 387036935a8SXiaoDong Huang WITH_16BITS_WMSK(clk_save[j])); 388036935a8SXiaoDong Huang 389036935a8SXiaoDong Huang for (i = 0; i < SECURE_SCRU_CLKGATE_CON_CNT; i++, j++) 390036935a8SXiaoDong Huang mmio_write_32(SECURE_CRU_BASE + SECURE_SCRU_CLKGATE_CON(i), 391036935a8SXiaoDong Huang WITH_16BITS_WMSK(clk_save[j])); 392036935a8SXiaoDong Huang 393036935a8SXiaoDong Huang for (i = 0; i < PMU1CRU_CLKGATE_CON_CNT; i++, j++) 394036935a8SXiaoDong Huang mmio_write_32(PMU1_CRU_BASE + PMU1CRU_CLKGATE_CON(i), 395036935a8SXiaoDong Huang WITH_16BITS_WMSK(clk_save[j])); 396036935a8SXiaoDong Huang 397036935a8SXiaoDong Huang for (i = 0; i < PMU1SCRU_CLKGATE_CON_CNT; i++, j++) 398036935a8SXiaoDong Huang mmio_write_32(PMU1_CRU_BASE + PMU1SCRU_CLKGATE_CON(i), 399036935a8SXiaoDong Huang WITH_16BITS_WMSK(clk_save[j])); 400036935a8SXiaoDong Huang } 401036935a8SXiaoDong Huang 402036935a8SXiaoDong Huang void pmu_bus_idle_req(uint32_t bus, uint32_t state) 403036935a8SXiaoDong Huang { 404036935a8SXiaoDong Huang uint32_t wait_cnt = 0; 405036935a8SXiaoDong Huang 406036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_BUS_IDLE_SFTCON(bus / 16), 407036935a8SXiaoDong Huang BITS_WITH_WMASK(state, 0x1, bus % 16)); 408036935a8SXiaoDong Huang 409036935a8SXiaoDong Huang while (pmu_bus_idle_st(bus) != state || 410036935a8SXiaoDong Huang pmu_bus_idle_ack(bus) != state) { 411036935a8SXiaoDong Huang if (++wait_cnt > BUS_IDLE_LOOP) 412036935a8SXiaoDong Huang break; 413036935a8SXiaoDong Huang udelay(1); 414036935a8SXiaoDong Huang } 415036935a8SXiaoDong Huang 416036935a8SXiaoDong Huang if (wait_cnt > BUS_IDLE_LOOP) 417036935a8SXiaoDong Huang WARN("%s: can't wait state %d for bus %d (0x%x)\n", 418036935a8SXiaoDong Huang __func__, state, bus, 419036935a8SXiaoDong Huang mmio_read_32(PMU_BASE + PMU2_BUS_IDLE_ST)); 420036935a8SXiaoDong Huang } 421036935a8SXiaoDong Huang 422036935a8SXiaoDong Huang static inline uint32_t pmu_power_domain_st(uint32_t pd) 423036935a8SXiaoDong Huang { 424036935a8SXiaoDong Huang return mmio_read_32(PMU_BASE + PMU2_PWR_GATE_ST) & BIT(pd) ? 425036935a8SXiaoDong Huang pmu_pd_off : 426036935a8SXiaoDong Huang pmu_pd_on; 427036935a8SXiaoDong Huang } 428036935a8SXiaoDong Huang 429036935a8SXiaoDong Huang int pmu_power_domain_ctr(uint32_t pd, uint32_t pd_state) 430036935a8SXiaoDong Huang { 431036935a8SXiaoDong Huang uint32_t loop = 0; 432036935a8SXiaoDong Huang int ret = 0; 433036935a8SXiaoDong Huang 434036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_PWR_GATE_SFTCON(pd / 16), 435036935a8SXiaoDong Huang BITS_WITH_WMASK(pd_state, 0x1, pd % 16)); 436036935a8SXiaoDong Huang dsb(); 437036935a8SXiaoDong Huang 438036935a8SXiaoDong Huang while ((pmu_power_domain_st(pd) != pd_state) && (loop < PD_CTR_LOOP)) { 439036935a8SXiaoDong Huang udelay(1); 440036935a8SXiaoDong Huang loop++; 441036935a8SXiaoDong Huang } 442036935a8SXiaoDong Huang 443036935a8SXiaoDong Huang if (pmu_power_domain_st(pd) != pd_state) { 444036935a8SXiaoDong Huang WARN("%s: %d, %d, (0x%x) error!\n", __func__, pd, pd_state, 445036935a8SXiaoDong Huang mmio_read_32(PMU_BASE + PMU2_PWR_GATE_ST)); 446036935a8SXiaoDong Huang ret = -EINVAL; 447036935a8SXiaoDong Huang } 448036935a8SXiaoDong Huang 449036935a8SXiaoDong Huang return ret; 450036935a8SXiaoDong Huang } 451036935a8SXiaoDong Huang 452036935a8SXiaoDong Huang static int pmu_set_power_domain(uint32_t pd_id, uint32_t pd_state) 453036935a8SXiaoDong Huang { 454036935a8SXiaoDong Huang uint32_t state; 455036935a8SXiaoDong Huang 456036935a8SXiaoDong Huang if (pmu_power_domain_st(pd_id) == pd_state) 457036935a8SXiaoDong Huang goto out; 458036935a8SXiaoDong Huang 459036935a8SXiaoDong Huang if (pd_state == pmu_pd_on) 460036935a8SXiaoDong Huang pmu_power_domain_ctr(pd_id, pd_state); 461036935a8SXiaoDong Huang 462036935a8SXiaoDong Huang state = (pd_state == pmu_pd_off) ? pmu_bus_idle : pmu_bus_active; 463036935a8SXiaoDong Huang 464036935a8SXiaoDong Huang switch (pd_id) { 465036935a8SXiaoDong Huang case pmu_pd_npu: 466036935a8SXiaoDong Huang pmu_bus_idle_req(pmu_bus_id_npusys, state); 467036935a8SXiaoDong Huang break; 468036935a8SXiaoDong Huang case pmu_pd_secure: 469036935a8SXiaoDong Huang pmu_bus_idle_req(pmu_bus_id_secure, state); 470036935a8SXiaoDong Huang break; 471036935a8SXiaoDong Huang case pmu_pd_nvm: 472036935a8SXiaoDong Huang pmu_bus_idle_req(pmu_bus_id_nvm, state); 473036935a8SXiaoDong Huang break; 474036935a8SXiaoDong Huang case pmu_pd_sd_gmac: 475036935a8SXiaoDong Huang pmu_bus_idle_req(pmu_bus_id_gmac, state); 476036935a8SXiaoDong Huang break; 477036935a8SXiaoDong Huang case pmu_pd_audio: 478036935a8SXiaoDong Huang pmu_bus_idle_req(pmu_bus_id_audio, state); 479036935a8SXiaoDong Huang break; 480036935a8SXiaoDong Huang case pmu_pd_php: 481036935a8SXiaoDong Huang pmu_bus_idle_req(pmu_bus_id_php, state); 482036935a8SXiaoDong Huang break; 483036935a8SXiaoDong Huang case pmu_pd_subphp: 484036935a8SXiaoDong Huang break; 485036935a8SXiaoDong Huang case pmu_pd_vop: 486036935a8SXiaoDong Huang pmu_bus_idle_req(pmu_bus_id_vop, state); 487036935a8SXiaoDong Huang break; 488036935a8SXiaoDong Huang case pmu_pd_vop_smart: 489036935a8SXiaoDong Huang break; 490036935a8SXiaoDong Huang case pmu_pd_vop_clst: 491036935a8SXiaoDong Huang break; 492036935a8SXiaoDong Huang case pmu_pd_vo1: 493036935a8SXiaoDong Huang pmu_bus_idle_req(pmu_bus_id_vo1, state); 494036935a8SXiaoDong Huang break; 495036935a8SXiaoDong Huang case pmu_pd_vo0: 496036935a8SXiaoDong Huang pmu_bus_idle_req(pmu_bus_id_vo0, state); 497036935a8SXiaoDong Huang break; 498036935a8SXiaoDong Huang case pmu_pd_usb: 499036935a8SXiaoDong Huang pmu_bus_idle_req(pmu_bus_id_usb, state); 500036935a8SXiaoDong Huang break; 501036935a8SXiaoDong Huang case pmu_pd_vi: 502036935a8SXiaoDong Huang pmu_bus_idle_req(pmu_bus_id_vi, state); 503036935a8SXiaoDong Huang break; 504036935a8SXiaoDong Huang case pmu_pd_vepu0: 505036935a8SXiaoDong Huang pmu_bus_idle_req(pmu_bus_id_vepu0, state); 506036935a8SXiaoDong Huang break; 507036935a8SXiaoDong Huang case pmu_pd_vepu1: 508036935a8SXiaoDong Huang pmu_bus_idle_req(pmu_bus_id_vepu1, state); 509036935a8SXiaoDong Huang break; 510036935a8SXiaoDong Huang case pmu_pd_vdec: 511036935a8SXiaoDong Huang pmu_bus_idle_req(pmu_bus_id_vdec, state); 512036935a8SXiaoDong Huang break; 513036935a8SXiaoDong Huang case pmu_pd_vpu: 514036935a8SXiaoDong Huang pmu_bus_idle_req(pmu_bus_id_vpu, state); 515036935a8SXiaoDong Huang break; 516036935a8SXiaoDong Huang case pmu_pd_nputop: 517036935a8SXiaoDong Huang pmu_bus_idle_req(pmu_bus_id_nputop, state); 518036935a8SXiaoDong Huang break; 519036935a8SXiaoDong Huang case pmu_pd_npu0: 520036935a8SXiaoDong Huang pmu_bus_idle_req(pmu_bus_id_npu0, state); 521036935a8SXiaoDong Huang break; 522036935a8SXiaoDong Huang case pmu_pd_npu1: 523036935a8SXiaoDong Huang pmu_bus_idle_req(pmu_bus_id_npu1, state); 524036935a8SXiaoDong Huang break; 525036935a8SXiaoDong Huang case pmu_pd_gpu: 526036935a8SXiaoDong Huang pmu_bus_idle_req(pmu_bus_id_gpu, state); 527036935a8SXiaoDong Huang break; 528036935a8SXiaoDong Huang default: 529036935a8SXiaoDong Huang break; 530036935a8SXiaoDong Huang } 531036935a8SXiaoDong Huang 532036935a8SXiaoDong Huang if (pd_state == pmu_pd_off) 533036935a8SXiaoDong Huang pmu_power_domain_ctr(pd_id, pd_state); 534036935a8SXiaoDong Huang 535036935a8SXiaoDong Huang out: 536036935a8SXiaoDong Huang return 0; 537036935a8SXiaoDong Huang } 538036935a8SXiaoDong Huang 539036935a8SXiaoDong Huang static void pmu_power_domains_suspend(void) 540036935a8SXiaoDong Huang { 541036935a8SXiaoDong Huang ddr_data.pmu_pd_st = mmio_read_32(PMU_BASE + PMU2_PWR_GATE_ST); 542036935a8SXiaoDong Huang ddr_data.bus_idle_st = mmio_read_32(PMU_BASE + PMU2_BUS_IDLE_ST); 543036935a8SXiaoDong Huang ddr_data.pmu2_pwrgt_sft_con0 = mmio_read_32(PMU_BASE + PMU2_PWR_GATE_SFTCON(0)); 544036935a8SXiaoDong Huang 545036935a8SXiaoDong Huang qos_save(); 546036935a8SXiaoDong Huang 547036935a8SXiaoDong Huang pd_usb2phy_save(); 548036935a8SXiaoDong Huang 549036935a8SXiaoDong Huang if ((ddr_data.pmu_pd_st & BIT(pmu_pd_php)) == 0) 550036935a8SXiaoDong Huang pd_php_save(); 551036935a8SXiaoDong Huang } 552036935a8SXiaoDong Huang 553036935a8SXiaoDong Huang static void pmu_power_domains_resume(void) 554036935a8SXiaoDong Huang { 555036935a8SXiaoDong Huang int i; 556036935a8SXiaoDong Huang 557036935a8SXiaoDong Huang for (i = 0; i < pmu_pd_id_max; i++) { 558036935a8SXiaoDong Huang /* vop smart/clst pd is not controlled by pmu */ 559036935a8SXiaoDong Huang if (i == pmu_pd_vop_smart || i == pmu_pd_vop_clst) 560036935a8SXiaoDong Huang continue; 561036935a8SXiaoDong Huang 562036935a8SXiaoDong Huang pmu_set_power_domain(i, !!(ddr_data.pmu_pd_st & BIT(i))); 563036935a8SXiaoDong Huang } 564036935a8SXiaoDong Huang 565036935a8SXiaoDong Huang /* restore vop smart/clst pd of pmu2_pwrgt_sft_con0 */ 566036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_PWR_GATE_SFTCON(0), 567036935a8SXiaoDong Huang 0x30000000 | ddr_data.pmu2_pwrgt_sft_con0); 568036935a8SXiaoDong Huang 569036935a8SXiaoDong Huang for (i = pmu_bus_id_max - 1; i >= 0; i--) 570036935a8SXiaoDong Huang pmu_bus_idle_req(i, !!(ddr_data.bus_idle_st & BIT(i))); 571036935a8SXiaoDong Huang 572036935a8SXiaoDong Huang if ((ddr_data.pmu_pd_st & BIT(pmu_pd_php)) == 0) 573036935a8SXiaoDong Huang pd_php_restore(); 574036935a8SXiaoDong Huang 575036935a8SXiaoDong Huang pd_usb2phy_restore(); 576036935a8SXiaoDong Huang 577036935a8SXiaoDong Huang qos_restore(); 578036935a8SXiaoDong Huang } 579036935a8SXiaoDong Huang 580036935a8SXiaoDong Huang static void ddr_sleep_config(void) 581036935a8SXiaoDong Huang { 582036935a8SXiaoDong Huang ddr_data.ddrgrf_cha_con2 = 583036935a8SXiaoDong Huang mmio_read_32(DDR_GRF_BASE + DDRGRF_CHA_CON(2)); 584036935a8SXiaoDong Huang ddr_data.ddrgrf_chb_con2 = 585036935a8SXiaoDong Huang mmio_read_32(DDR_GRF_BASE + DDRGRF_CHB_CON(2)); 586036935a8SXiaoDong Huang 587036935a8SXiaoDong Huang mmio_write_32(DDR_GRF_BASE + DDRGRF_CHA_CON(2), 0x0a000a00); 588036935a8SXiaoDong Huang mmio_write_32(DDR_GRF_BASE + DDRGRF_CHB_CON(2), 0x0a000a00); 589036935a8SXiaoDong Huang } 590036935a8SXiaoDong Huang 591036935a8SXiaoDong Huang static void ddr_sleep_config_restore(void) 592036935a8SXiaoDong Huang { 593036935a8SXiaoDong Huang mmio_write_32(DDR_GRF_BASE + DDRGRF_CHA_CON(2), 594036935a8SXiaoDong Huang WITH_16BITS_WMSK(ddr_data.ddrgrf_cha_con2)); 595036935a8SXiaoDong Huang mmio_write_32(DDR_GRF_BASE + DDRGRF_CHB_CON(2), 596036935a8SXiaoDong Huang WITH_16BITS_WMSK(ddr_data.ddrgrf_chb_con2)); 597036935a8SXiaoDong Huang } 598036935a8SXiaoDong Huang 599036935a8SXiaoDong Huang static void sleep_pin_config(void) 600036935a8SXiaoDong Huang { 601036935a8SXiaoDong Huang /* pwr0 sleep: gpio0_a3 */ 602036935a8SXiaoDong Huang mmio_write_32(PMU0_GRF_BASE + PMU0GRF_SOC_CON(1), 603036935a8SXiaoDong Huang BITS_WITH_WMASK(0x7, 0xf, 0)); 604036935a8SXiaoDong Huang mmio_write_32(PMU0_GRF_BASE + PMU0GRF_SOC_CON(0), 605036935a8SXiaoDong Huang BITS_WITH_WMASK(0, 0x1, 7)); 606036935a8SXiaoDong Huang mmio_write_32(PMU0_IOC_BASE + PMUIO0_IOC_GPIO0A_IOMUX_SEL_L, 607036935a8SXiaoDong Huang BITS_WITH_WMASK(9, 0xfu, 12)); 608036935a8SXiaoDong Huang } 609036935a8SXiaoDong Huang 610036935a8SXiaoDong Huang static void pmu_sleep_config(void) 611036935a8SXiaoDong Huang { 612036935a8SXiaoDong Huang uint32_t pmu1_wkup_int_con; 613036935a8SXiaoDong Huang uint32_t pmu1_pwr_con, pmu1_ddr_pwr_con, pmu1cru_pwr_con, pmu1_pll_pd_con; 614036935a8SXiaoDong Huang uint32_t pmu2_bus_idle_con[2], pmu2_pwr_gt_con[2]; 615036935a8SXiaoDong Huang uint32_t key_upd_msk = ddr_data.pmu_pd_st & BIT(pmu_pd_vop) ? 0x3 : 0x7; 616036935a8SXiaoDong Huang uint32_t fw_lkp_upd_msk = ddr_data.pmu_pd_st & BIT(pmu_pd_npu) ? 0x3 : 0x7; 617036935a8SXiaoDong Huang uint32_t fw_ddr_upd_msk = key_upd_msk; 618036935a8SXiaoDong Huang uint32_t pmu_pd_st = mmio_read_32(PMU_BASE + PMU2_PWR_GATE_ST); 619036935a8SXiaoDong Huang uint32_t bus_idle_st = mmio_read_32(PMU_BASE + PMU2_BUS_IDLE_ST); 620036935a8SXiaoDong Huang 621036935a8SXiaoDong Huang ddr_data.pmu2_bisr_glb_con = mmio_read_32(PMU_BASE + PMU2_BISR_GLB_CON); 622036935a8SXiaoDong Huang 623036935a8SXiaoDong Huang ddr_data.pmu2_fast_pwr_con = 624036935a8SXiaoDong Huang mmio_read_32(PMU_BASE + PMU2_FAST_POWER_CON); 625036935a8SXiaoDong Huang 626036935a8SXiaoDong Huang ddr_data.pmu2_c0_ack_sel_con0 = 627036935a8SXiaoDong Huang mmio_read_32(PMU_BASE + PMU2_C0_PWRACK_BYPASS_CON(0)); 628036935a8SXiaoDong Huang ddr_data.pmu2_c1_ack_sel_con0 = 629036935a8SXiaoDong Huang mmio_read_32(PMU_BASE + PMU2_C1_PWRACK_BYPASS_CON(0)); 630036935a8SXiaoDong Huang ddr_data.pmu2_c2_ack_sel_con0 = 631036935a8SXiaoDong Huang mmio_read_32(PMU_BASE + PMU2_C2_PWRACK_BYPASS_CON(0)); 632036935a8SXiaoDong Huang ddr_data.pmu0grf_soc_con5 = 633036935a8SXiaoDong Huang mmio_read_32(PMU0_GRF_BASE + PMU0GRF_SOC_CON(5)); 634036935a8SXiaoDong Huang 635036935a8SXiaoDong Huang /* set tsadc_shut_m0 pin iomux to gpio */ 636036935a8SXiaoDong Huang mmio_write_32(PMU0_IOC_BASE + PMUIO0_IOC_GPIO0A_IOMUX_SEL_L, 637036935a8SXiaoDong Huang BITS_WITH_WMASK(0, 0xf, 4)); 638036935a8SXiaoDong Huang 639036935a8SXiaoDong Huang pmu1_wkup_int_con = 640036935a8SXiaoDong Huang BIT(pmu_wkup_cpu0_int) | 641036935a8SXiaoDong Huang BIT(pmu_wkup_gpio0_int); 642036935a8SXiaoDong Huang 643036935a8SXiaoDong Huang pmu1_pwr_con = 644036935a8SXiaoDong Huang BIT(pmu_powermode_en) | 645036935a8SXiaoDong Huang /* BIT(pmu_scu0_byp) | */ 646036935a8SXiaoDong Huang /* BIT(pmu_scu1_byp) | */ 647036935a8SXiaoDong Huang /* BIT(pmu_cci_byp) | */ 648036935a8SXiaoDong Huang /* BIT(pmu_bus_byp) | */ 649036935a8SXiaoDong Huang /* BIT(pmu_ddr_byp) | */ 650036935a8SXiaoDong Huang /* BIT(pmu_pwrgt_byp) | */ 651036935a8SXiaoDong Huang /* BIT(pmu_cru_byp) | */ 652036935a8SXiaoDong Huang BIT(pmu_qch_byp) | 653036935a8SXiaoDong Huang /* BIT(pmu_wfi_byp) | */ 654036935a8SXiaoDong Huang BIT(pmu_slp_cnt_en); 655036935a8SXiaoDong Huang 656036935a8SXiaoDong Huang pmu1_ddr_pwr_con = 0; 657036935a8SXiaoDong Huang 658036935a8SXiaoDong Huang pmu1_pll_pd_con = 659036935a8SXiaoDong Huang BIT(pmu_bpll_pd_en) | 660036935a8SXiaoDong Huang BIT(pmu_lpll_pd_en) | 661036935a8SXiaoDong Huang BIT(pmu_spll_pd_en) | 662036935a8SXiaoDong Huang BIT(pmu_gpll_pd_en) | 663036935a8SXiaoDong Huang BIT(pmu_cpll_pd_en) | 664036935a8SXiaoDong Huang BIT(pmu_ppll_pd_en) | 665036935a8SXiaoDong Huang BIT(pmu_aupll_pd_en) | 666036935a8SXiaoDong Huang BIT(pmu_vpll_pd_en); 667036935a8SXiaoDong Huang 668036935a8SXiaoDong Huang pmu1cru_pwr_con = 669036935a8SXiaoDong Huang BIT(pmu_alive_osc_mode_en) | 670036935a8SXiaoDong Huang BIT(pmu_io_sleep_en) | 671036935a8SXiaoDong Huang BIT(pmu_power_off_en); 672036935a8SXiaoDong Huang 673036935a8SXiaoDong Huang pmu2_bus_idle_con[0] = 0xffff & ~(bus_idle_st & 0xffff); 674036935a8SXiaoDong Huang pmu2_bus_idle_con[1] = 0x3fff & ~(bus_idle_st >> 16); 675036935a8SXiaoDong Huang 676036935a8SXiaoDong Huang pmu2_pwr_gt_con[0] = 0xffff & ~(pmu_pd_st & 0xffff); 677036935a8SXiaoDong Huang pmu2_pwr_gt_con[1] = 0x03ff & ~(pmu_pd_st >> 16); 678036935a8SXiaoDong Huang 679036935a8SXiaoDong Huang pmu2_pwr_gt_con[0] &= 680036935a8SXiaoDong Huang ~(BIT(pmu_pd_secure) | 681036935a8SXiaoDong Huang BIT(pmu_pd_bus) | 682036935a8SXiaoDong Huang BIT(pmu_pd_center) | 683036935a8SXiaoDong Huang BIT(pmu_pd_ddr)); 684036935a8SXiaoDong Huang 685036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_BUS_IDLEACK_BYPASS_CON, 0x00030003); 686036935a8SXiaoDong Huang mmio_write_32(SYS_SGRF_FW_BASE + FW_SGRF_KEYUPD_CON0, 0x03ff0000); 687036935a8SXiaoDong Huang 688036935a8SXiaoDong Huang /* disable repair */ 689036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_BISR_GLB_CON, 0x00010000); 690036935a8SXiaoDong Huang 691036935a8SXiaoDong Huang /* disable ddr_hash_key update. 692036935a8SXiaoDong Huang * enable disable ddr_hash_key auto update. 693036935a8SXiaoDong Huang * wait ddr_hash_key auto update. 694036935a8SXiaoDong Huang */ 695036935a8SXiaoDong Huang mmio_write_32(SYS_SGRF_BASE + SYSSGRF_SOC_CON(19), 696036935a8SXiaoDong Huang BITS_WITH_WMASK(key_upd_msk, 0x7, 8)); 697036935a8SXiaoDong Huang mmio_write_32(SYS_SGRF_FW_BASE + FW_SGRF_KEYUPD_CON1, 698036935a8SXiaoDong Huang BITS_WITH_WMASK(fw_lkp_upd_msk, 0x7, 10)); 699036935a8SXiaoDong Huang mmio_write_32(SYS_SGRF_FW_BASE + FW_SGRF_KEYUPD_CON1, 700036935a8SXiaoDong Huang BITS_WITH_WMASK(fw_ddr_upd_msk, 0x7u, 13)); 701036935a8SXiaoDong Huang 702036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU0_PMIC_STABLE_CNT_THRES, 24000 * 5); 703036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU0_OSC_STABLE_CNT_THRES, 24000 * 5); 704036935a8SXiaoDong Huang 705036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU1_OSC_STABLE_CNT_THRESH, 24000 * 5); 706036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU1_STABLE_CNT_THRESH, 24000 * 5); 707036935a8SXiaoDong Huang 708036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU1_SLEEP_CNT_THRESH, 24000 * 15); 709036935a8SXiaoDong Huang 710036935a8SXiaoDong Huang /* Pmu's clk has switched to 24M back When pmu FSM counts 711036935a8SXiaoDong Huang * the follow counters, so we should use 24M to calculate 712036935a8SXiaoDong Huang * these counters. 713036935a8SXiaoDong Huang */ 714036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU0_WAKEUP_RST_CLR_CNT_THRES, 12000); 715036935a8SXiaoDong Huang 716036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU1_WAKEUP_RST_CLR_CNT_THRESH, 12000); 717036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU1_PLL_LOCK_CNT_THRESH, 12000); 718036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU1_PWM_SWITCH_CNT_THRESH, 719036935a8SXiaoDong Huang 24000 * 2); 720036935a8SXiaoDong Huang 721036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_SCU0_PWRUP_CNT_THRESH, 0); 722036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_SCU0_PWRDN_CNT_THRESH, 0); 723036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_SCU0_STABLE_CNT_THRESH, 0); 724036935a8SXiaoDong Huang 725036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_FAST_PWRUP_CNT_THRESH_0, 0); 726036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_FAST_PWRDN_CNT_THRESH_0, 0); 727036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_FAST_PWRUP_CNT_THRESH_1, 0); 728036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_FAST_PWRDN_CNT_THRESH_1, 0); 729036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_FAST_PWRUP_CNT_THRESH_2, 0); 730036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_FAST_PWRDN_CNT_THRESH_2, 0); 731036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_FAST_POWER_CON, 0xffff0007); 732036935a8SXiaoDong Huang 733036935a8SXiaoDong Huang /* pmu_clst_idle_con */ 734036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_CLUSTER0_IDLE_CON, 0xffff0007); 735036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_CLUSTER1_IDLE_CON, 0xffff0007); 736036935a8SXiaoDong Huang 737036935a8SXiaoDong Huang /* pmu_scu_pwr_con */ 738036935a8SXiaoDong Huang /* L2's flush and idle by hardware, so need to enable wfil2 bypass */ 739036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_SCU0_PWR_CON, 0xffff020f); 740036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_SCU1_PWR_CON, 0xffff020f); 741036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_SCU0_AUTO_PWR_CON, 0x00070000); 742036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_SCU1_AUTO_PWR_CON, 0x00070000); 743036935a8SXiaoDong Huang 744036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_CCI_PWR_CON, 0xffff0009); 745036935a8SXiaoDong Huang 746036935a8SXiaoDong Huang /* pmu_int_msk_con */ 747036935a8SXiaoDong Huang /* mmio_write_32(PMU_BASE + PMU1_INT_MASK_CON, BITS_WITH_WMASK(1, 0x1, 0)); */ 748036935a8SXiaoDong Huang 749036935a8SXiaoDong Huang /* pmu_pwr_con */ 750036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU1_PWR_CON, WITH_16BITS_WMSK(pmu1_pwr_con)); 751036935a8SXiaoDong Huang 752036935a8SXiaoDong Huang /* pmu_cru_pwr_conx */ 753036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU1_CRU_PWR_CON(0), WITH_16BITS_WMSK(pmu1cru_pwr_con)); 754036935a8SXiaoDong Huang 755036935a8SXiaoDong Huang /* pmu_ddr_pwr_con */ 756036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU0_DDR_RET_CON(1), 0xffff0000); 757036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU1_DDR_PWR_CON(0), WITH_16BITS_WMSK(pmu1_ddr_pwr_con)); 758036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU1_DDR_PWR_CON(1), WITH_16BITS_WMSK(pmu1_ddr_pwr_con)); 759036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU1_DDR_AXIPWR_CON(0), 0x03ff03ff); 760036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU1_DDR_AXIPWR_CON(1), 0x03ff03ff); 761036935a8SXiaoDong Huang 762036935a8SXiaoDong Huang /* pll_pd */ 763036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU1_PLLPD_CON(0), WITH_16BITS_WMSK(pmu1_pll_pd_con)); 764036935a8SXiaoDong Huang 765036935a8SXiaoDong Huang /* bus idle */ 766036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_BUS_IDLE_CON(0), WITH_16BITS_WMSK(pmu2_bus_idle_con[0])); 767036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_BUS_IDLE_CON(1), WITH_16BITS_WMSK(pmu2_bus_idle_con[1])); 768036935a8SXiaoDong Huang 769036935a8SXiaoDong Huang /* power gate */ 770036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_PWR_GATE_CON(0), WITH_16BITS_WMSK(pmu2_pwr_gt_con[0])); 771036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_PWR_GATE_CON(1), WITH_16BITS_WMSK(pmu2_pwr_gt_con[1])); 772036935a8SXiaoDong Huang 773036935a8SXiaoDong Huang /* vol gate */ 774036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_VOL_GATE_SFTCON(0), 0xffff0031); 775036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_VOL_GATE_SFTCON(1), 0xffff0200); 776036935a8SXiaoDong Huang 777036935a8SXiaoDong Huang /* wakeup source */ 778036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU1_WAKEUP_INT_CON, pmu1_wkup_int_con); 779036935a8SXiaoDong Huang 780036935a8SXiaoDong Huang /* ppll clamp */ 781036935a8SXiaoDong Huang mmio_write_32(PMU0_GRF_BASE + PMU0GRF_SOC_CON(5), 0x00400040); 782036935a8SXiaoDong Huang 783036935a8SXiaoDong Huang /* usbphy clamp */ 784036935a8SXiaoDong Huang mmio_write_32(PMU0_GRF_BASE + PMU0GRF_SOC_CON(5), 785036935a8SXiaoDong Huang BITS_WITH_WMASK(0x9, 0x9, 2)); 786036935a8SXiaoDong Huang 787036935a8SXiaoDong Huang /* big core pwr ack bypass */ 788036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_C0_PWRACK_BYPASS_CON(0), 0x01000100); 789036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_C1_PWRACK_BYPASS_CON(0), 0x01000100); 790036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_C2_PWRACK_BYPASS_CON(0), 0x01000100); 791036935a8SXiaoDong Huang } 792036935a8SXiaoDong Huang 793036935a8SXiaoDong Huang static void pmu_sleep_restore(void) 794036935a8SXiaoDong Huang { 795036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU0_INFO_TX_CON, 0xffff0000); 796036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_DEBUG_INFO_SEL, 0xffff0000); 797036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_CLUSTER0_IDLE_CON, 0xffff0000); 798036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_SCU0_PWR_CON, 0xffff0000); 799036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_CCI_PWR_CON, 0xffff0000); 800036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU1_INT_MASK_CON, 0xffff0000); 801036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU1_PWR_CON, 0xffff0000); 802036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU1_CRU_PWR_CON(0), 0xffff0000); 803036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU1_DDR_PWR_CON(0), 0xffff0000); 804036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU1_DDR_PWR_CON(1), 0xffff0000); 805036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU1_DDR_AXIPWR_CON(0), 0xffff0000); 806036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU1_DDR_AXIPWR_CON(1), 0xffff0000); 807036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU1_PLLPD_CON(0), 0xffff0000); 808036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_BUS_IDLE_CON(0), 0xffff0000); 809036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_BUS_IDLE_CON(1), 0xffff0000); 810036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_PWR_GATE_CON(0), 0xffff0000); 811036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_PWR_GATE_CON(1), 0xffff0000); 812036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_VOL_GATE_SFTCON(0), 0xffff0000); 813036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_VOL_GATE_SFTCON(1), 0xffff0000); 814036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_BUS_IDLEACK_BYPASS_CON, 0xffff0000); 815036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU1_WAKEUP_INT_CON, 0); 816036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_FAST_POWER_CON, 817036935a8SXiaoDong Huang WITH_16BITS_WMSK(ddr_data.pmu2_fast_pwr_con)); 818036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_BISR_GLB_CON, 819036935a8SXiaoDong Huang WITH_16BITS_WMSK(ddr_data.pmu2_bisr_glb_con)); 820036935a8SXiaoDong Huang 821036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_C0_PWRACK_BYPASS_CON(0), 822036935a8SXiaoDong Huang WITH_16BITS_WMSK(ddr_data.pmu2_c0_ack_sel_con0)); 823036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_C1_PWRACK_BYPASS_CON(0), 824036935a8SXiaoDong Huang WITH_16BITS_WMSK(ddr_data.pmu2_c1_ack_sel_con0)); 825036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_C2_PWRACK_BYPASS_CON(0), 826036935a8SXiaoDong Huang WITH_16BITS_WMSK(ddr_data.pmu2_c2_ack_sel_con0)); 827036935a8SXiaoDong Huang 828036935a8SXiaoDong Huang mmio_write_32(PMU0_GRF_BASE + PMU0GRF_SOC_CON(5), 829036935a8SXiaoDong Huang WITH_16BITS_WMSK(ddr_data.pmu0grf_soc_con5)); 830036935a8SXiaoDong Huang } 831036935a8SXiaoDong Huang 832036935a8SXiaoDong Huang static void secure_watchdog_disable(void) 833036935a8SXiaoDong Huang { 834036935a8SXiaoDong Huang ddr_data.sys_sgrf_soc_con0 = 835036935a8SXiaoDong Huang mmio_read_32(SYS_SGRF_BASE + SYSSGRF_SOC_CON(0)); 836036935a8SXiaoDong Huang 837036935a8SXiaoDong Huang /* pause wdt_s */ 838036935a8SXiaoDong Huang mmio_write_32(SYS_SGRF_BASE + SYSSGRF_SOC_CON(0), 839036935a8SXiaoDong Huang BITS_WITH_WMASK(1, 0x1, 14)); 840036935a8SXiaoDong Huang } 841036935a8SXiaoDong Huang 842036935a8SXiaoDong Huang static void secure_watchdog_restore(void) 843036935a8SXiaoDong Huang { 844036935a8SXiaoDong Huang mmio_write_32(SYS_SGRF_BASE + SYSSGRF_SOC_CON(0), 845036935a8SXiaoDong Huang ddr_data.sys_sgrf_soc_con0 | 846036935a8SXiaoDong Huang BITS_WMSK(0x1, 14)); 847036935a8SXiaoDong Huang 848036935a8SXiaoDong Huang if (mmio_read_32(WDT_S_BASE + WDT_CR) & WDT_EN) 849036935a8SXiaoDong Huang mmio_write_32(WDT_S_BASE + WDT_CRR, 0x76); 850036935a8SXiaoDong Huang } 851036935a8SXiaoDong Huang 852036935a8SXiaoDong Huang static void soc_sleep_config(void) 853036935a8SXiaoDong Huang { 854036935a8SXiaoDong Huang ddr_data.pmu0grf_soc_con0 = 855036935a8SXiaoDong Huang mmio_read_32(PMU0_GRF_BASE + PMU0GRF_SOC_CON(0)); 856036935a8SXiaoDong Huang ddr_data.pmu0grf_soc_con1 = 857036935a8SXiaoDong Huang mmio_read_32(PMU0_GRF_BASE + PMU0GRF_SOC_CON(1)); 858036935a8SXiaoDong Huang 859036935a8SXiaoDong Huang ddr_data.gpio0a_iomux_l = 860036935a8SXiaoDong Huang mmio_read_32(PMU0_IOC_BASE + PMUIO0_IOC_GPIO0A_IOMUX_SEL_L); 861036935a8SXiaoDong Huang ddr_data.gpio0a_iomux_h = 862036935a8SXiaoDong Huang mmio_read_32(PMU0_IOC_BASE + PMUIO0_IOC_GPIO0A_IOMUX_SEL_H); 863036935a8SXiaoDong Huang ddr_data.gpio0b_iomux_l = 864036935a8SXiaoDong Huang mmio_read_32(PMU0_IOC_BASE + PMUIO0_IOC_GPIO0B_IOMUX_SEL_L); 865036935a8SXiaoDong Huang 866036935a8SXiaoDong Huang sleep_pin_config(); 867036935a8SXiaoDong Huang pmu_sleep_config(); 868036935a8SXiaoDong Huang ddr_sleep_config(); 869036935a8SXiaoDong Huang secure_watchdog_disable(); 870036935a8SXiaoDong Huang } 871036935a8SXiaoDong Huang 872036935a8SXiaoDong Huang static void soc_sleep_restore(void) 873036935a8SXiaoDong Huang { 874036935a8SXiaoDong Huang secure_watchdog_restore(); 875036935a8SXiaoDong Huang ddr_sleep_config_restore(); 876036935a8SXiaoDong Huang pmu_sleep_restore(); 877036935a8SXiaoDong Huang 878036935a8SXiaoDong Huang mmio_write_32(PMU0_IOC_BASE + PMUIO0_IOC_GPIO0A_IOMUX_SEL_L, 879036935a8SXiaoDong Huang WITH_16BITS_WMSK(ddr_data.gpio0a_iomux_l)); 880036935a8SXiaoDong Huang mmio_write_32(PMU0_IOC_BASE + PMUIO0_IOC_GPIO0A_IOMUX_SEL_H, 881036935a8SXiaoDong Huang WITH_16BITS_WMSK(ddr_data.gpio0a_iomux_h)); 882036935a8SXiaoDong Huang mmio_write_32(PMU0_IOC_BASE + PMUIO0_IOC_GPIO0B_IOMUX_SEL_L, 883036935a8SXiaoDong Huang WITH_16BITS_WMSK(ddr_data.gpio0b_iomux_l)); 884036935a8SXiaoDong Huang 885036935a8SXiaoDong Huang mmio_write_32(PMU0_GRF_BASE + PMU0GRF_SOC_CON(1), 886036935a8SXiaoDong Huang WITH_16BITS_WMSK(ddr_data.pmu0grf_soc_con1)); 887036935a8SXiaoDong Huang mmio_write_32(PMU0_GRF_BASE + PMU0GRF_SOC_CON(0), 888036935a8SXiaoDong Huang WITH_16BITS_WMSK(ddr_data.pmu0grf_soc_con0)); 889036935a8SXiaoDong Huang } 890036935a8SXiaoDong Huang 891036935a8SXiaoDong Huang static void pm_pll_suspend(void) 892036935a8SXiaoDong Huang { 893036935a8SXiaoDong Huang ddr_data.cru_mode_con = mmio_read_32(CRU_BASE + 0x280); 894036935a8SXiaoDong Huang ddr_data.secure_cru_mode = mmio_read_32(SECURE_CRU_BASE + 0x4280); 895036935a8SXiaoDong Huang 896036935a8SXiaoDong Huang /* bpll gpll vpll aupll cpll spll switch to slow mode */ 897036935a8SXiaoDong Huang mmio_write_32(CRU_BASE + 0x280, 0x03ff0000); 898036935a8SXiaoDong Huang mmio_write_32(SECURE_CRU_BASE + 0x4280, 0x00030000); 899036935a8SXiaoDong Huang 900036935a8SXiaoDong Huang /* hclk_pmu_cm0_root_i_sel to 24M */ 901036935a8SXiaoDong Huang mmio_write_32(PMU1_CRU_BASE + PMU1CRU_CLKSEL_CON(4), 902036935a8SXiaoDong Huang BITS_WITH_WMASK(0x3, 0x3, 2)); 903036935a8SXiaoDong Huang } 904036935a8SXiaoDong Huang 905036935a8SXiaoDong Huang static void pm_pll_restore(void) 906036935a8SXiaoDong Huang { 907036935a8SXiaoDong Huang mmio_write_32(CRU_BASE + 0x280, WITH_16BITS_WMSK(ddr_data.cru_mode_con)); 908036935a8SXiaoDong Huang mmio_write_32(SECURE_CRU_BASE + 0x4280, 909036935a8SXiaoDong Huang WITH_16BITS_WMSK(ddr_data.secure_cru_mode)); 910036935a8SXiaoDong Huang } 911036935a8SXiaoDong Huang 912036935a8SXiaoDong Huang int rockchip_soc_sys_pwr_dm_suspend(void) 913036935a8SXiaoDong Huang { 914036935a8SXiaoDong Huang psram_sleep_cfg->pm_flag &= ~PM_WARM_BOOT_BIT; 915036935a8SXiaoDong Huang 916036935a8SXiaoDong Huang clk_gate_con_save(); 917036935a8SXiaoDong Huang clk_gate_con_disable(); 918036935a8SXiaoDong Huang dmc_save(); 919036935a8SXiaoDong Huang pmu_power_domains_suspend(); 920036935a8SXiaoDong Huang soc_sleep_config(); 921036935a8SXiaoDong Huang pm_pll_suspend(); 922036935a8SXiaoDong Huang pd_core_save(); 923036935a8SXiaoDong Huang 924036935a8SXiaoDong Huang return 0; 925036935a8SXiaoDong Huang } 926036935a8SXiaoDong Huang 927036935a8SXiaoDong Huang int rockchip_soc_sys_pwr_dm_resume(void) 928036935a8SXiaoDong Huang { 929036935a8SXiaoDong Huang pd_core_restore(); 930036935a8SXiaoDong Huang pm_pll_restore(); 931036935a8SXiaoDong Huang soc_sleep_restore(); 932036935a8SXiaoDong Huang pmu_power_domains_resume(); 933036935a8SXiaoDong Huang plat_rockchip_gic_cpuif_enable(); 934036935a8SXiaoDong Huang dmc_restore(); 935036935a8SXiaoDong Huang clk_gate_con_restore(); 936036935a8SXiaoDong Huang 937036935a8SXiaoDong Huang psram_sleep_cfg->pm_flag |= PM_WARM_BOOT_BIT; 938036935a8SXiaoDong Huang 939036935a8SXiaoDong Huang return 0; 940036935a8SXiaoDong Huang } 941036935a8SXiaoDong Huang 942036935a8SXiaoDong Huang static int rockchip_reboot_is_rbrom(void) 943036935a8SXiaoDong Huang { 944036935a8SXiaoDong Huang return mmio_read_32(PMU0_GRF_BASE + PMU0GRF_OS_REG(16)) == 945036935a8SXiaoDong Huang BOOT_BROM_DOWNLOAD; 946036935a8SXiaoDong Huang } 947036935a8SXiaoDong Huang 948036935a8SXiaoDong Huang static void rockchip_soc_soft_reset_check_rstout(void) 949036935a8SXiaoDong Huang { 950036935a8SXiaoDong Huang /* 951036935a8SXiaoDong Huang * Maskrom enter maskrom-usb mode according to os_reg0 which 952036935a8SXiaoDong Huang * will be reset by NPOR. So disable tsadc_shut_m0 if we want 953036935a8SXiaoDong Huang * to maskrom-usb mode. 954036935a8SXiaoDong Huang */ 955036935a8SXiaoDong Huang if (rockchip_reboot_is_rbrom() != 0) { 956036935a8SXiaoDong Huang /* write BOOT_BROM_DOWNLOAD to os_reg0 */ 957036935a8SXiaoDong Huang mmio_write_32(PMU1_GRF_BASE + PMU1GRF_OS_REG(0), BOOT_BROM_DOWNLOAD); 958036935a8SXiaoDong Huang 959036935a8SXiaoDong Huang /* disable first/tsadc/wdt reset output */ 960036935a8SXiaoDong Huang mmio_write_32(PMU1SGRF_BASE + PMU1SGRF_SOC_CON(0), 0x00070000); 961036935a8SXiaoDong Huang 962036935a8SXiaoDong Huang /* clear reset hold */ 963036935a8SXiaoDong Huang mmio_write_32(PMU0SGRF_BASE + PMU0SGRF_SOC_CON(1), 0xffff0000); 964036935a8SXiaoDong Huang mmio_write_32(PMU1SGRF_BASE + PMU1SGRF_SOC_CON(16), 0xffff0000); 965036935a8SXiaoDong Huang mmio_write_32(PMU1SGRF_BASE + PMU1SGRF_SOC_CON(17), 0xffff0000); 966036935a8SXiaoDong Huang } 967036935a8SXiaoDong Huang } 968036935a8SXiaoDong Huang 969036935a8SXiaoDong Huang void __dead2 rockchip_soc_soft_reset(void) 970036935a8SXiaoDong Huang { 971036935a8SXiaoDong Huang rockchip_soc_soft_reset_check_rstout(); 972036935a8SXiaoDong Huang 973036935a8SXiaoDong Huang /* pll slow mode */ 974036935a8SXiaoDong Huang mmio_write_32(CRU_BASE + CRU_MODE_CON, 0x003f0000); 975036935a8SXiaoDong Huang 976036935a8SXiaoDong Huang dsb(); 977036935a8SXiaoDong Huang isb(); 978036935a8SXiaoDong Huang 979036935a8SXiaoDong Huang INFO("system reset......\n"); 980036935a8SXiaoDong Huang mmio_write_32(CRU_BASE + CRU_GLB_SRST_FST, GLB_SRST_FST_CFG_VAL); 981036935a8SXiaoDong Huang 982036935a8SXiaoDong Huang /* 983036935a8SXiaoDong Huang * Maybe the HW needs some times to reset the system, 984036935a8SXiaoDong Huang * so we do not hope the core to execute valid codes. 985036935a8SXiaoDong Huang */ 986*1ed77d1bSBoyan Karatotev while (1) { 987*1ed77d1bSBoyan Karatotev wfi(); 988*1ed77d1bSBoyan Karatotev } 989036935a8SXiaoDong Huang } 990036935a8SXiaoDong Huang 991036935a8SXiaoDong Huang void __dead2 rockchip_soc_system_off(void) 992036935a8SXiaoDong Huang { 993036935a8SXiaoDong Huang INFO("system poweroff......\n"); 994036935a8SXiaoDong Huang 995036935a8SXiaoDong Huang /* gpio0_a3 config output */ 996036935a8SXiaoDong Huang mmio_write_32(GPIO0_BASE + GPIO_SWPORT_DDR_L, 997036935a8SXiaoDong Huang BITS_WITH_WMASK(1, 0x1, 3)); 998036935a8SXiaoDong Huang 999036935a8SXiaoDong Huang /* gpio0_a3 config output high level */ 1000036935a8SXiaoDong Huang mmio_write_32(GPIO0_BASE + GPIO_SWPORT_DR_L, 1001036935a8SXiaoDong Huang BITS_WITH_WMASK(1, 0x1, 3)); 1002036935a8SXiaoDong Huang dsb(); 1003036935a8SXiaoDong Huang 1004036935a8SXiaoDong Huang /* 1005036935a8SXiaoDong Huang * Maybe the HW needs some times to reset the system, 1006036935a8SXiaoDong Huang * so we do not hope the core to execute valid codes. 1007036935a8SXiaoDong Huang */ 1008*1ed77d1bSBoyan Karatotev while (1) { 1009*1ed77d1bSBoyan Karatotev wfi(); 1010*1ed77d1bSBoyan Karatotev } 1011036935a8SXiaoDong Huang } 1012036935a8SXiaoDong Huang 1013036935a8SXiaoDong Huang static void rockchip_pmu_pd_repair_init(void) 1014036935a8SXiaoDong Huang { 1015036935a8SXiaoDong Huang INFO("enable memory repair\n"); 1016036935a8SXiaoDong Huang /* Enable gpu and npu repair */ 1017036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_BISR_PDGEN_CON(1), 1018036935a8SXiaoDong Huang BITS_WITH_WMASK(0xf, 0xf, 6)); 1019036935a8SXiaoDong Huang } 1020036935a8SXiaoDong Huang 1021036935a8SXiaoDong Huang void plat_rockchip_pmu_init(void) 1022036935a8SXiaoDong Huang { 1023036935a8SXiaoDong Huang int cpu; 1024036935a8SXiaoDong Huang 1025036935a8SXiaoDong Huang for (cpu = 0; cpu < PLATFORM_CORE_COUNT; cpu++) 1026036935a8SXiaoDong Huang cpuson_flags[cpu] = 0; 1027036935a8SXiaoDong Huang 1028036935a8SXiaoDong Huang psram_sleep_cfg->sp = PSRAM_SP_TOP; 1029036935a8SXiaoDong Huang psram_sleep_cfg->ddr_func = (uint64_t)ddr_resume; 1030036935a8SXiaoDong Huang psram_sleep_cfg->ddr_data = 0; 1031036935a8SXiaoDong Huang psram_sleep_cfg->ddr_flag = 0; 1032036935a8SXiaoDong Huang psram_sleep_cfg->boot_mpidr = read_mpidr_el1() & 0xffff; 1033036935a8SXiaoDong Huang psram_sleep_cfg->pm_flag = PM_WARM_BOOT_BIT; 1034036935a8SXiaoDong Huang 1035036935a8SXiaoDong Huang nonboot_cpus_off(); 1036036935a8SXiaoDong Huang 1037036935a8SXiaoDong Huang /* 1038036935a8SXiaoDong Huang * When perform idle operation, corresponding clock can be 1039036935a8SXiaoDong Huang * opened or gated automatically. 1040036935a8SXiaoDong Huang */ 1041036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_NOC_AUTO_CON(0), 0xffffffff); 1042036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_NOC_AUTO_CON(1), 0xffffffff); 1043036935a8SXiaoDong Huang 1044036935a8SXiaoDong Huang /* remap pmusram to 0x00000000 */ 1045036935a8SXiaoDong Huang mmio_write_32(PMU0SGRF_BASE + PMU0SGRF_SOC_CON(2), BITS_WITH_WMASK(1, 0x3, 0)); 1046036935a8SXiaoDong Huang 1047036935a8SXiaoDong Huang /* enable power off VD_NPU by hrdware */ 1048036935a8SXiaoDong Huang mmio_write_32(PMU_BASE + PMU2_VOL_GATE_SFTCON(0), 1049036935a8SXiaoDong Huang BITS_WITH_WMASK(0x1, 0x1, 0)); 1050036935a8SXiaoDong Huang 1051036935a8SXiaoDong Huang rockchip_pmu_pd_repair_init(); 1052036935a8SXiaoDong Huang 1053036935a8SXiaoDong Huang pm_reg_rgns_init(); 1054036935a8SXiaoDong Huang } 1055