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