diff options
Diffstat (limited to 'drivers/net/phy')
-rw-r--r-- | drivers/net/phy/Makefile | 1 | ||||
-rw-r--r-- | drivers/net/phy/et1011c.c | 110 | ||||
-rw-r--r-- | drivers/net/phy/marvell.c | 11 | ||||
-rw-r--r-- | drivers/net/phy/phy.c | 3 | ||||
-rw-r--r-- | drivers/net/phy/teranetics.c | 16 | ||||
-rw-r--r-- | drivers/net/phy/vitesse.c | 67 |
6 files changed, 206 insertions, 2 deletions
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index 5e90d70..af5f4b8 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 0000000..5e22399 --- /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 <config.h> +#include <phy.h> + +#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/marvell.c b/drivers/net/phy/marvell.c index 4b27198..46801c7 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -465,6 +465,16 @@ static struct phy_driver M88E1149S_driver = { .shutdown = &genphy_shutdown, }; +static struct phy_driver M88E1518_driver = { + .name = "Marvell 88E1518", + .uid = 0x1410dd1, + .mask = 0xffffff0, + .features = PHY_GBIT_FEATURES, + .config = &m88e1111s_config, + .startup = &m88e1011s_startup, + .shutdown = &genphy_shutdown, +}; + int phy_marvell_init(void) { phy_register(&M88E1149S_driver); @@ -474,6 +484,7 @@ int phy_marvell_init(void) phy_register(&M88E1118R_driver); phy_register(&M88E1111S_driver); phy_register(&M88E1011S_driver); + phy_register(&M88E1518_driver); return 0; } diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index d0ed766..f8c5481 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/drivers/net/phy/teranetics.c b/drivers/net/phy/teranetics.c index 78447b7..84ce736 100644 --- a/drivers/net/phy/teranetics.c +++ b/drivers/net/phy/teranetics.c @@ -34,9 +34,21 @@ int tn2020_config(struct phy_device *phydev) unsigned short restart_an = (MDIO_AN_CTRL1_RESTART | MDIO_AN_CTRL1_ENABLE | MDIO_AN_CTRL1_XNP); + u8 phy_hwversion; - phy_write(phydev, 30, 93, 2); - phy_write(phydev, MDIO_MMD_AN, MDIO_CTRL1, restart_an); + /* + * bit 15:12 of register 30.32 indicates PHY hardware + * version. It can be used to distinguish TN80xx from + * TN2020. TN2020 needs write 0x2 to 30.93, but TN80xx + * needs 0x1. + */ + phy_hwversion = (phy_read(phydev, 30, 32) >> 12) & 0xf; + if (phy_hwversion <= 3) { + phy_write(phydev, 30, 93, 2); + phy_write(phydev, MDIO_MMD_AN, MDIO_CTRL1, restart_an); + } else { + phy_write(phydev, 30, 93, 1); + } } return 0; diff --git a/drivers/net/phy/vitesse.c b/drivers/net/phy/vitesse.c index 6c5cb99..c283d82 100644 --- a/drivers/net/phy/vitesse.c +++ b/drivers/net/phy/vitesse.c @@ -48,6 +48,19 @@ #define MIIM_VSC8601_SKEW_CTRL 0x1c #define PHY_EXT_PAGE_ACCESS 0x1f +#define PHY_EXT_PAGE_ACCESS_GENERAL 0x10 +#define PHY_EXT_PAGE_ACCESS_EXTENDED3 0x3 + +/* Vitesse VSC8574 control register */ +#define MIIM_VSC8574_MAC_SERDES_CON 0x10 +#define MIIM_VSC8574_MAC_SERDES_ANEG 0x80 +#define MIIM_VSC8574_GENERAL18 0x12 +#define MIIM_VSC8574_GENERAL19 0x13 + +/* Vitesse VSC8574 gerenal purpose register 18 */ +#define MIIM_VSC8574_18G_SGMII 0x80f0 +#define MIIM_VSC8574_18G_QSGMII 0x80e0 +#define MIIM_VSC8574_18G_CMDSTAT 0x8000 /* CIS8201 */ static int vitesse_config(struct phy_device *phydev) @@ -145,6 +158,49 @@ static int vsc8601_config(struct phy_device *phydev) return 0; } +static int vsc8574_config(struct phy_device *phydev) +{ + u32 val; + /* configure regiser 19G for MAC */ + phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS, + PHY_EXT_PAGE_ACCESS_GENERAL); + + val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_GENERAL19); + if (phydev->interface == PHY_INTERFACE_MODE_QSGMII) { + /* set bit 15:14 to '01' for QSGMII mode */ + val = (val & 0x3fff) | (1 << 14); + phy_write(phydev, MDIO_DEVAD_NONE, + MIIM_VSC8574_GENERAL19, val); + /* Enable 4 ports MAC QSGMII */ + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_GENERAL18, + MIIM_VSC8574_18G_QSGMII); + } else { + /* set bit 15:14 to '00' for SGMII mode */ + val = val & 0x3fff; + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_GENERAL19, val); + /* Enable 4 ports MAC SGMII */ + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_GENERAL18, + MIIM_VSC8574_18G_SGMII); + } + val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_GENERAL18); + /* When bit 15 is cleared the command has completed */ + while (val & MIIM_VSC8574_18G_CMDSTAT) + val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_GENERAL18); + + /* Enable Serdes Auto-negotiation */ + phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS, + PHY_EXT_PAGE_ACCESS_EXTENDED3); + val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_MAC_SERDES_CON); + val = val | MIIM_VSC8574_MAC_SERDES_ANEG; + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_MAC_SERDES_CON, val); + + phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS, 0); + + genphy_config_aneg(phydev); + + return 0; +} + static struct phy_driver VSC8211_driver = { .name = "Vitesse VSC8211", .uid = 0xfc4b0, @@ -185,6 +241,16 @@ static struct phy_driver VSC8234_driver = { .shutdown = &genphy_shutdown, }; +static struct phy_driver VSC8574_driver = { + .name = "Vitesse VSC8574", + .uid = 0x704a0, + .mask = 0xffff0, + .features = PHY_GBIT_FEATURES, + .config = &vsc8574_config, + .startup = &vitesse_startup, + .shutdown = &genphy_shutdown, +}; + static struct phy_driver VSC8601_driver = { .name = "Vitesse VSC8601", .uid = 0x70420, @@ -244,6 +310,7 @@ int phy_vitesse_init(void) phy_register(&VSC8244_driver); phy_register(&VSC8211_driver); phy_register(&VSC8221_driver); + phy_register(&VSC8574_driver); phy_register(&VSC8662_driver); phy_register(&cis8201_driver); phy_register(&cis8204_driver); |