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
xspi_save(void)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
xspi_restore(void)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
gpio_save(struct gpio_ctx * ctx)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 }
gpio_restore(struct gpio_ctx * ctx)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
wdog_save(struct wdog_ctx * wdog)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
wdog_restore(struct wdog_ctx * wdog)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
active_wakeup_irq(uint32_t irq)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 */
peripheral_qchannel_hsk(bool en)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
imx_set_sys_wakeup(uint32_t last_core,bool pdn)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
imx9_sys_sleep_prepare(uint32_t core_id)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
imx9_sys_sleep_unprepare(uint32_t core_id)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