Sun Jan 23 01:05:32 2011 UTC ()
change bootloader name to "altboot".  bump version and add README.


(nisimura)
diff -r1.1 -r1.2 src/sys/arch/sandpoint/stand/Makefile
diff -r0 -r1.1 src/sys/arch/sandpoint/stand/altboot/Makefile
diff -r0 -r1.1 src/sys/arch/sandpoint/stand/altboot/README.altboot
diff -r0 -r1.1 src/sys/arch/sandpoint/stand/altboot/brdsetup.c
diff -r0 -r1.1 src/sys/arch/sandpoint/stand/altboot/dev_net.c
diff -r0 -r1.1 src/sys/arch/sandpoint/stand/altboot/devopen.c
diff -r0 -r1.1 src/sys/arch/sandpoint/stand/altboot/dsk.c
diff -r0 -r1.1 src/sys/arch/sandpoint/stand/altboot/entry.S
diff -r0 -r1.1 src/sys/arch/sandpoint/stand/altboot/fxp.c
diff -r0 -r1.1 src/sys/arch/sandpoint/stand/altboot/globals.h
diff -r0 -r1.1 src/sys/arch/sandpoint/stand/altboot/kse.c
diff -r0 -r1.1 src/sys/arch/sandpoint/stand/altboot/main.c
diff -r0 -r1.1 src/sys/arch/sandpoint/stand/altboot/nif.c
diff -r0 -r1.1 src/sys/arch/sandpoint/stand/altboot/nvt.c
diff -r0 -r1.1 src/sys/arch/sandpoint/stand/altboot/pci.c
diff -r0 -r1.1 src/sys/arch/sandpoint/stand/altboot/pciide.c
diff -r0 -r1.1 src/sys/arch/sandpoint/stand/altboot/pcn.c
diff -r0 -r1.1 src/sys/arch/sandpoint/stand/altboot/printf.c
diff -r0 -r1.1 src/sys/arch/sandpoint/stand/altboot/rge.c
diff -r0 -r1.1 src/sys/arch/sandpoint/stand/altboot/siisata.c
diff -r0 -r1.1 src/sys/arch/sandpoint/stand/altboot/sip.c
diff -r0 -r1.1 src/sys/arch/sandpoint/stand/altboot/skg.c
diff -r0 -r1.1 src/sys/arch/sandpoint/stand/altboot/sme.c
diff -r0 -r1.1 src/sys/arch/sandpoint/stand/altboot/tlp.c
diff -r0 -r1.1 src/sys/arch/sandpoint/stand/altboot/vge.c
diff -r0 -r1.1 src/sys/arch/sandpoint/stand/altboot/wm.c
diff -r1.20 -r0 src/sys/arch/sandpoint/stand/netboot/Makefile
diff -r1.20 -r0 src/sys/arch/sandpoint/stand/netboot/nvt.c
diff -r1.22 -r0 src/sys/arch/sandpoint/stand/netboot/brdsetup.c
diff -r1.9 -r0 src/sys/arch/sandpoint/stand/netboot/dev_net.c
diff -r1.9 -r0 src/sys/arch/sandpoint/stand/netboot/pciide.c
diff -r1.12 -r0 src/sys/arch/sandpoint/stand/netboot/devopen.c
diff -r1.8 -r0 src/sys/arch/sandpoint/stand/netboot/dsk.c
diff -r1.7 -r0 src/sys/arch/sandpoint/stand/netboot/entry.S
diff -r1.7 -r0 src/sys/arch/sandpoint/stand/netboot/printf.c
diff -r1.11 -r0 src/sys/arch/sandpoint/stand/netboot/fxp.c
diff -r1.19 -r0 src/sys/arch/sandpoint/stand/netboot/globals.h
diff -r1.19 -r0 src/sys/arch/sandpoint/stand/netboot/pcn.c
diff -r1.19 -r0 src/sys/arch/sandpoint/stand/netboot/sip.c
diff -r1.6 -r0 src/sys/arch/sandpoint/stand/netboot/kse.c
diff -r1.6 -r0 src/sys/arch/sandpoint/stand/netboot/version
diff -r1.41 -r0 src/sys/arch/sandpoint/stand/netboot/main.c
diff -r1.3 -r0 src/sys/arch/sandpoint/stand/netboot/newvers.sh
diff -r1.3 -r0 src/sys/arch/sandpoint/stand/netboot/skg.c
diff -r1.13 -r0 src/sys/arch/sandpoint/stand/netboot/nif.c
diff -r1.13 -r0 src/sys/arch/sandpoint/stand/netboot/wm.c
diff -r1.14 -r0 src/sys/arch/sandpoint/stand/netboot/pci.c
diff -r1.17 -r0 src/sys/arch/sandpoint/stand/netboot/rge.c
diff -r1.15 -r0 src/sys/arch/sandpoint/stand/netboot/siisata.c
diff -r1.5 -r0 src/sys/arch/sandpoint/stand/netboot/sme.c
diff -r1.25 -r0 src/sys/arch/sandpoint/stand/netboot/tlp.c
diff -r1.18 -r0 src/sys/arch/sandpoint/stand/netboot/vge.c

cvs diff -r1.1 -r1.2 src/sys/arch/sandpoint/stand/Makefile (expand / switch to unified diff)

--- src/sys/arch/sandpoint/stand/Makefile 2009/07/20 11:43:08 1.1
+++ src/sys/arch/sandpoint/stand/Makefile 2011/01/23 01:05:29 1.2
@@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
1# $NetBSD: Makefile,v 1.1 2009/07/20 11:43:08 nisimura Exp $ 1# $NetBSD: Makefile,v 1.2 2011/01/23 01:05:29 nisimura Exp $
2 2
3SUBDIR= netboot 3SUBDIR= altboot
4 4
5.include <bsd.subdir.mk> 5.include <bsd.subdir.mk>

File Added: src/sys/arch/sandpoint/stand/altboot/Makefile
#	$NetBSD: Makefile,v 1.1 2011/01/23 01:05:30 nisimura Exp $

S=		${.CURDIR}/../../../..

PROG=		altboot
SRCS=		entry.S main.c brdsetup.c pci.c devopen.c dev_net.c nif.c \
		fxp.c tlp.c rge.c skg.c dsk.c pciide.c siisata.c printf.c
CLEANFILES+=	vers.c vers.o ${PROG} ${PROG}.bin
CFLAGS+=	-Wall -Wno-main -ffreestanding -msoft-float -mmultiple
CFLAGS+=	-Wmissing-prototypes -Wstrict-prototypes -Wpointer-arith
CPPFLAGS+=	-D_STANDALONE -DSUPPORT_DHCP
#CPPFLAGS+=	-DCONSNAME=\"com\" -DCONSPORT=0x3f8 -DCONSSPEED=115200
#CPPFLAGS+=	-DCONSNAME=\"eumb\" -DCONSPORT=0x4600 -DCONSSPEED=57600
CPPFLAGS+=	-nostdinc -I. -I${.OBJDIR} -I${S}
DBG=		-Os

# XXX SHOULD NOT NEED TO DEFINE THESE!
LIBCRT0=
LIBC=
LIBCRTBEGIN=
LIBCRTEND=

NOMAN=		# defined
STRIPFLAG=
BINMODE=	444

RELOC=		1000000
ENTRY=		_start


.if !make(obj) && !make(clean) && !make(cleandir)
.BEGIN:
	@[ -h machine ] || ln -s ${S}/arch/${MACHINE}/include machine
	@[ -h powerpc ] || ln -s ${S}/arch/powerpc/include powerpc
.NOPATH: machine powerpc
.endif
CLEANFILES+= machine powerpc

### find out what to use for libkern
KERN_AS=	library
.include "${S}/lib/libkern/Makefile.inc"
LIBKERN=	${KERNLIB}

### find out what to use for libz
Z_AS=		library
.include "${S}/lib/libz/Makefile.inc"
LIBZ=		${ZLIB}

### find out what to use for libsa
SA_AS=		library
SAMISCMAKEFLAGS= SA_USE_CREAD=yes SA_USE_LOADFILE=yes
.include "${S}/lib/libsa/Makefile.inc"
LIBSA=		${SALIB}

${PROG}: ${OBJS} ${LIBSA} ${LIBZ} ${LIBKERN}
	${HOST_SH} ${.CURDIR}/newvers.sh ${.CURDIR}/version
	${CC} -c vers.c
	${LD} -N -Ttext ${RELOC} -Bstatic -e ${ENTRY} -o ${PROG} \
	    ${OBJS} vers.o ${LIBSA} ${LIBZ} ${LIBKERN}
	${OBJCOPY} -S -O binary ${.TARGET} ${.TARGET}.bin

.include <bsd.prog.mk>

cleandir distclean: .WAIT cleanlibdir

cleanlibdir:
	-rm -rf lib

File Added: src/sys/arch/sandpoint/stand/altboot/README.altboot
/// notes about altboot ///

$NetBSD: README.altboot,v 1.1 2011/01/23 01:05:30 nisimura Exp $

Altboot is a functional bridge to fill the gap between a NAS product
custom bootloader and the NetBSD kernel startup environment.  Altboot
irons out and rectifies erroneously configured HW by product
bootloaders and prepares a sane runtime better suited for booting
NetBSD kernels.

- provides the foundation of a fast NetBSD porting cycle with functionalities
  product bootloaders don't have.
- facilitates a flexible and clean NetBSD implementation tailoured
  to target HW in detail, minimizing bumpy adjustments and hacks in
  locore asm and machdeps in very early kernel startup stage.
- levels out differences among similar-but-not-the-same porting
  targets to make it possible having common NetBSD kernels for them.
- builds and hands a bootinfo list to the NetBSD kernel.

Altboot is known working on two models.
- KuroBox with a popular U-Boot as the replacement of vendor proprietary

   U-Boot 1.1.4 LiSt 2.1.0 (Sep 21 2006 - 00:22:56) LinkStation / KuroBox

- Synology 101g+ with vendor custom PPCboot

   PPCBoot 2.0.0 (Mar  1 2005 - 15:31:41)

The standard use of altboot is to invoke it with a short script from
U-Boot/PPCboot, where the altboot image is stored in an unoccupied 128KB
section of the target's HW NOR flash.  Combined with standard
U-Boot/PPCboot functions, it is possible to boot a NetBSD kernel off
it right after power-on, without the help of manual intervention.  Note
that the original U-Boot/PPCboot still remains useful and altboot works
as a functional extension for them.

Altboot hands the following bootinfo records to the NetBSD/sandpoint
kernel.
- processor clock tick value driving MPC8241/8245.
- serial console selection.
- booted kernel filename and which device it was fetched from.
- Ethernet MAC address, if target HW lacks SEEPROM to store a unit unique
  value.
- product family indication.
- preloaded kernel module names (under development).

                             ### ### ###


File Added: src/sys/arch/sandpoint/stand/altboot/brdsetup.c
/* $NetBSD: brdsetup.c,v 1.1 2011/01/23 01:05:30 nisimura Exp $ */

/*-
 * Copyright (c) 2008 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by Tohru Nishimura.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include <sys/param.h>

#include <powerpc/oea/spr.h>

#include <lib/libsa/stand.h>
#include <lib/libsa/net.h>
#include <lib/libkern/libkern.h>

#include <machine/bootinfo.h>

#include "globals.h"

#define BRD_DECL(xxx) \
    void xxx ## setup(struct brdprop *); \
    void xxx ## brdfix(struct brdprop *); \
    void xxx ## pcifix(struct brdprop *); \
    void xxx ## reset(void)

BRD_DECL(mot);
BRD_DECL(enc);
BRD_DECL(kuro);
BRD_DECL(syno);
BRD_DECL(qnap);

static struct brdprop brdlist[] = {
    {
	"sandpoint",
	"Sandpoint X3",
	BRD_SANDPOINTX3,
	0,
	"com", 0x3f8, 115200,
	motsetup, motbrdfix, motpcifix },
    {
	"encpp1",
	"EnCore PP1",
	BRD_ENCOREPP1,
	0,
	"com", 0x3f8, 115200,
	encsetup, encbrdfix, encpcifix },
    {
	"kurobox",
	"KuroBox",
	BRD_KUROBOX,
	32768000,
	"eumb", 0x4600, 57600,
	kurosetup, kurobrdfix, kuropcifix },
    {
	"synology",
	"Synology DS",
	BRD_SYNOLOGY,
	33164691,	/* from Synology/Linux source */
	/* 33168000,		XXX better precision? */
	"eumb", 0x4500, 115200,
	synosetup, synobrdfix, synopcifix, synoreset },
    {
	"qnap",
	"QNAP TS-101",
	BRD_QNAPTS101,
	0,
	"eumb", 0x4500, 115200,
	NULL, NULL, qnappcifix },
    {
	"iomega",
	"IOMEGA Storcenter",
	BRD_STORCENTER,
	0,
	"eumb", 0x4500, 115200,
	NULL, NULL, NULL },
    {
	"unknown",
	"Unknown board",
	BRD_UNKNOWN,
	0,
	"eumb", 0x4500, 115200,
	NULL, NULL, NULL }, /* must be the last */
};

static struct brdprop *brdprop;
static uint32_t ticks_per_sec, ns_per_tick;

static void brdfixup(void);
static void setup(void);
static inline uint32_t cputype(void);
static inline u_quad_t mftb(void);
static void init_uart(unsigned, unsigned, uint8_t);
static void send_sat(char *);

const unsigned dcache_line_size = 32;		/* 32B linesize */
const unsigned dcache_range_size = 4 * 1024;	/* 16KB / 4-way */

unsigned uart1base;	/* console */
unsigned uart2base;	/* optional satellite processor */
#define THR		0
#define DLB		0
#define DMB		1
#define IER		1
#define FCR		2
#define LCR		3
#define  LCR_DLAB	0x80
#define  LCR_PEVEN	0x18
#define  LCR_PNONE	0x00
#define  LCR_8BITS	0x03
#define MCR		4
#define  MCR_RTS	0x02
#define  MCR_DTR	0x01
#define LSR		5
#define  LSR_THRE	0x20
#define DCR		0x11
#define UART_READ(base, r)	*(volatile char *)(base + (r))
#define UART_WRITE(base, r, v)	*(volatile char *)(base + (r)) = (v)

void brdsetup(void);	/* called by entry.S */

void
brdsetup(void)
{
	static uint8_t pci_to_memclk[] = {
		30, 30, 10, 10, 20, 10, 10, 10,
		10, 20, 20, 15, 20, 15, 20, 30,
		30, 40, 15, 40, 20, 25, 20, 40,
		25, 20, 10, 20, 15, 15, 20, 00
	};
	static uint8_t mem_to_cpuclk[] = {
		25, 30, 45, 20, 20, 00, 10, 30,
		30, 20, 45, 30, 25, 35, 30, 35,
		20, 25, 20, 30, 35, 40, 40, 20,
		30, 25, 40, 30, 30, 25, 35, 00
	};
	char *consname;
	int consport;
	uint32_t extclk;
	unsigned pchb, pcib, val;
	extern struct btinfo_memory bi_mem;
	extern struct btinfo_console bi_cons;
	extern struct btinfo_clock bi_clk;
	extern struct btinfo_prodfamily bi_fam;

	/*
	 * CHRP specification "Map-B" BAT012 layout
	 *   BAT0 0000-0000 (256MB) SDRAM
	 *   BAT1 8000-0000 (256MB) PCI mem space
	 *   BAT2 fc00-0000 (64MB)  EUMB, PCI I/O space, misc devs, flash
	 *
	 * EUMBBAR is at fc00-0000.
	 */
	pchb = pcimaketag(0, 0, 0);
	pcicfgwrite(pchb, 0x78, 0xfc000000);

	brdtype = BRD_UNKNOWN;
	extclk = EXT_CLK_FREQ;	/* usually 33MHz */
	busclock = 0;

	if (pcifinddev(0x10ad, 0x0565, &pcib) == 0) {
		brdtype = BRD_SANDPOINTX3;
	}
	else if (pcifinddev(0x1106, 0x0686, &pcib) == 0) {
		brdtype = BRD_ENCOREPP1;
	}
	else if ((pcicfgread(pcimaketag(0, 11, 0), PCI_CLASS_REG) >> 16) ==
	    PCI_CLASS_ETH) {
		/* tlp (ADMtek AN985) or re (RealTek 8169S) at dev 11 */
		brdtype = BRD_KUROBOX;
	}
	else if (PCI_VENDOR(pcicfgread(pcimaketag(0, 15, 0), PCI_ID_REG)) ==
	    0x11ab) {				/* PCI_VENDOR_MARVELL */
		brdtype = BRD_SYNOLOGY;
	}
	else if (PCI_VENDOR(pcicfgread(pcimaketag(0, 15, 0), PCI_ID_REG)) ==
	    0x8086) {				/* PCI_VENDOR_INTEL */
		brdtype = BRD_QNAPTS101;
	}
	else if (PCI_VENDOR(pcicfgread(pcimaketag(0, 13, 0), PCI_ID_REG)) ==
	    0x1106) {				/* PCI_VENDOR_VIA */
		brdtype = BRD_STORCENTER;
	}

	brdprop = brd_lookup(brdtype);

	/* brd dependent adjustments */
	setup();

	/* determine clock frequencies */
	if (brdprop->extclk != 0)
		extclk = brdprop->extclk;
	if (busclock == 0) {
		if (cputype() == MPC8245) {
			/* PLL_CFG from PCI host bridge register 0xe2 */
			val = pcicfgread(pchb, 0xe0);
			busclock = (extclk *
			    pci_to_memclk[(val >> 19) & 0x1f] + 10) / 10;
			/* PLLRATIO from HID1 */
			__asm ("mfspr %0,1009" : "=r"(val));
			cpuclock = ((uint64_t)busclock *
			    mem_to_cpuclk[val >> 27] + 10) / 10;
		} else
			busclock = 100000000;	/* 100MHz bus clock default */
	}
	ticks_per_sec = busclock >> 2;
	ns_per_tick = 1000000000 / ticks_per_sec;

	/* now prepare serial console */
	consname = brdprop->consname;
	consport = brdprop->consport;
	if (strcmp(consname, "eumb") == 0) {
		uart1base = 0xfc000000 + consport;	/* 0x4500, 0x4600 */
		UART_WRITE(uart1base, DCR, 0x01);	/* enable DUART mode */
		uart2base = uart1base ^ 0x0300;
	} else
		uart1base = 0xfe000000 + consport;	/* 0x3f8, 0x2f8 */

	/* more brd adjustments */
	brdfixup();

	bi_mem.memsize = mpc107memsize();
	snprintf(bi_cons.devname, sizeof(bi_cons.devname), consname);
	bi_cons.addr = consport;
	bi_cons.speed = brdprop->consspeed;
	bi_clk.ticks_per_sec = ticks_per_sec;
	snprintf(bi_fam.name, sizeof(bi_fam.name), brdprop->family);
}

struct brdprop *
brd_lookup(int brd)
{
	u_int i;

	for (i = 0; i < sizeof(brdlist)/sizeof(brdlist[0]); i++) {
		if (brdlist[i].brdtype == brd)
			return &brdlist[i];
	}
	return &brdlist[i - 1];
}

static void
setup()
{

	if (brdprop->setup == NULL)
		return;
	(*brdprop->setup)(brdprop);
}

static void
brdfixup()
{

	if (brdprop->brdfix == NULL)
		return;
	(*brdprop->brdfix)(brdprop);
}

void
pcifixup()
{

	if (brdprop->pcifix == NULL)
		return;
	(*brdprop->pcifix)(brdprop);
}

void
encsetup(struct brdprop *brd)
{

#ifdef COSNAME
	brd->consname = CONSNAME;
#endif
#ifdef CONSPORT
	brd->consport = CONSPORT;
#endif
#ifdef CONSSPEED
	brd->consspeed = CONSSPEED;
#endif
}

void
encbrdfix(struct brdprop *brd)
{
	unsigned ac97, ide, pcib, pmgt, usb12, umot4, val;

/*
 * VIA82C686B Southbridge
 *	0.22.0	1106.0686	PCI-ISA bridge
 *	0.22.1	1106.0571	IDE (viaide)
 *	0.22.2	1106.3038	USB 0/1 (uhci)
 *	0.22.3	1106.3038	USB 2/3 (uhci)
 *	0.22.4	1106.3057	power management
 *	0.22.5	1106.3058	AC97 (auvia)
 */
	pcib  = pcimaketag(0, 22, 0);
	ide   = pcimaketag(0, 22, 1);
	usb12 = pcimaketag(0, 22, 2);
	umot4 = pcimaketag(0, 22, 3);
	pmgt  = pcimaketag(0, 22, 4);
	ac97  = pcimaketag(0, 22, 5);

#define	CFG(i,v) do { \
   *(volatile unsigned char *)(0xfe000000 + 0x3f0) = (i); \
   *(volatile unsigned char *)(0xfe000000 + 0x3f1) = (v); \
   } while (0)
	val = pcicfgread(pcib, 0x84);
	val |= (02 << 8);
	pcicfgwrite(pcib, 0x84, val);
	CFG(0xe2, 0x0f); /* use COM1/2, don't use FDC/LPT */
	val = pcicfgread(pcib, 0x84);
	val &= ~(02 << 8);
	pcicfgwrite(pcib, 0x84, val);

	/* route pin C to i8259 IRQ 5, pin D to 11 */
	val = pcicfgread(pcib, 0x54);
	val = (val & 0xff) | 0xb0500000; /* Dx CB Ax xS */
	pcicfgwrite(pcib, 0x54, val);

	/* enable EISA ELCR1 (0x4d0) and ELCR2 (0x4d1) */
	val = pcicfgread(pcib, 0x44);
	val = val | 0x20000000;
	pcicfgwrite(pcib, 0x44, val);

	/* select level trigger for IRQ 5/11 at ELCR1/2 */
	*(volatile uint8_t *)0xfe0004d0 = 0x20; /* bit 5 */
	*(volatile uint8_t *)0xfe0004d1 = 0x08; /* bit 11 */

	/* USB and AC97 are hardwired with pin D and C */
	val = pcicfgread(usb12, 0x3c) &~ 0xff;
	val |= 11;
	pcicfgwrite(usb12, 0x3c, val);
	val = pcicfgread(umot4, 0x3c) &~ 0xff;
	val |= 11;
	pcicfgwrite(umot4, 0x3c, val);
	val = pcicfgread(ac97, 0x3c) &~ 0xff;
	val |= 5;
	pcicfgwrite(ac97, 0x3c, val);
}

void
motsetup(struct brdprop *brd)
{

#ifdef COSNAME
	brd->consname = CONSNAME;
#endif
#ifdef CONSPORT
	brd->consport = CONSPORT;
#endif
#ifdef CONSSPEED
	brd->consspeed = CONSSPEED;
#endif
}

void
motbrdfix(struct brdprop *brd)
{

/*
 * WinBond/Symphony Lab 83C553 with PC87308 "SuperIO"
 *
 *	0.11.0	10ad.0565	PCI-ISA bridge
 *	0.11.1	10ad.0105	IDE (slide)
 */
}

void
motpcifix(struct brdprop *brd)
{
	unsigned ide, nic, pcib, steer, val;
	int line;

	pcib = pcimaketag(0, 11, 0);
	ide  = pcimaketag(0, 11, 1);
	nic  = pcimaketag(0, 15, 0);

	/*
	 * //// WinBond PIRQ ////
	 * 0x40 - bit 5 (0x20) indicates PIRQ presense
	 * 0x60 - PIRQ interrupt routing steer
	 */
	if (pcicfgread(pcib, 0x40) & 0x20) {
		steer = pcicfgread(pcib, 0x60);
		if ((steer & 0x80808080) == 0x80808080)
			printf("PIRQ[0-3] disabled\n");
		else {
			unsigned i, v = steer;
			for (i = 0; i < 4; i++, v >>= 8) {
				if ((v & 0x80) != 0 || (v & 0xf) == 0)
					continue;
				printf("PIRQ[%d]=%d\n", i, v & 0xf);
				}
			}
		}
#if 1
	/*
	 * //// IDE fixup -- case A ////
	 * - "native PCI mode" (ide 0x09)
	 * - don't use ISA IRQ14/15 (pcib 0x43)
	 * - native IDE for both channels (ide 0x40)
	 * - LEGIRQ bit 11 steers interrupt to pin C (ide 0x40)
	 * - sign as PCI pin C line 11 (ide 0x3d/3c)
	 */
	/* ide: 0x09 - programming interface; 1000'SsPp */
	val = pcicfgread(ide, 0x08);
	val &= 0xffff00ff;
	pcicfgwrite(ide, 0x08, val | (0x8f << 8));

	/* pcib: 0x43 - IDE interrupt routing */
	val = pcicfgread(pcib, 0x40) & 0x00ffffff;
	pcicfgwrite(pcib, 0x40, val);

	/* pcib: 0x45/44 - PCI interrupt routing */
	val = pcicfgread(pcib, 0x44) & 0xffff0000;
	pcicfgwrite(pcib, 0x44, val);

	/* ide: 0x41/40 - IDE channel */
	val = pcicfgread(ide, 0x40) & 0xffff0000;
	val |= (1 << 11) | 0x33; /* LEGIRQ turns on PCI interrupt */
	pcicfgwrite(ide, 0x40, val);

	/* ide: 0x3d/3c - use PCI pin C/line 11 */
	val = pcicfgread(ide, 0x3c) & 0xffffff00;
	val |= 11; /* pin designation is hardwired to pin A */
	pcicfgwrite(ide, 0x3c, val);
#else
	/*
	 * //// IDE fixup -- case B ////
	 * - "compatiblity mode" (ide 0x09)
	 * - IDE primary/secondary interrupt routing (pcib 0x43)
	 * - PCI interrupt routing (pcib 0x45/44)
	 * - no PCI pin/line assignment (ide 0x3d/3c)
	 */
	/* ide: 0x09 - programming interface; 1000'SsPp */
	val = pcicfgread(ide, 0x08);
	val &= 0xffff00ff;
	pcicfgwrite(ide, 0x08, val | (0x8a << 8));

	/* pcib: 0x43 - IDE interrupt routing */
	val = pcicfgread(pcib, 0x40) & 0x00ffffff;
	pcicfgwrite(pcib, 0x40, val | (0xee << 24));

	/* ide: 0x45/44 - PCI interrupt routing */
	val = pcicfgread(ide, 0x44) & 0xffff0000;
	pcicfgwrite(ide, 0x44, val);

	/* ide: 0x3d/3c - turn off PCI pin/line */
	val = pcicfgread(ide, 0x3c) & 0xffff0000;
	pcicfgwrite(ide, 0x3c, val);
#endif

	/*
	 * //// fxp fixup ////
	 * - use PCI pin A line 15 (fxp 0x3d/3c)
	 */
	val = pcicfgread(nic, 0x3c) & 0xffff0000;
	pcidecomposetag(nic, NULL, &line, NULL);
	val |= (('A' - '@') << 8) | line;
	pcicfgwrite(nic, 0x3c, val);
}

void
encpcifix(struct brdprop *brd)
{
	unsigned ide, irq, nic, pcib, steer, val;

#define	STEER(v, b) (((v) & (b)) ? "edge" : "level")
	pcib = pcimaketag(0, 22, 0);
	ide  = pcimaketag(0, 22, 1);
	nic  = pcimaketag(0, 25, 0);

	/*
	 * //// VIA PIRQ ////
	 * 0x57/56/55/54 - Dx CB Ax xS
	 */
	val = pcicfgread(pcib, 0x54);	/* Dx CB Ax xs */
	steer = val & 0xf;
	irq = (val >> 12) & 0xf;	/* 15:12 */
	if (irq) {
		printf("pin A -> irq %d, %s\n",
			irq, STEER(steer, 0x1));
	}
	irq = (val >> 16) & 0xf;	/* 19:16 */
	if (irq) {
		printf("pin B -> irq %d, %s\n",
			irq, STEER(steer, 0x2));
	}
	irq = (val >> 20) & 0xf;	/* 23:20 */
	if (irq) {
		printf("pin C -> irq %d, %s\n",
			irq, STEER(steer, 0x4));
	}
	irq = (val >> 28);		/* 31:28 */
	if (irq) {
		printf("pin D -> irq %d, %s\n",
			irq, STEER(steer, 0x8));
	}
#if 0
	/*
	 * //// IDE fixup ////
	 * - "native mode" (ide 0x09)
	 * - use primary only (ide 0x40)
	 */
	/* ide: 0x09 - programming interface; 1000'SsPp */
	val = pcicfgread(ide, 0x08) & 0xffff00ff;
	pcicfgwrite(ide, 0x08, val | (0x8f << 8));

	/* ide: 0x10-20 - leave them PCI memory space assigned */

	/* ide: 0x40 - use primary only */
	val = pcicfgread(ide, 0x40) &~ 03;
	val |= 02;
	pcicfgwrite(ide, 0x40, val);
#else
	/*
	 * //// IDE fixup ////
	 * - "compatiblity mode" (ide 0x09)
	 * - use primary only (ide 0x40)
	 * - remove PCI pin assignment (ide 0x3d)
	 */
	/* ide: 0x09 - programming interface; 1000'SsPp */
	val = pcicfgread(ide, 0x08) & 0xffff00ff;
	val |= (0x8a << 8);
	pcicfgwrite(ide, 0x08, val);

	/* ide: 0x10-20 */
	/*
	experiment shows writing ide: 0x09 changes these
	register behaviour. The pcicfgwrite() above writes
	0x8a at ide: 0x09 to make sure legacy IDE.  Then
	reading BAR0-3 is to return value 0s even though
	pcisetup() has written range assignments.  Value
	overwrite makes no effect. Having 0x8f for native
	PCIIDE doesn't change register values and brings no
	weirdness.
	 */

	/* ide: 0x40 - use primary only */
	val = pcicfgread(ide, 0x40) &~ 03;
	val |= 02;
	pcicfgwrite(ide, 0x40, val);

		/* ide: 0x3d/3c - turn off PCI pin */
	val = pcicfgread(ide, 0x3c) & 0xffff00ff;
	pcicfgwrite(ide, 0x3c, val);
#endif
	/*
	 * //// USBx2, audio, and modem fixup ////
	 * - disable USB #0 and #1 (pcib 0x48 and 0x85)
	 * - disable AC97 audio and MC97 modem (pcib 0x85)
	 */

	/* pcib: 0x48 - disable USB #0 at function 2 */
	val = pcicfgread(pcib, 0x48);
	pcicfgwrite(pcib, 0x48, val | 04);

	/* pcib: 0x85 - disable USB #1 at function 3 */
	/* pcib: 0x85 - disable AC97/MC97 at function 5/6 */
	val = pcicfgread(pcib, 0x84);
	pcicfgwrite(pcib, 0x84, val | 0x1c00);

	/*
	 * //// fxp fixup ////
	 * - use PCI pin A line 25 (fxp 0x3d/3c)
	 */
	/* 0x3d/3c - PCI pin/line */
	val = pcicfgread(nic, 0x3c) & 0xffff0000;
	val |= (('A' - '@') << 8) | 25;
	pcicfgwrite(nic, 0x3c, val);
}

void
kurosetup(struct brdprop *brd)
{

	if (PCI_VENDOR(pcicfgread(pcimaketag(0, 11, 0), PCI_ID_REG)) == 0x10ec)
		brd->extclk = 32768000; /* decr 2457600Hz */
	else
		brd->extclk = 32521333; /* decr 2439100Hz */
}

void
kurobrdfix(struct brdprop *brd)
{

	init_uart(uart2base, 9600, LCR_8BITS | LCR_PEVEN);
	/* Stop Watchdog */
	send_sat("AAAAFFFFJJJJ>>>>VVVV>>>>ZZZZVVVVKKKK");
}

void
kuropcifix(struct brdprop *brd)
{
	unsigned ide, nic, usb, val;

	nic = pcimaketag(0, 11, 0);
	val = pcicfgread(nic, 0x3c) & 0xffffff00;
	val |= 11;
	pcicfgwrite(nic, 0x3c, val);

	ide = pcimaketag(0, 12, 0);
	val = pcicfgread(ide, 0x3c) & 0xffffff00;
	val |= 12;
	pcicfgwrite(ide, 0x3c, val);

	usb = pcimaketag(0, 14, 0);
	val = pcicfgread(usb, 0x3c) & 0xffffff00;
	val |= 14;
	pcicfgwrite(usb, 0x3c, val);

	usb = pcimaketag(0, 14, 1);
	val = pcicfgread(usb, 0x3c) & 0xffffff00;
	val |= 14;
	pcicfgwrite(usb, 0x3c, val);

	usb = pcimaketag(0, 14, 2);
	val = pcicfgread(usb, 0x3c) & 0xffffff00;
	val |= 14;
	pcicfgwrite(usb, 0x3c, val);
}

void
synosetup(struct brdprop *brd)
{

	/* nothing */
}

void
synobrdfix(struct brdprop *brd)
{

	init_uart(uart2base, 9600, LCR_8BITS | LCR_PNONE);
	/* beep, power LED on, status LED off */
	send_sat("247");
}

void
synopcifix(struct brdprop *brd)
{
	unsigned ide, nic, usb, val;

	ide = pcimaketag(0, 13, 0);
	val = pcicfgread(ide, 0x3c) & 0xffffff00;
	val |= 13;
	pcicfgwrite(ide, 0x3c, val);

	usb = pcimaketag(0, 14, 0);
	val = pcicfgread(usb, 0x3c) & 0xffffff00;
	val |= 14;
	pcicfgwrite(usb, 0x3c, val);

	usb = pcimaketag(0, 14, 1);
	val = pcicfgread(usb, 0x3c) & 0xffffff00;
	val |= 14;
	pcicfgwrite(usb, 0x3c, val);

	usb = pcimaketag(0, 14, 2);
	val = pcicfgread(usb, 0x3c) & 0xffffff00;
	val |= 14;
	pcicfgwrite(usb, 0x3c, val);

	nic = pcimaketag(0, 15, 0);
	val = pcicfgread(nic, 0x3c) & 0xffffff00;
	val |= 15;
	pcicfgwrite(nic, 0x3c, val);
}

void
qnappcifix(struct brdprop *brd)
{
	unsigned ide, nic, usb, val;

	ide = pcimaketag(0, 13, 0);
	val = pcicfgread(ide, 0x3c) & 0xffffff00;
	val |= 13;
	pcicfgwrite(ide, 0x3c, val);

	usb = pcimaketag(0, 14, 0);
	val = pcicfgread(usb, 0x3c) & 0xffffff00;
	val |= 14;
	pcicfgwrite(usb, 0x3c, val);

	usb = pcimaketag(0, 14, 1);
	val = pcicfgread(usb, 0x3c) & 0xffffff00;
	val |= 14;
	pcicfgwrite(usb, 0x3c, val);

	usb = pcimaketag(0, 14, 2);
	val = pcicfgread(usb, 0x3c) & 0xffffff00;
	val |= 14;
	pcicfgwrite(usb, 0x3c, val);

	nic = pcimaketag(0, 15, 0);
	val = pcicfgread(nic, 0x3c) & 0xffffff00;
	val |= 15;
	pcicfgwrite(nic, 0x3c, val);
}

void
synoreset()
{

	send_sat("C");
	/*NOTRECHED*/
}

void
_rtt(void)
{

	if (brdprop->reset != NULL)
		(*brdprop->reset)();
	else
		run(0, 0, 0, 0, (void *)0xFFF00100); /* reset entry */
	/*NOTREACHED*/
}

satime_t
getsecs(void)
{
	u_quad_t tb = mftb();

	return (tb / ticks_per_sec);
}

/*
 * Wait for about n microseconds (at least!).
 */
void
delay(u_int n)
{
	u_quad_t tb;
	u_long scratch, tbh, tbl;

	tb = mftb();
	tb += (n * 1000 + ns_per_tick - 1) / ns_per_tick;
	tbh = tb >> 32;
	tbl = tb;
	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));
}

void
_wb(uint32_t adr, uint32_t siz)
{
	uint32_t bnd;

	asm volatile("eieio");
	for (bnd = adr + siz; adr < bnd; adr += dcache_line_size)
		asm volatile ("dcbst 0,%0" :: "r"(adr));
	asm volatile ("sync");
}

void
_wbinv(uint32_t adr, uint32_t siz)
{
	uint32_t bnd;

	asm volatile("eieio");
	for (bnd = adr + siz; adr < bnd; adr += dcache_line_size)
		asm volatile ("dcbf 0,%0" :: "r"(adr));
	asm volatile ("sync");
}

void
_inv(uint32_t adr, uint32_t siz)
{
	uint32_t bnd, off;

	off = adr & (dcache_line_size - 1);
	adr -= off;
	siz += off;
	asm volatile ("eieio");
	if (off != 0) {
		/* wbinv() leading unaligned dcache line */
		asm volatile ("dcbf 0,%0" :: "r"(adr));
		if (siz < dcache_line_size)
			goto done;
		adr += dcache_line_size;
		siz -= dcache_line_size;
	}
	bnd = adr + siz;
	off = bnd & (dcache_line_size - 1);
	if (off != 0) {
		/* wbinv() trailing unaligned dcache line */
		asm volatile ("dcbf 0,%0" :: "r"(bnd)); /* it's OK */
		if (siz < dcache_line_size)
			goto done;
		siz -= off;
	}
	for (bnd = adr + siz; adr < bnd; adr += dcache_line_size) {
		/* inv() intermediate dcache lines if ever */
		asm volatile ("dcbi 0,%0" :: "r"(adr));
	}
  done:
	asm volatile ("sync");
}

static inline uint32_t
cputype(void)
{
	uint32_t pvr;

	__asm volatile ("mfpvr %0" : "=r"(pvr));
	return pvr >> 16;
}

static inline u_quad_t
mftb(void)
{
	u_long scratch;
	u_quad_t tb;

	asm ("1: mftbu %0; mftb %0+1; mftbu %1; cmpw %0,%1; bne 1b"
	    : "=r"(tb), "=r"(scratch));
	return (tb);
}

