11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 23396c7823efb3a5b8630388c464e1034ea031cedPaul Gortmaker drivers/net/ethernet/dec/tulip/media.c 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Copyright 2000,2001 The Linux Kernel Team 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Written/copyright 1994-2001 by Donald Becker. 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds This software may be used and distributed according to the terms 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds of the GNU General Public License, incorporated herein by reference. 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1078a655181409d9d0f2b730ccb897c18794826495Grant Grundler Please submit bugs to http://bugzilla.kernel.org/ . 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/ 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h> 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mii.h> 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h> 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/pci.h> 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "tulip.h" 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The maximum data clock rate is 2.5 Mhz. The minimum timing is usually 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds met by back-to-back PCI I/O cycles, but we insert a delay to avoid 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "overclocking" issues or future 66Mhz PCI. */ 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define mdio_delay() ioread32(mdio_addr) 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Read and write the MII registers using software-generated serial 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MDIO protocol. It is just different enough from the EEPROM protocol 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds to not share code. The maxium data clock rate is 2.5 Mhz. */ 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MDIO_SHIFT_CLK 0x10000 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MDIO_DATA_WRITE0 0x00000 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MDIO_DATA_WRITE1 0x20000 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MDIO_ENB 0x00000 /* Ignore the 0x02000 databook setting. */ 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MDIO_ENB_IN 0x40000 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MDIO_DATA_READ 0x80000 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const unsigned char comet_miireg2offset[32] = { 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0xB4, 0xB8, 0xBC, 0xC0, 0xC4, 0xC8, 0xCC, 0, 0,0,0,0, 0,0,0,0, 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0,0xD0,0,0, 0,0,0,0, 0,0,0,0, 0, 0xD4, 0xD8, 0xDC, }; 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* MII transceiver control section. 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Read and write the MII registers using software-generated serial 43b3bff39a2b3574542f5007e19038393dfdd64c85Valerie Henson MDIO protocol. 44b3bff39a2b3574542f5007e19038393dfdd64c85Valerie Henson See IEEE 802.3-2002.pdf (Section 2, Chapter "22.2.4 Management functions") 45b3bff39a2b3574542f5007e19038393dfdd64c85Valerie Henson or DP83840A data sheet for more details. 46b3bff39a2b3574542f5007e19038393dfdd64c85Valerie Henson */ 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint tulip_mdio_read(struct net_device *dev, int phy_id, int location) 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct tulip_private *tp = netdev_priv(dev); 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int read_cmd = (0xf6 << 10) | ((phy_id & 0x1f) << 5) | location; 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval = 0; 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void __iomem *ioaddr = tp->base_addr; 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void __iomem *mdio_addr = ioaddr + CSR9; 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (location & ~0x1f) 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0xffff; 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tp->chip_id == COMET && phy_id == 30) { 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (comet_miireg2offset[location]) 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ioread32(ioaddr + comet_miireg2offset[location]); 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0xffff; 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&tp->mii_lock, flags); 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tp->chip_id == LC82C168) { 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iowrite32(0x60020000 + (phy_id<<23) + (location<<18), ioaddr + 0xA0); 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ioread32(ioaddr + 0xA0); 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ioread32(ioaddr + 0xA0); 72de2f19daac017301b0bfd73bdecff89e7ea30eb7Hannes Eder for (i = 1000; i >= 0; --i) { 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds barrier(); 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ( ! ((retval = ioread32(ioaddr + 0xA0)) & 0x80000000)) 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&tp->mii_lock, flags); 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval & 0xffff; 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Establish sync by sending at least 32 logic ones. */ 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 32; i >= 0; i--) { 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iowrite32(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr); 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mdio_delay(); 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iowrite32(MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr); 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mdio_delay(); 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Shift the read command bits out. */ 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 15; i >= 0; i--) { 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int dataval = (read_cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0; 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iowrite32(MDIO_ENB | dataval, mdio_addr); 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mdio_delay(); 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iowrite32(MDIO_ENB | dataval | MDIO_SHIFT_CLK, mdio_addr); 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mdio_delay(); 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Read the two transition, 16 data, and wire-idle bits. */ 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 19; i > 0; i--) { 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iowrite32(MDIO_ENB_IN, mdio_addr); 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mdio_delay(); 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = (retval << 1) | ((ioread32(mdio_addr) & MDIO_DATA_READ) ? 1 : 0); 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iowrite32(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr); 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mdio_delay(); 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&tp->mii_lock, flags); 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (retval>>1) & 0xffff; 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid tulip_mdio_write(struct net_device *dev, int phy_id, int location, int val) 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct tulip_private *tp = netdev_priv(dev); 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int cmd = (0x5002 << 16) | ((phy_id & 0x1f) << 23) | (location<<18) | (val & 0xffff); 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void __iomem *ioaddr = tp->base_addr; 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void __iomem *mdio_addr = ioaddr + CSR9; 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (location & ~0x1f) 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tp->chip_id == COMET && phy_id == 30) { 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (comet_miireg2offset[location]) 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iowrite32(val, ioaddr + comet_miireg2offset[location]); 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&tp->mii_lock, flags); 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tp->chip_id == LC82C168) { 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iowrite32(cmd, ioaddr + 0xA0); 131de2f19daac017301b0bfd73bdecff89e7ea30eb7Hannes Eder for (i = 1000; i >= 0; --i) { 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds barrier(); 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ( ! (ioread32(ioaddr + 0xA0) & 0x80000000)) 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 135de2f19daac017301b0bfd73bdecff89e7ea30eb7Hannes Eder } 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&tp->mii_lock, flags); 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 139f3b197ac26ed0e57989856494c495818dcc7f9acJeff Garzik 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Establish sync by sending 32 logic ones. */ 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 32; i >= 0; i--) { 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iowrite32(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr); 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mdio_delay(); 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iowrite32(MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr); 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mdio_delay(); 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Shift the command bits out. */ 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 31; i >= 0; i--) { 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int dataval = (cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0; 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iowrite32(MDIO_ENB | dataval, mdio_addr); 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mdio_delay(); 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iowrite32(MDIO_ENB | dataval | MDIO_SHIFT_CLK, mdio_addr); 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mdio_delay(); 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Clear out extra bits. */ 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 2; i > 0; i--) { 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iowrite32(MDIO_ENB_IN, mdio_addr); 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mdio_delay(); 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iowrite32(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr); 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mdio_delay(); 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&tp->mii_lock, flags); 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Set up the transceiver control registers for the selected media type. */ 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid tulip_select_media(struct net_device *dev, int startup) 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct tulip_private *tp = netdev_priv(dev); 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void __iomem *ioaddr = tp->base_addr; 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mediatable *mtable = tp->mtable; 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 new_csr6; 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mtable) { 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct medialeaf *mleaf = &mtable->mleaf[tp->cur_index]; 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char *p = mleaf->leafdata; 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (mleaf->type) { 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0: /* 21140 non-MII xcvr. */ 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tulip_debug > 1) 182726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches netdev_dbg(dev, "Using a 21140 non-MII transceiver with control setting %02x\n", 183726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches p[1]); 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->if_port = p[0]; 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (startup) 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iowrite32(mtable->csr12dir | 0x100, ioaddr + CSR12); 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iowrite32(p[1], ioaddr + CSR12); 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds new_csr6 = 0x02000000 | ((p[2] & 0x71) << 18); 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 2: case 4: { 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u16 setup[5]; 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 csr13val, csr14val, csr15dir, csr15val; 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < 5; i++) 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds setup[i] = get_u16(&p[i*2 + 1]); 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->if_port = p[0] & MEDIA_MASK; 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tulip_media_cap[dev->if_port] & MediaAlwaysFD) 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp->full_duplex = 1; 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (startup && mtable->has_reset) { 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct medialeaf *rleaf = &mtable->mleaf[mtable->has_reset]; 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char *rst = rleaf->leafdata; 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tulip_debug > 1) 204726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches netdev_dbg(dev, "Resetting the transceiver\n"); 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < rst[0]; i++) 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iowrite32(get_u16(rst + 1 + (i<<1)) << 16, ioaddr + CSR15); 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tulip_debug > 1) 209726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches netdev_dbg(dev, "21143 non-MII %s transceiver control %04x/%04x\n", 210726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches medianame[dev->if_port], 211726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches setup[0], setup[1]); 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (p[0] & 0x40) { /* SIA (CSR13-15) setup values are provided. */ 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds csr13val = setup[0]; 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds csr14val = setup[1]; 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds csr15dir = (setup[3]<<16) | setup[2]; 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds csr15val = (setup[4]<<16) | setup[2]; 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iowrite32(0, ioaddr + CSR13); 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iowrite32(csr14val, ioaddr + CSR14); 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iowrite32(csr15dir, ioaddr + CSR15); /* Direction */ 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iowrite32(csr15val, ioaddr + CSR15); /* Data */ 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iowrite32(csr13val, ioaddr + CSR13); 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds csr13val = 1; 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds csr14val = 0; 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds csr15dir = (setup[0]<<16) | 0x0008; 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds csr15val = (setup[1]<<16) | 0x0008; 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dev->if_port <= 4) 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds csr14val = t21142_csr14[dev->if_port]; 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (startup) { 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iowrite32(0, ioaddr + CSR13); 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iowrite32(csr14val, ioaddr + CSR14); 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iowrite32(csr15dir, ioaddr + CSR15); /* Direction */ 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iowrite32(csr15val, ioaddr + CSR15); /* Data */ 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (startup) iowrite32(csr13val, ioaddr + CSR13); 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tulip_debug > 1) 238726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches netdev_dbg(dev, "Setting CSR15 to %08x/%08x\n", 239726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches csr15dir, csr15val); 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mleaf->type == 4) 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds new_csr6 = 0x82020000 | ((setup[2] & 0x71) << 18); 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds new_csr6 = 0x82420000; 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 1: case 3: { 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int phy_num = p[0]; 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int init_length = p[1]; 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u16 *misc_info, tmp_info; 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->if_port = 11; 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds new_csr6 = 0x020E0000; 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mleaf->type == 3) { /* 21142 */ 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u16 *init_sequence = (u16*)(p+2); 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u16 *reset_sequence = &((u16*)(p+3))[init_length]; 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int reset_length = p[2 + init_length*2]; 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds misc_info = reset_sequence + reset_length; 258eb117b1786804f2e128b871879ffe8f6a2701378Thibaut VARENE if (startup) { 259eb117b1786804f2e128b871879ffe8f6a2701378Thibaut VARENE int timeout = 10; /* max 1 ms */ 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < reset_length; i++) 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iowrite32(get_u16(&reset_sequence[i]) << 16, ioaddr + CSR15); 262eb117b1786804f2e128b871879ffe8f6a2701378Thibaut VARENE 263eb117b1786804f2e128b871879ffe8f6a2701378Thibaut VARENE /* flush posted writes */ 264eb117b1786804f2e128b871879ffe8f6a2701378Thibaut VARENE ioread32(ioaddr + CSR15); 265eb117b1786804f2e128b871879ffe8f6a2701378Thibaut VARENE 266eb117b1786804f2e128b871879ffe8f6a2701378Thibaut VARENE /* Sect 3.10.3 in DP83840A.pdf (p39) */ 267eb117b1786804f2e128b871879ffe8f6a2701378Thibaut VARENE udelay(500); 268eb117b1786804f2e128b871879ffe8f6a2701378Thibaut VARENE 269eb117b1786804f2e128b871879ffe8f6a2701378Thibaut VARENE /* Section 4.2 in DP83840A.pdf (p43) */ 270eb117b1786804f2e128b871879ffe8f6a2701378Thibaut VARENE /* and IEEE 802.3 "22.2.4.1.1 Reset" */ 271eb117b1786804f2e128b871879ffe8f6a2701378Thibaut VARENE while (timeout-- && 272eb117b1786804f2e128b871879ffe8f6a2701378Thibaut VARENE (tulip_mdio_read (dev, phy_num, MII_BMCR) & BMCR_RESET)) 273eb117b1786804f2e128b871879ffe8f6a2701378Thibaut VARENE udelay(100); 274eb117b1786804f2e128b871879ffe8f6a2701378Thibaut VARENE } 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < init_length; i++) 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iowrite32(get_u16(&init_sequence[i]) << 16, ioaddr + CSR15); 277eb117b1786804f2e128b871879ffe8f6a2701378Thibaut VARENE 278eb117b1786804f2e128b871879ffe8f6a2701378Thibaut VARENE ioread32(ioaddr + CSR15); /* flush posted writes */ 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 *init_sequence = p + 2; 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 *reset_sequence = p + 3 + init_length; 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int reset_length = p[2 + init_length]; 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds misc_info = (u16*)(reset_sequence + reset_length); 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (startup) { 285b3bff39a2b3574542f5007e19038393dfdd64c85Valerie Henson int timeout = 10; /* max 1 ms */ 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iowrite32(mtable->csr12dir | 0x100, ioaddr + CSR12); 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < reset_length; i++) 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iowrite32(reset_sequence[i], ioaddr + CSR12); 289b3bff39a2b3574542f5007e19038393dfdd64c85Valerie Henson 290b3bff39a2b3574542f5007e19038393dfdd64c85Valerie Henson /* flush posted writes */ 291b3bff39a2b3574542f5007e19038393dfdd64c85Valerie Henson ioread32(ioaddr + CSR12); 292b3bff39a2b3574542f5007e19038393dfdd64c85Valerie Henson 293b3bff39a2b3574542f5007e19038393dfdd64c85Valerie Henson /* Sect 3.10.3 in DP83840A.pdf (p39) */ 294b3bff39a2b3574542f5007e19038393dfdd64c85Valerie Henson udelay(500); 295b3bff39a2b3574542f5007e19038393dfdd64c85Valerie Henson 296b3bff39a2b3574542f5007e19038393dfdd64c85Valerie Henson /* Section 4.2 in DP83840A.pdf (p43) */ 297b3bff39a2b3574542f5007e19038393dfdd64c85Valerie Henson /* and IEEE 802.3 "22.2.4.1.1 Reset" */ 298b3bff39a2b3574542f5007e19038393dfdd64c85Valerie Henson while (timeout-- && 299b3bff39a2b3574542f5007e19038393dfdd64c85Valerie Henson (tulip_mdio_read (dev, phy_num, MII_BMCR) & BMCR_RESET)) 300b3bff39a2b3574542f5007e19038393dfdd64c85Valerie Henson udelay(100); 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < init_length; i++) 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iowrite32(init_sequence[i], ioaddr + CSR12); 304b3bff39a2b3574542f5007e19038393dfdd64c85Valerie Henson 305b3bff39a2b3574542f5007e19038393dfdd64c85Valerie Henson ioread32(ioaddr + CSR12); /* flush posted writes */ 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 307b3bff39a2b3574542f5007e19038393dfdd64c85Valerie Henson 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tmp_info = get_u16(&misc_info[1]); 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tmp_info) 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp->advertising[phy_num] = tmp_info | 1; 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tmp_info && startup < 2) { 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tp->mii_advertise == 0) 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp->mii_advertise = tp->advertising[phy_num]; 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tulip_debug > 1) 315726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches netdev_dbg(dev, " Advertising %04x on MII %d\n", 316726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches tp->mii_advertise, 317726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches tp->phys[phy_num]); 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tulip_mdio_write(dev, tp->phys[phy_num], 4, tp->mii_advertise); 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 5: case 6: { 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u16 setup[5]; 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds new_csr6 = 0; /* FIXME */ 3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < 5; i++) 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds setup[i] = get_u16(&p[i*2 + 1]); 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (startup && mtable->has_reset) { 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct medialeaf *rleaf = &mtable->mleaf[mtable->has_reset]; 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char *rst = rleaf->leafdata; 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tulip_debug > 1) 334726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches netdev_dbg(dev, "Resetting the transceiver\n"); 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < rst[0]; i++) 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iowrite32(get_u16(rst + 1 + (i<<1)) << 16, ioaddr + CSR15); 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 342726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches netdev_dbg(dev, " Invalid media table selection %d\n", 343726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches mleaf->type); 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds new_csr6 = 0x020E0000; 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tulip_debug > 1) 347726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches netdev_dbg(dev, "Using media type %s, CSR12 is %02x\n", 348726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches medianame[dev->if_port], 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ioread32(ioaddr + CSR12) & 0xff); 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (tp->chip_id == LC82C168) { 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (startup && ! tp->medialock) 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->if_port = tp->mii_cnt ? 11 : 0; 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tulip_debug > 1) 354726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches netdev_dbg(dev, "PNIC PHY status is %3.3x, media %s\n", 355726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches ioread32(ioaddr + 0xB8), 356726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches medianame[dev->if_port]); 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tp->mii_cnt) { 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds new_csr6 = 0x810C0000; 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iowrite32(0x0001, ioaddr + CSR15); 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iowrite32(0x0201B07A, ioaddr + 0xB8); 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (startup) { 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Start with 10mbps to do autonegotiation. */ 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iowrite32(0x32, ioaddr + CSR12); 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds new_csr6 = 0x00420000; 3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iowrite32(0x0001B078, ioaddr + 0xB8); 3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iowrite32(0x0201B078, ioaddr + 0xB8); 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (dev->if_port == 3 || dev->if_port == 5) { 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iowrite32(0x33, ioaddr + CSR12); 3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds new_csr6 = 0x01860000; 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Trigger autonegotiation. */ 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iowrite32(startup ? 0x0201F868 : 0x0001F868, ioaddr + 0xB8); 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iowrite32(0x32, ioaddr + CSR12); 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds new_csr6 = 0x00420000; 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iowrite32(0x1F078, ioaddr + 0xB8); 3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { /* Unknown chip type with no media table. */ 3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tp->default_port == 0) 3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->if_port = tp->mii_cnt ? 11 : 3; 3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tulip_media_cap[dev->if_port] & MediaIsMII) { 3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds new_csr6 = 0x020E0000; 3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (tulip_media_cap[dev->if_port] & MediaIsFx) { 3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds new_csr6 = 0x02860000; 3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds new_csr6 = 0x03860000; 3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tulip_debug > 1) 387726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches netdev_dbg(dev, "No media description table, assuming %s transceiver, CSR12 %02x\n", 388726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches medianame[dev->if_port], 389726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches ioread32(ioaddr + CSR12)); 3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp->csr6 = new_csr6 | (tp->csr6 & 0xfdff) | (tp->full_duplex ? 0x0200 : 0); 39312755c16a9e4fa2fd5b0ca1963e83d671a6251daRalf Baechle 39412755c16a9e4fa2fd5b0ca1963e83d671a6251daRalf Baechle mdelay(1); 3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Check the MII negotiated duplex and change the CSR6 setting if 3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds required. 4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Return 0 if everything is OK. 4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Return < 0 if the transceiver is missing or has no link beat. 4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint tulip_check_duplex(struct net_device *dev) 4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct tulip_private *tp = netdev_priv(dev); 4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int bmsr, lpa, negotiated, new_csr6; 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bmsr = tulip_mdio_read(dev, tp->phys[0], MII_BMSR); 4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lpa = tulip_mdio_read(dev, tp->phys[0], MII_LPA); 4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tulip_debug > 1) 411fa0b9a4c41490d550ebd3bd418f4551c989fec5dJoe Perches dev_info(&dev->dev, "MII status %04x, Link partner report %04x\n", 412fa0b9a4c41490d550ebd3bd418f4551c989fec5dJoe Perches bmsr, lpa); 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bmsr == 0xffff) 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -2; 4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((bmsr & BMSR_LSTATUS) == 0) { 4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int new_bmsr = tulip_mdio_read(dev, tp->phys[0], MII_BMSR); 4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((new_bmsr & BMSR_LSTATUS) == 0) { 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tulip_debug > 1) 419fa0b9a4c41490d550ebd3bd418f4551c989fec5dJoe Perches dev_info(&dev->dev, 420fa0b9a4c41490d550ebd3bd418f4551c989fec5dJoe Perches "No link beat on the MII interface, status %04x\n", 421fa0b9a4c41490d550ebd3bd418f4551c989fec5dJoe Perches new_bmsr); 4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; 4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds negotiated = lpa & tp->advertising[0]; 4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp->full_duplex = mii_duplex(tp->full_duplex_lock, negotiated); 4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds new_csr6 = tp->csr6; 4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (negotiated & LPA_100) new_csr6 &= ~TxThreshold; 4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else new_csr6 |= TxThreshold; 4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tp->full_duplex) new_csr6 |= FullDuplex; 4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else new_csr6 &= ~FullDuplex; 4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (new_csr6 != tp->csr6) { 4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp->csr6 = new_csr6; 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tulip_restart_rxtx(tp); 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tulip_debug > 0) 440fa0b9a4c41490d550ebd3bd418f4551c989fec5dJoe Perches dev_info(&dev->dev, 441fa0b9a4c41490d550ebd3bd418f4551c989fec5dJoe Perches "Setting %s-duplex based on MII#%d link partner capability of %04x\n", 442fa0b9a4c41490d550ebd3bd418f4551c989fec5dJoe Perches tp->full_duplex ? "full" : "half", 443fa0b9a4c41490d550ebd3bd418f4551c989fec5dJoe Perches tp->phys[0], lpa); 4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 1; 4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid __devinit tulip_find_mii (struct net_device *dev, int board_idx) 4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct tulip_private *tp = netdev_priv(dev); 4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int phyn, phy_idx = 0; 4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int mii_reg0; 4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int mii_advert; 4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int to_advert, new_bmcr, ane_switch; 4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Find the connected MII xcvrs. 4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Doing this in open() would allow detecting external xcvrs later, 4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds but takes much time. */ 4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (phyn = 1; phyn <= 32 && phy_idx < sizeof (tp->phys); phyn++) { 4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int phy = phyn & 0x1f; 4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int mii_status = tulip_mdio_read (dev, phy, MII_BMSR); 4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((mii_status & 0x8301) == 0x8001 || 4658e95a2026f3b43f7c3d676adaccd2de9532e8dccJoe Perches ((mii_status & BMSR_100BASE4) == 0 && 4668e95a2026f3b43f7c3d676adaccd2de9532e8dccJoe Perches (mii_status & 0x7800) != 0)) { 4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* preserve Becker logic, gain indentation level */ 4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mii_reg0 = tulip_mdio_read (dev, phy, MII_BMCR); 4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mii_advert = tulip_mdio_read (dev, phy, MII_ADVERTISE); 4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ane_switch = 0; 4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* if not advertising at all, gen an 4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * advertising value from the capability 4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * bits in BMSR 4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((mii_advert & ADVERTISE_ALL) == 0) { 4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int tmpadv = tulip_mdio_read (dev, phy, MII_BMSR); 4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mii_advert = ((tmpadv >> 6) & 0x3e0) | 1; 4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tp->mii_advertise) { 4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp->advertising[phy_idx] = 4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds to_advert = tp->mii_advertise; 4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (tp->advertising[phy_idx]) { 4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds to_advert = tp->advertising[phy_idx]; 4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp->advertising[phy_idx] = 4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp->mii_advertise = 4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds to_advert = mii_advert; 4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp->phys[phy_idx++] = phy; 4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 498fa0b9a4c41490d550ebd3bd418f4551c989fec5dJoe Perches pr_info("tulip%d: MII transceiver #%d config %04x status %04x advertising %04x\n", 4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds board_idx, phy, mii_reg0, mii_status, mii_advert); 5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Fixup for DLink with miswired PHY. */ 5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mii_advert != to_advert) { 503726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches pr_debug("tulip%d: Advertising %04x on PHY %d, previously advertising %04x\n", 504726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches board_idx, to_advert, phy, mii_advert); 5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tulip_mdio_write (dev, phy, 4, to_advert); 5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Enable autonegotiation: some boards default to off. */ 5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tp->default_port == 0) { 5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds new_bmcr = mii_reg0 | BMCR_ANENABLE; 5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (new_bmcr != mii_reg0) { 5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds new_bmcr |= BMCR_ANRESTART; 5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ane_switch = 1; 5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* ...or disable nway, if forcing media */ 5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else { 5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds new_bmcr = mii_reg0 & ~BMCR_ANENABLE; 5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (new_bmcr != mii_reg0) 5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ane_switch = 1; 5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* clear out bits we never want at this point */ 5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds new_bmcr &= ~(BMCR_CTST | BMCR_FULLDPLX | BMCR_ISOLATE | 5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BMCR_PDOWN | BMCR_SPEED100 | BMCR_LOOPBACK | 5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BMCR_RESET); 5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tp->full_duplex) 5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds new_bmcr |= BMCR_FULLDPLX; 5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tulip_media_cap[tp->default_port] & MediaIs100) 5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds new_bmcr |= BMCR_SPEED100; 5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (new_bmcr != mii_reg0) { 5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* some phys need the ANE switch to 5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * happen before forced media settings 5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * will "take." However, we write the 5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * same value twice in order not to 5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * confuse the sane phys. 5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ane_switch) { 5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tulip_mdio_write (dev, phy, MII_BMCR, new_bmcr); 5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds udelay (10); 5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tulip_mdio_write (dev, phy, MII_BMCR, new_bmcr); 5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp->mii_cnt = phy_idx; 5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tp->mtable && tp->mtable->has_mii && phy_idx == 0) { 549fa0b9a4c41490d550ebd3bd418f4551c989fec5dJoe Perches pr_info("tulip%d: ***WARNING***: No MII transceiver found!\n", 5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds board_idx); 5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp->phys[0] = 1; 5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 554