brdsetup.c revision 1.22
1/* $NetBSD: brdsetup.c,v 1.22 2011/11/07 21:11:55 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, iomegareset },
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
128/* Iomega StorCenter MC68HC908 microcontroller data packet */
129#define IOMEGA_POWER		0
130#define IOMEGA_LED		1
131#define IOMEGA_FLASH_RATE	2
132#define IOMEGA_FAN		3
133#define IOMEGA_HIGH_TEMP	4
134#define IOMEGA_LOW_TEMP		5
135#define IOMEGA_ID		6
136#define IOMEGA_CHECKSUM		7
137#define IOMEGA_PACKETSIZE	8
138
139static struct brdprop *brdprop;
140static uint32_t ticks_per_sec, ns_per_tick;
141
142static void brdfixup(void);
143static void setup(void);
144static int send_iomega(int, int, int, int, int, int);
145static inline uint32_t mfmsr(void);
146static inline void mtmsr(uint32_t);
147static inline uint32_t cputype(void);
148static inline u_quad_t mftb(void);
149static void init_uart(unsigned, unsigned, uint8_t);
150static void send_sat(char *);
151
152const unsigned dcache_line_size = 32;		/* 32B linesize */
153const unsigned dcache_range_size = 4 * 1024;	/* 16KB / 4-way */
154
155unsigned uart1base;	/* console */
156unsigned uart2base;	/* optional satellite processor */
157#define RBR		0
158#define THR		0
159#define DLB		0
160#define DMB		1
161#define IER		1
162#define FCR		2
163#define LCR		3
164#define  LCR_DLAB	0x80
165#define  LCR_PEVEN	0x18
166#define  LCR_PNONE	0x00
167#define  LCR_8BITS	0x03
168#define MCR		4
169#define  MCR_RTS	0x02
170#define  MCR_DTR	0x01
171#define LSR		5
172#define  LSR_THRE	0x20
173#define  LSR_DRDY	0x01
174#define DCR		0x11
175#define UART_READ(base, r)	in8(base + (r))
176#define UART_WRITE(base, r, v)	out8(base + (r), (v))
177
178void brdsetup(void);	/* called by entry.S */
179
180void
181brdsetup(void)
182{
183	static uint8_t pci_to_memclk[] = {
184		30, 30, 10, 10, 20, 10, 10, 10,
185		10, 20, 20, 15, 20, 15, 20, 30,
186		30, 40, 15, 40, 20, 25, 20, 40,
187		25, 20, 10, 20, 15, 15, 20, 00
188	};
189	static uint8_t mem_to_cpuclk[] = {
190		25, 30, 45, 20, 20, 00, 10, 30,
191		30, 20, 45, 30, 25, 35, 30, 35,
192		20, 25, 20, 30, 35, 40, 40, 20,
193		30, 25, 40, 30, 30, 25, 35, 00
194	};
195	char *consname;
196	int consport;
197	uint32_t extclk;
198	unsigned pchb, pcib, dev11, dev13, dev15, dev16, val;
199	extern struct btinfo_memory bi_mem;
200	extern struct btinfo_console bi_cons;
201	extern struct btinfo_clock bi_clk;
202	extern struct btinfo_prodfamily bi_fam;
203
204	/*
205	 * CHRP specification "Map-B" BAT012 layout
206	 *   BAT0 0000-0000 (256MB) SDRAM
207	 *   BAT1 8000-0000 (256MB) PCI mem space
208	 *   BAT2 fc00-0000 (64MB)  EUMB, PCI I/O space, misc devs, flash
209	 *
210	 * EUMBBAR is at fc00-0000.
211	 */
212	pchb = pcimaketag(0, 0, 0);
213	pcicfgwrite(pchb, 0x78, 0xfc000000);
214
215	brdtype = BRD_UNKNOWN;
216	extclk = EXT_CLK_FREQ;	/* usually 33MHz */
217	busclock = 0;
218
219	dev11 = pcimaketag(0, 11, 0);
220	dev13 = pcimaketag(0, 13, 0);
221	dev15 = pcimaketag(0, 15, 0);
222	dev16 = pcimaketag(0, 16, 0);
223
224	if (pcifinddev(0x10ad, 0x0565, &pcib) == 0) {
225		/* WinBond 553 southbridge at dev 11 */
226		brdtype = BRD_SANDPOINTX3;
227	}
228	else if (pcifinddev(0x1106, 0x0686, &pcib) == 0) {
229		/* VIA 686B southbridge at dev 22 */
230		brdtype = BRD_ENCOREPP1;
231	}
232	else if (PCI_CLASS(pcicfgread(dev11, PCI_CLASS_REG)) == PCI_CLASS_ETH) {
233		/* ADMtek AN985 (tlp) or RealTek 8169S (re) at dev 11 */
234		brdtype = BRD_KUROBOX;
235	}
236	else if (PCI_VENDOR(pcicfgread(dev15, PCI_ID_REG)) == 0x11ab) {
237		/* SKnet/Marvell (sk) at dev 15 */
238		brdtype = BRD_SYNOLOGY;
239	}
240	else if (PCI_VENDOR(pcicfgread(dev13, PCI_ID_REG)) == 0x1106) {
241		/* VIA 6410 (viaide) at dev 13 */
242		brdtype = BRD_STORCENTER;
243	}
244	else if (PCI_VENDOR(pcicfgread(dev16, PCI_ID_REG)) == 0x1191) {
245		/* ACARD ATP865 (acardide) at dev 16 */
246		brdtype = BRD_DLINKDSM;
247	}
248	else if (PCI_VENDOR(pcicfgread(dev16, PCI_ID_REG)) == 0x1283
249	    || PCI_VENDOR(pcicfgread(dev16, PCI_ID_REG)) == 0x1095) {
250		/* ITE (iteide) or SiI (satalink) at dev 16 */
251		brdtype = BRD_NH230NAS;
252	}
253	else if (PCI_VENDOR(pcicfgread(dev15, PCI_ID_REG)) == 0x8086
254	    || PCI_VENDOR(pcicfgread(dev15, PCI_ID_REG)) == 0x10ec) {
255		/* Intel (wm) or RealTek (re) at dev 15 */
256		brdtype = BRD_QNAPTS;
257	}
258
259	brdprop = brd_lookup(brdtype);
260
261	/* brd dependent adjustments */
262	setup();
263
264	/* determine clock frequencies */
265	if (brdprop->extclk != 0)
266		extclk = brdprop->extclk;
267	if (busclock == 0) {
268		if (cputype() == MPC8245) {
269			/* PLL_CFG from PCI host bridge register 0xe2 */
270			val = pcicfgread(pchb, 0xe0);
271			busclock = (extclk *
272			    pci_to_memclk[(val >> 19) & 0x1f] + 10) / 10;
273			/* PLLRATIO from HID1 */
274			asm volatile ("mfspr %0,1009" : "=r"(val));
275			cpuclock = ((uint64_t)busclock *
276			    mem_to_cpuclk[val >> 27] + 10) / 10;
277		} else
278			busclock = 100000000;	/* 100MHz bus clock default */
279	}
280	ticks_per_sec = busclock >> 2;
281	ns_per_tick = 1000000000 / ticks_per_sec;
282
283	/* now prepare serial console */
284	consname = brdprop->consname;
285	consport = brdprop->consport;
286	if (strcmp(consname, "eumb") == 0) {
287		uart1base = 0xfc000000 + consport;	/* 0x4500, 0x4600 */
288		UART_WRITE(uart1base, DCR, 0x01);	/* enable DUART mode */
289		uart2base = uart1base ^ 0x0300;
290	} else
291		uart1base = 0xfe000000 + consport;	/* 0x3f8, 0x2f8 */
292
293	/* more brd adjustments */
294	brdfixup();
295
296	bi_mem.memsize = mpc107memsize();
297	snprintf(bi_cons.devname, sizeof(bi_cons.devname), consname);
298	bi_cons.addr = consport;
299	bi_cons.speed = brdprop->consspeed;
300	bi_clk.ticks_per_sec = ticks_per_sec;
301	snprintf(bi_fam.name, sizeof(bi_fam.name), brdprop->family);
302}
303
304struct brdprop *
305brd_lookup(int brd)
306{
307	u_int i;
308
309	for (i = 0; i < sizeof(brdlist)/sizeof(brdlist[0]); i++) {
310		if (brdlist[i].brdtype == brd)
311			return &brdlist[i];
312	}
313	return &brdlist[i - 1];
314}
315
316static void
317setup()
318{
319
320	if (brdprop->setup == NULL)
321		return;
322	(*brdprop->setup)(brdprop);
323}
324
325static void
326brdfixup()
327{
328
329	if (brdprop->brdfix == NULL)
330		return;
331	(*brdprop->brdfix)(brdprop);
332}
333
334void
335pcifixup()
336{
337
338	if (brdprop->pcifix == NULL)
339		return;
340	(*brdprop->pcifix)(brdprop);
341}
342
343void
344encsetup(struct brdprop *brd)
345{
346
347#ifdef COSNAME
348	brd->consname = CONSNAME;
349#endif
350#ifdef CONSPORT
351	brd->consport = CONSPORT;
352#endif
353#ifdef CONSSPEED
354	brd->consspeed = CONSSPEED;
355#endif
356}
357
358void
359encbrdfix(struct brdprop *brd)
360{
361	unsigned ac97, ide, pcib, pmgt, usb12, usb34, val;
362
363/*
364 * VIA82C686B Southbridge
365 *	0.22.0	1106.0686	PCI-ISA bridge
366 *	0.22.1	1106.0571	IDE (viaide)
367 *	0.22.2	1106.3038	USB 0/1 (uhci)
368 *	0.22.3	1106.3038	USB 2/3 (uhci)
369 *	0.22.4	1106.3057	power management
370 *	0.22.5	1106.3058	AC97 (auvia)
371 */
372	pcib  = pcimaketag(0, 22, 0);
373	ide   = pcimaketag(0, 22, 1);
374	usb12 = pcimaketag(0, 22, 2);
375	usb34 = pcimaketag(0, 22, 3);
376	pmgt  = pcimaketag(0, 22, 4);
377	ac97  = pcimaketag(0, 22, 5);
378
379#define	CFG(i,v) do { \
380   *(volatile unsigned char *)(0xfe000000 + 0x3f0) = (i); \
381   *(volatile unsigned char *)(0xfe000000 + 0x3f1) = (v); \
382   } while (0)
383	val = pcicfgread(pcib, 0x84);
384	val |= (02 << 8);
385	pcicfgwrite(pcib, 0x84, val);
386	CFG(0xe2, 0x0f); /* use COM1/2, don't use FDC/LPT */
387	val = pcicfgread(pcib, 0x84);
388	val &= ~(02 << 8);
389	pcicfgwrite(pcib, 0x84, val);
390
391	/* route pin C to i8259 IRQ 5, pin D to 11 */
392	val = pcicfgread(pcib, 0x54);
393	val = (val & 0xff) | 0xb0500000; /* Dx CB Ax xS */
394	pcicfgwrite(pcib, 0x54, val);
395
396	/* enable EISA ELCR1 (0x4d0) and ELCR2 (0x4d1) */
397	val = pcicfgread(pcib, 0x44);
398	val = val | 0x20000000;
399	pcicfgwrite(pcib, 0x44, val);
400
401	/* select level trigger for IRQ 5/11 at ELCR1/2 */
402	*(volatile uint8_t *)0xfe0004d0 = 0x20; /* bit 5 */
403	*(volatile uint8_t *)0xfe0004d1 = 0x08; /* bit 11 */
404
405	/* USB and AC97 are hardwired with pin D and C */
406	val = pcicfgread(usb12, 0x3c) &~ 0xff;
407	val |= 11;
408	pcicfgwrite(usb12, 0x3c, val);
409	val = pcicfgread(usb34, 0x3c) &~ 0xff;
410	val |= 11;
411	pcicfgwrite(usb34, 0x3c, val);
412	val = pcicfgread(ac97, 0x3c) &~ 0xff;
413	val |= 5;
414	pcicfgwrite(ac97, 0x3c, val);
415}
416
417void
418encpcifix(struct brdprop *brd)
419{
420	unsigned ide, irq, net, pcib, steer, val;
421
422#define	STEER(v, b) (((v) & (b)) ? "edge" : "level")
423	pcib = pcimaketag(0, 22, 0);
424	ide  = pcimaketag(0, 22, 1);
425	net  = pcimaketag(0, 25, 0);
426
427	/*
428	 * //// VIA PIRQ ////
429	 * 0x57/56/55/54 - Dx CB Ax xS
430	 */
431	val = pcicfgread(pcib, 0x54);	/* Dx CB Ax xs */
432	steer = val & 0xf;
433	irq = (val >> 12) & 0xf;	/* 15:12 */
434	if (irq) {
435		printf("pin A -> irq %d, %s\n",
436			irq, STEER(steer, 0x1));
437	}
438	irq = (val >> 16) & 0xf;	/* 19:16 */
439	if (irq) {
440		printf("pin B -> irq %d, %s\n",
441			irq, STEER(steer, 0x2));
442	}
443	irq = (val >> 20) & 0xf;	/* 23:20 */
444	if (irq) {
445		printf("pin C -> irq %d, %s\n",
446			irq, STEER(steer, 0x4));
447	}
448	irq = (val >> 28);		/* 31:28 */
449	if (irq) {
450		printf("pin D -> irq %d, %s\n",
451			irq, STEER(steer, 0x8));
452	}
453#if 0
454	/*
455	 * //// IDE fixup ////
456	 * - "native mode" (ide 0x09)
457	 */
458
459	/* ide: 0x09 - programming interface; 1000'SsPp */
460	val = pcicfgread(ide, 0x08) & 0xffff00ff;
461	pcicfgwrite(ide, 0x08, val | (0x8f << 8));
462
463	/* ide: 0x10-20 - leave them PCI memory space assigned */
464#else
465	/*
466	 * //// IDE fixup ////
467	 * - "compatiblity mode" (ide 0x09)
468	 * - remove PCI pin assignment (ide 0x3d)
469	 */
470
471	/* ide: 0x09 - programming interface; 1000'SsPp */
472	val = pcicfgread(ide, 0x08) & 0xffff00ff;
473	val |= (0x8a << 8);
474	pcicfgwrite(ide, 0x08, val);
475
476	/* ide: 0x10-20 */
477	/*
478	 * experiment shows writing ide: 0x09 changes these
479	 * register behaviour. The pcicfgwrite() above writes
480	 * 0x8a at ide: 0x09 to make sure legacy IDE.  Then
481	 * reading BAR0-3 is to return value 0s even though
482	 * pcisetup() has written range assignments.  Value
483	 * overwrite makes no effect. Having 0x8f for native
484	 * PCIIDE doesn't change register values and brings no
485	 * weirdness.
486	 */
487
488	/* ide: 0x3d/3c - turn off PCI pin */
489	val = pcicfgread(ide, 0x3c) & 0xffff00ff;
490	pcicfgwrite(ide, 0x3c, val);
491#endif
492	/*
493	 * //// USBx2, audio, and modem fixup ////
494	 * - disable USB #0 and #1 (pcib 0x48 and 0x85)
495	 * - disable AC97 audio and MC97 modem (pcib 0x85)
496	 */
497
498	/* pcib: 0x48 - disable USB #0 at function 2 */
499	val = pcicfgread(pcib, 0x48);
500	pcicfgwrite(pcib, 0x48, val | 04);
501
502	/* pcib: 0x85 - disable USB #1 at function 3 */
503	/* pcib: 0x85 - disable AC97/MC97 at function 5/6 */
504	val = pcicfgread(pcib, 0x84);
505	pcicfgwrite(pcib, 0x84, val | 0x1c00);
506
507	/*
508	 * //// fxp fixup ////
509	 * - use PCI pin A line 25 (fxp 0x3d/3c)
510	 */
511	/* 0x3d/3c - PCI pin/line */
512	val = pcicfgread(net, 0x3c) & 0xffff0000;
513	val |= (('A' - '@') << 8) | 25;
514	pcicfgwrite(net, 0x3c, val);
515}
516
517void
518motsetup(struct brdprop *brd)
519{
520
521#ifdef COSNAME
522	brd->consname = CONSNAME;
523#endif
524#ifdef CONSPORT
525	brd->consport = CONSPORT;
526#endif
527#ifdef CONSSPEED
528	brd->consspeed = CONSSPEED;
529#endif
530}
531
532void
533motbrdfix(struct brdprop *brd)
534{
535
536/*
537 * WinBond/Symphony Lab 83C553 with PC87308 "SuperIO"
538 *
539 *	0.11.0	10ad.0565	PCI-ISA bridge
540 *	0.11.1	10ad.0105	IDE (slide)
541 */
542}
543
544void
545motpcifix(struct brdprop *brd)
546{
547	unsigned ide, net, pcib, steer, val;
548	int line;
549
550	pcib = pcimaketag(0, 11, 0);
551	ide  = pcimaketag(0, 11, 1);
552	net  = pcimaketag(0, 15, 0);
553
554	/*
555	 * //// WinBond PIRQ ////
556	 * 0x40 - bit 5 (0x20) indicates PIRQ presense
557	 * 0x60 - PIRQ interrupt routing steer
558	 */
559	if (pcicfgread(pcib, 0x40) & 0x20) {
560		steer = pcicfgread(pcib, 0x60);
561		if ((steer & 0x80808080) == 0x80808080)
562			printf("PIRQ[0-3] disabled\n");
563		else {
564			unsigned i, v = steer;
565			for (i = 0; i < 4; i++, v >>= 8) {
566				if ((v & 0x80) != 0 || (v & 0xf) == 0)
567					continue;
568				printf("PIRQ[%d]=%d\n", i, v & 0xf);
569				}
570			}
571		}
572#if 1
573	/*
574	 * //// IDE fixup -- case A ////
575	 * - "native PCI mode" (ide 0x09)
576	 * - don't use ISA IRQ14/15 (pcib 0x43)
577	 * - native IDE for both channels (ide 0x40)
578	 * - LEGIRQ bit 11 steers interrupt to pin C (ide 0x40)
579	 * - sign as PCI pin C line 11 (ide 0x3d/3c)
580	 */
581	/* ide: 0x09 - programming interface; 1000'SsPp */
582	val = pcicfgread(ide, 0x08);
583	val &= 0xffff00ff;
584	pcicfgwrite(ide, 0x08, val | (0x8f << 8));
585
586	/* pcib: 0x43 - IDE interrupt routing */
587	val = pcicfgread(pcib, 0x40) & 0x00ffffff;
588	pcicfgwrite(pcib, 0x40, val);
589
590	/* pcib: 0x45/44 - PCI interrupt routing */
591	val = pcicfgread(pcib, 0x44) & 0xffff0000;
592	pcicfgwrite(pcib, 0x44, val);
593
594	/* ide: 0x41/40 - IDE channel */
595	val = pcicfgread(ide, 0x40) & 0xffff0000;
596	val |= (1 << 11) | 0x33; /* LEGIRQ turns on PCI interrupt */
597	pcicfgwrite(ide, 0x40, val);
598
599	/* ide: 0x3d/3c - use PCI pin C/line 11 */
600	val = pcicfgread(ide, 0x3c) & 0xffffff00;
601	val |= 11; /* pin designation is hardwired to pin A */
602	pcicfgwrite(ide, 0x3c, val);
603#else
604	/*
605	 * //// IDE fixup -- case B ////
606	 * - "compatiblity mode" (ide 0x09)
607	 * - IDE primary/secondary interrupt routing (pcib 0x43)
608	 * - PCI interrupt routing (pcib 0x45/44)
609	 * - no PCI pin/line assignment (ide 0x3d/3c)
610	 */
611	/* ide: 0x09 - programming interface; 1000'SsPp */
612	val = pcicfgread(ide, 0x08);
613	val &= 0xffff00ff;
614	pcicfgwrite(ide, 0x08, val | (0x8a << 8));
615
616	/* pcib: 0x43 - IDE interrupt routing */
617	val = pcicfgread(pcib, 0x40) & 0x00ffffff;
618	pcicfgwrite(pcib, 0x40, val | (0xee << 24));
619
620	/* ide: 0x45/44 - PCI interrupt routing */
621	val = pcicfgread(ide, 0x44) & 0xffff0000;
622	pcicfgwrite(ide, 0x44, val);
623
624	/* ide: 0x3d/3c - turn off PCI pin/line */
625	val = pcicfgread(ide, 0x3c) & 0xffff0000;
626	pcicfgwrite(ide, 0x3c, val);
627#endif
628
629	/*
630	 * //// fxp fixup ////
631	 * - use PCI pin A line 15 (fxp 0x3d/3c)
632	 */
633	val = pcicfgread(net, 0x3c) & 0xffff0000;
634	pcidecomposetag(net, NULL, &line, NULL);
635	val |= (('A' - '@') << 8) | line;
636	pcicfgwrite(net, 0x3c, val);
637}
638
639void
640kurosetup(struct brdprop *brd)
641{
642
643	if (PCI_VENDOR(pcicfgread(pcimaketag(0, 11, 0), PCI_ID_REG)) == 0x10ec)
644		brd->extclk = 32768000; /* decr 2457600Hz */
645	else
646		brd->extclk = 32521333; /* decr 2439100Hz */
647}
648
649void
650kurobrdfix(struct brdprop *brd)
651{
652
653	init_uart(uart2base, 9600, LCR_8BITS | LCR_PEVEN);
654	/* Stop Watchdog */
655	send_sat("AAAAFFFFJJJJ>>>>VVVV>>>>ZZZZVVVVKKKK");
656}
657
658void
659synobrdfix(struct brdprop *brd)
660{
661
662	init_uart(uart2base, 9600, LCR_8BITS | LCR_PNONE);
663	/* beep, power LED on, status LED off */
664	send_sat("247");
665}
666
667void
668synoreset()
669{
670
671	send_sat("C");
672	/*NOTREACHED*/
673}
674
675void
676qnapbrdfix(struct brdprop *brd)
677{
678
679	init_uart(uart2base, 19200, LCR_8BITS | LCR_PNONE);
680	/* beep, status LED red */
681	send_sat("PW");
682}
683
684void
685qnapreset()
686{
687
688	send_sat("f");
689	/*NOTREACHED*/
690}
691
692void
693iomegabrdfix(struct brdprop *brd)
694{
695
696	init_uart(uart2base, 9600, LCR_8BITS | LCR_PNONE);
697	/* LED flashing blue, fan auto, turn on at 60C, turn off at 50C */
698	(void)send_iomega('b', 'd', 2, 'a', 60, 50);
699}
700
701void
702iomegareset()
703{
704
705	(void)send_iomega('g', 0, 0, 0, 0, 0);
706	/*NOTREACHED*/
707}
708
709void
710dlinkbrdfix(struct brdprop *brd)
711{
712
713	init_uart(uart2base, 9600, LCR_8BITS | LCR_PNONE);
714	send_sat("SYN\n");
715	send_sat("ZWO\n");	/* power LED solid on */
716}
717
718void
719nhnasbrdfix(struct brdprop *brd)
720{
721
722	/* illuminate LEDs */
723}
724
725void
726_rtt(void)
727{
728	uint32_t msr;
729
730	netif_shutdown_all();
731
732	if (brdprop->reset != NULL)
733		(*brdprop->reset)();
734	else {
735		msr = mfmsr();
736		msr &= ~PSL_EE;
737		mtmsr(msr);
738		asm volatile ("sync; isync");
739		asm volatile("mtspr %0,%1" : : "K"(81), "r"(0));
740		msr &= ~(PSL_ME | PSL_DR | PSL_IR);
741		mtmsr(msr);
742		asm volatile ("sync; isync");
743		run(0, 0, 0, 0, (void *)0xFFF00100); /* reset entry */
744	}
745	/*NOTREACHED*/
746}
747
748satime_t
749getsecs(void)
750{
751	u_quad_t tb = mftb();
752
753	return (tb / ticks_per_sec);
754}
755
756/*
757 * Wait for about n microseconds (at least!).
758 */
759void
760delay(u_int n)
761{
762	u_quad_t tb;
763	u_long scratch, tbh, tbl;
764
765	tb = mftb();
766	tb += (n * 1000 + ns_per_tick - 1) / ns_per_tick;
767	tbh = tb >> 32;
768	tbl = tb;
769	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));
770}
771
772void
773_wb(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 ("dcbst 0,%0" :: "r"(adr));
780	asm volatile ("sync");
781}
782
783void
784_wbinv(uint32_t adr, uint32_t siz)
785{
786	uint32_t bnd;
787
788	asm volatile("eieio");
789	for (bnd = adr + siz; adr < bnd; adr += dcache_line_size)
790		asm volatile ("dcbf 0,%0" :: "r"(adr));
791	asm volatile ("sync");
792}
793
794void
795_inv(uint32_t adr, uint32_t siz)
796{
797	uint32_t bnd, off;
798
799	off = adr & (dcache_line_size - 1);
800	adr -= off;
801	siz += off;
802	asm volatile ("eieio");
803	if (off != 0) {
804		/* wbinv() leading unaligned dcache line */
805		asm volatile ("dcbf 0,%0" :: "r"(adr));
806		if (siz < dcache_line_size)
807			goto done;
808		adr += dcache_line_size;
809		siz -= dcache_line_size;
810	}
811	bnd = adr + siz;
812	off = bnd & (dcache_line_size - 1);
813	if (off != 0) {
814		/* wbinv() trailing unaligned dcache line */
815		asm volatile ("dcbf 0,%0" :: "r"(bnd)); /* it's OK */
816		if (siz < dcache_line_size)
817			goto done;
818		siz -= off;
819	}
820	for (bnd = adr + siz; adr < bnd; adr += dcache_line_size) {
821		/* inv() intermediate dcache lines if ever */
822		asm volatile ("dcbi 0,%0" :: "r"(adr));
823	}
824  done:
825	asm volatile ("sync");
826}
827
828static inline uint32_t
829mfmsr(void)
830{
831	uint32_t msr;
832
833	asm volatile ("mfmsr %0" : "=r"(msr));
834	return msr;
835}
836
837static inline void
838mtmsr(uint32_t msr)
839{
840	asm volatile ("mtmsr %0" : : "r"(msr));
841}
842
843static inline uint32_t
844cputype(void)
845{
846	uint32_t pvr;
847
848	asm volatile ("mfpvr %0" : "=r"(pvr));
849	return pvr >> 16;
850}
851
852static inline u_quad_t
853mftb(void)
854{
855	u_long scratch;
856	u_quad_t tb;
857
858	asm ("1: mftbu %0; mftb %0+1; mftbu %1; cmpw %0,%1; bne 1b"
859	    : "=r"(tb), "=r"(scratch));
860	return tb;
861}
862
863static void
864init_uart(unsigned base, unsigned speed, uint8_t lcr)
865{
866	unsigned div;
867
868	div = busclock / speed / 16;
869	UART_WRITE(base, LCR, 0x80);		/* turn on DLAB bit */
870	UART_WRITE(base, FCR, 0x00);
871	UART_WRITE(base, DMB, div >> 8);	/* set speed */
872	UART_WRITE(base, DLB, div & 0xff);
873	UART_WRITE(base, LCR, lcr);
874	UART_WRITE(base, FCR, 0x07);		/* FIFO on, TXRX FIFO reset */
875	UART_WRITE(base, IER, 0x00);		/* make sure INT disabled */
876}
877
878/* talk to satellite processor */
879static void
880send_sat(char *msg)
881{
882	unsigned savedbase;
883
884	savedbase = uart1base;
885	uart1base = uart2base;
886	while (*msg)
887		putchar(*msg++);
888	uart1base = savedbase;
889}
890
891#ifdef DEBUG
892static void
893iomega_debug(const char *txt, uint8_t buf[])
894{
895	int i;
896
897	printf("%s:", txt);
898	for (i = 0; i < IOMEGA_PACKETSIZE; i++)
899		printf(" %02x", buf[i]);
900	putchar('\n');
901}
902#endif /* DEBUG */
903
904static int
905send_iomega(int power, int led, int rate, int fan, int high, int low)
906{
907	uint8_t buf[IOMEGA_PACKETSIZE];
908	unsigned i, savedbase;
909
910	savedbase = uart1base;
911	uart1base = uart2base;
912
913	/* first flush the receive buffer */
914  again:
915	while (tstchar())
916		(void)getchar();
917	delay(20000);
918	if (tstchar())
919		goto again;
920	/*
921	 * Now synchronize the transmitter by sending 0x00
922	 * until we receive a status reply.
923	 */
924	do {
925		putchar(0);
926		delay(25000);
927	} while (!tstchar());
928
929	for (i = 0; i < IOMEGA_PACKETSIZE; i++)
930		buf[i] = getchar();
931#ifdef DEBUG
932	uart1base = savedbase;
933	iomega_debug("68HC908 status", buf);
934	uart1base = uart2base;
935#endif
936
937	/* send command */
938	if (power >= 0)
939		buf[IOMEGA_POWER] = power;
940	if (led >= 0)
941		buf[IOMEGA_LED] = led;
942	if (rate >= 0)
943		buf[IOMEGA_FLASH_RATE] = rate;
944	if (fan >= 0)
945		buf[IOMEGA_FAN] = fan;
946	if (high >= 0)
947		buf[IOMEGA_HIGH_TEMP] = high;
948	if (low >= 0)
949		buf[IOMEGA_LOW_TEMP] = low;
950	buf[IOMEGA_ID] = 7;	/* host id */
951	buf[IOMEGA_CHECKSUM] = (buf[IOMEGA_POWER] + buf[IOMEGA_LED] +
952	    buf[IOMEGA_FLASH_RATE] + buf[IOMEGA_FAN] +
953	    buf[IOMEGA_HIGH_TEMP] + buf[IOMEGA_LOW_TEMP] +
954	    buf[IOMEGA_ID]) & 0x7f;
955#ifdef DEBUG
956	uart1base = savedbase;
957	iomega_debug("G2 sending", buf);
958	uart1base = uart2base;
959#endif
960	for (i = 0; i < IOMEGA_PACKETSIZE; i++)
961		putchar(buf[i]);
962
963	/* receive the reply */
964	for (i = 0; i < IOMEGA_PACKETSIZE; i++)
965		buf[i] = getchar();
966
967	uart1base = savedbase;
968#ifdef DEBUG
969	iomega_debug("68HC908 reply", buf);
970#endif
971	return buf[0] != '#';  /* error? */
972}
973
974void
975putchar(int c)
976{
977	unsigned timo, lsr;
978
979	if (c == '\n')
980		putchar('\r');
981
982	timo = 0x00100000;
983	do {
984		lsr = UART_READ(uart1base, LSR);
985	} while (timo-- > 0 && (lsr & LSR_THRE) == 0);
986	if (timo > 0)
987		UART_WRITE(uart1base, THR, c);
988}
989
990int
991getchar(void)
992{
993	unsigned lsr;
994
995	do {
996		lsr = UART_READ(uart1base, LSR);
997	} while ((lsr & LSR_DRDY) == 0);
998	return UART_READ(uart1base, RBR);
999}
1000
1001int
1002tstchar(void)
1003{
1004
1005	return (UART_READ(uart1base, LSR) & LSR_DRDY) != 0;
1006}
1007
1008unsigned
1009mpc107memsize()
1010{
1011	unsigned bankn, end, n, tag, val;
1012
1013	tag = pcimaketag(0, 0, 0);
1014
1015	if (brdtype == BRD_ENCOREPP1) {
1016		/* the brd's PPCBOOT looks to have erroneous values */
1017		unsigned tbl[] = {
1018#define MPC106_MEMSTARTADDR1	0x80
1019#define MPC106_EXTMEMSTARTADDR1	0x88
1020#define MPC106_MEMENDADDR1	0x90
1021#define MPC106_EXTMEMENDADDR1	0x98
1022#define MPC106_MEMEN		0xa0
1023#define	BK0_S	0x00000000
1024#define	BK0_E	(128 << 20) - 1
1025#define BK1_S	0x3ff00000
1026#define BK1_E	0x3fffffff
1027#define BK2_S	0x3ff00000
1028#define BK2_E	0x3fffffff
1029#define BK3_S	0x3ff00000
1030#define BK3_E	0x3fffffff
1031#define AR(v, s) ((((v) & SAR_MASK) >> SAR_SHIFT) << (s))
1032#define XR(v, s) ((((v) & EAR_MASK) >> EAR_SHIFT) << (s))
1033#define SAR_MASK 0x0ff00000
1034#define SAR_SHIFT    20
1035#define EAR_MASK 0x30000000
1036#define EAR_SHIFT    28
1037		AR(BK0_S, 0) | AR(BK1_S, 8) | AR(BK2_S, 16) | AR(BK3_S, 24),
1038		XR(BK0_S, 0) | XR(BK1_S, 8) | XR(BK2_S, 16) | XR(BK3_S, 24),
1039		AR(BK0_E, 0) | AR(BK1_E, 8) | AR(BK2_E, 16) | AR(BK3_E, 24),
1040		XR(BK0_E, 0) | XR(BK1_E, 8) | XR(BK2_E, 16) | XR(BK3_E, 24),
1041		};
1042		tag = pcimaketag(0, 0, 0);
1043		pcicfgwrite(tag, MPC106_MEMSTARTADDR1, tbl[0]);
1044		pcicfgwrite(tag, MPC106_EXTMEMSTARTADDR1, tbl[1]);
1045		pcicfgwrite(tag, MPC106_MEMENDADDR1, tbl[2]);
1046		pcicfgwrite(tag, MPC106_EXTMEMENDADDR1,	tbl[3]);
1047		pcicfgwrite(tag, MPC106_MEMEN, 1);
1048	}
1049
1050	bankn = 0;
1051	val = pcicfgread(tag, MPC106_MEMEN);
1052	for (n = 0; n < 4; n++) {
1053		if ((val & (1U << n)) == 0)
1054			break;
1055		bankn = n;
1056	}
1057	bankn = bankn * 8;
1058
1059	val = pcicfgread(tag, MPC106_EXTMEMENDADDR1);
1060	end =  ((val >> bankn) & 0x03) << 28;
1061	val = pcicfgread(tag, MPC106_MEMENDADDR1);
1062	end |= ((val >> bankn) & 0xff) << 20;
1063	end |= 0xfffff;
1064
1065	return (end + 1); /* assume the end address matches total amount */
1066}
1067
1068struct fis_dir_entry {
1069	char		name[16];
1070	uint32_t	startaddr;
1071	uint32_t	loadaddr;
1072	uint32_t	flashsize;
1073	uint32_t	entryaddr;
1074	uint32_t	filesize;
1075	char		pad[256 - (16 + 5 * sizeof(uint32_t))];
1076};
1077
1078#define FIS_LOWER_LIMIT	0xfff00000
1079
1080/*
1081 * Look for a Redboot-style Flash Image System FIS-directory and
1082 * return a pointer to the start address of the requested file.
1083 */
1084static void *
1085redboot_fis_lookup(const char *filename)
1086{
1087	static const char FISdirname[16] = {
1088	    'F', 'I', 'S', ' ',
1089	    'd', 'i', 'r', 'e', 'c', 't', 'o', 'r', 'y', 0, 0, 0
1090	};
1091	struct fis_dir_entry *dir;
1092
1093	/*
1094	 * The FIS directory is usually in the last sector of the flash.
1095	 * But we do not know the sector size (erase size), so start
1096	 * at 0xffffff00 and scan backwards in steps of the FIS directory
1097	 * entry size (0x100).
1098	 */
1099	for (dir = (struct fis_dir_entry *)0xffffff00;
1100	    (uint32_t)dir >= FIS_LOWER_LIMIT; dir--)
1101		if (memcmp(dir->name, FISdirname, sizeof(FISdirname)) == 0)
1102			break;
1103	if ((uint32_t)dir < FIS_LOWER_LIMIT) {
1104		printf("No FIS directory found!\n");
1105		return NULL;
1106	}
1107
1108	/* Now find filename by scanning the directory from beginning. */
1109	dir = (struct fis_dir_entry *)dir->startaddr;
1110	while (dir->name[0] != 0xff && (uint32_t)dir < 0xffffff00) {
1111		if (strcmp(dir->name, filename) == 0)
1112			return (void *)dir->startaddr;	/* found */
1113		dir++;
1114	}
1115	printf("\"%s\" not found in FIS directory!\n", filename);
1116	return NULL;
1117}
1118
1119static void
1120read_mac_string(uint8_t *mac, char *p)
1121{
1122	int i;
1123
1124	for (i = 0; i < 6; i++, p += 3)
1125		*mac++ = read_hex(p);
1126}
1127
1128/*
1129 * For cost saving reasons some NAS boxes lack SEEPROM for NIC's
1130 * ethernet address and keep it in their Flash memory instead.
1131 */
1132void
1133read_mac_from_flash(uint8_t *mac)
1134{
1135	uint8_t *p;
1136
1137	switch (brdtype) {
1138	case BRD_SYNOLOGY:
1139		p = redboot_fis_lookup("vendor");
1140		if (p == NULL)
1141			break;
1142		memcpy(mac, p, 6);
1143		return;
1144	case BRD_DLINKDSM:
1145		read_mac_string(mac, (char *)0xfff0ff80);
1146		return;
1147	default:
1148		printf("Warning: This board has no known method defined "
1149		    "to determine its MAC address!\n");
1150		break;
1151	}
1152
1153	/* set to 00:00:00:00:00:00 in case of error */
1154	memset(mac, 0, 6);
1155}
1156
1157#ifdef DEBUG
1158void
1159sat_write(char *p, int len)
1160{
1161	unsigned savedbase;
1162
1163	savedbase = uart1base;
1164	uart1base = uart2base;
1165	while (len--)
1166		putchar(*p++);
1167	uart1base = savedbase;
1168}
1169
1170int
1171sat_getch(void)
1172{
1173	unsigned lsr;
1174
1175	do {
1176		lsr = UART_READ(uart2base, LSR);
1177	} while ((lsr & LSR_DRDY) == 0);
1178	return UART_READ(uart2base, RBR);
1179}
1180
1181int
1182sat_tstch(void)
1183{
1184
1185	return (UART_READ(uart2base, LSR) & LSR_DRDY) != 0;
1186}
1187#endif /* DEBUG */
1188