static void
init_uart(unsigned base, unsigned speed, uint8_t lcr)
{
	unsigned div;

	div = busclock / speed / 16;
	UART_WRITE(base, LCR, 0x80);		/* turn on DLAB bit */
	UART_WRITE(base, FCR, 0x00);
	UART_WRITE(base, DMB, div >> 8);	/* set speed */
	UART_WRITE(base, DLB, div & 0xff);
	UART_WRITE(base, LCR, lcr);
	UART_WRITE(base, FCR, 0x07);		/* FIFO on, TXRX FIFO reset */
	UART_WRITE(base, IER, 0x00);		/* make sure INT disabled */
}

/* talk to satellite processor */
static void
send_sat(char *msg)
{
	unsigned savedbase;

	savedbase = uart1base;
	uart1base = uart2base;
	while (*msg)
		putchar(*msg++);
	uart1base = savedbase;
}

void
putchar(int c)
{
	unsigned timo, lsr;

	if (c == '\n')
		putchar('\r');

	timo = 0x00100000;
	do {
		lsr = UART_READ(uart1base, LSR);
	} while (timo-- > 0 && (lsr & LSR_THRE) == 0);
	if (timo > 0)
		UART_WRITE(uart1base, THR, c);
}

unsigned
mpc107memsize()
{
	unsigned bankn, end, n, tag, val;

	tag = pcimaketag(0, 0, 0);

	if (brdtype == BRD_ENCOREPP1) {
		/* the brd's PPCBOOT looks to have erroneous values */
		unsigned tbl[] = {
#define MPC106_MEMSTARTADDR1	0x80
#define MPC106_EXTMEMSTARTADDR1	0x88
#define MPC106_MEMENDADDR1	0x90
#define MPC106_EXTMEMENDADDR1	0x98
#define MPC106_MEMEN		0xa0
#define	BK0_S	0x00000000
#define	BK0_E	(128 << 20) - 1
#define BK1_S	0x3ff00000
#define BK1_E	0x3fffffff
#define BK2_S	0x3ff00000
#define BK2_E	0x3fffffff
#define BK3_S	0x3ff00000
#define BK3_E	0x3fffffff
#define AR(v, s) ((((v) & SAR_MASK) >> SAR_SHIFT) << (s))
#define XR(v, s) ((((v) & EAR_MASK) >> EAR_SHIFT) << (s))
#define SAR_MASK 0x0ff00000
#define SAR_SHIFT    20
#define EAR_MASK 0x30000000
#define EAR_SHIFT    28
		AR(BK0_S, 0) | AR(BK1_S, 8) | AR(BK2_S, 16) | AR(BK3_S, 24),
		XR(BK0_S, 0) | XR(BK1_S, 8) | XR(BK2_S, 16) | XR(BK3_S, 24),
		AR(BK0_E, 0) | AR(BK1_E, 8) | AR(BK2_E, 16) | AR(BK3_E, 24),
		XR(BK0_E, 0) | XR(BK1_E, 8) | XR(BK2_E, 16) | XR(BK3_E, 24),
		};
		tag = pcimaketag(0, 0, 0);
		pcicfgwrite(tag, MPC106_MEMSTARTADDR1, tbl[0]);
		pcicfgwrite(tag, MPC106_EXTMEMSTARTADDR1, tbl[1]);
		pcicfgwrite(tag, MPC106_MEMENDADDR1, tbl[2]);
		pcicfgwrite(tag, MPC106_EXTMEMENDADDR1,	tbl[3]);
		pcicfgwrite(tag, MPC106_MEMEN, 1);
	}

	bankn = 0;
	val = pcicfgread(tag, MPC106_MEMEN);
	for (n = 0; n < 4; n++) {
		if ((val & (1U << n)) == 0)
			break;
		bankn = n;
	}
	bankn = bankn * 8;

	val = pcicfgread(tag, MPC106_EXTMEMENDADDR1);
	end =  ((val >> bankn) & 0x03) << 28;
	val = pcicfgread(tag, MPC106_MEMENDADDR1);
	end |= ((val >> bankn) & 0xff) << 20;
	end |= 0xfffff;

	return (end + 1); /* assume the end address matches total amount */
}

struct fis_dir_entry {
	char		name[16];
	uint32_t	startaddr;
	uint32_t	loadaddr;
	uint32_t	flashsize;
	uint32_t	entryaddr;
	uint32_t	filesize;
	char		pad[256 - (16 + 5 * sizeof(uint32_t))];
};

#define FIS_LOWER_LIMIT	0xfff00000

/*
 * Look for a Redboot-style Flash Image System FIS-directory and
 * return a pointer to the start address of the requested file.
 */
static void *
redboot_fis_lookup(const char *filename)
{
	static const char FISdirname[16] = {
	    'F', 'I', 'S', ' ',
	    'd', 'i', 'r', 'e', 'c', 't', 'o', 'r', 'y', 0, 0, 0
	};
	struct fis_dir_entry *dir;

	/*
	 * The FIS directory is usually in the last sector of the flash.
	 * But we do not know the sector size (erase size), so start
	 * at 0xffffff00 and scan backwards in steps of the FIS directory
	 * entry size (0x100).
	 */
	for (dir = (struct fis_dir_entry *)0xffffff00;
	    (uint32_t)dir >= FIS_LOWER_LIMIT; dir--)
		if (memcmp(dir->name, FISdirname, sizeof(FISdirname)) == 0)
			break;
	if ((uint32_t)dir < FIS_LOWER_LIMIT) {
		printf("No FIS directory found!\n");
		return NULL;
	}

	/* Now find filename by scanning the directory from beginning. */
	dir = (struct fis_dir_entry *)dir->startaddr;
	while (dir->name[0] != 0xff && (uint32_t)dir < 0xffffff00) {
		if (strcmp(dir->name, filename) == 0)
			return (void *)dir->startaddr;	/* found */
		dir++;
	}
	printf("\"%s\" not found in FIS directory!\n", filename);
	return NULL;
}

/*
 * For cost saving reasons some NAS boxes are missing the ROM for the
 * NIC's ethernet address and keep it in their Flash memory.
 */
void
read_mac_from_flash(uint8_t *mac)
{
	uint8_t *p;

	if (brdtype == BRD_SYNOLOGY) {
		p = redboot_fis_lookup("vendor");
		if (p != NULL) {
			memcpy(mac, p, 6);
			return;
		}
	} else
		printf("Warning: This board has no known method defined "
		    "to determine its MAC address!\n");

	/* set to 00:00:00:00:00:00 in case of error */
	memset(mac, 0, 6);
}

File Added: src/sys/arch/sandpoint/stand/altboot/dev_net.c
/* $NetBSD: dev_net.c,v 1.1 2011/01/23 01:05:30 nisimura Exp $ */

/*-
 * Copyright (c) 2007 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by Tohru Nishimura.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include <sys/param.h>

#include <netinet/in.h>
#include <netinet/in_systm.h>

#include <lib/libsa/stand.h>
#include <lib/libsa/net.h>
#include <lib/libsa/bootp.h>
#include <lib/libsa/nfs.h>
#include <lib/libkern/libkern.h>

#include <machine/bootinfo.h>
#include <machine/stdarg.h>

#include "globals.h"

static int netdev_sock = -1;
static int netdev_opens;

int
net_open(struct open_file *f, ...)

{
	va_list ap;
	char *file, *proto;
	int error;
	extern struct btinfo_bootpath bi_path;
	
	va_start(ap, f);
	file = va_arg(ap, char *);
	proto = va_arg(ap, char *);
	va_end(ap);

	if (netdev_opens > 0)
		return 0;

	if ((netdev_sock = netif_open(NULL)) < 0)
		return ENXIO;	/* never fails indeed */

	error = 0;
	bootp(netdev_sock);	/* send DHCP request */
	if (myip.s_addr == 0) {
		error = ENOENT;	/* IP address was not found */
		goto bad;
	}

	if (file[0] != '\0') 
		snprintf(bootfile, sizeof(bootfile), file);
	else if (bootfile[0] == '\0')
		snprintf(bootfile, sizeof(bootfile), "netbsd");

	if (strcmp(proto, "nfs") == 0
	    && (error = nfs_mount(netdev_sock, rootip, rootpath)) != 0)
		goto bad;

	snprintf(bi_path.bootpath, sizeof(bi_path.bootpath), bootfile);
	f->f_devdata = &netdev_sock;
	netdev_opens++;
	return 0;
 bad:
	netif_close(netdev_sock);
	netdev_sock = -1;
	return error;
}

int
net_close(struct open_file *f)
	
{
	f->f_devdata = NULL;
	if (--netdev_opens > 0)
		return 0;
	netif_close(netdev_sock);
	netdev_sock = -1;
	return 0;
}

int
net_strategy(void *devdata, int rw, daddr_t dblk, size_t size,
	void *p, size_t *rsize)
{

	return EIO;
}

File Added: src/sys/arch/sandpoint/stand/altboot/devopen.c
/* $NetBSD: devopen.c,v 1.1 2011/01/23 01:05:30 nisimura Exp $ */

/*-
 * Copyright (c) 2007 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by Tohru Nishimura.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include <sys/param.h>

#include <netinet/in.h>

#include <lib/libsa/stand.h>
#include <lib/libsa/nfs.h>
#include <lib/libsa/ufs.h>
#include <lib/libsa/tftp.h>
#include <lib/libkern/libkern.h>

#include "globals.h"

struct devsw devnet = { "net", net_strategy, net_open, net_close, noioctl };
struct devsw devdsk = { "dsk", dsk_strategy, dsk_open, dsk_close, noioctl };

struct fs_ops file_system[1] = { FS_OPS(null) };
int nfsys = 1;
struct fs_ops fs_nfs   = FS_OPS(nfs);
struct fs_ops fs_tftp  = FS_OPS(tftp);
struct fs_ops fs_ffsv2 = FS_OPS(ffsv2);
struct fs_ops fs_ffsv1 = FS_OPS(ffsv1);
extern char *fsmod;

static void parseunit(const char *, int *, int *, char **);

int
devopen(struct open_file *of, const char *name, char **file)
{
	int error;
	int unit, part;
	extern char bootfile[]; /* handed by DHCP */

	if (of->f_flags != F_READ)
		return EPERM;

	if (strncmp("net:", name, 4) == 0 || strncmp("nfs:", name, 4) == 0) {
		of->f_dev = &devnet;
		if ((error = net_open(of, &name[4], "nfs")) != 0)
			return error;
		file_system[0] = fs_nfs;
		*file = bootfile;	/* resolved fname */
		return 0;		/* NFS */
	}
	if (strncmp("tftp:", name, 5) == 0) {
		of->f_dev = &devnet;
		if ((error = net_open(of, &name[5], "tftp")) != 0)
			return error;
		file_system[0] = fs_tftp;
		*file = bootfile;	/* resolved fname */
		return 0;		/* TFTP */
	}
	if (name[0] == 'w' && name[1] == 'd') {
		parseunit(&name[2], &unit, &part, file);
		of->f_dev = &devdsk;
		if (*file == NULL || **file <= ' ')
			*file = "netbsd";
		if ((error = dsk_open(of, unit, part, *file)) != 0)
			return error;
		file_system[0] = *dsk_fsops(of);
		return 0;		/* FFS */
	}
	return ENOENT;
}

static void
parseunit(const char *name, int *unitp, int *partp, char **pathp)
{
	const char *p = name;
	int unit, part;

	unit = part = -1;
	while (*p != ':' && *p != '\0') {
		if (unit == -1 && *p >= '0' && *p <= '9')
			unit = *p - '0';
		if (part == -1 && *p >= 'a' && *p < 'a' + 16)
			part = *p - 'a';
		p += 1;
	}
	*unitp = (unit == -1) ? 0 : unit;
	*partp = (part == -1) ? 0 : part;
	*pathp = (*p == ':') ? (char *)p + 1 : NULL;
}

/* ARGSUSED */
int
noioctl(struct open_file *f, u_long cmd, void *data)
{

	return EINVAL;
}

File Added: src/sys/arch/sandpoint/stand/altboot/dsk.c
/* $NetBSD: dsk.c,v 1.1 2011/01/23 01:05:30 nisimura Exp $ */

/*-
 * Copyright (c) 2010 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by Tohru Nishimura.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

/*
 * assumptions;
 * - up to 4 IDE/SATA drives.
 * - a single (master) drive in each IDE channel.
 * - all drives are up and spinning.
 */

#include <sys/types.h>

#include <lib/libsa/stand.h>
#include <lib/libsa/ufs.h>

#include <sys/disklabel.h>
#include <sys/bootblock.h>

#include <machine/bootinfo.h>
#include <machine/stdarg.h>

#include "globals.h"

/*
 * - no vtophys() translation, vaddr_t == paddr_t.
 */
#define CSR_READ_4(r)		in32rb(r)
#define CSR_WRITE_4(r,v)	out32rb(r,v)
#define CSR_READ_1(r)		*(volatile uint8_t *)(r)
#define CSR_WRITE_1(r,v)	*(volatile uint8_t *)(r)=(v)

#define DSK_DECL(xxx) \
    int xxx ## _match(unsigned, void *); \
    void * xxx ## _init(unsigned, void *)

DSK_DECL(pciide);
DSK_DECL(siisata);

struct dskdv {
	char *name;
	int (*match)(unsigned, void *);
	void *(*init)(unsigned, void *);
	void *priv;
};

static struct dskdv ldskdv[] = {
	{ "pciide", pciide_match, pciide_init, },
	{ "siisata", siisata_match, siisata_init, },
};
static int ndskdv = sizeof(ldskdv)/sizeof(ldskdv[0]);

static int probe_drive(struct dkdev_ata *, int);
static void drive_ident(struct disk *, char *);
static char *mkident(char *, int);
static void set_xfermode(struct dkdev_ata *, int);
static void decode_dlabel(struct disk *, char *);
static int lba_read(struct disk *, uint64_t, uint32_t, void *);
static void issue48(struct dvata_chan *, uint64_t, uint32_t);
static void issue28(struct dvata_chan *, uint64_t, uint32_t);
static struct disk *lookup_disk(int);

static struct disk ldisk[4];

int
dskdv_init(unsigned tag, void **cookie)
{
	struct dskdv *dv;
	int n;

	for (n = 0; n < ndskdv; n++) {
		dv = &ldskdv[n];
		if ((*dv->match)(tag, NULL) > 0)
			goto found;
	}
	return 0;
  found:
	dv->priv = (*dv->init)(tag, NULL);
	*cookie = dv;
	return 1;
}

int
disk_scan(void *cookie)
{
	struct dskdv *dv = cookie;
	struct dkdev_ata *l = dv->priv;
	struct disk *d;
	int n, ndrive;

	ndrive = 0;
	for (n = 0; n < 4; n++) {
		if (l->presense[n] == 0)
			continue;
		if (probe_drive(l, n) == 0) {
			l->presense[n] = 0;
			continue;
		}
		d = &ldisk[ndrive];
		d->dvops = l;
		d->unittag = ndrive;
		snprintf(d->xname, sizeof(d->xname), "wd%d", d->unittag);
		set_xfermode(l, n);
		drive_ident(d, l->iobuf);
		decode_dlabel(d, l->iobuf);
		ndrive += 1;
	}
	return ndrive;
}

int
spinwait_unbusy(struct dkdev_ata *l, int n, int milli, const char **err)
{
	struct dvata_chan *chan = &l->chan[n];
	int sts;
	const char *msg;

	/*
	 * For best compatibility it is recommended to wait 400ns and
	 * read the alternate status byte four times before the status
	 * is valid.
	 */
	delay(1);
	(void)CSR_READ_1(chan->alt);
	(void)CSR_READ_1(chan->alt);
	(void)CSR_READ_1(chan->alt);
	(void)CSR_READ_1(chan->alt);

	sts = CSR_READ_1(chan->cmd + _STS);
	while (milli-- > 0
	    && sts != 0xff
	    && (sts & (ATA_STS_BUSY|ATA_STS_DRDY)) != ATA_STS_DRDY) {
		delay(1000);
		sts = CSR_READ_1(chan->cmd + _STS);
	}

	msg = NULL;
	if (sts == 0xff)
		msg = "returned 0xff";
	else if (sts & ATA_STS_ERR)
		msg = "returned ERR";
	else if (sts & ATA_STS_BUSY)
		msg = "remains BUSY";
	else if ((sts & ATA_STS_DRDY) == 0)
		msg = "no DRDY";

	if (err != NULL)
		*err = msg;
	return msg == NULL;
}

int
perform_atareset(struct dkdev_ata *l, int n)
{
	struct dvata_chan *chan = &l->chan[n];

	CSR_WRITE_1(chan->ctl, ATA_DREQ);
	delay(10);
	CSR_WRITE_1(chan->ctl, ATA_SRST|ATA_DREQ);
	delay(10);
	CSR_WRITE_1(chan->ctl, ATA_DREQ);

	return spinwait_unbusy(l, n, 150, NULL);
}

int
satapresense(struct dkdev_ata *l, int n)
{
#define VND_CH(n) (((n&02)<<8)+((n&01)<<7))
#define VND_SC(n) (0x100+VND_CH(n))
#define VND_SS(n) (0x104+VND_CH(n))

	uint32_t sc = l->bar[5] + VND_SC(n);
	uint32_t ss = l->bar[5] + VND_SS(n);
	unsigned val;

	val = (00 << 4) | (03 << 8);	/* any speed, no pwrmgt */
	CSR_WRITE_4(sc, val | 01);	/* perform init */
	delay(50 * 1000);
	CSR_WRITE_4(sc, val);
	delay(50 * 1000);	
	val = CSR_READ_4(ss);		/* has completed */
	return ((val & 03) == 03);	/* active drive found */
}

static int
probe_drive(struct dkdev_ata *l, int n)
{
	struct dvata_chan *chan = &l->chan[n];
	uint16_t *p;
	int i;
	
	CSR_WRITE_1(chan->cmd + _CMD, ATA_CMD_IDENT);
	(void)CSR_READ_1(chan->alt);
	delay(10 * 1000);
	if (spinwait_unbusy(l, n, 1000, NULL) == 0)
		return 0;

	p = (uint16_t *)l->iobuf;
	for (i = 0; i < 512; i += 2) {
		/* need to have bswap16 */
		*p++ = iole16toh(chan->cmd + _DAT);
	}
	(void)CSR_READ_1(chan->cmd + _STS);
	return 1;
}

static void
drive_ident(struct disk *d, char *ident)
{
	uint16_t *p;
	uint64_t huge;

	p = (uint16_t *)ident;
#if 1
        printf("[49]%04x [82]%04x [83]%04x [84]%04x "
	       "[85]%04x [86]%04x [87]%04x [88]%04x\n",
		p[49], p[82], p[83], p[84],
		p[85], p[86], p[87], p[88]);
#endif
	huge = 0;
	printf("%s: ", d->xname);
	printf("<%s> ", mkident((char *)ident + 54, 40));
	if (p[49] & (1 << 8))
		printf("DMA ");
	if (p[49] & (1 << 9)) {
		printf("LBA ");
		huge = p[60] | (p[61] << 16);
	}
	if ((p[83] & 0xc000) == 0x4000 && (p[83] & (1 << 10))) {
		printf("LBA48 ");
		huge = p[100] | (p[101] << 16);
		huge |= (uint64_t)p[102] << 32;
		huge |= (uint64_t)p[103] << 48;
	}
	huge >>= (1 + 10);
	printf("%d MB\n", (int)huge);

	memcpy(d->ident, ident, sizeof(d->ident));
	d->nsect = huge;
	d->lba_read = lba_read;
}

static char *
mkident(char *src, int len)
{
	static char local[40];
	char *dst, *end, *last;
	
	if (len > sizeof(local))
		len = sizeof(local);
	dst = last = local;
	end = src + len - 1;

	/* reserve space for '\0' */
	if (len < 2)
		goto out;
	/* skip leading white space */
	while (*src != '\0' && src < end && *src == ' ')
		++src;
	/* copy string, omitting trailing white space */
	while (*src != '\0' && src < end) {
		*dst++ = *src;
		if (*src++ != ' ')
			last = dst;
	}
 out:
	*last = '\0';
	return local;
}

static void
decode_dlabel(struct disk *d, char *iobuf)
{
        struct mbr_partition *mp, *bsdp;
	struct disklabel *dlp;
	struct partition *pp;
	char *dp;
	int i, first;

	bsdp = NULL;
	(*d->lba_read)(d, 0, 1, iobuf);
	if (bswap16(*(uint16_t *)(iobuf + MBR_MAGIC_OFFSET)) != MBR_MAGIC)
		goto skip;
	mp = (struct mbr_partition *)(iobuf + MBR_PART_OFFSET);
	for (i = 0; i < MBR_PART_COUNT; i++, mp++) {
		if (mp->mbrp_type == MBR_PTYPE_NETBSD) {
			bsdp = mp;
			break;
		}
	}
  skip:
	first = (bsdp) ? bswap32(bsdp->mbrp_start) : 0;
	(*d->lba_read)(d, first + LABELSECTOR, 1, iobuf);
	dp = iobuf /* + LABELOFFSET */;
	for (i = 0; i < 512 - sizeof(struct disklabel); i++, dp += 4) {
		dlp = (struct disklabel *)dp;
		if (dlp->d_magic == DISKMAGIC && dlp->d_magic2 == DISKMAGIC) {
			goto found;
		}
	}
	d->dlabel = NULL;
	printf("%s: no disklabel\n", d->xname);
	return;
  found:
	d->dlabel = allocaligned(sizeof(struct disklabel), 4);
	memcpy(d->dlabel, dlp, sizeof(struct disklabel));
#if 1
	for (i = 0; i < dlp->d_npartitions; i += 1) {
		const char *type;
		pp = &dlp->d_partitions[i];
		type = NULL;
		switch (pp->p_fstype) {
		case FS_SWAP: /* swap */
			type = "swap";
			break;
		case FS_BSDFFS:
			type = "ffs";
			break;
		case FS_EX2FS:
			type = "ext2fs";
			break;
		}
		if (type != NULL)
			printf("%s%c: %s\n", d->xname, i + 'a', type);
	}
#endif
}

static void
set_xfermode(struct dkdev_ata *l, int n)
{
	struct dvata_chan *chan = &l->chan[n];

	CSR_WRITE_1(chan->cmd + _FEA, ATA_XFER);
	CSR_WRITE_1(chan->cmd + _NSECT, XFER_PIO0);
	CSR_WRITE_1(chan->cmd + _DEV, ATA_DEV_OBS); /* ??? */
	CSR_WRITE_1(chan->cmd + _CMD, ATA_CMD_SETF);

	spinwait_unbusy(l, n, 1000, NULL);
}

static int
lba_read(struct disk *d, uint64_t bno, uint32_t bcnt, void *buf)
{
	struct dkdev_ata *l;
	struct dvata_chan *chan;
	void (*issue)(struct dvata_chan *, uint64_t, uint32_t);
	int n, rdcnt, i, k;
	uint16_t *p;
	const char *err;
	int error;

	l = d->dvops;
	n = d->unittag;
	p = (uint16_t *)buf;
	chan = &l->chan[n];
	error = 0;
	for ( ; bcnt > 0; bno += rdcnt, bcnt -= rdcnt) {
		issue = (bno < (1ULL<<28)) ? issue28 : issue48;
		rdcnt = (bcnt > 255) ? 255 : bcnt;
		(*issue)(chan, bno, rdcnt);
		for (k = 0; k < rdcnt; k++) {
			if (spinwait_unbusy(l, n, 1000, &err) == 0) {
				printf("%s blk %d %s\n",
				   d->xname, (int)bno, err);
				error = EIO;
				break;
			}
			for (i = 0; i < 512; i += 2) {
				/* arrives in native order */
				*p++ = *(uint16_t *)(chan->cmd + _DAT);
			}
			/* clear irq if any */
			(void)CSR_READ_1(chan->cmd + _STS);
		}
	}
	return error;
}

static void
issue48(struct dvata_chan *chan, uint64_t bno, uint32_t nblk)
{

	CSR_WRITE_1(chan->cmd + _NSECT, 0); /* always less than 256 */
	CSR_WRITE_1(chan->cmd + _LBAL, (bno >> 24) & 0xff);
	CSR_WRITE_1(chan->cmd + _LBAM, (bno >> 32) & 0xff);
	CSR_WRITE_1(chan->cmd + _LBAH, (bno >> 40) & 0xff);
	CSR_WRITE_1(chan->cmd + _NSECT, nblk);
	CSR_WRITE_1(chan->cmd + _LBAL, (bno >>  0) & 0xff);
	CSR_WRITE_1(chan->cmd + _LBAM, (bno >>  8) & 0xff);
	CSR_WRITE_1(chan->cmd + _LBAH, (bno >> 16) & 0xff);
	CSR_WRITE_1(chan->cmd + _DEV, ATA_DEV_LBA);
	CSR_WRITE_1(chan->cmd + _CMD, ATA_CMD_READ_EXT);
}

static void
issue28(struct dvata_chan *chan, uint64_t bno, uint32_t nblk)
{

	CSR_WRITE_1(chan->cmd + _NSECT, nblk);
	CSR_WRITE_1(chan->cmd + _LBAL, (bno >>  0) & 0xff);
	CSR_WRITE_1(chan->cmd + _LBAM, (bno >>  8) & 0xff);
	CSR_WRITE_1(chan->cmd + _LBAH, (bno >> 16) & 0xff);
	CSR_WRITE_1(chan->cmd + _DEV, ((bno >> 24) & 0xf) | ATA_DEV_LBA);
	CSR_WRITE_1(chan->cmd + _CMD, ATA_CMD_READ);
}

static struct disk *
lookup_disk(int unit)
{

	return &ldisk[unit];
}

int
dsk_open(struct open_file *f, ...)
{
	va_list ap;
	int unit, part;
	const char *name;
	struct disk *d;
	struct disklabel *dlp;
	struct fs_ops *fs;
	int error;
	extern struct btinfo_bootpath bi_path;
	extern struct btinfo_rootdevice bi_rdev;
	extern struct fs_ops fs_ffsv2, fs_ffsv1;

	va_start(ap, f);
	unit = va_arg(ap, int);
	part = va_arg(ap, int);
	name = va_arg(ap, const char *);
	va_end(ap);

	if ((d = lookup_disk(unit)) == NULL)
		return ENXIO;
	f->f_devdata = d;
	if ((dlp = d->dlabel) == NULL || part >= dlp->d_npartitions)
		return ENXIO;
	d->part = part;

	snprintf(bi_path.bootpath, sizeof(bi_path.bootpath), name);
	if (dlp->d_partitions[part].p_fstype == FS_BSDFFS) {
		if ((error = ffsv2_open(name, f)) == 0) {
			fs = &fs_ffsv2;
			goto found;
		}
		if (error == EINVAL && (error = ffsv1_open(name, f)) == 0) {
			fs = &fs_ffsv1;
			goto found;
		}
		return error;
	}
	return ENXIO;
  found:
#if 0
printf("dsk_open found %s\n", fsmod);
#endif
	d->fsops = fs;
	f->f_devdata = d;

	/* build btinfo to identify disk device */
	snprintf(bi_rdev.devname, sizeof(bi_rdev.devname), "wd");
	bi_rdev.cookie = d->unittag; /* disk unit number */
	return 0;
}

int
dsk_close(struct open_file *f)
{
	struct disk *d = f->f_devdata;
	struct fs_ops *fs = d->fsops;

	(*fs->close)(f);
	d->fsops = NULL;
	f->f_devdata = NULL;
	return 0;
}

int
dsk_strategy(void *devdata, int rw, daddr_t dblk, size_t size,
	void *p, size_t *rsize)
{
	struct disk *d = devdata;
	struct disklabel *dlp;
	uint64_t bno;

#if 0
printf("%s %d %d\n", d->xname, (int)dblk, size);
#endif
	if (size == 0)
		return 0;
	if (rw != F_READ)
		return EOPNOTSUPP;

	bno = dblk;
	if ((dlp = d->dlabel) != NULL)
		bno += dlp->d_partitions[d->part].p_offset;
	(*d->lba_read)(d, bno, size / 512, p);
	if (rsize != NULL)
		*rsize = size;
	return 0;
}

struct fs_ops *
dsk_fsops(struct open_file *f)
{
	struct disk *d = f->f_devdata;

	return d->fsops;
}

File Added: src/sys/arch/sandpoint/stand/altboot/entry.S
/* $NetBSD: entry.S,v 1.1 2011/01/23 01:05:30 nisimura Exp $ */

#include <powerpc/psl.h>
#include <powerpc/spr.h>
#include <powerpc/oea/spr.h>
#include <powerpc/oea/bat.h>
#include <powerpc/oea/hid.h>

	.text
	.globl _start
_start:
	mr	30,3
	mr	31,4
	mfspr	11,SPR_HID0
	andi.	0,11,HID0_DCE
	ori	11,11,HID0_ICE
	ori	8,11,HID0_ICFI
	bne	1f			/* don't invalidate the D-cache */
	ori	8,8,HID0_DCFI		/* unless it wasn't enabled */
1:
	mfmsr	0
	andi.	0,0,PSL_DR
	beq	2f
	lis	5, 0xfec00000@ha	/* CONFIG_ADDR of PCI */
	lis	6, 0xfee00000@ha	/* CONFIG_DATA of PCI */
	mfspr	3,SPR_DBAT0U
	mfspr	4,SPR_DBAT0L
	bl	dbat_sanity_check
	beq	3f
	mfspr	3,SPR_DBAT1U
	mfspr	4,SPR_DBAT1L
	bl	dbat_sanity_check
	beq	3f
	mfspr	3,SPR_DBAT2U
	mfspr	4,SPR_DBAT2L
	bl	dbat_sanity_check
	beq	3f
	mfspr	3,SPR_DBAT3U
	mfspr	4,SPR_DBAT3L
	bl	dbat_sanity_check
	beq	3f

2:	/* Disable D-cache */
	li	0,HID0_DCE
	andc	11,11,0
	b	4f

3:	/* Enable D-cache */
	ori	11,11,HID0_DCE

4:
	lis	1,BAT123@ha
	addi	1,1,BAT123@l
	lwz	3,0(1)
	lwz	4,4(1)
	mtdbatl	1,3
	mtdbatu	1,4
	lwz	3,8(1)
	lwz	4,12(1)
	mtdbatl	2,3
	mtdbatu	2,4
	lwz	3,16(1)
	lwz	4,20(1)
	mtdbatl	3,3
	mtdbatu	3,4

	sync
	mtspr	SPR_HID0,8		/* enable and invalidate caches */
	sync
	mtspr	SPR_HID0,11		/* enable caches */
	sync
	isync

	/* make sure .bss gets zeroed. */
	li	0,0
	lis	8,edata@ha
	addi	8,8,edata@l
	lis	9,end@ha
	addi	9,9,end@l
5:	cmpw	0,8,9			/* edata & end are >= word aligned */
	bge	6f
	stw	0,0(8)
	addi	8,8,4
	b	5b

6:
	/* prepare stack at +1MB from _start. */
	lis	1,_start@h
	ori	1,1,_start@l
	addis	1,1,0x10
	addi	1,1,-4

	bl	brdsetup
	mr	3,30
	mr	4,31
	bl	main

hang:	b	hang
	/* NOTREACHED */

dbat_sanity_check:
	andi.	0,3,BAT_Vs
	beq	2f
	andi.	0,4,BAT_I|BAT_PP_RW
	cmpwi	0,0,BAT_I|BAT_PP_RW
	bnelr
	rlwinm	0,3,15,4,14
	andis.	3,3,0xfffe0000@ha	/* BAT_EPI */
	andis.	4,4,BAT_RPN@ha
	cmplw	0,3,4
	bnelr
	add	4,4,0
	oris	4,4,0x0001ffff@ha
	ori	4,4,0x0001ffff@l
	cmplw	0,3,5
	bgt	1f
	cmplw	0,5,4
	bgt	1f
	li	5,0
1:	cmplw	0,3,6
	bgt	2f
	cmplw	0,6,4
	bgt	2f
	li	6,0
2:	cmplw	0,5,6
	blr

/*
 * run(startsym, endsym, howto, bootinfo, entry)
 */
	.globl	run
run:
	mtctr	7 	/* hat trick jump to entry point */
	bctr

/*
 * reverse endian access to mimic outw/outl/inw/inl
 */
	.globl out16rb
	.globl iohtole16
out16rb:
iohtole16:
	sthbrx	4,0,3
	eieio
	blr 

	.globl out32rb
	.globl iohtole32
out32rb:
iohtole32:
	stwbrx	4,0,3
	eieio
	blr

	.global in16rb
	.global iole16toh
in16rb:
iole16toh:
	lhbrx	3,0,3
	eieio
	blr

	.global in32rb
	.global iole32toh
in32rb:
iole32toh:
	lwbrx	3,0,3
	eieio
	blr

	.data
#define	xBATL(pa, wimg, pp)						\
	((pa) | (wimg) | (pp))
#define	xBATU(va, len, v)						\
	((va) | ((len) & BAT_BL) | ((v) & BAT_V))
BAT123:
	.long xBATL(0x80000000, BAT_I|BAT_G, BAT_PP_RW)
	.long xBATU(0x80000000, BAT_BL_256M, BAT_Vs)
	.long xBATL(0xfc000000, BAT_I|BAT_G, BAT_PP_RW)
	.long xBATU(0xfc000000, BAT_BL_64M, BAT_Vs)
	.long 0
	.long 0

File Added: src/sys/arch/sandpoint/stand/altboot/fxp.c
/* $NetBSD: fxp.c,v 1.1 2011/01/23 01:05:30 nisimura Exp $ */

/*
 * most of the following code was imported from dev/ic/i82557.c; the
 * original copyright notice is as below.
 */

/*-
 * Copyright (c) 1997, 1998, 1999, 2001, 2002 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
 * NASA Ames Research Center.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

/*
 * Copyright (c) 1995, David Greenman
 * Copyright (c) 2001 Jonathan Lemon <jlemon@freebsd.org>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice unmodified, this list of conditions, and the following
 *    disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 *	Id: if_fxp.c,v 1.113 2001/05/17 23:50:24 jlemon
 */

#include <sys/param.h>

#include <netinet/in.h>
#include <netinet/in_systm.h>

#include <lib/libsa/stand.h>
#include <lib/libsa/net.h>

#include <dev/ic/i82557reg.h>

#include "globals.h"

#define FRAMESIZE 1536

/*
 * 82559ER 8086.1209/1229
 *
 * - reverse endian access for 16bit/32bit register.
 * - no vtophys() translation, vaddr_t == paddr_t. 
 * - PIPT writeback cache aware.
 */
#define CSR_WRITE_1(l, r, v)	*(volatile uint8_t *)((l)->iobase+(r)) = (v)
#define CSR_READ_1(l, r)	*(volatile uint8_t *)((l)->iobase+(r))
#define CSR_WRITE_2(l, r, v)	out16rb((l)->iobase+(r), (v))
#define CSR_READ_2(l, r)	in16rb((l)->iobase+(r))
#define CSR_WRITE_4(l, r, v) 	out32rb((l)->iobase+(r), (v))
#define CSR_READ_4(l, r)	in32rb((l)->iobase+(r))
#define VTOPHYS(va) 		(uint32_t)(va)
#define DEVTOV(pa) 		(uint32_t)(pa)
#define wbinv(adr, siz)		_wbinv(VTOPHYS(adr), (uint32_t)(siz))
#define inv(adr, siz)		_inv(VTOPHYS(adr), (uint32_t)(siz))
#define DELAY(n)		delay(n)
#define ALLOC(T,A)		(T *)allocaligned(sizeof(T),(A))

struct txdesc {
	volatile uint16_t cb_status;
	volatile uint16_t cb_command; 
	volatile uint32_t link_addr;
	volatile uint32_t tbd_array_addr;
	volatile uint16_t byte_count;
	volatile uint8_t tx_threshold;
	volatile uint8_t tbd_number;
	volatile uint32_t tx_buf_addr0;
	volatile uint32_t tx_buf_size0;
	volatile uint32_t tx_buf_addr1;
	volatile uint32_t tx_buf_size1;
}; /* mimic extended TxCB layout */

struct rxdesc {
	volatile uint16_t rfa_status;
	volatile uint16_t rfa_control;
	volatile uint32_t link_addr; 
	volatile uint32_t rbd_addr;
	volatile uint16_t actual_size; 
	volatile uint16_t size;
}; /* 16B rfa */

struct local {
	struct txdesc txd;
	uint8_t store[sizeof(struct rxdesc) + FRAMESIZE];
	unsigned iobase;
	unsigned eeprom_addr;
};

static void autosize_eeprom(struct local *);
static int read_eeprom(struct local *, int);
static void fxp_scb_wait(struct local *);
static int fxp_mdi_read(struct local *, int, int);

/*
 * Template for default configuration parameters.
 * See struct fxp_cb_config for the bit definitions.
 */
static uint8_t fxp_cb_config_template[] = {
	0x0, 0x0,		/* cb_status */
	0x80, 0x2,		/* cb_command */
	0xff, 0xff, 0xff, 0xff, /* link_addr */
	0x16,	/*  0 */
	0x8,	/*  1 */
	0x0,	/*  2 */
	0x0,	/*  3 */
	0x0,	/*  4 */
	0x80,	/*  5 */
	0xb2,	/*  6 */
	0x3,	/*  7 */
	0x1,	/*  8 */
	0x0,	/*  9 */
	0x26,	/* 10 */
	0x0,	/* 11 */
	0x60,	/* 12 */
	0x0,	/* 13 */
	0xf2,	/* 14 */
	0x48,	/* 15 */
	0x0,	/* 16 */
	0x40,	/* 17 */
	0xf3,	/* 18 */
	0x0,	/* 19 */
	0x3f,	/* 20 */
	0x5	/* 21 */
};

