svn commit: r335991 - stable/11/sys/arm/freescale/imx

Ian Lepore ian at FreeBSD.org
Thu Jul 5 16:12:49 UTC 2018


Author: ian
Date: Thu Jul  5 16:12:48 2018
New Revision: 335991
URL: https://svnweb.freebsd.org/changeset/base/335991

Log:
  MFC r333255, r333260
  
  r333255:
  Make reading imx6 gpio pins work correctly whether the pin is in open-drain
  mode or not.  An earlier attempt to make this work was done in r320456, by
  always reading the pad status register (PSR) instead of the data register.
  But it turns out the values in PSR only reflect the electrical level of an
  output pin if the pad is configured with the SION (Set Input On) bit in the
  pinmux config, and most output gpio pads are not configured that way.
  
  So now a gpio read is done by returning the value from the data register,
  which works right whether the pin is configured for input or output, unless
  the pin has been set for OPENDRAIN mode, in which case the PSR is read
  instead.  For this to work, the pin must also be configured with SION turned
  on in the fdt pinmux data, which is a reasonable thing to require for the
  unusual case of reading an open-drain output pin.
  
  r333260:
  Properly support the GPIO_PIN_PRESET_{LOW,HIGH} options when configuring
  a gpio pin.  If neither of the options is specified, pre-set the pin's
  output value to the pin's current input value, to achieve glitch-free
  transitions to output mode on pins that are pulled up or down at reset
  or via fdt pinctrl data.

Modified:
  stable/11/sys/arm/freescale/imx/imx_gpio.c
Directory Properties:
  stable/11/   (props changed)

Modified: stable/11/sys/arm/freescale/imx/imx_gpio.c
==============================================================================
--- stable/11/sys/arm/freescale/imx/imx_gpio.c	Thu Jul  5 16:03:03 2018	(r335990)
+++ stable/11/sys/arm/freescale/imx/imx_gpio.c	Thu Jul  5 16:12:48 2018	(r335991)
@@ -507,21 +507,41 @@ static void
 imx51_gpio_pin_configure(struct imx51_gpio_softc *sc, struct gpio_pin *pin,
     unsigned int flags)
 {
-	u_int newflags;
+	u_int newflags, pad;
 
 	mtx_lock_spin(&sc->sc_mtx);
 
 	/*
-	 * Manage input/output; other flags not supported yet.
+	 * Manage input/output; other flags not supported yet (maybe not ever,
+	 * since we have no connection to the pad config registers from here).
 	 *
+	 * When setting a pin to output, honor the PRESET_[LOW,HIGH] flags if
+	 * present.  Otherwise, for glitchless transistions on pins with pulls,
+	 * read the current state of the pad and preset the DR register to drive
+	 * the current value onto the pin before enabling the pin for output.
+	 *
 	 * Note that changes to pin->gp_flags must be acccumulated in newflags
 	 * and stored with a single writeback to gp_flags at the end, to enable
-	 * unlocked reads of that value elsewhere.
+	 * unlocked reads of that value elsewhere. This is only about unlocked
+	 * access to gp_flags from elsewhere; we still use locking in this
+	 * function to protect r-m-w access to the hardware registers.
 	 */
 	if (flags & (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)) {
 		newflags = pin->gp_flags & ~(GPIO_PIN_INPUT | GPIO_PIN_OUTPUT);
 		if (flags & GPIO_PIN_OUTPUT) {
+			if (flags & GPIO_PIN_PRESET_LOW) {
+				pad = 0;
+			} else if (flags & GPIO_PIN_PRESET_HIGH) {
+				pad = 1;
+			} else {
+				if (flags & GPIO_PIN_OPENDRAIN)
+					pad = READ4(sc, IMX_GPIO_PSR_REG);
+				else
+					pad = READ4(sc, IMX_GPIO_DR_REG);
+				pad = (pad >> pin->gp_pin) & 1;
+			}
 			newflags |= GPIO_PIN_OUTPUT;
+			SET4(sc, IMX_GPIO_DR_REG, (pad << pin->gp_pin));
 			SET4(sc, IMX_GPIO_OE_REG, (1U << pin->gp_pin));
 		} else {
 			newflags |= GPIO_PIN_INPUT;
@@ -645,7 +665,20 @@ imx51_gpio_pin_get(device_t dev, uint32_t pin, unsigne
 	if (pin >= sc->gpio_npins)
 		return (EINVAL);
 
-	*val = (READ4(sc, IMX_GPIO_PSR_REG) >> pin) & 1;
+	/*
+	 * Normally a pin set for output can be read by reading the DR reg which
+	 * indicates what value is being driven to that pin.  The exception is
+	 * pins configured for open-drain mode, in which case we have to read
+	 * the pad status register in case the pin is being driven externally.
+	 * Doing so requires that the SION bit be configured in pinmux, which
+	 * isn't the case for most normal gpio pins, so only try to read via PSR
+	 * if the OPENDRAIN flag is set, and it's the user's job to correctly
+	 * configure SION along with open-drain output mode for those pins.
+	 */
+	if (sc->gpio_pins[pin].gp_flags & GPIO_PIN_OPENDRAIN)
+		*val = (READ4(sc, IMX_GPIO_PSR_REG) >> pin) & 1;
+	else
+		*val = (READ4(sc, IMX_GPIO_DR_REG) >> pin) & 1;
 
 	return (0);
 }
@@ -680,7 +713,7 @@ imx51_gpio_pin_access_32(device_t dev, uint32_t first_
 	sc = device_get_softc(dev);
 
 	if (orig_pins != NULL)
-		*orig_pins = READ4(sc, IMX_GPIO_PSR_REG);
+		*orig_pins = READ4(sc, IMX_GPIO_DR_REG);
 
 	if ((clear_pins | change_pins) != 0) {
 		mtx_lock_spin(&sc->sc_mtx);
@@ -706,7 +739,7 @@ imx51_gpio_pin_config_32(device_t dev, uint32_t first_
 		return (EINVAL);
 
 	drclr = drset = oeclr = oeset = 0;
-	pads = READ4(sc, IMX_GPIO_PSR_REG);
+	pads = READ4(sc, IMX_GPIO_DR_REG);
 
 	for (i = 0; i < num_pins; ++i) {
 		bit = 1u << i;


More information about the svn-src-stable mailing list