From 8682aba7da2af2842296710acca7c03fcebafd5c Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Tue, 7 Feb 2012 14:08:48 +0000 Subject: [PATCH] net: phy: add support for Micrel's KSZ9021 Add the gigabit phy KSZ9021. Also, add function ksz9021_phy_extended_write /_read for access to the phys extended registers. The environment variable "disable_giga" can be used to disable 1000baseTx. Signed-off-by: Troy Kisky Acked-by: Dirk Behme --- drivers/net/phy/micrel.c | 87 ++++++++++++++++++++++++++++++++++++++++ include/micrel.h | 16 ++++++++ include/phy.h | 1 + 3 files changed, 104 insertions(+) create mode 100644 include/micrel.h diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c index d4e64f29d8..e3043dfa20 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c @@ -20,6 +20,9 @@ * author Andy Fleming * */ +#include +#include +#include #include static struct phy_driver KSZ804_driver = { @@ -42,10 +45,94 @@ static struct phy_driver KS8721_driver = { .shutdown = &genphy_shutdown, }; +/* ksz9021 PHY Registers */ +#define MII_KSZ9021_EXTENDED_CTRL 0x0b +#define MII_KSZ9021_EXTENDED_DATAW 0x0c +#define MII_KSZ9021_EXTENDED_DATAR 0x0d +#define MII_KSZ9021_PHY_CTL 0x1f +#define MIIM_KSZ9021_PHYCTL_1000 (1 << 6) +#define MIIM_KSZ9021_PHYCTL_100 (1 << 5) +#define MIIM_KSZ9021_PHYCTL_10 (1 << 4) +#define MIIM_KSZ9021_PHYCTL_DUPLEX (1 << 3) + +#define CTRL1000_PREFER_MASTER (1 << 10) +#define CTRL1000_CONFIG_MASTER (1 << 11) +#define CTRL1000_MANUAL_CONFIG (1 << 12) + +int ksz9021_phy_extended_write(struct phy_device *phydev, int regnum, u16 val) +{ + /* extended registers */ + phy_write(phydev, MDIO_DEVAD_NONE, + MII_KSZ9021_EXTENDED_CTRL, regnum | 0x8000); + return phy_write(phydev, MDIO_DEVAD_NONE, + MII_KSZ9021_EXTENDED_DATAW, val); +} + +int ksz9021_phy_extended_read(struct phy_device *phydev, int regnum) +{ + /* extended registers */ + phy_write(phydev, MDIO_DEVAD_NONE, MII_KSZ9021_EXTENDED_CTRL, regnum); + return phy_read(phydev, MDIO_DEVAD_NONE, MII_KSZ9021_EXTENDED_DATAR); +} + +/* Micrel ksz9021 */ +static int ksz9021_config(struct phy_device *phydev) +{ + unsigned ctrl1000 = 0; + const unsigned master = CTRL1000_PREFER_MASTER | + CTRL1000_CONFIG_MASTER | CTRL1000_MANUAL_CONFIG; + unsigned features = phydev->drv->features; + + if (getenv("disable_giga")) + features &= ~(SUPPORTED_1000baseT_Half | + SUPPORTED_1000baseT_Full); + /* force master mode for 1000BaseT due to chip errata */ + if (features & SUPPORTED_1000baseT_Half) + ctrl1000 |= ADVERTISE_1000HALF | master; + if (features & SUPPORTED_1000baseT_Full) + ctrl1000 |= ADVERTISE_1000FULL | master; + phydev->advertising = phydev->supported = features; + phy_write(phydev, MDIO_DEVAD_NONE, MII_CTRL1000, ctrl1000); + genphy_config_aneg(phydev); + genphy_restart_aneg(phydev); + return 0; +} + +static int ksz9021_startup(struct phy_device *phydev) +{ + unsigned phy_ctl; + genphy_update_link(phydev); + phy_ctl = phy_read(phydev, MDIO_DEVAD_NONE, MII_KSZ9021_PHY_CTL); + + if (phy_ctl & MIIM_KSZ9021_PHYCTL_DUPLEX) + phydev->duplex = DUPLEX_FULL; + else + phydev->duplex = DUPLEX_HALF; + + if (phy_ctl & MIIM_KSZ9021_PHYCTL_1000) + phydev->speed = SPEED_1000; + else if (phy_ctl & MIIM_KSZ9021_PHYCTL_100) + phydev->speed = SPEED_100; + else if (phy_ctl & MIIM_KSZ9021_PHYCTL_10) + phydev->speed = SPEED_10; + return 0; +} + +static struct phy_driver ksz9021_driver = { + .name = "Micrel ksz9021", + .uid = 0x221610, + .mask = 0xfffff0, + .features = PHY_GBIT_FEATURES, + .config = &ksz9021_config, + .startup = &ksz9021_startup, + .shutdown = &genphy_shutdown, +}; + int phy_micrel_init(void) { phy_register(&KSZ804_driver); phy_register(&KS8721_driver); + phy_register(&ksz9021_driver); return 0; } diff --git a/include/micrel.h b/include/micrel.h new file mode 100644 index 0000000000..25e8a4624b --- /dev/null +++ b/include/micrel.h @@ -0,0 +1,16 @@ +#ifndef _MICREL_H + +#define MII_KSZ9021_EXT_COMMON_CTRL 0x100 +#define MII_KSZ9021_EXT_STRAP_STATUS 0x101 +#define MII_KSZ9021_EXT_OP_STRAP_OVERRIDE 0x102 +#define MII_KSZ9021_EXT_OP_STRAP_STATUS 0x103 +#define MII_KSZ9021_EXT_RGMII_CLOCK_SKEW 0x104 +#define MII_KSZ9021_EXT_RGMII_RX_DATA_SKEW 0x105 +#define MII_KSZ9021_EXT_RGMII_TX_DATA_SKEW 0x106 +#define MII_KSZ9021_EXT_ANALOG_TEST 0x107 + +struct phy_device; +int ksz9021_phy_extended_write(struct phy_device *phydev, int regnum, u16 val); +int ksz9021_phy_extended_read(struct phy_device *phydev, int regnum); + +#endif diff --git a/include/phy.h b/include/phy.h index bc522d57c3..3c30f115b6 100644 --- a/include/phy.h +++ b/include/phy.h @@ -207,6 +207,7 @@ int phy_config(struct phy_device *phydev); int phy_shutdown(struct phy_device *phydev); int phy_register(struct phy_driver *drv); int genphy_config_aneg(struct phy_device *phydev); +int genphy_restart_aneg(struct phy_device *phydev); int genphy_update_link(struct phy_device *phydev); int genphy_config(struct phy_device *phydev); int genphy_startup(struct phy_device *phydev); -- 2.30.2