add basic secure monitor code for armv7+, for some reason sdram security does not...
[rpi-open-firmware.git] / arm_loader.cc
1 /*=============================================================================
2 Copyright (C) 2016-2017 Authors of rpi-open-firmware
3 All rights reserved.
4
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 FILE DESCRIPTION
16 ARM initialization stuff.
17
18 =============================================================================*/
19
20 #include <lib/runtime.h>
21 #include "hardware.h"
22
23 #define logf(fmt, ...) printf("[ARMLDR:%s]: " fmt, __FUNCTION__, ##__VA_ARGS__);
24
25 extern uint32_t g_CPUID;
26 extern uint32_t g_RAMSize;
27
28 extern uint8_t L_arm_code_start;
29 extern uint8_t L_arm_code_end;
30
31 #define ARM_MEMORY_BASE 0xC0000000
32 #define ARM_BKPT_OPCODE 0xE1200070
33
34 /*
35 * RPi3: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0488d/CIHBDCJD.html
36 */
37
38 /*
39 * This controls AA64nAA32 signal, when set, ARM starts in AArch64 mode. Only applicable
40 * to systems using Cortex-A53.
41 */
42 #define ARM_C0_AARCH64 0x00000200
43
44 /* XXX: What is this? */
45 #define PM_UNK_CFG_CLR 0xFFFCFFFF
46
47 static bool power_wait_bit(uint32_t bit) {
48 for (int i = 0; i < 20; i++) {
49 if (PM_PROC & bit) {
50 return true;
51 }
52 udelay(100);
53 }
54 return false;
55 }
56
57 static inline void assert_global_reset() {
58 logf("RSTN ...\n");
59 PM_PROC |= PM_PASSWORD | PM_PROC_ARMRSTN_SET;
60 udelay(300);
61 }
62
63 static void enable_power() {
64 uint32_t pmv;
65
66 logf("INIT PM_PROC: 0x%X\n", PM_PROC);
67
68 logf("requesting power up ...\n");
69
70 /* deassert all reset lines */
71 pmv = ((PM_PROC & PM_PROC_ARMRSTN_CLR) & PM_UNK_CFG_CLR) | PM_PASSWORD;
72
73 PM_PROC = pmv;
74
75 pmv |= PM_PROC_POWUP_SET;
76 udelay(10);
77 PM_PROC = pmv;
78
79 logf("POWUP PM_PROC: 0x%X\n", PM_PROC);
80
81 /* wait for POWOK */
82 logf("waiting for power up ...\n");
83 for (int i = 1; i < 5; i++) {
84 if (!power_wait_bit(PM_PROC_POWOK_SET)) {
85 /* only go up to 3 */
86 if (i == 4) {
87 panic("timed out waiting for power up, state of PM_PROC is: 0x%X", PM_PROC);
88 }
89
90 pmv = (pmv & PM_UNK_CFG_CLR) | (i << PM_PROC_CFG_LSB);
91 logf("timed out, trying different CFG: 0x%X \n", pmv);
92 PM_PROC = pmv;
93 }
94 }
95
96 pmv |= PM_PROC_ISPOW_SET;
97 PM_PROC = pmv;
98
99 pmv |= PM_PROC_MEMREP_SET;
100 PM_PROC = pmv;
101
102 logf("waiting for MRDONE ...\n");
103 if (!power_wait_bit(PM_PROC_MRDONE_SET)) {
104 panic("timed out waiting for MRDONE, state of PM_PROC is: 0x%X", PM_PROC);
105 }
106
107 logf("setting ISFUNC ...\n");
108
109 pmv |= PM_PROC_ISFUNC_SET;
110 PM_PROC = pmv;
111
112 logf("ARM power domain initialized succesfully, state of PM_PROC is: 0x%X!\n", PM_PROC);
113 }
114
115 static void bresp_cycle_write(uint32_t bits) {
116 ARM_CONTROL0 = (ARM_CONTROL0 & ~(ARM_C0_BRESP1|ARM_C0_BRESP2)) | bits;
117 printf("0x%X,", bits);
118 udelay(30);
119 }
120
121 static uint32_t g_BrespTab[] = {
122 0x10, 0x14, 0x10, 0x14, 0x10, 0x14, 0x10, 0x14, 0x10, 0x1C, 0x18, 0x1C, 0x18, 0x0,
123 0x10, 0x14, 0x10, 0x1C, 0x10, 0x14, 0x10, 0x14, 0x10, 0x14, 0x10, 0x14, 0x10, 0x0,
124 0x10, 0x14, 0x10, 0x1C, 0x18, 0x1C, 0x10, 0x14, 0x18, 0x1C, 0x10, 0x14, 0x10, 0x0,
125 0x10, 0x14, 0x18, 0x14, 0x10, 0x14, 0x10, 0x14, 0x10, 0x14, 0x10, 0x14, 0x10, 0x0,
126 0x10, 0x14, 0x18, 0x14, 0x18, 0x14, 0x10, 0x14, 0x10, 0x14, 0x10, 0x14, 0x18, 0x0
127 };
128 static void do_bresp_cycle() {
129 /* my little axi - peripherals are magic */
130 logf("Cycling AXI bits ...\n\t");
131
132 for (int i = 0; i < sizeof(g_BrespTab)/sizeof(g_BrespTab[0]); i++) {
133 bresp_cycle_write(g_BrespTab[i]);
134
135 if (i && ((i % 14) == 0))
136 printf("\n\t");
137 }
138
139 printf("\n");
140 }
141
142 void setup_bridge(bool bresp_cycle) {
143 logf("setting up async bridge ...\n");
144
145 if (bresp_cycle) {
146 assert_global_reset();
147 do_bresp_cycle();
148 assert_global_reset();
149 udelay(300);
150 }
151
152 logf("starting async bridge, ARM should be able to communicate through AXI ...\n");
153 ARM_CONTROL1 &= ~ARM_C1_REQSTOP;
154 udelay(300);
155
156 if (!bresp_cycle)
157 assert_global_reset();
158
159 logf("bridge init done, PM_PROC is now: 0x%X!\n", PM_PROC);
160 }
161
162 static void set_clock_source(unsigned int source) {
163 CM_ARMCTL = CM_PASSWORD | source | CM_ARMCTL_ENAB_SET;
164 }
165
166 static void enable_clock() {
167 logf("initializing PLLB ...\n");
168
169 /* oscillator->pllb */
170 A2W_XOSC_CTRL |= A2W_PASSWORD | A2W_XOSC_CTRL_PLLBEN_SET;
171
172 A2W_PLLB_FRAC = A2W_PASSWORD | 0xeaaa8;
173 A2W_PLLB_CTRL = A2W_PASSWORD | 48 | 0x1000;
174
175 CM_PLLB = CM_PASSWORD | CM_PLLB_DIGRST_SET | CM_PLLB_ANARST_SET;
176 CM_PLLB = CM_PASSWORD | CM_PLLB_DIGRST_SET | CM_PLLB_ANARST_SET | CM_PLLB_HOLDARM_SET;
177
178 A2W_PLLB_ANA3 = A2W_PASSWORD | 0x100;
179 A2W_PLLB_ANA2 = A2W_PASSWORD | 0x0;
180 A2W_PLLB_ANA1 = A2W_PASSWORD | 0x140000;
181 A2W_PLLB_ANA0 = A2W_PASSWORD | 0x0;
182
183 A2W_PLLB_DIG3 = A2W_PASSWORD | 0x0;
184 A2W_PLLB_DIG2 = A2W_PASSWORD | 0x400000;
185 A2W_PLLB_DIG1 = A2W_PASSWORD | 0x3a;
186 A2W_PLLB_DIG0 = A2W_PASSWORD | 48 | 0xAAA000;
187
188 A2W_PLLB_CTRL = A2W_PASSWORD | 48 | 0x21000;
189
190 A2W_PLLB_DIG3 = A2W_PASSWORD | 0x2;
191 A2W_PLLB_DIG2 = A2W_PASSWORD | 0x402401;
192 A2W_PLLB_DIG1 = A2W_PASSWORD | 0x403a;
193 A2W_PLLB_DIG0 = A2W_PASSWORD | 48 | 0xAAA000;
194
195 A2W_PLLB_ARM = A2W_PASSWORD | 2;
196
197 CM_PLLB = CM_PASSWORD | CM_PLLB_DIGRST_SET | CM_PLLB_ANARST_SET | CM_PLLB_HOLDARM_SET | CM_PLLB_LOADARM_SET;
198 CM_PLLB = CM_PASSWORD | CM_PLLB_DIGRST_SET | CM_PLLB_ANARST_SET | CM_PLLB_HOLDARM_SET;
199 CM_PLLB = CM_PASSWORD;
200
201 set_clock_source(4);
202
203 logf("KAIP = 0x%X\n", A2W_PLLB_ANA_KAIP);
204 logf("MULTI = 0x%X\n", A2W_PLLB_ANA_MULTI);
205
206 logf("ARM clock succesfully initialized!\n");
207 }
208
209 static void arm_load_code() {
210 uint32_t* mem = (uint32_t*)(ARM_MEMORY_BASE);
211
212 uint8_t* start = &L_arm_code_start;
213 uint8_t* end = &L_arm_code_end;
214 uint32_t size = (uint32_t)(end - start);
215
216 bcopy(start, mem, size);
217
218 logf("copied %d bytes to 0x%X!\n", size, ARM_MEMORY_BASE);
219
220 /* verify */
221 for (int i = 0; i < size; i++) {
222 uint8_t* mem8 = (uint8_t*)(mem);
223 if (start[i] != mem8[i])
224 panic("copy failed at 0x%X expected 0x%X, got 0x%X", (uint32_t)&mem8[i],
225 *((uint32_t*)&mem8[i]),
226 *((uint32_t*)&start[i]));
227 }
228 }
229
230 static void arm_pmap_enter(uint32_t bus_address, uint32_t arm_address) {
231 volatile uint32_t* tte = reinterpret_cast<volatile uint32_t*>(&ARM_TRANSLATE);
232
233 uint32_t index = arm_address >> 24;
234 uint32_t pte = bus_address >> 21;
235
236 tte[index] = pte;
237
238 //logf("Translation: [0x%X => 0x%X] 0x%X => 0x%X\n", index * 4, bus_address >> 21, bus_address, arm_address);
239 }
240
241 /*
242 #define ARM_C0_PRIO_PER 0x00F00000 // per priority mask
243 #define ARM_C0_PRIO_L2 0x0F000000
244 #define ARM_C0_PRIO_UC 0xF0000000
245 */
246
247 static void patch_arm_firmware_data() {
248 volatile firmware_arm_data_t* firmware_data = reinterpret_cast<firmware_arm_data_t*>(ARM_MEMORY_BASE + 32);
249
250 firmware_data->sdram_size = g_RAMSize;
251 firmware_data->vpu_cpuid = g_CPUID;
252 }
253
254 static void arm_enable_tzpc() {
255 /*
256 * enable SDRAM security.
257 * mask: 0xffffe000
258 */
259 logf("configuring secure SDRAM ...\n");
260 SD_SECSRT0 = 0xC0000000;
261 SD_SECEND0 = 0xC0011FFF;
262 logf("enabling secure SDRAM ...\n");
263 SD_SECSRT0 = 0xC0000001;
264 logf("secure SDRAM enabled ...\n");
265 }
266
267 extern "C" void arm_init() {
268 logf("arm init started\n");
269
270 arm_load_code();
271 patch_arm_firmware_data();
272
273 //arm_enable_tzpc();
274
275 logf("original memstart: 0x%X\n", *((volatile uint32_t*)ARM_MEMORY_BASE));
276
277 for (uint32_t i = 0; i < 62; i++) {
278 uint32_t offset = i * 0x1000000;
279 arm_pmap_enter(ARM_MEMORY_BASE + offset, 0x0 + offset);
280 }
281
282 logf("mapped VC 0x%X to ARM 0x%X\n", ARM_MEMORY_BASE, 0);
283
284 arm_pmap_enter(VC4_PERIPH_BASE, ARM_PERIPH_BASE);
285
286 logf("mapped peripherals VC 0x%X to ARM 0x%X\n", VC4_PERIPH_BASE, ARM_PERIPH_BASE);
287
288 /* see if the ARM block is responding */
289 logf("ARM ID: 0x%X C0: 0x%X\n", ARM_ID, ARM_CONTROL0);
290
291 /*
292 * enable peripheral access, map arm secure bits to axi secure bits 1:1 and
293 * set the mem size for who knows what reason.
294 */
295 ARM_CONTROL0 |= 0x008 | ARM_C0_APROTPASS | ARM_C0_SIZ1G | ARM_C0_FULLPERI;
296 ARM_CONTROL1 |= ARM_C1_PERSON;
297
298 ARM_IRQ_ENBL3 |= ARM_IE_MAIL;
299
300 logf("using C0: 0x%X\n", ARM_CONTROL0);
301
302 enable_clock();
303 enable_power();
304 /* start io bridge */
305 setup_bridge(true);
306 }
This page took 0.103076 seconds and 4 git commands to generate.