Skip to content
Snippets Groups Projects
Commit 995daa0b authored by Andy Fleming's avatar Andy Fleming
Browse files

Add mdio command for new PHY infrastructure


The new mdio command doesn't have all of the features of the mii
command, but it provides the necessary read/write primitives, and allows
users to interact with 10G PHYs, and other PHYs which use Clause 45 of
802.3.  This means that the mdio command requires a "Device Address"
argument, though for clause 22 PHYs, the argument can be "-".

Signed-off-by: default avatarAndy Fleming <afleming@freescale.com>
Acked-by: default avatarDetlev Zundel <dzu@denx.de>
parent 865ff856
No related branches found
No related tags found
No related merge requests found
...@@ -117,6 +117,9 @@ COBJS-$(CONFIG_MII) += miiphyutil.o ...@@ -117,6 +117,9 @@ COBJS-$(CONFIG_MII) += miiphyutil.o
COBJS-$(CONFIG_CMD_MII) += miiphyutil.o COBJS-$(CONFIG_CMD_MII) += miiphyutil.o
COBJS-$(CONFIG_PHYLIB) += miiphyutil.o COBJS-$(CONFIG_PHYLIB) += miiphyutil.o
COBJS-$(CONFIG_CMD_MII) += cmd_mii.o COBJS-$(CONFIG_CMD_MII) += cmd_mii.o
ifdef CONFIG_PHYLIB
COBJS-$(CONFIG_CMD_MII) += cmd_mdio.o
endif
COBJS-$(CONFIG_CMD_MISC) += cmd_misc.o COBJS-$(CONFIG_CMD_MISC) += cmd_misc.o
COBJS-$(CONFIG_CMD_MMC) += cmd_mmc.o COBJS-$(CONFIG_CMD_MMC) += cmd_mmc.o
COBJS-$(CONFIG_MP) += cmd_mp.o COBJS-$(CONFIG_MP) += cmd_mp.o
......
/*
* (C) Copyright 2011 Freescale Semiconductor, Inc
* Andy Fleming
*
* See file CREDITS for list of people who contributed to this
* project.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
/*
* MDIO Commands
*/
#include <common.h>
#include <command.h>
#include <miiphy.h>
#include <phy.h>
static char last_op[2];
static uint last_data;
static uint last_addr_lo;
static uint last_addr_hi;
static uint last_devad_lo;
static uint last_devad_hi;
static uint last_reg_lo;
static uint last_reg_hi;
static int extract_range(char *input, int *plo, int *phi)
{
char *end;
*plo = simple_strtol(input, &end, 0);
if (end == input)
return -1;
if ((*end == '-') && *(++end))
*phi = simple_strtol(end, NULL, 0);
else if (*end == '\0')
*phi = *plo;
else
return -1;
return 0;
}
int mdio_write_ranges(struct mii_dev *bus, int addrlo,
int addrhi, int devadlo, int devadhi,
int reglo, int reghi, unsigned short data)
{
int addr, devad, reg;
int err = 0;
for (addr = addrlo; addr <= addrhi; addr++) {
for (devad = devadlo; devad <= devadhi; devad++) {
for (reg = reglo; reg <= reghi; reg++) {
err = bus->write(bus, addr, devad, reg, data);
if (err)
goto err_out;
}
}
}
err_out:
return err;
}
int mdio_read_ranges(struct mii_dev *bus, int addrlo,
int addrhi, int devadlo, int devadhi,
int reglo, int reghi)
{
int addr, devad, reg;
printf("Reading from bus %s\n", bus->name);
for (addr = addrlo; addr <= addrhi; addr++) {
printf("PHY at address %d:\n", addr);
for (devad = devadlo; devad <= devadhi; devad++) {
for (reg = reglo; reg <= reghi; reg++) {
u16 val;
val = bus->read(bus, addr, devad, reg);
if (val < 0) {
printf("Error\n");
return val;
}
if (devad >= 0)
printf("%d.", devad);
printf("%d - 0x%x\n", reg, val & 0xffff);
}
}
}
return 0;
}
/* The register will be in the form [a[-b].]x[-y] */
int extract_reg_range(char *input, int *devadlo, int *devadhi,
int *reglo, int *reghi)
{
char *regstr;
/* use strrchr to find the last string after a '.' */
regstr = strrchr(input, '.');
/* If it exists, extract the devad(s) */
if (regstr) {
char devadstr[32];
strncpy(devadstr, input, regstr - input);
devadstr[regstr - input] = '\0';
if (extract_range(devadstr, devadlo, devadhi))
return -1;
regstr++;
} else {
/* Otherwise, we have no devad, and we just got regs */
*devadlo = *devadhi = MDIO_DEVAD_NONE;
regstr = input;
}
return extract_range(regstr, reglo, reghi);
}
int extract_phy_range(char *const argv[], int argc, struct mii_dev **bus,
int *addrlo, int *addrhi)
{
struct phy_device *phydev;
if ((argc < 1) || (argc > 2))
return -1;
/* If there are two arguments, it's busname addr */
if (argc == 2) {
*bus = miiphy_get_dev_by_name(argv[0]);
if (!*bus)
return -1;
return extract_range(argv[1], addrlo, addrhi);
}
/* It must be one argument, here */
/*
* This argument can be one of two things:
* 1) Ethernet device name
* 2) Just an address (use the previously-used bus)
*
* We check all buses for a PHY which is connected to an ethernet
* device by the given name. If none are found, we call
* extract_range() on the string, and see if it's an address range.
*/
phydev = mdio_phydev_for_ethname(argv[0]);
if (phydev) {
*addrlo = *addrhi = phydev->addr;
*bus = phydev->bus;
return 0;
}
/* It's an address or nothing useful */
return extract_range(argv[0], addrlo, addrhi);
}
/* ---------------------------------------------------------------- */
static int do_mdio(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
char op[2];
int addrlo, addrhi, reglo, reghi, devadlo, devadhi;
unsigned short data;
int pos = argc - 1;
struct mii_dev *bus;
if (argc < 2)
return cmd_usage(cmdtp);
/*
* We use the last specified parameters, unless new ones are
* entered.
*/
op[0] = argv[1][0];
addrlo = last_addr_lo;
addrhi = last_addr_hi;
devadlo = last_devad_lo;
devadhi = last_devad_hi;
reglo = last_reg_lo;
reghi = last_reg_hi;
data = last_data;
bus = mdio_get_current_dev();
if (flag & CMD_FLAG_REPEAT)
op[0] = last_op[0];
switch (op[0]) {
case 'w':
if (pos > 1)
data = simple_strtoul(argv[pos--], NULL, 16);
case 'r':
if (pos > 1)
if (extract_reg_range(argv[pos--], &devadlo, &devadhi,
&reglo, &reghi))
return -1;
default:
if (pos > 1)
if (extract_phy_range(&(argv[2]), pos - 1, &bus,
&addrlo, &addrhi))
return -1;
break;
}
if (op[0] == 'l') {
mdio_list_devices();
return 0;
}
/* Save the chosen bus */
miiphy_set_current_dev(bus->name);
switch (op[0]) {
case 'w':
mdio_write_ranges(bus, addrlo, addrhi, devadlo, devadhi,
reglo, reghi, data);
break;
case 'r':
mdio_read_ranges(bus, addrlo, addrhi, devadlo, devadhi,
reglo, reghi);
break;
}
/*
* Save the parameters for repeats.
*/
last_op[0] = op[0];
last_addr_lo = addrlo;
last_addr_hi = addrhi;
last_devad_lo = devadlo;
last_devad_hi = devadhi;
last_reg_lo = reglo;
last_reg_hi = reghi;
last_data = data;
return 0;
}
/***************************************************/
U_BOOT_CMD(
mdio, 6, 1, do_mdio,
"MDIO utility commands",
"list - List MDIO buses\n"
"mdio read <phydev> [<devad>.]<reg> - "
"read PHY's register at <devad>.<reg>\n"
"mdio write <phydev> [<devad>.]<reg> <data> - "
"write PHY's register at <devad>.<reg>\n"
"<phydev> may be:\n"
" <busname> <addr>\n"
" <addr>\n"
" <eth name>\n"
"<addr> <devad>, and <reg> may be ranges, e.g. 1-5.4-0x1f.\n"
);
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment