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