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