Subject: port-i386/31514: PATCH: Driver for hardware watchdog on AMD Geode SC1100
To: None <port-i386-maintainer@netbsd.org, gnats-admin@netbsd.org,>
From: None <john32979@gmail.com>
List: netbsd-bugs
Date: 10/08/2005 19:47:00
>Number: 31514
>Category: port-i386
>Synopsis: PATCH: Driver for hardware watchdog on AMD Geode SC1100
>Confidential: no
>Severity: non-critical
>Priority: low
>Responsible: port-i386-maintainer
>State: open
>Class: change-request
>Submitter-Id: net
>Arrival-Date: Sat Oct 08 19:47:00 +0000 2005
>Originator: John Yau
>Release:
>Organization:
>Environment:
>Description:
It looks like David Young beat me to it by a couple weeks. I'm submitting the file/patch anyway just in case anyone finds it useful.
There are two things:
geode_wdog.c (submitted in it's entirety)
files.i386 (patch)
>How-To-Repeat:
>Fix:
Index: files.i386
===================================================================
RCS file: /cvsroot/src/sys/arch/i386/conf/files.i386,v
retrieving revision 1.254
diff -u -r1.254 files.i386
--- files.i386 25 Mar 2004 23:32:10 -0000 1.254
+++ files.i386 8 Oct 2005 19:39:31 -0000
@@ -177,6 +177,11 @@
attach elansc at pci
file arch/i386/pci/elan520.c elansc
+# AMD Geode Watchdog
+device geode_wdog: sysmon_wdog
+attach geode_wdog at pci
+file arch/i386/pci/geode_wdog.c geode_wdog
+
# PCI-EISA bridges
device pceb: eisabus, isabus
attach pceb at pci
-------------------------------------------------------------------
geode_wdog.c (to be placed in /sys/arch/i386/pci)
-------------------------------------------------------------------
/*-
* A watch dog implementation for the AMD SC1100 "Geode" processor
*
* Snippets of code were taken from and information was gleaned from
* Poul-Henning Kamp's geode.c for FreeBSD.
*
* Copyright (c) 2005 John Yau
* Copyright (c) 2003-2004 Poul-Henning Kamp
* All rights reserved.
*
* 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.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
*/
#include <sys/cdefs.h>
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/wdog.h>
#include <machine/bus.h>
#include <dev/pci/pcivar.h>
#include <dev/pci/pcidevs.h>
#include <dev/sysmon/sysmonvar.h>
#define GEODE_WDTIMEOUT 0x00
#define GEODE_WDCONFIG 0x02
#define GEODE_WDSTATUS 0x04
#define GEODE_VENDOR_ID 0x100b
#define GEODE_DEVICE_ID 0x0515
static unsigned cba;
static unsigned geode_counter;
struct geode_wdog_softc {
struct device sc_dev;
struct sysmon_wdog sc_smw;
int sc_wdog_armed;
int sc_wdog_period;
};
static int
geode_wdog_tickle(struct sysmon_wdog *smw)
{
/* Convert seconds to ticks */
u_int16_t scaler = 0, reg;
u_int32_t ticks;
if (smw->smw_period == 0) {
reg = inw(cba + GEODE_WDCONFIG) & 0xff00;
/* Turn on the watch do, set the scaler and set the action to
* reset when the watchdog goes off
*/
outw(cba + GEODE_WDCONFIG, 0xf0 & reg);
outw(cba + GEODE_WDTIMEOUT, 0);
return (0);
}
/* The timer of the Geode runs at 32 kHz */
ticks = smw->smw_period * 32000;
/* We figure out the appropriate scaler and ticks */
while (scaler < 13 && ticks > 0xffff) {
ticks >>= 1;
scaler++;
}
if (scaler < 13 ) {
reg = inw(cba + GEODE_WDCONFIG) & 0xff00;
/* Turn on the watch dog, set the scaler and set the action to
* reset when the watchdog goes off
*/
if (ticks == 0)
{
scaler--;
ticks = 0xffff;
}
outw(cba + GEODE_WDCONFIG, scaler | 0xf0 | reg);
reg = (u_int16_t) ticks;
outw(cba + GEODE_WDTIMEOUT, reg);
} else {
reg = inw(cba + GEODE_WDCONFIG) & 0xff00;
/* Turn on the watch dog, set the scaler and set the action to
* reset when the watchdog goes off
*/
outw(cba + GEODE_WDCONFIG, 0xf0 & reg);
outw(cba + GEODE_WDTIMEOUT, 0);
}
return (0);
}
static int
geode_wdog_setmode(struct sysmon_wdog *smw)
{
struct geode_wdog_softc *sc = smw->smw_cookie;
u_int reg;
if ((smw->smw_mode & WDOG_MODE_MASK) == WDOG_MODE_DISARMED) {
if (sc->sc_wdog_armed) {
sc->sc_wdog_armed = 0;
reg = inw(cba + GEODE_WDCONFIG) & 0xff00;
/* Turn off the watch dog */
outw(cba + GEODE_WDCONFIG, 0 | reg);
outw(cba + GEODE_WDTIMEOUT, 0);
}
} else {
if (smw->smw_period == WDOG_PERIOD_DEFAULT) {
smw->smw_period = 30;
} else {
smw->smw_period = sc->sc_wdog_period;
}
sc->sc_wdog_armed = 1;
/* Watchdog is armed by tickling it. */
geode_wdog_tickle(smw);
}
return (0);
}
static int
geode_wdog_match(struct device *parent, struct cfdata *match, void *aux)
{
struct pci_attach_args *pa = aux;
if (PCI_VENDOR(pa->pa_id) == GEODE_VENDOR_ID &&
PCI_PRODUCT(pa->pa_id) == GEODE_DEVICE_ID) {
return (10);
}
return (0);
}
static void
geode_wdog_attach(struct device *parent, struct device *self, void *aux)
{
struct geode_wdog_softc *sc = (void *) self;
struct pci_attach_args *pa = aux;
if (PCI_VENDOR(pa->pa_id) == GEODE_VENDOR_ID &&
PCI_PRODUCT(pa->pa_id) == GEODE_DEVICE_ID) {
if (geode_counter == 0) {
/*
* The address of the CBA is written to this register
* by the bios, see p161 in data sheet.
*/
cba = pci_conf_read(pa->pa_pc, pa->pa_tag, 0x64);
printf("Geode CBA@ 0x%x\n", cba);
geode_counter = cba + 0x08;
outl(cba + 0x0d, 2);
printf("Geode rev: %02x %02x\n",
inb(cba + 0x3c), inb(cba + 0x3d));
sc->sc_smw.smw_name = sc->sc_dev.dv_xname;
sc->sc_smw.smw_cookie = sc;
sc->sc_smw.smw_setmode = geode_wdog_setmode;
sc->sc_smw.smw_tickle = geode_wdog_tickle;
sc->sc_smw.smw_period = sc->sc_wdog_period;
}
}
printf("Geode %s: Watchdog timer\n", sc->sc_dev.dv_xname);
printf("Geode %s: %d second period\n", sc->sc_dev.dv_xname,
sc->sc_wdog_period);
if (sysmon_wdog_register(&sc->sc_smw) != 0) {
printf("Geode %s: unable to register with sysmon\n",
sc->sc_dev.dv_xname);
}
}
CFATTACH_DECL(geode_wdog, sizeof(struct geode_wdog_softc),
geode_wdog_match, geode_wdog_attach, NULL, NULL);