diff options
Diffstat (limited to 'drivers/net/phy')
-rw-r--r-- | drivers/net/phy/Kconfig | 6 | ||||
-rw-r--r-- | drivers/net/phy/Makefile | 1 | ||||
-rw-r--r-- | drivers/net/phy/bcm7xxx.c | 343 | ||||
-rw-r--r-- | drivers/net/phy/broadcom.c | 52 | ||||
-rw-r--r-- | drivers/net/phy/mdio_bus.c | 20 | ||||
-rw-r--r-- | drivers/net/phy/micrel.c | 49 | ||||
-rw-r--r-- | drivers/net/phy/phy.c | 51 | ||||
-rw-r--r-- | drivers/net/phy/phy_device.c | 57 |
8 files changed, 505 insertions, 74 deletions
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index 9b5d46c03eed..6a17f92153b3 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig | |||
@@ -71,6 +71,12 @@ config BCM63XX_PHY | |||
71 | ---help--- | 71 | ---help--- |
72 | Currently supports the 6348 and 6358 PHYs. | 72 | Currently supports the 6348 and 6358 PHYs. |
73 | 73 | ||
74 | config BCM7XXX_PHY | ||
75 | tristate "Drivers for Broadcom 7xxx SOCs internal PHYs" | ||
76 | ---help--- | ||
77 | Currently supports the BCM7366, BCM7439, BCM7445, and | ||
78 | 40nm and 65nm generation of BCM7xxx Set Top Box SoCs. | ||
79 | |||
74 | config BCM87XX_PHY | 80 | config BCM87XX_PHY |
75 | tristate "Driver for Broadcom BCM8706 and BCM8727 PHYs" | 81 | tristate "Driver for Broadcom BCM8706 and BCM8727 PHYs" |
76 | help | 82 | help |
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index 9013dfa12aa3..07d24024863e 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile | |||
@@ -12,6 +12,7 @@ obj-$(CONFIG_SMSC_PHY) += smsc.o | |||
12 | obj-$(CONFIG_VITESSE_PHY) += vitesse.o | 12 | obj-$(CONFIG_VITESSE_PHY) += vitesse.o |
13 | obj-$(CONFIG_BROADCOM_PHY) += broadcom.o | 13 | obj-$(CONFIG_BROADCOM_PHY) += broadcom.o |
14 | obj-$(CONFIG_BCM63XX_PHY) += bcm63xx.o | 14 | obj-$(CONFIG_BCM63XX_PHY) += bcm63xx.o |
15 | obj-$(CONFIG_BCM7XXX_PHY) += bcm7xxx.o | ||
15 | obj-$(CONFIG_BCM87XX_PHY) += bcm87xx.o | 16 | obj-$(CONFIG_BCM87XX_PHY) += bcm87xx.o |
16 | obj-$(CONFIG_ICPLUS_PHY) += icplus.o | 17 | obj-$(CONFIG_ICPLUS_PHY) += icplus.o |
17 | obj-$(CONFIG_REALTEK_PHY) += realtek.o | 18 | obj-$(CONFIG_REALTEK_PHY) += realtek.o |
diff --git a/drivers/net/phy/bcm7xxx.c b/drivers/net/phy/bcm7xxx.c new file mode 100644 index 000000000000..697337220016 --- /dev/null +++ b/drivers/net/phy/bcm7xxx.c | |||
@@ -0,0 +1,343 @@ | |||
1 | /* | ||
2 | * Broadcom BCM7xxx internal transceivers support. | ||
3 | * | ||
4 | * Copyright (C) 2014, Broadcom Corporation | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License | ||
8 | * as published by the Free Software Foundation; either version | ||
9 | * 2 of the License, or (at your option) any later version. | ||
10 | */ | ||
11 | |||
12 | #include <linux/module.h> | ||
13 | #include <linux/phy.h> | ||
14 | #include <linux/delay.h> | ||
15 | #include <linux/bitops.h> | ||
16 | #include <linux/brcmphy.h> | ||
17 | |||
18 | /* Broadcom BCM7xxx internal PHY registers */ | ||
19 | #define MII_BCM7XXX_CHANNEL_WIDTH 0x2000 | ||
20 | |||
21 | /* 40nm only register definitions */ | ||
22 | #define MII_BCM7XXX_100TX_AUX_CTL 0x10 | ||
23 | #define MII_BCM7XXX_100TX_FALSE_CAR 0x13 | ||
24 | #define MII_BCM7XXX_100TX_DISC 0x14 | ||
25 | #define MII_BCM7XXX_AUX_MODE 0x1d | ||
26 | #define MII_BCM7XX_64CLK_MDIO BIT(12) | ||
27 | #define MII_BCM7XXX_CORE_BASE1E 0x1e | ||
28 | #define MII_BCM7XXX_TEST 0x1f | ||
29 | #define MII_BCM7XXX_SHD_MODE_2 BIT(2) | ||
30 | |||
31 | static int bcm7445_config_init(struct phy_device *phydev) | ||
32 | { | ||
33 | int ret; | ||
34 | const struct bcm7445_regs { | ||
35 | int reg; | ||
36 | u16 value; | ||
37 | } bcm7445_regs_cfg[] = { | ||
38 | /* increases ADC latency by 24ns */ | ||
39 | { MII_BCM54XX_EXP_SEL, 0x0038 }, | ||
40 | { MII_BCM54XX_EXP_DATA, 0xAB95 }, | ||
41 | /* increases internal 1V LDO voltage by 5% */ | ||
42 | { MII_BCM54XX_EXP_SEL, 0x2038 }, | ||
43 | { MII_BCM54XX_EXP_DATA, 0xBB22 }, | ||
44 | /* reduce RX low pass filter corner frequency */ | ||
45 | { MII_BCM54XX_EXP_SEL, 0x6038 }, | ||
46 | { MII_BCM54XX_EXP_DATA, 0xFFC5 }, | ||
47 | /* reduce RX high pass filter corner frequency */ | ||
48 | { MII_BCM54XX_EXP_SEL, 0x003a }, | ||
49 | { MII_BCM54XX_EXP_DATA, 0x2002 }, | ||
50 | }; | ||
51 | unsigned int i; | ||
52 | |||
53 | for (i = 0; i < ARRAY_SIZE(bcm7445_regs_cfg); i++) { | ||
54 | ret = phy_write(phydev, | ||
55 | bcm7445_regs_cfg[i].reg, | ||
56 | bcm7445_regs_cfg[i].value); | ||
57 | if (ret) | ||
58 | return ret; | ||
59 | } | ||
60 | |||
61 | return 0; | ||
62 | } | ||
63 | |||
64 | static void phy_write_exp(struct phy_device *phydev, | ||
65 | u16 reg, u16 value) | ||
66 | { | ||
67 | phy_write(phydev, MII_BCM54XX_EXP_SEL, MII_BCM54XX_EXP_SEL_ER | reg); | ||
68 | phy_write(phydev, MII_BCM54XX_EXP_DATA, value); | ||
69 | } | ||
70 | |||
71 | static void phy_write_misc(struct phy_device *phydev, | ||
72 | u16 reg, u16 chl, u16 value) | ||
73 | { | ||
74 | int tmp; | ||
75 | |||
76 | phy_write(phydev, MII_BCM54XX_AUX_CTL, MII_BCM54XX_AUXCTL_SHDWSEL_MISC); | ||
77 | |||
78 | tmp = phy_read(phydev, MII_BCM54XX_AUX_CTL); | ||
79 | tmp |= MII_BCM54XX_AUXCTL_ACTL_SMDSP_ENA; | ||
80 | phy_write(phydev, MII_BCM54XX_AUX_CTL, tmp); | ||
81 | |||
82 | tmp = (chl * MII_BCM7XXX_CHANNEL_WIDTH) | reg; | ||
83 | phy_write(phydev, MII_BCM54XX_EXP_SEL, tmp); | ||
84 | |||
85 | phy_write(phydev, MII_BCM54XX_EXP_DATA, value); | ||
86 | } | ||
87 | |||
88 | static int bcm7xxx_28nm_afe_config_init(struct phy_device *phydev) | ||
89 | { | ||
90 | /* write AFE_RXCONFIG_0 */ | ||
91 | phy_write_misc(phydev, 0x38, 0x0000, 0xeb19); | ||
92 | |||
93 | /* write AFE_RXCONFIG_1 */ | ||
94 | phy_write_misc(phydev, 0x38, 0x0001, 0x9a3f); | ||
95 | |||
96 | /* write AFE_RX_LP_COUNTER */ | ||
97 | phy_write_misc(phydev, 0x38, 0x0003, 0x7fc7); | ||
98 | |||
99 | /* write AFE_HPF_TRIM_OTHERS */ | ||
100 | phy_write_misc(phydev, 0x3A, 0x0000, 0x000b); | ||
101 | |||
102 | /* write AFTE_TX_CONFIG */ | ||
103 | phy_write_misc(phydev, 0x39, 0x0000, 0x0800); | ||
104 | |||
105 | /* Increase VCO range to prevent unlocking problem of PLL at low | ||
106 | * temp | ||
107 | */ | ||
108 | phy_write_misc(phydev, 0x0032, 0x0001, 0x0048); | ||
109 | |||
110 | /* Change Ki to 011 */ | ||
111 | phy_write_misc(phydev, 0x0032, 0x0002, 0x021b); | ||
112 | |||
113 | /* Disable loading of TVCO buffer to bandgap, set bandgap trim | ||
114 | * to 111 | ||
115 | */ | ||
116 | phy_write_misc(phydev, 0x0033, 0x0000, 0x0e20); | ||
117 | |||
118 | /* Adjust bias current trim by -3 */ | ||
119 | phy_write_misc(phydev, 0x000a, 0x0000, 0x690b); | ||
120 | |||
121 | /* Switch to CORE_BASE1E */ | ||
122 | phy_write(phydev, MII_BCM7XXX_CORE_BASE1E, 0xd); | ||
123 | |||
124 | /* Reset R_CAL/RC_CAL Engine */ | ||
125 | phy_write_exp(phydev, 0x00b0, 0x0010); | ||
126 | |||
127 | /* Disable Reset R_CAL/RC_CAL Engine */ | ||
128 | phy_write_exp(phydev, 0x00b0, 0x0000); | ||
129 | |||
130 | return 0; | ||
131 | } | ||
132 | |||
133 | static int bcm7xxx_28nm_config_init(struct phy_device *phydev) | ||
134 | { | ||
135 | int ret; | ||
136 | |||
137 | ret = bcm7445_config_init(phydev); | ||
138 | if (ret) | ||
139 | return ret; | ||
140 | |||
141 | return bcm7xxx_28nm_afe_config_init(phydev); | ||
142 | } | ||
143 | |||
144 | static int phy_set_clr_bits(struct phy_device *dev, int location, | ||
145 | int set_mask, int clr_mask) | ||
146 | { | ||
147 | int v, ret; | ||
148 | |||
149 | v = phy_read(dev, location); | ||
150 | if (v < 0) | ||
151 | return v; | ||
152 | |||
153 | v &= ~clr_mask; | ||
154 | v |= set_mask; | ||
155 | |||
156 | ret = phy_write(dev, location, v); | ||
157 | if (ret < 0) | ||
158 | return ret; | ||
159 | |||
160 | return v; | ||
161 | } | ||
162 | |||
163 | static int bcm7xxx_config_init(struct phy_device *phydev) | ||
164 | { | ||
165 | int ret; | ||
166 | |||
167 | /* Enable 64 clock MDIO */ | ||
168 | phy_write(phydev, MII_BCM7XXX_AUX_MODE, MII_BCM7XX_64CLK_MDIO); | ||
169 | phy_read(phydev, MII_BCM7XXX_AUX_MODE); | ||
170 | |||
171 | /* Workaround only required for 100Mbits/sec */ | ||
172 | if (!(phydev->dev_flags & PHY_BRCM_100MBPS_WAR)) | ||
173 | return 0; | ||
174 | |||
175 | /* set shadow mode 2 */ | ||
176 | ret = phy_set_clr_bits(phydev, MII_BCM7XXX_TEST, | ||
177 | MII_BCM7XXX_SHD_MODE_2, MII_BCM7XXX_SHD_MODE_2); | ||
178 | if (ret < 0) | ||
179 | return ret; | ||
180 | |||
181 | /* set iddq_clkbias */ | ||
182 | phy_write(phydev, MII_BCM7XXX_100TX_DISC, 0x0F00); | ||
183 | udelay(10); | ||
184 | |||
185 | /* reset iddq_clkbias */ | ||
186 | phy_write(phydev, MII_BCM7XXX_100TX_DISC, 0x0C00); | ||
187 | |||
188 | phy_write(phydev, MII_BCM7XXX_100TX_FALSE_CAR, 0x7555); | ||
189 | |||
190 | /* reset shadow mode 2 */ | ||
191 | ret = phy_set_clr_bits(phydev, MII_BCM7XXX_TEST, MII_BCM7XXX_SHD_MODE_2, 0); | ||
192 | if (ret < 0) | ||
193 | return ret; | ||
194 | |||
195 | return 0; | ||
196 | } | ||
197 | |||
198 | /* Workaround for putting the PHY in IDDQ mode, required | ||
199 | * for all BCM7XXX PHYs | ||
200 | */ | ||
201 | static int bcm7xxx_suspend(struct phy_device *phydev) | ||
202 | { | ||
203 | int ret; | ||
204 | const struct bcm7xxx_regs { | ||
205 | int reg; | ||
206 | u16 value; | ||
207 | } bcm7xxx_suspend_cfg[] = { | ||
208 | { MII_BCM7XXX_TEST, 0x008b }, | ||
209 | { MII_BCM7XXX_100TX_AUX_CTL, 0x01c0 }, | ||
210 | { MII_BCM7XXX_100TX_DISC, 0x7000 }, | ||
211 | { MII_BCM7XXX_TEST, 0x000f }, | ||
212 | { MII_BCM7XXX_100TX_AUX_CTL, 0x20d0 }, | ||
213 | { MII_BCM7XXX_TEST, 0x000b }, | ||
214 | }; | ||
215 | unsigned int i; | ||
216 | |||
217 | for (i = 0; i < ARRAY_SIZE(bcm7xxx_suspend_cfg); i++) { | ||
218 | ret = phy_write(phydev, | ||
219 | bcm7xxx_suspend_cfg[i].reg, | ||
220 | bcm7xxx_suspend_cfg[i].value); | ||
221 | if (ret) | ||
222 | return ret; | ||
223 | } | ||
224 | |||
225 | return 0; | ||
226 | } | ||
227 | |||
228 | static int bcm7xxx_dummy_config_init(struct phy_device *phydev) | ||
229 | { | ||
230 | return 0; | ||
231 | } | ||
232 | |||
233 | static struct phy_driver bcm7xxx_driver[] = { | ||
234 | { | ||
235 | .phy_id = PHY_ID_BCM7366, | ||
236 | .phy_id_mask = 0xfffffff0, | ||
237 | .name = "Broadcom BCM7366", | ||
238 | .features = PHY_GBIT_FEATURES | | ||
239 | SUPPORTED_Pause | SUPPORTED_Asym_Pause, | ||
240 | .flags = PHY_IS_INTERNAL, | ||
241 | .config_init = bcm7xxx_28nm_afe_config_init, | ||
242 | .config_aneg = genphy_config_aneg, | ||
243 | .read_status = genphy_read_status, | ||
244 | .suspend = bcm7xxx_suspend, | ||
245 | .resume = bcm7xxx_28nm_afe_config_init, | ||
246 | .driver = { .owner = THIS_MODULE }, | ||
247 | }, { | ||
248 | .phy_id = PHY_ID_BCM7439, | ||
249 | .phy_id_mask = 0xfffffff0, | ||
250 | .name = "Broadcom BCM7439", | ||
251 | .features = PHY_GBIT_FEATURES | | ||
252 | SUPPORTED_Pause | SUPPORTED_Asym_Pause, | ||
253 | .flags = PHY_IS_INTERNAL, | ||
254 | .config_init = bcm7xxx_28nm_afe_config_init, | ||
255 | .config_aneg = genphy_config_aneg, | ||
256 | .read_status = genphy_read_status, | ||
257 | .suspend = bcm7xxx_suspend, | ||
258 | .resume = bcm7xxx_28nm_afe_config_init, | ||
259 | .driver = { .owner = THIS_MODULE }, | ||
260 | }, { | ||
261 | .phy_id = PHY_ID_BCM7445, | ||
262 | .phy_id_mask = 0xfffffff0, | ||
263 | .name = "Broadcom BCM7445", | ||
264 | .features = PHY_GBIT_FEATURES | | ||
265 | SUPPORTED_Pause | SUPPORTED_Asym_Pause, | ||
266 | .flags = PHY_IS_INTERNAL, | ||
267 | .config_init = bcm7xxx_28nm_config_init, | ||
268 | .config_aneg = genphy_config_aneg, | ||
269 | .read_status = genphy_read_status, | ||
270 | .suspend = bcm7xxx_suspend, | ||
271 | .resume = bcm7xxx_28nm_config_init, | ||
272 | .driver = { .owner = THIS_MODULE }, | ||
273 | }, { | ||
274 | .name = "Broadcom BCM7XXX 28nm", | ||
275 | .phy_id = PHY_ID_BCM7XXX_28, | ||
276 | .phy_id_mask = PHY_BCM_OUI_MASK, | ||
277 | .features = PHY_GBIT_FEATURES | | ||
278 | SUPPORTED_Pause | SUPPORTED_Asym_Pause, | ||
279 | .flags = PHY_IS_INTERNAL, | ||
280 | .config_init = bcm7xxx_28nm_config_init, | ||
281 | .config_aneg = genphy_config_aneg, | ||
282 | .read_status = genphy_read_status, | ||
283 | .suspend = bcm7xxx_suspend, | ||
284 | .resume = bcm7xxx_28nm_config_init, | ||
285 | .driver = { .owner = THIS_MODULE }, | ||
286 | }, { | ||
287 | .phy_id = PHY_BCM_OUI_4, | ||
288 | .phy_id_mask = 0xffff0000, | ||
289 | .name = "Broadcom BCM7XXX 40nm", | ||
290 | .features = PHY_GBIT_FEATURES | | ||
291 | SUPPORTED_Pause | SUPPORTED_Asym_Pause, | ||
292 | .flags = PHY_IS_INTERNAL, | ||
293 | .config_init = bcm7xxx_config_init, | ||
294 | .config_aneg = genphy_config_aneg, | ||
295 | .read_status = genphy_read_status, | ||
296 | .suspend = bcm7xxx_suspend, | ||
297 | .resume = bcm7xxx_config_init, | ||
298 | .driver = { .owner = THIS_MODULE }, | ||
299 | }, { | ||
300 | .phy_id = PHY_BCM_OUI_5, | ||
301 | .phy_id_mask = 0xffffff00, | ||
302 | .name = "Broadcom BCM7XXX 65nm", | ||
303 | .features = PHY_BASIC_FEATURES | | ||
304 | SUPPORTED_Pause | SUPPORTED_Asym_Pause, | ||
305 | .flags = PHY_IS_INTERNAL, | ||
306 | .config_init = bcm7xxx_dummy_config_init, | ||
307 | .config_aneg = genphy_config_aneg, | ||
308 | .read_status = genphy_read_status, | ||
309 | .suspend = bcm7xxx_suspend, | ||
310 | .resume = bcm7xxx_config_init, | ||
311 | .driver = { .owner = THIS_MODULE }, | ||
312 | } }; | ||
313 | |||
314 | static struct mdio_device_id __maybe_unused bcm7xxx_tbl[] = { | ||
315 | { PHY_ID_BCM7366, 0xfffffff0, }, | ||
316 | { PHY_ID_BCM7439, 0xfffffff0, }, | ||
317 | { PHY_ID_BCM7445, 0xfffffff0, }, | ||
318 | { PHY_ID_BCM7XXX_28, 0xfffffc00 }, | ||
319 | { PHY_BCM_OUI_4, 0xffff0000 }, | ||
320 | { PHY_BCM_OUI_5, 0xffffff00 }, | ||
321 | { } | ||
322 | }; | ||
323 | |||
324 | static int __init bcm7xxx_phy_init(void) | ||
325 | { | ||
326 | return phy_drivers_register(bcm7xxx_driver, | ||
327 | ARRAY_SIZE(bcm7xxx_driver)); | ||
328 | } | ||
329 | |||
330 | static void __exit bcm7xxx_phy_exit(void) | ||
331 | { | ||
332 | phy_drivers_unregister(bcm7xxx_driver, | ||
333 | ARRAY_SIZE(bcm7xxx_driver)); | ||
334 | } | ||
335 | |||
336 | module_init(bcm7xxx_phy_init); | ||
337 | module_exit(bcm7xxx_phy_exit); | ||
338 | |||
339 | MODULE_DEVICE_TABLE(mdio, bcm7xxx_tbl); | ||
340 | |||
341 | MODULE_DESCRIPTION("Broadcom BCM7xxx internal PHY driver"); | ||
342 | MODULE_LICENSE("GPL"); | ||
343 | MODULE_AUTHOR("Broadcom Corporation"); | ||
diff --git a/drivers/net/phy/broadcom.c b/drivers/net/phy/broadcom.c index f8c90ea75108..34088d60da74 100644 --- a/drivers/net/phy/broadcom.c +++ b/drivers/net/phy/broadcom.c | |||
@@ -25,58 +25,6 @@ | |||
25 | #define BRCM_PHY_REV(phydev) \ | 25 | #define BRCM_PHY_REV(phydev) \ |
26 | ((phydev)->drv->phy_id & ~((phydev)->drv->phy_id_mask)) | 26 | ((phydev)->drv->phy_id & ~((phydev)->drv->phy_id_mask)) |
27 | 27 | ||
28 | |||
29 | #define MII_BCM54XX_ECR 0x10 /* BCM54xx extended control register */ | ||
30 | #define MII_BCM54XX_ECR_IM 0x1000 /* Interrupt mask */ | ||
31 | #define MII_BCM54XX_ECR_IF 0x0800 /* Interrupt force */ | ||
32 | |||
33 | #define MII_BCM54XX_ESR 0x11 /* BCM54xx extended status register */ | ||
34 | #define MII_BCM54XX_ESR_IS 0x1000 /* Interrupt status */ | ||
35 | |||
36 | #define MII_BCM54XX_EXP_DATA 0x15 /* Expansion register data */ | ||
37 | #define MII_BCM54XX_EXP_SEL 0x17 /* Expansion register select */ | ||
38 | #define MII_BCM54XX_EXP_SEL_SSD 0x0e00 /* Secondary SerDes select */ | ||
39 | #define MII_BCM54XX_EXP_SEL_ER 0x0f00 /* Expansion register select */ | ||
40 | |||
41 | #define MII_BCM54XX_AUX_CTL 0x18 /* Auxiliary control register */ | ||
42 | #define MII_BCM54XX_ISR 0x1a /* BCM54xx interrupt status register */ | ||
43 | #define MII_BCM54XX_IMR 0x1b /* BCM54xx interrupt mask register */ | ||
44 | #define MII_BCM54XX_INT_CRCERR 0x0001 /* CRC error */ | ||
45 | #define MII_BCM54XX_INT_LINK 0x0002 /* Link status changed */ | ||
46 | #define MII_BCM54XX_INT_SPEED 0x0004 /* Link speed change */ | ||
47 | #define MII_BCM54XX_INT_DUPLEX 0x0008 /* Duplex mode changed */ | ||
48 | #define MII_BCM54XX_INT_LRS 0x0010 /* Local receiver status changed */ | ||
49 | #define MII_BCM54XX_INT_RRS 0x0020 /* Remote receiver status changed */ | ||
50 | #define MII_BCM54XX_INT_SSERR 0x0040 /* Scrambler synchronization error */ | ||
51 | #define MII_BCM54XX_INT_UHCD 0x0080 /* Unsupported HCD negotiated */ | ||
52 | #define MII_BCM54XX_INT_NHCD 0x0100 /* No HCD */ | ||
53 | #define MII_BCM54XX_INT_NHCDL 0x0200 /* No HCD link */ | ||
54 | #define MII_BCM54XX_INT_ANPR 0x0400 /* Auto-negotiation page received */ | ||
55 | #define MII_BCM54XX_INT_LC 0x0800 /* All counters below 128 */ | ||
56 | #define MII_BCM54XX_INT_HC 0x1000 /* Counter above 32768 */ | ||
57 | #define MII_BCM54XX_INT_MDIX 0x2000 /* MDIX status change */ | ||
58 | #define MII_BCM54XX_INT_PSERR 0x4000 /* Pair swap error */ | ||
59 | |||
60 | #define MII_BCM54XX_SHD 0x1c /* 0x1c shadow registers */ | ||
61 | #define MII_BCM54XX_SHD_WRITE 0x8000 | ||
62 | #define MII_BCM54XX_SHD_VAL(x) ((x & 0x1f) << 10) | ||
63 | #define MII_BCM54XX_SHD_DATA(x) ((x & 0x3ff) << 0) | ||
64 | |||
65 | /* | ||
66 | * AUXILIARY CONTROL SHADOW ACCESS REGISTERS. (PHY REG 0x18) | ||
67 | */ | ||
68 | #define MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL 0x0000 | ||
69 | #define MII_BCM54XX_AUXCTL_ACTL_TX_6DB 0x0400 | ||
70 | #define MII_BCM54XX_AUXCTL_ACTL_SMDSP_ENA 0x0800 | ||
71 | |||
72 | #define MII_BCM54XX_AUXCTL_MISC_WREN 0x8000 | ||
73 | #define MII_BCM54XX_AUXCTL_MISC_FORCE_AMDIX 0x0200 | ||
74 | #define MII_BCM54XX_AUXCTL_MISC_RDSEL_MISC 0x7000 | ||
75 | #define MII_BCM54XX_AUXCTL_SHDWSEL_MISC 0x0007 | ||
76 | |||
77 | #define MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL 0x0000 | ||
78 | |||
79 | |||
80 | /* | 28 | /* |
81 | * Broadcom LED source encodings. These are used in BCM5461, BCM5481, | 29 | * Broadcom LED source encodings. These are used in BCM5461, BCM5481, |
82 | * BCM5482, and possibly some others. | 30 | * BCM5482, and possibly some others. |
diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c index 71e49000fbf3..76f54b32a120 100644 --- a/drivers/net/phy/mdio_bus.c +++ b/drivers/net/phy/mdio_bus.c | |||
@@ -432,8 +432,28 @@ phy_id_show(struct device *dev, struct device_attribute *attr, char *buf) | |||
432 | } | 432 | } |
433 | static DEVICE_ATTR_RO(phy_id); | 433 | static DEVICE_ATTR_RO(phy_id); |
434 | 434 | ||
435 | static ssize_t | ||
436 | phy_interface_show(struct device *dev, struct device_attribute *attr, char *buf) | ||
437 | { | ||
438 | struct phy_device *phydev = to_phy_device(dev); | ||
439 | |||
440 | return sprintf(buf, "%s\n", phy_modes(phydev->interface)); | ||
441 | } | ||
442 | static DEVICE_ATTR_RO(phy_interface); | ||
443 | |||
444 | static ssize_t | ||
445 | phy_has_fixups_show(struct device *dev, struct device_attribute *attr, char *buf) | ||
446 | { | ||
447 | struct phy_device *phydev = to_phy_device(dev); | ||
448 | |||
449 | return sprintf(buf, "%d\n", phydev->has_fixups); | ||
450 | } | ||
451 | static DEVICE_ATTR_RO(phy_has_fixups); | ||
452 | |||
435 | static struct attribute *mdio_dev_attrs[] = { | 453 | static struct attribute *mdio_dev_attrs[] = { |
436 | &dev_attr_phy_id.attr, | 454 | &dev_attr_phy_id.attr, |
455 | &dev_attr_phy_interface.attr, | ||
456 | &dev_attr_phy_has_fixups.attr, | ||
437 | NULL, | 457 | NULL, |
438 | }; | 458 | }; |
439 | ATTRIBUTE_GROUPS(mdio_dev); | 459 | ATTRIBUTE_GROUPS(mdio_dev); |
diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c index 5a8993b0cafc..0c9e4342f11d 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c | |||
@@ -148,15 +148,52 @@ static int ks8737_config_intr(struct phy_device *phydev) | |||
148 | return rc < 0 ? rc : 0; | 148 | return rc < 0 ? rc : 0; |
149 | } | 149 | } |
150 | 150 | ||
151 | static int kszphy_setup_led(struct phy_device *phydev, | ||
152 | unsigned int reg, unsigned int shift) | ||
153 | { | ||
154 | |||
155 | struct device *dev = &phydev->dev; | ||
156 | struct device_node *of_node = dev->of_node; | ||
157 | int rc, temp; | ||
158 | u32 val; | ||
159 | |||
160 | if (!of_node && dev->parent->of_node) | ||
161 | of_node = dev->parent->of_node; | ||
162 | |||
163 | if (of_property_read_u32(of_node, "micrel,led-mode", &val)) | ||
164 | return 0; | ||
165 | |||
166 | temp = phy_read(phydev, reg); | ||
167 | if (temp < 0) | ||
168 | return temp; | ||
169 | |||
170 | temp &= 3 << shift; | ||
171 | temp |= val << shift; | ||
172 | rc = phy_write(phydev, reg, temp); | ||
173 | |||
174 | return rc < 0 ? rc : 0; | ||
175 | } | ||
176 | |||
151 | static int kszphy_config_init(struct phy_device *phydev) | 177 | static int kszphy_config_init(struct phy_device *phydev) |
152 | { | 178 | { |
153 | return 0; | 179 | return 0; |
154 | } | 180 | } |
155 | 181 | ||
182 | static int kszphy_config_init_led8041(struct phy_device *phydev) | ||
183 | { | ||
184 | /* single led control, register 0x1e bits 15..14 */ | ||
185 | return kszphy_setup_led(phydev, 0x1e, 14); | ||
186 | } | ||
187 | |||
156 | static int ksz8021_config_init(struct phy_device *phydev) | 188 | static int ksz8021_config_init(struct phy_device *phydev) |
157 | { | 189 | { |
158 | int rc; | ||
159 | const u16 val = KSZPHY_OMSO_B_CAST_OFF | KSZPHY_OMSO_RMII_OVERRIDE; | 190 | const u16 val = KSZPHY_OMSO_B_CAST_OFF | KSZPHY_OMSO_RMII_OVERRIDE; |
191 | int rc; | ||
192 | |||
193 | rc = kszphy_setup_led(phydev, 0x1f, 4); | ||
194 | if (rc) | ||
195 | dev_err(&phydev->dev, "failed to set led mode\n"); | ||
196 | |||
160 | phy_write(phydev, MII_KSZPHY_OMSO, val); | 197 | phy_write(phydev, MII_KSZPHY_OMSO, val); |
161 | rc = ksz_config_flags(phydev); | 198 | rc = ksz_config_flags(phydev); |
162 | return rc < 0 ? rc : 0; | 199 | return rc < 0 ? rc : 0; |
@@ -166,6 +203,10 @@ static int ks8051_config_init(struct phy_device *phydev) | |||
166 | { | 203 | { |
167 | int rc; | 204 | int rc; |
168 | 205 | ||
206 | rc = kszphy_setup_led(phydev, 0x1f, 4); | ||
207 | if (rc) | ||
208 | dev_err(&phydev->dev, "failed to set led mode\n"); | ||
209 | |||
169 | rc = ksz_config_flags(phydev); | 210 | rc = ksz_config_flags(phydev); |
170 | return rc < 0 ? rc : 0; | 211 | return rc < 0 ? rc : 0; |
171 | } | 212 | } |
@@ -327,7 +368,7 @@ static struct phy_driver ksphy_driver[] = { | |||
327 | .features = (PHY_BASIC_FEATURES | SUPPORTED_Pause | 368 | .features = (PHY_BASIC_FEATURES | SUPPORTED_Pause |
328 | | SUPPORTED_Asym_Pause), | 369 | | SUPPORTED_Asym_Pause), |
329 | .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, | 370 | .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, |
330 | .config_init = kszphy_config_init, | 371 | .config_init = kszphy_config_init_led8041, |
331 | .config_aneg = genphy_config_aneg, | 372 | .config_aneg = genphy_config_aneg, |
332 | .read_status = genphy_read_status, | 373 | .read_status = genphy_read_status, |
333 | .ack_interrupt = kszphy_ack_interrupt, | 374 | .ack_interrupt = kszphy_ack_interrupt, |
@@ -342,7 +383,7 @@ static struct phy_driver ksphy_driver[] = { | |||
342 | .features = PHY_BASIC_FEATURES | | 383 | .features = PHY_BASIC_FEATURES | |
343 | SUPPORTED_Pause | SUPPORTED_Asym_Pause, | 384 | SUPPORTED_Pause | SUPPORTED_Asym_Pause, |
344 | .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, | 385 | .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, |
345 | .config_init = kszphy_config_init, | 386 | .config_init = kszphy_config_init_led8041, |
346 | .config_aneg = genphy_config_aneg, | 387 | .config_aneg = genphy_config_aneg, |
347 | .read_status = genphy_read_status, | 388 | .read_status = genphy_read_status, |
348 | .ack_interrupt = kszphy_ack_interrupt, | 389 | .ack_interrupt = kszphy_ack_interrupt, |
@@ -371,7 +412,7 @@ static struct phy_driver ksphy_driver[] = { | |||
371 | .phy_id_mask = 0x00ffffff, | 412 | .phy_id_mask = 0x00ffffff, |
372 | .features = (PHY_BASIC_FEATURES | SUPPORTED_Pause), | 413 | .features = (PHY_BASIC_FEATURES | SUPPORTED_Pause), |
373 | .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, | 414 | .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, |
374 | .config_init = kszphy_config_init, | 415 | .config_init = kszphy_config_init_led8041, |
375 | .config_aneg = genphy_config_aneg, | 416 | .config_aneg = genphy_config_aneg, |
376 | .read_status = genphy_read_status, | 417 | .read_status = genphy_read_status, |
377 | .ack_interrupt = kszphy_ack_interrupt, | 418 | .ack_interrupt = kszphy_ack_interrupt, |
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 19c9eca0ef26..643b5d665f41 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c | |||
@@ -38,6 +38,26 @@ | |||
38 | 38 | ||
39 | #include <asm/irq.h> | 39 | #include <asm/irq.h> |
40 | 40 | ||
41 | static const char *phy_speed_to_str(int speed) | ||
42 | { | ||
43 | switch (speed) { | ||
44 | case SPEED_10: | ||
45 | return "10Mbps"; | ||
46 | case SPEED_100: | ||
47 | return "100Mbps"; | ||
48 | case SPEED_1000: | ||
49 | return "1Gbps"; | ||
50 | case SPEED_2500: | ||
51 | return "2.5Gbps"; | ||
52 | case SPEED_10000: | ||
53 | return "10Gbps"; | ||
54 | case SPEED_UNKNOWN: | ||
55 | return "Unknown"; | ||
56 | default: | ||
57 | return "Unsupported (update phy.c)"; | ||
58 | } | ||
59 | } | ||
60 | |||
41 | /** | 61 | /** |
42 | * phy_print_status - Convenience function to print out the current phy status | 62 | * phy_print_status - Convenience function to print out the current phy status |
43 | * @phydev: the phy_device struct | 63 | * @phydev: the phy_device struct |
@@ -45,12 +65,13 @@ | |||
45 | void phy_print_status(struct phy_device *phydev) | 65 | void phy_print_status(struct phy_device *phydev) |
46 | { | 66 | { |
47 | if (phydev->link) { | 67 | if (phydev->link) { |
48 | pr_info("%s - Link is Up - %d/%s\n", | 68 | netdev_info(phydev->attached_dev, |
49 | dev_name(&phydev->dev), | 69 | "Link is Up - %s/%s - flow control %s\n", |
50 | phydev->speed, | 70 | phy_speed_to_str(phydev->speed), |
51 | DUPLEX_FULL == phydev->duplex ? "Full" : "Half"); | 71 | DUPLEX_FULL == phydev->duplex ? "Full" : "Half", |
72 | phydev->pause ? "rx/tx" : "off"); | ||
52 | } else { | 73 | } else { |
53 | pr_info("%s - Link is Down\n", dev_name(&phydev->dev)); | 74 | netdev_info(phydev->attached_dev, "Link is Down\n"); |
54 | } | 75 | } |
55 | } | 76 | } |
56 | EXPORT_SYMBOL(phy_print_status); | 77 | EXPORT_SYMBOL(phy_print_status); |
@@ -62,7 +83,7 @@ EXPORT_SYMBOL(phy_print_status); | |||
62 | * If the @phydev driver has an ack_interrupt function, call it to | 83 | * If the @phydev driver has an ack_interrupt function, call it to |
63 | * ack and clear the phy device's interrupt. | 84 | * ack and clear the phy device's interrupt. |
64 | * | 85 | * |
65 | * Returns 0 on success on < 0 on error. | 86 | * Returns 0 on success or < 0 on error. |
66 | */ | 87 | */ |
67 | static int phy_clear_interrupt(struct phy_device *phydev) | 88 | static int phy_clear_interrupt(struct phy_device *phydev) |
68 | { | 89 | { |
@@ -77,7 +98,7 @@ static int phy_clear_interrupt(struct phy_device *phydev) | |||
77 | * @phydev: the phy_device struct | 98 | * @phydev: the phy_device struct |
78 | * @interrupts: interrupt flags to configure for this @phydev | 99 | * @interrupts: interrupt flags to configure for this @phydev |
79 | * | 100 | * |
80 | * Returns 0 on success on < 0 on error. | 101 | * Returns 0 on success or < 0 on error. |
81 | */ | 102 | */ |
82 | static int phy_config_interrupt(struct phy_device *phydev, u32 interrupts) | 103 | static int phy_config_interrupt(struct phy_device *phydev, u32 interrupts) |
83 | { | 104 | { |
@@ -93,15 +114,16 @@ static int phy_config_interrupt(struct phy_device *phydev, u32 interrupts) | |||
93 | * phy_aneg_done - return auto-negotiation status | 114 | * phy_aneg_done - return auto-negotiation status |
94 | * @phydev: target phy_device struct | 115 | * @phydev: target phy_device struct |
95 | * | 116 | * |
96 | * Description: Reads the status register and returns 0 either if | 117 | * Description: Return the auto-negotiation status from this @phydev |
97 | * auto-negotiation is incomplete, or if there was an error. | 118 | * Returns > 0 on success or < 0 on error. 0 means that auto-negotiation |
98 | * Returns BMSR_ANEGCOMPLETE if auto-negotiation is done. | 119 | * is still pending. |
99 | */ | 120 | */ |
100 | static inline int phy_aneg_done(struct phy_device *phydev) | 121 | static inline int phy_aneg_done(struct phy_device *phydev) |
101 | { | 122 | { |
102 | int retval = phy_read(phydev, MII_BMSR); | 123 | if (phydev->drv->aneg_done) |
124 | return phydev->drv->aneg_done(phydev); | ||
103 | 125 | ||
104 | return (retval < 0) ? retval : (retval & BMSR_ANEGCOMPLETE); | 126 | return genphy_aneg_done(phydev); |
105 | } | 127 | } |
106 | 128 | ||
107 | /* A structure for mapping a particular speed and duplex | 129 | /* A structure for mapping a particular speed and duplex |
@@ -283,7 +305,10 @@ int phy_ethtool_gset(struct phy_device *phydev, struct ethtool_cmd *cmd) | |||
283 | 305 | ||
284 | ethtool_cmd_speed_set(cmd, phydev->speed); | 306 | ethtool_cmd_speed_set(cmd, phydev->speed); |
285 | cmd->duplex = phydev->duplex; | 307 | cmd->duplex = phydev->duplex; |
286 | cmd->port = PORT_MII; | 308 | if (phydev->interface == PHY_INTERFACE_MODE_MOCA) |
309 | cmd->port = PORT_BNC; | ||
310 | else | ||
311 | cmd->port = PORT_MII; | ||
287 | cmd->phy_address = phydev->addr; | 312 | cmd->phy_address = phydev->addr; |
288 | cmd->transceiver = phy_is_internal(phydev) ? | 313 | cmd->transceiver = phy_is_internal(phydev) ? |
289 | XCVR_INTERNAL : XCVR_EXTERNAL; | 314 | XCVR_INTERNAL : XCVR_EXTERNAL; |
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 4b970f7624c0..a2fbb3e1db9a 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c | |||
@@ -139,6 +139,7 @@ static int phy_scan_fixups(struct phy_device *phydev) | |||
139 | mutex_unlock(&phy_fixup_lock); | 139 | mutex_unlock(&phy_fixup_lock); |
140 | return err; | 140 | return err; |
141 | } | 141 | } |
142 | phydev->has_fixups = true; | ||
142 | } | 143 | } |
143 | } | 144 | } |
144 | mutex_unlock(&phy_fixup_lock); | 145 | mutex_unlock(&phy_fixup_lock); |
@@ -534,16 +535,16 @@ static int phy_poll_reset(struct phy_device *phydev) | |||
534 | 535 | ||
535 | int phy_init_hw(struct phy_device *phydev) | 536 | int phy_init_hw(struct phy_device *phydev) |
536 | { | 537 | { |
537 | int ret; | 538 | int ret = 0; |
538 | 539 | ||
539 | if (!phydev->drv || !phydev->drv->config_init) | 540 | if (!phydev->drv || !phydev->drv->config_init) |
540 | return 0; | 541 | return 0; |
541 | 542 | ||
542 | ret = phy_write(phydev, MII_BMCR, BMCR_RESET); | 543 | if (phydev->drv->soft_reset) |
543 | if (ret < 0) | 544 | ret = phydev->drv->soft_reset(phydev); |
544 | return ret; | 545 | else |
546 | ret = genphy_soft_reset(phydev); | ||
545 | 547 | ||
546 | ret = phy_poll_reset(phydev); | ||
547 | if (ret < 0) | 548 | if (ret < 0) |
548 | return ret; | 549 | return ret; |
549 | 550 | ||
@@ -865,6 +866,22 @@ int genphy_config_aneg(struct phy_device *phydev) | |||
865 | } | 866 | } |
866 | EXPORT_SYMBOL(genphy_config_aneg); | 867 | EXPORT_SYMBOL(genphy_config_aneg); |
867 | 868 | ||
869 | /** | ||
870 | * genphy_aneg_done - return auto-negotiation status | ||
871 | * @phydev: target phy_device struct | ||
872 | * | ||
873 | * Description: Reads the status register and returns 0 either if | ||
874 | * auto-negotiation is incomplete, or if there was an error. | ||
875 | * Returns BMSR_ANEGCOMPLETE if auto-negotiation is done. | ||
876 | */ | ||
877 | int genphy_aneg_done(struct phy_device *phydev) | ||
878 | { | ||
879 | int retval = phy_read(phydev, MII_BMSR); | ||
880 | |||
881 | return (retval < 0) ? retval : (retval & BMSR_ANEGCOMPLETE); | ||
882 | } | ||
883 | EXPORT_SYMBOL(genphy_aneg_done); | ||
884 | |||
868 | static int gen10g_config_aneg(struct phy_device *phydev) | 885 | static int gen10g_config_aneg(struct phy_device *phydev) |
869 | { | 886 | { |
870 | return 0; | 887 | return 0; |
@@ -1030,6 +1047,27 @@ static int gen10g_read_status(struct phy_device *phydev) | |||
1030 | return 0; | 1047 | return 0; |
1031 | } | 1048 | } |
1032 | 1049 | ||
1050 | /** | ||
1051 | * genphy_soft_reset - software reset the PHY via BMCR_RESET bit | ||
1052 | * @phydev: target phy_device struct | ||
1053 | * | ||
1054 | * Description: Perform a software PHY reset using the standard | ||
1055 | * BMCR_RESET bit and poll for the reset bit to be cleared. | ||
1056 | * | ||
1057 | * Returns: 0 on success, < 0 on failure | ||
1058 | */ | ||
1059 | int genphy_soft_reset(struct phy_device *phydev) | ||
1060 | { | ||
1061 | int ret; | ||
1062 | |||
1063 | ret = phy_write(phydev, MII_BMCR, BMCR_RESET); | ||
1064 | if (ret < 0) | ||
1065 | return ret; | ||
1066 | |||
1067 | return phy_poll_reset(phydev); | ||
1068 | } | ||
1069 | EXPORT_SYMBOL(genphy_soft_reset); | ||
1070 | |||
1033 | static int genphy_config_init(struct phy_device *phydev) | 1071 | static int genphy_config_init(struct phy_device *phydev) |
1034 | { | 1072 | { |
1035 | int val; | 1073 | int val; |
@@ -1076,6 +1114,12 @@ static int genphy_config_init(struct phy_device *phydev) | |||
1076 | return 0; | 1114 | return 0; |
1077 | } | 1115 | } |
1078 | 1116 | ||
1117 | static int gen10g_soft_reset(struct phy_device *phydev) | ||
1118 | { | ||
1119 | /* Do nothing for now */ | ||
1120 | return 0; | ||
1121 | } | ||
1122 | |||
1079 | static int gen10g_config_init(struct phy_device *phydev) | 1123 | static int gen10g_config_init(struct phy_device *phydev) |
1080 | { | 1124 | { |
1081 | /* Temporarily just say we support everything */ | 1125 | /* Temporarily just say we support everything */ |
@@ -1250,9 +1294,11 @@ static struct phy_driver genphy_driver[] = { | |||
1250 | .phy_id = 0xffffffff, | 1294 | .phy_id = 0xffffffff, |
1251 | .phy_id_mask = 0xffffffff, | 1295 | .phy_id_mask = 0xffffffff, |
1252 | .name = "Generic PHY", | 1296 | .name = "Generic PHY", |
1297 | .soft_reset = genphy_soft_reset, | ||
1253 | .config_init = genphy_config_init, | 1298 | .config_init = genphy_config_init, |
1254 | .features = 0, | 1299 | .features = 0, |
1255 | .config_aneg = genphy_config_aneg, | 1300 | .config_aneg = genphy_config_aneg, |
1301 | .aneg_done = genphy_aneg_done, | ||
1256 | .read_status = genphy_read_status, | 1302 | .read_status = genphy_read_status, |
1257 | .suspend = genphy_suspend, | 1303 | .suspend = genphy_suspend, |
1258 | .resume = genphy_resume, | 1304 | .resume = genphy_resume, |
@@ -1261,6 +1307,7 @@ static struct phy_driver genphy_driver[] = { | |||
1261 | .phy_id = 0xffffffff, | 1307 | .phy_id = 0xffffffff, |
1262 | .phy_id_mask = 0xffffffff, | 1308 | .phy_id_mask = 0xffffffff, |
1263 | .name = "Generic 10G PHY", | 1309 | .name = "Generic 10G PHY", |
1310 | .soft_reset = gen10g_soft_reset, | ||
1264 | .config_init = gen10g_config_init, | 1311 | .config_init = gen10g_config_init, |
1265 | .features = 0, | 1312 | .features = 0, |
1266 | .config_aneg = gen10g_config_aneg, | 1313 | .config_aneg = gen10g_config_aneg, |