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 /sys | |
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.
Diffstat (limited to 'sys')
-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); |