xref: /rk3399_ARM-atf/plat/imx/imx8ulp/imx8ulp_psci.c (revision fcd41e8692ce8e8fc98d069bc131820cbf83c55c)
1 /*
2  * Copyright 2021-2024 NXP
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include <stdbool.h>
8 
9 #include <arch.h>
10 #include <arch_helpers.h>
11 #include <common/debug.h>
12 #include <drivers/arm/gicv3.h>
13 #include <lib/mmio.h>
14 #include <lib/psci/psci.h>
15 
16 #include <plat_imx8.h>
17 
18 static uintptr_t secure_entrypoint;
19 
20 #define CORE_PWR_STATE(state) ((state)->pwr_domain_state[MPIDR_AFFLVL0])
21 #define CLUSTER_PWR_STATE(state) ((state)->pwr_domain_state[MPIDR_AFFLVL1])
22 #define SYSTEM_PWR_STATE(state) ((state)->pwr_domain_state[PLAT_MAX_PWR_LVL])
23 
24 #define RVBARADDRx(c)		(IMX_SIM1_BASE + 0x5c + 0x4 * (c))
25 #define WKPUx(c)		(IMX_SIM1_BASE + 0x3c + 0x4 * (c))
26 #define AD_COREx_LPMODE(c)	(IMX_CMC1_BASE + 0x50 + 0x4 * (c))
27 
28 static int imx_pwr_set_cpu_entry(unsigned int cpu, unsigned int entry)
29 {
30 	mmio_write_32(RVBARADDRx(cpu), entry);
31 
32 	/* set update bit */
33 	mmio_write_32(IMX_SIM1_BASE + 0x8, mmio_read_32(IMX_SIM1_BASE + 0x8) | BIT_32(24 + cpu));
34 	/* wait for ack */
35 	while (!(mmio_read_32(IMX_SIM1_BASE + 0x8) & BIT_32(26 + cpu))) {
36 	}
37 
38 	/* clear update bit */
39 	mmio_write_32(IMX_SIM1_BASE + 0x8, mmio_read_32(IMX_SIM1_BASE + 0x8) & ~BIT_32(24 + cpu));
40 	/* clear ack bit */
41 	mmio_write_32(IMX_SIM1_BASE + 0x8, mmio_read_32(IMX_SIM1_BASE + 0x8) | BIT_32(26 + cpu));
42 
43 	return 0;
44 }
45 
46 int imx_pwr_domain_on(u_register_t mpidr)
47 {
48 	unsigned int cpu = MPIDR_AFFLVL0_VAL(mpidr);
49 
50 	imx_pwr_set_cpu_entry(cpu, secure_entrypoint);
51 
52 	mmio_write_32(IMX_CMC1_BASE + 0x18, 0x3f);
53 	mmio_write_32(IMX_CMC1_BASE + 0x50 + 0x4 * cpu, 0);
54 
55 	/* enable wku wakeup for idle */
56 	mmio_write_32(IMX_SIM1_BASE + 0x3c + 0x4 * cpu, 0xffffffff);
57 
58 	return PSCI_E_SUCCESS;
59 }
60 
61 void imx_pwr_domain_on_finish(const psci_power_state_t *target_state)
62 {
63 	imx_pwr_set_cpu_entry(0, IMX_ROM_ENTRY);
64 	plat_gic_pcpu_init();
65 	plat_gic_cpuif_enable();
66 }
67 
68 int imx_validate_ns_entrypoint(uintptr_t ns_entrypoint)
69 {
70 	return PSCI_E_SUCCESS;
71 }
72 
73 void imx_pwr_domain_off(const psci_power_state_t *target_state)
74 {
75 	unsigned int cpu = MPIDR_AFFLVL0_VAL(read_mpidr_el1());
76 
77 	plat_gic_cpuif_disable();
78 
79 	/* disable wakeup */
80 	mmio_write_32(WKPUx(cpu), 0);
81 
82 	mmio_write_32(AD_COREx_LPMODE(cpu), 0x3);
83 }
84 
85 void __dead2 imx8ulp_pwr_domain_pwr_down_wfi(const psci_power_state_t *target_state)
86 {
87 	while (1) {
88 		wfi();
89 	}
90 }
91 
92 void __dead2 imx8ulp_system_reset(void)
93 {
94 	imx_pwr_set_cpu_entry(0, IMX_ROM_ENTRY);
95 
96 	/* Write invalid command to WDOG CNT to trigger reset */
97 	mmio_write_32(IMX_WDOG3_BASE + 0x4, 0x12345678);
98 
99 	while (true) {
100 		wfi();
101 	}
102 }
103 
104 static const plat_psci_ops_t imx_plat_psci_ops = {
105 	.pwr_domain_on = imx_pwr_domain_on,
106 	.pwr_domain_on_finish = imx_pwr_domain_on_finish,
107 	.validate_ns_entrypoint = imx_validate_ns_entrypoint,
108 	.system_reset = imx8ulp_system_reset,
109 	.pwr_domain_off = imx_pwr_domain_off,
110 	.pwr_domain_pwr_down_wfi = imx8ulp_pwr_domain_pwr_down_wfi,
111 };
112 
113 int plat_setup_psci_ops(uintptr_t sec_entrypoint,
114 			const plat_psci_ops_t **psci_ops)
115 {
116 	secure_entrypoint = sec_entrypoint;
117 	imx_pwr_set_cpu_entry(0, sec_entrypoint);
118 	*psci_ops = &imx_plat_psci_ops;
119 
120 	mmio_write_32(IMX_CMC1_BASE + 0x18, 0x3f);
121 	mmio_write_32(IMX_SIM1_BASE + 0x3c, 0xffffffff);
122 
123 	return 0;
124 }
125