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
|
extern void tb_system_reset(void);
extern void tb_system_off(void);
extern unsigned long tb_spin_gates[8];
extern unsigned char tb_pen_stamps[8];
static uint64_t psci_cpu_on(uint64_t target, uint64_t entry,
uint64_t ctx)
{
unsigned long mpidr;
int cpu;
if (target > 7)
return PSCI_RET_INVALID_PARAMS;
asm volatile("mrs %0, mpidr_el1" : "=r" (mpidr));
if ((mpidr & 0xff) == target)
return PSCI_RET_ALREADY_ON;
cpu = (int)target;
tb_spin_gates[cpu] = entry;
tb_pen_stamps[cpu] = (unsigned char)(ctx & 0xff);
asm volatile("dsb sy");
asm volatile("sev");
dprintf(ALWAYS, "psci: cpu_on %llu -> %llx\n",
(unsigned long long)target,
(unsigned long long)entry);
return PSCI_RET_SUCCESS;
}
extern void park_ret(void);
static uint64_t psci_cpu_off(void)
{
unsigned long mpidr;
int cpu;
asm volatile("mrs %0, mpidr_el1" : "=r" (mpidr));
cpu = (int)(mpidr & 0xff);
if (cpu > 7)
return PSCI_RET_NOT_SUPPORTED;
tb_spin_gates[cpu] = 0;
dprintf(ALWAYS, "psci: cpu_off %d\n", cpu);
asm volatile(
"dsb sy\n"
"b park_ret\n"
);
return PSCI_RET_INTERNAL_FAIL;
}
uint64_t tb_psci_dispatch(uint64_t fn, uint64_t x1, uint64_t x2,
uint64_t x3)
{
switch (fn) {
case PSCI_FN_VERSION:
return PSCI_VERSION_0_2;
case PSCI_FN_CPU_ON:
return psci_cpu_on(x1, x2, x3);
case PSCI_FN_CPU_OFF:
return psci_cpu_off();
case PSCI_FN_SYSTEM_OFF:
dprintf(ALWAYS, "psci: system off\n");
tb_system_off();
return PSCI_RET_SUCCESS;
case PSCI_FN_SYSTEM_RESET:
dprintf(ALWAYS, "psci: system reset\n");
tb_system_reset();
return PSCI_RET_INTERNAL_FAIL;
default:
return PSCI_RET_NOT_SUPPORTED;
}
}
|