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