summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/mii/icsphy.c24
-rw-r--r--sys/dev/pci/if_sis.c300
-rw-r--r--sys/dev/pci/if_sisreg.h23
3 files changed, 300 insertions, 47 deletions
diff --git a/sys/dev/mii/icsphy.c b/sys/dev/mii/icsphy.c
index e9e9dded289..1c955a85ab5 100644
--- a/sys/dev/mii/icsphy.c
+++ b/sys/dev/mii/icsphy.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: icsphy.c,v 1.10 2003/02/19 10:12:55 miod Exp $ */
+/* $OpenBSD: icsphy.c,v 1.11 2003/07/09 02:09:08 krw Exp $ */
/* $NetBSD: icsphy.c,v 1.17 2000/02/02 23:34:56 thorpej Exp $ */
/*-
@@ -136,16 +136,22 @@ icsphyattach(parent, self, aux)
struct mii_softc *sc = (struct mii_softc *)self;
struct mii_attach_args *ma = aux;
struct mii_data *mii = ma->mii_data;
+ char *model = "?";
- if (MII_OUI(ma->mii_id1, ma->mii_id2) == MII_OUI_xxICS &&
- MII_MODEL(ma->mii_id2) == MII_MODEL_xxICS_1890)
- printf(": %s, rev. %d\n", MII_STR_xxICS_1890,
- MII_REV(ma->mii_id2));
+ if (MII_OUI(ma->mii_id1, ma->mii_id2) == MII_OUI_xxICS)
+ switch (MII_MODEL(ma->mii_id2)) {
+ case MII_MODEL_xxICS_1890:
+ model = MII_STR_xxICS_1890;
+ break;
+ case MII_MODEL_xxICS_1892:
+ model = MII_STR_xxICS_1892;
+ break;
+ case MII_MODEL_xxICS_1893:
+ model = MII_STR_xxICS_1893;
+ break;
+ }
- if (MII_OUI(ma->mii_id1, ma->mii_id2) == MII_OUI_xxICS &&
- MII_MODEL(ma->mii_id2) == MII_MODEL_xxICS_1892)
- printf(": %s, rev. %d\n", MII_STR_xxICS_1892,
- MII_REV(ma->mii_id2));
+ printf(": %s, rev. %d\n", model, MII_REV(ma->mii_id2));
sc->mii_inst = mii->mii_instance;
sc->mii_phy = ma->mii_phyno;
diff --git a/sys/dev/pci/if_sis.c b/sys/dev/pci/if_sis.c
index 3af3d25d31d..561db236e7e 100644
--- a/sys/dev/pci/if_sis.c
+++ b/sys/dev/pci/if_sis.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_sis.c,v 1.32 2003/06/30 02:52:09 avsm Exp $ */
+/* $OpenBSD: if_sis.c,v 1.33 2003/07/09 02:09:08 krw Exp $ */
/*
* Copyright (c) 1997, 1998, 1999
* Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved.
@@ -133,6 +133,10 @@ void sis_read_cmos(struct sis_softc *, struct pci_attach_args *, caddr_t, int, i
void sis_read_mac(struct sis_softc *, struct pci_attach_args *);
void sis_read_eeprom(struct sis_softc *, caddr_t, int, int, int);
+void sis_mii_sync(struct sis_softc *);
+void sis_mii_send(struct sis_softc *, u_int32_t, int);
+int sis_mii_readreg(struct sis_softc *, struct sis_mii_frame *);
+int sis_mii_writereg(struct sis_softc *, struct sis_mii_frame *);
int sis_miibus_readreg(struct device *, int, int);
void sis_miibus_writereg(struct device *, int, int, int);
void sis_miibus_statchg(struct device *);
@@ -358,12 +362,197 @@ void sis_read_mac(sc, pa)
SIS_SETBIT(sc, SIS_RXFILT_CTL, SIS_RXFILTCTL_ENABLE);
}
+/*
+ * Sync the PHYs by setting data bit and strobing the clock 32 times.
+ */
+void sis_mii_sync(sc)
+ struct sis_softc *sc;
+{
+ register int i;
+
+ SIO_SET(SIS_MII_DIR|SIS_MII_DATA);
+
+ for (i = 0; i < 32; i++) {
+ SIO_SET(SIS_MII_CLK);
+ DELAY(1);
+ SIO_CLR(SIS_MII_CLK);
+ DELAY(1);
+ }
+
+ return;
+}
+
+/*
+ * Clock a series of bits through the MII.
+ */
+void sis_mii_send(sc, bits, cnt)
+ struct sis_softc *sc;
+ u_int32_t bits;
+ int cnt;
+{
+ int i;
+
+ SIO_CLR(SIS_MII_CLK);
+
+ for (i = (0x1 << (cnt - 1)); i; i >>= 1) {
+ if (bits & i) {
+ SIO_SET(SIS_MII_DATA);
+ } else {
+ SIO_CLR(SIS_MII_DATA);
+ }
+ DELAY(1);
+ SIO_CLR(SIS_MII_CLK);
+ DELAY(1);
+ SIO_SET(SIS_MII_CLK);
+ }
+}
+
+/*
+ * Read an PHY register through the MII.
+ */
+int sis_mii_readreg(sc, frame)
+ struct sis_softc *sc;
+ struct sis_mii_frame *frame;
+
+{
+ int i, ack, s;
+
+ s = splimp();
+
+ /*
+ * Set up frame for RX.
+ */
+ frame->mii_stdelim = SIS_MII_STARTDELIM;
+ frame->mii_opcode = SIS_MII_READOP;
+ frame->mii_turnaround = 0;
+ frame->mii_data = 0;
+
+ /*
+ * Turn on data xmit.
+ */
+ SIO_SET(SIS_MII_DIR);
+
+ sis_mii_sync(sc);
+
+ /*
+ * Send command/address info.
+ */
+ sis_mii_send(sc, frame->mii_stdelim, 2);
+ sis_mii_send(sc, frame->mii_opcode, 2);
+ sis_mii_send(sc, frame->mii_phyaddr, 5);
+ sis_mii_send(sc, frame->mii_regaddr, 5);
+
+ /* Idle bit */
+ SIO_CLR((SIS_MII_CLK|SIS_MII_DATA));
+ DELAY(1);
+ SIO_SET(SIS_MII_CLK);
+ DELAY(1);
+
+ /* Turn off xmit. */
+ SIO_CLR(SIS_MII_DIR);
+
+ /* Check for ack */
+ SIO_CLR(SIS_MII_CLK);
+ DELAY(1);
+ ack = CSR_READ_4(sc, SIS_EECTL) & SIS_MII_DATA;
+ SIO_SET(SIS_MII_CLK);
+ DELAY(1);
+
+ /*
+ * Now try reading data bits. If the ack failed, we still
+ * need to clock through 16 cycles to keep the PHY(s) in sync.
+ */
+ if (ack) {
+ for(i = 0; i < 16; i++) {
+ SIO_CLR(SIS_MII_CLK);
+ DELAY(1);
+ SIO_SET(SIS_MII_CLK);
+ DELAY(1);
+ }
+ goto fail;
+ }
+
+ for (i = 0x8000; i; i >>= 1) {
+ SIO_CLR(SIS_MII_CLK);
+ DELAY(1);
+ if (!ack) {
+ if (CSR_READ_4(sc, SIS_EECTL) & SIS_MII_DATA)
+ frame->mii_data |= i;
+ DELAY(1);
+ }
+ SIO_SET(SIS_MII_CLK);
+ DELAY(1);
+ }
+
+fail:
+
+ SIO_CLR(SIS_MII_CLK);
+ DELAY(1);
+ SIO_SET(SIS_MII_CLK);
+ DELAY(1);
+
+ splx(s);
+
+ if (ack)
+ return(1);
+ return(0);
+}
+
+/*
+ * Write to a PHY register through the MII.
+ */
+int sis_mii_writereg(sc, frame)
+ struct sis_softc *sc;
+ struct sis_mii_frame *frame;
+
+{
+ int s;
+
+ s = splimp();
+ /*
+ * Set up frame for TX.
+ */
+
+ frame->mii_stdelim = SIS_MII_STARTDELIM;
+ frame->mii_opcode = SIS_MII_WRITEOP;
+ frame->mii_turnaround = SIS_MII_TURNAROUND;
+
+ /*
+ * Turn on data output.
+ */
+ SIO_SET(SIS_MII_DIR);
+
+ sis_mii_sync(sc);
+
+ sis_mii_send(sc, frame->mii_stdelim, 2);
+ sis_mii_send(sc, frame->mii_opcode, 2);
+ sis_mii_send(sc, frame->mii_phyaddr, 5);
+ sis_mii_send(sc, frame->mii_regaddr, 5);
+ sis_mii_send(sc, frame->mii_turnaround, 2);
+ sis_mii_send(sc, frame->mii_data, 16);
+
+ /* Idle bit. */
+ SIO_SET(SIS_MII_CLK);
+ DELAY(1);
+ SIO_CLR(SIS_MII_CLK);
+ DELAY(1);
+
+ /*
+ * Turn off xmit.
+ */
+ SIO_CLR(SIS_MII_DIR);
+
+ splx(s);
+
+ return(0);
+}
+
int sis_miibus_readreg(self, phy, reg)
struct device *self;
int phy, reg;
{
struct sis_softc *sc = (struct sis_softc *)self;
- int i, val = 0;
+ struct sis_mii_frame frame;
if (sc->sis_type == SIS_TYPE_83815) {
if (phy != 0)
@@ -380,41 +569,60 @@ int sis_miibus_readreg(self, phy, reg)
*/
if (!CSR_READ_4(sc, NS_BMSR))
DELAY(1000);
- val = CSR_READ_4(sc, NS_BMCR + (reg * 4));
- return(val);
+ return CSR_READ_4(sc, NS_BMCR + (reg * 4));
}
+ /*
+ * Chipsets < SIS_635 seem not to be able to read/write
+ * through mdio. Use the enhanced PHY access register
+ * again for them.
+ */
if (sc->sis_type == SIS_TYPE_900 &&
- sc->sis_rev < SIS_REV_635 && phy != 0)
- return(0);
+ sc->sis_rev < SIS_REV_635) {
+ int i, val = 0;
- CSR_WRITE_4(sc, SIS_PHYCTL, (phy << 11) | (reg << 6) | SIS_PHYOP_READ);
- SIS_SETBIT(sc, SIS_PHYCTL, SIS_PHYCTL_ACCESS);
+ if (phy != 0)
+ return(0);
- for (i = 0; i < SIS_TIMEOUT; i++) {
- if (!(CSR_READ_4(sc, SIS_PHYCTL) & SIS_PHYCTL_ACCESS))
- break;
- }
+ CSR_WRITE_4(sc, SIS_PHYCTL,
+ (phy << 11) | (reg << 6) | SIS_PHYOP_READ);
+ SIS_SETBIT(sc, SIS_PHYCTL, SIS_PHYCTL_ACCESS);
- if (i == SIS_TIMEOUT) {
- printf("%s: PHY failed to come ready\n", sc->sc_dev.dv_xname);
- return(0);
- }
+ for (i = 0; i < SIS_TIMEOUT; i++) {
+ if (!(CSR_READ_4(sc, SIS_PHYCTL) & SIS_PHYCTL_ACCESS))
+ break;
+ }
+
+ if (i == SIS_TIMEOUT) {
+ printf("%s: PHY failed to come ready\n",
+ sc->sc_dev.dv_xname);
+ return(0);
+ }
+
+ val = (CSR_READ_4(sc, SIS_PHYCTL) >> 16) & 0xFFFF;
- val = (CSR_READ_4(sc, SIS_PHYCTL) >> 16) & 0xFFFF;
+ if (val == 0xFFFF)
+ return(0);
+
+ return(val);
+ } else {
+ bzero((char *)&frame, sizeof(frame));
- if (val == 0xFFFF)
- return(0);
+ frame.mii_phyaddr = phy;
+ frame.mii_regaddr = reg;
+ sis_mii_readreg(sc, &frame);
- return(val);
+ return(frame.mii_data);
+ }
}
+
void sis_miibus_writereg(self, phy, reg, data)
struct device *self;
int phy, reg, data;
{
struct sis_softc *sc = (struct sis_softc *)self;
- int i;
+ struct sis_mii_frame frame;
if (sc->sis_type == SIS_TYPE_83815) {
if (phy != 0)
@@ -423,25 +631,43 @@ void sis_miibus_writereg(self, phy, reg, data)
return;
}
- if (sc->sis_type == SIS_TYPE_900 && phy != 0)
- return;
+ /*
+ * Chipsets < SIS_635 seem not to be able to read/write
+ * through mdio. Use the enhanced PHY access register
+ * again for them.
+ */
+ if (sc->sis_type == SIS_TYPE_900 &&
+ sc->sis_rev < SIS_REV_635) {
+ int i;
- CSR_WRITE_4(sc, SIS_PHYCTL, (data << 16) | (phy << 11) |
- (reg << 6) | SIS_PHYOP_WRITE);
- SIS_SETBIT(sc, SIS_PHYCTL, SIS_PHYCTL_ACCESS);
+ if (phy != 0)
+ return;
- for (i = 0; i < SIS_TIMEOUT; i++) {
- if (!(CSR_READ_4(sc, SIS_PHYCTL) & SIS_PHYCTL_ACCESS))
- break;
- }
+ CSR_WRITE_4(sc, SIS_PHYCTL, (data << 16) | (phy << 11) |
+ (reg << 6) | SIS_PHYOP_WRITE);
+ SIS_SETBIT(sc, SIS_PHYCTL, SIS_PHYCTL_ACCESS);
- if (i == SIS_TIMEOUT)
- printf("%s: PHY failed to come ready\n", sc->sc_dev.dv_xname);
+ for (i = 0; i < SIS_TIMEOUT; i++) {
+ if (!(CSR_READ_4(sc, SIS_PHYCTL) & SIS_PHYCTL_ACCESS))
+ break;
+ }
+ if (i == SIS_TIMEOUT)
+ printf("%s: PHY failed to come ready\n",
+ sc->sc_dev.dv_xname);
+ } else {
+ bzero((char *)&frame, sizeof(frame));
+
+ frame.mii_phyaddr = phy;
+ frame.mii_regaddr = reg;
+ frame.mii_data = data;
+ sis_mii_writereg(sc, &frame);
+ }
return;
}
-void sis_miibus_statchg(self)
+void
+sis_miibus_statchg(self)
struct device *self;
{
struct sis_softc *sc = (struct sis_softc *)self;
@@ -676,7 +902,7 @@ void sis_attach(parent, self, aux)
/* Reset the power state. */
printf("%s: chip is in D%d power mode -- setting to D0\n",
- sc->sc_dev.dv_xname, command & SIS_PSTATE_MASK);
+ sc->sc_dev.dv_xname, command & SIS_PSTATE_MASK);
command &= 0xFFFFFFFC;
pci_conf_write(pc, pa->pa_tag, SIS_PCI_PWRMGMTCTRL, command);
@@ -1012,14 +1238,14 @@ int sis_newbuf(sc, c, m)
MGETHDR(m_new, M_DONTWAIT, MT_DATA);
if (m_new == NULL) {
printf("%s: no memory for rx list -- packet dropped!\n",
- sc->sc_dev.dv_xname);
+ sc->sc_dev.dv_xname);
return(ENOBUFS);
}
MCLGET(m_new, M_DONTWAIT);
if (!(m_new->m_flags & M_EXT)) {
printf("%s: no memory for rx list -- packet dropped!\n",
- sc->sc_dev.dv_xname);
+ sc->sc_dev.dv_xname);
m_freem(m_new);
return(ENOBUFS);
}
@@ -1481,7 +1707,7 @@ void sis_init(xsc)
/* Init circular RX list. */
if (sis_list_rx_init(sc) == ENOBUFS) {
printf("%s: initialization failed: no memory for rx buffers\n",
- sc->sc_dev.dv_xname);
+ sc->sc_dev.dv_xname);
sis_stop(sc);
splx(s);
return;
diff --git a/sys/dev/pci/if_sisreg.h b/sys/dev/pci/if_sisreg.h
index 43bf524f640..c47be3299ca 100644
--- a/sys/dev/pci/if_sisreg.h
+++ b/sys/dev/pci/if_sisreg.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_sisreg.h,v 1.12 2003/06/30 02:52:09 avsm Exp $ */
+/* $OpenBSD: if_sisreg.h,v 1.13 2003/07/09 02:09:08 krw Exp $ */
/*
* Copyright (c) 1997, 1998, 1999
* Bill Paul <wpaul@ee.columbia.edu>. All rights reserved.
@@ -120,6 +120,10 @@
#define SIS_EECTL_CLK 0x00000004
#define SIS_EECTL_CSEL 0x00000008
+#define SIS_MII_CLK 0x00000040
+#define SIS_MII_DIR 0x00000020
+#define SIS_MII_DATA 0x00000010
+
#define SIS_EECMD_WRITE 0x140
#define SIS_EECMD_READ 0x180
#define SIS_EECMD_ERASE 0x1c0
@@ -380,6 +384,23 @@ struct sis_type {
char *sis_name;
};
+struct sis_mii_frame {
+ u_int8_t mii_stdelim;
+ u_int8_t mii_opcode;
+ u_int8_t mii_phyaddr;
+ u_int8_t mii_regaddr;
+ u_int8_t mii_turnaround;
+ u_int16_t mii_data;
+};
+
+/*
+ * MII constants
+ */
+#define SIS_MII_STARTDELIM 0x01
+#define SIS_MII_READOP 0x02
+#define SIS_MII_WRITEOP 0x01
+#define SIS_MII_TURNAROUND 0x02
+
#define SIS_TYPE_900 1
#define SIS_TYPE_7016 2
#define SIS_TYPE_83815 3