1fcd41e86SJacky Bai /* 2fcd41e86SJacky Bai * Copyright 2021-2024 NXP 3fcd41e86SJacky Bai * 4fcd41e86SJacky Bai * SPDX-License-Identifier: BSD-3-Clause 5fcd41e86SJacky Bai */ 6fcd41e86SJacky Bai 7fcd41e86SJacky Bai #include <stdbool.h> 8fcd41e86SJacky Bai 9fcd41e86SJacky Bai #include <arch.h> 10fcd41e86SJacky Bai #include <arch_helpers.h> 11fcd41e86SJacky Bai #include <common/debug.h> 12fcd41e86SJacky Bai #include <drivers/arm/gicv3.h> 13fcd41e86SJacky Bai #include <lib/mmio.h> 14fcd41e86SJacky Bai #include <lib/psci/psci.h> 15fcd41e86SJacky Bai 16fcd41e86SJacky Bai #include <plat_imx8.h> 17daa4478aSJacky Bai #include <upower_api.h> 18fcd41e86SJacky Bai 19478af8d3SJacky Bai extern void cgc1_save(void); 20478af8d3SJacky Bai extern void cgc1_restore(void); 21478af8d3SJacky Bai extern void imx_apd_ctx_save(unsigned int cpu); 22478af8d3SJacky Bai extern void imx_apd_ctx_restore(unsigned int cpu); 23478af8d3SJacky Bai extern void usb_wakeup_enable(bool enable); 24*36af80c2SJacky Bai extern void upower_wait_resp(void); 25*36af80c2SJacky Bai extern bool is_lpav_owned_by_apd(void); 26*36af80c2SJacky Bai extern void apd_io_pad_off(void); 27*36af80c2SJacky Bai extern int upower_pmic_i2c_read(uint32_t reg_addr, uint32_t *reg_val); 28478af8d3SJacky Bai 29fcd41e86SJacky Bai static uintptr_t secure_entrypoint; 30fcd41e86SJacky Bai 31fcd41e86SJacky Bai #define CORE_PWR_STATE(state) ((state)->pwr_domain_state[MPIDR_AFFLVL0]) 32fcd41e86SJacky Bai #define CLUSTER_PWR_STATE(state) ((state)->pwr_domain_state[MPIDR_AFFLVL1]) 33fcd41e86SJacky Bai #define SYSTEM_PWR_STATE(state) ((state)->pwr_domain_state[PLAT_MAX_PWR_LVL]) 34fcd41e86SJacky Bai 35fcd41e86SJacky Bai #define RVBARADDRx(c) (IMX_SIM1_BASE + 0x5c + 0x4 * (c)) 36fcd41e86SJacky Bai #define WKPUx(c) (IMX_SIM1_BASE + 0x3c + 0x4 * (c)) 37fcd41e86SJacky Bai #define AD_COREx_LPMODE(c) (IMX_CMC1_BASE + 0x50 + 0x4 * (c)) 38fcd41e86SJacky Bai 39daa4478aSJacky Bai #define PMIC_CFG(v, m, msk) \ 40daa4478aSJacky Bai { \ 41daa4478aSJacky Bai .volt = (v), \ 42daa4478aSJacky Bai .mode = (m), \ 43daa4478aSJacky Bai .mode_msk = (msk), \ 44daa4478aSJacky Bai } 45daa4478aSJacky Bai 46daa4478aSJacky Bai #define PAD_CFG(c, r, t) \ 47daa4478aSJacky Bai { \ 48daa4478aSJacky Bai .pad_close = (c), \ 49daa4478aSJacky Bai .pad_reset = (r), \ 50daa4478aSJacky Bai .pad_tqsleep = (t) \ 51daa4478aSJacky Bai } 52daa4478aSJacky Bai 53daa4478aSJacky Bai #define BIAS_CFG(m, n, p, mbias) \ 54daa4478aSJacky Bai { \ 55daa4478aSJacky Bai .dombias_cfg = { \ 56daa4478aSJacky Bai .mode = (m), \ 57daa4478aSJacky Bai .rbbn = (n), \ 58daa4478aSJacky Bai .rbbp = (p), \ 59daa4478aSJacky Bai }, \ 60daa4478aSJacky Bai .membias_cfg = {mbias}, \ 61daa4478aSJacky Bai } 62daa4478aSJacky Bai 63daa4478aSJacky Bai #define SWT_BOARD(swt_on, msk) \ 64daa4478aSJacky Bai { \ 65daa4478aSJacky Bai .on = (swt_on), \ 66daa4478aSJacky Bai .mask = (msk), \ 67daa4478aSJacky Bai } 68daa4478aSJacky Bai 69daa4478aSJacky Bai #define SWT_MEM(a, p, m) \ 70daa4478aSJacky Bai { \ 71daa4478aSJacky Bai .array = (a), \ 72daa4478aSJacky Bai .perif = (p), \ 73daa4478aSJacky Bai .mask = (m), \ 74daa4478aSJacky Bai } 75daa4478aSJacky Bai 76fcd41e86SJacky Bai static int imx_pwr_set_cpu_entry(unsigned int cpu, unsigned int entry) 77fcd41e86SJacky Bai { 78fcd41e86SJacky Bai mmio_write_32(RVBARADDRx(cpu), entry); 79fcd41e86SJacky Bai 80fcd41e86SJacky Bai /* set update bit */ 81fcd41e86SJacky Bai mmio_write_32(IMX_SIM1_BASE + 0x8, mmio_read_32(IMX_SIM1_BASE + 0x8) | BIT_32(24 + cpu)); 82fcd41e86SJacky Bai /* wait for ack */ 83fcd41e86SJacky Bai while (!(mmio_read_32(IMX_SIM1_BASE + 0x8) & BIT_32(26 + cpu))) { 84fcd41e86SJacky Bai } 85fcd41e86SJacky Bai 86fcd41e86SJacky Bai /* clear update bit */ 87fcd41e86SJacky Bai mmio_write_32(IMX_SIM1_BASE + 0x8, mmio_read_32(IMX_SIM1_BASE + 0x8) & ~BIT_32(24 + cpu)); 88fcd41e86SJacky Bai /* clear ack bit */ 89fcd41e86SJacky Bai mmio_write_32(IMX_SIM1_BASE + 0x8, mmio_read_32(IMX_SIM1_BASE + 0x8) | BIT_32(26 + cpu)); 90fcd41e86SJacky Bai 91fcd41e86SJacky Bai return 0; 92fcd41e86SJacky Bai } 93fcd41e86SJacky Bai 94fcd41e86SJacky Bai int imx_pwr_domain_on(u_register_t mpidr) 95fcd41e86SJacky Bai { 96fcd41e86SJacky Bai unsigned int cpu = MPIDR_AFFLVL0_VAL(mpidr); 97fcd41e86SJacky Bai 98fcd41e86SJacky Bai imx_pwr_set_cpu_entry(cpu, secure_entrypoint); 99fcd41e86SJacky Bai 100fcd41e86SJacky Bai mmio_write_32(IMX_CMC1_BASE + 0x18, 0x3f); 101fcd41e86SJacky Bai mmio_write_32(IMX_CMC1_BASE + 0x50 + 0x4 * cpu, 0); 102fcd41e86SJacky Bai 103fcd41e86SJacky Bai /* enable wku wakeup for idle */ 104fcd41e86SJacky Bai mmio_write_32(IMX_SIM1_BASE + 0x3c + 0x4 * cpu, 0xffffffff); 105fcd41e86SJacky Bai 106fcd41e86SJacky Bai return PSCI_E_SUCCESS; 107fcd41e86SJacky Bai } 108fcd41e86SJacky Bai 109fcd41e86SJacky Bai void imx_pwr_domain_on_finish(const psci_power_state_t *target_state) 110fcd41e86SJacky Bai { 111fcd41e86SJacky Bai imx_pwr_set_cpu_entry(0, IMX_ROM_ENTRY); 112fcd41e86SJacky Bai plat_gic_pcpu_init(); 113fcd41e86SJacky Bai plat_gic_cpuif_enable(); 114fcd41e86SJacky Bai } 115fcd41e86SJacky Bai 116fcd41e86SJacky Bai int imx_validate_ns_entrypoint(uintptr_t ns_entrypoint) 117fcd41e86SJacky Bai { 118fcd41e86SJacky Bai return PSCI_E_SUCCESS; 119fcd41e86SJacky Bai } 120fcd41e86SJacky Bai 121fcd41e86SJacky Bai void imx_pwr_domain_off(const psci_power_state_t *target_state) 122fcd41e86SJacky Bai { 123fcd41e86SJacky Bai unsigned int cpu = MPIDR_AFFLVL0_VAL(read_mpidr_el1()); 124fcd41e86SJacky Bai 125fcd41e86SJacky Bai plat_gic_cpuif_disable(); 126fcd41e86SJacky Bai 127fcd41e86SJacky Bai /* disable wakeup */ 128fcd41e86SJacky Bai mmio_write_32(WKPUx(cpu), 0); 129fcd41e86SJacky Bai 130daa4478aSJacky Bai /* set core power mode to PD */ 131fcd41e86SJacky Bai mmio_write_32(AD_COREx_LPMODE(cpu), 0x3); 132fcd41e86SJacky Bai } 133478af8d3SJacky Bai 134daa4478aSJacky Bai /* APD power mode config */ 135daa4478aSJacky Bai ps_apd_pwr_mode_cfgs_t apd_pwr_mode_cfgs = { 136891c547eSJacky Bai [DPD_PWR_MODE] = { 137891c547eSJacky Bai .swt_board_offs = 0x180, 138891c547eSJacky Bai .swt_mem_offs = 0x188, 139*36af80c2SJacky Bai .pmic_cfg = PMIC_CFG(0x23, 0x0, 0x2), 140*36af80c2SJacky Bai .pad_cfg = PAD_CFG(0x0, 0xc, 0x01e80a02), 141891c547eSJacky Bai .bias_cfg = BIAS_CFG(0x0, 0x2, 0x2, 0x0), 142891c547eSJacky Bai }, 143891c547eSJacky Bai 144478af8d3SJacky Bai /* PD */ 145478af8d3SJacky Bai [PD_PWR_MODE] = { 146478af8d3SJacky Bai .swt_board_offs = 0x170, 147478af8d3SJacky Bai .swt_mem_offs = 0x178, 148*36af80c2SJacky Bai .pmic_cfg = PMIC_CFG(0x23, 0x0, 0x2), 149*36af80c2SJacky Bai .pad_cfg = PAD_CFG(0x0, 0xc, 0x01e80a00), 150478af8d3SJacky Bai .bias_cfg = BIAS_CFG(0x0, 0x2, 0x2, 0x0), 151478af8d3SJacky Bai }, 152478af8d3SJacky Bai 153daa4478aSJacky Bai [ADMA_PWR_MODE] = { 154daa4478aSJacky Bai .swt_board_offs = 0x120, 155daa4478aSJacky Bai .swt_mem_offs = 0x128, 156daa4478aSJacky Bai .pmic_cfg = PMIC_CFG(0x23, 0x0, 0x2), 157daa4478aSJacky Bai .pad_cfg = PAD_CFG(0x0, 0x0, 0x0deb7a00), 158*36af80c2SJacky Bai .bias_cfg = BIAS_CFG(0x2, 0x2, 0x2, 0x0), 159daa4478aSJacky Bai }, 160daa4478aSJacky Bai 161daa4478aSJacky Bai [ACT_PWR_MODE] = { 162daa4478aSJacky Bai .swt_board_offs = 0x110, 163daa4478aSJacky Bai .swt_mem_offs = 0x118, 164*36af80c2SJacky Bai .pmic_cfg = PMIC_CFG(0x23, 0x0, 0x2), 165daa4478aSJacky Bai .pad_cfg = PAD_CFG(0x0, 0x0, 0x0deb7a00), 166*36af80c2SJacky Bai .bias_cfg = BIAS_CFG(0x2, 0x2, 0x2, 0x0), 167daa4478aSJacky Bai }, 168daa4478aSJacky Bai }; 169daa4478aSJacky Bai 170daa4478aSJacky Bai /* APD power switch config */ 171daa4478aSJacky Bai ps_apd_swt_cfgs_t apd_swt_cfgs = { 172891c547eSJacky Bai [DPD_PWR_MODE] = { 173*36af80c2SJacky Bai .swt_board[0] = SWT_BOARD(0x0, 0x1fffc), 174891c547eSJacky Bai .swt_mem[0] = SWT_MEM(0x0, 0x0, 0x1ffff), 175891c547eSJacky Bai .swt_mem[1] = SWT_MEM(0x003fffff, 0x003fffff, 0x0), 176891c547eSJacky Bai }, 177891c547eSJacky Bai 178478af8d3SJacky Bai [PD_PWR_MODE] = { 179*36af80c2SJacky Bai .swt_board[0] = SWT_BOARD(0x0, 0x00001fffc), 180478af8d3SJacky Bai .swt_mem[0] = SWT_MEM(0x00010c00, 0x0, 0x1ffff), 181478af8d3SJacky Bai .swt_mem[1] = SWT_MEM(0x003fffff, 0x003f0000, 0x0), 182478af8d3SJacky Bai }, 183478af8d3SJacky Bai 184daa4478aSJacky Bai [ADMA_PWR_MODE] = { 185*36af80c2SJacky Bai .swt_board[0] = SWT_BOARD(0x15f74, 0x15f74), 186478af8d3SJacky Bai .swt_mem[0] = SWT_MEM(0x0001fffd, 0x0001fffd, 0x1ffff), 187478af8d3SJacky Bai .swt_mem[1] = SWT_MEM(0x003fffff, 0x003fffff, 0x0), 188daa4478aSJacky Bai }, 189daa4478aSJacky Bai 190daa4478aSJacky Bai [ACT_PWR_MODE] = { 191*36af80c2SJacky Bai .swt_board[0] = SWT_BOARD(0x15f74, 0x15f74), 192478af8d3SJacky Bai .swt_mem[0] = SWT_MEM(0x0001fffd, 0x0001fffd, 0x1ffff), 193478af8d3SJacky Bai .swt_mem[1] = SWT_MEM(0x003fffff, 0x003fffff, 0x0), 194daa4478aSJacky Bai }, 195daa4478aSJacky Bai }; 196daa4478aSJacky Bai 197*36af80c2SJacky Bai /* PMIC config for power down, LDO1 should be OFF */ 198*36af80c2SJacky Bai ps_apd_pmic_reg_data_cfgs_t pd_pmic_reg_cfgs = { 199*36af80c2SJacky Bai [0] = { 200*36af80c2SJacky Bai .tag = PMIC_REG_VALID_TAG, 201*36af80c2SJacky Bai .power_mode = PD_PWR_MODE, 202*36af80c2SJacky Bai .i2c_addr = 0x30, 203*36af80c2SJacky Bai .i2c_data = 0x9c, 204*36af80c2SJacky Bai }, 205*36af80c2SJacky Bai [1] = { 206*36af80c2SJacky Bai .tag = PMIC_REG_VALID_TAG, 207*36af80c2SJacky Bai .power_mode = PD_PWR_MODE, 208*36af80c2SJacky Bai .i2c_addr = 0x22, 209*36af80c2SJacky Bai .i2c_data = 0xb, 210*36af80c2SJacky Bai }, 211*36af80c2SJacky Bai [2] = { 212*36af80c2SJacky Bai .tag = PMIC_REG_VALID_TAG, 213*36af80c2SJacky Bai .power_mode = ACT_PWR_MODE, 214*36af80c2SJacky Bai .i2c_addr = 0x30, 215*36af80c2SJacky Bai .i2c_data = 0x9d, 216*36af80c2SJacky Bai }, 217*36af80c2SJacky Bai [3] = { 218*36af80c2SJacky Bai .tag = PMIC_REG_VALID_TAG, 219*36af80c2SJacky Bai .power_mode = ACT_PWR_MODE, 220*36af80c2SJacky Bai .i2c_addr = 0x22, 221*36af80c2SJacky Bai .i2c_data = 0x28, 222*36af80c2SJacky Bai }, 223*36af80c2SJacky Bai }; 224*36af80c2SJacky Bai 225*36af80c2SJacky Bai /* PMIC config for deep power down, BUCK3 should be OFF */ 226*36af80c2SJacky Bai ps_apd_pmic_reg_data_cfgs_t dpd_pmic_reg_cfgs = { 227*36af80c2SJacky Bai [0] = { 228*36af80c2SJacky Bai .tag = PMIC_REG_VALID_TAG, 229*36af80c2SJacky Bai .power_mode = DPD_PWR_MODE, 230*36af80c2SJacky Bai .i2c_addr = 0x21, 231*36af80c2SJacky Bai .i2c_data = 0x78, 232*36af80c2SJacky Bai }, 233*36af80c2SJacky Bai [1] = { 234*36af80c2SJacky Bai .tag = PMIC_REG_VALID_TAG, 235*36af80c2SJacky Bai .power_mode = DPD_PWR_MODE, 236*36af80c2SJacky Bai .i2c_addr = 0x30, 237*36af80c2SJacky Bai .i2c_data = 0x9c, 238*36af80c2SJacky Bai }, 239*36af80c2SJacky Bai [2] = { 240*36af80c2SJacky Bai .tag = PMIC_REG_VALID_TAG, 241*36af80c2SJacky Bai .power_mode = ACT_PWR_MODE, 242*36af80c2SJacky Bai .i2c_addr = 0x21, 243*36af80c2SJacky Bai .i2c_data = 0x79, 244*36af80c2SJacky Bai }, 245*36af80c2SJacky Bai [3] = { 246*36af80c2SJacky Bai .tag = PMIC_REG_VALID_TAG, 247*36af80c2SJacky Bai .power_mode = ACT_PWR_MODE, 248*36af80c2SJacky Bai .i2c_addr = 0x30, 249*36af80c2SJacky Bai .i2c_data = 0x9d, 250*36af80c2SJacky Bai }, 251*36af80c2SJacky Bai }; 252*36af80c2SJacky Bai 253daa4478aSJacky Bai struct ps_pwr_mode_cfg_t *pwr_sys_cfg = (struct ps_pwr_mode_cfg_t *)UPWR_DRAM_SHARED_BASE_ADDR; 254daa4478aSJacky Bai 255daa4478aSJacky Bai void imx_set_pwr_mode_cfg(abs_pwr_mode_t mode) 256daa4478aSJacky Bai { 257*36af80c2SJacky Bai uint32_t volt; 258*36af80c2SJacky Bai 259daa4478aSJacky Bai if (mode >= NUM_PWR_MODES) { 260daa4478aSJacky Bai return; 261daa4478aSJacky Bai } 262daa4478aSJacky Bai 263daa4478aSJacky Bai /* apd power mode config */ 264daa4478aSJacky Bai memcpy(&pwr_sys_cfg->ps_apd_pwr_mode_cfg[mode], &apd_pwr_mode_cfgs[mode], 265daa4478aSJacky Bai sizeof(struct ps_apd_pwr_mode_cfg_t)); 266daa4478aSJacky Bai 267daa4478aSJacky Bai /* apd power switch config */ 268daa4478aSJacky Bai memcpy(&pwr_sys_cfg->ps_apd_swt_cfg[mode], &apd_swt_cfgs[mode], sizeof(swt_config_t)); 269*36af80c2SJacky Bai 270*36af80c2SJacky Bai /* 271*36af80c2SJacky Bai * BUCK3 & LDO1 can only be shutdown when LPAV is owned by APD side 272*36af80c2SJacky Bai * otherwise RTD side is responsible to control them in low power mode. 273*36af80c2SJacky Bai */ 274*36af80c2SJacky Bai if (is_lpav_owned_by_apd()) { 275*36af80c2SJacky Bai /* power off the BUCK3 in DPD mode */ 276*36af80c2SJacky Bai if (mode == DPD_PWR_MODE) { 277*36af80c2SJacky Bai memcpy(&pwr_sys_cfg->ps_apd_pmic_reg_data_cfg, &dpd_pmic_reg_cfgs, 278*36af80c2SJacky Bai sizeof(ps_apd_pmic_reg_data_cfgs_t)); 279*36af80c2SJacky Bai /* LDO1 should be power off in PD mode */ 280*36af80c2SJacky Bai } else if (mode == PD_PWR_MODE) { 281*36af80c2SJacky Bai /* overwrite the buck3 voltage setting in active mode */ 282*36af80c2SJacky Bai upower_pmic_i2c_read(0x22, &volt); 283*36af80c2SJacky Bai pd_pmic_reg_cfgs[3].i2c_data = volt; 284*36af80c2SJacky Bai memcpy(&pwr_sys_cfg->ps_apd_pmic_reg_data_cfg, &pd_pmic_reg_cfgs, 285*36af80c2SJacky Bai sizeof(ps_apd_pmic_reg_data_cfgs_t)); 286*36af80c2SJacky Bai } 287*36af80c2SJacky Bai } 288daa4478aSJacky Bai } 289daa4478aSJacky Bai 290daa4478aSJacky Bai void imx_domain_suspend(const psci_power_state_t *target_state) 291daa4478aSJacky Bai { 292daa4478aSJacky Bai unsigned int cpu = MPIDR_AFFLVL0_VAL(read_mpidr_el1()); 293daa4478aSJacky Bai 294daa4478aSJacky Bai if (is_local_state_off(CORE_PWR_STATE(target_state))) { 295daa4478aSJacky Bai plat_gic_cpuif_disable(); 296daa4478aSJacky Bai imx_pwr_set_cpu_entry(cpu, secure_entrypoint); 297daa4478aSJacky Bai /* core put into power down */ 298daa4478aSJacky Bai mmio_write_32(IMX_CMC1_BASE + 0x50 + 0x4 * cpu, 0x3); 299daa4478aSJacky Bai /* FIXME config wakeup interrupt in WKPU */ 300daa4478aSJacky Bai mmio_write_32(IMX_SIM1_BASE + 0x3c + 0x4 * cpu, 0x7fffffe3); 301daa4478aSJacky Bai } else { 302daa4478aSJacky Bai /* for core standby/retention mode */ 303daa4478aSJacky Bai mmio_write_32(IMX_CMC1_BASE + 0x50 + 0x4 * cpu, 0x1); 304daa4478aSJacky Bai mmio_write_32(IMX_SIM1_BASE + 0x3c + 0x4 * cpu, 0x7fffffe3); 305daa4478aSJacky Bai dsb(); 306daa4478aSJacky Bai write_scr_el3(read_scr_el3() | SCR_FIQ_BIT); 307daa4478aSJacky Bai isb(); 308daa4478aSJacky Bai } 309daa4478aSJacky Bai 310478af8d3SJacky Bai if (is_local_state_retn(CLUSTER_PWR_STATE(target_state))) { 311daa4478aSJacky Bai /* 312daa4478aSJacky Bai * just for sleep mode for now, need to update to 313478af8d3SJacky Bai * support more modes, same for suspend finish call back. 314daa4478aSJacky Bai */ 315daa4478aSJacky Bai mmio_write_32(IMX_CMC1_BASE + 0x10, 0x1); 316daa4478aSJacky Bai mmio_write_32(IMX_CMC1_BASE + 0x20, 0x1); 317478af8d3SJacky Bai 318478af8d3SJacky Bai } else if (is_local_state_off(CLUSTER_PWR_STATE(target_state))) { 319478af8d3SJacky Bai /* 320478af8d3SJacky Bai * for cluster off state, put cluster into power down mode, 321478af8d3SJacky Bai * config the cluster clock to be off. 322478af8d3SJacky Bai */ 323478af8d3SJacky Bai mmio_write_32(IMX_CMC1_BASE + 0x10, 0x7); 324478af8d3SJacky Bai mmio_write_32(IMX_CMC1_BASE + 0x20, 0xf); 325daa4478aSJacky Bai } 326daa4478aSJacky Bai 327daa4478aSJacky Bai if (is_local_state_off(SYSTEM_PWR_STATE(target_state))) { 328daa4478aSJacky Bai /* 329daa4478aSJacky Bai * low power mode config info used by upower 330daa4478aSJacky Bai * to do low power mode transition. 331daa4478aSJacky Bai */ 332daa4478aSJacky Bai imx_set_pwr_mode_cfg(ADMA_PWR_MODE); 333daa4478aSJacky Bai imx_set_pwr_mode_cfg(ACT_PWR_MODE); 334478af8d3SJacky Bai imx_set_pwr_mode_cfg(PD_PWR_MODE); 335478af8d3SJacky Bai 336478af8d3SJacky Bai /* clear the upower wakeup */ 337478af8d3SJacky Bai upwr_xcp_set_rtd_apd_llwu(APD_DOMAIN, 0, NULL); 338478af8d3SJacky Bai upower_wait_resp(); 339478af8d3SJacky Bai 340478af8d3SJacky Bai /* enable the USB wakeup */ 341478af8d3SJacky Bai usb_wakeup_enable(true); 342478af8d3SJacky Bai 343478af8d3SJacky Bai /* config the WUU to enabled the wakeup source */ 344478af8d3SJacky Bai mmio_write_32(IMX_PCC3_BASE + 0x98, 0xc0800000); 345478af8d3SJacky Bai 346478af8d3SJacky Bai /* !!! clear all the pad wakeup pending event */ 347478af8d3SJacky Bai mmio_write_32(IMX_WUU1_BASE + 0x20, 0xffffffff); 348478af8d3SJacky Bai 349478af8d3SJacky Bai /* enable upower usb phy wakeup by default */ 350478af8d3SJacky Bai mmio_setbits_32(IMX_WUU1_BASE + 0x18, BIT(4) | BIT(1) | BIT(0)); 351478af8d3SJacky Bai 352478af8d3SJacky Bai /* enabled all pad wakeup by default */ 353478af8d3SJacky Bai mmio_write_32(IMX_WUU1_BASE + 0x8, 0xffffffff); 354478af8d3SJacky Bai 355478af8d3SJacky Bai /* save the AD domain context before entering PD mode */ 356478af8d3SJacky Bai imx_apd_ctx_save(cpu); 357daa4478aSJacky Bai } 358daa4478aSJacky Bai } 359daa4478aSJacky Bai 360478af8d3SJacky Bai extern void imx8ulp_init_scmi_server(void); 361daa4478aSJacky Bai void imx_domain_suspend_finish(const psci_power_state_t *target_state) 362daa4478aSJacky Bai { 363daa4478aSJacky Bai unsigned int cpu = MPIDR_AFFLVL0_VAL(read_mpidr_el1()); 364daa4478aSJacky Bai 365daa4478aSJacky Bai if (is_local_state_off(SYSTEM_PWR_STATE(target_state))) { 366478af8d3SJacky Bai /* restore the ap domain context */ 367478af8d3SJacky Bai imx_apd_ctx_restore(cpu); 368478af8d3SJacky Bai 369478af8d3SJacky Bai /* clear the upower wakeup */ 370478af8d3SJacky Bai upwr_xcp_set_rtd_apd_llwu(APD_DOMAIN, 0, NULL); 371478af8d3SJacky Bai upower_wait_resp(); 372478af8d3SJacky Bai 373478af8d3SJacky Bai /* disable all pad wakeup */ 374478af8d3SJacky Bai mmio_write_32(IMX_WUU1_BASE + 0x8, 0x0); 375478af8d3SJacky Bai 376478af8d3SJacky Bai /* clear all the pad wakeup pending event */ 377478af8d3SJacky Bai mmio_write_32(IMX_WUU1_BASE + 0x20, 0xffffffff); 378478af8d3SJacky Bai 379478af8d3SJacky Bai /* 380478af8d3SJacky Bai * disable the usb wakeup after resume to make sure the pending 381478af8d3SJacky Bai * usb wakeup in WUU can be cleared successfully, otherwise, 382478af8d3SJacky Bai * APD will resume failed in next PD mode. 383478af8d3SJacky Bai */ 384478af8d3SJacky Bai usb_wakeup_enable(false); 385478af8d3SJacky Bai 386478af8d3SJacky Bai /* re-init the SCMI channel */ 387478af8d3SJacky Bai imx8ulp_init_scmi_server(); 388daa4478aSJacky Bai } 389daa4478aSJacky Bai 390478af8d3SJacky Bai /* clear cluster's LPM setting. */ 391daa4478aSJacky Bai mmio_write_32(IMX_CMC1_BASE + 0x20, 0x0); 392daa4478aSJacky Bai mmio_write_32(IMX_CMC1_BASE + 0x10, 0x0); 393daa4478aSJacky Bai 394daa4478aSJacky Bai /* clear core's LPM setting */ 395daa4478aSJacky Bai mmio_write_32(IMX_CMC1_BASE + 0x50 + 0x4 * cpu, 0x0); 396daa4478aSJacky Bai mmio_write_32(IMX_SIM1_BASE + 0x3c + 0x4 * cpu, 0x0); 397daa4478aSJacky Bai 398daa4478aSJacky Bai if (is_local_state_off(CORE_PWR_STATE(target_state))) { 399daa4478aSJacky Bai imx_pwr_set_cpu_entry(0, IMX_ROM_ENTRY); 400daa4478aSJacky Bai plat_gic_cpuif_enable(); 401daa4478aSJacky Bai } else { 402daa4478aSJacky Bai dsb(); 403daa4478aSJacky Bai write_scr_el3(read_scr_el3() & (~SCR_FIQ_BIT)); 404daa4478aSJacky Bai isb(); 405daa4478aSJacky Bai } 406daa4478aSJacky Bai } 407fcd41e86SJacky Bai 408fcd41e86SJacky Bai void __dead2 imx8ulp_pwr_domain_pwr_down_wfi(const psci_power_state_t *target_state) 409fcd41e86SJacky Bai { 410fcd41e86SJacky Bai while (1) { 411fcd41e86SJacky Bai wfi(); 412fcd41e86SJacky Bai } 413fcd41e86SJacky Bai } 414fcd41e86SJacky Bai 415fcd41e86SJacky Bai void __dead2 imx8ulp_system_reset(void) 416fcd41e86SJacky Bai { 417fcd41e86SJacky Bai imx_pwr_set_cpu_entry(0, IMX_ROM_ENTRY); 418fcd41e86SJacky Bai 419fcd41e86SJacky Bai /* Write invalid command to WDOG CNT to trigger reset */ 420fcd41e86SJacky Bai mmio_write_32(IMX_WDOG3_BASE + 0x4, 0x12345678); 421fcd41e86SJacky Bai 422fcd41e86SJacky Bai while (true) { 423fcd41e86SJacky Bai wfi(); 424fcd41e86SJacky Bai } 425fcd41e86SJacky Bai } 426fcd41e86SJacky Bai 427daa4478aSJacky Bai int imx_validate_power_state(unsigned int power_state, 428daa4478aSJacky Bai psci_power_state_t *req_state) 429daa4478aSJacky Bai { 430daa4478aSJacky Bai int pwr_lvl = psci_get_pstate_pwrlvl(power_state); 431daa4478aSJacky Bai int pwr_type = psci_get_pstate_type(power_state); 432daa4478aSJacky Bai 433daa4478aSJacky Bai if (pwr_lvl > PLAT_MAX_PWR_LVL) { 434daa4478aSJacky Bai return PSCI_E_INVALID_PARAMS; 435daa4478aSJacky Bai } 436daa4478aSJacky Bai 437daa4478aSJacky Bai if (pwr_type == PSTATE_TYPE_STANDBY) { 438daa4478aSJacky Bai CORE_PWR_STATE(req_state) = PLAT_MAX_RET_STATE; 439daa4478aSJacky Bai CLUSTER_PWR_STATE(req_state) = PLAT_MAX_RET_STATE; 440daa4478aSJacky Bai } 441daa4478aSJacky Bai 442daa4478aSJacky Bai /* No power down state support */ 443daa4478aSJacky Bai if (pwr_type == PSTATE_TYPE_POWERDOWN) { 444daa4478aSJacky Bai return PSCI_E_INVALID_PARAMS; 445daa4478aSJacky Bai } 446daa4478aSJacky Bai 447daa4478aSJacky Bai return PSCI_E_SUCCESS; 448daa4478aSJacky Bai } 449daa4478aSJacky Bai 450daa4478aSJacky Bai void imx_get_sys_suspend_power_state(psci_power_state_t *req_state) 451daa4478aSJacky Bai { 452daa4478aSJacky Bai unsigned int i; 453daa4478aSJacky Bai 454daa4478aSJacky Bai for (i = IMX_PWR_LVL0; i <= PLAT_MAX_PWR_LVL; i++) { 455daa4478aSJacky Bai req_state->pwr_domain_state[i] = PLAT_POWER_DOWN_OFF_STATE; 456daa4478aSJacky Bai } 457daa4478aSJacky Bai } 458daa4478aSJacky Bai 459891c547eSJacky Bai void __dead2 imx_system_off(void) 460891c547eSJacky Bai { 461891c547eSJacky Bai unsigned int i; 462891c547eSJacky Bai 463891c547eSJacky Bai /* config the all the core into OFF mode and IRQ masked. */ 464891c547eSJacky Bai for (i = 0U; i < PLATFORM_CORE_COUNT; i++) { 465891c547eSJacky Bai /* disable wakeup from wkpu */ 466891c547eSJacky Bai mmio_write_32(WKPUx(i), 0x0); 467891c547eSJacky Bai 468891c547eSJacky Bai /* reset the core reset entry to 0x1000 */ 469891c547eSJacky Bai imx_pwr_set_cpu_entry(i, 0x1000); 470891c547eSJacky Bai 471891c547eSJacky Bai /* config the core power mode to off */ 472891c547eSJacky Bai mmio_write_32(AD_COREx_LPMODE(i), 0x3); 473891c547eSJacky Bai } 474891c547eSJacky Bai 475891c547eSJacky Bai plat_gic_cpuif_disable(); 476891c547eSJacky Bai 477*36af80c2SJacky Bai /* power off all the pad */ 478*36af80c2SJacky Bai apd_io_pad_off(); 479*36af80c2SJacky Bai 480891c547eSJacky Bai /* Config the power mode info for entering DPD mode and ACT mode */ 481891c547eSJacky Bai imx_set_pwr_mode_cfg(ADMA_PWR_MODE); 482891c547eSJacky Bai imx_set_pwr_mode_cfg(ACT_PWR_MODE); 483891c547eSJacky Bai imx_set_pwr_mode_cfg(DPD_PWR_MODE); 484891c547eSJacky Bai 485891c547eSJacky Bai /* Set the APD domain into DPD mode */ 486891c547eSJacky Bai mmio_write_32(IMX_CMC1_BASE + 0x10, 0x7); 487891c547eSJacky Bai mmio_write_32(IMX_CMC1_BASE + 0x20, 0x1f); 488891c547eSJacky Bai 489891c547eSJacky Bai /* make sure no pending upower wakeup */ 490891c547eSJacky Bai upwr_xcp_set_rtd_apd_llwu(APD_DOMAIN, 0, NULL); 491891c547eSJacky Bai upower_wait_resp(); 492891c547eSJacky Bai 493891c547eSJacky Bai /* enable the upower wakeup from wuu, act as APD boot up method */ 494891c547eSJacky Bai mmio_write_32(IMX_PCC3_BASE + 0x98, 0xc0800000); 495891c547eSJacky Bai mmio_setbits_32(IMX_WUU1_BASE + 0x18, BIT(4)); 496891c547eSJacky Bai 497891c547eSJacky Bai /* make sure no pad wakeup event is pending */ 498891c547eSJacky Bai mmio_write_32(IMX_WUU1_BASE + 0x20, 0xffffffff); 499891c547eSJacky Bai 500891c547eSJacky Bai wfi(); 501891c547eSJacky Bai 502891c547eSJacky Bai ERROR("power off failed.\n"); 503891c547eSJacky Bai panic(); 504891c547eSJacky Bai } 505891c547eSJacky Bai 506fcd41e86SJacky Bai static const plat_psci_ops_t imx_plat_psci_ops = { 507fcd41e86SJacky Bai .pwr_domain_on = imx_pwr_domain_on, 508fcd41e86SJacky Bai .pwr_domain_on_finish = imx_pwr_domain_on_finish, 509fcd41e86SJacky Bai .validate_ns_entrypoint = imx_validate_ns_entrypoint, 510891c547eSJacky Bai .system_off = imx_system_off, 511fcd41e86SJacky Bai .system_reset = imx8ulp_system_reset, 512fcd41e86SJacky Bai .pwr_domain_off = imx_pwr_domain_off, 513daa4478aSJacky Bai .pwr_domain_suspend = imx_domain_suspend, 514daa4478aSJacky Bai .pwr_domain_suspend_finish = imx_domain_suspend_finish, 515daa4478aSJacky Bai .get_sys_suspend_power_state = imx_get_sys_suspend_power_state, 516daa4478aSJacky Bai .validate_power_state = imx_validate_power_state, 517fcd41e86SJacky Bai .pwr_domain_pwr_down_wfi = imx8ulp_pwr_domain_pwr_down_wfi, 518fcd41e86SJacky Bai }; 519fcd41e86SJacky Bai 520fcd41e86SJacky Bai int plat_setup_psci_ops(uintptr_t sec_entrypoint, 521fcd41e86SJacky Bai const plat_psci_ops_t **psci_ops) 522fcd41e86SJacky Bai { 523fcd41e86SJacky Bai secure_entrypoint = sec_entrypoint; 524fcd41e86SJacky Bai imx_pwr_set_cpu_entry(0, sec_entrypoint); 525fcd41e86SJacky Bai *psci_ops = &imx_plat_psci_ops; 526fcd41e86SJacky Bai 527fcd41e86SJacky Bai mmio_write_32(IMX_CMC1_BASE + 0x18, 0x3f); 528fcd41e86SJacky Bai mmio_write_32(IMX_SIM1_BASE + 0x3c, 0xffffffff); 529fcd41e86SJacky Bai 530fcd41e86SJacky Bai return 0; 531fcd41e86SJacky Bai } 532