Thu Jul 28 15:38:49 2011 UTC ()
Bring forward from matt-nb5-mips64.  Support for Ralink RT3883 MIPS 74K SoC
from CradlePoint Technology.


(matt)
diff -r1.6 -r1.7 src/sys/arch/evbppc/conf/P2020DS
diff -r1.8 -r1.9 src/sys/arch/evbppc/conf/P2020RDB
diff -r0 -r1.2 src/sys/arch/mips/conf/files.ralink
diff -r0 -r1.2 src/sys/arch/mips/ralink/ralink_bus.c
diff -r0 -r1.2 src/sys/arch/mips/ralink/ralink_com.c
diff -r0 -r1.2 src/sys/arch/mips/ralink/ralink_debug.h
diff -r0 -r1.2 src/sys/arch/mips/ralink/ralink_ehci.c
diff -r0 -r1.2 src/sys/arch/mips/ralink/ralink_eth.c
diff -r0 -r1.2 src/sys/arch/mips/ralink/ralink_gpio.c
diff -r0 -r1.2 src/sys/arch/mips/ralink/ralink_gpio.h
diff -r0 -r1.2 src/sys/arch/mips/ralink/ralink_i2c.c
diff -r0 -r1.2 src/sys/arch/mips/ralink/ralink_intr.c
diff -r0 -r1.2 src/sys/arch/mips/ralink/ralink_mainbus.c
diff -r0 -r1.2 src/sys/arch/mips/ralink/ralink_ohci.c
diff -r0 -r1.2 src/sys/arch/mips/ralink/ralink_reg.h
diff -r0 -r1.2 src/sys/arch/mips/ralink/ralink_usbhcvar.h
diff -r0 -r1.2 src/sys/arch/mips/ralink/ralink_var.h
diff -r0 -r1.2 src/sys/arch/mips/ralink/ralink_wdog.c

cvs diff -r1.6 -r1.7 src/sys/arch/evbppc/conf/P2020DS (expand / switch to unified diff)

--- src/sys/arch/evbppc/conf/P2020DS 2011/07/16 22:16:59 1.6
+++ src/sys/arch/evbppc/conf/P2020DS 2011/07/28 15:38:48 1.7
@@ -1,34 +1,35 @@ @@ -1,34 +1,35 @@
1# $NetBSD: P2020DS,v 1.6 2011/07/16 22:16:59 matt Exp $ 1# $NetBSD: P2020DS,v 1.7 2011/07/28 15:38:48 matt Exp $
2# 2#
3# P2020DS -- everything that's currently supported 3# P2020DS -- everything that's currently supported
4# 4#
5# 5#
6 6
7include "arch/evbppc/conf/std.mpc85xx" 7include "arch/evbppc/conf/std.mpc85xx"
8 8
9options INCLUDE_CONFIG_FILE # embed config file in kernel binary 9options INCLUDE_CONFIG_FILE # embed config file in kernel binary
10 10
11ident "P2020DS-$Revision: 1.6 $" 11ident "P2020DS-$Revision: 1.7 $"
12 12
13maxusers 32 13maxusers 32
14 14
15#options UVMHIST 15#options UVMHIST
16#options UVMHIST_PRINT 16#options UVMHIST_PRINT
17 17
18options P2020 18options P2020
19options PIXIS 19options PIXIS
20#options SYS_CLK=100000000 20#options SYS_CLK=100000000
21#options HZ=1000 21#options HZ=1000
 22options MEMSIZE=0x40000000
22 23
23makeoptions NEED_BINARY="yes" 24makeoptions NEED_BINARY="yes"
24makeoptions NEED_UBOOTIMAGE="yes" 25makeoptions NEED_UBOOTIMAGE="yes"
25 26
26#options INSECURE # disable kernel security levels 27#options INSECURE # disable kernel security levels
27#options NTP # NTP phase/frequency locked loop 28#options NTP # NTP phase/frequency locked loop
28options KTRACE # system call tracing via ktrace(1) 29options KTRACE # system call tracing via ktrace(1)
29 30
30options SYSVMSG # System V message queues 31options SYSVMSG # System V message queues
31options SYSVSEM # System V semaphores 32options SYSVSEM # System V semaphores
32options SYSVSHM # System V shared memory 33options SYSVSHM # System V shared memory
33 34
34options USERCONF # userconf(4) support 35options USERCONF # userconf(4) support

cvs diff -r1.8 -r1.9 src/sys/arch/evbppc/conf/P2020RDB (expand / switch to unified diff)

--- src/sys/arch/evbppc/conf/P2020RDB 2011/07/20 13:20:26 1.8
+++ src/sys/arch/evbppc/conf/P2020RDB 2011/07/28 15:38:48 1.9
@@ -1,23 +1,23 @@ @@ -1,23 +1,23 @@
1# $NetBSD: P2020RDB,v 1.8 2011/07/20 13:20:26 matt Exp $ 1# $NetBSD: P2020RDB,v 1.9 2011/07/28 15:38:48 matt Exp $
2# 2#
3# P2020RBD -- everything that's currently supported 3# P2020RBD -- everything that's currently supported
4# 4#
5 5
6include "arch/evbppc/conf/std.mpc85xx" 6include "arch/evbppc/conf/std.mpc85xx"
7 7
8options INCLUDE_CONFIG_FILE # embed config file in kernel binary 8options INCLUDE_CONFIG_FILE # embed config file in kernel binary
9 9
10ident "P2020RBD-$Revision: 1.8 $" 10ident "P2020RBD-$Revision: 1.9 $"
11 11
12maxusers 32 12maxusers 32
13 13
14makeoptions NEED_BINARY="yes" 14makeoptions NEED_BINARY="yes"
15makeoptions NEED_UBOOTIMAGE="yes" 15makeoptions NEED_UBOOTIMAGE="yes"
16 16
17#options UVMHIST 17#options UVMHIST
18#options UVMHIST_PRINT 18#options UVMHIST_PRINT
19 19
20options P2020 20options P2020
21options SYS_CLK=100000000 21options SYS_CLK=100000000
22#options HZ=1000 22#options HZ=1000
23 23
@@ -172,26 +172,30 @@ ukphy* at mii? @@ -172,26 +172,30 @@ ukphy* at mii?
172 172
173diic* at cpunode? # i2c bus 173diic* at cpunode? # i2c bus
174iic* at diic? 174iic* at diic?
175dsrtc* at iic1 addr 0x68 # RTC 175dsrtc* at iic1 addr 0x68 # RTC
176 176
177pq3pcie* at cpunode? # PCI-Express controller 177pq3pcie* at cpunode? # PCI-Express controller
178pq3pci* at cpunode? # PCI(X) 178pq3pci* at cpunode? # PCI(X)
179pci* at pq3pcie? 179pci* at pq3pcie?
180pci* at pq3pci? 180pci* at pq3pci?
181 181
182ppb* at pci? dev ? function ? # PCI-PCI bridges 182ppb* at pci? dev ? function ? # PCI-PCI bridges
183pci* at ppb? 183pci* at ppb?
184 184
 185ahcisata* at pci? dev ? function ?
 186atabus* at ahcisata? channel ?
 187wd* at atabus? drive ?
 188
185ehci* at cpunode? # usb 189ehci* at cpunode? # usb
186usb* at ehci? 190usb* at ehci?
187uhub* at usb? 191uhub* at usb?
188umass* at uhub? port ? 192umass* at uhub? port ?
189scsibus* at umass? channel ? 193scsibus* at umass? channel ?
190sd* at scsibus? target ? lun ? 194sd* at scsibus? target ? lun ?
191 195
192#sdhc* at cpunode? # sdmmc 196#sdhc* at cpunode? # sdmmc
193#sdmmc* at sdhc? # SD/MMC bus 197#sdmmc* at sdhc? # SD/MMC bus
194#ld* at sdmmc? 198#ld* at sdmmc?
195 199
196#siisata* at pci? dev ? function ? 200#siisata* at pci? dev ? function ?
197#atabus* at siisata? channel ? 201#atabus* at siisata? channel ?

File Added: src/sys/arch/mips/conf/files.ralink
#	$NetBSD: files.ralink,v 1.2 2011/07/28 15:38:48 matt Exp $

file	arch/mips/ralink/ralink_intr.c
file	arch/mips/ralink/ralink_bus.c

# Ralink Watchdog Driver
defparam rwdog.h				RA_WDOG_DEFAULT_PERIOD
defparam rwdog.h				RA_WDOG_DEFAULT_MODE
device	rwdog: sysmon_wdog
attach	rwdog at mainbus
file	arch/mips/ralink/ralink_wdog.c		rwdog

# On-chip UART device as generic com
attach	com at mainbus with ralink_com
file	arch/mips/ralink/ralink_com.c		ralink_com
options COM_REGMAP

# Ralink GPIO Controller
device	rgpio: gpiobus
attach	rgpio at mainbus
file	arch/mips/ralink/ralink_gpio.c		rgpio

# Ralink I2C Controller
device	ri2c: i2cbus
attach	ri2c at mainbus
file	arch/mips/ralink/ralink_i2c.c		ri2c

# USB OHCI Host Controller
attach	ohci at mainbus with ralink_ohci
file	arch/mips/ralink/ralink_ohci.c		ralink_ohci

# USB EHCI Host Controller
attach	ehci at mainbus with ralink_ehci
file	arch/mips/ralink/ralink_ehci.c		ralink_ehci

# Ralink Ethernet Controller
device	reth: ether, ifnet, arp, mii
attach	reth at mainbus
file	arch/mips/ralink/ralink_eth.c		reth

File Added: src/sys/arch/mips/ralink/ralink_bus.c
/*	$NetBSD: ralink_bus.c,v 1.2 2011/07/28 15:38:49 matt Exp $	*/
/*-
 * Copyright (c) 2011 CradlePoint Technology, Inc.
 * 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, 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 CRADLEPOINT TECHNOLOGY, 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 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.
 */
/*
 * Copyright (c) 2006 Urbana-Champaign Independent Media Center.
 * Copyright (c) 2006 Garrett D'Amore.
 * All rights reserved.
 *
 * This code was written by Garrett D'Amore for the Champaign-Urbana
 * Community Wireless Network 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.
 * 3. All advertising materials mentioning features or use of this
 *    software must display the following acknowledgements:
 *      This product includes software developed by the Urbana-Champaign
 *      Independent Media Center.
 *	This product includes software developed by Garrett D'Amore.
 * 4. Urbana-Champaign Independent Media Center's name and Garrett
 *    D'Amore's name may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE URBANA-CHAMPAIGN INDEPENDENT
 * MEDIA CENTER AND GARRETT D'AMORE ``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 URBANA-CHAMPAIGN INDEPENDENT
 * MEDIA CENTER OR GARRETT D'AMORE 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 "locators.h"

#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ralink_bus.c,v 1.2 2011/07/28 15:38:49 matt Exp $");
#define	_MIPS_BUS_DMA_PRIVATE

#include <sys/param.h>
#include <sys/bus.h>
#include <sys/device.h>
#include <sys/extent.h>
#include <sys/malloc.h>
#include <sys/systm.h>

#include <mips/ralink/ralink_reg.h>
#include <mips/ralink/ralink_var.h>

static void ra_bus_bus_mem_init(bus_space_tag_t, void *);

struct mips_bus_space	ra_bus_memt;
struct mips_bus_dma_tag	ra_bus_dmat = {
	._dmamap_ops = _BUS_DMAMAP_OPS_INITIALIZER,
	._dmamem_ops = _BUS_DMAMEM_OPS_INITIALIZER,
	._dmatag_ops = _BUS_DMATAG_OPS_INITIALIZER,
};

void
ra_bus_init(void)
{
	ra_bus_bus_mem_init(&ra_bus_memt, NULL);
}

/*
 * CPU memory/register stuff
 *  defines ra_bus_bus_mem_init, which encompasses all of memory
 */

#define CHIP			ra_bus
#define CHIP_MEM		/* defined */
#define CHIP_W1_BUS_START(v)	0x00000000UL
#define CHIP_W1_BUS_END(v)	0x1fffffffUL
#define CHIP_W1_SYS_START(v)	CHIP_W1_BUS_START(v)
#define CHIP_W1_SYS_END(v)	CHIP_W1_BUS_END(v)

#include <mips/mips/bus_space_alignstride_chipdep.c>

File Added: src/sys/arch/mips/ralink/ralink_com.c
/*	$NetBSD: ralink_com.c,v 1.2 2011/07/28 15:38:49 matt Exp $	*/
/*-
 * Copyright (c) 2011 CradlePoint Technology, Inc.
 * 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, 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 CRADLEPOINT TECHNOLOGY, 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 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.
 */

/*-
 * Copyright (c) 2006 Urbana-Champaign Independent Media Center.
 * Copyright (c) 2006 Garrett D'Amore.
 * All rights reserved.
 *
 * Portions of this code were written by Garrett D'Amore for the
 * Champaign-Urbana Community Wireless Network 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.
 * 3. All advertising materials mentioning features or use of this
 *    software must display the following acknowledgements:
 *      This product includes software developed by the Urbana-Champaign
 *      Independent Media Center.
 *    This product includes software developed by Garrett D'Amore.
 * 4. Urbana-Champaign Independent Media Center's name and Garrett
 *    D'Amore's name may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE URBANA-CHAMPAIGN INDEPENDENT
 * MEDIA CENTER AND GARRETT D'AMORE ``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 URBANA-CHAMPAIGN INDEPENDENT
 * MEDIA CENTER OR GARRETT D'AMORE 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) 1998 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by Charles M. Hannum.
 *
 * 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) 1991 The Regents of the University of California.
 * 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, 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.
 * 3. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
 *
 *    @(#)com.c    7.5 (Berkeley) 5/16/91
 */

/* ralink_com.c -- Ralink 3052 uart console driver */

#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ralink_com.c,v 1.2 2011/07/28 15:38:49 matt Exp $");

#include <sys/param.h>
#include <sys/bus.h>
#include <sys/device.h>
#include <sys/kernel.h>
#include <sys/systm.h>
#include <sys/tty.h>
#include <sys/termios.h>
#include <sys/ttydefaults.h>

#include <dev/cons.h>
#include <dev/ic/comreg.h>
#include <dev/ic/comvar.h>

#include <mips/cpuregs.h>

#include <mips/ralink/ralink_reg.h>
#include <mips/ralink/ralink_var.h>

#include "opt_com.h"

struct ralink_com_softc {
    struct com_softc sc_com;
    void *           sc_ih;
};

static int ralink_com_match(device_t, cfdata_t , void *);
static void ralink_com_attach(device_t, device_t, void *);
static void ralink_com_initmap(struct com_regs *regsp);

CFATTACH_DECL_NEW(ralink_com, sizeof(struct ralink_com_softc),
	ralink_com_match, ralink_com_attach, NULL, NULL);

#define CONMODE	\
	((TTYDEF_CFLAG & ~(CSIZE | CSTOPB | PARENB)) | CS8) /* 8N1 */

#ifndef COM_REGMAP
#error  COM_REGMAP not defined!
#endif

static inline uint32_t
sysctl_read(const u_int offset)
{
	return *RA_IOREG_VADDR(RA_SYSCTL_BASE, offset);
}

static inline void
sysctl_write(const u_int offset, uint32_t val)
{
	*RA_IOREG_VADDR(RA_SYSCTL_BASE, offset) = val;
}

static inline uint32_t
uart_read(const u_int offset)
{
	return *RA_IOREG_VADDR(RA_UART_LITE_BASE, offset);
}

static inline void
uart_write(const u_int offset, const uint32_t val)
{
	*RA_IOREG_VADDR(RA_UART_LITE_BASE, offset) = val;
}


int
ralink_com_match(device_t parent, cfdata_t cf, void *aux)
{
	if (cn_tab == NULL || cn_tab->cn_pri < CN_NORMAL) {
		printf("NULL console set, don't install ourselves "
			"(of course this shouldn't print)");
		return 0;
	}

	/*
	 * If we got this far, assume we want to install it as the console.
	 * No need to probe. Future possibilities include checking to see if it 
	 * is console or KGDB but now it is our only console method if we aren't
	 * forcing a null console
	 */
	return 1;
}

void
ralink_com_attach(device_t parent, device_t self, void *aux)
{
	const struct mainbus_attach_args *ma = aux;
	struct ralink_com_softc * const rtsc = device_private(self);
	struct com_softc * const sc = &rtsc->sc_com;
	bus_space_handle_t ioh;
	int error;

	if ((error = bus_space_map(ma->ma_memt, RA_UART_LITE_BASE,
	    0x1000, 0, &ioh)) != 0) {
		aprint_error(": can't map registers, error=%d\n", error);
		return;
	}

	COM_INIT_REGS(sc->sc_regs, ma->ma_memt, ioh, RA_UART_LITE_BASE);
	sc->sc_dev = self;
	sc->sc_frequency = RA_UART_FREQ;
	sc->sc_regs.cr_nports = 0x1000;
	sc->sc_type = COM_TYPE_AU1x00;
	sc->enabled = 1;

	ralink_com_initmap(&sc->sc_regs);

	rtsc->sc_ih = ra_intr_establish(RA_IRQ_UARTL, comintr, sc, 1);

	com_attach_subr(sc);
}

static void
ralink_com_initmap(struct com_regs *regsp)
{
	regsp->cr_map[COM_REG_RXDATA] = RA_UART_RBR;
	regsp->cr_map[COM_REG_TXDATA] = RA_UART_TBR;
	regsp->cr_map[COM_REG_DLBL]   = RA_UART_DLL;
	regsp->cr_map[COM_REG_IER]    = RA_UART_IER;
	regsp->cr_map[COM_REG_IIR]    = RA_UART_IIR;
	regsp->cr_map[COM_REG_FIFO]   = RA_UART_FCR;
	regsp->cr_map[COM_REG_LCR]    = RA_UART_LCR;
	regsp->cr_map[COM_REG_MCR]    = RA_UART_MCR;
	regsp->cr_map[COM_REG_LSR]    = RA_UART_LSR;
	regsp->cr_map[COM_REG_MSR]    = RA_UART_MSR;
}

void
ralink_com_early(int silent) 
{
	struct com_regs regs;
	uint32_t r;
	int error;

	/* reset */
	r = sysctl_read(RA_SYSCTL_RST);
	r |= RST_UARTL;
	sysctl_write(RA_SYSCTL_RST, r);
	r ^= RST_UARTL;
	sysctl_write(RA_SYSCTL_RST, r);

	if (silent) {
		/*
		 * put us in PIO mode,
		 * effectively tri-stating the UARTL block
		 */
		r = sysctl_read(RA_SYSCTL_GPIOMODE);
		r |= GPIOMODE_UARTL;
		sysctl_write(RA_SYSCTL_GPIOMODE, r);
	} else {
		/* make sure we are in UART mode */
		r = sysctl_read(RA_SYSCTL_GPIOMODE);
		r &= ~GPIOMODE_UARTL;
		sysctl_write(RA_SYSCTL_GPIOMODE, r);
	}

	uart_write(RA_UART_IER, 0);		/* disable interrupts */
	uart_write(RA_UART_FCR, 0);		/* disable fifos */

	/* set baud rate */
	uart_write(RA_UART_LCR,
		UART_LCR_WLS0 | UART_LCR_WLS1 | UART_LCR_DLAB);
	uart_write(RA_UART_DLL,
		(RA_UART_FREQ / RA_SERIAL_CLKDIV / RA_BAUDRATE)
			& 0xffff);
	uart_write(RA_UART_LCR,
		UART_LCR_WLS0 | UART_LCR_WLS1);

	regs.cr_iot = &ra_bus_memt;
	regs.cr_iobase = RA_UART_LITE_BASE;
	regs.cr_nports = 0x1000;
	ralink_com_initmap(&regs);

	if ((error = bus_space_map(regs.cr_iot, regs.cr_iobase, regs.cr_nports,
	    0, &regs.cr_ioh)) != 0) {
		return;
	}

	/* Ralink UART has a 16-bit rate latch (like the AU1x00) */
	comcnattach1(&regs, RA_BAUDRATE, RA_UART_FREQ,
		COM_TYPE_AU1x00, CONMODE);
}

File Added: src/sys/arch/mips/ralink/ralink_debug.h
/*	$NetBSD: ralink_debug.h,v 1.2 2011/07/28 15:38:49 matt Exp $	*/
/*-
 * Copyright (c) 2011 CradlePoint Technology, Inc.
 * 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, 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 CRADLEPOINT TECHNOLOGY, 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 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.
 */

#ifndef _RALINK_DEBUG_H_
#define _RALINK_DEBUG_H_

/* Co-locate some debug routines to help keep the code clean.
 *  #define one or more ENABLE_RALINK_DEBUG_xxxx macros before including
 *  this file to turn on macros.  If none are defined the debug code
 *  won't be compiled in.
 */ 

/*
 * High-level debug compile flag.  If this isn't defined, this is
 *  a release build.
 */

/* Debugging options */
#ifndef ENABLE_RALINK_DEBUG_ERROR
 #define ENABLE_RALINK_DEBUG_ERROR 0
#endif
#ifndef ENABLE_RALINK_DEBUG_FUNC
 #define ENABLE_RALINK_DEBUG_FUNC  0
#endif
#ifndef ENABLE_RALINK_DEBUG_MISC
 #define ENABLE_RALINK_DEBUG_MISC  0
#endif
#ifndef ENABLE_RALINK_DEBUG_INFO
 #define ENABLE_RALINK_DEBUG_INFO  0
#endif
#ifndef ENABLE_RALINK_DEBUG_REG
 #define ENABLE_RALINK_DEBUG_REG   0
#endif
/* don't check anything in with this option.  Just use this if you want to
 * force a specific statement and the above options don't give you fine enough
 * control.
 */
#ifndef ENABLE_RALINK_DEBUG_FORCE
 #define ENABLE_RALINK_DEBUG_FORCE   0
#endif

#define RALINK_DEBUG_ERROR ((ENABLE_RALINK_DEBUG_ERROR ? 1 : 0) << 0)
#define RALINK_DEBUG_MISC  ((ENABLE_RALINK_DEBUG_MISC  ? 1 : 0) << 1)
#define RALINK_DEBUG_FUNC  ((ENABLE_RALINK_DEBUG_FUNC  ? 1 : 0) << 2)
#define RALINK_DEBUG_INFO  ((ENABLE_RALINK_DEBUG_INFO  ? 1 : 0) << 3)
#define RALINK_DEBUG_REG   ((ENABLE_RALINK_DEBUG_REG   ? 1 : 0) << 4)
#define RALINK_DEBUG_FORCE ((ENABLE_RALINK_DEBUG_FORCE ? 1 : 0) << 5)

#ifndef RALINK_DEBUG_ALL
#define RALINK_DEBUG_ALL	( RALINK_DEBUG_ERROR | RALINK_DEBUG_MISC | RALINK_DEBUG_FUNC | \
			  RALINK_DEBUG_INFO | RALINK_DEBUG_REG | RALINK_DEBUG_FORCE )
#endif

/*
 * RALINK_DEBUG_0 is used instead of:
 *
 * #if 0
 * 	RALINK_DEBUG(x, blah);
 * #endif
 *
 * in order to preserve the if'ed-out prints, without the clutter;
 * alternatively, just delete them and this macro
 */
#define RALINK_DEBUG_0(n, args...)	do { } while (0)

#ifdef CPDEBUG

#if RALINK_DEBUG_ALL > 0
#define RALINK_DEBUG(n, args...)		\
	do {				\
		if (RALINK_DEBUG_ALL & (n)) \
			printf(args);	\
	} while (0)
#else
#define RALINK_DEBUG(n, args...)   do { } while (0)
#endif 

/* helper so we don't have to retype a bunch of times */
#define RALINK_DEBUG_FUNC_ENTRY()	\
		RALINK_DEBUG(RALINK_DEBUG_FUNC, "%s() entry\n", __FUNCTION__)
#define RALINK_DEBUG_FUNC_EXIT()	\
		RALINK_DEBUG(RALINK_DEBUG_FUNC, "%s() exit\n", __FUNCTION__)

#else	/* DEBUG not defined (release build) */

#define RALINK_DEBUG(n, args...)
#define RALINK_DEBUG_FUNC_ENTRY()
#define RALINK_DEBUG_FUNC_EXIT()

#endif	/* DEBUG defined */

#endif	/* _RALINK_DEBUG_H_ */

File Added: src/sys/arch/mips/ralink/ralink_ehci.c
/*	$NetBSD: ralink_ehci.c,v 1.2 2011/07/28 15:38:49 matt Exp $	*/
/*-
 * Copyright (c) 2011 CradlePoint Technology, Inc.
 * 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, 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 CRADLEPOINT TECHNOLOGY, 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 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.
 */

/* ralink_ehci.c -- Ralink EHCI USB Driver */

#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ralink_ehci.c,v 1.2 2011/07/28 15:38:49 matt Exp $");

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

#include <dev/usb/usb.h>
#include <dev/usb/usbdi.h>
#include <dev/usb/usbdivar.h>
#include <dev/usb/usb_mem.h>

#include <dev/usb/ehcireg.h>
#include <dev/usb/ehcivar.h>

#include <mips/ralink/ralink_usbhcvar.h>

#include <mips/ralink/ralink_var.h>
#include <mips/ralink/ralink_reg.h>

#define RT3XXX_EHCI_BASE 	0x101c0000
#define RT3XXX_BLOCK_SIZE	0x1000

struct ralink_ehci_softc {
	struct ehci_softc	sc_ehci;
	void			*sc_ih;
};

static int  ralink_ehci_match(device_t, cfdata_t, void *);
static void ralink_ehci_attach(device_t, device_t, void *);
static int  ralink_ehci_detach(device_t, int);

CFATTACH_DECL2_NEW(ralink_ehci, sizeof(struct ralink_ehci_softc),
	ralink_ehci_match, ralink_ehci_attach, ralink_ehci_detach,
	ehci_activate, NULL, ehci_childdet);

static TAILQ_HEAD(, ralink_usb_hc) ralink_usb_alldevs =
	TAILQ_HEAD_INITIALIZER(ralink_usb_alldevs);

#if 0
struct usb_hc_alldevs ralink_usb_alldevs = TAILQ_HEAD_INITIALIZER(ralink_usb_alldevs);
#endif

/*
 * ralink_ehci_match
 */
static int
ralink_ehci_match(device_t parent, cfdata_t cf, void *aux)
{

	return 1;
}

/*
 * ralink_ehci_attach
 */
static void
ralink_ehci_attach(device_t parent, device_t self, void *aux)
{
	struct ralink_ehci_softc * const sc = device_private(self);
	const struct mainbus_attach_args *ma = aux;
	struct ralink_usb_hc *ruh;
	uint32_t r;
	bus_space_handle_t sysctl_memh;
	usbd_status status;
	int error;
#ifdef RALINK_EHCI_DEBUG
	const char *const devname = device_xname(self);
#endif

	aprint_naive(": EHCI USB controller\n");
	aprint_normal(": EHCI USB controller\n");

	sc->sc_ehci.sc_dev = self;
	sc->sc_ehci.sc_bus.hci_private = sc;
	sc->sc_ehci.iot = ma->ma_memt;
	sc->sc_ehci.sc_bus.dmatag = ma->ma_dmat;

	/* Map Sysctl registers */
	if (((error = bus_space_map(ma->ma_memt, RA_SYSCTL_BASE, 0x10000,
	    0, &sysctl_memh) != 0)) != 0) {
		aprint_error_dev(self, "can't map Sysctl registers, "
			"error=%d\n", error);
		return;
	}

	/* The USB block defaults PHY0 to device mode, change to host mode */
	r = bus_space_read_4(ma->ma_memt, sysctl_memh, RA_SYSCTL_CFG1);
	r |= (1 << 10);
	bus_space_write_4(ma->ma_memt, sysctl_memh, RA_SYSCTL_CFG1, r);

	/* done with Sysctl regs */
	bus_space_unmap(ma->ma_memt, sysctl_memh, 0x10000);

	/* Map EHCI registers */
	if ((error = bus_space_map(sc->sc_ehci.iot, RT3XXX_EHCI_BASE,
	    RT3XXX_BLOCK_SIZE, 0, &sc->sc_ehci.ioh)) != 0) {
		aprint_error_dev(self, "can't map EHCI registers, "
			"error=%d\n", error);
		return;
	}

	sc->sc_ehci.sc_size = RT3XXX_BLOCK_SIZE;
	sc->sc_ehci.sc_bus.usbrev = USBREV_2_0;

#ifdef RALINK_EHCI_DEBUG
	printf("%s sc: %p ma: %p\n", devname, sc, ma);
	printf("%s memt: %p dmat: %p\n", devname, ma->ma_memt, ma->ma_dmat);
	printf("%s: EHCI HCCAPBASE=0x%x\n", devname,
		EREAD4(&sc->sc_ehci, EHCI_CAPLENGTH));
	printf("%s: EHCI HCSPARAMS=0x%x\n", devname,
		EREAD4(&sc->sc_ehci, EHCI_HCSPARAMS));
	printf("%s: EHCI HCCPARAMS=0x%x\n", devname,
		EREAD4(&sc->sc_ehci, EHCI_HCCPARAMS));
	printf("%s: EHCI HCSP_PORTROUTE=0x%x\n", devname,
		EREAD4(&sc->sc_ehci, EHCI_HCSP_PORTROUTE));
#endif

	/* Disable EHCI interrupts. */
	sc->sc_ehci.sc_offs = EREAD1(&sc->sc_ehci, EHCI_CAPLENGTH);
	EOWRITE2(&sc->sc_ehci, EHCI_USBINTR, 0);

#ifdef RALINK_EHCI_DEBUG
	printf("%s: EHCI USBCMD=0x%x\n", devname,
		EOREAD4(&sc->sc_ehci, EHCI_USBCMD));
	printf("%s: EHCI USBSTS=0x%x\n", devname,
		EOREAD4(&sc->sc_ehci, EHCI_USBSTS));
	printf("%s: EHCI USBINTR=0x%x\n", devname,
		EOREAD4(&sc->sc_ehci, EHCI_USBINTR));
#endif

	/* Establish the MIPS level interrupt */
	sc->sc_ih = ra_intr_establish(RA_IRQ_USB, ehci_intr, sc, 1);
	if (sc->sc_ih == NULL) {
		aprint_error_dev(self, "unable to establish irq %d\n",
			RA_IRQ_USB);
		goto fail_0;
	}

	/*
	 * Find companion controllers.  According to the spec they always
	 * have lower function numbers so they should be enumerated already.
	 */
	int ncomp = 0;
	TAILQ_FOREACH(ruh, &ralink_usb_alldevs, next) {
		aprint_normal_dev(self, "companion %s\n",
			device_xname(ruh->usb));
		sc->sc_ehci.sc_comps[ncomp++] = ruh->usb;
		if (ncomp >= EHCI_COMPANION_MAX)
			break;
	}
	sc->sc_ehci.sc_ncomp = ncomp;

	/* set vendor for root hub descriptor. */
	sc->sc_ehci.sc_id_vendor = 0x1814;	/* XXX */
	strlcpy(sc->sc_ehci.sc_vendor, "Ralink", sizeof(sc->sc_ehci.sc_vendor));

	/* Initialize EHCI */
	status = ehci_init(&sc->sc_ehci);
	if (status != USBD_NORMAL_COMPLETION) {
		aprint_error_dev(self, "init failed, error=%d\n", status);
		goto fail_1;
	}

	if (!pmf_device_register1(self, ehci_suspend, ehci_resume,
	    ehci_shutdown))
		aprint_error_dev(self, "couldn't establish power handler\n");

	/* Attach usb device. */
	sc->sc_ehci.sc_child = config_found(self, &sc->sc_ehci.sc_bus,
		usbctlprint);

	return;

 fail_1:
	ra_intr_disestablish(sc->sc_ih);
	sc->sc_ih = NULL;
 fail_0:
	bus_space_unmap(sc->sc_ehci.iot, sc->sc_ehci.ioh, sc->sc_ehci.sc_size);
	sc->sc_ehci.sc_size = 0;
}

static int
ralink_ehci_detach(device_t self, int flags)
{
	struct ralink_ehci_softc * const sc = device_private(self);
	int rv;

	pmf_device_deregister(self);

	rv = ehci_detach(&sc->sc_ehci, flags);
	if (rv)
		return rv;

	if (sc->sc_ih != NULL) {
		ra_intr_disestablish(sc->sc_ih);
		sc->sc_ih = NULL;
	}

	if (sc->sc_ehci.sc_size != 0) {
		bus_space_unmap(sc->sc_ehci.iot, sc->sc_ehci.ioh,
			sc->sc_ehci.sc_size);
		sc->sc_ehci.sc_size = 0;
	}

	return 0;
}

void
ralink_usb_hc_add(struct ralink_usb_hc *ruh, device_t usbp)
{
	TAILQ_INSERT_TAIL(&ralink_usb_alldevs, ruh, next);
	ruh->usb = usbp;
}

void
ralink_usb_hc_rem(struct ralink_usb_hc *ruh)
{
	TAILQ_REMOVE(&ralink_usb_alldevs, ruh, next);
}

File Added: src/sys/arch/mips/ralink/ralink_eth.c
/*	$NetBSD: ralink_eth.c,v 1.2 2011/07/28 15:38:49 matt Exp $	*/
/*-
 * Copyright (c) 2011 CradlePoint Technology, Inc.
 * 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, 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 CRADLEPOINT TECHNOLOGY, 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 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.
 */

/* ralink_eth.c -- Ralink Ethernet Driver */

#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ralink_eth.c,v 1.2 2011/07/28 15:38:49 matt Exp $");

#include <sys/param.h>
#include <sys/callout.h>
#include <sys/device.h>
#include <sys/endian.h>
#include <sys/errno.h>
#include <sys/ioctl.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/socket.h>
#include <sys/systm.h>

