Hi
I have created a driver for the watchdog on the W83627HF. It would be
very easy to support other Winbond watchdogs with this driver but I
didnt bother to because I dont have access to any other chips. I have
tested it on both the SuperMicro 5013G-M and 5015M-MT, and with OpenBSD
3.6, 4.0, and 4.1.
Thanks
Jonathan Steel
=====================
File: /sys/dev/isa/wbwdgvar.h
=====================
/*
* Copyright (c) 2007 Jonathan Steel <[EMAIL PROTECTED]>
*
* 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.
*/
/* Registers */
#define WBWDG_ADDR 0x00
#define WBWDG_DATA (WBWDG_ADDR + 1)
#define WBWDG_LOGICAL_DEVICE 0x07
#define WBWDG_DEVID 0x20
#define WBWDG_DEVREV 0x21
/* Locial device 8 registers */
#define WBWDG_ENABLE 0x30
#define WBWDG_COUNT_METHOD 0xF3
#define WBWDG_MODE 0xF5
#define WBWDG_TIMEOUT 0xF6
/* Magic numbers */
#define WB_DEVID_W83627HF 0x52
#define WBWDG_ADDR_SIZE 0x02
#define WBWDG_ENTER_CONFIG_MODE 0x87
#define WBWDG_EXIT_CONFIG_MODE 0xAA
#define WBWDG_DEV_WDG 0x08
#define WBWDG_MODE_MIN (1 << 3)
#define WBWDG_MAX_TIMEOUT (0xFF * 60)
struct wbwdg_softc {
struct device sc_dev;
bus_space_tag_t sc_iot;
bus_space_handle_t sc_ioh;
/* If the timeout is in minutes or seconds */
int wdg_mode_sec;
};
=====================
File: /sys/dev/isa/wbwdg.c
=====================
/*
* Copyright (c) 2007 Jonathan Steel <[EMAIL PROTECTED]>
*
* 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.
*/
/*
* Winbond W83627HF watchdog driver.
* Datasheet:
* www.winbond-usa.com/products/winbond_products/pdfs/PCIC/W83627HF_HGb.pdf
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <machine/bus.h>
#include <sys/sensors.h>
#include <dev/isa/isareg.h>
#include <dev/isa/isavar.h>
#include <dev/isa/wbwdgvar.h>
#ifdef WBWDG_DEBUG
#define DPRINTF(x) printf x
#else
#define DPRINTF(x)
#endif
int winbond_wdg_match(struct device *, void *, void *);
void winbond_wdg_attach(struct device *, struct device *, void *);
void winbond_wdg_init(struct wbwdg_softc *sc);
int winbond_wdg_cb(void *, int);
struct cfattach wbwdg_ca = {
sizeof(struct wbwdg_softc),
winbond_wdg_match,
winbond_wdg_attach
};
struct cfdriver wbwdg_cd = {
NULL, "wbwdg", DV_DULL
};
static __inline void
winbond_conf_enable(bus_space_tag_t iot, bus_space_handle_t ioh)
{
bus_space_write_1(iot, ioh, WBWDG_ADDR, WBWDG_ENTER_CONFIG_MODE);
bus_space_write_1(iot, ioh, WBWDG_ADDR, WBWDG_ENTER_CONFIG_MODE);
}
static __inline void
winbond_conf_disable(bus_space_tag_t iot, bus_space_handle_t ioh)
{
bus_space_write_1(iot, ioh, WBWDG_ADDR, WBWDG_EXIT_CONFIG_MODE);
}
static __inline u_int8_t
winbond_conf_read(bus_space_tag_t iot, bus_space_handle_t ioh, u_int8_t index)
{
bus_space_write_1(iot, ioh, WBWDG_ADDR, index);
return (bus_space_read_1(iot, ioh, WBWDG_DATA));
}
static __inline void
winbond_conf_write(bus_space_tag_t iot, bus_space_handle_t ioh, u_int8_t index,
u_int8_t data)
{
bus_space_write_1(iot, ioh, WBWDG_ADDR, index);
bus_space_write_1(iot, ioh, WBWDG_DATA, data);
}
int
winbond_wdg_match(struct device *parent, void *match, void *aux)
{
struct isa_attach_args *ia = aux;
bus_space_tag_t iot;
bus_space_handle_t ioh;
u_int8_t device_id;
iot = ia->ia_iot;
if (bus_space_map(iot, ia->ipa_io[0].base, WBWDG_ADDR_SIZE, 0, &ioh))
return (0);
/* See if this machine has a compatible winbond chipset */
winbond_conf_enable(iot, ioh);
device_id = winbond_conf_read(iot, ioh, WBWDG_DEVID);
DPRINTF(("wbwdg_match: id 0x%02x\n", device_id));
winbond_conf_disable(iot, ioh);
bus_space_unmap(iot, ioh, WBWDG_ADDR_SIZE);
if (device_id == WB_DEVID_W83627HF) {
DPRINTF(("W83627HF Watchdog\n"));
}
else {
return (0);
}
ia->ipa_nio = 1;
ia->ipa_io[0].length = WBWDG_ADDR_SIZE;
ia->ipa_nmem = 0;
ia->ipa_nirq = 0;
ia->ipa_ndrq = 0;
return (1);
}
void
winbond_wdg_attach(struct device *parent, struct device *self, void *aux)
{
struct wbwdg_softc *sc = (void *)self;
struct isa_attach_args *ia = aux;
u_int8_t buf;
sc->sc_iot = ia->ia_iot;
if (bus_space_map(sc->sc_iot, ia->ipa_io[0].base,
WBWDG_ADDR_SIZE, 0, &sc->sc_ioh)) {
printf(": can't map I/O space\n");
return;
}
/* Enter configuration mode */
winbond_conf_enable(sc->sc_iot, sc->sc_ioh);
/* Read device id and revision */
buf = winbond_conf_read(sc->sc_iot, sc->sc_ioh, WBWDG_DEVID);
if (buf == WB_DEVID_W83627HF)
printf(": W83627HF : ");
buf = winbond_conf_read(sc->sc_iot, sc->sc_ioh, WBWDG_DEVREV);
printf("rev 0x%02x:", buf);
/* Initialize logical devices */
winbond_wdg_init(sc);
printf("\n");
/* Escape from configuration mode */
winbond_conf_disable(sc->sc_iot, sc->sc_ioh);
return;
}
void
winbond_wdg_init(struct wbwdg_softc *sc)
{
/* Select WDG logical device */
winbond_conf_write(sc->sc_iot, sc->sc_ioh,
WBWDG_LOGICAL_DEVICE, WBWDG_DEV_WDG);
/*
* Enable the timer. The default value of timeout is 0 which
* means that the timeout is disabled
*/
winbond_conf_write(sc->sc_iot, sc->sc_ioh, WBWDG_ENABLE, 1);
sc->wdg_mode_sec = 0;
wdog_register(sc, winbond_wdg_cb);
return;
}
int
winbond_wdg_cb(void *arg, int period)
{
struct wbwdg_softc *sc = arg;
int chip_period;
u_int8_t mode;
if (period < 0)
period = 0;
else if (period > WBWDG_MAX_TIMEOUT)
period = WBWDG_MAX_TIMEOUT;
/* Setup the chip to talk to the watchdog device */
winbond_conf_enable(sc->sc_iot, sc->sc_ioh);
winbond_conf_write(sc->sc_iot, sc->sc_ioh,
WBWDG_LOGICAL_DEVICE, WBWDG_DEV_WDG);
/* Tell the device to read the timeout as either seconds or minutes */
if (sc->wdg_mode_sec && period > 0xFF) {
sc->wdg_mode_sec = 0;
mode = winbond_conf_read(sc->sc_iot, sc->sc_ioh, WBWDG_MODE);
mode |= WBWDG_MODE_MIN;
winbond_conf_write(sc->sc_iot, sc->sc_ioh, WBWDG_MODE, mode);
}
else if (!sc->wdg_mode_sec && period <= 0xFF) {
sc->wdg_mode_sec = 1;
mode = winbond_conf_read(sc->sc_iot, sc->sc_ioh, WBWDG_MODE);
mode &= ~WBWDG_MODE_MIN;
winbond_conf_write(sc->sc_iot, sc->sc_ioh, WBWDG_MODE, mode);
}
chip_period = period;
/* Convert the period to minutes if necessary */
if (period > 0xFF)
chip_period = period / 60;
winbond_conf_write(sc->sc_iot, sc->sc_ioh, WBWDG_TIMEOUT, chip_period);
winbond_conf_disable(sc->sc_iot, sc->sc_ioh);
return (period);
}
====================
Additions to GENERIC
====================
- Add the following in the section for the National Semiconductor drivers.
wbwdt0 at isa? port 0x2e # Winbond W83627HF watchdog
wbwdt1 at isa? port 0x4e
====================
Additions to /sys/dev/isa/lpt_isa
====================
- Again, add the following in the section for the National Semiconductor
drivers.
# Winbond w83627hf watchdog timer
device wbwdg
attach wbwdg at isa
file dev/isa/wbwdg.c wbwdg