Tulip driver with Macronix Chips
Thomas Sailer
sailer@ife.ee.ethz.ch
Thu Jul 16 09:23:38 1998
This is a multi-part message in MIME format.
--------------9A787127D3AE9C6521455B53
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Here's a patch to make tulip v0.88 (as found in 2.0.35) work
with Macronix MX98713 MAC chips.
Changes basically are:
The original driver assumed MII registers for the 98713 - this is
simply not always true. In fact the "recommended" (by Macronix)
100MB PHY chipset (mx98702/704) does not have a MII interface.
The EEPROM layout is also different.
Macronix seems to distinguish their chips via the top 4 bits
of the PCI revision register, not using the device ID register like
everyone else.
Some registers/bits have to be initialized to magic constants, which
isn't very well documented. One of the better sources of information
to be found is Macronix' diagnostic program source code, which can
be found on their website (in MX-Driver-*.EXE)
Tom
--------------9A787127D3AE9C6521455B53
Content-Type: text/plain; charset=us-ascii; name="tulip.c-v0.88.diff"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline; filename="tulip.c-v0.88.diff"
--- tulip.c.orig Thu Jul 16 11:49:32 1998
+++ tulip.c Thu Jul 16 15:01:53 1998
@@ -235,6 +235,7 @@
http://cesdis.gsfc.nasa.gov/linux/misc/NWay.html
http://www.digital.com (search for current 21*4* datasheets and "21X4 SROM")
http://www.national.com/pf/DP/DP83840.html
+http://www.mxic.com.tw/
IVc. Errata
@@ -278,10 +279,23 @@
#ifndef PCI_VENDOR_ID_MXIC
#define PCI_VENDOR_ID_MXIC 0x10d9
#define PCI_DEVICE_ID_MX98713 0x0512
+#define PCI_DEVICE_ID_MX98713A 0x0531
#define PCI_DEVICE_ID_MX98715 0x0531
#define PCI_DEVICE_ID_MX98725 0x0531
#endif
+/* MXIC (Macronix) NIC chip detection
+
+ Macronix seems to distinguish their chips not via the PCI device ID register,
+ but using the top 4 bits of the PCI revision register
+
+ DevID Rev Chip
+ 0x512 0x0? 98713
+ 0x531 0x1? 98713A
+ 0x531 0x2? 98715, 98715A
+ 0x531 0x3? 98725
+ */
+
/* The rest of these values should never change. */
static void tulip_timer(unsigned long data);
@@ -309,8 +323,13 @@
HAS_MII | HAS_MEDIA_TABLE, t21142_timer },
{ PCI_DEVICE_ID_PNIC_X, "Lite-On 82c168 PNIC", 256, 0x0001ebef,
0, pnic_timer },
- { PCI_DEVICE_ID_MX98713, "Macronix 98713 PMAC", 128, 0x0001ebef,
- HAS_MII | HAS_MEDIA_TABLE, tulip_timer /* Tulip-like! */ },
+ { PCI_DEVICE_ID_MX98713, "Macronix 98713 PMAC", 256, 0x0001ebef,
+ HAS_MII /*| HAS_MEDIA_TABLE*/, tulip_timer /* Tulip-like! */ },
+ /* sailer@ife.ee.ethz.ch:
+ the MX98713 does not seem to have a media table in the EEPROM, cf 98713app.pdf, p10
+ from the chip pinout, the chip does not seem to have general purpose IO pins */
+ { PCI_DEVICE_ID_MX98713A, "Macronix 98713A PMAC", 256, 0x0001ebef,
+ HAS_MEDIA_TABLE, mxic_timer },
{ PCI_DEVICE_ID_MX98715, "Macronix 98715 PMAC", 256, 0x0001ebef,
HAS_MEDIA_TABLE, mxic_timer },
{ PCI_DEVICE_ID_MX98725, "Macronix 98725 PMAC", 256, 0x0001ebef,
@@ -319,7 +338,7 @@
};
/* This matches the table above. */
enum chips { DC21040=0, DC21041=1, DC21140=2, DC21142=3, DC21143=3,
- LC82C168, MX98713, MX98715, MX98725};
+ LC82C168, MX98713, MX98713A, MX98715, MX98725};
static const char * const medianame[] = {
"10baseT", "10base2", "AUI", "100baseTx",
@@ -346,7 +365,7 @@
enum tulip_offsets {
CSR0=0, CSR1=0x08, CSR2=0x10, CSR3=0x18, CSR4=0x20, CSR5=0x28,
CSR6=0x30, CSR7=0x38, CSR8=0x40, CSR9=0x48, CSR10=0x50, CSR11=0x58,
- CSR12=0x60, CSR13=0x68, CSR14=0x70, CSR15=0x78 };
+ CSR12=0x60, CSR13=0x68, CSR14=0x70, CSR15=0x78, CSR16=0x80 };
/* The bits in the CSR5 status registers, mostly interrupt sources. */
enum status_bits {
@@ -473,7 +492,9 @@
int tulip_probe(struct device *dev)
{
int cards_found = 0;
+ u8 revision;
static int pci_index = 0; /* Static, for multiple probe calls. */
+ static const enum chips mxic_rev[4] = { MX98713, MX98713A, MX98715, MX98725 };
/* Ideally we would detect all network cards in slot order. That would
be best done a central PCI probe dispatch, which wouldn't work
@@ -511,12 +532,22 @@
continue;
if (vendor == PCI_VENDOR_ID_LITEON)
device = PCI_DEVICE_ID_PNIC_X;
- else if (vendor == PCI_VENDOR_ID_MXIC)
- device = PCI_DEVICE_ID_MX98713;
- for (chip_idx = 0; tulip_tbl[chip_idx].chip_name; chip_idx++)
- if (device == tulip_tbl[chip_idx].device_id)
- break;
+ if (vendor == PCI_VENDOR_ID_MXIC) {
+ /* read chip revision, needed for Macronix */
+ pcibios_read_config_byte(pci_bus, pci_device_fn, PCI_REVISION_ID, &revision);
+ if (revision >= 0x40) {
+ printk(KERN_INFO "Unknown Macronix PCI ethernet chip revision %2.2x "
+ "detected: not configured.\n", revision);
+ continue;
+ }
+ chip_idx = mxic_rev[(revision >> 4) & 0xf];
+ } else {
+ for (chip_idx = 0; tulip_tbl[chip_idx].chip_name; chip_idx++)
+ if (device == tulip_tbl[chip_idx].device_id)
+ break;
+ }
+
if (tulip_tbl[chip_idx].chip_name == 0) {
printk(KERN_INFO "Unknown Tulip-style PCI ethernet chip type"
" %4.4x %4.4x"" detected: not configured.\n",
@@ -572,6 +603,30 @@
return cards_found ? 0 : -ENODEV;
}
+/* the Macronix CRC routine is stolen from their diagnostic
+ application source code and improved by Thomas Sailer, sailer@ife.ee.ethz.ch */
+
+#define MXIC_CRC_POLY 0x04c11db7
+
+static int mxic_check_crc(const u8 *eedata)
+{
+ unsigned long crc = ~0;
+ unsigned int i, j, k;
+ u8 ch;
+
+ for (i = 0; i < 128; i++) {
+ ch = eedata[i];
+ for (j = 0; j < 8; j++, ch >>= 1) {
+ k = (crc >> 31) ^ ch;
+ crc <<= 1;
+ if (k & 1)
+ crc ^= MXIC_CRC_POLY;
+ }
+ }
+ return ((crc & 0xffff) == 0x647d);
+}
+
+
static struct device *tulip_probe1(int pci_bus, int pci_device_fn,
struct device *dev, int ioaddr,
int chip_id, int board_idx)
@@ -584,6 +639,7 @@
u8 pci_irq_line;
int i;
unsigned short sum;
+ unsigned char ee_data[128];
if (tulip_debug > 0 && did_version++ == 0)
printk(KERN_INFO "%s", version);
@@ -634,12 +690,29 @@
((u16*)dev->dev_addr)[i] = value;
sum += value & 0xffff;
}
+ } else if (chip_id == MX98713 || chip_id == MX98713A ||
+ chip_id == MX98715 || chip_id == MX98725) {
+ unsigned int sa_offset = 0;
+
+ for (i = 0; i < sizeof(ee_data)/2; i++)
+ ((u16 *)ee_data)[i] = read_eeprom(ioaddr, i);
+ if (!mxic_check_crc(ee_data))
+ printk(" (Macronix EEPROM CRC error!)");
+ /* extract SA addr */
+ sa_offset = ee_data[0x70];
+ if (sa_offset > 0x1a) {
+ printk(" (Macronix SA index out of range %02x)", sa_offset);
+ sa_offset = 0;
+ }
+ for (i = 0; i < 6; i ++) {
+ dev->dev_addr[i] = ee_data[i + sa_offset];
+ sum += dev->dev_addr[i];
+ }
} else { /* Must be a new chip, with a serial EEPROM interface. */
/* We read the whole EEPROM, and sort it out later. DEC has a
specification _Digital Semiconductor 21X4 Serial ROM Format_
but early vendor boards just put the address in the first six
EEPROM locations. */
- unsigned char ee_data[128];
int sa_offset = 0;
for (i = 0; i < sizeof(ee_data)/2; i++)
@@ -818,10 +891,18 @@
outl(0x0001F078, ioaddr + 0xB8);
outl(0x0201F078, ioaddr + 0xB8); /* Turn on autonegotiation. */
break;
- case MX98713: case MX98715: case MX98725:
+ case MX98713:
+ memcpy(tp->eeprom, ee_data, sizeof(tp->eeprom));
+ /* initialize CSR16, the magic packet/test register */
+ outl(ee_data[0x73] ? 0xf37fec8 : 0xf3ffec8, ioaddr + CSR16);
+ break;
+ case MX98713A: case MX98715: case MX98725:
+ memcpy(tp->eeprom, ee_data, sizeof(tp->eeprom));
outl(0x00000000, ioaddr + CSR6);
outl(0x000711C0, ioaddr + CSR14); /* Turn on NWay. */
outl(0x00000001, ioaddr + CSR13);
+ /* initialize CSR16, the magic packet/test register */
+ outl(0xb3cfec8, ioaddr + CSR16);
break;
}
@@ -1498,6 +1579,15 @@
outl(FULL_DUPLEX_MAGIC, ioaddr + CSR11);
outl(0x00000000, ioaddr + CSR13); /* Reset the serial interface */
outl(dev->if_port ? 0x0000000C : 0x00000004, ioaddr + CSR13);
+ } else if (tp->chip_id == MX98713) {
+ new_csr6 = tp->eeprom[0x72] ? 0xc0000 : 0x18c0000;
+ } else if (tp->chip_id == MX98713A || tp->chip_id == MX98715 || tp->chip_id == MX98725) {
+ new_csr6 = 0x1a80000; /* auto */
+ outl(0xffffffff, dev->base_addr + CSR14);
+
+ /*new_csr6 = 0x1ac0000; 100 */
+ /*new_csr6 = 0x1a80000; 10 */
+ /* outl(0xffffff7f, dev->base_addr + CSR14); */
} else { /* Unknown chip type with no media table. */
if (tp->default_port == 0)
if (tp->mii_cnt) {
--------------9A787127D3AE9C6521455B53--