#include <uvm/uvm_extern.h>

#include <net/if.h>
#include <net/if_dl.h>
#include <net/if_media.h>
#include <net/if_ether.h>
#include <net/if_vlanvar.h>

#include <net/bpf.h>

#include <machine/bus.h>
#include <machine/intr.h>

#include <dev/mii/mii.h>
#include <dev/mii/miivar.h>
#include <dev/mii/mii_bitbang.h>

#include <mips/ralink/ralink_var.h>
#include <mips/ralink/ralink_reg.h>
#if 0
#define CPDEBUG				/* XXX TMP DEBUG FIXME */
#define RALINK_ETH_DEBUG			/* XXX TMP DEBUG FIXME */
#define ENABLE_RALINK_DEBUG_ERROR 1
#define ENABLE_RALINK_DEBUG_MISC  1
#define ENABLE_RALINK_DEBUG_INFO  1
#define ENABLE_RALINK_DEBUG_FORCE 1
#define ENABLE_RALINK_DEBUG_REG 1
#endif
#include <mips/ralink/ralink_debug.h>


/* PDMA RX Descriptor Format */
struct ralink_rx_desc {
	uint32_t data_ptr;
	uint32_t rxd_info1;
#define RXD_LEN1(x)  (((x) >> 0) & 0x3fff)
#define RXD_LAST1    (1 << 14)
#define RXD_LEN0(x)  (((x) >> 16) & 0x3fff)
#define RXD_LAST0    (1 << 30)
#define RXD_DDONE    (1 << 31)
	uint32_t unused;
	uint32_t rxd_info2;
#define RXD_FOE(x)   (((x) >> 0) & 0x3fff)
#define RXD_FVLD     (1 << 14)
#define RXD_INFO(x)  (((x) >> 16) & 0xff)
#define RXD_PORT(x)  (((x) >> 24) & 0x7)
#define RXD_INFO_CPU (1 << 27)
#define RXD_L4_FAIL  (1 << 28)
#define RXD_IP_FAIL  (1 << 29)
#define RXD_L4_VLD   (1 << 30)
#define RXD_IP_VLD   (1 << 31)
};

/* PDMA RX Descriptor Format */
struct ralink_tx_desc {
	uint32_t data_ptr0;
	uint32_t txd_info1;
#define TXD_LEN1(x)  (((x) & 0x3fff) << 0)
#define TXD_LAST1    (1 << 14)
#define TXD_BURST    (1 << 15)
#define TXD_LEN0(x)  (((x) & 0x3fff) << 16)
#define TXD_LAST0    (1 << 30)
#define TXD_DDONE    (1 << 31)
	uint32_t data_ptr1;
	uint32_t txd_info2;
#define TXD_VIDX(x)  (((x) & 0xf) << 0)
#define TXD_VPRI(x)  (((x) & 0x7) << 4)
#define TXD_VEN      (1 << 7)
#define TXD_SIDX(x)  (((x) & 0xf) << 8)
#define TXD_SEN(x)   (1 << 13)
#define TXD_QN(x)    (((x) & 0x7) << 16)
#define TXD_PN(x)    (((x) & 0x7) << 24)
#define  TXD_PN_CPU   0
#define  TXD_PN_GDMA1 1
#define  TXD_PN_GDMA2 2
#define TXD_TCP_EN   (1 << 29)
#define TXD_UDP_EN   (1 << 30)
#define TXD_IP_EN    (1 << 31)
};

/* TODO:
 * try to scale number of descriptors swith size of memory
 * these numbers may have a significant impact on performance/memory/mbuf usage
 */
#if RTMEMSIZE >= 64
#define RALINK_ETH_NUM_RX_DESC 256
#define RALINK_ETH_NUM_TX_DESC 256
#elif  RTMEMSIZE >= 32
#define RALINK_ETH_NUM_RX_DESC 64
#define RALINK_ETH_NUM_TX_DESC 64
#else
#error RTMEMSIZE invalid	/* XXX */
#endif
/* maximum segments per packet */
#define RALINK_ETH_MAX_TX_SEGS 1

/* define a struct for ease of dma memory allocation */
struct ralink_descs {
	struct ralink_rx_desc rxdesc[RALINK_ETH_NUM_RX_DESC];
	struct ralink_tx_desc txdesc[RALINK_ETH_NUM_TX_DESC];
};

/* Software state for transmit jobs. */
struct ralink_eth_txstate {
	struct mbuf *txs_mbuf;		/* head of our mbuf chain */
	bus_dmamap_t txs_dmamap;	/* our DMA map */
	int txs_idx;			/* the index in txdesc ring that */
					/*  this state is tracking */
	SIMPLEQ_ENTRY(ralink_eth_txstate) txs_q;
};

SIMPLEQ_HEAD(ralink_eth_txsq, ralink_eth_txstate);

/*
 * Software state for receive jobs.
 */
struct ralink_eth_rxstate {
	struct mbuf *rxs_mbuf;		/* head of our mbuf chain */
	bus_dmamap_t rxs_dmamap;	/* our DMA map */
};

typedef struct ralink_eth_softc {
	device_t sc_dev;		/* generic device information */
	bus_space_tag_t sc_memt;	/* bus space tag */
	bus_space_handle_t sc_sy_memh;	/* handle at SYSCTL_BASE */
	bus_space_handle_t sc_fe_memh;	/* handle at FRAME_ENGINE_BASE */
	bus_space_handle_t sc_sw_memh;	/* handle at ETH_SW_BASE */
	int sc_sy_size;			/* size of Sysctl regs space */
	int sc_fe_size;			/* size of Frame Engine regs space */
	int sc_sw_size;			/* size of Ether Switch regs space */
	bus_dma_tag_t sc_dmat;		/* bus DMA tag */
	void *sc_ih;			/* interrupt handle */

	/* tx/rx dma mapping */
	bus_dma_segment_t sc_dseg;
	int sc_ndseg;
	bus_dmamap_t sc_pdmamap;	/* PDMA DMA map */
#define sc_pdma sc_pdmamap->dm_segs[0].ds_addr

	struct ralink_descs *sc_descs;
#define sc_rxdesc sc_descs->rxdesc
#define sc_txdesc sc_descs->txdesc

#define RALINK_MIN_BUF 64
	char ralink_zero_buf[RALINK_MIN_BUF];

	struct ralink_eth_txstate sc_txstate[RALINK_ETH_NUM_TX_DESC];
	struct ralink_eth_rxstate sc_rxstate[RALINK_ETH_NUM_RX_DESC];

	struct ralink_eth_txsq sc_txfreeq;	/* free Tx descsofts */
	struct ralink_eth_txsq sc_txdirtyq;	/* dirty Tx descsofts */

	struct ethercom sc_ethercom;		/* ethernet common data */
	u_int sc_pending_tx;

	/* mii */
	struct mii_data sc_mii;
	struct callout sc_tick_callout;

	struct evcnt sc_evcnt_spurious_intr;
	struct evcnt sc_evcnt_rxintr;
	struct evcnt sc_evcnt_rxintr_skip_len;
	struct evcnt sc_evcnt_rxintr_skip_tag_none;
	struct evcnt sc_evcnt_rxintr_skip_tag_inval;
	struct evcnt sc_evcnt_rxintr_skip_inact;
	struct evcnt sc_evcnt_txintr;
	struct evcnt sc_evcnt_input;
	struct evcnt sc_evcnt_output;
	struct evcnt sc_evcnt_watchdog;
	struct evcnt sc_evcnt_wd_reactivate;
	struct evcnt sc_evcnt_wd_tx;
	struct evcnt sc_evcnt_wd_spurious;
	struct evcnt sc_evcnt_add_rxbuf_hdr_fail;
	struct evcnt sc_evcnt_add_rxbuf_mcl_fail;
} ralink_eth_softc_t;

/* alignment so the IP header is aligned */
#define RALINK_ETHER_ALIGN 2

/* device functions */
static int  ralink_eth_match(device_t, cfdata_t, void *);
static void ralink_eth_attach(device_t, device_t, void *);
static int  ralink_eth_detach(device_t, int);
static int  ralink_eth_activate(device_t, enum devact);

/* local driver functions */
static void ralink_eth_hw_init(ralink_eth_softc_t *);
static int  ralink_eth_intr(void *);
static void ralink_eth_reset(ralink_eth_softc_t *);
static void ralink_eth_rxintr(ralink_eth_softc_t *);
static void ralink_eth_txintr(ralink_eth_softc_t *);

/* partition functions */
static int  ralink_eth_enable(ralink_eth_softc_t *);
static void ralink_eth_disable(ralink_eth_softc_t *);

/* ifnet functions */
static int  ralink_eth_init(struct ifnet *);
static void ralink_eth_rxdrain(ralink_eth_softc_t *);
static void ralink_eth_stop(struct ifnet *, int);
static int  ralink_eth_add_rxbuf(ralink_eth_softc_t *, int);
static void ralink_eth_start(struct ifnet *);
static void ralink_eth_watchdog(struct ifnet *);
static int  ralink_eth_ioctl(struct ifnet *, u_long, void *);

/* mii functions */
#if defined(RT3050) || defined(RT3052)
static void ralink_eth_mdio_enable(ralink_eth_softc_t *, bool);
#endif
static void ralink_eth_mii_statchg(device_t);
static void ralink_eth_mii_tick(void *);
static int  ralink_eth_mii_read(device_t, int, int);
static void ralink_eth_mii_write(device_t, int, int, int);

CFATTACH_DECL_NEW(reth, sizeof(struct ralink_eth_softc),
    ralink_eth_match, ralink_eth_attach, ralink_eth_detach, ralink_eth_activate);

static inline uint32_t
sy_read(const ralink_eth_softc_t *sc, const bus_size_t off)
{
	return bus_space_read_4(sc->sc_memt, sc->sc_sy_memh, off);
}

static inline void
sy_write(const ralink_eth_softc_t *sc, const bus_size_t off, const uint32_t val)
{
	bus_space_write_4(sc->sc_memt, sc->sc_sy_memh, off, val);
}

static inline uint32_t
fe_read(const ralink_eth_softc_t *sc, const bus_size_t off)
{
	return bus_space_read_4(sc->sc_memt, sc->sc_fe_memh, off);
}

static inline void
fe_write(const ralink_eth_softc_t *sc, const bus_size_t off, const uint32_t val)
{
	bus_space_write_4(sc->sc_memt, sc->sc_fe_memh, off, val);
}

static inline uint32_t
sw_read(const ralink_eth_softc_t *sc, const bus_size_t off)
{
	return bus_space_read_4(sc->sc_memt, sc->sc_sw_memh, off);
}

static inline void
sw_write(const ralink_eth_softc_t *sc, const bus_size_t off, const uint32_t val)
{
	bus_space_write_4(sc->sc_memt, sc->sc_sw_memh, off, val);
}

/*
 * ralink_eth_match
 */
int
ralink_eth_match(device_t parent, cfdata_t cf, void *aux)
{
	return 1;
}

/*
 * ralink_eth_attach
 */
void
ralink_eth_attach(device_t parent, device_t self, void *aux)
{
	ralink_eth_softc_t * const sc = device_private(self);
	const struct mainbus_attach_args *ma = aux;
	int error;
	int i;

	aprint_naive(": Ralink Ethernet\n");
	aprint_normal(": Ralink Ethernet\n");

	evcnt_attach_dynamic(&sc->sc_evcnt_spurious_intr, EVCNT_TYPE_INTR, NULL,
		device_xname(self), "spurious intr");
	evcnt_attach_dynamic(&sc->sc_evcnt_rxintr, EVCNT_TYPE_INTR, NULL,
		device_xname(self), "rxintr");
	evcnt_attach_dynamic(&sc->sc_evcnt_rxintr_skip_len,
		EVCNT_TYPE_INTR, &sc->sc_evcnt_rxintr,
		device_xname(self), "rxintr skip: no room for VLAN header");
	evcnt_attach_dynamic(&sc->sc_evcnt_rxintr_skip_tag_none,
		EVCNT_TYPE_INTR, &sc->sc_evcnt_rxintr,
		device_xname(self), "rxintr skip: no VLAN tag");
	evcnt_attach_dynamic(&sc->sc_evcnt_rxintr_skip_tag_inval,
		EVCNT_TYPE_INTR, &sc->sc_evcnt_rxintr,
		device_xname(self), "rxintr skip: invalid VLAN tag");
	evcnt_attach_dynamic(&sc->sc_evcnt_rxintr_skip_inact,
		EVCNT_TYPE_INTR, &sc->sc_evcnt_rxintr,
		device_xname(self), "rxintr skip: partition inactive");
	evcnt_attach_dynamic(&sc->sc_evcnt_txintr, EVCNT_TYPE_INTR, NULL,
		device_xname(self), "txintr");
	evcnt_attach_dynamic(&sc->sc_evcnt_input, EVCNT_TYPE_INTR, NULL,
		device_xname(self), "input");
	evcnt_attach_dynamic(&sc->sc_evcnt_output, EVCNT_TYPE_INTR, NULL,
		device_xname(self), "output");
	evcnt_attach_dynamic(&sc->sc_evcnt_watchdog, EVCNT_TYPE_INTR, NULL,
		device_xname(self), "watchdog");
	evcnt_attach_dynamic(&sc->sc_evcnt_wd_tx,
		EVCNT_TYPE_INTR, &sc->sc_evcnt_watchdog,
		device_xname(self), "watchdog TX timeout");
	evcnt_attach_dynamic(&sc->sc_evcnt_wd_spurious,
		EVCNT_TYPE_INTR, &sc->sc_evcnt_watchdog,
		device_xname(self), "watchdog spurious");
	evcnt_attach_dynamic(&sc->sc_evcnt_wd_reactivate,
		EVCNT_TYPE_INTR, &sc->sc_evcnt_watchdog,
		device_xname(self), "watchdog reactivate");
	evcnt_attach_dynamic(&sc->sc_evcnt_add_rxbuf_hdr_fail,
		EVCNT_TYPE_INTR, NULL,
		device_xname(self), "add rxbuf hdr fail");
	evcnt_attach_dynamic(&sc->sc_evcnt_add_rxbuf_mcl_fail,
		EVCNT_TYPE_INTR, NULL,
		device_xname(self), "add rxbuf mcl fail");

	/*
	 * In order to obtain unique initial Ethernet address on a host,
	 * do some randomisation using the current uptime.  It's not meant
	 * for anything but avoiding hard-coding an address.
	 */
	uint8_t enaddr[ETHER_ADDR_LEN] = { 0x00, 0x30, 0x44, 0x00, 0x00, 0x00 };

	sc->sc_dev = self;
	sc->sc_dmat = ma->ma_dmat;
	sc->sc_memt = ma->ma_memt;
	sc->sc_sy_size = 0x10000;
	sc->sc_fe_size = 0x10000;
	sc->sc_sw_size = 0x08000;

	/*
	 * map the registers
	 *
	 * we map the Sysctl, Frame Engine and Ether Switch registers
	 * seperately so we can use the defined register offsets sanely
	 */
	if ((error = bus_space_map(sc->sc_memt, RA_SYSCTL_BASE,
	    sc->sc_sy_size, 0, &sc->sc_sy_memh)) != 0) {
		aprint_error_dev(self, "unable to map Sysctl registers, "
			"error=%d\n", error);
		goto fail_0a;
	}
	if ((error = bus_space_map(sc->sc_memt, RA_FRAME_ENGINE_BASE,
	    sc->sc_fe_size, 0, &sc->sc_fe_memh)) != 0) {
		aprint_error_dev(self, "unable to map Frame Engine registers, "
			"error=%d\n", error);
		goto fail_0b;
	}
	if ((error = bus_space_map(sc->sc_memt, RA_ETH_SW_BASE,
	    sc->sc_sw_size, 0, &sc->sc_sw_memh)) != 0) {
		aprint_error_dev(self, "unable to map Ether Switch registers, "
			"error=%d\n", error);
		goto fail_0c;
	}

	/* Allocate desc structures, and create & load the DMA map for them */
	if ((error = bus_dmamem_alloc(sc->sc_dmat, sizeof(struct ralink_descs),
	    PAGE_SIZE, 0, &sc->sc_dseg, 1, &sc->sc_ndseg, 0)) != 0) {
		aprint_error_dev(self, "unable to allocate transmit descs, "
			"error=%d\n", error);
		goto fail_1;
	}

	if ((error = bus_dmamem_map(sc->sc_dmat, &sc->sc_dseg, sc->sc_ndseg,
	    sizeof(struct ralink_descs), (void **)&sc->sc_descs, BUS_DMA_COHERENT))
	    != 0) {
		aprint_error_dev(self, "unable to map control data, "
			"error=%d\n", error);
		goto fail_2;
	}

	if ((error = bus_dmamap_create(sc->sc_dmat, sizeof(struct ralink_descs), 1,
	    sizeof(struct ralink_descs), 0, 0, &sc->sc_pdmamap)) != 0) {
		aprint_error_dev(self, "unable to create control data DMA map, "
			"error=%d\n", error);
		goto fail_3;
	}

	if ((error = bus_dmamap_load(sc->sc_dmat, sc->sc_pdmamap, sc->sc_descs,
	    sizeof(struct ralink_descs), NULL, 0)) != 0) {
		aprint_error_dev(self, "unable to load control data DMA map, "
			"error=%d\n", error);
		goto fail_4;
	}

	/* Create the transmit buffer DMA maps.  */
	for (i = 0; i < RALINK_ETH_NUM_TX_DESC; i++) {
		if ((error = bus_dmamap_create(sc->sc_dmat, MCLBYTES,
		    RALINK_ETH_MAX_TX_SEGS, MCLBYTES, 0, 0,
		    &sc->sc_txstate[i].txs_dmamap)) != 0) {
			aprint_error_dev(self, "unable to create tx DMA map %d, "
				"error=%d\n", i, error);
			goto fail_5;
		}
	}

	/* Create the receive buffer DMA maps.  */
	for (i = 0; i < RALINK_ETH_NUM_RX_DESC; i++) {
		if ((error = bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1,
		    MCLBYTES, 0, 0, &sc->sc_rxstate[i].rxs_dmamap)) != 0) {
			aprint_error_dev(self, "unable to create rx DMA map %d, "
				"error=%d\n", i, error);
			goto fail_6;
		}
		sc->sc_rxstate[i].rxs_mbuf = NULL;
	}

	/* this is a zero buffer used for zero'ing out short packets */
	memset(sc->ralink_zero_buf, 0, RALINK_MIN_BUF);

	/* setup some address in hardware */
	fe_write(sc, RA_FE_GDMA1_MAC_LSB,
		(enaddr[5] | (enaddr[4] << 8) |
		(enaddr[3] << 16) | (enaddr[2] << 24)));
	fe_write(sc, RA_FE_GDMA1_MAC_MSB,
		(enaddr[1] | (enaddr[0] << 8)));

	/*
	 * iterate through ports
	 *  slickrock must use specific non-linear sequence
	 *  others are linear
	 */
	struct ifnet * const ifp = &sc->sc_ethercom.ec_if;

	strlcpy(ifp->if_xname, device_xname(self), IFNAMSIZ);

	/*
	 * Initialize our media structures.
	 * This may probe the PHY, if present.
	 */
	sc->sc_mii.mii_ifp = ifp;
	sc->sc_mii.mii_readreg = ralink_eth_mii_read;
	sc->sc_mii.mii_writereg = ralink_eth_mii_write;
	sc->sc_mii.mii_statchg = ralink_eth_mii_statchg;
	sc->sc_ethercom.ec_mii = &sc->sc_mii;
	ifmedia_init(&sc->sc_mii.mii_media, 0, ether_mediachange,
		ether_mediastatus);
	mii_attach(sc->sc_dev, &sc->sc_mii, ~0, i, MII_OFFSET_ANY,
		MIIF_FORCEANEG|MIIF_DOPAUSE|MIIF_NOISOLATE);

	if (LIST_EMPTY(&sc->sc_mii.mii_phys)) {
#if 1
		ifmedia_add(&sc->sc_mii.mii_media, IFM_ETHER|IFM_1000_T|
			IFM_FDX|IFM_ETH_RXPAUSE|IFM_ETH_TXPAUSE, 0, NULL);
		ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER|IFM_1000_T|
			IFM_FDX|IFM_ETH_RXPAUSE|IFM_ETH_TXPAUSE);
#else
		ifmedia_add(&sc->sc_mii.mii_media,
			IFM_ETHER|IFM_MANUAL, 0, NULL);
		ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER|IFM_MANUAL);
#endif
	} else {
			/* Ensure we mask ok for the switch multiple phy's */
		ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER|IFM_AUTO);
	}

	ifp->if_softc = sc;
	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
	ifp->if_init = ralink_eth_init;
	ifp->if_start = ralink_eth_start;
	ifp->if_ioctl = ralink_eth_ioctl;
	ifp->if_stop = ralink_eth_stop;
	ifp->if_watchdog = ralink_eth_watchdog;
	IFQ_SET_READY(&ifp->if_snd);

	/* We can support 802.1Q VLAN-sized frames. */
	sc->sc_ethercom.ec_capabilities |= ETHERCAP_VLAN_MTU;

	/* We support IPV4 CRC Offload */
	ifp->if_capabilities |=
		(IFCAP_CSUM_IPv4_Tx | IFCAP_CSUM_IPv4_Rx |
		 IFCAP_CSUM_TCPv4_Tx | IFCAP_CSUM_TCPv4_Rx |
		 IFCAP_CSUM_UDPv4_Tx | IFCAP_CSUM_UDPv4_Rx);

	/* Attach the interface. */
	if_attach(ifp);
	ether_ifattach(ifp, enaddr);

	/* init our mii ticker */
	callout_init(&sc->sc_tick_callout, 0);
	callout_reset(&sc->sc_tick_callout, hz, ralink_eth_mii_tick, sc);

	return;

	/*
	 * Free any resources we've allocated during the failed attach
	 * attempt.  Do this in reverse order and fall through.
	 */
 fail_6:
	for (i = 0; i < RALINK_ETH_NUM_RX_DESC; i++) {
		if (sc->sc_rxstate[i].rxs_dmamap != NULL)
			bus_dmamap_destroy(sc->sc_dmat,
				sc->sc_rxstate[i].rxs_dmamap);
	}
 fail_5:
	for (i = 0; i < RALINK_ETH_NUM_TX_DESC; i++) {
		if (sc->sc_txstate[i].txs_dmamap != NULL)
			bus_dmamap_destroy(sc->sc_dmat,
				sc->sc_txstate[i].txs_dmamap);
	}
	bus_dmamap_unload(sc->sc_dmat, sc->sc_pdmamap);
 fail_4:
	bus_dmamap_destroy(sc->sc_dmat, sc->sc_pdmamap);
 fail_3:
	bus_dmamem_unmap(sc->sc_dmat, (void *)sc->sc_descs,
		sizeof(struct ralink_descs));
 fail_2:
	bus_dmamem_free(sc->sc_dmat, &sc->sc_dseg, sc->sc_ndseg);
 fail_1:
	bus_space_unmap(sc->sc_memt, sc->sc_sw_memh, sc->sc_sw_size);
 fail_0c:
	bus_space_unmap(sc->sc_memt, sc->sc_fe_memh, sc->sc_fe_size);
 fail_0b:
	bus_space_unmap(sc->sc_memt, sc->sc_sy_memh, sc->sc_fe_size);
 fail_0a:
	return;
}

/*
 * ralink_eth_activate:
 *
 *	Handle device activation/deactivation requests.
 */
int
ralink_eth_activate(device_t self, enum devact act)
{
	ralink_eth_softc_t * const sc = device_private(self);
	int error = 0;
	int s;

	s = splnet();
	switch (act) {
	case DVACT_DEACTIVATE:
		if_deactivate(&sc->sc_ethercom.ec_if);
		break;
	}
	splx(s);

	return error;
}

/*
 * ralink_eth_partition_enable
 */
static int
ralink_eth_enable(ralink_eth_softc_t *sc)
{
	RALINK_DEBUG_FUNC_ENTRY();

	if (sc->sc_ih != NULL) {
		RALINK_DEBUG(RALINK_DEBUG_MISC, "%s() already active",
			__func__);
		return EALREADY;
	}

	sc->sc_pending_tx = 0;

	int s = splnet();
	ralink_eth_hw_init(sc);
	sc->sc_ih = ra_intr_establish(RA_IRQ_FENGINE,
		ralink_eth_intr, sc, 1);
	splx(s);
	if (sc->sc_ih == NULL) {
		RALINK_DEBUG(RALINK_DEBUG_ERROR,
			"%s: unable to establish interrupt\n",
			device_xname(sc->sc_dev));
		return EIO;
	}

	return 0;
}

/*
 * ralink_eth_partition_disable
 */
static void
ralink_eth_disable(ralink_eth_softc_t *sc)
{
	RALINK_DEBUG_FUNC_ENTRY();

	int s = splnet();
	ralink_eth_rxdrain(sc);
	ra_intr_disestablish(sc->sc_ih);
	sc->sc_ih = NULL;

	/* stop the mii ticker */
	callout_stop(&sc->sc_tick_callout);

	/* quiesce the block */
	ralink_eth_reset(sc);
	splx(s);
}

/*
 * ralink_eth_detach
 */
static int
ralink_eth_detach(device_t self, int flags)
{
	RALINK_DEBUG_FUNC_ENTRY();
	ralink_eth_softc_t * const sc = device_private(self);
	struct ifnet * const ifp = &sc->sc_ethercom.ec_if;
	struct ralink_eth_rxstate *rxs;
	struct ralink_eth_txstate *txs;
	int i;

	ralink_eth_disable(sc);
	mii_detach(&sc->sc_mii, MII_PHY_ANY, MII_OFFSET_ANY);
	ifmedia_delete_instance(&sc->sc_mii.mii_media, IFM_INST_ANY);
	ether_ifdetach(ifp);
	if_detach(ifp);

	for (i = 0; i < RALINK_ETH_NUM_RX_DESC; i++) {
		rxs = &sc->sc_rxstate[i];
		if (rxs->rxs_mbuf != NULL) {
			bus_dmamap_unload(sc->sc_dmat, rxs->rxs_dmamap);
			m_freem(rxs->rxs_mbuf);
			rxs->rxs_mbuf = NULL;
		}
		bus_dmamap_destroy(sc->sc_dmat, rxs->rxs_dmamap);
	}

	for (i = 0; i < RALINK_ETH_NUM_TX_DESC; i++) {
		txs = &sc->sc_txstate[i];
		if (txs->txs_mbuf != NULL) {
			bus_dmamap_unload(sc->sc_dmat, txs->txs_dmamap);
			m_freem(txs->txs_mbuf);
			txs->txs_mbuf = NULL;
		}
		bus_dmamap_destroy(sc->sc_dmat, txs->txs_dmamap);
	}

	bus_dmamap_unload(sc->sc_dmat, sc->sc_pdmamap);
	bus_dmamap_destroy(sc->sc_dmat, sc->sc_pdmamap);
	bus_dmamem_unmap(sc->sc_dmat, (void *)sc->sc_descs,
		sizeof(struct ralink_descs));
	bus_dmamem_free(sc->sc_dmat, &sc->sc_dseg, sc->sc_ndseg);

	bus_space_unmap(sc->sc_memt, sc->sc_sw_memh, sc->sc_sw_size);
	bus_space_unmap(sc->sc_memt, sc->sc_fe_memh, sc->sc_fe_size);

	return 0;
}

/*
 * ralink_eth_reset
 */
static void
ralink_eth_reset(ralink_eth_softc_t *sc)
{
	RALINK_DEBUG_FUNC_ENTRY();
	uint32_t r;

	/* Reset the frame engine */
	r = sy_read(sc, RA_SYSCTL_RST);
	r |= RST_FE;
	sy_write(sc, RA_SYSCTL_RST, r);
	r ^= RST_FE;
	sy_write(sc, RA_SYSCTL_RST, r);

	/* Wait until the PDMA is quiscent */
	for (;;) {
		r = fe_read(sc, RA_FE_PDMA_GLOBAL_CFG);
		if (r & FE_PDMA_GLOBAL_CFG_RX_DMA_BUSY) {
			aprint_normal_dev(sc->sc_dev, "RX DMA BUSY\n");
			continue;
		}
		if (r & FE_PDMA_GLOBAL_CFG_TX_DMA_BUSY) {
			aprint_normal_dev(sc->sc_dev, "TX DMA BUSY\n");
			continue;
		}
		break;
	}
}

/*
 * ralink_eth_hw_init
 */
static void
ralink_eth_hw_init(ralink_eth_softc_t *sc)
{
	RALINK_DEBUG_FUNC_ENTRY();
	struct ralink_eth_txstate *txs;
	uint32_t r;
	int i;

	/* reset to a known good state */
	ralink_eth_reset(sc);

#if defined(RT3050) || defined(RT3052)
	/* Bring the switch to a sane default state (from linux driver) */
	bus_space_write_4(sc->sc_memt, sc->sc_sw_memh, RA_ETH_SW_SGC2,
		0x00000000);
	bus_space_write_4(sc->sc_memt, sc->sc_sw_memh, RA_ETH_SW_PFC1,
		0x00405555);	/* check VLAN tag on port forward */);
	bus_space_write_4(sc->sc_memt, sc->sc_sw_memh, RA_ETH_SW_VLANI0,
		0x00002001);
	bus_space_write_4(sc->sc_memt, sc->sc_sw_memh, RA_ETH_SW_PVIDC0,
		0x00001002);
	bus_space_write_4(sc->sc_memt, sc->sc_sw_memh, RA_ETH_SW_PVIDC1,
		0x00001001);
	bus_space_write_4(sc->sc_memt, sc->sc_sw_memh, RA_ETH_SW_PVIDC2,
		0x00001001);
	bus_space_write_4(sc->sc_memt, sc->sc_sw_memh, RA_ETH_SW_VMSC0,
		0xffff417e);
	bus_space_write_4(sc->sc_memt, sc->sc_sw_memh, RA_ETH_SW_POC0,
		0x00007f7f);
	bus_space_write_4(sc->sc_memt, sc->sc_sw_memh, RA_ETH_SW_POC2,
		0x00007f3f);
	bus_space_write_4(sc->sc_memt, sc->sc_sw_memh, RA_ETH_SW_FTC2,
		0x00d6500c);
	bus_space_write_4(sc->sc_memt, sc->sc_sw_memh, RA_ETH_SW_SWGC,
		0x0008a301);	/* hashing algorithm=XOR48 */
				/*  aging interval=300sec  */
	bus_space_write_4(sc->sc_memt, sc->sc_sw_memh, RA_ETH_SW_SOCPC,
		0x02404040);
	bus_space_write_4(sc->sc_memt, sc->sc_sw_memh, RA_ETH_SW_FPORT,
		0x3f502b28);	/* Change polling Ext PHY Addr=0x0 */
	bus_space_write_4(sc->sc_memt, sc->sc_sw_memh, RA_ETH_SW_FPA,
		0x00000000);

	/* do some mii magic  TODO: define these registers/bits */
	/* lower down PHY 10Mbps mode power */
	/* select local register */
	ralink_eth_mii_write(&sc->sc_dev, 0, 31, 0x8000);

	for (i=0;i<5;i++){
		/* set TX10 waveform coefficient */
		ralink_eth_mii_write(&sc->sc_dev, i, 26, 0x1601);

		/* set TX100/TX10 AD/DA current bias */
		ralink_eth_mii_write(&sc->sc_dev, i, 29, 0x7058);

		/* set TX100 slew rate control */
		ralink_eth_mii_write(&sc->sc_dev, i, 30, 0x0018);
	}

	/* PHY IOT */

	/* select global register */
	ralink_eth_mii_write(&sc->sc_dev, 0, 31, 0x0);

	/* tune TP_IDL tail and head waveform */
	ralink_eth_mii_write(&sc->sc_dev, 0, 22, 0x052f);

	/* set TX10 signal amplitude threshold to minimum */
	ralink_eth_mii_write(&sc->sc_dev, 0, 17, 0x0fe0);

	/* set squelch amplitude to higher threshold */
	ralink_eth_mii_write(&sc->sc_dev, 0, 18, 0x40ba);

	/* longer TP_IDL tail length */
	ralink_eth_mii_write(&sc->sc_dev, 0, 14, 0x65);

	/* select local register */
	ralink_eth_mii_write(&sc->sc_dev, 0, 31, 0x8000);
#else
	/* GE1 + GigSW */
	fe_write(sc, RA_FE_MDIO_CFG1,
		MDIO_CFG_PHY_ADDR(0x1f) |
		MDIO_CFG_BP_EN |
		MDIO_CFG_FORCE_CFG |
		MDIO_CFG_SPEED(MDIO_CFG_SPEED_1000M) |
		MDIO_CFG_FULL_DUPLEX |
		MDIO_CFG_FC_TX |
		MDIO_CFG_FC_RX |
		MDIO_CFG_TX_CLK_MODE(MDIO_CFG_TX_CLK_MODE_3COM));
