summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorimp <imp@FreeBSD.org>2006-02-04 23:32:13 +0000
committerimp <imp@FreeBSD.org>2006-02-04 23:32:13 +0000
commitf2384c93e3e037aeae70e774832e2695f10c6b10 (patch)
tree0452302e17fa41f14460f74e8e49e382307a52a3
parentd83080f6aefe88f9297accf3bbffd91236c3b5f9 (diff)
downloadFreeBSD-src-f2384c93e3e037aeae70e774832e2695f10c6b10.zip
FreeBSD-src-f2384c93e3e037aeae70e774832e2695f10c6b10.tar.gz
Import support for the Atmel AT91RM9200 CPU/Microcontroller. This SoC
is a ARM920T based CPU with a bunch of built-in peripherals. The inital import supports the SPI bus, the TWI bus (although iicbus integration is not complete), the uarts, the system timer and the onboard ethernet. Support for the Kwikbyte KB9202 (http://www.kwikbyte.com) board is also included, although there's no reason why the 9200 and the 9201 wouldn't also work. Primitive support for running under the skyeye emulator is also provided (although skyeye's support for the AT91RM9200 is a little weak). The code has been structured so that other members of Atmel's arm family can be supported in the future. The AT91SAM9260 is not presently supported due to lack of hardware. The arm7tdmi families are also not supported becasue they lack an MMU. Many thanks to cognet@ for his help and assistance in bringing up this board. He did much of the vm work and wrote parts of the uart and system timer code as well as the bus space implementation. The system boots to single user w/o problem, although the serial console is a little slow and the ethernet driver is still in flux. This work was sponsored by Timing Solutions, Corporation. I am grateful to their support of the FreeBSD project in this manner.
-rw-r--r--sys/arm/at91/at91.c516
-rw-r--r--sys/arm/at91/at91_spi.c451
-rw-r--r--sys/arm/at91/at91_spiio.h61
-rw-r--r--sys/arm/at91/at91_spireg.h30
-rw-r--r--sys/arm/at91/at91_st.c215
-rw-r--r--sys/arm/at91/at91_streg.h57
-rw-r--r--sys/arm/at91/at91_twi.c434
-rw-r--r--sys/arm/at91/at91_twiio.h61
-rw-r--r--sys/arm/at91/at91_twireg.h82
-rw-r--r--sys/arm/at91/at91_usartreg.h148
-rw-r--r--sys/arm/at91/at91rm92reg.h633
-rw-r--r--sys/arm/at91/at91st.c215
-rw-r--r--sys/arm/at91/at91var.h46
-rw-r--r--sys/arm/at91/files.at91rm9217
-rw-r--r--sys/arm/at91/files.kb920x2
-rw-r--r--sys/arm/at91/hints.at91rm920068
-rw-r--r--sys/arm/at91/hints.at91sam926167
-rw-r--r--sys/arm/at91/if_ate.c982
-rw-r--r--sys/arm/at91/if_atereg.h175
-rw-r--r--sys/arm/at91/kb920x_machdep.c389
-rw-r--r--sys/arm/at91/std.at91rm924
-rw-r--r--sys/arm/at91/std.kb920x6
-rw-r--r--sys/arm/at91/uart_bus_at91usart.c111
-rw-r--r--sys/arm/at91/uart_cpu_at91rm9200usart.c87
-rw-r--r--sys/arm/at91/uart_dev_at91usart.c408
-rw-r--r--sys/arm/conf/KB920X83
-rw-r--r--sys/arm/conf/SKYEYE88
27 files changed, 5436 insertions, 0 deletions
diff --git a/sys/arm/at91/at91.c b/sys/arm/at91/at91.c
new file mode 100644
index 0000000..0ee4724
--- /dev/null
+++ b/sys/arm/at91/at91.c
@@ -0,0 +1,516 @@
+/*-
+ * Copyright (c) 2005 Olivier Houchard. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+
+#include <vm/vm.h>
+#include <vm/vm_kern.h>
+#include <vm/pmap.h>
+#include <vm/vm_page.h>
+#include <vm/vm_extern.h>
+
+#define _ARM32_BUS_DMA_PRIVATE
+#include <machine/bus.h>
+#include <machine/intr.h>
+
+#include <arm/at91/at91rm92reg.h>
+#include <arm/at91/at91var.h>
+
+static struct at91_softc *at91_softc;
+
+static int
+at91_bs_map(void *t, bus_addr_t bpa, bus_size_t size, int flags,
+ bus_space_handle_t *bshp)
+{
+ vm_paddr_t pa, endpa;
+
+ pa = trunc_page(bpa);
+ if (pa >= 0xfff00000)
+ return (0);
+ endpa = round_page(bpa + size);
+
+ *bshp = (vm_offset_t)pmap_mapdev(pa, endpa - pa);
+
+ return (0);
+}
+
+static void
+at91_bs_unmap(void *t, bus_size_t size)
+{
+ vm_offset_t va, endva;
+
+ va = trunc_page((vm_offset_t)t);
+ endva = va + round_page(size);
+
+ /* Free the kernel virtual mapping. */
+ kmem_free(kernel_map, va, endva - va);
+}
+
+static int
+at91_bs_subregion(void *t, bus_space_handle_t bsh, bus_size_t offset,
+ bus_size_t size, bus_space_handle_t *nbshp)
+{
+
+ *nbshp = bsh + offset;
+ return (0);
+}
+
+bs_protos(generic);
+bs_protos(generic_armv4);
+
+struct bus_space at91_bs_tag = {
+ /* cookie */
+ (void *) 0,
+
+ /* mapping/unmapping */
+ at91_bs_map,
+ at91_bs_unmap,
+ at91_bs_subregion,
+
+ /* allocation/deallocation */
+ NULL,
+ NULL,
+
+ /* barrier */
+ NULL,
+
+ /* read (single) */
+ generic_bs_r_1,
+ generic_armv4_bs_r_2,
+ generic_bs_r_4,
+ NULL,
+
+ /* read multiple */
+ generic_bs_rm_1,
+ generic_armv4_bs_rm_2,
+ generic_bs_rm_4,
+ NULL,
+
+ /* read region */
+ NULL,
+ generic_armv4_bs_rr_2,
+ generic_bs_rr_4,
+ NULL,
+
+ /* write (single) */
+ generic_bs_w_1,
+ generic_armv4_bs_w_2,
+ generic_bs_w_4,
+ NULL,
+
+ /* write multiple */
+ generic_bs_wm_1,
+ generic_armv4_bs_wm_2,
+ generic_bs_wm_4,
+ NULL,
+
+ /* write region */
+ NULL,
+ generic_armv4_bs_wr_2,
+ generic_bs_wr_4,
+ NULL,
+
+ /* set multiple */
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+
+ /* set region */
+ NULL,
+ generic_armv4_bs_sr_2,
+ generic_bs_sr_4,
+ NULL,
+
+ /* copy */
+ NULL,
+ generic_armv4_bs_c_2,
+ NULL,
+ NULL,
+};
+
+static int
+at91_probe(device_t dev)
+{
+ device_set_desc(dev, "AT91RM9200 device bus");
+ return (0);
+}
+
+static void
+at91_identify(driver_t *drv, device_t parent)
+{
+
+ BUS_ADD_CHILD(parent, 0, "atmelarm", 0);
+}
+
+struct arm32_dma_range *
+bus_dma_get_range(void)
+{
+
+ return (NULL);
+}
+
+int
+bus_dma_get_range_nb(void)
+{
+ return (0);
+}
+
+extern void irq_entry(void);
+
+static void
+at91_add_child(device_t dev, int prio, const char *name, int unit,
+ bus_addr_t addr, bus_size_t size, int irq)
+{
+ device_t kid;
+ struct at91_ivar *ivar;
+
+ kid = device_add_child_ordered(dev, prio, name, unit);
+ if (kid == NULL)
+ return;
+ ivar = malloc(sizeof(*ivar), M_DEVBUF, M_WAITOK | M_ZERO);
+ if (ivar == NULL) {
+ device_delete_child(dev, kid);
+ return;
+ }
+ device_set_ivars(kid, ivar);
+ resource_list_init(&ivar->resources);
+ if (irq != -1)
+ bus_set_resource(kid, SYS_RES_IRQ, 0, irq, 1);
+ if (addr != 0)
+ bus_set_resource(kid, SYS_RES_MEMORY, 0, addr, size);
+}
+
+
+static int
+at91_attach(device_t dev)
+{
+ struct at91_softc *sc = device_get_softc(dev);
+ int i;
+
+ at91_softc = sc;
+ sc->sc_st = &at91_bs_tag;
+ sc->sc_sh = AT91RM92_BASE;
+ sc->dev = dev;
+ if (bus_space_subregion(sc->sc_st, sc->sc_sh, AT91RM92_SYS_BASE,
+ AT91RM92_SYS_SIZE, &sc->sc_sys_sh) != 0)
+ panic("Enable to map IRQ registers");
+ sc->sc_irq_rman.rm_type = RMAN_ARRAY;
+ sc->sc_irq_rman.rm_descr = "AT91RM92 IRQs";
+ sc->sc_mem_rman.rm_type = RMAN_ARRAY;
+ sc->sc_mem_rman.rm_descr = "AT91RM92 Memory";
+ if (rman_init(&sc->sc_irq_rman) != 0 ||
+ rman_manage_region(&sc->sc_irq_rman, 1, 31) != 0)
+ panic("at91_attach: failed to set up IRQ rman");
+ if (rman_init(&sc->sc_mem_rman) != 0 ||
+ rman_manage_region(&sc->sc_mem_rman, 0xfff00000ul,
+ 0xfffffffful) != 0)
+ panic("at91_attach: failed to set up memory rman");
+
+ for (i = 0; i < 32; i++) {
+ bus_space_write_4(sc->sc_st, sc->sc_sys_sh, IC_SVR +
+ i * 4, i);
+ /* Priority. */
+ /* XXX: Give better priorities to IRQs */
+ bus_space_write_4(sc->sc_st, sc->sc_sys_sh, IC_SMR + i * 4,
+ 0);
+ if (i < 8)
+ bus_space_write_4(sc->sc_st, sc->sc_sys_sh, IC_EOICR,
+ 1);
+
+ }
+ bus_space_write_4(sc->sc_st, sc->sc_sys_sh, IC_SPU, 32);
+ /* No debug. */
+ bus_space_write_4(sc->sc_st, sc->sc_sys_sh, IC_DCR, 0);
+ /* Disable and clear all interrupts. */
+ bus_space_write_4(sc->sc_st, sc->sc_sys_sh, IC_IDCR, 0xffffffff);
+ bus_space_write_4(sc->sc_st, sc->sc_sys_sh, IC_ICCR, 0xffffffff);
+
+ /* XXX */
+ /* Disable all interrupts for RTC (0xe24 == RTC_IDR) */
+ bus_space_write_4(sc->sc_st, sc->sc_sys_sh, 0xe24, 0xffffffff);
+ /* Disable all interrupts for PMC (0xc64 == PMC_IDR) */
+ bus_space_write_4(sc->sc_st, sc->sc_sys_sh, 0xc64, 0xffffffff);
+ /* Disable all interrupts for ST */
+ bus_space_write_4(sc->sc_st, sc->sc_sys_sh, 0xd18, 0xffffffff);
+ /* DIsable all interrupts for DBGU */
+ bus_space_write_4(sc->sc_st, sc->sc_sys_sh, 0x20c, 0xffffffff);
+ /* Disable all interrupts for PIOA */
+ bus_space_write_4(sc->sc_st, sc->sc_sys_sh, 0x444, 0xffffffff);
+ /* Disable all interrupts for PIOB */
+ bus_space_write_4(sc->sc_st, sc->sc_sys_sh, 0x644, 0xffffffff);
+ /* Disable all interrupts for PIOC */
+ bus_space_write_4(sc->sc_st, sc->sc_sys_sh, 0x844, 0xffffffff);
+ /* Disable all interrupts for PIOD */
+ bus_space_write_4(sc->sc_st, sc->sc_sys_sh, 0xa44, 0xffffffff);
+ /* Disable all interrupts for the SDRAM controller */
+ bus_space_write_4(sc->sc_st, sc->sc_sys_sh, 0xfa8, 0xffffffff);
+ at91_add_child(dev, 0, "at91_st", 0, 0, 0, 1);
+ at91_add_child(dev, 10, "at91_udp", 0, AT91RM92_BASE + // UDP
+ AT91RM92_UDP_BASE, AT91RM92_UDP_SIZE, AT91RM92_IRQ_UDP);
+ at91_add_child(dev, 10, "at91_mci", 0, AT91RM92_BASE + // MCI
+ AT91RM92_MCI_BASE, AT91RM92_MCI_SIZE, AT91RM92_IRQ_MCI);
+ at91_add_child(dev, 10, "at91_twi", 0, AT91RM92_BASE + // TWI
+ AT91RM92_TWI_BASE, AT91RM92_TWI_SIZE, AT91RM92_IRQ_TWI);
+ at91_add_child(dev, 10, "ate", 0, AT91RM92_BASE + // EMAC
+ AT91RM92_EMAC_BASE, AT91RM92_EMAC_SIZE, AT91RM92_IRQ_EMAC);
+ at91_add_child(dev, 10, "uart", 0, AT91RM92_BASE + // DBGU
+ AT91RM92_SYS_BASE + DBGU, DBGU_SIZE, AT91RM92_IRQ_SYSTEM);
+ at91_add_child(dev, 10, "uart", 1, AT91RM92_BASE + // USART0
+ AT91RM92_USART0_BASE, AT91RM92_USART_SIZE, AT91RM92_IRQ_USART0);
+ at91_add_child(dev, 10, "uart", 2, AT91RM92_BASE + // USART1
+ AT91RM92_USART1_BASE, AT91RM92_USART_SIZE, AT91RM92_IRQ_USART1);
+ at91_add_child(dev, 10, "uart", 3, AT91RM92_BASE + // USART2
+ AT91RM92_USART2_BASE, AT91RM92_USART_SIZE, AT91RM92_IRQ_USART2);
+ at91_add_child(dev, 10, "uart", 4, AT91RM92_BASE + // USART3
+ AT91RM92_USART3_BASE, AT91RM92_USART_SIZE, AT91RM92_IRQ_USART3);
+ at91_add_child(dev, 10, "at91_ssc", 0, AT91RM92_BASE + // SSC0
+ AT91RM92_SSC0_BASE, AT91RM92_SSC_SIZE, AT91RM92_IRQ_SSC0);
+ at91_add_child(dev, 10, "at91_ssc", 1, AT91RM92_BASE + // SSC1
+ AT91RM92_SSC1_BASE, AT91RM92_SSC_SIZE, AT91RM92_IRQ_SSC1);
+ at91_add_child(dev, 10, "at91_ssc", 2, AT91RM92_BASE + // SSC2
+ AT91RM92_SSC2_BASE, AT91RM92_SSC_SIZE, AT91RM92_IRQ_SSC2);
+ at91_add_child(dev, 10, "at91_spi", 0, AT91RM92_BASE + // SPI
+ AT91RM92_SPI_BASE, AT91RM92_SPI_SIZE, AT91RM92_IRQ_SPI);
+ // Not sure that the following belongs on this bus.
+ at91_add_child(dev, 10, "ohci", 0, AT91RM92_BASE + // UHP
+ AT91RM92_OHCI_BASE, AT91RM92_OHCI_SIZE, AT91RM92_IRQ_UHP);
+ bus_generic_probe(dev);
+ bus_generic_attach(dev);
+ enable_interrupts(I32_bit | F32_bit);
+ return (0);
+}
+
+static struct resource *
+at91_alloc_resource(device_t dev, device_t child, int type, int *rid,
+ u_long start, u_long end, u_long count, u_int flags)
+{
+ struct at91_softc *sc = device_get_softc(dev);
+ struct resource_list_entry *rle;
+ struct at91_ivar *ivar = device_get_ivars(child);
+ struct resource_list *rl = &ivar->resources;
+
+ if (device_get_parent(child) != dev)
+ return (BUS_ALLOC_RESOURCE(device_get_parent(dev), child,
+ type, rid, start, end, count, flags));
+
+ rle = resource_list_find(rl, type, *rid);
+ if (rle == NULL)
+ return (NULL);
+ if (rle->res)
+ panic("Resource rid %d type %d already in use", *rid, type);
+ if (start == 0UL && end == ~0UL) {
+ start = rle->start;
+ count = ulmax(count, rle->count);
+ end = ulmax(rle->end, start + count - 1);
+ }
+ switch (type)
+ {
+ case SYS_RES_IRQ:
+ rle->res = rman_reserve_resource(&sc->sc_irq_rman,
+ start, end, count, flags, child);
+ break;
+ case SYS_RES_MEMORY:
+ rle->res = rman_reserve_resource(&sc->sc_mem_rman,
+ start, end, count, flags, child);
+ rman_set_bustag(rle->res, &at91_bs_tag);
+ rman_set_bushandle(rle->res, start);
+ break;
+ }
+ if (rle->res) {
+ rle->start = rman_get_start(rle->res);
+ rle->end = rman_get_end(rle->res);
+ rle->count = count;
+ }
+ return (rle->res);
+}
+
+static struct resource_list *
+at91_get_resource_list(device_t dev, device_t child)
+{
+ struct at91_ivar *ivar;
+
+ ivar = device_get_ivars(child);
+ return (&(ivar->resources));
+}
+
+static int
+at91_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 = at91_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
+at91_setup_intr(device_t dev, device_t child,
+ struct resource *ires, int flags, driver_intr_t *intr, void *arg,
+ void **cookiep)
+{
+ struct at91_softc *sc = device_get_softc(dev);
+
+ BUS_SETUP_INTR(device_get_parent(dev), child, ires, flags, intr, arg,
+ cookiep);
+ bus_space_write_4(sc->sc_st, sc->sc_sys_sh, IC_IECR,
+ 1 << rman_get_start(ires));
+ return (0);
+}
+
+static int
+at91_teardown_intr(device_t dev, device_t child, struct resource *res,
+ void *cookie)
+{
+ struct at91_softc *sc = device_get_softc(dev);
+
+ bus_space_write_4(sc->sc_st, sc->sc_sys_sh, IC_IDCR,
+ 1 << rman_get_start(res));
+ return (BUS_TEARDOWN_INTR(device_get_parent(dev), child, res, cookie));
+}
+
+static int
+at91_activate_resource(device_t bus, device_t child, int type, int rid,
+ struct resource *r)
+{
+#if 0
+ u_long p;
+ int error;
+
+ if (type == SYS_RES_MEMORY) {
+ error = bus_space_map(rman_get_bustag(r),
+ rman_get_bushandle(r), rman_get_size(r), 0, &p);
+ if (error)
+ return (error);
+ rman_set_bushandle(r, p);
+ }
+#endif
+ return (rman_activate_resource(r));
+}
+
+static int
+at91_print_child(device_t dev, device_t child)
+{
+ struct at91_ivar *ivars;
+ struct resource_list *rl;
+ int retval = 0;
+
+ ivars = device_get_ivars(child);
+ rl = &ivars->resources;
+
+ retval += bus_print_child_header(dev, child);
+
+ retval += resource_list_print_type(rl, "port", SYS_RES_IOPORT, "%#lx");
+ retval += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#lx");
+ retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%ld");
+ if (device_get_flags(dev))
+ retval += printf(" flags %#x", device_get_flags(dev));
+
+ retval += bus_print_child_footer(dev, child);
+
+ return (retval);
+}
+
+void
+arm_mask_irq(uintptr_t nb)
+{
+
+ bus_space_write_4(at91_softc->sc_st,
+ at91_softc->sc_sys_sh, IC_IDCR, 1 << nb);
+
+}
+
+int
+arm_get_next_irq()
+{
+
+ int status;
+ int irq;
+
+ irq = bus_space_read_4(at91_softc->sc_st,
+ at91_softc->sc_sys_sh, IC_IVR);
+ status = bus_space_read_4(at91_softc->sc_st,
+ at91_softc->sc_sys_sh, IC_ISR);
+ if (status == 0) {
+ bus_space_write_4(at91_softc->sc_st,
+ at91_softc->sc_sys_sh, IC_EOICR, 1);
+ return (-1);
+ }
+ return (irq);
+}
+
+void
+arm_unmask_irq(uintptr_t nb)
+{
+
+ bus_space_write_4(at91_softc->sc_st,
+ at91_softc->sc_sys_sh, IC_IECR, 1 << nb);
+ bus_space_write_4(at91_softc->sc_st, at91_softc->sc_sys_sh,
+ IC_EOICR, 0);
+
+}
+
+static device_method_t at91_methods[] = {
+ DEVMETHOD(device_probe, at91_probe),
+ DEVMETHOD(device_attach, at91_attach),
+ DEVMETHOD(device_identify, at91_identify),
+
+ DEVMETHOD(bus_alloc_resource, at91_alloc_resource),
+ DEVMETHOD(bus_setup_intr, at91_setup_intr),
+ DEVMETHOD(bus_teardown_intr, at91_teardown_intr),
+ DEVMETHOD(bus_activate_resource, at91_activate_resource),
+ DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
+ DEVMETHOD(bus_get_resource_list,at91_get_resource_list),
+ DEVMETHOD(bus_set_resource, bus_generic_rl_set_resource),
+ DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource),
+ DEVMETHOD(bus_release_resource, at91_release_resource),
+ DEVMETHOD(bus_print_child, at91_print_child),
+
+ {0, 0},
+};
+
+static driver_t at91_driver = {
+ "atmelarm",
+ at91_methods,
+ sizeof(struct at91_softc),
+};
+static devclass_t at91_devclass;
+
+DRIVER_MODULE(atmelarm, nexus, at91_driver, at91_devclass, 0, 0);
diff --git a/sys/arm/at91/at91_spi.c b/sys/arm/at91/at91_spi.c
new file mode 100644
index 0000000..8d91f7d
--- /dev/null
+++ b/sys/arm/at91/at91_spi.c
@@ -0,0 +1,451 @@
+/*-
+ * Copyright (c) 2006 M. Warner Losh. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <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/lock.h>
+#include <sys/mbuf.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/rman.h>
+#include <machine/bus.h>
+
+#include <arm/at91/at91_spireg.h>
+#include <arm/at91/at91_spiio.h>
+
+struct at91_spi_softc
+{
+ device_t dev; /* Myself */
+ void *intrhand; /* Interrupt handle */
+ struct resource *irq_res; /* IRQ resource */
+ struct resource *mem_res; /* Memory resource */
+ struct mtx sc_mtx; /* basically a perimeter lock */
+ int flags;
+#define XFER_PENDING 1 /* true when transfer taking place */
+#define OPENED 2 /* Device opened */
+#define RXRDY 4
+#define TXCOMP 8
+#define TXRDY 0x10
+ struct cdev *cdev;
+};
+
+static inline uint32_t
+RD4(struct at91_spi_softc *sc, bus_size_t off)
+{
+ return bus_read_4(sc->mem_res, off);
+}
+
+static inline void
+WR4(struct at91_spi_softc *sc, bus_size_t off, uint32_t val)
+{
+ bus_write_4(sc->mem_res, off, val);
+}
+
+#define AT91_SPI_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx)
+#define AT91_SPI_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx)
+#define AT91_SPI_LOCK_INIT(_sc) \
+ mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->dev), \
+ "spi", MTX_DEF)
+#define AT91_SPI_LOCK_DESTROY(_sc) mtx_destroy(&_sc->sc_mtx);
+#define AT91_SPI_ASSERT_LOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_OWNED);
+#define AT91_SPI_ASSERT_UNLOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_NOTOWNED);
+#define CDEV2SOFTC(dev) ((dev)->si_drv1)
+
+static devclass_t at91_spi_devclass;
+
+/* bus entry points */
+
+static int at91_spi_probe(device_t dev);
+static int at91_spi_attach(device_t dev);
+static int at91_spi_detach(device_t dev);
+static void at91_spi_intr(void *);
+
+/* helper routines */
+static int at91_spi_activate(device_t dev);
+static void at91_spi_deactivate(device_t dev);
+
+/* cdev routines */
+static d_open_t at91_spi_open;
+static d_close_t at91_spi_close;
+static d_ioctl_t at91_spi_ioctl;
+
+static struct cdevsw at91_spi_cdevsw =
+{
+ .d_version = D_VERSION,
+ .d_open = at91_spi_open,
+ .d_close = at91_spi_close,
+ .d_ioctl = at91_spi_ioctl
+};
+
+static int
+at91_spi_probe(device_t dev)
+{
+ device_set_desc(dev, "SPI");
+ return (0);
+}
+
+static int
+at91_spi_attach(device_t dev)
+{
+ struct at91_spi_softc *sc = device_get_softc(dev);
+ int err;
+
+ sc->dev = dev;
+ err = at91_spi_activate(dev);
+ if (err)
+ goto out;
+
+ AT91_SPI_LOCK_INIT(sc);
+
+ /*
+ * Activate the interrupt
+ */
+ err = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC | INTR_MPSAFE,
+ at91_spi_intr, sc, &sc->intrhand);
+ if (err) {
+ AT91_SPI_LOCK_DESTROY(sc);
+ goto out;
+ }
+ sc->cdev = make_dev(&at91_spi_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600,
+ "spi%d", device_get_unit(dev));
+ if (sc->cdev == NULL) {
+ err = ENOMEM;
+ goto out;
+ }
+ sc->cdev->si_drv1 = sc;
+#if 0
+ /* init */
+ sc->cwgr = SPI_CWGR_CKDIV(1) |
+ SPI_CWGR_CHDIV(SPI_CWGR_DIV(SPI_DEF_CLK)) |
+ SPI_CWGR_CLDIV(SPI_CWGR_DIV(SPI_DEF_CLK));
+
+ WR4(sc, SPI_CR, SPI_CR_SWRST);
+ WR4(sc, SPI_CR, SPI_CR_MSEN | SPI_CR_SVDIS);
+ WR4(sc, SPI_CWGR, sc->cwgr);
+#endif
+out:;
+ if (err)
+ at91_spi_deactivate(dev);
+ return (err);
+}
+
+static int
+at91_spi_detach(device_t dev)
+{
+ return (EBUSY); /* XXX */
+}
+
+static int
+at91_spi_activate(device_t dev)
+{
+ struct at91_spi_softc *sc;
+ int rid;
+
+ sc = device_get_softc(dev);
+ rid = 0;
+ sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
+ RF_ACTIVE);
+ if (sc->mem_res == NULL)
+ goto errout;
+ rid = 0;
+ sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
+ RF_ACTIVE);
+ if (sc->mem_res == NULL)
+ goto errout;
+ return (0);
+errout:
+ at91_spi_deactivate(dev);
+ return (ENOMEM);
+}
+
+static void
+at91_spi_deactivate(device_t dev)
+{
+ struct at91_spi_softc *sc;
+
+ sc = device_get_softc(dev);
+ if (sc->intrhand)
+ bus_teardown_intr(dev, sc->irq_res, sc->intrhand);
+ sc->intrhand = 0;
+ bus_generic_detach(sc->dev);
+ if (sc->mem_res)
+ bus_release_resource(dev, SYS_RES_IOPORT,
+ rman_get_rid(sc->mem_res), sc->mem_res);
+ sc->mem_res = 0;
+ if (sc->irq_res)
+ bus_release_resource(dev, SYS_RES_IRQ,
+ rman_get_rid(sc->irq_res), sc->irq_res);
+ sc->irq_res = 0;
+ return;
+}
+
+static void
+at91_spi_intr(void *xsc)
+{
+ struct at91_spi_softc *sc = xsc;
+#if 0
+ uint32_t status;
+
+ /* Reading the status also clears the interrupt */
+ status = RD4(sc, SPI_SR);
+ if (status == 0)
+ return;
+ AT91_SPI_LOCK(sc);
+ if (status & SPI_SR_RXRDY)
+ sc->flags |= RXRDY;
+ if (status & SPI_SR_TXCOMP)
+ sc->flags |= TXCOMP;
+ if (status & SPI_SR_TXRDY)
+ sc->flags |= TXRDY;
+ AT91_SPI_UNLOCK(sc);
+#endif
+ wakeup(sc);
+ return;
+}
+
+static int
+at91_spi_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
+{
+ struct at91_spi_softc *sc;
+
+ sc = CDEV2SOFTC(dev);
+ AT91_SPI_LOCK(sc);
+ if (!(sc->flags & OPENED)) {
+ sc->flags |= OPENED;
+#if 0
+ WR4(sc, SPI_IER, SPI_SR_TXCOMP | SPI_SR_RXRDY | SPI_SR_TXRDY |
+ SPI_SR_OVRE | SPI_SR_UNRE | SPI_SR_NACK);
+#endif
+ }
+ AT91_SPI_UNLOCK(sc);
+ return (0);
+}
+
+static int
+at91_spi_close(struct cdev *dev, int fflag, int devtype, struct thread *td)
+{
+ struct at91_spi_softc *sc;
+
+ sc = CDEV2SOFTC(dev);
+ AT91_SPI_LOCK(sc);
+ sc->flags &= ~OPENED;
+#if 0
+ WR4(sc, SPI_IDR, SPI_SR_TXCOMP | SPI_SR_RXRDY | SPI_SR_TXRDY |
+ SPI_SR_OVRE | SPI_SR_UNRE | SPI_SR_NACK);
+#endif
+ AT91_SPI_UNLOCK(sc);
+ return (0);
+}
+
+static int
+at91_spi_read_master(struct at91_spi_softc *sc, struct at91_spi_io *xfr)
+{
+#if 1
+ return ENOTTY;
+#else
+ uint8_t *walker;
+ uint8_t buffer[256];
+ size_t len;
+ int err = 0;
+
+ if (xfr->xfer_len > sizeof(buffer))
+ return (EINVAL);
+ walker = buffer;
+ len = xfr->xfer_len;
+ RD4(sc, SPI_RHR);
+ // Master mode, with the right address and interal addr size
+ WR4(sc, SPI_MMR, SPI_MMR_IADRSZ(xfr->iadrsz) | SPI_MMR_MREAD |
+ SPI_MMR_DADR(xfr->dadr));
+ WR4(sc, SPI_IADR, xfr->iadr);
+ WR4(sc, SPI_CR, SPI_CR_START);
+ while (len-- > 1) {
+ while (!(sc->flags & RXRDY)) {
+ err = msleep(sc, &sc->sc_mtx, PZERO | PCATCH, "spird",
+ 0);
+ if (err)
+ return (err);
+ }
+ sc->flags &= ~RXRDY;
+ *walker++ = RD4(sc, SPI_RHR) & 0xff;
+ }
+ WR4(sc, SPI_CR, SPI_CR_STOP);
+ while (!(sc->flags & TXCOMP)) {
+ err = msleep(sc, &sc->sc_mtx, PZERO | PCATCH, "spird2", 0);
+ if (err)
+ return (err);
+ }
+ sc->flags &= ~TXCOMP;
+ *walker = RD4(sc, SPI_RHR) & 0xff;
+ if (xfr->xfer_buf) {
+ AT91_SPI_UNLOCK(sc);
+ err = copyout(buffer, xfr->xfer_buf, xfr->xfer_len);
+ AT91_SPI_LOCK(sc);
+ }
+ return (err);
+#endif
+}
+
+static int
+at91_spi_write_master(struct at91_spi_softc *sc, struct at91_spi_io *xfr)
+{
+#if 1
+ return ENOTTY;
+#else
+ uint8_t *walker;
+ uint8_t buffer[256];
+ size_t len;
+ int err;
+
+ if (xfr->xfer_len > sizeof(buffer))
+ return (EINVAL);
+ walker = buffer;
+ len = xfr->xfer_len;
+ AT91_SPI_UNLOCK(sc);
+ err = copyin(xfr->xfer_buf, buffer, xfr->xfer_len);
+ AT91_SPI_LOCK(sc);
+ if (err)
+ return (err);
+ /* Setup the xfr for later readback */
+ xfr->xfer_buf = 0;
+ xfr->xfer_len = 1;
+ while (len--) {
+ WR4(sc, SPI_MMR, SPI_MMR_IADRSZ(xfr->iadrsz) | SPI_MMR_MWRITE |
+ SPI_MMR_DADR(xfr->dadr));
+ WR4(sc, SPI_IADR, xfr->iadr++);
+ WR4(sc, SPI_THR, *walker++);
+ WR4(sc, SPI_CR, SPI_CR_START);
+ /*
+ * If we get signal while waiting for TXRDY, make sure we
+ * try to stop this device
+ */
+ while (!(sc->flags & TXRDY)) {
+ err = msleep(sc, &sc->sc_mtx, PZERO | PCATCH, "spiwr",
+ 0);
+ if (err)
+ break;
+ }
+ WR4(sc, SPI_CR, SPI_CR_STOP);
+ if (err)
+ return (err);
+ while (!(sc->flags & TXCOMP)) {
+ err = msleep(sc, &sc->sc_mtx, PZERO | PCATCH, "spiwr2",
+ 0);
+ if (err)
+ return (err);
+ }
+ /* Readback */
+ at91_spi_read_master(sc, xfr);
+ }
+ return (err);
+#endif
+}
+
+static int
+at91_spi_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag,
+ struct thread *td)
+{
+ int err = 0;
+ struct at91_spi_softc *sc;
+
+ sc = CDEV2SOFTC(dev);
+ AT91_SPI_LOCK(sc);
+ while (sc->flags & XFER_PENDING) {
+ err = msleep(sc, &sc->sc_mtx, PZERO | PCATCH,
+ "spiwait", 0);
+ if (err) {
+ AT91_SPI_UNLOCK(sc);
+ return (err);
+ }
+ }
+ sc->flags |= XFER_PENDING;
+
+ switch (cmd)
+ {
+ case SPIIOCXFER:
+ {
+ struct at91_spi_io *xfr = (struct at91_spi_io *)data;
+ switch (xfr->type)
+ {
+ case SPI_IO_READ_MASTER:
+ err = at91_spi_read_master(sc, xfr);
+ break;
+ case SPI_IO_WRITE_MASTER:
+ err = at91_spi_write_master(sc, xfr);
+ break;
+ default:
+ err = EINVAL;
+ break;
+ }
+ break;
+ }
+
+ case SPIIOCSETCLOCK:
+ {
+#if 0
+ struct at91_spi_clock *spick = (struct at91_spi_clock *)data;
+
+ sc->cwgr = SPI_CWGR_CKDIV(spick->ckdiv) |
+ SPI_CWGR_CHDIV(SPI_CWGR_DIV(spick->high_rate)) |
+ SPI_CWGR_CLDIV(SPI_CWGR_DIV(spick->low_rate));
+ WR4(sc, SPI_CR, SPI_CR_SWRST);
+ WR4(sc, SPI_CR, SPI_CR_MSEN | SPI_CR_SVDIS);
+ WR4(sc, SPI_CWGR, sc->cwgr);
+#else
+ err = ENOTTY;
+#endif
+ break;
+ }
+ default:
+ err = ENOTTY;
+ break;
+ }
+ sc->flags &= ~XFER_PENDING;
+ AT91_SPI_UNLOCK(sc);
+ wakeup(sc);
+ return err;
+}
+
+static device_method_t at91_spi_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, at91_spi_probe),
+ DEVMETHOD(device_attach, at91_spi_attach),
+ DEVMETHOD(device_detach, at91_spi_detach),
+
+ { 0, 0 }
+};
+
+static driver_t at91_spi_driver = {
+ "at91_spi",
+ at91_spi_methods,
+ sizeof(struct at91_spi_softc),
+};
+
+DRIVER_MODULE(at91_spi, atmelarm, at91_spi_driver, at91_spi_devclass, 0, 0);
diff --git a/sys/arm/at91/at91_spiio.h b/sys/arm/at91/at91_spiio.h
new file mode 100644
index 0000000..457259e
--- /dev/null
+++ b/sys/arm/at91/at91_spiio.h
@@ -0,0 +1,61 @@
+/*-
+ * Copyright (c) 2006 M. Warner Losh. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _ARM_AT91_AT91_SPIIO_H
+#define _ARM_AT91_AT91_SPIIO_H
+
+#include <sys/ioccom.h>
+
+struct at91_spi_io
+{
+ int dadr; /* Device address */
+ int type; /* read/write */
+#define SPI_IO_READ_MASTER 1
+#define SPI_IO_WRITE_MASTER 2
+ int iadrsz; /* Internal addr size */
+ uint32_t iadr; /* Interbak addr */
+ size_t xfer_len; /* Size to transfer */
+ caddr_t xfer_buf; /* buffer for xfer */
+};
+
+struct at91_spi_clock
+{
+ int ckdiv; /* Clock divider */
+ int high_rate; /* rate of clock high period */
+ int low_rate; /* rate of clock low period */
+};
+
+/** SPIIOCXFER: Do a two-wire transfer
+ */
+#define SPIIOCXFER _IOW('x', 1, struct at91_spi_io)
+
+/** SPIIOCSETCLOCK: Sets the clocking parameters for this operation.
+ */
+#define SPIIOCSETCLOCK _IOW('x', 2, struct at91_spi_clock)
+
+#endif /* !_ARM_AT91_AT91_SPIIO_H */
+
+
diff --git a/sys/arm/at91/at91_spireg.h b/sys/arm/at91/at91_spireg.h
new file mode 100644
index 0000000..10fb259
--- /dev/null
+++ b/sys/arm/at91/at91_spireg.h
@@ -0,0 +1,30 @@
+/*-
+ * Copyright (c) 2006 M. Warner Losh. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* $FreeBSD$ */
+
+#ifndef ARM_AT91_AT91_SPIREG_H
+#define ARM_AT91_AT91_SPIREG_H
+
+#endif /* ARM_AT91_AT91_SPIREG_H */
diff --git a/sys/arm/at91/at91_st.c b/sys/arm/at91/at91_st.c
new file mode 100644
index 0000000..8d77683
--- /dev/null
+++ b/sys/arm/at91/at91_st.c
@@ -0,0 +1,215 @@
+/*-
+ * Copyright (c) 2005 Olivier Houchard. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/time.h>
+#include <sys/bus.h>
+#include <sys/resource.h>
+#include <sys/rman.h>
+#include <sys/timetc.h>
+
+#include <machine/bus.h>
+#include <machine/cpu.h>
+#include <machine/cpufunc.h>
+#include <machine/resource.h>
+#include <machine/frame.h>
+#include <machine/intr.h>
+#include <arm/at91/at91rm92reg.h>
+#include <arm/at91/at91var.h>
+#include <arm/at91/at91_streg.h>
+
+static struct at91st_softc {
+ bus_space_tag_t sc_st;
+ bus_space_handle_t sc_sh;
+ device_t dev;
+} *timer_softc;
+
+#define RD4(off) \
+ bus_space_read_4(timer_softc->sc_st, timer_softc->sc_sh, (off))
+#define WR4(off, val) \
+ bus_space_write_4(timer_softc->sc_st, timer_softc->sc_sh, (off), (val))
+
+static inline int
+st_crtr(void)
+{
+ int cur1, cur2;
+ do {
+ cur1 = RD4(ST_CRTR);
+ cur2 = RD4(ST_CRTR);
+ } while (cur1 != cur2);
+ return (cur1);
+}
+
+static unsigned at91st_get_timecount(struct timecounter *tc);
+
+static struct timecounter at91st_timecounter = {
+ at91st_get_timecount, /* get_timecount */
+ NULL, /* no poll_pps */
+ 0xfffffu, /* counter_mask */
+ 32768, /* frequency */
+ "AT91RM9200 timer", /* name */
+ 0 /* quality */
+};
+
+static int
+at91st_probe(device_t dev)
+{
+
+ device_set_desc(dev, "ST");
+ return (0);
+}
+
+static int
+at91st_attach(device_t dev)
+{
+ struct at91_softc *sc = device_get_softc(device_get_parent(dev));
+
+ timer_softc = device_get_softc(dev);
+ timer_softc->sc_st = sc->sc_st;
+ timer_softc->dev = dev;
+ if (bus_space_subregion(sc->sc_st, sc->sc_sh, AT91RM92_ST_BASE,
+ AT91RM92_ST_SIZE, &timer_softc->sc_sh) != 0)
+ panic("couldn't subregion timer registers");
+ /*
+ * Real time counter increments every clock cycle, need to set before
+ * initializing clocks so that DELAY works.
+ */
+ WR4(ST_RTMR, 1);
+
+ return (0);
+}
+
+static device_method_t at91st_methods[] = {
+ DEVMETHOD(device_probe, at91st_probe),
+ DEVMETHOD(device_attach, at91st_attach),
+ {0, 0},
+};
+
+static driver_t at91st_driver = {
+ "at91_st",
+ at91st_methods,
+ sizeof(struct at91st_softc),
+};
+static devclass_t at91st_devclass;
+
+DRIVER_MODULE(at91_st, atmelarm, at91st_driver, at91st_devclass, 0, 0);
+
+static unsigned
+at91st_get_timecount(struct timecounter *tc)
+{
+ return (st_crtr());
+}
+
+static void
+clock_intr(void *arg)
+{
+ struct trapframe *fp = arg;
+
+ /* The interrupt is shared, so we have to make sure it's for us. */
+ if (RD4(ST_SR) & ST_SR_PITS)
+ hardclock(TRAPF_USERMODE(fp), TRAPF_PC(fp));
+}
+
+void
+cpu_initclocks(void)
+{
+ int rel_value;
+ struct resource *irq;
+ int rid = 0;
+ void *ih;
+ device_t dev = timer_softc->dev;
+
+ if (32768 % hz) {
+ printf("Cannot get %d Hz clock; using 128Hz\n", hz);
+ hz = 128;
+ }
+ rel_value = 32768 / hz;
+ /* Disable all interrupts. */
+ WR4(ST_IDR, 0xffffffff);
+ /* The system timer shares the system irq (1) */
+ irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 1, 1, 1,
+ RF_ACTIVE | RF_SHAREABLE);
+ if (!irq)
+ panic("Unable to allocate irq for the system timer");
+ else
+ bus_setup_intr(dev, irq, INTR_TYPE_CLK | INTR_FAST,
+ clock_intr, NULL, &ih);
+
+ WR4(ST_PIMR, rel_value);
+
+ /* Enable PITS interrupts. */
+ WR4(ST_IER, ST_SR_PITS);
+ tc_init(&at91st_timecounter);
+}
+
+void
+DELAY(int n)
+{
+ uint32_t start, end, cur;
+
+ start = st_crtr();
+ n = (n * 1000000) / 32768;
+ if (n <= 0)
+ n = 1;
+ end = (start + n) & ST_CRTR_MASK;
+ cur = start;
+ if (start > end) {
+ while (cur >= start || cur < end)
+ cur = st_crtr();
+ } else {
+ while (cur < end)
+ cur = st_crtr();
+ }
+}
+
+void
+cpu_reset(void)
+{
+ /*
+ * Reset the CPU by programmig the watchdog timer to reset the
+ * CPU after 128 'slow' clocks, or about ~4ms. Loop until
+ * the reset happens for safety.
+ */
+ WR4(ST_WDMR, ST_WDMR_RSTEN | 2);
+ WR4(ST_CR, ST_CR_WDRST);
+ while (1)
+ continue;
+}
+
+void
+cpu_startprofclock(void)
+{
+}
+
+void
+cpu_stopprofclock(void)
+{
+}
+
diff --git a/sys/arm/at91/at91_streg.h b/sys/arm/at91/at91_streg.h
new file mode 100644
index 0000000..cdf3f30
--- /dev/null
+++ b/sys/arm/at91/at91_streg.h
@@ -0,0 +1,57 @@
+/*-
+ * Copyright (c) 2005 M. Warner Losh. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* $FreeBSD$ */
+
+#ifndef ARM_AT91_AT91STREG_H
+#define ARM_AT91_AT91STREG_H
+
+#define ST_CR 0x00 /* Control register */
+#define ST_PIMR 0x04 /* Period interval mode register */
+#define ST_WDMR 0x08 /* Watchdog mode register */
+#define ST_RTMR 0x0c /* Real-time mode register */
+#define ST_SR 0x10 /* Status register */
+#define ST_IER 0x14 /* Interrupt enable register */
+#define ST_IDR 0x18 /* Interrupt disable register */
+#define ST_IMR 0x1c /* Interrupt mask register */
+#define ST_RTAR 0x20 /* Real-time alarm register */
+#define ST_CRTR 0x24 /* Current real-time register */
+
+/* ST_CR */
+#define ST_CR_WDRST (1U << 0) /* WDRST: Watchdog Timer Restart */
+
+/* ST_WDMR */
+#define ST_WDMR_EXTEN (1U << 17) /* EXTEN: External Signal Assert Enable */
+#define ST_WDMR_RSTEN (1U << 16) /* RSTEN: Reset Enable */
+
+/* ST_SR, ST_IER, ST_IDR, ST_IMR */
+#define ST_SR_PITS (1U << 0) /* PITS: Period Interval Timer Status */
+#define ST_SR_WDOVF (1U << 1) /* WDOVF: Watchdog Overflow */
+#define ST_SR_RTTINC (1U << 2) /* RTTINC: Real-time Timer Increment */
+#define ST_SR_ALMS (1U << 3) /* ALMS: Alarm Status */
+
+/* ST_CRTR */
+#define ST_CRTR_MASK 0xfffff /* 20-bit counter */
+
+#endif /* ARM_AT91_AT91STREG_H */
diff --git a/sys/arm/at91/at91_twi.c b/sys/arm/at91/at91_twi.c
new file mode 100644
index 0000000..142f1f9
--- /dev/null
+++ b/sys/arm/at91/at91_twi.c
@@ -0,0 +1,434 @@
+/*-
+ * Copyright (c) 2006 M. Warner Losh. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <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/lock.h>
+#include <sys/mbuf.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/rman.h>
+#include <machine/bus.h>
+
+#include <arm/at91/at91rm92reg.h>
+#include <arm/at91/at91_twireg.h>
+#include <arm/at91/at91_twiio.h>
+
+struct at91_twi_softc
+{
+ device_t dev; /* Myself */
+ void *intrhand; /* Interrupt handle */
+ struct resource *irq_res; /* IRQ resource */
+ struct resource *mem_res; /* Memory resource */
+ struct mtx sc_mtx; /* basically a perimeter lock */
+ int flags;
+#define XFER_PENDING 1 /* true when transfer taking place */
+#define OPENED 2 /* Device opened */
+#define RXRDY 4
+#define TXCOMP 8
+#define TXRDY 0x10
+ struct cdev *cdev;
+ uint32_t cwgr;
+};
+
+static inline uint32_t
+RD4(struct at91_twi_softc *sc, bus_size_t off)
+{
+ return bus_read_4(sc->mem_res, off);
+}
+
+static inline void
+WR4(struct at91_twi_softc *sc, bus_size_t off, uint32_t val)
+{
+ bus_write_4(sc->mem_res, off, val);
+}
+
+#define AT91_TWI_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx)
+#define AT91_TWI_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx)
+#define AT91_TWI_LOCK_INIT(_sc) \
+ mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->dev), \
+ "twi", MTX_DEF)
+#define AT91_TWI_LOCK_DESTROY(_sc) mtx_destroy(&_sc->sc_mtx);
+#define AT91_TWI_ASSERT_LOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_OWNED);
+#define AT91_TWI_ASSERT_UNLOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_NOTOWNED);
+#define CDEV2SOFTC(dev) ((dev)->si_drv1)
+#define TWI_DEF_CLK 100000
+
+static devclass_t at91_twi_devclass;
+
+/* bus entry points */
+
+static int at91_twi_probe(device_t dev);
+static int at91_twi_attach(device_t dev);
+static int at91_twi_detach(device_t dev);
+static void at91_twi_intr(void *);
+
+/* helper routines */
+static int at91_twi_activate(device_t dev);
+static void at91_twi_deactivate(device_t dev);
+
+/* cdev routines */
+static d_open_t at91_twi_open;
+static d_close_t at91_twi_close;
+static d_ioctl_t at91_twi_ioctl;
+
+static struct cdevsw at91_twi_cdevsw =
+{
+ .d_version = D_VERSION,
+ .d_open = at91_twi_open,
+ .d_close = at91_twi_close,
+ .d_ioctl = at91_twi_ioctl
+};
+
+static int
+at91_twi_probe(device_t dev)
+{
+ device_set_desc(dev, "TWI");
+ return (0);
+}
+
+static int
+at91_twi_attach(device_t dev)
+{
+ struct at91_twi_softc *sc = device_get_softc(dev);
+ int err;
+
+ sc->dev = dev;
+ err = at91_twi_activate(dev);
+ if (err)
+ goto out;
+
+ AT91_TWI_LOCK_INIT(sc);
+
+ /*
+ * Activate the interrupt
+ */
+ err = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC | INTR_MPSAFE,
+ at91_twi_intr, sc, &sc->intrhand);
+ if (err) {
+ AT91_TWI_LOCK_DESTROY(sc);
+ goto out;
+ }
+ sc->cdev = make_dev(&at91_twi_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600,
+ "twi%d", device_get_unit(dev));
+ if (sc->cdev == NULL) {
+ err = ENOMEM;
+ goto out;
+ }
+ sc->cdev->si_drv1 = sc;
+ sc->cwgr = TWI_CWGR_CKDIV(1) |
+ TWI_CWGR_CHDIV(TWI_CWGR_DIV(TWI_DEF_CLK)) |
+ TWI_CWGR_CLDIV(TWI_CWGR_DIV(TWI_DEF_CLK));
+
+ WR4(sc, TWI_CR, TWI_CR_SWRST);
+ WR4(sc, TWI_CR, TWI_CR_MSEN | TWI_CR_SVDIS);
+ WR4(sc, TWI_CWGR, sc->cwgr);
+out:;
+ if (err)
+ at91_twi_deactivate(dev);
+ return (err);
+}
+
+static int
+at91_twi_detach(device_t dev)
+{
+ return (EBUSY); /* XXX */
+}
+
+static int
+at91_twi_activate(device_t dev)
+{
+ struct at91_twi_softc *sc;
+ int rid;
+
+ sc = device_get_softc(dev);
+ rid = 0;
+ sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
+ RF_ACTIVE);
+ if (sc->mem_res == NULL)
+ goto errout;
+ rid = 0;
+ sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
+ RF_ACTIVE);
+ if (sc->mem_res == NULL)
+ goto errout;
+ return (0);
+errout:
+ at91_twi_deactivate(dev);
+ return (ENOMEM);
+}
+
+static void
+at91_twi_deactivate(device_t dev)
+{
+ struct at91_twi_softc *sc;
+
+ sc = device_get_softc(dev);
+ if (sc->intrhand)
+ bus_teardown_intr(dev, sc->irq_res, sc->intrhand);
+ sc->intrhand = 0;
+ bus_generic_detach(sc->dev);
+ if (sc->mem_res)
+ bus_release_resource(dev, SYS_RES_IOPORT,
+ rman_get_rid(sc->mem_res), sc->mem_res);
+ sc->mem_res = 0;
+ if (sc->irq_res)
+ bus_release_resource(dev, SYS_RES_IRQ,
+ rman_get_rid(sc->irq_res), sc->irq_res);
+ sc->irq_res = 0;
+ return;
+}
+
+static void
+at91_twi_intr(void *xsc)
+{
+ struct at91_twi_softc *sc = xsc;
+ uint32_t status;
+
+ /* Reading the status also clears the interrupt */
+ status = RD4(sc, TWI_SR);
+ if (status == 0)
+ return;
+ AT91_TWI_LOCK(sc);
+ if (status & TWI_SR_RXRDY)
+ sc->flags |= RXRDY;
+ if (status & TWI_SR_TXCOMP)
+ sc->flags |= TXCOMP;
+ if (status & TWI_SR_TXRDY)
+ sc->flags |= TXRDY;
+ AT91_TWI_UNLOCK(sc);
+ wakeup(sc);
+ return;
+}
+
+static int
+at91_twi_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
+{
+ struct at91_twi_softc *sc;
+
+ sc = CDEV2SOFTC(dev);
+ AT91_TWI_LOCK(sc);
+ if (!(sc->flags & OPENED)) {
+ sc->flags |= OPENED;
+ WR4(sc, TWI_IER, TWI_SR_TXCOMP | TWI_SR_RXRDY | TWI_SR_TXRDY |
+ TWI_SR_OVRE | TWI_SR_UNRE | TWI_SR_NACK);
+ }
+ AT91_TWI_UNLOCK(sc);
+ return (0);
+}
+
+static int
+at91_twi_close(struct cdev *dev, int fflag, int devtype, struct thread *td)
+{
+ struct at91_twi_softc *sc;
+
+ sc = CDEV2SOFTC(dev);
+ AT91_TWI_LOCK(sc);
+ sc->flags &= ~OPENED;
+ WR4(sc, TWI_IDR, TWI_SR_TXCOMP | TWI_SR_RXRDY | TWI_SR_TXRDY |
+ TWI_SR_OVRE | TWI_SR_UNRE | TWI_SR_NACK);
+ AT91_TWI_UNLOCK(sc);
+ return (0);
+}
+
+
+static int
+at91_twi_read_master(struct at91_twi_softc *sc, struct at91_twi_io *xfr)
+{
+ uint8_t *walker;
+ uint8_t buffer[256];
+ size_t len;
+ int err = 0;
+
+ if (xfr->xfer_len > sizeof(buffer))
+ return (EINVAL);
+ walker = buffer;
+ len = xfr->xfer_len;
+ RD4(sc, TWI_RHR);
+ // Master mode, with the right address and interal addr size
+ WR4(sc, TWI_MMR, TWI_MMR_IADRSZ(xfr->iadrsz) | TWI_MMR_MREAD |
+ TWI_MMR_DADR(xfr->dadr));
+ WR4(sc, TWI_IADR, xfr->iadr);
+ WR4(sc, TWI_CR, TWI_CR_START);
+ while (len-- > 1) {
+ while (!(sc->flags & RXRDY)) {
+ err = msleep(sc, &sc->sc_mtx, PZERO | PCATCH, "twird",
+ 0);
+ if (err)
+ return (err);
+ }
+ sc->flags &= ~RXRDY;
+ *walker++ = RD4(sc, TWI_RHR) & 0xff;
+ }
+ WR4(sc, TWI_CR, TWI_CR_STOP);
+ while (!(sc->flags & TXCOMP)) {
+ err = msleep(sc, &sc->sc_mtx, PZERO | PCATCH, "twird2", 0);
+ if (err)
+ return (err);
+ }
+ sc->flags &= ~TXCOMP;
+ *walker = RD4(sc, TWI_RHR) & 0xff;
+ if (xfr->xfer_buf) {
+ AT91_TWI_UNLOCK(sc);
+ err = copyout(buffer, xfr->xfer_buf, xfr->xfer_len);
+ AT91_TWI_LOCK(sc);
+ }
+ return (err);
+}
+
+static int
+at91_twi_write_master(struct at91_twi_softc *sc, struct at91_twi_io *xfr)
+{
+ uint8_t *walker;
+ uint8_t buffer[256];
+ size_t len;
+ int err;
+
+ if (xfr->xfer_len > sizeof(buffer))
+ return (EINVAL);
+ walker = buffer;
+ len = xfr->xfer_len;
+ AT91_TWI_UNLOCK(sc);
+ err = copyin(xfr->xfer_buf, buffer, xfr->xfer_len);
+ AT91_TWI_LOCK(sc);
+ if (err)
+ return (err);
+ /* Setup the xfr for later readback */
+ xfr->xfer_buf = 0;
+ xfr->xfer_len = 1;
+ while (len--) {
+ WR4(sc, TWI_MMR, TWI_MMR_IADRSZ(xfr->iadrsz) | TWI_MMR_MWRITE |
+ TWI_MMR_DADR(xfr->dadr));
+ WR4(sc, TWI_IADR, xfr->iadr++);
+ WR4(sc, TWI_THR, *walker++);
+ WR4(sc, TWI_CR, TWI_CR_START);
+ /*
+ * If we get signal while waiting for TXRDY, make sure we
+ * try to stop this device
+ */
+ while (!(sc->flags & TXRDY)) {
+ err = msleep(sc, &sc->sc_mtx, PZERO | PCATCH, "twiwr",
+ 0);
+ if (err)
+ break;
+ }
+ WR4(sc, TWI_CR, TWI_CR_STOP);
+ if (err)
+ return (err);
+ while (!(sc->flags & TXCOMP)) {
+ err = msleep(sc, &sc->sc_mtx, PZERO | PCATCH, "twiwr2",
+ 0);
+ if (err)
+ return (err);
+ }
+ /* Readback */
+ at91_twi_read_master(sc, xfr);
+ }
+ return (err);
+}
+
+static int
+at91_twi_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag,
+ struct thread *td)
+{
+ int err = 0;
+ struct at91_twi_softc *sc;
+
+ sc = CDEV2SOFTC(dev);
+ AT91_TWI_LOCK(sc);
+ while (sc->flags & XFER_PENDING) {
+ err = msleep(sc, &sc->sc_mtx, PZERO | PCATCH,
+ "twiwait", 0);
+ if (err) {
+ AT91_TWI_UNLOCK(sc);
+ return (err);
+ }
+ }
+ sc->flags |= XFER_PENDING;
+
+ switch (cmd)
+ {
+ case TWIIOCXFER:
+ {
+ struct at91_twi_io *xfr = (struct at91_twi_io *)data;
+ switch (xfr->type)
+ {
+ case TWI_IO_READ_MASTER:
+ err = at91_twi_read_master(sc, xfr);
+ break;
+ case TWI_IO_WRITE_MASTER:
+ err = at91_twi_write_master(sc, xfr);
+ break;
+ default:
+ err = EINVAL;
+ break;
+ }
+ break;
+ }
+
+ case TWIIOCSETCLOCK:
+ {
+ struct at91_twi_clock *twick = (struct at91_twi_clock *)data;
+
+ sc->cwgr = TWI_CWGR_CKDIV(twick->ckdiv) |
+ TWI_CWGR_CHDIV(TWI_CWGR_DIV(twick->high_rate)) |
+ TWI_CWGR_CLDIV(TWI_CWGR_DIV(twick->low_rate));
+ WR4(sc, TWI_CR, TWI_CR_SWRST);
+ WR4(sc, TWI_CR, TWI_CR_MSEN | TWI_CR_SVDIS);
+ WR4(sc, TWI_CWGR, sc->cwgr);
+ break;
+ }
+ default:
+ err = ENOTTY;
+ break;
+ }
+ sc->flags &= ~XFER_PENDING;
+ AT91_TWI_UNLOCK(sc);
+ wakeup(sc);
+ return err;
+}
+
+static device_method_t at91_twi_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, at91_twi_probe),
+ DEVMETHOD(device_attach, at91_twi_attach),
+ DEVMETHOD(device_detach, at91_twi_detach),
+
+ { 0, 0 }
+};
+
+static driver_t at91_twi_driver = {
+ "at91_twi",
+ at91_twi_methods,
+ sizeof(struct at91_twi_softc),
+};
+
+DRIVER_MODULE(at91_twi, atmelarm, at91_twi_driver, at91_twi_devclass, 0, 0);
diff --git a/sys/arm/at91/at91_twiio.h b/sys/arm/at91/at91_twiio.h
new file mode 100644
index 0000000..2e24439
--- /dev/null
+++ b/sys/arm/at91/at91_twiio.h
@@ -0,0 +1,61 @@
+/*-
+ * Copyright (c) 2006 M. Warner Losh. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _ARM_AT91_AT91_TWIIO_H
+#define _ARM_AT91_AT91_TWIIO_H
+
+#include <sys/ioccom.h>
+
+struct at91_twi_io
+{
+ int dadr; /* Device address */
+ int type; /* read/write */
+#define TWI_IO_READ_MASTER 1
+#define TWI_IO_WRITE_MASTER 2
+ int iadrsz; /* Internal addr size */
+ uint32_t iadr; /* Interbak addr */
+ size_t xfer_len; /* Size to transfer */
+ caddr_t xfer_buf; /* buffer for xfer */
+};
+
+struct at91_twi_clock
+{
+ int ckdiv; /* Clock divider */
+ int high_rate; /* rate of clock high period */
+ int low_rate; /* rate of clock low period */
+};
+
+/** TWIIOCXFER: Do a two-wire transfer
+ */
+#define TWIIOCXFER _IOW('x', 1, struct at91_twi_io)
+
+/** TWIIOCSETCLOCK: Sets the clocking parameters for this operation.
+ */
+#define TWIIOCSETCLOCK _IOW('x', 2, struct at91_twi_clock)
+
+#endif /* !_ARM_AT91_AT91_TWIIO_H */
+
+
diff --git a/sys/arm/at91/at91_twireg.h b/sys/arm/at91/at91_twireg.h
new file mode 100644
index 0000000..7afe0bd
--- /dev/null
+++ b/sys/arm/at91/at91_twireg.h
@@ -0,0 +1,82 @@
+/*-
+ * Copyright (c) 2006 M. Warner Losh. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* $FreeBSD$ */
+
+#ifndef ARM_AT91_AT91_TWIREG_H
+#define ARM_AT91_AT91_TWIREG_H
+
+#define TWI_CR 0x00 /* TWI Control Register */
+#define TWI_MMR 0x04 /* TWI Master Mode Register */
+#define TWI_SMR 0x08 /* TWI Master Mode Register */
+#define TWI_IADR 0x0c /* TWI Internal Address Register */
+#define TWI_CWGR 0x10 /* TWI Clock Waveform Generator Reg */
+ /* 0x14 reserved */
+ /* 0x18 reserved */
+ /* 0x1c reserved */
+#define TWI_SR 0x20 /* TWI Status Register */
+#define TWI_IER 0x24 /* TWI Interrupt Enable Register */
+#define TWI_IDR 0x28 /* TWI Interrupt Disable Register */
+#define TWI_IMR 0x2c /* TWI Interrupt Mask Register */
+#define TWI_RHR 0x30 /* TWI Receiver Holding Register */
+#define TWI_THR 0x34 /* TWI Transmit Holding Register */
+
+/* TWI_CR */
+#define TWI_CR_START (1U << 0) /* Send a start */
+#define TWI_CR_STOP (1U << 1) /* Send a stop */
+#define TWI_CR_MSEN (1U << 2) /* Master Transfer Enable */
+#define TWI_CR_MSDIS (1U << 3) /* Master Transfer Disable */
+#define TWI_CR_SVEN (1U << 4) /* Slave Transfer Enable */
+#define TWI_CR_SVDIS (1U << 5) /* Slave Transfer Disable */
+#define TWI_CR_SWRST (1U << 7) /* Software Reset */
+
+/* TWI_MMR */
+/* TWI_SMR */
+#define TWI_MMR_IADRSZ(n) ((n) << 8) /* Set size of transfer */
+#define TWI_MMR_MWRITE 0U /* Master Read Direction */
+#define TWI_MMR_MREAD (1U << 12) /* Master Read Direction */
+#define TWI_MMR_DADR(n) ((n) << 16) /* Device Address */
+
+/* TWI_CWGR */
+#define TWI_CWGR_CKDIV(x) ((x) << 16) /* Clock Divider */
+#define TWI_CWGR_CHDIV(x) ((x) << 8) /* Clock High Divider */
+#define TWI_CWGR_CLDIV(x) ((x) << 0) /* Clock Low Divider */
+#define TWI_CWGR_DIV(rate) ((AT91C_MASTER_CLOCK /(4*(rate))) - 2)
+
+/* TWI_SR */
+/* TWI_IER */
+/* TWI_IDR */
+/* TWI_IMR */
+#define TWI_SR_TXCOMP (1U << 0) /* Transmission Completed */
+#define TWI_SR_RXRDY (1U << 1) /* Receive Holding Register Ready */
+#define TWI_SR_TXRDY (1U << 2) /* Transmit Holding Register Ready */
+#define TWI_SR_SVREAD (1U << 3) /* Slave Read */
+#define TWI_SR_SVACC (1U << 4) /* Slave Access */
+#define TWI_SR_GCACC (1U << 5) /* General Call Access */
+#define TWI_SR_OVRE (1U << 6) /* Overrun error */
+#define TWI_SR_UNRE (1U << 7) /* Underrun Error */
+#define TWI_SR_NACK (1U << 8) /* Not Acknowledged */
+#define TWI_SR_ARBLST (1U << 9) /* Arbitration Lost */
+
+#endif /* ARM_AT91_AT91_TWIREG_H */
diff --git a/sys/arm/at91/at91_usartreg.h b/sys/arm/at91/at91_usartreg.h
new file mode 100644
index 0000000..f145f39
--- /dev/null
+++ b/sys/arm/at91/at91_usartreg.h
@@ -0,0 +1,148 @@
+/*-
+ * Copyright (c) 2005 Olivier Houchard. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* $FreeBSD$ */
+
+#ifndef AT91USARTREG_H_
+#define AT91USARTREG_H_
+
+#define USART_CR 0x00 /* Control register */
+#define USART_CR_RSTRX (1 << 2) /* Reset Receiver */
+#define USART_CR_RSTTX (1 << 3) /* Reset Transmitter */
+#define USART_CR_RXEN (1 << 4) /* Receiver Enable */
+#define USART_CR_RXDIS (1 << 5) /* Receiver Disable */
+#define USART_CR_TXEN (1 << 6) /* Transmitter Enable */
+#define USART_CR_TXDIS (1 << 7) /* Transmitter Disable */
+#define USART_CR_RSTSTA (1 << 8) /* Reset Status Bits */
+#define USART_CR_STTBRK (1 << 9) /* Start Break */
+#define USART_CR_STPBRK (1 << 10) /* Stop Break */
+#define USART_CR_STTTO (1 << 11) /* Start Time-out */
+#define USART_CR_SENDA (1 << 12) /* Send Address */
+#define USART_CR_RSTIT (1 << 13) /* Reset Iterations */
+#define USART_CR_RSTNACK (1 << 14) /* Reset Non Acknowledge */
+#define USART_CR_RETTO (1 << 15) /* Rearm Time-out */
+#define USART_CR_DTREN (1 << 16) /* Data Terminal ready Enable */
+#define USART_CR_DTRDIS (1 << 17) /* Data Terminal ready Disable */
+#define USART_CR_RTSEN (1 << 18) /* Request to Send enable */
+#define USART_CR_RTSDIS (1 << 19) /* Request to Send Disable */
+
+#define USART_MR 0x04 /* Mode register */
+#define USART_MR_MODE_NORMAL 0 /* Normal/Async/3-wire rs-232 */
+#define USART_MR_MODE_RS485 1 /* RS485 */
+#define USART_MR_MODE_HWFLOW 2 /* Hardware flow control/handshake */
+#define USART_MR_MODE_MODEM 3 /* Full modem protocol */
+#define USART_MR_MODE_ISO7816T0 4 /* ISO7816 T=0 */
+#define USART_MR_MODE_ISO7816T1 6 /* ISO7816 T=1 */
+#define USART_MR_MODE_IRDA 8 /* IrDA mode */
+#define USART_MR_USCLKS_MCK (0U << 4) /* use MCK for baudclock */
+#define USART_MR_USCLKS_MCKDIV (1U << 4) /* use MCK/DIV for baudclock */
+#define USART_MR_USCLKS_SCK (3U << 4) /* use SCK (ext) for baudclock */
+#define USART_MR_CHRL_5BITS (0U << 6)
+#define USART_MR_CHRL_6BITS (1U << 6)
+#define USART_MR_CHRL_7BITS (2U << 6)
+#define USART_MR_CHRL_8BITS (3U << 6)
+#define USART_MR_SYNC (1U << 8) /* 1 -> sync 0 -> async */
+#define USART_MR_PAR_EVEN (0U << 9)
+#define USART_MR_PAR_ODD (1U << 9)
+#define USART_MR_PAR_SPACE (2U << 9)
+#define USART_MR_PAR_MARK (3U << 9)
+#define USART_MR_PAR_NONE (4U << 9)
+#define USART_MR_PAR_MULTIDROP (6U << 9)
+#define USART_MR_NBSTOP_1 (0U << 12)
+#define USART_MR_NBSTOP_1_5 (1U << 12)
+#define USART_MR_NBSTOP_2 (2U << 12)
+#define USART_MR_CHMODE_NORMAL (0U << 14)
+#define USART_MR_CHMODE_ECHO (1U << 14)
+#define USART_MR_CHMODE_LOOP (2U << 14)
+#define USART_MR_CHMODE_REMLOOP (3U << 14)
+#define USART_MR_MSBF (1U << 16)
+#define USART_MR_MODE9 (1U << 17)
+#define USART_MR_CKLO_SCK (1U << 18)
+#define USART_MR_OVER16 0
+#define USART_MR_OVER8 (1U << 19)
+#define USART_MR_INACK (1U << 20) /* Inhibit NACK generation */
+#define USART_MR_DSNACK (1U << 21) /* Disable Successive NACK */
+#define USART_MR_MAXITERATION(x) ((x) << 24)
+#define USART_MR_FILTER (1U << 28) /* Filters for Ir lines */
+
+#define USART_IER 0x08 /* Interrupt enable register */
+#define USART_IDR 0x0c /* Interrupt disable register */
+#define USART_IMR 0x10 /* Interrupt mask register */
+#define USART_CSR 0x14 /* Channel status register */
+
+#define USART_CSR_RXRDY (1U << 0) /* Receiver ready */
+#define USART_CSR_TXRDY (1U << 1) /* Transmitter ready */
+#define USART_CSR_RXBRK (1U << 2) /* Break received */
+#define USART_CSR_ENDRX (1U << 3) /* End of Transfer RX from PDC */
+#define USART_CSR_ENDTX (1U << 4) /* End of Transfer TX from PDC */
+#define USART_CSR_OVRE (1U << 5) /* Overrun error */
+#define USART_CSR_FRAME (1U << 6) /* Framing error */
+#define USART_CSR_PARE (1U << 7) /* Parity Error */
+#define USART_CSR_TIMEOUT (1U << 8) /* Timeout since start-timeout */
+#define USART_CSR_TXEMPTY (1U << 9) /* Transmitter empty */
+#define USART_CSR_ITERATION (1U << 10) /* max repetitions since RSIT */
+#define USART_CSR_TXBUFE (1U << 11) /* Buffer empty from PDC */
+#define USART_CSR_RXBUFF (1U << 12) /* Buffer full from PDC */
+#define USART_CSR_NACK (1U << 13) /* NACK since last RSTNACK */
+#define USART_CSR_RIIC (1U << 16) /* RI delta since last csr read */
+#define USART_CSR_DSRIC (1U << 17) /* DSR delta */
+#define USART_CSR_DCDIC (1U << 18) /* DCD delta */
+#define USART_CSR_CTSIC (1U << 19) /* CTS delta */
+#define USART_CSR_RI (1U << 20) /* RI status */
+#define USART_CSR_DSR (1U << 21) /* DSR status */
+#define USART_CSR_DCD (1U << 22) /* DCD status */
+#define USART_CSR_CTS (1U << 23) /* CTS status */
+
+#define USART_RHR 0x18 /* Receiver holding register */
+#define USART_THR 0x1c /* Transmitter holding register */
+#define USART_BRGR 0x20 /* Baud rate generator register */
+#define USART_RTOR 0x24 /* Receiver time-out register */
+#define USART_TTR 0x28 /* Transmitter timeguard register */
+/* 0x2c to 0x3c reserved */
+#define USART_FDRR 0x40 /* FI DI ratio register */
+#define USART_NER 0x44 /* Number of errors register */
+/* 0x48 reserved */
+#define USART_IFR 0x48 /* IrDA filter register */
+
+
+#define UART_RXRDY (0x1 << 0) /* RXRDY Interrupt */
+#define UART_TXRDY (0x1 << 1) /* TXRDY Interrupt */
+#define UART_RXBRK (0x1 << 2) /* Break Received/End of Break */
+#define UART_ENDRX (0x1 << 3) /* End of Receive Transfer Interrupt */
+#define UART_ENDTX (0x1 << 4) /* End of Transmit Interrupt */
+#define UART_OVRE (0x1 << 5) /* Overrun Interrupt */
+#define UART_FRAME (0x1 << 6) /* Framing Error Interrupt */
+#define UART_PARE (0x1 << 7) /* Parity Error Interrupt */
+#define UART_TIMEOUT ( 0x1 << 8) /* (USART) Receiver Time-out */
+#define UART_TXEMPTY ( 0x1 << 9) /* (USART) TXEMPTY Interrupt */
+#define UART_ITERATION ( 0x1 << 10) /* (USART) Max number of Repetitions Reached */
+#define UART_TXBUFE ( 0x1 << 11) /* (USART) TXBUFE Interrupt */
+#define UART_RXBUFF ( 0x1 << 12) /* (USART) RXBUFF Interrupt */
+#define UART_NACK ( 0x1 << 13) /* (USART) Non Acknowledge */
+#define UART_RIIC ( 0x1 << 16) /* (USART) Ring INdicator Input Change Flag */
+#define AT91RM92_US_DSRIC ( 0x1 << 17) /* (USART) Data Set Ready Input Change Flag */
+#define AT91RM92_US_DCDIC ( 0x1 << 18) /* (USART) Data Carrier Flag */
+#define AT91RM92_US_CTSIC ( 0x1 << 19) /* (USART) Clear To Send Input Change Flag */
+
+#endif /* AT91RM92REG_H_ */
diff --git a/sys/arm/at91/at91rm92reg.h b/sys/arm/at91/at91rm92reg.h
new file mode 100644
index 0000000..82611d0
--- /dev/null
+++ b/sys/arm/at91/at91rm92reg.h
@@ -0,0 +1,633 @@
+/*-
+ * Copyright (c) 2005 Olivier Houchard. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* $FreeBSD$ */
+
+#ifndef AT91RM92REG_H_
+#define AT91RM92REG_H_
+/*
+ * Memory map, from datasheet :
+ * 0x00000000 - 0x0ffffffff : Internal Memories
+ * 0x10000000 - 0x1ffffffff : Chip Select 0
+ * 0x20000000 - 0x2ffffffff : Chip Select 1
+ * 0x30000000 - 0x3ffffffff : Chip Select 2
+ * 0x40000000 - 0x4ffffffff : Chip Select 3
+ * 0x50000000 - 0x5ffffffff : Chip Select 4
+ * 0x60000000 - 0x6ffffffff : Chip Select 5
+ * 0x70000000 - 0x7ffffffff : Chip Select 6
+ * 0x80000000 - 0x8ffffffff : Chip Select 7
+ * 0x90000000 - 0xeffffffff : Undefined (Abort)
+ * 0xf0000000 - 0xfffffffff : Peripherals
+ */
+
+#define AT91RM92_BASE 0xf0000000
+/* Usart */
+
+#define AT91RM92_USART0_BASE 0xffc0000
+#define AT91RM92_USART0_PDC 0xffc0100
+#define AT91RM92_USART1_BASE 0xffc4000
+#define AT91RM92_USART1_PDC 0xffc4100
+#define AT91RM92_USART2_BASE 0xffc8000
+#define AT91RM92_USART2_PDC 0xffc8100
+#define AT91RM92_USART3_BASE 0xffcc000
+#define AT91RM92_USART3_PDC 0xffcc100
+#define AT91RM92_USART_SIZE 0x4000
+
+/* System Registers */
+
+#define AT91RM92_SYS_BASE 0xffff000
+#define AT91RM92_SYS_SIZE 0x1000
+/* Interrupt Controller */
+#define IC_SMR (0) /* Source mode register */
+#define IC_SVR (128) /* Source vector register */
+#define IC_IVR (256) /* IRQ vector register */
+#define IC_FVR (260) /* FIQ vector register */
+#define IC_ISR (264) /* Interrupt status register */
+#define IC_IPR (268) /* Interrupt pending register */
+#define IC_IMR (272) /* Interrupt status register */
+#define IC_CISR (276) /* Core interrupt status register */
+#define IC_IECR (288) /* Interrupt enable command register */
+#define IC_IDCR (292) /* Interrupt disable command register */
+#define IC_ICCR (296) /* Interrupt clear command register */
+#define IC_ISCR (300) /* Interrupt set command register */
+#define IC_EOICR (304) /* End of interrupt command register */
+#define IC_SPU (308) /* Spurious vector register */
+#define IC_DCR (312) /* Debug control register */
+#define IC_FFER (320) /* Fast forcing enable register */
+#define IC_FFDR (324) /* Fast forcing disable register */
+#define IC_FFSR (328) /* Fast forcing status register */
+
+/* DBGU */
+
+#define DBGU 0x200
+#define DBGU_SIZE 0x200
+#define DBGU_C1R (0x200 + 64) /* Chip ID1 Register */
+#define DBGU_C2R (0x200 + 68) /* Chip ID2 Register */
+#define DBGU_FNTR (0x200 + 72) /* Force NTRST Register */
+
+#define PIOA_PER (0x400) /* PIO Enable Register */
+#define PIOA_PDR (0x400 + 4) /* PIO Disable Register */
+#define PIOA_PSR (0x400 + 8) /* PIO status register */
+#define PIOA_OER (0x400 + 16) /* Output enable register */
+#define PIOA_ODR (0x400 + 20) /* Output disable register */
+#define PIOA_OSR (0x400 + 24) /* Output status register */
+#define PIOA_IFER (0x400 + 32) /* Input filter enable register */
+#define PIOA_IFDR (0x400 + 36) /* Input filter disable register */
+#define PIOA_IFSR (0x400 + 40) /* Input filter status register */
+#define PIOA_SODR (0x400 + 48) /* Set output data register */
+#define PIOA_CODR (0x400 + 52) /* Clear output data register */
+#define PIOA_ODSR (0x400 + 56) /* Output data status register */
+#define PIOA_PDSR (0x400 + 60) /* Pin data status register */
+#define PIOA_IER (0x400 + 64) /* Interrupt enable register */
+#define PIOA_IDR (0x400 + 68) /* Interrupt disable register */
+#define PIOA_IMR (0x400 + 72) /* Interrupt mask register */
+#define PIOA_ISR (0x400 + 76) /* Interrupt status register */
+#define PIOA_MDER (0x400 + 80) /* Multi driver enable register */
+#define PIOA_MDDR (0x400 + 84) /* Multi driver disable register */
+#define PIOA_MDSR (0x400 + 88) /* Multi driver status register */
+#define PIOA_PPUDR (0x400 + 96) /* Pull-up disable register */
+#define PIOA_PPUER (0x400 + 100) /* Pull-up enable register */
+#define PIOA_PPUSR (0x400 + 104) /* Pad pull-up status register */
+#define PIOA_ASR (0x400 + 112) /* Select A register */
+#define PIOA_BSR (0x400 + 116) /* Select B register */
+#define PIOA_ABSR (0x400 + 120) /* AB Select status register */
+#define PIOA_OWER (0x400 + 160) /* Output Write enable register */
+#define PIOA_OWDR (0x400 + 164) /* Output write disable register */
+#define PIOA_OWSR (0x400 + 168) /* Output write status register */
+#define PIOB_PER (0x400) /* PIO Enable Register */
+#define PIOB_PDR (0x600 + 4) /* PIO Disable Register */
+#define PIOB_PSR (0x600 + 8) /* PIO status register */
+#define PIOB_OER (0x600 + 16) /* Output enable register */
+#define PIOB_ODR (0x600 + 20) /* Output disable register */
+#define PIOB_OSR (0x600 + 24) /* Output status register */
+#define PIOB_IFER (0x600 + 32) /* Input filter enable register */
+#define PIOB_IFDR (0x600 + 36) /* Input filter disable register */
+#define PIOB_IFSR (0x600 + 40) /* Input filter status register */
+#define PIOB_SODR (0x600 + 48) /* Set output data register */
+#define PIOB_CODR (0x600 + 52) /* Clear output data register */
+#define PIOB_ODSR (0x600 + 56) /* Output data status register */
+#define PIOB_PDSR (0x600 + 60) /* Pin data status register */
+#define PIOB_IER (0x600 + 64) /* Interrupt enable register */
+#define PIOB_IDR (0x600 + 68) /* Interrupt disable register */
+#define PIOB_IMR (0x600 + 72) /* Interrupt mask register */
+#define PIOB_ISR (0x600 + 76) /* Interrupt status register */
+#define PIOB_MDER (0x600 + 80) /* Multi driver enable register */
+#define PIOB_MDDR (0x600 + 84) /* Multi driver disable register */
+#define PIOB_MDSR (0x600 + 88) /* Multi driver status register */
+#define PIOB_PPUDR (0x600 + 96) /* Pull-up disable register */
+#define PIOB_PPUER (0x600 + 100) /* Pull-up enable register */
+#define PIOB_PPUSR (0x600 + 104) /* Pad pull-up status register */
+#define PIOB_ASR (0x600 + 112) /* Select A register */
+#define PIOB_BSR (0x600 + 116) /* Select B register */
+#define PIOB_ABSR (0x600 + 120) /* AB Select status register */
+#define PIOB_OWER (0x600 + 160) /* Output Write enable register */
+#define PIOB_OWDR (0x600 + 164) /* Output write disable register */
+#define PIOB_OWSR (0x600 + 168) /* Output write status register */
+#define PIOC_PER (0x800) /* PIO Enable Register */
+#define PIOC_PDR (0x800 + 4) /* PIO Disable Register */
+#define PIOC_PSR (0x800 + 8) /* PIO status register */
+#define PIOC_OER (0x800 + 16) /* Output enable register */
+#define PIOC_ODR (0x800 + 20) /* Output disable register */
+#define PIOC_OSR (0x800 + 24) /* Output status register */
+#define PIOC_IFER (0x800 + 32) /* Input filter enable register */
+#define PIOC_IFDR (0x800 + 36) /* Input filter disable register */
+#define PIOC_IFSR (0x800 + 40) /* Input filter status register */
+#define PIOC_SODR (0x800 + 48) /* Set output data register */
+#define PIOC_CODR (0x800 + 52) /* Clear output data register */
+#define PIOC_ODSR (0x800 + 56) /* Output data status register */
+#define PIOC_PDSR (0x800 + 60) /* Pin data status register */
+#define PIOC_IER (0x800 + 64) /* Interrupt enable register */
+#define PIOC_IDR (0x800 + 68) /* Interrupt disable register */
+#define PIOC_IMR (0x800 + 72) /* Interrupt mask register */
+#define PIOC_ISR (0x800 + 76) /* Interrupt status register */
+#define PIOC_MDER (0x800 + 80) /* Multi driver enable register */
+#define PIOC_MDDR (0x800 + 84) /* Multi driver disable register */
+#define PIOC_MDSR (0x800 + 88) /* Multi driver status register */
+#define PIOC_PPUDR (0x800 + 96) /* Pull-up disable register */
+#define PIOC_PPUER (0x800 + 100) /* Pull-up enable register */
+#define PIOC_PPUSR (0x800 + 104) /* Pad pull-up status register */
+#define PIOC_ASR (0x800 + 112) /* Select A register */
+#define PIOC_BSR (0x800 + 116) /* Select B register */
+#define PIOC_ABSR (0x800 + 120) /* AB Select status register */
+#define PIOC_OWER (0x800 + 160) /* Output Write enable register */
+#define PIOC_OWDR (0x800 + 164) /* Output write disable register */
+#define PIOC_OWSR (0x800 + 168) /* Output write status register */
+#define PIOD_PER (0xa00) /* PIO Enable Register */
+#define PIOD_PDR (0xa00 + 4) /* PIO Disable Register */
+#define PIOD_PSR (0xa00 + 8) /* PIO status register */
+#define PIOD_OER (0xa00 + 16) /* Output enable register */
+#define PIOD_ODR (0xa00 + 20) /* Output disable register */
+#define PIOD_OSR (0xa00 + 24) /* Output status register */
+#define PIOD_IFER (0xa00 + 32) /* Input filter enable register */
+#define PIOD_IFDR (0xa00 + 36) /* Input filter disable register */
+#define PIOD_IFSR (0xa00 + 40) /* Input filter status register */
+#define PIOD_SODR (0xa00 + 48) /* Set output data register */
+#define PIOD_CODR (0xa00 + 52) /* Clear output data register */
+#define PIOD_ODSR (0xa00 + 56) /* Output data status register */
+#define PIOD_PDSR (0xa00 + 60) /* Pin data status register */
+#define PIOD_IER (0xa00 + 64) /* Interrupt enable register */
+#define PIOD_IDR (0xa00 + 68) /* Interrupt disable register */
+#define PIOD_IMR (0xa00 + 72) /* Interrupt mask register */
+#define PIOD_ISR (0xa00 + 76) /* Interrupt status register */
+#define PIOD_MDER (0xa00 + 80) /* Multi driver enable register */
+#define PIOD_MDDR (0xa00 + 84) /* Multi driver disable register */
+#define PIOD_MDSR (0xa00 + 88) /* Multi driver status register */
+#define PIOD_PPUDR (0xa00 + 96) /* Pull-up disable register */
+#define PIOD_PPUER (0xa00 + 100) /* Pull-up enable register */
+#define PIOD_PPUSR (0xa00 + 104) /* Pad pull-up status register */
+#define PIOD_ASR (0xa00 + 112) /* Select A register */
+#define PIOD_BSR (0xa00 + 116) /* Select B register */
+#define PIOD_ABSR (0xa00 + 120) /* AB Select status register */
+#define PIOD_OWER (0xa00 + 160) /* Output Write enable register */
+#define PIOD_OWDR (0xa00 + 164) /* Output write disable register */
+#define PIOD_OWSR (0xa00 + 168) /* Output write status register */
+
+/* IRQs : */
+/*
+ * 0: AIC
+ * 1: System peripheral (System timer, RTC, DBGU)
+ * 2: PIO Controller A
+ * 3: PIO Controller B
+ * 4: PIO Controller C
+ * 5: PIO Controller D
+ * 6: USART 0
+ * 7: USART 1
+ * 8: USART 2
+ * 9: USART 3
+ * 10: MMC Interface
+ * 11: USB device port
+ * 12: Two-wirte interface
+ * 13: SPI
+ * 14: SSC
+ * 15: SSC
+ * 16: SSC
+ * 17: Timer Counter 0
+ * 18: Timer Counter 1
+ * 19: Timer Counter 2
+ * 20: Timer Counter 3
+ * 21: Timer Counter 4
+ * 22: Timer Counter 6
+ * 23: USB Host port
+ * 24: Ethernet
+ * 25: AIC
+ * 26: AIC
+ * 27: AIC
+ * 28: AIC
+ * 29: AIC
+ * 30: AIC
+ * 31: AIC
+ */
+
+#define AT91RM92_IRQ_SYSTEM 1
+#define AT91RM92_IRQ_PIOA 2
+#define AT91RM92_IRQ_PIOB 3
+#define AT91RM92_IRQ_PIOC 4
+#define AT91RM92_IRQ_PIOD 5
+#define AT91RM92_IRQ_USART0 6
+#define AT91RM92_IRQ_USART1 7
+#define AT91RM92_IRQ_USART2 8
+#define AT91RM92_IRQ_USART3 9
+#define AT91RM92_IRQ_MCI 10
+#define AT91RM92_IRQ_UDP 11
+#define AT91RM92_IRQ_TWI 12
+#define AT91RM92_IRQ_SPI 13
+#define AT91RM92_IRQ_SSC0 14
+#define AT91RM92_IRQ_SSC1 15
+#define AT91RM92_IRQ_SSC2 16
+#define AT91RM92_IRQ_TC0 17
+#define AT91RM92_IRQ_TC1 18
+#define AT91RM92_IRQ_TC2 19
+#define AT91RM92_IRQ_TC3 20
+#define AT91RM92_IRQ_TC4 21
+#define AT91RM92_IRQ_TC5 22
+#define AT91RM92_IRQ_UHP 23
+#define AT91RM92_IRQ_EMAC 24
+#define AT91RM92_IRQ_AIC_BASE 25
+
+/* Timer */
+
+#define AT91RM92_ST_BASE 0xffffd00
+#define AT91RM92_ST_SIZE 0x100
+
+#define AT91RM92_SPI_BASE 0xffe0000
+#define AT91RM92_SPI_SIZE 0x4000
+#define AT91RM92_SPI_PDC 0xffe0100
+
+#define AT91RM92_SSC0_BASE 0xffd0000
+#define AT91RM92_SSC0_PDC 0xffd0100
+
+#define AT91RM92_SSC1_BASE 0xffd4000
+#define AT91RM92_SSC1_PDC 0xffd4100
+
+#define AT91RM92_SSC2_BASE 0xffd8000
+#define AT91RM92_SSC2_PDC 0xffd8100
+
+#define AT91RM92_SSC_SIZE 0x4000
+
+#define AT91RM92_EMAC_BASE 0xffbc000
+#define AT91RM92_EMAC_SIZE 0x4000
+
+#define AT91RM92_TWI_BASE 0xffb8000
+#define AT91RM92_TWI_SIZE 0x4000
+
+#define AT91RM92_MCI_BASE 0xffb4000
+#define AT91RM92_MCI_PDC 0xffb4100
+#define AT91RM92_MCI_SIZE 0x4000
+
+#define AT91RM92_UDP_BASE 0xffb0000
+#define AT91RM92_UDP_SIZE 0x4000
+
+#define AT91RM92_TC0_BASE 0xffa0000
+#define AT91RM92_TC0_SIZE 0x4000
+#define AT91RM92_TC0C0_BASE 0xffa0000
+#define AT91RM92_TC0C1_BASE 0xffa0040
+#define AT91RM92_TC0C2_BASE 0xffa0080
+
+#define AT91RM92_TC1_BASE 0xffa4000
+#define AT91RM92_TC1_SIZE 0x4000
+#define AT91RM92_TC1C0_BASE 0xffa4000
+#define AT91RM92_TC1C1_BASE 0xffa4040
+#define AT91RM92_TC1C2_BASE 0xffa4080
+
+#define AT91RM92_OHCI_BASE 0x00300000
+#define AT91RM92_OHCI_SIZE 0x00100000
+
+/* Pio definitions */
+#define AT91RM92_PIO_PA0 (1 << 0)
+#define AT91RM92_PA0_MISO (AT91RM92_PIO_PA0) /* SPI Master In Slave */
+#define AT91RM92_PA0_PCK3 (AT91RM92_PIO_PA0) /* PMC Programmable Clock Output 3 */
+#define AT91RM92_PIO_PA1 (1 << 1)
+#define AT91RM92_PA1_MOSI (AT91RM92_PIO_PA1) /* SPI Master Out Slave */
+#define AT91RM92_PA1_PCK0 (AT91RM92_PIO_PA1) /* PMC Programmable Clock Output 0 */
+#define AT91RM92_PIO_PA2 (1 << 2)
+#define AT91RM92_PA2_SPCK (AT91RM92_PIO_PA2) /* SPI Serial Clock */
+#define AT91RM92_PA2_IRQ4 (AT91RM92_PIO_PA2) /* AIC Interrupt Input 4 */
+#define AT91RM92_PIO_PA3 (1 << 3)
+#define AT91RM92_PA3_NPCS0 (AT91RM92_PIO_PA3) /* SPI Peripheral Chip Select 0 */
+#define AT91RM92_PA3_IRQ5 (AT91RM92_PIO_PA3) /* AIC Interrupt Input 5 */
+#define AT91RM92_PIO_PA4 (1 << 4)
+#define AT91RM92_PA4_NPCS1 (AT91RM92_PIO_PA4) /* SPI Peripheral Chip Select 1 */
+#define AT91RM92_PA4_PCK1 (AT91RM92_PIO_PA4) /* PMC Programmable Clock Output 1 */
+#define AT91RM92_PIO_PA5 (1 << 5)
+#define AT91RM92_PA5_NPCS2 (AT91RM92_PIO_PA5) /* SPI Peripheral Chip Select 2 */
+#define AT91RM92_PA5_TXD3 (AT91RM92_PIO_PA5) /* USART 3 Transmit Data */
+#define AT91RM92_PIO_PA6 (1 << 6)
+#define AT91RM92_PA6_NPCS3 (AT91RM92_PIO_PA6) /* SPI Peripheral Chip Select 3 */
+#define AT91RM92_PA6_RXD3 (AT91RM92_PIO_PA6) /* USART 3 Receive Data */
+#define AT91RM92_PIO_PA7 (1 << 7)
+#define AT91RM92_PA7_ETXCK_EREFC (AT91RM92_PIO_PA7) /* Ethernet MAC Transmit Clock/Reference Clock */
+#define AT91RM92_PA7_PCK2 (AT91RM92_PIO_PA7) /* PMC Programmable Clock 2 */
+#define AT91RM92_PIO_PA8 (1 << 8)
+#define AT91RM92_PA8_ETXEN (AT91RM92_PIO_PA8) /* Ethernet MAC Transmit Enable */
+#define AT91RM92_PA8_MCCDB (AT91RM92_PIO_PA8) /* Multimedia Card B Command */
+#define AT91RM92_PIO_PA9 (1 << 9)
+#define AT91RM92_PA9_ETX0 (AT91RM92_PIO_PA9) /* Ethernet MAC Transmit Data 0 */
+#define AT91RM92_PA9_MCDB0 (AT91RM92_PIO_PA9) /* Multimedia Card B Data 0 */
+#define AT91RM92_PIO_PA10 (1 << 10)
+#define AT91RM92_PA10_ETX1 (AT91RM92_PIO_PA10) /* Ethernet MAC Transmit Data 1 */
+#define AT91RM92_PA10_MCDB1 (AT91RM92_PIO_PA10) /* Multimedia Card B Data 1 */
+#define AT91RM92_PIO_PA11 (1 << 11)
+#define AT91RM92_PA11_ECRS_ECRSDV (AT91RM92_PIO_PA11) /* Ethernet MAC Carrier Sense/Carrier Sense and Data Valid */
+#define AT91RM92_PA11_MCDB2 (AT91RM92_PIO_PA11) /* Multimedia Card B Data 2 */
+#define AT91RM92_PIO_PA12 (1 << 12)
+#define AT91RM92_PA12_ERX0 (AT91RM92_PIO_PA12) /* Ethernet MAC Receive Data 0 */
+#define AT91RM92_PA12_MCDB3 (AT91RM92_PIO_PA12) /* Multimedia Card B Data 3 */
+#define AT91RM92_PIO_PA13 (1 << 13)
+#define AT91RM92_PA13_ERX1 (AT91RM92_PIO_PA13) /* Ethernet MAC Receive Data 1 */
+#define AT91RM92_PA13_TCLK0 (AT91RM92_PIO_PA13) /* Timer Counter 0 external clock input */
+#define AT91RM92_PIO_PA14 (1 << 14)
+#define AT91RM92_PA14_ERXER (AT91RM92_PIO_PA14) /* Ethernet MAC Receive Error */
+#define AT91RM92_PA14_TCLK1 (AT91RM92_PIO_PA14) /* Timer Counter 1 external clock input */
+#define AT91RM92_PIO_PA15 (1 << 15)
+#define AT91RM92_PA15_EMDC (AT91RM92_PIO_PA15) /* Ethernet MAC Management Data Clock */
+#define AT91RM92_PA15_TCLK2 (AT91RM92_PIO_PA15) /* Timer Counter 2 external clock input */
+#define AT91RM92_PIO_PA16 (1 << 16)
+#define AT91RM92_PA16_EMDIO (AT91RM92_PIO_PA16) /* Ethernet MAC Management Data Input/Output */
+#define AT91RM92_PA16_IRQ6 (AT91RM92_PIO_PA16) /* AIC Interrupt input 6 */
+#define AT91RM92_PIO_PA17 (1 << 17)
+#define AT91RM92_PA17_TXD0 (AT91RM92_PIO_PA17) /* USART 0 Transmit Data */
+#define AT91RM92_PA17_TIOA0 (AT91RM92_PIO_PA17) /* Timer Counter 0 Multipurpose Timer I/O Pin A */
+#define AT91RM92_PIO_PA18 (1 << 18)
+#define AT91RM92_PA18_RXD0 (AT91RM92_PIO_PA18) /* USART 0 Receive Data */
+#define AT91RM92_PA18_TIOB0 (AT91RM92_PIO_PA18) /* Timer Counter 0 Multipurpose Timer I/O Pin B */
+#define AT91RM92_PIO_PA19 (1 << 19)
+#define AT91RM92_PA19_SCK0 (AT91RM92_PIO_PA19) /* USART 0 Serial Clock */
+#define AT91RM92_PA19_TIOA1 (AT91RM92_PIO_PA19) /* Timer Counter 1 Multipurpose Timer I/O Pin A */
+#define AT91RM92_PIO_PA20 (1 << 20)
+#define AT91RM92_PA20_CTS0 (AT91RM92_PIO_PA20) /* USART 0 Clear To Send */
+#define AT91RM92_PA20_TIOB1 (AT91RM92_PIO_PA20) /* Timer Counter 1 Multipurpose Timer I/O Pin B */
+#define AT91RM92_PIO_PA21 (1 << 21)
+#define AT91RM92_PA21_RTS0 (AT91RM92_PIO_PA21) /* USART 0 Ready To Send */
+#define AT91RM92_PA21_TIOA2 (AT91RM92_PIO_PA21) /* Timer Counter 2 Multipurpose Timer I/O Pin A */
+#define AT91RM92_PIO_PA22 (1 << 22)
+#define AT91RM92_PA22_RXD2 (AT91RM92_PIO_PA22) /* USART 2 Receive Data */
+#define AT91RM92_PA22_TIOB2 (AT91RM92_PIO_PA22) /* Timer Counter 2 Multipurpose Timer I/O Pin B */
+#define AT91RM92_PIO_PA23 (1 << 23)
+#define AT91RM92_PA23_TXD2 (AT91RM92_PIO_PA23) /* USART 2 Transmit Data */
+#define AT91RM92_PA23_IRQ3 (AT91RM92_PIO_PA23) /* Interrupt input 3 */
+#define AT91RM92_PIO_PA24 (1 << 24)
+#define AT91RM92_PA24_SCK2 (AT91RM92_PIO_PA24) /* USART 2 Serial Clock */
+#define AT91RM92_PA24_PCK1 (AT91RM92_PIO_PA24) /* PMC Programmable Clock Output 1 */
+#define AT91RM92_PIO_PA25 (1 << 25)
+#define AT91RM92_PA25_TWD (AT91RM92_PIO_PA25) /* TWI Two-wire Serial Data */
+#define AT91RM92_PA25_IRQ2 (AT91RM92_PIO_PA25) /* Interrupt input 2 */
+#define AT91RM92_PIO_PA26 (1 << 26)
+#define AT91RM92_PA26_TWCK (AT91RM92_PIO_PA26) /* TWI Two-wire Serial Clock */
+#define AT91RM92_PA26_IRQ1 (AT91RM92_PIO_PA26) /* Interrupt input 1 */
+#define AT91RM92_PIO_PA27 (1 << 27)
+#define AT91RM92_PA27_MCCK (AT91RM92_PIO_PA27) /* Multimedia Card Clock */
+#define AT91RM92_PA27_TCLK3 (AT91RM92_PIO_PA27) /* Timer Counter 3 External Clock Input */
+#define AT91RM92_PIO_PA28 (1 << 28)
+#define AT91RM92_PA28_MCCDA (AT91RM92_PIO_PA28) /* Multimedia Card A Command */
+#define AT91RM92_PA28_TCLK4 (AT91RM92_PIO_PA28) /* Timer Counter 4 external Clock Input */
+#define AT91RM92_PIO_PA29 (1 << 29)
+#define AT91RM92_PA29_MCDA0 (AT91RM92_PIO_PA29) /* Multimedia Card A Data 0 */
+#define AT91RM92_PA29_TCLK5 (AT91RM92_PIO_PA29) /* Timer Counter 5 external clock input */
+#define AT91RM92_PIO_PA30 (1 << 30)
+#define AT91RM92_PA30_DRXD (AT91RM92_PIO_PA30) /* DBGU Debug Receive Data */
+#define AT91RM92_PA30_CTS2 (AT91RM92_PIO_PA30) /* USART 2 Clear To Send */
+#define AT91RM92_PIO_PA31 (1 << 31)
+#define AT91RM92_PA31_DTXD (AT91RM92_PIO_PA31) /* DBGU Debug Transmit Data */
+#define AT91RM92_PA31_RTS2 (AT91RM92_PIO_PA31) /* USART 2 Ready To Send */
+
+#define AT91RM92_PIO_PB0 (1 << 0)
+#define AT91RM92_PB0_TF0 (AT91RM92_PIO_PB0) /* SSC Transmit Frame Sync 0 */
+#define AT91RM92_PB0_RTS3 (AT91RM92_PIO_PB0) /* USART 3 Ready To Send */
+#define AT91RM92_PIO_PB1 (1 << 1)
+#define AT91RM92_PB1_TK0 (AT91RM92_PIO_PB1) /* SSC Transmit Clock 0 */
+#define AT91RM92_PB1_CTS3 (AT91RM92_PIO_PB1) /* USART 3 Clear To Send */
+#define AT91RM92_PIO_PB2 (1 << 2)
+#define AT91RM92_PB2_TD0 (AT91RM92_PIO_PB2) /* SSC Transmit data */
+#define AT91RM92_PB2_SCK3 (AT91RM92_PIO_PB2) /* USART 3 Serial Clock */
+#define AT91RM92_PIO_PB3 (1 << 3)
+#define AT91RM92_PB3_RD0 (AT91RM92_PIO_PB3) /* SSC Receive Data */
+#define AT91RM92_PB3_MCDA1 (AT91RM92_PIO_PB3) /* Multimedia Card A Data 1 */
+#define AT91RM92_PIO_PB4 (1 << 4)
+#define AT91RM92_PB4_RK0 (AT91RM92_PIO_PB4) /* SSC Receive Clock */
+#define AT91RM92_PB4_MCDA2 (AT91RM92_PIO_PB4) /* Multimedia Card A Data 2 */
+#define AT91RM92_PIO_PB5 (1 << 5)
+#define AT91RM92_PB5_RF0 (AT91RM92_PIO_PB5) /* SSC Receive Frame Sync 0 */
+#define AT91RM92_PB5_MCDA3 (AT91RM92_PIO_PB5) /* Multimedia Card A Data 3 */
+#define AT91RM92_PIO_PB6 (1 << 6)
+#define AT91RM92_PB6_TF1 (AT91RM92_PIO_PB6) /* SSC Transmit Frame Sync 1 */
+#define AT91RM92_PB6_TIOA3 (AT91RM92_PIO_PB6) /* Timer Counter 4 Multipurpose Timer I/O Pin A */
+#define AT91RM92_PIO_PB7 (1 << 7)
+#define AT91RM92_PB7_TK1 (AT91RM92_PIO_PB7) /* SSC Transmit Clock 1 */
+#define AT91RM92_PB7_TIOB3 (AT91RM92_PIO_PB7) /* Timer Counter 3 Multipurpose Timer I/O Pin B */
+#define AT91RM92_PIO_PB8 (1 << 8)
+#define AT91RM92_PB8_TD1 (AT91RM92_PIO_PB8) /* SSC Transmit Data 1 */
+#define AT91RM92_PB8_TIOA4 (AT91RM92_PIO_PB8) /* Timer Counter 4 Multipurpose Timer I/O Pin A */
+#define AT91RM92_PIO_PB9 (1 << 9)
+#define AT91RM92_PB9_RD1 (AT91RM92_PIO_PB9) /* SSC Receive Data 1 */
+#define AT91RM92_PB9_TIOB4 (AT91RM92_PIO_PB9) /* Timer Counter 4 Multipurpose Timer I/O Pin B */
+#define AT91RM92_PIO_PB10 (1 << 10)
+#define AT91RM92_PB10_RK1 (AT91RM92_PIO_PB10) /* SSC Receive Clock 1 */
+#define AT91RM92_PB10_TIOA5 (AT91RM92_PIO_PB10) /* Timer Counter 5 Multipurpose Timer I/O Pin A */
+#define AT91RM92_PIO_PB11 (1 << 11)
+#define AT91RM92_PB11_RF1 (AT91RM92_PIO_PB11) /* SSC Receive Frame Sync 1 */
+#define AT91RM92_PB11_TIOB5 (AT91RM92_PIO_PB11) /* Timer Counter 5 Multipurpose Timer I/O Pin B */
+#define AT91RM92_PIO_PB12 (1 << 12)
+#define AT91RM92_PB12_TF2 (AT91RM92_PIO_PB12) /* SSC Transmit Frame Sync 2 */
+#define AT91RM92_PB12_ETX2 (AT91RM92_PIO_PB12) /* Ethernet MAC Transmit Data 2 */
+#define AT91RM92_PIO_PB13 (1 << 13)
+#define AT91RM92_PB13_TK2 (AT91RM92_PIO_PB13) /* SSC Transmit Clock 2 */
+#define AT91RM92_PB13_ETX3 (AT91RM92_PIO_PB13) /* Ethernet MAC Transmit Data 3 */
+#define AT91RM92_PIO_PB14 (1 << 14)
+#define AT91RM92_PB14_TD2 (AT91RM92_PIO_PB14) /* SSC Transmit Data 2 */
+#define AT91RM92_PB14_ETXER (AT91RM92_PIO_PB14) /* Ethernet MAC Transmikt Coding Error */
+#define AT91RM92_PIO_PB15 (1 << 15)
+#define AT91RM92_PB15_RD2 (AT91RM92_PIO_PB15) /* SSC Receive Data 2 */
+#define AT91RM92_PB15_ERX2 (AT91RM92_PIO_PB15) /* Ethernet MAC Receive Data 2 */
+#define AT91RM92_PIO_PB16 (1 << 16)
+#define AT91RM92_PB16_RK2 (AT91RM92_PIO_PB16) /* SSC Receive Clock 2 */
+#define AT91RM92_PB16_ERX3 (AT91RM92_PIO_PB16) /* Ethernet MAC Receive Data 3 */
+#define AT91RM92_PIO_PB17 (1 << 17)
+#define AT91RM92_PB17_RF2 (AT91RM92_PIO_PB17) /* SSC Receive Frame Sync 2 */
+#define AT91RM92_PB17_ERXDV (AT91RM92_PIO_PB17) /* Ethernet MAC Receive Data Valid */
+#define AT91RM92_PIO_PB18 (1 << 18)
+#define AT91RM92_PB18_RI1 (AT91RM92_PIO_PB18) /* USART 1 Ring Indicator */
+#define AT91RM92_PB18_ECOL (AT91RM92_PIO_PB18) /* Ethernet MAC Collision Detected */
+#define AT91RM92_PIO_PB19 (1 << 19)
+#define AT91RM92_PB19_DTR1 (AT91RM92_PIO_PB19) /* USART 1 Data Terminal ready */
+#define AT91RM92_PB19_ERXCK (AT91RM92_PIO_PB19) /* Ethernet MAC Receive Clock */
+#define AT91RM92_PIO_PB20 (1 << 20)
+#define AT91RM92_PB20_TXD1 (AT91RM92_PIO_PB20) /* USART 1 Transmit Data */
+#define AT91RM92_PIO_PB21 (1 << 21)
+#define AT91RM92_PB21_RXD1 (AT91RM92_PIO_PB21) /* USART 1 Receive Data */
+#define AT91RM92_PIO_PB22 (1 << 22)
+#define AT91RM92_PB22_SCK1 (AT91RM92_PIO_PB22) /* USART 1 Serial Clock */
+#define AT91RM92_PIO_PB23 (1 << 23)
+#define AT91RM92_PB23_DCD1 (AT91RM92_PIO_PB23) /* USART 1 Data Carrier Detect */
+#define AT91RM92_PIO_PB24 (1 << 24)
+#define AT91RM92_PB24_CTS1 (AT91RM92_PIO_PB24) /* USART 1 Clear To Send */
+#define AT91RM92_PIO_PB25 (1 << 25)
+#define AT91RM92_PB25_DSR1 (AT91RM92_PIO_PB25) /* USART 1 Data Set ready */
+#define AT91RM92_PB25_EF100 (AT91RM92_PIO_PB25) /* Ethernet MAC Force 100 Mbits/sec */
+#define AT91RM92_PIO_PB26 (1 << 26)
+#define AT91RM92_PB26_RTS1 (AT91RM92_PIO_PB26) /* USART 1 Ready To Send */
+#define AT91RM92_PIO_PB27 (1 << 27)
+#define AT91RM92_PB27_PCK0 (AT91RM92_PIO_PB27) /* PMC Programmable Clock Output 0 */
+#define AT91RM92_PIO_PB28 (1 << 28)
+#define AT91RM92_PB28_FIQ (AT91RM92_PIO_PB28) /* AIC Fast Interrupt Input */
+#define AT91RM92_PIO_PB29 (1 << 29)
+#define AT91RM92_PB29_IRQ0 (AT91RM92_PIO_PB29) /* Interrupt input 0 */
+
+#define AT91RM92_PIO_PC0 (1 << 0)
+#define AT91RM92_PC0_BFCK (AT91RM92_PIO_PC0) /* Burst Flash Clock */
+#define AT91RM92_PIO_PC1 (1 << 1)
+#define AT91RM92_PC1_BFRDY_SMOE (AT91RM92_PIO_PC1) /* Burst Flash Ready */
+#define AT91RM92_PIO_PC2 (1 << 2)
+#define AT91RM92_PC2_BFAVD (AT91RM92_PIO_PC2) /* Burst Flash Address Valid */
+#define AT91RM92_PIO_PC3 (1 << 3)
+#define AT91RM92_PC3_BFBAA_SMWE (AT91RM92_PIO_PC3) /* Burst Flash Address Advance / SmartMedia Write Enable */
+#define AT91RM92_PIO_PC4 (1 << 4)
+#define AT91RM92_PC4_BFOE (AT91RM92_PIO_PC4) /* Burst Flash Output Enable */
+#define AT91RM92_PIO_PC5 (1 << 5)
+#define AT91RM92_PC5_BFWE (AT91RM92_PIO_PC5) /* Burst Flash Write Enable */
+#define AT91RM92_PIO_PC6 (1 << 6)
+#define AT91RM92_PC6_NWAIT (AT91RM92_PIO_PC6) /* NWAIT */
+#define AT91RM92_PIO_PC7 (1 << 7)
+#define AT91RM92_PC7_A23 (AT91RM92_PIO_PC7) /* Address Bus[23] */
+#define AT91RM92_PIO_PC8 (1 << 8)
+#define AT91RM92_PC8_A24 (AT91RM92_PIO_PC8) /* Address Bus[24] */
+#define AT91RM92_PIO_PC9 (1 << 9)
+#define AT91RM92_PC9_A25_CFRNW (AT91RM92_PIO_PC9) /* Address Bus[25] / Compact Flash Read Not Write */
+#define AT91RM92_PIO_PC10 (1 << 10)
+#define AT91RM92_PC10_NCS4_CFCS (AT91RM92_PIO_PC10) /* Compact Flash Chip Select */
+#define AT91RM92_PIO_PC11 (1 << 11)
+#define AT91RM92_PC11_NCS5_CFCE1 (AT91RM92_PIO_PC11) /* Chip Select 5 / Compact Flash Chip Enable 1 */
+#define AT91RM92_PIO_PC12 (1 << 12)
+#define AT91RM92_PC12_NCS6_CFCE2(AT91RM92_PIO_PC12) /* Chip Select 6 / Compact Flash Chip Enable 2 */
+#define AT91RM92_PIO_PC13 (1 << 13)
+#define AT91RM92_PC13_NCS7 (AT91RM92_PIO_PC13) /* Chip Select 7 */
+#define AT91RM92_PIO_PC14 (1 << 14)
+#define AT91RM92_PIO_PC15 (1 << 15)
+#define AT91RM92_PIO_PC16 (1 << 16)
+#define AT91RM92_PC16_D16 (AT91RM92_PIO_PC16) /* Data Bus [16] */
+#define AT91RM92_PIO_PC17 (1 << 17)
+#define AT91RM92_PC17_D17 (AT91RM92_PIO_PC17) /* Data Bus [17] */
+#define AT91RM92_PIO_PC18 (1 << 18)
+#define AT91RM92_PC18_D18 (AT91RM92_PIO_PC18) /* Data Bus [18] */
+#define AT91RM92_PIO_PC19 (1 << 19)
+#define AT91RM92_PC19_D19 (AT91RM92_PIO_PC19) /* Data Bus [19] */
+#define AT91RM92_PIO_PC20 (1 << 20)
+#define AT91RM92_PC20_D20 (AT91RM92_PIO_PC20) /* Data Bus [20] */
+#define AT91RM92_PIO_PC21 (1 << 21)
+#define AT91RM92_PC21_D21 (AT91RM92_PIO_PC21) /* Data Bus [21] */
+#define AT91RM92_PIO_PC22 (1 << 22)
+#define AT91RM92_PC22_D22 (AT91RM92_PIO_PC22) /* Data Bus [22] */
+#define AT91RM92_PIO_PC23 (1 << 23)
+#define AT91RM92_PC23_D23 (AT91RM92_PIO_PC23) /* Data Bus [23] */
+#define AT91RM92_PIO_PC24 (1 << 24)
+#define AT91RM92_PC24_D24 (AT91RM92_PIO_PC24) /* Data Bus [24] */
+#define AT91RM92_PIO_PC25 (1 << 25)
+#define AT91RM92_PC25_D25 (AT91RM92_PIO_PC25) /* Data Bus [25] */
+#define AT91RM92_PIO_PC26 (1 << 26)
+#define AT91RM92_PC26_D26 (AT91RM92_PIO_PC26) /* Data Bus [26] */
+#define AT91RM92_PIO_PC27 (1 << 27)
+#define AT91RM92_PC27_D27 (AT91RM92_PIO_PC27) /* Data Bus [27] */
+#define AT91RM92_PIO_PC28 (1 << 28)
+#define AT91RM92_PC28_D28 (AT91RM92_PIO_PC28) /* Data Bus [28] */
+#define AT91RM92_PIO_PC29 (1 << 29)
+#define AT91RM92_PC29_D29 (AT91RM92_PIO_PC29) /* Data Bus [29] */
+#define AT91RM92_PIO_PC30 (1 << 30)
+#define AT91RM92_PC30_D30 (AT91RM92_PIO_PC30) /* Data Bus [30] */
+#define AT91RM92_PIO_PC31 (1 << 31)
+#define AT91RM92_PC31_D31 (AT91RM92_PIO_PC31) /* Data Bus [31] */
+
+#define AT91RM92_PIO_PD0 (1 << 0)
+#define AT91RM92_PD0_ETX0 (AT91RM92_PIO_PD0) /* Ethernet MAC Transmit Data 0 */
+#define AT91RM92_PIO_PD1 (1 << 1)
+#define AT91RM92_PD1_ETX1 (AT91RM92_PIO_PD1) /* Ethernet MAC Transmit Data 1 */
+#define AT91RM92_PIO_PD2 (1 << 2)
+#define AT91RM92_PD2_ETX2 (AT91RM92_PIO_PD2) /* Ethernet MAC Transmit Data 2 */
+#define AT91RM92_PIO_PD3 (1 << 3)
+#define AT91RM92_PD3_ETX3 (AT91RM92_PIO_PD3) /* Ethernet MAC Transmit Data 3 */
+#define AT91RM92_PIO_PD4 (1 << 4)
+#define AT91RM92_PD4_ETXEN (AT91RM92_PIO_PD4) /* Ethernet MAC Transmit Enable */
+#define AT91RM92_PIO_PD5 (1 << 5)
+#define AT91RM92_PD5_ETXER (AT91RM92_PIO_PD5) /* Ethernet MAC Transmit Coding Error */
+#define AT91RM92_PIO_PD6 (1 << 6)
+#define AT91RM92_PD6_DTXD (AT91RM92_PIO_PD6) /* DBGU Debug Transmit Data */
+#define AT91RM92_PIO_PD7 (1 << 7)
+#define AT91RM92_PD7_PCK0 (AT91RM92_PIO_PD7) /* PMC Programmable Clock Output 0 */
+#define AT91RM92_PD7_TSYNC (AT91RM92_PIO_PD7) /* ETM Synchronization signal */
+#define AT91RM92_PIO_PD8 (1 << 8)
+#define AT91RM92_PD8_PCK1 (AT91RM92_PIO_PD8) /* PMC Programmable Clock Output 1 */
+#define AT91RM92_PD8_TCLK (AT91RM92_PIO_PD8) /* ETM Trace Clock signal */
+#define AT91RM92_PIO_PD9 (1 << 9)
+#define AT91RM92_PD9_PCK2 (AT91RM92_PIO_PD9) /* PMC Programmable Clock 2 */
+#define AT91RM92_PD9_TPS0 (AT91RM92_PIO_PD9) /* ETM ARM9 pipeline status 0 */
+#define AT91RM92_PIO_PD10 (1 << 10)
+#define AT91RM92_PD10_PCK3 (AT91RM92_PIO_PD10) /* PMC Programmable Clock Output 3 */
+#define AT91RM92_PD10_TPS1 (AT91RM92_PIO_PD10) /* ETM ARM9 pipeline status 1 */
+#define AT91RM92_PIO_PD11 (1 << 11)
+#define AT91RM92_PD11_TPS2 (AT91RM92_PIO_PD11) /* ETM ARM9 pipeline status 2 */
+#define AT91RM92_PIO_PD12 (1 << 12)
+#define AT91RM92_PD12_TPK0 (AT91RM92_PIO_PD12) /* ETM Trace Packet 0 */
+#define AT91RM92_PIO_PD13 (1 << 13)
+#define AT91RM92_PD13_TPK1 (AT91RM92_PIO_PD13) /* ETM Trace Packet 1 */
+#define AT91RM92_PIO_PD14 (1 << 14)
+#define AT91RM92_PD14_TPK2 (AT91RM92_PIO_PD14) /* ETM Trace Packet 2 */
+#define AT91RM92_PIO_PD15 (1 << 15)
+#define AT91RM92_PD15_TD0 (AT91RM92_PIO_PD15) /* SSC Transmit data */
+#define AT91RM92_PD15_TPK3 (AT91RM92_PIO_PD15) /* ETM Trace Packet 3 */
+#define AT91RM92_PIO_PD16 (1 << 16)
+#define AT91RM92_PD16_TD1 (AT91RM92_PIO_PD16) /* SSC Transmit Data 1 */
+#define AT91RM92_PD16_TPK4 (AT91RM92_PIO_PD16) /* ETM Trace Packet 4 */
+#define AT91RM92_PIO_PD17 (1 << 17)
+#define AT91RM92_PD17_TD2 (AT91RM92_PIO_PD17) /* SSC Transmit Data 2 */
+#define AT91RM92_PD17_TPK5 (AT91RM92_PIO_PD17) /* ETM Trace Packet 5 */
+#define AT91RM92_PIO_PD18 (1 << 18)
+#define AT91RM92_PD18_NPCS1 (AT91RM92_PIO_PD18) /* SPI Peripheral Chip Select 1 */
+#define AT91RM92_PD18_TPK6 (AT91RM92_PIO_PD18) /* ETM Trace Packet 6 */
+#define AT91RM92_PIO_PD19 (1 << 19)
+#define AT91RM92_PD19_NPCS2 (AT91RM92_PIO_PD19) /* SPI Peripheral Chip Select 2 */
+#define AT91RM92_PD19_TPK7 (AT91RM92_PIO_PD19) /* ETM Trace Packet 7 */
+#define AT91RM92_PIO_PD20 (1 << 20)
+#define AT91RM92_PD20_NPCS3 (AT91RM92_PIO_PD20) /* SPI Peripheral Chip Select 3 */
+#define AT91RM92_PD20_TPK8 (AT91RM92_PIO_PD20) /* ETM Trace Packet 8 */
+#define AT91RM92_PIO_PD21 (1 << 21)
+#define AT91RM92_PD21_RTS0 (AT91RM92_PIO_PD21) /* Usart 0 Ready To Send */
+#define AT91RM92_PD21_TPK9 (AT91RM92_PIO_PD21) /* ETM Trace Packet 9 */
+#define AT91RM92_PIO_PD22 (1 << 22)
+#define AT91RM92_PD22_RTS1 (AT91RM92_PIO_PD22) /* Usart 0 Ready To Send */
+#define AT91RM92_PD22_TPK10 (AT91RM92_PIO_PD22) /* ETM Trace Packet 10 */
+#define AT91RM92_PIO_PD23 (1 << 23)
+#define AT91RM92_PD23_RTS2 (AT91RM92_PIO_PD23) /* USART 2 Ready To Send */
+#define AT91RM92_PD23_TPK11 (AT91RM92_PIO_PD23) /* ETM Trace Packet 11 */
+#define AT91RM92_PIO_PD24 (1 << 24)
+#define AT91RM92_PD24_RTS3 (AT91RM92_PIO_PD24) /* USART 3 Ready To Send */
+#define AT91RM92_PD24_TPK12 (AT91RM92_PIO_PD24) /* ETM Trace Packet 12 */
+#define AT91RM92_PIO_PD25 (1 << 25)
+#define AT91RM92_PD25_DTR1 (AT91RM92_PIO_PD25) /* USART 1 Data Terminal ready */
+#define AT91RM92_PD25_TPK13 (AT91RM92_PIO_PD25) /* ETM Trace Packet 13 */
+#define AT91RM92_PIO_PD26 (1 << 26)
+#define AT91RM92_PD26_TPK14 (AT91RM92_PIO_PD26) /* ETM Trace Packet 14 */
+#define AT91RM92_PIO_PD27 (1 << 27)
+#define AT91RM92_PD27_TPK15 (AT91RM92_PIO_PD27) /* ETM Trace Packet 15 */
+
+#define AT91C_MASTER_CLOCK 60000000
+
+#endif /* AT91RM92REG_H_ */
diff --git a/sys/arm/at91/at91st.c b/sys/arm/at91/at91st.c
new file mode 100644
index 0000000..a744222
--- /dev/null
+++ b/sys/arm/at91/at91st.c
@@ -0,0 +1,215 @@
+/*-
+ * Copyright (c) 2005 Olivier Houchard. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/time.h>
+#include <sys/bus.h>
+#include <sys/resource.h>
+#include <sys/rman.h>
+#include <sys/timetc.h>
+
+#include <machine/bus.h>
+#include <machine/cpu.h>
+#include <machine/cpufunc.h>
+#include <machine/resource.h>
+#include <machine/frame.h>
+#include <machine/intr.h>
+#include <arm/at91/at91rm92reg.h>
+#include <arm/at91/at91streg.h>
+#include <arm/at91/at91var.h>
+
+static struct at91st_softc {
+ bus_space_tag_t sc_st;
+ bus_space_handle_t sc_sh;
+ device_t dev;
+} *timer_softc;
+
+#define RD4(off) \
+ bus_space_read_4(timer_softc->sc_st, timer_softc->sc_sh, (off))
+#define WR4(off, val) \
+ bus_space_write_4(timer_softc->sc_st, timer_softc->sc_sh, (off), (val))
+
+static inline int
+st_crtr(void)
+{
+ int cur1, cur2;
+ do {
+ cur1 = RD4(ST_CRTR);
+ cur2 = RD4(ST_CRTR);
+ } while (cur1 != cur2);
+ return (cur1);
+}
+
+static unsigned at91st_get_timecount(struct timecounter *tc);
+
+static struct timecounter at91st_timecounter = {
+ at91st_get_timecount, /* get_timecount */
+ NULL, /* no poll_pps */
+ 0xfffffu, /* counter_mask */
+ 32768, /* frequency */
+ "AT91RM9200 timer", /* name */
+ 0 /* quality */
+};
+
+static int
+at91st_probe(device_t dev)
+{
+
+ device_set_desc(dev, "ST");
+ return (0);
+}
+
+static int
+at91st_attach(device_t dev)
+{
+ struct at91_softc *sc = device_get_softc(device_get_parent(dev));
+
+ timer_softc = device_get_softc(dev);
+ timer_softc->sc_st = sc->sc_st;
+ timer_softc->dev = dev;
+ if (bus_space_subregion(sc->sc_st, sc->sc_sh, AT91RM92_ST_BASE,
+ AT91RM92_ST_SIZE, &timer_softc->sc_sh) != 0)
+ panic("couldn't subregion timer registers");
+ /*
+ * Real time counter increments every clock cycle, need to set before
+ * initializing clocks so that DELAY works.
+ */
+ WR4(ST_RTMR, 1);
+
+ return (0);
+}
+
+static device_method_t at91st_methods[] = {
+ DEVMETHOD(device_probe, at91st_probe),
+ DEVMETHOD(device_attach, at91st_attach),
+ {0, 0},
+};
+
+static driver_t at91st_driver = {
+ "at91_st",
+ at91st_methods,
+ sizeof(struct at91st_softc),
+};
+static devclass_t at91st_devclass;
+
+DRIVER_MODULE(at91_st, atmelarm, at91st_driver, at91st_devclass, 0, 0);
+
+static unsigned
+at91st_get_timecount(struct timecounter *tc)
+{
+ return (st_crtr());
+}
+
+static void
+clock_intr(void *arg)
+{
+ struct trapframe *fp = arg;
+
+ /* The interrupt is shared, so we have to make sure it's for us. */
+ if (RD4(ST_SR) & ST_SR_PITS)
+ hardclock(TRAPF_USERMODE(fp), TRAPF_PC(fp));
+}
+
+void
+cpu_initclocks(void)
+{
+ int rel_value;
+ struct resource *irq;
+ int rid = 0;
+ void *ih;
+ device_t dev = timer_softc->dev;
+
+ if (32768 % hz) {
+ printf("Cannot get %d Hz clock; using 128Hz\n", hz);
+ hz = 128;
+ }
+ rel_value = 32768 / hz;
+ /* Disable all interrupts. */
+ WR4(ST_IDR, 0xffffffff);
+ /* The system timer shares the system irq (1) */
+ irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 1, 1, 1,
+ RF_ACTIVE | RF_SHAREABLE);
+ if (!irq)
+ panic("Unable to allocate irq for the system timer");
+ else
+ bus_setup_intr(dev, irq, INTR_TYPE_CLK | INTR_FAST,
+ clock_intr, NULL, &ih);
+
+ WR4(ST_PIMR, rel_value);
+
+ /* Enable PITS interrupts. */
+ WR4(ST_IER, ST_SR_PITS);
+ tc_init(&at91st_timecounter);
+}
+
+void
+DELAY(int n)
+{
+ uint32_t start, end, cur;
+
+ start = st_crtr();
+ n = (n * 1000000) / 32768;
+ if (n <= 0)
+ n = 1;
+ end = (start + n) & ST_CRTR_MASK;
+ cur = start;
+ if (start > end) {
+ while (cur >= start || cur < end)
+ cur = st_crtr();
+ } else {
+ while (cur < end)
+ cur = st_crtr();
+ }
+}
+
+void
+cpu_reset(void)
+{
+ /*
+ * Reset the CPU by programmig the watchdog timer to reset the
+ * CPU after 128 'slow' clocks, or about ~4ms. Loop until
+ * the reset happens for safety.
+ */
+ WR4(ST_WDMR, ST_WDMR_RSTEN | 2);
+ WR4(ST_CR, ST_CR_WDRST);
+ while (1)
+ continue;
+}
+
+void
+cpu_startprofclock(void)
+{
+}
+
+void
+cpu_stopprofclock(void)
+{
+}
+
diff --git a/sys/arm/at91/at91var.h b/sys/arm/at91/at91var.h
new file mode 100644
index 0000000..6294f1c
--- /dev/null
+++ b/sys/arm/at91/at91var.h
@@ -0,0 +1,46 @@
+/*-
+ * Copyright (c) 2005 Olivier Houchard. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* $FreeBSD$ */
+
+#ifndef _AT91VAR_H_
+#define _AT91VAR_H_
+
+#include <sys/rman.h>
+
+struct at91_softc {
+ device_t dev;
+ bus_space_tag_t sc_st;
+ bus_space_handle_t sc_sh;
+ bus_space_handle_t sc_sys_sh;
+ struct rman sc_irq_rman;
+ struct rman sc_mem_rman;
+};
+
+struct at91_ivar {
+ struct resource_list resources;
+};
+
+
+#endif /* _AT91VAR_H_ */
diff --git a/sys/arm/at91/files.at91rm92 b/sys/arm/at91/files.at91rm92
new file mode 100644
index 0000000..dbeb8ed
--- /dev/null
+++ b/sys/arm/at91/files.at91rm92
@@ -0,0 +1,17 @@
+# $FreeBSD$
+arm/arm/cpufunc_asm_arm9.S standard
+arm/arm/irq_dispatch.S standard
+arm/at91/at91.c standard
+arm/at91/at91_st.c standard
+arm/at91/uart_bus_at91usart.c optional uart
+arm/at91/uart_cpu_at91rm9200usart.c optional uart
+arm/at91/uart_dev_at91usart.c optional uart
+arm/at91/if_ate.c optional ate
+arm/at91/at91_mci.c optional at91_mci
+arm/at91/at91_pio.c optional at91_pio
+arm/at91/at91_pmc.c optional at91_pmc
+arm/at91/at91_ssc.c optional at91_ssc
+arm/at91/at91_spi.c optional at91_spi
+arm/at91/at91_twi.c optional at91_twi
+arm/at91/at91_udp.c optional at91_udp
+arm/at91/ohci_atmelarm.c optional ohci
diff --git a/sys/arm/at91/files.kb920x b/sys/arm/at91/files.kb920x
new file mode 100644
index 0000000..a35a5cd
--- /dev/null
+++ b/sys/arm/at91/files.kb920x
@@ -0,0 +1,2 @@
+#$FreeBSD$
+arm/at91/kb920x_machdep.c standard
diff --git a/sys/arm/at91/hints.at91rm9200 b/sys/arm/at91/hints.at91rm9200
new file mode 100644
index 0000000..4fb861f
--- /dev/null
+++ b/sys/arm/at91/hints.at91rm9200
@@ -0,0 +1,68 @@
+# $FreeBSD$
+#
+
+# These are the wiring for the at91rm9200. These are the built-in devices
+# for that cpu.
+
+# DBGU is unit 0
+hint.uart.0.at="apb"
+hint.uart.0.maddr="0xfffff200"
+hint.uart.0.flags=0x10
+# USART0 is unit 1
+hint.uart.1.at="apb"
+hint.uart.1.maddr="0xfffc0000"
+# USART1 is unit 2
+hint.uart.2.at="apb"
+hint.uart.2.maddr="0xfffc4000"
+# USART2 is unit 3
+hint.uart.3.at="apb"
+hint.uart.3.maddr="0xfffc8000"
+# USART3 is unit 4
+hint.uart.4.at="apb"
+hint.uart.4.maddr="0xfffcc000"
+
+# SSC0
+hint.ssc.0.at="apb"
+hint.ssc.0.maddr="0xfffd0000"
+# SSC1
+hint.ssc.1.at="apb"
+hint.ssc.1.maddr="0xfffd4000"
+# SSC2
+hint.ssc.1.at="apb"
+hint.ssc.1.maddr="0xfffd8000"
+
+# TC0, TC1, TC2
+hint.tc.0.at="apb"
+hint.tc.0.maddr="0xfffa0000"
+# TC3, TC4, TC5
+hint.tc.1.at="apb"
+hint.tc.1.maddr="0xfffa4000"
+
+# USB Device
+hint.udp.0.at="apb"
+hint.udp.0.maddr="0xfffb0000"
+
+# MCI
+hint.mci.0.at="apb"
+hint.mci.0.maddr="0xfffb4000"
+
+# TWI
+hint.twi.0.at="apb"
+hint.twi.0.maddr="0xfffb8000"
+
+# EMAC
+hint.emac.0.at="apb"
+hint.emac.0.maddr="0xfffbc000"
+
+# SPI
+hint.spi.0.at="apb"
+hint.spi.0.maddr="0xfffe0000"
+
+# PMC
+hint.pmc.0.at="apb"
+hint.pmc.0.maddr="0xfffffc00"
+
+# USB host (ohci)
+#??? maybe this needs to be on asb instead of apb
+hint.ohci.at="apb"
+hint.ohci.maddr="0x00300000"
diff --git a/sys/arm/at91/hints.at91sam9261 b/sys/arm/at91/hints.at91sam9261
new file mode 100644
index 0000000..b60c60e
--- /dev/null
+++ b/sys/arm/at91/hints.at91sam9261
@@ -0,0 +1,67 @@
+# $FreeBSD$
+#
+
+# These are the wiring for the at91sam9261. These are the built-in devices
+# for that cpu.
+
+# DBGU is unit 0
+hint.uart.0.at="apb"
+hint.uart.0.maddr="0xfffff200"
+hint.uart.0.flags=0x10
+# USART0 is unit 1
+hint.uart.1.at="apb"
+hint.uart.1.maddr="0xfffb0000"
+# USART1 is unit 2
+hint.uart.2.at="apb"
+hint.uart.2.maddr="0xfffb4000"
+# USART2 is unit 3
+hint.uart.3.at="apb"
+hint.uart.3.maddr="0xfffb8000"
+# USART3 is unit 4
+hint.uart.4.at="apb"
+hint.uart.4.maddr="0xfffbc000"
+
+# TC0, TC1, TC2
+hint.tc.0.at="apb"
+hint.tc.0.maddr="0xfffa0000"
+
+# USB Device
+hint.udp.0.at="apb"
+hint.udp.0.maddr="0xfffa4000"
+
+# MCI
+hint.mci.0.at="apb"
+hint.mci.0.maddr="0xfffa8000"
+
+# TWI
+hint.twi.0.at="apb"
+hint.twi.0.maddr="0xfffac000"
+
+# SSC0
+hint.ssc.0.at="apb"
+hint.ssc.0.maddr="0xfffbc000"
+# SSC1
+hint.ssc.1.at="apb"
+hint.ssc.1.maddr="0xfffc0000"
+# SSC2
+hint.ssc.1.at="apb"
+hint.ssc.1.maddr="0xfffc4000"
+
+# SPI0
+hint.spi.0.at="apb"
+hint.spi.0.maddr="0xfffc8000"
+# SSC1
+hint.spi.1.at="apb"
+hint.spi.1.maddr="0xfffcc000"
+
+# PMC
+hint.pmc.0.at="apb"
+hint.pmc.0.maddr="0xfffffc00"
+
+# USB host (ohci)
+#??? maybe this needs to be on asb instead of apb
+hint.ohci.at="apb"
+hint.ohci.maddr="0x00500000"
+# LCD controller
+hint.atlcd.at="apb"
+hint.atlcd.maddr="0x00600000"
diff --git a/sys/arm/at91/if_ate.c b/sys/arm/at91/if_ate.c
new file mode 100644
index 0000000..2736240
--- /dev/null
+++ b/sys/arm/at91/if_ate.c
@@ -0,0 +1,982 @@
+/*-
+ * Copyright (c) 2006 M. Warner Losh. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* TODO: (in no order)
+ *
+ * 5) Setup RX buffers in ateinit_locked
+ * 8) Need to sync busdma goo in atestop
+ * 9) atestop should maybe free the mbufs?
+ * 10) On Rx, how do we get a new mbuf?
+ *
+ * 1) detach
+ * 2) Free dma setup
+ * 3) Turn on the clock in pmc and turn on pins? Turn off?
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/mbuf.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/rman.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <machine/bus.h>
+
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+#include <net/if_mib.h>
+#include <net/if_types.h>
+
+#ifdef INET
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/in_var.h>
+#include <netinet/ip.h>
+#endif
+
+#include <net/bpf.h>
+#include <net/bpfdesc.h>
+
+#include <dev/mii/mii.h>
+#include <dev/mii/miivar.h>
+#include <arm/at91/if_atereg.h>
+
+#include "miibus_if.h"
+
+#define ATE_MAX_TX_BUFFERS 2 /* We have ping-pong tx buffers */
+#define ATE_MAX_RX_BUFFERS 8
+
+struct ate_softc
+{
+ struct ifnet *ifp; /* ifnet pointer */
+ struct mtx sc_mtx; /* basically a perimeter lock */
+ device_t dev; /* Myself */
+ device_t miibus; /* My child miibus */
+ void *intrhand; /* Interrupt handle */
+ struct resource *irq_res; /* IRQ resource */
+ struct resource *mem_res; /* Memory resource */
+ struct callout tick_ch; /* Tick callout */
+ bus_dma_tag_t mtag; /* bus dma tag for mbufs */
+ bus_dmamap_t tx_map[ATE_MAX_TX_BUFFERS];
+ bus_dma_tag_t rxtag;
+ bus_dmamap_t rx_map[ATE_MAX_RX_BUFFERS];
+ bus_dma_tag_t rx_desc_tag;
+ bus_dmamap_t rx_desc_map;
+ int txcur; /* current tx map pointer */
+ struct mbuf *sent_mbuf[ATE_MAX_TX_BUFFERS]; /* Sent mbufs */
+ struct mbuf *rx_mbuf[ATE_MAX_RX_BUFFERS]; /* RX mbufs */
+ bus_addr_t rx_desc_phys;
+ eth_rx_desc_t *rx_descs;
+ struct ifmib_iso_8802_3 mibdata; /* stuff for network mgmt */
+};
+
+static inline uint32_t
+RD4(struct ate_softc *sc, bus_size_t off)
+{
+ return bus_read_4(sc->mem_res, off);
+}
+
+static inline void
+WR4(struct ate_softc *sc, bus_size_t off, uint32_t val)
+{
+ bus_write_4(sc->mem_res, off, val);
+}
+
+#define ATE_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx)
+#define ATE_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx)
+#define ATE_LOCK_INIT(_sc) \
+ mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->dev), \
+ MTX_NETWORK_LOCK, MTX_DEF)
+#define ATE_LOCK_DESTROY(_sc) mtx_destroy(&_sc->sc_mtx);
+#define ATE_ASSERT_LOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_OWNED);
+#define ATE_ASSERT_UNLOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_NOTOWNED);
+
+static devclass_t ate_devclass;
+
+/* ifnet entry points */
+
+static void ateinit_locked(void *);
+static void atestart_locked(struct ifnet *);
+
+static void ateinit(void *);
+static void atestart(struct ifnet *);
+static void atestop(struct ate_softc *);
+static void atewatchdog(struct ifnet *);
+static int ateioctl(struct ifnet * ifp, u_long, caddr_t);
+
+/* bus entry points */
+
+static int ate_probe(device_t dev);
+static int ate_attach(device_t dev);
+static int ate_detach(device_t dev);
+static void ate_intr(void *);
+
+/* helper routines */
+static int ate_activate(device_t dev);
+static void ate_deactivate(device_t dev);
+static int ate_ifmedia_upd(struct ifnet *ifp);
+static void ate_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr);
+static void ate_get_mac(struct ate_softc *sc, u_char *eaddr);
+
+/*
+ * The AT91 family of products has the ethernet called EMAC. However,
+ * it isn't self identifying. It is anticipated that the parent bus
+ * code will take care to only add ate devices where they really are. As
+ * such, we do nothing here to identify the device and just set its name.
+ */
+static int
+ate_probe(device_t dev)
+{
+ device_set_desc(dev, "EMAC");
+ return (0);
+}
+
+static int
+ate_attach(device_t dev)
+{
+ struct ate_softc *sc = device_get_softc(dev);
+ struct ifnet *ifp = NULL;
+ int err;
+ u_char eaddr[6];
+
+ sc->dev = dev;
+ err = ate_activate(dev);
+ if (err)
+ goto out;
+
+ /* calling atestop before ifp is set is OK */
+ atestop(sc);
+ ATE_LOCK_INIT(sc);
+ callout_init_mtx(&sc->tick_ch, &sc->sc_mtx, 0);
+
+ ate_get_mac(sc, eaddr);
+
+ if (mii_phy_probe(dev, &sc->miibus, ate_ifmedia_upd, ate_ifmedia_sts)) {
+ device_printf(dev, "Cannot find my PHY.\n");
+ err = ENXIO;
+ goto out;
+ }
+
+ sc->ifp = ifp = if_alloc(IFT_ETHER);
+ ifp->if_softc = sc;
+ if_initname(ifp, device_get_name(dev), device_get_unit(dev));
+ ifp->if_mtu = ETHERMTU;
+ ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+ ifp->if_start = atestart;
+ ifp->if_ioctl = ateioctl;
+ ifp->if_watchdog = atewatchdog;
+ ifp->if_init = ateinit;
+ ifp->if_baudrate = 10000000;
+ IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
+ ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;
+ IFQ_SET_READY(&ifp->if_snd);
+ ifp->if_timer = 0;
+ ifp->if_linkmib = &sc->mibdata;
+ ifp->if_linkmiblen = sizeof(sc->mibdata);
+ sc->mibdata.dot3Compliance = DOT3COMPLIANCE_COLLS;
+
+ ether_ifattach(ifp, eaddr);
+
+ /*
+ * Activate the interrupt
+ */
+ err = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_NET | INTR_MPSAFE,
+ ate_intr, sc, &sc->intrhand);
+ if (err) {
+ ether_ifdetach(ifp);
+ ATE_LOCK_DESTROY(sc);
+ }
+out:;
+ if (err)
+ ate_deactivate(dev);
+ if (err && ifp)
+ if_free(ifp);
+ return (err);
+}
+
+static int
+ate_detach(device_t dev)
+{
+ return EBUSY; /* XXX TODO(1) */
+}
+
+static void
+ate_getaddr(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
+{
+ struct ate_softc *sc;
+
+ if (error != 0)
+ return;
+ sc = (struct ate_softc *)arg;
+ sc->rx_desc_phys = segs[0].ds_addr;
+}
+
+/*
+ * Compute the multicast filter for this device using the standard
+ * algorithm. I wonder why this isn't in ether somewhere as a lot
+ * of different MAC chips use this method (or the reverse the bits)
+ * method.
+ */
+static void
+ate_setmcast(struct ate_softc *sc)
+{
+ uint32_t index;
+ uint32_t mcaf[2];
+ u_char *af = (u_char *) mcaf;
+ struct ifmultiaddr *ifma;
+
+ mcaf[0] = 0;
+ mcaf[1] = 0;
+
+ IF_ADDR_LOCK(sc->ifp);
+ TAILQ_FOREACH(ifma, &sc->ifp->if_multiaddrs, ifma_link) {
+ if (ifma->ifma_addr->sa_family != AF_LINK)
+ continue;
+ index = ether_crc32_be(LLADDR((struct sockaddr_dl *)
+ ifma->ifma_addr), ETHER_ADDR_LEN) >> 26;
+ af[index >> 3] |= 1 << (index & 7);
+ }
+ IF_ADDR_UNLOCK(sc->ifp);
+
+ /*
+ * Write the hash to the hash register. This card can also
+ * accept unicast packets as well as multicast packets using this
+ * register for easier bridging operations, but we don't take
+ * advantage of that. Locks here are to avoid LOR with the
+ * IF_ADDR_LOCK, but might not be strictly necessary.
+ */
+ ATE_LOCK(sc);
+ WR4(sc, ETH_HSL, mcaf[0]);
+ WR4(sc, ETH_HSH, mcaf[1]);
+ ATE_UNLOCK(sc);
+}
+
+static int
+ate_activate(device_t dev)
+{
+ struct ate_softc *sc;
+ int rid, err, i;
+
+ sc = device_get_softc(dev);
+ rid = 0;
+ sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
+ RF_ACTIVE);
+ if (sc->mem_res == NULL)
+ goto errout;
+ rid = 0;
+ sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
+ RF_ACTIVE);
+ if (sc->mem_res == NULL)
+ goto errout;
+
+ /*
+ * Allocate DMA tags and maps
+ */
+ err = bus_dma_tag_create(NULL, 1, 0, BUS_SPACE_MAXADDR_32BIT,
+ BUS_SPACE_MAXADDR, NULL, NULL, MCLBYTES, 1, MCLBYTES, 0,
+ busdma_lock_mutex, &sc->sc_mtx, &sc->mtag);
+ if (err != 0)
+ goto errout;
+ for (i = 0; i < ATE_MAX_TX_BUFFERS; i++) {
+ err = bus_dmamap_create(sc->mtag, 0, &sc->tx_map[i]);
+ if (err != 0)
+ goto errout;
+ }
+ /*
+ * Allocate our Rx buffers. This chip has a rx structure that's filled
+ * in
+ */
+
+ /*
+ * Allocate DMA tags and maps for RX.
+ */
+ err = bus_dma_tag_create(NULL, 1, 0, BUS_SPACE_MAXADDR_32BIT,
+ BUS_SPACE_MAXADDR, NULL, NULL, MCLBYTES, 1, MCLBYTES, 0,
+ busdma_lock_mutex, &sc->sc_mtx, &sc->rxtag);
+ if (err != 0)
+ goto errout;
+ for (i = 0; i < ATE_MAX_RX_BUFFERS; i++) {
+ err = bus_dmamap_create(sc->rxtag, 0, &sc->rx_map[i]);
+ if (err != 0)
+ goto errout;
+ }
+
+ /* Dma TAG and MAP for the rx descriptors. */
+ err = bus_dma_tag_create(NULL, sizeof(eth_rx_desc_t), 0,
+ BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
+ ATE_MAX_RX_BUFFERS * sizeof(eth_rx_desc_t), 1,
+ ATE_MAX_RX_BUFFERS * sizeof(eth_rx_desc_t), 0, busdma_lock_mutex,
+ &sc->sc_mtx, &sc->rx_desc_tag);
+ if (err != 0)
+ goto errout;
+ if (bus_dmamem_alloc(sc->rx_desc_tag, (void **)&sc->rx_descs, M_WAITOK,
+ &sc->rx_desc_map) != 0)
+ goto errout;
+ if (bus_dmamap_load(sc->rx_desc_tag, sc->rx_desc_map,
+ sc->rx_descs, ATE_MAX_RX_BUFFERS * sizeof(eth_rx_desc_t),
+ ate_getaddr, sc, 0) != 0)
+ goto errout;
+ /* XXX TODO(5) Put this in ateinit_locked? */
+ for (i = 0; i < ATE_MAX_RX_BUFFERS; i++) {
+ bus_dma_segment_t seg;
+ int nsegs;
+
+ sc->rx_mbuf[i] = m_getcl(M_WAITOK, MT_DATA, M_PKTHDR);
+ sc->rx_mbuf[i]->m_len = sc->rx_mbuf[i]->m_pkthdr.len =
+ MCLBYTES;
+ if (bus_dmamap_load_mbuf_sg(sc->rxtag, sc->rx_map[i],
+ sc->rx_mbuf[i], &seg, &nsegs, 0) != 0)
+ goto errout;
+ /*
+ * For the last buffer, set the wrap bit so the controller
+ * restarts from the first descriptor.
+ */
+ if (i == ATE_MAX_RX_BUFFERS - 1)
+ seg.ds_addr |= 1 << 1;
+ sc->rx_descs[i].addr = seg.ds_addr;
+ sc->rx_descs[i].status = 0;
+ bus_dmamap_sync(sc->rxtag, sc->rx_map[i], BUS_DMASYNC_PREWRITE);
+ }
+ bus_dmamap_sync(sc->rx_desc_tag, sc->rx_desc_map, BUS_DMASYNC_PREWRITE);
+ /* Write the descriptor queue address. */
+ WR4(sc, ETH_RBQP, sc->rx_desc_phys);
+ return (0);
+errout:
+ ate_deactivate(dev);
+ return (ENOMEM);
+}
+
+static void
+ate_deactivate(device_t dev)
+{
+ struct ate_softc *sc;
+
+ sc = device_get_softc(dev);
+ /* XXX TODO(2) teardown busdma junk, below from fxp -- customize */
+#if 0
+ if (sc->fxp_mtag) {
+ for (i = 0; i < FXP_NRFABUFS; i++) {
+ rxp = &sc->fxp_desc.rx_list[i];
+ if (rxp->rx_mbuf != NULL) {
+ bus_dmamap_sync(sc->fxp_mtag, rxp->rx_map,
+ BUS_DMASYNC_POSTREAD);
+ bus_dmamap_unload(sc->fxp_mtag, rxp->rx_map);
+ m_freem(rxp->rx_mbuf);
+ }
+ bus_dmamap_destroy(sc->fxp_mtag, rxp->rx_map);
+ }
+ bus_dmamap_destroy(sc->fxp_mtag, sc->spare_map);
+ for (i = 0; i < FXP_NTXCB; i++) {
+ txp = &sc->fxp_desc.tx_list[i];
+ if (txp->tx_mbuf != NULL) {
+ bus_dmamap_sync(sc->fxp_mtag, txp->tx_map,
+ BUS_DMASYNC_POSTWRITE);
+ bus_dmamap_unload(sc->fxp_mtag, txp->tx_map);
+ m_freem(txp->tx_mbuf);
+ }
+ bus_dmamap_destroy(sc->fxp_mtag, txp->tx_map);
+ }
+ bus_dma_tag_destroy(sc->fxp_mtag);
+ }
+ if (sc->fxp_stag)
+ bus_dma_tag_destroy(sc->fxp_stag);
+ if (sc->cbl_tag)
+ bus_dma_tag_destroy(sc->cbl_tag);
+ if (sc->mcs_tag)
+ bus_dma_tag_destroy(sc->mcs_tag);
+#endif
+ if (sc->intrhand)
+ bus_teardown_intr(dev, sc->irq_res, sc->intrhand);
+ sc->intrhand = 0;
+ bus_generic_detach(sc->dev);
+ if (sc->miibus)
+ device_delete_child(sc->dev, sc->miibus);
+ if (sc->mem_res)
+ bus_release_resource(dev, SYS_RES_IOPORT,
+ rman_get_rid(sc->mem_res), sc->mem_res);
+ sc->mem_res = 0;
+ if (sc->irq_res)
+ bus_release_resource(dev, SYS_RES_IRQ,
+ rman_get_rid(sc->irq_res), sc->irq_res);
+ sc->irq_res = 0;
+ return;
+}
+
+/*
+ * Change media according to request.
+ */
+static int
+ate_ifmedia_upd(struct ifnet *ifp)
+{
+ struct ate_softc *sc = ifp->if_softc;
+ struct mii_data *mii;
+
+ mii = device_get_softc(sc->miibus);
+ ATE_LOCK(sc);
+ mii_mediachg(mii);
+ ATE_UNLOCK(sc);
+ return (0);
+}
+
+/*
+ * Notify the world which media we're using.
+ */
+static void
+ate_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
+{
+ struct ate_softc *sc = ifp->if_softc;
+ struct mii_data *mii;
+
+ mii = device_get_softc(sc->miibus);
+ ATE_LOCK(sc);
+ mii_pollstat(mii);
+ ifmr->ifm_active = mii->mii_media_active;
+ ifmr->ifm_status = mii->mii_media_status;
+ ATE_UNLOCK(sc);
+}
+
+static void
+ate_tick(void *xsc)
+{
+ struct ate_softc *sc = xsc;
+ struct mii_data *mii;
+ int active;
+
+ /*
+ * The KB920x boot loader tests ETH_SR & ETH_SR_LINK and will ask
+ * the MII if there's a link if this bit is clear. Not sure if we
+ * should do the same thing here or not.
+ */
+ ATE_ASSERT_LOCKED(sc);
+ if (sc->miibus != NULL) {
+ mii = device_get_softc(sc->miibus);
+ active = mii->mii_media_active;
+ mii_tick(mii);
+ if (mii->mii_media_status & IFM_ACTIVE &&
+ active != mii->mii_media_active) {
+ /*
+ * The speed and full/half-duplex state needs
+ * to be reflected in the ETH_CFG register, it
+ * seems.
+ */
+ if (IFM_SUBTYPE(mii->mii_media_active) == IFM_10_T)
+ WR4(sc, ETH_CFG, RD4(sc, ETH_CFG) &
+ ~ETH_CFG_SPD);
+ else
+ WR4(sc, ETH_CFG, RD4(sc, ETH_CFG) |
+ ETH_CFG_SPD);
+ if (mii->mii_media_active & IFM_FDX)
+ WR4(sc, ETH_CFG, RD4(sc, ETH_CFG) |
+ ETH_CFG_FD);
+ else
+ WR4(sc, ETH_CFG, RD4(sc, ETH_CFG) &
+ ~ETH_CFG_FD);
+ }
+ }
+
+ /*
+ * Update the stats as best we can. When we're done, clear
+ * the status counters and start over. We're supposed to read these
+ * registers often enough that they won't overflow. Hopefully
+ * once a second is often enough. Some don't map well to
+ * the dot3Stats mib, so for those we just count them as general
+ * errors. Stats for iframes, ibutes, oframes and obytes are
+ * collected elsewhere. These registers zero on a read to prevent
+ * races.
+ */
+ sc->mibdata.dot3StatsAlignmentErrors += RD4(sc, ETH_ALE);
+ sc->mibdata.dot3StatsFCSErrors += RD4(sc, ETH_SEQE);
+ sc->mibdata.dot3StatsSingleCollisionFrames += RD4(sc, ETH_SCOL);
+ sc->mibdata.dot3StatsMultipleCollisionFrames += RD4(sc, ETH_MCOL);
+ sc->mibdata.dot3StatsSQETestErrors += RD4(sc, ETH_SQEE);
+ sc->mibdata.dot3StatsDeferredTransmissions += RD4(sc, ETH_DTE);
+ sc->mibdata.dot3StatsLateCollisions += RD4(sc, ETH_LCOL);
+ sc->mibdata.dot3StatsExcessiveCollisions += RD4(sc, ETH_ECOL);
+ sc->mibdata.dot3StatsCarrierSenseErrors += RD4(sc, ETH_CSE);
+ sc->mibdata.dot3StatsFrameTooLongs += RD4(sc, ETH_ELR);
+ sc->mibdata.dot3StatsInternalMacReceiveErrors += RD4(sc, ETH_DRFC);
+ /*
+ * not sure where to lump these, so count them against the errors
+ * for the interface.
+ */
+ sc->ifp->if_oerrors += RD4(sc, ETH_CSE) + RD4(sc, ETH_TUE);
+ sc->ifp->if_ierrors += RD4(sc, ETH_CDE) + RD4(sc, ETH_RJB) +
+ RD4(sc, ETH_USF);
+
+ /*
+ * Schedule another timeout one second from now.
+ */
+ callout_reset(&sc->tick_ch, hz, ate_tick, sc);
+}
+
+static void
+ate_get_mac(struct ate_softc *sc, u_char *eaddr)
+{
+ uint32_t low, high;
+
+ /*
+ * The KB920x loaders will setup the MAC with an address, if one
+ * is set in the loader. The TSC loader will also set the MAC address
+ * in a similar way. Grab the MAC address from the SA1[HL] registers.
+ */
+ low = RD4(sc, ETH_SA1L);
+ high = RD4(sc, ETH_SA1H);
+ eaddr[0] = (high >> 8) & 0xff;
+ eaddr[1] = high & 0xff;
+ eaddr[2] = (low >> 24) & 0xff;
+ eaddr[3] = (low >> 16) & 0xff;
+ eaddr[4] = (low >> 8) & 0xff;
+ eaddr[5] = low & 0xff;
+}
+
+static void
+ate_intr(void *xsc)
+{
+ struct ate_softc *sc = xsc;
+ int status;
+ int i;
+
+ status = RD4(sc, ETH_ISR);
+ if (status == 0)
+ return;
+ printf("IT IS %x\n", RD4(sc, ETH_RSR));
+ if (status & ETH_ISR_RCOM) {
+ bus_dmamap_sync(sc->rx_desc_tag, sc->rx_desc_map,
+ BUS_DMASYNC_POSTREAD);
+ for (i = 0; i < ATE_MAX_RX_BUFFERS; i++) {
+ if (sc->rx_descs[i].addr & ETH_CPU_OWNER) {
+ struct mbuf *mb = sc->rx_mbuf[i];
+ bus_dma_segment_t seg;
+ int rx_stat = sc->rx_descs[i].status;
+ int nsegs;
+
+ printf("GOT ONE\n");
+ bus_dmamap_sync(sc->rxtag,
+ sc->rx_map[i], BUS_DMASYNC_POSTREAD);
+ bus_dmamap_unload(sc->rxtag,
+ sc->rx_map[i]);
+ WR4(sc, ETH_RSR, RD4(sc, ETH_RSR));
+ /*
+ * Allocate a new buffer to replace this one.
+ * if we cannot, then we drop this packet
+ * and keep the old buffer we had.
+ */
+ sc->rx_mbuf[i] = m_getcl(M_DONTWAIT, MT_DATA,
+ M_PKTHDR);
+ if (!sc->rx_mbuf[i]) {
+ sc->rx_mbuf[i] = mb;
+ sc->rx_descs[i].addr &= ~ETH_CPU_OWNER;
+ bus_dmamap_sync(sc->rx_desc_tag,
+ sc->rx_desc_map,
+ BUS_DMASYNC_PREWRITE);
+ continue;
+ }
+ if (bus_dmamap_load_mbuf_sg(sc->rxtag,
+ sc->rx_map[i],
+ sc->rx_mbuf[i], &seg, &nsegs, 0) != 0) {
+ sc->rx_mbuf[i] = mb;
+ sc->rx_descs[i].addr &= ~ETH_CPU_OWNER;
+ bus_dmamap_sync(sc->rx_desc_tag,
+ sc->rx_desc_map,
+ BUS_DMASYNC_PREWRITE);
+ continue;
+ }
+ /*
+ * For the last buffer, set the wrap bit so
+ * the controller restarts from the first
+ * descriptor.
+ */
+ if (i == ATE_MAX_RX_BUFFERS - 1)
+ seg.ds_addr |= 1 << 1;
+ sc->rx_descs[i].addr = seg.ds_addr;
+ sc->rx_descs[i].status = 0;
+ mb->m_len = rx_stat & ETH_LEN_MASK;
+ (*sc->ifp->if_input)(sc->ifp, mb);
+ break;
+ }
+ }
+ }
+ if (status & ETH_ISR_TCOM) {
+ if (sc->sent_mbuf[0])
+ m_freem(sc->sent_mbuf[0]);
+ if (sc->sent_mbuf[1]) {
+ if (RD4(sc, ETH_TSR) & ETH_TSR_IDLE) {
+ m_freem(sc->sent_mbuf[1]);
+ sc->txcur = 0;
+ sc->sent_mbuf[0] = sc->sent_mbuf[1] = NULL;
+ } else {
+ sc->sent_mbuf[0] = sc->sent_mbuf[1];
+ sc->sent_mbuf[1] = NULL;
+ sc->txcur = 1;
+ }
+ } else {
+ sc->sent_mbuf[0] = NULL;
+ sc->txcur = 0;
+ }
+ }
+ if (status & ETH_ISR_RBNA) {
+ /* Workaround Errata #11 */
+ WR4(sc, ETH_CTL, RD4(sc, ETH_CTL) &~ ETH_CTL_RE);
+ WR4(sc, ETH_CTL, RD4(sc, ETH_CTL) | ETH_CTL_RE);
+ }
+}
+
+/*
+ * Reset and initialize the chip
+ */
+static void
+ateinit_locked(void *xsc)
+{
+ struct ate_softc *sc = xsc;
+ struct ifnet *ifp = sc->ifp;
+
+ ATE_ASSERT_LOCKED(sc);
+
+ /*
+ * XXX TODO(3)
+ * we need to turn on the EMAC clock in the pmc. With the
+ * default boot loader, this is already turned on. However, we
+ * need to think about how best to turn it on/off as the interface
+ * is brought up/down, as well as dealing with the mii bus...
+ *
+ * We also need to multiplex the pins correctly.
+ */
+
+ /*
+ * There are two different ways that the mii bus is connected
+ * to this chip. Select the right one based on a compile-time
+ * option.
+ */
+#ifdef ATE_USE_RMII
+ WR4(sc, ETH_CFG, RD4(sc, ETH_CFG) | ETH_CFG_RMII);
+#else
+ WR4(sc, ETH_CFG, RD4(sc, ETH_CFG) & ~ETH_CFG_RMII);
+#endif
+ /*
+ * Turn on the multicast hash, and write 0's to it.
+ */
+ WR4(sc, ETH_CFG, RD4(sc, ETH_CFG) | ETH_CFG_MTI);
+ WR4(sc, ETH_HSH, 0);
+ WR4(sc, ETH_HSL, 0);
+
+ WR4(sc, ETH_CTL, RD4(sc, ETH_CTL) | ETH_CTL_TE | ETH_CTL_RE);
+ WR4(sc, ETH_IER, /*ETH_ISR_RCOM | ETH_ISR_TCOM | ETH_ISR_RBNA*/
+ 0xffffffff);
+
+ /*
+ * Boot loader fills in MAC address. If that's not the case, then
+ * we should set SA1L and SA1H here to the appropriate value. Note:
+ * the byte order is big endian, not little endian, so we have some
+ * swapping to do. Again, if we need it (which I don't think we do).
+ */
+
+ ate_setmcast(sc);
+
+ /*
+ * Set 'running' flag, and clear output active flag
+ * and attempt to start the output
+ */
+ ifp->if_drv_flags |= IFF_DRV_RUNNING;
+ ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
+ atestart_locked(ifp);
+
+ callout_reset(&sc->tick_ch, hz, ate_tick, sc);
+}
+
+/*
+ * dequeu packets and transmit
+ */
+static void
+atestart_locked(struct ifnet *ifp)
+{
+ struct ate_softc *sc = ifp->if_softc;
+ struct mbuf *m, *mdefrag;
+ bus_dma_segment_t segs[1];
+ int nseg;
+
+ ATE_ASSERT_LOCKED(sc);
+ if (ifp->if_drv_flags & IFF_DRV_OACTIVE)
+ return;
+
+outloop:
+ /*
+ * check to see if there's room to put another packet into the
+ * xmit queue. The EMAC chip has a ping-pong buffer for xmit
+ * packets. We use OACTIVE to indicate "we can stuff more into
+ * our buffers (clear) or not (set)."
+ */
+ if (!(RD4(sc, ETH_TSR) & ETH_TSR_BNQ)) {
+ ifp->if_drv_flags |= IFF_DRV_OACTIVE;
+ return;
+ }
+ IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
+ if (m == 0) {
+ ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
+ return;
+ }
+ mdefrag = m_defrag(m, M_DONTWAIT);
+ if (mdefrag == NULL) {
+ m_freem(m);
+ return;
+ }
+ m = mdefrag;
+
+ if (bus_dmamap_load_mbuf_sg(sc->mtag, sc->tx_map[sc->txcur], m, segs,
+ &nseg, 0) != 0) {
+ m_free(m);
+ goto outloop;
+ }
+ bus_dmamap_sync(sc->mtag, sc->tx_map[sc->txcur], BUS_DMASYNC_PREWRITE);
+ sc->sent_mbuf[sc->txcur] = m;
+ sc->txcur++;
+ if (sc->txcur >= ATE_MAX_TX_BUFFERS)
+ sc->txcur = 0;
+
+ /*
+ * tell the hardware to xmit the packet.
+ */
+ WR4(sc, ETH_TAR, segs[0].ds_addr);
+ WR4(sc, ETH_TCR, segs[0].ds_len);
+
+ /*
+ * Tap off here if there is a bpf listener.
+ */
+ BPF_MTAP(ifp, m);
+
+ /*
+ * Once we've queued one packet, we'll do the rest via the ISR,
+ * save off a pointer.
+ */
+ sc->sent_mbuf[1] = m;
+}
+
+static void
+ateinit(void *xsc)
+{
+ struct ate_softc *sc = xsc;
+ ATE_LOCK(sc);
+ ateinit_locked(sc);
+ ATE_UNLOCK(sc);
+}
+
+static void
+atestart(struct ifnet *ifp)
+{
+ struct ate_softc *sc = ifp->if_softc;
+ ATE_LOCK(sc);
+ atestart_locked(ifp);
+ ATE_UNLOCK(sc);
+}
+
+/*
+ * Turn off interrupts, and stop the nic. Can be called with sc->ifp NULL
+ * so be careful.
+ */
+static void
+atestop(struct ate_softc *sc)
+{
+ struct ifnet *ifp = sc->ifp;
+
+ if (ifp) {
+ ifp->if_timer = 0;
+ ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
+ }
+
+ callout_stop(&sc->tick_ch);
+
+ /*
+ * Enable some parts of the MAC that are needed always (like the
+ * MII bus. This turns off the RE and TE bits, which will remain
+ * off until atestart() is called to turn them on. With RE and TE
+ * turned off, there's no DMA to worry about after this write.
+ */
+ WR4(sc, ETH_CTL, ETH_CTL_MPE);
+
+ /*
+ * Turn off all the configured options and revert to defaults.
+ */
+ WR4(sc, ETH_CFG, ETH_CFG_CLK_32);
+
+ /*
+ * Turn off all the interrupts, and ack any pending ones by reading
+ * the ISR.
+ */
+ WR4(sc, ETH_IDR, 0xffffffff);
+ RD4(sc, ETH_ISR);
+
+ /*
+ * Clear out the Transmit and Receiver Status registers of any
+ * errors they may be reporting
+ */
+ WR4(sc, ETH_TSR, 0xffffffff);
+ WR4(sc, ETH_RSR, 0xffffffff);
+
+ /*
+ * XXX TODO(8)
+ * need to worry about the busdma resources? Yes, I think we need
+ * to sync and unload them. We may also need to release the mbufs
+ * that are assocaited with RX and TX operations.
+ */
+
+ /*
+ * XXX we should power down the EMAC if it isn't in use, after
+ * putting it into loopback mode. This saves about 400uA according
+ * to the datasheet.
+ */
+}
+
+static void
+atewatchdog(struct ifnet *ifp)
+{
+ struct ate_softc *sc = ifp->if_softc;
+
+ ATE_LOCK(sc);
+ device_printf(sc->dev, "Device timeout\n");
+ ifp->if_oerrors++;
+ ateinit_locked(sc);
+ ATE_UNLOCK(sc);
+}
+
+static int
+ateioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
+{
+ struct ate_softc *sc = ifp->if_softc;
+ int error = 0;
+
+ switch (cmd) {
+ case SIOCSIFFLAGS:
+ ATE_LOCK(sc);
+ if ((ifp->if_flags & IFF_UP) == 0 &&
+ ifp->if_drv_flags & IFF_DRV_RUNNING) {
+ ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
+ atestop(sc);
+ } else {
+ /* reinitialize card on any parameter change */
+ ateinit_locked(sc);
+ }
+ ATE_UNLOCK(sc);
+ break;
+
+ case SIOCADDMULTI:
+ case SIOCDELMULTI:
+ /* update multicast filter list. */
+ ate_setmcast(sc);
+ error = 0;
+ break;
+
+ default:
+ error = ether_ioctl(ifp, cmd, data);
+ break;
+ }
+ return (error);
+}
+
+static void
+ate_child_detached(device_t dev, device_t child)
+{
+ struct ate_softc *sc;
+
+ sc = device_get_softc(dev);
+ if (child == sc->miibus)
+ sc->miibus = NULL;
+}
+
+/*
+ * MII bus support routines.
+ */
+static int
+ate_miibus_readreg(device_t dev, int phy, int reg)
+{
+ struct ate_softc *sc;
+ int val;
+
+ /*
+ * XXX if we implement agressive power savings, then we need
+ * XXX to make sure that the clock to the emac is on here
+ */
+
+ if (phy != 0)
+ return (0xffff);
+ sc = device_get_softc(dev);
+ DELAY(1); /* Hangs w/o this delay really 30.5us atm */
+ WR4(sc, ETH_MAN, ETH_MAN_REG_RD(phy, reg));
+ while ((RD4(sc, ETH_SR) & ETH_SR_IDLE) == 0)
+ continue;
+ val = RD4(sc, ETH_MAN) & ETH_MAN_VALUE_MASK;
+
+ return (val);
+}
+
+static void
+ate_miibus_writereg(device_t dev, int phy, int reg, int data)
+{
+ struct ate_softc *sc;
+
+ /*
+ * XXX if we implement agressive power savings, then we need
+ * XXX to make sure that the clock to the emac is on here
+ */
+
+ sc = device_get_softc(dev);
+ WR4(sc, ETH_MAN, ETH_MAN_REG_WR(phy, reg, data));
+ while ((RD4(sc, ETH_SR) & ETH_SR_IDLE) == 0)
+ continue;
+ return;
+}
+
+static device_method_t ate_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, ate_probe),
+ DEVMETHOD(device_attach, ate_attach),
+ DEVMETHOD(device_detach, ate_detach),
+
+ /* Bus interface */
+ DEVMETHOD(bus_child_detached, ate_child_detached),
+
+ /* MII interface */
+ DEVMETHOD(miibus_readreg, ate_miibus_readreg),
+ DEVMETHOD(miibus_writereg, ate_miibus_writereg),
+
+ { 0, 0 }
+};
+
+static driver_t ate_driver = {
+ "ate",
+ ate_methods,
+ sizeof(struct ate_softc),
+};
+
+DRIVER_MODULE(ate, atmelarm, ate_driver, ate_devclass, 0, 0);
+DRIVER_MODULE(miibus, ate, miibus_driver, miibus_devclass, 0, 0);
+MODULE_DEPEND(ate, miibus, 1, 1, 1);
+MODULE_DEPEND(ate, ether, 1, 1, 1);
diff --git a/sys/arm/at91/if_atereg.h b/sys/arm/at91/if_atereg.h
new file mode 100644
index 0000000..00fc507
--- /dev/null
+++ b/sys/arm/at91/if_atereg.h
@@ -0,0 +1,175 @@
+/*-
+ * Copyright (c) 2006 M. Warner Losh. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* $FreeBSD$ */
+
+#ifndef ARM_AT91_IF_ATEREG_H
+#define ARM_AT91_IF_ATEREG_H
+
+#define ETH_CTL 0x00 /* EMAC Control Register */
+#define ETH_CFG 0x04 /* EMAC Configuration Register */
+#define ETH_SR 0x08 /* EMAC STatus Register */
+#define ETH_TAR 0x0c /* EMAC Transmit Address Register */
+#define ETH_TCR 0x10 /* EMAC Transmit Control Register */
+#define ETH_TSR 0x14 /* EMAC Transmit Status Register */
+#define ETH_RBQP 0x18 /* EMAC Receive Buffer Queue Pointer */
+ /* 0x1c reserved */
+#define ETH_RSR 0x20 /* EMAC Receive Status Register */
+#define ETH_ISR 0x24 /* EMAC Interrupt Status Register */
+#define ETH_IER 0x28 /* EMAC Interrupt Enable Register */
+#define ETH_IDR 0x2c /* EMAC Interrupt Disable Register */
+#define ETH_IMR 0x30 /* EMAC Interrupt Mask Register */
+#define ETH_MAN 0x34 /* EMAC PHY Maintenance Register */
+ /* 0x38 reserved */
+ /* 0x3c reserved */
+#define ETH_FRA 0x40 /* Frames Transmitted OK Register */
+#define ETH_SCOL 0x44 /* Single Collision Frame Register */
+#define ETH_MCOL 0x48 /* Multiple Collision Frame Register */
+#define ETH_OK 0x4c /* Frames Received OK Register */
+#define ETH_SEQE 0x50 /* Frame Check Sequence Error Reg */
+#define ETH_ALE 0x54 /* Alignment Error Register */
+#define ETH_DTE 0x58 /* Deferred Transmittion Frame Reg */
+#define ETH_LCOL 0x5c /* Late Collision Register */
+#define ETH_ECOL 0x60 /* Excessive Collision Register */
+#define ETH_CSE 0x64 /* Carrier Sense Error Register */
+#define ETH_TUE 0x68 /* Transmit Underrun Error Register */
+#define ETH_CDE 0x6c /* Code Error Register */
+#define ETH_ELR 0x70 /* Excessive Length Error Register */
+#define ETH_RJB 0x74 /* Receive Jabber Register */
+#define ETH_USF 0x78 /* Undersize Frame Register */
+#define ETH_SQEE 0x7c /* SQE Test Error Register */
+#define ETH_DRFC 0x80 /* Discarded RX Frame Register */
+ /* 0x84 reserved */
+ /* 0x88 reserved */
+ /* 0x8c reserved */
+#define ETH_HSH 0x90 /* EMAC Hash Address High [63:32] */
+#define ETH_HSL 0x94 /* EMAC Hash Address Low [31:0] */
+#define ETH_SA1L 0x98 /* EMAC Specific Address 1 Low */
+#define ETH_SA1H 0x9c /* EMAC Specific Address 1 High */
+#define ETH_SA2L 0xa0 /* EMAC Specific Address 2 Low */
+#define ETH_SA2H 0xa4 /* EMAC Specific Address 2 High */
+#define ETH_SA3L 0xa8 /* EMAC Specific Address 3 Low */
+#define ETH_SA3H 0xac /* EMAC Specific Address 3 High */
+#define ETH_SA4L 0xb0 /* EMAC Specific Address 4 Low */
+#define ETH_SA4H 0xb4 /* EMAC Specific Address 4 High */
+
+
+/* ETH_CTL */
+#define ETH_CTL_LB (1U << 0) /* LB: Loopback */
+#define ETH_CTL_LBL (1U << 1) /* LBL: Loopback Local */
+#define ETH_CTL_RE (1U << 2) /* RE: Receive Enable */
+#define ETH_CTL_TE (1U << 3) /* TE: Transmit Enable */
+#define ETH_CTL_MPE (1U << 4) /* MPE: Management Port Enable */
+#define ETH_CTL_CSR (1U << 5) /* CSR: Clear Statistics Registers */
+#define ETH_CTL_ISR (1U << 6) /* ISR: Incremenet Statistics Regs */
+#define ETH_CTL_WES (1U << 7) /* WES: Write Enable Statistics regs */
+#define ETH_CTL_BP (1U << 8) /* BP: Back Pressure */
+
+/* ETH_CFG */
+#define ETH_CFG_SPD (1U << 0) /* SPD: Speed 1 == 100: 0 == 10 */
+#define ETH_CFG_FD (1U << 1) /* FD: Full duplex */
+#define ETH_CFG_BR (1U << 2) /* BR: Bit Rate (optional?) */
+ /* bit 3 reserved */
+#define ETH_CFG_CAF (1U << 4) /* CAF: Copy All Frames */
+#define ETH_CFG_NBC (1U << 5) /* NBC: No Broadcast */
+#define ETH_CFG_MTI (1U << 6) /* MTI: Multicast Hash Enable */
+#define ETH_CFG_UNI (1U << 7) /* UNI: Unicast Hash Enable */
+#define ETH_CFG_BIG (1U << 8) /* BIG: Receive 1522 Bytes */
+#define ETH_CFG_EAE (1U << 9) /* EAE: External Address Match En */
+#define ETH_CFG_CLK_8 (0U << 10) /* CLK: Clock / 8 */
+#define ETH_CFG_CLK_16 (1U << 10) /* CLK: Clock / 16 */
+#define ETH_CFG_CLK_32 (2U << 10) /* CLK: Clock / 32 */
+#define ETH_CFG_CLK_64 (3U << 10) /* CLK: Clock / 64 */
+#define ETH_CFG_RTY (1U << 12) /* RTY: Retry Test*/
+#define ETH_CFG_RMII (1U << 13) /* RMII: Reduce MII */
+
+/* ETH_SR */
+#define ETH_SR_LINK (1U << 0) /* Reserved! */
+#define ETH_SR_MDIO (1U << 1) /* MDIO pin status */
+#define ETH_SR_IDLE (1U << 2) /* IDLE (PHY logic) */
+
+/* ETH_TCR */
+#define ETH_TCR_NCRC (1U << 15) /* NCRC: No CRC */
+
+/* ETH_TSR */
+#define ETH_TSR_OVR (1U << 0) /* OVR: Ethernet Transmit Overrun */
+#define ETH_TSR_COL (1U << 1) /* COL: Collision Occurred */
+#define ETH_TSR_RLE (1U << 2) /* RLE: Retry Limit Exceeded */
+#define ETH_TSR_IDLE (1U << 3) /* IDLE: Transmitter Idle */
+#define ETH_TSR_BNQ (1U << 4) /* BNQ: Enet Tran Buff not Queued */
+#define ETH_TSR_COMP (1U << 5) /* COMP: Transmit Complete */
+#define ETH_TSR_UND (1U << 6) /* UND: Transmit Underrun */
+#define ETH_TSR_WR_MASK (0x67) /* write 1 to clear bits */
+
+/* ETH_RSR */
+#define ETH_RSR_BNA (1U << 0) /* BNA: Buffer Not Available */
+#define ETH_RSR_REC (1U << 1) /* REC: Frame Received */
+#define ETH_RSR_OVR (1U << 2) /* OVR: RX Overrun */
+
+/* ETH_ISR */
+#define ETH_ISR_DONE (1U << 0) /* DONE: Management Done */
+#define ETH_ISR_RCOM (1U << 1) /* RCOM: Receive Complete */
+#define ETH_ISR_RBNA (1U << 2) /* RBNA: Receive Buffer Not Avail */
+#define ETH_ISR_TOVR (1U << 3) /* TOVR: Transmit Buffer Overrun */
+#define ETH_ISR_TUND (1U << 4) /* TUND: Transmit Buffer Underrun */
+#define ETH_ISR_RTRY (1U << 5) /* RTRY: Retry Limit */
+#define ETH_ISR_TBRE (1U << 6) /* TBRE: Trasnmit Buffer Reg empty */
+#define ETH_ISR_TCOM (1U << 7) /* TCOM: Transmit Complete */
+#define ETH_ISR_TIDLE (1U << 8) /* TIDLE: Transmit Idle */
+#define ETH_ISR_LINK (1U << 9) /* LINK: Link pin delta (optional) */
+#define ETH_ISR_ROVR (1U << 10) /* ROVR: RX Overrun */
+#define ETH_ISR_ABT (1U << 11) /* ABT: Abort */
+
+/* ETH_MAN */
+#define ETH_MAN_BITS 0x40020000 /* HIGH and CODE bits */
+#define ETH_MAN_READ (2U << 28)
+#define ETH_MAN_WRITE (1U << 28)
+#define ETH_MAN_PHYA_BIT 23
+#define ETH_MAN_REGA_BIT 18
+#define ETH_MAN_VALUE_MASK 0xffffU
+#define ETH_MAN_REG_WR(phy, reg, val) \
+ (ETH_MAN_BITS | ETH_MAN_WRITE | ((phy) << ETH_MAN_PHYA_BIT) | \
+ ((reg) << ETH_MAN_REGA_BIT) | ((val) & ETH_MAN_VALUE_MASK))
+#define ETH_MAN_REG_RD(phy, reg) \
+ (ETH_MAN_BITS | ETH_MAN_READ | ((phy) << ETH_MAN_PHYA_BIT) | \
+ ((reg) << ETH_MAN_REGA_BIT))
+
+typedef struct {
+ uint32_t addr;
+#define ETH_CPU_OWNER (1U << 0)
+#define ETH_WRAP_BIT (1U << 1)
+ uint32_t status;
+#define ETH_LEN_MASK 0x7ff
+#define ETH_MAC_LOCAL_4 (1U << 23) /* Packet matched addr 4 */
+#define ETH_MAC_LOCAL_3 (1U << 24) /* Packet matched addr 3 */
+#define ETH_MAC_LOCAL_2 (1U << 25) /* Packet matched addr 2 */
+#define ETH_MAC_LOCAL_1 (1U << 26) /* Packet matched addr 1 */
+#define ETH_MAC_UNK (1U << 27) /* Unkown source address RFU */
+#define ETH_MAC_EXT (1U << 28) /* External Address */
+#define ETH_MAC_UCAST (1U << 29) /* Unicast hash match */
+#define ETH_MAC_MCAST (1U << 30) /* Multicast hash match */
+#define ETH_MAC_ONES (1U << 31) /* Global all ones bcast addr */
+} eth_rx_desc_t;
+
+#endif /* ARM_AT91_IF_ATEREG_H */
diff --git a/sys/arm/at91/kb920x_machdep.c b/sys/arm/at91/kb920x_machdep.c
new file mode 100644
index 0000000..66b2664
--- /dev/null
+++ b/sys/arm/at91/kb920x_machdep.c
@@ -0,0 +1,389 @@
+/*-
+ * Copyright (c) 1994-1998 Mark Brinicombe.
+ * Copyright (c) 1994 Brini.
+ * All rights reserved.
+ *
+ * This code is derived from software written for Brini by Mark Brinicombe
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Brini.
+ * 4. The name of the company nor the name of the author may be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BRINI ``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 BRINI 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.
+ *
+ * RiscBSD kernel project
+ *
+ * machdep.c
+ *
+ * Machine dependant functions for kernel setup
+ *
+ * This file needs a lot of work.
+ *
+ * Created : 17/09/94
+ */
+
+#include "opt_msgbuf.h"
+#include "opt_ddb.h"
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#define _ARM32_BUS_DMA_PRIVATE
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/sysproto.h>
+#include <sys/signalvar.h>
+#include <sys/imgact.h>
+#include <sys/kernel.h>
+#include <sys/ktr.h>
+#include <sys/linker.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mutex.h>
+#include <sys/pcpu.h>
+#include <sys/proc.h>
+#include <sys/ptrace.h>
+#include <sys/cons.h>
+#include <sys/bio.h>
+#include <sys/bus.h>
+#include <sys/buf.h>
+#include <sys/exec.h>
+#include <sys/kdb.h>
+#include <sys/msgbuf.h>
+#include <machine/reg.h>
+#include <machine/cpu.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+#include <vm/vm.h>
+#include <vm/vm_object.h>
+#include <vm/vm_page.h>
+#include <vm/vm_pager.h>
+#include <vm/vm_map.h>
+#include <vm/vnode_pager.h>
+#include <machine/pmap.h>
+#include <machine/vmparam.h>
+#include <machine/pcb.h>
+#include <machine/undefined.h>
+#include <machine/machdep.h>
+#include <machine/metadata.h>
+#include <machine/armreg.h>
+#include <machine/bus.h>
+#include <sys/reboot.h>
+
+#include <arm/at91/at91rm92reg.h>
+
+#define KERNEL_PT_SYS 0 /* Page table for mapping proc0 zero page */
+#define KERNEL_PT_KERN 1
+#define KERNEL_PT_KERN_NUM 8
+#define KERNEL_PT_AFKERNEL KERNEL_PT_KERN + KERNEL_PT_KERN_NUM /* L2 table for mapping after kernel */
+#define KERNEL_PT_AFKERNEL_NUM 5
+
+/* this should be evenly divisable by PAGE_SIZE / L2_TABLE_SIZE_REAL (or 4) */
+#define NUM_KERNEL_PTS (KERNEL_PT_AFKERNEL + KERNEL_PT_AFKERNEL_NUM)
+
+/* Define various stack sizes in pages */
+#define IRQ_STACK_SIZE 1
+#define ABT_STACK_SIZE 1
+#define UND_STACK_SIZE 1
+
+extern u_int data_abort_handler_address;
+extern u_int prefetch_abort_handler_address;
+extern u_int undefined_handler_address;
+
+struct pv_addr kernel_pt_table[NUM_KERNEL_PTS];
+
+extern void *_end;
+
+extern vm_offset_t sa1_cache_clean_addr;
+
+extern int *end;
+
+struct pcpu __pcpu;
+struct pcpu *pcpup = &__pcpu;
+
+/* Physical and virtual addresses for some global pages */
+
+vm_paddr_t phys_avail[10];
+vm_paddr_t dump_avail[4];
+vm_offset_t physical_pages;
+vm_offset_t clean_sva, clean_eva;
+
+struct pv_addr systempage;
+struct pv_addr msgbufpv;
+struct pv_addr irqstack;
+struct pv_addr undstack;
+struct pv_addr abtstack;
+struct pv_addr kernelstack;
+struct pv_addr minidataclean;
+
+static struct trapframe proc0_tf;
+
+/* Static device mappings. */
+static const struct pmap_devmap kb920x_devmap[] = {
+ /*
+ * Map the on-board devices VA == PA so that we can access them
+ * with the MMU on or off.
+ */
+ {
+ /*
+ * This at least maps the interrupt controller, the UART
+ * and the timer. Other devices should use newbus to
+ * map their memory anyway.
+ */
+ 0xfff00000,
+ 0xfff00000,
+ 0x100000,
+ VM_PROT_READ|VM_PROT_WRITE,
+ PTE_NOCACHE,
+ },
+ {
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ }
+};
+
+#define SDRAM_START 0xa0000000
+
+#ifdef DDB
+extern vm_offset_t ksym_start, ksym_end;
+#endif
+
+void *
+initarm(void *arg, void *arg2)
+{
+ struct pv_addr kernel_l1pt;
+ int loop;
+ u_int l1pagetable;
+ vm_offset_t freemempos;
+ vm_offset_t afterkern;
+ int i = 0;
+ uint32_t fake_preload[35];
+ uint32_t memsize = 32 * 1024 * 1024;
+
+ i = 0;
+
+ set_cpufuncs();
+ cninit();
+
+ fake_preload[i++] = MODINFO_NAME;
+ fake_preload[i++] = strlen("elf kernel") + 1;
+ strcpy((char*)&fake_preload[i++], "elf kernel");
+ i += 2;
+ fake_preload[i++] = MODINFO_TYPE;
+ fake_preload[i++] = strlen("elf kernel") + 1;
+ strcpy((char*)&fake_preload[i++], "elf kernel");
+ i += 2;
+ fake_preload[i++] = MODINFO_ADDR;
+ fake_preload[i++] = sizeof(vm_offset_t);
+ fake_preload[i++] = KERNBASE;
+ fake_preload[i++] = MODINFO_SIZE;
+ fake_preload[i++] = sizeof(uint32_t);
+ fake_preload[i++] = (uint32_t)&end - KERNBASE;
+ fake_preload[i++] = 0;
+ fake_preload[i] = 0;
+ preload_metadata = (void *)fake_preload;
+
+
+ pcpu_init(pcpup, 0, sizeof(struct pcpu));
+ PCPU_SET(curthread, &thread0);
+
+#define KERNEL_TEXT_BASE (KERNBASE)
+ freemempos = ((vm_offset_t)&end + PAGE_MASK) & ~PAGE_MASK;
+ /* Define a macro to simplify memory allocation */
+#define valloc_pages(var, np) \
+ alloc_pages((var).pv_va, (np)); \
+ (var).pv_pa = (var).pv_va + (KERNPHYSADDR - KERNVIRTADDR);
+
+#define alloc_pages(var, np) \
+ (var) = freemempos; \
+ freemempos += (np * PAGE_SIZE); \
+ memset((char *)(var), 0, ((np) * PAGE_SIZE));
+
+ while (((freemempos - L1_TABLE_SIZE) & (L1_TABLE_SIZE - 1)) != 0)
+ freemempos += PAGE_SIZE;
+ valloc_pages(kernel_l1pt, L1_TABLE_SIZE / PAGE_SIZE);
+ for (loop = 0; loop < NUM_KERNEL_PTS; ++loop) {
+ if (!(loop % (PAGE_SIZE / L2_TABLE_SIZE_REAL))) {
+ valloc_pages(kernel_pt_table[loop],
+ L2_TABLE_SIZE / PAGE_SIZE);
+ } else {
+ kernel_pt_table[loop].pv_va = freemempos -
+ (loop % (PAGE_SIZE / L2_TABLE_SIZE_REAL)) *
+ L2_TABLE_SIZE_REAL;
+ kernel_pt_table[loop].pv_pa =
+ kernel_pt_table[loop].pv_va - KERNVIRTADDR +
+ KERNPHYSADDR;
+ }
+ i++;
+ }
+ /*
+ * Allocate a page for the system page mapped to V0x00000000
+ * This page will just contain the system vectors and can be
+ * shared by all processes.
+ */
+ valloc_pages(systempage, 1);
+
+ /* Allocate stacks for all modes */
+ valloc_pages(irqstack, IRQ_STACK_SIZE);
+ valloc_pages(abtstack, ABT_STACK_SIZE);
+ valloc_pages(undstack, UND_STACK_SIZE);
+ valloc_pages(kernelstack, KSTACK_PAGES);
+ alloc_pages(minidataclean.pv_pa, 1);
+ valloc_pages(msgbufpv, round_page(MSGBUF_SIZE) / PAGE_SIZE);
+ /*
+ * Now we start construction of the L1 page table
+ * We start by mapping the L2 page tables into the L1.
+ * This means that we can replace L1 mappings later on if necessary
+ */
+ l1pagetable = kernel_l1pt.pv_va;
+
+ /* Map the L2 pages tables in the L1 page table */
+ pmap_link_l2pt(l1pagetable, ARM_VECTORS_LOW,
+ &kernel_pt_table[KERNEL_PT_SYS]);
+ for (i = 0; i < KERNEL_PT_KERN_NUM; i++)
+ pmap_link_l2pt(l1pagetable, KERNBASE + i * 0x100000,
+ &kernel_pt_table[KERNEL_PT_KERN + i]);
+ pmap_map_chunk(l1pagetable, KERNBASE, KERNPHYSADDR,
+ (((uint32_t)(&end) - KERNBASE) + PAGE_SIZE) & ~(PAGE_SIZE - 1),
+ VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE);
+ afterkern = round_page(((vm_offset_t)&end + L1_S_SIZE) & ~(L1_S_SIZE
+ - 1));
+ for (i = 0; i < KERNEL_PT_AFKERNEL_NUM; i++) {
+ pmap_link_l2pt(l1pagetable, afterkern + i * 0x00100000,
+ &kernel_pt_table[KERNEL_PT_AFKERNEL + i]);
+ }
+ pmap_map_entry(l1pagetable, afterkern, minidataclean.pv_pa,
+ VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE);
+
+
+ /* Map the vector page. */
+ pmap_map_entry(l1pagetable, ARM_VECTORS_LOW, systempage.pv_pa,
+ VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE);
+ /* Map the stack pages */
+ pmap_map_chunk(l1pagetable, irqstack.pv_va, irqstack.pv_pa,
+ IRQ_STACK_SIZE * PAGE_SIZE, VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE);
+ pmap_map_chunk(l1pagetable, abtstack.pv_va, abtstack.pv_pa,
+ ABT_STACK_SIZE * PAGE_SIZE, VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE);
+ pmap_map_chunk(l1pagetable, undstack.pv_va, undstack.pv_pa,
+ UND_STACK_SIZE * PAGE_SIZE, VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE);
+ pmap_map_chunk(l1pagetable, kernelstack.pv_va, kernelstack.pv_pa,
+ KSTACK_PAGES * PAGE_SIZE, VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE);
+
+ pmap_map_chunk(l1pagetable, kernel_l1pt.pv_va, kernel_l1pt.pv_pa,
+ L1_TABLE_SIZE, VM_PROT_READ|VM_PROT_WRITE, PTE_PAGETABLE);
+ pmap_map_chunk(l1pagetable, msgbufpv.pv_va, msgbufpv.pv_pa,
+ MSGBUF_SIZE, VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE);
+
+
+ for (loop = 0; loop < NUM_KERNEL_PTS; ++loop) {
+ pmap_map_chunk(l1pagetable, kernel_pt_table[loop].pv_va,
+ kernel_pt_table[loop].pv_pa, L2_TABLE_SIZE,
+ VM_PROT_READ|VM_PROT_WRITE, PTE_PAGETABLE);
+ }
+
+ pmap_devmap_bootstrap(l1pagetable, kb920x_devmap);
+ cpu_domains((DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL*2)) | DOMAIN_CLIENT);
+ setttb(kernel_l1pt.pv_pa);
+ cpu_tlb_flushID();
+ cpu_domains(DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL*2));
+
+ /*
+ * Pages were allocated during the secondary bootstrap for the
+ * stacks for different CPU modes.
+ * We must now set the r13 registers in the different CPU modes to
+ * point to these stacks.
+ * Since the ARM stacks use STMFD etc. we must set r13 to the top end
+ * of the stack memory.
+ */
+
+ cpu_control(CPU_CONTROL_MMU_ENABLE, CPU_CONTROL_MMU_ENABLE);
+ set_stackptr(PSR_IRQ32_MODE,
+ irqstack.pv_va + IRQ_STACK_SIZE * PAGE_SIZE);
+ set_stackptr(PSR_ABT32_MODE,
+ abtstack.pv_va + ABT_STACK_SIZE * PAGE_SIZE);
+ set_stackptr(PSR_UND32_MODE,
+ undstack.pv_va + UND_STACK_SIZE * PAGE_SIZE);
+
+
+
+ /*
+ * We must now clean the cache again....
+ * Cleaning may be done by reading new data to displace any
+ * dirty data in the cache. This will have happened in setttb()
+ * but since we are boot strapping the addresses used for the read
+ * may have just been remapped and thus the cache could be out
+ * of sync. A re-clean after the switch will cure this.
+ * After booting there are no gross reloations of the kernel thus
+ * this problem will not occur after initarm().
+ */
+ cpu_idcache_wbinv_all();
+
+ /* Set stack for exception handlers */
+
+ data_abort_handler_address = (u_int)data_abort_handler;
+ prefetch_abort_handler_address = (u_int)prefetch_abort_handler;
+ undefined_handler_address = (u_int)undefinedinstruction_bounce;
+ undefined_init();
+
+ proc_linkup(&proc0, &ksegrp0, &thread0);
+ thread0.td_kstack = kernelstack.pv_va;
+ thread0.td_pcb = (struct pcb *)
+ (thread0.td_kstack + KSTACK_PAGES * PAGE_SIZE) - 1;
+ thread0.td_pcb->pcb_flags = 0;
+ thread0.td_frame = &proc0_tf;
+ pcpup->pc_curpcb = thread0.td_pcb;
+
+ arm_vector_init(ARM_VECTORS_LOW, ARM_VEC_ALL);
+
+ pmap_curmaxkvaddr = afterkern + 0x100000 * (KERNEL_PT_KERN_NUM - 1);
+ pmap_bootstrap(freemempos,
+ KERNVIRTADDR + 3 * memsize,
+ &kernel_l1pt);
+ msgbufp = (void*)msgbufpv.pv_va;
+ msgbufinit(msgbufp, MSGBUF_SIZE);
+ mutex_init();
+
+ i = 0;
+ dump_avail[0] = KERNPHYSADDR;
+ dump_avail[1] = KERNPHYSADDR + memsize;
+ dump_avail[2] = 0;
+ dump_avail[3] = 0;
+
+ phys_avail[0] = freemempos - KERNVIRTADDR + KERNPHYSADDR;
+ phys_avail[1] = KERNPHYSADDR + memsize;
+ phys_avail[2] = 0;
+ phys_avail[3] = 0;
+ /* Do basic tuning, hz etc */
+ init_param1();
+ init_param2(memsize / PAGE_SIZE);
+ avail_end = KERNPHYSADDR + memsize - 1;
+ kdb_init();
+ boothowto = RB_SINGLE;
+ return ((void *)(kernelstack.pv_va + USPACE_SVC_STACK_TOP -
+ sizeof(struct pcb)));
+}
diff --git a/sys/arm/at91/std.at91rm92 b/sys/arm/at91/std.at91rm92
new file mode 100644
index 0000000..2499f8b
--- /dev/null
+++ b/sys/arm/at91/std.at91rm92
@@ -0,0 +1,4 @@
+# $FreeBSD$
+
+files "../at91/files.at91rm92"
+cpu CPU_ARM9
diff --git a/sys/arm/at91/std.kb920x b/sys/arm/at91/std.kb920x
new file mode 100644
index 0000000..0b9d1d7
--- /dev/null
+++ b/sys/arm/at91/std.kb920x
@@ -0,0 +1,6 @@
+#$FreeBSD$
+include "../at91/std.at91rm92"
+files "../at91/files.kb920x"
+
+makeoptions KERNPHYSADDR=0x20000000
+makeoptions KERNVIRTADDR=0xc0000000
diff --git a/sys/arm/at91/uart_bus_at91usart.c b/sys/arm/at91/uart_bus_at91usart.c
new file mode 100644
index 0000000..c2dcc29
--- /dev/null
+++ b/sys/arm/at91/uart_bus_at91usart.c
@@ -0,0 +1,111 @@
+/*-
+ * Copyright (c) 2005 Olivier Houchard. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "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 <arm/at91/at91rm92reg.h>
+
+#include "uart_if.h"
+
+static int usart_at91rm92_probe(device_t dev);
+
+extern struct uart_class at91_usart_class;
+
+static device_method_t usart_at91rm92_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, usart_at91rm92_probe),
+ DEVMETHOD(device_attach, uart_bus_attach),
+ DEVMETHOD(device_detach, uart_bus_detach),
+ { 0, 0 }
+};
+
+static driver_t usart_at91rm92_driver = {
+ uart_driver_name,
+ usart_at91rm92_methods,
+ sizeof(struct uart_softc),
+};
+
+extern SLIST_HEAD(uart_devinfo_list, uart_devinfo) uart_sysdevs;
+
+static int
+usart_at91rm92_probe(device_t dev)
+{
+ struct uart_softc *sc;
+
+ sc = device_get_softc(dev);
+ switch (device_get_unit(dev))
+ {
+ case 0:
+ device_set_desc(dev, "DBGU");
+#ifndef USART0_CONSOLE
+ /*
+ * Setting sc_sysdev makes this device a 'system device' and
+ * indirectly makes it the system console.
+ */
+ sc->sc_sysdev = SLIST_FIRST(&uart_sysdevs);
+ bcopy(&sc->sc_sysdev->bas, &sc->sc_bas, sizeof(sc->sc_bas));
+#endif
+ break;
+ case 1:
+ device_set_desc(dev, "USART0");
+#ifdef USART0_CONSOLE
+ sc->sc_sysdev = SLIST_FIRST(&uart_sysdevs);
+ bcopy(&sc->sc_sysdev->bas, &sc->sc_bas, sizeof(sc->sc_bas));
+#endif
+ break;
+ case 2:
+ device_set_desc(dev, "USART1");
+ break;
+ case 3:
+ device_set_desc(dev, "USART2");
+ break;
+ case 4:
+ device_set_desc(dev, "USART3");
+ break;
+ }
+ sc->sc_class = &at91_usart_class;
+ return (uart_bus_probe(dev, 0, 0, 0, device_get_unit(dev), 0));
+}
+
+
+DRIVER_MODULE(uart, atmelarm, usart_at91rm92_driver, uart_devclass, 0, 0);
diff --git a/sys/arm/at91/uart_cpu_at91rm9200usart.c b/sys/arm/at91/uart_cpu_at91rm9200usart.c
new file mode 100644
index 0000000..2af5e2e
--- /dev/null
+++ b/sys/arm/at91/uart_cpu_at91rm9200usart.c
@@ -0,0 +1,87 @@
+/*-
+ * Copyright (c) 2003 Marcel Moolenaar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "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 <arm/at91/at91rm92reg.h>
+
+bus_space_tag_t uart_bus_space_io;
+bus_space_tag_t uart_bus_space_mem;
+
+extern struct uart_ops at91_usart_ops;
+extern struct bus_space at91_bs_tag;
+
+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 = at91_usart_ops;
+ di->bas.chan = 0;
+ di->bas.bst = &at91_bs_tag;
+ /*
+ * XXX: Not pretty, but will work because we map VA == PA early
+ * for the last 1MB of memory.
+ */
+#ifdef USART0_CONSOLE
+ di->bas.bsh = AT91RM92_BASE + AT91RM92_USART0_BASE;
+ di->bas.chan = 1;
+ di->baudrate = 38400;
+#else
+ di->bas.bsh = AT91RM92_BASE + AT91RM92_SYS_BASE + DBGU;
+ di->bas.chan = 0;
+ di->baudrate = 115200;
+#endif
+ di->bas.regshft = 0;
+ di->bas.rclk = 0;
+ di->databits = 8;
+ di->stopbits = 1;
+ di->parity = UART_PARITY_NONE;
+ /* Check the environment for overrides */
+ if (uart_getenv(devtype, di) == 0)
+ return (0);
+
+ uart_bus_space_io = &at91_bs_tag;
+ uart_bus_space_mem = NULL;
+
+ return (0);
+}
diff --git a/sys/arm/at91/uart_dev_at91usart.c b/sys/arm/at91/uart_dev_at91usart.c
new file mode 100644
index 0000000..c7bce4f
--- /dev/null
+++ b/sys/arm/at91/uart_dev_at91usart.c
@@ -0,0 +1,408 @@
+/*-
+ * Copyright (c) 2005 M. Warner Losh
+ * Copyright (c) 2005 cognet
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <sys/cons.h>
+#include <sys/tty.h>
+#include <machine/bus.h>
+
+#include <dev/uart/uart.h>
+#include <dev/uart/uart_cpu.h>
+#include <dev/uart/uart_bus.h>
+#include <arm/at91/at91rm92reg.h>
+#include <arm/at91/at91_usartreg.h>
+
+#include "uart_if.h"
+
+#define DEFAULT_RCLK AT91C_MASTER_CLOCK
+
+#define SIGCHG(c, i, s, d) \
+ do { \
+ if (c) { \
+ i |= (i & s) ? s : s | d; \
+ } else { \
+ i = (i & s) ? (i & ~s) | d : i; \
+ } \
+ } while (0);
+
+/*
+ * Low-level UART interface.
+ */
+static int at91_usart_probe(struct uart_bas *bas);
+static void at91_usart_init(struct uart_bas *bas, int, int, int, int);
+static void at91_usart_term(struct uart_bas *bas);
+static void at91_usart_putc(struct uart_bas *bas, int);
+static int at91_usart_poll(struct uart_bas *bas);
+static int at91_usart_getc(struct uart_bas *bas);
+
+extern SLIST_HEAD(uart_devinfo_list, uart_devinfo) uart_sysdevs;
+
+static int
+at91_usart_param(struct uart_bas *bas, int baudrate, int databits,
+ int stopbits, int parity)
+{
+ uint32_t mr;
+
+ /*
+ * Assume 3-write RS-232 configuration.
+ * XXX Not sure how uart will present the other modes to us, so
+ * XXX they are unimplemented. maybe ioctl?
+ */
+ mr = USART_MR_MODE_NORMAL;
+ mr |= USART_MR_USCLKS_MCK; /* Assume MCK */
+
+ /*
+ * Or in the databits requested
+ */
+ if (databits < 9)
+ mr &= ~USART_MR_MODE9;
+ switch (databits) {
+ case 5:
+ mr |= USART_MR_CHRL_5BITS;
+ break;
+ case 6:
+ mr |= USART_MR_CHRL_6BITS;
+ break;
+ case 7:
+ mr |= USART_MR_CHRL_7BITS;
+ break;
+ case 8:
+ mr |= USART_MR_CHRL_8BITS;
+ break;
+ case 9:
+ mr |= USART_MR_CHRL_8BITS | USART_MR_MODE9;
+ break;
+ default:
+ return (EINVAL);
+ }
+
+ /*
+ * Or in the parity
+ */
+ switch (parity) {
+ case UART_PARITY_NONE:
+ mr |= USART_MR_PAR_NONE;
+ break;
+ case UART_PARITY_ODD:
+ mr |= USART_MR_PAR_ODD;
+ break;
+ case UART_PARITY_EVEN:
+ mr |= USART_MR_PAR_EVEN;
+ break;
+ case UART_PARITY_MARK:
+ mr |= USART_MR_PAR_MARK;
+ break;
+ case UART_PARITY_SPACE:
+ mr |= USART_MR_PAR_SPACE;
+ break;
+ default:
+ return (EINVAL);
+ }
+
+ /*
+ * Or in the stop bits. Note: The hardware supports
+ * 1.5 stop bits in async mode, but there's no way to
+ * specify that AFAICT.
+ */
+ if (stopbits > 1)
+ mr |= USART_MR_NBSTOP_2;
+ else
+ mr |= USART_MR_NBSTOP_2;
+ /* else if (stopbits == 1.5)
+ mr |= USART_MR_NBSTOP_1_5; */
+
+ /*
+ * We want normal plumbing mode too, none of this fancy
+ * loopback or echo mode.
+ */
+ mr |= USART_MR_CHMODE_NORMAL;
+
+ mr &= ~USART_MR_MSBF; /* lsb first */
+ mr &= ~USART_MR_CKLO_SCK; /* Don't drive SCK */
+
+ /* XXX Need to take possible synchronous mode into account */
+ return (0);
+}
+
+struct uart_ops at91_usart_ops = {
+ .probe = at91_usart_probe,
+ .init = at91_usart_init,
+ .term = at91_usart_term,
+ .putc = at91_usart_putc,
+ .poll = at91_usart_poll,
+ .getc = at91_usart_getc,
+};
+
+static int
+at91_usart_probe(struct uart_bas *bas)
+{
+ /* We know that this is always here */
+ return (0);
+}
+
+/*
+ * Initialize this device (I think as the console)
+ */
+static void
+at91_usart_init(struct uart_bas *bas, int baudrate, int databits, int stopbits,
+ int parity)
+{
+ at91_usart_param(bas, baudrate, databits, stopbits, parity);
+
+ /* Turn on rx and tx */
+ uart_setreg(bas, USART_CR, USART_CR_RSTRX | USART_CR_RSTTX);
+ uart_setreg(bas, USART_CR, USART_CR_RXEN | USART_CR_TXEN);
+ uart_setreg(bas, USART_IER, USART_CSR_TXRDY | USART_CSR_RXRDY);
+}
+
+/*
+ * Free resources now that we're no longer the console. This appears to
+ * be never called, and I'm unsure quite what to do if I am called.
+ */
+static void
+at91_usart_term(struct uart_bas *bas)
+{
+ /* XXX */
+}
+
+/*
+ * Put a character of console output (so we do it here polling rather than
+ * interrutp driven).
+ */
+static void
+at91_usart_putc(struct uart_bas *bas, int c)
+{
+
+ while (!(uart_getreg(bas, USART_CSR) &
+ USART_CSR_TXRDY));
+ uart_setreg(bas, USART_THR, c);
+}
+
+/*
+ * Poll for a character available
+ */
+static int
+at91_usart_poll(struct uart_bas *bas)
+{
+
+ if (!(uart_getreg(bas, USART_CSR) & USART_CSR_RXRDY))
+ return (-1);
+ return (uart_getreg(bas, USART_RHR) & 0xff);
+}
+
+/*
+ * Block waiting for a character.
+ */
+static int
+at91_usart_getc(struct uart_bas *bas)
+{
+ int c;
+
+ while (!(uart_getreg(bas, USART_CSR) & USART_CSR_RXRDY))
+ ;
+ c = uart_getreg(bas, USART_RHR);
+ c &= 0xff;
+ return (c);
+}
+
+static int at91_usart_bus_probe(struct uart_softc *sc);
+static int at91_usart_bus_attach(struct uart_softc *sc);
+static int at91_usart_bus_flush(struct uart_softc *, int);
+static int at91_usart_bus_getsig(struct uart_softc *);
+static int at91_usart_bus_ioctl(struct uart_softc *, int, intptr_t);
+static int at91_usart_bus_ipend(struct uart_softc *);
+static int at91_usart_bus_param(struct uart_softc *, int, int, int, int);
+static int at91_usart_bus_receive(struct uart_softc *);
+static int at91_usart_bus_setsig(struct uart_softc *, int);
+static int at91_usart_bus_transmit(struct uart_softc *);
+
+static kobj_method_t at91_usart_methods[] = {
+ KOBJMETHOD(uart_probe, at91_usart_bus_probe),
+ KOBJMETHOD(uart_attach, at91_usart_bus_attach),
+ KOBJMETHOD(uart_flush, at91_usart_bus_flush),
+ KOBJMETHOD(uart_getsig, at91_usart_bus_getsig),
+ KOBJMETHOD(uart_ioctl, at91_usart_bus_ioctl),
+ KOBJMETHOD(uart_ipend, at91_usart_bus_ipend),
+ KOBJMETHOD(uart_param, at91_usart_bus_param),
+ KOBJMETHOD(uart_receive, at91_usart_bus_receive),
+ KOBJMETHOD(uart_setsig, at91_usart_bus_setsig),
+ KOBJMETHOD(uart_transmit, at91_usart_bus_transmit),
+
+ { 0, 0 }
+};
+
+int
+at91_usart_bus_probe(struct uart_softc *sc)
+{
+ return (0);
+}
+
+static int
+at91_usart_bus_attach(struct uart_softc *sc)
+{
+ sc->sc_txfifosz = 1;
+ sc->sc_rxfifosz = 1;
+ sc->sc_hwiflow = 0;
+ return (0);
+}
+static int
+at91_usart_bus_transmit(struct uart_softc *sc)
+{
+ int i;
+
+ /* XXX VERY sub-optimial */
+ mtx_lock_spin(&sc->sc_hwmtx);
+ sc->sc_txbusy = 1;
+ for (i = 0; i < sc->sc_txdatasz; i++)
+ at91_usart_putc(&sc->sc_bas, sc->sc_txbuf[i]);
+ mtx_unlock_spin(&sc->sc_hwmtx);
+#ifdef USART0_CONSOLE
+ /*
+ * XXX: Gross hack : Skyeye doesn't raise an interrupt once the
+ * transfer is done, so simulate it.
+ */
+ uart_setreg(&sc->sc_bas, USART_IER, USART_CSR_TXRDY);
+#endif
+ return (0);
+}
+static int
+at91_usart_bus_setsig(struct uart_softc *sc, int sig)
+{
+ uint32_t new, old, cr;
+ struct uart_bas *bas;
+
+ do {
+ old = sc->sc_hwsig;
+ new = old;
+ if (sig & SER_DDTR)
+ SIGCHG(sig & SER_DTR, new, SER_DTR, SER_DDTR);
+ if (sig & SER_DRTS)
+ SIGCHG(sig & SER_RTS, new, SER_RTS, SER_DRTS);
+ } while (!atomic_cmpset_32(&sc->sc_hwsig, old, new));
+ bas = &sc->sc_bas;
+ mtx_lock_spin(&sc->sc_hwmtx);
+ cr = uart_getreg(bas, USART_CR);
+ cr &= ~(USART_CR_DTREN | USART_CR_DTRDIS | USART_CR_RTSEN |
+ USART_CR_RTSDIS);
+ if (new & SER_DTR)
+ cr |= USART_CR_DTREN;
+ else
+ cr |= USART_CR_DTRDIS;
+ if (new & SER_RTS)
+ cr |= USART_CR_RTSEN;
+ else
+ cr |= USART_CR_RTSDIS;
+ uart_setreg(bas, USART_CR, cr);
+ mtx_unlock_spin(&sc->sc_hwmtx);
+ return (0);
+}
+static int
+at91_usart_bus_receive(struct uart_softc *sc)
+{
+
+ mtx_lock_spin(&sc->sc_hwmtx);
+ uart_rx_put(sc, at91_usart_getc(&sc->sc_bas));
+ mtx_unlock_spin(&sc->sc_hwmtx);
+ return (0);
+}
+static int
+at91_usart_bus_param(struct uart_softc *sc, int baudrate, int databits,
+ int stopbits, int parity)
+{
+ return (at91_usart_param(&sc->sc_bas, baudrate, databits, stopbits,
+ parity));
+}
+static int
+at91_usart_bus_ipend(struct uart_softc *sc)
+{
+ int csr = uart_getreg(&sc->sc_bas, USART_CSR);
+ int ipend = 0;
+
+#ifdef USART0_CONSOLE
+ /*
+ * XXX: We have to cheat for skyeye, as it will return 0xff for all
+ * the devices it doesn't emulate.
+ */
+ if (sc->sc_bas.chan != 1)
+ return (0);
+#endif
+
+ mtx_lock_spin(&sc->sc_hwmtx);
+ if (csr & USART_CSR_TXRDY && sc->sc_txbusy)
+ ipend |= UART_IPEND_TXIDLE;
+ if (csr & USART_CSR_RXRDY)
+ ipend |= UART_IPEND_RXREADY;
+ mtx_unlock_spin(&sc->sc_hwmtx);
+ return (ipend);
+}
+static int
+at91_usart_bus_flush(struct uart_softc *sc, int what)
+{
+ return (0);
+}
+
+static int
+at91_usart_bus_getsig(struct uart_softc *sc)
+{
+ uint32_t new, sig;
+ uint8_t csr;
+
+ mtx_lock_spin(&sc->sc_hwmtx);
+ csr = uart_getreg(&sc->sc_bas, USART_CSR);
+ sig = 0;
+ if (csr & USART_CSR_CTS)
+ sig |= SER_CTS;
+ if (csr & USART_CSR_DCD)
+ sig |= SER_DCD;
+ if (csr & USART_CSR_DSR)
+ sig |= SER_DSR;
+ if (csr & USART_CSR_RI)
+ sig |= SER_RI;
+ new = sig & ~UART_SIGMASK_DELTA;
+ sc->sc_hwsig = new;
+ mtx_unlock_spin(&sc->sc_hwmtx);
+ return (sig);
+}
+
+static int
+at91_usart_bus_ioctl(struct uart_softc *sc, int request, intptr_t data)
+{
+ return (EINVAL);
+}
+struct uart_class at91_usart_class = {
+ "at91_usart class",
+ at91_usart_methods,
+ 1,
+ .uc_range = 8,
+ .uc_rclk = DEFAULT_RCLK
+};
diff --git a/sys/arm/conf/KB920X b/sys/arm/conf/KB920X
new file mode 100644
index 0000000..c672c99
--- /dev/null
+++ b/sys/arm/conf/KB920X
@@ -0,0 +1,83 @@
+# GENERIC -- Generic kernel configuration file for FreeBSD/arm
+#
+# 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$
+
+machine arm
+ident KB920X
+
+options KERNPHYSADDR=0x20000000
+options KERNVIRTADDR=0xc0000000
+options PHYSADDR=0x20000000
+options STARTUP_PAGETABLE_ADDR=0x20800000
+options ARM32_NEW_VM_LAYOUT
+include "../at91/std.kb920x"
+#To statically compile in device wiring instead of /boot/device.hints
+#hints "GENERIC.hints" #Default places to look for devices.
+
+makeoptions DEBUG=-g #Build kernel with gdb(1) debug symbols
+makeoptions CONF_CFLAGS=-mcpu=arm9
+options DDB
+options KDB
+
+options SCHED_4BSD #4BSD scheduler
+options INET #InterNETworking
+#options INET6 #IPv6 communications protocols
+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 MD_ROOT #MD is a potential root device
+options MD_ROOT_SIZE=4096 # 3MB ram disk
+options ROOTDEVNAME=\"ufs:md0\"
+#options NFSCLIENT #Network Filesystem Client
+#options NFSSERVER #Network Filesystem Server
+#options NFS_ROOT #NFS usable as /, requires NFSCLIENT
+#options MSDOSFS #MSDOS Filesystem
+#options CD9660 #ISO 9660 Filesystem
+#options PROCFS #Process filesystem (requires PSEUDOFS)
+options PSEUDOFS #Pseudo-filesystem framework
+options COMPAT_43 #Compatible with BSD 4.3 [KEEP THIS!]
+#options SCSI_DELAY=5000 #Delay (in ms) before probing SCSI
+#options KTRACE #ktrace(1) support
+options SYSVSHM #SYSV-style shared memory
+options SYSVMSG #SYSV-style message queues
+options SYSVSEM #SYSV-style semaphores
+options _KPOSIX_PRIORITY_SCHEDULING #Posix P1003_1B real-time extensions
+options KBD_INSTALL_CDEV # install a CDEV entry in /dev
+options SYSCTL_OMIT_DESCR
+options MUTEX_NOINLINE
+options NO_FFS_SNAPSHOT
+options NO_SWAPPING
+device genclock
+device loop
+device ether
+device nexus
+device uart
+device ate
+device miibus
+
+# Debugging for use in -current
+#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
+
+device mem # Memory and kernel memory devices
+device md
+device at91_twi # TWI: Two Wire Interface
+device at91_spi # SPI:
diff --git a/sys/arm/conf/SKYEYE b/sys/arm/conf/SKYEYE
new file mode 100644
index 0000000..9348942
--- /dev/null
+++ b/sys/arm/conf/SKYEYE
@@ -0,0 +1,88 @@
+# GENERIC -- Generic kernel configuration file for FreeBSD/arm
+#
+# 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$
+
+machine arm
+ident KB920X
+
+options KERNPHYSADDR=0xc0000000
+options KERNVIRTADDR=0xc0000000
+options PHYSADDR=0xc0000000
+include "../at91/std.kb920x"
+#To statically compile in device wiring instead of /boot/device.hints
+#hints "GENERIC.hints" #Default places to look for devices.
+
+makeoptions DEBUG=-g #Build kernel with gdb(1) debug symbols
+makeoptions CONF_CFLAGS=-mcpu=arm9
+options DDB
+options KDB
+
+options USART0_CONSOLE
+
+options SCHED_4BSD #4BSD scheduler
+options INET #InterNETworking
+options INET6 #IPv6 communications protocols
+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 MD_ROOT #MD is a potential root device
+options ROOTDEVNAME=\"ufs:md0\"
+options NFSCLIENT #Network Filesystem Client
+options NFSSERVER #Network Filesystem Server
+options NFS_ROOT #NFS usable as /, requires NFSCLIENT
+#options MSDOSFS #MSDOS Filesystem
+options CD9660 #ISO 9660 Filesystem
+#options PROCFS #Process filesystem (requires PSEUDOFS)
+options PSEUDOFS #Pseudo-filesystem framework
+options COMPAT_43 #Compatible with BSD 4.3 [KEEP THIS!]
+options SCSI_DELAY=5000 #Delay (in ms) before probing SCSI
+#options KTRACE #ktrace(1) support
+options SYSVSHM #SYSV-style shared memory
+options SYSVMSG #SYSV-style message queues
+options SYSVSEM #SYSV-style semaphores
+options _KPOSIX_PRIORITY_SCHEDULING #Posix P1003_1B real-time extensions
+options KBD_INSTALL_CDEV # install a CDEV entry in /dev
+device genclock
+device loop
+device ether
+device nexus
+#device saarm
+device rl
+device uart
+#options AHC_REG_PRETTY_PRINT # Print register bitfields in debug
+ # output. Adds ~128k to driver.
+#options AHD_REG_PRETTY_PRINT # Print register bitfields in debug
+ # output. Adds ~215k to driver.
+
+# Debugging for use in -current
+#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
+
+# To make an SMP kernel, the next two are needed
+#options SMP # Symmetric MultiProcessor Kernel
+#options APIC_IO # Symmetric (APIC) I/O
+
+device mem # Memory and kernel memory devices
+device md
+options ARM32_NEW_VM_LAYOUT
+# Floppy drives
+
+
OpenPOWER on IntegriCloud