diff options
author | Mark Kettenis <kettenis@cvs.openbsd.org> | 2009-09-14 18:59:21 +0000 |
---|---|---|
committer | Mark Kettenis <kettenis@cvs.openbsd.org> | 2009-09-14 18:59:21 +0000 |
commit | c36b8d443f42f4a4764de7307b484c1cb296a58d (patch) | |
tree | 168407797ff109e1eed7d12c395d9bd3dd392ea5 | |
parent | 592cecb5eaa5757f8cfc557492fee691ee046a52 (diff) |
Deal with the fact that we need to control an external PHY attached to TSEC2
through the registers of TSEC1. Makes the first ethernet port on the rb600
usable.
-rw-r--r-- | sys/arch/socppc/dev/if_tsec.c | 68 |
1 files changed, 55 insertions, 13 deletions
diff --git a/sys/arch/socppc/dev/if_tsec.c b/sys/arch/socppc/dev/if_tsec.c index edbd6f1e5fb..97ea13cfc13 100644 --- a/sys/arch/socppc/dev/if_tsec.c +++ b/sys/arch/socppc/dev/if_tsec.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_tsec.c,v 1.26 2009/09/06 20:09:34 kettenis Exp $ */ +/* $OpenBSD: if_tsec.c,v 1.27 2009/09/14 18:59:20 kettenis Exp $ */ /* * Copyright (c) 2008 Mark Kettenis @@ -248,6 +248,7 @@ struct tsec_softc { struct device sc_dev; bus_space_tag_t sc_iot; bus_space_handle_t sc_ioh; + bus_space_handle_t sc_mii_ioh; bus_dma_tag_t sc_dmat; struct arpcom sc_ac; @@ -289,6 +290,8 @@ int tsec_find_phy(int, int); uint32_t tsec_read(struct tsec_softc *, bus_addr_t); void tsec_write(struct tsec_softc *, bus_addr_t, uint32_t); +uint32_t tsec_mii_read(struct tsec_softc *, bus_addr_t); +void tsec_mii_write(struct tsec_softc *, bus_addr_t, uint32_t); int tsec_ioctl(struct ifnet *, u_long, caddr_t); void tsec_start(struct ifnet *); @@ -326,6 +329,20 @@ void tsec_dmamem_free(struct tsec_softc *, struct tsec_dmamem *); struct mbuf *tsec_alloc_mbuf(struct tsec_softc *, bus_dmamap_t); void tsec_fill_rx_ring(struct tsec_softc *); +/* + * The MPC8349E processor has two TSECs but only one external + * management interface to control external PHYs. The registers + * controlling the management interface are part of TSEC1. So to + * control a PHY attached to TSEC2, one needs to access TSEC1's + * registers. To deal with this, the first TSEC that attaches maps + * the register space for both TSEC1 and TSEC2 and stores the bus + * space tag and bus space handle in these global variables. We use + * these to create subregions for each individual interface and the + * management interface. + */ +bus_space_tag_t tsec_iot; +bus_space_handle_t tsec_ioh; + int tsec_match(struct device *parent, void *cfdata, void *aux) { @@ -365,13 +382,26 @@ tsec_attach(struct device *parent, struct device *self, void *aux) oa->oa_phy = reg; } - sc->sc_iot = oa->oa_iot; - if (bus_space_map(sc->sc_iot, oa->oa_offset, 3072, 0, &sc->sc_ioh)) { - printf(": can't map registers\n"); - return; + /* Map registers for TSEC1 & TSEC2 if they're not mapped yet. */ + if (oa->oa_iot != tsec_iot) { + tsec_iot = oa->oa_iot; + if (bus_space_map(tsec_iot, oa->oa_offset & 0xffffc000, + 8192, 0, &tsec_ioh)) { + printf(": can't map registers\n"); + return; + } } + + sc->sc_iot = tsec_iot; sc->sc_dmat = oa->oa_dmat; + /* Ethernet Controller registers. */ + bus_space_subregion(tsec_iot, tsec_ioh, oa->oa_offset & 0x3fff, + 3072, &sc->sc_ioh); + + /* MII Management registers. */ + bus_space_subregion(tsec_iot, tsec_ioh, 0, 3072, &sc->sc_mii_ioh); + myetheraddr(sc->sc_lladdr); printf(": address %s\n", ether_sprintf(sc->sc_lladdr)); @@ -459,6 +489,18 @@ tsec_write(struct tsec_softc *sc, bus_addr_t addr, uint32_t data) bus_space_write_4(sc->sc_iot, sc->sc_ioh, addr, htole32(data)); } +uint32_t +tsec_mii_read(struct tsec_softc *sc, bus_addr_t addr) +{ + return (letoh32(bus_space_read_4(sc->sc_iot, sc->sc_mii_ioh, addr))); +} + +void +tsec_mii_write(struct tsec_softc *sc, bus_addr_t addr, uint32_t data) +{ + bus_space_write_4(sc->sc_iot, sc->sc_mii_ioh, addr, htole32(data)); +} + void tsec_lladdr_write(struct tsec_softc *sc) { @@ -599,13 +641,13 @@ tsec_mii_readreg(struct device *self, int phy, int reg) uint32_t v; int n; - tsec_write(sc, TSEC_MIIMADD, (phy << 8) | reg); - tsec_write(sc, TSEC_MIIMCOM, 0); - tsec_write(sc, TSEC_MIIMCOM, TSEC_MIIMCOM_READ); + tsec_mii_write(sc, TSEC_MIIMADD, (phy << 8) | reg); + tsec_mii_write(sc, TSEC_MIIMCOM, 0); + tsec_mii_write(sc, TSEC_MIIMCOM, TSEC_MIIMCOM_READ); for (n = 0; n < 100; n++) { - v = tsec_read(sc, TSEC_MIIMIND); + v = tsec_mii_read(sc, TSEC_MIIMIND); if ((v & (TSEC_MIIMIND_NOTVALID | TSEC_MIIMIND_BUSY)) == 0) - return (tsec_read(sc, TSEC_MIIMSTAT)); + return (tsec_mii_read(sc, TSEC_MIIMSTAT)); delay(10); } @@ -620,10 +662,10 @@ tsec_mii_writereg(struct device *self, int phy, int reg, int val) uint32_t v; int n; - tsec_write(sc, TSEC_MIIMADD, (phy << 8) | reg); - tsec_write(sc, TSEC_MIIMCON, val); + tsec_mii_write(sc, TSEC_MIIMADD, (phy << 8) | reg); + tsec_mii_write(sc, TSEC_MIIMCON, val); for (n = 0; n < 100; n++) { - v = tsec_read(sc, TSEC_MIIMIND); + v = tsec_mii_read(sc, TSEC_MIIMIND); if ((v & TSEC_MIIMIND_BUSY) == 0) return; delay(10); |