auto detect the size of the seeprom; from freebsd (from NetBSD (from Linux?))
authorjason <jason@openbsd.org>
Thu, 30 Mar 2000 02:49:35 +0000 (02:49 +0000)
committerjason <jason@openbsd.org>
Thu, 30 Mar 2000 02:49:35 +0000 (02:49 +0000)
sys/dev/pci/if_fxp.c
sys/dev/pci/if_fxpvar.h

index b59b729..79402d1 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: if_fxp.c,v 1.24 2000/01/09 22:36:46 jason Exp $       */
+/*     $OpenBSD: if_fxp.c,v 1.25 2000/03/30 02:49:35 jason Exp $       */
 /*     $NetBSD: if_fxp.c,v 1.2 1997/06/05 02:01:55 thorpej Exp $       */
 
 /*
@@ -209,6 +209,7 @@ static void fxp_watchdog    __P((struct ifnet *));
 static int fxp_add_rfabuf      __P((struct fxp_softc *, struct mbuf *));
 static int fxp_mdi_read                __P((struct device *, int, int));
 static void fxp_mdi_write      __P((struct device *, int, int, int));
+static void fxp_autosize_eeprom        __P((struct fxp_softc *));
 static void fxp_statchg                __P((struct device *));
 static void fxp_read_eeprom    __P((struct fxp_softc *, u_int16_t *,
                                    int, int));
@@ -745,6 +746,11 @@ fxp_attach_common(sc, enaddr)
                }
        }
 
+       /*
+        * Find out how large of an SEEPROM we have.
+        */
+       fxp_autosize_eeprom(sc);
+
        /*
         * Get info about the primary PHY
         */
@@ -752,7 +758,6 @@ fxp_attach_common(sc, enaddr)
        sc->phy_primary_addr = data & 0xff;
        sc->phy_primary_device = (data >> 8) & 0x3f;
        sc->phy_10Mbps_only = data >> 15;
-       sc->phy_settings = 0;
 
        /*
         * Read MAC address.
@@ -775,6 +780,76 @@ fxp_attach_common(sc, enaddr)
        return (ENOMEM);
 }
 
+/*
+ * From NetBSD:
+ *
+ * Figure out EEPROM size.
+ *
+ * 559's can have either 64-word or 256-word EEPROMs, the 558
+ * datasheet only talks about 64-word EEPROMs, and the 557 datasheet
+ * talks about the existance of 16 to 256 word EEPROMs.
+ *
+ * The only known sizes are 64 and 256, where the 256 version is used
+ * by CardBus cards to store CIS information.
+ *
+ * The address is shifted in msb-to-lsb, and after the last
+ * address-bit the EEPROM is supposed to output a `dummy zero' bit,
+ * after which follows the actual data. We try to detect this zero, by
+ * probing the data-out bit in the EEPROM control register just after
+ * having shifted in a bit. If the bit is zero, we assume we've
+ * shifted enough address bits. The data-out should be tri-state,
+ * before this, which should translate to a logical one.
+ *
+ * Other ways to do this would be to try to read a register with known
+ * contents with a varying number of address bits, but no such
+ * register seem to be available. The high bits of register 10 are 01
+ * on the 558 and 559, but apparently not on the 557.
+ * 
+ * The Linux driver computes a checksum on the EEPROM data, but the
+ * value of this checksum is not very well documented.
+ */
+static void
+fxp_autosize_eeprom(sc)
+       struct fxp_softc *sc;
+{
+       u_int16_t reg;
+       int x;
+
+       CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, FXP_EEPROM_EECS);
+       /*
+        * Shift in read opcode.
+        */
+       for (x = 3; x > 0; x--) {
+               if (FXP_EEPROM_OPC_READ & (1 << (x - 1))) {
+                       reg = FXP_EEPROM_EECS | FXP_EEPROM_EEDI;
+               } else {
+                       reg = FXP_EEPROM_EECS;
+               }
+               CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg);
+               CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL,
+                   reg | FXP_EEPROM_EESK);
+               DELAY(1);
+               CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg);
+               DELAY(1);
+       }
+       /*
+        * Shift in address.
+        * Wait for the dummy zero following a correct address shift.
+        */
+       for (x = 1; x <= 8; x++) {
+               CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, FXP_EEPROM_EECS);
+               CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL,
+                       FXP_EEPROM_EECS | FXP_EEPROM_EESK);
+               DELAY(1);
+               if ((CSR_READ_2(sc, FXP_CSR_EEPROMCONTROL) & FXP_EEPROM_EEDO) == 0)
+                       break;
+               CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, FXP_EEPROM_EECS);
+               DELAY(1);
+       }
+       CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, 0);
+       DELAY(1);
+       sc->eeprom_size = x;
+}
 /*
  * Read from the serial EEPROM. Basically, you manually shift in
  * the read opcode (one bit at a time) and then shift in the address,
@@ -813,7 +888,7 @@ fxp_read_eeprom(sc, data, offset, words)
                /*
                 * Shift in address.
                 */
-               for (x = 6; x > 0; x--) {
+               for (x = sc->eeprom_size; x > 0; x--) {
                        if ((i + offset) & (1 << (x - 1))) {
                                reg = FXP_EEPROM_EECS | FXP_EEPROM_EEDI;
                        } else {
index 1697ffd..e65aa55 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: if_fxpvar.h,v 1.6 1998/09/22 18:58:03 deraadt Exp $   */
+/*     $OpenBSD: if_fxpvar.h,v 1.7 2000/03/30 02:49:35 jason Exp $     */
 /*     $NetBSD: if_fxpvar.h,v 1.1 1997/06/05 02:01:58 thorpej Exp $    */
 
 /*                  
@@ -71,7 +71,7 @@ struct fxp_softc {
        int phy_primary_addr;           /* address of primary PHY */
        int phy_primary_device;         /* device type of primary PHY */
        int phy_10Mbps_only;            /* PHY is 10Mbps-only device */
-       int phy_settings;               /* previous PHY bits */
+       int eeprom_size;                /* size of serial EEPROM */
 };
 
 /* Macros to ease CSR access. */