18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0 OR MIT)
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Driver for Microsemi VSC85xx PHYs
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Author: Nagaraju Lakkaraju
68c2ecf20Sopenharmony_ci * License: Dual MIT/GPL
78c2ecf20Sopenharmony_ci * Copyright (c) 2016 Microsemi Corporation
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <linux/firmware.h>
118c2ecf20Sopenharmony_ci#include <linux/jiffies.h>
128c2ecf20Sopenharmony_ci#include <linux/kernel.h>
138c2ecf20Sopenharmony_ci#include <linux/module.h>
148c2ecf20Sopenharmony_ci#include <linux/mdio.h>
158c2ecf20Sopenharmony_ci#include <linux/mii.h>
168c2ecf20Sopenharmony_ci#include <linux/phy.h>
178c2ecf20Sopenharmony_ci#include <linux/of.h>
188c2ecf20Sopenharmony_ci#include <linux/netdevice.h>
198c2ecf20Sopenharmony_ci#include <dt-bindings/net/mscc-phy-vsc8531.h>
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci#include "mscc.h"
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_cistatic const struct vsc85xx_hw_stat vsc85xx_hw_stats[] = {
248c2ecf20Sopenharmony_ci	{
258c2ecf20Sopenharmony_ci		.string	= "phy_receive_errors",
268c2ecf20Sopenharmony_ci		.reg	= MSCC_PHY_ERR_RX_CNT,
278c2ecf20Sopenharmony_ci		.page	= MSCC_PHY_PAGE_STANDARD,
288c2ecf20Sopenharmony_ci		.mask	= ERR_CNT_MASK,
298c2ecf20Sopenharmony_ci	}, {
308c2ecf20Sopenharmony_ci		.string	= "phy_false_carrier",
318c2ecf20Sopenharmony_ci		.reg	= MSCC_PHY_ERR_FALSE_CARRIER_CNT,
328c2ecf20Sopenharmony_ci		.page	= MSCC_PHY_PAGE_STANDARD,
338c2ecf20Sopenharmony_ci		.mask	= ERR_CNT_MASK,
348c2ecf20Sopenharmony_ci	}, {
358c2ecf20Sopenharmony_ci		.string	= "phy_cu_media_link_disconnect",
368c2ecf20Sopenharmony_ci		.reg	= MSCC_PHY_ERR_LINK_DISCONNECT_CNT,
378c2ecf20Sopenharmony_ci		.page	= MSCC_PHY_PAGE_STANDARD,
388c2ecf20Sopenharmony_ci		.mask	= ERR_CNT_MASK,
398c2ecf20Sopenharmony_ci	}, {
408c2ecf20Sopenharmony_ci		.string	= "phy_cu_media_crc_good_count",
418c2ecf20Sopenharmony_ci		.reg	= MSCC_PHY_CU_MEDIA_CRC_VALID_CNT,
428c2ecf20Sopenharmony_ci		.page	= MSCC_PHY_PAGE_EXTENDED,
438c2ecf20Sopenharmony_ci		.mask	= VALID_CRC_CNT_CRC_MASK,
448c2ecf20Sopenharmony_ci	}, {
458c2ecf20Sopenharmony_ci		.string	= "phy_cu_media_crc_error_count",
468c2ecf20Sopenharmony_ci		.reg	= MSCC_PHY_EXT_PHY_CNTL_4,
478c2ecf20Sopenharmony_ci		.page	= MSCC_PHY_PAGE_EXTENDED,
488c2ecf20Sopenharmony_ci		.mask	= ERR_CNT_MASK,
498c2ecf20Sopenharmony_ci	},
508c2ecf20Sopenharmony_ci};
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_cistatic const struct vsc85xx_hw_stat vsc8584_hw_stats[] = {
538c2ecf20Sopenharmony_ci	{
548c2ecf20Sopenharmony_ci		.string	= "phy_receive_errors",
558c2ecf20Sopenharmony_ci		.reg	= MSCC_PHY_ERR_RX_CNT,
568c2ecf20Sopenharmony_ci		.page	= MSCC_PHY_PAGE_STANDARD,
578c2ecf20Sopenharmony_ci		.mask	= ERR_CNT_MASK,
588c2ecf20Sopenharmony_ci	}, {
598c2ecf20Sopenharmony_ci		.string	= "phy_false_carrier",
608c2ecf20Sopenharmony_ci		.reg	= MSCC_PHY_ERR_FALSE_CARRIER_CNT,
618c2ecf20Sopenharmony_ci		.page	= MSCC_PHY_PAGE_STANDARD,
628c2ecf20Sopenharmony_ci		.mask	= ERR_CNT_MASK,
638c2ecf20Sopenharmony_ci	}, {
648c2ecf20Sopenharmony_ci		.string	= "phy_cu_media_link_disconnect",
658c2ecf20Sopenharmony_ci		.reg	= MSCC_PHY_ERR_LINK_DISCONNECT_CNT,
668c2ecf20Sopenharmony_ci		.page	= MSCC_PHY_PAGE_STANDARD,
678c2ecf20Sopenharmony_ci		.mask	= ERR_CNT_MASK,
688c2ecf20Sopenharmony_ci	}, {
698c2ecf20Sopenharmony_ci		.string	= "phy_cu_media_crc_good_count",
708c2ecf20Sopenharmony_ci		.reg	= MSCC_PHY_CU_MEDIA_CRC_VALID_CNT,
718c2ecf20Sopenharmony_ci		.page	= MSCC_PHY_PAGE_EXTENDED,
728c2ecf20Sopenharmony_ci		.mask	= VALID_CRC_CNT_CRC_MASK,
738c2ecf20Sopenharmony_ci	}, {
748c2ecf20Sopenharmony_ci		.string	= "phy_cu_media_crc_error_count",
758c2ecf20Sopenharmony_ci		.reg	= MSCC_PHY_EXT_PHY_CNTL_4,
768c2ecf20Sopenharmony_ci		.page	= MSCC_PHY_PAGE_EXTENDED,
778c2ecf20Sopenharmony_ci		.mask	= ERR_CNT_MASK,
788c2ecf20Sopenharmony_ci	}, {
798c2ecf20Sopenharmony_ci		.string	= "phy_serdes_tx_good_pkt_count",
808c2ecf20Sopenharmony_ci		.reg	= MSCC_PHY_SERDES_TX_VALID_CNT,
818c2ecf20Sopenharmony_ci		.page	= MSCC_PHY_PAGE_EXTENDED_3,
828c2ecf20Sopenharmony_ci		.mask	= VALID_CRC_CNT_CRC_MASK,
838c2ecf20Sopenharmony_ci	}, {
848c2ecf20Sopenharmony_ci		.string	= "phy_serdes_tx_bad_crc_count",
858c2ecf20Sopenharmony_ci		.reg	= MSCC_PHY_SERDES_TX_CRC_ERR_CNT,
868c2ecf20Sopenharmony_ci		.page	= MSCC_PHY_PAGE_EXTENDED_3,
878c2ecf20Sopenharmony_ci		.mask	= ERR_CNT_MASK,
888c2ecf20Sopenharmony_ci	}, {
898c2ecf20Sopenharmony_ci		.string	= "phy_serdes_rx_good_pkt_count",
908c2ecf20Sopenharmony_ci		.reg	= MSCC_PHY_SERDES_RX_VALID_CNT,
918c2ecf20Sopenharmony_ci		.page	= MSCC_PHY_PAGE_EXTENDED_3,
928c2ecf20Sopenharmony_ci		.mask	= VALID_CRC_CNT_CRC_MASK,
938c2ecf20Sopenharmony_ci	}, {
948c2ecf20Sopenharmony_ci		.string	= "phy_serdes_rx_bad_crc_count",
958c2ecf20Sopenharmony_ci		.reg	= MSCC_PHY_SERDES_RX_CRC_ERR_CNT,
968c2ecf20Sopenharmony_ci		.page	= MSCC_PHY_PAGE_EXTENDED_3,
978c2ecf20Sopenharmony_ci		.mask	= ERR_CNT_MASK,
988c2ecf20Sopenharmony_ci	},
998c2ecf20Sopenharmony_ci};
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_OF_MDIO)
1028c2ecf20Sopenharmony_cistatic const struct vsc8531_edge_rate_table edge_table[] = {
1038c2ecf20Sopenharmony_ci	{MSCC_VDDMAC_3300, { 0, 2,  4,  7, 10, 17, 29, 53} },
1048c2ecf20Sopenharmony_ci	{MSCC_VDDMAC_2500, { 0, 3,  6, 10, 14, 23, 37, 63} },
1058c2ecf20Sopenharmony_ci	{MSCC_VDDMAC_1800, { 0, 5,  9, 16, 23, 35, 52, 76} },
1068c2ecf20Sopenharmony_ci	{MSCC_VDDMAC_1500, { 0, 6, 14, 21, 29, 42, 58, 77} },
1078c2ecf20Sopenharmony_ci};
1088c2ecf20Sopenharmony_ci#endif
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_cistatic int vsc85xx_phy_read_page(struct phy_device *phydev)
1118c2ecf20Sopenharmony_ci{
1128c2ecf20Sopenharmony_ci	return __phy_read(phydev, MSCC_EXT_PAGE_ACCESS);
1138c2ecf20Sopenharmony_ci}
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_cistatic int vsc85xx_phy_write_page(struct phy_device *phydev, int page)
1168c2ecf20Sopenharmony_ci{
1178c2ecf20Sopenharmony_ci	return __phy_write(phydev, MSCC_EXT_PAGE_ACCESS, page);
1188c2ecf20Sopenharmony_ci}
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_cistatic int vsc85xx_get_sset_count(struct phy_device *phydev)
1218c2ecf20Sopenharmony_ci{
1228c2ecf20Sopenharmony_ci	struct vsc8531_private *priv = phydev->priv;
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci	if (!priv)
1258c2ecf20Sopenharmony_ci		return 0;
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci	return priv->nstats;
1288c2ecf20Sopenharmony_ci}
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_cistatic void vsc85xx_get_strings(struct phy_device *phydev, u8 *data)
1318c2ecf20Sopenharmony_ci{
1328c2ecf20Sopenharmony_ci	struct vsc8531_private *priv = phydev->priv;
1338c2ecf20Sopenharmony_ci	int i;
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	if (!priv)
1368c2ecf20Sopenharmony_ci		return;
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	for (i = 0; i < priv->nstats; i++)
1398c2ecf20Sopenharmony_ci		strlcpy(data + i * ETH_GSTRING_LEN, priv->hw_stats[i].string,
1408c2ecf20Sopenharmony_ci			ETH_GSTRING_LEN);
1418c2ecf20Sopenharmony_ci}
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_cistatic u64 vsc85xx_get_stat(struct phy_device *phydev, int i)
1448c2ecf20Sopenharmony_ci{
1458c2ecf20Sopenharmony_ci	struct vsc8531_private *priv = phydev->priv;
1468c2ecf20Sopenharmony_ci	int val;
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci	val = phy_read_paged(phydev, priv->hw_stats[i].page,
1498c2ecf20Sopenharmony_ci			     priv->hw_stats[i].reg);
1508c2ecf20Sopenharmony_ci	if (val < 0)
1518c2ecf20Sopenharmony_ci		return U64_MAX;
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci	val = val & priv->hw_stats[i].mask;
1548c2ecf20Sopenharmony_ci	priv->stats[i] += val;
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci	return priv->stats[i];
1578c2ecf20Sopenharmony_ci}
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_cistatic void vsc85xx_get_stats(struct phy_device *phydev,
1608c2ecf20Sopenharmony_ci			      struct ethtool_stats *stats, u64 *data)
1618c2ecf20Sopenharmony_ci{
1628c2ecf20Sopenharmony_ci	struct vsc8531_private *priv = phydev->priv;
1638c2ecf20Sopenharmony_ci	int i;
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci	if (!priv)
1668c2ecf20Sopenharmony_ci		return;
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci	for (i = 0; i < priv->nstats; i++)
1698c2ecf20Sopenharmony_ci		data[i] = vsc85xx_get_stat(phydev, i);
1708c2ecf20Sopenharmony_ci}
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_cistatic int vsc85xx_led_cntl_set(struct phy_device *phydev,
1738c2ecf20Sopenharmony_ci				u8 led_num,
1748c2ecf20Sopenharmony_ci				u8 mode)
1758c2ecf20Sopenharmony_ci{
1768c2ecf20Sopenharmony_ci	int rc;
1778c2ecf20Sopenharmony_ci	u16 reg_val;
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	mutex_lock(&phydev->lock);
1808c2ecf20Sopenharmony_ci	reg_val = phy_read(phydev, MSCC_PHY_LED_MODE_SEL);
1818c2ecf20Sopenharmony_ci	reg_val &= ~LED_MODE_SEL_MASK(led_num);
1828c2ecf20Sopenharmony_ci	reg_val |= LED_MODE_SEL(led_num, (u16)mode);
1838c2ecf20Sopenharmony_ci	rc = phy_write(phydev, MSCC_PHY_LED_MODE_SEL, reg_val);
1848c2ecf20Sopenharmony_ci	mutex_unlock(&phydev->lock);
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci	return rc;
1878c2ecf20Sopenharmony_ci}
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_cistatic int vsc85xx_mdix_get(struct phy_device *phydev, u8 *mdix)
1908c2ecf20Sopenharmony_ci{
1918c2ecf20Sopenharmony_ci	u16 reg_val;
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	reg_val = phy_read(phydev, MSCC_PHY_DEV_AUX_CNTL);
1948c2ecf20Sopenharmony_ci	if (reg_val & HP_AUTO_MDIX_X_OVER_IND_MASK)
1958c2ecf20Sopenharmony_ci		*mdix = ETH_TP_MDI_X;
1968c2ecf20Sopenharmony_ci	else
1978c2ecf20Sopenharmony_ci		*mdix = ETH_TP_MDI;
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci	return 0;
2008c2ecf20Sopenharmony_ci}
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_cistatic int vsc85xx_mdix_set(struct phy_device *phydev, u8 mdix)
2038c2ecf20Sopenharmony_ci{
2048c2ecf20Sopenharmony_ci	int rc;
2058c2ecf20Sopenharmony_ci	u16 reg_val;
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci	reg_val = phy_read(phydev, MSCC_PHY_BYPASS_CONTROL);
2088c2ecf20Sopenharmony_ci	if (mdix == ETH_TP_MDI || mdix == ETH_TP_MDI_X) {
2098c2ecf20Sopenharmony_ci		reg_val |= (DISABLE_PAIR_SWAP_CORR_MASK |
2108c2ecf20Sopenharmony_ci			    DISABLE_POLARITY_CORR_MASK  |
2118c2ecf20Sopenharmony_ci			    DISABLE_HP_AUTO_MDIX_MASK);
2128c2ecf20Sopenharmony_ci	} else {
2138c2ecf20Sopenharmony_ci		reg_val &= ~(DISABLE_PAIR_SWAP_CORR_MASK |
2148c2ecf20Sopenharmony_ci			     DISABLE_POLARITY_CORR_MASK  |
2158c2ecf20Sopenharmony_ci			     DISABLE_HP_AUTO_MDIX_MASK);
2168c2ecf20Sopenharmony_ci	}
2178c2ecf20Sopenharmony_ci	rc = phy_write(phydev, MSCC_PHY_BYPASS_CONTROL, reg_val);
2188c2ecf20Sopenharmony_ci	if (rc)
2198c2ecf20Sopenharmony_ci		return rc;
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci	reg_val = 0;
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci	if (mdix == ETH_TP_MDI)
2248c2ecf20Sopenharmony_ci		reg_val = FORCE_MDI_CROSSOVER_MDI;
2258c2ecf20Sopenharmony_ci	else if (mdix == ETH_TP_MDI_X)
2268c2ecf20Sopenharmony_ci		reg_val = FORCE_MDI_CROSSOVER_MDIX;
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci	rc = phy_modify_paged(phydev, MSCC_PHY_PAGE_EXTENDED,
2298c2ecf20Sopenharmony_ci			      MSCC_PHY_EXT_MODE_CNTL, FORCE_MDI_CROSSOVER_MASK,
2308c2ecf20Sopenharmony_ci			      reg_val);
2318c2ecf20Sopenharmony_ci	if (rc < 0)
2328c2ecf20Sopenharmony_ci		return rc;
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci	return genphy_restart_aneg(phydev);
2358c2ecf20Sopenharmony_ci}
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_cistatic int vsc85xx_downshift_get(struct phy_device *phydev, u8 *count)
2388c2ecf20Sopenharmony_ci{
2398c2ecf20Sopenharmony_ci	int reg_val;
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci	reg_val = phy_read_paged(phydev, MSCC_PHY_PAGE_EXTENDED,
2428c2ecf20Sopenharmony_ci				 MSCC_PHY_ACTIPHY_CNTL);
2438c2ecf20Sopenharmony_ci	if (reg_val < 0)
2448c2ecf20Sopenharmony_ci		return reg_val;
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci	reg_val &= DOWNSHIFT_CNTL_MASK;
2478c2ecf20Sopenharmony_ci	if (!(reg_val & DOWNSHIFT_EN))
2488c2ecf20Sopenharmony_ci		*count = DOWNSHIFT_DEV_DISABLE;
2498c2ecf20Sopenharmony_ci	else
2508c2ecf20Sopenharmony_ci		*count = ((reg_val & ~DOWNSHIFT_EN) >> DOWNSHIFT_CNTL_POS) + 2;
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci	return 0;
2538c2ecf20Sopenharmony_ci}
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_cistatic int vsc85xx_downshift_set(struct phy_device *phydev, u8 count)
2568c2ecf20Sopenharmony_ci{
2578c2ecf20Sopenharmony_ci	if (count == DOWNSHIFT_DEV_DEFAULT_COUNT) {
2588c2ecf20Sopenharmony_ci		/* Default downshift count 3 (i.e. Bit3:2 = 0b01) */
2598c2ecf20Sopenharmony_ci		count = ((1 << DOWNSHIFT_CNTL_POS) | DOWNSHIFT_EN);
2608c2ecf20Sopenharmony_ci	} else if (count > DOWNSHIFT_COUNT_MAX || count == 1) {
2618c2ecf20Sopenharmony_ci		phydev_err(phydev, "Downshift count should be 2,3,4 or 5\n");
2628c2ecf20Sopenharmony_ci		return -ERANGE;
2638c2ecf20Sopenharmony_ci	} else if (count) {
2648c2ecf20Sopenharmony_ci		/* Downshift count is either 2,3,4 or 5 */
2658c2ecf20Sopenharmony_ci		count = (((count - 2) << DOWNSHIFT_CNTL_POS) | DOWNSHIFT_EN);
2668c2ecf20Sopenharmony_ci	}
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci	return phy_modify_paged(phydev, MSCC_PHY_PAGE_EXTENDED,
2698c2ecf20Sopenharmony_ci				MSCC_PHY_ACTIPHY_CNTL, DOWNSHIFT_CNTL_MASK,
2708c2ecf20Sopenharmony_ci				count);
2718c2ecf20Sopenharmony_ci}
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_cistatic int vsc85xx_wol_set(struct phy_device *phydev,
2748c2ecf20Sopenharmony_ci			   struct ethtool_wolinfo *wol)
2758c2ecf20Sopenharmony_ci{
2768c2ecf20Sopenharmony_ci	int rc;
2778c2ecf20Sopenharmony_ci	u16 reg_val;
2788c2ecf20Sopenharmony_ci	u8  i;
2798c2ecf20Sopenharmony_ci	u16 pwd[3] = {0, 0, 0};
2808c2ecf20Sopenharmony_ci	struct ethtool_wolinfo *wol_conf = wol;
2818c2ecf20Sopenharmony_ci	u8 *mac_addr = phydev->attached_dev->dev_addr;
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci	mutex_lock(&phydev->lock);
2848c2ecf20Sopenharmony_ci	rc = phy_select_page(phydev, MSCC_PHY_PAGE_EXTENDED_2);
2858c2ecf20Sopenharmony_ci	if (rc < 0) {
2868c2ecf20Sopenharmony_ci		rc = phy_restore_page(phydev, rc, rc);
2878c2ecf20Sopenharmony_ci		goto out_unlock;
2888c2ecf20Sopenharmony_ci	}
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci	if (wol->wolopts & WAKE_MAGIC) {
2918c2ecf20Sopenharmony_ci		/* Store the device address for the magic packet */
2928c2ecf20Sopenharmony_ci		for (i = 0; i < ARRAY_SIZE(pwd); i++)
2938c2ecf20Sopenharmony_ci			pwd[i] = mac_addr[5 - (i * 2 + 1)] << 8 |
2948c2ecf20Sopenharmony_ci				 mac_addr[5 - i * 2];
2958c2ecf20Sopenharmony_ci		__phy_write(phydev, MSCC_PHY_WOL_LOWER_MAC_ADDR, pwd[0]);
2968c2ecf20Sopenharmony_ci		__phy_write(phydev, MSCC_PHY_WOL_MID_MAC_ADDR, pwd[1]);
2978c2ecf20Sopenharmony_ci		__phy_write(phydev, MSCC_PHY_WOL_UPPER_MAC_ADDR, pwd[2]);
2988c2ecf20Sopenharmony_ci	} else {
2998c2ecf20Sopenharmony_ci		__phy_write(phydev, MSCC_PHY_WOL_LOWER_MAC_ADDR, 0);
3008c2ecf20Sopenharmony_ci		__phy_write(phydev, MSCC_PHY_WOL_MID_MAC_ADDR, 0);
3018c2ecf20Sopenharmony_ci		__phy_write(phydev, MSCC_PHY_WOL_UPPER_MAC_ADDR, 0);
3028c2ecf20Sopenharmony_ci	}
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci	if (wol_conf->wolopts & WAKE_MAGICSECURE) {
3058c2ecf20Sopenharmony_ci		for (i = 0; i < ARRAY_SIZE(pwd); i++)
3068c2ecf20Sopenharmony_ci			pwd[i] = wol_conf->sopass[5 - (i * 2 + 1)] << 8 |
3078c2ecf20Sopenharmony_ci				 wol_conf->sopass[5 - i * 2];
3088c2ecf20Sopenharmony_ci		__phy_write(phydev, MSCC_PHY_WOL_LOWER_PASSWD, pwd[0]);
3098c2ecf20Sopenharmony_ci		__phy_write(phydev, MSCC_PHY_WOL_MID_PASSWD, pwd[1]);
3108c2ecf20Sopenharmony_ci		__phy_write(phydev, MSCC_PHY_WOL_UPPER_PASSWD, pwd[2]);
3118c2ecf20Sopenharmony_ci	} else {
3128c2ecf20Sopenharmony_ci		__phy_write(phydev, MSCC_PHY_WOL_LOWER_PASSWD, 0);
3138c2ecf20Sopenharmony_ci		__phy_write(phydev, MSCC_PHY_WOL_MID_PASSWD, 0);
3148c2ecf20Sopenharmony_ci		__phy_write(phydev, MSCC_PHY_WOL_UPPER_PASSWD, 0);
3158c2ecf20Sopenharmony_ci	}
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci	reg_val = __phy_read(phydev, MSCC_PHY_WOL_MAC_CONTROL);
3188c2ecf20Sopenharmony_ci	if (wol_conf->wolopts & WAKE_MAGICSECURE)
3198c2ecf20Sopenharmony_ci		reg_val |= SECURE_ON_ENABLE;
3208c2ecf20Sopenharmony_ci	else
3218c2ecf20Sopenharmony_ci		reg_val &= ~SECURE_ON_ENABLE;
3228c2ecf20Sopenharmony_ci	__phy_write(phydev, MSCC_PHY_WOL_MAC_CONTROL, reg_val);
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci	rc = phy_restore_page(phydev, rc, rc > 0 ? 0 : rc);
3258c2ecf20Sopenharmony_ci	if (rc < 0)
3268c2ecf20Sopenharmony_ci		goto out_unlock;
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	if (wol->wolopts & WAKE_MAGIC) {
3298c2ecf20Sopenharmony_ci		/* Enable the WOL interrupt */
3308c2ecf20Sopenharmony_ci		reg_val = phy_read(phydev, MII_VSC85XX_INT_MASK);
3318c2ecf20Sopenharmony_ci		reg_val |= MII_VSC85XX_INT_MASK_WOL;
3328c2ecf20Sopenharmony_ci		rc = phy_write(phydev, MII_VSC85XX_INT_MASK, reg_val);
3338c2ecf20Sopenharmony_ci		if (rc)
3348c2ecf20Sopenharmony_ci			goto out_unlock;
3358c2ecf20Sopenharmony_ci	} else {
3368c2ecf20Sopenharmony_ci		/* Disable the WOL interrupt */
3378c2ecf20Sopenharmony_ci		reg_val = phy_read(phydev, MII_VSC85XX_INT_MASK);
3388c2ecf20Sopenharmony_ci		reg_val &= (~MII_VSC85XX_INT_MASK_WOL);
3398c2ecf20Sopenharmony_ci		rc = phy_write(phydev, MII_VSC85XX_INT_MASK, reg_val);
3408c2ecf20Sopenharmony_ci		if (rc)
3418c2ecf20Sopenharmony_ci			goto out_unlock;
3428c2ecf20Sopenharmony_ci	}
3438c2ecf20Sopenharmony_ci	/* Clear WOL iterrupt status */
3448c2ecf20Sopenharmony_ci	reg_val = phy_read(phydev, MII_VSC85XX_INT_STATUS);
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ciout_unlock:
3478c2ecf20Sopenharmony_ci	mutex_unlock(&phydev->lock);
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci	return rc;
3508c2ecf20Sopenharmony_ci}
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_cistatic void vsc85xx_wol_get(struct phy_device *phydev,
3538c2ecf20Sopenharmony_ci			    struct ethtool_wolinfo *wol)
3548c2ecf20Sopenharmony_ci{
3558c2ecf20Sopenharmony_ci	int rc;
3568c2ecf20Sopenharmony_ci	u16 reg_val;
3578c2ecf20Sopenharmony_ci	u8  i;
3588c2ecf20Sopenharmony_ci	u16 pwd[3] = {0, 0, 0};
3598c2ecf20Sopenharmony_ci	struct ethtool_wolinfo *wol_conf = wol;
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_ci	mutex_lock(&phydev->lock);
3628c2ecf20Sopenharmony_ci	rc = phy_select_page(phydev, MSCC_PHY_PAGE_EXTENDED_2);
3638c2ecf20Sopenharmony_ci	if (rc < 0)
3648c2ecf20Sopenharmony_ci		goto out_unlock;
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ci	reg_val = __phy_read(phydev, MSCC_PHY_WOL_MAC_CONTROL);
3678c2ecf20Sopenharmony_ci	if (reg_val & SECURE_ON_ENABLE)
3688c2ecf20Sopenharmony_ci		wol_conf->wolopts |= WAKE_MAGICSECURE;
3698c2ecf20Sopenharmony_ci	if (wol_conf->wolopts & WAKE_MAGICSECURE) {
3708c2ecf20Sopenharmony_ci		pwd[0] = __phy_read(phydev, MSCC_PHY_WOL_LOWER_PASSWD);
3718c2ecf20Sopenharmony_ci		pwd[1] = __phy_read(phydev, MSCC_PHY_WOL_MID_PASSWD);
3728c2ecf20Sopenharmony_ci		pwd[2] = __phy_read(phydev, MSCC_PHY_WOL_UPPER_PASSWD);
3738c2ecf20Sopenharmony_ci		for (i = 0; i < ARRAY_SIZE(pwd); i++) {
3748c2ecf20Sopenharmony_ci			wol_conf->sopass[5 - i * 2] = pwd[i] & 0x00ff;
3758c2ecf20Sopenharmony_ci			wol_conf->sopass[5 - (i * 2 + 1)] = (pwd[i] & 0xff00)
3768c2ecf20Sopenharmony_ci							    >> 8;
3778c2ecf20Sopenharmony_ci		}
3788c2ecf20Sopenharmony_ci	}
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ciout_unlock:
3818c2ecf20Sopenharmony_ci	phy_restore_page(phydev, rc, rc > 0 ? 0 : rc);
3828c2ecf20Sopenharmony_ci	mutex_unlock(&phydev->lock);
3838c2ecf20Sopenharmony_ci}
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_OF_MDIO)
3868c2ecf20Sopenharmony_cistatic int vsc85xx_edge_rate_magic_get(struct phy_device *phydev)
3878c2ecf20Sopenharmony_ci{
3888c2ecf20Sopenharmony_ci	u32 vdd, sd;
3898c2ecf20Sopenharmony_ci	int i, j;
3908c2ecf20Sopenharmony_ci	struct device *dev = &phydev->mdio.dev;
3918c2ecf20Sopenharmony_ci	struct device_node *of_node = dev->of_node;
3928c2ecf20Sopenharmony_ci	u8 sd_array_size = ARRAY_SIZE(edge_table[0].slowdown);
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ci	if (!of_node)
3958c2ecf20Sopenharmony_ci		return -ENODEV;
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_ci	if (of_property_read_u32(of_node, "vsc8531,vddmac", &vdd))
3988c2ecf20Sopenharmony_ci		vdd = MSCC_VDDMAC_3300;
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_ci	if (of_property_read_u32(of_node, "vsc8531,edge-slowdown", &sd))
4018c2ecf20Sopenharmony_ci		sd = 0;
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(edge_table); i++)
4048c2ecf20Sopenharmony_ci		if (edge_table[i].vddmac == vdd)
4058c2ecf20Sopenharmony_ci			for (j = 0; j < sd_array_size; j++)
4068c2ecf20Sopenharmony_ci				if (edge_table[i].slowdown[j] == sd)
4078c2ecf20Sopenharmony_ci					return (sd_array_size - j - 1);
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci	return -EINVAL;
4108c2ecf20Sopenharmony_ci}
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_cistatic int vsc85xx_dt_led_mode_get(struct phy_device *phydev,
4138c2ecf20Sopenharmony_ci				   char *led,
4148c2ecf20Sopenharmony_ci				   u32 default_mode)
4158c2ecf20Sopenharmony_ci{
4168c2ecf20Sopenharmony_ci	struct vsc8531_private *priv = phydev->priv;
4178c2ecf20Sopenharmony_ci	struct device *dev = &phydev->mdio.dev;
4188c2ecf20Sopenharmony_ci	struct device_node *of_node = dev->of_node;
4198c2ecf20Sopenharmony_ci	u32 led_mode;
4208c2ecf20Sopenharmony_ci	int err;
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ci	if (!of_node)
4238c2ecf20Sopenharmony_ci		return -ENODEV;
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_ci	led_mode = default_mode;
4268c2ecf20Sopenharmony_ci	err = of_property_read_u32(of_node, led, &led_mode);
4278c2ecf20Sopenharmony_ci	if (!err && !(BIT(led_mode) & priv->supp_led_modes)) {
4288c2ecf20Sopenharmony_ci		phydev_err(phydev, "DT %s invalid\n", led);
4298c2ecf20Sopenharmony_ci		return -EINVAL;
4308c2ecf20Sopenharmony_ci	}
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_ci	return led_mode;
4338c2ecf20Sopenharmony_ci}
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_ci#else
4368c2ecf20Sopenharmony_cistatic int vsc85xx_edge_rate_magic_get(struct phy_device *phydev)
4378c2ecf20Sopenharmony_ci{
4388c2ecf20Sopenharmony_ci	return 0;
4398c2ecf20Sopenharmony_ci}
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_cistatic int vsc85xx_dt_led_mode_get(struct phy_device *phydev,
4428c2ecf20Sopenharmony_ci				   char *led,
4438c2ecf20Sopenharmony_ci				   u8 default_mode)
4448c2ecf20Sopenharmony_ci{
4458c2ecf20Sopenharmony_ci	return default_mode;
4468c2ecf20Sopenharmony_ci}
4478c2ecf20Sopenharmony_ci#endif /* CONFIG_OF_MDIO */
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_cistatic int vsc85xx_dt_led_modes_get(struct phy_device *phydev,
4508c2ecf20Sopenharmony_ci				    u32 *default_mode)
4518c2ecf20Sopenharmony_ci{
4528c2ecf20Sopenharmony_ci	struct vsc8531_private *priv = phydev->priv;
4538c2ecf20Sopenharmony_ci	char led_dt_prop[28];
4548c2ecf20Sopenharmony_ci	int i, ret;
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_ci	for (i = 0; i < priv->nleds; i++) {
4578c2ecf20Sopenharmony_ci		ret = sprintf(led_dt_prop, "vsc8531,led-%d-mode", i);
4588c2ecf20Sopenharmony_ci		if (ret < 0)
4598c2ecf20Sopenharmony_ci			return ret;
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_ci		ret = vsc85xx_dt_led_mode_get(phydev, led_dt_prop,
4628c2ecf20Sopenharmony_ci					      default_mode[i]);
4638c2ecf20Sopenharmony_ci		if (ret < 0)
4648c2ecf20Sopenharmony_ci			return ret;
4658c2ecf20Sopenharmony_ci		priv->leds_mode[i] = ret;
4668c2ecf20Sopenharmony_ci	}
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_ci	return 0;
4698c2ecf20Sopenharmony_ci}
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_cistatic int vsc85xx_edge_rate_cntl_set(struct phy_device *phydev, u8 edge_rate)
4728c2ecf20Sopenharmony_ci{
4738c2ecf20Sopenharmony_ci	int rc;
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_ci	mutex_lock(&phydev->lock);
4768c2ecf20Sopenharmony_ci	rc = phy_modify_paged(phydev, MSCC_PHY_PAGE_EXTENDED_2,
4778c2ecf20Sopenharmony_ci			      MSCC_PHY_WOL_MAC_CONTROL, EDGE_RATE_CNTL_MASK,
4788c2ecf20Sopenharmony_ci			      edge_rate << EDGE_RATE_CNTL_POS);
4798c2ecf20Sopenharmony_ci	mutex_unlock(&phydev->lock);
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_ci	return rc;
4828c2ecf20Sopenharmony_ci}
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_cistatic int vsc85xx_mac_if_set(struct phy_device *phydev,
4858c2ecf20Sopenharmony_ci			      phy_interface_t interface)
4868c2ecf20Sopenharmony_ci{
4878c2ecf20Sopenharmony_ci	int rc;
4888c2ecf20Sopenharmony_ci	u16 reg_val;
4898c2ecf20Sopenharmony_ci
4908c2ecf20Sopenharmony_ci	mutex_lock(&phydev->lock);
4918c2ecf20Sopenharmony_ci	reg_val = phy_read(phydev, MSCC_PHY_EXT_PHY_CNTL_1);
4928c2ecf20Sopenharmony_ci	reg_val &= ~(MAC_IF_SELECTION_MASK);
4938c2ecf20Sopenharmony_ci	switch (interface) {
4948c2ecf20Sopenharmony_ci	case PHY_INTERFACE_MODE_RGMII_TXID:
4958c2ecf20Sopenharmony_ci	case PHY_INTERFACE_MODE_RGMII_RXID:
4968c2ecf20Sopenharmony_ci	case PHY_INTERFACE_MODE_RGMII_ID:
4978c2ecf20Sopenharmony_ci	case PHY_INTERFACE_MODE_RGMII:
4988c2ecf20Sopenharmony_ci		reg_val |= (MAC_IF_SELECTION_RGMII << MAC_IF_SELECTION_POS);
4998c2ecf20Sopenharmony_ci		break;
5008c2ecf20Sopenharmony_ci	case PHY_INTERFACE_MODE_RMII:
5018c2ecf20Sopenharmony_ci		reg_val |= (MAC_IF_SELECTION_RMII << MAC_IF_SELECTION_POS);
5028c2ecf20Sopenharmony_ci		break;
5038c2ecf20Sopenharmony_ci	case PHY_INTERFACE_MODE_MII:
5048c2ecf20Sopenharmony_ci	case PHY_INTERFACE_MODE_GMII:
5058c2ecf20Sopenharmony_ci		reg_val |= (MAC_IF_SELECTION_GMII << MAC_IF_SELECTION_POS);
5068c2ecf20Sopenharmony_ci		break;
5078c2ecf20Sopenharmony_ci	default:
5088c2ecf20Sopenharmony_ci		rc = -EINVAL;
5098c2ecf20Sopenharmony_ci		goto out_unlock;
5108c2ecf20Sopenharmony_ci	}
5118c2ecf20Sopenharmony_ci	rc = phy_write(phydev, MSCC_PHY_EXT_PHY_CNTL_1, reg_val);
5128c2ecf20Sopenharmony_ci	if (rc)
5138c2ecf20Sopenharmony_ci		goto out_unlock;
5148c2ecf20Sopenharmony_ci
5158c2ecf20Sopenharmony_ci	rc = genphy_soft_reset(phydev);
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_ciout_unlock:
5188c2ecf20Sopenharmony_ci	mutex_unlock(&phydev->lock);
5198c2ecf20Sopenharmony_ci
5208c2ecf20Sopenharmony_ci	return rc;
5218c2ecf20Sopenharmony_ci}
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_ci/* Set the RGMII RX and TX clock skews individually, according to the PHY
5248c2ecf20Sopenharmony_ci * interface type, to:
5258c2ecf20Sopenharmony_ci *  * 0.2 ns (their default, and lowest, hardware value) if delays should
5268c2ecf20Sopenharmony_ci *    not be enabled
5278c2ecf20Sopenharmony_ci *  * 2.0 ns (which causes the data to be sampled at exactly half way between
5288c2ecf20Sopenharmony_ci *    clock transitions at 1000 Mbps) if delays should be enabled
5298c2ecf20Sopenharmony_ci */
5308c2ecf20Sopenharmony_cistatic int vsc85xx_update_rgmii_cntl(struct phy_device *phydev, u32 rgmii_cntl,
5318c2ecf20Sopenharmony_ci				     u16 rgmii_rx_delay_mask,
5328c2ecf20Sopenharmony_ci				     u16 rgmii_tx_delay_mask)
5338c2ecf20Sopenharmony_ci{
5348c2ecf20Sopenharmony_ci	u16 rgmii_rx_delay_pos = ffs(rgmii_rx_delay_mask) - 1;
5358c2ecf20Sopenharmony_ci	u16 rgmii_tx_delay_pos = ffs(rgmii_tx_delay_mask) - 1;
5368c2ecf20Sopenharmony_ci	u16 reg_val = 0;
5378c2ecf20Sopenharmony_ci	u16 mask = 0;
5388c2ecf20Sopenharmony_ci	int rc = 0;
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_ci	/* For traffic to pass, the VSC8502 family needs the RX_CLK disable bit
5418c2ecf20Sopenharmony_ci	 * to be unset for all PHY modes, so do that as part of the paged
5428c2ecf20Sopenharmony_ci	 * register modification.
5438c2ecf20Sopenharmony_ci	 * For some family members (like VSC8530/31/40/41) this bit is reserved
5448c2ecf20Sopenharmony_ci	 * and read-only, and the RX clock is enabled by default.
5458c2ecf20Sopenharmony_ci	 */
5468c2ecf20Sopenharmony_ci	if (rgmii_cntl == VSC8502_RGMII_CNTL)
5478c2ecf20Sopenharmony_ci		mask |= VSC8502_RGMII_RX_CLK_DISABLE;
5488c2ecf20Sopenharmony_ci
5498c2ecf20Sopenharmony_ci	if (phy_interface_is_rgmii(phydev))
5508c2ecf20Sopenharmony_ci		mask |= rgmii_rx_delay_mask | rgmii_tx_delay_mask;
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_ci	mutex_lock(&phydev->lock);
5538c2ecf20Sopenharmony_ci
5548c2ecf20Sopenharmony_ci	if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID ||
5558c2ecf20Sopenharmony_ci	    phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)
5568c2ecf20Sopenharmony_ci		reg_val |= RGMII_CLK_DELAY_2_0_NS << rgmii_rx_delay_pos;
5578c2ecf20Sopenharmony_ci	if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID ||
5588c2ecf20Sopenharmony_ci	    phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)
5598c2ecf20Sopenharmony_ci		reg_val |= RGMII_CLK_DELAY_2_0_NS << rgmii_tx_delay_pos;
5608c2ecf20Sopenharmony_ci
5618c2ecf20Sopenharmony_ci	if (mask)
5628c2ecf20Sopenharmony_ci		rc = phy_modify_paged(phydev, MSCC_PHY_PAGE_EXTENDED_2,
5638c2ecf20Sopenharmony_ci				      rgmii_cntl, mask, reg_val);
5648c2ecf20Sopenharmony_ci
5658c2ecf20Sopenharmony_ci	mutex_unlock(&phydev->lock);
5668c2ecf20Sopenharmony_ci
5678c2ecf20Sopenharmony_ci	return rc;
5688c2ecf20Sopenharmony_ci}
5698c2ecf20Sopenharmony_ci
5708c2ecf20Sopenharmony_cistatic int vsc85xx_default_config(struct phy_device *phydev)
5718c2ecf20Sopenharmony_ci{
5728c2ecf20Sopenharmony_ci	phydev->mdix_ctrl = ETH_TP_MDI_AUTO;
5738c2ecf20Sopenharmony_ci
5748c2ecf20Sopenharmony_ci	return vsc85xx_update_rgmii_cntl(phydev, VSC8502_RGMII_CNTL,
5758c2ecf20Sopenharmony_ci					 VSC8502_RGMII_RX_DELAY_MASK,
5768c2ecf20Sopenharmony_ci					 VSC8502_RGMII_TX_DELAY_MASK);
5778c2ecf20Sopenharmony_ci}
5788c2ecf20Sopenharmony_ci
5798c2ecf20Sopenharmony_cistatic int vsc85xx_get_tunable(struct phy_device *phydev,
5808c2ecf20Sopenharmony_ci			       struct ethtool_tunable *tuna, void *data)
5818c2ecf20Sopenharmony_ci{
5828c2ecf20Sopenharmony_ci	switch (tuna->id) {
5838c2ecf20Sopenharmony_ci	case ETHTOOL_PHY_DOWNSHIFT:
5848c2ecf20Sopenharmony_ci		return vsc85xx_downshift_get(phydev, (u8 *)data);
5858c2ecf20Sopenharmony_ci	default:
5868c2ecf20Sopenharmony_ci		return -EINVAL;
5878c2ecf20Sopenharmony_ci	}
5888c2ecf20Sopenharmony_ci}
5898c2ecf20Sopenharmony_ci
5908c2ecf20Sopenharmony_cistatic int vsc85xx_set_tunable(struct phy_device *phydev,
5918c2ecf20Sopenharmony_ci			       struct ethtool_tunable *tuna,
5928c2ecf20Sopenharmony_ci			       const void *data)
5938c2ecf20Sopenharmony_ci{
5948c2ecf20Sopenharmony_ci	switch (tuna->id) {
5958c2ecf20Sopenharmony_ci	case ETHTOOL_PHY_DOWNSHIFT:
5968c2ecf20Sopenharmony_ci		return vsc85xx_downshift_set(phydev, *(u8 *)data);
5978c2ecf20Sopenharmony_ci	default:
5988c2ecf20Sopenharmony_ci		return -EINVAL;
5998c2ecf20Sopenharmony_ci	}
6008c2ecf20Sopenharmony_ci}
6018c2ecf20Sopenharmony_ci
6028c2ecf20Sopenharmony_ci/* mdiobus lock should be locked when using this function */
6038c2ecf20Sopenharmony_cistatic void vsc85xx_tr_write(struct phy_device *phydev, u16 addr, u32 val)
6048c2ecf20Sopenharmony_ci{
6058c2ecf20Sopenharmony_ci	__phy_write(phydev, MSCC_PHY_TR_MSB, val >> 16);
6068c2ecf20Sopenharmony_ci	__phy_write(phydev, MSCC_PHY_TR_LSB, val & GENMASK(15, 0));
6078c2ecf20Sopenharmony_ci	__phy_write(phydev, MSCC_PHY_TR_CNTL, TR_WRITE | TR_ADDR(addr));
6088c2ecf20Sopenharmony_ci}
6098c2ecf20Sopenharmony_ci
6108c2ecf20Sopenharmony_cistatic int vsc8531_pre_init_seq_set(struct phy_device *phydev)
6118c2ecf20Sopenharmony_ci{
6128c2ecf20Sopenharmony_ci	int rc;
6138c2ecf20Sopenharmony_ci	static const struct reg_val init_seq[] = {
6148c2ecf20Sopenharmony_ci		{0x0f90, 0x00688980},
6158c2ecf20Sopenharmony_ci		{0x0696, 0x00000003},
6168c2ecf20Sopenharmony_ci		{0x07fa, 0x0050100f},
6178c2ecf20Sopenharmony_ci		{0x1686, 0x00000004},
6188c2ecf20Sopenharmony_ci	};
6198c2ecf20Sopenharmony_ci	unsigned int i;
6208c2ecf20Sopenharmony_ci	int oldpage;
6218c2ecf20Sopenharmony_ci
6228c2ecf20Sopenharmony_ci	rc = phy_modify_paged(phydev, MSCC_PHY_PAGE_STANDARD,
6238c2ecf20Sopenharmony_ci			      MSCC_PHY_EXT_CNTL_STATUS, SMI_BROADCAST_WR_EN,
6248c2ecf20Sopenharmony_ci			      SMI_BROADCAST_WR_EN);
6258c2ecf20Sopenharmony_ci	if (rc < 0)
6268c2ecf20Sopenharmony_ci		return rc;
6278c2ecf20Sopenharmony_ci	rc = phy_modify_paged(phydev, MSCC_PHY_PAGE_TEST,
6288c2ecf20Sopenharmony_ci			      MSCC_PHY_TEST_PAGE_24, 0, 0x0400);
6298c2ecf20Sopenharmony_ci	if (rc < 0)
6308c2ecf20Sopenharmony_ci		return rc;
6318c2ecf20Sopenharmony_ci	rc = phy_modify_paged(phydev, MSCC_PHY_PAGE_TEST,
6328c2ecf20Sopenharmony_ci			      MSCC_PHY_TEST_PAGE_5, 0x0a00, 0x0e00);
6338c2ecf20Sopenharmony_ci	if (rc < 0)
6348c2ecf20Sopenharmony_ci		return rc;
6358c2ecf20Sopenharmony_ci	rc = phy_modify_paged(phydev, MSCC_PHY_PAGE_TEST,
6368c2ecf20Sopenharmony_ci			      MSCC_PHY_TEST_PAGE_8, TR_CLK_DISABLE, TR_CLK_DISABLE);
6378c2ecf20Sopenharmony_ci	if (rc < 0)
6388c2ecf20Sopenharmony_ci		return rc;
6398c2ecf20Sopenharmony_ci
6408c2ecf20Sopenharmony_ci	mutex_lock(&phydev->lock);
6418c2ecf20Sopenharmony_ci	oldpage = phy_select_page(phydev, MSCC_PHY_PAGE_TR);
6428c2ecf20Sopenharmony_ci	if (oldpage < 0)
6438c2ecf20Sopenharmony_ci		goto out_unlock;
6448c2ecf20Sopenharmony_ci
6458c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(init_seq); i++)
6468c2ecf20Sopenharmony_ci		vsc85xx_tr_write(phydev, init_seq[i].reg, init_seq[i].val);
6478c2ecf20Sopenharmony_ci
6488c2ecf20Sopenharmony_ciout_unlock:
6498c2ecf20Sopenharmony_ci	oldpage = phy_restore_page(phydev, oldpage, oldpage);
6508c2ecf20Sopenharmony_ci	mutex_unlock(&phydev->lock);
6518c2ecf20Sopenharmony_ci
6528c2ecf20Sopenharmony_ci	return oldpage;
6538c2ecf20Sopenharmony_ci}
6548c2ecf20Sopenharmony_ci
6558c2ecf20Sopenharmony_cistatic int vsc85xx_eee_init_seq_set(struct phy_device *phydev)
6568c2ecf20Sopenharmony_ci{
6578c2ecf20Sopenharmony_ci	static const struct reg_val init_eee[] = {
6588c2ecf20Sopenharmony_ci		{0x0f82, 0x0012b00a},
6598c2ecf20Sopenharmony_ci		{0x1686, 0x00000004},
6608c2ecf20Sopenharmony_ci		{0x168c, 0x00d2c46f},
6618c2ecf20Sopenharmony_ci		{0x17a2, 0x00000620},
6628c2ecf20Sopenharmony_ci		{0x16a0, 0x00eeffdd},
6638c2ecf20Sopenharmony_ci		{0x16a6, 0x00071448},
6648c2ecf20Sopenharmony_ci		{0x16a4, 0x0013132f},
6658c2ecf20Sopenharmony_ci		{0x16a8, 0x00000000},
6668c2ecf20Sopenharmony_ci		{0x0ffc, 0x00c0a028},
6678c2ecf20Sopenharmony_ci		{0x0fe8, 0x0091b06c},
6688c2ecf20Sopenharmony_ci		{0x0fea, 0x00041600},
6698c2ecf20Sopenharmony_ci		{0x0f80, 0x00000af4},
6708c2ecf20Sopenharmony_ci		{0x0fec, 0x00901809},
6718c2ecf20Sopenharmony_ci		{0x0fee, 0x0000a6a1},
6728c2ecf20Sopenharmony_ci		{0x0ffe, 0x00b01007},
6738c2ecf20Sopenharmony_ci		{0x16b0, 0x00eeff00},
6748c2ecf20Sopenharmony_ci		{0x16b2, 0x00007000},
6758c2ecf20Sopenharmony_ci		{0x16b4, 0x00000814},
6768c2ecf20Sopenharmony_ci	};
6778c2ecf20Sopenharmony_ci	unsigned int i;
6788c2ecf20Sopenharmony_ci	int oldpage;
6798c2ecf20Sopenharmony_ci
6808c2ecf20Sopenharmony_ci	mutex_lock(&phydev->lock);
6818c2ecf20Sopenharmony_ci	oldpage = phy_select_page(phydev, MSCC_PHY_PAGE_TR);
6828c2ecf20Sopenharmony_ci	if (oldpage < 0)
6838c2ecf20Sopenharmony_ci		goto out_unlock;
6848c2ecf20Sopenharmony_ci
6858c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(init_eee); i++)
6868c2ecf20Sopenharmony_ci		vsc85xx_tr_write(phydev, init_eee[i].reg, init_eee[i].val);
6878c2ecf20Sopenharmony_ci
6888c2ecf20Sopenharmony_ciout_unlock:
6898c2ecf20Sopenharmony_ci	oldpage = phy_restore_page(phydev, oldpage, oldpage);
6908c2ecf20Sopenharmony_ci	mutex_unlock(&phydev->lock);
6918c2ecf20Sopenharmony_ci
6928c2ecf20Sopenharmony_ci	return oldpage;
6938c2ecf20Sopenharmony_ci}
6948c2ecf20Sopenharmony_ci
6958c2ecf20Sopenharmony_ci/* phydev->bus->mdio_lock should be locked when using this function */
6968c2ecf20Sopenharmony_cistatic int phy_base_write(struct phy_device *phydev, u32 regnum, u16 val)
6978c2ecf20Sopenharmony_ci{
6988c2ecf20Sopenharmony_ci	if (unlikely(!mutex_is_locked(&phydev->mdio.bus->mdio_lock))) {
6998c2ecf20Sopenharmony_ci		dev_err(&phydev->mdio.dev, "MDIO bus lock not held!\n");
7008c2ecf20Sopenharmony_ci		dump_stack();
7018c2ecf20Sopenharmony_ci	}
7028c2ecf20Sopenharmony_ci
7038c2ecf20Sopenharmony_ci	return __phy_package_write(phydev, regnum, val);
7048c2ecf20Sopenharmony_ci}
7058c2ecf20Sopenharmony_ci
7068c2ecf20Sopenharmony_ci/* phydev->bus->mdio_lock should be locked when using this function */
7078c2ecf20Sopenharmony_cistatic int phy_base_read(struct phy_device *phydev, u32 regnum)
7088c2ecf20Sopenharmony_ci{
7098c2ecf20Sopenharmony_ci	if (unlikely(!mutex_is_locked(&phydev->mdio.bus->mdio_lock))) {
7108c2ecf20Sopenharmony_ci		dev_err(&phydev->mdio.dev, "MDIO bus lock not held!\n");
7118c2ecf20Sopenharmony_ci		dump_stack();
7128c2ecf20Sopenharmony_ci	}
7138c2ecf20Sopenharmony_ci
7148c2ecf20Sopenharmony_ci	return __phy_package_read(phydev, regnum);
7158c2ecf20Sopenharmony_ci}
7168c2ecf20Sopenharmony_ci
7178c2ecf20Sopenharmony_cistatic u32 vsc85xx_csr_read(struct phy_device *phydev,
7188c2ecf20Sopenharmony_ci			    enum csr_target target, u32 reg)
7198c2ecf20Sopenharmony_ci{
7208c2ecf20Sopenharmony_ci	unsigned long deadline;
7218c2ecf20Sopenharmony_ci	u32 val, val_l, val_h;
7228c2ecf20Sopenharmony_ci
7238c2ecf20Sopenharmony_ci	phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_CSR_CNTL);
7248c2ecf20Sopenharmony_ci
7258c2ecf20Sopenharmony_ci	/* CSR registers are grouped under different Target IDs.
7268c2ecf20Sopenharmony_ci	 * 6-bit Target_ID is split between MSCC_EXT_PAGE_CSR_CNTL_20 and
7278c2ecf20Sopenharmony_ci	 * MSCC_EXT_PAGE_CSR_CNTL_19 registers.
7288c2ecf20Sopenharmony_ci	 * Target_ID[5:2] maps to bits[3:0] of MSCC_EXT_PAGE_CSR_CNTL_20
7298c2ecf20Sopenharmony_ci	 * and Target_ID[1:0] maps to bits[13:12] of MSCC_EXT_PAGE_CSR_CNTL_19.
7308c2ecf20Sopenharmony_ci	 */
7318c2ecf20Sopenharmony_ci
7328c2ecf20Sopenharmony_ci	/* Setup the Target ID */
7338c2ecf20Sopenharmony_ci	phy_base_write(phydev, MSCC_EXT_PAGE_CSR_CNTL_20,
7348c2ecf20Sopenharmony_ci		       MSCC_PHY_CSR_CNTL_20_TARGET(target >> 2));
7358c2ecf20Sopenharmony_ci
7368c2ecf20Sopenharmony_ci	if ((target >> 2 == 0x1) || (target >> 2 == 0x3))
7378c2ecf20Sopenharmony_ci		/* non-MACsec access */
7388c2ecf20Sopenharmony_ci		target &= 0x3;
7398c2ecf20Sopenharmony_ci	else
7408c2ecf20Sopenharmony_ci		target = 0;
7418c2ecf20Sopenharmony_ci
7428c2ecf20Sopenharmony_ci	/* Trigger CSR Action - Read into the CSR's */
7438c2ecf20Sopenharmony_ci	phy_base_write(phydev, MSCC_EXT_PAGE_CSR_CNTL_19,
7448c2ecf20Sopenharmony_ci		       MSCC_PHY_CSR_CNTL_19_CMD | MSCC_PHY_CSR_CNTL_19_READ |
7458c2ecf20Sopenharmony_ci		       MSCC_PHY_CSR_CNTL_19_REG_ADDR(reg) |
7468c2ecf20Sopenharmony_ci		       MSCC_PHY_CSR_CNTL_19_TARGET(target));
7478c2ecf20Sopenharmony_ci
7488c2ecf20Sopenharmony_ci	/* Wait for register access*/
7498c2ecf20Sopenharmony_ci	deadline = jiffies + msecs_to_jiffies(PROC_CMD_NCOMPLETED_TIMEOUT_MS);
7508c2ecf20Sopenharmony_ci	do {
7518c2ecf20Sopenharmony_ci		usleep_range(500, 1000);
7528c2ecf20Sopenharmony_ci		val = phy_base_read(phydev, MSCC_EXT_PAGE_CSR_CNTL_19);
7538c2ecf20Sopenharmony_ci	} while (time_before(jiffies, deadline) &&
7548c2ecf20Sopenharmony_ci		!(val & MSCC_PHY_CSR_CNTL_19_CMD));
7558c2ecf20Sopenharmony_ci
7568c2ecf20Sopenharmony_ci	if (!(val & MSCC_PHY_CSR_CNTL_19_CMD))
7578c2ecf20Sopenharmony_ci		return 0xffffffff;
7588c2ecf20Sopenharmony_ci
7598c2ecf20Sopenharmony_ci	/* Read the Least Significant Word (LSW) (17) */
7608c2ecf20Sopenharmony_ci	val_l = phy_base_read(phydev, MSCC_EXT_PAGE_CSR_CNTL_17);
7618c2ecf20Sopenharmony_ci
7628c2ecf20Sopenharmony_ci	/* Read the Most Significant Word (MSW) (18) */
7638c2ecf20Sopenharmony_ci	val_h = phy_base_read(phydev, MSCC_EXT_PAGE_CSR_CNTL_18);
7648c2ecf20Sopenharmony_ci
7658c2ecf20Sopenharmony_ci	phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS,
7668c2ecf20Sopenharmony_ci		       MSCC_PHY_PAGE_STANDARD);
7678c2ecf20Sopenharmony_ci
7688c2ecf20Sopenharmony_ci	return (val_h << 16) | val_l;
7698c2ecf20Sopenharmony_ci}
7708c2ecf20Sopenharmony_ci
7718c2ecf20Sopenharmony_cistatic int vsc85xx_csr_write(struct phy_device *phydev,
7728c2ecf20Sopenharmony_ci			     enum csr_target target, u32 reg, u32 val)
7738c2ecf20Sopenharmony_ci{
7748c2ecf20Sopenharmony_ci	unsigned long deadline;
7758c2ecf20Sopenharmony_ci
7768c2ecf20Sopenharmony_ci	phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_CSR_CNTL);
7778c2ecf20Sopenharmony_ci
7788c2ecf20Sopenharmony_ci	/* CSR registers are grouped under different Target IDs.
7798c2ecf20Sopenharmony_ci	 * 6-bit Target_ID is split between MSCC_EXT_PAGE_CSR_CNTL_20 and
7808c2ecf20Sopenharmony_ci	 * MSCC_EXT_PAGE_CSR_CNTL_19 registers.
7818c2ecf20Sopenharmony_ci	 * Target_ID[5:2] maps to bits[3:0] of MSCC_EXT_PAGE_CSR_CNTL_20
7828c2ecf20Sopenharmony_ci	 * and Target_ID[1:0] maps to bits[13:12] of MSCC_EXT_PAGE_CSR_CNTL_19.
7838c2ecf20Sopenharmony_ci	 */
7848c2ecf20Sopenharmony_ci
7858c2ecf20Sopenharmony_ci	/* Setup the Target ID */
7868c2ecf20Sopenharmony_ci	phy_base_write(phydev, MSCC_EXT_PAGE_CSR_CNTL_20,
7878c2ecf20Sopenharmony_ci		       MSCC_PHY_CSR_CNTL_20_TARGET(target >> 2));
7888c2ecf20Sopenharmony_ci
7898c2ecf20Sopenharmony_ci	/* Write the Least Significant Word (LSW) (17) */
7908c2ecf20Sopenharmony_ci	phy_base_write(phydev, MSCC_EXT_PAGE_CSR_CNTL_17, (u16)val);
7918c2ecf20Sopenharmony_ci
7928c2ecf20Sopenharmony_ci	/* Write the Most Significant Word (MSW) (18) */
7938c2ecf20Sopenharmony_ci	phy_base_write(phydev, MSCC_EXT_PAGE_CSR_CNTL_18, (u16)(val >> 16));
7948c2ecf20Sopenharmony_ci
7958c2ecf20Sopenharmony_ci	if ((target >> 2 == 0x1) || (target >> 2 == 0x3))
7968c2ecf20Sopenharmony_ci		/* non-MACsec access */
7978c2ecf20Sopenharmony_ci		target &= 0x3;
7988c2ecf20Sopenharmony_ci	else
7998c2ecf20Sopenharmony_ci		target = 0;
8008c2ecf20Sopenharmony_ci
8018c2ecf20Sopenharmony_ci	/* Trigger CSR Action - Write into the CSR's */
8028c2ecf20Sopenharmony_ci	phy_base_write(phydev, MSCC_EXT_PAGE_CSR_CNTL_19,
8038c2ecf20Sopenharmony_ci		       MSCC_PHY_CSR_CNTL_19_CMD |
8048c2ecf20Sopenharmony_ci		       MSCC_PHY_CSR_CNTL_19_REG_ADDR(reg) |
8058c2ecf20Sopenharmony_ci		       MSCC_PHY_CSR_CNTL_19_TARGET(target));
8068c2ecf20Sopenharmony_ci
8078c2ecf20Sopenharmony_ci	/* Wait for register access */
8088c2ecf20Sopenharmony_ci	deadline = jiffies + msecs_to_jiffies(PROC_CMD_NCOMPLETED_TIMEOUT_MS);
8098c2ecf20Sopenharmony_ci	do {
8108c2ecf20Sopenharmony_ci		usleep_range(500, 1000);
8118c2ecf20Sopenharmony_ci		val = phy_base_read(phydev, MSCC_EXT_PAGE_CSR_CNTL_19);
8128c2ecf20Sopenharmony_ci	} while (time_before(jiffies, deadline) &&
8138c2ecf20Sopenharmony_ci		 !(val & MSCC_PHY_CSR_CNTL_19_CMD));
8148c2ecf20Sopenharmony_ci
8158c2ecf20Sopenharmony_ci	if (!(val & MSCC_PHY_CSR_CNTL_19_CMD))
8168c2ecf20Sopenharmony_ci		return -ETIMEDOUT;
8178c2ecf20Sopenharmony_ci
8188c2ecf20Sopenharmony_ci	phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS,
8198c2ecf20Sopenharmony_ci		       MSCC_PHY_PAGE_STANDARD);
8208c2ecf20Sopenharmony_ci
8218c2ecf20Sopenharmony_ci	return 0;
8228c2ecf20Sopenharmony_ci}
8238c2ecf20Sopenharmony_ci
8248c2ecf20Sopenharmony_ci/* bus->mdio_lock should be locked when using this function */
8258c2ecf20Sopenharmony_cistatic void vsc8584_csr_write(struct phy_device *phydev, u16 addr, u32 val)
8268c2ecf20Sopenharmony_ci{
8278c2ecf20Sopenharmony_ci	phy_base_write(phydev, MSCC_PHY_TR_MSB, val >> 16);
8288c2ecf20Sopenharmony_ci	phy_base_write(phydev, MSCC_PHY_TR_LSB, val & GENMASK(15, 0));
8298c2ecf20Sopenharmony_ci	phy_base_write(phydev, MSCC_PHY_TR_CNTL, TR_WRITE | TR_ADDR(addr));
8308c2ecf20Sopenharmony_ci}
8318c2ecf20Sopenharmony_ci
8328c2ecf20Sopenharmony_ci/* bus->mdio_lock should be locked when using this function */
8338c2ecf20Sopenharmony_cistatic int vsc8584_cmd(struct phy_device *phydev, u16 val)
8348c2ecf20Sopenharmony_ci{
8358c2ecf20Sopenharmony_ci	unsigned long deadline;
8368c2ecf20Sopenharmony_ci	u16 reg_val;
8378c2ecf20Sopenharmony_ci
8388c2ecf20Sopenharmony_ci	phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS,
8398c2ecf20Sopenharmony_ci		       MSCC_PHY_PAGE_EXTENDED_GPIO);
8408c2ecf20Sopenharmony_ci
8418c2ecf20Sopenharmony_ci	phy_base_write(phydev, MSCC_PHY_PROC_CMD, PROC_CMD_NCOMPLETED | val);
8428c2ecf20Sopenharmony_ci
8438c2ecf20Sopenharmony_ci	deadline = jiffies + msecs_to_jiffies(PROC_CMD_NCOMPLETED_TIMEOUT_MS);
8448c2ecf20Sopenharmony_ci	do {
8458c2ecf20Sopenharmony_ci		reg_val = phy_base_read(phydev, MSCC_PHY_PROC_CMD);
8468c2ecf20Sopenharmony_ci	} while (time_before(jiffies, deadline) &&
8478c2ecf20Sopenharmony_ci		 (reg_val & PROC_CMD_NCOMPLETED) &&
8488c2ecf20Sopenharmony_ci		 !(reg_val & PROC_CMD_FAILED));
8498c2ecf20Sopenharmony_ci
8508c2ecf20Sopenharmony_ci	phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);
8518c2ecf20Sopenharmony_ci
8528c2ecf20Sopenharmony_ci	if (reg_val & PROC_CMD_FAILED)
8538c2ecf20Sopenharmony_ci		return -EIO;
8548c2ecf20Sopenharmony_ci
8558c2ecf20Sopenharmony_ci	if (reg_val & PROC_CMD_NCOMPLETED)
8568c2ecf20Sopenharmony_ci		return -ETIMEDOUT;
8578c2ecf20Sopenharmony_ci
8588c2ecf20Sopenharmony_ci	return 0;
8598c2ecf20Sopenharmony_ci}
8608c2ecf20Sopenharmony_ci
8618c2ecf20Sopenharmony_ci/* bus->mdio_lock should be locked when using this function */
8628c2ecf20Sopenharmony_cistatic int vsc8584_micro_deassert_reset(struct phy_device *phydev,
8638c2ecf20Sopenharmony_ci					bool patch_en)
8648c2ecf20Sopenharmony_ci{
8658c2ecf20Sopenharmony_ci	u32 enable, release;
8668c2ecf20Sopenharmony_ci
8678c2ecf20Sopenharmony_ci	phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS,
8688c2ecf20Sopenharmony_ci		       MSCC_PHY_PAGE_EXTENDED_GPIO);
8698c2ecf20Sopenharmony_ci
8708c2ecf20Sopenharmony_ci	enable = RUN_FROM_INT_ROM | MICRO_CLK_EN | DW8051_CLK_EN;
8718c2ecf20Sopenharmony_ci	release = MICRO_NSOFT_RESET | RUN_FROM_INT_ROM | DW8051_CLK_EN |
8728c2ecf20Sopenharmony_ci		MICRO_CLK_EN;
8738c2ecf20Sopenharmony_ci
8748c2ecf20Sopenharmony_ci	if (patch_en) {
8758c2ecf20Sopenharmony_ci		enable |= MICRO_PATCH_EN;
8768c2ecf20Sopenharmony_ci		release |= MICRO_PATCH_EN;
8778c2ecf20Sopenharmony_ci
8788c2ecf20Sopenharmony_ci		/* Clear all patches */
8798c2ecf20Sopenharmony_ci		phy_base_write(phydev, MSCC_INT_MEM_CNTL, READ_RAM);
8808c2ecf20Sopenharmony_ci	}
8818c2ecf20Sopenharmony_ci
8828c2ecf20Sopenharmony_ci	/* Enable 8051 Micro clock; CLEAR/SET patch present; disable PRAM clock
8838c2ecf20Sopenharmony_ci	 * override and addr. auto-incr; operate at 125 MHz
8848c2ecf20Sopenharmony_ci	 */
8858c2ecf20Sopenharmony_ci	phy_base_write(phydev, MSCC_DW8051_CNTL_STATUS, enable);
8868c2ecf20Sopenharmony_ci	/* Release 8051 Micro SW reset */
8878c2ecf20Sopenharmony_ci	phy_base_write(phydev, MSCC_DW8051_CNTL_STATUS, release);
8888c2ecf20Sopenharmony_ci
8898c2ecf20Sopenharmony_ci	phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);
8908c2ecf20Sopenharmony_ci
8918c2ecf20Sopenharmony_ci	return 0;
8928c2ecf20Sopenharmony_ci}
8938c2ecf20Sopenharmony_ci
8948c2ecf20Sopenharmony_ci/* bus->mdio_lock should be locked when using this function */
8958c2ecf20Sopenharmony_cistatic int vsc8584_micro_assert_reset(struct phy_device *phydev)
8968c2ecf20Sopenharmony_ci{
8978c2ecf20Sopenharmony_ci	int ret;
8988c2ecf20Sopenharmony_ci	u16 reg;
8998c2ecf20Sopenharmony_ci
9008c2ecf20Sopenharmony_ci	ret = vsc8584_cmd(phydev, PROC_CMD_NOP);
9018c2ecf20Sopenharmony_ci	if (ret)
9028c2ecf20Sopenharmony_ci		return ret;
9038c2ecf20Sopenharmony_ci
9048c2ecf20Sopenharmony_ci	phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS,
9058c2ecf20Sopenharmony_ci		       MSCC_PHY_PAGE_EXTENDED_GPIO);
9068c2ecf20Sopenharmony_ci
9078c2ecf20Sopenharmony_ci	reg = phy_base_read(phydev, MSCC_INT_MEM_CNTL);
9088c2ecf20Sopenharmony_ci	reg &= ~EN_PATCH_RAM_TRAP_ADDR(4);
9098c2ecf20Sopenharmony_ci	phy_base_write(phydev, MSCC_INT_MEM_CNTL, reg);
9108c2ecf20Sopenharmony_ci
9118c2ecf20Sopenharmony_ci	phy_base_write(phydev, MSCC_TRAP_ROM_ADDR(4), 0x005b);
9128c2ecf20Sopenharmony_ci	phy_base_write(phydev, MSCC_PATCH_RAM_ADDR(4), 0x005b);
9138c2ecf20Sopenharmony_ci
9148c2ecf20Sopenharmony_ci	reg = phy_base_read(phydev, MSCC_INT_MEM_CNTL);
9158c2ecf20Sopenharmony_ci	reg |= EN_PATCH_RAM_TRAP_ADDR(4);
9168c2ecf20Sopenharmony_ci	phy_base_write(phydev, MSCC_INT_MEM_CNTL, reg);
9178c2ecf20Sopenharmony_ci
9188c2ecf20Sopenharmony_ci	phy_base_write(phydev, MSCC_PHY_PROC_CMD, PROC_CMD_NOP);
9198c2ecf20Sopenharmony_ci
9208c2ecf20Sopenharmony_ci	reg = phy_base_read(phydev, MSCC_DW8051_CNTL_STATUS);
9218c2ecf20Sopenharmony_ci	reg &= ~MICRO_NSOFT_RESET;
9228c2ecf20Sopenharmony_ci	phy_base_write(phydev, MSCC_DW8051_CNTL_STATUS, reg);
9238c2ecf20Sopenharmony_ci
9248c2ecf20Sopenharmony_ci	phy_base_write(phydev, MSCC_PHY_PROC_CMD, PROC_CMD_MCB_ACCESS_MAC_CONF |
9258c2ecf20Sopenharmony_ci		       PROC_CMD_SGMII_PORT(0) | PROC_CMD_NO_MAC_CONF |
9268c2ecf20Sopenharmony_ci		       PROC_CMD_READ);
9278c2ecf20Sopenharmony_ci
9288c2ecf20Sopenharmony_ci	reg = phy_base_read(phydev, MSCC_INT_MEM_CNTL);
9298c2ecf20Sopenharmony_ci	reg &= ~EN_PATCH_RAM_TRAP_ADDR(4);
9308c2ecf20Sopenharmony_ci	phy_base_write(phydev, MSCC_INT_MEM_CNTL, reg);
9318c2ecf20Sopenharmony_ci
9328c2ecf20Sopenharmony_ci	phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);
9338c2ecf20Sopenharmony_ci
9348c2ecf20Sopenharmony_ci	return 0;
9358c2ecf20Sopenharmony_ci}
9368c2ecf20Sopenharmony_ci
9378c2ecf20Sopenharmony_ci/* bus->mdio_lock should be locked when using this function */
9388c2ecf20Sopenharmony_cistatic int vsc8584_get_fw_crc(struct phy_device *phydev, u16 start, u16 size,
9398c2ecf20Sopenharmony_ci			      u16 *crc)
9408c2ecf20Sopenharmony_ci{
9418c2ecf20Sopenharmony_ci	int ret;
9428c2ecf20Sopenharmony_ci
9438c2ecf20Sopenharmony_ci	phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_EXTENDED);
9448c2ecf20Sopenharmony_ci
9458c2ecf20Sopenharmony_ci	phy_base_write(phydev, MSCC_PHY_VERIPHY_CNTL_2, start);
9468c2ecf20Sopenharmony_ci	phy_base_write(phydev, MSCC_PHY_VERIPHY_CNTL_3, size);
9478c2ecf20Sopenharmony_ci
9488c2ecf20Sopenharmony_ci	/* Start Micro command */
9498c2ecf20Sopenharmony_ci	ret = vsc8584_cmd(phydev, PROC_CMD_CRC16);
9508c2ecf20Sopenharmony_ci	if (ret)
9518c2ecf20Sopenharmony_ci		goto out;
9528c2ecf20Sopenharmony_ci
9538c2ecf20Sopenharmony_ci	phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_EXTENDED);
9548c2ecf20Sopenharmony_ci
9558c2ecf20Sopenharmony_ci	*crc = phy_base_read(phydev, MSCC_PHY_VERIPHY_CNTL_2);
9568c2ecf20Sopenharmony_ci
9578c2ecf20Sopenharmony_ciout:
9588c2ecf20Sopenharmony_ci	phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);
9598c2ecf20Sopenharmony_ci
9608c2ecf20Sopenharmony_ci	return ret;
9618c2ecf20Sopenharmony_ci}
9628c2ecf20Sopenharmony_ci
9638c2ecf20Sopenharmony_ci/* bus->mdio_lock should be locked when using this function */
9648c2ecf20Sopenharmony_cistatic int vsc8584_patch_fw(struct phy_device *phydev,
9658c2ecf20Sopenharmony_ci			    const struct firmware *fw)
9668c2ecf20Sopenharmony_ci{
9678c2ecf20Sopenharmony_ci	int i, ret;
9688c2ecf20Sopenharmony_ci
9698c2ecf20Sopenharmony_ci	ret = vsc8584_micro_assert_reset(phydev);
9708c2ecf20Sopenharmony_ci	if (ret) {
9718c2ecf20Sopenharmony_ci		dev_err(&phydev->mdio.dev,
9728c2ecf20Sopenharmony_ci			"%s: failed to assert reset of micro\n", __func__);
9738c2ecf20Sopenharmony_ci		return ret;
9748c2ecf20Sopenharmony_ci	}
9758c2ecf20Sopenharmony_ci
9768c2ecf20Sopenharmony_ci	phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS,
9778c2ecf20Sopenharmony_ci		       MSCC_PHY_PAGE_EXTENDED_GPIO);
9788c2ecf20Sopenharmony_ci
9798c2ecf20Sopenharmony_ci	/* Hold 8051 Micro in SW Reset, Enable auto incr address and patch clock
9808c2ecf20Sopenharmony_ci	 * Disable the 8051 Micro clock
9818c2ecf20Sopenharmony_ci	 */
9828c2ecf20Sopenharmony_ci	phy_base_write(phydev, MSCC_DW8051_CNTL_STATUS, RUN_FROM_INT_ROM |
9838c2ecf20Sopenharmony_ci		       AUTOINC_ADDR | PATCH_RAM_CLK | MICRO_CLK_EN |
9848c2ecf20Sopenharmony_ci		       MICRO_CLK_DIVIDE(2));
9858c2ecf20Sopenharmony_ci	phy_base_write(phydev, MSCC_INT_MEM_CNTL, READ_PRAM | INT_MEM_WRITE_EN |
9868c2ecf20Sopenharmony_ci		       INT_MEM_DATA(2));
9878c2ecf20Sopenharmony_ci	phy_base_write(phydev, MSCC_INT_MEM_ADDR, 0x0000);
9888c2ecf20Sopenharmony_ci
9898c2ecf20Sopenharmony_ci	for (i = 0; i < fw->size; i++)
9908c2ecf20Sopenharmony_ci		phy_base_write(phydev, MSCC_INT_MEM_CNTL, READ_PRAM |
9918c2ecf20Sopenharmony_ci			       INT_MEM_WRITE_EN | fw->data[i]);
9928c2ecf20Sopenharmony_ci
9938c2ecf20Sopenharmony_ci	/* Clear internal memory access */
9948c2ecf20Sopenharmony_ci	phy_base_write(phydev, MSCC_INT_MEM_CNTL, READ_RAM);
9958c2ecf20Sopenharmony_ci
9968c2ecf20Sopenharmony_ci	phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);
9978c2ecf20Sopenharmony_ci
9988c2ecf20Sopenharmony_ci	return 0;
9998c2ecf20Sopenharmony_ci}
10008c2ecf20Sopenharmony_ci
10018c2ecf20Sopenharmony_ci/* bus->mdio_lock should be locked when using this function */
10028c2ecf20Sopenharmony_cistatic bool vsc8574_is_serdes_init(struct phy_device *phydev)
10038c2ecf20Sopenharmony_ci{
10048c2ecf20Sopenharmony_ci	u16 reg;
10058c2ecf20Sopenharmony_ci	bool ret;
10068c2ecf20Sopenharmony_ci
10078c2ecf20Sopenharmony_ci	phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS,
10088c2ecf20Sopenharmony_ci		       MSCC_PHY_PAGE_EXTENDED_GPIO);
10098c2ecf20Sopenharmony_ci
10108c2ecf20Sopenharmony_ci	reg = phy_base_read(phydev, MSCC_TRAP_ROM_ADDR(1));
10118c2ecf20Sopenharmony_ci	if (reg != 0x3eb7) {
10128c2ecf20Sopenharmony_ci		ret = false;
10138c2ecf20Sopenharmony_ci		goto out;
10148c2ecf20Sopenharmony_ci	}
10158c2ecf20Sopenharmony_ci
10168c2ecf20Sopenharmony_ci	reg = phy_base_read(phydev, MSCC_PATCH_RAM_ADDR(1));
10178c2ecf20Sopenharmony_ci	if (reg != 0x4012) {
10188c2ecf20Sopenharmony_ci		ret = false;
10198c2ecf20Sopenharmony_ci		goto out;
10208c2ecf20Sopenharmony_ci	}
10218c2ecf20Sopenharmony_ci
10228c2ecf20Sopenharmony_ci	reg = phy_base_read(phydev, MSCC_INT_MEM_CNTL);
10238c2ecf20Sopenharmony_ci	if (reg != EN_PATCH_RAM_TRAP_ADDR(1)) {
10248c2ecf20Sopenharmony_ci		ret = false;
10258c2ecf20Sopenharmony_ci		goto out;
10268c2ecf20Sopenharmony_ci	}
10278c2ecf20Sopenharmony_ci
10288c2ecf20Sopenharmony_ci	reg = phy_base_read(phydev, MSCC_DW8051_CNTL_STATUS);
10298c2ecf20Sopenharmony_ci	if ((MICRO_NSOFT_RESET | RUN_FROM_INT_ROM |  DW8051_CLK_EN |
10308c2ecf20Sopenharmony_ci	     MICRO_CLK_EN) != (reg & MSCC_DW8051_VLD_MASK)) {
10318c2ecf20Sopenharmony_ci		ret = false;
10328c2ecf20Sopenharmony_ci		goto out;
10338c2ecf20Sopenharmony_ci	}
10348c2ecf20Sopenharmony_ci
10358c2ecf20Sopenharmony_ci	ret = true;
10368c2ecf20Sopenharmony_ciout:
10378c2ecf20Sopenharmony_ci	phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);
10388c2ecf20Sopenharmony_ci
10398c2ecf20Sopenharmony_ci	return ret;
10408c2ecf20Sopenharmony_ci}
10418c2ecf20Sopenharmony_ci
10428c2ecf20Sopenharmony_ci/* bus->mdio_lock should be locked when using this function */
10438c2ecf20Sopenharmony_cistatic int vsc8574_config_pre_init(struct phy_device *phydev)
10448c2ecf20Sopenharmony_ci{
10458c2ecf20Sopenharmony_ci	static const struct reg_val pre_init1[] = {
10468c2ecf20Sopenharmony_ci		{0x0fae, 0x000401bd},
10478c2ecf20Sopenharmony_ci		{0x0fac, 0x000f000f},
10488c2ecf20Sopenharmony_ci		{0x17a0, 0x00a0f147},
10498c2ecf20Sopenharmony_ci		{0x0fe4, 0x00052f54},
10508c2ecf20Sopenharmony_ci		{0x1792, 0x0027303d},
10518c2ecf20Sopenharmony_ci		{0x07fe, 0x00000704},
10528c2ecf20Sopenharmony_ci		{0x0fe0, 0x00060150},
10538c2ecf20Sopenharmony_ci		{0x0f82, 0x0012b00a},
10548c2ecf20Sopenharmony_ci		{0x0f80, 0x00000d74},
10558c2ecf20Sopenharmony_ci		{0x02e0, 0x00000012},
10568c2ecf20Sopenharmony_ci		{0x03a2, 0x00050208},
10578c2ecf20Sopenharmony_ci		{0x03b2, 0x00009186},
10588c2ecf20Sopenharmony_ci		{0x0fb0, 0x000e3700},
10598c2ecf20Sopenharmony_ci		{0x1688, 0x00049f81},
10608c2ecf20Sopenharmony_ci		{0x0fd2, 0x0000ffff},
10618c2ecf20Sopenharmony_ci		{0x168a, 0x00039fa2},
10628c2ecf20Sopenharmony_ci		{0x1690, 0x0020640b},
10638c2ecf20Sopenharmony_ci		{0x0258, 0x00002220},
10648c2ecf20Sopenharmony_ci		{0x025a, 0x00002a20},
10658c2ecf20Sopenharmony_ci		{0x025c, 0x00003060},
10668c2ecf20Sopenharmony_ci		{0x025e, 0x00003fa0},
10678c2ecf20Sopenharmony_ci		{0x03a6, 0x0000e0f0},
10688c2ecf20Sopenharmony_ci		{0x0f92, 0x00001489},
10698c2ecf20Sopenharmony_ci		{0x16a2, 0x00007000},
10708c2ecf20Sopenharmony_ci		{0x16a6, 0x00071448},
10718c2ecf20Sopenharmony_ci		{0x16a0, 0x00eeffdd},
10728c2ecf20Sopenharmony_ci		{0x0fe8, 0x0091b06c},
10738c2ecf20Sopenharmony_ci		{0x0fea, 0x00041600},
10748c2ecf20Sopenharmony_ci		{0x16b0, 0x00eeff00},
10758c2ecf20Sopenharmony_ci		{0x16b2, 0x00007000},
10768c2ecf20Sopenharmony_ci		{0x16b4, 0x00000814},
10778c2ecf20Sopenharmony_ci		{0x0f90, 0x00688980},
10788c2ecf20Sopenharmony_ci		{0x03a4, 0x0000d8f0},
10798c2ecf20Sopenharmony_ci		{0x0fc0, 0x00000400},
10808c2ecf20Sopenharmony_ci		{0x07fa, 0x0050100f},
10818c2ecf20Sopenharmony_ci		{0x0796, 0x00000003},
10828c2ecf20Sopenharmony_ci		{0x07f8, 0x00c3ff98},
10838c2ecf20Sopenharmony_ci		{0x0fa4, 0x0018292a},
10848c2ecf20Sopenharmony_ci		{0x168c, 0x00d2c46f},
10858c2ecf20Sopenharmony_ci		{0x17a2, 0x00000620},
10868c2ecf20Sopenharmony_ci		{0x16a4, 0x0013132f},
10878c2ecf20Sopenharmony_ci		{0x16a8, 0x00000000},
10888c2ecf20Sopenharmony_ci		{0x0ffc, 0x00c0a028},
10898c2ecf20Sopenharmony_ci		{0x0fec, 0x00901c09},
10908c2ecf20Sopenharmony_ci		{0x0fee, 0x0004a6a1},
10918c2ecf20Sopenharmony_ci		{0x0ffe, 0x00b01807},
10928c2ecf20Sopenharmony_ci	};
10938c2ecf20Sopenharmony_ci	static const struct reg_val pre_init2[] = {
10948c2ecf20Sopenharmony_ci		{0x0486, 0x0008a518},
10958c2ecf20Sopenharmony_ci		{0x0488, 0x006dc696},
10968c2ecf20Sopenharmony_ci		{0x048a, 0x00000912},
10978c2ecf20Sopenharmony_ci		{0x048e, 0x00000db6},
10988c2ecf20Sopenharmony_ci		{0x049c, 0x00596596},
10998c2ecf20Sopenharmony_ci		{0x049e, 0x00000514},
11008c2ecf20Sopenharmony_ci		{0x04a2, 0x00410280},
11018c2ecf20Sopenharmony_ci		{0x04a4, 0x00000000},
11028c2ecf20Sopenharmony_ci		{0x04a6, 0x00000000},
11038c2ecf20Sopenharmony_ci		{0x04a8, 0x00000000},
11048c2ecf20Sopenharmony_ci		{0x04aa, 0x00000000},
11058c2ecf20Sopenharmony_ci		{0x04ae, 0x007df7dd},
11068c2ecf20Sopenharmony_ci		{0x04b0, 0x006d95d4},
11078c2ecf20Sopenharmony_ci		{0x04b2, 0x00492410},
11088c2ecf20Sopenharmony_ci	};
11098c2ecf20Sopenharmony_ci	struct device *dev = &phydev->mdio.dev;
11108c2ecf20Sopenharmony_ci	const struct firmware *fw;
11118c2ecf20Sopenharmony_ci	unsigned int i;
11128c2ecf20Sopenharmony_ci	u16 crc, reg;
11138c2ecf20Sopenharmony_ci	bool serdes_init;
11148c2ecf20Sopenharmony_ci	int ret;
11158c2ecf20Sopenharmony_ci
11168c2ecf20Sopenharmony_ci	phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);
11178c2ecf20Sopenharmony_ci
11188c2ecf20Sopenharmony_ci	/* all writes below are broadcasted to all PHYs in the same package */
11198c2ecf20Sopenharmony_ci	reg = phy_base_read(phydev, MSCC_PHY_EXT_CNTL_STATUS);
11208c2ecf20Sopenharmony_ci	reg |= SMI_BROADCAST_WR_EN;
11218c2ecf20Sopenharmony_ci	phy_base_write(phydev, MSCC_PHY_EXT_CNTL_STATUS, reg);
11228c2ecf20Sopenharmony_ci
11238c2ecf20Sopenharmony_ci	phy_base_write(phydev, MII_VSC85XX_INT_MASK, 0);
11248c2ecf20Sopenharmony_ci
11258c2ecf20Sopenharmony_ci	/* The below register writes are tweaking analog and electrical
11268c2ecf20Sopenharmony_ci	 * configuration that were determined through characterization by PHY
11278c2ecf20Sopenharmony_ci	 * engineers. These don't mean anything more than "these are the best
11288c2ecf20Sopenharmony_ci	 * values".
11298c2ecf20Sopenharmony_ci	 */
11308c2ecf20Sopenharmony_ci	phy_base_write(phydev, MSCC_PHY_EXT_PHY_CNTL_2, 0x0040);
11318c2ecf20Sopenharmony_ci
11328c2ecf20Sopenharmony_ci	phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_TEST);
11338c2ecf20Sopenharmony_ci
11348c2ecf20Sopenharmony_ci	phy_base_write(phydev, MSCC_PHY_TEST_PAGE_20, 0x4320);
11358c2ecf20Sopenharmony_ci	phy_base_write(phydev, MSCC_PHY_TEST_PAGE_24, 0x0c00);
11368c2ecf20Sopenharmony_ci	phy_base_write(phydev, MSCC_PHY_TEST_PAGE_9, 0x18ca);
11378c2ecf20Sopenharmony_ci	phy_base_write(phydev, MSCC_PHY_TEST_PAGE_5, 0x1b20);
11388c2ecf20Sopenharmony_ci
11398c2ecf20Sopenharmony_ci	reg = phy_base_read(phydev, MSCC_PHY_TEST_PAGE_8);
11408c2ecf20Sopenharmony_ci	reg |= TR_CLK_DISABLE;
11418c2ecf20Sopenharmony_ci	phy_base_write(phydev, MSCC_PHY_TEST_PAGE_8, reg);
11428c2ecf20Sopenharmony_ci
11438c2ecf20Sopenharmony_ci	phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_TR);
11448c2ecf20Sopenharmony_ci
11458c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(pre_init1); i++)
11468c2ecf20Sopenharmony_ci		vsc8584_csr_write(phydev, pre_init1[i].reg, pre_init1[i].val);
11478c2ecf20Sopenharmony_ci
11488c2ecf20Sopenharmony_ci	phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_EXTENDED_2);
11498c2ecf20Sopenharmony_ci
11508c2ecf20Sopenharmony_ci	phy_base_write(phydev, MSCC_PHY_CU_PMD_TX_CNTL, 0x028e);
11518c2ecf20Sopenharmony_ci
11528c2ecf20Sopenharmony_ci	phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_TR);
11538c2ecf20Sopenharmony_ci
11548c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(pre_init2); i++)
11558c2ecf20Sopenharmony_ci		vsc8584_csr_write(phydev, pre_init2[i].reg, pre_init2[i].val);
11568c2ecf20Sopenharmony_ci
11578c2ecf20Sopenharmony_ci	phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_TEST);
11588c2ecf20Sopenharmony_ci
11598c2ecf20Sopenharmony_ci	reg = phy_base_read(phydev, MSCC_PHY_TEST_PAGE_8);
11608c2ecf20Sopenharmony_ci	reg &= ~TR_CLK_DISABLE;
11618c2ecf20Sopenharmony_ci	phy_base_write(phydev, MSCC_PHY_TEST_PAGE_8, reg);
11628c2ecf20Sopenharmony_ci
11638c2ecf20Sopenharmony_ci	phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);
11648c2ecf20Sopenharmony_ci
11658c2ecf20Sopenharmony_ci	/* end of write broadcasting */
11668c2ecf20Sopenharmony_ci	reg = phy_base_read(phydev, MSCC_PHY_EXT_CNTL_STATUS);
11678c2ecf20Sopenharmony_ci	reg &= ~SMI_BROADCAST_WR_EN;
11688c2ecf20Sopenharmony_ci	phy_base_write(phydev, MSCC_PHY_EXT_CNTL_STATUS, reg);
11698c2ecf20Sopenharmony_ci
11708c2ecf20Sopenharmony_ci	ret = request_firmware(&fw, MSCC_VSC8574_REVB_INT8051_FW, dev);
11718c2ecf20Sopenharmony_ci	if (ret) {
11728c2ecf20Sopenharmony_ci		dev_err(dev, "failed to load firmware %s, ret: %d\n",
11738c2ecf20Sopenharmony_ci			MSCC_VSC8574_REVB_INT8051_FW, ret);
11748c2ecf20Sopenharmony_ci		return ret;
11758c2ecf20Sopenharmony_ci	}
11768c2ecf20Sopenharmony_ci
11778c2ecf20Sopenharmony_ci	/* Add one byte to size for the one added by the patch_fw function */
11788c2ecf20Sopenharmony_ci	ret = vsc8584_get_fw_crc(phydev,
11798c2ecf20Sopenharmony_ci				 MSCC_VSC8574_REVB_INT8051_FW_START_ADDR,
11808c2ecf20Sopenharmony_ci				 fw->size + 1, &crc);
11818c2ecf20Sopenharmony_ci	if (ret)
11828c2ecf20Sopenharmony_ci		goto out;
11838c2ecf20Sopenharmony_ci
11848c2ecf20Sopenharmony_ci	if (crc == MSCC_VSC8574_REVB_INT8051_FW_CRC) {
11858c2ecf20Sopenharmony_ci		serdes_init = vsc8574_is_serdes_init(phydev);
11868c2ecf20Sopenharmony_ci
11878c2ecf20Sopenharmony_ci		if (!serdes_init) {
11888c2ecf20Sopenharmony_ci			ret = vsc8584_micro_assert_reset(phydev);
11898c2ecf20Sopenharmony_ci			if (ret) {
11908c2ecf20Sopenharmony_ci				dev_err(dev,
11918c2ecf20Sopenharmony_ci					"%s: failed to assert reset of micro\n",
11928c2ecf20Sopenharmony_ci					__func__);
11938c2ecf20Sopenharmony_ci				goto out;
11948c2ecf20Sopenharmony_ci			}
11958c2ecf20Sopenharmony_ci		}
11968c2ecf20Sopenharmony_ci	} else {
11978c2ecf20Sopenharmony_ci		dev_dbg(dev, "FW CRC is not the expected one, patching FW\n");
11988c2ecf20Sopenharmony_ci
11998c2ecf20Sopenharmony_ci		serdes_init = false;
12008c2ecf20Sopenharmony_ci
12018c2ecf20Sopenharmony_ci		if (vsc8584_patch_fw(phydev, fw))
12028c2ecf20Sopenharmony_ci			dev_warn(dev,
12038c2ecf20Sopenharmony_ci				 "failed to patch FW, expect non-optimal device\n");
12048c2ecf20Sopenharmony_ci	}
12058c2ecf20Sopenharmony_ci
12068c2ecf20Sopenharmony_ci	if (!serdes_init) {
12078c2ecf20Sopenharmony_ci		phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS,
12088c2ecf20Sopenharmony_ci			       MSCC_PHY_PAGE_EXTENDED_GPIO);
12098c2ecf20Sopenharmony_ci
12108c2ecf20Sopenharmony_ci		phy_base_write(phydev, MSCC_TRAP_ROM_ADDR(1), 0x3eb7);
12118c2ecf20Sopenharmony_ci		phy_base_write(phydev, MSCC_PATCH_RAM_ADDR(1), 0x4012);
12128c2ecf20Sopenharmony_ci		phy_base_write(phydev, MSCC_INT_MEM_CNTL,
12138c2ecf20Sopenharmony_ci			       EN_PATCH_RAM_TRAP_ADDR(1));
12148c2ecf20Sopenharmony_ci
12158c2ecf20Sopenharmony_ci		vsc8584_micro_deassert_reset(phydev, false);
12168c2ecf20Sopenharmony_ci
12178c2ecf20Sopenharmony_ci		/* Add one byte to size for the one added by the patch_fw
12188c2ecf20Sopenharmony_ci		 * function
12198c2ecf20Sopenharmony_ci		 */
12208c2ecf20Sopenharmony_ci		ret = vsc8584_get_fw_crc(phydev,
12218c2ecf20Sopenharmony_ci					 MSCC_VSC8574_REVB_INT8051_FW_START_ADDR,
12228c2ecf20Sopenharmony_ci					 fw->size + 1, &crc);
12238c2ecf20Sopenharmony_ci		if (ret)
12248c2ecf20Sopenharmony_ci			goto out;
12258c2ecf20Sopenharmony_ci
12268c2ecf20Sopenharmony_ci		if (crc != MSCC_VSC8574_REVB_INT8051_FW_CRC)
12278c2ecf20Sopenharmony_ci			dev_warn(dev,
12288c2ecf20Sopenharmony_ci				 "FW CRC after patching is not the expected one, expect non-optimal device\n");
12298c2ecf20Sopenharmony_ci	}
12308c2ecf20Sopenharmony_ci
12318c2ecf20Sopenharmony_ci	phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS,
12328c2ecf20Sopenharmony_ci		       MSCC_PHY_PAGE_EXTENDED_GPIO);
12338c2ecf20Sopenharmony_ci
12348c2ecf20Sopenharmony_ci	ret = vsc8584_cmd(phydev, PROC_CMD_1588_DEFAULT_INIT |
12358c2ecf20Sopenharmony_ci			  PROC_CMD_PHY_INIT);
12368c2ecf20Sopenharmony_ci
12378c2ecf20Sopenharmony_ciout:
12388c2ecf20Sopenharmony_ci	phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);
12398c2ecf20Sopenharmony_ci
12408c2ecf20Sopenharmony_ci	release_firmware(fw);
12418c2ecf20Sopenharmony_ci
12428c2ecf20Sopenharmony_ci	return ret;
12438c2ecf20Sopenharmony_ci}
12448c2ecf20Sopenharmony_ci
12458c2ecf20Sopenharmony_ci/* Access LCPLL Cfg_2 */
12468c2ecf20Sopenharmony_cistatic void vsc8584_pll5g_cfg2_wr(struct phy_device *phydev,
12478c2ecf20Sopenharmony_ci				  bool disable_fsm)
12488c2ecf20Sopenharmony_ci{
12498c2ecf20Sopenharmony_ci	u32 rd_dat;
12508c2ecf20Sopenharmony_ci
12518c2ecf20Sopenharmony_ci	rd_dat = vsc85xx_csr_read(phydev, MACRO_CTRL, PHY_S6G_PLL5G_CFG2);
12528c2ecf20Sopenharmony_ci	rd_dat &= ~BIT(PHY_S6G_CFG2_FSM_DIS);
12538c2ecf20Sopenharmony_ci	rd_dat |= (disable_fsm << PHY_S6G_CFG2_FSM_DIS);
12548c2ecf20Sopenharmony_ci	vsc85xx_csr_write(phydev, MACRO_CTRL, PHY_S6G_PLL5G_CFG2, rd_dat);
12558c2ecf20Sopenharmony_ci}
12568c2ecf20Sopenharmony_ci
12578c2ecf20Sopenharmony_ci/* trigger a read to the spcified MCB */
12588c2ecf20Sopenharmony_cistatic int vsc8584_mcb_rd_trig(struct phy_device *phydev,
12598c2ecf20Sopenharmony_ci			       u32 mcb_reg_addr, u8 mcb_slave_num)
12608c2ecf20Sopenharmony_ci{
12618c2ecf20Sopenharmony_ci	u32 rd_dat = 0;
12628c2ecf20Sopenharmony_ci
12638c2ecf20Sopenharmony_ci	/* read MCB */
12648c2ecf20Sopenharmony_ci	vsc85xx_csr_write(phydev, MACRO_CTRL, mcb_reg_addr,
12658c2ecf20Sopenharmony_ci			  (0x40000000 | (1L << mcb_slave_num)));
12668c2ecf20Sopenharmony_ci
12678c2ecf20Sopenharmony_ci	return read_poll_timeout(vsc85xx_csr_read, rd_dat,
12688c2ecf20Sopenharmony_ci				 !(rd_dat & 0x40000000),
12698c2ecf20Sopenharmony_ci				 4000, 200000, 0,
12708c2ecf20Sopenharmony_ci				 phydev, MACRO_CTRL, mcb_reg_addr);
12718c2ecf20Sopenharmony_ci}
12728c2ecf20Sopenharmony_ci
12738c2ecf20Sopenharmony_ci/* trigger a write to the spcified MCB */
12748c2ecf20Sopenharmony_cistatic int vsc8584_mcb_wr_trig(struct phy_device *phydev,
12758c2ecf20Sopenharmony_ci			       u32 mcb_reg_addr,
12768c2ecf20Sopenharmony_ci			       u8 mcb_slave_num)
12778c2ecf20Sopenharmony_ci{
12788c2ecf20Sopenharmony_ci	u32 rd_dat = 0;
12798c2ecf20Sopenharmony_ci
12808c2ecf20Sopenharmony_ci	/* write back MCB */
12818c2ecf20Sopenharmony_ci	vsc85xx_csr_write(phydev, MACRO_CTRL, mcb_reg_addr,
12828c2ecf20Sopenharmony_ci			  (0x80000000 | (1L << mcb_slave_num)));
12838c2ecf20Sopenharmony_ci
12848c2ecf20Sopenharmony_ci	return read_poll_timeout(vsc85xx_csr_read, rd_dat,
12858c2ecf20Sopenharmony_ci				 !(rd_dat & 0x80000000),
12868c2ecf20Sopenharmony_ci				 4000, 200000, 0,
12878c2ecf20Sopenharmony_ci				 phydev, MACRO_CTRL, mcb_reg_addr);
12888c2ecf20Sopenharmony_ci}
12898c2ecf20Sopenharmony_ci
12908c2ecf20Sopenharmony_ci/* Sequence to Reset LCPLL for the VIPER and ELISE PHY */
12918c2ecf20Sopenharmony_cistatic int vsc8584_pll5g_reset(struct phy_device *phydev)
12928c2ecf20Sopenharmony_ci{
12938c2ecf20Sopenharmony_ci	bool dis_fsm;
12948c2ecf20Sopenharmony_ci	int ret = 0;
12958c2ecf20Sopenharmony_ci
12968c2ecf20Sopenharmony_ci	ret = vsc8584_mcb_rd_trig(phydev, 0x11, 0);
12978c2ecf20Sopenharmony_ci	if (ret < 0)
12988c2ecf20Sopenharmony_ci		goto done;
12998c2ecf20Sopenharmony_ci	dis_fsm = 1;
13008c2ecf20Sopenharmony_ci
13018c2ecf20Sopenharmony_ci	/* Reset LCPLL */
13028c2ecf20Sopenharmony_ci	vsc8584_pll5g_cfg2_wr(phydev, dis_fsm);
13038c2ecf20Sopenharmony_ci
13048c2ecf20Sopenharmony_ci	/* write back LCPLL MCB */
13058c2ecf20Sopenharmony_ci	ret = vsc8584_mcb_wr_trig(phydev, 0x11, 0);
13068c2ecf20Sopenharmony_ci	if (ret < 0)
13078c2ecf20Sopenharmony_ci		goto done;
13088c2ecf20Sopenharmony_ci
13098c2ecf20Sopenharmony_ci	/* 10 mSec sleep while LCPLL is hold in reset */
13108c2ecf20Sopenharmony_ci	usleep_range(10000, 20000);
13118c2ecf20Sopenharmony_ci
13128c2ecf20Sopenharmony_ci	/* read LCPLL MCB into CSRs */
13138c2ecf20Sopenharmony_ci	ret = vsc8584_mcb_rd_trig(phydev, 0x11, 0);
13148c2ecf20Sopenharmony_ci	if (ret < 0)
13158c2ecf20Sopenharmony_ci		goto done;
13168c2ecf20Sopenharmony_ci	dis_fsm = 0;
13178c2ecf20Sopenharmony_ci
13188c2ecf20Sopenharmony_ci	/* Release the Reset of LCPLL */
13198c2ecf20Sopenharmony_ci	vsc8584_pll5g_cfg2_wr(phydev, dis_fsm);
13208c2ecf20Sopenharmony_ci
13218c2ecf20Sopenharmony_ci	/* write back LCPLL MCB */
13228c2ecf20Sopenharmony_ci	ret = vsc8584_mcb_wr_trig(phydev, 0x11, 0);
13238c2ecf20Sopenharmony_ci	if (ret < 0)
13248c2ecf20Sopenharmony_ci		goto done;
13258c2ecf20Sopenharmony_ci
13268c2ecf20Sopenharmony_ci	usleep_range(110000, 200000);
13278c2ecf20Sopenharmony_cidone:
13288c2ecf20Sopenharmony_ci	return ret;
13298c2ecf20Sopenharmony_ci}
13308c2ecf20Sopenharmony_ci
13318c2ecf20Sopenharmony_ci/* bus->mdio_lock should be locked when using this function */
13328c2ecf20Sopenharmony_cistatic int vsc8584_config_pre_init(struct phy_device *phydev)
13338c2ecf20Sopenharmony_ci{
13348c2ecf20Sopenharmony_ci	static const struct reg_val pre_init1[] = {
13358c2ecf20Sopenharmony_ci		{0x07fa, 0x0050100f},
13368c2ecf20Sopenharmony_ci		{0x1688, 0x00049f81},
13378c2ecf20Sopenharmony_ci		{0x0f90, 0x00688980},
13388c2ecf20Sopenharmony_ci		{0x03a4, 0x0000d8f0},
13398c2ecf20Sopenharmony_ci		{0x0fc0, 0x00000400},
13408c2ecf20Sopenharmony_ci		{0x0f82, 0x0012b002},
13418c2ecf20Sopenharmony_ci		{0x1686, 0x00000004},
13428c2ecf20Sopenharmony_ci		{0x168c, 0x00d2c46f},
13438c2ecf20Sopenharmony_ci		{0x17a2, 0x00000620},
13448c2ecf20Sopenharmony_ci		{0x16a0, 0x00eeffdd},
13458c2ecf20Sopenharmony_ci		{0x16a6, 0x00071448},
13468c2ecf20Sopenharmony_ci		{0x16a4, 0x0013132f},
13478c2ecf20Sopenharmony_ci		{0x16a8, 0x00000000},
13488c2ecf20Sopenharmony_ci		{0x0ffc, 0x00c0a028},
13498c2ecf20Sopenharmony_ci		{0x0fe8, 0x0091b06c},
13508c2ecf20Sopenharmony_ci		{0x0fea, 0x00041600},
13518c2ecf20Sopenharmony_ci		{0x0f80, 0x00fffaff},
13528c2ecf20Sopenharmony_ci		{0x0fec, 0x00901809},
13538c2ecf20Sopenharmony_ci		{0x0ffe, 0x00b01007},
13548c2ecf20Sopenharmony_ci		{0x16b0, 0x00eeff00},
13558c2ecf20Sopenharmony_ci		{0x16b2, 0x00007000},
13568c2ecf20Sopenharmony_ci		{0x16b4, 0x00000814},
13578c2ecf20Sopenharmony_ci	};
13588c2ecf20Sopenharmony_ci	static const struct reg_val pre_init2[] = {
13598c2ecf20Sopenharmony_ci		{0x0486, 0x0008a518},
13608c2ecf20Sopenharmony_ci		{0x0488, 0x006dc696},
13618c2ecf20Sopenharmony_ci		{0x048a, 0x00000912},
13628c2ecf20Sopenharmony_ci	};
13638c2ecf20Sopenharmony_ci	const struct firmware *fw;
13648c2ecf20Sopenharmony_ci	struct device *dev = &phydev->mdio.dev;
13658c2ecf20Sopenharmony_ci	unsigned int i;
13668c2ecf20Sopenharmony_ci	u16 crc, reg;
13678c2ecf20Sopenharmony_ci	int ret;
13688c2ecf20Sopenharmony_ci
13698c2ecf20Sopenharmony_ci	phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);
13708c2ecf20Sopenharmony_ci
13718c2ecf20Sopenharmony_ci	/* all writes below are broadcasted to all PHYs in the same package */
13728c2ecf20Sopenharmony_ci	reg = phy_base_read(phydev, MSCC_PHY_EXT_CNTL_STATUS);
13738c2ecf20Sopenharmony_ci	reg |= SMI_BROADCAST_WR_EN;
13748c2ecf20Sopenharmony_ci	phy_base_write(phydev, MSCC_PHY_EXT_CNTL_STATUS, reg);
13758c2ecf20Sopenharmony_ci
13768c2ecf20Sopenharmony_ci	phy_base_write(phydev, MII_VSC85XX_INT_MASK, 0);
13778c2ecf20Sopenharmony_ci
13788c2ecf20Sopenharmony_ci	reg = phy_base_read(phydev,  MSCC_PHY_BYPASS_CONTROL);
13798c2ecf20Sopenharmony_ci	reg |= PARALLEL_DET_IGNORE_ADVERTISED;
13808c2ecf20Sopenharmony_ci	phy_base_write(phydev, MSCC_PHY_BYPASS_CONTROL, reg);
13818c2ecf20Sopenharmony_ci
13828c2ecf20Sopenharmony_ci	/* The below register writes are tweaking analog and electrical
13838c2ecf20Sopenharmony_ci	 * configuration that were determined through characterization by PHY
13848c2ecf20Sopenharmony_ci	 * engineers. These don't mean anything more than "these are the best
13858c2ecf20Sopenharmony_ci	 * values".
13868c2ecf20Sopenharmony_ci	 */
13878c2ecf20Sopenharmony_ci	phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_EXTENDED_3);
13888c2ecf20Sopenharmony_ci
13898c2ecf20Sopenharmony_ci	phy_base_write(phydev, MSCC_PHY_SERDES_TX_CRC_ERR_CNT, 0x2000);
13908c2ecf20Sopenharmony_ci
13918c2ecf20Sopenharmony_ci	phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_TEST);
13928c2ecf20Sopenharmony_ci
13938c2ecf20Sopenharmony_ci	phy_base_write(phydev, MSCC_PHY_TEST_PAGE_5, 0x1f20);
13948c2ecf20Sopenharmony_ci
13958c2ecf20Sopenharmony_ci	reg = phy_base_read(phydev, MSCC_PHY_TEST_PAGE_8);
13968c2ecf20Sopenharmony_ci	reg |= TR_CLK_DISABLE;
13978c2ecf20Sopenharmony_ci	phy_base_write(phydev, MSCC_PHY_TEST_PAGE_8, reg);
13988c2ecf20Sopenharmony_ci
13998c2ecf20Sopenharmony_ci	phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_TR);
14008c2ecf20Sopenharmony_ci
14018c2ecf20Sopenharmony_ci	phy_base_write(phydev, MSCC_PHY_TR_CNTL, TR_WRITE | TR_ADDR(0x2fa4));
14028c2ecf20Sopenharmony_ci
14038c2ecf20Sopenharmony_ci	reg = phy_base_read(phydev, MSCC_PHY_TR_MSB);
14048c2ecf20Sopenharmony_ci	reg &= ~0x007f;
14058c2ecf20Sopenharmony_ci	reg |= 0x0019;
14068c2ecf20Sopenharmony_ci	phy_base_write(phydev, MSCC_PHY_TR_MSB, reg);
14078c2ecf20Sopenharmony_ci
14088c2ecf20Sopenharmony_ci	phy_base_write(phydev, MSCC_PHY_TR_CNTL, TR_WRITE | TR_ADDR(0x0fa4));
14098c2ecf20Sopenharmony_ci
14108c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(pre_init1); i++)
14118c2ecf20Sopenharmony_ci		vsc8584_csr_write(phydev, pre_init1[i].reg, pre_init1[i].val);
14128c2ecf20Sopenharmony_ci
14138c2ecf20Sopenharmony_ci	phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_EXTENDED_2);
14148c2ecf20Sopenharmony_ci
14158c2ecf20Sopenharmony_ci	phy_base_write(phydev, MSCC_PHY_CU_PMD_TX_CNTL, 0x028e);
14168c2ecf20Sopenharmony_ci
14178c2ecf20Sopenharmony_ci	phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_TR);
14188c2ecf20Sopenharmony_ci
14198c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(pre_init2); i++)
14208c2ecf20Sopenharmony_ci		vsc8584_csr_write(phydev, pre_init2[i].reg, pre_init2[i].val);
14218c2ecf20Sopenharmony_ci
14228c2ecf20Sopenharmony_ci	phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_TEST);
14238c2ecf20Sopenharmony_ci
14248c2ecf20Sopenharmony_ci	reg = phy_base_read(phydev, MSCC_PHY_TEST_PAGE_8);
14258c2ecf20Sopenharmony_ci	reg &= ~TR_CLK_DISABLE;
14268c2ecf20Sopenharmony_ci	phy_base_write(phydev, MSCC_PHY_TEST_PAGE_8, reg);
14278c2ecf20Sopenharmony_ci
14288c2ecf20Sopenharmony_ci	phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);
14298c2ecf20Sopenharmony_ci
14308c2ecf20Sopenharmony_ci	/* end of write broadcasting */
14318c2ecf20Sopenharmony_ci	reg = phy_base_read(phydev, MSCC_PHY_EXT_CNTL_STATUS);
14328c2ecf20Sopenharmony_ci	reg &= ~SMI_BROADCAST_WR_EN;
14338c2ecf20Sopenharmony_ci	phy_base_write(phydev, MSCC_PHY_EXT_CNTL_STATUS, reg);
14348c2ecf20Sopenharmony_ci
14358c2ecf20Sopenharmony_ci	ret = request_firmware(&fw, MSCC_VSC8584_REVB_INT8051_FW, dev);
14368c2ecf20Sopenharmony_ci	if (ret) {
14378c2ecf20Sopenharmony_ci		dev_err(dev, "failed to load firmware %s, ret: %d\n",
14388c2ecf20Sopenharmony_ci			MSCC_VSC8584_REVB_INT8051_FW, ret);
14398c2ecf20Sopenharmony_ci		return ret;
14408c2ecf20Sopenharmony_ci	}
14418c2ecf20Sopenharmony_ci
14428c2ecf20Sopenharmony_ci	/* Add one byte to size for the one added by the patch_fw function */
14438c2ecf20Sopenharmony_ci	ret = vsc8584_get_fw_crc(phydev,
14448c2ecf20Sopenharmony_ci				 MSCC_VSC8584_REVB_INT8051_FW_START_ADDR,
14458c2ecf20Sopenharmony_ci				 fw->size + 1, &crc);
14468c2ecf20Sopenharmony_ci	if (ret)
14478c2ecf20Sopenharmony_ci		goto out;
14488c2ecf20Sopenharmony_ci
14498c2ecf20Sopenharmony_ci	if (crc != MSCC_VSC8584_REVB_INT8051_FW_CRC) {
14508c2ecf20Sopenharmony_ci		dev_dbg(dev, "FW CRC is not the expected one, patching FW\n");
14518c2ecf20Sopenharmony_ci		if (vsc8584_patch_fw(phydev, fw))
14528c2ecf20Sopenharmony_ci			dev_warn(dev,
14538c2ecf20Sopenharmony_ci				 "failed to patch FW, expect non-optimal device\n");
14548c2ecf20Sopenharmony_ci	}
14558c2ecf20Sopenharmony_ci
14568c2ecf20Sopenharmony_ci	vsc8584_micro_deassert_reset(phydev, false);
14578c2ecf20Sopenharmony_ci
14588c2ecf20Sopenharmony_ci	/* Add one byte to size for the one added by the patch_fw function */
14598c2ecf20Sopenharmony_ci	ret = vsc8584_get_fw_crc(phydev,
14608c2ecf20Sopenharmony_ci				 MSCC_VSC8584_REVB_INT8051_FW_START_ADDR,
14618c2ecf20Sopenharmony_ci				 fw->size + 1, &crc);
14628c2ecf20Sopenharmony_ci	if (ret)
14638c2ecf20Sopenharmony_ci		goto out;
14648c2ecf20Sopenharmony_ci
14658c2ecf20Sopenharmony_ci	if (crc != MSCC_VSC8584_REVB_INT8051_FW_CRC)
14668c2ecf20Sopenharmony_ci		dev_warn(dev,
14678c2ecf20Sopenharmony_ci			 "FW CRC after patching is not the expected one, expect non-optimal device\n");
14688c2ecf20Sopenharmony_ci
14698c2ecf20Sopenharmony_ci	ret = vsc8584_micro_assert_reset(phydev);
14708c2ecf20Sopenharmony_ci	if (ret)
14718c2ecf20Sopenharmony_ci		goto out;
14728c2ecf20Sopenharmony_ci
14738c2ecf20Sopenharmony_ci	vsc8584_micro_deassert_reset(phydev, true);
14748c2ecf20Sopenharmony_ci
14758c2ecf20Sopenharmony_ciout:
14768c2ecf20Sopenharmony_ci	phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);
14778c2ecf20Sopenharmony_ci
14788c2ecf20Sopenharmony_ci	release_firmware(fw);
14798c2ecf20Sopenharmony_ci
14808c2ecf20Sopenharmony_ci	return ret;
14818c2ecf20Sopenharmony_ci}
14828c2ecf20Sopenharmony_ci
14838c2ecf20Sopenharmony_cistatic void vsc8584_get_base_addr(struct phy_device *phydev)
14848c2ecf20Sopenharmony_ci{
14858c2ecf20Sopenharmony_ci	struct vsc8531_private *vsc8531 = phydev->priv;
14868c2ecf20Sopenharmony_ci	u16 val, addr;
14878c2ecf20Sopenharmony_ci
14888c2ecf20Sopenharmony_ci	phy_lock_mdio_bus(phydev);
14898c2ecf20Sopenharmony_ci	__phy_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_EXTENDED);
14908c2ecf20Sopenharmony_ci
14918c2ecf20Sopenharmony_ci	addr = __phy_read(phydev, MSCC_PHY_EXT_PHY_CNTL_4);
14928c2ecf20Sopenharmony_ci	addr >>= PHY_CNTL_4_ADDR_POS;
14938c2ecf20Sopenharmony_ci
14948c2ecf20Sopenharmony_ci	val = __phy_read(phydev, MSCC_PHY_ACTIPHY_CNTL);
14958c2ecf20Sopenharmony_ci
14968c2ecf20Sopenharmony_ci	__phy_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);
14978c2ecf20Sopenharmony_ci	phy_unlock_mdio_bus(phydev);
14988c2ecf20Sopenharmony_ci
14998c2ecf20Sopenharmony_ci	/* In the package, there are two pairs of PHYs (PHY0 + PHY2 and
15008c2ecf20Sopenharmony_ci	 * PHY1 + PHY3). The first PHY of each pair (PHY0 and PHY1) is
15018c2ecf20Sopenharmony_ci	 * the base PHY for timestamping operations.
15028c2ecf20Sopenharmony_ci	 */
15038c2ecf20Sopenharmony_ci	vsc8531->ts_base_addr = phydev->mdio.addr;
15048c2ecf20Sopenharmony_ci	vsc8531->ts_base_phy = addr;
15058c2ecf20Sopenharmony_ci
15068c2ecf20Sopenharmony_ci	if (val & PHY_ADDR_REVERSED) {
15078c2ecf20Sopenharmony_ci		vsc8531->base_addr = phydev->mdio.addr + addr;
15088c2ecf20Sopenharmony_ci		if (addr > 1) {
15098c2ecf20Sopenharmony_ci			vsc8531->ts_base_addr += 2;
15108c2ecf20Sopenharmony_ci			vsc8531->ts_base_phy += 2;
15118c2ecf20Sopenharmony_ci		}
15128c2ecf20Sopenharmony_ci	} else {
15138c2ecf20Sopenharmony_ci		vsc8531->base_addr = phydev->mdio.addr - addr;
15148c2ecf20Sopenharmony_ci		if (addr > 1) {
15158c2ecf20Sopenharmony_ci			vsc8531->ts_base_addr -= 2;
15168c2ecf20Sopenharmony_ci			vsc8531->ts_base_phy -= 2;
15178c2ecf20Sopenharmony_ci		}
15188c2ecf20Sopenharmony_ci	}
15198c2ecf20Sopenharmony_ci
15208c2ecf20Sopenharmony_ci	vsc8531->addr = addr;
15218c2ecf20Sopenharmony_ci}
15228c2ecf20Sopenharmony_ci
15238c2ecf20Sopenharmony_cistatic int vsc8584_config_init(struct phy_device *phydev)
15248c2ecf20Sopenharmony_ci{
15258c2ecf20Sopenharmony_ci	struct vsc8531_private *vsc8531 = phydev->priv;
15268c2ecf20Sopenharmony_ci	int ret, i;
15278c2ecf20Sopenharmony_ci	u16 val;
15288c2ecf20Sopenharmony_ci
15298c2ecf20Sopenharmony_ci	phydev->mdix_ctrl = ETH_TP_MDI_AUTO;
15308c2ecf20Sopenharmony_ci
15318c2ecf20Sopenharmony_ci	phy_lock_mdio_bus(phydev);
15328c2ecf20Sopenharmony_ci
15338c2ecf20Sopenharmony_ci	/* Some parts of the init sequence are identical for every PHY in the
15348c2ecf20Sopenharmony_ci	 * package. Some parts are modifying the GPIO register bank which is a
15358c2ecf20Sopenharmony_ci	 * set of registers that are affecting all PHYs, a few resetting the
15368c2ecf20Sopenharmony_ci	 * microprocessor common to all PHYs. The CRC check responsible of the
15378c2ecf20Sopenharmony_ci	 * checking the firmware within the 8051 microprocessor can only be
15388c2ecf20Sopenharmony_ci	 * accessed via the PHY whose internal address in the package is 0.
15398c2ecf20Sopenharmony_ci	 * All PHYs' interrupts mask register has to be zeroed before enabling
15408c2ecf20Sopenharmony_ci	 * any PHY's interrupt in this register.
15418c2ecf20Sopenharmony_ci	 * For all these reasons, we need to do the init sequence once and only
15428c2ecf20Sopenharmony_ci	 * once whatever is the first PHY in the package that is initialized and
15438c2ecf20Sopenharmony_ci	 * do the correct init sequence for all PHYs that are package-critical
15448c2ecf20Sopenharmony_ci	 * in this pre-init function.
15458c2ecf20Sopenharmony_ci	 */
15468c2ecf20Sopenharmony_ci	if (phy_package_init_once(phydev)) {
15478c2ecf20Sopenharmony_ci		/* The following switch statement assumes that the lowest
15488c2ecf20Sopenharmony_ci		 * nibble of the phy_id_mask is always 0. This works because
15498c2ecf20Sopenharmony_ci		 * the lowest nibble of the PHY_ID's below are also 0.
15508c2ecf20Sopenharmony_ci		 */
15518c2ecf20Sopenharmony_ci		WARN_ON(phydev->drv->phy_id_mask & 0xf);
15528c2ecf20Sopenharmony_ci
15538c2ecf20Sopenharmony_ci		switch (phydev->phy_id & phydev->drv->phy_id_mask) {
15548c2ecf20Sopenharmony_ci		case PHY_ID_VSC8504:
15558c2ecf20Sopenharmony_ci		case PHY_ID_VSC8552:
15568c2ecf20Sopenharmony_ci		case PHY_ID_VSC8572:
15578c2ecf20Sopenharmony_ci		case PHY_ID_VSC8574:
15588c2ecf20Sopenharmony_ci			ret = vsc8574_config_pre_init(phydev);
15598c2ecf20Sopenharmony_ci			break;
15608c2ecf20Sopenharmony_ci		case PHY_ID_VSC856X:
15618c2ecf20Sopenharmony_ci		case PHY_ID_VSC8575:
15628c2ecf20Sopenharmony_ci		case PHY_ID_VSC8582:
15638c2ecf20Sopenharmony_ci		case PHY_ID_VSC8584:
15648c2ecf20Sopenharmony_ci			ret = vsc8584_config_pre_init(phydev);
15658c2ecf20Sopenharmony_ci			break;
15668c2ecf20Sopenharmony_ci		default:
15678c2ecf20Sopenharmony_ci			ret = -EINVAL;
15688c2ecf20Sopenharmony_ci			break;
15698c2ecf20Sopenharmony_ci		}
15708c2ecf20Sopenharmony_ci
15718c2ecf20Sopenharmony_ci		if (ret)
15728c2ecf20Sopenharmony_ci			goto err;
15738c2ecf20Sopenharmony_ci	}
15748c2ecf20Sopenharmony_ci
15758c2ecf20Sopenharmony_ci	ret = phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS,
15768c2ecf20Sopenharmony_ci			     MSCC_PHY_PAGE_EXTENDED_GPIO);
15778c2ecf20Sopenharmony_ci	if (ret)
15788c2ecf20Sopenharmony_ci		goto err;
15798c2ecf20Sopenharmony_ci
15808c2ecf20Sopenharmony_ci	val = phy_base_read(phydev, MSCC_PHY_MAC_CFG_FASTLINK);
15818c2ecf20Sopenharmony_ci	val &= ~MAC_CFG_MASK;
15828c2ecf20Sopenharmony_ci	if (phydev->interface == PHY_INTERFACE_MODE_QSGMII) {
15838c2ecf20Sopenharmony_ci		val |= MAC_CFG_QSGMII;
15848c2ecf20Sopenharmony_ci	} else if (phydev->interface == PHY_INTERFACE_MODE_SGMII) {
15858c2ecf20Sopenharmony_ci		val |= MAC_CFG_SGMII;
15868c2ecf20Sopenharmony_ci	} else if (phy_interface_is_rgmii(phydev)) {
15878c2ecf20Sopenharmony_ci		val |= MAC_CFG_RGMII;
15888c2ecf20Sopenharmony_ci	} else {
15898c2ecf20Sopenharmony_ci		ret = -EINVAL;
15908c2ecf20Sopenharmony_ci		goto err;
15918c2ecf20Sopenharmony_ci	}
15928c2ecf20Sopenharmony_ci
15938c2ecf20Sopenharmony_ci	ret = phy_base_write(phydev, MSCC_PHY_MAC_CFG_FASTLINK, val);
15948c2ecf20Sopenharmony_ci	if (ret)
15958c2ecf20Sopenharmony_ci		goto err;
15968c2ecf20Sopenharmony_ci
15978c2ecf20Sopenharmony_ci	ret = phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS,
15988c2ecf20Sopenharmony_ci			     MSCC_PHY_PAGE_STANDARD);
15998c2ecf20Sopenharmony_ci	if (ret)
16008c2ecf20Sopenharmony_ci		goto err;
16018c2ecf20Sopenharmony_ci
16028c2ecf20Sopenharmony_ci	if (!phy_interface_is_rgmii(phydev)) {
16038c2ecf20Sopenharmony_ci		val = PROC_CMD_MCB_ACCESS_MAC_CONF | PROC_CMD_RST_CONF_PORT |
16048c2ecf20Sopenharmony_ci			PROC_CMD_READ_MOD_WRITE_PORT;
16058c2ecf20Sopenharmony_ci		if (phydev->interface == PHY_INTERFACE_MODE_QSGMII)
16068c2ecf20Sopenharmony_ci			val |= PROC_CMD_QSGMII_MAC;
16078c2ecf20Sopenharmony_ci		else
16088c2ecf20Sopenharmony_ci			val |= PROC_CMD_SGMII_MAC;
16098c2ecf20Sopenharmony_ci
16108c2ecf20Sopenharmony_ci		ret = vsc8584_cmd(phydev, val);
16118c2ecf20Sopenharmony_ci		if (ret)
16128c2ecf20Sopenharmony_ci			goto err;
16138c2ecf20Sopenharmony_ci
16148c2ecf20Sopenharmony_ci		usleep_range(10000, 20000);
16158c2ecf20Sopenharmony_ci	}
16168c2ecf20Sopenharmony_ci
16178c2ecf20Sopenharmony_ci	/* Disable SerDes for 100Base-FX */
16188c2ecf20Sopenharmony_ci	ret = vsc8584_cmd(phydev, PROC_CMD_FIBER_MEDIA_CONF |
16198c2ecf20Sopenharmony_ci			  PROC_CMD_FIBER_PORT(vsc8531->addr) |
16208c2ecf20Sopenharmony_ci			  PROC_CMD_FIBER_DISABLE |
16218c2ecf20Sopenharmony_ci			  PROC_CMD_READ_MOD_WRITE_PORT |
16228c2ecf20Sopenharmony_ci			  PROC_CMD_RST_CONF_PORT | PROC_CMD_FIBER_100BASE_FX);
16238c2ecf20Sopenharmony_ci	if (ret)
16248c2ecf20Sopenharmony_ci		goto err;
16258c2ecf20Sopenharmony_ci
16268c2ecf20Sopenharmony_ci	/* Disable SerDes for 1000Base-X */
16278c2ecf20Sopenharmony_ci	ret = vsc8584_cmd(phydev, PROC_CMD_FIBER_MEDIA_CONF |
16288c2ecf20Sopenharmony_ci			  PROC_CMD_FIBER_PORT(vsc8531->addr) |
16298c2ecf20Sopenharmony_ci			  PROC_CMD_FIBER_DISABLE |
16308c2ecf20Sopenharmony_ci			  PROC_CMD_READ_MOD_WRITE_PORT |
16318c2ecf20Sopenharmony_ci			  PROC_CMD_RST_CONF_PORT | PROC_CMD_FIBER_1000BASE_X);
16328c2ecf20Sopenharmony_ci	if (ret)
16338c2ecf20Sopenharmony_ci		goto err;
16348c2ecf20Sopenharmony_ci
16358c2ecf20Sopenharmony_ci	phy_unlock_mdio_bus(phydev);
16368c2ecf20Sopenharmony_ci
16378c2ecf20Sopenharmony_ci	ret = vsc8584_macsec_init(phydev);
16388c2ecf20Sopenharmony_ci	if (ret)
16398c2ecf20Sopenharmony_ci		return ret;
16408c2ecf20Sopenharmony_ci
16418c2ecf20Sopenharmony_ci	ret = vsc8584_ptp_init(phydev);
16428c2ecf20Sopenharmony_ci	if (ret)
16438c2ecf20Sopenharmony_ci		return ret;
16448c2ecf20Sopenharmony_ci
16458c2ecf20Sopenharmony_ci	val = phy_read(phydev, MSCC_PHY_EXT_PHY_CNTL_1);
16468c2ecf20Sopenharmony_ci	val &= ~(MEDIA_OP_MODE_MASK | VSC8584_MAC_IF_SELECTION_MASK);
16478c2ecf20Sopenharmony_ci	val |= (MEDIA_OP_MODE_COPPER << MEDIA_OP_MODE_POS) |
16488c2ecf20Sopenharmony_ci	       (VSC8584_MAC_IF_SELECTION_SGMII << VSC8584_MAC_IF_SELECTION_POS);
16498c2ecf20Sopenharmony_ci	ret = phy_write(phydev, MSCC_PHY_EXT_PHY_CNTL_1, val);
16508c2ecf20Sopenharmony_ci	if (ret)
16518c2ecf20Sopenharmony_ci		return ret;
16528c2ecf20Sopenharmony_ci
16538c2ecf20Sopenharmony_ci	ret = vsc85xx_update_rgmii_cntl(phydev, VSC8572_RGMII_CNTL,
16548c2ecf20Sopenharmony_ci					VSC8572_RGMII_RX_DELAY_MASK,
16558c2ecf20Sopenharmony_ci					VSC8572_RGMII_TX_DELAY_MASK);
16568c2ecf20Sopenharmony_ci	if (ret)
16578c2ecf20Sopenharmony_ci		return ret;
16588c2ecf20Sopenharmony_ci
16598c2ecf20Sopenharmony_ci	ret = genphy_soft_reset(phydev);
16608c2ecf20Sopenharmony_ci	if (ret)
16618c2ecf20Sopenharmony_ci		return ret;
16628c2ecf20Sopenharmony_ci
16638c2ecf20Sopenharmony_ci	for (i = 0; i < vsc8531->nleds; i++) {
16648c2ecf20Sopenharmony_ci		ret = vsc85xx_led_cntl_set(phydev, i, vsc8531->leds_mode[i]);
16658c2ecf20Sopenharmony_ci		if (ret)
16668c2ecf20Sopenharmony_ci			return ret;
16678c2ecf20Sopenharmony_ci	}
16688c2ecf20Sopenharmony_ci
16698c2ecf20Sopenharmony_ci	return 0;
16708c2ecf20Sopenharmony_ci
16718c2ecf20Sopenharmony_cierr:
16728c2ecf20Sopenharmony_ci	phy_unlock_mdio_bus(phydev);
16738c2ecf20Sopenharmony_ci	return ret;
16748c2ecf20Sopenharmony_ci}
16758c2ecf20Sopenharmony_ci
16768c2ecf20Sopenharmony_cistatic irqreturn_t vsc8584_handle_interrupt(struct phy_device *phydev)
16778c2ecf20Sopenharmony_ci{
16788c2ecf20Sopenharmony_ci	irqreturn_t ret;
16798c2ecf20Sopenharmony_ci	int irq_status;
16808c2ecf20Sopenharmony_ci
16818c2ecf20Sopenharmony_ci	irq_status = phy_read(phydev, MII_VSC85XX_INT_STATUS);
16828c2ecf20Sopenharmony_ci	if (irq_status < 0)
16838c2ecf20Sopenharmony_ci		return IRQ_NONE;
16848c2ecf20Sopenharmony_ci
16858c2ecf20Sopenharmony_ci	/* Timestamping IRQ does not set a bit in the global INT_STATUS, so
16868c2ecf20Sopenharmony_ci	 * irq_status would be 0.
16878c2ecf20Sopenharmony_ci	 */
16888c2ecf20Sopenharmony_ci	ret = vsc8584_handle_ts_interrupt(phydev);
16898c2ecf20Sopenharmony_ci	if (!(irq_status & MII_VSC85XX_INT_MASK_MASK))
16908c2ecf20Sopenharmony_ci		return ret;
16918c2ecf20Sopenharmony_ci
16928c2ecf20Sopenharmony_ci	if (irq_status & MII_VSC85XX_INT_MASK_EXT)
16938c2ecf20Sopenharmony_ci		vsc8584_handle_macsec_interrupt(phydev);
16948c2ecf20Sopenharmony_ci
16958c2ecf20Sopenharmony_ci	if (irq_status & MII_VSC85XX_INT_MASK_LINK_CHG)
16968c2ecf20Sopenharmony_ci		phy_mac_interrupt(phydev);
16978c2ecf20Sopenharmony_ci
16988c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
16998c2ecf20Sopenharmony_ci}
17008c2ecf20Sopenharmony_ci
17018c2ecf20Sopenharmony_cistatic int vsc85xx_config_init(struct phy_device *phydev)
17028c2ecf20Sopenharmony_ci{
17038c2ecf20Sopenharmony_ci	int rc, i, phy_id;
17048c2ecf20Sopenharmony_ci	struct vsc8531_private *vsc8531 = phydev->priv;
17058c2ecf20Sopenharmony_ci
17068c2ecf20Sopenharmony_ci	rc = vsc85xx_default_config(phydev);
17078c2ecf20Sopenharmony_ci	if (rc)
17088c2ecf20Sopenharmony_ci		return rc;
17098c2ecf20Sopenharmony_ci
17108c2ecf20Sopenharmony_ci	rc = vsc85xx_mac_if_set(phydev, phydev->interface);
17118c2ecf20Sopenharmony_ci	if (rc)
17128c2ecf20Sopenharmony_ci		return rc;
17138c2ecf20Sopenharmony_ci
17148c2ecf20Sopenharmony_ci	rc = vsc85xx_edge_rate_cntl_set(phydev, vsc8531->rate_magic);
17158c2ecf20Sopenharmony_ci	if (rc)
17168c2ecf20Sopenharmony_ci		return rc;
17178c2ecf20Sopenharmony_ci
17188c2ecf20Sopenharmony_ci	phy_id = phydev->drv->phy_id & phydev->drv->phy_id_mask;
17198c2ecf20Sopenharmony_ci	if (PHY_ID_VSC8531 == phy_id || PHY_ID_VSC8541 == phy_id ||
17208c2ecf20Sopenharmony_ci	    PHY_ID_VSC8530 == phy_id || PHY_ID_VSC8540 == phy_id) {
17218c2ecf20Sopenharmony_ci		rc = vsc8531_pre_init_seq_set(phydev);
17228c2ecf20Sopenharmony_ci		if (rc)
17238c2ecf20Sopenharmony_ci			return rc;
17248c2ecf20Sopenharmony_ci	}
17258c2ecf20Sopenharmony_ci
17268c2ecf20Sopenharmony_ci	rc = vsc85xx_eee_init_seq_set(phydev);
17278c2ecf20Sopenharmony_ci	if (rc)
17288c2ecf20Sopenharmony_ci		return rc;
17298c2ecf20Sopenharmony_ci
17308c2ecf20Sopenharmony_ci	for (i = 0; i < vsc8531->nleds; i++) {
17318c2ecf20Sopenharmony_ci		rc = vsc85xx_led_cntl_set(phydev, i, vsc8531->leds_mode[i]);
17328c2ecf20Sopenharmony_ci		if (rc)
17338c2ecf20Sopenharmony_ci			return rc;
17348c2ecf20Sopenharmony_ci	}
17358c2ecf20Sopenharmony_ci
17368c2ecf20Sopenharmony_ci	return 0;
17378c2ecf20Sopenharmony_ci}
17388c2ecf20Sopenharmony_ci
17398c2ecf20Sopenharmony_cistatic int vsc8584_did_interrupt(struct phy_device *phydev)
17408c2ecf20Sopenharmony_ci{
17418c2ecf20Sopenharmony_ci	int rc = 0;
17428c2ecf20Sopenharmony_ci
17438c2ecf20Sopenharmony_ci	if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
17448c2ecf20Sopenharmony_ci		rc = phy_read(phydev, MII_VSC85XX_INT_STATUS);
17458c2ecf20Sopenharmony_ci
17468c2ecf20Sopenharmony_ci	return (rc < 0) ? 0 : rc & MII_VSC85XX_INT_MASK_MASK;
17478c2ecf20Sopenharmony_ci}
17488c2ecf20Sopenharmony_ci
17498c2ecf20Sopenharmony_cistatic int vsc8514_config_pre_init(struct phy_device *phydev)
17508c2ecf20Sopenharmony_ci{
17518c2ecf20Sopenharmony_ci	/* These are the settings to override the silicon default
17528c2ecf20Sopenharmony_ci	 * values to handle hardware performance of PHY. They
17538c2ecf20Sopenharmony_ci	 * are set at Power-On state and remain until PHY Reset.
17548c2ecf20Sopenharmony_ci	 */
17558c2ecf20Sopenharmony_ci	static const struct reg_val pre_init1[] = {
17568c2ecf20Sopenharmony_ci		{0x0f90, 0x00688980},
17578c2ecf20Sopenharmony_ci		{0x0786, 0x00000003},
17588c2ecf20Sopenharmony_ci		{0x07fa, 0x0050100f},
17598c2ecf20Sopenharmony_ci		{0x0f82, 0x0012b002},
17608c2ecf20Sopenharmony_ci		{0x1686, 0x00000004},
17618c2ecf20Sopenharmony_ci		{0x168c, 0x00d2c46f},
17628c2ecf20Sopenharmony_ci		{0x17a2, 0x00000620},
17638c2ecf20Sopenharmony_ci		{0x16a0, 0x00eeffdd},
17648c2ecf20Sopenharmony_ci		{0x16a6, 0x00071448},
17658c2ecf20Sopenharmony_ci		{0x16a4, 0x0013132f},
17668c2ecf20Sopenharmony_ci		{0x16a8, 0x00000000},
17678c2ecf20Sopenharmony_ci		{0x0ffc, 0x00c0a028},
17688c2ecf20Sopenharmony_ci		{0x0fe8, 0x0091b06c},
17698c2ecf20Sopenharmony_ci		{0x0fea, 0x00041600},
17708c2ecf20Sopenharmony_ci		{0x0f80, 0x00fffaff},
17718c2ecf20Sopenharmony_ci		{0x0fec, 0x00901809},
17728c2ecf20Sopenharmony_ci		{0x0ffe, 0x00b01007},
17738c2ecf20Sopenharmony_ci		{0x16b0, 0x00eeff00},
17748c2ecf20Sopenharmony_ci		{0x16b2, 0x00007000},
17758c2ecf20Sopenharmony_ci		{0x16b4, 0x00000814},
17768c2ecf20Sopenharmony_ci	};
17778c2ecf20Sopenharmony_ci	struct device *dev = &phydev->mdio.dev;
17788c2ecf20Sopenharmony_ci	unsigned int i;
17798c2ecf20Sopenharmony_ci	u16 reg;
17808c2ecf20Sopenharmony_ci	int ret;
17818c2ecf20Sopenharmony_ci
17828c2ecf20Sopenharmony_ci	ret = vsc8584_pll5g_reset(phydev);
17838c2ecf20Sopenharmony_ci	if (ret < 0) {
17848c2ecf20Sopenharmony_ci		dev_err(dev, "failed LCPLL reset, ret: %d\n", ret);
17858c2ecf20Sopenharmony_ci		return ret;
17868c2ecf20Sopenharmony_ci	}
17878c2ecf20Sopenharmony_ci
17888c2ecf20Sopenharmony_ci	phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);
17898c2ecf20Sopenharmony_ci
17908c2ecf20Sopenharmony_ci	/* all writes below are broadcasted to all PHYs in the same package */
17918c2ecf20Sopenharmony_ci	reg = phy_base_read(phydev, MSCC_PHY_EXT_CNTL_STATUS);
17928c2ecf20Sopenharmony_ci	reg |= SMI_BROADCAST_WR_EN;
17938c2ecf20Sopenharmony_ci	phy_base_write(phydev, MSCC_PHY_EXT_CNTL_STATUS, reg);
17948c2ecf20Sopenharmony_ci
17958c2ecf20Sopenharmony_ci	phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_TEST);
17968c2ecf20Sopenharmony_ci
17978c2ecf20Sopenharmony_ci	reg = phy_base_read(phydev, MSCC_PHY_TEST_PAGE_8);
17988c2ecf20Sopenharmony_ci	reg |= BIT(15);
17998c2ecf20Sopenharmony_ci	phy_base_write(phydev, MSCC_PHY_TEST_PAGE_8, reg);
18008c2ecf20Sopenharmony_ci
18018c2ecf20Sopenharmony_ci	phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_TR);
18028c2ecf20Sopenharmony_ci
18038c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(pre_init1); i++)
18048c2ecf20Sopenharmony_ci		vsc8584_csr_write(phydev, pre_init1[i].reg, pre_init1[i].val);
18058c2ecf20Sopenharmony_ci
18068c2ecf20Sopenharmony_ci	phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_TEST);
18078c2ecf20Sopenharmony_ci
18088c2ecf20Sopenharmony_ci	reg = phy_base_read(phydev, MSCC_PHY_TEST_PAGE_8);
18098c2ecf20Sopenharmony_ci	reg &= ~BIT(15);
18108c2ecf20Sopenharmony_ci	phy_base_write(phydev, MSCC_PHY_TEST_PAGE_8, reg);
18118c2ecf20Sopenharmony_ci
18128c2ecf20Sopenharmony_ci	phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);
18138c2ecf20Sopenharmony_ci
18148c2ecf20Sopenharmony_ci	reg = phy_base_read(phydev, MSCC_PHY_EXT_CNTL_STATUS);
18158c2ecf20Sopenharmony_ci	reg &= ~SMI_BROADCAST_WR_EN;
18168c2ecf20Sopenharmony_ci	phy_base_write(phydev, MSCC_PHY_EXT_CNTL_STATUS, reg);
18178c2ecf20Sopenharmony_ci
18188c2ecf20Sopenharmony_ci	return 0;
18198c2ecf20Sopenharmony_ci}
18208c2ecf20Sopenharmony_ci
18218c2ecf20Sopenharmony_cistatic int __phy_write_mcb_s6g(struct phy_device *phydev, u32 reg, u8 mcb,
18228c2ecf20Sopenharmony_ci			       u32 op)
18238c2ecf20Sopenharmony_ci{
18248c2ecf20Sopenharmony_ci	unsigned long deadline;
18258c2ecf20Sopenharmony_ci	u32 val;
18268c2ecf20Sopenharmony_ci	int ret;
18278c2ecf20Sopenharmony_ci
18288c2ecf20Sopenharmony_ci	ret = vsc85xx_csr_write(phydev, PHY_MCB_TARGET, reg,
18298c2ecf20Sopenharmony_ci				op | (1 << mcb));
18308c2ecf20Sopenharmony_ci	if (ret)
18318c2ecf20Sopenharmony_ci		return -EINVAL;
18328c2ecf20Sopenharmony_ci
18338c2ecf20Sopenharmony_ci	deadline = jiffies + msecs_to_jiffies(PROC_CMD_NCOMPLETED_TIMEOUT_MS);
18348c2ecf20Sopenharmony_ci	do {
18358c2ecf20Sopenharmony_ci		usleep_range(500, 1000);
18368c2ecf20Sopenharmony_ci		val = vsc85xx_csr_read(phydev, PHY_MCB_TARGET, reg);
18378c2ecf20Sopenharmony_ci
18388c2ecf20Sopenharmony_ci		if (val == 0xffffffff)
18398c2ecf20Sopenharmony_ci			return -EIO;
18408c2ecf20Sopenharmony_ci
18418c2ecf20Sopenharmony_ci	} while (time_before(jiffies, deadline) && (val & op));
18428c2ecf20Sopenharmony_ci
18438c2ecf20Sopenharmony_ci	if (val & op)
18448c2ecf20Sopenharmony_ci		return -ETIMEDOUT;
18458c2ecf20Sopenharmony_ci
18468c2ecf20Sopenharmony_ci	return 0;
18478c2ecf20Sopenharmony_ci}
18488c2ecf20Sopenharmony_ci
18498c2ecf20Sopenharmony_ci/* Trigger a read to the specified MCB */
18508c2ecf20Sopenharmony_cistatic int phy_update_mcb_s6g(struct phy_device *phydev, u32 reg, u8 mcb)
18518c2ecf20Sopenharmony_ci{
18528c2ecf20Sopenharmony_ci	return __phy_write_mcb_s6g(phydev, reg, mcb, PHY_MCB_S6G_READ);
18538c2ecf20Sopenharmony_ci}
18548c2ecf20Sopenharmony_ci
18558c2ecf20Sopenharmony_ci/* Trigger a write to the specified MCB */
18568c2ecf20Sopenharmony_cistatic int phy_commit_mcb_s6g(struct phy_device *phydev, u32 reg, u8 mcb)
18578c2ecf20Sopenharmony_ci{
18588c2ecf20Sopenharmony_ci	return __phy_write_mcb_s6g(phydev, reg, mcb, PHY_MCB_S6G_WRITE);
18598c2ecf20Sopenharmony_ci}
18608c2ecf20Sopenharmony_ci
18618c2ecf20Sopenharmony_cistatic int vsc8514_config_init(struct phy_device *phydev)
18628c2ecf20Sopenharmony_ci{
18638c2ecf20Sopenharmony_ci	struct vsc8531_private *vsc8531 = phydev->priv;
18648c2ecf20Sopenharmony_ci	unsigned long deadline;
18658c2ecf20Sopenharmony_ci	int ret, i;
18668c2ecf20Sopenharmony_ci	u16 val;
18678c2ecf20Sopenharmony_ci	u32 reg;
18688c2ecf20Sopenharmony_ci
18698c2ecf20Sopenharmony_ci	phydev->mdix_ctrl = ETH_TP_MDI_AUTO;
18708c2ecf20Sopenharmony_ci
18718c2ecf20Sopenharmony_ci	phy_lock_mdio_bus(phydev);
18728c2ecf20Sopenharmony_ci
18738c2ecf20Sopenharmony_ci	/* Some parts of the init sequence are identical for every PHY in the
18748c2ecf20Sopenharmony_ci	 * package. Some parts are modifying the GPIO register bank which is a
18758c2ecf20Sopenharmony_ci	 * set of registers that are affecting all PHYs, a few resetting the
18768c2ecf20Sopenharmony_ci	 * microprocessor common to all PHYs.
18778c2ecf20Sopenharmony_ci	 * All PHYs' interrupts mask register has to be zeroed before enabling
18788c2ecf20Sopenharmony_ci	 * any PHY's interrupt in this register.
18798c2ecf20Sopenharmony_ci	 * For all these reasons, we need to do the init sequence once and only
18808c2ecf20Sopenharmony_ci	 * once whatever is the first PHY in the package that is initialized and
18818c2ecf20Sopenharmony_ci	 * do the correct init sequence for all PHYs that are package-critical
18828c2ecf20Sopenharmony_ci	 * in this pre-init function.
18838c2ecf20Sopenharmony_ci	 */
18848c2ecf20Sopenharmony_ci	if (phy_package_init_once(phydev))
18858c2ecf20Sopenharmony_ci		vsc8514_config_pre_init(phydev);
18868c2ecf20Sopenharmony_ci
18878c2ecf20Sopenharmony_ci	ret = phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS,
18888c2ecf20Sopenharmony_ci			     MSCC_PHY_PAGE_EXTENDED_GPIO);
18898c2ecf20Sopenharmony_ci	if (ret)
18908c2ecf20Sopenharmony_ci		goto err;
18918c2ecf20Sopenharmony_ci
18928c2ecf20Sopenharmony_ci	val = phy_base_read(phydev, MSCC_PHY_MAC_CFG_FASTLINK);
18938c2ecf20Sopenharmony_ci
18948c2ecf20Sopenharmony_ci	val &= ~MAC_CFG_MASK;
18958c2ecf20Sopenharmony_ci	val |= MAC_CFG_QSGMII;
18968c2ecf20Sopenharmony_ci	ret = phy_base_write(phydev, MSCC_PHY_MAC_CFG_FASTLINK, val);
18978c2ecf20Sopenharmony_ci	if (ret)
18988c2ecf20Sopenharmony_ci		goto err;
18998c2ecf20Sopenharmony_ci
19008c2ecf20Sopenharmony_ci	ret = phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS,
19018c2ecf20Sopenharmony_ci			     MSCC_PHY_PAGE_STANDARD);
19028c2ecf20Sopenharmony_ci	if (ret)
19038c2ecf20Sopenharmony_ci		goto err;
19048c2ecf20Sopenharmony_ci
19058c2ecf20Sopenharmony_ci	ret = vsc8584_cmd(phydev,
19068c2ecf20Sopenharmony_ci			  PROC_CMD_MCB_ACCESS_MAC_CONF |
19078c2ecf20Sopenharmony_ci			  PROC_CMD_RST_CONF_PORT |
19088c2ecf20Sopenharmony_ci			  PROC_CMD_READ_MOD_WRITE_PORT | PROC_CMD_QSGMII_MAC);
19098c2ecf20Sopenharmony_ci	if (ret)
19108c2ecf20Sopenharmony_ci		goto err;
19118c2ecf20Sopenharmony_ci
19128c2ecf20Sopenharmony_ci	/* 6g mcb */
19138c2ecf20Sopenharmony_ci	phy_update_mcb_s6g(phydev, PHY_MCB_S6G_CFG, 0);
19148c2ecf20Sopenharmony_ci	/* lcpll mcb */
19158c2ecf20Sopenharmony_ci	phy_update_mcb_s6g(phydev, PHY_S6G_LCPLL_CFG, 0);
19168c2ecf20Sopenharmony_ci	/* pll5gcfg0 */
19178c2ecf20Sopenharmony_ci	ret = vsc85xx_csr_write(phydev, PHY_MCB_TARGET,
19188c2ecf20Sopenharmony_ci				PHY_S6G_PLL5G_CFG0, 0x7036f145);
19198c2ecf20Sopenharmony_ci	if (ret)
19208c2ecf20Sopenharmony_ci		goto err;
19218c2ecf20Sopenharmony_ci
19228c2ecf20Sopenharmony_ci	phy_commit_mcb_s6g(phydev, PHY_S6G_LCPLL_CFG, 0);
19238c2ecf20Sopenharmony_ci	/* pllcfg */
19248c2ecf20Sopenharmony_ci	ret = vsc85xx_csr_write(phydev, PHY_MCB_TARGET,
19258c2ecf20Sopenharmony_ci				PHY_S6G_PLL_CFG,
19268c2ecf20Sopenharmony_ci				(3 << PHY_S6G_PLL_ENA_OFFS_POS) |
19278c2ecf20Sopenharmony_ci				(120 << PHY_S6G_PLL_FSM_CTRL_DATA_POS)
19288c2ecf20Sopenharmony_ci				| (0 << PHY_S6G_PLL_FSM_ENA_POS));
19298c2ecf20Sopenharmony_ci	if (ret)
19308c2ecf20Sopenharmony_ci		goto err;
19318c2ecf20Sopenharmony_ci
19328c2ecf20Sopenharmony_ci	/* commoncfg */
19338c2ecf20Sopenharmony_ci	ret = vsc85xx_csr_write(phydev, PHY_MCB_TARGET,
19348c2ecf20Sopenharmony_ci				PHY_S6G_COMMON_CFG,
19358c2ecf20Sopenharmony_ci				(0 << PHY_S6G_SYS_RST_POS) |
19368c2ecf20Sopenharmony_ci				(0 << PHY_S6G_ENA_LANE_POS) |
19378c2ecf20Sopenharmony_ci				(0 << PHY_S6G_ENA_LOOP_POS) |
19388c2ecf20Sopenharmony_ci				(0 << PHY_S6G_QRATE_POS) |
19398c2ecf20Sopenharmony_ci				(3 << PHY_S6G_IF_MODE_POS));
19408c2ecf20Sopenharmony_ci	if (ret)
19418c2ecf20Sopenharmony_ci		goto err;
19428c2ecf20Sopenharmony_ci
19438c2ecf20Sopenharmony_ci	/* misccfg */
19448c2ecf20Sopenharmony_ci	ret = vsc85xx_csr_write(phydev, PHY_MCB_TARGET,
19458c2ecf20Sopenharmony_ci				PHY_S6G_MISC_CFG, 1);
19468c2ecf20Sopenharmony_ci	if (ret)
19478c2ecf20Sopenharmony_ci		goto err;
19488c2ecf20Sopenharmony_ci
19498c2ecf20Sopenharmony_ci	/* gpcfg */
19508c2ecf20Sopenharmony_ci	ret = vsc85xx_csr_write(phydev, PHY_MCB_TARGET,
19518c2ecf20Sopenharmony_ci				PHY_S6G_GPC_CFG, 768);
19528c2ecf20Sopenharmony_ci	if (ret)
19538c2ecf20Sopenharmony_ci		goto err;
19548c2ecf20Sopenharmony_ci
19558c2ecf20Sopenharmony_ci	phy_commit_mcb_s6g(phydev, PHY_S6G_DFT_CFG2, 0);
19568c2ecf20Sopenharmony_ci
19578c2ecf20Sopenharmony_ci	deadline = jiffies + msecs_to_jiffies(PROC_CMD_NCOMPLETED_TIMEOUT_MS);
19588c2ecf20Sopenharmony_ci	do {
19598c2ecf20Sopenharmony_ci		usleep_range(500, 1000);
19608c2ecf20Sopenharmony_ci		phy_update_mcb_s6g(phydev, PHY_MCB_S6G_CFG,
19618c2ecf20Sopenharmony_ci				   0); /* read 6G MCB into CSRs */
19628c2ecf20Sopenharmony_ci		reg = vsc85xx_csr_read(phydev, PHY_MCB_TARGET,
19638c2ecf20Sopenharmony_ci				       PHY_S6G_PLL_STATUS);
19648c2ecf20Sopenharmony_ci		if (reg == 0xffffffff) {
19658c2ecf20Sopenharmony_ci			phy_unlock_mdio_bus(phydev);
19668c2ecf20Sopenharmony_ci			return -EIO;
19678c2ecf20Sopenharmony_ci		}
19688c2ecf20Sopenharmony_ci
19698c2ecf20Sopenharmony_ci	} while (time_before(jiffies, deadline) && (reg & BIT(12)));
19708c2ecf20Sopenharmony_ci
19718c2ecf20Sopenharmony_ci	if (reg & BIT(12)) {
19728c2ecf20Sopenharmony_ci		phy_unlock_mdio_bus(phydev);
19738c2ecf20Sopenharmony_ci		return -ETIMEDOUT;
19748c2ecf20Sopenharmony_ci	}
19758c2ecf20Sopenharmony_ci
19768c2ecf20Sopenharmony_ci	/* misccfg */
19778c2ecf20Sopenharmony_ci	ret = vsc85xx_csr_write(phydev, PHY_MCB_TARGET,
19788c2ecf20Sopenharmony_ci				PHY_S6G_MISC_CFG, 0);
19798c2ecf20Sopenharmony_ci	if (ret)
19808c2ecf20Sopenharmony_ci		goto err;
19818c2ecf20Sopenharmony_ci
19828c2ecf20Sopenharmony_ci	phy_commit_mcb_s6g(phydev, PHY_MCB_S6G_CFG, 0);
19838c2ecf20Sopenharmony_ci
19848c2ecf20Sopenharmony_ci	deadline = jiffies + msecs_to_jiffies(PROC_CMD_NCOMPLETED_TIMEOUT_MS);
19858c2ecf20Sopenharmony_ci	do {
19868c2ecf20Sopenharmony_ci		usleep_range(500, 1000);
19878c2ecf20Sopenharmony_ci		phy_update_mcb_s6g(phydev, PHY_MCB_S6G_CFG,
19888c2ecf20Sopenharmony_ci				   0); /* read 6G MCB into CSRs */
19898c2ecf20Sopenharmony_ci		reg = vsc85xx_csr_read(phydev, PHY_MCB_TARGET,
19908c2ecf20Sopenharmony_ci				       PHY_S6G_IB_STATUS0);
19918c2ecf20Sopenharmony_ci		if (reg == 0xffffffff) {
19928c2ecf20Sopenharmony_ci			phy_unlock_mdio_bus(phydev);
19938c2ecf20Sopenharmony_ci			return -EIO;
19948c2ecf20Sopenharmony_ci		}
19958c2ecf20Sopenharmony_ci
19968c2ecf20Sopenharmony_ci	} while (time_before(jiffies, deadline) && !(reg & BIT(8)));
19978c2ecf20Sopenharmony_ci
19988c2ecf20Sopenharmony_ci	if (!(reg & BIT(8))) {
19998c2ecf20Sopenharmony_ci		phy_unlock_mdio_bus(phydev);
20008c2ecf20Sopenharmony_ci		return -ETIMEDOUT;
20018c2ecf20Sopenharmony_ci	}
20028c2ecf20Sopenharmony_ci
20038c2ecf20Sopenharmony_ci	phy_unlock_mdio_bus(phydev);
20048c2ecf20Sopenharmony_ci
20058c2ecf20Sopenharmony_ci	ret = phy_modify(phydev, MSCC_PHY_EXT_PHY_CNTL_1, MEDIA_OP_MODE_MASK,
20068c2ecf20Sopenharmony_ci			 MEDIA_OP_MODE_COPPER << MEDIA_OP_MODE_POS);
20078c2ecf20Sopenharmony_ci
20088c2ecf20Sopenharmony_ci	if (ret)
20098c2ecf20Sopenharmony_ci		return ret;
20108c2ecf20Sopenharmony_ci
20118c2ecf20Sopenharmony_ci	ret = genphy_soft_reset(phydev);
20128c2ecf20Sopenharmony_ci
20138c2ecf20Sopenharmony_ci	if (ret)
20148c2ecf20Sopenharmony_ci		return ret;
20158c2ecf20Sopenharmony_ci
20168c2ecf20Sopenharmony_ci	for (i = 0; i < vsc8531->nleds; i++) {
20178c2ecf20Sopenharmony_ci		ret = vsc85xx_led_cntl_set(phydev, i, vsc8531->leds_mode[i]);
20188c2ecf20Sopenharmony_ci		if (ret)
20198c2ecf20Sopenharmony_ci			return ret;
20208c2ecf20Sopenharmony_ci	}
20218c2ecf20Sopenharmony_ci
20228c2ecf20Sopenharmony_ci	return ret;
20238c2ecf20Sopenharmony_ci
20248c2ecf20Sopenharmony_cierr:
20258c2ecf20Sopenharmony_ci	phy_unlock_mdio_bus(phydev);
20268c2ecf20Sopenharmony_ci	return ret;
20278c2ecf20Sopenharmony_ci}
20288c2ecf20Sopenharmony_ci
20298c2ecf20Sopenharmony_cistatic int vsc85xx_ack_interrupt(struct phy_device *phydev)
20308c2ecf20Sopenharmony_ci{
20318c2ecf20Sopenharmony_ci	int rc = 0;
20328c2ecf20Sopenharmony_ci
20338c2ecf20Sopenharmony_ci	if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
20348c2ecf20Sopenharmony_ci		rc = phy_read(phydev, MII_VSC85XX_INT_STATUS);
20358c2ecf20Sopenharmony_ci
20368c2ecf20Sopenharmony_ci	return (rc < 0) ? rc : 0;
20378c2ecf20Sopenharmony_ci}
20388c2ecf20Sopenharmony_ci
20398c2ecf20Sopenharmony_cistatic int vsc85xx_config_intr(struct phy_device *phydev)
20408c2ecf20Sopenharmony_ci{
20418c2ecf20Sopenharmony_ci	int rc;
20428c2ecf20Sopenharmony_ci
20438c2ecf20Sopenharmony_ci	if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
20448c2ecf20Sopenharmony_ci		vsc8584_config_macsec_intr(phydev);
20458c2ecf20Sopenharmony_ci		vsc8584_config_ts_intr(phydev);
20468c2ecf20Sopenharmony_ci
20478c2ecf20Sopenharmony_ci		rc = phy_write(phydev, MII_VSC85XX_INT_MASK,
20488c2ecf20Sopenharmony_ci			       MII_VSC85XX_INT_MASK_MASK);
20498c2ecf20Sopenharmony_ci	} else {
20508c2ecf20Sopenharmony_ci		rc = phy_write(phydev, MII_VSC85XX_INT_MASK, 0);
20518c2ecf20Sopenharmony_ci		if (rc < 0)
20528c2ecf20Sopenharmony_ci			return rc;
20538c2ecf20Sopenharmony_ci		rc = phy_read(phydev, MII_VSC85XX_INT_STATUS);
20548c2ecf20Sopenharmony_ci	}
20558c2ecf20Sopenharmony_ci
20568c2ecf20Sopenharmony_ci	return rc;
20578c2ecf20Sopenharmony_ci}
20588c2ecf20Sopenharmony_ci
20598c2ecf20Sopenharmony_cistatic int vsc85xx_config_aneg(struct phy_device *phydev)
20608c2ecf20Sopenharmony_ci{
20618c2ecf20Sopenharmony_ci	int rc;
20628c2ecf20Sopenharmony_ci
20638c2ecf20Sopenharmony_ci	rc = vsc85xx_mdix_set(phydev, phydev->mdix_ctrl);
20648c2ecf20Sopenharmony_ci	if (rc < 0)
20658c2ecf20Sopenharmony_ci		return rc;
20668c2ecf20Sopenharmony_ci
20678c2ecf20Sopenharmony_ci	return genphy_config_aneg(phydev);
20688c2ecf20Sopenharmony_ci}
20698c2ecf20Sopenharmony_ci
20708c2ecf20Sopenharmony_cistatic int vsc85xx_read_status(struct phy_device *phydev)
20718c2ecf20Sopenharmony_ci{
20728c2ecf20Sopenharmony_ci	int rc;
20738c2ecf20Sopenharmony_ci
20748c2ecf20Sopenharmony_ci	rc = vsc85xx_mdix_get(phydev, &phydev->mdix);
20758c2ecf20Sopenharmony_ci	if (rc < 0)
20768c2ecf20Sopenharmony_ci		return rc;
20778c2ecf20Sopenharmony_ci
20788c2ecf20Sopenharmony_ci	return genphy_read_status(phydev);
20798c2ecf20Sopenharmony_ci}
20808c2ecf20Sopenharmony_ci
20818c2ecf20Sopenharmony_cistatic int vsc8514_probe(struct phy_device *phydev)
20828c2ecf20Sopenharmony_ci{
20838c2ecf20Sopenharmony_ci	struct vsc8531_private *vsc8531;
20848c2ecf20Sopenharmony_ci	u32 default_mode[4] = {VSC8531_LINK_1000_ACTIVITY,
20858c2ecf20Sopenharmony_ci	   VSC8531_LINK_100_ACTIVITY, VSC8531_LINK_ACTIVITY,
20868c2ecf20Sopenharmony_ci	   VSC8531_DUPLEX_COLLISION};
20878c2ecf20Sopenharmony_ci
20888c2ecf20Sopenharmony_ci	vsc8531 = devm_kzalloc(&phydev->mdio.dev, sizeof(*vsc8531), GFP_KERNEL);
20898c2ecf20Sopenharmony_ci	if (!vsc8531)
20908c2ecf20Sopenharmony_ci		return -ENOMEM;
20918c2ecf20Sopenharmony_ci
20928c2ecf20Sopenharmony_ci	phydev->priv = vsc8531;
20938c2ecf20Sopenharmony_ci
20948c2ecf20Sopenharmony_ci	vsc8584_get_base_addr(phydev);
20958c2ecf20Sopenharmony_ci	devm_phy_package_join(&phydev->mdio.dev, phydev,
20968c2ecf20Sopenharmony_ci			      vsc8531->base_addr, 0);
20978c2ecf20Sopenharmony_ci
20988c2ecf20Sopenharmony_ci	vsc8531->nleds = 4;
20998c2ecf20Sopenharmony_ci	vsc8531->supp_led_modes = VSC85XX_SUPP_LED_MODES;
21008c2ecf20Sopenharmony_ci	vsc8531->hw_stats = vsc85xx_hw_stats;
21018c2ecf20Sopenharmony_ci	vsc8531->nstats = ARRAY_SIZE(vsc85xx_hw_stats);
21028c2ecf20Sopenharmony_ci	vsc8531->stats = devm_kcalloc(&phydev->mdio.dev, vsc8531->nstats,
21038c2ecf20Sopenharmony_ci				      sizeof(u64), GFP_KERNEL);
21048c2ecf20Sopenharmony_ci	if (!vsc8531->stats)
21058c2ecf20Sopenharmony_ci		return -ENOMEM;
21068c2ecf20Sopenharmony_ci
21078c2ecf20Sopenharmony_ci	return vsc85xx_dt_led_modes_get(phydev, default_mode);
21088c2ecf20Sopenharmony_ci}
21098c2ecf20Sopenharmony_ci
21108c2ecf20Sopenharmony_cistatic int vsc8574_probe(struct phy_device *phydev)
21118c2ecf20Sopenharmony_ci{
21128c2ecf20Sopenharmony_ci	struct vsc8531_private *vsc8531;
21138c2ecf20Sopenharmony_ci	u32 default_mode[4] = {VSC8531_LINK_1000_ACTIVITY,
21148c2ecf20Sopenharmony_ci	   VSC8531_LINK_100_ACTIVITY, VSC8531_LINK_ACTIVITY,
21158c2ecf20Sopenharmony_ci	   VSC8531_DUPLEX_COLLISION};
21168c2ecf20Sopenharmony_ci
21178c2ecf20Sopenharmony_ci	vsc8531 = devm_kzalloc(&phydev->mdio.dev, sizeof(*vsc8531), GFP_KERNEL);
21188c2ecf20Sopenharmony_ci	if (!vsc8531)
21198c2ecf20Sopenharmony_ci		return -ENOMEM;
21208c2ecf20Sopenharmony_ci
21218c2ecf20Sopenharmony_ci	phydev->priv = vsc8531;
21228c2ecf20Sopenharmony_ci
21238c2ecf20Sopenharmony_ci	vsc8584_get_base_addr(phydev);
21248c2ecf20Sopenharmony_ci	devm_phy_package_join(&phydev->mdio.dev, phydev,
21258c2ecf20Sopenharmony_ci			      vsc8531->base_addr, 0);
21268c2ecf20Sopenharmony_ci
21278c2ecf20Sopenharmony_ci	vsc8531->nleds = 4;
21288c2ecf20Sopenharmony_ci	vsc8531->supp_led_modes = VSC8584_SUPP_LED_MODES;
21298c2ecf20Sopenharmony_ci	vsc8531->hw_stats = vsc8584_hw_stats;
21308c2ecf20Sopenharmony_ci	vsc8531->nstats = ARRAY_SIZE(vsc8584_hw_stats);
21318c2ecf20Sopenharmony_ci	vsc8531->stats = devm_kcalloc(&phydev->mdio.dev, vsc8531->nstats,
21328c2ecf20Sopenharmony_ci				      sizeof(u64), GFP_KERNEL);
21338c2ecf20Sopenharmony_ci	if (!vsc8531->stats)
21348c2ecf20Sopenharmony_ci		return -ENOMEM;
21358c2ecf20Sopenharmony_ci
21368c2ecf20Sopenharmony_ci	return vsc85xx_dt_led_modes_get(phydev, default_mode);
21378c2ecf20Sopenharmony_ci}
21388c2ecf20Sopenharmony_ci
21398c2ecf20Sopenharmony_cistatic int vsc8584_probe(struct phy_device *phydev)
21408c2ecf20Sopenharmony_ci{
21418c2ecf20Sopenharmony_ci	struct vsc8531_private *vsc8531;
21428c2ecf20Sopenharmony_ci	u32 default_mode[4] = {VSC8531_LINK_1000_ACTIVITY,
21438c2ecf20Sopenharmony_ci	   VSC8531_LINK_100_ACTIVITY, VSC8531_LINK_ACTIVITY,
21448c2ecf20Sopenharmony_ci	   VSC8531_DUPLEX_COLLISION};
21458c2ecf20Sopenharmony_ci	int ret;
21468c2ecf20Sopenharmony_ci
21478c2ecf20Sopenharmony_ci	if ((phydev->phy_id & MSCC_DEV_REV_MASK) != VSC8584_REVB) {
21488c2ecf20Sopenharmony_ci		dev_err(&phydev->mdio.dev, "Only VSC8584 revB is supported.\n");
21498c2ecf20Sopenharmony_ci		return -ENOTSUPP;
21508c2ecf20Sopenharmony_ci	}
21518c2ecf20Sopenharmony_ci
21528c2ecf20Sopenharmony_ci	vsc8531 = devm_kzalloc(&phydev->mdio.dev, sizeof(*vsc8531), GFP_KERNEL);
21538c2ecf20Sopenharmony_ci	if (!vsc8531)
21548c2ecf20Sopenharmony_ci		return -ENOMEM;
21558c2ecf20Sopenharmony_ci
21568c2ecf20Sopenharmony_ci	phydev->priv = vsc8531;
21578c2ecf20Sopenharmony_ci
21588c2ecf20Sopenharmony_ci	vsc8584_get_base_addr(phydev);
21598c2ecf20Sopenharmony_ci	devm_phy_package_join(&phydev->mdio.dev, phydev, vsc8531->base_addr,
21608c2ecf20Sopenharmony_ci			      sizeof(struct vsc85xx_shared_private));
21618c2ecf20Sopenharmony_ci
21628c2ecf20Sopenharmony_ci	vsc8531->nleds = 4;
21638c2ecf20Sopenharmony_ci	vsc8531->supp_led_modes = VSC8584_SUPP_LED_MODES;
21648c2ecf20Sopenharmony_ci	vsc8531->hw_stats = vsc8584_hw_stats;
21658c2ecf20Sopenharmony_ci	vsc8531->nstats = ARRAY_SIZE(vsc8584_hw_stats);
21668c2ecf20Sopenharmony_ci	vsc8531->stats = devm_kcalloc(&phydev->mdio.dev, vsc8531->nstats,
21678c2ecf20Sopenharmony_ci				      sizeof(u64), GFP_KERNEL);
21688c2ecf20Sopenharmony_ci	if (!vsc8531->stats)
21698c2ecf20Sopenharmony_ci		return -ENOMEM;
21708c2ecf20Sopenharmony_ci
21718c2ecf20Sopenharmony_ci	if (phy_package_probe_once(phydev)) {
21728c2ecf20Sopenharmony_ci		ret = vsc8584_ptp_probe_once(phydev);
21738c2ecf20Sopenharmony_ci		if (ret)
21748c2ecf20Sopenharmony_ci			return ret;
21758c2ecf20Sopenharmony_ci	}
21768c2ecf20Sopenharmony_ci
21778c2ecf20Sopenharmony_ci	ret = vsc8584_ptp_probe(phydev);
21788c2ecf20Sopenharmony_ci	if (ret)
21798c2ecf20Sopenharmony_ci		return ret;
21808c2ecf20Sopenharmony_ci
21818c2ecf20Sopenharmony_ci	return vsc85xx_dt_led_modes_get(phydev, default_mode);
21828c2ecf20Sopenharmony_ci}
21838c2ecf20Sopenharmony_ci
21848c2ecf20Sopenharmony_cistatic int vsc85xx_probe(struct phy_device *phydev)
21858c2ecf20Sopenharmony_ci{
21868c2ecf20Sopenharmony_ci	struct vsc8531_private *vsc8531;
21878c2ecf20Sopenharmony_ci	int rate_magic;
21888c2ecf20Sopenharmony_ci	u32 default_mode[2] = {VSC8531_LINK_1000_ACTIVITY,
21898c2ecf20Sopenharmony_ci	   VSC8531_LINK_100_ACTIVITY};
21908c2ecf20Sopenharmony_ci
21918c2ecf20Sopenharmony_ci	rate_magic = vsc85xx_edge_rate_magic_get(phydev);
21928c2ecf20Sopenharmony_ci	if (rate_magic < 0)
21938c2ecf20Sopenharmony_ci		return rate_magic;
21948c2ecf20Sopenharmony_ci
21958c2ecf20Sopenharmony_ci	vsc8531 = devm_kzalloc(&phydev->mdio.dev, sizeof(*vsc8531), GFP_KERNEL);
21968c2ecf20Sopenharmony_ci	if (!vsc8531)
21978c2ecf20Sopenharmony_ci		return -ENOMEM;
21988c2ecf20Sopenharmony_ci
21998c2ecf20Sopenharmony_ci	phydev->priv = vsc8531;
22008c2ecf20Sopenharmony_ci
22018c2ecf20Sopenharmony_ci	vsc8531->rate_magic = rate_magic;
22028c2ecf20Sopenharmony_ci	vsc8531->nleds = 2;
22038c2ecf20Sopenharmony_ci	vsc8531->supp_led_modes = VSC85XX_SUPP_LED_MODES;
22048c2ecf20Sopenharmony_ci	vsc8531->hw_stats = vsc85xx_hw_stats;
22058c2ecf20Sopenharmony_ci	vsc8531->nstats = ARRAY_SIZE(vsc85xx_hw_stats);
22068c2ecf20Sopenharmony_ci	vsc8531->stats = devm_kcalloc(&phydev->mdio.dev, vsc8531->nstats,
22078c2ecf20Sopenharmony_ci				      sizeof(u64), GFP_KERNEL);
22088c2ecf20Sopenharmony_ci	if (!vsc8531->stats)
22098c2ecf20Sopenharmony_ci		return -ENOMEM;
22108c2ecf20Sopenharmony_ci
22118c2ecf20Sopenharmony_ci	return vsc85xx_dt_led_modes_get(phydev, default_mode);
22128c2ecf20Sopenharmony_ci}
22138c2ecf20Sopenharmony_ci
22148c2ecf20Sopenharmony_ci/* Microsemi VSC85xx PHYs */
22158c2ecf20Sopenharmony_cistatic struct phy_driver vsc85xx_driver[] = {
22168c2ecf20Sopenharmony_ci{
22178c2ecf20Sopenharmony_ci	.phy_id		= PHY_ID_VSC8502,
22188c2ecf20Sopenharmony_ci	.name		= "Microsemi GE VSC8502 SyncE",
22198c2ecf20Sopenharmony_ci	.phy_id_mask	= 0xfffffff0,
22208c2ecf20Sopenharmony_ci	/* PHY_BASIC_FEATURES */
22218c2ecf20Sopenharmony_ci	.soft_reset	= &genphy_soft_reset,
22228c2ecf20Sopenharmony_ci	.config_init	= &vsc85xx_config_init,
22238c2ecf20Sopenharmony_ci	.config_aneg    = &vsc85xx_config_aneg,
22248c2ecf20Sopenharmony_ci	.read_status	= &vsc85xx_read_status,
22258c2ecf20Sopenharmony_ci	.ack_interrupt	= &vsc85xx_ack_interrupt,
22268c2ecf20Sopenharmony_ci	.config_intr	= &vsc85xx_config_intr,
22278c2ecf20Sopenharmony_ci	.suspend	= &genphy_suspend,
22288c2ecf20Sopenharmony_ci	.resume		= &genphy_resume,
22298c2ecf20Sopenharmony_ci	.probe		= &vsc85xx_probe,
22308c2ecf20Sopenharmony_ci	.set_wol	= &vsc85xx_wol_set,
22318c2ecf20Sopenharmony_ci	.get_wol	= &vsc85xx_wol_get,
22328c2ecf20Sopenharmony_ci	.get_tunable	= &vsc85xx_get_tunable,
22338c2ecf20Sopenharmony_ci	.set_tunable	= &vsc85xx_set_tunable,
22348c2ecf20Sopenharmony_ci	.read_page	= &vsc85xx_phy_read_page,
22358c2ecf20Sopenharmony_ci	.write_page	= &vsc85xx_phy_write_page,
22368c2ecf20Sopenharmony_ci	.get_sset_count = &vsc85xx_get_sset_count,
22378c2ecf20Sopenharmony_ci	.get_strings    = &vsc85xx_get_strings,
22388c2ecf20Sopenharmony_ci	.get_stats      = &vsc85xx_get_stats,
22398c2ecf20Sopenharmony_ci},
22408c2ecf20Sopenharmony_ci{
22418c2ecf20Sopenharmony_ci	.phy_id		= PHY_ID_VSC8504,
22428c2ecf20Sopenharmony_ci	.name		= "Microsemi GE VSC8504 SyncE",
22438c2ecf20Sopenharmony_ci	.phy_id_mask	= 0xfffffff0,
22448c2ecf20Sopenharmony_ci	/* PHY_GBIT_FEATURES */
22458c2ecf20Sopenharmony_ci	.soft_reset	= &genphy_soft_reset,
22468c2ecf20Sopenharmony_ci	.config_init    = &vsc8584_config_init,
22478c2ecf20Sopenharmony_ci	.config_aneg    = &vsc85xx_config_aneg,
22488c2ecf20Sopenharmony_ci	.aneg_done	= &genphy_aneg_done,
22498c2ecf20Sopenharmony_ci	.read_status	= &vsc85xx_read_status,
22508c2ecf20Sopenharmony_ci	.ack_interrupt  = &vsc85xx_ack_interrupt,
22518c2ecf20Sopenharmony_ci	.config_intr    = &vsc85xx_config_intr,
22528c2ecf20Sopenharmony_ci	.did_interrupt  = &vsc8584_did_interrupt,
22538c2ecf20Sopenharmony_ci	.suspend	= &genphy_suspend,
22548c2ecf20Sopenharmony_ci	.resume		= &genphy_resume,
22558c2ecf20Sopenharmony_ci	.probe		= &vsc8574_probe,
22568c2ecf20Sopenharmony_ci	.set_wol	= &vsc85xx_wol_set,
22578c2ecf20Sopenharmony_ci	.get_wol	= &vsc85xx_wol_get,
22588c2ecf20Sopenharmony_ci	.get_tunable	= &vsc85xx_get_tunable,
22598c2ecf20Sopenharmony_ci	.set_tunable	= &vsc85xx_set_tunable,
22608c2ecf20Sopenharmony_ci	.read_page	= &vsc85xx_phy_read_page,
22618c2ecf20Sopenharmony_ci	.write_page	= &vsc85xx_phy_write_page,
22628c2ecf20Sopenharmony_ci	.get_sset_count = &vsc85xx_get_sset_count,
22638c2ecf20Sopenharmony_ci	.get_strings    = &vsc85xx_get_strings,
22648c2ecf20Sopenharmony_ci	.get_stats      = &vsc85xx_get_stats,
22658c2ecf20Sopenharmony_ci},
22668c2ecf20Sopenharmony_ci{
22678c2ecf20Sopenharmony_ci	.phy_id		= PHY_ID_VSC8514,
22688c2ecf20Sopenharmony_ci	.name		= "Microsemi GE VSC8514 SyncE",
22698c2ecf20Sopenharmony_ci	.phy_id_mask	= 0xfffffff0,
22708c2ecf20Sopenharmony_ci	.soft_reset	= &genphy_soft_reset,
22718c2ecf20Sopenharmony_ci	.config_init    = &vsc8514_config_init,
22728c2ecf20Sopenharmony_ci	.config_aneg    = &vsc85xx_config_aneg,
22738c2ecf20Sopenharmony_ci	.read_status	= &vsc85xx_read_status,
22748c2ecf20Sopenharmony_ci	.ack_interrupt  = &vsc85xx_ack_interrupt,
22758c2ecf20Sopenharmony_ci	.config_intr    = &vsc85xx_config_intr,
22768c2ecf20Sopenharmony_ci	.suspend	= &genphy_suspend,
22778c2ecf20Sopenharmony_ci	.resume		= &genphy_resume,
22788c2ecf20Sopenharmony_ci	.probe		= &vsc8514_probe,
22798c2ecf20Sopenharmony_ci	.set_wol	= &vsc85xx_wol_set,
22808c2ecf20Sopenharmony_ci	.get_wol	= &vsc85xx_wol_get,
22818c2ecf20Sopenharmony_ci	.get_tunable	= &vsc85xx_get_tunable,
22828c2ecf20Sopenharmony_ci	.set_tunable	= &vsc85xx_set_tunable,
22838c2ecf20Sopenharmony_ci	.read_page      = &vsc85xx_phy_read_page,
22848c2ecf20Sopenharmony_ci	.write_page     = &vsc85xx_phy_write_page,
22858c2ecf20Sopenharmony_ci	.get_sset_count = &vsc85xx_get_sset_count,
22868c2ecf20Sopenharmony_ci	.get_strings    = &vsc85xx_get_strings,
22878c2ecf20Sopenharmony_ci	.get_stats      = &vsc85xx_get_stats,
22888c2ecf20Sopenharmony_ci},
22898c2ecf20Sopenharmony_ci{
22908c2ecf20Sopenharmony_ci	.phy_id		= PHY_ID_VSC8530,
22918c2ecf20Sopenharmony_ci	.name		= "Microsemi FE VSC8530",
22928c2ecf20Sopenharmony_ci	.phy_id_mask	= 0xfffffff0,
22938c2ecf20Sopenharmony_ci	/* PHY_BASIC_FEATURES */
22948c2ecf20Sopenharmony_ci	.soft_reset	= &genphy_soft_reset,
22958c2ecf20Sopenharmony_ci	.config_init	= &vsc85xx_config_init,
22968c2ecf20Sopenharmony_ci	.config_aneg    = &vsc85xx_config_aneg,
22978c2ecf20Sopenharmony_ci	.read_status	= &vsc85xx_read_status,
22988c2ecf20Sopenharmony_ci	.ack_interrupt	= &vsc85xx_ack_interrupt,
22998c2ecf20Sopenharmony_ci	.config_intr	= &vsc85xx_config_intr,
23008c2ecf20Sopenharmony_ci	.suspend	= &genphy_suspend,
23018c2ecf20Sopenharmony_ci	.resume		= &genphy_resume,
23028c2ecf20Sopenharmony_ci	.probe		= &vsc85xx_probe,
23038c2ecf20Sopenharmony_ci	.set_wol	= &vsc85xx_wol_set,
23048c2ecf20Sopenharmony_ci	.get_wol	= &vsc85xx_wol_get,
23058c2ecf20Sopenharmony_ci	.get_tunable	= &vsc85xx_get_tunable,
23068c2ecf20Sopenharmony_ci	.set_tunable	= &vsc85xx_set_tunable,
23078c2ecf20Sopenharmony_ci	.read_page	= &vsc85xx_phy_read_page,
23088c2ecf20Sopenharmony_ci	.write_page	= &vsc85xx_phy_write_page,
23098c2ecf20Sopenharmony_ci	.get_sset_count = &vsc85xx_get_sset_count,
23108c2ecf20Sopenharmony_ci	.get_strings    = &vsc85xx_get_strings,
23118c2ecf20Sopenharmony_ci	.get_stats      = &vsc85xx_get_stats,
23128c2ecf20Sopenharmony_ci},
23138c2ecf20Sopenharmony_ci{
23148c2ecf20Sopenharmony_ci	.phy_id		= PHY_ID_VSC8531,
23158c2ecf20Sopenharmony_ci	.name		= "Microsemi VSC8531",
23168c2ecf20Sopenharmony_ci	.phy_id_mask    = 0xfffffff0,
23178c2ecf20Sopenharmony_ci	/* PHY_GBIT_FEATURES */
23188c2ecf20Sopenharmony_ci	.soft_reset	= &genphy_soft_reset,
23198c2ecf20Sopenharmony_ci	.config_init    = &vsc85xx_config_init,
23208c2ecf20Sopenharmony_ci	.config_aneg    = &vsc85xx_config_aneg,
23218c2ecf20Sopenharmony_ci	.read_status	= &vsc85xx_read_status,
23228c2ecf20Sopenharmony_ci	.ack_interrupt  = &vsc85xx_ack_interrupt,
23238c2ecf20Sopenharmony_ci	.config_intr    = &vsc85xx_config_intr,
23248c2ecf20Sopenharmony_ci	.suspend	= &genphy_suspend,
23258c2ecf20Sopenharmony_ci	.resume		= &genphy_resume,
23268c2ecf20Sopenharmony_ci	.probe		= &vsc85xx_probe,
23278c2ecf20Sopenharmony_ci	.set_wol	= &vsc85xx_wol_set,
23288c2ecf20Sopenharmony_ci	.get_wol	= &vsc85xx_wol_get,
23298c2ecf20Sopenharmony_ci	.get_tunable	= &vsc85xx_get_tunable,
23308c2ecf20Sopenharmony_ci	.set_tunable	= &vsc85xx_set_tunable,
23318c2ecf20Sopenharmony_ci	.read_page	= &vsc85xx_phy_read_page,
23328c2ecf20Sopenharmony_ci	.write_page	= &vsc85xx_phy_write_page,
23338c2ecf20Sopenharmony_ci	.get_sset_count = &vsc85xx_get_sset_count,
23348c2ecf20Sopenharmony_ci	.get_strings    = &vsc85xx_get_strings,
23358c2ecf20Sopenharmony_ci	.get_stats      = &vsc85xx_get_stats,
23368c2ecf20Sopenharmony_ci},
23378c2ecf20Sopenharmony_ci{
23388c2ecf20Sopenharmony_ci	.phy_id		= PHY_ID_VSC8540,
23398c2ecf20Sopenharmony_ci	.name		= "Microsemi FE VSC8540 SyncE",
23408c2ecf20Sopenharmony_ci	.phy_id_mask	= 0xfffffff0,
23418c2ecf20Sopenharmony_ci	/* PHY_BASIC_FEATURES */
23428c2ecf20Sopenharmony_ci	.soft_reset	= &genphy_soft_reset,
23438c2ecf20Sopenharmony_ci	.config_init	= &vsc85xx_config_init,
23448c2ecf20Sopenharmony_ci	.config_aneg	= &vsc85xx_config_aneg,
23458c2ecf20Sopenharmony_ci	.read_status	= &vsc85xx_read_status,
23468c2ecf20Sopenharmony_ci	.ack_interrupt	= &vsc85xx_ack_interrupt,
23478c2ecf20Sopenharmony_ci	.config_intr	= &vsc85xx_config_intr,
23488c2ecf20Sopenharmony_ci	.suspend	= &genphy_suspend,
23498c2ecf20Sopenharmony_ci	.resume		= &genphy_resume,
23508c2ecf20Sopenharmony_ci	.probe		= &vsc85xx_probe,
23518c2ecf20Sopenharmony_ci	.set_wol	= &vsc85xx_wol_set,
23528c2ecf20Sopenharmony_ci	.get_wol	= &vsc85xx_wol_get,
23538c2ecf20Sopenharmony_ci	.get_tunable	= &vsc85xx_get_tunable,
23548c2ecf20Sopenharmony_ci	.set_tunable	= &vsc85xx_set_tunable,
23558c2ecf20Sopenharmony_ci	.read_page	= &vsc85xx_phy_read_page,
23568c2ecf20Sopenharmony_ci	.write_page	= &vsc85xx_phy_write_page,
23578c2ecf20Sopenharmony_ci	.get_sset_count = &vsc85xx_get_sset_count,
23588c2ecf20Sopenharmony_ci	.get_strings    = &vsc85xx_get_strings,
23598c2ecf20Sopenharmony_ci	.get_stats      = &vsc85xx_get_stats,
23608c2ecf20Sopenharmony_ci},
23618c2ecf20Sopenharmony_ci{
23628c2ecf20Sopenharmony_ci	.phy_id		= PHY_ID_VSC8541,
23638c2ecf20Sopenharmony_ci	.name		= "Microsemi VSC8541 SyncE",
23648c2ecf20Sopenharmony_ci	.phy_id_mask    = 0xfffffff0,
23658c2ecf20Sopenharmony_ci	/* PHY_GBIT_FEATURES */
23668c2ecf20Sopenharmony_ci	.soft_reset	= &genphy_soft_reset,
23678c2ecf20Sopenharmony_ci	.config_init    = &vsc85xx_config_init,
23688c2ecf20Sopenharmony_ci	.config_aneg    = &vsc85xx_config_aneg,
23698c2ecf20Sopenharmony_ci	.read_status	= &vsc85xx_read_status,
23708c2ecf20Sopenharmony_ci	.ack_interrupt  = &vsc85xx_ack_interrupt,
23718c2ecf20Sopenharmony_ci	.config_intr    = &vsc85xx_config_intr,
23728c2ecf20Sopenharmony_ci	.suspend	= &genphy_suspend,
23738c2ecf20Sopenharmony_ci	.resume		= &genphy_resume,
23748c2ecf20Sopenharmony_ci	.probe		= &vsc85xx_probe,
23758c2ecf20Sopenharmony_ci	.set_wol	= &vsc85xx_wol_set,
23768c2ecf20Sopenharmony_ci	.get_wol	= &vsc85xx_wol_get,
23778c2ecf20Sopenharmony_ci	.get_tunable	= &vsc85xx_get_tunable,
23788c2ecf20Sopenharmony_ci	.set_tunable	= &vsc85xx_set_tunable,
23798c2ecf20Sopenharmony_ci	.read_page	= &vsc85xx_phy_read_page,
23808c2ecf20Sopenharmony_ci	.write_page	= &vsc85xx_phy_write_page,
23818c2ecf20Sopenharmony_ci	.get_sset_count = &vsc85xx_get_sset_count,
23828c2ecf20Sopenharmony_ci	.get_strings    = &vsc85xx_get_strings,
23838c2ecf20Sopenharmony_ci	.get_stats      = &vsc85xx_get_stats,
23848c2ecf20Sopenharmony_ci},
23858c2ecf20Sopenharmony_ci{
23868c2ecf20Sopenharmony_ci	.phy_id		= PHY_ID_VSC8552,
23878c2ecf20Sopenharmony_ci	.name		= "Microsemi GE VSC8552 SyncE",
23888c2ecf20Sopenharmony_ci	.phy_id_mask	= 0xfffffff0,
23898c2ecf20Sopenharmony_ci	/* PHY_GBIT_FEATURES */
23908c2ecf20Sopenharmony_ci	.soft_reset	= &genphy_soft_reset,
23918c2ecf20Sopenharmony_ci	.config_init    = &vsc8584_config_init,
23928c2ecf20Sopenharmony_ci	.config_aneg    = &vsc85xx_config_aneg,
23938c2ecf20Sopenharmony_ci	.read_status	= &vsc85xx_read_status,
23948c2ecf20Sopenharmony_ci	.ack_interrupt  = &vsc85xx_ack_interrupt,
23958c2ecf20Sopenharmony_ci	.config_intr    = &vsc85xx_config_intr,
23968c2ecf20Sopenharmony_ci	.did_interrupt  = &vsc8584_did_interrupt,
23978c2ecf20Sopenharmony_ci	.suspend	= &genphy_suspend,
23988c2ecf20Sopenharmony_ci	.resume		= &genphy_resume,
23998c2ecf20Sopenharmony_ci	.probe		= &vsc8574_probe,
24008c2ecf20Sopenharmony_ci	.set_wol	= &vsc85xx_wol_set,
24018c2ecf20Sopenharmony_ci	.get_wol	= &vsc85xx_wol_get,
24028c2ecf20Sopenharmony_ci	.get_tunable	= &vsc85xx_get_tunable,
24038c2ecf20Sopenharmony_ci	.set_tunable	= &vsc85xx_set_tunable,
24048c2ecf20Sopenharmony_ci	.read_page	= &vsc85xx_phy_read_page,
24058c2ecf20Sopenharmony_ci	.write_page	= &vsc85xx_phy_write_page,
24068c2ecf20Sopenharmony_ci	.get_sset_count = &vsc85xx_get_sset_count,
24078c2ecf20Sopenharmony_ci	.get_strings    = &vsc85xx_get_strings,
24088c2ecf20Sopenharmony_ci	.get_stats      = &vsc85xx_get_stats,
24098c2ecf20Sopenharmony_ci},
24108c2ecf20Sopenharmony_ci{
24118c2ecf20Sopenharmony_ci	.phy_id		= PHY_ID_VSC856X,
24128c2ecf20Sopenharmony_ci	.name		= "Microsemi GE VSC856X SyncE",
24138c2ecf20Sopenharmony_ci	.phy_id_mask	= 0xfffffff0,
24148c2ecf20Sopenharmony_ci	/* PHY_GBIT_FEATURES */
24158c2ecf20Sopenharmony_ci	.soft_reset	= &genphy_soft_reset,
24168c2ecf20Sopenharmony_ci	.config_init    = &vsc8584_config_init,
24178c2ecf20Sopenharmony_ci	.config_aneg    = &vsc85xx_config_aneg,
24188c2ecf20Sopenharmony_ci	.read_status	= &vsc85xx_read_status,
24198c2ecf20Sopenharmony_ci	.ack_interrupt  = &vsc85xx_ack_interrupt,
24208c2ecf20Sopenharmony_ci	.config_intr    = &vsc85xx_config_intr,
24218c2ecf20Sopenharmony_ci	.did_interrupt  = &vsc8584_did_interrupt,
24228c2ecf20Sopenharmony_ci	.suspend	= &genphy_suspend,
24238c2ecf20Sopenharmony_ci	.resume		= &genphy_resume,
24248c2ecf20Sopenharmony_ci	.probe		= &vsc8584_probe,
24258c2ecf20Sopenharmony_ci	.get_tunable	= &vsc85xx_get_tunable,
24268c2ecf20Sopenharmony_ci	.set_tunable	= &vsc85xx_set_tunable,
24278c2ecf20Sopenharmony_ci	.read_page	= &vsc85xx_phy_read_page,
24288c2ecf20Sopenharmony_ci	.write_page	= &vsc85xx_phy_write_page,
24298c2ecf20Sopenharmony_ci	.get_sset_count = &vsc85xx_get_sset_count,
24308c2ecf20Sopenharmony_ci	.get_strings    = &vsc85xx_get_strings,
24318c2ecf20Sopenharmony_ci	.get_stats      = &vsc85xx_get_stats,
24328c2ecf20Sopenharmony_ci},
24338c2ecf20Sopenharmony_ci{
24348c2ecf20Sopenharmony_ci	.phy_id		= PHY_ID_VSC8572,
24358c2ecf20Sopenharmony_ci	.name		= "Microsemi GE VSC8572 SyncE",
24368c2ecf20Sopenharmony_ci	.phy_id_mask	= 0xfffffff0,
24378c2ecf20Sopenharmony_ci	/* PHY_GBIT_FEATURES */
24388c2ecf20Sopenharmony_ci	.soft_reset	= &genphy_soft_reset,
24398c2ecf20Sopenharmony_ci	.config_init    = &vsc8584_config_init,
24408c2ecf20Sopenharmony_ci	.config_aneg    = &vsc85xx_config_aneg,
24418c2ecf20Sopenharmony_ci	.aneg_done	= &genphy_aneg_done,
24428c2ecf20Sopenharmony_ci	.read_status	= &vsc85xx_read_status,
24438c2ecf20Sopenharmony_ci	.handle_interrupt = &vsc8584_handle_interrupt,
24448c2ecf20Sopenharmony_ci	.ack_interrupt  = &vsc85xx_ack_interrupt,
24458c2ecf20Sopenharmony_ci	.config_intr    = &vsc85xx_config_intr,
24468c2ecf20Sopenharmony_ci	.did_interrupt  = &vsc8584_did_interrupt,
24478c2ecf20Sopenharmony_ci	.suspend	= &genphy_suspend,
24488c2ecf20Sopenharmony_ci	.resume		= &genphy_resume,
24498c2ecf20Sopenharmony_ci	.probe		= &vsc8574_probe,
24508c2ecf20Sopenharmony_ci	.set_wol	= &vsc85xx_wol_set,
24518c2ecf20Sopenharmony_ci	.get_wol	= &vsc85xx_wol_get,
24528c2ecf20Sopenharmony_ci	.get_tunable	= &vsc85xx_get_tunable,
24538c2ecf20Sopenharmony_ci	.set_tunable	= &vsc85xx_set_tunable,
24548c2ecf20Sopenharmony_ci	.read_page	= &vsc85xx_phy_read_page,
24558c2ecf20Sopenharmony_ci	.write_page	= &vsc85xx_phy_write_page,
24568c2ecf20Sopenharmony_ci	.get_sset_count = &vsc85xx_get_sset_count,
24578c2ecf20Sopenharmony_ci	.get_strings    = &vsc85xx_get_strings,
24588c2ecf20Sopenharmony_ci	.get_stats      = &vsc85xx_get_stats,
24598c2ecf20Sopenharmony_ci},
24608c2ecf20Sopenharmony_ci{
24618c2ecf20Sopenharmony_ci	.phy_id		= PHY_ID_VSC8574,
24628c2ecf20Sopenharmony_ci	.name		= "Microsemi GE VSC8574 SyncE",
24638c2ecf20Sopenharmony_ci	.phy_id_mask	= 0xfffffff0,
24648c2ecf20Sopenharmony_ci	/* PHY_GBIT_FEATURES */
24658c2ecf20Sopenharmony_ci	.soft_reset	= &genphy_soft_reset,
24668c2ecf20Sopenharmony_ci	.config_init    = &vsc8584_config_init,
24678c2ecf20Sopenharmony_ci	.config_aneg    = &vsc85xx_config_aneg,
24688c2ecf20Sopenharmony_ci	.aneg_done	= &genphy_aneg_done,
24698c2ecf20Sopenharmony_ci	.read_status	= &vsc85xx_read_status,
24708c2ecf20Sopenharmony_ci	.ack_interrupt  = &vsc85xx_ack_interrupt,
24718c2ecf20Sopenharmony_ci	.config_intr    = &vsc85xx_config_intr,
24728c2ecf20Sopenharmony_ci	.did_interrupt  = &vsc8584_did_interrupt,
24738c2ecf20Sopenharmony_ci	.suspend	= &genphy_suspend,
24748c2ecf20Sopenharmony_ci	.resume		= &genphy_resume,
24758c2ecf20Sopenharmony_ci	.probe		= &vsc8574_probe,
24768c2ecf20Sopenharmony_ci	.set_wol	= &vsc85xx_wol_set,
24778c2ecf20Sopenharmony_ci	.get_wol	= &vsc85xx_wol_get,
24788c2ecf20Sopenharmony_ci	.get_tunable	= &vsc85xx_get_tunable,
24798c2ecf20Sopenharmony_ci	.set_tunable	= &vsc85xx_set_tunable,
24808c2ecf20Sopenharmony_ci	.read_page	= &vsc85xx_phy_read_page,
24818c2ecf20Sopenharmony_ci	.write_page	= &vsc85xx_phy_write_page,
24828c2ecf20Sopenharmony_ci	.get_sset_count = &vsc85xx_get_sset_count,
24838c2ecf20Sopenharmony_ci	.get_strings    = &vsc85xx_get_strings,
24848c2ecf20Sopenharmony_ci	.get_stats      = &vsc85xx_get_stats,
24858c2ecf20Sopenharmony_ci},
24868c2ecf20Sopenharmony_ci{
24878c2ecf20Sopenharmony_ci	.phy_id		= PHY_ID_VSC8575,
24888c2ecf20Sopenharmony_ci	.name		= "Microsemi GE VSC8575 SyncE",
24898c2ecf20Sopenharmony_ci	.phy_id_mask	= 0xfffffff0,
24908c2ecf20Sopenharmony_ci	/* PHY_GBIT_FEATURES */
24918c2ecf20Sopenharmony_ci	.soft_reset	= &genphy_soft_reset,
24928c2ecf20Sopenharmony_ci	.config_init    = &vsc8584_config_init,
24938c2ecf20Sopenharmony_ci	.config_aneg    = &vsc85xx_config_aneg,
24948c2ecf20Sopenharmony_ci	.aneg_done	= &genphy_aneg_done,
24958c2ecf20Sopenharmony_ci	.read_status	= &vsc85xx_read_status,
24968c2ecf20Sopenharmony_ci	.handle_interrupt = &vsc8584_handle_interrupt,
24978c2ecf20Sopenharmony_ci	.ack_interrupt  = &vsc85xx_ack_interrupt,
24988c2ecf20Sopenharmony_ci	.config_intr    = &vsc85xx_config_intr,
24998c2ecf20Sopenharmony_ci	.did_interrupt  = &vsc8584_did_interrupt,
25008c2ecf20Sopenharmony_ci	.suspend	= &genphy_suspend,
25018c2ecf20Sopenharmony_ci	.resume		= &genphy_resume,
25028c2ecf20Sopenharmony_ci	.probe		= &vsc8584_probe,
25038c2ecf20Sopenharmony_ci	.get_tunable	= &vsc85xx_get_tunable,
25048c2ecf20Sopenharmony_ci	.set_tunable	= &vsc85xx_set_tunable,
25058c2ecf20Sopenharmony_ci	.read_page	= &vsc85xx_phy_read_page,
25068c2ecf20Sopenharmony_ci	.write_page	= &vsc85xx_phy_write_page,
25078c2ecf20Sopenharmony_ci	.get_sset_count = &vsc85xx_get_sset_count,
25088c2ecf20Sopenharmony_ci	.get_strings    = &vsc85xx_get_strings,
25098c2ecf20Sopenharmony_ci	.get_stats      = &vsc85xx_get_stats,
25108c2ecf20Sopenharmony_ci},
25118c2ecf20Sopenharmony_ci{
25128c2ecf20Sopenharmony_ci	.phy_id		= PHY_ID_VSC8582,
25138c2ecf20Sopenharmony_ci	.name		= "Microsemi GE VSC8582 SyncE",
25148c2ecf20Sopenharmony_ci	.phy_id_mask	= 0xfffffff0,
25158c2ecf20Sopenharmony_ci	/* PHY_GBIT_FEATURES */
25168c2ecf20Sopenharmony_ci	.soft_reset	= &genphy_soft_reset,
25178c2ecf20Sopenharmony_ci	.config_init    = &vsc8584_config_init,
25188c2ecf20Sopenharmony_ci	.config_aneg    = &vsc85xx_config_aneg,
25198c2ecf20Sopenharmony_ci	.aneg_done	= &genphy_aneg_done,
25208c2ecf20Sopenharmony_ci	.read_status	= &vsc85xx_read_status,
25218c2ecf20Sopenharmony_ci	.handle_interrupt = &vsc8584_handle_interrupt,
25228c2ecf20Sopenharmony_ci	.ack_interrupt  = &vsc85xx_ack_interrupt,
25238c2ecf20Sopenharmony_ci	.config_intr    = &vsc85xx_config_intr,
25248c2ecf20Sopenharmony_ci	.did_interrupt  = &vsc8584_did_interrupt,
25258c2ecf20Sopenharmony_ci	.suspend	= &genphy_suspend,
25268c2ecf20Sopenharmony_ci	.resume		= &genphy_resume,
25278c2ecf20Sopenharmony_ci	.probe		= &vsc8584_probe,
25288c2ecf20Sopenharmony_ci	.get_tunable	= &vsc85xx_get_tunable,
25298c2ecf20Sopenharmony_ci	.set_tunable	= &vsc85xx_set_tunable,
25308c2ecf20Sopenharmony_ci	.read_page	= &vsc85xx_phy_read_page,
25318c2ecf20Sopenharmony_ci	.write_page	= &vsc85xx_phy_write_page,
25328c2ecf20Sopenharmony_ci	.get_sset_count = &vsc85xx_get_sset_count,
25338c2ecf20Sopenharmony_ci	.get_strings    = &vsc85xx_get_strings,
25348c2ecf20Sopenharmony_ci	.get_stats      = &vsc85xx_get_stats,
25358c2ecf20Sopenharmony_ci},
25368c2ecf20Sopenharmony_ci{
25378c2ecf20Sopenharmony_ci	.phy_id		= PHY_ID_VSC8584,
25388c2ecf20Sopenharmony_ci	.name		= "Microsemi GE VSC8584 SyncE",
25398c2ecf20Sopenharmony_ci	.phy_id_mask	= 0xfffffff0,
25408c2ecf20Sopenharmony_ci	/* PHY_GBIT_FEATURES */
25418c2ecf20Sopenharmony_ci	.soft_reset	= &genphy_soft_reset,
25428c2ecf20Sopenharmony_ci	.config_init    = &vsc8584_config_init,
25438c2ecf20Sopenharmony_ci	.config_aneg    = &vsc85xx_config_aneg,
25448c2ecf20Sopenharmony_ci	.aneg_done	= &genphy_aneg_done,
25458c2ecf20Sopenharmony_ci	.read_status	= &vsc85xx_read_status,
25468c2ecf20Sopenharmony_ci	.handle_interrupt = &vsc8584_handle_interrupt,
25478c2ecf20Sopenharmony_ci	.ack_interrupt  = &vsc85xx_ack_interrupt,
25488c2ecf20Sopenharmony_ci	.config_intr    = &vsc85xx_config_intr,
25498c2ecf20Sopenharmony_ci	.did_interrupt  = &vsc8584_did_interrupt,
25508c2ecf20Sopenharmony_ci	.suspend	= &genphy_suspend,
25518c2ecf20Sopenharmony_ci	.resume		= &genphy_resume,
25528c2ecf20Sopenharmony_ci	.probe		= &vsc8584_probe,
25538c2ecf20Sopenharmony_ci	.get_tunable	= &vsc85xx_get_tunable,
25548c2ecf20Sopenharmony_ci	.set_tunable	= &vsc85xx_set_tunable,
25558c2ecf20Sopenharmony_ci	.read_page	= &vsc85xx_phy_read_page,
25568c2ecf20Sopenharmony_ci	.write_page	= &vsc85xx_phy_write_page,
25578c2ecf20Sopenharmony_ci	.get_sset_count = &vsc85xx_get_sset_count,
25588c2ecf20Sopenharmony_ci	.get_strings    = &vsc85xx_get_strings,
25598c2ecf20Sopenharmony_ci	.get_stats      = &vsc85xx_get_stats,
25608c2ecf20Sopenharmony_ci	.link_change_notify = &vsc85xx_link_change_notify,
25618c2ecf20Sopenharmony_ci}
25628c2ecf20Sopenharmony_ci
25638c2ecf20Sopenharmony_ci};
25648c2ecf20Sopenharmony_ci
25658c2ecf20Sopenharmony_cimodule_phy_driver(vsc85xx_driver);
25668c2ecf20Sopenharmony_ci
25678c2ecf20Sopenharmony_cistatic struct mdio_device_id __maybe_unused vsc85xx_tbl[] = {
25688c2ecf20Sopenharmony_ci	{ PHY_ID_VSC8502, 0xfffffff0, },
25698c2ecf20Sopenharmony_ci	{ PHY_ID_VSC8504, 0xfffffff0, },
25708c2ecf20Sopenharmony_ci	{ PHY_ID_VSC8514, 0xfffffff0, },
25718c2ecf20Sopenharmony_ci	{ PHY_ID_VSC8530, 0xfffffff0, },
25728c2ecf20Sopenharmony_ci	{ PHY_ID_VSC8531, 0xfffffff0, },
25738c2ecf20Sopenharmony_ci	{ PHY_ID_VSC8540, 0xfffffff0, },
25748c2ecf20Sopenharmony_ci	{ PHY_ID_VSC8541, 0xfffffff0, },
25758c2ecf20Sopenharmony_ci	{ PHY_ID_VSC8552, 0xfffffff0, },
25768c2ecf20Sopenharmony_ci	{ PHY_ID_VSC856X, 0xfffffff0, },
25778c2ecf20Sopenharmony_ci	{ PHY_ID_VSC8572, 0xfffffff0, },
25788c2ecf20Sopenharmony_ci	{ PHY_ID_VSC8574, 0xfffffff0, },
25798c2ecf20Sopenharmony_ci	{ PHY_ID_VSC8575, 0xfffffff0, },
25808c2ecf20Sopenharmony_ci	{ PHY_ID_VSC8582, 0xfffffff0, },
25818c2ecf20Sopenharmony_ci	{ PHY_ID_VSC8584, 0xfffffff0, },
25828c2ecf20Sopenharmony_ci	{ }
25838c2ecf20Sopenharmony_ci};
25848c2ecf20Sopenharmony_ci
25858c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(mdio, vsc85xx_tbl);
25868c2ecf20Sopenharmony_ci
25878c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Microsemi VSC85xx PHY driver");
25888c2ecf20Sopenharmony_ciMODULE_AUTHOR("Nagaraju Lakkaraju");
25898c2ecf20Sopenharmony_ciMODULE_LICENSE("Dual MIT/GPL");
25908c2ecf20Sopenharmony_ci
25918c2ecf20Sopenharmony_ciMODULE_FIRMWARE(MSCC_VSC8584_REVB_INT8051_FW);
25928c2ecf20Sopenharmony_ciMODULE_FIRMWARE(MSCC_VSC8574_REVB_INT8051_FW);
2593