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