9
0
Fork 0

Merge branch 'for-next/net'

This commit is contained in:
Sascha Hauer 2016-02-08 08:26:45 +01:00
commit a22f59c178
12 changed files with 739 additions and 60 deletions

View File

@ -203,7 +203,7 @@ compatible NFS URI string must be passed to the boot command:
.. code-block:: sh
boot nfs://nfshost//path/
boot nfs://nfshost[:port]//path/
Additionally to the options defined in the original spec barebox understands the
``linux-appendroot`` option. This is a boolean value and if set to ``true`` barebox

View File

@ -115,8 +115,9 @@ static int show_basic_mii(struct mii_bus *mii, struct phy_device *phydev,
for (i = 0; i < 32; i++)
mii_val[i] = mii->read(mii, phydev->addr, i);
printf("%s: %s%d: ", phydev->cdev.name,
mii->parent->name, mii->parent->id);
printf((mii->parent->id) < 0 ? "%s: %s:" : "%s: %s%d: ",
phydev->cdev.name, mii->parent->name, mii->parent->id);
if (mii_val[MII_BMCR] == 0xffff || mii_val[MII_BMSR] == 0x0000) {
fprintf(stderr, " No MII transceiver present!.\n");
@ -233,70 +234,137 @@ static void mdiobus_show(struct device_d *dev, char *phydevname, int verbose)
struct phy_device *phydev;
phydev = mdiobus_scan(mii, i);
if (IS_ERR(phydev))
if (IS_ERR(phydev) || !phydev->registered)
continue;
if (phydev->registered) {
show_basic_mii(mii, phydev, verbose);
/*
* If we are looking for a secific phy, called
* 'phydevname', but current phydev is not it, skip to
* the next iteration
*/
if (phydevname &&
strcmp(phydev->cdev.name, phydevname))
continue;
if (phydevname &&
!strcmp(phydev->cdev.name, phydevname)) {
return;
}
}
show_basic_mii(mii, phydev, verbose);
/*
* We were looking for a specific device and at this
* point we already shown the info about it so end the
* loop and exit
*/
if (phydevname)
break;
}
return;
}
enum miitool_operations {
MIITOOL_NOOP,
MIITOOL_SHOW,
MIITOOL_REGISTER,
};
static int do_miitool(int argc, char *argv[])
{
char *phydevname;
char *phydevname = NULL;
char *regstr = NULL;
char *endp;
struct mii_bus *mii;
int opt;
int argc_min;
int verbose;
int opt, ret;
int verbose = 0;
struct phy_device *phydev;
enum miitool_operations action = MIITOOL_NOOP;
int addr, bus;
verbose = 0;
while ((opt = getopt(argc, argv, "v")) > 0) {
while ((opt = getopt(argc, argv, "vs:r:")) > 0) {
switch (opt) {
case 'a':
addr = simple_strtol(optarg, NULL, 0);
break;
case 'b':
bus = simple_strtoul(optarg, NULL, 0);
break;
case 's':
action = MIITOOL_SHOW;
phydevname = xstrdup(optarg);
break;
case 'r':
action = MIITOOL_REGISTER;
regstr = optarg;
break;
case 'v':
verbose++;
break;
default:
return COMMAND_ERROR_USAGE;
ret = COMMAND_ERROR_USAGE;
goto free_phydevname;
}
}
argc_min = optind + 1;
switch (action) {
case MIITOOL_REGISTER:
bus = simple_strtoul(regstr, &endp, 0);
if (*endp != ':') {
printf("No colon between bus and address\n");
return COMMAND_ERROR_USAGE;
}
endp++;
addr = simple_strtoul(endp, NULL, 0);
phydevname = NULL;
if (argc >= argc_min) {
phydevname = argv[optind];
if (addr >= PHY_MAX_ADDR)
printf("Address out of range (max %d)\n", PHY_MAX_ADDR - 1);
mii = mdiobus_get_bus(bus);
if (!mii) {
printf("Can't find MDIO bus #%d\n", bus);
ret = COMMAND_ERROR;
goto free_phydevname;
}
phydev = phy_device_create(mii, addr, -1);
ret = phy_register_device(phydev);
if (ret) {
printf("failed to register phy %s: %s\n",
dev_name(&phydev->dev), strerror(-ret));
goto free_phydevname;
} else {
printf("registered phy %s\n", dev_name(&phydev->dev));
}
break;
default:
case MIITOOL_SHOW:
for_each_mii_bus(mii) {
mdiobus_detect(&mii->dev);
mdiobus_show(&mii->dev, phydevname, verbose);
}
break;
}
for_each_mii_bus(mii) {
mdiobus_detect(&mii->dev);
mdiobus_show(&mii->dev, phydevname, verbose);
}
ret = COMMAND_SUCCESS;
return COMMAND_SUCCESS;
free_phydevname:
free(phydevname);
return ret;
}
BAREBOX_CMD_HELP_START(miitool)
BAREBOX_CMD_HELP_TEXT("This utility checks or sets the status of a network interface's")
BAREBOX_CMD_HELP_TEXT("Media Independent Interface (MII) unit. Most fast ethernet")
BAREBOX_CMD_HELP_TEXT("Media Independent Interface (MII) unit as well as allowing to")
BAREBOX_CMD_HELP_TEXT("register dummy PHY devices for raw MDIO access. Most fast ethernet")
BAREBOX_CMD_HELP_TEXT("adapters use an MII to autonegotiate link speed and duplex setting.")
BAREBOX_CMD_HELP_TEXT("")
BAREBOX_CMD_HELP_TEXT("Options:")
BAREBOX_CMD_HELP_OPT("-v", "increase verbosity")
BAREBOX_CMD_HELP_OPT("-s <devname>", "show PHY status (not providing PHY prints status of all)")
BAREBOX_CMD_HELP_OPT("-r <busno>:<adr>", "register a PHY")
BAREBOX_CMD_HELP_END
BAREBOX_CMD_START(miitool)
.cmd = do_miitool,
BAREBOX_CMD_DESC("view media-independent interface status")
BAREBOX_CMD_OPTS("[-v] PHY")
BAREBOX_CMD_OPTS("[-vsr]")
BAREBOX_CMD_GROUP(CMD_GRP_NET)
BAREBOX_CMD_HELP(cmd_miitool_help)
BAREBOX_CMD_END

View File

@ -46,6 +46,21 @@ config MDIO_MVEBU
---help---
Driver for the MDIO bus found on Marvell EBU SoCs.
config MDIO_BITBANG
bool "Support for bitbanged MDIO buses"
---help---
This module implements the MDIO bus protocol in software,
for use by low level drivers that export the ability to
drive the relevant pins.
If in doubt, say N.
config MDIO_GPIO
bool "Support for GPIO lib-based bitbanged MDIO buses"
depends on MDIO_BITBANG && GPIOLIB
---help---
Supports GPIO lib-based MDIO busses.
endif
endmenu

View File

@ -7,3 +7,5 @@ obj-$(CONFIG_NATIONAL_PHY) += national.o
obj-$(CONFIG_SMSC_PHY) += smsc.o
obj-$(CONFIG_MDIO_MVEBU) += mdio-mvebu.o
obj-$(CONFIG_MDIO_BITBANG) += mdio-bitbang.o
obj-$(CONFIG_MDIO_GPIO) += mdio-gpio.o

View File

@ -0,0 +1,228 @@
/*
* Bitbanged MDIO support.
*
* Author: Scott Wood <scottwood@freescale.com>
* Copyright (c) 2007 Freescale Semiconductor
*
* Based on CPM2 MDIO code which is:
*
* Copyright (c) 2003 Intracom S.A.
* by Pantelis Antoniou <panto@intracom.gr>
*
* 2005 (c) MontaVista Software, Inc.
* Vitaly Bordug <vbordug@ru.mvista.com>
*
* This file is licensed under the terms of the GNU General Public License
* version 2. This program is licensed "as is" without any warranty of any
* kind, whether express or implied.
*/
#include <common.h>
#include <driver.h>
#include <linux/phy.h>
#include <linux/mdio-bitbang.h>
#define MDIO_READ 2
#define MDIO_WRITE 1
#define MDIO_C45 (1<<15)
#define MDIO_C45_ADDR (MDIO_C45 | 0)
#define MDIO_C45_READ (MDIO_C45 | 3)
#define MDIO_C45_WRITE (MDIO_C45 | 1)
#define MDIO_SETUP_TIME 10
#define MDIO_HOLD_TIME 10
/* Minimum MDC period is 400 ns, plus some margin for error. MDIO_DELAY
* is done twice per period.
*/
#define MDIO_DELAY 250
/* The PHY may take up to 300 ns to produce data, plus some margin
* for error.
*/
#define MDIO_READ_DELAY 350
/* MDIO must already be configured as output. */
static void mdiobb_send_bit(struct mdiobb_ctrl *ctrl, int val)
{
const struct mdiobb_ops *ops = ctrl->ops;
ops->set_mdio_data(ctrl, val);
ndelay(MDIO_DELAY);
ops->set_mdc(ctrl, 1);
ndelay(MDIO_DELAY);
ops->set_mdc(ctrl, 0);
}
/* MDIO must already be configured as input. */
static int mdiobb_get_bit(struct mdiobb_ctrl *ctrl)
{
const struct mdiobb_ops *ops = ctrl->ops;
ndelay(MDIO_DELAY);
ops->set_mdc(ctrl, 1);
ndelay(MDIO_READ_DELAY);
ops->set_mdc(ctrl, 0);
return ops->get_mdio_data(ctrl);
}
/* MDIO must already be configured as output. */
static void mdiobb_send_num(struct mdiobb_ctrl *ctrl, u16 val, int bits)
{
int i;
for (i = bits - 1; i >= 0; i--)
mdiobb_send_bit(ctrl, (val >> i) & 1);
}
/* MDIO must already be configured as input. */
static u16 mdiobb_get_num(struct mdiobb_ctrl *ctrl, int bits)
{
int i;
u16 ret = 0;
for (i = bits - 1; i >= 0; i--) {
ret <<= 1;
ret |= mdiobb_get_bit(ctrl);
}
return ret;
}
/* Utility to send the preamble, address, and
* register (common to read and write).
*/
static void mdiobb_cmd(struct mdiobb_ctrl *ctrl, int op, u8 phy, u8 reg)
{
const struct mdiobb_ops *ops = ctrl->ops;
int i;
ops->set_mdio_dir(ctrl, 1);
/*
* Send a 32 bit preamble ('1's) with an extra '1' bit for good
* measure. The IEEE spec says this is a PHY optional
* requirement. The AMD 79C874 requires one after power up and
* one after a MII communications error. This means that we are
* doing more preambles than we need, but it is safer and will be
* much more robust.
*/
for (i = 0; i < 32; i++)
mdiobb_send_bit(ctrl, 1);
/* send the start bit (01) and the read opcode (10) or write (10).
Clause 45 operation uses 00 for the start and 11, 10 for
read/write */
mdiobb_send_bit(ctrl, 0);
if (op & MDIO_C45)
mdiobb_send_bit(ctrl, 0);
else
mdiobb_send_bit(ctrl, 1);
mdiobb_send_bit(ctrl, (op >> 1) & 1);
mdiobb_send_bit(ctrl, (op >> 0) & 1);
mdiobb_send_num(ctrl, phy, 5);
mdiobb_send_num(ctrl, reg, 5);
}
/* In clause 45 mode all commands are prefixed by MDIO_ADDR to specify the
lower 16 bits of the 21 bit address. This transfer is done identically to a
MDIO_WRITE except for a different code. To enable clause 45 mode or
MII_ADDR_C45 into the address. Theoretically clause 45 and normal devices
can exist on the same bus. Normal devices should ignore the MDIO_ADDR
phase. */
static int mdiobb_cmd_addr(struct mdiobb_ctrl *ctrl, int phy, u32 addr)
{
unsigned int dev_addr = (addr >> 16) & 0x1F;
unsigned int reg = addr & 0xFFFF;
mdiobb_cmd(ctrl, MDIO_C45_ADDR, phy, dev_addr);
/* send the turnaround (10) */
mdiobb_send_bit(ctrl, 1);
mdiobb_send_bit(ctrl, 0);
mdiobb_send_num(ctrl, reg, 16);
ctrl->ops->set_mdio_dir(ctrl, 0);
mdiobb_get_bit(ctrl);
return dev_addr;
}
static int mdiobb_read(struct mii_bus *bus, int phy, int reg)
{
struct mdiobb_ctrl *ctrl = bus->priv;
int ret, i;
if (reg & MII_ADDR_C45) {
reg = mdiobb_cmd_addr(ctrl, phy, reg);
mdiobb_cmd(ctrl, MDIO_C45_READ, phy, reg);
} else
mdiobb_cmd(ctrl, MDIO_READ, phy, reg);
ctrl->ops->set_mdio_dir(ctrl, 0);
/* check the turnaround bit: the PHY should be driving it to zero, if this
* PHY is listed in phy_ignore_ta_mask as having broken TA, skip that
*/
if (mdiobb_get_bit(ctrl) != 0) {
/* PHY didn't drive TA low -- flush any bits it
* may be trying to send.
*/
for (i = 0; i < 32; i++)
mdiobb_get_bit(ctrl);
return 0xffff;
}
ret = mdiobb_get_num(ctrl, 16);
mdiobb_get_bit(ctrl);
return ret;
}
static int mdiobb_write(struct mii_bus *bus, int phy, int reg, u16 val)
{
struct mdiobb_ctrl *ctrl = bus->priv;
if (reg & MII_ADDR_C45) {
reg = mdiobb_cmd_addr(ctrl, phy, reg);
mdiobb_cmd(ctrl, MDIO_C45_WRITE, phy, reg);
} else
mdiobb_cmd(ctrl, MDIO_WRITE, phy, reg);
/* send the turnaround (10) */
mdiobb_send_bit(ctrl, 1);
mdiobb_send_bit(ctrl, 0);
mdiobb_send_num(ctrl, val, 16);
ctrl->ops->set_mdio_dir(ctrl, 0);
mdiobb_get_bit(ctrl);
return 0;
}
static int mdiobb_reset(struct mii_bus *bus)
{
struct mdiobb_ctrl *ctrl = bus->priv;
if (ctrl->reset)
ctrl->reset(bus);
return 0;
}
struct mii_bus *alloc_mdio_bitbang(struct mdiobb_ctrl *ctrl)
{
struct mii_bus *bus;
bus = xzalloc(sizeof(*bus));
bus->read = mdiobb_read;
bus->write = mdiobb_write;
bus->reset = mdiobb_reset;
bus->priv = ctrl;
return bus;
}
EXPORT_SYMBOL(alloc_mdio_bitbang);

231
drivers/net/phy/mdio-gpio.c Normal file
View File

@ -0,0 +1,231 @@
/*
* GPIO based MDIO bitbang driver.
* Supports OpenFirmware.
*
* (C) Copyright 2015
* CogentEmbedded, Andrey Gusakov <andrey.gusakov@cogentembedded.com>
*
* based on mvmdio driver from Linux
* Copyright (c) 2008 CSE Semaphore Belgium.
* by Laurent Pinchart <laurentp@cse-semaphore.com>
*
* Copyright (C) 2008, Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
*
* Based on earlier work by
*
* Copyright (c) 2003 Intracom S.A.
* by Pantelis Antoniou <panto@intracom.gr>
*
* 2005 (c) MontaVista Software, Inc.
* Vitaly Bordug <vbordug@ru.mvista.com>
*
* This file is licensed under the terms of the GNU General Public License
* version 2. This program is licensed "as is" without any warranty of any
* kind, whether express or implied.
*/
#define DEBUG
#include <common.h>
#include <driver.h>
#include <init.h>
#include <io.h>
#include <of.h>
#include <of_gpio.h>
#include <linux/phy.h>
#include <gpio.h>
#include <malloc.h>
#include <xfuncs.h>
#include <linux/mdio-bitbang.h>
struct mdio_gpio_info {
struct mdiobb_ctrl ctrl;
int mdc, mdio, mdo;
int mdc_active_low, mdio_active_low, mdo_active_low;
};
struct mdio_gpio_info *mdio_gpio_of_get_info(struct device_d *dev)
{
int ret;
enum of_gpio_flags flags;
struct mdio_gpio_info *info;
info = xzalloc(sizeof(*info));
ret = of_get_gpio_flags(dev->device_node, 0, &flags);
if (ret < 0) {
dev_dbg(dev, "failed to get MDC inforamtion from DT\n");
goto free_info;
}
info->mdc = ret;
info->mdc_active_low = flags & OF_GPIO_ACTIVE_LOW;
ret = of_get_gpio_flags(dev->device_node, 1, &flags);
if (ret < 0) {
dev_dbg(dev, "failed to get MDIO inforamtion from DT\n");
goto free_info;
}
info->mdio = ret;
info->mdio_active_low = flags & OF_GPIO_ACTIVE_LOW;
ret = of_get_gpio_flags(dev->device_node, 2, &flags);
if (ret > 0) {
dev_dbg(dev, "found MDO information in DT\n");
info->mdo = ret;
info->mdo_active_low = flags & OF_GPIO_ACTIVE_LOW;
}
return info;
free_info:
free(info);
return ERR_PTR(ret);
}
static void mdio_dir(struct mdiobb_ctrl *ctrl, int dir)
{
struct mdio_gpio_info *bitbang =
container_of(ctrl, struct mdio_gpio_info, ctrl);
if (bitbang->mdo) {
/* Separate output pin. Always set its value to high
* when changing direction. If direction is input,
* assume the pin serves as pull-up. If direction is
* output, the default value is high.
*/
gpio_set_value(bitbang->mdo,
1 ^ bitbang->mdo_active_low);
return;
}
if (dir)
gpio_direction_output(bitbang->mdio,
1 ^ bitbang->mdio_active_low);
else
gpio_direction_input(bitbang->mdio);
}
static int mdio_get(struct mdiobb_ctrl *ctrl)
{
struct mdio_gpio_info *bitbang =
container_of(ctrl, struct mdio_gpio_info, ctrl);
return gpio_get_value(bitbang->mdio) ^
bitbang->mdio_active_low;
}
static void mdio_set(struct mdiobb_ctrl *ctrl, int what)
{
struct mdio_gpio_info *bitbang =
container_of(ctrl, struct mdio_gpio_info, ctrl);
if (bitbang->mdo)
gpio_set_value(bitbang->mdo,
what ^ bitbang->mdo_active_low);
else
gpio_set_value(bitbang->mdio,
what ^ bitbang->mdio_active_low);
}
static void mdc_set(struct mdiobb_ctrl *ctrl, int what)
{
struct mdio_gpio_info *bitbang =
container_of(ctrl, struct mdio_gpio_info, ctrl);
gpio_set_value(bitbang->mdc, what ^ bitbang->mdc_active_low);
}
static struct mdiobb_ops mdio_gpio_ops = {
.set_mdc = mdc_set,
.set_mdio_dir = mdio_dir,
.set_mdio_data = mdio_set,
.get_mdio_data = mdio_get,
};
static int mdio_gpio_probe(struct device_d *dev)
{
int ret;
struct device_node *np = dev->device_node;
struct mdio_gpio_info *info;
struct mii_bus *bus;
info = mdio_gpio_of_get_info(dev);
if (IS_ERR(info))
return PTR_ERR(info);
info->ctrl.ops = &mdio_gpio_ops;
ret = gpio_request(info->mdc, "mdc");
if (ret < 0) {
dev_dbg(dev, "failed to request MDC\n");
goto free_info;
}
ret = gpio_request(info->mdio, "mdio");
if (ret < 0) {
dev_dbg(dev, "failed to request MDIO\n");
goto free_mdc;
}
if (info->mdo) {
ret = gpio_request(info->mdo, "mdo");
if (ret < 0) {
dev_dbg(dev, "failed to request MDO\n");
goto free_mdio;
}
ret = gpio_direction_output(info->mdo, 1);
if (ret < 0) {
dev_dbg(dev, "failed to set MDO as output\n");
goto free_mdo;
}
ret = gpio_direction_input(info->mdio);
if (ret < 0) {
dev_dbg(dev, "failed to set MDIO as input\n");
goto free_mdo;
}
}
ret = gpio_direction_output(info->mdc, 0);
if (ret < 0) {
dev_dbg(dev, "failed to set MDC as output\n");
goto free_mdo;
}
bus = alloc_mdio_bitbang(&info->ctrl);
bus->parent = dev;
bus->dev.device_node = np;
dev->priv = bus;
ret = mdiobus_register(bus);
if (!ret)
return 0;
free(bus);
free_mdo:
gpio_free(info->mdo);
free_mdc:
gpio_free(info->mdc);
free_mdio:
gpio_free(info->mdio);
free_info:
free(info);
return ret;
}
static const struct of_device_id gpio_mdio_dt_ids[] = {
{ .compatible = "virtual,mdio-gpio", },
{ /* sentinel */ }
};
static struct driver_d mdio_gpio_driver = {
.name = "mdio-gpio",
.probe = mdio_gpio_probe,
.of_compatible = DRV_OF_COMPAT(gpio_mdio_dt_ids),
};
device_platform_driver(mdio_gpio_driver);

View File

@ -43,7 +43,7 @@ int mdiobus_detect(struct device_d *dev)
ret = phy_register_device(phydev);
if (ret)
dev_err(dev, "failed to register phy: %s\n", strerror(-ret));
dev_info(dev, "registered phy as /dev/%s\n", phydev->cdev.name);
dev_dbg(dev, "registered phy as /dev/%s\n", phydev->cdev.name);
}
return 0;
@ -187,6 +187,25 @@ struct phy_device *mdiobus_scan(struct mii_bus *bus, int addr)
}
EXPORT_SYMBOL(mdiobus_scan);
/**
*
* mdio_get_bus - get a MDIO bus from its busnum
*
* @param busnum the desired bus number
*
*/
struct mii_bus *mdiobus_get_bus(int busnum)
{
struct mii_bus *mii;
for_each_mii_bus(mii)
if (mii->dev.id == busnum)
return mii;
return NULL;
}
/**
* mdio_bus_match - determine if given PHY driver supports the given PHY device
* @dev: target PHY device
@ -314,7 +333,9 @@ static int mdio_bus_probe(struct device_d *_dev)
dev_add_param_int_ro(&dev->dev, "phy_addr", dev->addr, "%d");
dev_add_param_int_ro(&dev->dev, "phy_id", dev->phy_id, "0x%08x");
dev->cdev.name = asprintf("phy%d", _dev->id);
dev->cdev.name = xasprintf("mdio%d-phy%02x",
dev->bus->dev.id,
dev->addr);
dev->cdev.size = 64;
dev->cdev.ops = &phydev_ops;
dev->cdev.priv = dev;

View File

@ -25,17 +25,17 @@
/* Operation Mode Strap Override */
#define MII_KSZPHY_OMSO 0x16
#define KSZPHY_OMSO_B_CAST_OFF (1 << 9)
#define KSZPHY_OMSO_RMII_OVERRIDE (1 << 1)
#define KSZPHY_OMSO_MII_OVERRIDE (1 << 0)
#define KSZPHY_OMSO_B_CAST_OFF BIT(9)
#define KSZPHY_OMSO_RMII_OVERRIDE BIT(1)
#define KSZPHY_OMSO_MII_OVERRIDE BIT(0)
/* general PHY control reg in vendor specific block. */
#define MII_KSZPHY_CTRL 0x1F
/* bitmap of PHY register to set interrupt mode */
#define KSZPHY_CTRL_INT_ACTIVE_HIGH (1 << 9)
#define KSZ9021_CTRL_INT_ACTIVE_HIGH (1 << 14)
#define KS8737_CTRL_INT_ACTIVE_HIGH (1 << 14)
#define KSZ8051_RMII_50MHZ_CLK (1 << 7)
#define KSZPHY_CTRL_INT_ACTIVE_HIGH BIT(9)
#define KSZ9021_CTRL_INT_ACTIVE_HIGH BIT(14)
#define KS8737_CTRL_INT_ACTIVE_HIGH BIT(14)
#define KSZ8051_RMII_50MHZ_CLK BIT(7)
/* Write/read to/from extended registers */
#define MII_KSZPHY_EXTREG 0x0b
@ -91,8 +91,8 @@ static int ks8051_config_init(struct phy_device *phydev)
}
static int ksz9021_load_values_from_of(struct phy_device *phydev,
struct device_node *of_node, u16 reg,
const char *field[])
const struct device_node *of_node,
u16 reg, const char *field[])
{
int val, regval, i;
@ -113,8 +113,8 @@ static int ksz9021_load_values_from_of(struct phy_device *phydev,
static int ksz9021_config_init(struct phy_device *phydev)
{
struct device_d *dev = &phydev->dev;
struct device_node *of_node = dev->device_node;
const struct device_d *dev = &phydev->dev;
const struct device_node *of_node = dev->device_node;
const char *clk_pad_skew_names[] = {
"txen-skew-ps", "txc-skew-ps",
"rxdv-skew-ps", "rxc-skew-ps"
@ -149,15 +149,20 @@ static int ksz9021_config_init(struct phy_device *phydev)
#define KSZ9031_PS_TO_REG 60
/* Extended registers */
/* MMD Address 0x0 */
#define MII_KSZ9031RN_FLP_BURST_TX_LO 3
#define MII_KSZ9031RN_FLP_BURST_TX_HI 4
/* MMD Address 0x2 */
#define MII_KSZ9031RN_CONTROL_PAD_SKEW 4
#define MII_KSZ9031RN_RX_DATA_PAD_SKEW 5
#define MII_KSZ9031RN_TX_DATA_PAD_SKEW 6
#define MII_KSZ9031RN_CLK_PAD_SKEW 8
static int ksz9031_of_load_skew_values(struct phy_device *phydev,
struct device_node *of_node,
const struct device_node *of_node,
u16 reg, size_t field_sz,
char *field[], u8 numfields)
const char *field[], u8 numfields)
{
int val[4] = {-1, -2, -3, -4};
int matches = 0;
@ -192,20 +197,29 @@ static int ksz9031_of_load_skew_values(struct phy_device *phydev,
return 0;
}
static int ksz9031_center_flp_timing(struct phy_device *phydev)
{
/* Center KSZ9031RNX FLP timing at 16ms. */
phy_write_mmd_indirect(phydev, MII_KSZ9031RN_FLP_BURST_TX_HI, 0, 0x0006);
phy_write_mmd_indirect(phydev, MII_KSZ9031RN_FLP_BURST_TX_LO, 0, 0x1a80);
return genphy_restart_aneg(phydev);
}
static int ksz9031_config_init(struct phy_device *phydev)
{
struct device_d *dev = &phydev->dev;
struct device_node *of_node = dev->device_node;
char *clk_skews[2] = {"rxc-skew-ps", "txc-skew-ps"};
char *rx_data_skews[4] = {
const struct device_d *dev = &phydev->dev;
const struct device_node *of_node = dev->device_node;
static const char *clk_skews[2] = {"rxc-skew-ps", "txc-skew-ps"};
static const char *rx_data_skews[4] = {
"rxd0-skew-ps", "rxd1-skew-ps",
"rxd2-skew-ps", "rxd3-skew-ps"
};
char *tx_data_skews[4] = {
static const char *tx_data_skews[4] = {
"txd0-skew-ps", "txd1-skew-ps",
"txd2-skew-ps", "txd3-skew-ps"
};
char *control_skews[2] = {"txen-skew-ps", "rxdv-skew-ps"};
static const char *control_skews[2] = {"txen-skew-ps", "rxdv-skew-ps"};
if (!of_node && dev->parent->device_node)
of_node = dev->parent->device_node;
@ -227,13 +241,14 @@ static int ksz9031_config_init(struct phy_device *phydev)
MII_KSZ9031RN_TX_DATA_PAD_SKEW, 4,
tx_data_skews, 4);
}
return 0;
return ksz9031_center_flp_timing(phydev);
}
#define KSZ8873MLL_GLOBAL_CONTROL_4 0x06
#define KSZ8873MLL_GLOBAL_CONTROL_4_DUPLEX (1 << 6)
#define KSZ8873MLL_GLOBAL_CONTROL_4_SPEED (1 << 4)
int ksz8873mll_read_status(struct phy_device *phydev)
#define KSZ8873MLL_GLOBAL_CONTROL_4_DUPLEX BIT(6)
#define KSZ8873MLL_GLOBAL_CONTROL_4_SPEED BIT(4)
static int ksz8873mll_read_status(struct phy_device *phydev)
{
int regval;
@ -258,6 +273,27 @@ int ksz8873mll_read_status(struct phy_device *phydev)
return 0;
}
static int ksz9031_read_status(struct phy_device *phydev)
{
int err;
int regval;
err = genphy_read_status(phydev);
if (err)
return err;
/* Make sure the PHY is not broken. Read idle error count,
* and reset the PHY if it is maxed out.
*/
regval = phy_read(phydev, MII_STAT1000);
if ((regval & 0xff) == 0xff) {
phy_init_hw(phydev);
phydev->link = 0;
}
return 0;
}
static int ksz8873mll_config_aneg(struct phy_device *phydev)
{
return 0;
@ -353,7 +389,7 @@ static struct phy_driver ksphy_driver[] = {
.features = (PHY_GBIT_FEATURES | SUPPORTED_Pause),
.config_init = ksz9031_config_init,
.config_aneg = genphy_config_aneg,
.read_status = genphy_read_status,
.read_status = ksz9031_read_status,
}, {
.phy_id = PHY_ID_KSZ8873MLL,
.phy_id_mask = 0x00fffff0,

View File

@ -147,8 +147,13 @@ int phy_scan_fixups(struct phy_device *phydev)
return 0;
}
static struct phy_device *phy_device_create(struct mii_bus *bus, int addr, int phy_id)
/**
* phy_device_create - creates a struct phy_device.
* @bus: the target MII bus
* @addr: PHY address on the MII bus
* @phy_id: PHY ID.
*/
struct phy_device *phy_device_create(struct mii_bus *bus, int addr, int phy_id)
{
struct phy_device *phydev;
@ -168,8 +173,10 @@ static struct phy_device *phy_device_create(struct mii_bus *bus, int addr, int p
phydev->bus = bus;
phydev->dev.bus = &mdio_bus_type;
strcpy(phydev->dev.name, "phy");
phydev->dev.id = DEVICE_ID_DYNAMIC;
sprintf(phydev->dev.name, "mdio%d-phy%02x",
phydev->bus->dev.id,
phydev->addr);
phydev->dev.id = DEVICE_ID_SINGLE;
return phydev;
}

View File

@ -133,7 +133,9 @@ struct nfs_priv {
IPaddr_t server;
char *path;
uint16_t mount_port;
unsigned manual_mount_port:1;
uint16_t nfs_port;
unsigned manual_nfs_port:1;
uint32_t rpc_id;
uint32_t rootfh_len;
char rootfh[NFS3_FHSIZE];
@ -1311,7 +1313,7 @@ static char *rootnfsopts;
static void nfs_set_rootarg(struct nfs_priv *npriv, struct fs_device_d *fsdev)
{
char *str;
char *str, *tmp;
const char *ip;
ip = ip_to_string(npriv->server);
@ -1319,6 +1321,19 @@ static void nfs_set_rootarg(struct nfs_priv *npriv, struct fs_device_d *fsdev)
ip, npriv->path, rootnfsopts[0] ? "," : "",
rootnfsopts);
/* forward specific mount options on demand */
if (npriv->manual_nfs_port == 1) {
tmp = asprintf("%s,port=%hu", str, npriv->nfs_port);
free(str);
str = tmp;
}
if (npriv->manual_mount_port == 1) {
tmp = asprintf("%s,mountport=%hu", str, npriv->mount_port);
free(str);
str = tmp;
}
fsdev_set_linux_rootarg(fsdev, str);
free(str);
@ -1367,6 +1382,8 @@ static int nfs_probe(struct device_d *dev)
goto err2;
}
npriv->mount_port = ret;
} else {
npriv->manual_mount_port = 1;
}
debug("mount port: %hu\n", npriv->mount_port);
@ -1378,6 +1395,8 @@ static int nfs_probe(struct device_d *dev)
goto err2;
}
npriv->nfs_port = ret;
} else {
npriv->manual_nfs_port = 1;
}
debug("nfs port: %d\n", npriv->nfs_port);

View File

@ -0,0 +1,45 @@
#ifndef __LINUX_MDIO_BITBANG_H
#define __LINUX_MDIO_BITBANG_H
#include <linux/phy.h>
struct module;
struct mdiobb_ctrl;
struct mdiobb_ops {
struct module *owner;
/* Set the Management Data Clock high if level is one,
* low if level is zero.
*/
void (*set_mdc)(struct mdiobb_ctrl *ctrl, int level);
/* Configure the Management Data I/O pin as an input if
* "output" is zero, or an output if "output" is one.
*/
void (*set_mdio_dir)(struct mdiobb_ctrl *ctrl, int output);
/* Set the Management Data I/O pin high if value is one,
* low if "value" is zero. This may only be called
* when the MDIO pin is configured as an output.
*/
void (*set_mdio_data)(struct mdiobb_ctrl *ctrl, int value);
/* Retrieve the state Management Data I/O pin. */
int (*get_mdio_data)(struct mdiobb_ctrl *ctrl);
};
struct mdiobb_ctrl {
const struct mdiobb_ops *ops;
/* reset callback */
int (*reset)(struct mii_bus *bus);
};
/* The returned bus is not yet registered with the phy layer. */
struct mii_bus *alloc_mdio_bitbang(struct mdiobb_ctrl *ctrl);
/* The bus must already have been unregistered. */
void free_mdio_bitbang(struct mii_bus *bus);
#endif

View File

@ -69,6 +69,10 @@ typedef enum {
*/
#define MII_BUS_ID_SIZE (20 - 3)
/* Or MII_ADDR_C45 into regnum for read/write on mii_bus to enable the 21 bit
IEEE 802.3ae clause 45 addressing mode used by 10GIGE phy chips. */
#define MII_ADDR_C45 (1<<30)
#define PHYLIB_FORCE_10 (1 << 0)
#define PHYLIB_FORCE_100 (1 << 1)
#define PHYLIB_FORCE_LINK (1 << 2)
@ -110,6 +114,8 @@ int mdiobus_detect(struct device_d *dev);
#define for_each_mii_bus(mii) \
list_for_each_entry(mii, &mii_bus_list, list)
struct mii_bus *mdiobus_get_bus(int busnum);
/**
* mdiobus_read - Convenience function for reading a given MII mgmt register
* @bus: the mii_bus struct
@ -265,6 +271,7 @@ struct phy_device *get_phy_device(struct mii_bus *bus, int addr);
int phy_init(void);
int phy_init_hw(struct phy_device *phydev);
struct phy_device *phy_device_create(struct mii_bus *bus, int addr, int phy_id);
int phy_register_device(struct phy_device* dev);
void phy_unregister_device(struct phy_device *phydev);