1 /*
2 * bcm2711 (raspberry pi 4) architecture-specific stuff
3 */
4
5 #include "u.h"
6 #include "../port/lib.h"
7 #include "mem.h"
8 #include "dat.h"
9 #include "fns.h"
10 #include "../port/error.h"
11 #include "io.h"
12 #include "arm.h"
13
14 #include "../port/netif.h"
15 #include "etherif.h"
16
17 typedef struct Mbox Mbox;
18 typedef struct Mboxes Mboxes;
19
20 #define POWERREGS (VIRTIO+0x100000)
21
22 Soc soc = {
23 .dramsize = 0xFC000000,
24 .physio = 0xFE000000,
25 .busdram = 0xC0000000,
26 .busio = 0x7E000000,
27 .armlocal = 0xFF800000,
28 .oscfreq = 54000000,
29 .l1ptedramattrs = Cached | Buffered | L1wralloc | L1sharable,
30 .l2ptedramattrs = Cached | Buffered | L2wralloc | L2sharable,
31 };
32
33 enum {
34 Wdogfreq = 65536,
35 Wdogtime = 10, /* seconds, ≤ 15 */
36 };
37
38 /*
39 * Power management / watchdog registers
40 */
41 enum {
42 Rstc = 0x1c>>2,
43 Password = 0x5A<<24,
44 CfgMask = 0x03<<4,
45 CfgReset = 0x02<<4,
46 Rsts = 0x20>>2,
47 Wdog = 0x24>>2,
48 };
49
50 /*
51 * Arm local regs for smp
52 */
53 struct Mbox {
54 u32int doorbell;
55 u32int mbox1;
56 u32int mbox2;
57 u32int startcpu;
58 };
59 struct Mboxes {
60 Mbox set[4];
61 Mbox clr[4];
62 };
63
64 enum {
65 Mboxregs = 0x80
66 };
67
68 static Lock startlock[MAXMACH + 1];
69
70 void
archreset(void)71 archreset(void)
72 {
73 fpon();
74 }
75
76 void
archreboot(void)77 archreboot(void)
78 {
79 u32int *r;
80
81 r = (u32int*)POWERREGS;
82 r[Wdog] = Password | 1;
83 r[Rstc] = Password | (r[Rstc] & ~CfgMask) | CfgReset;
84 coherence();
85 for(;;)
86 ;
87 }
88
89 void
wdogfeed(void)90 wdogfeed(void)
91 {
92 u32int *r;
93
94 r = (u32int*)POWERREGS;
95 r[Wdog] = Password | (Wdogtime * Wdogfreq);
96 r[Rstc] = Password | (r[Rstc] & ~CfgMask) | CfgReset;
97 }
98
99 void
wdogoff(void)100 wdogoff(void)
101 {
102 u32int *r;
103
104 r = (u32int*)POWERREGS;
105 r[Rstc] = Password | (r[Rstc] & ~CfgMask);
106 }
107
108
109 char *
cputype2name(char * buf,int size)110 cputype2name(char *buf, int size)
111 {
112 u32int r;
113 uint part;
114 char *p;
115
116 r = cpidget(); /* main id register */
117 assert((r >> 24) == 'A');
118 part = (r >> 4) & MASK(12);
119 switch(part){
120 case 0xc07:
121 p = seprint(buf, buf + size, "Cortex-A7");
122 break;
123 case 0xd03:
124 p = seprint(buf, buf + size, "Cortex-A53");
125 break;
126 case 0xd08:
127 p = seprint(buf, buf + size, "Cortex-A72");
128 break;
129 default:
130 p = seprint(buf, buf + size, "Unknown-%#x", part);
131 break;
132 }
133 seprint(p, buf + size, " r%ldp%ld",
134 (r >> 20) & MASK(4), r & MASK(4));
135 return buf;
136 }
137
138 void
cpuidprint(void)139 cpuidprint(void)
140 {
141 char name[64];
142
143 cputype2name(name, sizeof name);
144 delay(50); /* let uart catch up */
145 print("cpu%d: %dMHz ARM %s\n", m->machno, m->cpumhz, name);
146 }
147
148 int
getncpus(void)149 getncpus(void)
150 {
151 int n, max;
152 char *p;
153
154 n = 4;
155 if(n > MAXMACH)
156 n = MAXMACH;
157 p = getconf("*ncpu");
158 if(p && (max = atoi(p)) > 0 && n > max)
159 n = max;
160 return n;
161 }
162
163 static int
startcpu(uint cpu)164 startcpu(uint cpu)
165 {
166 Mboxes *mb;
167 int i;
168 void cpureset();
169
170 mb = (Mboxes*)(ARMLOCAL + Mboxregs);
171 if(mb->clr[cpu].startcpu)
172 return -1;
173 mb->set[cpu].startcpu = PADDR(cpureset);
174 coherence();
175 sev();
176 for(i = 0; i < 1000; i++)
177 if(mb->clr[cpu].startcpu == 0)
178 return 0;
179 mb->clr[cpu].startcpu = PADDR(cpureset);
180 mb->set[cpu].doorbell = 1;
181 return 0;
182 }
183
184 void
mboxclear(uint cpu)185 mboxclear(uint cpu)
186 {
187 Mboxes *mb;
188
189 mb = (Mboxes*)(ARMLOCAL + Mboxregs);
190 mb->clr[cpu].mbox1 = 1;
191 }
192
193 void
wakecpu(uint cpu)194 wakecpu(uint cpu)
195 {
196 Mboxes *mb;
197
198 mb = (Mboxes*)(ARMLOCAL + Mboxregs);
199 mb->set[cpu].mbox1 = 1;
200 }
201
202 int
startcpus(uint ncpu)203 startcpus(uint ncpu)
204 {
205 int i, timeout;
206
207 for(i = 0; i < ncpu; i++)
208 lock(&startlock[i]);
209 cachedwbse(startlock, sizeof startlock);
210 for(i = 1; i < ncpu; i++){
211 if(startcpu(i) < 0)
212 return i;
213 timeout = 10000000;
214 while(!canlock(&startlock[i]))
215 if(--timeout == 0)
216 return i;
217 unlock(&startlock[i]);
218 }
219 return ncpu;
220 }
221
222 void
archbcm4link(void)223 archbcm4link(void)
224 {
225 addclock0link(wdogfeed, HZ);
226 }
227
228 int
archether(unsigned ctlrno,Ether * ether)229 archether(unsigned ctlrno, Ether *ether)
230 {
231 switch(ctlrno){
232 case 0:
233 ether->type = "genet";
234 break;
235 case 1:
236 ether->type = "4330";
237 break;
238 default:
239 return 0;
240 }
241 ether->ctlrno = ctlrno;
242 ether->irq = -1;
243 ether->nopt = 0;
244 ether->maxmtu = 9014;
245 return 1;
246 }
247
248 int
l2ap(int ap)249 l2ap(int ap)
250 {
251 return (AP(0, (ap)));
252 }
253
254 int
cmpswap(long * addr,long old,long new)255 cmpswap(long *addr, long old, long new)
256 {
257 return cas((ulong*)addr, old, new);
258 }
259
260 void
cpustart(int cpu)261 cpustart(int cpu)
262 {
263 Mboxes *mb;
264 void machon(int);
265
266 up = nil;
267 machinit();
268 mb = (Mboxes*)(ARMLOCAL + Mboxregs);
269 mb->clr[cpu].doorbell = 1;
270 trapinit();
271 clockinit();
272 mmuinit1();
273 timersinit();
274 cpuidprint();
275 archreset();
276 machon(m->machno);
277 unlock(&startlock[cpu]);
278 schedinit();
279 panic("schedinit returned");
280 }
281