Index: conf/ROUTERSTATION =================================================================== --- conf/ROUTERSTATION (revision 248780) +++ conf/ROUTERSTATION (working copy) @@ -15,6 +15,12 @@ device geom_uzip # compressed in-memory filesystem support options GEOM_UZIP +# For etherswitch support +options ARGE_MDIO +device miiproxy +device etherswitch +device adm6996 + # For DOS options MSDOSFS Index: conf/DIR-825.hints =================================================================== --- conf/DIR-825.hints (revision 248780) +++ conf/DIR-825.hints (working copy) @@ -66,5 +66,5 @@ hint.map.4.start=0x00660000 hint.map.4.end=0x00670000 hint.map.4.name="art" -hint.map.4.readonly=1 +hint.map.4.readonly=0 Index: conf/AP121 =================================================================== --- conf/AP121 (revision 0) +++ conf/AP121 (working copy) @@ -0,0 +1,46 @@ +# +# TP-1043ND -- Kernel configuration file for the TP-Link WR-1043ND +# +# $FreeBSD: head/sys/mips/conf/TP-WN1043ND 239625 2012-08-23 22:23:56Z ray $ +# + +# Include the default AR913x parameters common to all AR913x SoC users. +include "AR933X_BASE" + +ident AP121 + +# Override hints with board values +hints "AP121.hints" + +# Force the board memory - 16mb +# XXX check +options AR71XX_REALMEM=16*1024*1024 + +# i2c GPIO bus +#device gpioiic +#device iicbb +#device iicbus +#device iic + +# ethernet switch device +#device etherswitch + +# RTL8366RB support +#device rtl8366rb + +# read MSDOS formatted disks - USB +#options MSDOSFS + +# Enable the uboot environment stuff rather then the +# redboot stuff. +options AR71XX_ENV_UBOOT + +# uzip - to boot natively from flash +#device geom_uzip +#options GEOM_UZIP + +# Used for the static uboot partition map +device geom_map + +# Boot off of the rootfs, as defined in the geom_map setup. +options ROOTDEVNAME=\"ufs:map/rootfs.uzip\" Index: conf/AR933X_BASE =================================================================== --- conf/AR933X_BASE (revision 0) +++ conf/AR933X_BASE (working copy) @@ -0,0 +1,119 @@ +# +# AR91XX -- Kernel configuration base file for the Atheros AR913x SoC. +# +# This file (and the hints file accompanying it) are not designed to be +# used by themselves. Instead, users of this file should create a kernel +# config file which includes this file (which gets the basic hints), then +# override the default options (adding devices as needed) and adding +# hints as needed (for example, the GPIO and LAN PHY.) +# +# $FreeBSD: head/sys/mips/conf/AR91XX_BASE 235346 2012-05-12 17:42:22Z adrian $ +# + +machine mips mips +ident AR933X_BASE +cpu CPU_MIPS4KC +makeoptions KERNLOADADDR=0x80050000 +options HZ=1000 + +files "../atheros/files.ar71xx" +hints "AR933X_BASE.hints" + +makeoptions DEBUG=-g #Build kernel with gdb(1) debug symbols +# makeoptions MODULES_OVERRIDE="random gpio ar71xx if_gif if_gre if_bridge bridgestp usb wlan wlan_xauth wlan_acl wlan_wep wlan_tkip wlan_ccmp wlan_rssadapt wlan_amrr ath ath_ahb hwpmc" +makeoptions MODULES_OVERRIDE="" + +options DDB +options KDB +options ALQ + +options SCHED_4BSD #4BSD scheduler +options INET #InterNETworking +options INET6 #InterNETworking +#options NFSCL #Network Filesystem Client +options PSEUDOFS #Pseudo-filesystem framework +options _KPOSIX_PRIORITY_SCHEDULING #Posix P1003_1B real-time extensions + +# PMC +#options HWPMC_HOOKS +#device hwpmc +#device hwpmc_mips24k + +# options NFS_LEGACYRPC +# Debugging for use in -current +options INVARIANTS +options INVARIANT_SUPPORT +options WITNESS +options WITNESS_SKIPSPIN +options FFS #Berkeley Fast Filesystem +#options SOFTUPDATES #Enable FFS soft updates support +#options UFS_ACL #Support for access control lists +#options UFS_DIRHASH #Improve performance on big directories +options NO_FFS_SNAPSHOT # We don't require snapshot support + +# Wireless NIC cards +options IEEE80211_DEBUG +options IEEE80211_SUPPORT_MESH +options IEEE80211_SUPPORT_TDMA +options IEEE80211_ALQ # 802.11 ALQ logging support +#device wlan # 802.11 support +#device wlan_wep # 802.11 WEP support +#device wlan_ccmp # 802.11 CCMP support +#device wlan_tkip # 802.11 TKIP support +#device wlan_xauth # 802.11 hostap support + +# ath(4) +#device ath # Atheros network device +#device ath_rate_sample +#device ath_ahb # Atheros host bus glue +options ATH_DEBUG +options ATH_DIAGAPI +option ATH_ENABLE_11N +option AH_DEBUG_ALQ + +# Don't bother compiling the whole HAL - AH_SUPPORT_AR9130 breaks the +# rest of the 11n chipset support at the moment and the pre-AR5212 +# HALs aren't required. +# device ath_hal + +# The AR9130 code requires AR5416; and AR5416 requires the AR5212 code. +#device ath_ar5212 +#device ath_ar5416 +#device ath_ar9130 + +options AH_DEBUG +option AH_SUPPORT_AR5416 +option AH_SUPPORT_AR9130 # Makes other chipsets not function! +option AH_DEBUG_ALQ +# interrupt mitigation not possible on AR9130 +# option AH_AR5416_INTERRUPT_MITIGATION + +device mii +device arge + +device usb +options USB_EHCI_BIG_ENDIAN_DESC # handle big-endian byte order +options USB_DEBUG +options USB_HOST_ALIGN=32 # AR71XX (MIPS in general?) requires this +device ehci + +device scbus +device umass +device da + +device spibus +device ar71xx_spi +device mx25l +device ar71xx_wdog + +device uart +device uart_ar933x + +device loop +device ether +device md +device bpf +device random +device if_bridge +device gpio +device gpioled Index: conf/AP121.hints =================================================================== --- conf/AP121.hints (revision 0) +++ conf/AP121.hints (working copy) @@ -0,0 +1,129 @@ +# +# This file adds to the values in AR91XX_BASE.hints. +# +# $FreeBSD: head/sys/mips/conf/TP-WN1043ND.hints 235345 2012-05-12 17:41:42Z adrian $ + +# Hard-code the PHY for now, until there's switch phy support. +# hint.arge.0.phymask=0x000c +hint.arge.0.phymask=0x0000 +hint.arge.0.media=1000 +hint.arge.0.fduplex=1 +# Where is the MAC address stored in flash for this particular unit. +hint.arge.0.eeprommac=0x1f01fc00 + +# This isn't used, but configure it anyway. +# This should eventually just not be configured, but the if then +# needs to be properly disabled or spurious interrupts occur. +hint.arge.1.phymask=0x0 + +# Where the ART is +hint.ath.0.eepromaddr=0x1fff1000 + +# The AP121 4MB flash layout: +# +# bootargs=console=ttyS0,115200 root=31:02 rootfstype=squashfs +# init=/sbin/init mtdparts=ar7240-nor0:256k(u-boot),64k(u-boot-env), +# 2752k(rootfs),896k(uImage),64k(NVRAM),64k(ART) +# +# So: +# 256k: uboot +# 64: uboot-env +# 2752k: rootfs +# 896k: kernel +# 64k: config +# 64k: ART + +hint.map.0.at="flash/spi0" +hint.map.0.start=0x00000000 +hint.map.0.end=0x000040000 +hint.map.0.name="uboot" +hint.map.0.readonly=1 + +hint.map.1.at="flash/spi0" +hint.map.1.start=0x00040000 +hint.map.1.end=0x00050000 +hint.map.1.name="uboot-env" +hint.map.1.readonly=0 + +hint.map.2.at="flash/spi0" +hint.map.2.start=0x00050000 +hint.map.2.end=0x00300000 +hint.map.2.name="rootfs" +hint.map.2.readonly=0 + +hint.map.3.at="flash/spi0" +hint.map.3.start=0x00300000 +hint.map.3.end=0x003e0000 +hint.map.3.name="kernel" +hint.map.3.readonly=0 + +hint.map.4.at="flash/spi0" +hint.map.4.start=0x003e0000 +hint.map.4.end=0x003f0000 +hint.map.4.name="cfg" +hint.map.4.readonly=0 + +# This is radio calibration section. It is (or should be!) unique +# for each board, to take into account thermal and electrical differences +# as well as the regulatory compliance data. +# +hint.map.5.at="flash/spi0" +hint.map.5.start=0x003f0000 +hint.map.5.end=0x00400000 +hint.map.5.name="art" +hint.map.5.readonly=1 + +# GPIO specific configuration block + +# Don't flip on anything that isn't already enabled. +# This includes leaving the SPI CS1/CS2 pins as GPIO pins as they're +# not used here. +hint.gpio.0.function_set=0x00002000 +hint.gpio.0.function_clear=0x00000000 + +# These are the GPIO LEDs and buttons which can be software controlled. +hint.gpio.0.pinmask=0x001c02ae + +# pin 1 - USB (LED) +# pin 2 - System (LED) +# Pin 3 - Reset (input) +# Pin 5 - QSS (LED) +# Pin 7 - QSS Button (input) +# Pin 8 - wired into the chip reset line +# Pin 9 - WLAN +# Pin 10 - UART TX (not GPIO) +# Pin 13 - UART RX (not GPIO) +# Pin 18 - RTL8366RB switch data line +# Pin 19 - RTL8366RB switch clock line +# Pin 20 - "GPIO20" + +# LEDs are configured separately and driven by the LED device +#hint.gpioled.0.at="gpiobus0" +#hint.gpioled.0.name="usb" +#hint.gpioled.0.pins=0x0002 + +hint.gpioled.1.at="gpiobus0" +hint.gpioled.1.name="system" +hint.gpioled.1.pins=0x0004 + +hint.gpioled.2.at="gpiobus0" +hint.gpioled.2.name="qss" +hint.gpioled.2.pins=0x0020 + +hint.gpioled.3.at="gpiobus0" +hint.gpioled.3.name="wlan" +hint.gpioled.3.pins=0x0200 + +# GPIO I2C bus +hint.gpioiic.0.at="gpiobus0" +hint.gpioiic.0.pins=0xc0000 +hint.gpioiic.0.scl=1 +hint.gpioiic.0.sda=0 + +# I2C bus +# Don't be strict about I2C protocol - the relaxed semantics are required +# by the realtek switch PHY. +hint.iicbus.0.strict=0 + +# Bit bang bus - override default delay +#hint.iicbb.0.udelay=3 Index: conf/AR71XX_BASE =================================================================== --- conf/AR71XX_BASE (revision 248780) +++ conf/AR71XX_BASE (working copy) @@ -28,6 +28,7 @@ options DDB options KDB +options GDB options SCHED_4BSD #4BSD scheduler options INET #InterNETworking @@ -40,12 +41,12 @@ # options NFS_LEGACYRPC # Debugging for use in -current -options INVARIANTS -options INVARIANT_SUPPORT -options WITNESS -options WITNESS_SKIPSPIN -options DEBUG_REDZONE -options DEBUG_MEMGUARD +#options INVARIANTS +#options INVARIANT_SUPPORT +#options WITNESS +#options WITNESS_SKIPSPIN +#options DEBUG_REDZONE +#options DEBUG_MEMGUARD options FFS #Berkeley Fast Filesystem # options SOFTUPDATES #Enable FFS soft updates support Index: conf/AP91 =================================================================== --- conf/AP91 (revision 248780) +++ conf/AP91 (working copy) @@ -48,6 +48,14 @@ nooptions DEBUG_REDZONE nooptions DEBUG_MEMGUARD +# Compile AR9285 support +# AR5416 requires AR5212 support for now +options AH_SUPPORT_AR5212 +# AR9285 requires AR5416 (and AR9280 support?) +options AH_SUPPORT_AR5416 +options AH_SUPPORT_AR9280 +options AH_SUPPORT_AR9285 + # Used for the static uboot partition map device geom_map Index: conf/AP96 =================================================================== --- conf/AP96 (revision 248780) +++ conf/AP96 (working copy) @@ -43,3 +43,10 @@ device etherswitch device arswitch + +#options ALQ +#options KTR +#options KTR_ENTRIES=131072 + +#options AH_INTERRUPT_DEBUGGING +#options ATH_KTR_INTR_DEBUG Index: conf/ROUTERSTATION.hints =================================================================== --- conf/ROUTERSTATION.hints (revision 248780) +++ conf/ROUTERSTATION.hints (working copy) @@ -2,16 +2,33 @@ # $FreeBSD$ # -# Uncomment this hint for RS (not PRO) -# PHY20 = 1 << 20 -hint.arge.0.phymask=0x100000 +# arge0 mdio bus +hint.argemdio.0.at="nexus0" +hint.argemdio.0.maddr=0x19000000 +hint.argemdio.0.msize=0x1000 +hint.argemdio.0.order=0 -# should be 100 for RS -hint.arge.1.media=100 -hint.arge.1.fduplex=1 -# Uncomment this hint for RS (not PRO) -hint.arge.1.phymask=0x30000 +# arge0/arge1 don't quite work just yet - first, need to get the +# adm6996 configured and working "right". +# arge0 worked ok though, with +# hint.arge.0.phymask=0x100000 +# bit 20.. phy #21? how many PHYs does this adm6996 expose, +# and where? + +# arge0: dedicated switch port +hint.arge.0.phymask=0x0 # PHY4 +# hint.arge.0.miimode=3 # RGMII +# hint.arge.0.mdio=mdioproxy0 # .. off of the switch mdiobus + +# arge1: nail to 1000/full, RGMII - connected to the switch +hint.arge.1.media=1000 # Map to 1000/full +hint.arge.1.fduplex=1 # +hint.arge.1.phymask=0x0 # no directly mapped PHYs +hint.arge.1.miimode=3 # RGMII + +hint.admswitch.0.at="mdio0" + # RF led hint.gpioled.0.at="gpiobus0" hint.gpioled.0.name="rf" Index: conf/AR933X_BASE.hints =================================================================== --- conf/AR933X_BASE.hints (revision 0) +++ conf/AR933X_BASE.hints (working copy) @@ -0,0 +1,59 @@ +# This file (and the kernel config file accompanying it) are not designed +# to be used by themselves. Instead, users of this file should create a +# kernel # config file which includes this file (which gets the basic hints), +# then override the default options (adding devices as needed) and adding +# hints as needed (for example, the GPIO and LAN PHY.) + +# $FreeBSD: head/sys/mips/conf/AR91XX_BASE.hints 228519 2011-12-15 01:05:38Z adrian $ + +hint.apb.0.at="nexus0" +hint.apb.0.irq=4 + +# uart0 +hint.uart.0.at="apb0" +# This isn't an ns8250 UART, unfortunately +hint.uart.0.maddr=0x18020000 +hint.uart.0.msize=0x18 +hint.uart.0.irq=3 + +#ehci - note the 0x100 offset for the AR913x/AR724x +hint.ehci.0.at="nexus0" +hint.ehci.0.maddr=0x1b000100 +hint.ehci.0.msize=0x00ffff00 +hint.ehci.0.irq=1 + +hint.arge.0.at="nexus0" +hint.arge.0.maddr=0x19000000 +hint.arge.0.msize=0x1000 +hint.arge.0.irq=2 + +hint.arge.1.at="nexus0" +hint.arge.1.maddr=0x1a000000 +hint.arge.1.msize=0x1000 +hint.arge.1.irq=3 + +# XXX The ath device hangs off of the AHB, rather than the Nexus. +hint.ath.0.at="nexus0" +hint.ath.0.maddr=0x180c0000 +hint.ath.0.msize=0x30000 +hint.ath.0.irq=0 +# Set this to define where the ath calibration data +# should be fetched from in physical memory. +# hint.ath.0.eepromaddr=0x1fff1000 + +# SPI flash +hint.spi.0.at="nexus0" +hint.spi.0.maddr=0x1f000000 +hint.spi.0.msize=0x10 + +hint.mx25l.0.at="spibus0" +hint.mx25l.0.cs=0 + +# Watchdog +hint.ar71xx_wdog.0.at="nexus0" + +# The GPIO function and pin mask is configured per-board +hint.gpio.0.at="apb0" +hint.gpio.0.maddr=0x18040000 +hint.gpio.0.msize=0x1000 +hint.gpio.0.irq=2 Index: conf/RSPRO =================================================================== --- conf/RSPRO (revision 248780) +++ conf/RSPRO (working copy) @@ -28,3 +28,9 @@ # Boot off of flash options ROOTDEVNAME=\"ufs:redboot/rootfs.uzip\" +options ALQ +options KTR +options KTR_ENTRIES=8192 +options AH_INTERRUPT_DEBUGGING +options ATH_KTR_INTR_DEBUG + Index: mips/machdep.c =================================================================== --- mips/machdep.c (revision 248780) +++ mips/machdep.c (working copy) @@ -544,7 +544,7 @@ critical_enter(); cpu_idleclock(); } - mips_wait(); +// mips_wait(); if (!busy) { cpu_activeclock(); critical_exit(); Index: atheros/files.ar71xx =================================================================== --- atheros/files.ar71xx (revision 248780) +++ atheros/files.ar71xx (working copy) @@ -14,6 +14,9 @@ mips/atheros/if_arge.c optional arge mips/atheros/uart_bus_ar71xx.c optional uart_ar71xx mips/atheros/uart_cpu_ar71xx.c optional uart_ar71xx +mips/atheros/uart_bus_ar933x.c optional uart_ar933x +mips/atheros/uart_cpu_ar933x.c optional uart_ar933x +mips/atheros/uart_dev_ar933x.c optional uart_ar933x mips/atheros/ar71xx_bus_space_reversed.c standard mips/mips/intr_machdep.c standard mips/mips/tick.c standard @@ -21,6 +24,7 @@ mips/atheros/ar71xx_chip.c standard mips/atheros/ar724x_chip.c standard mips/atheros/ar91xx_chip.c standard +mips/atheros/ar933x_chip.c standard mips/atheros/ar71xx_fixup.c optional ar71xx_ath_eeprom dev/hwpmc/hwpmc_mips24k.c optional hwpmc_mips24k Index: atheros/if_argevar.h =================================================================== --- atheros/if_argevar.h (revision 248780) +++ atheros/if_argevar.h (working copy) @@ -31,8 +31,8 @@ #define __IF_ARGEVAR_H__ #define ARGE_NPHY 32 -#define ARGE_TX_RING_COUNT 128 -#define ARGE_RX_RING_COUNT 128 +#define ARGE_TX_RING_COUNT 1024 +#define ARGE_RX_RING_COUNT 1024 #define ARGE_RX_DMA_SIZE ARGE_RX_RING_COUNT * sizeof(struct arge_desc) #define ARGE_TX_DMA_SIZE ARGE_TX_RING_COUNT * sizeof(struct arge_desc) #define ARGE_MAXFRAGS 8 Index: atheros/uart_cpu_ar933x.c =================================================================== --- atheros/uart_cpu_ar933x.c (revision 0) +++ atheros/uart_cpu_ar933x.c (working copy) @@ -0,0 +1,78 @@ +/*- + * Copyright (c) 2012 Adrian Chadd + * 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 THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ +#include "opt_uart.h" + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include + +#include + +#include +#include + +#include +#include +#include + +#include + +bus_space_tag_t uart_bus_space_io; +bus_space_tag_t uart_bus_space_mem; + +int +uart_cpu_eqres(struct uart_bas *b1, struct uart_bas *b2) +{ + return ((b1->bsh == b2->bsh && b1->bst == b2->bst) ? 1 : 0); +} + +int +uart_cpu_getdev(int devtype, struct uart_devinfo *di) +{ + uint64_t freq; + + freq = ar71xx_ahb_freq(); + + di->ops = uart_getops(&uart_ar933x_class); + di->bas.chan = 0; + di->bas.bst = ar71xx_bus_space_reversed; + di->bas.regshft = 0; /* We'll do "correct" dword addressing here */ + di->bas.rclk = freq; + di->baudrate = 115200; + di->databits = 8; + di->stopbits = 1; + + di->parity = UART_PARITY_NONE; + + uart_bus_space_io = NULL; + uart_bus_space_mem = ar71xx_bus_space_reversed; + di->bas.bsh = MIPS_PHYS_TO_KSEG1(AR71XX_UART_ADDR); + return (0); +} Index: atheros/uart_bus_ar933x.c =================================================================== --- atheros/uart_bus_ar933x.c (revision 0) +++ atheros/uart_bus_ar933x.c (working copy) @@ -0,0 +1,91 @@ +/*- + * Copyright (c) 2012, Adrian Chadd + * 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 THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + */ +#include "opt_uart.h" + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include +#include + +#include + +#include "uart_if.h" + +static int uart_ar933x_probe(device_t dev); +extern struct uart_class uart_ar933x_uart_class; + +static device_method_t uart_ar933x_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, uart_ar933x_probe), + DEVMETHOD(device_attach, uart_bus_attach), + DEVMETHOD(device_detach, uart_bus_detach), + { 0, 0 } +}; + +static driver_t uart_ar933x_driver = { + uart_driver_name, + uart_ar933x_methods, + sizeof(struct uart_softc), +}; + +extern SLIST_HEAD(uart_devinfo_list, uart_devinfo) uart_sysdevs; + +static int +uart_ar933x_probe(device_t dev) +{ + struct uart_softc *sc; + uint64_t freq; + + freq = ar71xx_ahb_freq(); + + sc = device_get_softc(dev); + sc->sc_sysdev = SLIST_FIRST(&uart_sysdevs); + sc->sc_class = &uart_ar933x_class; + bcopy(&sc->sc_sysdev->bas, &sc->sc_bas, sizeof(sc->sc_bas)); + sc->sc_sysdev->bas.regshft = 0; + sc->sc_sysdev->bas.bst = mips_bus_space_generic; + sc->sc_sysdev->bas.bsh = MIPS_PHYS_TO_KSEG1(AR71XX_UART_ADDR); + sc->sc_bas.regshft = 0; + sc->sc_bas.bst = mips_bus_space_generic; + sc->sc_bas.bsh = MIPS_PHYS_TO_KSEG1(AR71XX_UART_ADDR); + + return (uart_bus_probe(dev, 2, freq, 0, 0)); +} + +DRIVER_MODULE(uart, apb, uart_ar933x_driver, uart_devclass, 0, 0); Index: atheros/ar71xx_setup.c =================================================================== --- atheros/ar71xx_setup.c (revision 248780) +++ atheros/ar71xx_setup.c (working copy) @@ -52,6 +52,8 @@ #include #include +#include + #include #include @@ -59,9 +61,8 @@ #include #include #include +#include -#include - #define AR71XX_SYS_TYPE_LEN 128 static char ar71xx_sys_type[AR71XX_SYS_TYPE_LEN]; @@ -142,8 +143,19 @@ break; } break; + case REV_ID_MAJOR_AR9330: + minor = 0; + rev = (id & AR933X_REV_ID_REVISION_MASK); + chip = "9330"; + ar71xx_cpu_ops = &ar933x_chip_def; + break; + case REV_ID_MAJOR_AR9331: + minor = 1; + rev = (id & AR933X_REV_ID_REVISION_MASK); + chip = "9331"; + ar71xx_cpu_ops = &ar933x_chip_def; + break; - default: panic("ar71xx: unknown chip id:0x%08x\n", id); } Index: atheros/uart_dev_ar933x.c =================================================================== --- atheros/uart_dev_ar933x.c (revision 0) +++ atheros/uart_dev_ar933x.c (working copy) @@ -0,0 +1,925 @@ +/*- + * Copyright (c) 2013 Adrian Chadd + * 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 THE AUTHOR ``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 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 +__FBSDID("$FreeBSD"); + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include "uart_if.h" + +#define DEFAULT_RCLK 1843200 + +#define ar933x_getreg(bas, reg) \ + bus_space_read_4((bas)->bst, (bas)->bsh, uart_regofs(bas, reg)) +#define ar933x_setreg(bas, reg, value) \ + bus_space_write_4((bas)->bst, (bas)->bsh, uart_regofs(bas, reg), value) + + +#if 0 +/* + * Clear pending interrupts. THRE is cleared by reading IIR. Data + * that may have been received gets lost here. + */ +static void +ar933x_clrint(struct uart_bas *bas) +{ + uint8_t iir, lsr; + + iir = uart_getreg(bas, REG_IIR); + while ((iir & IIR_NOPEND) == 0) { + iir &= IIR_IMASK; + if (iir == IIR_RLS) { + lsr = uart_getreg(bas, REG_LSR); + if (lsr & (LSR_BI|LSR_FE|LSR_PE)) + (void)uart_getreg(bas, REG_DATA); + } else if (iir == IIR_RXRDY || iir == IIR_RXTOUT) + (void)uart_getreg(bas, REG_DATA); + else if (iir == IIR_MLSC) + (void)uart_getreg(bas, REG_MSR); + uart_barrier(bas); + iir = uart_getreg(bas, REG_IIR); + } +} +#endif + +#if 0 +static int +ar933x_delay(struct uart_bas *bas) +{ + int divisor; + u_char lcr; + + lcr = uart_getreg(bas, REG_LCR); + uart_setreg(bas, REG_LCR, lcr | LCR_DLAB); + uart_barrier(bas); + divisor = uart_getreg(bas, REG_DLL) | (uart_getreg(bas, REG_DLH) << 8); + uart_barrier(bas); + uart_setreg(bas, REG_LCR, lcr); + uart_barrier(bas); + + /* 1/10th the time to transmit 1 character (estimate). */ + if (divisor <= 134) + return (16000000 * divisor / bas->rclk); + return (16000 * divisor / (bas->rclk / 1000)); + return (0); +} +#endif + +#if 0 +static int +ar933x_divisor(int rclk, int baudrate) +{ + int actual_baud, divisor; + int error; + + if (baudrate == 0) + return (0); + + divisor = (rclk / (baudrate << 3) + 1) >> 1; + if (divisor == 0 || divisor >= 65536) + return (0); + actual_baud = rclk / (divisor << 4); + + /* 10 times error in percent: */ + error = ((actual_baud - baudrate) * 2000 / baudrate + 1) >> 1; + + /* 3.0% maximum error tolerance: */ + if (error < -30 || error > 30) + return (0); + + return (divisor); +} +#endif + +#if 0 +static int +ar933x_drain(struct uart_bas *bas, int what) +{ + int delay, limit; + + delay = ar933x_delay(bas); + + if (what & UART_DRAIN_TRANSMITTER) { + /* + * Pick an arbitrary high limit to avoid getting stuck in + * an infinite loop when the hardware is broken. Make the + * limit high enough to handle large FIFOs. + */ + limit = 10*1024; + while ((uart_getreg(bas, REG_LSR) & LSR_TEMT) == 0 && --limit) + DELAY(delay); + if (limit == 0) { + /* printf("ns8250: transmitter appears stuck... "); */ + return (EIO); + } + } + + if (what & UART_DRAIN_RECEIVER) { + /* + * Pick an arbitrary high limit to avoid getting stuck in + * an infinite loop when the hardware is broken. Make the + * limit high enough to handle large FIFOs and integrated + * UARTs. The HP rx2600 for example has 3 UARTs on the + * management board that tend to get a lot of data send + * to it when the UART is first activated. + */ + limit=10*4096; + while ((uart_getreg(bas, REG_LSR) & LSR_RXRDY) && --limit) { + (void)uart_getreg(bas, REG_DATA); + uart_barrier(bas); + DELAY(delay << 2); + } + if (limit == 0) { + /* printf("ns8250: receiver appears broken... "); */ + return (EIO); + } + } + return (0); +} +#endif + +#if 0 +/* + * We can only flush UARTs with FIFOs. UARTs without FIFOs should be + * drained. WARNING: this function clobbers the FIFO setting! + */ +static void +ar933x_flush(struct uart_bas *bas, int what) +{ + uint8_t fcr; + + fcr = FCR_ENABLE; + if (what & UART_FLUSH_TRANSMITTER) + fcr |= FCR_XMT_RST; + if (what & UART_FLUSH_RECEIVER) + fcr |= FCR_RCV_RST; + uart_setreg(bas, REG_FCR, fcr); + uart_barrier(bas); +} +#endif + +#if 0 +static int +ar933x_param(struct uart_bas *bas, int baudrate, int databits, int stopbits, + int parity) +{ + int divisor; + uint8_t lcr; + + lcr = 0; + if (databits >= 8) + lcr |= LCR_8BITS; + else if (databits == 7) + lcr |= LCR_7BITS; + else if (databits == 6) + lcr |= LCR_6BITS; + else + lcr |= LCR_5BITS; + if (stopbits > 1) + lcr |= LCR_STOPB; + lcr |= parity << 3; + + /* Set baudrate. */ + if (baudrate > 0) { + divisor = ar933x_divisor(bas->rclk, baudrate); + if (divisor == 0) + return (EINVAL); + uart_setreg(bas, REG_LCR, lcr | LCR_DLAB); + uart_barrier(bas); + uart_setreg(bas, REG_DLL, divisor & 0xff); + uart_setreg(bas, REG_DLH, (divisor >> 8) & 0xff); + uart_barrier(bas); + } + + /* Set LCR and clear DLAB. */ + uart_setreg(bas, REG_LCR, lcr); + uart_barrier(bas); + return (0); +} +#endif + +/* + * Low-level UART interface. + */ +static int ar933x_probe(struct uart_bas *bas); +static void ar933x_init(struct uart_bas *bas, int, int, int, int); +static void ar933x_term(struct uart_bas *bas); +static void ar933x_putc(struct uart_bas *bas, int); +static int ar933x_rxready(struct uart_bas *bas); +static int ar933x_getc(struct uart_bas *bas, struct mtx *); + +static struct uart_ops uart_ar933x_ops = { + .probe = ar933x_probe, + .init = ar933x_init, + .term = ar933x_term, + .putc = ar933x_putc, + .rxready = ar933x_rxready, + .getc = ar933x_getc, +}; + +static int +ar933x_probe(struct uart_bas *bas) +{ +#if 0 + u_char val; + + /* Check known 0 bits that don't depend on DLAB. */ + val = uart_getreg(bas, REG_IIR); + if (val & 0x30) + return (ENXIO); + /* + * Bit 6 of the MCR (= 0x40) appears to be 1 for the Sun1699 + * chip, but otherwise doesn't seem to have a function. In + * other words, uart(4) works regardless. Ignore that bit so + * the probe succeeds. + */ + val = uart_getreg(bas, REG_MCR); + if (val & 0xa0) + return (ENXIO); +#endif + return (0); +} + +static void +ar933x_init(struct uart_bas *bas, int baudrate, int databits, int stopbits, + int parity) +{ +#if 0 + u_char ier; + + if (bas->rclk == 0) + bas->rclk = DEFAULT_RCLK; + ar933x_param(bas, baudrate, databits, stopbits, parity); + + /* Disable all interrupt sources. */ + /* + * We use 0xe0 instead of 0xf0 as the mask because the XScale PXA + * UARTs split the receive time-out interrupt bit out separately as + * 0x10. This gets handled by ier_mask and ier_rxbits below. + */ + ier = uart_getreg(bas, REG_IER) & 0xe0; + uart_setreg(bas, REG_IER, ier); + uart_barrier(bas); + + /* Disable the FIFO (if present). */ + uart_setreg(bas, REG_FCR, 0); + uart_barrier(bas); + + /* Set RTS & DTR. */ + uart_setreg(bas, REG_MCR, MCR_IE | MCR_RTS | MCR_DTR); + uart_barrier(bas); + + ar933x_clrint(bas); +#endif +} + +static void +ar933x_term(struct uart_bas *bas) +{ +#if 0 + /* Clear RTS & DTR. */ + uart_setreg(bas, REG_MCR, MCR_IE); + uart_barrier(bas); +#endif +} + +static void +ar933x_putc(struct uart_bas *bas, int c) +{ + int limit; + + limit = 250000; + + /* Wait for space in the TX FIFO */ + while ( ((ar933x_getreg(bas, AR933X_UART_DATA_REG) & + AR933X_UART_DATA_TX_CSR) == 0) && --limit) + DELAY(4); + + /* Write the actual byte */ + ar933x_setreg(bas, AR933X_UART_DATA_REG, + (c & 0xff) | AR933X_UART_DATA_TX_CSR); +} + +static int +ar933x_rxready(struct uart_bas *bas) +{ + + /* Wait for a character to come ready */ + return (!!(ar933x_getreg(bas, AR933X_UART_DATA_REG) + & AR933X_UART_DATA_RX_CSR)); +} + +static int +ar933x_getc(struct uart_bas *bas, struct mtx *hwmtx) +{ + int c; + + uart_lock(hwmtx); + + /* Wait for a character to come ready */ + while ((ar933x_getreg(bas, AR933X_UART_DATA_REG) & + AR933X_UART_DATA_RX_CSR) == 0) { + uart_unlock(hwmtx); + DELAY(4); + uart_lock(hwmtx); + } + + /* Read the top of the RX FIFO */ + c = ar933x_getreg(bas, AR933X_UART_DATA_REG) & 0xff; + + /* Remove that entry from said RX FIFO */ + ar933x_setreg(bas, AR933X_UART_DATA_REG, AR933X_UART_DATA_RX_CSR); + + uart_unlock(hwmtx); + + return (c); +} + +/* + * High-level UART interface. + */ +struct ar933x_softc { + struct uart_softc base; + uint8_t fcr; + uint8_t ier; + uint8_t mcr; + + uint8_t ier_mask; + uint8_t ier_rxbits; +}; + +static int ar933x_bus_attach(struct uart_softc *); +static int ar933x_bus_detach(struct uart_softc *); +static int ar933x_bus_flush(struct uart_softc *, int); +static int ar933x_bus_getsig(struct uart_softc *); +static int ar933x_bus_ioctl(struct uart_softc *, int, intptr_t); +static int ar933x_bus_ipend(struct uart_softc *); +static int ar933x_bus_param(struct uart_softc *, int, int, int, int); +static int ar933x_bus_probe(struct uart_softc *); +static int ar933x_bus_receive(struct uart_softc *); +static int ar933x_bus_setsig(struct uart_softc *, int); +static int ar933x_bus_transmit(struct uart_softc *); + +static kobj_method_t ar933x_methods[] = { + KOBJMETHOD(uart_attach, ar933x_bus_attach), + KOBJMETHOD(uart_detach, ar933x_bus_detach), + KOBJMETHOD(uart_flush, ar933x_bus_flush), + KOBJMETHOD(uart_getsig, ar933x_bus_getsig), + KOBJMETHOD(uart_ioctl, ar933x_bus_ioctl), + KOBJMETHOD(uart_ipend, ar933x_bus_ipend), + KOBJMETHOD(uart_param, ar933x_bus_param), + KOBJMETHOD(uart_probe, ar933x_bus_probe), + KOBJMETHOD(uart_receive, ar933x_bus_receive), + KOBJMETHOD(uart_setsig, ar933x_bus_setsig), + KOBJMETHOD(uart_transmit, ar933x_bus_transmit), + { 0, 0 } +}; + +struct uart_class uart_ar933x_class = { + "ar933x", + ar933x_methods, + sizeof(struct ar933x_softc), + .uc_ops = &uart_ar933x_ops, + .uc_range = 8, + .uc_rclk = DEFAULT_RCLK +}; + +#define SIGCHG(c, i, s, d) \ + if (c) { \ + i |= (i & s) ? s : s | d; \ + } else { \ + i = (i & s) ? (i & ~s) | d : i; \ + } + +static int +ar933x_bus_attach(struct uart_softc *sc) +{ +#if 0 + struct ar933x_softc *ns8250 = (struct ar933x_softc*)sc; + struct uart_bas *bas; + unsigned int ivar; + + bas = &sc->sc_bas; + + ns8250->mcr = uart_getreg(bas, REG_MCR); + ns8250->fcr = FCR_ENABLE; + if (!resource_int_value("uart", device_get_unit(sc->sc_dev), "flags", + &ivar)) { + if (UART_FLAGS_FCR_RX_LOW(ivar)) + ns8250->fcr |= FCR_RX_LOW; + else if (UART_FLAGS_FCR_RX_MEDL(ivar)) + ns8250->fcr |= FCR_RX_MEDL; + else if (UART_FLAGS_FCR_RX_HIGH(ivar)) + ns8250->fcr |= FCR_RX_HIGH; + else + ns8250->fcr |= FCR_RX_MEDH; + } else + ns8250->fcr |= FCR_RX_MEDH; + + /* Get IER mask */ + ivar = 0xf0; + resource_int_value("uart", device_get_unit(sc->sc_dev), "ier_mask", + &ivar); + ns8250->ier_mask = (uint8_t)(ivar & 0xff); + + /* Get IER RX interrupt bits */ + ivar = IER_EMSC | IER_ERLS | IER_ERXRDY; + resource_int_value("uart", device_get_unit(sc->sc_dev), "ier_rxbits", + &ivar); + ns8250->ier_rxbits = (uint8_t)(ivar & 0xff); + + uart_setreg(bas, REG_FCR, ns8250->fcr); + uart_barrier(bas); + ar933x_bus_flush(sc, UART_FLUSH_RECEIVER|UART_FLUSH_TRANSMITTER); + + if (ns8250->mcr & MCR_DTR) + sc->sc_hwsig |= SER_DTR; + if (ns8250->mcr & MCR_RTS) + sc->sc_hwsig |= SER_RTS; + ar933x_bus_getsig(sc); + + ar933x_clrint(bas); + ns8250->ier = uart_getreg(bas, REG_IER) & ns8250->ier_mask; + ns8250->ier |= ns8250->ier_rxbits; + uart_setreg(bas, REG_IER, ns8250->ier); + uart_barrier(bas); +#endif + return (0); +} + +static int +ar933x_bus_detach(struct uart_softc *sc) +{ +#if 0 + struct ar933x_softc *ns8250; + struct uart_bas *bas; + u_char ier; + + ns8250 = (struct ar933x_softc *)sc; + bas = &sc->sc_bas; + ier = uart_getreg(bas, REG_IER) & ns8250->ier_mask; + uart_setreg(bas, REG_IER, ier); + uart_barrier(bas); + ar933x_clrint(bas); +#endif + return (0); +} + +static int +ar933x_bus_flush(struct uart_softc *sc, int what) +{ +#if 0 + struct ar933x_softc *ns8250 = (struct ar933x_softc*)sc; + struct uart_bas *bas; + int error; + + bas = &sc->sc_bas; + uart_lock(sc->sc_hwmtx); + if (sc->sc_rxfifosz > 1) { + ar933x_flush(bas, what); + uart_setreg(bas, REG_FCR, ns8250->fcr); + uart_barrier(bas); + error = 0; + } else + error = ar933x_drain(bas, what); + uart_unlock(sc->sc_hwmtx); + return (error); +#endif + return (ENXIO); +} + +static int +ar933x_bus_getsig(struct uart_softc *sc) +{ +#if 0 + uint32_t new, old, sig; + uint8_t msr; + + do { + old = sc->sc_hwsig; + sig = old; + uart_lock(sc->sc_hwmtx); + msr = uart_getreg(&sc->sc_bas, REG_MSR); + uart_unlock(sc->sc_hwmtx); + SIGCHG(msr & MSR_DSR, sig, SER_DSR, SER_DDSR); + SIGCHG(msr & MSR_CTS, sig, SER_CTS, SER_DCTS); + SIGCHG(msr & MSR_DCD, sig, SER_DCD, SER_DDCD); + SIGCHG(msr & MSR_RI, sig, SER_RI, SER_DRI); + new = sig & ~SER_MASK_DELTA; + } while (!atomic_cmpset_32(&sc->sc_hwsig, old, new)); + return (sig); +#endif + return (0); +} + +static int +ar933x_bus_ioctl(struct uart_softc *sc, int request, intptr_t data) +{ +#if 0 + struct uart_bas *bas; + int baudrate, divisor, error; + uint8_t efr, lcr; + + bas = &sc->sc_bas; + error = 0; + uart_lock(sc->sc_hwmtx); + switch (request) { + case UART_IOCTL_BREAK: + lcr = uart_getreg(bas, REG_LCR); + if (data) + lcr |= LCR_SBREAK; + else + lcr &= ~LCR_SBREAK; + uart_setreg(bas, REG_LCR, lcr); + uart_barrier(bas); + break; + case UART_IOCTL_IFLOW: + lcr = uart_getreg(bas, REG_LCR); + uart_barrier(bas); + uart_setreg(bas, REG_LCR, 0xbf); + uart_barrier(bas); + efr = uart_getreg(bas, REG_EFR); + if (data) + efr |= EFR_RTS; + else + efr &= ~EFR_RTS; + uart_setreg(bas, REG_EFR, efr); + uart_barrier(bas); + uart_setreg(bas, REG_LCR, lcr); + uart_barrier(bas); + break; + case UART_IOCTL_OFLOW: + lcr = uart_getreg(bas, REG_LCR); + uart_barrier(bas); + uart_setreg(bas, REG_LCR, 0xbf); + uart_barrier(bas); + efr = uart_getreg(bas, REG_EFR); + if (data) + efr |= EFR_CTS; + else + efr &= ~EFR_CTS; + uart_setreg(bas, REG_EFR, efr); + uart_barrier(bas); + uart_setreg(bas, REG_LCR, lcr); + uart_barrier(bas); + break; + case UART_IOCTL_BAUD: + lcr = uart_getreg(bas, REG_LCR); + uart_setreg(bas, REG_LCR, lcr | LCR_DLAB); + uart_barrier(bas); + divisor = uart_getreg(bas, REG_DLL) | + (uart_getreg(bas, REG_DLH) << 8); + uart_barrier(bas); + uart_setreg(bas, REG_LCR, lcr); + uart_barrier(bas); + baudrate = (divisor > 0) ? bas->rclk / divisor / 16 : 0; + if (baudrate > 0) + *(int*)data = baudrate; + else + error = ENXIO; + break; + default: + error = EINVAL; + break; + } + uart_unlock(sc->sc_hwmtx); + return (error); +#endif + return (ENXIO); +} + +static int +ar933x_bus_ipend(struct uart_softc *sc) +{ +#if 0 + struct uart_bas *bas; + struct ar933x_softc *ns8250; + int ipend; + uint8_t iir, lsr; + + ns8250 = (struct ar933x_softc *)sc; + bas = &sc->sc_bas; + uart_lock(sc->sc_hwmtx); + iir = uart_getreg(bas, REG_IIR); + if (iir & IIR_NOPEND) { + uart_unlock(sc->sc_hwmtx); + return (0); + } + ipend = 0; + if (iir & IIR_RXRDY) { + lsr = uart_getreg(bas, REG_LSR); + if (lsr & LSR_OE) + ipend |= SER_INT_OVERRUN; + if (lsr & LSR_BI) + ipend |= SER_INT_BREAK; + if (lsr & LSR_RXRDY) + ipend |= SER_INT_RXREADY; + } else { + if (iir & IIR_TXRDY) { + ipend |= SER_INT_TXIDLE; + uart_setreg(bas, REG_IER, ns8250->ier); + } else + ipend |= SER_INT_SIGCHG; + } + if (ipend == 0) + ar933x_clrint(bas); + uart_unlock(sc->sc_hwmtx); + return (ipend); +#endif + return (0); +} + +static int +ar933x_bus_param(struct uart_softc *sc, int baudrate, int databits, + int stopbits, int parity) +{ +#if 0 + struct uart_bas *bas; + int error; + + bas = &sc->sc_bas; + uart_lock(sc->sc_hwmtx); + error = ar933x_param(bas, baudrate, databits, stopbits, parity); + uart_unlock(sc->sc_hwmtx); + return (error); +#endif + return (ENXIO); +} + +static int +ar933x_bus_probe(struct uart_softc *sc) +{ +#if 0 + struct ar933x_softc *ns8250; + struct uart_bas *bas; + int count, delay, error, limit; + uint8_t lsr, mcr, ier; + + ns8250 = (struct ar933x_softc *)sc; + bas = &sc->sc_bas; + + error = ar933x_probe(bas); + if (error) + return (error); + + mcr = MCR_IE; + if (sc->sc_sysdev == NULL) { + /* By using ar933x_init() we also set DTR and RTS. */ + ar933x_init(bas, 115200, 8, 1, UART_PARITY_NONE); + } else + mcr |= MCR_DTR | MCR_RTS; + + error = ar933x_drain(bas, UART_DRAIN_TRANSMITTER); + if (error) + return (error); + + /* + * Set loopback mode. This avoids having garbage on the wire and + * also allows us send and receive data. We set DTR and RTS to + * avoid the possibility that automatic flow-control prevents + * any data from being sent. + */ + uart_setreg(bas, REG_MCR, MCR_LOOPBACK | MCR_IE | MCR_DTR | MCR_RTS); + uart_barrier(bas); + + /* + * Enable FIFOs. And check that the UART has them. If not, we're + * done. Since this is the first time we enable the FIFOs, we reset + * them. + */ + uart_setreg(bas, REG_FCR, FCR_ENABLE); + uart_barrier(bas); + if (!(uart_getreg(bas, REG_IIR) & IIR_FIFO_MASK)) { + /* + * NS16450 or INS8250. We don't bother to differentiate + * between them. They're too old to be interesting. + */ + uart_setreg(bas, REG_MCR, mcr); + uart_barrier(bas); + sc->sc_rxfifosz = sc->sc_txfifosz = 1; + device_set_desc(sc->sc_dev, "8250 or 16450 or compatible"); + return (0); + } + + uart_setreg(bas, REG_FCR, FCR_ENABLE | FCR_XMT_RST | FCR_RCV_RST); + uart_barrier(bas); + + count = 0; + delay = ar933x_delay(bas); + + /* We have FIFOs. Drain the transmitter and receiver. */ + error = ar933x_drain(bas, UART_DRAIN_RECEIVER|UART_DRAIN_TRANSMITTER); + if (error) { + uart_setreg(bas, REG_MCR, mcr); + uart_setreg(bas, REG_FCR, 0); + uart_barrier(bas); + goto describe; + } + + /* + * We should have a sufficiently clean "pipe" to determine the + * size of the FIFOs. We send as much characters as is reasonable + * and wait for the overflow bit in the LSR register to be + * asserted, counting the characters as we send them. Based on + * that count we know the FIFO size. + */ + do { + uart_setreg(bas, REG_DATA, 0); + uart_barrier(bas); + count++; + + limit = 30; + lsr = 0; + /* + * LSR bits are cleared upon read, so we must accumulate + * them to be able to test LSR_OE below. + */ + while (((lsr |= uart_getreg(bas, REG_LSR)) & LSR_TEMT) == 0 && + --limit) + DELAY(delay); + if (limit == 0) { + ier = uart_getreg(bas, REG_IER) & ns8250->ier_mask; + uart_setreg(bas, REG_IER, ier); + uart_setreg(bas, REG_MCR, mcr); + uart_setreg(bas, REG_FCR, 0); + uart_barrier(bas); + count = 0; + goto describe; + } + } while ((lsr & LSR_OE) == 0 && count < 130); + count--; + + uart_setreg(bas, REG_MCR, mcr); + + /* Reset FIFOs. */ + ar933x_flush(bas, UART_FLUSH_RECEIVER|UART_FLUSH_TRANSMITTER); + + describe: + if (count >= 14 && count <= 16) { + sc->sc_rxfifosz = 16; + device_set_desc(sc->sc_dev, "16550 or compatible"); + } else if (count >= 28 && count <= 32) { + sc->sc_rxfifosz = 32; + device_set_desc(sc->sc_dev, "16650 or compatible"); + } else if (count >= 56 && count <= 64) { + sc->sc_rxfifosz = 64; + device_set_desc(sc->sc_dev, "16750 or compatible"); + } else if (count >= 112 && count <= 128) { + sc->sc_rxfifosz = 128; + device_set_desc(sc->sc_dev, "16950 or compatible"); + } else { + sc->sc_rxfifosz = 16; + device_set_desc(sc->sc_dev, + "Non-standard ns8250 class UART with FIFOs"); + } + + /* + * Force the Tx FIFO size to 16 bytes for now. We don't program the + * Tx trigger. Also, we assume that all data has been sent when the + * interrupt happens. + */ + sc->sc_txfifosz = 16; + +#if 0 + /* + * XXX there are some issues related to hardware flow control and + * it's likely that uart(4) is the cause. This basicly needs more + * investigation, but we avoid using for hardware flow control + * until then. + */ + /* 16650s or higher have automatic flow control. */ + if (sc->sc_rxfifosz > 16) { + sc->sc_hwiflow = 1; + sc->sc_hwoflow = 1; + } +#endif +#endif + return (0); +} + +static int +ar933x_bus_receive(struct uart_softc *sc) +{ +#if 0 + struct uart_bas *bas; + int xc; + uint8_t lsr; + + bas = &sc->sc_bas; + uart_lock(sc->sc_hwmtx); + lsr = uart_getreg(bas, REG_LSR); + while (lsr & LSR_RXRDY) { + if (uart_rx_full(sc)) { + sc->sc_rxbuf[sc->sc_rxput] = UART_STAT_OVERRUN; + break; + } + xc = uart_getreg(bas, REG_DATA); + if (lsr & LSR_FE) + xc |= UART_STAT_FRAMERR; + if (lsr & LSR_PE) + xc |= UART_STAT_PARERR; + uart_rx_put(sc, xc); + lsr = uart_getreg(bas, REG_LSR); + } + /* Discard everything left in the Rx FIFO. */ + while (lsr & LSR_RXRDY) { + (void)uart_getreg(bas, REG_DATA); + uart_barrier(bas); + lsr = uart_getreg(bas, REG_LSR); + } + uart_unlock(sc->sc_hwmtx); +#endif + return (0); +} + +static int +ar933x_bus_setsig(struct uart_softc *sc, int sig) +{ +#if 0 + struct ar933x_softc *ns8250 = (struct ar933x_softc*)sc; + struct uart_bas *bas; + uint32_t new, old; + + bas = &sc->sc_bas; + do { + old = sc->sc_hwsig; + new = old; + if (sig & SER_DDTR) { + SIGCHG(sig & SER_DTR, new, SER_DTR, + SER_DDTR); + } + if (sig & SER_DRTS) { + SIGCHG(sig & SER_RTS, new, SER_RTS, + SER_DRTS); + } + } while (!atomic_cmpset_32(&sc->sc_hwsig, old, new)); + uart_lock(sc->sc_hwmtx); + ns8250->mcr &= ~(MCR_DTR|MCR_RTS); + if (new & SER_DTR) + ns8250->mcr |= MCR_DTR; + if (new & SER_RTS) + ns8250->mcr |= MCR_RTS; + uart_setreg(bas, REG_MCR, ns8250->mcr); + uart_barrier(bas); + uart_unlock(sc->sc_hwmtx); +#endif + return (0); +} + +static int +ar933x_bus_transmit(struct uart_softc *sc) +{ +#if 0 + struct ar933x_softc *ns8250 = (struct ar933x_softc*)sc; + struct uart_bas *bas; + int i; + + bas = &sc->sc_bas; + uart_lock(sc->sc_hwmtx); + while ((uart_getreg(bas, REG_LSR) & LSR_THRE) == 0) + ; + uart_setreg(bas, REG_IER, ns8250->ier | IER_ETXRDY); + uart_barrier(bas); + for (i = 0; i < sc->sc_txdatasz; i++) { + uart_setreg(bas, REG_DATA, sc->sc_txbuf[i]); + uart_barrier(bas); + } + sc->sc_txbusy = 1; + uart_unlock(sc->sc_hwmtx); +#endif + return (0); +} Index: atheros/uart_dev_ar933x.h =================================================================== --- atheros/uart_dev_ar933x.h (revision 0) +++ atheros/uart_dev_ar933x.h (working copy) @@ -0,0 +1,6 @@ +#ifndef __UART_DEV_AR933X__ +#define __UART_DEV_AR933X__ + +extern struct uart_class uart_ar933x_class; + +#endif