xref: /openbmc/u-boot/arch/arm/mach-stm32mp/psci.c (revision e8f80a5a)
1*41c79775SPatrick Delaunay // SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
2*41c79775SPatrick Delaunay /*
3*41c79775SPatrick Delaunay  * Copyright (C) 2018, STMicroelectronics - All Rights Reserved
4*41c79775SPatrick Delaunay  */
5*41c79775SPatrick Delaunay 
6*41c79775SPatrick Delaunay #include <config.h>
7*41c79775SPatrick Delaunay #include <common.h>
8*41c79775SPatrick Delaunay #include <asm/armv7.h>
9*41c79775SPatrick Delaunay #include <asm/gic.h>
10*41c79775SPatrick Delaunay #include <asm/io.h>
11*41c79775SPatrick Delaunay #include <asm/psci.h>
12*41c79775SPatrick Delaunay #include <asm/secure.h>
13*41c79775SPatrick Delaunay 
14*41c79775SPatrick Delaunay #define BOOT_API_A7_CORE0_MAGIC_NUMBER	0xCA7FACE0
15*41c79775SPatrick Delaunay #define BOOT_API_A7_CORE1_MAGIC_NUMBER	0xCA7FACE1
16*41c79775SPatrick Delaunay 
17*41c79775SPatrick Delaunay #define MPIDR_AFF0			GENMASK(7, 0)
18*41c79775SPatrick Delaunay 
19*41c79775SPatrick Delaunay #define RCC_MP_GRSTCSETR		(STM32_RCC_BASE + 0x0404)
20*41c79775SPatrick Delaunay #define RCC_MP_GRSTCSETR_MPUP1RST	BIT(5)
21*41c79775SPatrick Delaunay #define RCC_MP_GRSTCSETR_MPUP0RST	BIT(4)
22*41c79775SPatrick Delaunay #define RCC_MP_GRSTCSETR_MPSYSRST	BIT(0)
23*41c79775SPatrick Delaunay 
24*41c79775SPatrick Delaunay #define STM32MP1_PSCI_NR_CPUS		2
25*41c79775SPatrick Delaunay #if STM32MP1_PSCI_NR_CPUS > CONFIG_ARMV7_PSCI_NR_CPUS
26*41c79775SPatrick Delaunay #error "invalid value for CONFIG_ARMV7_PSCI_NR_CPUS"
27*41c79775SPatrick Delaunay #endif
28*41c79775SPatrick Delaunay 
29*41c79775SPatrick Delaunay u8 psci_state[STM32MP1_PSCI_NR_CPUS] __secure_data = {
30*41c79775SPatrick Delaunay 	 PSCI_AFFINITY_LEVEL_ON,
31*41c79775SPatrick Delaunay 	 PSCI_AFFINITY_LEVEL_OFF};
32*41c79775SPatrick Delaunay 
psci_set_state(int cpu,u8 state)33*41c79775SPatrick Delaunay void __secure psci_set_state(int cpu, u8 state)
34*41c79775SPatrick Delaunay {
35*41c79775SPatrick Delaunay 	psci_state[cpu] = state;
36*41c79775SPatrick Delaunay 	dsb();
37*41c79775SPatrick Delaunay 	isb();
38*41c79775SPatrick Delaunay }
39*41c79775SPatrick Delaunay 
stm32mp_get_gicd_base_address(void)40*41c79775SPatrick Delaunay static u32 __secure stm32mp_get_gicd_base_address(void)
41*41c79775SPatrick Delaunay {
42*41c79775SPatrick Delaunay 	u32 periphbase;
43*41c79775SPatrick Delaunay 
44*41c79775SPatrick Delaunay 	/* get the GIC base address from the CBAR register */
45*41c79775SPatrick Delaunay 	asm("mrc p15, 4, %0, c15, c0, 0\n" : "=r" (periphbase));
46*41c79775SPatrick Delaunay 
47*41c79775SPatrick Delaunay 	return (periphbase & CBAR_MASK) + GIC_DIST_OFFSET;
48*41c79775SPatrick Delaunay }
49*41c79775SPatrick Delaunay 
stm32mp_smp_kick_all_cpus(void)50*41c79775SPatrick Delaunay static void __secure stm32mp_smp_kick_all_cpus(void)
51*41c79775SPatrick Delaunay {
52*41c79775SPatrick Delaunay 	u32 gic_dist_addr;
53*41c79775SPatrick Delaunay 
54*41c79775SPatrick Delaunay 	gic_dist_addr = stm32mp_get_gicd_base_address();
55*41c79775SPatrick Delaunay 
56*41c79775SPatrick Delaunay 	/* kick all CPUs (except this one) by writing to GICD_SGIR */
57*41c79775SPatrick Delaunay 	writel(1U << 24, gic_dist_addr + GICD_SGIR);
58*41c79775SPatrick Delaunay }
59*41c79775SPatrick Delaunay 
psci_arch_cpu_entry(void)60*41c79775SPatrick Delaunay void __secure psci_arch_cpu_entry(void)
61*41c79775SPatrick Delaunay {
62*41c79775SPatrick Delaunay 	u32 cpu = psci_get_cpu_id();
63*41c79775SPatrick Delaunay 
64*41c79775SPatrick Delaunay 	psci_set_state(cpu, PSCI_AFFINITY_LEVEL_ON);
65*41c79775SPatrick Delaunay }
66*41c79775SPatrick Delaunay 
psci_features(u32 function_id,u32 psci_fid)67*41c79775SPatrick Delaunay int __secure psci_features(u32 function_id, u32 psci_fid)
68*41c79775SPatrick Delaunay {
69*41c79775SPatrick Delaunay 	switch (psci_fid) {
70*41c79775SPatrick Delaunay 	case ARM_PSCI_0_2_FN_PSCI_VERSION:
71*41c79775SPatrick Delaunay 	case ARM_PSCI_0_2_FN_CPU_OFF:
72*41c79775SPatrick Delaunay 	case ARM_PSCI_0_2_FN_CPU_ON:
73*41c79775SPatrick Delaunay 	case ARM_PSCI_0_2_FN_AFFINITY_INFO:
74*41c79775SPatrick Delaunay 	case ARM_PSCI_0_2_FN_MIGRATE_INFO_TYPE:
75*41c79775SPatrick Delaunay 	case ARM_PSCI_0_2_FN_SYSTEM_OFF:
76*41c79775SPatrick Delaunay 	case ARM_PSCI_0_2_FN_SYSTEM_RESET:
77*41c79775SPatrick Delaunay 		return 0x0;
78*41c79775SPatrick Delaunay 	}
79*41c79775SPatrick Delaunay 	return ARM_PSCI_RET_NI;
80*41c79775SPatrick Delaunay }
81*41c79775SPatrick Delaunay 
psci_version(u32 function_id)82*41c79775SPatrick Delaunay unsigned int __secure psci_version(u32 function_id)
83*41c79775SPatrick Delaunay {
84*41c79775SPatrick Delaunay 	return ARM_PSCI_VER_1_0;
85*41c79775SPatrick Delaunay }
86*41c79775SPatrick Delaunay 
psci_affinity_info(u32 function_id,u32 target_affinity,u32 lowest_affinity_level)87*41c79775SPatrick Delaunay int __secure psci_affinity_info(u32 function_id, u32 target_affinity,
88*41c79775SPatrick Delaunay 				u32  lowest_affinity_level)
89*41c79775SPatrick Delaunay {
90*41c79775SPatrick Delaunay 	u32 cpu = target_affinity & MPIDR_AFF0;
91*41c79775SPatrick Delaunay 
92*41c79775SPatrick Delaunay 	if (lowest_affinity_level > 0)
93*41c79775SPatrick Delaunay 		return ARM_PSCI_RET_INVAL;
94*41c79775SPatrick Delaunay 
95*41c79775SPatrick Delaunay 	if (target_affinity & ~MPIDR_AFF0)
96*41c79775SPatrick Delaunay 		return ARM_PSCI_RET_INVAL;
97*41c79775SPatrick Delaunay 
98*41c79775SPatrick Delaunay 	if (cpu >= STM32MP1_PSCI_NR_CPUS)
99*41c79775SPatrick Delaunay 		return ARM_PSCI_RET_INVAL;
100*41c79775SPatrick Delaunay 
101*41c79775SPatrick Delaunay 	return psci_state[cpu];
102*41c79775SPatrick Delaunay }
103*41c79775SPatrick Delaunay 
psci_migrate_info_type(u32 function_id)104*41c79775SPatrick Delaunay int __secure psci_migrate_info_type(u32 function_id)
105*41c79775SPatrick Delaunay {
106*41c79775SPatrick Delaunay 	/* Trusted OS is either not present or does not require migration */
107*41c79775SPatrick Delaunay 	return 2;
108*41c79775SPatrick Delaunay }
109*41c79775SPatrick Delaunay 
psci_cpu_on(u32 function_id,u32 target_cpu,u32 pc,u32 context_id)110*41c79775SPatrick Delaunay int __secure psci_cpu_on(u32 function_id, u32 target_cpu, u32 pc,
111*41c79775SPatrick Delaunay 			 u32 context_id)
112*41c79775SPatrick Delaunay {
113*41c79775SPatrick Delaunay 	u32 cpu = target_cpu & MPIDR_AFF0;
114*41c79775SPatrick Delaunay 
115*41c79775SPatrick Delaunay 	if (target_cpu & ~MPIDR_AFF0)
116*41c79775SPatrick Delaunay 		return ARM_PSCI_RET_INVAL;
117*41c79775SPatrick Delaunay 
118*41c79775SPatrick Delaunay 	if (cpu >= STM32MP1_PSCI_NR_CPUS)
119*41c79775SPatrick Delaunay 		return ARM_PSCI_RET_INVAL;
120*41c79775SPatrick Delaunay 
121*41c79775SPatrick Delaunay 	if (psci_state[cpu] == PSCI_AFFINITY_LEVEL_ON)
122*41c79775SPatrick Delaunay 		return ARM_PSCI_RET_ALREADY_ON;
123*41c79775SPatrick Delaunay 
124*41c79775SPatrick Delaunay 	/* store target PC and context id*/
125*41c79775SPatrick Delaunay 	psci_save(cpu, pc, context_id);
126*41c79775SPatrick Delaunay 
127*41c79775SPatrick Delaunay 	/* write entrypoint in backup RAM register */
128*41c79775SPatrick Delaunay 	writel((u32)&psci_cpu_entry, TAMP_BACKUP_BRANCH_ADDRESS);
129*41c79775SPatrick Delaunay 	psci_set_state(cpu, PSCI_AFFINITY_LEVEL_ON_PENDING);
130*41c79775SPatrick Delaunay 
131*41c79775SPatrick Delaunay 	/* write magic number in backup register */
132*41c79775SPatrick Delaunay 	if (cpu == 0x01)
133*41c79775SPatrick Delaunay 		writel(BOOT_API_A7_CORE1_MAGIC_NUMBER,
134*41c79775SPatrick Delaunay 		       TAMP_BACKUP_MAGIC_NUMBER);
135*41c79775SPatrick Delaunay 	else
136*41c79775SPatrick Delaunay 		writel(BOOT_API_A7_CORE0_MAGIC_NUMBER,
137*41c79775SPatrick Delaunay 		       TAMP_BACKUP_MAGIC_NUMBER);
138*41c79775SPatrick Delaunay 
139*41c79775SPatrick Delaunay 	stm32mp_smp_kick_all_cpus();
140*41c79775SPatrick Delaunay 
141*41c79775SPatrick Delaunay 	return ARM_PSCI_RET_SUCCESS;
142*41c79775SPatrick Delaunay }
143*41c79775SPatrick Delaunay 
psci_cpu_off(u32 function_id)144*41c79775SPatrick Delaunay int __secure psci_cpu_off(u32 function_id)
145*41c79775SPatrick Delaunay {
146*41c79775SPatrick Delaunay 	u32 cpu;
147*41c79775SPatrick Delaunay 
148*41c79775SPatrick Delaunay 	cpu = psci_get_cpu_id();
149*41c79775SPatrick Delaunay 
150*41c79775SPatrick Delaunay 	psci_cpu_off_common();
151*41c79775SPatrick Delaunay 	psci_set_state(cpu, PSCI_AFFINITY_LEVEL_OFF);
152*41c79775SPatrick Delaunay 
153*41c79775SPatrick Delaunay 	/* reset core: wfi is managed by BootRom */
154*41c79775SPatrick Delaunay 	if (cpu == 0x01)
155*41c79775SPatrick Delaunay 		writel(RCC_MP_GRSTCSETR_MPUP1RST, RCC_MP_GRSTCSETR);
156*41c79775SPatrick Delaunay 	else
157*41c79775SPatrick Delaunay 		writel(RCC_MP_GRSTCSETR_MPUP0RST, RCC_MP_GRSTCSETR);
158*41c79775SPatrick Delaunay 
159*41c79775SPatrick Delaunay 	/* just waiting reset */
160*41c79775SPatrick Delaunay 	while (1)
161*41c79775SPatrick Delaunay 		wfi();
162*41c79775SPatrick Delaunay }
163*41c79775SPatrick Delaunay 
psci_system_reset(u32 function_id)164*41c79775SPatrick Delaunay void __secure psci_system_reset(u32 function_id)
165*41c79775SPatrick Delaunay {
166*41c79775SPatrick Delaunay 	/* System reset */
167*41c79775SPatrick Delaunay 	writel(RCC_MP_GRSTCSETR_MPSYSRST, RCC_MP_GRSTCSETR);
168*41c79775SPatrick Delaunay 	/* just waiting reset */
169*41c79775SPatrick Delaunay 	while (1)
170*41c79775SPatrick Delaunay 		wfi();
171*41c79775SPatrick Delaunay }
172*41c79775SPatrick Delaunay 
psci_system_off(u32 function_id)173*41c79775SPatrick Delaunay void __secure psci_system_off(u32 function_id)
174*41c79775SPatrick Delaunay {
175*41c79775SPatrick Delaunay 	/* System Off is not managed, waiting user power off
176*41c79775SPatrick Delaunay 	 * TODO: handle I2C write in PMIC Main Control register bit 0 = SWOFF
177*41c79775SPatrick Delaunay 	 */
178*41c79775SPatrick Delaunay 	while (1)
179*41c79775SPatrick Delaunay 		wfi();
180*41c79775SPatrick Delaunay }
181