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