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