.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0+ |
---|
1 | 2 | /* |
---|
2 | 3 | * Broadcom BCM7xxx internal transceivers support. |
---|
3 | 4 | * |
---|
4 | 5 | * Copyright (C) 2014-2017 Broadcom |
---|
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 | 6 | */ |
---|
11 | 7 | |
---|
12 | 8 | #include <linux/module.h> |
---|
.. | .. |
---|
15 | 11 | #include "bcm-phy-lib.h" |
---|
16 | 12 | #include <linux/bitops.h> |
---|
17 | 13 | #include <linux/brcmphy.h> |
---|
| 14 | +#include <linux/clk.h> |
---|
18 | 15 | #include <linux/mdio.h> |
---|
19 | 16 | |
---|
20 | 17 | /* Broadcom BCM7xxx internal PHY registers */ |
---|
.. | .. |
---|
46 | 43 | #define MII_BCM7XXX_SHD_3_TL4 0x23 |
---|
47 | 44 | #define MII_BCM7XXX_TL4_RST_MSK (BIT(2) | BIT(1)) |
---|
48 | 45 | |
---|
49 | | -/* 28nm only register definitions */ |
---|
50 | | -#define MISC_ADDR(base, channel) base, channel |
---|
51 | | - |
---|
52 | | -#define DSP_TAP10 MISC_ADDR(0x0a, 0) |
---|
53 | | -#define PLL_PLLCTRL_1 MISC_ADDR(0x32, 1) |
---|
54 | | -#define PLL_PLLCTRL_2 MISC_ADDR(0x32, 2) |
---|
55 | | -#define PLL_PLLCTRL_4 MISC_ADDR(0x33, 0) |
---|
56 | | - |
---|
57 | | -#define AFE_RXCONFIG_0 MISC_ADDR(0x38, 0) |
---|
58 | | -#define AFE_RXCONFIG_1 MISC_ADDR(0x38, 1) |
---|
59 | | -#define AFE_RXCONFIG_2 MISC_ADDR(0x38, 2) |
---|
60 | | -#define AFE_RX_LP_COUNTER MISC_ADDR(0x38, 3) |
---|
61 | | -#define AFE_TX_CONFIG MISC_ADDR(0x39, 0) |
---|
62 | | -#define AFE_VDCA_ICTRL_0 MISC_ADDR(0x39, 1) |
---|
63 | | -#define AFE_VDAC_OTHERS_0 MISC_ADDR(0x39, 3) |
---|
64 | | -#define AFE_HPF_TRIM_OTHERS MISC_ADDR(0x3a, 0) |
---|
65 | | - |
---|
66 | 46 | struct bcm7xxx_phy_priv { |
---|
67 | 47 | u64 *stats; |
---|
| 48 | + struct clk *clk; |
---|
68 | 49 | }; |
---|
69 | | - |
---|
70 | | -static void r_rc_cal_reset(struct phy_device *phydev) |
---|
71 | | -{ |
---|
72 | | - /* Reset R_CAL/RC_CAL Engine */ |
---|
73 | | - bcm_phy_write_exp_sel(phydev, 0x00b0, 0x0010); |
---|
74 | | - |
---|
75 | | - /* Disable Reset R_AL/RC_CAL Engine */ |
---|
76 | | - bcm_phy_write_exp_sel(phydev, 0x00b0, 0x0000); |
---|
77 | | -} |
---|
78 | | - |
---|
79 | | -static int bcm7xxx_28nm_b0_afe_config_init(struct phy_device *phydev) |
---|
80 | | -{ |
---|
81 | | - /* Increase VCO range to prevent unlocking problem of PLL at low |
---|
82 | | - * temp |
---|
83 | | - */ |
---|
84 | | - bcm_phy_write_misc(phydev, PLL_PLLCTRL_1, 0x0048); |
---|
85 | | - |
---|
86 | | - /* Change Ki to 011 */ |
---|
87 | | - bcm_phy_write_misc(phydev, PLL_PLLCTRL_2, 0x021b); |
---|
88 | | - |
---|
89 | | - /* Disable loading of TVCO buffer to bandgap, set bandgap trim |
---|
90 | | - * to 111 |
---|
91 | | - */ |
---|
92 | | - bcm_phy_write_misc(phydev, PLL_PLLCTRL_4, 0x0e20); |
---|
93 | | - |
---|
94 | | - /* Adjust bias current trim by -3 */ |
---|
95 | | - bcm_phy_write_misc(phydev, DSP_TAP10, 0x690b); |
---|
96 | | - |
---|
97 | | - /* Switch to CORE_BASE1E */ |
---|
98 | | - phy_write(phydev, MII_BRCM_CORE_BASE1E, 0xd); |
---|
99 | | - |
---|
100 | | - r_rc_cal_reset(phydev); |
---|
101 | | - |
---|
102 | | - /* write AFE_RXCONFIG_0 */ |
---|
103 | | - bcm_phy_write_misc(phydev, AFE_RXCONFIG_0, 0xeb19); |
---|
104 | | - |
---|
105 | | - /* write AFE_RXCONFIG_1 */ |
---|
106 | | - bcm_phy_write_misc(phydev, AFE_RXCONFIG_1, 0x9a3f); |
---|
107 | | - |
---|
108 | | - /* write AFE_RX_LP_COUNTER */ |
---|
109 | | - bcm_phy_write_misc(phydev, AFE_RX_LP_COUNTER, 0x7fc0); |
---|
110 | | - |
---|
111 | | - /* write AFE_HPF_TRIM_OTHERS */ |
---|
112 | | - bcm_phy_write_misc(phydev, AFE_HPF_TRIM_OTHERS, 0x000b); |
---|
113 | | - |
---|
114 | | - /* write AFTE_TX_CONFIG */ |
---|
115 | | - bcm_phy_write_misc(phydev, AFE_TX_CONFIG, 0x0800); |
---|
116 | | - |
---|
117 | | - return 0; |
---|
118 | | -} |
---|
119 | 50 | |
---|
120 | 51 | static int bcm7xxx_28nm_d0_afe_config_init(struct phy_device *phydev) |
---|
121 | 52 | { |
---|
.. | .. |
---|
152 | 83 | bcm_phy_write_misc(phydev, DSP_TAP10, 0x011b); |
---|
153 | 84 | |
---|
154 | 85 | /* Reset R_CAL/RC_CAL engine */ |
---|
155 | | - r_rc_cal_reset(phydev); |
---|
| 86 | + bcm_phy_r_rc_cal_reset(phydev); |
---|
156 | 87 | |
---|
157 | 88 | return 0; |
---|
158 | 89 | } |
---|
.. | .. |
---|
180 | 111 | bcm_phy_write_misc(phydev, DSP_TAP10, 0x011b); |
---|
181 | 112 | |
---|
182 | 113 | /* Reset R_CAL/RC_CAL engine */ |
---|
183 | | - r_rc_cal_reset(phydev); |
---|
| 114 | + bcm_phy_r_rc_cal_reset(phydev); |
---|
184 | 115 | |
---|
185 | 116 | return 0; |
---|
186 | 117 | } |
---|
.. | .. |
---|
205 | 136 | /* Enable ffe zero detection for Vitesse interoperability */ |
---|
206 | 137 | bcm_phy_write_misc(phydev, 0x26, 0x2, 0x0015); |
---|
207 | 138 | |
---|
208 | | - r_rc_cal_reset(phydev); |
---|
| 139 | + bcm_phy_r_rc_cal_reset(phydev); |
---|
209 | 140 | |
---|
210 | 141 | return 0; |
---|
211 | 142 | } |
---|
.. | .. |
---|
236 | 167 | switch (rev) { |
---|
237 | 168 | case 0xa0: |
---|
238 | 169 | case 0xb0: |
---|
239 | | - ret = bcm7xxx_28nm_b0_afe_config_init(phydev); |
---|
| 170 | + ret = bcm_phy_28nm_a0b0_afe_config_init(phydev); |
---|
240 | 171 | break; |
---|
241 | 172 | case 0xd0: |
---|
242 | 173 | ret = bcm7xxx_28nm_d0_afe_config_init(phydev); |
---|
.. | .. |
---|
254 | 185 | break; |
---|
255 | 186 | } |
---|
256 | 187 | |
---|
| 188 | + if (ret) |
---|
| 189 | + return ret; |
---|
| 190 | + |
---|
| 191 | + ret = bcm_phy_enable_jumbo(phydev); |
---|
257 | 192 | if (ret) |
---|
258 | 193 | return ret; |
---|
259 | 194 | |
---|
.. | .. |
---|
286 | 221 | return genphy_config_aneg(phydev); |
---|
287 | 222 | } |
---|
288 | 223 | |
---|
289 | | -static int phy_set_clr_bits(struct phy_device *dev, int location, |
---|
290 | | - int set_mask, int clr_mask) |
---|
| 224 | +static int __phy_set_clr_bits(struct phy_device *dev, int location, |
---|
| 225 | + int set_mask, int clr_mask) |
---|
291 | 226 | { |
---|
292 | 227 | int v, ret; |
---|
293 | 228 | |
---|
294 | | - v = phy_read(dev, location); |
---|
| 229 | + v = __phy_read(dev, location); |
---|
295 | 230 | if (v < 0) |
---|
296 | 231 | return v; |
---|
297 | 232 | |
---|
298 | 233 | v &= ~clr_mask; |
---|
299 | 234 | v |= set_mask; |
---|
300 | 235 | |
---|
301 | | - ret = phy_write(dev, location, v); |
---|
| 236 | + ret = __phy_write(dev, location, v); |
---|
302 | 237 | if (ret < 0) |
---|
303 | 238 | return ret; |
---|
304 | 239 | |
---|
305 | 240 | return v; |
---|
| 241 | +} |
---|
| 242 | + |
---|
| 243 | +static int phy_set_clr_bits(struct phy_device *dev, int location, |
---|
| 244 | + int set_mask, int clr_mask) |
---|
| 245 | +{ |
---|
| 246 | + int ret; |
---|
| 247 | + |
---|
| 248 | + mutex_lock(&dev->mdio.bus->mdio_lock); |
---|
| 249 | + ret = __phy_set_clr_bits(dev, location, set_mask, clr_mask); |
---|
| 250 | + mutex_unlock(&dev->mdio.bus->mdio_lock); |
---|
| 251 | + |
---|
| 252 | + return ret; |
---|
306 | 253 | } |
---|
307 | 254 | |
---|
308 | 255 | static int bcm7xxx_28nm_ephy_01_afe_config_init(struct phy_device *phydev) |
---|
.. | .. |
---|
506 | 453 | return -EOPNOTSUPP; |
---|
507 | 454 | |
---|
508 | 455 | /* set shadow mode 2 */ |
---|
509 | | - ret = phy_set_clr_bits(phydev, MII_BCM7XXX_TEST, |
---|
510 | | - MII_BCM7XXX_SHD_MODE_2, 0); |
---|
| 456 | + ret = __phy_set_clr_bits(phydev, MII_BCM7XXX_TEST, |
---|
| 457 | + MII_BCM7XXX_SHD_MODE_2, 0); |
---|
511 | 458 | if (ret < 0) |
---|
512 | 459 | return ret; |
---|
513 | 460 | |
---|
514 | 461 | /* Access the desired shadow register address */ |
---|
515 | | - ret = phy_write(phydev, MII_BCM7XXX_SHD_2_ADDR_CTRL, shd); |
---|
| 462 | + ret = __phy_write(phydev, MII_BCM7XXX_SHD_2_ADDR_CTRL, shd); |
---|
516 | 463 | if (ret < 0) |
---|
517 | 464 | goto reset_shadow_mode; |
---|
518 | 465 | |
---|
519 | | - ret = phy_read(phydev, MII_BCM7XXX_SHD_2_CTRL_STAT); |
---|
| 466 | + ret = __phy_read(phydev, MII_BCM7XXX_SHD_2_CTRL_STAT); |
---|
520 | 467 | |
---|
521 | 468 | reset_shadow_mode: |
---|
522 | 469 | /* reset shadow mode 2 */ |
---|
523 | | - phy_set_clr_bits(phydev, MII_BCM7XXX_TEST, 0, |
---|
524 | | - MII_BCM7XXX_SHD_MODE_2); |
---|
| 470 | + __phy_set_clr_bits(phydev, MII_BCM7XXX_TEST, 0, |
---|
| 471 | + MII_BCM7XXX_SHD_MODE_2); |
---|
525 | 472 | return ret; |
---|
526 | 473 | } |
---|
527 | 474 | |
---|
.. | .. |
---|
536 | 483 | return -EOPNOTSUPP; |
---|
537 | 484 | |
---|
538 | 485 | /* set shadow mode 2 */ |
---|
539 | | - ret = phy_set_clr_bits(phydev, MII_BCM7XXX_TEST, |
---|
540 | | - MII_BCM7XXX_SHD_MODE_2, 0); |
---|
| 486 | + ret = __phy_set_clr_bits(phydev, MII_BCM7XXX_TEST, |
---|
| 487 | + MII_BCM7XXX_SHD_MODE_2, 0); |
---|
541 | 488 | if (ret < 0) |
---|
542 | 489 | return ret; |
---|
543 | 490 | |
---|
544 | 491 | /* Access the desired shadow register address */ |
---|
545 | | - ret = phy_write(phydev, MII_BCM7XXX_SHD_2_ADDR_CTRL, shd); |
---|
| 492 | + ret = __phy_write(phydev, MII_BCM7XXX_SHD_2_ADDR_CTRL, shd); |
---|
546 | 493 | if (ret < 0) |
---|
547 | 494 | goto reset_shadow_mode; |
---|
548 | 495 | |
---|
549 | 496 | /* Write the desired value in the shadow register */ |
---|
550 | | - phy_write(phydev, MII_BCM7XXX_SHD_2_CTRL_STAT, val); |
---|
| 497 | + __phy_write(phydev, MII_BCM7XXX_SHD_2_CTRL_STAT, val); |
---|
551 | 498 | |
---|
552 | 499 | reset_shadow_mode: |
---|
553 | 500 | /* reset shadow mode 2 */ |
---|
554 | | - return phy_set_clr_bits(phydev, MII_BCM7XXX_TEST, 0, |
---|
555 | | - MII_BCM7XXX_SHD_MODE_2); |
---|
| 501 | + return __phy_set_clr_bits(phydev, MII_BCM7XXX_TEST, 0, |
---|
| 502 | + MII_BCM7XXX_SHD_MODE_2); |
---|
556 | 503 | } |
---|
557 | 504 | |
---|
558 | 505 | static int bcm7xxx_28nm_ephy_resume(struct phy_device *phydev) |
---|
.. | .. |
---|
680 | 627 | static int bcm7xxx_28nm_probe(struct phy_device *phydev) |
---|
681 | 628 | { |
---|
682 | 629 | struct bcm7xxx_phy_priv *priv; |
---|
| 630 | + int ret = 0; |
---|
683 | 631 | |
---|
684 | 632 | priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL); |
---|
685 | 633 | if (!priv) |
---|
.. | .. |
---|
693 | 641 | if (!priv->stats) |
---|
694 | 642 | return -ENOMEM; |
---|
695 | 643 | |
---|
696 | | - return 0; |
---|
| 644 | + priv->clk = devm_clk_get_optional(&phydev->mdio.dev, NULL); |
---|
| 645 | + if (IS_ERR(priv->clk)) |
---|
| 646 | + return PTR_ERR(priv->clk); |
---|
| 647 | + |
---|
| 648 | + ret = clk_prepare_enable(priv->clk); |
---|
| 649 | + if (ret) |
---|
| 650 | + return ret; |
---|
| 651 | + |
---|
| 652 | + /* Dummy read to a register to workaround an issue upon reset where the |
---|
| 653 | + * internal inverter may not allow the first MDIO transaction to pass |
---|
| 654 | + * the MDIO management controller and make us return 0xffff for such |
---|
| 655 | + * reads. This is needed to ensure that any subsequent reads to the |
---|
| 656 | + * PHY will succeed. |
---|
| 657 | + */ |
---|
| 658 | + phy_read(phydev, MII_BMSR); |
---|
| 659 | + |
---|
| 660 | + return ret; |
---|
| 661 | +} |
---|
| 662 | + |
---|
| 663 | +static void bcm7xxx_28nm_remove(struct phy_device *phydev) |
---|
| 664 | +{ |
---|
| 665 | + struct bcm7xxx_phy_priv *priv = phydev->priv; |
---|
| 666 | + |
---|
| 667 | + clk_disable_unprepare(priv->clk); |
---|
697 | 668 | } |
---|
698 | 669 | |
---|
699 | 670 | #define BCM7XXX_28NM_GPHY(_oui, _name) \ |
---|
.. | .. |
---|
701 | 672 | .phy_id = (_oui), \ |
---|
702 | 673 | .phy_id_mask = 0xfffffff0, \ |
---|
703 | 674 | .name = _name, \ |
---|
704 | | - .features = PHY_GBIT_FEATURES, \ |
---|
| 675 | + /* PHY_GBIT_FEATURES */ \ |
---|
705 | 676 | .flags = PHY_IS_INTERNAL, \ |
---|
706 | 677 | .config_init = bcm7xxx_28nm_config_init, \ |
---|
707 | 678 | .resume = bcm7xxx_28nm_resume, \ |
---|
.. | .. |
---|
711 | 682 | .get_strings = bcm_phy_get_strings, \ |
---|
712 | 683 | .get_stats = bcm7xxx_28nm_get_phy_stats, \ |
---|
713 | 684 | .probe = bcm7xxx_28nm_probe, \ |
---|
| 685 | + .remove = bcm7xxx_28nm_remove, \ |
---|
714 | 686 | } |
---|
715 | 687 | |
---|
716 | 688 | #define BCM7XXX_28NM_EPHY(_oui, _name) \ |
---|
.. | .. |
---|
718 | 690 | .phy_id = (_oui), \ |
---|
719 | 691 | .phy_id_mask = 0xfffffff0, \ |
---|
720 | 692 | .name = _name, \ |
---|
721 | | - .features = PHY_BASIC_FEATURES, \ |
---|
| 693 | + /* PHY_BASIC_FEATURES */ \ |
---|
722 | 694 | .flags = PHY_IS_INTERNAL, \ |
---|
723 | 695 | .config_init = bcm7xxx_28nm_ephy_config_init, \ |
---|
724 | 696 | .resume = bcm7xxx_28nm_ephy_resume, \ |
---|
.. | .. |
---|
726 | 698 | .get_strings = bcm_phy_get_strings, \ |
---|
727 | 699 | .get_stats = bcm7xxx_28nm_get_phy_stats, \ |
---|
728 | 700 | .probe = bcm7xxx_28nm_probe, \ |
---|
| 701 | + .remove = bcm7xxx_28nm_remove, \ |
---|
729 | 702 | .read_mmd = bcm7xxx_28nm_ephy_read_mmd, \ |
---|
730 | 703 | .write_mmd = bcm7xxx_28nm_ephy_write_mmd, \ |
---|
731 | 704 | } |
---|
.. | .. |
---|
735 | 708 | .phy_id = (_oui), \ |
---|
736 | 709 | .phy_id_mask = 0xfffffff0, \ |
---|
737 | 710 | .name = _name, \ |
---|
738 | | - .features = PHY_BASIC_FEATURES, \ |
---|
| 711 | + /* PHY_BASIC_FEATURES */ \ |
---|
739 | 712 | .flags = PHY_IS_INTERNAL, \ |
---|
740 | 713 | .soft_reset = genphy_soft_reset, \ |
---|
741 | 714 | .config_init = bcm7xxx_config_init, \ |
---|
.. | .. |
---|
744 | 717 | } |
---|
745 | 718 | |
---|
746 | 719 | static struct phy_driver bcm7xxx_driver[] = { |
---|
| 720 | + BCM7XXX_28NM_EPHY(PHY_ID_BCM72113, "Broadcom BCM72113"), |
---|
747 | 721 | BCM7XXX_28NM_GPHY(PHY_ID_BCM7250, "Broadcom BCM7250"), |
---|
| 722 | + BCM7XXX_28NM_EPHY(PHY_ID_BCM7255, "Broadcom BCM7255"), |
---|
748 | 723 | BCM7XXX_28NM_EPHY(PHY_ID_BCM7260, "Broadcom BCM7260"), |
---|
749 | 724 | BCM7XXX_28NM_EPHY(PHY_ID_BCM7268, "Broadcom BCM7268"), |
---|
750 | 725 | BCM7XXX_28NM_EPHY(PHY_ID_BCM7271, "Broadcom BCM7271"), |
---|
.. | .. |
---|
755 | 730 | BCM7XXX_28NM_GPHY(PHY_ID_BCM7439, "Broadcom BCM7439"), |
---|
756 | 731 | BCM7XXX_28NM_GPHY(PHY_ID_BCM7439_2, "Broadcom BCM7439 (2)"), |
---|
757 | 732 | BCM7XXX_28NM_GPHY(PHY_ID_BCM7445, "Broadcom BCM7445"), |
---|
758 | | - BCM7XXX_28NM_GPHY(PHY_ID_BCM_OMEGA, "Broadcom Omega Combo GPHY"), |
---|
759 | 733 | BCM7XXX_40NM_EPHY(PHY_ID_BCM7346, "Broadcom BCM7346"), |
---|
760 | 734 | BCM7XXX_40NM_EPHY(PHY_ID_BCM7362, "Broadcom BCM7362"), |
---|
761 | 735 | BCM7XXX_40NM_EPHY(PHY_ID_BCM7425, "Broadcom BCM7425"), |
---|
.. | .. |
---|
764 | 738 | }; |
---|
765 | 739 | |
---|
766 | 740 | static struct mdio_device_id __maybe_unused bcm7xxx_tbl[] = { |
---|
| 741 | + { PHY_ID_BCM72113, 0xfffffff0 }, |
---|
767 | 742 | { PHY_ID_BCM7250, 0xfffffff0, }, |
---|
| 743 | + { PHY_ID_BCM7255, 0xfffffff0, }, |
---|
768 | 744 | { PHY_ID_BCM7260, 0xfffffff0, }, |
---|
769 | 745 | { PHY_ID_BCM7268, 0xfffffff0, }, |
---|
770 | 746 | { PHY_ID_BCM7271, 0xfffffff0, }, |
---|