From 16a5323833cc3536fac4c6aa3c6c4cf681679952 Mon Sep 17 00:00:00 2001 From: Andy Fleming Date: Thu, 7 Apr 2011 14:38:35 -0500 Subject: miiphy: Fix some formatting issues Mostly putting a space between function name and "(", and doing return (foo) Signed-off-by: Andy Fleming Acked-by: Detlev Zundel --- common/miiphyutil.c | 144 ++++++++++++++++++++++++++-------------------------- 1 file changed, 72 insertions(+), 72 deletions(-) (limited to 'common') diff --git a/common/miiphyutil.c b/common/miiphyutil.c index e282096a13..6944ea7730 100644 --- a/common/miiphyutil.c +++ b/common/miiphyutil.c @@ -39,17 +39,17 @@ #undef debug #ifdef MII_DEBUG -#define debug(fmt,args...) printf (fmt ,##args) +#define debug(fmt, args...) printf(fmt, ##args) #else -#define debug(fmt,args...) +#define debug(fmt, args...) #endif /* MII_DEBUG */ struct mii_dev { struct list_head link; const char *name; - int (*read) (const char *devname, unsigned char addr, + int (*read)(const char *devname, unsigned char addr, unsigned char reg, unsigned short *value); - int (*write) (const char *devname, unsigned char addr, + int (*write)(const char *devname, unsigned char addr, unsigned char reg, unsigned short value); }; @@ -86,7 +86,7 @@ static struct mii_dev *miiphy_get_dev_by_name(const char *devname, int quiet) */ void miiphy_init(void) { - INIT_LIST_HEAD (&mii_devs); + INIT_LIST_HEAD(&mii_devs); current_mii = NULL; } @@ -95,9 +95,9 @@ void miiphy_init(void) * Register read and write MII access routines for the device . */ void miiphy_register(const char *name, - int (*read) (const char *devname, unsigned char addr, + int (*read)(const char *devname, unsigned char addr, unsigned char reg, unsigned short *value), - int (*write) (const char *devname, unsigned char addr, + int (*write)(const char *devname, unsigned char addr, unsigned char reg, unsigned short value)) { struct mii_dev *new_dev; @@ -112,30 +112,30 @@ void miiphy_register(const char *name, } /* allocate memory */ - name_len = strlen (name); + name_len = strlen(name); new_dev = - (struct mii_dev *)malloc (sizeof (struct mii_dev) + name_len + 1); + (struct mii_dev *)malloc(sizeof(struct mii_dev) + name_len + 1); if (new_dev == NULL) { - printf ("miiphy_register: cannot allocate memory for '%s'\n", + printf("miiphy_register: cannot allocate memory for '%s'\n", name); return; } - memset (new_dev, 0, sizeof (struct mii_dev) + name_len); + memset(new_dev, 0, sizeof(struct mii_dev) + name_len); /* initalize mii_dev struct fields */ - INIT_LIST_HEAD (&new_dev->link); + INIT_LIST_HEAD(&new_dev->link); new_dev->read = read; new_dev->write = write; new_dev->name = new_name = (char *)(new_dev + 1); - strncpy (new_name, name, name_len); + strncpy(new_name, name, name_len); new_name[name_len] = '\0'; - debug ("miiphy_register: added '%s', read=0x%08lx, write=0x%08lx\n", + debug("miiphy_register: added '%s', read=0x%08lx, write=0x%08lx\n", new_dev->name, new_dev->read, new_dev->write); /* add it to the list */ - list_add_tail (&new_dev->link, &mii_devs); + list_add_tail(&new_dev->link, &mii_devs); if (!current_mii) current_mii = new_dev; @@ -220,20 +220,20 @@ int miiphy_write(const char *devname, unsigned char addr, unsigned char reg, * * Print out list of registered MII capable devices. */ -void miiphy_listdev (void) +void miiphy_listdev(void) { struct list_head *entry; struct mii_dev *dev; - puts ("MII devices: "); - list_for_each (entry, &mii_devs) { - dev = list_entry (entry, struct mii_dev, link); - printf ("'%s' ", dev->name); + puts("MII devices: "); + list_for_each(entry, &mii_devs) { + dev = list_entry(entry, struct mii_dev, link); + printf("'%s' ", dev->name); } - puts ("\n"); + puts("\n"); if (current_mii) - printf ("Current device: '%s'\n", current_mii->name); + printf("Current device: '%s'\n", current_mii->name); } /***************************************************************************** @@ -253,30 +253,30 @@ int miiphy_info(const char *devname, unsigned char addr, unsigned int *oui, unsigned int reg = 0; unsigned short tmp; - if (miiphy_read (devname, addr, MII_PHYSID2, &tmp) != 0) { - debug ("PHY ID register 2 read failed\n"); - return (-1); + if (miiphy_read(devname, addr, MII_PHYSID2, &tmp) != 0) { + debug("PHY ID register 2 read failed\n"); + return -1; } reg = tmp; - debug ("MII_PHYSID2 @ 0x%x = 0x%04x\n", addr, reg); + debug("MII_PHYSID2 @ 0x%x = 0x%04x\n", addr, reg); if (reg == 0xFFFF) { /* No physical device present at this address */ - return (-1); + return -1; } - if (miiphy_read (devname, addr, MII_PHYSID1, &tmp) != 0) { - debug ("PHY ID register 1 read failed\n"); - return (-1); + if (miiphy_read(devname, addr, MII_PHYSID1, &tmp) != 0) { + debug("PHY ID register 1 read failed\n"); + return -1; } reg |= tmp << 16; - debug ("PHY_PHYIDR[1,2] @ 0x%x = 0x%08x\n", addr, reg); + debug("PHY_PHYIDR[1,2] @ 0x%x = 0x%08x\n", addr, reg); *oui = (reg >> 10); *model = (unsigned char)((reg >> 4) & 0x0000003F); *rev = (unsigned char)(reg & 0x0000000F); - return (0); + return 0; } /***************************************************************************** @@ -290,16 +290,16 @@ int miiphy_reset(const char *devname, unsigned char addr) unsigned short reg; int timeout = 500; - if (miiphy_read (devname, addr, MII_BMCR, ®) != 0) { - debug ("PHY status read failed\n"); - return (-1); + if (miiphy_read(devname, addr, MII_BMCR, ®) != 0) { + debug("PHY status read failed\n"); + return -1; } - if (miiphy_write (devname, addr, MII_BMCR, reg | BMCR_RESET) != 0) { - debug ("PHY reset failed\n"); - return (-1); + if (miiphy_write(devname, addr, MII_BMCR, reg | BMCR_RESET) != 0) { + debug("PHY reset failed\n"); + return -1; } #ifdef CONFIG_PHY_RESET_DELAY - udelay (CONFIG_PHY_RESET_DELAY); /* Intel LXT971A needs this */ + udelay(CONFIG_PHY_RESET_DELAY); /* Intel LXT971A needs this */ #endif /* * Poll the control register for the reset bit to go to 0 (it is @@ -315,12 +315,12 @@ int miiphy_reset(const char *devname, unsigned char addr) udelay(1000); } if ((reg & 0x8000) == 0) { - return (0); + return 0; } else { - puts ("PHY reset timed out\n"); - return (-1); + puts("PHY reset timed out\n"); + return -1; } - return (0); + return 0; } /***************************************************************************** @@ -338,33 +338,33 @@ int miiphy_speed(const char *devname, unsigned char addr) * Check for 1000BASE-X. If it is supported, then assume that the speed * is 1000. */ - if (miiphy_is_1000base_x (devname, addr)) { + if (miiphy_is_1000base_x(devname, addr)) return _1000BASET; - } + /* * No 1000BASE-X, so assume 1000BASE-T/100BASE-TX/10BASE-T register set. */ /* Check for 1000BASE-T. */ - if (miiphy_read (devname, addr, MII_STAT1000, &btsr)) { - printf ("PHY 1000BT status"); + if (miiphy_read(devname, addr, MII_STAT1000, &btsr)) { + printf("PHY 1000BT status"); goto miiphy_read_failed; } if (btsr != 0xFFFF && - (btsr & (PHY_1000BTSR_1000FD | PHY_1000BTSR_1000HD))) { + (btsr & (PHY_1000BTSR_1000FD | PHY_1000BTSR_1000HD))) return _1000BASET; - } + #endif /* CONFIG_PHY_GIGE */ /* Check Basic Management Control Register first. */ - if (miiphy_read (devname, addr, MII_BMCR, &bmcr)) { - printf ("PHY speed"); + if (miiphy_read(devname, addr, MII_BMCR, &bmcr)) { + printf("PHY speed"); goto miiphy_read_failed; } /* Check if auto-negotiation is on. */ if (bmcr & BMCR_ANENABLE) { /* Get auto-negotiation results. */ - if (miiphy_read (devname, addr, MII_LPA, &anlpar)) { - printf ("PHY AN speed"); + if (miiphy_read(devname, addr, MII_LPA, &anlpar)) { + printf("PHY AN speed"); goto miiphy_read_failed; } return (anlpar & LPA_100) ? _100BASET : _10BASET; @@ -373,7 +373,7 @@ int miiphy_speed(const char *devname, unsigned char addr) return (bmcr & BMCR_SPEED100) ? _100BASET : _10BASET; miiphy_read_failed: - printf (" read failed, assuming 10BASE-T\n"); + printf(" read failed, assuming 10BASE-T\n"); return _10BASET; } @@ -389,10 +389,10 @@ int miiphy_duplex(const char *devname, unsigned char addr) u16 btsr; /* Check for 1000BASE-X. */ - if (miiphy_is_1000base_x (devname, addr)) { + if (miiphy_is_1000base_x(devname, addr)) { /* 1000BASE-X */ - if (miiphy_read (devname, addr, MII_LPA, &anlpar)) { - printf ("1000BASE-X PHY AN duplex"); + if (miiphy_read(devname, addr, MII_LPA, &anlpar)) { + printf("1000BASE-X PHY AN duplex"); goto miiphy_read_failed; } } @@ -400,8 +400,8 @@ int miiphy_duplex(const char *devname, unsigned char addr) * No 1000BASE-X, so assume 1000BASE-T/100BASE-TX/10BASE-T register set. */ /* Check for 1000BASE-T. */ - if (miiphy_read (devname, addr, MII_STAT1000, &btsr)) { - printf ("PHY 1000BT status"); + if (miiphy_read(devname, addr, MII_STAT1000, &btsr)) { + printf("PHY 1000BT status"); goto miiphy_read_failed; } if (btsr != 0xFFFF) { @@ -414,15 +414,15 @@ int miiphy_duplex(const char *devname, unsigned char addr) #endif /* CONFIG_PHY_GIGE */ /* Check Basic Management Control Register first. */ - if (miiphy_read (devname, addr, MII_BMCR, &bmcr)) { - puts ("PHY duplex"); + if (miiphy_read(devname, addr, MII_BMCR, &bmcr)) { + puts("PHY duplex"); goto miiphy_read_failed; } /* Check if auto-negotiation is on. */ if (bmcr & BMCR_ANENABLE) { /* Get auto-negotiation results. */ - if (miiphy_read (devname, addr, MII_LPA, &anlpar)) { - puts ("PHY AN duplex"); + if (miiphy_read(devname, addr, MII_LPA, &anlpar)) { + puts("PHY AN duplex"); goto miiphy_read_failed; } return (anlpar & (LPA_10FULL | LPA_100FULL)) ? @@ -432,7 +432,7 @@ int miiphy_duplex(const char *devname, unsigned char addr) return (bmcr & BMCR_FULLDPLX) ? FULL : HALF; miiphy_read_failed: - printf (" read failed, assuming half duplex\n"); + printf(" read failed, assuming half duplex\n"); return HALF; } @@ -446,8 +446,8 @@ int miiphy_is_1000base_x(const char *devname, unsigned char addr) #if defined(CONFIG_PHY_GIGE) u16 exsr; - if (miiphy_read (devname, addr, MII_ESTATUS, &exsr)) { - printf ("PHY extended status read failed, assuming no " + if (miiphy_read(devname, addr, MII_ESTATUS, &exsr)) { + printf("PHY extended status read failed, assuming no " "1000BASE-X\n"); return 0; } @@ -467,17 +467,17 @@ int miiphy_link(const char *devname, unsigned char addr) unsigned short reg; /* dummy read; needed to latch some phys */ - (void)miiphy_read (devname, addr, MII_BMSR, ®); - if (miiphy_read (devname, addr, MII_BMSR, ®)) { - puts ("MII_BMSR read failed, assuming no link\n"); - return (0); + (void)miiphy_read(devname, addr, MII_BMSR, ®); + if (miiphy_read(devname, addr, MII_BMSR, ®)) { + puts("MII_BMSR read failed, assuming no link\n"); + return 0; } /* Determine if a link is active */ if ((reg & BMSR_LSTATUS) != 0) { - return (1); + return 1; } else { - return (0); + return 0; } } #endif -- cgit v1.2.1 From 5f184715ecd31bfcb8d09ba2d9f14adfa172a141 Mon Sep 17 00:00:00 2001 From: Andy Fleming Date: Fri, 8 Apr 2011 02:10:27 -0500 Subject: Create PHY Lib for U-Boot Extends the mii_dev structure to participate in a full-blown MDIO and PHY driver scheme. The mii_dev structure and miiphy calls are modified in such a way to allow the original mii command and miiphy infrastructure to work as before, but also to support a new set of APIs which allow (among other things) sharing of PHY driver code and 10G support The mii command will continue to support normal PHY management functions (Clause 22 of 802.3), but will not be changed to support 10G (Clause 45). The basic design is similar to PHY Lib from Linux, but simplified for U-Boot's network and driver infrastructure. We now have MDIO drivers and PHY drivers An MDIO driver provides: read write reset A PHY driver provides: (optionally): probe config - initial setup, starting of auto-negotiation startup - waiting for AN, and reading link state shutdown - any cleanup needed The ethernet drivers interact with the PHY Lib using these functions: phy_connect() phy_config() phy_startup() phy_shutdown() Each PHY driver can be configured separately, or all at once using config_phylib_all_drivers.h (added in the patch which adds the drivers) We also provide generic drivers for Clause 22 (10/100/1000), and Clause 45 (10G) PHYs. We also implement phy_reset(), and call it in phy_connect(). Because phy_reset() is essentially the same as miiphy_reset, but: a) must support 10G PHYs, and b) should use the phylib primitives, we implement miiphy_reset, using phy_reset(), but only when CONFIG_PHYLIB is set. Otherwise, we just use the old version. In this way, we save on compile size, even if we don't manage to save code size. Pulled ethtool.h and mdio.h from: git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6 782d640afd15af7a1faf01cfe566ca4ac511319d With many, many deletions so as to enable compilation under u-boot Signed-off-by: Andy Fleming Signed-off-by: Kumar Gala Acked-by: Detlev Zundel --- common/Makefile | 1 + common/miiphyutil.c | 181 +++++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 146 insertions(+), 36 deletions(-) (limited to 'common') diff --git a/common/Makefile b/common/Makefile index 4555716108..02dbeedcee 100644 --- a/common/Makefile +++ b/common/Makefile @@ -115,6 +115,7 @@ COBJS-$(CONFIG_CMD_MFSL) += cmd_mfsl.o COBJS-$(CONFIG_CMD_MG_DISK) += cmd_mgdisk.o COBJS-$(CONFIG_MII) += miiphyutil.o COBJS-$(CONFIG_CMD_MII) += miiphyutil.o +COBJS-$(CONFIG_PHYLIB) += miiphyutil.o COBJS-$(CONFIG_CMD_MII) += cmd_mii.o COBJS-$(CONFIG_CMD_MISC) += cmd_misc.o COBJS-$(CONFIG_CMD_MMC) += cmd_mmc.o diff --git a/common/miiphyutil.c b/common/miiphyutil.c index 6944ea7730..243cae97a4 100644 --- a/common/miiphyutil.c +++ b/common/miiphyutil.c @@ -28,6 +28,7 @@ #include #include +#include #include #include @@ -44,22 +45,13 @@ #define debug(fmt, args...) #endif /* MII_DEBUG */ -struct mii_dev { - struct list_head link; - const char *name; - int (*read)(const char *devname, unsigned char addr, - unsigned char reg, unsigned short *value); - int (*write)(const char *devname, unsigned char addr, - unsigned char reg, unsigned short value); -}; - static struct list_head mii_devs; static struct mii_dev *current_mii; /* * Lookup the mii_dev struct by the registered device name. */ -static struct mii_dev *miiphy_get_dev_by_name(const char *devname, int quiet) +struct mii_dev *miiphy_get_dev_by_name(const char *devname) { struct list_head *entry; struct mii_dev *dev; @@ -75,8 +67,6 @@ static struct mii_dev *miiphy_get_dev_by_name(const char *devname, int quiet) return dev; } - if (!quiet) - printf("No such device: %s\n", devname); return NULL; } @@ -90,6 +80,25 @@ void miiphy_init(void) current_mii = NULL; } +static int legacy_miiphy_read(struct mii_dev *bus, int addr, int devad, int reg) +{ + unsigned short val; + int ret; + struct legacy_mii_dev *ldev = bus->priv; + + ret = ldev->read(bus->name, addr, reg, &val); + + return ret ? -1 : (int)val; +} + +static int legacy_miiphy_write(struct mii_dev *bus, int addr, int devad, + int reg, u16 val) +{ + struct legacy_mii_dev *ldev = bus->priv; + + return ldev->write(bus->name, addr, reg, val); +} + /***************************************************************************** * * Register read and write MII access routines for the device . @@ -101,11 +110,11 @@ void miiphy_register(const char *name, unsigned char reg, unsigned short value)) { struct mii_dev *new_dev; + struct legacy_mii_dev *ldev; unsigned int name_len; - char *new_name; /* check if we have unique name */ - new_dev = miiphy_get_dev_by_name(name, 1); + new_dev = miiphy_get_dev_by_name(name); if (new_dev) { printf("miiphy_register: non unique device name '%s'\n", name); return; @@ -113,26 +122,32 @@ void miiphy_register(const char *name, /* allocate memory */ name_len = strlen(name); - new_dev = - (struct mii_dev *)malloc(sizeof(struct mii_dev) + name_len + 1); + if (name_len > MDIO_NAME_LEN - 1) { + /* Hopefully this won't happen, but if it does, we'll know */ + printf("miiphy_register: MDIO name was longer than %d\n", + MDIO_NAME_LEN); + return; + } - if (new_dev == NULL) { + new_dev = mdio_alloc(); + ldev = malloc(sizeof(*ldev)); + + if (new_dev == NULL || ldev == NULL) { printf("miiphy_register: cannot allocate memory for '%s'\n", name); return; } - memset(new_dev, 0, sizeof(struct mii_dev) + name_len); /* initalize mii_dev struct fields */ - INIT_LIST_HEAD(&new_dev->link); - new_dev->read = read; - new_dev->write = write; - new_dev->name = new_name = (char *)(new_dev + 1); - strncpy(new_name, name, name_len); - new_name[name_len] = '\0'; + new_dev->read = legacy_miiphy_read; + new_dev->write = legacy_miiphy_write; + sprintf(new_dev->name, name); + ldev->read = read; + ldev->write = write; + new_dev->priv = ldev; debug("miiphy_register: added '%s', read=0x%08lx, write=0x%08lx\n", - new_dev->name, new_dev->read, new_dev->write); + new_dev->name, ldev->read, ldev->write); /* add it to the list */ list_add_tail(&new_dev->link, &mii_devs); @@ -141,19 +156,110 @@ void miiphy_register(const char *name, current_mii = new_dev; } +struct mii_dev *mdio_alloc(void) +{ + struct mii_dev *bus; + + bus = malloc(sizeof(*bus)); + if (!bus) + return bus; + + memset(bus, 0, sizeof(*bus)); + + /* initalize mii_dev struct fields */ + INIT_LIST_HEAD(&bus->link); + + return bus; +} + +int mdio_register(struct mii_dev *bus) +{ + if (!bus || !bus->name || !bus->read || !bus->write) + return -1; + + /* check if we have unique name */ + if (miiphy_get_dev_by_name(bus->name)) { + printf("mdio_register: non unique device name '%s'\n", + bus->name); + return -1; + } + + /* add it to the list */ + list_add_tail(&bus->link, &mii_devs); + + if (!current_mii) + current_mii = bus; + + return 0; +} + +void mdio_list_devices(void) +{ + struct list_head *entry; + + list_for_each(entry, &mii_devs) { + int i; + struct mii_dev *bus = list_entry(entry, struct mii_dev, link); + + printf("%s:\n", bus->name); + + for (i = 0; i < PHY_MAX_ADDR; i++) { + struct phy_device *phydev = bus->phymap[i]; + + if (phydev) { + printf("%d - %s", i, phydev->drv->name); + + if (phydev->dev) + printf(" <--> %s\n", phydev->dev->name); + else + printf("\n"); + } + } + } +} + int miiphy_set_current_dev(const char *devname) { struct mii_dev *dev; - dev = miiphy_get_dev_by_name(devname, 0); + dev = miiphy_get_dev_by_name(devname); if (dev) { current_mii = dev; return 0; } + printf("No such device: %s\n", devname); + return 1; } +struct mii_dev *mdio_get_current_dev(void) +{ + return current_mii; +} + +struct phy_device *mdio_phydev_for_ethname(const char *ethname) +{ + struct list_head *entry; + struct mii_dev *bus; + + list_for_each(entry, &mii_devs) { + int i; + bus = list_entry(entry, struct mii_dev, link); + + for (i = 0; i < PHY_MAX_ADDR; i++) { + if (!bus->phymap[i] || !bus->phymap[i]->dev) + continue; + + if (strcmp(bus->phymap[i]->dev->name, ethname) == 0) + return bus->phymap[i]; + } + } + + printf("%s is not a known ethernet\n", ethname); + return NULL; +} + const char *miiphy_get_current_dev(void) { if (current_mii) @@ -187,13 +293,15 @@ static struct mii_dev *miiphy_get_active_dev(const char *devname) int miiphy_read(const char *devname, unsigned char addr, unsigned char reg, unsigned short *value) { - struct mii_dev *dev; + struct mii_dev *bus; - dev = miiphy_get_active_dev(devname); - if (dev) - return dev->read(devname, addr, reg, value); + bus = miiphy_get_active_dev(devname); + if (bus) + *value = bus->read(bus, addr, MDIO_DEVAD_NONE, reg); + else + return 1; - return 1; + return (*value < 0) ? 1 : 0; } /***************************************************************************** @@ -207,11 +315,11 @@ int miiphy_read(const char *devname, unsigned char addr, unsigned char reg, int miiphy_write(const char *devname, unsigned char addr, unsigned char reg, unsigned short value) { - struct mii_dev *dev; + struct mii_dev *bus; - dev = miiphy_get_active_dev(devname); - if (dev) - return dev->write(devname, addr, reg, value); + bus = miiphy_get_active_dev(devname); + if (bus) + return bus->write(bus, addr, MDIO_DEVAD_NONE, reg, value); return 1; } @@ -279,6 +387,7 @@ int miiphy_info(const char *devname, unsigned char addr, unsigned int *oui, return 0; } +#ifndef CONFIG_PHYLIB /***************************************************************************** * * Reset the PHY. @@ -322,6 +431,7 @@ int miiphy_reset(const char *devname, unsigned char addr) } return 0; } +#endif /* !PHYLIB */ /***************************************************************************** * @@ -352,7 +462,6 @@ int miiphy_speed(const char *devname, unsigned char addr) if (btsr != 0xFFFF && (btsr & (PHY_1000BTSR_1000FD | PHY_1000BTSR_1000HD))) return _1000BASET; - #endif /* CONFIG_PHY_GIGE */ /* Check Basic Management Control Register first. */ -- cgit v1.2.1 From 995daa0b81f35c93a1d14e5c6a932bc304d06718 Mon Sep 17 00:00:00 2001 From: Andy Fleming Date: Mon, 21 Mar 2011 18:03:22 -0500 Subject: Add mdio command for new PHY infrastructure The new mdio command doesn't have all of the features of the mii command, but it provides the necessary read/write primitives, and allows users to interact with 10G PHYs, and other PHYs which use Clause 45 of 802.3. This means that the mdio command requires a "Device Address" argument, though for clause 22 PHYs, the argument can be "-". Signed-off-by: Andy Fleming Acked-by: Detlev Zundel --- common/Makefile | 3 + common/cmd_mdio.c | 286 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 289 insertions(+) create mode 100644 common/cmd_mdio.c (limited to 'common') diff --git a/common/Makefile b/common/Makefile index 02dbeedcee..5f0c5340a0 100644 --- a/common/Makefile +++ b/common/Makefile @@ -117,6 +117,9 @@ COBJS-$(CONFIG_MII) += miiphyutil.o COBJS-$(CONFIG_CMD_MII) += miiphyutil.o COBJS-$(CONFIG_PHYLIB) += miiphyutil.o COBJS-$(CONFIG_CMD_MII) += cmd_mii.o +ifdef CONFIG_PHYLIB +COBJS-$(CONFIG_CMD_MII) += cmd_mdio.o +endif COBJS-$(CONFIG_CMD_MISC) += cmd_misc.o COBJS-$(CONFIG_CMD_MMC) += cmd_mmc.o COBJS-$(CONFIG_MP) += cmd_mp.o diff --git a/common/cmd_mdio.c b/common/cmd_mdio.c new file mode 100644 index 0000000000..cac0703089 --- /dev/null +++ b/common/cmd_mdio.c @@ -0,0 +1,286 @@ +/* + * (C) Copyright 2011 Freescale Semiconductor, Inc + * Andy Fleming + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* + * MDIO Commands + */ + +#include +#include +#include +#include + + +static char last_op[2]; +static uint last_data; +static uint last_addr_lo; +static uint last_addr_hi; +static uint last_devad_lo; +static uint last_devad_hi; +static uint last_reg_lo; +static uint last_reg_hi; + +static int extract_range(char *input, int *plo, int *phi) +{ + char *end; + *plo = simple_strtol(input, &end, 0); + if (end == input) + return -1; + + if ((*end == '-') && *(++end)) + *phi = simple_strtol(end, NULL, 0); + else if (*end == '\0') + *phi = *plo; + else + return -1; + + return 0; +} + +int mdio_write_ranges(struct mii_dev *bus, int addrlo, + int addrhi, int devadlo, int devadhi, + int reglo, int reghi, unsigned short data) +{ + int addr, devad, reg; + int err = 0; + + for (addr = addrlo; addr <= addrhi; addr++) { + for (devad = devadlo; devad <= devadhi; devad++) { + for (reg = reglo; reg <= reghi; reg++) { + err = bus->write(bus, addr, devad, reg, data); + + if (err) + goto err_out; + } + } + } + +err_out: + return err; +} + +int mdio_read_ranges(struct mii_dev *bus, int addrlo, + int addrhi, int devadlo, int devadhi, + int reglo, int reghi) +{ + int addr, devad, reg; + + printf("Reading from bus %s\n", bus->name); + for (addr = addrlo; addr <= addrhi; addr++) { + printf("PHY at address %d:\n", addr); + + for (devad = devadlo; devad <= devadhi; devad++) { + for (reg = reglo; reg <= reghi; reg++) { + u16 val; + val = bus->read(bus, addr, devad, reg); + + if (val < 0) { + printf("Error\n"); + + return val; + } + + if (devad >= 0) + printf("%d.", devad); + + printf("%d - 0x%x\n", reg, val & 0xffff); + } + } + } + + return 0; +} + +/* The register will be in the form [a[-b].]x[-y] */ +int extract_reg_range(char *input, int *devadlo, int *devadhi, + int *reglo, int *reghi) +{ + char *regstr; + + /* use strrchr to find the last string after a '.' */ + regstr = strrchr(input, '.'); + + /* If it exists, extract the devad(s) */ + if (regstr) { + char devadstr[32]; + + strncpy(devadstr, input, regstr - input); + devadstr[regstr - input] = '\0'; + + if (extract_range(devadstr, devadlo, devadhi)) + return -1; + + regstr++; + } else { + /* Otherwise, we have no devad, and we just got regs */ + *devadlo = *devadhi = MDIO_DEVAD_NONE; + + regstr = input; + } + + return extract_range(regstr, reglo, reghi); +} + +int extract_phy_range(char *const argv[], int argc, struct mii_dev **bus, + int *addrlo, int *addrhi) +{ + struct phy_device *phydev; + + if ((argc < 1) || (argc > 2)) + return -1; + + /* If there are two arguments, it's busname addr */ + if (argc == 2) { + *bus = miiphy_get_dev_by_name(argv[0]); + + if (!*bus) + return -1; + + return extract_range(argv[1], addrlo, addrhi); + } + + /* It must be one argument, here */ + + /* + * This argument can be one of two things: + * 1) Ethernet device name + * 2) Just an address (use the previously-used bus) + * + * We check all buses for a PHY which is connected to an ethernet + * device by the given name. If none are found, we call + * extract_range() on the string, and see if it's an address range. + */ + phydev = mdio_phydev_for_ethname(argv[0]); + + if (phydev) { + *addrlo = *addrhi = phydev->addr; + *bus = phydev->bus; + + return 0; + } + + /* It's an address or nothing useful */ + return extract_range(argv[0], addrlo, addrhi); +} + +/* ---------------------------------------------------------------- */ +static int do_mdio(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + char op[2]; + int addrlo, addrhi, reglo, reghi, devadlo, devadhi; + unsigned short data; + int pos = argc - 1; + struct mii_dev *bus; + + if (argc < 2) + return cmd_usage(cmdtp); + + /* + * We use the last specified parameters, unless new ones are + * entered. + */ + op[0] = argv[1][0]; + addrlo = last_addr_lo; + addrhi = last_addr_hi; + devadlo = last_devad_lo; + devadhi = last_devad_hi; + reglo = last_reg_lo; + reghi = last_reg_hi; + data = last_data; + + bus = mdio_get_current_dev(); + + if (flag & CMD_FLAG_REPEAT) + op[0] = last_op[0]; + + switch (op[0]) { + case 'w': + if (pos > 1) + data = simple_strtoul(argv[pos--], NULL, 16); + case 'r': + if (pos > 1) + if (extract_reg_range(argv[pos--], &devadlo, &devadhi, + ®lo, ®hi)) + return -1; + + default: + if (pos > 1) + if (extract_phy_range(&(argv[2]), pos - 1, &bus, + &addrlo, &addrhi)) + return -1; + + break; + } + + if (op[0] == 'l') { + mdio_list_devices(); + + return 0; + } + + /* Save the chosen bus */ + miiphy_set_current_dev(bus->name); + + switch (op[0]) { + case 'w': + mdio_write_ranges(bus, addrlo, addrhi, devadlo, devadhi, + reglo, reghi, data); + break; + + case 'r': + mdio_read_ranges(bus, addrlo, addrhi, devadlo, devadhi, + reglo, reghi); + break; + } + + /* + * Save the parameters for repeats. + */ + last_op[0] = op[0]; + last_addr_lo = addrlo; + last_addr_hi = addrhi; + last_devad_lo = devadlo; + last_devad_hi = devadhi; + last_reg_lo = reglo; + last_reg_hi = reghi; + last_data = data; + + return 0; +} + +/***************************************************/ + +U_BOOT_CMD( + mdio, 6, 1, do_mdio, + "MDIO utility commands", + "list - List MDIO buses\n" + "mdio read [.] - " + "read PHY's register at .\n" + "mdio write [.] - " + "write PHY's register at .\n" + " may be:\n" + " \n" + " \n" + " \n" + " , and may be ranges, e.g. 1-5.4-0x1f.\n" +); -- cgit v1.2.1