svn commit: r222805 - in head: share/man/man4 sys/dev/amdsbwd

Andriy Gapon avg at FreeBSD.org
Tue Jun 7 06:18:02 UTC 2011


Author: avg
Date: Tue Jun  7 06:18:02 2011
New Revision: 222805
URL: http://svn.freebsd.org/changeset/base/222805

Log:
  amdsbwd: update to support SB8xx southbridges
  
  Many thanks to Tino <tinotom at gmail.com> for drawing my attention to
  this, for doing a lot of testing and providing great feedback.
  Many thanks to AMD for continuing to release public specifications for
  their chipsets.
  
  PR:		kern/157568
  Tested by:	Tino <tinotom at gmail.com>
  MFC after:	1 week

Modified:
  head/share/man/man4/amdsbwd.4
  head/sys/dev/amdsbwd/amdsbwd.c

Modified: head/share/man/man4/amdsbwd.4
==============================================================================
--- head/share/man/man4/amdsbwd.4	Tue Jun  7 05:04:37 2011	(r222804)
+++ head/share/man/man4/amdsbwd.4	Tue Jun  7 06:18:02 2011	(r222805)
@@ -25,12 +25,12 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd November 30, 2009
+.Dd June 7, 2011
 .Dt AMDSBWD 4
 .Os
 .Sh NAME
 .Nm amdsbwd
-.Nd device driver for the AMD SB600/SB700/SB710/SB750 watchdog timer
+.Nd device driver for the AMD SB600/SB7xx/SB8xx watchdog timers
 .Sh SYNOPSIS
 To compile this driver into the kernel,
 place the following line in your
@@ -51,7 +51,7 @@ The
 driver provides
 .Xr watchdog 4
 support for the watchdog timers present on
-AMD SB600 and SB7xx south bridge chips.
+AMD SB600, SB7xx and SB8xx southbridges.
 .Sh SEE ALSO
 .Xr watchdog 4 ,
 .Xr watchdog 8 ,

Modified: head/sys/dev/amdsbwd/amdsbwd.c
==============================================================================
--- head/sys/dev/amdsbwd/amdsbwd.c	Tue Jun  7 05:04:37 2011	(r222804)
+++ head/sys/dev/amdsbwd/amdsbwd.c	Tue Jun  7 06:18:02 2011	(r222805)
@@ -25,8 +25,8 @@
  */
 
 /*
- * This is a driver for watchdog timer present in AMD SB600/SB7xx
- * south bridges and other watchdog timers advertised via WDRT ACPI table.
+ * This is a driver for watchdog timer present in AMD SB600/SB7xx/SB8xx
+ * southbridges.
  * Please see the following specifications for the descriptions of the
  * registers and flags:
  * - AMD SB600 Register Reference Guide, Public Version,  Rev. 3.03 (SB600 RRG)
@@ -35,11 +35,13 @@
  *   http://developer.amd.com/assets/43009_sb7xx_rrg_pub_1.00.pdf
  * - AMD SB700/710/750 Register Programming Requirements (RPR)
  *   http://developer.amd.com/assets/42413_sb7xx_rpr_pub_1.00.pdf
+ * - AMD SB800-Series Southbridges Register Reference Guide (RRG)
+ *   http://support.amd.com/us/Embedded_TechDocs/45482.pdf
  * Please see the following for Watchdog Resource Table specification:
  * - Watchdog Timer Hardware Requirements for Windows Server 2003 (WDRT)
  *   http://www.microsoft.com/whdc/system/sysinternals/watchdog.mspx
- * AMD SB600/SB7xx watchdog hardware seems to conform to the above,
- * but my system doesn't provide the table.
+ * AMD SB600/SB7xx/SB8xx watchdog hardware seems to conform to the above
+ * specifications, but the table hasn't been spotted in the wild yet.
  */
 
 #include <sys/cdefs.h>
@@ -59,15 +61,15 @@ __FBSDID("$FreeBSD$");
 #include <dev/pci/pcivar.h>
 #include <isa/isavar.h>
 
-/* RRG 2.3.3.1.1, page 161. */
+/* SB7xx RRG 2.3.3.1.1. */
 #define	AMDSB_PMIO_INDEX		0xcd6
 #define	AMDSB_PMIO_DATA			(PMIO_INDEX + 1)
 #define	AMDSB_PMIO_WIDTH		2
