2716 lines · c
1// SPDX-License-Identifier: (GPL-2.0 OR MIT)2/*3 * Driver for Microsemi VSC85xx PHYs4 *5 * Author: Nagaraju Lakkaraju6 * License: Dual MIT/GPL7 * Copyright (c) 2016 Microsemi Corporation8 */9 10#include <linux/firmware.h>11#include <linux/jiffies.h>12#include <linux/kernel.h>13#include <linux/module.h>14#include <linux/mdio.h>15#include <linux/mii.h>16#include <linux/phy.h>17#include <linux/of.h>18#include <linux/netdevice.h>19#include <dt-bindings/net/mscc-phy-vsc8531.h>20#include "mscc_serdes.h"21#include "mscc.h"22 23static const struct vsc85xx_hw_stat vsc85xx_hw_stats[] = {24 {25 .string = "phy_receive_errors",26 .reg = MSCC_PHY_ERR_RX_CNT,27 .page = MSCC_PHY_PAGE_STANDARD,28 .mask = ERR_CNT_MASK,29 }, {30 .string = "phy_false_carrier",31 .reg = MSCC_PHY_ERR_FALSE_CARRIER_CNT,32 .page = MSCC_PHY_PAGE_STANDARD,33 .mask = ERR_CNT_MASK,34 }, {35 .string = "phy_cu_media_link_disconnect",36 .reg = MSCC_PHY_ERR_LINK_DISCONNECT_CNT,37 .page = MSCC_PHY_PAGE_STANDARD,38 .mask = ERR_CNT_MASK,39 }, {40 .string = "phy_cu_media_crc_good_count",41 .reg = MSCC_PHY_CU_MEDIA_CRC_VALID_CNT,42 .page = MSCC_PHY_PAGE_EXTENDED,43 .mask = VALID_CRC_CNT_CRC_MASK,44 }, {45 .string = "phy_cu_media_crc_error_count",46 .reg = MSCC_PHY_EXT_PHY_CNTL_4,47 .page = MSCC_PHY_PAGE_EXTENDED,48 .mask = ERR_CNT_MASK,49 },50};51 52static const struct vsc85xx_hw_stat vsc8584_hw_stats[] = {53 {54 .string = "phy_receive_errors",55 .reg = MSCC_PHY_ERR_RX_CNT,56 .page = MSCC_PHY_PAGE_STANDARD,57 .mask = ERR_CNT_MASK,58 }, {59 .string = "phy_false_carrier",60 .reg = MSCC_PHY_ERR_FALSE_CARRIER_CNT,61 .page = MSCC_PHY_PAGE_STANDARD,62 .mask = ERR_CNT_MASK,63 }, {64 .string = "phy_cu_media_link_disconnect",65 .reg = MSCC_PHY_ERR_LINK_DISCONNECT_CNT,66 .page = MSCC_PHY_PAGE_STANDARD,67 .mask = ERR_CNT_MASK,68 }, {69 .string = "phy_cu_media_crc_good_count",70 .reg = MSCC_PHY_CU_MEDIA_CRC_VALID_CNT,71 .page = MSCC_PHY_PAGE_EXTENDED,72 .mask = VALID_CRC_CNT_CRC_MASK,73 }, {74 .string = "phy_cu_media_crc_error_count",75 .reg = MSCC_PHY_EXT_PHY_CNTL_4,76 .page = MSCC_PHY_PAGE_EXTENDED,77 .mask = ERR_CNT_MASK,78 }, {79 .string = "phy_serdes_tx_good_pkt_count",80 .reg = MSCC_PHY_SERDES_TX_VALID_CNT,81 .page = MSCC_PHY_PAGE_EXTENDED_3,82 .mask = VALID_CRC_CNT_CRC_MASK,83 }, {84 .string = "phy_serdes_tx_bad_crc_count",85 .reg = MSCC_PHY_SERDES_TX_CRC_ERR_CNT,86 .page = MSCC_PHY_PAGE_EXTENDED_3,87 .mask = ERR_CNT_MASK,88 }, {89 .string = "phy_serdes_rx_good_pkt_count",90 .reg = MSCC_PHY_SERDES_RX_VALID_CNT,91 .page = MSCC_PHY_PAGE_EXTENDED_3,92 .mask = VALID_CRC_CNT_CRC_MASK,93 }, {94 .string = "phy_serdes_rx_bad_crc_count",95 .reg = MSCC_PHY_SERDES_RX_CRC_ERR_CNT,96 .page = MSCC_PHY_PAGE_EXTENDED_3,97 .mask = ERR_CNT_MASK,98 },99};100 101#if IS_ENABLED(CONFIG_OF_MDIO)102static const struct vsc8531_edge_rate_table edge_table[] = {103 {MSCC_VDDMAC_3300, { 0, 2, 4, 7, 10, 17, 29, 53} },104 {MSCC_VDDMAC_2500, { 0, 3, 6, 10, 14, 23, 37, 63} },105 {MSCC_VDDMAC_1800, { 0, 5, 9, 16, 23, 35, 52, 76} },106 {MSCC_VDDMAC_1500, { 0, 6, 14, 21, 29, 42, 58, 77} },107};108#endif109 110static const int vsc85xx_internal_delay[] = {200, 800, 1100, 1700, 2000, 2300,111 2600, 3400};112 113static int vsc85xx_phy_read_page(struct phy_device *phydev)114{115 return __phy_read(phydev, MSCC_EXT_PAGE_ACCESS);116}117 118static int vsc85xx_phy_write_page(struct phy_device *phydev, int page)119{120 return __phy_write(phydev, MSCC_EXT_PAGE_ACCESS, page);121}122 123static int vsc85xx_get_sset_count(struct phy_device *phydev)124{125 struct vsc8531_private *priv = phydev->priv;126 127 if (!priv)128 return 0;129 130 return priv->nstats;131}132 133static void vsc85xx_get_strings(struct phy_device *phydev, u8 *data)134{135 struct vsc8531_private *priv = phydev->priv;136 int i;137 138 if (!priv)139 return;140 141 for (i = 0; i < priv->nstats; i++)142 strscpy(data + i * ETH_GSTRING_LEN, priv->hw_stats[i].string,143 ETH_GSTRING_LEN);144}145 146static u64 vsc85xx_get_stat(struct phy_device *phydev, int i)147{148 struct vsc8531_private *priv = phydev->priv;149 int val;150 151 val = phy_read_paged(phydev, priv->hw_stats[i].page,152 priv->hw_stats[i].reg);153 if (val < 0)154 return U64_MAX;155 156 val = val & priv->hw_stats[i].mask;157 priv->stats[i] += val;158 159 return priv->stats[i];160}161 162static void vsc85xx_get_stats(struct phy_device *phydev,163 struct ethtool_stats *stats, u64 *data)164{165 struct vsc8531_private *priv = phydev->priv;166 int i;167 168 if (!priv)169 return;170 171 for (i = 0; i < priv->nstats; i++)172 data[i] = vsc85xx_get_stat(phydev, i);173}174 175static int vsc85xx_led_cntl_set(struct phy_device *phydev,176 u8 led_num,177 u8 mode)178{179 int rc;180 u16 reg_val;181 182 mutex_lock(&phydev->lock);183 reg_val = phy_read(phydev, MSCC_PHY_LED_MODE_SEL);184 reg_val &= ~LED_MODE_SEL_MASK(led_num);185 reg_val |= LED_MODE_SEL(led_num, (u16)mode);186 rc = phy_write(phydev, MSCC_PHY_LED_MODE_SEL, reg_val);187 mutex_unlock(&phydev->lock);188 189 return rc;190}191 192static int vsc85xx_mdix_get(struct phy_device *phydev, u8 *mdix)193{194 u16 reg_val;195 196 reg_val = phy_read(phydev, MSCC_PHY_DEV_AUX_CNTL);197 if (reg_val & HP_AUTO_MDIX_X_OVER_IND_MASK)198 *mdix = ETH_TP_MDI_X;199 else200 *mdix = ETH_TP_MDI;201 202 return 0;203}204 205static int vsc85xx_mdix_set(struct phy_device *phydev, u8 mdix)206{207 int rc;208 u16 reg_val;209 210 reg_val = phy_read(phydev, MSCC_PHY_BYPASS_CONTROL);211 if (mdix == ETH_TP_MDI || mdix == ETH_TP_MDI_X) {212 reg_val |= (DISABLE_PAIR_SWAP_CORR_MASK |213 DISABLE_POLARITY_CORR_MASK |214 DISABLE_HP_AUTO_MDIX_MASK);215 } else {216 reg_val &= ~(DISABLE_PAIR_SWAP_CORR_MASK |217 DISABLE_POLARITY_CORR_MASK |218 DISABLE_HP_AUTO_MDIX_MASK);219 }220 rc = phy_write(phydev, MSCC_PHY_BYPASS_CONTROL, reg_val);221 if (rc)222 return rc;223 224 reg_val = 0;225 226 if (mdix == ETH_TP_MDI)227 reg_val = FORCE_MDI_CROSSOVER_MDI;228 else if (mdix == ETH_TP_MDI_X)229 reg_val = FORCE_MDI_CROSSOVER_MDIX;230 231 rc = phy_modify_paged(phydev, MSCC_PHY_PAGE_EXTENDED,232 MSCC_PHY_EXT_MODE_CNTL, FORCE_MDI_CROSSOVER_MASK,233 reg_val);234 if (rc < 0)235 return rc;236 237 return genphy_restart_aneg(phydev);238}239 240static int vsc85xx_downshift_get(struct phy_device *phydev, u8 *count)241{242 int reg_val;243 244 reg_val = phy_read_paged(phydev, MSCC_PHY_PAGE_EXTENDED,245 MSCC_PHY_ACTIPHY_CNTL);246 if (reg_val < 0)247 return reg_val;248 249 reg_val &= DOWNSHIFT_CNTL_MASK;250 if (!(reg_val & DOWNSHIFT_EN))251 *count = DOWNSHIFT_DEV_DISABLE;252 else253 *count = ((reg_val & ~DOWNSHIFT_EN) >> DOWNSHIFT_CNTL_POS) + 2;254 255 return 0;256}257 258static int vsc85xx_downshift_set(struct phy_device *phydev, u8 count)259{260 if (count == DOWNSHIFT_DEV_DEFAULT_COUNT) {261 /* Default downshift count 3 (i.e. Bit3:2 = 0b01) */262 count = ((1 << DOWNSHIFT_CNTL_POS) | DOWNSHIFT_EN);263 } else if (count > DOWNSHIFT_COUNT_MAX || count == 1) {264 phydev_err(phydev, "Downshift count should be 2,3,4 or 5\n");265 return -ERANGE;266 } else if (count) {267 /* Downshift count is either 2,3,4 or 5 */268 count = (((count - 2) << DOWNSHIFT_CNTL_POS) | DOWNSHIFT_EN);269 }270 271 return phy_modify_paged(phydev, MSCC_PHY_PAGE_EXTENDED,272 MSCC_PHY_ACTIPHY_CNTL, DOWNSHIFT_CNTL_MASK,273 count);274}275 276static int vsc85xx_wol_set(struct phy_device *phydev,277 struct ethtool_wolinfo *wol)278{279 const u8 *mac_addr = phydev->attached_dev->dev_addr;280 int rc;281 u16 reg_val;282 u8 i;283 u16 pwd[3] = {0, 0, 0};284 struct ethtool_wolinfo *wol_conf = wol;285 286 rc = phy_select_page(phydev, MSCC_PHY_PAGE_EXTENDED_2);287 if (rc < 0)288 return phy_restore_page(phydev, rc, rc);289 290 if (wol->wolopts & WAKE_MAGIC) {291 /* Store the device address for the magic packet */292 for (i = 0; i < ARRAY_SIZE(pwd); i++)293 pwd[i] = mac_addr[5 - (i * 2 + 1)] << 8 |294 mac_addr[5 - i * 2];295 __phy_write(phydev, MSCC_PHY_WOL_LOWER_MAC_ADDR, pwd[0]);296 __phy_write(phydev, MSCC_PHY_WOL_MID_MAC_ADDR, pwd[1]);297 __phy_write(phydev, MSCC_PHY_WOL_UPPER_MAC_ADDR, pwd[2]);298 } else {299 __phy_write(phydev, MSCC_PHY_WOL_LOWER_MAC_ADDR, 0);300 __phy_write(phydev, MSCC_PHY_WOL_MID_MAC_ADDR, 0);301 __phy_write(phydev, MSCC_PHY_WOL_UPPER_MAC_ADDR, 0);302 }303 304 if (wol_conf->wolopts & WAKE_MAGICSECURE) {305 for (i = 0; i < ARRAY_SIZE(pwd); i++)306 pwd[i] = wol_conf->sopass[5 - (i * 2 + 1)] << 8 |307 wol_conf->sopass[5 - i * 2];308 __phy_write(phydev, MSCC_PHY_WOL_LOWER_PASSWD, pwd[0]);309 __phy_write(phydev, MSCC_PHY_WOL_MID_PASSWD, pwd[1]);310 __phy_write(phydev, MSCC_PHY_WOL_UPPER_PASSWD, pwd[2]);311 } else {312 __phy_write(phydev, MSCC_PHY_WOL_LOWER_PASSWD, 0);313 __phy_write(phydev, MSCC_PHY_WOL_MID_PASSWD, 0);314 __phy_write(phydev, MSCC_PHY_WOL_UPPER_PASSWD, 0);315 }316 317 reg_val = __phy_read(phydev, MSCC_PHY_WOL_MAC_CONTROL);318 if (wol_conf->wolopts & WAKE_MAGICSECURE)319 reg_val |= SECURE_ON_ENABLE;320 else321 reg_val &= ~SECURE_ON_ENABLE;322 __phy_write(phydev, MSCC_PHY_WOL_MAC_CONTROL, reg_val);323 324 rc = phy_restore_page(phydev, rc, rc > 0 ? 0 : rc);325 if (rc < 0)326 return rc;327 328 if (wol->wolopts & WAKE_MAGIC) {329 /* Enable the WOL interrupt */330 reg_val = phy_read(phydev, MII_VSC85XX_INT_MASK);331 reg_val |= MII_VSC85XX_INT_MASK_WOL;332 rc = phy_write(phydev, MII_VSC85XX_INT_MASK, reg_val);333 if (rc)334 return rc;335 } else {336 /* Disable the WOL interrupt */337 reg_val = phy_read(phydev, MII_VSC85XX_INT_MASK);338 reg_val &= (~MII_VSC85XX_INT_MASK_WOL);339 rc = phy_write(phydev, MII_VSC85XX_INT_MASK, reg_val);340 if (rc)341 return rc;342 }343 /* Clear WOL iterrupt status */344 reg_val = phy_read(phydev, MII_VSC85XX_INT_STATUS);345 346 return 0;347}348 349static void vsc85xx_wol_get(struct phy_device *phydev,350 struct ethtool_wolinfo *wol)351{352 int rc;353 u16 reg_val;354 u8 i;355 u16 pwd[3] = {0, 0, 0};356 struct ethtool_wolinfo *wol_conf = wol;357 358 rc = phy_select_page(phydev, MSCC_PHY_PAGE_EXTENDED_2);359 if (rc < 0)360 goto out_restore_page;361 362 reg_val = __phy_read(phydev, MSCC_PHY_WOL_MAC_CONTROL);363 if (reg_val & SECURE_ON_ENABLE)364 wol_conf->wolopts |= WAKE_MAGICSECURE;365 if (wol_conf->wolopts & WAKE_MAGICSECURE) {366 pwd[0] = __phy_read(phydev, MSCC_PHY_WOL_LOWER_PASSWD);367 pwd[1] = __phy_read(phydev, MSCC_PHY_WOL_MID_PASSWD);368 pwd[2] = __phy_read(phydev, MSCC_PHY_WOL_UPPER_PASSWD);369 for (i = 0; i < ARRAY_SIZE(pwd); i++) {370 wol_conf->sopass[5 - i * 2] = pwd[i] & 0x00ff;371 wol_conf->sopass[5 - (i * 2 + 1)] = (pwd[i] & 0xff00)372 >> 8;373 }374 }375 376out_restore_page:377 phy_restore_page(phydev, rc, rc > 0 ? 0 : rc);378}379 380#if IS_ENABLED(CONFIG_OF_MDIO)381static int vsc85xx_edge_rate_magic_get(struct phy_device *phydev)382{383 u32 vdd, sd;384 int i, j;385 struct device *dev = &phydev->mdio.dev;386 struct device_node *of_node = dev->of_node;387 u8 sd_array_size = ARRAY_SIZE(edge_table[0].slowdown);388 389 if (!of_node)390 return -ENODEV;391 392 if (of_property_read_u32(of_node, "vsc8531,vddmac", &vdd))393 vdd = MSCC_VDDMAC_3300;394 395 if (of_property_read_u32(of_node, "vsc8531,edge-slowdown", &sd))396 sd = 0;397 398 for (i = 0; i < ARRAY_SIZE(edge_table); i++)399 if (edge_table[i].vddmac == vdd)400 for (j = 0; j < sd_array_size; j++)401 if (edge_table[i].slowdown[j] == sd)402 return (sd_array_size - j - 1);403 404 return -EINVAL;405}406 407static int vsc85xx_dt_led_mode_get(struct phy_device *phydev,408 char *led,409 u32 default_mode)410{411 struct vsc8531_private *priv = phydev->priv;412 struct device *dev = &phydev->mdio.dev;413 struct device_node *of_node = dev->of_node;414 u32 led_mode;415 int err;416 417 if (!of_node)418 return -ENODEV;419 420 led_mode = default_mode;421 err = of_property_read_u32(of_node, led, &led_mode);422 if (!err && !(BIT(led_mode) & priv->supp_led_modes)) {423 phydev_err(phydev, "DT %s invalid\n", led);424 return -EINVAL;425 }426 427 return led_mode;428}429 430#else431static int vsc85xx_edge_rate_magic_get(struct phy_device *phydev)432{433 return 0;434}435 436static int vsc85xx_dt_led_mode_get(struct phy_device *phydev,437 char *led,438 u8 default_mode)439{440 return default_mode;441}442#endif /* CONFIG_OF_MDIO */443 444static int vsc85xx_dt_led_modes_get(struct phy_device *phydev,445 u32 *default_mode)446{447 struct vsc8531_private *priv = phydev->priv;448 char led_dt_prop[28];449 int i, ret;450 451 for (i = 0; i < priv->nleds; i++) {452 ret = sprintf(led_dt_prop, "vsc8531,led-%d-mode", i);453 if (ret < 0)454 return ret;455 456 ret = vsc85xx_dt_led_mode_get(phydev, led_dt_prop,457 default_mode[i]);458 if (ret < 0)459 return ret;460 priv->leds_mode[i] = ret;461 }462 463 return 0;464}465 466static int vsc85xx_edge_rate_cntl_set(struct phy_device *phydev, u8 edge_rate)467{468 int rc;469 470 mutex_lock(&phydev->lock);471 rc = phy_modify_paged(phydev, MSCC_PHY_PAGE_EXTENDED_2,472 MSCC_PHY_WOL_MAC_CONTROL, EDGE_RATE_CNTL_MASK,473 edge_rate << EDGE_RATE_CNTL_POS);474 mutex_unlock(&phydev->lock);475 476 return rc;477}478 479static int vsc85xx_mac_if_set(struct phy_device *phydev,480 phy_interface_t interface)481{482 int rc;483 u16 reg_val;484 485 mutex_lock(&phydev->lock);486 reg_val = phy_read(phydev, MSCC_PHY_EXT_PHY_CNTL_1);487 reg_val &= ~(MAC_IF_SELECTION_MASK);488 switch (interface) {489 case PHY_INTERFACE_MODE_RGMII_TXID:490 case PHY_INTERFACE_MODE_RGMII_RXID:491 case PHY_INTERFACE_MODE_RGMII_ID:492 case PHY_INTERFACE_MODE_RGMII:493 reg_val |= (MAC_IF_SELECTION_RGMII << MAC_IF_SELECTION_POS);494 break;495 case PHY_INTERFACE_MODE_RMII:496 reg_val |= (MAC_IF_SELECTION_RMII << MAC_IF_SELECTION_POS);497 break;498 case PHY_INTERFACE_MODE_MII:499 case PHY_INTERFACE_MODE_GMII:500 reg_val |= (MAC_IF_SELECTION_GMII << MAC_IF_SELECTION_POS);501 break;502 default:503 rc = -EINVAL;504 goto out_unlock;505 }506 rc = phy_write(phydev, MSCC_PHY_EXT_PHY_CNTL_1, reg_val);507 if (rc)508 goto out_unlock;509 510 rc = genphy_soft_reset(phydev);511 512out_unlock:513 mutex_unlock(&phydev->lock);514 515 return rc;516}517 518/* Set the RGMII RX and TX clock skews individually, according to the PHY519 * interface type, to:520 * * 0.2 ns (their default, and lowest, hardware value) if delays should521 * not be enabled522 * * 2.0 ns (which causes the data to be sampled at exactly half way between523 * clock transitions at 1000 Mbps) if delays should be enabled524 */525static int vsc85xx_update_rgmii_cntl(struct phy_device *phydev, u32 rgmii_cntl,526 u16 rgmii_rx_delay_mask,527 u16 rgmii_tx_delay_mask)528{529 u16 rgmii_rx_delay_pos = ffs(rgmii_rx_delay_mask) - 1;530 u16 rgmii_tx_delay_pos = ffs(rgmii_tx_delay_mask) - 1;531 int delay_size = ARRAY_SIZE(vsc85xx_internal_delay);532 struct device *dev = &phydev->mdio.dev;533 u16 reg_val = 0;534 u16 mask = 0;535 s32 rx_delay;536 s32 tx_delay;537 int rc = 0;538 539 /* For traffic to pass, the VSC8502 family needs the RX_CLK disable bit540 * to be unset for all PHY modes, so do that as part of the paged541 * register modification.542 * For some family members (like VSC8530/31/40/41) this bit is reserved543 * and read-only, and the RX clock is enabled by default.544 */545 if (rgmii_cntl == VSC8502_RGMII_CNTL)546 mask |= VSC8502_RGMII_RX_CLK_DISABLE;547 548 if (phy_interface_is_rgmii(phydev))549 mask |= rgmii_rx_delay_mask | rgmii_tx_delay_mask;550 551 rx_delay = phy_get_internal_delay(phydev, dev, vsc85xx_internal_delay,552 delay_size, true);553 if (rx_delay < 0) {554 if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID ||555 phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)556 rx_delay = RGMII_CLK_DELAY_2_0_NS;557 else558 rx_delay = RGMII_CLK_DELAY_0_2_NS;559 }560 561 tx_delay = phy_get_internal_delay(phydev, dev, vsc85xx_internal_delay,562 delay_size, false);563 if (tx_delay < 0) {564 if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID ||565 phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)566 tx_delay = RGMII_CLK_DELAY_2_0_NS;567 else568 tx_delay = RGMII_CLK_DELAY_0_2_NS;569 }570 571 reg_val |= rx_delay << rgmii_rx_delay_pos;572 reg_val |= tx_delay << rgmii_tx_delay_pos;573 574 if (mask)575 rc = phy_modify_paged(phydev, MSCC_PHY_PAGE_EXTENDED_2,576 rgmii_cntl, mask, reg_val);577 578 return rc;579}580 581static int vsc85xx_default_config(struct phy_device *phydev)582{583 phydev->mdix_ctrl = ETH_TP_MDI_AUTO;584 585 return vsc85xx_update_rgmii_cntl(phydev, VSC8502_RGMII_CNTL,586 VSC8502_RGMII_RX_DELAY_MASK,587 VSC8502_RGMII_TX_DELAY_MASK);588}589 590static int vsc85xx_get_tunable(struct phy_device *phydev,591 struct ethtool_tunable *tuna, void *data)592{593 switch (tuna->id) {594 case ETHTOOL_PHY_DOWNSHIFT:595 return vsc85xx_downshift_get(phydev, (u8 *)data);596 default:597 return -EINVAL;598 }599}600 601static int vsc85xx_set_tunable(struct phy_device *phydev,602 struct ethtool_tunable *tuna,603 const void *data)604{605 switch (tuna->id) {606 case ETHTOOL_PHY_DOWNSHIFT:607 return vsc85xx_downshift_set(phydev, *(u8 *)data);608 default:609 return -EINVAL;610 }611}612 613/* mdiobus lock should be locked when using this function */614static void vsc85xx_tr_write(struct phy_device *phydev, u16 addr, u32 val)615{616 __phy_write(phydev, MSCC_PHY_TR_MSB, val >> 16);617 __phy_write(phydev, MSCC_PHY_TR_LSB, val & GENMASK(15, 0));618 __phy_write(phydev, MSCC_PHY_TR_CNTL, TR_WRITE | TR_ADDR(addr));619}620 621static int vsc8531_pre_init_seq_set(struct phy_device *phydev)622{623 int rc;624 static const struct reg_val init_seq[] = {625 {0x0f90, 0x00688980},626 {0x0696, 0x00000003},627 {0x07fa, 0x0050100f},628 {0x1686, 0x00000004},629 };630 unsigned int i;631 int oldpage;632 633 rc = phy_modify_paged(phydev, MSCC_PHY_PAGE_STANDARD,634 MSCC_PHY_EXT_CNTL_STATUS, SMI_BROADCAST_WR_EN,635 SMI_BROADCAST_WR_EN);636 if (rc < 0)637 return rc;638 rc = phy_modify_paged(phydev, MSCC_PHY_PAGE_TEST,639 MSCC_PHY_TEST_PAGE_24, 0, 0x0400);640 if (rc < 0)641 return rc;642 rc = phy_modify_paged(phydev, MSCC_PHY_PAGE_TEST,643 MSCC_PHY_TEST_PAGE_5, 0x0a00, 0x0e00);644 if (rc < 0)645 return rc;646 rc = phy_modify_paged(phydev, MSCC_PHY_PAGE_TEST,647 MSCC_PHY_TEST_PAGE_8, TR_CLK_DISABLE, TR_CLK_DISABLE);648 if (rc < 0)649 return rc;650 651 mutex_lock(&phydev->lock);652 oldpage = phy_select_page(phydev, MSCC_PHY_PAGE_TR);653 if (oldpage < 0)654 goto out_unlock;655 656 for (i = 0; i < ARRAY_SIZE(init_seq); i++)657 vsc85xx_tr_write(phydev, init_seq[i].reg, init_seq[i].val);658 659out_unlock:660 oldpage = phy_restore_page(phydev, oldpage, oldpage);661 mutex_unlock(&phydev->lock);662 663 return oldpage;664}665 666static int vsc85xx_eee_init_seq_set(struct phy_device *phydev)667{668 static const struct reg_val init_eee[] = {669 {0x0f82, 0x0012b00a},670 {0x1686, 0x00000004},671 {0x168c, 0x00d2c46f},672 {0x17a2, 0x00000620},673 {0x16a0, 0x00eeffdd},674 {0x16a6, 0x00071448},675 {0x16a4, 0x0013132f},676 {0x16a8, 0x00000000},677 {0x0ffc, 0x00c0a028},678 {0x0fe8, 0x0091b06c},679 {0x0fea, 0x00041600},680 {0x0f80, 0x00000af4},681 {0x0fec, 0x00901809},682 {0x0fee, 0x0000a6a1},683 {0x0ffe, 0x00b01007},684 {0x16b0, 0x00eeff00},685 {0x16b2, 0x00007000},686 {0x16b4, 0x00000814},687 };688 unsigned int i;689 int oldpage;690 691 mutex_lock(&phydev->lock);692 oldpage = phy_select_page(phydev, MSCC_PHY_PAGE_TR);693 if (oldpage < 0)694 goto out_unlock;695 696 for (i = 0; i < ARRAY_SIZE(init_eee); i++)697 vsc85xx_tr_write(phydev, init_eee[i].reg, init_eee[i].val);698 699out_unlock:700 oldpage = phy_restore_page(phydev, oldpage, oldpage);701 mutex_unlock(&phydev->lock);702 703 return oldpage;704}705 706/* phydev->bus->mdio_lock should be locked when using this function */707int phy_base_write(struct phy_device *phydev, u32 regnum, u16 val)708{709 if (unlikely(!mutex_is_locked(&phydev->mdio.bus->mdio_lock))) {710 dev_err(&phydev->mdio.dev, "MDIO bus lock not held!\n");711 dump_stack();712 }713 714 return __phy_package_write(phydev, VSC88XX_BASE_ADDR, regnum, val);715}716 717/* phydev->bus->mdio_lock should be locked when using this function */718int phy_base_read(struct phy_device *phydev, u32 regnum)719{720 if (unlikely(!mutex_is_locked(&phydev->mdio.bus->mdio_lock))) {721 dev_err(&phydev->mdio.dev, "MDIO bus lock not held!\n");722 dump_stack();723 }724 725 return __phy_package_read(phydev, VSC88XX_BASE_ADDR, regnum);726}727 728u32 vsc85xx_csr_read(struct phy_device *phydev,729 enum csr_target target, u32 reg)730{731 unsigned long deadline;732 u32 val, val_l, val_h;733 734 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_CSR_CNTL);735 736 /* CSR registers are grouped under different Target IDs.737 * 6-bit Target_ID is split between MSCC_EXT_PAGE_CSR_CNTL_20 and738 * MSCC_EXT_PAGE_CSR_CNTL_19 registers.739 * Target_ID[5:2] maps to bits[3:0] of MSCC_EXT_PAGE_CSR_CNTL_20740 * and Target_ID[1:0] maps to bits[13:12] of MSCC_EXT_PAGE_CSR_CNTL_19.741 */742 743 /* Setup the Target ID */744 phy_base_write(phydev, MSCC_EXT_PAGE_CSR_CNTL_20,745 MSCC_PHY_CSR_CNTL_20_TARGET(target >> 2));746 747 if ((target >> 2 == 0x1) || (target >> 2 == 0x3))748 /* non-MACsec access */749 target &= 0x3;750 else751 target = 0;752 753 /* Trigger CSR Action - Read into the CSR's */754 phy_base_write(phydev, MSCC_EXT_PAGE_CSR_CNTL_19,755 MSCC_PHY_CSR_CNTL_19_CMD | MSCC_PHY_CSR_CNTL_19_READ |756 MSCC_PHY_CSR_CNTL_19_REG_ADDR(reg) |757 MSCC_PHY_CSR_CNTL_19_TARGET(target));758 759 /* Wait for register access*/760 deadline = jiffies + msecs_to_jiffies(PROC_CMD_NCOMPLETED_TIMEOUT_MS);761 do {762 usleep_range(500, 1000);763 val = phy_base_read(phydev, MSCC_EXT_PAGE_CSR_CNTL_19);764 } while (time_before(jiffies, deadline) &&765 !(val & MSCC_PHY_CSR_CNTL_19_CMD));766 767 if (!(val & MSCC_PHY_CSR_CNTL_19_CMD))768 return 0xffffffff;769 770 /* Read the Least Significant Word (LSW) (17) */771 val_l = phy_base_read(phydev, MSCC_EXT_PAGE_CSR_CNTL_17);772 773 /* Read the Most Significant Word (MSW) (18) */774 val_h = phy_base_read(phydev, MSCC_EXT_PAGE_CSR_CNTL_18);775 776 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS,777 MSCC_PHY_PAGE_STANDARD);778 779 return (val_h << 16) | val_l;780}781 782int vsc85xx_csr_write(struct phy_device *phydev,783 enum csr_target target, u32 reg, u32 val)784{785 unsigned long deadline;786 787 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_CSR_CNTL);788 789 /* CSR registers are grouped under different Target IDs.790 * 6-bit Target_ID is split between MSCC_EXT_PAGE_CSR_CNTL_20 and791 * MSCC_EXT_PAGE_CSR_CNTL_19 registers.792 * Target_ID[5:2] maps to bits[3:0] of MSCC_EXT_PAGE_CSR_CNTL_20793 * and Target_ID[1:0] maps to bits[13:12] of MSCC_EXT_PAGE_CSR_CNTL_19.794 */795 796 /* Setup the Target ID */797 phy_base_write(phydev, MSCC_EXT_PAGE_CSR_CNTL_20,798 MSCC_PHY_CSR_CNTL_20_TARGET(target >> 2));799 800 /* Write the Least Significant Word (LSW) (17) */801 phy_base_write(phydev, MSCC_EXT_PAGE_CSR_CNTL_17, (u16)val);802 803 /* Write the Most Significant Word (MSW) (18) */804 phy_base_write(phydev, MSCC_EXT_PAGE_CSR_CNTL_18, (u16)(val >> 16));805 806 if ((target >> 2 == 0x1) || (target >> 2 == 0x3))807 /* non-MACsec access */808 target &= 0x3;809 else810 target = 0;811 812 /* Trigger CSR Action - Write into the CSR's */813 phy_base_write(phydev, MSCC_EXT_PAGE_CSR_CNTL_19,814 MSCC_PHY_CSR_CNTL_19_CMD |815 MSCC_PHY_CSR_CNTL_19_REG_ADDR(reg) |816 MSCC_PHY_CSR_CNTL_19_TARGET(target));817 818 /* Wait for register access */819 deadline = jiffies + msecs_to_jiffies(PROC_CMD_NCOMPLETED_TIMEOUT_MS);820 do {821 usleep_range(500, 1000);822 val = phy_base_read(phydev, MSCC_EXT_PAGE_CSR_CNTL_19);823 } while (time_before(jiffies, deadline) &&824 !(val & MSCC_PHY_CSR_CNTL_19_CMD));825 826 if (!(val & MSCC_PHY_CSR_CNTL_19_CMD))827 return -ETIMEDOUT;828 829 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS,830 MSCC_PHY_PAGE_STANDARD);831 832 return 0;833}834 835/* bus->mdio_lock should be locked when using this function */836static void vsc8584_csr_write(struct phy_device *phydev, u16 addr, u32 val)837{838 phy_base_write(phydev, MSCC_PHY_TR_MSB, val >> 16);839 phy_base_write(phydev, MSCC_PHY_TR_LSB, val & GENMASK(15, 0));840 phy_base_write(phydev, MSCC_PHY_TR_CNTL, TR_WRITE | TR_ADDR(addr));841}842 843/* bus->mdio_lock should be locked when using this function */844int vsc8584_cmd(struct phy_device *phydev, u16 val)845{846 unsigned long deadline;847 u16 reg_val;848 849 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS,850 MSCC_PHY_PAGE_EXTENDED_GPIO);851 852 phy_base_write(phydev, MSCC_PHY_PROC_CMD, PROC_CMD_NCOMPLETED | val);853 854 deadline = jiffies + msecs_to_jiffies(PROC_CMD_NCOMPLETED_TIMEOUT_MS);855 do {856 reg_val = phy_base_read(phydev, MSCC_PHY_PROC_CMD);857 } while (time_before(jiffies, deadline) &&858 (reg_val & PROC_CMD_NCOMPLETED) &&859 !(reg_val & PROC_CMD_FAILED));860 861 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);862 863 if (reg_val & PROC_CMD_FAILED)864 return -EIO;865 866 if (reg_val & PROC_CMD_NCOMPLETED)867 return -ETIMEDOUT;868 869 return 0;870}871 872/* bus->mdio_lock should be locked when using this function */873static int vsc8584_micro_deassert_reset(struct phy_device *phydev,874 bool patch_en)875{876 u32 enable, release;877 878 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS,879 MSCC_PHY_PAGE_EXTENDED_GPIO);880 881 enable = RUN_FROM_INT_ROM | MICRO_CLK_EN | DW8051_CLK_EN;882 release = MICRO_NSOFT_RESET | RUN_FROM_INT_ROM | DW8051_CLK_EN |883 MICRO_CLK_EN;884 885 if (patch_en) {886 enable |= MICRO_PATCH_EN;887 release |= MICRO_PATCH_EN;888 889 /* Clear all patches */890 phy_base_write(phydev, MSCC_INT_MEM_CNTL, READ_RAM);891 }892 893 /* Enable 8051 Micro clock; CLEAR/SET patch present; disable PRAM clock894 * override and addr. auto-incr; operate at 125 MHz895 */896 phy_base_write(phydev, MSCC_DW8051_CNTL_STATUS, enable);897 /* Release 8051 Micro SW reset */898 phy_base_write(phydev, MSCC_DW8051_CNTL_STATUS, release);899 900 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);901 902 return 0;903}904 905/* bus->mdio_lock should be locked when using this function */906static int vsc8584_micro_assert_reset(struct phy_device *phydev)907{908 int ret;909 u16 reg;910 911 ret = vsc8584_cmd(phydev, PROC_CMD_NOP);912 if (ret)913 return ret;914 915 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS,916 MSCC_PHY_PAGE_EXTENDED_GPIO);917 918 reg = phy_base_read(phydev, MSCC_INT_MEM_CNTL);919 reg &= ~EN_PATCH_RAM_TRAP_ADDR(4);920 phy_base_write(phydev, MSCC_INT_MEM_CNTL, reg);921 922 phy_base_write(phydev, MSCC_TRAP_ROM_ADDR(4), 0x005b);923 phy_base_write(phydev, MSCC_PATCH_RAM_ADDR(4), 0x005b);924 925 reg = phy_base_read(phydev, MSCC_INT_MEM_CNTL);926 reg |= EN_PATCH_RAM_TRAP_ADDR(4);927 phy_base_write(phydev, MSCC_INT_MEM_CNTL, reg);928 929 phy_base_write(phydev, MSCC_PHY_PROC_CMD, PROC_CMD_NOP);930 931 reg = phy_base_read(phydev, MSCC_DW8051_CNTL_STATUS);932 reg &= ~MICRO_NSOFT_RESET;933 phy_base_write(phydev, MSCC_DW8051_CNTL_STATUS, reg);934 935 phy_base_write(phydev, MSCC_PHY_PROC_CMD, PROC_CMD_MCB_ACCESS_MAC_CONF |936 PROC_CMD_SGMII_PORT(0) | PROC_CMD_NO_MAC_CONF |937 PROC_CMD_READ);938 939 reg = phy_base_read(phydev, MSCC_INT_MEM_CNTL);940 reg &= ~EN_PATCH_RAM_TRAP_ADDR(4);941 phy_base_write(phydev, MSCC_INT_MEM_CNTL, reg);942 943 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);944 945 return 0;946}947 948/* bus->mdio_lock should be locked when using this function */949static int vsc8584_get_fw_crc(struct phy_device *phydev, u16 start, u16 size,950 u16 *crc)951{952 int ret;953 954 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_EXTENDED);955 956 phy_base_write(phydev, MSCC_PHY_VERIPHY_CNTL_2, start);957 phy_base_write(phydev, MSCC_PHY_VERIPHY_CNTL_3, size);958 959 /* Start Micro command */960 ret = vsc8584_cmd(phydev, PROC_CMD_CRC16);961 if (ret)962 goto out;963 964 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_EXTENDED);965 966 *crc = phy_base_read(phydev, MSCC_PHY_VERIPHY_CNTL_2);967 968out:969 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);970 971 return ret;972}973 974/* bus->mdio_lock should be locked when using this function */975static int vsc8584_patch_fw(struct phy_device *phydev,976 const struct firmware *fw)977{978 int i, ret;979 980 ret = vsc8584_micro_assert_reset(phydev);981 if (ret) {982 dev_err(&phydev->mdio.dev,983 "%s: failed to assert reset of micro\n", __func__);984 return ret;985 }986 987 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS,988 MSCC_PHY_PAGE_EXTENDED_GPIO);989 990 /* Hold 8051 Micro in SW Reset, Enable auto incr address and patch clock991 * Disable the 8051 Micro clock992 */993 phy_base_write(phydev, MSCC_DW8051_CNTL_STATUS, RUN_FROM_INT_ROM |994 AUTOINC_ADDR | PATCH_RAM_CLK | MICRO_CLK_EN |995 MICRO_CLK_DIVIDE(2));996 phy_base_write(phydev, MSCC_INT_MEM_CNTL, READ_PRAM | INT_MEM_WRITE_EN |997 INT_MEM_DATA(2));998 phy_base_write(phydev, MSCC_INT_MEM_ADDR, 0x0000);999 1000 for (i = 0; i < fw->size; i++)1001 phy_base_write(phydev, MSCC_INT_MEM_CNTL, READ_PRAM |1002 INT_MEM_WRITE_EN | fw->data[i]);1003 1004 /* Clear internal memory access */1005 phy_base_write(phydev, MSCC_INT_MEM_CNTL, READ_RAM);1006 1007 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);1008 1009 return 0;1010}1011 1012/* bus->mdio_lock should be locked when using this function */1013static bool vsc8574_is_serdes_init(struct phy_device *phydev)1014{1015 u16 reg;1016 bool ret;1017 1018 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS,1019 MSCC_PHY_PAGE_EXTENDED_GPIO);1020 1021 reg = phy_base_read(phydev, MSCC_TRAP_ROM_ADDR(1));1022 if (reg != 0x3eb7) {1023 ret = false;1024 goto out;1025 }1026 1027 reg = phy_base_read(phydev, MSCC_PATCH_RAM_ADDR(1));1028 if (reg != 0x4012) {1029 ret = false;1030 goto out;1031 }1032 1033 reg = phy_base_read(phydev, MSCC_INT_MEM_CNTL);1034 if (reg != EN_PATCH_RAM_TRAP_ADDR(1)) {1035 ret = false;1036 goto out;1037 }1038 1039 reg = phy_base_read(phydev, MSCC_DW8051_CNTL_STATUS);1040 if ((MICRO_NSOFT_RESET | RUN_FROM_INT_ROM | DW8051_CLK_EN |1041 MICRO_CLK_EN) != (reg & MSCC_DW8051_VLD_MASK)) {1042 ret = false;1043 goto out;1044 }1045 1046 ret = true;1047out:1048 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);1049 1050 return ret;1051}1052 1053/* bus->mdio_lock should be locked when using this function */1054static int vsc8574_config_pre_init(struct phy_device *phydev)1055{1056 static const struct reg_val pre_init1[] = {1057 {0x0fae, 0x000401bd},1058 {0x0fac, 0x000f000f},1059 {0x17a0, 0x00a0f147},1060 {0x0fe4, 0x00052f54},1061 {0x1792, 0x0027303d},1062 {0x07fe, 0x00000704},1063 {0x0fe0, 0x00060150},1064 {0x0f82, 0x0012b00a},1065 {0x0f80, 0x00000d74},1066 {0x02e0, 0x00000012},1067 {0x03a2, 0x00050208},1068 {0x03b2, 0x00009186},1069 {0x0fb0, 0x000e3700},1070 {0x1688, 0x00049f81},1071 {0x0fd2, 0x0000ffff},1072 {0x168a, 0x00039fa2},1073 {0x1690, 0x0020640b},1074 {0x0258, 0x00002220},1075 {0x025a, 0x00002a20},1076 {0x025c, 0x00003060},1077 {0x025e, 0x00003fa0},1078 {0x03a6, 0x0000e0f0},1079 {0x0f92, 0x00001489},1080 {0x16a2, 0x00007000},1081 {0x16a6, 0x00071448},1082 {0x16a0, 0x00eeffdd},1083 {0x0fe8, 0x0091b06c},1084 {0x0fea, 0x00041600},1085 {0x16b0, 0x00eeff00},1086 {0x16b2, 0x00007000},1087 {0x16b4, 0x00000814},1088 {0x0f90, 0x00688980},1089 {0x03a4, 0x0000d8f0},1090 {0x0fc0, 0x00000400},1091 {0x07fa, 0x0050100f},1092 {0x0796, 0x00000003},1093 {0x07f8, 0x00c3ff98},1094 {0x0fa4, 0x0018292a},1095 {0x168c, 0x00d2c46f},1096 {0x17a2, 0x00000620},1097 {0x16a4, 0x0013132f},1098 {0x16a8, 0x00000000},1099 {0x0ffc, 0x00c0a028},1100 {0x0fec, 0x00901c09},1101 {0x0fee, 0x0004a6a1},1102 {0x0ffe, 0x00b01807},1103 };1104 static const struct reg_val pre_init2[] = {1105 {0x0486, 0x0008a518},1106 {0x0488, 0x006dc696},1107 {0x048a, 0x00000912},1108 {0x048e, 0x00000db6},1109 {0x049c, 0x00596596},1110 {0x049e, 0x00000514},1111 {0x04a2, 0x00410280},1112 {0x04a4, 0x00000000},1113 {0x04a6, 0x00000000},1114 {0x04a8, 0x00000000},1115 {0x04aa, 0x00000000},1116 {0x04ae, 0x007df7dd},1117 {0x04b0, 0x006d95d4},1118 {0x04b2, 0x00492410},1119 };1120 struct device *dev = &phydev->mdio.dev;1121 const struct firmware *fw;1122 unsigned int i;1123 u16 crc, reg;1124 bool serdes_init;1125 int ret;1126 1127 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);1128 1129 /* all writes below are broadcasted to all PHYs in the same package */1130 reg = phy_base_read(phydev, MSCC_PHY_EXT_CNTL_STATUS);1131 reg |= SMI_BROADCAST_WR_EN;1132 phy_base_write(phydev, MSCC_PHY_EXT_CNTL_STATUS, reg);1133 1134 phy_base_write(phydev, MII_VSC85XX_INT_MASK, 0);1135 1136 /* The below register writes are tweaking analog and electrical1137 * configuration that were determined through characterization by PHY1138 * engineers. These don't mean anything more than "these are the best1139 * values".1140 */1141 phy_base_write(phydev, MSCC_PHY_EXT_PHY_CNTL_2, 0x0040);1142 1143 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_TEST);1144 1145 phy_base_write(phydev, MSCC_PHY_TEST_PAGE_20, 0x4320);1146 phy_base_write(phydev, MSCC_PHY_TEST_PAGE_24, 0x0c00);1147 phy_base_write(phydev, MSCC_PHY_TEST_PAGE_9, 0x18ca);1148 phy_base_write(phydev, MSCC_PHY_TEST_PAGE_5, 0x1b20);1149 1150 reg = phy_base_read(phydev, MSCC_PHY_TEST_PAGE_8);1151 reg |= TR_CLK_DISABLE;1152 phy_base_write(phydev, MSCC_PHY_TEST_PAGE_8, reg);1153 1154 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_TR);1155 1156 for (i = 0; i < ARRAY_SIZE(pre_init1); i++)1157 vsc8584_csr_write(phydev, pre_init1[i].reg, pre_init1[i].val);1158 1159 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_EXTENDED_2);1160 1161 phy_base_write(phydev, MSCC_PHY_CU_PMD_TX_CNTL, 0x028e);1162 1163 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_TR);1164 1165 for (i = 0; i < ARRAY_SIZE(pre_init2); i++)1166 vsc8584_csr_write(phydev, pre_init2[i].reg, pre_init2[i].val);1167 1168 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_TEST);1169 1170 reg = phy_base_read(phydev, MSCC_PHY_TEST_PAGE_8);1171 reg &= ~TR_CLK_DISABLE;1172 phy_base_write(phydev, MSCC_PHY_TEST_PAGE_8, reg);1173 1174 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);1175 1176 /* end of write broadcasting */1177 reg = phy_base_read(phydev, MSCC_PHY_EXT_CNTL_STATUS);1178 reg &= ~SMI_BROADCAST_WR_EN;1179 phy_base_write(phydev, MSCC_PHY_EXT_CNTL_STATUS, reg);1180 1181 ret = request_firmware(&fw, MSCC_VSC8574_REVB_INT8051_FW, dev);1182 if (ret) {1183 dev_err(dev, "failed to load firmware %s, ret: %d\n",1184 MSCC_VSC8574_REVB_INT8051_FW, ret);1185 return ret;1186 }1187 1188 /* Add one byte to size for the one added by the patch_fw function */1189 ret = vsc8584_get_fw_crc(phydev,1190 MSCC_VSC8574_REVB_INT8051_FW_START_ADDR,1191 fw->size + 1, &crc);1192 if (ret)1193 goto out;1194 1195 if (crc == MSCC_VSC8574_REVB_INT8051_FW_CRC) {1196 serdes_init = vsc8574_is_serdes_init(phydev);1197 1198 if (!serdes_init) {1199 ret = vsc8584_micro_assert_reset(phydev);1200 if (ret) {1201 dev_err(dev,1202 "%s: failed to assert reset of micro\n",1203 __func__);1204 goto out;1205 }1206 }1207 } else {1208 dev_dbg(dev, "FW CRC is not the expected one, patching FW\n");1209 1210 serdes_init = false;1211 1212 if (vsc8584_patch_fw(phydev, fw))1213 dev_warn(dev,1214 "failed to patch FW, expect non-optimal device\n");1215 }1216 1217 if (!serdes_init) {1218 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS,1219 MSCC_PHY_PAGE_EXTENDED_GPIO);1220 1221 phy_base_write(phydev, MSCC_TRAP_ROM_ADDR(1), 0x3eb7);1222 phy_base_write(phydev, MSCC_PATCH_RAM_ADDR(1), 0x4012);1223 phy_base_write(phydev, MSCC_INT_MEM_CNTL,1224 EN_PATCH_RAM_TRAP_ADDR(1));1225 1226 vsc8584_micro_deassert_reset(phydev, false);1227 1228 /* Add one byte to size for the one added by the patch_fw1229 * function1230 */1231 ret = vsc8584_get_fw_crc(phydev,1232 MSCC_VSC8574_REVB_INT8051_FW_START_ADDR,1233 fw->size + 1, &crc);1234 if (ret)1235 goto out;1236 1237 if (crc != MSCC_VSC8574_REVB_INT8051_FW_CRC)1238 dev_warn(dev,1239 "FW CRC after patching is not the expected one, expect non-optimal device\n");1240 }1241 1242 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS,1243 MSCC_PHY_PAGE_EXTENDED_GPIO);1244 1245 ret = vsc8584_cmd(phydev, PROC_CMD_1588_DEFAULT_INIT |1246 PROC_CMD_PHY_INIT);1247 1248out:1249 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);1250 1251 release_firmware(fw);1252 1253 return ret;1254}1255 1256/* Access LCPLL Cfg_2 */1257static void vsc8584_pll5g_cfg2_wr(struct phy_device *phydev,1258 bool disable_fsm)1259{1260 u32 rd_dat;1261 1262 rd_dat = vsc85xx_csr_read(phydev, MACRO_CTRL, PHY_S6G_PLL5G_CFG2);1263 rd_dat &= ~BIT(PHY_S6G_CFG2_FSM_DIS);1264 rd_dat |= (disable_fsm << PHY_S6G_CFG2_FSM_DIS);1265 vsc85xx_csr_write(phydev, MACRO_CTRL, PHY_S6G_PLL5G_CFG2, rd_dat);1266}1267 1268/* trigger a read to the spcified MCB */1269static int vsc8584_mcb_rd_trig(struct phy_device *phydev,1270 u32 mcb_reg_addr, u8 mcb_slave_num)1271{1272 u32 rd_dat = 0;1273 1274 /* read MCB */1275 vsc85xx_csr_write(phydev, MACRO_CTRL, mcb_reg_addr,1276 (0x40000000 | (1L << mcb_slave_num)));1277 1278 return read_poll_timeout(vsc85xx_csr_read, rd_dat,1279 !(rd_dat & 0x40000000),1280 4000, 200000, 0,1281 phydev, MACRO_CTRL, mcb_reg_addr);1282}1283 1284/* trigger a write to the spcified MCB */1285static int vsc8584_mcb_wr_trig(struct phy_device *phydev,1286 u32 mcb_reg_addr,1287 u8 mcb_slave_num)1288{1289 u32 rd_dat = 0;1290 1291 /* write back MCB */1292 vsc85xx_csr_write(phydev, MACRO_CTRL, mcb_reg_addr,1293 (0x80000000 | (1L << mcb_slave_num)));1294 1295 return read_poll_timeout(vsc85xx_csr_read, rd_dat,1296 !(rd_dat & 0x80000000),1297 4000, 200000, 0,1298 phydev, MACRO_CTRL, mcb_reg_addr);1299}1300 1301/* Sequence to Reset LCPLL for the VIPER and ELISE PHY */1302static int vsc8584_pll5g_reset(struct phy_device *phydev)1303{1304 bool dis_fsm;1305 int ret = 0;1306 1307 ret = vsc8584_mcb_rd_trig(phydev, 0x11, 0);1308 if (ret < 0)1309 goto done;1310 dis_fsm = 1;1311 1312 /* Reset LCPLL */1313 vsc8584_pll5g_cfg2_wr(phydev, dis_fsm);1314 1315 /* write back LCPLL MCB */1316 ret = vsc8584_mcb_wr_trig(phydev, 0x11, 0);1317 if (ret < 0)1318 goto done;1319 1320 /* 10 mSec sleep while LCPLL is hold in reset */1321 usleep_range(10000, 20000);1322 1323 /* read LCPLL MCB into CSRs */1324 ret = vsc8584_mcb_rd_trig(phydev, 0x11, 0);1325 if (ret < 0)1326 goto done;1327 dis_fsm = 0;1328 1329 /* Release the Reset of LCPLL */1330 vsc8584_pll5g_cfg2_wr(phydev, dis_fsm);1331 1332 /* write back LCPLL MCB */1333 ret = vsc8584_mcb_wr_trig(phydev, 0x11, 0);1334 if (ret < 0)1335 goto done;1336 1337 usleep_range(110000, 200000);1338done:1339 return ret;1340}1341 1342/* bus->mdio_lock should be locked when using this function */1343static int vsc8584_config_pre_init(struct phy_device *phydev)1344{1345 static const struct reg_val pre_init1[] = {1346 {0x07fa, 0x0050100f},1347 {0x1688, 0x00049f81},1348 {0x0f90, 0x00688980},1349 {0x03a4, 0x0000d8f0},1350 {0x0fc0, 0x00000400},1351 {0x0f82, 0x0012b002},1352 {0x1686, 0x00000004},1353 {0x168c, 0x00d2c46f},1354 {0x17a2, 0x00000620},1355 {0x16a0, 0x00eeffdd},1356 {0x16a6, 0x00071448},1357 {0x16a4, 0x0013132f},1358 {0x16a8, 0x00000000},1359 {0x0ffc, 0x00c0a028},1360 {0x0fe8, 0x0091b06c},1361 {0x0fea, 0x00041600},1362 {0x0f80, 0x00fffaff},1363 {0x0fec, 0x00901809},1364 {0x0ffe, 0x00b01007},1365 {0x16b0, 0x00eeff00},1366 {0x16b2, 0x00007000},1367 {0x16b4, 0x00000814},1368 };1369 static const struct reg_val pre_init2[] = {1370 {0x0486, 0x0008a518},1371 {0x0488, 0x006dc696},1372 {0x048a, 0x00000912},1373 };1374 const struct firmware *fw;1375 struct device *dev = &phydev->mdio.dev;1376 unsigned int i;1377 u16 crc, reg;1378 int ret;1379 1380 ret = vsc8584_pll5g_reset(phydev);1381 if (ret < 0) {1382 dev_err(dev, "failed LCPLL reset, ret: %d\n", ret);1383 return ret;1384 }1385 1386 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);1387 1388 /* all writes below are broadcasted to all PHYs in the same package */1389 reg = phy_base_read(phydev, MSCC_PHY_EXT_CNTL_STATUS);1390 reg |= SMI_BROADCAST_WR_EN;1391 phy_base_write(phydev, MSCC_PHY_EXT_CNTL_STATUS, reg);1392 1393 phy_base_write(phydev, MII_VSC85XX_INT_MASK, 0);1394 1395 reg = phy_base_read(phydev, MSCC_PHY_BYPASS_CONTROL);1396 reg |= PARALLEL_DET_IGNORE_ADVERTISED;1397 phy_base_write(phydev, MSCC_PHY_BYPASS_CONTROL, reg);1398 1399 /* The below register writes are tweaking analog and electrical1400 * configuration that were determined through characterization by PHY1401 * engineers. These don't mean anything more than "these are the best1402 * values".1403 */1404 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_EXTENDED_3);1405 1406 phy_base_write(phydev, MSCC_PHY_SERDES_TX_CRC_ERR_CNT, 0x2000);1407 1408 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_TEST);1409 1410 phy_base_write(phydev, MSCC_PHY_TEST_PAGE_5, 0x1f20);1411 1412 reg = phy_base_read(phydev, MSCC_PHY_TEST_PAGE_8);1413 reg |= TR_CLK_DISABLE;1414 phy_base_write(phydev, MSCC_PHY_TEST_PAGE_8, reg);1415 1416 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_TR);1417 1418 phy_base_write(phydev, MSCC_PHY_TR_CNTL, TR_WRITE | TR_ADDR(0x2fa4));1419 1420 reg = phy_base_read(phydev, MSCC_PHY_TR_MSB);1421 reg &= ~0x007f;1422 reg |= 0x0019;1423 phy_base_write(phydev, MSCC_PHY_TR_MSB, reg);1424 1425 phy_base_write(phydev, MSCC_PHY_TR_CNTL, TR_WRITE | TR_ADDR(0x0fa4));1426 1427 for (i = 0; i < ARRAY_SIZE(pre_init1); i++)1428 vsc8584_csr_write(phydev, pre_init1[i].reg, pre_init1[i].val);1429 1430 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_EXTENDED_2);1431 1432 phy_base_write(phydev, MSCC_PHY_CU_PMD_TX_CNTL, 0x028e);1433 1434 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_TR);1435 1436 for (i = 0; i < ARRAY_SIZE(pre_init2); i++)1437 vsc8584_csr_write(phydev, pre_init2[i].reg, pre_init2[i].val);1438 1439 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_TEST);1440 1441 reg = phy_base_read(phydev, MSCC_PHY_TEST_PAGE_8);1442 reg &= ~TR_CLK_DISABLE;1443 phy_base_write(phydev, MSCC_PHY_TEST_PAGE_8, reg);1444 1445 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);1446 1447 /* end of write broadcasting */1448 reg = phy_base_read(phydev, MSCC_PHY_EXT_CNTL_STATUS);1449 reg &= ~SMI_BROADCAST_WR_EN;1450 phy_base_write(phydev, MSCC_PHY_EXT_CNTL_STATUS, reg);1451 1452 ret = request_firmware(&fw, MSCC_VSC8584_REVB_INT8051_FW, dev);1453 if (ret) {1454 dev_err(dev, "failed to load firmware %s, ret: %d\n",1455 MSCC_VSC8584_REVB_INT8051_FW, ret);1456 return ret;1457 }1458 1459 /* Add one byte to size for the one added by the patch_fw function */1460 ret = vsc8584_get_fw_crc(phydev,1461 MSCC_VSC8584_REVB_INT8051_FW_START_ADDR,1462 fw->size + 1, &crc);1463 if (ret)1464 goto out;1465 1466 if (crc != MSCC_VSC8584_REVB_INT8051_FW_CRC) {1467 dev_dbg(dev, "FW CRC is not the expected one, patching FW\n");1468 if (vsc8584_patch_fw(phydev, fw))1469 dev_warn(dev,1470 "failed to patch FW, expect non-optimal device\n");1471 }1472 1473 vsc8584_micro_deassert_reset(phydev, false);1474 1475 /* Add one byte to size for the one added by the patch_fw function */1476 ret = vsc8584_get_fw_crc(phydev,1477 MSCC_VSC8584_REVB_INT8051_FW_START_ADDR,1478 fw->size + 1, &crc);1479 if (ret)1480 goto out;1481 1482 if (crc != MSCC_VSC8584_REVB_INT8051_FW_CRC)1483 dev_warn(dev,1484 "FW CRC after patching is not the expected one, expect non-optimal device\n");1485 1486 ret = vsc8584_micro_assert_reset(phydev);1487 if (ret)1488 goto out;1489 1490 /* Write patch vector 0, to skip IB cal polling */1491 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_EXTENDED_GPIO);1492 reg = MSCC_ROM_TRAP_SERDES_6G_CFG; /* ROM address to trap, for patch vector 0 */1493 ret = phy_base_write(phydev, MSCC_TRAP_ROM_ADDR(1), reg);1494 if (ret)1495 goto out;1496 1497 reg = MSCC_RAM_TRAP_SERDES_6G_CFG; /* RAM address to jump to, when patch vector 0 enabled */1498 ret = phy_base_write(phydev, MSCC_PATCH_RAM_ADDR(1), reg);1499 if (ret)1500 goto out;1501 1502 reg = phy_base_read(phydev, MSCC_INT_MEM_CNTL);1503 reg |= PATCH_VEC_ZERO_EN; /* bit 8, enable patch vector 0 */1504 ret = phy_base_write(phydev, MSCC_INT_MEM_CNTL, reg);1505 if (ret)1506 goto out;1507 1508 vsc8584_micro_deassert_reset(phydev, true);1509 1510out:1511 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);1512 1513 release_firmware(fw);1514 1515 return ret;1516}1517 1518static void vsc8584_get_base_addr(struct phy_device *phydev)1519{1520 struct vsc8531_private *vsc8531 = phydev->priv;1521 u16 val, addr;1522 1523 phy_lock_mdio_bus(phydev);1524 __phy_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_EXTENDED);1525 1526 addr = __phy_read(phydev, MSCC_PHY_EXT_PHY_CNTL_4);1527 addr >>= PHY_CNTL_4_ADDR_POS;1528 1529 val = __phy_read(phydev, MSCC_PHY_ACTIPHY_CNTL);1530 1531 __phy_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);1532 phy_unlock_mdio_bus(phydev);1533 1534 /* In the package, there are two pairs of PHYs (PHY0 + PHY2 and1535 * PHY1 + PHY3). The first PHY of each pair (PHY0 and PHY1) is1536 * the base PHY for timestamping operations.1537 */1538 vsc8531->ts_base_addr = phydev->mdio.addr;1539 vsc8531->ts_base_phy = addr;1540 1541 if (val & PHY_ADDR_REVERSED) {1542 vsc8531->base_addr = phydev->mdio.addr + addr;1543 if (addr > 1) {1544 vsc8531->ts_base_addr += 2;1545 vsc8531->ts_base_phy += 2;1546 }1547 } else {1548 vsc8531->base_addr = phydev->mdio.addr - addr;1549 if (addr > 1) {1550 vsc8531->ts_base_addr -= 2;1551 vsc8531->ts_base_phy -= 2;1552 }1553 }1554 1555 vsc8531->addr = addr;1556}1557 1558static void vsc85xx_coma_mode_release(struct phy_device *phydev)1559{1560 /* The coma mode (pin or reg) provides an optional feature that1561 * may be used to control when the PHYs become active.1562 * Alternatively the COMA_MODE pin may be connected low1563 * so that the PHYs are fully active once out of reset.1564 */1565 1566 /* Enable output (mode=0) and write zero to it */1567 vsc85xx_phy_write_page(phydev, MSCC_PHY_PAGE_EXTENDED_GPIO);1568 __phy_modify(phydev, MSCC_PHY_GPIO_CONTROL_2,1569 MSCC_PHY_COMA_MODE | MSCC_PHY_COMA_OUTPUT, 0);1570 vsc85xx_phy_write_page(phydev, MSCC_PHY_PAGE_STANDARD);1571}1572 1573static int vsc8584_config_host_serdes(struct phy_device *phydev)1574{1575 struct vsc8531_private *vsc8531 = phydev->priv;1576 int ret;1577 u16 val;1578 1579 ret = phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS,1580 MSCC_PHY_PAGE_EXTENDED_GPIO);1581 if (ret)1582 return ret;1583 1584 val = phy_base_read(phydev, MSCC_PHY_MAC_CFG_FASTLINK);1585 val &= ~MAC_CFG_MASK;1586 if (phydev->interface == PHY_INTERFACE_MODE_QSGMII) {1587 val |= MAC_CFG_QSGMII;1588 } else if (phydev->interface == PHY_INTERFACE_MODE_SGMII) {1589 val |= MAC_CFG_SGMII;1590 } else {1591 ret = -EINVAL;1592 return ret;1593 }1594 1595 ret = phy_base_write(phydev, MSCC_PHY_MAC_CFG_FASTLINK, val);1596 if (ret)1597 return ret;1598 1599 ret = phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS,1600 MSCC_PHY_PAGE_STANDARD);1601 if (ret)1602 return ret;1603 1604 val = PROC_CMD_MCB_ACCESS_MAC_CONF | PROC_CMD_RST_CONF_PORT |1605 PROC_CMD_READ_MOD_WRITE_PORT;1606 if (phydev->interface == PHY_INTERFACE_MODE_QSGMII)1607 val |= PROC_CMD_QSGMII_MAC;1608 else1609 val |= PROC_CMD_SGMII_MAC;1610 1611 ret = vsc8584_cmd(phydev, val);1612 if (ret)1613 return ret;1614 1615 usleep_range(10000, 20000);1616 1617 /* Disable SerDes for 100Base-FX */1618 ret = vsc8584_cmd(phydev, PROC_CMD_FIBER_MEDIA_CONF |1619 PROC_CMD_FIBER_PORT(vsc8531->addr) |1620 PROC_CMD_FIBER_DISABLE |1621 PROC_CMD_READ_MOD_WRITE_PORT |1622 PROC_CMD_RST_CONF_PORT | PROC_CMD_FIBER_100BASE_FX);1623 if (ret)1624 return ret;1625 1626 /* Disable SerDes for 1000Base-X */1627 ret = vsc8584_cmd(phydev, PROC_CMD_FIBER_MEDIA_CONF |1628 PROC_CMD_FIBER_PORT(vsc8531->addr) |1629 PROC_CMD_FIBER_DISABLE |1630 PROC_CMD_READ_MOD_WRITE_PORT |1631 PROC_CMD_RST_CONF_PORT | PROC_CMD_FIBER_1000BASE_X);1632 if (ret)1633 return ret;1634 1635 return vsc85xx_sd6g_config_v2(phydev);1636}1637 1638static int vsc8574_config_host_serdes(struct phy_device *phydev)1639{1640 struct vsc8531_private *vsc8531 = phydev->priv;1641 int ret;1642 u16 val;1643 1644 ret = phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS,1645 MSCC_PHY_PAGE_EXTENDED_GPIO);1646 if (ret)1647 return ret;1648 1649 val = phy_base_read(phydev, MSCC_PHY_MAC_CFG_FASTLINK);1650 val &= ~MAC_CFG_MASK;1651 if (phydev->interface == PHY_INTERFACE_MODE_QSGMII) {1652 val |= MAC_CFG_QSGMII;1653 } else if (phydev->interface == PHY_INTERFACE_MODE_SGMII) {1654 val |= MAC_CFG_SGMII;1655 } else if (phy_interface_is_rgmii(phydev)) {1656 val |= MAC_CFG_RGMII;1657 } else {1658 ret = -EINVAL;1659 return ret;1660 }1661 1662 ret = phy_base_write(phydev, MSCC_PHY_MAC_CFG_FASTLINK, val);1663 if (ret)1664 return ret;1665 1666 ret = phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS,1667 MSCC_PHY_PAGE_STANDARD);1668 if (ret)1669 return ret;1670 1671 if (!phy_interface_is_rgmii(phydev)) {1672 val = PROC_CMD_MCB_ACCESS_MAC_CONF | PROC_CMD_RST_CONF_PORT |1673 PROC_CMD_READ_MOD_WRITE_PORT;1674 if (phydev->interface == PHY_INTERFACE_MODE_QSGMII)1675 val |= PROC_CMD_QSGMII_MAC;1676 else1677 val |= PROC_CMD_SGMII_MAC;1678 1679 ret = vsc8584_cmd(phydev, val);1680 if (ret)1681 return ret;1682 1683 usleep_range(10000, 20000);1684 }1685 1686 /* Disable SerDes for 100Base-FX */1687 ret = vsc8584_cmd(phydev, PROC_CMD_FIBER_MEDIA_CONF |1688 PROC_CMD_FIBER_PORT(vsc8531->addr) |1689 PROC_CMD_FIBER_DISABLE |1690 PROC_CMD_READ_MOD_WRITE_PORT |1691 PROC_CMD_RST_CONF_PORT | PROC_CMD_FIBER_100BASE_FX);1692 if (ret)1693 return ret;1694 1695 /* Disable SerDes for 1000Base-X */1696 return vsc8584_cmd(phydev, PROC_CMD_FIBER_MEDIA_CONF |1697 PROC_CMD_FIBER_PORT(vsc8531->addr) |1698 PROC_CMD_FIBER_DISABLE |1699 PROC_CMD_READ_MOD_WRITE_PORT |1700 PROC_CMD_RST_CONF_PORT | PROC_CMD_FIBER_1000BASE_X);1701}1702 1703static int vsc8584_config_init(struct phy_device *phydev)1704{1705 struct vsc8531_private *vsc8531 = phydev->priv;1706 int ret, i;1707 u16 val;1708 1709 phydev->mdix_ctrl = ETH_TP_MDI_AUTO;1710 1711 phy_lock_mdio_bus(phydev);1712 1713 /* Some parts of the init sequence are identical for every PHY in the1714 * package. Some parts are modifying the GPIO register bank which is a1715 * set of registers that are affecting all PHYs, a few resetting the1716 * microprocessor common to all PHYs. The CRC check responsible of the1717 * checking the firmware within the 8051 microprocessor can only be1718 * accessed via the PHY whose internal address in the package is 0.1719 * All PHYs' interrupts mask register has to be zeroed before enabling1720 * any PHY's interrupt in this register.1721 * For all these reasons, we need to do the init sequence once and only1722 * once whatever is the first PHY in the package that is initialized and1723 * do the correct init sequence for all PHYs that are package-critical1724 * in this pre-init function.1725 */1726 if (phy_package_init_once(phydev)) {1727 /* The following switch statement assumes that the lowest1728 * nibble of the phy_id_mask is always 0. This works because1729 * the lowest nibble of the PHY_ID's below are also 0.1730 */1731 WARN_ON(phydev->drv->phy_id_mask & 0xf);1732 1733 switch (phydev->phy_id & phydev->drv->phy_id_mask) {1734 case PHY_ID_VSC8504:1735 case PHY_ID_VSC8552:1736 case PHY_ID_VSC8572:1737 case PHY_ID_VSC8574:1738 ret = vsc8574_config_pre_init(phydev);1739 if (ret)1740 goto err;1741 ret = vsc8574_config_host_serdes(phydev);1742 if (ret)1743 goto err;1744 break;1745 case PHY_ID_VSC856X:1746 case PHY_ID_VSC8575:1747 case PHY_ID_VSC8582:1748 case PHY_ID_VSC8584:1749 ret = vsc8584_config_pre_init(phydev);1750 if (ret)1751 goto err;1752 ret = vsc8584_config_host_serdes(phydev);1753 if (ret)1754 goto err;1755 vsc85xx_coma_mode_release(phydev);1756 break;1757 default:1758 ret = -EINVAL;1759 break;1760 }1761 1762 if (ret)1763 goto err;1764 }1765 1766 phy_unlock_mdio_bus(phydev);1767 1768 ret = vsc8584_macsec_init(phydev);1769 if (ret)1770 return ret;1771 1772 ret = vsc8584_ptp_init(phydev);1773 if (ret)1774 return ret;1775 1776 val = phy_read(phydev, MSCC_PHY_EXT_PHY_CNTL_1);1777 val &= ~(MEDIA_OP_MODE_MASK | VSC8584_MAC_IF_SELECTION_MASK);1778 val |= (MEDIA_OP_MODE_COPPER << MEDIA_OP_MODE_POS) |1779 (VSC8584_MAC_IF_SELECTION_SGMII << VSC8584_MAC_IF_SELECTION_POS);1780 ret = phy_write(phydev, MSCC_PHY_EXT_PHY_CNTL_1, val);1781 if (ret)1782 return ret;1783 1784 ret = vsc85xx_update_rgmii_cntl(phydev, VSC8572_RGMII_CNTL,1785 VSC8572_RGMII_RX_DELAY_MASK,1786 VSC8572_RGMII_TX_DELAY_MASK);1787 if (ret)1788 return ret;1789 1790 ret = genphy_soft_reset(phydev);1791 if (ret)1792 return ret;1793 1794 for (i = 0; i < vsc8531->nleds; i++) {1795 ret = vsc85xx_led_cntl_set(phydev, i, vsc8531->leds_mode[i]);1796 if (ret)1797 return ret;1798 }1799 1800 return 0;1801 1802err:1803 phy_unlock_mdio_bus(phydev);1804 return ret;1805}1806 1807static irqreturn_t vsc8584_handle_interrupt(struct phy_device *phydev)1808{1809 irqreturn_t ret;1810 int irq_status;1811 1812 irq_status = phy_read(phydev, MII_VSC85XX_INT_STATUS);1813 if (irq_status < 0)1814 return IRQ_NONE;1815 1816 /* Timestamping IRQ does not set a bit in the global INT_STATUS, so1817 * irq_status would be 0.1818 */1819 ret = vsc8584_handle_ts_interrupt(phydev);1820 if (!(irq_status & MII_VSC85XX_INT_MASK_MASK))1821 return ret;1822 1823 if (irq_status & MII_VSC85XX_INT_MASK_EXT)1824 vsc8584_handle_macsec_interrupt(phydev);1825 1826 if (irq_status & MII_VSC85XX_INT_MASK_LINK_CHG)1827 phy_trigger_machine(phydev);1828 1829 return IRQ_HANDLED;1830}1831 1832static int vsc85xx_config_init(struct phy_device *phydev)1833{1834 int rc, i, phy_id;1835 struct vsc8531_private *vsc8531 = phydev->priv;1836 1837 rc = vsc85xx_default_config(phydev);1838 if (rc)1839 return rc;1840 1841 rc = vsc85xx_mac_if_set(phydev, phydev->interface);1842 if (rc)1843 return rc;1844 1845 rc = vsc85xx_edge_rate_cntl_set(phydev, vsc8531->rate_magic);1846 if (rc)1847 return rc;1848 1849 phy_id = phydev->drv->phy_id & phydev->drv->phy_id_mask;1850 if (PHY_ID_VSC8531 == phy_id || PHY_ID_VSC8541 == phy_id ||1851 PHY_ID_VSC8530 == phy_id || PHY_ID_VSC8540 == phy_id) {1852 rc = vsc8531_pre_init_seq_set(phydev);1853 if (rc)1854 return rc;1855 }1856 1857 rc = vsc85xx_eee_init_seq_set(phydev);1858 if (rc)1859 return rc;1860 1861 for (i = 0; i < vsc8531->nleds; i++) {1862 rc = vsc85xx_led_cntl_set(phydev, i, vsc8531->leds_mode[i]);1863 if (rc)1864 return rc;1865 }1866 1867 return 0;1868}1869 1870static int __phy_write_mcb_s6g(struct phy_device *phydev, u32 reg, u8 mcb,1871 u32 op)1872{1873 unsigned long deadline;1874 u32 val;1875 int ret;1876 1877 ret = vsc85xx_csr_write(phydev, PHY_MCB_TARGET, reg,1878 op | (1 << mcb));1879 if (ret)1880 return -EINVAL;1881 1882 deadline = jiffies + msecs_to_jiffies(PROC_CMD_NCOMPLETED_TIMEOUT_MS);1883 do {1884 usleep_range(500, 1000);1885 val = vsc85xx_csr_read(phydev, PHY_MCB_TARGET, reg);1886 1887 if (val == 0xffffffff)1888 return -EIO;1889 1890 } while (time_before(jiffies, deadline) && (val & op));1891 1892 if (val & op)1893 return -ETIMEDOUT;1894 1895 return 0;1896}1897 1898/* Trigger a read to the specified MCB */1899int phy_update_mcb_s6g(struct phy_device *phydev, u32 reg, u8 mcb)1900{1901 return __phy_write_mcb_s6g(phydev, reg, mcb, PHY_MCB_S6G_READ);1902}1903 1904/* Trigger a write to the specified MCB */1905int phy_commit_mcb_s6g(struct phy_device *phydev, u32 reg, u8 mcb)1906{1907 return __phy_write_mcb_s6g(phydev, reg, mcb, PHY_MCB_S6G_WRITE);1908}1909 1910static int vsc8514_config_host_serdes(struct phy_device *phydev)1911{1912 int ret;1913 u16 val;1914 1915 ret = phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS,1916 MSCC_PHY_PAGE_EXTENDED_GPIO);1917 if (ret)1918 return ret;1919 1920 val = phy_base_read(phydev, MSCC_PHY_MAC_CFG_FASTLINK);1921 val &= ~MAC_CFG_MASK;1922 val |= MAC_CFG_QSGMII;1923 ret = phy_base_write(phydev, MSCC_PHY_MAC_CFG_FASTLINK, val);1924 if (ret)1925 return ret;1926 1927 ret = phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS,1928 MSCC_PHY_PAGE_STANDARD);1929 if (ret)1930 return ret;1931 1932 ret = vsc8584_cmd(phydev, PROC_CMD_NOP);1933 if (ret)1934 return ret;1935 1936 ret = vsc8584_cmd(phydev,1937 PROC_CMD_MCB_ACCESS_MAC_CONF |1938 PROC_CMD_RST_CONF_PORT |1939 PROC_CMD_READ_MOD_WRITE_PORT | PROC_CMD_QSGMII_MAC);1940 if (ret) {1941 dev_err(&phydev->mdio.dev, "%s: QSGMII error: %d\n",1942 __func__, ret);1943 return ret;1944 }1945 1946 /* Apply 6G SerDes FOJI Algorithm1947 * Initial condition requirement:1948 * 1. hold 8051 in reset1949 * 2. disable patch vector 0, in order to allow IB cal poll during FoJi1950 * 3. deassert 8051 reset after change patch vector status1951 * 4. proceed with FoJi (vsc85xx_sd6g_config_v2)1952 */1953 vsc8584_micro_assert_reset(phydev);1954 val = phy_base_read(phydev, MSCC_INT_MEM_CNTL);1955 /* clear bit 8, to disable patch vector 0 */1956 val &= ~PATCH_VEC_ZERO_EN;1957 ret = phy_base_write(phydev, MSCC_INT_MEM_CNTL, val);1958 /* Enable 8051 clock, don't set patch present, disable PRAM clock override */1959 vsc8584_micro_deassert_reset(phydev, false);1960 1961 return vsc85xx_sd6g_config_v2(phydev);1962}1963 1964static int vsc8514_config_pre_init(struct phy_device *phydev)1965{1966 /* These are the settings to override the silicon default1967 * values to handle hardware performance of PHY. They1968 * are set at Power-On state and remain until PHY Reset.1969 */1970 static const struct reg_val pre_init1[] = {1971 {0x0f90, 0x00688980},1972 {0x0786, 0x00000003},1973 {0x07fa, 0x0050100f},1974 {0x0f82, 0x0012b002},1975 {0x1686, 0x00000004},1976 {0x168c, 0x00d2c46f},1977 {0x17a2, 0x00000620},1978 {0x16a0, 0x00eeffdd},1979 {0x16a6, 0x00071448},1980 {0x16a4, 0x0013132f},1981 {0x16a8, 0x00000000},1982 {0x0ffc, 0x00c0a028},1983 {0x0fe8, 0x0091b06c},1984 {0x0fea, 0x00041600},1985 {0x0f80, 0x00fffaff},1986 {0x0fec, 0x00901809},1987 {0x0ffe, 0x00b01007},1988 {0x16b0, 0x00eeff00},1989 {0x16b2, 0x00007000},1990 {0x16b4, 0x00000814},1991 };1992 struct device *dev = &phydev->mdio.dev;1993 unsigned int i;1994 u16 reg;1995 int ret;1996 1997 ret = vsc8584_pll5g_reset(phydev);1998 if (ret < 0) {1999 dev_err(dev, "failed LCPLL reset, ret: %d\n", ret);2000 return ret;2001 }2002 2003 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);2004 2005 /* all writes below are broadcasted to all PHYs in the same package */2006 reg = phy_base_read(phydev, MSCC_PHY_EXT_CNTL_STATUS);2007 reg |= SMI_BROADCAST_WR_EN;2008 phy_base_write(phydev, MSCC_PHY_EXT_CNTL_STATUS, reg);2009 2010 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_TEST);2011 2012 reg = phy_base_read(phydev, MSCC_PHY_TEST_PAGE_8);2013 reg |= BIT(15);2014 phy_base_write(phydev, MSCC_PHY_TEST_PAGE_8, reg);2015 2016 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_TR);2017 2018 for (i = 0; i < ARRAY_SIZE(pre_init1); i++)2019 vsc8584_csr_write(phydev, pre_init1[i].reg, pre_init1[i].val);2020 2021 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_TEST);2022 2023 reg = phy_base_read(phydev, MSCC_PHY_TEST_PAGE_8);2024 reg &= ~BIT(15);2025 phy_base_write(phydev, MSCC_PHY_TEST_PAGE_8, reg);2026 2027 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);2028 2029 reg = phy_base_read(phydev, MSCC_PHY_EXT_CNTL_STATUS);2030 reg &= ~SMI_BROADCAST_WR_EN;2031 phy_base_write(phydev, MSCC_PHY_EXT_CNTL_STATUS, reg);2032 2033 /* Add pre-patching commands to:2034 * 1. enable 8051 clock, operate 8051 clock at 125 MHz2035 * instead of HW default 62.5MHz2036 * 2. write patch vector 0, to skip IB cal polling executed2037 * as part of the 0x80E0 ROM command2038 */2039 vsc8584_micro_deassert_reset(phydev, false);2040 2041 vsc8584_micro_assert_reset(phydev);2042 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS,2043 MSCC_PHY_PAGE_EXTENDED_GPIO);2044 /* ROM address to trap, for patch vector 0 */2045 reg = MSCC_ROM_TRAP_SERDES_6G_CFG;2046 ret = phy_base_write(phydev, MSCC_TRAP_ROM_ADDR(1), reg);2047 if (ret)2048 goto err;2049 /* RAM address to jump to, when patch vector 0 enabled */2050 reg = MSCC_RAM_TRAP_SERDES_6G_CFG;2051 ret = phy_base_write(phydev, MSCC_PATCH_RAM_ADDR(1), reg);2052 if (ret)2053 goto err;2054 reg = phy_base_read(phydev, MSCC_INT_MEM_CNTL);2055 reg |= PATCH_VEC_ZERO_EN; /* bit 8, enable patch vector 0 */2056 ret = phy_base_write(phydev, MSCC_INT_MEM_CNTL, reg);2057 if (ret)2058 goto err;2059 2060 /* Enable 8051 clock, don't set patch present2061 * yet, disable PRAM clock override2062 */2063 vsc8584_micro_deassert_reset(phydev, false);2064 return ret;2065 err:2066 /* restore 8051 and bail w error */2067 vsc8584_micro_deassert_reset(phydev, false);2068 return ret;2069}2070 2071static int vsc8514_config_init(struct phy_device *phydev)2072{2073 struct vsc8531_private *vsc8531 = phydev->priv;2074 int ret, i;2075 2076 phydev->mdix_ctrl = ETH_TP_MDI_AUTO;2077 2078 phy_lock_mdio_bus(phydev);2079 2080 /* Some parts of the init sequence are identical for every PHY in the2081 * package. Some parts are modifying the GPIO register bank which is a2082 * set of registers that are affecting all PHYs, a few resetting the2083 * microprocessor common to all PHYs.2084 * All PHYs' interrupts mask register has to be zeroed before enabling2085 * any PHY's interrupt in this register.2086 * For all these reasons, we need to do the init sequence once and only2087 * once whatever is the first PHY in the package that is initialized and2088 * do the correct init sequence for all PHYs that are package-critical2089 * in this pre-init function.2090 */2091 if (phy_package_init_once(phydev)) {2092 ret = vsc8514_config_pre_init(phydev);2093 if (ret)2094 goto err;2095 ret = vsc8514_config_host_serdes(phydev);2096 if (ret)2097 goto err;2098 vsc85xx_coma_mode_release(phydev);2099 }2100 2101 phy_unlock_mdio_bus(phydev);2102 2103 ret = phy_modify(phydev, MSCC_PHY_EXT_PHY_CNTL_1, MEDIA_OP_MODE_MASK,2104 MEDIA_OP_MODE_COPPER << MEDIA_OP_MODE_POS);2105 2106 if (ret)2107 return ret;2108 2109 ret = genphy_soft_reset(phydev);2110 2111 if (ret)2112 return ret;2113 2114 for (i = 0; i < vsc8531->nleds; i++) {2115 ret = vsc85xx_led_cntl_set(phydev, i, vsc8531->leds_mode[i]);2116 if (ret)2117 return ret;2118 }2119 2120 return ret;2121 2122err:2123 phy_unlock_mdio_bus(phydev);2124 return ret;2125}2126 2127static int vsc85xx_ack_interrupt(struct phy_device *phydev)2128{2129 int rc = 0;2130 2131 if (phydev->interrupts == PHY_INTERRUPT_ENABLED)2132 rc = phy_read(phydev, MII_VSC85XX_INT_STATUS);2133 2134 return (rc < 0) ? rc : 0;2135}2136 2137static int vsc85xx_config_intr(struct phy_device *phydev)2138{2139 int rc;2140 2141 if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {2142 rc = vsc85xx_ack_interrupt(phydev);2143 if (rc)2144 return rc;2145 2146 vsc8584_config_macsec_intr(phydev);2147 vsc8584_config_ts_intr(phydev);2148 2149 rc = phy_write(phydev, MII_VSC85XX_INT_MASK,2150 MII_VSC85XX_INT_MASK_MASK);2151 } else {2152 rc = phy_write(phydev, MII_VSC85XX_INT_MASK, 0);2153 if (rc < 0)2154 return rc;2155 rc = phy_read(phydev, MII_VSC85XX_INT_STATUS);2156 if (rc < 0)2157 return rc;2158 2159 rc = vsc85xx_ack_interrupt(phydev);2160 }2161 2162 return rc;2163}2164 2165static irqreturn_t vsc85xx_handle_interrupt(struct phy_device *phydev)2166{2167 int irq_status;2168 2169 irq_status = phy_read(phydev, MII_VSC85XX_INT_STATUS);2170 if (irq_status < 0) {2171 phy_error(phydev);2172 return IRQ_NONE;2173 }2174 2175 if (!(irq_status & MII_VSC85XX_INT_MASK_MASK))2176 return IRQ_NONE;2177 2178 phy_trigger_machine(phydev);2179 2180 return IRQ_HANDLED;2181}2182 2183static int vsc85xx_config_aneg(struct phy_device *phydev)2184{2185 int rc;2186 2187 rc = vsc85xx_mdix_set(phydev, phydev->mdix_ctrl);2188 if (rc < 0)2189 return rc;2190 2191 return genphy_config_aneg(phydev);2192}2193 2194static int vsc85xx_read_status(struct phy_device *phydev)2195{2196 int rc;2197 2198 rc = vsc85xx_mdix_get(phydev, &phydev->mdix);2199 if (rc < 0)2200 return rc;2201 2202 return genphy_read_status(phydev);2203}2204 2205static int vsc8514_probe(struct phy_device *phydev)2206{2207 struct vsc8531_private *vsc8531;2208 u32 default_mode[4] = {VSC8531_LINK_1000_ACTIVITY,2209 VSC8531_LINK_100_ACTIVITY, VSC8531_LINK_ACTIVITY,2210 VSC8531_DUPLEX_COLLISION};2211 2212 vsc8531 = devm_kzalloc(&phydev->mdio.dev, sizeof(*vsc8531), GFP_KERNEL);2213 if (!vsc8531)2214 return -ENOMEM;2215 2216 phydev->priv = vsc8531;2217 2218 vsc8584_get_base_addr(phydev);2219 devm_phy_package_join(&phydev->mdio.dev, phydev,2220 vsc8531->base_addr, 0);2221 2222 vsc8531->nleds = 4;2223 vsc8531->supp_led_modes = VSC85XX_SUPP_LED_MODES;2224 vsc8531->hw_stats = vsc85xx_hw_stats;2225 vsc8531->nstats = ARRAY_SIZE(vsc85xx_hw_stats);2226 vsc8531->stats = devm_kcalloc(&phydev->mdio.dev, vsc8531->nstats,2227 sizeof(u64), GFP_KERNEL);2228 if (!vsc8531->stats)2229 return -ENOMEM;2230 2231 return vsc85xx_dt_led_modes_get(phydev, default_mode);2232}2233 2234static int vsc8574_probe(struct phy_device *phydev)2235{2236 struct vsc8531_private *vsc8531;2237 u32 default_mode[4] = {VSC8531_LINK_1000_ACTIVITY,2238 VSC8531_LINK_100_ACTIVITY, VSC8531_LINK_ACTIVITY,2239 VSC8531_DUPLEX_COLLISION};2240 2241 vsc8531 = devm_kzalloc(&phydev->mdio.dev, sizeof(*vsc8531), GFP_KERNEL);2242 if (!vsc8531)2243 return -ENOMEM;2244 2245 phydev->priv = vsc8531;2246 2247 vsc8584_get_base_addr(phydev);2248 devm_phy_package_join(&phydev->mdio.dev, phydev,2249 vsc8531->base_addr, 0);2250 2251 vsc8531->nleds = 4;2252 vsc8531->supp_led_modes = VSC8584_SUPP_LED_MODES;2253 vsc8531->hw_stats = vsc8584_hw_stats;2254 vsc8531->nstats = ARRAY_SIZE(vsc8584_hw_stats);2255 vsc8531->stats = devm_kcalloc(&phydev->mdio.dev, vsc8531->nstats,2256 sizeof(u64), GFP_KERNEL);2257 if (!vsc8531->stats)2258 return -ENOMEM;2259 2260 return vsc85xx_dt_led_modes_get(phydev, default_mode);2261}2262 2263static int vsc8584_probe(struct phy_device *phydev)2264{2265 struct vsc8531_private *vsc8531;2266 u32 default_mode[4] = {VSC8531_LINK_1000_ACTIVITY,2267 VSC8531_LINK_100_ACTIVITY, VSC8531_LINK_ACTIVITY,2268 VSC8531_DUPLEX_COLLISION};2269 int ret;2270 2271 if ((phydev->phy_id & MSCC_DEV_REV_MASK) != VSC8584_REVB) {2272 dev_err(&phydev->mdio.dev, "Only VSC8584 revB is supported.\n");2273 return -ENOTSUPP;2274 }2275 2276 vsc8531 = devm_kzalloc(&phydev->mdio.dev, sizeof(*vsc8531), GFP_KERNEL);2277 if (!vsc8531)2278 return -ENOMEM;2279 2280 phydev->priv = vsc8531;2281 2282 vsc8584_get_base_addr(phydev);2283 devm_phy_package_join(&phydev->mdio.dev, phydev, vsc8531->base_addr,2284 sizeof(struct vsc85xx_shared_private));2285 2286 vsc8531->nleds = 4;2287 vsc8531->supp_led_modes = VSC8584_SUPP_LED_MODES;2288 vsc8531->hw_stats = vsc8584_hw_stats;2289 vsc8531->nstats = ARRAY_SIZE(vsc8584_hw_stats);2290 vsc8531->stats = devm_kcalloc(&phydev->mdio.dev, vsc8531->nstats,2291 sizeof(u64), GFP_KERNEL);2292 if (!vsc8531->stats)2293 return -ENOMEM;2294 2295 if (phy_package_probe_once(phydev)) {2296 ret = vsc8584_ptp_probe_once(phydev);2297 if (ret)2298 return ret;2299 }2300 2301 ret = vsc8584_ptp_probe(phydev);2302 if (ret)2303 return ret;2304 2305 return vsc85xx_dt_led_modes_get(phydev, default_mode);2306}2307 2308static int vsc85xx_probe(struct phy_device *phydev)2309{2310 struct vsc8531_private *vsc8531;2311 int rate_magic;2312 u32 default_mode[2] = {VSC8531_LINK_1000_ACTIVITY,2313 VSC8531_LINK_100_ACTIVITY};2314 2315 rate_magic = vsc85xx_edge_rate_magic_get(phydev);2316 if (rate_magic < 0)2317 return rate_magic;2318 2319 vsc8531 = devm_kzalloc(&phydev->mdio.dev, sizeof(*vsc8531), GFP_KERNEL);2320 if (!vsc8531)2321 return -ENOMEM;2322 2323 phydev->priv = vsc8531;2324 2325 vsc8531->rate_magic = rate_magic;2326 vsc8531->nleds = 2;2327 vsc8531->supp_led_modes = VSC85XX_SUPP_LED_MODES;2328 vsc8531->hw_stats = vsc85xx_hw_stats;2329 vsc8531->nstats = ARRAY_SIZE(vsc85xx_hw_stats);2330 vsc8531->stats = devm_kcalloc(&phydev->mdio.dev, vsc8531->nstats,2331 sizeof(u64), GFP_KERNEL);2332 if (!vsc8531->stats)2333 return -ENOMEM;2334 2335 return vsc85xx_dt_led_modes_get(phydev, default_mode);2336}2337 2338/* Microsemi VSC85xx PHYs */2339static struct phy_driver vsc85xx_driver[] = {2340{2341 .phy_id = PHY_ID_VSC8501,2342 .name = "Microsemi GE VSC8501 SyncE",2343 .phy_id_mask = 0xfffffff0,2344 /* PHY_BASIC_FEATURES */2345 .soft_reset = &genphy_soft_reset,2346 .config_init = &vsc85xx_config_init,2347 .config_aneg = &vsc85xx_config_aneg,2348 .read_status = &vsc85xx_read_status,2349 .handle_interrupt = vsc85xx_handle_interrupt,2350 .config_intr = &vsc85xx_config_intr,2351 .suspend = &genphy_suspend,2352 .resume = &genphy_resume,2353 .probe = &vsc85xx_probe,2354 .set_wol = &vsc85xx_wol_set,2355 .get_wol = &vsc85xx_wol_get,2356 .get_tunable = &vsc85xx_get_tunable,2357 .set_tunable = &vsc85xx_set_tunable,2358 .read_page = &vsc85xx_phy_read_page,2359 .write_page = &vsc85xx_phy_write_page,2360 .get_sset_count = &vsc85xx_get_sset_count,2361 .get_strings = &vsc85xx_get_strings,2362 .get_stats = &vsc85xx_get_stats,2363},2364{2365 .phy_id = PHY_ID_VSC8502,2366 .name = "Microsemi GE VSC8502 SyncE",2367 .phy_id_mask = 0xfffffff0,2368 /* PHY_BASIC_FEATURES */2369 .soft_reset = &genphy_soft_reset,2370 .config_init = &vsc85xx_config_init,2371 .config_aneg = &vsc85xx_config_aneg,2372 .read_status = &vsc85xx_read_status,2373 .handle_interrupt = vsc85xx_handle_interrupt,2374 .config_intr = &vsc85xx_config_intr,2375 .suspend = &genphy_suspend,2376 .resume = &genphy_resume,2377 .probe = &vsc85xx_probe,2378 .set_wol = &vsc85xx_wol_set,2379 .get_wol = &vsc85xx_wol_get,2380 .get_tunable = &vsc85xx_get_tunable,2381 .set_tunable = &vsc85xx_set_tunable,2382 .read_page = &vsc85xx_phy_read_page,2383 .write_page = &vsc85xx_phy_write_page,2384 .get_sset_count = &vsc85xx_get_sset_count,2385 .get_strings = &vsc85xx_get_strings,2386 .get_stats = &vsc85xx_get_stats,2387},2388{2389 .phy_id = PHY_ID_VSC8504,2390 .name = "Microsemi GE VSC8504 SyncE",2391 .phy_id_mask = 0xfffffff0,2392 /* PHY_GBIT_FEATURES */2393 .soft_reset = &genphy_soft_reset,2394 .config_init = &vsc8584_config_init,2395 .config_aneg = &vsc85xx_config_aneg,2396 .aneg_done = &genphy_aneg_done,2397 .read_status = &vsc85xx_read_status,2398 .handle_interrupt = vsc85xx_handle_interrupt,2399 .config_intr = &vsc85xx_config_intr,2400 .suspend = &genphy_suspend,2401 .resume = &genphy_resume,2402 .probe = &vsc8574_probe,2403 .set_wol = &vsc85xx_wol_set,2404 .get_wol = &vsc85xx_wol_get,2405 .get_tunable = &vsc85xx_get_tunable,2406 .set_tunable = &vsc85xx_set_tunable,2407 .read_page = &vsc85xx_phy_read_page,2408 .write_page = &vsc85xx_phy_write_page,2409 .get_sset_count = &vsc85xx_get_sset_count,2410 .get_strings = &vsc85xx_get_strings,2411 .get_stats = &vsc85xx_get_stats,2412},2413{2414 .phy_id = PHY_ID_VSC8514,2415 .name = "Microsemi GE VSC8514 SyncE",2416 .phy_id_mask = 0xfffffff0,2417 .soft_reset = &genphy_soft_reset,2418 .config_init = &vsc8514_config_init,2419 .config_aneg = &vsc85xx_config_aneg,2420 .read_status = &vsc85xx_read_status,2421 .handle_interrupt = vsc85xx_handle_interrupt,2422 .config_intr = &vsc85xx_config_intr,2423 .suspend = &genphy_suspend,2424 .resume = &genphy_resume,2425 .probe = &vsc8514_probe,2426 .set_wol = &vsc85xx_wol_set,2427 .get_wol = &vsc85xx_wol_get,2428 .get_tunable = &vsc85xx_get_tunable,2429 .set_tunable = &vsc85xx_set_tunable,2430 .read_page = &vsc85xx_phy_read_page,2431 .write_page = &vsc85xx_phy_write_page,2432 .get_sset_count = &vsc85xx_get_sset_count,2433 .get_strings = &vsc85xx_get_strings,2434 .get_stats = &vsc85xx_get_stats,2435},2436{2437 .phy_id = PHY_ID_VSC8530,2438 .name = "Microsemi FE VSC8530",2439 .phy_id_mask = 0xfffffff0,2440 /* PHY_BASIC_FEATURES */2441 .soft_reset = &genphy_soft_reset,2442 .config_init = &vsc85xx_config_init,2443 .config_aneg = &vsc85xx_config_aneg,2444 .read_status = &vsc85xx_read_status,2445 .handle_interrupt = vsc85xx_handle_interrupt,2446 .config_intr = &vsc85xx_config_intr,2447 .suspend = &genphy_suspend,2448 .resume = &genphy_resume,2449 .probe = &vsc85xx_probe,2450 .set_wol = &vsc85xx_wol_set,2451 .get_wol = &vsc85xx_wol_get,2452 .get_tunable = &vsc85xx_get_tunable,2453 .set_tunable = &vsc85xx_set_tunable,2454 .read_page = &vsc85xx_phy_read_page,2455 .write_page = &vsc85xx_phy_write_page,2456 .get_sset_count = &vsc85xx_get_sset_count,2457 .get_strings = &vsc85xx_get_strings,2458 .get_stats = &vsc85xx_get_stats,2459},2460{2461 .phy_id = PHY_ID_VSC8531,2462 .name = "Microsemi VSC8531",2463 .phy_id_mask = 0xfffffff0,2464 /* PHY_GBIT_FEATURES */2465 .soft_reset = &genphy_soft_reset,2466 .config_init = &vsc85xx_config_init,2467 .config_aneg = &vsc85xx_config_aneg,2468 .read_status = &vsc85xx_read_status,2469 .handle_interrupt = vsc85xx_handle_interrupt,2470 .config_intr = &vsc85xx_config_intr,2471 .suspend = &genphy_suspend,2472 .resume = &genphy_resume,2473 .probe = &vsc85xx_probe,2474 .set_wol = &vsc85xx_wol_set,2475 .get_wol = &vsc85xx_wol_get,2476 .get_tunable = &vsc85xx_get_tunable,2477 .set_tunable = &vsc85xx_set_tunable,2478 .read_page = &vsc85xx_phy_read_page,2479 .write_page = &vsc85xx_phy_write_page,2480 .get_sset_count = &vsc85xx_get_sset_count,2481 .get_strings = &vsc85xx_get_strings,2482 .get_stats = &vsc85xx_get_stats,2483},2484{2485 .phy_id = PHY_ID_VSC8540,2486 .name = "Microsemi FE VSC8540 SyncE",2487 .phy_id_mask = 0xfffffff0,2488 /* PHY_BASIC_FEATURES */2489 .soft_reset = &genphy_soft_reset,2490 .config_init = &vsc85xx_config_init,2491 .config_aneg = &vsc85xx_config_aneg,2492 .read_status = &vsc85xx_read_status,2493 .handle_interrupt = vsc85xx_handle_interrupt,2494 .config_intr = &vsc85xx_config_intr,2495 .suspend = &genphy_suspend,2496 .resume = &genphy_resume,2497 .probe = &vsc85xx_probe,2498 .set_wol = &vsc85xx_wol_set,2499 .get_wol = &vsc85xx_wol_get,2500 .get_tunable = &vsc85xx_get_tunable,2501 .set_tunable = &vsc85xx_set_tunable,2502 .read_page = &vsc85xx_phy_read_page,2503 .write_page = &vsc85xx_phy_write_page,2504 .get_sset_count = &vsc85xx_get_sset_count,2505 .get_strings = &vsc85xx_get_strings,2506 .get_stats = &vsc85xx_get_stats,2507},2508{2509 .phy_id = PHY_ID_VSC8541,2510 .name = "Microsemi VSC8541 SyncE",2511 .phy_id_mask = 0xfffffff0,2512 /* PHY_GBIT_FEATURES */2513 .soft_reset = &genphy_soft_reset,2514 .config_init = &vsc85xx_config_init,2515 .config_aneg = &vsc85xx_config_aneg,2516 .read_status = &vsc85xx_read_status,2517 .handle_interrupt = vsc85xx_handle_interrupt,2518 .config_intr = &vsc85xx_config_intr,2519 .suspend = &genphy_suspend,2520 .resume = &genphy_resume,2521 .probe = &vsc85xx_probe,2522 .set_wol = &vsc85xx_wol_set,2523 .get_wol = &vsc85xx_wol_get,2524 .get_tunable = &vsc85xx_get_tunable,2525 .set_tunable = &vsc85xx_set_tunable,2526 .read_page = &vsc85xx_phy_read_page,2527 .write_page = &vsc85xx_phy_write_page,2528 .get_sset_count = &vsc85xx_get_sset_count,2529 .get_strings = &vsc85xx_get_strings,2530 .get_stats = &vsc85xx_get_stats,2531},2532{2533 .phy_id = PHY_ID_VSC8552,2534 .name = "Microsemi GE VSC8552 SyncE",2535 .phy_id_mask = 0xfffffff0,2536 /* PHY_GBIT_FEATURES */2537 .soft_reset = &genphy_soft_reset,2538 .config_init = &vsc8584_config_init,2539 .config_aneg = &vsc85xx_config_aneg,2540 .read_status = &vsc85xx_read_status,2541 .handle_interrupt = vsc85xx_handle_interrupt,2542 .config_intr = &vsc85xx_config_intr,2543 .suspend = &genphy_suspend,2544 .resume = &genphy_resume,2545 .probe = &vsc8574_probe,2546 .set_wol = &vsc85xx_wol_set,2547 .get_wol = &vsc85xx_wol_get,2548 .get_tunable = &vsc85xx_get_tunable,2549 .set_tunable = &vsc85xx_set_tunable,2550 .read_page = &vsc85xx_phy_read_page,2551 .write_page = &vsc85xx_phy_write_page,2552 .get_sset_count = &vsc85xx_get_sset_count,2553 .get_strings = &vsc85xx_get_strings,2554 .get_stats = &vsc85xx_get_stats,2555},2556{2557 .phy_id = PHY_ID_VSC856X,2558 .name = "Microsemi GE VSC856X SyncE",2559 .phy_id_mask = 0xfffffff0,2560 /* PHY_GBIT_FEATURES */2561 .soft_reset = &genphy_soft_reset,2562 .config_init = &vsc8584_config_init,2563 .config_aneg = &vsc85xx_config_aneg,2564 .read_status = &vsc85xx_read_status,2565 .handle_interrupt = vsc85xx_handle_interrupt,2566 .config_intr = &vsc85xx_config_intr,2567 .suspend = &genphy_suspend,2568 .resume = &genphy_resume,2569 .probe = &vsc8584_probe,2570 .get_tunable = &vsc85xx_get_tunable,2571 .set_tunable = &vsc85xx_set_tunable,2572 .read_page = &vsc85xx_phy_read_page,2573 .write_page = &vsc85xx_phy_write_page,2574 .get_sset_count = &vsc85xx_get_sset_count,2575 .get_strings = &vsc85xx_get_strings,2576 .get_stats = &vsc85xx_get_stats,2577},2578{2579 .phy_id = PHY_ID_VSC8572,2580 .name = "Microsemi GE VSC8572 SyncE",2581 .phy_id_mask = 0xfffffff0,2582 /* PHY_GBIT_FEATURES */2583 .soft_reset = &genphy_soft_reset,2584 .config_init = &vsc8584_config_init,2585 .config_aneg = &vsc85xx_config_aneg,2586 .aneg_done = &genphy_aneg_done,2587 .read_status = &vsc85xx_read_status,2588 .handle_interrupt = &vsc8584_handle_interrupt,2589 .config_intr = &vsc85xx_config_intr,2590 .suspend = &genphy_suspend,2591 .resume = &genphy_resume,2592 .probe = &vsc8574_probe,2593 .set_wol = &vsc85xx_wol_set,2594 .get_wol = &vsc85xx_wol_get,2595 .get_tunable = &vsc85xx_get_tunable,2596 .set_tunable = &vsc85xx_set_tunable,2597 .read_page = &vsc85xx_phy_read_page,2598 .write_page = &vsc85xx_phy_write_page,2599 .get_sset_count = &vsc85xx_get_sset_count,2600 .get_strings = &vsc85xx_get_strings,2601 .get_stats = &vsc85xx_get_stats,2602},2603{2604 .phy_id = PHY_ID_VSC8574,2605 .name = "Microsemi GE VSC8574 SyncE",2606 .phy_id_mask = 0xfffffff0,2607 /* PHY_GBIT_FEATURES */2608 .soft_reset = &genphy_soft_reset,2609 .config_init = &vsc8584_config_init,2610 .config_aneg = &vsc85xx_config_aneg,2611 .aneg_done = &genphy_aneg_done,2612 .read_status = &vsc85xx_read_status,2613 .handle_interrupt = vsc85xx_handle_interrupt,2614 .config_intr = &vsc85xx_config_intr,2615 .suspend = &genphy_suspend,2616 .resume = &genphy_resume,2617 .probe = &vsc8574_probe,2618 .set_wol = &vsc85xx_wol_set,2619 .get_wol = &vsc85xx_wol_get,2620 .get_tunable = &vsc85xx_get_tunable,2621 .set_tunable = &vsc85xx_set_tunable,2622 .read_page = &vsc85xx_phy_read_page,2623 .write_page = &vsc85xx_phy_write_page,2624 .get_sset_count = &vsc85xx_get_sset_count,2625 .get_strings = &vsc85xx_get_strings,2626 .get_stats = &vsc85xx_get_stats,2627},2628{2629 .phy_id = PHY_ID_VSC8575,2630 .name = "Microsemi GE VSC8575 SyncE",2631 .phy_id_mask = 0xfffffff0,2632 /* PHY_GBIT_FEATURES */2633 .soft_reset = &genphy_soft_reset,2634 .config_init = &vsc8584_config_init,2635 .config_aneg = &vsc85xx_config_aneg,2636 .aneg_done = &genphy_aneg_done,2637 .read_status = &vsc85xx_read_status,2638 .handle_interrupt = &vsc8584_handle_interrupt,2639 .config_intr = &vsc85xx_config_intr,2640 .suspend = &genphy_suspend,2641 .resume = &genphy_resume,2642 .probe = &vsc8584_probe,2643 .get_tunable = &vsc85xx_get_tunable,2644 .set_tunable = &vsc85xx_set_tunable,2645 .read_page = &vsc85xx_phy_read_page,2646 .write_page = &vsc85xx_phy_write_page,2647 .get_sset_count = &vsc85xx_get_sset_count,2648 .get_strings = &vsc85xx_get_strings,2649 .get_stats = &vsc85xx_get_stats,2650},2651{2652 .phy_id = PHY_ID_VSC8582,2653 .name = "Microsemi GE VSC8582 SyncE",2654 .phy_id_mask = 0xfffffff0,2655 /* PHY_GBIT_FEATURES */2656 .soft_reset = &genphy_soft_reset,2657 .config_init = &vsc8584_config_init,2658 .config_aneg = &vsc85xx_config_aneg,2659 .aneg_done = &genphy_aneg_done,2660 .read_status = &vsc85xx_read_status,2661 .handle_interrupt = &vsc8584_handle_interrupt,2662 .config_intr = &vsc85xx_config_intr,2663 .suspend = &genphy_suspend,2664 .resume = &genphy_resume,2665 .probe = &vsc8584_probe,2666 .get_tunable = &vsc85xx_get_tunable,2667 .set_tunable = &vsc85xx_set_tunable,2668 .read_page = &vsc85xx_phy_read_page,2669 .write_page = &vsc85xx_phy_write_page,2670 .get_sset_count = &vsc85xx_get_sset_count,2671 .get_strings = &vsc85xx_get_strings,2672 .get_stats = &vsc85xx_get_stats,2673},2674{2675 .phy_id = PHY_ID_VSC8584,2676 .name = "Microsemi GE VSC8584 SyncE",2677 .phy_id_mask = 0xfffffff0,2678 /* PHY_GBIT_FEATURES */2679 .soft_reset = &genphy_soft_reset,2680 .config_init = &vsc8584_config_init,2681 .config_aneg = &vsc85xx_config_aneg,2682 .aneg_done = &genphy_aneg_done,2683 .read_status = &vsc85xx_read_status,2684 .handle_interrupt = &vsc8584_handle_interrupt,2685 .config_intr = &vsc85xx_config_intr,2686 .suspend = &genphy_suspend,2687 .resume = &genphy_resume,2688 .probe = &vsc8584_probe,2689 .get_tunable = &vsc85xx_get_tunable,2690 .set_tunable = &vsc85xx_set_tunable,2691 .read_page = &vsc85xx_phy_read_page,2692 .write_page = &vsc85xx_phy_write_page,2693 .get_sset_count = &vsc85xx_get_sset_count,2694 .get_strings = &vsc85xx_get_strings,2695 .get_stats = &vsc85xx_get_stats,2696 .link_change_notify = &vsc85xx_link_change_notify,2697}2698 2699};2700 2701module_phy_driver(vsc85xx_driver);2702 2703static struct mdio_device_id __maybe_unused vsc85xx_tbl[] = {2704 { PHY_ID_MATCH_VENDOR(PHY_VENDOR_MSCC) },2705 { }2706};2707 2708MODULE_DEVICE_TABLE(mdio, vsc85xx_tbl);2709 2710MODULE_DESCRIPTION("Microsemi VSC85xx PHY driver");2711MODULE_AUTHOR("Nagaraju Lakkaraju");2712MODULE_LICENSE("Dual MIT/GPL");2713 2714MODULE_FIRMWARE(MSCC_VSC8584_REVB_INT8051_FW);2715MODULE_FIRMWARE(MSCC_VSC8574_REVB_INT8051_FW);2716