brintos

brintos / linux-shallow public Read only

0
0
Text · 103.9 KiB · 9964bf3 Raw
4163 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 * drivers/net/phy/marvell.c4 *5 * Driver for Marvell PHYs6 *7 * Author: Andy Fleming8 *9 * Copyright (c) 2004 Freescale Semiconductor, Inc.10 *11 * Copyright (c) 2013 Michael Stapelberg <michael@stapelberg.de>12 */13#include <linux/kernel.h>14#include <linux/string.h>15#include <linux/ctype.h>16#include <linux/errno.h>17#include <linux/unistd.h>18#include <linux/hwmon.h>19#include <linux/interrupt.h>20#include <linux/init.h>21#include <linux/delay.h>22#include <linux/netdevice.h>23#include <linux/etherdevice.h>24#include <linux/skbuff.h>25#include <linux/spinlock.h>26#include <linux/mm.h>27#include <linux/module.h>28#include <linux/mii.h>29#include <linux/ethtool.h>30#include <linux/ethtool_netlink.h>31#include <linux/phy.h>32#include <linux/marvell_phy.h>33#include <linux/bitfield.h>34#include <linux/of.h>35#include <linux/sfp.h>36 37#include <linux/io.h>38#include <asm/irq.h>39#include <linux/uaccess.h>40 41#define MII_MARVELL_PHY_PAGE		2242#define MII_MARVELL_COPPER_PAGE		0x0043#define MII_MARVELL_FIBER_PAGE		0x0144#define MII_MARVELL_MSCR_PAGE		0x0245#define MII_MARVELL_LED_PAGE		0x0346#define MII_MARVELL_VCT5_PAGE		0x0547#define MII_MARVELL_MISC_TEST_PAGE	0x0648#define MII_MARVELL_VCT7_PAGE		0x0749#define MII_MARVELL_WOL_PAGE		0x1150#define MII_MARVELL_MODE_PAGE		0x1251 52#define MII_M1011_IEVENT		0x1353#define MII_M1011_IEVENT_CLEAR		0x000054 55#define MII_M1011_IMASK			0x1256#define MII_M1011_IMASK_INIT		0x640057#define MII_M1011_IMASK_CLEAR		0x000058 59#define MII_M1011_PHY_SCR			0x1060#define MII_M1011_PHY_SCR_DOWNSHIFT_EN		BIT(11)61#define MII_M1011_PHY_SCR_DOWNSHIFT_MASK	GENMASK(14, 12)62#define MII_M1011_PHY_SCR_DOWNSHIFT_MAX		863#define MII_M1011_PHY_SCR_MDI			(0x0 << 5)64#define MII_M1011_PHY_SCR_MDI_X			(0x1 << 5)65#define MII_M1011_PHY_SCR_AUTO_CROSS		(0x3 << 5)66 67#define MII_M1011_PHY_SSR			0x1168#define MII_M1011_PHY_SSR_DOWNSHIFT		BIT(5)69 70#define MII_M1111_PHY_LED_CONTROL	0x1871#define MII_M1111_PHY_LED_DIRECT	0x410072#define MII_M1111_PHY_LED_COMBINE	0x411c73#define MII_M1111_PHY_EXT_CR		0x1474#define MII_M1111_PHY_EXT_CR_DOWNSHIFT_MASK	GENMASK(11, 9)75#define MII_M1111_PHY_EXT_CR_DOWNSHIFT_MAX	876#define MII_M1111_PHY_EXT_CR_DOWNSHIFT_EN	BIT(8)77#define MII_M1111_RGMII_RX_DELAY	BIT(7)78#define MII_M1111_RGMII_TX_DELAY	BIT(1)79#define MII_M1111_PHY_EXT_SR		0x1b80 81#define MII_M1111_HWCFG_MODE_MASK		0xf82#define MII_M1111_HWCFG_MODE_FIBER_RGMII	0x383#define MII_M1111_HWCFG_MODE_SGMII_NO_CLK	0x484#define MII_M1111_HWCFG_MODE_RTBI		0x785#define MII_M1111_HWCFG_MODE_COPPER_1000X_AN	0x886#define MII_M1111_HWCFG_MODE_COPPER_RTBI	0x987#define MII_M1111_HWCFG_MODE_COPPER_RGMII	0xb88#define MII_M1111_HWCFG_MODE_COPPER_1000X_NOAN	0xc89#define MII_M1111_HWCFG_SERIAL_AN_BYPASS	BIT(12)90#define MII_M1111_HWCFG_FIBER_COPPER_RES	BIT(13)91#define MII_M1111_HWCFG_FIBER_COPPER_AUTO	BIT(15)92 93#define MII_88E1121_PHY_MSCR_REG	2194#define MII_88E1121_PHY_MSCR_RX_DELAY	BIT(5)95#define MII_88E1121_PHY_MSCR_TX_DELAY	BIT(4)96#define MII_88E1121_PHY_MSCR_DELAY_MASK	(BIT(5) | BIT(4))97 98#define MII_88E1121_MISC_TEST				0x1a99#define MII_88E1510_MISC_TEST_TEMP_THRESHOLD_MASK	0x1f00100#define MII_88E1510_MISC_TEST_TEMP_THRESHOLD_SHIFT	8101#define MII_88E1510_MISC_TEST_TEMP_IRQ_EN		BIT(7)102#define MII_88E1510_MISC_TEST_TEMP_IRQ			BIT(6)103#define MII_88E1121_MISC_TEST_TEMP_SENSOR_EN		BIT(5)104#define MII_88E1121_MISC_TEST_TEMP_MASK			0x1f105 106#define MII_88E1510_TEMP_SENSOR		0x1b107#define MII_88E1510_TEMP_SENSOR_MASK	0xff108 109#define MII_88E1540_COPPER_CTRL3	0x1a110#define MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_MASK	GENMASK(11, 10)111#define MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_00MS	0112#define MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_10MS	1113#define MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_20MS	2114#define MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_40MS	3115#define MII_88E1540_COPPER_CTRL3_FAST_LINK_DOWN		BIT(9)116 117#define MII_88E6390_MISC_TEST		0x1b118#define MII_88E6390_MISC_TEST_TEMP_SENSOR_ENABLE_SAMPLE_1S	(0x0 << 14)119#define MII_88E6390_MISC_TEST_TEMP_SENSOR_ENABLE		(0x1 << 14)120#define MII_88E6390_MISC_TEST_TEMP_SENSOR_ENABLE_ONESHOT	(0x2 << 14)121#define MII_88E6390_MISC_TEST_TEMP_SENSOR_DISABLE		(0x3 << 14)122#define MII_88E6390_MISC_TEST_TEMP_SENSOR_MASK			(0x3 << 14)123#define MII_88E6393_MISC_TEST_SAMPLES_2048	(0x0 << 11)124#define MII_88E6393_MISC_TEST_SAMPLES_4096	(0x1 << 11)125#define MII_88E6393_MISC_TEST_SAMPLES_8192	(0x2 << 11)126#define MII_88E6393_MISC_TEST_SAMPLES_16384	(0x3 << 11)127#define MII_88E6393_MISC_TEST_SAMPLES_MASK	(0x3 << 11)128#define MII_88E6393_MISC_TEST_RATE_2_3MS	(0x5 << 8)129#define MII_88E6393_MISC_TEST_RATE_6_4MS	(0x6 << 8)130#define MII_88E6393_MISC_TEST_RATE_11_9MS	(0x7 << 8)131#define MII_88E6393_MISC_TEST_RATE_MASK		(0x7 << 8)132 133#define MII_88E6390_TEMP_SENSOR		0x1c134#define MII_88E6393_TEMP_SENSOR_THRESHOLD_MASK	0xff00135#define MII_88E6393_TEMP_SENSOR_THRESHOLD_SHIFT	8136#define MII_88E6390_TEMP_SENSOR_MASK		0xff137#define MII_88E6390_TEMP_SENSOR_SAMPLES		10138 139#define MII_88E1318S_PHY_MSCR1_REG	16140#define MII_88E1318S_PHY_MSCR1_PAD_ODD	BIT(6)141 142/* Copper Specific Interrupt Enable Register */143#define MII_88E1318S_PHY_CSIER				0x12144/* WOL Event Interrupt Enable */145#define MII_88E1318S_PHY_CSIER_WOL_EIE			BIT(7)146 147#define MII_88E1318S_PHY_LED_FUNC		0x10148#define MII_88E1318S_PHY_LED_FUNC_OFF		(0x8)149#define MII_88E1318S_PHY_LED_FUNC_ON		(0x9)150#define MII_88E1318S_PHY_LED_FUNC_HI_Z		(0xa)151#define MII_88E1318S_PHY_LED_FUNC_BLINK		(0xb)152#define MII_88E1318S_PHY_LED_TCR		0x12153#define MII_88E1318S_PHY_LED_TCR_FORCE_INT	BIT(15)154#define MII_88E1318S_PHY_LED_TCR_INTn_ENABLE	BIT(7)155#define MII_88E1318S_PHY_LED_TCR_INT_ACTIVE_LOW	BIT(11)156 157/* Magic Packet MAC address registers */158#define MII_88E1318S_PHY_MAGIC_PACKET_WORD2		0x17159#define MII_88E1318S_PHY_MAGIC_PACKET_WORD1		0x18160#define MII_88E1318S_PHY_MAGIC_PACKET_WORD0		0x19161 162#define MII_88E1318S_PHY_WOL_CTRL				0x10163#define MII_88E1318S_PHY_WOL_CTRL_CLEAR_WOL_STATUS		BIT(12)164#define MII_88E1318S_PHY_WOL_CTRL_LINK_UP_ENABLE		BIT(13)165#define MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE	BIT(14)166 167#define MII_PHY_LED_CTRL	        16168#define MII_88E1121_PHY_LED_DEF		0x0030169#define MII_88E1510_PHY_LED_DEF		0x1177170#define MII_88E1510_PHY_LED0_LINK_LED1_ACTIVE	0x1040171 172#define MII_M1011_PHY_STATUS		0x11173#define MII_M1011_PHY_STATUS_1000	0x8000174#define MII_M1011_PHY_STATUS_100	0x4000175#define MII_M1011_PHY_STATUS_SPD_MASK	0xc000176#define MII_M1011_PHY_STATUS_FULLDUPLEX	0x2000177#define MII_M1011_PHY_STATUS_RESOLVED	0x0800178#define MII_M1011_PHY_STATUS_LINK	0x0400179 180#define MII_88E3016_PHY_SPEC_CTRL	0x10181#define MII_88E3016_DISABLE_SCRAMBLER	0x0200182#define MII_88E3016_AUTO_MDIX_CROSSOVER	0x0030183 184#define MII_88E1510_GEN_CTRL_REG_1		0x14185#define MII_88E1510_GEN_CTRL_REG_1_MODE_MASK	0x7186#define MII_88E1510_GEN_CTRL_REG_1_MODE_RGMII	0x0	/* RGMII to copper */187#define MII_88E1510_GEN_CTRL_REG_1_MODE_SGMII	0x1	/* SGMII to copper */188/* RGMII to 1000BASE-X */189#define MII_88E1510_GEN_CTRL_REG_1_MODE_RGMII_1000X	0x2190/* RGMII to 100BASE-FX */191#define MII_88E1510_GEN_CTRL_REG_1_MODE_RGMII_100FX	0x3192/* RGMII to SGMII */193#define MII_88E1510_GEN_CTRL_REG_1_MODE_RGMII_SGMII	0x4194#define MII_88E1510_GEN_CTRL_REG_1_RESET	0x8000	/* Soft reset */195 196#define MII_88E1510_MSCR_2		0x15197 198#define MII_VCT5_TX_RX_MDI0_COUPLING	0x10199#define MII_VCT5_TX_RX_MDI1_COUPLING	0x11200#define MII_VCT5_TX_RX_MDI2_COUPLING	0x12201#define MII_VCT5_TX_RX_MDI3_COUPLING	0x13202#define MII_VCT5_TX_RX_AMPLITUDE_MASK	0x7f00203#define MII_VCT5_TX_RX_AMPLITUDE_SHIFT	8204#define MII_VCT5_TX_RX_COUPLING_POSITIVE_REFLECTION	BIT(15)205 206#define MII_VCT5_CTRL				0x17207#define MII_VCT5_CTRL_ENABLE				BIT(15)208#define MII_VCT5_CTRL_COMPLETE				BIT(14)209#define MII_VCT5_CTRL_TX_SAME_CHANNEL			(0x0 << 11)210#define MII_VCT5_CTRL_TX0_CHANNEL			(0x4 << 11)211#define MII_VCT5_CTRL_TX1_CHANNEL			(0x5 << 11)212#define MII_VCT5_CTRL_TX2_CHANNEL			(0x6 << 11)213#define MII_VCT5_CTRL_TX3_CHANNEL			(0x7 << 11)214#define MII_VCT5_CTRL_SAMPLES_2				(0x0 << 8)215#define MII_VCT5_CTRL_SAMPLES_4				(0x1 << 8)216#define MII_VCT5_CTRL_SAMPLES_8				(0x2 << 8)217#define MII_VCT5_CTRL_SAMPLES_16			(0x3 << 8)218#define MII_VCT5_CTRL_SAMPLES_32			(0x4 << 8)219#define MII_VCT5_CTRL_SAMPLES_64			(0x5 << 8)220#define MII_VCT5_CTRL_SAMPLES_128			(0x6 << 8)221#define MII_VCT5_CTRL_SAMPLES_DEFAULT			(0x6 << 8)222#define MII_VCT5_CTRL_SAMPLES_256			(0x7 << 8)223#define MII_VCT5_CTRL_SAMPLES_SHIFT			8224#define MII_VCT5_CTRL_MODE_MAXIMUM_PEEK			(0x0 << 6)225#define MII_VCT5_CTRL_MODE_FIRST_LAST_PEEK		(0x1 << 6)226#define MII_VCT5_CTRL_MODE_OFFSET			(0x2 << 6)227#define MII_VCT5_CTRL_SAMPLE_POINT			(0x3 << 6)228#define MII_VCT5_CTRL_PEEK_HYST_DEFAULT			3229 230#define MII_VCT5_SAMPLE_POINT_DISTANCE		0x18231#define MII_VCT5_SAMPLE_POINT_DISTANCE_MAX	511232#define MII_VCT5_TX_PULSE_CTRL			0x1c233#define MII_VCT5_TX_PULSE_CTRL_DONT_WAIT_LINK_DOWN	BIT(12)234#define MII_VCT5_TX_PULSE_CTRL_PULSE_WIDTH_128nS	(0x0 << 10)235#define MII_VCT5_TX_PULSE_CTRL_PULSE_WIDTH_96nS		(0x1 << 10)236#define MII_VCT5_TX_PULSE_CTRL_PULSE_WIDTH_64nS		(0x2 << 10)237#define MII_VCT5_TX_PULSE_CTRL_PULSE_WIDTH_32nS		(0x3 << 10)238#define MII_VCT5_TX_PULSE_CTRL_PULSE_WIDTH_SHIFT	10239#define MII_VCT5_TX_PULSE_CTRL_PULSE_AMPLITUDE_1000mV	(0x0 << 8)240#define MII_VCT5_TX_PULSE_CTRL_PULSE_AMPLITUDE_750mV	(0x1 << 8)241#define MII_VCT5_TX_PULSE_CTRL_PULSE_AMPLITUDE_500mV	(0x2 << 8)242#define MII_VCT5_TX_PULSE_CTRL_PULSE_AMPLITUDE_250mV	(0x3 << 8)243#define MII_VCT5_TX_PULSE_CTRL_PULSE_AMPLITUDE_SHIFT	8244#define MII_VCT5_TX_PULSE_CTRL_MAX_AMP			BIT(7)245#define MII_VCT5_TX_PULSE_CTRL_GT_140m_46_86mV		(0x6 << 0)246 247/* For TDR measurements less than 11 meters, a short pulse should be248 * used.249 */250#define TDR_SHORT_CABLE_LENGTH	11251 252#define MII_VCT7_PAIR_0_DISTANCE	0x10253#define MII_VCT7_PAIR_1_DISTANCE	0x11254#define MII_VCT7_PAIR_2_DISTANCE	0x12255#define MII_VCT7_PAIR_3_DISTANCE	0x13256 257#define MII_VCT7_RESULTS	0x14258#define MII_VCT7_RESULTS_PAIR3_MASK	0xf000259#define MII_VCT7_RESULTS_PAIR2_MASK	0x0f00260#define MII_VCT7_RESULTS_PAIR1_MASK	0x00f0261#define MII_VCT7_RESULTS_PAIR0_MASK	0x000f262#define MII_VCT7_RESULTS_PAIR3_SHIFT	12263#define MII_VCT7_RESULTS_PAIR2_SHIFT	8264#define MII_VCT7_RESULTS_PAIR1_SHIFT	4265#define MII_VCT7_RESULTS_PAIR0_SHIFT	0266#define MII_VCT7_RESULTS_INVALID	0267#define MII_VCT7_RESULTS_OK		1268#define MII_VCT7_RESULTS_OPEN		2269#define MII_VCT7_RESULTS_SAME_SHORT	3270#define MII_VCT7_RESULTS_CROSS_SHORT	4271#define MII_VCT7_RESULTS_BUSY		9272 273#define MII_VCT7_CTRL		0x15274#define MII_VCT7_CTRL_RUN_NOW			BIT(15)275#define MII_VCT7_CTRL_RUN_ANEG			BIT(14)276#define MII_VCT7_CTRL_DISABLE_CROSS		BIT(13)277#define MII_VCT7_CTRL_RUN_AFTER_BREAK_LINK	BIT(12)278#define MII_VCT7_CTRL_IN_PROGRESS		BIT(11)279#define MII_VCT7_CTRL_METERS			BIT(10)280#define MII_VCT7_CTRL_CENTIMETERS		0281 282#define MII_VCT_TXPINS			0x1A283#define MII_VCT_RXPINS			0x1B284#define MII_VCT_SR			0x1C285#define MII_VCT_TXPINS_ENVCT		BIT(15)286#define MII_VCT_TXRXPINS_VCTTST		GENMASK(14, 13)287#define MII_VCT_TXRXPINS_VCTTST_SHIFT	13288#define MII_VCT_TXRXPINS_VCTTST_OK	0289#define MII_VCT_TXRXPINS_VCTTST_SHORT	1290#define MII_VCT_TXRXPINS_VCTTST_OPEN	2291#define MII_VCT_TXRXPINS_VCTTST_FAIL	3292#define MII_VCT_TXRXPINS_AMPRFLN	GENMASK(12, 8)293#define MII_VCT_TXRXPINS_AMPRFLN_SHIFT	8294#define MII_VCT_TXRXPINS_DISTRFLN	GENMASK(7, 0)295#define MII_VCT_TXRXPINS_DISTRFLN_MAX	0xff296 297#define M88E3082_PAIR_A		BIT(0)298#define M88E3082_PAIR_B		BIT(1)299 300#define LPA_PAUSE_FIBER		0x180301#define LPA_PAUSE_ASYM_FIBER	0x100302 303#define NB_FIBER_STATS	1304#define NB_STAT_MAX	3305 306MODULE_DESCRIPTION("Marvell PHY driver");307MODULE_AUTHOR("Andy Fleming");308MODULE_LICENSE("GPL");309 310struct marvell_hw_stat {311	const char *string;312	u8 page;313	u8 reg;314	u8 bits;315};316 317static const struct marvell_hw_stat marvell_hw_stats[] = {318	{ "phy_receive_errors_copper", 0, 21, 16},319	{ "phy_idle_errors", 0, 10, 8 },320	{ "phy_receive_errors_fiber", 1, 21, 16},321};322 323static_assert(ARRAY_SIZE(marvell_hw_stats) <= NB_STAT_MAX);324 325/* "simple" stat list + corresponding marvell_get_*_simple functions are used326 * on PHYs without a page register327 */328struct marvell_hw_stat_simple {329	const char *string;330	u8 reg;331	u8 bits;332};333 334static const struct marvell_hw_stat_simple marvell_hw_stats_simple[] = {335	{ "phy_receive_errors", 21, 16},336};337 338static_assert(ARRAY_SIZE(marvell_hw_stats_simple) <= NB_STAT_MAX);339 340enum {341	M88E3082_VCT_OFF,342	M88E3082_VCT_PHASE1,343	M88E3082_VCT_PHASE2,344};345 346struct marvell_priv {347	u64 stats[NB_STAT_MAX];348	char *hwmon_name;349	struct device *hwmon_dev;350	bool cable_test_tdr;351	u32 first;352	u32 last;353	u32 step;354	s8 pair;355	u8 vct_phase;356};357 358static int marvell_read_page(struct phy_device *phydev)359{360	return __phy_read(phydev, MII_MARVELL_PHY_PAGE);361}362 363static int marvell_write_page(struct phy_device *phydev, int page)364{365	return __phy_write(phydev, MII_MARVELL_PHY_PAGE, page);366}367 368static int marvell_set_page(struct phy_device *phydev, int page)369{370	return phy_write(phydev, MII_MARVELL_PHY_PAGE, page);371}372 373static int marvell_ack_interrupt(struct phy_device *phydev)374{375	int err;376 377	/* Clear the interrupts by reading the reg */378	err = phy_read(phydev, MII_M1011_IEVENT);379 380	if (err < 0)381		return err;382 383	return 0;384}385 386static int marvell_config_intr(struct phy_device *phydev)387{388	int err;389 390	if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {391		err = marvell_ack_interrupt(phydev);392		if (err)393			return err;394 395		err = phy_write(phydev, MII_M1011_IMASK,396				MII_M1011_IMASK_INIT);397	} else {398		err = phy_write(phydev, MII_M1011_IMASK,399				MII_M1011_IMASK_CLEAR);400		if (err)401			return err;402 403		err = marvell_ack_interrupt(phydev);404	}405 406	return err;407}408 409static irqreturn_t marvell_handle_interrupt(struct phy_device *phydev)410{411	int irq_status;412 413	irq_status = phy_read(phydev, MII_M1011_IEVENT);414	if (irq_status < 0) {415		phy_error(phydev);416		return IRQ_NONE;417	}418 419	if (!(irq_status & MII_M1011_IMASK_INIT))420		return IRQ_NONE;421 422	phy_trigger_machine(phydev);423 424	return IRQ_HANDLED;425}426 427static int marvell_set_polarity(struct phy_device *phydev, int polarity)428{429	u16 val;430 431	switch (polarity) {432	case ETH_TP_MDI:433		val = MII_M1011_PHY_SCR_MDI;434		break;435	case ETH_TP_MDI_X:436		val = MII_M1011_PHY_SCR_MDI_X;437		break;438	case ETH_TP_MDI_AUTO:439	case ETH_TP_MDI_INVALID:440	default:441		val = MII_M1011_PHY_SCR_AUTO_CROSS;442		break;443	}444 445	return phy_modify_changed(phydev, MII_M1011_PHY_SCR,446				  MII_M1011_PHY_SCR_AUTO_CROSS, val);447}448 449static int marvell_config_aneg(struct phy_device *phydev)450{451	int changed = 0;452	int err;453 454	err = marvell_set_polarity(phydev, phydev->mdix_ctrl);455	if (err < 0)456		return err;457 458	changed = err;459 460	err = phy_write(phydev, MII_M1111_PHY_LED_CONTROL,461			MII_M1111_PHY_LED_DIRECT);462	if (err < 0)463		return err;464 465	err = genphy_config_aneg(phydev);466	if (err < 0)467		return err;468 469	if (phydev->autoneg != AUTONEG_ENABLE || changed) {470		/* A write to speed/duplex bits (that is performed by471		 * genphy_config_aneg() call above) must be followed by472		 * a software reset. Otherwise, the write has no effect.473		 */474		err = genphy_soft_reset(phydev);475		if (err < 0)476			return err;477	}478 479	return 0;480}481 482static int m88e1101_config_aneg(struct phy_device *phydev)483{484	int err;485 486	/* This Marvell PHY has an errata which requires487	 * that certain registers get written in order488	 * to restart autonegotiation489	 */490	err = genphy_soft_reset(phydev);491	if (err < 0)492		return err;493 494	err = phy_write(phydev, 0x1d, 0x1f);495	if (err < 0)496		return err;497 498	err = phy_write(phydev, 0x1e, 0x200c);499	if (err < 0)500		return err;501 502	err = phy_write(phydev, 0x1d, 0x5);503	if (err < 0)504		return err;505 506	err = phy_write(phydev, 0x1e, 0);507	if (err < 0)508		return err;509 510	err = phy_write(phydev, 0x1e, 0x100);511	if (err < 0)512		return err;513 514	return marvell_config_aneg(phydev);515}516 517#if IS_ENABLED(CONFIG_OF_MDIO)518/* Set and/or override some configuration registers based on the519 * marvell,reg-init property stored in the of_node for the phydev.520 *521 * marvell,reg-init = <reg-page reg mask value>,...;522 *523 * There may be one or more sets of <reg-page reg mask value>:524 *525 * reg-page: which register bank to use.526 * reg: the register.527 * mask: if non-zero, ANDed with existing register value.528 * value: ORed with the masked value and written to the regiser.529 *530 */531static int marvell_of_reg_init(struct phy_device *phydev)532{533	const __be32 *paddr;534	int len, i, saved_page, current_page, ret = 0;535 536	if (!phydev->mdio.dev.of_node)537		return 0;538 539	paddr = of_get_property(phydev->mdio.dev.of_node,540				"marvell,reg-init", &len);541	if (!paddr || len < (4 * sizeof(*paddr)))542		return 0;543 544	saved_page = phy_save_page(phydev);545	if (saved_page < 0)546		goto err;547	current_page = saved_page;548 549	len /= sizeof(*paddr);550	for (i = 0; i < len - 3; i += 4) {551		u16 page = be32_to_cpup(paddr + i);552		u16 reg = be32_to_cpup(paddr + i + 1);553		u16 mask = be32_to_cpup(paddr + i + 2);554		u16 val_bits = be32_to_cpup(paddr + i + 3);555		int val;556 557		if (page != current_page) {558			current_page = page;559			ret = marvell_write_page(phydev, page);560			if (ret < 0)561				goto err;562		}563 564		val = 0;565		if (mask) {566			val = __phy_read(phydev, reg);567			if (val < 0) {568				ret = val;569				goto err;570			}571			val &= mask;572		}573		val |= val_bits;574 575		ret = __phy_write(phydev, reg, val);576		if (ret < 0)577			goto err;578	}579err:580	return phy_restore_page(phydev, saved_page, ret);581}582#else583static int marvell_of_reg_init(struct phy_device *phydev)584{585	return 0;586}587#endif /* CONFIG_OF_MDIO */588 589static int m88e1121_config_aneg_rgmii_delays(struct phy_device *phydev)590{591	int mscr;592 593	if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)594		mscr = MII_88E1121_PHY_MSCR_RX_DELAY |595		       MII_88E1121_PHY_MSCR_TX_DELAY;596	else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID)597		mscr = MII_88E1121_PHY_MSCR_RX_DELAY;598	else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)599		mscr = MII_88E1121_PHY_MSCR_TX_DELAY;600	else601		mscr = 0;602 603	return phy_modify_paged_changed(phydev, MII_MARVELL_MSCR_PAGE,604					MII_88E1121_PHY_MSCR_REG,605					MII_88E1121_PHY_MSCR_DELAY_MASK, mscr);606}607 608static int m88e1121_config_aneg(struct phy_device *phydev)609{610	int changed = 0;611	int err = 0;612 613	if (phy_interface_is_rgmii(phydev)) {614		err = m88e1121_config_aneg_rgmii_delays(phydev);615		if (err < 0)616			return err;617	}618 619	changed = err;620 621	err = marvell_set_polarity(phydev, phydev->mdix_ctrl);622	if (err < 0)623		return err;624 625	changed |= err;626 627	err = genphy_config_aneg(phydev);628	if (err < 0)629		return err;630 631	if (phydev->autoneg != AUTONEG_ENABLE || changed) {632		/* A software reset is used to ensure a "commit" of the633		 * changes is done.634		 */635		err = genphy_soft_reset(phydev);636		if (err < 0)637			return err;638	}639 640	return 0;641}642 643static int m88e1318_config_aneg(struct phy_device *phydev)644{645	int err;646 647	err = phy_modify_paged(phydev, MII_MARVELL_MSCR_PAGE,648			       MII_88E1318S_PHY_MSCR1_REG,649			       0, MII_88E1318S_PHY_MSCR1_PAD_ODD);650	if (err < 0)651		return err;652 653	return m88e1121_config_aneg(phydev);654}655 656/**657 * linkmode_adv_to_fiber_adv_t658 * @advertise: the linkmode advertisement settings659 *660 * A small helper function that translates linkmode advertisement661 * settings to phy autonegotiation advertisements for the MII_ADV662 * register for fiber link.663 */664static inline u32 linkmode_adv_to_fiber_adv_t(unsigned long *advertise)665{666	u32 result = 0;667 668	if (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT, advertise))669		result |= ADVERTISE_1000XHALF;670	if (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, advertise))671		result |= ADVERTISE_1000XFULL;672 673	if (linkmode_test_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, advertise) &&674	    linkmode_test_bit(ETHTOOL_LINK_MODE_Pause_BIT, advertise))675		result |= ADVERTISE_1000XPSE_ASYM;676	else if (linkmode_test_bit(ETHTOOL_LINK_MODE_Pause_BIT, advertise))677		result |= ADVERTISE_1000XPAUSE;678 679	return result;680}681 682/**683 * marvell_config_aneg_fiber - restart auto-negotiation or write BMCR684 * @phydev: target phy_device struct685 *686 * Description: If auto-negotiation is enabled, we configure the687 *   advertising, and then restart auto-negotiation.  If it is not688 *   enabled, then we write the BMCR. Adapted for fiber link in689 *   some Marvell's devices.690 */691static int marvell_config_aneg_fiber(struct phy_device *phydev)692{693	int changed = 0;694	int err;695	u16 adv;696 697	if (phydev->autoneg != AUTONEG_ENABLE)698		return genphy_setup_forced(phydev);699 700	/* Only allow advertising what this PHY supports */701	linkmode_and(phydev->advertising, phydev->advertising,702		     phydev->supported);703 704	adv = linkmode_adv_to_fiber_adv_t(phydev->advertising);705 706	/* Setup fiber advertisement */707	err = phy_modify_changed(phydev, MII_ADVERTISE,708				 ADVERTISE_1000XHALF | ADVERTISE_1000XFULL |709				 ADVERTISE_1000XPAUSE | ADVERTISE_1000XPSE_ASYM,710				 adv);711	if (err < 0)712		return err;713	if (err > 0)714		changed = 1;715 716	return genphy_check_and_restart_aneg(phydev, changed);717}718 719static int m88e1111_config_aneg(struct phy_device *phydev)720{721	int extsr = phy_read(phydev, MII_M1111_PHY_EXT_SR);722	int err;723 724	if (extsr < 0)725		return extsr;726 727	/* If not using SGMII or copper 1000BaseX modes, use normal process.728	 * Steps below are only required for these modes.729	 */730	if (phydev->interface != PHY_INTERFACE_MODE_SGMII &&731	    (extsr & MII_M1111_HWCFG_MODE_MASK) !=732	    MII_M1111_HWCFG_MODE_COPPER_1000X_AN)733		return marvell_config_aneg(phydev);734 735	err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);736	if (err < 0)737		goto error;738 739	/* Configure the copper link first */740	err = marvell_config_aneg(phydev);741	if (err < 0)742		goto error;743 744	/* Then the fiber link */745	err = marvell_set_page(phydev, MII_MARVELL_FIBER_PAGE);746	if (err < 0)747		goto error;748 749	if (phydev->interface == PHY_INTERFACE_MODE_SGMII)750		/* Do not touch the fiber advertisement if we're in copper->sgmii mode.751		 * Just ensure that SGMII-side autonegotiation is enabled.752		 * If we switched from some other mode to SGMII it may not be.753		 */754		err = genphy_check_and_restart_aneg(phydev, false);755	else756		err = marvell_config_aneg_fiber(phydev);757	if (err < 0)758		goto error;759 760	return marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);761 762error:763	marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);764	return err;765}766 767static int m88e1510_config_aneg(struct phy_device *phydev)768{769	int err;770 771	err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);772	if (err < 0)773		goto error;774 775	/* Configure the copper link first */776	err = m88e1318_config_aneg(phydev);777	if (err < 0)778		goto error;779 780	/* Do not touch the fiber page if we're in copper->sgmii mode */781	if (phydev->interface == PHY_INTERFACE_MODE_SGMII)782		return 0;783 784	/* Then the fiber link */785	err = marvell_set_page(phydev, MII_MARVELL_FIBER_PAGE);786	if (err < 0)787		goto error;788 789	err = marvell_config_aneg_fiber(phydev);790	if (err < 0)791		goto error;792 793	return marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);794 795error:796	marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);797	return err;798}799 800static void marvell_config_led(struct phy_device *phydev)801{802	u16 def_config;803	int err;804 805	switch (MARVELL_PHY_FAMILY_ID(phydev->phy_id)) {806	/* Default PHY LED config: LED[0] .. Link, LED[1] .. Activity */807	case MARVELL_PHY_FAMILY_ID(MARVELL_PHY_ID_88E1121R):808	case MARVELL_PHY_FAMILY_ID(MARVELL_PHY_ID_88E1318S):809		def_config = MII_88E1121_PHY_LED_DEF;810		break;811	/* Default PHY LED config:812	 * LED[0] .. 1000Mbps Link813	 * LED[1] .. 100Mbps Link814	 * LED[2] .. Blink, Activity815	 */816	case MARVELL_PHY_FAMILY_ID(MARVELL_PHY_ID_88E1510):817		if (phydev->dev_flags & MARVELL_PHY_LED0_LINK_LED1_ACTIVE)818			def_config = MII_88E1510_PHY_LED0_LINK_LED1_ACTIVE;819		else820			def_config = MII_88E1510_PHY_LED_DEF;821		break;822	default:823		return;824	}825 826	err = phy_write_paged(phydev, MII_MARVELL_LED_PAGE, MII_PHY_LED_CTRL,827			      def_config);828	if (err < 0)829		phydev_warn(phydev, "Fail to config marvell phy LED.\n");830}831 832static int marvell_config_init(struct phy_device *phydev)833{834	/* Set default LED */835	marvell_config_led(phydev);836 837	/* Set registers from marvell,reg-init DT property */838	return marvell_of_reg_init(phydev);839}840 841static int m88e3016_config_init(struct phy_device *phydev)842{843	int ret;844 845	/* Enable Scrambler and Auto-Crossover */846	ret = phy_modify(phydev, MII_88E3016_PHY_SPEC_CTRL,847			 MII_88E3016_DISABLE_SCRAMBLER,848			 MII_88E3016_AUTO_MDIX_CROSSOVER);849	if (ret < 0)850		return ret;851 852	return marvell_config_init(phydev);853}854 855static int m88e1111_config_init_hwcfg_mode(struct phy_device *phydev,856					   u16 mode,857					   int fibre_copper_auto)858{859	if (fibre_copper_auto)860		mode |= MII_M1111_HWCFG_FIBER_COPPER_AUTO;861 862	return phy_modify(phydev, MII_M1111_PHY_EXT_SR,863			  MII_M1111_HWCFG_MODE_MASK |864			  MII_M1111_HWCFG_FIBER_COPPER_AUTO |865			  MII_M1111_HWCFG_FIBER_COPPER_RES,866			  mode);867}868 869static int m88e1111_config_init_rgmii_delays(struct phy_device *phydev)870{871	int delay;872 873	switch (phydev->interface) {874	case PHY_INTERFACE_MODE_RGMII_ID:875		delay = MII_M1111_RGMII_RX_DELAY | MII_M1111_RGMII_TX_DELAY;876		break;877	case PHY_INTERFACE_MODE_RGMII_RXID:878		delay = MII_M1111_RGMII_RX_DELAY;879		break;880	case PHY_INTERFACE_MODE_RGMII_TXID:881		delay = MII_M1111_RGMII_TX_DELAY;882		break;883	default:884		delay = 0;885		break;886	}887 888	return phy_modify(phydev, MII_M1111_PHY_EXT_CR,889			  MII_M1111_RGMII_RX_DELAY | MII_M1111_RGMII_TX_DELAY,890			  delay);891}892 893static int m88e1111_config_init_rgmii(struct phy_device *phydev)894{895	int temp;896	int err;897 898	err = m88e1111_config_init_rgmii_delays(phydev);899	if (err < 0)900		return err;901 902	temp = phy_read(phydev, MII_M1111_PHY_EXT_SR);903	if (temp < 0)904		return temp;905 906	temp &= ~(MII_M1111_HWCFG_MODE_MASK);907 908	if (temp & MII_M1111_HWCFG_FIBER_COPPER_RES)909		temp |= MII_M1111_HWCFG_MODE_FIBER_RGMII;910	else911		temp |= MII_M1111_HWCFG_MODE_COPPER_RGMII;912 913	return phy_write(phydev, MII_M1111_PHY_EXT_SR, temp);914}915 916static int m88e1111_config_init_sgmii(struct phy_device *phydev)917{918	int err;919 920	err = m88e1111_config_init_hwcfg_mode(921		phydev,922		MII_M1111_HWCFG_MODE_SGMII_NO_CLK,923		MII_M1111_HWCFG_FIBER_COPPER_AUTO);924	if (err < 0)925		return err;926 927	/* make sure copper is selected */928	return marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);929}930 931static int m88e1111_config_init_rtbi(struct phy_device *phydev)932{933	int err;934 935	err = m88e1111_config_init_rgmii_delays(phydev);936	if (err < 0)937		return err;938 939	err = m88e1111_config_init_hwcfg_mode(940		phydev,941		MII_M1111_HWCFG_MODE_RTBI,942		MII_M1111_HWCFG_FIBER_COPPER_AUTO);943	if (err < 0)944		return err;945 946	/* soft reset */947	err = genphy_soft_reset(phydev);948	if (err < 0)949		return err;950 951	return m88e1111_config_init_hwcfg_mode(952		phydev,953		MII_M1111_HWCFG_MODE_RTBI,954		MII_M1111_HWCFG_FIBER_COPPER_AUTO);955}956 957static int m88e1111_config_init_1000basex(struct phy_device *phydev)958{959	int extsr = phy_read(phydev, MII_M1111_PHY_EXT_SR);960	int err, mode;961 962	if (extsr < 0)963		return extsr;964 965	/* If using copper mode, ensure 1000BaseX auto-negotiation is enabled.966	 * FIXME: this does not actually enable 1000BaseX auto-negotiation if967	 * it was previously disabled in the Fiber BMCR!968	 */969	mode = extsr & MII_M1111_HWCFG_MODE_MASK;970	if (mode == MII_M1111_HWCFG_MODE_COPPER_1000X_NOAN) {971		err = phy_modify(phydev, MII_M1111_PHY_EXT_SR,972				 MII_M1111_HWCFG_MODE_MASK |973				 MII_M1111_HWCFG_SERIAL_AN_BYPASS,974				 MII_M1111_HWCFG_MODE_COPPER_1000X_AN |975				 MII_M1111_HWCFG_SERIAL_AN_BYPASS);976		if (err < 0)977			return err;978	}979	return 0;980}981 982static int m88e1111_config_init(struct phy_device *phydev)983{984	int err;985 986	if (phy_interface_is_rgmii(phydev)) {987		err = m88e1111_config_init_rgmii(phydev);988		if (err < 0)989			return err;990	}991 992	if (phydev->interface == PHY_INTERFACE_MODE_SGMII) {993		err = m88e1111_config_init_sgmii(phydev);994		if (err < 0)995			return err;996	}997 998	if (phydev->interface == PHY_INTERFACE_MODE_RTBI) {999		err = m88e1111_config_init_rtbi(phydev);1000		if (err < 0)1001			return err;1002	}1003 1004	if (phydev->interface == PHY_INTERFACE_MODE_1000BASEX) {1005		err = m88e1111_config_init_1000basex(phydev);1006		if (err < 0)1007			return err;1008	}1009 1010	err = marvell_of_reg_init(phydev);1011	if (err < 0)1012		return err;1013 1014	err = genphy_soft_reset(phydev);1015	if (err < 0)1016		return err;1017 1018	if (phydev->interface == PHY_INTERFACE_MODE_SGMII) {1019		/* If the HWCFG_MODE was changed from another mode (such as1020		 * 1000BaseX) to SGMII, the state of the support bits may have1021		 * also changed now that the PHY has been reset.1022		 * Update the PHY abilities accordingly.1023		 */1024		err = genphy_read_abilities(phydev);1025		linkmode_or(phydev->advertising, phydev->advertising,1026			    phydev->supported);1027	}1028	return err;1029}1030 1031static int m88e1111_get_downshift(struct phy_device *phydev, u8 *data)1032{1033	int val, cnt, enable;1034 1035	val = phy_read(phydev, MII_M1111_PHY_EXT_CR);1036	if (val < 0)1037		return val;1038 1039	enable = FIELD_GET(MII_M1111_PHY_EXT_CR_DOWNSHIFT_EN, val);1040	cnt = FIELD_GET(MII_M1111_PHY_EXT_CR_DOWNSHIFT_MASK, val) + 1;1041 1042	*data = enable ? cnt : DOWNSHIFT_DEV_DISABLE;1043 1044	return 0;1045}1046 1047static int m88e1111_set_downshift(struct phy_device *phydev, u8 cnt)1048{1049	int val, err;1050 1051	if (cnt > MII_M1111_PHY_EXT_CR_DOWNSHIFT_MAX)1052		return -E2BIG;1053 1054	if (!cnt) {1055		err = phy_clear_bits(phydev, MII_M1111_PHY_EXT_CR,1056				     MII_M1111_PHY_EXT_CR_DOWNSHIFT_EN);1057	} else {1058		val = MII_M1111_PHY_EXT_CR_DOWNSHIFT_EN;1059		val |= FIELD_PREP(MII_M1111_PHY_EXT_CR_DOWNSHIFT_MASK, cnt - 1);1060 1061		err = phy_modify(phydev, MII_M1111_PHY_EXT_CR,1062				 MII_M1111_PHY_EXT_CR_DOWNSHIFT_EN |1063				 MII_M1111_PHY_EXT_CR_DOWNSHIFT_MASK,1064				 val);1065	}1066 1067	if (err < 0)1068		return err;1069 1070	return genphy_soft_reset(phydev);1071}1072 1073static int m88e1111_get_tunable(struct phy_device *phydev,1074				struct ethtool_tunable *tuna, void *data)1075{1076	switch (tuna->id) {1077	case ETHTOOL_PHY_DOWNSHIFT:1078		return m88e1111_get_downshift(phydev, data);1079	default:1080		return -EOPNOTSUPP;1081	}1082}1083 1084static int m88e1111_set_tunable(struct phy_device *phydev,1085				struct ethtool_tunable *tuna, const void *data)1086{1087	switch (tuna->id) {1088	case ETHTOOL_PHY_DOWNSHIFT:1089		return m88e1111_set_downshift(phydev, *(const u8 *)data);1090	default:1091		return -EOPNOTSUPP;1092	}1093}1094 1095static int m88e1011_get_downshift(struct phy_device *phydev, u8 *data)1096{1097	int val, cnt, enable;1098 1099	val = phy_read(phydev, MII_M1011_PHY_SCR);1100	if (val < 0)1101		return val;1102 1103	enable = FIELD_GET(MII_M1011_PHY_SCR_DOWNSHIFT_EN, val);1104	cnt = FIELD_GET(MII_M1011_PHY_SCR_DOWNSHIFT_MASK, val) + 1;1105 1106	*data = enable ? cnt : DOWNSHIFT_DEV_DISABLE;1107 1108	return 0;1109}1110 1111static int m88e1011_set_downshift(struct phy_device *phydev, u8 cnt)1112{1113	int val, err;1114 1115	if (cnt > MII_M1011_PHY_SCR_DOWNSHIFT_MAX)1116		return -E2BIG;1117 1118	if (!cnt) {1119		err = phy_clear_bits(phydev, MII_M1011_PHY_SCR,1120				     MII_M1011_PHY_SCR_DOWNSHIFT_EN);1121	} else {1122		val = MII_M1011_PHY_SCR_DOWNSHIFT_EN;1123		val |= FIELD_PREP(MII_M1011_PHY_SCR_DOWNSHIFT_MASK, cnt - 1);1124 1125		err = phy_modify(phydev, MII_M1011_PHY_SCR,1126				 MII_M1011_PHY_SCR_DOWNSHIFT_EN |1127				 MII_M1011_PHY_SCR_DOWNSHIFT_MASK,1128				 val);1129	}1130 1131	if (err < 0)1132		return err;1133 1134	return genphy_soft_reset(phydev);1135}1136 1137static int m88e1011_get_tunable(struct phy_device *phydev,1138				struct ethtool_tunable *tuna, void *data)1139{1140	switch (tuna->id) {1141	case ETHTOOL_PHY_DOWNSHIFT:1142		return m88e1011_get_downshift(phydev, data);1143	default:1144		return -EOPNOTSUPP;1145	}1146}1147 1148static int m88e1011_set_tunable(struct phy_device *phydev,1149				struct ethtool_tunable *tuna, const void *data)1150{1151	switch (tuna->id) {1152	case ETHTOOL_PHY_DOWNSHIFT:1153		return m88e1011_set_downshift(phydev, *(const u8 *)data);1154	default:1155		return -EOPNOTSUPP;1156	}1157}1158 1159static int m88e1112_config_init(struct phy_device *phydev)1160{1161	int err;1162 1163	err = m88e1011_set_downshift(phydev, 3);1164	if (err < 0)1165		return err;1166 1167	return m88e1111_config_init(phydev);1168}1169 1170static int m88e1111gbe_config_init(struct phy_device *phydev)1171{1172	int err;1173 1174	err = m88e1111_set_downshift(phydev, 3);1175	if (err < 0)1176		return err;1177 1178	return m88e1111_config_init(phydev);1179}1180 1181static int marvell_1011gbe_config_init(struct phy_device *phydev)1182{1183	int err;1184 1185	err = m88e1011_set_downshift(phydev, 3);1186	if (err < 0)1187		return err;1188 1189	return marvell_config_init(phydev);1190}1191static int m88e1116r_config_init(struct phy_device *phydev)1192{1193	int err;1194 1195	err = genphy_soft_reset(phydev);1196	if (err < 0)1197		return err;1198 1199	msleep(500);1200 1201	err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);1202	if (err < 0)1203		return err;1204 1205	err = marvell_set_polarity(phydev, phydev->mdix_ctrl);1206	if (err < 0)1207		return err;1208 1209	err = m88e1011_set_downshift(phydev, 8);1210	if (err < 0)1211		return err;1212 1213	if (phy_interface_is_rgmii(phydev)) {1214		err = m88e1121_config_aneg_rgmii_delays(phydev);1215		if (err < 0)1216			return err;1217	}1218 1219	err = genphy_soft_reset(phydev);1220	if (err < 0)1221		return err;1222 1223	return marvell_config_init(phydev);1224}1225 1226static int m88e1318_config_init(struct phy_device *phydev)1227{1228	if (phy_interrupt_is_valid(phydev)) {1229		int err = phy_modify_paged(1230			phydev, MII_MARVELL_LED_PAGE,1231			MII_88E1318S_PHY_LED_TCR,1232			MII_88E1318S_PHY_LED_TCR_FORCE_INT,1233			MII_88E1318S_PHY_LED_TCR_INTn_ENABLE |1234			MII_88E1318S_PHY_LED_TCR_INT_ACTIVE_LOW);1235		if (err < 0)1236			return err;1237	}1238 1239	return marvell_config_init(phydev);1240}1241 1242static int m88e1510_config_init(struct phy_device *phydev)1243{1244	static const struct {1245		u16 reg17, reg16;1246	} errata_vals[] = {1247		{ 0x214b, 0x2144 },1248		{ 0x0c28, 0x2146 },1249		{ 0xb233, 0x214d },1250		{ 0xcc0c, 0x2159 },1251	};1252	int err;1253	int i;1254 1255	/* As per Marvell Release Notes - Alaska 88E1510/88E1518/88E1512/1256	 * 88E1514 Rev A0, Errata Section 5.1:1257	 * If EEE is intended to be used, the following register writes1258	 * must be done once after every hardware reset.1259	 */1260	err = marvell_set_page(phydev, 0x00FF);1261	if (err < 0)1262		return err;1263 1264	for (i = 0; i < ARRAY_SIZE(errata_vals); ++i) {1265		err = phy_write(phydev, 17, errata_vals[i].reg17);1266		if (err)1267			return err;1268		err = phy_write(phydev, 16, errata_vals[i].reg16);1269		if (err)1270			return err;1271	}1272 1273	err = marvell_set_page(phydev, 0x00FB);1274	if (err < 0)1275		return err;1276	err = phy_write(phydev, 07, 0xC00D);1277	if (err < 0)1278		return err;1279	err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);1280	if (err < 0)1281		return err;1282 1283	/* SGMII-to-Copper mode initialization */1284	if (phydev->interface == PHY_INTERFACE_MODE_SGMII) {1285		/* Select page 18 */1286		err = marvell_set_page(phydev, 18);1287		if (err < 0)1288			return err;1289 1290		/* In reg 20, write MODE[2:0] = 0x1 (SGMII to Copper) */1291		err = phy_modify(phydev, MII_88E1510_GEN_CTRL_REG_1,1292				 MII_88E1510_GEN_CTRL_REG_1_MODE_MASK,1293				 MII_88E1510_GEN_CTRL_REG_1_MODE_SGMII);1294		if (err < 0)1295			return err;1296 1297		/* PHY reset is necessary after changing MODE[2:0] */1298		err = phy_set_bits(phydev, MII_88E1510_GEN_CTRL_REG_1,1299				   MII_88E1510_GEN_CTRL_REG_1_RESET);1300		if (err < 0)1301			return err;1302 1303		/* Reset page selection */1304		err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);1305		if (err < 0)1306			return err;1307	}1308	err = m88e1011_set_downshift(phydev, 3);1309	if (err < 0)1310		return err;1311 1312	return m88e1318_config_init(phydev);1313}1314 1315static int m88e1118_config_aneg(struct phy_device *phydev)1316{1317	int err;1318 1319	err = marvell_set_polarity(phydev, phydev->mdix_ctrl);1320	if (err < 0)1321		return err;1322 1323	err = genphy_config_aneg(phydev);1324	if (err < 0)1325		return err;1326 1327	return genphy_soft_reset(phydev);1328}1329 1330static int m88e1118_config_init(struct phy_device *phydev)1331{1332	u16 leds;1333	int err;1334 1335	/* Enable 1000 Mbit */1336	err = phy_write_paged(phydev, MII_MARVELL_MSCR_PAGE,1337			      MII_88E1121_PHY_MSCR_REG, 0x1070);1338	if (err < 0)1339		return err;1340 1341	if (phy_interface_is_rgmii(phydev)) {1342		err = m88e1121_config_aneg_rgmii_delays(phydev);1343		if (err < 0)1344			return err;1345	}1346 1347	/* Adjust LED Control */1348	if (phydev->dev_flags & MARVELL_PHY_M1118_DNS323_LEDS)1349		leds = 0x1100;1350	else1351		leds = 0x021e;1352 1353	err = phy_write_paged(phydev, MII_MARVELL_LED_PAGE, 0x10, leds);1354	if (err < 0)1355		return err;1356 1357	err = marvell_of_reg_init(phydev);1358	if (err < 0)1359		return err;1360 1361	/* Reset page register */1362	err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);1363	if (err < 0)1364		return err;1365 1366	return genphy_soft_reset(phydev);1367}1368 1369static int m88e1149_config_init(struct phy_device *phydev)1370{1371	int err;1372 1373	/* Change address */1374	err = marvell_set_page(phydev, MII_MARVELL_MSCR_PAGE);1375	if (err < 0)1376		return err;1377 1378	/* Enable 1000 Mbit */1379	err = phy_write(phydev, 0x15, 0x1048);1380	if (err < 0)1381		return err;1382 1383	err = marvell_of_reg_init(phydev);1384	if (err < 0)1385		return err;1386 1387	/* Reset address */1388	err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);1389	if (err < 0)1390		return err;1391 1392	return genphy_soft_reset(phydev);1393}1394 1395static int m88e1145_config_init_rgmii(struct phy_device *phydev)1396{1397	int err;1398 1399	err = m88e1111_config_init_rgmii_delays(phydev);1400	if (err < 0)1401		return err;1402 1403	if (phydev->dev_flags & MARVELL_PHY_M1145_FLAGS_RESISTANCE) {1404		err = phy_write(phydev, 0x1d, 0x0012);1405		if (err < 0)1406			return err;1407 1408		err = phy_modify(phydev, 0x1e, 0x0fc0,1409				 2 << 9 | /* 36 ohm */1410				 2 << 6); /* 39 ohm */1411		if (err < 0)1412			return err;1413 1414		err = phy_write(phydev, 0x1d, 0x3);1415		if (err < 0)1416			return err;1417 1418		err = phy_write(phydev, 0x1e, 0x8000);1419	}1420	return err;1421}1422 1423static int m88e1145_config_init_sgmii(struct phy_device *phydev)1424{1425	return m88e1111_config_init_hwcfg_mode(1426		phydev, MII_M1111_HWCFG_MODE_SGMII_NO_CLK,1427		MII_M1111_HWCFG_FIBER_COPPER_AUTO);1428}1429 1430static int m88e1145_config_init(struct phy_device *phydev)1431{1432	int err;1433 1434	/* Take care of errata E0 & E1 */1435	err = phy_write(phydev, 0x1d, 0x001b);1436	if (err < 0)1437		return err;1438 1439	err = phy_write(phydev, 0x1e, 0x418f);1440	if (err < 0)1441		return err;1442 1443	err = phy_write(phydev, 0x1d, 0x0016);1444	if (err < 0)1445		return err;1446 1447	err = phy_write(phydev, 0x1e, 0xa2da);1448	if (err < 0)1449		return err;1450 1451	if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) {1452		err = m88e1145_config_init_rgmii(phydev);1453		if (err < 0)1454			return err;1455	}1456 1457	if (phydev->interface == PHY_INTERFACE_MODE_SGMII) {1458		err = m88e1145_config_init_sgmii(phydev);1459		if (err < 0)1460			return err;1461	}1462	err = m88e1111_set_downshift(phydev, 3);1463	if (err < 0)1464		return err;1465 1466	err = marvell_of_reg_init(phydev);1467	if (err < 0)1468		return err;1469 1470	return 0;1471}1472 1473static int m88e1540_get_fld(struct phy_device *phydev, u8 *msecs)1474{1475	int val;1476 1477	val = phy_read(phydev, MII_88E1540_COPPER_CTRL3);1478	if (val < 0)1479		return val;1480 1481	if (!(val & MII_88E1540_COPPER_CTRL3_FAST_LINK_DOWN)) {1482		*msecs = ETHTOOL_PHY_FAST_LINK_DOWN_OFF;1483		return 0;1484	}1485 1486	val = FIELD_GET(MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_MASK, val);1487 1488	switch (val) {1489	case MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_00MS:1490		*msecs = 0;1491		break;1492	case MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_10MS:1493		*msecs = 10;1494		break;1495	case MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_20MS:1496		*msecs = 20;1497		break;1498	case MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_40MS:1499		*msecs = 40;1500		break;1501	default:1502		return -EINVAL;1503	}1504 1505	return 0;1506}1507 1508static int m88e1540_set_fld(struct phy_device *phydev, const u8 *msecs)1509{1510	struct ethtool_keee eee;1511	int val, ret;1512 1513	if (*msecs == ETHTOOL_PHY_FAST_LINK_DOWN_OFF)1514		return phy_clear_bits(phydev, MII_88E1540_COPPER_CTRL3,1515				      MII_88E1540_COPPER_CTRL3_FAST_LINK_DOWN);1516 1517	/* According to the Marvell data sheet EEE must be disabled for1518	 * Fast Link Down detection to work properly1519	 */1520	ret = genphy_c45_ethtool_get_eee(phydev, &eee);1521	if (!ret && eee.eee_enabled) {1522		phydev_warn(phydev, "Fast Link Down detection requires EEE to be disabled!\n");1523		return -EBUSY;1524	}1525 1526	if (*msecs <= 5)1527		val = MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_00MS;1528	else if (*msecs <= 15)1529		val = MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_10MS;1530	else if (*msecs <= 30)1531		val = MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_20MS;1532	else1533		val = MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_40MS;1534 1535	val = FIELD_PREP(MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_MASK, val);1536 1537	ret = phy_modify(phydev, MII_88E1540_COPPER_CTRL3,1538			 MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_MASK, val);1539	if (ret)1540		return ret;1541 1542	return phy_set_bits(phydev, MII_88E1540_COPPER_CTRL3,1543			    MII_88E1540_COPPER_CTRL3_FAST_LINK_DOWN);1544}1545 1546static int m88e1540_get_tunable(struct phy_device *phydev,1547				struct ethtool_tunable *tuna, void *data)1548{1549	switch (tuna->id) {1550	case ETHTOOL_PHY_FAST_LINK_DOWN:1551		return m88e1540_get_fld(phydev, data);1552	case ETHTOOL_PHY_DOWNSHIFT:1553		return m88e1011_get_downshift(phydev, data);1554	default:1555		return -EOPNOTSUPP;1556	}1557}1558 1559static int m88e1540_set_tunable(struct phy_device *phydev,1560				struct ethtool_tunable *tuna, const void *data)1561{1562	switch (tuna->id) {1563	case ETHTOOL_PHY_FAST_LINK_DOWN:1564		return m88e1540_set_fld(phydev, data);1565	case ETHTOOL_PHY_DOWNSHIFT:1566		return m88e1011_set_downshift(phydev, *(const u8 *)data);1567	default:1568		return -EOPNOTSUPP;1569	}1570}1571 1572/* The VOD can be out of specification on link up. Poke an1573 * undocumented register, in an undocumented page, with a magic value1574 * to fix this.1575 */1576static int m88e6390_errata(struct phy_device *phydev)1577{1578	int err;1579 1580	err = phy_write(phydev, MII_BMCR,1581			BMCR_ANENABLE | BMCR_SPEED1000 | BMCR_FULLDPLX);1582	if (err)1583		return err;1584 1585	usleep_range(300, 400);1586 1587	err = phy_write_paged(phydev, 0xf8, 0x08, 0x36);1588	if (err)1589		return err;1590 1591	return genphy_soft_reset(phydev);1592}1593 1594static int m88e6390_config_aneg(struct phy_device *phydev)1595{1596	int err;1597 1598	err = m88e6390_errata(phydev);1599	if (err)1600		return err;1601 1602	return m88e1510_config_aneg(phydev);1603}1604 1605/**1606 * fiber_lpa_mod_linkmode_lpa_t1607 * @advertising: the linkmode advertisement settings1608 * @lpa: value of the MII_LPA register for fiber link1609 *1610 * A small helper function that translates MII_LPA bits to linkmode LP1611 * advertisement settings. Other bits in advertising are left1612 * unchanged.1613 */1614static void fiber_lpa_mod_linkmode_lpa_t(unsigned long *advertising, u32 lpa)1615{1616	linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT,1617			 advertising, lpa & LPA_1000XHALF);1618 1619	linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,1620			 advertising, lpa & LPA_1000XFULL);1621}1622 1623static int marvell_read_status_page_an(struct phy_device *phydev,1624				       int fiber, int status)1625{1626	int lpa;1627	int err;1628 1629	if (!(status & MII_M1011_PHY_STATUS_RESOLVED)) {1630		phydev->link = 0;1631		return 0;1632	}1633 1634	if (status & MII_M1011_PHY_STATUS_FULLDUPLEX)1635		phydev->duplex = DUPLEX_FULL;1636	else1637		phydev->duplex = DUPLEX_HALF;1638 1639	switch (status & MII_M1011_PHY_STATUS_SPD_MASK) {1640	case MII_M1011_PHY_STATUS_1000:1641		phydev->speed = SPEED_1000;1642		break;1643 1644	case MII_M1011_PHY_STATUS_100:1645		phydev->speed = SPEED_100;1646		break;1647 1648	default:1649		phydev->speed = SPEED_10;1650		break;1651	}1652 1653	if (!fiber) {1654		err = genphy_read_lpa(phydev);1655		if (err < 0)1656			return err;1657 1658		phy_resolve_aneg_pause(phydev);1659	} else {1660		lpa = phy_read(phydev, MII_LPA);1661		if (lpa < 0)1662			return lpa;1663 1664		/* The fiber link is only 1000M capable */1665		fiber_lpa_mod_linkmode_lpa_t(phydev->lp_advertising, lpa);1666 1667		if (phydev->duplex == DUPLEX_FULL) {1668			if (!(lpa & LPA_PAUSE_FIBER)) {1669				phydev->pause = 0;1670				phydev->asym_pause = 0;1671			} else if ((lpa & LPA_PAUSE_ASYM_FIBER)) {1672				phydev->pause = 1;1673				phydev->asym_pause = 1;1674			} else {1675				phydev->pause = 1;1676				phydev->asym_pause = 0;1677			}1678		}1679	}1680 1681	return 0;1682}1683 1684/* marvell_read_status_page1685 *1686 * Description:1687 *   Check the link, then figure out the current state1688 *   by comparing what we advertise with what the link partner1689 *   advertises.  Start by checking the gigabit possibilities,1690 *   then move on to 10/100.1691 */1692static int marvell_read_status_page(struct phy_device *phydev, int page)1693{1694	int status;1695	int fiber;1696	int err;1697 1698	status = phy_read(phydev, MII_M1011_PHY_STATUS);1699	if (status < 0)1700		return status;1701 1702	/* Use the generic register for copper link status,1703	 * and the PHY status register for fiber link status.1704	 */1705	if (page == MII_MARVELL_FIBER_PAGE) {1706		phydev->link = !!(status & MII_M1011_PHY_STATUS_LINK);1707	} else {1708		err = genphy_update_link(phydev);1709		if (err)1710			return err;1711	}1712 1713	if (page == MII_MARVELL_FIBER_PAGE)1714		fiber = 1;1715	else1716		fiber = 0;1717 1718	linkmode_zero(phydev->lp_advertising);1719	phydev->pause = 0;1720	phydev->asym_pause = 0;1721	phydev->speed = SPEED_UNKNOWN;1722	phydev->duplex = DUPLEX_UNKNOWN;1723	phydev->port = fiber ? PORT_FIBRE : PORT_TP;1724 1725	if (phydev->autoneg == AUTONEG_ENABLE)1726		err = marvell_read_status_page_an(phydev, fiber, status);1727	else1728		err = genphy_read_status_fixed(phydev);1729 1730	return err;1731}1732 1733/* marvell_read_status1734 *1735 * Some Marvell's phys have two modes: fiber and copper.1736 * Both need status checked.1737 * Description:1738 *   First, check the fiber link and status.1739 *   If the fiber link is down, check the copper link and status which1740 *   will be the default value if both link are down.1741 */1742static int marvell_read_status(struct phy_device *phydev)1743{1744	int err;1745 1746	/* Check the fiber mode first */1747	if (linkmode_test_bit(ETHTOOL_LINK_MODE_FIBRE_BIT,1748			      phydev->supported) &&1749	    phydev->interface != PHY_INTERFACE_MODE_SGMII) {1750		err = marvell_set_page(phydev, MII_MARVELL_FIBER_PAGE);1751		if (err < 0)1752			goto error;1753 1754		err = marvell_read_status_page(phydev, MII_MARVELL_FIBER_PAGE);1755		if (err < 0)1756			goto error;1757 1758		/* If the fiber link is up, it is the selected and1759		 * used link. In this case, we need to stay in the1760		 * fiber page. Please to be careful about that, avoid1761		 * to restore Copper page in other functions which1762		 * could break the behaviour for some fiber phy like1763		 * 88E1512.1764		 */1765		if (phydev->link)1766			return 0;1767 1768		/* If fiber link is down, check and save copper mode state */1769		err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);1770		if (err < 0)1771			goto error;1772	}1773 1774	return marvell_read_status_page(phydev, MII_MARVELL_COPPER_PAGE);1775 1776error:1777	marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);1778	return err;1779}1780 1781/* marvell_suspend1782 *1783 * Some Marvell's phys have two modes: fiber and copper.1784 * Both need to be suspended1785 */1786static int marvell_suspend(struct phy_device *phydev)1787{1788	int err;1789 1790	/* Suspend the fiber mode first */1791	if (linkmode_test_bit(ETHTOOL_LINK_MODE_FIBRE_BIT,1792			      phydev->supported)) {1793		err = marvell_set_page(phydev, MII_MARVELL_FIBER_PAGE);1794		if (err < 0)1795			goto error;1796 1797		/* With the page set, use the generic suspend */1798		err = genphy_suspend(phydev);1799		if (err < 0)1800			goto error;1801 1802		/* Then, the copper link */1803		err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);1804		if (err < 0)1805			goto error;1806	}1807 1808	/* With the page set, use the generic suspend */1809	return genphy_suspend(phydev);1810 1811error:1812	marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);1813	return err;1814}1815 1816/* marvell_resume1817 *1818 * Some Marvell's phys have two modes: fiber and copper.1819 * Both need to be resumed1820 */1821static int marvell_resume(struct phy_device *phydev)1822{1823	int err;1824 1825	/* Resume the fiber mode first */1826	if (linkmode_test_bit(ETHTOOL_LINK_MODE_FIBRE_BIT,1827			      phydev->supported)) {1828		err = marvell_set_page(phydev, MII_MARVELL_FIBER_PAGE);1829		if (err < 0)1830			goto error;1831 1832		/* With the page set, use the generic resume */1833		err = genphy_resume(phydev);1834		if (err < 0)1835			goto error;1836 1837		/* Then, the copper link */1838		err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);1839		if (err < 0)1840			goto error;1841	}1842 1843	/* With the page set, use the generic resume */1844	return genphy_resume(phydev);1845 1846error:1847	marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);1848	return err;1849}1850 1851static int marvell_aneg_done(struct phy_device *phydev)1852{1853	int retval = phy_read(phydev, MII_M1011_PHY_STATUS);1854 1855	return (retval < 0) ? retval : (retval & MII_M1011_PHY_STATUS_RESOLVED);1856}1857 1858static void m88e1318_get_wol(struct phy_device *phydev,1859			     struct ethtool_wolinfo *wol)1860{1861	int ret;1862 1863	wol->supported = WAKE_MAGIC | WAKE_PHY;1864	wol->wolopts = 0;1865 1866	ret = phy_read_paged(phydev, MII_MARVELL_WOL_PAGE,1867			     MII_88E1318S_PHY_WOL_CTRL);1868	if (ret < 0)1869		return;1870 1871	if (ret & MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE)1872		wol->wolopts |= WAKE_MAGIC;1873 1874	if (ret & MII_88E1318S_PHY_WOL_CTRL_LINK_UP_ENABLE)1875		wol->wolopts |= WAKE_PHY;1876}1877 1878static int m88e1318_set_wol(struct phy_device *phydev,1879			    struct ethtool_wolinfo *wol)1880{1881	int err = 0, oldpage;1882 1883	oldpage = phy_save_page(phydev);1884	if (oldpage < 0)1885		goto error;1886 1887	if (wol->wolopts & (WAKE_MAGIC | WAKE_PHY)) {1888		/* Explicitly switch to page 0x00, just to be sure */1889		err = marvell_write_page(phydev, MII_MARVELL_COPPER_PAGE);1890		if (err < 0)1891			goto error;1892 1893		/* If WOL event happened once, the LED[2] interrupt pin1894		 * will not be cleared unless we reading the interrupt status1895		 * register. If interrupts are in use, the normal interrupt1896		 * handling will clear the WOL event. Clear the WOL event1897		 * before enabling it if !phy_interrupt_is_valid()1898		 */1899		if (!phy_interrupt_is_valid(phydev))1900			__phy_read(phydev, MII_M1011_IEVENT);1901 1902		/* Enable the WOL interrupt */1903		err = __phy_set_bits(phydev, MII_88E1318S_PHY_CSIER,1904				     MII_88E1318S_PHY_CSIER_WOL_EIE);1905		if (err < 0)1906			goto error;1907 1908		err = marvell_write_page(phydev, MII_MARVELL_LED_PAGE);1909		if (err < 0)1910			goto error;1911 1912		/* Setup LED[2] as interrupt pin (active low) */1913		err = __phy_modify(phydev, MII_88E1318S_PHY_LED_TCR,1914				   MII_88E1318S_PHY_LED_TCR_FORCE_INT,1915				   MII_88E1318S_PHY_LED_TCR_INTn_ENABLE |1916				   MII_88E1318S_PHY_LED_TCR_INT_ACTIVE_LOW);1917		if (err < 0)1918			goto error;1919	}1920 1921	if (wol->wolopts & WAKE_MAGIC) {1922		err = marvell_write_page(phydev, MII_MARVELL_WOL_PAGE);1923		if (err < 0)1924			goto error;1925 1926		/* Store the device address for the magic packet */1927		err = __phy_write(phydev, MII_88E1318S_PHY_MAGIC_PACKET_WORD2,1928				((phydev->attached_dev->dev_addr[5] << 8) |1929				 phydev->attached_dev->dev_addr[4]));1930		if (err < 0)1931			goto error;1932		err = __phy_write(phydev, MII_88E1318S_PHY_MAGIC_PACKET_WORD1,1933				((phydev->attached_dev->dev_addr[3] << 8) |1934				 phydev->attached_dev->dev_addr[2]));1935		if (err < 0)1936			goto error;1937		err = __phy_write(phydev, MII_88E1318S_PHY_MAGIC_PACKET_WORD0,1938				((phydev->attached_dev->dev_addr[1] << 8) |1939				 phydev->attached_dev->dev_addr[0]));1940		if (err < 0)1941			goto error;1942 1943		/* Clear WOL status and enable magic packet matching */1944		err = __phy_set_bits(phydev, MII_88E1318S_PHY_WOL_CTRL,1945				     MII_88E1318S_PHY_WOL_CTRL_CLEAR_WOL_STATUS |1946				     MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE);1947		if (err < 0)1948			goto error;1949	} else {1950		err = marvell_write_page(phydev, MII_MARVELL_WOL_PAGE);1951		if (err < 0)1952			goto error;1953 1954		/* Clear WOL status and disable magic packet matching */1955		err = __phy_modify(phydev, MII_88E1318S_PHY_WOL_CTRL,1956				   MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE,1957				   MII_88E1318S_PHY_WOL_CTRL_CLEAR_WOL_STATUS);1958		if (err < 0)1959			goto error;1960	}1961 1962	if (wol->wolopts & WAKE_PHY) {1963		err = marvell_write_page(phydev, MII_MARVELL_WOL_PAGE);1964		if (err < 0)1965			goto error;1966 1967		/* Clear WOL status and enable link up event */1968		err = __phy_modify(phydev, MII_88E1318S_PHY_WOL_CTRL, 0,1969				   MII_88E1318S_PHY_WOL_CTRL_CLEAR_WOL_STATUS |1970				   MII_88E1318S_PHY_WOL_CTRL_LINK_UP_ENABLE);1971		if (err < 0)1972			goto error;1973	} else {1974		err = marvell_write_page(phydev, MII_MARVELL_WOL_PAGE);1975		if (err < 0)1976			goto error;1977 1978		/* Clear WOL status and disable link up event */1979		err = __phy_modify(phydev, MII_88E1318S_PHY_WOL_CTRL,1980				   MII_88E1318S_PHY_WOL_CTRL_LINK_UP_ENABLE,1981				   MII_88E1318S_PHY_WOL_CTRL_CLEAR_WOL_STATUS);1982		if (err < 0)1983			goto error;1984	}1985 1986error:1987	return phy_restore_page(phydev, oldpage, err);1988}1989 1990static int marvell_get_sset_count(struct phy_device *phydev)1991{1992	if (linkmode_test_bit(ETHTOOL_LINK_MODE_FIBRE_BIT,1993			      phydev->supported))1994		return ARRAY_SIZE(marvell_hw_stats);1995	else1996		return ARRAY_SIZE(marvell_hw_stats) - NB_FIBER_STATS;1997}1998 1999static int marvell_get_sset_count_simple(struct phy_device *phydev)2000{2001	return ARRAY_SIZE(marvell_hw_stats_simple);2002}2003 2004static void marvell_get_strings(struct phy_device *phydev, u8 *data)2005{2006	int count = marvell_get_sset_count(phydev);2007	int i;2008 2009	for (i = 0; i < count; i++) {2010		strscpy(data + i * ETH_GSTRING_LEN,2011			marvell_hw_stats[i].string, ETH_GSTRING_LEN);2012	}2013}2014 2015static void marvell_get_strings_simple(struct phy_device *phydev, u8 *data)2016{2017	int count = marvell_get_sset_count_simple(phydev);2018	int i;2019 2020	for (i = 0; i < count; i++) {2021		strscpy(data + i * ETH_GSTRING_LEN,2022			marvell_hw_stats_simple[i].string, ETH_GSTRING_LEN);2023	}2024}2025 2026static u64 marvell_get_stat(struct phy_device *phydev, int i)2027{2028	struct marvell_hw_stat stat = marvell_hw_stats[i];2029	struct marvell_priv *priv = phydev->priv;2030	int val;2031	u64 ret;2032 2033	val = phy_read_paged(phydev, stat.page, stat.reg);2034	if (val < 0) {2035		ret = U64_MAX;2036	} else {2037		val = val & ((1 << stat.bits) - 1);2038		priv->stats[i] += val;2039		ret = priv->stats[i];2040	}2041 2042	return ret;2043}2044 2045static u64 marvell_get_stat_simple(struct phy_device *phydev, int i)2046{2047	struct marvell_hw_stat_simple stat = marvell_hw_stats_simple[i];2048	struct marvell_priv *priv = phydev->priv;2049	int val;2050	u64 ret;2051 2052	val = phy_read(phydev, stat.reg);2053	if (val < 0) {2054		ret = U64_MAX;2055	} else {2056		val = val & ((1 << stat.bits) - 1);2057		priv->stats[i] += val;2058		ret = priv->stats[i];2059	}2060 2061	return ret;2062}2063 2064static void marvell_get_stats(struct phy_device *phydev,2065			      struct ethtool_stats *stats, u64 *data)2066{2067	int count = marvell_get_sset_count(phydev);2068	int i;2069 2070	for (i = 0; i < count; i++)2071		data[i] = marvell_get_stat(phydev, i);2072}2073 2074static void marvell_get_stats_simple(struct phy_device *phydev,2075				     struct ethtool_stats *stats, u64 *data)2076{2077	int count = marvell_get_sset_count_simple(phydev);2078	int i;2079 2080	for (i = 0; i < count; i++)2081		data[i] = marvell_get_stat_simple(phydev, i);2082}2083 2084static int m88e1510_loopback(struct phy_device *phydev, bool enable)2085{2086	int err;2087 2088	if (enable) {2089		u16 bmcr_ctl, mscr2_ctl = 0;2090 2091		bmcr_ctl = mii_bmcr_encode_fixed(phydev->speed, phydev->duplex);2092 2093		err = phy_write(phydev, MII_BMCR, bmcr_ctl);2094		if (err < 0)2095			return err;2096 2097		if (phydev->speed == SPEED_1000)2098			mscr2_ctl = BMCR_SPEED1000;2099		else if (phydev->speed == SPEED_100)2100			mscr2_ctl = BMCR_SPEED100;2101 2102		err = phy_modify_paged(phydev, MII_MARVELL_MSCR_PAGE,2103				       MII_88E1510_MSCR_2, BMCR_SPEED1000 |2104				       BMCR_SPEED100, mscr2_ctl);2105		if (err < 0)2106			return err;2107 2108		/* Need soft reset to have speed configuration takes effect */2109		err = genphy_soft_reset(phydev);2110		if (err < 0)2111			return err;2112 2113		err = phy_modify(phydev, MII_BMCR, BMCR_LOOPBACK,2114				 BMCR_LOOPBACK);2115 2116		if (!err) {2117			/* It takes some time for PHY device to switch2118			 * into/out-of loopback mode.2119			 */2120			msleep(1000);2121		}2122		return err;2123	} else {2124		err = phy_modify(phydev, MII_BMCR, BMCR_LOOPBACK, 0);2125		if (err < 0)2126			return err;2127 2128		return phy_config_aneg(phydev);2129	}2130}2131 2132static int marvell_vct5_wait_complete(struct phy_device *phydev)2133{2134	int i;2135	int val;2136 2137	for (i = 0; i < 32; i++) {2138		val = __phy_read(phydev, MII_VCT5_CTRL);2139		if (val < 0)2140			return val;2141 2142		if (val & MII_VCT5_CTRL_COMPLETE)2143			return 0;2144	}2145 2146	phydev_err(phydev, "Timeout while waiting for cable test to finish\n");2147	return -ETIMEDOUT;2148}2149 2150static int marvell_vct5_amplitude(struct phy_device *phydev, int pair)2151{2152	int amplitude;2153	int val;2154	int reg;2155 2156	reg = MII_VCT5_TX_RX_MDI0_COUPLING + pair;2157	val = __phy_read(phydev, reg);2158 2159	if (val < 0)2160		return 0;2161 2162	amplitude = (val & MII_VCT5_TX_RX_AMPLITUDE_MASK) >>2163		MII_VCT5_TX_RX_AMPLITUDE_SHIFT;2164 2165	if (!(val & MII_VCT5_TX_RX_COUPLING_POSITIVE_REFLECTION))2166		amplitude = -amplitude;2167 2168	return 1000 * amplitude / 128;2169}2170 2171static u32 marvell_vct5_distance2cm(int distance)2172{2173	return distance * 805 / 10;2174}2175 2176static u32 marvell_vct5_cm2distance(int cm)2177{2178	return cm * 10 / 805;2179}2180 2181static int marvell_vct5_amplitude_distance(struct phy_device *phydev,2182					   int distance, int pair)2183{2184	u16 reg;2185	int err;2186	int mV;2187	int i;2188 2189	err = __phy_write(phydev, MII_VCT5_SAMPLE_POINT_DISTANCE,2190			  distance);2191	if (err)2192		return err;2193 2194	reg = MII_VCT5_CTRL_ENABLE |2195		MII_VCT5_CTRL_TX_SAME_CHANNEL |2196		MII_VCT5_CTRL_SAMPLES_DEFAULT |2197		MII_VCT5_CTRL_SAMPLE_POINT |2198		MII_VCT5_CTRL_PEEK_HYST_DEFAULT;2199	err = __phy_write(phydev, MII_VCT5_CTRL, reg);2200	if (err)2201		return err;2202 2203	err = marvell_vct5_wait_complete(phydev);2204	if (err)2205		return err;2206 2207	for (i = 0; i < 4; i++) {2208		if (pair != PHY_PAIR_ALL && i != pair)2209			continue;2210 2211		mV = marvell_vct5_amplitude(phydev, i);2212		ethnl_cable_test_amplitude(phydev, i, mV);2213	}2214 2215	return 0;2216}2217 2218static int marvell_vct5_amplitude_graph(struct phy_device *phydev)2219{2220	struct marvell_priv *priv = phydev->priv;2221	int distance;2222	u16 width;2223	int page;2224	int err;2225	u16 reg;2226 2227	if (priv->first <= TDR_SHORT_CABLE_LENGTH)2228		width = MII_VCT5_TX_PULSE_CTRL_PULSE_WIDTH_32nS;2229	else2230		width = MII_VCT5_TX_PULSE_CTRL_PULSE_WIDTH_128nS;2231 2232	reg = MII_VCT5_TX_PULSE_CTRL_GT_140m_46_86mV |2233		MII_VCT5_TX_PULSE_CTRL_DONT_WAIT_LINK_DOWN |2234		MII_VCT5_TX_PULSE_CTRL_MAX_AMP | width;2235 2236	err = phy_write_paged(phydev, MII_MARVELL_VCT5_PAGE,2237			      MII_VCT5_TX_PULSE_CTRL, reg);2238	if (err)2239		return err;2240 2241	/* Reading the TDR data is very MDIO heavy. We need to optimize2242	 * access to keep the time to a minimum. So lock the bus once,2243	 * and don't release it until complete. We can then avoid having2244	 * to change the page for every access, greatly speeding things2245	 * up.2246	 */2247	page = phy_select_page(phydev, MII_MARVELL_VCT5_PAGE);2248	if (page < 0)2249		goto restore_page;2250 2251	for (distance = priv->first;2252	     distance <= priv->last;2253	     distance += priv->step) {2254		err = marvell_vct5_amplitude_distance(phydev, distance,2255						      priv->pair);2256		if (err)2257			goto restore_page;2258 2259		if (distance > TDR_SHORT_CABLE_LENGTH &&2260		    width == MII_VCT5_TX_PULSE_CTRL_PULSE_WIDTH_32nS) {2261			width = MII_VCT5_TX_PULSE_CTRL_PULSE_WIDTH_128nS;2262			reg = MII_VCT5_TX_PULSE_CTRL_GT_140m_46_86mV |2263				MII_VCT5_TX_PULSE_CTRL_DONT_WAIT_LINK_DOWN |2264				MII_VCT5_TX_PULSE_CTRL_MAX_AMP | width;2265			err = __phy_write(phydev, MII_VCT5_TX_PULSE_CTRL, reg);2266			if (err)2267				goto restore_page;2268		}2269	}2270 2271restore_page:2272	return phy_restore_page(phydev, page, err);2273}2274 2275static int marvell_cable_test_start_common(struct phy_device *phydev)2276{2277	int bmcr, bmsr, ret;2278 2279	/* If auto-negotiation is enabled, but not complete, the cable2280	 * test never completes. So disable auto-neg.2281	 */2282	bmcr = phy_read(phydev, MII_BMCR);2283	if (bmcr < 0)2284		return bmcr;2285 2286	bmsr = phy_read(phydev, MII_BMSR);2287 2288	if (bmsr < 0)2289		return bmsr;2290 2291	if (bmcr & BMCR_ANENABLE) {2292		ret =  phy_clear_bits(phydev, MII_BMCR, BMCR_ANENABLE);2293		if (ret < 0)2294			return ret;2295		ret = genphy_soft_reset(phydev);2296		if (ret < 0)2297			return ret;2298	}2299 2300	/* If the link is up, allow it some time to go down */2301	if (bmsr & BMSR_LSTATUS)2302		msleep(1500);2303 2304	return 0;2305}2306 2307static int marvell_vct7_cable_test_start(struct phy_device *phydev)2308{2309	struct marvell_priv *priv = phydev->priv;2310	int ret;2311 2312	ret = marvell_cable_test_start_common(phydev);2313	if (ret)2314		return ret;2315 2316	priv->cable_test_tdr = false;2317 2318	/* Reset the VCT5 API control to defaults, otherwise2319	 * VCT7 does not work correctly.2320	 */2321	ret = phy_write_paged(phydev, MII_MARVELL_VCT5_PAGE,2322			      MII_VCT5_CTRL,2323			      MII_VCT5_CTRL_TX_SAME_CHANNEL |2324			      MII_VCT5_CTRL_SAMPLES_DEFAULT |2325			      MII_VCT5_CTRL_MODE_MAXIMUM_PEEK |2326			      MII_VCT5_CTRL_PEEK_HYST_DEFAULT);2327	if (ret)2328		return ret;2329 2330	ret = phy_write_paged(phydev, MII_MARVELL_VCT5_PAGE,2331			      MII_VCT5_SAMPLE_POINT_DISTANCE, 0);2332	if (ret)2333		return ret;2334 2335	return phy_write_paged(phydev, MII_MARVELL_VCT7_PAGE,2336			       MII_VCT7_CTRL,2337			       MII_VCT7_CTRL_RUN_NOW |2338			       MII_VCT7_CTRL_CENTIMETERS);2339}2340 2341static int marvell_vct5_cable_test_tdr_start(struct phy_device *phydev,2342					     const struct phy_tdr_config *cfg)2343{2344	struct marvell_priv *priv = phydev->priv;2345	int ret;2346 2347	priv->cable_test_tdr = true;2348	priv->first = marvell_vct5_cm2distance(cfg->first);2349	priv->last = marvell_vct5_cm2distance(cfg->last);2350	priv->step = marvell_vct5_cm2distance(cfg->step);2351	priv->pair = cfg->pair;2352 2353	if (priv->first > MII_VCT5_SAMPLE_POINT_DISTANCE_MAX)2354		return -EINVAL;2355 2356	if (priv->last > MII_VCT5_SAMPLE_POINT_DISTANCE_MAX)2357		return -EINVAL;2358 2359	/* Disable  VCT7 */2360	ret = phy_write_paged(phydev, MII_MARVELL_VCT7_PAGE,2361			      MII_VCT7_CTRL, 0);2362	if (ret)2363		return ret;2364 2365	ret = marvell_cable_test_start_common(phydev);2366	if (ret)2367		return ret;2368 2369	ret = ethnl_cable_test_pulse(phydev, 1000);2370	if (ret)2371		return ret;2372 2373	return ethnl_cable_test_step(phydev,2374				     marvell_vct5_distance2cm(priv->first),2375				     marvell_vct5_distance2cm(priv->last),2376				     marvell_vct5_distance2cm(priv->step));2377}2378 2379static int marvell_vct7_distance_to_length(int distance, bool meter)2380{2381	if (meter)2382		distance *= 100;2383 2384	return distance;2385}2386 2387static bool marvell_vct7_distance_valid(int result)2388{2389	switch (result) {2390	case MII_VCT7_RESULTS_OPEN:2391	case MII_VCT7_RESULTS_SAME_SHORT:2392	case MII_VCT7_RESULTS_CROSS_SHORT:2393		return true;2394	}2395	return false;2396}2397 2398static int marvell_vct7_report_length(struct phy_device *phydev,2399				      int pair, bool meter)2400{2401	int length;2402	int ret;2403 2404	ret = phy_read_paged(phydev, MII_MARVELL_VCT7_PAGE,2405			     MII_VCT7_PAIR_0_DISTANCE + pair);2406	if (ret < 0)2407		return ret;2408 2409	length = marvell_vct7_distance_to_length(ret, meter);2410 2411	ethnl_cable_test_fault_length(phydev, pair, length);2412 2413	return 0;2414}2415 2416static int marvell_vct7_cable_test_report_trans(int result)2417{2418	switch (result) {2419	case MII_VCT7_RESULTS_OK:2420		return ETHTOOL_A_CABLE_RESULT_CODE_OK;2421	case MII_VCT7_RESULTS_OPEN:2422		return ETHTOOL_A_CABLE_RESULT_CODE_OPEN;2423	case MII_VCT7_RESULTS_SAME_SHORT:2424		return ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT;2425	case MII_VCT7_RESULTS_CROSS_SHORT:2426		return ETHTOOL_A_CABLE_RESULT_CODE_CROSS_SHORT;2427	default:2428		return ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC;2429	}2430}2431 2432static int marvell_vct7_cable_test_report(struct phy_device *phydev)2433{2434	int pair0, pair1, pair2, pair3;2435	bool meter;2436	int ret;2437 2438	ret = phy_read_paged(phydev, MII_MARVELL_VCT7_PAGE,2439			     MII_VCT7_RESULTS);2440	if (ret < 0)2441		return ret;2442 2443	pair3 = (ret & MII_VCT7_RESULTS_PAIR3_MASK) >>2444		MII_VCT7_RESULTS_PAIR3_SHIFT;2445	pair2 = (ret & MII_VCT7_RESULTS_PAIR2_MASK) >>2446		MII_VCT7_RESULTS_PAIR2_SHIFT;2447	pair1 = (ret & MII_VCT7_RESULTS_PAIR1_MASK) >>2448		MII_VCT7_RESULTS_PAIR1_SHIFT;2449	pair0 = (ret & MII_VCT7_RESULTS_PAIR0_MASK) >>2450		MII_VCT7_RESULTS_PAIR0_SHIFT;2451 2452	ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_A,2453				marvell_vct7_cable_test_report_trans(pair0));2454	ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_B,2455				marvell_vct7_cable_test_report_trans(pair1));2456	ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_C,2457				marvell_vct7_cable_test_report_trans(pair2));2458	ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_D,2459				marvell_vct7_cable_test_report_trans(pair3));2460 2461	ret = phy_read_paged(phydev, MII_MARVELL_VCT7_PAGE, MII_VCT7_CTRL);2462	if (ret < 0)2463		return ret;2464 2465	meter = ret & MII_VCT7_CTRL_METERS;2466 2467	if (marvell_vct7_distance_valid(pair0))2468		marvell_vct7_report_length(phydev, 0, meter);2469	if (marvell_vct7_distance_valid(pair1))2470		marvell_vct7_report_length(phydev, 1, meter);2471	if (marvell_vct7_distance_valid(pair2))2472		marvell_vct7_report_length(phydev, 2, meter);2473	if (marvell_vct7_distance_valid(pair3))2474		marvell_vct7_report_length(phydev, 3, meter);2475 2476	return 0;2477}2478 2479static int marvell_vct7_cable_test_get_status(struct phy_device *phydev,2480					      bool *finished)2481{2482	struct marvell_priv *priv = phydev->priv;2483	int ret;2484 2485	if (priv->cable_test_tdr) {2486		ret = marvell_vct5_amplitude_graph(phydev);2487		*finished = true;2488		return ret;2489	}2490 2491	*finished = false;2492 2493	ret = phy_read_paged(phydev, MII_MARVELL_VCT7_PAGE,2494			     MII_VCT7_CTRL);2495 2496	if (ret < 0)2497		return ret;2498 2499	if (!(ret & MII_VCT7_CTRL_IN_PROGRESS)) {2500		*finished = true;2501 2502		return marvell_vct7_cable_test_report(phydev);2503	}2504 2505	return 0;2506}2507 2508static int m88e3082_vct_cable_test_start(struct phy_device *phydev)2509{2510	struct marvell_priv *priv = phydev->priv;2511	int ret;2512 2513	/* It needs some magic workarounds described in VCT manual for this PHY.2514	 */2515	ret = phy_write(phydev, 29, 0x0003);2516	if (ret < 0)2517		return ret;2518 2519	ret = phy_write(phydev, 30, 0x6440);2520	if (ret < 0)2521		return ret;2522 2523	if (priv->vct_phase == M88E3082_VCT_PHASE1) {2524		ret = phy_write(phydev, 29, 0x000a);2525		if (ret < 0)2526			return ret;2527 2528		ret = phy_write(phydev, 30, 0x0002);2529		if (ret < 0)2530			return ret;2531	}2532 2533	ret = phy_write(phydev, MII_BMCR,2534			BMCR_RESET | BMCR_SPEED100 | BMCR_FULLDPLX);2535	if (ret < 0)2536		return ret;2537 2538	ret = phy_write(phydev, MII_VCT_TXPINS, MII_VCT_TXPINS_ENVCT);2539	if (ret < 0)2540		return ret;2541 2542	ret = phy_write(phydev, 29, 0x0003);2543	if (ret < 0)2544		return ret;2545 2546	ret = phy_write(phydev, 30, 0x0);2547	if (ret < 0)2548		return ret;2549 2550	if (priv->vct_phase == M88E3082_VCT_OFF) {2551		priv->vct_phase = M88E3082_VCT_PHASE1;2552		priv->pair = 0;2553 2554		return 0;2555	}2556 2557	ret = phy_write(phydev, 29, 0x000a);2558	if (ret < 0)2559		return ret;2560 2561	ret = phy_write(phydev, 30, 0x0);2562	if (ret < 0)2563		return ret;2564 2565	priv->vct_phase = M88E3082_VCT_PHASE2;2566 2567	return 0;2568}2569 2570static int m88e3082_vct_cable_test_report_trans(int result, u8 distance)2571{2572	switch (result) {2573	case MII_VCT_TXRXPINS_VCTTST_OK:2574		if (distance == MII_VCT_TXRXPINS_DISTRFLN_MAX)2575			return ETHTOOL_A_CABLE_RESULT_CODE_OK;2576		return ETHTOOL_A_CABLE_RESULT_CODE_IMPEDANCE_MISMATCH;2577	case MII_VCT_TXRXPINS_VCTTST_SHORT:2578		return ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT;2579	case MII_VCT_TXRXPINS_VCTTST_OPEN:2580		return ETHTOOL_A_CABLE_RESULT_CODE_OPEN;2581	default:2582		return ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC;2583	}2584}2585 2586static u32 m88e3082_vct_distrfln_2_cm(u8 distrfln)2587{2588	if (distrfln < 24)2589		return 0;2590 2591	/* Original function for meters: y = 0.7861x - 18.862 */2592	return (7861 * distrfln - 188620) / 100;2593}2594 2595static int m88e3082_vct_cable_test_get_status(struct phy_device *phydev,2596					      bool *finished)2597{2598	u8 tx_vcttst_res, rx_vcttst_res, tx_distrfln, rx_distrfln;2599	struct marvell_priv *priv = phydev->priv;2600	int ret, tx_result, rx_result;2601	bool done_phase = true;2602 2603	*finished = false;2604 2605	ret = phy_read(phydev, MII_VCT_TXPINS);2606	if (ret < 0)2607		return ret;2608	else if (ret & MII_VCT_TXPINS_ENVCT)2609		return 0;2610 2611	tx_distrfln = ret & MII_VCT_TXRXPINS_DISTRFLN;2612	tx_vcttst_res = (ret & MII_VCT_TXRXPINS_VCTTST) >>2613			MII_VCT_TXRXPINS_VCTTST_SHIFT;2614 2615	ret = phy_read(phydev, MII_VCT_RXPINS);2616	if (ret < 0)2617		return ret;2618 2619	rx_distrfln = ret & MII_VCT_TXRXPINS_DISTRFLN;2620	rx_vcttst_res = (ret & MII_VCT_TXRXPINS_VCTTST) >>2621			MII_VCT_TXRXPINS_VCTTST_SHIFT;2622 2623	*finished = true;2624 2625	switch (priv->vct_phase) {2626	case M88E3082_VCT_PHASE1:2627		tx_result = m88e3082_vct_cable_test_report_trans(tx_vcttst_res,2628								 tx_distrfln);2629		rx_result = m88e3082_vct_cable_test_report_trans(rx_vcttst_res,2630								 rx_distrfln);2631 2632		ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_A,2633					tx_result);2634		ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_B,2635					rx_result);2636 2637		if (tx_vcttst_res == MII_VCT_TXRXPINS_VCTTST_OPEN) {2638			done_phase = false;2639			priv->pair |= M88E3082_PAIR_A;2640		} else if (tx_distrfln < MII_VCT_TXRXPINS_DISTRFLN_MAX) {2641			u8 pair = ETHTOOL_A_CABLE_PAIR_A;2642			u32 cm = m88e3082_vct_distrfln_2_cm(tx_distrfln);2643 2644			ethnl_cable_test_fault_length(phydev, pair, cm);2645		}2646 2647		if (rx_vcttst_res == MII_VCT_TXRXPINS_VCTTST_OPEN) {2648			done_phase = false;2649			priv->pair |= M88E3082_PAIR_B;2650		} else if (rx_distrfln < MII_VCT_TXRXPINS_DISTRFLN_MAX) {2651			u8 pair = ETHTOOL_A_CABLE_PAIR_B;2652			u32 cm = m88e3082_vct_distrfln_2_cm(rx_distrfln);2653 2654			ethnl_cable_test_fault_length(phydev, pair, cm);2655		}2656 2657		break;2658	case M88E3082_VCT_PHASE2:2659		if (priv->pair & M88E3082_PAIR_A &&2660		    tx_vcttst_res == MII_VCT_TXRXPINS_VCTTST_OPEN &&2661		    tx_distrfln < MII_VCT_TXRXPINS_DISTRFLN_MAX) {2662			u8 pair = ETHTOOL_A_CABLE_PAIR_A;2663			u32 cm = m88e3082_vct_distrfln_2_cm(tx_distrfln);2664 2665			ethnl_cable_test_fault_length(phydev, pair, cm);2666		}2667		if (priv->pair & M88E3082_PAIR_B &&2668		    rx_vcttst_res == MII_VCT_TXRXPINS_VCTTST_OPEN &&2669		    rx_distrfln < MII_VCT_TXRXPINS_DISTRFLN_MAX) {2670			u8 pair = ETHTOOL_A_CABLE_PAIR_B;2671			u32 cm = m88e3082_vct_distrfln_2_cm(rx_distrfln);2672 2673			ethnl_cable_test_fault_length(phydev, pair, cm);2674		}2675 2676		break;2677	default:2678		return -EINVAL;2679	}2680 2681	if (!done_phase) {2682		*finished = false;2683		return m88e3082_vct_cable_test_start(phydev);2684	}2685	if (*finished)2686		priv->vct_phase = M88E3082_VCT_OFF;2687	return 0;2688}2689 2690static int m88e1111_vct_cable_test_start(struct phy_device *phydev)2691{2692	int ret;2693 2694	ret = marvell_cable_test_start_common(phydev);2695	if (ret)2696		return ret;2697 2698	/* It needs some magic workarounds described in VCT manual for this PHY.2699	 */2700	ret = phy_write(phydev, 29, 0x0018);2701	if (ret < 0)2702		return ret;2703 2704	ret = phy_write(phydev, 30, 0x00c2);2705	if (ret < 0)2706		return ret;2707 2708	ret = phy_write(phydev, 30, 0x00ca);2709	if (ret < 0)2710		return ret;2711 2712	ret = phy_write(phydev, 30, 0x00c2);2713	if (ret < 0)2714		return ret;2715 2716	ret = phy_write_paged(phydev, MII_MARVELL_COPPER_PAGE, MII_VCT_SR,2717			      MII_VCT_TXPINS_ENVCT);2718	if (ret < 0)2719		return ret;2720 2721	ret = phy_write(phydev, 29, 0x0018);2722	if (ret < 0)2723		return ret;2724 2725	ret = phy_write(phydev, 30, 0x0042);2726	if (ret < 0)2727		return ret;2728 2729	return 0;2730}2731 2732static u32 m88e1111_vct_distrfln_2_cm(u8 distrfln)2733{2734	if (distrfln < 36)2735		return 0;2736 2737	/* Original function for meters: y = 0.8018x - 28.751 */2738	return (8018 * distrfln - 287510) / 100;2739}2740 2741static int m88e1111_vct_cable_test_get_status(struct phy_device *phydev,2742					      bool *finished)2743{2744	u8 vcttst_res, distrfln;2745	int ret, result;2746 2747	*finished = false;2748 2749	/* Each pair use one page: A-0, B-1, C-2, D-3 */2750	for (u8 i = 0; i < 4; i++) {2751		ret = phy_read_paged(phydev, i, MII_VCT_SR);2752		if (ret < 0)2753			return ret;2754		else if (i == 0 && ret & MII_VCT_TXPINS_ENVCT)2755			return 0;2756 2757		distrfln = ret & MII_VCT_TXRXPINS_DISTRFLN;2758		vcttst_res = (ret & MII_VCT_TXRXPINS_VCTTST) >>2759			      MII_VCT_TXRXPINS_VCTTST_SHIFT;2760 2761		result = m88e3082_vct_cable_test_report_trans(vcttst_res,2762							      distrfln);2763		ethnl_cable_test_result(phydev, i, result);2764 2765		if (distrfln < MII_VCT_TXRXPINS_DISTRFLN_MAX) {2766			u32 cm = m88e1111_vct_distrfln_2_cm(distrfln);2767 2768			ethnl_cable_test_fault_length(phydev, i, cm);2769		}2770	}2771 2772	*finished = true;2773	return 0;2774}2775 2776#ifdef CONFIG_HWMON2777struct marvell_hwmon_ops {2778	int (*config)(struct phy_device *phydev);2779	int (*get_temp)(struct phy_device *phydev, long *temp);2780	int (*get_temp_critical)(struct phy_device *phydev, long *temp);2781	int (*set_temp_critical)(struct phy_device *phydev, long temp);2782	int (*get_temp_alarm)(struct phy_device *phydev, long *alarm);2783};2784 2785static const struct marvell_hwmon_ops *2786to_marvell_hwmon_ops(const struct phy_device *phydev)2787{2788	return phydev->drv->driver_data;2789}2790 2791static int m88e1121_get_temp(struct phy_device *phydev, long *temp)2792{2793	int oldpage;2794	int ret = 0;2795	int val;2796 2797	*temp = 0;2798 2799	oldpage = phy_select_page(phydev, MII_MARVELL_MISC_TEST_PAGE);2800	if (oldpage < 0)2801		goto error;2802 2803	/* Enable temperature sensor */2804	ret = __phy_read(phydev, MII_88E1121_MISC_TEST);2805	if (ret < 0)2806		goto error;2807 2808	ret = __phy_write(phydev, MII_88E1121_MISC_TEST,2809			  ret | MII_88E1121_MISC_TEST_TEMP_SENSOR_EN);2810	if (ret < 0)2811		goto error;2812 2813	/* Wait for temperature to stabilize */2814	usleep_range(10000, 12000);2815 2816	val = __phy_read(phydev, MII_88E1121_MISC_TEST);2817	if (val < 0) {2818		ret = val;2819		goto error;2820	}2821 2822	/* Disable temperature sensor */2823	ret = __phy_write(phydev, MII_88E1121_MISC_TEST,2824			  ret & ~MII_88E1121_MISC_TEST_TEMP_SENSOR_EN);2825	if (ret < 0)2826		goto error;2827 2828	*temp = ((val & MII_88E1121_MISC_TEST_TEMP_MASK) - 5) * 5000;2829 2830error:2831	return phy_restore_page(phydev, oldpage, ret);2832}2833 2834static int m88e1510_get_temp(struct phy_device *phydev, long *temp)2835{2836	int ret;2837 2838	*temp = 0;2839 2840	ret = phy_read_paged(phydev, MII_MARVELL_MISC_TEST_PAGE,2841			     MII_88E1510_TEMP_SENSOR);2842	if (ret < 0)2843		return ret;2844 2845	*temp = ((ret & MII_88E1510_TEMP_SENSOR_MASK) - 25) * 1000;2846 2847	return 0;2848}2849 2850static int m88e1510_get_temp_critical(struct phy_device *phydev, long *temp)2851{2852	int ret;2853 2854	*temp = 0;2855 2856	ret = phy_read_paged(phydev, MII_MARVELL_MISC_TEST_PAGE,2857			     MII_88E1121_MISC_TEST);2858	if (ret < 0)2859		return ret;2860 2861	*temp = (((ret & MII_88E1510_MISC_TEST_TEMP_THRESHOLD_MASK) >>2862		  MII_88E1510_MISC_TEST_TEMP_THRESHOLD_SHIFT) * 5) - 25;2863	/* convert to mC */2864	*temp *= 1000;2865 2866	return 0;2867}2868 2869static int m88e1510_set_temp_critical(struct phy_device *phydev, long temp)2870{2871	temp = temp / 1000;2872	temp = clamp_val(DIV_ROUND_CLOSEST(temp, 5) + 5, 0, 0x1f);2873 2874	return phy_modify_paged(phydev, MII_MARVELL_MISC_TEST_PAGE,2875				MII_88E1121_MISC_TEST,2876				MII_88E1510_MISC_TEST_TEMP_THRESHOLD_MASK,2877				temp << MII_88E1510_MISC_TEST_TEMP_THRESHOLD_SHIFT);2878}2879 2880static int m88e1510_get_temp_alarm(struct phy_device *phydev, long *alarm)2881{2882	int ret;2883 2884	*alarm = false;2885 2886	ret = phy_read_paged(phydev, MII_MARVELL_MISC_TEST_PAGE,2887			     MII_88E1121_MISC_TEST);2888	if (ret < 0)2889		return ret;2890 2891	*alarm = !!(ret & MII_88E1510_MISC_TEST_TEMP_IRQ);2892 2893	return 0;2894}2895 2896static int m88e6390_get_temp(struct phy_device *phydev, long *temp)2897{2898	int sum = 0;2899	int oldpage;2900	int ret = 0;2901	int i;2902 2903	*temp = 0;2904 2905	oldpage = phy_select_page(phydev, MII_MARVELL_MISC_TEST_PAGE);2906	if (oldpage < 0)2907		goto error;2908 2909	/* Enable temperature sensor */2910	ret = __phy_read(phydev, MII_88E6390_MISC_TEST);2911	if (ret < 0)2912		goto error;2913 2914	ret &= ~MII_88E6390_MISC_TEST_TEMP_SENSOR_MASK;2915	ret |= MII_88E6390_MISC_TEST_TEMP_SENSOR_ENABLE_SAMPLE_1S;2916 2917	ret = __phy_write(phydev, MII_88E6390_MISC_TEST, ret);2918	if (ret < 0)2919		goto error;2920 2921	/* Wait for temperature to stabilize */2922	usleep_range(10000, 12000);2923 2924	/* Reading the temperature sense has an errata. You need to read2925	 * a number of times and take an average.2926	 */2927	for (i = 0; i < MII_88E6390_TEMP_SENSOR_SAMPLES; i++) {2928		ret = __phy_read(phydev, MII_88E6390_TEMP_SENSOR);2929		if (ret < 0)2930			goto error;2931		sum += ret & MII_88E6390_TEMP_SENSOR_MASK;2932	}2933 2934	sum /= MII_88E6390_TEMP_SENSOR_SAMPLES;2935	*temp = (sum  - 75) * 1000;2936 2937	/* Disable temperature sensor */2938	ret = __phy_read(phydev, MII_88E6390_MISC_TEST);2939	if (ret < 0)2940		goto error;2941 2942	ret = ret & ~MII_88E6390_MISC_TEST_TEMP_SENSOR_MASK;2943	ret |= MII_88E6390_MISC_TEST_TEMP_SENSOR_DISABLE;2944 2945	ret = __phy_write(phydev, MII_88E6390_MISC_TEST, ret);2946 2947error:2948	phy_restore_page(phydev, oldpage, ret);2949 2950	return ret;2951}2952 2953static int m88e6393_get_temp(struct phy_device *phydev, long *temp)2954{2955	int err;2956 2957	err = m88e1510_get_temp(phydev, temp);2958 2959	/* 88E1510 measures T + 25, while the PHY on 88E6393X switch2960	 * T + 75, so we have to subtract another 502961	 */2962	*temp -= 50000;2963 2964	return err;2965}2966 2967static int m88e6393_get_temp_critical(struct phy_device *phydev, long *temp)2968{2969	int ret;2970 2971	*temp = 0;2972 2973	ret = phy_read_paged(phydev, MII_MARVELL_MISC_TEST_PAGE,2974			     MII_88E6390_TEMP_SENSOR);2975	if (ret < 0)2976		return ret;2977 2978	*temp = (((ret & MII_88E6393_TEMP_SENSOR_THRESHOLD_MASK) >>2979		  MII_88E6393_TEMP_SENSOR_THRESHOLD_SHIFT) - 75) * 1000;2980 2981	return 0;2982}2983 2984static int m88e6393_set_temp_critical(struct phy_device *phydev, long temp)2985{2986	temp = (temp / 1000) + 75;2987 2988	return phy_modify_paged(phydev, MII_MARVELL_MISC_TEST_PAGE,2989				MII_88E6390_TEMP_SENSOR,2990				MII_88E6393_TEMP_SENSOR_THRESHOLD_MASK,2991				temp << MII_88E6393_TEMP_SENSOR_THRESHOLD_SHIFT);2992}2993 2994static int m88e6393_hwmon_config(struct phy_device *phydev)2995{2996	int err;2997 2998	err = m88e6393_set_temp_critical(phydev, 100000);2999	if (err)3000		return err;3001 3002	return phy_modify_paged(phydev, MII_MARVELL_MISC_TEST_PAGE,3003				MII_88E6390_MISC_TEST,3004				MII_88E6390_MISC_TEST_TEMP_SENSOR_MASK |3005				MII_88E6393_MISC_TEST_SAMPLES_MASK |3006				MII_88E6393_MISC_TEST_RATE_MASK,3007				MII_88E6390_MISC_TEST_TEMP_SENSOR_ENABLE |3008				MII_88E6393_MISC_TEST_SAMPLES_2048 |3009				MII_88E6393_MISC_TEST_RATE_2_3MS);3010}3011 3012static int marvell_hwmon_read(struct device *dev, enum hwmon_sensor_types type,3013			      u32 attr, int channel, long *temp)3014{3015	struct phy_device *phydev = dev_get_drvdata(dev);3016	const struct marvell_hwmon_ops *ops = to_marvell_hwmon_ops(phydev);3017	int err = -EOPNOTSUPP;3018 3019	switch (attr) {3020	case hwmon_temp_input:3021		if (ops->get_temp)3022			err = ops->get_temp(phydev, temp);3023		break;3024	case hwmon_temp_crit:3025		if (ops->get_temp_critical)3026			err = ops->get_temp_critical(phydev, temp);3027		break;3028	case hwmon_temp_max_alarm:3029		if (ops->get_temp_alarm)3030			err = ops->get_temp_alarm(phydev, temp);3031		break;3032	}3033 3034	return err;3035}3036 3037static int marvell_hwmon_write(struct device *dev, enum hwmon_sensor_types type,3038			       u32 attr, int channel, long temp)3039{3040	struct phy_device *phydev = dev_get_drvdata(dev);3041	const struct marvell_hwmon_ops *ops = to_marvell_hwmon_ops(phydev);3042	int err = -EOPNOTSUPP;3043 3044	switch (attr) {3045	case hwmon_temp_crit:3046		if (ops->set_temp_critical)3047			err = ops->set_temp_critical(phydev, temp);3048		break;3049	}3050 3051	return err;3052}3053 3054static umode_t marvell_hwmon_is_visible(const void *data,3055					enum hwmon_sensor_types type,3056					u32 attr, int channel)3057{3058	const struct phy_device *phydev = data;3059	const struct marvell_hwmon_ops *ops = to_marvell_hwmon_ops(phydev);3060 3061	if (type != hwmon_temp)3062		return 0;3063 3064	switch (attr) {3065	case hwmon_temp_input:3066		return ops->get_temp ? 0444 : 0;3067	case hwmon_temp_max_alarm:3068		return ops->get_temp_alarm ? 0444 : 0;3069	case hwmon_temp_crit:3070		return (ops->get_temp_critical ? 0444 : 0) |3071		       (ops->set_temp_critical ? 0200 : 0);3072	default:3073		return 0;3074	}3075}3076 3077static u32 marvell_hwmon_chip_config[] = {3078	HWMON_C_REGISTER_TZ,3079	03080};3081 3082static const struct hwmon_channel_info marvell_hwmon_chip = {3083	.type = hwmon_chip,3084	.config = marvell_hwmon_chip_config,3085};3086 3087/* we can define HWMON_T_CRIT and HWMON_T_MAX_ALARM even though these are not3088 * defined for all PHYs, because the hwmon code checks whether the attributes3089 * exists via the .is_visible method3090 */3091static u32 marvell_hwmon_temp_config[] = {3092	HWMON_T_INPUT | HWMON_T_CRIT | HWMON_T_MAX_ALARM,3093	03094};3095 3096static const struct hwmon_channel_info marvell_hwmon_temp = {3097	.type = hwmon_temp,3098	.config = marvell_hwmon_temp_config,3099};3100 3101static const struct hwmon_channel_info * const marvell_hwmon_info[] = {3102	&marvell_hwmon_chip,3103	&marvell_hwmon_temp,3104	NULL3105};3106 3107static const struct hwmon_ops marvell_hwmon_hwmon_ops = {3108	.is_visible = marvell_hwmon_is_visible,3109	.read = marvell_hwmon_read,3110	.write = marvell_hwmon_write,3111};3112 3113static const struct hwmon_chip_info marvell_hwmon_chip_info = {3114	.ops = &marvell_hwmon_hwmon_ops,3115	.info = marvell_hwmon_info,3116};3117 3118static int marvell_hwmon_name(struct phy_device *phydev)3119{3120	struct marvell_priv *priv = phydev->priv;3121	struct device *dev = &phydev->mdio.dev;3122	const char *devname = dev_name(dev);3123	size_t len = strlen(devname);3124	int i, j;3125 3126	priv->hwmon_name = devm_kzalloc(dev, len, GFP_KERNEL);3127	if (!priv->hwmon_name)3128		return -ENOMEM;3129 3130	for (i = j = 0; i < len && devname[i]; i++) {3131		if (isalnum(devname[i]))3132			priv->hwmon_name[j++] = devname[i];3133	}3134 3135	return 0;3136}3137 3138static int marvell_hwmon_probe(struct phy_device *phydev)3139{3140	const struct marvell_hwmon_ops *ops = to_marvell_hwmon_ops(phydev);3141	struct marvell_priv *priv = phydev->priv;3142	struct device *dev = &phydev->mdio.dev;3143	int err;3144 3145	if (!ops)3146		return 0;3147 3148	err = marvell_hwmon_name(phydev);3149	if (err)3150		return err;3151 3152	priv->hwmon_dev = devm_hwmon_device_register_with_info(3153		dev, priv->hwmon_name, phydev, &marvell_hwmon_chip_info, NULL);3154	if (IS_ERR(priv->hwmon_dev))3155		return PTR_ERR(priv->hwmon_dev);3156 3157	if (ops->config)3158		err = ops->config(phydev);3159 3160	return err;3161}3162 3163static const struct marvell_hwmon_ops m88e1121_hwmon_ops = {3164	.get_temp = m88e1121_get_temp,3165};3166 3167static const struct marvell_hwmon_ops m88e1510_hwmon_ops = {3168	.get_temp = m88e1510_get_temp,3169	.get_temp_critical = m88e1510_get_temp_critical,3170	.set_temp_critical = m88e1510_set_temp_critical,3171	.get_temp_alarm = m88e1510_get_temp_alarm,3172};3173 3174static const struct marvell_hwmon_ops m88e6390_hwmon_ops = {3175	.get_temp = m88e6390_get_temp,3176};3177 3178static const struct marvell_hwmon_ops m88e6393_hwmon_ops = {3179	.config = m88e6393_hwmon_config,3180	.get_temp = m88e6393_get_temp,3181	.get_temp_critical = m88e6393_get_temp_critical,3182	.set_temp_critical = m88e6393_set_temp_critical,3183	.get_temp_alarm = m88e1510_get_temp_alarm,3184};3185 3186#define DEF_MARVELL_HWMON_OPS(s) (&(s))3187 3188#else3189 3190#define DEF_MARVELL_HWMON_OPS(s) NULL3191 3192static int marvell_hwmon_probe(struct phy_device *phydev)3193{3194	return 0;3195}3196#endif3197 3198static int m88e1318_led_brightness_set(struct phy_device *phydev,3199				       u8 index, enum led_brightness value)3200{3201	int reg;3202 3203	reg = phy_read_paged(phydev, MII_MARVELL_LED_PAGE,3204			     MII_88E1318S_PHY_LED_FUNC);3205	if (reg < 0)3206		return reg;3207 3208	switch (index) {3209	case 0:3210	case 1:3211	case 2:3212		reg &= ~(0xf << (4 * index));3213		if (value == LED_OFF)3214			reg |= MII_88E1318S_PHY_LED_FUNC_OFF << (4 * index);3215		else3216			reg |= MII_88E1318S_PHY_LED_FUNC_ON << (4 * index);3217		break;3218	default:3219		return -EINVAL;3220	}3221 3222	return phy_write_paged(phydev, MII_MARVELL_LED_PAGE,3223			       MII_88E1318S_PHY_LED_FUNC, reg);3224}3225 3226static int m88e1318_led_blink_set(struct phy_device *phydev, u8 index,3227				  unsigned long *delay_on,3228				  unsigned long *delay_off)3229{3230	int reg;3231 3232	reg = phy_read_paged(phydev, MII_MARVELL_LED_PAGE,3233			     MII_88E1318S_PHY_LED_FUNC);3234	if (reg < 0)3235		return reg;3236 3237	switch (index) {3238	case 0:3239	case 1:3240	case 2:3241		reg &= ~(0xf << (4 * index));3242		reg |= MII_88E1318S_PHY_LED_FUNC_BLINK << (4 * index);3243		/* Reset default is 84ms */3244		*delay_on = 84 / 2;3245		*delay_off = 84 / 2;3246		break;3247	default:3248		return -EINVAL;3249	}3250 3251	return phy_write_paged(phydev, MII_MARVELL_LED_PAGE,3252			       MII_88E1318S_PHY_LED_FUNC, reg);3253}3254 3255struct marvell_led_rules {3256	int mode;3257	unsigned long rules;3258};3259 3260static const struct marvell_led_rules marvell_led0[] = {3261	{3262		.mode = 0,3263		.rules = BIT(TRIGGER_NETDEV_LINK),3264	},3265	{3266		.mode = 1,3267		.rules = (BIT(TRIGGER_NETDEV_LINK) |3268			  BIT(TRIGGER_NETDEV_RX) |3269			  BIT(TRIGGER_NETDEV_TX)),3270	},3271	{3272		.mode = 3,3273		.rules = (BIT(TRIGGER_NETDEV_RX) |3274			  BIT(TRIGGER_NETDEV_TX)),3275	},3276	{3277		.mode = 4,3278		.rules = (BIT(TRIGGER_NETDEV_RX) |3279			  BIT(TRIGGER_NETDEV_TX)),3280	},3281	{3282		.mode = 5,3283		.rules = BIT(TRIGGER_NETDEV_TX),3284	},3285	{3286		.mode = 6,3287		.rules = BIT(TRIGGER_NETDEV_LINK),3288	},3289	{3290		.mode = 7,3291		.rules = BIT(TRIGGER_NETDEV_LINK_1000),3292	},3293	{3294		.mode = 8,3295		.rules = 0,3296	},3297};3298 3299static const struct marvell_led_rules marvell_led1[] = {3300	{3301		.mode = 1,3302		.rules = (BIT(TRIGGER_NETDEV_LINK) |3303			  BIT(TRIGGER_NETDEV_RX) |3304			  BIT(TRIGGER_NETDEV_TX)),3305	},3306	{3307		.mode = 2,3308		.rules = (BIT(TRIGGER_NETDEV_LINK) |3309			  BIT(TRIGGER_NETDEV_RX)),3310	},3311	{3312		.mode = 3,3313		.rules = (BIT(TRIGGER_NETDEV_RX) |3314			  BIT(TRIGGER_NETDEV_TX)),3315	},3316	{3317		.mode = 4,3318		.rules = (BIT(TRIGGER_NETDEV_RX) |3319			  BIT(TRIGGER_NETDEV_TX)),3320	},3321	{3322		.mode = 6,3323		.rules = (BIT(TRIGGER_NETDEV_LINK_100) |3324			  BIT(TRIGGER_NETDEV_LINK_1000)),3325	},3326	{3327		.mode = 7,3328		.rules = BIT(TRIGGER_NETDEV_LINK_100),3329	},3330	{3331		.mode = 8,3332		.rules = 0,3333	},3334};3335 3336static const struct marvell_led_rules marvell_led2[] = {3337	{3338		.mode = 0,3339		.rules = BIT(TRIGGER_NETDEV_LINK),3340	},3341	{3342		.mode = 1,3343		.rules = (BIT(TRIGGER_NETDEV_LINK) |3344			  BIT(TRIGGER_NETDEV_RX) |3345			  BIT(TRIGGER_NETDEV_TX)),3346	},3347	{3348		.mode = 3,3349		.rules = (BIT(TRIGGER_NETDEV_RX) |3350			  BIT(TRIGGER_NETDEV_TX)),3351	},3352	{3353		.mode = 4,3354		.rules = (BIT(TRIGGER_NETDEV_RX) |3355			  BIT(TRIGGER_NETDEV_TX)),3356	},3357	{3358		.mode = 5,3359		.rules = BIT(TRIGGER_NETDEV_TX),3360	},3361	{3362		.mode = 6,3363		.rules = (BIT(TRIGGER_NETDEV_LINK_10) |3364			  BIT(TRIGGER_NETDEV_LINK_1000)),3365	},3366	{3367		.mode = 7,3368		.rules = BIT(TRIGGER_NETDEV_LINK_10),3369	},3370	{3371		.mode = 8,3372		.rules = 0,3373	},3374};3375 3376static int marvell_find_led_mode(unsigned long rules,3377				 const struct marvell_led_rules *marvell_rules,3378				 int count,3379				 int *mode)3380{3381	int i;3382 3383	for (i = 0; i < count; i++) {3384		if (marvell_rules[i].rules == rules) {3385			*mode = marvell_rules[i].mode;3386			return 0;3387		}3388	}3389	return -EOPNOTSUPP;3390}3391 3392static int marvell_get_led_mode(u8 index, unsigned long rules, int *mode)3393{3394	int ret;3395 3396	switch (index) {3397	case 0:3398		ret = marvell_find_led_mode(rules, marvell_led0,3399					    ARRAY_SIZE(marvell_led0), mode);3400		break;3401	case 1:3402		ret = marvell_find_led_mode(rules, marvell_led1,3403					    ARRAY_SIZE(marvell_led1), mode);3404		break;3405	case 2:3406		ret = marvell_find_led_mode(rules, marvell_led2,3407					    ARRAY_SIZE(marvell_led2), mode);3408		break;3409	default:3410		ret = -EINVAL;3411	}3412 3413	return ret;3414}3415 3416static int marvell_find_led_rules(unsigned long *rules,3417				  const struct marvell_led_rules *marvell_rules,3418				  int count,3419				  int mode)3420{3421	int i;3422 3423	for (i = 0; i < count; i++) {3424		if (marvell_rules[i].mode == mode) {3425			*rules = marvell_rules[i].rules;3426			return 0;3427		}3428	}3429	return -EOPNOTSUPP;3430}3431 3432static int marvell_get_led_rules(u8 index, unsigned long *rules, int mode)3433{3434	int ret;3435 3436	switch (index) {3437	case 0:3438		ret = marvell_find_led_rules(rules, marvell_led0,3439					     ARRAY_SIZE(marvell_led0), mode);3440		break;3441	case 1:3442		ret = marvell_find_led_rules(rules, marvell_led1,3443					     ARRAY_SIZE(marvell_led1), mode);3444		break;3445	case 2:3446		ret = marvell_find_led_rules(rules, marvell_led2,3447					     ARRAY_SIZE(marvell_led2), mode);3448		break;3449	default:3450		ret = -EOPNOTSUPP;3451	}3452 3453	return ret;3454}3455 3456static int m88e1318_led_hw_is_supported(struct phy_device *phydev, u8 index,3457					unsigned long rules)3458{3459	int mode, ret;3460 3461	switch (index) {3462	case 0:3463	case 1:3464	case 2:3465		ret = marvell_get_led_mode(index, rules, &mode);3466		break;3467	default:3468		ret = -EINVAL;3469	}3470 3471	return ret;3472}3473 3474static int m88e1318_led_hw_control_set(struct phy_device *phydev, u8 index,3475				       unsigned long rules)3476{3477	int mode, ret, reg;3478 3479	switch (index) {3480	case 0:3481	case 1:3482	case 2:3483		ret = marvell_get_led_mode(index, rules, &mode);3484		break;3485	default:3486		ret = -EINVAL;3487	}3488 3489	if (ret < 0)3490		return ret;3491 3492	reg = phy_read_paged(phydev, MII_MARVELL_LED_PAGE,3493			     MII_88E1318S_PHY_LED_FUNC);3494	if (reg < 0)3495		return reg;3496 3497	reg &= ~(0xf << (4 * index));3498	reg |= mode << (4 * index);3499	return phy_write_paged(phydev, MII_MARVELL_LED_PAGE,3500			       MII_88E1318S_PHY_LED_FUNC, reg);3501}3502 3503static int m88e1318_led_hw_control_get(struct phy_device *phydev, u8 index,3504				       unsigned long *rules)3505{3506	int mode, reg;3507 3508	if (index > 2)3509		return -EINVAL;3510 3511	reg = phy_read_paged(phydev, MII_MARVELL_LED_PAGE,3512			     MII_88E1318S_PHY_LED_FUNC);3513	if (reg < 0)3514		return reg;3515 3516	mode = (reg >> (4 * index)) & 0xf;3517 3518	return marvell_get_led_rules(index, rules, mode);3519}3520 3521static int marvell_probe(struct phy_device *phydev)3522{3523	struct marvell_priv *priv;3524 3525	priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL);3526	if (!priv)3527		return -ENOMEM;3528 3529	phydev->priv = priv;3530 3531	return marvell_hwmon_probe(phydev);3532}3533 3534static int m88e1510_sfp_insert(void *upstream, const struct sfp_eeprom_id *id)3535{3536	DECLARE_PHY_INTERFACE_MASK(interfaces);3537	struct phy_device *phydev = upstream;3538	phy_interface_t interface;3539	struct device *dev;3540	int oldpage;3541	int ret = 0;3542	u16 mode;3543 3544	__ETHTOOL_DECLARE_LINK_MODE_MASK(supported) = { 0, };3545 3546	dev = &phydev->mdio.dev;3547 3548	sfp_parse_support(phydev->sfp_bus, id, supported, interfaces);3549	interface = sfp_select_interface(phydev->sfp_bus, supported);3550 3551	dev_info(dev, "%s SFP module inserted\n", phy_modes(interface));3552 3553	switch (interface) {3554	case PHY_INTERFACE_MODE_1000BASEX:3555		mode = MII_88E1510_GEN_CTRL_REG_1_MODE_RGMII_1000X;3556 3557		break;3558	case PHY_INTERFACE_MODE_100BASEX:3559		mode = MII_88E1510_GEN_CTRL_REG_1_MODE_RGMII_100FX;3560 3561		break;3562	case PHY_INTERFACE_MODE_SGMII:3563		mode = MII_88E1510_GEN_CTRL_REG_1_MODE_RGMII_SGMII;3564 3565		break;3566	default:3567		dev_err(dev, "Incompatible SFP module inserted\n");3568 3569		return -EINVAL;3570	}3571 3572	oldpage = phy_select_page(phydev, MII_MARVELL_MODE_PAGE);3573	if (oldpage < 0)3574		goto error;3575 3576	ret = __phy_modify(phydev, MII_88E1510_GEN_CTRL_REG_1,3577			   MII_88E1510_GEN_CTRL_REG_1_MODE_MASK, mode);3578	if (ret < 0)3579		goto error;3580 3581	ret = __phy_set_bits(phydev, MII_88E1510_GEN_CTRL_REG_1,3582			     MII_88E1510_GEN_CTRL_REG_1_RESET);3583 3584error:3585	return phy_restore_page(phydev, oldpage, ret);3586}3587 3588static void m88e1510_sfp_remove(void *upstream)3589{3590	struct phy_device *phydev = upstream;3591	int oldpage;3592	int ret = 0;3593 3594	oldpage = phy_select_page(phydev, MII_MARVELL_MODE_PAGE);3595	if (oldpage < 0)3596		goto error;3597 3598	ret = __phy_modify(phydev, MII_88E1510_GEN_CTRL_REG_1,3599			   MII_88E1510_GEN_CTRL_REG_1_MODE_MASK,3600			   MII_88E1510_GEN_CTRL_REG_1_MODE_RGMII);3601	if (ret < 0)3602		goto error;3603 3604	ret = __phy_set_bits(phydev, MII_88E1510_GEN_CTRL_REG_1,3605			     MII_88E1510_GEN_CTRL_REG_1_RESET);3606 3607error:3608	phy_restore_page(phydev, oldpage, ret);3609}3610 3611static const struct sfp_upstream_ops m88e1510_sfp_ops = {3612	.module_insert = m88e1510_sfp_insert,3613	.module_remove = m88e1510_sfp_remove,3614	.attach = phy_sfp_attach,3615	.detach = phy_sfp_detach,3616	.connect_phy = phy_sfp_connect_phy,3617	.disconnect_phy = phy_sfp_disconnect_phy,3618};3619 3620static int m88e1510_probe(struct phy_device *phydev)3621{3622	int err;3623 3624	err = marvell_probe(phydev);3625	if (err)3626		return err;3627 3628	return phy_sfp_probe(phydev, &m88e1510_sfp_ops);3629}3630 3631static struct phy_driver marvell_drivers[] = {3632	{3633		.phy_id = MARVELL_PHY_ID_88E1101,3634		.phy_id_mask = MARVELL_PHY_ID_MASK,3635		.name = "Marvell 88E1101",3636		/* PHY_GBIT_FEATURES */3637		.probe = marvell_probe,3638		.config_init = marvell_config_init,3639		.config_aneg = m88e1101_config_aneg,3640		.config_intr = marvell_config_intr,3641		.handle_interrupt = marvell_handle_interrupt,3642		.resume = genphy_resume,3643		.suspend = genphy_suspend,3644		.read_page = marvell_read_page,3645		.write_page = marvell_write_page,3646		.get_sset_count = marvell_get_sset_count,3647		.get_strings = marvell_get_strings,3648		.get_stats = marvell_get_stats,3649	},3650	{3651		.phy_id = MARVELL_PHY_ID_88E3082,3652		.phy_id_mask = MARVELL_PHY_ID_MASK,3653		.name = "Marvell 88E308X/88E609X Family",3654		/* PHY_BASIC_FEATURES */3655		.probe = marvell_probe,3656		.config_init = marvell_config_init,3657		.aneg_done = marvell_aneg_done,3658		.read_status = marvell_read_status,3659		.resume = genphy_resume,3660		.suspend = genphy_suspend,3661		.cable_test_start = m88e3082_vct_cable_test_start,3662		.cable_test_get_status = m88e3082_vct_cable_test_get_status,3663	},3664	{3665		.phy_id = MARVELL_PHY_ID_88E1112,3666		.phy_id_mask = MARVELL_PHY_ID_MASK,3667		.name = "Marvell 88E1112",3668		/* PHY_GBIT_FEATURES */3669		.probe = marvell_probe,3670		.config_init = m88e1112_config_init,3671		.config_aneg = marvell_config_aneg,3672		.config_intr = marvell_config_intr,3673		.handle_interrupt = marvell_handle_interrupt,3674		.resume = genphy_resume,3675		.suspend = genphy_suspend,3676		.read_page = marvell_read_page,3677		.write_page = marvell_write_page,3678		.get_sset_count = marvell_get_sset_count,3679		.get_strings = marvell_get_strings,3680		.get_stats = marvell_get_stats,3681		.get_tunable = m88e1011_get_tunable,3682		.set_tunable = m88e1011_set_tunable,3683	},3684	{3685		.phy_id = MARVELL_PHY_ID_88E1111,3686		.phy_id_mask = MARVELL_PHY_ID_MASK,3687		.name = "Marvell 88E1111",3688		/* PHY_GBIT_FEATURES */3689		.flags = PHY_POLL_CABLE_TEST,3690		.probe = marvell_probe,3691		.config_init = m88e1111gbe_config_init,3692		.config_aneg = m88e1111_config_aneg,3693		.read_status = marvell_read_status,3694		.config_intr = marvell_config_intr,3695		.handle_interrupt = marvell_handle_interrupt,3696		.resume = genphy_resume,3697		.suspend = genphy_suspend,3698		.read_page = marvell_read_page,3699		.write_page = marvell_write_page,3700		.get_sset_count = marvell_get_sset_count,3701		.get_strings = marvell_get_strings,3702		.get_stats = marvell_get_stats,3703		.get_tunable = m88e1111_get_tunable,3704		.set_tunable = m88e1111_set_tunable,3705		.cable_test_start = m88e1111_vct_cable_test_start,3706		.cable_test_get_status = m88e1111_vct_cable_test_get_status,3707	},3708	{3709		.phy_id = MARVELL_PHY_ID_88E1111_FINISAR,3710		.phy_id_mask = MARVELL_PHY_ID_MASK,3711		.name = "Marvell 88E1111 (Finisar)",3712		/* PHY_GBIT_FEATURES */3713		.probe = marvell_probe,3714		.config_init = m88e1111gbe_config_init,3715		.config_aneg = m88e1111_config_aneg,3716		.read_status = marvell_read_status,3717		.config_intr = marvell_config_intr,3718		.handle_interrupt = marvell_handle_interrupt,3719		.resume = genphy_resume,3720		.suspend = genphy_suspend,3721		.read_page = marvell_read_page,3722		.write_page = marvell_write_page,3723		.get_sset_count = marvell_get_sset_count,3724		.get_strings = marvell_get_strings,3725		.get_stats = marvell_get_stats,3726		.get_tunable = m88e1111_get_tunable,3727		.set_tunable = m88e1111_set_tunable,3728	},3729	{3730		.phy_id = MARVELL_PHY_ID_88E1118,3731		.phy_id_mask = MARVELL_PHY_ID_MASK,3732		.name = "Marvell 88E1118",3733		/* PHY_GBIT_FEATURES */3734		.probe = marvell_probe,3735		.config_init = m88e1118_config_init,3736		.config_aneg = m88e1118_config_aneg,3737		.config_intr = marvell_config_intr,3738		.handle_interrupt = marvell_handle_interrupt,3739		.resume = genphy_resume,3740		.suspend = genphy_suspend,3741		.read_page = marvell_read_page,3742		.write_page = marvell_write_page,3743		.get_sset_count = marvell_get_sset_count,3744		.get_strings = marvell_get_strings,3745		.get_stats = marvell_get_stats,3746	},3747	{3748		.phy_id = MARVELL_PHY_ID_88E1121R,3749		.phy_id_mask = MARVELL_PHY_ID_MASK,3750		.name = "Marvell 88E1121R",3751		.driver_data = DEF_MARVELL_HWMON_OPS(m88e1121_hwmon_ops),3752		/* PHY_GBIT_FEATURES */3753		.probe = marvell_probe,3754		.config_init = marvell_1011gbe_config_init,3755		.config_aneg = m88e1121_config_aneg,3756		.read_status = marvell_read_status,3757		.config_intr = marvell_config_intr,3758		.handle_interrupt = marvell_handle_interrupt,3759		.resume = genphy_resume,3760		.suspend = genphy_suspend,3761		.read_page = marvell_read_page,3762		.write_page = marvell_write_page,3763		.get_sset_count = marvell_get_sset_count,3764		.get_strings = marvell_get_strings,3765		.get_stats = marvell_get_stats,3766		.get_tunable = m88e1011_get_tunable,3767		.set_tunable = m88e1011_set_tunable,3768	},3769	{3770		.phy_id = MARVELL_PHY_ID_88E1318S,3771		.phy_id_mask = MARVELL_PHY_ID_MASK,3772		.name = "Marvell 88E1318S",3773		/* PHY_GBIT_FEATURES */3774		.probe = marvell_probe,3775		.config_init = m88e1318_config_init,3776		.config_aneg = m88e1318_config_aneg,3777		.read_status = marvell_read_status,3778		.config_intr = marvell_config_intr,3779		.handle_interrupt = marvell_handle_interrupt,3780		.get_wol = m88e1318_get_wol,3781		.set_wol = m88e1318_set_wol,3782		.resume = genphy_resume,3783		.suspend = genphy_suspend,3784		.read_page = marvell_read_page,3785		.write_page = marvell_write_page,3786		.get_sset_count = marvell_get_sset_count,3787		.get_strings = marvell_get_strings,3788		.get_stats = marvell_get_stats,3789		.led_brightness_set = m88e1318_led_brightness_set,3790		.led_blink_set = m88e1318_led_blink_set,3791		.led_hw_is_supported = m88e1318_led_hw_is_supported,3792		.led_hw_control_set = m88e1318_led_hw_control_set,3793		.led_hw_control_get = m88e1318_led_hw_control_get,3794	},3795	{3796		.phy_id = MARVELL_PHY_ID_88E1145,3797		.phy_id_mask = MARVELL_PHY_ID_MASK,3798		.name = "Marvell 88E1145",3799		/* PHY_GBIT_FEATURES */3800		.flags = PHY_POLL_CABLE_TEST,3801		.probe = marvell_probe,3802		.config_init = m88e1145_config_init,3803		.config_aneg = m88e1101_config_aneg,3804		.config_intr = marvell_config_intr,3805		.handle_interrupt = marvell_handle_interrupt,3806		.resume = genphy_resume,3807		.suspend = genphy_suspend,3808		.read_page = marvell_read_page,3809		.write_page = marvell_write_page,3810		.get_sset_count = marvell_get_sset_count,3811		.get_strings = marvell_get_strings,3812		.get_stats = marvell_get_stats,3813		.get_tunable = m88e1111_get_tunable,3814		.set_tunable = m88e1111_set_tunable,3815		.cable_test_start = m88e1111_vct_cable_test_start,3816		.cable_test_get_status = m88e1111_vct_cable_test_get_status,3817	},3818	{3819		.phy_id = MARVELL_PHY_ID_88E1149R,3820		.phy_id_mask = MARVELL_PHY_ID_MASK,3821		.name = "Marvell 88E1149R",3822		/* PHY_GBIT_FEATURES */3823		.probe = marvell_probe,3824		.config_init = m88e1149_config_init,3825		.config_aneg = m88e1118_config_aneg,3826		.config_intr = marvell_config_intr,3827		.handle_interrupt = marvell_handle_interrupt,3828		.resume = genphy_resume,3829		.suspend = genphy_suspend,3830		.read_page = marvell_read_page,3831		.write_page = marvell_write_page,3832		.get_sset_count = marvell_get_sset_count,3833		.get_strings = marvell_get_strings,3834		.get_stats = marvell_get_stats,3835	},3836	{3837		.phy_id = MARVELL_PHY_ID_88E1240,3838		.phy_id_mask = MARVELL_PHY_ID_MASK,3839		.name = "Marvell 88E1240",3840		/* PHY_GBIT_FEATURES */3841		.probe = marvell_probe,3842		.config_init = m88e1112_config_init,3843		.config_aneg = marvell_config_aneg,3844		.config_intr = marvell_config_intr,3845		.handle_interrupt = marvell_handle_interrupt,3846		.resume = genphy_resume,3847		.suspend = genphy_suspend,3848		.read_page = marvell_read_page,3849		.write_page = marvell_write_page,3850		.get_sset_count = marvell_get_sset_count,3851		.get_strings = marvell_get_strings,3852		.get_stats = marvell_get_stats,3853		.get_tunable = m88e1011_get_tunable,3854		.set_tunable = m88e1011_set_tunable,3855	},3856	{3857		.phy_id = MARVELL_PHY_ID_88E1116R,3858		.phy_id_mask = MARVELL_PHY_ID_MASK,3859		.name = "Marvell 88E1116R",3860		/* PHY_GBIT_FEATURES */3861		.probe = marvell_probe,3862		.config_init = m88e1116r_config_init,3863		.config_intr = marvell_config_intr,3864		.handle_interrupt = marvell_handle_interrupt,3865		.resume = genphy_resume,3866		.suspend = genphy_suspend,3867		.read_page = marvell_read_page,3868		.write_page = marvell_write_page,3869		.get_sset_count = marvell_get_sset_count,3870		.get_strings = marvell_get_strings,3871		.get_stats = marvell_get_stats,3872		.get_tunable = m88e1011_get_tunable,3873		.set_tunable = m88e1011_set_tunable,3874	},3875	{3876		.phy_id = MARVELL_PHY_ID_88E1510,3877		.phy_id_mask = MARVELL_PHY_ID_MASK,3878		.name = "Marvell 88E1510",3879		.driver_data = DEF_MARVELL_HWMON_OPS(m88e1510_hwmon_ops),3880		.features = PHY_GBIT_FIBRE_FEATURES,3881		.flags = PHY_POLL_CABLE_TEST,3882		.probe = m88e1510_probe,3883		.config_init = m88e1510_config_init,3884		.config_aneg = m88e1510_config_aneg,3885		.read_status = marvell_read_status,3886		.config_intr = marvell_config_intr,3887		.handle_interrupt = marvell_handle_interrupt,3888		.get_wol = m88e1318_get_wol,3889		.set_wol = m88e1318_set_wol,3890		.resume = marvell_resume,3891		.suspend = marvell_suspend,3892		.read_page = marvell_read_page,3893		.write_page = marvell_write_page,3894		.get_sset_count = marvell_get_sset_count,3895		.get_strings = marvell_get_strings,3896		.get_stats = marvell_get_stats,3897		.set_loopback = m88e1510_loopback,3898		.get_tunable = m88e1011_get_tunable,3899		.set_tunable = m88e1011_set_tunable,3900		.cable_test_start = marvell_vct7_cable_test_start,3901		.cable_test_tdr_start = marvell_vct5_cable_test_tdr_start,3902		.cable_test_get_status = marvell_vct7_cable_test_get_status,3903		.led_brightness_set = m88e1318_led_brightness_set,3904		.led_blink_set = m88e1318_led_blink_set,3905		.led_hw_is_supported = m88e1318_led_hw_is_supported,3906		.led_hw_control_set = m88e1318_led_hw_control_set,3907		.led_hw_control_get = m88e1318_led_hw_control_get,3908	},3909	{3910		.phy_id = MARVELL_PHY_ID_88E1540,3911		.phy_id_mask = MARVELL_PHY_ID_MASK,3912		.name = "Marvell 88E1540",3913		.driver_data = DEF_MARVELL_HWMON_OPS(m88e1510_hwmon_ops),3914		/* PHY_GBIT_FEATURES */3915		.flags = PHY_POLL_CABLE_TEST,3916		.probe = marvell_probe,3917		.config_init = marvell_1011gbe_config_init,3918		.config_aneg = m88e1510_config_aneg,3919		.read_status = marvell_read_status,3920		.config_intr = marvell_config_intr,3921		.handle_interrupt = marvell_handle_interrupt,3922		.resume = genphy_resume,3923		.suspend = genphy_suspend,3924		.read_page = marvell_read_page,3925		.write_page = marvell_write_page,3926		.get_sset_count = marvell_get_sset_count,3927		.get_strings = marvell_get_strings,3928		.get_stats = marvell_get_stats,3929		.get_tunable = m88e1540_get_tunable,3930		.set_tunable = m88e1540_set_tunable,3931		.cable_test_start = marvell_vct7_cable_test_start,3932		.cable_test_tdr_start = marvell_vct5_cable_test_tdr_start,3933		.cable_test_get_status = marvell_vct7_cable_test_get_status,3934		.led_brightness_set = m88e1318_led_brightness_set,3935		.led_blink_set = m88e1318_led_blink_set,3936		.led_hw_is_supported = m88e1318_led_hw_is_supported,3937		.led_hw_control_set = m88e1318_led_hw_control_set,3938		.led_hw_control_get = m88e1318_led_hw_control_get,3939	},3940	{3941		.phy_id = MARVELL_PHY_ID_88E1545,3942		.phy_id_mask = MARVELL_PHY_ID_MASK,3943		.name = "Marvell 88E1545",3944		.driver_data = DEF_MARVELL_HWMON_OPS(m88e1510_hwmon_ops),3945		.probe = marvell_probe,3946		/* PHY_GBIT_FEATURES */3947		.flags = PHY_POLL_CABLE_TEST,3948		.config_init = marvell_1011gbe_config_init,3949		.config_aneg = m88e1510_config_aneg,3950		.read_status = marvell_read_status,3951		.config_intr = marvell_config_intr,3952		.handle_interrupt = marvell_handle_interrupt,3953		.resume = genphy_resume,3954		.suspend = genphy_suspend,3955		.read_page = marvell_read_page,3956		.write_page = marvell_write_page,3957		.get_sset_count = marvell_get_sset_count,3958		.get_strings = marvell_get_strings,3959		.get_stats = marvell_get_stats,3960		.get_tunable = m88e1540_get_tunable,3961		.set_tunable = m88e1540_set_tunable,3962		.cable_test_start = marvell_vct7_cable_test_start,3963		.cable_test_tdr_start = marvell_vct5_cable_test_tdr_start,3964		.cable_test_get_status = marvell_vct7_cable_test_get_status,3965		.led_brightness_set = m88e1318_led_brightness_set,3966		.led_blink_set = m88e1318_led_blink_set,3967		.led_hw_is_supported = m88e1318_led_hw_is_supported,3968		.led_hw_control_set = m88e1318_led_hw_control_set,3969		.led_hw_control_get = m88e1318_led_hw_control_get,3970	},3971	{3972		.phy_id = MARVELL_PHY_ID_88E3016,3973		.phy_id_mask = MARVELL_PHY_ID_MASK,3974		.name = "Marvell 88E3016",3975		/* PHY_BASIC_FEATURES */3976		.probe = marvell_probe,3977		.config_init = m88e3016_config_init,3978		.aneg_done = marvell_aneg_done,3979		.read_status = marvell_read_status,3980		.config_intr = marvell_config_intr,3981		.handle_interrupt = marvell_handle_interrupt,3982		.resume = genphy_resume,3983		.suspend = genphy_suspend,3984		.read_page = marvell_read_page,3985		.write_page = marvell_write_page,3986		.get_sset_count = marvell_get_sset_count,3987		.get_strings = marvell_get_strings,3988		.get_stats = marvell_get_stats,3989	},3990	{3991		.phy_id = MARVELL_PHY_ID_88E6250_FAMILY,3992		.phy_id_mask = MARVELL_PHY_ID_MASK,3993		.name = "Marvell 88E6250 Family",3994		/* PHY_BASIC_FEATURES */3995		.probe = marvell_probe,3996		.aneg_done = marvell_aneg_done,3997		.config_intr = marvell_config_intr,3998		.handle_interrupt = marvell_handle_interrupt,3999		.resume = genphy_resume,4000		.suspend = genphy_suspend,4001		.get_sset_count = marvell_get_sset_count_simple,4002		.get_strings = marvell_get_strings_simple,4003		.get_stats = marvell_get_stats_simple,4004	},4005	{4006		.phy_id = MARVELL_PHY_ID_88E6341_FAMILY,4007		.phy_id_mask = MARVELL_PHY_ID_MASK,4008		.name = "Marvell 88E6341 Family",4009		.driver_data = DEF_MARVELL_HWMON_OPS(m88e1510_hwmon_ops),4010		/* PHY_GBIT_FEATURES */4011		.flags = PHY_POLL_CABLE_TEST,4012		.probe = marvell_probe,4013		.config_init = marvell_1011gbe_config_init,4014		.config_aneg = m88e6390_config_aneg,4015		.read_status = marvell_read_status,4016		.config_intr = marvell_config_intr,4017		.handle_interrupt = marvell_handle_interrupt,4018		.resume = genphy_resume,4019		.suspend = genphy_suspend,4020		.read_page = marvell_read_page,4021		.write_page = marvell_write_page,4022		.get_sset_count = marvell_get_sset_count,4023		.get_strings = marvell_get_strings,4024		.get_stats = marvell_get_stats,4025		.get_tunable = m88e1540_get_tunable,4026		.set_tunable = m88e1540_set_tunable,4027		.cable_test_start = marvell_vct7_cable_test_start,4028		.cable_test_tdr_start = marvell_vct5_cable_test_tdr_start,4029		.cable_test_get_status = marvell_vct7_cable_test_get_status,4030	},4031	{4032		.phy_id = MARVELL_PHY_ID_88E6390_FAMILY,4033		.phy_id_mask = MARVELL_PHY_ID_MASK,4034		.name = "Marvell 88E6390 Family",4035		.driver_data = DEF_MARVELL_HWMON_OPS(m88e6390_hwmon_ops),4036		/* PHY_GBIT_FEATURES */4037		.flags = PHY_POLL_CABLE_TEST,4038		.probe = marvell_probe,4039		.config_init = marvell_1011gbe_config_init,4040		.config_aneg = m88e6390_config_aneg,4041		.read_status = marvell_read_status,4042		.config_intr = marvell_config_intr,4043		.handle_interrupt = marvell_handle_interrupt,4044		.resume = genphy_resume,4045		.suspend = genphy_suspend,4046		.read_page = marvell_read_page,4047		.write_page = marvell_write_page,4048		.get_sset_count = marvell_get_sset_count,4049		.get_strings = marvell_get_strings,4050		.get_stats = marvell_get_stats,4051		.get_tunable = m88e1540_get_tunable,4052		.set_tunable = m88e1540_set_tunable,4053		.cable_test_start = marvell_vct7_cable_test_start,4054		.cable_test_tdr_start = marvell_vct5_cable_test_tdr_start,4055		.cable_test_get_status = marvell_vct7_cable_test_get_status,4056	},4057	{4058		.phy_id = MARVELL_PHY_ID_88E6393_FAMILY,4059		.phy_id_mask = MARVELL_PHY_ID_MASK,4060		.name = "Marvell 88E6393 Family",4061		.driver_data = DEF_MARVELL_HWMON_OPS(m88e6393_hwmon_ops),4062		/* PHY_GBIT_FEATURES */4063		.flags = PHY_POLL_CABLE_TEST,4064		.probe = marvell_probe,4065		.config_init = marvell_1011gbe_config_init,4066		.config_aneg = m88e1510_config_aneg,4067		.read_status = marvell_read_status,4068		.config_intr = marvell_config_intr,4069		.handle_interrupt = marvell_handle_interrupt,4070		.resume = genphy_resume,4071		.suspend = genphy_suspend,4072		.read_page = marvell_read_page,4073		.write_page = marvell_write_page,4074		.get_sset_count = marvell_get_sset_count,4075		.get_strings = marvell_get_strings,4076		.get_stats = marvell_get_stats,4077		.get_tunable = m88e1540_get_tunable,4078		.set_tunable = m88e1540_set_tunable,4079		.cable_test_start = marvell_vct7_cable_test_start,4080		.cable_test_tdr_start = marvell_vct5_cable_test_tdr_start,4081		.cable_test_get_status = marvell_vct7_cable_test_get_status,4082	},4083	{4084		.phy_id = MARVELL_PHY_ID_88E1340S,4085		.phy_id_mask = MARVELL_PHY_ID_MASK,4086		.name = "Marvell 88E1340S",4087		.driver_data = DEF_MARVELL_HWMON_OPS(m88e1510_hwmon_ops),4088		.probe = marvell_probe,4089		/* PHY_GBIT_FEATURES */4090		.config_init = marvell_1011gbe_config_init,4091		.config_aneg = m88e1510_config_aneg,4092		.read_status = marvell_read_status,4093		.config_intr = marvell_config_intr,4094		.handle_interrupt = marvell_handle_interrupt,4095		.resume = genphy_resume,4096		.suspend = genphy_suspend,4097		.read_page = marvell_read_page,4098		.write_page = marvell_write_page,4099		.get_sset_count = marvell_get_sset_count,4100		.get_strings = marvell_get_strings,4101		.get_stats = marvell_get_stats,4102		.get_tunable = m88e1540_get_tunable,4103		.set_tunable = m88e1540_set_tunable,4104	},4105	{4106		.phy_id = MARVELL_PHY_ID_88E1548P,4107		.phy_id_mask = MARVELL_PHY_ID_MASK,4108		.name = "Marvell 88E1548P",4109		.driver_data = DEF_MARVELL_HWMON_OPS(m88e1510_hwmon_ops),4110		.probe = marvell_probe,4111		.features = PHY_GBIT_FIBRE_FEATURES,4112		.config_init = marvell_1011gbe_config_init,4113		.config_aneg = m88e1510_config_aneg,4114		.read_status = marvell_read_status,4115		.config_intr = marvell_config_intr,4116		.handle_interrupt = marvell_handle_interrupt,4117		.resume = genphy_resume,4118		.suspend = genphy_suspend,4119		.read_page = marvell_read_page,4120		.write_page = marvell_write_page,4121		.get_sset_count = marvell_get_sset_count,4122		.get_strings = marvell_get_strings,4123		.get_stats = marvell_get_stats,4124		.get_tunable = m88e1540_get_tunable,4125		.set_tunable = m88e1540_set_tunable,4126		.led_brightness_set = m88e1318_led_brightness_set,4127		.led_blink_set = m88e1318_led_blink_set,4128		.led_hw_is_supported = m88e1318_led_hw_is_supported,4129		.led_hw_control_set = m88e1318_led_hw_control_set,4130		.led_hw_control_get = m88e1318_led_hw_control_get,4131	},4132};4133 4134module_phy_driver(marvell_drivers);4135 4136static struct mdio_device_id __maybe_unused marvell_tbl[] = {4137	{ MARVELL_PHY_ID_88E1101, MARVELL_PHY_ID_MASK },4138	{ MARVELL_PHY_ID_88E3082, MARVELL_PHY_ID_MASK },4139	{ MARVELL_PHY_ID_88E1112, MARVELL_PHY_ID_MASK },4140	{ MARVELL_PHY_ID_88E1111, MARVELL_PHY_ID_MASK },4141	{ MARVELL_PHY_ID_88E1111_FINISAR, MARVELL_PHY_ID_MASK },4142	{ MARVELL_PHY_ID_88E1118, MARVELL_PHY_ID_MASK },4143	{ MARVELL_PHY_ID_88E1121R, MARVELL_PHY_ID_MASK },4144	{ MARVELL_PHY_ID_88E1145, MARVELL_PHY_ID_MASK },4145	{ MARVELL_PHY_ID_88E1149R, MARVELL_PHY_ID_MASK },4146	{ MARVELL_PHY_ID_88E1240, MARVELL_PHY_ID_MASK },4147	{ MARVELL_PHY_ID_88E1318S, MARVELL_PHY_ID_MASK },4148	{ MARVELL_PHY_ID_88E1116R, MARVELL_PHY_ID_MASK },4149	{ MARVELL_PHY_ID_88E1510, MARVELL_PHY_ID_MASK },4150	{ MARVELL_PHY_ID_88E1540, MARVELL_PHY_ID_MASK },4151	{ MARVELL_PHY_ID_88E1545, MARVELL_PHY_ID_MASK },4152	{ MARVELL_PHY_ID_88E3016, MARVELL_PHY_ID_MASK },4153	{ MARVELL_PHY_ID_88E6250_FAMILY, MARVELL_PHY_ID_MASK },4154	{ MARVELL_PHY_ID_88E6341_FAMILY, MARVELL_PHY_ID_MASK },4155	{ MARVELL_PHY_ID_88E6390_FAMILY, MARVELL_PHY_ID_MASK },4156	{ MARVELL_PHY_ID_88E6393_FAMILY, MARVELL_PHY_ID_MASK },4157	{ MARVELL_PHY_ID_88E1340S, MARVELL_PHY_ID_MASK },4158	{ MARVELL_PHY_ID_88E1548P, MARVELL_PHY_ID_MASK },4159	{ }4160};4161 4162MODULE_DEVICE_TABLE(mdio, marvell_tbl);4163