aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/phy
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/phy')
-rw-r--r--drivers/net/phy/Kconfig6
-rw-r--r--drivers/net/phy/Makefile1
-rw-r--r--drivers/net/phy/bcm7xxx.c343
-rw-r--r--drivers/net/phy/broadcom.c52
-rw-r--r--drivers/net/phy/mdio_bus.c20
-rw-r--r--drivers/net/phy/micrel.c49
-rw-r--r--drivers/net/phy/phy.c51
-rw-r--r--drivers/net/phy/phy_device.c57
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
74config 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
74config BCM87XX_PHY 80config 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
12obj-$(CONFIG_VITESSE_PHY) += vitesse.o 12obj-$(CONFIG_VITESSE_PHY) += vitesse.o
13obj-$(CONFIG_BROADCOM_PHY) += broadcom.o 13obj-$(CONFIG_BROADCOM_PHY) += broadcom.o
14obj-$(CONFIG_BCM63XX_PHY) += bcm63xx.o 14obj-$(CONFIG_BCM63XX_PHY) += bcm63xx.o
15obj-$(CONFIG_BCM7XXX_PHY) += bcm7xxx.o
15obj-$(CONFIG_BCM87XX_PHY) += bcm87xx.o 16obj-$(CONFIG_BCM87XX_PHY) += bcm87xx.o
16obj-$(CONFIG_ICPLUS_PHY) += icplus.o 17obj-$(CONFIG_ICPLUS_PHY) += icplus.o
17obj-$(CONFIG_REALTEK_PHY) += realtek.o 18obj-$(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
31static 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
64static 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
71static 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
88static 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
133static 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
144static 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
163static 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 */
201static 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
228static int bcm7xxx_dummy_config_init(struct phy_device *phydev)
229{
230 return 0;
231}
232
233static 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
314static 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
324static int __init bcm7xxx_phy_init(void)
325{
326 return phy_drivers_register(bcm7xxx_driver,
327 ARRAY_SIZE(bcm7xxx_driver));
328}
329
330static void __exit bcm7xxx_phy_exit(void)
331{
332 phy_drivers_unregister(bcm7xxx_driver,
333 ARRAY_SIZE(bcm7xxx_driver));
334}
335
336module_init(bcm7xxx_phy_init);
337module_exit(bcm7xxx_phy_exit);
338
339MODULE_DEVICE_TABLE(mdio, bcm7xxx_tbl);
340
341MODULE_DESCRIPTION("Broadcom BCM7xxx internal PHY driver");
342MODULE_LICENSE("GPL");
343MODULE_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}
433static DEVICE_ATTR_RO(phy_id); 433static DEVICE_ATTR_RO(phy_id);
434 434
435static ssize_t
436phy_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}
442static DEVICE_ATTR_RO(phy_interface);
443
444static ssize_t
445phy_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}
451static DEVICE_ATTR_RO(phy_has_fixups);
452
435static struct attribute *mdio_dev_attrs[] = { 453static 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};
439ATTRIBUTE_GROUPS(mdio_dev); 459ATTRIBUTE_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
151static 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
151static int kszphy_config_init(struct phy_device *phydev) 177static int kszphy_config_init(struct phy_device *phydev)
152{ 178{
153 return 0; 179 return 0;
154} 180}
155 181
182static 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
156static int ksz8021_config_init(struct phy_device *phydev) 188static 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
41static 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 @@
45void phy_print_status(struct phy_device *phydev) 65void 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}
56EXPORT_SYMBOL(phy_print_status); 77EXPORT_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 */
67static int phy_clear_interrupt(struct phy_device *phydev) 88static 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 */
82static int phy_config_interrupt(struct phy_device *phydev, u32 interrupts) 103static 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 */
100static inline int phy_aneg_done(struct phy_device *phydev) 121static 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
535int phy_init_hw(struct phy_device *phydev) 536int 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}
866EXPORT_SYMBOL(genphy_config_aneg); 867EXPORT_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 */
877int 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}
883EXPORT_SYMBOL(genphy_aneg_done);
884
868static int gen10g_config_aneg(struct phy_device *phydev) 885static 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 */
1059int 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}
1069EXPORT_SYMBOL(genphy_soft_reset);
1070
1033static int genphy_config_init(struct phy_device *phydev) 1071static 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
1117static int gen10g_soft_reset(struct phy_device *phydev)
1118{
1119 /* Do nothing for now */
1120 return 0;
1121}
1122
1079static int gen10g_config_init(struct phy_device *phydev) 1123static 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,