The diff below adds support for the watchdog as found in the embedded
AMD FCH (fusion controller hub) as found on APU2.

Index: sys/dev/pci/piixpm.c
===================================================================
RCS file: /cvs/src/sys/dev/pci/piixpm.c,v
retrieving revision 1.42
diff -u -p -r1.42 piixpm.c
--- sys/dev/pci/piixpm.c        21 Jan 2020 06:37:24 -0000      1.42
+++ sys/dev/pci/piixpm.c        8 Feb 2020 04:44:42 -0000
@@ -54,8 +54,10 @@ struct piixpm_softc {
        struct device           sc_dev;
 
        bus_space_tag_t         sc_iot;
+       bus_space_tag_t         sc_memt;
        bus_space_handle_t      sc_ioh;
        bus_space_handle_t      sc_sb800_ioh;
+       bus_space_handle_t      sc_wdt_mh;
        void *                  sc_ih;
        int                     sc_poll;
        int                     sc_is_sb800;
@@ -83,6 +85,8 @@ int   piixpm_i2c_exec(void *, i2c_op_t, i2
 
 int    piixpm_intr(void *);
 
+int    piixpm_wdt_cb(void *arg, int period);
+
 struct cfattach piixpm_ca = {
        sizeof(struct piixpm_softc),
        piixpm_match,
@@ -127,7 +131,7 @@ piixpm_attach(struct device *parent, str
        struct piixpm_softc *sc = (struct piixpm_softc *)self;
        struct pci_attach_args *pa = aux;
        bus_space_handle_t ioh;
-       u_int16_t val, smb0en;
+       u_int16_t val, smb0en, wdten = 0;
        bus_addr_t base;
        pcireg_t conf;
        pci_intr_handle_t ih;
@@ -136,6 +140,7 @@ piixpm_attach(struct device *parent, str
        int numbusses, i;
 
        sc->sc_iot = pa->pa_iot;
+       sc->sc_memt = pa->pa_memt;
        numbusses = 1;
 
        if ((PCI_VENDOR(pa->pa_id) == PCI_VENDOR_AMD &&
@@ -160,7 +165,7 @@ piixpm_attach(struct device *parent, str
 
                /*
                 * AMD Bolton matches PCI_PRODUCT_AMD_HUDSON2_SMB but
-                * uses old register layout. Therefor check PCI_REVISION.
+                * uses old register layout. Therefore check PCI_REVISION.
                 */
                if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_AMD &&
                    ((PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_AMD_HUDSON2_SMB &&
@@ -170,6 +175,7 @@ piixpm_attach(struct device *parent, str
                            AMDFCH41_PM_DECODE_EN);
                        val = bus_space_read_1(sc->sc_iot, ioh, 1);
                        smb0en = val & AMDFCH41_SMBUS_EN;
+                       wdten = val & AMDFCH41_WDT_EN;
 
                        bus_space_write_1(sc->sc_iot, ioh, 0,
                            AMDFCH41_PM_DECODE_EN + 1);
@@ -282,7 +288,59 @@ piixpm_attach(struct device *parent, str
                config_found(self, &iba, iicbus_print);
        }
 
+       /* Register watchdog */
+       if (wdten && bus_space_map(sc->sc_memt, AMDFCH41_WDTREG_BASE,
+           AMDFCH41_WDTREG_SIZE, 0, &sc->sc_wdt_mh) == 0) {
+               val = bus_space_read_1(sc->sc_memt, sc->sc_wdt_mh,
+                   AMDFCH41_WDTREG_CTL);
+               if (val & AMDFCH41_WDTREG_CTL_FIRED) {
+                       printf("%s watchdog caused previous restart\n",
+                           sc->sc_dev.dv_xname);
+                       bus_space_write_1(sc->sc_memt, sc->sc_wdt_mh,
+                           AMDFCH41_WDTREG_CTL,
+                           val | AMDFCH41_WDTREG_CTL_FIRED);
+               }
+
+               if (val & AMDFCH41_WDTREG_CTL_DISABLED)
+                       printf("%s watchdog disabled\n", sc->sc_dev.dv_xname);
+               else {
+                       printf("%s watchdog found\n", sc->sc_dev.dv_xname);
+
+                       /* Set 1 second counter period */
+                       bus_space_write_1(sc->sc_iot, sc->sc_sb800_ioh, 0,
+                           AMDFCH41_PM_DECODE_EN + 3);
+                       val = bus_space_read_1(sc->sc_iot, sc->sc_sb800_ioh, 1);
+                       val = (val & ~AMDFCH41_WDT_MASK) | AMDFCH41_WDT_1S;
+                       bus_space_write_1(sc->sc_iot, sc->sc_sb800_ioh, 1, val);
+
+                       wdog_register(piixpm_wdt_cb, sc);
+               }
+       }
+
        return;
+}
+
+int
+piixpm_wdt_cb(void *arg, int period)
+{
+       struct piixpm_softc *sc = (struct piixpm_softc *)arg;
+       u_int16_t val;
+
+       val = bus_space_read_1(sc->sc_memt, sc->sc_wdt_mh, AMDFCH41_WDTREG_CTL);
+
+       if (period > 0xffff)
+               period = 0xffff;
+       if (period > 0) {
+               bus_space_write_2(sc->sc_memt, sc->sc_wdt_mh,
+                   AMDFCH41_WDTREG_COUNT, period);
+               val |= AMDFCH41_WDTREG_CTL_RUN | AMDFCH41_WDTREG_CTL_TRIGGER;
+       }
+       else
+               val &= ~AMDFCH41_WDTREG_CTL_RUN;
+
+       bus_space_write_1(sc->sc_memt, sc->sc_wdt_mh, AMDFCH41_WDTREG_CTL, val);
+
+       return period;
 }
 
 int
Index: sys/dev/pci/piixreg.h
===================================================================
RCS file: /cvs/src/sys/dev/pci/piixreg.h,v
retrieving revision 1.6
diff -u -p -r1.6 piixreg.h
--- sys/dev/pci/piixreg.h       21 Jan 2020 06:37:24 -0000      1.6
+++ sys/dev/pci/piixreg.h       8 Feb 2020 04:44:42 -0000
@@ -87,5 +87,19 @@
 #define AMDFCH41_PM_DECODE_EN  0x00    /* 16-bit register */
 #define AMDFCH41_PM_PORT_INDEX 0x02
 #define AMDFCH41_SMBUS_EN      0x10
+#define AMDFCH41_WDT_EN                0x80
+#define AMDFCH41_WDT_MASK      0x0f
+#define AMDFCH41_WDT_32US      0x00
+#define AMDFCH41_WDT_10MS      0x01
+#define AMDFCH41_WDT_100MS     0x02
+#define AMDFCH41_WDT_1S                0x03
+#define AMDFCH41_WDTREG_BASE   0xfeb00000
+#define AMDFCH41_WDTREG_SIZE   0x10
+#define AMDFCH41_WDTREG_CTL    0x00
+#define AMDFCH41_WDTREG_CTL_RUN                0x01
+#define AMDFCH41_WDTREG_CTL_FIRED      0x02
+#define AMDFCH41_WDTREG_CTL_DISABLED   0x08
+#define AMDFCH41_WDTREG_CTL_TRIGGER    0x80
+#define AMDFCH41_WDTREG_COUNT  0x04
 
 #endif /* !_DEV_PCI_PIIXREG_H_ */

Reply via email to