/* * Disable the MDIO bit in the MAC control register */ static void disable_mdi(void) { unsigned long ctl; ctl = at91_emac_read(AT91_EMAC_CTL); at91_emac_write(AT91_EMAC_CTL, ctl & ~AT91_EMAC_MPE); /* disable management port */ }
static void enable_mdi(void) { unsigned long ctl; ctl = at91_emac_read(AT91_EMAC_CTL); at91_emac_write(AT91_EMAC_CTL, ctl | AT91_EMAC_MPE); }
static int at91_ether_send(struct eth_device *edev, void *packet, int length) { while (!(at91_emac_read(AT91_EMAC_TSR) & AT91_EMAC_TSR_BNQ)); dma_flush_range((ulong) packet, (ulong)packet + length); /* Set address of the data in the Transmit Address register */ at91_emac_write(AT91_EMAC_TAR, (unsigned long) packet); /* Set length of the packet in the Transmit Control register */ at91_emac_write(AT91_EMAC_TCR, length); while (at91_emac_read(AT91_EMAC_TCR) & 0x7ff); at91_emac_write(AT91_EMAC_TSR, at91_emac_read(AT91_EMAC_TSR) | AT91_EMAC_TSR_COMP); return 0; }
static void at91_ether_halt (struct eth_device *edev) { unsigned long ctl; /* Disable Receiver and Transmitter */ ctl = at91_emac_read(AT91_EMAC_CTL); ctl &= ~(AT91_EMAC_TE | AT91_EMAC_RE); at91_emac_write(AT91_EMAC_CTL, ctl); }
static int at91_ether_open(struct eth_device *edev) { int i; unsigned long ctl; struct ether_device *etdev = to_ether(edev); unsigned char *rbf_framebuf = etdev->rbf_framebuf; int ret; ret = phy_device_connect(edev, &etdev->miibus, etdev->phy_addr, update_linkspeed, 0, etdev->interface); if (ret) return ret; /* Clear internal statistics */ ctl = at91_emac_read(AT91_EMAC_CTL); at91_emac_write(AT91_EMAC_CTL, ctl | AT91_EMAC_CSR); /* Init Ethernet buffers */ etdev->rbfp = etdev->rbfdt; for (i = 0; i < MAX_RX_DESCR; i++) { etdev->rbfp[i].addr = (unsigned long)rbf_framebuf; etdev->rbfp[i].size = 0; rbf_framebuf += MAX_RBUFF_SZ; } etdev->rbfp[i - 1].addr |= RBF_WRAP; /* Program address of descriptor list in Rx Buffer Queue register */ at91_emac_write(AT91_EMAC_RBQP, (unsigned long) etdev->rbfdt); ctl = at91_emac_read(AT91_EMAC_RSR); ctl &= ~(AT91_EMAC_RSR_OVR | AT91_EMAC_RSR_REC | AT91_EMAC_RSR_BNA); at91_emac_write(AT91_EMAC_RSR, ctl); ctl = at91_emac_read(AT91_EMAC_CFG); ctl |= AT91_EMAC_CAF | AT91_EMAC_NBC; at91_emac_write(AT91_EMAC_CFG, ctl); /* Enable Receive and Transmit */ ctl = at91_emac_read(AT91_EMAC_CTL); ctl |= AT91_EMAC_RE | AT91_EMAC_TE; at91_emac_write(AT91_EMAC_CTL, ctl); return 0; }
/* * Read value stored in a PHY register. * Note: MDI interface is assumed to already have been enabled. */ static void read_phy(unsigned char phy_addr, unsigned char address, unsigned int *value) { at91_emac_write(AT91_EMAC_MAN, AT91_EMAC_MAN_802_3 | AT91_EMAC_RW_R | ((phy_addr & 0x1f) << 23) | (address << 18)); /* Wait until IDLE bit in Network Status register is cleared */ at91_phy_wait(); *value = at91_emac_read(AT91_EMAC_MAN) & AT91_EMAC_DATA; }
static void read_phy(unsigned char phy_addr, unsigned char address, unsigned int *value) { at91_emac_write(AT91_EMAC_MAN, AT91_EMAC_MAN_802_3 | AT91_EMAC_RW_R | ((phy_addr & 0x1f) << 23) | (address << 18)); at91_phy_wait(); *value = at91_emac_read(AT91_EMAC_MAN) & AT91_EMAC_DATA; }
/* * Wait until the PHY operation is complete. */ static inline void at91_phy_wait(void) { unsigned long timeout = jiffies + 2; while (!(at91_emac_read(AT91_EMAC_SR) & AT91_EMAC_SR_IDLE)) { if (time_after(jiffies, timeout)) { printk("at91_ether: MIO timeout\n"); break; } cpu_relax(); } }
/* * Wait until the PHY operation is complete. */ static inline int at91_phy_wait(void) { uint64_t start; start = get_time_ns(); do { if (is_timeout(start, 2 * MSECOND)) { puts("at91_ether: MIO timeout\n"); return -1; } } while (!(at91_emac_read(AT91_EMAC_SR) & AT91_EMAC_SR_IDLE)); return 0; }
/* * Access the PHY to determine the current link speed and mode, and update the * MAC accordingly. * If no link or auto-negotiation is busy, then no changes are made. */ static void update_linkspeed(struct net_device *dev, int silent) { struct at91_private *lp = netdev_priv(dev); unsigned int bmsr, bmcr, lpa, mac_cfg; unsigned int speed, duplex; if (!mii_link_ok(&lp->mii)) { /* no link */ netif_carrier_off(dev); if (!silent) printk(KERN_INFO "%s: Link down.\n", dev->name); return; } /* Link up, or auto-negotiation still in progress */ read_phy(lp->phy_address, MII_BMSR, &bmsr); read_phy(lp->phy_address, MII_BMCR, &bmcr); if (bmcr & BMCR_ANENABLE) { /* AutoNegotiation is enabled */ if (!(bmsr & BMSR_ANEGCOMPLETE)) return; /* Do nothing - another interrupt generated when negotiation complete */ read_phy(lp->phy_address, MII_LPA, &lpa); if ((lpa & LPA_100FULL) || (lpa & LPA_100HALF)) speed = SPEED_100; else speed = SPEED_10; if ((lpa & LPA_100FULL) || (lpa & LPA_10FULL)) duplex = DUPLEX_FULL; else duplex = DUPLEX_HALF; } else { speed = (bmcr & BMCR_SPEED100) ? SPEED_100 : SPEED_10; duplex = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF; } /* Update the MAC */ mac_cfg = at91_emac_read(AT91_EMAC_CFG) & ~(AT91_EMAC_SPD | AT91_EMAC_FD); if (speed == SPEED_100) { if (duplex == DUPLEX_FULL) /* 100 Full Duplex */ mac_cfg |= AT91_EMAC_SPD | AT91_EMAC_FD; else /* 100 Half Duplex */ mac_cfg |= AT91_EMAC_SPD; } else { if (duplex == DUPLEX_FULL) /* 10 Full Duplex */ mac_cfg |= AT91_EMAC_FD; else {} /* 10 Half Duplex */ } at91_emac_write(AT91_EMAC_CFG, mac_cfg); if (!silent) printk(KERN_INFO "%s: Link now %i-%s\n", dev->name, speed, (duplex == DUPLEX_FULL) ? "FullDuplex" : "HalfDuplex"); netif_carrier_on(dev); }
static void update_linkspeed(struct net_device *dev, int silent) { struct at91_private *lp = netdev_priv(dev); unsigned int bmsr, bmcr, lpa, mac_cfg; unsigned int speed, duplex; if (!mii_link_ok(&lp->mii)) { netif_carrier_off(dev); if (!silent) printk(KERN_INFO "%s: Link down.\n", dev->name); return; } read_phy(lp->phy_address, MII_BMSR, &bmsr); read_phy(lp->phy_address, MII_BMCR, &bmcr); if (bmcr & BMCR_ANENABLE) { if (!(bmsr & BMSR_ANEGCOMPLETE)) return; read_phy(lp->phy_address, MII_LPA, &lpa); if ((lpa & LPA_100FULL) || (lpa & LPA_100HALF)) speed = SPEED_100; else speed = SPEED_10; if ((lpa & LPA_100FULL) || (lpa & LPA_10FULL)) duplex = DUPLEX_FULL; else duplex = DUPLEX_HALF; } else { speed = (bmcr & BMCR_SPEED100) ? SPEED_100 : SPEED_10; duplex = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF; } mac_cfg = at91_emac_read(AT91_EMAC_CFG) & ~(AT91_EMAC_SPD | AT91_EMAC_FD); if (speed == SPEED_100) { if (duplex == DUPLEX_FULL) mac_cfg |= AT91_EMAC_SPD | AT91_EMAC_FD; else mac_cfg |= AT91_EMAC_SPD; } else { if (duplex == DUPLEX_FULL) mac_cfg |= AT91_EMAC_FD; else {} } at91_emac_write(AT91_EMAC_CFG, mac_cfg); if (!silent) printk(KERN_INFO "%s: Link now %i-%s\n", dev->name, speed, (duplex == DUPLEX_FULL) ? "FullDuplex" : "HalfDuplex"); netif_carrier_on(dev); }
static void update_linkspeed(struct eth_device *edev) { unsigned int mac_cfg; /* Update the MAC */ mac_cfg = at91_emac_read(AT91_EMAC_CFG) & ~(AT91_EMAC_SPD | AT91_EMAC_FD); if (edev->phydev->speed == SPEED_100) { if (edev->phydev->duplex) mac_cfg |= AT91_EMAC_SPD | AT91_EMAC_FD; else /* 100 Half Duplex */ mac_cfg |= AT91_EMAC_SPD; } else { if (edev->phydev->duplex) mac_cfg |= AT91_EMAC_FD; else {} /* 10 Half Duplex */ } at91_emac_write(AT91_EMAC_CFG, mac_cfg); }
static int at91_ether_mii_read(struct mii_bus *dev, int addr, int reg) { int value; enable_mdi(); at91_emac_write(AT91_EMAC_MAN, AT91_EMAC_MAN_802_3 | AT91_EMAC_RW_R | ((addr & 0x1f) << 23) | (reg << 18)); /* Wait until IDLE bit in Network Status register is cleared */ value = at91_phy_wait(); if (value < 0) goto out; value = at91_emac_read(AT91_EMAC_MAN) & AT91_EMAC_DATA; out: disable_mdi(); return value; }
static int at91_ether_rx(struct eth_device *edev) { struct ether_device *etdev = to_ether(edev); int size; struct rbf_t *rbfp = etdev->rbfp; if (!(rbfp->addr & RBF_OWNER)) return 0; size = rbfp->size & RBF_SIZE; net_receive(edev, (unsigned char *)(rbfp->addr & RBF_ADDR), size); rbfp->addr &= ~RBF_OWNER; if (rbfp->addr & RBF_WRAP) etdev->rbfp = etdev->rbfdt; else etdev->rbfp++; at91_emac_write(AT91_EMAC_RSR, at91_emac_read(AT91_EMAC_RSR) | AT91_EMAC_RSR_REC); return size; }
static int at91_ether_probe(struct device_d *dev) { unsigned int mac_cfg; struct ether_device *ether_dev; struct eth_device *edev; struct mii_bus *miibus; unsigned long ether_hz; struct clk *pclk; struct macb_platform_data *pdata; if (!dev->platform_data) { printf("at91_ether: no platform_data\n"); return -ENODEV; } pdata = dev->platform_data; ether_dev = xzalloc(sizeof(struct ether_device)); edev = ðer_dev->netdev; miibus = ðer_dev->miibus; edev->priv = ether_dev; edev->init = at91_ether_init; edev->open = at91_ether_open; edev->send = at91_ether_send; edev->recv = at91_ether_rx; edev->halt = at91_ether_halt; edev->get_ethaddr = at91_ether_get_ethaddr; edev->set_ethaddr = at91_ether_set_ethaddr; ether_dev->rbf_framebuf = dma_alloc_coherent(MAX_RX_DESCR * MAX_RBUFF_SZ); ether_dev->rbfdt = dma_alloc_coherent(sizeof(struct rbf_t) * MAX_RX_DESCR); ether_dev->phy_addr = pdata->phy_addr; miibus->read = at91_ether_mii_read; miibus->write = at91_ether_mii_write; /* Sanitize the clocks */ mac_cfg = at91_emac_read(AT91_EMAC_CFG); pclk = clk_get(dev, "ether_clk"); clk_enable(pclk); ether_hz = clk_get_rate(pclk); if (ether_hz > 40000000) { /* MDIO clock must not exceed 2.5 MHz, so enable MCK divider */ mac_cfg |= AT91_EMAC_CLK_DIV64; } else { mac_cfg &= ~AT91_EMAC_CLK; } mac_cfg |= AT91_EMAC_CLK_DIV32 | AT91_EMAC_BIG; if (pdata->phy_interface == PHY_INTERFACE_MODE_RMII) { ether_dev->interface = PHY_INTERFACE_MODE_RGMII; mac_cfg |= AT91_EMAC_RMII; } else { ether_dev->interface = PHY_INTERFACE_MODE_MII; } at91_emac_write(AT91_EMAC_CFG, mac_cfg); mdiobus_register(miibus); eth_register(edev); return 0; }