1 /* 2 * Core PHY library, taken from phy.c 3 * 4 * This program is free software; you can redistribute it and/or modify it 5 * under the terms of the GNU General Public License as published by the 6 * Free Software Foundation; either version 2 of the License, or (at your 7 * option) any later version. 8 */ 9 #include <linux/export.h> 10 #include <linux/phy.h> 11 12 const char *phy_speed_to_str(int speed) 13 { 14 switch (speed) { 15 case SPEED_10: 16 return "10Mbps"; 17 case SPEED_100: 18 return "100Mbps"; 19 case SPEED_1000: 20 return "1Gbps"; 21 case SPEED_2500: 22 return "2.5Gbps"; 23 case SPEED_5000: 24 return "5Gbps"; 25 case SPEED_10000: 26 return "10Gbps"; 27 case SPEED_14000: 28 return "14Gbps"; 29 case SPEED_20000: 30 return "20Gbps"; 31 case SPEED_25000: 32 return "25Gbps"; 33 case SPEED_40000: 34 return "40Gbps"; 35 case SPEED_50000: 36 return "50Gbps"; 37 case SPEED_56000: 38 return "56Gbps"; 39 case SPEED_100000: 40 return "100Gbps"; 41 case SPEED_UNKNOWN: 42 return "Unknown"; 43 default: 44 return "Unsupported (update phy-core.c)"; 45 } 46 } 47 EXPORT_SYMBOL_GPL(phy_speed_to_str); 48 49 const char *phy_duplex_to_str(unsigned int duplex) 50 { 51 if (duplex == DUPLEX_HALF) 52 return "Half"; 53 if (duplex == DUPLEX_FULL) 54 return "Full"; 55 if (duplex == DUPLEX_UNKNOWN) 56 return "Unknown"; 57 return "Unsupported (update phy-core.c)"; 58 } 59 EXPORT_SYMBOL_GPL(phy_duplex_to_str); 60 61 /* A mapping of all SUPPORTED settings to speed/duplex. This table 62 * must be grouped by speed and sorted in descending match priority 63 * - iow, descending speed. */ 64 static const struct phy_setting settings[] = { 65 { 66 .speed = SPEED_10000, 67 .duplex = DUPLEX_FULL, 68 .bit = ETHTOOL_LINK_MODE_10000baseKR_Full_BIT, 69 }, 70 { 71 .speed = SPEED_10000, 72 .duplex = DUPLEX_FULL, 73 .bit = ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT, 74 }, 75 { 76 .speed = SPEED_10000, 77 .duplex = DUPLEX_FULL, 78 .bit = ETHTOOL_LINK_MODE_10000baseT_Full_BIT, 79 }, 80 { 81 .speed = SPEED_2500, 82 .duplex = DUPLEX_FULL, 83 .bit = ETHTOOL_LINK_MODE_2500baseX_Full_BIT, 84 }, 85 { 86 .speed = SPEED_1000, 87 .duplex = DUPLEX_FULL, 88 .bit = ETHTOOL_LINK_MODE_1000baseKX_Full_BIT, 89 }, 90 { 91 .speed = SPEED_1000, 92 .duplex = DUPLEX_FULL, 93 .bit = ETHTOOL_LINK_MODE_1000baseT_Full_BIT, 94 }, 95 { 96 .speed = SPEED_1000, 97 .duplex = DUPLEX_HALF, 98 .bit = ETHTOOL_LINK_MODE_1000baseT_Half_BIT, 99 }, 100 { 101 .speed = SPEED_100, 102 .duplex = DUPLEX_FULL, 103 .bit = ETHTOOL_LINK_MODE_100baseT_Full_BIT, 104 }, 105 { 106 .speed = SPEED_100, 107 .duplex = DUPLEX_HALF, 108 .bit = ETHTOOL_LINK_MODE_100baseT_Half_BIT, 109 }, 110 { 111 .speed = SPEED_10, 112 .duplex = DUPLEX_FULL, 113 .bit = ETHTOOL_LINK_MODE_10baseT_Full_BIT, 114 }, 115 { 116 .speed = SPEED_10, 117 .duplex = DUPLEX_HALF, 118 .bit = ETHTOOL_LINK_MODE_10baseT_Half_BIT, 119 }, 120 }; 121 122 /** 123 * phy_lookup_setting - lookup a PHY setting 124 * @speed: speed to match 125 * @duplex: duplex to match 126 * @mask: allowed link modes 127 * @maxbit: bit size of link modes 128 * @exact: an exact match is required 129 * 130 * Search the settings array for a setting that matches the speed and 131 * duplex, and which is supported. 132 * 133 * If @exact is unset, either an exact match or %NULL for no match will 134 * be returned. 135 * 136 * If @exact is set, an exact match, the fastest supported setting at 137 * or below the specified speed, the slowest supported setting, or if 138 * they all fail, %NULL will be returned. 139 */ 140 const struct phy_setting * 141 phy_lookup_setting(int speed, int duplex, const unsigned long *mask, 142 size_t maxbit, bool exact) 143 { 144 const struct phy_setting *p, *match = NULL, *last = NULL; 145 int i; 146 147 for (i = 0, p = settings; i < ARRAY_SIZE(settings); i++, p++) { 148 if (p->bit < maxbit && test_bit(p->bit, mask)) { 149 last = p; 150 if (p->speed == speed && p->duplex == duplex) { 151 /* Exact match for speed and duplex */ 152 match = p; 153 break; 154 } else if (!exact) { 155 if (!match && p->speed <= speed) 156 /* Candidate */ 157 match = p; 158 159 if (p->speed < speed) 160 break; 161 } 162 } 163 } 164 165 if (!match && !exact) 166 match = last; 167 168 return match; 169 } 170 EXPORT_SYMBOL_GPL(phy_lookup_setting); 171 172 size_t phy_speeds(unsigned int *speeds, size_t size, 173 unsigned long *mask, size_t maxbit) 174 { 175 size_t count; 176 int i; 177 178 for (i = 0, count = 0; i < ARRAY_SIZE(settings) && count < size; i++) 179 if (settings[i].bit < maxbit && 180 test_bit(settings[i].bit, mask) && 181 (count == 0 || speeds[count - 1] != settings[i].speed)) 182 speeds[count++] = settings[i].speed; 183 184 return count; 185 } 186 187 static void mmd_phy_indirect(struct mii_bus *bus, int phy_addr, int devad, 188 u16 regnum) 189 { 190 /* Write the desired MMD Devad */ 191 bus->write(bus, phy_addr, MII_MMD_CTRL, devad); 192 193 /* Write the desired MMD register address */ 194 bus->write(bus, phy_addr, MII_MMD_DATA, regnum); 195 196 /* Select the Function : DATA with no post increment */ 197 bus->write(bus, phy_addr, MII_MMD_CTRL, devad | MII_MMD_CTRL_NOINCR); 198 } 199 200 /** 201 * phy_read_mmd - Convenience function for reading a register 202 * from an MMD on a given PHY. 203 * @phydev: The phy_device struct 204 * @devad: The MMD to read from (0..31) 205 * @regnum: The register on the MMD to read (0..65535) 206 * 207 * Same rules as for phy_read(); 208 */ 209 int phy_read_mmd(struct phy_device *phydev, int devad, u32 regnum) 210 { 211 int val; 212 213 if (regnum > (u16)~0 || devad > 32) 214 return -EINVAL; 215 216 if (phydev->drv->read_mmd) { 217 val = phydev->drv->read_mmd(phydev, devad, regnum); 218 } else if (phydev->is_c45) { 219 u32 addr = MII_ADDR_C45 | (devad << 16) | (regnum & 0xffff); 220 221 val = mdiobus_read(phydev->mdio.bus, phydev->mdio.addr, addr); 222 } else { 223 struct mii_bus *bus = phydev->mdio.bus; 224 int phy_addr = phydev->mdio.addr; 225 226 mutex_lock(&bus->mdio_lock); 227 mmd_phy_indirect(bus, phy_addr, devad, regnum); 228 229 /* Read the content of the MMD's selected register */ 230 val = bus->read(bus, phy_addr, MII_MMD_DATA); 231 mutex_unlock(&bus->mdio_lock); 232 } 233 return val; 234 } 235 EXPORT_SYMBOL(phy_read_mmd); 236 237 /** 238 * phy_write_mmd - Convenience function for writing a register 239 * on an MMD on a given PHY. 240 * @phydev: The phy_device struct 241 * @devad: The MMD to read from 242 * @regnum: The register on the MMD to read 243 * @val: value to write to @regnum 244 * 245 * Same rules as for phy_write(); 246 */ 247 int phy_write_mmd(struct phy_device *phydev, int devad, u32 regnum, u16 val) 248 { 249 int ret; 250 251 if (regnum > (u16)~0 || devad > 32) 252 return -EINVAL; 253 254 if (phydev->drv->write_mmd) { 255 ret = phydev->drv->write_mmd(phydev, devad, regnum, val); 256 } else if (phydev->is_c45) { 257 u32 addr = MII_ADDR_C45 | (devad << 16) | (regnum & 0xffff); 258 259 ret = mdiobus_write(phydev->mdio.bus, phydev->mdio.addr, 260 addr, val); 261 } else { 262 struct mii_bus *bus = phydev->mdio.bus; 263 int phy_addr = phydev->mdio.addr; 264 265 mutex_lock(&bus->mdio_lock); 266 mmd_phy_indirect(bus, phy_addr, devad, regnum); 267 268 /* Write the data into MMD's selected register */ 269 bus->write(bus, phy_addr, MII_MMD_DATA, val); 270 mutex_unlock(&bus->mdio_lock); 271 272 ret = 0; 273 } 274 return ret; 275 } 276 EXPORT_SYMBOL(phy_write_mmd); 277