static int phy_autoneg(struct net_device *dev) { struct tangox_enet_priv *priv; int loop; unsigned int val = 0; priv = netdev_priv(dev); /* reset phy */ val = enet_mdio_read(dev, priv->mii.phy_id, MII_BMCR); enet_mdio_write(dev, priv->mii.phy_id, MII_BMCR, val | BMCR_ANENABLE|BMCR_ANRESTART); udelay(100); loop = 10000; while (loop) { if (enet_mdio_read(dev, priv->mii.phy_id, MII_BMSR) & BMSR_ANEGCOMPLETE) break; mdelay(1); loop--; } if (!loop) { printk(KERN_ERR "%s: PHY autonegotiation does not complete...\n", priv->name); return -EBUSY; } return 0; }
static int phy_reset(struct net_device *dev) { struct tangox_enet_priv *priv; int loop; unsigned int val = 0; priv = netdev_priv(dev); /* reset phy */ val = enet_mdio_read(dev, priv->mii.phy_id, MII_BMCR); enet_mdio_write(dev, priv->mii.phy_id, MII_BMCR, val | BMCR_RESET); /* wait for the reset bit to clear */ udelay(100); loop = 100; while (loop) { if (!(enet_mdio_read(dev, priv->mii.phy_id, MII_BMCR) & BMCR_RESET)) break; mdelay(1); loop--; } if (!loop) { printk(KERN_ERR "%s: PHY reset does not complete...\n", priv->name); return -EBUSY; } return 0; }
static int enet_get_speed(struct net_device *dev) { struct tangox_enet_priv *priv; unsigned int physr; int speed = 100; priv = netdev_priv(dev); if(priv->rgmii == 0){ /*Realtek*/ physr = enet_mdio_read(dev, priv->mii.phy_id, MII_PHYADDR); switch(physr & 0x3){ case 1: speed = 100; break; case 2: speed = 10; break; default: speed = 0; break; } return speed; } /* Vitesse */ physr = enet_mdio_read(dev, priv->mii.phy_id, MII_NCONFIG); physr >>= 3; switch(physr & 0x3){ case 0: speed = 10; break; case 1: speed = 100; break; case 2: speed = 1000; break; case 3: speed = 0; break; } return speed; }
static void enet_mac_config(struct net_device *dev) { struct tangox_enet_priv *priv; unsigned char val; int speed; priv = netdev_priv(dev); if(priv->rgmii == 0) { /* 100 baseT, realtek*/ val = enet_readb(ENET_MAC_MODE(priv->enet_mac_base)); if(val & (GMAC_MODE | RGMII_MODE)){ val &= ~(GMAC_MODE | RGMII_MODE); /*disable Gigabit mode for now*/ //val |= /*LB_EN |*/ BST_EN; /*loopback off, burst on*/ enet_writeb(ENET_MAC_MODE(priv->enet_mac_base), val); } return; } /*set RGMII skew timing compensation enable */ /* This added 2ns delay to RX_CLK and TX_CLK*/ val = enet_mdio_read(dev, priv->mii.phy_id, MII_RESV1); enet_mdio_write(dev, priv->mii.phy_id, MII_RESV1 , val | (1<<8)); val = enet_readl(ENET_MAC_MODE(priv->enet_mac_base)); speed = enet_get_speed(dev); if(speed == 1000 ){ if((val & RGMII_MODE) && (val & GMAC_MODE)) return; /* configured for gigabit */ val |= RGMII_MODE; val |= GMAC_MODE; enet_writeb(ENET_MAC_MODE(priv->enet_mac_base), val); //printk("set 1000mbps val=0x%x\n", val); }else if(speed == 100){ if((val & RGMII_MODE) && !(val & GMAC_MODE)) return; /* configured for 100mbps*/ val |= RGMII_MODE; val &= ~GMAC_MODE; enet_writeb(ENET_MAC_MODE(priv->enet_mac_base), val); //printk("set 100mbps val=0x%x\n", val); }else /*TODO*/ ; //printk("set 10 mbps or other val=0x%x\n", val); /*set threshold for internal clock 0x1*/ enet_writeb(ENET_IC_THRESHOLD(priv->enet_mac_base), (speed==1000 ? 3:1)); /*set slot time 0x7f for 10/100Mbps*/ enet_writeb(ENET_SLOT_TIME(priv->enet_mac_base), (speed==1000 ? 0xff : 0x7f)); //phy_autoneg(dev); }
int fec_phy_read(struct mii_dev *bus, int phyAddr, int dev_addr, int regAddr) { return enet_mdio_read((struct enet*)bus->priv, phyAddr, regAddr); }
static int enet_probe(int idx) { struct tangox_enet_priv *priv; struct net_device *dev; int ret; struct sockaddr sock; char pad_mode; short clk_div; unsigned long enet_mac_base; const char *name; enet_mac_base = eth_mac_cores[idx].enet_mac_base; name = eth_mac_cores[idx].name; #if 1 /* this part may be moved to boot loader */ /* set pad_mode*/ pad_mode = enet_readb(enet_mac_base + 0x400); enet_writeb(enet_mac_base + 0x400, pad_mode & 0xf0); pad_mode = enet_readb(enet_mac_base + 0x400); /* set MDIO clock divider */ clk_div = enet_readw(enet_mac_base + 0x420); //DBG("default clk_div =%d\n", clk_div); //enet_writew(enet_mac_base + 0x420, 50); enet_writew(enet_mac_base + 0x420, tangox_get_sysclock() / (2500000 * 2)); clk_div = enet_readw(enet_mac_base + 0x420); //DBG("clk_div =%d: set MDIO clock=200/%d=%dMHz\n", clk_div, clk_div, 200/(clk_div*2)); #endif /* allocate netdevice structure with enough length for our * context data */ dev = alloc_etherdev(sizeof (*priv)); if (!dev) return -ENOMEM; /* initialize private data */ priv = netdev_priv(dev); memset(priv, 0, sizeof (*priv)); priv->enet_mac_base = enet_mac_base; priv->name = name; priv->pending_tx = -1; priv->pending_tx_cnt = 0; priv->reclaim_limit = -1; spin_lock_init(&priv->tx_lock); spin_lock_init(&priv->ier_lock); spin_lock_init(&priv->maccr_lock); /* init tx done tasklet */ tasklet_init(&priv->tx_reclaim_tasklet, enet_tx_reclaim, (unsigned long)dev); #if 0 /* init tx reclaim timer */ init_timer(&priv->tx_reclaim_timer); priv->tx_reclaim_timer.data = (unsigned long )dev; priv->tx_reclaim_timer.function = enet_tx_reclaim_timer; #endif /* init link check timer and mii lock */ init_timer(&priv->link_check_timer); priv->link_check_timer.data = (unsigned long)dev; priv->link_check_timer.function = enet_link_check; spin_lock_init(&priv->mii_lock); /* fill mii info */ priv->mii.dev = dev; priv->mii.phy_id_mask = 0x1f; priv->mii.reg_num_mask = 0x1f; priv->mii.mdio_read = enet_mdio_read; priv->mii.mdio_write = enet_mdio_write; if (eth_mac_cores[idx].phy_id != -1) { /* phy id forced, just check for sanity */ if (eth_mac_cores[idx].phy_id < 0 || eth_mac_cores[idx].phy_id > 31) { ret = -EINVAL; goto err_free; } priv->mii.phy_id = eth_mac_cores[idx].phy_id; } else { int i; /* try to probe phy if not given */ for (i = 0; i <32; i++) { uint32_t id; int val; val = enet_mdio_read(dev, i, MII_PHYSID1); id = (val << 16); val = enet_mdio_read(dev, i, MII_PHYSID2); id |= val; if (id != 0xffffffff && id != 0x00000000) { /* check vsc8061 */ if(id == 0x00070421) priv->rgmii = 1; break; } } if (i == 32) { printk(KERN_ERR "%s: unable to autodetect phy\n", priv->name); ret = -EIO; goto err_free; } printk(KERN_ERR "%s: detected phy %s at address 0x%02x\n", name,(priv->rgmii? "vsc8601":""), i); priv->mii.phy_id = i; } printk(KERN_INFO "%s: Ethernet driver for SMP864x/SMP865x internal MAC core %d: %s Base at 0x%lx\n", name, idx, priv->rgmii?"1000Mbps":"100Mbps", enet_mac_base); /* initialize hardware */ if ((ret = enet_hw_init(dev))) goto err_free; /* initialize dma descriptors */ if ((ret = enet_dma_init(priv))) goto err_free; ret = request_irq(eth_mac_cores[idx].irq, enet_isr, IRQF_DISABLED, eth_mac_cores[idx].name, dev); dev->irq = eth_mac_cores[idx].irq; if (ret) goto err_free; /* install driver callbacks and register netdevice */ dev->open = enet_open; dev->stop = enet_stop; dev->hard_start_xmit = enet_xmit; dev->get_stats = enet_get_stats; dev->set_mac_address = enet_set_mac_address; dev->set_multicast_list = enet_set_multicast_list; dev->poll = enet_poll; dev->ethtool_ops = &enet_ethtool_ops; dev->do_ioctl = enet_ioctl; dev->weight = RX_DESC_COUNT; dev->tx_queue_len = TX_DESC_COUNT; #ifdef ENABLE_MULTICAST dev->flags |= IFF_MULTICAST; #else dev->flags &= ~IFF_MULTICAST; #endif /* set default mac address */ tangox_ethernet_getmac(idx, dev->dev_addr); memcpy(&(sock.sa_data), dev->dev_addr, ETH_ALEN); enet_set_mac_address(dev, &sock); if ((ret = register_netdev(dev))) { printk(KERN_ERR "%s: unable to register netdevice\n", priv->name); goto err_free; } printk(KERN_INFO "%s: mac address %02x:%02x:%02x:%02x:%02x:%02x\n", priv->name, dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); eth_mac_cores[idx].gdev = dev; return 0; err_free: if (dev->irq) free_irq(dev->irq, dev); enet_dma_free(priv); free_netdev(dev); return ret; }