xref: /rk3399_ARM-atf/plat/imx/imx9/common/imx9_sys_sleep.c (revision 480e8dd9df291cc0e31695983fa6ff235e1671cd)
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