diff --git a/sys/arch/arm/xscale/files.i80321 b/sys/arch/arm/xscale/files.i80321 new file mode 100644 index 000000000000..21982459c6fa --- /dev/null +++ b/sys/arch/arm/xscale/files.i80321 @@ -0,0 +1,17 @@ +# $NetBSD: files.i80321,v 1.1 2002/03/27 21:45:47 thorpej Exp $ +# +# Configuration info for Intel i80321 XScale I/O Processor support +# + +file arch/arm/xscale/i80321_icu.c +file arch/arm/xscale/i80321_irq.S +file arch/arm/xscale/i80321_mcu.c +file arch/arm/xscale/i80321_timer.c + +device iopxs: pcibus +# Board-specific front-end provides attachment. +file arch/arm/xscale/i80321.c iopxs +file arch/arm/xscale/i80321_pci.c iopxs +file arch/arm/xscale/i80321_pci_dma.c iopxs +file arch/arm/xscale/i80321_space.c iopxs +file arch/arm/xscale/i80321_space_asm.S iopxs diff --git a/sys/arch/arm/xscale/i80321.c b/sys/arch/arm/xscale/i80321.c new file mode 100644 index 000000000000..15cd7de4494d --- /dev/null +++ b/sys/arch/arm/xscale/i80321.c @@ -0,0 +1,228 @@ +/* $NetBSD: i80321.c,v 1.1 2002/03/27 21:45:47 thorpej Exp $ */ + +/* + * Copyright (c) 2002 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. + */ + +/* + * Autoconfiguration support for the Intel i80321 I/O Processor. + */ + +#include +#include +#include + +#include + +#include +#include + +/* + * Statically-allocated bus_space stucture used to access the + * i80321's own registers. + */ +struct bus_space i80321_bs_tag; + +/* + * There can be only one i80321, so we keep a global pointer to + * the softc, so board-specific code can use features of the + * i80321 without having to have a handle on the softc itself. + */ +struct i80321_softc *i80321_softc; + +int i80321_pcibus_print(void *, const char *); + +/* + * i80321_attach: + * + * Board-independent attach routine for the i80321. + */ +void +i80321_attach(struct i80321_softc *sc) +{ + struct pcibus_attach_args pba; + pcireg_t preg; + + i80321_softc = sc; + + /* + * Slice off some useful subregion handles. + */ + + if (bus_space_subregion(sc->sc_st, sc->sc_sh, VERDE_ATU_BASE, + VERDE_ATU_SIZE, &sc->sc_atu_sh)) + panic("%s: unable to subregion ATU registers\n", + sc->sc_dev.dv_xname); + + /* We expect the Memory Controller to be already sliced off. */ + + /* + * Program the Inbound windows. + */ + if (sc->sc_is_host) { + bus_space_write_4(sc->sc_st, sc->sc_atu_sh, + PCI_MAPREG_START, sc->sc_iwin[0].iwin_base_lo); + bus_space_write_4(sc->sc_st, sc->sc_atu_sh, + PCI_MAPREG_START + 0x04, sc->sc_iwin[0].iwin_base_hi); + } + bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_IALR0, + (0xffffffff - (sc->sc_iwin[0].iwin_size - 1)) & 0xffffffc0); + bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_IATVR0, + sc->sc_iwin[0].iwin_xlate); + + if (sc->sc_is_host) { + bus_space_write_4(sc->sc_st, sc->sc_atu_sh, + PCI_MAPREG_START + 0x08, sc->sc_iwin[1].iwin_base_lo); + bus_space_write_4(sc->sc_st, sc->sc_atu_sh, + PCI_MAPREG_START + 0x0c, sc->sc_iwin[1].iwin_base_hi); + } + bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_IALR1, + (0xffffffff - (sc->sc_iwin[1].iwin_size - 1)) & 0xffffffc0); + /* no xlate for window 1 */ + + if (sc->sc_is_host) { + bus_space_write_4(sc->sc_st, sc->sc_atu_sh, + PCI_MAPREG_START + 0x10, sc->sc_iwin[2].iwin_base_lo); + bus_space_write_4(sc->sc_st, sc->sc_atu_sh, + PCI_MAPREG_START + 0x14, sc->sc_iwin[2].iwin_base_hi); + } + bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_IALR2, + (0xffffffff - (sc->sc_iwin[2].iwin_size - 1)) & 0xffffffc0); + bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_IATVR2, + sc->sc_iwin[2].iwin_xlate); + + if (sc->sc_is_host) { + bus_space_write_4(sc->sc_st, sc->sc_atu_sh, + ATU_IABAR3, sc->sc_iwin[3].iwin_base_lo); + bus_space_write_4(sc->sc_st, sc->sc_atu_sh, + ATU_IAUBAR3, sc->sc_iwin[3].iwin_base_hi); + } + bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_IALR3, + (0xffffffff - (sc->sc_iwin[3].iwin_size - 1)) & 0xffffffc0); + bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_IATVR3, + sc->sc_iwin[3].iwin_xlate); + + /* + * Mask (disable) the ATU interrupt sources. + * XXX May want to revisit this if we encounter + * XXX an application that wants it. + */ + bus_space_write_4(sc->sc_st, sc->sc_atu_sh, + ATU_ATUIMR, + ATUIMR_IMW1BU|ATUIMR_ISCEM|ATUIMR_RSCEM|ATUIMR_PST| + ATUIMR_DPE|ATUIMR_P_SERR_ASRT|ATUIMR_PMA|ATUIMR_PTAM| + ATUIMR_PTAT|ATUIMR_PMPE); + + /* + * Program the outbound windows. + */ + bus_space_write_4(sc->sc_st, sc->sc_atu_sh, + ATU_OIOWTVR, sc->sc_ioout_xlate); + + bus_space_write_4(sc->sc_st, sc->sc_atu_sh, + ATU_OMWTVR0, sc->sc_owin[0].owin_xlate_lo); + bus_space_write_4(sc->sc_st, sc->sc_atu_sh, + ATU_OUMWTVR0, sc->sc_owin[0].owin_xlate_hi); + + bus_space_write_4(sc->sc_st, sc->sc_atu_sh, + ATU_OMWTVR1, sc->sc_owin[1].owin_xlate_lo); + bus_space_write_4(sc->sc_st, sc->sc_atu_sh, + ATU_OUMWTVR1, sc->sc_owin[1].owin_xlate_hi); + + /* + * Set up the ATU configuration register. All we do + * right now is enable Outbound Windows. + */ + bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_ATUCR, + ATUCR_OUT_EN); + + /* + * Enable bus mastering, memory access, SERR, and parity + * checking on the ATU. + */ + if (sc->sc_is_host) { + preg = bus_space_read_4(sc->sc_st, sc->sc_atu_sh, + PCI_COMMAND_STATUS_REG); + preg |= PCI_COMMAND_MEM_ENABLE | PCI_COMMAND_MASTER_ENABLE | + PCI_COMMAND_PARITY_ENABLE | PCI_COMMAND_SERR_ENABLE; + bus_space_write_4(sc->sc_st, sc->sc_atu_sh, + PCI_COMMAND_STATUS_REG, preg); + } + + /* + * Initialize the bus space and DMA tags and the PCI chipset tag. + */ + i80321_io_bs_init(&sc->sc_pci_iot, sc); + i80321_mem_bs_init(&sc->sc_pci_memt, sc); + i80321_pci_dma_init(&sc->sc_pci_dmat, sc); + i80321_pci_init(&sc->sc_pci_chipset, sc); + + /* + * Attach the PCI bus. + */ + preg = bus_space_read_4(sc->sc_st, sc->sc_atu_sh, ATU_PCIXSR); + preg = PCIXSR_BUSNO(preg); + if (preg == 0xff) + preg = 0; + pba.pba_busname = "pci"; + pba.pba_iot = &sc->sc_pci_iot; + pba.pba_memt = &sc->sc_pci_memt; + pba.pba_dmat = &sc->sc_pci_dmat; + pba.pba_pc = &sc->sc_pci_chipset; + pba.pba_bus = preg; + pba.pba_intrswiz = 0; /* XXX what if busno != 0? */ + pba.pba_intrtag = 0; + pba.pba_flags = PCI_FLAGS_IO_ENABLED | PCI_FLAGS_MEM_ENABLED | + PCI_FLAGS_MRL_OKAY | PCI_FLAGS_MRM_OKAY | PCI_FLAGS_MWI_OKAY; + (void) config_found(&sc->sc_dev, &pba, i80321_pcibus_print); +} + +/* + * i80321_pcibus_print: + * + * Autoconfiguration cfprint routine when attaching + * to the "pcibus" attribute. + */ +int +i80321_pcibus_print(void *aux, const char *pnp) +{ + struct pcibus_attach_args *pba = aux; + + if (pnp) + printf("%s at %s", pba->pba_busname, pnp); + + printf(" bus %d", pba->pba_bus); + + return (UNCONF); +} diff --git a/sys/arch/arm/xscale/i80321_icu.c b/sys/arch/arm/xscale/i80321_icu.c new file mode 100644 index 000000000000..c1c81b97bfbc --- /dev/null +++ b/sys/arch/arm/xscale/i80321_icu.c @@ -0,0 +1,516 @@ +/* $NetBSD: i80321_icu.c,v 1.1 2002/03/27 21:45:47 thorpej Exp $ */ + +/* + * Copyright (c) 2001, 2002 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. + */ + +/* + * Interrupt support for the Intel i80321 I/O Processor. + */ + +#include +#include +#include + +#include + +#include +#include + +#include + +#include +#include + +/* Interrupt handler queues. */ +struct intrq intrq[NIRQ]; + +/* Interrupts to mask at each level. */ +static int imask[NIPL]; + +/* Current interrupt priority level. */ +__volatile int current_spl_level; + +/* Interrupts pending. */ +static __volatile int ipending; + +/* Software copy of the IRQs we have enabled. */ +__volatile uint32_t intr_enabled; + +/* Mask if interrupts steered to FIQs. */ +uint32_t intr_steer; + +/* + * Map a software interrupt queue index (to the unused bits in the + * ICU registers -- XXX will need to revisit this if those bits are + * ever used in future steppings). + */ +static const uint32_t si_to_irqbit[SI_NQUEUES] = { + ICU_INT_bit26, /* SI_SOFT */ + ICU_INT_bit22, /* SI_SOFTCLOCK */ + ICU_INT_bit5, /* SI_SOFTNET */ + ICU_INT_bit4, /* SI_SOFTSERIAL */ +}; + +#define SI_TO_IRQBIT(si) (1U << si_to_irqbit[(si)]) + +/* + * Map a software interrupt queue to an interrupt priority level. + */ +static const int si_to_ipl[SI_NQUEUES] = { + IPL_SOFT, /* SI_SOFT */ + IPL_SOFTCLOCK, /* SI_SOFTCLOCK */ + IPL_SOFTNET, /* SI_SOFTNET */ + IPL_SOFTSERIAL, /* SI_SOFTSERIAL */ +}; + +void i80321_intr_dispatch(struct clockframe *frame); + +static __inline uint32_t +i80321_iintsrc_read(void) +{ + uint32_t iintsrc; + + __asm __volatile("mrc p6, 0, %0, c8, c0, 0" + : "=r" (iintsrc)); + + /* + * The IINTSRC register shows bits that are active even + * if they are masked in INTCTL, so we have to mask them + * off with the interrupts we consider enabled. + */ + return (iintsrc & intr_enabled); +} + +static __inline void +i80321_set_intrmask(void) +{ + + __asm __volatile("mcr p6, 0, %0, c0, c0, 0" + : + : "r" (intr_enabled & ICU_INT_HWMASK)); +} + +static __inline void +i80321_set_intrsteer(void) +{ + + __asm __volatile("mcr p6, 0, %0, c4, c0, 0" + : + : "r" (intr_steer & ICU_INT_HWMASK)); +} + +static __inline void +i80321_enable_irq(int irq) +{ + + intr_enabled |= (1U << irq); + i80321_set_intrmask(); +} + +static __inline void +i80321_disable_irq(int irq) +{ + + intr_enabled &= ~(1U << irq); + i80321_set_intrmask(); +} + +/* + * NOTE: This routine must be called with interrupts disabled in the CPSR. + */ +static void +i80321_intr_calculate_masks(void) +{ + struct intrq *iq; + struct intrhand *ih; + int irq, ipl; + + /* First, figure out which IPLs each IRQ has. */ + for (irq = 0; irq < NIRQ; irq++) { + int levels = 0; + iq = &intrq[irq]; + i80321_disable_irq(irq); + for (ih = TAILQ_FIRST(&iq->iq_list); ih != NULL; + ih = TAILQ_NEXT(ih, ih_list)) + levels |= (1U << ih->ih_ipl); + iq->iq_levels = levels; + } + + /* Next, figure out which IRQs are used by each IPL. */ + for (ipl = 0; ipl < NIPL; ipl++) { + int irqs = 0; + for (irq = 0; irq < NIRQ; irq++) { + if (intrq[irq].iq_levels & (1U << ipl)) + irqs |= (1U << irq); + } + imask[ipl] = irqs; + } + + imask[IPL_NONE] = 0; + + /* + * Initialize the soft interrupt masks to block themselves. + */ + imask[IPL_SOFT] = SI_TO_IRQBIT(SI_SOFT); + imask[IPL_SOFTCLOCK] = SI_TO_IRQBIT(SI_SOFTCLOCK); + imask[IPL_SOFTNET] = SI_TO_IRQBIT(SI_SOFTNET); + imask[IPL_SOFTSERIAL] = SI_TO_IRQBIT(SI_SOFTSERIAL); + + /* + * splsoftclock() is the only interface that users of the + * generic software interrupt facility have to block their + * soft intrs, so splsoftclock() must also block IPL_SOFT. + */ + imask[IPL_SOFTCLOCK] |= imask[IPL_SOFT]; + + /* + * splsoftnet() must also block splsoftclock(), since we don't + * want timer-driven network events to occur while we're + * processing incoming packets. + */ + imask[IPL_SOFTNET] |= imask[IPL_SOFTCLOCK]; + + /* + * Enforce a heirarchy that gives "slow" device (or devices with + * limited input buffer space/"real-time" requirements) a better + * chance at not dropping data. + */ + imask[IPL_BIO] |= imask[IPL_SOFTNET]; + imask[IPL_NET] |= imask[IPL_BIO]; + imask[IPL_SOFTSERIAL] |= imask[IPL_NET]; + imask[IPL_TTY] |= imask[IPL_SOFTSERIAL]; + + /* + * splvm() blocks all interrupts that use the kernel memory + * allocation facilities. + */ + imask[IPL_IMP] |= imask[IPL_TTY]; + + /* + * Audio devices are not allowed to perform memory allocation + * in their interrupt routines, and they have fairly "real-time" + * requirements, so give them a high interrupt priority. + */ + imask[IPL_AUDIO] |= imask[IPL_IMP]; + + /* + * splclock() must block anything that uses the scheduler. + */ + imask[IPL_CLOCK] |= imask[IPL_AUDIO]; + + /* + * No separate statclock on the IQ80310. + */ + imask[IPL_STATCLOCK] |= imask[IPL_CLOCK]; + + /* + * splhigh() must block "everything". + */ + imask[IPL_HIGH] |= imask[IPL_STATCLOCK]; + + /* + * XXX We need serial drivers to run at the absolute highest priority + * in order to avoid overruns, so serial > high. + */ + imask[IPL_SERIAL] |= imask[IPL_HIGH]; + + /* + * Now compute which IRQs must be blocked when servicing any + * given IRQ. + */ + for (irq = 0; irq < NIRQ; irq++) { + int irqs = (1U << irq); + iq = &intrq[irq]; + if (TAILQ_FIRST(&iq->iq_list) != NULL) + i80321_enable_irq(irq); + for (ih = TAILQ_FIRST(&iq->iq_list); ih != NULL; + ih = TAILQ_NEXT(ih, ih_list)) + irqs |= imask[ih->ih_ipl]; + iq->iq_mask = irqs; + } +} + +static void +i80321_do_pending(void) +{ + static __cpu_simple_lock_t processing = __SIMPLELOCK_UNLOCKED; + int new, oldirqstate; + + if (__cpu_simple_lock_try(&processing) == 0) + return; + + new = current_spl_level; + + oldirqstate = disable_interrupts(I32_bit); + +#define DO_SOFTINT(si) \ + if ((ipending & ~new) & SI_TO_IRQBIT(si)) { \ + ipending &= ~SI_TO_IRQBIT(si); \ + current_spl_level |= imask[si_to_ipl[(si)]]; \ + restore_interrupts(oldirqstate); \ + softintr_dispatch(si); \ + oldirqstate = disable_interrupts(I32_bit); \ + current_spl_level = new; \ + } + + DO_SOFTINT(SI_SOFTSERIAL); + DO_SOFTINT(SI_SOFTNET); + DO_SOFTINT(SI_SOFTCLOCK); + DO_SOFTINT(SI_SOFT); + + __cpu_simple_unlock(&processing); + + restore_interrupts(oldirqstate); +} + +int +_splraise(int ipl) +{ + int old, oldirqstate; + + oldirqstate = disable_interrupts(I32_bit); + old = current_spl_level; + current_spl_level |= imask[ipl]; + + restore_interrupts(oldirqstate); + + return (old); +} + +__inline void +splx(int new) +{ + int oldirqstate, hwpend; + + current_spl_level = new; + + /* + * If there are pending HW interrupts which are being + * unmasked, then enable them in the INTCTL register. + * This will cause them to come flooding in. + */ + hwpend = (ipending & ICU_INT_HWMASK) & ~new; + if (hwpend != 0) { + oldirqstate = disable_interrupts(I32_bit); + intr_enabled |= hwpend; + i80321_set_intrmask(); + restore_interrupts(oldirqstate); + } + + /* If there are software interrupts to process, do it. */ + if ((ipending & ~ICU_INT_HWMASK) & ~new) + i80321_do_pending(); +} + +int +_spllower(int ipl) +{ + int old = current_spl_level; + + splx(imask[ipl]); + return (old); +} + +void +_setsoftintr(int si) +{ + int oldirqstate; + + oldirqstate = disable_interrupts(I32_bit); + ipending |= SI_TO_IRQBIT(si); + restore_interrupts(oldirqstate); + + /* Process unmasked pending soft interrupts. */ + if ((ipending & ~ICU_INT_HWMASK) & ~current_spl_level) + i80321_do_pending(); +} + +/* + * i80321_icu_init: + * + * Initialize the i80321 ICU. Called early in bootstrap + * to make sure the ICU is in a pristine state. + */ +void +i80321_icu_init(void) +{ + + intr_enabled = 0; /* All interrupts disabled */ + i80321_set_intrmask(); + + intr_steer = 0; /* All interrupts steered to IRQ */ + i80321_set_intrsteer(); +} + +/* + * i80321_intr_init: + * + * Initialize the rest of the interrupt subsystem, making it + * ready to handle interrupts from devices. + */ +void +i80321_intr_init(void) +{ + struct intrq *iq; + int i; + + intr_enabled = 0; + + for (i = 0; i < NIRQ; i++) { + iq = &intrq[i]; + TAILQ_INIT(&iq->iq_list); + + sprintf(iq->iq_name, "irq %d", i); + evcnt_attach_dynamic(&iq->iq_ev, EVCNT_TYPE_INTR, + NULL, "iop321", iq->iq_name); + } + + i80321_intr_calculate_masks(); + + /* Enable IRQs (don't yet use FIQs). */ + enable_interrupts(I32_bit); +} + +void * +i80321_intr_establish(int irq, int ipl, int (*func)(void *), void *arg) +{ + struct intrq *iq; + struct intrhand *ih; + u_int oldirqstate; + + if (irq < 0 || irq > NIRQ) + panic("i80321_intr_establish: IRQ %d out of range", irq); + + ih = malloc(sizeof(*ih), M_DEVBUF, M_NOWAIT); + if (ih == NULL) + return (NULL); + + ih->ih_func = func; + ih->ih_arg = arg; + ih->ih_ipl = ipl; + ih->ih_irq = irq; + + iq = &intrq[irq]; + + /* All IOP321 interrupts are level-triggered. */ + iq->iq_ist = IST_LEVEL; + + oldirqstate = disable_interrupts(I32_bit); + + TAILQ_INSERT_TAIL(&iq->iq_list, ih, ih_list); + + i80321_intr_calculate_masks(); + + restore_interrupts(oldirqstate); + + return (ih); +} + +void +i80321_intr_disestablish(void *cookie) +{ + struct intrhand *ih = cookie; + struct intrq *iq = &intrq[ih->ih_irq]; + int oldirqstate; + + oldirqstate = disable_interrupts(I32_bit); + + TAILQ_REMOVE(&iq->iq_list, ih, ih_list); + + i80321_intr_calculate_masks(); + + restore_interrupts(oldirqstate); +} + +void +i80321_intr_dispatch(struct clockframe *frame) +{ + struct intrq *iq; + struct intrhand *ih; + int oldirqstate, pcpl, irq, ibit, hwpend; + + pcpl = current_spl_level; + + hwpend = i80321_iintsrc_read(); + + /* + * Disable all the interrupts that are pending. We will + * reenable them once they are processed and not masked. + */ + intr_enabled &= ~hwpend; + i80321_set_intrmask(); + + while (hwpend != 0) { + irq = ffs(hwpend) - 1; + ibit = (1U << irq); + + hwpend &= ~ibit; + + if (pcpl & ibit) { + /* + * IRQ is masked; mark it as pending and check + * the next one. Note: the IRQ is already disabled. + */ + ipending |= ibit; + continue; + } + + ipending &= ~ibit; + + iq = &intrq[irq]; + iq->iq_ev.ev_count++; + uvmexp.intrs++; + current_spl_level |= iq->iq_mask; + oldirqstate = enable_interrupts(I32_bit); + for (ih = TAILQ_FIRST(&iq->iq_list); ih != NULL; + ih = TAILQ_NEXT(ih, ih_list)) { + (void) (*ih->ih_func)(ih->ih_arg ? ih->ih_arg : frame); + } + restore_interrupts(oldirqstate); + + current_spl_level = pcpl; + + /* Re-enable this interrupt now that's it's cleared. */ + intr_enabled |= ibit; + i80321_set_intrmask(); + } + + /* Check for pendings soft intrs. */ + if ((ipending & ~ICU_INT_HWMASK) & ~current_spl_level) { + oldirqstate = enable_interrupts(I32_bit); + i80321_do_pending(); + restore_interrupts(oldirqstate); + } +} diff --git a/sys/arch/arm/xscale/i80321_irq.S b/sys/arch/arm/xscale/i80321_irq.S new file mode 100644 index 000000000000..098940c89c17 --- /dev/null +++ b/sys/arch/arm/xscale/i80321_irq.S @@ -0,0 +1,155 @@ +/* $NetBSD: i80321_irq.S,v 1.1 2002/03/27 21:45:47 thorpej Exp $ */ + +/* + * Copyright (c) 2002 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. + */ + +#include "assym.h" + +#include +#include +#include + +/* + * irq_entry: + * + * Main entry point for the IRQ vector. + */ + + .text + .align 0 + +Lcurrent_intr_depth: + .word _C_LABEL(current_intr_depth) + .word _C_LABEL(prev_intr_depth) + +Lintr_dispatch: + .word _C_LABEL(i80321_intr_dispatch) + +Lastpending: + .word _C_LABEL(astpending) + +ASENTRY_NP(irq_entry) + sub lr, lr, #0x00000004 /* Adjust the lr */ + + PUSHFRAMEINSVC /* Push an interrupt frame */ + + /* + * Note that we have entered the IRQ handler. We are + * in SVC mode so we cannot use the processor mode to + * determine if we are in an IRQ. Instead, we will + * count each time the interrupt handler is nested. + */ + ldr r0, Lcurrent_intr_depth + ldr r2, Lcurrent_intr_depth+4 + ldr r1, [r0] + str r1, [r2] + add r1, r1, #1 + str r1, [r0] + + /* + * Call the C interrupt dispatch routine. + */ + add lr, pc, #(Lirq_return - . - 8) + mov r0, sp + ldr pc, Lintr_dispatch +Lirq_return: + + /* Decremement the nest count. */ + ldr r0, Lcurrent_intr_depth + ldr r2, Lcurrent_intr_depth+4 + ldr r1, [r0] + str r1, [r2] + sub r1, r1, #1 + str r1, [r0] + + /* + * If we're returning to user mode, check for pending ASTs. + */ + ldr r0, [sp] /* Get the SPSR from stack */ + and r0, r0, #(PSR_MODE) /* Test for USR32 mode before the IRQ */ + teq r0, #(PSR_USR32_MODE) + bne Lirqout /* Nope, get out now */ + +Lastloop: + ldr r0, Lastpending /* Do we have an AST pending? */ + ldr r1, [r0] + teq r1, #0x00000000 + beq Lirqout /* Nope, get out now */ + + mov r1, #0x00000000 + str r1, [r0] /* Clear astpending */ + + mrs r4, cpsr_all /* save CPSR */ + bic r0, r4, #(I32_bit) /* Enable IRQs */ + msr cpsr_all, r0 + + mov r0, sp + bl _C_LABEL(ast) /* ast(frame) */ + + msr cpsr_all, r4 /* Disable IRQs */ + b Lastloop /* Check for more ASTs */ + +Lirqout: + PULLFRAMEFROMSVCANDEXIT + movs pc, lr /* Exit */ + + .bss + .align 0 + + .global _C_LABEL(astpending) +_C_LABEL(astpending): + .word 0 + + .global _C_LABEL(current_intr_depth) +_C_LABEL(current_intr_depth): + .word 0 + + .global _C_LABEL(prev_intr_depth) +_C_LABEL(prev_intr_depth): + .word 0 + + /* + * XXX Provide intrnames/intrcnt for legacy code, but + * don't actually use them. + */ + + .global _C_LABEL(intrnames), _C_LABEL(eintrnames) + .global _C_LABEL(intrcnt), _C_LABEL(eintrcnt) +_C_LABEL(intrnames): +_C_LABEL(eintrnames): + + .global _C_LABEL(intrcnt), _C_LABEL(sintrcnt), _C_LABEL(eintrcnt) +_C_LABEL(intrcnt): +_C_LABEL(eintrcnt): diff --git a/sys/arch/arm/xscale/i80321_mcu.c b/sys/arch/arm/xscale/i80321_mcu.c new file mode 100644 index 000000000000..8ee13cc57d37 --- /dev/null +++ b/sys/arch/arm/xscale/i80321_mcu.c @@ -0,0 +1,86 @@ +/* $NetBSD: i80321_mcu.c,v 1.1 2002/03/27 21:45:47 thorpej Exp $ */ + +/* + * Copyright (c) 2001, 2002 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. + */ + +/* + * Intel i80321 I/O Processor memory controller support. + */ + +#include +#include + +#include + +#include +#include + +/* + * i80321_sdram_bounds: + * + * Retrieve the start and size of SDRAM. + */ +void +i80321_sdram_bounds(bus_space_tag_t st, bus_space_handle_t sh, + paddr_t *start, psize_t *size) +{ + uint32_t sdbr, sbr0, sbr1; + uint32_t bank0, bank1; + + sdbr = bus_space_read_4(st, sh, MCU_SDBR); + sbr0 = bus_space_read_4(st, sh, MCU_SBR0); + sbr1 = bus_space_read_4(st, sh, MCU_SBR1); + +#ifdef VERBOSE_INIT_ARM + printf("i80321: SBDR = 0x%08x SBR0 = 0x%08x SBR1 = 0x%08x\n", + sdbr, sbr0, sbr1); +#endif + + *start = sdbr; + + sdbr = (sdbr >> 25) & 0x1f; + + sbr0 &= 0x3f; + sbr1 &= 0x3f; + + bank0 = (sbr0 - sdbr) << 25; + bank1 = (sbr1 - sbr0) << 25; + +#ifdef VERBOSE_INIT_ARM + printf("i80321: BANK0 = 0x%08x BANK1 = 0x%08x\n", bank0, bank1); +#endif + + *size = bank0 + bank1; +} diff --git a/sys/arch/arm/xscale/i80321_pci.c b/sys/arch/arm/xscale/i80321_pci.c new file mode 100644 index 000000000000..e307767752d7 --- /dev/null +++ b/sys/arch/arm/xscale/i80321_pci.c @@ -0,0 +1,252 @@ +/* $NetBSD: i80321_pci.c,v 1.1 2002/03/27 21:45:47 thorpej Exp $ */ + +/* + * Copyright (c) 2001, 2002 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. + */ + +/* + * PCI configuration support for i80321 I/O Processor chip. + */ + +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include + +#include +#include + +#include "opt_pci.h" +#include "pci.h" + +void i80321_pci_attach_hook(struct device *, struct device *, + struct pcibus_attach_args *); +int i80321_pci_bus_maxdevs(void *, int); +pcitag_t i80321_pci_make_tag(void *, int, int, int); +void i80321_pci_decompose_tag(void *, pcitag_t, int *, int *, + int *); +pcireg_t i80321_pci_conf_read(void *, pcitag_t, int); +void i80321_pci_conf_write(void *, pcitag_t, int, pcireg_t); + +#define PCI_CONF_LOCK(s) (s) = disable_interrupts(I32_bit) +#define PCI_CONF_UNLOCK(s) restore_interrupts((s)) + +void +i80321_pci_init(pci_chipset_tag_t pc, void *cookie) +{ +#if NPCI > 0 && defined(PCI_NETBSD_CONFIGURE) + struct i80321_softc *sc = cookie; + struct extent *ioext, *memext; + uint32_t busno; +#endif + + pc->pc_conf_v = cookie; + pc->pc_attach_hook = i80321_pci_attach_hook; + pc->pc_bus_maxdevs = i80321_pci_bus_maxdevs; + pc->pc_make_tag = i80321_pci_make_tag; + pc->pc_decompose_tag = i80321_pci_decompose_tag; + pc->pc_conf_read = i80321_pci_conf_read; + pc->pc_conf_write = i80321_pci_conf_write; + +#if NPCI > 0 && defined(PCI_NETBSD_CONFIGURE) + /* + * Configure the PCI bus. + * + * XXX We need to revisit this. We only configure the Secondary + * bus (and its children). The bus configure code needs changes + * to support how the busses are arranged on this chip. We also + * need to only configure devices in the private device space on + * the Secondary bus. + */ + + busno = bus_space_read_4(sc->sc_st, sc->sc_atu_sh, ATU_PCIXSR); + busno = PCIXSR_BUSNO(busno); + if (busno == 0xff) + busno = 0; + + ioext = extent_create("pciio", sc->sc_ioout_xlate, + sc->sc_ioout_xlate + VERDE_OUT_XLATE_IO_WIN_SIZE - 1, + M_DEVBUF, NULL, 0, EX_NOWAIT); + memext = extent_create("pcimem", sc->sc_owin[0].owin_xlate_lo, + sc->sc_owin[0].owin_xlate_lo + VERDE_OUT_XLATE_MEM_WIN_SIZE - 1, + M_DEVBUF, NULL, 0, EX_NOWAIT); + + printf("%s: configuring PCI bus\n", sc->sc_dev.dv_xname); + pci_configure_bus(pc, ioext, memext, NULL, busno, arm_dcache_align); + + extent_destroy(ioext); + extent_destroy(memext); +#endif +} + +void +pci_conf_interrupt(pci_chipset_tag_t pc, int a, int b, int c, int d, int *p) +{ +} + +void +i80321_pci_attach_hook(struct device *parent, struct device *self, + struct pcibus_attach_args *pba) +{ + + /* Nothing to do. */ +} + +int +i80321_pci_bus_maxdevs(void *v, int busno) +{ + + return (32); +} + +pcitag_t +i80321_pci_make_tag(void *v, int b, int d, int f) +{ + + return ((b << 16) | (d << 11) | (f << 8)); +} + +void +i80321_pci_decompose_tag(void *v, pcitag_t tag, int *bp, int *dp, int *fp) +{ + + if (bp != NULL) + *bp = (tag >> 16) & 0xff; + if (dp != NULL) + *dp = (tag >> 11) & 0x1f; + if (fp != NULL) + *fp = (tag >> 8) & 0x7; +} + +struct pciconf_state { + uint32_t ps_addr_val; + + int ps_b, ps_d, ps_f; +}; + +static int +i80321_pci_conf_setup(struct i80321_softc *sc, pcitag_t tag, int offset, + struct pciconf_state *ps) +{ + uint32_t busno; + + i80321_pci_decompose_tag(sc, tag, &ps->ps_b, &ps->ps_d, &ps->ps_f); + + busno = bus_space_read_4(sc->sc_st, sc->sc_atu_sh, ATU_PCIXSR); + busno = PCIXSR_BUSNO(busno); + if (busno == 0xff) + busno = 0; + + /* + * If the bus # is the same as our own, then use Type 0 cycles, + * else use Type 1. + * + * XXX We should filter out all non-private devices here! + * XXX How does private space interact with PCI-PCI bridges? + */ + if (ps->ps_b == busno) { + if (ps->ps_d > (31 - 16)) + return (1); + ps->ps_addr_val = (1U << (ps->ps_d + 16)) | (ps->ps_f << 8) | + offset; + } else { + /* The tag is already in the correct format. */ + ps->ps_addr_val = tag | offset | 1; + } + + return (0); +} + +pcireg_t +i80321_pci_conf_read(void *v, pcitag_t tag, int offset) +{ + struct i80321_softc *sc = v; + struct pciconf_state ps; + vaddr_t va; + uint32_t isr; + pcireg_t rv; + u_int s; + + if (i80321_pci_conf_setup(sc, tag, offset, &ps)) + return ((pcireg_t) -1); + + PCI_CONF_LOCK(s); + + bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_OCCAR, + ps.ps_addr_val); + + va = (vaddr_t) bus_space_vaddr(sc->sc_st, sc->sc_atu_sh); + if (badaddr_read((void *) (va + ATU_OCCDR), sizeof(rv), &rv)) { + isr = bus_space_read_4(sc->sc_st, sc->sc_atu_sh, ATU_ATUISR); + bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_ATUISR, + isr & (ATUISR_P_SERR_DET|ATUISR_PMA|ATUISR_PTAM| + ATUISR_PTAT|ATUISR_PMPE)); +#if 0 + printf("conf_read: %d/%d/%d bad address\n", + ps.ps_b, ps.ps_d, ps.ps_f); +#endif + rv = (pcireg_t) -1; + } + + PCI_CONF_UNLOCK(s); + + return (rv); +} + +void +i80321_pci_conf_write(void *v, pcitag_t tag, int offset, pcireg_t val) +{ + struct i80321_softc *sc = v; + struct pciconf_state ps; + u_int s; + + if (i80321_pci_conf_setup(sc, tag, offset, &ps)) + return; + + PCI_CONF_LOCK(s); + + bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_OCCAR, + ps.ps_addr_val); + bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_OCCDR, val); + + PCI_CONF_UNLOCK(s); +} diff --git a/sys/arch/arm/xscale/i80321_pci_dma.c b/sys/arch/arm/xscale/i80321_pci_dma.c new file mode 100644 index 000000000000..02b15ae905e4 --- /dev/null +++ b/sys/arch/arm/xscale/i80321_pci_dma.c @@ -0,0 +1,369 @@ +/* $NetBSD: i80321_pci_dma.c,v 1.1 2002/03/27 21:45:48 thorpej Exp $ */ + +/* + * Copyright (c) 2001, 2002 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. + */ + +/* + * PCI DMA support for i80321 I/O Processor chip. + */ + +#include +#include +#include +#include +#include + +#include + +#define _ARM32_BUS_DMA_PRIVATE +#include + +#include +#include + +int i80321_pci_dmamap_load(bus_dma_tag_t, bus_dmamap_t, void *, + bus_size_t, struct proc *, int); +int i80321_pci_dmamap_load_mbuf(bus_dma_tag_t, bus_dmamap_t, + struct mbuf *, int); +int i80321_pci_dmamap_load_uio(bus_dma_tag_t, bus_dmamap_t, + struct uio *, int); +int i80321_pci_dmamap_load_raw(bus_dma_tag_t, bus_dmamap_t, + bus_dma_segment_t *, int, bus_size_t, int); + +int i80321_pci_dmamem_alloc(bus_dma_tag_t, bus_size_t, + bus_size_t, bus_size_t, bus_dma_segment_t *, int, int *, int); + +void +i80321_pci_dma_init(bus_dma_tag_t dmat, void *cookie) +{ + + /* + * XXX XXX XXX The arm32_bus_dma_tag really needs to + * XXX XXX XXX be rototilled. + */ + + dmat->_ranges = cookie; + dmat->_nranges = 0; + + dmat->_dmamap_create = _bus_dmamap_create; + dmat->_dmamap_destroy = _bus_dmamap_destroy; + dmat->_dmamap_load = i80321_pci_dmamap_load; + dmat->_dmamap_load_mbuf = i80321_pci_dmamap_load_mbuf; + dmat->_dmamap_load_uio = i80321_pci_dmamap_load_uio; + dmat->_dmamap_load_raw = i80321_pci_dmamap_load_raw; + dmat->_dmamap_unload = _bus_dmamap_unload; + dmat->_dmamap_sync = _bus_dmamap_sync; + + dmat->_dmamem_alloc = i80321_pci_dmamem_alloc; + dmat->_dmamem_free = _bus_dmamem_free; + dmat->_dmamem_map = _bus_dmamem_map; + dmat->_dmamem_unmap = _bus_dmamem_unmap; + dmat->_dmamem_mmap = _bus_dmamem_mmap; +} + +/* + * i80321_pci_dmamap_load_buffer: + * + * Utility function to load a linear buffer. lastaddrp holds state + * between invocations (for multiple-buffer loads). segp contains + * the starting segment on entry, and the ending segment on exit. + * first indicates if this is the first invocation of this function. + */ +static int +i80321_pci_dmamap_load_buffer(bus_dma_tag_t t, bus_dmamap_t map, + void *buf, bus_size_t buflen, struct proc *p, int flags, + vaddr_t *lastaddrp, int *segp, int first) +{ + struct i80321_softc *sc = (void *) t->_ranges; /* XXX XXX XXX */ + bus_size_t sgsize; + bus_addr_t curaddr, lastaddr, baddr, bmask; + vaddr_t vaddr = (vaddr_t) buf; + int seg; + struct pmap *pmap; + + if (p != NULL) + pmap = p->p_vmspace->vm_map.pmap; + else + pmap = pmap_kernel(); + + lastaddr = *lastaddrp; + bmask = ~(map->_dm_boundary - 1); + + for (seg = *segp; buflen > 0; ) { + /* Get the physical address for this segment. */ + (void) pmap_extract(pmap, (vaddr_t) vaddr, &curaddr); + + /* + * Make sure we're in an allowed DMA range. + * XXX Limited to Secondary bus for now. + */ + if (curaddr < sc->sc_iwin[2].iwin_xlate || + curaddr >= (sc->sc_iwin[2].iwin_xlate + + sc->sc_iwin[2].iwin_size)) + return (EINVAL); + + /* + * Translate the physical memory address to an address + * in the Secondary Inbound window. + */ + curaddr = (curaddr - sc->sc_iwin[2].iwin_xlate) + + sc->sc_iwin[2].iwin_base_lo; + + /* Compute the segment size, and adjust counts. */ + sgsize = PAGE_SIZE - (vaddr & PAGE_MASK); + if (buflen < sgsize) + sgsize = buflen; + + /* Make sure we don't cross any boundaries. */ + if (map->_dm_boundary > 0) { + baddr = (curaddr + map->_dm_boundary) & bmask; + if (sgsize > (baddr - curaddr)) + sgsize = (baddr - curaddr); + } + + /* + * Insert chunk into a segment, coalescing with + * the previous segment if possible. + */ + if (first) { + map->dm_segs[seg].ds_addr = curaddr; + map->dm_segs[seg].ds_len = sgsize; + map->dm_segs[seg]._ds_vaddr = vaddr; + first = 0; + } else { + if (curaddr == lastaddr && + (map->dm_segs[seg].ds_len + sgsize) <= + map->_dm_maxsegsz && + (map->_dm_boundary == 0 || + (map->dm_segs[seg].ds_addr & bmask) == + (curaddr & bmask))) + map->dm_segs[seg].ds_len += sgsize; + else { + if (++seg >= map->_dm_segcnt) + break; + map->dm_segs[seg].ds_addr = curaddr; + map->dm_segs[seg].ds_len = sgsize; + map->dm_segs[seg]._ds_vaddr = vaddr; + } + } + + lastaddr = curaddr + sgsize; + vaddr += sgsize; + buflen -= sgsize; + } + + *segp = seg; + *lastaddrp = lastaddr; + + /* Did we fit? */ + if (buflen != 0) + return (EFBIG); /* XXX better return value here? */ + return (0); +} + +/* + * bus_dmamap_load: + * + * Load a DMA map with a linear buffer. + */ +int +i80321_pci_dmamap_load(bus_dma_tag_t t, bus_dmamap_t map, void *buf, + bus_size_t buflen, struct proc *p, int flags) +{ + vaddr_t lastaddr; + int seg, error; + + /* + * Make sure that on error condition we return "no valid mappings". + */ + map->dm_mapsize = 0; + map->dm_nsegs = 0; + + if (buflen > map->_dm_size) + return (EINVAL); + + seg = 0; + error = i80321_pci_dmamap_load_buffer(t, map, buf, buflen, p, + flags, &lastaddr, &seg, 1); + if (error == 0) { + map->dm_mapsize = buflen; + map->dm_nsegs = seg + 1; + map->_dm_proc = p; + } + + return (error); +} + +/* + * bus_dmamap_load_mbuf: + * + * Load a DMA map with an mbuf chain. + */ +int +i80321_pci_dmamap_load_mbuf(bus_dma_tag_t t, bus_dmamap_t map, + struct mbuf *m0, int flags) +{ + vaddr_t lastaddr; + int seg, error, first; + struct mbuf *m; + + /* + * Make sure that on error condition we return "no valid mappings". + */ + map->dm_mapsize = 0; + map->dm_nsegs = 0; + +#ifdef DIAGNOSTIC + if ((m0->m_flags & M_PKTHDR) == 0) + panic("i80321_pci_bus_dmamap_load_mbuf: no packet header"); +#endif + + if (m0->m_pkthdr.len > map->_dm_size) + return (EINVAL); + + first = 1; + seg = 0; + error = 0; + for (m = m0; m != NULL && error == 0; m = m->m_next) { + error = i80321_pci_dmamap_load_buffer(t, map, m->m_data, + m->m_len, NULL, flags, &lastaddr, &seg, first); + first = 0; + } + if (error == 0) { + map->dm_mapsize = m0->m_pkthdr.len; + map->dm_nsegs = seg + 1; + map->_dm_proc = NULL; /* always kernel */ + } + + return (0); +} + +/* + * bus_dmamap_load_uio: + * + * Load a DMA map with a uio. + */ +int +i80321_pci_dmamap_load_uio(bus_dma_tag_t t, bus_dmamap_t map, + struct uio *uio, int flags) +{ + vaddr_t lastaddr; + int seg, i, error, first; + bus_size_t minlen, resid; + struct proc *p = NULL; + struct iovec *iov; + caddr_t addr; + + /* + * Make sure that on error condition we return "no valid mappings". + */ + map->dm_mapsize = 0; + map->dm_nsegs = 0; + + resid = uio->uio_resid; + iov = uio->uio_iov; + + if (uio->uio_segflg == UIO_USERSPACE) { + p = uio->uio_procp; +#ifdef DIAGNOSTIC + if (p == NULL) + panic("i80321_pci_dmamap_load_uio: USERSPACE but " + "no proc"); +#endif + } + + first = 1; + seg = 0; + error = 0; + for (i = 0; i < uio->uio_iovcnt && resid != 0 && error == 0; i++) { + /* + * Now at the first iovec to load. Load each iovec + * until we have exhausted the residual count. + */ + minlen = resid < iov[i].iov_len ? resid : iov[i].iov_len; + addr = (caddr_t)iov[i].iov_base; + + error = i80321_pci_dmamap_load_buffer(t, map, addr, minlen, + p, flags, &lastaddr, &seg, first); + first = 0; + + resid -= minlen; + } + if (error == 0) { + map->dm_mapsize = uio->uio_resid; + map->dm_nsegs = seg + 1; + map->_dm_proc = p; + } + + return (error); +} + +/* + * bus_dmamap_load_raw: + * + * Load a DMA map with raw memory allocated with + * bus_dmamem_alloc(). + */ +int +i80321_pci_dmamap_load_raw(bus_dma_tag_t t, bus_dmamap_t map, + bus_dma_segment_t *segs, int nsegs, bus_size_t size, int flags) +{ + + panic("i80321_pci_dmamap_load_raw: not implemented"); +} + +/* + * bus_dmamem_alloc: + * + * Allocate DMA-safe memory. + */ +int +i80321_pci_dmamem_alloc(bus_dma_tag_t t, bus_size_t size, + bus_size_t alignment, bus_size_t boundary, + bus_dma_segment_t *segs, int nsegs, int *rsegs, int flags) +{ + struct i80321_softc *sc = (void *) t->_ranges; + int error; + + if (sc->sc_iwin[2].iwin_size == 0) + return (ENOMEM); + + error = _bus_dmamem_alloc_range(t, size, alignment, boundary, + segs, nsegs, rsegs, flags, trunc_page(sc->sc_iwin[2].iwin_xlate), + trunc_page(sc->sc_iwin[2].iwin_xlate + + sc->sc_iwin[2].iwin_size - 1)); + + return (error); +} diff --git a/sys/arch/arm/xscale/i80321_space.c b/sys/arch/arm/xscale/i80321_space.c new file mode 100644 index 000000000000..8a79314e9898 --- /dev/null +++ b/sys/arch/arm/xscale/i80321_space.c @@ -0,0 +1,352 @@ +/* $NetBSD: i80321_space.c,v 1.1 2002/03/27 21:45:48 thorpej Exp $ */ + +/* + * Copyright (c) 2001, 2002 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 i80321 I/O Processor. + */ + +#include +#include + +#include + +#include + +#include +#include + +/* Prototypes for all the bus_space structure functions */ +bs_protos(i80321); +bs_protos(i80321_io); +bs_protos(i80321_mem); +bs_protos(bs_notimpl); + +/* + * Template bus_space -- copied, and the bits that are NULL are + * filled in. + */ +const struct bus_space i80321_bs_tag_template = { + /* cookie */ + (void *) 0, + + /* mapping/unmapping */ + NULL, + NULL, + i80321_bs_subregion, + + /* allocation/deallocation */ + NULL, + NULL, + + /* get kernel virtual address */ + i80321_bs_vaddr, + + /* mmap */ + i80321_bs_mmap, + + /* barrier */ + i80321_bs_barrier, + + /* read (single) */ + i80321_bs_r_1, + i80321_bs_r_2, + i80321_bs_r_4, + bs_notimpl_bs_r_8, + + /* read multiple */ + i80321_bs_rm_1, + i80321_bs_rm_2, + i80321_bs_rm_4, + bs_notimpl_bs_rm_8, + + /* read region */ + bs_notimpl_bs_rr_1, + i80321_bs_rr_2, + i80321_bs_rr_4, + bs_notimpl_bs_rr_8, + + /* write (single) */ + i80321_bs_w_1, + i80321_bs_w_2, + i80321_bs_w_4, + bs_notimpl_bs_w_8, + + /* write multiple */ + i80321_bs_wm_1, + i80321_bs_wm_2, + i80321_bs_wm_4, + bs_notimpl_bs_wm_8, + + /* write region */ + bs_notimpl_bs_wr_1, + i80321_bs_wr_2, + i80321_bs_wr_4, + bs_notimpl_bs_wr_8, + + /* set multiple */ + bs_notimpl_bs_sm_1, + bs_notimpl_bs_sm_2, + bs_notimpl_bs_sm_4, + bs_notimpl_bs_sm_8, + + /* set region */ + bs_notimpl_bs_sr_1, + i80321_bs_sr_2, + bs_notimpl_bs_sr_4, + bs_notimpl_bs_sr_8, + + /* copy */ + bs_notimpl_bs_c_1, + i80321_bs_c_2, + bs_notimpl_bs_c_4, + bs_notimpl_bs_c_8, +}; + +void +i80321_bs_init(bus_space_tag_t bs, void *cookie) +{ + + *bs = i80321_bs_tag_template; + bs->bs_cookie = cookie; +} + +void +i80321_io_bs_init(bus_space_tag_t bs, void *cookie) +{ + + *bs = i80321_bs_tag_template; + bs->bs_cookie = cookie; + + bs->bs_map = i80321_io_bs_map; + bs->bs_unmap = i80321_io_bs_unmap; + bs->bs_alloc = i80321_io_bs_alloc; + bs->bs_free = i80321_io_bs_free; + + bs->bs_vaddr = i80321_io_bs_vaddr; +} + +void +i80321_mem_bs_init(bus_space_tag_t bs, void *cookie) +{ + + *bs = i80321_bs_tag_template; + bs->bs_cookie = cookie; + + bs->bs_map = i80321_mem_bs_map; + bs->bs_unmap = i80321_mem_bs_unmap; + bs->bs_alloc = i80321_mem_bs_alloc; + bs->bs_free = i80321_mem_bs_free; + + bs->bs_mmap = i80321_mem_bs_mmap; +} + +/* *** Routines shared by i80321, PCI IO, and PCI MEM. *** */ + +int +i80321_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 +i80321_bs_barrier(void *t, bus_space_handle_t bsh, bus_size_t offset, + bus_size_t len, int flags) +{ + + /* Nothing to do. */ +} + +void * +i80321_bs_vaddr(void *t, bus_space_handle_t bsh) +{ + + return ((void *)bsh); +} + +paddr_t +i80321_bs_mmap(void *t, bus_addr_t addr, off_t off, int prot, int flags) +{ + + /* Not supported. */ + return (-1); +} + +/* *** Routines for PCI IO. *** */ + +int +i80321_io_bs_map(void *t, bus_addr_t bpa, bus_size_t size, int flags, + bus_space_handle_t *bshp) +{ + struct i80321_softc *sc = t; + vaddr_t winvaddr; + uint32_t busbase; + + if (bpa >= sc->sc_ioout_xlate && + bpa < (sc->sc_ioout_xlate + VERDE_OUT_XLATE_IO_WIN_SIZE)) { + busbase = sc->sc_ioout_xlate; + winvaddr = sc->sc_iow_vaddr; + } else + return (EINVAL); + + if ((bpa + size) >= (busbase + VERDE_OUT_XLATE_IO_WIN_SIZE)) + return (EINVAL); + + /* + * Found the window -- PCI I/O space is mapped at a fixed + * virtual address by board-specific code. Translate the + * bus address to the virtual address. + */ + *bshp = winvaddr + (bpa - busbase); + + return (0); +} + +void +i80321_io_bs_unmap(void *t, bus_space_handle_t bsh, bus_size_t size) +{ + + /* Nothing to do. */ +} + +int +i80321_io_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("i80321_io_bs_alloc(): not implemented\n"); +} + +void +i80321_io_bs_free(void *t, bus_space_handle_t bsh, bus_size_t size) +{ + + panic("i80321_io_bs_free(): not implemented\n"); +} + +void * +i80321_io_bs_vaddr(void *t, bus_space_handle_t bsh) +{ + + /* Not supported. */ + return (NULL); +} + +/* *** Routines for PCI MEM. *** */ + +int +i80321_mem_bs_map(void *t, bus_addr_t bpa, bus_size_t size, int flags, + bus_space_handle_t *bshp) +{ + + struct i80321_softc *sc = t; + vaddr_t va; + uint32_t busbase; + paddr_t pa, endpa, physbase; + + if (bpa >= sc->sc_owin[0].owin_xlate_lo && + bpa < (sc->sc_owin[0].owin_xlate_lo + + VERDE_OUT_XLATE_MEM_WIN_SIZE)) { + busbase = sc->sc_owin[0].owin_xlate_lo; + physbase = sc->sc_iwin[1].iwin_xlate; + } else + return (EINVAL); + + if ((bpa + size) >= (busbase + VERDE_OUT_XLATE_MEM_WIN_SIZE)) + return (EINVAL); + + /* + * Found the window -- PCI MEM space is not mapped by allocating + * some kernel VA space and mapping the pages with pmap_enter(). + * pmap_enter() will map unmanaged pages as non-cacheable. + */ + pa = trunc_page((bpa - busbase) + physbase); + endpa = round_page(((bpa - busbase) + physbase) + size); + + va = uvm_km_valloc(kernel_map, endpa - pa); + if (va == 0) + return (ENOMEM); + + *bshp = va + (bpa & PAGE_MASK); + + for (; pa < endpa; pa += PAGE_SIZE, va += PAGE_SIZE) { + pmap_enter(pmap_kernel(), va, pa, + VM_PROT_READ | VM_PROT_WRITE, PMAP_WIRED); + } + pmap_update(pmap_kernel()); + + return (0); +} + +void +i80321_mem_bs_unmap(void *t, bus_space_handle_t bsh, bus_size_t size) +{ + vaddr_t va, endva; + + va = trunc_page(bsh); + endva = round_page(bsh + size); + + /* Free the kernel virtual mapping. */ + uvm_km_free(kernel_map, va, endva - va); +} + +int +i80321_mem_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("i80321_mem_bs_alloc(): not implemented\n"); +} + +void +i80321_mem_bs_free(void *t, bus_space_handle_t bsh, bus_size_t size) +{ + + panic("i80321_mem_bs_free(): not implemented\n"); +} + +paddr_t +i80321_mem_bs_mmap(void *t, bus_addr_t addr, off_t off, int prot, int flags) +{ + + /* XXX */ + return (-1); +} diff --git a/sys/arch/arm/xscale/i80321_space_asm.S b/sys/arch/arm/xscale/i80321_space_asm.S new file mode 100644 index 000000000000..472edd3376f1 --- /dev/null +++ b/sys/arch/arm/xscale/i80321_space_asm.S @@ -0,0 +1,299 @@ +/* $NetBSD: i80321_space_asm.S,v 1.1 2002/03/27 21:45:48 thorpej Exp $ */ + +/* + * Copyright (c) 1997 Causality Limited. + * Copyright (c) 1997 Mark Brinicombe. + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Mark Brinicombe + * for the NetBSD Project. + * 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 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 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. + */ + +#include + +/* + * bus_space functions for the i80321 + */ + +/* + * Note these functions use ARM Architecture V4 instructions as + * all i80321 based systems have Intel XScale processors on them. + */ + +/* + * read single + */ + +ENTRY(i80321_bs_r_1) + ldrb r0, [r1, r2] + mov pc, lr + +ENTRY(i80321_bs_r_2) + ldrh r0, [r1, r2] + mov pc, lr + +ENTRY(i80321_bs_r_4) + ldr r0, [r1, r2] + mov pc, lr + +/* + * write single + */ + +ENTRY(i80321_bs_w_1) + strb r3, [r1, r2] + mov pc, lr + +ENTRY(i80321_bs_w_2) + strh r3, [r1, r2] + mov pc, lr + +ENTRY(i80321_bs_w_4) + str r3, [r1, r2] + mov pc, lr + +/* + * read multiple + */ + +ENTRY(i80321_bs_rm_1) + add r0, r1, r2 + mov r1, r3 + ldr r2, [sp, #0] + teq r2, #0 + moveq pc, lr + +Li80321_bs_rm_1_loop: + ldrb r3, [r0] + strb r3, [r1], #1 + subs r2, r2, #1 + bne Li80321_bs_rm_1_loop + + mov pc, lr + +ENTRY(i80321_bs_rm_2) + add r0, r1, r2 + mov r1, r3 + ldr r2, [sp, #0] + teq r2, #0 + moveq pc, lr + +Li80321_bs_rm_2_loop: + ldrh r3, [r0] + strh r3, [r1], #2 + subs r2, r2, #1 + bne Li80321_bs_rm_2_loop + + mov pc, lr + +ENTRY(i80321_bs_rm_4) + add r0, r1, r2 + mov r1, r3 + ldr r2, [sp, #0] + teq r2, #0 + moveq pc, lr + +Li80321_bs_rm_4_loop: + ldr r3, [r0] + str r3, [r1], #4 + subs r2, r2, #1 + bne Li80321_bs_rm_4_loop + + mov pc, lr + +/* + * write multiple + */ + +ENTRY(i80321_bs_wm_1) + add r0, r1, r2 + mov r1, r3 + ldr r2, [sp, #0] + teq r2, #0 + moveq pc, lr + +Li80321_bs_wm_1_loop: + ldrb r3, [r1], #1 + strb r3, [r0] + subs r2, r2, #1 + bne Li80321_bs_wm_1_loop + + mov pc, lr + +ENTRY(i80321_bs_wm_2) + add r0, r1, r2 + mov r1, r3 + ldr r2, [sp, #0] + teq r2, #0 + moveq pc, lr + +Li80321_bs_wm_2_loop: + ldrh r3, [r1], #2 + strh r3, [r0] + subs r2, r2, #1 + bne Li80321_bs_wm_2_loop + + mov pc, lr + +ENTRY(i80321_bs_wm_4) + add r0, r1, r2 + mov r1, r3 + ldr r2, [sp, #0] + teq r2, #0 + moveq pc, lr + +Li80321_bs_wm_4_loop: + ldr r3, [r1], #4 + str r3, [r0] + subs r2, r2, #1 + bne Li80321_bs_wm_4_loop + + mov pc, lr + +/* + * read region + */ + +ENTRY(i80321_bs_rr_2) + add r0, r1, r2 + mov r1, r3 + ldr r2, [sp, #0] + teq r2, #0 + moveq pc, lr + +Li80321_rr_2_loop: + ldrh r3, [r0], #2 + strh r3, [r1], #2 + subs r2, r2, #1 + bne Li80321_rr_2_loop + + mov pc, lr + +ENTRY(i80321_bs_rr_4) + add r0, r1, r2 + mov r1, r3 + ldr r2, [sp, #0] + teq r2, #0 + moveq pc, lr + +Li80321_rr_4_loop: + ldr r3, [r0], #4 + str r3, [r1], #4 + subs r2, r2, #1 + bne Li80321_rr_4_loop + + mov pc, lr + +/* + * write region. + */ + +ENTRY(i80321_bs_wr_2) + add r0, r1, r2 + mov r1, r3 + ldr r2, [sp, #0] + teq r2, #0 + moveq pc, lr + +Li80321_wr_2_loop: + ldrh r3, [r1], #2 + strh r3, [r0], #2 + subs r2, r2, #1 + bne Li80321_wr_2_loop + + mov pc, lr + +ENTRY(i80321_bs_wr_4) + add r0, r1, r2 + mov r1, r3 + ldr r2, [sp, #0] + teq r2, #0 + moveq pc, lr + +Li80321_wr_4_loop: + ldr r3, [r1], #4 + str r3, [r0], #4 + subs r2, r2, #1 + bne Li80321_wr_4_loop + + mov pc, lr + +/* + * set region + */ + +ENTRY(i80321_bs_sr_2) + add r0, r1, r2 + mov r1, r3 + ldr r2, [sp, #0] + teq r2, #0 + moveq pc, lr + +Li80321_bs_sr_2_loop: + strh r1, [r0], #2 + subs r2, r2, #1 + bne Li80321_bs_sr_2_loop + + mov pc, lr + +/* + * copy region + */ + +ENTRY(i80321_bs_c_2) + add r0, r1, r2 + ldr r2, [sp, #0] + add r1, r2, r3 + ldr r2, [sp, #4] + teq r2, #0 + moveq pc, lr + + cmp r0, r1 + blt Li80321_bs_c_2_backwards + +Li80321_bs_cf_2_loop: + ldrh r3, [r0], #2 + strh r3, [r1], #2 + subs r2, r2, #1 + bne Li80321_bs_cf_2_loop + + mov pc, lr + +Li80321_bs_c_2_backwards: + add r0, r0, r2, lsl #1 + add r1, r1, r2, lsl #1 + sub r0, r0, #2 + sub r1, r1, #2 + +Li80321_bs_cb_2_loop: + ldrh r3, [r0], #-2 + strh r3, [r1], #-2 + subs r2, r2, #1 + bne Li80321_bs_cb_2_loop + + mov pc, lr diff --git a/sys/arch/arm/xscale/i80321_timer.c b/sys/arch/arm/xscale/i80321_timer.c new file mode 100644 index 000000000000..efcbb6e0461c --- /dev/null +++ b/sys/arch/arm/xscale/i80321_timer.c @@ -0,0 +1,342 @@ +/* $NetBSD: i80321_timer.c,v 1.1 2002/03/27 21:45:48 thorpej Exp $ */ + +/* + * Copyright (c) 2001, 2002 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. + */ + +/* + * Timer/clock support for the Intel i80321 I/O processor. + */ + +#include +#include +#include +#include + +#include +#include + +#include +#include + +void (*i80321_hardclock_hook)(void); + +#define COUNTS_PER_SEC 200000000 /* 200MHz */ +#define COUNTS_PER_USEC (COUNTS_PER_SEC / 1000000) + +static void *clock_ih; + +static uint32_t counts_per_hz; + +int clockhandler(void *); + +static __inline uint32_t +tmr0_read(void) +{ + uint32_t rv; + + __asm __volatile("mrc p6, 0, %0, c0, c1, 0" + : "=r" (rv)); + return (rv); +} + +static __inline void +tmr0_write(uint32_t val) +{ + + __asm __volatile("mcr p6, 0, %0, c0, c1, 0" + : + : "r" (val)); +} + +static __inline uint32_t +tcr0_read(void) +{ + uint32_t rv; + + __asm __volatile("mrc p6, 0, %0, c2, c1, 0" + : "=r" (rv)); + return (rv); +} + +static __inline void +tcr0_write(uint32_t val) +{ + + __asm __volatile("mcr p6, 0, %0, c2, c1, 0" + : + : "r" (val)); +} + +static __inline void +trr0_write(uint32_t val) +{ + + __asm __volatile("mcr p6, 0, %0, c4, c1, 0" + : + : "r" (val)); +} + +static __inline void +tisr_write(uint32_t val) +{ + + __asm __volatile("mcr p6, 0, %0, c6, c1, 0" + : + : "r" (val)); +} + +/* + * i80321_calibrate_delay: + * + * Calibrate the delay loop. + */ +void +i80321_calibrate_delay(void) +{ + + /* + * Just use hz=100 for now -- we'll adjust it, if necessary, + * in cpu_initclocks(). + */ + counts_per_hz = COUNTS_PER_SEC / 100; + + tmr0_write(0); /* stop timer */ + tisr_write(TISR_TMR0); /* clear interrupt */ + trr0_write(counts_per_hz); /* reload value */ + tcr0_write(counts_per_hz); /* current value */ + + tmr0_write(TMRx_ENABLE|TMRx_RELOAD|TMRx_CSEL_CORE); +} + +/* + * cpu_initclocks: + * + * Initialize the clock and get them going. + */ +void +cpu_initclocks(void) +{ + u_int oldirqstate; + + if (hz < 50 || COUNTS_PER_SEC % hz) { + printf("Cannot get %d Hz clock; using 100 Hz\n", hz); + hz = 100; + } + tick = 1000000 / hz; /* number of microseconds between interrupts */ + tickfix = 1000000 - (hz * tick); + if (tickfix) { + int ftp; + + ftp = min(ffs(tickfix), ffs(hz)); + tickfix >>= (ftp - 1); + tickfixinterval = hz >> (ftp - 1); + } + + /* + * We only have one timer available; stathz and profhz are + * always left as 0 (the upper-layer clock code deals with + * this situation). + */ + if (stathz != 0) + printf("Cannot get %d Hz statclock\n", stathz); + stathz = 0; + + if (profhz != 0) + printf("Cannot get %d Hz profclock\n", profhz); + profhz = 0; + + /* Report the clock frequency. */ + printf("clock: hz=%d stathz=%d profhz=%d\n", hz, stathz, profhz); + + oldirqstate = disable_interrupts(I32_bit); + + /* Hook up the clock interrupt handler. */ + clock_ih = i80321_intr_establish(ICU_INT_TMR0, IPL_CLOCK, + clockhandler, NULL); + if (clock_ih == NULL) + panic("cpu_initclocks: unable to register timer interrupt"); + + /* Set up the new clock parameters. */ + + tmr0_write(0); /* stop timer */ + tisr_write(TISR_TMR0); /* clear interrupt */ + + counts_per_hz = COUNTS_PER_SEC / hz; + + trr0_write(counts_per_hz); /* reload value */ + tcr0_write(counts_per_hz); /* current value */ + + tmr0_write(TMRx_ENABLE|TMRx_RELOAD|TMRx_CSEL_CORE); + + restore_interrupts(oldirqstate); +} + +/* + * setstatclockrate: + * + * Set the rate of the statistics clock. + * + * We assume that hz is either stathz or profhz, and that neither + * will change after being set by cpu_initclocks(). We could + * recalculate the intervals here, but that would be a pain. + */ +void +setstatclockrate(int hz) +{ + + /* + * XXX Use TMR1? + */ +} + +/* + * microtime: + * + * Fill in the specified timeval struct with the current time + * accurate to the microsecond. + */ +void +microtime(struct timeval *tvp) +{ + static struct timeval lasttv; + u_int oldirqstate; + uint32_t counts; + + oldirqstate = disable_interrupts(I32_bit); + + counts = counts_per_hz - tcr0_read(); + + /* Fill in the timeval struct. */ + *tvp = time; + tvp->tv_usec += (counts / COUNTS_PER_USEC); + + /* Make sure microseconds doesn't overflow. */ + while (tvp->tv_usec >= 1000000) { + tvp->tv_usec -= 1000000; + tvp->tv_sec++; + } + + /* Make sure the time has advanced. */ + if (tvp->tv_sec == lasttv.tv_sec && + tvp->tv_usec <= lasttv.tv_usec) { + tvp->tv_usec = lasttv.tv_usec + 1; + if (tvp->tv_usec >= 1000000) { + tvp->tv_usec -= 1000000; + tvp->tv_sec++; + } + } + + lasttv = *tvp; + + restore_interrupts(oldirqstate); +} + +/* + * delay: + * + * Delay for at least N microseconds. + */ +void +delay(u_int n) +{ + uint32_t cur, last, delta, usecs; + + /* + * This works by polling the timer and counting the + * number of microseconds that go by. + */ + last = tcr0_read(); + delta = usecs = 0; + + while (n > usecs) { + cur = tcr0_read(); + + /* Check to see if the timer has wrapped around. */ + if (last < cur) + delta += (last + (counts_per_hz - cur)); + else + delta += (last - cur); + + last = cur; + + if (delta >= COUNTS_PER_USEC) { + usecs += delta / COUNTS_PER_USEC; + delta %= COUNTS_PER_USEC; + } + } +} + +/* + * inittodr: + * + * Initialize time from the time-of-day register. + */ +void +inittodr(time_t base) +{ + + time.tv_sec = base; + time.tv_usec = 0; +} + +/* + * resettodr: + * + * Reset the time-of-day register with the current time. + */ +void +resettodr(void) +{ +} + +/* + * clockhandler: + * + * Handle the hardclock interrupt. + */ +int +clockhandler(void *arg) +{ + struct clockframe *frame = arg; + + tisr_write(TISR_TMR0); + + hardclock(frame); + + if (i80321_hardclock_hook != NULL) + (*i80321_hardclock_hook)(); + + return (1); +} diff --git a/sys/arch/arm/xscale/i80321reg.h b/sys/arch/arm/xscale/i80321reg.h new file mode 100644 index 000000000000..bd5356cdae18 --- /dev/null +++ b/sys/arch/arm/xscale/i80321reg.h @@ -0,0 +1,340 @@ +/* $NetBSD: i80321reg.h,v 1.1 2002/03/27 21:45:48 thorpej Exp $ */ + +/* + * Copyright (c) 2002 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. + */ + +#ifndef _ARM_XSCALE_I80321REG_H_ +#define _ARM_XSCALE_I80321REG_H_ + +/* + * Register definitions for the Intel 80321 (``Verde'') I/O processor, + * based on the XScale core. + */ + +/* + * Base i80321 memory map: + * + * 0x0000.0000 - 0x7fff.ffff ATU Outbound Direct Addressing Window + * 0x8000.0000 - 0x9001.ffff ATU Outbound Translation Windows + * 0x9002.0000 - 0xffff.dfff External Memory + * 0xffff.e000 - 0xffff.e8ff Peripheral Memory Mapped Registers + * 0xffff.e900 - 0xffff.ffff Reserved + */ + +#define VERDE_OUT_DIRECT_WIN_BASE 0x00000000UL +#define VERDE_OUT_DIRECT_WIN_SIZE 0x80000000UL + +#define VERDE_OUT_XLATE_MEM_WIN_SIZE 0x04000000UL +#define VERDE_OUT_XLATE_IO_WIN_SIZE 0x00010000UL + +#define VERDE_OUT_XLATE_MEM_WIN0_BASE 0x80000000UL +#define VERDE_OUT_XLATE_MEM_WIN1_BASE 0x84000000UL + +#define VERDE_OUT_XLATE_IO_WIN0_BASE 0x90000000UL + +#define VERDE_EXTMEM_BASE 0x90020000UL + +#define VERDE_PMMR_BASE 0xffffe000UL +#define VERDE_PMMR_SIZE 0x00000900UL + +/* + * Peripheral Memory Mapped Registers. Defined as offsets + * from the VERDE_PMMR_BASE. + */ +#define VERDE_ATU_BASE 0x0100 +#define VERDE_ATU_SIZE 0x0100 + +#define VERDE_MCU_BASE 0x0500 +#define VERDE_MCU_SIZE 0x0100 + +/* + * Address Translation Unit + */ + /* 0x00 - 0x38 -- PCI configuration space header */ +#define ATU_IALR0 0x40 /* Inbound ATU Limit 0 */ +#define ATU_IATVR0 0x44 /* Inbound ATU Xlate Value 0 */ +#define ATU_ERLR 0x48 /* Expansion ROM Limit */ +#define ATU_ERTVR 0x4c /* Expansion ROM Xlate Value */ +#define ATU_IALR1 0x50 /* Inbound ATU Limit 1 */ +#define ATU_IALR2 0x54 /* Inbound ATU Limit 2 */ +#define ATU_IATVR2 0x58 /* Inbound ATU Xlate Value 2 */ +#define ATU_OIOWTVR 0x5c /* Outbound I/O Window Xlate Value */ +#define ATU_OMWTVR0 0x60 /* Outbound Mem Window Xlate Value 0 */ +#define ATU_OUMWTVR0 0x64 /* Outbound Mem Window Xlate Value 0 Upper */ +#define ATU_OMWTVR1 0x68 /* Outbound Mem Window Xlate Value 1 */ +#define ATU_OUMWTVR1 0x6c /* Outbound Mem Window Xlate Value 1 Upper */ +#define ATU_OUDWTVR 0x78 /* Outbound Mem Direct Xlate Value Upper */ +#define ATU_ATUCR 0x80 /* ATU Configuration */ +#define ATU_PCSR 0x84 /* PCI Configuration and Status */ +#define ATU_ATUISR 0x88 /* ATU Interrupt Status */ +#define ATU_ATUIMR 0x8c /* ATU Interrupt Mask */ +#define ATU_IABAR3 0x90 /* Inbound ATU Base Address 3 */ +#define ATU_IAUBAR3 0x94 /* Inbound ATU Base Address 3 Upper */ +#define ATU_IALR3 0x98 /* Inbound ATU Limit 3 */ +#define ATU_IATVR3 0x9c /* Inbound ATU Xlate Value 3 */ +#define ATU_OCCAR 0xa4 /* Outbound Configuration Cycle Address */ +#define ATU_OCCDR 0xac /* Outbound Configuration Cycle Data */ +#define ATU_MSI_PORT 0xb4 /* MSI port */ +#define ATU_PDSCR 0xbc /* PCI Bus Drive Strength Control */ +#define ATU_PCI_X_CAP_ID 0xe0 /* (1) */ +#define ATU_PCI_X_NEXT 0xe1 /* (1) */ +#define ATU_PCIXCMD 0xe2 /* PCI-X Command Register (2) */ +#define ATU_PCIXSR 0xe4 /* PCI-X Status Register */ + +#define ATUCR_DRC_ALIAS (1U << 19) +#define ATUCR_DAU2GXEN (1U << 18) +#define ATUCR_P_SERR_MA (1U << 16) +#define ATUCR_DTS (1U << 15) +#define ATUCR_P_SERR_DIE (1U << 9) +#define ATUCR_DAE (1U << 8) +#define ATUCR_BIST_IE (1U << 3) +#define ATUCR_OUT_EN (1U << 1) + +#define PCSR_DAAAPE (1U << 18) +#define PCSR_PCI_X_CAP (3U << 16) +#define PCSR_PCI_X_CAP_BORING (0 << 16) +#define PCSR_PCI_X_CAP_66 (1U << 16) +#define PCSR_PCI_X_CAP_100 (2U << 16) +#define PCSR_PCI_X_CAP_133 (3U << 16) +#define PCSR_OTQB (1U << 15) +#define PCSR_IRTQB (1U << 14) +#define PCSR_DTV (1U << 12) +#define PCSR_BUS66 (1U << 10) +#define PCSR_BUS64 (1U << 8) +#define PCSR_RIB (1U << 5) +#define PCSR_RPB (1U << 4) +#define PCSR_CCR (1U << 2) +#define PCSR_CPR (1U << 1) + +#define ATUISR_IMW1BU (1U << 14) +#define ATUISR_ISCEM (1U << 13) +#define ATUISR_RSCEM (1U << 12) +#define ATUISR_PST (1U << 11) +#define ATUISR_P_SERR_ASRT (1U << 10) +#define ATUISR_DPE (1U << 9) +#define ATUISR_BIST (1U << 8) +#define ATUISR_IBMA (1U << 7) +#define ATUISR_P_SERR_DET (1U << 4) +#define ATUISR_PMA (1U << 3) +#define ATUISR_PTAM (1U << 2) +#define ATUISR_PTAT (1U << 1) +#define ATUISR_PMPE (1U << 0) + +#define ATUIMR_IMW1BU (1U << 11) +#define ATUIMR_ISCEM (1U << 10) +#define ATUIMR_RSCEM (1U << 9) +#define ATUIMR_PST (1U << 8) +#define ATUIMR_DPE (1U << 7) +#define ATUIMR_P_SERR_ASRT (1U << 6) +#define ATUIMR_PMA (1U << 5) +#define ATUIMR_PTAM (1U << 4) +#define ATUIMR_PTAT (1U << 3) +#define ATUIMR_PMPE (1U << 2) +#define ATUIMR_IE_SERR_EN (1U << 1) +#define ATUIMR_ECC_TAE (1U << 0) + +#define PCIXCMD_MOST_1 (0 << 4) +#define PCIXCMD_MOST_2 (1 << 4) +#define PCIXCMD_MOST_3 (2 << 4) +#define PCIXCMD_MOST_4 (3 << 4) +#define PCIXCMD_MOST_8 (4 << 4) +#define PCIXCMD_MOST_12 (5 << 4) +#define PCIXCMD_MOST_16 (6 << 4) +#define PCIXCMD_MOST_32 (7 << 4) +#define PCIXCMD_MOST_MASK (7 << 4) +#define PCIXCMD_MMRBC_512 (0 << 2) +#define PCIXCMD_MMRBC_1024 (1 << 2) +#define PCIXCMD_MMRBC_2048 (2 << 2) +#define PCIXCMD_MMRBC_4096 (3 << 2) +#define PCIXCMD_MMRBC_MASK (3 << 2) +#define PCIXCMD_ERO (1U << 1) +#define PCIXCMD_DPERE (1U << 0) + +#define PCIXSR_RSCEM (1U << 29) +#define PCIXSR_DMCRS_MASK (7 << 26) +#define PCIXSR_DMOST_MASK (7 << 23) +#define PCIXSR_COMPLEX (1U << 20) +#define PCIXSR_USC (1U << 19) +#define PCIXSR_SCD (1U << 18) +#define PCIXSR_133_CAP (1U << 17) +#define PCIXSR_32PCI (1U << 16) /* 0 = 32, 1 = 64 */ +#define PCIXSR_BUSNO(x) (((x) & 0xff) >> 8) +#define PCIXSR_DEVNO(x) (((x) & 0x1f) >> 3) +#define PCIXSR_FUNCNO(x) ((x) & 0x7) + +/* + * Memory Controller Unit + */ +#define MCU_SDIR 0x00 /* DDR SDRAM Init. Register */ +#define MCU_SDCR 0x04 /* DDR SDRAM Control Register */ +#define MCU_SDBR 0x08 /* SDRAM Base Register */ +#define MCU_SBR0 0x0c /* SDRAM Boundary 0 */ +#define MCU_SBR1 0x10 /* SDRAM Boundary 1 */ +#define MCU_ECCR 0x34 /* ECC Control Register */ +#define MCU_ELOG0 0x38 /* ECC Log 0 */ +#define MCU_ELOG1 0x3c /* ECC Log 1 */ +#define MCU_ECAR0 0x40 /* ECC address 0 */ +#define MCU_ECAR1 0x44 /* ECC address 1 */ +#define MCU_ECTST 0x48 /* ECC test register */ +#define MCU_MCISR 0x4c /* MCU Interrupt Status Register */ +#define MCU_RFR 0x50 /* Refresh Frequency Register */ +#define MCU_DBUDSR 0x54 /* Data Bus Pull-up Drive Strength */ +#define MCU_DBDDSR 0x58 /* Data Bus Pull-down Drive Strength */ +#define MCU_CUDSR 0x5c /* Clock Pull-up Drive Strength */ +#define MCU_CDDSR 0x60 /* Clock Pull-down Drive Strength */ +#define MCU_CEUDSR 0x64 /* Clock En Pull-up Drive Strength */ +#define MCU_CEDDSR 0x68 /* Clock En Pull-down Drive Strength */ +#define MCU_CSUDSR 0x6c /* Chip Sel Pull-up Drive Strength */ +#define MCU_CSDDSR 0x70 /* Chip Sel Pull-down Drive Strength */ +#define MCU_REUDSR 0x74 /* Rx En Pull-up Drive Strength */ +#define MCU_REDDSR 0x78 /* Rx En Pull-down Drive Strength */ +#define MCU_ABUDSR 0x7c /* Addr Bus Pull-up Drive Strength */ +#define MCU_ABDDSR 0x80 /* Addr Bus Pull-down Drive Strength */ +#define MCU_DSDR 0x84 /* Data Strobe Delay Register */ +#define MCU_REDR 0x88 /* Rx Enable Delay Register */ + +#define SDCR_DIMMTYPE (1U << 1) /* 0 = unbuf, 1 = reg */ +#define SDCR_BUSWIDTH (1U << 2) /* 0 = 64, 1 = 32 */ + +#define SBRx_TECH (1U << 31) +#define SBRx_BOUND 0x0000003f + +#define ECCR_SBERE (1U << 0) +#define ECCR_MBERE (1U << 1) +#define ECCR_SBECE (1U << 2) +#define ECCR_ECCEN (1U << 3) + +#define ELOGx_SYNDROME 0x000000ff +#define ELOGx_ERRTYPE (1U << 8) /* 1 = multi-bit */ +#define ELOGx_RW (1U << 12) /* 1 = write error */ + /* + * Dev ID Func Requester + * 2 0 XScale core + * 2 1 ATU + * 13 0 DMA channel 0 + * 13 1 DMA channel 1 + * 26 0 ATU + */ +#define ELOGx_REQ_DEV(x) (((x) >> 19) & 0x1f) +#define ELOGx_REQ_FUNC(x) (((x) >> 16) & 0x3) + +#define MCISR_ECC_ERR0 (1U << 0) +#define MCISR_ECC_ERR1 (1U << 1) +#define MCISR_ECC_ERRN (1U << 2) + +/* + * Timers + * + * The i80321 timer registers are available in both memory-mapped + * and coprocessor spaces. Most of the registers are read-only + * if memory-mapped, so we access them via coprocessor space. + * + * TMR0 cp6 c0,1 0xffffe7e0 + * TMR1 cp6 c1,1 0xffffe7e4 + * TCR0 cp6 c2,1 0xffffe7e8 + * TCR1 cp6 c3,1 0xffffe7ec + * TRR0 cp6 c4,1 0xffffe7f0 + * TRR1 cp6 c5,1 0xffffe7f4 + * TISR cp6 c6,1 0xffffe7f8 + * WDTCR cp6 c7,1 0xffffe7fc + */ + +#define TMRx_TC (1U << 0) +#define TMRx_ENABLE (1U << 1) +#define TMRx_RELOAD (1U << 2) +#define TMRx_CSEL_CORE (0 << 4) +#define TMRx_CSEL_CORE_div4 (1 << 4) +#define TMRx_CSEL_CORE_div8 (2 << 4) +#define TMRx_CSEL_CORE_div16 (3 << 4) + +#define TISR_TMR0 (1U << 0) +#define TISR_TMR1 (1U << 1) + +#define WTDCR_ENABLE1 0x1e1e1e1e +#define WTDCR_ENABLE2 0xe1e1e1e1 + +/* + * Interrupt Controller Unit. + * + * INTCTL cp6 c0,0 0xffffe7d0 + * INTSTR cp6 c4,0 0xffffe7d4 + * IINTSRC cp6 c8,0 0xffffe7d8 + * FINTSRC cp6 c9,0 0xffffe7dc + * PIRSR 0xffffe2ec + */ + +#define ICU_PIRSR 0x02ec +#define ICU_GPOE 0x07c4 +#define ICU_GPID 0x07c8 +#define ICU_GPOD 0x07cc + +/* + * NOTE: WE USE THE `bitXX' BITS TO INDICATE PENDING SOFTWARE + * INTERRUPTS. See i80321_icu.c + */ +#define ICU_INT_HPI 31 /* high priority interrupt */ +#define ICU_INT_XINT(x) ((x) + 27) /* external interrupts */ +#define ICU_INT_bit26 26 +#define ICU_INT_SSP 25 /* SSP serial port */ +#define ICU_INT_MUE 24 /* msg unit error */ +#define ICU_INT_AAUE 23 /* AAU error */ +#define ICU_INT_bit22 22 +#define ICU_INT_DMA1E 21 /* DMA Ch 1 error */ +#define ICU_INT_DMA0E 20 /* DMA Ch 0 error */ +#define ICU_INT_MCUE 19 /* memory controller error */ +#define ICU_INT_ATUE 18 /* ATU error */ +#define ICU_INT_BIUE 17 /* bus interface unit error */ +#define ICU_INT_PMU 16 /* XScale PMU */ +#define ICU_INT_PPM 15 /* peripheral PMU */ +#define ICU_INT_BIST 14 /* ATU Start BIST */ +#define ICU_INT_MU 13 /* messaging unit */ +#define ICU_INT_I2C1 12 /* i2c unit 1 */ +#define ICU_INT_I2C0 11 /* i2c unit 0 */ +#define ICU_INT_TMR1 10 /* timer 1 */ +#define ICU_INT_TMR0 9 /* timer 0 */ +#define ICU_INT_CPPM 8 /* core processor PMU */ +#define ICU_INT_AAU_EOC 7 /* AAU end-of-chain */ +#define ICU_INT_AAU_EOT 6 /* AAU end-of-transfer */ +#define ICU_INT_bit5 5 +#define ICU_INT_bit4 4 +#define ICU_INT_DMA1_EOC 3 /* DMA1 end-of-chain */ +#define ICU_INT_DMA1_EOT 2 /* DMA1 end-of-transfer */ +#define ICU_INT_DMA0_EOC 1 /* DMA0 end-of-chain */ +#define ICU_INT_DMA0_EOT 0 /* DMA0 end-of-transfer */ + +#define ICU_INT_HWMASK (0xffffffff & ~(ICU_INT_bit26|ICU_INT_bit22| \ + ICU_INT_bit5|ICU_INT_bit4)) + +#endif /* _ARM_XSCALE_I80321REG_H_ */ diff --git a/sys/arch/arm/xscale/i80321var.h b/sys/arch/arm/xscale/i80321var.h new file mode 100644 index 000000000000..3f134590d1bb --- /dev/null +++ b/sys/arch/arm/xscale/i80321var.h @@ -0,0 +1,162 @@ +/* $NetBSD: i80321var.h,v 1.1 2002/03/27 21:45:48 thorpej Exp $ */ + +/* + * Copyright (c) 2002 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. + */ + +#ifndef _ARM_XSCALE_I80321VAR_H_ +#define _ARM_XSCALE_I80321VAR_H_ + +#include +#include + +/* + * There are roughly 32 interrupt sources. + */ +#define NIRQ 32 + +struct intrhand { + TAILQ_ENTRY(intrhand) ih_list; /* link on intrq list */ + int (*ih_func)(void *); /* handler */ + void *ih_arg; /* arg for handler */ + int ih_ipl; /* IPL_* */ + int ih_irq; /* IRQ number */ +}; + +#define IRQNAMESIZE sizeof("iop321 irq 31") + +struct intrq { + TAILQ_HEAD(, intrhand) iq_list; /* handler list */ + struct evcnt iq_ev; /* event counter */ + int iq_mask; /* IRQs to mask while handling */ + int iq_levels; /* IPL_*'s this IRQ has */ + int iq_ist; /* share type */ + char iq_name[IRQNAMESIZE]; /* interrupt name */ +}; + +struct i80321_softc { + struct device sc_dev; /* generic device glue */ + + int sc_is_host; /* indicates if we're a host or + plugged into another host */ + + /* + * This is the bus_space and handle used to access the + * i80321 itself. This is filled in by the board-specific + * front-end. + */ + bus_space_tag_t sc_st; + bus_space_handle_t sc_sh; + + /* Handles for the various subregions. */ + bus_space_handle_t sc_atu_sh; + bus_space_handle_t sc_mcu_sh; + + /* + * We expect the board-specific front-end to have already mapped + * the PCI I/O space .. it is only 64K, and I/O mappings tend to + * be smaller than a page size, so it's generally more efficient + * to map them all into virtual space in one fell swoop. + */ + vaddr_t sc_iow_vaddr; /* I/O window vaddr */ + + /* + * Variables that define the Inbound windows. The base address of + * 0-2 are configured by a host via BARs. The xlate variable + * defines the start of the local address space that it maps to. + * The size variable defines the byte size. + * + * The first 3 windows are for incoming PCI memory read/write + * cycles from a host. The 4th window, not configured by the + * host (as it outside the normal BAR range) is the inbound + * window for PCI devices controlled by the i80321. + */ + struct { + uint32_t iwin_base_hi; + uint32_t iwin_base_lo; + uint32_t iwin_xlate; + uint32_t iwin_size; + } sc_iwin[4]; + + /* + * Variables that define the Outbound windows. + */ + struct { + uint32_t owin_xlate_lo; + uint32_t owin_xlate_hi; + } sc_owin[2]; + + /* + * This is the PCI address that the Outbound I/O + * window maps to. + */ + uint32_t sc_ioout_xlate; + + /* Bus space, DMA, and PCI tags for the PCI bus (private devices). */ + struct bus_space sc_pci_iot; + struct bus_space sc_pci_memt; + struct arm32_bus_dma_tag sc_pci_dmat; + struct arm32_pci_chipset sc_pci_chipset; + + /* GPIO state */ + uint8_t sc_gpio_dir; /* GPIO pin direction (1 == output) */ + uint8_t sc_gpio_val; /* GPIO output pin value */ +}; + +extern struct bus_space i80321_bs_tag; +extern struct i80321_softc *i80321_softc; + +extern void (*i80321_hardclock_hook)(void); + +void i80321_sdram_bounds(bus_space_tag_t, bus_space_handle_t, + paddr_t *, psize_t *); + +void i80321_calibrate_delay(void); + +void i80321_icu_init(void); +void i80321_intr_init(void); +void *i80321_intr_establish(int, int, int (*)(void *), void *); +void i80321_intr_disestablish(void *); + +void i80321_bs_init(bus_space_tag_t, void *); +void i80321_io_bs_init(bus_space_tag_t, void *); +void i80321_mem_bs_init(bus_space_tag_t, void *); + +void i80321_pci_dma_init(bus_dma_tag_t, void *); + +void i80321_pci_init(pci_chipset_tag_t, void *); + +void i80321_attach(struct i80321_softc *); + +#endif /* _ARM_XSCALE_I80321VAR_H_ */