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); 24478af8d3SJacky Bai 25fcd41e86SJacky Bai static uintptr_t secure_entrypoint; 26fcd41e86SJacky Bai 27fcd41e86SJacky Bai #define CORE_PWR_STATE(state) ((state)->pwr_domain_state[MPIDR_AFFLVL0]) 28fcd41e86SJacky Bai #define CLUSTER_PWR_STATE(state) ((state)->pwr_domain_state[MPIDR_AFFLVL1]) 29fcd41e86SJacky Bai #define SYSTEM_PWR_STATE(state) ((state)->pwr_domain_state[PLAT_MAX_PWR_LVL]) 30fcd41e86SJacky Bai 31fcd41e86SJacky Bai #define RVBARADDRx(c) (IMX_SIM1_BASE + 0x5c + 0x4 * (c)) 32fcd41e86SJacky Bai #define WKPUx(c) (IMX_SIM1_BASE + 0x3c + 0x4 * (c)) 33fcd41e86SJacky Bai #define AD_COREx_LPMODE(c) (IMX_CMC1_BASE + 0x50 + 0x4 * (c)) 34fcd41e86SJacky Bai 35daa4478aSJacky Bai #define PMIC_CFG(v, m, msk) \ 36daa4478aSJacky Bai { \ 37daa4478aSJacky Bai .volt = (v), \ 38daa4478aSJacky Bai .mode = (m), \ 39daa4478aSJacky Bai .mode_msk = (msk), \ 40daa4478aSJacky Bai } 41daa4478aSJacky Bai 42daa4478aSJacky Bai #define PAD_CFG(c, r, t) \ 43daa4478aSJacky Bai { \ 44daa4478aSJacky Bai .pad_close = (c), \ 45daa4478aSJacky Bai .pad_reset = (r), \ 46daa4478aSJacky Bai .pad_tqsleep = (t) \ 47daa4478aSJacky Bai } 48daa4478aSJacky Bai 49daa4478aSJacky Bai #define BIAS_CFG(m, n, p, mbias) \ 50daa4478aSJacky Bai { \ 51daa4478aSJacky Bai .dombias_cfg = { \ 52daa4478aSJacky Bai .mode = (m), \ 53daa4478aSJacky Bai .rbbn = (n), \ 54daa4478aSJacky Bai .rbbp = (p), \ 55daa4478aSJacky Bai }, \ 56daa4478aSJacky Bai .membias_cfg = {mbias}, \ 57daa4478aSJacky Bai } 58daa4478aSJacky Bai 59daa4478aSJacky Bai #define SWT_BOARD(swt_on, msk) \ 60daa4478aSJacky Bai { \ 61daa4478aSJacky Bai .on = (swt_on), \ 62daa4478aSJacky Bai .mask = (msk), \ 63daa4478aSJacky Bai } 64daa4478aSJacky Bai 65daa4478aSJacky Bai #define SWT_MEM(a, p, m) \ 66daa4478aSJacky Bai { \ 67daa4478aSJacky Bai .array = (a), \ 68daa4478aSJacky Bai .perif = (p), \ 69daa4478aSJacky Bai .mask = (m), \ 70daa4478aSJacky Bai } 71daa4478aSJacky Bai 72478af8d3SJacky Bai extern void upower_wait_resp(void); 73478af8d3SJacky Bai 74fcd41e86SJacky Bai static int imx_pwr_set_cpu_entry(unsigned int cpu, unsigned int entry) 75fcd41e86SJacky Bai { 76fcd41e86SJacky Bai mmio_write_32(RVBARADDRx(cpu), entry); 77fcd41e86SJacky Bai 78fcd41e86SJacky Bai /* set update bit */ 79fcd41e86SJacky Bai mmio_write_32(IMX_SIM1_BASE + 0x8, mmio_read_32(IMX_SIM1_BASE + 0x8) | BIT_32(24 + cpu)); 80fcd41e86SJacky Bai /* wait for ack */ 81fcd41e86SJacky Bai while (!(mmio_read_32(IMX_SIM1_BASE + 0x8) & BIT_32(26 + cpu))) { 82fcd41e86SJacky Bai } 83fcd41e86SJacky Bai 84fcd41e86SJacky Bai /* clear update bit */ 85fcd41e86SJacky Bai mmio_write_32(IMX_SIM1_BASE + 0x8, mmio_read_32(IMX_SIM1_BASE + 0x8) & ~BIT_32(24 + cpu)); 86fcd41e86SJacky Bai /* clear ack bit */ 87fcd41e86SJacky Bai mmio_write_32(IMX_SIM1_BASE + 0x8, mmio_read_32(IMX_SIM1_BASE + 0x8) | BIT_32(26 + cpu)); 88fcd41e86SJacky Bai 89fcd41e86SJacky Bai return 0; 90fcd41e86SJacky Bai } 91fcd41e86SJacky Bai 92fcd41e86SJacky Bai int imx_pwr_domain_on(u_register_t mpidr) 93fcd41e86SJacky Bai { 94fcd41e86SJacky Bai unsigned int cpu = MPIDR_AFFLVL0_VAL(mpidr); 95fcd41e86SJacky Bai 96fcd41e86SJacky Bai imx_pwr_set_cpu_entry(cpu, secure_entrypoint); 97fcd41e86SJacky Bai 98fcd41e86SJacky Bai mmio_write_32(IMX_CMC1_BASE + 0x18, 0x3f); 99fcd41e86SJacky Bai mmio_write_32(IMX_CMC1_BASE + 0x50 + 0x4 * cpu, 0); 100fcd41e86SJacky Bai 101fcd41e86SJacky Bai /* enable wku wakeup for idle */ 102fcd41e86SJacky Bai mmio_write_32(IMX_SIM1_BASE + 0x3c + 0x4 * cpu, 0xffffffff); 103fcd41e86SJacky Bai 104fcd41e86SJacky Bai return PSCI_E_SUCCESS; 105fcd41e86SJacky Bai } 106fcd41e86SJacky Bai 107fcd41e86SJacky Bai void imx_pwr_domain_on_finish(const psci_power_state_t *target_state) 108fcd41e86SJacky Bai { 109fcd41e86SJacky Bai imx_pwr_set_cpu_entry(0, IMX_ROM_ENTRY); 110fcd41e86SJacky Bai plat_gic_pcpu_init(); 111fcd41e86SJacky Bai plat_gic_cpuif_enable(); 112fcd41e86SJacky Bai } 113fcd41e86SJacky Bai 114fcd41e86SJacky Bai int imx_validate_ns_entrypoint(uintptr_t ns_entrypoint) 115fcd41e86SJacky Bai { 116fcd41e86SJacky Bai return PSCI_E_SUCCESS; 117fcd41e86SJacky Bai } 118fcd41e86SJacky Bai 119fcd41e86SJacky Bai void imx_pwr_domain_off(const psci_power_state_t *target_state) 120fcd41e86SJacky Bai { 121fcd41e86SJacky Bai unsigned int cpu = MPIDR_AFFLVL0_VAL(read_mpidr_el1()); 122fcd41e86SJacky Bai 123fcd41e86SJacky Bai plat_gic_cpuif_disable(); 124fcd41e86SJacky Bai 125fcd41e86SJacky Bai /* disable wakeup */ 126fcd41e86SJacky Bai mmio_write_32(WKPUx(cpu), 0); 127fcd41e86SJacky Bai 128daa4478aSJacky Bai /* set core power mode to PD */ 129fcd41e86SJacky Bai mmio_write_32(AD_COREx_LPMODE(cpu), 0x3); 130fcd41e86SJacky Bai } 131478af8d3SJacky Bai 132daa4478aSJacky Bai /* APD power mode config */ 133daa4478aSJacky Bai ps_apd_pwr_mode_cfgs_t apd_pwr_mode_cfgs = { 134*891c547eSJacky Bai [DPD_PWR_MODE] = { 135*891c547eSJacky Bai .swt_board_offs = 0x180, 136*891c547eSJacky Bai .swt_mem_offs = 0x188, 137*891c547eSJacky Bai .pmic_cfg = PMIC_CFG(0x23, 0xa, 0x2), 138*891c547eSJacky Bai .pad_cfg = PAD_CFG(0xc, 0x0, 0x01e80a02), 139*891c547eSJacky Bai .bias_cfg = BIAS_CFG(0x0, 0x2, 0x2, 0x0), 140*891c547eSJacky Bai }, 141*891c547eSJacky Bai 142478af8d3SJacky Bai /* PD */ 143478af8d3SJacky Bai [PD_PWR_MODE] = { 144478af8d3SJacky Bai .swt_board_offs = 0x170, 145478af8d3SJacky Bai .swt_mem_offs = 0x178, 146478af8d3SJacky Bai .pmic_cfg = PMIC_CFG(0x23, 0x2, 0x2), 147478af8d3SJacky Bai .pad_cfg = PAD_CFG(0x0, 0x0, 0x01e80a00), 148478af8d3SJacky Bai .bias_cfg = BIAS_CFG(0x0, 0x2, 0x2, 0x0), 149478af8d3SJacky Bai }, 150478af8d3SJacky Bai 151daa4478aSJacky Bai [ADMA_PWR_MODE] = { 152daa4478aSJacky Bai .swt_board_offs = 0x120, 153daa4478aSJacky Bai .swt_mem_offs = 0x128, 154daa4478aSJacky Bai .pmic_cfg = PMIC_CFG(0x23, 0x0, 0x2), 155daa4478aSJacky Bai .pad_cfg = PAD_CFG(0x0, 0x0, 0x0deb7a00), 156daa4478aSJacky Bai .bias_cfg = BIAS_CFG(0x0, 0x2, 0x2, 0x0), 157daa4478aSJacky Bai }, 158daa4478aSJacky Bai 159daa4478aSJacky Bai [ACT_PWR_MODE] = { 160daa4478aSJacky Bai .swt_board_offs = 0x110, 161daa4478aSJacky Bai .swt_mem_offs = 0x118, 162daa4478aSJacky Bai .pmic_cfg = PMIC_CFG(0x23, 0x2, 0x2), 163daa4478aSJacky Bai .pad_cfg = PAD_CFG(0x0, 0x0, 0x0deb7a00), 164daa4478aSJacky Bai .bias_cfg = BIAS_CFG(0x0, 0x2, 0x2, 0x0), 165daa4478aSJacky Bai }, 166daa4478aSJacky Bai }; 167daa4478aSJacky Bai 168daa4478aSJacky Bai /* APD power switch config */ 169daa4478aSJacky Bai ps_apd_swt_cfgs_t apd_swt_cfgs = { 170*891c547eSJacky Bai [DPD_PWR_MODE] = { 171*891c547eSJacky Bai .swt_board[0] = SWT_BOARD(0x00060003, 0x7c), 172*891c547eSJacky Bai .swt_mem[0] = SWT_MEM(0x0, 0x0, 0x1ffff), 173*891c547eSJacky Bai .swt_mem[1] = SWT_MEM(0x003fffff, 0x003fffff, 0x0), 174*891c547eSJacky Bai }, 175*891c547eSJacky Bai 176478af8d3SJacky Bai [PD_PWR_MODE] = { 177478af8d3SJacky Bai .swt_board[0] = SWT_BOARD(0x00060003, 0x00001e74), 178478af8d3SJacky Bai .swt_mem[0] = SWT_MEM(0x00010c00, 0x0, 0x1ffff), 179478af8d3SJacky Bai .swt_mem[1] = SWT_MEM(0x003fffff, 0x003f0000, 0x0), 180478af8d3SJacky Bai }, 181478af8d3SJacky Bai 182daa4478aSJacky Bai [ADMA_PWR_MODE] = { 183478af8d3SJacky Bai .swt_board[0] = SWT_BOARD(0x0006ff77, 0x0006ff7c), 184478af8d3SJacky Bai .swt_mem[0] = SWT_MEM(0x0001fffd, 0x0001fffd, 0x1ffff), 185478af8d3SJacky Bai .swt_mem[1] = SWT_MEM(0x003fffff, 0x003fffff, 0x0), 186daa4478aSJacky Bai }, 187daa4478aSJacky Bai 188daa4478aSJacky Bai [ACT_PWR_MODE] = { 189478af8d3SJacky Bai .swt_board[0] = SWT_BOARD(0x0006ff77, 0x0000ff7c), 190478af8d3SJacky Bai .swt_mem[0] = SWT_MEM(0x0001fffd, 0x0001fffd, 0x1ffff), 191478af8d3SJacky Bai .swt_mem[1] = SWT_MEM(0x003fffff, 0x003fffff, 0x0), 192daa4478aSJacky Bai }, 193daa4478aSJacky Bai }; 194daa4478aSJacky Bai 195daa4478aSJacky Bai struct ps_pwr_mode_cfg_t *pwr_sys_cfg = (struct ps_pwr_mode_cfg_t *)UPWR_DRAM_SHARED_BASE_ADDR; 196daa4478aSJacky Bai 197daa4478aSJacky Bai void imx_set_pwr_mode_cfg(abs_pwr_mode_t mode) 198daa4478aSJacky Bai { 199daa4478aSJacky Bai if (mode >= NUM_PWR_MODES) { 200daa4478aSJacky Bai return; 201daa4478aSJacky Bai } 202daa4478aSJacky Bai 203daa4478aSJacky Bai /* apd power mode config */ 204daa4478aSJacky Bai memcpy(&pwr_sys_cfg->ps_apd_pwr_mode_cfg[mode], &apd_pwr_mode_cfgs[mode], 205daa4478aSJacky Bai sizeof(struct ps_apd_pwr_mode_cfg_t)); 206daa4478aSJacky Bai 207daa4478aSJacky Bai /* apd power switch config */ 208daa4478aSJacky Bai memcpy(&pwr_sys_cfg->ps_apd_swt_cfg[mode], &apd_swt_cfgs[mode], sizeof(swt_config_t)); 209daa4478aSJacky Bai } 210daa4478aSJacky Bai 211daa4478aSJacky Bai void imx_domain_suspend(const psci_power_state_t *target_state) 212daa4478aSJacky Bai { 213daa4478aSJacky Bai unsigned int cpu = MPIDR_AFFLVL0_VAL(read_mpidr_el1()); 214daa4478aSJacky Bai 215daa4478aSJacky Bai if (is_local_state_off(CORE_PWR_STATE(target_state))) { 216daa4478aSJacky Bai plat_gic_cpuif_disable(); 217daa4478aSJacky Bai imx_pwr_set_cpu_entry(cpu, secure_entrypoint); 218daa4478aSJacky Bai /* core put into power down */ 219daa4478aSJacky Bai mmio_write_32(IMX_CMC1_BASE + 0x50 + 0x4 * cpu, 0x3); 220daa4478aSJacky Bai /* FIXME config wakeup interrupt in WKPU */ 221daa4478aSJacky Bai mmio_write_32(IMX_SIM1_BASE + 0x3c + 0x4 * cpu, 0x7fffffe3); 222daa4478aSJacky Bai } else { 223daa4478aSJacky Bai /* for core standby/retention mode */ 224daa4478aSJacky Bai mmio_write_32(IMX_CMC1_BASE + 0x50 + 0x4 * cpu, 0x1); 225daa4478aSJacky Bai mmio_write_32(IMX_SIM1_BASE + 0x3c + 0x4 * cpu, 0x7fffffe3); 226daa4478aSJacky Bai dsb(); 227daa4478aSJacky Bai write_scr_el3(read_scr_el3() | SCR_FIQ_BIT); 228daa4478aSJacky Bai isb(); 229daa4478aSJacky Bai } 230daa4478aSJacky Bai 231478af8d3SJacky Bai if (is_local_state_retn(CLUSTER_PWR_STATE(target_state))) { 232daa4478aSJacky Bai /* 233daa4478aSJacky Bai * just for sleep mode for now, need to update to 234478af8d3SJacky Bai * support more modes, same for suspend finish call back. 235daa4478aSJacky Bai */ 236daa4478aSJacky Bai mmio_write_32(IMX_CMC1_BASE + 0x10, 0x1); 237daa4478aSJacky Bai mmio_write_32(IMX_CMC1_BASE + 0x20, 0x1); 238478af8d3SJacky Bai 239478af8d3SJacky Bai } else if (is_local_state_off(CLUSTER_PWR_STATE(target_state))) { 240478af8d3SJacky Bai /* 241478af8d3SJacky Bai * for cluster off state, put cluster into power down mode, 242478af8d3SJacky Bai * config the cluster clock to be off. 243478af8d3SJacky Bai */ 244478af8d3SJacky Bai mmio_write_32(IMX_CMC1_BASE + 0x10, 0x7); 245478af8d3SJacky Bai mmio_write_32(IMX_CMC1_BASE + 0x20, 0xf); 246daa4478aSJacky Bai } 247daa4478aSJacky Bai 248daa4478aSJacky Bai if (is_local_state_off(SYSTEM_PWR_STATE(target_state))) { 249daa4478aSJacky Bai /* 250daa4478aSJacky Bai * low power mode config info used by upower 251daa4478aSJacky Bai * to do low power mode transition. 252daa4478aSJacky Bai */ 253daa4478aSJacky Bai imx_set_pwr_mode_cfg(ADMA_PWR_MODE); 254daa4478aSJacky Bai imx_set_pwr_mode_cfg(ACT_PWR_MODE); 255478af8d3SJacky Bai imx_set_pwr_mode_cfg(PD_PWR_MODE); 256478af8d3SJacky Bai 257478af8d3SJacky Bai /* clear the upower wakeup */ 258478af8d3SJacky Bai upwr_xcp_set_rtd_apd_llwu(APD_DOMAIN, 0, NULL); 259478af8d3SJacky Bai upower_wait_resp(); 260478af8d3SJacky Bai 261478af8d3SJacky Bai /* enable the USB wakeup */ 262478af8d3SJacky Bai usb_wakeup_enable(true); 263478af8d3SJacky Bai 264478af8d3SJacky Bai /* config the WUU to enabled the wakeup source */ 265478af8d3SJacky Bai mmio_write_32(IMX_PCC3_BASE + 0x98, 0xc0800000); 266478af8d3SJacky Bai 267478af8d3SJacky Bai /* !!! clear all the pad wakeup pending event */ 268478af8d3SJacky Bai mmio_write_32(IMX_WUU1_BASE + 0x20, 0xffffffff); 269478af8d3SJacky Bai 270478af8d3SJacky Bai /* enable upower usb phy wakeup by default */ 271478af8d3SJacky Bai mmio_setbits_32(IMX_WUU1_BASE + 0x18, BIT(4) | BIT(1) | BIT(0)); 272478af8d3SJacky Bai 273478af8d3SJacky Bai /* enabled all pad wakeup by default */ 274478af8d3SJacky Bai mmio_write_32(IMX_WUU1_BASE + 0x8, 0xffffffff); 275478af8d3SJacky Bai 276478af8d3SJacky Bai /* save the AD domain context before entering PD mode */ 277478af8d3SJacky Bai imx_apd_ctx_save(cpu); 278daa4478aSJacky Bai } 279daa4478aSJacky Bai } 280daa4478aSJacky Bai 281478af8d3SJacky Bai extern void imx8ulp_init_scmi_server(void); 282daa4478aSJacky Bai void imx_domain_suspend_finish(const psci_power_state_t *target_state) 283daa4478aSJacky Bai { 284daa4478aSJacky Bai unsigned int cpu = MPIDR_AFFLVL0_VAL(read_mpidr_el1()); 285daa4478aSJacky Bai 286daa4478aSJacky Bai if (is_local_state_off(SYSTEM_PWR_STATE(target_state))) { 287478af8d3SJacky Bai /* restore the ap domain context */ 288478af8d3SJacky Bai imx_apd_ctx_restore(cpu); 289478af8d3SJacky Bai 290478af8d3SJacky Bai /* clear the upower wakeup */ 291478af8d3SJacky Bai upwr_xcp_set_rtd_apd_llwu(APD_DOMAIN, 0, NULL); 292478af8d3SJacky Bai upower_wait_resp(); 293478af8d3SJacky Bai 294478af8d3SJacky Bai /* disable all pad wakeup */ 295478af8d3SJacky Bai mmio_write_32(IMX_WUU1_BASE + 0x8, 0x0); 296478af8d3SJacky Bai 297478af8d3SJacky Bai /* clear all the pad wakeup pending event */ 298478af8d3SJacky Bai mmio_write_32(IMX_WUU1_BASE + 0x20, 0xffffffff); 299478af8d3SJacky Bai 300478af8d3SJacky Bai /* 301478af8d3SJacky Bai * disable the usb wakeup after resume to make sure the pending 302478af8d3SJacky Bai * usb wakeup in WUU can be cleared successfully, otherwise, 303478af8d3SJacky Bai * APD will resume failed in next PD mode. 304478af8d3SJacky Bai */ 305478af8d3SJacky Bai usb_wakeup_enable(false); 306478af8d3SJacky Bai 307478af8d3SJacky Bai /* re-init the SCMI channel */ 308478af8d3SJacky Bai imx8ulp_init_scmi_server(); 309daa4478aSJacky Bai } 310daa4478aSJacky Bai 311478af8d3SJacky Bai /* clear cluster's LPM setting. */ 312daa4478aSJacky Bai mmio_write_32(IMX_CMC1_BASE + 0x20, 0x0); 313daa4478aSJacky Bai mmio_write_32(IMX_CMC1_BASE + 0x10, 0x0); 314daa4478aSJacky Bai 315daa4478aSJacky Bai /* clear core's LPM setting */ 316daa4478aSJacky Bai mmio_write_32(IMX_CMC1_BASE + 0x50 + 0x4 * cpu, 0x0); 317daa4478aSJacky Bai mmio_write_32(IMX_SIM1_BASE + 0x3c + 0x4 * cpu, 0x0); 318daa4478aSJacky Bai 319daa4478aSJacky Bai if (is_local_state_off(CORE_PWR_STATE(target_state))) { 320daa4478aSJacky Bai imx_pwr_set_cpu_entry(0, IMX_ROM_ENTRY); 321daa4478aSJacky Bai plat_gic_cpuif_enable(); 322daa4478aSJacky Bai } else { 323daa4478aSJacky Bai dsb(); 324daa4478aSJacky Bai write_scr_el3(read_scr_el3() & (~SCR_FIQ_BIT)); 325daa4478aSJacky Bai isb(); 326daa4478aSJacky Bai } 327daa4478aSJacky Bai } 328fcd41e86SJacky Bai 329fcd41e86SJacky Bai void __dead2 imx8ulp_pwr_domain_pwr_down_wfi(const psci_power_state_t *target_state) 330fcd41e86SJacky Bai { 331fcd41e86SJacky Bai while (1) { 332fcd41e86SJacky Bai wfi(); 333fcd41e86SJacky Bai } 334fcd41e86SJacky Bai } 335fcd41e86SJacky Bai 336fcd41e86SJacky Bai void __dead2 imx8ulp_system_reset(void) 337fcd41e86SJacky Bai { 338fcd41e86SJacky Bai imx_pwr_set_cpu_entry(0, IMX_ROM_ENTRY); 339fcd41e86SJacky Bai 340fcd41e86SJacky Bai /* Write invalid command to WDOG CNT to trigger reset */ 341fcd41e86SJacky Bai mmio_write_32(IMX_WDOG3_BASE + 0x4, 0x12345678); 342fcd41e86SJacky Bai 343fcd41e86SJacky Bai while (true) { 344fcd41e86SJacky Bai wfi(); 345fcd41e86SJacky Bai } 346fcd41e86SJacky Bai } 347fcd41e86SJacky Bai 348daa4478aSJacky Bai int imx_validate_power_state(unsigned int power_state, 349daa4478aSJacky Bai psci_power_state_t *req_state) 350daa4478aSJacky Bai { 351daa4478aSJacky Bai int pwr_lvl = psci_get_pstate_pwrlvl(power_state); 352daa4478aSJacky Bai int pwr_type = psci_get_pstate_type(power_state); 353daa4478aSJacky Bai 354daa4478aSJacky Bai if (pwr_lvl > PLAT_MAX_PWR_LVL) { 355daa4478aSJacky Bai return PSCI_E_INVALID_PARAMS; 356daa4478aSJacky Bai } 357daa4478aSJacky Bai 358daa4478aSJacky Bai if (pwr_type == PSTATE_TYPE_STANDBY) { 359daa4478aSJacky Bai CORE_PWR_STATE(req_state) = PLAT_MAX_RET_STATE; 360daa4478aSJacky Bai CLUSTER_PWR_STATE(req_state) = PLAT_MAX_RET_STATE; 361daa4478aSJacky Bai } 362daa4478aSJacky Bai 363daa4478aSJacky Bai /* No power down state support */ 364daa4478aSJacky Bai if (pwr_type == PSTATE_TYPE_POWERDOWN) { 365daa4478aSJacky Bai return PSCI_E_INVALID_PARAMS; 366daa4478aSJacky Bai } 367daa4478aSJacky Bai 368daa4478aSJacky Bai return PSCI_E_SUCCESS; 369daa4478aSJacky Bai } 370daa4478aSJacky Bai 371daa4478aSJacky Bai void imx_get_sys_suspend_power_state(psci_power_state_t *req_state) 372daa4478aSJacky Bai { 373daa4478aSJacky Bai unsigned int i; 374daa4478aSJacky Bai 375daa4478aSJacky Bai for (i = IMX_PWR_LVL0; i <= PLAT_MAX_PWR_LVL; i++) { 376daa4478aSJacky Bai req_state->pwr_domain_state[i] = PLAT_POWER_DOWN_OFF_STATE; 377daa4478aSJacky Bai } 378daa4478aSJacky Bai } 379daa4478aSJacky Bai 380*891c547eSJacky Bai void __dead2 imx_system_off(void) 381*891c547eSJacky Bai { 382*891c547eSJacky Bai unsigned int i; 383*891c547eSJacky Bai 384*891c547eSJacky Bai /* config the all the core into OFF mode and IRQ masked. */ 385*891c547eSJacky Bai for (i = 0U; i < PLATFORM_CORE_COUNT; i++) { 386*891c547eSJacky Bai /* disable wakeup from wkpu */ 387*891c547eSJacky Bai mmio_write_32(WKPUx(i), 0x0); 388*891c547eSJacky Bai 389*891c547eSJacky Bai /* reset the core reset entry to 0x1000 */ 390*891c547eSJacky Bai imx_pwr_set_cpu_entry(i, 0x1000); 391*891c547eSJacky Bai 392*891c547eSJacky Bai /* config the core power mode to off */ 393*891c547eSJacky Bai mmio_write_32(AD_COREx_LPMODE(i), 0x3); 394*891c547eSJacky Bai } 395*891c547eSJacky Bai 396*891c547eSJacky Bai plat_gic_cpuif_disable(); 397*891c547eSJacky Bai 398*891c547eSJacky Bai /* Config the power mode info for entering DPD mode and ACT mode */ 399*891c547eSJacky Bai imx_set_pwr_mode_cfg(ADMA_PWR_MODE); 400*891c547eSJacky Bai imx_set_pwr_mode_cfg(ACT_PWR_MODE); 401*891c547eSJacky Bai imx_set_pwr_mode_cfg(DPD_PWR_MODE); 402*891c547eSJacky Bai 403*891c547eSJacky Bai /* Set the APD domain into DPD mode */ 404*891c547eSJacky Bai mmio_write_32(IMX_CMC1_BASE + 0x10, 0x7); 405*891c547eSJacky Bai mmio_write_32(IMX_CMC1_BASE + 0x20, 0x1f); 406*891c547eSJacky Bai 407*891c547eSJacky Bai /* make sure no pending upower wakeup */ 408*891c547eSJacky Bai upwr_xcp_set_rtd_apd_llwu(APD_DOMAIN, 0, NULL); 409*891c547eSJacky Bai upower_wait_resp(); 410*891c547eSJacky Bai 411*891c547eSJacky Bai /* enable the upower wakeup from wuu, act as APD boot up method */ 412*891c547eSJacky Bai mmio_write_32(IMX_PCC3_BASE + 0x98, 0xc0800000); 413*891c547eSJacky Bai mmio_setbits_32(IMX_WUU1_BASE + 0x18, BIT(4)); 414*891c547eSJacky Bai 415*891c547eSJacky Bai /* make sure no pad wakeup event is pending */ 416*891c547eSJacky Bai mmio_write_32(IMX_WUU1_BASE + 0x20, 0xffffffff); 417*891c547eSJacky Bai 418*891c547eSJacky Bai wfi(); 419*891c547eSJacky Bai 420*891c547eSJacky Bai ERROR("power off failed.\n"); 421*891c547eSJacky Bai panic(); 422*891c547eSJacky Bai } 423*891c547eSJacky Bai 424fcd41e86SJacky Bai static const plat_psci_ops_t imx_plat_psci_ops = { 425fcd41e86SJacky Bai .pwr_domain_on = imx_pwr_domain_on, 426fcd41e86SJacky Bai .pwr_domain_on_finish = imx_pwr_domain_on_finish, 427fcd41e86SJacky Bai .validate_ns_entrypoint = imx_validate_ns_entrypoint, 428*891c547eSJacky Bai .system_off = imx_system_off, 429fcd41e86SJacky Bai .system_reset = imx8ulp_system_reset, 430fcd41e86SJacky Bai .pwr_domain_off = imx_pwr_domain_off, 431daa4478aSJacky Bai .pwr_domain_suspend = imx_domain_suspend, 432daa4478aSJacky Bai .pwr_domain_suspend_finish = imx_domain_suspend_finish, 433daa4478aSJacky Bai .get_sys_suspend_power_state = imx_get_sys_suspend_power_state, 434daa4478aSJacky Bai .validate_power_state = imx_validate_power_state, 435fcd41e86SJacky Bai .pwr_domain_pwr_down_wfi = imx8ulp_pwr_domain_pwr_down_wfi, 436fcd41e86SJacky Bai }; 437fcd41e86SJacky Bai 438fcd41e86SJacky Bai int plat_setup_psci_ops(uintptr_t sec_entrypoint, 439fcd41e86SJacky Bai const plat_psci_ops_t **psci_ops) 440fcd41e86SJacky Bai { 441fcd41e86SJacky Bai secure_entrypoint = sec_entrypoint; 442fcd41e86SJacky Bai imx_pwr_set_cpu_entry(0, sec_entrypoint); 443fcd41e86SJacky Bai *psci_ops = &imx_plat_psci_ops; 444fcd41e86SJacky Bai 445fcd41e86SJacky Bai mmio_write_32(IMX_CMC1_BASE + 0x18, 0x3f); 446fcd41e86SJacky Bai mmio_write_32(IMX_SIM1_BASE + 0x3c, 0xffffffff); 447fcd41e86SJacky Bai 448fcd41e86SJacky Bai return 0; 449fcd41e86SJacky Bai } 450