]> asedeno.scripts.mit.edu Git - linux.git/blob - drivers/net/phy/bcm7xxx.c
net: phy: phy drivers should not set SUPPORTED_[Asym_]Pause
[linux.git] / drivers / net / phy / bcm7xxx.c
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 "bcm-phy-lib.h"
16 #include <linux/bitops.h>
17 #include <linux/brcmphy.h>
18 #include <linux/mdio.h>
19
20 /* Broadcom BCM7xxx internal PHY registers */
21
22 /* 40nm only register definitions */
23 #define MII_BCM7XXX_100TX_AUX_CTL       0x10
24 #define MII_BCM7XXX_100TX_FALSE_CAR     0x13
25 #define MII_BCM7XXX_100TX_DISC          0x14
26 #define MII_BCM7XXX_AUX_MODE            0x1d
27 #define  MII_BCM7XXX_64CLK_MDIO         BIT(12)
28 #define MII_BCM7XXX_TEST                0x1f
29 #define  MII_BCM7XXX_SHD_MODE_2         BIT(2)
30
31 /* 28nm only register definitions */
32 #define MISC_ADDR(base, channel)        base, channel
33
34 #define DSP_TAP10                       MISC_ADDR(0x0a, 0)
35 #define PLL_PLLCTRL_1                   MISC_ADDR(0x32, 1)
36 #define PLL_PLLCTRL_2                   MISC_ADDR(0x32, 2)
37 #define PLL_PLLCTRL_4                   MISC_ADDR(0x33, 0)
38
39 #define AFE_RXCONFIG_0                  MISC_ADDR(0x38, 0)
40 #define AFE_RXCONFIG_1                  MISC_ADDR(0x38, 1)
41 #define AFE_RXCONFIG_2                  MISC_ADDR(0x38, 2)
42 #define AFE_RX_LP_COUNTER               MISC_ADDR(0x38, 3)
43 #define AFE_TX_CONFIG                   MISC_ADDR(0x39, 0)
44 #define AFE_VDCA_ICTRL_0                MISC_ADDR(0x39, 1)
45 #define AFE_VDAC_OTHERS_0               MISC_ADDR(0x39, 3)
46 #define AFE_HPF_TRIM_OTHERS             MISC_ADDR(0x3a, 0)
47
48 struct bcm7xxx_phy_priv {
49         u64     *stats;
50 };
51
52 static void r_rc_cal_reset(struct phy_device *phydev)
53 {
54         /* Reset R_CAL/RC_CAL Engine */
55         bcm_phy_write_exp(phydev, 0x00b0, 0x0010);
56
57         /* Disable Reset R_AL/RC_CAL Engine */
58         bcm_phy_write_exp(phydev, 0x00b0, 0x0000);
59 }
60
61 static int bcm7xxx_28nm_b0_afe_config_init(struct phy_device *phydev)
62 {
63         /* Increase VCO range to prevent unlocking problem of PLL at low
64          * temp
65          */
66         bcm_phy_write_misc(phydev, PLL_PLLCTRL_1, 0x0048);
67
68         /* Change Ki to 011 */
69         bcm_phy_write_misc(phydev, PLL_PLLCTRL_2, 0x021b);
70
71         /* Disable loading of TVCO buffer to bandgap, set bandgap trim
72          * to 111
73          */
74         bcm_phy_write_misc(phydev, PLL_PLLCTRL_4, 0x0e20);
75
76         /* Adjust bias current trim by -3 */
77         bcm_phy_write_misc(phydev, DSP_TAP10, 0x690b);
78
79         /* Switch to CORE_BASE1E */
80         phy_write(phydev, MII_BRCM_CORE_BASE1E, 0xd);
81
82         r_rc_cal_reset(phydev);
83
84         /* write AFE_RXCONFIG_0 */
85         bcm_phy_write_misc(phydev, AFE_RXCONFIG_0, 0xeb19);
86
87         /* write AFE_RXCONFIG_1 */
88         bcm_phy_write_misc(phydev, AFE_RXCONFIG_1, 0x9a3f);
89
90         /* write AFE_RX_LP_COUNTER */
91         bcm_phy_write_misc(phydev, AFE_RX_LP_COUNTER, 0x7fc0);
92
93         /* write AFE_HPF_TRIM_OTHERS */
94         bcm_phy_write_misc(phydev, AFE_HPF_TRIM_OTHERS, 0x000b);
95
96         /* write AFTE_TX_CONFIG */
97         bcm_phy_write_misc(phydev, AFE_TX_CONFIG, 0x0800);
98
99         return 0;
100 }
101
102 static int bcm7xxx_28nm_d0_afe_config_init(struct phy_device *phydev)
103 {
104         /* AFE_RXCONFIG_0 */
105         bcm_phy_write_misc(phydev, AFE_RXCONFIG_0, 0xeb15);
106
107         /* AFE_RXCONFIG_1 */
108         bcm_phy_write_misc(phydev, AFE_RXCONFIG_1, 0x9b2f);
109
110         /* AFE_RXCONFIG_2, set rCal offset for HT=0 code and LT=-2 code */
111         bcm_phy_write_misc(phydev, AFE_RXCONFIG_2, 0x2003);
112
113         /* AFE_RX_LP_COUNTER, set RX bandwidth to maximum */
114         bcm_phy_write_misc(phydev, AFE_RX_LP_COUNTER, 0x7fc0);
115
116         /* AFE_TX_CONFIG, set 100BT Cfeed=011 to improve rise/fall time */
117         bcm_phy_write_misc(phydev, AFE_TX_CONFIG, 0x431);
118
119         /* AFE_VDCA_ICTRL_0, set Iq=1101 instead of 0111 for AB symmetry */
120         bcm_phy_write_misc(phydev, AFE_VDCA_ICTRL_0, 0xa7da);
121
122         /* AFE_VDAC_OTHERS_0, set 1000BT Cidac=010 for all ports */
123         bcm_phy_write_misc(phydev, AFE_VDAC_OTHERS_0, 0xa020);
124
125         /* AFE_HPF_TRIM_OTHERS, set 100Tx/10BT to -4.5% swing and set rCal
126          * offset for HT=0 code
127          */
128         bcm_phy_write_misc(phydev, AFE_HPF_TRIM_OTHERS, 0x00e3);
129
130         /* CORE_BASE1E, force trim to overwrite and set I_ext trim to 0000 */
131         phy_write(phydev, MII_BRCM_CORE_BASE1E, 0x0010);
132
133         /* DSP_TAP10, adjust bias current trim (+0% swing, +0 tick) */
134         bcm_phy_write_misc(phydev, DSP_TAP10, 0x011b);
135
136         /* Reset R_CAL/RC_CAL engine */
137         r_rc_cal_reset(phydev);
138
139         return 0;
140 }
141
142 static int bcm7xxx_28nm_e0_plus_afe_config_init(struct phy_device *phydev)
143 {
144         /* AFE_RXCONFIG_1, provide more margin for INL/DNL measurement */
145         bcm_phy_write_misc(phydev, AFE_RXCONFIG_1, 0x9b2f);
146
147         /* AFE_TX_CONFIG, set 100BT Cfeed=011 to improve rise/fall time */
148         bcm_phy_write_misc(phydev, AFE_TX_CONFIG, 0x431);
149
150         /* AFE_VDCA_ICTRL_0, set Iq=1101 instead of 0111 for AB symmetry */
151         bcm_phy_write_misc(phydev, AFE_VDCA_ICTRL_0, 0xa7da);
152
153         /* AFE_HPF_TRIM_OTHERS, set 100Tx/10BT to -4.5% swing and set rCal
154          * offset for HT=0 code
155          */
156         bcm_phy_write_misc(phydev, AFE_HPF_TRIM_OTHERS, 0x00e3);
157
158         /* CORE_BASE1E, force trim to overwrite and set I_ext trim to 0000 */
159         phy_write(phydev, MII_BRCM_CORE_BASE1E, 0x0010);
160
161         /* DSP_TAP10, adjust bias current trim (+0% swing, +0 tick) */
162         bcm_phy_write_misc(phydev, DSP_TAP10, 0x011b);
163
164         /* Reset R_CAL/RC_CAL engine */
165         r_rc_cal_reset(phydev);
166
167         return 0;
168 }
169
170 static int bcm7xxx_28nm_config_init(struct phy_device *phydev)
171 {
172         u8 rev = PHY_BRCM_7XXX_REV(phydev->dev_flags);
173         u8 patch = PHY_BRCM_7XXX_PATCH(phydev->dev_flags);
174         u8 count;
175         int ret = 0;
176
177         pr_info_once("%s: %s PHY revision: 0x%02x, patch: %d\n",
178                      phydev_name(phydev), phydev->drv->name, rev, patch);
179
180         /* Dummy read to a register to workaround an issue upon reset where the
181          * internal inverter may not allow the first MDIO transaction to pass
182          * the MDIO management controller and make us return 0xffff for such
183          * reads.
184          */
185         phy_read(phydev, MII_BMSR);
186
187         switch (rev) {
188         case 0xb0:
189                 ret = bcm7xxx_28nm_b0_afe_config_init(phydev);
190                 break;
191         case 0xd0:
192                 ret = bcm7xxx_28nm_d0_afe_config_init(phydev);
193                 break;
194         case 0xe0:
195         case 0xf0:
196         /* Rev G0 introduces a roll over */
197         case 0x10:
198                 ret = bcm7xxx_28nm_e0_plus_afe_config_init(phydev);
199                 break;
200         default:
201                 break;
202         }
203
204         if (ret)
205                 return ret;
206
207         ret = bcm_phy_downshift_get(phydev, &count);
208         if (ret)
209                 return ret;
210
211         /* Only enable EEE if Wirespeed/downshift is disabled */
212         ret = bcm_phy_set_eee(phydev, count == DOWNSHIFT_DEV_DISABLE);
213         if (ret)
214                 return ret;
215
216         return bcm_phy_enable_apd(phydev, true);
217 }
218
219 static int bcm7xxx_28nm_resume(struct phy_device *phydev)
220 {
221         int ret;
222
223         /* Re-apply workarounds coming out suspend/resume */
224         ret = bcm7xxx_28nm_config_init(phydev);
225         if (ret)
226                 return ret;
227
228         /* 28nm Gigabit PHYs come out of reset without any half-duplex
229          * or "hub" compliant advertised mode, fix that. This does not
230          * cause any problems with the PHY library since genphy_config_aneg()
231          * gracefully handles auto-negotiated and forced modes.
232          */
233         return genphy_config_aneg(phydev);
234 }
235
236 static int phy_set_clr_bits(struct phy_device *dev, int location,
237                                         int set_mask, int clr_mask)
238 {
239         int v, ret;
240
241         v = phy_read(dev, location);
242         if (v < 0)
243                 return v;
244
245         v &= ~clr_mask;
246         v |= set_mask;
247
248         ret = phy_write(dev, location, v);
249         if (ret < 0)
250                 return ret;
251
252         return v;
253 }
254
255 static int bcm7xxx_config_init(struct phy_device *phydev)
256 {
257         int ret;
258
259         /* Enable 64 clock MDIO */
260         phy_write(phydev, MII_BCM7XXX_AUX_MODE, MII_BCM7XXX_64CLK_MDIO);
261         phy_read(phydev, MII_BCM7XXX_AUX_MODE);
262
263         /* set shadow mode 2 */
264         ret = phy_set_clr_bits(phydev, MII_BCM7XXX_TEST,
265                         MII_BCM7XXX_SHD_MODE_2, MII_BCM7XXX_SHD_MODE_2);
266         if (ret < 0)
267                 return ret;
268
269         /* set iddq_clkbias */
270         phy_write(phydev, MII_BCM7XXX_100TX_DISC, 0x0F00);
271         udelay(10);
272
273         /* reset iddq_clkbias */
274         phy_write(phydev, MII_BCM7XXX_100TX_DISC, 0x0C00);
275
276         phy_write(phydev, MII_BCM7XXX_100TX_FALSE_CAR, 0x7555);
277
278         /* reset shadow mode 2 */
279         ret = phy_set_clr_bits(phydev, MII_BCM7XXX_TEST, 0, MII_BCM7XXX_SHD_MODE_2);
280         if (ret < 0)
281                 return ret;
282
283         return 0;
284 }
285
286 /* Workaround for putting the PHY in IDDQ mode, required
287  * for all BCM7XXX 40nm and 65nm PHYs
288  */
289 static int bcm7xxx_suspend(struct phy_device *phydev)
290 {
291         int ret;
292         const struct bcm7xxx_regs {
293                 int reg;
294                 u16 value;
295         } bcm7xxx_suspend_cfg[] = {
296                 { MII_BCM7XXX_TEST, 0x008b },
297                 { MII_BCM7XXX_100TX_AUX_CTL, 0x01c0 },
298                 { MII_BCM7XXX_100TX_DISC, 0x7000 },
299                 { MII_BCM7XXX_TEST, 0x000f },
300                 { MII_BCM7XXX_100TX_AUX_CTL, 0x20d0 },
301                 { MII_BCM7XXX_TEST, 0x000b },
302         };
303         unsigned int i;
304
305         for (i = 0; i < ARRAY_SIZE(bcm7xxx_suspend_cfg); i++) {
306                 ret = phy_write(phydev,
307                                 bcm7xxx_suspend_cfg[i].reg,
308                                 bcm7xxx_suspend_cfg[i].value);
309                 if (ret)
310                         return ret;
311         }
312
313         return 0;
314 }
315
316 static int bcm7xxx_28nm_get_tunable(struct phy_device *phydev,
317                                     struct ethtool_tunable *tuna,
318                                     void *data)
319 {
320         switch (tuna->id) {
321         case ETHTOOL_PHY_DOWNSHIFT:
322                 return bcm_phy_downshift_get(phydev, (u8 *)data);
323         default:
324                 return -EOPNOTSUPP;
325         }
326 }
327
328 static int bcm7xxx_28nm_set_tunable(struct phy_device *phydev,
329                                     struct ethtool_tunable *tuna,
330                                     const void *data)
331 {
332         u8 count = *(u8 *)data;
333         int ret;
334
335         switch (tuna->id) {
336         case ETHTOOL_PHY_DOWNSHIFT:
337                 ret = bcm_phy_downshift_set(phydev, count);
338                 break;
339         default:
340                 return -EOPNOTSUPP;
341         }
342
343         if (ret)
344                 return ret;
345
346         /* Disable EEE advertisment since this prevents the PHY
347          * from successfully linking up, trigger auto-negotiation restart
348          * to let the MAC decide what to do.
349          */
350         ret = bcm_phy_set_eee(phydev, count == DOWNSHIFT_DEV_DISABLE);
351         if (ret)
352                 return ret;
353
354         return genphy_restart_aneg(phydev);
355 }
356
357 static void bcm7xxx_28nm_get_phy_stats(struct phy_device *phydev,
358                                        struct ethtool_stats *stats, u64 *data)
359 {
360         struct bcm7xxx_phy_priv *priv = phydev->priv;
361
362         bcm_phy_get_stats(phydev, priv->stats, stats, data);
363 }
364
365 static int bcm7xxx_28nm_probe(struct phy_device *phydev)
366 {
367         struct bcm7xxx_phy_priv *priv;
368
369         priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL);
370         if (!priv)
371                 return -ENOMEM;
372
373         phydev->priv = priv;
374
375         priv->stats = devm_kcalloc(&phydev->mdio.dev,
376                                    bcm_phy_get_sset_count(phydev), sizeof(u64),
377                                    GFP_KERNEL);
378         if (!priv->stats)
379                 return -ENOMEM;
380
381         return 0;
382 }
383
384 #define BCM7XXX_28NM_GPHY(_oui, _name)                                  \
385 {                                                                       \
386         .phy_id         = (_oui),                                       \
387         .phy_id_mask    = 0xfffffff0,                                   \
388         .name           = _name,                                        \
389         .features       = PHY_GBIT_FEATURES,                            \
390         .flags          = PHY_IS_INTERNAL,                              \
391         .config_init    = bcm7xxx_28nm_config_init,                     \
392         .config_aneg    = genphy_config_aneg,                           \
393         .read_status    = genphy_read_status,                           \
394         .resume         = bcm7xxx_28nm_resume,                          \
395         .get_tunable    = bcm7xxx_28nm_get_tunable,                     \
396         .set_tunable    = bcm7xxx_28nm_set_tunable,                     \
397         .get_sset_count = bcm_phy_get_sset_count,                       \
398         .get_strings    = bcm_phy_get_strings,                          \
399         .get_stats      = bcm7xxx_28nm_get_phy_stats,                   \
400         .probe          = bcm7xxx_28nm_probe,                           \
401 }
402
403 #define BCM7XXX_40NM_EPHY(_oui, _name)                                  \
404 {                                                                       \
405         .phy_id         = (_oui),                                       \
406         .phy_id_mask    = 0xfffffff0,                                   \
407         .name           = _name,                                        \
408         .features       = PHY_BASIC_FEATURES,                           \
409         .flags          = PHY_IS_INTERNAL,                              \
410         .config_init    = bcm7xxx_config_init,                          \
411         .config_aneg    = genphy_config_aneg,                           \
412         .read_status    = genphy_read_status,                           \
413         .suspend        = bcm7xxx_suspend,                              \
414         .resume         = bcm7xxx_config_init,                          \
415 }
416
417 static struct phy_driver bcm7xxx_driver[] = {
418         BCM7XXX_28NM_GPHY(PHY_ID_BCM7250, "Broadcom BCM7250"),
419         BCM7XXX_28NM_GPHY(PHY_ID_BCM7364, "Broadcom BCM7364"),
420         BCM7XXX_28NM_GPHY(PHY_ID_BCM7366, "Broadcom BCM7366"),
421         BCM7XXX_28NM_GPHY(PHY_ID_BCM7439, "Broadcom BCM7439"),
422         BCM7XXX_28NM_GPHY(PHY_ID_BCM7439_2, "Broadcom BCM7439 (2)"),
423         BCM7XXX_28NM_GPHY(PHY_ID_BCM7445, "Broadcom BCM7445"),
424         BCM7XXX_40NM_EPHY(PHY_ID_BCM7346, "Broadcom BCM7346"),
425         BCM7XXX_40NM_EPHY(PHY_ID_BCM7362, "Broadcom BCM7362"),
426         BCM7XXX_40NM_EPHY(PHY_ID_BCM7425, "Broadcom BCM7425"),
427         BCM7XXX_40NM_EPHY(PHY_ID_BCM7429, "Broadcom BCM7429"),
428         BCM7XXX_40NM_EPHY(PHY_ID_BCM7435, "Broadcom BCM7435"),
429 };
430
431 static struct mdio_device_id __maybe_unused bcm7xxx_tbl[] = {
432         { PHY_ID_BCM7250, 0xfffffff0, },
433         { PHY_ID_BCM7364, 0xfffffff0, },
434         { PHY_ID_BCM7366, 0xfffffff0, },
435         { PHY_ID_BCM7346, 0xfffffff0, },
436         { PHY_ID_BCM7362, 0xfffffff0, },
437         { PHY_ID_BCM7425, 0xfffffff0, },
438         { PHY_ID_BCM7429, 0xfffffff0, },
439         { PHY_ID_BCM7439, 0xfffffff0, },
440         { PHY_ID_BCM7435, 0xfffffff0, },
441         { PHY_ID_BCM7445, 0xfffffff0, },
442         { }
443 };
444
445 module_phy_driver(bcm7xxx_driver);
446
447 MODULE_DEVICE_TABLE(mdio, bcm7xxx_tbl);
448
449 MODULE_DESCRIPTION("Broadcom BCM7xxx internal PHY driver");
450 MODULE_LICENSE("GPL");
451 MODULE_AUTHOR("Broadcom Corporation");