"Das U-Boot" Source Tree
at master 333 lines 7.2 kB view raw
1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * (C) Copyright 2011 Freescale Semiconductor, Inc 4 * Andy Fleming 5 */ 6 7/* 8 * MDIO Commands 9 */ 10 11#include <command.h> 12#include <dm.h> 13#include <miiphy.h> 14#include <phy.h> 15 16static char last_op[2]; 17static uint last_data; 18static uint last_addr_lo; 19static uint last_addr_hi; 20static uint last_devad_lo; 21static uint last_devad_hi; 22static uint last_reg_lo; 23static uint last_reg_hi; 24 25static int extract_range(char *input, int *plo, int *phi) 26{ 27 char *end; 28 *plo = simple_strtol(input, &end, 16); 29 if (end == input) 30 return -1; 31 32 if ((*end == '-') && *(++end)) 33 *phi = simple_strtol(end, NULL, 16); 34 else if (*end == '\0') 35 *phi = *plo; 36 else 37 return -1; 38 39 return 0; 40} 41 42static int mdio_write_ranges(struct mii_dev *bus, 43 int addrlo, 44 int addrhi, int devadlo, int devadhi, 45 int reglo, int reghi, unsigned short data, 46 int extended) 47{ 48 struct phy_device *phydev; 49 int addr, devad, reg; 50 int err = 0; 51 52 for (addr = addrlo; addr <= addrhi; addr++) { 53 phydev = bus->phymap[addr]; 54 55 for (devad = devadlo; devad <= devadhi; devad++) { 56 for (reg = reglo; reg <= reghi; reg++) { 57 if (!phydev) 58 err = bus->write(bus, addr, devad, 59 reg, data); 60 else if (!extended) 61 err = phy_write_mmd(phydev, devad, 62 reg, data); 63 else 64 err = phydev->drv->writeext(phydev, 65 addr, devad, reg, data); 66 67 if (err) 68 goto err_out; 69 } 70 } 71 } 72 73err_out: 74 return err; 75} 76 77static int mdio_read_ranges(struct mii_dev *bus, 78 int addrlo, 79 int addrhi, int devadlo, int devadhi, 80 int reglo, int reghi, int extended) 81{ 82 int addr, devad, reg; 83 struct phy_device *phydev; 84 85 printf("Reading from bus %s\n", bus->name); 86 for (addr = addrlo; addr <= addrhi; addr++) { 87 phydev = bus->phymap[addr]; 88 printf("PHY at address %x:\n", addr); 89 90 for (devad = devadlo; devad <= devadhi; devad++) { 91 for (reg = reglo; reg <= reghi; reg++) { 92 int val; 93 94 if (!phydev) 95 val = bus->read(bus, addr, devad, reg); 96 else if (!extended) 97 val = phy_read_mmd(phydev, devad, reg); 98 else 99 val = phydev->drv->readext(phydev, addr, 100 devad, reg); 101 102 if (val < 0) { 103 printf("Error\n"); 104 105 return val; 106 } 107 108 if (devad >= 0) 109 printf("%d.", devad); 110 111 printf("%d - 0x%x\n", reg, val & 0xffff); 112 } 113 } 114 } 115 116 return 0; 117} 118 119/* The register will be in the form [a[-b].]x[-y] */ 120static int extract_reg_range(char *input, int *devadlo, int *devadhi, 121 int *reglo, int *reghi) 122{ 123 char *regstr; 124 125 /* use strrchr to find the last string after a '.' */ 126 regstr = strrchr(input, '.'); 127 128 /* If it exists, extract the devad(s) */ 129 if (regstr) { 130 char devadstr[32]; 131 132 strncpy(devadstr, input, regstr - input); 133 devadstr[regstr - input] = '\0'; 134 135 if (extract_range(devadstr, devadlo, devadhi)) 136 return -1; 137 138 regstr++; 139 } else { 140 /* Otherwise, we have no devad, and we just got regs */ 141 *devadlo = *devadhi = MDIO_DEVAD_NONE; 142 143 regstr = input; 144 } 145 146 return extract_range(regstr, reglo, reghi); 147} 148 149static int extract_phy_range(char *const argv[], int argc, struct mii_dev **bus, 150 struct phy_device **phydev, 151 int *addrlo, int *addrhi) 152{ 153 struct phy_device *dev = *phydev; 154 155 if ((argc < 1) || (argc > 2)) 156 return -1; 157 158 /* If there are two arguments, it's busname addr */ 159 if (argc == 2) { 160 *bus = miiphy_get_dev_by_name(argv[0]); 161 162 if (!*bus) 163 return -1; 164 165 return extract_range(argv[1], addrlo, addrhi); 166 } 167 168 /* It must be one argument, here */ 169 170 /* 171 * This argument can be one of two things: 172 * 1) Ethernet device name 173 * 2) Just an address (use the previously-used bus) 174 * 175 * We check all buses for a PHY which is connected to an ethernet 176 * device by the given name. If none are found, we call 177 * extract_range() on the string, and see if it's an address range. 178 */ 179 dev = mdio_phydev_for_ethname(argv[0]); 180 181 if (dev) { 182 *addrlo = *addrhi = dev->addr; 183 *bus = dev->bus; 184 185 return 0; 186 } 187 188 /* It's an address or nothing useful */ 189 return extract_range(argv[0], addrlo, addrhi); 190} 191 192/* ---------------------------------------------------------------- */ 193static int do_mdio(struct cmd_tbl *cmdtp, int flag, int argc, 194 char *const argv[]) 195{ 196 char op[2]; 197 int addrlo, addrhi, reglo, reghi, devadlo, devadhi; 198 unsigned short data; 199 int pos = argc - 1; 200 struct mii_dev *bus; 201 struct phy_device *phydev = NULL; 202 int extended = 0; 203 204 if (argc < 2) 205 return CMD_RET_USAGE; 206 207#ifdef CONFIG_DM_MDIO 208 /* probe DM MII device before any operation so they are all accesible */ 209 dm_mdio_probe_devices(); 210#endif 211 212 /* 213 * We use the last specified parameters, unless new ones are 214 * entered. 215 */ 216 op[0] = argv[1][0]; 217 addrlo = last_addr_lo; 218 addrhi = last_addr_hi; 219 devadlo = last_devad_lo; 220 devadhi = last_devad_hi; 221 reglo = last_reg_lo; 222 reghi = last_reg_hi; 223 data = last_data; 224 225 bus = mdio_get_current_dev(); 226 227 if (flag & CMD_FLAG_REPEAT) 228 op[0] = last_op[0]; 229 230 if (strlen(argv[1]) > 1) { 231 op[1] = argv[1][1]; 232 if (op[1] == 'x') { 233 phydev = mdio_phydev_for_ethname(argv[2]); 234 235 if (phydev) { 236 addrlo = phydev->addr; 237 addrhi = addrlo; 238 bus = phydev->bus; 239 extended = 1; 240 } else { 241 return CMD_RET_FAILURE; 242 } 243 244 if (!phydev->drv || 245 (!phydev->drv->writeext && (op[0] == 'w')) || 246 (!phydev->drv->readext && (op[0] == 'r'))) { 247 puts("PHY does not have extended functions\n"); 248 return CMD_RET_FAILURE; 249 } 250 } 251 } 252 253 switch (op[0]) { 254 case 'w': 255 if (pos > 1) 256 data = hextoul(argv[pos--], NULL); 257 /* Intentional fall-through - Get reg for read and write */ 258 case 'r': 259 if (pos > 1) 260 if (extract_reg_range(argv[pos--], &devadlo, &devadhi, 261 &reglo, &reghi)) 262 return CMD_RET_FAILURE; 263 /* Intentional fall-through - Get phy for all commands */ 264 default: 265 if (pos > 1) 266 if (extract_phy_range(&argv[2], pos - 1, &bus, 267 &phydev, &addrlo, &addrhi)) 268 return CMD_RET_FAILURE; 269 270 break; 271 } 272 273 if (!bus) { 274 puts("No MDIO bus found\n"); 275 return CMD_RET_FAILURE; 276 } 277 278 if (op[0] == 'l') { 279 mdio_list_devices(); 280 281 return 0; 282 } 283 284 /* Save the chosen bus */ 285 miiphy_set_current_dev(bus->name); 286 287 switch (op[0]) { 288 case 'w': 289 mdio_write_ranges(bus, addrlo, addrhi, devadlo, devadhi, 290 reglo, reghi, data, extended); 291 break; 292 293 case 'r': 294 mdio_read_ranges(bus, addrlo, addrhi, devadlo, devadhi, 295 reglo, reghi, extended); 296 break; 297 } 298 299 /* 300 * Save the parameters for repeats. 301 */ 302 last_op[0] = op[0]; 303 last_addr_lo = addrlo; 304 last_addr_hi = addrhi; 305 last_devad_lo = devadlo; 306 last_devad_hi = devadhi; 307 last_reg_lo = reglo; 308 last_reg_hi = reghi; 309 last_data = data; 310 311 return 0; 312} 313 314/***************************************************/ 315 316U_BOOT_CMD( 317 mdio, 6, 1, do_mdio, 318 "MDIO utility commands", 319 "list - List MDIO buses\n" 320 "mdio read <phydev> [<devad>.]<reg> - " 321 "read PHY's register at <devad>.<reg>\n" 322 "mdio write <phydev> [<devad>.]<reg> <data> - " 323 "write PHY's register at <devad>.<reg>\n" 324 "mdio rx <phydev> [<devad>.]<reg> - " 325 "read PHY's extended register at <devad>.<reg>\n" 326 "mdio wx <phydev> [<devad>.]<reg> <data> - " 327 "write PHY's extended register at <devad>.<reg>\n" 328 "<phydev> may be:\n" 329 " <busname> <addr>\n" 330 " <addr>\n" 331 " <eth name>\n" 332 "<addr> <devad>, and <reg> may be ranges, e.g. 1-5.4-0x1f.\n" 333);