brintos

brintos / linux-shallow public Read only

0
0
Text · 73.5 KiB · 6f74ce0 Raw
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