static struct fxp_cb_config store_cbc;
static struct fxp_cb_ias store_cbi;

int
fxp_match(unsigned tag, void *data)
{
	unsigned v;

	v = pcicfgread(tag, PCI_ID_REG);
	switch (v) {
	case PCI_DEVICE(0x8086, 0x1209):
	case PCI_DEVICE(0x8086, 0x1229):
		return 1;
	}
	return 0;
}

void *
fxp_init(unsigned tag, void *data)
{
	struct local *sc;
	uint8_t *en = data;
	struct fxp_cb_config *cbp = &store_cbc;
	struct fxp_cb_ias *cb_ias = &store_cbi;
	struct rxdesc *rfa;
	unsigned v, i;

	sc = ALLOC(struct local, sizeof(struct txdesc)); /* desc alignment */
	memset(sc, 0, sizeof(struct local));
	sc->iobase = DEVTOV(pcicfgread(tag, 0x10)); /* use mem space */

	CSR_WRITE_4(sc, FXP_CSR_PORT, FXP_PORT_SELECTIVE_RESET);
	DELAY(100);	

	autosize_eeprom(sc);
	v = read_eeprom(sc, 0); en[0] = v; en[1] = v >> 8;
	v = read_eeprom(sc, 1); en[2] = v; en[3] = v >> 8;
	v = read_eeprom(sc, 2); en[4] = v; en[5] = v >> 8;

	printf("MAC address %02x:%02x:%02x:%02x:%02x:%02x, ",
		en[0], en[1], en[2], en[3], en[4], en[5]);

	printf("PHY %d (%04x.%04x)\n", fxp_mdi_read(sc, 1, 18),
	   fxp_mdi_read(sc, 1, 2), fxp_mdi_read(sc, 1, 3));

	/* 
	 * Initialize base of CBL and RFA memory. Loading with zero
	 * sets it up for regular linear addressing.
	 */
	CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL, 0);
	CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_BASE);

	fxp_scb_wait(sc);
	CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_RU_BASE);

	/*
	 * This memcpy is kind of disgusting, but there are a bunch of must be
	 * zero and must be one bits in this structure and this is the easiest
	 * way to initialize them all to proper values.
	 */
	memcpy(cbp, fxp_cb_config_template, sizeof(fxp_cb_config_template));

#define prm 0
#define phy_10Mbps_only 0
#define all_mcasts 0
	cbp->cb_status =	0;
	cbp->cb_command =	htole16(FXP_CB_COMMAND_CONFIG |
				    FXP_CB_COMMAND_EL);
	cbp->link_addr =	-1;	/* (no) next command */
	cbp->byte_count =	22;	/* (22) bytes to config */
	cbp->rx_fifo_limit =	8;	/* rx fifo threshold (32 bytes) */
	cbp->tx_fifo_limit =	0;	/* tx fifo threshold (0 bytes) */
	cbp->adaptive_ifs =	0;	/* (no) adaptive interframe spacing */
	cbp->rx_dma_bytecount = 0;	/* (no) rx DMA max */
	cbp->tx_dma_bytecount = 0;	/* (no) tx DMA max */
	cbp->dma_mbce =		0;	/* (disable) dma max counters */
	cbp->late_scb =		0;	/* (don't) defer SCB update */
	cbp->tno_int_or_tco_en = 0;	/* (disable) tx not okay interrupt */
	cbp->ci_int =		0;	/* interrupt on CU not active */
	cbp->save_bf =		prm;	/* save bad frames */
	cbp->disc_short_rx =	!prm;	/* discard short packets */
	cbp->underrun_retry =	1;	/* retry mode (1) on DMA underrun */
	cbp->mediatype =	!phy_10Mbps_only; /* interface mode */
	cbp->nsai =		1;     /* (don't) disable source addr insert */
	cbp->preamble_length =	2;	/* (7 byte) preamble */
	cbp->loopback =		0;	/* (don't) loopback */
	cbp->linear_priority =	0;	/* (normal CSMA/CD operation) */
	cbp->linear_pri_mode =	0;	/* (wait after xmit only) */
	cbp->interfrm_spacing = 6;	/* (96 bits of) interframe spacing */
	cbp->promiscuous =	prm;	/* promiscuous mode */
	cbp->bcast_disable =	0;	/* (don't) disable broadcasts */
	cbp->crscdt =		0;	/* (CRS only) */
	cbp->stripping =	!prm;	/* truncate rx packet to byte count */
	cbp->padding =		1;	/* (do) pad short tx packets */
	cbp->rcv_crc_xfer =	0;	/* (don't) xfer CRC to host */
	cbp->force_fdx =	0;	/* (don't) force full duplex */
	cbp->fdx_pin_en =	1;	/* (enable) FDX# pin */
	cbp->multi_ia =		0;	/* (don't) accept multiple IAs */
	cbp->mc_all =		all_mcasts;/* accept all multicasts */
#undef prm
#undef phy_10Mbps_only
#undef all_mcasts

	wbinv(cbp, sizeof(*cbp));
	fxp_scb_wait(sc);
	CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL, VTOPHYS(cbp));
	CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_START);
	i = 1000;
	while (!(le16toh(cbp->cb_status) & FXP_CB_STATUS_C) && --i > 0) {
		DELAY(1);
		inv(&cbp->cb_status, sizeof(cbp->cb_status));
	}
	if (i == 0)
		printf("cbp config timeout\n");

	/*
	 * Initialize the station address.
	 */
	cb_ias->cb_status = 0;
	cb_ias->cb_command = htole16(FXP_CB_COMMAND_IAS | FXP_CB_COMMAND_EL);
	cb_ias->link_addr = -1;
	memcpy(cb_ias->macaddr, en, 6);

	/*
	 * Start the IAS (Individual Address Setup) command/DMA.
	 */
	wbinv(cb_ias, sizeof(*cb_ias));
	fxp_scb_wait(sc);
	CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL, VTOPHYS(cb_ias));
	CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_START);

	i = 1000;
	while (!(le16toh(cb_ias->cb_status) & FXP_CB_STATUS_C) && --i > 0) {
		DELAY(1);
		inv(&cb_ias->cb_status, sizeof(cb_ias->cb_status));
	}
	if (i == 0)
		printf("ias config timeout\n");

	rfa = (struct rxdesc *)sc->store;
	rfa->rfa_status = 0;
	rfa->rfa_control = htole16(FXP_RFA_CONTROL_S);
	rfa->link_addr = htole32(VTOPHYS(rfa));
	rfa->rbd_addr = -1;
	rfa->actual_size = 0;
	rfa->size = htole16(sizeof(sc->store) - sizeof(struct rxdesc));
	wbinv(rfa, sizeof(sc->store));

	fxp_scb_wait(sc);
	CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL, VTOPHYS(rfa));
	CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_RU_START);

	return sc;
}

int
fxp_send(void *dev, char *buf, unsigned len)
{
	struct local *l = dev;
	struct txdesc *txd;
	int loop;

	if (len > 1520)
		printf("fxp_send: len > 1520 (%u)\n", len);

	txd = &l->txd;
	txd->cb_status = 0;
	txd->cb_command =
	    htole16(FXP_CB_COMMAND_XMIT|FXP_CB_COMMAND_SF|FXP_CB_COMMAND_EL);
	txd->link_addr = -1;
	txd->tbd_array_addr = htole32(VTOPHYS(&txd->tx_buf_addr0));
	txd->tx_buf_addr0 = htole32(VTOPHYS(buf));
	txd->tx_buf_size0 = htole32(len);
	txd->byte_count = htole16(0x8000);
	txd->tx_threshold = 0x20;
	txd->tbd_number = 1;
	wbinv(buf, len);
	wbinv(txd, sizeof(*txd));

	fxp_scb_wait(l);
	CSR_WRITE_4(l, FXP_CSR_SCB_GENERAL, VTOPHYS(txd));
	CSR_WRITE_1(l, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_START);
	
	loop = 10000;
	while (!(le16toh(txd->cb_status) & FXP_CB_STATUS_C) && --loop > 0) {
		DELAY(1);
		inv(txd, sizeof(struct txdesc));
	}
	if (loop == 0)
		printf("send timeout\n");

	return len;
}

int
fxp_recv(void *dev, char *buf, unsigned maxlen, unsigned timo)
{
	struct local *l = dev;
	struct rxdesc *rfa;
	unsigned bound, ruscus, len;

	fxp_scb_wait(l);
	CSR_WRITE_1(l, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_RU_RESUME);

	bound = 1000 * timo;
	do {
		ruscus = CSR_READ_1(l, FXP_CSR_SCB_RUSCUS);
		if (((ruscus >> 2) & 0x0f) != FXP_SCB_RUS_READY
		    && (((ruscus >> 2) & 0x0f) == FXP_SCB_RUS_SUSPENDED))
			goto gotone;
		DELAY(1000);	/* 1 milli second */
	} while (--bound > 0);
	errno = 0;
	return -1;
  gotone:
	rfa = (struct rxdesc *)l->store;
	inv(rfa, sizeof(l->store)); /* whole including received frame */
	if ((le16toh(rfa->rfa_status) & FXP_RFA_STATUS_C) == 0)
		return 0;
	len = le16toh(rfa->actual_size) & 0x7ff;
	if (len > maxlen)
		len = maxlen;
	memcpy(buf, &l->store[sizeof(struct rxdesc)], len);

	rfa->rfa_status = 0;
	rfa->rfa_control = htole16(FXP_RFA_CONTROL_S);
	rfa->actual_size = 0;
	wbinv(rfa, sizeof(struct rxdesc));
#if 0
	fxp_scb_wait(l);
	CSR_WRITE_1(l, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_RU_RESUME);
#endif
	return len;
}

static void
eeprom_shiftin(struct local *sc, int data, int len)
{
	uint16_t reg;
	int x;

	for (x = 1 << (len - 1); x != 0; x >>= 1) {
		DELAY(40);
		if (data & x)
			reg = FXP_EEPROM_EECS | FXP_EEPROM_EEDI;
		else
			reg = FXP_EEPROM_EECS;
		CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg);
		DELAY(40);
		CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL,
		    reg | FXP_EEPROM_EESK);
		DELAY(40);
		CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg);
	}
	DELAY(40);
}

void
autosize_eeprom(struct local *sc)
{
	int x;

	CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, FXP_EEPROM_EECS);
	DELAY(40);

	/* Shift in read opcode. */
	eeprom_shiftin(sc, FXP_EEPROM_OPC_READ, 3);

	/*
	 * Shift in address, wait for the dummy zero following a correct
	 * address shift.
	 */
	for (x = 1; x <= 8; x++) {
		CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, FXP_EEPROM_EECS);
		DELAY(40);
		CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL,
		    FXP_EEPROM_EECS | FXP_EEPROM_EESK);
		DELAY(40);
		if ((CSR_READ_2(sc, FXP_CSR_EEPROMCONTROL) &
		    FXP_EEPROM_EEDO) == 0)
			break;
		DELAY(40);
		CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, FXP_EEPROM_EECS);
		DELAY(40);
	}
	CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, 0);
	DELAY(40);
	if (x != 6 && x != 8)
		printf("fxp: strange EEPROM address size (%d)\n", x);
	else
		sc->eeprom_addr = x;
}

static int
read_eeprom(struct local *sc, int offset)
{
	uint16_t reg;
	int x, val;

	CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, FXP_EEPROM_EECS);

	/* Shift in read opcode. */
	eeprom_shiftin(sc, FXP_EEPROM_OPC_READ, 3);

	/* Shift in address. */
	eeprom_shiftin(sc, offset, sc->eeprom_addr);

	reg = FXP_EEPROM_EECS;
	val = 0;
	/*
	 * Shift out data.
	 */
	for (x = 16; x > 0; x--) {
		CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL,
		    reg | FXP_EEPROM_EESK);
		DELAY(1);
		if (CSR_READ_2(sc, FXP_CSR_EEPROMCONTROL) &
		    FXP_EEPROM_EEDO)
			val |= (1 << (x - 1));
		CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg);
		DELAY(1);
	}
	CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, 0);
	DELAY(1);

	return val;
}

static void
fxp_scb_wait(struct local *sc)
{
	int loop = 5000;

	while (CSR_READ_1(sc, FXP_CSR_SCB_COMMAND) && --loop > 0)
		DELAY(2);
	if (loop == 0)
		printf("SCB timeout\n");
}

static int
fxp_mdi_read(struct local *sc, int phy, int reg)
{
	int count = 10000;
	int value;

	CSR_WRITE_4(sc, FXP_CSR_MDICONTROL,
	    (FXP_MDI_READ << 26) | (reg << 16) | (phy << 21));

	while (((value = CSR_READ_4(sc, FXP_CSR_MDICONTROL)) &
	    0x10000000) == 0 && count--)
		DELAY(10);

	if (count <= 0)
		printf("fxp_mdi_read: timed out\n");

	return (value & 0xffff);
}

File Added: src/sys/arch/sandpoint/stand/altboot/globals.h
/* $NetBSD: globals.h,v 1.1 2011/01/23 01:05:30 nisimura Exp $ */

/* clock feed */
#ifndef EXT_CLK_FREQ
#define EXT_CLK_FREQ	33333333	/* external clock (PCI clock) */
#endif

/* brd type */
extern int brdtype;
#define BRD_SANDPOINTX2		2
#define BRD_SANDPOINTX3		3
#define BRD_ENCOREPP1		10
#define BRD_KUROBOX		100
#define BRD_QNAPTS101		101
#define BRD_SYNOLOGY		102
#define BRD_STORCENTER		103
#define BRD_UNKNOWN		-1

struct brdprop {
	const char *family;
	const char *verbose;
	int brdtype;
	uint32_t extclk;
	char *consname;
	int consport;
	int consspeed;
	void (*setup)(struct brdprop *);
	void (*brdfix)(struct brdprop *);
	void (*pcifix)(struct brdprop *);
	void (*reset)(void);
};

extern uint32_t cpuclock, busclock;

/* board specific support code */
struct brdprop *brd_lookup(int);
unsigned mpc107memsize(void);
void read_mac_from_flash(uint8_t *);

/* PPC processor ctl */
void __syncicache(void *, size_t);

/* byte swap access */
void out16rb(unsigned, unsigned);
void out32rb(unsigned, unsigned);
unsigned in16rb(unsigned);
unsigned in32rb(unsigned);
void iohtole16(unsigned, unsigned);
void iohtole32(unsigned, unsigned);
unsigned iole32toh(unsigned);
unsigned iole16toh(unsigned);

/* far call would never return */
void run(void *, void *, void *, void *, void *);

/* micro second precision delay */
void delay(unsigned);

/* PCI stuff */
void  pcisetup(void);
void  pcifixup(void);
unsigned pcimaketag(int, int, int);
void  pcidecomposetag(unsigned, int *, int *, int *);
int   pcifinddev(unsigned, unsigned, unsigned *);
int   pcilookup(unsigned, unsigned [][2], int);
unsigned pcicfgread(unsigned, int);
void  pcicfgwrite(unsigned, int, unsigned);

#define PCI_ID_REG			0x00
#define PCI_COMMAND_STATUS_REG		0x04
#define  PCI_VENDOR(id)			((id) & 0xffff)
#define  PCI_PRODUCT(id)		(((id) >> 16) & 0xffff)
#define  PCI_VENDOR_INVALID		0xffff
#define  PCI_DEVICE(v,p)		((v) | ((p) << 16))
#define PCI_CLASS_REG			0x08
#define  PCI_CLASS_PPB			0x0604
#define  PCI_CLASS_ETH			0x0200
#define  PCI_CLASS_IDE			0x0101
#define  PCI_CLASS_RAID			0x0104
#define  PCI_CLASS_SATA			0x0106
#define  PCI_CLASS_MISCSTORAGE		0x0180
#define PCI_BHLC_REG			0x0c
#define  PCI_HDRTYPE_TYPE(r)		(((r) >> 16) & 0x7f)
#define  PCI_HDRTYPE_MULTIFN(r)		((r) & (0x80 << 16))

/*
 * "Map B" layout
 *
 * practice direct mode configuration scheme with CONFIG_ADDR
 * (0xfec0'0000) and CONFIG_DATA (0xfee0'0000).
 */
#define PCI_MEMBASE	0x80000000	/* PCI memory space */
#define PCI_MEMLIMIT	0xfbffffff	/* EUMB is next to this */
#define PCI_IOBASE	0x00001000	/* reserves room for southbridge */
#define PCI_IOLIMIT	0x000fffff
#define PCI_XIOBASE	0xfe000000	/* ISA/PCI io space */
#define CONFIG_ADDR	0xfec00000
#define CONFIG_DATA	0xfee00000

/* cache ops */
void _wb(uint32_t, uint32_t);
void _wbinv(uint32_t, uint32_t);
void _inv(uint32_t, uint32_t);

/* heap */
void *allocaligned(size_t, size_t);

/* NIF support */
int net_open(struct open_file *, ...);
int net_close(struct open_file *);
int net_strategy(void *, int, daddr_t, size_t, void *, size_t *);

int netif_init(unsigned);
int netif_open(void *); 
int netif_close(int); 

#define NIF_DECL(xxx) \
    int xxx ## _match(unsigned, void *); \
    void * xxx ## _init(unsigned, void *); \
    int xxx ## _send(void *, char *, unsigned); \
    int xxx ## _recv(void *, char *, unsigned, unsigned)

NIF_DECL(fxp);
NIF_DECL(tlp);
NIF_DECL(rge);
NIF_DECL(skg);

/* DSK support */
int dskdv_init(unsigned, void **);
int disk_scan(void *);

int dsk_open(struct open_file *, ...);
int dsk_close(struct open_file *);
int dsk_strategy(void *, int, daddr_t, size_t, void *, size_t *);
struct fs_ops *dsk_fsops(struct open_file *);

/* status */
#define ATA_STS_BUSY		0x80
#define ATA_STS_DRDY		0x40
#define ATA_STS_ERR 		0x01
/* command */
#define ATA_CMD_IDENT		0xec
#define ATA_CMD_READ		0x20
#define ATA_CMD_READ_EXT	0x24
#define ATA_CMD_SETF		0xef
/* device */
#define ATA_DEV_LBA		0xe0
#define ATA_DEV_OBS		0x90
/* control */
#define ATA_DREQ		0x08
#define ATA_SRST		0x04

#define ATA_XFER		0x03
#define XFER_PIO4		0x0c
#define XFER_PIO0		0x08

struct dvata_chan {
	uint32_t cmd, ctl, alt, dma;
};
#define _DAT	0	/* RW */
#define _ERR	1	/* R */
#define _FEA	1	/* W */
#define _NSECT	2	/* RW */
#define _LBAL	3	/* RW */
#define _LBAM	4	/* RW */
#define _LBAH	5	/* RW */
#define _DEV	6	/* W */
#define _STS	7	/* R */
#define _CMD	7	/* W */

struct dkdev_ata {
	unsigned tag;
	uint32_t bar[6];
	struct dvata_chan chan[4];
	int presense[4];
	char *iobuf;
};

struct disk {
	char xname[8];
	void *dvops;
	unsigned unittag;
	uint16_t ident[128];
	uint64_t nsect;
	uint64_t first;
	void *dlabel;
	int part;
	void *fsops;
	int (*lba_read)(struct disk *, uint64_t, uint32_t, void *);
};

int spinwait_unbusy(struct dkdev_ata *, int, int, const char **);
int perform_atareset(struct dkdev_ata *, int);
int satapresense(struct dkdev_ata *, int);

File Added: src/sys/arch/sandpoint/stand/altboot/kse.c
/* $NetBSD: kse.c,v 1.1 2011/01/23 01:05:30 nisimura Exp $ */

/*-
 * Copyright (c) 2008 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by Tohru Nishimura.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include <sys/param.h>
 
#include <netinet/in.h>
#include <netinet/in_systm.h>
 
#include <lib/libsa/stand.h>
#include <lib/libsa/net.h>

#include "globals.h"

/*
 * - reverse endian access every CSR.
 * - no VTOPHYS() translation, vaddr_t == paddr_t. 
 * - PIPT writeback cache aware.
 */
#define CSR_READ_4(l, r)	in32rb((l)->csr+(r))
#define CSR_WRITE_4(l, r, v) 	out32rb((l)->csr+(r), (v))
#define CSR_READ_2(l, r)	in16rb((l)->csr+(r))
#define CSR_WRITE_2(l, r, v) 	out16rb((l)->csr+(r), (v))
#define VTOPHYS(va) 		(uint32_t)(va)
#define DEVTOV(pa) 		(uint32_t)(pa)
#define wbinv(adr, siz)		_wbinv(VTOPHYS(adr), (uint32_t)(siz))
#define inv(adr, siz)		_inv(VTOPHYS(adr), (uint32_t)(siz))
#define DELAY(n)		delay(n)
#define ALLOC(T,A)		(T *)allocaligned(sizeof(T),(A))

struct desc {
	uint32_t xd0, xd1, xd2, xd3;
};
#define T0_OWN		(1U<<31)	/* desc is ready to Tx */
#define T1_IC		(1U<<31)	/* post interrupt on complete */
#define T1_FS		(1U<<30)	/* first segment of frame */
#define T1_LS		(1U<<29)	/* last segment of frame */
#define T1_TER		(1U<<25)	/* end of ring */
#define T1_SPN		0x00300000	/* 21:20 switch port 1/2 */
#define T1_TBS_MASK	0x7ff		/* segment size 10:0 */

#define R0_OWN		(1U<<31)	/* desc is empty */
#define R0_FS		(1U<<30)	/* first segment of frame */
#define R0_LS		(1U<<29)	/* last segment of frame */
#define R0_IPE		(1U<<28)	/* IP checksum error */
#define R0_TCPE		(1U<<27)	/* TCP checksum error */
#define R0_UDPE		(1U<<26)	/* UDP checksum error */
#define R0_ES		(1U<<25)	/* error summary */
#define R0_MF		(1U<<24)	/* multicast frame */
#define R0_SPN		0x00300000	/* 21:20 switch port 1/2 */
#define R0_RE		(1U<<19)	/* MII reported error */
#define R0_TL		(1U<<18)	/* frame too long, beyond 1518 */
#define R0_RF		(1U<<17)	/* damaged runt frame */
#define R0_CE		(1U<<16)	/* CRC error */
#define R0_FT		(1U<<15)	/* frame type */
#define R0_FL_MASK	0x7ff		/* frame length 10:0 */
#define R1_RER		(1U<<25)	/* end of ring */
#define R1_RBS_MASK	0x7fc		/* segment size 10:0 */

#define MDTXC	0x000	/* DMA transmit control */
#define MDRXC	0x004	/* DMA receive control */
#define MDTSC	0x008	/* DMA transmit start */
#define MDRSC	0x00c	/* DMA receive start */
#define TDLB	0x010	/* transmit descriptor list base */
#define RDLB	0x014	/* receive descriptor list base */
#define MARL	0x200	/* MAC address low */
#define MARM	0x202	/* MAC address middle */
#define MARH	0x204	/* MAC address high */
#define CIDR	0x400	/* chip ID and enable */
#define P1CR4	0x512	/* port 1 control 4 */
#define P1SR	0x514	/* port 1 status */

#define FRAMESIZE	1536

struct local {
	struct desc txd[2];
	struct desc rxd[2];
	uint8_t rxstore[2][FRAMESIZE];
	unsigned csr, tx, rx;
};

static void mii_dealan(struct local *, unsigned);

int
kse_match(unsigned tag, void *data)
{
	unsigned v;

	v = pcicfgread(tag, PCI_ID_REG);
	switch (v) {
	case PCI_DEVICE(0x16c6, 0x8841):
	case PCI_DEVICE(0x16c6, 0x8842):
		return 1;
	}
	return 0;
}

void *
kse_init(unsigned tag, void *data)
{
	struct local *l;
	struct desc *txd, *rxd;
	unsigned i, val, fdx;
	uint8_t *en;

	l = ALLOC(struct local, 32); /* desc alignment */
	memset(l, 0, sizeof(struct local));
	l->csr = DEVTOV(pcicfgread(tag, 0x10));

	en = data;
	i = CSR_READ_2(l, MARL);
	en[0] = i;
	en[1] = i >> 8;
	i = CSR_READ_2(l, MARM);
	en[2] = i;
	en[3] = i >> 8;
	i = CSR_READ_2(l, MARH);
	en[4] = i;
	en[5] = i >> 8;

	printf("MAC address %02x:%02x:%02x:%02x:%02x:%02x\n",
	    en[0], en[1], en[2], en[3], en[4], en[5]);

	CSR_WRITE_2(l, CIDR, 1);

	mii_dealan(l, 5);

	val = pcicfgread(tag, PCI_ID_REG);
	if (PCI_PRODUCT(val) == 0x8841) {
		val = CSR_READ_2(l, P1SR);
		fdx = !!(val & (1U << 9));
		printf("%s", (val & (1U << 8)) ? "100Mbps" : "10Mbps");
		if (fdx)
			printf("-FDX");
		printf("\n");
	}

	txd = &l->txd[0];
	rxd = &l->rxd[0];
	rxd[0].xd0 = htole32(R0_OWN);
	rxd[0].xd1 = htole32(FRAMESIZE);
	rxd[0].xd2 = htole32(VTOPHYS(l->rxstore[0]));
	rxd[0].xd3 = htole32(VTOPHYS(&rxd[1]));
	rxd[1].xd0 = htole32(R0_OWN);
	rxd[1].xd1 = htole32(R1_RER | FRAMESIZE);
	rxd[1].xd2 = htole32(VTOPHYS(l->rxstore[1]));
	rxd[1].xd3 = htole32(VTOPHYS(&rxd[0]));
	l->tx = l->rx = 0;

	CSR_WRITE_4(l, TDLB, VTOPHYS(txd));
	CSR_WRITE_4(l, RDLB, VTOPHYS(rxd));
	CSR_WRITE_4(l, MDTXC, 07); /* stretch short, add CRC, Tx enable */
	CSR_WRITE_4(l, MDRXC, 01); /* Rx enable */
	CSR_WRITE_4(l, MDRSC, 01); /* start receiving */

	return l;
}

int
kse_send(void *dev, char *buf, unsigned len)
{
	struct local *l = dev;
	volatile struct desc *txd;
	unsigned txstat, loop;

	wbinv(buf, len);
	txd = &l->txd[l->tx];
	txd->xd2 = htole32(VTOPHYS(buf));
	txd->xd1 = htole32(T1_FS | T1_LS | (len & T1_TBS_MASK));
	txd->xd0 = htole32(T0_OWN);
	wbinv(txd, sizeof(struct desc));
	CSR_WRITE_4(l, MDTSC, 01); /* start transmission */
	loop = 100;
	do {
		txstat = le32toh(txd->xd0);
		if ((txstat & T0_OWN) == 0)
			goto done;
		DELAY(10);
		inv(txd, sizeof(struct desc));
	} while (--loop != 0);
	printf("xmit failed\n");
	return -1;
  done:
	l->tx ^= 1;
	return len;
}

int
kse_recv(void *dev, char *buf, unsigned maxlen, unsigned timo)
{
	struct local *l = dev;
	volatile struct desc *rxd;
	unsigned bound, rxstat, len;
	uint8_t *ptr;

	bound = 1000 * timo;
printf("recving with %u sec. timeout\n", timo);
  again:
	rxd = &l->rxd[l->rx];
	do {
		inv(rxd, sizeof(struct desc));
		rxstat = le32toh(rxd->xd0);
		if ((rxstat & R0_OWN) == 0)
			goto gotone;
		DELAY(1000); /* 1 milli second */
	} while (--bound > 0);
	errno = 0;
	return -1;
  gotone:
	if (rxstat & R0_ES) {
		rxd->xd0 = htole32(R0_OWN);
		wbinv(rxd, sizeof(struct desc));
		l->rx ^= 1;
		CSR_WRITE_4(l, MDRSC, 01); /* restart receiving */
		goto again;
	}
	/* good frame */
	len = (rxstat & R0_FL_MASK) - 4 /* HASFCS */;
        if (len > maxlen)
                len = maxlen;
	ptr = l->rxstore[l->rx];
        inv(ptr, len);
        memcpy(buf, ptr, len);
	rxd->xd0 = htole32(R0_OWN);
	wbinv(rxd, sizeof(struct desc));
	l->rx ^= 1;
	CSR_WRITE_4(l, MDRSC, 01); /* necessary? */
	return len;
}

void
mii_dealan(struct local *l, unsigned timo)
{
	unsigned val, bound;

	val = (1U << 13) | (1U << 7) | 0x1f /* advertise all caps */;
	CSR_WRITE_2(l, P1CR4, val);
	bound = getsecs() + timo;
	do {
		val = CSR_READ_2(l, P1SR);
		if (val & (1U << 5)) /* link is found up */
			break;
		DELAY(10 * 1000);
	} while (getsecs() < bound);
	return;
}

File Added: src/sys/arch/sandpoint/stand/altboot/main.c
/* $NetBSD: main.c,v 1.1 2011/01/23 01:05:30 nisimura Exp $ */

/*-
 * Copyright (c) 2007 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by Tohru Nishimura.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include <sys/param.h>
#include <sys/reboot.h>

#include <lib/libsa/stand.h>
#include <lib/libsa/loadfile.h>
#include <lib/libkern/libkern.h>

#include <machine/bootinfo.h>

#include "globals.h"

static const struct bootarg {
	const char *name;
	int value;
} bootargs[] = {
	{ "multi",	RB_AUTOBOOT },
	{ "auto",	RB_AUTOBOOT },
	{ "ask",	RB_ASKNAME },
	{ "single",	RB_SINGLE },
	{ "ddb",	RB_KDB },
	{ "userconf",	RB_USERCONF },
	{ "norm",	AB_NORMAL },
	{ "quiet",	AB_QUIET },
	{ "verb",	AB_VERBOSE },
	{ "silent",	AB_SILENT },
	{ "debug",	AB_DEBUG }
};

void *bootinfo; /* low memory reserved to pass bootinfo structures */
int bi_size;	/* BOOTINFO_MAXSIZE */
char *bi_next;

void bi_init(void *);
void bi_add(void *, int, int);

struct btinfo_memory bi_mem;
struct btinfo_console bi_cons;
struct btinfo_clock bi_clk;
struct btinfo_prodfamily bi_fam;
struct btinfo_bootpath bi_path;
struct btinfo_rootdevice bi_rdev;
struct btinfo_net bi_net;
struct btinfo_modulelist *btinfo_modulelist;
size_t btinfo_modulelist_size;

struct boot_module {
	char *bm_kmod;
	ssize_t bm_len;
	struct boot_module *bm_next;
};
struct boot_module *boot_modules;
char module_base[80];
uint32_t kmodloadp;
int modules_enabled = 0;

void module_add(char *);
void module_load(char *);
int module_open(struct boot_module *);

void main(int, char **);
extern char bootprog_rev[], bootprog_maker[], bootprog_date[];

int brdtype;
uint32_t busclock, cpuclock;

static int check_bootname(char *);
#define	BNAME_DEFAULT "nfs:"

void
main(int argc, char *argv[])
{
	struct brdprop *brdprop;
	unsigned long marks[MARK_MAX];
	unsigned lata[1][2], lnif[1][2];
	unsigned tag, dsk;
	int b, d, f, fd, howto, i, n;
	char *bname;
	void *dev;

	printf("\n");
	printf(">> NetBSD/sandpoint Boot, Revision %s\n", bootprog_rev);
	printf(">> (%s, %s)\n", bootprog_maker, bootprog_date);

	brdprop = brd_lookup(brdtype);
	printf("%s, cpu %u MHz, bus %u MHz, %dMB SDRAM\n", brdprop->verbose,
	    cpuclock / 1000000, busclock / 1000000, bi_mem.memsize >> 20);

	n = pcilookup(PCI_CLASS_IDE, lata, sizeof(lata)/sizeof(lata[0]));
	if (n == 0)
		n = pcilookup(PCI_CLASS_MISCSTORAGE, lata,
		    sizeof(lata)/sizeof(lata[0]));
	if (n == 0) {
		dsk = ~0;
		printf("no IDE found\n");
	}
	else {
		dsk = lata[0][1];
		pcidecomposetag(dsk, &b, &d, &f);
		printf("%04x.%04x IDE %02d:%02d:%02d\n",
		    PCI_VENDOR(lata[0][0]), PCI_PRODUCT(lata[0][0]),
		    b, d, f);
	}

	n = pcilookup(PCI_CLASS_ETH, lnif, sizeof(lnif)/sizeof(lnif[0]));
	if (n == 0) {
		tag = ~0;
		printf("no NIC found\n");
	}
	else {
		tag = lnif[0][1];
		pcidecomposetag(tag, &b, &d, &f);
		printf("%04x.%04x NIC %02d:%02d:%02d\n",
		    PCI_VENDOR(lnif[0][0]), PCI_PRODUCT(lnif[0][0]),
		    b, d, f);
	}

	pcisetup();
	pcifixup();

	if (dskdv_init(dsk, &dev) == 0 || disk_scan(dev) == 0)
		printf("no IDE/SATA device driver was found\n");

	if (netif_init(tag) == 0)
		printf("no NIC device driver was found\n");

	howto = RB_AUTOBOOT;		/* default is autoboot = 0 */

	/* get boot options and determine bootname */
	for (n = 1; n < argc; n++) {
		for (i = 0; i < sizeof(bootargs) / sizeof(bootargs[0]); i++) {
			if (strncasecmp(argv[n], bootargs[i].name,
			    strlen(bootargs[i].name)) == 0) {
				howto |= bootargs[i].value;
				break;
			}
		}
		if (i >= sizeof(bootargs) / sizeof(bootargs[0]))
			break;	/* break on first unknown string */
	}
	if (n >= argc)
		bname = BNAME_DEFAULT;
	else {
		bname = argv[n];
		if (check_bootname(bname) == 0) {
			printf("%s not a valid bootname\n", bname);
			goto loadfail;
		}
	}

	if ((fd = open(bname, 0)) < 0) {
		if (errno == ENOENT)
			printf("\"%s\" not found\n", bi_path.bootpath);
		goto loadfail;
	}
	printf("loading \"%s\" ", bi_path.bootpath);
	marks[MARK_START] = 0;
	if (fdloadfile(fd, marks, LOAD_KERNEL) < 0)
		goto loadfail;
	close(fd);

	printf("entry=%p, ssym=%p, esym=%p\n",
	    (void *)marks[MARK_ENTRY],
	    (void *)marks[MARK_SYM],
	    (void *)marks[MARK_END]);

	bootinfo = (void *)0x4000;
	bi_init(bootinfo);
	bi_add(&bi_cons, BTINFO_CONSOLE, sizeof(bi_cons));
	bi_add(&bi_mem, BTINFO_MEMORY, sizeof(bi_mem));
	bi_add(&bi_clk, BTINFO_CLOCK, sizeof(bi_clk));
	bi_add(&bi_path, BTINFO_BOOTPATH, sizeof(bi_path));
	bi_add(&bi_rdev, BTINFO_ROOTDEVICE, sizeof(bi_rdev));
	bi_add(&bi_fam, BTINFO_PRODFAMILY, sizeof(bi_fam));
	if (brdtype == BRD_SYNOLOGY) {
		/* need to set MAC address for Marvell-SKnet */
		bi_add(&bi_net, BTINFO_NET, sizeof(bi_net));
	}

	if (modules_enabled) {
		module_add(fsmod);
		if (fsmod2 != NULL && strcmp(fsmod, fsmod2) != 0)
			module_add(fsmod2);
		kmodloadp = marks[MARK_END];
		btinfo_modulelist = NULL;
		module_load(bname);
		if (btinfo_modulelist != NULL && btinfo_modulelist->num > 0)
			bi_add(btinfo_modulelist, BTINFO_MODULELIST,
			    btinfo_modulelist_size);
	}

	__syncicache((void *)marks[MARK_ENTRY],
	    (u_int)marks[MARK_SYM] - (u_int)marks[MARK_ENTRY]);

	run((void *)marks[MARK_SYM], (void *)marks[MARK_END],
	    (void *)howto, bootinfo, (void *)marks[MARK_ENTRY]);

	/* should never come here */
	printf("exec returned. Restarting...\n");
	_rtt();

  loadfail:
	printf("load failed. Restarting...\n");
	_rtt();
}

void
bi_init(void *addr)
{
	struct btinfo_magic bi_magic;

	memset(addr, 0, BOOTINFO_MAXSIZE);
	bi_next = (char *)addr;
	bi_size = 0;

	bi_magic.magic = BOOTINFO_MAGIC;
	bi_add(&bi_magic, BTINFO_MAGIC, sizeof(bi_magic));
}

void
bi_add(void *new, int type, int size)
{
	struct btinfo_common *bi;

	if (bi_size + size > BOOTINFO_MAXSIZE)
		return;				/* XXX error? */

	bi = new;
	bi->next = size;
	bi->type = type;
	memcpy(bi_next, new, size);
	bi_next += size;
}

void
module_add(char *name)
{
	struct boot_module *bm, *bmp;

	while (*name == ' ' || *name == '\t')
		++name;

	bm = alloc(sizeof(struct boot_module) + strlen(name) + 1);
	if (bm == NULL) {
		printf("couldn't allocate module %s\n", name); 
		return; 
	}

	bm->bm_kmod = (char *)(bm + 1);
	bm->bm_len = -1;
	bm->bm_next = NULL;
	strcpy(bm->bm_kmod, name);
	if ((bmp = boot_modules) == NULL)
		boot_modules = bm;
	else {
		while (bmp->bm_next != NULL)
			bmp = bmp->bm_next;
		bmp->bm_next = bm;
	}
}

#define PAGE_SIZE	4096
#define alignpg(x)	(((x)+PAGE_SIZE-1) & ~(PAGE_SIZE-1))

