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