📄 tulip.c
字号:
outl(inl(ioaddr + CSR6) | 0x0200, ioaddr + CSR6); outl(0x0000EF05, ioaddr + CSR13); break; case DC21040: outl(0x00000000, ioaddr + CSR13); outl(0x00000004, ioaddr + CSR13); break; case DC21140: default: if (tp->mtable) outl(tp->mtable->csr12dir | 0x100, ioaddr + CSR12); break; case DC21142: outl(0x82420200, ioaddr + CSR6); outl(0x0001, ioaddr + CSR13); outl(0x0003FFFF, ioaddr + CSR14); outl(0x0008, ioaddr + CSR15); outl(0x0001, ioaddr + CSR13); outl(0x1301, ioaddr + CSR12); /* Start NWay. */ break; case LC82C168: if ( ! tp->mii_cnt) { outl(0x00420000, ioaddr + CSR6); outl(0x30, ioaddr + CSR12); outl(0x0001F078, ioaddr + 0xB8); outl(0x0201F078, ioaddr + 0xB8); /* Turn on autonegotiation. */ } break; case MX98713: case MX98715: case MX98725: outl(0x00000000, ioaddr + CSR6); outl(0x000711C0, ioaddr + CSR14); /* Turn on NWay. */ outl(0x00000001, ioaddr + CSR13); break; } return dev;}/* Serial EEPROM section. *//* The main routine to parse the very complicated SROM structure. Search www.digital.com for "21X4 SROM" to get details. This code is very complex, and will require changes to support additional cards, so I'll be verbose about what is going on. *//* Known cards that have old-style EEPROMs. */static struct fixups { char *name; unsigned char addr0, addr1, addr2; u16 newtable[32]; /* Max length below. */} eeprom_fixups[] = { {"Asante", 0, 0, 0x94, {0x1e00, 0x0000, 0x0800, 0x0100, 0x018c, 0x0000, 0x0000, 0xe078, 0x0001, 0x0050, 0x0018 }}, {"SMC9332DST", 0, 0, 0xC0, { 0x1e00, 0x0000, 0x0800, 0x021f, 0x0000, 0x009E, /* 10baseT */ 0x0903, 0x006D, /* 100baseTx */ }}, {"Cogent EM100", 0, 0, 0x92, { 0x1e00, 0x0000, 0x0800, 0x033f, 0x0107, 0x8021, /* 100baseFx */ 0x0108, 0x8021, /* 100baseFx-FD */ 0x0103, 0x006D, /* 100baseTx */ }}, {"Maxtech NX-110", 0, 0, 0xE8, { 0x1e00, 0x0000, 0x0800, 0x0313, 0x1001, 0x009E, /* 10base2, CSR12 0x10*/ 0x0000, 0x009E, /* 10baseT */ 0x0303, 0x006D, /* 100baseTx, CSR12 0x03 */ }}, {"Accton EN1207", 0, 0, 0xE8, { 0x1e00, 0x0000, 0x0800, 0x031F, 0x1B01, 0x0000, /* 10base2, CSR12 0x1B */ 0x1B03, 0x006D, /* 100baseTx, CSR12 0x1B */ 0x0B00, 0x009E, /* 10baseT, CSR12 0x0B */ }}, {0, 0, 0, 0, {}}};static const char * block_name[] = {"21140 non-MII", "21140 MII PHY", "21142 Serial PHY", "21142 MII PHY", "21143 SYM PHY", "21143 reset method"};#define EEPROM_SIZE 128#if defined(__i386__)#define get_u16(ptr) (*(u16 *)(ptr))#else#define get_u16(ptr) (((u8*)(ptr))[0] + (((u8*)(ptr))[1]<<8))#endifstatic void parse_eeprom(struct device *dev){ /* The last media info list parsed, for multiport boards. */ static struct mediatable *last_mediatable = NULL; static unsigned char *last_ee_data = NULL; static int controller_index = 0; struct tulip_private *tp = (struct tulip_private *)dev->priv; long ioaddr = dev->base_addr; unsigned char *ee_data = tp->eeprom; int i; tp->mtable = 0; for (i = 0; i < EEPROM_SIZE/2; i++) ((u16 *)ee_data)[i] = read_eeprom(ioaddr, i); /* Detect an old-style (SA only) EEPROM layout: memcmp(eedata, eedata+16, 8). */ for (i = 0; i < 8; i ++) if (ee_data[i] != ee_data[16+i]) break; if (i >= 8) { if (ee_data[0] == 0xff) { if (last_mediatable) { controller_index++; printk(KERN_INFO "%s: Controller %d of multiport board.\n", dev->name, controller_index); tp->mtable = last_mediatable; ee_data = last_ee_data; goto subsequent_board; } else printk(KERN_INFO "%s: Missing EEPROM, this interface may " "not work correctly!\n", dev->name); return; } /* Do a fix-up based on the vendor half of the station address prefix. */ for (i = 0; eeprom_fixups[i].name; i++) { if (dev->dev_addr[0] == eeprom_fixups[i].addr0 && dev->dev_addr[1] == eeprom_fixups[i].addr1 && dev->dev_addr[2] == eeprom_fixups[i].addr2) { if (dev->dev_addr[2] == 0xE8 && ee_data[0x1a] == 0x55) i++; /* An Accton EN1207, not an outlaw Maxtech. */ memcpy(ee_data + 26, eeprom_fixups[i].newtable, sizeof(eeprom_fixups[i].newtable)); printk(KERN_INFO "%s: Old format EEPROM on '%s' board. Using" " substitute media control info.\n", dev->name, eeprom_fixups[i].name); break; } } if (eeprom_fixups[i].name == NULL) { /* No fixup found. */ printk(KERN_INFO "%s: Old style EEPROM -- no media selection information.\n", dev->name); return; } } if (tulip_debug > 1) { printk(KERN_DEBUG "read_eeprom:"); for (i = 0; i < 64; i++) { printk("%s%4.4x", (i & 7) == 0 ? "\n" KERN_DEBUG : " ", read_eeprom(ioaddr, i)); } printk("\n"); } controller_index = 0; if (ee_data[19] > 1) { /* Multiport board. */ last_ee_data = ee_data; }subsequent_board: if (ee_data[27] == 0) { /* No valid media table. */ } else if (tp->chip_id == DC21041) { unsigned char *p = (void *)ee_data + ee_data[27 + controller_index*3]; short media; int count; media = get_u16(p); p += 2; count = *p++; printk(KERN_INFO "%s:21041 Media information at %d, default media " "%4.4x (%s).\n", dev->name, ee_data[27], media, media & 0x0800 ? "Autosense" : medianame[media & 15]); for (i = 0; i < count; i++) { unsigned char media_code = *p++; u16 csrvals[3]; int idx; for (idx = 0; idx < 3; idx++) { csrvals[idx] = get_u16(p); p += 2; } if (media_code & 0x40) { printk(KERN_INFO "%s: 21041 media %2.2x (%s)," " csr13 %4.4x csr14 %4.4x csr15 %4.4x.\n", dev->name, media_code & 15, medianame[media_code & 15], csrvals[0], csrvals[1], csrvals[2]); } else printk(KERN_INFO "%s: 21041 media #%d, %s.\n", dev->name, media_code & 15, medianame[media_code & 15]); } } else { unsigned char *p = (void *)ee_data + ee_data[27]; unsigned char csr12dir = 0; int count; struct mediatable *mtable; u16 media = get_u16(p); p += 2; if (tulip_tbl[tp->chip_id].flags & CSR12_IN_SROM) csr12dir = *p++; count = *p++; mtable = (struct mediatable *) kmalloc(sizeof(struct mediatable) + count*sizeof(struct medialeaf), GFP_KERNEL); if (mtable == NULL) return; /* Horrible, impossible failure. */ last_mediatable = tp->mtable = mtable; mtable->defaultmedia = media; mtable->leafcount = count; mtable->csr12dir = csr12dir; mtable->has_nonmii = mtable->has_mii = 0; printk(KERN_INFO "%s: EEPROM default media type %s.\n", dev->name, media & 0x0800 ? "Autosense" : medianame[media & 15]); for (i = 0; i < count; i++) { struct medialeaf *leaf = &mtable->mleaf[i]; if ((p[0] & 0x80) == 0) { /* 21140 Compact block. */ leaf->type = 0; leaf->media = p[0] & 0x3f; leaf->leafdata = p; if ((p[2] & 0x61) == 0x01) /* Bogus, but Znyx boards do it. */ mtable->has_mii = 1; p += 4; } else { leaf->type = p[1]; if (p[1] & 1) { mtable->has_mii = 1; leaf->media = 11; } else { mtable->has_nonmii = 1; leaf->media = p[2] & 0x0f; } leaf->leafdata = p + 2; p += (p[0] & 0x3f) + 1; } if (tulip_debug > 1 && leaf->media == 11) { unsigned char *bp = leaf->leafdata; printk(KERN_INFO "%s: MII interface PHY %d, setup/reset " "sequences %d/%d long, capabilities %2.2x %2.2x.\n", dev->name, bp[0], bp[1], bp[1 + bp[1]*2], bp[5 + bp[2 + bp[1]*2]*2], bp[4 + bp[2 + bp[1]*2]*2]); } printk(KERN_INFO "%s: Index #%d - Media %s (#%d) described " "by a %s (%d) block.\n", dev->name, i, medianame[leaf->media], leaf->media, block_name[leaf->type], leaf->type); } }}/* Reading a serial EEPROM is a "bit" grungy, but we work our way through:->.*//* EEPROM_Ctrl bits. */#define EE_SHIFT_CLK 0x02 /* EEPROM shift clock. */#define EE_CS 0x01 /* EEPROM chip select. */#define EE_DATA_WRITE 0x04 /* EEPROM chip data in. */#define EE_WRITE_0 0x01#define EE_WRITE_1 0x05#define EE_DATA_READ 0x08 /* EEPROM chip data out. */#define EE_ENB (0x4800 | EE_CS)/* Delay between EEPROM clock transitions. The 1.2 code is a "nasty" timing loop, but PC compatible machines are *supposed* to delay an ISA-compatible period for the SLOW_DOWN_IO macro. */#ifdef _LINUX_DELAY_H#define eeprom_delay(nanosec) udelay((nanosec + 999)/1000)#else#define eeprom_delay(nanosec) do { int _i = 3; while (--_i > 0) { __SLOW_DOWN_IO; }} while (0)#endif/* The EEPROM commands include the alway-set leading bit. */#define EE_WRITE_CMD (5 << 6)#define EE_READ_CMD (6 << 6)#define EE_ERASE_CMD (7 << 6)static int read_eeprom(long ioaddr, int location){ int i; unsigned short retval = 0; long ee_addr = ioaddr + CSR9; int read_cmd = location | EE_READ_CMD; outl(EE_ENB & ~EE_CS, ee_addr); outl(EE_ENB, ee_addr); /* Shift the read command bits out. */ for (i = 10; i >= 0; i--) { short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0; outl(EE_ENB | dataval, ee_addr); eeprom_delay(100); outl(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr); eeprom_delay(150); outl(EE_ENB | dataval, ee_addr); /* Finish EEPROM a clock tick. */ eeprom_delay(250); } outl(EE_ENB, ee_addr); for (i = 16; i > 0; i--) { outl(EE_ENB | EE_SHIFT_CLK, ee_addr); eeprom_delay(100); retval = (retval << 1) | ((inl(ee_addr) & EE_DATA_READ) ? 1 : 0); outl(EE_ENB, ee_addr); eeprom_delay(100); } /* Terminate the EEPROM access. */ outl(EE_ENB & ~EE_CS, ee_addr); return retval;}/* MII transceiver control section. Read and write the MII registers using software-generated serial MDIO protocol. See the MII specifications or DP83840A data sheet for details. *//* The maximum data clock rate is 2.5 Mhz. The minimum timing is usually met by back-to-back PCI I/O cycles, but we insert a delay to avoid "overclocking" issues or future 66Mhz PCI. */#define mdio_delay() inl(mdio_addr)/* Read and write the MII registers using software-generated serial MDIO protocol. It is just different enough from the EEPROM protocol to not share code. The maxium data clock rate is 2.5 Mhz. */#define MDIO_SHIFT_CLK 0x10000#define MDIO_DATA_WRITE0 0x00000#define MDIO_DATA_WRITE1 0x20000#define MDIO_ENB 0x00000 /* Ignore the 0x02000 databook setting. */#define MDIO_ENB_IN 0x40000#define MDIO_DATA_READ 0x80000static int mdio_read(struct device *dev, int phy_id, int location){ struct tulip_private *tp = (struct tulip_private *)dev->priv; int i; int read_cmd = (0xf6 << 10) | (phy_id << 5) | location; int retval = 0; long mdio_addr = dev->base_addr + CSR9; if (tp->chip_id == LC82C168) { long ioaddr = dev->base_addr; int i = 1000; outl(0x60020000 + (phy_id<<23) + (location<<18), ioaddr + 0xA0); while (--i > 0) if ( ! ((retval = inl(ioaddr + 0xA0)) & 0x80000000)) return retval & 0xffff; return 0xffff; } /* Establish sync by sending at least 32 logic ones. */ for (i = 32; i >= 0; i--) { outl(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr); mdio_delay(); outl(MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr); mdio_delay(); } /* Shift the read command bits out. */ for (i = 15; i >= 0; i--) { int dataval = (read_cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0; outl(MDIO_ENB | dataval, mdio_addr); mdio_delay(); outl(MDIO_ENB | dataval | MDIO_SHIFT_CLK, mdio_addr); mdio_delay(); } /* Read the two transition, 16 data, and wire-idle bits. */ for (i = 19; i > 0; i--) { outl(MDIO_ENB_IN, mdio_addr); mdio_delay(); retval = (retval << 1) | ((inl(mdio_addr) & MDIO_DATA_READ) ? 1 : 0); outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr); mdio_delay(); } return (retval>>1) & 0xffff;}static void mdio_write(struct device *dev, int phy_id, int location, int value){ struct tulip_private *tp = (struct tulip_private *)dev->priv; int i; int cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value; long mdio_addr = dev->base_addr + CSR9; if (tp->chip_id == LC82C168) { long ioaddr = dev->base_addr; int i = 1000; outl(cmd, ioaddr + 0xA0); do if ( ! (inl(ioaddr + 0xA0) & 0x80000000)) break; while (--i > 0); return; } /* Establish sync by sending 32 logic ones. */ for (i = 32; i >= 0; i--) { outl(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr); mdio_delay(); outl(MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr); mdio_delay(); } /* Shift the command bits out. */ for (i = 31; i >= 0; i--) { int dataval = (cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0; outl(MDIO_ENB | dataval, mdio_addr); mdio_delay();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -