kernel: bump 5.4 to 5.4.71
[openwrt/openwrt.git] / target / linux / generic / pending-5.4 / 752-net-phy-add-Broadcom-BCM84881-PHY-driver.patch
1 From 75f4d8d10e016f7428c268424483a927ee7a78bb Mon Sep 17 00:00:00 2001
2 From: Russell King <rmk+kernel@armlinux.org.uk>
3 Date: Wed, 11 Dec 2019 10:56:56 +0000
4 Subject: [PATCH] net: phy: add Broadcom BCM84881 PHY driver
5
6 Add a rudimentary Clause 45 driver for the BCM84881 PHY, found on
7 Methode DM7052 SFPs.
8
9 Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
10 Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
11 Signed-off-by: David S. Miller <davem@davemloft.net>
12 ---
13 drivers/net/phy/Kconfig | 6 +
14 drivers/net/phy/Makefile | 1 +
15 drivers/net/phy/bcm84881.c | 269 +++++++++++++++++++++++++++++++++++++
16 3 files changed, 276 insertions(+)
17 create mode 100644 drivers/net/phy/bcm84881.c
18
19 --- a/drivers/net/phy/Kconfig
20 +++ b/drivers/net/phy/Kconfig
21 @@ -330,6 +330,12 @@ config BROADCOM_PHY
22 Currently supports the BCM5411, BCM5421, BCM5461, BCM54616S, BCM5464,
23 BCM5481, BCM54810 and BCM5482 PHYs.
24
25 +config BCM84881_PHY
26 + tristate "Broadcom BCM84881 PHY"
27 + depends on PHYLIB
28 + ---help---
29 + Support the Broadcom BCM84881 PHY.
30 +
31 config CICADA_PHY
32 tristate "Cicada PHYs"
33 ---help---
34 --- a/drivers/net/phy/Makefile
35 +++ b/drivers/net/phy/Makefile
36 @@ -62,6 +62,7 @@ obj-$(CONFIG_BCM87XX_PHY) += bcm87xx.o
37 obj-$(CONFIG_BCM_CYGNUS_PHY) += bcm-cygnus.o
38 obj-$(CONFIG_BCM_NET_PHYLIB) += bcm-phy-lib.o
39 obj-$(CONFIG_BROADCOM_PHY) += broadcom.o
40 +obj-$(CONFIG_BCM84881_PHY) += bcm84881.o
41 obj-$(CONFIG_CICADA_PHY) += cicada.o
42 obj-$(CONFIG_CORTINA_PHY) += cortina.o
43 obj-$(CONFIG_DAVICOM_PHY) += davicom.o
44 --- /dev/null
45 +++ b/drivers/net/phy/bcm84881.c
46 @@ -0,0 +1,269 @@
47 +// SPDX-License-Identifier: GPL-2.0
48 +// Broadcom BCM84881 NBASE-T PHY driver, as found on a SFP+ module.
49 +// Copyright (C) 2019 Russell King, Deep Blue Solutions Ltd.
50 +//
51 +// Like the Marvell 88x3310, the Broadcom 84881 changes its host-side
52 +// interface according to the operating speed between 10GBASE-R,
53 +// 2500BASE-X and SGMII (but unlike the 88x3310, without the control
54 +// word).
55 +//
56 +// This driver only supports those aspects of the PHY that I'm able to
57 +// observe and test with the SFP+ module, which is an incomplete subset
58 +// of what this PHY is able to support. For example, I only assume it
59 +// supports a single lane Serdes connection, but it may be that the PHY
60 +// is able to support more than that.
61 +#include <linux/delay.h>
62 +#include <linux/module.h>
63 +#include <linux/phy.h>
64 +
65 +enum {
66 + MDIO_AN_C22 = 0xffe0,
67 +};
68 +
69 +static int bcm84881_wait_init(struct phy_device *phydev)
70 +{
71 + unsigned int tries = 20;
72 + int ret, val;
73 +
74 + do {
75 + val = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_CTRL1);
76 + if (val < 0) {
77 + ret = val;
78 + break;
79 + }
80 + if (!(val & MDIO_CTRL1_RESET)) {
81 + ret = 0;
82 + break;
83 + }
84 + if (!--tries) {
85 + ret = -ETIMEDOUT;
86 + break;
87 + }
88 + msleep(100);
89 + } while (1);
90 +
91 + if (ret)
92 + phydev_err(phydev, "%s failed: %d\n", __func__, ret);
93 +
94 + return ret;
95 +}
96 +
97 +static int bcm84881_config_init(struct phy_device *phydev)
98 +{
99 + switch (phydev->interface) {
100 + case PHY_INTERFACE_MODE_SGMII:
101 + case PHY_INTERFACE_MODE_2500BASEX:
102 + case PHY_INTERFACE_MODE_10GKR:
103 + break;
104 + default:
105 + return -ENODEV;
106 + }
107 + return 0;
108 +}
109 +
110 +static int bcm84881_probe(struct phy_device *phydev)
111 +{
112 + /* This driver requires PMAPMD and AN blocks */
113 + const u32 mmd_mask = MDIO_DEVS_PMAPMD | MDIO_DEVS_AN;
114 +
115 + if (!phydev->is_c45 ||
116 + (phydev->c45_ids.devices_in_package & mmd_mask) != mmd_mask)
117 + return -ENODEV;
118 +
119 + return 0;
120 +}
121 +
122 +static int bcm84881_get_features(struct phy_device *phydev)
123 +{
124 + int ret;
125 +
126 + ret = genphy_c45_pma_read_abilities(phydev);
127 + if (ret)
128 + return ret;
129 +
130 + /* Although the PHY sets bit 1.11.8, it does not support 10M modes */
131 + linkmode_clear_bit(ETHTOOL_LINK_MODE_10baseT_Half_BIT,
132 + phydev->supported);
133 + linkmode_clear_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT,
134 + phydev->supported);
135 +
136 + return 0;
137 +}
138 +
139 +static int bcm84881_config_aneg(struct phy_device *phydev)
140 +{
141 + bool changed = false;
142 + u32 adv;
143 + int ret;
144 +
145 + /* Wait for the PHY to finish initialising, otherwise our
146 + * advertisement may be overwritten.
147 + */
148 + ret = bcm84881_wait_init(phydev);
149 + if (ret)
150 + return ret;
151 +
152 + /* We don't support manual MDI control */
153 + phydev->mdix_ctrl = ETH_TP_MDI_AUTO;
154 +
155 + /* disabled autoneg doesn't seem to work with this PHY */
156 + if (phydev->autoneg == AUTONEG_DISABLE)
157 + return -EINVAL;
158 +
159 + ret = genphy_c45_an_config_aneg(phydev);
160 + if (ret < 0)
161 + return ret;
162 + if (ret > 0)
163 + changed = true;
164 +
165 + adv = linkmode_adv_to_mii_ctrl1000_t(phydev->advertising);
166 + ret = phy_modify_mmd_changed(phydev, MDIO_MMD_AN,
167 + MDIO_AN_C22 + MII_CTRL1000,
168 + ADVERTISE_1000FULL | ADVERTISE_1000HALF,
169 + adv);
170 + if (ret < 0)
171 + return ret;
172 + if (ret > 0)
173 + changed = true;
174 +
175 + return genphy_c45_check_and_restart_aneg(phydev, changed);
176 +}
177 +
178 +static int bcm84881_aneg_done(struct phy_device *phydev)
179 +{
180 + int bmsr, val;
181 +
182 + val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_STAT1);
183 + if (val < 0)
184 + return val;
185 +
186 + bmsr = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_C22 + MII_BMSR);
187 + if (bmsr < 0)
188 + return val;
189 +
190 + return !!(val & MDIO_AN_STAT1_COMPLETE) &&
191 + !!(bmsr & BMSR_ANEGCOMPLETE);
192 +}
193 +
194 +static int bcm84881_read_status(struct phy_device *phydev)
195 +{
196 + unsigned int mode;
197 + int bmsr, val;
198 +
199 + val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_CTRL1);
200 + if (val < 0)
201 + return val;
202 +
203 + if (val & MDIO_AN_CTRL1_RESTART) {
204 + phydev->link = 0;
205 + return 0;
206 + }
207 +
208 + val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_STAT1);
209 + if (val < 0)
210 + return val;
211 +
212 + bmsr = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_C22 + MII_BMSR);
213 + if (bmsr < 0)
214 + return val;
215 +
216 + phydev->autoneg_complete = !!(val & MDIO_AN_STAT1_COMPLETE) &&
217 + !!(bmsr & BMSR_ANEGCOMPLETE);
218 + phydev->link = !!(val & MDIO_STAT1_LSTATUS) &&
219 + !!(bmsr & BMSR_LSTATUS);
220 + if (phydev->autoneg == AUTONEG_ENABLE && !phydev->autoneg_complete)
221 + phydev->link = false;
222 +
223 + if (!phydev->link)
224 + return 0;
225 +
226 + linkmode_zero(phydev->lp_advertising);
227 + phydev->speed = SPEED_UNKNOWN;
228 + phydev->duplex = DUPLEX_UNKNOWN;
229 + phydev->pause = 0;
230 + phydev->asym_pause = 0;
231 + phydev->mdix = 0;
232 +
233 + if (phydev->autoneg_complete) {
234 + val = genphy_c45_read_lpa(phydev);
235 + if (val < 0)
236 + return val;
237 +
238 + val = phy_read_mmd(phydev, MDIO_MMD_AN,
239 + MDIO_AN_C22 + MII_STAT1000);
240 + if (val < 0)
241 + return val;
242 +
243 + mii_stat1000_mod_linkmode_lpa_t(phydev->lp_advertising, val);
244 +
245 + if (phydev->autoneg == AUTONEG_ENABLE)
246 + phy_resolve_aneg_linkmode(phydev);
247 + }
248 +
249 + if (phydev->autoneg == AUTONEG_DISABLE) {
250 + /* disabled autoneg doesn't seem to work, so force the link
251 + * down.
252 + */
253 + phydev->link = 0;
254 + return 0;
255 + }
256 +
257 + /* Set the host link mode - we set the phy interface mode and
258 + * the speed according to this register so that downshift works.
259 + * We leave the duplex setting as per the resolution from the
260 + * above.
261 + */
262 + val = phy_read_mmd(phydev, MDIO_MMD_VEND1, 0x4011);
263 + mode = (val & 0x1e) >> 1;
264 + if (mode == 1 || mode == 2)
265 + phydev->interface = PHY_INTERFACE_MODE_SGMII;
266 + else if (mode == 3)
267 + phydev->interface = PHY_INTERFACE_MODE_10GKR;
268 + else if (mode == 4)
269 + phydev->interface = PHY_INTERFACE_MODE_2500BASEX;
270 + switch (mode & 7) {
271 + case 1:
272 + phydev->speed = SPEED_100;
273 + break;
274 + case 2:
275 + phydev->speed = SPEED_1000;
276 + break;
277 + case 3:
278 + phydev->speed = SPEED_10000;
279 + break;
280 + case 4:
281 + phydev->speed = SPEED_2500;
282 + break;
283 + case 5:
284 + phydev->speed = SPEED_5000;
285 + break;
286 + }
287 +
288 + return genphy_c45_read_mdix(phydev);
289 +}
290 +
291 +static struct phy_driver bcm84881_drivers[] = {
292 + {
293 + .phy_id = 0xae025150,
294 + .phy_id_mask = 0xfffffff0,
295 + .name = "Broadcom BCM84881",
296 + .config_init = bcm84881_config_init,
297 + .probe = bcm84881_probe,
298 + .get_features = bcm84881_get_features,
299 + .config_aneg = bcm84881_config_aneg,
300 + .aneg_done = bcm84881_aneg_done,
301 + .read_status = bcm84881_read_status,
302 + },
303 +};
304 +
305 +module_phy_driver(bcm84881_drivers);
306 +
307 +/* FIXME: module auto-loading for Clause 45 PHYs seems non-functional */
308 +static struct mdio_device_id __maybe_unused bcm84881_tbl[] = {
309 + { 0xae025150, 0xfffffff0 },
310 + { },
311 +};
312 +MODULE_AUTHOR("Russell King");
313 +MODULE_DESCRIPTION("Broadcom BCM84881 PHY driver");
314 +MODULE_DEVICE_TABLE(mdio, bcm84881_tbl);
315 +MODULE_LICENSE("GPL");