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 */ 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