X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=drivers%2Fnet%2Fphy%2Fphy.c;h=f2d17aa91a07e394f968d1cf6343cae36301a35a;hb=44fb0d6c9f5147a41c710032869e5e01b3c9e310;hp=e31f3aa3a989c66741b83cd425d933a3796792cd;hpb=fdb6c3232f66bc9c07c30de87928506477ac4e63;p=platform%2Fkernel%2Fu-boot.git diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index e31f3aa..f2d17aa 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -1,15 +1,12 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * Generic PHY Management code * - * SPDX-License-Identifier: GPL-2.0+ - * * Copyright 2011 Freescale Semiconductor, Inc. * author Andy Fleming * * Based loosely off of Linux's PHY Lib */ - -#include #include #include #include @@ -27,7 +24,7 @@ DECLARE_GLOBAL_DATA_PTR; /* Generic PHY support and helper functions */ /** - * genphy_config_advert - sanitize and advertise auto-negotation parameters + * genphy_config_advert - sanitize and advertise auto-negotiation parameters * @phydev: target phy_device struct * * Description: Writes MII_ADVERTISE with the appropriate values, @@ -117,7 +114,6 @@ static int genphy_config_advert(struct phy_device *phydev) return changed; } - /** * genphy_setup_forced - configures/forces speed/duplex from @phydev * @phydev: target phy_device struct @@ -130,14 +126,15 @@ static int genphy_setup_forced(struct phy_device *phydev) int err; int ctl = BMCR_ANRESTART; - phydev->pause = phydev->asym_pause = 0; + phydev->pause = 0; + phydev->asym_pause = 0; - if (SPEED_1000 == phydev->speed) + if (phydev->speed == SPEED_1000) ctl |= BMCR_SPEED1000; - else if (SPEED_100 == phydev->speed) + else if (phydev->speed == SPEED_100) ctl |= BMCR_SPEED100; - if (DUPLEX_FULL == phydev->duplex) + if (phydev->duplex == DUPLEX_FULL) ctl |= BMCR_FULLDPLX; err = phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, ctl); @@ -145,7 +142,6 @@ static int genphy_setup_forced(struct phy_device *phydev) return err; } - /** * genphy_restart_aneg - Enable and Restart Autonegotiation * @phydev: target phy_device struct @@ -169,7 +165,6 @@ int genphy_restart_aneg(struct phy_device *phydev) return ctl; } - /** * genphy_config_aneg - restart auto-negotiation or write BMCR * @phydev: target phy_device struct @@ -182,7 +177,7 @@ int genphy_config_aneg(struct phy_device *phydev) { int result; - if (AUTONEG_ENABLE != phydev->autoneg) + if (phydev->autoneg != AUTONEG_ENABLE) return genphy_setup_forced(phydev); result = genphy_config_advert(phydev); @@ -191,8 +186,10 @@ int genphy_config_aneg(struct phy_device *phydev) return result; if (result == 0) { - /* Advertisment hasn't changed, but maybe aneg was never on to - * begin with? Or maybe phy was isolated? */ + /* + * Advertisment hasn't changed, but maybe aneg was never on to + * begin with? Or maybe phy was isolated? + */ int ctl = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR); if (ctl < 0) @@ -202,8 +199,10 @@ int genphy_config_aneg(struct phy_device *phydev) result = 1; /* do restart aneg */ } - /* Only restart aneg if we are advertising something different - * than we were before. */ + /* + * Only restart aneg if we are advertising something different + * than we were before. + */ if (result > 0) result = genphy_restart_aneg(phydev); @@ -240,7 +239,7 @@ int genphy_update_link(struct phy_device *phydev) int i = 0; printf("%s Waiting for PHY auto negotiation to complete", - phydev->dev->name); + phydev->dev->name); while (!(mii_reg & BMSR_ANEGCOMPLETE)) { /* * Timeout reached ? @@ -305,7 +304,8 @@ int genphy_parse_link(struct phy_device *phydev) */ gblpa = phy_read(phydev, MDIO_DEVAD_NONE, MII_STAT1000); if (gblpa < 0) { - debug("Could not read MII_STAT1000. Ignoring gigabit capability\n"); + debug("Could not read MII_STAT1000. "); + debug("Ignoring gigabit capability\n"); gblpa = 0; } gblpa &= phy_read(phydev, @@ -338,8 +338,9 @@ int genphy_parse_link(struct phy_device *phydev) if (lpa & LPA_100FULL) phydev->duplex = DUPLEX_FULL; - } else if (lpa & LPA_10FULL) + } else if (lpa & LPA_10FULL) { phydev->duplex = DUPLEX_FULL; + } /* * Extended status may indicate that the PHY supports @@ -457,10 +458,27 @@ static struct phy_driver genphy_driver = { .shutdown = genphy_shutdown, }; +int genphy_init(void) +{ + return phy_register(&genphy_driver); +} + static LIST_HEAD(phy_drivers); int phy_init(void) { +#ifdef CONFIG_NEEDS_MANUAL_RELOC + /* + * The pointers inside phy_drivers also needs to be updated incase of + * manual reloc, without which these points to some invalid + * pre reloc address and leads to invalid accesses, hangs. + */ + struct list_head *head = &phy_drivers; + + head->next = (void *)head->next + gd->reloc_off; + head->prev = (void *)head->prev + gd->reloc_off; +#endif + #ifdef CONFIG_B53_SWITCH phy_b53_init(); #endif @@ -527,6 +545,11 @@ int phy_init(void) #ifdef CONFIG_PHY_FIXED phy_fixed_init(); #endif +#ifdef CONFIG_PHY_XILINX_GMII2RGMII + phy_xilinx_gmii2rgmii_init(); +#endif + genphy_init(); + return 0; } @@ -548,6 +571,10 @@ int phy_register(struct phy_driver *drv) drv->readext += gd->reloc_off; if (drv->writeext) drv->writeext += gd->reloc_off; + if (drv->read_mmd) + drv->read_mmd += gd->reloc_off; + if (drv->write_mmd) + drv->write_mmd += gd->reloc_off; #endif return 0; } @@ -580,7 +607,9 @@ static int phy_probe(struct phy_device *phydev) { int err = 0; - phydev->advertising = phydev->supported = phydev->drv->features; + phydev->advertising = phydev->drv->features; + phydev->supported = phydev->drv->features; + phydev->mmds = phydev->drv->mmds; if (phydev->drv->probe) @@ -600,7 +629,7 @@ static struct phy_driver *generic_for_interface(phy_interface_t interface) } static struct phy_driver *get_phy_driver(struct phy_device *phydev, - phy_interface_t interface) + phy_interface_t interface) { struct list_head *entry; int phy_id = phydev->phy_id; @@ -617,17 +646,19 @@ static struct phy_driver *get_phy_driver(struct phy_device *phydev, } static struct phy_device *phy_device_create(struct mii_dev *bus, int addr, - u32 phy_id, + u32 phy_id, bool is_c45, phy_interface_t interface) { struct phy_device *dev; - /* We allocate the device, and initialize the - * default values */ + /* + * We allocate the device, and initialize the + * default values + */ dev = malloc(sizeof(*dev)); if (!dev) { printf("Failed to allocate PHY device for %s:%d\n", - bus->name, addr); + bus->name, addr); return NULL; } @@ -637,17 +668,26 @@ static struct phy_device *phy_device_create(struct mii_dev *bus, int addr, dev->link = 0; dev->interface = interface; +#ifdef CONFIG_DM_ETH + dev->node = ofnode_null(); +#endif + dev->autoneg = AUTONEG_ENABLE; dev->addr = addr; dev->phy_id = phy_id; + dev->is_c45 = is_c45; dev->bus = bus; dev->drv = get_phy_driver(dev, interface); - phy_probe(dev); + if (phy_probe(dev)) { + printf("%s, PHY probe failed\n", __func__); + return NULL; + } - bus->phymap[addr] = dev; + if (addr >= 0 && addr < PHY_MAX_ADDR) + bus->phymap[addr] = dev; return dev; } @@ -665,8 +705,10 @@ int __weak get_phy_id(struct mii_dev *bus, int addr, int devad, u32 *phy_id) { int phy_reg; - /* Grab the bits from PHYIR1, and put them - * in the upper half */ + /* + * Grab the bits from PHYIR1, and put them + * in the upper half + */ phy_reg = bus->read(bus, addr, devad, MII_PHYSID1); if (phy_reg < 0) @@ -686,26 +728,45 @@ int __weak get_phy_id(struct mii_dev *bus, int addr, int devad, u32 *phy_id) } static struct phy_device *create_phy_by_mask(struct mii_dev *bus, - unsigned phy_mask, int devad, phy_interface_t interface) + uint phy_mask, int devad, + phy_interface_t interface) { u32 phy_id = 0xffffffff; + bool is_c45; + while (phy_mask) { int addr = ffs(phy_mask) - 1; int r = get_phy_id(bus, addr, devad, &phy_id); + + /* + * If the PHY ID is flat 0 we ignore it. There are C45 PHYs + * that return all 0s for C22 reads (like Aquantia AQR112) and + * there are C22 PHYs that return all 0s for C45 reads (like + * Atheros AR8035). + */ + if (r == 0 && phy_id == 0) + goto next; + /* If the PHY ID is mostly f's, we didn't find anything */ - if (r == 0 && (phy_id & 0x1fffffff) != 0x1fffffff) - return phy_device_create(bus, addr, phy_id, interface); + if (r == 0 && (phy_id & 0x1fffffff) != 0x1fffffff) { + is_c45 = (devad == MDIO_DEVAD_NONE) ? false : true; + return phy_device_create(bus, addr, phy_id, is_c45, + interface); + } +next: 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) + uint 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]; @@ -716,7 +777,8 @@ static struct phy_device *search_for_existing_phy(struct mii_dev *bus, } static struct phy_device *get_phy_device_by_mask(struct mii_dev *bus, - unsigned phy_mask, phy_interface_t interface) + uint phy_mask, + phy_interface_t interface) { int i; struct phy_device *phydev; @@ -728,7 +790,7 @@ static struct phy_device *get_phy_device_by_mask(struct mii_dev *bus, /* 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); + i ? i : MDIO_DEVAD_NONE, interface); if (IS_ERR(phydev)) return NULL; if (phydev) @@ -738,6 +800,7 @@ static struct phy_device *get_phy_device_by_mask(struct mii_dev *bus, debug("\n%s PHY: ", bus->name); while (phy_mask) { int addr = ffs(phy_mask) - 1; + debug("%d ", addr); phy_mask &= ~(1 << addr); } @@ -747,7 +810,8 @@ static struct phy_device *get_phy_device_by_mask(struct mii_dev *bus, } /** - * get_phy_device - reads the specified PHY device and returns its @phy_device struct + * get_phy_device - reads the specified PHY device and returns its + * @phy_device struct * @bus: the target MII bus * @addr: PHY address on the MII bus * @@ -826,15 +890,15 @@ int miiphy_reset(const char *devname, unsigned char addr) return phy_reset(phydev); } -struct phy_device *phy_find_by_mask(struct mii_dev *bus, unsigned phy_mask, - phy_interface_t interface) +struct phy_device *phy_find_by_mask(struct mii_dev *bus, uint phy_mask, + phy_interface_t interface) { /* Reset the bus */ if (bus->reset) { bus->reset(bus); /* Wait 15ms to make sure the PHY has come out of hard reset */ - udelay(15000); + mdelay(15); } return get_phy_device_by_mask(bus, phy_mask, interface); @@ -850,38 +914,101 @@ void phy_connect_dev(struct phy_device *phydev, struct eth_device *dev) phy_reset(phydev); if (phydev->dev && phydev->dev != dev) { printf("%s:%d is connected to %s. Reconnecting to %s\n", - phydev->bus->name, phydev->addr, - phydev->dev->name, dev->name); + phydev->bus->name, phydev->addr, + phydev->dev->name, dev->name); } phydev->dev = dev; debug("%s connected to %s\n", dev->name, phydev->drv->name); } +#ifdef CONFIG_PHY_XILINX_GMII2RGMII #ifdef CONFIG_DM_ETH -struct phy_device *phy_connect(struct mii_dev *bus, int addr, - struct udevice *dev, phy_interface_t interface) +static struct phy_device *phy_connect_gmii2rgmii(struct mii_dev *bus, + struct udevice *dev, + phy_interface_t interface) #else -struct phy_device *phy_connect(struct mii_dev *bus, int addr, - struct eth_device *dev, phy_interface_t interface) +static struct phy_device *phy_connect_gmii2rgmii(struct mii_dev *bus, + struct eth_device *dev, + phy_interface_t interface) #endif { struct phy_device *phydev = NULL; + int sn = dev_of_offset(dev); + int off; + + while (sn > 0) { + off = fdt_node_offset_by_compatible(gd->fdt_blob, sn, + "xlnx,gmii-to-rgmii-1.0"); + if (off > 0) { + phydev = phy_device_create(bus, off, + PHY_GMII2RGMII_ID, false, + interface); + break; + } + if (off == -FDT_ERR_NOTFOUND) + sn = fdt_first_subnode(gd->fdt_blob, sn); + else + printf("%s: Error finding compat string:%d\n", + __func__, off); + } + + return phydev; +} +#endif + #ifdef CONFIG_PHY_FIXED +#ifdef CONFIG_DM_ETH +static struct phy_device *phy_connect_fixed(struct mii_dev *bus, + struct udevice *dev, + phy_interface_t interface) +#else +static struct phy_device *phy_connect_fixed(struct mii_dev *bus, + struct eth_device *dev, + phy_interface_t interface) +#endif +{ + struct phy_device *phydev = NULL; int sn; const char *name; + sn = fdt_first_subnode(gd->fdt_blob, dev_of_offset(dev)); while (sn > 0) { name = fdt_get_name(gd->fdt_blob, sn, NULL); - if (name != NULL && strcmp(name, "fixed-link") == 0) { - phydev = phy_device_create(bus, - sn, PHY_FIXED_ID, interface); + if (name && strcmp(name, "fixed-link") == 0) { + phydev = phy_device_create(bus, sn, PHY_FIXED_ID, false, + interface); break; } sn = fdt_next_subnode(gd->fdt_blob, sn); } + + return phydev; +} #endif - if (phydev == NULL) - phydev = phy_find_by_mask(bus, 1 << addr, interface); + +#ifdef CONFIG_DM_ETH +struct phy_device *phy_connect(struct mii_dev *bus, int addr, + struct udevice *dev, + phy_interface_t interface) +#else +struct phy_device *phy_connect(struct mii_dev *bus, int addr, + struct eth_device *dev, + phy_interface_t interface) +#endif +{ + struct phy_device *phydev = NULL; + uint mask = (addr > 0) ? (1 << addr) : 0xffffffff; + +#ifdef CONFIG_PHY_FIXED + phydev = phy_connect_fixed(bus, dev, interface); +#endif +#ifdef CONFIG_PHY_XILINX_GMII2RGMII + if (!phydev) + phydev = phy_connect_gmii2rgmii(bus, dev, interface); +#endif + + if (!phydev) + phydev = phy_find_by_mask(bus, mask, interface); if (phydev) phy_connect_dev(phydev, dev);