[U-Boot] [PATCH 1/3] phy: add phy_connect_by_mask

It is useful to be able to try a range of possible phy addresses to connect.
Signed-off-by: Troy Kisky troy.kisky@boundarydevices.com --- drivers/net/phy/phy.c | 108 +++++++++++++++++++++++++++++++------------------ include/phy.h | 2 + 2 files changed, 71 insertions(+), 39 deletions(-)
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index baef60f..a22d2e0 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -31,6 +31,7 @@ #include <miiphy.h> #include <phy.h> #include <errno.h> +#include <linux/err.h>
/* Generic PHY support and helper functions */
@@ -573,6 +574,61 @@ int get_phy_id(struct mii_dev *bus, int addr, int devad, u32 *phy_id) return 0; }
+static struct phy_device *create_phy_by_mask(struct mii_dev *bus, + unsigned phy_mask, int devad, phy_interface_t interface) +{ + u32 phy_id = 0xffffffff; + while (phy_mask) { + int addr = ffs(phy_mask) - 1; + int r = get_phy_id(bus, addr, devad, &phy_id); + if (r < 0) + return ERR_PTR(r); + /* If the PHY ID is mostly f's, we didn't find anything */ + if ((phy_id & 0x1fffffff) != 0x1fffffff) + return phy_device_create(bus, addr, phy_id, interface); + phy_mask &= ~(1 << addr); + } + return NULL; +} + +static struct phy_device *search_for_existing_phy(struct mii_dev *bus, + unsigned phy_mask, phy_interface_t interface) +{ + /* If we have one, return the existing device, with new interface */ + while (phy_mask) { + int addr = ffs(phy_mask) - 1; + if (bus->phymap[addr]) { + bus->phymap[addr]->interface = interface; + return bus->phymap[addr]; + } + phy_mask &= ~(1 << addr); + } + return NULL; +} + +static struct phy_device *get_phy_device_by_mask(struct mii_dev *bus, + unsigned phy_mask, phy_interface_t interface) +{ + int i; + struct phy_device *phydev; + + phydev = search_for_existing_phy(bus, phy_mask, interface); + if (phydev) + return phydev; + /* Try Standard (ie Clause 22) access */ + /* Otherwise we have to try Clause 45 */ + for (i = 0; i < 5; i++) { + phydev = create_phy_by_mask(bus, phy_mask, + i ? i : MDIO_DEVAD_NONE, interface); + if (IS_ERR(phydev)) + return NULL; + if (phydev) + return phydev; + } + printf("Phy not found\n"); + return phy_device_create(bus, ffs(phy_mask) - 1, 0xffffffff, interface); +} + /** * get_phy_device - reads the specified PHY device and returns its @phy_device struct * @bus: the target MII bus @@ -584,38 +640,7 @@ int get_phy_id(struct mii_dev *bus, int addr, int devad, u32 *phy_id) struct phy_device *get_phy_device(struct mii_dev *bus, int addr, phy_interface_t interface) { - u32 phy_id = 0x1fffffff; - int i; - int r; - - /* If we have one, return the existing device, with new interface */ - if (bus->phymap[addr]) { - bus->phymap[addr]->interface = interface; - - return bus->phymap[addr]; - } - - /* Try Standard (ie Clause 22) access */ - r = get_phy_id(bus, addr, MDIO_DEVAD_NONE, &phy_id); - if (r) - return NULL; - - /* If the PHY ID is mostly f's, we didn't find anything */ - if ((phy_id & 0x1fffffff) != 0x1fffffff) - return phy_device_create(bus, addr, phy_id, interface); - - /* Otherwise we have to try Clause 45 */ - for (i = 1; i < 5; i++) { - r = get_phy_id(bus, addr, i, &phy_id); - if (r) - return NULL; - - /* If the phy_id is mostly Fs, there is no device there */ - if ((phy_id & 0x1fffffff) != 0x1fffffff) - break; - } - - return phy_device_create(bus, addr, phy_id, interface); + return get_phy_device_by_mask(bus, 1 << addr, interface); }
int phy_reset(struct phy_device *phydev) @@ -688,9 +713,8 @@ int miiphy_reset(const char *devname, unsigned char addr) return phy_reset(phydev); }
-struct phy_device *phy_connect(struct mii_dev *bus, int addr, - struct eth_device *dev, - phy_interface_t interface) +struct phy_device *phy_connect_by_mask(struct mii_dev *bus, unsigned phy_mask, + struct eth_device *dev, phy_interface_t interface) { struct phy_device *phydev;
@@ -701,11 +725,11 @@ struct phy_device *phy_connect(struct mii_dev *bus, int addr, /* Wait 15ms to make sure the PHY has come out of hard reset */ udelay(15000);
- phydev = get_phy_device(bus, addr, interface); + phydev = get_phy_device_by_mask(bus, phy_mask, interface);
if (!phydev) { - printf("Could not get PHY for %s:%d\n", bus->name, addr); - + printf("Could not get PHY for %s: phy mask %x\n", + bus->name, phy_mask); return NULL; }
@@ -714,7 +738,7 @@ struct phy_device *phy_connect(struct mii_dev *bus, int addr,
if (phydev->dev) printf("%s:%d is connected to %s. Reconnecting to %s\n", - bus->name, addr, phydev->dev->name, dev->name); + bus->name, phydev->addr, phydev->dev->name, dev->name);
phydev->dev = dev;
@@ -723,6 +747,12 @@ struct phy_device *phy_connect(struct mii_dev *bus, int addr, return phydev; }
+struct phy_device *phy_connect(struct mii_dev *bus, int addr, + struct eth_device *dev, phy_interface_t interface) +{ + return phy_connect_by_mask(bus, 1 << addr, dev, interface); +} + /* * Start the PHY. Returns 0 on success, or a negative error code. */ diff --git a/include/phy.h b/include/phy.h index 3c30f11..aea462f 100644 --- a/include/phy.h +++ b/include/phy.h @@ -202,6 +202,8 @@ int phy_reset(struct phy_device *phydev); struct phy_device *phy_connect(struct mii_dev *bus, int addr, struct eth_device *dev, phy_interface_t interface); +struct phy_device *phy_connect_by_mask(struct mii_dev *bus, unsigned phy_mask, + struct eth_device *dev, phy_interface_t interface); int phy_startup(struct phy_device *phydev); int phy_config(struct phy_device *phydev); int phy_shutdown(struct phy_device *phydev);

Allow board config files to list a range of possible phy addresses, in case the exact phy address is not certain.
Signed-off-by: Troy Kisky troy.kisky@boundarydevices.com --- drivers/net/fec_mxc.c | 21 +++++++++++++++------ drivers/net/fec_mxc.h | 3 ++- 2 files changed, 17 insertions(+), 7 deletions(-)
diff --git a/drivers/net/fec_mxc.c b/drivers/net/fec_mxc.c index fbfc842..4af4976 100644 --- a/drivers/net/fec_mxc.c +++ b/drivers/net/fec_mxc.c @@ -391,7 +391,7 @@ static void fec_eth_phy_config(struct eth_device *dev) struct fec_priv *fec = (struct fec_priv *)dev->priv; struct phy_device *phydev;
- phydev = phy_connect(fec->bus, fec->phy_id, dev, + phydev = phy_connect_by_mask(fec->bus, fec->phy_mask, dev, PHY_INTERFACE_MODE_RGMII); if (phydev) { fec->phydev = phydev; @@ -898,7 +898,8 @@ static int fec_recv(struct eth_device *dev) return len; }
-static int fec_probe(bd_t *bd, int dev_id, int phy_id, uint32_t base_addr) +static int fec_probe(bd_t *bd, int dev_id, unsigned phy_mask, + uint32_t base_addr) { struct eth_device *edev; struct fec_priv *fec; @@ -958,8 +959,11 @@ static int fec_probe(bd_t *bd, int dev_id, int phy_id, uint32_t base_addr) sprintf(edev->name, "FEC%i", dev_id); fec->dev_id = dev_id; } - fec->phy_id = phy_id; - +#ifdef CONFIG_PHYLIB + fec->phy_mask = phy_mask; +#else + fec->phy_id = ffs(phy_mask) - 1; +#endif bus = mdio_alloc(); if (!bus) { printf("mdio_alloc failed\n"); @@ -1008,9 +1012,14 @@ err1: int fecmxc_initialize(bd_t *bd) { int lout = 1; +#ifdef CONFIG_FEC_MXC_PHYMASK + unsigned phy_mask = CONFIG_FEC_MXC_PHYMASK; +#else + unsigned phy_mask = 1 << CONFIG_FEC_MXC_PHYADDR; +#endif
debug("eth_init: fec_probe(bd)\n"); - lout = fec_probe(bd, -1, CONFIG_FEC_MXC_PHYADDR, IMX_FEC_BASE); + lout = fec_probe(bd, -1, phy_mask, IMX_FEC_BASE);
return lout; } @@ -1021,7 +1030,7 @@ int fecmxc_initialize_multi(bd_t *bd, int dev_id, int phy_id, uint32_t addr) int lout = 1;
debug("eth_init: fec_probe(bd, %i, %i) @ %08x\n", dev_id, phy_id, addr); - lout = fec_probe(bd, dev_id, phy_id, addr); + lout = fec_probe(bd, dev_id, 1 << phy_id, addr);
return lout; } diff --git a/drivers/net/fec_mxc.h b/drivers/net/fec_mxc.h index 852b2e0..a0f50af 100644 --- a/drivers/net/fec_mxc.h +++ b/drivers/net/fec_mxc.h @@ -268,11 +268,12 @@ struct fec_priv { bd_t *bd; uint8_t *tdb_ptr; int dev_id; - int phy_id; struct mii_dev *bus; #ifdef CONFIG_PHYLIB + int phy_mask; struct phy_device *phydev; #else + int phy_id; int (*mii_postcall)(int); #endif };

On 15/08/2012 22:40, Troy Kisky wrote:
Allow board config files to list a range of possible phy addresses, in case the exact phy address is not certain.
Signed-off-by: Troy Kisky troy.kisky@boundarydevices.com
Hi Troy,
drivers/net/fec_mxc.c | 21 +++++++++++++++------ drivers/net/fec_mxc.h | 3 ++- 2 files changed, 17 insertions(+), 7 deletions(-)
diff --git a/drivers/net/fec_mxc.c b/drivers/net/fec_mxc.c index fbfc842..4af4976 100644 --- a/drivers/net/fec_mxc.c +++ b/drivers/net/fec_mxc.c @@ -391,7 +391,7 @@ static void fec_eth_phy_config(struct eth_device *dev) struct fec_priv *fec = (struct fec_priv *)dev->priv; struct phy_device *phydev;
- phydev = phy_connect(fec->bus, fec->phy_id, dev,
- phydev = phy_connect_by_mask(fec->bus, fec->phy_mask, dev, PHY_INTERFACE_MODE_RGMII); if (phydev) { fec->phydev = phydev;
@@ -898,7 +898,8 @@ static int fec_recv(struct eth_device *dev) return len; }
-static int fec_probe(bd_t *bd, int dev_id, int phy_id, uint32_t base_addr) +static int fec_probe(bd_t *bd, int dev_id, unsigned phy_mask,
uint32_t base_addr)
{ struct eth_device *edev; struct fec_priv *fec; @@ -958,8 +959,11 @@ static int fec_probe(bd_t *bd, int dev_id, int phy_id, uint32_t base_addr) sprintf(edev->name, "FEC%i", dev_id); fec->dev_id = dev_id; }
- fec->phy_id = phy_id;
+#ifdef CONFIG_PHYLIB
- fec->phy_mask = phy_mask;
+#else
- fec->phy_id = ffs(phy_mask) - 1;
+#endif bus = mdio_alloc(); if (!bus) { printf("mdio_alloc failed\n"); @@ -1008,9 +1012,14 @@ err1: int fecmxc_initialize(bd_t *bd) { int lout = 1; +#ifdef CONFIG_FEC_MXC_PHYMASK
- unsigned phy_mask = CONFIG_FEC_MXC_PHYMASK;
+#else
- unsigned phy_mask = 1 << CONFIG_FEC_MXC_PHYADDR;
+#endif
debug("eth_init: fec_probe(bd)\n");
- lout = fec_probe(bd, -1, CONFIG_FEC_MXC_PHYADDR, IMX_FEC_BASE);
lout = fec_probe(bd, -1, phy_mask, IMX_FEC_BASE);
return lout;
} @@ -1021,7 +1030,7 @@ int fecmxc_initialize_multi(bd_t *bd, int dev_id, int phy_id, uint32_t addr) int lout = 1;
debug("eth_init: fec_probe(bd, %i, %i) @ %08x\n", dev_id, phy_id, addr);
- lout = fec_probe(bd, dev_id, phy_id, addr);
lout = fec_probe(bd, dev_id, 1 << phy_id, addr);
return lout;
} diff --git a/drivers/net/fec_mxc.h b/drivers/net/fec_mxc.h index 852b2e0..a0f50af 100644 --- a/drivers/net/fec_mxc.h +++ b/drivers/net/fec_mxc.h @@ -268,11 +268,12 @@ struct fec_priv { bd_t *bd; uint8_t *tdb_ptr; int dev_id;
- int phy_id; struct mii_dev *bus;
#ifdef CONFIG_PHYLIB
- int phy_mask; struct phy_device *phydev;
#else
- int phy_id; int (*mii_postcall)(int);
#endif };
I generally agree with this patchset. My only concern is that we add a new CONFIG_ option without documentation. Can you add an entry into the README file (I know, a lot of CONFIG_ are missing, but we can at least avoid to add hidden features..).
Best regards, Stefano Babic

On 8/17/2012 3:20 AM, Stefano Babic wrote:
I generally agree with this patchset. My only concern is that we add a new CONFIG_ option without documentation. Can you add an entry into the README file (I know, a lot of CONFIG_ are missing, but we can at least avoid to add hidden features..). Best regards, Stefano Babic
Will do
Thanks Troy

Different ethernet jacks parts can result in the Micrel KSZ9021 getting a different phy address. Let's support all parts.
Signed-off-by: Troy Kisky troy.kisky@boundarydevices.com --- include/configs/mx6qsabrelite.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/include/configs/mx6qsabrelite.h b/include/configs/mx6qsabrelite.h index 782abc8..44b8c7f 100644 --- a/include/configs/mx6qsabrelite.h +++ b/include/configs/mx6qsabrelite.h @@ -99,7 +99,7 @@ #define IMX_FEC_BASE ENET_BASE_ADDR #define CONFIG_FEC_XCV_TYPE RGMII #define CONFIG_ETHPRIME "FEC" -#define CONFIG_FEC_MXC_PHYADDR 6 +#define CONFIG_FEC_MXC_PHYMASK (0xf << 4) /* scan phy 4,5,6,7 */ #define CONFIG_PHYLIB #define CONFIG_PHY_MICREL #define CONFIG_PHY_MICREL_KSZ9021
participants (2)
-
Stefano Babic
-
Troy Kisky