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