Author: ian
Date: Sat Mar 24 21:27:10 2018
New Revision: 331498
URL: https://svnweb.freebsd.org/changeset/base/331498

Log:
  MFC r328345, r328349, r328405, r328407, r328442
  
  r328345:
  Reformat indentation to match other imx5/6 register definition headers, and
  tweak some comments.  No functional changes.
  
  r328349:
  Make the trivial imx_soc_family() function an inline in imx_machdep.h.
  
  The imx_machdep.c file is on the fast path to non-existance and this would
  be the only thing left in it after some watchdog changes are completed.
  
  r328405:
  Minor cleanups... Move DRIVER_MODULE() and other boilerplate stuff to the
  bottom of the file, where it is in most imx5/6 drivers.  Switch from an RD2
  macro using bus_space_read_2() to an inline function using bus_read_2();
  likewise for WR2.  Use RESOURCE_SPEC_END to end the resource_spec list.
  
  Net effect should be no functional changes.
  
  r328407:
  Fix return style in RD2.  Remove bogus return value from a void function
  in WR2 (I have no idea why that didn't result in a compile error).
  
  r328442:
  Add support to the imx5/6 watchdog for the external reset signal.  Also, if
  the "power down" watchdog used by the ROM boot code is still active when the
  regular watchdog is activated, turn off the power-down watchdog.
  
  This adds support for the "fsl,ext-reset-output" FDT property.  When
  present, that property indicates that a chip reset is accomplished by
  asserting the WDOG1_B external signal, which is supposed to trigger some
  external component such as a PMIC to ready the hardware for reset (for
  example, adjusting voltages from idle to full-power levels), and assert the
  POR signal to SoC when ready.  To guard against misconfiguation leading to a
  non-rebootable system, the external reset signal is backstopped by code
  that asserts a normal internal chip reset if nothing responds to the
  external reset signal within one second.

Modified:
  stable/11/sys/arm/freescale/imx/imx_machdep.c
  stable/11/sys/arm/freescale/imx/imx_machdep.h
  stable/11/sys/arm/freescale/imx/imx_wdog.c
  stable/11/sys/arm/freescale/imx/imx_wdogreg.h
Directory Properties:
  stable/11/   (props changed)

Modified: stable/11/sys/arm/freescale/imx/imx_machdep.c
==============================================================================
--- stable/11/sys/arm/freescale/imx/imx_machdep.c       Sat Mar 24 21:22:28 
2018        (r331497)
+++ stable/11/sys/arm/freescale/imx/imx_machdep.c       Sat Mar 24 21:27:10 
2018        (r331498)
@@ -41,6 +41,7 @@ __FBSDID("$FreeBSD$");
 
 #include <machine/armreg.h>
 #include <machine/bus.h>
+#include <machine/cpu.h>
 #include <machine/machdep.h>
 
 #include <arm/freescale/imx/imx_machdep.h>
@@ -65,27 +66,51 @@ SYSCTL_STRING(_hw_imx, OID_AUTO, last_reset_reason, CT
 void
 imx_wdog_cpu_reset(vm_offset_t wdcr_physaddr)
 {
-       volatile uint16_t * pcr;
+       volatile uint16_t cr, *pcr;
 
+       if ((pcr = devmap_ptov(wdcr_physaddr, sizeof(*pcr))) == NULL) {
+               printf("imx_wdog_cpu_reset(): "
+                   "cannot find control register... locking up now.");
+               for (;;)
+                       cpu_spinwait();
+       }
+       cr = *pcr;
+
        /*
-        * Trigger an immediate reset by clearing the SRS bit in the watchdog
-        * control register.  The reset happens on the next cycle of the wdog
-        * 32KHz clock, so hang out in a spin loop until the reset takes effect.
+        * If the watchdog hardware has been set up to trigger an external reset
+        * signal on watchdog timeout, then we do software-requested rebooting
+        * the same way, by asserting the external reset signal.
         *
+        * Asserting external reset is supposed to result in some external
+        * component asserting the POR pin on the SoC, possibly after adjusting
+        * and stabilizing system voltages, or taking other system-wide reset
+        * actions.  Just in case there is some kind of misconfiguration, we
+        * hang out and do nothing for a full second, then continue on into
+        * the code to assert a software reset as well.
+        */
+       if (cr & WDOG_CR_WDT) {
+               cr &= ~WDOG_CR_WDA; /* Assert active-low ext reset bit. */
+               *pcr = cr;
+               DELAY(1000000);
+               printf("imx_wdog_cpu_reset(): "
+                   "External reset failed, trying internal cpu-reset\n");
+               DELAY(10000); /* Time for printf to appear */
+       }
+
+       /*
         * Imx6 erratum ERR004346 says the SRS bit has to be cleared twice
         * within the same cycle of the 32khz clock to reliably trigger the
         * reset.  Writing it 3 times in a row ensures at least 2 of the writes
         * happen in the same 32k clock cycle.
         */
-       if ((pcr = devmap_ptov(wdcr_physaddr, sizeof(*pcr))) == NULL) {
-               printf("cpu_reset() can't find its control register... locking 
up now.");
-       } else {
-               *pcr &= ~WDOG_CR_SRS;
-               *pcr &= ~WDOG_CR_SRS;
-               *pcr &= ~WDOG_CR_SRS;
-       }
+       cr &= ~WDOG_CR_SRS; /* Assert active-low software reset bit. */
+       *pcr = cr;
+       *pcr = cr;
+       *pcr = cr;
+
+       /* Reset happens on the next tick of the 32khz clock, wait for it. */
        for (;;)
-               continue;
+               cpu_spinwait();
 }
 
 void
@@ -104,11 +129,4 @@ imx_wdog_init_last_reset(vm_offset_t wdsr_phys)
                sysctl___hw_imx_last_reset_reason.oid_arg1 = "PowerOnReset";
        }
 }
-
-u_int
-imx_soc_family(void)
-{
-       return (imx_soc_type() >> IMXSOC_FAMSHIFT);
-}
-
 

Modified: stable/11/sys/arm/freescale/imx/imx_machdep.h
==============================================================================
--- stable/11/sys/arm/freescale/imx/imx_machdep.h       Sat Mar 24 21:22:28 
2018        (r331497)
+++ stable/11/sys/arm/freescale/imx/imx_machdep.h       Sat Mar 24 21:27:10 
2018        (r331498)
@@ -61,7 +61,12 @@ void imx_wdog_init_last_reset(vm_offset_t _wdsr_phys);
 #define        IMXSOC_FAMSHIFT 28
 
 u_int imx_soc_type(void);
-u_int imx_soc_family(void);
+
+static inline u_int
+imx_soc_family(void)
+{
+       return (imx_soc_type() >> IMXSOC_FAMSHIFT);
+}
 
 #endif
 

Modified: stable/11/sys/arm/freescale/imx/imx_wdog.c
==============================================================================
--- stable/11/sys/arm/freescale/imx/imx_wdog.c  Sat Mar 24 21:22:28 2018        
(r331497)
+++ stable/11/sys/arm/freescale/imx/imx_wdog.c  Sat Mar 24 21:27:10 2018        
(r331498)
@@ -50,23 +50,27 @@ __FBSDID("$FreeBSD$");
 #include <dev/ofw/ofw_bus.h>
 #include <dev/ofw/ofw_bus_subr.h>
 
+#include <arm/freescale/imx/imx_machdep.h>
 #include <arm/freescale/imx/imx_wdogreg.h>
 
 struct imx_wdog_softc {
        struct mtx              sc_mtx;
        device_t                sc_dev;
-       bus_space_tag_t         sc_bst;
-       bus_space_handle_t      sc_bsh;
        struct resource         *sc_res[2];
+       void                    *sc_ih;
        uint32_t                sc_timeout;
+       bool                    sc_pde_enabled;
 };
 
 static struct resource_spec imx_wdog_spec[] = {
        { SYS_RES_MEMORY,       0,      RF_ACTIVE },
        { SYS_RES_IRQ,          0,      RF_ACTIVE },
-       { -1, 0 }
+       RESOURCE_SPEC_END
 };
 
+#define        MEMRES  0
+#define        IRQRES  1
+
 static struct ofw_compat_data compat_data[] = {
        {"fsl,imx6sx-wdt", 1},
        {"fsl,imx6sl-wdt", 1},
@@ -81,28 +85,19 @@ static struct ofw_compat_data compat_data[] = {
        {NULL,             0}
 };
 
-static void    imx_watchdog(void *, u_int, int *);
-static int     imx_wdog_probe(device_t);
-static int     imx_wdog_attach(device_t);
+static inline uint16_t
+RD2(struct imx_wdog_softc *sc, bus_size_t offs)
+{
 
-static device_method_t imx_wdog_methods[] = {
-       DEVMETHOD(device_probe,         imx_wdog_probe),
-       DEVMETHOD(device_attach,        imx_wdog_attach),
-       DEVMETHOD_END
-};
+       return (bus_read_2(sc->sc_res[MEMRES], offs));
+}
 
-static driver_t imx_wdog_driver = {
-       "imx_wdog",
-       imx_wdog_methods,
-       sizeof(struct imx_wdog_softc),
-};
-static devclass_t imx_wdog_devclass;
-DRIVER_MODULE(imx_wdog, simplebus, imx_wdog_driver, imx_wdog_devclass, 0, 0);
+static inline void
+WR2(struct imx_wdog_softc *sc, bus_size_t offs, uint16_t val)
+{
 
-#define        RD2(_sc, _r)                                                    
\
-               bus_space_read_2((_sc)->sc_bst, (_sc)->sc_bsh, (_r))
-#define        WR2(_sc, _r, _v)                                                
\
-               bus_space_write_2((_sc)->sc_bst, (_sc)->sc_bsh, (_r), (_v))
+       bus_write_2(sc->sc_res[MEMRES], offs, val);
+}
 
 static void
 imx_watchdog(void *arg, u_int cmd, int *error)
@@ -131,6 +126,12 @@ imx_watchdog(void *arg, u_int cmd, int *error)
                        /* Refresh counter */
                        WR2(sc, WDOG_SR_REG, WDOG_SR_STEP1);
                        WR2(sc, WDOG_SR_REG, WDOG_SR_STEP2);
+                       /* Watchdog active, can disable rom-boot watchdog. */
+                       if (sc->sc_pde_enabled) {
+                               sc->sc_pde_enabled = false;
+                               reg = RD2(sc, WDOG_MCR_REG);
+                               WR2(sc, WDOG_MCR_REG, reg & ~WDOG_MCR_PDE);
+                       }
                        *error = 0;
                }
        }
