diff options
author | Sascha Hauer <s.hauer@pengutronix.de> | 2007-07-05 18:02:06 +0200 |
---|---|---|
committer | Sascha Hauer <sha@octopus.labnet.pengutronix.de> | 2007-07-05 18:02:06 +0200 |
commit | 14edc91f970c42b55a4ab680fe014374a626ba0d (patch) | |
tree | 8f71fc44999637294a8bce6b74684ffa5b079162 /drivers/net/miiphy.c | |
parent | 367ed9fd09fb8933f6015fc853c6dcab695332ea (diff) | |
download | barebox-14edc91f970c42b55a4ab680fe014374a626ba0d.tar.gz barebox-14edc91f970c42b55a4ab680fe014374a626ba0d.tar.xz |
svn_rev_572
add miiphy support
Diffstat (limited to 'drivers/net/miiphy.c')
-rw-r--r-- | drivers/net/miiphy.c | 167 |
1 files changed, 167 insertions, 0 deletions
diff --git a/drivers/net/miiphy.c b/drivers/net/miiphy.c new file mode 100644 index 0000000000..8f810f54d1 --- /dev/null +++ b/drivers/net/miiphy.c @@ -0,0 +1,167 @@ +#include <common.h> +#include <driver.h> +#include <init.h> +#include <mii_phy.h> + +int miiphy_restart_aneg(struct miiphy_device *mdev) +{ + uint16_t status; + int timeout; + + /* + * Reset PHY, then delay 300ns + */ + mdev->write(mdev, mdev->address, PHY_BMCR, PHY_BMCR_RESET); + udelay(1000); + + if (mdev->flags & MIIPHY_FORCE_10) { + printf("Forcing 10 Mbps ethernet link... "); + mdev->read(mdev, mdev->address, PHY_BMSR, &status); + mdev->write(mdev, mdev->address, PHY_BMCR, PHY_BMCR_DPLX | PHY_BMCR_COL_TST); + + timeout = 20; + do { /* wait for link status to go down */ + udelay(10000); + if ((timeout--) == 0) { +#if (DEBUG & 0x2) + printf("hmmm, should not have waited..."); +#endif + break; + } + mdev->read(mdev, mdev->address, PHY_BMSR, &status); + } while (status & PHY_BMSR_LS); + + } else { /* MII100 */ + /* + * Set the auto-negotiation advertisement register bits + */ + mdev->write(mdev, mdev->address, PHY_ANAR, 0x01e1); + + mdev->write(mdev, mdev->address, PHY_BMCR, PHY_BMCR_AUTON | PHY_BMCR_RST_NEG); + } + + return 0; +} + +int miiphy_wait_aneg(struct miiphy_device *mdev) +{ + int timeout = 1; + uint16_t status; + + /* + * Wait for AN completion + */ + timeout = 5000; + do { + udelay(1000); + + if (!timeout--) { + printf("%s: Autonegotiation timeout\n", mdev->dev.id); + return -1; + } + + if (mdev->read(mdev, mdev->address, PHY_BMSR, &status)) { + printf("%s: Autonegotiation failed. status: 0x%04x\n", mdev->dev.id, status); + return -1; + } + } while (!(status & PHY_BMSR_LS)); + + return 0; +} + +int miiphy_print_status(struct miiphy_device *mdev) +{ + uint16_t bmsr, bmcr, anlpar; + char *duplex; + int speed; + + if (mdev->read(mdev, mdev->address, PHY_BMSR, &bmsr) != 0) + goto err_out; + if (mdev->read(mdev, mdev->address, PHY_BMCR, &bmcr) != 0) + goto err_out; + if (mdev->read(mdev, mdev->address, PHY_ANLPAR, &anlpar) != 0) + goto err_out; + + printf("%s: Link is %s", mdev->dev.id, + bmsr & PHY_BMSR_LS ? "up" : "down"); + + if (bmcr & PHY_BMCR_AUTON) { + duplex = (PHY_ANLPAR_10FD | PHY_ANLPAR_TXFD) ? "Full" : "Half"; + speed = anlpar & PHY_ANLPAR_100 ? 100 : 10; + } else { + duplex = bmcr & PHY_BMCR_DPLX ? "Full" : "Half"; + speed = bmcr & PHY_BMCR_100MB ? 100 : 10; + } + + printf(" - %d/%s\n", speed, duplex); + + return 0; +err_out: + printf("%s: failed to read\n", mdev->dev.id); + return -1; +} + +ssize_t miiphy_read(struct device_d *dev, void *_buf, size_t count, ulong offset, ulong flags) +{ + int i = count; + uint16_t *buf = _buf; + struct miiphy_device *mdev = dev->priv; + + while (i > 1) { + mdev->read(mdev, mdev->address, offset, buf); + buf++; + i -= 2; + offset++; + } + + return count; +} + +ssize_t miiphy_write(struct device_d *dev, const void *_buf, size_t count, ulong offset, ulong flags) +{ + int i = count; + const uint16_t *buf = _buf; + struct miiphy_device *mdev = dev->priv; + + while (i > 1) { + mdev->write(mdev, mdev->address, offset, *buf); + buf++; + i -= 2; + offset++; + } + + return count; +} + +static int miiphy_probe(struct device_d *dev) +{ + return 0; +} + +int miiphy_register(struct miiphy_device *mdev) +{ + strcpy(mdev->dev.name, "miiphy"); + get_free_deviceid(mdev->dev.id, "phy"); + mdev->dev.type = DEVICE_TYPE_MIIPHY; + mdev->dev.priv = mdev; + mdev->dev.size = 32; + + return register_device(&mdev->dev); +} + +static struct driver_d miiphy_drv = { + .name = "miiphy", + .probe = miiphy_probe, + .read = miiphy_read, + .write = miiphy_write, + .type = DEVICE_TYPE_MIIPHY, +}; + +static int miiphy_init(void) +{ + register_driver(&miiphy_drv); + return 0; +} + +device_initcall(miiphy_init); + |