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

Reply via email to