Subject: kern/22480: SiS900 revision 635+ support
To: None <gnats-bugs@gnats.netbsd.org>
From: Joerg Sonnenberger <joerg@britannica.bec.de>
List: netbsd-bugs
Date: 08/14/2003 11:50:14
>Number: 22480
>Category: kern
>Synopsis: SiS900 revision 635+ support
>Confidential: no
>Severity: critical
>Priority: medium
>Responsible: kern-bug-people
>State: open
>Class: change-request
>Submitter-Id: net
>Arrival-Date: Thu Aug 14 09:52:00 UTC 2003
>Closed-Date:
>Last-Modified:
>Originator: Joerg Sonnenberger
>Release: NetBSD 1.6W 2003/08/12
>Organization:
>Environment:
System: NetBSD britannica 1.6W NetBSD 1.6W (TURTLE.fw) #1: Wed Aug 13 00:23:37 CEST 2003 root@britannica:/home/NetBSD/src/sys/arch/i386/compile/TURTLE.fw i386
Architecture: i386
Machine: i386
>Description:
SiS900 revision 635+ uses a different way to access the MII registers.
The patch adds the necessary support.
>How-To-Repeat:
>Fix:
--- 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)
--- 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
>Release-Note:
>Audit-Trail:
>Unformatted: