diff --git a/sys/arm/conf/GUMSTIX b/sys/arm/conf/GUMSTIX new file mode 100644 index 000000000000..dee63dfef4cd --- /dev/null +++ b/sys/arm/conf/GUMSTIX @@ -0,0 +1,93 @@ +# GUMSTIX -- Custom configuration for the Gumstix Basix and Connex boards from +# gumstix.com +# +# 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 GUMSTIX +cpu CPU_XSCALE_PXA2X0 + +# This probably wants to move somewhere else. Maybe we can create a basic +# PXA2X0 config, then make a GUMSTIX config that includes the basic one, +# adds the smc and smcphy devices and pulls in this hints file. +hints "GUMSTIX.hints" + +options PHYSADDR=0xa0000000 +options KERNPHYSADDR=0xa0200000 +options KERNVIRTADDR=0xc0200000 # Used in ldscript.arm + +options STARTUP_PAGETABLE_ADDR=0xa0000000 +include "../xscale/pxa/std.pxa" +#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 +options HZ=100 +#options DEVICE_POLLING + +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 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 BOOTP +options BOOTP_NFSROOT +options BOOTP_WIRED_TO=smc0 +options BOOTP_COMPAT +options BOOTP_NFSV3 +options BOOTP_BLOCKSIZE=4096 +options PREEMPTION +device loop +device ether +device mem # Memory and kernel memory devices +device mii +device smc +device smcphy +device uart +device uart_ns8250 + +device pty + +# Debugging for use in -current +options KDB +options DDB #Enable the kernel debugger +#options INVARIANTS #Enable calls of extra sanity checking +#options INVARIANT_SUPPORT #Extra sanity checks of internal structures, required by INVARIANTS +#options WITNESS #Enable checks to detect deadlocks and cycles +#options WITNESS_SKIPSPIN #Don't run witness on spinlocks for speed +#options DIAGNOSTIC + +device md +device random # Entropy device diff --git a/sys/arm/conf/GUMSTIX.hints b/sys/arm/conf/GUMSTIX.hints new file mode 100644 index 000000000000..5f4130ebc798 --- /dev/null +++ b/sys/arm/conf/GUMSTIX.hints @@ -0,0 +1,19 @@ +# $FreeBSD$ + +# Make sure we don't trample important bits in the UART registers. +hint.uart.0.ier_mask="0xe0" +hint.uart.0.ier_rxbits="0x1d" +hint.uart.1.ier_mask="0xe0" +hint.uart.1.ier_rxbits="0x1d" +hint.uart.2.ier_mask="0xe0" +hint.uart.2.ier_rxbits="0x1d" + +# SMSC LAN91C111s found on the netCF, netMMC and netDUO boards. +hint.smc.0.at="smi0" +hint.smc.0.mem="0x04000300" +hint.smc.0.size="0x10" +hint.smc.0.irq="100" +hint.smc.1.at="smi0" +hint.smc.1.mem="0x08000300" +hint.smc.1.size="0x10" +hint.smc.1.irq="91" diff --git a/sys/arm/include/intr.h b/sys/arm/include/intr.h index a252a928fef0..a41b214f82a9 100644 --- a/sys/arm/include/intr.h +++ b/sys/arm/include/intr.h @@ -41,6 +41,9 @@ #ifdef CPU_XSCALE_81342 #define NIRQ 128 +#elif defined(CPU_XSCALE_PXA2X0) +#include +#define NIRQ IRQ_GPIO_MAX #elif defined(CPU_ARM9) #define NIRQ 64 #else diff --git a/sys/arm/xscale/pxa/files.pxa b/sys/arm/xscale/pxa/files.pxa new file mode 100644 index 000000000000..492425f8b15d --- /dev/null +++ b/sys/arm/xscale/pxa/files.pxa @@ -0,0 +1,17 @@ +# $FreeBSD$ + +arm/arm/cpufunc_asm_xscale.S standard +arm/arm/irq_dispatch.S standard + +arm/xscale/pxa/pxa_gpio.c standard +arm/xscale/pxa/pxa_icu.c standard +arm/xscale/pxa/pxa_machdep.c standard +arm/xscale/pxa/pxa_obio.c standard +arm/xscale/pxa/pxa_smi.c standard +arm/xscale/pxa/pxa_space.c standard +arm/xscale/pxa/pxa_timer.c standard + +arm/xscale/pxa/uart_bus_pxa.c optional uart +arm/xscale/pxa/uart_cpu_pxa.c optional uart + +arm/xscale/pxa/if_smc_smi.c optional smc diff --git a/sys/arm/xscale/pxa/if_smc_smi.c b/sys/arm/xscale/pxa/if_smc_smi.c new file mode 100644 index 000000000000..1896a0a3f8c9 --- /dev/null +++ b/sys/arm/xscale/pxa/if_smc_smi.c @@ -0,0 +1,124 @@ +/*- + * Copyright (c) 2008 Benno Rice + * 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include + +#include "miibus_if.h" + +#include +#include + +static int smc_smi_probe(device_t); +static int smc_smi_attach(device_t); +static int smc_smi_detach(device_t); + +static int +smc_smi_probe(device_t dev) +{ + struct smc_softc *sc; + + sc = device_get_softc(dev); + sc->smc_usemem = 1; + + if (smc_probe(dev) != 0) { + return (ENXIO); + } + return (0); +} + +static int +smc_smi_attach(device_t dev) +{ + int err; + struct smc_softc *sc; + + sc = device_get_softc(dev); + + err = smc_attach(dev); + if (err) { + return (err); + } + + return (0); +} + +static int +smc_smi_detach(device_t dev) +{ + + smc_detach(dev); + + return (0); +} + +static device_method_t smc_smi_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, smc_smi_probe), + DEVMETHOD(device_attach, smc_smi_attach), + DEVMETHOD(device_detach, smc_smi_detach), + + /* MII interface */ + DEVMETHOD(miibus_readreg, smc_miibus_readreg), + DEVMETHOD(miibus_writereg, smc_miibus_writereg), + DEVMETHOD(miibus_statchg, smc_miibus_statchg), + + { 0, 0 } +}; + +static driver_t smc_smi_driver = { + "smc", + smc_smi_methods, + sizeof(struct smc_softc), +}; + +extern devclass_t smc_devclass; + +DRIVER_MODULE(smc, smi, smc_smi_driver, smc_devclass, 0, 0); +DRIVER_MODULE(miibus, smc, miibus_driver, miibus_devclass, 0, 0); +MODULE_DEPEND(smc, smi, 1, 1, 1); +MODULE_DEPEND(smc, ether, 1, 1, 1); +MODULE_DEPEND(smc, miibus, 1, 1, 1); diff --git a/sys/arm/xscale/pxa/pxa_gpio.c b/sys/arm/xscale/pxa/pxa_gpio.c new file mode 100644 index 000000000000..ecc220ae55de --- /dev/null +++ b/sys/arm/xscale/pxa/pxa_gpio.c @@ -0,0 +1,358 @@ +/*- + * Copyright (c) 2006 Benno Rice. 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +struct pxa_gpio_softc { + struct resource * pg_res[4]; + bus_space_tag_t pg_bst; + bus_space_handle_t pg_bsh; + struct mtx pg_mtx; + + uint32_t pg_intr[3]; +}; + +static struct resource_spec pxa_gpio_spec[] = { + { SYS_RES_MEMORY, 0, RF_ACTIVE }, + { SYS_RES_IRQ, 0, RF_ACTIVE }, + { SYS_RES_IRQ, 1, RF_ACTIVE }, + { SYS_RES_IRQ, 2, RF_ACTIVE }, + { -1, 0 } +}; + +static struct pxa_gpio_softc *pxa_gpio_softc = NULL; + +static int pxa_gpio_probe(device_t); +static int pxa_gpio_attach(device_t); + +static driver_filter_t pxa_gpio_intr0; +static driver_filter_t pxa_gpio_intr1; +static driver_filter_t pxa_gpio_intrN; + +static int +pxa_gpio_probe(device_t dev) +{ + + device_set_desc(dev, "GPIO Controller"); + return (0); +} + +static int +pxa_gpio_attach(device_t dev) +{ + int error; + void *ihl; + struct pxa_gpio_softc *sc; + + sc = (struct pxa_gpio_softc *)device_get_softc(dev); + + if (pxa_gpio_softc != NULL) + return (ENXIO); + pxa_gpio_softc = sc; + + error = bus_alloc_resources(dev, pxa_gpio_spec, sc->pg_res); + if (error) { + device_printf(dev, "could not allocate resources\n"); + return (ENXIO); + } + + sc->pg_bst = rman_get_bustag(sc->pg_res[0]); + sc->pg_bsh = rman_get_bushandle(sc->pg_res[0]); + + /* Disable and clear all interrupts. */ + bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GRER0, 0); + bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GRER1, 0); + bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GRER2, 0); + bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GFER0, 0); + bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GFER1, 0); + bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GFER2, 0); + bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GEDR0, ~0); + bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GEDR1, ~0); + bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GEDR2, ~0); + + mtx_init(&sc->pg_mtx, "GPIO mutex", NULL, MTX_SPIN); + + if (bus_setup_intr(dev, sc->pg_res[1], INTR_TYPE_MISC|INTR_MPSAFE, + pxa_gpio_intr0, NULL, sc, &ihl) != 0) { + bus_release_resources(dev, pxa_gpio_spec, sc->pg_res); + device_printf(dev, "could not set up intr0\n"); + return (ENXIO); + } + + if (bus_setup_intr(dev, sc->pg_res[2], INTR_TYPE_MISC|INTR_MPSAFE, + pxa_gpio_intr1, NULL, sc, &ihl) != 0) { + bus_release_resources(dev, pxa_gpio_spec, sc->pg_res); + device_printf(dev, "could not set up intr1\n"); + return (ENXIO); + } + + if (bus_setup_intr(dev, sc->pg_res[3], INTR_TYPE_MISC|INTR_MPSAFE, + pxa_gpio_intrN, NULL, sc, &ihl) != 0) { + bus_release_resources(dev, pxa_gpio_spec, sc->pg_res); + device_printf(dev, "could not set up intrN\n"); + return (ENXIO); + } + + return (0); +} + +static int +pxa_gpio_intr0(void *arg) +{ + struct pxa_gpio_softc *sc; + + sc = (struct pxa_gpio_softc *)arg; + + bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GEDR0, 0x1); + sc->pg_intr[0] |= 1; + + return (FILTER_HANDLED); +} + +static int +pxa_gpio_intr1(void *arg) +{ + struct pxa_gpio_softc *sc; + + sc = (struct pxa_gpio_softc *)arg; + + bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GEDR0, 0x2); + sc->pg_intr[1] |= 2; + + return (FILTER_HANDLED); +} + +static int +pxa_gpio_intrN(void *arg) +{ + uint32_t gedr0, gedr1, gedr2; + struct pxa_gpio_softc *sc; + + sc = (struct pxa_gpio_softc *)arg; + + gedr0 = bus_space_read_4(sc->pg_bst, sc->pg_bsh, GPIO_GEDR0); + gedr0 &= 0xfffffffc; + bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GEDR0, gedr0); + + gedr1 = bus_space_read_4(sc->pg_bst, sc->pg_bsh, GPIO_GEDR1); + bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GEDR1, gedr1); + + gedr2 = bus_space_read_4(sc->pg_bst, sc->pg_bsh, GPIO_GEDR2); + gedr2 &= 0x001fffff; + bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GEDR2, gedr2); + + sc->pg_intr[0] |= gedr0; + sc->pg_intr[1] |= gedr1; + sc->pg_intr[2] |= gedr2; + + return (FILTER_HANDLED); +} + +static device_method_t pxa_gpio_methods[] = { + DEVMETHOD(device_probe, pxa_gpio_probe), + DEVMETHOD(device_attach, pxa_gpio_attach), + + {0, 0} +}; + +static driver_t pxa_gpio_driver = { + "gpio", + pxa_gpio_methods, + sizeof(struct pxa_gpio_softc), +}; + +static devclass_t pxa_gpio_devclass; + +DRIVER_MODULE(pxagpio, pxa, pxa_gpio_driver, pxa_gpio_devclass, 0, 0); + +#define pxagpio_reg_read(softc, reg) \ + bus_space_read_4(sc->pg_bst, sc->pg_bsh, reg) +#define pxagpio_reg_write(softc, reg, val) \ + bus_space_write_4(sc->pg_bst, sc->pg_bsh, reg, val) + +uint32_t +pxa_gpio_get_function(int gpio) +{ + struct pxa_gpio_softc *sc; + uint32_t rv, io; + + sc = pxa_gpio_softc; + + rv = pxagpio_reg_read(sc, GPIO_FN_REG(gpio)) >> GPIO_FN_SHIFT(gpio); + rv = GPIO_FN(rv); + + io = pxagpio_reg_read(sc, PXA250_GPIO_REG(GPIO_GPDR0, gpio)); + if (io & GPIO_BIT(gpio)) + rv |= GPIO_OUT; + + io = pxagpio_reg_read(sc, PXA250_GPIO_REG(GPIO_GPLR0, gpio)); + if (io & GPIO_BIT(gpio)) + rv |= GPIO_SET; + + return (rv); +} + +uint32_t +pxa_gpio_set_function(int gpio, uint32_t fn) +{ + struct pxa_gpio_softc *sc; + uint32_t rv, bit, oldfn; + + sc = pxa_gpio_softc; + + oldfn = pxa_gpio_get_function(gpio); + + if (GPIO_FN(fn) == GPIO_FN(oldfn) && + GPIO_FN_IS_OUT(fn) == GPIO_FN_IS_OUT(oldfn)) { + /* + * The pin's function is not changing. + * For Alternate Functions and GPIO input, we can just + * return now. + * For GPIO output pins, check the initial state is + * the same. + * + * Return 'fn' instead of 'oldfn' so the caller can + * reliably detect that we didn't change anything. + * (The initial state might be different for non- + * GPIO output pins). + */ + if (!GPIO_IS_GPIO_OUT(fn) || + GPIO_FN_IS_SET(fn) == GPIO_FN_IS_SET(oldfn)) + return (fn); + } + + /* + * See section 4.1.3.7 of the PXA2x0 Developer's Manual for + * the correct procedure for changing GPIO pin functions. + */ + + bit = GPIO_BIT(gpio); + + /* + * 1. Configure the correct set/clear state of the pin + */ + if (GPIO_FN_IS_SET(fn)) + pxagpio_reg_write(sc, PXA250_GPIO_REG(GPIO_GPSR0, gpio), bit); + else + pxagpio_reg_write(sc, PXA250_GPIO_REG(GPIO_GPCR0, gpio), bit); + + /* + * 2. Configure the pin as an input or output as appropriate + */ + rv = pxagpio_reg_read(sc, PXA250_GPIO_REG(GPIO_GPDR0, gpio)) & ~bit; + if (GPIO_FN_IS_OUT(fn)) + rv |= bit; + pxagpio_reg_write(sc, PXA250_GPIO_REG(GPIO_GPDR0, gpio), rv); + + /* + * 3. Configure the pin's function + */ + bit = GPIO_FN_MASK << GPIO_FN_SHIFT(gpio); + fn = GPIO_FN(fn) << GPIO_FN_SHIFT(gpio); + rv = pxagpio_reg_read(sc, GPIO_FN_REG(gpio)) & ~bit; + pxagpio_reg_write(sc, GPIO_FN_REG(gpio), rv | fn); + + return (oldfn); +} + +/* + * GPIO "interrupt" handling. + */ + +void +pxa_gpio_mask_irq(int irq) +{ + uint32_t val; + struct pxa_gpio_softc *sc; + int gpio; + + sc = pxa_gpio_softc; + gpio = IRQ_TO_GPIO(irq); + + val = pxagpio_reg_read(sc, PXA250_GPIO_REG(GPIO_GRER0, gpio)); + val &= ~GPIO_BIT(gpio); + pxagpio_reg_write(sc, PXA250_GPIO_REG(GPIO_GRER0, gpio), val); +} + +void +pxa_gpio_unmask_irq(int irq) +{ + uint32_t val; + struct pxa_gpio_softc *sc; + int gpio; + + sc = pxa_gpio_softc; + gpio = IRQ_TO_GPIO(irq); + + val = pxagpio_reg_read(sc, PXA250_GPIO_REG(GPIO_GRER0, gpio)); + val |= GPIO_BIT(gpio); + pxagpio_reg_write(sc, PXA250_GPIO_REG(GPIO_GRER0, gpio), val); +} + +int +pxa_gpio_get_next_irq() +{ + struct pxa_gpio_softc *sc; + int gpio; + + sc = pxa_gpio_softc; + + if (sc->pg_intr[0] != 0) { + gpio = ffs(sc->pg_intr[0]) - 1; + sc->pg_intr[0] &= ~(1 << gpio); + return (GPIO_TO_IRQ(gpio)); + } + if (sc->pg_intr[1] != 0) { + gpio = ffs(sc->pg_intr[1]) - 1; + sc->pg_intr[1] &= ~(1 << gpio); + return (GPIO_TO_IRQ(gpio + 32)); + } + if (sc->pg_intr[2] != 0) { + gpio = ffs(sc->pg_intr[2]) - 1; + sc->pg_intr[2] &= ~(1 << gpio); + return (GPIO_TO_IRQ(gpio + 64)); + } + + return (-1); +} diff --git a/sys/arm/xscale/pxa/pxa_icu.c b/sys/arm/xscale/pxa/pxa_icu.c new file mode 100644 index 000000000000..2cb2cbb6fb7c --- /dev/null +++ b/sys/arm/xscale/pxa/pxa_icu.c @@ -0,0 +1,258 @@ +/*- + * Copyright (c) 2006 Benno Rice. 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +struct pxa_icu_softc { + struct resource * pi_res[1]; + bus_space_tag_t pi_bst; + bus_space_handle_t pi_bsh; +}; + +static struct resource_spec pxa_icu_spec[] = { + { SYS_RES_MEMORY, 0, RF_ACTIVE }, + { -1, 0 } +}; + +static struct pxa_icu_softc *pxa_icu_softc = NULL; + +static int pxa_icu_probe(device_t); +static int pxa_icu_attach(device_t); + +uint32_t pxa_icu_get_icip(void); +void pxa_icu_clear_icip(int); +uint32_t pxa_icu_get_icfp(void); +void pxa_icu_clear_icfp(int); +uint32_t pxa_icu_get_icmr(void); +void pxa_icu_set_icmr(uint32_t); +uint32_t pxa_icu_get_iclr(void); +void pxa_icu_set_iclr(uint32_t); +uint32_t pxa_icu_get_icpr(void); +void pxa_icu_idle_enable(void); +void pxa_icu_idle_disable(void); + +extern uint32_t pxa_gpio_intr_flags[]; + +static int +pxa_icu_probe(device_t dev) +{ + + device_set_desc(dev, "Interrupt Controller"); + return (0); +} + +static int +pxa_icu_attach(device_t dev) +{ + int error; + struct pxa_icu_softc *sc; + + sc = (struct pxa_icu_softc *)device_get_softc(dev); + + if (pxa_icu_softc != NULL) + return (ENXIO); + pxa_icu_softc = sc; + + error = bus_alloc_resources(dev, pxa_icu_spec, sc->pi_res); + if (error) { + device_printf(dev, "could not allocate resources\n"); + return (ENXIO); + } + + sc->pi_bst = rman_get_bustag(sc->pi_res[0]); + sc->pi_bsh = rman_get_bushandle(sc->pi_res[0]); + + /* Disable all interrupts. */ + pxa_icu_set_icmr(0); + + /* Route all interrupts to IRQ rather than FIQ. */ + pxa_icu_set_iclr(0); + + /* XXX: This should move to configure_final or something. */ + enable_interrupts(I32_bit|F32_bit); + + return (0); +} + +static device_method_t pxa_icu_methods[] = { + DEVMETHOD(device_probe, pxa_icu_probe), + DEVMETHOD(device_attach, pxa_icu_attach), + + {0, 0} +}; + +static driver_t pxa_icu_driver = { + "icu", + pxa_icu_methods, + sizeof(struct pxa_icu_softc), +}; + +static devclass_t pxa_icu_devclass; + +DRIVER_MODULE(pxaicu, pxa, pxa_icu_driver, pxa_icu_devclass, 0, 0); + +int +arm_get_next_irq() +{ + int irq; + + if ((irq = pxa_icu_get_icip()) != 0) { + return (ffs(irq) - 1); + } + + return (pxa_gpio_get_next_irq()); +} + +void +arm_mask_irq(uintptr_t nb) +{ + uint32_t mr; + + if (nb >= IRQ_GPIO0) { + pxa_gpio_mask_irq(nb); + return; + } + + mr = pxa_icu_get_icmr(); + mr &= ~(1 << nb); + pxa_icu_set_icmr(mr); +} + +void +arm_unmask_irq(uintptr_t nb) +{ + uint32_t mr; + + if (nb >= IRQ_GPIO0) { + pxa_gpio_unmask_irq(nb); + return; + } + + mr = pxa_icu_get_icmr(); + mr |= (1 << nb); + pxa_icu_set_icmr(mr); +} + +uint32_t +pxa_icu_get_icip() +{ + + return (bus_space_read_4(pxa_icu_softc->pi_bst, + pxa_icu_softc->pi_bsh, ICU_IP)); +} + +void +pxa_icu_clear_icip(int irq) +{ + + bus_space_write_4(pxa_icu_softc->pi_bst, + pxa_icu_softc->pi_bsh, ICU_IP, (1 << irq)); +} + +uint32_t +pxa_icu_get_icfp() +{ + + return (bus_space_read_4(pxa_icu_softc->pi_bst, + pxa_icu_softc->pi_bsh, ICU_FP)); +} + +void +pxa_icu_clear_icfp(int irq) +{ + + bus_space_write_4(pxa_icu_softc->pi_bst, + pxa_icu_softc->pi_bsh, ICU_FP, (1 << irq)); +} + +uint32_t +pxa_icu_get_icmr() +{ + + return (bus_space_read_4(pxa_icu_softc->pi_bst, + pxa_icu_softc->pi_bsh, ICU_MR)); +} + +void +pxa_icu_set_icmr(uint32_t val) +{ + + bus_space_write_4(pxa_icu_softc->pi_bst, + pxa_icu_softc->pi_bsh, ICU_MR, val); +} + +uint32_t +pxa_icu_get_iclr() +{ + + return (bus_space_read_4(pxa_icu_softc->pi_bst, + pxa_icu_softc->pi_bsh, ICU_LR)); +} + +void +pxa_icu_set_iclr(uint32_t val) +{ + + bus_space_write_4(pxa_icu_softc->pi_bst, + pxa_icu_softc->pi_bsh, ICU_LR, val); +} + +uint32_t +pxa_icu_get_icpr() +{ + + return (bus_space_read_4(pxa_icu_softc->pi_bst, + pxa_icu_softc->pi_bsh, ICU_PR)); +} + +void +pxa_icu_idle_enable() +{ + + bus_space_write_4(pxa_icu_softc->pi_bst, + pxa_icu_softc->pi_bsh, ICU_CR, 0x0); +} + +void +pxa_icu_idle_disable() +{ + + bus_space_write_4(pxa_icu_softc->pi_bst, + pxa_icu_softc->pi_bsh, ICU_CR, 0x1); +} diff --git a/sys/arm/xscale/pxa/pxa_machdep.c b/sys/arm/xscale/pxa/pxa_machdep.c new file mode 100644 index 000000000000..fc9918de6ecc --- /dev/null +++ b/sys/arm/xscale/pxa/pxa_machdep.c @@ -0,0 +1,576 @@ +/* $NetBSD: hpc_machdep.c,v 1.70 2003/09/16 08:18:22 agc Exp $ */ + +/*- + * 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 +__FBSDID("$FreeBSD$"); + +#define _ARM32_BUS_DMA_PRIVATE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define KERNEL_PT_SYS 0 /* Page table for mapping proc0 zero page */ +#define KERNEL_PT_IOPXS 1 +#define KERNEL_PT_BEFOREKERN 2 +#define KERNEL_PT_AFKERNEL 3 /* L2 table for mapping after kernel */ +#define KERNEL_PT_AFKERNEL_NUM 9 + +/* 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 +#ifdef IPKDB +#define UND_STACK_SIZE 2 +#else +#define UND_STACK_SIZE 1 +#endif + +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[PXA2X0_SDRAM_BANKS * 2 + 4]; +vm_paddr_t dump_avail[PXA2X0_SDRAM_BANKS * 2 + 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; + +void enable_mmu(vm_offset_t); +static struct trapframe proc0_tf; + +static void pxa_probe_sdram(bus_space_tag_t, bus_space_handle_t, + uint32_t *, uint32_t *); + +/* Static device mappings. */ +static const struct pmap_devmap pxa_devmap[] = { + /* + * Map the on-board devices up into the KVA region so we don't muck + * up user-space. + */ + { + PXA2X0_PERIPH_START + PXA2X0_PERIPH_OFFSET, + PXA2X0_PERIPH_START, + PXA250_PERIPH_END - PXA2X0_PERIPH_START, + 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 + +extern vm_offset_t xscale_cache_clean_addr; + +extern void boot_putc(int); + +void * +initarm(void *arg, void *arg2) +{ + struct pv_addr kernel_l1pt; + int loop; + u_int l1pagetable; + vm_offset_t freemempos; + vm_offset_t freemem_pt; + vm_offset_t afterkern; + vm_offset_t freemem_after; + vm_offset_t lastaddr; +#ifdef DDB + vm_offset_t zstart = 0, zend = 0; +#endif + int i, j; + uint32_t fake_preload[35]; + uint32_t memsize[PXA2X0_SDRAM_BANKS], memstart[PXA2X0_SDRAM_BANKS]; + + i = 0; + j = 0; + boothowto |= RB_SERIAL | RB_SINGLE; + bootverbose = 1; + + set_cpufuncs(); + 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 + 0x00200000; + fake_preload[i++] = MODINFO_SIZE; + fake_preload[i++] = sizeof(uint32_t); + fake_preload[i++] = (uint32_t)&end - KERNBASE - 0x00200000; +#ifdef DDB + if (*(uint32_t *)KERNVIRTADDR == MAGIC_TRAMP_NUMBER) { + fake_preload[i++] = MODINFO_METADATA|MODINFOMD_SSYM; + fake_preload[i++] = sizeof(vm_offset_t); + fake_preload[i++] = *(uint32_t *)(KERNVIRTADDR + 4); + fake_preload[i++] = MODINFO_METADATA|MODINFOMD_ESYM; + fake_preload[i++] = sizeof(vm_offset_t); + fake_preload[i++] = *(uint32_t *)(KERNVIRTADDR + 8); + lastaddr = *(uint32_t *)(KERNVIRTADDR + 8); + zend = lastaddr; + zstart = *(uint32_t *)(KERNVIRTADDR + 4); + ksym_start = zstart; + ksym_end = zend; + } else +#endif + lastaddr = (vm_offset_t)&end; + + 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 + 0x00200000) + freemempos = 0xa0200000; + /* Define a macro to simplify memory allocation */ +#define valloc_pages(var, np) \ + alloc_pages((var).pv_pa, (np)); \ + (var).pv_va = (var).pv_pa + 0x20000000; + +#define alloc_pages(var, np) \ + freemempos -= (np * PAGE_SIZE); \ + (var) = freemempos; \ + 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_pa = freemempos + + (loop % (PAGE_SIZE / L2_TABLE_SIZE_REAL)) * + L2_TABLE_SIZE_REAL; + kernel_pt_table[loop].pv_va = + kernel_pt_table[loop].pv_pa + 0x20000000; + } + i++; + } + freemem_pt = freemempos; + freemempos = 0xa0100000; + /* + * 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); +#ifdef ARM_USE_SMALL_ALLOC + freemempos -= PAGE_SIZE; + freemem_pt = trunc_page(freemem_pt); + freemem_after = freemempos - ((freemem_pt - 0xa0100000) / + PAGE_SIZE) * sizeof(struct arm_small_page); + arm_add_smallalloc_pages((void *)(freemem_after + 0x20000000) + , (void *)0xc0100000, freemem_pt - 0xa0100000, 1); + freemem_after -= ((freemem_after - 0xa0001000) / PAGE_SIZE) * + sizeof(struct arm_small_page); + arm_add_smallalloc_pages((void *)(freemem_after + 0x20000000) + , (void *)0xc0001000, trunc_page(freemem_after) - 0xa0001000, 0); + freemempos = trunc_page(freemem_after); + freemempos -= PAGE_SIZE; +#endif + /* + * Allocate memory for the l1 and l2 page tables. The scheme to avoid + * wasting memory by allocating the l1pt on the first 16k memory was + * taken from NetBSD rpc_machdep.c. NKPT should be greater than 12 for + * this to work (which is supposed to be the case). + */ + + /* + * 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_HIGH & ~(0x00100000 - 1), + &kernel_pt_table[KERNEL_PT_SYS]); +#if 0 /* XXXBJR: What is this? Don't know if there's an analogue. */ + pmap_link_l2pt(l1pagetable, IQ80321_IOPXS_VBASE, + &kernel_pt_table[KERNEL_PT_IOPXS]); +#endif + pmap_link_l2pt(l1pagetable, KERNBASE, + &kernel_pt_table[KERNEL_PT_BEFOREKERN]); + pmap_map_chunk(l1pagetable, KERNBASE, SDRAM_START, 0x100000, + VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE); + pmap_map_chunk(l1pagetable, KERNBASE + 0x100000, SDRAM_START + 0x100000, + 0x100000, VM_PROT_READ|VM_PROT_WRITE, PTE_PAGETABLE); + pmap_map_chunk(l1pagetable, KERNBASE + 0x200000, SDRAM_START + 0x200000, + (((uint32_t)(lastaddr) - KERNBASE - 0x200000) + L1_S_SIZE) & ~(L1_S_SIZE - 1), + VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE); + freemem_after = ((int)lastaddr + PAGE_SIZE) & ~(PAGE_SIZE - 1); + afterkern = round_page(((vm_offset_t)lastaddr + 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); + +#ifdef ARM_USE_SMALL_ALLOC + if ((freemem_after + 2 * PAGE_SIZE) <= afterkern) { + arm_add_smallalloc_pages((void *)(freemem_after), + (void*)(freemem_after + PAGE_SIZE), + afterkern - (freemem_after + PAGE_SIZE), 0); + } +#endif + + /* Map the Mini-Data cache clean area. */ + xscale_setup_minidata(l1pagetable, afterkern, + minidataclean.pv_pa); + + /* Map the vector page. */ + pmap_map_entry(l1pagetable, ARM_VECTORS_HIGH, systempage.pv_pa, + VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE); + pmap_devmap_bootstrap(l1pagetable, pxa_devmap); + + /* + * Give the XScale global cache clean code an appropriately + * sized chunk of unmapped VA space starting at 0xff000000 + * (our device mappings end before this address). + */ + xscale_cache_clean_addr = 0xff000000U; + + 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. + */ + 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(); + + /* + * Sort out bus_space for on-board devices. + */ + pxa_obio_tag_init(); + + /* + * Fetch the SDRAM start/size from the PXA2X0 SDRAM configration + * registers. + */ + pxa_probe_sdram(obio_tag, PXA2X0_MEMCTL_BASE, memstart, memsize); + + physmem = 0; + for (i = 0; i < PXA2X0_SDRAM_BANKS; i++) { + physmem += memsize[i] / PAGE_SIZE; + } + + /* Fire up consoles. */ + cninit(); + + /* 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, &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; + + /* Enable MMU, I-cache, D-cache, write buffer. */ + arm_vector_init(ARM_VECTORS_HIGH, ARM_VEC_ALL); + + pmap_curmaxkvaddr = afterkern + PAGE_SIZE; + /* + * ARM USE_SMALL_ALLOC uses dump_avail, so it must be filled before + * calling pmap_bootstrap. + */ + i = 0; + for (j = 0; j < PXA2X0_SDRAM_BANKS; j++) { + if (memsize[j] > 0) { + dump_avail[i++] = round_page(memstart[j]); + dump_avail[i++] = + trunc_page(memstart[j] + memsize[j]); + } + } + dump_avail[i] = 0; + dump_avail[i] = 0; + pmap_bootstrap(pmap_curmaxkvaddr, 0xd0000000, &kernel_l1pt); + msgbufp = (void*)msgbufpv.pv_va; + msgbufinit(msgbufp, MSGBUF_SIZE); + mutex_init(); + + i = 0; +#ifdef ARM_USE_SMALL_ALLOC + phys_avail[i++] = 0xa0000000; + phys_avail[i++] = 0xa0001000; /* + *XXX: Gross hack to get our + * pages in the vm_page_array + . */ +#endif + for (j = 0; j < PXA2X0_SDRAM_BANKS; j++) { + if (memsize[j] > 0) { + phys_avail[i] = round_page(memstart[j]); + dump_avail[i++] = round_page(memstart[j]); + phys_avail[i] = + trunc_page(memstart[j] + memsize[j]); + dump_avail[i++] = + trunc_page(memstart[j] + memsize[j]); + } + } + + dump_avail[i] = 0; + phys_avail[i++] = 0; + dump_avail[i] = 0; + phys_avail[i] = 0; +#ifdef ARM_USE_SMALL_ALLOC + phys_avail[2] = round_page(virtual_avail - KERNBASE + phys_avail[2]); +#else + phys_avail[0] = round_page(virtual_avail - KERNBASE + phys_avail[0]); +#endif + + /* Do basic tuning, hz etc */ + init_param1(); + init_param2(physmem); + kdb_init(); + return ((void *)(kernelstack.pv_va + USPACE_SVC_STACK_TOP - + sizeof(struct pcb))); +} + +static void +pxa_probe_sdram(bus_space_tag_t bst, bus_space_handle_t bsh, + uint32_t *memstart, uint32_t *memsize) +{ + uint32_t mdcnfg, dwid, dcac, drac, dnb; + int i; + + mdcnfg = bus_space_read_4(bst, bsh, MEMCTL_MDCNFG); + + /* + * Scan all 4 SDRAM banks + */ + for (i = 0; i < PXA2X0_SDRAM_BANKS; i++) { + memstart[i] = 0; + memsize[i] = 0; + + switch (i) { + case 0: + case 1: + if ((i == 0 && (mdcnfg & MDCNFG_DE0) == 0) || + (i == 1 && (mdcnfg & MDCNFG_DE1) == 0)) + continue; + dwid = mdcnfg >> MDCNFD_DWID01_SHIFT; + dcac = mdcnfg >> MDCNFD_DCAC01_SHIFT; + drac = mdcnfg >> MDCNFD_DRAC01_SHIFT; + dnb = mdcnfg >> MDCNFD_DNB01_SHIFT; + break; + + case 2: + case 3: + if ((i == 2 && (mdcnfg & MDCNFG_DE2) == 0) || + (i == 3 && (mdcnfg & MDCNFG_DE3) == 0)) + continue; + dwid = mdcnfg >> MDCNFD_DWID23_SHIFT; + dcac = mdcnfg >> MDCNFD_DCAC23_SHIFT; + drac = mdcnfg >> MDCNFD_DRAC23_SHIFT; + dnb = mdcnfg >> MDCNFD_DNB23_SHIFT; + break; + default: + panic("pxa_probe_sdram: impossible"); + } + + dwid = 2 << (1 - (dwid & MDCNFD_DWID_MASK)); /* 16/32 width */ + dcac = 1 << ((dcac & MDCNFD_DCAC_MASK) + 8); /* 8-11 columns */ + drac = 1 << ((drac & MDCNFD_DRAC_MASK) + 11); /* 11-13 rows */ + dnb = 2 << (dnb & MDCNFD_DNB_MASK); /* # of banks */ + + memsize[i] = dwid * dcac * drac * dnb; + memstart[i] = PXA2X0_SDRAM0_START + + (i * PXA2X0_SDRAM_BANK_SIZE); + } +} + +#define TIMER_FREQUENCY 3686400 +#define UNIMPLEMENTED panic("%s: unimplemented", __func__) + +/* XXXBJR: Belongs with DELAY in a timer.c of some sort. */ +void +cpu_startprofclock(void) +{ + UNIMPLEMENTED; +} + +void +cpu_stopprofclock(void) +{ + UNIMPLEMENTED; +} + +static struct arm32_dma_range pxa_range = { + .dr_sysbase = 0, + .dr_busbase = 0, + .dr_len = ~0u, +}; + +struct arm32_dma_range * +bus_dma_get_range(void) +{ + + return (&pxa_range); +} + +int +bus_dma_get_range_nb(void) +{ + + return (1); +} diff --git a/sys/arm/xscale/pxa/pxa_obio.c b/sys/arm/xscale/pxa/pxa_obio.c new file mode 100644 index 000000000000..00812f4ce1ce --- /dev/null +++ b/sys/arm/xscale/pxa/pxa_obio.c @@ -0,0 +1,388 @@ +/*- + * Copyright (c) 2006 Benno Rice. 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +static void pxa_identify(driver_t *, device_t); +static int pxa_probe(device_t); +static int pxa_attach(device_t); + +static int pxa_print_child(device_t, device_t); + +static int pxa_setup_intr(device_t, device_t, struct resource *, int, + driver_filter_t *, driver_intr_t *, void *, void **); +static int pxa_read_ivar(device_t, device_t, int, uintptr_t *); + +static struct resource_list * pxa_get_resource_list(device_t, device_t); +static struct resource * pxa_alloc_resource(device_t, device_t, int, + int *, u_long, u_long, u_long, u_int); +static int pxa_release_resource(device_t, device_t, int, + int, struct resource *); +static int pxa_activate_resource(device_t, device_t, + int, int, struct resource *); + +static struct resource * pxa_alloc_gpio_irq(device_t, device_t, int, + int *, u_long, u_long, u_long, u_int); + +struct obio_device { + const char *od_name; + u_long od_base; + u_long od_size; + u_int od_irqs[5]; + struct resource_list od_resources; +}; + +static struct obio_device obio_devices[] = { + { "icu", PXA2X0_INTCTL_BASE, PXA2X0_INTCTL_SIZE, { 0 } }, + { "timer", PXA2X0_OST_BASE, PXA2X0_OST_SIZE, { PXA2X0_INT_OST0, PXA2X0_INT_OST1, PXA2X0_INT_OST2, PXA2X0_INT_OST3, 0 } }, + { "dmac", PXA2X0_DMAC_BASE, PXA2X0_DMAC_SIZE, { PXA2X0_INT_DMA, 0 } }, + { "gpio", PXA2X0_GPIO_BASE, PXA250_GPIO_SIZE, { PXA2X0_INT_GPIO0, PXA2X0_INT_GPIO1, PXA2X0_INT_GPION, 0 } }, + { "uart", PXA2X0_FFUART_BASE, PXA2X0_FFUART_SIZE, { PXA2X0_INT_FFUART, 0 } }, + { "uart", PXA2X0_BTUART_BASE, PXA2X0_BTUART_SIZE, { PXA2X0_INT_BTUART, 0 } }, + { "uart", PXA2X0_STUART_BASE, PXA2X0_STUART_SIZE, { PXA2X0_INT_STUART, 0 } }, + { "uart", PXA2X0_HWUART_BASE, PXA2X0_HWUART_SIZE, { PXA2X0_INT_HWUART, 0 } }, + { "smi", PXA2X0_CS0_START, PXA2X0_CS_SIZE * 6, { 0 } }, + { NULL, 0, 0, { 0 } } +}; + +void +pxa_identify(driver_t *driver, device_t parent) +{ + + BUS_ADD_CHILD(parent, 0, "pxa", 0); +} + +int +pxa_probe(device_t dev) +{ + + device_set_desc(dev, "XScale PXA On-board IO"); + return (0); +} + +int +pxa_attach(device_t dev) +{ + struct obio_softc *sc; + struct obio_device *od; + int i; + device_t child; + + sc = device_get_softc(dev); + + sc->obio_bst = obio_tag; + + sc->obio_mem.rm_type = RMAN_ARRAY; + sc->obio_mem.rm_descr = "PXA2X0 OBIO Memory"; + if (rman_init(&sc->obio_mem) != 0) + panic("pxa_attach: failed to init obio mem rman"); + if (rman_manage_region(&sc->obio_mem, 0, PXA250_PERIPH_END) != 0) + panic("pxa_attach: failed to set up obio mem rman"); + + sc->obio_irq.rm_type = RMAN_ARRAY; + sc->obio_irq.rm_descr = "PXA2X0 OBIO IRQ"; + if (rman_init(&sc->obio_irq) != 0) + panic("pxa_attach: failed to init obio irq rman"); + if (rman_manage_region(&sc->obio_irq, 0, 31) != 0) + panic("pxa_attach: failed to set up obio irq rman (main irqs)"); + if (rman_manage_region(&sc->obio_irq, IRQ_GPIO0, IRQ_GPIO_MAX) != 0) + panic("pxa_attach: failed to set up obio irq rman (gpio irqs)"); + + for (od = obio_devices; od->od_name != NULL; od++) { + resource_list_init(&od->od_resources); + + resource_list_add(&od->od_resources, SYS_RES_MEMORY, 0, + od->od_base, od->od_base + od->od_size, od->od_size); + + for (i = 0; od->od_irqs[i] != 0; i++) { + resource_list_add(&od->od_resources, SYS_RES_IRQ, i, + od->od_irqs[i], od->od_irqs[i], 1); + } + + child = device_add_child(dev, od->od_name, -1); + device_set_ivars(child, od); + } + + bus_generic_probe(dev); + bus_generic_attach(dev); + + return (0); +} + +static int +pxa_print_child(device_t dev, device_t child) +{ + struct obio_device *od; + int retval; + + od = (struct obio_device *)device_get_ivars(child); + if (od == NULL) + panic("Unknown device on pxa0"); + + retval = 0; + + retval += bus_print_child_header(dev, child); + + retval += resource_list_print_type(&od->od_resources, "at mem", + SYS_RES_MEMORY, "0x%08lx"); + retval += resource_list_print_type(&od->od_resources, "irq", + SYS_RES_IRQ, "%ld"); + + retval += bus_print_child_footer(dev, child); + + return (retval); +} + +static int +pxa_setup_intr(device_t dev, device_t child, struct resource *irq, int flags, + driver_filter_t *filter, driver_intr_t *ithread, void *arg, void **cookiep) +{ + struct obio_softc *sc; + + sc = (struct obio_softc *)device_get_softc(dev); + + BUS_SETUP_INTR(device_get_parent(dev), child, irq, flags, filter, + ithread, arg, cookiep); + arm_unmask_irq(rman_get_start(irq)); + return (0); +} + +static int +pxa_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) +{ + struct obio_device *od; + + od = (struct obio_device *)device_get_ivars(child); + + switch (which) { + case PXA_IVAR_BASE: + *((u_long *)result) = od->od_base; + break; + + default: + return (ENOENT); + } + + return (0); +} + +static struct resource_list * +pxa_get_resource_list(device_t dev, device_t child) +{ + struct obio_device *od; + + od = (struct obio_device *)device_get_ivars(child); + + if (od == NULL) + return (NULL); + + return (&od->od_resources); +} + +static struct resource * +pxa_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 obio_softc *sc; + struct obio_device *od; + struct resource *rv; + struct resource_list *rl; + struct resource_list_entry *rle; + struct rman *rm; + int needactivate; + + sc = (struct obio_softc *)device_get_softc(dev); + od = (struct obio_device *)device_get_ivars(child); + rl = &od->od_resources; + + rle = resource_list_find(rl, type, *rid); + if (rle == NULL) { + /* We can allocate GPIO-based IRQs lazily. */ + if (type == SYS_RES_IRQ) + return (pxa_alloc_gpio_irq(dev, child, type, rid, + start, end, count, flags)); + return (NULL); + } + if (rle->res != NULL) + panic("pxa_alloc_resource: resource is busy"); + + switch (type) { + case SYS_RES_IRQ: + rm = &sc->obio_irq; + break; + + case SYS_RES_MEMORY: + rm = &sc->obio_mem; + break; + + default: + return (NULL); + } + + needactivate = flags & RF_ACTIVE; + flags &= ~RF_ACTIVE; + rv = rman_reserve_resource(rm, rle->start, rle->end, rle->count, flags, + child); + if (rv == NULL) + return (NULL); + rle->res = rv; + rman_set_rid(rv, *rid); + if (type == SYS_RES_MEMORY) { + rman_set_bustag(rv, sc->obio_bst); + rman_set_bushandle(rv, rle->start); + } + + if (needactivate) { + if (bus_activate_resource(child, type, *rid, rv)) { + rman_release_resource(rv); + return (NULL); + } + } + + return (rv); +} + +static int +pxa_release_resource(device_t dev, device_t child, int type, int rid, + struct resource *r) +{ + struct obio_device *od; + struct resource_list *rl; + struct resource_list_entry *rle; + + od = (struct obio_device *)device_get_ivars(child); + rl = &od->od_resources; + + if (type == SYS_RES_IOPORT) + type = SYS_RES_MEMORY; + + rle = resource_list_find(rl, type, rid); + + if (!rle) + panic("pxa_release_resource: can't find resource"); + if (!rle->res) + panic("pxa_release_resource: resource entry is not busy"); + + rman_release_resource(rle->res); + rle->res = NULL; + + return (0); +} + +static int +pxa_activate_resource(device_t dev, device_t child, int type, int rid, + struct resource *r) +{ + + return (rman_activate_resource(r)); +} + +static device_method_t pxa_methods[] = { + DEVMETHOD(device_identify, pxa_identify), + DEVMETHOD(device_probe, pxa_probe), + DEVMETHOD(device_attach, pxa_attach), + + DEVMETHOD(bus_print_child, pxa_print_child), + + DEVMETHOD(bus_read_ivar, pxa_read_ivar), + DEVMETHOD(bus_setup_intr, pxa_setup_intr), + + DEVMETHOD(bus_get_resource_list, pxa_get_resource_list), + DEVMETHOD(bus_alloc_resource, pxa_alloc_resource), + DEVMETHOD(bus_release_resource, pxa_release_resource), + DEVMETHOD(bus_activate_resource, pxa_activate_resource), + + {0, 0} +}; + +static driver_t pxa_driver = { + "pxa", + pxa_methods, + sizeof(struct obio_softc), +}; + +static devclass_t pxa_devclass; + +DRIVER_MODULE(pxa, nexus, pxa_driver, pxa_devclass, 0, 0); + +static struct resource * +pxa_alloc_gpio_irq(device_t dev, device_t child, int type, int *rid, + u_long start, u_long end, u_long count, u_int flags) +{ + struct obio_softc *sc; + struct obio_device *od; + struct resource_list *rl; + struct resource_list_entry *rle; + struct resource *rv; + struct rman *rm; + int needactivate; + + sc = device_get_softc(dev); + od = device_get_ivars(child); + rl = &od->od_resources; + rm = &sc->obio_irq; + + needactivate = flags & RF_ACTIVE; + flags &= ~RF_ACTIVE; + rv = rman_reserve_resource(rm, start, end, count, flags, child); + if (rv == NULL) + return (NULL); + + resource_list_add(rl, type, *rid, start, end, count); + rle = resource_list_find(rl, type, *rid); + if (rle == NULL) + panic("pxa_alloc_gpio_irq: unexpectedly can't find resource"); + + rle->res = rv; + rle->start = rman_get_start(rv); + rle->end = rman_get_end(rv); + rle->count = count; + + if (needactivate) { + if (bus_activate_resource(child, type, *rid, rv)) { + rman_release_resource(rv); + return (NULL); + } + } + + if (bootverbose) + device_printf(dev, "lazy allocation of irq %ld for %s\n", + start, device_get_nameunit(child)); + + return (rv); +} diff --git a/sys/arm/xscale/pxa/pxa_smi.c b/sys/arm/xscale/pxa/pxa_smi.c new file mode 100644 index 000000000000..b2b904c01253 --- /dev/null +++ b/sys/arm/xscale/pxa/pxa_smi.c @@ -0,0 +1,355 @@ +/*- + * Copyright (c) 2006 Benno Rice. 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +MALLOC_DEFINE(M_PXASMI, "PXA SMI", "Data for static memory interface devices."); + +struct pxa_smi_softc { + struct resource *ps_res[1]; + struct rman ps_mem; + bus_space_tag_t ps_bst; + bus_addr_t ps_base; +}; + +struct smi_ivars { + struct resource_list smid_resources; + bus_addr_t smid_mem; +}; + +static struct resource_spec pxa_smi_spec[] = { + { SYS_RES_MEMORY, 0, RF_ACTIVE }, + { -1, 0 } +}; + +static int pxa_smi_probe(device_t); +static int pxa_smi_attach(device_t); + +static int pxa_smi_print_child(device_t, device_t); + +static int pxa_smi_read_ivar(device_t, device_t, int, uintptr_t *); + +static struct resource * pxa_smi_alloc_resource(device_t, device_t, + int, int *, u_long, u_long, u_long, u_int); +static int pxa_smi_release_resource(device_t, device_t, + int, int, struct resource *); +static int pxa_smi_activate_resource(device_t, device_t, + int, int, struct resource *); + +static void pxa_smi_add_device(device_t, const char *, int); + +static int +pxa_smi_probe(device_t dev) +{ + + if (resource_disabled("smi", device_get_unit(dev))) + return (ENXIO); + + device_set_desc(dev, "Static Memory Interface"); + return (0); +} + +static int +pxa_smi_attach(device_t dev) +{ + int error, i, dunit; + const char *dname; + struct pxa_smi_softc *sc; + + sc = (struct pxa_smi_softc *)device_get_softc(dev); + + error = bus_alloc_resources(dev, pxa_smi_spec, sc->ps_res); + if (error) { + device_printf(dev, "could not allocate resources\n"); + return (ENXIO); + } + + sc->ps_mem.rm_type = RMAN_ARRAY; + sc->ps_mem.rm_descr = device_get_nameunit(dev); + if (rman_init(&sc->ps_mem) != 0) + panic("pxa_smi_attach: failed to init mem rman"); + if (rman_manage_region(&sc->ps_mem, 0, PXA2X0_CS_SIZE * 6) != 0) + panic("pxa_smi_attach: failed ot set up mem rman"); + + sc->ps_bst = base_tag; + sc->ps_base = rman_get_start(sc->ps_res[0]); + + i = 0; + while (resource_find_match(&i, &dname, &dunit, "at", + device_get_nameunit(dev)) == 0) { + pxa_smi_add_device(dev, dname, dunit); + } + + bus_generic_probe(dev); + bus_generic_attach(dev); + + return (0); +} + +static int +pxa_smi_print_child(device_t dev, device_t child) +{ + struct smi_ivars *smid; + int retval; + + smid = (struct smi_ivars *)device_get_ivars(child); + if (smid == NULL) { + device_printf(dev, "unknown device: %s\n", + device_get_nameunit(child)); + return (0); + } + + retval = 0; + + retval += bus_print_child_header(dev, child); + + retval += resource_list_print_type(&smid->smid_resources, "at mem", + SYS_RES_MEMORY, "%#lx"); + retval += resource_list_print_type(&smid->smid_resources, "irq", + SYS_RES_IRQ, "%ld"); + + retval += bus_print_child_footer(dev, child); + + return (retval); +} + +static int +pxa_smi_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) +{ + struct pxa_smi_softc *sc; + struct smi_ivars *smid; + + sc = device_get_softc(dev); + smid = device_get_ivars(child); + + switch (which) { + case SMI_IVAR_PHYSBASE: + *((bus_addr_t *)result) = smid->smid_mem; + break; + + default: + return (ENOENT); + } + + return (0); +} + +static struct resource * +pxa_smi_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 pxa_smi_softc *sc; + struct smi_ivars *smid; + struct resource *rv; + struct resource_list *rl; + struct resource_list_entry *rle; + int needactivate; + + sc = (struct pxa_smi_softc *)device_get_softc(dev); + smid = (struct smi_ivars *)device_get_ivars(child); + rl = &smid->smid_resources; + + if (type == SYS_RES_IOPORT) + type = SYS_RES_MEMORY; + + rle = resource_list_find(rl, type, *rid); + if (rle == NULL) + return (NULL); + if (rle->res != NULL) + panic("pxa_smi_alloc_resource: resource is busy"); + + needactivate = flags & RF_ACTIVE; + flags &= ~RF_ACTIVE; + + switch (type) { + case SYS_RES_MEMORY: + rv = rman_reserve_resource(&sc->ps_mem, rle->start, rle->end, + rle->count, flags, child); + if (rv == NULL) + return (NULL); + rle->res = rv; + rman_set_rid(rv, *rid); + rman_set_bustag(rv, sc->ps_bst); + rman_set_bushandle(rv, rle->start); + if (needactivate) { + if (bus_activate_resource(child, type, *rid, rv) != 0) { + rman_release_resource(rv); + return (NULL); + } + } + + break; + + case SYS_RES_IRQ: + rv = bus_alloc_resource(dev, type, rid, rle->start, rle->end, + rle->count, flags); + if (rv == NULL) + return (NULL); + if (needactivate) { + if (bus_activate_resource(child, type, *rid, rv) != 0) { + bus_release_resource(dev, type, *rid, rv); + return (NULL); + } + } + + break; + + default: + return (NULL); + } + + return (rv); +} + +static int +pxa_smi_release_resource(device_t dev, device_t child, int type, int rid, + struct resource *r) +{ + struct smi_ivars *smid; + struct resource_list *rl; + struct resource_list_entry *rle; + + if (type == SYS_RES_IRQ) + return (bus_release_resource(dev, SYS_RES_IRQ, rid, r)); + + smid = (struct smi_ivars *)device_get_ivars(child); + rl = &smid->smid_resources; + + if (type == SYS_RES_IOPORT) + type = SYS_RES_MEMORY; + + rle = resource_list_find(rl, type, rid); + if (rle == NULL) + panic("pxa_smi_release_resource: can't find resource"); + if (rle->res == NULL) + panic("pxa_smi_release_resource: resource entry not busy"); + + rman_release_resource(rle->res); + rle->res = NULL; + + return (0); +} + +static int +pxa_smi_activate_resource(device_t dev, device_t child, int type, int rid, + struct resource *r) +{ + struct pxa_smi_softc *sc; + + sc = (struct pxa_smi_softc *)device_get_softc(dev); + + if (type == SYS_RES_IRQ) + return (bus_activate_resource(dev, SYS_RES_IRQ, rid, r)); + + rman_set_bushandle(r, (bus_space_handle_t)pmap_mapdev(rman_get_start(r), + rman_get_size(r))); + return (rman_activate_resource(r)); +} + +static device_method_t pxa_smi_methods[] = { + DEVMETHOD(device_probe, pxa_smi_probe), + DEVMETHOD(device_attach, pxa_smi_attach), + + DEVMETHOD(bus_print_child, pxa_smi_print_child), + + DEVMETHOD(bus_read_ivar, pxa_smi_read_ivar), + + DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), + + DEVMETHOD(bus_alloc_resource, pxa_smi_alloc_resource), + DEVMETHOD(bus_release_resource, pxa_smi_release_resource), + DEVMETHOD(bus_activate_resource, pxa_smi_activate_resource), + + {0, 0} +}; + +static driver_t pxa_smi_driver = { + "smi", + pxa_smi_methods, + sizeof(struct pxa_smi_softc), +}; + +static devclass_t pxa_smi_devclass; + +DRIVER_MODULE(smi, pxa, pxa_smi_driver, pxa_smi_devclass, 0, 0); + +static void +pxa_smi_add_device(device_t dev, const char *name, int unit) +{ + device_t child; + int start, count; + struct smi_ivars *ivars; + + ivars = (struct smi_ivars *)malloc( + sizeof(struct smi_ivars), M_PXASMI, M_WAITOK); + if (ivars == NULL) + return; + + child = device_add_child(dev, name, unit); + if (child == NULL) { + free(ivars, M_PXASMI); + return; + } + + device_set_ivars(child, ivars); + resource_list_init(&ivars->smid_resources); + + start = 0; + count = 0; + resource_int_value(name, unit, "mem", &start); + resource_int_value(name, unit, "size", &count); + if (start > 0 || count > 0) { + resource_list_add(&ivars->smid_resources, SYS_RES_MEMORY, 0, + start, start + count, count); + ivars->smid_mem = (bus_addr_t)start; + } + + start = -1; + count = 0; + resource_int_value(name, unit, "irq", &start); + if (start > -1) + resource_list_add(&ivars->smid_resources, SYS_RES_IRQ, 0, start, + start, 1); + + if (resource_disabled(name, unit)) + device_disable(child); +} diff --git a/sys/arm/xscale/pxa/pxa_space.c b/sys/arm/xscale/pxa/pxa_space.c new file mode 100644 index 000000000000..512ac0651c52 --- /dev/null +++ b/sys/arm/xscale/pxa/pxa_space.c @@ -0,0 +1,329 @@ +/* $NetBSD: obio_space.c,v 1.6 2003/07/15 00:25:05 lukem Exp $ */ + +/*- + * Copyright (c) 2001, 2002, 2003 Wasabi Systems, Inc. + * All rights reserved. + * + * Written by Jason R. Thorpe for Wasabi Systems, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed for the NetBSD Project by + * Wasabi Systems, Inc. + * 4. The name of Wasabi Systems, Inc. may not be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * bus_space functions for PXA devices + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include + +#include +#include + +MALLOC_DEFINE(M_PXATAG, "PXA bus_space tags", "Bus_space tags for PXA"); + +/* Prototypes for all the bus_space structure functions */ +bs_protos(obio); +bs_protos(generic); +bs_protos(generic_armv4); +bs_protos(pxa); + +/* + * The obio bus space tag. This is constant for all instances, so + * we never have to explicitly "create" it. + */ +struct bus_space _base_tag = { + /* cookie */ + (void *) 0, + + /* mapping/unmapping */ + obio_bs_map, + obio_bs_unmap, + obio_bs_subregion, + + /* allocation/deallocation */ + obio_bs_alloc, + obio_bs_free, + + /* barrier */ + obio_bs_barrier, + + /* read (single) */ + pxa_bs_r_1, + pxa_bs_r_2, + pxa_bs_r_4, + NULL, + + /* read multiple */ + pxa_bs_rm_1, + pxa_bs_rm_2, + NULL, + NULL, + + /* read region */ + pxa_bs_rr_1, + NULL, + NULL, + NULL, + + /* write (single) */ + pxa_bs_w_1, + pxa_bs_w_2, + pxa_bs_w_4, + NULL, + + /* write multiple */ + pxa_bs_wm_1, + pxa_bs_wm_2, + NULL, + NULL, + + /* write region */ + NULL, + NULL, + NULL, + NULL, + + /* set multiple */ + NULL, + NULL, + NULL, + NULL, + + /* set region */ + NULL, + NULL, + NULL, + NULL, + + /* copy */ + NULL, + NULL, + NULL, + NULL, +}; + +static struct bus_space _obio_tag; + +bus_space_tag_t base_tag = &_base_tag; +bus_space_tag_t obio_tag = NULL; + +void +pxa_obio_tag_init() +{ + + bcopy(&_base_tag, &_obio_tag, sizeof(struct bus_space)); + _obio_tag.bs_cookie = (void *)PXA2X0_PERIPH_OFFSET; + obio_tag = &_obio_tag; +} + +bus_space_tag_t +pxa_bus_tag_alloc(bus_addr_t offset) +{ + struct bus_space *tag; + + tag = (struct bus_space *)malloc(sizeof(struct bus_space), M_PXATAG, + M_WAITOK); + if (tag == NULL) { + return (NULL); + } + + bcopy(&_base_tag, tag, sizeof(struct bus_space)); + tag->bs_cookie = (void *)offset; + + return ((bus_space_tag_t)tag); +} + +int +obio_bs_map(void *t, bus_addr_t bpa, bus_size_t size, int flags, + bus_space_handle_t *bshp) +{ + const struct pmap_devmap *pd; + vm_paddr_t startpa, endpa, pa, offset; + vm_offset_t va; + pt_entry_t *pte; + + if ((pd = pmap_devmap_find_pa(bpa, size)) != NULL) { + /* Device was statically mapped. */ + *bshp = pd->pd_va + (bpa - pd->pd_pa); + return (0); + } + + endpa = round_page(bpa + size); + offset = bpa & PAGE_MASK; + startpa = trunc_page(bpa); + + va = kmem_alloc(kernel_map, endpa - startpa); + if (va == 0) + return (ENOMEM); + + *bshp = va + offset; + + for (pa = startpa; pa < endpa; pa += PAGE_SIZE, va += PAGE_SIZE) { + pmap_kenter(va, pa); + pte = vtopte(va); + *pte &= ~L2_S_CACHE_MASK; + PTE_SYNC(pte); + } + + return (0); +} + +int +obio_bs_alloc(void *t, bus_addr_t rstart, bus_addr_t rend, bus_size_t size, + bus_size_t alignment, bus_size_t boundary, int flags, bus_addr_t *bpap, + bus_space_handle_t *bshp) +{ + + panic("obio_bs_alloc(): not implemented"); +} + + +void +obio_bs_unmap(void *t, bus_space_handle_t h, bus_size_t size) +{ + vm_offset_t va, endva; + + if (pmap_devmap_find_va((vm_offset_t)t, size) != NULL) { + /* Device was statically mapped; nothing to do. */ + return; + } + + endva = round_page((vm_offset_t)t + size); + va = trunc_page((vm_offset_t)t); + + while (va < endva) { + pmap_kremove(va); + va += PAGE_SIZE; + } + kmem_free(kernel_map, va, endva - va); +} + +void +obio_bs_free(void *t, bus_space_handle_t bsh, bus_size_t size) +{ + + panic("obio_bs_free(): not implemented"); +} + +int +obio_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); +} + +void +obio_bs_barrier(void *t, bus_space_handle_t bsh, bus_size_t offset, + bus_size_t len, int flags) +{ + + /* Nothing to do. */ +} + +#define READ_SINGLE(type, proto, base) \ + type \ + proto(void *cookie, bus_space_handle_t bsh, bus_size_t offset) \ + { \ + bus_addr_t tag_offset; \ + type value; \ + tag_offset = (bus_addr_t)cookie; \ + value = base(NULL, bsh + tag_offset, offset); \ + return (value); \ + } + +READ_SINGLE(u_int8_t, pxa_bs_r_1, generic_bs_r_1) +READ_SINGLE(u_int16_t, pxa_bs_r_2, generic_armv4_bs_r_2) +READ_SINGLE(u_int32_t, pxa_bs_r_4, generic_bs_r_4) + +#undef READ_SINGLE + +#define WRITE_SINGLE(type, proto, base) \ + void \ + proto(void *cookie, bus_space_handle_t bsh, bus_size_t offset, \ + type value) \ + { \ + bus_addr_t tag_offset; \ + tag_offset = (bus_addr_t)cookie; \ + base(NULL, bsh + tag_offset, offset, value); \ + } + +WRITE_SINGLE(u_int8_t, pxa_bs_w_1, generic_bs_w_1) +WRITE_SINGLE(u_int16_t, pxa_bs_w_2, generic_armv4_bs_w_2) +WRITE_SINGLE(u_int32_t, pxa_bs_w_4, generic_bs_w_4) + +#undef WRITE_SINGLE + +#define READ_MULTI(type, proto, base) \ + void \ + proto(void *cookie, bus_space_handle_t bsh, bus_size_t offset, \ + type *dest, bus_size_t count) \ + { \ + bus_addr_t tag_offset; \ + tag_offset = (bus_addr_t)cookie; \ + base(NULL, bsh + tag_offset, offset, dest, count); \ + } + +READ_MULTI(u_int8_t, pxa_bs_rm_1, generic_bs_rm_1) +READ_MULTI(u_int16_t, pxa_bs_rm_2, generic_armv4_bs_rm_2) + +READ_MULTI(u_int8_t, pxa_bs_rr_1, generic_bs_rr_1) + +#undef READ_MULTI + +#define WRITE_MULTI(type, proto, base) \ + void \ + proto(void *cookie, bus_space_handle_t bsh, bus_size_t offset, \ + const type *src, bus_size_t count) \ + { \ + bus_addr_t tag_offset; \ + tag_offset = (bus_addr_t)cookie; \ + base(NULL, bsh + tag_offset, offset, src, count); \ + } + +WRITE_MULTI(u_int8_t, pxa_bs_wm_1, generic_bs_wm_1) +WRITE_MULTI(u_int16_t, pxa_bs_wm_2, generic_armv4_bs_wm_2) + +#undef WRITE_MULTI diff --git a/sys/arm/xscale/pxa/pxa_timer.c b/sys/arm/xscale/pxa/pxa_timer.c new file mode 100644 index 000000000000..77e68a2eb095 --- /dev/null +++ b/sys/arm/xscale/pxa/pxa_timer.c @@ -0,0 +1,317 @@ +/*- + * Copyright (c) 2006 Benno Rice. 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define PXA_TIMER_FREQUENCY 3686400 +#define PXA_TIMER_TICK (PXA_TIMER_FREQUENCY / hz) + +struct pxa_timer_softc { + struct resource * pt_res[5]; + bus_space_tag_t pt_bst; + bus_space_handle_t pt_bsh; +}; + +static struct resource_spec pxa_timer_spec[] = { + { SYS_RES_MEMORY, 0, RF_ACTIVE }, + { SYS_RES_IRQ, 0, RF_ACTIVE }, + { SYS_RES_IRQ, 1, RF_ACTIVE }, + { SYS_RES_IRQ, 2, RF_ACTIVE }, + { SYS_RES_IRQ, 3, RF_ACTIVE }, + { -1, 0 } +}; + +static struct pxa_timer_softc *timer_softc = NULL; + +static int pxa_timer_probe(device_t); +static int pxa_timer_attach(device_t); + +static driver_filter_t pxa_hardclock; + +static unsigned pxa_timer_get_timecount(struct timecounter *); + +uint32_t pxa_timer_get_osmr(int); +void pxa_timer_set_osmr(int, uint32_t); +uint32_t pxa_timer_get_oscr(void); +void pxa_timer_set_oscr(uint32_t); +uint32_t pxa_timer_get_ossr(void); +void pxa_timer_clear_ossr(uint32_t); +void pxa_timer_watchdog_enable(void); +void pxa_timer_watchdog_disable(void); +void pxa_timer_interrupt_enable(int); +void pxa_timer_interrupt_disable(int); + +static struct timecounter pxa_timer_timecounter = { + .tc_get_timecount = pxa_timer_get_timecount, + .tc_name = "OS Timer", + .tc_frequency = PXA_TIMER_FREQUENCY, + .tc_counter_mask = ~0u, + .tc_quality = 1000, +}; + +static int +pxa_timer_probe(device_t dev) +{ + + device_set_desc(dev, "OS Timer"); + return (0); +} + +static int +pxa_timer_attach(device_t dev) +{ + int error; + void *ihl; + struct pxa_timer_softc *sc; + + sc = (struct pxa_timer_softc *)device_get_softc(dev); + + if (timer_softc != NULL) + return (ENXIO); + + error = bus_alloc_resources(dev, pxa_timer_spec, sc->pt_res); + if (error) { + device_printf(dev, "could not allocate resources\n"); + return (ENXIO); + } + + sc->pt_bst = rman_get_bustag(sc->pt_res[0]); + sc->pt_bsh = rman_get_bushandle(sc->pt_res[0]); + + timer_softc = sc; + + pxa_timer_interrupt_disable(-1); + pxa_timer_watchdog_disable(); + + if (bus_setup_intr(dev, sc->pt_res[1], INTR_TYPE_CLK, + pxa_hardclock, NULL, NULL, &ihl) != 0) { + bus_release_resources(dev, pxa_timer_spec, sc->pt_res); + device_printf(dev, "could not setup hardclock interrupt\n"); + return (ENXIO); + } + + return (0); +} + +static int +pxa_hardclock(void *arg) +{ + struct trapframe *frame; + + frame = (struct trapframe *)arg; + + /* Clear the interrupt */ + pxa_timer_clear_ossr(OST_SR_CH0); + + /* Schedule next tick */ + pxa_timer_set_osmr(0, pxa_timer_get_oscr() + PXA_TIMER_TICK); + + /* Do what we came here for */ + hardclock(TRAPF_USERMODE(frame), TRAPF_PC(frame)); + + return (FILTER_HANDLED); +} + +static device_method_t pxa_timer_methods[] = { + DEVMETHOD(device_probe, pxa_timer_probe), + DEVMETHOD(device_attach, pxa_timer_attach), + + {0, 0} +}; + +static driver_t pxa_timer_driver = { + "timer", + pxa_timer_methods, + sizeof(struct pxa_timer_softc), +}; + +static devclass_t pxa_timer_devclass; + +DRIVER_MODULE(pxatimer, pxa, pxa_timer_driver, pxa_timer_devclass, 0, 0); + +static unsigned +pxa_timer_get_timecount(struct timecounter *tc) +{ + + return (pxa_timer_get_oscr()); +} + +void +cpu_initclocks(void) +{ + + pxa_timer_set_oscr(0); + pxa_timer_set_osmr(0, PXA_TIMER_TICK); + pxa_timer_interrupt_enable(0); + + tc_init(&pxa_timer_timecounter); +} + +void +cpu_reset(void) +{ + uint32_t val; + + (void)disable_interrupts(I32_bit|F32_bit); + + val = pxa_timer_get_oscr(); + val += PXA_TIMER_FREQUENCY; + pxa_timer_set_osmr(3, val); + pxa_timer_watchdog_enable(); + + for(;;); +} + +void +DELAY(int usec) +{ + uint32_t val; + + if (timer_softc == NULL) { + for (; usec > 0; usec--) + for (val = 100; val > 0; val--) + ; + return; + } + + val = pxa_timer_get_oscr(); + val += (PXA_TIMER_FREQUENCY * usec) / 1000000; + while (pxa_timer_get_oscr() <= val); +} + +uint32_t +pxa_timer_get_osmr(int which) +{ + + return (bus_space_read_4(timer_softc->pt_bst, + timer_softc->pt_bsh, which * 0x4)); +} + +void +pxa_timer_set_osmr(int which, uint32_t val) +{ + + bus_space_write_4(timer_softc->pt_bst, + timer_softc->pt_bsh, which * 0x4, val); +} + +uint32_t +pxa_timer_get_oscr() +{ + + return (bus_space_read_4(timer_softc->pt_bst, + timer_softc->pt_bsh, OST_CR)); +} + +void +pxa_timer_set_oscr(uint32_t val) +{ + + bus_space_write_4(timer_softc->pt_bst, + timer_softc->pt_bsh, OST_CR, val); +} + +uint32_t +pxa_timer_get_ossr() +{ + + return (bus_space_read_4(timer_softc->pt_bst, + timer_softc->pt_bsh, OST_SR)); +} + +void +pxa_timer_clear_ossr(uint32_t val) +{ + + bus_space_write_4(timer_softc->pt_bst, + timer_softc->pt_bsh, OST_SR, val); +} + +void +pxa_timer_watchdog_enable() +{ + + bus_space_write_4(timer_softc->pt_bst, + timer_softc->pt_bsh, OST_WR, 0x1); +} + +void +pxa_timer_watchdog_disable() +{ + + bus_space_write_4(timer_softc->pt_bst, + timer_softc->pt_bsh, OST_WR, 0x0); +} + +void +pxa_timer_interrupt_enable(int which) +{ + uint32_t oier; + + if (which == -1) { + bus_space_write_4(timer_softc->pt_bst, + timer_softc->pt_bsh, OST_IR, 0xf); + return; + } + + oier = bus_space_read_4(timer_softc->pt_bst, + timer_softc->pt_bsh, OST_IR); + oier |= 1 << which; + bus_space_write_4(timer_softc->pt_bst, + timer_softc->pt_bsh, OST_IR, oier); +} + +void +pxa_timer_interrupt_disable(int which) +{ + uint32_t oier; + + if (which == -1) { + bus_space_write_4(timer_softc->pt_bst, + timer_softc->pt_bsh, OST_IR, 0); + } + + oier = bus_space_read_4(timer_softc->pt_bst, + timer_softc->pt_bsh, OST_IR); + oier &= ~(1 << which); + bus_space_write_4(timer_softc->pt_bst, + timer_softc->pt_bsh, OST_IR, oier); +} diff --git a/sys/arm/xscale/pxa/pxareg.h b/sys/arm/xscale/pxa/pxareg.h new file mode 100644 index 000000000000..bdd70c0d1567 --- /dev/null +++ b/sys/arm/xscale/pxa/pxareg.h @@ -0,0 +1,759 @@ +/* $NetBSD: pxa2x0reg.h,v 1.9 2006/04/10 04:13:58 simonb Exp $ */ + +/* + * Copyright (c) 2002 Genetec Corporation. All rights reserved. + * Written by Hiroyuki Bessho for Genetec Corporation. + * + * 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 for the NetBSD Project by + * Genetec Corporation. + * 4. The name of Genetec Corporation may not be used to endorse or + * promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY GENETEC CORPORATION ``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 GENETEC CORPORATION + * 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$ + */ + + +/* + * Intel PXA2[15]0 processor is XScale based integrated CPU + * + * Reference: + * Intel(r) PXA250 and PXA210 Application Processors + * Developer's Manual + * (278522-001.pdf) + */ +#ifndef _ARM_XSCALE_PXAREG_H_ +#define _ARM_XSCALE_PXAREG_H_ + +/* Borrow some register definitions from sa11x0 */ +#include + +#ifndef _LOCORE +#include /* for uint32_t */ +#endif + +/* + * Chip select domains + */ +#define PXA2X0_CS0_START 0x00000000 +#define PXA2X0_CS1_START 0x04000000 +#define PXA2X0_CS2_START 0x08000000 +#define PXA2X0_CS3_START 0x0c000000 +#define PXA2X0_CS4_START 0x10000000 +#define PXA2X0_CS5_START 0x14000000 +#define PXA2X0_CS_SIZE 0x04000000 + +#define PXA2X0_PCMCIA_SLOT0 0x20000000 +#define PXA2X0_PCMCIA_SLOT1 0x30000000 + +#define PXA2X0_PERIPH_START 0x40000000 +/* #define PXA2X0_MEMCTL_START 0x48000000 */ +#define PXA270_PERIPH_END 0x530fffff +#define PXA250_PERIPH_END 0x480fffff +#define PXA2X0_PERIPH_OFFSET 0xa8000000 + +#define PXA2X0_SDRAM0_START 0xa0000000 +#define PXA2X0_SDRAM1_START 0xa4000000 +#define PXA2X0_SDRAM2_START 0xa8000000 +#define PXA2X0_SDRAM3_START 0xac000000 +#define PXA2X0_SDRAM_BANKS 4 +#define PXA2X0_SDRAM_BANK_SIZE 0x04000000 + +/* + * Physical address of integrated peripherals + */ + +#define PXA2X0_DMAC_BASE 0x40000000 +#define PXA2X0_DMAC_SIZE 0x300 +#define PXA2X0_FFUART_BASE 0x40100000 /* Full Function UART */ +#define PXA2X0_FFUART_SIZE 0x20 +#define PXA2X0_BTUART_BASE 0x40200000 /* Bluetooth UART */ +#define PXA2X0_BTUART_SIZE 0x24 +#define PXA2X0_I2C_BASE 0x40300000 +#define PXA2X0_I2C_SIZE 0x000016a4 +#define PXA2X0_I2S_BASE 0x40400000 +#define PXA2X0_AC97_BASE 0x40500000 +#define PXA2X0_AC97_SIZE 0x600 +#define PXA2X0_USBDC_BASE 0x40600000 /* USB Client */ +#define PXA2X0_USBDC_SIZE 0x0e04 +#define PXA2X0_STUART_BASE 0x40700000 /* Standard UART */ +#define PXA2X0_STUART_SIZE 0x24 +#define PXA2X0_ICP_BASE 0x40800000 +#define PXA2X0_RTC_BASE 0x40900000 +#define PXA2X0_RTC_SIZE 0x10 +#define PXA2X0_OST_BASE 0x40a00000 /* OS Timer */ +#define PXA2X0_OST_SIZE 0x20 +#define PXA2X0_PWM0_BASE 0x40b00000 +#define PXA2X0_PWM1_BASE 0x40c00000 +#define PXA2X0_INTCTL_BASE 0x40d00000 /* Interrupt controller */ +#define PXA2X0_INTCTL_SIZE 0x20 +#define PXA2X0_GPIO_BASE 0x40e00000 + +#define PXA270_GPIO_SIZE 0x150 +#define PXA250_GPIO_SIZE 0x70 +#define PXA2X0_POWMAN_BASE 0x40f00000 /* Power management */ +#define PXA2X0_SSP_BASE 0x41000000 +#define PXA2X0_MMC_BASE 0x41100000 /* MultiMediaCard */ +#define PXA2X0_MMC_SIZE 0x48 +#define PXA2X0_CLKMAN_BASE 0x41300000 /* Clock Manager */ +#define PXA2X0_CLKMAN_SIZE 12 +#define PXA2X0_HWUART_BASE 0x41600000 /* Hardware UART */ +#define PXA2X0_HWUART_SIZE 0x30 +#define PXA2X0_LCDC_BASE 0x44000000 /* LCD Controller */ +#define PXA2X0_LCDC_SIZE 0x220 +#define PXA2X0_MEMCTL_BASE 0x48000000 /* Memory Controller */ +#define PXA2X0_MEMCTL_SIZE 0x48 +#define PXA2X0_USBH_BASE 0x4c000000 /* USB Host controller */ +#define PXA2X0_USBH_SIZE 0x70 + +/* Internal SRAM storage. PXA27x only */ +#define PXA270_SRAM0_START 0x5c000000 +#define PXA270_SRAM1_START 0x5c010000 +#define PXA270_SRAM2_START 0x5c020000 +#define PXA270_SRAM3_START 0x5c030000 +#define PXA270_SRAM_BANKS 4 +#define PXA270_SRAM_BANK_SIZE 0x00010000 + +/* width of interrupt controller */ +#define ICU_LEN 32 /* but [0..7,15,16] is not used */ +#define ICU_INT_HWMASK 0xffffff00 +#define PXA250_IRQ_MIN 8 /* 0..7 are not used by integrated + peripherals */ +#define PXA270_IRQ_MIN 0 + +#define PXA2X0_INT_USBH1 3 /* USB host (OHCI) */ + +#define PXA2X0_INT_HWUART 7 +#define PXA2X0_INT_GPIO0 8 +#define PXA2X0_INT_GPIO1 9 +#define PXA2X0_INT_GPION 10 /* irq from GPIO[2..80] */ +#define PXA2X0_INT_USB 11 +#define PXA2X0_INT_PMU 12 +#define PXA2X0_INT_I2S 13 +#define PXA2X0_INT_AC97 14 +#define PXA2X0_INT_LCD 17 +#define PXA2X0_INT_I2C 18 +#define PXA2X0_INT_ICP 19 +#define PXA2X0_INT_STUART 20 +#define PXA2X0_INT_BTUART 21 +#define PXA2X0_INT_FFUART 22 +#define PXA2X0_INT_MMC 23 +#define PXA2X0_INT_SSP 24 +#define PXA2X0_INT_DMA 25 +#define PXA2X0_INT_OST0 26 +#define PXA2X0_INT_OST1 27 +#define PXA2X0_INT_OST2 28 +#define PXA2X0_INT_OST3 29 +#define PXA2X0_INT_RTCHZ 30 +#define PXA2X0_INT_ALARM 31 /* RTC Alarm interrupt */ + +/* DMAC */ +#define DMAC_N_CHANNELS 16 +#define DMAC_N_PRIORITIES 3 + +#define DMAC_DCSR(n) ((n)*4) +#define DCSR_BUSERRINTR (1<<0) /* bus error interrupt */ +#define DCSR_STARTINTR (1<<1) /* start interrupt */ +#define DCSR_ENDINTR (1<<2) /* end interrupt */ +#define DCSR_STOPSTATE (1<<3) /* channel is not running */ +#define DCSR_REQPEND (1<<8) /* request pending */ +#define DCSR_STOPIRQEN (1<<29) /* stop interrupt enable */ +#define DCSR_NODESCFETCH (1<<30) /* no-descriptor fetch mode */ +#define DCSR_RUN (1<<31) +#define DMAC_DINT 0x00f0 /* DAM interrupt */ +#define DMAC_DINT_MASK 0xffffu +#define DMAC_DRCMR(n) (0x100+(n)*4) /* Channel map register */ +#define DRCMR_CHLNUM 0x0f /* channel number */ +#define DRCMR_MAPVLD (1<<7) /* map valid */ +#define DMAC_DDADR(n) (0x0200+(n)*16) +#define DDADR_STOP (1<<0) +#define DMAC_DSADR(n) (0x0204+(n)*16) +#define DMAC_DTADR(n) (0x0208+(n)*16) +#define DMAC_DCMD(n) (0x020c+(n)*16) +#define DCMD_LENGTH_MASK 0x1fff +#define DCMD_WIDTH_SHIFT 14 +#define DCMD_WIDTH_0 (0< + +struct obio_softc { + bus_space_tag_t obio_bst; /* bus space tag */ + struct rman obio_mem; + struct rman obio_irq; +}; + +extern bus_space_tag_t base_tag; +extern bus_space_tag_t obio_tag; +void pxa_obio_tag_init(void); +bus_space_tag_t pxa_bus_tag_alloc(bus_addr_t); + +uint32_t pxa_gpio_get_function(int); +uint32_t pxa_gpio_set_function(int, uint32_t); +int pxa_gpio_setup_intrhandler(const char *, driver_filter_t *, + driver_intr_t *, void *, int, int, void **); +void pxa_gpio_mask_irq(int); +void pxa_gpio_unmask_irq(int); +int pxa_gpio_get_next_irq(void); + +struct dmac_channel; + +struct dmac_descriptor { + uint32_t ddadr; + uint32_t dsadr; + uint32_t dtadr; + uint32_t dcmd; +}; +#define DMACD_SET_DESCRIPTOR(d, dadr) do { d->ddadr = dadr; } while (0) +#define DMACD_SET_SOURCE(d, sadr) do { d->dsadr = sadr; } while (0) +#define DMACD_SET_TARGET(d, tadr) do { d->dtadr = tadr; } while (0) +#define DMACD_SET_COMMAND(d, cmd) do { d->dcmd = cmd; } while (0) + +#define DMAC_PRIORITY_HIGHEST 1 +#define DMAC_PRIORITY_HIGH 2 +#define DMAC_PRIORITY_LOW 3 + +int pxa_dmac_alloc(int, struct dmac_channel **, int); +void pxa_dmac_release(struct dmac_channel *); +int pxa_dmac_transfer(struct dmac_channel *, bus_addr_t); +int pxa_dmac_transfer_single(struct dmac_channel *, + bus_addr_t, bus_addr_t, uint32_t); +int pxa_dmac_transfer_done(struct dmac_channel *); +int pxa_dmac_transfer_failed(struct dmac_channel *); + +enum pxa_device_ivars { + PXA_IVAR_BASE, +}; + +enum smi_device_ivars { + SMI_IVAR_PHYSBASE, +}; + +#define PXA_ACCESSOR(var, ivar, type) \ + __BUS_ACCESSOR(pxa, var, PXA, ivar, type) + +PXA_ACCESSOR(base, BASE, u_long) + +#undef PXA_ACCESSOR + +#define SMI_ACCESSOR(var, ivar, type) \ + __BUS_ACCESSOR(smi, var, SMI, ivar, type) + +SMI_ACCESSOR(physbase, PHYSBASE, bus_addr_t) + +#undef CSR_ACCESSOR + +#endif /* _PXAVAR_H_ */ diff --git a/sys/arm/xscale/pxa/std.pxa b/sys/arm/xscale/pxa/std.pxa new file mode 100644 index 000000000000..9842b8412b0d --- /dev/null +++ b/sys/arm/xscale/pxa/std.pxa @@ -0,0 +1,9 @@ +# XScale PXA generic configuration +# $FreeBSD$ +files "../xscale/pxa/files.pxa" +include "../xscale/std.xscale" +makeoptions KERNPHYSADDR=0xa0200000 +makeoptions KERNVIRTADDR=0xc0200000 +makeoptions CONF_CFLAGS=-mcpu=xscale +options XSCALE_CACHE_READ_WRITE_ALLOCATE +options ARM_USE_SMALL_ALLOC diff --git a/sys/arm/xscale/pxa/uart_bus_pxa.c b/sys/arm/xscale/pxa/uart_bus_pxa.c new file mode 100644 index 000000000000..eab7883881b8 --- /dev/null +++ b/sys/arm/xscale/pxa/uart_bus_pxa.c @@ -0,0 +1,87 @@ +/*- + * Copyright (c) 2006 Benno Rice. 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include + +#include +#include + +#include "uart_if.h" + +#define PXA_UART_UUE 0x40 /* UART Unit Enable */ + +static int uart_pxa_probe(device_t dev); + +static device_method_t uart_pxa_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, uart_pxa_probe), + DEVMETHOD(device_attach, uart_bus_attach), + DEVMETHOD(device_detach, uart_bus_detach), + { 0, 0 } +}; + +static driver_t uart_pxa_driver = { + uart_driver_name, + uart_pxa_methods, + sizeof(struct uart_softc), +}; + +static int +uart_pxa_probe(device_t dev) +{ + bus_space_handle_t base; + struct uart_softc *sc; + + /* Check to see if the enable bit's on. */ + base = (bus_space_handle_t)pxa_get_base(dev); + if ((bus_space_read_4(obio_tag, base, + (REG_IER << 2)) & PXA_UART_UUE) == 0) + return (ENXIO); + + sc = device_get_softc(dev); + sc->sc_class = &uart_ns8250_class; + + return(uart_bus_probe(dev, 2, PXA2X0_COM_FREQ, 0, 0)); +} + +DRIVER_MODULE(uart, pxa, uart_pxa_driver, uart_devclass, 0, 0); diff --git a/sys/arm/xscale/pxa/uart_cpu_pxa.c b/sys/arm/xscale/pxa/uart_cpu_pxa.c new file mode 100644 index 000000000000..1cb4671178cc --- /dev/null +++ b/sys/arm/xscale/pxa/uart_cpu_pxa.c @@ -0,0 +1,69 @@ +/*- + * 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +bus_space_tag_t uart_bus_space_io; +bus_space_tag_t uart_bus_space_mem; + +int +uart_cpu_eqres(struct uart_bas *b1, struct uart_bas *b2) +{ + + return (b1->bsh == b2->bsh ? 1 : 0); +} + +int +uart_cpu_getdev(int devtype, struct uart_devinfo *di) +{ + + di->ops = uart_getops(&uart_ns8250_class); + di->bas.chan = 0; + di->bas.bst = obio_tag; + di->bas.regshft = 2; + di->bas.rclk = PXA2X0_COM_FREQ; + di->baudrate = 115200; + di->databits = 8; + di->stopbits = 1; + di->parity = UART_PARITY_NONE; + uart_bus_space_mem = obio_tag; + uart_bus_space_io = NULL; + di->bas.bsh = PXA2X0_FFUART_BASE; + return (0); +} diff --git a/sys/conf/options.arm b/sys/conf/options.arm index 0dea8ce34e01..484634713cab 100644 --- a/sys/conf/options.arm +++ b/sys/conf/options.arm @@ -14,6 +14,7 @@ CPU_XSCALE_80219 opt_global.h CPU_XSCALE_80321 opt_global.h CPU_XSCALE_81342 opt_global.h CPU_XSCALE_IXP425 opt_global.h +CPU_XSCALE_PXA2X0 opt_global.h FLASHADDR opt_global.h KERNPHYSADDR opt_global.h KERNVIRTADDR opt_global.h