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