diff options
Diffstat (limited to 'drivers/net/phy')
-rw-r--r-- | drivers/net/phy/Makefile | 1 | ||||
-rw-r--r-- | drivers/net/phy/atheros.c | 45 | ||||
-rw-r--r-- | drivers/net/phy/icplus.c | 94 | ||||
-rw-r--r-- | drivers/net/phy/marvell.c | 48 | ||||
-rw-r--r-- | drivers/net/phy/micrel.c | 113 | ||||
-rw-r--r-- | drivers/net/phy/natsemi.c | 37 | ||||
-rw-r--r-- | drivers/net/phy/phy.c | 26 |
7 files changed, 335 insertions, 29 deletions
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index af5f4b848c..695873eaa4 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -35,6 +35,7 @@ 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_ICPLUS) += icplus.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/atheros.c b/drivers/net/phy/atheros.c index 9b3808bfa9..09d487971f 100644 --- a/drivers/net/phy/atheros.c +++ b/drivers/net/phy/atheros.c @@ -16,7 +16,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA * - * Copyright 2011 Freescale Semiconductor, Inc. + * Copyright 2011, 2013 Freescale Semiconductor, Inc. * author Andy Fleming * */ @@ -30,6 +30,27 @@ static int ar8021_config(struct phy_device *phydev) return 0; } +static int ar8035_config(struct phy_device *phydev) +{ + int regval; + + phy_write(phydev, MDIO_DEVAD_NONE, 0xd, 0x0007); + phy_write(phydev, MDIO_DEVAD_NONE, 0xe, 0x8016); + phy_write(phydev, MDIO_DEVAD_NONE, 0xd, 0x4007); + regval = phy_read(phydev, MDIO_DEVAD_NONE, 0xe); + phy_write(phydev, MDIO_DEVAD_NONE, 0xe, (regval|0x0018)); + + phy_write(phydev, MDIO_DEVAD_NONE, 0x1d, 0x05); + regval = phy_read(phydev, MDIO_DEVAD_NONE, 0x1e); + phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, (regval|0x0100)); + + genphy_config_aneg(phydev); + + phy_reset(phydev); + + return 0; +} + static struct phy_driver AR8021_driver = { .name = "AR8021", .uid = 0x4dd040, @@ -40,9 +61,31 @@ static struct phy_driver AR8021_driver = { .shutdown = genphy_shutdown, }; +static struct phy_driver AR8031_driver = { + .name = "AR8031", + .uid = 0x4dd074, + .mask = 0xfffff0, + .features = PHY_GBIT_FEATURES, + .config = genphy_config, + .startup = genphy_startup, + .shutdown = genphy_shutdown, +}; + +static struct phy_driver AR8035_driver = { + .name = "AR8035", + .uid = 0x4dd072, + .mask = 0x4fffff, + .features = PHY_GBIT_FEATURES, + .config = ar8035_config, + .startup = genphy_startup, + .shutdown = genphy_shutdown, +}; + int phy_atheros_init(void) { phy_register(&AR8021_driver); + phy_register(&AR8031_driver); + phy_register(&AR8035_driver); return 0; } diff --git a/drivers/net/phy/icplus.c b/drivers/net/phy/icplus.c new file mode 100644 index 0000000000..dd5c59259d --- /dev/null +++ b/drivers/net/phy/icplus.c @@ -0,0 +1,94 @@ +/* + * ICPlus PHY drivers + * + * 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 + * + * Copyright (c) 2007 Freescale Semiconductor, Inc. + * + */ +#include <phy.h> + +/* IP101A/G - IP1001 */ +#define IP10XX_SPEC_CTRL_STATUS 16 /* Spec. Control Register */ +#define IP1001_SPEC_CTRL_STATUS_2 20 /* IP1001 Spec. Control Reg 2 */ +#define IP1001_PHASE_SEL_MASK 3 /* IP1001 RX/TXPHASE_SEL */ +#define IP1001_APS_ON 11 /* IP1001 APS Mode bit */ +#define IP101A_G_APS_ON 2 /* IP101A/G APS Mode bit */ +#define IP101A_G_IRQ_CONF_STATUS 0x11 /* Conf Info IRQ & Status Reg */ +#define IP101A_G_IRQ_PIN_USED (1<<15) /* INTR pin used */ +#define IP101A_G_IRQ_DEFAULT IP101A_G_IRQ_PIN_USED + +static int ip1001_config(struct phy_device *phydev) +{ + int c; + + /* Enable Auto Power Saving mode */ + c = phy_read(phydev, MDIO_DEVAD_NONE, IP1001_SPEC_CTRL_STATUS_2); + if (c < 0) + return c; + c |= IP1001_APS_ON; + c = phy_write(phydev, MDIO_DEVAD_NONE, IP1001_SPEC_CTRL_STATUS_2, c); + if (c < 0) + return c; + + /* INTR pin used: speed/link/duplex will cause an interrupt */ + c = phy_write(phydev, MDIO_DEVAD_NONE, IP101A_G_IRQ_CONF_STATUS, + IP101A_G_IRQ_DEFAULT); + if (c < 0) + return c; + + if (phydev->interface == PHY_INTERFACE_MODE_RGMII) { + /* + * Additional delay (2ns) used to adjust RX clock phase + * at RGMII interface + */ + c = phy_read(phydev, MDIO_DEVAD_NONE, IP10XX_SPEC_CTRL_STATUS); + if (c < 0) + return c; + + c |= IP1001_PHASE_SEL_MASK; + c = phy_write(phydev, MDIO_DEVAD_NONE, IP10XX_SPEC_CTRL_STATUS, + c); + if (c < 0) + return c; + } + + return 0; +} + +static int ip1001_startup(struct phy_device *phydev) +{ + genphy_update_link(phydev); + genphy_parse_link(phydev); + + return 0; +} +static struct phy_driver IP1001_driver = { + .name = "ICPlus IP1001", + .uid = 0x02430d90, + .mask = 0x0ffffff0, + .features = PHY_GBIT_FEATURES, + .config = &ip1001_config, + .startup = &ip1001_startup, + .shutdown = &genphy_shutdown, +}; + +int phy_icplus_init(void) +{ + phy_register(&IP1001_driver); + + return 0; +} diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index 46801c7919..8397e32e1a 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -89,6 +89,12 @@ #define MIIM_88E1149_PHY_PAGE 29 +/* 88E1310 PHY defines */ +#define MIIM_88E1310_PHY_LED_CTRL 16 +#define MIIM_88E1310_PHY_IRQ_EN 18 +#define MIIM_88E1310_PHY_RGMII_CTRL 21 +#define MIIM_88E1310_PHY_PAGE 22 + /* Marvell 88E1011S */ static int m88e1011s_config(struct phy_device *phydev) { @@ -394,6 +400,37 @@ static int m88e1149_config(struct phy_device *phydev) return 0; } +/* Marvell 88E1310 */ +static int m88e1310_config(struct phy_device *phydev) +{ + u16 reg; + + /* LED link and activity */ + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_PAGE, 0x0003); + reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_LED_CTRL); + reg = (reg & ~0xf) | 0x1; + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_LED_CTRL, reg); + + /* Set LED2/INT to INT mode, low active */ + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_PAGE, 0x0003); + reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_IRQ_EN); + reg = (reg & 0x77ff) | 0x0880; + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_IRQ_EN, reg); + + /* Set RGMII delay */ + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_PAGE, 0x0002); + reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_RGMII_CTRL); + reg |= 0x0030; + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_RGMII_CTRL, reg); + + /* Ensure to return to page 0 */ + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_PAGE, 0x0000); + + genphy_config_aneg(phydev); + phy_reset(phydev); + + return 0; +} static struct phy_driver M88E1011S_driver = { .name = "Marvell 88E1011S", @@ -475,8 +512,19 @@ static struct phy_driver M88E1518_driver = { .shutdown = &genphy_shutdown, }; +static struct phy_driver M88E1310_driver = { + .name = "Marvell 88E1310", + .uid = 0x01410e90, + .mask = 0xffffff0, + .features = PHY_GBIT_FEATURES, + .config = &m88e1310_config, + .startup = &m88e1011s_startup, + .shutdown = &genphy_shutdown, +}; + int phy_marvell_init(void) { + phy_register(&M88E1310_driver); phy_register(&M88E1149S_driver); phy_register(&M88E1145_driver); phy_register(&M88E1121R_driver); diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c index 30f3264897..aa9cbcfffc 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c @@ -18,6 +18,7 @@ * * Copyright 2010-2011 Freescale Semiconductor, Inc. * author Andy Fleming + * (C) 2012 NetModule AG, David Andrey, added KSZ9031 * */ #include <config.h> @@ -52,16 +53,46 @@ static struct phy_driver KS8721_driver = { }; #endif + +/** + * KSZ9021 - KSZ9031 common + */ + +#define MII_KSZ90xx_PHY_CTL 0x1f +#define MIIM_KSZ90xx_PHYCTL_1000 (1 << 6) +#define MIIM_KSZ90xx_PHYCTL_100 (1 << 5) +#define MIIM_KSZ90xx_PHYCTL_10 (1 << 4) +#define MIIM_KSZ90xx_PHYCTL_DUPLEX (1 << 3) + +static int ksz90xx_startup(struct phy_device *phydev) +{ + unsigned phy_ctl; + genphy_update_link(phydev); + phy_ctl = phy_read(phydev, MDIO_DEVAD_NONE, MII_KSZ90xx_PHY_CTL); + + if (phy_ctl & MIIM_KSZ90xx_PHYCTL_DUPLEX) + phydev->duplex = DUPLEX_FULL; + else + phydev->duplex = DUPLEX_HALF; + + if (phy_ctl & MIIM_KSZ90xx_PHYCTL_1000) + phydev->speed = SPEED_1000; + else if (phy_ctl & MIIM_KSZ90xx_PHYCTL_100) + phydev->speed = SPEED_100; + else if (phy_ctl & MIIM_KSZ90xx_PHYCTL_10) + phydev->speed = SPEED_10; + return 0; +} #ifdef CONFIG_PHY_MICREL_KSZ9021 -/* ksz9021 PHY Registers */ + +/* + * 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) @@ -106,37 +137,64 @@ static int ksz9021_config(struct phy_device *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, + .startup = &ksz90xx_startup, .shutdown = &genphy_shutdown, }; #endif +/** + * KSZ9031 + */ +/* PHY Registers */ +#define MII_KSZ9031_MMD_ACCES_CTRL 0x0d +#define MII_KSZ9031_MMD_REG_DATA 0x0e + +/* Accessors to extended registers*/ +int ksz9031_phy_extended_write(struct phy_device *phydev, + int devaddr, int regnum, u16 mode, u16 val) +{ + /*select register addr for mmd*/ + phy_write(phydev, MDIO_DEVAD_NONE, + MII_KSZ9031_MMD_ACCES_CTRL, devaddr); + /*select register for mmd*/ + phy_write(phydev, MDIO_DEVAD_NONE, + MII_KSZ9031_MMD_REG_DATA, regnum); + /*setup mode*/ + phy_write(phydev, MDIO_DEVAD_NONE, + MII_KSZ9031_MMD_ACCES_CTRL, (mode | devaddr)); + /*write the value*/ + return phy_write(phydev, MDIO_DEVAD_NONE, + MII_KSZ9031_MMD_REG_DATA, val); +} + +int ksz9031_phy_extended_read(struct phy_device *phydev, int devaddr, + int regnum, u16 mode) +{ + phy_write(phydev, MDIO_DEVAD_NONE, + MII_KSZ9031_MMD_ACCES_CTRL, devaddr); + phy_write(phydev, MDIO_DEVAD_NONE, + MII_KSZ9031_MMD_REG_DATA, regnum); + phy_write(phydev, MDIO_DEVAD_NONE, + MII_KSZ9031_MMD_ACCES_CTRL, (devaddr | mode)); + return phy_read(phydev, MDIO_DEVAD_NONE, MII_KSZ9031_MMD_REG_DATA); +} + +static struct phy_driver ksz9031_driver = { + .name = "Micrel ksz9031", + .uid = 0x221620, + .mask = 0xfffffe, + .features = PHY_GBIT_FEATURES, + .config = &genphy_config, + .startup = &ksz90xx_startup, + .shutdown = &genphy_shutdown, +}; + int phy_micrel_init(void) { phy_register(&KSZ804_driver); @@ -145,5 +203,6 @@ int phy_micrel_init(void) #else phy_register(&KS8721_driver); #endif + phy_register(&ksz9031_driver); return 0; } diff --git a/drivers/net/phy/natsemi.c b/drivers/net/phy/natsemi.c index ea60ac1b0e..6dc7ed5059 100644 --- a/drivers/net/phy/natsemi.c +++ b/drivers/net/phy/natsemi.c @@ -22,6 +22,42 @@ */ #include <phy.h> +/* NatSemi DP83630 */ + +#define DP83630_PHY_PAGESEL_REG 0x13 +#define DP83630_PHY_PTP_COC_REG 0x14 +#define DP83630_PHY_PTP_CLKOUT_EN (1<<15) +#define DP83630_PHY_RBR_REG 0x17 + +static int dp83630_config(struct phy_device *phydev) +{ + int ptp_coc_reg; + + phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET); + phy_write(phydev, MDIO_DEVAD_NONE, DP83630_PHY_PAGESEL_REG, 0x6); + ptp_coc_reg = phy_read(phydev, MDIO_DEVAD_NONE, + DP83630_PHY_PTP_COC_REG); + ptp_coc_reg &= ~DP83630_PHY_PTP_CLKOUT_EN; + phy_write(phydev, MDIO_DEVAD_NONE, DP83630_PHY_PTP_COC_REG, + ptp_coc_reg); + phy_write(phydev, MDIO_DEVAD_NONE, DP83630_PHY_PAGESEL_REG, 0); + + genphy_config_aneg(phydev); + + return 0; +} + +static struct phy_driver DP83630_driver = { + .name = "NatSemi DP83630", + .uid = 0x20005ce1, + .mask = 0xfffffff0, + .features = PHY_BASIC_FEATURES, + .config = &dp83630_config, + .startup = &genphy_startup, + .shutdown = &genphy_shutdown, +}; + + /* DP83865 Link and Auto-Neg Status Register */ #define MIIM_DP83865_LANR 0x11 #define MIIM_DP83865_SPD_MASK 0x0018 @@ -90,6 +126,7 @@ static struct phy_driver DP83865_driver = { int phy_natsemi_init(void) { + phy_register(&DP83630_driver); phy_register(&DP83865_driver); return 0; diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index f8c5481477..7c0eaec513 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -75,6 +75,10 @@ static int genphy_config_advert(struct phy_device *phydev) adv |= ADVERTISE_PAUSE_CAP; if (advertise & ADVERTISED_Asym_Pause) adv |= ADVERTISE_PAUSE_ASYM; + if (advertise & ADVERTISED_1000baseX_Half) + adv |= ADVERTISE_1000XHALF; + if (advertise & ADVERTISED_1000baseX_Full) + adv |= ADVERTISE_1000XFULL; if (adv != oldadv) { err = phy_write(phydev, MDIO_DEVAD_NONE, MII_ADVERTISE, adv); @@ -280,7 +284,7 @@ int genphy_update_link(struct phy_device *phydev) * * Stolen from Linux's mii.c and phy_device.c */ -static int genphy_parse_link(struct phy_device *phydev) +int genphy_parse_link(struct phy_device *phydev) { int mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR); @@ -288,6 +292,7 @@ static int genphy_parse_link(struct phy_device *phydev) if (mii_reg & BMSR_ANEGCAPABLE) { u32 lpa = 0; u32 gblpa = 0; + u32 estatus = 0; /* Check for gigabit capability */ if (mii_reg & BMSR_ERCAP) { @@ -327,6 +332,18 @@ static int genphy_parse_link(struct phy_device *phydev) } else if (lpa & LPA_10FULL) phydev->duplex = DUPLEX_FULL; + + if (mii_reg & BMSR_ESTATEN) + estatus = phy_read(phydev, MDIO_DEVAD_NONE, + MII_ESTATUS); + + if (estatus & (ESTATUS_1000_XFULL | ESTATUS_1000_XHALF | + ESTATUS_1000_TFULL | ESTATUS_1000_THALF)) { + phydev->speed = SPEED_1000; + if (estatus & (ESTATUS_1000_XFULL | ESTATUS_1000_TFULL)) + phydev->duplex = DUPLEX_FULL; + } + } else { u32 bmcr = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR); @@ -384,6 +401,10 @@ int genphy_config(struct phy_device *phydev) features |= SUPPORTED_1000baseT_Full; if (val & ESTATUS_1000_THALF) features |= SUPPORTED_1000baseT_Half; + if (val & ESTATUS_1000_XFULL) + features |= SUPPORTED_1000baseX_Full; + if (val & ESTATUS_1000_XHALF) + features |= SUPPORTED_1000baseX_Full; } phydev->supported = features; @@ -433,6 +454,9 @@ int phy_init(void) #ifdef CONFIG_PHY_ET1011C phy_et1011c_init(); #endif +#ifdef CONFIG_PHY_ICPLUS + phy_icplus_init(); +#endif #ifdef CONFIG_PHY_LXT phy_lxt_init(); #endif |