552e693341bae76bf3ae71a1585597daad747810
[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 <drivers/BCM2708PowerManagement.hpp>
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 inline void assert_global_reset() {
48 PowerManagementDomain::getDeviceForDomain(kCprPowerDomainARM)->setReset();
49 }
50
51 static void enable_power() {
52 PowerManagementDomain* armPm = PowerManagementDomain::getDeviceForDomain(kCprPowerDomainARM);
53 assert(armPm);
54 armPm->start();
55 }
56
57 static void bresp_cycle_write(uint32_t bits) {
58 ARM_CONTROL0 = (ARM_CONTROL0 & ~(ARM_C0_BRESP1|ARM_C0_BRESP2)) | bits;
59 printf("0x%X,", bits);
60 udelay(30);
61 }
62
63 static uint32_t g_BrespTab[] = {
64 0x10, 0x14, 0x10, 0x14, 0x10, 0x14, 0x10, 0x14, 0x10, 0x1C, 0x18, 0x1C, 0x18, 0x0,
65 0x10, 0x14, 0x10, 0x1C, 0x10, 0x14, 0x10, 0x14, 0x10, 0x14, 0x10, 0x14, 0x10, 0x0,
66 0x10, 0x14, 0x10, 0x1C, 0x18, 0x1C, 0x10, 0x14, 0x18, 0x1C, 0x10, 0x14, 0x10, 0x0,
67 0x10, 0x14, 0x18, 0x14, 0x10, 0x14, 0x10, 0x14, 0x10, 0x14, 0x10, 0x14, 0x10, 0x0,
68 0x10, 0x14, 0x18, 0x14, 0x18, 0x14, 0x10, 0x14, 0x10, 0x14, 0x10, 0x14, 0x18, 0x0
69 };
70 static void do_bresp_cycle() {
71 /* my little axi - peripherals are magic */
72 logf("Cycling AXI bits ...\n\t");
73
74 for (int i = 0; i < sizeof(g_BrespTab)/sizeof(g_BrespTab[0]); i++) {
75 bresp_cycle_write(g_BrespTab[i]);
76
77 if (i && ((i % 14) == 0))
78 printf("\n\t");
79 }
80
81 printf("\n");
82 }
83
84 void setup_bridge(bool bresp_cycle) {
85 logf("setting up async bridge ...\n");
86
87 if (bresp_cycle) {
88 assert_global_reset();
89 do_bresp_cycle();
90 assert_global_reset();
91 udelay(300);
92 }
93
94 logf("starting async bridge, ARM should be able to communicate through AXI ...\n");
95 ARM_CONTROL1 &= ~ARM_C1_REQSTOP;
96 udelay(300);
97
98 if (!bresp_cycle)
99 assert_global_reset();
100
101 logf("bridge init done, PM_PROC is now: 0x%X!\n", PM_PROC);
102 }
103
104 static void set_clock_source(unsigned int source) {
105 CM_ARMCTL = CM_PASSWORD | source | CM_ARMCTL_ENAB_SET;
106 }
107
108 static void enable_clock() {
109 logf("initializing PLLB ...\n");
110
111 /* oscillator->pllb */
112 A2W_XOSC_CTRL |= A2W_PASSWORD | A2W_XOSC_CTRL_PLLBEN_SET;
113
114 A2W_PLLB_FRAC = A2W_PASSWORD | 0xeaaa8;
115 A2W_PLLB_CTRL = A2W_PASSWORD | 48 | 0x1000;
116
117 CM_PLLB = CM_PASSWORD | CM_PLLB_DIGRST_SET | CM_PLLB_ANARST_SET;
118 CM_PLLB = CM_PASSWORD | CM_PLLB_DIGRST_SET | CM_PLLB_ANARST_SET | CM_PLLB_HOLDARM_SET;
119
120 A2W_PLLB_ANA3 = A2W_PASSWORD | 0x100;
121 A2W_PLLB_ANA2 = A2W_PASSWORD | 0x0;
122 A2W_PLLB_ANA1 = A2W_PASSWORD | 0x140000;
123 A2W_PLLB_ANA0 = A2W_PASSWORD | 0x0;
124
125 A2W_PLLB_DIG3 = A2W_PASSWORD | 0x0;
126 A2W_PLLB_DIG2 = A2W_PASSWORD | 0x400000;
127 A2W_PLLB_DIG1 = A2W_PASSWORD | 0x3a;
128 A2W_PLLB_DIG0 = A2W_PASSWORD | 48 | 0xAAA000;
129
130 A2W_PLLB_CTRL = A2W_PASSWORD | 48 | 0x21000;
131
132 A2W_PLLB_DIG3 = A2W_PASSWORD | 0x2;
133 A2W_PLLB_DIG2 = A2W_PASSWORD | 0x402401;
134 A2W_PLLB_DIG1 = A2W_PASSWORD | 0x403a;
135 A2W_PLLB_DIG0 = A2W_PASSWORD | 48 | 0xAAA000;
136
137 A2W_PLLB_ARM = A2W_PASSWORD | 2;
138
139 CM_PLLB = CM_PASSWORD | CM_PLLB_DIGRST_SET | CM_PLLB_ANARST_SET | CM_PLLB_HOLDARM_SET | CM_PLLB_LOADARM_SET;
140 CM_PLLB = CM_PASSWORD | CM_PLLB_DIGRST_SET | CM_PLLB_ANARST_SET | CM_PLLB_HOLDARM_SET;
141 CM_PLLB = CM_PASSWORD;
142
143 set_clock_source(4);
144
145 logf("KAIP = 0x%X\n", A2W_PLLB_ANA_KAIP);
146 logf("MULTI = 0x%X\n", A2W_PLLB_ANA_MULTI);
147
148 logf("ARM clock succesfully initialized!\n");
149 }
150
151 static void arm_load_code() {
152 uint32_t* mem = (uint32_t*)(ARM_MEMORY_BASE);
153
154 uint8_t* start = &L_arm_code_start;
155 uint8_t* end = &L_arm_code_end;
156 uint32_t size = (uint32_t)(end - start);
157
158 bcopy(start, mem, size);
159
160 logf("copied %d bytes to 0x%X!\n", size, ARM_MEMORY_BASE);
161
162 /* verify */
163 for (int i = 0; i < size; i++) {
164 uint8_t* mem8 = (uint8_t*)(mem);
165 if (start[i] != mem8[i])
166 panic("copy failed at 0x%X expected 0x%X, got 0x%X", (uint32_t)&mem8[i],
167 *((uint32_t*)&mem8[i]),
168 *((uint32_t*)&start[i]));
169 }
170 }
171
172 static void arm_pmap_enter(uint32_t bus_address, uint32_t arm_address) {
173 volatile uint32_t* tte = reinterpret_cast<volatile uint32_t*>(&ARM_TRANSLATE);
174
175 uint32_t index = arm_address >> 24;
176 uint32_t pte = bus_address >> 21;
177
178 tte[index] = pte;
179
180 //logf("Translation: [0x%X => 0x%X] 0x%X => 0x%X\n", index * 4, bus_address >> 21, bus_address, arm_address);
181 }
182
183 /*
184 #define ARM_C0_PRIO_PER 0x00F00000 // per priority mask
185 #define ARM_C0_PRIO_L2 0x0F000000
186 #define ARM_C0_PRIO_UC 0xF0000000
187 */
188
189 static void patch_arm_firmware_data() {
190 volatile firmware_arm_data_t* firmware_data = reinterpret_cast<firmware_arm_data_t*>(ARM_MEMORY_BASE + 32);
191
192 firmware_data->sdram_size = g_RAMSize;
193 firmware_data->vpu_cpuid = g_CPUID;
194 }
195
196 static void arm_enable_tzpc() {
197 /*
198 * enable SDRAM security.
199 * mask: 0xffffe000
200 */
201 logf("configuring secure SDRAM ...\n");
202 SD_SECSRT0 = 0xC0000000;
203 SD_SECEND0 = 0xC0011FFF;
204 logf("enabling secure SDRAM ...\n");
205 SD_SECSRT0 = 0xC0000001;
206 logf("secure SDRAM enabled ...\n");
207 }
208
209 extern "C" void arm_init() {
210 logf("arm init started\n");
211
212 arm_load_code();
213 patch_arm_firmware_data();
214
215 //arm_enable_tzpc();
216
217 logf("original memstart: 0x%X\n", *((volatile uint32_t*)ARM_MEMORY_BASE));
218
219 for (uint32_t i = 0; i < 62; i++) {
220 uint32_t offset = i * 0x1000000;
221 arm_pmap_enter(ARM_MEMORY_BASE + offset, 0x0 + offset);
222 }
223
224 logf("mapped VC 0x%X to ARM 0x%X\n", ARM_MEMORY_BASE, 0);
225
226 arm_pmap_enter(VC4_PERIPH_BASE, ARM_PERIPH_BASE);
227
228 logf("mapped peripherals VC 0x%X to ARM 0x%X\n", VC4_PERIPH_BASE, ARM_PERIPH_BASE);
229
230 /* see if the ARM block is responding */
231 logf("ARM ID: 0x%X C0: 0x%X\n", ARM_ID, ARM_CONTROL0);
232
233 /*
234 * enable peripheral access, map arm secure bits to axi secure bits 1:1 and
235 * set the mem size for who knows what reason.
236 */
237 ARM_CONTROL0 |= 0x008 | ARM_C0_APROTPASS | ARM_C0_SIZ1G | ARM_C0_FULLPERI;
238 ARM_CONTROL1 |= ARM_C1_PERSON;
239
240 ARM_IRQ_ENBL3 |= ARM_IE_MAIL;
241
242 logf("using C0: 0x%X\n", ARM_CONTROL0);
243
244 enable_clock();
245 enable_power();
246 /* start io bridge */
247 setup_bridge(true);
248 }
This page took 0.091607 seconds and 3 git commands to generate.