add preliminary clock code that's expected to be set up by fw, gut old arm loader...
[rpi-open-firmware.git] / drivers / BCM2708ArmControl.cc
1 /*
2 * VideoCore4_Drivers
3 * Copyright (c) 2017 Kristina Brooks
4 *
5 * ARM control driver.
6 */
7
8 #include <drivers/IODevice.hpp>
9 #include <drivers/BCM2708PowerManagement.hpp>
10 #include <drivers/BCM2708ClockDomains.hpp>
11
12 #define FLAG_BUSY (1 << 31)
13
14 extern uint32_t g_CPUID;
15 extern uint32_t g_RAMSize;
16
17 extern uint8_t L_arm_code_start;
18 extern uint8_t L_arm_code_end;
19
20 #define ARM_MEMORY_BASE 0xC0000000
21 #define ARM_BKPT_OPCODE 0xE1200070
22
23 /*
24 * RPi3: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0488d/CIHBDCJD.html
25 */
26
27 /*
28 * This controls AA64nAA32 signal, when set, ARM starts in AArch64 mode. Only applicable
29 * to systems using Cortex-A53.
30 */
31 #define ARM_C0_AARCH64 0x00000200
32
33 static uint32_t g_BrespTab[] = {
34 0x10, 0x14, 0x10, 0x14, 0x10, 0x14, 0x10, 0x14, 0x10, 0x1C, 0x18, 0x1C, 0x18, 0x0,
35 0x10, 0x14, 0x10, 0x1C, 0x10, 0x14, 0x10, 0x14, 0x10, 0x14, 0x10, 0x14, 0x10, 0x0,
36 0x10, 0x14, 0x10, 0x1C, 0x18, 0x1C, 0x10, 0x14, 0x18, 0x1C, 0x10, 0x14, 0x10, 0x0,
37 0x10, 0x14, 0x18, 0x14, 0x10, 0x14, 0x10, 0x14, 0x10, 0x14, 0x10, 0x14, 0x10, 0x0,
38 0x10, 0x14, 0x18, 0x14, 0x18, 0x14, 0x10, 0x14, 0x10, 0x14, 0x10, 0x14, 0x18, 0x0
39 };
40
41 struct BCM2708ArmControl : IODevice {
42 IODriverConstructor(BCM2708ArmControl);
43
44 PowerManagementDomain* pmDomain;
45
46 static inline void bridgeWriteBresp(uint32_t bits) {
47 ARM_CONTROL0 = (ARM_CONTROL0 & ~(ARM_C0_BRESP1|ARM_C0_BRESP2)) | bits;
48 udelay(30);
49 }
50
51 void bridgeCycleBresp() {
52 IODriverLog("cycling through bresp bits ...");
53 for (int i = 0; i < sizeof(g_BrespTab)/sizeof(g_BrespTab[0]); i++) {
54 bridgeWriteBresp(g_BrespTab[i]);
55 }
56 }
57
58 void bridgeStart(bool cycleBrespBits) {
59 IODriverLog("setting up async bridge ...");
60
61 if (cycleBrespBits) {
62 pmDomain->setReset();
63 bridgeCycleBresp();
64 pmDomain->setReset();
65
66 udelay(300);
67 }
68
69 IODriverLog("starting async bridge now!");
70 ARM_CONTROL1 &= ~ARM_C1_REQSTOP;
71 udelay(300);
72
73 if (!cycleBrespBits)
74 pmDomain->setReset();
75
76 IODriverLog("bridge init done, PM_PROC is now: 0x%X!", PM_PROC);
77 }
78
79 void setupClock() {
80 IODriverLog("initializing PLLB ...");
81
82 /* oscillator->pllb */
83 A2W_XOSC_CTRL |= A2W_PASSWORD | A2W_XOSC_CTRL_PLLBEN_SET;
84
85 A2W_PLLB_FRAC = A2W_PASSWORD | 0xeaaa8;
86 A2W_PLLB_CTRL = A2W_PASSWORD | 48 | 0x1000;
87
88 CM_PLLB = CM_PASSWORD | CM_PLLB_DIGRST_SET | CM_PLLB_ANARST_SET;
89 CM_PLLB = CM_PASSWORD | CM_PLLB_DIGRST_SET | CM_PLLB_ANARST_SET | CM_PLLB_HOLDARM_SET;
90
91 A2W_PLLB_ANA3 = A2W_PASSWORD | 0x100;
92 A2W_PLLB_ANA2 = A2W_PASSWORD | 0x0;
93 A2W_PLLB_ANA1 = A2W_PASSWORD | 0x140000;
94 A2W_PLLB_ANA0 = A2W_PASSWORD | 0x0;
95
96 BCM2708VCO* pllb = static_cast<BCM2708VCO*>(IODevice::findByTag('PLLB'));
97 assert(pllb);
98 pllb->setDigValues();
99
100 A2W_PLLB_ARM = A2W_PASSWORD | 2;
101
102 CM_PLLB = CM_PASSWORD | CM_PLLB_DIGRST_SET | CM_PLLB_ANARST_SET | CM_PLLB_HOLDARM_SET | CM_PLLB_LOADARM_SET;
103 CM_PLLB = CM_PASSWORD | CM_PLLB_DIGRST_SET | CM_PLLB_ANARST_SET | CM_PLLB_HOLDARM_SET;
104 CM_PLLB = CM_PASSWORD;
105
106 CM_ARMCTL = CM_PASSWORD | 4 | CM_ARMCTL_ENAB_SET;
107
108 IODriverLog("KAIP = 0x%X", A2W_PLLB_ANA_KAIP); /* 0x228 */
109 IODriverLog("MULTI = 0x%X", A2W_PLLB_ANA_MULTI); /* 0x613277 */
110
111 IODriverLog("ARM clock succesfully initialized!");
112 }
113
114 void patchFirmwareData() {
115 volatile firmware_arm_data_t* firmware_data = reinterpret_cast<firmware_arm_data_t*>(ARM_MEMORY_BASE + 32);
116
117 firmware_data->sdram_size = g_RAMSize;
118 firmware_data->vpu_cpuid = g_CPUID;
119 }
120
121 void loadInitialCode() {
122 uint32_t* mem = (uint32_t*)(ARM_MEMORY_BASE);
123
124 uint8_t* start = &L_arm_code_start;
125 uint8_t* end = &L_arm_code_end;
126 uint32_t size = (uint32_t)(end - start);
127
128 bcopy(start, mem, size);
129
130 IODriverLog("copied %d bytes to 0x%X!", size, ARM_MEMORY_BASE);
131
132 /* verify */
133 for (int i = 0; i < size; i++) {
134 uint8_t* mem8 = (uint8_t*)(mem);
135 if (start[i] != mem8[i])
136 panic("copy failed at 0x%X expected 0x%X, got 0x%X", (uint32_t)&mem8[i],
137 *((uint32_t*)&mem8[i]),
138 *((uint32_t*)&start[i]));
139 }
140
141 patchFirmwareData();
142 }
143
144 void mapBusToArm(uint32_t busAddr, uint32_t armAddr) {
145 volatile uint32_t* tte = reinterpret_cast<volatile uint32_t*>(&ARM_TRANSLATE);
146
147 uint32_t index = armAddr >> 24;
148 uint32_t pte = busAddr >> 21;
149
150 tte[index] = pte;
151 }
152
153 virtual void start() override {
154 IODriverLog("starting ...");
155
156 pmDomain = PowerManagementDomain::getDeviceForDomain(kCprPowerDomainARM);
157 assert(pmDomain);
158
159 loadInitialCode();
160
161 IODriverLog("original memstart: 0x%X", *((volatile uint32_t*)ARM_MEMORY_BASE));
162
163 for (uint32_t i = 0; i < 62; i++) {
164 uint32_t offset = i * 0x1000000;
165 mapBusToArm(ARM_MEMORY_BASE + offset, 0x0 + offset);
166 }
167
168 IODriverLog("mapped VC 0x%X to ARM 0x%X", ARM_MEMORY_BASE, 0);
169
170 mapBusToArm(VC4_PERIPH_BASE, ARM_PERIPH_BASE);
171
172 IODriverLog("mapped peripherals VC 0x%X to ARM 0x%X", VC4_PERIPH_BASE, ARM_PERIPH_BASE);
173
174 /* see if the ARM block is responding */
175 IODriverLog("ARM ID: 0x%X C0: 0x%X", ARM_ID, ARM_CONTROL0);
176
177 /*
178 * enable peripheral access, map arm secure bits to axi secure bits 1:1 and
179 * set the mem size for who knows what reason.
180 */
181 ARM_CONTROL0 |= 0x008 | ARM_C0_APROTPASS | ARM_C0_SIZ1G | ARM_C0_FULLPERI;
182 ARM_CONTROL1 |= ARM_C1_PERSON;
183
184 ARM_IRQ_ENBL3 |= ARM_IE_MAIL;
185
186 IODriverLog("using C0: 0x%X", ARM_CONTROL0);
187
188 setupClock();
189 pmDomain->start();
190
191 /*
192 * ARM is now powered on but stalling on a bus transaction, start the
193 * async bridge and let ARM start fetching instructions.
194 */
195 bridgeStart(true);
196
197 IODevice::start();
198 }
199
200 virtual void init() override {
201 setTag('ARMC');
202 }
203 };
204
205 IODriverCreateSingletonInstance(BCM2708ArmControl);
206
This page took 0.095237 seconds and 4 git commands to generate.