Subject: SiS 900 revision 635+ support
To: None <tech-kern@netbsd.org>
From: Joerg Sonnenberger <joerg@britannica.bec.de>
List: tech-kern
Date: 08/13/2003 17:47:14
--GvXjxJ+pjyke8COw
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

Hi all,
this is a cleaned version of the patch I sent to current-users@
sometime ago. I didn't recieve any feedback, but I hope this can
be commited.

The patch adds the support for the MII on newer SiS900 revisions.
It has been ported from FreeBSD/OpenBSD. You need this patch if
your SiS chip is detected but no PHY on it.

Regards, Joerg

--GvXjxJ+pjyke8COw
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="if_sip.c.diff"

--- if_sip.c.orig	2003-03-23 01:56:15.000000000 +0100
+++ if_sip.c	2003-08-13 00:22:31.000000000 +0200
@@ -439,6 +439,9 @@
 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 +3045,53 @@
 	bus_space_write_4(sc->sc_st, sc->sc_sh, SIP_EROMAR, val);
 }
 #else /* ! DP83820 */
+
+#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)
 {
@@ -3054,8 +3099,75 @@
 	u_int32_t enphy;
 
 	/*
-	 * The SiS 900 has only an internal PHY on the MII.  Only allow
-	 * MII address 0.
+	 * The SiS 900 revision 635 and later uses a different interface.
+	 */
+	if (sc->sc_model->sip_product == PCI_PRODUCT_SIS_900 &&
+	    sc->sc_rev >= SIS_REV_635) {
+		int i, ack, s;
+		u_int16_t mii_data = 0;
+
+		s = splnet();
+
+		/* 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;
+	}	
+
+	/*
+	 * The SiS 900 before revision 635 has only an internal PHY
+	 * on the MII.  Only allow MII address 0.
 	 */
 	if (sc->sc_model->sip_product == PCI_PRODUCT_SIS_900 &&
 	    sc->sc_rev < SIS_REV_635 && phy != 0)
@@ -3082,8 +3194,39 @@
 	u_int32_t enphy;
 
 	/*
-	 * The SiS 900 has only an internal PHY on the MII.  Only allow
-	 * MII address 0.
+	 * The SiS 900 revision 635 and later uses a different interface.
+	 */
+	if (sc->sc_model->sip_product == PCI_PRODUCT_SIS_900 &&
+	    sc->sc_rev >= SIS_REV_635 && phy != 0) {
+		int s;
+
+		s = splnet();
+
+		/* 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);
+	}
+
+	/*
+	 * The SiS 900 before revision 635 has only an internal PHY
+	 * on the MII.  Only allow MII address 0.
 	 */
 	if (sc->sc_model->sip_product == PCI_PRODUCT_SIS_900 &&
 	    sc->sc_rev < SIS_REV_635 && phy != 0)

--GvXjxJ+pjyke8COw
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="if_sipreg.h.diff"

--- if_sipreg.h.orig	2002-06-30 20:04:12.000000000 +0200
+++ if_sipreg.h	2003-08-13 00:13:35.000000000 +0200
@@ -596,6 +596,17 @@
 #ifndef DP83820
 #define	SIP_NS_PHY(miireg)	/* PHY registers (83815) */		\
 	(0x80 + ((miireg) << 2))
+
+#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
 #endif
 
 #ifdef DP83820

--GvXjxJ+pjyke8COw--