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