static int at91emac_phy_init(struct eth_device *netdev) { u16 phy_id, status, adv, lpa; int media, speed, duplex; int i; at91_emac_t *emac; emac = (at91_emac_t *) netdev->iobase; /* Check if the PHY is up to snuff... */ at91emac_read(emac, CONFIG_DRIVER_AT91EMAC_PHYADDR, MII_PHYSID1, &phy_id); if (phy_id == 0xffff) { printf("%s: No PHY present\n", netdev->name); return 1; } at91emac_read(emac, CONFIG_DRIVER_AT91EMAC_PHYADDR, MII_BMSR, &status); if (!(status & BMSR_LSTATUS)) { /* Try to re-negotiate if we don't have link already. */ if (at91emac_phy_reset(netdev)) return 2; for (i = 0; i < 100000 / 100; i++) { at91emac_read(emac, CONFIG_DRIVER_AT91EMAC_PHYADDR, MII_BMSR, &status); if (status & BMSR_LSTATUS) break; udelay(100); } } if (!(status & BMSR_LSTATUS)) { VERBOSEP("%s: link down\n", netdev->name); return 3; } else { at91emac_read(emac, CONFIG_DRIVER_AT91EMAC_PHYADDR, MII_ADVERTISE, &adv); at91emac_read(emac, CONFIG_DRIVER_AT91EMAC_PHYADDR, MII_LPA, &lpa); media = mii_nway_result(lpa & adv); speed = (media & (ADVERTISE_100FULL | ADVERTISE_100HALF) ? 1 : 0); duplex = (media & ADVERTISE_FULL) ? 1 : 0; VERBOSEP("%s: link up, %sMbps %s-duplex\n", netdev->name, speed ? "100" : "10", duplex ? "full" : "half"); } return 0; }
static int at91emac_phy_reset(struct eth_device *netdev) { int i; u16 status, adv; at91_emac_t *emac; emac = (at91_emac_t *) netdev->iobase; adv = ADVERTISE_CSMA | ADVERTISE_ALL; at91emac_write(emac, 0, MII_ADVERTISE, adv); VERBOSEP("%s: Starting autonegotiation...\n", netdev->name); at91emac_write(emac, 0, MII_BMCR, (BMCR_ANENABLE | BMCR_ANRESTART)); for (i = 0; i < 100000 / 100; i++) { at91emac_read(emac, 0, MII_BMSR, &status); if (status & BMSR_ANEGCOMPLETE) break; udelay(100); } if (status & BMSR_ANEGCOMPLETE) { VERBOSEP("%s: Autonegotiation complete\n", netdev->name); } else { printf("%s: Autonegotiation timed out (status=0x%04x)\n", netdev->name, status); return 1; } return 0; }
int at91emac_mii_read(char *devname, unsigned char addr, unsigned char reg, unsigned short *value) { at91_emac_t *emac; emac = get_emacbase_by_name(devname); at91emac_read(emac , addr, reg, value); return 0; }
int at91emac_UpdateLinkSpeed(at91_emac_t *emac) { unsigned short stat1; at91emac_read(emac, 0, MII_BMSR, &stat1); if (!(stat1 & BMSR_LSTATUS)) /* link status up? */ return 1; if (stat1 & BMSR_100FULL) { /*set Emac for 100BaseTX and Full Duplex */ writel(readl(&emac->cfg) | AT91_EMAC_CFG_SPD | AT91_EMAC_CFG_FD, &emac->cfg); return 0; } if (stat1 & BMSR_10FULL) { /*set MII for 10BaseT and Full Duplex */ writel((readl(&emac->cfg) & ~(AT91_EMAC_CFG_SPD | AT91_EMAC_CFG_FD) ) | AT91_EMAC_CFG_FD, &emac->cfg); return 0; } if (stat1 & BMSR_100HALF) { /*set MII for 100BaseTX and Half Duplex */ writel((readl(&emac->cfg) & ~(AT91_EMAC_CFG_SPD | AT91_EMAC_CFG_FD) ) | AT91_EMAC_CFG_SPD, &emac->cfg); return 0; } if (stat1 & BMSR_10HALF) { /*set MII for 10BaseT and Half Duplex */ writel((readl(&emac->cfg) & ~(AT91_EMAC_CFG_SPD | AT91_EMAC_CFG_FD)), &emac->cfg); return 0; } return 1; }