summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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