2 * Driver for Microsemi VSC85xx PHYs
4 * Author: Nagaraju Lakkaraju
5 * License: Dual MIT/GPL
6 * Copyright (c) 2016 Microsemi Corporation
9 #include <linux/kernel.h>
10 #include <linux/module.h>
11 #include <linux/mdio.h>
12 #include <linux/mii.h>
13 #include <linux/phy.h>
15 #include <linux/netdevice.h>
16 #include <dt-bindings/net/mscc-phy-vsc8531.h>
18 enum rgmii_rx_clock_delay {
19 RGMII_RX_CLK_DELAY_0_2_NS = 0,
20 RGMII_RX_CLK_DELAY_0_8_NS = 1,
21 RGMII_RX_CLK_DELAY_1_1_NS = 2,
22 RGMII_RX_CLK_DELAY_1_7_NS = 3,
23 RGMII_RX_CLK_DELAY_2_0_NS = 4,
24 RGMII_RX_CLK_DELAY_2_3_NS = 5,
25 RGMII_RX_CLK_DELAY_2_6_NS = 6,
26 RGMII_RX_CLK_DELAY_3_4_NS = 7
29 /* Microsemi VSC85xx PHY registers */
30 /* IEEE 802. Std Registers */
31 #define MSCC_PHY_BYPASS_CONTROL 18
32 #define DISABLE_HP_AUTO_MDIX_MASK 0x0080
33 #define DISABLE_PAIR_SWAP_CORR_MASK 0x0020
34 #define DISABLE_POLARITY_CORR_MASK 0x0010
36 #define MSCC_PHY_ERR_RX_CNT 19
37 #define MSCC_PHY_ERR_FALSE_CARRIER_CNT 20
38 #define MSCC_PHY_ERR_LINK_DISCONNECT_CNT 21
39 #define ERR_CNT_MASK GENMASK(7, 0)
41 #define MSCC_PHY_EXT_PHY_CNTL_1 23
42 #define MAC_IF_SELECTION_MASK 0x1800
43 #define MAC_IF_SELECTION_GMII 0
44 #define MAC_IF_SELECTION_RMII 1
45 #define MAC_IF_SELECTION_RGMII 2
46 #define MAC_IF_SELECTION_POS 11
47 #define FAR_END_LOOPBACK_MODE_MASK 0x0008
49 #define MII_VSC85XX_INT_MASK 25
50 #define MII_VSC85XX_INT_MASK_MASK 0xa000
51 #define MII_VSC85XX_INT_MASK_WOL 0x0040
52 #define MII_VSC85XX_INT_STATUS 26
54 #define MSCC_PHY_WOL_MAC_CONTROL 27
55 #define EDGE_RATE_CNTL_POS 5
56 #define EDGE_RATE_CNTL_MASK 0x00E0
58 #define MSCC_PHY_DEV_AUX_CNTL 28
59 #define HP_AUTO_MDIX_X_OVER_IND_MASK 0x2000
61 #define MSCC_PHY_LED_MODE_SEL 29
62 #define LED_MODE_SEL_POS(x) ((x) * 4)
63 #define LED_MODE_SEL_MASK(x) (GENMASK(3, 0) << LED_MODE_SEL_POS(x))
64 #define LED_MODE_SEL(x, mode) (((mode) << LED_MODE_SEL_POS(x)) & LED_MODE_SEL_MASK(x))
66 #define MSCC_EXT_PAGE_ACCESS 31
67 #define MSCC_PHY_PAGE_STANDARD 0x0000 /* Standard registers */
68 #define MSCC_PHY_PAGE_EXTENDED 0x0001 /* Extended registers */
69 #define MSCC_PHY_PAGE_EXTENDED_2 0x0002 /* Extended reg - page 2 */
70 #define MSCC_PHY_PAGE_TR 0x52b5 /* Token ring registers */
72 /* Extended Page 1 Registers */
73 #define MSCC_PHY_CU_MEDIA_CRC_VALID_CNT 18
74 #define VALID_CRC_CNT_CRC_MASK GENMASK(13, 0)
76 #define MSCC_PHY_EXT_MODE_CNTL 19
77 #define FORCE_MDI_CROSSOVER_MASK 0x000C
78 #define FORCE_MDI_CROSSOVER_MDIX 0x000C
79 #define FORCE_MDI_CROSSOVER_MDI 0x0008
81 #define MSCC_PHY_ACTIPHY_CNTL 20
82 #define DOWNSHIFT_CNTL_MASK 0x001C
83 #define DOWNSHIFT_EN 0x0010
84 #define DOWNSHIFT_CNTL_POS 2
86 #define MSCC_PHY_EXT_PHY_CNTL_4 23
88 /* Extended Page 2 Registers */
89 #define MSCC_PHY_RGMII_CNTL 20
90 #define RGMII_RX_CLK_DELAY_MASK 0x0070
91 #define RGMII_RX_CLK_DELAY_POS 4
93 #define MSCC_PHY_WOL_LOWER_MAC_ADDR 21
94 #define MSCC_PHY_WOL_MID_MAC_ADDR 22
95 #define MSCC_PHY_WOL_UPPER_MAC_ADDR 23
96 #define MSCC_PHY_WOL_LOWER_PASSWD 24
97 #define MSCC_PHY_WOL_MID_PASSWD 25
98 #define MSCC_PHY_WOL_UPPER_PASSWD 26
100 #define MSCC_PHY_WOL_MAC_CONTROL 27
101 #define SECURE_ON_ENABLE 0x8000
102 #define SECURE_ON_PASSWD_LEN_4 0x4000
104 /* Token ring page Registers */
105 #define MSCC_PHY_TR_CNTL 16
106 #define TR_WRITE 0x8000
107 #define TR_ADDR(x) (0x7fff & (x))
108 #define MSCC_PHY_TR_LSB 17
109 #define MSCC_PHY_TR_MSB 18
111 /* Microsemi PHY ID's */
112 #define PHY_ID_VSC8530 0x00070560
113 #define PHY_ID_VSC8531 0x00070570
114 #define PHY_ID_VSC8540 0x00070760
115 #define PHY_ID_VSC8541 0x00070770
117 #define MSCC_VDDMAC_1500 1500
118 #define MSCC_VDDMAC_1800 1800
119 #define MSCC_VDDMAC_2500 2500
120 #define MSCC_VDDMAC_3300 3300
122 #define DOWNSHIFT_COUNT_MAX 5
125 #define VSC85XX_SUPP_LED_MODES (BIT(VSC8531_LINK_ACTIVITY) | \
126 BIT(VSC8531_LINK_1000_ACTIVITY) | \
127 BIT(VSC8531_LINK_100_ACTIVITY) | \
128 BIT(VSC8531_LINK_10_ACTIVITY) | \
129 BIT(VSC8531_LINK_100_1000_ACTIVITY) | \
130 BIT(VSC8531_LINK_10_1000_ACTIVITY) | \
131 BIT(VSC8531_LINK_10_100_ACTIVITY) | \
132 BIT(VSC8531_DUPLEX_COLLISION) | \
133 BIT(VSC8531_COLLISION) | \
134 BIT(VSC8531_ACTIVITY) | \
135 BIT(VSC8531_AUTONEG_FAULT) | \
136 BIT(VSC8531_SERIAL_MODE) | \
137 BIT(VSC8531_FORCE_LED_OFF) | \
138 BIT(VSC8531_FORCE_LED_ON))
145 struct vsc85xx_hw_stat {
152 static const struct vsc85xx_hw_stat vsc85xx_hw_stats[] = {
154 .string = "phy_receive_errors",
155 .reg = MSCC_PHY_ERR_RX_CNT,
156 .page = MSCC_PHY_PAGE_STANDARD,
157 .mask = ERR_CNT_MASK,
159 .string = "phy_false_carrier",
160 .reg = MSCC_PHY_ERR_FALSE_CARRIER_CNT,
161 .page = MSCC_PHY_PAGE_STANDARD,
162 .mask = ERR_CNT_MASK,
164 .string = "phy_cu_media_link_disconnect",
165 .reg = MSCC_PHY_ERR_LINK_DISCONNECT_CNT,
166 .page = MSCC_PHY_PAGE_STANDARD,
167 .mask = ERR_CNT_MASK,
169 .string = "phy_cu_media_crc_good_count",
170 .reg = MSCC_PHY_CU_MEDIA_CRC_VALID_CNT,
171 .page = MSCC_PHY_PAGE_EXTENDED,
172 .mask = VALID_CRC_CNT_CRC_MASK,
174 .string = "phy_cu_media_crc_error_count",
175 .reg = MSCC_PHY_EXT_PHY_CNTL_4,
176 .page = MSCC_PHY_PAGE_EXTENDED,
177 .mask = ERR_CNT_MASK,
181 struct vsc8531_private {
184 u32 leds_mode[MAX_LEDS];
186 const struct vsc85xx_hw_stat *hw_stats;
191 #ifdef CONFIG_OF_MDIO
192 struct vsc8531_edge_rate_table {
197 static const struct vsc8531_edge_rate_table edge_table[] = {
198 {MSCC_VDDMAC_3300, { 0, 2, 4, 7, 10, 17, 29, 53} },
199 {MSCC_VDDMAC_2500, { 0, 3, 6, 10, 14, 23, 37, 63} },
200 {MSCC_VDDMAC_1800, { 0, 5, 9, 16, 23, 35, 52, 76} },
201 {MSCC_VDDMAC_1500, { 0, 6, 14, 21, 29, 42, 58, 77} },
203 #endif /* CONFIG_OF_MDIO */
205 static int vsc85xx_phy_read_page(struct phy_device *phydev)
207 return __phy_read(phydev, MSCC_EXT_PAGE_ACCESS);
210 static int vsc85xx_phy_write_page(struct phy_device *phydev, int page)
212 return __phy_write(phydev, MSCC_EXT_PAGE_ACCESS, page);
215 static int vsc85xx_get_sset_count(struct phy_device *phydev)
217 struct vsc8531_private *priv = phydev->priv;
225 static void vsc85xx_get_strings(struct phy_device *phydev, u8 *data)
227 struct vsc8531_private *priv = phydev->priv;
233 for (i = 0; i < priv->nstats; i++)
234 strlcpy(data + i * ETH_GSTRING_LEN, priv->hw_stats[i].string,
238 static u64 vsc85xx_get_stat(struct phy_device *phydev, int i)
240 struct vsc8531_private *priv = phydev->priv;
243 val = phy_read_paged(phydev, priv->hw_stats[i].page,
244 priv->hw_stats[i].reg);
248 val = val & priv->hw_stats[i].mask;
249 priv->stats[i] += val;
251 return priv->stats[i];
254 static void vsc85xx_get_stats(struct phy_device *phydev,
255 struct ethtool_stats *stats, u64 *data)
257 struct vsc8531_private *priv = phydev->priv;
263 for (i = 0; i < priv->nstats; i++)
264 data[i] = vsc85xx_get_stat(phydev, i);
267 static int vsc85xx_led_cntl_set(struct phy_device *phydev,
274 mutex_lock(&phydev->lock);
275 reg_val = phy_read(phydev, MSCC_PHY_LED_MODE_SEL);
276 reg_val &= ~LED_MODE_SEL_MASK(led_num);
277 reg_val |= LED_MODE_SEL(led_num, (u16)mode);
278 rc = phy_write(phydev, MSCC_PHY_LED_MODE_SEL, reg_val);
279 mutex_unlock(&phydev->lock);
284 static int vsc85xx_mdix_get(struct phy_device *phydev, u8 *mdix)
288 reg_val = phy_read(phydev, MSCC_PHY_DEV_AUX_CNTL);
289 if (reg_val & HP_AUTO_MDIX_X_OVER_IND_MASK)
290 *mdix = ETH_TP_MDI_X;
297 static int vsc85xx_mdix_set(struct phy_device *phydev, u8 mdix)
302 reg_val = phy_read(phydev, MSCC_PHY_BYPASS_CONTROL);
303 if (mdix == ETH_TP_MDI || mdix == ETH_TP_MDI_X) {
304 reg_val |= (DISABLE_PAIR_SWAP_CORR_MASK |
305 DISABLE_POLARITY_CORR_MASK |
306 DISABLE_HP_AUTO_MDIX_MASK);
308 reg_val &= ~(DISABLE_PAIR_SWAP_CORR_MASK |
309 DISABLE_POLARITY_CORR_MASK |
310 DISABLE_HP_AUTO_MDIX_MASK);
312 rc = phy_write(phydev, MSCC_PHY_BYPASS_CONTROL, reg_val);
318 if (mdix == ETH_TP_MDI)
319 reg_val = FORCE_MDI_CROSSOVER_MDI;
320 else if (mdix == ETH_TP_MDI_X)
321 reg_val = FORCE_MDI_CROSSOVER_MDIX;
323 rc = phy_modify_paged(phydev, MSCC_PHY_PAGE_EXTENDED,
324 MSCC_PHY_EXT_MODE_CNTL, FORCE_MDI_CROSSOVER_MASK,
329 return genphy_restart_aneg(phydev);
332 static int vsc85xx_downshift_get(struct phy_device *phydev, u8 *count)
336 reg_val = phy_read_paged(phydev, MSCC_PHY_PAGE_EXTENDED,
337 MSCC_PHY_ACTIPHY_CNTL);
341 reg_val &= DOWNSHIFT_CNTL_MASK;
342 if (!(reg_val & DOWNSHIFT_EN))
343 *count = DOWNSHIFT_DEV_DISABLE;
345 *count = ((reg_val & ~DOWNSHIFT_EN) >> DOWNSHIFT_CNTL_POS) + 2;
350 static int vsc85xx_downshift_set(struct phy_device *phydev, u8 count)
352 if (count == DOWNSHIFT_DEV_DEFAULT_COUNT) {
353 /* Default downshift count 3 (i.e. Bit3:2 = 0b01) */
354 count = ((1 << DOWNSHIFT_CNTL_POS) | DOWNSHIFT_EN);
355 } else if (count > DOWNSHIFT_COUNT_MAX || count == 1) {
356 phydev_err(phydev, "Downshift count should be 2,3,4 or 5\n");
359 /* Downshift count is either 2,3,4 or 5 */
360 count = (((count - 2) << DOWNSHIFT_CNTL_POS) | DOWNSHIFT_EN);
363 return phy_modify_paged(phydev, MSCC_PHY_PAGE_EXTENDED,
364 MSCC_PHY_ACTIPHY_CNTL, DOWNSHIFT_CNTL_MASK,
368 static int vsc85xx_wol_set(struct phy_device *phydev,
369 struct ethtool_wolinfo *wol)
374 u16 pwd[3] = {0, 0, 0};
375 struct ethtool_wolinfo *wol_conf = wol;
376 u8 *mac_addr = phydev->attached_dev->dev_addr;
378 mutex_lock(&phydev->lock);
379 rc = phy_select_page(phydev, MSCC_PHY_PAGE_EXTENDED_2);
381 rc = phy_restore_page(phydev, rc, rc);
385 if (wol->wolopts & WAKE_MAGIC) {
386 /* Store the device address for the magic packet */
387 for (i = 0; i < ARRAY_SIZE(pwd); i++)
388 pwd[i] = mac_addr[5 - (i * 2 + 1)] << 8 |
390 __phy_write(phydev, MSCC_PHY_WOL_LOWER_MAC_ADDR, pwd[0]);
391 __phy_write(phydev, MSCC_PHY_WOL_MID_MAC_ADDR, pwd[1]);
392 __phy_write(phydev, MSCC_PHY_WOL_UPPER_MAC_ADDR, pwd[2]);
394 __phy_write(phydev, MSCC_PHY_WOL_LOWER_MAC_ADDR, 0);
395 __phy_write(phydev, MSCC_PHY_WOL_MID_MAC_ADDR, 0);
396 __phy_write(phydev, MSCC_PHY_WOL_UPPER_MAC_ADDR, 0);
399 if (wol_conf->wolopts & WAKE_MAGICSECURE) {
400 for (i = 0; i < ARRAY_SIZE(pwd); i++)
401 pwd[i] = wol_conf->sopass[5 - (i * 2 + 1)] << 8 |
402 wol_conf->sopass[5 - i * 2];
403 __phy_write(phydev, MSCC_PHY_WOL_LOWER_PASSWD, pwd[0]);
404 __phy_write(phydev, MSCC_PHY_WOL_MID_PASSWD, pwd[1]);
405 __phy_write(phydev, MSCC_PHY_WOL_UPPER_PASSWD, pwd[2]);
407 __phy_write(phydev, MSCC_PHY_WOL_LOWER_PASSWD, 0);
408 __phy_write(phydev, MSCC_PHY_WOL_MID_PASSWD, 0);
409 __phy_write(phydev, MSCC_PHY_WOL_UPPER_PASSWD, 0);
412 reg_val = __phy_read(phydev, MSCC_PHY_WOL_MAC_CONTROL);
413 if (wol_conf->wolopts & WAKE_MAGICSECURE)
414 reg_val |= SECURE_ON_ENABLE;
416 reg_val &= ~SECURE_ON_ENABLE;
417 __phy_write(phydev, MSCC_PHY_WOL_MAC_CONTROL, reg_val);
419 rc = phy_restore_page(phydev, rc, rc > 0 ? 0 : rc);
423 if (wol->wolopts & WAKE_MAGIC) {
424 /* Enable the WOL interrupt */
425 reg_val = phy_read(phydev, MII_VSC85XX_INT_MASK);
426 reg_val |= MII_VSC85XX_INT_MASK_WOL;
427 rc = phy_write(phydev, MII_VSC85XX_INT_MASK, reg_val);
431 /* Disable the WOL interrupt */
432 reg_val = phy_read(phydev, MII_VSC85XX_INT_MASK);
433 reg_val &= (~MII_VSC85XX_INT_MASK_WOL);
434 rc = phy_write(phydev, MII_VSC85XX_INT_MASK, reg_val);
438 /* Clear WOL iterrupt status */
439 reg_val = phy_read(phydev, MII_VSC85XX_INT_STATUS);
442 mutex_unlock(&phydev->lock);
447 static void vsc85xx_wol_get(struct phy_device *phydev,
448 struct ethtool_wolinfo *wol)
453 u16 pwd[3] = {0, 0, 0};
454 struct ethtool_wolinfo *wol_conf = wol;
456 mutex_lock(&phydev->lock);
457 rc = phy_select_page(phydev, MSCC_PHY_PAGE_EXTENDED_2);
461 reg_val = __phy_read(phydev, MSCC_PHY_WOL_MAC_CONTROL);
462 if (reg_val & SECURE_ON_ENABLE)
463 wol_conf->wolopts |= WAKE_MAGICSECURE;
464 if (wol_conf->wolopts & WAKE_MAGICSECURE) {
465 pwd[0] = __phy_read(phydev, MSCC_PHY_WOL_LOWER_PASSWD);
466 pwd[1] = __phy_read(phydev, MSCC_PHY_WOL_MID_PASSWD);
467 pwd[2] = __phy_read(phydev, MSCC_PHY_WOL_UPPER_PASSWD);
468 for (i = 0; i < ARRAY_SIZE(pwd); i++) {
469 wol_conf->sopass[5 - i * 2] = pwd[i] & 0x00ff;
470 wol_conf->sopass[5 - (i * 2 + 1)] = (pwd[i] & 0xff00)
476 phy_restore_page(phydev, rc, rc > 0 ? 0 : rc);
477 mutex_unlock(&phydev->lock);
480 #ifdef CONFIG_OF_MDIO
481 static int vsc85xx_edge_rate_magic_get(struct phy_device *phydev)
485 struct device *dev = &phydev->mdio.dev;
486 struct device_node *of_node = dev->of_node;
487 u8 sd_array_size = ARRAY_SIZE(edge_table[0].slowdown);
492 if (of_property_read_u32(of_node, "vsc8531,vddmac", &vdd))
493 vdd = MSCC_VDDMAC_3300;
495 if (of_property_read_u32(of_node, "vsc8531,edge-slowdown", &sd))
498 for (i = 0; i < ARRAY_SIZE(edge_table); i++)
499 if (edge_table[i].vddmac == vdd)
500 for (j = 0; j < sd_array_size; j++)
501 if (edge_table[i].slowdown[j] == sd)
502 return (sd_array_size - j - 1);
507 static int vsc85xx_dt_led_mode_get(struct phy_device *phydev,
511 struct vsc8531_private *priv = phydev->priv;
512 struct device *dev = &phydev->mdio.dev;
513 struct device_node *of_node = dev->of_node;
520 led_mode = default_mode;
521 err = of_property_read_u32(of_node, led, &led_mode);
522 if (!err && !(BIT(led_mode) & priv->supp_led_modes)) {
523 phydev_err(phydev, "DT %s invalid\n", led);
531 static int vsc85xx_edge_rate_magic_get(struct phy_device *phydev)
536 static int vsc85xx_dt_led_mode_get(struct phy_device *phydev,
542 #endif /* CONFIG_OF_MDIO */
544 static int vsc85xx_dt_led_modes_get(struct phy_device *phydev,
547 struct vsc8531_private *priv = phydev->priv;
548 char led_dt_prop[28];
551 for (i = 0; i < priv->nleds; i++) {
552 ret = sprintf(led_dt_prop, "vsc8531,led-%d-mode", i);
556 ret = vsc85xx_dt_led_mode_get(phydev, led_dt_prop,
560 priv->leds_mode[i] = ret;
566 static int vsc85xx_edge_rate_cntl_set(struct phy_device *phydev, u8 edge_rate)
570 mutex_lock(&phydev->lock);
571 rc = phy_modify_paged(phydev, MSCC_PHY_PAGE_EXTENDED_2,
572 MSCC_PHY_WOL_MAC_CONTROL, EDGE_RATE_CNTL_MASK,
573 edge_rate << EDGE_RATE_CNTL_POS);
574 mutex_unlock(&phydev->lock);
579 static int vsc85xx_mac_if_set(struct phy_device *phydev,
580 phy_interface_t interface)
585 mutex_lock(&phydev->lock);
586 reg_val = phy_read(phydev, MSCC_PHY_EXT_PHY_CNTL_1);
587 reg_val &= ~(MAC_IF_SELECTION_MASK);
589 case PHY_INTERFACE_MODE_RGMII:
590 reg_val |= (MAC_IF_SELECTION_RGMII << MAC_IF_SELECTION_POS);
592 case PHY_INTERFACE_MODE_RMII:
593 reg_val |= (MAC_IF_SELECTION_RMII << MAC_IF_SELECTION_POS);
595 case PHY_INTERFACE_MODE_MII:
596 case PHY_INTERFACE_MODE_GMII:
597 reg_val |= (MAC_IF_SELECTION_GMII << MAC_IF_SELECTION_POS);
603 rc = phy_write(phydev, MSCC_PHY_EXT_PHY_CNTL_1, reg_val);
607 rc = genphy_soft_reset(phydev);
610 mutex_unlock(&phydev->lock);
615 static int vsc85xx_default_config(struct phy_device *phydev)
620 phydev->mdix_ctrl = ETH_TP_MDI_AUTO;
621 mutex_lock(&phydev->lock);
622 rc = phy_select_page(phydev, MSCC_PHY_PAGE_EXTENDED_2);
626 reg_val = phy_read(phydev, MSCC_PHY_RGMII_CNTL);
627 reg_val &= ~(RGMII_RX_CLK_DELAY_MASK);
628 reg_val |= (RGMII_RX_CLK_DELAY_1_1_NS << RGMII_RX_CLK_DELAY_POS);
629 phy_write(phydev, MSCC_PHY_RGMII_CNTL, reg_val);
632 rc = phy_restore_page(phydev, rc, rc > 0 ? 0 : rc);
633 mutex_unlock(&phydev->lock);
638 static int vsc85xx_get_tunable(struct phy_device *phydev,
639 struct ethtool_tunable *tuna, void *data)
642 case ETHTOOL_PHY_DOWNSHIFT:
643 return vsc85xx_downshift_get(phydev, (u8 *)data);
649 static int vsc85xx_set_tunable(struct phy_device *phydev,
650 struct ethtool_tunable *tuna,
654 case ETHTOOL_PHY_DOWNSHIFT:
655 return vsc85xx_downshift_set(phydev, *(u8 *)data);
661 /* mdiobus lock should be locked when using this function */
662 static void vsc85xx_tr_write(struct phy_device *phydev, u16 addr, u32 val)
664 __phy_write(phydev, MSCC_PHY_TR_MSB, val >> 16);
665 __phy_write(phydev, MSCC_PHY_TR_LSB, val & GENMASK(15, 0));
666 __phy_write(phydev, MSCC_PHY_TR_CNTL, TR_WRITE | TR_ADDR(addr));
669 static int vsc85xx_eee_init_seq_set(struct phy_device *phydev)
671 const struct reg_val init_eee[] = {
672 {0x0f82, 0x0012b00a},
673 {0x1686, 0x00000004},
674 {0x168c, 0x00d2c46f},
675 {0x17a2, 0x00000620},
676 {0x16a0, 0x00eeffdd},
677 {0x16a6, 0x00071448},
678 {0x16a4, 0x0013132f},
679 {0x16a8, 0x00000000},
680 {0x0ffc, 0x00c0a028},
681 {0x0fe8, 0x0091b06c},
682 {0x0fea, 0x00041600},
683 {0x0f80, 0x00000af4},
684 {0x0fec, 0x00901809},
685 {0x0fee, 0x0000a6a1},
686 {0x0ffe, 0x00b01007},
687 {0x16b0, 0x00eeff00},
688 {0x16b2, 0x00007000},
689 {0x16b4, 0x00000814},
694 mutex_lock(&phydev->lock);
695 oldpage = phy_select_page(phydev, MSCC_PHY_PAGE_TR);
699 for (i = 0; i < ARRAY_SIZE(init_eee); i++)
700 vsc85xx_tr_write(phydev, init_eee[i].reg, init_eee[i].val);
703 oldpage = phy_restore_page(phydev, oldpage, oldpage);
704 mutex_unlock(&phydev->lock);
709 static int vsc85xx_config_init(struct phy_device *phydev)
712 struct vsc8531_private *vsc8531 = phydev->priv;
714 rc = vsc85xx_default_config(phydev);
718 rc = vsc85xx_mac_if_set(phydev, phydev->interface);
722 rc = vsc85xx_edge_rate_cntl_set(phydev, vsc8531->rate_magic);
726 rc = vsc85xx_eee_init_seq_set(phydev);
730 for (i = 0; i < vsc8531->nleds; i++) {
731 rc = vsc85xx_led_cntl_set(phydev, i, vsc8531->leds_mode[i]);
736 return genphy_config_init(phydev);
739 static int vsc85xx_ack_interrupt(struct phy_device *phydev)
743 if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
744 rc = phy_read(phydev, MII_VSC85XX_INT_STATUS);
746 return (rc < 0) ? rc : 0;
749 static int vsc85xx_config_intr(struct phy_device *phydev)
753 if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
754 rc = phy_write(phydev, MII_VSC85XX_INT_MASK,
755 MII_VSC85XX_INT_MASK_MASK);
757 rc = phy_write(phydev, MII_VSC85XX_INT_MASK, 0);
760 rc = phy_read(phydev, MII_VSC85XX_INT_STATUS);
766 static int vsc85xx_config_aneg(struct phy_device *phydev)
770 rc = vsc85xx_mdix_set(phydev, phydev->mdix_ctrl);
774 return genphy_config_aneg(phydev);
777 static int vsc85xx_read_status(struct phy_device *phydev)
781 rc = vsc85xx_mdix_get(phydev, &phydev->mdix);
785 return genphy_read_status(phydev);
788 static int vsc85xx_probe(struct phy_device *phydev)
790 struct vsc8531_private *vsc8531;
792 u32 default_mode[2] = {VSC8531_LINK_1000_ACTIVITY,
793 VSC8531_LINK_100_ACTIVITY};
795 rate_magic = vsc85xx_edge_rate_magic_get(phydev);
799 vsc8531 = devm_kzalloc(&phydev->mdio.dev, sizeof(*vsc8531), GFP_KERNEL);
803 phydev->priv = vsc8531;
805 vsc8531->rate_magic = rate_magic;
807 vsc8531->supp_led_modes = VSC85XX_SUPP_LED_MODES;
808 vsc8531->hw_stats = vsc85xx_hw_stats;
809 vsc8531->nstats = ARRAY_SIZE(vsc85xx_hw_stats);
810 vsc8531->stats = devm_kmalloc_array(&phydev->mdio.dev, vsc8531->nstats,
811 sizeof(u64), GFP_KERNEL);
815 return vsc85xx_dt_led_modes_get(phydev, default_mode);
818 /* Microsemi VSC85xx PHYs */
819 static struct phy_driver vsc85xx_driver[] = {
821 .phy_id = PHY_ID_VSC8530,
822 .name = "Microsemi FE VSC8530",
823 .phy_id_mask = 0xfffffff0,
824 .features = PHY_BASIC_FEATURES,
825 .flags = PHY_HAS_INTERRUPT,
826 .soft_reset = &genphy_soft_reset,
827 .config_init = &vsc85xx_config_init,
828 .config_aneg = &vsc85xx_config_aneg,
829 .aneg_done = &genphy_aneg_done,
830 .read_status = &vsc85xx_read_status,
831 .ack_interrupt = &vsc85xx_ack_interrupt,
832 .config_intr = &vsc85xx_config_intr,
833 .suspend = &genphy_suspend,
834 .resume = &genphy_resume,
835 .probe = &vsc85xx_probe,
836 .set_wol = &vsc85xx_wol_set,
837 .get_wol = &vsc85xx_wol_get,
838 .get_tunable = &vsc85xx_get_tunable,
839 .set_tunable = &vsc85xx_set_tunable,
840 .read_page = &vsc85xx_phy_read_page,
841 .write_page = &vsc85xx_phy_write_page,
842 .get_sset_count = &vsc85xx_get_sset_count,
843 .get_strings = &vsc85xx_get_strings,
844 .get_stats = &vsc85xx_get_stats,
847 .phy_id = PHY_ID_VSC8531,
848 .name = "Microsemi VSC8531",
849 .phy_id_mask = 0xfffffff0,
850 .features = PHY_GBIT_FEATURES,
851 .flags = PHY_HAS_INTERRUPT,
852 .soft_reset = &genphy_soft_reset,
853 .config_init = &vsc85xx_config_init,
854 .config_aneg = &vsc85xx_config_aneg,
855 .aneg_done = &genphy_aneg_done,
856 .read_status = &vsc85xx_read_status,
857 .ack_interrupt = &vsc85xx_ack_interrupt,
858 .config_intr = &vsc85xx_config_intr,
859 .suspend = &genphy_suspend,
860 .resume = &genphy_resume,
861 .probe = &vsc85xx_probe,
862 .set_wol = &vsc85xx_wol_set,
863 .get_wol = &vsc85xx_wol_get,
864 .get_tunable = &vsc85xx_get_tunable,
865 .set_tunable = &vsc85xx_set_tunable,
866 .read_page = &vsc85xx_phy_read_page,
867 .write_page = &vsc85xx_phy_write_page,
868 .get_sset_count = &vsc85xx_get_sset_count,
869 .get_strings = &vsc85xx_get_strings,
870 .get_stats = &vsc85xx_get_stats,
873 .phy_id = PHY_ID_VSC8540,
874 .name = "Microsemi FE VSC8540 SyncE",
875 .phy_id_mask = 0xfffffff0,
876 .features = PHY_BASIC_FEATURES,
877 .flags = PHY_HAS_INTERRUPT,
878 .soft_reset = &genphy_soft_reset,
879 .config_init = &vsc85xx_config_init,
880 .config_aneg = &vsc85xx_config_aneg,
881 .aneg_done = &genphy_aneg_done,
882 .read_status = &vsc85xx_read_status,
883 .ack_interrupt = &vsc85xx_ack_interrupt,
884 .config_intr = &vsc85xx_config_intr,
885 .suspend = &genphy_suspend,
886 .resume = &genphy_resume,
887 .probe = &vsc85xx_probe,
888 .set_wol = &vsc85xx_wol_set,
889 .get_wol = &vsc85xx_wol_get,
890 .get_tunable = &vsc85xx_get_tunable,
891 .set_tunable = &vsc85xx_set_tunable,
892 .read_page = &vsc85xx_phy_read_page,
893 .write_page = &vsc85xx_phy_write_page,
894 .get_sset_count = &vsc85xx_get_sset_count,
895 .get_strings = &vsc85xx_get_strings,
896 .get_stats = &vsc85xx_get_stats,
899 .phy_id = PHY_ID_VSC8541,
900 .name = "Microsemi VSC8541 SyncE",
901 .phy_id_mask = 0xfffffff0,
902 .features = PHY_GBIT_FEATURES,
903 .flags = PHY_HAS_INTERRUPT,
904 .soft_reset = &genphy_soft_reset,
905 .config_init = &vsc85xx_config_init,
906 .config_aneg = &vsc85xx_config_aneg,
907 .aneg_done = &genphy_aneg_done,
908 .read_status = &vsc85xx_read_status,
909 .ack_interrupt = &vsc85xx_ack_interrupt,
910 .config_intr = &vsc85xx_config_intr,
911 .suspend = &genphy_suspend,
912 .resume = &genphy_resume,
913 .probe = &vsc85xx_probe,
914 .set_wol = &vsc85xx_wol_set,
915 .get_wol = &vsc85xx_wol_get,
916 .get_tunable = &vsc85xx_get_tunable,
917 .set_tunable = &vsc85xx_set_tunable,
918 .read_page = &vsc85xx_phy_read_page,
919 .write_page = &vsc85xx_phy_write_page,
920 .get_sset_count = &vsc85xx_get_sset_count,
921 .get_strings = &vsc85xx_get_strings,
922 .get_stats = &vsc85xx_get_stats,
927 module_phy_driver(vsc85xx_driver);
929 static struct mdio_device_id __maybe_unused vsc85xx_tbl[] = {
930 { PHY_ID_VSC8530, 0xfffffff0, },
931 { PHY_ID_VSC8531, 0xfffffff0, },
932 { PHY_ID_VSC8540, 0xfffffff0, },
933 { PHY_ID_VSC8541, 0xfffffff0, },
937 MODULE_DEVICE_TABLE(mdio, vsc85xx_tbl);
939 MODULE_DESCRIPTION("Microsemi VSC85xx PHY driver");
940 MODULE_AUTHOR("Nagaraju Lakkaraju");
941 MODULE_LICENSE("Dual MIT/GPL");