-/* RRG 2.3.3.2, page 181. */
+/* SB7xx RRG 2.3.3.2. */
 #define	AMDSB_PM_RESET_STATUS0		0x44
 #define	AMDSB_PM_RESET_STATUS1		0x45
 #define		AMDSB_WD_RST_STS	0x02
-/* RRG 2.3.3.2, page 188; RPR 2.36, page 30. */
+/* SB7xx RRG 2.3.3.2, RPR 2.36. */
 #define	AMDSB_PM_WDT_CTRL		0x69
 #define		AMDSB_WDT_DISABLE	0x01
 #define		AMDSB_WDT_RES_MASK	(0x02 | 0x04)
@@ -77,7 +79,18 @@ __FBSDID("$FreeBSD$");
 #define		AMDSB_WDT_RES_1S	0x06
 #define	AMDSB_PM_WDT_BASE_LSB		0x6c
 #define	AMDSB_PM_WDT_BASE_MSB		0x6f
-/* RRG 2.3.4, page 223, WDRT. */
+/* SB8xx RRG 2.3.3. */
+#define	AMDSB8_PM_WDT_EN		0x48
+#define		AMDSB8_WDT_DEC_EN	0x01
+#define		AMDSB8_WDT_DISABLE	0x02
+#define	AMDSB8_PM_WDT_CTRL		0x4c
+#define		AMDSB8_WDT_32KHZ	0x00
+#define		AMDSB8_WDT_1HZ		0x03
+#define		AMDSB8_WDT_RES_MASK	0x03
+#define	AMDSB8_PM_RESET_STATUS0		0xC0
+#define	AMDSB8_PM_RESET_STATUS1		0xC1
+#define		AMDSB8_WD_RST_STS	0x20
+/* SB7xx RRG 2.3.4, WDRT. */
 #define	AMDSB_WD_CTRL			0x00
 #define		AMDSB_WD_RUN		0x01
 #define		AMDSB_WD_FIRED		0x02
@@ -90,8 +103,9 @@ __FBSDID("$FreeBSD$");
 #define	AMDSB_WDIO_REG_WIDTH		4
 /* WDRT */
 #define	MAXCOUNT_MIN_VALUE		511
