xref: /plan9-contrib/sys/src/9/bcm/archbcm2.c (revision 5c47fe09a0cc86dfb02c0ea4a2b6aec7eda2361f)
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