@@ -138,6 +139,27 @@ imx_watchdog(void *arg, u_int cmd, int *error)
 }
 
 static int
+imx_wdog_intr(void *arg)
+{
+       struct imx_wdog_softc *sc = arg;
+
+       /*
+        * When configured for external reset, the actual reset is supposed to
+        * happen when some external device responds to the assertion of the
+        * WDOG_B signal by asserting the POR signal to the chip.  This
+        * interrupt handler is a backstop mechanism; it is set up to fire
+        * simultaneously with WDOG_B, and if the external reset happens we'll
+        * never actually make it to here.  If we do make it here, just trigger
+        * a software reset.  That code will see that external reset is
+        * configured, and it will wait for 1 second for it to take effect, then
+        * it will do a software reset as a fallback.
+        */
+       imx_wdog_cpu_reset(BUS_SPACE_PHYSADDR(sc->sc_res[MEMRES], WDOG_CR_REG));
+
+       return (FILTER_HANDLED); /* unreached */
+}
+
+static int
 imx_wdog_probe(device_t dev)
 {
 
@@ -166,12 +188,43 @@ imx_wdog_attach(device_t dev)
 
        mtx_init(&sc->sc_mtx, device_get_nameunit(dev), "imx_wdt", MTX_DEF);
 
-       sc->sc_dev = dev;
-       sc->sc_bst = rman_get_bustag(sc->sc_res[0]);
-       sc->sc_bsh = rman_get_bushandle(sc->sc_res[0]);
+       /*
+        * If we're configured to assert an external reset signal, set up the
+        * hardware to do so, and install an interrupt handler whose only
+        * purpose is to backstop the external reset.  Don't worry if the
+        * interrupt setup fails, since it's only a backstop measure.
+        */
+       if (ofw_bus_has_prop(sc->sc_dev, "fsl,ext-reset-output")) {
+               WR2(sc, WDOG_CR_REG, WDOG_CR_WDT | RD2(sc, WDOG_CR_REG));
+               bus_setup_intr(sc->sc_dev, sc->sc_res[IRQRES],
+                   INTR_TYPE_MISC | INTR_MPSAFE, imx_wdog_intr, NULL, sc,
+                   &sc->sc_ih);
+               WR2(sc, WDOG_ICR_REG, WDOG_ICR_WIE); /* Enable, count is 0. */
+       }
 
-       /* TODO: handle interrupt */
+       /*
+        * Note whether the rom-boot so-called "power-down" watchdog is active,
+        * so we can disable it when the regular watchdog is first enabled.
+        */
+       if (RD2(sc, WDOG_MCR_REG) & WDOG_MCR_PDE)
+               sc->sc_pde_enabled = true;
 
        EVENTHANDLER_REGISTER(watchdog_list, imx_watchdog, sc, 0);
        return (0);
 }