#endif

	/*
	 * TODO: QOS - RT3052 has 4 TX queues for QOS,
	 * forgoing for 1 for simplicity
	 */

	/*
	 * Allocate DMA accessible memory for TX/RX descriptor rings
	 */

	/* Initialize the TX queues. */
	SIMPLEQ_INIT(&sc->sc_txfreeq);
	SIMPLEQ_INIT(&sc->sc_txdirtyq);

	/* Initialize the TX descriptor ring. */
	memset(sc->sc_txdesc, 0, sizeof(sc->sc_txdesc));
	for (i = 0; i < RALINK_ETH_NUM_TX_DESC; i++) {

		sc->sc_txdesc[i].txd_info1 = TXD_LAST0 | TXD_DDONE;

		/* setup the freeq as well */
		txs = &sc->sc_txstate[i];
		txs->txs_mbuf = NULL;
		txs->txs_idx = i;
		SIMPLEQ_INSERT_TAIL(&sc->sc_txfreeq, txs, txs_q);
	}

	/*
	 * Flush the TX descriptors
	 *  - TODO: can we just access descriptors via KSEG1
	 *    to avoid the flush?
	 */
	bus_dmamap_sync(sc->sc_dmat, sc->sc_pdmamap,
		(int)&sc->sc_txdesc - (int)sc->sc_descs, sizeof(sc->sc_txdesc),
		BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);

	/* Initialize the RX descriptor ring */
	memset(sc->sc_rxdesc, 0, sizeof(sc->sc_rxdesc));
	for (i = 0; i < RALINK_ETH_NUM_RX_DESC; i++) {
		if (ralink_eth_add_rxbuf(sc, i)) {
			panic("Can't allocate rx mbuf\n");
		}
	}

	/*
	 * Flush the RX descriptors
	 * - TODO: can we just access descriptors via KSEG1
	 *   to avoid the flush?
	 */
	bus_dmamap_sync(sc->sc_dmat, sc->sc_pdmamap,
		(int)&sc->sc_rxdesc - (int)sc->sc_descs, sizeof(sc->sc_rxdesc),
		BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);

	/* Clear the PDMA state */
	r = fe_read(sc, RA_FE_PDMA_GLOBAL_CFG);
	r &= 0xff;
	fe_write(sc, RA_FE_PDMA_GLOBAL_CFG, r);
	(void) fe_read(sc, RA_FE_PDMA_GLOBAL_CFG);

	/* Setup the PDMA VLAN ID's */
	fe_write(sc, RA_FE_VLAN_ID_0001, 0x00010000);
	fe_write(sc, RA_FE_VLAN_ID_0203, 0x00030002);
	fe_write(sc, RA_FE_VLAN_ID_0405, 0x00050004);
	fe_write(sc, RA_FE_VLAN_ID_0607, 0x00070006);
	fe_write(sc, RA_FE_VLAN_ID_0809, 0x00090008);
	fe_write(sc, RA_FE_VLAN_ID_1011, 0x000b000a);
	fe_write(sc, RA_FE_VLAN_ID_1213, 0x000d000c);
	fe_write(sc, RA_FE_VLAN_ID_1415, 0x000f000e);

	/* Give the TX and TX rings to the chip. */
	fe_write(sc, RA_FE_PDMA_TX0_PTR,
		htole32(MIPS_KSEG0_TO_PHYS(&sc->sc_txdesc)));
	fe_write(sc, RA_FE_PDMA_TX0_COUNT, htole32(RALINK_ETH_NUM_TX_DESC));
	fe_write(sc, RA_FE_PDMA_TX0_CPU_IDX, 0);
	fe_write(sc, RA_FE_PDMA_RESET_IDX, PDMA_RST_TX0);

	fe_write(sc, RA_FE_PDMA_RX0_PTR,
		htole32(MIPS_KSEG0_TO_PHYS(&sc->sc_rxdesc)));
	fe_write(sc, RA_FE_PDMA_RX0_COUNT, htole32(RALINK_ETH_NUM_RX_DESC));
	fe_write(sc, RA_FE_PDMA_RX0_CPU_IDX,
		htole32(RALINK_ETH_NUM_RX_DESC - 1));
	fe_write(sc, RA_FE_PDMA_RESET_IDX, PDMA_RST_RX0);
	fe_write(sc, RA_FE_PDMA_RX0_CPU_IDX,
		htole32(RALINK_ETH_NUM_RX_DESC - 1));

	/* Start PDMA */
	fe_write(sc, RA_FE_PDMA_GLOBAL_CFG,
		FE_PDMA_GLOBAL_CFG_TX_WB_DDONE |
		FE_PDMA_GLOBAL_CFG_RX_DMA_EN |
		FE_PDMA_GLOBAL_CFG_TX_DMA_EN |
		FE_PDMA_GLOBAL_CFG_BURST_SZ_4);

	/* Setup the clock for the Frame Engine */
	fe_write(sc, RA_FE_GLOBAL_CFG,
		FE_GLOBAL_CFG_EXT_VLAN(0x8100) |
		FE_GLOBAL_CFG_US_CLK(RA_BUS_FREQ / 1000000) |
		FE_GLOBAL_CFG_L2_SPACE(0x8));

	/* Turn on all interrupts */
	fe_write(sc, RA_FE_INT_ENABLE,
		FE_INT_RX | FE_INT_TX3 | FE_INT_TX2 | FE_INT_TX1 | FE_INT_TX0);

	/*
	 * Configure GDMA forwarding
	 * - default all packets to CPU
	 * - Turn on auto-CRC
	 */
#if 0
	fe_write(sc, RA_FE_GDMA1_FWD_CFG,
		(FE_GDMA_FWD_CFG_DIS_TX_CRC | FE_GDMA_FWD_CFG_DIS_TX_PAD));
#endif
	fe_write(sc, RA_FE_GDMA1_FWD_CFG,
		FE_GDMA_FWD_CFG_JUMBO_LEN(MCLBYTES/1024) |
		FE_GDMA_FWD_CFG_STRIP_RX_CRC |
		FE_GDMA_FWD_CFG_IP4_CRC_EN |
		FE_GDMA_FWD_CFG_TCP_CRC_EN |
		FE_GDMA_FWD_CFG_UDP_CRC_EN);

	/* CDMA also needs CRCs turned on */
	r = fe_read(sc, RA_FE_CDMA_CSG_CFG);
	r |= (FE_CDMA_CSG_CFG_IP4_CRC_EN | FE_CDMA_CSG_CFG_UDP_CRC_EN |
		FE_CDMA_CSG_CFG_TCP_CRC_EN);
	fe_write(sc, RA_FE_CDMA_CSG_CFG, r);

	/* Configure Flow Control Thresholds */
#ifdef RT3883
	fe_write(sc, RA_FE_PSE_FQ_CFG,
		FE_PSE_FQ_MAX_COUNT(0xff) |
		FE_PSE_FQ_FC_RELEASE(0x90) |
		FE_PSE_FQ_FC_ASSERT(0x80));
#else
	fe_write(sc, RA_FE_PSE_FQ_CFG,
		FE_PSE_FQ_MAX_COUNT(0x80) |
		FE_PSE_FQ_FC_RELEASE(0x50) |
		FE_PSE_FQ_FC_ASSERT(0x40));
#endif

#ifdef RALINK_ETH_DEBUG
	printf("FE_MDIO_CFG1: 0x%08x\n", fe_read(sc, RA_FE_MDIO_CFG1));
	printf("FE_MDIO_CFG2: 0x%08x\n", fe_read(sc, RA_FE_MDIO_CFG2));
	printf("FE_PDMA_TX0_PTR: %08x\n", fe_read(sc, RA_FE_PDMA_TX0_PTR));
	printf("FE_PDMA_TX0_COUNT: %08x\n",
		fe_read(sc, RA_FE_PDMA_TX0_COUNT));
	printf("FE_PDMA_TX0_CPU_IDX: %08x\n",
		fe_read(sc, RA_FE_PDMA_TX0_CPU_IDX));
	printf("FE_PDMA_TX0_DMA_IDX: %08x\n",
		fe_read(sc, RA_FE_PDMA_TX0_DMA_IDX));
	printf("FE_PDMA_RX0_PTR: %08x\n", fe_read(sc, RA_FE_PDMA_RX0_PTR));
	printf("FE_PDMA_RX0_COUNT: %08x\n",
		fe_read(sc, RA_FE_PDMA_RX0_COUNT));
	printf("FE_PDMA_RX0_CPU_IDX: %08x\n",
		fe_read(sc, RA_FE_PDMA_RX0_CPU_IDX));
	printf("FE_PDMA_RX0_DMA_IDX: %08x\n",
		fe_read(sc, RA_FE_PDMA_RX0_DMA_IDX));
	printf("FE_PDMA_GLOBAL_CFG: %08x\n",
		fe_read(sc, RA_FE_PDMA_GLOBAL_CFG));
	printf("FE_GLOBAL_CFG: %08x\n", fe_read(sc, RA_FE_GLOBAL_CFG));
	printf("FE_GDMA1_FWD_CFG: %08x\n",
		fe_read(sc, RA_FE_GDMA1_FWD_CFG));
	printf("FE_CDMA_CSG_CFG: %08x\n", fe_read(sc, RA_FE_CDMA_CSG_CFG));
	printf("FE_PSE_FQ_CFG: %08x\n", fe_read(sc, RA_FE_PSE_FQ_CFG));
#endif

	/* Force PSE Reset to get everything finalized */
	fe_write(sc, RA_FE_GLOBAL_RESET, FE_GLOBAL_RESET_PSE);
	fe_write(sc, RA_FE_GLOBAL_RESET, 0);
}

/*
 * ralink_eth_init
 */
static int
ralink_eth_init(struct ifnet *ifp)
{
	RALINK_DEBUG_FUNC_ENTRY();
	ralink_eth_softc_t * const sc = ifp->if_softc;
	int error;

	error = ralink_eth_enable(sc);
	if (!error) {
		/* Note that the interface is now running. */
		ifp->if_flags |= IFF_RUNNING;
		ifp->if_flags &= ~IFF_OACTIVE;
	}

	return error;
}

/*
 * ralink_eth_rxdrain
 *
 *  Drain the receive queue.
 */
static void
ralink_eth_rxdrain(ralink_eth_softc_t *sc)
{
	RALINK_DEBUG_FUNC_ENTRY();

	for (int i = 0; i < RALINK_ETH_NUM_RX_DESC; i++) {
		struct ralink_eth_rxstate *rxs = &sc->sc_rxstate[i];
		if (rxs->rxs_mbuf != NULL) {
			bus_dmamap_unload(sc->sc_dmat, rxs->rxs_dmamap);
			m_freem(rxs->rxs_mbuf);
			rxs->rxs_mbuf = NULL;
		}
	}
}

/*
 * ralink_eth_stop
 */
static void
ralink_eth_stop(struct ifnet *ifp, int disable)
{
	RALINK_DEBUG_FUNC_ENTRY();
	ralink_eth_softc_t * const sc = ifp->if_softc;

	ralink_eth_disable(sc);

	/* Mark the interface down and cancel the watchdog timer.  */
	ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
	ifp->if_timer = 0;
}

/*
 * ralink_eth_add_rxbuf
 */
static int
ralink_eth_add_rxbuf(ralink_eth_softc_t *sc, int idx)
{
	RALINK_DEBUG_FUNC_ENTRY();
	struct ralink_eth_rxstate * const rxs = &sc->sc_rxstate[idx];
	struct mbuf *m;
	int error;

	MGETHDR(m, M_DONTWAIT, MT_DATA);
	if (m == NULL) {
		printf("MGETHDR failed\n");
		sc->sc_evcnt_add_rxbuf_hdr_fail.ev_count++;
		return ENOBUFS;
	}

	MCLGET(m, M_DONTWAIT);
	if ((m->m_flags & M_EXT) == 0) {
		m_freem(m);
		printf("MCLGET failed\n");
		sc->sc_evcnt_add_rxbuf_mcl_fail.ev_count++;
		return ENOBUFS;
	}

	m->m_data = m->m_ext.ext_buf;
	rxs->rxs_mbuf = m;

	error = bus_dmamap_load(sc->sc_dmat, rxs->rxs_dmamap, m->m_ext.ext_buf,
	    m->m_ext.ext_size, NULL, BUS_DMA_READ|BUS_DMA_NOWAIT);
	if (error) {
		aprint_error_dev(sc->sc_dev, "can't load rx DMA map %d, "
			"error=%d\n", idx, error);
		panic(__func__);  /* XXX */
	}

	sc->sc_rxdesc[idx].data_ptr = MIPS_KSEG0_TO_PHYS(
		rxs->rxs_dmamap->dm_segs[0].ds_addr + RALINK_ETHER_ALIGN);
	sc->sc_rxdesc[idx].rxd_info1 = RXD_LAST0;

	bus_dmamap_sync(sc->sc_dmat, rxs->rxs_dmamap, 0,
		rxs->rxs_dmamap->dm_mapsize, BUS_DMASYNC_PREREAD);

	return 0;
}


/*
 * ralink_eth_start
 */
static void
ralink_eth_start(struct ifnet *ifp)
{
	RALINK_DEBUG_FUNC_ENTRY();
	ralink_eth_softc_t * const sc = ifp->if_softc;
	struct mbuf *m0, *m = NULL;
	struct ralink_eth_txstate *txs;
	bus_dmamap_t dmamap;
	int tx_cpu_idx;
	int error;
	int s;

	if ((ifp->if_flags & (IFF_RUNNING|IFF_OACTIVE)) != IFF_RUNNING)
		return;

	s = splnet();

	tx_cpu_idx = fe_read(sc, RA_FE_PDMA_TX0_CPU_IDX);

	/*
	 * Loop through the send queue, setting up transmit descriptors
	 * until we drain the queue, or use up all available
	 * transmit descriptors.
	 */
	while ((txs = SIMPLEQ_FIRST(&sc->sc_txfreeq)) != NULL) {
		/* Grab a packet off the queue.  */
		IFQ_POLL(&ifp->if_snd, m0);
		if (m0 == NULL)
			break;

		dmamap = txs->txs_dmamap;

		if (m0->m_pkthdr.len < RALINK_MIN_BUF) {
			int padlen = 64 - m0->m_pkthdr.len;
			m_copyback(m0, m0->m_pkthdr.len, padlen,
				sc->ralink_zero_buf);
			/* TODO : need some checking here */
		}

		/*
		 * Do we need to align the buffer
		 * or does the DMA map load fail?
		 */
		if (bus_dmamap_load_mbuf(sc->sc_dmat, dmamap, m0,
		    BUS_DMA_WRITE|BUS_DMA_NOWAIT) != 0) {

			/* Allocate a new mbuf for re-alignment */
			MGETHDR(m, M_DONTWAIT, MT_DATA);
			if (m == NULL) {
				aprint_error_dev(sc->sc_dev,
					"unable to allocate aligned Tx mbuf\n");
				break;
			}
			MCLAIM(m, &sc->sc_ethercom.ec_tx_mowner);
			if (m0->m_pkthdr.len > MHLEN) {
				MCLGET(m, M_DONTWAIT);
				if ((m->m_flags & M_EXT) == 0) {
					aprint_error_dev(sc->sc_dev,
				 	    "unable to allocate Tx cluster\n");
					m_freem(m);
					break;
				}
			}
			m_copydata(m0, 0, m0->m_pkthdr.len, mtod(m, void *));
			m->m_pkthdr.len = m->m_len = m0->m_pkthdr.len;
			error = bus_dmamap_load_mbuf(sc->sc_dmat, dmamap, m,
			    BUS_DMA_WRITE|BUS_DMA_NOWAIT);
			if (error) {
				aprint_error_dev(sc->sc_dev,
					"unable to load Tx buffer error=%d\n",
					error);
				m_freem(m);
				break;
			}
		}

		IFQ_DEQUEUE(&ifp->if_snd, m0);
		/* did we copy the buffer out already? */
		if (m != NULL) {
			m_freem(m0);
			m0 = m;
		}

		/* Sync the DMA map. */
		bus_dmamap_sync(sc->sc_dmat, dmamap, 0, dmamap->dm_mapsize,
			BUS_DMASYNC_PREWRITE);

		/* Initialize the transmit descriptor */
		sc->sc_txdesc[tx_cpu_idx].data_ptr0 =
			MIPS_KSEG0_TO_PHYS(dmamap->dm_segs[0].ds_addr);
		sc->sc_txdesc[tx_cpu_idx].txd_info1 =
			TXD_LEN0(dmamap->dm_segs[0].ds_len) | TXD_LAST0;
		sc->sc_txdesc[tx_cpu_idx].txd_info2 =
			TXD_QN(3) | TXD_PN(TXD_PN_GDMA1);
		sc->sc_txdesc[tx_cpu_idx].txd_info2 = TXD_QN(3) |
			TXD_PN(TXD_PN_GDMA1) | TXD_VEN |
			// TXD_VIDX(pt->vlan_id) |
			TXD_TCP_EN | TXD_UDP_EN | TXD_IP_EN;

		RALINK_DEBUG(RALINK_DEBUG_REG,"+tx(%d) 0x%08x: 0x%08x\n",
			tx_cpu_idx, (int)&sc->sc_txdesc[tx_cpu_idx].data_ptr0,
			sc->sc_txdesc[tx_cpu_idx].data_ptr0);
		RALINK_DEBUG(RALINK_DEBUG_REG,"+tx(%d) 0x%08x: 0x%08x\n",
			tx_cpu_idx, (int)&sc->sc_txdesc[tx_cpu_idx].txd_info1,
			sc->sc_txdesc[tx_cpu_idx].txd_info1);
		RALINK_DEBUG(RALINK_DEBUG_REG,"+tx(%d) 0x%08x: 0x%08x\n",
			tx_cpu_idx, (int)&sc->sc_txdesc[tx_cpu_idx].data_ptr1,
			sc->sc_txdesc[tx_cpu_idx].data_ptr1);
		RALINK_DEBUG(RALINK_DEBUG_REG,"+tx(%d) 0x%08x: 0x%08x\n", tx_cpu_idx,
			(int)&sc->sc_txdesc[tx_cpu_idx].txd_info2,
			sc->sc_txdesc[tx_cpu_idx].txd_info2);

		/* sync the descriptor we're using. */
		bus_dmamap_sync(sc->sc_dmat, sc->sc_pdmamap,
			(int)&sc->sc_txdesc[tx_cpu_idx] - (int)sc->sc_descs,
			sizeof(struct ralink_tx_desc),
			BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);

		/*
		 * Store a pointer to the packet so we can free it later,
		 * and remember what txdirty will be once the packet is
		 * done.
		 */
		txs->txs_mbuf = m0;
		sc->sc_pending_tx++;
		if (txs->txs_idx != tx_cpu_idx) {
			panic("txs_idx doesn't match %d != %d\n",
				txs->txs_idx, tx_cpu_idx);
		}

		SIMPLEQ_REMOVE_HEAD(&sc->sc_txfreeq, txs_q);
		SIMPLEQ_INSERT_TAIL(&sc->sc_txdirtyq, txs, txs_q);

		/* Pass the packet to any BPF listeners. */
		bpf_mtap(ifp, m0);

		/* Set a watchdog timer in case the chip flakes out. */
		ifp->if_timer = 5;

		tx_cpu_idx = (tx_cpu_idx + 1) % RALINK_ETH_NUM_TX_DESC;

		/* Write back the tx_cpu_idx */
		fe_write(sc, RA_FE_PDMA_TX0_CPU_IDX, tx_cpu_idx);
	}

	if (txs == NULL) {
		/* No more slots left; notify upper layer. */
		ifp->if_flags |= IFF_OACTIVE;
	}

	splx(s);
}

/*
 * ralink_eth_watchdog
 *
 *	Watchdog timer handler.
 */
static void
ralink_eth_watchdog(struct ifnet *ifp)
{
	RALINK_DEBUG_FUNC_ENTRY();
	ralink_eth_softc_t * const sc = ifp->if_softc;
	bool doing_transmit;

	sc->sc_evcnt_watchdog.ev_count++;
	doing_transmit = !SIMPLEQ_EMPTY(&sc->sc_txdirtyq);

	if (doing_transmit) {
		RALINK_DEBUG(RALINK_DEBUG_ERROR, "%s: transmit timeout\n",
			ifp->if_xname);
		ifp->if_oerrors++;
		sc->sc_evcnt_wd_tx.ev_count++;
	} else {
		RALINK_DEBUG(RALINK_DEBUG_ERROR, "%s: spurious watchog timeout\n",
			ifp->if_xname);
		sc->sc_evcnt_wd_spurious.ev_count++;
		return;
	}

	sc->sc_evcnt_wd_reactivate.ev_count++;
	const int s = splnet();
	/* deactive the active partitions, retaining the active information */
	ralink_eth_disable(sc);
	ralink_eth_enable(sc);
	splx(s);

	/* Try to get more packets going. */
	ralink_eth_start(ifp);
}

/*
 * ralink_eth_ioctl
 *
 *	Handle control requests from the operator.
 */
static int
ralink_eth_ioctl(struct ifnet *ifp, u_long cmd, void *data)
{
	RALINK_DEBUG_FUNC_ENTRY();
	struct ifdrv * const ifd = (struct ifdrv *) data;
	ralink_eth_softc_t * const sc = ifp->if_softc;
	int s, error = 0;

	RALINK_DEBUG(RALINK_DEBUG_INFO, "ifp: %p  cmd: %lu  data: %p\n",
		ifp, cmd, data);

	s = splnet();

	switch (cmd) {
	case SIOCSDRVSPEC:
		switch (ifd->ifd_cmd) {
#if 0
		case ETH_SWITCH_CMD_PORT_MODE:
			/* len parameter is the mode */
			pt->mode = (int) ifd->ifd_len;
			ralink_eth_configure_switch(pt->sc_reth);
			break;
#endif
		default:
			error = EINVAL;
		}
		break;
	default:
		error = ether_ioctl(ifp, cmd, data);
		if (error == ENETRESET) {
			if (ifp->if_flags & IFF_RUNNING) {
				/*
				 * Multicast list has changed.  Set the
				 * hardware filter accordingly.
				 */
				RALINK_DEBUG(RALINK_DEBUG_INFO, "TODO!!!");
#if 0
				ralink_eth_filter_setup(sc);
#endif
			}
			error = 0;
		}
		break;
	}

	splx(s);

	/* Try to get more packets going. */
	if (sc->sc_ih != NULL)
		ralink_eth_start(ifp);

	return error;
}

/*
 * ralink_eth_intr
 *
 */
static int
ralink_eth_intr(void *arg)
{
	RALINK_DEBUG_FUNC_ENTRY();
	ralink_eth_softc_t * const sc = arg;

	for (u_int n=0;; n = 1) {
		u_int32_t status = fe_read(sc, RA_FE_INT_STATUS);
		fe_write(sc, RA_FE_INT_STATUS, ~0);
		RALINK_DEBUG(RALINK_DEBUG_REG,"%s() status: 0x%08x\n",
			__func__, status);

		if ((status & (FE_INT_RX | FE_INT_TX0)) == 0) {
			if (n == 0)
				sc->sc_evcnt_spurious_intr.ev_count++;
			return (n != 0);
		}

		if (status & FE_INT_RX)
			ralink_eth_rxintr(sc);

		if (status & FE_INT_TX0)
			ralink_eth_txintr(sc);
	}

	/* Try to get more packets going. */
	ralink_eth_start(&sc->sc_ethercom.ec_if);

	return 1;
}

/*
 * ralink_eth_rxintr
 */
static void
ralink_eth_rxintr(ralink_eth_softc_t *sc)
{
	RALINK_DEBUG_FUNC_ENTRY();
	struct ifnet * const ifp = &sc->sc_ethercom.ec_if;
	struct ralink_eth_rxstate *rxs;
	struct mbuf *m;
	int len;
	int rx_cpu_idx;

	KASSERT(curcpu()->ci_cpl >= IPL_NET);
	sc->sc_evcnt_rxintr.ev_count++;
	rx_cpu_idx = fe_read(sc, RA_FE_PDMA_RX0_CPU_IDX);

	for (;;)  {
		rx_cpu_idx = (rx_cpu_idx + 1) % RALINK_ETH_NUM_RX_DESC;

		rxs = &sc->sc_rxstate[rx_cpu_idx];

		bus_dmamap_sync(sc->sc_dmat, sc->sc_pdmamap,
			(int)&sc->sc_rxdesc[rx_cpu_idx] - (int)sc->sc_descs,
			sizeof(struct ralink_rx_desc),
			BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);

		RALINK_DEBUG(RALINK_DEBUG_REG,"rx(%d) 0x%08x: 0x%08x\n",
			rx_cpu_idx, (int)&sc->sc_rxdesc[rx_cpu_idx].data_ptr,
			sc->sc_rxdesc[rx_cpu_idx].data_ptr);
		RALINK_DEBUG(RALINK_DEBUG_REG,"rx(%d) 0x%08x: 0x%08x\n",
			rx_cpu_idx, (int)&sc->sc_rxdesc[rx_cpu_idx].rxd_info1,
			sc->sc_rxdesc[rx_cpu_idx].rxd_info1);
		RALINK_DEBUG(RALINK_DEBUG_REG,"rx(%d) 0x%08x: 0x%08x\n", rx_cpu_idx,
			(int)&sc->sc_rxdesc[rx_cpu_idx].unused,
			sc->sc_rxdesc[rx_cpu_idx].unused);
		RALINK_DEBUG(RALINK_DEBUG_REG,"rx(%d) 0x%08x: 0x%08x\n",
			rx_cpu_idx, (int)&sc->sc_rxdesc[rx_cpu_idx].rxd_info2,
			sc->sc_rxdesc[rx_cpu_idx].rxd_info2);

		if (!(sc->sc_rxdesc[rx_cpu_idx].rxd_info1 & RXD_DDONE))
			break;

		bus_dmamap_sync(sc->sc_dmat, rxs->rxs_dmamap, 0,
			rxs->rxs_dmamap->dm_mapsize, BUS_DMASYNC_POSTREAD);

		/*
		 * No errors; receive the packet.
		 * Note the chip includes the CRC with every packet.
		 */
		len = RXD_LEN0(sc->sc_rxdesc[rx_cpu_idx].rxd_info1);

		RALINK_DEBUG(RALINK_DEBUG_REG,"rx(%d) packet rx %d bytes\n",
			rx_cpu_idx, len);

		/*
		 * Allocate a new mbuf cluster.  If that fails, we are
		 * out of memory, and must drop the packet and recycle
		 * the buffer that's already attached to this descriptor.
		 */
		m = rxs->rxs_mbuf;
		if (ralink_eth_add_rxbuf(sc, rx_cpu_idx) != 0)
			break;
		m->m_data += RALINK_ETHER_ALIGN;
		m->m_pkthdr.len = m->m_len = len;

#ifdef RALINK_ETH_DEBUG
 {
		struct ether_header *eh = mtod(m, struct ether_header *);
		printf("rx: eth_dst: %s ", ether_sprintf(eh->ether_dhost));
		printf("rx: eth_src: %s type: 0x%04x \n",
			ether_sprintf(eh->ether_shost), ntohs(eh->ether_type));
		printf("0x14: %08x\n", *(volatile unsigned int *)(0xb0110014));
		printf("0x98: %08x\n", *(volatile unsigned int *)(0xb0110098));

		unsigned char * s = mtod(m, unsigned char *);
		for (int j = 0; j < 32; j++)
			printf("%02x%c", *(s + j),
				(j == 15 || j == 31) ? '\n' : ' ');
 }
#endif

		/*
		 * claim the buffer here since we can't do it at
		 * allocation time due to the SW partitions
		 */
		MCLAIM(m, &sc->sc_ethercom.ec_rx_mowner);

		/* push it up the inteface */
		ifp->if_ipackets++;
		m->m_pkthdr.rcvif = ifp;

#ifdef RALINK_ETH_DEBUG
 {
		struct ether_header *eh = mtod(m, struct ether_header *);
		printf("rx: eth_dst: %s ", ether_sprintf(eh->ether_dhost));
		printf("rx: eth_src: %s type: 0x%04x\n",
			ether_sprintf(eh->ether_shost), ntohs(eh->ether_type));
		printf("0x14: %08x\n", *(volatile unsigned int *)(0xb0110014));
		printf("0x98: %08x\n", *(volatile unsigned int *)(0xb0110098));

		unsigned char * s = mtod(m, unsigned char *);
		for (int j = 0; j < 32; j++)
			printf("%02x%c", *(s + j),
				(j == 15 || j == 31) ? '\n' : ' ');
 }
#endif

		/*
		 * XXX: M_CSUM_TCPv4 and M_CSUM_UDPv4 do not currently work when
		 * using PF's ROUTETO option for load balancing.
		 */
		m->m_pkthdr.csum_flags |= M_CSUM_IPv4;

		/*
		 * Pass this up to any BPF listeners, but only
		 * pass it up the stack if its for us.
		 */
		bpf_mtap(ifp, m);

		/* Pass it on. */
		sc->sc_evcnt_input.ev_count++;
		(*ifp->if_input)(ifp, m);

		fe_write(sc, RA_FE_PDMA_RX0_CPU_IDX, rx_cpu_idx);
	}
}

/*
 * ralink_eth_txintr
 */
static void
ralink_eth_txintr(ralink_eth_softc_t *sc)
{
	RALINK_DEBUG_FUNC_ENTRY();
	struct ralink_eth_txstate *txs;

	KASSERT(curcpu()->ci_cpl >= IPL_NET);
	sc->sc_evcnt_txintr.ev_count++;

	/*
	 * Go through our Tx list and free mbufs for those
	 * frames that have been transmitted.
	 */
	while ((txs = SIMPLEQ_FIRST(&sc->sc_txdirtyq)) != NULL) {
		bus_dmamap_sync(sc->sc_dmat, sc->sc_pdmamap,
			(int)&sc->sc_txdesc[txs->txs_idx] - (int)sc->sc_descs,
			sizeof(struct ralink_tx_desc),
			BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);

		RALINK_DEBUG(RALINK_DEBUG_REG,"-tx(%d) 0x%08x: 0x%08x\n", txs->txs_idx,
			(int)&sc->sc_txdesc[txs->txs_idx].data_ptr0,
			sc->sc_txdesc[txs->txs_idx].data_ptr0);
		RALINK_DEBUG(RALINK_DEBUG_REG,"-tx(%d) 0x%08x: 0x%08x\n", txs->txs_idx,
			(int)&sc->sc_txdesc[txs->txs_idx].txd_info1,
			sc->sc_txdesc[txs->txs_idx].txd_info1);
		RALINK_DEBUG(RALINK_DEBUG_REG,"-tx(%d) 0x%08x: 0x%08x\n", txs->txs_idx,
			(int)&sc->sc_txdesc[txs->txs_idx].data_ptr1,
			sc->sc_txdesc[txs->txs_idx].data_ptr1);
		RALINK_DEBUG(RALINK_DEBUG_REG,"-tx(%d) 0x%08x: 0x%08x\n", txs->txs_idx,
			(int)&sc->sc_txdesc[txs->txs_idx].txd_info2,
			sc->sc_txdesc[txs->txs_idx].txd_info2);

		/* we're finished if the current tx isn't done */
		if (!(sc->sc_txdesc[txs->txs_idx].txd_info1 & TXD_DDONE))
			break;

		RALINK_DEBUG(RALINK_DEBUG_REG,"-tx(%d) transmitted\n", txs->txs_idx);

		SIMPLEQ_REMOVE_HEAD(&sc->sc_txdirtyq, txs_q);

		bus_dmamap_sync(sc->sc_dmat, txs->txs_dmamap, 0,
			txs->txs_dmamap->dm_mapsize, BUS_DMASYNC_POSTWRITE);
		bus_dmamap_unload(sc->sc_dmat, txs->txs_dmamap);
		m_freem(txs->txs_mbuf);
		txs->txs_mbuf = NULL;

		SIMPLEQ_INSERT_TAIL(&sc->sc_txfreeq, txs, txs_q);

		struct ifnet *ifp = &sc->sc_ethercom.ec_if;
		ifp->if_flags &= ~IFF_OACTIVE;
		ifp->if_opackets++;
		sc->sc_evcnt_output.ev_count++;

		if (--sc->sc_pending_tx == 0)
			ifp->if_timer = 0;
	}
}

/*
 * ralink_eth_mdio_enable
 */
#if defined (RT3050) || defined(RT3052)
static void
ralink_eth_mdio_enable(ralink_eth_softc_t *sc, bool enable)
{
	uint32_t data = sy_read(sc, RA_SYSCTL_GPIOMODE);

	if (enable)
		data &= ~GPIOMODE_MDIO;
	else
		data |= GPIOMODE_MDIO;

	sy_write(sc, RA__GPIOMODE, data);
}
#else
#define ralink_eth_mdio_enable(sc, enable)
#endif

/*
 * ralink_eth_mii_statchg
 */
static void
ralink_eth_mii_statchg(device_t self)
{
#if 0
	ralink_eth_softc_t * const sc = device_private(self);

#endif
}

/*
 * ralink_eth_mii_tick
 *
 *	One second timer, used to tick the MIIs.
 */
static void
ralink_eth_mii_tick(void *arg)
{
	ralink_eth_softc_t * const sc = arg;

	const int s = splnet();
	mii_tick(&sc->sc_mii);
	splx(s);

	callout_reset(&sc->sc_tick_callout, hz, ralink_eth_mii_tick, sc);
}

/*
 * ralink_eth_mii_read
 */