-/* RRG 2.3.1.1, page 122; SB600 RRG 2.3.1.1, page 97. */
-#define	AMDSB7xx_SMBUS_DEVID		0x43851002
+/* SB7xx RRG 2.3.1.1, SB600 RRG 2.3.1.1, SB8xx RRG 2.3.1.  */
+#define	AMDSB_SMBUS_DEVID		0x43851002
+#define	AMDSB8_SMBUS_REVID		0x40
 
 #define	amdsbwd_verbose_printf(dev, ...)	\
 	do {						\
@@ -265,7 +279,7 @@ amdsbwd_identify(driver_t *driver, devic
 	smb_dev = pci_find_bsf(0, 20, 0);
 	if (smb_dev == NULL)
 		return;
-	if (pci_get_devid(smb_dev) != AMDSB7xx_SMBUS_DEVID)
+	if (pci_get_devid(smb_dev) != AMDSB_SMBUS_DEVID)
 		return;
 
 	child = BUS_ADD_CHILD(parent, ISA_ORDER_SPECULATIVE, "amdsbwd", -1);
@@ -273,15 +287,102 @@ amdsbwd_identify(driver_t *driver, devic
 		device_printf(parent, "add amdsbwd child failed\n");
 }
 
+
+static void
+amdsbwd_probe_sb7xx(device_t dev, struct resource *pmres, uint32_t *addr)
+{
+	uint32_t	val;
+	int		i;
+
+	/* Report cause of previous reset for user's convenience. */
+	val = pmio_read(pmres, AMDSB_PM_RESET_STATUS0);
+	if (val != 0)
+		amdsbwd_verbose_printf(dev, "ResetStatus0 = %#04x\n", val);
+	val = pmio_read(pmres, AMDSB_PM_RESET_STATUS1);
+	if (val != 0)
+		amdsbwd_verbose_printf(dev, "ResetStatus1 = %#04x\n", val);
+	if ((val & AMDSB_WD_RST_STS) != 0)
+		device_printf(dev, "Previous Reset was caused by Watchdog\n");
+
+	/* Find base address of memory mapped WDT registers. */
+	for (*addr = 0, i = 0; i < 4; i++) {
+		*addr <<= 8;
+		*addr |= pmio_read(pmres, AMDSB_PM_WDT_BASE_MSB - i);
+	}
+	/* Set watchdog timer tick to 1s. */
+	val = pmio_read(pmres, AMDSB_PM_WDT_CTRL);
+	val &= ~AMDSB_WDT_RES_MASK;
+	val |= AMDSB_WDT_RES_10MS;
+	pmio_write(pmres, AMDSB_PM_WDT_CTRL, val);
+
+	/* Enable watchdog device (in stopped state). */
+	val = pmio_read(pmres, AMDSB_PM_WDT_CTRL);
+	val &= ~AMDSB_WDT_DISABLE;
+	pmio_write(pmres, AMDSB_PM_WDT_CTRL, val);
+
+	/*
+	 * XXX TODO: Ensure that watchdog decode is enabled
+	 * (register 0x41, bit 3).
+	 */
+	device_set_desc(dev, "AMD SB600/SB7xx Watchdog Timer");
+}
+
+static void
+amdsbwd_probe_sb8xx(device_t dev, struct resource *pmres, uint32_t *addr)
+{
+	uint32_t	val;
+	int		i;
+
+	/* Report cause of previous reset for user's convenience. */
+	val = pmio_read(pmres, AMDSB8_PM_RESET_STATUS0);
+	if (val != 0)
+		amdsbwd_verbose_printf(dev, "ResetStatus0 = %#04x\n", val);
+	val = pmio_read(pmres, AMDSB8_PM_RESET_STATUS1);
+	if (val != 0)
+		amdsbwd_verbose_printf(dev, "ResetStatus1 = %#04x\n", val);
+	if ((val & AMDSB8_WD_RST_STS) != 0)
+		device_printf(dev, "Previous Reset was caused by Watchdog\n");
+
+	/* Find base address of memory mapped WDT registers. */
+	for (*addr = 0, i = 0; i < 4; i++) {
+		*addr <<= 8;
+		*addr |= pmio_read(pmres, AMDSB8_PM_WDT_EN + 3 - i);
+	}
+	*addr &= ~0x07u;
+
+	/* Set watchdog timer tick to 1s. */
+	val = pmio_read(pmres, AMDSB8_PM_WDT_CTRL);
+	val &= ~AMDSB8_WDT_RES_MASK;
+	val |= AMDSB8_WDT_1HZ;
+	pmio_write(pmres, AMDSB8_PM_WDT_CTRL, val);
+#ifdef AMDSBWD_DEBUG
+	val = pmio_read(pmres, AMDSB8_PM_WDT_CTRL);
+	amdsbwd_verbose_printf(dev, "AMDSB8_PM_WDT_CTRL value = %#02x\n", val);
+#endif
+
+	/*
+	 * Enable watchdog device (in stopped state)
+	 * and decoding of its address.
+	 */
+	val = pmio_read(pmres, AMDSB8_PM_WDT_EN);
+	val &= ~AMDSB8_WDT_DISABLE;
+	val |= AMDSB8_WDT_DEC_EN;
+	pmio_write(pmres, AMDSB8_PM_WDT_EN, val);
+#ifdef AMDSBWD_DEBUG
+	val = pmio_read(pmres, AMDSB8_PM_WDT_EN);
+	device_printf(dev, "AMDSB8_PM_WDT_EN value = %#02x\n", val);
+#endif
+	device_set_desc(dev, "AMD SB8xx Watchdog Timer");
+}
+
 static int
 amdsbwd_probe(device_t dev)
 {
 	struct resource		*res;
+	device_t		smb_dev;
 	uint32_t		addr;
-	uint32_t		val;
 	int			rid;
 	int			rc;
-	int			i;
 
 	/* Do not claim some ISA PnP device by accident. */
 	if (isa_get_logicalid(dev) != 0)
@@ -301,21 +402,16 @@ amdsbwd_probe(device_t dev)
 		return (ENXIO);
 	}
 
-	/* Report cause of previous reset for user's convenience. */
-	val = pmio_read(res, AMDSB_PM_RESET_STATUS0);
-	if (val != 0)
-		amdsbwd_verbose_printf(dev, "ResetStatus0 = %#04x\n", val);
-	val = pmio_read(res, AMDSB_PM_RESET_STATUS1);
-	if (val != 0)
-		amdsbwd_verbose_printf(dev, "ResetStatus1 = %#04x\n", val);
-	if ((val & AMDSB_WD_RST_STS) != 0)
-		device_printf(dev, "Previous Reset was caused by Watchdog\n");
+	smb_dev = pci_find_bsf(0, 20, 0);
+	KASSERT(smb_dev != NULL, ("can't find SMBus PCI device\n"));
+	if (pci_get_revid(smb_dev) < AMDSB8_SMBUS_REVID)
+		amdsbwd_probe_sb7xx(dev, res, &addr);
+	else
+		amdsbwd_probe_sb8xx(dev, res, &addr);
+
+	bus_release_resource(dev, SYS_RES_IOPORT, rid, res);
+	bus_delete_resource(dev, SYS_RES_IOPORT, rid);
 
-	/* Find base address of memory mapped WDT registers. */
-	for (addr = 0, i = 0; i < 4; i++) {
-		addr <<= 8;
-		addr |= pmio_read(res, AMDSB_PM_WDT_BASE_MSB - i);
-	}
 	amdsbwd_verbose_printf(dev, "memory base address = %#010x\n", addr);
 	rc = bus_set_resource(dev, SYS_RES_MEMORY, 0, addr + AMDSB_WD_CTRL,
 	    AMDSB_WDIO_REG_WIDTH);
@@ -330,36 +426,25 @@ amdsbwd_probe(device_t dev)
 		return (ENXIO);
 	}
 
-	/* Set watchdog timer tick to 10ms. */
-	val = pmio_read(res, AMDSB_PM_WDT_CTRL);
-	val &= ~AMDSB_WDT_RES_MASK;
-	val |= AMDSB_WDT_RES_10MS;
-	pmio_write(res, AMDSB_PM_WDT_CTRL, val);
-
-	/* Enable watchdog device (in stopped state). */
-	val = pmio_read(res, AMDSB_PM_WDT_CTRL);
-	val &= ~AMDSB_WDT_DISABLE;
-	pmio_write(res, AMDSB_PM_WDT_CTRL, val);
-
-	/*
-	 * XXX TODO: Ensure that watchdog decode is enabled
-	 * (register 0x41, bit 3).
-	 */
-	bus_release_resource(dev, SYS_RES_IOPORT, rid, res);
-	bus_delete_resource(dev, SYS_RES_IOPORT, rid);
-
-	device_set_desc(dev, "AMD SB600/SB7xx Watchdog Timer");
 	return (0);
 }
 
 static int
 amdsbwd_attach_sb(device_t dev, struct amdsbwd_softc *sc)
 {
+	device_t	smb_dev;
+
 	sc->max_ticks = UINT16_MAX;
-	sc->ms_per_tick = 10;
 	sc->rid_ctrl = 0;
 	sc->rid_count = 1;
 
+	smb_dev = pci_find_bsf(0, 20, 0);
+	KASSERT(smb_dev != NULL, ("can't find SMBus PCI device\n"));
+	if (pci_get_revid(smb_dev) < AMDSB8_SMBUS_REVID)
+		sc->ms_per_tick = 10;
+	else
+		sc->ms_per_tick = 1000;
+
 	sc->res_ctrl = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
 	    &sc->rid_ctrl, RF_ACTIVE);
 	if (sc->res_ctrl == NULL) {
@@ -388,6 +473,11 @@ amdsbwd_attach(device_t dev)
 	if (rc != 0)
 		goto fail;
 
+#ifdef AMDSBWD_DEBUG
+	device_printf(dev, "wd ctrl = %#04x\n", wdctrl_read(sc));
+	device_printf(dev, "wd count = %#04x\n", wdcount_read(sc));
+#endif
+
 	/* Setup initial state of Watchdog Control. */
 	wdctrl_write(sc, AMDSB_WD_FIRED);
 


More information about the svn-src-all mailing list