+
+static device_method_t imx_wdog_methods[] = {
+       DEVMETHOD(device_probe,         imx_wdog_probe),
+       DEVMETHOD(device_attach,        imx_wdog_attach),
+       DEVMETHOD_END
+};
+
+static driver_t imx_wdog_driver = {
+       "imx_wdog",
+       imx_wdog_methods,
+       sizeof(struct imx_wdog_softc),
+};
+
+static devclass_t imx_wdog_devclass;
+
+DRIVER_MODULE(imx_wdog, simplebus, imx_wdog_driver, imx_wdog_devclass, 0, 0);

Modified: stable/11/sys/arm/freescale/imx/imx_wdogreg.h
==============================================================================
--- stable/11/sys/arm/freescale/imx/imx_wdogreg.h       Sat Mar 24 21:22:28 
2018        (r331497)
+++ stable/11/sys/arm/freescale/imx/imx_wdogreg.h       Sat Mar 24 21:27:10 
2018        (r331498)
@@ -34,31 +34,31 @@
 #define        WDOG_CLK_FREQ   32768
 
 #define        WDOG_CR_REG     0x00    /* Control Register */
-#define                WDOG_CR_WT_MASK         0xff00  /* Count of 0.5 sec */
-#define                WDOG_CR_WT_SHIFT        8
-#define                WDOG_CR_WDW             (1 << 7) /* Suspend WDog */
-#define                WDOG_CR_WDA             (1 << 5) /* Don't touch 
ipp_wdog */
-#define                WDOG_CR_SRS             (1 << 4) /* Don't touch 
sys_reset */
-#define                WDOG_CR_WDT             (1 << 3) /* Assert ipp_wdog on 
tout */
-#define                WDOG_CR_WDE             (1 << 2) /* WDog Enable */
-#define                WDOG_CR_WDBG            (1 << 1) /* Suspend when DBG 
mode */
-#define                WDOG_CR_WDZST           (1 << 0) /* Suspend when LP 
mode */
+#define          WDOG_CR_WT_MASK         0xff00    /* Count; 0.5 sec units */
+#define          WDOG_CR_WT_SHIFT        8
+#define          WDOG_CR_WDW             (1u << 7) /* Suspend when in WAIT 
mode */
+#define          WDOG_CR_WDA             (1u << 5) /* Don't assert ext reset */
+#define          WDOG_CR_SRS             (1u << 4) /* Don't assert soft reset 
*/
+#define          WDOG_CR_WDT             (1u << 3) /* Assert ext reset on 
timeout */
+#define          WDOG_CR_WDE             (1u << 2) /* Watchdog Enable */
+#define          WDOG_CR_WDBG            (1u << 1) /* Suspend when DBG mode */
+#define          WDOG_CR_WDZST           (1u << 0) /* Suspend when LP mode */
 
 #define        WDOG_SR_REG     0x02    /* Service Register */
