diff options
| author | Madalin Bucur <madalin.bucur@freescale.com> | 2013-11-20 17:38:19 -0500 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2013-11-20 22:09:19 -0500 |
| commit | 3fb69bcadda6263b92dbf8dd74717cba27c77ed9 (patch) | |
| tree | 63c40467c4237dbf3f402d97df9a2be5aba62b8d | |
| parent | 06ae4f848fe69ebd3c3a00d2ecbb8af22fb75418 (diff) | |
net/phy: Add the autocross feature for forced links on VSC82x4
Add auto-MDI/MDI-X capability for forced (autonegotiation disabled)
10/100 Mbps speeds on Vitesse VSC82x4 PHYs. Exported previously static
function genphy_setup_forced() required by the new config_aneg handler
in the Vitesse PHY module.
Signed-off-by: Madalin Bucur <madalin.bucur@freescale.com>
Signed-off-by: Shruti Kanetkar <Shruti@freescale.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
| -rw-r--r-- | drivers/net/phy/phy_device.c | 4 | ||||
| -rw-r--r-- | drivers/net/phy/vitesse.c | 75 | ||||
| -rw-r--r-- | include/linux/phy.h | 1 |
3 files changed, 73 insertions, 7 deletions
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 74630e94fa3b..d6447b3f7409 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c | |||
| @@ -697,7 +697,7 @@ static int genphy_config_advert(struct phy_device *phydev) | |||
| 697 | * to the values in phydev. Assumes that the values are valid. | 697 | * to the values in phydev. Assumes that the values are valid. |
| 698 | * Please see phy_sanitize_settings(). | 698 | * Please see phy_sanitize_settings(). |
| 699 | */ | 699 | */ |
| 700 | static int genphy_setup_forced(struct phy_device *phydev) | 700 | int genphy_setup_forced(struct phy_device *phydev) |
| 701 | { | 701 | { |
| 702 | int err; | 702 | int err; |
| 703 | int ctl = 0; | 703 | int ctl = 0; |
| @@ -716,7 +716,7 @@ static int genphy_setup_forced(struct phy_device *phydev) | |||
| 716 | 716 | ||
| 717 | return err; | 717 | return err; |
| 718 | } | 718 | } |
| 719 | 719 | EXPORT_SYMBOL(genphy_setup_forced); | |
| 720 | 720 | ||
| 721 | /** | 721 | /** |
| 722 | * genphy_restart_aneg - Enable and Restart Autonegotiation | 722 | * genphy_restart_aneg - Enable and Restart Autonegotiation |
diff --git a/drivers/net/phy/vitesse.c b/drivers/net/phy/vitesse.c index 40406bc2f8af..508e4359338b 100644 --- a/drivers/net/phy/vitesse.c +++ b/drivers/net/phy/vitesse.c | |||
| @@ -3,7 +3,7 @@ | |||
| 3 | * | 3 | * |
| 4 | * Author: Kriston Carson | 4 | * Author: Kriston Carson |
| 5 | * | 5 | * |
| 6 | * Copyright (c) 2005, 2009 Freescale Semiconductor, Inc. | 6 | * Copyright (c) 2005, 2009, 2011 Freescale Semiconductor, Inc. |
| 7 | * | 7 | * |
| 8 | * This program is free software; you can redistribute it and/or modify it | 8 | * This program is free software; you can redistribute it and/or modify it |
| 9 | * under the terms of the GNU General Public License as published by the | 9 | * under the terms of the GNU General Public License as published by the |
| @@ -18,6 +18,11 @@ | |||
| 18 | #include <linux/ethtool.h> | 18 | #include <linux/ethtool.h> |
| 19 | #include <linux/phy.h> | 19 | #include <linux/phy.h> |
| 20 | 20 | ||
| 21 | /* Vitesse Extended Page Magic Register(s) */ | ||
| 22 | #define MII_VSC82X4_EXT_PAGE_16E 0x10 | ||
| 23 | #define MII_VSC82X4_EXT_PAGE_17E 0x11 | ||
| 24 | #define MII_VSC82X4_EXT_PAGE_18E 0x12 | ||
| 25 | |||
| 21 | /* Vitesse Extended Control Register 1 */ | 26 | /* Vitesse Extended Control Register 1 */ |
| 22 | #define MII_VSC8244_EXT_CON1 0x17 | 27 | #define MII_VSC8244_EXT_CON1 0x17 |
| 23 | #define MII_VSC8244_EXTCON1_INIT 0x0000 | 28 | #define MII_VSC8244_EXTCON1_INIT 0x0000 |
| @@ -54,6 +59,9 @@ | |||
| 54 | #define MII_VSC8221_AUXCONSTAT_INIT 0x0004 /* need to set this bit? */ | 59 | #define MII_VSC8221_AUXCONSTAT_INIT 0x0004 /* need to set this bit? */ |
| 55 | #define MII_VSC8221_AUXCONSTAT_RESERVED 0x0004 | 60 | #define MII_VSC8221_AUXCONSTAT_RESERVED 0x0004 |
| 56 | 61 | ||
| 62 | /* Vitesse Extended Page Access Register */ | ||
| 63 | #define MII_VSC82X4_EXT_PAGE_ACCESS 0x1f | ||
| 64 | |||
| 57 | #define PHY_ID_VSC8234 0x000fc620 | 65 | #define PHY_ID_VSC8234 0x000fc620 |
| 58 | #define PHY_ID_VSC8244 0x000fc6c0 | 66 | #define PHY_ID_VSC8244 0x000fc6c0 |
| 59 | #define PHY_ID_VSC8574 0x000704a0 | 67 | #define PHY_ID_VSC8574 0x000704a0 |
| @@ -154,6 +162,63 @@ static int vsc8221_config_init(struct phy_device *phydev) | |||
| 154 | */ | 162 | */ |
| 155 | } | 163 | } |
| 156 | 164 | ||
| 165 | /* vsc82x4_config_autocross_enable - Enable auto MDI/MDI-X for forced links | ||
| 166 | * @phydev: target phy_device struct | ||
| 167 | * | ||
| 168 | * Enable auto MDI/MDI-X when in 10/100 forced link speeds by writing | ||
| 169 | * special values in the VSC8234/VSC8244 extended reserved registers | ||
| 170 | */ | ||
| 171 | static int vsc82x4_config_autocross_enable(struct phy_device *phydev) | ||
| 172 | { | ||
| 173 | int ret; | ||
| 174 | |||
| 175 | if (phydev->autoneg == AUTONEG_ENABLE || phydev->speed > SPEED_100) | ||
| 176 | return 0; | ||
| 177 | |||
| 178 | /* map extended registers set 0x10 - 0x1e */ | ||
| 179 | ret = phy_write(phydev, MII_VSC82X4_EXT_PAGE_ACCESS, 0x52b5); | ||
| 180 | if (ret >= 0) | ||
| 181 | ret = phy_write(phydev, MII_VSC82X4_EXT_PAGE_18E, 0x0012); | ||
| 182 | if (ret >= 0) | ||
| 183 | ret = phy_write(phydev, MII_VSC82X4_EXT_PAGE_17E, 0x2803); | ||
| 184 | if (ret >= 0) | ||
| 185 | ret = phy_write(phydev, MII_VSC82X4_EXT_PAGE_16E, 0x87fa); | ||
| 186 | /* map standard registers set 0x10 - 0x1e */ | ||
| 187 | if (ret >= 0) | ||
| 188 | ret = phy_write(phydev, MII_VSC82X4_EXT_PAGE_ACCESS, 0x0000); | ||
| 189 | else | ||
| 190 | phy_write(phydev, MII_VSC82X4_EXT_PAGE_ACCESS, 0x0000); | ||
| 191 | |||
| 192 | return ret; | ||
| 193 | } | ||
| 194 | |||
| 195 | /* vsc82x4_config_aneg - restart auto-negotiation or write BMCR | ||
| 196 | * @phydev: target phy_device struct | ||
| 197 | * | ||
| 198 | * Description: If auto-negotiation is enabled, we configure the | ||
| 199 | * advertising, and then restart auto-negotiation. If it is not | ||
| 200 | * enabled, then we write the BMCR and also start the auto | ||
| 201 | * MDI/MDI-X feature | ||
| 202 | */ | ||
| 203 | static int vsc82x4_config_aneg(struct phy_device *phydev) | ||
| 204 | { | ||
| 205 | int ret; | ||
| 206 | |||
| 207 | /* Enable auto MDI/MDI-X when in 10/100 forced link speeds by | ||
| 208 | * writing special values in the VSC8234 extended reserved registers | ||
| 209 | */ | ||
| 210 | if (phydev->autoneg != AUTONEG_ENABLE && phydev->speed <= SPEED_100) { | ||
| 211 | ret = genphy_setup_forced(phydev); | ||
| 212 | |||
| 213 | if (ret < 0) /* error */ | ||
| 214 | return ret; | ||
| 215 | |||
| 216 | return vsc82x4_config_autocross_enable(phydev); | ||
| 217 | } | ||
| 218 | |||
| 219 | return genphy_config_aneg(phydev); | ||
| 220 | } | ||
| 221 | |||
| 157 | /* Vitesse 82xx */ | 222 | /* Vitesse 82xx */ |
| 158 | static struct phy_driver vsc82xx_driver[] = { | 223 | static struct phy_driver vsc82xx_driver[] = { |
| 159 | { | 224 | { |
| @@ -163,7 +228,7 @@ static struct phy_driver vsc82xx_driver[] = { | |||
| 163 | .features = PHY_GBIT_FEATURES, | 228 | .features = PHY_GBIT_FEATURES, |
| 164 | .flags = PHY_HAS_INTERRUPT, | 229 | .flags = PHY_HAS_INTERRUPT, |
| 165 | .config_init = &vsc824x_config_init, | 230 | .config_init = &vsc824x_config_init, |
| 166 | .config_aneg = &genphy_config_aneg, | 231 | .config_aneg = &vsc82x4_config_aneg, |
| 167 | .read_status = &genphy_read_status, | 232 | .read_status = &genphy_read_status, |
| 168 | .ack_interrupt = &vsc824x_ack_interrupt, | 233 | .ack_interrupt = &vsc824x_ack_interrupt, |
| 169 | .config_intr = &vsc82xx_config_intr, | 234 | .config_intr = &vsc82xx_config_intr, |
| @@ -175,7 +240,7 @@ static struct phy_driver vsc82xx_driver[] = { | |||
| 175 | .features = PHY_GBIT_FEATURES, | 240 | .features = PHY_GBIT_FEATURES, |
| 176 | .flags = PHY_HAS_INTERRUPT, | 241 | .flags = PHY_HAS_INTERRUPT, |
| 177 | .config_init = &vsc824x_config_init, | 242 | .config_init = &vsc824x_config_init, |
| 178 | .config_aneg = &genphy_config_aneg, | 243 | .config_aneg = &vsc82x4_config_aneg, |
| 179 | .read_status = &genphy_read_status, | 244 | .read_status = &genphy_read_status, |
| 180 | .ack_interrupt = &vsc824x_ack_interrupt, | 245 | .ack_interrupt = &vsc824x_ack_interrupt, |
| 181 | .config_intr = &vsc82xx_config_intr, | 246 | .config_intr = &vsc82xx_config_intr, |
| @@ -187,7 +252,7 @@ static struct phy_driver vsc82xx_driver[] = { | |||
| 187 | .features = PHY_GBIT_FEATURES, | 252 | .features = PHY_GBIT_FEATURES, |
| 188 | .flags = PHY_HAS_INTERRUPT, | 253 | .flags = PHY_HAS_INTERRUPT, |
| 189 | .config_init = &vsc824x_config_init, | 254 | .config_init = &vsc824x_config_init, |
| 190 | .config_aneg = &genphy_config_aneg, | 255 | .config_aneg = &vsc82x4_config_aneg, |
| 191 | .read_status = &genphy_read_status, | 256 | .read_status = &genphy_read_status, |
| 192 | .ack_interrupt = &vsc824x_ack_interrupt, | 257 | .ack_interrupt = &vsc824x_ack_interrupt, |
| 193 | .config_intr = &vsc82xx_config_intr, | 258 | .config_intr = &vsc82xx_config_intr, |
| @@ -199,7 +264,7 @@ static struct phy_driver vsc82xx_driver[] = { | |||
| 199 | .features = PHY_GBIT_FEATURES, | 264 | .features = PHY_GBIT_FEATURES, |
| 200 | .flags = PHY_HAS_INTERRUPT, | 265 | .flags = PHY_HAS_INTERRUPT, |
| 201 | .config_init = &vsc824x_config_init, | 266 | .config_init = &vsc824x_config_init, |
| 202 | .config_aneg = &genphy_config_aneg, | 267 | .config_aneg = &vsc82x4_config_aneg, |
| 203 | .read_status = &genphy_read_status, | 268 | .read_status = &genphy_read_status, |
| 204 | .ack_interrupt = &vsc824x_ack_interrupt, | 269 | .ack_interrupt = &vsc824x_ack_interrupt, |
| 205 | .config_intr = &vsc82xx_config_intr, | 270 | .config_intr = &vsc82xx_config_intr, |
diff --git a/include/linux/phy.h b/include/linux/phy.h index 64ab823f7b74..48a4dc3cb8cf 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h | |||
| @@ -559,6 +559,7 @@ static inline int phy_read_status(struct phy_device *phydev) { | |||
| 559 | return phydev->drv->read_status(phydev); | 559 | return phydev->drv->read_status(phydev); |
| 560 | } | 560 | } |
| 561 | 561 | ||
| 562 | int genphy_setup_forced(struct phy_device *phydev); | ||
| 562 | int genphy_restart_aneg(struct phy_device *phydev); | 563 | int genphy_restart_aneg(struct phy_device *phydev); |
| 563 | int genphy_config_aneg(struct phy_device *phydev); | 564 | int genphy_config_aneg(struct phy_device *phydev); |
| 564 | int genphy_update_link(struct phy_device *phydev); | 565 | int genphy_update_link(struct phy_device *phydev); |
