xref: /rk3399_ARM-atf/plat/imx/imx9/imx94/imx94_psci.c (revision b67e984664a8644d6cfd1812cabaa02cf24f09c9)
1 /*
2  * Copyright 2024-2025 NXP
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include <lib/psci/psci.h>
8 #include <scmi_imx9.h>
9 
10 #include <imx9_psci_common.h>
11 #include <imx9_sys_sleep.h>
12 #include <imx_scmi_client.h>
13 #include <plat_imx8.h>
14 
15 uint32_t mask_all[IMR_NUM] = {
16 	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
17 	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
18 	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
19 	0xffffffff, 0xffffffff, 0xffffffff
20 };
21 
22 /*
23  * IRQ masks used to check if any of the below IRQ is
24  * enabled as the wakeup source:
25  * lpuart1: 21, flexcan2-5: 40, 42, 44, 46, usdhc1-3: 96, 97, 116
26  */
27 uint32_t wakeup_irq_mask[IMR_NUM] = {
28 	0x600000, 0x5500, 0xFFC0, 0x100003, 0x0, 0x0, 0x0, 0x0,
29 	0x0, 0x0, 0x0, 0x80
30 };
31 
32 struct per_hsk_cfg per_hsk_cfg[] = {
33 	{ CPU_PER_LPI_IDX_CAN2, 40U },
34 	{ CPU_PER_LPI_IDX_CAN3, 42U },
35 	{ CPU_PER_LPI_IDX_CAN4, 44U },
36 	{ CPU_PER_LPI_IDX_CAN5, 46U },
37 
38 	{ CPU_PER_LPI_IDX_LPUART1, 21U },
39 	{ CPU_PER_LPI_IDX_LPUART2, 22U },
40 	{ CPU_PER_LPI_IDX_LPUART3, 74U },
41 	{ CPU_PER_LPI_IDX_LPUART4, 75U },
42 	{ CPU_PER_LPI_IDX_LPUART5, 76U },
43 	{ CPU_PER_LPI_IDX_LPUART6, 77U },
44 	{ CPU_PER_LPI_IDX_LPUART7, 78U },
45 	{ CPU_PER_LPI_IDX_LPUART8, 79U },
46 	{ CPU_PER_LPI_IDX_LPUART9, 80U },
47 	{ CPU_PER_LPI_IDX_LPUART10, 81U },
48 	{ CPU_PER_LPI_IDX_LPUART11, 82U },
49 	{ CPU_PER_LPI_IDX_LPUART12, 83U },
50 
51 	{ CPU_PER_LPI_IDX_GPIO2, 54U },
52 	{ CPU_PER_LPI_IDX_GPIO3, 56U },
53 	{ CPU_PER_LPI_IDX_GPIO4, 58U },
54 	{ CPU_PER_LPI_IDX_GPIO5, 60U },
55 	{ CPU_PER_LPI_IDX_GPIO6, 62U },
56 	{ CPU_PER_LPI_IDX_GPIO7, 64U },
57 };
58 
59 struct gpio_ctx gpios[GPIO_NUM] = {
60 	GPIO_CTX(GPIO2_BASE, 32U),
61 	GPIO_CTX(GPIO3_BASE, 26U),
62 	GPIO_CTX(GPIO4_BASE, 32U),
63 	GPIO_CTX(GPIO5_BASE, 32U),
64 	GPIO_CTX(GPIO6_BASE, 32U),
65 	GPIO_CTX(GPIO7_BASE, 22U),
66 };
67 
68 struct wdog_ctx wdogs[WDOG_NUM] = {
69 	{ WDOG3_BASE },
70 	{ WDOG4_BASE },
71 };
72 
73 static const plat_psci_ops_t imx_plat_psci_ops = {
74 	.validate_ns_entrypoint = imx_validate_ns_entrypoint,
75 	.validate_power_state = imx_validate_power_state,
76 	.pwr_domain_on = imx_pwr_domain_on,
77 	.pwr_domain_off = imx_pwr_domain_off,
78 	.pwr_domain_on_finish = imx_pwr_domain_on_finish,
79 	.pwr_domain_suspend = imx_pwr_domain_suspend,
80 	.pwr_domain_suspend_finish = imx_pwr_domain_suspend_finish,
81 	.get_sys_suspend_power_state = imx_get_sys_suspend_power_state,
82 	.pwr_domain_pwr_down = imx_pwr_domain_pwr_down,
83 	.system_reset = imx_system_reset,
84 	.system_off = imx_system_off,
85 };
86 
87 /* Export the platform specific psci ops */
88 int plat_setup_psci_ops(uintptr_t sec_entrypoint,
89 			const plat_psci_ops_t **psci_ops)
90 {
91 	uint32_t mask = DEBUG_WAKEUP_MASK | EVENT_WAKEUP_MASK;
92 
93 	/* sec_entrypoint is used for warm reset */
94 	secure_entrypoint = sec_entrypoint;
95 	imx_set_cpu_boot_entry(0U, secure_entrypoint, SCMI_CPU_VEC_FLAGS_BOOT);
96 
97 	/*
98 	 * Set NON-IRQ wakeup mask for both last core and cluster.
99 	 * Disable wakeup on DEBUG_WAKEUP
100 	 */
101 	scmi_core_nonIrq_wake_set(imx9_scmi_handle, IMX9_SCMI_CPU_A55C0, 0U, 1U, mask);
102 	scmi_core_nonIrq_wake_set(imx9_scmi_handle, IMX9_SCMI_CPU_A55P, 0U, 1U, mask);
103 
104 	/*
105 	 * Setup A55 Cluster state for Cpuidle.
106 	 */
107 	struct scmi_lpm_config cpu_lpm_cfg[] = {
108 		{
109 			SCMI_PWR_MIX_SLICE_IDX_A55P,
110 			SCMI_CPU_PD_LPM_ON_RUN,
111 			BIT_32(SCMI_PWR_MEM_SLICE_IDX_A55L3)
112 		},
113 		{
114 			SCMI_PWR_MIX_SLICE_IDX_NOC,
115 			SCMI_CPU_PD_LPM_ON_ALWAYS,
116 			0U
117 		},
118 		{
119 			SCMI_PWR_MIX_SLICE_IDX_WAKEUP,
120 			SCMI_CPU_PD_LPM_ON_ALWAYS,
121 			0U
122 		}
123 	};
124 
125 	/* Set the default LPM state for suspend/hotplug */
126 	scmi_core_lpm_mode_set(imx9_scmi_handle,
127 			       IMX9_SCMI_CPU_A55P,
128 			       ARRAY_SIZE(cpu_lpm_cfg),
129 			       cpu_lpm_cfg);
130 
131 	/* Set the LPM state for cpuidle for A55C0 (boot core) */
132 	cpu_lpm_cfg[0].power_domain = SCMI_PWR_MIX_SLICE_IDX_A55C0;
133 	cpu_lpm_cfg[0].lpmsetting = SCMI_CPU_PD_LPM_ON_RUN;
134 	cpu_lpm_cfg[0].retentionmask = 0U;
135 	scmi_core_lpm_mode_set(imx9_scmi_handle, IMX9_SCMI_CPU_A55C0,
136 				1U, cpu_lpm_cfg);
137 
138 	/*
139 	 * Set core/custer to GIC wakeup source since NOCMIX is not
140 	 * powered down, config the target mode to WAIT
141 	 */
142 	scmi_core_set_sleep_mode(imx9_scmi_handle, IMX9_SCMI_CPU_A55C0,
143 				 SCMI_GIC_WAKEUP, SCMI_CPU_SLEEP_WAIT);
144 
145 	scmi_core_set_sleep_mode(imx9_scmi_handle, IMX9_SCMI_CPU_A55P,
146 				 SCMI_GIC_WAKEUP, SCMI_CPU_SLEEP_WAIT);
147 
148 	/* Enable the wdog3 per handshake */
149 	struct scmi_per_lpm_config per_lpm[1] = {
150 		{ CPU_PER_LPI_IDX_WDOG3, SCMI_CPU_PD_LPM_ON_RUN_WAIT_STOP },
151 	};
152 
153 	scmi_per_lpm_mode_set(imx9_scmi_handle, IMX9_SCMI_CPU_A55P,
154 			      1U, per_lpm);
155 
156 	*psci_ops = &imx_plat_psci_ops;
157 
158 	return 0;
159 }
160