summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Kettenis <kettenis@cvs.openbsd.org>2009-09-14 18:59:21 +0000
committerMark Kettenis <kettenis@cvs.openbsd.org>2009-09-14 18:59:21 +0000
commitc36b8d443f42f4a4764de7307b484c1cb296a58d (patch)
tree168407797ff109e1eed7d12c395d9bd3dd392ea5
parent592cecb5eaa5757f8cfc557492fee691ee046a52 (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.c68
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);