Home | History | Annotate | Line # | Download | only in altboot
brdsetup.c revision 1.19
      1 /* $NetBSD: brdsetup.c,v 1.19 2011/10/30 21:08:33 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 
     51 BRD_DECL(mot);
     52 BRD_DECL(enc);
     53 BRD_DECL(kuro);
     54 BRD_DECL(syno);
     55 BRD_DECL(qnap);
     56 BRD_DECL(iomega);
     57 BRD_DECL(dlink);
     58 BRD_DECL(nhnas);
     59 
     60 static 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 
    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 
    139 static struct brdprop *brdprop;
    140 static uint32_t ticks_per_sec, ns_per_tick;
    141 
    142 static void brdfixup(void);
    143 static void setup(void);
    144 static int send_iomega(int, int, int, int, int, int, uint8_t *);
    145 static inline uint32_t mfmsr(void);
    146 static inline void mtmsr(uint32_t);
    147 static inline uint32_t cputype(void);
    148 static inline u_quad_t mftb(void);
    149 static void init_uart(unsigned, unsigned, uint8_t);
    150 static void send_sat(char *);
    151 
    152 const unsigned dcache_line_size = 32;		/* 32B linesize */
    153 const unsigned dcache_range_size = 4 * 1024;	/* 16KB / 4-way */
    154 
    155 unsigned uart1base;	/* console */
    156 unsigned 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 
    178 void brdsetup(void);	/* called by entry.S */
    179 
    180 void
    181 brdsetup(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 
    304 struct brdprop *
    305 brd_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 
    316 static void
    317 setup()
    318 {
    319 
    320 	if (brdprop->setup == NULL)
    321 		return;
    322 	(*brdprop->setup)(brdprop);
    323 }
    324 
    325 static void
    326 brdfixup()
    327 {
    328 
    329 	if (brdprop->brdfix == NULL)
    330 		return;
    331 	(*brdprop->brdfix)(brdprop);
    332 }
    333 
    334 void
    335 pcifixup()
    336 {
    337 
    338 	if (brdprop->pcifix == NULL)
    339 		return;
    340 	(*brdprop->pcifix)(brdprop);
    341 }
    342 
    343 void
    344 encsetup(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 
    358 void
    359 encbrdfix(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 
    417 void
    418 encpcifix(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 	 * - use primary only (ide 0x40)
    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 
    465 	/* ide: 0x40 - use primary only */
    466 	val = pcicfgread(ide, 0x40) &~ 03;
    467 	val |= 02;
    468 	pcicfgwrite(ide, 0x40, val);
    469 #else
    470 	/*
    471 	 * //// IDE fixup ////
    472 	 * - "compatiblity mode" (ide 0x09)
    473 	 * - use primary only (ide 0x40)
    474 	 * - remove PCI pin assignment (ide 0x3d)
    475 	 */
    476 	/* ide: 0x09 - programming interface; 1000'SsPp */
    477 	val = pcicfgread(ide, 0x08) & 0xffff00ff;
    478 	val |= (0x8a << 8);
    479 	pcicfgwrite(ide, 0x08, val);
    480 
    481 	/* ide: 0x10-20 */
    482 	/*
    483 	experiment shows writing ide: 0x09 changes these
    484 	register behaviour. The pcicfgwrite() above writes
    485 	0x8a at ide: 0x09 to make sure legacy IDE.  Then
    486 	reading BAR0-3 is to return value 0s even though
    487 	pcisetup() has written range assignments.  Value
    488 	overwrite makes no effect. Having 0x8f for native
    489 	PCIIDE doesn't change register values and brings no
    490 	weirdness.
    491 	 */
    492 
    493 	/* ide: 0x40 - use primary only */
    494 	val = pcicfgread(ide, 0x40) &~ 03;
    495 	val |= 02;
    496 	pcicfgwrite(ide, 0x40, val);
    497 
    498 		/* ide: 0x3d/3c - turn off PCI pin */
    499 	val = pcicfgread(ide, 0x3c) & 0xffff00ff;
    500 	pcicfgwrite(ide, 0x3c, val);
    501 #endif
    502 	/*
    503 	 * //// USBx2, audio, and modem fixup ////
    504 	 * - disable USB #0 and #1 (pcib 0x48 and 0x85)
    505 	 * - disable AC97 audio and MC97 modem (pcib 0x85)
    506 	 */
    507 
    508 	/* pcib: 0x48 - disable USB #0 at function 2 */
    509 	val = pcicfgread(pcib, 0x48);
    510 	pcicfgwrite(pcib, 0x48, val | 04);
    511 
    512 	/* pcib: 0x85 - disable USB #1 at function 3 */
    513 	/* pcib: 0x85 - disable AC97/MC97 at function 5/6 */
    514 	val = pcicfgread(pcib, 0x84);
    515 	pcicfgwrite(pcib, 0x84, val | 0x1c00);
    516 
    517 	/*
    518 	 * //// fxp fixup ////
    519 	 * - use PCI pin A line 25 (fxp 0x3d/3c)
    520 	 */
    521 	/* 0x3d/3c - PCI pin/line */
    522 	val = pcicfgread(net, 0x3c) & 0xffff0000;
    523 	val |= (('A' - '@') << 8) | 25;
    524 	pcicfgwrite(net, 0x3c, val);
    525 }
    526 
    527 void
    528 motsetup(struct brdprop *brd)
    529 {
    530 
    531 #ifdef COSNAME
    532 	brd->consname = CONSNAME;
    533 #endif
    534 #ifdef CONSPORT
    535 	brd->consport = CONSPORT;
    536 #endif
    537 #ifdef CONSSPEED
    538 	brd->consspeed = CONSSPEED;
    539 #endif
    540 }
    541 
    542 void
    543 motbrdfix(struct brdprop *brd)
    544 {
    545 
    546 /*
    547  * WinBond/Symphony Lab 83C553 with PC87308 "SuperIO"
    548  *
    549  *	0.11.0	10ad.0565	PCI-ISA bridge
    550  *	0.11.1	10ad.0105	IDE (slide)
    551  */
    552 }
    553 
    554 void
    555 motpcifix(struct brdprop *brd)
    556 {
    557 	unsigned ide, net, pcib, steer, val;
    558 	int line;
    559 
    560 	pcib = pcimaketag(0, 11, 0);
    561 	ide  = pcimaketag(0, 11, 1);
    562 	net  = pcimaketag(0, 15, 0);
    563 
    564 	/*
    565 	 * //// WinBond PIRQ ////
    566 	 * 0x40 - bit 5 (0x20) indicates PIRQ presense
    567 	 * 0x60 - PIRQ interrupt routing steer
    568 	 */
    569 	if (pcicfgread(pcib, 0x40) & 0x20) {
    570 		steer = pcicfgread(pcib, 0x60);
    571 		if ((steer & 0x80808080) == 0x80808080)
    572 			printf("PIRQ[0-3] disabled\n");
    573 		else {
    574 			unsigned i, v = steer;
    575 			for (i = 0; i < 4; i++, v >>= 8) {
    576 				if ((v & 0x80) != 0 || (v & 0xf) == 0)
    577 					continue;
    578 				printf("PIRQ[%d]=%d\n", i, v & 0xf);
    579 				}
    580 			}
    581 		}
    582 #if 1
    583 	/*
    584 	 * //// IDE fixup -- case A ////
    585 	 * - "native PCI mode" (ide 0x09)
    586 	 * - don't use ISA IRQ14/15 (pcib 0x43)
    587 	 * - native IDE for both channels (ide 0x40)
    588 	 * - LEGIRQ bit 11 steers interrupt to pin C (ide 0x40)
    589 	 * - sign as PCI pin C line 11 (ide 0x3d/3c)
    590 	 */
    591 	/* ide: 0x09 - programming interface; 1000'SsPp */
    592 	val = pcicfgread(ide, 0x08);
    593 	val &= 0xffff00ff;
    594 	pcicfgwrite(ide, 0x08, val | (0x8f << 8));
    595 
    596 	/* pcib: 0x43 - IDE interrupt routing */
    597 	val = pcicfgread(pcib, 0x40) & 0x00ffffff;
    598 	pcicfgwrite(pcib, 0x40, val);
    599 
    600 	/* pcib: 0x45/44 - PCI interrupt routing */
    601 	val = pcicfgread(pcib, 0x44) & 0xffff0000;
    602 	pcicfgwrite(pcib, 0x44, val);
    603 
    604 	/* ide: 0x41/40 - IDE channel */
    605 	val = pcicfgread(ide, 0x40) & 0xffff0000;
    606 	val |= (1 << 11) | 0x33; /* LEGIRQ turns on PCI interrupt */
    607 	pcicfgwrite(ide, 0x40, val);
    608 
    609 	/* ide: 0x3d/3c - use PCI pin C/line 11 */
    610 	val = pcicfgread(ide, 0x3c) & 0xffffff00;
    611 	val |= 11; /* pin designation is hardwired to pin A */
    612 	pcicfgwrite(ide, 0x3c, val);
    613 #else
    614 	/*
    615 	 * //// IDE fixup -- case B ////
    616 	 * - "compatiblity mode" (ide 0x09)
    617 	 * - IDE primary/secondary interrupt routing (pcib 0x43)
    618 	 * - PCI interrupt routing (pcib 0x45/44)
    619 	 * - no PCI pin/line assignment (ide 0x3d/3c)
    620 	 */
    621 	/* ide: 0x09 - programming interface; 1000'SsPp */
    622 	val = pcicfgread(ide, 0x08);
    623 	val &= 0xffff00ff;
    624 	pcicfgwrite(ide, 0x08, val | (0x8a << 8));
    625 
    626 	/* pcib: 0x43 - IDE interrupt routing */
    627 	val = pcicfgread(pcib, 0x40) & 0x00ffffff;
    628 	pcicfgwrite(pcib, 0x40, val | (0xee << 24));
    629 
    630 	/* ide: 0x45/44 - PCI interrupt routing */
    631 	val = pcicfgread(ide, 0x44) & 0xffff0000;
    632 	pcicfgwrite(ide, 0x44, val);
    633 
    634 	/* ide: 0x3d/3c - turn off PCI pin/line */
    635 	val = pcicfgread(ide, 0x3c) & 0xffff0000;
    636 	pcicfgwrite(ide, 0x3c, val);
    637 #endif
    638 
    639 	/*
    640 	 * //// fxp fixup ////
    641 	 * - use PCI pin A line 15 (fxp 0x3d/3c)
    642 	 */
    643 	val = pcicfgread(net, 0x3c) & 0xffff0000;
    644 	pcidecomposetag(net, NULL, &line, NULL);
    645 	val |= (('A' - '@') << 8) | line;
    646 	pcicfgwrite(net, 0x3c, val);
    647 }
    648 
    649 void
    650 kurosetup(struct brdprop *brd)
    651 {
    652 
    653 	if (PCI_VENDOR(pcicfgread(pcimaketag(0, 11, 0), PCI_ID_REG)) == 0x10ec)
    654 		brd->extclk = 32768000; /* decr 2457600Hz */
    655 	else
    656 		brd->extclk = 32521333; /* decr 2439100Hz */
    657 }
    658 
    659 void
    660 kurobrdfix(struct brdprop *brd)
    661 {
    662 
    663 	init_uart(uart2base, 9600, LCR_8BITS | LCR_PEVEN);
    664 	/* Stop Watchdog */
    665 	send_sat("AAAAFFFFJJJJ>>>>VVVV>>>>ZZZZVVVVKKKK");
    666 }
    667 
    668 void
    669 synobrdfix(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 
    677 void
    678 synoreset()
    679 {
    680 
    681 	send_sat("C");
    682 	/*NOTREACHED*/
    683 }
    684 
    685 void
    686 qnapbrdfix(struct brdprop *brd)
    687 {
    688 
    689 	init_uart(uart2base, 19200, LCR_8BITS | LCR_PNONE);
    690 	/* beep, status LED red */
    691 	send_sat("PW");
    692 }
    693 
    694 void
    695 qnapreset()
    696 {
    697 
    698 	send_sat("f");
    699 	/*NOTREACHED*/
    700 }
    701 
    702 void
    703 iomegabrdfix(struct brdprop *brd)
    704 {
    705 
    706 	init_uart(uart2base, 9600, LCR_8BITS | LCR_PNONE);
    707 	/* illuminate LEDs */
    708 	(void)send_iomega('b', 'd', 2, 'a', 60, 50, NULL);
    709 }
    710 
    711 void
    712 dlinkbrdfix(struct brdprop *brd)
    713 {
    714 
    715 	init_uart(uart2base, 9600, LCR_8BITS | LCR_PNONE);
    716 	send_sat("SYN\n");
    717 	send_sat("ZWO\n");	/* power LED solid on */
    718 }
    719 
    720 void
    721 nhnasbrdfix(struct brdprop *brd)
    722 {
    723 
    724 	/* illuminate LEDs */
    725 }
    726 
    727 void
    728 _rtt(void)
    729 {
    730 	uint32_t msr;
    731 
    732 	netif_shutdown_all();
    733 
    734 	if (brdprop->reset != NULL)
    735 		(*brdprop->reset)();
    736 	else {
    737 		msr = mfmsr();
    738 		msr &= ~PSL_EE;
    739 		mtmsr(msr);
    740 		asm volatile ("sync; isync");
    741 		asm volatile("mtspr %0,%1" : : "K"(81), "r"(0));
    742 		msr &= ~(PSL_ME | PSL_DR | PSL_IR);
    743 		mtmsr(msr);
    744 		asm volatile ("sync; isync");
    745 		run(0, 0, 0, 0, (void *)0xFFF00100); /* reset entry */
    746 	}
    747 	/*NOTREACHED*/
    748 }
    749 
    750 satime_t
    751 getsecs(void)
    752 {
    753 	u_quad_t tb = mftb();
    754 
    755 	return (tb / ticks_per_sec);
    756 }
    757 
    758 /*
    759  * Wait for about n microseconds (at least!).
    760  */
    761 void
    762 delay(u_int n)
    763 {
    764 	u_quad_t tb;
    765 	u_long scratch, tbh, tbl;
    766 
    767 	tb = mftb();
    768 	tb += (n * 1000 + ns_per_tick - 1) / ns_per_tick;
    769 	tbh = tb >> 32;
    770 	tbl = tb;
    771 	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));
    772 }
    773 
    774 void
    775 _wb(uint32_t adr, uint32_t siz)
    776 {
    777 	uint32_t bnd;
    778 
    779 	asm volatile("eieio");
    780 	for (bnd = adr + siz; adr < bnd; adr += dcache_line_size)
    781 		asm volatile ("dcbst 0,%0" :: "r"(adr));
    782 	asm volatile ("sync");
    783 }
    784 
    785 void
    786 _wbinv(uint32_t adr, uint32_t siz)
    787 {
    788 	uint32_t bnd;
    789 
    790 	asm volatile("eieio");
    791 	for (bnd = adr + siz; adr < bnd; adr += dcache_line_size)
    792 		asm volatile ("dcbf 0,%0" :: "r"(adr));
    793 	asm volatile ("sync");
    794 }
    795 
    796 void
    797 _inv(uint32_t adr, uint32_t siz)
    798 {
    799 	uint32_t bnd, off;
    800 
    801 	off = adr & (dcache_line_size - 1);
    802 	adr -= off;
    803 	siz += off;
    804 	asm volatile ("eieio");
    805 	if (off != 0) {
    806 		/* wbinv() leading unaligned dcache line */
    807 		asm volatile ("dcbf 0,%0" :: "r"(adr));
    808 		if (siz < dcache_line_size)
    809 			goto done;
    810 		adr += dcache_line_size;
    811 		siz -= dcache_line_size;
    812 	}
    813 	bnd = adr + siz;
    814 	off = bnd & (dcache_line_size - 1);
    815 	if (off != 0) {
    816 		/* wbinv() trailing unaligned dcache line */
    817 		asm volatile ("dcbf 0,%0" :: "r"(bnd)); /* it's OK */
    818 		if (siz < dcache_line_size)
    819 			goto done;
    820 		siz -= off;
    821 	}
    822 	for (bnd = adr + siz; adr < bnd; adr += dcache_line_size) {
    823 		/* inv() intermediate dcache lines if ever */
    824 		asm volatile ("dcbi 0,%0" :: "r"(adr));
    825 	}
    826   done:
    827 	asm volatile ("sync");
    828 }
    829 
    830 static inline uint32_t
    831 mfmsr(void)
    832 {
    833 	uint32_t msr;
    834 
    835 	asm volatile ("mfmsr %0" : "=r"(msr));
    836 	return msr;
    837 }
    838 
    839 static inline void
    840 mtmsr(uint32_t msr)
    841 {
    842 	asm volatile ("mtmsr %0" : : "r"(msr));
    843 }
    844 
    845 static inline uint32_t
    846 cputype(void)
    847 {
    848 	uint32_t pvr;
    849 
    850 	asm volatile ("mfpvr %0" : "=r"(pvr));
    851 	return pvr >> 16;
    852 }
    853 
    854 static inline u_quad_t
    855 mftb(void)
    856 {
    857 	u_long scratch;
    858 	u_quad_t tb;
    859 
    860 	asm ("1: mftbu %0; mftb %0+1; mftbu %1; cmpw %0,%1; bne 1b"
    861 	    : "=r"(tb), "=r"(scratch));
    862 	return tb;
    863 }
    864 
    865 static void
    866 init_uart(unsigned base, unsigned speed, uint8_t lcr)
    867 {
    868 	unsigned div;
    869 
    870 	div = busclock / speed / 16;
    871 	UART_WRITE(base, LCR, 0x80);		/* turn on DLAB bit */
    872 	UART_WRITE(base, FCR, 0x00);
    873 	UART_WRITE(base, DMB, div >> 8);	/* set speed */
    874 	UART_WRITE(base, DLB, div & 0xff);
    875 	UART_WRITE(base, LCR, lcr);
    876 	UART_WRITE(base, FCR, 0x07);		/* FIFO on, TXRX FIFO reset */
    877 	UART_WRITE(base, IER, 0x00);		/* make sure INT disabled */
    878 }
    879 
    880 /* talk to satellite processor */
    881 static void
    882 send_sat(char *msg)
    883 {
    884 	unsigned savedbase;
    885 
    886 	savedbase = uart1base;
    887 	uart1base = uart2base;
    888 	while (*msg)
    889 		putchar(*msg++);
    890 	uart1base = savedbase;
    891 }
    892 
    893 static int
    894 send_iomega(int power, int led, int rate, int fan, int high, int low,
    895     uint8_t *st)
    896 {
    897 	unsigned i, savedbase;
    898 	static uint8_t cur_state[IOMEGA_PACKETSIZE];
    899 	uint8_t buf[IOMEGA_PACKETSIZE];
    900 
    901 	buf[IOMEGA_POWER] =
    902 	    power >= 0 ? power : cur_state[IOMEGA_POWER];
    903 	buf[IOMEGA_LED] =
    904 	    led >= 0 ? led : cur_state[IOMEGA_LED];
    905 	buf[IOMEGA_FLASH_RATE] =
    906 	    rate >= 0 ? rate : cur_state[IOMEGA_FLASH_RATE];
    907 	buf[IOMEGA_FAN] =
    908 	    fan >= 0 ? fan : cur_state[IOMEGA_FAN];
    909 	buf[IOMEGA_HIGH_TEMP] =
    910 	    high >= 0 ? high : cur_state[IOMEGA_HIGH_TEMP];
    911 	buf[IOMEGA_LOW_TEMP] =
    912 	    low >= 0 ? low : cur_state[IOMEGA_LOW_TEMP];
    913 	buf[IOMEGA_ID] = 7;	/* host id */
    914 	buf[IOMEGA_CHECKSUM] = (buf[IOMEGA_POWER] + buf[IOMEGA_LED] +
    915 	    buf[IOMEGA_FLASH_RATE] + buf[IOMEGA_FAN] +
    916 	    buf[IOMEGA_HIGH_TEMP] + buf[IOMEGA_LOW_TEMP] +
    917 	    buf[IOMEGA_ID]) & 0x7f;
    918 
    919 	savedbase = uart1base;
    920 	uart1base = uart2base;
    921 	for (i = 0; i < IOMEGA_PACKETSIZE; i++)
    922 		putchar(buf[i]);
    923 	for (i = 0; i < IOMEGA_PACKETSIZE; i++)
    924 		buf[i] = getchar();
    925 	uart1base = savedbase;
    926 	for (i = 0; i < IOMEGA_PACKETSIZE; i++)
    927 		printf("%02x", buf[i]);
    928 	printf("\n");
    929 
    930 	return 0;
    931 }
    932 
    933 void
    934 putchar(int c)
    935 {
    936 	unsigned timo, lsr;
    937 
    938 	if (c == '\n')
    939 		putchar('\r');
    940 
    941 	timo = 0x00100000;
    942 	do {
    943 		lsr = UART_READ(uart1base, LSR);
    944 	} while (timo-- > 0 && (lsr & LSR_THRE) == 0);
    945 	if (timo > 0)
    946 		UART_WRITE(uart1base, THR, c);
    947 }
    948 
    949 int
    950 getchar(void)
    951 {
    952 	unsigned lsr;
    953 
    954 	do {
    955 		lsr = UART_READ(uart1base, LSR);
    956 	} while ((lsr & LSR_DRDY) == 0);
    957 	return UART_READ(uart1base, RBR);
    958 }
    959 
    960 int
    961 tstchar(void)
    962 {
    963 	return (UART_READ(uart1base, LSR) & LSR_DRDY) != 0;
    964 }
    965 
    966 unsigned
    967 mpc107memsize()
    968 {
    969 	unsigned bankn, end, n, tag, val;
    970 
    971 	tag = pcimaketag(0, 0, 0);
    972 
    973 	if (brdtype == BRD_ENCOREPP1) {
    974 		/* the brd's PPCBOOT looks to have erroneous values */
    975 		unsigned tbl[] = {
    976 #define MPC106_MEMSTARTADDR1	0x80
    977 #define MPC106_EXTMEMSTARTADDR1	0x88
    978 #define MPC106_MEMENDADDR1	0x90
    979 #define MPC106_EXTMEMENDADDR1	0x98
    980 #define MPC106_MEMEN		0xa0
    981 #define	BK0_S	0x00000000
    982 #define	BK0_E	(128 << 20) - 1
    983 #define BK1_S	0x3ff00000
    984 #define BK1_E	0x3fffffff
    985 #define BK2_S	0x3ff00000
    986 #define BK2_E	0x3fffffff
    987 #define BK3_S	0x3ff00000
    988 #define BK3_E	0x3fffffff
    989 #define AR(v, s) ((((v) & SAR_MASK) >> SAR_SHIFT) << (s))
    990 #define XR(v, s) ((((v) & EAR_MASK) >> EAR_SHIFT) << (s))
    991 #define SAR_MASK 0x0ff00000
    992 #define SAR_SHIFT    20
    993 #define EAR_MASK 0x30000000
    994 #define EAR_SHIFT    28
    995 		AR(BK0_S, 0) | AR(BK1_S, 8) | AR(BK2_S, 16) | AR(BK3_S, 24),
    996 		XR(BK0_S, 0) | XR(BK1_S, 8) | XR(BK2_S, 16) | XR(BK3_S, 24),
    997 		AR(BK0_E, 0) | AR(BK1_E, 8) | AR(BK2_E, 16) | AR(BK3_E, 24),
    998 		XR(BK0_E, 0) | XR(BK1_E, 8) | XR(BK2_E, 16) | XR(BK3_E, 24),
    999 		};
   1000 		tag = pcimaketag(0, 0, 0);
   1001 		pcicfgwrite(tag, MPC106_MEMSTARTADDR1, tbl[0]);
   1002 		pcicfgwrite(tag, MPC106_EXTMEMSTARTADDR1, tbl[1]);
   1003 		pcicfgwrite(tag, MPC106_MEMENDADDR1, tbl[2]);
   1004 		pcicfgwrite(tag, MPC106_EXTMEMENDADDR1,	tbl[3]);
   1005 		pcicfgwrite(tag, MPC106_MEMEN, 1);
   1006 	}
   1007 
   1008 	bankn = 0;
   1009 	val = pcicfgread(tag, MPC106_MEMEN);
   1010 	for (n = 0; n < 4; n++) {
   1011 		if ((val & (1U << n)) == 0)
   1012 			break;
   1013 		bankn = n;
   1014 	}
   1015 	bankn = bankn * 8;
   1016 
   1017 	val = pcicfgread(tag, MPC106_EXTMEMENDADDR1);
   1018 	end =  ((val >> bankn) & 0x03) << 28;
   1019 	val = pcicfgread(tag, MPC106_MEMENDADDR1);
   1020 	end |= ((val >> bankn) & 0xff) << 20;
   1021 	end |= 0xfffff;
   1022 
   1023 	return (end + 1); /* assume the end address matches total amount */
   1024 }
   1025 
   1026 struct fis_dir_entry {
   1027 	char		name[16];
   1028 	uint32_t	startaddr;
   1029 	uint32_t	loadaddr;
   1030 	uint32_t	flashsize;
   1031 	uint32_t	entryaddr;
   1032 	uint32_t	filesize;
   1033 	char		pad[256 - (16 + 5 * sizeof(uint32_t))];
   1034 };
   1035 
   1036 #define FIS_LOWER_LIMIT	0xfff00000
   1037 
   1038 /*
   1039  * Look for a Redboot-style Flash Image System FIS-directory and
   1040  * return a pointer to the start address of the requested file.
   1041  */
   1042 static void *
   1043 redboot_fis_lookup(const char *filename)
   1044 {
   1045 	static const char FISdirname[16] = {
   1046 	    'F', 'I', 'S', ' ',
   1047 	    'd', 'i', 'r', 'e', 'c', 't', 'o', 'r', 'y', 0, 0, 0
   1048 	};
   1049 	struct fis_dir_entry *dir;
   1050 
   1051 	/*
   1052 	 * The FIS directory is usually in the last sector of the flash.
   1053 	 * But we do not know the sector size (erase size), so start
   1054 	 * at 0xffffff00 and scan backwards in steps of the FIS directory
   1055 	 * entry size (0x100).
   1056 	 */
   1057 	for (dir = (struct fis_dir_entry *)0xffffff00;
   1058 	    (uint32_t)dir >= FIS_LOWER_LIMIT; dir--)
   1059 		if (memcmp(dir->name, FISdirname, sizeof(FISdirname)) == 0)
   1060 			break;
   1061 	if ((uint32_t)dir < FIS_LOWER_LIMIT) {
   1062 		printf("No FIS directory found!\n");
   1063 		return NULL;
   1064 	}
   1065 
   1066 	/* Now find filename by scanning the directory from beginning. */
   1067 	dir = (struct fis_dir_entry *)dir->startaddr;
   1068 	while (dir->name[0] != 0xff && (uint32_t)dir < 0xffffff00) {
   1069 		if (strcmp(dir->name, filename) == 0)
   1070 			return (void *)dir->startaddr;	/* found */
   1071 		dir++;
   1072 	}
   1073 	printf("\"%s\" not found in FIS directory!\n", filename);
   1074 	return NULL;
   1075 }
   1076 
   1077 static void
   1078 read_mac_string(uint8_t *mac, char *p)
   1079 {
   1080 	int i;
   1081 
   1082 	for (i = 0; i < 6; i++, p += 3)
   1083 		*mac++ = read_hex(p);
   1084 }
   1085 
   1086 /*
   1087  * For cost saving reasons some NAS boxes lack SEEPROM for NIC's
   1088  * ethernet address and keep it in their Flash memory instead.
   1089  */
   1090 void
   1091 read_mac_from_flash(uint8_t *mac)
   1092 {
   1093 	uint8_t *p;
   1094 
   1095 	switch (brdtype) {
   1096 	case BRD_SYNOLOGY:
   1097 		p = redboot_fis_lookup("vendor");
   1098 		if (p == NULL)
   1099 			break;
   1100 		memcpy(mac, p, 6);
   1101 		return;
   1102 	case BRD_DLINKDSM:
   1103 		read_mac_string(mac, (char *)0xfff0ff80);
   1104 		return;
   1105 	default:
   1106 		printf("Warning: This board has no known method defined "
   1107 		    "to determine its MAC address!\n");
   1108 		break;
   1109 	}
   1110 
   1111 	/* set to 00:00:00:00:00:00 in case of error */
   1112 	memset(mac, 0, 6);
   1113 }
   1114