void
module_load(char *kernel_path) 
{
	struct boot_module *bm;
	struct bi_modulelist_entry *bi;
	struct stat st;
	char *p; 
	int size, fd;

	strcpy(module_base, kernel_path);
	if ((p = strchr(module_base, ':')) == NULL)
		return; /* eeh?! */
	p += 1;
	size = sizeof(module_base) - (p - module_base);

	if (netbsd_version / 1000000 % 100 == 99) {
		/* -current */
		snprintf(p, size,
		    "/stand/sandpoint/%d.%d.%d/modules",
		    netbsd_version / 100000000,
		    netbsd_version / 1000000 % 100,
		    netbsd_version / 100 % 100);
	}
	 else if (netbsd_version != 0) {
		/* release */
		snprintf(p, size,
		    "/stand/sandpoint/%d.%d/modules",
		    netbsd_version / 100000000,
		    netbsd_version / 1000000 % 100);
	}

	/*
	 * 1st pass; determine module existence
	 */
	size = 0;
	for (bm = boot_modules; bm != NULL; bm = bm->bm_next) {
		fd = module_open(bm);
		if (fd == -1)
			continue;
		if (fstat(fd, &st) == -1 || st.st_size == -1) {
			printf("WARNING: couldn't stat %s\n", bm->bm_kmod);
			close(fd);
			continue;
		}
		bm->bm_len = (int)st.st_size;
		close(fd);
		size += sizeof(struct bi_modulelist_entry); 
	}
	if (size == 0)
		return;

	size += sizeof(struct btinfo_modulelist);
	btinfo_modulelist = alloc(size);
	if (btinfo_modulelist == NULL) {
		printf("WARNING: couldn't allocate module list\n");
		return;
	}
	btinfo_modulelist_size = size;
	btinfo_modulelist->num = 0;

	/*
	 * 2nd pass; load modules into memory
	 */
	kmodloadp = alignpg(kmodloadp);
	bi = (struct bi_modulelist_entry *)(btinfo_modulelist + 1);
	for (bm = boot_modules; bm != NULL; bm = bm->bm_next) {
		if (bm->bm_len == -1)
			continue; /* already found unavailable */
		fd = module_open(bm);
		printf("module \"%s\" ", bm->bm_kmod);
		size = read(fd, (char *)kmodloadp, SSIZE_MAX);
		if (size < bm->bm_len)
			printf("WARNING: couldn't load");
		else {
			snprintf(bi->kmod, sizeof(bi->kmod), bm->bm_kmod);
			bi->type = BI_MODULE_ELF;
			bi->len = size;
			bi->base = kmodloadp;
			btinfo_modulelist->num += 1;
			printf("loaded at 0x%08x size 0x%x", kmodloadp, size);
			kmodloadp += alignpg(size);
			bi += 1;
		}
		printf("\n");
		close(fd);
	}
	btinfo_modulelist->endpa = kmodloadp;
}

int
module_open(struct boot_module *bm)
{
	char path[80];
	int fd;

	snprintf(path, sizeof(path),
	    "%s/%s/%s.kmod", module_base, bm->bm_kmod, bm->bm_kmod);
	fd = open(path, 0);
	return fd;
}

#if 0
static const char *cmdln[] = {
	"console=ttyS0,115200 root=/dev/sda1 rw initrd=0x200000,2M",
	"console=ttyS0,115200 root=/dev/nfs ip=dhcp"
};

void
mkatagparams(unsigned addr, char *kcmd)
{
	struct tag {
		unsigned siz;
		unsigned tag;
		unsigned val[1];
	};
	struct tag *p;
#define ATAG_CORE 	0x54410001
#define ATAG_MEM	0x54410002
#define ATAG_INITRD	0x54410005
#define ATAG_CMDLINE	0x54410009
#define ATAG_NONE	0x00000000
#define tagnext(p) (struct tag *)((unsigned *)(p) + (p)->siz)
#define tagsize(n) (2 + (n))

	p = (struct tag *)addr;
	p->tag = ATAG_CORE;
	p->siz = tagsize(3);
	p->val[0] = 0;		/* flags */
	p->val[1] = 0;		/* pagesize */
	p->val[2] = 0;		/* rootdev */
	p = tagnext(p);
	p->tag = ATAG_MEM;
	p->siz = tagsize(2);
	p->val[0] = 64 * 1024 * 1024;
	p->val[1] = 0;		/* start */
	p = tagnext(p);
	if (kcmd != NULL) {
		p = tagnext(p);
		p->tag = ATAG_CMDLINE;
		p->siz = tagsize((strlen(kcmd) + 1 + 3) >> 2);
		strcpy((void *)p->val, kcmd);
	}
	p = tagnext(p);
	p->tag = ATAG_NONE;
	p->siz = 0;
}
#endif

void *
allocaligned(size_t size, size_t align)
{
	uint32_t p;

	if (align-- < 2)
		return alloc(size);
	p = (uint32_t)alloc(size + align);
	return (void *)((p + align) & ~align);
}

static int
check_bootname(char *s)
{
	/*
	 * nfs:
	 * nfs:<bootfile>
	 * tftp:
	 * tftp:<bootfile>
	 * wd[N[P]]:<bootfile>
	 *
	 * net is a synonym of nfs.
	 */
	if (strncmp(s, "nfs:", 4) == 0 || strncmp(s, "net:", 4) == 0)
		return 1;
	if (strncmp(s, "tftp:", 5) == 0)
		return 1;
	if (s[0] == 'w' && s[1] == 'd') {
		s += 2;
		if (*s != ':' && *s >= '0' && *s <= '3') {
			++s;
			if (*s != ':' && *s >= 'a' && *s <= 'p')
				++s;
		}
		return *s == ':';
	}
	return 0;
}

File Added: src/sys/arch/sandpoint/stand/altboot/nif.c
/* $NetBSD: nif.c,v 1.1 2011/01/23 01:05:30 nisimura Exp $ */

/*-
 * Copyright (c) 2007 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by Tohru Nishimura.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include <sys/param.h>

#include <netinet/in.h>
#include <netinet/in_systm.h>

#include <lib/libsa/stand.h>
#include <lib/libsa/net.h>

#include <machine/bootinfo.h>

#include "globals.h"

struct nifdv {
	char *name;
	int (*match)(unsigned, void *);
	void *(*init)(unsigned, void *);
	int (*send)(void *, char *, unsigned);
	int (*recv)(void *, char *, unsigned, unsigned);
	int (*halt)(void *, int);
	void *priv;
};

static struct iodesc netdesc;

static struct nifdv lnifdv[] = {
	{ "fxp", fxp_match, fxp_init, fxp_send, fxp_recv },
	{ "tlp", tlp_match, tlp_init, tlp_send, tlp_recv },
	{ "re",  rge_match, rge_init, rge_send, rge_recv },
	{ "sk",  skg_match, skg_init, skg_send, skg_recv },
};
static int nnifdv = sizeof(lnifdv)/sizeof(lnifdv[0]);

int
netif_init(unsigned tag)
{
	struct iodesc *s;
	struct nifdv *dv;
	int n;
	uint8_t enaddr[6];
	extern struct btinfo_net bi_net;
	extern struct btinfo_rootdevice bi_rdev;

	for (n = 0; n < nnifdv; n++) {
		dv = &lnifdv[n];
		if ((*dv->match)(tag, NULL) > 0)
			goto found;
	}
	return 0;
  found:
	dv->priv = (*dv->init)(tag, enaddr);
	s = &netdesc;
	s->io_netif = dv;
	memcpy(s->myea, enaddr, sizeof(s->myea));

	/* build btinfo to identify NIF device */
	snprintf(bi_net.devname, sizeof(bi_net.devname), dv->name);
	memcpy(bi_net.mac_address, enaddr, sizeof(bi_net.mac_address));
	bi_net.cookie = tag;
	snprintf(bi_rdev.devname, sizeof(bi_rdev.devname), dv->name);
	bi_rdev.cookie = tag;
	return 1;
}

int
netif_open(void *cookie)
{
	/* single action */
	return 0;
}

int
netif_close(int sock)
{
	/* nothing to do for the HW */
	return 0;
}

/*
 * Send a packet.  The ether header is already there.
 * Return the length sent (or -1 on error).
 */
ssize_t
netif_put(struct iodesc *desc, void *pkt, size_t len)
{
	struct nifdv *dv = desc->io_netif;

	return dv ? (*dv->send)(dv->priv, pkt, len) : -1;
}

/*
 * Receive a packet, including the ether header.
 * Return the total length received (or -1 on error).
 */
ssize_t
netif_get(struct iodesc *desc, void *pkt, size_t maxlen, saseconds_t timo)
{
	struct nifdv *dv = desc->io_netif;
	int len;

	len = dv ? (*dv->recv)(dv->priv, pkt, maxlen, timo) : -1;
	if (len == -1)
		printf("timeout\n");
	return len;
}

struct iodesc *
socktodesc(int num)
{

	return (num == 0) ? &netdesc : NULL;
}

File Added: src/sys/arch/sandpoint/stand/altboot/nvt.c
/* $NetBSD: nvt.c,v 1.1 2011/01/23 01:05:30 nisimura Exp $ */

/*-
 * Copyright (c) 2007 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by Tohru Nishimura.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include <sys/param.h>

#include <netinet/in.h>
#include <netinet/in_systm.h>

#include <lib/libsa/stand.h>
#include <lib/libsa/net.h>

#include "globals.h"

/*
 * - reverse endian access every CSR.
 * - no vtophys() translation, vaddr_t == paddr_t.
 * - PIPT writeback cache aware.
 */
#define CSR_WRITE_1(l, r, v)	*(volatile uint8_t *)((l)->csr+(r)) = (v)
#define CSR_READ_1(l, r)	*(volatile uint8_t *)((l)->csr+(r))
#define CSR_WRITE_2(l, r, v)	out16rb((l)->csr+(r), (v))
#define CSR_READ_2(l, r)	in16rb((l)->csr+(r))
#define CSR_WRITE_4(l, r, v)	out32rb((l)->csr+(r), (v))
#define CSR_READ_4(l, r)	in32rb((l)->csr+(r))
#define VTOPHYS(va)		(uint32_t)(va)
#define DEVTOV(pa)		(uint32_t)(pa)
#define wbinv(adr, siz)		_wbinv(VTOPHYS(adr), (uint32_t)(siz))
#define inv(adr, siz)		_inv(VTOPHYS(adr), (uint32_t)(siz))
#define DELAY(n)		delay(n)
#define ALLOC(T,A)		(T *)allocaligned(sizeof(T),(A))

struct desc {
	uint32_t xd0, xd1, xd2, xd3;
};
#define T0_OWN		(1U << 31)	/* 1: loaded for HW to send */
#define T0_TERR		(1U << 15)	/* Tx error; ABT|CBH */
#define T0_UDF		(1U << 11)	/* FIFO underflow */
#define T0_CRS		(1U << 10)	/* found carrier sense lost */
#define T0_OWC		(1U << 9)	/* found out of window collision */
#define T0_ABT		(1U << 8)	/* excess collision Tx abort */
#define T0_CBH		(1U << 7)	/* heartbeat check failure */
#define T0_COLS		(1U << 4)	/* collision detected */
#define T0_NCRMASK	0x3		/* number of collision retries */
#define T1_IC		(1U << 23)	/* post Tx done interrupt */
#define T1_STP		(1U << 22)	/* first frame segment */
#define T1_EDP		(1U << 21)	/* last frame segment */
#define T1_CRC		(1U << 16)	/* _disable_ CRC generation */
#define T1_CHN		(1U << 15)	/* "more bit," not the last seg. */
#define T_FLMASK	0x00007fff	/* Tx frame/segment length */

#define R0_OWN		(1U << 31)	/* 1: empty for HW to load anew */
#define R0_FLMASK	0x7fff0000	/* frame length */
#define R0_RXOK		(1U << 15)
#define R0_MAR		(1U << 13)	/* multicast frame */
#define R0_BAR		(1U << 12)	/* broadcast frame */
#define R0_PHY		(1U << 11)	/* unicast frame */
#define R0_CHN		(1U << 10)	/* "more bit," not the last seg. */
#define R0_STP		(1U << 9)	/* first frame segment */
#define R0_EDP		(1U << 8)	/* last frame segment */
#define R0_BUFF		(1U << 7)	/* segment chain was broken */
#define R0_RUNT		(1U << 5)	/* runt frame received */
#define R0_LONG		(1U << 4)	/* frame too long */
#define R0_FOV		(1U << 3)	/* Rx FIFO overflow */
#define R0_FAE		(1U << 2)	/* frame alignment error */
#define R0_CRCE		(1U << 1)	/* CRC error */
#define R0_RERR		(1U << 0)	/* Rx error summary */
#define R1_FLMASK	0x00007ffc	/* Rx segment buffer length */

#define VR_PAR0		0x00		/* SA [0] */
#define VR_PAR1		0x01		/* SA [1] */
#define VR_PAR2		0x02		/* SA [2] */
#define VR_PAR3		0x03		/* SA [3] */
#define VR_PAR4		0x04		/* SA [4] */
#define VR_PAR5		0x05		/* SA [5] */
#define VR_RCR		0x06		/* Rx control */
#define  RCR_PROM	(1U << 4)	/* accept any frame */
#define  RCR_AB		(1U << 3)	/* accept broadcast frame */
#define  RCR_AM		(1U << 2)	/* use multicast filter */
#define VR_TCR		0x07		/* Tx control */
#define VR_CTL0		0x08		/* control #0 */
#define  CTL0_RDMD	(1U << 6)	/* instruct Rx descriptor poll */
#define  CTL0_TDMD	(1U << 5)	/* instruct Tx descriptor poll */
#define  CTL0_TXON	(1U << 4)	/* enable Tx DMA */
#define  CTL0_RXON	(1U << 3)	/* enable Rx DMA */
#define  CTL0_STOP	(1U << 2)	/* activate stop processing */
#define  CTL0_START	(1U << 1)	/* start and activate */
#define VR_CTL1		0x09		/* control #1 */
#define  CTL1_RESET	(1U << 7)	/* SW reset, self-clearing */
#define  CTL1_DPOLL	(1U << 3)	/* _disable_ Tx auto polling */
#define  CTL1_FDX	(1U << 2)	/* set full duplex */
#define VR_ISR		0x0c		/* interrupt status */
#define VR_IEN		0x0e		/* interrupt enable */
#define VR_RDBA		0x18		/* Rx descriptor list base */
#define VR_TDBA		0x1c		/* Tx descriptor list base */
#define VR_MIICFG	0x6c		/* 4:0 PHY number */
#define VR_MIISR	0x6d		/* MII status */
#define VR_MIICR	0x70		/* MII control */
#define  MIICR_MAUTO	(1U << 7)	/* activate autopoll mode */
#define  MIICR_RCMD	(1U << 6)	/* MII read operation */
#define  MIICR_WCMD	(1U << 5)	/* MII write operation */
#define VR_MIIADR	0x71		/* MII indirect */
#define  MIIADR_MIDLE	(1U << 7)	/* not in auto polling */
#define VR_MIIDATA	0x72		/* MII read/write */
#define VR_RXC		0x7e		/* Rx feature control */
#define VR_TXC		0x7f		/* Tx feature control */
#define VR_MCR0		0x80		/* misc control #0 */
#define  MCR0_RFDXFLC	(1U << 3)	/* FCR1? */
#define  MCR0_HDXFLC	(1U << 2)	/* FCR2? */
#define VR_MCR1		0x81		/* misc control #1 */

#define FRAMESIZE	1536

struct local {
	struct desc txd[2];
	struct desc rxd[2];
	uint8_t rxstore[2][FRAMESIZE];
	unsigned csr, tx, rx;
	unsigned phy, bmsr, anlpar;
	unsigned ctl0;
};

static void mii_autopoll(struct local *);
static void mii_stoppoll(struct local *);
static int mii_read(struct local *, int, int);
static void mii_write(struct local *, int, int, int);
static void mii_dealan(struct local *, unsigned);

int
nvt_match(unsigned tag, void *data)
{
	unsigned v;

	v = pcicfgread(tag, PCI_ID_REG);
	switch (v) {
	case PCI_DEVICE(0x1106, 0x3053):
	case PCI_DEVICE(0x1106, 0x3065):
		return 1;
	}
	return 0;
}

void *
nvt_init(unsigned tag, void *data)
{
	unsigned val, fdx;
	struct local *l;
	struct desc *txd, *rxd;
	uint8_t *en;

	l = ALLOC(struct local, 32); /* desc alignment */
	memset(l, 0, sizeof(struct local));
	l->csr = ~01 & DEVTOV(pcicfgread(tag, 0x10)); /* use IO space */

	val = CTL1_RESET;
	CSR_WRITE_1(l, VR_CTL1, val);
	do {
		val = CSR_READ_1(l, VR_CTL1);
	} while (val & CTL1_RESET);
	/* PHY number is loaded from EEPROM */
	l->phy = CSR_READ_1(l, VR_MIICFG) & 0x1f;

	en = data;
	en[0] = CSR_READ_1(l, VR_PAR0);
	en[1] = CSR_READ_1(l, VR_PAR1);
	en[2] = CSR_READ_1(l, VR_PAR2);
	en[3] = CSR_READ_1(l, VR_PAR3);
	en[4] = CSR_READ_1(l, VR_PAR4);
	en[5] = CSR_READ_1(l, VR_PAR5);

	printf("MAC address %02x:%02x:%02x:%02x:%02x:%02x\n",
	    en[0], en[1], en[2], en[3], en[4], en[5]);
	printf("PHY %d (%04x.%04x)\n", l->phy,
	    mii_read(l, l->phy, 2), mii_read(l, l->phy, 3));

	mii_dealan(l, 5);

	/* speed and duplexity can be seen in MII 20 */
	val = mii_read(l, l->phy, 20);
	fdx = !!(val & (1U << 0));
	printf("%s", (val & (1U << 1)) ? "100Mbps" : "10Mbps");
	if (fdx)
		printf("-FDX");
	printf("\n");

	txd = &l->txd[0];
	rxd = &l->rxd[0];
	rxd[0].xd0 = htole32(R0_OWN);
	rxd[0].xd1 = htole32(FRAMESIZE << 16);
	rxd[0].xd2 = htole32(VTOPHYS(l->rxstore[0]));
	rxd[0].xd3 = htole32(VTOPHYS(&rxd[1]));
	rxd[1].xd0 = htole32(R0_OWN);
	rxd[1].xd1 = htole32(VTOPHYS(l->rxstore[1]));
	rxd[1].xd2 = htole32(FRAMESIZE << 16);
	rxd[1].xd3 = htole32(VTOPHYS(&rxd[0]));
	wbinv(l, sizeof(struct local));
	l->tx = l->rx = 0;

	/* enable transmitter and receiver */
	l->ctl0 = CTL0_TXON | CTL0_RXON | CTL0_START;
	CSR_WRITE_4(l, VR_RDBA, VTOPHYS(rxd));
	CSR_WRITE_4(l, VR_TDBA, VTOPHYS(txd));
	CSR_WRITE_1(l, VR_RCR, 0);
	CSR_WRITE_1(l, VR_TCR, 0);
	CSR_WRITE_2(l, VR_ISR, ~0);
	CSR_WRITE_2(l, VR_IEN, 0);
	if (fdx)
		CSR_WRITE_1(l, VR_CTL1, CTL1_FDX);
	CSR_WRITE_1(l, VR_CTL0, CTL0_START);
	CSR_WRITE_1(l, VR_CTL0, l->ctl0);

	return l;
}

int
nvt_send(void *dev, char *buf, unsigned len)
{
	struct local *l = dev;
	volatile struct desc *txd;
	unsigned loop;
	
	len = (len & T_FLMASK);
	if (len < 60)
		len = 60; /* needs to stretch to ETHER_MIN_LEN - 4 */
	wbinv(buf, len);
	txd = &l->txd[l->tx];
	txd->xd3 = htole32(txd);
	txd->xd2 = htole32(VTOPHYS(buf));
	txd->xd1 = htole32(T1_STP | T1_EDP | len);
	txd->xd0 = htole32(T0_OWN);
	wbinv(txd, sizeof(struct desc));
	CSR_WRITE_1(l, VR_CTL0, l->ctl0 | CTL0_TDMD);
	loop = 100;
	do {
		if ((le32toh(txd->xd0) & T0_OWN) == 0)
			goto done;
		DELAY(10);
		inv(txd, sizeof(struct desc));
	} while (--loop > 0);
	printf("xmit failed\n");
	return -1;
  done:
	l->tx ^= 1;
	return len;
}

int
nvt_recv(void *dev, char *buf, unsigned maxlen, unsigned timo)
{
	struct local *l = dev;
	volatile struct desc *rxd;
	unsigned bound, rxstat, len;
	uint8_t *ptr;

	bound = 1000 * timo;
printf("recving with %u sec. timeout\n", timo);
  again:
	rxd = &l->rxd[l->rx];
	do {
		inv(rxd, sizeof(struct desc));
		rxstat = le32toh(rxd->xd0);
		if ((rxstat & R0_OWN) == 0)
			goto gotone;
		DELAY(1000);	/* 1 milli second */
	} while (--bound > 0);
	errno = 0;
	return -1;
  gotone:
	if ((rxstat & R0_RXOK) == 0) {
		rxd->xd0 = htole32(R0_OWN);
		wbinv(rxd, sizeof(struct desc));
		l->rx ^= 1;
		goto again;
	}
	len = ((rxstat & R0_FLMASK) >> 16) - 4 /* HASFCS */;
	if (len > maxlen)
		len = maxlen;
	ptr = l->rxstore[l->rx];
	inv(ptr, len);
	memcpy(buf, ptr, len);
	rxd->xd0 = htole32(R0_OWN);
	wbinv(rxd, sizeof(struct desc));
	l->rx ^= 1;
	return len;
}

static void
mii_autopoll(struct local *l)
{
	int v;

	CSR_WRITE_1(l, VR_MIICR, 0);
	do {
		DELAY(1);
		v = CSR_READ_1(l, VR_MIISR);
	} while ((v & MIIADR_MIDLE) == 0);
	CSR_WRITE_1(l, VR_MIICR, MIICR_MAUTO);
	do {
		DELAY(1);
		v = CSR_READ_1(l, VR_MIISR);
	} while ((v & MIIADR_MIDLE) != 0);
}	
	
static void
mii_stoppoll(struct local *l)
{	
	int v;
	
	CSR_WRITE_1(l, VR_MIICR, 0);
	do {
		DELAY(1);
		v = CSR_READ_1(l, VR_MIISR);
	} while ((v & MIIADR_MIDLE) == 0);
}

static int
mii_read(struct local *l, int phy, int reg)
{
	int v;

	mii_stoppoll(l);
	CSR_WRITE_1(l, VR_MIICFG, phy);
	CSR_WRITE_1(l, VR_MIIADR, reg);
	CSR_WRITE_1(l, VR_MIICR, MIICR_RCMD);
	do {
		v = CSR_READ_1(l, VR_MIICR);
	} while (v & MIICR_RCMD);
	v = CSR_READ_2(l, VR_MIIDATA);
	mii_autopoll(l);
	return v;
}

static void
mii_write(struct local *l, int phy, int reg, int data)
{
	int v;

	mii_stoppoll(l);
	CSR_WRITE_2(l, VR_MIIDATA, data);
	CSR_WRITE_1(l, VR_MIICFG, phy);
	CSR_WRITE_1(l, VR_MIIADR, reg);
	CSR_WRITE_1(l, VR_MIICR, MIICR_WCMD);
	do {
		v = CSR_READ_1(l, VR_MIICR);
	} while (v & MIICR_WCMD);
	mii_autopoll(l);
}

#define MII_BMCR	0x00	/* Basic mode control register (rw) */
#define  BMCR_RESET	0x8000	/* reset */
#define  BMCR_AUTOEN	0x1000	/* autonegotiation enable */
#define  BMCR_ISO	0x0400	/* isolate */
#define  BMCR_STARTNEG	0x0200	/* restart autonegotiation */
#define MII_BMSR	0x01	/* Basic mode status register (ro) */
#define  BMSR_ACOMP	0x0020	/* Autonegotiation complete */
#define  BMSR_LINK	0x0004	/* Link status */
#define MII_ANAR	0x04	/* Autonegotiation advertisement (rw) */
#define  ANAR_FC	0x0400	/* local device supports PAUSE */
#define  ANAR_TX_FD	0x0100	/* local device supports 100bTx FD */
#define  ANAR_TX	0x0080	/* local device supports 100bTx */
#define  ANAR_10_FD	0x0040	/* local device supports 10bT FD */
#define  ANAR_10	0x0020	/* local device supports 10bT */
#define  ANAR_CSMA	0x0001	/* protocol selector CSMA/CD */
#define MII_ANLPAR	0x05	/* Autonegotiation lnk partner abilities (rw) */

void
mii_dealan(struct local *l, unsigned timo)
{
	unsigned anar, bound;

	anar = ANAR_TX_FD | ANAR_TX | ANAR_10_FD | ANAR_10 | ANAR_CSMA;
	mii_write(l, l->phy, MII_ANAR, anar);
	mii_write(l, l->phy, MII_BMCR, BMCR_AUTOEN | BMCR_STARTNEG);
	l->anlpar = 0;
	bound = getsecs() + timo;
	do {
		l->bmsr = mii_read(l, l->phy, MII_BMSR) |
		   mii_read(l, l->phy, MII_BMSR); /* read twice */
		if ((l->bmsr & BMSR_LINK) && (l->bmsr & BMSR_ACOMP)) {
			l->anlpar = mii_read(l, l->phy, MII_ANLPAR);
			break;
		}
		DELAY(10 * 1000);
	} while (getsecs() < bound);
	return;
}

File Added: src/sys/arch/sandpoint/stand/altboot/pci.c
/* $NetBSD: pci.c,v 1.1 2011/01/23 01:05:30 nisimura Exp $ */

/*-
 * Copyright (c) 2007 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by Tohru Nishimura.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include <sys/param.h>

#include <lib/libsa/stand.h>


#define MAXNDEVS 32

#include "globals.h"

static unsigned cfgread(int, int, int, int);
static void cfgwrite(int, int, int, int, unsigned);
static void _buswalk(int,
		int (*)(int, int, int, unsigned long), unsigned long);
static int _pcilookup(int,
		int (*)(int, int, int, unsigned long), unsigned long,
		unsigned [][2], int, int);
static int deviceinit(int, int, int, unsigned long);
static void memassign(int, int, int);
static int devmatch(int, int, int, unsigned long);
static int clsmatch(int, int, int, unsigned long);

unsigned memstart, memlimit;
unsigned iostart, iolimit;
unsigned maxbus;

void
pcisetup(void)
{

	memstart = PCI_MEMBASE;
	memlimit = PCI_MEMLIMIT;
	iostart =  PCI_IOBASE;
	iolimit =  PCI_IOLIMIT;
	maxbus = 0;

	(void)_buswalk(0, deviceinit, 0UL);
}

int
pcifinddev(unsigned vend, unsigned prod, unsigned *tag)
{
	unsigned pciid, target[1][2];

	pciid = PCI_DEVICE(vend, prod);
	if (_pcilookup(0, devmatch, pciid, target, 0, 1)) {
		*tag = target[0][1];
		return 0;
	}
	*tag = ~0;
	return -1;
}

int
pcilookup(type, list, max)
	unsigned type;
	unsigned list[][2];
	int max;
{

	return _pcilookup(0, clsmatch, type, list, 0, max);
}

unsigned
pcimaketag(int b, int d, int f)
{

	return (1U << 31) | (b << 16) | (d << 11) | (f << 8);
}

void
pcidecomposetag(unsigned tag, int *b, int *d, int *f)
{

	if (b != NULL)
		*b = (tag >> 16) & 0xff;
	if (d != NULL)
		*d = (tag >> 11) & 0x1f;
	if (f != NULL)
		*f = (tag >> 8) & 0x7;
	return;
}

unsigned
pcicfgread(unsigned tag, int off)
{
	unsigned cfg;
	
	cfg = tag | (off &~ 03);
	iohtole32(CONFIG_ADDR, cfg);
	return iole32toh(CONFIG_DATA);
}

void
pcicfgwrite(unsigned tag, int off, unsigned val)
{
	unsigned cfg;

	cfg = tag | (off &~ 03);
	iohtole32(CONFIG_ADDR, cfg);
	iohtole32(CONFIG_DATA, val);
}

static unsigned
cfgread(int b, int d, int f, int off)
{
	unsigned cfg;
	
	off &= ~03;
	cfg = (1U << 31) | (b << 16) | (d << 11) | (f << 8) | off | 0;
	iohtole32(CONFIG_ADDR, cfg);
	return iole32toh(CONFIG_DATA);
}

static void
cfgwrite(int b, int d, int f, int off, unsigned val)
{
	unsigned cfg;

	off &= ~03;
	cfg = (1U << 31) | (b << 16) | (d << 11) | (f << 8) | off | 0;
	iohtole32(CONFIG_ADDR, cfg);
	iohtole32(CONFIG_DATA, val);
}

static void
_buswalk(int bus, int (*proc)(int, int, int, unsigned long), unsigned long data)
{
	int device, function, nfunctions;
	unsigned pciid, bhlcr;

	for (device = 0; device < MAXNDEVS; device++) {
		pciid = cfgread(bus, device, 0, PCI_ID_REG);
		if (PCI_VENDOR(pciid) == PCI_VENDOR_INVALID)
			continue;
		if (PCI_VENDOR(pciid) == 0)
			continue;
		bhlcr = cfgread(bus, device, 0, PCI_BHLC_REG);
		nfunctions = (PCI_HDRTYPE_MULTIFN(bhlcr)) ? 8 : 1;
		for (function = 0; function < nfunctions; function++) {
			pciid = cfgread(bus, device, function, PCI_ID_REG);
			if (PCI_VENDOR(pciid) == PCI_VENDOR_INVALID)
				continue;
			if (PCI_VENDOR(pciid) == 0)
				continue;

			if ((*proc)(bus, device, function, data) != 0)
				goto out; /* early exit */
		}
	}
  out:;
}

static int
deviceinit(int bus, int dev, int func, unsigned long data)
{
	unsigned val;

	/* 0x00 */
	printf("%02d:%02d:%02d:", bus, dev, func);
	val = cfgread(bus, dev, func, 0x00);
	printf(" chip %04x.%04x", val & 0xffff, val>>16);
	val = cfgread(bus, dev, func, 0x2c);
	printf(" card %04x.%04x", val & 0xffff, val>>16);
	val = cfgread(bus, dev, func, 0x08);
	printf(" rev %02x class %02x.%02x.%02x",
		val & 0xff, (val>>24), (val>>16) & 0xff, (val>>8) & 0xff);
	val = cfgread(bus, dev, func, 0x0c);
	printf(" hdr %02x\n", (val>>16) & 0xff);

	/* 0x04 */
	val = cfgread(bus, dev, func, 0x04);
	val |= 0xffff0107; /* enable IO,MEM,MASTER,SERR */
	cfgwrite(bus, dev, func, 0x04, val);

	/* 0x0c */
	val = 0x80 << 8 | 0x08 /* 32B cache line */;
	cfgwrite(bus, dev, func, 0x0c, val);

	/* skip legacy mode IDE controller BAR assignment */
	val = cfgread(bus, dev, func, PCI_CLASS_REG);
	if ((val >> 16) == PCI_CLASS_IDE && ((val >> 8) & 0x05) == 0)
		return 0;

	memassign(bus, dev, func);

	/* descending toward PCI-PCI bridge */
	if ((cfgread(bus, dev, func, 0x08) >> 16) == PCI_CLASS_PPB) {
		unsigned new;

		/* 0x18 */
		new = (maxbus += 1);
		val = (0xff << 16) | (new << 8) | bus;
		cfgwrite(bus, dev, func, 0x18, val);

		/* 0x1c and 0x30 */
		val = (iostart + (0xfff)) & ~0xfff; /* 4KB boundary */
		iostart = val;
		val = 0xffff0000 | (iolimit & 0xf000) | (val & 0xf000) >> 8;
		cfgwrite(bus, dev, func, 0x1c, val);
		val = (iolimit & 0xffff0000) | (val & 0xffff0000) >> 16;
		cfgwrite(bus, dev, func, 0x30, val);

		/* 0x20 */
		val = (memstart + 0xfffff) &~ 0xfffff; /* 1MB boundary */
		memstart = val;
		val = (memlimit & 0xffff0000) | (val & 0xffff0000) >> 16;
		cfgwrite(bus, dev, func, 0x20, val);

		/* redo 0x04 */
		val = cfgread(bus, dev, func, 0x04);
		val |= 0xffff0107;
		cfgwrite(bus, dev, func, 0x04, val);

		_buswalk(new, deviceinit, data);

		/* adjust 0x18 */
		val = cfgread(bus, dev, func, 0x18);
		val = (maxbus << 16) | (val & 0xffff);
		cfgwrite(bus, dev, func, 0x18, val);
	}
	return 0;
}

static void
memassign(int bus, int dev, int func)
{
	unsigned val, maxbar, mapr, req, mapbase, size;

	val = cfgread(bus, dev, func, 0x0c);
	switch (PCI_HDRTYPE_TYPE(val)) {
	case 0:
		maxbar = 0x10 + 6 * 4; break;
	case 1:
		maxbar = 0x10 + 2 * 4; break;
	default:
		maxbar = 0x10 + 1 * 4; break;
	}
	for (mapr = 0x10; mapr < maxbar; mapr += 4) {
		cfgwrite(bus, dev, func, mapr, 0xffffffff);
		val = cfgread(bus, dev, func, mapr);
		if (val & 01) {
			/* PCI IO space */
			req = ~(val & 0xfffffffc) + 1;
			if (req & (req - 1))	/* power of 2 */
				continue;
			if (req == 0)		/* ever exists */
				continue;
			size = (req > 0x10) ? req : 0x10;
			mapbase = (iostart + size - 1) & ~(size - 1);
			if (mapbase + size > iolimit)
				continue;

			iostart = mapbase + size;
			/* establish IO space */
			cfgwrite(bus, dev, func, mapr, mapbase | 01);
		}
		else {
			/* PCI memory space */
			req = ~(val & 0xfffffff0) + 1;
			if (req & (req - 1))	/* power of 2 */
				continue;
			if (req == 0)		/* ever exists */
				continue;
			val &= 0x6;
			if (val == 2 || val == 6)
				continue;
			size = (req > 0x1000) ? req : 0x1000;
			mapbase = (memstart + size - 1) & ~(size - 1);
			if (mapbase + size > memlimit)
				continue;

			memstart = mapbase + size;
			/* establish memory space */
			cfgwrite(bus, dev, func, mapr, mapbase);
			if (val == 4) {
				mapr += 4;
				cfgwrite(bus, dev, func, mapr, 0);
			}
		}
printf("%s base %x size %x\n", (val & 01) ? "i/o" : "mem", mapbase, size);
	}
}

static int
devmatch(int bus, int dev, int func, unsigned long data)
{
	unsigned pciid;

	pciid = cfgread(bus, dev, func, PCI_ID_REG);
	return (pciid == (unsigned)data);
}

static int
clsmatch(int bus, int dev, int func, unsigned long data)
{
	unsigned class;

	class = cfgread(bus, dev, func, PCI_CLASS_REG);
	return ((class >> 16) == (unsigned)data);
}

static int
_pcilookup(int bus, int (*match)(int, int, int, unsigned long), unsigned long data, unsigned list[][2], int index, int limit)
{
	int device, function, nfuncs;
	unsigned pciid, bhlcr, class;
	
	for (device = 0; device < MAXNDEVS; device++) {
		pciid = cfgread(bus, device, 0, PCI_ID_REG);
		if (PCI_VENDOR(pciid) == PCI_VENDOR_INVALID)
			continue;
		if (PCI_VENDOR(pciid) == 0)
			continue;
		class = cfgread(bus, device, 0, PCI_CLASS_REG);
		if ((class >> 16) == PCI_CLASS_PPB) {
			/* exploring bus beyond PCI-PCI bridge */
			index = _pcilookup(bus + 1,
				    match, data, list, index, limit);
			if (index >= limit)
				goto out;
			continue;
		}
		bhlcr = cfgread(bus, device, 0, PCI_BHLC_REG);
		nfuncs = (PCI_HDRTYPE_MULTIFN(bhlcr)) ? 8 : 1;
		for (function = 0; function < nfuncs; function++) {
			pciid = cfgread(bus, device, function, PCI_ID_REG);
			if (PCI_VENDOR(pciid) == PCI_VENDOR_INVALID)
				continue;
			if (PCI_VENDOR(pciid) == 0)
				continue;
			if ((*match)(bus, device, function, data)) {
				list[index][0] = pciid;
				list[index][1] =
				     pcimaketag(bus, device, function);
				index += 1;
				if (index >= limit)
					goto out;
			}
		}
	}
  out:
	return index;
}

File Added: src/sys/arch/sandpoint/stand/altboot/pciide.c
/* $NetBSD: pciide.c,v 1.1 2011/01/23 01:05:30 nisimura Exp $ */

/*-
 * Copyright (c) 2008 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by Tohru Nishimura.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include <sys/param.h>

#include <lib/libsa/stand.h>

#include "globals.h"

static uint32_t pciiobase = PCI_XIOBASE;

struct myops {
	int (*chipfix)(struct dkdev_ata *);
	int (*presense)(struct dkdev_ata *, int);
};
static int cmdidefix(struct dkdev_ata *);
static struct myops cmdideops = { cmdidefix, NULL };
static struct myops *myops = &cmdideops;

int pciide_match(unsigned, void *);
void *pciide_init(unsigned, void *);

int
pciide_match(unsigned tag, void *data)
{
	unsigned v;

	v = pcicfgread(tag, PCI_ID_REG);
	switch (v) {
	case PCI_DEVICE(0x1095, 0x0680): /* SiI 0680 IDE */
	case PCI_DEVICE(0x1283, 0x8211): /* ITE 8211 IDE */
	case PCI_DEVICE(0x1106, 0x1571): /* VIA 82C586 IDE */
	case PCI_DEVICE(0x10ad, 0x0105): /* Symphony Labs 82C105 IDE */
	case PCI_DEVICE(0x10b8, 0x5229): /* ALi IDE */
		return 1;
	}
	return 0;
}

