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
--- 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 | |
7 | include "arch/evbppc/conf/std.mpc85xx" | | 7 | include "arch/evbppc/conf/std.mpc85xx" |
8 | | | 8 | |
9 | options INCLUDE_CONFIG_FILE # embed config file in kernel binary | | 9 | options INCLUDE_CONFIG_FILE # embed config file in kernel binary |
10 | | | 10 | |
11 | ident "P2020DS-$Revision: 1.6 $" | | 11 | ident "P2020DS-$Revision: 1.7 $" |
12 | | | 12 | |
13 | maxusers 32 | | 13 | maxusers 32 |
14 | | | 14 | |
15 | #options UVMHIST | | 15 | #options UVMHIST |
16 | #options UVMHIST_PRINT | | 16 | #options UVMHIST_PRINT |
17 | | | 17 | |
18 | options P2020 | | 18 | options P2020 |
19 | options PIXIS | | 19 | options PIXIS |
20 | #options SYS_CLK=100000000 | | 20 | #options SYS_CLK=100000000 |
21 | #options HZ=1000 | | 21 | #options HZ=1000 |
| | | 22 | options MEMSIZE=0x40000000 |
22 | | | 23 | |
23 | makeoptions NEED_BINARY="yes" | | 24 | makeoptions NEED_BINARY="yes" |
24 | makeoptions NEED_UBOOTIMAGE="yes" | | 25 | makeoptions 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 |
28 | options KTRACE # system call tracing via ktrace(1) | | 29 | options KTRACE # system call tracing via ktrace(1) |
29 | | | 30 | |
30 | options SYSVMSG # System V message queues | | 31 | options SYSVMSG # System V message queues |
31 | options SYSVSEM # System V semaphores | | 32 | options SYSVSEM # System V semaphores |
32 | options SYSVSHM # System V shared memory | | 33 | options SYSVSHM # System V shared memory |
33 | | | 34 | |
34 | options USERCONF # userconf(4) support | | 35 | options USERCONF # userconf(4) support |
--- 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 | |
6 | include "arch/evbppc/conf/std.mpc85xx" | | 6 | include "arch/evbppc/conf/std.mpc85xx" |
7 | | | 7 | |
8 | options INCLUDE_CONFIG_FILE # embed config file in kernel binary | | 8 | options INCLUDE_CONFIG_FILE # embed config file in kernel binary |
9 | | | 9 | |
10 | ident "P2020RBD-$Revision: 1.8 $" | | 10 | ident "P2020RBD-$Revision: 1.9 $" |
11 | | | 11 | |
12 | maxusers 32 | | 12 | maxusers 32 |
13 | | | 13 | |
14 | makeoptions NEED_BINARY="yes" | | 14 | makeoptions NEED_BINARY="yes" |
15 | makeoptions NEED_UBOOTIMAGE="yes" | | 15 | makeoptions NEED_UBOOTIMAGE="yes" |
16 | | | 16 | |
17 | #options UVMHIST | | 17 | #options UVMHIST |
18 | #options UVMHIST_PRINT | | 18 | #options UVMHIST_PRINT |
19 | | | 19 | |
20 | options P2020 | | 20 | options P2020 |
21 | options SYS_CLK=100000000 | | 21 | options 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 | |
173 | diic* at cpunode? # i2c bus | | 173 | diic* at cpunode? # i2c bus |
174 | iic* at diic? | | 174 | iic* at diic? |
175 | dsrtc* at iic1 addr 0x68 # RTC | | 175 | dsrtc* at iic1 addr 0x68 # RTC |
176 | | | 176 | |
177 | pq3pcie* at cpunode? # PCI-Express controller | | 177 | pq3pcie* at cpunode? # PCI-Express controller |
178 | pq3pci* at cpunode? # PCI(X) | | 178 | pq3pci* at cpunode? # PCI(X) |
179 | pci* at pq3pcie? | | 179 | pci* at pq3pcie? |
180 | pci* at pq3pci? | | 180 | pci* at pq3pci? |
181 | | | 181 | |
182 | ppb* at pci? dev ? function ? # PCI-PCI bridges | | 182 | ppb* at pci? dev ? function ? # PCI-PCI bridges |
183 | pci* at ppb? | | 183 | pci* at ppb? |
184 | | | 184 | |
| | | 185 | ahcisata* at pci? dev ? function ? |
| | | 186 | atabus* at ahcisata? channel ? |
| | | 187 | wd* at atabus? drive ? |
| | | 188 | |
185 | ehci* at cpunode? # usb | | 189 | ehci* at cpunode? # usb |
186 | usb* at ehci? | | 190 | usb* at ehci? |
187 | uhub* at usb? | | 191 | uhub* at usb? |
188 | umass* at uhub? port ? | | 192 | umass* at uhub? port ? |
189 | scsibus* at umass? channel ? | | 193 | scsibus* at umass? channel ? |
190 | sd* at scsibus? target ? lun ? | | 194 | sd* 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 ? |
# $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
/* $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>
/* $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(®s);
if ((error = bus_space_map(regs.cr_iot, regs.cr_iobase, regs.cr_nports,
0, ®s.cr_ioh)) != 0) {
return;
}
/* Ralink UART has a 16-bit rate latch (like the AU1x00) */
comcnattach1(®s, RA_BAUDRATE, RA_UART_FREQ,
COM_TYPE_AU1x00, CONMODE);
}
/* $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_ */
/* $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);
}
/* $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
}
}
/* $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
}
/* $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_ */
/* $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);
}
/* $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);
}
}
/* $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);
}
}
/* $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;
}
/* $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_ */
/* $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_ */
/* $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_ */
/* $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;
}