Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 24 Mar 2018 21:27:10 +0000 (UTC)
From:      Ian Lepore <ian@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-11@freebsd.org
Subject:   svn commit: r331498 - stable/11/sys/arm/freescale/imx
Message-ID:  <201803242127.w2OLRACu076515@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
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 */
 



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201803242127.w2OLRACu076515>