void *
pciide_init(unsigned tag, void *data)
{
	int native, n;
	unsigned val;
	struct dkdev_ata *l;

	l = alloc(sizeof(struct dkdev_ata));
	memset(l, 0, sizeof(struct dkdev_ata));
	l->iobuf = allocaligned(512, 16);
	l->tag = tag;

	val = pcicfgread(tag, PCI_CLASS_REG);
	native = val & 03;
	if (native) {
		/* native, use BAR 01234 */
		l->bar[0] = pciiobase + (pcicfgread(tag, 0x10) &~ 01);
		l->bar[1] = pciiobase + (pcicfgread(tag, 0x14) &~ 01);
		l->bar[2] = pciiobase + (pcicfgread(tag, 0x18) &~ 01);
		l->bar[3] = pciiobase + (pcicfgread(tag, 0x1c) &~ 01);
		l->bar[4] = pciiobase + (pcicfgread(tag, 0x20) &~ 01);
		l->chan[0].cmd = l->bar[0];
		l->chan[0].ctl = l->chan[0].alt = l->bar[1] | 02;
		l->chan[0].dma = l->bar[4] + 0x0;
		l->chan[1].cmd = l->bar[2];
		l->chan[1].ctl = l->chan[1].alt = l->bar[3] | 02;
		l->chan[1].dma = l->bar[4] + 0x8;
	}
	else {
		/* legacy */
		l->bar[0]= pciiobase + 0x1f0;
		l->bar[1]= pciiobase + 0x3f4;
		l->bar[2]= pciiobase + 0x170;
		l->bar[3]= pciiobase + 0x374;
		l->chan[0].cmd = l->bar[0];
		l->chan[0].ctl = l->chan[0].alt = l->bar[1] | 02;
		l->chan[0].dma = 0;
		l->chan[1].cmd = l->bar[2];
		l->chan[1].ctl = l->chan[1].alt = l->bar[3] | 02;
		l->chan[1].dma = 0;
	}

	for (n = 0; n < 2; n++) {
		if (myops->presense && (*myops->presense)(l, n) == 0)
			l->presense[n] = 0; /* found not exist */
		else {
			/* check to see whether soft reset works */
			l->presense[n] = perform_atareset(l, n);
		}
		if (l->presense[n])
			printf("channel %d present\n", n);
	}

	/* make sure to have PIO0 */
	if (myops->chipfix)
		(*myops->chipfix)(l);

	return l;
}

static int
cmdidefix(struct dkdev_ata *l)
{
	int v;

	v = pcicfgread(l->tag, 0x80);
	pcicfgwrite(l->tag, 0x80, (v & ~0xff) | 0x01);
	v = pcicfgread(l->tag, 0x84);
	pcicfgwrite(l->tag, 0x84, (v & ~0xff) | 0x01);
	v = pcicfgread(l->tag, 0xa4);
	pcicfgwrite(l->tag, 0xa4, (v & ~0xffff) | 0x328a);
	v = pcicfgread(l->tag, 0xb4);
	pcicfgwrite(l->tag, 0xb4, (v & ~0xffff) | 0x328a);

	return 1;
}

File Added: src/sys/arch/sandpoint/stand/altboot/pcn.c
/* $NetBSD: pcn.c,v 1.1 2011/01/23 01:05:30 nisimura Exp $ */

/*-
 * Copyright (c) 2007 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by Tohru Nishimura.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include <sys/param.h>
 
#include <netinet/in.h>
#include <netinet/in_systm.h>
 
#include <lib/libsa/stand.h>
#include <lib/libsa/net.h>

#include "globals.h"

/*
 * - reverse endian access every CSR.
 * - no vtophys() translation, vaddr_t == paddr_t. 
 * - PIPT writeback cache aware.
 */
#define CSR_READ_4(l, r)	in32rb((l)->csr+(r))
#define CSR_WRITE_4(l, r, v) 	out32rb((l)->csr+(r), (v))
#define CSR_READ_2(l, r)	in16rb((l)->csr+(r))
#define CSR_WRITE_2(l, r, v)	out16rb((l)->csr+(r), (v))
#define VTOPHYS(va) 		(uint32_t)(va)
#define DEVTOV(pa) 		(uint32_t)(pa)
#define wbinv(adr, siz)		_wbinv(VTOPHYS(adr), (uint32_t)(siz))
#define inv(adr, siz)		_inv(VTOPHYS(adr), (uint32_t)(siz))
#define DELAY(n)		delay(n)
#define ALLOC(T,A)		(T *)allocaligned(sizeof(T),(A))

struct desc {
	uint32_t xd0, xd1, xd2;
	uint32_t hole;
};
#define T1_OWN		(1U << 31)	/* 1: empty for HW to load anew */
#define T1_STP		(1U << 25)	/* first frame segment */
#define T1_ENP		(1U << 24)	/* last frame segment */
#define T1_ONES		0xf000		/* filler */
#define T1_FLMASK	0x0fff		/* Tx segment length */
#define R1_OWN		(1U << 31)	/* 1: loaded for HW to send */
#define R1_ERR		(1U << 30)	/* Rx error summary */
#define R1_ONES		0xf000		/* filler */
#define R1_FLMASK	0x0fff		/* Rx frame length */

#define PCN_RDP		0x10
#define PCN_RAP		0x12
#define PCN_16RESET	0x14
#define PCN_32RESET	0x18
#define PCN_BDP		0x1c
#define PCN_CSR0	0x00
#define  C0_IDON	(1U << 8)	/* initblk done indication */
#define  C0_TXON	(1U << 5)
#define  C0_RXON	(1U << 4)
#define  C0_TDMD	(1U << 3)	/* immediate Tx descriptor poll */
#define  C0_STOP	(1U << 2)	/* reset with abrupt abort */
#define  C0_STRT	(1U << 1)	/* activate whole Tx/Rx DMA */
#define  C0_INIT	(1U << 0)	/* instruct to process initblk */
#define PCN_CSR1	0x01
#define PCN_CSR2	0x02
#define PCN_CSR3	0x03
#define  C3_MISSM	(1U << 12)
#define  C3_IDONM	(1U << 8)
#define  C3_DXSUFLO	(1U << 6)
#define PCN_CSR4	0x04
#define  C4_DMAPLUS	(1U << 14)
#define  C4_TXDPOLL	(1U << 12)	/* _disable_ Tx descriptor polling */
#define  C4_APAD_XMT	(1U << 11)
#define  C4_MFCOM	(1U << 8)
#define  C4_RCVCCOM	(1U << 4)
#define  C4_TXSTRTM	(1U << 6)
#define PCN_CSR5	0x05
#define PCN_CSR12	0x0c
#define PCN_CSR13	0x0d
#define PCN_CSR14	0x0e
#define PCN_CSR58	0x4a		/* mapped to BCR20 */
#define PCN_BCR20	0x14		/* "software style" */
#define PCN_BCR33	0x21
#define PCN_BCR34	0x22

struct pcninit {
	uint32_t init_mode;
	uint32_t init_padr[2];
	uint16_t init_ladrf[4];
	uint32_t init_rdra;
	uint32_t init_tdra;
	uint32_t pad;
};

#define FRAMESIZE	1536

struct local {
	struct desc txd[2];
	struct desc rxd[2];
	uint8_t rxstore[2][FRAMESIZE];
	unsigned csr, tx, rx;
	unsigned phy, bmsr, anlpar;
};

unsigned pcn_mii_read(struct local *, int, int);
void pcn_mii_write(struct local *, int, int, int);
static unsigned pcn_csr_read(struct local *, int);
static void pcn_csr_write(struct local *, int, int);
static unsigned pcn_bcr_read(struct local *, int);
static void pcn_bcr_write(struct local *, int, int);
static void mii_initphy(struct local *l);

int
pcn_match(unsigned tag, void *data)
{
	unsigned v;

	v = pcicfgread(tag, PCI_ID_REG);
	return (v == PCI_DEVICE(0x1022, 0x2000));
}

void *
pcn_init(unsigned tag, void *data)
{
	unsigned val, fdx, loop;
	struct local *l;
	struct desc *txd, *rxd;
	uint8_t *en;
	struct pcninit initblock, *ib;

	l = ALLOC(struct local, 32); /* desc alignment */
	memset(l, 0, sizeof(struct local));
	l->csr = DEVTOV(pcicfgread(tag, 0x14)); /* use mem space */

	(void)CSR_READ_2(l, PCN_16RESET);
	(void)CSR_READ_4(l, PCN_32RESET);
	DELAY(1000); /* 1 milli second */
	/* go 32bit RW mode */
	CSR_WRITE_4(l, PCN_RDP, 0);
	/* use 32bit software structure design "2" */
	pcn_bcr_write(l, PCN_BCR20, 2);

	mii_initphy(l);

	en = data;
	val = pcn_csr_read(l, PCN_CSR12); en[0] = val; en[1] = (val >> 8);
	val = pcn_csr_read(l, PCN_CSR13); en[2] = val; en[3] = (val >> 8);
	val = pcn_csr_read(l, PCN_CSR14); en[4] = val; en[5] = (val >> 8);
#if 1
	printf("MAC address %02x:%02x:%02x:%02x:%02x:%02x\n",
		en[0], en[1], en[2], en[3], en[4], en[5]);
#endif
	/* speed and duplexity are found in MII ANR24 */
	val = pcn_mii_read(l, l->phy, 24);
	fdx = !!(val & (1U << 2));
	printf("%s", (val & (1U << 0)) ? "100Mbps" : "10Mbps");
	if (fdx)
		printf("-FDX");
	printf("\n");

	txd = &l->txd[0];
	rxd = &l->rxd[0];
	rxd[0].xd0 = htole32(VTOPHYS(l->rxstore[0]));
	rxd[0].xd1 = htole32(R1_OWN | R1_ONES | FRAMESIZE);
	rxd[1].xd0 = htole32(VTOPHYS(l->rxstore[1]));
	rxd[1].xd1 = htole32(R1_OWN | R1_ONES | FRAMESIZE);
	l->tx = l->rx = 0;

	ib = &initblock;
	ib->init_mode = htole32((0 << 28) | (1 << 20) | 0);
	ib->init_padr[0] =
	    htole32(en[0] | (en[1] << 8) | (en[2] << 16) | (en[3] << 24));
	ib->init_padr[1] =
	    htole32(en[4] | (en[5] << 8));
	ib->init_rdra = htole32(VTOPHYS(rxd));
	ib->init_tdra = htole32(VTOPHYS(txd));

	pcn_csr_write(l, PCN_CSR3, C3_MISSM|C3_IDONM|C3_DXSUFLO);
	pcn_csr_write(l, PCN_CSR4, C4_DMAPLUS|C4_APAD_XMT|
	    C4_MFCOM|C4_RCVCCOM|C4_TXSTRTM);
	pcn_csr_write(l, PCN_CSR5, 0);

	wbinv(&initblock, sizeof(initblock));
	pcn_csr_write(l, PCN_CSR1, VTOPHYS(&initblock) & 0xffff);
	pcn_csr_write(l, PCN_CSR2, (VTOPHYS(&initblock) >> 16) & 0xffff);
	pcn_csr_write(l, PCN_CSR0, C0_INIT);
	loop = 10000;
	do {
		DELAY(10);
	} while (--loop > 0 && !(pcn_csr_read(l, PCN_CSR0) & C0_IDON));
	if (loop == 0)
		printf("pcn: timeout processing init block\n");

	pcn_csr_write(l, PCN_CSR0, C0_STRT);

	return l;
}

int
pcn_send(void *dev, char *buf, unsigned len)
{
	struct local *l = dev;
	volatile struct desc *txd;
	unsigned loop;
	int tlen;

	wbinv(buf, len);
	txd = &l->txd[l->tx];
	tlen = (-len) & T1_FLMASK; /* two's complement */
	txd->xd0 = htole32(VTOPHYS(buf));
	txd->xd1 = htole32(T1_OWN | T1_STP | T1_ENP | T1_ONES | tlen);
	wbinv(txd, sizeof(struct desc));
	/* pcn_csr_write(l, PCN_CSR0, C0_TDMD); */
	loop = 100;
	do {
		if ((le32toh(txd->xd1) & T1_OWN) == 0)
			goto done;
		DELAY(10);
		inv(txd, sizeof(struct desc));
	} while (--loop > 0);
	printf("xmit failed\n");
	return -1;
  done:
	l->tx ^= 1;
	return len;
}

int
pcn_recv(void *dev, char *buf, unsigned maxlen, unsigned timo)
{
	struct local *l = dev;
	volatile struct desc *rxd;
	unsigned bound, rxstat, len;
	uint8_t *ptr;

	bound = 1000 * timo;
printf("recving with %u sec. timeout\n", timo);
  again:
	rxd = &l->rxd[l->rx];
	do {
		inv(rxd, sizeof(struct desc));
		rxstat = le32toh(rxd->xd1);
		if ((rxstat & R1_OWN) == 0)
			goto gotone;
		DELAY(1000);	/* 1 milli second */
	} while (--bound > 0);
	errno = 0;
	return -1;
  gotone:
	if (rxstat & R1_ERR) {
		rxd->xd1 |= htole32(R1_OWN);
		rxd->xd2 = 0;
		wbinv(rxd, sizeof(struct desc));
		l->rx ^= 1;
		goto again;
	}
	/* good frame */
	len = (rxstat & R1_FLMASK) - 4 /* HASFCS */;
	if (len > maxlen)
		len = maxlen;
	ptr = l->rxstore[l->rx];
	inv(ptr, len);
	memcpy(buf, ptr, len);
	rxd->xd1 |= htole32(R1_OWN);
	rxd->xd2 = 0;
	wbinv(rxd, sizeof(struct desc));
	l->rx ^= 1;
	return len;
}

#define MREG(v)		((v)<< 0)
#define MPHY(v)		((v)<< 5)
#define MIIMD		0xffff

unsigned
pcn_mii_read(struct local *l, int phy, int reg)
{
	pcn_bcr_write(l, PCN_BCR33, MREG(reg) | MPHY(phy));
	return (pcn_bcr_read(l, PCN_BCR34) & MIIMD);
}

void
pcn_mii_write(struct local *l, int phy, int reg, int val)
{
	pcn_bcr_write(l, PCN_BCR33, MREG(reg) | MPHY(phy));
	pcn_bcr_write(l, PCN_BCR34, val);
}

static unsigned
pcn_csr_read(struct local *l, int r)
{
	CSR_WRITE_4(l, PCN_RAP, r);
	return CSR_READ_4(l, PCN_RDP);
}

static void
pcn_csr_write(struct local *l, int r, int v)
{
	CSR_WRITE_4(l, PCN_RAP, r);
	CSR_WRITE_4(l, PCN_RDP, v);
}

static unsigned
pcn_bcr_read(struct local *l, int r)
{
	CSR_WRITE_4(l, PCN_RAP, r);
	return CSR_READ_4(l, PCN_BDP);
}

static void
pcn_bcr_write(struct local *l, int r, int v)
{
	CSR_WRITE_4(l, PCN_RAP, r);
	CSR_WRITE_4(l, PCN_BDP, v);
}

#define MII_BMCR	0x00 	/* Basic mode control register (rw) */
#define  BMCR_RESET	0x8000	/* reset */
#define  BMCR_AUTOEN	0x1000	/* autonegotiation enable */
#define  BMCR_ISO	0x0400	/* isolate */
#define  BMCR_STARTNEG	0x0200	/* restart autonegotiation */
#define MII_BMSR	0x01	/* Basic mode status register (ro) */

static void
mii_initphy(struct local *l)
{
	int phy, ctl, sts, bound;

	for (phy = 0; phy < 32; phy++) {
		ctl = pcn_mii_read(l, phy, MII_BMCR);
		sts = pcn_mii_read(l, phy, MII_BMSR);
		if (ctl != 0xffff && sts != 0xffff)
			goto found;
	}
	printf("MII: no PHY found\n");
	return;
  found:
	ctl = pcn_mii_read(l, phy, MII_BMCR);
	pcn_mii_write(l, phy, MII_BMCR, ctl | BMCR_RESET);
	bound = 100;
	do {
		DELAY(10);
		ctl = pcn_mii_read(l, phy, MII_BMCR);
		if (ctl == 0xffff) {
			printf("MII: PHY %d has died after reset\n", phy);
			return;
		}
	} while (bound-- > 0 && (ctl & BMCR_RESET));
	if (bound == 0) {
		printf("PHY %d reset failed\n", phy);
	}
	ctl &= ~BMCR_ISO;
	pcn_mii_write(l, phy, MII_BMCR, ctl);
	sts = pcn_mii_read(l, phy, MII_BMSR) |
	    pcn_mii_read(l, phy, MII_BMSR); /* read twice */
	l->phy = phy;
	l->bmsr = sts;
}

#if 0
static void
mii_dealan(struct local *, unsigned timo)
{
	unsigned anar, bound;

	anar = ANAR_TX_FD | ANAR_TX | ANAR_10_FD | ANAR_10 | ANAR_CSMA;
	pcn_mii_write(l, l->phy, MII_ANAR, anar);
	pcn_mii_write(l, l->phy, MII_BMCR, BMCR_AUTOEN | BMCR_STARTNEG);
	l->anlpar = 0;
	bound = getsecs() + timo;
	do {
		l->bmsr = pcn_mii_read(l, l->phy, MII_BMSR) |
		   pcn_mii_read(l, l->phy, MII_BMSR); /* read twice */
		if ((l->bmsr & BMSR_LINK) && (l->bmsr & BMSR_ACOMP)) {
			l->anlpar = pcn_mii_read(l, l->phy, MII_ANLPAR);
			break;
		}
		DELAY(10 * 1000);
	} while (getsecs() < bound);
	return;
}
#endif

File Added: src/sys/arch/sandpoint/stand/altboot/Attic/printf.c
/* $NetBSD: printf.c,v 1.1 2011/01/23 01:05:30 nisimura Exp $ */

/*-
 * Copyright (c) 2007 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by Tohru Nishimura.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

/*
 * printf -- format and write output using 'func' to write characters
 */

#include <sys/types.h>
#include <machine/stdarg.h>
#include <lib/libsa/stand.h>

#define MAXSTR	80

static int _doprnt(void (*)(int), const char *, va_list);
static void pr_int(unsigned long, int, char *);
static void sputchar(int);

static char *sbuf, *ebuf;

void
printf(const char *fmt, ...)
{
	va_list ap;

	va_start(ap, fmt);
	_doprnt(putchar, fmt, ap);
	va_end(ap);
}

void
vprintf(const char *fmt, va_list ap)
{

	_doprnt(putchar, fmt, ap);
}

int
sprintf(char *buf, const char *fmt, ...)
{
	va_list ap;

	sbuf = buf;
	ebuf = buf + -(size_t)buf - 1;
	va_start(ap, fmt);
	_doprnt(sputchar, fmt, ap);
	*sbuf = '\0';
	return (sbuf - buf);
}

int
snprintf(char *buf, size_t size, const char *fmt, ...)
{
	va_list ap;

	sbuf = buf;
	ebuf = buf + size - 1;
	va_start(ap, fmt);
	_doprnt(sputchar, fmt, ap);
	*sbuf = '\0';
	return (sbuf - buf);
}

static int
_doprnt(func, fmt, ap)
	void (*func)(int);	/* Function to put a character */
	const char *fmt;	/* Format string for pr_int/pr_float */
	va_list ap;		/* Arguments to pr_int/pr_float */
{
	int i;
	char *str;
	char string[20];
	int length;
	int leftjust;
	int longflag;
	int fmax, fmin;
	int leading;
	int outcnt;
	char fill;
	char sign;

	outcnt = 0;
	while ((i = *fmt++) != '\0') {
		if (i != '%') {
			(*func)(i);
			outcnt += 1;
			continue;
		}
		if (*fmt == '%') {
			(*func)(*fmt++);
			outcnt += 1;
			continue;
		}
		leftjust = (*fmt == '-');
		if (leftjust)
			fmt++;
		fill = (*fmt == '0') ? *fmt++ : ' ';
		if (*fmt == '*')
			fmin = va_arg(ap, int);
		else {
			fmin = 0;
			while ('0' <= *fmt && *fmt <= '9')
				fmin = fmin * 10 + *fmt++ - '0';
		}
		if (*fmt != '.')
			fmax = 0;
		else {
			fmt++;
			if (*fmt == '*')
				fmax = va_arg(ap, int);
			else {
				fmax = 0;
				while ('0' <= *fmt && *fmt <= '9')
					fmax = fmax * 10 + *fmt++ - '0';
			}
		}
		longflag = (*fmt == 'l');
		if (longflag)
			fmt++;
		if ((i = *fmt++) == '\0') {
			(*func)('%');
			outcnt += 1;
			break;
		}
		str = string;
		sign = ' ';
		switch (i) {
		case 'c':
			str[0] = va_arg(ap, int);
			str[1] = '\0';
			fmax = 0;
			fill = ' ';
			break;

		case 's':
			str = va_arg(ap, char *);
			fill = ' ';
			break;

		case 'd':
		      {
			long l = va_arg(ap, long);
			if (l < 0) { sign = '-' ; l = -l; }
			pr_int((unsigned long)l, 10, str);
		      }
			break;

		case 'u':
			pr_int(va_arg(ap, unsigned long), 10, str);
			break;

		case 'o':
			pr_int(va_arg(ap, unsigned long), 8, str);
			fmax = 0;
			break;

		case 'X':
		case 'x':
			pr_int(va_arg(ap, unsigned long), 16, str);
			fmax = 0;
			break;

		case 'p':
			pr_int(va_arg(ap, unsigned long), 16, str);
			fill = '0';
			fmin = 8;
			fmax = 0;
			(*func)('0'); (*func)('x');
			outcnt += 2;
			break;
		default:
			(*func)(i);
			break;
		}
		for (i = 0; str[i] != '\0'; i++)
			;
		length = i;
		if (fmin > MAXSTR || fmin < 0)
			fmin = 0;
		if (fmax > MAXSTR || fmax < 0)
			fmax = 0;
		leading = 0;
		if (fmax != 0 || fmin != 0) {
			if (fmax != 0 && length > fmax)
				length = fmax;
			if (fmin != 0)
				leading = fmin - length;
			if (sign == '-')
				--leading;
		}
		outcnt += leading + length;
		if (sign == '-')
			outcnt += 1;
		if (sign == '-' && fill == '0')
			(*func)(sign);
		if (leftjust == 0)
			for (i = 0; i < leading; i++) (*func)(fill);
		if (sign == '-' && fill == ' ')
			(*func)(sign);
		for (i = 0; i < length; i++)
			(*func)(str[i]);
		if (leftjust != 0)
			for (i = 0; i < leading; i++) (*func)(fill);
	}
	return outcnt;
}

static void pr_int(lval, base, s)
	unsigned long lval;
	int base;
	char *s;
{
	char ptmp[12];	/* unsigned long requires 11 digit in octal form */
	int i;
	char *t = ptmp;
	static const char hexdigit[] = "0123456789abcdef";

	i = 1;
	*t++ = '\0';
	do {
		*t++ = hexdigit[lval % base];
	} while ((lval /= base) != 0 && ++i < sizeof(ptmp));
	while ((*s++ = *--t) != '\0')
		;
}

static void
sputchar(int c)
{

	if (sbuf < ebuf)
		*sbuf++ = c;
}

File Added: src/sys/arch/sandpoint/stand/altboot/rge.c
/* $NetBSD: rge.c,v 1.1 2011/01/23 01:05:30 nisimura Exp $ */

/*-
 * Copyright (c) 2007 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by Tohru Nishimura.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include <sys/param.h>

#include <netinet/in.h>
#include <netinet/in_systm.h>

#include <lib/libsa/stand.h>
#include <lib/libsa/net.h>

#include "globals.h"

/*
 * - reverse endian access every CSR.
 * - no vtophys() translation, vaddr_t == paddr_t. 
 * - PIPT writeback cache aware.
 */
#define CSR_WRITE_1(l, r, v)	*(volatile uint8_t *)((l)->csr+(r)) = (v)
#define CSR_READ_1(l, r)	*(volatile uint8_t *)((l)->csr+(r))
#define CSR_WRITE_2(l, r, v)	out16rb((l)->csr+(r), (v))
#define CSR_READ_2(l, r)	in16rb((l)->csr+(r))
#define CSR_WRITE_4(l, r, v)	out32rb((l)->csr+(r), (v))
#define CSR_READ_4(l, r)	in32rb((l)->csr+(r))
#define VTOPHYS(va)		(uint32_t)(va)
#define DEVTOV(pa)		(uint32_t)(pa)
#define wbinv(adr, siz)		_wbinv(VTOPHYS(adr), (uint32_t)(siz))
#define inv(adr, siz)		_inv(VTOPHYS(adr), (uint32_t)(siz))
#define DELAY(n)		delay(n)
#define ALLOC(T,A)		(T *)allocaligned(sizeof(T),(A))

struct desc {
	uint32_t xd0, xd1, xd2, xd3;
};
#define T0_OWN		0x80000000	/* loaded for HW to send */
#define T0_EOR		0x40000000	/* end of ring */
#define T0_FS		0x20000000	/* first descriptor */
#define T0_LS		0x10000000	/* last descriptor */
#define T0_FRMASK	0x0000ffff

#define R0_OWN		0x80000000	/* empty for HW to load anew */
#define R0_EOR		0x40000000	/* end mark to form a ring */
#define R0_BUFLEN	0x00003ff8	/* max frag. size to receive */
#define R0_FS		0x20000000	/* start of frame */
#define R0_LS		0x10000000	/* end of frame */
#define R0_RES		0x00200000	/* Rx error summary */
#define R0_RUNT		0x00100000	/* runt frame received */
#define R0_CRC		0x00080000	/* CRC error found */
#define R0_FRMASK	0x00003fff	/* 13:0 frame length */

#define RGE_IDR0	0x00		/* MAC address [0] */
#define RGE_IDR1	0x01		/* MAC address [1] */
#define RGE_IDR2	0x02		/* MAC address [2] */
#define RGE_IDR3	0x03		/* MAC address [3] */
#define RGE_IDR4	0x04		/* MAC address [4] */
#define RGE_IDR5	0x05		/* MAC address [5] */
#define RGE_TNPDS	0x20		/* Tx descriptor base paddr */
#define RGE_THPDS	0x28		/* high pro. Tx des. base paddr */
#define RGE_CR		0x37		/* command */
#define	 CR_RESET	(1U << 4)	/* reset S1C */
#define	 CR_RXEN	(1U << 3)	/* Rx enable */
#define	 CR_TXEN	(1U << 2)	/* Tx enable */
#define RGE_TPPOLL	0x38		/* activate desc polling */
#define RGE_IMR		0x3c		/* interrupt mask */
#define RGE_ISR		0x3e		/* interrupt status */
#define RGE_TCR		0x40		/* Tx control */
#define	 TCR_MAXDMA	0x0700		/* 10:8 Tx DMA burst size */
#define RGE_RCR		0x44		/* Rx control */
#define	 RCR_RXTFH	0xe000		/* 15:13 Rx FIFO threshold */
#define	 RCR_MAXDMA	0x0700		/* 10:8 Rx DMA burst size */
#define	 RCR_AE		(1U << 5)	/* accept error frame */
#define	 RCR_RE		(1U << 4)	/* accept runt frame */
#define	 RCR_AB		(1U << 3)	/* accept broadcast frame */
#define	 RCR_AM		(1U << 2)	/* accept multicast frame */
#define	 RCR_APM	(1U << 1)	/* accept unicast frame */
#define	 RCR_AAP	(1U << 0)	/* promiscuous */
#define RGE_PHYAR	0x60		/* PHY access */
#define RGE_PHYSR	0x6c		/* PHY status */
#define RGE_RMS		0xda		/* Rx maximum frame size */
#define RGE_RDSAR	0xe4		/* Rx descriptor base paddr */
#define RGE_ETTHR	0xec		/* Tx threshold */

#define FRAMESIZE	1536

struct local {
	struct desc txd[2]; /* 256B align */
	  uint8_t _hole0[256 - 2 * sizeof(struct desc)];
	struct desc rxd[2]; /* 256B align */
	  uint8_t _hole1[256 - 2 * sizeof(struct desc)];
	uint8_t rxstore[2][FRAMESIZE];
	unsigned csr, tx, rx;
	unsigned phy, bmsr, anlpar;
	unsigned tcr, rcr;
};

static int mii_read(struct local *, int, int);
static void mii_write(struct local *, int, int, int);
static void mii_initphy(struct local *);
static void mii_dealan(struct local *, unsigned);

int
rge_match(unsigned tag, void *data)
{
	unsigned v;

	v = pcicfgread(tag, PCI_ID_REG);
	switch (v) {
	case PCI_DEVICE(0x10ec, 0x8169):
		return 1;
	}
	return 0;
}

void *
rge_init(unsigned tag, void *data)
{
	unsigned val;
	struct local *l;
	struct desc *txd, *rxd;
	uint8_t *en = data;

	l = ALLOC(struct local, 256);	/* desc alignment */
	memset(l, 0, sizeof(struct local));
	l->csr = DEVTOV(pcicfgread(tag, 0x14)); /* use mem space */

	CSR_WRITE_1(l, RGE_CR, CR_RESET);
	do {
		val = CSR_READ_1(l, RGE_CR);
	} while (val & CR_RESET);

	mii_initphy(l);

	en = data;
	en[0] = CSR_READ_1(l, RGE_IDR0);
	en[1] = CSR_READ_1(l, RGE_IDR1);
	en[2] = CSR_READ_1(l, RGE_IDR2);
	en[3] = CSR_READ_1(l, RGE_IDR3);
	en[4] = CSR_READ_1(l, RGE_IDR4);
	en[5] = CSR_READ_1(l, RGE_IDR5);

	printf("MAC address %02x:%02x:%02x:%02x:%02x:%02x\n",
	    en[0], en[1], en[2], en[3], en[4], en[5]);
	printf("PHY %d (%04x.%04x)\n", l->phy,
	    mii_read(l, l->phy, 2), mii_read(l, l->phy, 3));

	mii_dealan(l, 5);

	/* speed and duplexity can be seen in PHYSR */
	val = CSR_READ_1(l, RGE_PHYSR);
	if (val & (1U << 4))
		printf("1000Mbps");
	if (val & (1U << 3))
		printf("100Mbps");
	if (val & (1U << 2))
		printf("10Mbps");
	if (val & (1U << 0))
		printf("-FDX");
	printf("\n");

	txd = &l->txd[0];
	txd[1].xd0 = htole32(T0_EOR);
	rxd = &l->rxd[0];
	rxd[0].xd0 = htole32(R0_OWN | FRAMESIZE);
	rxd[0].xd2 = htole32(VTOPHYS(l->rxstore[0]));
	rxd[1].xd0 = htole32(R0_OWN | R0_EOR | FRAMESIZE);
	rxd[1].xd2 = htole32(VTOPHYS(l->rxstore[1]));
	wbinv(l, sizeof(struct local));
	l->tx = l->rx = 0;

	l->tcr = (03 << 24) | (07 << 8);
	l->rcr = (07 << 13) | (07 << 8) | RCR_APM;
	CSR_WRITE_1(l, RGE_CR, CR_TXEN | CR_RXEN);
	CSR_WRITE_1(l, RGE_ETTHR, 0x3f);
	CSR_WRITE_2(l, RGE_RMS, FRAMELEN);
	CSR_WRITE_4(l, RGE_TCR, l->tcr);
	CSR_WRITE_4(l, RGE_RCR, l->rcr);
	CSR_WRITE_4(l, RGE_TNPDS, VTOPHYS(txd));
	CSR_WRITE_4(l, RGE_RDSAR, VTOPHYS(rxd));
	CSR_WRITE_4(l, RGE_TNPDS + 4, 0); 
	CSR_WRITE_4(l, RGE_RDSAR + 4, 0); 
	CSR_WRITE_2(l, RGE_ISR, ~0);
	CSR_WRITE_2(l, RGE_IMR, 0);

	return l;
}

int
rge_send(void *dev, char *buf, unsigned len)
{
	struct local *l = dev;
	volatile struct desc *txd;
	unsigned loop;

	wbinv(buf, len);
	txd = &l->txd[l->tx];
	txd->xd2 = htole32(VTOPHYS(buf));
	txd->xd0 &= htole32(T0_EOR);
	txd->xd0 |= htole32(T0_OWN | T0_FS | T0_LS | (len & T0_FRMASK));
	wbinv(txd, sizeof(struct desc));
	CSR_WRITE_1(l, RGE_TPPOLL, 0x40);
	loop = 100;
	do {
		if ((le32toh(txd->xd0) & T0_OWN) == 0)
			goto done;
		DELAY(10);
		inv(txd, sizeof(struct desc));
	} while (--loop > 0);
	printf("xmit failed\n");
	return -1;
  done:
	l->tx ^= 1;
	return len;
}

int
rge_recv(void *dev, char *buf, unsigned maxlen, unsigned timo)
{
	struct local *l = dev;
	volatile struct desc *rxd;
	unsigned bound, rxstat, len;
	uint8_t *ptr;

	bound = 1000 * timo;
#if 0
printf("recving with %u sec. timeout\n", timo);
#endif
  again:
	rxd = &l->rxd[l->rx];
	do {
		inv(rxd, sizeof(struct desc));
		rxstat = le32toh(rxd->xd0);
		if ((rxstat & R0_OWN) == 0)
			goto gotone;
		DELAY(1000);	/* 1 milli second */
	} while (--bound > 0);
	errno = 0;
	return -1;
  gotone:
	if (rxstat & R0_RES) {
		rxd->xd0 &= htole32(R0_EOR);
		rxd->xd0 |= htole32(R0_OWN | FRAMESIZE);
		wbinv(rxd, sizeof(struct desc));
		l->rx ^= 1;
		goto again;
	}
	len = rxstat & R0_FRMASK;
	if (len > maxlen)
		len = maxlen;
	ptr = l->rxstore[l->rx];
	inv(ptr, len);
	memcpy(buf, ptr, len);
	rxd->xd0 &= htole32(R0_EOR);
	rxd->xd0 |= htole32(R0_OWN | FRAMESIZE);
	wbinv(rxd, sizeof(struct desc));
	l->rx ^= 1;
	return len;
}

static int
mii_read(struct local *l, int phy, int reg)
{
	unsigned v, loop;

	v = reg << 16;
	CSR_WRITE_4(l, RGE_PHYAR, v);
	loop = 100;
	do {
		v = CSR_READ_4(l, RGE_PHYAR);
	} while ((v & (1U << 31)) == 0); /* wait for 0 -> 1 */
	return v;
}

static void
mii_write(struct local *l, int phy, int reg, int data)
{
	unsigned v;

	v = (reg << 16) | (data & 0xffff) | (1U << 31);
	CSR_WRITE_4(l, RGE_PHYAR, v);
	do {
		v = CSR_READ_4(l, RGE_PHYAR);
	} while (v & (1U << 31)); /* wait for 1 -> 0 */
}

#define MII_BMCR	0x00	/* Basic mode control register (rw) */
#define  BMCR_RESET	0x8000	/* reset */
#define  BMCR_AUTOEN	0x1000	/* autonegotiation enable */
#define  BMCR_ISO	0x0400	/* isolate */
#define  BMCR_STARTNEG	0x0200	/* restart autonegotiation */
#define MII_BMSR	0x01	/* Basic mode status register (ro) */
#define  BMSR_ACOMP	0x0020	/* Autonegotiation complete */
#define  BMSR_LINK	0x0004	/* Link status */
#define MII_ANAR	0x04	/* Autonegotiation advertisement (rw) */
#define  ANAR_FC	0x0400	/* local device supports PAUSE */
#define  ANAR_TX_FD	0x0100	/* local device supports 100bTx FD */
#define  ANAR_TX	0x0080	/* local device supports 100bTx */
#define  ANAR_10_FD	0x0040	/* local device supports 10bT FD */
#define  ANAR_10	0x0020	/* local device supports 10bT */
#define  ANAR_CSMA	0x0001	/* protocol selector CSMA/CD */
#define MII_ANLPAR	0x05	/* Autonegotiation lnk partner abilities (rw) */
#define MII_GTCR	0x09	/* 1000baseT control */
#define  GANA_1000TFDX	0x0200	/* advertise 1000baseT FDX */
#define  GANA_1000THDX	0x0100	/* advertise 1000baseT HDX */
#define MII_GTSR	0x0a	/* 1000baseT status */
#define  GLPA_1000TFDX	0x0800	/* link partner 1000baseT FDX capable */
#define  GLPA_1000THDX	0x0400	/* link partner 1000baseT HDX capable */
#define  GLPA_ASM_DIR	0x0200	/* link partner asym. pause dir. capable */

static void
mii_initphy(struct local *l)
{
	int phy, ctl, sts, bound;

	for (phy = 0; phy < 32; phy++) {
		ctl = mii_read(l, phy, MII_BMCR);
		sts = mii_read(l, phy, MII_BMSR);
		if (ctl != 0xffff && sts != 0xffff)
			goto found;
	}
	printf("MII: no PHY found\n");
	return;
  found:
	ctl = mii_read(l, phy, MII_BMCR);
	mii_write(l, phy, MII_BMCR, ctl | BMCR_RESET);
	bound = 100;
	do {
		DELAY(10);
		ctl = mii_read(l, phy, MII_BMCR);
		if (ctl == 0xffff) {
			printf("MII: PHY %d has died after reset\n", phy);
			return;
		}
	} while (bound-- > 0 && (ctl & BMCR_RESET));
	if (bound == 0) {
		printf("PHY %d reset failed\n", phy);
	}
	ctl &= ~BMCR_ISO;
	mii_write(l, phy, MII_BMCR, ctl);
	sts = mii_read(l, phy, MII_BMSR) |
	    mii_read(l, phy, MII_BMSR); /* read twice */
	l->phy = phy;
	l->bmsr = sts;
}

