Module Name: src
Committed By: knakahara
Date: Wed Dec 13 00:27:53 UTC 2017
Modified Files:
src/sys/dev/isa: wbsio.c wbsioreg.h
Log Message:
Add Watchdog timer implementation to wbsio(4). Implemeted by s-yamaguchi@IIJ,
reviewed by [email protected].
I just commit by proxy.
To generate a diff of this commit:
cvs rdiff -u -r1.17 -r1.18 src/sys/dev/isa/wbsio.c
cvs rdiff -u -r1.6 -r1.7 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/sys/dev/isa/wbsio.c
diff -u src/sys/dev/isa/wbsio.c:1.17 src/sys/dev/isa/wbsio.c:1.18
--- src/sys/dev/isa/wbsio.c:1.17 Wed Dec 13 00:27:01 2017
+++ src/sys/dev/isa/wbsio.c Wed Dec 13 00:27:53 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: wbsio.c,v 1.17 2017/12/13 00:27:01 knakahara Exp $ */
+/* $NetBSD: wbsio.c,v 1.18 2017/12/13 00:27:53 knakahara Exp $ */
/* $OpenBSD: wbsio.c,v 1.10 2015/03/14 03:38:47 jsg Exp $ */
/*
* Copyright (c) 2008 Mark Kettenis <[email protected]>
@@ -34,6 +34,7 @@
#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 */
#ifndef _MODULE
@@ -52,6 +53,7 @@ struct wbsio_softc {
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;
@@ -63,6 +65,9 @@ struct wbsio_softc {
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 {
@@ -101,6 +106,7 @@ 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 *);
@@ -112,22 +118,35 @@ static void wbsio_gpio_rt_pin_ctl(void *
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
@@ -188,11 +207,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)
@@ -228,8 +247,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);
@@ -237,7 +258,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");
@@ -259,8 +280,11 @@ 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
@@ -275,6 +299,9 @@ 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);
@@ -290,6 +317,8 @@ wbsio_detach(device_t self, int flags)
mutex_destroy(&sc->sc_gpio_lock);
}
#endif
+
+ mutex_destroy(&sc->sc_conf_lock);
return 0;
}
@@ -328,7 +357,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);
@@ -343,7 +372,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);
@@ -351,12 +380,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__);
@@ -394,6 +423,20 @@ wbsio_print(void *aux, const char *pnp)
return (UNCONF);
}
+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)
@@ -406,12 +449,12 @@ wbsio_gpio_search(device_t parent, cfdat
int i;
/* 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__);
@@ -479,7 +522,7 @@ wbsio_gpio_rt_init(struct wbsio_softc *s
uint8_t reg0, reg1;
/* 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);
/* Get GPIO Register Table address */
wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_LDN, WBSIO_LDN_GPIO0);
@@ -488,7 +531,7 @@ wbsio_gpio_rt_init(struct wbsio_softc *s
iobase = (reg1 << 8) | (reg0 & ~0x7);
/* 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 (bus_space_map(sc->sc_iot, iobase, WBSIO_GPIO_IOSIZE,
0, &sc->sc_gpio_ioh)) {
@@ -606,7 +649,7 @@ wbsio_gpio_enable_nct6779d(device_t pare
uint8_t reg, conf;
/* 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);
wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_LDN, WBSIO_LDN_GPIO0);
reg = WBSIO_GPIO_CONF;
@@ -630,7 +673,7 @@ wbsio_gpio_enable_nct6779d(device_t pare
wbsio_conf_write(sc->sc_iot, sc->sc_ioh, reg, conf);
/* 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);
}
static void
@@ -641,7 +684,7 @@ wbsio_gpio_pinconfig_nct6779d(device_t p
uint8_t mfs4, mfs5, mfs6, gopt2, hm_conf;
/* 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);
/* Strapping Function Result */
sfr = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_SFR);
@@ -740,10 +783,157 @@ wbsio_gpio_pinconfig_nct6779d(device_t p
wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_HM_CONF, hm_conf);
/* 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);
+}
+
+#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;
}
-#endif
MODULE(MODULE_CLASS_DRIVER, wbsio, NULL);
Index: src/sys/dev/isa/wbsioreg.h
diff -u src/sys/dev/isa/wbsioreg.h:1.6 src/sys/dev/isa/wbsioreg.h:1.7
--- src/sys/dev/isa/wbsioreg.h:1.6 Wed Dec 13 00:26:06 2017
+++ src/sys/dev/isa/wbsioreg.h Wed Dec 13 00:27:53 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: wbsioreg.h,v 1.6 2017/12/13 00:26:06 knakahara Exp $ */
+/* $NetBSD: wbsioreg.h,v 1.7 2017/12/13 00:27:53 knakahara Exp $ */
/* $OpenBSD: wbsioreg.h,v 1.4 2015/01/02 23:02:54 chris Exp $ */
/*
@@ -96,8 +96,15 @@
#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)
@@ -116,8 +123,20 @@
#define WBSIO_GPIO_DAT 0x02 /* Data */
#define WBSIO_GPIO_INV 0x03 /* Inversion */
#define WBSIO_GPIO_DST 0x04 /* Event Status */
-#define WBSIO_GPIO_WDTMOD 0x05
-#define WBSIO_GPIO_WDTTIM 0x06
+ /* 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)
@@ -159,3 +178,4 @@
#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)