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