void
mii_dealan(struct local *l, unsigned timo)
{
	unsigned anar, gtcr, bound;

	anar = ANAR_TX_FD | ANAR_TX | ANAR_10_FD | ANAR_10 | ANAR_CSMA;
	anar |= ANAR_FC;
	gtcr = GANA_1000TFDX | GANA_1000THDX;
	mii_write(l, l->phy, MII_ANAR, anar);
	mii_write(l, l->phy, MII_GTCR, gtcr);
	mii_write(l, l->phy, MII_BMCR, BMCR_AUTOEN | BMCR_STARTNEG);
	l->anlpar = 0;
	bound = getsecs() + timo;
	do {
		l->bmsr = mii_read(l, l->phy, MII_BMSR) |
		   mii_read(l, l->phy, MII_BMSR); /* read twice */
		if ((l->bmsr & BMSR_LINK) && (l->bmsr & BMSR_ACOMP)) {
			l->anlpar = mii_read(l, l->phy, MII_ANLPAR);
			break;
		}
		DELAY(10 * 1000);
	} while (getsecs() < bound);
	return;
}

File Added: src/sys/arch/sandpoint/stand/altboot/siisata.c
/* $NetBSD: siisata.c,v 1.1 2011/01/23 01:05:30 nisimura Exp $ */

/*-
 * Copyright (c) 2008 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by Tohru Nishimura.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include <sys/param.h>

#include <lib/libsa/stand.h>

#include "globals.h"

static uint32_t pciiobase = PCI_XIOBASE;

int siisata_match(unsigned, void *);
void *siisata_init(unsigned, void *);

int
siisata_match(unsigned tag, void *data)
{
	unsigned v;

	v = pcicfgread(tag, PCI_ID_REG);
	switch (v) {
	case PCI_DEVICE(0x1095, 0x3112): /* SiI 3112 SATALink */
	case PCI_DEVICE(0x1095, 0x3512): /*     3512 SATALink */
	case PCI_DEVICE(0x1095, 0x3114): /* SiI 3114 SATALink */
		return 1;
	}
	return 0;
}

void *
siisata_init(unsigned tag, void *data)
{
	unsigned idreg;
	int nchan, n;
	struct dkdev_ata *l;

	l = alloc(sizeof(struct dkdev_ata));
	memset(l, 0, sizeof(struct dkdev_ata));
	l->iobuf = allocaligned(512, 16);
	l->tag = tag;

	idreg = pcicfgread(tag, PCI_ID_REG);
	l->bar[0] = pciiobase + (pcicfgread(tag, 0x10) &~ 01);
	l->bar[1] = pciiobase + (pcicfgread(tag, 0x14) &~ 01);
	l->bar[2] = pciiobase + (pcicfgread(tag, 0x18) &~ 01);
	l->bar[3] = pciiobase + (pcicfgread(tag, 0x1c) &~ 01);
	l->bar[4] = pciiobase + (pcicfgread(tag, 0x20) &~ 01);
	l->bar[5] = pcicfgread(tag, 0x24) &~ 0x3ff;

	if ((PCI_PRODUCT(idreg) & 0xf) == 0x2) {
		/* 3112/3512 */
		l->chan[0].cmd = l->bar[0];
		l->chan[0].ctl = l->chan[0].alt = l->bar[1] | 02;
		l->chan[0].dma = l->bar[4] + 0x0;
		l->chan[1].cmd = l->bar[2];
		l->chan[1].ctl = l->chan[1].alt = l->bar[3] | 02;
		l->chan[1].dma = l->bar[4] + 0x8;
		nchan = 2;
	}
	else {
		/* 3114 - assume BA5 access is possible XXX */
		l->chan[0].cmd = l->bar[5] + 0x080;
		l->chan[0].ctl = l->chan[0].alt = (l->bar[5] + 0x088) | 02;
		l->chan[1].cmd = l->bar[5] + 0x0c0;
		l->chan[1].ctl = l->chan[1].alt = (l->bar[5] + 0x0c8) | 02;
		l->chan[2].cmd = l->bar[5] + 0x280;
		l->chan[2].ctl = l->chan[2].alt = (l->bar[5] + 0x288) | 02;
		l->chan[3].cmd = l->bar[5] + 0x2c0;
		l->chan[3].ctl = l->chan[3].alt = (l->bar[5] + 0x2c8) | 02;
		nchan = 4;
	}

	/* configure PIO transfer mode */
	pcicfgwrite(tag, 0x80, 0x00);
	pcicfgwrite(tag, 0x84, 0x00);

	for (n = 0; n < nchan; n++) {
		if (satapresense(l, n)) {
			/* drive present, now check whether soft reset works */
			if (perform_atareset(l, n)) {
				printf("port %d device present\n", n);
				l->presense[n] = 1;
			}
		} else
			l->presense[n] = 0;
	}
	return l;
}

File Added: src/sys/arch/sandpoint/stand/altboot/sip.c
/* $NetBSD: sip.c,v 1.1 2011/01/23 01:05:30 nisimura Exp $ */

/*-
 * Copyright (c) 2007 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by Tohru Nishimura.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include <sys/param.h>
 
#include <netinet/in.h>
#include <netinet/in_systm.h>
 
#include <lib/libsa/stand.h>
#include <lib/libsa/net.h>

#include "globals.h"

/*
 * - reverse endian access every CSR.
 * - no VTOPHYS() translation, vaddr_t == paddr_t. 
 * - PIPT writeback cache aware.
 */
#define CSR_READ(l, r)		in32rb((l)->csr+(r))
#define CSR_WRITE(l, r, v) 	out32rb((l)->csr+(r), (v))
#define VTOPHYS(va) 		(uint32_t)(va)
#define DEVTOV(pa) 		(uint32_t)(pa)
#define wbinv(adr, siz)		_wbinv(VTOPHYS(adr), (uint32_t)(siz))
#define inv(adr, siz)		_inv(VTOPHYS(adr), (uint32_t)(siz))
#define DELAY(n)		delay(n)
#define ALLOC(T,A)		(T *)allocaligned(sizeof(T),(A))

struct desc {
	uint32_t xd0, xd1, xd2;
	uint32_t hole;
};
#define XD1_OWN		(1U << 31)
#define XD1_OK		(1U << 27)

#define SIP_CR		0x00
#define  CR_RST		(1U << 8)	/* software reset */
#define  CR_RXR		(1U << 5)	/* Rx abort and reset */
#define  CR_TXR		(1U << 4)	/* Tx abort and reset */
#define  CR_RXD		(1U << 3)	/* graceful Rx stop */
#define  CR_RXE		(1U << 2)	/* run and activate Rx */
#define  CR_TXD		(1U << 1)	/* graceful Tx stop */
#define  CR_TXE		(1U << 0)	/* run and activate Tx */
#define SIP_CFG		0x04
#define SIP_MEAR	0x08
#define  MEAR_EESEL	(1U << 3)	/* SEEP chipselect */
#define  MEAR_EECLK	(1U << 2)	/* clock */
#define  MEAR_EEDO	(1U << 1)	/* bit retrieve */
#define  MEAR_EEDI	(1U << 0)	/* bit feed */
#define SIP_IMR		0x14
#define SIP_IER		0x18
#define SIP_TXDP	0x20
#define SIP_TXCFG	0x24
#define  TXCFG_CSI	(1U << 31)
#define  TXCFG_HBI	(1U << 30)
#define  TXCFG_ATP	(1U << 28)
#define  TXCFG_DMA256	0x300000
#define SIP_RXDP	0x30
#define SIP_RXCFG	0x34
#define  RXCFG_ATX	(1U << 28)
#define  RXCFG_DMA256	0x300000
#define SIP_RFCR	0x48
#define  RFCR_RFEN	(1U << 31)	/* activate Rx filter */
#define  RFCR_APM	(1U << 27)	/* accept perfect match */
#define SIP_RFDR	0x4c
#define SIP_MIBC	0x5c
#define SIP_BMCR	0x80
#define SIP_PHYSTS	0xc0
#define SIP_PHYCR	0xe4

#define FRAMESIZE	1536

struct local {
	struct desc txd[2];
	struct desc rxd[2];
	uint8_t store[2][FRAMESIZE];
	unsigned csr, tx, rx;
	unsigned phy, bmsr, anlpar;
	unsigned cr;
};

static int read_eeprom(struct local *, int);
static unsigned mii_read(struct local *, int, int);
static void mii_write(struct local *, int, int, int);
static void mii_initphy(struct local *);
static void mii_dealan(struct local *, unsigned);

/* Table and macro to bit-reverse an octet. */
static const uint8_t bbr4[] = {0,8,4,12,2,10,6,14,1,9,5,13,3,11,7,15};
#define bbr(v)	((bbr4[(v)&0xf] << 4) | bbr4[((v)>>4) & 0xf])

int
sip_match(unsigned tag, void *data)
{
	unsigned v;

	v = pcicfgread(tag, PCI_ID_REG);
	switch (v) {
	case PCI_DEVICE(0x100b, 0x0020):
		return 1;
	}
	return 0;
}

void *
sip_init(unsigned tag, void *data)
{
	unsigned val, i, fdx, txc, rxc;
	struct local *l;
	struct desc *txd, *rxd;
	uint16_t eedata[4], *ee;
	uint8_t *en;

	val = pcicfgread(tag, PCI_ID_REG);
	if (PCI_DEVICE(0x100b, 0x0020) != val)
		return NULL;

	l = ALLOC(struct local, 32); /* desc alignment */
	memset(l, 0, sizeof(struct local));
	l->csr = DEVTOV(pcicfgread(tag, 0x14)); /* use mem space */

	CSR_WRITE(l, SIP_IER, 0);
	CSR_WRITE(l, SIP_IMR, 0);
	CSR_WRITE(l, SIP_RFCR, 0);
	CSR_WRITE(l, SIP_CR, CR_RST);
	do {
		val = CSR_READ(l, SIP_CR);
	} while (val & CR_RST); /* S1C */

	mii_initphy(l);

	ee = eedata; en = data;
	ee[0] = read_eeprom(l, 6);
	ee[1] = read_eeprom(l, 7);
	ee[2] = read_eeprom(l, 8);
	ee[3] = read_eeprom(l, 9);
	en[0] = ((*ee & 0x1) << 7);
	ee++;
	en[0] |= ((*ee & 0xFE00) >> 9);
	en[1] = ((*ee & 0x1FE) >> 1);
	en[2] = ((*ee & 0x1) << 7);
	ee++;
	en[2] |= ((*ee & 0xFE00) >> 9);
	en[3] = ((*ee & 0x1FE) >> 1);
	en[4] = ((*ee & 0x1) << 7);
	ee++;
	en[4] |= ((*ee & 0xFE00) >> 9);
	en[5] = ((*ee & 0x1FE) >> 1);
	for (i = 0; i < 6; i++)
		en[i] = bbr(en[i]);

	printf("MAC address %02x:%02x:%02x:%02x:%02x:%02x, ",
	    en[0], en[1], en[2], en[3], en[4], en[5]);
	printf("PHY %d (%04x.%04x)\n", l->phy,
	    mii_read(l, l->phy, 2), mii_read(l, l->phy, 3));

	mii_dealan(l, 5);

	/* speed and duplexity are found in CFG */
	val = CSR_READ(l, SIP_CFG);
	fdx = !!(val & (1U << 29));
	printf("%s", (val & (1U << 30)) ? "100Mbps" : "10Mbps");
	if (fdx)
		printf("-FDX");
	printf("\n");

	txd = &l->txd[0];
	txd->xd0 = htole32(VTOPHYS(txd));
	rxd = l->rxd;
	rxd[0].xd0 = htole32(VTOPHYS(&rxd[1]));
	rxd[0].xd1 = htole32(XD1_OWN | FRAMESIZE);
	rxd[0].xd2 = htole32(VTOPHYS(l->store[0]));
	rxd[1].xd0 = htole32(VTOPHYS(&rxd[0]));
	rxd[1].xd1 = htole32(XD1_OWN | FRAMESIZE);
	rxd[1].xd2 = htole32(VTOPHYS(l->store[1]));
	wbinv(l, sizeof(struct local));
	l->tx = l->rx = 0;

	CSR_WRITE(l, SIP_RFCR, 0);
	CSR_WRITE(l, SIP_RFDR, (en[1] << 8) | en[0]);
	CSR_WRITE(l, SIP_RFCR, 2);
	CSR_WRITE(l, SIP_RFDR, (en[3] << 8) | en[2]);
	CSR_WRITE(l, SIP_RFCR, 4);
	CSR_WRITE(l, SIP_RFDR, (en[5] << 8) | en[4]);
	CSR_WRITE(l, SIP_RFCR, RFCR_RFEN | RFCR_APM);

	txc = TXCFG_ATP | TXCFG_DMA256 | 0x1002;
	rxc = RXCFG_DMA256 | 0x20;
	if (fdx) {
		txc |= TXCFG_CSI | TXCFG_HBI;
		rxc |= RXCFG_ATX;
	}
	l->cr = CR_RXE;
	CSR_WRITE(l, SIP_TXDP, VTOPHYS(txd));
	CSR_WRITE(l, SIP_RXDP, VTOPHYS(rxd));
	CSR_WRITE(l, SIP_TXCFG, txc);
	CSR_WRITE(l, SIP_RXCFG, rxc);
	CSR_WRITE(l, SIP_CR, l->cr);

	return l;
}

int
sip_send(void *dev, char *buf, unsigned len)
{
	struct local *l = dev;
	volatile struct desc *txd;
	unsigned loop;

	wbinv(buf, len);
	txd = &l->txd[l->tx];
	txd->xd2 = htole32(VTOPHYS(buf));
	txd->xd1 = htole32(XD1_OWN | (len & 0xfff));
	wbinv(txd, sizeof(struct desc));
	CSR_WRITE(l, SIP_CR, l->cr | CR_TXE);
	loop = 100;
	do {
		if ((le32toh(txd->xd1) & XD1_OWN) == 0)
			goto done;
		DELAY(10);
		inv(txd, sizeof(struct desc));
	} while (--loop != 0);
	printf("xmit failed\n");
	return -1;
  done:
	l->tx ^= 1;
	return len;
}

int
sip_recv(void *dev, char *buf, unsigned maxlen, unsigned timo)
{
	struct local *l = dev;
	volatile struct desc *rxd;
	unsigned bound, rxstat, len;
	uint8_t *ptr;

	bound = 1000 * timo;
printf("recving with %u sec. timeout\n", timo);
  again:
	rxd = &l->rxd[l->rx];
	do {
		inv(rxd, sizeof(struct desc));
		rxstat = le32toh(rxd->xd1);
		if ((rxstat & XD1_OWN) == 0)
			goto gotone;
		DELAY(1000);	/* 1 milli second */
	} while (--bound > 0);
	errno = 0;
	return -1;
  gotone:
	if ((rxstat & XD1_OK) == 0) {
		rxd->xd1 = htole32(XD1_OWN | FRAMESIZE);
		wbinv(rxd, sizeof(struct desc));
		l->rx ^= 1;
		goto again;
	}
	/* good frame */
	len = (rxstat & 0xfff) - 4 /* HASFCS */;
	if (len > maxlen)
		len = maxlen;
	ptr = l->store[l->rx];
	inv(ptr, len);
	memcpy(buf, ptr, len);
	rxd->xd1 = htole32(XD1_OWN | FRAMESIZE);
	wbinv(rxd, sizeof(struct desc));
	l->rx ^= 1;
	CSR_WRITE(l, SIP_CR, l->cr);
	return len;
}

static int
read_eeprom(struct local *l, int loc)
{
#define R110 06 /* SEEPROM READ op. */
	unsigned data, v, i;

	/* hold chip select */
	v = MEAR_EESEL;
	CSR_WRITE(l, SIP_MEAR, v);

	data = (R110 << 6) | (loc & 0x3f); /* 6 bit addressing */
	/* instruct R110 op. at loc in MSB first order */
	for (i = (1 << 8); i != 0; i >>= 1) {
		if (data & i)
			v |= MEAR_EEDI;
		else
			v &= ~MEAR_EEDI;
		CSR_WRITE(l, SIP_MEAR, v);
		CSR_WRITE(l, SIP_MEAR, v | MEAR_EECLK);
		DELAY(4);
		CSR_WRITE(l, SIP_MEAR, v);
		DELAY(4);
	}
	v = MEAR_EESEL;
	/* read 16bit quantity in MSB first order */
	data = 0;
	for (i = 0; i < 16; i++) {
		CSR_WRITE(l, SIP_MEAR, v | MEAR_EECLK);
		DELAY(4);
		data = (data << 1) | !!(CSR_READ(l, SIP_MEAR) & MEAR_EEDO);
		CSR_WRITE(l, SIP_MEAR, v);
		DELAY(4);
	}
	/* turn off chip select */
	CSR_WRITE(l, SIP_MEAR, 0);
	DELAY(4);
	return data;
}

#define MII_BMCR	0x00 	/* Basic mode control register (rw) */
#define  BMCR_RESET	0x8000	/* reset */
#define  BMCR_AUTOEN	0x1000	/* autonegotiation enable */
#define  BMCR_ISO	0x0400	/* isolate */
#define  BMCR_STARTNEG	0x0200	/* restart autonegotiation */
#define MII_BMSR	0x01	/* Basic mode status register (ro) */
#define  BMSR_ACOMP	0x0020	/* Autonegotiation complete */
#define  BMSR_LINK	0x0004	/* Link status */
#define MII_ANAR	0x04	/* Autonegotiation advertisement (rw) */
#define  ANAR_FC	0x0400	/* local device supports PAUSE */
#define  ANAR_TX_FD	0x0100	/* local device supports 100bTx FD */
#define  ANAR_TX	0x0080	/* local device supports 100bTx */
#define  ANAR_10_FD	0x0040	/* local device supports 10bT FD */
#define  ANAR_10	0x0020	/* local device supports 10bT */
#define  ANAR_CSMA	0x0001	/* protocol selector CSMA/CD */
#define MII_ANLPAR	0x05	/* Autonegotiation lnk partner abilities (rw) */

unsigned
mii_read(struct local *l, int phy, int reg)
{
	unsigned val;

	do {
		val = CSR_READ(l, SIP_BMCR + (reg << 2));
	} while (reg == MII_BMSR && val == 0);
	return val & 0xffff;
}

void
mii_write(struct local *l, int phy, int reg, int val)
{

	CSR_WRITE(l, SIP_BMCR + (reg << 2), val);
}

void
mii_initphy(struct local *l)
{
	int phy, ctl, sts, bound;

	for (phy = 0; phy < 32; phy++) {
		ctl = mii_read(l, phy, MII_BMCR);
		sts = mii_read(l, phy, MII_BMSR);
		if (ctl != 0xffff && sts != 0xffff)
			goto found;
	}
	printf("MII: no PHY found\n");
	return;
  found:
	ctl = mii_read(l, phy, MII_BMCR);
	mii_write(l, phy, MII_BMCR, ctl | BMCR_RESET);
	bound = 100;
	do {
		DELAY(10);
		ctl = mii_read(l, phy, MII_BMCR);
		if (ctl == 0xffff) {
			printf("MII: PHY %d has died after reset\n", phy);
			return;
		}
	} while (bound-- > 0 && (ctl & BMCR_RESET));
	if (bound == 0) {
		printf("PHY %d reset failed\n", phy);
	}
	ctl &= ~BMCR_ISO;
	mii_write(l, phy, MII_BMCR, ctl);
	sts = mii_read(l, phy, MII_BMSR) |
	    mii_read(l, phy, MII_BMSR); /* read twice */
	l->phy = phy; /* should be 0 */
	l->bmsr = sts;
}

void
mii_dealan(struct local *l, unsigned timo)
{
	unsigned anar, bound;

	anar = ANAR_TX_FD | ANAR_TX | ANAR_10_FD | ANAR_10 | ANAR_CSMA;
	mii_write(l, l->phy, MII_ANAR, anar);
	mii_write(l, l->phy, MII_BMCR, BMCR_AUTOEN | BMCR_STARTNEG);
	l->anlpar = 0;
	bound = getsecs() + timo;
	do {
		l->bmsr = mii_read(l, l->phy, MII_BMSR) |
		   mii_read(l, l->phy, MII_BMSR); /* read twice */
		if ((l->bmsr & BMSR_LINK) && (l->bmsr & BMSR_ACOMP)) {
			l->anlpar = mii_read(l, l->phy, MII_ANLPAR);
			break;
		}
		DELAY(10 * 1000);
	} while (getsecs() < bound);
	return;
}

File Added: src/sys/arch/sandpoint/stand/altboot/skg.c
/* $NetBSD: skg.c,v 1.1 2011/01/23 01:05:30 nisimura Exp $ */

/*-
 * Copyright (c) 2010 Frank Wille.
 * All rights reserved.
 *
 * Written by Frank Wille for The NetBSD Project.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include <sys/param.h>

#include <netinet/in.h>
#include <netinet/in_systm.h>

#include <lib/libsa/stand.h>
#include <lib/libsa/net.h>

#include "globals.h"

/*
 * - reverse endian access every CSR.
 * - no vtophys() translation, vaddr_t == paddr_t.
 * - PIPT writeback cache aware.
 */
#define CSR_WRITE_1(l, r, v)	*(volatile uint8_t *)((l)->csr+(r)) = (v)
#define CSR_READ_1(l, r)	*(volatile uint8_t *)((l)->csr+(r))
#define CSR_WRITE_2(l, r, v)	out16rb((l)->csr+(r), (v))
#define CSR_READ_2(l, r)	in16rb((l)->csr+(r))
#define CSR_WRITE_4(l, r, v)	out32rb((l)->csr+(r), (v))
#define CSR_READ_4(l, r)	in32rb((l)->csr+(r))
#define VTOPHYS(va)		(uint32_t)(va)
#define DEVTOV(pa)		(uint32_t)(pa)
#define wbinv(adr, siz)		_wbinv(VTOPHYS(adr), (uint32_t)(siz))
#define inv(adr, siz)		_inv(VTOPHYS(adr), (uint32_t)(siz))
#define DELAY(n)		delay(n)
#define ALLOC(T,A)		(T *)allocaligned(sizeof(T),(A))

struct desc {
	uint32_t xd0, xd1, xd2, xd3, xd4;
	uint32_t rsrvd[3];
};
#define CTL_LS			0x20000000
#define CTL_FS			0x40000000
#define CTL_OWN			0x80000000
#define CTL_DEFOPC		0x00550000
#define FRAMEMASK		0x0000ffff
#define RXSTAT_RXOK		0x00000100

#define SK_CSR			0x0004
#define  CSR_SW_RESET		0x0001
#define  CSR_SW_UNRESET		0x0002
#define  CSR_MASTER_RESET	0x0004
#define  CSR_MASTER_UNRESET	0x0008
#define SK_IMR			0x000c
#define SK_BMU_RX_CSR0		0x0060
#define SK_BMU_TXS_CSR0		0x0068
#define SK_MAC0			0x0100
#define SK_MAC1			0x0108
#define SK_GPIO			0x015c
#define SK_RAMCTL		0x01a0
#define SK_TXAR1_COUNTERCTL	0x0210
#define  TXARCTL_ON		0x02
#define  TXARCTL_FSYNC_ON       0x80
#define SK_RXQ1_CURADDR_LO	0x0420
#define SK_RXQ1_CURADDR_HI	0x0424
#define SK_RXQ1_BMU_CSR		0x0434
#define  RXBMU_CLR_IRQ_EOF		0x00000002
#define  RXBMU_RX_START			0x00000010
#define  RXBMU_RX_STOP			0x00000020
#define  RXBMU_POLL_ON			0x00000080
#define  RXBMU_TRANSFER_SM_UNRESET	0x00000200
#define  RXBMU_DESCWR_SM_UNRESET	0x00000800
#define  RXBMU_DESCRD_SM_UNRESET	0x00002000
#define  RXBMU_SUPERVISOR_SM_UNRESET	0x00008000
#define  RXBMU_PFI_SM_UNRESET		0x00020000
#define  RXBMU_FIFO_UNRESET		0x00080000
#define  RXBMU_DESC_UNRESET		0x00200000
#define SK_TXQS1_CURADDR_LO	0x0620
#define SK_TXQS1_CURADDR_HI	0x0624
#define SK_TXQS1_BMU_CSR	0x0634
#define  TXBMU_CLR_IRQ_EOF		0x00000002
#define  TXBMU_TX_START			0x00000010
#define  TXBMU_TX_STOP			0x00000020
#define  TXBMU_POLL_ON			0x00000080
#define  TXBMU_TRANSFER_SM_UNRESET	0x00000200
#define  TXBMU_DESCWR_SM_UNRESET	0x00000800
#define  TXBMU_DESCRD_SM_UNRESET	0x00002000
#define  TXBMU_SUPERVISOR_SM_UNRESET	0x00008000
#define  TXBMU_PFI_SM_UNRESET		0x00020000
#define  TXBMU_FIFO_UNRESET		0x00080000
#define  TXBMU_DESC_UNRESET		0x00200000
#define SK_RXRB1_START		0x0800
#define SK_RXRB1_END		0x0804
#define SK_RXRB1_WR_PTR		0x0808
#define SK_RXRB1_RD_PTR		0x080c
#define SK_RXRB1_CTLTST		0x0828
#define  RBCTL_UNRESET		0x02
#define  RBCTL_ON		0x08
#define  RBCTL_STORENFWD_ON	0x20
#define SK_TXRBS1_START		0x0a00
#define SK_TXRBS1_END		0x0a04
#define SK_TXRBS1_WR_PTR	0x0a08
#define SK_TXRBS1_RD_PTR	0x0a0c
#define SK_TXRBS1_CTLTST	0x0a28
#define SK_RXMF1_CTRL_TEST	0x0c48
#define  RFCTL_OPERATION_ON	0x00000008
#define  RFCTL_RESET_CLEAR	0x00000002
#define SK_TXMF1_CTRL_TEST	0x0D48
#define  TFCTL_OPERATION_ON	0x00000008
#define  TFCTL_RESET_CLEAR	0x00000002
#define SK_GMAC_CTRL		0x0f00
#define  GMAC_LOOP_OFF		0x00000010
#define  GMAC_PAUSE_ON		0x00000008
#define  GMAC_RESET_CLEAR	0x00000002
#define  GMAC_RESET_SET		0x00000001
#define SK_GPHY_CTRL		0x0f04
#define  GPHY_INT_POL_HI	0x08000000
#define  GPHY_DIS_FC		0x02000000
#define  GPHY_DIS_SLEEP		0x01000000
#define  GPHY_ENA_XC		0x00040000
#define  GPHY_ENA_PAUSE		0x00002000
#define  GPHY_RESET_CLEAR	0x00000002
#define  GPHY_RESET_SET		0x00000001
#define  GPHY_ANEG_ALL		0x0009c000
#define  GPHY_COPPER		0x00f00000
#define SK_LINK_CTRL		0x0f10
#define  LINK_RESET_CLEAR	0x0002
#define  LINK_RESET_SET		0x0001

#define YUKON_GPCR		0x2804
#define  GPCR_TXEN		0x1000
#define  GPCR_RXEN		0x0800
#define YUKON_SA1		0x281c
#define YUKON_SA2		0x2828
#define YUKON_SMICR		0x2880
#define  SMICR_PHYAD(x)		(((x) & 0x1f) << 11)
#define  SMICR_REGAD(x)		(((x) & 0x1f) << 6)
#define  SMICR_OP_READ		0x0020
#define  SMICR_OP_WRITE		0x0000
#define  SMICR_READ_VALID	0x0010
#define  SMICR_BUSY		0x0008
#define YUKON_SMIDR		0x2884

#define MII_PSSR		0x11	/* MAKPHY status register */
#define  PSSR_DUPLEX		0x2000	/* FDX */
#define  PSSR_RESOLVED		0x0800	/* speed and duplex resolved */
#define  PSSR_LINK		0x0400  /* link indication */
#define  PSSR_SPEED(x)		(((x) >> 14) & 0x3)
#define  SPEED10		0
#define  SPEED100		1
#define  SPEED1000 		2

#define FRAMESIZE	1536

struct local {
	struct desc txd[2];
	struct desc rxd[2];
	uint8_t rxstore[2][FRAMESIZE];
	unsigned csr, rx, tx, phy;
	uint16_t pssr, anlpar;
};

static int mii_read(struct local *, int, int);
static void mii_write(struct local *, int, int, int);
static void mii_initphy(struct local *);
static void mii_dealan(struct local *, unsigned);

int
skg_match(unsigned tag, void *data)
{
	unsigned v;

	v = pcicfgread(tag, PCI_ID_REG);
	switch (v) {
	case PCI_DEVICE(0x11ab, 0x4320):
		return 1;
	}
	return 0;
}

void *
skg_init(unsigned tag, void *data)
{
	struct local *l;
	struct desc *txd, *rxd;
	uint8_t *en;
	unsigned i;
	uint16_t reg;

	l = ALLOC(struct local, 32);	/* desc alignment */
	memset(l, 0, sizeof(struct local));
	l->csr = DEVTOV(pcicfgread(tag, 0x10)); /* use mem space */

	/* reset the chip */
	CSR_WRITE_2(l, SK_CSR, CSR_SW_RESET);
	CSR_WRITE_2(l, SK_CSR, CSR_MASTER_RESET);
	CSR_WRITE_2(l, SK_LINK_CTRL, LINK_RESET_SET);
	DELAY(1000);
	CSR_WRITE_2(l, SK_CSR, CSR_SW_UNRESET);
	DELAY(2);
	CSR_WRITE_2(l, SK_CSR, CSR_MASTER_UNRESET);
	CSR_WRITE_2(l, SK_LINK_CTRL, LINK_RESET_CLEAR);
	CSR_WRITE_4(l, SK_RAMCTL, 2);	/* enable RAM interface */

	mii_initphy(l);

	/* read ethernet address */
	en = data;
	if (brdtype == BRD_SYNOLOGY)
		read_mac_from_flash(en);
	else
		for (i = 0; i < 6; i++)
			en[i] = CSR_READ_1(l, SK_MAC0 + i);
	printf("MAC address %02x:%02x:%02x:%02x:%02x:%02x\n",
	    en[0], en[1], en[2], en[3], en[4], en[5]);
	printf("PHY %d (%04x.%04x)\n", l->phy,
	    mii_read(l, l->phy, 2), mii_read(l, l->phy, 3));

	/* set station address */
	for (i = 0; i < 3; i++)
		CSR_WRITE_2(l, YUKON_SA1 + i * 4,
		    (en[i * 2] << 8) | en[i * 2 + 1]);

	/* configure RX and TX MAC FIFO */
	CSR_WRITE_1(l, SK_RXMF1_CTRL_TEST, RFCTL_RESET_CLEAR);
	CSR_WRITE_4(l, SK_RXMF1_CTRL_TEST, RFCTL_OPERATION_ON);
	CSR_WRITE_1(l, SK_TXMF1_CTRL_TEST, TFCTL_RESET_CLEAR);
	CSR_WRITE_4(l, SK_TXMF1_CTRL_TEST, TFCTL_OPERATION_ON);

	mii_dealan(l, 5);

	switch (PSSR_SPEED(l->pssr)) {
	case SPEED1000:
		printf("1000Mbps");
		break;
	case SPEED100:
		printf("100Mbps");
		break;
	case SPEED10:
		printf("10Mbps");
		break;
	}
	if (l->pssr & PSSR_DUPLEX)
		printf("-FDX");
	printf("\n");

	/* configure RAM buffers, assuming 64k RAM */
	CSR_WRITE_4(l, SK_RXRB1_CTLTST, RBCTL_UNRESET);
	CSR_WRITE_4(l, SK_RXRB1_START, 0);
	CSR_WRITE_4(l, SK_RXRB1_WR_PTR, 0);
	CSR_WRITE_4(l, SK_RXRB1_RD_PTR, 0);
	CSR_WRITE_4(l, SK_RXRB1_END, 0xfff);
	CSR_WRITE_4(l, SK_RXRB1_CTLTST, RBCTL_ON);
	CSR_WRITE_4(l, SK_TXRBS1_CTLTST, RBCTL_UNRESET);
	CSR_WRITE_4(l, SK_TXRBS1_CTLTST, RBCTL_STORENFWD_ON);
	CSR_WRITE_4(l, SK_TXRBS1_START, 0x1000);
	CSR_WRITE_4(l, SK_TXRBS1_WR_PTR, 0x1000);
	CSR_WRITE_4(l, SK_TXRBS1_RD_PTR, 0x1000);
	CSR_WRITE_4(l, SK_TXRBS1_END, 0x1fff);
	CSR_WRITE_4(l, SK_TXRBS1_CTLTST, RBCTL_ON);

	/* setup descriptors and BMU */
	CSR_WRITE_1(l, SK_TXAR1_COUNTERCTL, TXARCTL_ON|TXARCTL_FSYNC_ON);

	txd = &l->txd[0];
	txd[0].xd1 = htole32(VTOPHYS(&txd[1]));
	txd[1].xd1 = htole32(VTOPHYS(&txd[0]));
	rxd = &l->rxd[0];
	rxd[0].xd0 = htole32(FRAMESIZE|CTL_DEFOPC|CTL_LS|CTL_FS|CTL_OWN);
	rxd[0].xd1 = htole32(VTOPHYS(&rxd[1]));
	rxd[0].xd2 = htole32(VTOPHYS(l->rxstore[0]));
	rxd[1].xd0 = htole32(FRAMESIZE|CTL_DEFOPC|CTL_LS|CTL_FS|CTL_OWN);
	rxd[1].xd1 = htole32(VTOPHYS(&rxd[0]));
	rxd[1].xd2 = htole32(VTOPHYS(l->rxstore[1]));
	wbinv(l, sizeof(struct local));

	CSR_WRITE_4(l, SK_RXQ1_BMU_CSR,
	    RXBMU_TRANSFER_SM_UNRESET|RXBMU_DESCWR_SM_UNRESET|
	    RXBMU_DESCRD_SM_UNRESET|RXBMU_SUPERVISOR_SM_UNRESET|
	    RXBMU_PFI_SM_UNRESET|RXBMU_FIFO_UNRESET|
	    RXBMU_DESC_UNRESET);
	CSR_WRITE_4(l, SK_RXQ1_CURADDR_LO, VTOPHYS(rxd));
	CSR_WRITE_4(l, SK_RXQ1_CURADDR_HI, 0);

	CSR_WRITE_4(l, SK_TXQS1_BMU_CSR,
	    TXBMU_TRANSFER_SM_UNRESET|TXBMU_DESCWR_SM_UNRESET|
	    TXBMU_DESCRD_SM_UNRESET|TXBMU_SUPERVISOR_SM_UNRESET|
	    TXBMU_PFI_SM_UNRESET|TXBMU_FIFO_UNRESET|
	    TXBMU_DESC_UNRESET|TXBMU_POLL_ON);
	CSR_WRITE_4(l, SK_TXQS1_CURADDR_LO, VTOPHYS(txd));
	CSR_WRITE_4(l, SK_TXQS1_CURADDR_HI, 0);

	CSR_WRITE_4(l, SK_IMR, 0);
	CSR_WRITE_4(l, SK_RXQ1_BMU_CSR, RXBMU_RX_START);
	reg = CSR_READ_2(l, YUKON_GPCR);
	reg |= GPCR_TXEN | GPCR_RXEN;
	CSR_WRITE_2(l, YUKON_GPCR, reg);

	return l;
}

int
skg_send(void *dev, char *buf, unsigned len)
{
	struct local *l = dev;
	volatile struct desc *txd;
	unsigned loop;

	wbinv(buf, len);
	txd = &l->txd[l->tx];
	txd->xd2 = htole32(VTOPHYS(buf));
	txd->xd0 = htole32((len & FRAMEMASK)|CTL_DEFOPC|CTL_FS|CTL_LS|CTL_OWN);
	wbinv(txd, sizeof(struct desc));
	CSR_WRITE_4(l, SK_BMU_TXS_CSR0, TXBMU_TX_START);
	loop = 100;
	do {
		if ((le32toh(txd->xd0) & CTL_OWN) == 0)
			goto done;
		DELAY(10);
		inv(txd, sizeof(struct desc));
	} while (--loop > 0);
	printf("xmit failed\n");
	return -1;
  done:
	l->tx ^= 1;
	return len;
}

int
skg_recv(void *dev, char *buf, unsigned maxlen, unsigned timo)
{
	struct local *l = dev;
	volatile struct desc *rxd;
	unsigned bound, ctl, rxstat, len;
	uint8_t *ptr;

	bound = 1000 * timo;
#if 0
printf("recving with %u sec. timeout\n", timo);
#endif
  again:
	rxd = &l->rxd[l->rx];
	do {
		inv(rxd, sizeof(struct desc));
		ctl = le32toh(rxd->xd0);
		if ((ctl & CTL_OWN) == 0)
			goto gotone;
		DELAY(1000);	/* 1 milli second */
	} while (--bound > 0);
	errno = 0;
	return -1;
  gotone:
  	rxstat = le32toh(rxd->xd4);
	if ((rxstat & RXSTAT_RXOK) == 0) {
		rxd->xd0 = htole32(FRAMESIZE|CTL_DEFOPC|CTL_LS|CTL_FS|CTL_OWN);
		wbinv(rxd, sizeof(struct desc));
		l->rx ^= 1;
		goto again;
	}
	len = ctl & FRAMEMASK;
	if (len > maxlen)
		len = maxlen;
	ptr = l->rxstore[l->rx];
	inv(ptr, len);
	memcpy(buf, ptr, len);
	rxd->xd0 = htole32(FRAMESIZE|CTL_DEFOPC|CTL_LS|CTL_FS|CTL_OWN);
	wbinv(rxd, sizeof(struct desc));
	l->rx ^= 1;
	return len;
}

