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