brdsetup.c revision 1.16
1/* $NetBSD: brdsetup.c,v 1.16 2011/04/25 18:28:47 phx Exp $ */
2
3/*-
4 * Copyright (c) 2008 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Tohru Nishimura.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32#include <sys/param.h>
33
34#include <powerpc/psl.h>
35#include <powerpc/oea/spr.h>
36
37#include <lib/libsa/stand.h>
38#include <lib/libsa/net.h>
39#include <lib/libkern/libkern.h>
40
41#include <machine/bootinfo.h>
42
43#include "globals.h"
44
45#define BRD_DECL(xxx) \
46    void xxx ## setup(struct brdprop *); \
47    void xxx ## brdfix(struct brdprop *); \
48    void xxx ## pcifix(struct brdprop *); \
49    void xxx ## reset(void)
50
51BRD_DECL(mot);
52BRD_DECL(enc);
53BRD_DECL(kuro);
54BRD_DECL(syno);
55BRD_DECL(qnap);
56BRD_DECL(iomega);
57BRD_DECL(dlink);
58BRD_DECL(nhnas);
59
60static struct brdprop brdlist[] = {
61    {
62	"sandpoint",
63	"Sandpoint X3",
64	BRD_SANDPOINTX3,
65	0,
66	"com", 0x3f8, 115200,
67	motsetup, motbrdfix, motpcifix, NULL },
68    {
69	"encpp1",
70	"EnCore PP1",
71	BRD_ENCOREPP1,
72	0,
73	"com", 0x3f8, 115200,
74	encsetup, encbrdfix, encpcifix, NULL },
75    {
76	"kurobox",
77	"KuroBox",
78	BRD_KUROBOX,
79	32768000,
80	"eumb", 0x4600, 57600,
81	kurosetup, kurobrdfix, NULL, NULL },
82    {
83	"synology",
84	"Synology DS",
85	BRD_SYNOLOGY,
86	33164691,	/* from Synology/Linux source            */
87			/* XXX should be 33165343 for the CS-406 */
88	"eumb", 0x4500, 115200,
89	NULL, synobrdfix, NULL, synoreset },
90    {
91	"qnap",
92	"QNAP TS",
93	BRD_QNAPTS,
94	33164691,	/* Linux source says 33000000, but the Synology  */
95			/* clock value delivers a much better precision. */
96	"eumb", 0x4500, 115200,
97	NULL, qnapbrdfix, NULL, qnapreset },
98    {
99	"iomega",
100	"IOMEGA StorCenter G2",
101	BRD_STORCENTER,
102	0,
103	"eumb", 0x4500, 115200,
104	NULL, iomegabrdfix, NULL, NULL },
105    {
106	"dlink",
107	"D-Link DSM-G600",
108	BRD_DLINKDSM,
109	33000000,
110	"eumb", 0x4500, 9600,
111	NULL, dlinkbrdfix, NULL, NULL },
112    {
113	"nhnas",
114	"Netronics NH230/231",
115	BRD_NH230NAS,
116	0,
117	"eumb", 0x4500, 9600,
118	NULL, nhnasbrdfix, NULL, NULL },
119    {
120	"unknown",
121	"Unknown board",
122	BRD_UNKNOWN,
123	0,
124	"eumb", 0x4500, 115200,
125	NULL, NULL, NULL, NULL }, /* must be the last */
126};
127
128static struct brdprop *brdprop;
129static uint32_t ticks_per_sec, ns_per_tick;
130
131static void brdfixup(void);
132static void setup(void);
133static inline uint32_t mfmsr(void);
134static inline void mtmsr(uint32_t);
135static inline uint32_t cputype(void);
136static inline u_quad_t mftb(void);
137static void init_uart(unsigned, unsigned, uint8_t);
138static void send_sat(char *);
139
140const unsigned dcache_line_size = 32;		/* 32B linesize */
141const unsigned dcache_range_size = 4 * 1024;	/* 16KB / 4-way */
142
143unsigned uart1base;	/* console */
144unsigned uart2base;	/* optional satellite processor */
145#define RBR		0
146#define THR		0
147#define DLB		0
148#define DMB		1
149#define IER		1
150#define FCR		2
151#define LCR		3
152#define  LCR_DLAB	0x80
153#define  LCR_PEVEN	0x18
154#define  LCR_PNONE	0x00
155#define  LCR_8BITS	0x03
156#define MCR		4
157#define  MCR_RTS	0x02
158#define  MCR_DTR	0x01
159#define LSR		5
160#define  LSR_THRE	0x20
161#define  LSR_DRDY	0x01
162#define DCR		0x11
163#define UART_READ(base, r)	*(volatile char *)(base + (r))
164#define UART_WRITE(base, r, v)	*(volatile char *)(base + (r)) = (v)
165
166void brdsetup(void);	/* called by entry.S */
167
168void
169brdsetup(void)
170{
171	static uint8_t pci_to_memclk[] = {
172		30, 30, 10, 10, 20, 10, 10, 10,
173		10, 20, 20, 15, 20, 15, 20, 30,
174		30, 40, 15, 40, 20, 25, 20, 40,
175		25, 20, 10, 20, 15, 15, 20, 00
176	};
177	static uint8_t mem_to_cpuclk[] = {
178		25, 30, 45, 20, 20, 00, 10, 30,
179		30, 20, 45, 30, 25, 35, 30, 35,
180		20, 25, 20, 30, 35, 40, 40, 20,
181		30, 25, 40, 30, 30, 25, 35, 00
182	};
183	char *consname;
184	int consport;
185	uint32_t extclk;
186	unsigned pchb, pcib, dev11, dev13, dev15, dev16, val;
187	extern struct btinfo_memory bi_mem;
188	extern struct btinfo_console bi_cons;
189	extern struct btinfo_clock bi_clk;
190	extern struct btinfo_prodfamily bi_fam;
191
192	/*
193	 * CHRP specification "Map-B" BAT012 layout
194	 *   BAT0 0000-0000 (256MB) SDRAM
195	 *   BAT1 8000-0000 (256MB) PCI mem space
196	 *   BAT2 fc00-0000 (64MB)  EUMB, PCI I/O space, misc devs, flash
197	 *
198	 * EUMBBAR is at fc00-0000.
199	 */
200	pchb = pcimaketag(0, 0, 0);
201	pcicfgwrite(pchb, 0x78, 0xfc000000);
202
203	brdtype = BRD_UNKNOWN;
204	extclk = EXT_CLK_FREQ;	/* usually 33MHz */
205	busclock = 0;
206
207	dev11 = pcimaketag(0, 11, 0);
208	dev13 = pcimaketag(0, 13, 0);
209	dev15 = pcimaketag(0, 15, 0);
210	dev16 = pcimaketag(0, 16, 0);
211
212	if (pcifinddev(0x10ad, 0x0565, &pcib) == 0) {
213		/* WinBond 553 southbridge at dev 11 */
214		brdtype = BRD_SANDPOINTX3;
215	}
216	else if (pcifinddev(0x1106, 0x0686, &pcib) == 0) {
217		/* VIA 686B southbridge at dev 22 */
218		brdtype = BRD_ENCOREPP1;
219	}
220	else if (PCI_CLASS(pcicfgread(dev11, PCI_CLASS_REG)) == PCI_CLASS_ETH) {
221		/* ADMtek AN985 (tlp) or RealTek 8169S (re) at dev 11 */
222		brdtype = BRD_KUROBOX;
223	}
224	else if (PCI_VENDOR(pcicfgread(dev15, PCI_ID_REG)) == 0x11ab) {
225		/* SKnet/Marvell (sk) at dev 15 */
226		brdtype = BRD_SYNOLOGY;
227	}
228	else if (PCI_VENDOR(pcicfgread(dev13, PCI_ID_REG)) == 0x1106) {
229		/* VIA 6410 (viaide) at dev 13 */
230		brdtype = BRD_STORCENTER;
231	}
232	else if (PCI_VENDOR(pcicfgread(dev15, PCI_ID_REG)) == 0x8086
233	    || PCI_VENDOR(pcicfgread(dev15, PCI_ID_REG)) == 0x10ec) {
234		/* Intel (wm) or RealTek (re) at dev 15 */
235		brdtype = BRD_QNAPTS;
236	}
237	else if (PCI_VENDOR(pcicfgread(dev16, PCI_ID_REG)) == 0x1191) {
238		/* ACARD ATP865 (acardide) at dev 16 */
239		brdtype = BRD_DLINKDSM;
240	}
241	else if (PCI_VENDOR(pcicfgread(dev16, PCI_ID_REG)) == 0x1283
242	    || PCI_VENDOR(pcicfgread(dev16, PCI_ID_REG)) == 0x1095) {
243		/* ITE (iteide) or SiI (satalink) at dev 16 */
244		brdtype = BRD_NH230NAS;
245	}
246
247	brdprop = brd_lookup(brdtype);
248
249	/* brd dependent adjustments */
250	setup();
251
252	/* determine clock frequencies */
253	if (brdprop->extclk != 0)
254		extclk = brdprop->extclk;
255	if (busclock == 0) {
256		if (cputype() == MPC8245) {
257			/* PLL_CFG from PCI host bridge register 0xe2 */
258			val = pcicfgread(pchb, 0xe0);
259			busclock = (extclk *
260			    pci_to_memclk[(val >> 19) & 0x1f] + 10) / 10;
261			/* PLLRATIO from HID1 */
262			asm volatile ("mfspr %0,1009" : "=r"(val));
263			cpuclock = ((uint64_t)busclock *
264			    mem_to_cpuclk[val >> 27] + 10) / 10;
265		} else
266			busclock = 100000000;	/* 100MHz bus clock default */
267	}
268	ticks_per_sec = busclock >> 2;
269	ns_per_tick = 1000000000 / ticks_per_sec;
270
271	/* now prepare serial console */
272	consname = brdprop->consname;
273	consport = brdprop->consport;
274	if (strcmp(consname, "eumb") == 0) {
275		uart1base = 0xfc000000 + consport;	/* 0x4500, 0x4600 */
276		UART_WRITE(uart1base, DCR, 0x01);	/* enable DUART mode */
277		uart2base = uart1base ^ 0x0300;
278	} else
279		uart1base = 0xfe000000 + consport;	/* 0x3f8, 0x2f8 */
280
281	/* more brd adjustments */
282	brdfixup();
283
284	bi_mem.memsize = mpc107memsize();
285	snprintf(bi_cons.devname, sizeof(bi_cons.devname), consname);
286	bi_cons.addr = consport;
287	bi_cons.speed = brdprop->consspeed;
288	bi_clk.ticks_per_sec = ticks_per_sec;
289	snprintf(bi_fam.name, sizeof(bi_fam.name), brdprop->family);
290}
291
292struct brdprop *
293brd_lookup(int brd)
294{
295	u_int i;
296
297	for (i = 0; i < sizeof(brdlist)/sizeof(brdlist[0]); i++) {
298		if (brdlist[i].brdtype == brd)
299			return &brdlist[i];
300	}
301	return &brdlist[i - 1];
302}
303
304static void
305setup()
306{
307
308	if (brdprop->setup == NULL)
309		return;
310	(*brdprop->setup)(brdprop);
311}
312
313static void
314brdfixup()
315{
316
317	if (brdprop->brdfix == NULL)
318		return;
319	(*brdprop->brdfix)(brdprop);
320}
321
322void
323pcifixup()
324{
325
326	if (brdprop->pcifix == NULL)
327		return;
328	(*brdprop->pcifix)(brdprop);
329}
330
331void
332encsetup(struct brdprop *brd)
333{
334
335#ifdef COSNAME
336	brd->consname = CONSNAME;
337#endif
338#ifdef CONSPORT
339	brd->consport = CONSPORT;
340#endif
341#ifdef CONSSPEED
342	brd->consspeed = CONSSPEED;
343#endif
344}
345
346void
347encbrdfix(struct brdprop *brd)
348{
349	unsigned ac97, ide, pcib, pmgt, usb12, usb34, val;
350
351/*
352 * VIA82C686B Southbridge
353 *	0.22.0	1106.0686	PCI-ISA bridge
354 *	0.22.1	1106.0571	IDE (viaide)
355 *	0.22.2	1106.3038	USB 0/1 (uhci)
356 *	0.22.3	1106.3038	USB 2/3 (uhci)
357 *	0.22.4	1106.3057	power management
358 *	0.22.5	1106.3058	AC97 (auvia)
359 */
360	pcib  = pcimaketag(0, 22, 0);
361	ide   = pcimaketag(0, 22, 1);
362	usb12 = pcimaketag(0, 22, 2);
363	usb34 = pcimaketag(0, 22, 3);
364	pmgt  = pcimaketag(0, 22, 4);
365	ac97  = pcimaketag(0, 22, 5);
366
367#define	CFG(i,v) do { \
368   *(volatile unsigned char *)(0xfe000000 + 0x3f0) = (i); \
369   *(volatile unsigned char *)(0xfe000000 + 0x3f1) = (v); \
370   } while (0)
371	val = pcicfgread(pcib, 0x84);
372	val |= (02 << 8);
373	pcicfgwrite(pcib, 0x84, val);
374	CFG(0xe2, 0x0f); /* use COM1/2, don't use FDC/LPT */
375	val = pcicfgread(pcib, 0x84);
376	val &= ~(02 << 8);
377	pcicfgwrite(pcib, 0x84, val);
378
379	/* route pin C to i8259 IRQ 5, pin D to 11 */
380	val = pcicfgread(pcib, 0x54);
381	val = (val & 0xff) | 0xb0500000; /* Dx CB Ax xS */
382	pcicfgwrite(pcib, 0x54, val);
383
384	/* enable EISA ELCR1 (0x4d0) and ELCR2 (0x4d1) */
385	val = pcicfgread(pcib, 0x44);
386	val = val | 0x20000000;
387	pcicfgwrite(pcib, 0x44, val);
388
389	/* select level trigger for IRQ 5/11 at ELCR1/2 */
390	*(volatile uint8_t *)0xfe0004d0 = 0x20; /* bit 5 */
391	*(volatile uint8_t *)0xfe0004d1 = 0x08; /* bit 11 */
392
393	/* USB and AC97 are hardwired with pin D and C */
394	val = pcicfgread(usb12, 0x3c) &~ 0xff;
395	val |= 11;
396	pcicfgwrite(usb12, 0x3c, val);
397	val = pcicfgread(usb34, 0x3c) &~ 0xff;
398	val |= 11;
399	pcicfgwrite(usb34, 0x3c, val);
400	val = pcicfgread(ac97, 0x3c) &~ 0xff;
401	val |= 5;
402	pcicfgwrite(ac97, 0x3c, val);
403}
404
405void
406encpcifix(struct brdprop *brd)
407{
408	unsigned ide, irq, net, pcib, steer, val;
409
410#define	STEER(v, b) (((v) & (b)) ? "edge" : "level")
411	pcib = pcimaketag(0, 22, 0);
412	ide  = pcimaketag(0, 22, 1);
413	net  = pcimaketag(0, 25, 0);
414
415	/*
416	 * //// VIA PIRQ ////
417	 * 0x57/56/55/54 - Dx CB Ax xS
418	 */
419	val = pcicfgread(pcib, 0x54);	/* Dx CB Ax xs */
420	steer = val & 0xf;
421	irq = (val >> 12) & 0xf;	/* 15:12 */
422	if (irq) {
423		printf("pin A -> irq %d, %s\n",
424			irq, STEER(steer, 0x1));
425	}
426	irq = (val >> 16) & 0xf;	/* 19:16 */
427	if (irq) {
428		printf("pin B -> irq %d, %s\n",
429			irq, STEER(steer, 0x2));
430	}
431	irq = (val >> 20) & 0xf;	/* 23:20 */
432	if (irq) {
433		printf("pin C -> irq %d, %s\n",
434			irq, STEER(steer, 0x4));
435	}
436	irq = (val >> 28);		/* 31:28 */
437	if (irq) {
438		printf("pin D -> irq %d, %s\n",
439			irq, STEER(steer, 0x8));
440	}
441#if 0
442	/*
443	 * //// IDE fixup ////
444	 * - "native mode" (ide 0x09)
445	 * - use primary only (ide 0x40)
446	 */
447	/* ide: 0x09 - programming interface; 1000'SsPp */
448	val = pcicfgread(ide, 0x08) & 0xffff00ff;
449	pcicfgwrite(ide, 0x08, val | (0x8f << 8));
450
451	/* ide: 0x10-20 - leave them PCI memory space assigned */
452
453	/* ide: 0x40 - use primary only */
454	val = pcicfgread(ide, 0x40) &~ 03;
455	val |= 02;
456	pcicfgwrite(ide, 0x40, val);
457#else
458	/*
459	 * //// IDE fixup ////
460	 * - "compatiblity mode" (ide 0x09)
461	 * - use primary only (ide 0x40)
462	 * - remove PCI pin assignment (ide 0x3d)
463	 */
464	/* ide: 0x09 - programming interface; 1000'SsPp */
465	val = pcicfgread(ide, 0x08) & 0xffff00ff;
466	val |= (0x8a << 8);
467	pcicfgwrite(ide, 0x08, val);
468
469	/* ide: 0x10-20 */
470	/*
471	experiment shows writing ide: 0x09 changes these
472	register behaviour. The pcicfgwrite() above writes
473	0x8a at ide: 0x09 to make sure legacy IDE.  Then
474	reading BAR0-3 is to return value 0s even though
475	pcisetup() has written range assignments.  Value
476	overwrite makes no effect. Having 0x8f for native
477	PCIIDE doesn't change register values and brings no
478	weirdness.
479	 */
480
481	/* ide: 0x40 - use primary only */
482	val = pcicfgread(ide, 0x40) &~ 03;
483	val |= 02;
484	pcicfgwrite(ide, 0x40, val);
485
486		/* ide: 0x3d/3c - turn off PCI pin */
487	val = pcicfgread(ide, 0x3c) & 0xffff00ff;
488	pcicfgwrite(ide, 0x3c, val);
489#endif
490	/*
491	 * //// USBx2, audio, and modem fixup ////
492	 * - disable USB #0 and #1 (pcib 0x48 and 0x85)
493	 * - disable AC97 audio and MC97 modem (pcib 0x85)
494	 */
495
496	/* pcib: 0x48 - disable USB #0 at function 2 */
497	val = pcicfgread(pcib, 0x48);
498	pcicfgwrite(pcib, 0x48, val | 04);
499
500	/* pcib: 0x85 - disable USB #1 at function 3 */
501	/* pcib: 0x85 - disable AC97/MC97 at function 5/6 */
502	val = pcicfgread(pcib, 0x84);
503	pcicfgwrite(pcib, 0x84, val | 0x1c00);
504
505	/*
506	 * //// fxp fixup ////
507	 * - use PCI pin A line 25 (fxp 0x3d/3c)
508	 */
509	/* 0x3d/3c - PCI pin/line */
510	val = pcicfgread(net, 0x3c) & 0xffff0000;
511	val |= (('A' - '@') << 8) | 25;
512	pcicfgwrite(net, 0x3c, val);
513}
514
515void
516motsetup(struct brdprop *brd)
517{
518
519#ifdef COSNAME
520	brd->consname = CONSNAME;
521#endif
522#ifdef CONSPORT
523	brd->consport = CONSPORT;
524#endif
525#ifdef CONSSPEED
526	brd->consspeed = CONSSPEED;
527#endif
528}
529
530void
531motbrdfix(struct brdprop *brd)
532{
533
534/*
535 * WinBond/Symphony Lab 83C553 with PC87308 "SuperIO"
536 *
537 *	0.11.0	10ad.0565	PCI-ISA bridge
538 *	0.11.1	10ad.0105	IDE (slide)
539 */
540}
541
542void
543motpcifix(struct brdprop *brd)
544{
545	unsigned ide, net, pcib, steer, val;
546	int line;
547
548	pcib = pcimaketag(0, 11, 0);
549	ide  = pcimaketag(0, 11, 1);
550	net  = pcimaketag(0, 15, 0);
551
552	/*
553	 * //// WinBond PIRQ ////
554	 * 0x40 - bit 5 (0x20) indicates PIRQ presense
555	 * 0x60 - PIRQ interrupt routing steer
556	 */
557	if (pcicfgread(pcib, 0x40) & 0x20) {
558		steer = pcicfgread(pcib, 0x60);
559		if ((steer & 0x80808080) == 0x80808080)
560			printf("PIRQ[0-3] disabled\n");
561		else {
562			unsigned i, v = steer;
563			for (i = 0; i < 4; i++, v >>= 8) {
564				if ((v & 0x80) != 0 || (v & 0xf) == 0)
565					continue;
566				printf("PIRQ[%d]=%d\n", i, v & 0xf);
567				}
568			}
569		}
570#if 1
571	/*
572	 * //// IDE fixup -- case A ////
573	 * - "native PCI mode" (ide 0x09)
574	 * - don't use ISA IRQ14/15 (pcib 0x43)
575	 * - native IDE for both channels (ide 0x40)
576	 * - LEGIRQ bit 11 steers interrupt to pin C (ide 0x40)
577	 * - sign as PCI pin C line 11 (ide 0x3d/3c)
578	 */
579	/* ide: 0x09 - programming interface; 1000'SsPp */
580	val = pcicfgread(ide, 0x08);
581	val &= 0xffff00ff;
582	pcicfgwrite(ide, 0x08, val | (0x8f << 8));
583
584	/* pcib: 0x43 - IDE interrupt routing */
585	val = pcicfgread(pcib, 0x40) & 0x00ffffff;
586	pcicfgwrite(pcib, 0x40, val);
587
588	/* pcib: 0x45/44 - PCI interrupt routing */
589	val = pcicfgread(pcib, 0x44) & 0xffff0000;
590	pcicfgwrite(pcib, 0x44, val);
591
592	/* ide: 0x41/40 - IDE channel */
593	val = pcicfgread(ide, 0x40) & 0xffff0000;
594	val |= (1 << 11) | 0x33; /* LEGIRQ turns on PCI interrupt */
595	pcicfgwrite(ide, 0x40, val);
596
597	/* ide: 0x3d/3c - use PCI pin C/line 11 */
598	val = pcicfgread(ide, 0x3c) & 0xffffff00;
599	val |= 11; /* pin designation is hardwired to pin A */
600	pcicfgwrite(ide, 0x3c, val);
601#else
602	/*
603	 * //// IDE fixup -- case B ////
604	 * - "compatiblity mode" (ide 0x09)
605	 * - IDE primary/secondary interrupt routing (pcib 0x43)
606	 * - PCI interrupt routing (pcib 0x45/44)
607	 * - no PCI pin/line assignment (ide 0x3d/3c)
608	 */
609	/* ide: 0x09 - programming interface; 1000'SsPp */
610	val = pcicfgread(ide, 0x08);
611	val &= 0xffff00ff;
612	pcicfgwrite(ide, 0x08, val | (0x8a << 8));
613
614	/* pcib: 0x43 - IDE interrupt routing */
615	val = pcicfgread(pcib, 0x40) & 0x00ffffff;
616	pcicfgwrite(pcib, 0x40, val | (0xee << 24));
617
618	/* ide: 0x45/44 - PCI interrupt routing */
619	val = pcicfgread(ide, 0x44) & 0xffff0000;
620	pcicfgwrite(ide, 0x44, val);
621
622	/* ide: 0x3d/3c - turn off PCI pin/line */
623	val = pcicfgread(ide, 0x3c) & 0xffff0000;
624	pcicfgwrite(ide, 0x3c, val);
625#endif
626
627	/*
628	 * //// fxp fixup ////
629	 * - use PCI pin A line 15 (fxp 0x3d/3c)
630	 */
631	val = pcicfgread(net, 0x3c) & 0xffff0000;
632	pcidecomposetag(net, NULL, &line, NULL);
633	val |= (('A' - '@') << 8) | line;
634	pcicfgwrite(net, 0x3c, val);
635}
636
637void
638kurosetup(struct brdprop *brd)
639{
640
641	if (PCI_VENDOR(pcicfgread(pcimaketag(0, 11, 0), PCI_ID_REG)) == 0x10ec)
642		brd->extclk = 32768000; /* decr 2457600Hz */
643	else
644		brd->extclk = 32521333; /* decr 2439100Hz */
645}
646
647void
648kurobrdfix(struct brdprop *brd)
649{
650
651	init_uart(uart2base, 9600, LCR_8BITS | LCR_PEVEN);
652	/* Stop Watchdog */
653	send_sat("AAAAFFFFJJJJ>>>>VVVV>>>>ZZZZVVVVKKKK");
654}
655
656void
657synobrdfix(struct brdprop *brd)
658{
659
660	init_uart(uart2base, 9600, LCR_8BITS | LCR_PNONE);
661	/* beep, power LED on, status LED off */
662	send_sat("247");
663}
664
665void
666synoreset()
667{
668
669	send_sat("C");
670	/*NOTREACHED*/
671}
672
673void
674qnapbrdfix(struct brdprop *brd)
675{
676
677	init_uart(uart2base, 19200, LCR_8BITS | LCR_PNONE);
678	/* beep, status LED red */
679	send_sat("PW");
680}
681
682void
683qnapreset()
684{
685
686	send_sat("f");
687	/*NOTREACHED*/
688}
689
690void
691iomegabrdfix(struct brdprop *brd)
692{
693
694	init_uart(uart2base, 9600, LCR_8BITS | LCR_PNONE);
695	/* illuminate LEDs */
696}
697
698void
699dlinkbrdfix(struct brdprop *brd)
700{
701
702	init_uart(uart2base, 9600, LCR_8BITS | LCR_PNONE);
703	send_sat("SYN\n");
704	send_sat("ZWO\n");	/* power LED solid on */
705}
706
707void
708nhnasbrdfix(struct brdprop *brd)
709{
710
711	/* illuminate LEDs */
712}
713
714void
715_rtt(void)
716{
717	uint32_t msr;
718
719	netif_shutdown_all();
720
721	if (brdprop->reset != NULL)
722		(*brdprop->reset)();
723	else {
724		msr = mfmsr();
725		msr &= ~PSL_EE;
726		mtmsr(msr);
727		asm volatile ("sync; isync");
728		asm volatile("mtspr %0,%1" : : "K"(81), "r"(0));
729		msr &= ~(PSL_ME | PSL_DR | PSL_IR);
730		mtmsr(msr);
731		asm volatile ("sync; isync");
732		run(0, 0, 0, 0, (void *)0xFFF00100); /* reset entry */
733	}
734	/*NOTREACHED*/
735}
736
737satime_t
738getsecs(void)
739{
740	u_quad_t tb = mftb();
741
742	return (tb / ticks_per_sec);
743}
744
745/*
746 * Wait for about n microseconds (at least!).
747 */
748void
749delay(u_int n)
750{
751	u_quad_t tb;
752	u_long scratch, tbh, tbl;
753
754	tb = mftb();
755	tb += (n * 1000 + ns_per_tick - 1) / ns_per_tick;
756	tbh = tb >> 32;
757	tbl = tb;
758	asm volatile ("1: mftbu %0; cmpw %0,%1; blt 1b; bgt 2f; mftb %0; cmpw 0, %0,%2; blt 1b; 2:" : "=&r"(scratch) : "r"(tbh), "r"(tbl));
759}
760
761void
762_wb(uint32_t adr, uint32_t siz)
763{
764	uint32_t bnd;
765
766	asm volatile("eieio");
767	for (bnd = adr + siz; adr < bnd; adr += dcache_line_size)
768		asm volatile ("dcbst 0,%0" :: "r"(adr));
769	asm volatile ("sync");
770}
771
772void
773_wbinv(uint32_t adr, uint32_t siz)
774{
775	uint32_t bnd;
776
777	asm volatile("eieio");
778	for (bnd = adr + siz; adr < bnd; adr += dcache_line_size)
779		asm volatile ("dcbf 0,%0" :: "r"(adr));
780	asm volatile ("sync");
781}
782
783void
784_inv(uint32_t adr, uint32_t siz)
785{
786	uint32_t bnd, off;
787
788	off = adr & (dcache_line_size - 1);
789	adr -= off;
790	siz += off;
791	asm volatile ("eieio");
792	if (off != 0) {
793		/* wbinv() leading unaligned dcache line */
794		asm volatile ("dcbf 0,%0" :: "r"(adr));
795		if (siz < dcache_line_size)
796			goto done;
797		adr += dcache_line_size;
798		siz -= dcache_line_size;
799	}
800	bnd = adr + siz;
801	off = bnd & (dcache_line_size - 1);
802	if (off != 0) {
803		/* wbinv() trailing unaligned dcache line */
804		asm volatile ("dcbf 0,%0" :: "r"(bnd)); /* it's OK */
805		if (siz < dcache_line_size)
806			goto done;
807		siz -= off;
808	}
809	for (bnd = adr + siz; adr < bnd; adr += dcache_line_size) {
810		/* inv() intermediate dcache lines if ever */
811		asm volatile ("dcbi 0,%0" :: "r"(adr));
812	}
813  done:
814	asm volatile ("sync");
815}
816
817static inline uint32_t
818mfmsr(void)
819{
820	uint32_t msr;
821
822	asm volatile ("mfmsr %0" : "=r"(msr));
823	return msr;
824}
825
826static inline void
827mtmsr(uint32_t msr)
828{
829	asm volatile ("mtmsr %0" : : "r"(msr));
830}
831
832static inline uint32_t
833cputype(void)
834{
835	uint32_t pvr;
836
837	asm volatile ("mfpvr %0" : "=r"(pvr));
838	return pvr >> 16;
839}
840
841static inline u_quad_t
842mftb(void)
843{
844	u_long scratch;
845	u_quad_t tb;
846
847	asm ("1: mftbu %0; mftb %0+1; mftbu %1; cmpw %0,%1; bne 1b"
848	    : "=r"(tb), "=r"(scratch));
849	return tb;
850}
851
852static void
853init_uart(unsigned base, unsigned speed, uint8_t lcr)
854{
855	unsigned div;
856
857	div = busclock / speed / 16;
858	UART_WRITE(base, LCR, 0x80);		/* turn on DLAB bit */
859	UART_WRITE(base, FCR, 0x00);
860	UART_WRITE(base, DMB, div >> 8);	/* set speed */
861	UART_WRITE(base, DLB, div & 0xff);
862	UART_WRITE(base, LCR, lcr);
863	UART_WRITE(base, FCR, 0x07);		/* FIFO on, TXRX FIFO reset */
864	UART_WRITE(base, IER, 0x00);		/* make sure INT disabled */
865}
866
867/* talk to satellite processor */
868static void
869send_sat(char *msg)
870{
871	unsigned savedbase;
872
873	savedbase = uart1base;
874	uart1base = uart2base;
875	while (*msg)
876		putchar(*msg++);
877	uart1base = savedbase;
878}
879
880void
881putchar(int c)
882{
883	unsigned timo, lsr;
884
885	if (c == '\n')
886		putchar('\r');
887
888	timo = 0x00100000;
889	do {
890		lsr = UART_READ(uart1base, LSR);
891	} while (timo-- > 0 && (lsr & LSR_THRE) == 0);
892	if (timo > 0)
893		UART_WRITE(uart1base, THR, c);
894}
895
896int
897getchar(void)
898{
899	unsigned lsr;
900
901	do {
902		lsr = UART_READ(uart1base, LSR);
903	} while ((lsr & LSR_DRDY) == 0);
904	return UART_READ(uart1base, RBR);
905}
906
907int
908tstchar(void)
909{
910	return (UART_READ(uart1base, LSR) & LSR_DRDY) != 0;
911}
912
913unsigned
914mpc107memsize()
915{
916	unsigned bankn, end, n, tag, val;
917
918	tag = pcimaketag(0, 0, 0);
919
920	if (brdtype == BRD_ENCOREPP1) {
921		/* the brd's PPCBOOT looks to have erroneous values */
922		unsigned tbl[] = {
923#define MPC106_MEMSTARTADDR1	0x80
924#define MPC106_EXTMEMSTARTADDR1	0x88
925#define MPC106_MEMENDADDR1	0x90
926#define MPC106_EXTMEMENDADDR1	0x98
927#define MPC106_MEMEN		0xa0
928#define	BK0_S	0x00000000
929#define	BK0_E	(128 << 20) - 1
930#define BK1_S	0x3ff00000
931#define BK1_E	0x3fffffff
932#define BK2_S	0x3ff00000
933#define BK2_E	0x3fffffff
934#define BK3_S	0x3ff00000
935#define BK3_E	0x3fffffff
936#define AR(v, s) ((((v) & SAR_MASK) >> SAR_SHIFT) << (s))
937#define XR(v, s) ((((v) & EAR_MASK) >> EAR_SHIFT) << (s))
938#define SAR_MASK 0x0ff00000
939#define SAR_SHIFT    20
940#define EAR_MASK 0x30000000
941#define EAR_SHIFT    28
942		AR(BK0_S, 0) | AR(BK1_S, 8) | AR(BK2_S, 16) | AR(BK3_S, 24),
943		XR(BK0_S, 0) | XR(BK1_S, 8) | XR(BK2_S, 16) | XR(BK3_S, 24),
944		AR(BK0_E, 0) | AR(BK1_E, 8) | AR(BK2_E, 16) | AR(BK3_E, 24),
945		XR(BK0_E, 0) | XR(BK1_E, 8) | XR(BK2_E, 16) | XR(BK3_E, 24),
946		};
947		tag = pcimaketag(0, 0, 0);
948		pcicfgwrite(tag, MPC106_MEMSTARTADDR1, tbl[0]);
949		pcicfgwrite(tag, MPC106_EXTMEMSTARTADDR1, tbl[1]);
950		pcicfgwrite(tag, MPC106_MEMENDADDR1, tbl[2]);
951		pcicfgwrite(tag, MPC106_EXTMEMENDADDR1,	tbl[3]);
952		pcicfgwrite(tag, MPC106_MEMEN, 1);
953	}
954
955	bankn = 0;
956	val = pcicfgread(tag, MPC106_MEMEN);
957	for (n = 0; n < 4; n++) {
958		if ((val & (1U << n)) == 0)
959			break;
960		bankn = n;
961	}
962	bankn = bankn * 8;
963
964	val = pcicfgread(tag, MPC106_EXTMEMENDADDR1);
965	end =  ((val >> bankn) & 0x03) << 28;
966	val = pcicfgread(tag, MPC106_MEMENDADDR1);
967	end |= ((val >> bankn) & 0xff) << 20;
968	end |= 0xfffff;
969
970	return (end + 1); /* assume the end address matches total amount */
971}
972
973struct fis_dir_entry {
974	char		name[16];
975	uint32_t	startaddr;
976	uint32_t	loadaddr;
977	uint32_t	flashsize;
978	uint32_t	entryaddr;
979	uint32_t	filesize;
980	char		pad[256 - (16 + 5 * sizeof(uint32_t))];
981};
982
983#define FIS_LOWER_LIMIT	0xfff00000
984
985/*
986 * Look for a Redboot-style Flash Image System FIS-directory and
987 * return a pointer to the start address of the requested file.
988 */
989static void *
990redboot_fis_lookup(const char *filename)
991{
992	static const char FISdirname[16] = {
993	    'F', 'I', 'S', ' ',
994	    'd', 'i', 'r', 'e', 'c', 't', 'o', 'r', 'y', 0, 0, 0
995	};
996	struct fis_dir_entry *dir;
997
998	/*
999	 * The FIS directory is usually in the last sector of the flash.
1000	 * But we do not know the sector size (erase size), so start
1001	 * at 0xffffff00 and scan backwards in steps of the FIS directory
1002	 * entry size (0x100).
1003	 */
1004	for (dir = (struct fis_dir_entry *)0xffffff00;
1005	    (uint32_t)dir >= FIS_LOWER_LIMIT; dir--)
1006		if (memcmp(dir->name, FISdirname, sizeof(FISdirname)) == 0)
1007			break;
1008	if ((uint32_t)dir < FIS_LOWER_LIMIT) {
1009		printf("No FIS directory found!\n");
1010		return NULL;
1011	}
1012
1013	/* Now find filename by scanning the directory from beginning. */
1014	dir = (struct fis_dir_entry *)dir->startaddr;
1015	while (dir->name[0] != 0xff && (uint32_t)dir < 0xffffff00) {
1016		if (strcmp(dir->name, filename) == 0)
1017			return (void *)dir->startaddr;	/* found */
1018		dir++;
1019	}
1020	printf("\"%s\" not found in FIS directory!\n", filename);
1021	return NULL;
1022}
1023
1024static void
1025read_mac_string(uint8_t *mac, char *p)
1026{
1027	int i;
1028
1029	for (i = 0; i < 6; i++, p += 3)
1030		*mac++ = read_hex(p);
1031}
1032
1033/*
1034 * For cost saving reasons some NAS boxes lack SEEPROM for NIC's
1035 * ethernet address and keep it in their Flash memory instead.
1036 */
1037void
1038read_mac_from_flash(uint8_t *mac)
1039{
1040	uint8_t *p;
1041
1042	switch (brdtype) {
1043	case BRD_SYNOLOGY:
1044		p = redboot_fis_lookup("vendor");
1045		if (p == NULL)
1046			break;
1047		memcpy(mac, p, 6);
1048		return;
1049	case BRD_DLINKDSM:
1050		read_mac_string(mac, (char *)0xfff0ff80);
1051		return;
1052	default:
1053		printf("Warning: This board has no known method defined "
1054		    "to determine its MAC address!\n");
1055		break;
1056	}
1057
1058	/* set to 00:00:00:00:00:00 in case of error */
1059	memset(mac, 0, 6);
1060}
1061