diff options
Diffstat (limited to 'sys/alpha/pci/tsunami.c')
-rw-r--r-- | sys/alpha/pci/tsunami.c | 576 |
1 files changed, 576 insertions, 0 deletions
diff --git a/sys/alpha/pci/tsunami.c b/sys/alpha/pci/tsunami.c new file mode 100644 index 0000000..70278d3 --- /dev/null +++ b/sys/alpha/pci/tsunami.c @@ -0,0 +1,576 @@ +/*- + * Copyright (c) 1999 Andrew Gallatin + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id $ + */ + +#include "opt_cpu.h" + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/module.h> +#include <sys/bus.h> +#include <machine/bus.h> +#include <sys/rman.h> +#include <sys/malloc.h> + +#include <pci/pcivar.h> +#include <alpha/pci/tsunamireg.h> +#include <alpha/pci/tsunamivar.h> +#include <alpha/pci/pcibus.h> +#include <machine/bwx.h> +#include <machine/intr.h> +#include <machine/intrcnt.h> +#include <machine/cpuconf.h> +#include <machine/rpb.h> +#include <machine/resource.h> + +#define KV(pa) ALPHA_PHYS_TO_K0SEG(pa) + +static devclass_t tsunami_devclass; +static device_t tsunami0; /* XXX only one for now */ +extern vm_offset_t alpha_XXX_dmamap_or; +struct tsunami_softc { + int junk; /* no softc */ +}; + +#define TSUNAMI_SOFTC(dev) (struct tsunami_softc*) device_get_softc(dev) + +static alpha_chipset_inb_t tsunami_inb; +static alpha_chipset_inw_t tsunami_inw; +static alpha_chipset_inl_t tsunami_inl; +static alpha_chipset_outb_t tsunami_outb; +static alpha_chipset_outw_t tsunami_outw; +static alpha_chipset_outl_t tsunami_outl; +static alpha_chipset_readb_t tsunami_readb; +static alpha_chipset_readw_t tsunami_readw; +static alpha_chipset_readl_t tsunami_readl; +static alpha_chipset_writeb_t tsunami_writeb; +static alpha_chipset_writew_t tsunami_writew; +static alpha_chipset_writel_t tsunami_writel; +static alpha_chipset_maxdevs_t tsunami_maxdevs; +static alpha_chipset_cfgreadb_t tsunami_cfgreadb; +static alpha_chipset_cfgreadw_t tsunami_cfgreadw; +static alpha_chipset_cfgreadl_t tsunami_cfgreadl; +static alpha_chipset_cfgwriteb_t tsunami_cfgwriteb; +static alpha_chipset_cfgwritew_t tsunami_cfgwritew; +static alpha_chipset_cfgwritel_t tsunami_cfgwritel; +static alpha_chipset_addrcvt_t tsunami_cvt_dense, tsunami_cvt_bwx; + +static alpha_chipset_read_hae_t tsunami_read_hae; +static alpha_chipset_write_hae_t tsunami_write_hae; + +static alpha_chipset_t tsunami_chipset = { + tsunami_inb, + tsunami_inw, + tsunami_inl, + tsunami_outb, + tsunami_outw, + tsunami_outl, + tsunami_readb, + tsunami_readw, + tsunami_readl, + tsunami_writeb, + tsunami_writew, + tsunami_writel, + tsunami_maxdevs, + tsunami_cfgreadb, + tsunami_cfgreadw, + tsunami_cfgreadl, + tsunami_cfgwriteb, + tsunami_cfgwritew, + tsunami_cfgwritel, + tsunami_cvt_dense, + tsunami_cvt_bwx, + tsunami_read_hae, + tsunami_write_hae, +}; + +/* + * This setup will only allow for one additional hose + */ + +#define ADDR_TO_HOSE(x) ((x) >> 31) +#define STRIP_HOSE(x) ((x) & 0x7fffffff) + +static void tsunami_intr_enable __P((int)); +static void tsunami_intr_disable __P((int)); + +static u_int8_t +tsunami_inb(u_int32_t port) +{ + int hose = ADDR_TO_HOSE(port); + port = STRIP_HOSE(port); + alpha_mb(); + return ldbu(KV(TSUNAMI_IO(hose) + port)); +} + +static u_int16_t +tsunami_inw(u_int32_t port) +{ + int hose = ADDR_TO_HOSE(port); + port = STRIP_HOSE(port); + alpha_mb(); + return ldwu(KV(TSUNAMI_IO(hose) + port)); +} + +static u_int32_t +tsunami_inl(u_int32_t port) +{ + int hose = ADDR_TO_HOSE(port); + port = STRIP_HOSE(port); + alpha_mb(); + return ldl(KV(TSUNAMI_IO(hose) + port)); +} + +static void +tsunami_outb(u_int32_t port, u_int8_t data) +{ + int hose = ADDR_TO_HOSE(port); + port = STRIP_HOSE(port); + stb(KV(TSUNAMI_IO(hose) + port), data); + alpha_mb(); +} + +static void +tsunami_outw(u_int32_t port, u_int16_t data) +{ + int hose = ADDR_TO_HOSE(port); + port = STRIP_HOSE(port); + stw(KV(TSUNAMI_IO(hose) + port), data); + alpha_mb(); +} + +static void +tsunami_outl(u_int32_t port, u_int32_t data) +{ + int hose = ADDR_TO_HOSE(port); + port = STRIP_HOSE(port); + stl(KV(TSUNAMI_IO(hose) + port), data); + alpha_mb(); +} + +static u_int8_t +tsunami_readb(u_int32_t pa) +{ + int hose = ADDR_TO_HOSE(pa); + pa = STRIP_HOSE(pa); + alpha_mb(); + return ldbu(KV(TSUNAMI_MEM(hose) + pa)); +} + +static u_int16_t +tsunami_readw(u_int32_t pa) +{ + int hose = ADDR_TO_HOSE(pa); + pa = STRIP_HOSE(pa); + alpha_mb(); + return ldwu(KV(TSUNAMI_MEM(hose) + pa)); +} + +static u_int32_t +tsunami_readl(u_int32_t pa) +{ + int hose = ADDR_TO_HOSE(pa); + pa = STRIP_HOSE(pa); + alpha_mb(); + return ldl(KV(TSUNAMI_MEM(hose) + pa)); +} + +static void +tsunami_writeb(u_int32_t pa, u_int8_t data) +{ + int hose = ADDR_TO_HOSE(pa); + pa = STRIP_HOSE(pa); + stb(KV(TSUNAMI_MEM(hose) + pa), data); + alpha_mb(); +} + +static void +tsunami_writew(u_int32_t pa, u_int16_t data) +{ + int hose = ADDR_TO_HOSE(pa); + pa = STRIP_HOSE(pa); + stw(KV(TSUNAMI_MEM(hose) + pa), data); + alpha_mb(); +} + +static void +tsunami_writel(u_int32_t pa, u_int32_t data) +{ + int hose = ADDR_TO_HOSE(pa); + pa = STRIP_HOSE(pa); + stl(KV(TSUNAMI_MEM(hose) + pa), data); + alpha_mb(); +} + +static int +tsunami_maxdevs(u_int b) +{ + return 12; /* XXX */ +} + +static void +tsunami_clear_abort(void) +{ + alpha_mb(); + alpha_pal_draina(); +} + +static int +tsunami_check_abort(void) +{ +/* u_int32_t errbits;*/ + int ba = 0; + + alpha_pal_draina(); + alpha_mb(); +#if 0 + errbits = REGVAL(TSUNAMI_CSR_TSUNAMI_ERR); + if (errbits & (TSUNAMI_ERR_RCVD_MAS_ABT|TSUNAMI_ERR_RCVD_TAR_ABT)) + ba = 1; + + if (errbits) { + REGVAL(TSUNAMI_CSR_TSUNAMI_ERR) = errbits; + alpha_mb(); + alpha_pal_draina(); + } +#endif + return ba; +} + +#define TSUNAMI_CFGADDR(b, s, f, r, h) \ + KV(TSUNAMI_CONF(h) | ((b) << 16) | ((s) << 11) | ((f) << 8) | (r)) + +#define CFGREAD(h, b, s, f, r, op, width, type) \ + int bus = tsunami_bus_within_hose(h, b); \ + vm_offset_t va = TSUNAMI_CFGADDR(bus, s, f, r, h); \ + type data; \ + tsunami_clear_abort(); \ + if (badaddr((caddr_t)va, width)) { \ + tsunami_check_abort(); \ + return ~0; \ + } \ + data = ##op##(va); \ + if (tsunami_check_abort()) \ + return ~0; \ + return data; + +#define CFWRITE(h, b, s, f, r, data, op, width) \ + int bus = tsunami_bus_within_hose(h, b); \ + vm_offset_t va = TSUNAMI_CFGADDR(bus, s, f, r, h); \ + tsunami_clear_abort(); \ + if (badaddr((caddr_t)va, width)) \ + return; \ + ##op##(va, data); \ + tsunami_check_abort(); + + + + +static u_int8_t +tsunami_cfgreadb(u_int h, u_int b, u_int s, u_int f, u_int r) +{ + CFGREAD(h, b, s, f, r, ldbu, 1, u_int8_t) +} + +static u_int16_t +tsunami_cfgreadw(u_int h, u_int b, u_int s, u_int f, u_int r) +{ + CFGREAD(h, b, s, f, r, ldwu, 2, u_int16_t) +} + +static u_int32_t +tsunami_cfgreadl(u_int h, u_int b, u_int s, u_int f, u_int r) +{ + CFGREAD(h, b, s, f, r, ldl, 4, u_int32_t) +} + +static void +tsunami_cfgwriteb(u_int h, u_int b, u_int s, u_int f, u_int r, u_int8_t data) +{ + CFWRITE(h, b, s, f, r, data, stb, 1) +} + +static void +tsunami_cfgwritew(u_int h, u_int b, u_int s, u_int f, u_int r, u_int16_t data) +{ + CFWRITE(h, b, s, f, r, data, stw, 2) +} + +static void +tsunami_cfgwritel(u_int h, u_int b, u_int s, u_int f, u_int r, u_int32_t data) +{ + CFWRITE(h, b, s, f, r, data, stl, 4) +} + + +vm_offset_t +tsunami_cvt_bwx(vm_offset_t addr) +{ + int hose; + vm_offset_t laddr; + laddr = addr & 0xffffffffUL; + hose = ADDR_TO_HOSE(laddr); + laddr = STRIP_HOSE(addr); + laddr |= TSUNAMI_MEM(hose); + return (KV(laddr)); +} + +vm_offset_t +tsunami_cvt_dense(vm_offset_t addr) +{ + return tsunami_cvt_bwx(addr); +} + + +/* + * There doesn't appear to be an hae on this platform + */ + + +static u_int64_t +tsunami_read_hae(void) +{ + return 0; +} + +static void +tsunami_write_hae(u_int64_t hae) +{ +} + +static int tsunami_probe(device_t dev); +static int tsunami_attach(device_t dev); +static int tsunami_setup_intr(device_t dev, device_t child, + struct resource *irq, int flags, + driver_intr_t *intr, void *arg, void **cookiep); +static int tsunami_teardown_intr(device_t dev, device_t child, + struct resource *irq, void *cookie); + +static device_method_t tsunami_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, tsunami_probe), + DEVMETHOD(device_attach, tsunami_attach), + + /* Bus interface */ + DEVMETHOD(bus_print_child, bus_generic_print_child), + DEVMETHOD(bus_alloc_resource, pci_alloc_resource), + DEVMETHOD(bus_release_resource, pci_release_resource), + DEVMETHOD(bus_activate_resource, pci_activate_resource), + DEVMETHOD(bus_deactivate_resource, pci_deactivate_resource), + DEVMETHOD(bus_setup_intr, tsunami_setup_intr), + DEVMETHOD(bus_teardown_intr, tsunami_teardown_intr), + + { 0, 0 } +}; + +static driver_t tsunami_driver = { + "tsunami", + tsunami_methods, + sizeof(struct tsunami_softc), +}; + +static void +pchip_init(tsunami_pchip *pchip, int index) +{ +#if 0 + + /* + * The code below, if active, would attempt to + * setup the DMA base and size registers of Window 0 + * to emulate the placement of the direct-mapped window + * on previous chipsets. + * + * HOWEVER: doing this means that a 64-bit card at device 11 + * would not be able to be setup for DMA. + * + * For now, we just trust the SRM console to set things up + * properly. This works on the xp1000, but may need to be + * to be revisited for other systems. + */ + + printf("initializing pchip%d\n", index); + pchip->wsba[0].reg = 1L | (1024*1024*1024U & 0xfff00000U); + pchip->wsm[0].reg = (1024*1024*1024U - 1) & 0xfff00000UL; + pchip->tba[0].reg = 0; + /* + * disable windows 1, 2 and 3 + */ + + + pchip->wsba[1].reg = 0; + pchip->wsba[2].reg = 0; + pchip->wsba[3].reg = 0; + + alpha_mb(); +#endif + +} + + +void +tsunami_init() +{ + static int initted = 0; + + if (initted) return; + initted = 1; + + chipset = tsunami_chipset; + platform.pci_intr_enable = tsunami_intr_enable; + platform.pci_intr_disable = tsunami_intr_disable; + alpha_XXX_dmamap_or = 2UL * 1024UL * 1024UL * 1024UL; + + if (platform.pci_intr_init) + platform.pci_intr_init(); +} + +static int +tsunami_probe(device_t dev) +{ + int *hose; + int i; + if (tsunami0) + return ENXIO; + tsunami0 = dev; + device_set_desc(dev, "21271 Core Logic chipset"); + + pci_init_resources(); + isa_init_intr(); + + for(i = 0; i < 2; i++) { + hose = malloc(sizeof(int), M_DEVBUF, M_NOWAIT); + *hose = i; + device_add_child(dev, "pcib", i, hose); + } + pchip_init(pchip0, 0); + pchip_init(pchip1, 1); + return 0; +} + + + +static int +tsunami_attach(device_t dev) +{ + tsunami_init(); + + if (!platform.iointr) /* XXX */ + set_iointr(alpha_dispatch_intr); + + snprintf(chipset_type, sizeof(chipset_type), "tsunami"); + chipset_bwx = 1; + + chipset_ports = TSUNAMI_IO(0); + chipset_memory = TSUNAMI_MEM(0); + chipset_dense = TSUNAMI_MEM(0); + bus_generic_attach(dev); + + return 0; +} + +static int +tsunami_setup_intr(device_t dev, device_t child, + struct resource *irq, int flags, + driver_intr_t *intr, void *arg, void **cookiep) +{ + int error; + + error = rman_activate_resource(irq); + if (error) + return error; + + error = alpha_setup_intr(0x900 + (irq->r_start << 4), + intr, arg, cookiep, + &intrcnt[INTRCNT_EB164_IRQ + irq->r_start]); + if (error) + return error; + + /* Enable PCI interrupt */ + platform.pci_intr_enable(irq->r_start); + + device_printf(child, "interrupting at TSUNAMI irq %d\n", + (int) irq->r_start); + + return 0; +} + +static int +tsunami_teardown_intr(device_t dev, device_t child, + struct resource *irq, void *cookie) +{ + + alpha_teardown_intr(cookie); + return rman_deactivate_resource(irq); + +} + + +/* + * Currently, all interrupts will be funneled through CPU 0 + */ + +static void +tsunami_intr_enable(int irq) +{ + volatile u_int64_t *mask; + u_int64_t saved_mask; + + mask = &cchip->dim0.reg; + saved_mask = *mask; + + saved_mask |= (1UL << (unsigned long)irq); + *mask = saved_mask; + alpha_mb(); + alpha_mb(); + saved_mask = *mask; + alpha_mb(); + alpha_mb(); +} + +static void +tsunami_intr_disable(int irq) +{ + volatile u_int64_t *mask; + u_int64_t saved_mask; + + mask = &cchip->dim0.reg; + saved_mask = *mask; + + saved_mask &= ~(1UL << (unsigned long)irq); + *mask = saved_mask; + alpha_mb(); + saved_mask = *mask; + alpha_mb(); + alpha_mb(); + +} + + + +DRIVER_MODULE(tsunami, root, tsunami_driver, tsunami_devclass, 0, 0); + |