9561e2e672af3cff3c770c7425705510457b612a
[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
24 #define logf(fmt, ...) printf("[ARMLDR:%s]: " fmt, __FUNCTION__, ##__VA_ARGS__);
25
26 extern uint8_t L_arm_code_start;
27 extern uint8_t 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 = reinterpret_cast<volatile uint32_t*>(&ARM_TRANSLATE);
219
220 uint32_t index = arm_address >> 24;
221 uint32_t pte = bus_address >> 21;
222
223 tte[index] = pte;
224
225 //logf("Translation: [0x%X => 0x%X] 0x%X => 0x%X\n", index * 4, bus_address >> 21, bus_address, arm_address);
226 }
227
228 /*
229 #define ARM_C0_PRIO_PER 0x00F00000 // per priority mask
230 #define ARM_C0_PRIO_L2 0x0F000000
231 #define ARM_C0_PRIO_UC 0xF0000000
232 */
233
234 extern "C" void arm_init() {
235 logf("arm init started\n");
236
237 arm_load_code();
238
239 logf("original memstart: 0x%X\n", *((volatile uint32_t*)ARM_MEMORY_BASE));
240
241 for (uint32_t i = 0; i < 62; i++) {
242 uint32_t offset = i * 0x1000000;
243 arm_pmap_enter(ARM_MEMORY_BASE + offset, 0x0 + offset);
244 }
245
246 logf("mapped VC 0x%X to ARM 0x%X\n", ARM_MEMORY_BASE, 0);
247
248 arm_pmap_enter(VC4_PERIPH_BASE, ARM_PERIPH_BASE);
249
250 logf("mapped peripherals VC 0x%X to ARM 0x%X\n", VC4_PERIPH_BASE, ARM_PERIPH_BASE);
251
252 /* see if the ARM block is responding */
253 logf("ARM ID: 0x%X C0: 0x%X\n", ARM_ID, ARM_CONTROL0);
254
255 /*
256 * enable peripheral access, map arm secure bits to axi secure bits 1:1 and
257 * set the mem size for who knows what reason.
258 */
259 ARM_CONTROL0 |= 0x008 | ARM_C0_APROTSYST | ARM_C0_SIZ1G | ARM_C0_FULLPERI;
260 ARM_CONTROL1 |= ARM_C1_PERSON;
261
262 ARM_IRQ_ENBL3 |= ARM_IE_MAIL;
263
264 logf("using C0: 0x%X\n", ARM_CONTROL0);
265
266 enable_clock();
267 enable_power();
268 /* start io bridge */
269 setup_bridge(true);
270 }
This page took 0.093027 seconds and 3 git commands to generate.