diff options
author | marius <marius@FreeBSD.org> | 2011-11-01 16:13:59 +0000 |
---|---|---|
committer | marius <marius@FreeBSD.org> | 2011-11-01 16:13:59 +0000 |
commit | b4610d98b0096971fd87d53d90c40f4da7db34e2 (patch) | |
tree | ad9ba266ea9f21e3bb8157cdc1c2c7c8b1a6b9a3 /sys/dev/smc | |
parent | d08a02f709c03ad61dd57d1fa39412d6de62189d (diff) | |
download | FreeBSD-src-b4610d98b0096971fd87d53d90c40f4da7db34e2.zip FreeBSD-src-b4610d98b0096971fd87d53d90c40f4da7db34e2.tar.gz |
- Import the common MII bitbang'ing code from NetBSD and convert drivers to
take advantage of it instead of duplicating it. This reduces the size of
the i386 GENERIC kernel by about 4k. The only potential in-tree user left
unconverted is xe(4), which generally should be changed to use miibus(4)
instead of implementing PHY handling on its own, as otherwise it makes not
much sense to add a dependency on miibus(4)/mii_bitbang(4) to xe(4) just
for the MII bitbang'ing code. The common MII bitbang'ing code also is
useful in the embedded space for using GPIO pins to implement MII access.
- Based on lessons learnt with dc(4) (see r185750), add bus barriers to the
MII bitbang read and write functions of the other drivers converted in
order to ensure the intended ordering. Given that register access via an
index register as well as register bank/window switching is subject to the
same problem, also add bus barriers to the respective functions of smc(4),
tl(4) and xl(4).
- Sprinkle some const.
Thanks to the following testers:
Andrew Bliznak (nge(4)), nwhitehorn@ (bm(4)), yongari@ (sis(4) and ste(4))
Thanks to Hans-Joerg Sirtl for supplying hardware to test stge(4).
Reviewed by: yongari (subset of drivers)
Obtained from: NetBSD (partially)
Diffstat (limited to 'sys/dev/smc')
-rw-r--r-- | sys/dev/smc/if_smc.c | 145 |
1 files changed, 57 insertions, 88 deletions
diff --git a/sys/dev/smc/if_smc.c b/sys/dev/smc/if_smc.c index 4aa0396..9404f56 100644 --- a/sys/dev/smc/if_smc.c +++ b/sys/dev/smc/if_smc.c @@ -74,6 +74,7 @@ __FBSDID("$FreeBSD$"); #include <dev/smc/if_smcvar.h> #include <dev/mii/mii.h> +#include <dev/mii/mii_bitbang.h> #include <dev/mii/miivar.h> #define SMC_LOCK(sc) mtx_lock(&(sc)->smc_mtx) @@ -123,11 +124,33 @@ static timeout_t smc_watchdog; static poll_handler_t smc_poll; #endif +/* + * MII bit-bang glue + */ +static uint32_t smc_mii_bitbang_read(device_t); +static void smc_mii_bitbang_write(device_t, uint32_t); + +static const struct mii_bitbang_ops smc_mii_bitbang_ops = { + smc_mii_bitbang_read, + smc_mii_bitbang_write, + { + MGMT_MDO, /* MII_BIT_MDO */ + MGMT_MDI, /* MII_BIT_MDI */ + MGMT_MCLK, /* MII_BIT_MDC */ + MGMT_MDOE, /* MII_BIT_DIR_HOST_PHY */ + 0, /* MII_BIT_DIR_PHY_HOST */ + } +}; + static __inline void smc_select_bank(struct smc_softc *sc, uint16_t bank) { + bus_barrier(sc->smc_reg, BSR, 2, + BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); bus_write_2(sc->smc_reg, BSR, bank & BSR_BANK_MASK); + bus_barrier(sc->smc_reg, BSR, 2, + BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); } /* Never call this when not in bank 2. */ @@ -143,35 +166,35 @@ smc_mmu_wait(struct smc_softc *sc) } static __inline uint8_t -smc_read_1(struct smc_softc *sc, bus_addr_t offset) +smc_read_1(struct smc_softc *sc, bus_size_t offset) { return (bus_read_1(sc->smc_reg, offset)); } static __inline void -smc_write_1(struct smc_softc *sc, bus_addr_t offset, uint8_t val) +smc_write_1(struct smc_softc *sc, bus_size_t offset, uint8_t val) { bus_write_1(sc->smc_reg, offset, val); } static __inline uint16_t -smc_read_2(struct smc_softc *sc, bus_addr_t offset) +smc_read_2(struct smc_softc *sc, bus_size_t offset) { return (bus_read_2(sc->smc_reg, offset)); } static __inline void -smc_write_2(struct smc_softc *sc, bus_addr_t offset, uint16_t val) +smc_write_2(struct smc_softc *sc, bus_size_t offset, uint16_t val) { bus_write_2(sc->smc_reg, offset, val); } static __inline void -smc_read_multi_2(struct smc_softc *sc, bus_addr_t offset, uint16_t *datap, +smc_read_multi_2(struct smc_softc *sc, bus_size_t offset, uint16_t *datap, bus_size_t count) { @@ -179,13 +202,21 @@ smc_read_multi_2(struct smc_softc *sc, bus_addr_t offset, uint16_t *datap, } static __inline void -smc_write_multi_2(struct smc_softc *sc, bus_addr_t offset, uint16_t *datap, +smc_write_multi_2(struct smc_softc *sc, bus_size_t offset, uint16_t *datap, bus_size_t count) { bus_write_multi_2(sc->smc_reg, offset, datap, count); } +static __inline void +smc_barrier(struct smc_softc *sc, bus_size_t offset, bus_size_t length, + int flags) +{ + + bus_barrier(sc->smc_reg, offset, length, flags); +} + int smc_probe(device_t dev) { @@ -900,70 +931,43 @@ smc_task_intr(void *context, int pending) SMC_UNLOCK(sc); } -static u_int -smc_mii_readbits(struct smc_softc *sc, int nbits) +static uint32_t +smc_mii_bitbang_read(device_t dev) { - u_int mgmt, mask, val; + struct smc_softc *sc; + uint32_t val; + + sc = device_get_softc(dev); SMC_ASSERT_LOCKED(sc); KASSERT((smc_read_2(sc, BSR) & BSR_BANK_MASK) == 3, - ("%s: smc_mii_readbits called with bank %d (!= 3)", + ("%s: smc_mii_bitbang_read called with bank %d (!= 3)", device_get_nameunit(sc->smc_dev), smc_read_2(sc, BSR) & BSR_BANK_MASK)); - /* - * Set up the MGMT (aka MII) register. - */ - mgmt = smc_read_2(sc, MGMT) & ~(MGMT_MCLK | MGMT_MDOE | MGMT_MDO); - smc_write_2(sc, MGMT, mgmt); - - /* - * Read the bits in. - */ - for (mask = 1 << (nbits - 1), val = 0; mask; mask >>= 1) { - if (smc_read_2(sc, MGMT) & MGMT_MDI) - val |= mask; - - smc_write_2(sc, MGMT, mgmt); - DELAY(1); - smc_write_2(sc, MGMT, mgmt | MGMT_MCLK); - DELAY(1); - } + val = smc_read_2(sc, MGMT); + smc_barrier(sc, MGMT, 2, + BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); return (val); } static void -smc_mii_writebits(struct smc_softc *sc, u_int val, int nbits) +smc_mii_bitbang_write(device_t dev, uint32_t val) { - u_int mgmt, mask; + struct smc_softc *sc; + + sc = device_get_softc(dev); SMC_ASSERT_LOCKED(sc); KASSERT((smc_read_2(sc, BSR) & BSR_BANK_MASK) == 3, - ("%s: smc_mii_writebits called with bank %d (!= 3)", + ("%s: smc_mii_bitbang_write called with bank %d (!= 3)", device_get_nameunit(sc->smc_dev), smc_read_2(sc, BSR) & BSR_BANK_MASK)); - /* - * Set up the MGMT (aka MII) register). - */ - mgmt = smc_read_2(sc, MGMT) & ~(MGMT_MCLK | MGMT_MDOE | MGMT_MDO); - mgmt |= MGMT_MDOE; - - /* - * Push the bits out. - */ - for (mask = 1 << (nbits - 1); mask; mask >>= 1) { - if (val & mask) - mgmt |= MGMT_MDO; - else - mgmt &= ~MGMT_MDO; - - smc_write_2(sc, MGMT, mgmt); - DELAY(1); - smc_write_2(sc, MGMT, mgmt | MGMT_MCLK); - DELAY(1); - } + smc_write_2(sc, MGMT, val); + smc_barrier(sc, MGMT, 2, + BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); } int @@ -978,26 +982,7 @@ smc_miibus_readreg(device_t dev, int phy, int reg) smc_select_bank(sc, 3); - /* - * Send out the idle pattern. - */ - smc_mii_writebits(sc, 0xffffffff, 32); - - /* - * Start code + read opcode + phy address + phy register - */ - smc_mii_writebits(sc, 6 << 10 | phy << 5 | reg, 14); - - /* - * Turnaround + data - */ - val = smc_mii_readbits(sc, 18); - - /* - * Reset the MDIO interface. - */ - smc_write_2(sc, MGMT, - smc_read_2(sc, MGMT) & ~(MGMT_MCLK | MGMT_MDOE | MGMT_MDO)); + val = mii_bitbang_readreg(dev, &smc_mii_bitbang_ops, phy, reg); SMC_UNLOCK(sc); return (val); @@ -1014,23 +999,7 @@ smc_miibus_writereg(device_t dev, int phy, int reg, int data) smc_select_bank(sc, 3); - /* - * Send idle pattern. - */ - smc_mii_writebits(sc, 0xffffffff, 32); - - /* - * Start code + write opcode + phy address + phy register + turnaround - * + data. - */ - smc_mii_writebits(sc, 5 << 28 | phy << 23 | reg << 18 | 2 << 16 | data, - 32); - - /* - * Reset MDIO interface. - */ - smc_write_2(sc, MGMT, - smc_read_2(sc, MGMT) & ~(MGMT_MCLK | MGMT_MDOE | MGMT_MDO)); + mii_bitbang_writereg(dev, &smc_mii_bitbang_ops, phy, reg, data); SMC_UNLOCK(sc); return (0); |