diff options
author | Marius Strobl <marius@FreeBSD.org> | 2008-12-07 23:02:37 +0000 |
---|---|---|
committer | Marius Strobl <marius@FreeBSD.org> | 2008-12-07 23:02:37 +0000 |
commit | 155781198a1e5f675dbb3bb8b4df4ecc182c67f9 (patch) | |
tree | 5e8839c045e4e51e8717550cec6cb78699ace04c /sys | |
parent | f2323a477f0429fa65e1943f67b3d4137889e639 (diff) | |
download | src-155781198a1e5f675dbb3bb8b4df4ecc182c67f9.tar.gz src-155781198a1e5f675dbb3bb8b4df4ecc182c67f9.zip |
- According to the corresponding Linux, NetBSD and OpenSolaris
drivers, there should be a 1us delay after every write when
bit-banging the MII. Also insert barriers in order to ensure
the intended ordering. These changes hopefully will solve the
bus wedging occasionally experienced with DM9102A since r182461.
- Deobfuscate dc_mii_readreg() a bit.
Notes
Notes:
svn path=/head/; revision=185750
Diffstat (limited to 'sys')
-rw-r--r-- | sys/dev/dc/if_dc.c | 80 | ||||
-rw-r--r-- | sys/dev/dc/if_dcreg.h | 3 |
2 files changed, 47 insertions, 36 deletions
diff --git a/sys/dev/dc/if_dc.c b/sys/dev/dc/if_dc.c index 979748dd135a..be24cb0e3184 100644 --- a/sys/dev/dc/if_dc.c +++ b/sys/dev/dc/if_dc.c @@ -607,15 +607,22 @@ dc_read_eeprom(struct dc_softc *sc, caddr_t dest, int off, int cnt, int be) static void dc_mii_writebit(struct dc_softc *sc, int bit) { - - if (bit) - CSR_WRITE_4(sc, DC_SIO, - DC_SIO_ROMCTL_WRITE | DC_SIO_MII_DATAOUT); - else - CSR_WRITE_4(sc, DC_SIO, DC_SIO_ROMCTL_WRITE); - - DC_SETBIT(sc, DC_SIO, DC_SIO_MII_CLK); - DC_CLRBIT(sc, DC_SIO, DC_SIO_MII_CLK); + uint32_t reg; + + reg = DC_SIO_ROMCTL_WRITE | (bit != 0 ? DC_SIO_MII_DATAOUT : 0); + CSR_WRITE_4(sc, DC_SIO, reg); + CSR_BARRIER_4(sc, DC_SIO, + BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); + DELAY(1); + + CSR_WRITE_4(sc, DC_SIO, reg | DC_SIO_MII_CLK); + CSR_BARRIER_4(sc, DC_SIO, + BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); + DELAY(1); + CSR_WRITE_4(sc, DC_SIO, reg); + CSR_BARRIER_4(sc, DC_SIO, + BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); + DELAY(1); } /* @@ -624,11 +631,22 @@ dc_mii_writebit(struct dc_softc *sc, int bit) static int dc_mii_readbit(struct dc_softc *sc) { - - CSR_WRITE_4(sc, DC_SIO, DC_SIO_ROMCTL_READ | DC_SIO_MII_DIR); - CSR_READ_4(sc, DC_SIO); - DC_SETBIT(sc, DC_SIO, DC_SIO_MII_CLK); - DC_CLRBIT(sc, DC_SIO, DC_SIO_MII_CLK); + uint32_t reg; + + reg = DC_SIO_ROMCTL_READ | DC_SIO_MII_DIR; + CSR_WRITE_4(sc, DC_SIO, reg); + CSR_BARRIER_4(sc, DC_SIO, + BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); + DELAY(1); + (void)CSR_READ_4(sc, DC_SIO); + CSR_WRITE_4(sc, DC_SIO, reg | DC_SIO_MII_CLK); + CSR_BARRIER_4(sc, DC_SIO, + BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); + DELAY(1); + CSR_WRITE_4(sc, DC_SIO, reg); + CSR_BARRIER_4(sc, DC_SIO, + BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); + DELAY(1); if (CSR_READ_4(sc, DC_SIO) & DC_SIO_MII_DATAIN) return (1); @@ -644,6 +662,9 @@ dc_mii_sync(struct dc_softc *sc) int i; CSR_WRITE_4(sc, DC_SIO, DC_SIO_ROMCTL_WRITE); + CSR_BARRIER_4(sc, DC_SIO, + BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); + DELAY(1); for (i = 0; i < 32; i++) dc_mii_writebit(sc, 1); @@ -667,15 +688,13 @@ dc_mii_send(struct dc_softc *sc, u_int32_t bits, int cnt) static int dc_mii_readreg(struct dc_softc *sc, struct dc_mii_frame *frame) { - int i, ack; + int i; /* * Set up frame for RX. */ frame->mii_stdelim = DC_MII_STARTDELIM; frame->mii_opcode = DC_MII_READOP; - frame->mii_turnaround = 0; - frame->mii_data = 0; /* * Sync the PHYs. @@ -690,38 +709,28 @@ dc_mii_readreg(struct dc_softc *sc, struct dc_mii_frame *frame) dc_mii_send(sc, frame->mii_phyaddr, 5); dc_mii_send(sc, frame->mii_regaddr, 5); -#ifdef notdef - /* Idle bit */ - dc_mii_writebit(sc, 1); - dc_mii_writebit(sc, 0); -#endif - - /* Check for ack. */ - ack = dc_mii_readbit(sc); - /* - * Now try reading data bits. If the ack failed, we still + * Now try reading data bits. If the turnaround failed, we still * need to clock through 16 cycles to keep the PHY(s) in sync. */ - if (ack) { + frame->mii_turnaround = dc_mii_readbit(sc); + if (frame->mii_turnaround != 0) { for (i = 0; i < 16; i++) dc_mii_readbit(sc); goto fail; } - for (i = 0x8000; i; i >>= 1) { - if (!ack) { - if (dc_mii_readbit(sc)) - frame->mii_data |= i; - } + if (dc_mii_readbit(sc)) + frame->mii_data |= i; } fail: + /* Clock the idle bits. */ dc_mii_writebit(sc, 0); dc_mii_writebit(sc, 0); - if (ack) + if (frame->mii_turnaround != 0) return (1); return (0); } @@ -736,7 +745,6 @@ dc_mii_writereg(struct dc_softc *sc, struct dc_mii_frame *frame) /* * Set up frame for TX. */ - frame->mii_stdelim = DC_MII_STARTDELIM; frame->mii_opcode = DC_MII_WRITEOP; frame->mii_turnaround = DC_MII_TURNAROUND; @@ -753,7 +761,7 @@ dc_mii_writereg(struct dc_softc *sc, struct dc_mii_frame *frame) dc_mii_send(sc, frame->mii_turnaround, 2); dc_mii_send(sc, frame->mii_data, 16); - /* Idle bit. */ + /* Clock the idle bits. */ dc_mii_writebit(sc, 0); dc_mii_writebit(sc, 0); diff --git a/sys/dev/dc/if_dcreg.h b/sys/dev/dc/if_dcreg.h index eb798dcb19bb..cce2c1003585 100644 --- a/sys/dev/dc/if_dcreg.h +++ b/sys/dev/dc/if_dcreg.h @@ -791,6 +791,9 @@ struct dc_softc { #define CSR_READ_4(sc, reg) \ bus_space_read_4(sc->dc_btag, sc->dc_bhandle, reg) +#define CSR_BARRIER_4(sc, reg, flags) \ + bus_space_barrier(sc->dc_btag, sc->dc_bhandle, reg, 4, flags) + #define DC_TIMEOUT 1000 #define ETHER_ALIGN 2 |