1*83d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+ 2c609719bSwdenk /* 3c609719bSwdenk * (C) Copyright 2001 4c609719bSwdenk * Gerald Van Baren, Custom IDEAS, vanbaren@cideas.com. 5c609719bSwdenk */ 6c609719bSwdenk 7c609719bSwdenk /* 8c609719bSwdenk * This provides a bit-banged interface to the ethernet MII management 9c609719bSwdenk * channel. 10c609719bSwdenk */ 11c609719bSwdenk 12c609719bSwdenk #include <common.h> 13c74c8e66SSimon Glass #include <dm.h> 14c609719bSwdenk #include <miiphy.h> 155f184715SAndy Fleming #include <phy.h> 16c609719bSwdenk 1763ff004cSMarian Balakowicz #include <asm/types.h> 1863ff004cSMarian Balakowicz #include <linux/list.h> 1963ff004cSMarian Balakowicz #include <malloc.h> 2063ff004cSMarian Balakowicz #include <net.h> 2163ff004cSMarian Balakowicz 2263ff004cSMarian Balakowicz /* local debug macro */ 2363ff004cSMarian Balakowicz #undef MII_DEBUG 2463ff004cSMarian Balakowicz 2563ff004cSMarian Balakowicz #undef debug 2663ff004cSMarian Balakowicz #ifdef MII_DEBUG 2763ff004cSMarian Balakowicz #define debug(fmt, args...) printf(fmt, ##args) 2863ff004cSMarian Balakowicz #else 2963ff004cSMarian Balakowicz #define debug(fmt, args...) 3063ff004cSMarian Balakowicz #endif /* MII_DEBUG */ 3163ff004cSMarian Balakowicz 3263ff004cSMarian Balakowicz static struct list_head mii_devs; 3363ff004cSMarian Balakowicz static struct mii_dev *current_mii; 3463ff004cSMarian Balakowicz 350daac978SMike Frysinger /* 360daac978SMike Frysinger * Lookup the mii_dev struct by the registered device name. 370daac978SMike Frysinger */ 385f184715SAndy Fleming struct mii_dev *miiphy_get_dev_by_name(const char *devname) 390daac978SMike Frysinger { 400daac978SMike Frysinger struct list_head *entry; 410daac978SMike Frysinger struct mii_dev *dev; 420daac978SMike Frysinger 430daac978SMike Frysinger if (!devname) { 440daac978SMike Frysinger printf("NULL device name!\n"); 450daac978SMike Frysinger return NULL; 460daac978SMike Frysinger } 470daac978SMike Frysinger 480daac978SMike Frysinger list_for_each(entry, &mii_devs) { 490daac978SMike Frysinger dev = list_entry(entry, struct mii_dev, link); 500daac978SMike Frysinger if (strcmp(dev->name, devname) == 0) 510daac978SMike Frysinger return dev; 520daac978SMike Frysinger } 530daac978SMike Frysinger 540daac978SMike Frysinger return NULL; 550daac978SMike Frysinger } 560daac978SMike Frysinger 5763ff004cSMarian Balakowicz /***************************************************************************** 5863ff004cSMarian Balakowicz * 59d9785c14SMarian Balakowicz * Initialize global data. Need to be called before any other miiphy routine. 60d9785c14SMarian Balakowicz */ 615700bb63SMike Frysinger void miiphy_init(void) 62d9785c14SMarian Balakowicz { 63d9785c14SMarian Balakowicz INIT_LIST_HEAD(&mii_devs); 64d9785c14SMarian Balakowicz current_mii = NULL; 65d9785c14SMarian Balakowicz } 66d9785c14SMarian Balakowicz 675f184715SAndy Fleming struct mii_dev *mdio_alloc(void) 685f184715SAndy Fleming { 695f184715SAndy Fleming struct mii_dev *bus; 705f184715SAndy Fleming 715f184715SAndy Fleming bus = malloc(sizeof(*bus)); 725f184715SAndy Fleming if (!bus) 735f184715SAndy Fleming return bus; 745f184715SAndy Fleming 755f184715SAndy Fleming memset(bus, 0, sizeof(*bus)); 765f184715SAndy Fleming 775f184715SAndy Fleming /* initalize mii_dev struct fields */ 785f184715SAndy Fleming INIT_LIST_HEAD(&bus->link); 795f184715SAndy Fleming 805f184715SAndy Fleming return bus; 815f184715SAndy Fleming } 825f184715SAndy Fleming 83cb6baca7SBin Meng void mdio_free(struct mii_dev *bus) 84cb6baca7SBin Meng { 85cb6baca7SBin Meng free(bus); 86cb6baca7SBin Meng } 87cb6baca7SBin Meng 885f184715SAndy Fleming int mdio_register(struct mii_dev *bus) 895f184715SAndy Fleming { 90d39449b1SPeng Fan if (!bus || !bus->read || !bus->write) 915f184715SAndy Fleming return -1; 925f184715SAndy Fleming 935f184715SAndy Fleming /* check if we have unique name */ 945f184715SAndy Fleming if (miiphy_get_dev_by_name(bus->name)) { 955f184715SAndy Fleming printf("mdio_register: non unique device name '%s'\n", 965f184715SAndy Fleming bus->name); 975f184715SAndy Fleming return -1; 985f184715SAndy Fleming } 995f184715SAndy Fleming 1005f184715SAndy Fleming /* add it to the list */ 1015f184715SAndy Fleming list_add_tail(&bus->link, &mii_devs); 1025f184715SAndy Fleming 1035f184715SAndy Fleming if (!current_mii) 1045f184715SAndy Fleming current_mii = bus; 1055f184715SAndy Fleming 1065f184715SAndy Fleming return 0; 1075f184715SAndy Fleming } 1085f184715SAndy Fleming 10979e2a6a0SMichal Simek int mdio_register_seq(struct mii_dev *bus, int seq) 11079e2a6a0SMichal Simek { 11179e2a6a0SMichal Simek int ret; 11279e2a6a0SMichal Simek 11379e2a6a0SMichal Simek /* Setup a unique name for each mdio bus */ 11479e2a6a0SMichal Simek ret = snprintf(bus->name, MDIO_NAME_LEN, "eth%d", seq); 11579e2a6a0SMichal Simek if (ret < 0) 11679e2a6a0SMichal Simek return ret; 11779e2a6a0SMichal Simek 11879e2a6a0SMichal Simek return mdio_register(bus); 11979e2a6a0SMichal Simek } 12079e2a6a0SMichal Simek 121cb6baca7SBin Meng int mdio_unregister(struct mii_dev *bus) 122cb6baca7SBin Meng { 123cb6baca7SBin Meng if (!bus) 124cb6baca7SBin Meng return 0; 125cb6baca7SBin Meng 126cb6baca7SBin Meng /* delete it from the list */ 127cb6baca7SBin Meng list_del(&bus->link); 128cb6baca7SBin Meng 129cb6baca7SBin Meng if (current_mii == bus) 130cb6baca7SBin Meng current_mii = NULL; 131cb6baca7SBin Meng 132cb6baca7SBin Meng return 0; 133cb6baca7SBin Meng } 134cb6baca7SBin Meng 1355f184715SAndy Fleming void mdio_list_devices(void) 1365f184715SAndy Fleming { 1375f184715SAndy Fleming struct list_head *entry; 1385f184715SAndy Fleming 1395f184715SAndy Fleming list_for_each(entry, &mii_devs) { 1405f184715SAndy Fleming int i; 1415f184715SAndy Fleming struct mii_dev *bus = list_entry(entry, struct mii_dev, link); 1425f184715SAndy Fleming 1435f184715SAndy Fleming printf("%s:\n", bus->name); 1445f184715SAndy Fleming 1455f184715SAndy Fleming for (i = 0; i < PHY_MAX_ADDR; i++) { 1465f184715SAndy Fleming struct phy_device *phydev = bus->phymap[i]; 1475f184715SAndy Fleming 1485f184715SAndy Fleming if (phydev) { 14915a2acdfSMichal Simek printf("%x - %s", i, phydev->drv->name); 1505f184715SAndy Fleming 1515f184715SAndy Fleming if (phydev->dev) 1525f184715SAndy Fleming printf(" <--> %s\n", phydev->dev->name); 1535f184715SAndy Fleming else 1545f184715SAndy Fleming printf("\n"); 1555f184715SAndy Fleming } 1565f184715SAndy Fleming } 1575f184715SAndy Fleming } 1585f184715SAndy Fleming } 1595f184715SAndy Fleming 1605700bb63SMike Frysinger int miiphy_set_current_dev(const char *devname) 16163ff004cSMarian Balakowicz { 16263ff004cSMarian Balakowicz struct mii_dev *dev; 16363ff004cSMarian Balakowicz 1645f184715SAndy Fleming dev = miiphy_get_dev_by_name(devname); 1650daac978SMike Frysinger if (dev) { 16663ff004cSMarian Balakowicz current_mii = dev; 16763ff004cSMarian Balakowicz return 0; 16863ff004cSMarian Balakowicz } 16963ff004cSMarian Balakowicz 1705f184715SAndy Fleming printf("No such device: %s\n", devname); 1715f184715SAndy Fleming 17263ff004cSMarian Balakowicz return 1; 17363ff004cSMarian Balakowicz } 17463ff004cSMarian Balakowicz 1755f184715SAndy Fleming struct mii_dev *mdio_get_current_dev(void) 1765f184715SAndy Fleming { 1775f184715SAndy Fleming return current_mii; 1785f184715SAndy Fleming } 1795f184715SAndy Fleming 1805f184715SAndy Fleming struct phy_device *mdio_phydev_for_ethname(const char *ethname) 1815f184715SAndy Fleming { 1825f184715SAndy Fleming struct list_head *entry; 1835f184715SAndy Fleming struct mii_dev *bus; 1845f184715SAndy Fleming 1855f184715SAndy Fleming list_for_each(entry, &mii_devs) { 1865f184715SAndy Fleming int i; 1875f184715SAndy Fleming bus = list_entry(entry, struct mii_dev, link); 1885f184715SAndy Fleming 1895f184715SAndy Fleming for (i = 0; i < PHY_MAX_ADDR; i++) { 1905f184715SAndy Fleming if (!bus->phymap[i] || !bus->phymap[i]->dev) 1915f184715SAndy Fleming continue; 1925f184715SAndy Fleming 1935f184715SAndy Fleming if (strcmp(bus->phymap[i]->dev->name, ethname) == 0) 1945f184715SAndy Fleming return bus->phymap[i]; 1955f184715SAndy Fleming } 1965f184715SAndy Fleming } 1975f184715SAndy Fleming 1985f184715SAndy Fleming printf("%s is not a known ethernet\n", ethname); 1995f184715SAndy Fleming return NULL; 2005f184715SAndy Fleming } 2015f184715SAndy Fleming 2025700bb63SMike Frysinger const char *miiphy_get_current_dev(void) 20363ff004cSMarian Balakowicz { 20463ff004cSMarian Balakowicz if (current_mii) 20563ff004cSMarian Balakowicz return current_mii->name; 20663ff004cSMarian Balakowicz 20763ff004cSMarian Balakowicz return NULL; 20863ff004cSMarian Balakowicz } 20963ff004cSMarian Balakowicz 210ede16ea3SMike Frysinger static struct mii_dev *miiphy_get_active_dev(const char *devname) 211ede16ea3SMike Frysinger { 212ede16ea3SMike Frysinger /* If the current mii is the one we want, return it */ 213ede16ea3SMike Frysinger if (current_mii) 214ede16ea3SMike Frysinger if (strcmp(current_mii->name, devname) == 0) 215ede16ea3SMike Frysinger return current_mii; 216ede16ea3SMike Frysinger 217ede16ea3SMike Frysinger /* Otherwise, set the active one to the one we want */ 218ede16ea3SMike Frysinger if (miiphy_set_current_dev(devname)) 219ede16ea3SMike Frysinger return NULL; 220ede16ea3SMike Frysinger else 221ede16ea3SMike Frysinger return current_mii; 222ede16ea3SMike Frysinger } 223ede16ea3SMike Frysinger 22463ff004cSMarian Balakowicz /***************************************************************************** 22563ff004cSMarian Balakowicz * 22663ff004cSMarian Balakowicz * Read to variable <value> from the PHY attached to device <devname>, 22763ff004cSMarian Balakowicz * use PHY address <addr> and register <reg>. 22863ff004cSMarian Balakowicz * 2291cdabc4bSAndy Fleming * This API is deprecated. Use phy_read on a phy_device found via phy_connect 2301cdabc4bSAndy Fleming * 23163ff004cSMarian Balakowicz * Returns: 23263ff004cSMarian Balakowicz * 0 on success 23363ff004cSMarian Balakowicz */ 234f915c931SWolfgang Denk int miiphy_read(const char *devname, unsigned char addr, unsigned char reg, 23563ff004cSMarian Balakowicz unsigned short *value) 23663ff004cSMarian Balakowicz { 2375f184715SAndy Fleming struct mii_dev *bus; 238d67d5d52SAnatolij Gustschin int ret; 23963ff004cSMarian Balakowicz 2405f184715SAndy Fleming bus = miiphy_get_active_dev(devname); 241d67d5d52SAnatolij Gustschin if (!bus) 24263ff004cSMarian Balakowicz return 1; 2435f184715SAndy Fleming 244d67d5d52SAnatolij Gustschin ret = bus->read(bus, addr, MDIO_DEVAD_NONE, reg); 245d67d5d52SAnatolij Gustschin if (ret < 0) 246d67d5d52SAnatolij Gustschin return 1; 247d67d5d52SAnatolij Gustschin 248d67d5d52SAnatolij Gustschin *value = (unsigned short)ret; 249d67d5d52SAnatolij Gustschin return 0; 25063ff004cSMarian Balakowicz } 25163ff004cSMarian Balakowicz 25263ff004cSMarian Balakowicz /***************************************************************************** 25363ff004cSMarian Balakowicz * 25463ff004cSMarian Balakowicz * Write <value> to the PHY attached to device <devname>, 25563ff004cSMarian Balakowicz * use PHY address <addr> and register <reg>. 25663ff004cSMarian Balakowicz * 2571cdabc4bSAndy Fleming * This API is deprecated. Use phy_write on a phy_device found by phy_connect 2581cdabc4bSAndy Fleming * 25963ff004cSMarian Balakowicz * Returns: 26063ff004cSMarian Balakowicz * 0 on success 26163ff004cSMarian Balakowicz */ 262f915c931SWolfgang Denk int miiphy_write(const char *devname, unsigned char addr, unsigned char reg, 26363ff004cSMarian Balakowicz unsigned short value) 26463ff004cSMarian Balakowicz { 2655f184715SAndy Fleming struct mii_dev *bus; 26663ff004cSMarian Balakowicz 2675f184715SAndy Fleming bus = miiphy_get_active_dev(devname); 2685f184715SAndy Fleming if (bus) 2695f184715SAndy Fleming return bus->write(bus, addr, MDIO_DEVAD_NONE, reg, value); 2700daac978SMike Frysinger 27163ff004cSMarian Balakowicz return 1; 27263ff004cSMarian Balakowicz } 27363ff004cSMarian Balakowicz 27463ff004cSMarian Balakowicz /***************************************************************************** 27563ff004cSMarian Balakowicz * 27663ff004cSMarian Balakowicz * Print out list of registered MII capable devices. 27763ff004cSMarian Balakowicz */ 27863ff004cSMarian Balakowicz void miiphy_listdev(void) 27963ff004cSMarian Balakowicz { 28063ff004cSMarian Balakowicz struct list_head *entry; 28163ff004cSMarian Balakowicz struct mii_dev *dev; 28263ff004cSMarian Balakowicz 28363ff004cSMarian Balakowicz puts("MII devices: "); 28463ff004cSMarian Balakowicz list_for_each(entry, &mii_devs) { 28563ff004cSMarian Balakowicz dev = list_entry(entry, struct mii_dev, link); 28663ff004cSMarian Balakowicz printf("'%s' ", dev->name); 28763ff004cSMarian Balakowicz } 28863ff004cSMarian Balakowicz puts("\n"); 28963ff004cSMarian Balakowicz 29063ff004cSMarian Balakowicz if (current_mii) 29163ff004cSMarian Balakowicz printf("Current device: '%s'\n", current_mii->name); 29263ff004cSMarian Balakowicz } 29363ff004cSMarian Balakowicz 294c609719bSwdenk /***************************************************************************** 295c609719bSwdenk * 296c609719bSwdenk * Read the OUI, manufacture's model number, and revision number. 297c609719bSwdenk * 298c609719bSwdenk * OUI: 22 bits (unsigned int) 299c609719bSwdenk * Model: 6 bits (unsigned char) 300c609719bSwdenk * Revision: 4 bits (unsigned char) 301c609719bSwdenk * 3021cdabc4bSAndy Fleming * This API is deprecated. 3031cdabc4bSAndy Fleming * 304c609719bSwdenk * Returns: 305c609719bSwdenk * 0 on success 306c609719bSwdenk */ 3075700bb63SMike Frysinger int miiphy_info(const char *devname, unsigned char addr, unsigned int *oui, 308c609719bSwdenk unsigned char *model, unsigned char *rev) 309c609719bSwdenk { 310c609719bSwdenk unsigned int reg = 0; 3118bf3b005Swdenk unsigned short tmp; 312c609719bSwdenk 3138ef583a0SMike Frysinger if (miiphy_read(devname, addr, MII_PHYSID2, &tmp) != 0) { 31426c7bab8SShinya Kuribayashi debug("PHY ID register 2 read failed\n"); 31516a53238SAndy Fleming return -1; 316c609719bSwdenk } 3178bf3b005Swdenk reg = tmp; 318c609719bSwdenk 3198ef583a0SMike Frysinger debug("MII_PHYSID2 @ 0x%x = 0x%04x\n", addr, reg); 32026c7bab8SShinya Kuribayashi 321c609719bSwdenk if (reg == 0xFFFF) { 322c609719bSwdenk /* No physical device present at this address */ 32316a53238SAndy Fleming return -1; 324c609719bSwdenk } 325c609719bSwdenk 3268ef583a0SMike Frysinger if (miiphy_read(devname, addr, MII_PHYSID1, &tmp) != 0) { 32726c7bab8SShinya Kuribayashi debug("PHY ID register 1 read failed\n"); 32816a53238SAndy Fleming return -1; 329c609719bSwdenk } 3308bf3b005Swdenk reg |= tmp << 16; 33126c7bab8SShinya Kuribayashi debug("PHY_PHYIDR[1,2] @ 0x%x = 0x%08x\n", addr, reg); 33226c7bab8SShinya Kuribayashi 333c609719bSwdenk *oui = (reg >> 10); 334c609719bSwdenk *model = (unsigned char)((reg >> 4) & 0x0000003F); 335c609719bSwdenk *rev = (unsigned char)(reg & 0x0000000F); 33616a53238SAndy Fleming return 0; 337c609719bSwdenk } 338c609719bSwdenk 3395f184715SAndy Fleming #ifndef CONFIG_PHYLIB 340c609719bSwdenk /***************************************************************************** 341c609719bSwdenk * 342c609719bSwdenk * Reset the PHY. 3431cdabc4bSAndy Fleming * 3441cdabc4bSAndy Fleming * This API is deprecated. Use PHYLIB. 3451cdabc4bSAndy Fleming * 346c609719bSwdenk * Returns: 347c609719bSwdenk * 0 on success 348c609719bSwdenk */ 3495700bb63SMike Frysinger int miiphy_reset(const char *devname, unsigned char addr) 350c609719bSwdenk { 351c609719bSwdenk unsigned short reg; 352ab5a0dcbSStefan Roese int timeout = 500; 353c609719bSwdenk 3548ef583a0SMike Frysinger if (miiphy_read(devname, addr, MII_BMCR, ®) != 0) { 35526c7bab8SShinya Kuribayashi debug("PHY status read failed\n"); 35616a53238SAndy Fleming return -1; 357f89920c3SWolfgang Denk } 3588ef583a0SMike Frysinger if (miiphy_write(devname, addr, MII_BMCR, reg | BMCR_RESET) != 0) { 35926c7bab8SShinya Kuribayashi debug("PHY reset failed\n"); 36016a53238SAndy Fleming return -1; 361c609719bSwdenk } 3625653fc33Swdenk #ifdef CONFIG_PHY_RESET_DELAY 3635653fc33Swdenk udelay(CONFIG_PHY_RESET_DELAY); /* Intel LXT971A needs this */ 3645653fc33Swdenk #endif 365c609719bSwdenk /* 366c609719bSwdenk * Poll the control register for the reset bit to go to 0 (it is 367c609719bSwdenk * auto-clearing). This should happen within 0.5 seconds per the 368c609719bSwdenk * IEEE spec. 369c609719bSwdenk */ 370c609719bSwdenk reg = 0x8000; 371ab5a0dcbSStefan Roese while (((reg & 0x8000) != 0) && timeout--) { 3728ef583a0SMike Frysinger if (miiphy_read(devname, addr, MII_BMCR, ®) != 0) { 37326c7bab8SShinya Kuribayashi debug("PHY status read failed\n"); 374ab5a0dcbSStefan Roese return -1; 375c609719bSwdenk } 376ab5a0dcbSStefan Roese udelay(1000); 377c609719bSwdenk } 378c609719bSwdenk if ((reg & 0x8000) == 0) { 37916a53238SAndy Fleming return 0; 380c609719bSwdenk } else { 3814b9206edSwdenk puts("PHY reset timed out\n"); 38216a53238SAndy Fleming return -1; 383c609719bSwdenk } 38416a53238SAndy Fleming return 0; 385c609719bSwdenk } 3865f184715SAndy Fleming #endif /* !PHYLIB */ 387c609719bSwdenk 388c609719bSwdenk /***************************************************************************** 389c609719bSwdenk * 39071bc6e64SLarry Johnson * Determine the ethernet speed (10/100/1000). Return 10 on error. 391c609719bSwdenk */ 3925700bb63SMike Frysinger int miiphy_speed(const char *devname, unsigned char addr) 393c609719bSwdenk { 3948c83c030SDongpo Li u16 bmcr, anlpar, adv; 395c609719bSwdenk 3966fb6af6dSwdenk #if defined(CONFIG_PHY_GIGE) 39771bc6e64SLarry Johnson u16 btsr; 39871bc6e64SLarry Johnson 39971bc6e64SLarry Johnson /* 40071bc6e64SLarry Johnson * Check for 1000BASE-X. If it is supported, then assume that the speed 40171bc6e64SLarry Johnson * is 1000. 40271bc6e64SLarry Johnson */ 40316a53238SAndy Fleming if (miiphy_is_1000base_x(devname, addr)) 40471bc6e64SLarry Johnson return _1000BASET; 40516a53238SAndy Fleming 40671bc6e64SLarry Johnson /* 40771bc6e64SLarry Johnson * No 1000BASE-X, so assume 1000BASE-T/100BASE-TX/10BASE-T register set. 40871bc6e64SLarry Johnson */ 40971bc6e64SLarry Johnson /* Check for 1000BASE-T. */ 4108ef583a0SMike Frysinger if (miiphy_read(devname, addr, MII_STAT1000, &btsr)) { 41171bc6e64SLarry Johnson printf("PHY 1000BT status"); 41271bc6e64SLarry Johnson goto miiphy_read_failed; 413855a496fSwdenk } 41471bc6e64SLarry Johnson if (btsr != 0xFFFF && 41516a53238SAndy Fleming (btsr & (PHY_1000BTSR_1000FD | PHY_1000BTSR_1000HD))) 41671bc6e64SLarry Johnson return _1000BASET; 4176fb6af6dSwdenk #endif /* CONFIG_PHY_GIGE */ 418855a496fSwdenk 419a56bd922Swdenk /* Check Basic Management Control Register first. */ 4208ef583a0SMike Frysinger if (miiphy_read(devname, addr, MII_BMCR, &bmcr)) { 42171bc6e64SLarry Johnson printf("PHY speed"); 42271bc6e64SLarry Johnson goto miiphy_read_failed; 423a56bd922Swdenk } 424a56bd922Swdenk /* Check if auto-negotiation is on. */ 4258ef583a0SMike Frysinger if (bmcr & BMCR_ANENABLE) { 426a56bd922Swdenk /* Get auto-negotiation results. */ 4278ef583a0SMike Frysinger if (miiphy_read(devname, addr, MII_LPA, &anlpar)) { 42871bc6e64SLarry Johnson printf("PHY AN speed"); 42971bc6e64SLarry Johnson goto miiphy_read_failed; 430c609719bSwdenk } 4318c83c030SDongpo Li 4328c83c030SDongpo Li if (miiphy_read(devname, addr, MII_ADVERTISE, &adv)) { 4338c83c030SDongpo Li puts("PHY AN adv speed"); 4348c83c030SDongpo Li goto miiphy_read_failed; 4358c83c030SDongpo Li } 4368c83c030SDongpo Li return ((anlpar & adv) & LPA_100) ? _100BASET : _10BASET; 437c609719bSwdenk } 438a56bd922Swdenk /* Get speed from basic control settings. */ 4398ef583a0SMike Frysinger return (bmcr & BMCR_SPEED100) ? _100BASET : _10BASET; 440a56bd922Swdenk 44171bc6e64SLarry Johnson miiphy_read_failed: 44271bc6e64SLarry Johnson printf(" read failed, assuming 10BASE-T\n"); 44371bc6e64SLarry Johnson return _10BASET; 444a56bd922Swdenk } 445c609719bSwdenk 446c609719bSwdenk /***************************************************************************** 447c609719bSwdenk * 44871bc6e64SLarry Johnson * Determine full/half duplex. Return half on error. 449c609719bSwdenk */ 4505700bb63SMike Frysinger int miiphy_duplex(const char *devname, unsigned char addr) 451c609719bSwdenk { 4528c83c030SDongpo Li u16 bmcr, anlpar, adv; 453c609719bSwdenk 4546fb6af6dSwdenk #if defined(CONFIG_PHY_GIGE) 45571bc6e64SLarry Johnson u16 btsr; 45671bc6e64SLarry Johnson 45771bc6e64SLarry Johnson /* Check for 1000BASE-X. */ 45871bc6e64SLarry Johnson if (miiphy_is_1000base_x(devname, addr)) { 45971bc6e64SLarry Johnson /* 1000BASE-X */ 4608ef583a0SMike Frysinger if (miiphy_read(devname, addr, MII_LPA, &anlpar)) { 46171bc6e64SLarry Johnson printf("1000BASE-X PHY AN duplex"); 46271bc6e64SLarry Johnson goto miiphy_read_failed; 463855a496fSwdenk } 464855a496fSwdenk } 46571bc6e64SLarry Johnson /* 46671bc6e64SLarry Johnson * No 1000BASE-X, so assume 1000BASE-T/100BASE-TX/10BASE-T register set. 46771bc6e64SLarry Johnson */ 46871bc6e64SLarry Johnson /* Check for 1000BASE-T. */ 4698ef583a0SMike Frysinger if (miiphy_read(devname, addr, MII_STAT1000, &btsr)) { 47071bc6e64SLarry Johnson printf("PHY 1000BT status"); 47171bc6e64SLarry Johnson goto miiphy_read_failed; 47271bc6e64SLarry Johnson } 47371bc6e64SLarry Johnson if (btsr != 0xFFFF) { 47471bc6e64SLarry Johnson if (btsr & PHY_1000BTSR_1000FD) { 47571bc6e64SLarry Johnson return FULL; 47671bc6e64SLarry Johnson } else if (btsr & PHY_1000BTSR_1000HD) { 47771bc6e64SLarry Johnson return HALF; 47871bc6e64SLarry Johnson } 479855a496fSwdenk } 4806fb6af6dSwdenk #endif /* CONFIG_PHY_GIGE */ 481855a496fSwdenk 482a56bd922Swdenk /* Check Basic Management Control Register first. */ 4838ef583a0SMike Frysinger if (miiphy_read(devname, addr, MII_BMCR, &bmcr)) { 48471bc6e64SLarry Johnson puts("PHY duplex"); 48571bc6e64SLarry Johnson goto miiphy_read_failed; 486c609719bSwdenk } 487a56bd922Swdenk /* Check if auto-negotiation is on. */ 4888ef583a0SMike Frysinger if (bmcr & BMCR_ANENABLE) { 489a56bd922Swdenk /* Get auto-negotiation results. */ 4908ef583a0SMike Frysinger if (miiphy_read(devname, addr, MII_LPA, &anlpar)) { 49171bc6e64SLarry Johnson puts("PHY AN duplex"); 49271bc6e64SLarry Johnson goto miiphy_read_failed; 493a56bd922Swdenk } 4948c83c030SDongpo Li 4958c83c030SDongpo Li if (miiphy_read(devname, addr, MII_ADVERTISE, &adv)) { 4968c83c030SDongpo Li puts("PHY AN adv duplex"); 4978c83c030SDongpo Li goto miiphy_read_failed; 4988c83c030SDongpo Li } 4998c83c030SDongpo Li return ((anlpar & adv) & (LPA_10FULL | LPA_100FULL)) ? 50071bc6e64SLarry Johnson FULL : HALF; 501c609719bSwdenk } 502a56bd922Swdenk /* Get speed from basic control settings. */ 5038ef583a0SMike Frysinger return (bmcr & BMCR_FULLDPLX) ? FULL : HALF; 50471bc6e64SLarry Johnson 50571bc6e64SLarry Johnson miiphy_read_failed: 50671bc6e64SLarry Johnson printf(" read failed, assuming half duplex\n"); 50771bc6e64SLarry Johnson return HALF; 508a56bd922Swdenk } 509a56bd922Swdenk 51071bc6e64SLarry Johnson /***************************************************************************** 51171bc6e64SLarry Johnson * 51271bc6e64SLarry Johnson * Return 1 if PHY supports 1000BASE-X, 0 if PHY supports 10BASE-T/100BASE-TX/ 51371bc6e64SLarry Johnson * 1000BASE-T, or on error. 51471bc6e64SLarry Johnson */ 5155700bb63SMike Frysinger int miiphy_is_1000base_x(const char *devname, unsigned char addr) 51671bc6e64SLarry Johnson { 51771bc6e64SLarry Johnson #if defined(CONFIG_PHY_GIGE) 51871bc6e64SLarry Johnson u16 exsr; 51971bc6e64SLarry Johnson 5208ef583a0SMike Frysinger if (miiphy_read(devname, addr, MII_ESTATUS, &exsr)) { 52171bc6e64SLarry Johnson printf("PHY extended status read failed, assuming no " 52271bc6e64SLarry Johnson "1000BASE-X\n"); 52371bc6e64SLarry Johnson return 0; 52471bc6e64SLarry Johnson } 5258ef583a0SMike Frysinger return 0 != (exsr & (ESTATUS_1000XF | ESTATUS_1000XH)); 52671bc6e64SLarry Johnson #else 52771bc6e64SLarry Johnson return 0; 52871bc6e64SLarry Johnson #endif 529a56bd922Swdenk } 530c609719bSwdenk 5316d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_SYS_FAULT_ECHO_LINK_DOWN 532fc3e2165Swdenk /***************************************************************************** 533fc3e2165Swdenk * 534fc3e2165Swdenk * Determine link status 535fc3e2165Swdenk */ 5365700bb63SMike Frysinger int miiphy_link(const char *devname, unsigned char addr) 537fc3e2165Swdenk { 538fc3e2165Swdenk unsigned short reg; 539fc3e2165Swdenk 540a3d991bdSwdenk /* dummy read; needed to latch some phys */ 5418ef583a0SMike Frysinger (void)miiphy_read(devname, addr, MII_BMSR, ®); 5428ef583a0SMike Frysinger if (miiphy_read(devname, addr, MII_BMSR, ®)) { 5438ef583a0SMike Frysinger puts("MII_BMSR read failed, assuming no link\n"); 54416a53238SAndy Fleming return 0; 545fc3e2165Swdenk } 546fc3e2165Swdenk 547fc3e2165Swdenk /* Determine if a link is active */ 5488ef583a0SMike Frysinger if ((reg & BMSR_LSTATUS) != 0) { 54916a53238SAndy Fleming return 1; 550fc3e2165Swdenk } else { 55116a53238SAndy Fleming return 0; 552fc3e2165Swdenk } 553fc3e2165Swdenk } 554fc3e2165Swdenk #endif 555