Date: Wed, 16 Oct 2013 02:10:35 +0000 (UTC) From: Adrian Chadd <adrian@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r256572 - head/sys/mips/atheros Message-ID: <201310160210.r9G2AZTm075441@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
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);
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201310160210.r9G2AZTm075441>