Merge branch 'for-next/phylib'
Conflicts: drivers/net/phy/phy.c
This commit is contained in:
commit
8f32824c6e
|
@ -33,7 +33,7 @@
|
|||
#include <spi/spi.h>
|
||||
|
||||
static struct at91_ether_platform_data ether_pdata = {
|
||||
.flags = AT91SAM_ETHER_RMII,
|
||||
.is_rmii = 1,
|
||||
.phy_addr = 0,
|
||||
};
|
||||
|
||||
|
|
|
@ -128,7 +128,7 @@ static void ek_add_device_nand(void)
|
|||
}
|
||||
|
||||
static struct at91_ether_platform_data macb_pdata = {
|
||||
.flags = AT91SAM_ETHER_RMII,
|
||||
.is_rmii = 1,
|
||||
.phy_addr = 0,
|
||||
};
|
||||
|
||||
|
|
|
@ -84,7 +84,7 @@ static void ek_add_device_nand(void)
|
|||
}
|
||||
|
||||
static struct at91_ether_platform_data macb_pdata = {
|
||||
.flags = AT91SAM_ETHER_RMII,
|
||||
.is_rmii = 1,
|
||||
.phy_addr = 0,
|
||||
};
|
||||
|
||||
|
|
|
@ -107,7 +107,7 @@ static void ek_add_device_nand(void)
|
|||
}
|
||||
|
||||
static struct at91_ether_platform_data macb_pdata = {
|
||||
.flags = AT91SAM_ETHER_RMII,
|
||||
.is_rmii = 1,
|
||||
.phy_addr = 0,
|
||||
};
|
||||
|
||||
|
|
|
@ -106,7 +106,7 @@ static void ek_add_device_nand(void)
|
|||
}
|
||||
|
||||
static struct at91_ether_platform_data macb_pdata = {
|
||||
.flags = AT91SAM_ETHER_RMII,
|
||||
.is_rmii = 1,
|
||||
.phy_addr = 0,
|
||||
};
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
#include <mach/io.h>
|
||||
|
||||
static struct at91_ether_platform_data macb_pdata = {
|
||||
.flags = AT91SAM_ETHER_MII | AT91SAM_ETHER_FORCE_LINK,
|
||||
.phy_flags = PHYLIB_FORCE_LINK,
|
||||
.phy_addr = 4,
|
||||
};
|
||||
|
||||
|
|
|
@ -90,7 +90,7 @@ static void pm_add_device_nand(void)
|
|||
}
|
||||
|
||||
static struct at91_ether_platform_data macb_pdata = {
|
||||
.flags = AT91SAM_ETHER_RMII,
|
||||
.is_rmii = 1,
|
||||
.phy_addr = 0,
|
||||
};
|
||||
|
||||
|
|
|
@ -114,7 +114,7 @@ static void __init pm9g45_add_device_usbh(void) {}
|
|||
#endif
|
||||
|
||||
static struct at91_ether_platform_data macb_pdata = {
|
||||
.flags = AT91SAM_ETHER_RMII,
|
||||
.is_rmii = 1,
|
||||
.phy_addr = 0,
|
||||
};
|
||||
|
||||
|
|
|
@ -79,7 +79,7 @@ static void qil_a9260_add_device_mci(void) {}
|
|||
|
||||
#ifdef CONFIG_CALAO_MB_QIL_A9260
|
||||
static struct at91_ether_platform_data macb_pdata = {
|
||||
.flags = AT91SAM_ETHER_RMII,
|
||||
.is_rmii = 1,
|
||||
.phy_addr = -1,
|
||||
};
|
||||
|
||||
|
|
|
@ -114,7 +114,7 @@ static void tny_a9260_add_device_nand(void)
|
|||
|
||||
#ifdef CONFIG_DRIVER_NET_MACB
|
||||
static struct at91_ether_platform_data macb_pdata = {
|
||||
.flags = AT91SAM_ETHER_RMII,
|
||||
.is_rmii = 1,
|
||||
.phy_addr = -1,
|
||||
};
|
||||
|
||||
|
|
|
@ -114,7 +114,7 @@ static void usb_a9260_add_device_nand(void)
|
|||
}
|
||||
|
||||
static struct at91_ether_platform_data macb_pdata = {
|
||||
.flags = AT91SAM_ETHER_RMII,
|
||||
.is_rmii = 1,
|
||||
.phy_addr = -1,
|
||||
};
|
||||
|
||||
|
|
|
@ -91,7 +91,7 @@ void __init at91_add_device_eth(int id, struct at91_ether_platform_data *data)
|
|||
at91_set_A_periph(AT91_PIN_PA8, 0); /* ETXEN */
|
||||
at91_set_A_periph(AT91_PIN_PA7, 0); /* ETXCK_EREFCK */
|
||||
|
||||
if (!(data->flags & AT91SAM_ETHER_RMII)) {
|
||||
if (!data->is_rmii) {
|
||||
at91_set_B_periph(AT91_PIN_PB19, 0); /* ERXCK */
|
||||
at91_set_B_periph(AT91_PIN_PB18, 0); /* ECOL */
|
||||
at91_set_B_periph(AT91_PIN_PB17, 0); /* ERXDV */
|
||||
|
|
|
@ -89,7 +89,7 @@ void at91_add_device_eth(int id, struct at91_ether_platform_data *data)
|
|||
at91_set_A_periph(AT91_PIN_PA21, 0); /* EMDIO */
|
||||
at91_set_A_periph(AT91_PIN_PA20, 0); /* EMDC */
|
||||
|
||||
if (!(data->flags & AT91SAM_ETHER_RMII)) {
|
||||
if (!data->is_rmii) {
|
||||
at91_set_B_periph(AT91_PIN_PA28, 0); /* ECRS */
|
||||
at91_set_B_periph(AT91_PIN_PA29, 0); /* ECOL */
|
||||
at91_set_B_periph(AT91_PIN_PA25, 0); /* ERX2 */
|
||||
|
|
|
@ -96,7 +96,7 @@ void at91_add_device_eth(int id, struct at91_ether_platform_data *data)
|
|||
at91_set_A_periph(AT91_PIN_PE30, 0); /* EMDIO */
|
||||
at91_set_A_periph(AT91_PIN_PE29, 0); /* EMDC */
|
||||
|
||||
if (!(data->flags & AT91SAM_ETHER_RMII)) {
|
||||
if (!data->is_rmii) {
|
||||
at91_set_A_periph(AT91_PIN_PE22, 0); /* ECRS */
|
||||
at91_set_B_periph(AT91_PIN_PC26, 0); /* ECOL */
|
||||
at91_set_B_periph(AT91_PIN_PC22, 0); /* ERX2 */
|
||||
|
|
|
@ -72,7 +72,7 @@ void at91_add_device_eth(int id, struct at91_ether_platform_data *data)
|
|||
at91_set_A_periph(AT91_PIN_PA19, 0); /* EMDIO */
|
||||
at91_set_A_periph(AT91_PIN_PA18, 0); /* EMDC */
|
||||
|
||||
if (!(data->flags & AT91SAM_ETHER_RMII)) {
|
||||
if (!data->is_rmii) {
|
||||
at91_set_B_periph(AT91_PIN_PA29, 0); /* ECRS */
|
||||
at91_set_B_periph(AT91_PIN_PA30, 0); /* ECOL */
|
||||
at91_set_B_periph(AT91_PIN_PA8, 0); /* ERX2 */
|
||||
|
|
|
@ -84,7 +84,7 @@ void at91_add_device_eth(int id, struct at91_ether_platform_data *data)
|
|||
at91_set_A_periph(AT91_PIN_PB5, 0); /* EMDIO */
|
||||
at91_set_A_periph(AT91_PIN_PB6, 0); /* EMDC */
|
||||
|
||||
if (!(data->flags & AT91SAM_ETHER_RMII)) {
|
||||
if (!data->is_rmii) {
|
||||
at91_set_A_periph(AT91_PIN_PB16, 0); /* ECRS */
|
||||
at91_set_A_periph(AT91_PIN_PB17, 0); /* ECOL */
|
||||
at91_set_A_periph(AT91_PIN_PB13, 0); /* ERX2 */
|
||||
|
@ -97,7 +97,7 @@ void at91_add_device_eth(int id, struct at91_ether_platform_data *data)
|
|||
break;
|
||||
case 1:
|
||||
start = AT91SAM9X5_BASE_EMAC1;
|
||||
if (!(data->flags & AT91SAM_ETHER_RMII))
|
||||
if (!data->is_rmii)
|
||||
pr_warn("AT91: Only RMII available on interface macb%d.\n", id);
|
||||
|
||||
/* Pins used for RMII */
|
||||
|
|
|
@ -64,14 +64,13 @@ struct atmel_nand_data {
|
|||
void at91_add_device_nand(struct atmel_nand_data *data);
|
||||
|
||||
/* Ethernet (EMAC & MACB) */
|
||||
#define AT91SAM_ETHER_MII (0 << 0)
|
||||
#define AT91SAM_ETHER_RMII (1 << 0)
|
||||
#define AT91SAM_ETHER_FORCE_LINK (1 << 1)
|
||||
#define AT91SAM_ETX2_ETX3_ALTERNATIVE (1 << 2)
|
||||
#define AT91SAM_ETX2_ETX3_ALTERNATIVE (1 << 0)
|
||||
|
||||
struct at91_ether_platform_data {
|
||||
unsigned int phy_flags;
|
||||
unsigned int flags;
|
||||
int phy_addr;
|
||||
int is_rmii;
|
||||
int (*get_ethaddr)(struct eth_device*, unsigned char *adr);
|
||||
};
|
||||
|
||||
|
|
|
@ -75,6 +75,21 @@ int get_free_deviceid(const char *name_template)
|
|||
};
|
||||
}
|
||||
|
||||
int device_probe(struct device_d *dev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = dev->bus->probe(dev);
|
||||
if (ret) {
|
||||
dev_err(dev, "probe failed: %s\n", strerror(-ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
list_add(&dev->active, &active);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int match(struct driver_d *drv, struct device_d *dev)
|
||||
{
|
||||
int ret;
|
||||
|
@ -86,13 +101,9 @@ static int match(struct driver_d *drv, struct device_d *dev)
|
|||
|
||||
if (dev->bus->match(dev, drv))
|
||||
goto err_out;
|
||||
ret = dev->bus->probe(dev);
|
||||
if (ret) {
|
||||
dev_err(dev, "probe failed: %s\n", strerror(-ret));
|
||||
ret = device_probe(dev);
|
||||
if (ret)
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
list_add(&dev->active, &active);
|
||||
|
||||
return 0;
|
||||
err_out:
|
||||
|
|
|
@ -342,7 +342,7 @@ static int at91_ether_probe(struct device_d *dev)
|
|||
|
||||
mac_cfg |= AT91_EMAC_CLK_DIV32 | AT91_EMAC_BIG;
|
||||
|
||||
if (pdata->flags & AT91SAM_ETHER_RMII) {
|
||||
if (pdata->is_rmii) {
|
||||
ether_dev->interface = PHY_INTERFACE_MODE_RGMII;
|
||||
mac_cfg |= AT91_EMAC_RMII;
|
||||
} else {
|
||||
|
|
|
@ -439,13 +439,12 @@ static int macb_probe(struct device_d *dev)
|
|||
macb->miibus.priv = macb;
|
||||
macb->miibus.parent = dev;
|
||||
|
||||
if (pdata->flags & AT91SAM_ETHER_RMII)
|
||||
if (pdata->is_rmii)
|
||||
macb->interface = PHY_INTERFACE_MODE_RMII;
|
||||
else
|
||||
macb->interface = PHY_INTERFACE_MODE_MII;
|
||||
|
||||
macb->phy_flags = pdata->flags & AT91SAM_ETHER_FORCE_LINK ?
|
||||
PHYLIB_FORCE_LINK : 0;
|
||||
macb->phy_flags = pdata->phy_flags;
|
||||
|
||||
macb->rx_buffer = dma_alloc_coherent(CFG_MACB_RX_BUFFER_SIZE);
|
||||
macb->rx_ring = dma_alloc_coherent(CFG_MACB_RX_RING_SIZE * sizeof(struct macb_dma_desc));
|
||||
|
|
|
@ -8,15 +8,16 @@ if PHYLIB
|
|||
|
||||
comment "MII PHY device drivers"
|
||||
|
||||
config GENERIC_PHY
|
||||
bool "Drivers for the Generic PHYs"
|
||||
default y
|
||||
|
||||
endif
|
||||
config MICREL_PHY
|
||||
bool "Driver for Micrel PHYs"
|
||||
---help---
|
||||
Supports the KSZ9021, VSC8201, KS8001 PHYs.
|
||||
|
||||
config SMSC_PHY
|
||||
bool "Drivers for SMSC PHYs"
|
||||
---help---
|
||||
Currently supports the LAN83C185, LAN8187 and LAN8700 PHYs
|
||||
|
||||
endif
|
||||
|
||||
endmenu
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
obj-y += phy.o mdio_bus.o
|
||||
obj-$(CONFIG_GENERIC_PHY) += generic.o
|
||||
obj-$(CONFIG_MICREL_PHY) += micrel.o
|
||||
obj-$(CONFIG_SMSC_PHY) += smsc.o
|
||||
|
|
|
@ -1,36 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2009 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
|
||||
*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <linux/phy.h>
|
||||
#include <init.h>
|
||||
|
||||
static struct phy_driver generic_phy = {
|
||||
.drv.name = "Generic PHY",
|
||||
.phy_id = PHY_ANY_UID,
|
||||
.phy_id_mask = PHY_ANY_UID,
|
||||
.features = 0,
|
||||
};
|
||||
|
||||
static int generic_phy_register(void)
|
||||
{
|
||||
return phy_driver_register(&generic_phy);
|
||||
}
|
||||
device_initcall(generic_phy_register);
|
|
@ -153,6 +153,7 @@ static int mdio_bus_probe(struct device_d *_dev)
|
|||
struct phy_device *dev = to_phy_device(_dev);
|
||||
struct phy_driver *drv = to_phy_driver(_dev->driver);
|
||||
|
||||
int ret;
|
||||
char str[16];
|
||||
|
||||
dev->attached_dev->phydev = dev;
|
||||
|
@ -160,14 +161,9 @@ static int mdio_bus_probe(struct device_d *_dev)
|
|||
dev_add_child(dev->dev.parent, _dev);
|
||||
|
||||
if (drv->probe) {
|
||||
int ret;
|
||||
|
||||
ret = drv->probe(dev);
|
||||
if (ret) {
|
||||
dev->attached_dev->phydev = NULL;
|
||||
dev->attached_dev = NULL;
|
||||
return ret;
|
||||
}
|
||||
if (ret)
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (dev->dev_flags) {
|
||||
|
@ -175,6 +171,10 @@ static int mdio_bus_probe(struct device_d *_dev)
|
|||
dev->speed = SPEED_10;
|
||||
dev->duplex = DUPLEX_FULL;
|
||||
dev->autoneg = !AUTONEG_ENABLE;
|
||||
} else if (dev->dev_flags & PHYLIB_FORCE_100) {
|
||||
dev->speed = SPEED_100;
|
||||
dev->duplex = DUPLEX_FULL;
|
||||
dev->autoneg = !AUTONEG_ENABLE;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -184,7 +184,9 @@ static int mdio_bus_probe(struct device_d *_dev)
|
|||
dev->supported = drv->features;
|
||||
dev->advertising = drv->features;
|
||||
|
||||
drv->config_init(dev);
|
||||
ret = phy_init_hw(dev);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
/* Sanitize settings based on PHY capabilities */
|
||||
if ((dev->supported & SUPPORTED_Autoneg) == 0)
|
||||
|
@ -193,6 +195,9 @@ static int mdio_bus_probe(struct device_d *_dev)
|
|||
sprintf(str, "%d", dev->addr);
|
||||
dev_add_param_fixed(&dev->dev, "phy_addr", str);
|
||||
|
||||
sprintf(str, "0x%08x", dev->phy_id);
|
||||
dev_add_param_fixed(&dev->dev, "phy_id", str);
|
||||
|
||||
dev->cdev.name = asprintf("phy%d", _dev->id);
|
||||
dev->cdev.size = 64;
|
||||
dev->cdev.ops = &phydev_ops;
|
||||
|
@ -201,6 +206,11 @@ static int mdio_bus_probe(struct device_d *_dev)
|
|||
devfs_create(&dev->cdev);
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
dev->attached_dev->phydev = NULL;
|
||||
dev->attached_dev = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void mdio_bus_remove(struct device_d *_dev)
|
||||
|
|
|
@ -0,0 +1,174 @@
|
|||
/*
|
||||
* drivers/net/phy/micrel.c
|
||||
*
|
||||
* Driver for Micrel PHYs
|
||||
*
|
||||
* Author: David J. Choi
|
||||
*
|
||||
* Copyright (c) 2010 Micrel, Inc.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Support : ksz9021 1000/100/10 phy from Micrel
|
||||
* ks8001, ks8737, ks8721, ks8041, ks8051 100/10 phy
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <init.h>
|
||||
#include <linux/mii.h>
|
||||
#include <linux/ethtool.h>
|
||||
#include <linux/phy.h>
|
||||
#include <linux/micrel_phy.h>
|
||||
|
||||
/* 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)
|
||||
|
||||
/* 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)
|
||||
|
||||
static int kszphy_config_init(struct phy_device *phydev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ksz8021_config_init(struct phy_device *phydev)
|
||||
{
|
||||
const u16 val = KSZPHY_OMSO_B_CAST_OFF | KSZPHY_OMSO_RMII_OVERRIDE;
|
||||
phy_write(phydev, MII_KSZPHY_OMSO, val);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ks8051_config_init(struct phy_device *phydev)
|
||||
{
|
||||
int regval;
|
||||
|
||||
if (phydev->dev_flags & MICREL_PHY_50MHZ_CLK) {
|
||||
regval = phy_read(phydev, MII_KSZPHY_CTRL);
|
||||
regval |= KSZ8051_RMII_50MHZ_CLK;
|
||||
phy_write(phydev, MII_KSZPHY_CTRL, regval);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#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)
|
||||
{
|
||||
int regval;
|
||||
|
||||
/* dummy read */
|
||||
regval = phy_read(phydev, KSZ8873MLL_GLOBAL_CONTROL_4);
|
||||
|
||||
regval = phy_read(phydev, KSZ8873MLL_GLOBAL_CONTROL_4);
|
||||
|
||||
if (regval & KSZ8873MLL_GLOBAL_CONTROL_4_DUPLEX)
|
||||
phydev->duplex = DUPLEX_HALF;
|
||||
else
|
||||
phydev->duplex = DUPLEX_FULL;
|
||||
|
||||
if (regval & KSZ8873MLL_GLOBAL_CONTROL_4_SPEED)
|
||||
phydev->speed = SPEED_10;
|
||||
else
|
||||
phydev->speed = SPEED_100;
|
||||
|
||||
phydev->link = 1;
|
||||
phydev->pause = phydev->asym_pause = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ksz8873mll_config_aneg(struct phy_device *phydev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ksz8873mll_config_init(struct phy_device *phydev)
|
||||
{
|
||||
phydev->autoneg = AUTONEG_DISABLE;
|
||||
phydev->link = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct phy_driver ksphy_driver[] = {
|
||||
{
|
||||
.phy_id = PHY_ID_KS8737,
|
||||
.phy_id_mask = 0x00fffff0,
|
||||
.drv.name = "Micrel KS8737",
|
||||
.features = (PHY_BASIC_FEATURES | SUPPORTED_Pause),
|
||||
.config_init = kszphy_config_init,
|
||||
.config_aneg = genphy_config_aneg,
|
||||
.read_status = genphy_read_status,
|
||||
}, {
|
||||
.phy_id = PHY_ID_KSZ8021,
|
||||
.phy_id_mask = 0x00ffffff,
|
||||
.drv.name = "Micrel KSZ8021",
|
||||
.features = (PHY_BASIC_FEATURES | SUPPORTED_Pause |
|
||||
SUPPORTED_Asym_Pause),
|
||||
.config_init = ksz8021_config_init,
|
||||
.config_aneg = genphy_config_aneg,
|
||||
.read_status = genphy_read_status,
|
||||
}, {
|
||||
.phy_id = PHY_ID_KSZ8041,
|
||||
.phy_id_mask = 0x00fffff0,
|
||||
.drv.name = "Micrel KSZ8041",
|
||||
.features = (PHY_BASIC_FEATURES | SUPPORTED_Pause
|
||||
| SUPPORTED_Asym_Pause),
|
||||
.config_init = kszphy_config_init,
|
||||
.config_aneg = genphy_config_aneg,
|
||||
.read_status = genphy_read_status,
|
||||
}, {
|
||||
.phy_id = PHY_ID_KSZ8051,
|
||||
.phy_id_mask = 0x00fffff0,
|
||||
.drv.name = "Micrel KSZ8051",
|
||||
.features = (PHY_BASIC_FEATURES | SUPPORTED_Pause
|
||||
| SUPPORTED_Asym_Pause),
|
||||
.config_init = ks8051_config_init,
|
||||
.config_aneg = genphy_config_aneg,
|
||||
.read_status = genphy_read_status,
|
||||
}, {
|
||||
.phy_id = PHY_ID_KSZ8001,
|
||||
.drv.name = "Micrel KSZ8001 or KS8721",
|
||||
.phy_id_mask = 0x00ffffff,
|
||||
.features = (PHY_BASIC_FEATURES | SUPPORTED_Pause),
|
||||
.config_init = kszphy_config_init,
|
||||
.config_aneg = genphy_config_aneg,
|
||||
.read_status = genphy_read_status,
|
||||
}, {
|
||||
.phy_id = PHY_ID_KSZ9021,
|
||||
.phy_id_mask = 0x000ffffe,
|
||||
.drv.name = "Micrel KSZ9021 Gigabit PHY",
|
||||
.features = (PHY_GBIT_FEATURES | SUPPORTED_Pause
|
||||
| SUPPORTED_Asym_Pause),
|
||||
.config_init = kszphy_config_init,
|
||||
.config_aneg = genphy_config_aneg,
|
||||
.read_status = genphy_read_status,
|
||||
}, {
|
||||
.phy_id = PHY_ID_KSZ8873MLL,
|
||||
.phy_id_mask = 0x00fffff0,
|
||||
.drv.name = "Micrel KSZ8873MLL Switch",
|
||||
.features = (SUPPORTED_Pause | SUPPORTED_Asym_Pause),
|
||||
.config_init = ksz8873mll_config_init,
|
||||
.config_aneg = ksz8873mll_config_aneg,
|
||||
.read_status = ksz8873mll_read_status,
|
||||
} };
|
||||
|
||||
static int ksphy_init(void)
|
||||
{
|
||||
return phy_drivers_register(ksphy_driver,
|
||||
ARRAY_SIZE(ksphy_driver));
|
||||
}
|
||||
fs_initcall(ksphy_init);
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
#include <common.h>
|
||||
#include <driver.h>
|
||||
#include <init.h>
|
||||
#include <net.h>
|
||||
#include <malloc.h>
|
||||
#include <linux/phy.h>
|
||||
|
@ -27,6 +28,7 @@
|
|||
|
||||
#define PHY_AN_TIMEOUT 10
|
||||
|
||||
static struct phy_driver genphy_driver;
|
||||
static int genphy_config_init(struct phy_device *phydev);
|
||||
|
||||
int phy_update_status(struct phy_device *dev)
|
||||
|
@ -53,6 +55,87 @@ int phy_update_status(struct phy_device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static LIST_HEAD(phy_fixup_list);
|
||||
|
||||
/*
|
||||
* Creates a new phy_fixup and adds it to the list
|
||||
* @bus_id: A string which matches phydev->dev.bus_id (or PHY_ANY_ID)
|
||||
* @phy_uid: Used to match against phydev->phy_id (the UID of the PHY)
|
||||
* It can also be PHY_ANY_UID
|
||||
* @phy_uid_mask: Applied to phydev->phy_id and fixup->phy_uid before
|
||||
* comparison
|
||||
* @run: The actual code to be run when a matching PHY is found
|
||||
*/
|
||||
int phy_register_fixup(const char *bus_id, u32 phy_uid, u32 phy_uid_mask,
|
||||
int (*run)(struct phy_device *))
|
||||
{
|
||||
struct phy_fixup *fixup;
|
||||
|
||||
fixup = kzalloc(sizeof(struct phy_fixup), GFP_KERNEL);
|
||||
if (!fixup)
|
||||
return -ENOMEM;
|
||||
|
||||
strlcpy(fixup->bus_id, bus_id, sizeof(fixup->bus_id));
|
||||
fixup->phy_uid = phy_uid;
|
||||
fixup->phy_uid_mask = phy_uid_mask;
|
||||
fixup->run = run;
|
||||
|
||||
list_add_tail(&fixup->list, &phy_fixup_list);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Registers a fixup to be run on any PHY with the UID in phy_uid */
|
||||
int phy_register_fixup_for_uid(u32 phy_uid, u32 phy_uid_mask,
|
||||
int (*run)(struct phy_device *))
|
||||
{
|
||||
return phy_register_fixup(PHY_ANY_ID, phy_uid, phy_uid_mask, run);
|
||||
}
|
||||
|
||||
/* Registers a fixup to be run on the PHY with id string bus_id */
|
||||
int phy_register_fixup_for_id(const char *bus_id,
|
||||
int (*run)(struct phy_device *))
|
||||
{
|
||||
return phy_register_fixup(bus_id, PHY_ANY_UID, 0xffffffff, run);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns 1 if fixup matches phydev in bus_id and phy_uid.
|
||||
* Fixups can be set to match any in one or more fields.
|
||||
*/
|
||||
static int phy_needs_fixup(struct phy_device *phydev, struct phy_fixup *fixup)
|
||||
{
|
||||
if (strcmp(fixup->bus_id, dev_name(&phydev->dev)) != 0)
|
||||
if (strcmp(fixup->bus_id, PHY_ANY_ID) != 0)
|
||||
return 0;
|
||||
|
||||
if ((fixup->phy_uid & fixup->phy_uid_mask) !=
|
||||
(phydev->phy_id & fixup->phy_uid_mask))
|
||||
if (fixup->phy_uid != PHY_ANY_UID)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
/* Runs any matching fixups for this phydev */
|
||||
int phy_scan_fixups(struct phy_device *phydev)
|
||||
{
|
||||
struct phy_fixup *fixup;
|
||||
|
||||
list_for_each_entry(fixup, &phy_fixup_list, list) {
|
||||
if (phy_needs_fixup(phydev, fixup)) {
|
||||
int err;
|
||||
|
||||
err = fixup->run(phydev);
|
||||
|
||||
if (err < 0) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct phy_device *phy_device_create(struct mii_bus *bus, int addr, int phy_id)
|
||||
{
|
||||
struct phy_device *dev;
|
||||
|
@ -142,6 +225,21 @@ struct phy_device *get_phy_device(struct mii_bus *bus, int addr)
|
|||
return dev;
|
||||
}
|
||||
|
||||
static int phy_register_device(struct phy_device* dev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = register_device(&dev->dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (dev->dev.driver)
|
||||
return 0;
|
||||
|
||||
dev->dev.driver = &genphy_driver.drv;
|
||||
return device_probe(&dev->dev);
|
||||
}
|
||||
|
||||
/* Automatically gets and returns the PHY device */
|
||||
int phy_device_connect(struct eth_device *edev, struct mii_bus *bus, int addr,
|
||||
void (*adjust_link) (struct eth_device *edev),
|
||||
|
@ -164,7 +262,7 @@ int phy_device_connect(struct eth_device *edev, struct mii_bus *bus, int addr,
|
|||
dev->interface = interface;
|
||||
dev->dev_flags = flags;
|
||||
|
||||
ret = register_device(&dev->dev);
|
||||
ret = phy_register_device(dev);
|
||||
if (ret)
|
||||
goto fail;
|
||||
} else {
|
||||
|
@ -181,7 +279,7 @@ int phy_device_connect(struct eth_device *edev, struct mii_bus *bus, int addr,
|
|||
dev->interface = interface;
|
||||
dev->dev_flags = flags;
|
||||
|
||||
ret = register_device(&dev->dev);
|
||||
ret = phy_register_device(dev);
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
|
@ -597,3 +695,31 @@ int phy_drivers_register(struct phy_driver *new_driver, int n)
|
|||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int phy_init_hw(struct phy_device *phydev)
|
||||
{
|
||||
struct phy_driver *phydrv = to_phy_driver(phydev->dev.driver);
|
||||
int ret;
|
||||
|
||||
if (!phydrv || !phydrv->config_init)
|
||||
return 0;
|
||||
|
||||
ret = phy_scan_fixups(phydev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return phydrv->config_init(phydev);
|
||||
}
|
||||
|
||||
static struct phy_driver genphy_driver = {
|
||||
.drv.name = "Generic PHY",
|
||||
.phy_id = PHY_ANY_UID,
|
||||
.phy_id_mask = PHY_ANY_UID,
|
||||
.features = 0,
|
||||
};
|
||||
|
||||
static int generic_phy_register(void)
|
||||
{
|
||||
return phy_driver_register(&genphy_driver);
|
||||
}
|
||||
device_initcall(generic_phy_register);
|
||||
|
|
|
@ -148,6 +148,11 @@ struct driver_d {
|
|||
int register_driver(struct driver_d *);
|
||||
int register_device(struct device_d *);
|
||||
|
||||
/* manualy probe a device
|
||||
* the driver need to be specified
|
||||
*/
|
||||
int device_probe(struct device_d *dev);
|
||||
|
||||
/* Unregister a device. This function can fail, e.g. when the device
|
||||
* has children.
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* include/linux/micrel_phy.h
|
||||
*
|
||||
* Micrel PHY IDs
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _MICREL_PHY_H
|
||||
#define _MICREL_PHY_H
|
||||
|
||||
#define MICREL_PHY_ID_MASK 0x00fffff0
|
||||
|
||||
#define PHY_ID_KSZ8873MLL 0x000e7237
|
||||
#define PHY_ID_KSZ9021 0x00221610
|
||||
#define PHY_ID_KS8737 0x00221720
|
||||
#define PHY_ID_KSZ8021 0x00221555
|
||||
#define PHY_ID_KSZ8041 0x00221510
|
||||
#define PHY_ID_KSZ8051 0x00221550
|
||||
/* both for ks8001 Rev. A/B, and for ks8721 Rev 3. */
|
||||
#define PHY_ID_KSZ8001 0x0022161A
|
||||
|
||||
/* struct phy_device dev_flags definitions */
|
||||
#define MICREL_PHY_50MHZ_CLK 0x00000001
|
||||
|
||||
#endif /* _MICREL_PHY_H */
|
|
@ -60,7 +60,8 @@ typedef enum {
|
|||
#define MII_BUS_ID_SIZE (20 - 3)
|
||||
|
||||
#define PHYLIB_FORCE_10 (1 << 0)
|
||||
#define PHYLIB_FORCE_LINK (1 << 1)
|
||||
#define PHYLIB_FORCE_100 (1 << 1)
|
||||
#define PHYLIB_FORCE_LINK (1 << 2)
|
||||
|
||||
#define PHYLIB_CAPABLE_1000M (1 << 0)
|
||||
|
||||
|
@ -225,10 +226,20 @@ struct phy_driver {
|
|||
#define PHY_ANY_ID "MATCH ANY PHY"
|
||||
#define PHY_ANY_UID 0xffffffff
|
||||
|
||||
/* A Structure for boards to register fixups with the PHY Lib */
|
||||
struct phy_fixup {
|
||||
struct list_head list;
|
||||
char bus_id[20];
|
||||
u32 phy_uid;
|
||||
u32 phy_uid_mask;
|
||||
int (*run)(struct phy_device *phydev);
|
||||
};
|
||||
|
||||
int phy_driver_register(struct phy_driver *drv);
|
||||
int phy_drivers_register(struct phy_driver *new_driver, int n);
|
||||
struct phy_device *get_phy_device(struct mii_bus *bus, int addr);
|
||||
int phy_init(void);
|
||||
int phy_init_hw(struct phy_device *phydev);
|
||||
|
||||
/**
|
||||
* phy_read - Convenience function for reading a given PHY register
|
||||
|
@ -266,5 +277,13 @@ int genphy_config_advert(struct phy_device *phydev);
|
|||
int genphy_setup_forced(struct phy_device *phydev);
|
||||
int get_phy_id(struct mii_bus *bus, int addr, u32 *phy_id);
|
||||
|
||||
int phy_register_fixup(const char *bus_id, u32 phy_uid, u32 phy_uid_mask,
|
||||
int (*run)(struct phy_device *));
|
||||
int phy_register_fixup_for_id(const char *bus_id,
|
||||
int (*run)(struct phy_device *));
|
||||
int phy_register_fixup_for_uid(u32 phy_uid, u32 phy_uid_mask,
|
||||
int (*run)(struct phy_device *));
|
||||
int phy_scan_fixups(struct phy_device *phydev);
|
||||
|
||||
extern struct bus_type mdio_bus_type;
|
||||
#endif /* __PHYDEV_H__ */
|
||||
|
|
Loading…
Reference in New Issue