diff options
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 + + |