diff options
-rw-r--r-- | sys/arch/i386/conf/GENERIC | 3 | ||||
-rw-r--r-- | sys/arch/i386/conf/files.i386 | 7 | ||||
-rw-r--r-- | sys/arch/i386/pci/elan520.c | 246 | ||||
-rw-r--r-- | sys/arch/i386/pci/elan520reg.h | 147 |
4 files changed, 401 insertions, 2 deletions
diff --git a/sys/arch/i386/conf/GENERIC b/sys/arch/i386/conf/GENERIC index 51128dbd081..23c2ff5a16d 100644 --- a/sys/arch/i386/conf/GENERIC +++ b/sys/arch/i386/conf/GENERIC @@ -1,4 +1,4 @@ -# $OpenBSD: GENERIC,v 1.327 2002/12/13 03:02:07 tdeval Exp $ +# $OpenBSD: GENERIC,v 1.328 2003/01/21 17:02:29 markus Exp $ # $NetBSD: GENERIC,v 1.48 1996/05/20 18:17:23 mrg Exp $ # # GENERIC -- everything that's currently supported @@ -58,6 +58,7 @@ pcib* at pci? dev ? function ? # PCI-ISA bridge # power management and other environmental stuff #amdpm* at pci? dev ? function ? # AMD768MPX +#elansc* at pci? dev ? function ? # AMD Elan SC520 System Controller # ISA PCMCIA controllers #option PCMCIAVERBOSE diff --git a/sys/arch/i386/conf/files.i386 b/sys/arch/i386/conf/files.i386 index 4379d4228af..62bff991afb 100644 --- a/sys/arch/i386/conf/files.i386 +++ b/sys/arch/i386/conf/files.i386 @@ -1,4 +1,4 @@ -# $OpenBSD: files.i386,v 1.100 2002/11/07 22:03:22 mickey Exp $ +# $OpenBSD: files.i386,v 1.101 2003/01/21 17:02:29 markus Exp $ # $NetBSD: files.i386,v 1.73 1996/05/07 00:58:36 thorpej Exp $ # # new style config file for i386 architecture @@ -105,6 +105,11 @@ device pchb: pcibus attach pchb at pci file arch/i386/pci/pchb.c pchb +# AMD Elan SC520 System Controller (PCI-Host bridge) +device elansc +attach elansc at pci +file arch/i386/pci/elan520.c elansc + # PCI-ISA bridge chipsets device pcib: isabus attach pcib at pci diff --git a/sys/arch/i386/pci/elan520.c b/sys/arch/i386/pci/elan520.c new file mode 100644 index 00000000000..4f50cf41d18 --- /dev/null +++ b/sys/arch/i386/pci/elan520.c @@ -0,0 +1,246 @@ +/* $OpenBSD: elan520.c,v 1.1 2003/01/21 17:02:29 markus Exp $ */ +/* $NetBSD: elan520.c,v 1.4 2002/10/02 05:47:15 thorpej Exp $ */ + +/*- + * Copyright (c) 2002 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +/* + * Device driver for the AMD Elan SC520 System Controller. This attaches + * where the "pchb" driver might normally attach, and provides support for + * extra features on the SC520, such as the watchdog timer and GPIO. + * + * Information about the GP bus echo bug work-around is from code posted + * to the "soekris-tech" mailing list by Jasper Wallace. + */ + +#include <sys/cdefs.h> +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> + +#include <machine/bus.h> + +#include <dev/pci/pcivar.h> +#include <dev/pci/pcidevs.h> + +#include <arch/i386/pci/elan520reg.h> + +struct elansc_softc { + struct device sc_dev; + bus_space_tag_t sc_memt; + bus_space_handle_t sc_memh; + int sc_echobug; +}; + +int elansc_match(struct device *, void *, void *); +void elansc_attach(struct device *, struct device *, void *); + +void elansc_wdogctl(struct elansc_softc *, int, uint16_t); +#define elansc_wdogctl_reset(sc) elansc_wdogctl(sc, 1, 0) +#define elansc_wdogctl_write(sc, val) elansc_wdogctl(sc, 0, val) +int elansc_wdogctl_cb(void *, int); + +struct cfattach elansc_ca = { + sizeof(struct elansc_softc), elansc_match, elansc_attach +}; + +struct cfdriver elansc_cd = { + NULL, "elansc", DV_DULL +}; + +int +elansc_match(struct device *parent, void *match, void *aux) +{ + struct pci_attach_args *pa = aux; + + if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_AMD && + PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_AMD_ELANSC520) + return (10); /* beat pchb */ + + return (0); +} + +static const char *elansc_speeds[] = { + "(reserved 00)", + "100MHz", + "133MHz", + "(reserved 11)", +}; + +#define RSTBITS "\20\x07SCP\x06HRST\x05SRST\x04WDT\x03SD\x02PRGRST\x01PWRGOOD" + +void +elansc_attach(struct device *parent, struct device *self, void *aux) +{ + struct elansc_softc *sc = (void *) self; + struct pci_attach_args *pa = aux; + uint16_t rev; + uint8_t ressta, cpuctl; + + printf("\n"); + + sc->sc_memt = pa->pa_memt; + if (bus_space_map(sc->sc_memt, MMCR_BASE_ADDR, NBPG, 0, + &sc->sc_memh) != 0) { + printf("%s: unable to map registers\n", sc->sc_dev.dv_xname); + return; + } + + rev = bus_space_read_2(sc->sc_memt, sc->sc_memh, MMCR_REVID); + cpuctl = bus_space_read_1(sc->sc_memt, sc->sc_memh, MMCR_CPUCTL); + ressta = bus_space_read_1(sc->sc_memt, sc->sc_memh, MMCR_RESSTA); + + printf("%s: product %d stepping %d.%d, CPU clock %s" + ", reset %b", + sc->sc_dev.dv_xname, + (rev & REVID_PRODID) >> REVID_PRODID_SHIFT, + (rev & REVID_MAJSTEP) >> REVID_MAJSTEP_SHIFT, + (rev & REVID_MINSTEP), + elansc_speeds[cpuctl & CPUCTL_CPU_CLK_SPD_MASK], + ressta, RSTBITS); + + printf("\n"); + + /* + * SC520 rev A1 has a bug that affects the watchdog timer. If + * the GP bus echo mode is enabled, writing to the watchdog control + * register is blocked. + * + * The BIOS in some systems (e.g. the Soekris net4501) enables + * GP bus echo for various reasons, so we need to switch it off + * when we talk to the watchdog timer. + * + * XXX The step 1.1 (B1?) in my Soekris net4501 also has this + * XXX problem, so we'll just enable it for all Elan SC520s + * XXX for now. --thorpej@netbsd.org + */ + if (1 || rev == ((PRODID_ELAN_SC520 << REVID_PRODID_SHIFT) | + (0 << REVID_MAJSTEP_SHIFT) | (1))) + sc->sc_echobug = 1; + + /* + * Determine cause of the last reset, and issue a warning if it + * was due to watchdog expiry. + */ + if (ressta & RESSTA_WDT_RST_DET) + printf("%s: WARNING: LAST RESET DUE TO WATCHDOG EXPIRATION!\n", + sc->sc_dev.dv_xname); + bus_space_write_1(sc->sc_memt, sc->sc_memh, MMCR_RESSTA, ressta); + + /* Set up the watchdog registers with some defaults. */ + elansc_wdogctl_write(sc, WDTMRCTL_WRST_ENB | WDTMRCTL_EXP_SEL30); + + /* ...and clear it. */ + elansc_wdogctl_reset(sc); + + wdog_register(sc, elansc_wdogctl_cb); +} + +void +elansc_wdogctl(struct elansc_softc *sc, int do_reset, uint16_t val) +{ + int s; + uint8_t echo_mode; + + s = splhigh(); + + /* Switch off GP bus echo mode if we need to. */ + if (sc->sc_echobug) { + echo_mode = bus_space_read_1(sc->sc_memt, sc->sc_memh, + MMCR_GPECHO); + bus_space_write_1(sc->sc_memt, sc->sc_memh, + MMCR_GPECHO, echo_mode & ~GPECHO_GP_ECHO_ENB); + } + + if (do_reset) { + /* Reset the watchdog. */ + bus_space_write_2(sc->sc_memt, sc->sc_memh, MMCR_WDTMRCTL, + WDTMRCTL_RESET1); + bus_space_write_2(sc->sc_memt, sc->sc_memh, MMCR_WDTMRCTL, + WDTMRCTL_RESET2); + } else { + /* Unlock the register. */ + bus_space_write_2(sc->sc_memt, sc->sc_memh, MMCR_WDTMRCTL, + WDTMRCTL_UNLOCK1); + bus_space_write_2(sc->sc_memt, sc->sc_memh, MMCR_WDTMRCTL, + WDTMRCTL_UNLOCK2); + + /* Write the value. */ + bus_space_write_2(sc->sc_memt, sc->sc_memh, MMCR_WDTMRCTL, + val); + } + + /* Switch GP bus echo mode back. */ + if (sc->sc_echobug) + bus_space_write_1(sc->sc_memt, sc->sc_memh, MMCR_GPECHO, + echo_mode); + + splx(s); +} + +static const struct { + int period; /* whole seconds */ + uint16_t exp; /* exponent select */ +} elansc_wdog_periods[] = { + { 1, WDTMRCTL_EXP_SEL25 }, + { 2, WDTMRCTL_EXP_SEL26 }, + { 4, WDTMRCTL_EXP_SEL27 }, + { 8, WDTMRCTL_EXP_SEL28 }, + { 16, WDTMRCTL_EXP_SEL29 }, + { 32, WDTMRCTL_EXP_SEL30 }, +}; + +int +elansc_wdogctl_cb(void *self, int period) +{ + struct elansc_softc *sc = self; + int i; + + if (period == 0) { + elansc_wdogctl_write(sc, + WDTMRCTL_WRST_ENB | WDTMRCTL_EXP_SEL30); + } else { + for (i = 0; i < (sizeof(elansc_wdog_periods) / + sizeof(elansc_wdog_periods[0])) - 1; i++) + if (elansc_wdog_periods[i].period >= period) + break; + period = elansc_wdog_periods[i].period; + elansc_wdogctl_write(sc, WDTMRCTL_ENB | + WDTMRCTL_WRST_ENB | elansc_wdog_periods[i].exp); + elansc_wdogctl_reset(sc); + } + return (period); +} diff --git a/sys/arch/i386/pci/elan520reg.h b/sys/arch/i386/pci/elan520reg.h new file mode 100644 index 00000000000..d53d8decb43 --- /dev/null +++ b/sys/arch/i386/pci/elan520reg.h @@ -0,0 +1,147 @@ +/* $OpenBSD: elan520reg.h,v 1.1 2003/01/21 17:02:29 markus Exp $ */ +/* $NetBSD: elan520reg.h,v 1.1 2002/08/12 01:03:14 thorpej Exp $ */ + +/*- + * Copyright (c) 2002 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +/* + * Register definitions for the AMD Elan SC520 System Controller. + */ + +#ifndef _I386_PCI_ELAN520REG_H_ +#define _I386_PCI_ELAN520REG_H_ + +#define MMCR_BASE_ADDR 0xfffef000 + +/* + * Am5x86 CPU Registers. + */ +#define MMCR_REVID 0x0000 +#define MMCR_CPUCTL 0x0002 + +#define REVID_PRODID 0xff00 /* product ID */ +#define REVID_PRODID_SHIFT 8 +#define REVID_MAJSTEP 0x00f0 /* stepping major */ +#define REVID_MAJSTEP_SHIFT 4 +#define REVID_MINSTEP 0x000f /* stepping minor */ + +#define PRODID_ELAN_SC520 0x00 /* Elan SC520 */ + +#define CPUCTL_CPU_CLK_SPD_MASK 0x03 /* CPU clock speed */ +#define CPUCTL_CACHE_WR_MODE 0x10 /* cache mode (0 = wb, 1 = wt) */ + +/* + * General Purpose Bus Registers + */ +#define MMCR_GPECHO 0x0c00 /* GP echo mode */ +#define MMCR_GPCSDW 0x0c01 /* GP chip sel data width */ +#define MMCR_CPCSQUAL 0x0c02 /* GP chip sel qualification */ +#define MMCR_GPCSRT 0x0c08 /* GP chip sel recovery time */ +#define MMCR_GPCSPW 0x0c09 /* GP chip sel pulse width */ +#define MMCR_GPCSOFF 0x0c0a /* GP chip sel offset */ +#define MMCR_GPRDW 0x0c0b /* GP read pulse width */ +#define MMCR_GPRDOFF 0x0c0c /* GP read offset */ +#define MMCR_GPWRW 0x0c0d /* GP write pulse width */ +#define MMCR_GPWROFF 0x0c0e /* GP write offset */ +#define MMCR_GPALEW 0x0c0f /* GPALE pulse width */ +#define MMCR_GPALEOFF 0x0c10 /* GPALE offset */ + +#define GPECHO_GP_ECHO_ENB 0x01 /* GP bus echo mode enable */ + +/* + * Programmable Input/Output Registers + */ +#define MMCR_PIOPFS15_0 0x0c20 /* PIO15-PIO0 pin func sel */ +#define MMCR_PIOPFS31_16 0x0c22 /* PIO31-PIO16 pin func sel */ +#define MMCR_CSPFS 0x0c24 /* chip sel pin func sel */ +#define MMCR_CLKSEL 0x0c26 /* clock select */ +#define MMCR_DSCTL 0x0c28 /* drive strength control */ +#define MMCR_PIODIR15_0 0x0c2a /* PIO15-PIO0 direction */ +#define MMCR_PIODIR31_16 0x0c2c /* PIO31-PIO16 direction */ +#define MMCR_PIODATA15_0 0x0c30 /* PIO15-PIO0 data */ +#define MMCR_PIODATA31_16 0x0c32 /* PIO31-PIO16 data */ +#define MMCR_PIOSET15_0 0x0c34 /* PIO15-PIO0 set */ +#define MMCR_PIOSET31_16 0x0c36 /* PIO31-PIO16 set */ +#define MMCR_PIOCLR15_0 0x0c38 /* PIO15-PIO0 clear */ +#define MMCR_PIOCLR31_16 0x0c3a /* PIO31-PIO16 clear */ + +/* + * Watchdog Timer Registers. + */ +#define MMCR_WDTMRCTL 0x0cb0 /* watchdog timer control */ +#define MMCR_WDTMRCNTL 0x0cb2 /* watchdog timer count low */ +#define MMCR_WDTMRCNTH 0x0cb4 /* watchdog timer count high */ + +#define WDTMRCTL_EXP_SEL_MASK 0x00ff /* exponent select */ +#define WDTMRCTL_EXP_SEL14 0x0001 /* 496us/492us */ +#define WDTMRCTL_EXP_SEL24 0x0002 /* 508ms/503ms */ +#define WDTMRCTL_EXP_SEL25 0x0004 /* 1.02s/1.01s */ +#define WDTMRCTL_EXP_SEL26 0x0008 /* 2.03s/2.01s */ +#define WDTMRCTL_EXP_SEL27 0x0010 /* 4.07s/4.03s */ +#define WDTMRCTL_EXP_SEL28 0x0020 /* 8.13s/8.05s */ +#define WDTMRCTL_EXP_SEL29 0x0040 /* 16.27s/16.11s */ +#define WDTMRCTL_EXP_SEL30 0x0080 /* 32.54s/32.21s */ +#define WDTMRCTL_IRQ_FLG 0x1000 /* interrupt request */ +#define WDTMRCTL_WRST_ENB 0x4000 /* watchdog timer reset enable */ +#define WDTMRCTL_ENB 0x8000 /* watchdog timer enable */ + +#define WDTMRCTL_UNLOCK1 0x3333 +#define WDTMRCTL_UNLOCK2 0xcccc + +#define WDTMRCTL_RESET1 0xaaaa +#define WDTMRCTL_RESET2 0x5555 + +/* + * Reset Generation Registers. + */ +#define MMCR_SYSINFO 0x0d70 /* system board information */ +#define MMCR_RESCFG 0x0d72 /* reset configuration */ +#define MMCR_RESSTA 0x0d74 /* reset status */ + +#define RESCFG_SYS_RST 0x01 /* software system reset */ +#define RESCFG_GP_RST 0x02 /* assert GP bus reset */ +#define RESCFG_PRG_RST_ENB 0x04 /* programmable reset enable */ +#define RESCFG_ICE_ON_RST 0x08 /* enter AMDebug(tm) on reset */ + +#define RESSTA_PWRGOOD_DET 0x01 /* POWERGOOD reset detect */ +#define RESSTA_PRGRST_DET 0x02 /* programmable reset detect */ +#define RESSTA_SD_RST_DET 0x04 /* CPU shutdown reset detect */ +#define RESSTA_WDT_RST_DET 0x08 /* watchdog timer reset detect */ +#define RESSTA_ICE_SRST_DET 0x10 /* AMDebug(tm) soft reset detect */ +#define RESSTA_ICE_HRST_DET 0x20 /* AMDebug(tm) soft reset detect */ +#define RESSTA_SCP_RST 0x40 /* SCP reset detect */ + +#endif /* _I386_PCI_ELAN520REG_H_ */ |