diff options
-rw-r--r-- | sys/mips/conf/RT305X | 134 | ||||
-rw-r--r-- | sys/mips/conf/RT305X.hints | 136 | ||||
-rw-r--r-- | sys/mips/rt305x/files.rt305x | 13 | ||||
-rw-r--r-- | sys/mips/rt305x/obio.c | 627 | ||||
-rw-r--r-- | sys/mips/rt305x/obiovar.h | 58 | ||||
-rw-r--r-- | sys/mips/rt305x/rt305x_dotg.c | 247 | ||||
-rw-r--r-- | sys/mips/rt305x/rt305x_gpio.c | 619 | ||||
-rw-r--r-- | sys/mips/rt305x/rt305x_gpio.h | 111 | ||||
-rw-r--r-- | sys/mips/rt305x/rt305x_gpiovar.h | 48 | ||||
-rw-r--r-- | sys/mips/rt305x/rt305x_ic.c | 141 | ||||
-rw-r--r-- | sys/mips/rt305x/rt305x_icvar.h | 42 | ||||
-rw-r--r-- | sys/mips/rt305x/rt305x_machdep.c | 217 | ||||
-rw-r--r-- | sys/mips/rt305x/rt305x_sysctl.c | 240 | ||||
-rw-r--r-- | sys/mips/rt305x/rt305x_sysctlvar.h | 45 | ||||
-rw-r--r-- | sys/mips/rt305x/rt305xreg.h | 368 | ||||
-rw-r--r-- | sys/mips/rt305x/rt_swreg.h | 160 | ||||
-rw-r--r-- | sys/mips/rt305x/std.rt305x | 8 | ||||
-rw-r--r-- | sys/mips/rt305x/uart_bus_rt305x.c | 102 | ||||
-rw-r--r-- | sys/mips/rt305x/uart_cpu_rt305x.c | 82 | ||||
-rw-r--r-- | sys/mips/rt305x/uart_dev_rt305x.c | 507 | ||||
-rw-r--r-- | sys/mips/rt305x/uart_dev_rt305x.h | 126 |
21 files changed, 4031 insertions, 0 deletions
diff --git a/sys/mips/conf/RT305X b/sys/mips/conf/RT305X new file mode 100644 index 0000000..50ed9c4 --- /dev/null +++ b/sys/mips/conf/RT305X @@ -0,0 +1,134 @@ +# RT305X -- Kernel configuration file for FreeBSD/mips for Ralink RT305xF systems +# +# For more information on this file, please read the handbook section on +# Kernel Configuration Files: +# +# http://www.FreeBSD.org/doc/en_US.ISO8859-1/books/handbook/kernelconfig-config.html +# +# The handbook is also available locally in /usr/share/doc/handbook +# if you've installed the doc distribution, otherwise always see the +# FreeBSD World Wide Web server (http://www.FreeBSD.org/) for the +# latest information. +# +# An exhaustive list of options and more detailed explanations of the +# device lines is also present in the ../../conf/NOTES and NOTES files. +# If you are in doubt as to the purpose or necessity of a line, check first +# in NOTES. +# +# $FreeBSD$ + +ident RT305X + +machine mips mipsel +makeoptions MIPS_LITTLE_ENDIAN=defined +makeoptions KERNLOADADDR=0x80001000 + +# Don't build any modules yet. +makeoptions MODULES_OVERRIDE="wlan_xauth wlan_wep wlan_tkip wlan_acl wlan_amrr wlan_ccmp wlan_rssadapt random if_bridge bridgestp msdosfs md ipfw dummynet libalias geom/geom_label ufs usb/uplcom usb/u3g usb/umodem usb/umass usb/ucom cam zlib" +makeoptions RT3052F + +include "../rt305x/std.rt305x" + +hints "RT305X.hints" #Default places to look for devices. + +#makeoptions DEBUG=-g #Build kernel with gdb(1) debug symbols + +# Debugging for use in -current +#options DEADLKRES #Enable the deadlock resolver +#options INVARIANTS #Enable calls of extra sanity checking +#options INVARIANT_SUPPORT #Extra sanity checks of internal structures, required by INVARIANTS +#options WITNESS #Enable checks to detect deadlocks and cycles +#options WITNESS_SKIPSPIN #Don't run witness on spinlocks for speed +#options DIAGNOSTIC +#options DEBUG_LOCKS +#options DEBUG_VFS_LOCKS +#options GDB +options DDB +options KDB + +options SCHED_ULE +#options SCHED_4BSD #4BSD scheduler +#options COMPAT_43 +options INET #InterNETworking +options NFSCLIENT #Network Filesystem Client +options NFS_ROOT #NFS usable as /, requires NFSCLIENT +options PSEUDOFS #Pseudo-filesystem framework +#options _KPOSIX_PRIORITY_SCHEDULING #Posix P1003_1B real-time extensions + +options BOOTP +#options BOOTP_NFSROOT +options BOOTP_NFSV3 +options BOOTP_WIRED_TO=rt0 +options BOOTP_COMPAT +options CD9660 # ISO 9660 Filesystem +options ROOTDEVNAME=\"cd9660:/dev/map/rootfs.uncompress\" +options TMPFS # TMP Memory Filesystem + +#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 ROOTDEVNAME=\"nfs:10.0.0.1:/mnt/bsd\" + +# Options for making kernel less hangry +makeoptions INLINE_LIMIT=1024 +options MAXUSERS=3 +options MAXFILES=512 +options NSFBUFS=256 +options SHMALL=128 +options MSGBUF_SIZE=65536 + +# Options for making kernel smallest +options NO_SYSCTL_DESCR # No description string of sysctl +#options NO_FFS_SNAPSHOT # Disable Snapshot supporting +options SCSI_NO_SENSE_STRINGS +options SCSI_NO_OP_STRINGS +options RWLOCK_NOINLINE +options SX_NOINLINE +options NO_SWAPPING +options ZERO_COPY_SOCKETS +options MROUTING # Multicast routing +options IPFIREWALL_DEFAULT_TO_ACCEPT + +device random +device loop +# RT3050F, RT3052F have only pseudo PHYs +#device mii +#device miibus +device pty # Pseudo-ttys (telnet etc) +device ether +device bpf # Berkeley packet filter +device vlan +#device lagg +#device if_bridge +device uart +nodevice uart_ns8250 +device tun # Packet tunnel. + +device wlan + + +device gpio +device gpioled + +device cfi # Detect Flash memmory +device cfid + +device nvram2env + +device usb +#device dotg # DWC like USB OTG Controller driver +#device u3g +#device umodem +#device uplcom +#device umass +#device da +#device pass +#device scbus +options SCSI_DELAY=1000 # Delay (in ms) before probing SCSI + +#options USB_EHCI_BIG_ENDIAN_DESC # handle big-endian byte order +#options USB_DEBUG +#options USB_REQ_DEBUG + + diff --git a/sys/mips/conf/RT305X.hints b/sys/mips/conf/RT305X.hints new file mode 100644 index 0000000..3c8b6cb --- /dev/null +++ b/sys/mips/conf/RT305X.hints @@ -0,0 +1,136 @@ +# $FreeBSD$ +# device.hints +hint.obio.0.at="nexus0" +hint.obio.0.maddr=0x10000000 +hint.obio.0.msize=0x10000000 + +hint.nvram.0.sig=0xe5e60a74 +hint.nvram.0.base=0x1f030000 +hint.nvram.0.maxsize=0x2000 +hint.nvram.0.flags=3 # 1 = No check, 2 = Format Generic +hint.nvram.1.sig=0x5a045e94 +hint.nvram.1.base=0x1f032000 +hint.nvram.1.maxsize=0x4000 +hint.nvram.1.flags=3 # 1 = No check, 2 = Format Generic + +# on-board Ralink Frame Engine +#hint.rt.0.at="nexus0" +#hint.rt.0.maddr=0x12000000 +#hint.rt.0.msize=0x200000 +#hint.rt.0.irq=9 +hint.rt.0.macaddr="00:18:e7:d5:83:90" + +# on-board Ralink 2872 802.11n core +hint.rt2860.0.at="nexus0" +hint.rt2860.0.maddr=0x10180000 +hint.rt2860.0.msize=0x40000 +hint.rt2860.0.irq=4 + +# uart0 +#hint.uart.0.at="obio0" +#hint.uart.0.maddr=0x10000C00 +#hint.uart.0.msize=0x100 +#hint.uart.0.irq=12 +#hint.uart.0.flags="0x30" + +# uart1 +#hint.uart.1.at="obio0" +#hint.uart.1.maddr=0x10000500 +#hint.uart.1.msize=0x100 +#hint.uart.1.irq=5 +#hint.uart.1.flags="0x30" + + +# gpio +# GPIO0 - WPS BTN IN II IO +hint.gpiobutton.0.at="gpiobus0" +hint.gpiobutton.0.pins="0x01" +hint.gpiobutton.0.name="wps" +hint.gpiobutton.0.flags="0x0581" + +# GPIO7 - MODE SW AP IN II IO +hint.gpiobutton.1.at="gpiobus0" +hint.gpiobutton.1.pins="0x80" +hint.gpiobutton.1.name="mode_ap" +hint.gpiobutton.1.flags="0x0581" + +# GPIO8 - ST LEDRED OUT /* 2pin BiDir RED/BLUE LED */ +# GPIO9 - ST LEDBLUE OUT +hint.gpioled.0.at="gpiobus0" +hint.gpioled.0.pins="0x100" +hint.gpioled.0.name="status_red" +hint.gpioled.0.flags="0x0002" +hint.gpioled.1.at="gpiobus0" +hint.gpioled.1.pins="0x200" +#hint.gpioled.1.name="status_blue" +hint.gpioled.1.name="status" +hint.gpioled.1.flags="0x0002" + +# GPIO10 - RST BTN IN II IO +hint.gpiobutton.2.at="gpiobus0" +hint.gpiobutton.2.pins="0x400" +hint.gpiobutton.2.name="reset" +hint.gpiobutton.2.flags="0x0581" + +# GPIO11 - MODE SW CL IN II IO +hint.gpiobutton.3.at="gpiobus0" +hint.gpiobutton.3.pins="0x800" +hint.gpiobutton.3.name="mode_wlan_client" +hint.gpiobutton.3.flags="0x0581" + +# GPIO14 - WPS LED OUT II IO +hint.gpioled.2.at="gpiobus0" +hint.gpioled.2.pins="0x4000" +hint.gpioled.2.name="wps" +hint.gpioled.2.flags="0x0182" + + + +#0x00000000-0x00030000 : "Bootloader" +#0x00030000-0x00040000 : "Factory" +#0x00040000-0x00070000 : "Config" +#0x00070000-0x000b0000 : "Language" +#0x000b0000-0x001a0000 : "Kernel" +#0x001a0000-0x01000000 : "RootFS" + +hint.map.0.at="cfid0" +hint.map.0.start=0x00000000 +hint.map.0.end=0x00030000 +hint.map.0.name="bootloader" +hint.map.0.readonly=1 + +hint.map.1.at="cfid0" +hint.map.1.start=0x00030000 +hint.map.1.end=0x00040000 +hint.map.1.name="factory" + +hint.map.2.at="cfid0" +hint.map.2.start=0x00040000 +hint.map.2.end=0x00800000 +hint.map.2.name="upgrade" + +hint.map.3.at="cfid0" +hint.map.3.start=0x00040000 +hint.map.3.end=0x00050000 +hint.map.3.name="config" + +hint.map.4.at="cfid0" +hint.map.4.start=0x00000000 +hint.map.4.end=0x00000000 +hint.map.4.name="language" + +hint.map.5.at="cfid0" +hint.map.5.start=0x00050000 +hint.map.5.end=0x00150000 +hint.map.5.name="kernel" + +hint.map.6.at="cfid0" +hint.map.6.start=0x00150000 +hint.map.6.end=0x00800000 +hint.map.6.name="rootfs" + + +hint.rt.0.phymask=0x1f +hint.rt.0.media=100 +hint.rt.0.fduplex=1 + diff --git a/sys/mips/rt305x/files.rt305x b/sys/mips/rt305x/files.rt305x new file mode 100644 index 0000000..caf4c3d --- /dev/null +++ b/sys/mips/rt305x/files.rt305x @@ -0,0 +1,13 @@ +# $FreeBSD$ + +# RT305X on-board devices +mips/rt305x/rt305x_machdep.c standard +mips/rt305x/obio.c standard +mips/rt305x/rt305x_sysctl.c standard +mips/rt305x/rt305x_ic.c standard +mips/rt305x/rt305x_gpio.c optional gpio +mips/rt305x/uart_bus_rt305x.c optional uart +mips/rt305x/uart_cpu_rt305x.c optional uart +mips/rt305x/uart_dev_rt305x.c optional uart +mips/mips/intr_machdep.c standard +mips/mips/tick.c standard diff --git a/sys/mips/rt305x/obio.c b/sys/mips/rt305x/obio.c new file mode 100644 index 0000000..870afea --- /dev/null +++ b/sys/mips/rt305x/obio.c @@ -0,0 +1,627 @@ +/* $NetBSD: obio.c,v 1.11 2003/07/15 00:25:05 lukem Exp $ */ + +/*- + * Copyright (c) 2001, 2002, 2003 Wasabi Systems, Inc. + * All rights reserved. + * + * Written by Jason R. Thorpe for Wasabi Systems, Inc. + * + * 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 WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC + * 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> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/bus.h> +#include <sys/interrupt.h> +#include <sys/kernel.h> +#include <sys/module.h> +#include <sys/rman.h> +#include <sys/malloc.h> + +#include <machine/bus.h> + +#include <mips/rt305x/rt305xreg.h> +#include <mips/rt305x/obiovar.h> +#include <mips/rt305x/rt305x_icvar.h> + +/* MIPS HW interrupts of IRQ/FIQ respectively */ +#define RT305X_INTR 0 +#define RT305X_FAST_INTR 1 + +/* Interrupt levels */ +#define INTR_IRQ 0 +#define INTR_FIQ 1 + + +int irq_priorities[NIRQS] = { + INTR_IRQ, /* SYSCTL */ + INTR_FIQ, /* TIMER0 */ + INTR_FIQ, /* WDTIMER */ + INTR_IRQ, /* Illegal Access */ + INTR_IRQ, /* PCM */ + INTR_IRQ, /* UART */ + INTR_IRQ, /* GPIO */ + INTR_FIQ, /* GDMA */ + INTR_IRQ, /* NAND */ + INTR_IRQ, /* Perfomance Counter */ + INTR_IRQ, /* I2S */ + INTR_IRQ, /* unknown */ + INTR_IRQ, /* UARTLITE */ + INTR_IRQ, /* unknown */ + INTR_IRQ, /* unknown */ + INTR_IRQ, /* unknown */ + INTR_IRQ, /* unknown */ + INTR_IRQ, /* EtherNet Switch */ + INTR_FIQ, /* OTG */ + INTR_IRQ, /* unknown */ + INTR_IRQ, /* unknown */ + INTR_IRQ, /* unknown */ + INTR_IRQ, /* unknown */ + INTR_IRQ, /* unknown */ + INTR_IRQ, /* unknown */ + INTR_IRQ, /* unknown */ + INTR_IRQ, /* unknown */ + INTR_IRQ, /* unknown */ + INTR_IRQ, /* unknown */ + INTR_IRQ, /* unknown */ + INTR_IRQ, /* unknown */ + INTR_IRQ, /* unknown */ +}; + + +#define REG_READ(o) *((volatile uint32_t *)MIPS_PHYS_TO_KSEG1(INTCTL_BASE + (o))) +#define REG_WRITE(o,v) (REG_READ(o)) = (v) + +static int obio_activate_resource(device_t, device_t, int, int, + struct resource *); +static device_t obio_add_child(device_t, u_int, const char *, int); +static struct resource * + obio_alloc_resource(device_t, device_t, int, int *, u_long, + u_long, u_long, u_int); +static int obio_attach(device_t); +static int obio_deactivate_resource(device_t, device_t, int, int, + struct resource *); +static struct resource_list * + obio_get_resource_list(device_t, device_t); +static void obio_add_res_child(device_t, const char *, int, long, int, int); +static void obio_hinted_child(device_t, const char *, int); +static int obio_intr(void *); +static int obio_probe(device_t); +static int obio_release_resource(device_t, device_t, int, int, + struct resource *); +static int obio_setup_intr(device_t, device_t, struct resource *, int, + driver_filter_t *, driver_intr_t *, void *, void **); +static int obio_teardown_intr(device_t, device_t, struct resource *, + void *); + +static void +obio_mask_irq(void *source) +{ + int irq; + uint32_t irqmask; + + irq = (int)source; + irqmask = 1 << irq; + + /* disable IRQ */ + rt305x_ic_set(IC_INT_DIS, irqmask); +} + +static void +obio_unmask_irq(void *source) +{ + int irq; + uint32_t irqmask; + + irq = (int)source; + irqmask = 1 << irq; + + /* enable IRQ */ + rt305x_ic_set(IC_INT_ENA, irqmask); + +} + + +static int +obio_probe(device_t dev) +{ + + return (0); +} + +static int +obio_attach(device_t dev) +{ + struct obio_softc *sc = device_get_softc(dev); + int rid; + + sc->oba_mem_rman.rm_type = RMAN_ARRAY; + sc->oba_mem_rman.rm_descr = "OBIO memory"; + if (rman_init(&sc->oba_mem_rman) != 0 || + rman_manage_region(&sc->oba_mem_rman, OBIO_MEM_START, + OBIO_MEM_END) != 0) + panic("obio_attach: failed to set up I/O rman"); + + sc->oba_irq_rman.rm_type = RMAN_ARRAY; + sc->oba_irq_rman.rm_descr = "OBIO IRQ"; + if (rman_init(&sc->oba_irq_rman) != 0 || + rman_manage_region(&sc->oba_irq_rman, 0, NIRQS-1) != 0) + panic("obio_attach: failed to set up IRQ rman"); + + /* Hook up our interrupt handler. */ + if ((sc->sc_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, + RT305X_INTR, RT305X_INTR, 1, + RF_SHAREABLE | RF_ACTIVE)) == NULL) { + device_printf(dev, "unable to allocate IRQ resource\n"); + return (ENXIO); + } + + if ((bus_setup_intr(dev, sc->sc_irq, INTR_TYPE_MISC, obio_intr, NULL, + sc, &sc->sc_ih))) { + device_printf(dev, + "WARNING: unable to register interrupt handler\n"); + return (ENXIO); + } + + /* Hook up our FAST interrupt handler. */ + if ((sc->sc_fast_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, + RT305X_FAST_INTR, RT305X_FAST_INTR, 1, + RF_SHAREABLE | RF_ACTIVE)) == NULL) { + device_printf(dev, "unable to allocate IRQ resource\n"); + return (ENXIO); + } + + if ((bus_setup_intr(dev, sc->sc_fast_irq, INTR_TYPE_MISC, obio_intr, + NULL, sc, &sc->sc_fast_ih))) { + device_printf(dev, + "WARNING: unable to register interrupt handler\n"); + return (ENXIO); + } + + /* disable all interrupts */ + rt305x_ic_set(IC_INT_DIS, IC_INT_MASK|IC_LINE_GLOBAL); + + bus_generic_probe(dev); + + obio_add_res_child(dev, "rt305x_sysctl", 0, + SYSCTL_BASE, (SYSCTL_END - SYSCTL_BASE + 1), + IC_SYSCTL); + obio_add_res_child(dev, "rt305x_ic", 0, + INTCTL_BASE, (INTCTL_END - INTCTL_BASE + 1), + -1); +#ifdef notyet + obio_add_res_child(dev, "timer",0, + TIMER_BASE, (TIMER_END - TIMER_BASE + 1), + IC_TIMER0); + obio_add_res_child(dev, "rt305x_memc", 0, + MEMCTRL_BASE, (MEMCTRL_END - MEMCTRL_BASE + 1), + -1); + obio_add_res_child(dev, "pcm", 0, + PCM_BASE, (PCM_END - PCM_BASE + 1), + IC_PCM); + obio_add_res_child(dev, "uart", 0, + UART_BASE, (UART_END - UART_BASE + 1), + IC_UART); +#endif + obio_add_res_child(dev, "gpio", 0, + PIO_BASE, (PIO_END - PIO_BASE + 1), + IC_PIO); +#ifdef notyet + obio_add_res_child(dev, "rt305x_dma", 0, + GDMA_BASE, (GDMA_END - GDMA_BASE + 1), + IC_DMA); + obio_add_res_child(dev, "rt305x_nandc", 0, + NANDFC_BASE, (NANDFC_END - NANDFC_BASE + 1), + IC_NAND); + obio_add_res_child(dev, "i2c", 0, + I2C_BASE, (I2C_END - I2C_BASE + 1), + -1); + obio_add_res_child(dev, "i2s", 0, + I2S_BASE, (I2S_END - I2S_BASE + 1), + IC_I2S); + obio_add_res_child(dev, "spi", 0, + SPI_BASE, (SPI_END - SPI_BASE + 1), + -1); +#endif + obio_add_res_child(dev, "uart", 1, + UARTLITE_BASE, (UARTLITE_END - UARTLITE_BASE + 1), + IC_UARTLITE); + obio_add_res_child(dev, "cfi", 0, + FLASH_BASE, (FLASH_END - FLASH_BASE + 1), + -1); + obio_add_res_child(dev, "dotg", 0, + USB_OTG_BASE, (USB_OTG_END - USB_OTG_BASE + 1), + IC_OTG); + obio_add_res_child(dev, "switch", 0, + ETHSW_BASE, (ETHSW_END - ETHSW_BASE + 1), + IC_ETHSW); + + bus_enumerate_hinted_children(dev); + bus_generic_attach(dev); + + /* enable IC */ + rt305x_ic_set(IC_INT_ENA, IC_LINE_GLOBAL); + + return (0); +} + +static struct resource * +obio_alloc_resource(device_t bus, device_t child, int type, int *rid, + u_long start, u_long end, u_long count, u_int flags) +{ + struct obio_softc *sc = device_get_softc(bus); + struct obio_ivar *ivar = device_get_ivars(child); + struct resource *rv; + struct resource_list_entry *rle; + struct rman *rm; + int isdefault, needactivate, passthrough; + + isdefault = (start == 0UL && end == ~0UL && count == 1); + needactivate = flags & RF_ACTIVE; + passthrough = (device_get_parent(child) != bus); + rle = NULL; + + if (passthrough) + return (BUS_ALLOC_RESOURCE(device_get_parent(bus), child, type, + rid, start, end, count, flags)); + + /* + * If this is an allocation of the "default" range for a given RID, + * and we know what the resources for this device are (ie. they aren't + * maintained by a child bus), then work out the start/end values. + */ + if (isdefault) { + rle = resource_list_find(&ivar->resources, type, *rid); + if (rle == NULL) + return (NULL); + if (rle->res != NULL) { + panic("%s: resource entry is busy", __func__); + } + start = rle->start; + end = rle->end; + count = rle->count; + } + + switch (type) { + case SYS_RES_IRQ: + rm = &sc->oba_irq_rman; + break; + case SYS_RES_MEMORY: + rm = &sc->oba_mem_rman; + break; + default: + printf("%s: unknown resource type %d\n", __func__, type); + return (0); + } + + rv = rman_reserve_resource(rm, start, end, count, flags, child); + if (rv == 0) { + printf("%s: could not reserve resource\n", __func__); + return (0); + } + + rman_set_rid(rv, *rid); + + if (needactivate) { + if (bus_activate_resource(child, type, *rid, rv)) { + printf("%s: could not activate resource\n", __func__); + rman_release_resource(rv); + return (0); + } + } + + return (rv); +} + +static int +obio_activate_resource(device_t bus, device_t child, int type, int rid, + struct resource *r) +{ + + /* + * If this is a memory resource, track the direct mapping + * in the uncached MIPS KSEG1 segment. + */ + if (type == SYS_RES_MEMORY) { + void *vaddr; + + vaddr = (void *)MIPS_PHYS_TO_KSEG1((intptr_t)rman_get_start(r)); + rman_set_virtual(r, vaddr); + rman_set_bustag(r, mips_bus_space_generic); + rman_set_bushandle(r, (bus_space_handle_t)vaddr); + } + + return (rman_activate_resource(r)); +} + +static int +obio_deactivate_resource(device_t bus, device_t child, int type, int rid, + struct resource *r) +{ + + return (rman_deactivate_resource(r)); +} + +static int +obio_release_resource(device_t dev, device_t child, int type, + int rid, struct resource *r) +{ + struct resource_list *rl; + struct resource_list_entry *rle; + + rl = obio_get_resource_list(dev, child); + if (rl == NULL) + return (EINVAL); + rle = resource_list_find(rl, type, rid); + if (rle == NULL) + return (EINVAL); + rman_release_resource(r); + rle->res = NULL; + + return (0); +} + +static int +obio_setup_intr(device_t dev, device_t child, struct resource *ires, + int flags, driver_filter_t *filt, driver_intr_t *handler, + void *arg, void **cookiep) +{ + struct obio_softc *sc = device_get_softc(dev); + struct intr_event *event; + int irq, error, priority; + uint32_t irqmask; + + irq = rman_get_start(ires); + + if (irq >= NIRQS) + panic("%s: bad irq %d", __func__, irq); + + event = sc->sc_eventstab[irq]; + if (event == NULL) { + error = intr_event_create(&event, (void *)irq, 0, irq, + obio_mask_irq, obio_unmask_irq, + NULL, NULL, "obio intr%d:", irq); + + sc->sc_eventstab[irq] = event; + } + else + panic("obio: Can't share IRQs"); + + intr_event_add_handler(event, device_get_nameunit(child), filt, + handler, arg, intr_priority(flags), flags, cookiep); + + irqmask = 1 << irq; + priority = irq_priorities[irq]; + + if (priority == INTR_FIQ) + rt305x_ic_set(IC_INTTYPE, rt305x_ic_get(IC_INTTYPE) | irqmask); + else + rt305x_ic_set(IC_INTTYPE, rt305x_ic_get(IC_INTTYPE) & ~irqmask); + + /* enable */ + obio_unmask_irq((void*)irq); + + return (0); +} + +static int +obio_teardown_intr(device_t dev, device_t child, struct resource *ires, + void *cookie) +{ + struct obio_softc *sc = device_get_softc(dev); + int irq, result, priority; + uint32_t irqmask; + + irq = rman_get_start(ires); + if (irq >= NIRQS) + panic("%s: bad irq %d", __func__, irq); + + if (sc->sc_eventstab[irq] == NULL) + panic("Trying to teardown unoccupied IRQ"); + + irqmask = (1 << irq); + priority = irq_priorities[irq]; + + if (priority == INTR_FIQ) + rt305x_ic_set(IC_INTTYPE, rt305x_ic_get(IC_INTTYPE) & ~irqmask); + else + rt305x_ic_set(IC_INTTYPE, rt305x_ic_get(IC_INTTYPE) | irqmask); + + /* disable */ + obio_mask_irq((void*)irq); + + result = intr_event_remove_handler(cookie); + if (!result) { + sc->sc_eventstab[irq] = NULL; + } + + return (result); +} + +static int +obio_intr(void *arg) +{ + struct obio_softc *sc = arg; + struct intr_event *event; + uint32_t irqstat; + int irq; + + irqstat = rt305x_ic_get(IC_IRQ0STAT); + irqstat |= rt305x_ic_get(IC_IRQ1STAT); + + irq = 0; + while (irqstat != 0) { + if ((irqstat & 1) == 1) { + event = sc->sc_eventstab[irq]; + if (!event || TAILQ_EMPTY(&event->ie_handlers)) + continue; + + /* TODO: pass frame as an argument*/ + /* TODO: log stray interrupt */ + intr_event_handle(event, NULL); + } + irq++; + irqstat >>= 1; + } + + return (FILTER_HANDLED); +} + +static void +obio_add_res_child(device_t bus, const char *dname, int dunit, + long maddr, int msize, int irq) +{ + device_t child; + int result; + + child = BUS_ADD_CHILD(bus, 0, dname, dunit); + + result = bus_set_resource(child, SYS_RES_MEMORY, 0, + maddr, msize); + if (result != 0) + device_printf(bus, "warning: bus_set_resource() failed\n"); + + if (irq != -1) { + result = bus_set_resource(child, SYS_RES_IRQ, 0, irq, 1); + if (result != 0) + device_printf(bus, + "warning: bus_set_resource() failed\n"); + } +} + +static void +obio_hinted_child(device_t bus, const char *dname, int dunit) +{ + long maddr; + int msize; + int irq; + + /* + * Set hard-wired resources for hinted child using + * specific RIDs. + */ + resource_long_value(dname, dunit, "maddr", &maddr); + resource_int_value(dname, dunit, "msize", &msize); + + + if (resource_int_value(dname, dunit, "irq", &irq) == 0) irq = -1; + + obio_add_res_child(bus, dname, dunit, maddr, msize, irq); +} + +static device_t +obio_add_child(device_t bus, u_int order, const char *name, int unit) +{ + device_t child; + struct obio_ivar *ivar; + + ivar = malloc(sizeof(struct obio_ivar), M_DEVBUF, M_WAITOK | M_ZERO); + if (ivar == NULL) { + printf("Failed to allocate ivar\n"); + return (0); + } + resource_list_init(&ivar->resources); + + child = device_add_child_ordered(bus, order, name, unit); + if (child == NULL) { + printf("Can't add child %s%d ordered\n", name, unit); + return (0); + } + + device_set_ivars(child, ivar); + + return (child); +} + +/* + * Helper routine for bus_generic_rl_get_resource/bus_generic_rl_set_resource + * Provides pointer to resource_list for these routines + */ +static struct resource_list * +obio_get_resource_list(device_t dev, device_t child) +{ + struct obio_ivar *ivar; + + ivar = device_get_ivars(child); + return (&(ivar->resources)); +} + +static int +obio_print_all_resources(device_t dev) +{ + struct obio_ivar *ivar = device_get_ivars(dev); + struct resource_list *rl = &ivar->resources; + int retval = 0; + + if (STAILQ_FIRST(rl)) + retval += printf(" at"); + + retval += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#lx"); + retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%ld"); + + return (retval); +} + +static int +obio_print_child(device_t bus, device_t child) +{ + int retval = 0; + + retval += bus_print_child_header(bus, child); + retval += obio_print_all_resources(child); + if (device_get_flags(child)) + retval += printf(" flags %#x", device_get_flags(child)); + retval += printf(" on %s\n", device_get_nameunit(bus)); + + return (retval); +} + +static device_method_t obio_methods[] = { + DEVMETHOD(bus_activate_resource, obio_activate_resource), + DEVMETHOD(bus_add_child, obio_add_child), + DEVMETHOD(bus_alloc_resource, obio_alloc_resource), + DEVMETHOD(bus_deactivate_resource, obio_deactivate_resource), + DEVMETHOD(bus_get_resource_list, obio_get_resource_list), + DEVMETHOD(bus_hinted_child, obio_hinted_child), + DEVMETHOD(bus_print_child, obio_print_child), + DEVMETHOD(bus_release_resource, obio_release_resource), + DEVMETHOD(bus_setup_intr, obio_setup_intr), + DEVMETHOD(bus_teardown_intr, obio_teardown_intr), + DEVMETHOD(device_attach, obio_attach), + DEVMETHOD(device_probe, obio_probe), + DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource), + DEVMETHOD(bus_set_resource, bus_generic_rl_set_resource), + + {0, 0}, +}; + +static driver_t obio_driver = { + "obio", + obio_methods, + sizeof(struct obio_softc), +}; +static devclass_t obio_devclass; + +DRIVER_MODULE(obio, nexus, obio_driver, obio_devclass, 0, 0); diff --git a/sys/mips/rt305x/obiovar.h b/sys/mips/rt305x/obiovar.h new file mode 100644 index 0000000..e1742e8 --- /dev/null +++ b/sys/mips/rt305x/obiovar.h @@ -0,0 +1,58 @@ +/* $NetBSD: obiovar.h,v 1.4 2003/06/16 17:40:53 thorpej Exp $ */ + +/*- + * Copyright (c) 2002, 2003 Wasabi Systems, Inc. + * All rights reserved. + * + * Written by Jason R. Thorpe for Wasabi Systems, Inc. + * + * 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 WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC + * 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. + * + * $FreeBSD$ + * + */ + +#ifndef _RT305X_OBIOVAR_H_ +#define _RT305X_OBIOVAR_H_ + +#include <sys/rman.h> + +/* Number of IRQs */ +#define NIRQS 32 + + +struct obio_softc { + struct rman oba_mem_rman; + struct rman oba_irq_rman; + struct rman oba_gpio_rman; + struct intr_event *sc_eventstab[NIRQS]; /* IRQ events structs */ + struct resource *sc_irq; /* IRQ resource */ + void *sc_ih; /* interrupt cookie */ + struct resource *sc_fast_irq; /* IRQ resource */ + void *sc_fast_ih; /* interrupt cookie */ +}; + +struct obio_ivar { + struct resource_list resources; +}; + +#endif /* _RT305X_OBIOVAR_H_ */ diff --git a/sys/mips/rt305x/rt305x_dotg.c b/sys/mips/rt305x/rt305x_dotg.c new file mode 100644 index 0000000..32ebbfe --- /dev/null +++ b/sys/mips/rt305x/rt305x_dotg.c @@ -0,0 +1,247 @@ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/*- + * Copyright (c) 2010,2011 Aleksandr Rybalko. All rights reserved. + * Copyright (c) 2007-2008 Hans Petter Selasky. 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 <sys/stdint.h> +#include <sys/stddef.h> +#include <sys/param.h> +#include <sys/queue.h> +#include <sys/types.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/bus.h> +#include <sys/module.h> +#include <sys/lock.h> +#include <sys/mutex.h> +#include <sys/condvar.h> +#include <sys/sysctl.h> +#include <sys/sx.h> +#include <sys/unistd.h> +#include <sys/callout.h> +#include <sys/malloc.h> +#include <sys/priv.h> +#include <sys/rman.h> + +#include <dev/usb/usb.h> +#include <dev/usb/usbdi.h> + +#include <dev/usb/usb_core.h> +#include <dev/usb/usb_busdma.h> +#include <dev/usb/usb_process.h> +#include <dev/usb/usb_util.h> + +#include <dev/usb/usb_controller.h> +#include <dev/usb/usb_bus.h> + +#include <dev/usb/controller/dotg.h> +#include <mips/rt305x/rt305xreg.h> +#include <mips/rt305x/rt305x_sysctlvar.h> + +#define MEM_RID 0 + +static device_probe_t dotg_obio_probe; +static device_attach_t dotg_obio_attach; +static device_detach_t dotg_obio_detach; +static device_shutdown_t dotg_obio_shutdown; + +struct dotg_obio_softc { + struct dotg_softc sc_dci; /* must be first */ +}; + +static int +dotg_obio_probe(device_t dev) +{ + device_set_desc(dev, "DWC like USB OTG controller"); + return (0); +} + +static int +dotg_obio_attach(device_t dev) +{ + struct dotg_obio_softc *sc = device_get_softc(dev); + int err; + + /* setup controller interface softc */ + + /* initialise some bus fields */ + sc->sc_dci.sc_dev = dev; + sc->sc_dci.sc_bus.parent = dev; + sc->sc_dci.sc_bus.devices = sc->sc_dci.sc_devices; + sc->sc_dci.sc_bus.devices_max = DOTG_MAX_DEVICES; + + /* get all DMA memory */ + if (usb_bus_mem_alloc_all(&sc->sc_dci.sc_bus, + USB_GET_DMA_TAG(dev), NULL)) { + printf("No mem\n"); + return (ENOMEM); + } + sc->sc_dci.sc_mem_rid = 0; + sc->sc_dci.sc_mem_res = + bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->sc_dci.sc_irq_rid, + RF_ACTIVE); + if (!(sc->sc_dci.sc_mem_res)) { + printf("Can`t alloc MEM\n"); + goto error; + } + sc->sc_dci.sc_bst = rman_get_bustag(sc->sc_dci.sc_mem_res); + sc->sc_dci.sc_bsh = rman_get_bushandle(sc->sc_dci.sc_mem_res); + + sc->sc_dci.sc_irq_rid = 0; + sc->sc_dci.sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, + &sc->sc_dci.sc_irq_rid, RF_SHAREABLE| RF_ACTIVE); + if (!(sc->sc_dci.sc_irq_res)) { + printf("Can`t alloc IRQ\n"); + goto error; + } + + sc->sc_dci.sc_bus.bdev = device_add_child(dev, "usbus", -1); + if (!(sc->sc_dci.sc_bus.bdev)) { + printf("Can`t add usbus\n"); + goto error; + } + device_set_ivars(sc->sc_dci.sc_bus.bdev, &sc->sc_dci.sc_bus); + +#if (__FreeBSD_version >= 700031) + err = bus_setup_intr(dev, sc->sc_dci.sc_irq_res, + INTR_TYPE_BIO | INTR_MPSAFE, NULL, (driver_intr_t *)dotg_interrupt, + sc, &sc->sc_dci.sc_intr_hdl); +#else + err = bus_setup_intr(dev, sc->sc_dci.sc_irq_res, + INTR_TYPE_BIO | INTR_MPSAFE, (driver_intr_t *)dotg_interrupt, + sc, &sc->sc_dci.sc_intr_hdl); +#endif + if (err) { + sc->sc_dci.sc_intr_hdl = NULL; + printf("Can`t set IRQ handle\n"); + goto error; + } + + /* Run clock for OTG core */ + rt305x_sysctl_set(SYSCTL_CLKCFG1, rt305x_sysctl_get(SYSCTL_CLKCFG1) | + SYSCTL_CLKCFG1_OTG_CLK_EN); + rt305x_sysctl_set(SYSCTL_RSTCTRL, SYSCTL_RSTCTRL_OTG); + DELAY(100); + + err = dotg_init(&sc->sc_dci); + if (err) printf("dotg_init fail\n"); + if (!err) { + err = device_probe_and_attach(sc->sc_dci.sc_bus.bdev); + if (err) printf("device_probe_and_attach fail\n"); + } + if (err) { + goto error; + } + return (0); + +error: + dotg_obio_detach(dev); + return (ENXIO); +} + +static int +dotg_obio_detach(device_t dev) +{ + struct dotg_obio_softc *sc = device_get_softc(dev); + device_t bdev; + int err; + + if (sc->sc_dci.sc_bus.bdev) { + bdev = sc->sc_dci.sc_bus.bdev; + device_detach(bdev); + device_delete_child(dev, bdev); + } + /* during module unload there are lots of children leftover */ + device_delete_all_children(dev); + + if (sc->sc_dci.sc_irq_res && sc->sc_dci.sc_intr_hdl) { + /* + * only call dotg_obio_uninit() after dotg_obio_init() + */ + dotg_uninit(&sc->sc_dci); + + /* Stop OTG clock */ + rt305x_sysctl_set(SYSCTL_CLKCFG1, + rt305x_sysctl_get(SYSCTL_CLKCFG1) & + ~SYSCTL_CLKCFG1_OTG_CLK_EN); + + err = bus_teardown_intr(dev, sc->sc_dci.sc_irq_res, + sc->sc_dci.sc_intr_hdl); + sc->sc_dci.sc_intr_hdl = NULL; + } + if (sc->sc_dci.sc_irq_res) { + bus_release_resource(dev, SYS_RES_IRQ, 0, + sc->sc_dci.sc_irq_res); + sc->sc_dci.sc_irq_res = NULL; + } + if (sc->sc_dci.sc_mem_res) { + bus_release_resource(dev, SYS_RES_MEMORY, 0, + sc->sc_dci.sc_mem_res); + sc->sc_dci.sc_mem_res = NULL; + } + usb_bus_mem_free_all(&sc->sc_dci.sc_bus, NULL); + + return (0); +} + +static int +dotg_obio_shutdown(device_t dev) +{ + struct dotg_obio_softc *sc = device_get_softc(dev); + int err; + + err = bus_generic_shutdown(dev); + if (err) + return (err); + + dotg_uninit(&sc->sc_dci); + + return (0); +} + +static device_method_t dotg_obio_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, dotg_obio_probe), + DEVMETHOD(device_attach, dotg_obio_attach), + DEVMETHOD(device_detach, dotg_obio_detach), + DEVMETHOD(device_shutdown, dotg_obio_shutdown), + + /* Bus interface */ + DEVMETHOD(bus_print_child, bus_generic_print_child), + + {0, 0} +}; + +static driver_t dotg_obio_driver = { + "dotg", + dotg_obio_methods, + sizeof(struct dotg_obio_softc), +}; + +static devclass_t dotg_obio_devclass; + +DRIVER_MODULE(dotg, obio, dotg_obio_driver, dotg_obio_devclass, 0, 0); diff --git a/sys/mips/rt305x/rt305x_gpio.c b/sys/mips/rt305x/rt305x_gpio.c new file mode 100644 index 0000000..a570889 --- /dev/null +++ b/sys/mips/rt305x/rt305x_gpio.c @@ -0,0 +1,619 @@ +/*- + * Copyright (c) 2010-2011, Aleksandr Rybalko <ray@ddteam.net> + * Copyright (c) 2009, Oleksandr Tymoshenko <gonzo@FreeBSD.org> + * Copyright (c) 2009, Luiz Otavio O Souza. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * GPIO driver for RT305X SoC. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/bus.h> + +#include <sys/kernel.h> +#include <sys/module.h> +#include <sys/rman.h> +#include <sys/lock.h> +#include <sys/mutex.h> +#include <sys/gpio.h> + +#include <machine/bus.h> +#include <machine/resource.h> +#include <mips/rt305x/rt305xreg.h> +#include <mips/rt305x/rt305x_gpio.h> +#include <mips/rt305x/rt305x_gpiovar.h> +#include <mips/rt305x/rt305x_sysctlvar.h> + +#include "gpio_if.h" + +#ifdef notyet +#define DEFAULT_CAPS (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | GPIO_PIN_INVIN | \ + GPIO_PIN_INVOUT | GPIO_PIN_REPORT ) +#else +#define DEFAULT_CAPS (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | GPIO_PIN_INVIN | \ + GPIO_PIN_INVOUT ) +#endif + +/* + * Helpers + */ +static void rt305x_gpio_pin_configure(struct rt305x_gpio_softc *sc, + struct gpio_pin *pin, uint32_t flags); + +/* + * Driver stuff + */ +static int rt305x_gpio_probe(device_t dev); +static int rt305x_gpio_attach(device_t dev); +static int rt305x_gpio_detach(device_t dev); +static int rt305x_gpio_intr(void *arg); + +int rt305x_get_int_mask (device_t); +void rt305x_set_int_mask (device_t, uint32_t); +int rt305x_get_int_status(device_t); +void rt305x_set_int_status(device_t, uint32_t); + +/* + * GPIO interface + */ +static int rt305x_gpio_pin_max(device_t dev, int *maxpin); +static int rt305x_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps); +static int rt305x_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t + *flags); +static int rt305x_gpio_pin_getname(device_t dev, uint32_t pin, char *name); +static int rt305x_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags); +static int rt305x_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value); +static int rt305x_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val); +static int rt305x_gpio_pin_toggle(device_t dev, uint32_t pin); + +static void +rt305x_gpio_pin_configure(struct rt305x_gpio_softc *sc, struct gpio_pin *pin, + unsigned int flags) +{ + GPIO_LOCK(sc); + + /* + * Manage input/output + */ + if (flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) { + pin->gp_flags &= ~(GPIO_PIN_INPUT|GPIO_PIN_OUTPUT); + if (flags & GPIO_PIN_OUTPUT) { + pin->gp_flags |= GPIO_PIN_OUTPUT; + GPIO_BIT_SET(sc, pin->gp_pin, DIR); + } + else { + pin->gp_flags |= GPIO_PIN_INPUT; + GPIO_BIT_CLR(sc, pin->gp_pin, DIR); + } + } + + if (flags & GPIO_PIN_INVOUT) { + pin->gp_flags |= GPIO_PIN_INVOUT; + GPIO_BIT_SET(sc, pin->gp_pin, POL); + } + else { + pin->gp_flags &= ~GPIO_PIN_INVOUT; + GPIO_BIT_CLR(sc, pin->gp_pin, POL); + } + + if (flags & GPIO_PIN_INVIN) { + pin->gp_flags |= GPIO_PIN_INVIN; + GPIO_BIT_SET(sc, pin->gp_pin, POL); + } + else { + pin->gp_flags &= ~GPIO_PIN_INVIN; + GPIO_BIT_CLR(sc, pin->gp_pin, POL); + } + +#ifdef notyet + /* Enable interrupt bits for rising/falling transitions */ + if (flags & GPIO_PIN_REPORT) { + pin->gp_flags |= GPIO_PIN_REPORT; + GPIO_BIT_SET(sc, pin->gp_pin, RENA); + GPIO_BIT_SET(sc, pin->gp_pin, FENA); + device_printf(sc->dev, "Will report interrupt on pin %d\n", + pin->gp_pin); + + } + else { + pin->gp_flags &= ~GPIO_PIN_REPORT; + GPIO_BIT_CLR(sc, pin->gp_pin, RENA); + GPIO_BIT_CLR(sc, pin->gp_pin, FENA); + } +#else + /* Disable generating interrupts for now */ + GPIO_BIT_CLR(sc, pin->gp_pin, RENA); + GPIO_BIT_CLR(sc, pin->gp_pin, FENA); +#endif + + GPIO_UNLOCK(sc); +} + +static int +rt305x_gpio_pin_max(device_t dev, int *maxpin) +{ + + *maxpin = NGPIO - 1; + return (0); +} + +static int +rt305x_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps) +{ + struct rt305x_gpio_softc *sc = device_get_softc(dev); + int i; + + for (i = 0; i < sc->gpio_npins; i++) { + if (sc->gpio_pins[i].gp_pin == pin) + break; + } + + if (i >= sc->gpio_npins) + return (EINVAL); + + GPIO_LOCK(sc); + *caps = sc->gpio_pins[i].gp_caps; + GPIO_UNLOCK(sc); + + return (0); +} + +static int +rt305x_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags) +{ + struct rt305x_gpio_softc *sc = device_get_softc(dev); + int i; + + for (i = 0; i < sc->gpio_npins; i++) { + if (sc->gpio_pins[i].gp_pin == pin) + break; + } + + if (i >= sc->gpio_npins) + return (EINVAL); + + GPIO_LOCK(sc); + *flags = sc->gpio_pins[i].gp_flags; + GPIO_UNLOCK(sc); + + return (0); +} + +static int +rt305x_gpio_pin_getname(device_t dev, uint32_t pin, char *name) +{ + struct rt305x_gpio_softc *sc = device_get_softc(dev); + int i; + + for (i = 0; i < sc->gpio_npins; i++) { + if (sc->gpio_pins[i].gp_pin == pin) + break; + } + + if (i >= sc->gpio_npins) + return (EINVAL); + + GPIO_LOCK(sc); + memcpy(name, sc->gpio_pins[i].gp_name, GPIOMAXNAME); + GPIO_UNLOCK(sc); + + return (0); +} + +static int +rt305x_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags) +{ + int i; + struct rt305x_gpio_softc *sc = device_get_softc(dev); + + for (i = 0; i < sc->gpio_npins; i++) { + if (sc->gpio_pins[i].gp_pin == pin) + break; + } + + if (i >= sc->gpio_npins) + return (EINVAL); + + /* Filter out unwanted flags */ + if ((flags &= sc->gpio_pins[i].gp_caps) != flags) + return (EINVAL); + + /* Can't mix input/output together */ + if ((flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) == + (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) + return (EINVAL); + + rt305x_gpio_pin_configure(sc, &sc->gpio_pins[i], flags); + + + return (0); +} + +static int +rt305x_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value) +{ + struct rt305x_gpio_softc *sc = device_get_softc(dev); + int i; + + for (i = 0; i < sc->gpio_npins; i++) { + if (sc->gpio_pins[i].gp_pin == pin) + break; + } + + if (i >= sc->gpio_npins) + return (EINVAL); + + + GPIO_LOCK(sc); + if (value) GPIO_BIT_SET(sc, i, DATA); + else GPIO_BIT_CLR(sc, i, DATA); + GPIO_UNLOCK(sc); + + return (0); +} + +static int +rt305x_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val) +{ + struct rt305x_gpio_softc *sc = device_get_softc(dev); + int i; + + for (i = 0; i < sc->gpio_npins; i++) { + if (sc->gpio_pins[i].gp_pin == pin) + break; + } + + if (i >= sc->gpio_npins) + return (EINVAL); + + GPIO_LOCK(sc); + *val = GPIO_BIT_GET(sc, i, DATA); + GPIO_UNLOCK(sc); + + return (0); +} + +static int +rt305x_gpio_pin_toggle(device_t dev, uint32_t pin) +{ + int i; + struct rt305x_gpio_softc *sc = device_get_softc(dev); + + for (i = 0; i < sc->gpio_npins; i++) { + if (sc->gpio_pins[i].gp_pin == pin) + break; + } + + if (i >= sc->gpio_npins) + return (EINVAL); + + GPIO_LOCK(sc); + GPIO_BIT_SET(sc, i, TOG); + GPIO_UNLOCK(sc); + + return (0); +} + +static int +rt305x_gpio_intr(void *arg) +{ + struct rt305x_gpio_softc *sc = arg; +#ifdef notyet + uint32_t i; +#endif + uint64_t input, value; +#ifdef notyet + uint64_t reset_pin; + char notify[16]; + char pinname[6]; +#endif + + /* Read all reported pins */ + input = GPIO_READ_ALL(sc, INT); + /* Clear int status */ + GPIO_WRITE_ALL(sc, INT, input); + /* Clear report for OUTs */ + input &= ~GPIO_READ_ALL(sc, DIR); + value = input & GPIO_READ_ALL(sc, DATA); + + if (!input) goto intr_done; + +#ifdef notyet + /* if reset_gpio and this pin is input */ + if (sc->reset_gpio >= 0 && (input & (1 << sc->reset_gpio))) { + /* get reset_gpio pin value */ + reset_pin = (value & (1 << sc->reset_gpio))?1:0; + if ( sc->reset_gpio_last != reset_pin ) { + /* + * if now reset is high, check how long + * and do reset if less than 2 seconds + */ + if ( reset_pin && + (time_uptime - sc->reset_gpio_ontime) < 2 ) + shutdown_nice(0); + + sc->reset_gpio_last = reset_pin; + sc->reset_gpio_ontime = time_uptime; + } + } + + for ( i = 0; i < NGPIO; i ++ ) + { + /* Next if output pin */ + if ( !(( input >> i) & 1) ) continue; + + if ( (((value & input) >> i) & 1) != sc->gpio_pins[i].gp_last ) + { + /* !system=GPIO subsystem=pin7 type=PIN_HIGH period=3 */ + snprintf(notify , sizeof(notify ), "period=%d", + (uint32_t)time_uptime - sc->gpio_pins[i].gp_time); + snprintf(pinname, sizeof(pinname), "pin%02d", i); + devctl_notify("GPIO", pinname, + (((value & input) >> i) & 1)?"PIN_HIGH":"PIN_LOW", + notify); + printf("GPIO[%s] %s %s\n", pinname, + (((value & input) >> i) & 1)?"PIN_HIGH":"PIN_LOW", + notify); + sc->gpio_pins[i].gp_last = ((value & input) >> i) & 1; + sc->gpio_pins[i].gp_time = time_uptime; + } + + } +#endif + +intr_done: + return (FILTER_HANDLED); +} + +static int +rt305x_gpio_probe(device_t dev) +{ + device_set_desc(dev, "RT305X GPIO driver"); + return (0); +} + +static uint64_t +rt305x_gpio_init(device_t dev) +{ + uint64_t avl = ~0ULL; + uint32_t gmode = rt305x_sysctl_get(SYSCTL_GPIOMODE); + if (!(gmode & SYSCTL_GPIOMODE_RGMII_GPIO_MODE)) + avl &= ~RGMII_GPIO_MODE_MASK; + if (!(gmode & SYSCTL_GPIOMODE_SDRAM_GPIO_MODE)) + avl &= ~SDRAM_GPIO_MODE_MASK; + if (!(gmode & SYSCTL_GPIOMODE_MDIO_GPIO_MODE)) + avl &= ~MDIO_GPIO_MODE_MASK; + if (!(gmode & SYSCTL_GPIOMODE_JTAG_GPIO_MODE)) + avl &= ~JTAG_GPIO_MODE_MASK; + if (!(gmode & SYSCTL_GPIOMODE_UARTL_GPIO_MODE)) + avl &= ~UARTL_GPIO_MODE_MASK; + if (!(gmode & SYSCTL_GPIOMODE_SPI_GPIO_MODE)) + avl &= ~SPI_GPIO_MODE_MASK; + if (!(gmode & SYSCTL_GPIOMODE_I2C_GPIO_MODE)) + avl &= ~I2C_GPIO_MODE_MASK; + if ((gmode & SYSCTL_GPIOMODE_UARTF_SHARE_MODE_GPIO) != + SYSCTL_GPIOMODE_UARTF_SHARE_MODE_GPIO) + avl &= ~I2C_GPIO_MODE_MASK; +/* D-Link DAP-1350 Board have + * MDIO_GPIO_MODE + * UARTF_GPIO_MODE + * SPI_GPIO_MODE + * I2C_GPIO_MODE + * So we have + * 00000001 10000000 01111111 11111110 +*/ + return (avl); + +} + +#define DAP1350_RESET_GPIO 10 + +static int +rt305x_gpio_attach(device_t dev) +{ + struct rt305x_gpio_softc *sc = device_get_softc(dev); + int error = 0, i; + uint64_t avlpins = 0; + sc->reset_gpio = DAP1350_RESET_GPIO; + + KASSERT((device_get_unit(dev) == 0), + ("rt305x_gpio_gpio: Only one gpio module supported")); + + mtx_init(&sc->gpio_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, + MTX_DEF); + + /* Map control/status registers. */ + sc->gpio_mem_rid = 0; + sc->gpio_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, + &sc->gpio_mem_rid, RF_ACTIVE); + + if (sc->gpio_mem_res == NULL) { + device_printf(dev, "couldn't map memory\n"); + error = ENXIO; + rt305x_gpio_detach(dev); + return(error); + } + + if ((sc->gpio_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, + &sc->gpio_irq_rid, RF_SHAREABLE | RF_ACTIVE)) == NULL) { + device_printf(dev, "unable to allocate IRQ resource\n"); + return (ENXIO); + } + + if ((bus_setup_intr(dev, sc->gpio_irq_res, INTR_TYPE_MISC, + /* rt305x_gpio_filter, */ + rt305x_gpio_intr, NULL, sc, &sc->gpio_ih))) { + device_printf(dev, + "WARNING: unable to register interrupt handler\n"); + return (ENXIO); + } + + sc->dev = dev; + avlpins = rt305x_gpio_init(dev); + + /* Configure all pins as input */ + /* disable interrupts for all pins */ + /* TODO */ + + sc->gpio_npins = NGPIO; + resource_int_value(device_get_name(dev), device_get_unit(dev), + "pins", &sc->gpio_npins); + + for (i = 0; i < sc->gpio_npins; i++) { + sc->gpio_pins[i].gp_pin = i; + sc->gpio_pins[i].gp_caps = DEFAULT_CAPS; + sc->gpio_pins[i].gp_flags = 0; + } + + /* Setup reset pin interrupt */ + if (TUNABLE_INT_FETCH("reset_gpio", &sc->reset_gpio)) { + device_printf(dev, "\tHinted reset_gpio %d\n", sc->reset_gpio); + } +#ifdef notyet + if (sc->reset_gpio != -1) { + rt305x_gpio_pin_setflags(dev, sc->reset_gpio, + GPIO_PIN_INPUT|GPIO_PIN_INVOUT| + GPIO_PIN_INVOUT|GPIO_PIN_REPORT); + device_printf(dev, "\tUse reset_gpio %d\n", sc->reset_gpio); + } +#else + if (sc->reset_gpio != -1) { + rt305x_gpio_pin_setflags(dev, sc->reset_gpio, + GPIO_PIN_INPUT|GPIO_PIN_INVOUT); + device_printf(dev, "\tUse reset_gpio %d\n", sc->reset_gpio); + } +#endif + + device_add_child(dev, "gpioc", device_get_unit(dev)); + device_add_child(dev, "gpiobus", device_get_unit(dev)); + + + return (bus_generic_attach(dev)); +} + +static int +rt305x_gpio_detach(device_t dev) +{ + struct rt305x_gpio_softc *sc = device_get_softc(dev); + + KASSERT(mtx_initialized(&sc->gpio_mtx), ("gpio mutex not initialized")); + + bus_generic_detach(dev); + + if (sc->gpio_mem_res) + bus_release_resource(dev, SYS_RES_MEMORY, sc->gpio_mem_rid, + sc->gpio_mem_res); + + mtx_destroy(&sc->gpio_mtx); + + return(0); +} + +#ifdef notyet +static struct resource * +rt305x_gpio_alloc_resource(device_t bus, device_t child, int type, int *rid, + u_long start, u_long end, u_long count, u_int flags) +{ + struct obio_softc *sc = device_get_softc(bus); + struct resource *rv; + struct rman *rm; + + switch (type) { + case SYS_RES_GPIO: + rm = &sc->gpio_rman; + break; + default: + printf("%s: unknown resource type %d\n", __func__, type); + return (0); + } + + rv = rman_reserve_resource(rm, start, end, count, flags, child); + if (rv == 0) { + printf("%s: could not reserve resource\n", __func__); + return (0); + } + + rman_set_rid(rv, *rid); + + return (rv); +} + +static int +rt305x_gpio_activate_resource(device_t bus, device_t child, int type, int rid, + struct resource *r) +{ + + return (rman_activate_resource(r)); +} + +static int +rt305x_gpio_deactivate_resource(device_t bus, device_t child, int type, int rid, + struct resource *r) +{ + + return (rman_deactivate_resource(r)); +} + +static int +rt305x_gpio_release_resource(device_t dev, device_t child, int type, + int rid, struct resource *r) +{ + rman_release_resource(r); + return (0); +} +#endif + +static device_method_t rt305x_gpio_methods[] = { + DEVMETHOD(device_probe, rt305x_gpio_probe), + DEVMETHOD(device_attach, rt305x_gpio_attach), + DEVMETHOD(device_detach, rt305x_gpio_detach), + + /* GPIO protocol */ + DEVMETHOD(gpio_pin_max, rt305x_gpio_pin_max), + DEVMETHOD(gpio_pin_getname, rt305x_gpio_pin_getname), + DEVMETHOD(gpio_pin_getflags, rt305x_gpio_pin_getflags), + DEVMETHOD(gpio_pin_getcaps, rt305x_gpio_pin_getcaps), + DEVMETHOD(gpio_pin_setflags, rt305x_gpio_pin_setflags), + DEVMETHOD(gpio_pin_get, rt305x_gpio_pin_get), + DEVMETHOD(gpio_pin_set, rt305x_gpio_pin_set), + DEVMETHOD(gpio_pin_toggle, rt305x_gpio_pin_toggle), + {0, 0}, +}; + +static driver_t rt305x_gpio_driver = { + "gpio", + rt305x_gpio_methods, + sizeof(struct rt305x_gpio_softc), +}; +static devclass_t rt305x_gpio_devclass; + +DRIVER_MODULE(rt305x_gpio, obio, rt305x_gpio_driver, + rt305x_gpio_devclass, 0, 0); diff --git a/sys/mips/rt305x/rt305x_gpio.h b/sys/mips/rt305x/rt305x_gpio.h new file mode 100644 index 0000000..8ce3ab5 --- /dev/null +++ b/sys/mips/rt305x/rt305x_gpio.h @@ -0,0 +1,111 @@ +/*- + * Copyright (c) 2010 Aleksandr Rybalko. + * 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. + * + * $FreeBSD$ + */ +#ifndef _RT305X_GPIO_H_ +#define _RT305X_GPIO_H_ + +#define NGPIO 52 + +#define RGMII_GPIO_MODE_MASK (0x0fffULL<<40) +#define SDRAM_GPIO_MODE_MASK (0xffffULL<<24) +#define MDIO_GPIO_MODE_MASK (0x0003ULL<<22) +#define JTAG_GPIO_MODE_MASK (0x001fULL<<17) +#define UARTL_GPIO_MODE_MASK (0x0003ULL<<15) +#define UARTF_GPIO_MODE_MASK (0x00ffULL<<7) +#define SPI_GPIO_MODE_MASK (0x000fULL<<3) +#define I2C_GPIO_MODE_MASK (0x0003ULL<<1) + +#define GPIO23_00_INT 0x00 /* Programmed I/O Int Status */ +#define GPIO23_00_EDGE 0x04 /* Programmed I/O Edge Status */ +#define GPIO23_00_RENA 0x08 /* Programmed I/O Int on Rising */ +#define GPIO23_00_FENA 0x0C /* Programmed I/O Int on Falling */ +#define GPIO23_00_DATA 0x20 /* Programmed I/O Data */ +#define GPIO23_00_DIR 0x24 /* Programmed I/O Direction */ +#define GPIO23_00_POL 0x28 /* Programmed I/O Pin Polarity */ +#define GPIO23_00_SET 0x2C /* Set PIO Data Bit */ +#define GPIO23_00_RESET 0x30 /* Clear PIO Data bit */ +#define GPIO23_00_TOG 0x34 /* Toggle PIO Data bit */ + +#define GPIO39_24_INT 0x38 +#define GPIO39_24_EDGE 0x3c +#define GPIO39_24_RENA 0x40 +#define GPIO39_24_FENA 0x44 +#define GPIO39_24_DATA 0x48 +#define GPIO39_24_DIR 0x4c +#define GPIO39_24_POL 0x50 +#define GPIO39_24_SET 0x54 +#define GPIO39_24_RESET 0x58 +#define GPIO39_24_TOG 0x5c + +#define GPIO51_40_INT 0x60 +#define GPIO51_40_EDGE 0x64 +#define GPIO51_40_RENA 0x68 +#define GPIO51_40_FENA 0x6C +#define GPIO51_40_DATA 0x70 +#define GPIO51_40_DIR 0x74 +#define GPIO51_40_POL 0x78 +#define GPIO51_40_SET 0x7C +#define GPIO51_40_RESET 0x80 +#define GPIO51_40_TOG 0x84 + +#define GPIO_REG(g, n) \ + ((g<24)?(GPIO23_00_##n):(g<40)?(GPIO39_24_##n):(GPIO51_40_##n)) +#define GPIO_MASK(g) \ + ((g<24)?(1<<g):(g<40)?(1<<(g-24)):(1<<(g-40))) +#define GPIO_BIT_SHIFT(g) ((g<24)?(g):(g<40)?(g-24):(g-40)) + +#define GPIO_READ(r, g, n) \ + bus_read_4(r->gpio_mem_res, GPIO_REG(g, n)) +#define GPIO_WRITE(r, g, n, v) \ + bus_write_4(r->gpio_mem_res, GPIO_REG(g, n), v) +#define GPIO_READ_ALL(r, n) \ + (((uint64_t)bus_read_4(r->gpio_mem_res, GPIO23_00_##n)) | \ + (((uint64_t)bus_read_4(r->gpio_mem_res, GPIO39_24_##n)) << 24) |\ + (((uint64_t)bus_read_4(r->gpio_mem_res, GPIO51_40_##n)) << 40)) +#define GPIO_WRITE_ALL(r, n, v) \ + {bus_write_4(r->gpio_mem_res,GPIO23_00_##n, v &0x00ffffff);\ + bus_write_4(r->gpio_mem_res, GPIO39_24_##n, (v>>24)&0x0000ffff);\ + bus_write_4(r->gpio_mem_res, GPIO51_40_##n, (v>>40)&0x00000fff);} + + +#define GPIO_BIT_CLR(r, g, n) \ + bus_write_4(r->gpio_mem_res, GPIO_REG(g, n), \ + bus_read_4(r->gpio_mem_res, GPIO_REG(g, n)) & ~GPIO_MASK(g)) +#define GPIO_BIT_SET(r, g, n) \ + bus_write_4(r->gpio_mem_res, GPIO_REG(g, n), \ + bus_read_4(r->gpio_mem_res, GPIO_REG(g, n)) | GPIO_MASK(g)) + +#define GPIO_BIT_GET(r, g, n) \ + ((bus_read_4(r->gpio_mem_res, GPIO_REG(g, n)) >> \ + GPIO_BIT_SHIFT(g)) & 1) + +#define GPIO_LOCK(_sc) mtx_lock(&(_sc)->gpio_mtx) +#define GPIO_UNLOCK(_sc) mtx_unlock(&(_sc)->gpio_mtx) +#define GPIO_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->gpio_mtx, MA_OWNED) + +#endif /* _RT305X_GPIO_H_ */ + diff --git a/sys/mips/rt305x/rt305x_gpiovar.h b/sys/mips/rt305x/rt305x_gpiovar.h new file mode 100644 index 0000000..ed79e2d --- /dev/null +++ b/sys/mips/rt305x/rt305x_gpiovar.h @@ -0,0 +1,48 @@ +/*- + * Copyright (c) 2010 Aleksandr Rybalko. + * 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. + * + * $FreeBSD$ + */ +#ifndef _RT305X_GPIOVAR_H_ +#define _RT305X_GPIOVAR_H_ + +struct rt305x_gpio_softc { + device_t dev; + struct mtx gpio_mtx; + struct resource *gpio_mem_res; + int gpio_mem_rid; + struct resource *gpio_irq_res; + int gpio_irq_rid; + void *gpio_ih; + int gpio_npins; + struct gpio_pin gpio_pins[NGPIO]; + int reset_gpio; + int reset_gpio_last; + time_t reset_gpio_ontime; +}; + +#endif /* _RT305X_GPIOVAR_H_ */ + + diff --git a/sys/mips/rt305x/rt305x_ic.c b/sys/mips/rt305x/rt305x_ic.c new file mode 100644 index 0000000..8bddd41 --- /dev/null +++ b/sys/mips/rt305x/rt305x_ic.c @@ -0,0 +1,141 @@ +/*- + * Copyright (c) 2010 Aleksandr Rybalko. + * 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 <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/bus.h> +#include <sys/interrupt.h> +#include <sys/kernel.h> +#include <sys/module.h> +#include <sys/rman.h> +#include <sys/malloc.h> + +#include <machine/bus.h> + +#include <mips/rt305x/rt305xreg.h> +#include <mips/rt305x/rt305x_icvar.h> + + +static int rt305x_ic_probe(device_t); +static int rt305x_ic_attach(device_t); +static int rt305x_ic_detach(device_t); + + +static struct rt305x_ic_softc *rt305x_ic_softc = NULL; + +static int +rt305x_ic_probe(device_t dev) +{ + device_set_desc(dev, "RT305X Interrupt Controller driver"); + return (0); +} + +static int +rt305x_ic_attach(device_t dev) +{ + struct rt305x_ic_softc *sc = device_get_softc(dev); + int error = 0; + + KASSERT((device_get_unit(dev) == 0), + ("rt305x_ic: Only one Interrupt Controller module supported")); + + if (rt305x_ic_softc != NULL) + return (ENXIO); + rt305x_ic_softc = sc; + + + /* Map control/status registers. */ + sc->mem_rid = 0; + sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, + &sc->mem_rid, RF_ACTIVE); + + if (sc->mem_res == NULL) { + device_printf(dev, "couldn't map memory\n"); + error = ENXIO; + rt305x_ic_detach(dev); + return(error); + } + return (bus_generic_attach(dev)); +} + +static int +rt305x_ic_detach(device_t dev) +{ + struct rt305x_ic_softc *sc = device_get_softc(dev); + + bus_generic_detach(dev); + + if (sc->mem_res) + bus_release_resource(dev, SYS_RES_MEMORY, sc->mem_rid, + sc->mem_res); + return(0); +} + + +uint32_t +rt305x_ic_get(uint32_t reg) +{ + struct rt305x_ic_softc *sc = rt305x_ic_softc; + + if (!sc) + return (0); + + return (bus_read_4(sc->mem_res, reg)); +} + +void +rt305x_ic_set(uint32_t reg, uint32_t val) +{ + struct rt305x_ic_softc *sc = rt305x_ic_softc; + + if (!sc) + return; + + bus_write_4(sc->mem_res, reg, val); + + return; +} + + +static device_method_t rt305x_ic_methods[] = { + DEVMETHOD(device_probe, rt305x_ic_probe), + DEVMETHOD(device_attach, rt305x_ic_attach), + DEVMETHOD(device_detach, rt305x_ic_detach), + + {0, 0}, +}; + +static driver_t rt305x_ic_driver = { + "rt305x_ic", + rt305x_ic_methods, + sizeof(struct rt305x_ic_softc), +}; +static devclass_t rt305x_ic_devclass; + +DRIVER_MODULE(rt305x_ic, obio, rt305x_ic_driver, rt305x_ic_devclass, 0, 0); diff --git a/sys/mips/rt305x/rt305x_icvar.h b/sys/mips/rt305x/rt305x_icvar.h new file mode 100644 index 0000000..4d969c8 --- /dev/null +++ b/sys/mips/rt305x/rt305x_icvar.h @@ -0,0 +1,42 @@ +/*- + * Copyright (c) 2010 Aleksandr Rybalko. + * 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. + * + * $FreeBSD$ + */ +#ifndef _RT305X_ICVAR_H_ +#define _RT305X_ICVAR_H_ + +struct rt305x_ic_softc { + device_t dev; + struct resource *mem_res; + int mem_rid; +}; + + +uint32_t rt305x_ic_get(uint32_t); +void rt305x_ic_set(uint32_t, uint32_t); + +#endif /* _RT305X_ICVAR_H_ */ + diff --git a/sys/mips/rt305x/rt305x_machdep.c b/sys/mips/rt305x/rt305x_machdep.c new file mode 100644 index 0000000..a388b4f --- /dev/null +++ b/sys/mips/rt305x/rt305x_machdep.c @@ -0,0 +1,217 @@ +/*- + * Copyright (C) 2010-2011 by Aleksandr Rybalko. All rights reserved. + * Copyright (C) 2007 by Oleksandr Tymoshenko. 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 OR HIS RELATIVES 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 MIND, 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> +__FBSDID("$FreeBSD$"); + +#include "opt_ddb.h" + +#include <sys/param.h> +#include <sys/conf.h> +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/imgact.h> +#include <sys/bio.h> +#include <sys/buf.h> +#include <sys/bus.h> +#include <sys/cpu.h> +#include <sys/cons.h> +#include <sys/exec.h> +#include <sys/ucontext.h> +#include <sys/proc.h> +#include <sys/kdb.h> +#include <sys/ptrace.h> +#include <sys/reboot.h> +#include <sys/signalvar.h> +#include <sys/sysent.h> +#include <sys/sysproto.h> +#include <sys/user.h> + +#include <vm/vm.h> +#include <vm/vm_object.h> +#include <vm/vm_page.h> +#include <vm/vm_pager.h> + +#include <machine/cache.h> +#include <machine/clock.h> +#include <machine/cpu.h> +#include <machine/cpuinfo.h> +#include <machine/cpufunc.h> +#include <machine/cpuregs.h> +#include <machine/hwfunc.h> +#include <machine/intr_machdep.h> +#include <machine/locore.h> +#include <machine/md_var.h> +#include <machine/pte.h> +#include <machine/sigframe.h> +#include <machine/trap.h> +#include <machine/vmparam.h> + +#include <mips/rt305x/rt305xreg.h> + +extern int *edata; +extern int *end; +static char boot1_env[0x1000]; + + +void +platform_cpu_init() +{ + /* Nothing special */ +} + +static void +mips_init(void) +{ + int i; + + printf("entry: mips_init()\n"); + + bootverbose = 1; + realmem = btoc(32 << 20); + + for (i = 0; i < 10; i++) { + phys_avail[i] = 0; + } + + /* phys_avail regions are in bytes */ + dump_avail[0] = phys_avail[0] = MIPS_KSEG0_TO_PHYS(kernel_kseg0_end); + dump_avail[1] = phys_avail[1] = ctob(realmem); + + physmem = realmem; + + init_param1(); + init_param2(physmem); + mips_cpu_init(); + pmap_bootstrap(); + mips_proc0_init(); + mutex_init(); + kdb_init(); +#ifdef KDB + if (boothowto & RB_KDB) + kdb_enter(KDB_WHY_BOOTFLAGS, "Boot flags requested debugger"); +#endif +} + +void +platform_halt(void) +{ + +} + + +void +platform_identify(void) +{ + +} + +void +platform_reset(void) +{ + + __asm __volatile("li $25, 0xbf000000"); + __asm __volatile("j $25"); +} + +void +platform_trap_enter(void) +{ + +} + +void +platform_trap_exit(void) +{ + +} + +void +platform_start(__register_t a0 __unused, __register_t a1 __unused, + __register_t a2 __unused, __register_t a3 __unused) +{ + vm_offset_t kernend; + uint64_t platform_counter_freq = PLATFORM_COUNTER_FREQ; + int i; + int argc = a0; + char **argv = (char **)MIPS_PHYS_TO_KSEG0(a1); + char **envp = (char **)MIPS_PHYS_TO_KSEG0(a2); + + /* clear the BSS and SBSS segments */ + kernend = (vm_offset_t)&end; + memset(&edata, 0, kernend - (vm_offset_t)(&edata)); + + mips_postboot_fixup(); + + /* Initialize pcpu stuff */ + mips_pcpu0_init(); + + /* initialize console so that we have printf */ + boothowto |= (RB_SERIAL | RB_MULTIPLE); /* Use multiple consoles */ + boothowto |= (RB_VERBOSE); + cninit(); + + init_static_kenv(boot1_env, sizeof(boot1_env)); + + printf("U-Boot args (from %d args):\n", argc - 1); + + if (argc == 1) + printf("\tNone\n"); + + for (i = 1; i < argc; i++) { + char *n = "argv ", *arg; + + if (i > 99) + break; + + if (argv[i]) + { + arg = (char *)(intptr_t)MIPS_PHYS_TO_KSEG0(argv[i]); + printf("\targv[%d] = %s\n", i, arg); + sprintf(n, "argv%d", i); + setenv(n, arg); + } + } + + printf("Environment:\n"); + + for (i = 0; envp[i] ; i++) { + char *n, *arg; + + arg = (char *)(intptr_t)MIPS_PHYS_TO_KSEG0(envp[i]); + printf("\t%s\n", arg); + n = strsep(&arg, "="); + if (arg == NULL) + setenv(n, "1"); + else + setenv(n, arg); + } + + + mips_init(); + mips_timer_init_params(platform_counter_freq, 2); +} diff --git a/sys/mips/rt305x/rt305x_sysctl.c b/sys/mips/rt305x/rt305x_sysctl.c new file mode 100644 index 0000000..7a3b0c2 --- /dev/null +++ b/sys/mips/rt305x/rt305x_sysctl.c @@ -0,0 +1,240 @@ +/*- + * Copyright (c) 2010 Aleksandr Rybalko. + * 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 <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/bus.h> +#include <sys/interrupt.h> +#include <sys/kernel.h> +#include <sys/module.h> +#include <sys/rman.h> +#include <sys/malloc.h> + +#include <machine/bus.h> + +#include <mips/rt305x/rt305xreg.h> +#include <mips/rt305x/rt305x_sysctlvar.h> + + +static int rt305x_sysctl_probe(device_t); +static int rt305x_sysctl_attach(device_t); +static int rt305x_sysctl_detach(device_t); + + +static struct rt305x_sysctl_softc *rt305x_sysctl_softc = NULL; + +static void +rt305x_sysctl_dump_config(device_t dev) +{ + uint32_t val; +#define DUMPREG(r) \ + val = rt305x_sysctl_get(r); printf(" " #r "=%#08x\n", val) + + val = rt305x_sysctl_get(SYSCTL_CHIPID0_3); + printf("\tChip ID: \"%c%c%c%c", + (val >> 0 ) & 0xff, + (val >> 8 ) & 0xff, + (val >> 16) & 0xff, + (val >> 24) & 0xff); + val = rt305x_sysctl_get(SYSCTL_CHIPID4_7); + printf("%c%c%c%c\"\n", + (val >> 0 ) & 0xff, + (val >> 8 ) & 0xff, + (val >> 16) & 0xff, + (val >> 24) & 0xff); + + DUMPREG(SYSCTL_SYSCFG); + if ( val & SYSCTL_SYSCFG_INIC_EE_SDRAM) + printf("\tGet SDRAM config from EEPROM\n"); + if ( val & SYSCTL_SYSCFG_INIC_8MB_SDRAM) + printf("\tBootstrap flag is set\n"); + printf("\tGE0 mode %u\n", + ((val & SYSCTL_SYSCFG_GE0_MODE_MASK) >> + SYSCTL_SYSCFG_GE0_MODE_SHIFT)); + if ( val & SYSCTL_SYSCFG_BOOT_ADDR_1F00) + printf("\tBoot from 0x1f000000\n"); + if ( val & SYSCTL_SYSCFG_BYPASS_PLL) + printf("\tBypass PLL\n"); + if ( val & SYSCTL_SYSCFG_BIG_ENDIAN) + printf("\tBig Endian\n"); + if ( val & SYSCTL_SYSCFG_CPU_CLK_SEL_384MHZ) + printf("\tClock is 384Mhz\n"); + printf("\tBoot from %u\n", + ((val & SYSCTL_SYSCFG_BOOT_FROM_MASK) >> + SYSCTL_SYSCFG_BOOT_FROM_SHIFT)); + printf("\tBootstrap test code %u\n", + ((val & SYSCTL_SYSCFG_TEST_CODE_MASK) >> + SYSCTL_SYSCFG_TEST_CODE_SHIFT)); + printf("\tSRAM_CS mode %u\n", + ((val & SYSCTL_SYSCFG_SRAM_CS_MODE_MASK) >> + SYSCTL_SYSCFG_SRAM_CS_MODE_SHIFT)); + printf("\t%umA SDRAM_CLK driving\n", + (val & SYSCTL_SYSCFG_SDRAM_CLK_DRV)?12:8); + + DUMPREG(SYSCTL_CLKCFG0); + printf("\tSDRAM_CLK_SKEW %uns\n", (val >> 30) & 0x03); + + DUMPREG(SYSCTL_CLKCFG1); + if ( val & SYSCTL_CLKCFG1_PBUS_DIV_CLK_BY2) + printf("\tPbus clock is 1/2 of System clock\n"); + if ( val & SYSCTL_CLKCFG1_OTG_CLK_EN) + printf("\tUSB OTG clock is enabled\n"); + if ( val & SYSCTL_CLKCFG1_I2S_CLK_EN) + printf("\tI2S clock is enabled\n"); + printf("\tI2S clock is %s\n", + (val & SYSCTL_CLKCFG1_I2S_CLK_SEL_EXT)? + "external":"internal 15.625Mhz"); + printf("\tI2S clock divider %u\n", + ((val & SYSCTL_CLKCFG1_I2S_CLK_DIV_MASK) >> + SYSCTL_CLKCFG1_I2S_CLK_DIV_SHIFT)); + if ( val & SYSCTL_CLKCFG1_PCM_CLK_EN) + printf("\tPCM clock is enabled\n"); + + printf("\tPCM clock is %s\n", + (val & SYSCTL_CLKCFG1_PCM_CLK_SEL_EXT)? + "external":"internal 15.625Mhz"); + printf("\tPCM clock divider %u\n", + ((val & SYSCTL_CLKCFG1_PCM_CLK_DIV_MASK) >> + SYSCTL_CLKCFG1_PCM_CLK_DIV_SHIFT)); + DUMPREG(SYSCTL_GPIOMODE); +#undef DUMPREG + + return; +} + +static int +rt305x_sysctl_probe(device_t dev) +{ + device_set_desc(dev, "RT305X System Control driver"); + return (0); +} + +static int +rt305x_sysctl_attach(device_t dev) +{ + struct rt305x_sysctl_softc *sc = device_get_softc(dev); + int error = 0; + + KASSERT((device_get_unit(dev) == 0), + ("rt305x_sysctl: Only one sysctl module supported")); + + if (rt305x_sysctl_softc != NULL) + return (ENXIO); + rt305x_sysctl_softc = sc; + + + /* Map control/status registers. */ + sc->mem_rid = 0; + sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, + &sc->mem_rid, RF_ACTIVE); + + if (sc->mem_res == NULL) { + device_printf(dev, "couldn't map memory\n"); + error = ENXIO; + rt305x_sysctl_detach(dev); + return(error); + } +#ifdef notyet + sc->irq_rid = 0; + if ((sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, + &sc->irq_rid, RF_SHAREABLE | RF_ACTIVE)) == NULL) { + device_printf(dev, "unable to allocate IRQ resource\n"); + return (ENXIO); + } + + if ((bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC, + rt305x_sysctl_intr, NULL, sc, &sc->sysctl_ih))) { + device_printf(dev, + "WARNING: unable to register interrupt handler\n"); + return (ENXIO); + } +#endif + rt305x_sysctl_dump_config(dev); + + return (bus_generic_attach(dev)); +} + +static int +rt305x_sysctl_detach(device_t dev) +{ + struct rt305x_sysctl_softc *sc = device_get_softc(dev); + + bus_generic_detach(dev); + + if (sc->mem_res) + bus_release_resource(dev, SYS_RES_MEMORY, sc->mem_rid, + sc->mem_res); +#ifdef notyet + if (sc->irq_res) + bus_release_resource(dev, SYS_RES_IRQ, sc->irq_rid, + sc->irq_res); +#endif + return(0); +} + +#ifdef notyet +static int +rt305x_sysctl_intr(void *arg) +{ + return (FILTER_HANDLED); +} +#endif + +uint32_t +rt305x_sysctl_get(uint32_t reg) +{ + struct rt305x_sysctl_softc *sc = rt305x_sysctl_softc; + return (bus_read_4(sc->mem_res, reg)); +} + +void +rt305x_sysctl_set(uint32_t reg, uint32_t val) +{ + struct rt305x_sysctl_softc *sc = rt305x_sysctl_softc; + bus_write_4(sc->mem_res, reg, val); + return; +} + + +static device_method_t rt305x_sysctl_methods[] = { + DEVMETHOD(device_probe, rt305x_sysctl_probe), + DEVMETHOD(device_attach, rt305x_sysctl_attach), + DEVMETHOD(device_detach, rt305x_sysctl_detach), + + {0, 0}, +}; + +static driver_t rt305x_sysctl_driver = { + "rt305x_sysctl", + rt305x_sysctl_methods, + sizeof(struct rt305x_sysctl_softc), +}; +static devclass_t rt305x_sysctl_devclass; + +DRIVER_MODULE(rt305x_sysctl, obio, rt305x_sysctl_driver, rt305x_sysctl_devclass, 0, 0); diff --git a/sys/mips/rt305x/rt305x_sysctlvar.h b/sys/mips/rt305x/rt305x_sysctlvar.h new file mode 100644 index 0000000..91a5282 --- /dev/null +++ b/sys/mips/rt305x/rt305x_sysctlvar.h @@ -0,0 +1,45 @@ +/*- + * Copyright (c) 2010 Aleksandr Rybalko. + * 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. + * + * $FreeBSD$ + */ +#ifndef _RT305X_SYSCTLVAR_H_ +#define _RT305X_SYSCTLVAR_H_ + +struct rt305x_sysctl_softc { + device_t dev; + struct resource *mem_res; + int mem_rid; + struct resource *irq_res; + int irq_rid; + int sysctl_ih; +}; + + +uint32_t rt305x_sysctl_get(uint32_t); +void rt305x_sysctl_set(uint32_t, uint32_t); + +#endif /* _RT305X_SYSCTLVAR_H_ */ + diff --git a/sys/mips/rt305x/rt305xreg.h b/sys/mips/rt305x/rt305xreg.h new file mode 100644 index 0000000..42a6c86 --- /dev/null +++ b/sys/mips/rt305x/rt305xreg.h @@ -0,0 +1,368 @@ +/*- + * Copyright (c) 2010 Aleksandr Rybalko. + * 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. + * + * $FreeBSD$ + */ + +#ifndef _RT305XREG_H_ +#define _RT305XREG_H_ + +/* XXX: must move to config */ +#define RT305X 1 +#define RT305XF 1 +#define RT3052F 1 +#define __U_BOOT__ 1 +/* XXX: must move to config */ + +#ifdef RT3052F +#define PLATFORM_COUNTER_FREQ (384 * 1000 * 1000) +#endif +#ifdef RT3050F +#define PLATFORM_COUNTER_FREQ (320 * 1000 * 1000) +#endif +#ifndef PLATFORM_COUNTER_FREQ +#error "Nor RT3052F nor RT3050F defined" +#endif + +#define SYSTEM_CLOCK (PLATFORM_COUNTER_FREQ/3) + + +#define SDRAM_BASE 0x00000000 +#define SDRAM_END 0x03FFFFFF + +#define SYSCTL_BASE 0x10000000 +#define SYSCTL_END 0x100000FF +#define TIMER_BASE 0x10000100 +#define TIMER_END 0x100001FF +#define INTCTL_BASE 0x10000200 +#define INTCTL_END 0x100002FF +#define MEMCTRL_BASE 0x10000300 +#define MEMCTRL_END 0x100003FF /* SDRAM & Flash/SRAM */ +#define PCM_BASE 0x10000400 +#define PCM_END 0x100004FF +#define UART_BASE 0x10000500 +#define UART_END 0x100005FF +#define PIO_BASE 0x10000600 +#define PIO_END 0x100006FF +#define GDMA_BASE 0x10000700 +#define GDMA_END 0x100007FF /* Generic DMA */ +#define NANDFC_BASE 0x10000800 +#define NANDFC_END 0x100008FF /* NAND Flash Controller */ +#define I2C_BASE 0x10000900 +#define I2C_END 0x100009FF +#define I2S_BASE 0x10000A00 +#define I2S_END 0x10000AFF +#define SPI_BASE 0x10000B00 +#define SPI_END 0x10000BFF +#define UARTLITE_BASE 0x10000C00 +#define UARTLITE_END 0x10000CFF + +#define FRENG_BASE 0x10100000 +#define FRENG_END 0x1010FFFF /* Frame Engine */ +#define ETHSW_BASE 0x10110000 +#define ETHSW_END 0x10117FFF /* Ethernet Switch */ +#define ROM_BASE 0x10118000 +#define ROM_END 0x10119FFF +#define WLAN_BASE 0x10180000 +#define WLAN_END 0x101BFFFF /* 802.11n MAC/BBP */ +#define USB_OTG_BASE 0x101C0000 +#define USB_OTG_END 0x101FFFFF +#define EMEM_BASE 0x1B000000 +#define EMEM_END 0x1BFFFFFF /* External SRAM/Flash */ +#define FLASH_BASE 0x1F000000 +#define FLASH_END 0x1FFFFFFF /* Flash window */ + +#define OBIO_MEM_BASE SYSCTL_BASE +#define OBIO_MEM_START OBIO_MEM_BASE +#define OBIO_MEM_END FLASH_END + + + +/* System Control */ +#define SYSCTL_CHIPID0_3 0x00 /* 'R''T''3''0' */ +#define SYSCTL_CHIPID4_7 0x04 /* '5''2'' '' ' */ +#define SYSCTL_SYSCFG 0x10 +#define SYSCTL_SYSCFG_INIC_EE_SDRAM (1<<29) +#define SYSCTL_SYSCFG_INIC_8MB_SDRAM (1<<28) +#define SYSCTL_SYSCFG_GE0_MODE_MASK 0x03000000 +#define SYSCTL_SYSCFG_GE0_MODE_SHIFT 24 +#define SYSCTL_SYSCFG_GE0_MODE_RGMII 0 /* RGMII Mode */ +#define SYSCTL_SYSCFG_GE0_MODE_MII 1 /* MII Mode */ +#define SYSCTL_SYSCFG_GE0_MODE_REV_MII 2 /*Reversed MII Mode*/ +#define SYSCTL_SYSCFG_BOOT_ADDR_1F00 (1<<22) +#define SYSCTL_SYSCFG_BYPASS_PLL (1<<21) +#define SYSCTL_SYSCFG_BIG_ENDIAN (1<<20) +#define SYSCTL_SYSCFG_CPU_CLK_SEL_384MHZ (1<<18) +#define SYSCTL_SYSCFG_BOOT_FROM_MASK 0x00030000 +#define SYSCTL_SYSCFG_BOOT_FROM_SHIFT 16 +#define SYSCTL_SYSCFG_BOOT_FROM_FLASH16 0 +#define SYSCTL_SYSCFG_BOOT_FROM_FLASH8 1 +#define SYSCTL_SYSCFG_BOOT_FROM_NANDFLASH 2 +#define SYSCTL_SYSCFG_BOOT_FROM_ROM 3 +#define SYSCTL_SYSCFG_TEST_CODE_MASK 0x0000ff00 +#define SYSCTL_SYSCFG_TEST_CODE_SHIFT 8 +#define SYSCTL_SYSCFG_SRAM_CS_MODE_MASK 0x0000000c +#define SYSCTL_SYSCFG_SRAM_CS_MODE_SHIFT 2 +#define SYSCTL_SYSCFG_SRAM_CS_MODE_SRAM 0 +#define SYSCTL_SYSCFG_SRAM_CS_MODE_WDOG_RST 1 +#define SYSCTL_SYSCFG_SRAM_CS_MODE_BT_COEX 2 +#define SYSCTL_SYSCFG_SDRAM_CLK_DRV (1<<0) /* 8mA/12mA */ + +#define SYSCTL_TESTSTAT 0x18 +#define SYSCTL_TESTSTAT2 0x1C + +#define SYSCTL_CLKCFG0 0x2C +#define SYSCTL_CLKCFG0_SDRAM_CLK_SKEW_MASK 0xc0000000 +#define SYSCTL_CLKCFG0_SDRAM_CLK_SKEW_SHIFT 30 +#define SYSCTL_CLKCFG0_SDRAM_CLK_SKEW_ZERO_DELAY 0 +#define SYSCTL_CLKCFG0_SDRAM_CLK_SKEW_1NS_DELAY 1 +#define SYSCTL_CLKCFG0_SDRAM_CLK_SKEW_2NS_DELAY 2 +#define SYSCTL_CLKCFG0_SDRAM_CLK_SKEW_3NS_DELAY 3 + +#define SYSCTL_CLKCFG1 0x30 +#define SYSCTL_CLKCFG1_PBUS_DIV_CLK_BY2 (1<<30) +#define SYSCTL_CLKCFG1_OTG_CLK_EN (1<<18) +#define SYSCTL_CLKCFG1_I2S_CLK_EN (1<<15) +#define SYSCTL_CLKCFG1_I2S_CLK_SEL_EXT (1<<14) +#define SYSCTL_CLKCFG1_I2S_CLK_DIV_MASK 0x00003f00 +#define SYSCTL_CLKCFG1_I2S_CLK_DIV_SHIFT 8 +#define SYSCTL_CLKCFG1_PCM_CLK_EN (1<<7) +#define SYSCTL_CLKCFG1_PCM_CLK_SEL_EXT (1<<6) +#define SYSCTL_CLKCFG1_PCM_CLK_DIV_MASK 0x0000003f +#define SYSCTL_CLKCFG1_PCM_CLK_DIV_SHIFT 0 + +#define SYSCTL_RSTCTRL 0x34 +#define SYSCTL_RSTCTRL_ETHSW (1<<23) +#define SYSCTL_RSTCTRL_OTG (1<<22) +#define SYSCTL_RSTCTRL_FRENG (1<<21) +#define SYSCTL_RSTCTRL_WLAN (1<<20) +#define SYSCTL_RSTCTRL_UARTL (1<<19) +#define SYSCTL_RSTCTRL_SPI (1<<18) +#define SYSCTL_RSTCTRL_I2S (1<<17) +#define SYSCTL_RSTCTRL_I2C (1<<16) +#define SYSCTL_RSTCTRL_DMA (1<<14) +#define SYSCTL_RSTCTRL_PIO (1<<13) +#define SYSCTL_RSTCTRL_UART (1<<12) +#define SYSCTL_RSTCTRL_PCM (1<<11) +#define SYSCTL_RSTCTRL_MC (1<<10) +#define SYSCTL_RSTCTRL_INTC (1<<9) +#define SYSCTL_RSTCTRL_TIMER (1<<8) +#define SYSCTL_RSTCTRL_SYS (1<<0) + +#define SYSCTL_RSTSTAT 0x38 +#define SYSCTL_RSTSTAT_SWCPURST (1<<3) +#define SYSCTL_RSTSTAT_SWSYSRST (1<<2) +#define SYSCTL_RSTSTAT_WDRST (1<<1) + +#define SYSCTL_GPIOMODE 0x60 +#define SYSCTL_GPIOMODE_RGMII_GPIO_MODE (1<<9) +#define SYSCTL_GPIOMODE_SDRAM_GPIO_MODE (1<<8) +#define SYSCTL_GPIOMODE_MDIO_GPIO_MODE (1<<7) +#define SYSCTL_GPIOMODE_JTAG_GPIO_MODE (1<<6) +#define SYSCTL_GPIOMODE_UARTL_GPIO_MODE (1<<5) +#define SYSCTL_GPIOMODE_UARTF_SHARE_MODE_UARTF (0<<2) +#define SYSCTL_GPIOMODE_UARTF_SHARE_MODE_PCM_UARTF (1<<2) +#define SYSCTL_GPIOMODE_UARTF_SHARE_MODE_PCM_I2S (2<<2) +#define SYSCTL_GPIOMODE_UARTF_SHARE_MODE_I2S_UARTF (3<<2) +#define SYSCTL_GPIOMODE_UARTF_SHARE_MODE_PCM_GPIO (4<<2) +#define SYSCTL_GPIOMODE_UARTF_SHARE_MODE_GPIO_UARTF (5<<2) +#define SYSCTL_GPIOMODE_UARTF_SHARE_MODE_GPIO_I2S (6<<2) +#define SYSCTL_GPIOMODE_UARTF_SHARE_MODE_GPIO (7<<2) +#define SYSCTL_GPIOMODE_SPI_GPIO_MODE (1<<1) +#define SYSCTL_GPIOMODE_I2C_GPIO_MODE (1<<0) + +#define SYSCTL_MEMO0 0x68 +#define SYSCTL_MEMO1 0x6C + +/* Timer */ +#define TIMER_TMRSTAT 0x00 +#define TIMER_TMRSTAT_TMR1RST (1<<5) +#define TIMER_TMRSTAT_TMR0RST (1<<4) +#define TIMER_TMRSTAT_TMR1INT (1<<1) +#define TIMER_TMRSTAT_TMR0INT (1<<0) +#define TIMER_TMR0LOAD 0x10 +#define TIMER_TMR0VAL 0x14 +#define TIMER_TMR0CTL 0x18 +#define TIMER_TMR1LOAD 0x20 +#define TIMER_TMR1VAL 0x24 +#define TIMER_TMR1CTL 0x28 + +#define TIMER_TMRLOAD_TMR0LOAD_MASK 0xffff + +#define TIMER_TMRVAL_TMR0VAL_MASK 0xffff + +#define TIMER_TMRCTL_ENABLE (1<<7) +#define TIMER_TMRCTL_MODE_MASK 0x00000030 +#define TIMER_TMRCTL_MODE_SHIFT 4 +#define TIMER_TMRCTL_MODE_FREE 0 +#define TIMER_TMRCTL_MODE_PERIODIC 1 +#define TIMER_TMRCTL_MODE_TIMOUT 2 +#define TIMER_TMRCTL_MODE_TIMOUT3 3 +#define TIMER_TMRCTL_PRESCALE_MASK 0x0000000f +#define TIMER_TMRCTL_PRESCALE_SHIFT 0 +#define TIMER_TMRCTL_PRESCALE_NONE 0 +#define TIMER_TMRCTL_PRESCALE_BY_4 1 +#define TIMER_TMRCTL_PRESCALE_BY_8 2 +#define TIMER_TMRCTL_PRESCALE_BY_16 3 +#define TIMER_TMRCTL_PRESCALE_BY_32 4 +#define TIMER_TMRCTL_PRESCALE_BY_64 5 +#define TIMER_TMRCTL_PRESCALE_BY_128 6 +#define TIMER_TMRCTL_PRESCALE_BY_256 7 +#define TIMER_TMRCTL_PRESCALE_BY_512 8 +#define TIMER_TMRCTL_PRESCALE_BY_1K 9 +#define TIMER_TMRCTL_PRESCALE_BY_2K 10 +#define TIMER_TMRCTL_PRESCALE_BY_4K 11 +#define TIMER_TMRCTL_PRESCALE_BY_8K 12 +#define TIMER_TMRCTL_PRESCALE_BY_16K 13 +#define TIMER_TMRCTL_PRESCALE_BY_32K 14 +#define TIMER_TMRCTL_PRESCALE_BY_64K 15 + +/* Interrupt Controller */ +#define IC_IRQ0STAT 0x00 +#define IC_IRQ1STAT 0x04 +#define IC_INTTYPE 0x20 +#define IC_INTRAW 0x30 +#define IC_INT_ENA 0x34 +#define IC_INT_DIS 0x38 + +#define IC_OTG 18 +#define IC_ETHSW 17 +#define IC_UARTLITE 12 +#define IC_I2S 10 +#define IC_PERFC 9 +#define IC_NAND 8 +#define IC_DMA 7 +#define IC_PIO 6 +#define IC_UART 5 +#define IC_PCM 4 +#define IC_ILL_ACCESS 3 +#define IC_WDTIMER 2 +#define IC_TIMER0 1 +#define IC_SYSCTL 0 + +#define IC_LINE_GLOBAL (1<<31) /* Only for DIS/ENA regs */ +#define IC_LINE_OTG (1<<18) +#define IC_LINE_ETHSW (1<<17) +#define IC_LINE_UARTLITE (1<<12) +#define IC_LINE_I2S (1<<10) +#define IC_LINE_PERFC (1<<9) +#define IC_LINE_NAND (1<<8) +#define IC_LINE_DMA (1<<7) +#define IC_LINE_PIO (1<<6) +#define IC_LINE_UART (1<<5) +#define IC_LINE_PCM (1<<4) +#define IC_LINE_ILL_ACCESS (1<<3) +#define IC_LINE_WDTIMER (1<<2) +#define IC_LINE_TIMER0 (1<<1) +#define IC_LINE_SYSCTL (1<<0) + +#define IC_INT_MASK 0x000617ff + +/* GPIO */ + +#define GPIO23_00_INT 0x00 /* Programmed I/O Int Status */ +#define GPIO23_00_EDGE 0x04 /* Programmed I/O Edge Status */ +#define GPIO23_00_RENA 0x08 /* Programmed I/O Int on Rising */ +#define GPIO23_00_FENA 0x0C /* Programmed I/O Int on Falling */ +#define GPIO23_00_DATA 0x20 /* Programmed I/O Data */ +#define GPIO23_00_DIR 0x24 /* Programmed I/O Direction */ +#define GPIO23_00_POL 0x28 /* Programmed I/O Pin Polarity */ +#define GPIO23_00_SET 0x2C /* Set PIO Data Bit */ +#define GPIO23_00_RESET 0x30 /* Clear PIO Data bit */ +#define GPIO23_00_TOG 0x34 /* Toggle PIO Data bit */ + +#define GPIO39_24_INT 0x38 +#define GPIO39_24_EDGE 0x3c +#define GPIO39_24_RENA 0x40 +#define GPIO39_24_FENA 0x44 +#define GPIO39_24_DATA 0x48 +#define GPIO39_24_DIR 0x4c +#define GPIO39_24_POL 0x50 +#define GPIO39_24_SET 0x54 +#define GPIO39_24_RESET 0x58 +#define GPIO39_24_TOG 0x5c + +#define GPIO51_40_INT 0x60 +#define GPIO51_40_EDGE 0x64 +#define GPIO51_40_RENA 0x68 +#define GPIO51_40_FENA 0x6C +#define GPIO51_40_DATA 0x70 +#define GPIO51_40_DIR 0x74 +#define GPIO51_40_POL 0x78 +#define GPIO51_40_SET 0x7C +#define GPIO51_40_RESET 0x80 +#define GPIO51_40_TOG 0x84 + + + + +#define GDMA_CHANNEL_REQ0 0 +#define GDMA_CHANNEL_REQ1 1 /* (NAND-flash) */ +#define GDMA_CHANNEL_REQ2 2 /* (I2S) */ +#define GDMA_CHANNEL_REQ3 3 /* (PCM0-RX) */ +#define GDMA_CHANNEL_REQ4 4 /* (PCM1-RX) */ +#define GDMA_CHANNEL_REQ5 5 /* (PCM0-TX) */ +#define GDMA_CHANNEL_REQ6 6 /* (PCM1-TX) */ +#define GDMA_CHANNEL_REQ7 7 +#define GDMA_CHANNEL_MEM 8 + +/* Generic DMA Controller */ +/* GDMA Channel n Source Address */ +#define GDMASA(n) (0x00 + 0x10*n) + /* GDMA Channel n Destination Address */ +#define GDMADA(n) (0x04 + 0x10*n) + /* GDMA Channel n Control Register 0 */ +#define GDMACT0(n) (0x08 + 0x10*n) + +#define GDMACT0_TR_COUNT_MASK 0x0fff0000 +#define GDMACT0_TR_COUNT_SHIFT 16 +#define GDMACT0_SRC_CHAN_SHIFT 12 +#define GDMACT0_SRC_CHAN_MASK 0x0000f000 +#define GDMACT0_DST_CHAN_SHIFT 8 +#define GDMACT0_DST_CHAN_MASK 0x00000f00 +#define GDMACT0_SRC_BURST_MODE (1<<7) +#define GDMACT0_DST_BURST_MODE (1<<6) +#define GDMACT0_BURST_SIZE_SHIFT 3 +#define GDMACT0_BURST_SIZE_MASK 0x00000038 +#define GDMACT0_BURST_SIZE_1 0 +#define GDMACT0_BURST_SIZE_2 1 +#define GDMACT0_BURST_SIZE_4 2 +#define GDMACT0_BURST_SIZE_8 3 +#define GDMACT0_BURST_SIZE_16 4 + +#define GDMACT0_DONE_INT_EN (1<<2) +#define GDMACT0_CHAN_EN (1<<1) +/* + * In software mode, the data transfer will start when the Channel Enable bit + * is set. + * In hardware mode, the data transfer will start when the DMA Request is + * asserted. +*/ +#define GDMACT0_SWMODE (1<<0) + + + + +#endif /* _RT305XREG_H_ */ diff --git a/sys/mips/rt305x/rt_swreg.h b/sys/mips/rt305x/rt_swreg.h new file mode 100644 index 0000000..ab382b9 --- /dev/null +++ b/sys/mips/rt305x/rt_swreg.h @@ -0,0 +1,160 @@ +/*- + * Copyright (c) 2010 Aleksandr Rybalko. + * 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. + * + * $FreeBSD$ + */ + +#ifndef _RT_SWREG_H_ +#define _RT_SWREG_H_ + +/* XXX: must move to config */ +#define RT3052F + +#define RT_SW_BASE 0x10110000 + +#define RT_SW_ISR 0x00 + +#define WATCHDOG1_TMR_EXPIRED (1<<29) +#define WATCHDOG0_TMR_EXPIRED (1<<28) +#define HAS_INTRUDER (1<<27) +#define PORT_ST_CHG (1<<26) +#define BC_STORM (1<<25) +#define MUST_DROP_LAN (1<<24) +#define GLOBAL_QUE_FULL (1<<23) +#define LAN_QUE_FULL6 (1<<20) +#define LAN_QUE_FULL5 (1<<19) +#define LAN_QUE_FULL4 (1<<18) +#define LAN_QUE_FULL3 (1<<17) +#define LAN_QUE_FULL2 (1<<16) +#define LAN_QUE_FULL1 (1<<15) +#define LAN_QUE_FULL0 (1<<14) + +#define RT_SW_IMR 0x04 + +#define RT_SW_FCT0 0x08 +#define RT_SW_FCT1 0x0c +#define RT_SW_PFC0 0x10 +#define RT_SW_PFC1 0x14 +#define RT_SW_PFC2 0x18 +#define RT_SW_GQS0 0x1c +#define RT_SW_GQS1 0x20 +#define RT_SW_ATS 0x24 +#define RT_SW_ATS0 0x28 +#define RT_SW_ATS1 0x2c +#define RT_SW_ATS2 0x30 +#define RT_SW_WMAD0 0x34 +#define RT_SW_WMAD1 0x38 +#define RT_SW_WMAD2 0x3c +#define RT_SW_PVIDC0 0x40 +#define RT_SW_PVIDC1 0x44 +#define RT_SW_PVIDC2 0x48 +#define RT_SW_PVIDC3 0x4c +#define RT_SW_VID0 0x50 +#define RT_SW_VID1 0x54 +#define RT_SW_VID2 0x58 +#define RT_SW_VID3 0x5c +#define RT_SW_VID4 0x60 +#define RT_SW_VID5 0x64 +#define RT_SW_VID6 0x68 +#define RT_SW_VID7 0x6c +#define RT_SW_VMSC0 0x70 +#define RT_SW_VMSC1 0x74 +#define RT_SW_VMSC2 0x78 +#define RT_SW_VMSC3 0x7c +#define RT_SW_POA 0x80 +#define RT_SW_FPA 0x84 +#define RT_SW_PTS 0x88 +#define RT_SW_SOCPC 0x8c +#define RT_SW_POC0 0x90 +#define RT_SW_POC1 0x94 +#define RT_SW_POC2 0x98 +#define RT_SW_SGC 0x9c +#define RT_SW_STRT 0xa0 +#define RT_SW_LEDP0 0xa4 +#define RT_SW_LEDP1 0xa8 +#define RT_SW_LEDP2 0xac +#define RT_SW_LEDP3 0xb0 +#define RT_SW_LEDP4 0xb4 +#define RT_SW_WDTR 0xb8 +#define RT_SW_DES 0xbc +#define RT_SW_PCR0 0xc0 +#define RT_SW_PCR1 0xc4 +#define RT_SW_FPA 0xc8 +#define RT_SW_FCT2 0xcc +#define RT_SW_QSS0 0xd0 + +#define RT_SW_QSS1 0xd4 +#define RT_SW_DEC 0xd8 +#define BRIDGE_IPG_SHIFT 24 +#define DEBUG_SW_PORT_SEL_SHIFT 3 +#define DEBUG_SW_PORT_SEL_MASK 0x00000038 + +#define RT_SW_MTI 0xdc +#define SKIP_BLOCKS_SHIFT 7 +#define SKIP_BLOCKS_MASK 0x0000ff80 +#define SW_RAM_TEST_DONE (1<<6) +#define AT_RAM_TEST_DONE (1<<5) +#define AT_RAM_TEST_FAIL (1<<4) +#define LK_RAM_TEST_DONE (1<<3) +#define LK_RAM_TEST_FAIL (1<<2) +#define DT_RAM_TEST_DONE (1<<1) +#define DT_RAM_TEST_FAIL (1<<0) + +#define RT_SW_PPC 0xe0 +#define SW2FE_CNT_SHIFT 16 +#define FE2SW_CNT_SHIFT 0 + +#define RT_SW_SGC2 0xe4 +#define FE2SW_WL_FC_EN (1<<30) +#define LAN_PMAP_P0_IS_LAN (1<<24) +#define LAN_PMAP_P1_IS_LAN (1<<25) +#define LAN_PMAP_P2_IS_LAN (1<<26) +#define LAN_PMAP_P3_IS_LAN (1<<27) +#define LAN_PMAP_P4_IS_LAN (1<<28) +#define LAN_PMAP_P5_IS_LAN (1<<29) +/* Transmit CPU TPID(810x) port bit map */ +#define TX_CPU_TPID_BIT_MAP_SHIFT 16 +#define TX_CPU_TPID_BIT_MAP_MASK 0x007f0000 +#define ARBITER_LAN_EN (1<<11) +#define CPU_TPID_EN (1<<10) +#define P0_DOUBLE_TAG_EN (1<<0) +#define P1_DOUBLE_TAG_EN (1<<1) +#define P2_DOUBLE_TAG_EN (1<<2) +#define P3_DOUBLE_TAG_EN (1<<3) +#define P4_DOUBLE_TAG_EN (1<<4) +#define P5_DOUBLE_TAG_EN (1<<5) + +#define RT_SW_P0PC 0xe8 +#define RT_SW_P1PC 0xec +#define RT_SW_P2PC 0xf0 +#define RT_SW_P3PC 0xf4 +#define RT_SW_P4PC 0xf8 +#define RT_SW_P5PC 0xfc +#define BAD_PCOUNT_SHIFT 16 +#define BAD_PCOUNT_MASK 0xffff0000 +#define GOOD_PCOUNT_SHIFT 0 +#define GOOD_PCOUNT_MASK 0x0000ffff + +#endif /* _RT_SWREG_H_ */ diff --git a/sys/mips/rt305x/std.rt305x b/sys/mips/rt305x/std.rt305x new file mode 100644 index 0000000..6c56e15 --- /dev/null +++ b/sys/mips/rt305x/std.rt305x @@ -0,0 +1,8 @@ +# $FreeBSD$ +# Standard include file for RT305XF SoC + +files "../rt305x/files.rt305x" + +cpu CPU_MIPS4KC +options ISA_MIPS32 + diff --git a/sys/mips/rt305x/uart_bus_rt305x.c b/sys/mips/rt305x/uart_bus_rt305x.c new file mode 100644 index 0000000..9cd1df7 --- /dev/null +++ b/sys/mips/rt305x/uart_bus_rt305x.c @@ -0,0 +1,102 @@ +/*- + * Copyright (c) 2007 Bruce M. Simpson. + * 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 + * $Id$ + */ +/* + * Skeleton of this file was based on respective code for ARM + * code written by Olivier Houchard. + */ + +/* + * XXXMIPS: This file is hacked from arm/... . XXXMIPS here means this file is + * experimental and was written for MIPS32 port. + */ +#include "opt_uart.h" + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/bus.h> +#include <sys/conf.h> +#include <sys/kernel.h> +#include <sys/module.h> +#include <machine/bus.h> +#include <sys/rman.h> +#include <machine/resource.h> + +#include <dev/pci/pcivar.h> + +#include <dev/uart/uart.h> +#include <dev/uart/uart_bus.h> +#include <dev/uart/uart_cpu.h> + +#include <mips/rt305x/rt305xreg.h> + +#include "uart_if.h" + +static int uart_rt305x_probe(device_t dev); + +extern struct uart_class uart_rt305x_uart_class; + +static device_method_t uart_rt305x_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, uart_rt305x_probe), + DEVMETHOD(device_attach, uart_bus_attach), + DEVMETHOD(device_detach, uart_bus_detach), + { 0, 0 } +}; + +static driver_t uart_rt305x_driver = { + uart_driver_name, + uart_rt305x_methods, + sizeof(struct uart_softc), +}; + +extern SLIST_HEAD(uart_devinfo_list, uart_devinfo) uart_sysdevs; + +static int +uart_rt305x_probe(device_t dev) +{ + struct uart_softc *sc; + + sc = device_get_softc(dev); + sc->sc_sysdev = SLIST_FIRST(&uart_sysdevs); + sc->sc_class = &uart_rt305x_uart_class; + bcopy(&sc->sc_sysdev->bas, &sc->sc_bas, sizeof(sc->sc_bas)); + sc->sc_sysdev->bas.regshft = 2; + sc->sc_sysdev->bas.bst = mips_bus_space_generic; + sc->sc_sysdev->bas.bsh = + MIPS_PHYS_TO_KSEG1(device_get_unit(dev)?UARTLITE_BASE:UART_BASE); + sc->sc_bas.regshft = 2; + sc->sc_bas.bst = mips_bus_space_generic; + sc->sc_bas.bsh = + MIPS_PHYS_TO_KSEG1(device_get_unit(dev)?UARTLITE_BASE:UART_BASE); + + return (uart_bus_probe(dev, 2, SYSTEM_CLOCK, 0, 0)); +} + +DRIVER_MODULE(uart, obio, uart_rt305x_driver, uart_devclass, 0, 0); + diff --git a/sys/mips/rt305x/uart_cpu_rt305x.c b/sys/mips/rt305x/uart_cpu_rt305x.c new file mode 100644 index 0000000..b9225a1 --- /dev/null +++ b/sys/mips/rt305x/uart_cpu_rt305x.c @@ -0,0 +1,82 @@ +/*- + * Copyright (c) 2006 Wojciech A. Koszek <wkoszek@FreeBSD.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id$ + */ +/* + * Skeleton of this file was based on respective code for ARM + * code written by Olivier Houchard. + */ +/* + * XXXMIPS: This file is hacked from arm/... . XXXMIPS here means this file is + * experimental and was written for MIPS32 port. + */ +#include "opt_uart.h" + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/bus.h> +#include <sys/cons.h> + +#include <machine/bus.h> + +#include <dev/uart/uart.h> +#include <dev/uart/uart_cpu.h> + +#include <mips/rt305x/rt305xreg.h> + +extern struct uart_class uart_rt305x_uart_class; +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) +{ + di->ops = uart_getops(&uart_rt305x_uart_class); + di->bas.chan = 0; + di->bas.bst = mips_bus_space_generic; + di->bas.regshft = 2; + di->bas.rclk = SYSTEM_CLOCK; + di->baudrate = 115200; + di->databits = 8; + di->stopbits = 1; + + di->parity = UART_PARITY_NONE; + + uart_bus_space_io = NULL; + uart_bus_space_mem = mips_bus_space_generic; + di->bas.bsh = MIPS_PHYS_TO_KSEG1(UARTLITE_BASE); + return (0); +} diff --git a/sys/mips/rt305x/uart_dev_rt305x.c b/sys/mips/rt305x/uart_dev_rt305x.c new file mode 100644 index 0000000..677c0c6 --- /dev/null +++ b/sys/mips/rt305x/uart_dev_rt305x.c @@ -0,0 +1,507 @@ +/* $NetBSD: uart.c,v 1.2 2007/03/23 20:05:47 dogcow Exp $ */ + +/*- + * Copyright (c) 2010 Aleksandr Rybalko. + * Copyright (c) 2007 Ruslan Ermilov and Vsevolod Lobko. + * Copyright (c) 2007 Oleksandr Tymoshenko. + * 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 AUTHORS ``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 AUTHORS + * 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> +__FBSDID("$FreeBSD$"); + +#include "opt_ddb.h" + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/bus.h> +#include <sys/conf.h> +#include <sys/kdb.h> +#include <sys/reboot.h> +#include <sys/sysctl.h> +#include <sys/kernel.h> +#include <machine/bus.h> + +#include <dev/uart/uart.h> +#include <dev/uart/uart_cpu.h> +#include <dev/uart/uart_bus.h> + +#include <mips/rt305x/uart_dev_rt305x.h> +#include <mips/rt305x/rt305xreg.h> + +#include "uart_if.h" +/* + * Low-level UART interface. + */ +static int rt305x_uart_probe(struct uart_bas *bas); +static void rt305x_uart_init(struct uart_bas *bas, int, int, int, int); +static void rt305x_uart_term(struct uart_bas *bas); +static void rt305x_uart_putc(struct uart_bas *bas, int); +static int rt305x_uart_rxready(struct uart_bas *bas); +static int rt305x_uart_getc(struct uart_bas *bas, struct mtx *); + +static struct uart_ops uart_rt305x_uart_ops = { + .probe = rt305x_uart_probe, + .init = rt305x_uart_init, + .term = rt305x_uart_term, + .putc = rt305x_uart_putc, + .rxready = rt305x_uart_rxready, + .getc = rt305x_uart_getc, +}; + +static int uart_output = 1; +TUNABLE_INT("kern.uart_output", &uart_output); +SYSCTL_INT(_kern, OID_AUTO, uart_output, CTLFLAG_RW, + &uart_output, 0, "UART output enabled."); + + + + +static int +rt305x_uart_probe(struct uart_bas *bas) +{ + + return (0); +} + +static void +rt305x_uart_init(struct uart_bas *bas, int baudrate, int databits, + int stopbits, int parity) +{ +#ifdef notyet + /* CLKDIV = 384000000/ 3/ 16/ br */ + /* for 384MHz CLKDIV = 8000000 / baudrate; */ + switch (databits) { + case 5: + databits = UART_LCR_5B; + break; + case 6: + databits = UART_LCR_6B; + break; + case 7: + databits = UART_LCR_7B; + break; + case 8: + databits = UART_LCR_8B; + break; + default: + /* Unsupported */ + return; + } + switch (parity) { + case UART_PARITY_EVEN: parity = (UART_LCR_PEN|UART_LCR_EVEN); break; + case UART_PARITY_NONE: parity = (UART_LCR_PEN); break; + case UART_PARITY_ODD: parity = 0; break; + /* Unsupported */ + default: return; + } + uart_setreg(bas, UART_CDDL_REG, 8000000/baudrate); + uart_barrier(bas); + uart_setreg(bas, UART_LCR_REG, databits | (stopbits==1?0:4) | parity); + uart_barrier(bas); +#endif +} + +static void +rt305x_uart_term(struct uart_bas *bas) +{ + uart_setreg(bas, UART_MCR_REG, 0); + uart_barrier(bas); +} + +static void +rt305x_uart_putc(struct uart_bas *bas, int c) +{ + char chr; + if (!uart_output) return; + chr = c; + while (!(uart_getreg(bas, UART_LSR_REG) & UART_LSR_THRE)); + uart_setreg(bas, UART_TX_REG, c); + uart_barrier(bas); + while (!(uart_getreg(bas, UART_LSR_REG) & UART_LSR_THRE)); +} + +static int +rt305x_uart_rxready(struct uart_bas *bas) +{ +#ifdef notyet + if (uart_getreg(bas, UART_LSR_REG) & UART_LSR_DR) + return (1); + + return (0); +#else + return (1); +#endif +} + +static int +rt305x_uart_getc(struct uart_bas *bas, struct mtx *hwmtx) +{ + int c; + + uart_lock(hwmtx); + + while (!(uart_getreg(bas, UART_LSR_REG) & UART_LSR_DR)) { + uart_unlock(hwmtx); + DELAY(10); + uart_lock(hwmtx); + } + + c = uart_getreg(bas, UART_RX_REG); + + uart_unlock(hwmtx); + + return (c); +} + +/* + * High-level UART interface. + */ +struct rt305x_uart_softc { + struct uart_softc base; +}; + +static int rt305x_uart_bus_attach(struct uart_softc *); +static int rt305x_uart_bus_detach(struct uart_softc *); +static int rt305x_uart_bus_flush(struct uart_softc *, int); +static int rt305x_uart_bus_getsig(struct uart_softc *); +static int rt305x_uart_bus_ioctl(struct uart_softc *, int, intptr_t); +static int rt305x_uart_bus_ipend(struct uart_softc *); +static int rt305x_uart_bus_param(struct uart_softc *, int, int, int, int); +static int rt305x_uart_bus_probe(struct uart_softc *); +static int rt305x_uart_bus_receive(struct uart_softc *); +static int rt305x_uart_bus_setsig(struct uart_softc *, int); +static int rt305x_uart_bus_transmit(struct uart_softc *); + +static kobj_method_t rt305x_uart_methods[] = { + KOBJMETHOD(uart_attach, rt305x_uart_bus_attach), + KOBJMETHOD(uart_detach, rt305x_uart_bus_detach), + KOBJMETHOD(uart_flush, rt305x_uart_bus_flush), + KOBJMETHOD(uart_getsig, rt305x_uart_bus_getsig), + KOBJMETHOD(uart_ioctl, rt305x_uart_bus_ioctl), + KOBJMETHOD(uart_ipend, rt305x_uart_bus_ipend), + KOBJMETHOD(uart_param, rt305x_uart_bus_param), + KOBJMETHOD(uart_probe, rt305x_uart_bus_probe), + KOBJMETHOD(uart_receive, rt305x_uart_bus_receive), + KOBJMETHOD(uart_setsig, rt305x_uart_bus_setsig), + KOBJMETHOD(uart_transmit, rt305x_uart_bus_transmit), + { 0, 0 } +}; + +struct uart_class uart_rt305x_uart_class = { + "rt305x", + rt305x_uart_methods, + sizeof(struct rt305x_uart_softc), + .uc_ops = &uart_rt305x_uart_ops, + .uc_range = 1, /* use hinted range */ + .uc_rclk = SYSTEM_CLOCK +}; + +#define SIGCHG(c, i, s, d) \ + if (c) { \ + i |= (i & s) ? s : s | d; \ + } else { \ + i = (i & s) ? (i & ~s) | d : i; \ + } + +/* + * Disable TX interrupt. uart should be locked + */ +static __inline void +rt305x_uart_disable_txintr(struct uart_softc *sc) +{ + struct uart_bas *bas = &sc->sc_bas; + uint8_t cr; + + cr = uart_getreg(bas, UART_IER_REG); + cr &= ~UART_IER_ETBEI; + uart_setreg(bas, UART_IER_REG, cr); + uart_barrier(bas); +} + +/* + * Enable TX interrupt. uart should be locked + */ +static __inline void +rt305x_uart_enable_txintr(struct uart_softc *sc) +{ + struct uart_bas *bas = &sc->sc_bas; + uint8_t cr; + + cr = uart_getreg(bas, UART_IER_REG); + cr |= UART_IER_ETBEI; + uart_setreg(bas, UART_IER_REG, cr); + uart_barrier(bas); +} + +static int +rt305x_uart_bus_attach(struct uart_softc *sc) +{ + struct uart_bas *bas; + struct uart_devinfo *di; + + bas = &sc->sc_bas; + if (sc->sc_sysdev != NULL) { + di = sc->sc_sysdev; + rt305x_uart_init(bas, di->baudrate, di->databits, di->stopbits, + di->parity); + } else { + rt305x_uart_init(bas, 115200, 8, 1, 0); + } + + sc->sc_rxfifosz = 16; + sc->sc_txfifosz = 16; + + (void)rt305x_uart_bus_getsig(sc); + + /* Enable FIFO */ + uart_setreg(bas, UART_FCR_REG, + uart_getreg(bas, UART_FCR_REG) | + UART_FCR_FIFOEN | UART_FCR_TXTGR_1 | UART_FCR_RXTGR_1); + uart_barrier(bas); + /* Enable interrupts */ + uart_setreg(bas, UART_IER_REG, + UART_IER_EDSSI | UART_IER_ELSI | UART_IER_ERBFI); + uart_barrier(bas); + + return (0); +} + +static int +rt305x_uart_bus_detach(struct uart_softc *sc) +{ + + return (0); +} + +static int +rt305x_uart_bus_flush(struct uart_softc *sc, int what) +{ + struct uart_bas *bas = &sc->sc_bas; + uint32_t fcr = uart_getreg(bas, UART_FCR_REG); + if (what & UART_FLUSH_TRANSMITTER) { + uart_setreg(bas, UART_FCR_REG, fcr|UART_FCR_TXRST); + uart_barrier(bas); + } + if (what & UART_FLUSH_RECEIVER) { + uart_setreg(bas, UART_FCR_REG, fcr|UART_FCR_RXRST); + uart_barrier(bas); + } + uart_setreg(bas, UART_FCR_REG, fcr); + uart_barrier(bas); + return (0); +} + +static int +rt305x_uart_bus_getsig(struct uart_softc *sc) +{ + uint32_t new, old, sig; + uint8_t bes; + + do { + old = sc->sc_hwsig; + sig = old; + uart_lock(sc->sc_hwmtx); + bes = uart_getreg(&sc->sc_bas, UART_MSR_REG); + uart_unlock(sc->sc_hwmtx); + /* XXX: chip can show delta */ + SIGCHG(bes & UART_MSR_CTS, sig, SER_CTS, SER_DCTS); + SIGCHG(bes & UART_MSR_DCD, sig, SER_DCD, SER_DDCD); + SIGCHG(bes & UART_MSR_DSR, sig, SER_DSR, SER_DDSR); + new = sig & ~SER_MASK_DELTA; + } while (!atomic_cmpset_32(&sc->sc_hwsig, old, new)); + + return (sig); +} + +static int +rt305x_uart_bus_ioctl(struct uart_softc *sc, int request, intptr_t data) +{ + struct uart_bas *bas; + int baudrate, divisor, error; + + bas = &sc->sc_bas; + error = 0; + uart_lock(sc->sc_hwmtx); + switch (request) { + case UART_IOCTL_BREAK: + /* TODO: Send BREAK */ + break; + case UART_IOCTL_BAUD: + divisor = uart_getreg(bas, UART_CDDL_REG); + baudrate = bas->rclk / (divisor * 16); + *(int*)data = baudrate; + break; + default: + error = EINVAL; + break; + } + uart_unlock(sc->sc_hwmtx); + return (error); +} + +static int +rt305x_uart_bus_ipend(struct uart_softc *sc) +{ + struct uart_bas *bas; + int ipend; + uint8_t iir, lsr, msr; + + bas = &sc->sc_bas; + ipend = 0; + + uart_lock(sc->sc_hwmtx); + iir = uart_getreg(&sc->sc_bas, UART_IIR_REG); + lsr = uart_getreg(&sc->sc_bas, UART_LSR_REG); + uart_setreg(&sc->sc_bas, UART_LSR_REG, lsr); + msr = uart_getreg(&sc->sc_bas, UART_MSR_REG); + uart_setreg(&sc->sc_bas, UART_MSR_REG, msr); + if (iir & UART_IIR_INTP) { + uart_unlock(sc->sc_hwmtx); + return (0); + } + + + switch ((iir >> 1) & 0x07) { + case UART_IIR_ID_THRE: + ipend |= SER_INT_TXIDLE; + break; + case UART_IIR_ID_DR2: + rt305x_uart_bus_flush(sc, UART_FLUSH_RECEIVER); + /* passthrough */ + case UART_IIR_ID_DR: + ipend |= SER_INT_RXREADY; + break; + case UART_IIR_ID_MST: + case UART_IIR_ID_LINESTATUS: + ipend |= SER_INT_SIGCHG; + if (lsr & UART_LSR_BI) + { + ipend |= SER_INT_BREAK; +#ifdef KDB + breakpoint(); +#endif + } + if (lsr & UART_LSR_OE) + ipend |= SER_INT_OVERRUN; + break; + default: + /* XXX: maybe return error here */ + break; + } + + uart_unlock(sc->sc_hwmtx); + + return (ipend); +} + +static int +rt305x_uart_bus_param(struct uart_softc *sc, int baudrate, int databits, + int stopbits, int parity) +{ + uart_lock(sc->sc_hwmtx); + rt305x_uart_init(&sc->sc_bas, baudrate, databits, stopbits, parity); + uart_unlock(sc->sc_hwmtx); + return (0); +} + +static int +rt305x_uart_bus_probe(struct uart_softc *sc) +{ + char buf[80]; + int error; + + error = rt305x_uart_probe(&sc->sc_bas); + if (error) + return (error); + + snprintf(buf, sizeof(buf), "rt305x_uart"); + device_set_desc_copy(sc->sc_dev, buf); + + return (0); +} + +static int +rt305x_uart_bus_receive(struct uart_softc *sc) +{ + struct uart_bas *bas; + int xc; + uint8_t lsr; + + bas = &sc->sc_bas; + uart_lock(sc->sc_hwmtx); + lsr = uart_getreg(bas, UART_LSR_REG); + while ((lsr & UART_LSR_DR)) { + if (uart_rx_full(sc)) { + sc->sc_rxbuf[sc->sc_rxput] = UART_STAT_OVERRUN; + break; + } + xc = 0; + xc = uart_getreg(bas, UART_RX_REG); + if (lsr & UART_LSR_FE) + xc |= UART_STAT_FRAMERR; + if (lsr & UART_LSR_PE) + xc |= UART_STAT_PARERR; + if (lsr & UART_LSR_OE) + xc |= UART_STAT_OVERRUN; + uart_barrier(bas); + uart_rx_put(sc, xc); + lsr = uart_getreg(bas, UART_LSR_REG); + } + + uart_unlock(sc->sc_hwmtx); + return (0); +} + +static int +rt305x_uart_bus_setsig(struct uart_softc *sc, int sig) +{ + + /* TODO: implement (?) */ + return (0); +} + +static int +rt305x_uart_bus_transmit(struct uart_softc *sc) +{ + struct uart_bas *bas = &sc->sc_bas; + int i; + + if (!uart_output) return (0); + + bas = &sc->sc_bas; + uart_lock(sc->sc_hwmtx); + while ((uart_getreg(bas, UART_LSR_REG) & UART_LSR_THRE) == 0) + ; + rt305x_uart_enable_txintr(sc); + for (i = 0; i < sc->sc_txdatasz; i++) { + uart_setreg(bas, UART_TX_REG, sc->sc_txbuf[i]); + uart_barrier(bas); + } + sc->sc_txbusy = 1; + uart_unlock(sc->sc_hwmtx); + return (0); +} diff --git a/sys/mips/rt305x/uart_dev_rt305x.h b/sys/mips/rt305x/uart_dev_rt305x.h new file mode 100644 index 0000000..c24b339 --- /dev/null +++ b/sys/mips/rt305x/uart_dev_rt305x.h @@ -0,0 +1,126 @@ +/*- + * Copyright (c) 2010 Aleksandr Rybalko. + * 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. The names of the authors may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``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 AUTHORS + * 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. + * + * $FreeBSD$ + */ +#ifndef _RT305XUART_H +#define _RT305XUART_H + +#undef uart_getreg +#undef uart_setreg +#define uart_getreg(bas, reg) \ + bus_space_read_4((bas)->bst, (bas)->bsh, reg) +#define uart_setreg(bas, reg, value) \ + bus_space_write_4((bas)->bst, (bas)->bsh, reg, value) + +/* UART registers */ +#define UART_RX_REG 0x00 +#define UART_TX_REG 0x04 + +#define UART_IER_REG 0x08 +#define UART_IER_EDSSI (1<<3) /* Only full UART */ +#define UART_IER_ELSI (1<<2) +#define UART_IER_ETBEI (1<<1) +#define UART_IER_ERBFI (1<<0) + +#define UART_IIR_REG 0x0c +#define UART_IIR_RXFIFO (1<<7) +#define UART_IIR_TXFIFO (1<<6) +#define UART_IIR_ID_MST 0 +#define UART_IIR_ID_THRE 1 +#define UART_IIR_ID_DR 2 +#define UART_IIR_ID_LINESTATUS 3 +#define UART_IIR_ID_DR2 6 +#define UART_IIR_ID_SHIFT 1 +#define UART_IIR_ID_MASK 0x0000000e +#define UART_IIR_INTP (1<<0) + +#define UART_FCR_REG 0x10 +#define UART_FCR_RXTGR_1 (0<<6) +#define UART_FCR_RXTGR_4 (1<<6) +#define UART_FCR_RXTGR_8 (2<<6) +#define UART_FCR_RXTGR_12 (3<<6) +#define UART_FCR_TXTGR_1 (0<<4) +#define UART_FCR_TXTGR_4 (1<<4) +#define UART_FCR_TXTGR_8 (2<<4) +#define UART_FCR_TXTGR_12 (3<<4) +#define UART_FCR_DMA (1<<3) +#define UART_FCR_TXRST (1<<2) +#define UART_FCR_RXRST (1<<1) +#define UART_FCR_FIFOEN (1<<0) + +#define UART_LCR_REG 0x14 +#define UART_LCR_DLAB (1<<7) +#define UART_LCR_BRK (1<<6) +#define UART_LCR_FPAR (1<<5) +#define UART_LCR_EVEN (1<<4) +#define UART_LCR_PEN (1<<3) +#define UART_LCR_STB_15 (1<<2) +#define UART_LCR_5B 0 +#define UART_LCR_6B 1 +#define UART_LCR_7B 2 +#define UART_LCR_8B 3 + +#define UART_MCR_REG 0x18 +#define UART_MCR_LOOP (1<<4) +#define UART_MCR_OUT2_L (1<<3) /* Only full UART */ +#define UART_MCR_OUT1_L (1<<2) /* Only full UART */ +#define UART_MCR_RTS_L (1<<1) /* Only full UART */ +#define UART_MCR_DTR_L (1<<0) /* Only full UART */ + +#define UART_LSR_REG 0x1c +#define UART_LSR_ERINF (1<<7) +#define UART_LSR_TEMT (1<<6) +#define UART_LSR_THRE (1<<5) +#define UART_LSR_BI (1<<4) +#define UART_LSR_FE (1<<3) +#define UART_LSR_PE (1<<2) +#define UART_LSR_OE (1<<1) +#define UART_LSR_DR (1<<0) + +#define UART_MSR_REG 0x20 /* Only full UART */ +#define UART_MSR_DCD (1<<7) /* Only full UART */ +#define UART_MSR_RI (1<<6) /* Only full UART */ +#define UART_MSR_DSR (1<<5) /* Only full UART */ +#define UART_MSR_CTS (1<<4) /* Only full UART */ +#define UART_MSR_DDCD (1<<3) /* Only full UART */ +#define UART_MSR_TERI (1<<2) /* Only full UART */ +#define UART_MSR_DDSR (1<<1) /* Only full UART */ +#define UART_MSR_DCTS (1<<0) /* Only full UART */ + +#define UART_CDDL_REG 0x28 +#define UART_CDDLL_REG 0x2c +#define UART_CDDLH_REG 0x30 + +#define UART_IFCTL_REG 0x34 +#define UART_IFCTL_IFCTL (1<<0) + +int uart_cnattach(void); +#endif /* _RT305XUART_H */ |