Author: avg
Date: Wed Jun 22 06:45:34 2011
New Revision: 223409
URL: http://svn.freebsd.org/changeset/base/223409

Log:
  MFC r222805: amdsbwd: update to support SB8xx southbridges
  
  PR:           kern/157568

Modified:
  stable/8/share/man/man4/amdsbwd.4
  stable/8/sys/dev/amdsbwd/amdsbwd.c
Directory Properties:
  stable/8/share/man/man4/   (props changed)
  stable/8/sys/   (props changed)
  stable/8/sys/amd64/include/xen/   (props changed)
  stable/8/sys/cddl/contrib/opensolaris/   (props changed)
  stable/8/sys/contrib/dev/acpica/   (props changed)
  stable/8/sys/contrib/pf/   (props changed)

Modified: stable/8/share/man/man4/amdsbwd.4
==============================================================================
--- stable/8/share/man/man4/amdsbwd.4   Wed Jun 22 06:27:32 2011        
(r223408)
+++ stable/8/share/man/man4/amdsbwd.4   Wed Jun 22 06:45:34 2011        
(r223409)
@@ -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: stable/8/sys/dev/amdsbwd/amdsbwd.c
==============================================================================
--- stable/8/sys/dev/amdsbwd/amdsbwd.c  Wed Jun 22 06:27:32 2011        
(r223408)
+++ stable/8/sys/dev/amdsbwd/amdsbwd.c  Wed Jun 22 06:45:34 2011        
(r223409)
@@ -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);
 
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to