diff options
author | Dale Rahn <drahn@cvs.openbsd.org> | 2006-05-29 17:01:43 +0000 |
---|---|---|
committer | Dale Rahn <drahn@cvs.openbsd.org> | 2006-05-29 17:01:43 +0000 |
commit | 5786ac2dc222f4a4b3ebfe563d1cd07e6ec9ebd6 (patch) | |
tree | 849c938de6050f5e1011f223b9324b2d49cc5429 /sys/arch/arm | |
parent | 80dd2285399afad05923b7c6202b6dfbdb5c9079 (diff) |
Add support for i80321 based systems.
Diffstat (limited to 'sys/arch/arm')
-rw-r--r-- | sys/arch/arm/arm/conf.c | 10 | ||||
-rw-r--r-- | sys/arch/arm/arm/cpu.c | 14 | ||||
-rw-r--r-- | sys/arch/arm/arm/cpufunc.c | 9 | ||||
-rw-r--r-- | sys/arch/arm/include/armreg.h | 4 | ||||
-rw-r--r-- | sys/arch/arm/xscale/files.i80321 | 9 | ||||
-rw-r--r-- | sys/arch/arm/xscale/i80321.c | 391 | ||||
-rw-r--r-- | sys/arch/arm/xscale/i80321_intr.c | 676 | ||||
-rw-r--r-- | sys/arch/arm/xscale/i80321_mcu.c | 86 | ||||
-rw-r--r-- | sys/arch/arm/xscale/i80321_pci.c | 261 | ||||
-rw-r--r-- | sys/arch/arm/xscale/i80321_space.c | 441 | ||||
-rw-r--r-- | sys/arch/arm/xscale/i80321_timer.c | 435 | ||||
-rw-r--r-- | sys/arch/arm/xscale/i80321reg.h | 502 | ||||
-rw-r--r-- | sys/arch/arm/xscale/i80321var.h | 222 | ||||
-rw-r--r-- | sys/arch/arm/xscale/xscalereg.h | 71 |
14 files changed, 3125 insertions, 6 deletions
diff --git a/sys/arch/arm/arm/conf.c b/sys/arch/arm/arm/conf.c index b715fa9534c..0c18afd3fde 100644 --- a/sys/arch/arm/arm/conf.c +++ b/sys/arch/arm/arm/conf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: conf.c,v 1.11 2005/05/13 22:54:00 miod Exp $ */ +/* $OpenBSD: conf.c,v 1.12 2006/05/29 17:01:42 drahn Exp $ */ /* $NetBSD: conf.c,v 1.10 2002/04/19 01:04:38 wiz Exp $ */ /* @@ -278,6 +278,12 @@ cdev_decl(xfs_dev); #include "hotplug.h" +#ifdef CONF_HAVE_GPIO +#include "gpio.h" +#else +#define NGPIO 0 +#endif + #ifdef CONF_HAVE_SPKR #include "spkr.h" #else @@ -298,7 +304,7 @@ struct cdevsw cdevsw[] = { cdev_lkm_dummy(), /* 10: */ cdev_lkm_dummy(), /* 11: */ cdev_tty_init(NCOM,com), /* 12: serial port */ - cdev_lkm_dummy(), /* 13: */ + cdev_gpio_init(NGPIO,gpio), /* 13: GPIO interface */ cdev_lkm_dummy(), /* 14: */ cdev_lkm_dummy(), /* 15: */ cdev_disk_init(NWD,wd), /* 16: ST506/ESDI/IDE disk */ diff --git a/sys/arch/arm/arm/cpu.c b/sys/arch/arm/arm/cpu.c index 5e18f873745..072c468133e 100644 --- a/sys/arch/arm/arm/cpu.c +++ b/sys/arch/arm/arm/cpu.c @@ -1,4 +1,4 @@ -/* $OpenBSD: cpu.c,v 1.6 2005/12/22 20:11:16 deraadt Exp $ */ +/* $OpenBSD: cpu.c,v 1.7 2006/05/29 17:01:42 drahn Exp $ */ /* $NetBSD: cpu.c,v 1.56 2004/04/14 04:01:49 bsh Exp $ */ @@ -219,6 +219,13 @@ static const char * const i80321_steppings[16] = { "rev 12", "rev 13", "rev 14", "rev 15" }; +static const char * const i80219_steppings[16] = { + "step A-0", "rev 1", "rev 2", "rev 3", + "rev 4", "rev 5", "rev 6", "rev 7", + "rev 8", "rev 9", "rev 10", "rev 11", + "rev 12", "rev 13", "rev 14", "rev 15", +}; + /* Steppings for PXA2[15]0 */ static const char * const pxa2x0_steppings[16] = { "step A-0", "step A-1", "step B-0", "step B-1", @@ -339,6 +346,11 @@ const struct cpuidtab cpuids[] = { { CPU_ID_80321_600_B0, CPU_CLASS_XSCALE, "i80321 600MHz", i80321_steppings }, + { CPU_ID_80219_400, CPU_CLASS_XSCALE, "i80219 400MHz", + i80219_steppings }, + { CPU_ID_80219_600, CPU_CLASS_XSCALE, "i80219 600MHz", + i80219_steppings }, + { CPU_ID_PXA250A, CPU_CLASS_XSCALE, "PXA250", pxa2x0_steppings }, { CPU_ID_PXA210A, CPU_CLASS_XSCALE, "PXA210", diff --git a/sys/arch/arm/arm/cpufunc.c b/sys/arch/arm/arm/cpufunc.c index e0d94e19f85..b261bc48d7a 100644 --- a/sys/arch/arm/arm/cpufunc.c +++ b/sys/arch/arm/arm/cpufunc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: cpufunc.c,v 1.5 2006/03/07 20:20:28 miod Exp $ */ +/* $OpenBSD: cpufunc.c,v 1.6 2006/05/29 17:01:42 drahn Exp $ */ /* $NetBSD: cpufunc.c,v 1.65 2003/11/05 12:53:15 scw Exp $ */ /* @@ -1038,6 +1038,7 @@ set_cpufuncs() i80200_icu_init(); +#ifdef PERFCTRS /* * Reset the Performance Monitoring Unit to a * pristine state: @@ -1049,6 +1050,7 @@ set_cpufuncs() : : "r" (PMNC_P|PMNC_C|PMNC_PMN0_IF|PMNC_PMN1_IF| PMNC_CC_IF)); +#endif /* PERFCTRS */ #if defined(XSCALE_CCLKCFG) /* @@ -1091,9 +1093,11 @@ set_cpufuncs() #endif /* CPU_XSCALE_80200 */ #ifdef CPU_XSCALE_80321 if (cputype == CPU_ID_80321_400 || cputype == CPU_ID_80321_600 || - cputype == CPU_ID_80321_400_B0 || cputype == CPU_ID_80321_600_B0) { + cputype == CPU_ID_80321_400_B0 || cputype == CPU_ID_80321_600_B0 || + cputype == CPU_ID_80219_400 || cputype == CPU_ID_80219_600) { i80321_icu_init(); +#ifdef PERFCTRS /* * Reset the Performance Monitoring Unit to a * pristine state: @@ -1105,6 +1109,7 @@ set_cpufuncs() : : "r" (PMNC_P|PMNC_C|PMNC_PMN0_IF|PMNC_PMN1_IF| PMNC_CC_IF)); +#endif /* PERFCTRS */ cpufuncs = xscale_cpufuncs; #if defined(PERFCTRS) diff --git a/sys/arch/arm/include/armreg.h b/sys/arch/arm/include/armreg.h index c66abada963..87b7ccfcc37 100644 --- a/sys/arch/arm/include/armreg.h +++ b/sys/arch/arm/include/armreg.h @@ -1,4 +1,4 @@ -/* $OpenBSD: armreg.h,v 1.2 2004/12/30 23:30:14 drahn Exp $ */ +/* $OpenBSD: armreg.h,v 1.3 2006/05/29 17:01:42 drahn Exp $ */ /* $NetBSD: armreg.h,v 1.27 2003/09/06 08:43:02 rearnsha Exp $ */ /* @@ -204,6 +204,8 @@ #define CPU_ID_PXA210B 0x69052920 /* 3rd version Core */ #define CPU_ID_PXA250C 0x69052d00 /* 4th version Core */ #define CPU_ID_PXA210C 0x69052d20 /* 4th version Core */ +#define CPU_ID_80219_400 0x69052e20 +#define CPU_ID_80219_600 0x69052e30 #define CPU_ID_PXA27X 0x69054110 #define CPU_ID_80321_400 0x69052420 #define CPU_ID_80321_600 0x69052430 diff --git a/sys/arch/arm/xscale/files.i80321 b/sys/arch/arm/xscale/files.i80321 new file mode 100644 index 00000000000..cd18fb66d7d --- /dev/null +++ b/sys/arch/arm/xscale/files.i80321 @@ -0,0 +1,9 @@ +# $OpenBSD: files.i80321,v 1.1 2006/05/29 17:01:42 drahn Exp $ +device iopxs {}: pcibus, bus_space_generic, gpiobus +file arch/arm/xscale/i80321_space.c iopxs +file arch/arm/xscale/i80321_mcu.c iopxs +file arch/arm/xscale/i80321.c iopxs +file arch/arm/xscale/i80321_pci.c iopxs + +file arch/arm/xscale/i80321_intr.c iopxs +file arch/arm/xscale/i80321_timer.c iopxs diff --git a/sys/arch/arm/xscale/i80321.c b/sys/arch/arm/xscale/i80321.c new file mode 100644 index 00000000000..dbeb6b29394 --- /dev/null +++ b/sys/arch/arm/xscale/i80321.c @@ -0,0 +1,391 @@ +/* $NetBSD: i80321.c,v 1.18 2006/02/25 02:28:56 wiz 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 <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> + +#define _ARM32_BUS_DMA_PRIVATE +#include <machine/bus.h> + +#include <arm/xscale/i80321reg.h> +#include <arm/xscale/i80321var.h> + +/* + * Statically-allocated bus_space structure 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; + +static int i80321_iopxs_print(void *, const char *); + +/* Built-in devices. */ +static const struct iopxs_device { + const char *id_name; + bus_addr_t id_offset; + bus_size_t id_size; +} iopxs_devices[] = { + { "iopaau", VERDE_AAU_BASE, VERDE_AAU_SIZE }, +/* { "iopdma", VERDE_DMA_BASE0, VERDE_DMA_CHSIZE }, */ +/* { "iopdma", VERDE_DMA_BASE1, VERDE_DMA_CHSIZE }, */ + { "iopiic", VERDE_I2C_BASE0, VERDE_I2C_CHSIZE }, + { "iopiic", VERDE_I2C_BASE1, VERDE_I2C_CHSIZE }, +/* { "iopssp", VERDE_SSP_BASE, VERDE_SSP_SIZE }, */ + { "iopmu", VERDE_MU_BASE, VERDE_MU_SIZE }, + { "iopwdog", 0, 0 }, + { NULL, 0, 0 } +}; + +static void i80321_pci_dma_init(struct i80321_softc *); + +/* XXX - debug */ +void dump_regs(struct i80321_softc *sc); +/* + * i80321_attach: + * + * Board-independent attach routine for the i80321. + */ +void +i80321_attach(struct i80321_softc *sc) +{ + struct pcibus_attach_args pba; + const struct iopxs_device *id; + struct iopxs_attach_args ia; + pcireg_t preg; + + i80321_softc = sc; + +#if 0 +dump_regs(sc); +#endif + /* + * Program the Inbound windows. + */ + 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); + + 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_IALR1, + (0xffffffff - (sc->sc_iwin[1].iwin_size - 1)) & 0xffffffc0); + /* no xlate for window 1 */ + + 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_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); + + 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_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); + + 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); + + /* + * 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); + + printf("owin_xlate_0 %x %x\n", + sc->sc_owin[0].owin_xlate_lo, + sc->sc_owin[0].owin_xlate_hi); + printf("owin_xlate_1 %x %x\n", + sc->sc_owin[1].owin_xlate_hi, + 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. + */ + 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); + +#if 0 +dump_regs(sc); +#endif + + /* Initialize the bus space tags. */ + i80321_io_bs_init(&sc->sc_pci_iot, sc); + i80321_mem_bs_init(&sc->sc_pci_memt, sc); + + /* Initialize the DMA tags. */ + i80321_pci_dma_init(sc); + i80321_local_dma_init(sc); + + /* + * Attach all the IOP built-ins. + */ + for (id = iopxs_devices; id->id_name != NULL; id++) { + ia.ia_name = id->id_name; + ia.ia_st = sc->sc_st; + ia.ia_sh = sc->sc_sh; + ia.ia_dmat = &sc->sc_local_dmat; + ia.ia_offset = id->id_offset; + ia.ia_size = id->id_size; + +#if 0 + (void) config_found_ia(&sc->sc_dev, "iopxs", &ia, + i80321_iopxs_print); +#endif + config_found(&sc->sc_dev, &ia, i80321_iopxs_print); + } + + /* + * 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_bridgetag = NULL; + pba.pba_intrswiz = 0; /* XXX what if busno != 0? */ + pba.pba_intrtag = 0; + +#if 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_ia(&sc->sc_dev, "pcibus", &pba, pcibusprint); +#endif + config_found((struct device *)sc, &pba, i80321_iopxs_print); +} + +/* + * i80321_iopxs_print: + * + * Autoconfiguration cfprint routine when attaching + * to the "iopxs" device. + */ +static int +i80321_iopxs_print(void *aux, const char *pnp) +{ + + return (QUIET); +} + +/* + * i80321_pci_dma_init: + * + * Initialize the PCI DMA tag. + */ +static void +i80321_pci_dma_init(struct i80321_softc *sc) +{ + bus_dma_tag_t dmat = &sc->sc_pci_dmat; + struct arm32_dma_range *dr = &sc->sc_pci_dma_range; + + dr->dr_sysbase = sc->sc_iwin[2].iwin_xlate; + dr->dr_busbase = PCI_MAPREG_MEM_ADDR(sc->sc_iwin[2].iwin_base_lo); + dr->dr_len = sc->sc_iwin[2].iwin_size; + + dmat->_ranges = dr; + dmat->_nranges = 1; + + dmat->_dmamap_create = _bus_dmamap_create; + dmat->_dmamap_destroy = _bus_dmamap_destroy; + dmat->_dmamap_load = _bus_dmamap_load; + dmat->_dmamap_load_mbuf = _bus_dmamap_load_mbuf; + dmat->_dmamap_load_uio = _bus_dmamap_load_uio; + dmat->_dmamap_load_raw = _bus_dmamap_load_raw; + dmat->_dmamap_unload = _bus_dmamap_unload; +#if 0 + dmat->_dmamap_sync_pre = _bus_dmamap_sync; + dmat->_dmamap_sync_post = NULL; +#endif + dmat->_dmamap_sync = _bus_dmamap_sync; + + dmat->_dmamem_alloc = _bus_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_local_dma_init: + * + * Initialize the local DMA tag. + */ +void +i80321_local_dma_init(struct i80321_softc *sc) +{ + bus_dma_tag_t dmat = &sc->sc_local_dmat; + + dmat->_ranges = NULL; + dmat->_nranges = 0; + + dmat->_dmamap_create = _bus_dmamap_create; + dmat->_dmamap_destroy = _bus_dmamap_destroy; + dmat->_dmamap_load = _bus_dmamap_load; + dmat->_dmamap_load_mbuf = _bus_dmamap_load_mbuf; + dmat->_dmamap_load_uio = _bus_dmamap_load_uio; + dmat->_dmamap_load_raw = _bus_dmamap_load_raw; + dmat->_dmamap_unload = _bus_dmamap_unload; +#if 0 + dmat->_dmamap_sync_pre = _bus_dmamap_sync; + dmat->_dmamap_sync_post = NULL; +#endif + dmat->_dmamap_sync = _bus_dmamap_sync; + + dmat->_dmamem_alloc = _bus_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; +} + +void board_reset(void); /* XXX */ +void +board_reset() +{ + struct i80321_softc *sc = i80321_softc; + uint32_t val; + + printf("attempting reset\n"); + val = bus_space_read_4(sc->sc_st, sc->sc_sh, 0x7CC); + val &= ~0x10; + bus_space_write_4(sc->sc_st, sc->sc_sh, 0x7CC, val); + val = bus_space_read_4(sc->sc_st, sc->sc_sh, 0x7C4); + val &= ~0x10; + bus_space_write_4(sc->sc_st, sc->sc_sh, 0x7C4, val); + +} +void +dump_regs(struct i80321_softc *sc) +{ + +#define printreg(x) \ + printf("%s %x\n", \ + # x, \ + bus_space_read_4(sc->sc_st, sc->sc_atu_sh, x)); + + printreg(ATU_IALR0); + printreg(ATU_IATVR0); + printreg(PCI_MAPREG_START); + printreg(PCI_MAPREG_START+0x4); + + printreg(ATU_IALR1); + printreg(PCI_MAPREG_START+0x8); + printreg(PCI_MAPREG_START+0xc); + + printreg(ATU_IALR2); + printreg(ATU_IATVR2); + printreg(PCI_MAPREG_START+0x10); + printreg(PCI_MAPREG_START+0x14); + + printreg(ATU_IALR3); + printreg(ATU_IATVR3); + printreg(ATU_IABAR3); + printreg(ATU_IAUBAR3); + + printreg(ATU_OIOWTVR); + printreg(ATU_OMWTVR0); + printreg(ATU_OUMWTVR0); + printreg(ATU_OMWTVR1); + printreg(ATU_OUMWTVR1); + printreg(ATU_OUDWTVR); + printreg(ATU_ATUCR); +} diff --git a/sys/arch/arm/xscale/i80321_intr.c b/sys/arch/arm/xscale/i80321_intr.c new file mode 100644 index 00000000000..c4347eff6f0 --- /dev/null +++ b/sys/arch/arm/xscale/i80321_intr.c @@ -0,0 +1,676 @@ +/* $NetBSD: i80321_icu.c,v 1.11 2005/12/24 20:06:52 perry 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. + */ + +#include <sys/cdefs.h> + +/* + * Interrupt support for the Intel i80321 I/O Processor. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/malloc.h> +#include <sys/evcount.h> + +#include <uvm/uvm_extern.h> + +#include <machine/bus.h> +#include <machine/intr.h> + +#include <arm/cpufunc.h> + +#include <arm/xscale/i80321reg.h> +#include <arm/xscale/i80321var.h> + +/* Interrupt handler queues. */ +struct intrq intrq[NIRQ]; + +/* Interrupts to mask at each level. */ +int i80321_imask[NIPL]; + +/* Current interrupt priority level. */ +volatile int current_ipl_level; + +/* Interrupts pending. */ +volatile int i80321_ipending; +volatile int softint_ipending; + +/* Software copy of the IRQs we have enabled. */ +volatile uint32_t intr_enabled; + +/* Mask if interrupts steered to FIQs. */ +uint32_t intr_steer; + +#define INT_SWMASK \ + ((1U << ICU_INT_bit23) | (1U << ICU_INT_bit22) | \ + (1U << ICU_INT_bit5) | (1U << ICU_INT_bit4)) +/* + * 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_bit23, /* 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 */ +}; + +/* + * Interrupt bit names. + */ +const char *i80321_irqnames[] = { + "DMA0 EOT", + "DMA0 EOC", + "DMA1 EOT", + "DMA1 EOC", + "irq 4", + "irq 5", + "AAU EOT", + "AAU EOC", + "core PMU", + "TMR0 (hardclock)", + "TMR1", + "I2C0", + "I2C1", + "MU", + "BIST", + "periph PMU", + "XScale PMU", + "BIU error", + "ATU error", + "MCU error", + "DMA0 error", + "DMA1 error", + "irq 22", + "AAU error", + "MU error", + "SSP", + "irq 26", + "irq 27", + "irq 28", + "irq 29", + "irq 30", + "irq 31", +}; + +int i80321intc_match(struct device *parent, void *cf, void *aux); +void i80321intc_attach(struct device *, struct device *, void *); +void i80321_set_intrmask(void); +void i80321_do_pending(void); +uint32_t i80321_iintsrc_read(void); +void i80321_enable_irq(int irq); +void i80321_disable_irq(int irq); +void i80321_intr_calculate_masks(void); + + +struct cfattach i80321intc_ca = { + sizeof(struct device), i80321intc_match, i80321intc_attach +}; + +struct cfdriver i80321intc_cd = { + NULL, "i80321intc", DV_DULL +}; + +int +i80321intc_match(struct device *parent, void *cf, void *aux) +{ + + /* XXX */ +#if 0 + struct ip_attach_args *pxa = aux; + + if (pxaintc_attached || pxa->pxa_addr != PXA2X0_INTCTL_BASE) + return (0); +#endif + + return (1); +} +void +i80321intc_attach(struct device *parent, struct device *self, void *args) +{ + i80321_icu_init(); +} + +void +i80321_set_intrmask(void) +{ + extern volatile uint32_t intr_enabled; + + __asm volatile("mcr p6, 0, %0, c0, c0, 0" + : + : "r" (intr_enabled & ICU_INT_HWMASK)); +} + + +void i80321_intr_dispatch(struct clockframe *frame); + +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_intrsteer(void) +{ + + __asm volatile("mcr p6, 0, %0, c4, c0, 0" + : + : "r" (intr_steer & ICU_INT_HWMASK)); +} + +void +i80321_enable_irq(int irq) +{ + + intr_enabled |= (1U << irq); + i80321_set_intrmask(); +} + +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. + */ +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); + } + i80321_imask[ipl] = irqs; + } + + i80321_imask[IPL_NONE] = 0; + + /* + * Initialize the soft interrupt masks to block themselves. + */ + i80321_imask[IPL_SOFT] = SI_TO_IRQBIT(SI_SOFT); + i80321_imask[IPL_SOFTCLOCK] = SI_TO_IRQBIT(SI_SOFTCLOCK); + i80321_imask[IPL_SOFTNET] = SI_TO_IRQBIT(SI_SOFTNET); + i80321_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. + */ + i80321_imask[IPL_SOFTCLOCK] |= i80321_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. + */ + i80321_imask[IPL_SOFTNET] |= i80321_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. + */ + i80321_imask[IPL_BIO] |= i80321_imask[IPL_SOFTNET]; + i80321_imask[IPL_NET] |= i80321_imask[IPL_BIO]; + i80321_imask[IPL_SOFTSERIAL] |= i80321_imask[IPL_NET]; + i80321_imask[IPL_TTY] |= i80321_imask[IPL_SOFTSERIAL]; + + /* + * splvm() blocks all interrupts that use the kernel memory + * allocation facilities. + */ + i80321_imask[IPL_VM] |= i80321_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. + */ + i80321_imask[IPL_AUDIO] |= i80321_imask[IPL_VM]; + + /* + * splclock() must block anything that uses the scheduler. + */ + i80321_imask[IPL_CLOCK] |= i80321_imask[IPL_AUDIO]; + + /* + * No separate statclock on the IQ80310. + */ + i80321_imask[IPL_STATCLOCK] |= i80321_imask[IPL_CLOCK]; + + /* + * splhigh() must block "everything". + */ + i80321_imask[IPL_HIGH] |= i80321_imask[IPL_STATCLOCK]; + + /* + * XXX We need serial drivers to run at the absolute highest priority + * in order to avoid overruns, so serial > high. + */ + i80321_imask[IPL_SERIAL] |= i80321_imask[IPL_HIGH]; + + /* + * Now compute which IRQs must be blocked when servicing any + * given IRQ. + */ + for (irq = 0; irq < NIRQ; irq++) { + int maxirq = IPL_NONE; + 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)) + maxirq = ih->ih_ipl > maxirq ? ih->ih_ipl : maxirq; + iq->iq_irq = maxirq; + } +} + +void +i80321_do_pending(void) +{ + static int processing = 0; + int new, oldirqstate; + + oldirqstate = disable_interrupts(I32_bit); + + if (processing) { + restore_interrupts(oldirqstate); + return; + } + + processing = 1; + + new = current_ipl_level; + + +#define DO_SOFTINT(si) \ + if ((softint_ipending & ~i80321_imask[new]) & SI_TO_IRQBIT(si)){ \ + softint_ipending &= ~SI_TO_IRQBIT(si); \ + current_ipl_level |= si_to_ipl[(si)]; \ + restore_interrupts(oldirqstate); \ + softintr_dispatch(si); \ + oldirqstate = disable_interrupts(I32_bit); \ + current_ipl_level = new; \ + } + + do { + DO_SOFTINT(SI_SOFTSERIAL); + DO_SOFTINT(SI_SOFTNET); + DO_SOFTINT(SI_SOFTCLOCK); + DO_SOFTINT(SI_SOFT); + } while( softint_ipending & i80321_imask[current_ipl_level] ); + + processing = 0; + restore_interrupts(oldirqstate); +} + +int spl_debug; +int nesting; +void +splx(int new) +{ + + int oldirqstate, hwpend; + + current_ipl_level = new; + + hwpend = (i80321_ipending & ICU_INT_HWMASK) & ~i80321_imask[new]; + if (hwpend != 0) { + oldirqstate = disable_interrupts(I32_bit); + intr_enabled |= hwpend; + i80321_set_intrmask(); + restore_interrupts(oldirqstate); + } + if (spl_debug) { + nesting ++; + if (nesting == 1) + printf("sX %d\n", new); + nesting --; + } + + if ((softint_ipending & INT_SWMASK) & ~i80321_imask[new]) + i80321_do_pending(); +} + +int +_spllower(int ipl) +{ + + extern int i80321_imask[]; + int old = current_ipl_level; + + splx(i80321_imask[ipl]); + if (spl_debug) { + nesting ++; + if (nesting == 1) + printf("sL %d\n", ipl); + nesting --; + } + return(old); +} + +int +_splraise(int ipl) +{ + + int old; + + old = current_ipl_level; + current_ipl_level = ipl; + if (spl_debug) { + nesting ++; + if (nesting == 1) + printf("sR %d\n", ipl); + nesting --; + } + + return (old); +} + +void +_setsoftintr(int si) +{ + int oldirqstate; + + oldirqstate = disable_interrupts(I32_bit); + softint_ipending |= SI_TO_IRQBIT(si); + restore_interrupts(oldirqstate); + + /* Process unmasked pending soft interrupts. */ + if ((softint_ipending & INT_SWMASK) & ~i80321_imask[current_ipl_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(); +} + +struct { + int id; + struct evcount ev; +} i80321_spur[NIRQ]; + +/* + * 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); + + i80321_spur[i].id = i; + evcount_attach(&i80321_spur[i].ev, "spur", + (void *)&i80321_spur[i].id, &evcount_intr); + } + + 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, + char *name) +{ + 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_name = name; + ih->ih_irq = irq; + + iq = &intrq[irq]; + + if (name != NULL) + evcount_attach(&ih->ih_count, name, (void *)&ih->ih_irq, + &evcount_intr); + + /* 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); + if (ih->ih_name != NULL) + evcount_detach(&ih->ih_count); + + i80321_intr_calculate_masks(); + + restore_interrupts(oldirqstate); +} + +void +i80321_irq_handler(void *v) +{ + struct clockframe *frame = v; + struct intrq *iq; + struct intrhand *ih; + int oldirqstate, pipl, irq, ibit, hwpend; + int spur = 1; + + pipl = current_ipl_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); + +#if 0 + if (irq != 9) + printf("irq %d\n", irq); +#endif + + hwpend &= ~ibit; + + if (i80321_imask[pipl] & ibit) { + /* + * IRQ is masked; mark it as pending and check + * the next one. Note: the IRQ is already disabled. + */ + i80321_ipending |= ibit; + continue; + } + + i80321_ipending &= ~ibit; + + iq = &intrq[irq]; + uvmexp.intrs++; + current_ipl_level |= iq->iq_irq; + oldirqstate = enable_interrupts(I32_bit); + for (ih = TAILQ_FIRST(&iq->iq_list); ih != NULL; + ih = TAILQ_NEXT(ih, ih_list)) { + if ((*ih->ih_func)(ih->ih_arg ? ih->ih_arg : frame)) { + ih->ih_count.ec_count++; + spur = 0; + } + } + restore_interrupts(oldirqstate); + + if (spur == 1) + i80321_spur[irq].ev.ec_count++; + + current_ipl_level = pipl; + + /* Re-enable this interrupt now that's it's cleared. */ + intr_enabled |= ibit; + i80321_set_intrmask(); + + /* + * Don't forget to include interrupts which may have + * arrived in the meantime. + */ + hwpend |= ((i80321_ipending & ICU_INT_HWMASK) & ~i80321_imask[pipl]); + } + + /* Check for pendings soft intrs. */ + if ((softint_ipending & INT_SWMASK) & ~i80321_imask[current_ipl_level]) { + oldirqstate = enable_interrupts(I32_bit); + i80321_do_pending(); + restore_interrupts(oldirqstate); + } +} +uint32_t get_pending_irq(void); +uint32_t +get_pending_irq() +{ + uint32_t pending; +#if 1 + uint32_t ointr_enabled; + uint32_t oldirqstate; + oldirqstate = disable_interrupts(I32_bit); + ointr_enabled = intr_enabled; + intr_enabled = 0xffffffff; + __asm volatile("mcr p6, 0, %0, c0, c0, 0":: "r" (0xffffffff)); + i80321_set_intrmask(); +#endif + __asm volatile("mrc p6, 0, %0, c8, c0, 0" + : "=r" (pending)); +#if 1 + intr_enabled = ointr_enabled; + i80321_set_intrmask(); + restore_interrupts(oldirqstate); +#endif + return pending; +} diff --git a/sys/arch/arm/xscale/i80321_mcu.c b/sys/arch/arm/xscale/i80321_mcu.c new file mode 100644 index 00000000000..64620b17ca4 --- /dev/null +++ b/sys/arch/arm/xscale/i80321_mcu.c @@ -0,0 +1,86 @@ +/* $NetBSD: i80321_mcu.c,v 1.3 2005/12/11 12:16:51 christos 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 <sys/param.h> +#include <sys/systm.h> + +#include <machine/bus.h> + +#include <arm/xscale/i80321reg.h> +#include <arm/xscale/i80321var.h> + +/* + * 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 00000000000..57e9f1bb64e --- /dev/null +++ b/sys/arch/arm/xscale/i80321_pci.c @@ -0,0 +1,261 @@ +/* $NetBSD: i80321_pci.c,v 1.7 2005/12/15 01:44:00 briggs 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 <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> +#include <sys/extent.h> +#include <sys/malloc.h> + +#include <uvm/uvm_extern.h> + +#include <machine/bus.h> + +#include <arm/xscale/i80321reg.h> +#include <arm/xscale/i80321var.h> + +#include <dev/pci/ppbreg.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_offset, + 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); + + aprint_normal("%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 +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); + /* + * NOTE: PCI-X requires that that devices updated their + * PCIXSR on every config write with the device number + * specified in AD[15:11]. If we don't set this field, + * each device could end of thinking it is at device 0, + * which can cause a number of problems. Doing this + * unconditionally should be OK when only PCI devices + * are present. + */ + ps->ps_addr_val = (1U << (ps->ps_d + 16)) | + (ps->ps_d << 11) | (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); + +#if 0 + if (rv != 0xffffffff) + printf("conf read %x %x %x %x: %x\n", + ps.ps_b, ps.ps_d, ps.ps_f, offset, rv); +#endif + + 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_space.c b/sys/arch/arm/xscale/i80321_space.c new file mode 100644 index 00000000000..cfcbcf6a7ea --- /dev/null +++ b/sys/arch/arm/xscale/i80321_space.c @@ -0,0 +1,441 @@ +/* $NetBSD: i80321_space.c,v 1.9 2005/11/24 13:08:32 yamt 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 <sys/param.h> +#include <sys/systm.h> + +#include <uvm/uvm_extern.h> + +#include <machine/bus.h> + +#include <arm/xscale/i80321reg.h> +#include <arm/xscale/i80321var.h> + +/* Prototypes for all the bus_space structure functions */ +bs_protos(i80321); +bs_protos(i80321_io); +bs_protos(i80321_mem); +bs_protos(generic); +bs_protos(generic_armv4); +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 */ + i80321_bs_map, + i80321_bs_unmap, + i80321_bs_subregion, + + /* allocation/deallocation */ + NULL, + NULL, + + /* get kernel virtual address */ + i80321_bs_vaddr, + + /* mmap */ + i80321_bs_mmap, + + /* barrier */ + i80321_bs_barrier, + + /* read (single) */ + generic_bs_r_1, + generic_armv4_bs_r_2, + generic_bs_r_4, + bs_notimpl_bs_r_8, + + /* read multiple */ + generic_bs_rm_1, + generic_armv4_bs_rm_2, + generic_bs_rm_4, + bs_notimpl_bs_rm_8, + + /* read region */ + generic_bs_rr_1, + generic_armv4_bs_rr_2, + generic_bs_rr_4, + bs_notimpl_bs_rr_8, + + /* write (single) */ + generic_bs_w_1, + generic_armv4_bs_w_2, + generic_bs_w_4, + bs_notimpl_bs_w_8, + + /* write multiple */ + generic_bs_wm_1, + generic_armv4_bs_wm_2, + generic_bs_wm_4, + bs_notimpl_bs_wm_8, + + /* write region */ + generic_bs_wr_1, + generic_armv4_bs_wr_2, + generic_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, + generic_armv4_bs_sr_2, + generic_bs_sr_4, + bs_notimpl_bs_sr_8, + + /* copy */ + bs_notimpl_bs_c_1, + generic_armv4_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; +} + +int +i80321_bs_map(void *t, bus_addr_t bpa, bus_size_t size, int flag, + bus_space_handle_t *bshp) +{ + const struct pmap_devmap *pd; + paddr_t startpa, endpa, pa, pagecnt; + vaddr_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); + } + +#if 0 +printf("i80321_bs_map bpa %x, size %x flag %x\n", bpa, size, flag); +#endif + endpa = round_page(bpa + size); + startpa = trunc_page(bpa); + pagecnt = endpa - startpa; + + va = uvm_km_valloc(kernel_map, endpa - startpa); + if (va == 0) + return(ENOMEM); +#if 0 +printf("i80321_bs_map va %x pa %x, endpa %x, sz %x\n", va, startpa, + endpa, endpa-startpa); +#endif + + *bshp = (bus_space_handle_t)(va + (bpa - startpa)); + + for (pa = startpa; pagecnt > 0; + pa += PAGE_SIZE, va += PAGE_SIZE, pagecnt -= PAGE_SIZE) { + pmap_kenter_pa(va, pa, VM_PROT_READ | VM_PROT_WRITE); + if ((flag & BUS_SPACE_MAP_CACHEABLE) == 0) { + pte = vtopte(va); + *pte &= ~L2_S_CACHE_MASK; + PTE_SYNC(pte); + } + } + pmap_update(pmap_kernel()); + + return (0); +} + +void +i80321_bs_unmap(void *t, bus_space_handle_t bsh, bus_size_t size) +{ + vaddr_t va, endva; + + if (pmap_devmap_find_va(bsh, size) != NULL) { + /* Device was statically mapped; nothing to do. */ + return; + } + + endva = round_page(bsh + size); + va = trunc_page(bsh); + + pmap_kremove(va, endva - va); + uvm_km_free(kernel_map, va, endva - va); +} + + +/* *** 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; + 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; + } else if (bpa < 0x10000) { + busbase = 0; + } 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. + */ + bus_space_subregion(sc->sc_st, sc->sc_io_sh, (bpa - busbase), size, + bshp); + + 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"); +} + +void +i80321_io_bs_free(void *t, bus_space_handle_t bsh, bus_size_t size) +{ + + panic("i80321_io_bs_free(): not implemented"); +} + +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 flag, + bus_space_handle_t *bshp) +{ + + struct i80321_softc *sc = t; + vaddr_t va; + uint32_t busbase; + paddr_t pa, endpa, physbase; + pt_entry_t *pte; + +#if 0 +printf("i80321_bs_map bpa %x, size %x flag %x : %x %x \n", bpa, size, flag, + sc->sc_owin[0].owin_xlate_lo, + sc->sc_owin[0].owin_xlate_lo+ VERDE_OUT_XLATE_MEM_WIN_SIZE); +#endif + + 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; + busbase = 0; + physbase = sc->sc_iwin[1].iwin_xlate; + physbase = 0x40000000; /* COMPLETELY FUCKING WRONG */ + } else + return (EINVAL); + + if ((bpa + size) >= ( sc->sc_owin[0].owin_xlate_lo + + VERDE_OUT_XLATE_MEM_WIN_SIZE)) + return (EINVAL); + + /* + * Found the window -- PCI MEM space is now 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); +//printf("i80321_mem_bs_map bpa %x pa %x va %x sz %x\n", bpa, pa, va, endpa-pa); + +#if 0 +printf("i80321_bs_map va %x pa %x, endpa %x, sz %x\n", va, pa, + endpa, endpa-pa); +#endif + + *bshp = va + (bpa & PAGE_MASK); + + for (; pa < endpa; pa += PAGE_SIZE, va += PAGE_SIZE) { + pmap_kenter_pa(va, pa, VM_PROT_READ | VM_PROT_WRITE); + if ((flag & BUS_SPACE_MAP_CACHEABLE) == 0) { + pte = vtopte(va); + *pte &= ~L2_S_CACHE_MASK; + PTE_SYNC(pte); + } + } + 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); + + pmap_kremove(va, endva - va); + pmap_update(pmap_kernel()); + + /* 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"); +} + +void +i80321_mem_bs_free(void *t, bus_space_handle_t bsh, bus_size_t size) +{ + + panic("i80321_mem_bs_free(): not implemented"); +} + +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_timer.c b/sys/arch/arm/xscale/i80321_timer.c new file mode 100644 index 00000000000..7913136d855 --- /dev/null +++ b/sys/arch/arm/xscale/i80321_timer.c @@ -0,0 +1,435 @@ +/* $NetBSD: i80321_timer.c,v 1.13 2005/12/24 20:06:52 perry 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 <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/time.h> + +#include <dev/clock_subr.h> + +#include <machine/bus.h> +#include <arm/cpufunc.h> + +#include <arm/xscale/i80321reg.h> +#include <arm/xscale/i80321var.h> + +void (*i80321_hardclock_hook)(void); + +#ifndef COUNTS_PER_SEC +#define COUNTS_PER_SEC 200000000 /* 200MHz */ +#endif +#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); +} + +int foo(void *); +int +foo(void *v) +{ + return 0; +} +/* + * cpu_initclocks: + * + * Initialize the clock and get them going. + */ +void +cpu_initclocks(void) +{ + u_int oldirqstate; +#if defined(PERFCTRS) + void *pmu_ih; +#endif + + 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, "clock"); +#if 1 +i80321_intr_establish(ICU_INT_TMR0, IPL_TTY, + foo, NULL, "dummyclock"); +#endif + + if (clock_ih == NULL) + panic("cpu_initclocks: unable to register timer interrupt"); + +#if defined(PERFCTRS) + pmu_ih = i80321_intr_establish(ICU_INT_PMU, IPL_STATCLOCK, + xscale_pmc_dispatch, NULL, "pmu"); + if (pmu_ih == NULL) + panic("cpu_initclocks: unable to register timer interrupt"); +#endif + + /* 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 newhz) +{ + + /* + * 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; + } + } +} + +todr_chip_handle_t todr_handle; + +#if 0 +/* + * todr_attach: + * + * Set the specified time-of-day register as the system real-time clock. + */ +void +todr_attach(todr_chip_handle_t todr) +{ + + if (todr_handle) + panic("todr_attach: rtc already configured"); + todr_handle = todr; +} +#endif + +/* + * inittodr: + * + * Initialize time from the time-of-day register. + */ +#define MINYEAR 2003 /* minimum plausible year */ +void +inittodr(time_t base) +{ + time_t deltat; + int badbase; + + if (base < (MINYEAR - 1970) * SECYR) { + printf("WARNING: preposterous time in file system"); + /* read the system clock anyway */ + base = (MINYEAR - 1970) * SECYR; + badbase = 1; + } else + badbase = 0; + + if (todr_handle == NULL || +/* todr_gettime(todr_handle, &time) != 0 || */ + time.tv_sec == 0) { + /* + * Believe the time in the file system for lack of + * anything better, resetting the TODR. + */ + time.tv_sec = base; + time.tv_usec = 0; + if (todr_handle != NULL && !badbase) { + printf("WARNING: preposterous clock chip time\n"); + resettodr(); + } + goto bad; + } + + if (!badbase) { + /* + * See if we gained/lost two or more days; if + * so, assume something is amiss. + */ + deltat = time.tv_sec - base; + if (deltat < 0) + deltat = -deltat; + if (deltat < 2 * SECDAY) + return; /* all is well */ + printf("WARNING: clock %s %ld days\n", + time.tv_sec < base ? "lost" : "gained", + (long)deltat / SECDAY); + } + bad: + printf("WARNING: CHECK AND RESET THE DATE!\n"); +} + +/* + * resettodr: + * + * Reset the time-of-day register with the current time. + */ +void +resettodr(void) +{ + + if (time.tv_sec == 0) + return; + + if (todr_handle != NULL /* && */ + /* todr_settime(todr_handle, &time) != 0 */) + printf("resettodr: failed to set time\n"); +} + +/* + * clockhandler: + * + * Handle the hardclock interrupt. + */ +int poll_console(void); +int +clockhandler(void *arg) +{ + struct clockframe *frame = arg; + + tisr_write(TISR_TMR0); + + hardclock(frame); + + if (i80321_hardclock_hook != NULL) + (*i80321_hardclock_hook)(); + + poll_console(); + return (1); +} diff --git a/sys/arch/arm/xscale/i80321reg.h b/sys/arch/arm/xscale/i80321reg.h new file mode 100644 index 00000000000..ea44cb45ff2 --- /dev/null +++ b/sys/arch/arm/xscale/i80321reg.h @@ -0,0 +1,502 @@ +/* $NetBSD: i80321reg.h,v 1.15 2005/12/11 12:16:51 christos 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 0x00001700UL + +/* + * Peripheral Memory Mapped Registers. Defined as offsets + * from the VERDE_PMMR_BASE. + */ +#define VERDE_ATU_BASE 0x0100 +#define VERDE_ATU_SIZE 0x0100 + +#define VERDE_MU_BASE 0x0300 +#define VERDE_MU_SIZE 0x0100 + +#define VERDE_DMA_BASE 0x0400 +#define VERDE_DMA_BASE0 (VERDE_DMA_BASE + 0x00) +#define VERDE_DMA_BASE1 (VERDE_DMA_BASE + 0x40) +#define VERDE_DMA_SIZE 0x0100 +#define VERDE_DMA_CHSIZE 0x0040 + +#define VERDE_MCU_BASE 0x0500 +#define VERDE_MCU_SIZE 0x0100 + +#define VERDE_SSP_BASE 0x0600 +#define VERDE_SSP_SIZE 0x0080 + +#define VERDE_PBIU_BASE 0x0680 +#define VERDE_PBIU_SIZE 0x0080 + +#define VERDE_AAU_BASE 0x0800 +#define VERDE_AAU_SIZE 0x0100 + +#define VERDE_I2C_BASE 0x1680 +#define VERDE_I2C_BASE0 (VERDE_I2C_BASE + 0x00) +#define VERDE_I2C_BASE1 (VERDE_I2C_BASE + 0x20) +#define VERDE_I2C_SIZE 0x0080 +#define VERDE_I2C_CHSIZE 0x0020 + +/* + * 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) & 0xff00) >> 8) +#define PCIXSR_DEVNO(x) (((x) & 0xf8) >> 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 WDTCR_ENABLE1 0x1e1e1e1e +#define WDTCR_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 0xffffe1ec + */ + +#define ICU_PIRSR 0x01ec +#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_XINT0 27 /* external interrupts */ +#define ICU_INT_XINT(x) ((x) + ICU_INT_XINT0) +#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_bit23 23 +#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 & \ + ~((1 << ICU_INT_bit26) | \ + (1 << ICU_INT_bit22) | \ + (1 << ICU_INT_bit5) | \ + (1 << ICU_INT_bit4))) + +/* + * SSP Serial Port + */ + +#define SSP_SSCR0 0x00 /* SSC control 0 */ +#define SSP_SSCR1 0x04 /* SSC control 1 */ +#define SSP_SSSR 0x08 /* SSP status */ +#define SSP_SSITR 0x0c /* SSP interrupt test */ +#define SSP_SSDR 0x10 /* SSP data */ + +#define SSP_SSCR0_DSIZE(x) ((x) - 1)/* data size: 4..16 */ +#define SSP_SSCR0_FRF_SPI (0 << 4) /* Motorola Serial Periph Iface */ +#define SSP_SSCR0_FRF_SSP (1U << 4)/* TI Sync. Serial Protocol */ +#define SSP_SSCR0_FRF_UWIRE (2U << 4)/* NatSemi Microwire */ +#define SSP_SSCR0_FRF_rsvd (3U << 4)/* reserved */ +#define SSP_SSCR0_ECS (1U << 6)/* external clock select */ +#define SSP_SSCR0_SSE (1U << 7)/* sync. serial port enable */ +#define SSP_SSCR0_SCR(x) ((x) << 8)/* serial clock rate */ + /* bit rate = 3.6864 * 10e6 / + (2 * (SCR + 1)) */ + +#define SSP_SSCR1_RIE (1U << 0)/* Rx FIFO interrupt enable */ +#define SSP_SSCR1_TIE (1U << 1)/* Tx FIFO interrupt enable */ +#define SSP_SSCR1_LBM (1U << 2)/* loopback mode enable */ +#define SSP_SSCR1_SPO (1U << 3)/* Moto SPI SSCLK pol. (1 = high) */ +#define SSP_SSCR1_SPH (1U << 4)/* Moto SPI SSCLK phase: + 0 = inactive full at start, + 1/2 at end of frame + 1 = inactive 1/2 at start, + full at end of frame */ +#define SSP_SSCR1_MWDS (1U << 5)/* Microwire data size: + 0 = 8 bit + 1 = 16 bit */ +#define SSP_SSCR1_TFT (((x) - 1) << 6) /* Tx FIFO threshold */ +#define SSP_SSCR1_RFT (((x) - 1) << 10)/* Rx FIFO threshold */ +#define SSP_SSCR1_EFWR (1U << 14)/* enab. FIFO write/read */ +#define SSP_SSCR1_STRF (1U << 15)/* FIFO write/read FIFO select: + 0 = Tx FIFO + 1 = Rx FIFO */ + +#define SSP_SSSR_TNF (1U << 2)/* Tx FIFO not full */ +#define SSP_SSSR_RNE (1U << 3)/* Rx FIFO not empty */ +#define SSP_SSSR_BSY (1U << 4)/* SSP is busy */ +#define SSP_SSSR_TFS (1U << 5)/* Tx FIFO service request */ +#define SSP_SSSR_RFS (1U << 6)/* Rx FIFO service request */ +#define SSP_SSSR_ROR (1U << 7)/* Rx FIFO overrun */ +#define SSP_SSSR_TFL(x) (((x) >> 8) & 0xf) /* Tx FIFO level */ +#define SSP_SSSR_RFL(x) (((x) >> 12) & 0xf)/* Rx FIFO level */ + +#define SSP_SSITR_TTFS (1U << 5)/* Test Tx FIFO service */ +#define SSP_SSITR_TRFS (1U << 6)/* Test Rx FIFO service */ +#define SSP_SSITR_TROR (1U << 7)/* Test Rx overrun */ + +/* + * Peripheral Bus Interface Unit + */ + +#define PBIU_PBCR 0x00 /* PBIU Control Register */ +#define PBIU_PBBAR0 0x08 /* PBIU Base Address Register 0 */ +#define PBIU_PBLR0 0x0c /* PBIU Limit Register 0 */ +#define PBIU_PBBAR1 0x10 /* PBIU Base Address Register 1 */ +#define PBIU_PBLR1 0x14 /* PBIU Limit Register 1 */ +#define PBIU_PBBAR2 0x18 /* PBIU Base Address Register 2 */ +#define PBIU_PBLR2 0x1c /* PBIU Limit Register 2 */ +#define PBIU_PBBAR3 0x20 /* PBIU Base Address Register 3 */ +#define PBIU_PBLR3 0x24 /* PBIU Limit Register 3 */ +#define PBIU_PBBAR4 0x28 /* PBIU Base Address Register 4 */ +#define PBIU_PBLR4 0x2c /* PBIU Limit Register 4 */ +#define PBIU_PBBAR5 0x30 /* PBIU Base Address Register 5 */ +#define PBIU_PBLR5 0x34 /* PBIU Limit Register 5 */ +#define PBIU_DSCR 0x38 /* PBIU Drive Strength Control Reg. */ +#define PBIU_MBR0 0x40 /* PBIU Memory-less Boot Reg. 0 */ +#define PBIU_MBR1 0x60 /* PBIU Memory-less Boot Reg. 1 */ +#define PBIU_MBR2 0x64 /* PBIU Memory-less Boot Reg. 2 */ + +#define PBIU_PBCR_PBIEN (1 << 0) +#define PBIU_PBCR_PBI100 (1 << 1) +#define PBIU_PBCR_PBI66 (2 << 1) +#define PBIU_PBCR_PBI33 (3 << 1) +#define PBIU_PBCR_PBBEN (1 << 3) + +#define PBIU_PBARx_WIDTH8 (0 << 0) +#define PBIU_PBARx_WIDTH16 (1 << 0) +#define PBIU_PBARx_WIDTH32 (2 << 0) +#define PBIU_PBARx_ADWAIT4 (0 << 2) +#define PBIU_PBARx_ADWAIT8 (1 << 2) +#define PBIU_PBARx_ADWAIT12 (2 << 2) +#define PBIU_PBARx_ADWAIT16 (3 << 2) +#define PBIU_PBARx_ADWAIT20 (4 << 2) +#define PBIU_PBARx_RCWAIT1 (0 << 6) +#define PBIU_PBARx_RCWAIT4 (1 << 6) +#define PBIU_PBARx_RCWAIT8 (2 << 6) +#define PBIU_PBARx_RCWAIT12 (3 << 6) +#define PBIU_PBARx_RCWAIT16 (4 << 6) +#define PBIU_PBARx_RCWAIT20 (5 << 6) +#define PBIU_PBARx_FWE (1 << 9) +#define PBIU_BASE_MASK 0xfffff000U + +#define PBIU_PBLRx_SIZE(x) (~((x) - 1)) + +/* + * Messaging Unit + */ +#define MU_IMR0 0x0010 /* MU Inbound Message Register 0 */ +#define MU_IMR1 0x0014 /* MU Inbound Message Register 1 */ +#define MU_OMR0 0x0018 /* MU Outbound Message Register 0 */ +#define MU_OMR1 0x001c /* MU Outbound Message Register 1 */ +#define MU_IDR 0x0020 /* MU Inbound Doorbell Register */ +#define MU_IISR 0x0024 /* MU Inbound Interrupt Status Reg */ +#define MU_IIMR 0x0028 /* MU Inbound Interrupt Mask Reg */ +#define MU_ODR 0x002c /* MU Outbound Doorbell Register */ +#define MU_OISR 0x0030 /* MU Outbound Interrupt Status Reg */ +#define MU_OIMR 0x0034 /* MU Outbound Interrupt Mask Reg */ +#define MU_MUCR 0x0050 /* MU Configuration Register */ +#define MU_QBAR 0x0054 /* MU Queue Base Address Register */ +#define MU_IFHPR 0x0060 /* MU Inbound Free Head Pointer Reg */ +#define MU_IFTPR 0x0064 /* MU Inbound Free Tail Pointer Reg */ +#define MU_IPHPR 0x0068 /* MU Inbound Post Head Pointer Reg */ +#define MU_IPTPR 0x006c /* MU Inbound Post Tail Pointer Reg */ +#define MU_OFHPR 0x0070 /* MU Outbound Free Head Pointer Reg */ +#define MU_OFTPR 0x0074 /* MU Outbound Free Tail Pointer Reg */ +#define MU_OPHPR 0x0078 /* MU Outbound Post Head Pointer Reg */ +#define MU_OPTPR 0x007c /* MU Outbound Post Tail Pointer Reg */ +#define MU_IAR 0x0080 /* MU Index Address Register */ + +#define MU_IIMR_IRI (1 << 6) /* Index Register Interrupt */ +#define MU_IIMR_OFQFI (1 << 5) /* Outbound Free Queue Full Int. */ +#define MU_IIMR_IPQI (1 << 4) /* Inbound Post Queue Interrupt */ +#define MU_IIMR_EDI (1 << 3) /* Error Doorbell Interrupt */ +#define MU_IIMR_IDI (1 << 2) /* Inbound Doorbell Interrupt */ +#define MU_IIMR_IM1I (1 << 1) /* Inbound Message 1 Interrupt */ +#define MU_IIMR_IM0I (1 << 0) /* Inbound Message 0 Interrupt */ + +#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 00000000000..1b642726693 --- /dev/null +++ b/sys/arch/arm/xscale/i80321var.h @@ -0,0 +1,222 @@ +/* $NetBSD: i80321var.h,v 1.10 2005/12/15 01:44:00 briggs Exp $ */ + +/* + * Copyright (c) 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. + */ + +#ifndef _ARM_XSCALE_I80321VAR_H_ +#define _ARM_XSCALE_I80321VAR_H_ + +#include <sys/queue.h> +#include <sys/gpio.h> +#include <sys/evcount.h> +#include <dev/pci/pcivar.h> +#include <dev/gpio/gpiovar.h> + +/* + * 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 */ + struct evcount ih_count; + char *ih_name; +}; + +#define IRQNAMESIZE sizeof("iop321 irq 31") + +struct intrq { + TAILQ_HEAD(, intrhand) iq_list; /* handler list */ + int iq_irq; /* IRQ to mask while handling */ + int iq_levels; /* IPL_*'s this IRQ has */ + int iq_ist; /* share type */ +}; + +struct config_bus_space { + u_int32_t bus_base; + u_int32_t bus_size; + int bus_io; +}; + +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; + +#ifdef BULLSHIT + /* + * 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 */ +#else + bus_space_handle_t sc_io_sh; +#endif + + /* + * 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. + * The offset is to keep the actual used I/O address away from 0, + * which can be bad if, say, an i8254x gig-e chip gets mapped there. + * The 0 value apparently looks like "unconfigured" to the controller + * and it ignores writes to that region (it doesn't cause a bus fault, + * it just ignores them--leading to a non-functional controller). The + * wm(4) driver usually uses memory-mapped regions, but does use the + * I/O-mapped region for reset operations in order to work around a + * bug in the chip. + * Iyonix, while using sc_ioout_xlate 0 needs an offset of 0, too, in + * order to function properly. These values are both set in the + * port-specific i80321_mainbus_attach() routine. + */ + uint32_t sc_ioout_xlate; + uint32_t sc_ioout_xlate_offset; + + /* 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; + + /* DMA window info for PCI DMA. */ + struct arm32_dma_range sc_pci_dma_range; + + /* GPIO state */ + uint8_t sc_gpio_dir; /* GPIO pin direction (1 == output) */ + uint8_t sc_gpio_val; /* GPIO output pin value */ + +#define I80219_GPIO_NPINS 8 + /* GPIO for 80219 -XXX */ + struct gpio_chipset_tag sc_gpio_gc; + struct gpio_pin sc_gpio_pins[I80219_GPIO_NPINS]; + + /* DMA tag for local devices. */ + struct arm32_bus_dma_tag sc_local_dmat; + + /* Structures to do bus fixup */ + int nbogus; + struct extent *extent_mem; + struct extent *extent_port; + struct config_bus_space sc_membus_space; + struct config_bus_space sc_iobus_space; + + +}; + +/* + * Arguments used to attach IOP built-ins. + */ +struct iopxs_attach_args { + const char *ia_name; /* name of device */ + bus_space_tag_t ia_st; /* space tag */ + bus_space_handle_t ia_sh;/* handle of IOP base */ + bus_dma_tag_t ia_dmat; /* DMA tag */ + bus_addr_t ia_offset; /* offset of device from IOP base */ + bus_size_t ia_size; /* size of sub-device */ +}; + +extern struct bus_space i80321_bs_tag; +extern struct i80321_softc *i80321_softc; +extern const char *i80321_irqnames[]; + +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 *, char *); +void i80321_intr_disestablish(void *); + +void i80321_gpio_set_direction(uint8_t, uint8_t); +void i80321_gpio_set_val(uint8_t, uint8_t); +uint8_t i80321_gpio_get_val(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_local_dma_init(struct i80321_softc *sc); + +void i80321_pci_init(pci_chipset_tag_t, void *); + +void i80321_attach(struct i80321_softc *); +#endif /* _ARM_XSCALE_I80321VAR_H_ */ diff --git a/sys/arch/arm/xscale/xscalereg.h b/sys/arch/arm/xscale/xscalereg.h new file mode 100644 index 00000000000..829e1506f7f --- /dev/null +++ b/sys/arch/arm/xscale/xscalereg.h @@ -0,0 +1,71 @@ +/* $NetBSD: xscalereg.h,v 1.2 2002/08/07 05:15:02 briggs Exp $ */ + +/* + * Copyright (c) 2001 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_XSCALEREG_H_ +#define _ARM_XSCALE_XSCALEREG_H_ + +/* + * Register definitions for the Intel XScale processor core. + */ + +/* + * Performance Monitoring Unit (CP14) + * + * CP14.0 Performance Monitor Control Register + * CP14.1 Clock Counter + * CP14.2 Performance Counter Register 0 + * CP14.3 Performance Counter Register 1 + */ + +#define PMNC_E 0x00000001 /* enable counters */ +#define PMNC_P 0x00000002 /* reset both PMNs to 0 */ +#define PMNC_C 0x00000004 /* clock counter reset */ +#define PMNC_D 0x00000008 /* clock counter / 64 */ +#define PMNC_PMN0_IE 0x00000010 /* enable PMN0 interrupt */ +#define PMNC_PMN1_IE 0x00000020 /* enable PMN1 interrupt */ +#define PMNC_CC_IE 0x00000040 /* enable clock counter interrupt */ +#define PMNC_PMN0_IF 0x00000100 /* PMN0 overflow/interrupt */ +#define PMNC_PMN1_IF 0x00000200 /* PMN1 overflow/interrupt */ +#define PMNC_CC_IF 0x00000400 /* clock counter overflow/interrupt */ +#define PMNC_EVCNT0_MASK 0x000ff000 /* event to count for PMN0 */ +#define PMNC_EVCNT0_SHIFT 12 +#define PMNC_EVCNT1_MASK 0x0ff00000 /* event to count for PMN1 */ +#define PMNC_EVCNT1_SHIFT 20 + +void xscale_pmu_init(void); + +#endif /* _ARM_XSCALE_XSCALEREG_H_ */ |