summaryrefslogtreecommitdiffstats
path: root/drivers/net/miiphy.c
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2007-07-05 18:02:06 +0200
committerSascha Hauer <sha@octopus.labnet.pengutronix.de>2007-07-05 18:02:06 +0200
commit14edc91f970c42b55a4ab680fe014374a626ba0d (patch)
tree8f71fc44999637294a8bce6b74684ffa5b079162 /drivers/net/miiphy.c
parent367ed9fd09fb8933f6015fc853c6dcab695332ea (diff)
downloadbarebox-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.c167
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);
+