1*4ddfb6f1SJacky Bai /* 2*4ddfb6f1SJacky Bai * Copyright 2025 NXP 3*4ddfb6f1SJacky Bai * 4*4ddfb6f1SJacky Bai * SPDX-License-Identifier: BSD-3-Clause 5*4ddfb6f1SJacky Bai */ 6*4ddfb6f1SJacky Bai 7*4ddfb6f1SJacky Bai #include "../drivers/arm/gic/v3/gicv3_private.h" 8*4ddfb6f1SJacky Bai 9*4ddfb6f1SJacky Bai #include <drivers/arm/gic.h> 10*4ddfb6f1SJacky Bai #include <lib/mmio.h> 11*4ddfb6f1SJacky Bai #include <scmi_imx9.h> 12*4ddfb6f1SJacky Bai 13*4ddfb6f1SJacky Bai #include <ele_api.h> 14*4ddfb6f1SJacky Bai #include <imx9_sys_sleep.h> 15*4ddfb6f1SJacky Bai #include <imx_scmi_client.h> 16*4ddfb6f1SJacky Bai #include <plat_imx8.h> 17*4ddfb6f1SJacky Bai 18*4ddfb6f1SJacky Bai #define IRQ_MASK(x) irq_mask[(x) / 32U] 19*4ddfb6f1SJacky Bai #define IRQ_SHIFT(x) (1U << (x) % 32U) 20*4ddfb6f1SJacky Bai 21*4ddfb6f1SJacky Bai static uint32_t irq_mask[IMR_NUM] = { 0x0 }; 22*4ddfb6f1SJacky Bai static struct scmi_per_lpm_config per_lpm[PER_NUM]; 23*4ddfb6f1SJacky Bai 24*4ddfb6f1SJacky Bai static const uint32_t gpio_ctrl_offset[GPIO_CTRL_REG_NUM] = { 25*4ddfb6f1SJacky Bai 0xc, 0x10, 0x14, 0x18, 0x1c, 0x40, 0x54, 0x58 26*4ddfb6f1SJacky Bai }; 27*4ddfb6f1SJacky Bai 28*4ddfb6f1SJacky Bai bool has_netc_irq; 29*4ddfb6f1SJacky Bai static bool has_wakeup_irq; 30*4ddfb6f1SJacky Bai static bool gpio_wakeup; 31*4ddfb6f1SJacky Bai bool keep_wakeupmix_on; 32*4ddfb6f1SJacky Bai 33*4ddfb6f1SJacky Bai #if HAS_XSPI_SUPPORT 34*4ddfb6f1SJacky Bai static uint32_t xspi_mto[2]; 35*4ddfb6f1SJacky Bai 36*4ddfb6f1SJacky Bai static void xspi_save(void) 37*4ddfb6f1SJacky Bai { 38*4ddfb6f1SJacky Bai /* Save the XSPI MTO register */ 39*4ddfb6f1SJacky Bai xspi_mto[0] = mmio_read_32(XSPI1_BASE + XSPI_MTO); 40*4ddfb6f1SJacky Bai xspi_mto[1] = mmio_read_32(XSPI2_BASE + XSPI_MTO); 41*4ddfb6f1SJacky Bai } 42*4ddfb6f1SJacky Bai 43*4ddfb6f1SJacky Bai static void xspi_restore(void) 44*4ddfb6f1SJacky Bai { 45*4ddfb6f1SJacky Bai /* request the GMID first */ 46*4ddfb6f1SJacky Bai ele_release_gmid(); 47*4ddfb6f1SJacky Bai mmio_write_32(XSPI1_BASE + XSPI_MTO, xspi_mto[0]); 48*4ddfb6f1SJacky Bai mmio_write_32(XSPI2_BASE + XSPI_MTO, xspi_mto[1]); 49*4ddfb6f1SJacky Bai } 50*4ddfb6f1SJacky Bai #endif 51*4ddfb6f1SJacky Bai 52*4ddfb6f1SJacky Bai static void gpio_save(struct gpio_ctx *ctx) 53*4ddfb6f1SJacky Bai { 54*4ddfb6f1SJacky Bai for (uint32_t i = 0U; i < GPIO_CTRL_REG_NUM; i++) { 55*4ddfb6f1SJacky Bai /* First 4 regs for permission */ 56*4ddfb6f1SJacky Bai if (i < 4U) { 57*4ddfb6f1SJacky Bai ctx->port_ctrl[i] = mmio_read_32(ctx->base + gpio_ctrl_offset[i]); 58*4ddfb6f1SJacky Bai /* Clear the permission to read the gpio non-secure setting. */ 59*4ddfb6f1SJacky Bai mmio_write_32(ctx->base + gpio_ctrl_offset[i], 0x0); 60*4ddfb6f1SJacky Bai } else { 61*4ddfb6f1SJacky Bai ctx->port_ctrl[i] = mmio_read_32(ctx->base + gpio_ctrl_offset[i]); 62*4ddfb6f1SJacky Bai } 63*4ddfb6f1SJacky Bai } 64*4ddfb6f1SJacky Bai 65*4ddfb6f1SJacky Bai /* Save the gpio icr */ 66*4ddfb6f1SJacky Bai for (uint32_t i = 0U; i < ctx->pin_num; i++) { 67*4ddfb6f1SJacky Bai ctx->gpio_icr[i] = mmio_read_32(ctx->base + 0x80 + i * 4U); 68*4ddfb6f1SJacky Bai /* Mark if any gpio pin is used as wakeup irq */ 69*4ddfb6f1SJacky Bai if (ctx->gpio_icr[i]) { 70*4ddfb6f1SJacky Bai gpio_wakeup = true; 71*4ddfb6f1SJacky Bai } 72*4ddfb6f1SJacky Bai } 73*4ddfb6f1SJacky Bai 74*4ddfb6f1SJacky Bai /* Restore the gpio permission */ 75*4ddfb6f1SJacky Bai for (uint32_t i = 0U; i < 4U; i++) { 76*4ddfb6f1SJacky Bai mmio_write_32(ctx->base + gpio_ctrl_offset[i], ctx->port_ctrl[i]); 77*4ddfb6f1SJacky Bai } 78*4ddfb6f1SJacky Bai } 79*4ddfb6f1SJacky Bai static void gpio_restore(struct gpio_ctx *ctx) 80*4ddfb6f1SJacky Bai { 81*4ddfb6f1SJacky Bai /* Clear the gpio permission */ 82*4ddfb6f1SJacky Bai for (uint32_t i = 0U; i < 4U; i++) { 83*4ddfb6f1SJacky Bai mmio_write_32(ctx->base + gpio_ctrl_offset[i], 0x0); 84*4ddfb6f1SJacky Bai } 85*4ddfb6f1SJacky Bai 86*4ddfb6f1SJacky Bai for (uint32_t i = 0U; i < ctx->pin_num; i++) { 87*4ddfb6f1SJacky Bai mmio_write_32(ctx->base + 0x80 + i * 4U, ctx->gpio_icr[i]); 88*4ddfb6f1SJacky Bai } 89*4ddfb6f1SJacky Bai 90*4ddfb6f1SJacky Bai for (uint32_t i = 4U; i < GPIO_CTRL_REG_NUM; i++) 91*4ddfb6f1SJacky Bai mmio_write_32(ctx->base + gpio_ctrl_offset[i], ctx->port_ctrl[i]); 92*4ddfb6f1SJacky Bai 93*4ddfb6f1SJacky Bai /* Permission config retore last */ 94*4ddfb6f1SJacky Bai for (uint32_t i = 0U; i < 4U; i++) { 95*4ddfb6f1SJacky Bai mmio_write_32(ctx->base + gpio_ctrl_offset[i], ctx->port_ctrl[i]); 96*4ddfb6f1SJacky Bai } 97*4ddfb6f1SJacky Bai 98*4ddfb6f1SJacky Bai gpio_wakeup = false; 99*4ddfb6f1SJacky Bai } 100*4ddfb6f1SJacky Bai 101*4ddfb6f1SJacky Bai static void wdog_save(struct wdog_ctx *wdog) 102*4ddfb6f1SJacky Bai { 103*4ddfb6f1SJacky Bai wdog->regs[0] = mmio_read_32(wdog->base); 104*4ddfb6f1SJacky Bai wdog->regs[1] = mmio_read_32(wdog->base + 0x8); 105*4ddfb6f1SJacky Bai } 106*4ddfb6f1SJacky Bai 107*4ddfb6f1SJacky Bai static void wdog_restore(struct wdog_ctx *wdog) 108*4ddfb6f1SJacky Bai { 109*4ddfb6f1SJacky Bai uint32_t cs, toval; 110*4ddfb6f1SJacky Bai 111*4ddfb6f1SJacky Bai cs = mmio_read_32(wdog->base); 112*4ddfb6f1SJacky Bai toval = mmio_read_32(wdog->base + 0x8); 113*4ddfb6f1SJacky Bai 114*4ddfb6f1SJacky Bai /* Wdog does not lost context, no need to restore */ 115*4ddfb6f1SJacky Bai if (cs == wdog->regs[0] && toval == wdog->regs[1]) { 116*4ddfb6f1SJacky Bai return; 117*4ddfb6f1SJacky Bai } 118*4ddfb6f1SJacky Bai 119*4ddfb6f1SJacky Bai /* Reconfig the CS */ 120*4ddfb6f1SJacky Bai mmio_write_32(wdog->base, wdog->regs[0]); 121*4ddfb6f1SJacky Bai /* Set the tiemout value */ 122*4ddfb6f1SJacky Bai mmio_write_32(wdog->base + 0x8, wdog->regs[1]); 123*4ddfb6f1SJacky Bai 124*4ddfb6f1SJacky Bai /* Wait for the lock status */ 125*4ddfb6f1SJacky Bai while ((mmio_read_32(wdog->base) & BIT(11))) { 126*4ddfb6f1SJacky Bai ; 127*4ddfb6f1SJacky Bai } 128*4ddfb6f1SJacky Bai 129*4ddfb6f1SJacky Bai /* Wait for the config done */ 130*4ddfb6f1SJacky Bai while (!(mmio_read_32(wdog->base) & BIT(10))) { 131*4ddfb6f1SJacky Bai ; 132*4ddfb6f1SJacky Bai } 133*4ddfb6f1SJacky Bai } 134*4ddfb6f1SJacky Bai 135*4ddfb6f1SJacky Bai static inline bool active_wakeup_irq(uint32_t irq) 136*4ddfb6f1SJacky Bai { 137*4ddfb6f1SJacky Bai return !(IRQ_MASK(irq) & IRQ_SHIFT(irq)); 138*4ddfb6f1SJacky Bai } 139*4ddfb6f1SJacky Bai 140*4ddfb6f1SJacky Bai /* 141*4ddfb6f1SJacky Bai * For peripherals like CANs, GPIOs & UARTs that need to support 142*4ddfb6f1SJacky Bai * async wakeup when clock is gated, LPCGs of these IPs need to be 143*4ddfb6f1SJacky Bai * changed to CPU LPM controlled, and for CANs &UARTs, we also need 144*4ddfb6f1SJacky Bai * to make sure its ROOT clock slice is enabled. 145*4ddfb6f1SJacky Bai */ 146*4ddfb6f1SJacky Bai static void peripheral_qchannel_hsk(bool en) 147*4ddfb6f1SJacky Bai { 148*4ddfb6f1SJacky Bai uint32_t num_hsks = 0U; 149*4ddfb6f1SJacky Bai 150*4ddfb6f1SJacky Bai for (uint32_t i = 0U; i < ARRAY_SIZE(per_hsk_cfg); i++) { 151*4ddfb6f1SJacky Bai if (active_wakeup_irq(per_hsk_cfg[i].wakeup_irq)) { 152*4ddfb6f1SJacky Bai per_lpm[num_hsks].perId = per_hsk_cfg[i].per_idx; 153*4ddfb6f1SJacky Bai per_lpm[num_hsks].lpmSetting = en ? SCMI_CPU_PD_LPM_ON_RUN_WAIT_STOP : 154*4ddfb6f1SJacky Bai SCMI_CPU_PD_LPM_ON_ALWAYS; 155*4ddfb6f1SJacky Bai num_hsks++; 156*4ddfb6f1SJacky Bai } 157*4ddfb6f1SJacky Bai } 158*4ddfb6f1SJacky Bai 159*4ddfb6f1SJacky Bai scmi_per_lpm_mode_set(imx9_scmi_handle, IMX9_SCMI_CPU_A55P, 160*4ddfb6f1SJacky Bai num_hsks, per_lpm); 161*4ddfb6f1SJacky Bai } 162*4ddfb6f1SJacky Bai 163*4ddfb6f1SJacky Bai void imx_set_sys_wakeup(uint32_t last_core, bool pdn) 164*4ddfb6f1SJacky Bai { 165*4ddfb6f1SJacky Bai uintptr_t gicd_base = PLAT_GICD_BASE; 166*4ddfb6f1SJacky Bai 167*4ddfb6f1SJacky Bai /* Set the GPC IMRs based on GIC IRQ mask setting */ 168*4ddfb6f1SJacky Bai for (uint32_t i = 0U; i < IMR_NUM; i++) { 169*4ddfb6f1SJacky Bai if (pdn) { 170*4ddfb6f1SJacky Bai /* set the wakeup irq based on GIC */ 171*4ddfb6f1SJacky Bai irq_mask[i] = 172*4ddfb6f1SJacky Bai ~gicd_read_isenabler(gicd_base, 32 * (i + 1)); 173*4ddfb6f1SJacky Bai } else { 174*4ddfb6f1SJacky Bai irq_mask[i] = 0xFFFFFFFF; 175*4ddfb6f1SJacky Bai } 176*4ddfb6f1SJacky Bai 177*4ddfb6f1SJacky Bai if (~irq_mask[i] & wakeup_irq_mask[i]) { 178*4ddfb6f1SJacky Bai if (i == IRQ_MASK(NETC_IREC_PCI_INT_X0) && 179*4ddfb6f1SJacky Bai (wakeup_irq_mask[i] & IRQ_SHIFT(NETC_IREC_PCI_INT_X0))) { 180*4ddfb6f1SJacky Bai has_netc_irq = true; 181*4ddfb6f1SJacky Bai } else { 182*4ddfb6f1SJacky Bai has_wakeup_irq = true; 183*4ddfb6f1SJacky Bai } 184*4ddfb6f1SJacky Bai } 185*4ddfb6f1SJacky Bai } 186*4ddfb6f1SJacky Bai 187*4ddfb6f1SJacky Bai /* Set IRQ wakeup mask for the last core & cluster */ 188*4ddfb6f1SJacky Bai scmi_core_Irq_wake_set(imx9_scmi_handle, IMX9_SCMI_CPU_A55P, 189*4ddfb6f1SJacky Bai 0, IMR_NUM, irq_mask); 190*4ddfb6f1SJacky Bai 191*4ddfb6f1SJacky Bai scmi_core_Irq_wake_set(imx9_scmi_handle, SCMI_CPU_A55_ID(last_core), 192*4ddfb6f1SJacky Bai 0, IMR_NUM, irq_mask); 193*4ddfb6f1SJacky Bai 194*4ddfb6f1SJacky Bai /* Configure low power wakeup source interface */ 195*4ddfb6f1SJacky Bai peripheral_qchannel_hsk(pdn); 196*4ddfb6f1SJacky Bai } 197*4ddfb6f1SJacky Bai 198*4ddfb6f1SJacky Bai void imx9_sys_sleep_prepare(uint32_t core_id) 199*4ddfb6f1SJacky Bai { 200*4ddfb6f1SJacky Bai /* Save the gic context */ 201*4ddfb6f1SJacky Bai gic_save(); 202*4ddfb6f1SJacky Bai 203*4ddfb6f1SJacky Bai /* Save contex of gpios in wakeupmix */ 204*4ddfb6f1SJacky Bai for (uint32_t i = 0U; i < GPIO_NUM; i++) { 205*4ddfb6f1SJacky Bai gpio_save(&gpios[i]); 206*4ddfb6f1SJacky Bai } 207*4ddfb6f1SJacky Bai 208*4ddfb6f1SJacky Bai /* Save wdog3/4 ctx */ 209*4ddfb6f1SJacky Bai for (uint32_t i = 0U; i < WDOG_NUM; i++) { 210*4ddfb6f1SJacky Bai wdog_save(&wdogs[i]); 211*4ddfb6f1SJacky Bai } 212*4ddfb6f1SJacky Bai 213*4ddfb6f1SJacky Bai #if HAS_XSPI_SUPPORT 214*4ddfb6f1SJacky Bai xspi_save(); 215*4ddfb6f1SJacky Bai #endif 216*4ddfb6f1SJacky Bai imx_set_sys_wakeup(core_id, true); 217*4ddfb6f1SJacky Bai 218*4ddfb6f1SJacky Bai keep_wakeupmix_on = gpio_wakeup || has_wakeup_irq; 219*4ddfb6f1SJacky Bai } 220*4ddfb6f1SJacky Bai 221*4ddfb6f1SJacky Bai void imx9_sys_sleep_unprepare(uint32_t core_id) 222*4ddfb6f1SJacky Bai { 223*4ddfb6f1SJacky Bai /* Restore the gic context */ 224*4ddfb6f1SJacky Bai gic_resume(); 225*4ddfb6f1SJacky Bai 226*4ddfb6f1SJacky Bai #if HAS_XSPI_SUPPORT 227*4ddfb6f1SJacky Bai xspi_restore(); 228*4ddfb6f1SJacky Bai #endif 229*4ddfb6f1SJacky Bai /* Restore contex of gpios in wakeupmix */ 230*4ddfb6f1SJacky Bai for (uint32_t i = 0U; i < GPIO_NUM; i++) { 231*4ddfb6f1SJacky Bai gpio_restore(&gpios[i]); 232*4ddfb6f1SJacky Bai } 233*4ddfb6f1SJacky Bai 234*4ddfb6f1SJacky Bai /* Restore wdog3/4 ctx */ 235*4ddfb6f1SJacky Bai for (uint32_t i = 0U; i < WDOG_NUM; i++) { 236*4ddfb6f1SJacky Bai wdog_restore(&wdogs[i]); 237*4ddfb6f1SJacky Bai } 238*4ddfb6f1SJacky Bai 239*4ddfb6f1SJacky Bai imx_set_sys_wakeup(core_id, false); 240*4ddfb6f1SJacky Bai 241*4ddfb6f1SJacky Bai has_wakeup_irq = false; 242*4ddfb6f1SJacky Bai } 243