xref: /inferno-os/os/cerf405/main.c (revision 74a4d8c26dd3c1e9febcb717cfd6cb6512991a7a)
1 #include	"u.h"
2 #include	"../port/lib.h"
3 #include	"mem.h"
4 #include	"dat.h"
5 #include	"fns.h"
6 #include	"io.h"
7 #include	"ureg.h"
8 #include	"../ip/ip.h"
9 #include "version.h"
10 
11 #define	MAXCONF		32
12 
13 extern ulong kerndate;
14 extern int cflag;
15 int	remotedebug;
16 
17 extern int main_pool_pcnt;
18 extern int heap_pool_pcnt;
19 extern int image_pool_pcnt;
20 
21 char *confname[MAXCONF];
22 char *confval[MAXCONF];
23 int nconf;
24 
25 void addconf(char *, char *);
26 void	eepromscan(void);
27 
28 static void
options(void)29 options(void)
30 {
31 //	nconf = archconfval(confname, confval, sizeof(confname));
32 }
33 
34 void
doc(char * m)35 doc(char *m)
36 {
37 	USED(m);
38 	iprint("%s...\n", m);
39 }
40 
41 void
idoc(char * m)42 idoc(char *m)
43 {
44 	uartputs(m, strlen(m));
45 }
46 
47 static void
poolsizeinit(void)48 poolsizeinit(void)
49 {
50 	ulong nb;
51 
52 	nb = conf.npage*BY2PG;
53 	poolsize(mainmem, (nb*main_pool_pcnt)/100, 0);
54 	poolsize(heapmem, (nb*heap_pool_pcnt)/100, 0);
55 	poolsize(imagmem, (nb*image_pool_pcnt)/100, 1);
56 }
57 
58 static void
serialconsole(void)59 serialconsole(void)
60 {
61 	char *p;
62 	int port, baud;
63 
64 	p = getconf("console");
65 	if(p == nil)
66 		p = "0";
67 	if(p != nil && !remotedebug){
68 		port = strtol(p, nil, 0);
69 		baud = 115200;
70 		p = getconf("baud");
71 		if(p != nil){
72 			baud = strtol(p, nil, 0);
73 			if(baud < 9600)
74 				baud = 9600;
75 		}
76 		uartspecial(port, baud, &kbdq, &printq, kbdcr2nl);
77 	}
78 }
79 
80 void
main(void)81 main(void)
82 {
83 	idoc("machinit...\n");
84 	machinit();
85 	idoc("options...\n");
86 	compiledcr();
87 	options();
88 //	archinit();
89 	quotefmtinstall();
90 	idoc("confinit...\n");
91 	confinit();
92 	xinit();
93 	poolsizeinit();
94 	poolinit();
95 	idoc("trapinit...\n");
96 	trapinit();
97 	mmuinit();
98 	ioinit();
99 	printinit();
100 	uartinstall();
101 	serialconsole();
102 	pcimapinit();
103 	eepromscan();
104 	doc("clockinit");
105 	clockinit();
106 	doc("procinit");
107 	procinit();
108 	cpuidprint();
109 	doc("links");
110 	links();
111 	doc("chandevreset");
112 	chandevreset();
113 
114 	eve = strdup("inferno");
115 
116 	print("\nInferno %s\n", VERSION);
117 	print("Vita Nuova\n");
118 	print("conf %s (%lud) jit %d\n\n",conffile, kerndate, cflag);
119 
120 	doc("userinit");
121 	userinit();
122 	doc("schedinit");
123 	schedinit();
124 }
125 
126 //ccdv=1 cbdv=2 opdv=2 epdv=3 mpdv=1 ppdv=2
127 
128 void
machinit(void)129 machinit(void)
130 {
131 	int n;
132 
133 	n = m->machno;
134 	memset(m, 0, sizeof(Mach));
135 	m->machno = n;
136 	m->mmask = 1<<m->machno;
137 	m->cputype = getpvr()>>16;
138 	m->delayloop = 20000;	/* initial estimate only; set by clockinit */
139 	m->speed = 266;	/* initial estimate only; set by archinit */
140 	m->cpuhz = 266333333;
141 	m->vcohz = 799000000;
142 	m->pllhz = 266333333;
143 	m->plbhz = 133166666;
144 	m->opbhz = 66600000;
145 	m->epbhz = 44*MHz;
146 	m->pcihz = 66600000;
147 	m->clockgen = m->cpuhz;	/* it's the internal cpu clock */
148 }
149 
150 void
init0(void)151 init0(void)
152 {
153 	Osenv *o;
154 	int i;
155 	char buf[2*KNAMELEN];
156 
157 	up->nerrlab = 0;
158 
159 	spllo();
160 
161 	if(waserror())
162 		panic("init0");
163 	/*
164 	 * These are o.k. because rootinit is null.
165 	 * Then early kproc's will have a root and dot.
166 	 */
167 	o = up->env;
168 	o->pgrp->slash = namec("#/", Atodir, 0, 0);
169 	cnameclose(o->pgrp->slash->name);
170 	o->pgrp->slash->name = newcname("/");
171 	o->pgrp->dot = cclone(o->pgrp->slash);
172 
173 	chandevinit();
174 
175 	if(!waserror()){
176 		ksetenv("cputype", "power", 0);
177 		snprint(buf, sizeof(buf), "power %s", conffile);
178 		ksetenv("terminal", buf, 0);
179 		poperror();
180 	}
181 	for(i = 0; i < nconf; i++)
182 		if(confname[i][0] != '*'){
183 			if(!waserror()){
184 				ksetenv(confname[i], confval[i], 0);
185 				poperror();
186 			}
187 		}
188 
189 	poperror();
190 	disinit("/osinit.dis");
191 }
192 
193 void
userinit(void)194 userinit(void)
195 {
196 	Proc *p;
197 	Osenv *o;
198 
199 	p = newproc();
200 	o = p->env;
201 
202 	o->fgrp = newfgrp(nil);
203 	o->pgrp = newpgrp();
204 	o->egrp = newegrp();
205 	kstrdup(&o->user, eve);
206 
207 	strcpy(p->text, "interp");
208 
209 	/*
210 	 * Kernel Stack
211 	 */
212 	p->sched.pc = (ulong)init0;
213 	p->sched.sp = (ulong)p->kstack+KSTACK;
214 
215 	ready(p);
216 }
217 
218 Conf	conf;
219 
220 void
addconf(char * name,char * val)221 addconf(char *name, char *val)
222 {
223 	if(nconf >= MAXCONF)
224 		return;
225 	confname[nconf] = name;
226 	confval[nconf] = val;
227 	nconf++;
228 }
229 
230 char*
getconf(char * name)231 getconf(char *name)
232 {
233 	int i;
234 
235 	for(i = 0; i < nconf; i++)
236 		if(cistrcmp(confname[i], name) == 0)
237 			return confval[i];
238 	return 0;
239 }
240 
241 void
confinit(void)242 confinit(void)
243 {
244 	char *p;
245 	int pcnt;
246 
247 
248 	if(p = getconf("*kernelpercent"))
249 		pcnt = 100 - strtol(p, 0, 0);
250 	else
251 		pcnt = 0;
252 
253 	archconfinit();
254 
255 	conf.npage = conf.npage0 + conf.npage1;
256 	if(pcnt < 10)
257 		pcnt = 70;
258 	conf.ialloc = (((conf.npage*(100-pcnt))/100)/2)*BY2PG;
259 
260 	conf.nproc = 100 + ((conf.npage*BY2PG)/MB)*5;
261 	conf.nmach = MAXMACH;
262 
263 }
264 
265 static void
twinkle(void)266 twinkle(void)
267 {
268 	if(m->ticks%MS2TK(1000) == 0)
269 		((Gpioregs*)PHYSGPIO)->or ^= 1<<31;
270 }
271 
272 void (*archclocktick)(void) = twinkle;
273 
274 void
exit(int ispanic)275 exit(int ispanic)
276 {
277 	up = 0;
278 	spllo();
279 	print("cpu %d exiting\n", m->machno);
280 
281 	/* Shutdown running devices */
282 	chandevshutdown();
283 
284 	delay(1000);
285 	splhi();
286 	if(ispanic)
287 		for(;;);
288 	archreboot();
289 }
290 
291 void
reboot(void)292 reboot(void)
293 {
294 	exit(0);
295 }
296 
297 void
halt(void)298 halt(void)
299 {
300 	print("cpu halted\n");
301 	microdelay(1000);
302 	for(;;)
303 		;
304 }
305 
306 /*
307  * kept in case it's needed for PCI/ISA devices
308  */
309 int
isaconfig(char * class,int ctlrno,ISAConf * isa)310 isaconfig(char *class, int ctlrno, ISAConf *isa)
311 {
312 	char cc[KNAMELEN], *p;
313 	int i;
314 
315 	snprint(cc, sizeof cc, "%s%d", class, ctlrno);
316 	p = getconf(cc);
317 	if(p == nil)
318 		return 0;
319 
320 	isa->nopt = tokenize(p, isa->opt, NISAOPT);
321 	for(i = 0; i < isa->nopt; i++){
322 		p = isa->opt[i];
323 		if(cistrncmp(p, "type=", 5) == 0)
324 			isa->type = p + 5;
325 		else if(cistrncmp(p, "port=", 5) == 0)
326 			isa->port = strtoul(p+5, &p, 0);
327 		else if(cistrncmp(p, "irq=", 4) == 0)
328 			isa->irq = strtoul(p+4, &p, 0);
329 		else if(cistrncmp(p, "mem=", 4) == 0)
330 			isa->mem = strtoul(p+4, &p, 0);
331 		else if(cistrncmp(p, "size=", 5) == 0)
332 			isa->size = strtoul(p+5, &p, 0);
333 		else if(cistrncmp(p, "freq=", 5) == 0)
334 			isa->freq = strtoul(p+5, &p, 0);
335 		else if(cistrncmp(p, "dma=", 4) == 0)
336 			isa->dma = strtoul(p+4, &p, 0);
337 	}
338 	return 1;
339 }
340 
341 /*
342  *  Save the mach dependent part of the process state.
343  */
344 void
procsave(Proc *)345 procsave(Proc*)
346 {
347 }
348 
349 void
idlehands(void)350 idlehands(void)
351 {
352 	putmsr(getmsr() | MSR_WE | MSR_EE | MSR_CE);	/* MSR_DE as well? */
353 }
354 
355 /* stubs */
356 void
setfsr(ulong)357 setfsr(ulong)
358 {
359 }
360 
361 ulong
getfsr()362 getfsr()
363 {
364 	return 0;
365 }
366 
367 void
setfcr(ulong)368 setfcr(ulong)
369 {
370 }
371 
372 ulong
getfcr()373 getfcr()
374 {
375 	return 0;
376 }
377 
378 /*
379  * some of this is possibly ice-cube specific
380  */
381 
382 enum {
383 	Cpc0Pllmr0=	0xF0,	/* PLL mode register 0 */
384 	Cpc0Boot=	0xF1,	/* clock status */
385 	Cpc0Pllmr1=	0xF4,	/* PLL mode register 1 */
386 	Cpc0Srr=		0xF6,	/* PCI soft reset */
387 	Cpc0PCI=		0xF9,	/* PCI control */
388 };
389 /*
390 00f0 = 00011101
391 00f1 = 00000025
392 00f2 = 00000000
393 00f3 = 00000000
394 00f4 = 8085523e
395 00f5 = 00000017
396 00f6 = 00000000
397 ccdv=1 cbdv=2 opdv=2 epdv=3 mpdv=1 ppdv=2
398 fbmul=8 fwdva=5 fwdvb=5 tun=257 m=40
399 */
400 void
archconfinit(void)401 archconfinit(void)
402 {
403 	ulong ktop;
404 
405 	conf.npage0 = (32*1024*1024)/BY2PG;
406 	conf.base0 = 0;
407 	ktop = PGROUND((ulong)end);
408 	ktop = PADDR(ktop) - conf.base0;
409 	conf.npage0 -= ktop/BY2PG;
410 	conf.base0 += ktop;
411 
412 	{int i; for(i=0xF0; i<=0xF6; i++){iprint("%.4ux = %.8lux\n", i, getdcr(i));}}
413 	{
414 		int ccdv, cbdv, opdv, epdv, mpdv, ppdv;
415 		int fbmul, fwdva, fwdvb, tun;
416 		ulong mr0, mr1;
417 
418 		mr0 = getdcr(Cpc0Pllmr0);
419 		ccdv = ((mr0>>20)&3)+1;
420 		cbdv = ((mr0>>16)&3)+1;
421 		opdv = ((mr0>>12)&3)+1;
422 		epdv = ((mr0>>8)&3)+2;
423 		mpdv = ((mr0>>4)&3)+1;
424 		ppdv = (mr0&3)+1;
425 		iprint("ccdv=%d cbdv=%d opdv=%d epdv=%d mpdv=%d ppdv=%d\n",
426 			ccdv, cbdv, opdv, epdv, mpdv, ppdv);
427 		mr1 = getdcr(Cpc0Pllmr1);
428 		fbmul = (mr1>>20) & 0xF;
429 		if(fbmul == 0)
430 			fbmul = 16;
431 		fwdva = (mr1>>16) & 7;
432 		if(fwdva == 0)
433 			fwdva = 8;
434 		fwdvb = (mr1>>12) & 7;
435 		if(fwdvb == 0)
436 			fwdvb = 8;
437 		tun = mr0 & 0x3FF;
438 		iprint("fbmul=%d fwdva=%d fwdvb=%d tun=%d m=%d\n",
439 			fbmul, fwdva, fwdvb, tun, fbmul*fwdva);
440 	}
441 }
442 
443 void
archreboot(void)444 archreboot(void)
445 {
446 	putevpr(~0);
447 	firmware(0);
448 	for(;;);
449 }
450 
451 void
clockcheck(void)452 clockcheck(void)
453 {
454 }
455 
456 void
cpuidprint(void)457 cpuidprint(void)
458 {
459 	iprint("PowerPC 405EP pvr=%8.8lux\n", getpvr());
460 	/* TO DO */
461 }
462 
463 #include	"../port/flashif.h"
464 
465 /*
466  * for devflash.c:/^flashreset
467  * retrieve flash type, virtual base and length and return 0;
468  * return -1 on error (no flash)
469  */
470 int
archflashreset(int bank,Flash * f)471 archflashreset(int bank, Flash *f)
472 {
473 	switch(bank){
474 	case 0:
475 		f->type = "AMD29F0x0";	/* not right, but will do for now */
476 		f->addr = (void*)PHYSFLASH;
477 		f->size = FLASHSIZE;
478 		f->width = 2;
479 		return 0;
480 	case 1:
481 		f->type = "nand";
482 		f->addr = (void*)PHYSNAND;
483 		f->size = 0;	/* done by probe */
484 		f->width = 1;
485 		return 0;
486 	default:
487 		return -1;
488 	}
489 }
490 
491 void
archflashwp(Flash *,int)492 archflashwp(Flash*, int)
493 {
494 }
495 
496 #include "../port/netif.h"
497 #include "etherif.h"
498 
499 enum {
500 	/* EMAC-PHY control, tucked away in CPC0 */
501 	Cpc0Epctl=	0xF3,	/* EMAC-PHY ctl */
502 
503 	E0Nf=	1<<31,	/* Emac0 noise filter enable */
504 	E1Nf=	1<<30,	/* Emac1 noise filter enable */
505 	E1pr=	1<<7,	/* Emac1 packet reject is active high */
506 	E0pr=	1<<6,	/* Emac 0 packet reject is active high */
507 	E1rm=	1<<5,	/* enable Emac 1 packet removal */
508 	E0rm=	1<<4,	/* enable Emac 0 packet removal */
509 	E1pci=	1<<1,	/* Emac 1 clock source is Tx clock output (loopback) */
510 	E0pci=	1<<0,	/* Emac 0 clock source is Tx clock output (loopback) */
511 };
512 
513 int
archether(int ctlno,Ether * ether)514 archether(int ctlno, Ether *ether)
515 {
516 	char name[KNAMELEN], *p;
517 	int s;
518 
519 	if(ctlno > 1)
520 		return -1;
521 	ether->type = "EMAC";
522 	ether->port = ctlno;
523 	if(ctlno != 0)
524 		snprint(name, sizeof(name), "eth%daddr", ctlno);
525 	else
526 		strcpy(name, "ethaddr");
527 	p = getconf(name);
528 	if(p == 0){
529 		iprint("ether%d: no %s in EEPROM env\n", ctlno, name);
530 		return -1;
531 	}
532 	parsemac(ether->ea, p, Eaddrlen);
533 	s = splhi();
534 	putdcr(Cpc0Epctl, getdcr(Cpc0Epctl) | (ctlno?E1Nf:E0Nf));
535 	splx(s);
536 	return 1;
537 }
538 
539 enum {
540 	/* UART control */
541 	Cpc0Ucr=		0xF5,	/* UART control register */
542 
543 	U0Dc=		1<<21,	/* UART0 DMA clear enable */
544 	U0Dt=		1<<20,	/* enable UART0 DMA transmit channel */
545 	U0Dr=		1<<19,	/* enable UART0 DMA receive channel */
546 	U1Dc=		1<<18,	/* UART1 DMA clear enable */
547 	U1Dt=		1<<17,	/* enable UART1 DMA transmit channel */
548 	U1Dr=		1<<16,	/* enable UART1 DMA receive channel */
549 	U1Div_s=		8,		/* UART1 serial clock divisor (shift) */
550 	U1Stop=		1<<8,
551 	U0Div_s=		0,		/* UART0 serial clock divisor (shift) */
552 	U0Stop=		1<<0,
553 	UDiv_m=		0x7F,	/* UARTx divisor mask */
554 };
555 
556 static ulong
findserialclock(int rate,ulong * freq)557 findserialclock(int rate, ulong *freq)
558 {
559 	ulong d, b;
560 	ulong serialclock;
561 	int actual, e, beste, bestd;
562 
563 	*freq = 0;
564 	if(rate == 0)
565 		return 0;
566 	d = ((m->pllhz+m->opbhz-1)/m->opbhz)*2;	/* double to allow for later rounding */
567 	beste = 0;
568 	bestd = -1;
569 	for(; d<=128; d++){
570 		serialclock = (2*m->pllhz)/d;
571 		b = ((serialclock+8*rate-1)/(rate*16))>>1;
572 		actual = ((serialclock+8*b-1)/(b*16))>>1;
573 		e = rate-actual;
574 		if(e < 0)
575 			e = -e;
576 		if(bestd < 0 || e < beste || e == beste && (bestd&1) && (d&1)==0){
577 			beste = e;
578 			bestd = d;
579 		}
580 	}
581 	if(bestd > 0)
582 		*freq = m->pllhz/bestd;
583 	return bestd;
584 }
585 
586 /*
587  * return a value for UARTn's baud rate generator, and
588  * set a corresponding divsor in the UARTn clock generator
589  * (between 2 and 128)
590  */
591 ulong
archuartclock(int n,int rate)592 archuartclock(int n, int rate)
593 {
594 	int d, s;
595 	ulong m, freq;
596 
597 	d = findserialclock(rate, &freq);
598 	if(d <= 0)
599 		d = U0Stop;
600 	m = UDiv_m;
601 	if(n){
602 		d <<= U1Div_s;
603 		m <<= U1Div_s;
604 	}
605 	s = splhi();
606 	putdcr(Cpc0Ucr, (getdcr(Cpc0Ucr) & ~m) | d);
607 	splx(s);
608 	return freq;
609 }
610 
611 void
archuartdma(int n,int on)612 archuartdma(int n, int on)
613 {
614 	ulong r;
615 	int s;
616 
617 	r = n? (U1Dc|U1Dt|U1Dr): (U0Dc|U0Dt|U0Dr);
618 	if(on){
619 		s = splhi();
620 		putdcr(Cpc0Ucr, getdcr(Cpc0Ucr) | r);
621 		splx(s);
622 	}else{
623 		s = splhi();
624 		putdcr(Cpc0Ucr, getdcr(Cpc0Ucr) & ~r);
625 		splx(s);
626 	}
627 }
628 
629 /*
630  * boot environment in eeprom
631  */
632 
633 enum {
634 	EEpromHdr=	8,	/* bytes */
635 	Envsize=	0x400,
636 };
637 
638 static I2Cdev eedev;
639 static struct {
640 	uchar	buf[Envsize];
641 	int	size;
642 } bootenv;
643 
644 static int
eepromitem(uchar * buf,int lim,ulong * off)645 eepromitem(uchar *buf, int lim, ulong *off)
646 {
647 	int l;
648 	uchar b;
649 
650 	if(i2crecv(&eedev, &b, 1, (*off)++) != 1)
651 		return -1;
652 	l = b;
653 	if(l & 0x80){
654 		if(i2crecv(&eedev, &b, 1, (*off)++) != 1)
655 			return -1;
656 		l = ((l & 0x7F)<<8) | b;
657 	}
658 	if(buf == nil)
659 		return l;
660 	if(l > lim)
661 		l = lim;
662 	return i2crecv(&eedev, buf, l, *off);
663 }
664 
665 void
eepromscan(void)666 eepromscan(void)
667 {
668 	int n, l;
669 	ulong off;
670 	uchar buf[2];
671 	char *p, *ep, *v;
672 
673 	eedev.addr = 0x50;
674 	eedev.salen = 2;
675 	i2csetup(1);
676 	n = i2crecv(&eedev, buf, sizeof(buf), 0);
677 	if(n <= 0){
678 		iprint("eepromscan: %d\n", n);
679 		return;
680 	}
681 	if(buf[0] != 0xEF || buf[1] != 0xBE){
682 		iprint("eeprom invalid\n");
683 		return;
684 	}
685 	bootenv.size = 0;
686 	for(off = EEpromHdr; off < 16384;){
687 		l = eepromitem(bootenv.buf, sizeof(bootenv.buf), &off);	/* key */
688 		if(l <= 0)
689 			break;
690 		off += l;
691 		if(l == 7 && memcmp(bootenv.buf, "PPCBOOT", 7) == 0){	/* intrinsyc key */
692 			bootenv.size = eepromitem(bootenv.buf, sizeof(bootenv.buf), &off);
693 			break;
694 		}
695 		l = eepromitem(nil, 0, &off);	/* skip value */
696 		if(l < 0)
697 			break;
698 		off += l+2;	/* 2 byte crc */
699 	}
700 	p = (char*)bootenv.buf+4;	/* skip crc */
701 	ep = p+bootenv.size;
702 	for(; p < ep && *p; p += l){
703 		l = strlen(p)+1;
704 		v = strchr(p, '=');
705 		if(v != nil)
706 			*v++ = 0;
707 		else
708 			v = "";
709 		addconf(p, v);
710 		if(0)
711 			iprint("%q = %q\n", p, v);
712 	}
713 }
714 
715 ulong
logfsnow(void)716 logfsnow(void)
717 {
718 	return rtctime();
719 }
720