static int
mii_read(struct local *l, int phy, int reg)
{
	unsigned loop, v;

	CSR_WRITE_2(l, YUKON_SMICR, SMICR_PHYAD(phy) | SMICR_REGAD(reg) |
	    SMICR_OP_READ);
	loop = 1000;
	do {
		DELAY(1);
		v = CSR_READ_2(l, YUKON_SMICR);
	} while ((v & SMICR_READ_VALID) == 0 && --loop);
	if (loop == 0) {
		printf("mii_read timeout!\n");
		return 0;
	}
	return CSR_READ_2(l, YUKON_SMIDR);
}

static void
mii_write(struct local *l, int phy, int reg, int data)
{
	unsigned loop, v;

	CSR_WRITE_2(l, YUKON_SMIDR, data);
	CSR_WRITE_2(l, YUKON_SMICR, SMICR_PHYAD(phy) | SMICR_REGAD(reg) |
	    SMICR_OP_WRITE);
	loop = 1000;
	do {
		DELAY(1);
		v = CSR_READ_2(l, YUKON_SMICR);
	} while ((v & SMICR_BUSY) != 0 && --loop);
	if (loop == 0)
		printf("mii_write timeout!\n");
}

#define MII_BMCR	0x00	/* Basic mode control register (rw) */
#define  BMCR_AUTOEN	0x1000	/* autonegotiation enable */
#define  BMCR_STARTNEG	0x0200	/* restart autonegotiation */
#define MII_BMSR	0x01	/* Basic mode status register (ro) */
#define  BMSR_ACOMP	0x0020	/* Autonegotiation complete */
#define  BMSR_LINK	0x0004	/* Link status */
#define MII_ANAR	0x04	/* Autonegotiation advertisement (rw) */
#define  ANAR_FC	0x0400	/* local device supports PAUSE */
#define  ANAR_TX_FD	0x0100	/* local device supports 100bTx FD */
#define  ANAR_TX	0x0080	/* local device supports 100bTx */
#define  ANAR_10_FD	0x0040	/* local device supports 10bT FD */
#define  ANAR_10	0x0020	/* local device supports 10bT */
#define  ANAR_CSMA	0x0001	/* protocol selector CSMA/CD */
#define MII_ANLPAR	0x05	/* Autonegotiation lnk partner abilities (rw) */
#define MII_GTCR	0x09	/* 1000baseT control */
#define  GANA_1000TFDX	0x0200	/* advertise 1000baseT FDX */
#define  GANA_1000THDX	0x0100	/* advertise 1000baseT HDX */
#define MII_GTSR	0x0a	/* 1000baseT status */
#define  GLPA_1000TFDX	0x0800	/* link partner 1000baseT FDX capable */
#define  GLPA_1000THDX	0x0400	/* link partner 1000baseT HDX capable */

static void
mii_initphy(struct local *l)
{
	unsigned val;

	l->phy = 0;

	/* take PHY out of reset */
	val = CSR_READ_4(l, SK_GPIO);
	CSR_WRITE_4(l, SK_GPIO, (val | 0x2000000) & ~0x200);

	/* GMAC and GPHY reset */
	CSR_WRITE_4(l, SK_GPHY_CTRL, GPHY_RESET_SET);
	CSR_WRITE_4(l, SK_GMAC_CTRL, GMAC_RESET_SET);
	DELAY(1000);
	CSR_WRITE_4(l, SK_GMAC_CTRL, GMAC_RESET_CLEAR);
	CSR_WRITE_4(l, SK_GMAC_CTRL, GMAC_RESET_SET);
	DELAY(1000);

	val = GPHY_INT_POL_HI | GPHY_DIS_FC | GPHY_DIS_SLEEP | GPHY_ENA_XC |
	    GPHY_ANEG_ALL | GPHY_ENA_PAUSE | GPHY_COPPER;
	CSR_WRITE_4(l, SK_GPHY_CTRL, val | GPHY_RESET_SET);
	DELAY(1000);
	CSR_WRITE_4(l, SK_GPHY_CTRL, val | GPHY_RESET_CLEAR);
	CSR_WRITE_4(l, SK_GMAC_CTRL, GMAC_LOOP_OFF | GMAC_PAUSE_ON |
	    GMAC_RESET_CLEAR);
}

static void
mii_dealan(struct local *l, unsigned timo)
{
	unsigned bmsr, bound;

	mii_write(l, l->phy, MII_ANAR, ANAR_TX_FD | ANAR_TX | ANAR_10_FD |
	    ANAR_10 | ANAR_CSMA | ANAR_FC);
	mii_write(l, l->phy, MII_GTCR, GANA_1000TFDX | GANA_1000THDX);
	mii_write(l, l->phy, MII_BMCR, BMCR_AUTOEN | BMCR_STARTNEG);
	l->anlpar = 0;
	bound = getsecs() + timo;
	do {
		bmsr = mii_read(l, l->phy, MII_BMSR) |
		   mii_read(l, l->phy, MII_BMSR); /* read twice */
		if ((bmsr & BMSR_LINK) && (bmsr & BMSR_ACOMP)) {
			l->pssr = mii_read(l, l->phy, MII_PSSR);
			l->anlpar = mii_read(l, l->phy, MII_ANLPAR);
			if ((l->pssr & PSSR_RESOLVED) == 0)
				continue;
			break;
		}
		DELAY(10 * 1000);
	} while (getsecs() < bound);
}

File Added: src/sys/arch/sandpoint/stand/altboot/sme.c
/* $NetBSD: sme.c,v 1.1 2011/01/23 01:05:30 nisimura Exp $ */

/*-
 * Copyright (c) 2008 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by Tohru Nishimura.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include <sys/param.h>
 
#include <netinet/in.h>
#include <netinet/in_systm.h>
 
#include <lib/libsa/stand.h>
#include <lib/libsa/net.h>

#include "globals.h"

/*
 * - reverse endian access every CSR.
 * - no VTOPHYS() translation, vaddr_t == paddr_t. 
 * - PIPT writeback cache aware.
 */
#define CSR_READ(l, r)		in32rb((l)->csr+(r))
#define CSR_WRITE(l, r, v) 	out32rb((l)->csr+(r), (v))
#define VTOPHYS(va) 		(uint32_t)(va)
#define DEVTOV(pa) 		(uint32_t)(pa)
#define wbinv(adr, siz)		_wbinv(VTOPHYS(adr), (uint32_t)(siz))
#define inv(adr, siz)		_inv(VTOPHYS(adr), (uint32_t)(siz))
#define DELAY(n)		delay(n)
#define ALLOC(T,A)		(T *)allocaligned(sizeof(T),(A))

struct desc {
	uint32_t xd0, xd1, xd2, xd3;
};
#define T0_OWN		(1U<<31)	/* */
#define T0_ES		(1U<<15)	/* error summary */
#define	T0_FL		0x7fff0000	/* frame length */
#define T1_LS		(1U<<30)	/* last descriptor of Tx frame */
#define T1_FS		(1U<<29)	/* first descriptor of Tx frame */
#define T1_TER		(1U<<25)	/* wrap mark to form a ring */
#define T1_TCH		(1U<<24)	/* TDES3 points the next desc */
#define T1_FL		0x00007ff	/* Tx frame/segment length */
#define R0_OWN		(1U<<31)	/* */
#define R0_FL		0x3fff0000	/* frame length */
#define R0_ES		(1U<<15)	/* error summary */
#define R1_RER		(1U<<25)	/* wrap mark to form a ring */
#define	R1_RCH		(1U<<24)	/* RDES3 points the next desc */
/* RDES1 will be never changed while operation */

#define	BUSMODE		0x00
#define	TXPOLLD		0x04		/* start transmission */
#define RXPOLLD		0x08		/* start receiving */
#define RXDBASE		0x0c		/* Rx descriptor list base */
#define	TXDBASE		0x10		/* Tx descriptor list base */
#define DMACCTL		0x18		/* DMAC control */
#define  DMACCTL_ST	(1U<<13)	/* start/stop Tx DMA */
#define  DMACCTL_SR	(1U<< 1)	/* start/stop Rx DMA */
#define MAC_CR		0x80		/* MAC control */
#define  MACCR_FDPX     (1U<<20)	/* full duplex operation */
#define  MACCR_TXEN     (1U<< 3)	/* enable xmit */
#define  MACCR_RXEN     (1U<< 2)	/* enable recv */
#define ADDRH		0x84		/* ea 5:4 */
#define ADDRL		0x88		/* ea 3:0 */
#define MIIADDR		0x94		/* MII control */
#define MIIDATA		0x98		/* MII data */

#define FRAMESIZE	1536

struct local {
	struct desc txd[2];
	struct desc rxd[2];
	uint8_t rxstore[2][FRAMESIZE];
	unsigned csr, tx, rx;
	unsigned phy, bmsr, anlpar;
};

static int mii_read(struct local *, int, int);
static void mii_write(struct local *, int, int, int);
static void mii_dealan(struct local *, unsigned);

int
sme_match(unsigned tag, void *data)
{
	unsigned v;

	v = pcicfgread(tag, PCI_ID_REG);
	switch (v) {
	case PCI_DEVICE(0x1055, 0xe940):
		return 1;
	}
	return 0;
}

void *
sme_init(unsigned tag, void *data)
{
	struct local *l;
	struct desc *txd, *rxd;
	unsigned mac32, mac16, val, fdx;
	uint8_t *en;

	l = ALLOC(struct local, 32); /* desc alignment */
	memset(l, 0, sizeof(struct local));
	l->csr = DEVTOV(pcicfgread(tag, 0x1c)); /* BAR3 mem space, LE */
	l->phy = 1; /* 9420 internal PHY */

	en = data;
	mac32 = CSR_READ(l, ADDRL);
	mac16 = CSR_READ(l, ADDRH);
	en[0] = mac32;
	en[1] = mac32 >> 8;
	en[2] = mac32 >> 16;
	en[3] = mac32 >> 24;
	en[4] = mac16;
	en[5] = mac16 >> 8;
#if 1
	printf("MAC address %02x:%02x:%02x:%02x:%02x:%02x\n",
		en[0], en[1], en[2], en[3], en[4], en[5]);
	printf("PHY %d (%04x.%04x)\n", l->phy,
	    mii_read(l, l->phy, 2), mii_read(l, l->phy, 3));
#endif

	mii_dealan(l, 5);

	/* speed and duplexity can be seen in MII 31 */
	val = mii_read(l, l->phy, 31);
	fdx = !!(val & (1U << 4));
	printf("%s", (val & (1U << 3)) ? "100Mbps" : "10Mbps");
	if (fdx)
		printf("-FDX");
	printf("\n");

	txd = &l->txd[0];
	rxd = &l->rxd[0];
	rxd[0].xd0 = htole32(R0_OWN);
	rxd[0].xd1 = htole32(R1_RCH | FRAMESIZE);
	rxd[0].xd2 = htole32(VTOPHYS(l->rxstore[0]));
	rxd[0].xd3 = htole32(VTOPHYS(&rxd[1]));
	rxd[1].xd0 = htole32(R0_OWN);
	rxd[1].xd1 = htole32(R1_RER | FRAMESIZE);
	rxd[1].xd2 = htole32(VTOPHYS(l->rxstore[1]));
	/* R1_RER neglects xd3 */
	l->tx = l->rx = 0;

	wbinv(l, sizeof(struct local));

	CSR_WRITE(l, TXDBASE, VTOPHYS(txd));
	CSR_WRITE(l, RXDBASE, VTOPHYS(rxd));
	val = MACCR_TXEN | MACCR_RXEN;
	if (fdx)
		val |= MACCR_FDPX;
	CSR_WRITE(l, BUSMODE, 0);
	CSR_WRITE(l, DMACCTL, DMACCTL_ST | DMACCTL_SR);
	CSR_WRITE(l, MAC_CR, val); /* (FDX), Tx/Rx enable */
	CSR_WRITE(l, RXPOLLD, 01); /* start receiving */

	return l;
}

int
sme_send(void *dev, char *buf, unsigned len)
{
	struct local *l = dev;
	volatile struct desc *txd;
	unsigned txstat, loop;

	/* send a single frame with no T1_TER|T1_TCH designation */
	wbinv(buf, len);
	txd = &l->txd[l->tx];
	txd->xd2 = htole32(VTOPHYS(buf));
	txd->xd1 = htole32(T1_FS | T1_LS | (len & T1_FL));
	txd->xd0 = htole32(T0_OWN | (len & T0_FL) << 16);
	wbinv(txd, sizeof(struct desc));
	CSR_WRITE(l, TXPOLLD, 01); /* start transmission */
	loop = 100;
	do {
		txstat = le32toh(txd->xd0);
		if (txstat & T0_ES)
			break;
		if ((txstat & T0_OWN) == 0)
			goto done;
		DELAY(10);
		inv(txd, sizeof(struct desc));
	} while (--loop != 0);
	printf("xmit failed\n");
	return -1;
  done:
	l->tx ^= 1;
	return len;
}

int
sme_recv(void *dev, char *buf, unsigned maxlen, unsigned timo)
{
	struct local *l = dev;
	volatile struct desc *rxd;
	unsigned bound, rxstat, len;
	uint8_t *ptr;

	bound = 1000 * timo;
printf("recving with %u sec. timeout\n", timo);
  again:
	rxd = &l->rxd[l->rx];
	do {
		inv(rxd, sizeof(struct desc));
		rxstat = le32toh(rxd->xd0);
		if ((rxstat & R0_OWN) == 0)
			goto gotone;
		DELAY(1000); /* 1 milli second */
	} while (--bound > 0);
	errno = 0;
	return -1;
  gotone:
	if (rxstat & R0_ES) {
		rxd->xd0 = htole32(R0_OWN);
		wbinv(rxd, sizeof(struct desc));
		l->rx ^= 1;
		CSR_WRITE(l, RXPOLLD, 01); /* restart receiving */
		goto again;
	}
	/* good frame */
	len = (rxstat & R0_FL) >> 16 /* no FCS included */;
        if (len > maxlen)
                len = maxlen;
	ptr = l->rxstore[l->rx];
        inv(ptr, len);
        memcpy(buf, ptr, len);
	rxd->xd0 = htole32(R0_OWN);
	wbinv(rxd, sizeof(struct desc));
	l->rx ^= 1;
	CSR_WRITE(l, RXPOLLD, 01); /* necessary? */
	return len;
}

#define MII_BMCR	0x00 	/* Basic mode control register (rw) */
#define  BMCR_RESET	0x8000	/* reset */
#define  BMCR_AUTOEN	0x1000	/* autonegotiation enable */
#define  BMCR_ISO	0x0400	/* isolate */
#define  BMCR_STARTNEG	0x0200	/* restart autonegotiation */
#define MII_BMSR	0x01	/* Basic mode status register (ro) */
#define  BMSR_ACOMP	0x0020	/* Autonegotiation complete */
#define  BMSR_LINK	0x0004	/* Link status */
#define MII_ANAR	0x04	/* Autonegotiation advertisement (rw) */
#define  ANAR_FC	0x0400	/* local device supports PAUSE */
#define  ANAR_TX_FD	0x0100	/* local device supports 100bTx FD */
#define  ANAR_TX	0x0080	/* local device supports 100bTx */
#define  ANAR_10_FD	0x0040	/* local device supports 10bT FD */
#define  ANAR_10	0x0020	/* local device supports 10bT */
#define  ANAR_CSMA	0x0001	/* protocol selector CSMA/CD */
#define MII_ANLPAR	0x05	/* Autonegotiation lnk partner abilities (rw) */

static int
mii_read(struct local *l, int phy, int reg)
{
	uint32_t ctl;

	do {
		ctl = CSR_READ(l, MIIADDR);
	} while (ctl & 01);
	ctl = (phy << 11) | (reg << 6) | (0 << 1); /* READ op */
	CSR_WRITE(l, MIIADDR, ctl);
	do {
		ctl = CSR_READ(l, MIIADDR);
	} while (ctl & 01);
	return CSR_READ(l, MIIDATA);
}

void
mii_write(struct local *l, int phy, int reg, int val)
{
	uint32_t ctl;

	do {
		ctl = CSR_READ(l, MIIADDR);
	} while (ctl & 01);
	ctl = (phy << 11) | (reg << 6) | (1 << 1); /* WRITE op */
	CSR_WRITE(l, MIIDATA, val);
}

void
mii_dealan(struct local *l, unsigned timo)
{
	unsigned anar, bound;

	anar = ANAR_TX_FD | ANAR_TX | ANAR_10_FD | ANAR_10 | ANAR_CSMA;
	mii_write(l, l->phy, MII_ANAR, anar);
	mii_write(l, l->phy, MII_BMCR, BMCR_AUTOEN | BMCR_STARTNEG);
	l->anlpar = 0;
	bound = getsecs() + timo;
	do {
		l->bmsr = mii_read(l, l->phy, MII_BMSR) |
		   mii_read(l, l->phy, MII_BMSR); /* read twice */
		if ((l->bmsr & BMSR_LINK) && (l->bmsr & BMSR_ACOMP)) {
			l->anlpar = mii_read(l, l->phy, MII_ANLPAR);
			break;
		}
		DELAY(10 * 1000);
	} while (getsecs() < bound);
	return;
}

File Added: src/sys/arch/sandpoint/stand/altboot/tlp.c
/* $NetBSD: tlp.c,v 1.1 2011/01/23 01:05:30 nisimura Exp $ */

/*-
 * Copyright (c) 2007 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by Tohru Nishimura.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include <sys/param.h>

#include <netinet/in.h>
#include <netinet/in_systm.h>

#include <lib/libsa/stand.h>
#include <lib/libsa/net.h>

#include "globals.h"

/*
 * - reverse endian access for CSR register.
 * - no vtophys() translation, vaddr_t == paddr_t.
 * - PIPT writeback cache aware.
 */
#define CSR_READ(l, r)		in32rb((l)->csr+(r))
#define CSR_WRITE(l, r, v)	out32rb((l)->csr+(r), (v))
#define VTOPHYS(va)		(uint32_t)(va)
#define DEVTOV(pa)		(uint32_t)(pa)
#define wbinv(adr, siz)		_wbinv(VTOPHYS(adr), (uint32_t)(siz))
#define inv(adr, siz)		_inv(VTOPHYS(adr), (uint32_t)(siz))
#define DELAY(n)		delay(n)
#define ALLOC(T,A)		(T *)allocaligned(sizeof(T),(A))

struct desc {
	uint32_t xd0, xd1, xd2, xd3;
};
#define T0_OWN		(1U<<31)	/* desc is ready to tx */
#define T0_ES		(1U<<15)	/* Tx error summary */
#define T1_LS		(1U<<30)	/* last segment */
#define T1_FS		(1U<<29)	/* first segment */
#define T1_TER		(1U<<25)	/* end of ring mark */
#define T1_TCH		(1U<<24)	/* TDES3 points the next desc */
#define T1_TBS_MASK	0x7ff		/* segment size 10:0 */
#define R0_OWN		(1U<<31)	/* desc is empty */
#define R0_FS		(1U<<30)	/* first desc of frame */
#define R0_LS		(1U<<8)		/* last desc of frame */
#define R0_ES		(1U<<15)	/* Rx error summary */
#define R1_RER		(1U<<25)	/* end of ring mark */
#define R1_RCH		(1U<<24)	/* RDES3 points the next desc */
#define R0_FLMASK	0x3fff0000	/* frame length 29:16 */
#define R1_RBS_MASK	0x7ff		/* segment size 10:0 */

#define PAR_CSR0	0x00		/* bus mode */
#define  PAR_DEFAULTS	0x00001000	/* PDF sez it should be ... */
#define  PAR_SWR	01
#define TDR_CSR1	0x08		/* T0_OWN poll demand */
#define RDR_CSR2	0x10		/* R0_OWN poll demand */
#define RDB_CSR3	0x18		/* Rx descriptor base */
#define TDB_CSR4	0x20		/* Tx descriptor base */
#define SR_CSR5		0x28		/* interrupt stauts */
#define NAR_CSR6	0x30		/* operation mode */
#define  NAR_NOSQE	(1U<<19)	/* _not_ use SQE signal */
#define  NAR_TEN	(1U<<13)	/* instruct start/stop Tx */
#define  NAR_REN	(1U<< 1)	/* instruct start/stop Rx */
#define IER_CSR7	0x38		/* interrupt enable mask */
#define SPR_CSR9	0x48		/* SEEPROM and MII management */
#define  MII_MDI	(1U<<19)	/* 0/1 presense after read op */
#define  MII_MIDIR	(1U<<18)	/* 1 for PHY->HOST */
#define  MII_MDO	(1U<<17)	/* 0/1 for write op */
#define  MII_MDC	(1U<<16)	/* MDIO clock */
#define  SROM_RD	(1U<<14)	/* read operation */
#define  SROM_WR	(1U<<13)	/* write openration */
#define  SROM_SR	(1U<<11)	/* SEEPROM select */
#define PAR0_CSR25	0xa4		/* MAC 3:0 */
#define PAR1_CSR26	0xa8		/* MAC 5:4 */
#define AN_OMODE	0xfc		/* operation mode */

#define FRAMESIZE	1536

struct local {
	struct desc txd[2];
	struct desc rxd[2];
	uint8_t rxstore[2][FRAMESIZE];
	unsigned csr, omr, tx, rx;
	unsigned phy, bmsr, anlpar;
};

static unsigned mii_read(struct local *, int, int);
static void mii_write(struct local *, int, int, int);
static void mii_initphy(struct local *);
static void mii_dealan(struct local *, unsigned);

int
tlp_match(unsigned tag, void *data)
{
	unsigned v;

	v = pcicfgread(tag, PCI_ID_REG);
	switch (v) {
	case PCI_DEVICE(0x1317, 0x0985): /* ADMTek/Infineon 983B/BX */
		return 1;
	}
	return 0;
}

void *
tlp_init(unsigned tag, void *data)
{
	struct local *l;
	struct desc *txd, *rxd;
	unsigned i, val, fdx;
	uint8_t *en;
	
	l = ALLOC(struct local, 2 * sizeof(struct desc)); /* desc alignment */
	memset(l, 0, sizeof(struct local));
	l->csr = DEVTOV(pcicfgread(tag, 0x14)); /* use mem space */

	CSR_WRITE(l, PAR_CSR0, PAR_SWR);
	i = 100;
	do {
		DELAY(10);
	} while (i-- > 0 && (CSR_READ(l, PAR_CSR0) & PAR_SWR) != 0);
	CSR_WRITE(l, PAR_CSR0, PAR_DEFAULTS);

	l->omr = NAR_NOSQE;
	CSR_WRITE(l, NAR_CSR6, l->omr);
	CSR_WRITE(l, SR_CSR5, ~0);
	CSR_WRITE(l, IER_CSR7, 0);

	en = data;
	val = CSR_READ(l, PAR0_CSR25);
	en[0] = val & 0xff;
	en[1] = (val >> 8) & 0xff;
	en[2] = (val >> 16) & 0xff;
	en[3] = (val >> 24) & 0xff;
	val = CSR_READ(l, PAR1_CSR26);
	en[4] = val & 0xff;
	en[5] = (val >> 8) & 0xff;
#if 1
	printf("MAC address %02x:%02x:%02x:%02x:%02x:%02x\n",
		en[0], en[1], en[2], en[3], en[4], en[5]);
#endif

	mii_initphy(l);
	mii_dealan(l, 5);

	val = CSR_READ(l, AN_OMODE);
	if (val & (1U << 29)) {
		printf("%s", (val & (1U << 31)) ? "100Mbps" : "10Mbps");
		fdx = !!(val & (1U << 30));
		if (fdx)
			printf("-FDX");
		printf("\n");
	}

	txd = &l->txd[0];
	txd[1].xd1 = htole32(T1_TER);
	rxd = &l->rxd[0];
	rxd[0].xd0 = htole32(R0_OWN);
	rxd[0].xd1 = htole32(FRAMESIZE);
	rxd[0].xd2 = htole32(VTOPHYS(l->rxstore[0]));
	rxd[1].xd0 = htole32(R0_OWN);
	rxd[1].xd1 = htole32(R1_RER | FRAMESIZE);
	rxd[1].xd2 = htole32(VTOPHYS(l->rxstore[1]));
	l->tx = l->rx = 0;

	/* make sure the entire descriptors transfered to memory */
	wbinv(l, sizeof(struct local));

	CSR_WRITE(l, TDB_CSR4, VTOPHYS(txd));
	CSR_WRITE(l, RDB_CSR3, VTOPHYS(rxd));

	/* start Tx/Rx */
	CSR_WRITE(l, NAR_CSR6, l->omr | NAR_TEN | NAR_REN);

	return l;
}

int
tlp_send(void *dev, char *buf, unsigned len)
{
	struct local *l = dev;
	volatile struct desc *txd;
	unsigned txstat, loop;

	wbinv(buf, len);
	txd = &l->txd[l->tx];
	txd->xd2 = htole32(VTOPHYS(buf));
	txd->xd1 &= htole32(T1_TER);
	txd->xd1 |= htole32(T1_FS | T1_LS | (len & T1_TBS_MASK));
	txd->xd0 = htole32(T0_OWN);
	wbinv(txd, sizeof(struct desc));
	CSR_WRITE(l, TDR_CSR1, 01);
	loop = 100;
	do {
		txstat = le32toh(txd->xd0);
		if ((txstat & T0_OWN) == 0)
			goto done;
		DELAY(10);
		inv(txd, sizeof(struct desc));
	} while (--loop != 0);
	printf("xmit failed\n");
	return -1;
  done:
	l->tx ^= 1;
	return len;
}

int
tlp_recv(void *dev, char *buf, unsigned maxlen, unsigned timo)
{
	struct local *l = dev;
	volatile struct desc *rxd;
	unsigned bound, rxstat, len;
	uint8_t *ptr;

	bound = 1000 * timo;
#if 0
printf("recving with %u sec. timeout\n", timo);
#endif
  again:
	rxd = &l->rxd[l->rx];
	do {
		inv(rxd, sizeof(struct desc));
		rxstat = le32toh(rxd->xd0);
		if ((rxstat & R0_OWN) == 0)
			goto gotone;
		DELAY(1000); /* 1 milli second */
	} while (--bound > 0);
	errno = 0;
	return -1;
  gotone:
	if (rxstat & R0_ES) {
		rxd->xd0 = htole32(R0_OWN);
		wbinv(rxd, sizeof(struct desc));
		l->rx ^= 1;
		goto again;
	}
	/* good frame */
	len = ((rxstat & R0_FLMASK) >> 16) - 4 /* HASFCS */;
	if (len > maxlen)
		len = maxlen;
	ptr = l->rxstore[l->rx];
	inv(ptr, len);
	memcpy(buf, ptr, len);
	rxd->xd0 = htole32(R0_OWN);
	wbinv(rxd, sizeof(struct desc));
	l->rx ^= 1;
	return len;
}

/*
 * bare MII access with bitbang'ing
 */
#define R110	6		/* SEEPROM/MDIO read op */
#define W101	5		/* SEEPROM/MDIO write op */
#define CS	(1U << 0)	/* hold chip select */
#define CLK	(1U << 1)	/* clk bit */
#define D1	(1U << 2)	/* bit existence */
#define VV	(1U << 3)	/* taken 0/1 from SEEPROM */

static unsigned
mii_read(struct local *l, int phy, int reg)
{
	unsigned data, rv, v, i;

	data = (R110 << 10) | (phy << 5) | reg;
	CSR_WRITE(l, SPR_CSR9, MII_MDO);
	for (i = 0; i < 32; i++) {
		CSR_WRITE(l, SPR_CSR9, MII_MDO | MII_MDC);
		DELAY(1);
		CSR_WRITE(l, SPR_CSR9, MII_MDO);
		DELAY(1);
	}
	CSR_WRITE(l, SPR_CSR9, 0);
	v = 0; /* 4OP + 5ADDR + 5REG */
	for (i = (1 << 13); i != 0; i >>= 1) {
		if (data & i)
			v |= MII_MDO;
		else
			v &= ~MII_MDO;
		CSR_WRITE(l, SPR_CSR9, v);
		DELAY(1);
		CSR_WRITE(l, SPR_CSR9, v | MII_MDC);
		DELAY(1);
		CSR_WRITE(l, SPR_CSR9, v);
		DELAY(1);
	}
	rv = 0; /* 2TA + 16MDI */
	for (i = 0; i < 18; i++) {
		CSR_WRITE(l, SPR_CSR9, MII_MIDIR);
		DELAY(1);
		rv = (rv << 1) | !!(CSR_READ(l, SPR_CSR9) & MII_MDI);
		CSR_WRITE(l, SPR_CSR9, MII_MIDIR | MII_MDC);
		DELAY(1);
	}
	CSR_WRITE(l, SPR_CSR9, 0);
	return rv & 0xffff;
}

static void
mii_write(struct local *l, int phy, int reg, int val)
{
	unsigned data, v, i;

	data = (W101 << 28) | (phy << 23) | (reg << 18) | (02 << 16);
	data |= val & 0xffff;
	CSR_WRITE(l, SPR_CSR9, MII_MDO);
	for (i = 0; i < 32; i++) {
		CSR_WRITE(l, SPR_CSR9, MII_MDO | MII_MDC);
		DELAY(1);
		CSR_WRITE(l, SPR_CSR9, MII_MDO);
		DELAY(1);
	}
	CSR_WRITE(l, SPR_CSR9, 0);
	v = 0; /* 4OP + 5ADDR + 5REG + 2TA + 16DATA */
	for (i = (1 << 31); i != 0; i >>= 1) {
		if (data & i)
			v |= MII_MDO;
		else
			v &= ~MII_MDO;
		CSR_WRITE(l, SPR_CSR9, v);
		DELAY(1);
		CSR_WRITE(l, SPR_CSR9, v | MII_MDC);
		DELAY(1);
		CSR_WRITE(l, SPR_CSR9, v);
		DELAY(1);
	}
	CSR_WRITE(l, SPR_CSR9, 0);
}

#define MII_BMCR	0x00	/* Basic mode control register (rw) */
#define  BMCR_RESET	0x8000	/* reset */
#define  BMCR_AUTOEN	0x1000	/* autonegotiation enable */
#define  BMCR_ISO	0x0400	/* isolate */
#define  BMCR_STARTNEG	0x0200	/* restart autonegotiation */
#define MII_BMSR	0x01	/* Basic mode status register (ro) */
#define  BMSR_ACOMP	0x0020	/* Autonegotiation complete */
#define  BMSR_LINK	0x0004	/* Link status */
#define MII_ANAR	0x04	/* Autonegotiation advertisement (rw) */
#define  ANAR_FC	0x0400	/* local device supports PAUSE */
#define  ANAR_TX_FD	0x0100	/* local device supports 100bTx FD */
#define  ANAR_TX	0x0080	/* local device supports 100bTx */
#define  ANAR_10_FD	0x0040	/* local device supports 10bT FD */
#define  ANAR_10	0x0020	/* local device supports 10bT */
#define  ANAR_CSMA	0x0001	/* protocol selector CSMA/CD */
#define MII_ANLPAR	0x05	/* Autonegotiation lnk partner abilities (rw) */

static void
mii_initphy(struct local *l)
{
	int phy, ctl, sts, bound;

	for (phy = 0; phy < 32; phy++) {
		ctl = mii_read(l, phy, MII_BMCR);
		sts = mii_read(l, phy, MII_BMSR);
		if (ctl != 0xffff && sts != 0xffff)
			goto found;
	}
	printf("MII: no PHY found\n");
	return;
  found:
	ctl = mii_read(l, phy, MII_BMCR);
	mii_write(l, phy, MII_BMCR, ctl | BMCR_RESET);
	bound = 100;
	do {
		DELAY(10);
		ctl = mii_read(l, phy, MII_BMCR);
		if (ctl == 0xffff) {
			printf("MII: PHY %d has died after reset\n", phy);
			return;
		}
	} while (bound-- > 0 && (ctl & BMCR_RESET));
	if (bound == 0) {
		printf("PHY %d reset failed\n", phy);
	}
	ctl &= ~BMCR_ISO;
	mii_write(l, phy, MII_BMCR, ctl);
	sts = mii_read(l, phy, MII_BMSR) |
	    mii_read(l, phy, MII_BMSR); /* read twice */
	l->phy = phy;
	l->bmsr = sts;
}

static void
mii_dealan(struct local *l, unsigned timo)
{
	unsigned anar, bound;

	anar = ANAR_TX_FD | ANAR_TX | ANAR_10_FD | ANAR_10 | ANAR_CSMA;
	mii_write(l, l->phy, MII_ANAR, anar);
	mii_write(l, l->phy, MII_BMCR, BMCR_AUTOEN | BMCR_STARTNEG);
	l->anlpar = 0;
	bound = getsecs() + timo;
	do {
		l->bmsr = mii_read(l, l->phy, MII_BMSR) |
		   mii_read(l, l->phy, MII_BMSR); /* read twice */
		if ((l->bmsr & BMSR_LINK) && (l->bmsr & BMSR_ACOMP)) {
			l->anlpar = mii_read(l, l->phy, MII_ANLPAR);
			break;
		}
		DELAY(10 * 1000);
	} while (getsecs() < bound);
	return;
}

File Added: src/sys/arch/sandpoint/stand/altboot/vge.c
/* $NetBSD: vge.c,v 1.1 2011/01/23 01:05:30 nisimura Exp $ */

/*-
 * Copyright (c) 2007 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by Tohru Nishimura.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include <sys/param.h>

#include <netinet/in.h>
#include <netinet/in_systm.h>

#include <lib/libsa/stand.h>
#include <lib/libsa/net.h>

#include "globals.h"

/*
 * - reverse endian access every CSR.
 * - no vtophys() translation, vaddr_t == paddr_t.
 * - PIPT writeback cache aware.
 */
#define CSR_WRITE_1(l, r, v)	*(volatile uint8_t *)((l)->csr+(r)) = (v)
#define CSR_READ_1(l, r)	*(volatile uint8_t *)((l)->csr+(r))
#define CSR_WRITE_2(l, r, v)	out16rb((l)->csr+(r), (v))
#define CSR_READ_2(l, r)	in16rb((l)->csr+(r))
#define CSR_WRITE_4(l, r, v)	out32rb((l)->csr+(r), (v))
#define CSR_READ_4(l, r)	in32rb((l)->csr+(r))
#define VTOPHYS(va)		(uint32_t)(va)
#define DEVTOV(pa)		(uint32_t)(pa)
#define wbinv(adr, siz)		_wbinv(VTOPHYS(adr), (uint32_t)(siz))
#define inv(adr, siz)		_inv(VTOPHYS(adr), (uint32_t)(siz))
#define DELAY(n)		delay(n)
#define ALLOC(T,A)		(T *)allocaligned(sizeof(T),(A))

struct tdesc {
	uint32_t t0, t1;
	struct {
		uint32_t lo;
		uint32_t hi;
	} tf[7];
};
struct rdesc {
	uint32_t r0, r1, r2, r3;
};
#define T0_OWN		(1U << 31)	/* 1: loaded for HW to send */	
#define T0_TERR		(1U << 15)	/* Tx error summary */		
#define T0_UDF		(1U << 12)	/* found link down when Tx */	
#define T0_SHDN		(1U << 10)	/* transfer was shutdowned */	
#define T0_CRS		(1U << 9)	/* found carrier sense lost */
#define T0_CDH		(1U << 8)	/* heartbeat check failure */
#define T0_ABT		(1U << 7)	/* excessive collision Tx abort */
#define T0_OWT		(1U << 6)	/* jumbo Tx frame was aborted */
#define T0_OWC		(1U << 5)	/* found out of window collision */
#define T0_COLS		(1U << 4)	/* collision detected */
#define T0_NCRMASK	0xf		/* number of collision retries */
#define T1_EOF		(1U << 25)	/* TCP large last segment */
#define T1_SOF		(1U << 24)	/* TCP large first segment */
#define T1_TIC		(1U << 13)	/* post Tx done interrupt */
#define T1_PIC		(1U << 22)	/* post priority interrupt */
#define T1_VTAG		(1U << 21)	/* insert VLAG tag */
#define T1_IPCK		(1U << 20)	/* generate IPv4 csum */
#define T1_UDPCK	(1U << 19)	/* generate UDPv4 csum */
#define T1_TCPCK	(1U << 18)	/* generate TCPv4 csum */
#define T1_JUMBO	(1U << 17)	/* jumbo frame */
#define T1_CRC		(1U << 16)	/* _disable_ CRC generation */
#define T1_PRIO		0x0000e000	/* VLAN priority value */
#define T1_CFI		(1U << 12)	/* VLAN CFI */
#define T1_VID		0x00000fff	/* VLAN ID 11:0 */
#define T_FLMASK	0x00003fff	/* Tx frame/segment length */
#define TF0_Q		(1U << 31)	/* "Q" bit of tf[0].hi */

