Home | History | Annotate | Line # | Download | only in altboot
brdsetup.c revision 1.31
      1 /* $NetBSD: brdsetup.c,v 1.31 2012/04/16 16:55:29 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 ## 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), 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), 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 
    451 void
    452 encpcifix(struct brdprop *brd)
    453 {
    454 	unsigned ide, irq, net, pcib, steer, val;
    455 
    456 #define	STEER(v, b) (((v) & (b)) ? "edge" : "level")
    457 	pcib = pcimaketag(0, 22, 0);
    458 	ide  = pcimaketag(0, 22, 1);
    459 	net  = pcimaketag(0, 25, 0);
    460 
    461 	/*
    462 	 * //// VIA PIRQ ////
    463 	 * 0x57/56/55/54 - Dx CB Ax xS
    464 	 */
    465 	val = pcicfgread(pcib, 0x54);	/* Dx CB Ax xs */
    466 	steer = val & 0xf;
    467 	irq = (val >> 12) & 0xf;	/* 15:12 */
    468 	if (irq) {
    469 		printf("pin A -> irq %d, %s\n",
    470 			irq, STEER(steer, 0x1));
    471 	}
    472 	irq = (val >> 16) & 0xf;	/* 19:16 */
    473 	if (irq) {
    474 		printf("pin B -> irq %d, %s\n",
    475 			irq, STEER(steer, 0x2));
    476 	}
    477 	irq = (val >> 20) & 0xf;	/* 23:20 */
    478 	if (irq) {
    479 		printf("pin C -> irq %d, %s\n",
    480 			irq, STEER(steer, 0x4));
    481 	}
    482 	irq = (val >> 28);		/* 31:28 */
    483 	if (irq) {
    484 		printf("pin D -> irq %d, %s\n",
    485 			irq, STEER(steer, 0x8));
    486 	}
    487 #if 0
    488 	/*
    489 	 * //// IDE fixup ////
    490 	 * - "native mode" (ide 0x09)
    491 	 */
    492 
    493 	/* ide: 0x09 - programming interface; 1000'SsPp */
    494 	val = pcicfgread(ide, 0x08) & 0xffff00ff;
    495 	pcicfgwrite(ide, 0x08, val | (0x8f << 8));
    496 
    497 	/* ide: 0x10-20 - leave them PCI memory space assigned */
    498 #else
    499 	/*
    500 	 * //// IDE fixup ////
    501 	 * - "compatiblity mode" (ide 0x09)
    502 	 * - remove PCI pin assignment (ide 0x3d)
    503 	 */
    504 
    505 	/* ide: 0x09 - programming interface; 1000'SsPp */
    506 	val = pcicfgread(ide, 0x08) & 0xffff00ff;
    507 	val |= (0x8a << 8);
    508 	pcicfgwrite(ide, 0x08, val);
    509 
    510 	/* ide: 0x10-20 */
    511 	/*
    512 	 * experiment shows writing ide: 0x09 changes these
    513 	 * register behaviour. The pcicfgwrite() above writes
    514 	 * 0x8a at ide: 0x09 to make sure legacy IDE.  Then
    515 	 * reading BAR0-3 is to return value 0s even though
    516 	 * pcisetup() has written range assignments.  Value
    517 	 * overwrite makes no effect. Having 0x8f for native
    518 	 * PCIIDE doesn't change register values and brings no
    519 	 * weirdness.
    520 	 */
    521 
    522 	/* ide: 0x3d/3c - turn off PCI pin */
    523 	val = pcicfgread(ide, 0x3c) & 0xffff00ff;
    524 	pcicfgwrite(ide, 0x3c, val);
    525 #endif
    526 	/*
    527 	 * //// USBx2, audio, and modem fixup ////
    528 	 * - disable USB #0 and #1 (pcib 0x48 and 0x85)
    529 	 * - disable AC97 audio and MC97 modem (pcib 0x85)
    530 	 */
    531 
    532 	/* pcib: 0x48 - disable USB #0 at function 2 */
    533 	val = pcicfgread(pcib, 0x48);
    534 	pcicfgwrite(pcib, 0x48, val | 04);
    535 
    536 	/* pcib: 0x85 - disable USB #1 at function 3 */
    537 	/* pcib: 0x85 - disable AC97/MC97 at function 5/6 */
    538 	val = pcicfgread(pcib, 0x84);
    539 	pcicfgwrite(pcib, 0x84, val | 0x1c00);
    540 
    541 	/*
    542 	 * //// fxp fixup ////
    543 	 * - use PCI pin A line 25 (fxp 0x3d/3c)
    544 	 */
    545 	/* 0x3d/3c - PCI pin/line */
    546 	val = pcicfgread(net, 0x3c) & 0xffff0000;
    547 	val |= (('A' - '@') << 8) | 25;
    548 	pcicfgwrite(net, 0x3c, val);
    549 }
    550 
    551 void
    552 motsetup(struct brdprop *brd)
    553 {
    554 
    555 #ifdef COSNAME
    556 	brd->consname = CONSNAME;
    557 #endif
    558 #ifdef CONSPORT
    559 	brd->consport = CONSPORT;
    560 #endif
    561 #ifdef CONSSPEED
    562 	brd->consspeed = CONSSPEED;
    563 #endif
    564 }
    565 
    566 void
    567 motbrdfix(struct brdprop *brd)
    568 {
    569 
    570 /*
    571  * WinBond/Symphony Lab 83C553 with PC87308 "SuperIO"
    572  *
    573  *	0.11.0	10ad.0565	PCI-ISA bridge
    574  *	0.11.1	10ad.0105	IDE (slide)
    575  */
    576 }
    577 
    578 void
    579 motpcifix(struct brdprop *brd)
    580 {
    581 	unsigned ide, net, pcib, steer, val;
    582 	int line;
    583 
    584 	pcib = pcimaketag(0, 11, 0);
    585 	ide  = pcimaketag(0, 11, 1);
    586 	net  = pcimaketag(0, 15, 0);
    587 
    588 	/*
    589 	 * //// WinBond PIRQ ////
    590 	 * 0x40 - bit 5 (0x20) indicates PIRQ presense
    591 	 * 0x60 - PIRQ interrupt routing steer
    592 	 */
    593 	if (pcicfgread(pcib, 0x40) & 0x20) {
    594 		steer = pcicfgread(pcib, 0x60);
    595 		if ((steer & 0x80808080) == 0x80808080)
    596 			printf("PIRQ[0-3] disabled\n");
    597 		else {
    598 			unsigned i, v = steer;
    599 			for (i = 0; i < 4; i++, v >>= 8) {
    600 				if ((v & 0x80) != 0 || (v & 0xf) == 0)
    601 					continue;
    602 				printf("PIRQ[%d]=%d\n", i, v & 0xf);
    603 				}
    604 			}
    605 		}
    606 #if 1
    607 	/*
    608 	 * //// IDE fixup -- case A ////
    609 	 * - "native PCI mode" (ide 0x09)
    610 	 * - don't use ISA IRQ14/15 (pcib 0x43)
    611 	 * - native IDE for both channels (ide 0x40)
    612 	 * - LEGIRQ bit 11 steers interrupt to pin C (ide 0x40)
    613 	 * - sign as PCI pin C line 11 (ide 0x3d/3c)
    614 	 */
    615 	/* ide: 0x09 - programming interface; 1000'SsPp */
    616 	val = pcicfgread(ide, 0x08);
    617 	val &= 0xffff00ff;
    618 	pcicfgwrite(ide, 0x08, val | (0x8f << 8));
    619 
    620 	/* pcib: 0x43 - IDE interrupt routing */
    621 	val = pcicfgread(pcib, 0x40) & 0x00ffffff;
    622 	pcicfgwrite(pcib, 0x40, val);
    623 
    624 	/* pcib: 0x45/44 - PCI interrupt routing */
    625 	val = pcicfgread(pcib, 0x44) & 0xffff0000;
    626 	pcicfgwrite(pcib, 0x44, val);
    627 
    628 	/* ide: 0x41/40 - IDE channel */
    629 	val = pcicfgread(ide, 0x40) & 0xffff0000;
    630 	val |= (1 << 11) | 0x33; /* LEGIRQ turns on PCI interrupt */
    631 	pcicfgwrite(ide, 0x40, val);
    632 
    633 	/* ide: 0x3d/3c - use PCI pin C/line 11 */
    634 	val = pcicfgread(ide, 0x3c) & 0xffffff00;
    635 	val |= 11; /* pin designation is hardwired to pin A */
    636 	pcicfgwrite(ide, 0x3c, val);
    637 #else
    638 	/*
    639 	 * //// IDE fixup -- case B ////
    640 	 * - "compatiblity mode" (ide 0x09)
    641 	 * - IDE primary/secondary interrupt routing (pcib 0x43)
    642 	 * - PCI interrupt routing (pcib 0x45/44)
    643 	 * - no PCI pin/line assignment (ide 0x3d/3c)
    644 	 */
    645 	/* ide: 0x09 - programming interface; 1000'SsPp */
    646 	val = pcicfgread(ide, 0x08);
    647 	val &= 0xffff00ff;
    648 	pcicfgwrite(ide, 0x08, val | (0x8a << 8));
    649 
    650 	/* pcib: 0x43 - IDE interrupt routing */
    651 	val = pcicfgread(pcib, 0x40) & 0x00ffffff;
    652 	pcicfgwrite(pcib, 0x40, val | (0xee << 24));
    653 
    654 	/* ide: 0x45/44 - PCI interrupt routing */
    655 	val = pcicfgread(ide, 0x44) & 0xffff0000;
    656 	pcicfgwrite(ide, 0x44, val);
    657 
    658 	/* ide: 0x3d/3c - turn off PCI pin/line */
    659 	val = pcicfgread(ide, 0x3c) & 0xffff0000;
    660 	pcicfgwrite(ide, 0x3c, val);
    661 #endif
    662 
    663 	/*
    664 	 * //// fxp fixup ////
    665 	 * - use PCI pin A line 15 (fxp 0x3d/3c)
    666 	 */
    667 	val = pcicfgread(net, 0x3c) & 0xffff0000;
    668 	pcidecomposetag(net, NULL, &line, NULL);
    669 	val |= (('A' - '@') << 8) | line;
    670 	pcicfgwrite(net, 0x3c, val);
    671 }
    672 
    673 void
    674 kurosetup(struct brdprop *brd)
    675 {
    676 
    677 	if (PCI_VENDOR(pcicfgread(pcimaketag(0, 11, 0), PCI_ID_REG)) == 0x10ec)
    678 		brd->extclk = 32768000; /* decr 2457600Hz */
    679 	else
    680 		brd->extclk = 32521333; /* decr 2439100Hz */
    681 }
    682 
    683 void
    684 kurobrdfix(struct brdprop *brd)
    685 {
    686 
    687 	init_uart(uart2base, 9600, LCR_8BITS | LCR_PEVEN);
    688 	/* Stop Watchdog */
    689 	send_sat("AAAAFFFFJJJJ>>>>VVVV>>>>ZZZZVVVVKKKK");
    690 }
    691 
    692 void
    693 kuroreset()
    694 {
    695 
    696 	send_sat("CCGG");
    697 	/*NOTREACHED*/
    698 }
    699 
    700 void
    701 synosetup(struct brdprop *brd)
    702 {
    703 
    704 	if (1) /* 200 and 266MHz models */
    705 		brd->extclk = 33164691; /* from Synology/Linux source */
    706 	else   /* 400MHz models XXX how to check? */
    707 		brd->extclk = 33165343;
    708 }
    709 
    710 void
    711 synobrdfix(struct brdprop *brd)
    712 {
    713 
    714 	init_uart(uart2base, 9600, LCR_8BITS | LCR_PNONE);
    715 	/* beep, power LED on, status LED off */
    716 	send_sat("247");
    717 }
    718 
    719 void
    720 synopcifix(struct brdprop *brd)
    721 {
    722 	static const char csmodel[4][7] = {
    723 		"CS406e", "CS406", "RS406", "CS407e"
    724 	};
    725 	volatile uint8_t *cpld = (volatile uint8_t *)0xff000000;
    726 	uint8_t pwrstate;
    727 
    728 	if (nata > 1) {
    729 		/*
    730 		 * CS/RS stations power-up their disks one after another.
    731 		 * We have to watch over the current power state in a CPLD
    732 		 * register, until all disks become available.
    733 		 */
    734 		printf("CPLD V1.%d for model %s\n", cpld[2] & 3,
    735 		    csmodel[(cpld[2] & 0x0c) >> 2]);
    736 		cpld[0] = 0x00; /* all drive LEDs blinking yellow */
    737 		do {
    738 			delay(1000 * 1000);
    739 			pwrstate = cpld[1];
    740 			printf("Power state: %02x\r", pwrstate);
    741 		} while (pwrstate != 0xff);
    742 		putchar('\n');
    743 	}
    744 }
    745 
    746 void
    747 synolaunch(struct brdprop *brd)
    748 {
    749 	volatile uint8_t *cpld = (volatile uint8_t *)0xff000000;
    750 	struct dkdev_ata *sata1, *sata2;
    751 
    752 	if (nata > 1) {
    753 		/* enable drive LEDs for active disk drives on CS/RS models */
    754 		sata1 = lata[0].drv;
    755 		sata2 = lata[1].drv;
    756 		cpld[0] = (sata1->presense[0] ? 0x80 : 0xc0) |
    757 		    (sata1->presense[1] ? 0x20 : 0x30) |
    758 		    (sata2->presense[0] ? 0x08 : 0x0c) |
    759 		    (sata2->presense[1] ? 0x02 : 0x03);
    760 	}
    761 }
    762 
    763 void
    764 synoreset()
    765 {
    766 
    767 	send_sat("C");
    768 	/*NOTREACHED*/
    769 }
    770 
    771 void
    772 qnapbrdfix(struct brdprop *brd)
    773 {
    774 
    775 	init_uart(uart2base, 19200, LCR_8BITS | LCR_PNONE);
    776 	/* beep, status LED red */
    777 	send_sat("PW");
    778 }
    779 
    780 void
    781 qnapreset()
    782 {
    783 
    784 	send_sat("f");
    785 	/*NOTREACHED*/
    786 }
    787 
    788 void
    789 iomegabrdfix(struct brdprop *brd)
    790 {
    791 
    792 	init_uart(uart2base, 9600, LCR_8BITS | LCR_PNONE);
    793 	/* LED flashing blue, fan auto, turn on at 50C, turn off at 45C */
    794 	send_iomega('b', 'd', 2, 'a', 50, 45);
    795 }
    796 
    797 void
    798 iomegareset()
    799 {
    800 
    801 	send_iomega('g', 0, 0, 0, 0, 0);
    802 	/*NOTREACHED*/
    803 }
    804 
    805 void
    806 dlinkbrdfix(struct brdprop *brd)
    807 {
    808 
    809 	init_uart(uart2base, 9600, LCR_8BITS | LCR_PNONE);
    810 	send_sat("SYN\n");
    811 	send_sat("ZWO\n");	/* power LED solid on */
    812 }
    813 
    814 void
    815 nhnasbrdfix(struct brdprop *brd)
    816 {
    817 
    818 	/* status LED off, USB-LEDs on, low-speed fan */
    819 	NHGPIO_WRITE(0x04);
    820 }
    821 
    822 void
    823 nhnasreset()
    824 {
    825 
    826 	/* status LED on, assert system-reset to all devices */
    827 	NHGPIO_WRITE(0x02);
    828 	delay(100000);
    829 	/*NOTREACHED*/
    830 }
    831 
    832 void
    833 kurot4brdfix(struct brdprop *brd)
    834 {
    835 
    836 	init_uart(uart2base, 38400, LCR_8BITS | LCR_PEVEN);
    837 }
    838 
    839 void
    840 _rtt(void)
    841 {
    842 	uint32_t msr;
    843 
    844 	netif_shutdown_all();
    845 
    846 	if (brdprop->reset != NULL)
    847 		(*brdprop->reset)();
    848 	else {
    849 		msr = mfmsr();
    850 		msr &= ~PSL_EE;
    851 		mtmsr(msr);
    852 		asm volatile ("sync; isync");
    853 		asm volatile("mtspr %0,%1" : : "K"(81), "r"(0));
    854 		msr &= ~(PSL_ME | PSL_DR | PSL_IR);
    855 		mtmsr(msr);
    856 		asm volatile ("sync; isync");
    857 		run(0, 0, 0, 0, (void *)0xFFF00100); /* reset entry */
    858 	}
    859 	/*NOTREACHED*/
    860 }
    861 
    862 satime_t
    863 getsecs(void)
    864 {
    865 	u_quad_t tb = mftb();
    866 
    867 	return (tb / ticks_per_sec);
    868 }
    869 
    870 /*
    871  * Wait for about n microseconds (at least!).
    872  */
    873 void
    874 delay(u_int n)
    875 {
    876 	u_quad_t tb;
    877 	u_long scratch, tbh, tbl;
    878 
    879 	tb = mftb();
    880 	tb += (n * 1000 + ns_per_tick - 1) / ns_per_tick;
    881 	tbh = tb >> 32;
    882 	tbl = tb;
    883 	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));
    884 }
    885 
    886 void
    887 _wb(uint32_t adr, uint32_t siz)
    888 {
    889 	uint32_t bnd;
    890 
    891 	asm volatile("eieio");
    892 	for (bnd = adr + siz; adr < bnd; adr += dcache_line_size)
    893 		asm volatile ("dcbst 0,%0" :: "r"(adr));
    894 	asm volatile ("sync");
    895 }
    896 
    897 void
    898 _wbinv(uint32_t adr, uint32_t siz)
    899 {
    900 	uint32_t bnd;
    901 
    902 	asm volatile("eieio");
    903 	for (bnd = adr + siz; adr < bnd; adr += dcache_line_size)
    904 		asm volatile ("dcbf 0,%0" :: "r"(adr));
    905 	asm volatile ("sync");
    906 }
    907 
    908 void
    909 _inv(uint32_t adr, uint32_t siz)
    910 {
    911 	uint32_t bnd, off;
    912 
    913 	off = adr & (dcache_line_size - 1);
    914 	adr -= off;
    915 	siz += off;
    916 	asm volatile ("eieio");
    917 	if (off != 0) {
    918 		/* wbinv() leading unaligned dcache line */
    919 		asm volatile ("dcbf 0,%0" :: "r"(adr));
    920 		if (siz < dcache_line_size)
    921 			goto done;
    922 		adr += dcache_line_size;
    923 		siz -= dcache_line_size;
    924 	}
    925 	bnd = adr + siz;
    926 	off = bnd & (dcache_line_size - 1);
    927 	if (off != 0) {
    928 		/* wbinv() trailing unaligned dcache line */
    929 		asm volatile ("dcbf 0,%0" :: "r"(bnd)); /* it's OK */
    930 		if (siz < dcache_line_size)
    931 			goto done;
    932 		siz -= off;
    933 	}
    934 	for (bnd = adr + siz; adr < bnd; adr += dcache_line_size) {
    935 		/* inv() intermediate dcache lines if ever */
    936 		asm volatile ("dcbi 0,%0" :: "r"(adr));
    937 	}
    938   done:
    939 	asm volatile ("sync");
    940 }
    941 
    942 static inline uint32_t
    943 mfmsr(void)
    944 {
    945 	uint32_t msr;
    946 
    947 	asm volatile ("mfmsr %0" : "=r"(msr));
    948 	return msr;
    949 }
    950 
    951 static inline void
    952 mtmsr(uint32_t msr)
    953 {
    954 	asm volatile ("mtmsr %0" : : "r"(msr));
    955 }
    956 
    957 static inline uint32_t
    958 cputype(void)
    959 {
    960 	uint32_t pvr;
    961 
    962 	asm volatile ("mfpvr %0" : "=r"(pvr));
    963 	return pvr >> 16;
    964 }
    965 
    966 static inline u_quad_t
    967 mftb(void)
    968 {
    969 	u_long scratch;
    970 	u_quad_t tb;
    971 
    972 	asm ("1: mftbu %0; mftb %0+1; mftbu %1; cmpw %0,%1; bne 1b"
    973 	    : "=r"(tb), "=r"(scratch));
    974 	return tb;
    975 }
    976 
    977 static void
    978 init_uart(unsigned base, unsigned speed, uint8_t lcr)
    979 {
    980 	unsigned div;
    981 
    982 	div = busclock / speed / 16;
    983 	UART_WRITE(base, LCR, 0x80);		/* turn on DLAB bit */
    984 	UART_WRITE(base, FCR, 0x00);
    985 	UART_WRITE(base, DMB, div >> 8);	/* set speed */
    986 	UART_WRITE(base, DLB, div & 0xff);
    987 	UART_WRITE(base, LCR, lcr);
    988 	UART_WRITE(base, FCR, 0x07);		/* FIFO on, TXRX FIFO reset */
    989 	UART_WRITE(base, IER, 0x00);		/* make sure INT disabled */
    990 }
    991 
    992 /* talk to satellite processor */
    993 static void
    994 send_sat(char *msg)
    995 {
    996 	unsigned savedbase;
    997 
    998 	savedbase = uart1base;
    999 	uart1base = uart2base;
   1000 	while (*msg)
   1001 		putchar(*msg++);
   1002 	uart1base = savedbase;
   1003 }
   1004 
   1005 #ifdef DEBUG
   1006 static void
   1007 iomega_debug(const char *txt, uint8_t buf[])
   1008 {
   1009 	int i;
   1010 
   1011 	printf("%s:", txt);
   1012 	for (i = 0; i < IOMEGA_PACKETSIZE; i++)
   1013 		printf(" %02x", buf[i]);
   1014 	putchar('\n');
   1015 }
   1016 #endif /* DEBUG */
   1017 
   1018 static void
   1019 send_iomega(int power, int led, int rate, int fan, int high, int low)
   1020 {
   1021 	uint8_t buf[IOMEGA_PACKETSIZE];
   1022 	unsigned i, savedbase;
   1023 
   1024 	savedbase = uart1base;
   1025 	uart1base = uart2base;
   1026 
   1027 	/* first flush the receive buffer */
   1028   again:
   1029 	while (tstchar())
   1030 		(void)getchar();
   1031 	delay(20000);
   1032 	if (tstchar())
   1033 		goto again;
   1034 	/*
   1035 	 * Now synchronize the transmitter by sending 0x00
   1036 	 * until we receive a status reply.
   1037 	 */
   1038 	do {
   1039 		putchar(0);
   1040 		delay(50000);
   1041 	} while (!tstchar());
   1042 
   1043 	for (i = 0; i < IOMEGA_PACKETSIZE; i++)
   1044 		buf[i] = getchar();
   1045 #ifdef DEBUG
   1046 	uart1base = savedbase;
   1047 	iomega_debug("68HC908 status", buf);
   1048 	uart1base = uart2base;
   1049 #endif
   1050 
   1051 	/* send command */
   1052 	buf[IOMEGA_POWER] = power;
   1053 	buf[IOMEGA_LED] = led;
   1054 	buf[IOMEGA_FLASH_RATE] = rate;
   1055 	buf[IOMEGA_FAN] = fan;
   1056 	buf[IOMEGA_HIGH_TEMP] = high;
   1057 	buf[IOMEGA_LOW_TEMP] = low;
   1058 	buf[IOMEGA_ID] = 7;	/* host id */
   1059 	buf[IOMEGA_CHECKSUM] = (buf[IOMEGA_POWER] + buf[IOMEGA_LED] +
   1060 	    buf[IOMEGA_FLASH_RATE] + buf[IOMEGA_FAN] +
   1061 	    buf[IOMEGA_HIGH_TEMP] + buf[IOMEGA_LOW_TEMP] +
   1062 	    buf[IOMEGA_ID]) & 0x7f;
   1063 #ifdef DEBUG
   1064 	uart1base = savedbase;
   1065 	iomega_debug("G2 sending", buf);
   1066 	uart1base = uart2base;
   1067 #endif
   1068 	for (i = 0; i < IOMEGA_PACKETSIZE; i++)
   1069 		putchar(buf[i]);
   1070 
   1071 	/* receive the reply */
   1072 	for (i = 0; i < IOMEGA_PACKETSIZE; i++)
   1073 		buf[i] = getchar();
   1074 #ifdef DEBUG
   1075 	uart1base = savedbase;
   1076 	iomega_debug("68HC908 reply", buf);
   1077 	uart1base = uart2base;
   1078 #endif
   1079 
   1080 	if (buf[0] == '#')
   1081 		goto again;  /* try again on error */
   1082 	uart1base = savedbase;
   1083 }
   1084 
   1085 void
   1086 putchar(int c)
   1087 {
   1088 	unsigned timo, lsr;
   1089 
   1090 	if (c == '\n')
   1091 		putchar('\r');
   1092 
   1093 	timo = 0x00100000;
   1094 	do {
   1095 		lsr = UART_READ(uart1base, LSR);
   1096 	} while (timo-- > 0 && (lsr & LSR_THRE) == 0);
   1097 	if (timo > 0)
   1098 		UART_WRITE(uart1base, THR, c);
   1099 }
   1100 
   1101 int
   1102 getchar(void)
   1103 {
   1104 	unsigned lsr;
   1105 
   1106 	do {
   1107 		lsr = UART_READ(uart1base, LSR);
   1108 	} while ((lsr & LSR_DRDY) == 0);
   1109 	return UART_READ(uart1base, RBR);
   1110 }
   1111 
   1112 int
   1113 tstchar(void)
   1114 {
   1115 
   1116 	return (UART_READ(uart1base, LSR) & LSR_DRDY) != 0;
   1117 }
   1118 
   1119 #define SAR_MASK 0x0ff00000
   1120 #define SAR_SHIFT    20
   1121 #define EAR_MASK 0x30000000
   1122 #define EAR_SHIFT    28
   1123 #define AR(v, s) ((((v) & SAR_MASK) >> SAR_SHIFT) << (s))
   1124 #define XR(v, s) ((((v) & EAR_MASK) >> EAR_SHIFT) << (s))
   1125 static void
   1126 set_mem_bounds(unsigned tag, unsigned bk_en, ...)
   1127 {
   1128 	unsigned mbst, mbxst, mben, mbxen;
   1129 	unsigned start, end;
   1130 	va_list ap;
   1131 	int i, sh;
   1132 
   1133 	va_start(ap, bk_en);
   1134 	mbst = mbxst = mben = mbxen = 0;
   1135 
   1136 	for (i = 0; i < 4; i++) {
   1137 		if ((bk_en & (1U << i)) != 0) {
   1138 			start = va_arg(ap, unsigned);
   1139 			end = va_arg(ap, unsigned);
   1140 		} else {
   1141 			start = 0x3ff00000;
   1142 			end = 0x3fffffff;
   1143 		}
   1144 		sh = i << 3;
   1145 		mbst |= AR(start, sh);
   1146 		mbxst |= XR(start, sh);
   1147 		mben |= AR(end, sh);
   1148 		mbxen |= XR(end, sh);
   1149 	}
   1150 	va_end(ap);
   1151 
   1152 	pcicfgwrite(tag, MPC106_MEMSTARTADDR1, mbst);
   1153 	pcicfgwrite(tag, MPC106_EXTMEMSTARTADDR1, mbxst);
   1154 	pcicfgwrite(tag, MPC106_MEMENDADDR1, mben);
   1155 	pcicfgwrite(tag, MPC106_EXTMEMENDADDR1,	mbxen);
   1156 	pcicfgwrite(tag, MPC106_MEMEN,
   1157 	    (pcicfgread(tag, MPC106_MEMEN) & ~0xff) | (bk_en & 0xff));
   1158 }
   1159 
   1160 static unsigned
   1161 mpc107memsize(void)
   1162 {
   1163 	unsigned bankn, end, n, tag, val;
   1164 
   1165 	tag = pcimaketag(0, 0, 0);
   1166 
   1167 	if (brdtype == BRD_ENCOREPP1) {
   1168 		/* the brd's PPCBOOT looks to have erroneous values */
   1169 		set_mem_bounds(tag, 1, 0x00000000, (128 << 20) - 1);
   1170 	} else if (brdtype == BRD_NH230NAS) {
   1171 		/*
   1172 		 * PPCBoot sets the end address to 0x7ffffff, although the
   1173 		 * board has just 64MB (0x3ffffff).
   1174 		 */
   1175 		set_mem_bounds(tag, 1, 0x00000000, 0x03ffffff);
   1176 	}
   1177 
   1178 	bankn = 0;
   1179 	val = pcicfgread(tag, MPC106_MEMEN);
   1180 	for (n = 0; n < 4; n++) {
   1181 		if ((val & (1U << n)) == 0)
   1182 			break;
   1183 		bankn = n;
   1184 	}
   1185 	bankn <<= 3;
   1186 
   1187 	val = pcicfgread(tag, MPC106_EXTMEMENDADDR1);
   1188 	end =  ((val >> bankn) & 0x03) << 28;
   1189 	val = pcicfgread(tag, MPC106_MEMENDADDR1);
   1190 	end |= ((val >> bankn) & 0xff) << 20;
   1191 	end |= 0xfffff;
   1192 
   1193 	return (end + 1); /* assume the end address matches total amount */
   1194 }
   1195 
   1196 struct fis_dir_entry {
   1197 	char		name[16];
   1198 	uint32_t	startaddr;
   1199 	uint32_t	loadaddr;
   1200 	uint32_t	flashsize;
   1201 	uint32_t	entryaddr;
   1202 	uint32_t	filesize;
   1203 	char		pad[256 - (16 + 5 * sizeof(uint32_t))];
   1204 };
   1205 
   1206 #define FIS_LOWER_LIMIT	0xfff00000
   1207 
   1208 /*
   1209  * Look for a Redboot-style Flash Image System FIS-directory and
   1210  * return a pointer to the start address of the requested file.
   1211  */
   1212 static void *
   1213 redboot_fis_lookup(const char *filename)
   1214 {
   1215 	static const char FISdirname[16] = {
   1216 	    'F', 'I', 'S', ' ',
   1217 	    'd', 'i', 'r', 'e', 'c', 't', 'o', 'r', 'y', 0, 0, 0
   1218 	};
   1219 	struct fis_dir_entry *dir;
   1220 
   1221 	/*
   1222 	 * The FIS directory is usually in the last sector of the flash.
   1223 	 * But we do not know the sector size (erase size), so start
   1224 	 * at 0xffffff00 and scan backwards in steps of the FIS directory
   1225 	 * entry size (0x100).
   1226 	 */
   1227 	for (dir = (struct fis_dir_entry *)0xffffff00;
   1228 	    (uint32_t)dir >= FIS_LOWER_LIMIT; dir--)
   1229 		if (memcmp(dir->name, FISdirname, sizeof(FISdirname)) == 0)
   1230 			break;
   1231 	if ((uint32_t)dir < FIS_LOWER_LIMIT) {
   1232 		printf("No FIS directory found!\n");
   1233 		return NULL;
   1234 	}
   1235 
   1236 	/* Now find filename by scanning the directory from beginning. */
   1237 	dir = (struct fis_dir_entry *)dir->startaddr;
   1238 	while (dir->name[0] != 0xff && (uint32_t)dir < 0xffffff00) {
   1239 		if (strcmp(dir->name, filename) == 0)
   1240 			return (void *)dir->startaddr;	/* found */
   1241 		dir++;
   1242 	}
   1243 	printf("\"%s\" not found in FIS directory!\n", filename);
   1244 	return NULL;
   1245 }
   1246 
   1247 static void
   1248 read_mac_string(uint8_t *mac, char *p)
   1249 {
   1250 	int i;
   1251 
   1252 	for (i = 0; i < 6; i++, p += 3)
   1253 		*mac++ = read_hex(p);
   1254 }
   1255 
   1256 /*
   1257  * For cost saving reasons some NAS boxes lack SEEPROM for NIC's
   1258  * ethernet address and keep it in their Flash memory instead.
   1259  */
   1260 void
   1261 read_mac_from_flash(uint8_t *mac)
   1262 {
   1263 	uint8_t *p;
   1264 
   1265 	switch (brdtype) {
   1266 	case BRD_SYNOLOGY:
   1267 		p = redboot_fis_lookup("vendor");
   1268 		if (p == NULL)
   1269 			break;
   1270 		memcpy(mac, p, 6);
   1271 		return;
   1272 	case BRD_DLINKDSM:
   1273 		read_mac_string(mac, (char *)0xfff0ff80);
   1274 		return;
   1275 	default:
   1276 		printf("Warning: This board has no known method defined "
   1277 		    "to determine its MAC address!\n");
   1278 		break;
   1279 	}
   1280 
   1281 	/* set to 00:00:00:00:00:00 in case of error */
   1282 	memset(mac, 0, 6);
   1283 }
   1284 
   1285 #ifdef DEBUG
   1286 void
   1287 sat_write(char *p, int len)
   1288 {
   1289 	unsigned savedbase;
   1290 
   1291 	savedbase = uart1base;
   1292 	uart1base = uart2base;
   1293 	while (len--)
   1294 		putchar(*p++);
   1295 	uart1base = savedbase;
   1296 }
   1297 
   1298 int
   1299 sat_getch(void)
   1300 {
   1301 	unsigned lsr;
   1302 
   1303 	do {
   1304 		lsr = UART_READ(uart2base, LSR);
   1305 	} while ((lsr & LSR_DRDY) == 0);
   1306 	return UART_READ(uart2base, RBR);
   1307 }
   1308 
   1309 int
   1310 sat_tstch(void)
   1311 {
   1312 
   1313 	return (UART_READ(uart2base, LSR) & LSR_DRDY) != 0;
   1314 }
   1315 #endif /* DEBUG */
   1316