From f485c8a35b38356a473208bec5ed786792c1eafe Mon Sep 17 00:00:00 2001 From: Matt Porter Date: Wed, 20 Mar 2013 05:38:13 +0000 Subject: [PATCH] phy: add support for ET1011C phys Adds an ET1011C PHY driver which is derived from the Linux kernel PHY driver (drivers/net/phy/et1011c.c) from the v3.9-rc2 tag. Note that an errata workaround config option is implemented to allow for TX_CLK to be enabled even when gigabit mode is negotiated. This workaround is used on the PG1.0 TI814X EVM. Signed-off-by: Matt Porter Reviewed-by: Tom Rini --- drivers/net/phy/Makefile | 1 + drivers/net/phy/et1011c.c | 110 ++++++++++++++++++++++++++++++++++++++ drivers/net/phy/phy.c | 3 ++ include/phy.h | 1 + 4 files changed, 115 insertions(+) create mode 100644 drivers/net/phy/et1011c.c diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index 5e90d7098d..af5f4b848c 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -34,6 +34,7 @@ COBJS-$(CONFIG_PHYLIB_10G) += generic_10g.o COBJS-$(CONFIG_PHY_ATHEROS) += atheros.o COBJS-$(CONFIG_PHY_BROADCOM) += broadcom.o COBJS-$(CONFIG_PHY_DAVICOM) += davicom.o +COBJS-$(CONFIG_PHY_ET1011C) += et1011c.o COBJS-$(CONFIG_PHY_LXT) += lxt.o COBJS-$(CONFIG_PHY_MARVELL) += marvell.o COBJS-$(CONFIG_PHY_MICREL) += micrel.o diff --git a/drivers/net/phy/et1011c.c b/drivers/net/phy/et1011c.c new file mode 100644 index 0000000000..5e22399af1 --- /dev/null +++ b/drivers/net/phy/et1011c.c @@ -0,0 +1,110 @@ +/* + * ET1011C PHY driver + * + * Derived from Linux kernel driver by Chaithrika U S + * Copyright (C) 2013, Texas Instruments, Incorporated - http://www.ti.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. + * + */ +#include +#include + +#define ET1011C_CONFIG_REG (0x16) +#define ET1011C_TX_FIFO_MASK (0x3 << 12) +#define ET1011C_TX_FIFO_DEPTH_8 (0x0 << 12) +#define ET1011C_TX_FIFO_DEPTH_16 (0x1 << 12) +#define ET1011C_INTERFACE_MASK (0x7 << 0) +#define ET1011C_GMII_INTERFACE (0x2 << 0) +#define ET1011C_SYS_CLK_EN (0x1 << 4) +#define ET1011C_TX_CLK_EN (0x1 << 5) + +#define ET1011C_STATUS_REG (0x1A) +#define ET1011C_DUPLEX_STATUS (0x1 << 7) +#define ET1011C_SPEED_MASK (0x3 << 8) +#define ET1011C_SPEED_1000 (0x2 << 8) +#define ET1011C_SPEED_100 (0x1 << 8) +#define ET1011C_SPEED_10 (0x0 << 8) + +static int et1011c_config(struct phy_device *phydev) +{ + int ctl = 0; + ctl = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR); + if (ctl < 0) + return ctl; + ctl &= ~(BMCR_FULLDPLX | BMCR_SPEED100 | BMCR_SPEED1000 | + BMCR_ANENABLE); + /* First clear the PHY */ + phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, ctl | BMCR_RESET); + + return genphy_config_aneg(phydev); +} + +static int et1011c_parse_status(struct phy_device *phydev) +{ + int mii_reg; + int speed; + + mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, ET1011C_STATUS_REG); + + if (mii_reg & ET1011C_DUPLEX_STATUS) + phydev->duplex = DUPLEX_FULL; + else + phydev->duplex = DUPLEX_HALF; + + speed = mii_reg & ET1011C_SPEED_MASK; + switch (speed) { + case ET1011C_SPEED_1000: + phydev->speed = SPEED_1000; + mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, ET1011C_CONFIG_REG); + mii_reg &= ~ET1011C_TX_FIFO_MASK; + phy_write(phydev, MDIO_DEVAD_NONE, ET1011C_CONFIG_REG, + mii_reg | + ET1011C_GMII_INTERFACE | + ET1011C_SYS_CLK_EN | +#ifdef CONFIG_PHY_ET1011C_TX_CLK_FIX + ET1011C_TX_CLK_EN | +#endif + ET1011C_TX_FIFO_DEPTH_16); + break; + case ET1011C_SPEED_100: + phydev->speed = SPEED_100; + break; + case ET1011C_SPEED_10: + phydev->speed = SPEED_10; + break; + } + + return 0; +} + +static int et1011c_startup(struct phy_device *phydev) +{ + genphy_update_link(phydev); + et1011c_parse_status(phydev); + return 0; +} + +static struct phy_driver et1011c_driver = { + .name = "ET1011C", + .uid = 0x0282f014, + .mask = 0xfffffff0, + .features = PHY_GBIT_FEATURES, + .config = &et1011c_config, + .startup = &et1011c_startup, +}; + +int phy_et1011c_init(void) +{ + phy_register(&et1011c_driver); + + return 0; +} diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index d0ed7666ed..f8c5481477 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -430,6 +430,9 @@ int phy_init(void) #ifdef CONFIG_PHY_DAVICOM phy_davicom_init(); #endif +#ifdef CONFIG_PHY_ET1011C + phy_et1011c_init(); +#endif #ifdef CONFIG_PHY_LXT phy_lxt_init(); #endif diff --git a/include/phy.h b/include/phy.h index 58ca2730c8..7b4ce744e1 100644 --- a/include/phy.h +++ b/include/phy.h @@ -223,6 +223,7 @@ int gen10g_discover_mmds(struct phy_device *phydev); int phy_atheros_init(void); int phy_broadcom_init(void); int phy_davicom_init(void); +int phy_et1011c_init(void); int phy_lxt_init(void); int phy_marvell_init(void); int phy_micrel_init(void); -- 2.39.5