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); |