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