xref: /plan9/sys/src/9/kw/archkw.c (revision b649930dd34d6bab2bb3fa27632347c57745aead)
1 /*
2  * stuff specific to marvell's kirkwood architecture
3  * as seen in the sheevaplug
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 
13 #include "../port/netif.h"
14 #include "etherif.h"
15 #include "../port/flashif.h"
16 
17 #include "arm.h"
18 
19 enum {
20 	L2writeback = 1,
21 	Debug = 0,
22 };
23 
24 typedef struct GpioReg GpioReg;
25 struct GpioReg {
26 	ulong	dataout;
27 	ulong	dataoutena;
28 	ulong	blinkena;
29 	ulong	datainpol;
30 	ulong	datain;
31 	ulong	intrcause;
32 	ulong	intrmask;
33 	ulong	intrlevelmask;
34 };
35 
36 typedef struct L2uncache L2uncache;
37 typedef struct L2win L2win;
38 struct L2uncache {
39 	struct L2win {
40 		ulong	base;	/* phys addr */
41 		ulong	size;
42 	} win[4];
43 };
44 
45 enum {
46 	/* L2win->base bits */
47 	L2enable	= 1<<0,
48 };
49 
50 typedef struct Dramctl Dramctl;
51 struct Dramctl {
52 	ulong	ctl;
53 	ulong	ddrctllo;
54 	struct {
55 		ulong	lo;
56 		ulong	hi;
57 	} time;
58 	ulong	addrctl;
59 	ulong	opagectl;
60 	ulong	oper;
61 	ulong	mode;
62 	ulong	extmode;
63 	ulong	ddrctlhi;
64 	ulong	ddr2timelo;
65 	ulong	operctl;
66 	struct {
67 		ulong	lo;
68 		ulong	hi;
69 	} mbusctl;
70 	ulong	mbustimeout;
71 	ulong	ddrtimehi;
72 	ulong	sdinitctl;
73 	ulong	extsdmode1;
74 	ulong	extsdmode2;
75 	struct {
76 		ulong	lo;
77 		ulong	hi;
78 	} odtctl;
79 	ulong	ddrodtctl;
80 	ulong	rbuffsel;
81 
82 	ulong	accalib;
83 	ulong	dqcalib;
84 	ulong	dqscalib;
85 };
86 
87 /* unused so far */
88 typedef struct SDramdReg SDramdReg;
89 struct SDramdReg {
90 	struct {
91 		ulong	base;
92 		ulong	size;
93 	} win[4];
94 };
95 
96 typedef struct Addrmap Addrmap;
97 typedef struct Addrwin Addrwin;
98 struct Addrmap {
99 	struct Addrwin {
100 		ulong	ctl;		/* see Winenable in io.h */
101 		ulong	base;		/* virtual address */
102 		ulong	remaplo;	/* physical address sent to target */
103 		ulong	remaphi;	/* " */
104 	} win[8];
105 	ulong	dirba;		/* device internal reg's base addr.: PHYSIO */
106 };
107 
108 Soc soc = {
109 	.cpu		= PHYSIO+0x20100,
110 	.devid		= PHYSIO+0x10034,
111 	.l2cache	= PHYSIO+0x20a00,  	/* uncachable addrs for L2 */
112 	.sdramc		= PHYSIO+0x01400,
113 //	.sdramd		= PHYSIO+0x01500,	/* unused */
114 
115 	.iocfg		= PHYSIO+0x100e0,
116 	.addrmap	= PHYSIO+0x20000,	/* cpu address map */
117 	.intr		= PHYSIO+0x20200,
118 	.nand		= PHYSIO+0x10418,
119 	.cesa		= PHYSIO+0x30000,	/* crypto accelerator */
120 	.ehci		= PHYSIO+0x50000,
121 	.spi		= PHYSIO+0x10600,
122  	.twsi		= PHYSIO+0x11000,
123 
124 	.analog		= PHYSIO+0x1007c,
125 	.pci		= PHYSIO+0x40000,
126 	.pcibase	= PHYSIO+0x41800,
127 
128 	.rtc		= PHYSIO+0x10300,
129 	.clock		= PHYSIO+0x20300,
130 //	.clockctl	= PHYSIO+0x1004c,	/* unused */
131 
132 	.ether		= { PHYSIO+0x72000, PHYSIO+0x76000, },
133 	.sata		= { PHYSIO+0x80000,	/* sata config reg here */
134 			PHYSIO+0x82000,		/* edma config reg here */
135 			PHYSIO+0x84000,		/* edma config reg here */
136 			},
137 	.uart		= { PHYSIO+0x12000, PHYSIO+0x12100, },
138 	.gpio		= { PHYSIO+0x10100, PHYSIO+0x10140, },
139 };
140 
141 /*
142  * sheeva/openrd u-boot leaves us with this address map:
143  *
144  * 0 targ 4 attr 0xe8 size 256MB addr 0x9::  remap addr 0x9::	pci mem
145  * 1 targ 1 attr 0x2f size   8MB addr 0xf9:: remap addr 0xf9::	nand flash
146  * 2 targ 4 attr 0xe0 size  16MB addr 0xf::  remap addr 0xc::	pci i/o
147  * 3 targ 1 attr 0x1e size  16MB addr 0xf8:: remap addr 0x0	spi flash
148  * 4 targ 1 attr 0x1d size  16MB addr 0xff::			boot rom
149  * 5 targ 1 attr 0x1e size 128MB addr 0xe8::	disabled	spi flash
150  * 6 targ 1 attr 0x1d size 128MB addr 0xf::	disabled	boot rom
151  * 7 targ 3 attr 0x1  size  64K  addr 0xfb::			crypto sram
152  *
153  * dreamplug u-boot leaves us with this address map:
154  *
155  * 0 targ 4 attr 0xe8 size 256MB addr 0x9::  remap addr 0x9::	pci mem
156  * 1 targ 4 attr 0xe0 size  64KB addr 0xc::  remap addr 0xc::	pci i/o
157  * 2 targ 1 attr 0x2f size 128MB addr 0xd8:: remap addr 0xd8::	nand flash
158  * 3 targ 1 attr 0x1e size 128MB addr 0xe8:: remap addr 0xe8::	spi flash
159  * 4 targ 1 attr 0x1d size 128MB addr 0xf8::			boot rom
160  * 5 targ 3 attr 0x1  size  64K  addr 0xc801::			crypto sram
161  * 6 targ 0 attr 0x0  size  64K  addr 0xf::	disabled	ram?
162  * 7 targ 0 attr 0x0  size  64K  addr 0xf8::	disabled	ram?
163  */
164 
165 #define WINTARG(ctl)	(((ctl) >> 4) & 017)
166 #define WINATTR(ctl)	(((ctl) >> 8) & 0377)
167 #define WIN64KSIZE(ctl)	(((ctl) >> 16) + 1)
168 
169 static void
praddrwin(Addrwin * win,int i)170 praddrwin(Addrwin *win, int i)
171 {
172 	ulong ctl, targ, attr, size64k;
173 
174 	if (!Debug) {
175 		USED(win, i);
176 		return;
177 	}
178 	ctl = win->ctl;
179 	targ = WINTARG(ctl);
180 	attr = WINATTR(ctl);
181 	size64k = WIN64KSIZE(ctl);
182 	print("cpu addr map: %s window %d: targ %ld attr %#lux size %,ld addr %#lux",
183 		ctl & Winenable? "enabled": "disabled", i, targ, attr,
184 		size64k * 64*1024, win->base);
185 	if (i < 4)
186 		print(" remap addr %#llux", (uvlong)win->remaphi<<32 |
187 			win->remaplo);
188 	print("\n");
189 }
190 
191 static void
fixaddrmap(void)192 fixaddrmap(void)
193 {
194 	int i;
195 	ulong ctl, targ, attr, size64k;
196 	Addrmap *map;
197 	Addrwin *win;
198 
199 	map = (Addrmap *)soc.addrmap;
200 	for (i = 0; i < nelem(map->win); i++) {
201 		win = &map->win[i];
202 		ctl = win->ctl;
203 		targ = WINTARG(ctl);
204 		attr = WINATTR(ctl);
205 		size64k = WIN64KSIZE(ctl);
206 
207 		USED(attr, size64k);
208 		if (targ == Targcesasram) {
209 			win->ctl |= Winenable;
210 			win->base = PHYSCESASRAM;
211 			coherence();
212 			praddrwin(win, i);
213 		}
214 	}
215 	if (map->dirba != PHYSIO)
216 		panic("dirba not %#ux", PHYSIO);
217 }
218 
219 static void
praddrmap(void)220 praddrmap(void)
221 {
222 	int i;
223 	Addrmap *map;
224 
225 	map = (Addrmap *)soc.addrmap;
226 	for (i = 0; i < nelem(map->win); i++)
227 		praddrwin(&map->win[i], i);
228 }
229 
230 int
ispow2(uvlong ul)231 ispow2(uvlong ul)
232 {
233 	/* see Hacker's Delight if this isn't obvious */
234 	return (ul & (ul - 1)) == 0;
235 }
236 
237 /*
238  * return exponent of smallest power of 2 ≥ n
239  */
240 int
log2(ulong n)241 log2(ulong n)
242 {
243 	int i;
244 
245 	i = 31 - clz(n);
246 	if (!ispow2(n) || n == 0)
247 		i++;
248 	return i;
249 }
250 
251 void
cacheinfo(int level,int kind,Memcache * cp)252 cacheinfo(int level, int kind, Memcache *cp)		/* l1 only */
253 {
254 	uint len, assoc, size;
255 	ulong setsways;
256 
257 	/* get cache types & sizes (read-only reg) */
258 	setsways = cprdsc(0, CpID, CpIDidct, CpIDct);
259 
260 	cp->level = level;
261 	cp->kind = kind;
262 
263 	if ((setsways & (1<<24)) == 0)
264 		kind = Unified;
265 	if (kind != Icache)
266 		setsways >>= 12;
267 
268 	assoc = (setsways >> 3) & MASK(3);
269 	cp->nways = 1 << assoc;
270 	size = (setsways >> 6) & MASK(4);
271 	cp->size  = 1 << (size + 9);
272 	len = setsways & MASK(2);
273 	cp->log2linelen = len + 3;
274 	cp->linelen = 1 << cp->log2linelen;
275 	cp->setsways = setsways;
276 
277 	cp->nsets = 1 << (size + 6 - assoc - len);
278 	cp->setsh = cp->log2linelen;
279 	cp->waysh = 32 - log2(cp->nways);
280 }
281 
282 static char *
wbtype(uint type)283 wbtype(uint type)
284 {
285 	static char *types[] = {
286 		"write-through",
287 		"read data block",
288 		"reg 7 ops, no lock-down",
289 	[06]	"reg 7 ops, format A",
290 	[07]	"reg 7 ops, format B deprecated",
291 	[016]	"reg 7 ops, format C",
292 	[05]	"reg 7 ops, format D",
293 	};
294 
295 	if (type >= nelem(types) || types[type] == nil)
296 		return "GOK";
297 	return types[type];
298 }
299 
300 static void
prcache(Memcache * mcp)301 prcache(Memcache *mcp)
302 {
303 	int type;
304 	char id;
305 
306 	if (mcp->kind == Unified)
307 		id = 'U';
308 	else if (mcp->kind == Icache)
309 		id = 'I';
310 	else if (mcp->kind == Dcache)
311 		id = 'D';
312 	else
313 		id = '?';
314 	print("l%d %c: %d bytes, %d ways %d sets %d bytes/line",
315 		mcp->level, id, mcp->size, mcp->nways, mcp->nsets,
316 		mcp->linelen);
317 	if (mcp->linelen != CACHELINESZ)
318 		print(" *should* be %d", CACHELINESZ);
319 	type = (mcp->setsways >> 25) & MASK(4);
320 	if (type == 0)
321 		print("; write-through only");
322 	else
323 		print("; write-back type `%s' (%#o) possible",
324 			wbtype(type), type);
325 	if (mcp->setsways & (1<<11))
326 		print("; page table mapping restrictions apply");
327 	if (mcp->setsways & (1<<2))
328 		print("; M bit is set in cache type reg");
329 	print("\n");
330 }
331 
332 static void
prcachecfg(void)333 prcachecfg(void)
334 {
335 	Memcache mc;
336 
337 	cacheinfo(1, Dcache, &mc);
338 	prcache(&mc);
339 	cacheinfo(1, Icache, &mc);
340 	prcache(&mc);
341 }
342 
343 void
l2cacheon(void)344 l2cacheon(void)
345 {
346 	ulong cfg;
347 	CpucsReg *cpu;
348 	L2uncache *l2p;
349 
350 	cacheuwbinv();
351 	l2cacheuwbinv();
352 	l1cachesoff();			/* turns off L2 as a side effect */
353 
354 	cpwrsc(CpDef, CpCLD, 0, 0, 0);  /* GL-CPU-100: set D cache lockdown reg. */
355 
356 	/* marvell guideline GL-CPU-130 */
357 	cpu = (CpucsReg *)soc.cpu;
358 	cfg = cpu->cpucfg | L2exists | L2ecc | Cfgiprefetch | Cfgdprefetch;
359 
360 	if (L2writeback)
361 		cfg &= ~L2writethru;	/* see PTE Cached & Buffered bits */
362 	else
363 		cfg |= L2writethru;
364 	cpu->l2cfg = cfg;
365 	coherence();			/* force l2 cache to pay attention */
366 	cpu->l2tm1 = cpu->l2tm0 = 0x66666666; /* marvell guideline GL-CPU-120 */
367 	coherence();
368 
369 	cpwrsc(CpL2, CpTESTCFG, CpTCl2waylck, CpTCl2waylock, 0);
370 
371 	cachedinv();
372 	l2cacheuinv();
373 
374 	/* disable l2 caching of i/o registers */
375 	l2p = (L2uncache *)soc.l2cache;
376 	memset(l2p, 0, sizeof *l2p);
377 	/*
378 	 * l2: don't cache upper half of address space.
379 	 * the L2 cache is PIPT, so the addresses are physical.
380 	 */
381 	l2p->win[0].base = 0x80000000 | L2enable;	/* 64K multiple */
382 	l2p->win[0].size = (32*1024-1) << 16;		/* 64K multiples */
383 	coherence();
384 
385 	l2cachecfgon();
386 	l1cacheson();			/* turns L2 on as a side effect */
387 	print("l2 cache: 256K or 512K: 4 ways, 32-byte lines, write-%s, sdram only\n",
388 		cpu->l2cfg & L2writethru? "through": "back");
389 }
390 
391 /* called late in main */
392 void
archconfinit(void)393 archconfinit(void)
394 {
395 	m->cpuhz = Frequency;
396 	m->delayloop = m->cpuhz/2000; 	 /* initial estimate */
397 	fixaddrmap();
398 	if (Debug)
399 		praddrmap();
400 	prcachecfg();
401 
402 	l2cacheon();
403 }
404 
405 void
archkwlink(void)406 archkwlink(void)
407 {
408 }
409 
410 int
archether(unsigned ctlno,Ether * ether)411 archether(unsigned ctlno, Ether *ether)
412 {
413 	if(ctlno >= 2)
414 		return -1;
415 	ether->type = "88e1116";
416 	ether->port = ctlno;
417 //	ether->mbps = 1000;
418 	return 1;
419 }
420 
421 /* LED/USB gpios */
422 enum {
423 	/*
424 	 * the bit assignments are MPP pin numbers from the last page of the
425 	 * sheevaplug 6.0.1 schematic.
426 	 */
427 	KWOEValHigh	= 1<<(49-32),	/* pin 49: LED pin */
428 	KWOEValLow	= 1<<29,	/* pin 29: USB_PWEN, pin 28: usb_pwerr */
429 	KWOELow		= ~0,
430 	KWOEHigh	= ~0,
431 };
432 
433 /* called early in main */
434 void
archreset(void)435 archreset(void)
436 {
437 	ulong clocks;
438 	CpucsReg *cpu;
439 	Dramctl *dram;
440 	GpioReg *gpio;
441 
442 	clockshutdown();		/* watchdog disabled */
443 
444 	/* configure gpios */
445 	gpio = (GpioReg*)soc.gpio[0];
446 	gpio->dataout = KWOEValLow;
447 	coherence();
448 	gpio->dataoutena = KWOELow;
449 
450 	gpio = (GpioReg*)soc.gpio[1];
451 	gpio->dataout = KWOEValHigh;
452 	coherence();
453 	gpio->dataoutena = KWOEHigh;
454 	coherence();
455 
456 	cpu = (CpucsReg *)soc.cpu;
457 	cpu->mempm = 0;			/* turn everything on */
458 	coherence();
459 
460 	clocks = MASK(10);
461 	clocks |= MASK(21) & ~MASK(14);
462 	clocks &= ~(1<<18 | 1<<1);	/* reserved bits */
463 	cpu->clockgate |= clocks;	/* enable all the clocks */
464 	cpu->l2cfg |= L2exists;		/* when L2exists is 0, the l2 ignores us */
465 	coherence();
466 
467 	dram = (Dramctl *)soc.sdramc;
468 	dram->ddrctllo &= ~(1<<6);	/* marvell guideline GL-MEM-70 */
469 
470 	*(ulong *)soc.analog = 0x68;	/* marvell guideline GL-MISC-40 */
471 	coherence();
472 }
473 
474 void
archreboot(void)475 archreboot(void)
476 {
477 	CpucsReg *cpu;
478 
479 	iprint("reset!\n");
480 	delay(10);
481 
482 	cpu = (CpucsReg *)soc.cpu;
483 	cpu->rstout = RstoutSoft;
484 	cpu->softreset = ResetSystem;
485 	coherence();
486 	cpu->cpucsr = Reset;
487 	coherence();
488 	delay(500);
489 
490 	splhi();
491 	iprint("waiting...");
492 	for(;;)
493 		idlehands();
494 }
495 
496 void
archconsole(void)497 archconsole(void)
498 {
499 //	uartconsole(0, "b115200");
500 //serialputs("uart0 console @ 115200\n", strlen("uart0 console @ 115200\n"));
501 }
502 
503 void
archflashwp(Flash *,int)504 archflashwp(Flash*, int)
505 {
506 }
507 
508 int	flashat(Flash *f, uintptr pa);
509 
510 /*
511  * for ../port/devflash.c:/^flashreset
512  * retrieve flash type, virtual base and length and return 0;
513  * return -1 on error (no flash)
514  */
515 int
archflashreset(int bank,Flash * f)516 archflashreset(int bank, Flash *f)
517 {
518 	if(bank != 0)
519 		return -1;
520 	f->type = "nand";
521 	if (flashat(f, PHYSNAND1))
522 		f->addr = (void*)PHYSNAND1;
523 	else if (flashat(f, PHYSNAND2))
524 		f->addr = (void*)PHYSNAND2;
525 	else
526 		f->addr = nil;
527 	f->size = 0;		/* done by probe */
528 	f->width = 1;
529 	f->interleave = 0;
530 	return 0;
531 }
532