diff options
author | Miod Vallat <miod@cvs.openbsd.org> | 2012-03-28 20:44:24 +0000 |
---|---|---|
committer | Miod Vallat <miod@cvs.openbsd.org> | 2012-03-28 20:44:24 +0000 |
commit | 6ea0ed8392999d052b79785548a577d7e55b7184 (patch) | |
tree | b4c5fb05563150bb09cc3d203971a18a2b5277bc /sys/arch/sgi/localbus/imc.c | |
parent | b71835f84a40d614f56816274c2400a719e82600 (diff) |
Work in progress support for the SGI Indigo, Indigo 2 and Indy systems
(IP20, IP22, IP24) in 64-bit mode, adapated from NetBSD. Currently limited
to headless operation, input and video drivers will get ported soon.
Should work on all R4000, R4440 and R5000 based systems. L2 cache on R5000SC
Indy not supported yet (coming soon), R4600 not supported yet either (coming
soon as well).
Tested to boot multiuser on: Indigo2 R4000SC, Indy R4000PC, Indy R4000SC,
Indy R5000SC, Indigo2 R4400SC. There are still glitches in the Ethernet driver
which are being looked at.
Expansion support is limited to the GIO E++ board; GIO boards with PCI-GIO
bridges not ported yet due to the lack of hardware, and this kind of driver
does not port blindly.
Most of this work comes from NetBSD, polishing and integration work, as well
as putting as many ``R4x00 in 64-bit mode'' erratas as necessary, by yours
truly.
More work is coming, as well as trying to get some easy way to boot install
kernels (as older PROM can only boot ECOFF binaries, which won't do for the
kernel).
Diffstat (limited to 'sys/arch/sgi/localbus/imc.c')
-rw-r--r-- | sys/arch/sgi/localbus/imc.c | 826 |
1 files changed, 826 insertions, 0 deletions
diff --git a/sys/arch/sgi/localbus/imc.c b/sys/arch/sgi/localbus/imc.c new file mode 100644 index 00000000000..c8544aa8788 --- /dev/null +++ b/sys/arch/sgi/localbus/imc.c @@ -0,0 +1,826 @@ +/* $OpenBSD: imc.c,v 1.1 2012/03/28 20:44:23 miod Exp $ */ +/* $NetBSD: imc.c,v 1.32 2011/07/01 18:53:46 dyoung Exp $ */ + +/* + * Copyright (c) 2012 Miodrag Vallat. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/* + * Copyright (c) 2001 Rafal K. Boni + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR 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/param.h> +#include <sys/device.h> +#include <sys/systm.h> + +#include <mips64/archtype.h> + +#include <machine/autoconf.h> +#include <machine/bus.h> +#include <machine/cpu.h> + +#include <sgi/sgi/ip22.h> +#include <sgi/localbus/imcreg.h> +#include <sgi/localbus/imcvar.h> + +#include <sgi/hpc/hpcreg.h> +#include <sgi/gio/giovar.h> + +#include "eisa.h" + +#if NEISA > 0 +#include <dev/eisa/eisavar.h> +#endif + +int imc_match(struct device *, void *, void *); +void imc_attach(struct device *, struct device *, void *); +int imc_print(void *, const char *); + +const struct cfattach imc_ca = { + sizeof(struct device), imc_match, imc_attach +}; + +struct cfdriver imc_cd = { + NULL, "imc", DV_DULL +}; + +uint32_t imc_bus_error(uint32_t, struct trap_frame *); +void imc_bus_reset(void); +int imc_watchdog_cb(void *, int); + +uint8_t imc_read_1(bus_space_tag_t, bus_space_handle_t, bus_size_t); +uint16_t imc_read_2(bus_space_tag_t, bus_space_handle_t, bus_size_t); +void imc_read_raw_2(bus_space_tag_t, bus_space_handle_t, bus_addr_t, + uint8_t *, bus_size_t); +void imc_write_1(bus_space_tag_t, bus_space_handle_t, bus_size_t, uint8_t); +void imc_write_2(bus_space_tag_t, bus_space_handle_t, bus_size_t, uint16_t); +void imc_write_raw_2(bus_space_tag_t, bus_space_handle_t, bus_addr_t, + const uint8_t *, bus_size_t); +uint32_t imc_read_4(bus_space_tag_t, bus_space_handle_t, bus_size_t); +uint64_t imc_read_8(bus_space_tag_t, bus_space_handle_t, bus_size_t); +void imc_write_4(bus_space_tag_t, bus_space_handle_t, bus_size_t, uint32_t); +void imc_write_8(bus_space_tag_t, bus_space_handle_t, bus_size_t, uint64_t); +void imc_read_raw_4(bus_space_tag_t, bus_space_handle_t, bus_addr_t, + uint8_t *, bus_size_t); +void imc_write_raw_4(bus_space_tag_t, bus_space_handle_t, bus_addr_t, + const uint8_t *, bus_size_t); +void imc_read_raw_8(bus_space_tag_t, bus_space_handle_t, bus_addr_t, + uint8_t *, bus_size_t); +void imc_write_raw_8(bus_space_tag_t, bus_space_handle_t, bus_addr_t, + const uint8_t *, bus_size_t); +int imc_space_map(bus_space_tag_t, bus_addr_t, bus_size_t, int, + bus_space_handle_t *); +void imc_space_unmap(bus_space_tag_t, bus_space_handle_t, bus_size_t); +int imc_space_region(bus_space_tag_t, bus_space_handle_t, bus_size_t, + bus_size_t, bus_space_handle_t *); +void *imc_space_vaddr(bus_space_tag_t, bus_space_handle_t); +void imc_space_barrier(bus_space_tag_t, bus_space_handle_t, bus_size_t, + bus_size_t, int); + +bus_space_t imcbus_tag = {/* not static for gio_cnattch() */ + PHYS_TO_XKPHYS(0, CCA_NC), + NULL, + imc_read_1, imc_write_1, + imc_read_2, imc_write_2, + imc_read_4, imc_write_4, + imc_read_8, imc_write_8, + imc_read_raw_2, imc_write_raw_2, + imc_read_raw_4, imc_write_raw_4, + imc_read_raw_8, imc_write_raw_8, + imc_space_map, imc_space_unmap, imc_space_region, + imc_space_vaddr, imc_space_barrier +}; + +#if NEISA > 0 +int imc_eisa_io_map(bus_space_tag_t, bus_addr_t, bus_size_t, int, + bus_space_handle_t *); +int imc_eisa_io_region(bus_space_tag_t, bus_space_handle_t, bus_size_t, + bus_size_t, bus_space_handle_t *); +int imc_eisa_mem_map(bus_space_tag_t, bus_addr_t, bus_size_t, int, + bus_space_handle_t *); +int imc_eisa_mem_region(bus_space_tag_t, bus_space_handle_t, bus_size_t, + bus_size_t, bus_space_handle_t *); + +static bus_space_t imcbus_eisa_io_tag = { + PHYS_TO_XKPHYS(EISA_IO_BASE, CCA_NC), + NULL, + imc_read_1, imc_write_1, + imc_read_2, imc_write_2, + imc_read_4, imc_write_4, + imc_read_8, imc_write_8, + imc_read_raw_2, imc_write_raw_2, + imc_read_raw_4, imc_write_raw_4, + imc_read_raw_8, imc_write_raw_8, + imc_eisa_io_map, imc_space_unmap, imc_eisa_io_region, + imc_space_vaddr, imc_space_barrier +}; +static bus_space_t imcbus_eisa_mem_tag = { + PHYS_TO_XKPHYS(0, CCA_NC), + NULL, + imc_read_1, imc_write_1, + imc_read_2, imc_write_2, + imc_read_4, imc_write_4, + imc_read_8, imc_write_8, + imc_read_raw_2, imc_write_raw_2, + imc_read_raw_4, imc_write_raw_4, + imc_read_raw_8, imc_write_raw_8, + imc_eisa_mem_map, imc_space_unmap, imc_eisa_mem_region, + imc_space_vaddr, imc_space_barrier +}; +#endif + +bus_addr_t imc_pa_to_device(paddr_t); +paddr_t imc_device_to_pa(bus_addr_t); + +struct machine_bus_dma_tag imc_bus_dma_tag = {/* not static for gio_cnattch() */ + NULL, /* _cookie */ + _dmamap_create, + _dmamap_destroy, + _dmamap_load, + _dmamap_load_mbuf, + _dmamap_load_uio, + _dmamap_load_raw, + _dmamap_load_buffer, + _dmamap_unload, + _dmamap_sync, + _dmamem_alloc, + _dmamem_free, + _dmamem_map, + _dmamem_unmap, + _dmamem_mmap, + imc_pa_to_device, + imc_device_to_pa, + 0 +}; + +/* + * Bus access primitives. + */ + +uint8_t +imc_read_1(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o) +{ + return *(volatile uint8_t *)(h + o); +} + +uint16_t +imc_read_2(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o) +{ + return *(volatile uint16_t *)(h + o); +} + +uint32_t +imc_read_4(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o) +{ + return *(volatile uint32_t *)(h + o); +} + +uint64_t +imc_read_8(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o) +{ + return *(volatile uint64_t *)(h + o); +} + +void +imc_write_1(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o, uint8_t v) +{ + *(volatile uint8_t *)(h + o) = v; +} + +void +imc_write_2(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o, uint16_t v) +{ + *(volatile uint16_t *)(h + o) = v; +} + +void +imc_write_4(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o, uint32_t v) +{ + *(volatile uint32_t *)(h + o) = v; +} + +void +imc_write_8(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o, uint64_t v) +{ + *(volatile uint64_t *)(h + o) = v; +} + +void +imc_read_raw_2(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t o, + uint8_t *buf, bus_size_t len) +{ + volatile uint16_t *addr = (volatile uint16_t *)(h + o); + len >>= 1; + while (len-- != 0) { + *(uint16_t *)buf = *addr; + buf += 2; + } +} + +void +imc_write_raw_2(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t o, + const uint8_t *buf, bus_size_t len) +{ + volatile uint16_t *addr = (volatile uint16_t *)(h + o); + len >>= 1; + while (len-- != 0) { + *addr = *(uint16_t *)buf; + buf += 2; + } +} + +void +imc_read_raw_4(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t o, + uint8_t *buf, bus_size_t len) +{ + volatile uint32_t *addr = (volatile uint32_t *)(h + o); + len >>= 2; + while (len-- != 0) { + *(uint32_t *)buf = *addr; + buf += 4; + } +} + +void +imc_write_raw_4(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t o, + const uint8_t *buf, bus_size_t len) +{ + volatile uint32_t *addr = (volatile uint32_t *)(h + o); + len >>= 2; + while (len-- != 0) { + *addr = *(uint32_t *)buf; + buf += 4; + } +} + +void +imc_read_raw_8(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t o, + uint8_t *buf, bus_size_t len) +{ + volatile uint64_t *addr = (volatile uint64_t *)(h + o); + len >>= 3; + while (len-- != 0) { + *(uint64_t *)buf = *addr; + buf += 8; + } +} + +void +imc_write_raw_8(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t o, + const uint8_t *buf, bus_size_t len) +{ + volatile uint64_t *addr = (volatile uint64_t *)(h + o); + len >>= 3; + while (len-- != 0) { + *addr = *(uint64_t *)buf; + buf += 8; + } +} + +int +imc_space_map(bus_space_tag_t t, bus_addr_t offs, bus_size_t size, + int flags, bus_space_handle_t *bshp) +{ + *bshp = t->bus_base + offs; + return 0; +} + +void +imc_space_unmap(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t size) +{ +} + +int +imc_space_region(bus_space_tag_t 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 * +imc_space_vaddr(bus_space_tag_t t, bus_space_handle_t h) +{ + return (void *)h; +} + +void +imc_space_barrier(bus_space_tag_t t, bus_space_handle_t h, bus_size_t offs, + bus_size_t len, int flags) +{ + __asm__ __volatile__ ("sync" ::: "memory"); +} + +#if NEISA > 0 +int +imc_eisa_io_map(bus_space_tag_t t, bus_addr_t offs, bus_size_t size, int flags, + bus_space_handle_t *bshp) +{ + if (offs + size > EISA_IO_END - EISA_IO_BASE) + return EINVAL; + + *bshp = t->bus_base + offs; + return 0; +} + +int +imc_eisa_io_region(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset, + bus_size_t size, bus_space_handle_t *nbshp) +{ + if ((bsh - t->bus_base) + offset + size > EISA_IO_END - EISA_IO_BASE) + return EINVAL; + + *nbshp = bsh + offset; + return 0; +} + +int +imc_eisa_mem_map(bus_space_tag_t t, bus_addr_t offs, bus_size_t size, int flags, + bus_space_handle_t *bshp) +{ + if ((offs >= EISA_MEM0_BASE && offs + size <= EISA_MEM0_END) || + (offs >= EISA_MEM1_BASE && offs + size <= EISA_MEM1_END)) { + *bshp = t->bus_base + offs; + return 0; + } + + return EINVAL; +} + +int +imc_eisa_mem_region(bus_space_tag_t t, bus_space_handle_t bsh, + bus_size_t offset, bus_size_t size, bus_space_handle_t *nbshp) +{ + bus_addr_t orig = bsh - t->bus_base; + + if ((orig >= EISA_MEM0_BASE && orig + offset + size <= EISA_MEM0_END) || + (orig >= EISA_MEM1_BASE && orig + offset + size <= EISA_MEM1_END)) { + *nbshp = t->bus_base + offset; + return 0; + } + + return EINVAL; +} +#endif + +bus_addr_t +imc_pa_to_device(paddr_t pa) +{ + return (bus_addr_t)pa; +} + +paddr_t +imc_device_to_pa(bus_addr_t addr) +{ + return (paddr_t)addr; +} + +/* + * Autoconf glue. + */ + +int +imc_match(struct device *parent, void *match, void *aux) +{ + struct mainbus_attach_args *maa = (void *)aux; + + switch (sys_config.system_type) { + case SGI_IP20: + case SGI_IP22: + case SGI_IP26: + case SGI_IP28: + break; + default: + return 0; + } + + return strcmp(maa->maa_name, imc_cd.cd_name) == 0; +} + +void +imc_attach(struct device *parent, struct device *self, void *aux) +{ + struct imc_attach_args iaa; +#if NEISA > 0 + struct eisabus_attach_args eba; +#endif + uint32_t reg; + uint32_t id, rev; + int have_eisa; + + id = imc_read(IMC_SYSID); + rev = id & IMC_SYSID_REVMASK; + + /* EISA exists on Indigo2 only */ + if (sys_config.system_type != SGI_IP20 && + sys_config.system_subtype == IP22_INDIGO2) + have_eisa = (id & IMC_SYSID_HAVEISA) != 0; + else + have_eisa = 0; + + printf(": revision %d\n", rev); + + /* Clear CPU/GIO error status registers to clear any leftover bits. */ + imc_bus_reset(); + + /* Disable watchdog if leftover from previous reboot */ + imc_watchdog_cb(self, 0); + + /* Hook the bus error handler into the ISR */ + set_intr(INTPRI_BUSERR, CR_INT_4, imc_bus_error); + + /* + * Enable parity reporting on GIO/main memory transactions. + * Disable parity checking on CPU bus transactions (as turning + * it on seems to cause spurious bus errors), but enable parity + * checking on CPU reads from main memory (note that this bit + * has the opposite sense... Turning it on turns the checks off!). + * Finally, turn on interrupt writes to the CPU from the MC. + */ + reg = imc_read(IMC_CPUCTRL0); + reg &= ~IMC_CPUCTRL0_NCHKMEMPAR; + reg |= (IMC_CPUCTRL0_GPR | IMC_CPUCTRL0_MPR | IMC_CPUCTRL0_INTENA); + imc_write(IMC_CPUCTRL0, reg); + + /* Setup the MC write buffer depth */ + reg = imc_read(IMC_CPUCTRL1); + reg = (reg & ~IMC_CPUCTRL1_MCHWMSK) | 13; + + /* + * Force endianness on the onboard HPC and both slots. + * This should be safe for Fullhouse, but leave it conditional + * for now. + */ + switch (sys_config.system_type) { + case SGI_IP22: + if (sys_config.system_subtype != IP22_INDY) + break; + /* FALLTHROUGH */ + case SGI_IP20: + reg |= IMC_CPUCTRL1_HPCFX; + reg |= IMC_CPUCTRL1_EXP0FX; + reg |= IMC_CPUCTRL1_EXP1FX; + reg &= ~IMC_CPUCTRL1_HPCLITTLE; + reg &= ~IMC_CPUCTRL1_EXP0LITTLE; + reg &= ~IMC_CPUCTRL1_EXP1LITTLE; + break; + } + imc_write(IMC_CPUCTRL1, reg); + + /* + * Set GIO64 arbitrator configuration register: + * + * Preserve PROM-set graphics-related bits, as they seem to depend + * on the graphics variant present and I'm not sure how to figure + * that out or 100% sure what the correct settings are for each. + */ + reg = imc_read(IMC_GIO64ARB); + reg &= (IMC_GIO64ARB_GRX64 | IMC_GIO64ARB_GRXRT | IMC_GIO64ARB_GRXMST); + + /* + * Rest of settings are machine/board dependent + * XXX I wonder if this even works as advertized. The logic apparently + * XXX comes from Linux, but the EISA settings look horribly broken to + * XXX me -- miod + */ + switch (sys_config.system_type) { + case SGI_IP20: + reg |= IMC_GIO64ARB_ONEGIO; + reg |= IMC_GIO64ARB_EXP0RT | IMC_GIO64ARB_EXP1RT; + reg |= IMC_GIO64ARB_EXP0MST | IMC_GIO64ARB_EXP1MST; + reg &= ~(IMC_GIO64ARB_HPC64 | + IMC_GIO64ARB_HPCEXP64 | IMC_GIO64ARB_EISA64 | + IMC_GIO64ARB_EXP064 | IMC_GIO64ARB_EXP164 | + IMC_GIO64ARB_EXP0PIPE | IMC_GIO64ARB_EXP1PIPE); + break; + default: + /* + * GIO64 invariant for all IP22 platforms: one GIO bus, + * HPC1 @ 64 + */ + reg |= IMC_GIO64ARB_ONEGIO | IMC_GIO64ARB_HPC64; + + switch (sys_config.system_subtype) { + default: + case IP22_INDY: + /* XXX is MST mutually exclusive? */ + reg |= IMC_GIO64ARB_EXP0RT | IMC_GIO64ARB_EXP1RT; + reg |= IMC_GIO64ARB_EXP0MST | IMC_GIO64ARB_EXP1MST; + + /* EISA can bus-master, is 64-bit */ + reg |= IMC_GIO64ARB_EISAMST | IMC_GIO64ARB_EISA64; + break; + + case IP22_INDIGO2: + /* + * All Fullhouse boards have a 64-bit HPC2 and pipelined + * EXP0 slot. + */ + reg |= IMC_GIO64ARB_HPCEXP64 | IMC_GIO64ARB_EXP0PIPE; + + if (rev < 2) { + /* EXP0 realtime, EXP1 can master */ + reg |= IMC_GIO64ARB_EXP0RT | + IMC_GIO64ARB_EXP1MST; + } else { + /* EXP1 pipelined as well, EISA masters */ + reg |= IMC_GIO64ARB_EXP1PIPE | + IMC_GIO64ARB_EISAMST; + } + break; + } + } + + imc_write(IMC_GIO64ARB, reg); + +#if NEISA > 0 + if (have_eisa) { + memset(&eba, 0, sizeof(eba)); + eba.eba_busname = "eisa"; + eba.eba_iot = &imcbus_eisa_io_tag; + eba.eba_memt = &imcbus_eisa_mem_tag; + eba.eba_dmat = &imc_bus_dma_tag; + eba.eba_ec = NULL; + config_found(self, &eba, imc_print); + } +#endif + + memset(&iaa, 0, sizeof(iaa)); + iaa.iaa_name = "gio"; + iaa.iaa_st = &imcbus_tag; + iaa.iaa_dmat = &imc_bus_dma_tag; + config_found(self, &iaa, imc_print); + + /* Clear CPU/GIO error status registers to clear any leftover bits. */ + imc_bus_reset(); + + /* Register watchdog */ + wdog_register(self, imc_watchdog_cb); +} + +int +imc_print(void *aux, const char *name) +{ + struct imc_attach_args *iaa = aux; + + if (name != NULL) + printf("%s at %s", iaa->iaa_name, name); + + return UNCONF; +} + +void +imc_bus_reset() +{ + imc_write(IMC_CPU_ERRSTAT, 0); + imc_write(IMC_GIO_ERRSTAT, 0); +} + +uint32_t +imc_bus_error(uint32_t hwpend, struct trap_frame *tf) +{ + printf("bus error: cpu_stat %08x addr %08x, gio_stat %08x addr %08x\n", + imc_read(IMC_CPU_ERRSTAT), + imc_read(IMC_CPU_ERRADDR), + imc_read(IMC_GIO_ERRSTAT), + imc_read(IMC_GIO_ERRADDR)); + imc_bus_reset(); + + return hwpend; +} + +int +imc_watchdog_cb(void *v, int period) +{ + uint32_t reg; + + if (period == 0) { + /* reset... */ + imc_write(IMC_WDOG, 0); + /* ...and disable */ + reg = imc_read(IMC_CPUCTRL0); + reg &= ~(IMC_CPUCTRL0_WDOG); + imc_write(IMC_CPUCTRL0, reg); + + return 0; + } else { + /* enable... */ + reg = imc_read(IMC_CPUCTRL0); + reg |= IMC_CPUCTRL0_WDOG; + imc_write(IMC_CPUCTRL0, reg); + /* ...and reset */ + imc_write(IMC_WDOG, 0); + + /* + * The watchdog period is not controllable; it will fire + * when the 20 bit counter, running on a 64 usec clock, + * overflows. + */ + return (64 << 20) / 1000000; + } +} + +/* intended to be called from gio/gio.c only */ +int +imc_gio64_arb_config(int slot, uint32_t flags) +{ + uint32_t reg; + + if (sys_config.system_type == SGI_IP20 || + sys_config.system_subtype != IP22_INDIGO2) { + /* GIO_SLOT_GFX is only usable on Fullhouse */ + if (slot == GIO_SLOT_GFX) + return EINVAL; + } else { + /* GIO_SLOT_EXP1 is unusable on Fullhouse */ + if (slot == GIO_SLOT_EXP1) + return EINVAL; + } + + /* GIO_SLOT_GFX is always pipelined */ + if (slot == GIO_SLOT_GFX && (flags & GIO_ARB_NOPIPE)) + return EINVAL; + + /* IP20 does not support pipelining (XXX what about Indy?) */ + if (((flags & GIO_ARB_PIPE) || (flags & GIO_ARB_NOPIPE)) && + sys_config.system_type == SGI_IP20) + return EINVAL; + + reg = imc_read(IMC_GIO64ARB); + + if (flags & GIO_ARB_RT) { + if (slot == GIO_SLOT_EXP0) + reg |= IMC_GIO64ARB_EXP0RT; + else if (slot == GIO_SLOT_EXP1) + reg |= IMC_GIO64ARB_EXP1RT; + else if (slot == GIO_SLOT_GFX) + reg |= IMC_GIO64ARB_GRXRT; + } + + if (flags & GIO_ARB_MST) { + if (slot == GIO_SLOT_EXP0) + reg |= IMC_GIO64ARB_EXP0MST; + else if (slot == GIO_SLOT_EXP1) + reg |= IMC_GIO64ARB_EXP1MST; + else if (slot == GIO_SLOT_GFX) + reg |= IMC_GIO64ARB_GRXMST; + } + + if (flags & GIO_ARB_PIPE) { + if (slot == GIO_SLOT_EXP0) + reg |= IMC_GIO64ARB_EXP0PIPE; + else if (slot == GIO_SLOT_EXP1) + reg |= IMC_GIO64ARB_EXP1PIPE; + } + + if (flags & GIO_ARB_LB) { + if (slot == GIO_SLOT_EXP0) + reg &= ~IMC_GIO64ARB_EXP0RT; + else if (slot == GIO_SLOT_EXP1) + reg &= ~IMC_GIO64ARB_EXP1RT; + else if (slot == GIO_SLOT_GFX) + reg &= ~IMC_GIO64ARB_GRXRT; + } + + if (flags & GIO_ARB_SLV) { + if (slot == GIO_SLOT_EXP0) + reg &= ~IMC_GIO64ARB_EXP0MST; + else if (slot == GIO_SLOT_EXP1) + reg &= ~IMC_GIO64ARB_EXP1MST; + else if (slot == GIO_SLOT_GFX) + reg &= ~IMC_GIO64ARB_GRXMST; + } + + if (flags & GIO_ARB_NOPIPE) { + if (slot == GIO_SLOT_EXP0) + reg &= ~IMC_GIO64ARB_EXP0PIPE; + else if (slot == GIO_SLOT_EXP1) + reg &= ~IMC_GIO64ARB_EXP1PIPE; + } + + if (flags & GIO_ARB_32BIT) { + if (slot == GIO_SLOT_EXP0) + reg &= ~IMC_GIO64ARB_EXP064; + else if (slot == GIO_SLOT_EXP1) + reg &= ~IMC_GIO64ARB_EXP164; + } + + if (flags & GIO_ARB_64BIT) { + if (slot == GIO_SLOT_EXP0) + reg |= IMC_GIO64ARB_EXP064; + else if (slot == GIO_SLOT_EXP1) + reg |= IMC_GIO64ARB_EXP164; + } + + if (flags & GIO_ARB_HPC2_32BIT) + reg &= ~IMC_GIO64ARB_HPCEXP64; + + if (flags & GIO_ARB_HPC2_64BIT) + reg |= IMC_GIO64ARB_HPCEXP64; + + imc_write(IMC_GIO64ARB, reg); + + return 0; +} + +/* + * According to chapter 19 of the "IRIX Device Driver Programmer's Guide", + * some GIO devices, which do not drive all data lines, may cause false + * memory read parity errors on the SysAD bus. The workaround is to disable + * parity checking. + */ +void +imc_disable_sysad_parity(void) +{ + uint32_t reg; + + switch (sys_config.system_type) { + case SGI_IP20: + case SGI_IP22: + case SGI_IP26: + case SGI_IP28: + break; + default: + return; + } + + reg = imc_read(IMC_CPUCTRL0); + reg |= IMC_CPUCTRL0_NCHKMEMPAR; + imc_write(IMC_CPUCTRL0, reg); +} + +void +imc_enable_sysad_parity(void) +{ + uint32_t reg; + + switch (sys_config.system_type) { + case SGI_IP20: + case SGI_IP22: + case SGI_IP26: + case SGI_IP28: + break; + default: + return; + } + + reg = imc_read(IMC_CPUCTRL0); + reg &= ~IMC_CPUCTRL0_NCHKMEMPAR; + imc_write(IMC_CPUCTRL0, reg); +} + +#if 0 +int +imc_is_sysad_parity_enabled(void) +{ + uint32_t reg; + + switch (sys_config.system_type) { + case SGI_IP20: + case SGI_IP22: + case SGI_IP26: + case SGI_IP28: + break; + default: + return 0; + } + + reg = imc_read(IMC_CPUCTRL0); + + return reg & IMC_CPUCTRL0_NCHKMEMPAR; +} +#endif |