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 */
plat_setup_psci_ops(uintptr_t sec_entrypoint,const plat_psci_ops_t ** 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