9d1d977ee634272cd7a05f78757476dd28b6ef24
[rpi-open-firmware.git] / arm_loader.c
1 /*=============================================================================
2 Copyright (C) 2016 Kristina Brooks
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 <common.h>
21 #include "hardware.h"
22
23
24 #define logf(fmt, ...) printf("[ARMLDR:%s]: " fmt, __FUNCTION__, ##__VA_ARGS__);
25
26 extern char L_arm_code_start;
27 extern char L_arm_code_end;
28
29 #define ARM_MEMORY_BASE 0xC0000000
30 #define ARM_BKPT_OPCODE 0xE1200070
31
32 /* XXX: What is this? */
33 #define PM_UNK_CFG_CLR 0xFFFCFFFF
34
35 static bool power_wait_bit(uint32_t bit) {
36 for (int i = 0; i < 20; i++) {
37 if (PM_PROC & bit) {
38 return true;
39 }
40 udelay(100);
41 }
42 return false;
43 }
44
45 static inline void assert_global_reset() {
46 logf("RSTN ...\n");
47 PM_PROC |= PM_PASSWORD | PM_PROC_ARMRSTN_SET;
48 udelay(300);
49 }
50
51 static void enable_power() {
52 uint32_t pmv;
53
54 logf("INIT PM_PROC: 0x%X\n", PM_PROC);
55
56 logf("requesting power up ...\n");
57
58 /* deassert all reset lines */
59 pmv = ((PM_PROC & PM_PROC_ARMRSTN_CLR) & PM_UNK_CFG_CLR) | PM_PASSWORD;
60
61 PM_PROC = pmv;
62
63 pmv |= PM_PROC_POWUP_SET;
64 udelay(10);
65 PM_PROC = pmv;
66
67 logf("POWUP PM_PROC: 0x%X\n", PM_PROC);
68
69 /* wait for POWOK */
70 logf("waiting for power up ...\n");
71 for (int i = 1; i < 5; i++) {
72 if (!power_wait_bit(PM_PROC_POWOK_SET)) {
73 /* only go up to 3 */
74 if (i == 4) {
75 panic("timed out waiting for power up, state of PM_PROC is: 0x%X", PM_PROC);
76 }
77
78 pmv = (pmv & PM_UNK_CFG_CLR) | (i << PM_PROC_CFG_LSB);
79 logf("timed out, trying different CFG: 0x%X \n", pmv);
80 PM_PROC = pmv;
81 }
82 }
83
84 pmv |= PM_PROC_ISPOW_SET;
85 PM_PROC = pmv;
86
87 pmv |= PM_PROC_MEMREP_SET;
88 PM_PROC = pmv;
89
90 logf("waiting for MRDONE ...\n");
91 if (!power_wait_bit(PM_PROC_MRDONE_SET)) {
92 panic("timed out waiting for MRDONE, state of PM_PROC is: 0x%X", PM_PROC);
93 }
94
95 logf("setting ISFUNC ...\n");
96
97 pmv |= PM_PROC_ISFUNC_SET;
98 PM_PROC = pmv;
99
100 logf("ARM power domain initialized succesfully, state of PM_PROC is: 0x%X!\n", PM_PROC);
101 }
102
103 static void bresp_cycle_write(uint32_t bits) {
104 ARM_CONTROL0 = (ARM_CONTROL0 & ~(ARM_C0_BRESP1|ARM_C0_BRESP2)) | bits;
105 printf("0x%X,", bits);
106 udelay(30);
107 }
108
109 static uint32_t g_BrespTab[] = {
110 0x10, 0x14, 0x10, 0x14, 0x10, 0x14, 0x10, 0x14, 0x10, 0x1C, 0x18, 0x1C, 0x18, 0x0,
111 0x10, 0x14, 0x10, 0x1C, 0x10, 0x14, 0x10, 0x14, 0x10, 0x14, 0x10, 0x14, 0x10, 0x0,
112 0x10, 0x14, 0x10, 0x1C, 0x18, 0x1C, 0x10, 0x14, 0x18, 0x1C, 0x10, 0x14, 0x10, 0x0,
113 0x10, 0x14, 0x18, 0x14, 0x10, 0x14, 0x10, 0x14, 0x10, 0x14, 0x10, 0x14, 0x10, 0x0,
114 0x10, 0x14, 0x18, 0x14, 0x18, 0x14, 0x10, 0x14, 0x10, 0x14, 0x10, 0x14, 0x18, 0x0
115 };
116 static void do_bresp_cycle() {
117 /* my little axi - peripherals are magic */
118 logf("Cycling AXI bits ...\n\t");
119
120 for (int i = 0; i < sizeof(g_BrespTab)/sizeof(g_BrespTab[0]); i++) {
121 bresp_cycle_write(g_BrespTab[i]);
122
123 if (i && ((i % 14) == 0))
124 printf("\n\t");
125 }
126
127 printf("\n");
128 }
129
130 void setup_bridge(bool bresp_cycle) {
131 logf("setting up async bridge ...\n");
132
133 if (bresp_cycle) {
134 assert_global_reset();
135 do_bresp_cycle();
136 assert_global_reset();
137 udelay(300);
138 }
139
140 ARM_CONTROL1 &= ~ARM_C1_REQSTOP;
141 udelay(300);
142
143 if (!bresp_cycle)
144 assert_global_reset();
145
146 logf("bridge init done, PM_PROC is now: 0x%X!\n", PM_PROC);
147 }
148
149 static void set_clock_source(unsigned int source) {
150 CM_ARMCTL = CM_PASSWORD | source | CM_ARMCTL_ENAB_SET;
151 }
152
153 static void enable_clock() {
154 logf("initializing PLLB ...\n");
155
156 /* oscillator->pllb */
157 A2W_XOSC_CTRL |= A2W_PASSWORD | A2W_XOSC_CTRL_PLLBEN_SET;
158
159 A2W_PLLB_FRAC = A2W_PASSWORD | 0xeaaa8;
160 A2W_PLLB_CTRL = A2W_PASSWORD | 48 | 0x1000;
161
162 CM_PLLB = CM_PASSWORD | CM_PLLB_DIGRST_SET | CM_PLLB_ANARST_SET;
163 CM_PLLB = CM_PASSWORD | CM_PLLB_DIGRST_SET | CM_PLLB_ANARST_SET | CM_PLLB_HOLDARM_SET;
164
165 A2W_PLLB_ANA3 = A2W_PASSWORD | 0x100;
166 A2W_PLLB_ANA2 = A2W_PASSWORD | 0x0;
167 A2W_PLLB_ANA1 = A2W_PASSWORD | 0x140000;
168 A2W_PLLB_ANA0 = A2W_PASSWORD | 0x0;
169
170 A2W_PLLB_DIG3 = A2W_PASSWORD | 0x0;
171 A2W_PLLB_DIG2 = A2W_PASSWORD | 0x400000;
172 A2W_PLLB_DIG1 = A2W_PASSWORD | 0x3a;
173 A2W_PLLB_DIG0 = A2W_PASSWORD | 48 | 0xAAA000;
174
175 A2W_PLLB_CTRL = A2W_PASSWORD | 48 | 0x21000;
176
177 A2W_PLLB_DIG3 = A2W_PASSWORD | 0x2;
178 A2W_PLLB_DIG2 = A2W_PASSWORD | 0x402401;
179 A2W_PLLB_DIG1 = A2W_PASSWORD | 0x403a;
180 A2W_PLLB_DIG0 = A2W_PASSWORD | 48 | 0xAAA000;
181
182 A2W_PLLB_ARM = A2W_PASSWORD | 2;
183
184 CM_PLLB = CM_PASSWORD | CM_PLLB_DIGRST_SET | CM_PLLB_ANARST_SET | CM_PLLB_HOLDARM_SET | CM_PLLB_LOADARM_SET;
185 CM_PLLB = CM_PASSWORD | CM_PLLB_DIGRST_SET | CM_PLLB_ANARST_SET | CM_PLLB_HOLDARM_SET;
186 CM_PLLB = CM_PASSWORD;
187
188 set_clock_source(4);
189
190 logf("KAIP = 0x%X\n", A2W_PLLB_ANA_KAIP);
191 logf("MULTI = 0x%X\n", A2W_PLLB_ANA_MULTI);
192
193 logf("ARM clock succesfully initialized!\n");
194 }
195
196 static void arm_load_code() {
197 uint32_t* mem = (uint32_t*)(ARM_MEMORY_BASE);
198
199 uint8_t* start = &L_arm_code_start;
200 uint8_t* end = &L_arm_code_end;
201 uint32_t size = (uint32_t)(end - start);
202
203 bcopy(start, mem, size);
204
205 logf("copied %d bytes to 0x%X!\n", size, ARM_MEMORY_BASE);
206
207 /* verify */
208 for (int i = 0; i < size; i++) {
209 uint8_t* mem8 = (uint8_t*)(mem);
210 if (start[i] != mem8[i])
211 panic("copy failed at 0x%X expected 0x%X, got 0x%X", (uint32_t)&mem8[i],
212 *((uint32_t*)&mem8[i]),
213 *((uint32_t*)&start[i]));
214 }
215 }
216
217 static void arm_pmap_enter(uint32_t bus_address, uint32_t arm_address) {
218 volatile uint32_t* tte = &ARM_TRANSLATE;
219 uint32_t index = arm_address >> 24;
220 uint32_t pte = bus_address >> 21;
221
222 tte[index] = pte;
223
224 //logf("Translation: [0x%X => 0x%X] 0x%X => 0x%X\n", index * 4, bus_address >> 21, bus_address, arm_address);
225 }
226
227 /*
228 #define ARM_C0_PRIO_PER 0x00F00000 // per priority mask
229 #define ARM_C0_PRIO_L2 0x0F000000
230 #define ARM_C0_PRIO_UC 0xF0000000
231 */
232
233 void arm_init() {
234 logf("arm init started\n");
235
236 arm_load_code();
237
238 logf("original memstart: 0x%X\n", *((volatile uint32_t*)ARM_MEMORY_BASE));
239
240 for (uint32_t i = 0; i < 62; i++) {
241 uint32_t offset = i * 0x1000000;
242 arm_pmap_enter(ARM_MEMORY_BASE + offset, 0x0 + offset);
243 }
244
245 logf("mapped VC 0x%X to ARM 0x%X\n", ARM_MEMORY_BASE, 0);
246
247 arm_pmap_enter(VC4_PERIPH_BASE, ARM_PERIPH_BASE);
248
249 logf("mapped peripherals VC 0x%X to ARM 0x%X\n", VC4_PERIPH_BASE, ARM_PERIPH_BASE);
250
251 /* see if the ARM block is responding */
252 logf("ARM ID: 0x%X C0: 0x%X\n", ARM_ID, ARM_CONTROL0);
253
254 /*
255 * enable peripheral access, map arm secure bits to axi secure bits 1:1 and
256 * set the mem size for who knows what reason.
257 */
258 ARM_CONTROL0 |= 0x008 | ARM_C0_APROTSYST | ARM_C0_SIZ1G | ARM_C0_FULLPERI;
259
260 logf("using C0: 0x%X\n", ARM_CONTROL0);
261
262 enable_clock();
263 enable_power();
264 /* start io bridge */
265 setup_bridge(true);
266 logf("polling ARM state ...\n");
267
268 volatile uint32_t* arm_membase = (volatile uint32_t*)ARM_MEMORY_BASE;
269
270 /* skip vectors and get to comm chan */
271 arm_membase += 8;
272
273 for (;;/*int i = 0; i < 10; i++*/) {
274 if (arm_membase[3] == VPU_KILL_COMMAND) {
275 return;
276 }
277 logf("0x%X 0x%X 0x%X 0x%X\n", arm_membase[0], arm_membase[1], arm_membase[2], arm_membase[3]);
278 udelay(5000);
279 }
280 }
This page took 0.093541 seconds and 3 git commands to generate.