-#define                WDOG_SR_STEP1           0x5555
-#define                WDOG_SR_STEP2           0xaaaa
+#define          WDOG_SR_STEP1           0x5555
+#define          WDOG_SR_STEP2           0xaaaa
 
 #define        WDOG_RSR_REG    0x04    /* Reset Status Register */
-#define                WDOG_RSR_POR            (1 << 4) /* Due to Power-On 
Reset */
-#define                WDOG_RSR_TOUT           (1 << 1) /* Due WDog timeout 
reset */
-#define                WDOG_RSR_SFTW           (1 << 0) /* Due Soft reset */
+#define          WDOG_RSR_POR            (1u << 4) /* Due to Power-On Reset */
+#define          WDOG_RSR_TOUT           (1u << 1) /* Due WDog timeout reset */
+#define          WDOG_RSR_SFTW           (1u << 0) /* Due Soft reset */
 
 #define        WDOG_ICR_REG    0x06    /* Interrupt Control Register */
-#define                WDOG_ICR_WIE            (1 << 15) /* Enable Interrupt */
-#define                WDOG_ICR_WTIS           (1 << 14) /* Interrupt has 
occurred */
-#define                WDOG_ICR_WTCT_MASK      0x00ff
-#define                WDOG_ICR_WTCT_SHIFT     0       /* Interrupt hold time 
*/
+#define          WDOG_ICR_WIE            (1u << 15) /* Enable Interrupt */
+#define          WDOG_ICR_WTIS           (1u << 14) /* Interrupt has occurred 
*/
+#define          WDOG_ICR_WTCT_MASK      0x00ff     /* Interrupt lead time in 
0.5s */
+#define          WDOG_ICR_WTCT_SHIFT     0          /* units before reset 
occurs */
 
 #define        WDOG_MCR_REG    0x08    /* Miscellaneous Control Register */
-#define                WDOG_MCR_PDE            (1 << 0)
+#define          WDOG_MCR_PDE            (1u << 0)  /* Power-down enable */
 
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to