Module Name: src Committed By: snj Date: Mon Feb 19 18:50:35 UTC 2018
Modified Files: src/share/man/man4 [netbsd-8]: wbsio.4 src/sys/dev/isa [netbsd-8]: files.isa wbsio.c wbsioreg.h Log Message: Pull up following revision(s) (requested by yamaguchi in ticket #558): share/man/man4/wbsio.4: 1.7-1.8 sys/dev/isa/files.isa: 1.168-1.169 sys/dev/isa/wbsio.c: 1.16-1.21 sys/dev/isa/wbsioreg.h: 1.6-1.7 Add wbsio(4) GPIO driver. Implemeted by s-yamaguchi@IIJ, reviewed by msaitoh@n.o. I just commit by proxy. -- Fix NCT6779 gpio pin configuration. Implemeted by s-yamaguchi@IIJ, reviewed by msaitoh@n.o. I just commit by proxy. -- Add Watchdog timer implementation to wbsio(4). Implemeted by s-yamaguchi@IIJ, reviewed by msaitoh@n.o. I just commit by proxy. -- Add an option to enable GPIO function of wbsio. Implemeted by s-yamaguchi@IIJ, reviewed by msaitoh@n.o. I just commit by proxy. -- Improve the error log message to use product name. Implemeted by s-yamaguchi@IIJ, reviewed by msaitoh@n.o. I just commit by proxy. -- Update the manual of wbsio(4). Implemeted by s-yamaguchi@IIJ, reviewed by msaitoh@n.o. I just commit by proxy. -- New sentence, new line. Fix xref. Sort SEE ALSO. -- PR/52887: HITOSHI Osada: wbsio needs sysmon_wdog. -- Now that watchdog support has been added, make sure that a modular driver requires the sysmon_wdog module. To generate a diff of this commit: cvs rdiff -u -r1.3.18.1 -r1.3.18.2 src/share/man/man4/wbsio.4 cvs rdiff -u -r1.167 -r1.167.8.1 src/sys/dev/isa/files.isa cvs rdiff -u -r1.10.10.1 -r1.10.10.2 src/sys/dev/isa/wbsio.c cvs rdiff -u -r1.5.2.2 -r1.5.2.3 src/sys/dev/isa/wbsioreg.h Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/share/man/man4/wbsio.4 diff -u src/share/man/man4/wbsio.4:1.3.18.1 src/share/man/man4/wbsio.4:1.3.18.2 --- src/share/man/man4/wbsio.4:1.3.18.1 Wed Nov 22 14:56:30 2017 +++ src/share/man/man4/wbsio.4 Mon Feb 19 18:50:35 2018 @@ -1,4 +1,4 @@ -.\" $NetBSD: wbsio.4,v 1.3.18.1 2017/11/22 14:56:30 martin Exp $ +.\" $NetBSD: wbsio.4,v 1.3.18.2 2018/02/19 18:50:35 snj Exp $ .\" $OpenBSD: wbsio.4,v 1.2 2008/02/17 16:48:47 jmc Exp $ .\" .\" Copyright (c) 2008 Mark Kettenis <kette...@openbsd.org> @@ -15,7 +15,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd July 12, 2017 +.Dd December 12, 2017 .Dt WBSIO 4 .Os .Sh NAME @@ -25,17 +25,25 @@ .Cd "wbsio* at isa? port 0x2e" .Cd "wbsio* at isa? port 0x4e" .Cd "lm* at wbsio?" +.Cd "gpio* at gpiobus?" +.Pp +.Cd "options WBSIO_GPIO" .Sh DESCRIPTION The .Nm -driver provides support for the Winbond (was spun off as Nuvoton) LPC Super I/O -ICs. -Only the hardware monitoring function is currently supported. +driver provides support for the Winbond (was spun off as Nuvoton) +LPC Super I/O ICs. +The hardware monitoring function and GPIO are currently supported. .Pp Support for the hardware monitor function is provided through the .Xr lm 4 driver. +The GPIO function supports 64 pins for NCT6795D. +Access to the pins provided by the +.Xr gpio 4 +interface. .Sh SEE ALSO +.Xr gpio 4 , .Xr intro 4 , .Xr isa 4 , .Xr lm 4 Index: src/sys/dev/isa/files.isa diff -u src/sys/dev/isa/files.isa:1.167 src/sys/dev/isa/files.isa:1.167.8.1 --- src/sys/dev/isa/files.isa:1.167 Fri Dec 9 04:32:39 2016 +++ src/sys/dev/isa/files.isa Mon Feb 19 18:50:35 2018 @@ -1,4 +1,4 @@ -# $NetBSD: files.isa,v 1.167 2016/12/09 04:32:39 christos Exp $ +# $NetBSD: files.isa,v 1.167.8.1 2018/02/19 18:50:35 snj Exp $ # # Config file and device description for machine-independent ISA code. # Included by ports that need it. Requires that the SCSI files be @@ -454,7 +454,7 @@ attach smsc at isa with smsc file dev/isa/smsc.c smsc needs-flag # Winbond LPC Super I/O -device wbsio {} +device wbsio { }: gpiobus, sysmon_wdog attach wbsio at isa file dev/isa/wbsio.c wbsio Index: src/sys/dev/isa/wbsio.c diff -u src/sys/dev/isa/wbsio.c:1.10.10.1 src/sys/dev/isa/wbsio.c:1.10.10.2 --- src/sys/dev/isa/wbsio.c:1.10.10.1 Wed Nov 22 14:56:30 2017 +++ src/sys/dev/isa/wbsio.c Mon Feb 19 18:50:35 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: wbsio.c,v 1.10.10.1 2017/11/22 14:56:30 martin Exp $ */ +/* $NetBSD: wbsio.c,v 1.10.10.2 2018/02/19 18:50:35 snj Exp $ */ /* $OpenBSD: wbsio.c,v 1.10 2015/03/14 03:38:47 jsg Exp $ */ /* * Copyright (c) 2008 Mark Kettenis <kette...@openbsd.org> @@ -20,27 +20,55 @@ * Winbond LPC Super I/O driver. */ +#include <sys/cdefs.h> #include <sys/param.h> #include <sys/device.h> #include <sys/kernel.h> #include <sys/module.h> #include <sys/systm.h> +#include <sys/mutex.h> +#include <sys/gpio.h> #include <sys/bus.h> #include <dev/isa/isareg.h> #include <dev/isa/isavar.h> #include <dev/isa/wbsioreg.h> +#include <dev/sysmon/sysmonvar.h> + +/* Don't use gpio for now in the module */ +#if !defined(_MODULE) && defined(WBSIO_GPIO) +#include "gpio.h" +#endif + +#if NGPIO > 0 +#include <dev/gpio/gpiovar.h> +#endif struct wbsio_softc { device_t sc_dev; device_t sc_lm_dev; +#if NGPIO > 0 + device_t sc_gpio_dev; +#endif bus_space_tag_t sc_iot; bus_space_handle_t sc_ioh; + kmutex_t sc_conf_lock; struct isa_attach_args sc_ia; struct isa_io sc_io; + +#if NGPIO > 0 + bus_space_handle_t sc_gpio_ioh; + kmutex_t sc_gpio_lock; + struct gpio_chipset_tag sc_gpio_gc; + struct gpio_pin sc_gpio_pins[WBSIO_GPIO_NPINS]; + bool sc_gpio_rt; +#endif + + struct sysmon_wdog sc_smw; + bool sc_smw_valid; }; static const struct wbsio_product { @@ -79,22 +107,47 @@ static int wbsio_rescan(device_t, const static void wbsio_childdet(device_t, device_t); static int wbsio_print(void *, const char *); static int wbsio_search(device_t, cfdata_t, const int *, void *); +static bool wbsio_suspend(device_t, const pmf_qual_t *); +#if NGPIO > 0 +static int wbsio_gpio_search(device_t, cfdata_t, const int *, void *); +static int wbsio_gpio_rt_init(struct wbsio_softc *); +static int wbsio_gpio_rt_read(struct wbsio_softc *, int, int); +static void wbsio_gpio_rt_write(struct wbsio_softc *, int, int, int); +static int wbsio_gpio_rt_pin_read(void *, int); +static void wbsio_gpio_rt_pin_write(void *, int, int); +static void wbsio_gpio_rt_pin_ctl(void *, int, int); +static void wbsio_gpio_enable_nct6779d(device_t); +static void wbsio_gpio_pinconfig_nct6779d(device_t); +#endif +static void wbsio_wdog_attach(device_t); +static int wbsio_wdog_detach(device_t); +static int wbsio_wdog_setmode(struct sysmon_wdog *); +static int wbsio_wdog_tickle(struct sysmon_wdog *); +static void wbsio_wdog_setcounter(struct wbsio_softc *, uint8_t); +static void wbsio_wdog_clear_timeout(struct wbsio_softc *); CFATTACH_DECL2_NEW(wbsio, sizeof(struct wbsio_softc), wbsio_match, wbsio_attach, wbsio_detach, NULL, wbsio_rescan, wbsio_childdet); static __inline void -wbsio_conf_enable(bus_space_tag_t iot, bus_space_handle_t ioh) +wbsio_conf_enable(kmutex_t *lock, bus_space_tag_t iot, bus_space_handle_t ioh) { + if (lock) + mutex_enter(lock); + bus_space_write_1(iot, ioh, WBSIO_INDEX, WBSIO_CONF_EN_MAGIC); bus_space_write_1(iot, ioh, WBSIO_INDEX, WBSIO_CONF_EN_MAGIC); } static __inline void -wbsio_conf_disable(bus_space_tag_t iot, bus_space_handle_t ioh) +wbsio_conf_disable(kmutex_t *lock, bus_space_tag_t iot, bus_space_handle_t ioh) { + bus_space_write_1(iot, ioh, WBSIO_INDEX, WBSIO_CONF_DS_MAGIC); + + if (lock) + mutex_exit(lock); } static __inline uint8_t @@ -155,11 +208,11 @@ wbsio_match(device_t parent, cfdata_t ma iot = ia->ia_iot; if (bus_space_map(iot, ia->ia_io[0].ir_addr, WBSIO_IOSIZE, 0, &ioh)) return 0; - wbsio_conf_enable(iot, ioh); + wbsio_conf_enable(NULL, iot, ioh); id = wbsio_conf_read(iot, ioh, WBSIO_ID); rev = wbsio_conf_read(iot, ioh, WBSIO_REV); aprint_debug("wbsio_probe: id 0x%02x, rev 0x%02x\n", id, rev); - wbsio_conf_disable(iot, ioh); + wbsio_conf_disable(NULL, iot, ioh); bus_space_unmap(iot, ioh, WBSIO_IOSIZE); if ((product = wbsio_lookup(id, rev)) == NULL) @@ -195,8 +248,10 @@ wbsio_attach(device_t parent, device_t s return; } + mutex_init(&sc->sc_conf_lock, MUTEX_DEFAULT, IPL_NONE); + /* Enter configuration mode */ - wbsio_conf_enable(sc->sc_iot, sc->sc_ioh); + wbsio_conf_enable(&sc->sc_conf_lock, sc->sc_iot, sc->sc_ioh); /* Read device ID */ id = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_ID); @@ -204,7 +259,7 @@ wbsio_attach(device_t parent, device_t s rev = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_REV); /* Escape from configuration mode */ - wbsio_conf_disable(sc->sc_iot, sc->sc_ioh); + wbsio_conf_disable(&sc->sc_conf_lock, sc->sc_iot, sc->sc_ioh); if ((product = wbsio_lookup(id, rev)) == NULL) { aprint_error_dev(self, "Unknown device. Failed to attach\n"); @@ -226,9 +281,17 @@ wbsio_attach(device_t parent, device_t s } else aprint_normal("0x%02x\n", rev); - if (!pmf_device_register(self, NULL, NULL)) + if (!pmf_device_register(self, wbsio_suspend, NULL)) aprint_error_dev(self, "couldn't establish power handler\n"); + + wbsio_wdog_attach(self); + wbsio_rescan(self, "wbsio", NULL); + +#if NGPIO > 0 + + wbsio_rescan(self, "gpiobus", NULL); +#endif } int @@ -237,10 +300,26 @@ wbsio_detach(device_t self, int flags) struct wbsio_softc *sc = device_private(self); int rc; + if ((rc = wbsio_wdog_detach(self)) != 0) + return rc; + if ((rc = config_detach_children(self, flags)) != 0) return rc; bus_space_unmap(sc->sc_iot, sc->sc_ioh, WBSIO_IOSIZE); pmf_device_deregister(self); + +#if NGPIO > 0 + if (sc->sc_gpio_dev) { + bus_space_unmap(sc->sc_iot, sc->sc_gpio_ioh, + WBSIO_GPIO_IOSIZE); + } + + if (sc->sc_gpio_rt) { + mutex_destroy(&sc->sc_gpio_lock); + } +#endif + + mutex_destroy(&sc->sc_conf_lock); return 0; } @@ -248,6 +327,13 @@ int wbsio_rescan(device_t self, const char *ifattr, const int *locators) { +#if NGPIO > 0 + if (ifattr_match(ifattr, "gpiobus")) { + config_search_loc(wbsio_gpio_search, self, + ifattr, locators, NULL); + return 0; + } +#endif config_search_loc(wbsio_search, self, ifattr, locators, NULL); return 0; @@ -272,7 +358,7 @@ wbsio_search(device_t parent, cfdata_t c uint8_t reg0, reg1, rev; /* Enter configuration mode */ - wbsio_conf_enable(sc->sc_iot, sc->sc_ioh); + wbsio_conf_enable(&sc->sc_conf_lock, sc->sc_iot, sc->sc_ioh); /* Select HM logical device */ wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_LDN, WBSIO_LDN_HM); @@ -287,7 +373,7 @@ wbsio_search(device_t parent, cfdata_t c reg1 = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_HM_ADDR_MSB); /* Escape from configuration mode */ - wbsio_conf_disable(sc->sc_iot, sc->sc_ioh); + wbsio_conf_disable(&sc->sc_conf_lock, sc->sc_iot, sc->sc_ioh); iobase = (reg1 << 8) | (reg0 & ~0x7); @@ -295,12 +381,12 @@ wbsio_search(device_t parent, cfdata_t c return -1; /* Enter configuration mode */ - wbsio_conf_enable(sc->sc_iot, sc->sc_ioh); + wbsio_conf_enable(&sc->sc_conf_lock, sc->sc_iot, sc->sc_ioh); /* Read device ID and revision */ devid = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_ID); rev = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_REV); /* Escape from configuration mode */ - wbsio_conf_disable(sc->sc_iot, sc->sc_ioh); + wbsio_conf_disable(&sc->sc_conf_lock, sc->sc_iot, sc->sc_ioh); if ((product = wbsio_lookup(devid, rev)) == NULL) { aprint_error_dev(parent, "%s: Unknown device.\n", __func__); @@ -338,7 +424,520 @@ wbsio_print(void *aux, const char *pnp) return (UNCONF); } -MODULE(MODULE_CLASS_DRIVER, wbsio, NULL); +static bool +wbsio_suspend(device_t self, const pmf_qual_t *qual) +{ + struct wbsio_softc *sc = device_private(self); + + if (sc->sc_smw_valid) { + if ((sc->sc_smw.smw_mode & WDOG_MODE_MASK) + != WDOG_MODE_DISARMED) + return false; + } + + return true; +} + +#if NGPIO > 0 +static int +wbsio_gpio_search(device_t parent, cfdata_t cf, const int *slocs, void *aux) +{ + struct wbsio_softc *sc = device_private(parent); + const struct wbsio_product *product; + struct gpiobus_attach_args gba; + uint16_t devid; + uint8_t rev; + int i; + + /* Enter configuration mode */ + wbsio_conf_enable(&sc->sc_conf_lock, sc->sc_iot, sc->sc_ioh); + /* Read device ID and revision */ + devid = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_ID); + rev = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_REV); + /* Escape from configuration mode */ + wbsio_conf_disable(&sc->sc_conf_lock, sc->sc_iot, sc->sc_ioh); + + if ((product = wbsio_lookup(devid, rev)) == NULL) { + aprint_error_dev(parent, "%s: Unknown device.\n", __func__); + return -1; + } + + sc->sc_gpio_rt = false; + + switch (product->id) { + case WBSIO_ID_NCT6779D: + wbsio_gpio_enable_nct6779d(parent); + sc->sc_gpio_rt = true; + break; + default: + aprint_error_dev(parent, "%s's GPIO is not supported yet\n", + product->str); + return -1; + } + + if (sc->sc_gpio_rt) { + if (wbsio_gpio_rt_init(sc) != 0) { + sc->sc_gpio_rt = false; + return -1; + } + sc->sc_gpio_gc.gp_cookie = sc; + sc->sc_gpio_gc.gp_pin_read = wbsio_gpio_rt_pin_read; + sc->sc_gpio_gc.gp_pin_write = wbsio_gpio_rt_pin_write; + sc->sc_gpio_gc.gp_pin_ctl = wbsio_gpio_rt_pin_ctl; + } else { + aprint_error_dev(parent, + "GPIO indirect access is not supported\n"); + return -1; + } + + for (i = 0; i < WBSIO_GPIO_NPINS; i++) { + sc->sc_gpio_pins[i].pin_num = i; + sc->sc_gpio_pins[i].pin_caps = GPIO_PIN_INPUT | + GPIO_PIN_OUTPUT | GPIO_PIN_INVIN | GPIO_PIN_INVOUT; + + /* safe defaults */ + sc->sc_gpio_pins[i].pin_flags = GPIO_PIN_INPUT; + sc->sc_gpio_pins[i].pin_state = GPIO_PIN_LOW; + sc->sc_gpio_gc.gp_pin_ctl(sc, i, sc->sc_gpio_pins[i].pin_flags); + sc->sc_gpio_gc.gp_pin_write(sc, i, sc->sc_gpio_pins[i].pin_state); + } + + switch (product->id) { + case WBSIO_ID_NCT6779D: + wbsio_gpio_pinconfig_nct6779d(parent); + break; + } + + gba.gba_gc = &sc->sc_gpio_gc; + gba.gba_pins = sc->sc_gpio_pins; + gba.gba_npins = WBSIO_GPIO_NPINS; + + sc->sc_gpio_dev = config_attach(parent, cf, &gba, gpiobus_print); + + return 0; +} + +static int +wbsio_gpio_rt_init(struct wbsio_softc *sc) +{ + uint16_t iobase; + uint8_t reg0, reg1; + + /* Enter configuration mode */ + wbsio_conf_enable(&sc->sc_conf_lock, sc->sc_iot, sc->sc_ioh); + + /* Get GPIO Register Table address */ + wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_LDN, WBSIO_LDN_GPIO0); + reg0 = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_GPIO_ADDR_LSB); + reg1 = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_GPIO_ADDR_MSB); + iobase = (reg1 << 8) | (reg0 & ~0x7); + + /* Escape from configuration mode */ + wbsio_conf_disable(&sc->sc_conf_lock, sc->sc_iot, sc->sc_ioh); + + if (bus_space_map(sc->sc_iot, iobase, WBSIO_GPIO_IOSIZE, + 0, &sc->sc_gpio_ioh)) { + aprint_error_dev(sc->sc_dev, + "can't map gpio to i/o space\n"); + return -1; + } + + aprint_normal_dev(sc->sc_dev, "GPIO: port 0x%x-0x%x\n", + iobase, iobase + WBSIO_GPIO_IOSIZE); + + mutex_init(&sc->sc_gpio_lock, MUTEX_DEFAULT, IPL_NONE); + + return 0; +} + +static int +wbsio_gpio_rt_read(struct wbsio_softc *sc, int port, int reg) +{ + int v; + + mutex_enter(&sc->sc_gpio_lock); + + bus_space_write_1(sc->sc_iot, sc->sc_gpio_ioh, + WBSIO_GPIO_GSR, port); + v = bus_space_read_1(sc->sc_iot, sc->sc_gpio_ioh, reg); + + mutex_exit(&sc->sc_gpio_lock); + + return v; +} + +static void +wbsio_gpio_rt_write(struct wbsio_softc *sc, int port, int reg, int value) +{ + + mutex_enter(&sc->sc_gpio_lock); + + bus_space_write_1(sc->sc_iot, sc->sc_gpio_ioh, + WBSIO_GPIO_GSR, port); + bus_space_write_1(sc->sc_iot, sc->sc_gpio_ioh, + reg, value); + + mutex_exit(&sc->sc_gpio_lock); +} + +static int +wbsio_gpio_rt_pin_read(void *aux, int pin) +{ + struct wbsio_softc *sc = (struct wbsio_softc *)aux; + int port, shift, data; + + port = (pin >> 3) & 0x07; + shift = pin & 0x07; + + data = wbsio_gpio_rt_read(sc, port, WBSIO_GPIO_DAT); + + return ((data >> shift) & 0x01); +} + +static void +wbsio_gpio_rt_pin_write(void *aux, int pin, int v) +{ + struct wbsio_softc *sc = (struct wbsio_softc *)aux; + int port, shift, data; + + port = (pin >> 3) & 0x07; + shift = pin & 0x07; + + data = wbsio_gpio_rt_read(sc, port, WBSIO_GPIO_DAT); + + if (v == 0) + data &= ~(1 << shift); + else if (v == 1) + data |= (1 << shift); + + wbsio_gpio_rt_write(sc, port, WBSIO_GPIO_DAT, data); +} + +static void +wbsio_gpio_rt_pin_ctl(void *aux, int pin, int flags) +{ + struct wbsio_softc *sc = (struct wbsio_softc *)aux; + uint8_t ior, inv; + int port, shift; + + port = (pin >> 3) & 0x07; + shift = pin & 0x07; + + ior = wbsio_gpio_rt_read(sc, port, WBSIO_GPIO_IOR); + inv = wbsio_gpio_rt_read(sc, port, WBSIO_GPIO_INV); + + if (flags & GPIO_PIN_INPUT) { + ior |= (1 << shift); + inv &= ~(1 << shift); + } else if (flags & GPIO_PIN_OUTPUT) { + ior &= ~(1 << shift); + inv &= ~(1 << shift); + } else if (flags & GPIO_PIN_INVIN) { + ior |= (1 << shift); + inv |= (1 << shift); + } else if (flags & GPIO_PIN_INVOUT) { + ior &= ~(1 << shift); + inv |= (1 << shift); + } + + wbsio_gpio_rt_write(sc, port, WBSIO_GPIO_IOR, ior); + wbsio_gpio_rt_write(sc, port, WBSIO_GPIO_INV, inv); +} + +static void +wbsio_gpio_enable_nct6779d(device_t parent) +{ + struct wbsio_softc *sc = device_private(parent); + uint8_t reg, conf; + + /* Enter configuration mode */ + wbsio_conf_enable(&sc->sc_conf_lock, sc->sc_iot, sc->sc_ioh); + + wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_LDN, WBSIO_LDN_GPIO0); + reg = WBSIO_GPIO_CONF; + conf = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, reg); + /* Activate Register Table access */ + conf |= WBSIO_GPIO_BASEADDR; + + conf |= WBSIO_GPIO0_ENABLE; + wbsio_conf_write(sc->sc_iot, sc->sc_ioh, reg, conf); + + wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_LDN, WBSIO_LDN_GPIO1); + reg = WBSIO_GPIO_CONF; + conf = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, reg); + conf |= WBSIO_GPIO1_ENABLE; + conf |= WBSIO_GPIO2_ENABLE; + conf |= WBSIO_GPIO3_ENABLE; + conf |= WBSIO_GPIO4_ENABLE; + conf |= WBSIO_GPIO5_ENABLE; + conf |= WBSIO_GPIO6_ENABLE; + conf |= WBSIO_GPIO7_ENABLE; + wbsio_conf_write(sc->sc_iot, sc->sc_ioh, reg, conf); + + /* Escape from configuration mode */ + wbsio_conf_disable(&sc->sc_conf_lock, sc->sc_iot, sc->sc_ioh); +} + +static void +wbsio_gpio_pinconfig_nct6779d(device_t parent) +{ + struct wbsio_softc *sc = device_private(parent); + uint8_t sfr, mfs0, mfs1, mfs2, mfs3; + uint8_t mfs4, mfs5, mfs6, gopt2, hm_conf; + + /* Enter configuration mode */ + wbsio_conf_enable(&sc->sc_conf_lock, sc->sc_iot, sc->sc_ioh); + + /* Strapping Function Result */ + sfr = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_SFR); + sfr &= ~(WBSIO_SFR_LPT | WBSIO_SFR_DSW | WBSIO_SFR_AMDPWR); + + /* Read current configuration */ + mfs0 = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_MFS0); + mfs1 = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_MFS1); + mfs2 = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_MFS2); + mfs3 = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_MFS3); + mfs4 = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_MFS4); + mfs5 = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_MFS5); + mfs6 = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_MFS6); + gopt2 = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_GOPT2); + + wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_LDN, WBSIO_LDN_HM); + hm_conf = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_HM_CONF); + + /* GPIO0 pin configs */ + mfs2 |= WBSIO_NCT6779D_MFS2_GP00; + mfs2 |= WBSIO_NCT6779D_MFS2_GP01; + mfs2 |= WBSIO_NCT6779D_MFS2_GP02; + mfs2 &= ~WBSIO_NCT6779D_MFS2_GP03_MASK; + mfs2 |= WBSIO_NCT6779D_MFS2_GP04; + mfs2 |= WBSIO_NCT6779D_MFS2_GP05; + mfs2 |= WBSIO_NCT6779D_MFS2_GP06; + mfs3 &= ~WBSIO_NCT6779D_MFS3_GP07_MASK; + + /* GPIO1 pin configs */ + mfs4 |= WBSIO_NCT6779D_MFS4_GP10_GP17; + + /* GPIO2 pin configs */ + mfs4 |= WBSIO_NCT6779D_MFS4_GP20_GP21; + mfs4 |= WBSIO_NCT6779D_MFS4_GP22_GP23; + mfs1 &= ~WBSIO_NCT6779D_MFS1_GP24_MASK; + gopt2 &= ~WBSIO_NCT6779D_GOPT2_GP24_MASK; + mfs4 &= ~WBSIO_NCT6779D_MFS4_GP25_MASK; + gopt2 &= ~WBSIO_NCT6779D_GOPT2_GP25_MASK; + mfs6 |= WBSIO_NCT6779D_MFS6_GP26; + mfs6 &= ~WBSIO_NCT6779D_MFS6_GP27_MASK; + + /* GPIO3 pin configs */ + mfs0 &= ~WBSIO_NCT6779D_MFS0_GP30_MASK; + mfs0 |= WBSIO_NCT6779D_MFS0_GP30; + mfs1 &= ~WBSIO_NCT6779D_MFS1_GP31_MASK; + mfs0 |= WBSIO_NCT6779D_MFS0_GP31; + mfs1 &= ~WBSIO_NCT6779D_MFS1_GP32_MASK; + mfs0 |= WBSIO_NCT6779D_MFS0_GP32; + mfs6 &= ~WBSIO_NCT6779D_MFS6_GP33_MASK; + mfs6 |= WBSIO_NCT6779D_MFS6_GP33; + /* GP34, 35 and 36 are enabled by LPT_EN=0 */ + /* GP37 is not existed */ + + /* GPIO4 pin configs */ + mfs1 |= WBSIO_NCT6779D_MFS1_GP40; + /* GP41 to GP46 requires LPT_EN=0 */ + mfs0 &= ~WBSIO_NCT6779D_MFS0_GP41_MASK; + mfs0 |= WBSIO_NCT6779D_MFS0_GP41; + mfs1 |= WBSIO_NCT6779D_MFS1_GP42; + mfs1 |= WBSIO_NCT6779D_MFS1_GP42; + gopt2 |= WBSIO_NCT6779D_GOPT2_GP43; + mfs1 &= ~WBSIO_NCT6779D_MFS1_GP44_GP45_MASK; + gopt2 &= ~WBSIO_NCT6779D_GOPT2_GP46_MASK; + mfs1 |= WBSIO_NCT6779D_MFS1_GP47; + + /* GPIO5 pin configs */ + /* GP50 to GP55 requires DSW_EN=0 */ + hm_conf &= ~WBSIO_NCT6779D_HM_GP50_MASK; + /* GP51 is enabled by DSW_EN=0 */ + hm_conf &= ~WBSIO_NCT6779D_HM_GP52_MASK; + /* GP53 and GP54 are enabled by DSW_EN=0 */ + hm_conf &= ~WBSIO_NCT6779D_HM_GP55_MASK; + /* GP56 and GP57 are enabled by AMDPWR_EN=0 */ + + /* GPIO6 pin configs are shared with GP43 */ + + /* GPIO7 pin configs */ + /* GP70 to GP73 are enabled by TEST_MODE_EN */ + mfs5 |= WBSIO_NCT6779D_MFS5_GP74; + mfs5 |= WBSIO_NCT6779D_MFS5_GP75; + mfs5 |= WBSIO_NCT6779D_MFS5_GP76; + /* GP77 is not existed */ + + /* Write all pin configs */ + wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_SFR, sfr); + wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_MFS0, mfs0); + wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_MFS1, mfs1); + wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_MFS2, mfs2); + wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_MFS3, mfs3); + wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_MFS4, mfs4); + wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_MFS5, mfs5); + wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_MFS6, mfs6); + wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_GOPT2, gopt2); + + wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_LDN, WBSIO_LDN_HM); + wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_HM_CONF, hm_conf); + + /* Escape from configuration mode */ + wbsio_conf_disable(&sc->sc_conf_lock, sc->sc_iot, sc->sc_ioh); +} + +#endif /* NGPIO > 0 */ + +static void +wbsio_wdog_attach(device_t self) +{ + struct wbsio_softc *sc = device_private(self); + const struct wbsio_product *product; + uint8_t gpio, mode; + uint16_t devid; + uint8_t rev; + + sc->sc_smw_valid = false; + + wbsio_conf_enable(&sc->sc_conf_lock, sc->sc_iot, sc->sc_ioh); + devid = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_ID); + rev = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_REV); + wbsio_conf_disable(&sc->sc_conf_lock, sc->sc_iot, sc->sc_ioh); + + if ((product = wbsio_lookup(devid, rev)) == NULL) { + return; + } + + switch (product->id) { + case WBSIO_ID_NCT6779D: + break; + default: + /* WDT is not supoorted */ + return; + } + + wbsio_wdog_setcounter(sc, WBSIO_WDT_CNTR_STOP); + + wbsio_conf_enable(&sc->sc_conf_lock, sc->sc_iot, sc->sc_ioh); + wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_LDN, WBSIO_LDN_GPIO0); + + gpio = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_GPIO_CONF); + mode = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_WDT_MODE); + + gpio |= WBSIO_GPIO0_WDT1; + + mode &= ~WBSIO_WDT_MODE_FASTER; + mode &= ~WBSIO_WDT_MODE_MINUTES; + mode &= ~WBSIO_WDT_MODE_KBCRST; + mode &= ~WBSIO_WDT_MODE_LEVEL; + + /* initialize WDT mode */ + wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_WDT_MODE, mode); + /* Activate WDT1 function */ + wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_GPIO_CONF, gpio); + + wbsio_conf_disable(&sc->sc_conf_lock, sc->sc_iot, sc->sc_ioh); + + sc->sc_smw.smw_name = device_xname(self); + sc->sc_smw.smw_cookie = sc; + sc->sc_smw.smw_setmode = wbsio_wdog_setmode; + sc->sc_smw.smw_tickle = wbsio_wdog_tickle; + sc->sc_smw.smw_period = WBSIO_WDT_CNTR_MAX; + + if (sysmon_wdog_register(&sc->sc_smw)) + aprint_error_dev(self, "couldn't register with sysmon\n"); + else + sc->sc_smw_valid = true; +} + +static int +wbsio_wdog_detach(device_t self) +{ + struct wbsio_softc *sc = device_private(self); + int error; + + error = 0; + + if (sc->sc_smw_valid) { + if ((sc->sc_smw.smw_mode & WDOG_MODE_MASK) + != WDOG_MODE_DISARMED) + return EBUSY; + + error = sysmon_wdog_unregister(&sc->sc_smw); + } + + if (!error) + sc->sc_smw_valid = false; + + return error; +} + +static int +wbsio_wdog_setmode(struct sysmon_wdog *smw) +{ + + switch(smw->smw_mode & WDOG_MODE_MASK) { + case WDOG_MODE_DISARMED: + wbsio_wdog_setcounter(smw->smw_cookie, WBSIO_WDT_CNTR_STOP); + wbsio_wdog_clear_timeout(smw->smw_cookie); + break; + default: + if (smw->smw_period > WBSIO_WDT_CNTR_MAX + || smw->smw_period == 0) + return EINVAL; + + wbsio_wdog_setcounter(smw->smw_cookie, smw->smw_period); + } + + return 0; +} + +static void +wbsio_wdog_setcounter(struct wbsio_softc *sc, uint8_t period) +{ + + KASSERT(!mutex_owned(&sc->sc_conf_lock)); + + wbsio_conf_enable(&sc->sc_conf_lock, sc->sc_iot, sc->sc_ioh); + + wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_LDN, WBSIO_LDN_GPIO0); + wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_WDT_CNTR, period); + + wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_LDN, WBSIO_LDN_GPIO0); + + + wbsio_conf_disable(&sc->sc_conf_lock, sc->sc_iot, sc->sc_ioh); +} + +static void +wbsio_wdog_clear_timeout(struct wbsio_softc *sc) +{ + uint8_t st; + + KASSERT(!mutex_owned(&sc->sc_conf_lock)); + + wbsio_conf_enable(&sc->sc_conf_lock, sc->sc_iot, sc->sc_ioh); + + st = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_WDT_STAT); + st &= ~WBSIO_WDT_STAT_TIMEOUT; + wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_WDT_STAT, st); + + wbsio_conf_disable(&sc->sc_conf_lock, sc->sc_iot, sc->sc_ioh); +} + +static int +wbsio_wdog_tickle(struct sysmon_wdog *smw) +{ + + wbsio_wdog_setcounter(smw->smw_cookie, smw->smw_period); + + return 0; +} + + +MODULE(MODULE_CLASS_DRIVER, wbsio, "sysmon_wdog"); #ifdef _MODULE #include "ioconf.c" Index: src/sys/dev/isa/wbsioreg.h diff -u src/sys/dev/isa/wbsioreg.h:1.5.2.2 src/sys/dev/isa/wbsioreg.h:1.5.2.3 --- src/sys/dev/isa/wbsioreg.h:1.5.2.2 Wed Nov 22 14:56:30 2017 +++ src/sys/dev/isa/wbsioreg.h Mon Feb 19 18:50:35 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: wbsioreg.h,v 1.5.2.2 2017/11/22 14:56:30 martin Exp $ */ +/* $NetBSD: wbsioreg.h,v 1.5.2.3 2018/02/19 18:50:35 snj Exp $ */ /* $OpenBSD: wbsioreg.h,v 1.4 2015/01/02 23:02:54 chris Exp $ */ /* @@ -32,8 +32,21 @@ /* Configuration Space Registers */ #define WBSIO_LDN 0x07 /* Logical Device Number */ +#define WBSIO_MFS0 0x1A /* Multi Function Selection 0 */ +#define WBSIO_MFS1 0x1B /* Multi Function Selection 1 */ +#define WBSIO_MFS2 0x1C /* Multi Function Selection 2 */ +#define WBSIO_MFS3 0x1D /* Multi Function Selection 3 */ #define WBSIO_ID 0x20 /* Device ID */ #define WBSIO_REV 0x21 /* Device Revision */ +#define WBSIO_GOPT0 0x24 /* Global Option 0 */ +#define WBSIO_GOPT1 0x26 /* Global Option 1 */ +#define WBSIO_GOPT2 0x27 /* Global Option 2 */ +#define WBSIO_GOPT3 0x28 /* Global Option 3 */ +#define WBSIO_MFS4 0x2A /* Multi Function Selection 4 */ +#define WBSIO_MFS5 0x2B /* Multi Function Selection 5 */ +#define WBSIO_MFS6 0x2C /* Multi Function Selection 6 */ +#define WBSIO_SFR 0x2F /* Strapping Function Result */ + #define WBSIO_ID_W83627HF 0x52 #define WBSIO_ID_W83697HF 0x60 @@ -58,10 +71,111 @@ #define WBSIO_ID_NCT6793D 0xd12 #define WBSIO_ID_NCT6795D 0xd35 +/* Strapping Function Result */ +#define WBSIO_SFR_24M48M 0x01 +#define WBSIO_SFR_LPT 0x02 +#define WBSIO_SFR_TEST 0x04 +#define WBSIO_SFR_DSW 0x08 +#define WBSIO_SFR_AMDPWR 0x20 +#define WBSIO_SFR_UARTP80 0x40 + /* Logical Device Number (LDN) Assignments */ #define WBSIO_LDN_HM 0x0b +#define WBSIO_LDN_GPIO0 0x08 /* WDT, GPIO 0 */ +#define WBSIO_LDN_GPIO1 0x09 /* GPIO 1 to GPIO 8 */ /* Hardware Monitor Control Registers (LDN B) */ #define WBSIO_HM_ADDR_MSB 0x60 /* Address [15:8] */ #define WBSIO_HM_ADDR_LSB 0x61 /* Address [7:0] */ - +#define WBSIO_HM_CONF 0xE4 /* Configuration Register */ +#define WBSIO_HM_CONF_RSTOUT4 0x02 /* RSTOUT4# bit */ +#define WBSIO_HM_CONF_RSTOUT3 0x04 /* RSTOUT3# bit */ +#define WBSIO_HM_CONF_PWROK 0x08 /* Power OK Bit */ + +/* GPIO Registers */ +#define WBSIO_GPIO_ADDR_MSB 0x60 /* Address [15:8] */ +#define WBSIO_GPIO_ADDR_LSB 0x61 /* Address [7:0] */ +#define WBSIO_GPIO_CONF 0x30 /* GPIO0, WDT1 config */ +#define WBSIO_WDT_MODE 0xF5 /* WDT1 Control Mode */ +#define WBSIO_WDT_CNTR 0xF6 /* WDT1 Counter */ +#define WBSIO_WDT_STAT 0xF7 /* WDT1 Control & Status */ +#define WBSIO_GPIO4_MFS 0xEE /* GPIO4 Multi-Function Select */ + +#define WBSIO_GPIO0_WDT1 __BIT(0) +#define WBSIO_GPIO0_ENABLE __BIT(1) + + /* Reserved */ +#define WBSIO_GPIO_BASEADDR __BIT(3) /* Base address mode */ +#define WBSIO_GPIO1_ENABLE __BIT(1) +#define WBSIO_GPIO2_ENABLE __BIT(2) +#define WBSIO_GPIO3_ENABLE __BIT(3) +#define WBSIO_GPIO4_ENABLE __BIT(4) +#define WBSIO_GPIO5_ENABLE __BIT(5) +#define WBSIO_GPIO6_ENABLE __BIT(6) +#define WBSIO_GPIO7_ENABLE __BIT(7) +#define WBSIO_GPIO8_ENABLE __BIT(0) + +#define WBSIO_GPIO_NPINS 64 +#define WBSIO_GPIO_IOSIZE 0x06 /* GPIO register table size */ + +#define WBSIO_GPIO_GSR 0x00 /* GPIO Select Register */ +#define WBSIO_GPIO_IOR 0x01 /* I/O direction */ +#define WBSIO_GPIO_DAT 0x02 /* Data */ +#define WBSIO_GPIO_INV 0x03 /* Inversion */ +#define WBSIO_GPIO_DST 0x04 /* Event Status */ + /* WDT1 Control Mode */ + /* WDT1 control */ +#define WBSIO_WDT_MODE_LEVEL __BIT(0) + /* enable/disable KBRST */ +#define WBSIO_WDT_MODE_KBCRST __BIT(2) +#define WBSIO_WDT_MODE_MINUTES __BIT(3) +#define WBSIO_WDT_MODE_FASTER __BIT(4) + +#define WBSIO_WDT_CNTR_STOP 0 +#define WBSIO_WDT_CNTR_MAX 255 + +#define WBSIO_WDT_STAT_TIMEOUT __BIT(4) +#define WBSIO_WDT_STAT_EVENT __BIT(5) + + +/* NCT6779D */ +#define WBSIO_NCT6779D_MFS2_GP00 __BIT(0) +#define WBSIO_NCT6779D_MFS2_GP01 __BIT(1) +#define WBSIO_NCT6779D_MFS2_GP02 __BIT(2) +#define WBSIO_NCT6779D_MFS2_GP03_MASK (__BIT(3)|__BIT(4)) +#define WBSIO_NCT6779D_MFS2_GP04 __BIT(5) +#define WBSIO_NCT6779D_MFS2_GP05 __BIT(6) +#define WBSIO_NCT6779D_MFS2_GP06 __BIT(7) +#define WBSIO_NCT6779D_MFS3_GP07_MASK __BIT(0) +#define WBSIO_NCT6779D_MFS4_GP10_GP17 __BIT(6) +#define WBSIO_NCT6779D_MFS4_GP20_GP21 __BIT(0) +#define WBSIO_NCT6779D_MFS4_GP22_GP23 __BIT(1) +#define WBSIO_NCT6779D_MFS1_GP24_MASK __BIT(4) +#define WBSIO_NCT6779D_GOPT2_GP24_MASK __BIT(3) +#define WBSIO_NCT6779D_MFS4_GP25_MASK __BIT(3) +#define WBSIO_NCT6779D_GOPT2_GP25_MASK __BIT(3) +#define WBSIO_NCT6779D_MFS6_GP26 __BIT(0) +#define WBSIO_NCT6779D_MFS6_GP27_MASK (__BIT(3)|__BIT(4)) +#define WBSIO_NCT6779D_MFS0_GP30 __BIT(6) +#define WBSIO_NCT6779D_MFS0_GP30_MASK __BIT(7) +#define WBSIO_NCT6779D_MFS0_GP31 __BIT(5) +#define WBSIO_NCT6779D_MFS1_GP31_MASK __BIT(0) +#define WBSIO_NCT6779D_MFS0_GP32 __BIT(4) +#define WBSIO_NCT6779D_MFS1_GP32_MASK __BIT(0) +#define WBSIO_NCT6779D_MFS6_GP33 __BIT(7) +#define WBSIO_NCT6779D_MFS6_GP33_MASK __BIT(6) +#define WBSIO_NCT6779D_MFS1_GP40 __BIT(3) +#define WBSIO_NCT6779D_MFS0_GP41 __BIT(3) +#define WBSIO_NCT6779D_MFS0_GP41_MASK __BIT(2) +#define WBSIO_NCT6779D_MFS1_GP42 (__BIT(1)|__BIT(2)) +#define WBSIO_NCT6779D_GOPT2_GP43 __BIT(4) +#define WBSIO_NCT6779D_MFS1_GP44_GP45_MASK __BIT(6) +#define WBSIO_NCT6779D_GOPT2_GP46_MASK __BIT(5) +#define WBSIO_NCT6779D_MFS1_GP47 __BIT(7) +#define WBSIO_NCT6779D_HM_GP50_MASK __BIT(2) +#define WBSIO_NCT6779D_HM_GP52_MASK __BIT(1) +#define WBSIO_NCT6779D_HM_GP55_MASK __BIT(3) +#define WBSIO_NCT6779D_MFS5_GP74 __BIT(5) +#define WBSIO_NCT6779D_MFS5_GP75 __BIT(6) +#define WBSIO_NCT6779D_MFS5_GP76 __BIT(7) +#define WBSIO_NCT6779D_GPIO4_WDTO __BIT(4)