diff options
Diffstat (limited to 'sys/arm')
-rw-r--r-- | sys/arm/arm/minidump_machdep.c | 7 | ||||
-rw-r--r-- | sys/arm/arm/physmem.c | 6 | ||||
-rw-r--r-- | sys/arm/at91/at91.c | 163 | ||||
-rw-r--r-- | sys/arm/at91/at91_common.c | 2 | ||||
-rw-r--r-- | sys/arm/at91/at91_machdep.c | 2 | ||||
-rw-r--r-- | sys/arm/at91/at91_mci.c | 21 | ||||
-rw-r--r-- | sys/arm/at91/at91_ohci.c | 242 | ||||
-rw-r--r-- | sys/arm/at91/at91_ohci_fdt.c | 251 | ||||
-rw-r--r-- | sys/arm/at91/board_tsc4370.c | 62 | ||||
-rw-r--r-- | sys/arm/at91/files.at91 | 14 | ||||
-rw-r--r-- | sys/arm/at91/uart_cpu_at91usart.c | 5 | ||||
-rw-r--r-- | sys/arm/conf/IMX53 | 8 | ||||
-rw-r--r-- | sys/arm/conf/IMX6 | 8 | ||||
-rw-r--r-- | sys/arm/freescale/imx/imx_sdhci.c | 1 | ||||
-rw-r--r-- | sys/arm/include/minidump.h | 16 | ||||
-rw-r--r-- | sys/arm/include/sysarch.h | 8 |
16 files changed, 583 insertions, 233 deletions
diff --git a/sys/arm/arm/minidump_machdep.c b/sys/arm/arm/minidump_machdep.c index 71e732ed929c..7a4abe467429 100644 --- a/sys/arm/arm/minidump_machdep.c +++ b/sys/arm/arm/minidump_machdep.c @@ -312,7 +312,12 @@ minidumpsys(struct dumperinfo *di) mdhdr.bitmapsize = vm_page_dump_size; mdhdr.ptesize = ptesize; mdhdr.kernbase = KERNBASE; - + mdhdr.arch = __ARM_ARCH; +#if __ARM_ARCH >= 6 + mdhdr.mmuformat = MINIDUMP_MMU_FORMAT_V6; +#else + mdhdr.mmuformat = MINIDUMP_MMU_FORMAT_V4; +#endif mkdumpheader(&kdh, KERNELDUMPMAGIC, KERNELDUMP_ARM_VERSION, dumpsize, di->blocksize); diff --git a/sys/arm/arm/physmem.c b/sys/arm/arm/physmem.c index 566ab8569550..999d38c283c9 100644 --- a/sys/arm/arm/physmem.c +++ b/sys/arm/arm/physmem.c @@ -292,9 +292,13 @@ arm_physmem_hardware_region(vm_paddr_t pa, vm_size_t sz) * than leave some folks with an unusable system while we investigate. */ if (pa == 0) { + if (sz <= PAGE_SIZE) + return; pa = PAGE_SIZE; sz -= PAGE_SIZE; } else if (pa + sz == 0) { + if (sz <= 1024 * 1024) + return; sz -= 1024 * 1024; } @@ -306,7 +310,7 @@ arm_physmem_hardware_region(vm_paddr_t pa, vm_size_t sz) pa = round_page(pa); sz = trunc_page(sz - adj); - if (hwcnt < nitems(hwregions)) + if (sz > 0 && hwcnt < nitems(hwregions)) insert_region(hwregions, hwcnt++, pa, sz, 0); } diff --git a/sys/arm/at91/at91.c b/sys/arm/at91/at91.c index 209a11997a15..8b94dc627a77 100644 --- a/sys/arm/at91/at91.c +++ b/sys/arm/at91/at91.c @@ -54,54 +54,6 @@ __FBSDID("$FreeBSD$"); uint32_t at91_master_clock; -static int -at91_bs_map(bus_space_tag_t tag, 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 >= AT91_PA_BASE + 0xff00000) { - *bshp = bpa - AT91_PA_BASE + AT91_BASE; - return (0); - } - if (pa >= AT91_BASE + 0xff00000) { - *bshp = bpa; - return (0); - } - endpa = round_page(bpa + size); - - *bshp = (vm_offset_t)pmap_mapdev(pa, endpa - pa) + (bpa - pa); - - return (0); -} - -static void -at91_bs_unmap(bus_space_tag_t tag, bus_space_handle_t h, bus_size_t size) -{ - vm_offset_t va; - - va = (vm_offset_t)h; - if (va >= AT91_BASE && va <= AT91_BASE + 0xff00000) - return; - pmap_unmapdev(va, size); -} - -static int -at91_bs_subregion(bus_space_tag_t tag, bus_space_handle_t bsh, bus_size_t offset, - bus_size_t size, bus_space_handle_t *nbshp) -{ - - *nbshp = bsh + offset; - return (0); -} - -static void -at91_barrier(bus_space_tag_t tag, bus_space_handle_t bsh, bus_size_t size, bus_size_t b, - int a) -{ -} - struct arm32_dma_range * bus_dma_get_range(void) { @@ -115,115 +67,6 @@ bus_dma_get_range_nb(void) return (0); } -bs_protos(generic); - -struct bus_space at91_bs_tag = { - /* privdata is whatever the implementer wants; unused in base tag */ - .bs_privdata = NULL, - - /* mapping/unmapping */ - .bs_map = at91_bs_map, - .bs_unmap = at91_bs_unmap, - .bs_subregion = at91_bs_subregion, - - /* allocation/deallocation */ - .bs_alloc = generic_bs_alloc, - .bs_free = generic_bs_free, - - /* barrier */ - .bs_barrier = at91_barrier, - - /* read (single) */ - .bs_r_1 = NULL, /* Use inline code in bus.h */ - .bs_r_2 = NULL, /* Use inline code in bus.h */ - .bs_r_4 = NULL, /* Use inline code in bus.h */ - .bs_r_8 = NULL, /* Use inline code in bus.h */ - - /* read multiple */ - .bs_rm_1 = generic_bs_rm_1, - .bs_rm_2 = generic_bs_rm_2, - .bs_rm_4 = generic_bs_rm_4, - .bs_rm_8 = BS_UNIMPLEMENTED, - - /* read region */ - .bs_rr_1 = generic_bs_rr_1, - .bs_rr_2 = generic_bs_rr_2, - .bs_rr_4 = generic_bs_rr_4, - .bs_rr_8 = BS_UNIMPLEMENTED, - - /* write (single) */ - .bs_w_1 = NULL, /* Use inline code in bus.h */ - .bs_w_2 = NULL, /* Use inline code in bus.h */ - .bs_w_4 = NULL, /* Use inline code in bus.h */ - .bs_w_8 = NULL, /* Use inline code in bus.h */ - - /* write multiple */ - .bs_wm_1 = generic_bs_wm_1, - .bs_wm_2 = generic_bs_wm_2, - .bs_wm_4 = generic_bs_wm_4, - .bs_wm_8 = BS_UNIMPLEMENTED, - - /* write region */ - .bs_wr_1 = generic_bs_wr_1, - .bs_wr_2 = generic_bs_wr_2, - .bs_wr_4 = generic_bs_wr_4, - .bs_wr_8 = BS_UNIMPLEMENTED, - - /* set multiple */ - .bs_sm_1 = BS_UNIMPLEMENTED, - .bs_sm_2 = BS_UNIMPLEMENTED, - .bs_sm_4 = BS_UNIMPLEMENTED, - .bs_sm_8 = BS_UNIMPLEMENTED, - - /* set region */ - .bs_sr_1 = generic_bs_sr_1, - .bs_sr_2 = generic_bs_sr_2, - .bs_sr_4 = generic_bs_sr_4, - .bs_sr_8 = BS_UNIMPLEMENTED, - - /* copy */ - .bs_c_1 = BS_UNIMPLEMENTED, - .bs_c_2 = generic_bs_c_2, - .bs_c_4 = BS_UNIMPLEMENTED, - .bs_c_8 = BS_UNIMPLEMENTED, - - /* read stream (single) */ - .bs_r_1_s = NULL, /* Use inline code in bus.h */ - .bs_r_2_s = NULL, /* Use inline code in bus.h */ - .bs_r_4_s = NULL, /* Use inline code in bus.h */ - .bs_r_8_s = NULL, /* Use inline code in bus.h */ - - /* read multiple stream */ - .bs_rm_1_s = generic_bs_rm_1, - .bs_rm_2_s = generic_bs_rm_2, - .bs_rm_4_s = generic_bs_rm_4, - .bs_rm_8_s = BS_UNIMPLEMENTED, - - /* read region stream */ - .bs_rr_1_s = generic_bs_rr_1, - .bs_rr_2_s = generic_bs_rr_2, - .bs_rr_4_s = generic_bs_rr_4, - .bs_rr_8_s = BS_UNIMPLEMENTED, - - /* write stream (single) */ - .bs_w_1_s = NULL, /* Use inline code in bus.h */ - .bs_w_2_s = NULL, /* Use inline code in bus.h */ - .bs_w_4_s = NULL, /* Use inline code in bus.h */ - .bs_w_8_s = NULL, /* Use inline code in bus.h */ - - /* write multiple stream */ - .bs_wm_1_s = generic_bs_wm_1, - .bs_wm_2_s = generic_bs_wm_2, - .bs_wm_4_s = generic_bs_wm_4, - .bs_wm_8_s = BS_UNIMPLEMENTED, - - /* write region stream */ - .bs_wr_1_s = generic_bs_wr_1, - .bs_wr_2_s = generic_bs_wr_2, - .bs_wr_4_s = generic_bs_wr_4, - .bs_wr_8_s = BS_UNIMPLEMENTED, -}; - #ifndef FDT static struct at91_softc *at91_softc; @@ -265,7 +108,7 @@ at91_attach(device_t dev) arm_post_filter = at91_eoi; at91_softc = sc; - sc->sc_st = &at91_bs_tag; + sc->sc_st = arm_base_bs_tag; sc->sc_sh = AT91_BASE; sc->sc_aic_sh = AT91_BASE + AT91_SYS_BASE; sc->dev = dev; @@ -336,9 +179,9 @@ at91_alloc_resource(device_t dev, device_t child, int type, int *rid, rle->res = rman_reserve_resource(&sc->sc_mem_rman, start, end, count, flags, child); if (rle->res != NULL) { - bus_space_map(&at91_bs_tag, start, + bus_space_map(arm_base_bs_tag, start, rman_get_size(rle->res), 0, &bsh); - rman_set_bustag(rle->res, &at91_bs_tag); + rman_set_bustag(rle->res, arm_base_bs_tag); rman_set_bushandle(rle->res, bsh); } break; diff --git a/sys/arm/at91/at91_common.c b/sys/arm/at91/at91_common.c index 4153366c3ecf..9f960f67aa51 100644 --- a/sys/arm/at91/at91_common.c +++ b/sys/arm/at91/at91_common.c @@ -48,8 +48,6 @@ __FBSDID("$FreeBSD$"); #include <machine/fdt.h> extern const struct arm_devmap_entry at91_devmap[]; -extern struct bus_space at91_bs_tag; -bus_space_tag_t fdtbus_bs_tag = &at91_bs_tag; struct fdt_fixup_entry fdt_fixup_table[] = { { NULL, NULL } diff --git a/sys/arm/at91/at91_machdep.c b/sys/arm/at91/at91_machdep.c index 2d5dda2942ab..936f145909de 100644 --- a/sys/arm/at91/at91_machdep.c +++ b/sys/arm/at91/at91_machdep.c @@ -114,8 +114,6 @@ __FBSDID("$FreeBSD$"); /* 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) -extern struct bus_space at91_bs_tag; - struct pv_addr kernel_pt_table[NUM_KERNEL_PTS]; /* Static device mappings. */ diff --git a/sys/arm/at91/at91_mci.c b/sys/arm/at91/at91_mci.c index 8e55e02f6f1e..5bab815202a3 100644 --- a/sys/arm/at91/at91_mci.c +++ b/sys/arm/at91/at91_mci.c @@ -446,6 +446,9 @@ at91_mci_attach(device_t dev) CTLFLAG_RW, &sc->allow_overclock, 0, "Allow up to 30MHz clock for 25MHz request when next highest speed 15MHz or less."); + SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "debug", + CTLFLAG_RWTUN, &mci_debug, 0, "enable debug output"); + /* * Our real min freq is master_clock/512, but upper driver layers are * going to set the min speed during card discovery, and the right speed @@ -783,15 +786,6 @@ at91_mci_start_cmd(struct at91_mci_softc *sc, struct mmc_command *cmd) WR4(sc, PDC_PTCR, PDC_PTCR_RXTEN); } else { len = min(BBSIZE, remaining); - /* - * If this is MCI1 revision 2xx controller, apply - * a work-around for the "Data Write Operation and - * number of bytes" erratum. - */ - if ((sc->sc_cap & CAP_MCI1_REV2XX) && len < 12) { - len = 12; - memset(sc->bbuf_vaddr[0], 0, 12); - } at91_bswap_buf(sc, sc->bbuf_vaddr[0], data->data, len); err = bus_dmamap_load(sc->dmatag, sc->bbuf_map[0], sc->bbuf_vaddr[0], len, at91_mci_getaddr, @@ -800,8 +794,13 @@ at91_mci_start_cmd(struct at91_mci_softc *sc, struct mmc_command *cmd) panic("IO write dmamap_load failed\n"); bus_dmamap_sync(sc->dmatag, sc->bbuf_map[0], BUS_DMASYNC_PREWRITE); + /* + * Erratum workaround: PDC transfer length on a write + * must not be smaller than 12 bytes (3 words); only + * blklen bytes (set above) are actually transferred. + */ WR4(sc, PDC_TPR,paddr); - WR4(sc, PDC_TCR, len / 4); + WR4(sc, PDC_TCR, (len < 12) ? 3 : len / 4); sc->bbuf_len[0] = len; remaining -= len; if (remaining == 0) { @@ -818,7 +817,7 @@ at91_mci_start_cmd(struct at91_mci_softc *sc, struct mmc_command *cmd) bus_dmamap_sync(sc->dmatag, sc->bbuf_map[1], BUS_DMASYNC_PREWRITE); WR4(sc, PDC_TNPR, paddr); - WR4(sc, PDC_TNCR, len / 4); + WR4(sc, PDC_TNCR, (len < 12) ? 3 : len / 4); sc->bbuf_len[1] = len; remaining -= len; } diff --git a/sys/arm/at91/at91_ohci.c b/sys/arm/at91/at91_ohci.c new file mode 100644 index 000000000000..3e39f5115450 --- /dev/null +++ b/sys/arm/at91/at91_ohci.c @@ -0,0 +1,242 @@ +/*- + * 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/stdint.h> +#include <sys/stddef.h> +#include <sys/param.h> +#include <sys/queue.h> +#include <sys/types.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/bus.h> +#include <sys/module.h> +#include <sys/lock.h> +#include <sys/mutex.h> +#include <sys/condvar.h> +#include <sys/sysctl.h> +#include <sys/sx.h> +#include <sys/unistd.h> +#include <sys/callout.h> +#include <sys/malloc.h> +#include <sys/priv.h> + +#include <dev/usb/usb.h> +#include <dev/usb/usbdi.h> + +#include <dev/usb/usb_core.h> +#include <dev/usb/usb_busdma.h> +#include <dev/usb/usb_process.h> +#include <dev/usb/usb_util.h> + +#include <dev/usb/usb_controller.h> +#include <dev/usb/usb_bus.h> +#include <dev/usb/controller/ohci.h> +#include <dev/usb/controller/ohcireg.h> + +#include <sys/rman.h> + +#include <arm/at91/at91_pmcvar.h> + +#define MEM_RID 0 + +static device_probe_t ohci_atmelarm_probe; +static device_attach_t ohci_atmelarm_attach; +static device_detach_t ohci_atmelarm_detach; + +struct at91_ohci_softc { + struct ohci_softc sc_ohci; /* must be first */ + struct at91_pmc_clock *mclk; + struct at91_pmc_clock *iclk; + struct at91_pmc_clock *fclk; +}; + +static int +ohci_atmelarm_probe(device_t dev) +{ + + device_set_desc(dev, "AT91 integrated OHCI controller"); + return (BUS_PROBE_DEFAULT); +} + +static int +ohci_atmelarm_attach(device_t dev) +{ + struct at91_ohci_softc *sc = device_get_softc(dev); + int err; + int rid; + + /* initialise some bus fields */ + sc->sc_ohci.sc_bus.parent = dev; + sc->sc_ohci.sc_bus.devices = sc->sc_ohci.sc_devices; + sc->sc_ohci.sc_bus.devices_max = OHCI_MAX_DEVICES; + sc->sc_ohci.sc_bus.dma_bits = 32; + + /* get all DMA memory */ + if (usb_bus_mem_alloc_all(&sc->sc_ohci.sc_bus, + USB_GET_DMA_TAG(dev), &ohci_iterate_hw_softc)) { + return (ENOMEM); + } + sc->mclk = at91_pmc_clock_ref("mck"); + sc->iclk = at91_pmc_clock_ref("ohci_clk"); + sc->fclk = at91_pmc_clock_ref("uhpck"); + + sc->sc_ohci.sc_dev = dev; + + rid = MEM_RID; + sc->sc_ohci.sc_io_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, + &rid, RF_ACTIVE); + + if (!(sc->sc_ohci.sc_io_res)) { + err = ENOMEM; + goto error; + } + sc->sc_ohci.sc_io_tag = rman_get_bustag(sc->sc_ohci.sc_io_res); + sc->sc_ohci.sc_io_hdl = rman_get_bushandle(sc->sc_ohci.sc_io_res); + sc->sc_ohci.sc_io_size = rman_get_size(sc->sc_ohci.sc_io_res); + + rid = 0; + sc->sc_ohci.sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, + RF_ACTIVE); + if (!(sc->sc_ohci.sc_irq_res)) { + goto error; + } + sc->sc_ohci.sc_bus.bdev = device_add_child(dev, "usbus", -1); + if (!(sc->sc_ohci.sc_bus.bdev)) { + goto error; + } + device_set_ivars(sc->sc_ohci.sc_bus.bdev, &sc->sc_ohci.sc_bus); + + strlcpy(sc->sc_ohci.sc_vendor, "Atmel", sizeof(sc->sc_ohci.sc_vendor)); + + err = bus_setup_intr(dev, sc->sc_ohci.sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, + NULL, (driver_intr_t *)ohci_interrupt, sc, &sc->sc_ohci.sc_intr_hdl); + if (err) { + sc->sc_ohci.sc_intr_hdl = NULL; + goto error; + } + /* + * turn on the clocks from the AT91's point of view. Keep the unit in reset. + */ + at91_pmc_clock_enable(sc->mclk); + at91_pmc_clock_enable(sc->iclk); + at91_pmc_clock_enable(sc->fclk); + bus_space_write_4(sc->sc_ohci.sc_io_tag, sc->sc_ohci.sc_io_hdl, + OHCI_CONTROL, 0); + + err = ohci_init(&sc->sc_ohci); + if (!err) { + err = device_probe_and_attach(sc->sc_ohci.sc_bus.bdev); + } + if (err) { + goto error; + } + return (0); + +error: + ohci_atmelarm_detach(dev); + return (ENXIO); +} + +static int +ohci_atmelarm_detach(device_t dev) +{ + struct at91_ohci_softc *sc = device_get_softc(dev); + device_t bdev; + int err; + + if (sc->sc_ohci.sc_bus.bdev) { + bdev = sc->sc_ohci.sc_bus.bdev; + device_detach(bdev); + device_delete_child(dev, bdev); + } + /* during module unload there are lots of children leftover */ + device_delete_children(dev); + + /* + * Put the controller into reset, then disable clocks and do + * the MI tear down. We have to disable the clocks/hardware + * after we do the rest of the teardown. We also disable the + * clocks in the opposite order we acquire them, but that + * doesn't seem to be absolutely necessary. We free up the + * clocks after we disable them, so the system could, in + * theory, reuse them. + */ + bus_space_write_4(sc->sc_ohci.sc_io_tag, sc->sc_ohci.sc_io_hdl, + OHCI_CONTROL, 0); + + at91_pmc_clock_disable(sc->fclk); + at91_pmc_clock_disable(sc->iclk); + at91_pmc_clock_disable(sc->mclk); + at91_pmc_clock_deref(sc->fclk); + at91_pmc_clock_deref(sc->iclk); + at91_pmc_clock_deref(sc->mclk); + + if (sc->sc_ohci.sc_irq_res && sc->sc_ohci.sc_intr_hdl) { + /* + * only call ohci_detach() after ohci_init() + */ + ohci_detach(&sc->sc_ohci); + + err = bus_teardown_intr(dev, sc->sc_ohci.sc_irq_res, sc->sc_ohci.sc_intr_hdl); + sc->sc_ohci.sc_intr_hdl = NULL; + } + if (sc->sc_ohci.sc_irq_res) { + bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_ohci.sc_irq_res); + sc->sc_ohci.sc_irq_res = NULL; + } + if (sc->sc_ohci.sc_io_res) { + bus_release_resource(dev, SYS_RES_MEMORY, MEM_RID, + sc->sc_ohci.sc_io_res); + sc->sc_ohci.sc_io_res = NULL; + } + usb_bus_mem_free_all(&sc->sc_ohci.sc_bus, &ohci_iterate_hw_softc); + + return (0); +} + +static device_method_t ohci_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, ohci_atmelarm_probe), + DEVMETHOD(device_attach, ohci_atmelarm_attach), + DEVMETHOD(device_detach, ohci_atmelarm_detach), + DEVMETHOD(device_suspend, bus_generic_suspend), + DEVMETHOD(device_resume, bus_generic_resume), + DEVMETHOD(device_shutdown, bus_generic_shutdown), + + DEVMETHOD_END +}; + +static driver_t ohci_driver = { + .name = "ohci", + .methods = ohci_methods, + .size = sizeof(struct at91_ohci_softc), +}; + +static devclass_t ohci_devclass; + +DRIVER_MODULE(ohci, atmelarm, ohci_driver, ohci_devclass, 0, 0); +MODULE_DEPEND(ohci, usb, 1, 1, 1); diff --git a/sys/arm/at91/at91_ohci_fdt.c b/sys/arm/at91/at91_ohci_fdt.c new file mode 100644 index 000000000000..de3d3574deb2 --- /dev/null +++ b/sys/arm/at91/at91_ohci_fdt.c @@ -0,0 +1,251 @@ +/*- + * 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/stdint.h> +#include <sys/stddef.h> +#include <sys/param.h> +#include <sys/queue.h> +#include <sys/types.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/bus.h> +#include <sys/module.h> +#include <sys/lock.h> +#include <sys/mutex.h> +#include <sys/condvar.h> +#include <sys/sysctl.h> +#include <sys/sx.h> +#include <sys/unistd.h> +#include <sys/callout.h> +#include <sys/malloc.h> +#include <sys/priv.h> + +#include <dev/usb/usb.h> +#include <dev/usb/usbdi.h> + +#include <dev/usb/usb_core.h> +#include <dev/usb/usb_busdma.h> +#include <dev/usb/usb_process.h> +#include <dev/usb/usb_util.h> + +#include <dev/usb/usb_controller.h> +#include <dev/usb/usb_bus.h> +#include <dev/usb/controller/ohci.h> +#include <dev/usb/controller/ohcireg.h> + +#include <sys/rman.h> + +#include <arm/at91/at91_pmcvar.h> + +#include <dev/fdt/fdt_common.h> +#include <dev/ofw/ofw_bus.h> +#include <dev/ofw/ofw_bus_subr.h> + +#define MEM_RID 0 + +static device_probe_t ohci_at91_fdt_probe; +static device_attach_t ohci_at91_fdt_attach; +static device_detach_t ohci_at91_fdt_detach; + +struct at91_ohci_softc { + struct ohci_softc sc_ohci; /* must be first */ + struct at91_pmc_clock *mclk; + struct at91_pmc_clock *iclk; + struct at91_pmc_clock *fclk; +}; + +static int +ohci_at91_fdt_probe(device_t dev) +{ + if (!ofw_bus_is_compatible(dev, "atmel,at91rm9200-ohci")) + return (ENXIO); + device_set_desc(dev, "AT91 integrated OHCI controller"); + + return (BUS_PROBE_DEFAULT); +} + +static int +ohci_at91_fdt_attach(device_t dev) +{ + struct at91_ohci_softc *sc = device_get_softc(dev); + int err; + int rid; + + /* initialise some bus fields */ + sc->sc_ohci.sc_bus.parent = dev; + sc->sc_ohci.sc_bus.devices = sc->sc_ohci.sc_devices; + sc->sc_ohci.sc_bus.devices_max = OHCI_MAX_DEVICES; + sc->sc_ohci.sc_bus.dma_bits = 32; + + /* get all DMA memory */ + if (usb_bus_mem_alloc_all(&sc->sc_ohci.sc_bus, + USB_GET_DMA_TAG(dev), &ohci_iterate_hw_softc)) { + return (ENOMEM); + } + sc->mclk = at91_pmc_clock_ref("mck"); + sc->iclk = at91_pmc_clock_ref("ohci_clk"); + sc->fclk = at91_pmc_clock_ref("uhpck"); + + sc->sc_ohci.sc_dev = dev; + + rid = MEM_RID; + sc->sc_ohci.sc_io_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, + &rid, RF_ACTIVE); + + if (!(sc->sc_ohci.sc_io_res)) { + err = ENOMEM; + goto error; + } + sc->sc_ohci.sc_io_tag = rman_get_bustag(sc->sc_ohci.sc_io_res); + sc->sc_ohci.sc_io_hdl = rman_get_bushandle(sc->sc_ohci.sc_io_res); + sc->sc_ohci.sc_io_size = rman_get_size(sc->sc_ohci.sc_io_res); + + rid = 0; + sc->sc_ohci.sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, + RF_ACTIVE); + if (!(sc->sc_ohci.sc_irq_res)) { + goto error; + } + sc->sc_ohci.sc_bus.bdev = device_add_child(dev, "usbus", -1); + if (!(sc->sc_ohci.sc_bus.bdev)) { + goto error; + } + device_set_ivars(sc->sc_ohci.sc_bus.bdev, &sc->sc_ohci.sc_bus); + + strlcpy(sc->sc_ohci.sc_vendor, "Atmel", sizeof(sc->sc_ohci.sc_vendor)); + + err = bus_setup_intr(dev, sc->sc_ohci.sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, + NULL, (driver_intr_t *)ohci_interrupt, sc, &sc->sc_ohci.sc_intr_hdl); + if (err) { + sc->sc_ohci.sc_intr_hdl = NULL; + goto error; + } + /* + * turn on the clocks from the AT91's point of view. Keep the unit in reset. + */ + at91_pmc_clock_enable(sc->mclk); + at91_pmc_clock_enable(sc->iclk); + at91_pmc_clock_enable(sc->fclk); + bus_space_write_4(sc->sc_ohci.sc_io_tag, sc->sc_ohci.sc_io_hdl, + OHCI_CONTROL, 0); + + err = ohci_init(&sc->sc_ohci); + if (!err) { + err = device_probe_and_attach(sc->sc_ohci.sc_bus.bdev); + } + if (err) { + goto error; + } + return (0); + +error: + ohci_at91_fdt_detach(dev); + return (ENXIO); +} + +static int +ohci_at91_fdt_detach(device_t dev) +{ + struct at91_ohci_softc *sc = device_get_softc(dev); + device_t bdev; + int err; + + if (sc->sc_ohci.sc_bus.bdev) { + bdev = sc->sc_ohci.sc_bus.bdev; + device_detach(bdev); + device_delete_child(dev, bdev); + } + /* during module unload there are lots of children leftover */ + device_delete_children(dev); + + if (sc->sc_ohci.sc_io_res != NULL) { + /* + * Put the controller into reset, then disable clocks and do + * the MI tear down. We have to disable the clocks/hardware + * after we do the rest of the teardown. We also disable the + * clocks in the opposite order we acquire them, but that + * doesn't seem to be absolutely necessary. We free up the + * clocks after we disable them, so the system could, in + * theory, reuse them. + */ + bus_space_write_4(sc->sc_ohci.sc_io_tag, sc->sc_ohci.sc_io_hdl, + OHCI_CONTROL, 0); + + at91_pmc_clock_disable(sc->fclk); + at91_pmc_clock_disable(sc->iclk); + at91_pmc_clock_disable(sc->mclk); + at91_pmc_clock_deref(sc->fclk); + at91_pmc_clock_deref(sc->iclk); + at91_pmc_clock_deref(sc->mclk); + + if (sc->sc_ohci.sc_irq_res && sc->sc_ohci.sc_intr_hdl) { + /* + * only call ohci_detach() after ohci_init() + */ + ohci_detach(&sc->sc_ohci); + + err = bus_teardown_intr(dev, sc->sc_ohci.sc_irq_res, + sc->sc_ohci.sc_intr_hdl); + sc->sc_ohci.sc_intr_hdl = NULL; + } + if (sc->sc_ohci.sc_irq_res) { + bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_ohci.sc_irq_res); + sc->sc_ohci.sc_irq_res = NULL; + } + if (sc->sc_ohci.sc_io_res) { + bus_release_resource(dev, SYS_RES_MEMORY, MEM_RID, + sc->sc_ohci.sc_io_res); + sc->sc_ohci.sc_io_res = NULL; + } + } + usb_bus_mem_free_all(&sc->sc_ohci.sc_bus, &ohci_iterate_hw_softc); + + return (0); +} + +static device_method_t ohci_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, ohci_at91_fdt_probe), + DEVMETHOD(device_attach, ohci_at91_fdt_attach), + DEVMETHOD(device_detach, ohci_at91_fdt_detach), + DEVMETHOD(device_suspend, bus_generic_suspend), + DEVMETHOD(device_resume, bus_generic_resume), + DEVMETHOD(device_shutdown, bus_generic_shutdown), + + DEVMETHOD_END +}; + +static driver_t ohci_driver = { + .name = "ohci", + .methods = ohci_methods, + .size = sizeof(struct at91_ohci_softc), +}; + +static devclass_t ohci_devclass; + +DRIVER_MODULE(ohci, simplebus, ohci_driver, ohci_devclass, 0, 0); +MODULE_DEPEND(ohci, usb, 1, 1, 1); diff --git a/sys/arm/at91/board_tsc4370.c b/sys/arm/at91/board_tsc4370.c index c898518623fb..1bc0426878ba 100644 --- a/sys/arm/at91/board_tsc4370.c +++ b/sys/arm/at91/board_tsc4370.c @@ -70,6 +70,10 @@ WR4HW(uint32_t devbase, uint32_t regoff, uint32_t val) *(volatile uint32_t *)(AT91_BASE + devbase + regoff) = val; } +/* + * This is the same calculation the at91 uart driver does, we use it to update + * the console uart baud rate after changing the MCK rate. + */ #ifndef BAUD2DIVISOR #define BAUD2DIVISOR(b) \ ((((at91_master_clock * 10) / ((b) * 16)) + 5) / 10) @@ -96,34 +100,6 @@ static struct arm_boot_params boot_params; static struct tsc_bootinfo inkernel_bootinfo; /* - * Override the default boot param parser (supplied via weak linkage) with one - * that knows how to handle our custom tsc_bootinfo passed in from boot2. - */ -vm_offset_t -parse_boot_param(struct arm_boot_params *abp) -{ - - boot_params = *abp; - - /* - * If the right magic is in r0 and a non-NULL pointer is in r1, then - * it's our bootinfo, copy it. The pointer in r1 is a physical address - * passed from boot2. This routine is called immediately upon entry to - * initarm() and is in very nearly the same environment as boot2. In - * particular, va=pa and we can safely copy the args before we lose easy - * access to the memory they're stashed in right now. - * - * Note that all versions of boot2 that we've ever shipped have put - * zeroes into r2 and r3. Maybe that'll be useful some day. - */ - if (abp->abp_r0 == TSC_BOOTINFO_MAGIC && abp->abp_r1 != 0) { - inkernel_bootinfo = *(struct tsc_bootinfo *)(abp->abp_r1); - } - - return fake_preload_metadata(abp); -} - -/* * Change the master clock config and wait for it to stabilize. */ static void @@ -516,6 +492,8 @@ board_init(void) */ master_clock_init(); + /* From this point on you can use printf. */ + /* * Configure UARTs. */ @@ -598,5 +576,33 @@ board_init(void) return (at91_ramsize()); } +/* + * Override the default boot param parser (supplied via weak linkage) with one + * that knows how to handle our custom tsc_bootinfo passed in from boot2. + */ +vm_offset_t +parse_boot_param(struct arm_boot_params *abp) +{ + + boot_params = *abp; + + /* + * If the right magic is in r0 and a non-NULL pointer is in r1, then + * it's our bootinfo, copy it. The pointer in r1 is a physical address + * passed from boot2. This routine is called immediately upon entry to + * initarm() and is in very nearly the same environment as boot2. In + * particular, va=pa and we can safely copy the args before we lose easy + * access to the memory they're stashed in right now. + * + * Note that all versions of boot2 that we've ever shipped have put + * zeroes into r2 and r3. Maybe that'll be useful some day. + */ + if (abp->abp_r0 == TSC_BOOTINFO_MAGIC && abp->abp_r1 != 0) { + inkernel_bootinfo = *(struct tsc_bootinfo *)(abp->abp_r1); + } + + return fake_preload_metadata(abp); +} + ARM_BOARD(NONE, "TSC4370 Controller Board"); diff --git a/sys/arm/at91/files.at91 b/sys/arm/at91/files.at91 index 84056a4e1ed4..57c21ade0867 100644 --- a/sys/arm/at91/files.at91 +++ b/sys/arm/at91/files.at91 @@ -9,6 +9,8 @@ arm/at91/at91_smc.c standard arm/at91/at91_cfata.c optional at91_cfata arm/at91/at91_common.c optional fdt arm/at91/at91_mci.c optional at91_mci +arm/at91/at91_ohci.c optional ohci ! fdt +arm/at91/at91_ohci_fdt.c optional ohci fdt arm/at91/at91_pinctrl.c optional fdt fdt_pinctrl arm/at91/at91_pit.c optional at91sam9 arm/at91/at91_reset.S optional at91sam9 @@ -58,8 +60,14 @@ arm/at91/board_tsc4370.c optional at91_board_tsc4370 # # usb # +# XXX these should likely move to sys/at91 as well. They are also +# XXX slightly inconsistent with sys/conf/files and that ambiguity +# XXX should be fixed when this can be tested on real kit. The dci +# XXX code has hard-coded GPIO pins which is almost certainly wrong. dev/usb/controller/at91dci.c optional at91_dci -dev/usb/controller/at91dci_atmelarm.c optional at91_dci !fdt -dev/usb/controller/ohci_atmelarm.c optional ohci !fdt +dev/usb/controller/at91dci_atmelarm.c optional at91_dci ! fdt dev/usb/controller/at91dci_fdt.c optional at91_dci fdt -dev/usb/controller/ohci_fdt.c optional ohci fdt + +# We need this for both FDT and !FDT since we use arm_base_bs_ta +# files.arm picks it up for FDT. +arm/arm/bus_space_base.c optional !fdt diff --git a/sys/arm/at91/uart_cpu_at91usart.c b/sys/arm/at91/uart_cpu_at91usart.c index 57c4a5aafe1c..39f146cc5698 100644 --- a/sys/arm/at91/uart_cpu_at91usart.c +++ b/sys/arm/at91/uart_cpu_at91usart.c @@ -50,7 +50,6 @@ __FBSDID("$FreeBSD$"); bus_space_tag_t uart_bus_space_io; bus_space_tag_t uart_bus_space_mem; -extern struct bus_space at91_bs_tag; extern struct uart_class at91_usart_class; int @@ -69,7 +68,7 @@ uart_cpu_getdev(int devtype, struct uart_devinfo *di) class->uc_rclk = at91_master_clock; di->ops = uart_getops(class); di->bas.chan = 0; - di->bas.bst = &at91_bs_tag; + di->bas.bst = arm_base_bs_tag; /* * XXX: Not pretty, but will work because we map the needed addresses * early. At least we probed this so that the console will work on @@ -82,7 +81,7 @@ uart_cpu_getdev(int devtype, struct uart_devinfo *di) di->databits = 8; di->stopbits = 1; di->parity = UART_PARITY_NONE; - uart_bus_space_io = &at91_bs_tag; + uart_bus_space_io = arm_base_bs_tag; uart_bus_space_mem = NULL; /* Check the environment for overrides */ uart_getenv(devtype, di, class); diff --git a/sys/arm/conf/IMX53 b/sys/arm/conf/IMX53 index 7fe97a290a02..972437516e38 100644 --- a/sys/arm/conf/IMX53 +++ b/sys/arm/conf/IMX53 @@ -136,11 +136,3 @@ device wlan_amrr # AMRR transmit rate control algorithm # Flattened Device Tree options FDT # Configure using FDT/DTB data - -# NOTE: serial console will be disabled if syscons enabled -# Uncomment following lines for framebuffer/syscons support -#device sc -#device vt -#device kbdmux -#options SC_DFLT_FONT # compile font in -#makeoptions SC_DFLT_FONT=cp437 diff --git a/sys/arm/conf/IMX6 b/sys/arm/conf/IMX6 index 6de7c26e549c..6b383e28ccfd 100644 --- a/sys/arm/conf/IMX6 +++ b/sys/arm/conf/IMX6 @@ -125,14 +125,6 @@ device u3g # USB modems #device wlan_tkip # 802.11 TKIP support #device wlan_amrr # AMRR transmit rate control algorithm -# NOTE: serial console will be disabled if syscons enabled -# Uncomment following lines for framebuffer/syscons support -# Wandboard has no video console support yet. -#device sc -#device kbdmux -#options SC_DFLT_FONT # compile font in -#makeoptions SC_DFLT_FONT=cp437 - device vt device kbdmux device ukbd diff --git a/sys/arm/freescale/imx/imx_sdhci.c b/sys/arm/freescale/imx/imx_sdhci.c index 17edf0740d07..fa9d8edd138e 100644 --- a/sys/arm/freescale/imx/imx_sdhci.c +++ b/sys/arm/freescale/imx/imx_sdhci.c @@ -429,6 +429,7 @@ imx_sdhci_write_2(device_t dev, struct sdhci_slot *slot, bus_size_t off, uint16_ } else { imx_sdhc_set_clock(sc, false); } + return; } /* diff --git a/sys/arm/include/minidump.h b/sys/arm/include/minidump.h index ad7a90a00edc..aea9ec470f43 100644 --- a/sys/arm/include/minidump.h +++ b/sys/arm/include/minidump.h @@ -28,11 +28,18 @@ */ #ifndef _MACHINE_MINIDUMP_H_ -#define _MACHINE_MINIDUMP_H_ 1 +#define _MACHINE_MINIDUMP_H_ #define MINIDUMP_MAGIC "minidump FreeBSD/arm" #define MINIDUMP_VERSION 1 +/* + * The first page of vmcore is dedicated to the following header. + * As the rest of the page is zeroed, any header extension can be + * done without version bumping. It should be taken into account + * only that new entries will be zero in old vmcores. + */ + struct minidumphdr { char magic[24]; uint32_t version; @@ -40,6 +47,13 @@ struct minidumphdr { uint32_t bitmapsize; uint32_t ptesize; uint32_t kernbase; + uint32_t arch; + uint32_t mmuformat; }; +#define MINIDUMP_MMU_FORMAT_UNKNOWN 0 +#define MINIDUMP_MMU_FORMAT_V4 1 +#define MINIDUMP_MMU_FORMAT_V6 2 +#define MINIDUMP_MMU_FORMAT_V6_LPAE 3 + #endif /* _MACHINE_MINIDUMP_H_ */ diff --git a/sys/arm/include/sysarch.h b/sys/arm/include/sysarch.h index 71023e89d972..ac0a64d6b211 100644 --- a/sys/arm/include/sysarch.h +++ b/sys/arm/include/sysarch.h @@ -37,7 +37,9 @@ #ifndef _ARM_SYSARCH_H_ #define _ARM_SYSARCH_H_ +#include <machine/acle-compat.h> #include <machine/armreg.h> + /* * The ARM_TP_ADDRESS points to a special purpose page, which is used as local * store for the ARM per-thread data and Restartable Atomic Sequences support. @@ -53,11 +55,7 @@ /* ARM_TP_ADDRESS is needed for processors that don't support * the exclusive-access opcodes introduced with ARMv6K. */ -/* TODO: #if !defined(_HAVE_ARMv6K_INSTRUCTIONS) */ -#if !defined (__ARM_ARCH_7__) && \ - !defined (__ARM_ARCH_7A__) && \ - !defined (__ARM_ARCH_6K__) && \ - !defined (__ARM_ARCH_6ZK__) +#if __ARM_ARCH <= 5 #define ARM_TP_ADDRESS (ARM_VECTORS_HIGH + 0x1000) #define ARM_RAS_START (ARM_TP_ADDRESS + 4) #define ARM_RAS_END (ARM_TP_ADDRESS + 8) |