blob: 0e0bcc304d6c8c94ca269ab12dcb3a5868aa006a [file] [log] [blame]
b.liue9582032025-04-17 19:18:16 +08001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * drivers/net/phy/broadcom.c
4 *
5 * Broadcom BCM5411, BCM5421 and BCM5461 Gigabit Ethernet
6 * transceivers.
7 *
8 * Copyright (c) 2006 Maciej W. Rozycki
9 *
10 * Inspired by code written by Amy Fong.
11 */
12
13#include "bcm-phy-lib.h"
14#include <linux/delay.h>
15#include <linux/module.h>
16#include <linux/phy.h>
17#include <linux/brcmphy.h>
18#include <linux/of.h>
19
20#define BRCM_PHY_MODEL(phydev) \
21 ((phydev)->drv->phy_id & (phydev)->drv->phy_id_mask)
22
23#define BRCM_PHY_REV(phydev) \
24 ((phydev)->drv->phy_id & ~((phydev)->drv->phy_id_mask))
25
26MODULE_DESCRIPTION("Broadcom PHY driver");
27MODULE_AUTHOR("Maciej W. Rozycki");
28MODULE_LICENSE("GPL");
29
30static int bcm54xx_config_clock_delay(struct phy_device *phydev);
31
32static int bcm54210e_config_init(struct phy_device *phydev)
33{
34 int val;
35
36 bcm54xx_config_clock_delay(phydev);
37
38 if (phydev->dev_flags & PHY_BRCM_EN_MASTER_MODE) {
39 val = phy_read(phydev, MII_CTRL1000);
40 val |= CTL1000_AS_MASTER | CTL1000_ENABLE_MASTER;
41 phy_write(phydev, MII_CTRL1000, val);
42 }
43
44 return 0;
45}
46
47static int bcm54612e_config_init(struct phy_device *phydev)
48{
49 int reg;
50
51 /* Clear TX internal delay unless requested. */
52 if ((phydev->interface != PHY_INTERFACE_MODE_RGMII_ID) &&
53 (phydev->interface != PHY_INTERFACE_MODE_RGMII_TXID)) {
54 /* Disable TXD to GTXCLK clock delay (default set) */
55 /* Bit 9 is the only field in shadow register 00011 */
56 bcm_phy_write_shadow(phydev, 0x03, 0);
57 }
58
59 /* Clear RX internal delay unless requested. */
60 if ((phydev->interface != PHY_INTERFACE_MODE_RGMII_ID) &&
61 (phydev->interface != PHY_INTERFACE_MODE_RGMII_RXID)) {
62 reg = bcm54xx_auxctl_read(phydev,
63 MII_BCM54XX_AUXCTL_SHDWSEL_MISC);
64 /* Disable RXD to RXC delay (default set) */
65 reg &= ~MII_BCM54XX_AUXCTL_SHDWSEL_MISC_RGMII_SKEW_EN;
66 /* Clear shadow selector field */
67 reg &= ~MII_BCM54XX_AUXCTL_SHDWSEL_MASK;
68 bcm54xx_auxctl_write(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC,
69 MII_BCM54XX_AUXCTL_MISC_WREN | reg);
70 }
71
72 /* Enable CLK125 MUX on LED4 if ref clock is enabled. */
73 if (!(phydev->dev_flags & PHY_BRCM_RX_REFCLK_UNUSED)) {
74 int err;
75
76 reg = bcm_phy_read_exp(phydev, BCM54612E_EXP_SPARE0);
77 err = bcm_phy_write_exp(phydev, BCM54612E_EXP_SPARE0,
78 BCM54612E_LED4_CLK125OUT_EN | reg);
79
80 if (err < 0)
81 return err;
82 }
83
84 return 0;
85}
86
87static int bcm54xx_config_clock_delay(struct phy_device *phydev)
88{
89 int rc, val;
90
91 /* handling PHY's internal RX clock delay */
92 val = bcm54xx_auxctl_read(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC);
93 val |= MII_BCM54XX_AUXCTL_MISC_WREN;
94 if (phydev->interface == PHY_INTERFACE_MODE_RGMII ||
95 phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) {
96 /* Disable RGMII RXC-RXD skew */
97 val &= ~MII_BCM54XX_AUXCTL_SHDWSEL_MISC_RGMII_SKEW_EN;
98 }
99 if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
100 phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) {
101 /* Enable RGMII RXC-RXD skew */
102 val |= MII_BCM54XX_AUXCTL_SHDWSEL_MISC_RGMII_SKEW_EN;
103 }
104 rc = bcm54xx_auxctl_write(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC,
105 val);
106 if (rc < 0)
107 return rc;
108
109 /* handling PHY's internal TX clock delay */
110 val = bcm_phy_read_shadow(phydev, BCM54810_SHD_CLK_CTL);
111 if (phydev->interface == PHY_INTERFACE_MODE_RGMII ||
112 phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) {
113 /* Disable internal TX clock delay */
114 val &= ~BCM54810_SHD_CLK_CTL_GTXCLK_EN;
115 }
116 if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
117 phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) {
118 /* Enable internal TX clock delay */
119 val |= BCM54810_SHD_CLK_CTL_GTXCLK_EN;
120 }
121 rc = bcm_phy_write_shadow(phydev, BCM54810_SHD_CLK_CTL, val);
122 if (rc < 0)
123 return rc;
124
125 return 0;
126}
127
128/* Needs SMDSP clock enabled via bcm54xx_phydsp_config() */
129static int bcm50610_a0_workaround(struct phy_device *phydev)
130{
131 int err;
132
133 err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_AADJ1CH0,
134 MII_BCM54XX_EXP_AADJ1CH0_SWP_ABCD_OEN |
135 MII_BCM54XX_EXP_AADJ1CH0_SWSEL_THPF);
136 if (err < 0)
137 return err;
138
139 err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_AADJ1CH3,
140 MII_BCM54XX_EXP_AADJ1CH3_ADCCKADJ);
141 if (err < 0)
142 return err;
143
144 err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP75,
145 MII_BCM54XX_EXP_EXP75_VDACCTRL);
146 if (err < 0)
147 return err;
148
149 err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP96,
150 MII_BCM54XX_EXP_EXP96_MYST);
151 if (err < 0)
152 return err;
153
154 err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP97,
155 MII_BCM54XX_EXP_EXP97_MYST);
156
157 return err;
158}
159
160static int bcm54xx_phydsp_config(struct phy_device *phydev)
161{
162 int err, err2;
163
164 /* Enable the SMDSP clock */
165 err = bcm54xx_auxctl_write(phydev,
166 MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL,
167 MII_BCM54XX_AUXCTL_ACTL_SMDSP_ENA |
168 MII_BCM54XX_AUXCTL_ACTL_TX_6DB);
169 if (err < 0)
170 return err;
171
172 if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610 ||
173 BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610M) {
174 /* Clear bit 9 to fix a phy interop issue. */
175 err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP08,
176 MII_BCM54XX_EXP_EXP08_RJCT_2MHZ);
177 if (err < 0)
178 goto error;
179
180 if (phydev->drv->phy_id == PHY_ID_BCM50610) {
181 err = bcm50610_a0_workaround(phydev);
182 if (err < 0)
183 goto error;
184 }
185 }
186
187 if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM57780) {
188 int val;
189
190 val = bcm_phy_read_exp(phydev, MII_BCM54XX_EXP_EXP75);
191 if (val < 0)
192 goto error;
193
194 val |= MII_BCM54XX_EXP_EXP75_CM_OSC;
195 err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP75, val);
196 }
197
198error:
199 /* Disable the SMDSP clock */
200 err2 = bcm54xx_auxctl_write(phydev,
201 MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL,
202 MII_BCM54XX_AUXCTL_ACTL_TX_6DB);
203
204 /* Return the first error reported. */
205 return err ? err : err2;
206}
207
208static void bcm54xx_adjust_rxrefclk(struct phy_device *phydev)
209{
210 u32 orig;
211 int val;
212 bool clk125en = true;
213
214 /* Abort if we are using an untested phy. */
215 if (BRCM_PHY_MODEL(phydev) != PHY_ID_BCM57780 &&
216 BRCM_PHY_MODEL(phydev) != PHY_ID_BCM50610 &&
217 BRCM_PHY_MODEL(phydev) != PHY_ID_BCM50610M)
218 return;
219
220 val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_SCR3);
221 if (val < 0)
222 return;
223
224 orig = val;
225
226 if ((BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610 ||
227 BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610M) &&
228 BRCM_PHY_REV(phydev) >= 0x3) {
229 /*
230 * Here, bit 0 _disables_ CLK125 when set.
231 * This bit is set by default.
232 */
233 clk125en = false;
234 } else {
235 if (phydev->dev_flags & PHY_BRCM_RX_REFCLK_UNUSED) {
236 /* Here, bit 0 _enables_ CLK125 when set */
237 val &= ~BCM54XX_SHD_SCR3_DEF_CLK125;
238 clk125en = false;
239 }
240 }
241
242 if (!clk125en || (phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE))
243 val &= ~BCM54XX_SHD_SCR3_DLLAPD_DIS;
244 else
245 val |= BCM54XX_SHD_SCR3_DLLAPD_DIS;
246
247 if (phydev->dev_flags & PHY_BRCM_DIS_TXCRXC_NOENRGY)
248 val |= BCM54XX_SHD_SCR3_TRDDAPD;
249
250 if (orig != val)
251 bcm_phy_write_shadow(phydev, BCM54XX_SHD_SCR3, val);
252
253 val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_APD);
254 if (val < 0)
255 return;
256
257 orig = val;
258
259 if (!clk125en || (phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE))
260 val |= BCM54XX_SHD_APD_EN;
261 else
262 val &= ~BCM54XX_SHD_APD_EN;
263
264 if (orig != val)
265 bcm_phy_write_shadow(phydev, BCM54XX_SHD_APD, val);
266}
267
268static int bcm54xx_config_init(struct phy_device *phydev)
269{
270 int reg, err, val;
271
272 reg = phy_read(phydev, MII_BCM54XX_ECR);
273 if (reg < 0)
274 return reg;
275
276 /* Mask interrupts globally. */
277 reg |= MII_BCM54XX_ECR_IM;
278 err = phy_write(phydev, MII_BCM54XX_ECR, reg);
279 if (err < 0)
280 return err;
281
282 /* Unmask events we are interested in. */
283 reg = ~(MII_BCM54XX_INT_DUPLEX |
284 MII_BCM54XX_INT_SPEED |
285 MII_BCM54XX_INT_LINK);
286 err = phy_write(phydev, MII_BCM54XX_IMR, reg);
287 if (err < 0)
288 return err;
289
290 if ((BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610 ||
291 BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610M) &&
292 (phydev->dev_flags & PHY_BRCM_CLEAR_RGMII_MODE))
293 bcm_phy_write_shadow(phydev, BCM54XX_SHD_RGMII_MODE, 0);
294
295 if ((phydev->dev_flags & PHY_BRCM_RX_REFCLK_UNUSED) ||
296 (phydev->dev_flags & PHY_BRCM_DIS_TXCRXC_NOENRGY) ||
297 (phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE))
298 bcm54xx_adjust_rxrefclk(phydev);
299
300 if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM54210E) {
301 err = bcm54210e_config_init(phydev);
302 if (err)
303 return err;
304 } else if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM54612E) {
305 err = bcm54612e_config_init(phydev);
306 if (err)
307 return err;
308 } else if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM54810) {
309 /* For BCM54810, we need to disable BroadR-Reach function */
310 val = bcm_phy_read_exp(phydev,
311 BCM54810_EXP_BROADREACH_LRE_MISC_CTL);
312 val &= ~BCM54810_EXP_BROADREACH_LRE_MISC_CTL_EN;
313 err = bcm_phy_write_exp(phydev,
314 BCM54810_EXP_BROADREACH_LRE_MISC_CTL,
315 val);
316 if (err < 0)
317 return err;
318 }
319
320 bcm54xx_phydsp_config(phydev);
321
322 /* Encode link speed into LED1 and LED3 pair (green/amber).
323 * Also flash these two LEDs on activity. This means configuring
324 * them for MULTICOLOR and encoding link/activity into them.
325 */
326 val = BCM5482_SHD_LEDS1_LED1(BCM_LED_SRC_MULTICOLOR1) |
327 BCM5482_SHD_LEDS1_LED3(BCM_LED_SRC_MULTICOLOR1);
328 bcm_phy_write_shadow(phydev, BCM5482_SHD_LEDS1, val);
329
330 val = BCM_LED_MULTICOLOR_IN_PHASE |
331 BCM5482_SHD_LEDS1_LED1(BCM_LED_MULTICOLOR_LINK_ACT) |
332 BCM5482_SHD_LEDS1_LED3(BCM_LED_MULTICOLOR_LINK_ACT);
333 bcm_phy_write_exp(phydev, BCM_EXP_MULTICOLOR, val);
334
335 return 0;
336}
337
338static int bcm5482_config_init(struct phy_device *phydev)
339{
340 int err, reg;
341
342 err = bcm54xx_config_init(phydev);
343
344 if (phydev->dev_flags & PHY_BCM_FLAGS_MODE_1000BX) {
345 /*
346 * Enable secondary SerDes and its use as an LED source
347 */
348 reg = bcm_phy_read_shadow(phydev, BCM5482_SHD_SSD);
349 bcm_phy_write_shadow(phydev, BCM5482_SHD_SSD,
350 reg |
351 BCM5482_SHD_SSD_LEDM |
352 BCM5482_SHD_SSD_EN);
353
354 /*
355 * Enable SGMII slave mode and auto-detection
356 */
357 reg = BCM5482_SSD_SGMII_SLAVE | MII_BCM54XX_EXP_SEL_SSD;
358 err = bcm_phy_read_exp(phydev, reg);
359 if (err < 0)
360 return err;
361 err = bcm_phy_write_exp(phydev, reg, err |
362 BCM5482_SSD_SGMII_SLAVE_EN |
363 BCM5482_SSD_SGMII_SLAVE_AD);
364 if (err < 0)
365 return err;
366
367 /*
368 * Disable secondary SerDes powerdown
369 */
370 reg = BCM5482_SSD_1000BX_CTL | MII_BCM54XX_EXP_SEL_SSD;
371 err = bcm_phy_read_exp(phydev, reg);
372 if (err < 0)
373 return err;
374 err = bcm_phy_write_exp(phydev, reg,
375 err & ~BCM5482_SSD_1000BX_CTL_PWRDOWN);
376 if (err < 0)
377 return err;
378
379 /*
380 * Select 1000BASE-X register set (primary SerDes)
381 */
382 reg = bcm_phy_read_shadow(phydev, BCM5482_SHD_MODE);
383 bcm_phy_write_shadow(phydev, BCM5482_SHD_MODE,
384 reg | BCM5482_SHD_MODE_1000BX);
385
386 /*
387 * LED1=ACTIVITYLED, LED3=LINKSPD[2]
388 * (Use LED1 as secondary SerDes ACTIVITY LED)
389 */
390 bcm_phy_write_shadow(phydev, BCM5482_SHD_LEDS1,
391 BCM5482_SHD_LEDS1_LED1(BCM_LED_SRC_ACTIVITYLED) |
392 BCM5482_SHD_LEDS1_LED3(BCM_LED_SRC_LINKSPD2));
393
394 /*
395 * Auto-negotiation doesn't seem to work quite right
396 * in this mode, so we disable it and force it to the
397 * right speed/duplex setting. Only 'link status'
398 * is important.
399 */
400 phydev->autoneg = AUTONEG_DISABLE;
401 phydev->speed = SPEED_1000;
402 phydev->duplex = DUPLEX_FULL;
403 }
404
405 return err;
406}
407
408static int bcm5482_read_status(struct phy_device *phydev)
409{
410 int err;
411
412 err = genphy_read_status(phydev);
413
414 if (phydev->dev_flags & PHY_BCM_FLAGS_MODE_1000BX) {
415 /*
416 * Only link status matters for 1000Base-X mode, so force
417 * 1000 Mbit/s full-duplex status
418 */
419 if (phydev->link) {
420 phydev->speed = SPEED_1000;
421 phydev->duplex = DUPLEX_FULL;
422 }
423 }
424
425 return err;
426}
427
428static int bcm54810_read_mmd(struct phy_device *phydev, int devnum, u16 regnum)
429{
430 return -EOPNOTSUPP;
431}
432
433static int bcm54810_write_mmd(struct phy_device *phydev, int devnum, u16 regnum,
434 u16 val)
435{
436 return -EOPNOTSUPP;
437}
438
439static int bcm5481_config_aneg(struct phy_device *phydev)
440{
441 struct device_node *np = phydev->mdio.dev.of_node;
442 int ret;
443
444 /* Aneg firsly. */
445 ret = genphy_config_aneg(phydev);
446
447 /* Then we can set up the delay. */
448 bcm54xx_config_clock_delay(phydev);
449
450 if (of_property_read_bool(np, "enet-phy-lane-swap")) {
451 /* Lane Swap - Undocumented register...magic! */
452 ret = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_SEL_ER + 0x9,
453 0x11B);
454 if (ret < 0)
455 return ret;
456 }
457
458 return ret;
459}
460
461static int bcm54616s_config_aneg(struct phy_device *phydev)
462{
463 int ret;
464
465 /* Aneg firsly. */
466 ret = genphy_config_aneg(phydev);
467
468 /* Then we can set up the delay. */
469 bcm54xx_config_clock_delay(phydev);
470
471 return ret;
472}
473
474static int brcm_phy_setbits(struct phy_device *phydev, int reg, int set)
475{
476 int val;
477
478 val = phy_read(phydev, reg);
479 if (val < 0)
480 return val;
481
482 return phy_write(phydev, reg, val | set);
483}
484
485static int brcm_fet_config_init(struct phy_device *phydev)
486{
487 int reg, err, err2, brcmtest;
488
489 /* Reset the PHY to bring it to a known state. */
490 err = phy_write(phydev, MII_BMCR, BMCR_RESET);
491 if (err < 0)
492 return err;
493
494 /* The datasheet indicates the PHY needs up to 1us to complete a reset,
495 * build some slack here.
496 */
497 usleep_range(1000, 2000);
498
499 /* The PHY requires 65 MDC clock cycles to complete a write operation
500 * and turnaround the line properly.
501 *
502 * We ignore -EIO here as the MDIO controller (e.g.: mdio-bcm-unimac)
503 * may flag the lack of turn-around as a read failure. This is
504 * particularly true with this combination since the MDIO controller
505 * only used 64 MDC cycles. This is not a critical failure in this
506 * specific case and it has no functional impact otherwise, so we let
507 * that one go through. If there is a genuine bus error, the next read
508 * of MII_BRCM_FET_INTREG will error out.
509 */
510 err = phy_read(phydev, MII_BMCR);
511 if (err < 0 && err != -EIO)
512 return err;
513
514 reg = phy_read(phydev, MII_BRCM_FET_INTREG);
515 if (reg < 0)
516 return reg;
517
518 /* Unmask events we are interested in and mask interrupts globally. */
519 reg = MII_BRCM_FET_IR_DUPLEX_EN |
520 MII_BRCM_FET_IR_SPEED_EN |
521 MII_BRCM_FET_IR_LINK_EN |
522 MII_BRCM_FET_IR_ENABLE |
523 MII_BRCM_FET_IR_MASK;
524
525 err = phy_write(phydev, MII_BRCM_FET_INTREG, reg);
526 if (err < 0)
527 return err;
528
529 /* Enable shadow register access */
530 brcmtest = phy_read(phydev, MII_BRCM_FET_BRCMTEST);
531 if (brcmtest < 0)
532 return brcmtest;
533
534 reg = brcmtest | MII_BRCM_FET_BT_SRE;
535
536 err = phy_write(phydev, MII_BRCM_FET_BRCMTEST, reg);
537 if (err < 0)
538 return err;
539
540 /* Set the LED mode */
541 reg = phy_read(phydev, MII_BRCM_FET_SHDW_AUXMODE4);
542 if (reg < 0) {
543 err = reg;
544 goto done;
545 }
546
547 reg &= ~MII_BRCM_FET_SHDW_AM4_LED_MASK;
548 reg |= MII_BRCM_FET_SHDW_AM4_LED_MODE1;
549
550 err = phy_write(phydev, MII_BRCM_FET_SHDW_AUXMODE4, reg);
551 if (err < 0)
552 goto done;
553
554 /* Enable auto MDIX */
555 err = brcm_phy_setbits(phydev, MII_BRCM_FET_SHDW_MISCCTRL,
556 MII_BRCM_FET_SHDW_MC_FAME);
557 if (err < 0)
558 goto done;
559
560 if (phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE) {
561 /* Enable auto power down */
562 err = brcm_phy_setbits(phydev, MII_BRCM_FET_SHDW_AUXSTAT2,
563 MII_BRCM_FET_SHDW_AS2_APDE);
564 }
565
566done:
567 /* Disable shadow register access */
568 err2 = phy_write(phydev, MII_BRCM_FET_BRCMTEST, brcmtest);
569 if (!err)
570 err = err2;
571
572 return err;
573}
574
575static int brcm_fet_ack_interrupt(struct phy_device *phydev)
576{
577 int reg;
578
579 /* Clear pending interrupts. */
580 reg = phy_read(phydev, MII_BRCM_FET_INTREG);
581 if (reg < 0)
582 return reg;
583
584 return 0;
585}
586
587static int brcm_fet_config_intr(struct phy_device *phydev)
588{
589 int reg, err;
590
591 reg = phy_read(phydev, MII_BRCM_FET_INTREG);
592 if (reg < 0)
593 return reg;
594
595 if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
596 reg &= ~MII_BRCM_FET_IR_MASK;
597 else
598 reg |= MII_BRCM_FET_IR_MASK;
599
600 err = phy_write(phydev, MII_BRCM_FET_INTREG, reg);
601 return err;
602}
603
604struct bcm53xx_phy_priv {
605 u64 *stats;
606};
607
608static int bcm53xx_phy_probe(struct phy_device *phydev)
609{
610 struct bcm53xx_phy_priv *priv;
611
612 priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL);
613 if (!priv)
614 return -ENOMEM;
615
616 phydev->priv = priv;
617
618 priv->stats = devm_kcalloc(&phydev->mdio.dev,
619 bcm_phy_get_sset_count(phydev), sizeof(u64),
620 GFP_KERNEL);
621 if (!priv->stats)
622 return -ENOMEM;
623
624 return 0;
625}
626
627static void bcm53xx_phy_get_stats(struct phy_device *phydev,
628 struct ethtool_stats *stats, u64 *data)
629{
630 struct bcm53xx_phy_priv *priv = phydev->priv;
631
632 bcm_phy_get_stats(phydev, priv->stats, stats, data);
633}
634
635static struct phy_driver broadcom_drivers[] = {
636{
637 .phy_id = PHY_ID_BCM5411,
638 .phy_id_mask = 0xfffffff0,
639 .name = "Broadcom BCM5411",
640 /* PHY_GBIT_FEATURES */
641 .config_init = bcm54xx_config_init,
642 .ack_interrupt = bcm_phy_ack_intr,
643 .config_intr = bcm_phy_config_intr,
644}, {
645 .phy_id = PHY_ID_BCM5421,
646 .phy_id_mask = 0xfffffff0,
647 .name = "Broadcom BCM5421",
648 /* PHY_GBIT_FEATURES */
649 .config_init = bcm54xx_config_init,
650 .ack_interrupt = bcm_phy_ack_intr,
651 .config_intr = bcm_phy_config_intr,
652}, {
653 .phy_id = PHY_ID_BCM54210E,
654 .phy_id_mask = 0xfffffff0,
655 .name = "Broadcom BCM54210E",
656 /* PHY_GBIT_FEATURES */
657 .config_init = bcm54xx_config_init,
658 .ack_interrupt = bcm_phy_ack_intr,
659 .config_intr = bcm_phy_config_intr,
660}, {
661 .phy_id = PHY_ID_BCM5461,
662 .phy_id_mask = 0xfffffff0,
663 .name = "Broadcom BCM5461",
664 /* PHY_GBIT_FEATURES */
665 .config_init = bcm54xx_config_init,
666 .ack_interrupt = bcm_phy_ack_intr,
667 .config_intr = bcm_phy_config_intr,
668}, {
669 .phy_id = PHY_ID_BCM54612E,
670 .phy_id_mask = 0xfffffff0,
671 .name = "Broadcom BCM54612E",
672 /* PHY_GBIT_FEATURES */
673 .config_init = bcm54xx_config_init,
674 .ack_interrupt = bcm_phy_ack_intr,
675 .config_intr = bcm_phy_config_intr,
676}, {
677 .phy_id = PHY_ID_BCM54616S,
678 .phy_id_mask = 0xfffffff0,
679 .name = "Broadcom BCM54616S",
680 /* PHY_GBIT_FEATURES */
681 .soft_reset = genphy_soft_reset,
682 .config_init = bcm54xx_config_init,
683 .config_aneg = bcm54616s_config_aneg,
684 .ack_interrupt = bcm_phy_ack_intr,
685 .config_intr = bcm_phy_config_intr,
686}, {
687 .phy_id = PHY_ID_BCM5464,
688 .phy_id_mask = 0xfffffff0,
689 .name = "Broadcom BCM5464",
690 /* PHY_GBIT_FEATURES */
691 .config_init = bcm54xx_config_init,
692 .ack_interrupt = bcm_phy_ack_intr,
693 .config_intr = bcm_phy_config_intr,
694 .suspend = genphy_suspend,
695 .resume = genphy_resume,
696}, {
697 .phy_id = PHY_ID_BCM5481,
698 .phy_id_mask = 0xfffffff0,
699 .name = "Broadcom BCM5481",
700 /* PHY_GBIT_FEATURES */
701 .config_init = bcm54xx_config_init,
702 .config_aneg = bcm5481_config_aneg,
703 .ack_interrupt = bcm_phy_ack_intr,
704 .config_intr = bcm_phy_config_intr,
705}, {
706 .phy_id = PHY_ID_BCM54810,
707 .phy_id_mask = 0xfffffff0,
708 .name = "Broadcom BCM54810",
709 /* PHY_GBIT_FEATURES */
710 .read_mmd = bcm54810_read_mmd,
711 .write_mmd = bcm54810_write_mmd,
712 .config_init = bcm54xx_config_init,
713 .config_aneg = bcm5481_config_aneg,
714 .ack_interrupt = bcm_phy_ack_intr,
715 .config_intr = bcm_phy_config_intr,
716}, {
717 .phy_id = PHY_ID_BCM5482,
718 .phy_id_mask = 0xfffffff0,
719 .name = "Broadcom BCM5482",
720 /* PHY_GBIT_FEATURES */
721 .config_init = bcm5482_config_init,
722 .read_status = bcm5482_read_status,
723 .ack_interrupt = bcm_phy_ack_intr,
724 .config_intr = bcm_phy_config_intr,
725}, {
726 .phy_id = PHY_ID_BCM50610,
727 .phy_id_mask = 0xfffffff0,
728 .name = "Broadcom BCM50610",
729 /* PHY_GBIT_FEATURES */
730 .config_init = bcm54xx_config_init,
731 .ack_interrupt = bcm_phy_ack_intr,
732 .config_intr = bcm_phy_config_intr,
733}, {
734 .phy_id = PHY_ID_BCM50610M,
735 .phy_id_mask = 0xfffffff0,
736 .name = "Broadcom BCM50610M",
737 /* PHY_GBIT_FEATURES */
738 .config_init = bcm54xx_config_init,
739 .ack_interrupt = bcm_phy_ack_intr,
740 .config_intr = bcm_phy_config_intr,
741}, {
742 .phy_id = PHY_ID_BCM57780,
743 .phy_id_mask = 0xfffffff0,
744 .name = "Broadcom BCM57780",
745 /* PHY_GBIT_FEATURES */
746 .config_init = bcm54xx_config_init,
747 .ack_interrupt = bcm_phy_ack_intr,
748 .config_intr = bcm_phy_config_intr,
749}, {
750 .phy_id = PHY_ID_BCMAC131,
751 .phy_id_mask = 0xfffffff0,
752 .name = "Broadcom BCMAC131",
753 /* PHY_BASIC_FEATURES */
754 .config_init = brcm_fet_config_init,
755 .ack_interrupt = brcm_fet_ack_interrupt,
756 .config_intr = brcm_fet_config_intr,
757}, {
758 .phy_id = PHY_ID_BCM5241,
759 .phy_id_mask = 0xfffffff0,
760 .name = "Broadcom BCM5241",
761 /* PHY_BASIC_FEATURES */
762 .config_init = brcm_fet_config_init,
763 .ack_interrupt = brcm_fet_ack_interrupt,
764 .config_intr = brcm_fet_config_intr,
765}, {
766 .phy_id = PHY_ID_BCM5395,
767 .phy_id_mask = 0xfffffff0,
768 .name = "Broadcom BCM5395",
769 .flags = PHY_IS_INTERNAL,
770 /* PHY_GBIT_FEATURES */
771 .get_sset_count = bcm_phy_get_sset_count,
772 .get_strings = bcm_phy_get_strings,
773 .get_stats = bcm53xx_phy_get_stats,
774 .probe = bcm53xx_phy_probe,
775}, {
776 .phy_id = PHY_ID_BCM89610,
777 .phy_id_mask = 0xfffffff0,
778 .name = "Broadcom BCM89610",
779 /* PHY_GBIT_FEATURES */
780 .config_init = bcm54xx_config_init,
781 .ack_interrupt = bcm_phy_ack_intr,
782 .config_intr = bcm_phy_config_intr,
783} };
784
785module_phy_driver(broadcom_drivers);
786
787static struct mdio_device_id __maybe_unused broadcom_tbl[] = {
788 { PHY_ID_BCM5411, 0xfffffff0 },
789 { PHY_ID_BCM5421, 0xfffffff0 },
790 { PHY_ID_BCM54210E, 0xfffffff0 },
791 { PHY_ID_BCM5461, 0xfffffff0 },
792 { PHY_ID_BCM54612E, 0xfffffff0 },
793 { PHY_ID_BCM54616S, 0xfffffff0 },
794 { PHY_ID_BCM5464, 0xfffffff0 },
795 { PHY_ID_BCM5481, 0xfffffff0 },
796 { PHY_ID_BCM54810, 0xfffffff0 },
797 { PHY_ID_BCM5482, 0xfffffff0 },
798 { PHY_ID_BCM50610, 0xfffffff0 },
799 { PHY_ID_BCM50610M, 0xfffffff0 },
800 { PHY_ID_BCM57780, 0xfffffff0 },
801 { PHY_ID_BCMAC131, 0xfffffff0 },
802 { PHY_ID_BCM5241, 0xfffffff0 },
803 { PHY_ID_BCM5395, 0xfffffff0 },
804 { PHY_ID_BCM89610, 0xfffffff0 },
805 { }
806};
807
808MODULE_DEVICE_TABLE(mdio, broadcom_tbl);