xref: /rk3399_ARM-atf/plat/imx/imx9/imx95/imx95_psci.c (revision 05d22c3045e2e972c2262b9ccd6c82cb7545bf83)
1 /*
2  * Copyright 2023-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 };
20 
21 /*
22  * IRQ masks used to check if any of the below IRQ is
23  * enabled as the wakeup source:
24  * lpuart3-8: 64-67, flexcan2:38, usdhc1-2:86-87,usdhc3:191
25  * flexcan3: 40, flexcan4: 42, flexcan5: 44, netc: 304;
26  */
27 uint32_t wakeup_irq_mask[IMR_NUM] = {
28 	0x0, 0x1540, 0xc0000f, 0x0,
29 	0x0, 0x80000000, 0x0, 0x0,
30 	0x0, 0x10000,
31 };
32 
33 struct per_hsk_cfg per_hsk_cfg[] = {
34 	{ CPU_PER_LPI_IDX_CAN1, 8U },
35 	{ CPU_PER_LPI_IDX_CAN2, 38U },
36 	{ CPU_PER_LPI_IDX_CAN3, 40U },
37 	{ CPU_PER_LPI_IDX_CAN4, 42U },
38 	{ CPU_PER_LPI_IDX_CAN5, 44U },
39 
40 	{ CPU_PER_LPI_IDX_LPUART1, 19U },
41 	{ CPU_PER_LPI_IDX_LPUART4, 65U },
42 	{ CPU_PER_LPI_IDX_LPUART5, 66U },
43 	{ CPU_PER_LPI_IDX_LPUART6, 67U },
44 	{ CPU_PER_LPI_IDX_LPUART7, 68U },
45 	{ CPU_PER_LPI_IDX_LPUART8, 69U },
46 
47 	{ CPU_PER_LPI_IDX_GPIO2, 49U },
48 	{ CPU_PER_LPI_IDX_GPIO3, 51U },
49 	{ CPU_PER_LPI_IDX_GPIO4, 53U },
50 	{ CPU_PER_LPI_IDX_GPIO5, 55U },
51 };
52 
53 struct gpio_ctx gpios[GPIO_NUM] = {
54 	GPIO_CTX(GPIO2_BASE, 32U),
55 	GPIO_CTX(GPIO3_BASE, 32U),
56 	GPIO_CTX(GPIO4_BASE, 30U),
57 	GPIO_CTX(GPIO5_BASE, 18U),
58 };
59 
60 struct wdog_ctx wdogs[WDOG_NUM] = {
61 	{ WDOG3_BASE },
62 	{ WDOG4_BASE },
63 };
64 
65 static const plat_psci_ops_t imx_plat_psci_ops = {
66 	.validate_ns_entrypoint = imx_validate_ns_entrypoint,
67 	.validate_power_state = imx_validate_power_state,
68 	.pwr_domain_on = imx_pwr_domain_on,
69 	.pwr_domain_off = imx_pwr_domain_off,
70 	.pwr_domain_on_finish = imx_pwr_domain_on_finish,
71 	.pwr_domain_suspend = imx_pwr_domain_suspend,
72 	.pwr_domain_suspend_finish = imx_pwr_domain_suspend_finish,
73 	.get_sys_suspend_power_state = imx_get_sys_suspend_power_state,
74 	.pwr_domain_pwr_down = imx_pwr_domain_pwr_down,
75 	.system_reset = imx_system_reset,
76 	.system_off = imx_system_off,
77 };
78 
79 /* Export the platform specific psci ops */
80 int plat_setup_psci_ops(uintptr_t sec_entrypoint,
81 			const plat_psci_ops_t **psci_ops)
82 {
83 	uint32_t mask = DEBUG_WAKEUP_MASK | EVENT_WAKEUP_MASK;
84 
85 	/* sec_entrypoint is used for warm reset */
86 	secure_entrypoint = sec_entrypoint;
87 
88 	imx_set_cpu_boot_entry(0U, secure_entrypoint, SCMI_CPU_VEC_FLAGS_BOOT);
89 
90 	/*
91 	 * Set NON-IRQ wakeup mask for both last core and cluster.
92 	 * Disable wakeup on DEBUG_WAKEUP
93 	 */
94 	scmi_core_nonIrq_wake_set(imx9_scmi_handle, IMX9_SCMI_CPU_A55C0, 0U, 1U, mask);
95 	scmi_core_nonIrq_wake_set(imx9_scmi_handle, IMX9_SCMI_CPU_A55P, 0U, 1U, mask);
96 
97 	/* Setup A55 Cluster state for Cpuidle. */
98 	struct scmi_lpm_config cpu_lpm_cfg[] = {
99 		{
100 			SCMI_PWR_MIX_SLICE_IDX_A55P,
101 			SCMI_CPU_PD_LPM_ON_ALWAYS,
102 			BIT_32(SCMI_PWR_MEM_SLICE_IDX_A55L3)
103 		},
104 		{
105 			SCMI_PWR_MIX_SLICE_IDX_NOC,
106 			SCMI_CPU_PD_LPM_ON_ALWAYS,
107 			0U
108 		},
109 		{
110 			SCMI_PWR_MIX_SLICE_IDX_WAKEUP,
111 			SCMI_CPU_PD_LPM_ON_ALWAYS,
112 			0U
113 		}
114 	};
115 
116 	/* Set the default LPM state for suspend/hotplug */
117 	scmi_core_lpm_mode_set(imx9_scmi_handle,
118 			       IMX9_SCMI_CPU_A55P,
119 			       ARRAY_SIZE(cpu_lpm_cfg),
120 			       cpu_lpm_cfg);
121 
122 	/* Set the LPM state for cpuidle for A55C0 (boot core) */
123 	cpu_lpm_cfg[0].power_domain = SCMI_PWR_MIX_SLICE_IDX_A55C0;
124 	cpu_lpm_cfg[0].lpmsetting = SCMI_CPU_PD_LPM_ON_RUN;
125 	cpu_lpm_cfg[0].retentionmask = 0U;
126 	scmi_core_lpm_mode_set(imx9_scmi_handle, IMX9_SCMI_CPU_A55C0,
127 			       1U, cpu_lpm_cfg);
128 
129 	/*
130 	 * Set core/custer to GIC wakeup source since NOCMIX is not
131 	 * powered down, config the target mode to WAIT
132 	 */
133 	scmi_core_set_sleep_mode(imx9_scmi_handle, IMX9_SCMI_CPU_A55C0,
134 				 SCMI_GIC_WAKEUP, SCMI_CPU_SLEEP_WAIT);
135 
136 	scmi_core_set_sleep_mode(imx9_scmi_handle, IMX9_SCMI_CPU_A55P,
137 				 SCMI_GIC_WAKEUP, SCMI_CPU_SLEEP_WAIT);
138 
139 	*psci_ops = &imx_plat_psci_ops;
140 
141 	return 0;
142 }
143