svn commit: r256572 - head/sys/mips/atheros

Adrian Chadd adrian at FreeBSD.org
Wed Oct 16 02:10:36 UTC 2013


Author: adrian
Date: Wed Oct 16 02:10:35 2013
New Revision: 256572
URL: http://svnweb.freebsd.org/changeset/base/256572

Log:
  Add bus space barriers to the AR71xx SPI code.
  
  This is required for correct, stable operation on the MIPS74k SoCs
  that are dual-issue, superscalar pipelines.
  
  Tested:
  
  * AR9344 SoC (MIPS74k)
  * AR9331 SoC (MIPS24k)

Modified:
  head/sys/mips/atheros/ar71xx_spi.c

Modified: head/sys/mips/atheros/ar71xx_spi.c
==============================================================================
--- head/sys/mips/atheros/ar71xx_spi.c	Wed Oct 16 01:39:26 2013	(r256571)
+++ head/sys/mips/atheros/ar71xx_spi.c	Wed Oct 16 02:10:35 2013	(r256572)
@@ -62,8 +62,16 @@ __FBSDID("$FreeBSD$");
 /*
  * register space access macros
  */
-#define SPI_WRITE(sc, reg, val)	do {	\
-		bus_write_4(sc->sc_mem_res, (reg), (val)); \
+
+#define	SPI_BARRIER_WRITE(sc)		bus_barrier((sc)->sc_mem_res, 0, 0, 	\
+					    BUS_SPACE_BARRIER_WRITE)
+#define	SPI_BARRIER_READ(sc)	bus_barrier((sc)->sc_mem_res, 0, 0, 	\
+					    BUS_SPACE_BARRIER_READ)
+#define	SPI_BARRIER_RW(sc)		bus_barrier((sc)->sc_mem_res, 0, 0, 	\
+					    BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE)
+
+#define SPI_WRITE(sc, reg, val)	do {				\
+		bus_write_4(sc->sc_mem_res, (reg), (val));	\
 	} while (0)
 
 #define SPI_READ(sc, reg)	 bus_read_4(sc->sc_mem_res, (reg))
@@ -102,12 +110,30 @@ ar71xx_spi_attach(device_t dev)
 		return (ENXIO);
 	}
 
-
 	SPI_WRITE(sc, AR71XX_SPI_FS, 1);
+
+	/* Flush out read before reading the control register */
+	SPI_BARRIER_WRITE(sc);
+
 	sc->sc_reg_ctrl  = SPI_READ(sc, AR71XX_SPI_CTRL);
+
+	/*
+	 * XXX TODO: document what the SPI control register does.
+	 */
 	SPI_WRITE(sc, AR71XX_SPI_CTRL, 0x43);
+
+	/*
+	 * Ensure the config register write has gone out before configuring
+	 * the chip select mask.
+	 */
+	SPI_BARRIER_WRITE(sc);
 	SPI_WRITE(sc, AR71XX_SPI_IO_CTRL, SPI_IO_CTRL_CSMASK);
 
+	/*
+	 * .. and ensure the write has gone out before continuing.
+	 */
+	SPI_BARRIER_WRITE(sc);
+
 	device_add_child(dev, "spibus", -1);
 	return (bus_generic_attach(dev));
 }
@@ -121,7 +147,15 @@ ar71xx_spi_chip_activate(struct ar71xx_s
 	 */
 	ioctrl &= ~(SPI_IO_CTRL_CS0 << cs);
 
+	/*
+	 * Make sure any other writes have gone out to the
+	 * device before changing the chip select line;
+	 * then ensure that it has made it out to the device
+	 * before continuing.
+	 */
+	SPI_BARRIER_WRITE(sc);
 	SPI_WRITE(sc, AR71XX_SPI_IO_CTRL, ioctrl);
+	SPI_BARRIER_WRITE(sc);
 }
 
 static void
@@ -150,14 +184,18 @@ ar71xx_spi_txrx(struct ar71xx_spi_softc 
 			iod = ioctrl | SPI_IO_CTRL_DO;
 		else
 			iod = ioctrl & ~SPI_IO_CTRL_DO;
+		SPI_BARRIER_WRITE(sc);
 		SPI_WRITE(sc, AR71XX_SPI_IO_CTRL, iod);
+		SPI_BARRIER_WRITE(sc);
 		SPI_WRITE(sc, AR71XX_SPI_IO_CTRL, iod | SPI_IO_CTRL_CLK);
 	}
 
 	/*
 	 * Provide falling edge for connected device by clear clock bit.
 	 */
+	SPI_BARRIER_WRITE(sc);
 	SPI_WRITE(sc, AR71XX_SPI_IO_CTRL, iod);
+	SPI_BARRIER_WRITE(sc);
 	rds = SPI_READ(sc, AR71XX_SPI_RDS);
 
 	return (rds & 0xff);
@@ -206,8 +244,25 @@ ar71xx_spi_detach(device_t dev)
 {
 	struct ar71xx_spi_softc *sc = device_get_softc(dev);
 
+	/*
+	 * Ensure any other writes to the device are finished
+	 * before we tear down the SPI device.
+	 */
+	SPI_BARRIER_WRITE(sc);
+
+	/*
+	 * Restore the control register; ensure it has hit the
+	 * hardware before continuing.
+	 */
 	SPI_WRITE(sc, AR71XX_SPI_CTRL, sc->sc_reg_ctrl);
+	SPI_BARRIER_WRITE(sc);
+
+	/*
+	 * And now, put the flash back into mapped IO mode and
+	 * ensure _that_ has completed before we finish up.
+	 */
 	SPI_WRITE(sc, AR71XX_SPI_FS, 0);
+	SPI_BARRIER_WRITE(sc);
 
 	if (sc->sc_mem_res)
 		bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res);


More information about the svn-src-all mailing list