Merge branch 'for-next/net-of-phy'
This commit is contained in:
commit
73339649ae
|
@ -621,6 +621,7 @@ static int fec_alloc_receive_packets(struct fec_priv *fec, int count, int size)
|
||||||
#ifdef CONFIG_OFDEVICE
|
#ifdef CONFIG_OFDEVICE
|
||||||
static int fec_probe_dt(struct device_d *dev, struct fec_priv *fec)
|
static int fec_probe_dt(struct device_d *dev, struct fec_priv *fec)
|
||||||
{
|
{
|
||||||
|
struct device_node *mdiobus;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = of_get_phy_mode(dev->device_node);
|
ret = of_get_phy_mode(dev->device_node);
|
||||||
|
@ -629,6 +630,10 @@ static int fec_probe_dt(struct device_d *dev, struct fec_priv *fec)
|
||||||
else
|
else
|
||||||
fec->interface = ret;
|
fec->interface = ret;
|
||||||
|
|
||||||
|
mdiobus = of_get_child_by_name(dev->device_node, "mdio");
|
||||||
|
if (mdiobus)
|
||||||
|
fec->miibus.dev.device_node = mdiobus;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
|
|
@ -56,6 +56,7 @@ struct txdesc {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct port_priv {
|
struct port_priv {
|
||||||
|
struct device_d dev;
|
||||||
struct eth_device edev;
|
struct eth_device edev;
|
||||||
void __iomem *regs;
|
void __iomem *regs;
|
||||||
struct device_node *np;
|
struct device_node *np;
|
||||||
|
@ -64,6 +65,7 @@ struct port_priv {
|
||||||
struct rxdesc *rxdesc;
|
struct rxdesc *rxdesc;
|
||||||
struct rxdesc *current_rxdesc;
|
struct rxdesc *current_rxdesc;
|
||||||
u8 *rxbuf;
|
u8 *rxbuf;
|
||||||
|
phy_interface_t intf;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct orion_gbe {
|
struct orion_gbe {
|
||||||
|
@ -351,16 +353,6 @@ static int port_get_ethaddr(struct eth_device *edev, unsigned char *mac)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int port_open(struct eth_device *edev)
|
|
||||||
{
|
|
||||||
struct port_priv *port = edev->priv;
|
|
||||||
|
|
||||||
/* enable receive queue */
|
|
||||||
writel(BIT(URXQ), port->regs + PORT_RQC);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void port_adjust_link(struct eth_device *edev)
|
static void port_adjust_link(struct eth_device *edev)
|
||||||
{
|
{
|
||||||
struct port_priv *port = edev->priv;
|
struct port_priv *port = edev->priv;
|
||||||
|
@ -389,10 +381,25 @@ static void port_adjust_link(struct eth_device *edev)
|
||||||
writel(reg, port->regs + PORT_SC0);
|
writel(reg, port->regs + PORT_SC0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int port_open(struct eth_device *edev)
|
||||||
|
{
|
||||||
|
struct port_priv *port = edev->priv;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = phy_device_connect(&port->edev, NULL, -1, port_adjust_link, 0,
|
||||||
|
port->intf);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/* enable receive queue */
|
||||||
|
writel(BIT(URXQ), port->regs + PORT_RQC);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int port_probe(struct device_d *parent, struct port_priv *port)
|
static int port_probe(struct device_d *parent, struct port_priv *port)
|
||||||
{
|
{
|
||||||
struct device_node *phynp;
|
struct device_d *dev = &port->dev;
|
||||||
phy_interface_t intf = PHY_INTERFACE_MODE_RGMII;
|
|
||||||
u32 reg;
|
u32 reg;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
@ -400,12 +407,11 @@ static int port_probe(struct device_d *parent, struct port_priv *port)
|
||||||
if (of_property_read_u32(port->np, "reg", &port->portno))
|
if (of_property_read_u32(port->np, "reg", &port->portno))
|
||||||
dev_warn(parent, "port node is missing reg property\n");
|
dev_warn(parent, "port node is missing reg property\n");
|
||||||
|
|
||||||
phynp = of_parse_phandle(port->np, "phy-handle", 0);
|
ret = of_get_phy_mode(port->np);
|
||||||
if (phynp) {
|
if (ret > 0)
|
||||||
ret = of_get_phy_mode(port->np);
|
port->intf = ret;
|
||||||
if (ret > 0)
|
else
|
||||||
intf = ret;
|
port->intf = PHY_INTERFACE_MODE_RGMII;
|
||||||
}
|
|
||||||
|
|
||||||
port->regs = dev_get_mem_region(parent, 0) + PORTn_REGS(port->portno);
|
port->regs = dev_get_mem_region(parent, 0) + PORTn_REGS(port->portno);
|
||||||
|
|
||||||
|
@ -440,10 +446,18 @@ static int port_probe(struct device_d *parent, struct port_priv *port)
|
||||||
|
|
||||||
reg = SC1_RESERVED;
|
reg = SC1_RESERVED;
|
||||||
reg |= DEFAULT_COL_LIMIT | COL_ON_BACKPRESS | INBAND_ANEG_BYPASS;
|
reg |= DEFAULT_COL_LIMIT | COL_ON_BACKPRESS | INBAND_ANEG_BYPASS;
|
||||||
if (intf == PHY_INTERFACE_MODE_RGMII)
|
if (port->intf == PHY_INTERFACE_MODE_RGMII)
|
||||||
reg |= RGMII_ENABLE;
|
reg |= RGMII_ENABLE;
|
||||||
writel(reg, port->regs + PORT_SC1);
|
writel(reg, port->regs + PORT_SC1);
|
||||||
|
|
||||||
|
sprintf(dev->name, "orion-gbe-port");
|
||||||
|
dev->id = port->portno;
|
||||||
|
dev->parent = parent;
|
||||||
|
dev->device_node = port->np;
|
||||||
|
ret = register_device(dev);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
/* register eth device */
|
/* register eth device */
|
||||||
port->edev.priv = port;
|
port->edev.priv = port;
|
||||||
port->edev.open = port_open;
|
port->edev.open = port_open;
|
||||||
|
@ -452,20 +466,12 @@ static int port_probe(struct device_d *parent, struct port_priv *port)
|
||||||
port->edev.halt = port_halt;
|
port->edev.halt = port_halt;
|
||||||
port->edev.set_ethaddr = port_set_ethaddr;
|
port->edev.set_ethaddr = port_set_ethaddr;
|
||||||
port->edev.get_ethaddr = port_get_ethaddr;
|
port->edev.get_ethaddr = port_get_ethaddr;
|
||||||
port->edev.parent = parent;
|
port->edev.parent = dev;
|
||||||
|
|
||||||
ret = eth_register(&port->edev);
|
ret = eth_register(&port->edev);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
/* attach phy device */
|
|
||||||
if (phynp) {
|
|
||||||
ret = of_phy_device_connect(&port->edev, phynp,
|
|
||||||
port_adjust_link, 0, intf);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -120,6 +120,7 @@ static int mvebu_mdio_probe(struct device_d *dev)
|
||||||
if (!IS_ERR(priv->clk))
|
if (!IS_ERR(priv->clk))
|
||||||
clk_enable(priv->clk);
|
clk_enable(priv->clk);
|
||||||
|
|
||||||
|
priv->miibus.dev.device_node = dev->device_node;
|
||||||
priv->miibus.priv = priv;
|
priv->miibus.priv = priv;
|
||||||
priv->miibus.parent = dev;
|
priv->miibus.parent = dev;
|
||||||
priv->miibus.read = mvebu_mdio_read;
|
priv->miibus.read = mvebu_mdio_read;
|
||||||
|
|
|
@ -49,6 +49,71 @@ int mdiobus_detect(struct device_d *dev)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int of_mdiobus_register_phy(struct mii_bus *mdio, struct device_node *child,
|
||||||
|
u32 addr)
|
||||||
|
{
|
||||||
|
struct phy_device *phy;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
phy = get_phy_device(mdio, addr);
|
||||||
|
if (IS_ERR(phy))
|
||||||
|
return PTR_ERR(phy);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Associate the OF node with the device structure so it
|
||||||
|
* can be looked up later
|
||||||
|
*/
|
||||||
|
phy->dev.device_node = child;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* All data is now stored in the phy struct;
|
||||||
|
* register it
|
||||||
|
*/
|
||||||
|
ret = phy_register_device(phy);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
dev_dbg(&mdio->dev, "registered phy %s at address %i\n",
|
||||||
|
child->name, addr);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* of_mdiobus_register - Register mii_bus and create PHYs from the device tree
|
||||||
|
* @mdio: pointer to mii_bus structure
|
||||||
|
* @np: pointer to device_node of MDIO bus.
|
||||||
|
*
|
||||||
|
* This function registers the mii_bus structure and registers a phy_device
|
||||||
|
* for each child node of @np.
|
||||||
|
*/
|
||||||
|
static int of_mdiobus_register(struct mii_bus *mdio, struct device_node *np)
|
||||||
|
{
|
||||||
|
struct device_node *child;
|
||||||
|
u32 addr;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/* Loop over the child nodes and register a phy_device for each one */
|
||||||
|
for_each_available_child_of_node(np, child) {
|
||||||
|
ret = of_property_read_u32(child, "reg", &addr);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(&mdio->dev, "%s has invalid PHY address\n",
|
||||||
|
child->full_name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (addr >= PHY_MAX_ADDR) {
|
||||||
|
dev_err(&mdio->dev, "%s PHY address %i is too large\n",
|
||||||
|
child->full_name, addr);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
of_mdiobus_register_phy(mdio, child, addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* mdiobus_register - bring up all the PHYs on a given bus and attach them to bus
|
* mdiobus_register - bring up all the PHYs on a given bus and attach them to bus
|
||||||
* @bus: target mii_bus
|
* @bus: target mii_bus
|
||||||
|
@ -85,6 +150,10 @@ int mdiobus_register(struct mii_bus *bus)
|
||||||
list_add_tail(&bus->list, &mii_bus_list);
|
list_add_tail(&bus->list, &mii_bus_list);
|
||||||
|
|
||||||
pr_info("%s: probed\n", dev_name(&bus->dev));
|
pr_info("%s: probed\n", dev_name(&bus->dev));
|
||||||
|
|
||||||
|
if (bus->dev.device_node)
|
||||||
|
of_mdiobus_register(bus, bus->dev.device_node);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(mdiobus_register);
|
EXPORT_SYMBOL(mdiobus_register);
|
||||||
|
@ -114,8 +183,6 @@ struct phy_device *mdiobus_scan(struct mii_bus *bus, int addr)
|
||||||
if (IS_ERR(phydev))
|
if (IS_ERR(phydev))
|
||||||
return phydev;
|
return phydev;
|
||||||
|
|
||||||
bus->phy_map[addr] = phydev;
|
|
||||||
|
|
||||||
return phydev;
|
return phydev;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(mdiobus_scan);
|
EXPORT_SYMBOL(mdiobus_scan);
|
||||||
|
@ -175,6 +242,39 @@ static struct file_operations phydev_ops = {
|
||||||
.lseek = dev_lseek_default,
|
.lseek = dev_lseek_default,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void of_set_phy_supported(struct phy_device *phydev)
|
||||||
|
{
|
||||||
|
struct device_node *node = phydev->dev.device_node;
|
||||||
|
u32 max_speed;
|
||||||
|
|
||||||
|
if (!IS_ENABLED(CONFIG_OFDEVICE))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!node)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!of_property_read_u32(node, "max-speed", &max_speed)) {
|
||||||
|
/*
|
||||||
|
* The default values for phydev->supported are provided by the PHY
|
||||||
|
* driver "features" member, we want to reset to sane defaults first
|
||||||
|
* before supporting higher speeds.
|
||||||
|
*/
|
||||||
|
phydev->supported &= PHY_DEFAULT_FEATURES;
|
||||||
|
|
||||||
|
switch (max_speed) {
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
|
||||||
|
case SPEED_1000:
|
||||||
|
phydev->supported |= PHY_1000BT_FEATURES;
|
||||||
|
case SPEED_100:
|
||||||
|
phydev->supported |= PHY_100BT_FEATURES;
|
||||||
|
case SPEED_10:
|
||||||
|
phydev->supported |= PHY_10BT_FEATURES;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int mdio_bus_probe(struct device_d *_dev)
|
static int mdio_bus_probe(struct device_d *_dev)
|
||||||
{
|
{
|
||||||
struct phy_device *dev = to_phy_device(_dev);
|
struct phy_device *dev = to_phy_device(_dev);
|
||||||
|
@ -208,7 +308,8 @@ static int mdio_bus_probe(struct device_d *_dev)
|
||||||
* a controller will attach, and may modify one
|
* a controller will attach, and may modify one
|
||||||
* or both of these values */
|
* or both of these values */
|
||||||
dev->supported = drv->features;
|
dev->supported = drv->features;
|
||||||
dev->advertising = drv->features;
|
of_set_phy_supported(dev);
|
||||||
|
dev->advertising = dev->supported;
|
||||||
|
|
||||||
dev_add_param_int_ro(&dev->dev, "phy_addr", dev->addr, "%d");
|
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_add_param_int_ro(&dev->dev, "phy_id", dev->phy_id, "0x%08x");
|
||||||
|
|
|
@ -37,6 +37,34 @@
|
||||||
#define KS8737_CTRL_INT_ACTIVE_HIGH (1 << 14)
|
#define KS8737_CTRL_INT_ACTIVE_HIGH (1 << 14)
|
||||||
#define KSZ8051_RMII_50MHZ_CLK (1 << 7)
|
#define KSZ8051_RMII_50MHZ_CLK (1 << 7)
|
||||||
|
|
||||||
|
/* Write/read to/from extended registers */
|
||||||
|
#define MII_KSZPHY_EXTREG 0x0b
|
||||||
|
#define KSZPHY_EXTREG_WRITE 0x8000
|
||||||
|
|
||||||
|
#define MII_KSZPHY_EXTREG_WRITE 0x0c
|
||||||
|
#define MII_KSZPHY_EXTREG_READ 0x0d
|
||||||
|
|
||||||
|
/* Extended registers */
|
||||||
|
#define MII_KSZPHY_CLK_CONTROL_PAD_SKEW 0x104
|
||||||
|
#define MII_KSZPHY_RX_DATA_PAD_SKEW 0x105
|
||||||
|
#define MII_KSZPHY_TX_DATA_PAD_SKEW 0x106
|
||||||
|
|
||||||
|
#define PS_TO_REG 200
|
||||||
|
|
||||||
|
static int kszphy_extended_write(struct phy_device *phydev,
|
||||||
|
u32 regnum, u16 val)
|
||||||
|
{
|
||||||
|
phy_write(phydev, MII_KSZPHY_EXTREG, KSZPHY_EXTREG_WRITE | regnum);
|
||||||
|
return phy_write(phydev, MII_KSZPHY_EXTREG_WRITE, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int kszphy_extended_read(struct phy_device *phydev,
|
||||||
|
u32 regnum)
|
||||||
|
{
|
||||||
|
phy_write(phydev, MII_KSZPHY_EXTREG, regnum);
|
||||||
|
return phy_read(phydev, MII_KSZPHY_EXTREG_READ);
|
||||||
|
}
|
||||||
|
|
||||||
static int kszphy_config_init(struct phy_device *phydev)
|
static int kszphy_config_init(struct phy_device *phydev)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -62,6 +90,62 @@ static int ks8051_config_init(struct phy_device *phydev)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int ksz9021_load_values_from_of(struct phy_device *phydev,
|
||||||
|
struct device_node *of_node, u16 reg,
|
||||||
|
const char *field[])
|
||||||
|
{
|
||||||
|
int val, regval, i;
|
||||||
|
|
||||||
|
regval = kszphy_extended_read(phydev, reg);
|
||||||
|
|
||||||
|
for (i = 0; i < 4; i++) {
|
||||||
|
int shift = i * 4;
|
||||||
|
|
||||||
|
if (of_property_read_u32(of_node, field[i], &val))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
regval &= ~(0xf << shift);
|
||||||
|
regval |= ((val / PS_TO_REG) & 0xf) << shift;
|
||||||
|
}
|
||||||
|
|
||||||
|
return kszphy_extended_write(phydev, reg, regval);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ksz9021_config_init(struct phy_device *phydev)
|
||||||
|
{
|
||||||
|
struct device_d *dev = &phydev->dev;
|
||||||
|
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"
|
||||||
|
};
|
||||||
|
const char *rx_pad_skew_names[] = {
|
||||||
|
"rxd0-skew-ps", "rxd1-skew-ps",
|
||||||
|
"rxd2-skew-ps", "rxd3-skew-ps"
|
||||||
|
};
|
||||||
|
const char *tx_pad_skew_names[] = {
|
||||||
|
"txd0-skew-ps", "txd1-skew-ps",
|
||||||
|
"txd2-skew-ps", "txd3-skew-ps"
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!of_node && dev->parent->device_node)
|
||||||
|
of_node = dev->parent->device_node;
|
||||||
|
|
||||||
|
if (of_node) {
|
||||||
|
ksz9021_load_values_from_of(phydev, of_node,
|
||||||
|
MII_KSZPHY_CLK_CONTROL_PAD_SKEW,
|
||||||
|
clk_pad_skew_names);
|
||||||
|
ksz9021_load_values_from_of(phydev, of_node,
|
||||||
|
MII_KSZPHY_RX_DATA_PAD_SKEW,
|
||||||
|
rx_pad_skew_names);
|
||||||
|
ksz9021_load_values_from_of(phydev, of_node,
|
||||||
|
MII_KSZPHY_TX_DATA_PAD_SKEW,
|
||||||
|
tx_pad_skew_names);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
#define KSZ8873MLL_GLOBAL_CONTROL_4 0x06
|
#define KSZ8873MLL_GLOBAL_CONTROL_4 0x06
|
||||||
#define KSZ8873MLL_GLOBAL_CONTROL_4_DUPLEX (1 << 6)
|
#define KSZ8873MLL_GLOBAL_CONTROL_4_DUPLEX (1 << 6)
|
||||||
#define KSZ8873MLL_GLOBAL_CONTROL_4_SPEED (1 << 4)
|
#define KSZ8873MLL_GLOBAL_CONTROL_4_SPEED (1 << 4)
|
||||||
|
@ -166,6 +250,15 @@ static struct phy_driver ksphy_driver[] = {
|
||||||
.phy_id_mask = 0x000ffffe,
|
.phy_id_mask = 0x000ffffe,
|
||||||
.drv.name = "Micrel KSZ9021 Gigabit PHY",
|
.drv.name = "Micrel KSZ9021 Gigabit PHY",
|
||||||
.features = (PHY_GBIT_FEATURES | SUPPORTED_Pause),
|
.features = (PHY_GBIT_FEATURES | SUPPORTED_Pause),
|
||||||
|
.config_init = ksz9021_config_init,
|
||||||
|
.config_aneg = genphy_config_aneg,
|
||||||
|
.read_status = genphy_read_status,
|
||||||
|
}, {
|
||||||
|
.phy_id = PHY_ID_KSZ9031,
|
||||||
|
.phy_id_mask = 0x00fffff0,
|
||||||
|
.drv.name = "Micrel KSZ9031 Gigabit PHY",
|
||||||
|
.features = (PHY_GBIT_FEATURES | SUPPORTED_Pause
|
||||||
|
| SUPPORTED_Asym_Pause),
|
||||||
.config_init = kszphy_config_init,
|
.config_init = kszphy_config_init,
|
||||||
.config_aneg = genphy_config_aneg,
|
.config_aneg = genphy_config_aneg,
|
||||||
.read_status = genphy_read_status,
|
.read_status = genphy_read_status,
|
||||||
|
|
|
@ -245,6 +245,8 @@ int phy_register_device(struct phy_device* dev)
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
dev->bus->phy_map[dev->addr] = dev;
|
||||||
|
|
||||||
dev->registered = 1;
|
dev->registered = 1;
|
||||||
|
|
||||||
if (dev->dev.driver)
|
if (dev->dev.driver)
|
||||||
|
@ -260,12 +262,71 @@ int phy_register_device(struct phy_device* dev)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct phy_device *of_mdio_find_phy(struct eth_device *edev)
|
||||||
|
{
|
||||||
|
struct device_d *dev;
|
||||||
|
struct device_node *phy_node;
|
||||||
|
|
||||||
|
if (!IS_ENABLED(CONFIG_OFDEVICE))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (!edev->parent->device_node)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
phy_node = of_parse_phandle(edev->parent->device_node, "phy-handle", 0);
|
||||||
|
if (!phy_node)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
bus_for_each_device(&mdio_bus_type, dev) {
|
||||||
|
if (dev->device_node == phy_node)
|
||||||
|
return container_of(dev, struct phy_device, dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int phy_device_attach(struct phy_device *phy, struct eth_device *edev,
|
||||||
|
void (*adjust_link) (struct eth_device *edev),
|
||||||
|
u32 flags, phy_interface_t interface)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (phy->attached_dev)
|
||||||
|
return -EBUSY;
|
||||||
|
|
||||||
|
phy->interface = interface;
|
||||||
|
phy->dev_flags = flags;
|
||||||
|
|
||||||
|
if (!phy->registered) {
|
||||||
|
ret = phy_register_device(phy);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
edev->phydev = phy;
|
||||||
|
phy->attached_dev = edev;
|
||||||
|
|
||||||
|
ret = phy_init_hw(phy);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/* Sanitize settings based on PHY capabilities */
|
||||||
|
if ((phy->supported & SUPPORTED_Autoneg) == 0)
|
||||||
|
phy->autoneg = AUTONEG_DISABLE;
|
||||||
|
|
||||||
|
phy_config_aneg(edev->phydev);
|
||||||
|
|
||||||
|
phy->adjust_link = adjust_link;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Automatically gets and returns the PHY device */
|
/* Automatically gets and returns the PHY device */
|
||||||
int phy_device_connect(struct eth_device *edev, struct mii_bus *bus, int addr,
|
int phy_device_connect(struct eth_device *edev, struct mii_bus *bus, int addr,
|
||||||
void (*adjust_link) (struct eth_device *edev),
|
void (*adjust_link) (struct eth_device *edev),
|
||||||
u32 flags, phy_interface_t interface)
|
u32 flags, phy_interface_t interface)
|
||||||
{
|
{
|
||||||
struct phy_device* dev = NULL;
|
struct phy_device *phy;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
int ret = -EINVAL;
|
int ret = -EINVAL;
|
||||||
|
|
||||||
|
@ -274,94 +335,47 @@ int phy_device_connect(struct eth_device *edev, struct mii_bus *bus, int addr,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
phy = of_mdio_find_phy(edev);
|
||||||
|
if (phy) {
|
||||||
|
ret = phy_device_attach(phy, edev, adjust_link, flags, interface);
|
||||||
|
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
if (addr >= 0) {
|
if (addr >= 0) {
|
||||||
dev = mdiobus_scan(bus, addr);
|
phy = mdiobus_scan(bus, addr);
|
||||||
if (IS_ERR(dev)) {
|
if (IS_ERR(phy)) {
|
||||||
ret = -EIO;
|
ret = -EIO;
|
||||||
goto fail;
|
goto out;
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for (i = 0; i < PHY_MAX_ADDR && !edev->phydev; i++) {
|
|
||||||
/* skip masked out PHY addresses */
|
|
||||||
if (bus->phy_mask & (1 << i))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
dev = mdiobus_scan(bus, i);
|
|
||||||
if (!IS_ERR(dev) && !dev->attached_dev)
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IS_ERR(dev)) {
|
ret = phy_device_attach(phy, edev, adjust_link, flags, interface);
|
||||||
ret = PTR_ERR(dev);
|
|
||||||
goto fail;
|
goto out;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dev->attached_dev)
|
for (i = 0; i < PHY_MAX_ADDR && !edev->phydev; i++) {
|
||||||
return -EBUSY;
|
/* skip masked out PHY addresses */
|
||||||
|
if (bus->phy_mask & (1 << i))
|
||||||
|
continue;
|
||||||
|
|
||||||
dev->interface = interface;
|
phy = mdiobus_scan(bus, i);
|
||||||
dev->dev_flags = flags;
|
if (IS_ERR(phy))
|
||||||
|
continue;
|
||||||
|
|
||||||
if (!dev->registered) {
|
ret = phy_device_attach(phy, edev, adjust_link, flags, interface);
|
||||||
ret = phy_register_device(dev);
|
|
||||||
if (ret)
|
goto out;
|
||||||
goto fail;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
edev->phydev = dev;
|
ret = -ENODEV;
|
||||||
dev->attached_dev = edev;
|
out:
|
||||||
|
|
||||||
ret = phy_init_hw(dev);
|
|
||||||
if (ret)
|
if (ret)
|
||||||
goto fail;
|
puts("Unable to find a PHY (unknown ID?)\n");
|
||||||
|
|
||||||
/* Sanitize settings based on PHY capabilities */
|
|
||||||
if ((dev->supported & SUPPORTED_Autoneg) == 0)
|
|
||||||
dev->autoneg = AUTONEG_DISABLE;
|
|
||||||
|
|
||||||
phy_config_aneg(edev->phydev);
|
|
||||||
|
|
||||||
dev->adjust_link = adjust_link;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
fail:
|
|
||||||
puts("Unable to find a PHY (unknown ID?)\n");
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(CONFIG_OFTREE)
|
|
||||||
int of_phy_device_connect(struct eth_device *edev, struct device_node *phy_np,
|
|
||||||
void (*adjust_link) (struct eth_device *edev),
|
|
||||||
u32 flags, phy_interface_t interface)
|
|
||||||
{
|
|
||||||
struct device_node *bus_np;
|
|
||||||
struct mii_bus *miibus;
|
|
||||||
int phy_addr = -ENODEV;
|
|
||||||
|
|
||||||
if (!phy_np)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
of_property_read_u32(phy_np, "reg", &phy_addr);
|
|
||||||
|
|
||||||
bus_np = of_get_parent(phy_np);
|
|
||||||
if (!bus_np)
|
|
||||||
return -ENODEV;
|
|
||||||
|
|
||||||
for_each_mii_bus(miibus) {
|
|
||||||
if (miibus->parent && miibus->parent->device_node == bus_np)
|
|
||||||
return phy_device_connect(edev, miibus, phy_addr,
|
|
||||||
adjust_link, flags, interface);
|
|
||||||
}
|
|
||||||
|
|
||||||
dev_err(&edev->dev, "unable to mdio bus for phy %s\n",
|
|
||||||
phy_np->full_name);
|
|
||||||
|
|
||||||
return -ENODEV;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Generic PHY support and helper functions */
|
/* Generic PHY support and helper functions */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -376,7 +390,7 @@ int of_phy_device_connect(struct eth_device *edev, struct device_node *phy_np,
|
||||||
int genphy_config_advert(struct phy_device *phydev)
|
int genphy_config_advert(struct phy_device *phydev)
|
||||||
{
|
{
|
||||||
u32 advertise;
|
u32 advertise;
|
||||||
int oldadv, adv;
|
int oldadv, adv, bmsr;
|
||||||
int err, changed = 0;
|
int err, changed = 0;
|
||||||
|
|
||||||
/* Only allow advertising what
|
/* Only allow advertising what
|
||||||
|
@ -403,8 +417,11 @@ int genphy_config_advert(struct phy_device *phydev)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Configure gigabit if it's supported */
|
/* Configure gigabit if it's supported */
|
||||||
if (phydev->supported & (SUPPORTED_1000baseT_Half |
|
bmsr = phy_read(phydev, MII_BMSR);
|
||||||
SUPPORTED_1000baseT_Full)) {
|
if (bmsr < 0)
|
||||||
|
return bmsr;
|
||||||
|
|
||||||
|
if (bmsr & BMSR_ESTATEN) {
|
||||||
oldadv = adv = phy_read(phydev, MII_CTRL1000);
|
oldadv = adv = phy_read(phydev, MII_CTRL1000);
|
||||||
|
|
||||||
if (adv < 0)
|
if (adv < 0)
|
||||||
|
@ -788,8 +805,8 @@ static int genphy_config_init(struct phy_device *phydev)
|
||||||
features |= SUPPORTED_1000baseT_Half;
|
features |= SUPPORTED_1000baseT_Half;
|
||||||
}
|
}
|
||||||
|
|
||||||
phydev->supported = features;
|
phydev->supported &= features;
|
||||||
phydev->advertising = features;
|
phydev->advertising &= features;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -841,7 +858,9 @@ static struct phy_driver genphy_driver = {
|
||||||
.drv.name = "Generic PHY",
|
.drv.name = "Generic PHY",
|
||||||
.phy_id = PHY_ANY_UID,
|
.phy_id = PHY_ANY_UID,
|
||||||
.phy_id_mask = PHY_ANY_UID,
|
.phy_id_mask = PHY_ANY_UID,
|
||||||
.features = 0,
|
.features = PHY_GBIT_FEATURES | SUPPORTED_MII |
|
||||||
|
SUPPORTED_AUI | SUPPORTED_FIBRE |
|
||||||
|
SUPPORTED_BNC,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int generic_phy_register(void)
|
static int generic_phy_register(void)
|
||||||
|
|
|
@ -20,18 +20,26 @@
|
||||||
#include <linux/ethtool.h>
|
#include <linux/ethtool.h>
|
||||||
#include <linux/mii.h>
|
#include <linux/mii.h>
|
||||||
|
|
||||||
#define PHY_BASIC_FEATURES (SUPPORTED_10baseT_Half | \
|
#define PHY_DEFAULT_FEATURES (SUPPORTED_Autoneg | \
|
||||||
SUPPORTED_10baseT_Full | \
|
|
||||||
SUPPORTED_100baseT_Half | \
|
|
||||||
SUPPORTED_100baseT_Full | \
|
|
||||||
SUPPORTED_Autoneg | \
|
|
||||||
SUPPORTED_TP | \
|
SUPPORTED_TP | \
|
||||||
SUPPORTED_MII)
|
SUPPORTED_MII)
|
||||||
|
|
||||||
#define PHY_GBIT_FEATURES (PHY_BASIC_FEATURES | \
|
#define PHY_10BT_FEATURES (SUPPORTED_10baseT_Half | \
|
||||||
SUPPORTED_1000baseT_Half | \
|
SUPPORTED_10baseT_Full)
|
||||||
|
|
||||||
|
#define PHY_100BT_FEATURES (SUPPORTED_100baseT_Half | \
|
||||||
|
SUPPORTED_100baseT_Full)
|
||||||
|
|
||||||
|
#define PHY_1000BT_FEATURES (SUPPORTED_1000baseT_Half | \
|
||||||
SUPPORTED_1000baseT_Full)
|
SUPPORTED_1000baseT_Full)
|
||||||
|
|
||||||
|
#define PHY_BASIC_FEATURES (PHY_10BT_FEATURES | \
|
||||||
|
PHY_100BT_FEATURES | \
|
||||||
|
PHY_DEFAULT_FEATURES)
|
||||||
|
|
||||||
|
#define PHY_GBIT_FEATURES (PHY_BASIC_FEATURES | \
|
||||||
|
PHY_1000BT_FEATURES)
|
||||||
|
|
||||||
/* Interface Mode definitions */
|
/* Interface Mode definitions */
|
||||||
typedef enum {
|
typedef enum {
|
||||||
PHY_INTERFACE_MODE_NA,
|
PHY_INTERFACE_MODE_NA,
|
||||||
|
@ -280,20 +288,6 @@ int phy_device_connect(struct eth_device *dev, struct mii_bus *bus, int addr,
|
||||||
void (*adjust_link) (struct eth_device *edev),
|
void (*adjust_link) (struct eth_device *edev),
|
||||||
u32 flags, phy_interface_t interface);
|
u32 flags, phy_interface_t interface);
|
||||||
|
|
||||||
#if defined(CONFIG_OFTREE)
|
|
||||||
int of_phy_device_connect(struct eth_device *edev, struct device_node *phy_np,
|
|
||||||
void (*adjust_link) (struct eth_device *edev),
|
|
||||||
u32 flags, phy_interface_t interface);
|
|
||||||
#else
|
|
||||||
static inline int of_phy_device_connect(struct eth_device *edev,
|
|
||||||
struct device_node *phy_np,
|
|
||||||
void (*adjust_link) (struct eth_device *edev),
|
|
||||||
u32 flags, phy_interface_t interface)
|
|
||||||
{
|
|
||||||
return -ENOSYS;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int phy_update_status(struct phy_device *phydev);
|
int phy_update_status(struct phy_device *phydev);
|
||||||
int phy_wait_aneg_done(struct phy_device *phydev);
|
int phy_wait_aneg_done(struct phy_device *phydev);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue