Subject: if_sip patch for newer SIS900 revisions
To: None <current-users@netbsd.org>
From: Joerg Sonnenberger <joerg@britannica.bec.de>
List: current-users
Date: 08/08/2003 21:20:12
--AhhlLboLdkugWU4S
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
Hi all,
attached is a patch against if_sip.c which adds support for
newer SIS chipset revisions. If `ifconfig sip0` gives you
no media type and no PHY is detected on boot, this patch
might (should) fix it. It has been ported from FreeBSD.
The patch needs some additional cleanup, but hopeful some of
you can test it.
Joerg
--AhhlLboLdkugWU4S
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="sis.patch"
--- if_sip.c.orig 2003-08-08 19:29:17.000000000 +0200
+++ if_sip.c 2003-08-08 20:50:56.000000000 +0200
@@ -439,6 +439,8 @@
void SIP_DECL(dp83820_mii_writereg)(struct device *, int, int, int);
void SIP_DECL(dp83820_mii_statchg)(struct device *);
#else
+static void sis900_mii_sync(struct sip_softc *)
+static void sis900_mii_send(struct sip_softc *, u_int32_t, int)
int SIP_DECL(sis900_mii_readreg)(struct device *, int, int);
void SIP_DECL(sis900_mii_writereg)(struct device *, int, int, int);
void SIP_DECL(sis900_mii_statchg)(struct device *);
@@ -3042,11 +3044,64 @@
bus_space_write_4(sc->sc_st, sc->sc_sh, SIP_EROMAR, val);
}
#else /* ! DP83820 */
+
+#define SIS_EECTL 0x08
+
+#define SIS_MII_CLK 0x00000040
+#define SIS_MII_DIR 0x00000020
+#define SIS_MII_DATA 0x00000010
+
+#define SIS_MII_STARTDELIM 0x01
+#define SIS_MII_READOP 0x02
+#define SIS_MII_WRITEOP 0x01
+#define SIS_MII_TURNAROUND 0x02
+
+#define SIO_SET(x) bus_space_write_4(sc->sc_st,sc->sc_sh,SIS_EECTL, \
+ bus_space_read_4(sc->sc_st,sc->sc_sh,SIS_EECTL) | (x))
+#define SIO_CLR(x) bus_space_write_4(sc->sc_st,sc->sc_sh,SIS_EECTL, \
+ bus_space_read_4(sc->sc_st,sc->sc_sh,SIS_EECTL) & ~(x))
+
+static void
+sis900_mii_sync(struct sip_softc *sc)
+{
+ 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);
+ }
+}
+
+static void
+sis900_mii_send(struct sip_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);
+ }
+}
+
/*
* sip_sis900_mii_readreg: [mii interface function]
*
* Read a PHY register on the MII.
*/
+
int
SIP_DECL(sis900_mii_readreg)(struct device *self, int phy, int reg)
{
@@ -3058,16 +3113,80 @@
* MII address 0.
*/
if (sc->sc_model->sip_product == PCI_PRODUCT_SIS_900 &&
- sc->sc_rev < SIS_REV_635 && phy != 0)
- return (0);
+ sc->sc_rev < SIS_REV_635) {
+ if (phy != 0)
+ return (0);
- bus_space_write_4(sc->sc_st, sc->sc_sh, SIP_ENPHY,
- (phy << ENPHY_PHYADDR_SHIFT) | (reg << ENPHY_REGADDR_SHIFT) |
- ENPHY_RWCMD | ENPHY_ACCESS);
- do {
- enphy = bus_space_read_4(sc->sc_st, sc->sc_sh, SIP_ENPHY);
- } while (enphy & ENPHY_ACCESS);
- return ((enphy & ENPHY_PHYDATA) >> ENPHY_DATA_SHIFT);
+ bus_space_write_4(sc->sc_st, sc->sc_sh, SIP_ENPHY,
+ (phy << ENPHY_PHYADDR_SHIFT) | (reg << ENPHY_REGADDR_SHIFT) |
+ ENPHY_RWCMD | ENPHY_ACCESS);
+ do {
+ enphy = bus_space_read_4(sc->sc_st, sc->sc_sh, SIP_ENPHY);
+ } while (enphy & ENPHY_ACCESS);
+ return ((enphy & ENPHY_PHYDATA) >> ENPHY_DATA_SHIFT);
+ }
+ else {
+ int i, ack, s;
+ u_int16_t mii_data = 0;
+
+ s = splvm();
+
+ /* Turn on data xmit. */
+ SIO_SET(SIS_MII_DIR);
+ sis900_mii_sync(sc);
+
+ /* Send command/address info */
+ sis900_mii_send(sc,SIS_MII_STARTDELIM,2);
+ sis900_mii_send(sc,SIS_MII_READOP,2);
+ sis900_mii_send(sc,phy,5);
+ sis900_mii_send(sc,reg,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 = bus_space_read_4(sc->sc_st,sc->sc_sh,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);
+ }
+ } else {
+ for (i = 0x8000; i; i >>= 1) {
+ SIO_CLR(SIS_MII_CLK);
+ DELAY(1);
+ if (bus_space_read_4(sc->sc_st,sc->sc_sh,SIS_EECTL) & SIS_MII_DATA)
+ mii_data |= i;
+ SIO_SET(SIS_MII_CLK);
+ DELAY(1);
+ }
+ }
+
+ SIO_CLR(SIS_MII_CLK);
+ DELAY(1);
+ SIO_SET(SIS_MII_CLK);
+ DELAY(1);
+
+ splx(s);
+ return mii_data;
+ }
}
/*
@@ -3086,15 +3205,42 @@
* MII address 0.
*/
if (sc->sc_model->sip_product == PCI_PRODUCT_SIS_900 &&
- sc->sc_rev < SIS_REV_635 && phy != 0)
- return;
+ sc->sc_rev < SIS_REV_635 && phy != 0) {
+ if (phy != 0)
+ return;
- bus_space_write_4(sc->sc_st, sc->sc_sh, SIP_ENPHY,
- (val << ENPHY_DATA_SHIFT) | (phy << ENPHY_PHYADDR_SHIFT) |
- (reg << ENPHY_REGADDR_SHIFT) | ENPHY_ACCESS);
- do {
- enphy = bus_space_read_4(sc->sc_st, sc->sc_sh, SIP_ENPHY);
- } while (enphy & ENPHY_ACCESS);
+ bus_space_write_4(sc->sc_st, sc->sc_sh, SIP_ENPHY,
+ (val << ENPHY_DATA_SHIFT) | (phy << ENPHY_PHYADDR_SHIFT) |
+ (reg << ENPHY_REGADDR_SHIFT) | ENPHY_ACCESS);
+ do {
+ enphy = bus_space_read_4(sc->sc_st, sc->sc_sh, SIP_ENPHY);
+ } while (enphy & ENPHY_ACCESS);
+ } else {
+ int s;
+
+ s = splvm();
+
+ /* Turn on data output. */
+ SIO_SET(SIS_MII_DIR);
+ sis900_mii_sync(sc);
+ sis900_mii_send(sc,SIS_MII_STARTDELIM,2);
+ sis900_mii_send(sc,SIS_MII_WRITEOP,2);
+ sis900_mii_send(sc,phy,5);
+ sis900_mii_send(sc,reg,5);
+ sis900_mii_send(sc,SIS_MII_TURNAROUND,2);
+ sis900_mii_send(sc,val,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);
+ }
}
/*
--AhhlLboLdkugWU4S--