static int
ralink_eth_mii_read(device_t self, int phy_addr, int phy_reg)
{
	const ralink_eth_softc_t *sc = device_private(self);
	KASSERT(sc != NULL);
#if 0
	printf("%s() phy_addr: %d  phy_reg: %d\n", __func__, phy_addr, phy_reg);
#endif
#if defined(RT3050) || defined(RT3052)
	if (phy_addr > 5)
		return 0;
#endif

	/* We enable mdio gpio purpose register, and disable it when exit. */
	ralink_eth_mdio_enable(sc, true);

	/*
	 * make sure previous read operation is complete
	 * TODO: timeout (linux uses jiffies to measure 5 seconds)
	 */
	for (;;) {
		/* rd_rdy: read operation is complete */
#if defined(RT3050) || defined(RT3052)
		if ((sw_read(sc, RA_ETH_SW_PCTL1) & PCTL1_RD_DONE) == 0)
			break;
#else
		if ((fe_read(sc, RA_FE_MDIO_ACCESS) & MDIO_ACCESS_TRG) == 0)
			break;
#endif
	}

#if defined(RT3050) || defined(RT3052)
	sw_write(sc, RA_ETH_SW_PCTL0,
		PCTL0_RD_CMD | PCTL0_REG(phy_reg) | PCTL0_ADDR(phy_addr);
#else
	fe_write(sc, RA_FE_MDIO_ACCESS,
		MDIO_ACCESS_PHY_ADDR(phy_addr) | MDIO_ACCESS_REG(phy_reg));
	fe_write(sc, RA_FE_MDIO_ACCESS,
		MDIO_ACCESS_PHY_ADDR(phy_addr) | MDIO_ACCESS_REG(phy_reg) |
		MDIO_ACCESS_TRG);
#endif

	/*
	 * make sure read operation is complete
	 * TODO: timeout (linux uses jiffies to measure 5 seconds)
	 */
	for (;;) {
#if defined(RT3050) || defined(RT3052)
		if ((sw_read(sc, RA_ETH_SW_PCTL1) & PCTL1_RD_DONE) != 0) {
			int data = PCTL1_RD_VAL(
				sw_read(sc, RA_ETH_SW_PCTL1));
			ralink_eth_mdio_enable(sc, false);
			return data;
		}
#else
		if ((fe_read(sc, RA_FE_MDIO_ACCESS) & MDIO_ACCESS_TRG) == 0) {
			int data = MDIO_ACCESS_DATA(
				fe_read(sc, RA_FE_MDIO_ACCESS));
			ralink_eth_mdio_enable(sc, false);
			return data;
		}
#endif
	}
}

/*
 * ralink_eth_mii_write
 */
static void
ralink_eth_mii_write(device_t self, int phy_addr, int phy_reg, int val)
{
	const ralink_eth_softc_t *sc = device_private(self);
	KASSERT(sc != NULL);
#if 0
	printf("%s() phy_addr: %d  phy_reg: %d  val: 0x%04x\n",
		__func__, phy_addr, phy_reg, val);
#endif
	ralink_eth_mdio_enable(sc, true);

	/*
	 * make sure previous write operation is complete
	 * TODO: timeout (linux uses jiffies to measure 5 seconds)
	 */
	for (;;) {
#if defined(RT3050) || defined(RT3052)
		if ((sw_read(sc, RA_ETH_SW_PCTL1) & PCTL1_RD_DONE) == 0)
			break;
#else
		if ((fe_read(sc, RA_FE_MDIO_ACCESS) & MDIO_ACCESS_TRG) == 0)
			break;
#endif
	}

#if defined(RT3050) || defined(RT3052)
	sw_write(sc, RA_ETH_SW_PCTL0,
		PCTL0_WR_CMD | PCTL0_WR_VAL(val) | PCTL0_REG(phy_reg) |
		PCTL0_ADDR(phy_addr));
#else
	fe_write(sc, RA_FE_MDIO_ACCESS,
		MDIO_ACCESS_WR | MDIO_ACCESS_PHY_ADDR(phy_addr) |
		MDIO_ACCESS_REG(phy_reg) | MDIO_ACCESS_DATA(val));
	fe_write(sc, RA_FE_MDIO_ACCESS,
		MDIO_ACCESS_WR | MDIO_ACCESS_PHY_ADDR(phy_addr) |
		MDIO_ACCESS_REG(phy_reg) | MDIO_ACCESS_DATA(val) |
		MDIO_ACCESS_TRG);
#endif


	/* make sure write operation is complete */
	for (;;) {
#if defined(RT3050) || defined(RT3052)
		if ((sw_read(sc, RA_ETH_SW_PCTL1) & PCTL1_WR_DONE) != 0) {
			ralink_eth_mdio_enable(sc, false);
			return;
		}
#else
		if ((fe_read(sc, RA_FE_MDIO_ACCESS) & MDIO_ACCESS_TRG) == 0){
			ralink_eth_mdio_enable(sc, false);
			return;
		}
#endif
	}
}

File Added: src/sys/arch/mips/ralink/ralink_gpio.c
/*	$NetBSD: ralink_gpio.c,v 1.2 2011/07/28 15:38:49 matt Exp $	*/
/*-
 * Copyright (c) 2011 CradlePoint Technology, Inc.
 * 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, 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 CRADLEPOINT TECHNOLOGY, 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 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.
 */

/* ra_gpio.c -- Ralink 3052 gpio driver */

#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ralink_gpio.c,v 1.2 2011/07/28 15:38:49 matt Exp $");

#include <sys/param.h>
#include <sys/bus.h>
#include <sys/callout.h>
#include <sys/device.h>
#include <sys/event.h>
#include <sys/intr.h>
#include <sys/kernel.h>
#include <sys/systm.h>

#include <dev/cons.h>

#include <mips/cpuregs.h>
#include <sys/gpio.h>
#include <dev/gpio/gpiovar.h>

#define SLICKROCK

#include <mips/ralink/ralink_reg.h>
#include <mips/ralink/ralink_var.h>
#include <mips/ralink/ralink_gpio.h>

#if 0
#define ENABLE_RALINK_DEBUG_ERROR 1
#define ENABLE_RALINK_DEBUG_MISC  1
#define ENABLE_RALINK_DEBUG_INFO  1
#define ENABLE_RALINK_DEBUG_FORCE 1
#define ENABLE_RALINK_DEBUG_FUNC 1
#endif

#include <mips/ralink/ralink_debug.h>

/*
 * From the RT3052 datasheet, the GPIO pins are
 * shared with a number of other functions.  Not
 * all will be available for GPIO.  To make sure
 * pins are in GPIO mode, the GPIOMODE purpose
 * select register must be set (reset defaults all pins
 * as GPIO except for JTAG)
 *
 * Note, GPIO0 is not shared, it is the single dedicated
 * GPIO pin.
 *
 * 52 pins:
 *
 *	40 - 51 RGMII  (GE0_* pins)
 *	24 - 39 SDRAM  (MD31:MD16 pins)
 *	22 - 23 MDIO   (MDC/MDIO pins)
 *	17 - 21 JTAG   (JTAG_* pins)
 *	15 - 16 UART Light  (RXD2/TXD2 pins)
 *	7  - 14 UART Full   (8 pins)
 *	(7 - 14)  UARTF_7 (3'b111 in Share mode reg)
 *	(11 - 14) UARTF_5 (3'b110 in Share mode reg, same with 6)
 *	(7 - 9)   UARTF_4 (3'b100 in Share mode reg)
 *	3  -  6 SPI    (SPI_* pins)
 *	1  -  2 I2C    (I2C_SCLK/I2C_SD pins)
 */

#if defined(SLICKROCK)
#define GPIO_PINS 96
#else
#define GPIO_PINS 52
#endif

/*
 * Special commands are pseudo pin numbers used to pass data to bootloader,
 */
#define BOOT_COUNT		GPIO_PINS
#define UPGRADE			(BOOT_COUNT + 1)
#define SPECIAL_COMMANDS	(UPGRADE + 1 - GPIO_PINS)

/*
 * The pin_share array maps to the highest pin used for each of the 10
 * GPIO mode bit settings.
 */
#if defined(SLICKROCK)
#define SR_GPIO_MODE 0xc1c1f
#else
#define GPIO_MODE_SETTINGS 10
const static u_int8_t pin_share[GPIO_MODE_SETTINGS] = {
	2, 6, 9, 14, 14, 16, 21, 23, 39, 51
};
#endif

#define DEBOUNCE_TIME 150  /* Milliseconds */

#if defined(TABLEROCK)  || defined(SPOT2) || defined(PUCK) || defined(MOAB)

static const u_int32_t debounce_pin[DEBOUNCED_PINS] = {
	WPS_BUTTON,
	POWER_OFF_BUTTON,
	DOCK_SENSE,
	IN_5V,
	LAN_WAN_SW
};
static struct timeval debounce_time[DEBOUNCED_PINS];

/* LED defines for display during boot */
static const char led_array1[] = {
	LED_BATT_7,
	LED_BATT_8,
	LED_BATT_9,
	LED_BATT_10,
	LED_SS_11,
	LED_SS_12,
	LED_SS_13,
	LED_SS_14
};

#define SET_SS_LED_REG RA_PIO_24_39_SET_BIT
#define CLEAR_SS_LED_REG RA_PIO_24_39_CLR_BIT
#define SS_OFFSET 24
#define BOOT_LED_TIMING 3000

#endif	/* TABLEROCK || SPOT2 || PUCK || MOAB */

#if defined(PEBBLES500) || defined (PEBBLES35)

static const u_int32_t debounce_pin[DEBOUNCED_PINS] = {
	WPS_BUTTON,
	SOFT_RST_IN_BUTTON,
	CURRENT_LIMIT_FLAG1_3_3v,
	CURRENT_LIMIT_FLAG_USB1,
	CURRENT_LIMIT_FLAG1_1_5v,
	EXCARD_ATTACH
};
static struct timeval debounce_time[DEBOUNCED_PINS];

/* LED defines for display during boot */
#if defined(PEBBLES500)
static const char led_array1[] = {
	LED_SS_13,
	LED_SS_12,
	LED_SS_11,
	LED_SS_10
};
#else
static const char led_array1[] = {};
#endif

#define SET_SS_LED_REG RA_PIO_40_51_SET_BIT
#define CLEAR_SS_LED_REG RA_PIO_40_51_CLR_BIT
#define SS_OFFSET 40
#define BOOT_LED_TIMING 5500

#endif	/* PEBBLES500 || PEBBLES35 */


#if defined(SLICKROCK)

static const u_int32_t debounce_pin[DEBOUNCED_PINS] = {
	WPS_BUTTON,
	SOFT_RST_IN_BUTTON,
	SS_BUTTON,
	CURRENT_LIMIT_FLAG_USB1,
	CURRENT_LIMIT_FLAG_USB2,
	CURRENT_LIMIT_FLAG_USB3,
	CURRENT_LIMIT_FLAG_EX1,
	CURRENT_LIMIT_FLAG_EX2,
	WIFI_ENABLE
};
static struct timeval debounce_time[DEBOUNCED_PINS];

/* LED defines for display during boot */
static const char led_array1[] = {
	LED_SS_13,
	LED_SS_12,
	LED_SS_11,
	LED_SS_10
};

#define SET_SS_LED_REG RA_PIO_40_51_SET_BIT
#define CLEAR_SS_LED_REG RA_PIO_40_51_CLR_BIT
#define SS_OFFSET 40
#define BOOT_LED_TIMING 3250

#endif	/* SLICKROCK */

#ifndef DEBOUNCED_PINS
static const u_int32_t debounce_pin[] = {};
static struct timeval debounce_time[] = {};
#endif
#ifndef BOOT_LED_TIMING
static const char led_array1[] = {};
#endif

#define RA_GPIO_PIN_INIT(sc, var, pin, ptp, regname)			\
	do {								\
		const u_int _reg_bit = 1 << (pin - ptp->pin_reg_base);	\
		const u_int _mask_bit = 1 << (pin - ptp->pin_mask_base);\
		var = gp_read(sc, ptp->regname.reg);			\
		if ((ptp->regname.mask & _mask_bit) != 0) {		\
			var |= _reg_bit;				\
		} else {						\
			var &= ~_reg_bit;				\
		}							\
		gp_write(sc, ptp->regname.reg, var);			\
	} while (0)

#define RA_GPIO_PIN_INIT_DIR(sc, var, pin, ptp)				\
	do {								\
		const u_int _reg_bit = 1 << (pin - ptp->pin_reg_base);	\
		const u_int _mask_bit = 1 << (pin - ptp->pin_mask_base);\
		var = gp_read(sc, ptp->pin_dir.reg);			\
		if ((ptp->pin_dir.mask & _mask_bit) != 0) {		\
			var |= _reg_bit;				\
			sc->sc_pins[pin].pin_flags = GPIO_PIN_OUTPUT;	\
		} else {						\
			var &= ~_reg_bit;				\
			sc->sc_pins[pin].pin_flags = GPIO_PIN_INPUT;	\
		}							\
		gp_write(sc, ptp->pin_dir.reg, var);			\
	} while (0)



typedef struct ra_gpio_softc {
	device_t sc_dev;
	struct gpio_chipset_tag	sc_gc;
	gpio_pin_t sc_pins[GPIO_PINS + SPECIAL_COMMANDS];

	bus_space_tag_t	sc_memt;	/* bus space tag */

	bus_space_handle_t sc_sy_memh;	/* Sysctl bus space handle */
	int sc_sy_size;			/* size of Sysctl register space */

	bus_space_handle_t sc_gp_memh;	/* PIO bus space handle */
	int sc_gp_size;			/* size of PIO register space */

	void *sc_ih;			/* interrupt handle */
	void *sc_si;			/* softintr handle  */

	struct callout sc_tick_callout;	/* For debouncing inputs */

 	/* 
	 * These track gpio pins that have interrupted
	 */
	uint32_t sc_intr_status00_23;
	uint32_t sc_intr_status24_39;
	uint32_t sc_intr_status40_51;
	uint32_t sc_intr_status72_95;

} ra_gpio_softc_t;

static int ra_gpio_match(device_t, cfdata_t , void *);
static void ra_gpio_attach(device_t, device_t, void *);
#ifdef NOTYET
static int ra_gpio_open(void *, device_t);
static int ra_gpio_close(void *, device_t);
#endif
static void ra_gpio_pin_init(ra_gpio_softc_t *, int);
static void ra_gpio_pin_ctl(void *, int, int);

static int  ra_gpio_intr(void *);
static void ra_gpio_softintr(void *);
static void ra_gpio_debounce_process(void *);
static void ra_gpio_debounce_setup(ra_gpio_softc_t *);

static void disable_gpio_interrupt(ra_gpio_softc_t *, int);
static void enable_gpio_interrupt(ra_gpio_softc_t *, int);

static void gpio_reset_registers(ra_gpio_softc_t *);
#if 0
static void gpio_register_dump(ra_gpio_softc_t *);
#endif

typedef struct pin_reg {
	u_int mask;
	u_int reg;
} pin_reg_t;

typedef struct pin_tab {
	int pin_reg_base;
	int pin_reg_limit;
	int pin_mask_base;
	u_int pin_enabled;
	u_int pin_input;
	u_int pin_output_clr;
	u_int pin_output_set;
	pin_reg_t pin_dir;
	pin_reg_t pin_rise;
	pin_reg_t pin_fall;
	pin_reg_t pin_pol;
} pin_tab_t;

/*
 * use pin_tab[] in conjunction with pin_tab_index[]
 * to look up register offsets, masks, etc. for a given GPIO pin,
 * instead of lots of if/then/else test & branching
 */
static const pin_tab_t pin_tab[] = {
    {
	0, 24, 0, GPIO_PIN_MASK,
	RA_PIO_00_23_DATA,
	RA_PIO_00_23_CLR_BIT,
	RA_PIO_00_23_SET_BIT,
	{ GPIO_OUTPUT_PIN_MASK,          RA_PIO_00_23_DIR,         },
	{ GPIO_INT_PIN_MASK,             RA_PIO_00_23_INT_RISE_EN, },
	{ GPIO_INT_FEDGE_PIN_MASK,       RA_PIO_00_23_INT_RISE_EN, },
	{ GPIO_POL_MASK,                 RA_PIO_00_23_POLARITY,    },
    },
    {
	24, 40, 24, GPIO_PIN_MASK_24_51,
	RA_PIO_24_39_DATA,
	RA_PIO_24_39_CLR_BIT,
	RA_PIO_24_39_SET_BIT,
	{ GPIO_OUTPUT_PIN_MASK_24_51,    RA_PIO_24_39_DIR,         },
	{ GPIO_INT_PIN_MASK_24_51,       RA_PIO_24_39_INT_RISE_EN, },
	{ GPIO_INT_FEDGE_PIN_MASK_24_51, RA_PIO_24_39_INT_FALL_EN, },
	{ GPIO_POL_MASK_24_51,           RA_PIO_24_39_POLARITY,    },
    },
    {
	40, 52, 24, GPIO_PIN_MASK_24_51,
	RA_PIO_40_51_DATA,
	RA_PIO_40_51_CLR_BIT,
	RA_PIO_40_51_SET_BIT,
	{ GPIO_OUTPUT_PIN_MASK_24_51,    RA_PIO_40_51_DIR,         },
	{ GPIO_INT_PIN_MASK_24_51,       RA_PIO_40_51_INT_RISE_EN, },
	{ GPIO_INT_FEDGE_PIN_MASK_24_51, RA_PIO_40_51_INT_FALL_EN, },
	{ GPIO_POL_MASK_24_51,           RA_PIO_40_51_POLARITY,    },
    },
#if defined(SLICKROCK)
    {
	72, 96, 72, GPIO_PIN_MASK_72_95,
	RA_PIO_72_95_DATA,
	RA_PIO_72_95_CLR_BIT,
	RA_PIO_72_95_SET_BIT,
	{ GPIO_OUTPUT_PIN_MASK_72_95,    RA_PIO_72_95_DIR,         },
	{ GPIO_INT_PIN_MASK_72_95,       RA_PIO_72_95_INT_RISE_EN, },
	{ GPIO_INT_FEDGE_PIN_MASK_72_95, RA_PIO_72_95_INT_FALL_EN, },
	{ GPIO_POL_MASK_72_95,           RA_PIO_72_95_POLARITY,    },
    },
#endif
};

/*
 * use pin_tab_index[] to determine index in pin_tab[]
 * for a given pin.  -1 means there is no pin there.
 */
static const int pin_tab_index[GPIO_PINS] = {
/*		 0   1   2   3   4   5   6   7   8   9	*/
/*  0 */	 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
/* 10 */	 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
/* 20 */	 0,  0,  0,  0,  1,  1,  1,  1,  1,  1,
/* 30 */	 1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
/* 40 */	 2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
/* 50 */	 2,  2,
#if defined(SLICKROCK)
/* 50 */	        -1, -1, -1, -1, -1, -1, -1, -1,
/* 60 */	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
/* 70 */	-1, -1,
/* 72 */	         3,  3,  3,  3,  3,  3,  3,  3,
/* 80 */	 3,  3,  3,  3,  3,  3,  3,  3,  3,  3,
/* 90 */	 3,  3,  3,  3,  3,  3
#endif
};

CFATTACH_DECL_NEW(rgpio, sizeof(struct ra_gpio_softc), ra_gpio_match,
	ra_gpio_attach, NULL, NULL);

/*
 * Event handler calls and structures
 */
static int  gpio_event_app_user_attach(struct knote *);
static void gpio_event_app_user_detach(struct knote *);
static int  gpio_event_app_user_event(struct knote *, long);

static struct klist knotes;
static int app_filter_id;
static struct filterops app_fops = {
	0,
	gpio_event_app_user_attach,
	gpio_event_app_user_detach,
	gpio_event_app_user_event
};
static struct callout led_tick_callout;
static int gpio_driver_blink_leds = 1;

static inline uint32_t
sy_read(ra_gpio_softc_t *sc, bus_size_t off)
{
	KASSERTMSG((off & 3) == 0, ("%s: unaligned off=%#" PRIxBUSSIZE "\n",
		__func__, off));
	return bus_space_read_4(sc->sc_memt, sc->sc_sy_memh, off);
}

static inline void
sy_write(ra_gpio_softc_t *sc, bus_size_t off, uint32_t val)
{
	KASSERTMSG((off & 3) == 0, ("%s: unaligned off=%#" PRIxBUSSIZE "\n",
		__func__, off));
	bus_space_write_4(sc->sc_memt, sc->sc_sy_memh, off, val);
}

static inline uint32_t
gp_read(ra_gpio_softc_t *sc, bus_size_t off)
{
	KASSERTMSG((off & 3) == 0, ("%s: unaligned off=%#" PRIxBUSSIZE "\n",
		__func__, off));
	return bus_space_read_4(sc->sc_memt, sc->sc_gp_memh, off);
}

static inline void
gp_write(ra_gpio_softc_t *sc, bus_size_t off, uint32_t val)
{
	KASSERTMSG((off & 3) == 0, ("%s: unaligned off=%#" PRIxBUSSIZE "\n",
		__func__, off));
	bus_space_write_4(sc->sc_memt, sc->sc_gp_memh, off, val);
}

/*
 * Basic debug function, dump all PIO registers
 */
#if 0
static void
gpio_register_dump(ra_gpio_softc_t *sc)
{
	for (int i=0; i < 0xb0; i+=4)
		RALINK_DEBUG(RALINK_DEBUG_INFO, "Reg: 0x%x, Value: 0x%x\n",
			(RA_PIO_BASE + i), gp_read(sc, i));
}
#endif

static void
gpio_reset_registers(ra_gpio_softc_t *sc)
{
#if 0
	for (int i=0; i < 0x88; i+=4)
		gp_write(sc, i, 0);
#endif
}


static int
ra_gpio_match(device_t parent, cfdata_t cf, void *aux)
{
	RALINK_DEBUG_FUNC_ENTRY();

	return 1;
}

static void
ra_gpio_attach(device_t parent, device_t self, void *aux)
{

	struct gpiobus_attach_args gba;
	ra_gpio_softc_t * const sc = device_private(self);
	const struct mainbus_attach_args *ma = aux;
	int error;

	aprint_naive(": Ralink GPIO controller\n");
	aprint_normal(": Ralink GPIO controller\n");

	sc->sc_dev = self;
	sc->sc_memt = ma->ma_memt;
	sc->sc_sy_size = 0x10000;
	sc->sc_gp_size = 0x1000;

	/*
	 * map the registers
	 *
	 * we map the Sysctl, and PIO registers seperately so we can use the
	 * defined register offsets sanely; just use the correct corresponding
	 * bus_space_handle
	 */

	if ((error = bus_space_map(sc->sc_memt, RA_SYSCTL_BASE,
	    sc->sc_sy_size, 0, &sc->sc_sy_memh)) != 0) {
		aprint_error_dev(sc->sc_dev,
			"unable to map Sysctl registers, error=%d\n", error);
		goto fail_0;
	}

	if ((error = bus_space_map(sc->sc_memt, RA_PIO_BASE,
	    sc->sc_gp_size, 0, &sc->sc_gp_memh)) != 0) {
		aprint_error_dev(sc->sc_dev,
			"unable to map PIO registers, error=%d\n", error);
		goto fail_1;
	}

	/* Reset some registers */
	gp_write(sc, RA_PIO_00_23_INT, 0xffffff);
	gp_write(sc, RA_PIO_00_23_EDGE_INT, 0xffffff);
	gp_write(sc, RA_PIO_24_39_INT, 0xffff);
	gp_write(sc, RA_PIO_24_39_EDGE_INT, 0xffff);
	gp_write(sc, RA_PIO_40_51_INT, 0xfff);
	gp_write(sc, RA_PIO_40_51_EDGE_INT, 0xfff);
	gp_write(sc, RA_PIO_00_23_POLARITY, 0);
#if defined(SLICKROCK)
	gp_write(sc, RA_PIO_72_95_INT, 0xffffff);
	gp_write(sc, RA_PIO_72_95_EDGE_INT, 0xffffff);
#endif

	/* Set up for interrupt handling, low priority interrupt queue */
	sc->sc_ih = ra_intr_establish(RA_IRQ_PIO,
		ra_gpio_intr, sc, 0);
	if (sc->sc_ih == NULL) {
		RALINK_DEBUG(RALINK_DEBUG_ERROR,
			"%s: unable to establish interrupt\n",
			sc->sc_dev->dv_xname);
		goto fail_2;
	}

	/* Soft int setup */
	sc->sc_si = softint_establish(SOFTINT_BIO, ra_gpio_softintr, sc);
	if (sc->sc_si == NULL) {
		ra_intr_disestablish(sc->sc_ih);
		RALINK_DEBUG(RALINK_DEBUG_ERROR,
			"%s: unable to establish soft interrupt\n",
			sc->sc_dev->dv_xname);
		goto fail_3;
	}

	SLIST_INIT(&knotes);
	if (kfilter_register("CP_GPIO_EVENT", &app_fops, &app_filter_id) != 0) {
		RALINK_DEBUG(RALINK_DEBUG_ERROR,
			"%s: kfilter_register for CP_GPIO_EVENT failed\n",
			__func__);
		goto fail_4;
	}

	sc->sc_gc.gp_cookie = sc;
	sc->sc_gc.gp_pin_read = ra_gpio_pin_read;
	sc->sc_gc.gp_pin_write = ra_gpio_pin_write;
	sc->sc_gc.gp_pin_ctl = ra_gpio_pin_ctl;

#if 0
	gpio_register_dump(sc);
#endif
	gpio_reset_registers(sc);

	/* Initialize the GPIO pins */
	for (int pin=0; pin < GPIO_PINS; pin++)
		ra_gpio_pin_init(sc, pin);

#if 0
	/* debug check */
	KASSERT((sy_read(sc, RA_SYSCTL_GPIOMODE) == 0x31c) != 0);
	RALINK_DEBUG(RALINK_DEBUG_INFO, "SYSCTL_GPIOMODE = 0x%x\n",
		sy_read(sc, RA_SYSCTL_GPIOMODE));
#endif

	/*
	 * Some simple board setup actions:
	 * Check if we're attached to the dock. If so, enable dock power.
	 *  BIG NOTE: Dock power is dependent on USB5V_EN!
	 */
#if defined(PEBBLES500) || defined (PEBBLES35)
	RALINK_DEBUG(RALINK_DEBUG_INFO, "Enabling USB power\n");
	ra_gpio_pin_write(sc, VBUS_EN, 1);
	ra_gpio_pin_write(sc, POWER_EN_USB, 1);
#if defined(PEBBLES500)
	/*
	 * Is an express card attached? Enable power if it is
	 *  or it isn't
	 */
#if 0
	if (ra_gpio_pin_read(sc, EXCARD_ATTACH) == 0) {
#endif
		ra_gpio_pin_write(sc, POWER_EN_EXCARD1_3_3v, 1);
		ra_gpio_pin_write(sc, POWER_EN_EXCARD1_1_5v, 1);
#if 0
	}
#endif	/* 0 */
#endif	/* PEBBLES500 */
#endif	/* PEBBLES500 || PEBBLES35 */

#if defined(TABLEROCK) || defined(SPOT2) || defined(PUCK) || defined(MOAB)
	/* CHARGER_OFF pin matches the IN_5V */
	if (ra_gpio_pin_read(sc, IN_5V) == 0) {
		ra_gpio_pin_write(sc, CHARGER_OFF, 0);
	} else {
		ra_gpio_pin_write(sc, CHARGER_OFF, 1);
	}
#endif

#if defined(SLICKROCK)
	/* Enable all modem slots */
	ra_gpio_pin_write(sc, POWER_EN_USB1, 1);
	ra_gpio_pin_write(sc, POWER_EN_USB2, 1);
	ra_gpio_pin_write(sc, POWER_EN_USB3, 1);
	ra_gpio_pin_write(sc, POWER_EN_EX1, 1);
	ra_gpio_pin_write(sc, EX1_CPUSB_RST, 0);
	ra_gpio_pin_write(sc, POWER_EN_EX2, 1);
	ra_gpio_pin_write(sc, EX2_CPUSB_RST, 0);

	/* Wake up with an overcurrent on EX1. Try to shut it down. */
	gp_write(sc, RA_PIO_72_95_INT, 0xffffff);
	gp_write(sc, RA_PIO_72_95_EDGE_INT, 0xffffff);
#endif

	sc->sc_pins[BOOT_COUNT].pin_flags = GPIO_PIN_OUTPUT;
	sc->sc_pins[BOOT_COUNT].pin_mapped = 0;
	sc->sc_pins[UPGRADE].pin_flags = GPIO_PIN_OUTPUT;
	sc->sc_pins[UPGRADE].pin_mapped = 0;
	gba.gba_gc = &sc->sc_gc;
	gba.gba_pins = sc->sc_pins;

	/* Note, > 52nd pin isn't a gpio, it is a special command */
	gba.gba_npins = (GPIO_PINS + SPECIAL_COMMANDS);

	config_found_ia(sc->sc_dev, "gpiobus", &gba, gpiobus_print);

#if 0
	gpio_register_dump(sc);
#endif

	/* init our gpio debounce */
	callout_init(&sc->sc_tick_callout, 0);
	callout_setfunc(&sc->sc_tick_callout, ra_gpio_debounce_process, sc);

	/* LED blinking during boot */
	callout_init(&led_tick_callout, 0);

	ra_gpio_toggle_LED(sc);
	return;

 fail_4:
	softint_disestablish(sc->sc_si);
 fail_3:
	ra_intr_disestablish(sc->sc_ih);
 fail_2:
	bus_space_unmap(sc->sc_memt, sc->sc_gp_memh, sc->sc_sy_size);
 fail_1:
	bus_space_unmap(sc->sc_memt, sc->sc_sy_memh, sc->sc_sy_size);
 fail_0:
	return;
}

/*
 * ra_gpio_pin_init - initialize the given gpio pin
 */
static void
ra_gpio_pin_init(ra_gpio_softc_t *sc, int pin)
{
	u_int gpio_mode;
	uint32_t r;

	sc->sc_pins[pin].pin_caps = 0;
	sc->sc_pins[pin].pin_flags = 0;
	sc->sc_pins[pin].pin_state = 0;
	sc->sc_pins[pin].pin_mapped = 0;

	/* ensure pin number is in range */
	KASSERT(pin < GPIO_PINS);
	if (pin >= GPIO_PINS)
		return;

	/* if pin number is in a gap in the range, just return */
	const int index = pin_tab_index[pin];
	if (index == -1)
		return;

	/* if pin is not enabled, just return */
	const pin_tab_t * const ptp = &pin_tab[index];
	const u_int mask_bit = 1 << (pin - ptp->pin_mask_base);
	if ((ptp->pin_enabled & mask_bit) == 0)
		return;

	sc->sc_pins[pin].pin_caps = GPIO_PIN_INPUT | GPIO_PIN_OUTPUT |
	    GPIO_PIN_INVIN | GPIO_PIN_INVOUT;
	sc->sc_pins[pin].pin_state = GPIO_PIN_INPUT;
	gpio_mode = 0;

#if defined(SLICKROCK)
	r = sy_read(sc, RA_SYSCTL_GPIOMODE);
	r |= SR_GPIO_MODE;
	sy_write(sc, RA_SYSCTL_GPIOMODE, r);
#else
	/*
	 * Set the SYSCTL_GPIOMODE register to 1 for
	 * the PIO block of any mapped GPIO
	 * (most have reset defaults of 1 already).
	 * GPIO0 doesn't have an associated MODE register.
	 */
	if (pin != 0) {
		for (gpio_mode=0; gpio_mode < GPIO_MODE_SETTINGS; gpio_mode++) {
			if (pin <= pin_share[gpio_mode]) {
				r = sy_read(sc, RA_SYSCTL_GPIOMODE);
				if (10 == pin) {
					/*
					 * Special case:
					 *   GPIO 10 requires GPIOMODE_UARTF0-2
					 */
					r |= GPIOMODE_UARTF_0_2;
				} else {
					/* standard case */
					r |= (1 << gpio_mode);
				}
				sy_write(sc, RA_SYSCTL_GPIOMODE, r);
				break;
			}
		}
	}
#endif

	/* set direction */
	RA_GPIO_PIN_INIT_DIR(sc, r, pin, ptp);

	/* rising edge interrupt */
	RA_GPIO_PIN_INIT(sc, r, pin, ptp, pin_rise);

	/* falling edge interrupt */
	RA_GPIO_PIN_INIT(sc, r, pin, ptp, pin_fall);

	/* polarirty */
	RA_GPIO_PIN_INIT(sc, r, pin, ptp, pin_pol);
}

/*
 * Note: This has special hacks in it. If pseudo-pin BOOT_COUNT
 * is requested, it is a signal check the memo register for a special key
 * that means run Wi-Fi in no security mode.
 */
int
ra_gpio_pin_read(void *arg, int pin)
{
	RALINK_DEBUG_FUNC_ENTRY();
	const ra_gpio_softc_t * const sc = arg;
	int rv;

	KASSERT(sc != NULL);

	if (pin < GPIO_PINS) {
		/*
		 * normal case: a regular GPIO pin
		 * if pin number is in a gap in the range,
		 * then warn and return 0
		 */
		const int index = pin_tab_index[pin];
		KASSERTMSG(index != -1, ("%s: non-existant pin=%d\n",
			__func__, pin));
		if (index == -1) {
			rv = 0;
		} else {
			const pin_tab_t * const ptp = &pin_tab[index];
			const uint32_t reg_bit = 1 << (pin - ptp->pin_reg_base);
			const bus_size_t off = ptp->pin_input;
			uint32_t r;

			r = bus_space_read_4(sc->sc_memt, sc->sc_gp_memh, off);
			rv = ((r & (1 << reg_bit)) != 0);
		}
	} else {
		/*
		 * Special hack: a pseudo-pin used for signaling
		 */
		rv = 0;
		switch(pin) {
		case BOOT_COUNT:
			if (1 == ra_check_memo_reg(NO_SECURITY))
				rv = 1;
			break;
		default:
#ifdef DIAGNOSTIC
			aprint_normal_dev(sc->sc_dev, "%s: bad pin=%d\n",
				__func__, pin);
#endif
			break;
		}
	}

	RALINK_DEBUG_0(RALINK_DEBUG_INFO, "pin %d, value %x\n", pin, rv);
	return rv;
}

/*
 * There are three ways to change the value of a pin.
 *   You can write to the DATA register, which will set
 *   or reset a pin.  But you need to store it locally and
 *   read/mask/set it, which is potentially racy without locks.
 *   There are also SET and RESET registers, which allow you to write
 *   a value to a single pin and not affect any other pins
 *   by accident.
 *
 * NOTE:  This has special hacks in it.  If pin 52 (which does not exist)
 * is written, it is a signal to clear the boot count register.  If pin
 * 53 is written, it is a upgrade signal to the bootloader.
 *
 */
#define MAGIC		0x27051956
#define UPGRADE_MAGIC	0x27051957
void
ra_gpio_pin_write(void *arg, int pin, int value)
{
	RALINK_DEBUG_FUNC_ENTRY();
	ra_gpio_softc_t * const sc = arg;
	uint32_t r;

	KASSERT(sc != NULL);
	RALINK_DEBUG(RALINK_DEBUG_INFO, "pin %d, val %d\n", pin, value);

	if (pin >= GPIO_PINS) {
		/*
		 * Special hack: a pseudo-pin used for signaling
		 */
		switch(pin) {
		case BOOT_COUNT:
			/* Reset boot count */
			r = sy_read(sc, RA_SYSCTL_MEMO0);
			if (r == MAGIC)
				sy_write(sc, RA_SYSCTL_MEMO1, 0);
			break;
		case UPGRADE:
			/* Set upgrade flag */
			sy_write(sc, RA_SYSCTL_MEMO0, UPGRADE_MAGIC);
			sy_write(sc, RA_SYSCTL_MEMO1, UPGRADE_MAGIC);
			break;
		default:
#ifdef DIAGNOSTIC
			aprint_normal_dev(sc->sc_dev, "%s: bad pin=%d\n",
				__func__, pin);
#endif
		}
		return;
	}
	
	/*
	 * normal case: a regular GPIO pin
	 * if pin number is in a gap in the range,
	 * then warn and return
	 */
	const int index = pin_tab_index[pin];
	KASSERTMSG(index != -1, ("%s: non-existant pin=%d\n", __func__, pin));
	if (index == -1)
		return;

	const pin_tab_t * const ptp = &pin_tab[index];
	const u_int mask_bit = 1 << (pin - ptp->pin_mask_base);
	const uint32_t reg_bit = 1 << (pin - ptp->pin_reg_base);
	const bus_size_t off = (value == 0) ?
		ptp->pin_output_clr : ptp->pin_output_set;

	if ((ptp->pin_dir.mask & mask_bit) == 0) {
#ifdef DIAGNOSTIC
		aprint_normal_dev(sc->sc_dev,
			"%s: Writing non-output pin: %d\n", __func__, pin);
#endif
		return;
	}

	bus_space_write_4(sc->sc_memt, sc->sc_gp_memh, off, reg_bit);
}

static void
ra_gpio_pin_ctl(void *arg, int pin, int flags)
{
	RALINK_DEBUG_FUNC_ENTRY();

	/*
	 * For now, this lets us know that user-space is using the GPIOs
	 *  and the kernel shouldn't blink LEDs any more
	 */
	gpio_driver_blink_leds = 0;
}

/*
 *  Check the three interrupt registers and ack them
 *   immediately.  If a button is pushed, use the
 *   handle_key_press call to debounce it.  Otherwise,
 *   call the softint handler to send any necessary
 *   events.
 */
static int
ra_gpio_intr(void *arg)
{
	RALINK_DEBUG_FUNC_ENTRY();
	ra_gpio_softc_t * const sc = arg;

#if 0
	/* Read the 3 interrupt registers */
	if (sc->sc_intr_status00_23 || sc->sc_intr_status24_39 ||
	    sc->sc_intr_status40_51) {
		printf("\n0-23 %x, 24-39 %x, 40_51 %x\n",
			sc->sc_intr_status00_23,
			sc->sc_ntr_status24_39, 
			sc->sc_ntr_status40_51);
	}
#endif

	sc->sc_intr_status00_23 |= gp_read(sc, RA_PIO_00_23_INT);
	sc->sc_intr_status24_39 |= gp_read(sc, RA_PIO_24_39_INT);
	sc->sc_intr_status40_51 |= gp_read(sc, RA_PIO_40_51_INT);
#if defined(SLICKROCK)
	sc->sc_intr_status72_95 |= gp_read(sc, RA_PIO_72_95_INT);
#endif

#if 0
	/* Trivial error checking, some interrupt had to have fired */
	KASSERT((sc->sc_intr_status00_23 | sc->sc_intr_status24_39 |
		sc->sc_intr_status40_51) != 0);
#endif

	/* Debounce interrupt */
	ra_gpio_debounce_setup(sc);

	/*
	 * and ACK the interrupt.
	 *  OR the values in case the softint handler hasn't
	 *  been scheduled and handled any previous int
	 *  I don't know if resetting the EDGE register is
	 *  necessary, but the Ralink Linux driver does it.
	 */
	gp_write(sc, RA_PIO_00_23_INT, sc->sc_intr_status00_23);
	gp_write(sc, RA_PIO_00_23_EDGE_INT, sc->sc_intr_status00_23);
	gp_write(sc, RA_PIO_24_39_INT, sc->sc_intr_status24_39);
	gp_write(sc, RA_PIO_24_39_EDGE_INT, sc->sc_intr_status24_39);
	gp_write(sc, RA_PIO_40_51_INT, sc->sc_intr_status40_51);
	gp_write(sc, RA_PIO_40_51_EDGE_INT, sc->sc_intr_status40_51);
#if defined(SLICKROCK)
	gp_write(sc, RA_PIO_72_95_INT, sc->sc_intr_status72_95);
	gp_write(sc, RA_PIO_72_95_EDGE_INT, sc->sc_intr_status72_95);
#endif

	/* Reset until next time */
	sc->sc_intr_status00_23 = 0;
	sc->sc_intr_status24_39 = 0;
	sc->sc_intr_status40_51 = 0;
	sc->sc_intr_status72_95 = 0;

	return 1;
}

/*
 *  Handle key debouncing for the given pin
 */
static bool
ra_gpio_debounce_pin(ra_gpio_softc_t *sc, struct timeval *tv, u_int pin)
{
	RALINK_DEBUG_FUNC_ENTRY();

	/*
	 * If a pin has a time set, it is waiting for
	 *  a debounce period.  Check if it is ready
	 *  to send its event and clean up.  Otherwise,
	 *  reschedule 10mSec and try again later.
	 */
	if (0 != debounce_time[pin].tv_sec) {
		if (timercmp(tv, &debounce_time[pin], <)) {
			/*
			 * Haven't hit debounce time,
			 * need to reschedule
			 */
			return true;
		}
#if defined(SLICKROCK)
		switch (debounce_pin[pin]) {
		case SOFT_RST_IN_BUTTON:
			KNOTE(&knotes, RESET_BUTTON_EVT);
			break;
			
		case SS_BUTTON:
			KNOTE(&knotes, SS_BUTTON_EVT);
			break;
			
		case WPS_BUTTON:
			KNOTE(&knotes, WPS_BUTTON_EVT);
			break;
			
		case WIFI_ENABLE:
			KNOTE(&knotes, WIFI_ENABLE_EVT);
			break;
			
		/*
		 * These events are in case of overcurrent
		 * on USB/ExpressCard devices.
		 * If we receive an overcurrent signal,
		 * turn off power to the device and
		 * let the USB driver know.
		 */
		case CURRENT_LIMIT_FLAG_USB1:
			ra_gpio_pin_write(sc, POWER_EN_USB1, 0);
			KNOTE(&knotes, CURRENT_LIMIT_EVT);
#if 0
			cpusb_overcurrent_occurred(CURRENT_LIMIT_FLAG_USB1);
#endif
			printf("\nUSB1 current limit received!\n");
			break;

		case CURRENT_LIMIT_FLAG_USB2:
			ra_gpio_pin_write(sc, POWER_EN_USB2, 0);
			KNOTE(&knotes, CURRENT_LIMIT_EVT);
#if 0
			cpusb_overcurrent_occurred(CURRENT_LIMIT_FLAG_USB2);
#endif
			printf("\nUSB2 current limit received!\n");
			break;

		case CURRENT_LIMIT_FLAG_USB3:
			ra_gpio_pin_write(sc, POWER_EN_USB3, 0);
			KNOTE(&knotes, CURRENT_LIMIT_EVT);
#if 0
			cpusb_overcurrent_occurred(CURRENT_LIMIT_FLAG_USB3);
#endif
			printf("\nUSB3 current limit received!\n");
			break;

		case CURRENT_LIMIT_FLAG_EX1:
			ra_gpio_pin_write(sc, POWER_EN_EX1, 0);
			KNOTE(&knotes, CURRENT_LIMIT_EVT);
#if 0
			cpusb_overcurrent_occurred(debounce_pin[pin]);
#endif
			printf("\nExpressCard1 current limit received!\n");
			break;

		case CURRENT_LIMIT_FLAG_EX2:
			ra_gpio_pin_write(sc, POWER_EN_EX2, 0);
			KNOTE(&knotes, CURRENT_LIMIT_EVT);
#if 0
			cpusb_overcurrent_occurred(debounce_pin[pin]);
#endif
			printf("\nExpressCard2 current limit received!\n");
			break;

		default:
			printf("\nUnknown debounce pin %d received.\n",
				debounce_pin[pin]);
		}
#endif/* SLICKROCK */
#if defined(PEBBLES500) || defined(PEBBLES35)
		switch (debounce_pin[pin]) {
		case SOFT_RST_IN_BUTTON:
			KNOTE(&knotes, RESET_BUTTON_EVT);
			break;
			
		case WPS_BUTTON:
			KNOTE(&knotes, WPS_BUTTON_EVT);
			break;
			
		case EXCARD_ATTACH:
			KNOTE(&knotes, EXCARD_ATTACH_EVT);
			break;
			
		/*
		 * These events are in case of overcurrent
		 * on USB/ExpressCard devices.
		 * If we receive an overcurrent signal,
		 * turn off power to the device and
		 * let the USB driver know.
		 */
		case CURRENT_LIMIT_FLAG_USB1:
			ra_gpio_pin_write(sc, POWER_EN_USB, 0);
			KNOTE(&knotes, CURRENT_LIMIT_EVT);
			cpusb_overcurrent_occurred(CURRENT_LIMIT_FLAG_USB1);
			printf("\nUSB current limit received!\n");
			break;

		/*
		 * If either voltage is over current,
		 * turn off all ExpressCard power
		 */
		case CURRENT_LIMIT_FLAG1_3_3v:
		case CURRENT_LIMIT_FLAG1_1_5v:
			ra_gpio_pin_write(sc, POWER_EN_EXCARD1_3_3v, 0);
			ra_gpio_pin_write(sc, POWER_EN_EXCARD1_1_5v, 0);				
			KNOTE(&knotes, CURRENT_LIMIT_EVT);
			cpusb_overcurrent_occurred(debounce_pin[pin]);
			printf("\nExpressCard current limit received!\n");
			break;

		default:
			printf("\nUnknown debounce pin received.\n");
		}
#endif/* PEBBLES500 || PEBBLES35 */
#if defined(TABLEROCK) || defined(SPOT2) || defined(PUCK) || defined(MOAB)
		if (POWER_OFF_BUTTON == debounce_pin[pin]) {
			KNOTE(&knotes, POWER_BUTTON_EVT);
		}
		if (LAN_WAN_SW == debounce_pin[pin]) {
			KNOTE(&knotes, LAN_WAN_SW_EVT);
		}
		if (DOCK_SENSE == debounce_pin[pin]) {
			KNOTE(&knotes, DOCK_SENSE_EVT);
		}
		if (WPS_BUTTON == debounce_pin[pin]) {
			KNOTE(&knotes, WPS_BUTTON_EVT);
		}
		if (IN_5V == debounce_pin[pin]) {
			/* Set the charger to match the in 5V line */
			if (ra_gpio_pin_read(sc, IN_5V) == 0) {
				ra_gpio_pin_write(sc, CHARGER_OFF, 0);
			} else {
				ra_gpio_pin_write(sc, CHARGER_OFF, 1);
			}
			KNOTE(&knotes, IN_5V_EVT);
		}
#endif/* TABLEROCK || SPOT2 || PUCK || MOAB */
		/* Re-enable interrupt and reset time */
		enable_gpio_interrupt(sc, debounce_pin[pin]);
		debounce_time[pin].tv_sec = 0;

	}
	return false;
}

/*
 *  Handle key debouncing.
 *  Re-enable the key interrupt after DEBOUNCE_TIME
 */
static void
ra_gpio_debounce_process(void *arg)
{
	RALINK_DEBUG_FUNC_ENTRY();
	ra_gpio_softc_t * const sc = arg;
	bool reschedule = false;
	struct timeval now;

	microtime(&now);

	for (u_int pin=0; pin < __arraycount(debounce_pin); pin++)
		if (ra_gpio_debounce_pin(sc, &now, pin))
			reschedule = true;

	if (reschedule)
		callout_schedule(&sc->sc_tick_callout, MS_TO_HZ(10));
}

/*
 * Handle key and other interrupt debouncing.
 */
static void
ra_gpio_debounce_setup(ra_gpio_softc_t *sc)
{
	RALINK_DEBUG_FUNC_ENTRY();
	u_int32_t pin;
	struct timeval now;
	struct timeval wait = {
		.tv_sec  = 0,
		.tv_usec = (DEBOUNCE_TIME * 1000)
	};

	/*
	 * The 371/372 series are a bit more complex.  They have
	 *  interrupt sources across all three interrupt
	 *  registers.
	 */
	for (int i=0; i < __arraycount(debounce_pin); i++) {
		u_int32_t *intr_status;
		int offset;
		if (debounce_pin[i] < 24) {
			intr_status = &sc->sc_intr_status00_23;
			offset = 0;
		} else if (debounce_pin[i] < 40) {
			intr_status = &sc->sc_intr_status24_39;
			offset = 24;
		} else if (debounce_pin[i] < 71) {
			intr_status = &sc->sc_intr_status40_51;
			offset = 40;
		} else {
			intr_status = &sc->sc_intr_status72_95;
			offset = 72;
		}
		if (*intr_status & (1 << (debounce_pin[i] - offset))) {
			pin = debounce_pin[i];

#ifdef ENABLE_RALINK_DEBUG_INFO
			if (ra_gpio_pin_read(sc, pin)) {
				RALINK_DEBUG(RALINK_DEBUG_INFO,
					"%s() button 0x%x, pin %d released\n",
					__func__, *intr_status, pin);
			} else {
				RALINK_DEBUG(RALINK_DEBUG_INFO,
					"%s() button 0x%x, pin %d pressed\n",
					__func__, *intr_status, pin);
			}
#endif

#if 0
			/* Mask pin that is being handled */
			*intr_status &= ~((1 << (debounce_pin[i] - offset)));
#endif

			/* Handle debouncing. */
			disable_gpio_interrupt(sc, pin);
			microtime(&now);

#if defined(TABLEROCK)
			/*
			 * The dock's LAN_WAN switch can cause a fire of
			 * interrupts if it sticks in the half-way position.
			 * Ignore it for longer than other buttons.
			 */
			if (pin == LAN_WAN_SW) {
				wait.tv_usec *= 2;
			}
#endif

			timeradd(&now, &wait, &debounce_time[i]);
		}
	}

	/* If the debounce callout hasn't been scheduled, start it up. */
	if (FALSE == callout_pending(&sc->sc_tick_callout)) {
		callout_schedule(&sc->sc_tick_callout, MS_TO_HZ(DEBOUNCE_TIME));
	}
}

/*
 * Disable both rising and falling
 */
static void
disable_gpio_interrupt(ra_gpio_softc_t *sc, int pin)
{
	RALINK_DEBUG_FUNC_ENTRY();
	const int index = pin_tab_index[pin];
	KASSERTMSG(index != -1, ("%s: non-existant pin=%d\n", __func__, pin));
	if (index == -1)
		return;

	const pin_tab_t * const ptp = &pin_tab[index];
	const uint32_t reg_bit = 1 << (pin - ptp->pin_reg_base);
	uint32_t r;

	r = gp_read(sc, ptp->pin_rise.reg);
	r &= ~reg_bit;
	gp_write(sc, ptp->pin_rise.reg, r);

	r = gp_read(sc, ptp->pin_fall.reg);
	r &= ~reg_bit;
	gp_write(sc, ptp->pin_fall.reg, r);
}

/*
 * Restore GPIO interrupt setting
 */
static void
enable_gpio_interrupt(ra_gpio_softc_t *sc, int pin)
{
	const int index = pin_tab_index[pin];
	KASSERTMSG(index != -1, ("%s: non-existant pin=%d\n", __func__, pin));
	if (index == -1)
		return;

	const pin_tab_t * const ptp = &pin_tab[index];
        const uint32_t mask_bit = 1 << (pin - ptp->pin_mask_base);
        const uint32_t reg_bit = 1 << (pin - ptp->pin_reg_base);
	uint32_t r;

	if (ptp->pin_rise.mask & mask_bit) {
		r = gp_read(sc, ptp->pin_rise.reg);
		r |= reg_bit;
		gp_write(sc, ptp->pin_rise.reg, r);
	}

	if (ptp->pin_fall.mask & mask_bit) {
		r = gp_read(sc, ptp->pin_fall.reg);
		r |= reg_bit;
		gp_write(sc, ptp->pin_fall.reg, r);
	}
}

/*
 * XXX this function is obsolete/unused? XXX
 *
 *  Go through each of the interrupts and send the appropriate
 *   event.
 */
static void
ra_gpio_softintr(void *arg)
{
	RALINK_DEBUG(RALINK_DEBUG_INFO,
		"gpio softintr called with 0x%x, 0x%x, 0x%x, 0x%x\n",
		sc->sc_intr_status00_23, sc->sc_intr_status24_39,
		sc->sc_intr_status40_51, sc->sc_intr_status72_95);
}

/*
 * gpio_event_app_user_attach - called when knote is ADDed
 */
static int
gpio_event_app_user_attach(struct knote *kn)
{
	RALINK_DEBUG_0(RALINK_DEBUG_INFO, "%s() %p\n", __func__, kn);

	if (NULL == kn) {
		RALINK_DEBUG(RALINK_DEBUG_ERROR, "Null kn found\n");
		return 0;
	}

	kn->kn_flags |= EV_CLEAR;       /* automatically set */
	SLIST_INSERT_HEAD(&knotes, kn, kn_selnext);

	return 0;
}

/*
 * gpio_event_app_user_detach - called when knote is DELETEd
 */
static void
gpio_event_app_user_detach(struct knote *kn)
{
	RALINK_DEBUG_0(RALINK_DEBUG_INFO, "%s() %p\n", __func__, kn);
	if (NULL == kn) {
		RALINK_DEBUG(RALINK_DEBUG_ERROR, "Null kn found\n");
		return;
	}
	SLIST_REMOVE(&knotes, kn, knote, kn_selnext);
}

/*
 * gpio_event_app_user_event - called when event is triggered
 */
static int
gpio_event_app_user_event(struct knote *kn, long hint)
{
	RALINK_DEBUG_0(RALINK_DEBUG_INFO, "%s() %p hint: %ld\n", __func__, kn, hint);

	if (NULL == kn) {
		RALINK_DEBUG(RALINK_DEBUG_ERROR, "Null kn found\n");
		return 0;
	}

	if (hint != 0) {
		kn->kn_data = kn->kn_sdata;
		kn->kn_fflags |= hint;
	}

	return 1;
}

/*
 *  Blinky light control during boot.
 *  This marches through the SS/BATT LEDS
 *  to give an indication something is going on.
 */
void
ra_gpio_toggle_LED(void *arg)
{
	RALINK_DEBUG_FUNC_ENTRY();
	ra_gpio_softc_t * const sc = arg;
	static int led_index = 0;
	static int led_timing_hack = 1;

	if ((led_timing_hack >= 6) ||
		(0 == gpio_driver_blink_leds)) {
		/* We're out of boot timing, don't blink LEDs any more */
		return;
	}

#if 0
	/* Disable lit LED */
	gp_write(sc, SET_SS_LED_REG,
		(1 << (led_array1[led_index++] - SS_OFFSET)));
#endif

	if (led_index == (sizeof(led_array1))) {
		led_index = 0;
		for (int i=0; i < sizeof(led_array1); i++) {
			ra_gpio_pin_write(sc, led_array1[i], 1);
		}
	}

	/* Light next LED */
	ra_gpio_pin_write(sc, led_array1[led_index++], 0);

#if 0
	if (led_index == 4) {
		led_timing_hack = 1;
	}
#endif

#ifdef BOOT_LED_TIMING
	/* Setting 3.5 second per LED */
	if ((led_timing_hack) &&
		(led_timing_hack < 6)) {
		led_timing_hack++;
		callout_reset(&led_tick_callout, MS_TO_HZ(BOOT_LED_TIMING),
			ra_gpio_toggle_LED, sc);
	}
#endif
}

File Added: src/sys/arch/mips/ralink/ralink_gpio.h
/*	$NetBSD: ralink_gpio.h,v 1.2 2011/07/28 15:38:49 matt Exp $	*/
/*-
 * Copyright (c) 2011 CradlePoint Technology, Inc.
 * 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, 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 CRADLEPOINT TECHNOLOGY, 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 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.
 */

#ifndef _RALINK_GPIO_H_
#define _RALINK_GPIO_H_

/* ra_gpio.h -- Ralink 3052 gpio driver public defines */

/* Board-specific details */

#if defined(TABLEROCK) || defined(SPOT2) || defined(PUCK) || defined(MOAB)

/*
 * Enable pins:		UART Full, and GPIO0 pins 0-23
 * Rising edge:		three buttons & dock sense
 * Falling edge:	three buttons & dock sense
 */
#define GPIO_TR_PIN_MASK            0x017f81
#define GPIO_TR_OUTPUT_PIN_MASK     0x003b80
#define GPIO_TR_INT_PIN_MASK        0x014401
#define GPIO_TR_INT_FEDGE_PIN_MASK  0x014401 
#define GPIO_TR_POL_MASK            0x000000

/*
 * Enable pins:		RGMII, and SDRAM GPIO pins 24-51
 * Rising edge:		IN_5V, DOCK_SENSE and LAN_WAN_SWITCH
 * Falling edge:	IN_5V, DOCK_SENSE and LAN_WAN_SWITCH
 */
#define GPIO_TR_PIN_MASK_24_51            0x0affff3f
#define GPIO_TR_OUTPUT_PIN_MASK_24_51     0x00ffff07
#define GPIO_TR_INT_PIN_MASK_24_51        0x02000010
#define GPIO_TR_INT_FEDGE_PIN_MASK_24_51  0x02000010
#define GPIO_TR_POL_MASK_24_51            0x00000000

#define WPS_BUTTON          0		/* input, interrupt */

/* UARTF Block */
#define POWER_EN_3G         7
#define POWER_EN_WIMAX      8
#define POWER_ON            9
#define SOFT_RST_IN_BUTTON 10		/* input, interrupt */
#define NC_4               11
#define USB_SW1            12
#define USB_SW2            13
#define POWER_OFF_BUTTON   14		/* input, interrupt */

/* UARTL Block */
#define NC_6               15
#define DOCK_SENSE         16		/* input, interrupt */

/* SDRAM block */
#define DOCK_5V_ENA        24
#define USB5V_EN           25
#define CHARGER_OFF        26		/* 1 : charger on, 0 : charger off */
#define PA_OR_PC_IN        27		/* input */
#define IN_5V              28		/* input, interrupt */
#define CHRGB              29		/* input, NI for P1 board */
#define NC_1               30
#define NC_2               31
#define LED_BATT_7         32
#define LED_BATT_8         33
#define LED_BATT_9         34
#define LED_BATT_10        35
#define LED_SS_11          36
#define LED_SS_12          37
#define LED_SS_13          38
#define LED_SS_14          39

/* RGMII block */
#define LED_WPS            40
#define LED_WIFI           41
#define LED_CHARGE         42
#define LED_POWER          43
#define LED_WIMAX          44
#define LED_3G             45
#define POWER_ON_LATCH     46
#define HUB_RST            47
#define NC_3               48
#define LAN_WAN_SW         49		/* input, interrupt */
#define NC_5               50
#define PUCK_BATTERY_LOW   51

/*
 * Debounced pins:
 *	WPS_BUTTON, POWER_OFF_BUTTON, DOCK_SENSE, IN_5V, LAN_WAN_SW
 */
#define DEBOUNCED_PINS 5

#define GPIO_PIN_MASK GPIO_TR_PIN_MASK
#define GPIO_OUTPUT_PIN_MASK GPIO_TR_OUTPUT_PIN_MASK
#define GPIO_INT_PIN_MASK GPIO_TR_INT_PIN_MASK
#define GPIO_INT_FEDGE_PIN_MASK GPIO_TR_INT_FEDGE_PIN_MASK
#define GPIO_POL_MASK GPIO_TR_POL_MASK

#define GPIO_PIN_MASK_24_51 GPIO_TR_PIN_MASK_24_51
#define GPIO_OUTPUT_PIN_MASK_24_51 GPIO_TR_OUTPUT_PIN_MASK_24_51
#define GPIO_INT_PIN_MASK_24_51 GPIO_TR_INT_PIN_MASK_24_51
#define GPIO_INT_FEDGE_PIN_MASK_24_51 GPIO_TR_INT_FEDGE_PIN_MASK_24_51
#define GPIO_POL_MASK_24_51 GPIO_TR_POL_MASK_24_51

#define GPIO_PIN_MASK_72_95           0
#define GPIO_OUTPUT_PIN_MASK_72_95    0
#define GPIO_INT_PIN_MASK_72_95       0
#define GPIO_INT_FEDGE_PIN_MASK_72_95 0
#define GPIO_POL_MASK_72_95           0

#endif	/* !TABLEROCK */

#if defined(PEBBLES500) || defined(PEBBLES35)

/*
 * Enable pins:		I2C, UART Full, and GPIO0 pins 0-23
 * Rising edge:		?
 * Falling edge:	buttons
 */
#define GPIO_PB500_PIN_MASK            0x005d83
#define GPIO_PB500_OUTPUT_PIN_MASK     0x000083
#define GPIO_PB500_INT_PIN_MASK        0x005c00
#define GPIO_PB500_INT_FEDGE_PIN_MASK  0x000500
#define GPIO_PB500_POL_MASK            0x000000

/* Enable RGMII */
#define P3_HARDWARE
#if defined(P3_HARDWARE)
#define GPIO_PB500_PIN_MASK_24_51            0x03cafe00
#define GPIO_PB500_OUTPUT_PIN_MASK_24_51     0x03c8fe00   
#else
#define GPIO_PB500_PIN_MASK_24_51            0x0fff0000
#define GPIO_PB500_OUTPUT_PIN_MASK_24_51     0x0ffd0000   
#endif
#define GPIO_PB500_INT_PIN_MASK_24_51        0x00020000   /* rising edge ints */
#define GPIO_PB500_INT_FEDGE_PIN_MASK_24_51  0x00020000
#define GPIO_PB500_POL_MASK_24_51            0x00000000

/* I2C block */
#define POWER_EN_EXCARD1_3_3v  1
#define POWER_EN_EXCARD1_1_5v  2

/* UARTF Block */
#define VBUS_EN                    7
#define WPS_BUTTON                 8         /* input, interrupt */
#define SOFT_RST_IN_BUTTON        10         /* input, interrupt */
#define CURRENT_LIMIT_FLAG1_3_3v  11         /* input, interrupt */
#define CURRENT_LIMIT_FLAG_USB1   12         /* input, interrupt */
#define CURRENT_LIMIT_FLAG1_1_5v  14         /* input, interrupt */

/* SDRAM block */
#if defined(P3_HARDWARE)
#define LAN_WAN            33
#define LED_WIFI           34
#define LED_WPS            35
#define LED_USB            36
#define LED_USB_RED        37
#if defined(PEBBLES500)
#define LED_EXP            38
#define LED_EXP_RED        39
#endif
#else	/* P3_HARDWARE */
#define LED_WPS            45
#define LED_WIFI           42
#define LED_USB            40
#define LED_USB_RED        44
#if defined(PEBBLES500)
#define LED_EXP            50
#define LED_EXP_RED        51
#endif
#endif	/* P3_HARDWARE */

/* RGMII block */
#define EXCARD_ATTACH      41         /* input, interrupt */
#define POWER_EN_USB       43
#if defined(PEBBLES500)
#define LED_SS_13          46
#define LED_SS_12          47
#define LED_SS_11          48
#define LED_SS_10          49
#endif

/*
 * Debounced Pins:
 *	WPS_BUTTON, SOFT_RST_IN_BUTTON, CURRENT_LIMIT_FLAG_USB,
 *	CURRENT_LIMIT_FLAG3_3, CURRENT_LIMIT_FLAG1_5, EXCARD_ATTACH
 */
#define DEBOUNCED_PINS 6

#define GPIO_PIN_MASK GPIO_PB500_PIN_MASK
#define GPIO_OUTPUT_PIN_MASK GPIO_PB500_OUTPUT_PIN_MASK
#define GPIO_INT_PIN_MASK GPIO_PB500_INT_PIN_MASK
#define GPIO_INT_FEDGE_PIN_MASK GPIO_PB500_INT_FEDGE_PIN_MASK
#define GPIO_POL_MASK GPIO_PB500_POL_MASK

#define GPIO_PIN_MASK_24_51 GPIO_PB500_PIN_MASK_24_51
#define GPIO_OUTPUT_PIN_MASK_24_51 GPIO_PB500_OUTPUT_PIN_MASK_24_51
#define GPIO_INT_PIN_MASK_24_51 GPIO_PB500_INT_PIN_MASK_24_51
#define GPIO_INT_FEDGE_PIN_MASK_24_51 GPIO_PB500_INT_FEDGE_PIN_MASK_24_51
#define GPIO_POL_MASK_24_51 GPIO_PB500_POL_MASK_24_51

#define GPIO_PIN_MASK_72_95           0
#define GPIO_OUTPUT_PIN_MASK_72_95    0
#define GPIO_INT_PIN_MASK_72_95       0
#define GPIO_INT_FEDGE_PIN_MASK_72_95 0
#define GPIO_POL_MASK_72_95           0

#endif	/*  TABLEROCK || SPOT2 || PUCK || MOAB */

#if defined(SLICKROCK)

/*
 * Enable:	I2C, UART Full, and GPIO0 pins 0-23
 * Rising edge:		buttons, overcurrent, switch
 * Falling edge:	buttons, overcurrent, switch
 */
#define GPIO_SR_PIN_MASK            0x007fcf
#define GPIO_SR_OUTPUT_PIN_MASK     0x00128d
#define GPIO_SR_INT_PIN_MASK        0x006d42
#define GPIO_SR_INT_FEDGE_PIN_MASK  0x006c42
#define GPIO_SR_POL_MASK            0x000002

/* Enable RGMII */
#define GPIO_SR_PIN_MASK_24_51        0x0000387f   
#define GPIO_SR_OUTPUT_PIN_MASK_24_51 0x0000387b   
#define GPIO_SR_INT_PIN_MASK_24_51        0x0004
#define GPIO_SR_INT_FEDGE_PIN_MASK_24_51  0x0004
#define GPIO_SR_POL_MASK_24_51            0x00000000

#define GPIO_SR_PIN_MASK_72_95        0x00000fff   
#define GPIO_SR_OUTPUT_PIN_MASK_72_95 0x00000ff7   
#define GPIO_SR_INT_PIN_MASK_72_95        0x0008
#define GPIO_SR_INT_FEDGE_PIN_MASK_72_95  0x0008
#define GPIO_SR_POL_MASK_72_95            0x00000000

#define LED_USB2_G          0

/* I2C block */
#define WIFI_ENABLE                1
#define EX2_CPUSB_RST              2

/* SPI block */
#define POWER_EN_USB3              3
#define CURRENT_LIMIT_FLAG_USB3    6         /* input, interrupt */

/* UARTF Block */
#define EX1_CPUSB_RST              7
#define SS_BUTTON                  8         /* input, interrupt */
#define POWER_EN_USB1              9
#define SOFT_RST_IN_BUTTON        10         /* input, interrupt */
#define CURRENT_LIMIT_FLAG_USB2   11         /* input, interrupt */
#define POWER_EN_USB2             12
#define CURRENT_LIMIT_FLAG_EX2    13         /* input, interrupt */
					     /*  (pin 76 on P1 boards) */
#define CURRENT_LIMIT_FLAG_USB1   14         /* input, interrupt */

/* GPIO */
#define LED_USB1_G         24
#define LED_USB1_R         25
#define WPS_BUTTON         26
#define LED_EX1_R          27
#define LED_EX2_G          28
#define LED_EX2_R          29
#define LED_WIFI_RED       30

/* LNA_PE_Gx */
#define LED_USB3_G         35
#define LED_USB3_R         36
#define LED_EX1_G          37

/* RGMII2 */
#define POWER_EN_EX1       74
#define CURRENT_LIMIT_FLAG_EX1 75  /* input, interrupt */
#define LED_USB2_R         76
#define POWER_EN_EX2       77
#define LED_POWER          78
#define LED_WPS            79
#define LED_WIFI_BLUE      82
#define LED_WIFI           83

#define LED_SS_10          73
#define LED_SS_11          80
#define LED_SS_12          81
#define LED_SS_13          72

/* Debounced Pins:
 *	WPS_BUTTON, SOFT_RST_IN_BUTTON, SS_BUTTON
 *	CURRENT_LIMIT_FLAG USB * 3 + EXP * 2  
 */
#define DEBOUNCED_PINS 9

#define GPIO_PIN_MASK GPIO_SR_PIN_MASK
#define GPIO_OUTPUT_PIN_MASK GPIO_SR_OUTPUT_PIN_MASK
#define GPIO_INT_PIN_MASK GPIO_SR_INT_PIN_MASK
#define GPIO_INT_FEDGE_PIN_MASK GPIO_SR_INT_FEDGE_PIN_MASK
#define GPIO_POL_MASK GPIO_SR_POL_MASK

#define GPIO_PIN_MASK_24_51 GPIO_SR_PIN_MASK_24_51
#define GPIO_OUTPUT_PIN_MASK_24_51 GPIO_SR_OUTPUT_PIN_MASK_24_51
#define GPIO_INT_PIN_MASK_24_51 GPIO_SR_INT_PIN_MASK_24_51
#define GPIO_INT_FEDGE_PIN_MASK_24_51 GPIO_SR_INT_FEDGE_PIN_MASK_24_51
#define GPIO_POL_MASK_24_51 GPIO_SR_POL_MASK_24_51

#define GPIO_PIN_MASK_72_95 GPIO_SR_PIN_MASK_72_95
#define GPIO_OUTPUT_PIN_MASK_72_95 GPIO_SR_OUTPUT_PIN_MASK_72_95
#define GPIO_INT_PIN_MASK_72_95 GPIO_SR_INT_PIN_MASK_72_95
#define GPIO_INT_FEDGE_PIN_MASK_72_95 GPIO_SR_INT_FEDGE_PIN_MASK_72_95
#define GPIO_POL_MASK_72_95 GPIO_SR_POL_MASK_72_95

#endif	/* SLICKROCK */


/* Exported functions */
extern int ra_gpio_pin_read(void *arg, int pin);
extern void ra_gpio_pin_write(void *arg, int pin, int value);

/* Kernel Events (platform-neutral) */
#define WPS_BUTTON_EVT 1
#define RESET_BUTTON_EVT 2
#define POWER_BUTTON_EVT 3
#define IN_5V_EVT 4
#if 0
#define PWR_FLAG_3G_EVT 5
#endif
#define DOCK_SENSE_EVT 6
#define LAN_WAN_SW_EVT 7
#define WIFI_ENABLE_EVT 8
#define SS_BUTTON_EVT 9
#define CURRENT_LIMIT_EVT 10
#define EXCARD_ATTACH_EVT 11

#endif	/* _RALINK_GPIO_H_ */

File Added: src/sys/arch/mips/ralink/ralink_i2c.c
/*	$NetBSD: ralink_i2c.c,v 1.2 2011/07/28 15:38:49 matt Exp $	*/
/*-
 * Copyright (c) 2011 CradlePoint Technology, Inc.
 * 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, 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 CRADLEPOINT TECHNOLOGY, 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 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.
 */

/* ra_i2c.c - Ralink i2c 3052 driver */

#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ralink_i2c.c,v 1.2 2011/07/28 15:38:49 matt Exp $");

#include <sys/param.h>
#include <sys/bus.h>
#include <sys/device.h>
#include <sys/errno.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/proc.h>
#include <sys/systm.h>

#include <dev/i2c/i2cvar.h>

#include <mips/ralink/ralink_var.h>
#include <mips/ralink/ralink_reg.h>

#if 0
/*
 * Defined for the Ralink 3050, w/320MHz CPU:  milage may vary.
 * Set the I2C clock to 100K bps (low speed) transfer rate.
 * Value is based upon the forms defined in the Ralink reference document
 * for RT3050, page 53.  JCL.
 */
#define CLKDIV_VALUE 533
#endif

/*
 * Slow the I2C bus clock to 12.5 KHz to work around the misbehavior 
 * of the TI part.
 */
#define CLKDIV_VALUE 4264

#define i2c_busy_loop		(clkdiv*30)
#define max_ee_busy_loop	(clkdiv*25)


typedef struct ra_i2c_softc {
	device_t		sc_dev;
	struct i2c_controller	sc_i2c;
	bus_space_tag_t		sc_memt;
	bus_space_handle_t	sc_i2c_memh;
	bus_space_handle_t	sc_sy_memh;
} ra_i2c_softc_t;


static int  ra_i2c_match(struct device *, cfdata_t, void *);
static void ra_i2c_attach(struct device *, struct device *, void *);

/* RT3052 I2C functions */
static int  i2c_write(ra_i2c_softc_t *, u_long, const u_char *, u_long);
static int  i2c_read(ra_i2c_softc_t *, u_long, u_char *, u_long);
#ifdef NOTYET
static void i2c_write_stop(ra_i2c_softc_t *, u_long, u_char *);
static void i2c_read_stop(ra_i2c_softc_t *, u_long, u_char *);
#endif

/* i2c driver functions */
int  ra_i2c_acquire_bus(void *, int);
void ra_i2c_release_bus(void *, int);
int  ra_i2c_exec(void *, i2c_op_t, i2c_addr_t, const void *, size_t,
	void *, size_t, int);
void ra_i2c_reset(ra_i2c_softc_t *);

CFATTACH_DECL_NEW(ri2c, sizeof(struct ra_i2c_softc),
	ra_i2c_match, ra_i2c_attach, NULL, NULL);

unsigned int clkdiv = CLKDIV_VALUE;

static inline void
ra_i2c_busy_wait(ra_i2c_softc_t *sc)
{
	for (int i=0; i < i2c_busy_loop; i++) {
		uint32_t r;
		r = bus_space_read_4(sc->sc_memt, sc->sc_i2c_memh,
			RA_I2C_STATUS);
		if ((r & I2C_STATUS_BUSY) == 0)
			break;
	}
}

int
ra_i2c_match(device_t parent, cfdata_t cf, void *aux)
{
	return 1;
}


void
ra_i2c_attach(device_t parent, device_t self, void *aux)
{
	ra_i2c_softc_t * const sc = device_private(self);
	const struct mainbus_attach_args *ma = aux;
	struct i2cbus_attach_args iba;
	uint32_t r;
	int error;

	aprint_naive(": Ralink I2C controller\n");
	aprint_normal(": Ralink I2C controller\n");

	/* save out bus space tag */
	sc->sc_memt = ma->ma_memt;

	/* Map Sysctl registers */
	if ((error = bus_space_map(ma->ma_memt, RA_SYSCTL_BASE, 0x10000,
	    0, &sc->sc_sy_memh)) != 0) {
		aprint_error_dev(self, "unable to map Sysctl registers, "
			"error=%d\n", error);
		return;
	}

	/* map the I2C registers */
	if ((error = bus_space_map(sc->sc_memt, RA_I2C_BASE, 0x100,
	    0, &sc->sc_i2c_memh)) != 0) {
		aprint_error_dev(self, "unable to map registers, "
			"error=%d\n", error);
		bus_space_unmap(ma->ma_memt, sc->sc_sy_memh, 0x10000);
		return;
	}

	/*  Enable I2C block */
	r = bus_space_read_4(sc->sc_memt, sc->sc_sy_memh,
		RA_SYSCTL_GPIOMODE);
	r &= ~GPIOMODE_I2C;
	bus_space_write_4(sc->sc_memt, sc->sc_sy_memh,
		RA_SYSCTL_GPIOMODE, r);

	sc->sc_i2c.ic_cookie = sc;
	sc->sc_i2c.ic_acquire_bus = ra_i2c_acquire_bus;
	sc->sc_i2c.ic_release_bus = ra_i2c_release_bus;
	sc->sc_i2c.ic_exec = ra_i2c_exec;

	memset(&iba, 0, sizeof(iba));
	iba.iba_type = I2C_TYPE_SMBUS;
	iba.iba_tag = &sc->sc_i2c;
	config_found(self, &iba, iicbus_print);
}



/*
 * I2C API
 */

/* Might not be needed.  JCL. */
int
ra_i2c_acquire_bus(void *cookie, int flags)
{
	/* nothing */
	return 0;
}



/* Might not be needed.  JCL. */
void
ra_i2c_release_bus(void *cookie, int flags)
{
	/* nothing */
}

int
ra_i2c_exec(void *cookie, i2c_op_t op, i2c_addr_t addr, const void *cmdbuf,
	size_t cmdlen, void *buf, size_t len, int flags)
{
	ra_i2c_softc_t * const sc = cookie;

	/*
	 * Make sure we only pass a seven-bit device address,
	 * as per I2C standard.
	 */
	KASSERT(addr <= 127);
	if (addr > 127)
		return -1;

	bus_space_write_4(sc->sc_memt, sc->sc_i2c_memh, RA_I2C_DEVADDR,
		addr);

	ra_i2c_reset(sc);

	/*
	 * Process the requested operation.
	 * There are four I2C operations of interest:
	 *   - Write
	 *   - Write with stop
	 *   - Read
	 *   - Read with stop
	 * Because the I2C block on the Ralink part generates stop markers
	 * at approprite places, based upon the byte count, the read and write
	 * with stop operations will rarely be needed.  They are included here
	 * as placeholders, but haven't been implemented or tested.
	 */
	switch(op) {
	case  I2C_OP_WRITE:
		return i2c_write(sc, addr, cmdbuf, cmdlen);
		break;
	case I2C_OP_READ:
		return i2c_read(sc, addr, buf, len);
		break;
#ifdef NOTYET
	case I2C_OP_WRITE_WITH_STOP:
		i2c_write_stop(sc, addr, buf);
		break;
	case I2C_OP_READ_WITH_STOP:
		i2c_read_stop(sc, addr, buf);
		break;
#endif
	default:
		return -1;  /* Illegal operation, error return. */
	}

	return 0;
}

static int
i2c_write(ra_i2c_softc_t *sc, u_long addr, const u_char *data,
	u_long nbytes)
{
	uint32_t r;
	int i, j;

	bus_space_write_4(sc->sc_memt, sc->sc_i2c_memh, RA_I2C_DEVADDR,
		addr);
	bus_space_write_4(sc->sc_memt, sc->sc_i2c_memh, RA_I2C_BYTECNT,
		nbytes - 1);
	bus_space_write_4(sc->sc_memt, sc->sc_i2c_memh, RA_I2C_STARTXFR,
		I2C_OP_WRITE);

	for (i=0; i < nbytes; i++) {
		for (j=0; j < max_ee_busy_loop; j++) {
			r = bus_space_read_4(sc->sc_memt, sc->sc_i2c_memh, 
				RA_I2C_STATUS);
			if ((r & I2C_STATUS_SDOEMPTY) != 0) {
				bus_space_write_4(sc->sc_memt, sc->sc_i2c_memh,
					RA_I2C_DATAOUT, data[i]);
				break;
			}
		}
#if 0
		if ((r & I2C_STATUS_ACKERR) != 0) {
			aprint_error_dev(sc->sc_dev, "ACK error in %s\n",
				__func__);
			return EAGAIN;
		}
#endif
		if (j == max_ee_busy_loop) {
			aprint_error_dev(sc->sc_dev, "timeout error in %s\n",
				__func__);
			return EAGAIN;
		}	
	}

	ra_i2c_busy_wait(sc);

	return 0;
}


static int
i2c_read(ra_i2c_softc_t *sc, u_long addr, u_char *data, u_long nbytes)
{
	bus_space_write_4(sc->sc_memt, sc->sc_i2c_memh, RA_I2C_DEVADDR,
		addr);
	bus_space_write_4(sc->sc_memt, sc->sc_i2c_memh, RA_I2C_BYTECNT,
		nbytes - 1);
	bus_space_write_4(sc->sc_memt, sc->sc_i2c_memh, RA_I2C_STARTXFR,
		I2C_OP_READ);

	for (u_int i = 0; i < nbytes; i++) {
		u_long j;
		uint32_t r;

		for (j=0; j < max_ee_busy_loop; j++) {
			r = bus_space_read_4(sc->sc_memt, sc->sc_i2c_memh, 
				RA_I2C_STATUS);
			if ((r & I2C_STATUS_DATARDY) != 0) {
				data[i] = bus_space_read_4(
						sc->sc_memt, sc->sc_i2c_memh,
						RA_I2C_DATAIN);
				break;
			}
		}
#if 0
		if ((r & I2C_STATUS_ACKERR) != 0) {
			aprint_error_dev(sc->sc_dev, "ACK error in %s\n",
				__func__);
			return EAGAIN;
		}
#endif
		if (j == max_ee_busy_loop) {
			aprint_error_dev(sc->sc_dev, "timeout error in %s\n",
				__func__);
			return EAGAIN;
		}
	}

	ra_i2c_busy_wait(sc);

	return 0;

}


#ifdef NOTYET
static void
i2c_write_stop(ra_i2c_softc_t *sc, u_long address, u_char *data)
{
	/* unimplemented */
}

static void
i2c_read_stop(ra_i2c_softc_t *sc, u_long address, u_char *data)
{
	/* unimplemented */
}
#endif

void
ra_i2c_reset(ra_i2c_softc_t *sc)
{
	uint32_t r;

	/* reset i2c block */
	r = bus_space_read_4(sc->sc_memt, sc->sc_sy_memh, RA_SYSCTL_RST);
	bus_space_write_4(sc->sc_memt, sc->sc_sy_memh, RA_SYSCTL_RST, 
		r | RST_I2C);
	bus_space_write_4(sc->sc_memt, sc->sc_sy_memh, RA_SYSCTL_RST, r);

	r = I2C_CONFIG_ADDRLEN(I2C_CONFIG_ADDRLEN_8) |
	    I2C_CONFIG_DEVADLEN(I2C_CONFIG_DEVADLEN_7) |
	    I2C_CONFIG_ADDRDIS;
	bus_space_write_4(sc->sc_memt, sc->sc_i2c_memh, RA_I2C_CONFIG, r);

	/*
	 * Set the I2C clock divider.  Appears to be set to 200,000,
	 * which is strange, as I2C is 100K/400K/3.?M bps.
	 */
	bus_space_write_4(sc->sc_memt, sc->sc_i2c_memh, RA_I2C_CLKDIV,
		clkdiv);
}

File Added: src/sys/arch/mips/ralink/ralink_intr.c
/*	$NetBSD: ralink_intr.c,v 1.2 2011/07/28 15:38:49 matt Exp $	*/
/*-
 * Copyright (c) 2011 CradlePoint Technology, Inc.
 * 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, 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 CRADLEPOINT TECHNOLOGY, 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 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.
 */

#define __INTR_PRIVATE

#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ralink_intr.c,v 1.2 2011/07/28 15:38:49 matt Exp $");

#include <sys/param.h>
#include <sys/bus.h>
#include <sys/device.h>
#include <sys/intr.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/systm.h>

#include <mips/locore.h>

#include <mips/ralink/ralink_reg.h>
#include <mips/ralink/ralink_var.h>

static int ra_pic_intr(void *arg);

/*
 * evbmips spl integration:
 *  this is a mask of bits to clear in the SR when we go to a
 *  given hardware interrupt priority level.
 */
static const struct ipl_sr_map ralink_ipl_sr_map = {
    .sr_bits = {
	    [IPL_NONE]		= 0,
	    [IPL_SOFTCLOCK]	= MIPS_SOFT_INT_MASK_0,
	    [IPL_SOFTBIO]	= MIPS_SOFT_INT_MASK_0,
	    [IPL_SOFTNET]	= MIPS_SOFT_INT_MASK,
	    [IPL_SOFTSERIAL]	= MIPS_SOFT_INT_MASK,
	    [IPL_VM]		= MIPS_INT_MASK ^ MIPS_INT_MASK_5,
	    [IPL_SCHED]		= MIPS_INT_MASK,
	    [IPL_DDB]		= MIPS_INT_MASK,
	    [IPL_HIGH]		= MIPS_INT_MASK,
     },
};


/*
 * RT3052 Interrupt Block Definitions
 *
 * HW_INT0 - Low Priority Chip Interrupts (Lowest Priority)
 * HW_INT1 - High Priority Chip Interrupts
 * HW_INT2 - PCIe/PCI (3883 only)
 * HW_INT3 - Frame Engine
 * HW_INT4 - 802.11n NIC
 * HW_INT5 - Timer Interrupt (Highest Priority)
 *
 * HW_INT0 and HW_INT1 can be configured to fire with any of the other
 *  interrupts on chip.  They can be masked for either INT0 or INT1
 *  but not both.
 *
 * SYSCTL
 * TIMER0
 * WDTIMER
 * ILLACC
 * PCM
 * UARTF
 * PIO
 * DMA
 * NAND
 * PERF
 * I2S
 * UARTL
 * ETHSW
 * USB
 */


/*
 * we use 5 MIPS cpu interrupts: 
 *	MIPS INT0 .. INT4
 */
#define NCPUINTRS	5

struct ra_intr {
	LIST_HEAD(, evbmips_intrhand) intr_list;
	struct evcnt intr_evcnt;
};

/*
 * ordering for ra_intrtab[] and ra_intr_names[]
 * corresponds to the RA_IRQ_* definitions
 * which include the CPU intrs and the PIC intrs
 */
static struct ra_intr ra_intrtab[RA_IRQ_MAX];
static const char * const ra_intr_names[RA_IRQ_MAX] = {
        "intr 0 (lowpri)",
        "intr 1 (highpri)",
        "intr 2 (pci)",
        "intr 3 (frame)",
        "intr 4 (wlan)",
        "intr 5 (timer)",
	"intr 0 (sysctl)",
	"intr 1 (timer0)",
	"intr 2 (watchdog)",
	"intr 3 (illacc)",
	"intr 4 (pcm)",
	"intr 5 (uartf)",
	"intr 6 (gpio)",
	"intr 7 (dma)",
	"intr 8 (nand)",
	"intr 9 (perf)",
	"intr 10 (i2s)",
	"intr 12 (uartl)",
	"intr 17 (ethsw)",
	"intr 18 (usb)"
};

/* determine if irq belongs to the PIC */
#define PIC_IRQ_P(irq)	((irq) > RA_IRQ_TIMER)

/* map the IRQ num to PIC reg bits */
static const uint8_t irq2bit[RA_IRQ_MAX] = {
    -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 17, 18
};

/* map the PIC reg bits to IRQ num */
static const uint8_t bit2irq[19] = {
    6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 255, 17, 255, 255, 255, 255, 18, 19
};



static inline uint32_t
intctl_read(u_int offset)
{
	return *RA_IOREG_VADDR(RA_INTCTL_BASE, offset);
}

static inline void
intctl_write(u_int offset, uint32_t val)
{
	*RA_IOREG_VADDR(RA_INTCTL_BASE, offset) = val;
}


void
evbmips_intr_init(void)
{
	ipl_sr_map = ralink_ipl_sr_map;

	for (int irq=0; irq < RA_IRQ_MAX; irq++) {
		LIST_INIT(&ra_intrtab[irq].intr_list);
		if (PIC_IRQ_P(irq)) {
			evcnt_attach_dynamic(&ra_intrtab[irq].intr_evcnt,
				EVCNT_TYPE_INTR, NULL, "pic",
				ra_intr_names[irq]);
		} else {
			evcnt_attach_dynamic(&ra_intrtab[irq].intr_evcnt,
				EVCNT_TYPE_INTR, NULL, "cpu0",
				ra_intr_names[irq]);
		}
	}

	/*
	 * make sure we start without any misc interrupts enabled,
	 * but the block enabled
	 */
	intctl_write(RA_INTCTL_DISABLE, ~0);
	intctl_write(RA_INTCTL_ENABLE, INT_GLOBAL);

	/* 
	 * establish the low/high priority cpu interrupts.
	 * note here we pass the value of the priority as the argument
	 * so it is passed to ra_pic_intr() correctly.
	 */
	ra_intr_establish(RA_IRQ_HIGH, ra_pic_intr,
		(void *)1, 1);
	ra_intr_establish(RA_IRQ_LOW, ra_pic_intr,
		(void *)0, 0);
}


void *
ra_intr_establish(int intr, int (*func)(void *), void *arg, int priority)
{
	struct evbmips_intrhand *ih;

	if ((ih = malloc(sizeof(*ih), M_DEVBUF, M_NOWAIT)) == NULL) {
		KASSERTMSG(0, ("%s: cannot malloc intrhand", __func__));
		return NULL;
	}

	ih->ih_func = func;
	ih->ih_arg = arg;
	ih->ih_irq = intr;

	const int s = splhigh();

	LIST_INSERT_HEAD(&ra_intrtab[intr].intr_list, ih, ih_q);

	if (PIC_IRQ_P(intr)) {
		/* irq belongs to the PIC */
		uint32_t r;
		r = intctl_read(RA_INTCTL_TYPE);
		r |= (priority << irq2bit[intr]);
		intctl_write(RA_INTCTL_TYPE, r);
		r = intctl_read(RA_INTCTL_ENABLE);
		r |= (1 << irq2bit[intr]);
		intctl_write(RA_INTCTL_ENABLE, r);
	}

	splx(s);

	return ih;
}

void
ra_intr_disestablish(void *arg)
{
	struct evbmips_intrhand * const ih = arg;

	const int s = splhigh();

	LIST_REMOVE(ih, ih_q);
	if (PIC_IRQ_P(ih->ih_irq) &&
	    LIST_EMPTY(&ra_intrtab[ih->ih_irq].intr_list)) {
		uint32_t r;
		r = intctl_read(RA_INTCTL_DISABLE);
		r &= ~(1 << irq2bit[ih->ih_irq]);
		intctl_write(RA_INTCTL_DISABLE, r);
	}

	splx(s);

	free(ih, M_DEVBUF);
}

/*
 * ra_pic_intr - service PIC interrupts
 *
 * caller handles priority by the calling this function w/ PRI_HIGH first
 */
static int
ra_pic_intr(void *arg)
{
	const int priority = (intptr_t)arg;
	const u_int off = (priority == 0) ?
		RA_INTCTL_IRQ0STAT : RA_INTCTL_IRQ1STAT;
	uint32_t pending = intctl_read(off);

	while (pending != 0) {
		const u_int bitno = 31 - __builtin_clz(pending);
		pending ^= (1 << bitno);
		const int irq = bit2irq[bitno];
		KASSERT(PIC_IRQ_P(irq));
		ra_intrtab[irq].intr_evcnt.ev_count++;
		struct evbmips_intrhand *ih;
		LIST_FOREACH(ih, &ra_intrtab[irq].intr_list, ih_q)
			(*ih->ih_func)(ih->ih_arg);
	}

	return 1;
}

/*
 * evbmips_iointr - process CPU interrupts
 *
 * we only see IRQ 4..0 here as IRQ 5 is handled
 * in the generic MIPS code for the timer
 */
void
evbmips_iointr(int ipl, vaddr_t pc, uint32_t ipending)
{
	while (ipending != 0) {
		const u_int bitno = 31 - __builtin_clz(ipending);
		ipending ^= (1 << bitno);
		const int irq = bitno - (31 - __builtin_clz(MIPS_INT_MASK_0));
		KASSERT(!PIC_IRQ_P(irq));
		ra_intrtab[irq].intr_evcnt.ev_count++;
		struct evbmips_intrhand *ih;
		LIST_FOREACH(ih, &ra_intrtab[irq].intr_list, ih_q)
			(*ih->ih_func)(ih->ih_arg);
	}
}

File Added: src/sys/arch/mips/ralink/ralink_mainbus.c
/*	$NetBSD: ralink_mainbus.c,v 1.2 2011/07/28 15:38:49 matt Exp $	*/
/*-
 * Copyright (c) 2011 CradlePoint Technology, Inc.
 * 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, 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 CRADLEPOINT TECHNOLOGY, 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 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.
 */

#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ralink_mainbus.c,v 1.2 2011/07/28 15:38:49 matt Exp $");

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>

#include <mips/cache.h>
#include <mips/cpuregs.h>

#include <mips/ralink/ralink_reg.h>
#include <mips/ralink/ralink_var.h>

typedef struct mainbus_softc {
	device_t	sc_dev;
	bus_space_tag_t	sc_memt;
	bus_dma_tag_t	sc_dmat;
} mainbus_softc_t;

static int  mainbus_match(device_t, cfdata_t, void *);
static void mainbus_attach(device_t, device_t, void *);
static int  mainbus_search(device_t, cfdata_t, const int *, void *);
static int  mainbus_print(void *, const char *);
static int  mainbus_find(device_t, cfdata_t, const int *, void *);
static void mainbus_attach_critical(struct mainbus_softc *);


CFATTACH_DECL_NEW(mainbus, sizeof(struct mainbus_softc),
	mainbus_match, mainbus_attach, NULL, NULL);

static bool mainbus_found;

/*
 * critical devices, if found, will be attached in the order listed here
 */
static const struct {
	const char *name;
	bool required;
} critical_devs[] = {
	{ .name = "cpu0",	.required = true  },
	{ .name = "rwdog0",	.required = false },
	{ .name = "rgpio0",	.required = true  },
	{ .name = "ri2c0",	.required = false },
	{ .name = "com0",	.required = false },
};


static int
mainbus_match(device_t parent, cfdata_t match, void *aux)
{
	if (mainbus_found)
		return 0;
	return 1;
}

static void
mainbus_attach(device_t parent, device_t self, void *aux)
{
	mainbus_softc_t * const sc = device_private(self);
	struct mainbus_attach_args ma;

	mainbus_found = true;

	aprint_naive(": Ralink System Bus\n");
	aprint_normal(": Ralink System Bus\n");

	sc->sc_dev = self;
	ma.ma_name = NULL;
	ma.ma_memt = sc->sc_memt = &ra_bus_memt;
	ma.ma_dmat = sc->sc_dmat = &ra_bus_dmat;

	/* attach critical devices */
	mainbus_attach_critical(sc);

	/* attach other devices */
	config_search_ia(mainbus_search, self, "mainbus", &ma);
}

static int
mainbus_search(device_t parent, cfdata_t cf, const int *ldesc, void *aux)
{
	if (config_match(parent, cf, aux) > 0)
		config_attach(parent, cf, aux, mainbus_print);
	else
		mainbus_print(aux, cf->cf_name);
	return 0;
}

int
mainbus_print(void *aux, const char *pnp)
{
	if (pnp)
		aprint_normal("%s unconfigured\n", pnp);

	return UNCONF;
}

static int
mainbus_find(device_t parent, cfdata_t cf, const int *ldesc, void *aux)
{
	struct mainbus_attach_args * const ma = aux;
	char devname[16];

	sprintf(devname, "%s%d", cf->cf_name, cf->cf_unit);
	if (strcmp(ma->ma_name, devname) != 0)
		return 0;

	return config_match(parent, cf, ma);
}

static void
mainbus_attach_critical(struct mainbus_softc *sc)
{
	struct mainbus_attach_args ma;
	cfdata_t cf;
	size_t i;

	for (i = 0; i < __arraycount(critical_devs); i++) {
		ma.ma_name = critical_devs[i].name;
		ma.ma_memt = sc->sc_memt;
		ma.ma_dmat = sc->sc_dmat;

		cf = config_search_ia(mainbus_find, sc->sc_dev, "mainbus", &ma);
		if (cf == NULL && critical_devs[i].required)
			panic("%s: failed to find %s",
				__func__, critical_devs[i].name);

		config_attach(sc->sc_dev, cf, &ma, mainbus_print);
	}
}

File Added: src/sys/arch/mips/ralink/ralink_ohci.c
/*	$NetBSD: ralink_ohci.c,v 1.2 2011/07/28 15:38:49 matt Exp $	*/
/*-
 * Copyright (c) 2011 CradlePoint Technology, Inc.
 * 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, 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 CRADLEPOINT TECHNOLOGY, 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 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.
 */

/* ralink_ohci.c -- Ralink OHCI USB Driver */

#include "ehci.h"

#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ralink_ohci.c,v 1.2 2011/07/28 15:38:49 matt Exp $");

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

#include <dev/usb/usb.h>
#include <dev/usb/usbdi.h>
#include <dev/usb/usbdivar.h>
#include <dev/usb/usb_mem.h>

#include <dev/usb/ohcireg.h>
#include <dev/usb/ohcivar.h>

#include <mips/ralink/ralink_var.h>
#include <mips/ralink/ralink_reg.h>
#include <mips/ralink/ralink_usbhcvar.h>

#define OREAD4(sc, a) bus_space_read_4((sc)->iot, (sc)->ioh, (a))
#define OWRITE4(sc, a, x) bus_space_write_4((sc)->iot, (sc)->ioh, (a), (x))

#define RT3XXX_OHCI_BASE 	0x101c1000
#define RT3XXX_BLOCK_SIZE	0x1000

struct ralink_ohci_softc {
	struct ohci_softc sc_ohci;
#if NEHCI > 0
	struct ralink_usb_hc sc_hc;
#endif
	void  *sc_ih;
};

static int  ralink_ohci_match(device_t, cfdata_t, void *);
static void ralink_ohci_attach(device_t, device_t, void *);
static int  ralink_ohci_detach(device_t, int);

CFATTACH_DECL2_NEW(ralink_ohci, sizeof(struct ralink_ohci_softc),
	ralink_ohci_match, ralink_ohci_attach, ralink_ohci_detach,
	ohci_activate, NULL, ohci_childdet);

/*
 * ralink_ohci_match
 */
static int
ralink_ohci_match(device_t parent, cfdata_t cf, void *aux)
{
	return 1;
}

/*
 * ralink_ohci_attach
 */
static void
ralink_ohci_attach(device_t parent, device_t self, void *aux)
{
	struct ralink_ohci_softc * const sc = device_private(self);
	const struct mainbus_attach_args *ma = aux;
	usbd_status status;
	int error;
#ifdef RALINK_OHCI_DEBUG
	const char * const devname = device_xname(self);
#endif

	aprint_naive(": OHCI USB controller\n");
	aprint_normal(": OHCI USB controller\n");

	sc->sc_ohci.sc_dev = self;
	sc->sc_ohci.sc_bus.hci_private = sc;
	sc->sc_ohci.iot = ma->ma_memt;
	sc->sc_ohci.sc_bus.dmatag = ma->ma_dmat;

	/* Map I/O registers */
	if ((error = bus_space_map(sc->sc_ohci.iot, RT3XXX_OHCI_BASE,
	    RT3XXX_BLOCK_SIZE, 0, &sc->sc_ohci.ioh)) != 0) {
		aprint_error_dev(self, "can't map OHCI registers, "
			"error=%d\n", error);
		return;
	}
	
	sc->sc_ohci.sc_size = RT3XXX_BLOCK_SIZE;

#ifdef RALINK_OHCI_DEBUG
	printf("%s sc: %p ma: %p\n", devname, sc, ma);
	printf("%s memt: %p dmat: %p\n", devname, ma->ma_memt, ma->ma_dmat);

	printf("%s: OHCI HcRevision=0x%x\n", devname,
		OREAD4(&sc->sc_ohci, OHCI_REVISION));
	printf("%s: OHCI HcControl=0x%x\n", devname,
		OREAD4(&sc->sc_ohci, OHCI_CONTROL));
	printf("%s: OHCI HcCommandStatus=0x%x\n", devname,
		OREAD4(&sc->sc_ohci, OHCI_COMMAND_STATUS));
	printf("%s: OHCI HcInterruptStatus=0x%x\n", devname,
		OREAD4(&sc->sc_ohci, OHCI_INTERRUPT_STATUS));
#endif

	/* Disable OHCI interrupts. */
	OWRITE4(&sc->sc_ohci, OHCI_INTERRUPT_DISABLE, OHCI_ALL_INTRS);

	/* establish the MIPS level interrupt */
	sc->sc_ih = ra_intr_establish(RA_IRQ_USB, ohci_intr, sc, 0);
	if (sc->sc_ih == NULL) {
		aprint_error_dev(self, "unable to establish irq %d\n",
			RA_IRQ_USB);
		goto fail_0;
	}

	/* Set vendor for root hub descriptor. */
	sc->sc_ohci.sc_id_vendor = 0x1814;
	strlcpy(sc->sc_ohci.sc_vendor, "Ralink", sizeof(sc->sc_ohci.sc_vendor));

	/* Initialize OHCI */
	status = ohci_init(&sc->sc_ohci);
	if (status != USBD_NORMAL_COMPLETION) {
		aprint_error_dev(self, "init failed, error=%d\n", status);
		goto fail_0;
	}

#if NEHCI > 0
	ralink_usb_hc_add(&sc->sc_hc, self);
#endif

	if (!pmf_device_register1(self, ohci_suspend, ohci_resume,
	    ohci_shutdown))
		aprint_error_dev(self, "couldn't establish power handler\n");

	/* Attach usb device. */
	sc->sc_ohci.sc_child = config_found(self, &sc->sc_ohci.sc_bus,
		usbctlprint);

	return;

 fail_0:
	bus_space_unmap(sc->sc_ohci.iot, sc->sc_ohci.ioh, sc->sc_ohci.sc_size);
	sc->sc_ohci.sc_size = 0;
}

static int
ralink_ohci_detach(device_t self, int flags)
{
	struct ralink_ohci_softc *sc = device_private(self);
	int rv;

	pmf_device_deregister(self);

	rv = ohci_detach(&sc->sc_ohci, flags);
	if (rv != 0)
		return rv;

	if (sc->sc_ih != NULL) {
		ra_intr_disestablish(sc->sc_ih);
		sc->sc_ih = NULL;
	}

	if (sc->sc_ohci.sc_size == 0) {
		bus_space_unmap(sc->sc_ohci.iot, sc->sc_ohci.ioh,
			sc->sc_ohci.sc_size);
		sc->sc_ohci.sc_size = 0;
	}

#if NEHCI > 0
	ralink_usb_hc_rem(&sc->sc_hc);
#endif

	return 0;
}

File Added: src/sys/arch/mips/ralink/ralink_reg.h
/*	$NetBSD: ralink_reg.h,v 1.2 2011/07/28 15:38:49 matt Exp $	*/
/*-
 * Copyright (c) 2011 CradlePoint Technology, Inc.
 * 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, 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 CRADLEPOINT TECHNOLOGY, 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 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.
 */

/*
 * This file contains the configuration parameters for the RT3052 board.
 */

#ifndef _RALINK_REG_H_
#define _RALINK_REG_H_

#include <mips/cpuregs.h>

#if defined(RT3050)
#define RA_CLOCK_RATE          320000000
#define RA_BUS_FREQ            (RA_CLOCK_RATE / 3)
#define RA_UART_FREQ           RA_BUS_FREQ
#elif defined(RT3052)
#define RA_CLOCK_RATE          384000000
#define RA_BUS_FREQ            (RA_CLOCK_RATE / 3)
#define RA_UART_FREQ           RA_BUS_FREQ
#elif defined(RT3883)
#if 0
#define RA_CLOCK_RATE          480000000
#else
#define RA_CLOCK_RATE          500000000
#endif
#define RA_BUS_FREQ            166000000 /* DDR speed */
#define RA_UART_FREQ           40000000
#else
/* Ralink dev board */
#define RA_CLOCK_RATE          384000000
#define RA_BUS_FREQ            (RA_CLOCK_RATE / 3)
#define RA_UART_FREQ           RA_BUS_FREQ
#endif

#define RA_BAUDRATE            CONSPEED
#define RA_SERIAL_CLKDIV       16

#define RA_SRAM_BASE           0x00000000
#define RA_SRAM_END            0x0FFFFFFF
#define RA_SYSCTL_BASE         0x10000000
#define RA_TIMER_BASE          0x10000100
#define RA_INTCTL_BASE         0x10000200
#define RA_MEMCTL_BASE         0x10000300
#if defined(RT3052) || defined(RT3050)
#define RA_PCM_BASE            0x10000400
#endif
#define RA_UART_BASE           0x10000500
#define RA_PIO_BASE            0x10000600
#if defined(RT3052) || defined(RT3050)
#define RA_GDMA_BASE           0x10000700
#elif defined(RT3883)
#define RA_FLASHCTL_BASE       0x10000700
#endif
#define RA_NANDCTL_BASE        0x10000800
#define RA_I2C_BASE            0x10000900
#define RA_I2S_BASE            0x10000A00
#define RA_SPI_BASE            0x10000B00
#define RA_UART_LITE_BASE      0x10000C00
#if defined(RT3883)
#define RA_PCM_BASE            0x10002000
#define RA_GDMA_BASE           0x10002800
#define RA_CODEC1_BASE         0x10003000
#define RA_CODEC2_BASE         0x10003800
#endif
#define RA_FRAME_ENGINE_BASE   0x10100000
#define RA_ETH_SW_BASE         0x10110000
#define RA_ROM_BASE            0x10118000
#if defined(RT3883)
#define RA_USB_DEVICE_BASE     0x10120000
#define RA_PCI_BASE            0x10140000
#endif
#define RA_11N_MAC_BASE        0x10180000
#define RA_USB_OTG_BASE        0x101C0000
#if defined(RT3883)
#define RA_USB_HOST_BASE       0x101C0000
#endif
#if defined(RT3052) || defined(RT3050)
#define RA_FLASH_BASE          0x1F000000
#define RA_FLASH_END           0x1F7FFFFF
#elif defined(RT3883) 
#define RA_FLASH_BASE          0x1C000000
#define RA_FLASH_END           0x1DFFFFFF
#endif

#define RA_IOREG_VADDR(base, offset)	\
	(volatile uint32_t *)MIPS_PHYS_TO_KSEG1((base) + (offset))

#define FLD_GET(val,pos,mask)      (((val) >> (pos)) & (mask))
#define FLD_SET(val,pos,mask)      (((val) & (mask)) << (pos))

/*
 * System Control Registers
 */
#define RA_SYSCTL_ID0          0x00
#define RA_SYSCTL_ID1          0x04
#define RA_SYSCTL_CFG0         0x10
#define RA_SYSCTL_CFG1         0x14
#define RA_SYSCTL_CLKCFG0      0x2C
#define RA_SYSCTL_CLKCFG1      0x30
#define RA_SYSCTL_RST          0x34
#define RA_SYSCTL_RSTSTAT      0x38
#define RA_SYSCTL_GPIOMODE     0x60

#if defined(RT3883)
/* 3883 doesn't have memo regs, use teststat instead */
#define RA_SYSCTL_MEMO0        0x18
#define RA_SYSCTL_MEMO1        0x1C
#else
#define RA_SYSCTL_MEMO0        0x68
#define RA_SYSCTL_MEMO1        0x6C
#endif

#define  RST_SW        (1 << 23)
#define  RST_OTG       (1 << 22)
#define  RST_FE        (1 << 21)
#define  RST_WLAN      (1 << 20)
#define  RST_UARTL     (1 << 19)
#define  RST_SPI       (1 << 18)
#define  RST_I2S       (1 << 17)
#define  RST_I2C       (1 << 16)
#define  RST_NAND      (1 << 15)
#define  RST_DMA       (1 << 14)
#define  RST_PIO       (1 << 13)
#define  RST_UART      (1 << 12)
#define  RST_PCM       (1 << 11)
#define  RST_MC        (1 << 10)
#define  RST_INTC      (1 << 9)
#define  RST_TIMER     (1 << 8)
#define  RST_SYS       (1 << 0)
#define  GPIOMODE_RGMII  (1 << 9)
#define  GPIOMODE_SDRAM  (1 << 8)
#define  GPIOMODE_MDIO   (1 << 7)
#define  GPIOMODE_JTAG   (1 << 6)
#define  GPIOMODE_UARTL  (1 << 5)
#define  GPIOMODE_UARTF2 (1 << 4)
#define  GPIOMODE_UARTF1 (1 << 3)
#define  GPIOMODE_UARTF0 (1 << 2)
#define  GPIOMODE_UARTF_0_2	\
			 (GPIOMODE_UARTF0|GPIOMODE_UARTF1|GPIOMODE_UARTF2)
#define  GPIOMODE_SPI    (1 << 1)
#define  GPIOMODE_I2C    (1 << 0)

/*
 * Timer Registers
 */
#define RA_TIMER_STAT          0x00
#define RA_TIMER_0_LOAD        0x10
#define RA_TIMER_0_VALUE       0x14
#define RA_TIMER_0_CNTRL       0x18
#define RA_TIMER_1_LOAD        0x20
#define RA_TIMER_1_VALUE       0x24
#define RA_TIMER_1_CNTRL       0x28

#define  TIMER_1_RESET         (1 << 5)
#define  TIMER_0_RESET         (1 << 4)
#define  TIMER_1_INT_STATUS    (1 << 1)
#define  TIMER_0_INT_STATUS    (1 << 0)
#define  TIMER_TEST_EN         (1 << 15)
#define  TIMER_EN              (1 << 7)
#define  TIMER_MODE(x)         (((x) & 0x3) << 4)
#define   TIMER_MODE_FREE       0
#define   TIMER_MODE_PERIODIC   1
#define   TIMER_MODE_TIMEOUT    2
#define   TIMER_MODE_WDOG       3	/* only valid for TIMER_1 */
#define  TIMER_PRESCALE(x)     (((x) & 0xf) << 0)
#define   TIMER_PRESCALE_DIV_1     0
#define   TIMER_PRESCALE_DIV_4     1
#define   TIMER_PRESCALE_DIV_8     2
#define   TIMER_PRESCALE_DIV_16    3
#define   TIMER_PRESCALE_DIV_32    4
#define   TIMER_PRESCALE_DIV_64    5
#define   TIMER_PRESCALE_DIV_128   6
#define   TIMER_PRESCALE_DIV_256   7
#define   TIMER_PRESCALE_DIV_512   8
#define   TIMER_PRESCALE_DIV_1024  9
#define   TIMER_PRESCALE_DIV_2048  10
#define   TIMER_PRESCALE_DIV_4096  11
#define   TIMER_PRESCALE_DIV_8192  12
#define   TIMER_PRESCALE_DIV_16384 13
#define   TIMER_PRESCALE_DIV_32768 14
#define   TIMER_PRESCALE_DIV_65536 15

/*
 * Interrupt Controller Registers
 */
#define RA_INTCTL_IRQ0STAT     0x00
#define RA_INTCTL_IRQ1STAT     0x04
#define RA_INTCTL_TYPE         0x20
#define RA_INTCTL_RAW          0x30
#define RA_INTCTL_ENABLE       0x34
#define RA_INTCTL_DISABLE      0x38


#define INT_GLOBAL    (1 << 31)
#define INT_USB       (1 << 18)
#define INT_ETHSW     (1 << 17)
#define INT_UARTL     (1 << 12)
#define INT_I2S       (1 << 10)
#define INT_PERF      (1 << 9)
#define INT_NAND      (1 << 8)
#define INT_DMA       (1 << 7)
#define INT_PIO       (1 << 6)
#define INT_UARTF     (1 << 5)
#define INT_PCM       (1 << 4)
#define INT_ILLACC    (1 << 3)
#define INT_WDOG      (1 << 2)
#define INT_TIMER0    (1 << 1)
#define INT_SYSCTL    (1 << 0)

/*
 * Ralink Linear CPU Interrupt Mapping For Lists
 */
#define RA_IRQ_LOW        0
#define RA_IRQ_HIGH       1
#define RA_IRQ_PCI        2
#define RA_IRQ_FENGINE    3
#define RA_IRQ_WLAN       4
#define RA_IRQ_TIMER      5
#define RA_IRQ_SYSCTL     6
#define RA_IRQ_TIMER0     7
#define RA_IRQ_WDOG       8
#define RA_IRQ_ILLACC     9
#define RA_IRQ_PCM        10
#define RA_IRQ_UARTF      11
#define RA_IRQ_PIO        12
#define RA_IRQ_DMA        13
#define RA_IRQ_NAND       14
#define RA_IRQ_PERF       15
#define RA_IRQ_I2S        16
#define RA_IRQ_UARTL      17
#define RA_IRQ_ETHSW      18
#define RA_IRQ_USB        19
#define RA_IRQ_MAX        20

/*
 * General Purpose I/O
 */
#define RA_PIO_00_23_INT         0x00
#define RA_PIO_00_23_EDGE_INT    0x04
#define RA_PIO_00_23_INT_RISE_EN 0x08
#define RA_PIO_00_23_INT_FALL_EN 0x0C
#define RA_PIO_00_23_DATA        0x20
#define RA_PIO_00_23_DIR         0x24
#define RA_PIO_00_23_POLARITY    0x28
#define RA_PIO_00_23_SET_BIT     0x2C
#define RA_PIO_00_23_CLR_BIT     0x30
#define RA_PIO_00_23_TGL_BIT     0x34
#define RA_PIO_24_39_INT         0x38
#define RA_PIO_24_39_EDGE_INT    0x3C
#define RA_PIO_24_39_INT_RISE_EN 0x40
#define RA_PIO_24_39_INT_FALL_EN 0x44
#define RA_PIO_24_39_DATA        0x48
#define RA_PIO_24_39_DIR         0x4C
#define RA_PIO_24_39_POLARITY    0x50
#define RA_PIO_24_39_SET_BIT     0x54
#define RA_PIO_24_39_CLR_BIT     0x58
#define RA_PIO_24_39_TGL_BIT     0x5C
#define RA_PIO_40_51_INT         0x60
#define RA_PIO_40_51_EDGE_INT    0x64
#define RA_PIO_40_51_INT_RISE_EN 0x68
#define RA_PIO_40_51_INT_FALL_EN 0x6C
#define RA_PIO_40_51_DATA        0x70
#define RA_PIO_40_51_DIR         0x74
#define RA_PIO_40_51_POLARITY    0x78
#define RA_PIO_40_51_SET_BIT     0x7C
#define RA_PIO_40_51_CLR_BIT     0x80
#define RA_PIO_40_51_TGL_BIT     0x84
#define RA_PIO_72_95_INT         0x88
#define RA_PIO_72_95_EDGE_INT    0x8c
#define RA_PIO_72_95_INT_RISE_EN 0x90
#define RA_PIO_72_95_INT_FALL_EN 0x94
#define RA_PIO_72_95_DATA        0x98
#define RA_PIO_72_95_DIR         0x9c
#define RA_PIO_72_95_POLARITY    0xa0
#define RA_PIO_72_95_SET_BIT     0xa4
#define RA_PIO_72_95_CLR_BIT     0xa8
#define RA_PIO_72_95_TGL_BIT     0xac


/*
 * UART registers
 */

#define RA_UART_RBR    0x00
#define RA_UART_TBR    0x04
#define RA_UART_IER    0x08
#define RA_UART_IIR    0x0C
#define RA_UART_FCR    0x10
#define RA_UART_LCR    0x14
#define RA_UART_MCR    0x18
#define RA_UART_LSR    0x1C
#define RA_UART_MSR    0x20
#define RA_UART_DLL    0x28


#define UART_IER_ELSI      (1 << 2)
		/* Receiver Line Status Interrupt Enable */
#define UART_IER_ETBEI     (1 << 1)
		/* Transmit Buffer Empty Interrupt Enable */
#define UART_IER_ERBFI     (1 << 0)
		/* Data Ready or Character Time-Out Interrupt Enable */

#define UART_IIR_FIFOES1   (1 << 7)    /* FIFO Mode Enable Status */
#define UART_IIR_FIFOES0   (1 << 6)    /* FIFO Mode Enable Status */
#define UART_IIR_IID3      (1 << 3)    /* Interrupt Source Encoded */
#define UART_IIR_IID2      (1 << 2)    /* Interrupt Source Encoded */
#define UART_IIR_IID1      (1 << 1)    /* Interrupt Source Encoded */
#define UART_IIR_IP        (1 << 0)    /* Interrupt Pending (active low) */

#define UART_FCR_RXTRIG1   (1 << 7)    /* Receiver Interrupt Trigger Level */
#define UART_FCR_RXTRIG0   (1 << 6)    /* Receiver Interrupt Trigger Level */
#define UART_FCR_TXTRIG1   (1 << 5)    /* Transmitter Interrupt Trigger Level */
#define UART_FCR_TXTRIG0   (1 << 4)    /* Transmitter Interrupt Trigger Level */
#define UART_FCR_DMAMODE   (1 << 3)    /* Enable DMA transfers */
#define UART_FCR_TXRST     (1 << 2)    /* Reset Transmitter FIFO */
#define UART_FCR_RXRST     (1 << 1)    /* Reset Receiver FIFO */
#define UART_FCR_FIFOE     (1 << 0)    /* Transmit and Receive FIFO Enable */

#define UART_LCR_DLAB      (1 << 7)    /* Divisor Latch Access Bit */
#define UART_LCR_SB        (1 << 6)    /* Set Break */
#define UART_LCR_STKYP     (1 << 5)    /* Sticky Parity */
#define UART_LCR_EPS       (1 << 4)    /* Even Parity Select */
#define UART_LCR_PEN       (1 << 3)    /* Parity Enable */
#define UART_LCR_STB       (1 << 2)    /* Stop Bit */
#define UART_LCR_WLS1      (1 << 1)    /* Word Length Select */
#define UART_LCR_WLS0      (1 << 0)    /* Word Length Select */

#define UART_MCR_LOOP      (1 << 4)    /* Loop-back Mode Enable */

#define UART_MSR_DCD       (1 << 7)    /* Data Carrier Detect */
#define UART_MSR_RI        (1 << 6)    /* Ring Indicator */
#define UART_MSR_DSR       (1 << 5)    /* Data Set Ready */
#define UART_MSR_CTS       (1 << 4)    /* Clear To Send */
#define UART_MSR_DDCD      (1 << 3)    /* Delta Data Carrier Detect */
#define UART_MSR_TERI      (1 << 2)    /* Trailing Edge Ring Indicator */
#define UART_MSR_DDSR      (1 << 1)    /* Delta Data Set Ready */
#define UART_MSR_DCTS      (1 << 0)    /* Delta Clear To Send */

#define UART_LSR_FIFOE     (1 << 7)    /* FIFO Error Status */
#define UART_LSR_TEMT      (1 << 6)    /* Transmitter Empty */
#define UART_LSR_TDRQ      (1 << 5)    /* Transmit Data Request */
#define UART_LSR_BI        (1 << 4)    /* Break Interrupt */
#define UART_LSR_FE        (1 << 3)    /* Framing Error */
#define UART_LSR_PE        (1 << 2)    /* Parity Error */
#define UART_LSR_OE        (1 << 1)    /* Overrun Error */
#define UART_LSR_DR        (1 << 0)    /* Data Ready */

/*
 * I2C registers
 */
#define RA_I2C_CONFIG          0x00
#define RA_I2C_CLKDIV          0x04
#define RA_I2C_DEVADDR         0x08
#define RA_I2C_ADDR            0x0C
#define RA_I2C_DATAOUT         0x10
#define RA_I2C_DATAIN          0x14
#define RA_I2C_STATUS          0x18
#define RA_I2C_STARTXFR        0x1C
#define RA_I2C_BYTECNT         0x20

#define  I2C_CONFIG_ADDRLEN(x)     (((x) & 0x7) << 5)
#define   I2C_CONFIG_ADDRLEN_7     6
#define   I2C_CONFIG_ADDRLEN_8     7
#define  I2C_CONFIG_DEVADLEN(x)    (((x) & 0x7) << 2)
#define   I2C_CONFIG_DEVADLEN_6    5
#define   I2C_CONFIG_DEVADLEN_7    6
#define  I2C_CONFIG_ADDRDIS        (1 << 1)
#define  I2C_CONFIG_DEVDIS         (1 << 0)
#define  I2C_STATUS_STARTERR       (1 << 4)
#define  I2C_STATUS_ACKERR         (1 << 3)
#define  I2C_STATUS_DATARDY        (1 << 2)
#define  I2C_STATUS_SDOEMPTY       (1 << 1)
#define  I2C_STATUS_BUSY           (1 << 0)

/*
 * SPI registers
 */
#define RA_SPI_STATUS          0x00
#define RA_SPI_CONFIG          0x10
#define RA_SPI_CONTROL         0x14
#define RA_SPI_DATA            0x20

#define  SPI_STATUS_BUSY            (1 << 0)
#define  SPI_CONFIG_MSBFIRST        (1 << 8)
#define  SPI_CONFIG_CLK             (1 << 6)
#define  SPI_CONFIG_RXCLKEDGE_FALL  (1 << 5)
#define  SPI_CONFIG_TXCLKEDGE_FALL  (1 << 4)
#define  SPI_CONFIG_TRISTATE        (1 << 3)
#define  SPI_CONFIG_RATE(x)         ((x) & 0x7)
#define   SPI_CONFIG_RATE_DIV_2     0
#define   SPI_CONFIG_RATE_DIV_4     1
#define   SPI_CONFIG_RATE_DIV_8     2
#define   SPI_CONFIG_RATE_DIV_16    3
#define   SPI_CONFIG_RATE_DIV_32    4
#define   SPI_CONFIG_RATE_DIV_64    5
#define   SPI_CONFIG_RATE_DIV_128   6
#define   SPI_CONFIG_RATE_DIV_NONE  7
#define  SPI_CONTROL_TRISTATE       (1 << 3)
#define  SPI_CONTROL_STARTWR        (1 << 2)
#define  SPI_CONTROL_STARTRD        (1 << 1)
#define  SPI_CONTROL_ENABLE_LOW     (0 << 0)
#define  SPI_CONTROL_ENABLE_HIGH    (1 << 0)
#define  SPI_DATA_VAL(x)            ((x) & 0xff)

/*
 * Frame Engine registers
 */
#define RA_FE_MDIO_ACCESS      0x000
#define RA_FE_MDIO_CFG1        0x004
#define RA_FE_GLOBAL_CFG       0x008
#define RA_FE_GLOBAL_RESET     0x00C
#define RA_FE_INT_STATUS       0x010
#define RA_FE_INT_ENABLE       0x014
#define RA_FE_MDIO_CFG2        0x018
#define RA_FE_TIME_STAMP       0x01C
#define RA_FE_GDMA1_FWD_CFG    0x020
#define RA_FE_GDMA1_SCHED_CFG  0x024
#define RA_FE_GDMA1_SHAPE_CFG  0x028
#define RA_FE_GDMA1_MAC_LSB    0x02C
#define RA_FE_GDMA1_MAC_MSB    0x030
#define RA_FE_PSE_FQ_CFG       0x040
#define RA_FE_CDMA_FC_CFG      0x044
#define RA_FE_GDMA1_FC_CFG     0x048
#define RA_FE_GDMA2_FC_CFG     0x04C
#define RA_FE_CDMA_OQ_STA      0x050
#define RA_FE_GDMA1_OQ_STA     0x054
#define RA_FE_GDMA2_OQ_STA     0x058
#define RA_FE_PSE_IQ_STA       0x05C
#define RA_FE_GDMA2_FWD_CFG    0x060
#define RA_FE_GDMA2_SCHED_CFG  0x064
#define RA_FE_GDMA2_SHAPE_CFG  0x068
#define RA_FE_GDMA2_MAC_LSB    0x06C
#define RA_FE_GDMA2_MAC_MSB    0x070
#define RA_FE_CDMA_CSG_CFG     0x080
#define RA_FE_CDMA_SCHED_CFG   0x084
#define RA_FE_PPPOE_SID_0001   0x088
#define RA_FE_PPPOE_SID_0203   0x08C
#define RA_FE_PPPOE_SID_0405   0x090
#define RA_FE_PPPOE_SID_0607   0x094
#define RA_FE_PPPOE_SID_0809   0x098
#define RA_FE_PPPOE_SID_1011   0x09C
#define RA_FE_PPPOE_SID_1213   0x0A0
#define RA_FE_PPPOE_SID_1415   0x0A4
#define RA_FE_VLAN_ID_0001     0x0A8
#define RA_FE_VLAN_ID_0203     0x0AC
#define RA_FE_VLAN_ID_0405     0x0B0
#define RA_FE_VLAN_ID_0607     0x0B4
#define RA_FE_VLAN_ID_0809     0x0B8
#define RA_FE_VLAN_ID_1011     0x0BC
#define RA_FE_VLAN_ID_1213     0x0C0
#define RA_FE_VLAN_ID_1415     0x0C4
#define RA_FE_PDMA_GLOBAL_CFG  0x100
#define RA_FE_PDMA_RESET_IDX   0x104
#define RA_FE_PDMA_SCHED_CFG   0x108
#define RA_FE_PDMA_DLY_INT_CFG 0x10C
#define RA_FE_PDMA_TX0_PTR     0x110
#define RA_FE_PDMA_TX0_COUNT   0x114
#define RA_FE_PDMA_TX0_CPU_IDX 0x118
#define RA_FE_PDMA_TX0_DMA_IDX 0x11C
#define RA_FE_PDMA_TX1_PTR     0x120
#define RA_FE_PDMA_TX1_COUNT   0x124
#define RA_FE_PDMA_TX1_CPU_IDX 0x128
#define RA_FE_PDMA_TX1_DMA_IDX 0x12C
#define RA_FE_PDMA_RX0_PTR     0x130
#define RA_FE_PDMA_RX0_COUNT   0x134
#define RA_FE_PDMA_RX0_CPU_IDX 0x138
#define RA_FE_PDMA_RX0_DMA_IDX 0x13C
#define RA_FE_PDMA_TX2_PTR     0x140
#define RA_FE_PDMA_TX2_COUNT   0x144
#define RA_FE_PDMA_TX2_CPU_IDX 0x148
#define RA_FE_PDMA_TX2_DMA_IDX 0x14C
#define RA_FE_PDMA_TX3_PTR     0x150
#define RA_FE_PDMA_TX3_COUNT   0x154
#define RA_FE_PDMA_TX3_CPU_IDX 0x158
#define RA_FE_PDMA_TX3_DMA_IDX 0x15C
#define RA_FE_PDMA_FC_CFG      0x1F0
/* TODO: FE_COUNTERS */

#define  MDIO_ACCESS_TRG         (1 << 31)
#define  MDIO_ACCESS_WR          (1 << 30)
#define  MDIO_ACCESS_PHY_ADDR(x) (((x) & 0x1f) << 24)
#define  MDIO_ACCESS_REG(x)      (((x) & 0x1f) << 16)
#define  MDIO_ACCESS_DATA(x)     ((x) & 0xffff)
#define  MDIO_CFG_AUTO_POLL      (1 << 29)
#define  MDIO_CFG_PHY_ADDR(x)    (((x) & 0x1f) << 24)
#define  MDIO_CFG_BP_EN          (1 << 16)
#define  MDIO_CFG_FORCE_CFG      (1 << 15)
#define  MDIO_CFG_SPEED(x)       (((x) & 0x3) << 13)
#define   MDIO_CFG_SPEED_1000M   2
#define   MDIO_CFG_SPEED_100M    1
#define   MDIO_CFG_SPEED_10M     0
#define  MDIO_CFG_FULL_DUPLEX    (1 << 12)
#define  MDIO_CFG_FC_TX          (1 << 11)
#define  MDIO_CFG_FC_RX          (1 << 10)
#define  MDIO_CFG_LINK_DOWN      (1 << 9)
#define  MDIO_CFG_AUTO_DONE      (1 << 8)
#define  MDIO_CFG_MDC_CLKDIV(x)  (((x) & 0x3) << 6)
#define   MDIO_CFG_MDC_512KHZ    3
#define   MDIO_CFG_MDC_1MHZ      2
#define   MDIO_CFG_MDC_2MHZ      1
#define   MDIO_CFG_MDC_4MHZ      0
#define  MDIO_CFG_TURBO_50MHZ   (1 << 5)
#define  MDIO_CFG_TURBO_EN      (1 << 4)
#define  MDIO_CFG_RX_CLK_SKEW   (((x) & 0x3) << 2)
#define   MDIO_CFG_RX_SKEW_INV   3
#define   MDIO_CFG_RX_SKEW_400PS 2
#define   MDIO_CFG_RX_SKEW_200PS 1
#define   MDIO_CFG_RX_SKEW_ZERO  0
#define  MDIO_CFG_TX_CLK_MODE(x) (((x) & 0x1) << 0)
#define   MDIO_CFG_TX_CLK_MODE_3COM  1
#define   MDIO_CFG_TX_CLK_MODE_HP    0
#define  FE_GLOBAL_CFG_EXT_VLAN(x) (((x) & 0xffff) << 16)
#define  FE_GLOBAL_CFG_US_CLK(x)   (((x) & 0xff) << 8)
#define  FE_GLOBAL_CFG_L2_SPACE(x) (((x) & 0xf) << 4)
#define  FE_GLOBAL_RESET_PSE       (1 << 0)
#define  FE_INT_PPE_COUNT_HIGH     (1 << 31)
#define  FE_INT_DMA_COUNT_HIGH     (1 << 29)
#define  FE_INT_PSE_P2_FC_ASSERT   (1 << 26)
#define  FE_INT_PSE_FC_DROP        (1 << 24)
#define  FE_INT_GDMA_DROP_OTHER    (1 << 23)
#define  FE_INT_PSE_P1_FC_ASSERT   (1 << 22)
#define  FE_INT_PSE_P0_FC_ASSERT   (1 << 21)
#define  FE_INT_PSE_FQ_EMPTY       (1 << 20)
#define  FE_INT_TX_COHERENT        (1 << 17)
#define  FE_INT_RX_COHERENT        (1 << 16)
#define  FE_INT_TX3                (1 << 11)
#define  FE_INT_TX2                (1 << 10)
#define  FE_INT_TX1                (1 << 9)
#define  FE_INT_TX0                (1 << 8)
#define  FE_INT_RX                 (1 << 2)
#define  FE_INT_TX_DELAY           (1 << 1)
#define  FE_INT_RX_DELAY           (1 << 0)
#define  FE_GDMA_FWD_CFG_JUMBO_LEN(x)  (((x) & 0xf) << 28)
#define  FE_GDMA_FWD_CFG_DROP_256B     (1 << 23)
#define  FE_GDMA_FWD_CFG_IP4_CRC_EN    (1 << 22)
#define  FE_GDMA_FWD_CFG_TCP_CRC_EN    (1 << 21)
#define  FE_GDMA_FWD_CFG_UDP_CRC_EN    (1 << 20)
#define  FE_GDMA_FWD_CFG_JUMBO_EN      (1 << 19)
#define  FE_GDMA_FWD_CFG_DIS_TX_PAD    (1 << 18)
#define  FE_GDMA_FWD_CFG_DIS_TX_CRC    (1 << 17)
#define  FE_GDMA_FWD_CFG_STRIP_RX_CRC  (1 << 16)
#define  FE_GDMA_FWD_CFG_UNICA_PORT(x) (((x) & 0x3) << 12)
#define  FE_GDMA_FWD_CFG_BROAD_PORT(x) (((x) & 0x3) << 8)
#define  FE_GDMA_FWD_CFG_MULTI_PORT(x) (((x) & 0x3) << 6)
#define  FE_GDMA_FWD_CFG_OTHER_PORT(x) (((x) & 0x3) << 0)
#define   FE_GDMA_FWD_CFG_PORT_DROP  7
#define   FE_GDMA_FWD_CFG_PORT_PPE   6
#define   FE_GDMA_FWD_CFG_PORT_GDMA2 2
#define   FE_GDMA_FWD_CFG_PORT_GDMA1 1
#define   FE_GDMA_FWD_CFG_PORT_CPU   0
#define  FE_PSE_FQ_MAX_COUNT(x)  (((x) & 0xff) << 24)
#define  FE_PSE_FQ_FC_RELEASE(x) (((x) & 0xff) << 16)
#define  FE_PSE_FQ_FC_ASSERT(x)  (((x) & 0xff) << 8)
#define  FE_PSE_FQ_FC_DROP(x)    (((x) & 0xff) << 0)
#define  FE_CDMA_CSG_CFG_VLAN_TAG(x) (((x) & 0xffff) << 16)
#define  FE_CDMA_CSG_CFG_IP4_CRC_EN  (1 << 2)
#define  FE_CDMA_CSG_CFG_UDP_CRC_EN  (1 << 1)
#define  FE_CDMA_CSG_CFG_TCP_CRC_EN  (1 << 0)
#define  FE_PDMA_GLOBAL_CFG_HDR_SEG_LEN  (1 << 16)
#define  FE_PDMA_GLOBAL_CFG_TX_WB_DDONE  (1 << 6)
#define  FE_PDMA_GLOBAL_CFG_BURST_SZ(x)  (((x) & 0x3) << 4)
#define   FE_PDMA_GLOBAL_CFG_BURST_SZ_4  (0 << 4)
#define   FE_PDMA_GLOBAL_CFG_BURST_SZ_8  (1 << 4)
#define   FE_PDMA_GLOBAL_CFG_BURST_SZ_16 (2 << 4)
#define  FE_PDMA_GLOBAL_CFG_RX_DMA_BUSY  (1 << 3)
#define  FE_PDMA_GLOBAL_CFG_RX_DMA_EN    (1 << 2)
#define  FE_PDMA_GLOBAL_CFG_TX_DMA_BUSY  (1 << 1)
#define  FE_PDMA_GLOBAL_CFG_TX_DMA_EN    (1 << 0)
#define  PDMA_RST_RX0          (1 << 16)
#define  PDMA_RST_TX3          (1 << 3)
#define  PDMA_RST_TX2          (1 << 2)
#define  PDMA_RST_TX1          (1 << 1)
#define  PDMA_RST_TX0          (1 << 0)

/*
 * 10/100 Switch registers
 */

#define RA_ETH_SW_ISR    0x00
#define RA_ETH_SW_IMR    0x04
#define RA_ETH_SW_FCT0   0x08
#define RA_ETH_SW_FCT1   0x0C
#define RA_ETH_SW_PFC0   0x10
#define RA_ETH_SW_PFC1   0x14
#define RA_ETH_SW_PFC2   0x18
#define RA_ETH_SW_QCS0   0x1C
#define RA_ETH_SW_QCS1   0x20
#define RA_ETH_SW_ATS    0x24
#define RA_ETH_SW_ATS0   0x28
#define RA_ETH_SW_ATS1   0x2C
#define RA_ETH_SW_ATS2   0x30
#define RA_ETH_SW_WMAD0  0x34
#define RA_ETH_SW_WMAD1  0x38
#define RA_ETH_SW_WMAD2  0x3C
#define RA_ETH_SW_PVIDC0 0x40
#define RA_ETH_SW_PVIDC1 0x44
#define RA_ETH_SW_PVIDC2 0x48
#define RA_ETH_SW_PVIDC3 0x4C
#define RA_ETH_SW_VLANI0 0x50
#define RA_ETH_SW_VLANI1 0x54
#define RA_ETH_SW_VLANI2 0x58
#define RA_ETH_SW_VLANI3 0x5C
#define RA_ETH_SW_VLANI4 0x60
#define RA_ETH_SW_VLANI5 0x64
#define RA_ETH_SW_VLANI6 0x68
#define RA_ETH_SW_VLANI7 0x6C
#define RA_ETH_SW_VMSC0  0x70
#define RA_ETH_SW_VMSC1  0x74
#define RA_ETH_SW_VMSC2  0x78
#define RA_ETH_SW_VMSC3  0x7C
#define RA_ETH_SW_POA    0x80
#define RA_ETH_SW_FPA    0x84
#define RA_ETH_SW_PTS    0x88
#define RA_ETH_SW_SOCPC  0x8C
#define RA_ETH_SW_POC0   0x90
#define RA_ETH_SW_POC1   0x94
#define RA_ETH_SW_POC2   0x98
#define RA_ETH_SW_SWGC   0x9C
#define RA_ETH_SW_RST    0xA0
#define RA_ETH_SW_LEDP0  0xA4
#define RA_ETH_SW_LEDP1  0xA8
#define RA_ETH_SW_LEDP2  0xAC
#define RA_ETH_SW_LEDP3  0xB0
#define RA_ETH_SW_LEDP4  0xB4
#define RA_ETH_SW_WDOG   0xB8
#define RA_ETH_SW_DBG    0xBC
#define RA_ETH_SW_PCTL0  0xC0
#define RA_ETH_SW_PCTL1  0xC4
#define RA_ETH_SW_FPORT  0xC8
#define RA_ETH_SW_FTC2   0xCC
#define RA_ETH_SW_QSS0   0xD0
#define RA_ETH_SW_QSS1   0xD4
#define RA_ETH_SW_DBGC   0xD8
#define RA_ETH_SW_MTI1   0xDC
#define RA_ETH_SW_PPC    0xE0
#define RA_ETH_SW_SGC2   0xE4
#define RA_ETH_SW_PCNT0  0xE8
#define RA_ETH_SW_PCNT1  0xEC
#define RA_ETH_SW_PCNT2  0xF0
#define RA_ETH_SW_PCNT3  0xF4
#define RA_ETH_SW_PCNT4  0xF8
#define RA_ETH_SW_PCNT5  0xFC

#define  ISR_WDOG1_EXPIRED    (1 << 29)
#define  ISR_WDOG0_EXPIRED    (1 << 28)
#define  ISR_HAS_INTRUDER     (1 << 27)
#define  ISR_PORT_STS_CHNG    (1 << 26)
#define  ISR_BRDCAST_STORM    (1 << 25)
#define  ISR_MUST_DROP_LAN    (1 << 24)
#define  ISR_GLOB_QUE_FULL    (1 << 23)
#define  ISR_LAN_QUE6_FULL    (1 << 20)
#define  ISR_LAN_QUE5_FULL    (1 << 19)
#define  ISR_LAN_QUE4_FULL    (1 << 18)
#define  ISR_LAN_QUE3_FULL    (1 << 17)
#define  ISR_LAN_QUE2_FULL    (1 << 16)
#define  ISR_LAN_QUE1_FULL    (1 << 15)
#define  ISR_LAN_QUE0_FULL    (1 << 14)
#define  FTC0_REL_THR          24
#define  FTC0_SET_THR          16
#define  FTC0_DROP_REL_THR     8
#define  FTC0_DROP_SET_THR     0
#define  FTC1_PER_PORT_THR     0
#define  PCTL0_WR_VAL(x) (((x) & 0xffff) << 16)
#define  PCTL0_RD_CMD    (1 << 14)
#define  PCTL0_WR_CMD    (1 << 13)
#define  PCTL0_REG(x)    (((x) & 0x1f) << 8)
#define  PCTL0_ADDR(x)   (((x) & 0x1f) << 0)
#define  PCTL1_RD_VAL(x) (((x) >> 16) & 0xffff)
#define  PCTL1_RD_DONE   (1 << 1)	/* read clear */
#define  PCTL1_WR_DONE   (1 << 0)	/* read clear */
#define  SGC2_WL_FC_EN       (1 << 30)
#define  SGC2_PORT5_IS_LAN   (1 << 29)
#define  SGC2_PORT4_IS_LAN   (1 << 28)
#define  SGC2_PORT3_IS_LAN   (1 << 27)
#define  SGC2_PORT2_IS_LAN   (1 << 26)
#define  SGC2_PORT1_IS_LAN   (1 << 25)
#define  SGC2_PORT0_IS_LAN   (1 << 24)
#define  SGC2_TX_CPU_TPID(x) ((x) << 16)
#define  SGC2_ARBITER_LAN_EN (1 << 11)
#define  SGC2_CPU_TPID_EN    (1 << 10)
#define  SGC2_DBL_TAG_EN5    (1 << 5)
#define  SGC2_DBL_TAG_EN4    (1 << 4)
#define  SGC2_DBL_TAG_EN3    (1 << 3)
#define  SGC2_DBL_TAG_EN2    (1 << 2)
#define  SGC2_DBL_TAG_EN1    (1 << 1)
#define  SGC2_DBL_TAG_EN0    (1 << 0)


#define FTC_THR_MSK           0xff

#define PFC0_MTCC_LIMIT       24
#define PFC0_TURN_OFF_CF      16
#define PFC0_TURN_OFF_CF_MSK  0xff
#define PFC0_VO_NUM           12
#define PFC0_CL_NUM           8
#define PFC0_BE_NUM           4
#define PFC0_BK_NUM           0
#define PFC0_NUM_MSK          0xf

#define PFC1_P6_Q1_EN        (1 << 31)
#define PFC1_P6_TOS_EN       (1 << 30)
#define PFC1_P5_TOS_EN       (1 << 29)
#define PFC1_P4_TOS_EN       (1 << 28)
#define PFC1_P3_TOS_EN       (1 << 27)

#define PFC1_P1_TOS_EN       (1 << 25)
#define PFC1_P0_TOS_EN       (1 << 24)
#define PFC1_PORT_PRI6        12
#define PFC1_PORT_PRI5        10
#define PFC1_PORT_PRI4        8
#define PFC1_PORT_PRI3        6
#define PFC1_PORT_PRI2        4
#define PFC1_PORT_PRI1        2
#define PFC1_PORT_PRI0        0
#define PFC1_PORT_MSK         0x3

#define PFC2_PRI_THR_VO       24
#define PFC2_PRI_THR_CL       16
#define PFC2_PRI_THR_BE       8
#define PFC2_PRI_THR_BK       0
#define PFC2_PRI_THR_MSK      0xff

#define GQC0_EMPTY_BLOCKS      0
#define GQC0_EMPTY_BLOCKS_MSK  0xff

/*
 * USB OTG Registers
 */
#define RA_USB_OTG_OTG_CNTRL       0x000
#define RA_USB_OTG_OTG_INT         0x004
#define RA_USB_OTG_AHB_CFG         0x008
#define RA_USB_OTG_CFG             0x00C
#define RA_USB_OTG_RESET           0x010
#define RA_USB_OTG_INT             0x014
#define RA_USB_OTG_INT_MASK        0x018
#define RA_USB_OTG_RX_STAT         0x01C
#define RA_USB_OTG_RX_POP_STAT     0x020
#define RA_USB_OTG_RX_FIFO_SZ      0x024
#define RA_USB_OTG_TX_FIFO_SZ      0x028
#define RA_USB_OTG_TX_FIFO_STAT    0x02C
#define RA_USB_OTG_I2C_ACCESS      0x030
#define RA_USB_OTG_PHY_CTL         0x034
#define RA_USB_OTG_GPIO            0x038
#define RA_USB_OTG_GUID            0x03C
#define RA_USB_OTG_SNPSID          0x040
#define RA_USB_OTG_HWCFG1          0x044
#define RA_USB_OTG_HWCFG2          0x048
#define RA_USB_OTG_HWCFG3          0x04C
#define RA_USB_OTG_HWCFG4          0x050
#define RA_USB_OTG_HC_TX_FIFO_SZ   0x100
#define RA_USB_OTG_DV_TX_FIFO_SZ   0x104
#define RA_USB_OTG_HC_CFG          0x400
#define RA_USB_OTG_HC_FRM_INTRVL   0x404
#define RA_USB_OTG_HC_FRM_NUM      0x408
#define RA_USB_OTG_HC_TX_STAT      0x410
#define RA_USB_OTG_HC_INT          0x414
#define RA_USB_OTG_HC_INT_MASK     0x418
#define RA_USB_OTG_HC_PORT         0x440
#define RA_USB_OTG_HC_CH_CFG       0x500
#define RA_USB_OTG_HC_CH_SPLT      0x504
#define RA_USB_OTG_HC_CH_INT       0x508
#define RA_USB_OTG_HC_CH_INT_MASK  0x50C
#define RA_USB_OTG_HC_CH_XFER      0x510
#define RA_USB_OTG_HC_CH_DMA_ADDR  0x514
#define RA_USB_OTG_DV_CFG          0x800
#define RA_USB_OTG_DV_CTL          0x804
#define RA_USB_OTG_DV_STAT         0x808
#define RA_USB_OTG_DV_IN_INT_MASK  0x810
#define RA_USB_OTG_DV_OUT_INT_MASK 0x814
#define RA_USB_OTG_DV_ALL_INT      0x818
#define RA_USB_OTG_DV_EP_INT_MASK  0x81c
#define RA_USB_OTG_DV_IN_SEQ_RQ1   0x820
#define RA_USB_OTG_DV_IN_SEQ_RQ2   0x824
#define RA_USB_OTG_DV_IN_SEQ_RQ3   0x830
#define RA_USB_OTG_DV_IN_SEQ_RQ4   0x834
#define RA_USB_OTG_DV_VBUS_DISCH   0x828
#define RA_USB_OTG_DV_VBUS_PULSE   0x82c
#define RA_USB_OTG_DV_THRESH_CTL   0x830
#define RA_USB_OTG_DV_IN_FIFO_INT  0x834
#define RA_USB_OTG_DV_IN0_CTL      0x900

#define  OTG_OTG_CNTRL_B_SESS_VALID      (1 << 19)
#define  OTG_OTG_CNTRL_A_SESS_VALID      (1 << 18)
#define  OTG_OTG_CNTRL_DEBOUNCE_SHORT    (1 << 17)
#define  OTG_OTG_CNTRL_CONNID_STATUS     (1 << 16)
#define  OTG_OTG_CNTRL_DV_HNP_EN         (1 << 11)
#define  OTG_OTG_CNTRL_HC_SET_HNP_EN     (1 << 10)
#define  OTG_OTG_CNTRL_HNP_REQ           (1 << 9)
#define  OTG_OTG_CNTRL_HNP_SUCCESS       (1 << 8)
#define  OTG_OTG_CNTRL_SESS_REQ          (1 << 1)
#define  OTG_OTG_CNTRL_SESS_REQ_SUCCESS  (1 << 0)
#define  OTG_OTG_INT_DEBOUNCE_DONE       (1 << 19)
#define  OTG_OTG_INT_ADEV_TIMEOUT        (1 << 18)
#define  OTG_OTG_INT_HOST_NEG_DETECT     (1 << 17)
#define  OTG_OTG_INT_HOST_NEG_STATUS     (1 << 9)
#define  OTG_OTG_INT_SESSION_REQ_STATUS  (1 << 8)
#define  OTG_OTG_INT_SESSION_END_STATUS  (1 << 2)
#define  OTG_AHB_CFG_TX_PFIFO_EMPTY_INT_EN  (1 << 8)
#define  OTG_AHB_CFG_TX_NPFIFO_EMPTY_INT_EN (1 << 7)
#define  OTG_AHB_CFG_DMA_EN                 (1 << 5)
#define  OTG_AHB_CFG_BURST(x)               (((x) & 0xf) << 1)
#define   OTG_AHB_CFG_BURST_SINGLE	     0
#define   OTG_AHB_CFG_BURST_INCR  	     1
#define   OTG_AHB_CFG_BURST_INCR4 	     3
#define   OTG_AHB_CFG_BURST_INCR8 	     5
#define   OTG_AHB_CFG_BURST_INCR16	     7
#define  OTG_AHB_CFG_GLOBAL_INT_EN          (1 << 0)
#define  OTG_CFG_CORRUPT_TX              (1 << 31)
#define  OTG_CFG_FORCE_DEVICE            (1 << 30)
#define  OTG_CFG_FORCE_HOST              (1 << 29)
#define  OTG_CFG_ULPI_EXT_VBUS_IND_SEL   (1 << 22)
#define  OTG_CFG_ULPI_EXT_VBUS_IND       (1 << 21)
#define  OTG_CFG_ULPI_EXT_VBUS_DRV       (1 << 20)
#define  OTG_CFG_ULPI_CLOCK_SUSPEND      (1 << 19)
#define  OTG_CFG_ULPI_AUTO_RESUME        (1 << 18)
#define  OTG_CFG_ULPI_FS_LS_SEL          (1 << 17)
#define  OTG_CFG_UTMI_I2C_SEL            (1 << 16)
#define  OTG_CFG_TURNAROUND_TIME(x)      (((x) & 0xf) << 10)
#define  OTG_CFG_HNP_CAP                 (1 << 9)
#define  OTG_CFG_SRP_CAP                 (1 << 8)
#define  OTG_CFG_ULPI_DDR_SEL            (1 << 7)
#define  OTG_CFG_HS_PHY_SEL              (1 << 6)
#define  OTG_CFG_FS_IF_SEL               (1 << 5)
#define  OTG_CFG_ULPI_UTMI_SEL           (1 << 4)
#define  OTG_CFG_PHY_IF                  (1 << 3)
#define  OTG_CFG_TIMEOUT(x)              (((x) & 0x7) << 0)
#define  OTG_RST_AHB_IDLE                (1 << 31)
#define  OTG_RST_DMA_ACTIVE              (1 << 30)
#define  OTG_RST_TXQ_TO_FLUSH(x)         (((x) & 0x1f) << 6)
#define   OTG_RST_TXQ_FLUSH_ALL          0x10
#define  OTG_RST_TXQ_FLUSH               (1 << 5)
#define  OTG_RST_RXQ_FLUSH               (1 << 4)
#define  OTG_RST_INQ_FLUSH               (1 << 3)
#define  OTG_RST_HC_FRAME                (1 << 2)
#define  OTG_RST_AHB                     (1 << 1)
#define  OTG_RST_CORE                    (1 << 0)
#define  OTG_INT_RESUME                  (1 << 31)
#define  OTG_INT_SESSION_REQ             (1 << 30)
#define  OTG_INT_DISCONNECT              (1 << 29)
#define  OTG_INT_CONNID_STATUS           (1 << 28)
#define  OTG_INT_PTX_EMPTY               (1 << 26)
#define  OTG_INT_HOST_CHANNEL            (1 << 25)
#define  OTG_INT_PORT_STATUS             (1 << 24)
#define  OTG_INT_DMA_FETCH_SUSPEND       (1 << 22)
#define  OTG_INT_INCOMPLETE_PERIODIC     (1 << 21)
#define  OTG_INT_INCOMPLETE_ISOC         (1 << 20)
#define  OTG_INT_DV_OUT_EP               (1 << 19)
#define  OTG_INT_DV_IN_EP                (1 << 18)
#define  OTG_INT_DV_EP_MISMATCH          (1 << 17)
#define  OTG_INT_DV_PERIODIC_END         (1 << 15)
#define  OTG_INT_DV_ISOC_OUT_DROP        (1 << 14)
#define  OTG_INT_DV_ENUM_COMPLETE        (1 << 13)
#define  OTG_INT_DV_USB_RESET            (1 << 12)
#define  OTG_INT_DV_USB_SUSPEND          (1 << 11)
#define  OTG_INT_DV_USB_EARLY_SUSPEND    (1 << 10)
#define  OTG_INT_I2C                     (1 << 9)
#define  OTG_INT_ULPI_CARKIT             (1 << 8)
#define  OTG_INT_DV_OUT_NAK_EFFECTIVE    (1 << 7)
#define  OTG_INT_DV_IN_NAK_EFFECTIVE     (1 << 6)
#define  OTG_INT_NPTX_EMPTY              (1 << 5)
#define  OTG_INT_RX_FIFO                 (1 << 4)
#define  OTG_INT_SOF                     (1 << 3)
#define  OTG_INT_OTG                     (1 << 2)
#define  OTG_INT_MODE_MISMATCH           (1 << 1)
#define  OTG_INT_MODE                    (1 << 0)
#define  USB_OTG_SNPSID_CORE_REV_2_00  0x4F542000
#define  OTG_HC_CFG_FORCE_NO_HS          (1 << 2)
#define  OTG_HC_CFG_FSLS_CLK_SEL(x)      (((x) & 0x3) << 0)
#define   OTG_HC_CFG_FS_CLK_3060         0
#define   OTG_HC_CFG_FS_CLK_48           1
#define   OTG_HC_CFG_LS_CLK_3060         0
#define   OTG_HC_CFG_LS_CLK_48           1
#define   OTG_HC_CFG_LS_CLK_6            2
#define  USB_OTG_HC_FRM_NUM(x)            (x & 0x3fff)
#define  USB_OTG_HC_FRM_REM(x)            (x >> 16)
#define  USB_OTG_HC_PORT_SPEED(x)         (((x) >> 17) & 0x3)
#define   USB_OTG_HC_PORT_SPEED_HS        0
#define   USB_OTG_HC_PORT_SPEED_FS        1
#define   USB_OTG_HC_PORT_SPEED_LS        2
#define  USB_OTG_HC_PORT_TEST(x)          (((x) & 0xf) << 13)
#define   USB_OTG_HC_PORT_TEST_DISABLED   0
#define   USB_OTG_HC_PORT_TEST_J_MODE     1
#define   USB_OTG_HC_PORT_TEST_K_MODE     2
#define   USB_OTG_HC_PORT_TEST_NAK_MODE   3
#define   USB_OTG_HC_PORT_TEST_PKT_MODE   4
#define   USB_OTG_HC_PORT_TEST_FORCE_MODE 5
#define  USB_OTG_HC_PORT_POWER            (1 << 12)
#define  USB_OTG_HC_PORT_LINE_STAT        (((x) >> 10) & 0x3)
#define   USB_OTG_HC_PORT_LINE_STAT_DP    1
#define   USB_OTG_HC_PORT_LINE_STAT_DM    3
#define  USB_OTG_HC_PORT_RESET            (1 << 8)
#define  USB_OTG_HC_PORT_SUSPEND          (1 << 7)
#define  USB_OTG_HC_PORT_RESUME           (1 << 6)
#define  USB_OTG_HC_PORT_OVCURR_CHANGE    (1 << 5)
#define  USB_OTG_HC_PORT_OVCURR           (1 << 4)
#define  USB_OTG_HC_PORT_ENABLE_CHANGE    (1 << 3)
#define  USB_OTG_HC_PORT_ENABLE           (1 << 2)
#define  USB_OTG_HC_PORT_CONNECT_CHANGE   (1 << 1)
#define  USB_OTG_HC_PORT_STATUS           (1 << 0)
#define  USB_OTG_HC_CH_CFG_ENABLE         (1 << 31)
#define  USB_OTG_HC_CH_CFG_DISABLE        (1 << 30)
#define  USB_OTG_HC_CH_CFG_ODD_FRAME      (1 << 29)
#define  USB_OTG_HC_CH_CFG_DEV_ADDR(x)    (((x) & 0x7f) << 22)
#define  USB_OTG_HC_CH_CFG_MULTI_CNT(x)   (((x) & 0x3) << 20)
#define  USB_OTG_HC_CH_CFG_EP_TYPE(x)     (((x) & 0x3) << 18)
#define   USB_OTG_HC_CH_CFG_EP_TYPE_CTRL   0
#define   USB_OTG_HC_CH_CFG_EP_TYPE_ISOC   1
#define   USB_OTG_HC_CH_CFG_EP_TYPE_BULK   2
#define   USB_OTG_HC_CH_CFG_EP_TYPE_INTR   3
#define  USB_OTG_HC_CH_CFG_LS             (1 << 17)
#define  USB_OTG_HC_CH_CFG_EP_DIR(x)      (((x) & 0x1) << 15)
#define   USB_OTG_HC_CH_CFG_EP_DIR_OUT     0
#define   USB_OTG_HC_CH_CFG_EP_DIR_IN      1
#define  USB_OTG_HC_CH_CFG_EP_NUM(x)      (((x) & 0xf) << 11)
#define  USB_OTG_HC_CH_CFG_MAX_PKT_SZ(x)  (((x) & 0x7ff) << 0)
#define  USB_OTG_HC_CH_SPLT_EN           (1 << 31)
#define  USB_OTG_HC_CH_SPLT_COMPLETE     (1 << 16)
#define  USB_OTG_HC_CH_SPLT_POS(x)       (((x) & 0x3) << 14)
#define   USB_OTG_HC_CH_SPLT_POS_MID      0
#define   USB_OTG_HC_CH_SPLT_POS_END      1
#define   USB_OTG_HC_CH_SPLT_POS_BEGIN    2
#define   USB_OTG_HC_CH_SPLT_POS_ALL      3
#define  USB_OTG_HC_CH_SPLT_HUB_ADDR(x)  (((x) & 0x7f) << 7)
#define  USB_OTG_HC_CH_SPLT_PORT_ADDR(x) (((x) & 0x7f) << 0)
#define  USB_OTG_HC_CH_INT_ALL            0x7ff
#define  USB_OTG_HC_CH_INT_TOGGLE_ERROR   (1 << 10)
#define  USB_OTG_HC_CH_INT_FRAME_OVERRUN  (1 << 9)
#define  USB_OTG_HC_CH_INT_BABBLE_ERROR   (1 << 8)
#define  USB_OTG_HC_CH_INT_XACT_ERROR     (1 << 7)
#define  USB_OTG_HC_CH_INT_NYET           (1 << 6)
#define  USB_OTG_HC_CH_INT_ACK            (1 << 5)
#define  USB_OTG_HC_CH_INT_NAK            (1 << 4)
#define  USB_OTG_HC_CH_INT_STALL          (1 << 3)
#define  USB_OTG_HC_CH_INT_DMA_ERROR      (1 << 2)
#define  USB_OTG_HC_CH_INT_HALTED         (1 << 1)
#define  USB_OTG_HC_CH_INT_XFER_COMPLETE  (1 << 0)
#define  USB_OTG_HC_CH_XFER_DO_PING      (1 << 31)
#define  USB_OTG_HC_CH_WR_XFER_PID(x)       (((x) & 0x3) << 29)
#define  USB_OTG_HC_CH_RD_XFER_PID(x)       (((x) >> 29) & 0x3)
#define  USB_OTG_HC_CH_XFER_PID_DATA0    0
#define  USB_OTG_HC_CH_XFER_PID_DATA2    1
#define  USB_OTG_HC_CH_XFER_PID_DATA1    2
#define  USB_OTG_HC_CH_XFER_PID_SETUP    3
#define  USB_OTG_HC_CH_XFER_PID_MDATA    3
#define  USB_OTG_HC_CH_XFER_SET_PKT_CNT(x)   (((x) & 0x3ff) << 19)
#define  USB_OTG_HC_CH_XFER_SET_BYTES(x)     ((x) & 0x7ffff)
#define  USB_OTG_HC_CH_XFER_GET_PKT_CNT(x)   (((x) >> 19) & 0x3ff)
#define  USB_OTG_HC_CH_XFER_GET_BYTES(x)     ((x) & 0x7ffff)

#endif /* _RALINK_REG_H_ */

File Added: src/sys/arch/mips/ralink/ralink_usbhcvar.h
/*	$NetBSD: ralink_usbhcvar.h,v 1.2 2011/07/28 15:38:49 matt Exp $	*/
/*-
 * Copyright (c) 2011 CradlePoint Technology, Inc.
 * 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, 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 CRADLEPOINT TECHNOLOGY, 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 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.
 */

#ifndef _RALINK_USBHCVAR_H_
#define _RALINK_USBHCVAR_H_

#include <mips/ralink/ralink_var.h>

/*
 * EHCI controllers need a way to find their compainion controllers
 * so we keep track of them as we attach.
 */

struct ralink_usb_hc {
	TAILQ_ENTRY(ralink_usb_hc) next;
	struct device *usb;
};

void ralink_usb_hc_add(struct ralink_usb_hc *, struct device *);
void ralink_usb_hc_rem(struct ralink_usb_hc *);

#endif	/* _RALINK_USBHCVAR_H_ */

File Added: src/sys/arch/mips/ralink/ralink_var.h
/*	$NetBSD: ralink_var.h,v 1.2 2011/07/28 15:38:49 matt Exp $	*/
/*-
 * Copyright (c) 2011 CradlePoint Technology, Inc.
 * 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, 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 CRADLEPOINT TECHNOLOGY, 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 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.
 */

#ifndef _RALINK_VAR_H_
#define _RALINK_VAR_H_

#include <machine/bus.h>

extern void ralink_com_early(int);

extern void *ra_intr_establish(int, int (*)(void *), void *, int);
extern void ra_intr_disestablish(void *);

extern void ra_bus_init(void);
extern int  ra_spiflash_read(void *, vaddr_t, vsize_t, char *);

extern void ra_gpio_toggle_LED(void *);

extern struct mips_bus_space     ra_bus_memt;
extern struct mips_bus_dma_tag	 ra_bus_dmat;

struct mainbus_attach_args {
	const char     *ma_name;
	bus_space_tag_t ma_memt;
	bus_dma_tag_t   ma_dmat;
};

#define SERIAL_CONSOLE 1
#define NO_SECURITY    2
extern int ra_check_memo_reg(int);

/* helper defines */
#define MS_TO_HZ(ms) ((ms) * hz / 1000)

#if 0
#define RA_CONSOLE_EARLY 1
extern void ra_console_early(void);
#endif

#endif	/* _RALINK_VAR_H_ */

File Added: src/sys/arch/mips/ralink/ralink_wdog.c
/*	$NetBSD: ralink_wdog.c,v 1.2 2011/07/28 15:38:49 matt Exp $	*/
/*-
 * Copyright (c) 2011 CradlePoint Technology, Inc.
 * 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, 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 CRADLEPOINT TECHNOLOGY, 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 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.
 */

/*
 * ra_wdog.c -- Ralink 305x Watchdog Timer driver
 *
 * Timer 1 is used as a system reset watchdog timer
 * Timer 0 is (optionally) used as a periodic watchdog service interrupt
 *
 * NetBSD sysmon watchdog is used in mode defined by RA_WDOG_DEFAULT_MODE
 * (which can be set via kernel config), or by mode passed to
 * our 'smw_setmode' function.  The mode used determines what
 * mechanism is used to periodically service the watchdog.
 *
 * KTICKLE mode is default and supports 2 variants, allowing some control
 * over the priority of the service routine:
 *
 * 1. the specified reset period is a positive integer:
 *    A callout runs the 'smw_tickle' function at IPL_SOFTCLOCK for service.
 *    If your system cannot make "forward progress" without softints running,
 *    you should use this variant.
 *
 * 2. the specified reset period is a negative integer:
 *    Timer 0 interrupt runs ra_wdog_timer0() at IPL_VM for service.
 *    If your system can make "forward progress" while spelding long times
 *    at IPL_VM, you should use this variant.
 *    The numbner is rectified 
 *
 * The reset period is defined by RA_WDOG_DEFAULT_PERIOD
 * (which can be set via kernel config), or by period passed to
 * our 'smw_setmode' function.  The interrupt service interval
 * is half the reset interval.
 *
 */

#include "rwdog.h"

#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ralink_wdog.c,v 1.2 2011/07/28 15:38:49 matt Exp $");

#include <sys/param.h>
#include <sys/bus.h>
#include <sys/device.h>
#include <sys/systm.h>
#include <sys/wdog.h>

#include <mips/ralink/ralink_var.h>
#include <mips/ralink/ralink_reg.h>

#include <dev/sysmon/sysmonvar.h>

#if 0
# define DISABLE_WATCHDOG
#endif

#ifndef RA_WDOG_DEFAULT_MODE
# define RA_WDOG_DEFAULT_MODE	WDOG_MODE_KTICKLE
#endif

/*
 * PERIODs are in in seconds;
 * the counter is 16-bits;
 * maximum period depends on bus freq
 */
#ifndef RA_WDOG_DEFAULT_PERIOD
# define RA_WDOG_DEFAULT_PERIOD	10
#endif
#define WDOG_COUNT_MASK		0xffff
#define WDOG_MAX_COUNT		WDOG_COUNT_MASK
#define WDOG_MAX_PERIOD	\
		(WDOG_MAX_COUNT / (RA_BUS_FREQ / WDOG_MAX_COUNT))

static int  ra_wdog_match(device_t, cfdata_t, void *);
static void ra_wdog_attach(device_t, device_t, void *);
static int  ra_wdog_tickle(struct sysmon_wdog *);
static int  ra_wdog_timer0(void *);
static int  ra_wdog_setmode(struct sysmon_wdog *);

extern int sysmon_wdog_setmode(struct sysmon_wdog *, int, u_int);

typedef struct ra_wdog_softc {
	device_t		sc_dev;
	struct sysmon_wdog 	sc_smw;
	bus_space_tag_t		sc_memt;
	bus_space_handle_t	sc_memh;
	void			*sc_ih;
} ra_wdog_softc_t;


CFATTACH_DECL_NEW(rwdog, sizeof(struct ra_wdog_softc),
	ra_wdog_match, ra_wdog_attach, NULL, NULL);

static const char *wdog_modestr[WDOG_MODE_MASK+1] = {
	[ WDOG_MODE_DISARMED ] = "DISARMED",
	[ WDOG_MODE_KTICKLE  ] = "KTICKLE",
	[ WDOG_MODE_UTICKLE  ] = "UTICKLE",
	[ WDOG_MODE_ETICKLE  ] = "ETICKLE"
};

static inline void
ra_wdog_reset(const ra_wdog_softc_t *sc)
{
	uint32_t r;

	r = bus_space_read_4(sc->sc_memt, sc->sc_memh, RA_TIMER_STAT);
	r |= TIMER_1_RESET;
	bus_space_write_4(sc->sc_memt, sc->sc_memh, RA_TIMER_STAT, r);
}

static inline u_int32_t
ra_wdog_sec_to_count(u_int nsec)
{
	KASSERT(nsec <= WDOG_MAX_PERIOD);
	const u_int32_t count = (RA_BUS_FREQ / WDOG_MAX_COUNT) * nsec;
	KASSERT(count <= WDOG_MAX_COUNT);
	return count;
}

static int
ra_wdog_match(device_t parent, cfdata_t cf, void *aux)
{
	return 1;
}

static void
ra_wdog_attach(device_t parent, device_t self, void *aux)
{
	ra_wdog_softc_t * const sc = device_private(self);
	const struct mainbus_attach_args *ma = aux;
	bus_space_handle_t memh;
	int error;

	aprint_naive(": Ralink watchdog controller\n");
	aprint_normal(": Ralink watchdog controller\n");
	aprint_normal_dev(self, "max period %d sec.\n", WDOG_MAX_PERIOD);

	error = bus_space_map(ma->ma_memt, RA_TIMER_BASE, 0x100, 0, &memh);
	if (error != 0) {
		aprint_error_dev(self, "unable to map registers, "
			"error=%d\n", error);
                return;
	}
 
	sc->sc_memt = ma->ma_memt;
	sc->sc_memh = memh;

	sc->sc_smw.smw_name = device_xname(self);
	sc->sc_smw.smw_cookie = sc;
	sc->sc_smw.smw_setmode = ra_wdog_setmode;
	sc->sc_smw.smw_tickle = ra_wdog_tickle;
	sc->sc_smw.smw_period = RA_WDOG_DEFAULT_PERIOD;

	error = sysmon_wdog_register(&sc->sc_smw);
	if (error != 0)
		aprint_error_dev(self, "unable to register with sysmon, "
			"error %d\n", error);

	sc->sc_ih = ra_intr_establish(RA_IRQ_TIMER0, ra_wdog_timer0, sc, 0);
	if (sc->sc_ih == NULL)
		aprint_error_dev(self, "unable to establish interrupt\n");
			/* expect watchdog reset shortly */

	if (RA_WDOG_DEFAULT_MODE == WDOG_MODE_DISARMED) {
		/*
		 * disarm the watchdog
		 */
		bus_space_write_4(sc->sc_memt, memh, RA_TIMER_0_CNTRL, 0);
		bus_space_write_4(sc->sc_memt, memh, RA_TIMER_1_CNTRL, 0);
		aprint_normal_dev(self, "%s mode\n",
			wdog_modestr[sc->sc_smw.smw_mode]);
	} else {
		/*
		 * initialize and arm the watchdog now.
		 * if boot loader already initialized the watchdog
		 * then we are re-initializing; this will buy some time
		 * until interrupts are enabled, and will establish our
		 * (default) mode and smw_period indedpendent of the
		 * boot loader.
		 */
		error = sysmon_wdog_setmode(&sc->sc_smw, RA_WDOG_DEFAULT_MODE,
			RA_WDOG_DEFAULT_PERIOD);
		if (error != 0) {
			aprint_error_dev(self, "unable to set sysmon wdog, "
				"mode %d, error %d\n",
				RA_WDOG_DEFAULT_MODE, error);
		} else {
			aprint_normal_dev(self, "%s mode, period %d sec.\n",
				wdog_modestr[sc->sc_smw.smw_mode],
				sc->sc_smw.smw_period);
		}
	}
}

/*
 * ra_wdog_tickle - smw watchdog service function
 */
static int
ra_wdog_tickle(struct sysmon_wdog *smw)
{
	const ra_wdog_softc_t * const sc = smw->smw_cookie;
	ra_wdog_reset(sc);
	return 0;
}

/*
 * ra_wdog_timer0 - periodic watchdog service ISR
 */
static int
ra_wdog_timer0(void *arg)
{
	const ra_wdog_softc_t * const sc = arg;
	ra_wdog_reset(sc);
	return 0;
}

static int
ra_wdog_setmode(struct sysmon_wdog *smw)
{
	const ra_wdog_softc_t * const sc = smw->smw_cookie;
	u_int period = smw->smw_period;
	bool itickle = false;
	uint32_t r;

	if (((smw->smw_mode & WDOG_MODE_MASK) == WDOG_MODE_KTICKLE) &&
	    ((int)period < 0)) {
		itickle = true;		/* use Timer 0 */
		period = -period;
	}

	/* all configuration has to be done with the timer disabled */
	bus_space_write_4(sc->sc_memt, sc->sc_memh, RA_TIMER_0_CNTRL, 0);
	bus_space_write_4(sc->sc_memt, sc->sc_memh, RA_TIMER_1_CNTRL, 0);

	if ((smw->smw_mode & WDOG_MODE_MASK) == WDOG_MODE_DISARMED)
		return 0;

	if (period > WDOG_MAX_PERIOD)
		return EOPNOTSUPP;

	/* Set the new watchdog reset period in Timer 1 */
	r = ra_wdog_sec_to_count(period);
	bus_space_write_4(sc->sc_memt, sc->sc_memh, RA_TIMER_1_LOAD, r);
	bus_space_write_4(sc->sc_memt, sc->sc_memh, RA_TIMER_1_CNTRL,
		TIMER_EN | TIMER_MODE(TIMER_MODE_WDOG) |
			TIMER_PRESCALE(TIMER_PRESCALE_DIV_65536));

	if (itickle) {
		/* Set the new watchdog service period in Timer 0 */
		r = ra_wdog_sec_to_count(period) / 2;
		bus_space_write_4(sc->sc_memt, sc->sc_memh, RA_TIMER_0_LOAD, r);
		bus_space_write_4(sc->sc_memt, sc->sc_memh, RA_TIMER_0_CNTRL,
			TIMER_EN | TIMER_MODE(TIMER_MODE_PERIODIC) |
				TIMER_PRESCALE(TIMER_PRESCALE_DIV_65536));
	}

	return 0;
}