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