From 14edc91f970c42b55a4ab680fe014374a626ba0d Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Thu, 5 Jul 2007 18:02:06 +0200 Subject: svn_rev_572 add miiphy support --- drivers/net/Kconfig | 4 ++ drivers/net/Makefile | 1 + drivers/net/miiphy.c | 167 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 172 insertions(+) create mode 100644 drivers/net/miiphy.c (limited to 'drivers') diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 93443a5aef..7c2ef080e0 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -7,6 +7,9 @@ config HAS_DM9000 config HAS_AT91_ETHER bool +config MIIPHY + bool + menu "Network drivers " depends on NET @@ -25,6 +28,7 @@ config DRIVER_NET_AT91_ETHER config DRIVER_NET_MPC5200 bool "MPC5200 Ethernet driver" depends on ARCH_MPC5200 + select MIIPHY config DRIVER_NET_TAP bool "tap Ethernet driver" diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 189896e71a..62745b78b7 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -3,3 +3,4 @@ obj-$(CONFIG_DRIVER_NET_DM9000) += dm9000.o obj-$(CONFIG_DRIVER_NET_AT91_ETHER) += at91_ether.o obj-$(CONFIG_DRIVER_NET_MPC5200) += fec_mpc5200.o obj-$(CONFIG_DRIVER_NET_TAP) += tap.o +obj-$(CONFIG_MIIPHY) += miiphy.o 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 +#include +#include +#include + +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); + -- cgit v1.2.3