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