#define R0_OWN		(1U << 31)	/* 1: empty for HW to load anew */
#define R0_FLMASK	0x3fff0000	/* frame length */
#define R0_RXOK		(1U << 15)
#define R0_MAR		(1U << 13)	/* multicast frame */
#define R0_BAR		(1U << 12)	/* broadcast frame */
#define R0_PHY		(1U << 11)	/* unicast frame */	
#define R0_VTAG		(1U << 10)	/* VTAG indicator */	
#define R0_STP		(1U << 9)	/* first frame segment */	
#define R0_EDP		(1U << 8)	/* last frame segment */
#define R0_DETAG	(1U << 7)	/* VTAG has removed */
#define R0_SNTAG	(1U << 6)	/* tagged SNAP frame */
#define R0_SYME		(1U << 5)	/* symbol error */
#define R0_LENE		(1U << 4)	/* frame length error */	
#define R0_CSUME	(1U << 3)	/* TCP/IP bad csum */
#define R0_FAE		(1U << 2)	/* frame alignment error */
#define R0_CRCE		(1U << 1)	/* CRC error */ 
#define R0_VIDM		(1U << 0)	/* VTAG filter miss */		
#define R1_IPOK		(1U << 22)	/* IP csum was fine */
#define R1_TUPOK	(1U << 21)	/* TCP/UDP csum was fine */	
#define R1_FRAG		(1U << 20)	/* fragmented IP */
#define R1_CKSMZO	(1U << 19)	/* UDP csum field was zero */
#define R1_IPKT		(1U << 18)	/* frame was IPv4 */
#define R1_TPKT		(1U << 17)	/* frame was TCPv4 */
#define R1_UPKT		(1U << 16)	/* frame was UDPv4 */		
#define R3_IC		(1U << 31)	/* post Rx interrupt */
#define R_FLMASK	0x00003ffd	/* Rx segment buffer length */	

#define VR_PAR0		0x00		/* SA [0] */
#define VR_PAR1		0x01		/* SA [1] */
#define VR_PAR2		0x02		/* SA [2] */
#define VR_PAR3		0x03		/* SA [3] */
#define VR_PAR4		0x04		/* SA [4] */
#define VR_PAR5		0x05		/* SA [5] */
#define VR_CAM0		0x10		/* 0..7 */
#define VR_RCR		0x06		/* Rx control */
#define  RCR_AP		(1U << 6)	/* accept unicast frame */
#define  RCR_AL		(1U << 5)	/* accept long VTAG frame */
#define  RCR_PROM	(1U << 4)	/* accept any frame */
#define  RCR_AB		(1U << 3)	/* accept broadcast frame */
#define  RCR_AM		(1U << 2)	/* use multicast filter */
#define VR_TCR		0x07		/* Tx control */
#define VR_CTL0		0x08		/* control #0 */
#define  CTL0_TXON	(1U << 3)	/* enable Tx DMA */
#define  CTL0_RXON	(1U << 2)	/* enable Rx DMA */
#define  CTL0_STOP	(1U << 1)	/* activate stop processing */
#define  CTL0_START	(1U << 0)	/* start and activate */
#define VR_CTL1		0x09		/* control #1 */
#define  CTL1_RESET	(1U << 7)
#define  CTL1_DPOLL	(1U << 3)	/* _disable_ TDES/RDES polling */
#define VR_CTL2		0x0a		/* control #2 */
#define  CTL2_3XFLC	(1U << 7)	/* 802.3x PAUSE flow control */
#define  CTL2_TPAUSE	(1U << 6)	/* handle PAUSE on transmit side */
#define  CTL2_RPAUSE	(1U << 5)	/* handle PAUSE on receive side */
#define  CTL2_HDXFLC	(1U << 4)	/* HDX jabber flow control */
#define VR_CTL3		0x0b		/* control #3 */
#define  CTL3_GIEN	(1U << 1)	/* global interrupt enable */
#define VR_DESCHI	0x18		/* RDES/TDES base high 63:32 */
#define VR_DATAHI	0x1c		/* frame data base high 63:48 */
#define VR_ISR		0x24		/* ISR0123 */
#define VR_IEN		0x28		/* IEN0123 */
#define VR_TDCSR	0x30
#define VR_RDCSR	0x32
#define VR_RDB		0x38		/* RDES base lo 31:0 */
#define VR_TDB0		0x40		/* #0 TDES base lo 31:0 */
#define VR_RDCSIZE	0x50		/* 0..255 */
#define VR_TDCSIZE	0x52		/* 0..4095 */
#define VR_RBRDU	0x5e		/* 0..255 */
#define VR_CAMADR	0x68
#define  CAM_EN		(1U << 7)	/* enable to manipulate */
#define  SADR_CAM	(0U << 6)	/* station address table */
#define  VTAG_CAM	(1U << 6)	/* VLAN tag table */
#define VR_CAMCTL	0x69
#define  CAMCTL_MULT	(00U << 6)	/* multicast address hash */
#define  CAMCTL_VBIT	(01U << 6)	/* valid bitmask */
#define  CAMCTL_ADDR	(02U << 6)	/* address data */
#define  CAMCTL_RD	(1U << 3)	/* CAM read op, auto cleared */
#define  CAMCTL_WR	(1U << 2)	/* CAM write op, auto cleared */
#define VR_MIICFG	0x6c		/* PHY number 4:0 */
#define VR_MIISR	0x6d		/* MII status */
#define  MIISR_MIDLE	(1U << 7)	/* not in auto polling */
#define VR_PHYSR0	0x6e		/* PHY status 0 */
#define VR_MIICR	0x70		/* MII control */
#define  MIICR_MAUTO	(1U << 7)	/* activate autopoll mode */
#define  MIICR_RCMD	(1U << 6)	/* MII read operation */
#define  MIICR_WCMD	(1U << 5)	/* MII write operation */
#define VR_MIIADR	0x71		/* MII indirect */
#define VR_MIIDATA	0x72		/* MII read/write */

#define FRAMESIZE	1536
#define NRXDESC		4	/* HW demands multiple of 4 */

struct local {
	struct tdesc txd;
	struct rdesc rxd[NRXDESC];
	uint8_t rxstore[NRXDESC][FRAMESIZE];
	unsigned csr, rx;
	unsigned phy, bmsr, anlpar;
};

static void mii_autopoll(struct local *);
static void mii_stoppoll(struct local *);
static int mii_read(struct local *, int, int);
static void mii_write(struct local *, int, int, int);
static void mii_dealan(struct local *, unsigned);

int
vge_match(unsigned tag, void *data)
{
	unsigned v;

	v = pcicfgread(tag, PCI_ID_REG);
	switch (v) {
	case PCI_DEVICE(0x1106, 0x3119):
		return 1;
	}
	return 0;
}

void *
vge_init(unsigned tag, void *data)
{
	unsigned val, i, fdx, loop;
	struct local *l;
	struct tdesc *txd;
	struct rdesc *rxd;
	uint8_t *en;


	l = ALLOC(struct local, 64);   /* desc alignment */
	memset(l, 0, sizeof(struct local));
	l->csr = DEVTOV(pcicfgread(tag, 0x14)); /* use mem space */

	val = CTL1_RESET;
	CSR_WRITE_1(l, VR_CTL1, val);
	do {
		val = CSR_READ_1(l, VR_CTL1);
	} while (val & CTL1_RESET);

	l->phy = CSR_READ_1(l, VR_MIICFG) & 0x1f;

	en = data;
	en[0] = CSR_READ_1(l, VR_PAR0);
	en[1] = CSR_READ_1(l, VR_PAR1);
	en[2] = CSR_READ_1(l, VR_PAR2);
	en[3] = CSR_READ_1(l, VR_PAR3);
	en[4] = CSR_READ_1(l, VR_PAR4);
	en[5] = CSR_READ_1(l, VR_PAR5);

	printf("MAC address %02x:%02x:%02x:%02x:%02x:%02x\n",
	    en[0], en[1], en[2], en[3], en[4], en[5]);
	printf("PHY %d (%04x.%04x)\n", l->phy,
	    mii_read(l, l->phy, 2), mii_read(l, l->phy, 3));

	mii_dealan(l, 5);
	
	/* speed and duplexity can be seen in MII 28 */
	val = mii_read(l, l->phy, 28);
	fdx = (val >> 5) & 01;
	switch ((val >> 3) & 03) {
	case 0: printf("10baseT"); break;
	case 1: printf("100baseTX"); break;
	case 2: printf("1000baseT"); break;
	}
	if (fdx)
		printf("-FDX");
	printf("\n");

	txd = &l->txd;
	rxd = &l->rxd[0];
	for (i = 0; i < NRXDESC; i++) {
		rxd[i].r0 = htole32(R0_OWN);
		rxd[i].r1 = 0;
		rxd[i].r2 = htole32(VTOPHYS(l->rxstore[i]));
		rxd[i].r3 = htole32(FRAMESIZE << 16);
	}
	wbinv(l, sizeof(struct local));
	l->rx = 0;

	/* set own station address into entry #0 */	
	CSR_WRITE_1(l, VR_CAMCTL, CAMCTL_ADDR);
	CSR_WRITE_1(l, VR_CAMADR, CAM_EN | SADR_CAM | 0);
	for (i = 0; i < 6; i++)
		CSR_WRITE_1(l, VR_CAM0 + i, en[i]);
	CSR_WRITE_1(l, VR_CAMCTL, CAMCTL_ADDR | CAMCTL_WR);
	loop = 20;
	while (--loop > 0 && (i = CSR_READ_1(l, VR_CAMCTL)) & CAMCTL_WR)
		DELAY(1);
	/* mark entry #0 valid, position 0 of 63:0 */
	CSR_WRITE_1(l, VR_CAMCTL, CAMCTL_VBIT);
	CSR_WRITE_1(l, VR_CAM0, 01);
	for (i = 1; i < 8; i++)
		CSR_WRITE_1(l, VR_CAM0 + i, 00);
	CSR_WRITE_1(l, VR_CAMADR, 0);
	CSR_WRITE_1(l, VR_CAMCTL, 0);

	/* prepare descriptor lists */
	CSR_WRITE_4(l, VR_RDB, VTOPHYS(rxd));
	CSR_WRITE_2(l, VR_RDCSIZE, NRXDESC - 1);
	CSR_WRITE_2(l, VR_RBRDU, NRXDESC - 1);
	CSR_WRITE_4(l, VR_TDB0, VTOPHYS(txd));
	CSR_WRITE_2(l, VR_TDCSIZE, 0);

	/* enable transmitter and receiver */
	CSR_WRITE_1(l, VR_RDCSR, 01);
	CSR_WRITE_1(l, VR_RDCSR, 04);
	CSR_WRITE_2(l, VR_TDCSR, 01);
	CSR_WRITE_1(l, VR_RCR, RCR_AP);
	CSR_WRITE_1(l, VR_TCR, 0);
	CSR_WRITE_1(l, VR_CTL0 + 0x4, CTL0_STOP);
	CSR_WRITE_1(l, VR_CTL0, CTL0_TXON | CTL0_RXON | CTL0_START);
	CSR_WRITE_4(l, VR_ISR, ~0);
	CSR_WRITE_4(l, VR_IEN, 0);

	return l;
}

int
vge_send(void *dev, char *buf, unsigned len)
{
	struct local *l = dev;
	volatile struct tdesc *txd;
	unsigned loop;
	
	len = (len & T_FLMASK);
	if (len < 60)
		len = 60; /* needs to stretch to ETHER_MIN_LEN - 4 */
	wbinv(buf, len);
	txd = &l->txd;
	txd->tf[0].lo = htole32(VTOPHYS(buf));
	txd->tf[0].hi = htole32(len << 16);
	txd->t1 = htole32(T1_SOF | T1_EOF | (2 << 28));
	txd->t0 = htole32(T0_OWN | len << 16);
	wbinv(txd, sizeof(struct tdesc));
	CSR_WRITE_2(l, VR_TDCSR, 04);
	loop = 100;
	do {
		if ((le32toh(txd->t0) & T0_OWN) == 0)
			goto done;
		DELAY(10);
		inv(txd, sizeof(struct tdesc));
	} while (--loop > 0);
	printf("xmit failed\n");
	return -1;
  done:
	return len;
}

int
vge_recv(void *dev, char *buf, unsigned maxlen, unsigned timo)
{
	struct local *l = dev;
	volatile struct rdesc *rxd;
	unsigned bound, rxstat, len;
	uint8_t *ptr;

	bound = 1000 * timo;
printf("recving with %u sec. timeout\n", timo);
  again:
	rxd = &l->rxd[l->rx];
	do {
		inv(rxd, sizeof(struct rdesc));
		rxstat = le32toh(rxd->r0);
		if ((rxstat & R0_OWN) == 0)
			goto gotone;
		DELAY(1000);	/* 1 milli second */
	} while (--bound > 0);
	errno = 0;
	return -1;
  gotone:
	if ((rxstat & R0_RXOK) == 0) {
		rxd->r0 = htole32(R0_OWN);
		rxd->r1 = 0;
		wbinv(rxd, sizeof(struct rdesc));
		l->rx ^= 1;
		goto again;
	}
	len = ((rxstat & R0_FLMASK) >> 16) - 4 /* HASFCS */;
	if (len > maxlen)
		len = maxlen;
	ptr = l->rxstore[l->rx];
	inv(ptr, len);
	memcpy(buf, ptr, len);
	if ((l->rx & 03) == 3) {
		/* needs to set R0_OWN to 4 descriptors at a time */
		rxd[00].r0 = htole32(R0_OWN);
		rxd[00].r1 = 0;
		rxd[-1].r0 = htole32(R0_OWN);
		rxd[-1].r1 = 0;
		rxd[-2].r0 = htole32(R0_OWN);
		rxd[-2].r1 = 0;
		rxd[-3].r0 = htole32(R0_OWN);
		rxd[-3].r1 = 0;
		wbinv(rxd, NRXDESC * sizeof(struct rdesc));
	}
	l->rx = (l->rx + 1) & (NRXDESC - 1);
	return len;
}

static void
mii_autopoll(struct local *l)
{
	int v;

	CSR_WRITE_1(l, VR_MIICR, 0);
	CSR_WRITE_1(l, VR_MIIADR, 1U << 7);
	do {
		DELAY(1);
		v = CSR_READ_1(l, VR_MIISR);
	} while ((v & MIISR_MIDLE) == 0);
	CSR_WRITE_1(l, VR_MIICR, MIICR_MAUTO);
	do {
		DELAY(1);
		v = CSR_READ_1(l, VR_MIISR);
	} while ((v & MIISR_MIDLE) != 0);
}

static void
mii_stoppoll(struct local *l)
{	
	int v;
	
	CSR_WRITE_1(l, VR_MIICR, 0);
	do {
		DELAY(1);
		v = CSR_READ_1(l, VR_MIISR);
	} while ((v & MIISR_MIDLE) == 0);
}

static int
mii_read(struct local *l, int phy, int reg)
{
	int v;

	mii_stoppoll(l);
	CSR_WRITE_1(l, VR_MIICFG, phy);
	CSR_WRITE_1(l, VR_MIIADR, reg);
	CSR_WRITE_1(l, VR_MIICR, MIICR_RCMD);
	do {
		v = CSR_READ_1(l, VR_MIICR);
	} while (v & MIICR_RCMD);
	v = CSR_READ_2(l, VR_MIIDATA);
	mii_autopoll(l);
	return v;
}

static void
mii_write(struct local *l, int phy, int reg, int data)
{
	int v;

	mii_stoppoll(l);
	CSR_WRITE_2(l, VR_MIIDATA, data);
	CSR_WRITE_1(l, VR_MIICFG, phy);
	CSR_WRITE_1(l, VR_MIIADR, reg);
	CSR_WRITE_1(l, VR_MIICR, MIICR_WCMD);
	do {
		v = CSR_READ_1(l, VR_MIICR);
	} while (v & MIICR_WCMD);
	mii_autopoll(l);
}

#define MII_BMCR	0x00	/* Basic mode control register (rw) */
#define  BMCR_RESET	0x8000	/* reset */
#define  BMCR_AUTOEN	0x1000	/* autonegotiation enable */
#define  BMCR_ISO	0x0400	/* isolate */
#define  BMCR_STARTNEG	0x0200	/* restart autonegotiation */
#define MII_BMSR	0x01	/* Basic mode status register (ro) */
#define  BMSR_ACOMP	0x0020	/* Autonegotiation complete */
#define  BMSR_LINK	0x0004	/* Link status */
#define MII_ANAR	0x04	/* Autonegotiation advertisement (rw) */
#define  ANAR_FC	0x0400	/* local device supports PAUSE */
#define  ANAR_TX_FD	0x0100	/* local device supports 100bTx FD */
#define  ANAR_TX	0x0080	/* local device supports 100bTx */
#define  ANAR_10_FD	0x0040	/* local device supports 10bT FD */
#define  ANAR_10	0x0020	/* local device supports 10bT */
#define  ANAR_CSMA	0x0001	/* protocol selector CSMA/CD */
#define MII_ANLPAR	0x05	/* Autonegotiation lnk partner abilities (rw) */
#define MII_GTCR	0x09	/* 1000baseT control */
#define  GANA_1000TFDX	0x0200	/* advertise 1000baseT FDX */
#define  GANA_1000THDX	0x0100	/* advertise 1000baseT HDX */
#define MII_GTSR	0x0a	/* 1000baseT status */
#define  GLPA_1000TFDX	0x0800	/* link partner 1000baseT FDX capable */
#define  GLPA_1000THDX	0x0400	/* link partner 1000baseT HDX capable */
#define  GLPA_ASM_DIR	0x0200	/* link partner asym. pause dir. capable */

void
mii_dealan(struct local *l, unsigned timo)
{
	unsigned anar, gtcr, bound;

	anar = ANAR_TX_FD | ANAR_TX | ANAR_10_FD | ANAR_10 | ANAR_CSMA;
	anar |= ANAR_FC;
	gtcr = GANA_1000TFDX | GANA_1000THDX;
	mii_write(l, l->phy, MII_ANAR, anar);
	mii_write(l, l->phy, MII_GTCR, gtcr);
	mii_write(l, l->phy, MII_BMCR, BMCR_AUTOEN | BMCR_STARTNEG);
	l->anlpar = 0;
	bound = getsecs() + timo;
	do {
		l->bmsr = mii_read(l, l->phy, MII_BMSR) |
		   mii_read(l, l->phy, MII_BMSR); /* read twice */
		if ((l->bmsr & BMSR_LINK) && (l->bmsr & BMSR_ACOMP)) {
			l->anlpar = mii_read(l, l->phy, MII_ANLPAR);
			break;
		}
		DELAY(10 * 1000);
	} while (getsecs() < bound);
	return;
}

File Added: src/sys/arch/sandpoint/stand/altboot/wm.c
/* $NetBSD: wm.c,v 1.1 2011/01/23 01:05:30 nisimura Exp $ */

/*-
 * Copyright (c) 2007 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by Tohru Nishimura.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include <sys/param.h>
 
#include <netinet/in.h>
#include <netinet/in_systm.h>
 
#include <lib/libsa/stand.h>
#include <lib/libsa/net.h>

#include <dev/pci/if_wmreg.h>

#include "globals.h"

/*
 * - reverse endian access every CSR.
 * - no vtophys() translation, vaddr_t == paddr_t. 
 * - PIPT writeback cache aware.
 */
#define CSR_READ(l, r)		in32rb((l)->csr+(r))
#define CSR_WRITE(l, r, v) 	out32rb((l)->csr+(r), (v))
#define VTOPHYS(va) 		(uint32_t)(va)
#define DEVTOV(pa) 		(uint32_t)(pa)
#define wbinv(adr, siz)		_wbinv(VTOPHYS(adr), (uint32_t)(siz))
#define inv(adr, siz)		_inv(VTOPHYS(adr), (uint32_t)(siz))
#define DELAY(n)		delay(n)
#define ALLOC(T,A)		(T *)allocaligned(sizeof(T),(A))

struct tdesc {
	uint32_t lo;	/* 31:0 */
	uint32_t hi;	/* 63:32 */
	uint32_t t2;	/* 31:16 command, 15:0 Tx frame length */
	uint32_t t3;	/* 31:16 VTAG, 15:8 opt, 7:0 Tx status */
};
struct rdesc {
	uint32_t lo;	/* 31:0 */
	uint32_t hi;	/* 63:32 */
	uint32_t r2;	/* 31:16 checksum, 15:0 Rx frame length */
	uint32_t r3;	/* 31:16 special, 15:8 errors, 7:0 status */
};
/* T2 command */
#define T2_FLMASK	0xffff		/* 15:0 */
#define T2_DTYP_C	(1U << 20)	/* data descriptor */
#define T2_EOP		(1U << 24)	/* end of packet */
#define T2_IFCS		(1U << 25)	/* insert FCS */
#define T2_RS		(1U << 27)	/* report status */
#define T2_RPS		(1U << 28)	/* report packet sent */
#define T2_DEXT		(1U << 29)	/* descriptor extention */
#define T2_VLE		(1U << 30)	/* VLAN enable */
#define T2_IDE		(1U << 31)	/* interrupt delay enable */
/* T3 status */
#define T3_DD		(1U << 0)	/* 1: Tx has done and vacant */
/* T3 option */
#define T3_IXSM		(1U << 16)	/* generate IP csum */
#define T3_TXSM		(1U << 17)	/* generate TCP/UDP csum */

#define R2_FLMASK	0xffff		/* 15:0 */
/* R3 status */
#define	R3_DD		(1U << 0)	/* 1: Rx frame loaded and available */
#define R3_EOP		(1U << 1)	/* end of packet */
#define R3_IXSM		(1U << 2)	/* ignore checksum indication */
#define R3_VP		(1U << 3)	/* VLAN packet */
#define R3_TCPCS	(1U << 5)	/* TCP csum performed */
#define R3_IPCS		(1U << 6)	/* IP csum performed */
#define R3_PIF		(1U << 7)	/* passed in-exact filter */
/* R3 error status */
#define R3_CE		(1U << 8)	/* CRC error */
#define R3_SE		(1U << 9)	/* symbol error */
#define R3_SEQ		(1U << 10)	/* sequence error */
#define R3_CXE		(1U << 12)	/* carrier extention error */
#define R3_TCPE		(1U << 13)	/* TCP csum error found */
#define R3_IPE		(1U << 14)	/* IP csum error found */
#define R3_RXE		(1U << 15)	/* Rx data error */

#define FRAMESIZE	1536

struct local {
	struct tdesc txd[2];
	struct rdesc rxd[2];
	uint8_t rxstore[2][FRAMESIZE];
	unsigned csr, tx, rx;
	unsigned ctl, tctl, rctl;
	unsigned phy, bmsr, anlpar;
	int sromsft;
};

static int read_srom(struct local *, int);
static unsigned mii_read(struct local *, int, int);
static void mii_write(struct local *, int, int, int);
static void mii_initphy(struct local *);
static void mii_dealan(struct local *, unsigned);

int
wm_match(unsigned tag, void *data)
{
	unsigned v;

	v = pcicfgread(tag, PCI_ID_REG);
	switch (v) {
	case PCI_DEVICE(0x8086, 0x107c):
		return 1;
	}
	return 0;
}

void *
wm_init(unsigned tag, void *data)
{
	unsigned val, fdx;
	struct local *l;
	struct tdesc *txd;
	struct rdesc *rxd;
	uint8_t *en;

	l = ALLOC(struct local, 32); /* desc alignment */
	memset(l, 0, sizeof(struct local));
	l->csr = pcicfgread(tag, 0x10); /* use mem space */

	CSR_WRITE(l, WMREG_TCTL, 0);
	CSR_WRITE(l, WMREG_RCTL, 0);

	mii_initphy(l);

	l->sromsft = 6;
	en = data;
	val = read_srom(l, 0); en[0] = val; en[1] = (val >> 8);
	val = read_srom(l, 1); en[2] = val; en[3] = (val >> 8);
	val = read_srom(l, 2); en[4] = val; en[5] = (val >> 8);

	printf("MAC address %02x:%02x:%02x:%02x:%02x:%02x\n",
	    en[0], en[1], en[2], en[3], en[4], en[5]);
	printf("PHY %d (%04x.%04x)\n", l->phy,
	    mii_read(l, l->phy, 2), mii_read(l, l->phy, 3));

	mii_dealan(l, 5);

	/* speed and duplexity are found at 82451 internal GPHY reg 17 */
	val = mii_read(l, l->phy, 0x11);
	fdx = !!(val & 0x0200);
	switch (val & 0xc000) {
	case 0x4000: printf("10Mbps"); break;
	case 0x8000: printf("100Mbps"); break;
	case 0xc000: printf("1000Mbps"); break;
	}
	if (fdx)
		printf("-FDX");
	printf("\n");

	txd = &l->txd[0];
	rxd = &l->rxd[0];
	rxd[0].lo = htole32(VTOPHYS(l->rxstore[0]));
	rxd[0].r2 = 0;
	rxd[0].r3 = 0;
	rxd[1].lo = htole32(VTOPHYS(l->rxstore[1]));
	rxd[1].r2 = 0;
	rxd[0].r3 = 0;
	l->tx = l->rx = 0;

	CSR_WRITE(l, WMREG_TDBAH, 0);
	CSR_WRITE(l, WMREG_TDBAL, VTOPHYS(txd));
	CSR_WRITE(l, WMREG_TDLEN, sizeof(l->txd));
	CSR_WRITE(l, WMREG_TDH, 0);
	CSR_WRITE(l, WMREG_TDT, 0);
	CSR_WRITE(l, WMREG_TIDV, 64);
	CSR_WRITE(l, WMREG_TADV, 128);
	CSR_WRITE(l, WMREG_TXDCTL, TXDCTL_PTHRESH(0) |
	    TXDCTL_HTHRESH(0) | TXDCTL_WTHRESH(0));
	CSR_WRITE(l, WMREG_TQSA_LO, 0);
	CSR_WRITE(l, WMREG_TQSA_HI, 0);

	CSR_WRITE(l, WMREG_RDBAH, 0);
	CSR_WRITE(l, WMREG_RDBAL, VTOPHYS(rxd));
	CSR_WRITE(l, WMREG_RDLEN, sizeof(l->rxd));
	CSR_WRITE(l, WMREG_RDH, 0);
	CSR_WRITE(l, WMREG_RDT, 0);
	CSR_WRITE(l, WMREG_RDTR, 0 | RDTR_FPD);
	CSR_WRITE(l, WMREG_RADV, 128);
	CSR_WRITE(l, WMREG_RXDCTL, RXDCTL_PTHRESH(0) |
	    RXDCTL_HTHRESH(0) | RXDCTL_WTHRESH(1));

	CSR_WRITE(l, WMREG_VET, 0);
	CSR_WRITE(l, WMREG_IMC, ~0);
	CSR_WRITE(l, WMREG_IMS, 0);

	l->tctl = TCTL_EN | TCTL_PSP | TCTL_CT(15);
	l->rctl = RCTL_EN | RCTL_LBM_NONE | RCTL_RDMTS_1_2;
	CSR_WRITE(l, WMREG_TCTL, l->tctl);
	CSR_WRITE(l, WMREG_RCTL, l->rctl);

	return l;
}

int
wm_send(void *dev, char *buf, unsigned len)
{
	struct local *l = dev;
	volatile struct tdesc *txd;
	unsigned loop;

	wbinv(buf, len);
	txd = &l->txd[l->tx];
	txd->lo = htole32(VTOPHYS(buf));
	txd->t2 = htole32(T2_EOP|T2_IFCS|T2_RS | (len & T2_FLMASK));
	txd->t3 = 0;
	wbinv(txd, sizeof(struct tdesc));
	CSR_WRITE(l, WMREG_TDT, 0);
	loop = 100;
	do {
		if ((le32toh(txd->t3) & T3_DD) != 0)
			goto done;
		DELAY(10);
		inv(txd, sizeof(struct tdesc));
	} while (--loop > 0);
	printf("xmit failed\n");
	return -1;
  done:
	l->tx ^= 1;
	return len;
}

int
wm_recv(void *dev, char *buf, unsigned maxlen, unsigned timo)
{
	struct local *l = dev;
	volatile struct rdesc *rxd;
	unsigned bound, rxstat, len;
	uint8_t *ptr;

	bound = 1000 * timo;
printf("recving with %u sec. timeout\n", timo);
  again:
	rxd = &l->rxd[l->rx];
	do {
		inv(rxd, sizeof(struct rdesc));
		rxstat = le32toh(rxd->r3);
		if ((rxstat & R3_DD) != 0)
			goto gotone;
		DELAY(1000);	/* 1 milli second */
	} while (--bound > 0);
	errno = 0;
	return -1;
  gotone:
	/* expect this has R3_EOP mark */
	if (rxstat & (R3_CE|R3_SE|R3_SEQ|R3_CXE|R3_RXE)) {
		rxd->r2 = 0;
		rxd->r3 = 0;
		wbinv(rxd, sizeof(struct rdesc));
		CSR_WRITE(l, WMREG_RDT, l->rx);
		l->rx ^= 1;
		goto again;
	}
	len = (rxstat & R2_FLMASK) - 4 /* HASFCS */; 
	if (len > maxlen)
		len = maxlen;
	ptr = l->rxstore[l->rx];
	inv(ptr, len);
	memcpy(buf, ptr, len);
	rxd->r2 = 0;
	rxd->r3 = 0;
	wbinv(rxd, sizeof(struct rdesc));
	CSR_WRITE(l, WMREG_RDT, l->rx);
	l->rx ^= 1;
	return len;
}

/*
 * bare SEEPROM access with bitbang'ing
 */
#define R110	6		/* SEEPROM read op */
#define CS  	(1U << 0)	/* hold chip select */
#define CLK	(1U << 1)	/* clk bit */
#define D1	(1U << 2)	/* bit existence */
#define VV 	(1U << 3)	/* taken 0/1 from SEEPROM */

static int
read_srom(struct local *l, int off)
{
	unsigned data, v, i;

	data = off & 0xff;		/* A5/A7-A0 */
	data |= R110 << l->sromsft;	/* 110 for READ */

	v = CSR_READ(l, WMREG_EECD) & ~(EECD_SK | EECD_DI);
	CSR_WRITE(l, WMREG_EECD, v);
	v |= EECD_CS;			/* hold CS */
	CSR_WRITE(l, WMREG_EECD, v);
	DELAY(2);

	/* instruct R110 op. at off in MSB first order */
	for (i = (1 << (l->sromsft + 2)); i != 0; i >>= 1) {
		if (data & i)
			v |= EECD_DI;
		else
			v &= ~EECD_DI;
		CSR_WRITE(l, WMREG_EECD, v);
		DELAY(2);
		CSR_WRITE(l, WMREG_EECD, v | EECD_SK);
		DELAY(2);
		CSR_WRITE(l, WMREG_EECD, v);
		DELAY(2);
	}
	v &= ~EECD_DI;

	/* read 16bit quantity in MSB first order */
	data = 0;
	for (i = 0; i < 16; i++) {
		CSR_WRITE(l, WMREG_EECD, v | EECD_SK);
		DELAY(2);
		data = (data << 1) | !!(CSR_READ(l, WMREG_EECD) & EECD_DO);
		CSR_WRITE(l, WMREG_EECD, v);
		DELAY(2);
	}
	/* turn off chip select */
	v = CSR_READ(l, WMREG_EECD) & ~EECD_CS;
	CSR_WRITE(l, WMREG_EECD, v);
	DELAY(2);

	return data;
}

#define MREG(v)		((v)<< 16)
#define MPHY(v)		((v)<< 21)

unsigned
mii_read(struct local *l, int phy, int reg)
{
	unsigned data;

	data = (2U << 26) | MPHY(phy) | MREG(reg);
	CSR_WRITE(l, WMREG_MDIC, data);
	do {
		data = CSR_READ(l, WMREG_MDIC);
	} while ((data & (1U << 28)) == 0);
	return data & 0xffff;
}

void
mii_write(struct local *l, int phy, int reg, int val)
{
	unsigned data;

	data = (1U << 26) | MPHY(phy) | MREG(reg) | (val & 0xffff);
	CSR_WRITE(l, WMREG_MDIC, data);
	do {
		data = CSR_READ(l, WMREG_MDIC);
	} while ((data & (1U << 28)) == 0);
}

#define MII_BMCR	0x00	/* Basic mode control register (rw) */
#define  BMCR_RESET	0x8000	/* reset */
#define  BMCR_AUTOEN	0x1000	/* autonegotiation enable */
#define  BMCR_ISO	0x0400	/* isolate */
#define  BMCR_STARTNEG	0x0200	/* restart autonegotiation */
#define MII_BMSR	0x01	/* Basic mode status register (ro) */
#define  BMSR_ACOMP	0x0020	/* Autonegotiation complete */
#define  BMSR_LINK	0x0004	/* Link status */
#define MII_ANAR	0x04	/* Autonegotiation advertisement (rw) */
#define  ANAR_FC	0x0400	/* local device supports PAUSE */
#define  ANAR_TX_FD	0x0100	/* local device supports 100bTx FD */
#define  ANAR_TX	0x0080	/* local device supports 100bTx */
#define  ANAR_10_FD	0x0040	/* local device supports 10bT FD */
#define  ANAR_10	0x0020	/* local device supports 10bT */
#define  ANAR_CSMA	0x0001	/* protocol selector CSMA/CD */
#define MII_ANLPAR	0x05	/* Autonegotiation lnk partner abilities (rw) */
#define MII_GTCR	0x09	/* 1000baseT control */
#define  GANA_1000TFDX	0x0200	/* advertise 1000baseT FDX */
#define  GANA_1000THDX	0x0100	/* advertise 1000baseT HDX */
#define MII_GTSR	0x0a	/* 1000baseT status */
#define  GLPA_1000TFDX	0x0800	/* link partner 1000baseT FDX capable */
#define  GLPA_1000THDX	0x0400	/* link partner 1000baseT HDX capable */
#define  GLPA_ASM_DIR	0x0200	/* link partner asym. pause dir. capable */

static void
mii_initphy(struct local *l)
{
	int phy, ctl, sts, bound;

	for (phy = 0; phy < 32; phy++) {
		ctl = mii_read(l, phy, MII_BMCR);
		sts = mii_read(l, phy, MII_BMSR);
		if (ctl != 0xffff && sts != 0xffff)
			goto found;
	}
	printf("MII: no PHY found\n");
	return;
  found:
	ctl = mii_read(l, phy, MII_BMCR);
	mii_write(l, phy, MII_BMCR, ctl | BMCR_RESET);
	bound = 100;
	do {
		DELAY(10);
		ctl = mii_read(l, phy, MII_BMCR);
		if (ctl == 0xffff) {
			printf("MII: PHY %d has died after reset\n", phy);
			return;
		}
	} while (bound-- > 0 && (ctl & BMCR_RESET));
	if (bound == 0) {
		printf("PHY %d reset failed\n", phy);
	}
	ctl &= ~BMCR_ISO;
	mii_write(l, phy, MII_BMCR, ctl);
	sts = mii_read(l, phy, MII_BMSR) |
	    mii_read(l, phy, MII_BMSR); /* read twice */
	l->phy = phy;
	l->bmsr = sts;
}

void
mii_dealan(struct local *l, unsigned timo)
{
	unsigned anar, gtcr, bound;

	anar = ANAR_TX_FD | ANAR_TX | ANAR_10_FD | ANAR_10 | ANAR_CSMA;
	anar |= ANAR_FC;
	gtcr = GANA_1000TFDX | GANA_1000THDX;
	mii_write(l, l->phy, MII_ANAR, anar);
	mii_write(l, l->phy, MII_GTCR, gtcr);
	mii_write(l, l->phy, MII_BMCR, BMCR_AUTOEN | BMCR_STARTNEG);
	l->anlpar = 0;
	bound = getsecs() + timo;
	do {
		l->bmsr = mii_read(l, l->phy, MII_BMSR) |
		   mii_read(l, l->phy, MII_BMSR); /* read twice */
		if ((l->bmsr & BMSR_LINK) && (l->bmsr & BMSR_ACOMP)) {
			l->anlpar = mii_read(l, l->phy, MII_ANLPAR);
			break;
		}
		DELAY(10 * 1000);
	} while (getsecs() < bound);
	return;
}

File Deleted: src/sys/arch/sandpoint/stand/netboot/Attic/Makefile

File Deleted: src/sys/arch/sandpoint/stand/netboot/Attic/nvt.c

File Deleted: src/sys/arch/sandpoint/stand/netboot/Attic/brdsetup.c

File Deleted: src/sys/arch/sandpoint/stand/netboot/Attic/dev_net.c

File Deleted: src/sys/arch/sandpoint/stand/netboot/Attic/pciide.c

File Deleted: src/sys/arch/sandpoint/stand/netboot/Attic/devopen.c

File Deleted: src/sys/arch/sandpoint/stand/netboot/Attic/dsk.c

File Deleted: src/sys/arch/sandpoint/stand/netboot/Attic/entry.S

File Deleted: src/sys/arch/sandpoint/stand/netboot/Attic/printf.c

File Deleted: src/sys/arch/sandpoint/stand/netboot/Attic/fxp.c

File Deleted: src/sys/arch/sandpoint/stand/netboot/Attic/globals.h

File Deleted: src/sys/arch/sandpoint/stand/netboot/Attic/pcn.c

File Deleted: src/sys/arch/sandpoint/stand/netboot/Attic/sip.c

File Deleted: src/sys/arch/sandpoint/stand/netboot/Attic/kse.c

File Deleted: src/sys/arch/sandpoint/stand/netboot/Attic/version

File Deleted: src/sys/arch/sandpoint/stand/netboot/Attic/main.c

File Deleted: src/sys/arch/sandpoint/stand/netboot/Attic/newvers.sh

File Deleted: src/sys/arch/sandpoint/stand/netboot/Attic/skg.c

File Deleted: src/sys/arch/sandpoint/stand/netboot/Attic/nif.c

File Deleted: src/sys/arch/sandpoint/stand/netboot/Attic/wm.c

File Deleted: src/sys/arch/sandpoint/stand/netboot/Attic/pci.c

File Deleted: src/sys/arch/sandpoint/stand/netboot/Attic/rge.c

File Deleted: src/sys/arch/sandpoint/stand/netboot/Attic/siisata.c

File Deleted: src/sys/arch/sandpoint/stand/netboot/Attic/sme.c

File Deleted: src/sys/arch/sandpoint/stand/netboot/Attic/tlp.c

File Deleted: src/sys/arch/sandpoint/stand/netboot/Attic/vge.c