xref: /openbmc/linux/drivers/net/phy/marvell.c (revision b82cf17f)
1a2443fd1SAndrew Lunn // SPDX-License-Identifier: GPL-2.0+
200db8189SAndy Fleming /*
300db8189SAndy Fleming  * drivers/net/phy/marvell.c
400db8189SAndy Fleming  *
500db8189SAndy Fleming  * Driver for Marvell PHYs
600db8189SAndy Fleming  *
700db8189SAndy Fleming  * Author: Andy Fleming
800db8189SAndy Fleming  *
900db8189SAndy Fleming  * Copyright (c) 2004 Freescale Semiconductor, Inc.
1000db8189SAndy Fleming  *
113871c387SMichael Stapelberg  * Copyright (c) 2013 Michael Stapelberg <michael@stapelberg.de>
1200db8189SAndy Fleming  */
1300db8189SAndy Fleming #include <linux/kernel.h>
1400db8189SAndy Fleming #include <linux/string.h>
150b04680fSAndrew Lunn #include <linux/ctype.h>
1600db8189SAndy Fleming #include <linux/errno.h>
1700db8189SAndy Fleming #include <linux/unistd.h>
180b04680fSAndrew Lunn #include <linux/hwmon.h>
1900db8189SAndy Fleming #include <linux/interrupt.h>
2000db8189SAndy Fleming #include <linux/init.h>
2100db8189SAndy Fleming #include <linux/delay.h>
2200db8189SAndy Fleming #include <linux/netdevice.h>
2300db8189SAndy Fleming #include <linux/etherdevice.h>
2400db8189SAndy Fleming #include <linux/skbuff.h>
2500db8189SAndy Fleming #include <linux/spinlock.h>
2600db8189SAndy Fleming #include <linux/mm.h>
2700db8189SAndy Fleming #include <linux/module.h>
2800db8189SAndy Fleming #include <linux/mii.h>
2900db8189SAndy Fleming #include <linux/ethtool.h>
3000db8189SAndy Fleming #include <linux/phy.h>
312f495c39SBenjamin Herrenschmidt #include <linux/marvell_phy.h>
3269f42be8SHeiner Kallweit #include <linux/bitfield.h>
33cf41a51dSDavid Daney #include <linux/of.h>
3400db8189SAndy Fleming 
35eea3b201SAvinash Kumar #include <linux/io.h>
3600db8189SAndy Fleming #include <asm/irq.h>
37eea3b201SAvinash Kumar #include <linux/uaccess.h>
3800db8189SAndy Fleming 
3927d916d6SDavid Daney #define MII_MARVELL_PHY_PAGE		22
4052295666SAndrew Lunn #define MII_MARVELL_COPPER_PAGE		0x00
4152295666SAndrew Lunn #define MII_MARVELL_FIBER_PAGE		0x01
4252295666SAndrew Lunn #define MII_MARVELL_MSCR_PAGE		0x02
4352295666SAndrew Lunn #define MII_MARVELL_LED_PAGE		0x03
4452295666SAndrew Lunn #define MII_MARVELL_MISC_TEST_PAGE	0x06
4552295666SAndrew Lunn #define MII_MARVELL_WOL_PAGE		0x11
4627d916d6SDavid Daney 
4700db8189SAndy Fleming #define MII_M1011_IEVENT		0x13
4800db8189SAndy Fleming #define MII_M1011_IEVENT_CLEAR		0x0000
4900db8189SAndy Fleming 
5000db8189SAndy Fleming #define MII_M1011_IMASK			0x12
5100db8189SAndy Fleming #define MII_M1011_IMASK_INIT		0x6400
5200db8189SAndy Fleming #define MII_M1011_IMASK_CLEAR		0x0000
5300db8189SAndy Fleming 
5476884679SAndy Fleming #define MII_M1011_PHY_SCR			0x10
55fecd5e91SAndrew Lunn #define MII_M1011_PHY_SCR_DOWNSHIFT_EN		BIT(11)
56f8d975beSHeiner Kallweit #define MII_M1011_PHY_SCR_DOWNSHIFT_MASK	GENMASK(14, 12)
57a3bdfce7SHeiner Kallweit #define MII_M1011_PHY_SCR_DOWNSHIFT_MAX		8
58fecd5e91SAndrew Lunn #define MII_M1011_PHY_SCR_MDI			(0x0 << 5)
59fecd5e91SAndrew Lunn #define MII_M1011_PHY_SCR_MDI_X			(0x1 << 5)
60fecd5e91SAndrew Lunn #define MII_M1011_PHY_SCR_AUTO_CROSS		(0x3 << 5)
6176884679SAndy Fleming 
62a3bdfce7SHeiner Kallweit #define MII_M1011_PHY_SSR			0x11
63a3bdfce7SHeiner Kallweit #define MII_M1011_PHY_SSR_DOWNSHIFT		BIT(5)
64a3bdfce7SHeiner Kallweit 
6576884679SAndy Fleming #define MII_M1111_PHY_LED_CONTROL	0x18
6676884679SAndy Fleming #define MII_M1111_PHY_LED_DIRECT	0x4100
6776884679SAndy Fleming #define MII_M1111_PHY_LED_COMBINE	0x411c
68895ee682SKim Phillips #define MII_M1111_PHY_EXT_CR		0x14
695c6bc519SHeiner Kallweit #define MII_M1111_PHY_EXT_CR_DOWNSHIFT_MASK	GENMASK(11, 9)
705c6bc519SHeiner Kallweit #define MII_M1111_PHY_EXT_CR_DOWNSHIFT_MAX	8
715c6bc519SHeiner Kallweit #define MII_M1111_PHY_EXT_CR_DOWNSHIFT_EN	BIT(8)
7261111598SAndrew Lunn #define MII_M1111_RGMII_RX_DELAY	BIT(7)
7361111598SAndrew Lunn #define MII_M1111_RGMII_TX_DELAY	BIT(1)
74895ee682SKim Phillips #define MII_M1111_PHY_EXT_SR		0x1b
75be937f1fSAlexandr Smirnov 
76895ee682SKim Phillips #define MII_M1111_HWCFG_MODE_MASK		0xf
77be937f1fSAlexandr Smirnov #define MII_M1111_HWCFG_MODE_FIBER_RGMII	0x3
784117b5beSKapil Juneja #define MII_M1111_HWCFG_MODE_SGMII_NO_CLK	0x4
79865b813aSAndrew Lunn #define MII_M1111_HWCFG_MODE_RTBI		0x7
805f8cbc13SLiu Yu-B13201 #define MII_M1111_HWCFG_MODE_COPPER_RTBI	0x9
81865b813aSAndrew Lunn #define MII_M1111_HWCFG_MODE_COPPER_RGMII	0xb
82865b813aSAndrew Lunn #define MII_M1111_HWCFG_FIBER_COPPER_RES	BIT(13)
83865b813aSAndrew Lunn #define MII_M1111_HWCFG_FIBER_COPPER_AUTO	BIT(15)
84be937f1fSAlexandr Smirnov 
85c477d044SCyril Chemparathy #define MII_88E1121_PHY_MSCR_REG	21
86c477d044SCyril Chemparathy #define MII_88E1121_PHY_MSCR_RX_DELAY	BIT(5)
87c477d044SCyril Chemparathy #define MII_88E1121_PHY_MSCR_TX_DELAY	BIT(4)
88424ca4c5SRussell King #define MII_88E1121_PHY_MSCR_DELAY_MASK	(BIT(5) | BIT(4))
89c477d044SCyril Chemparathy 
900b04680fSAndrew Lunn #define MII_88E1121_MISC_TEST				0x1a
910b04680fSAndrew Lunn #define MII_88E1510_MISC_TEST_TEMP_THRESHOLD_MASK	0x1f00
920b04680fSAndrew Lunn #define MII_88E1510_MISC_TEST_TEMP_THRESHOLD_SHIFT	8
930b04680fSAndrew Lunn #define MII_88E1510_MISC_TEST_TEMP_IRQ_EN		BIT(7)
940b04680fSAndrew Lunn #define MII_88E1510_MISC_TEST_TEMP_IRQ			BIT(6)
950b04680fSAndrew Lunn #define MII_88E1121_MISC_TEST_TEMP_SENSOR_EN		BIT(5)
960b04680fSAndrew Lunn #define MII_88E1121_MISC_TEST_TEMP_MASK			0x1f
970b04680fSAndrew Lunn 
980b04680fSAndrew Lunn #define MII_88E1510_TEMP_SENSOR		0x1b
990b04680fSAndrew Lunn #define MII_88E1510_TEMP_SENSOR_MASK	0xff
1000b04680fSAndrew Lunn 
10169f42be8SHeiner Kallweit #define MII_88E1540_COPPER_CTRL3	0x1a
10269f42be8SHeiner Kallweit #define MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_MASK	GENMASK(11, 10)
10369f42be8SHeiner Kallweit #define MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_00MS	0
10469f42be8SHeiner Kallweit #define MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_10MS	1
10569f42be8SHeiner Kallweit #define MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_20MS	2
10669f42be8SHeiner Kallweit #define MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_40MS	3
10769f42be8SHeiner Kallweit #define MII_88E1540_COPPER_CTRL3_FAST_LINK_DOWN		BIT(9)
10869f42be8SHeiner Kallweit 
109fee2d546SAndrew Lunn #define MII_88E6390_MISC_TEST		0x1b
110fee2d546SAndrew Lunn #define MII_88E6390_MISC_TEST_SAMPLE_1S		0
111fee2d546SAndrew Lunn #define MII_88E6390_MISC_TEST_SAMPLE_10MS	BIT(14)
112fee2d546SAndrew Lunn #define MII_88E6390_MISC_TEST_SAMPLE_DISABLE	BIT(15)
113fee2d546SAndrew Lunn #define MII_88E6390_MISC_TEST_SAMPLE_ENABLE	0
114fee2d546SAndrew Lunn #define MII_88E6390_MISC_TEST_SAMPLE_MASK	(0x3 << 14)
115fee2d546SAndrew Lunn 
116fee2d546SAndrew Lunn #define MII_88E6390_TEMP_SENSOR		0x1c
117fee2d546SAndrew Lunn #define MII_88E6390_TEMP_SENSOR_MASK	0xff
118fee2d546SAndrew Lunn #define MII_88E6390_TEMP_SENSOR_SAMPLES 10
119fee2d546SAndrew Lunn 
120337ac9d5SCyril Chemparathy #define MII_88E1318S_PHY_MSCR1_REG	16
121337ac9d5SCyril Chemparathy #define MII_88E1318S_PHY_MSCR1_PAD_ODD	BIT(6)
1223ff1c259SCyril Chemparathy 
1233871c387SMichael Stapelberg /* Copper Specific Interrupt Enable Register */
1243871c387SMichael Stapelberg #define MII_88E1318S_PHY_CSIER				0x12
1253871c387SMichael Stapelberg /* WOL Event Interrupt Enable */
1263871c387SMichael Stapelberg #define MII_88E1318S_PHY_CSIER_WOL_EIE			BIT(7)
1273871c387SMichael Stapelberg 
1283871c387SMichael Stapelberg /* LED Timer Control Register */
1293871c387SMichael Stapelberg #define MII_88E1318S_PHY_LED_TCR			0x12
1303871c387SMichael Stapelberg #define MII_88E1318S_PHY_LED_TCR_FORCE_INT		BIT(15)
1313871c387SMichael Stapelberg #define MII_88E1318S_PHY_LED_TCR_INTn_ENABLE		BIT(7)
1323871c387SMichael Stapelberg #define MII_88E1318S_PHY_LED_TCR_INT_ACTIVE_LOW		BIT(11)
1333871c387SMichael Stapelberg 
1343871c387SMichael Stapelberg /* Magic Packet MAC address registers */
1353871c387SMichael Stapelberg #define MII_88E1318S_PHY_MAGIC_PACKET_WORD2		0x17
1363871c387SMichael Stapelberg #define MII_88E1318S_PHY_MAGIC_PACKET_WORD1		0x18
1373871c387SMichael Stapelberg #define MII_88E1318S_PHY_MAGIC_PACKET_WORD0		0x19
1383871c387SMichael Stapelberg 
1393871c387SMichael Stapelberg #define MII_88E1318S_PHY_WOL_CTRL				0x10
1403871c387SMichael Stapelberg #define MII_88E1318S_PHY_WOL_CTRL_CLEAR_WOL_STATUS		BIT(12)
1413871c387SMichael Stapelberg #define MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE	BIT(14)
1423871c387SMichael Stapelberg 
14307777246SWang Dongsheng #define MII_PHY_LED_CTRL	        16
144140bc929SSergei Poselenov #define MII_88E1121_PHY_LED_DEF		0x0030
14507777246SWang Dongsheng #define MII_88E1510_PHY_LED_DEF		0x1177
146a93f7fe1SJian Shen #define MII_88E1510_PHY_LED0_LINK_LED1_ACTIVE	0x1040
147140bc929SSergei Poselenov 
148be937f1fSAlexandr Smirnov #define MII_M1011_PHY_STATUS		0x11
149be937f1fSAlexandr Smirnov #define MII_M1011_PHY_STATUS_1000	0x8000
150be937f1fSAlexandr Smirnov #define MII_M1011_PHY_STATUS_100	0x4000
151be937f1fSAlexandr Smirnov #define MII_M1011_PHY_STATUS_SPD_MASK	0xc000
152be937f1fSAlexandr Smirnov #define MII_M1011_PHY_STATUS_FULLDUPLEX	0x2000
153be937f1fSAlexandr Smirnov #define MII_M1011_PHY_STATUS_RESOLVED	0x0800
154be937f1fSAlexandr Smirnov #define MII_M1011_PHY_STATUS_LINK	0x0400
155be937f1fSAlexandr Smirnov 
1566b358aedSSebastian Hesselbarth #define MII_88E3016_PHY_SPEC_CTRL	0x10
1576b358aedSSebastian Hesselbarth #define MII_88E3016_DISABLE_SCRAMBLER	0x0200
1586b358aedSSebastian Hesselbarth #define MII_88E3016_AUTO_MDIX_CROSSOVER	0x0030
15976884679SAndy Fleming 
160930b37eeSStefan Roese #define MII_88E1510_GEN_CTRL_REG_1		0x14
161930b37eeSStefan Roese #define MII_88E1510_GEN_CTRL_REG_1_MODE_MASK	0x7
162930b37eeSStefan Roese #define MII_88E1510_GEN_CTRL_REG_1_MODE_SGMII	0x1	/* SGMII to copper */
163930b37eeSStefan Roese #define MII_88E1510_GEN_CTRL_REG_1_RESET	0x8000	/* Soft reset */
164930b37eeSStefan Roese 
1656cfb3bccSCharles-Antoine Couret #define LPA_PAUSE_FIBER		0x180
1666cfb3bccSCharles-Antoine Couret #define LPA_PAUSE_ASYM_FIBER	0x100
1676cfb3bccSCharles-Antoine Couret 
1682170fef7SCharles-Antoine Couret #define NB_FIBER_STATS	1
1696cfb3bccSCharles-Antoine Couret 
17000db8189SAndy Fleming MODULE_DESCRIPTION("Marvell PHY driver");
17100db8189SAndy Fleming MODULE_AUTHOR("Andy Fleming");
17200db8189SAndy Fleming MODULE_LICENSE("GPL");
17300db8189SAndy Fleming 
174d2fa47d9SAndrew Lunn struct marvell_hw_stat {
175d2fa47d9SAndrew Lunn 	const char *string;
176d2fa47d9SAndrew Lunn 	u8 page;
177d2fa47d9SAndrew Lunn 	u8 reg;
178d2fa47d9SAndrew Lunn 	u8 bits;
179d2fa47d9SAndrew Lunn };
180d2fa47d9SAndrew Lunn 
181d2fa47d9SAndrew Lunn static struct marvell_hw_stat marvell_hw_stats[] = {
1822170fef7SCharles-Antoine Couret 	{ "phy_receive_errors_copper", 0, 21, 16},
183d2fa47d9SAndrew Lunn 	{ "phy_idle_errors", 0, 10, 8 },
1842170fef7SCharles-Antoine Couret 	{ "phy_receive_errors_fiber", 1, 21, 16},
185d2fa47d9SAndrew Lunn };
186d2fa47d9SAndrew Lunn 
187d2fa47d9SAndrew Lunn struct marvell_priv {
188d2fa47d9SAndrew Lunn 	u64 stats[ARRAY_SIZE(marvell_hw_stats)];
1890b04680fSAndrew Lunn 	char *hwmon_name;
1900b04680fSAndrew Lunn 	struct device *hwmon_dev;
191d2fa47d9SAndrew Lunn };
192d2fa47d9SAndrew Lunn 
193424ca4c5SRussell King static int marvell_read_page(struct phy_device *phydev)
1946427bb2dSAndrew Lunn {
195424ca4c5SRussell King 	return __phy_read(phydev, MII_MARVELL_PHY_PAGE);
196424ca4c5SRussell King }
197424ca4c5SRussell King 
198424ca4c5SRussell King static int marvell_write_page(struct phy_device *phydev, int page)
199424ca4c5SRussell King {
200424ca4c5SRussell King 	return __phy_write(phydev, MII_MARVELL_PHY_PAGE, page);
2016427bb2dSAndrew Lunn }
2026427bb2dSAndrew Lunn 
2036427bb2dSAndrew Lunn static int marvell_set_page(struct phy_device *phydev, int page)
2046427bb2dSAndrew Lunn {
2056427bb2dSAndrew Lunn 	return phy_write(phydev, MII_MARVELL_PHY_PAGE, page);
2066427bb2dSAndrew Lunn }
2076427bb2dSAndrew Lunn 
20800db8189SAndy Fleming static int marvell_ack_interrupt(struct phy_device *phydev)
20900db8189SAndy Fleming {
21000db8189SAndy Fleming 	int err;
21100db8189SAndy Fleming 
21200db8189SAndy Fleming 	/* Clear the interrupts by reading the reg */
21300db8189SAndy Fleming 	err = phy_read(phydev, MII_M1011_IEVENT);
21400db8189SAndy Fleming 
21500db8189SAndy Fleming 	if (err < 0)
21600db8189SAndy Fleming 		return err;
21700db8189SAndy Fleming 
21800db8189SAndy Fleming 	return 0;
21900db8189SAndy Fleming }
22000db8189SAndy Fleming 
22100db8189SAndy Fleming static int marvell_config_intr(struct phy_device *phydev)
22200db8189SAndy Fleming {
22300db8189SAndy Fleming 	int err;
22400db8189SAndy Fleming 
22500db8189SAndy Fleming 	if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
22623beb38fSAndrew Lunn 		err = phy_write(phydev, MII_M1011_IMASK,
22723beb38fSAndrew Lunn 				MII_M1011_IMASK_INIT);
22800db8189SAndy Fleming 	else
22923beb38fSAndrew Lunn 		err = phy_write(phydev, MII_M1011_IMASK,
23023beb38fSAndrew Lunn 				MII_M1011_IMASK_CLEAR);
23100db8189SAndy Fleming 
23200db8189SAndy Fleming 	return err;
23300db8189SAndy Fleming }
23400db8189SAndy Fleming 
235239aa55bSDavid Thomson static int marvell_set_polarity(struct phy_device *phydev, int polarity)
236239aa55bSDavid Thomson {
237239aa55bSDavid Thomson 	int reg;
238239aa55bSDavid Thomson 	int err;
239239aa55bSDavid Thomson 	int val;
240239aa55bSDavid Thomson 
241239aa55bSDavid Thomson 	/* get the current settings */
242239aa55bSDavid Thomson 	reg = phy_read(phydev, MII_M1011_PHY_SCR);
243239aa55bSDavid Thomson 	if (reg < 0)
244239aa55bSDavid Thomson 		return reg;
245239aa55bSDavid Thomson 
246239aa55bSDavid Thomson 	val = reg;
247239aa55bSDavid Thomson 	val &= ~MII_M1011_PHY_SCR_AUTO_CROSS;
248239aa55bSDavid Thomson 	switch (polarity) {
249239aa55bSDavid Thomson 	case ETH_TP_MDI:
250239aa55bSDavid Thomson 		val |= MII_M1011_PHY_SCR_MDI;
251239aa55bSDavid Thomson 		break;
252239aa55bSDavid Thomson 	case ETH_TP_MDI_X:
253239aa55bSDavid Thomson 		val |= MII_M1011_PHY_SCR_MDI_X;
254239aa55bSDavid Thomson 		break;
255239aa55bSDavid Thomson 	case ETH_TP_MDI_AUTO:
256239aa55bSDavid Thomson 	case ETH_TP_MDI_INVALID:
257239aa55bSDavid Thomson 	default:
258239aa55bSDavid Thomson 		val |= MII_M1011_PHY_SCR_AUTO_CROSS;
259239aa55bSDavid Thomson 		break;
260239aa55bSDavid Thomson 	}
261239aa55bSDavid Thomson 
262239aa55bSDavid Thomson 	if (val != reg) {
263239aa55bSDavid Thomson 		/* Set the new polarity value in the register */
264239aa55bSDavid Thomson 		err = phy_write(phydev, MII_M1011_PHY_SCR, val);
265239aa55bSDavid Thomson 		if (err)
266239aa55bSDavid Thomson 			return err;
267239aa55bSDavid Thomson 	}
268239aa55bSDavid Thomson 
269d6ab9336SFlorian Fainelli 	return val != reg;
270239aa55bSDavid Thomson }
271239aa55bSDavid Thomson 
27200db8189SAndy Fleming static int marvell_config_aneg(struct phy_device *phydev)
27300db8189SAndy Fleming {
274d6ab9336SFlorian Fainelli 	int changed = 0;
27500db8189SAndy Fleming 	int err;
27600db8189SAndy Fleming 
2774e26c5c3SRaju Lakkaraju 	err = marvell_set_polarity(phydev, phydev->mdix_ctrl);
27876884679SAndy Fleming 	if (err < 0)
27976884679SAndy Fleming 		return err;
28076884679SAndy Fleming 
281d6ab9336SFlorian Fainelli 	changed = err;
282d6ab9336SFlorian Fainelli 
28376884679SAndy Fleming 	err = phy_write(phydev, MII_M1111_PHY_LED_CONTROL,
28476884679SAndy Fleming 			MII_M1111_PHY_LED_DIRECT);
28576884679SAndy Fleming 	if (err < 0)
28676884679SAndy Fleming 		return err;
28700db8189SAndy Fleming 
28800db8189SAndy Fleming 	err = genphy_config_aneg(phydev);
2898ff44985SAnton Vorontsov 	if (err < 0)
29000db8189SAndy Fleming 		return err;
2918ff44985SAnton Vorontsov 
292d6ab9336SFlorian Fainelli 	if (phydev->autoneg != AUTONEG_ENABLE || changed) {
2930c3439bcSAndrew Lunn 		/* A write to speed/duplex bits (that is performed by
2948ff44985SAnton Vorontsov 		 * genphy_config_aneg() call above) must be followed by
2958ff44985SAnton Vorontsov 		 * a software reset. Otherwise, the write has no effect.
2968ff44985SAnton Vorontsov 		 */
29734386344SAndrew Lunn 		err = genphy_soft_reset(phydev);
2988ff44985SAnton Vorontsov 		if (err < 0)
2998ff44985SAnton Vorontsov 			return err;
3008ff44985SAnton Vorontsov 	}
3018ff44985SAnton Vorontsov 
3028ff44985SAnton Vorontsov 	return 0;
30300db8189SAndy Fleming }
30400db8189SAndy Fleming 
305f2899788SAndrew Lunn static int m88e1101_config_aneg(struct phy_device *phydev)
306f2899788SAndrew Lunn {
307f2899788SAndrew Lunn 	int err;
308f2899788SAndrew Lunn 
309f2899788SAndrew Lunn 	/* This Marvell PHY has an errata which requires
310f2899788SAndrew Lunn 	 * that certain registers get written in order
311f2899788SAndrew Lunn 	 * to restart autonegotiation
312f2899788SAndrew Lunn 	 */
31334386344SAndrew Lunn 	err = genphy_soft_reset(phydev);
314f2899788SAndrew Lunn 	if (err < 0)
315f2899788SAndrew Lunn 		return err;
316f2899788SAndrew Lunn 
317f2899788SAndrew Lunn 	err = phy_write(phydev, 0x1d, 0x1f);
318f2899788SAndrew Lunn 	if (err < 0)
319f2899788SAndrew Lunn 		return err;
320f2899788SAndrew Lunn 
321f2899788SAndrew Lunn 	err = phy_write(phydev, 0x1e, 0x200c);
322f2899788SAndrew Lunn 	if (err < 0)
323f2899788SAndrew Lunn 		return err;
324f2899788SAndrew Lunn 
325f2899788SAndrew Lunn 	err = phy_write(phydev, 0x1d, 0x5);
326f2899788SAndrew Lunn 	if (err < 0)
327f2899788SAndrew Lunn 		return err;
328f2899788SAndrew Lunn 
329f2899788SAndrew Lunn 	err = phy_write(phydev, 0x1e, 0);
330f2899788SAndrew Lunn 	if (err < 0)
331f2899788SAndrew Lunn 		return err;
332f2899788SAndrew Lunn 
333f2899788SAndrew Lunn 	err = phy_write(phydev, 0x1e, 0x100);
334f2899788SAndrew Lunn 	if (err < 0)
335f2899788SAndrew Lunn 		return err;
336f2899788SAndrew Lunn 
337f2899788SAndrew Lunn 	return marvell_config_aneg(phydev);
338f2899788SAndrew Lunn }
339f2899788SAndrew Lunn 
340cf41a51dSDavid Daney #ifdef CONFIG_OF_MDIO
3410c3439bcSAndrew Lunn /* Set and/or override some configuration registers based on the
342cf41a51dSDavid Daney  * marvell,reg-init property stored in the of_node for the phydev.
343cf41a51dSDavid Daney  *
344cf41a51dSDavid Daney  * marvell,reg-init = <reg-page reg mask value>,...;
345cf41a51dSDavid Daney  *
346cf41a51dSDavid Daney  * There may be one or more sets of <reg-page reg mask value>:
347cf41a51dSDavid Daney  *
348cf41a51dSDavid Daney  * reg-page: which register bank to use.
349cf41a51dSDavid Daney  * reg: the register.
350cf41a51dSDavid Daney  * mask: if non-zero, ANDed with existing register value.
351cf41a51dSDavid Daney  * value: ORed with the masked value and written to the regiser.
352cf41a51dSDavid Daney  *
353cf41a51dSDavid Daney  */
354cf41a51dSDavid Daney static int marvell_of_reg_init(struct phy_device *phydev)
355cf41a51dSDavid Daney {
356cf41a51dSDavid Daney 	const __be32 *paddr;
357424ca4c5SRussell King 	int len, i, saved_page, current_page, ret = 0;
358cf41a51dSDavid Daney 
359e5a03bfdSAndrew Lunn 	if (!phydev->mdio.dev.of_node)
360cf41a51dSDavid Daney 		return 0;
361cf41a51dSDavid Daney 
362e5a03bfdSAndrew Lunn 	paddr = of_get_property(phydev->mdio.dev.of_node,
363e5a03bfdSAndrew Lunn 				"marvell,reg-init", &len);
364cf41a51dSDavid Daney 	if (!paddr || len < (4 * sizeof(*paddr)))
365cf41a51dSDavid Daney 		return 0;
366cf41a51dSDavid Daney 
367424ca4c5SRussell King 	saved_page = phy_save_page(phydev);
368cf41a51dSDavid Daney 	if (saved_page < 0)
369424ca4c5SRussell King 		goto err;
370cf41a51dSDavid Daney 	current_page = saved_page;
371cf41a51dSDavid Daney 
372cf41a51dSDavid Daney 	len /= sizeof(*paddr);
373cf41a51dSDavid Daney 	for (i = 0; i < len - 3; i += 4) {
3746427bb2dSAndrew Lunn 		u16 page = be32_to_cpup(paddr + i);
375cf41a51dSDavid Daney 		u16 reg = be32_to_cpup(paddr + i + 1);
376cf41a51dSDavid Daney 		u16 mask = be32_to_cpup(paddr + i + 2);
377cf41a51dSDavid Daney 		u16 val_bits = be32_to_cpup(paddr + i + 3);
378cf41a51dSDavid Daney 		int val;
379cf41a51dSDavid Daney 
3806427bb2dSAndrew Lunn 		if (page != current_page) {
3816427bb2dSAndrew Lunn 			current_page = page;
382424ca4c5SRussell King 			ret = marvell_write_page(phydev, page);
383cf41a51dSDavid Daney 			if (ret < 0)
384cf41a51dSDavid Daney 				goto err;
385cf41a51dSDavid Daney 		}
386cf41a51dSDavid Daney 
387cf41a51dSDavid Daney 		val = 0;
388cf41a51dSDavid Daney 		if (mask) {
389424ca4c5SRussell King 			val = __phy_read(phydev, reg);
390cf41a51dSDavid Daney 			if (val < 0) {
391cf41a51dSDavid Daney 				ret = val;
392cf41a51dSDavid Daney 				goto err;
393cf41a51dSDavid Daney 			}
394cf41a51dSDavid Daney 			val &= mask;
395cf41a51dSDavid Daney 		}
396cf41a51dSDavid Daney 		val |= val_bits;
397cf41a51dSDavid Daney 
398424ca4c5SRussell King 		ret = __phy_write(phydev, reg, val);
399cf41a51dSDavid Daney 		if (ret < 0)
400cf41a51dSDavid Daney 			goto err;
401cf41a51dSDavid Daney 	}
402cf41a51dSDavid Daney err:
403424ca4c5SRussell King 	return phy_restore_page(phydev, saved_page, ret);
404cf41a51dSDavid Daney }
405cf41a51dSDavid Daney #else
406cf41a51dSDavid Daney static int marvell_of_reg_init(struct phy_device *phydev)
407cf41a51dSDavid Daney {
408cf41a51dSDavid Daney 	return 0;
409cf41a51dSDavid Daney }
410cf41a51dSDavid Daney #endif /* CONFIG_OF_MDIO */
411cf41a51dSDavid Daney 
412864dc729SAndrew Lunn static int m88e1121_config_aneg_rgmii_delays(struct phy_device *phydev)
413140bc929SSergei Poselenov {
414424ca4c5SRussell King 	int mscr;
415c477d044SCyril Chemparathy 
416c477d044SCyril Chemparathy 	if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)
417424ca4c5SRussell King 		mscr = MII_88E1121_PHY_MSCR_RX_DELAY |
418424ca4c5SRussell King 		       MII_88E1121_PHY_MSCR_TX_DELAY;
419c477d044SCyril Chemparathy 	else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID)
420424ca4c5SRussell King 		mscr = MII_88E1121_PHY_MSCR_RX_DELAY;
421c477d044SCyril Chemparathy 	else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)
422424ca4c5SRussell King 		mscr = MII_88E1121_PHY_MSCR_TX_DELAY;
423424ca4c5SRussell King 	else
424424ca4c5SRussell King 		mscr = 0;
425c477d044SCyril Chemparathy 
426424ca4c5SRussell King 	return phy_modify_paged(phydev, MII_MARVELL_MSCR_PAGE,
427424ca4c5SRussell King 				MII_88E1121_PHY_MSCR_REG,
428424ca4c5SRussell King 				MII_88E1121_PHY_MSCR_DELAY_MASK, mscr);
429be8c6480SArnaud Patard }
430c477d044SCyril Chemparathy 
431864dc729SAndrew Lunn static int m88e1121_config_aneg(struct phy_device *phydev)
432864dc729SAndrew Lunn {
433d6ab9336SFlorian Fainelli 	int changed = 0;
434864dc729SAndrew Lunn 	int err = 0;
435864dc729SAndrew Lunn 
436864dc729SAndrew Lunn 	if (phy_interface_is_rgmii(phydev)) {
437864dc729SAndrew Lunn 		err = m88e1121_config_aneg_rgmii_delays(phydev);
438fea23fb5SRussell King 		if (err < 0)
439864dc729SAndrew Lunn 			return err;
440864dc729SAndrew Lunn 	}
441140bc929SSergei Poselenov 
442fecd5e91SAndrew Lunn 	err = marvell_set_polarity(phydev, phydev->mdix_ctrl);
443140bc929SSergei Poselenov 	if (err < 0)
444140bc929SSergei Poselenov 		return err;
445140bc929SSergei Poselenov 
446d6ab9336SFlorian Fainelli 	changed = err;
447d6ab9336SFlorian Fainelli 
448d6ab9336SFlorian Fainelli 	err = genphy_config_aneg(phydev);
449d6ab9336SFlorian Fainelli 	if (err < 0)
450d6ab9336SFlorian Fainelli 		return err;
451d6ab9336SFlorian Fainelli 
4524b1bd697SDavid S. Miller 	if (phydev->autoneg != AUTONEG_ENABLE || changed) {
453d6ab9336SFlorian Fainelli 		/* A software reset is used to ensure a "commit" of the
454d6ab9336SFlorian Fainelli 		 * changes is done.
455d6ab9336SFlorian Fainelli 		 */
456d6ab9336SFlorian Fainelli 		err = genphy_soft_reset(phydev);
457d6ab9336SFlorian Fainelli 		if (err < 0)
458d6ab9336SFlorian Fainelli 			return err;
459d6ab9336SFlorian Fainelli 	}
460d6ab9336SFlorian Fainelli 
461d6ab9336SFlorian Fainelli 	return 0;
462140bc929SSergei Poselenov }
463140bc929SSergei Poselenov 
464337ac9d5SCyril Chemparathy static int m88e1318_config_aneg(struct phy_device *phydev)
4653ff1c259SCyril Chemparathy {
466424ca4c5SRussell King 	int err;
4673ff1c259SCyril Chemparathy 
468424ca4c5SRussell King 	err = phy_modify_paged(phydev, MII_MARVELL_MSCR_PAGE,
469424ca4c5SRussell King 			       MII_88E1318S_PHY_MSCR1_REG,
470424ca4c5SRussell King 			       0, MII_88E1318S_PHY_MSCR1_PAD_ODD);
4713ff1c259SCyril Chemparathy 	if (err < 0)
4723ff1c259SCyril Chemparathy 		return err;
4733ff1c259SCyril Chemparathy 
4743ff1c259SCyril Chemparathy 	return m88e1121_config_aneg(phydev);
4753ff1c259SCyril Chemparathy }
4763ff1c259SCyril Chemparathy 
47778301ebeSCharles-Antoine Couret /**
4783c1bcc86SAndrew Lunn  * linkmode_adv_to_fiber_adv_t
4793c1bcc86SAndrew Lunn  * @advertise: the linkmode advertisement settings
48078301ebeSCharles-Antoine Couret  *
4813c1bcc86SAndrew Lunn  * A small helper function that translates linkmode advertisement
4823c1bcc86SAndrew Lunn  * settings to phy autonegotiation advertisements for the MII_ADV
4833c1bcc86SAndrew Lunn  * register for fiber link.
48478301ebeSCharles-Antoine Couret  */
4853c1bcc86SAndrew Lunn static inline u32 linkmode_adv_to_fiber_adv_t(unsigned long *advertise)
48678301ebeSCharles-Antoine Couret {
48778301ebeSCharles-Antoine Couret 	u32 result = 0;
48878301ebeSCharles-Antoine Couret 
4893c1bcc86SAndrew Lunn 	if (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT, advertise))
49020ecf424SRussell King 		result |= ADVERTISE_1000XHALF;
4913c1bcc86SAndrew Lunn 	if (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, advertise))
49220ecf424SRussell King 		result |= ADVERTISE_1000XFULL;
49378301ebeSCharles-Antoine Couret 
4943c1bcc86SAndrew Lunn 	if (linkmode_test_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, advertise) &&
4953c1bcc86SAndrew Lunn 	    linkmode_test_bit(ETHTOOL_LINK_MODE_Pause_BIT, advertise))
49620ecf424SRussell King 		result |= ADVERTISE_1000XPSE_ASYM;
4973c1bcc86SAndrew Lunn 	else if (linkmode_test_bit(ETHTOOL_LINK_MODE_Pause_BIT, advertise))
49820ecf424SRussell King 		result |= ADVERTISE_1000XPAUSE;
49978301ebeSCharles-Antoine Couret 
50078301ebeSCharles-Antoine Couret 	return result;
50178301ebeSCharles-Antoine Couret }
50278301ebeSCharles-Antoine Couret 
50378301ebeSCharles-Antoine Couret /**
50478301ebeSCharles-Antoine Couret  * marvell_config_aneg_fiber - restart auto-negotiation or write BMCR
50578301ebeSCharles-Antoine Couret  * @phydev: target phy_device struct
50678301ebeSCharles-Antoine Couret  *
50778301ebeSCharles-Antoine Couret  * Description: If auto-negotiation is enabled, we configure the
50878301ebeSCharles-Antoine Couret  *   advertising, and then restart auto-negotiation.  If it is not
50978301ebeSCharles-Antoine Couret  *   enabled, then we write the BMCR. Adapted for fiber link in
51078301ebeSCharles-Antoine Couret  *   some Marvell's devices.
51178301ebeSCharles-Antoine Couret  */
51278301ebeSCharles-Antoine Couret static int marvell_config_aneg_fiber(struct phy_device *phydev)
51378301ebeSCharles-Antoine Couret {
51478301ebeSCharles-Antoine Couret 	int changed = 0;
51578301ebeSCharles-Antoine Couret 	int err;
5169f4bae70SRussell King 	u16 adv;
51778301ebeSCharles-Antoine Couret 
51878301ebeSCharles-Antoine Couret 	if (phydev->autoneg != AUTONEG_ENABLE)
51978301ebeSCharles-Antoine Couret 		return genphy_setup_forced(phydev);
52078301ebeSCharles-Antoine Couret 
52178301ebeSCharles-Antoine Couret 	/* Only allow advertising what this PHY supports */
5223c1bcc86SAndrew Lunn 	linkmode_and(phydev->advertising, phydev->advertising,
5233c1bcc86SAndrew Lunn 		     phydev->supported);
52478301ebeSCharles-Antoine Couret 
5259f4bae70SRussell King 	adv = linkmode_adv_to_fiber_adv_t(phydev->advertising);
5269f4bae70SRussell King 
52778301ebeSCharles-Antoine Couret 	/* Setup fiber advertisement */
5289f4bae70SRussell King 	err = phy_modify_changed(phydev, MII_ADVERTISE,
5299f4bae70SRussell King 				 ADVERTISE_1000XHALF | ADVERTISE_1000XFULL |
5309f4bae70SRussell King 				 ADVERTISE_1000XPAUSE | ADVERTISE_1000XPSE_ASYM,
5319f4bae70SRussell King 				 adv);
53278301ebeSCharles-Antoine Couret 	if (err < 0)
53378301ebeSCharles-Antoine Couret 		return err;
5349f4bae70SRussell King 	if (err > 0)
53578301ebeSCharles-Antoine Couret 		changed = 1;
53678301ebeSCharles-Antoine Couret 
537b5abac2dSRussell King 	return genphy_check_and_restart_aneg(phydev, changed);
53878301ebeSCharles-Antoine Couret }
53978301ebeSCharles-Antoine Couret 
54010e24caaSMichal Simek static int m88e1510_config_aneg(struct phy_device *phydev)
54110e24caaSMichal Simek {
54210e24caaSMichal Simek 	int err;
54310e24caaSMichal Simek 
54452295666SAndrew Lunn 	err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);
54578301ebeSCharles-Antoine Couret 	if (err < 0)
54678301ebeSCharles-Antoine Couret 		goto error;
54778301ebeSCharles-Antoine Couret 
54878301ebeSCharles-Antoine Couret 	/* Configure the copper link first */
54910e24caaSMichal Simek 	err = m88e1318_config_aneg(phydev);
55010e24caaSMichal Simek 	if (err < 0)
55178301ebeSCharles-Antoine Couret 		goto error;
55210e24caaSMichal Simek 
553de9c4e06SRussell King 	/* Do not touch the fiber page if we're in copper->sgmii mode */
554de9c4e06SRussell King 	if (phydev->interface == PHY_INTERFACE_MODE_SGMII)
555de9c4e06SRussell King 		return 0;
556de9c4e06SRussell King 
55778301ebeSCharles-Antoine Couret 	/* Then the fiber link */
55852295666SAndrew Lunn 	err = marvell_set_page(phydev, MII_MARVELL_FIBER_PAGE);
55978301ebeSCharles-Antoine Couret 	if (err < 0)
56078301ebeSCharles-Antoine Couret 		goto error;
56178301ebeSCharles-Antoine Couret 
56278301ebeSCharles-Antoine Couret 	err = marvell_config_aneg_fiber(phydev);
56378301ebeSCharles-Antoine Couret 	if (err < 0)
56478301ebeSCharles-Antoine Couret 		goto error;
56578301ebeSCharles-Antoine Couret 
56652295666SAndrew Lunn 	return marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);
56778301ebeSCharles-Antoine Couret 
56878301ebeSCharles-Antoine Couret error:
56952295666SAndrew Lunn 	marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);
57078301ebeSCharles-Antoine Couret 	return err;
57179be1a1cSClemens Gruber }
57279be1a1cSClemens Gruber 
57307777246SWang Dongsheng static void marvell_config_led(struct phy_device *phydev)
57407777246SWang Dongsheng {
57507777246SWang Dongsheng 	u16 def_config;
57607777246SWang Dongsheng 	int err;
57707777246SWang Dongsheng 
57807777246SWang Dongsheng 	switch (MARVELL_PHY_FAMILY_ID(phydev->phy_id)) {
57907777246SWang Dongsheng 	/* Default PHY LED config: LED[0] .. Link, LED[1] .. Activity */
58007777246SWang Dongsheng 	case MARVELL_PHY_FAMILY_ID(MARVELL_PHY_ID_88E1121R):
58107777246SWang Dongsheng 	case MARVELL_PHY_FAMILY_ID(MARVELL_PHY_ID_88E1318S):
58207777246SWang Dongsheng 		def_config = MII_88E1121_PHY_LED_DEF;
58307777246SWang Dongsheng 		break;
58407777246SWang Dongsheng 	/* Default PHY LED config:
58507777246SWang Dongsheng 	 * LED[0] .. 1000Mbps Link
58607777246SWang Dongsheng 	 * LED[1] .. 100Mbps Link
58707777246SWang Dongsheng 	 * LED[2] .. Blink, Activity
58807777246SWang Dongsheng 	 */
58907777246SWang Dongsheng 	case MARVELL_PHY_FAMILY_ID(MARVELL_PHY_ID_88E1510):
590a93f7fe1SJian Shen 		if (phydev->dev_flags & MARVELL_PHY_LED0_LINK_LED1_ACTIVE)
591a93f7fe1SJian Shen 			def_config = MII_88E1510_PHY_LED0_LINK_LED1_ACTIVE;
592a93f7fe1SJian Shen 		else
59307777246SWang Dongsheng 			def_config = MII_88E1510_PHY_LED_DEF;
59407777246SWang Dongsheng 		break;
59507777246SWang Dongsheng 	default:
59607777246SWang Dongsheng 		return;
59707777246SWang Dongsheng 	}
59807777246SWang Dongsheng 
59907777246SWang Dongsheng 	err = phy_write_paged(phydev, MII_MARVELL_LED_PAGE, MII_PHY_LED_CTRL,
60007777246SWang Dongsheng 			      def_config);
60107777246SWang Dongsheng 	if (err < 0)
602ab2a605fSAndrew Lunn 		phydev_warn(phydev, "Fail to config marvell phy LED.\n");
60307777246SWang Dongsheng }
60407777246SWang Dongsheng 
60579be1a1cSClemens Gruber static int marvell_config_init(struct phy_device *phydev)
60679be1a1cSClemens Gruber {
60707777246SWang Dongsheng 	/* Set defalut LED */
60807777246SWang Dongsheng 	marvell_config_led(phydev);
60907777246SWang Dongsheng 
61079be1a1cSClemens Gruber 	/* Set registers from marvell,reg-init DT property */
61110e24caaSMichal Simek 	return marvell_of_reg_init(phydev);
61210e24caaSMichal Simek }
61310e24caaSMichal Simek 
6146b358aedSSebastian Hesselbarth static int m88e3016_config_init(struct phy_device *phydev)
6156b358aedSSebastian Hesselbarth {
616fea23fb5SRussell King 	int ret;
6176b358aedSSebastian Hesselbarth 
6186b358aedSSebastian Hesselbarth 	/* Enable Scrambler and Auto-Crossover */
619fea23fb5SRussell King 	ret = phy_modify(phydev, MII_88E3016_PHY_SPEC_CTRL,
620f102852fSRussell King 			 MII_88E3016_DISABLE_SCRAMBLER,
621fea23fb5SRussell King 			 MII_88E3016_AUTO_MDIX_CROSSOVER);
622fea23fb5SRussell King 	if (ret < 0)
623fea23fb5SRussell King 		return ret;
6246b358aedSSebastian Hesselbarth 
62579be1a1cSClemens Gruber 	return marvell_config_init(phydev);
6266b358aedSSebastian Hesselbarth }
6276b358aedSSebastian Hesselbarth 
628865b813aSAndrew Lunn static int m88e1111_config_init_hwcfg_mode(struct phy_device *phydev,
629865b813aSAndrew Lunn 					   u16 mode,
630865b813aSAndrew Lunn 					   int fibre_copper_auto)
631865b813aSAndrew Lunn {
632865b813aSAndrew Lunn 	if (fibre_copper_auto)
633fea23fb5SRussell King 		mode |= MII_M1111_HWCFG_FIBER_COPPER_AUTO;
634865b813aSAndrew Lunn 
635fea23fb5SRussell King 	return phy_modify(phydev, MII_M1111_PHY_EXT_SR,
636f102852fSRussell King 			  MII_M1111_HWCFG_MODE_MASK |
637fea23fb5SRussell King 			  MII_M1111_HWCFG_FIBER_COPPER_AUTO |
638f102852fSRussell King 			  MII_M1111_HWCFG_FIBER_COPPER_RES,
639fea23fb5SRussell King 			  mode);
640865b813aSAndrew Lunn }
641865b813aSAndrew Lunn 
64261111598SAndrew Lunn static int m88e1111_config_init_rgmii_delays(struct phy_device *phydev)
643895ee682SKim Phillips {
644fea23fb5SRussell King 	int delay;
645895ee682SKim Phillips 
6469daf5a76SKim Phillips 	if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) {
647fea23fb5SRussell King 		delay = MII_M1111_RGMII_RX_DELAY | MII_M1111_RGMII_TX_DELAY;
6489daf5a76SKim Phillips 	} else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) {
649fea23fb5SRussell King 		delay = MII_M1111_RGMII_RX_DELAY;
6509daf5a76SKim Phillips 	} else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) {
651fea23fb5SRussell King 		delay = MII_M1111_RGMII_TX_DELAY;
652fea23fb5SRussell King 	} else {
653fea23fb5SRussell King 		delay = 0;
6549daf5a76SKim Phillips 	}
655895ee682SKim Phillips 
656fea23fb5SRussell King 	return phy_modify(phydev, MII_M1111_PHY_EXT_CR,
657f102852fSRussell King 			  MII_M1111_RGMII_RX_DELAY | MII_M1111_RGMII_TX_DELAY,
658fea23fb5SRussell King 			  delay);
65961111598SAndrew Lunn }
66061111598SAndrew Lunn 
66161111598SAndrew Lunn static int m88e1111_config_init_rgmii(struct phy_device *phydev)
66261111598SAndrew Lunn {
66361111598SAndrew Lunn 	int temp;
66461111598SAndrew Lunn 	int err;
66561111598SAndrew Lunn 
66661111598SAndrew Lunn 	err = m88e1111_config_init_rgmii_delays(phydev);
667895ee682SKim Phillips 	if (err < 0)
668895ee682SKim Phillips 		return err;
669895ee682SKim Phillips 
670895ee682SKim Phillips 	temp = phy_read(phydev, MII_M1111_PHY_EXT_SR);
671895ee682SKim Phillips 	if (temp < 0)
672895ee682SKim Phillips 		return temp;
673895ee682SKim Phillips 
674895ee682SKim Phillips 	temp &= ~(MII_M1111_HWCFG_MODE_MASK);
675be937f1fSAlexandr Smirnov 
6767239016dSWang Jian 	if (temp & MII_M1111_HWCFG_FIBER_COPPER_RES)
677be937f1fSAlexandr Smirnov 		temp |= MII_M1111_HWCFG_MODE_FIBER_RGMII;
678be937f1fSAlexandr Smirnov 	else
679be937f1fSAlexandr Smirnov 		temp |= MII_M1111_HWCFG_MODE_COPPER_RGMII;
680895ee682SKim Phillips 
681e1dde8dcSAndrew Lunn 	return phy_write(phydev, MII_M1111_PHY_EXT_SR, temp);
682895ee682SKim Phillips }
683895ee682SKim Phillips 
684e1dde8dcSAndrew Lunn static int m88e1111_config_init_sgmii(struct phy_device *phydev)
685e1dde8dcSAndrew Lunn {
686e1dde8dcSAndrew Lunn 	int err;
687e1dde8dcSAndrew Lunn 
688865b813aSAndrew Lunn 	err = m88e1111_config_init_hwcfg_mode(
689865b813aSAndrew Lunn 		phydev,
690865b813aSAndrew Lunn 		MII_M1111_HWCFG_MODE_SGMII_NO_CLK,
691865b813aSAndrew Lunn 		MII_M1111_HWCFG_FIBER_COPPER_AUTO);
6924117b5beSKapil Juneja 	if (err < 0)
6934117b5beSKapil Juneja 		return err;
69407151bc9SMadalin Bucur 
69507151bc9SMadalin Bucur 	/* make sure copper is selected */
69652295666SAndrew Lunn 	return marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);
6974117b5beSKapil Juneja }
6984117b5beSKapil Juneja 
699e1dde8dcSAndrew Lunn static int m88e1111_config_init_rtbi(struct phy_device *phydev)
700e1dde8dcSAndrew Lunn {
70161111598SAndrew Lunn 	int err;
702e1dde8dcSAndrew Lunn 
70361111598SAndrew Lunn 	err = m88e1111_config_init_rgmii_delays(phydev);
704fea23fb5SRussell King 	if (err < 0)
7055f8cbc13SLiu Yu-B13201 		return err;
7065f8cbc13SLiu Yu-B13201 
707865b813aSAndrew Lunn 	err = m88e1111_config_init_hwcfg_mode(
708865b813aSAndrew Lunn 		phydev,
709865b813aSAndrew Lunn 		MII_M1111_HWCFG_MODE_RTBI,
710865b813aSAndrew Lunn 		MII_M1111_HWCFG_FIBER_COPPER_AUTO);
7115f8cbc13SLiu Yu-B13201 	if (err < 0)
7125f8cbc13SLiu Yu-B13201 		return err;
7135f8cbc13SLiu Yu-B13201 
7145f8cbc13SLiu Yu-B13201 	/* soft reset */
71534386344SAndrew Lunn 	err = genphy_soft_reset(phydev);
7165f8cbc13SLiu Yu-B13201 	if (err < 0)
7175f8cbc13SLiu Yu-B13201 		return err;
718e1dde8dcSAndrew Lunn 
719865b813aSAndrew Lunn 	return m88e1111_config_init_hwcfg_mode(
720865b813aSAndrew Lunn 		phydev,
721865b813aSAndrew Lunn 		MII_M1111_HWCFG_MODE_RTBI,
722865b813aSAndrew Lunn 		MII_M1111_HWCFG_FIBER_COPPER_AUTO);
723e1dde8dcSAndrew Lunn }
724e1dde8dcSAndrew Lunn 
725e1dde8dcSAndrew Lunn static int m88e1111_config_init(struct phy_device *phydev)
726e1dde8dcSAndrew Lunn {
727e1dde8dcSAndrew Lunn 	int err;
728e1dde8dcSAndrew Lunn 
729e1dde8dcSAndrew Lunn 	if (phy_interface_is_rgmii(phydev)) {
730e1dde8dcSAndrew Lunn 		err = m88e1111_config_init_rgmii(phydev);
731fea23fb5SRussell King 		if (err < 0)
732e1dde8dcSAndrew Lunn 			return err;
733e1dde8dcSAndrew Lunn 	}
734e1dde8dcSAndrew Lunn 
735e1dde8dcSAndrew Lunn 	if (phydev->interface == PHY_INTERFACE_MODE_SGMII) {
736e1dde8dcSAndrew Lunn 		err = m88e1111_config_init_sgmii(phydev);
737e1dde8dcSAndrew Lunn 		if (err < 0)
738e1dde8dcSAndrew Lunn 			return err;
739e1dde8dcSAndrew Lunn 	}
740e1dde8dcSAndrew Lunn 
741e1dde8dcSAndrew Lunn 	if (phydev->interface == PHY_INTERFACE_MODE_RTBI) {
742e1dde8dcSAndrew Lunn 		err = m88e1111_config_init_rtbi(phydev);
7435f8cbc13SLiu Yu-B13201 		if (err < 0)
7445f8cbc13SLiu Yu-B13201 			return err;
7455f8cbc13SLiu Yu-B13201 	}
7465f8cbc13SLiu Yu-B13201 
747cf41a51dSDavid Daney 	err = marvell_of_reg_init(phydev);
748cf41a51dSDavid Daney 	if (err < 0)
749cf41a51dSDavid Daney 		return err;
7505f8cbc13SLiu Yu-B13201 
75134386344SAndrew Lunn 	return genphy_soft_reset(phydev);
752895ee682SKim Phillips }
753895ee682SKim Phillips 
7545c6bc519SHeiner Kallweit static int m88e1111_get_downshift(struct phy_device *phydev, u8 *data)
7555c6bc519SHeiner Kallweit {
7565c6bc519SHeiner Kallweit 	int val, cnt, enable;
7575c6bc519SHeiner Kallweit 
7585c6bc519SHeiner Kallweit 	val = phy_read(phydev, MII_M1111_PHY_EXT_CR);
7595c6bc519SHeiner Kallweit 	if (val < 0)
7605c6bc519SHeiner Kallweit 		return val;
7615c6bc519SHeiner Kallweit 
7625c6bc519SHeiner Kallweit 	enable = FIELD_GET(MII_M1111_PHY_EXT_CR_DOWNSHIFT_EN, val);
7635c6bc519SHeiner Kallweit 	cnt = FIELD_GET(MII_M1111_PHY_EXT_CR_DOWNSHIFT_MASK, val) + 1;
7645c6bc519SHeiner Kallweit 
7655c6bc519SHeiner Kallweit 	*data = enable ? cnt : DOWNSHIFT_DEV_DISABLE;
7665c6bc519SHeiner Kallweit 
7675c6bc519SHeiner Kallweit 	return 0;
7685c6bc519SHeiner Kallweit }
7695c6bc519SHeiner Kallweit 
7705c6bc519SHeiner Kallweit static int m88e1111_set_downshift(struct phy_device *phydev, u8 cnt)
7715c6bc519SHeiner Kallweit {
7725c6bc519SHeiner Kallweit 	int val;
7735c6bc519SHeiner Kallweit 
7745c6bc519SHeiner Kallweit 	if (cnt > MII_M1111_PHY_EXT_CR_DOWNSHIFT_MAX)
7755c6bc519SHeiner Kallweit 		return -E2BIG;
7765c6bc519SHeiner Kallweit 
7775c6bc519SHeiner Kallweit 	if (!cnt)
7785c6bc519SHeiner Kallweit 		return phy_clear_bits(phydev, MII_M1111_PHY_EXT_CR,
7795c6bc519SHeiner Kallweit 				      MII_M1111_PHY_EXT_CR_DOWNSHIFT_EN);
7805c6bc519SHeiner Kallweit 
7815c6bc519SHeiner Kallweit 	val = MII_M1111_PHY_EXT_CR_DOWNSHIFT_EN;
7825c6bc519SHeiner Kallweit 	val |= FIELD_PREP(MII_M1111_PHY_EXT_CR_DOWNSHIFT_MASK, cnt - 1);
7835c6bc519SHeiner Kallweit 
7845c6bc519SHeiner Kallweit 	return phy_modify(phydev, MII_M1111_PHY_EXT_CR,
7855c6bc519SHeiner Kallweit 			  MII_M1111_PHY_EXT_CR_DOWNSHIFT_EN |
7865c6bc519SHeiner Kallweit 			  MII_M1111_PHY_EXT_CR_DOWNSHIFT_MASK,
7875c6bc519SHeiner Kallweit 			  val);
7885c6bc519SHeiner Kallweit }
7895c6bc519SHeiner Kallweit 
7905c6bc519SHeiner Kallweit static int m88e1111_get_tunable(struct phy_device *phydev,
7915c6bc519SHeiner Kallweit 				struct ethtool_tunable *tuna, void *data)
7925c6bc519SHeiner Kallweit {
7935c6bc519SHeiner Kallweit 	switch (tuna->id) {
7945c6bc519SHeiner Kallweit 	case ETHTOOL_PHY_DOWNSHIFT:
7955c6bc519SHeiner Kallweit 		return m88e1111_get_downshift(phydev, data);
7965c6bc519SHeiner Kallweit 	default:
7975c6bc519SHeiner Kallweit 		return -EOPNOTSUPP;
7985c6bc519SHeiner Kallweit 	}
7995c6bc519SHeiner Kallweit }
8005c6bc519SHeiner Kallweit 
8015c6bc519SHeiner Kallweit static int m88e1111_set_tunable(struct phy_device *phydev,
8025c6bc519SHeiner Kallweit 				struct ethtool_tunable *tuna, const void *data)
8035c6bc519SHeiner Kallweit {
8045c6bc519SHeiner Kallweit 	switch (tuna->id) {
8055c6bc519SHeiner Kallweit 	case ETHTOOL_PHY_DOWNSHIFT:
8065c6bc519SHeiner Kallweit 		return m88e1111_set_downshift(phydev, *(const u8 *)data);
8075c6bc519SHeiner Kallweit 	default:
8085c6bc519SHeiner Kallweit 		return -EOPNOTSUPP;
8095c6bc519SHeiner Kallweit 	}
8105c6bc519SHeiner Kallweit }
8115c6bc519SHeiner Kallweit 
812911af5e1SHeiner Kallweit static int m88e1011_get_downshift(struct phy_device *phydev, u8 *data)
813a3bdfce7SHeiner Kallweit {
814a3bdfce7SHeiner Kallweit 	int val, cnt, enable;
815a3bdfce7SHeiner Kallweit 
816a3bdfce7SHeiner Kallweit 	val = phy_read(phydev, MII_M1011_PHY_SCR);
817a3bdfce7SHeiner Kallweit 	if (val < 0)
818a3bdfce7SHeiner Kallweit 		return val;
819a3bdfce7SHeiner Kallweit 
820a3bdfce7SHeiner Kallweit 	enable = FIELD_GET(MII_M1011_PHY_SCR_DOWNSHIFT_EN, val);
821f8d975beSHeiner Kallweit 	cnt = FIELD_GET(MII_M1011_PHY_SCR_DOWNSHIFT_MASK, val) + 1;
822a3bdfce7SHeiner Kallweit 
823a3bdfce7SHeiner Kallweit 	*data = enable ? cnt : DOWNSHIFT_DEV_DISABLE;
824a3bdfce7SHeiner Kallweit 
825a3bdfce7SHeiner Kallweit 	return 0;
826a3bdfce7SHeiner Kallweit }
827a3bdfce7SHeiner Kallweit 
828911af5e1SHeiner Kallweit static int m88e1011_set_downshift(struct phy_device *phydev, u8 cnt)
829a3bdfce7SHeiner Kallweit {
830a3bdfce7SHeiner Kallweit 	int val;
831a3bdfce7SHeiner Kallweit 
832a3bdfce7SHeiner Kallweit 	if (cnt > MII_M1011_PHY_SCR_DOWNSHIFT_MAX)
833a3bdfce7SHeiner Kallweit 		return -E2BIG;
834a3bdfce7SHeiner Kallweit 
835a3bdfce7SHeiner Kallweit 	if (!cnt)
836a3bdfce7SHeiner Kallweit 		return phy_clear_bits(phydev, MII_M1011_PHY_SCR,
837a3bdfce7SHeiner Kallweit 				      MII_M1011_PHY_SCR_DOWNSHIFT_EN);
838a3bdfce7SHeiner Kallweit 
839a3bdfce7SHeiner Kallweit 	val = MII_M1011_PHY_SCR_DOWNSHIFT_EN;
840f8d975beSHeiner Kallweit 	val |= FIELD_PREP(MII_M1011_PHY_SCR_DOWNSHIFT_MASK, cnt - 1);
841a3bdfce7SHeiner Kallweit 
842a3bdfce7SHeiner Kallweit 	return phy_modify(phydev, MII_M1011_PHY_SCR,
843a3bdfce7SHeiner Kallweit 			  MII_M1011_PHY_SCR_DOWNSHIFT_EN |
844f8d975beSHeiner Kallweit 			  MII_M1011_PHY_SCR_DOWNSHIFT_MASK,
845a3bdfce7SHeiner Kallweit 			  val);
846a3bdfce7SHeiner Kallweit }
847a3bdfce7SHeiner Kallweit 
848911af5e1SHeiner Kallweit static int m88e1011_get_tunable(struct phy_device *phydev,
849a3bdfce7SHeiner Kallweit 				struct ethtool_tunable *tuna, void *data)
850a3bdfce7SHeiner Kallweit {
851a3bdfce7SHeiner Kallweit 	switch (tuna->id) {
852a3bdfce7SHeiner Kallweit 	case ETHTOOL_PHY_DOWNSHIFT:
853911af5e1SHeiner Kallweit 		return m88e1011_get_downshift(phydev, data);
854a3bdfce7SHeiner Kallweit 	default:
855a3bdfce7SHeiner Kallweit 		return -EOPNOTSUPP;
856a3bdfce7SHeiner Kallweit 	}
857a3bdfce7SHeiner Kallweit }
858a3bdfce7SHeiner Kallweit 
859911af5e1SHeiner Kallweit static int m88e1011_set_tunable(struct phy_device *phydev,
860a3bdfce7SHeiner Kallweit 				struct ethtool_tunable *tuna, const void *data)
861a3bdfce7SHeiner Kallweit {
862a3bdfce7SHeiner Kallweit 	switch (tuna->id) {
863a3bdfce7SHeiner Kallweit 	case ETHTOOL_PHY_DOWNSHIFT:
864911af5e1SHeiner Kallweit 		return m88e1011_set_downshift(phydev, *(const u8 *)data);
865a3bdfce7SHeiner Kallweit 	default:
866a3bdfce7SHeiner Kallweit 		return -EOPNOTSUPP;
867a3bdfce7SHeiner Kallweit 	}
868a3bdfce7SHeiner Kallweit }
869a3bdfce7SHeiner Kallweit 
870911af5e1SHeiner Kallweit static void m88e1011_link_change_notify(struct phy_device *phydev)
871a3bdfce7SHeiner Kallweit {
872a3bdfce7SHeiner Kallweit 	int status;
873a3bdfce7SHeiner Kallweit 
874a3bdfce7SHeiner Kallweit 	if (phydev->state != PHY_RUNNING)
875a3bdfce7SHeiner Kallweit 		return;
876a3bdfce7SHeiner Kallweit 
877a3bdfce7SHeiner Kallweit 	/* we may be on fiber page currently */
878a3bdfce7SHeiner Kallweit 	status = phy_read_paged(phydev, MII_MARVELL_COPPER_PAGE,
879a3bdfce7SHeiner Kallweit 				MII_M1011_PHY_SSR);
880a3bdfce7SHeiner Kallweit 
881a3bdfce7SHeiner Kallweit 	if (status > 0 && status & MII_M1011_PHY_SSR_DOWNSHIFT)
882a3bdfce7SHeiner Kallweit 		phydev_warn(phydev, "Downshift occurred! Cabling may be defective.\n");
883a3bdfce7SHeiner Kallweit }
884a3bdfce7SHeiner Kallweit 
885e2d861ccSHeiner Kallweit static int m88e1116r_config_init(struct phy_device *phydev)
886e2d861ccSHeiner Kallweit {
887e2d861ccSHeiner Kallweit 	int err;
888e2d861ccSHeiner Kallweit 
889e2d861ccSHeiner Kallweit 	err = genphy_soft_reset(phydev);
890e2d861ccSHeiner Kallweit 	if (err < 0)
891e2d861ccSHeiner Kallweit 		return err;
892e2d861ccSHeiner Kallweit 
893e2d861ccSHeiner Kallweit 	msleep(500);
894e2d861ccSHeiner Kallweit 
895e2d861ccSHeiner Kallweit 	err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);
896e2d861ccSHeiner Kallweit 	if (err < 0)
897e2d861ccSHeiner Kallweit 		return err;
898e2d861ccSHeiner Kallweit 
899e2d861ccSHeiner Kallweit 	err = marvell_set_polarity(phydev, phydev->mdix_ctrl);
900e2d861ccSHeiner Kallweit 	if (err < 0)
901e2d861ccSHeiner Kallweit 		return err;
902e2d861ccSHeiner Kallweit 
903911af5e1SHeiner Kallweit 	err = m88e1011_set_downshift(phydev, 8);
904e2d861ccSHeiner Kallweit 	if (err < 0)
905e2d861ccSHeiner Kallweit 		return err;
906e2d861ccSHeiner Kallweit 
907e2d861ccSHeiner Kallweit 	if (phy_interface_is_rgmii(phydev)) {
908e2d861ccSHeiner Kallweit 		err = m88e1121_config_aneg_rgmii_delays(phydev);
909e2d861ccSHeiner Kallweit 		if (err < 0)
910e2d861ccSHeiner Kallweit 			return err;
911e2d861ccSHeiner Kallweit 	}
912e2d861ccSHeiner Kallweit 
913e2d861ccSHeiner Kallweit 	err = genphy_soft_reset(phydev);
914e2d861ccSHeiner Kallweit 	if (err < 0)
915e2d861ccSHeiner Kallweit 		return err;
916e2d861ccSHeiner Kallweit 
917e2d861ccSHeiner Kallweit 	return marvell_config_init(phydev);
918e2d861ccSHeiner Kallweit }
919e2d861ccSHeiner Kallweit 
920dd9a122aSEsben Haabendal static int m88e1318_config_init(struct phy_device *phydev)
921dd9a122aSEsben Haabendal {
922dd9a122aSEsben Haabendal 	if (phy_interrupt_is_valid(phydev)) {
923dd9a122aSEsben Haabendal 		int err = phy_modify_paged(
924dd9a122aSEsben Haabendal 			phydev, MII_MARVELL_LED_PAGE,
925dd9a122aSEsben Haabendal 			MII_88E1318S_PHY_LED_TCR,
926dd9a122aSEsben Haabendal 			MII_88E1318S_PHY_LED_TCR_FORCE_INT,
927dd9a122aSEsben Haabendal 			MII_88E1318S_PHY_LED_TCR_INTn_ENABLE |
928dd9a122aSEsben Haabendal 			MII_88E1318S_PHY_LED_TCR_INT_ACTIVE_LOW);
929dd9a122aSEsben Haabendal 		if (err < 0)
930dd9a122aSEsben Haabendal 			return err;
931dd9a122aSEsben Haabendal 	}
932dd9a122aSEsben Haabendal 
93307777246SWang Dongsheng 	return marvell_config_init(phydev);
934dd9a122aSEsben Haabendal }
935dd9a122aSEsben Haabendal 
936407353ecSClemens Gruber static int m88e1510_config_init(struct phy_device *phydev)
937407353ecSClemens Gruber {
938407353ecSClemens Gruber 	int err;
939407353ecSClemens Gruber 
940407353ecSClemens Gruber 	/* SGMII-to-Copper mode initialization */
941407353ecSClemens Gruber 	if (phydev->interface == PHY_INTERFACE_MODE_SGMII) {
942407353ecSClemens Gruber 		/* Select page 18 */
9436427bb2dSAndrew Lunn 		err = marvell_set_page(phydev, 18);
944407353ecSClemens Gruber 		if (err < 0)
945407353ecSClemens Gruber 			return err;
946407353ecSClemens Gruber 
947407353ecSClemens Gruber 		/* In reg 20, write MODE[2:0] = 0x1 (SGMII to Copper) */
948fea23fb5SRussell King 		err = phy_modify(phydev, MII_88E1510_GEN_CTRL_REG_1,
949f102852fSRussell King 				 MII_88E1510_GEN_CTRL_REG_1_MODE_MASK,
950fea23fb5SRussell King 				 MII_88E1510_GEN_CTRL_REG_1_MODE_SGMII);
951407353ecSClemens Gruber 		if (err < 0)
952407353ecSClemens Gruber 			return err;
953407353ecSClemens Gruber 
954407353ecSClemens Gruber 		/* PHY reset is necessary after changing MODE[2:0] */
955fea23fb5SRussell King 		err = phy_modify(phydev, MII_88E1510_GEN_CTRL_REG_1, 0,
956fea23fb5SRussell King 				 MII_88E1510_GEN_CTRL_REG_1_RESET);
957407353ecSClemens Gruber 		if (err < 0)
958407353ecSClemens Gruber 			return err;
959407353ecSClemens Gruber 
960407353ecSClemens Gruber 		/* Reset page selection */
96152295666SAndrew Lunn 		err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);
962407353ecSClemens Gruber 		if (err < 0)
963407353ecSClemens Gruber 			return err;
964407353ecSClemens Gruber 	}
965407353ecSClemens Gruber 
966dd9a122aSEsben Haabendal 	return m88e1318_config_init(phydev);
967407353ecSClemens Gruber }
968407353ecSClemens Gruber 
969605f196eSRon Madrid static int m88e1118_config_aneg(struct phy_device *phydev)
970605f196eSRon Madrid {
971605f196eSRon Madrid 	int err;
972605f196eSRon Madrid 
97334386344SAndrew Lunn 	err = genphy_soft_reset(phydev);
974605f196eSRon Madrid 	if (err < 0)
975605f196eSRon Madrid 		return err;
976605f196eSRon Madrid 
977fecd5e91SAndrew Lunn 	err = marvell_set_polarity(phydev, phydev->mdix_ctrl);
978605f196eSRon Madrid 	if (err < 0)
979605f196eSRon Madrid 		return err;
980605f196eSRon Madrid 
981605f196eSRon Madrid 	err = genphy_config_aneg(phydev);
982605f196eSRon Madrid 	return 0;
983605f196eSRon Madrid }
984605f196eSRon Madrid 
985605f196eSRon Madrid static int m88e1118_config_init(struct phy_device *phydev)
986605f196eSRon Madrid {
987605f196eSRon Madrid 	int err;
988605f196eSRon Madrid 
989605f196eSRon Madrid 	/* Change address */
99052295666SAndrew Lunn 	err = marvell_set_page(phydev, MII_MARVELL_MSCR_PAGE);
991605f196eSRon Madrid 	if (err < 0)
992605f196eSRon Madrid 		return err;
993605f196eSRon Madrid 
994605f196eSRon Madrid 	/* Enable 1000 Mbit */
995605f196eSRon Madrid 	err = phy_write(phydev, 0x15, 0x1070);
996605f196eSRon Madrid 	if (err < 0)
997605f196eSRon Madrid 		return err;
998605f196eSRon Madrid 
999605f196eSRon Madrid 	/* Change address */
100052295666SAndrew Lunn 	err = marvell_set_page(phydev, MII_MARVELL_LED_PAGE);
1001605f196eSRon Madrid 	if (err < 0)
1002605f196eSRon Madrid 		return err;
1003605f196eSRon Madrid 
1004605f196eSRon Madrid 	/* Adjust LED Control */
10052f495c39SBenjamin Herrenschmidt 	if (phydev->dev_flags & MARVELL_PHY_M1118_DNS323_LEDS)
10062f495c39SBenjamin Herrenschmidt 		err = phy_write(phydev, 0x10, 0x1100);
10072f495c39SBenjamin Herrenschmidt 	else
1008605f196eSRon Madrid 		err = phy_write(phydev, 0x10, 0x021e);
1009605f196eSRon Madrid 	if (err < 0)
1010605f196eSRon Madrid 		return err;
1011605f196eSRon Madrid 
1012cf41a51dSDavid Daney 	err = marvell_of_reg_init(phydev);
1013cf41a51dSDavid Daney 	if (err < 0)
1014cf41a51dSDavid Daney 		return err;
1015cf41a51dSDavid Daney 
1016605f196eSRon Madrid 	/* Reset address */
101752295666SAndrew Lunn 	err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);
1018605f196eSRon Madrid 	if (err < 0)
1019605f196eSRon Madrid 		return err;
1020605f196eSRon Madrid 
102134386344SAndrew Lunn 	return genphy_soft_reset(phydev);
1022605f196eSRon Madrid }
1023605f196eSRon Madrid 
102490600732SDavid Daney static int m88e1149_config_init(struct phy_device *phydev)
102590600732SDavid Daney {
102690600732SDavid Daney 	int err;
102790600732SDavid Daney 
102890600732SDavid Daney 	/* Change address */
102952295666SAndrew Lunn 	err = marvell_set_page(phydev, MII_MARVELL_MSCR_PAGE);
103090600732SDavid Daney 	if (err < 0)
103190600732SDavid Daney 		return err;
103290600732SDavid Daney 
103390600732SDavid Daney 	/* Enable 1000 Mbit */
103490600732SDavid Daney 	err = phy_write(phydev, 0x15, 0x1048);
103590600732SDavid Daney 	if (err < 0)
103690600732SDavid Daney 		return err;
103790600732SDavid Daney 
1038cf41a51dSDavid Daney 	err = marvell_of_reg_init(phydev);
1039cf41a51dSDavid Daney 	if (err < 0)
1040cf41a51dSDavid Daney 		return err;
1041cf41a51dSDavid Daney 
104290600732SDavid Daney 	/* Reset address */
104352295666SAndrew Lunn 	err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);
104490600732SDavid Daney 	if (err < 0)
104590600732SDavid Daney 		return err;
104690600732SDavid Daney 
104734386344SAndrew Lunn 	return genphy_soft_reset(phydev);
104890600732SDavid Daney }
104990600732SDavid Daney 
1050e1dde8dcSAndrew Lunn static int m88e1145_config_init_rgmii(struct phy_device *phydev)
105176884679SAndy Fleming {
105276884679SAndy Fleming 	int err;
1053e69d9ed4SAndrew Lunn 
105461111598SAndrew Lunn 	err = m88e1111_config_init_rgmii_delays(phydev);
105576884679SAndy Fleming 	if (err < 0)
105676884679SAndy Fleming 		return err;
105776884679SAndy Fleming 
10582f495c39SBenjamin Herrenschmidt 	if (phydev->dev_flags & MARVELL_PHY_M1145_FLAGS_RESISTANCE) {
105976884679SAndy Fleming 		err = phy_write(phydev, 0x1d, 0x0012);
106076884679SAndy Fleming 		if (err < 0)
106176884679SAndy Fleming 			return err;
106276884679SAndy Fleming 
1063f102852fSRussell King 		err = phy_modify(phydev, 0x1e, 0x0fc0,
1064fea23fb5SRussell King 				 2 << 9 | /* 36 ohm */
1065fea23fb5SRussell King 				 2 << 6); /* 39 ohm */
106676884679SAndy Fleming 		if (err < 0)
106776884679SAndy Fleming 			return err;
106876884679SAndy Fleming 
106976884679SAndy Fleming 		err = phy_write(phydev, 0x1d, 0x3);
107076884679SAndy Fleming 		if (err < 0)
107176884679SAndy Fleming 			return err;
107276884679SAndy Fleming 
107376884679SAndy Fleming 		err = phy_write(phydev, 0x1e, 0x8000);
1074e1dde8dcSAndrew Lunn 	}
107576884679SAndy Fleming 	return err;
107676884679SAndy Fleming }
107776884679SAndy Fleming 
1078e1dde8dcSAndrew Lunn static int m88e1145_config_init_sgmii(struct phy_device *phydev)
1079e1dde8dcSAndrew Lunn {
1080865b813aSAndrew Lunn 	return m88e1111_config_init_hwcfg_mode(
1081865b813aSAndrew Lunn 		phydev, MII_M1111_HWCFG_MODE_SGMII_NO_CLK,
1082865b813aSAndrew Lunn 		MII_M1111_HWCFG_FIBER_COPPER_AUTO);
1083e1dde8dcSAndrew Lunn }
1084e1dde8dcSAndrew Lunn 
1085e1dde8dcSAndrew Lunn static int m88e1145_config_init(struct phy_device *phydev)
1086e1dde8dcSAndrew Lunn {
1087e1dde8dcSAndrew Lunn 	int err;
1088e1dde8dcSAndrew Lunn 
1089e1dde8dcSAndrew Lunn 	/* Take care of errata E0 & E1 */
1090e1dde8dcSAndrew Lunn 	err = phy_write(phydev, 0x1d, 0x001b);
1091e1dde8dcSAndrew Lunn 	if (err < 0)
1092e1dde8dcSAndrew Lunn 		return err;
1093e1dde8dcSAndrew Lunn 
1094e1dde8dcSAndrew Lunn 	err = phy_write(phydev, 0x1e, 0x418f);
1095e1dde8dcSAndrew Lunn 	if (err < 0)
1096e1dde8dcSAndrew Lunn 		return err;
1097e1dde8dcSAndrew Lunn 
1098e1dde8dcSAndrew Lunn 	err = phy_write(phydev, 0x1d, 0x0016);
1099e1dde8dcSAndrew Lunn 	if (err < 0)
1100e1dde8dcSAndrew Lunn 		return err;
1101e1dde8dcSAndrew Lunn 
1102e1dde8dcSAndrew Lunn 	err = phy_write(phydev, 0x1e, 0xa2da);
1103e1dde8dcSAndrew Lunn 	if (err < 0)
1104e1dde8dcSAndrew Lunn 		return err;
1105e1dde8dcSAndrew Lunn 
1106e1dde8dcSAndrew Lunn 	if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) {
1107e1dde8dcSAndrew Lunn 		err = m88e1145_config_init_rgmii(phydev);
1108e1dde8dcSAndrew Lunn 		if (err < 0)
1109e1dde8dcSAndrew Lunn 			return err;
1110e1dde8dcSAndrew Lunn 	}
1111e1dde8dcSAndrew Lunn 
1112e1dde8dcSAndrew Lunn 	if (phydev->interface == PHY_INTERFACE_MODE_SGMII) {
1113e1dde8dcSAndrew Lunn 		err = m88e1145_config_init_sgmii(phydev);
1114b0224175SViet Nga Dao 		if (err < 0)
1115b0224175SViet Nga Dao 			return err;
1116b0224175SViet Nga Dao 	}
1117b0224175SViet Nga Dao 
1118cf41a51dSDavid Daney 	err = marvell_of_reg_init(phydev);
1119cf41a51dSDavid Daney 	if (err < 0)
1120cf41a51dSDavid Daney 		return err;
1121cf41a51dSDavid Daney 
112276884679SAndy Fleming 	return 0;
112376884679SAndy Fleming }
112400db8189SAndy Fleming 
112569f42be8SHeiner Kallweit static int m88e1540_get_fld(struct phy_device *phydev, u8 *msecs)
112669f42be8SHeiner Kallweit {
112769f42be8SHeiner Kallweit 	int val;
112869f42be8SHeiner Kallweit 
112969f42be8SHeiner Kallweit 	val = phy_read(phydev, MII_88E1540_COPPER_CTRL3);
113069f42be8SHeiner Kallweit 	if (val < 0)
113169f42be8SHeiner Kallweit 		return val;
113269f42be8SHeiner Kallweit 
113369f42be8SHeiner Kallweit 	if (!(val & MII_88E1540_COPPER_CTRL3_FAST_LINK_DOWN)) {
113469f42be8SHeiner Kallweit 		*msecs = ETHTOOL_PHY_FAST_LINK_DOWN_OFF;
113569f42be8SHeiner Kallweit 		return 0;
113669f42be8SHeiner Kallweit 	}
113769f42be8SHeiner Kallweit 
113869f42be8SHeiner Kallweit 	val = FIELD_GET(MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_MASK, val);
113969f42be8SHeiner Kallweit 
114069f42be8SHeiner Kallweit 	switch (val) {
114169f42be8SHeiner Kallweit 	case MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_00MS:
114269f42be8SHeiner Kallweit 		*msecs = 0;
114369f42be8SHeiner Kallweit 		break;
114469f42be8SHeiner Kallweit 	case MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_10MS:
114569f42be8SHeiner Kallweit 		*msecs = 10;
114669f42be8SHeiner Kallweit 		break;
114769f42be8SHeiner Kallweit 	case MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_20MS:
114869f42be8SHeiner Kallweit 		*msecs = 20;
114969f42be8SHeiner Kallweit 		break;
115069f42be8SHeiner Kallweit 	case MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_40MS:
115169f42be8SHeiner Kallweit 		*msecs = 40;
115269f42be8SHeiner Kallweit 		break;
115369f42be8SHeiner Kallweit 	default:
115469f42be8SHeiner Kallweit 		return -EINVAL;
115569f42be8SHeiner Kallweit 	}
115669f42be8SHeiner Kallweit 
115769f42be8SHeiner Kallweit 	return 0;
115869f42be8SHeiner Kallweit }
115969f42be8SHeiner Kallweit 
116069f42be8SHeiner Kallweit static int m88e1540_set_fld(struct phy_device *phydev, const u8 *msecs)
116169f42be8SHeiner Kallweit {
116269f42be8SHeiner Kallweit 	struct ethtool_eee eee;
116369f42be8SHeiner Kallweit 	int val, ret;
116469f42be8SHeiner Kallweit 
116569f42be8SHeiner Kallweit 	if (*msecs == ETHTOOL_PHY_FAST_LINK_DOWN_OFF)
116669f42be8SHeiner Kallweit 		return phy_clear_bits(phydev, MII_88E1540_COPPER_CTRL3,
116769f42be8SHeiner Kallweit 				      MII_88E1540_COPPER_CTRL3_FAST_LINK_DOWN);
116869f42be8SHeiner Kallweit 
116969f42be8SHeiner Kallweit 	/* According to the Marvell data sheet EEE must be disabled for
117069f42be8SHeiner Kallweit 	 * Fast Link Down detection to work properly
117169f42be8SHeiner Kallweit 	 */
117269f42be8SHeiner Kallweit 	ret = phy_ethtool_get_eee(phydev, &eee);
117369f42be8SHeiner Kallweit 	if (!ret && eee.eee_enabled) {
117469f42be8SHeiner Kallweit 		phydev_warn(phydev, "Fast Link Down detection requires EEE to be disabled!\n");
117569f42be8SHeiner Kallweit 		return -EBUSY;
117669f42be8SHeiner Kallweit 	}
117769f42be8SHeiner Kallweit 
117869f42be8SHeiner Kallweit 	if (*msecs <= 5)
117969f42be8SHeiner Kallweit 		val = MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_00MS;
118069f42be8SHeiner Kallweit 	else if (*msecs <= 15)
118169f42be8SHeiner Kallweit 		val = MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_10MS;
118269f42be8SHeiner Kallweit 	else if (*msecs <= 30)
118369f42be8SHeiner Kallweit 		val = MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_20MS;
118469f42be8SHeiner Kallweit 	else
118569f42be8SHeiner Kallweit 		val = MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_40MS;
118669f42be8SHeiner Kallweit 
118769f42be8SHeiner Kallweit 	val = FIELD_PREP(MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_MASK, val);
118869f42be8SHeiner Kallweit 
118969f42be8SHeiner Kallweit 	ret = phy_modify(phydev, MII_88E1540_COPPER_CTRL3,
119069f42be8SHeiner Kallweit 			 MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_MASK, val);
119169f42be8SHeiner Kallweit 	if (ret)
119269f42be8SHeiner Kallweit 		return ret;
119369f42be8SHeiner Kallweit 
119469f42be8SHeiner Kallweit 	return phy_set_bits(phydev, MII_88E1540_COPPER_CTRL3,
119569f42be8SHeiner Kallweit 			    MII_88E1540_COPPER_CTRL3_FAST_LINK_DOWN);
119669f42be8SHeiner Kallweit }
119769f42be8SHeiner Kallweit 
119869f42be8SHeiner Kallweit static int m88e1540_get_tunable(struct phy_device *phydev,
119969f42be8SHeiner Kallweit 				struct ethtool_tunable *tuna, void *data)
120069f42be8SHeiner Kallweit {
120169f42be8SHeiner Kallweit 	switch (tuna->id) {
120269f42be8SHeiner Kallweit 	case ETHTOOL_PHY_FAST_LINK_DOWN:
120369f42be8SHeiner Kallweit 		return m88e1540_get_fld(phydev, data);
1204a3bdfce7SHeiner Kallweit 	case ETHTOOL_PHY_DOWNSHIFT:
1205911af5e1SHeiner Kallweit 		return m88e1011_get_downshift(phydev, data);
120669f42be8SHeiner Kallweit 	default:
120769f42be8SHeiner Kallweit 		return -EOPNOTSUPP;
120869f42be8SHeiner Kallweit 	}
120969f42be8SHeiner Kallweit }
121069f42be8SHeiner Kallweit 
121169f42be8SHeiner Kallweit static int m88e1540_set_tunable(struct phy_device *phydev,
121269f42be8SHeiner Kallweit 				struct ethtool_tunable *tuna, const void *data)
121369f42be8SHeiner Kallweit {
121469f42be8SHeiner Kallweit 	switch (tuna->id) {
121569f42be8SHeiner Kallweit 	case ETHTOOL_PHY_FAST_LINK_DOWN:
121669f42be8SHeiner Kallweit 		return m88e1540_set_fld(phydev, data);
1217a3bdfce7SHeiner Kallweit 	case ETHTOOL_PHY_DOWNSHIFT:
1218911af5e1SHeiner Kallweit 		return m88e1011_set_downshift(phydev, *(const u8 *)data);
121969f42be8SHeiner Kallweit 	default:
122069f42be8SHeiner Kallweit 		return -EOPNOTSUPP;
122169f42be8SHeiner Kallweit 	}
122269f42be8SHeiner Kallweit }
122369f42be8SHeiner Kallweit 
12248cbcdc1aSAndrew Lunn /* The VOD can be out of specification on link up. Poke an
12258cbcdc1aSAndrew Lunn  * undocumented register, in an undocumented page, with a magic value
12268cbcdc1aSAndrew Lunn  * to fix this.
12278cbcdc1aSAndrew Lunn  */
12288cbcdc1aSAndrew Lunn static int m88e6390_errata(struct phy_device *phydev)
12298cbcdc1aSAndrew Lunn {
12308cbcdc1aSAndrew Lunn 	int err;
12318cbcdc1aSAndrew Lunn 
12328cbcdc1aSAndrew Lunn 	err = phy_write(phydev, MII_BMCR,
12338cbcdc1aSAndrew Lunn 			BMCR_ANENABLE | BMCR_SPEED1000 | BMCR_FULLDPLX);
12348cbcdc1aSAndrew Lunn 	if (err)
12358cbcdc1aSAndrew Lunn 		return err;
12368cbcdc1aSAndrew Lunn 
12378cbcdc1aSAndrew Lunn 	usleep_range(300, 400);
12388cbcdc1aSAndrew Lunn 
12398cbcdc1aSAndrew Lunn 	err = phy_write_paged(phydev, 0xf8, 0x08, 0x36);
12408cbcdc1aSAndrew Lunn 	if (err)
12418cbcdc1aSAndrew Lunn 		return err;
12428cbcdc1aSAndrew Lunn 
12438cbcdc1aSAndrew Lunn 	return genphy_soft_reset(phydev);
12448cbcdc1aSAndrew Lunn }
12458cbcdc1aSAndrew Lunn 
12468cbcdc1aSAndrew Lunn static int m88e6390_config_aneg(struct phy_device *phydev)
12478cbcdc1aSAndrew Lunn {
12488cbcdc1aSAndrew Lunn 	int err;
12498cbcdc1aSAndrew Lunn 
12508cbcdc1aSAndrew Lunn 	err = m88e6390_errata(phydev);
12518cbcdc1aSAndrew Lunn 	if (err)
12528cbcdc1aSAndrew Lunn 		return err;
12538cbcdc1aSAndrew Lunn 
12548cbcdc1aSAndrew Lunn 	return m88e1510_config_aneg(phydev);
12558cbcdc1aSAndrew Lunn }
12568cbcdc1aSAndrew Lunn 
12576cfb3bccSCharles-Antoine Couret /**
1258ab9cb729SAndrew Lunn  * fiber_lpa_mod_linkmode_lpa_t
1259c0ec3c27SAndrew Lunn  * @advertising: the linkmode advertisement settings
12606cfb3bccSCharles-Antoine Couret  * @lpa: value of the MII_LPA register for fiber link
1261be937f1fSAlexandr Smirnov  *
1262ab9cb729SAndrew Lunn  * A small helper function that translates MII_LPA bits to linkmode LP
1263ab9cb729SAndrew Lunn  * advertisement settings. Other bits in advertising are left
1264ab9cb729SAndrew Lunn  * unchanged.
12656cfb3bccSCharles-Antoine Couret  */
1266ab9cb729SAndrew Lunn static void fiber_lpa_mod_linkmode_lpa_t(unsigned long *advertising, u32 lpa)
12676cfb3bccSCharles-Antoine Couret {
1268ab9cb729SAndrew Lunn 	linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT,
126920ecf424SRussell King 			 advertising, lpa & LPA_1000XHALF);
1270ab9cb729SAndrew Lunn 
1271ab9cb729SAndrew Lunn 	linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
127220ecf424SRussell King 			 advertising, lpa & LPA_1000XFULL);
12736cfb3bccSCharles-Antoine Couret }
12746cfb3bccSCharles-Antoine Couret 
1275e1dde8dcSAndrew Lunn static int marvell_read_status_page_an(struct phy_device *phydev,
1276d2004e27SRussell King 				       int fiber, int status)
1277be937f1fSAlexandr Smirnov {
1278be937f1fSAlexandr Smirnov 	int lpa;
1279fcf1f59aSRussell King 	int err;
1280be937f1fSAlexandr Smirnov 
1281fcf1f59aSRussell King 	if (!fiber) {
1282fcf1f59aSRussell King 		err = genphy_read_lpa(phydev);
1283fcf1f59aSRussell King 		if (err < 0)
1284fcf1f59aSRussell King 			return err;
1285fcf1f59aSRussell King 
1286fcf1f59aSRussell King 		phy_resolve_aneg_pause(phydev);
1287fcf1f59aSRussell King 	} else {
1288be937f1fSAlexandr Smirnov 		lpa = phy_read(phydev, MII_LPA);
1289be937f1fSAlexandr Smirnov 		if (lpa < 0)
1290be937f1fSAlexandr Smirnov 			return lpa;
1291be937f1fSAlexandr Smirnov 
12926cfb3bccSCharles-Antoine Couret 		/* The fiber link is only 1000M capable */
1293ab9cb729SAndrew Lunn 		fiber_lpa_mod_linkmode_lpa_t(phydev->lp_advertising, lpa);
12946cfb3bccSCharles-Antoine Couret 
12956cfb3bccSCharles-Antoine Couret 		if (phydev->duplex == DUPLEX_FULL) {
12966cfb3bccSCharles-Antoine Couret 			if (!(lpa & LPA_PAUSE_FIBER)) {
12976cfb3bccSCharles-Antoine Couret 				phydev->pause = 0;
12986cfb3bccSCharles-Antoine Couret 				phydev->asym_pause = 0;
12996cfb3bccSCharles-Antoine Couret 			} else if ((lpa & LPA_PAUSE_ASYM_FIBER)) {
13006cfb3bccSCharles-Antoine Couret 				phydev->pause = 1;
13016cfb3bccSCharles-Antoine Couret 				phydev->asym_pause = 1;
13026cfb3bccSCharles-Antoine Couret 			} else {
13036cfb3bccSCharles-Antoine Couret 				phydev->pause = 1;
13046cfb3bccSCharles-Antoine Couret 				phydev->asym_pause = 0;
13056cfb3bccSCharles-Antoine Couret 			}
13066cfb3bccSCharles-Antoine Couret 		}
13076cfb3bccSCharles-Antoine Couret 	}
1308fcf1f59aSRussell King 
1309b82cf17fSRussell King 	if (!(status & MII_M1011_PHY_STATUS_RESOLVED))
1310b82cf17fSRussell King 		return 0;
1311b82cf17fSRussell King 
1312fcf1f59aSRussell King 	if (status & MII_M1011_PHY_STATUS_FULLDUPLEX)
1313fcf1f59aSRussell King 		phydev->duplex = DUPLEX_FULL;
1314fcf1f59aSRussell King 	else
1315fcf1f59aSRussell King 		phydev->duplex = DUPLEX_HALF;
1316fcf1f59aSRussell King 
1317fcf1f59aSRussell King 	switch (status & MII_M1011_PHY_STATUS_SPD_MASK) {
1318fcf1f59aSRussell King 	case MII_M1011_PHY_STATUS_1000:
1319fcf1f59aSRussell King 		phydev->speed = SPEED_1000;
1320fcf1f59aSRussell King 		break;
1321fcf1f59aSRussell King 
1322fcf1f59aSRussell King 	case MII_M1011_PHY_STATUS_100:
1323fcf1f59aSRussell King 		phydev->speed = SPEED_100;
1324fcf1f59aSRussell King 		break;
1325fcf1f59aSRussell King 
1326fcf1f59aSRussell King 	default:
1327fcf1f59aSRussell King 		phydev->speed = SPEED_10;
1328fcf1f59aSRussell King 		break;
1329fcf1f59aSRussell King 	}
1330fcf1f59aSRussell King 
1331e1dde8dcSAndrew Lunn 	return 0;
1332e1dde8dcSAndrew Lunn }
1333e1dde8dcSAndrew Lunn 
1334e1dde8dcSAndrew Lunn /* marvell_read_status_page
1335e1dde8dcSAndrew Lunn  *
1336e1dde8dcSAndrew Lunn  * Description:
1337e1dde8dcSAndrew Lunn  *   Check the link, then figure out the current state
1338e1dde8dcSAndrew Lunn  *   by comparing what we advertise with what the link partner
1339e1dde8dcSAndrew Lunn  *   advertises.  Start by checking the gigabit possibilities,
1340e1dde8dcSAndrew Lunn  *   then move on to 10/100.
1341e1dde8dcSAndrew Lunn  */
1342e1dde8dcSAndrew Lunn static int marvell_read_status_page(struct phy_device *phydev, int page)
1343e1dde8dcSAndrew Lunn {
1344d2004e27SRussell King 	int status;
1345e1dde8dcSAndrew Lunn 	int fiber;
1346e1dde8dcSAndrew Lunn 	int err;
1347e1dde8dcSAndrew Lunn 
1348d2004e27SRussell King 	status = phy_read(phydev, MII_M1011_PHY_STATUS);
1349d2004e27SRussell King 	if (status < 0)
1350d2004e27SRussell King 		return status;
1351d2004e27SRussell King 
1352d2004e27SRussell King 	/* Use the generic register for copper link status,
1353d2004e27SRussell King 	 * and the PHY status register for fiber link status.
1354e1dde8dcSAndrew Lunn 	 */
1355d2004e27SRussell King 	if (page == MII_MARVELL_FIBER_PAGE) {
1356d2004e27SRussell King 		phydev->link = !!(status & MII_M1011_PHY_STATUS_LINK);
1357d2004e27SRussell King 	} else {
1358d2004e27SRussell King 		err = genphy_update_link(phydev);
1359d2004e27SRussell King 		if (err)
1360d2004e27SRussell King 			return err;
1361d2004e27SRussell King 	}
1362d2004e27SRussell King 
136352295666SAndrew Lunn 	if (page == MII_MARVELL_FIBER_PAGE)
1364e1dde8dcSAndrew Lunn 		fiber = 1;
1365e1dde8dcSAndrew Lunn 	else
1366e1dde8dcSAndrew Lunn 		fiber = 0;
1367e1dde8dcSAndrew Lunn 
136898f92831SRussell King 	linkmode_zero(phydev->lp_advertising);
136998f92831SRussell King 	phydev->pause = 0;
137098f92831SRussell King 	phydev->asym_pause = 0;
1371b82cf17fSRussell King 	phydev->speed = SPEED_UNKNOWN;
1372b82cf17fSRussell King 	phydev->duplex = DUPLEX_UNKNOWN;
137398f92831SRussell King 
1374e1dde8dcSAndrew Lunn 	if (phydev->autoneg == AUTONEG_ENABLE)
1375d2004e27SRussell King 		err = marvell_read_status_page_an(phydev, fiber, status);
1376e1dde8dcSAndrew Lunn 	else
137798f92831SRussell King 		err = genphy_read_status_fixed(phydev);
1378e1dde8dcSAndrew Lunn 
1379e1dde8dcSAndrew Lunn 	return err;
1380e1dde8dcSAndrew Lunn }
1381e1dde8dcSAndrew Lunn 
13826cfb3bccSCharles-Antoine Couret /* marvell_read_status
13836cfb3bccSCharles-Antoine Couret  *
13846cfb3bccSCharles-Antoine Couret  * Some Marvell's phys have two modes: fiber and copper.
13856cfb3bccSCharles-Antoine Couret  * Both need status checked.
13866cfb3bccSCharles-Antoine Couret  * Description:
13876cfb3bccSCharles-Antoine Couret  *   First, check the fiber link and status.
13886cfb3bccSCharles-Antoine Couret  *   If the fiber link is down, check the copper link and status which
13896cfb3bccSCharles-Antoine Couret  *   will be the default value if both link are down.
13906cfb3bccSCharles-Antoine Couret  */
13916cfb3bccSCharles-Antoine Couret static int marvell_read_status(struct phy_device *phydev)
13926cfb3bccSCharles-Antoine Couret {
13936cfb3bccSCharles-Antoine Couret 	int err;
13946cfb3bccSCharles-Antoine Couret 
13956cfb3bccSCharles-Antoine Couret 	/* Check the fiber mode first */
13963c1bcc86SAndrew Lunn 	if (linkmode_test_bit(ETHTOOL_LINK_MODE_FIBRE_BIT,
13973c1bcc86SAndrew Lunn 			      phydev->supported) &&
1398a13c0652SRussell King 	    phydev->interface != PHY_INTERFACE_MODE_SGMII) {
139952295666SAndrew Lunn 		err = marvell_set_page(phydev, MII_MARVELL_FIBER_PAGE);
14006cfb3bccSCharles-Antoine Couret 		if (err < 0)
14016cfb3bccSCharles-Antoine Couret 			goto error;
14026cfb3bccSCharles-Antoine Couret 
140352295666SAndrew Lunn 		err = marvell_read_status_page(phydev, MII_MARVELL_FIBER_PAGE);
14046cfb3bccSCharles-Antoine Couret 		if (err < 0)
14056cfb3bccSCharles-Antoine Couret 			goto error;
14066cfb3bccSCharles-Antoine Couret 
14070c3439bcSAndrew Lunn 		/* If the fiber link is up, it is the selected and
14080c3439bcSAndrew Lunn 		 * used link. In this case, we need to stay in the
14090c3439bcSAndrew Lunn 		 * fiber page. Please to be careful about that, avoid
14100c3439bcSAndrew Lunn 		 * to restore Copper page in other functions which
14110c3439bcSAndrew Lunn 		 * could break the behaviour for some fiber phy like
14120c3439bcSAndrew Lunn 		 * 88E1512.
14130c3439bcSAndrew Lunn 		 */
14146cfb3bccSCharles-Antoine Couret 		if (phydev->link)
14156cfb3bccSCharles-Antoine Couret 			return 0;
14166cfb3bccSCharles-Antoine Couret 
14176cfb3bccSCharles-Antoine Couret 		/* If fiber link is down, check and save copper mode state */
141852295666SAndrew Lunn 		err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);
14196cfb3bccSCharles-Antoine Couret 		if (err < 0)
14206cfb3bccSCharles-Antoine Couret 			goto error;
14216cfb3bccSCharles-Antoine Couret 	}
14226cfb3bccSCharles-Antoine Couret 
142352295666SAndrew Lunn 	return marvell_read_status_page(phydev, MII_MARVELL_COPPER_PAGE);
14246cfb3bccSCharles-Antoine Couret 
14256cfb3bccSCharles-Antoine Couret error:
142652295666SAndrew Lunn 	marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);
14276cfb3bccSCharles-Antoine Couret 	return err;
14286cfb3bccSCharles-Antoine Couret }
14293758be3dSCharles-Antoine Couret 
14303758be3dSCharles-Antoine Couret /* marvell_suspend
14313758be3dSCharles-Antoine Couret  *
14323758be3dSCharles-Antoine Couret  * Some Marvell's phys have two modes: fiber and copper.
14333758be3dSCharles-Antoine Couret  * Both need to be suspended
14343758be3dSCharles-Antoine Couret  */
14353758be3dSCharles-Antoine Couret static int marvell_suspend(struct phy_device *phydev)
14363758be3dSCharles-Antoine Couret {
14373758be3dSCharles-Antoine Couret 	int err;
14383758be3dSCharles-Antoine Couret 
14393758be3dSCharles-Antoine Couret 	/* Suspend the fiber mode first */
14403c1bcc86SAndrew Lunn 	if (!linkmode_test_bit(ETHTOOL_LINK_MODE_FIBRE_BIT,
14413c1bcc86SAndrew Lunn 			       phydev->supported)) {
144252295666SAndrew Lunn 		err = marvell_set_page(phydev, MII_MARVELL_FIBER_PAGE);
14433758be3dSCharles-Antoine Couret 		if (err < 0)
14443758be3dSCharles-Antoine Couret 			goto error;
14453758be3dSCharles-Antoine Couret 
14463758be3dSCharles-Antoine Couret 		/* With the page set, use the generic suspend */
14473758be3dSCharles-Antoine Couret 		err = genphy_suspend(phydev);
14483758be3dSCharles-Antoine Couret 		if (err < 0)
14493758be3dSCharles-Antoine Couret 			goto error;
14503758be3dSCharles-Antoine Couret 
14513758be3dSCharles-Antoine Couret 		/* Then, the copper link */
145252295666SAndrew Lunn 		err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);
14533758be3dSCharles-Antoine Couret 		if (err < 0)
14543758be3dSCharles-Antoine Couret 			goto error;
14553758be3dSCharles-Antoine Couret 	}
14563758be3dSCharles-Antoine Couret 
14573758be3dSCharles-Antoine Couret 	/* With the page set, use the generic suspend */
14583758be3dSCharles-Antoine Couret 	return genphy_suspend(phydev);
14593758be3dSCharles-Antoine Couret 
14603758be3dSCharles-Antoine Couret error:
146152295666SAndrew Lunn 	marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);
14623758be3dSCharles-Antoine Couret 	return err;
14633758be3dSCharles-Antoine Couret }
14643758be3dSCharles-Antoine Couret 
14653758be3dSCharles-Antoine Couret /* marvell_resume
14663758be3dSCharles-Antoine Couret  *
14673758be3dSCharles-Antoine Couret  * Some Marvell's phys have two modes: fiber and copper.
14683758be3dSCharles-Antoine Couret  * Both need to be resumed
14693758be3dSCharles-Antoine Couret  */
14703758be3dSCharles-Antoine Couret static int marvell_resume(struct phy_device *phydev)
14713758be3dSCharles-Antoine Couret {
14723758be3dSCharles-Antoine Couret 	int err;
14733758be3dSCharles-Antoine Couret 
14743758be3dSCharles-Antoine Couret 	/* Resume the fiber mode first */
14753c1bcc86SAndrew Lunn 	if (!linkmode_test_bit(ETHTOOL_LINK_MODE_FIBRE_BIT,
14763c1bcc86SAndrew Lunn 			       phydev->supported)) {
147752295666SAndrew Lunn 		err = marvell_set_page(phydev, MII_MARVELL_FIBER_PAGE);
14783758be3dSCharles-Antoine Couret 		if (err < 0)
14793758be3dSCharles-Antoine Couret 			goto error;
14803758be3dSCharles-Antoine Couret 
14813758be3dSCharles-Antoine Couret 		/* With the page set, use the generic resume */
14823758be3dSCharles-Antoine Couret 		err = genphy_resume(phydev);
14833758be3dSCharles-Antoine Couret 		if (err < 0)
14843758be3dSCharles-Antoine Couret 			goto error;
14853758be3dSCharles-Antoine Couret 
14863758be3dSCharles-Antoine Couret 		/* Then, the copper link */
148752295666SAndrew Lunn 		err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);
14883758be3dSCharles-Antoine Couret 		if (err < 0)
14893758be3dSCharles-Antoine Couret 			goto error;
14903758be3dSCharles-Antoine Couret 	}
14913758be3dSCharles-Antoine Couret 
14923758be3dSCharles-Antoine Couret 	/* With the page set, use the generic resume */
14933758be3dSCharles-Antoine Couret 	return genphy_resume(phydev);
14943758be3dSCharles-Antoine Couret 
14953758be3dSCharles-Antoine Couret error:
149652295666SAndrew Lunn 	marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);
14973758be3dSCharles-Antoine Couret 	return err;
14983758be3dSCharles-Antoine Couret }
14993758be3dSCharles-Antoine Couret 
15006b358aedSSebastian Hesselbarth static int marvell_aneg_done(struct phy_device *phydev)
15016b358aedSSebastian Hesselbarth {
15026b358aedSSebastian Hesselbarth 	int retval = phy_read(phydev, MII_M1011_PHY_STATUS);
1503e69d9ed4SAndrew Lunn 
15046b358aedSSebastian Hesselbarth 	return (retval < 0) ? retval : (retval & MII_M1011_PHY_STATUS_RESOLVED);
15056b358aedSSebastian Hesselbarth }
15066b358aedSSebastian Hesselbarth 
1507dcd07be3SAnatolij Gustschin static int m88e1121_did_interrupt(struct phy_device *phydev)
1508dcd07be3SAnatolij Gustschin {
1509dcd07be3SAnatolij Gustschin 	int imask;
1510dcd07be3SAnatolij Gustschin 
1511dcd07be3SAnatolij Gustschin 	imask = phy_read(phydev, MII_M1011_IEVENT);
1512dcd07be3SAnatolij Gustschin 
1513dcd07be3SAnatolij Gustschin 	if (imask & MII_M1011_IMASK_INIT)
1514dcd07be3SAnatolij Gustschin 		return 1;
1515dcd07be3SAnatolij Gustschin 
1516dcd07be3SAnatolij Gustschin 	return 0;
1517dcd07be3SAnatolij Gustschin }
1518dcd07be3SAnatolij Gustschin 
151923beb38fSAndrew Lunn static void m88e1318_get_wol(struct phy_device *phydev,
152023beb38fSAndrew Lunn 			     struct ethtool_wolinfo *wol)
15213871c387SMichael Stapelberg {
1522424ca4c5SRussell King 	int oldpage, ret = 0;
1523424ca4c5SRussell King 
15243871c387SMichael Stapelberg 	wol->supported = WAKE_MAGIC;
15253871c387SMichael Stapelberg 	wol->wolopts = 0;
15263871c387SMichael Stapelberg 
1527424ca4c5SRussell King 	oldpage = phy_select_page(phydev, MII_MARVELL_WOL_PAGE);
1528424ca4c5SRussell King 	if (oldpage < 0)
1529424ca4c5SRussell King 		goto error;
15303871c387SMichael Stapelberg 
1531424ca4c5SRussell King 	ret = __phy_read(phydev, MII_88E1318S_PHY_WOL_CTRL);
1532424ca4c5SRussell King 	if (ret & MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE)
15333871c387SMichael Stapelberg 		wol->wolopts |= WAKE_MAGIC;
15343871c387SMichael Stapelberg 
1535424ca4c5SRussell King error:
1536424ca4c5SRussell King 	phy_restore_page(phydev, oldpage, ret);
15373871c387SMichael Stapelberg }
15383871c387SMichael Stapelberg 
153923beb38fSAndrew Lunn static int m88e1318_set_wol(struct phy_device *phydev,
154023beb38fSAndrew Lunn 			    struct ethtool_wolinfo *wol)
15413871c387SMichael Stapelberg {
1542424ca4c5SRussell King 	int err = 0, oldpage;
15433871c387SMichael Stapelberg 
1544424ca4c5SRussell King 	oldpage = phy_save_page(phydev);
1545424ca4c5SRussell King 	if (oldpage < 0)
1546424ca4c5SRussell King 		goto error;
15473871c387SMichael Stapelberg 
15483871c387SMichael Stapelberg 	if (wol->wolopts & WAKE_MAGIC) {
15493871c387SMichael Stapelberg 		/* Explicitly switch to page 0x00, just to be sure */
1550424ca4c5SRussell King 		err = marvell_write_page(phydev, MII_MARVELL_COPPER_PAGE);
15513871c387SMichael Stapelberg 		if (err < 0)
1552424ca4c5SRussell King 			goto error;
15533871c387SMichael Stapelberg 
1554b6a930faSJingju Hou 		/* If WOL event happened once, the LED[2] interrupt pin
1555b6a930faSJingju Hou 		 * will not be cleared unless we reading the interrupt status
1556b6a930faSJingju Hou 		 * register. If interrupts are in use, the normal interrupt
1557b6a930faSJingju Hou 		 * handling will clear the WOL event. Clear the WOL event
1558b6a930faSJingju Hou 		 * before enabling it if !phy_interrupt_is_valid()
1559b6a930faSJingju Hou 		 */
1560b6a930faSJingju Hou 		if (!phy_interrupt_is_valid(phydev))
1561e0a7328fSAndrew Lunn 			__phy_read(phydev, MII_M1011_IEVENT);
1562b6a930faSJingju Hou 
15633871c387SMichael Stapelberg 		/* Enable the WOL interrupt */
1564424ca4c5SRussell King 		err = __phy_modify(phydev, MII_88E1318S_PHY_CSIER, 0,
1565424ca4c5SRussell King 				   MII_88E1318S_PHY_CSIER_WOL_EIE);
15663871c387SMichael Stapelberg 		if (err < 0)
1567424ca4c5SRussell King 			goto error;
15683871c387SMichael Stapelberg 
1569424ca4c5SRussell King 		err = marvell_write_page(phydev, MII_MARVELL_LED_PAGE);
15703871c387SMichael Stapelberg 		if (err < 0)
1571424ca4c5SRussell King 			goto error;
15723871c387SMichael Stapelberg 
15733871c387SMichael Stapelberg 		/* Setup LED[2] as interrupt pin (active low) */
1574424ca4c5SRussell King 		err = __phy_modify(phydev, MII_88E1318S_PHY_LED_TCR,
1575f102852fSRussell King 				   MII_88E1318S_PHY_LED_TCR_FORCE_INT,
1576424ca4c5SRussell King 				   MII_88E1318S_PHY_LED_TCR_INTn_ENABLE |
1577424ca4c5SRussell King 				   MII_88E1318S_PHY_LED_TCR_INT_ACTIVE_LOW);
15783871c387SMichael Stapelberg 		if (err < 0)
1579424ca4c5SRussell King 			goto error;
15803871c387SMichael Stapelberg 
1581424ca4c5SRussell King 		err = marvell_write_page(phydev, MII_MARVELL_WOL_PAGE);
15823871c387SMichael Stapelberg 		if (err < 0)
1583424ca4c5SRussell King 			goto error;
15843871c387SMichael Stapelberg 
15853871c387SMichael Stapelberg 		/* Store the device address for the magic packet */
1586424ca4c5SRussell King 		err = __phy_write(phydev, MII_88E1318S_PHY_MAGIC_PACKET_WORD2,
15873871c387SMichael Stapelberg 				((phydev->attached_dev->dev_addr[5] << 8) |
15883871c387SMichael Stapelberg 				 phydev->attached_dev->dev_addr[4]));
15893871c387SMichael Stapelberg 		if (err < 0)
1590424ca4c5SRussell King 			goto error;
1591424ca4c5SRussell King 		err = __phy_write(phydev, MII_88E1318S_PHY_MAGIC_PACKET_WORD1,
15923871c387SMichael Stapelberg 				((phydev->attached_dev->dev_addr[3] << 8) |
15933871c387SMichael Stapelberg 				 phydev->attached_dev->dev_addr[2]));
15943871c387SMichael Stapelberg 		if (err < 0)
1595424ca4c5SRussell King 			goto error;
1596424ca4c5SRussell King 		err = __phy_write(phydev, MII_88E1318S_PHY_MAGIC_PACKET_WORD0,
15973871c387SMichael Stapelberg 				((phydev->attached_dev->dev_addr[1] << 8) |
15983871c387SMichael Stapelberg 				 phydev->attached_dev->dev_addr[0]));
15993871c387SMichael Stapelberg 		if (err < 0)
1600424ca4c5SRussell King 			goto error;
16013871c387SMichael Stapelberg 
16023871c387SMichael Stapelberg 		/* Clear WOL status and enable magic packet matching */
1603424ca4c5SRussell King 		err = __phy_modify(phydev, MII_88E1318S_PHY_WOL_CTRL, 0,
1604424ca4c5SRussell King 				   MII_88E1318S_PHY_WOL_CTRL_CLEAR_WOL_STATUS |
1605424ca4c5SRussell King 				   MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE);
16063871c387SMichael Stapelberg 		if (err < 0)
1607424ca4c5SRussell King 			goto error;
16083871c387SMichael Stapelberg 	} else {
1609424ca4c5SRussell King 		err = marvell_write_page(phydev, MII_MARVELL_WOL_PAGE);
16103871c387SMichael Stapelberg 		if (err < 0)
1611424ca4c5SRussell King 			goto error;
16123871c387SMichael Stapelberg 
16133871c387SMichael Stapelberg 		/* Clear WOL status and disable magic packet matching */
1614424ca4c5SRussell King 		err = __phy_modify(phydev, MII_88E1318S_PHY_WOL_CTRL,
1615f102852fSRussell King 				   MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE,
1616424ca4c5SRussell King 				   MII_88E1318S_PHY_WOL_CTRL_CLEAR_WOL_STATUS);
16173871c387SMichael Stapelberg 		if (err < 0)
1618424ca4c5SRussell King 			goto error;
16193871c387SMichael Stapelberg 	}
16203871c387SMichael Stapelberg 
1621424ca4c5SRussell King error:
1622424ca4c5SRussell King 	return phy_restore_page(phydev, oldpage, err);
16233871c387SMichael Stapelberg }
16243871c387SMichael Stapelberg 
1625d2fa47d9SAndrew Lunn static int marvell_get_sset_count(struct phy_device *phydev)
1626d2fa47d9SAndrew Lunn {
16273c1bcc86SAndrew Lunn 	if (linkmode_test_bit(ETHTOOL_LINK_MODE_FIBRE_BIT,
16283c1bcc86SAndrew Lunn 			      phydev->supported))
1629d2fa47d9SAndrew Lunn 		return ARRAY_SIZE(marvell_hw_stats);
16302170fef7SCharles-Antoine Couret 	else
16312170fef7SCharles-Antoine Couret 		return ARRAY_SIZE(marvell_hw_stats) - NB_FIBER_STATS;
1632d2fa47d9SAndrew Lunn }
1633d2fa47d9SAndrew Lunn 
1634d2fa47d9SAndrew Lunn static void marvell_get_strings(struct phy_device *phydev, u8 *data)
1635d2fa47d9SAndrew Lunn {
1636fdfdf867SAndrew Lunn 	int count = marvell_get_sset_count(phydev);
1637d2fa47d9SAndrew Lunn 	int i;
1638d2fa47d9SAndrew Lunn 
1639fdfdf867SAndrew Lunn 	for (i = 0; i < count; i++) {
164098409b2bSFlorian Fainelli 		strlcpy(data + i * ETH_GSTRING_LEN,
1641d2fa47d9SAndrew Lunn 			marvell_hw_stats[i].string, ETH_GSTRING_LEN);
1642d2fa47d9SAndrew Lunn 	}
1643d2fa47d9SAndrew Lunn }
1644d2fa47d9SAndrew Lunn 
1645d2fa47d9SAndrew Lunn static u64 marvell_get_stat(struct phy_device *phydev, int i)
1646d2fa47d9SAndrew Lunn {
1647d2fa47d9SAndrew Lunn 	struct marvell_hw_stat stat = marvell_hw_stats[i];
1648d2fa47d9SAndrew Lunn 	struct marvell_priv *priv = phydev->priv;
1649424ca4c5SRussell King 	int val;
1650321b4d4bSAndrew Lunn 	u64 ret;
1651d2fa47d9SAndrew Lunn 
1652424ca4c5SRussell King 	val = phy_read_paged(phydev, stat.page, stat.reg);
1653d2fa47d9SAndrew Lunn 	if (val < 0) {
16546c3442f5SJisheng Zhang 		ret = U64_MAX;
1655d2fa47d9SAndrew Lunn 	} else {
1656d2fa47d9SAndrew Lunn 		val = val & ((1 << stat.bits) - 1);
1657d2fa47d9SAndrew Lunn 		priv->stats[i] += val;
1658321b4d4bSAndrew Lunn 		ret = priv->stats[i];
1659d2fa47d9SAndrew Lunn 	}
1660d2fa47d9SAndrew Lunn 
1661321b4d4bSAndrew Lunn 	return ret;
1662d2fa47d9SAndrew Lunn }
1663d2fa47d9SAndrew Lunn 
1664d2fa47d9SAndrew Lunn static void marvell_get_stats(struct phy_device *phydev,
1665d2fa47d9SAndrew Lunn 			      struct ethtool_stats *stats, u64 *data)
1666d2fa47d9SAndrew Lunn {
1667fdfdf867SAndrew Lunn 	int count = marvell_get_sset_count(phydev);
1668d2fa47d9SAndrew Lunn 	int i;
1669d2fa47d9SAndrew Lunn 
1670fdfdf867SAndrew Lunn 	for (i = 0; i < count; i++)
1671d2fa47d9SAndrew Lunn 		data[i] = marvell_get_stat(phydev, i);
1672d2fa47d9SAndrew Lunn }
1673d2fa47d9SAndrew Lunn 
16740b04680fSAndrew Lunn #ifdef CONFIG_HWMON
16750b04680fSAndrew Lunn static int m88e1121_get_temp(struct phy_device *phydev, long *temp)
16760b04680fSAndrew Lunn {
1677975b388cSAndrew Lunn 	int oldpage;
1678424ca4c5SRussell King 	int ret = 0;
16790b04680fSAndrew Lunn 	int val;
16800b04680fSAndrew Lunn 
16810b04680fSAndrew Lunn 	*temp = 0;
16820b04680fSAndrew Lunn 
1683424ca4c5SRussell King 	oldpage = phy_select_page(phydev, MII_MARVELL_MISC_TEST_PAGE);
1684424ca4c5SRussell King 	if (oldpage < 0)
1685424ca4c5SRussell King 		goto error;
1686975b388cSAndrew Lunn 
16870b04680fSAndrew Lunn 	/* Enable temperature sensor */
1688424ca4c5SRussell King 	ret = __phy_read(phydev, MII_88E1121_MISC_TEST);
16890b04680fSAndrew Lunn 	if (ret < 0)
16900b04680fSAndrew Lunn 		goto error;
16910b04680fSAndrew Lunn 
1692424ca4c5SRussell King 	ret = __phy_write(phydev, MII_88E1121_MISC_TEST,
16930b04680fSAndrew Lunn 			  ret | MII_88E1121_MISC_TEST_TEMP_SENSOR_EN);
16940b04680fSAndrew Lunn 	if (ret < 0)
16950b04680fSAndrew Lunn 		goto error;
16960b04680fSAndrew Lunn 
16970b04680fSAndrew Lunn 	/* Wait for temperature to stabilize */
16980b04680fSAndrew Lunn 	usleep_range(10000, 12000);
16990b04680fSAndrew Lunn 
1700424ca4c5SRussell King 	val = __phy_read(phydev, MII_88E1121_MISC_TEST);
17010b04680fSAndrew Lunn 	if (val < 0) {
17020b04680fSAndrew Lunn 		ret = val;
17030b04680fSAndrew Lunn 		goto error;
17040b04680fSAndrew Lunn 	}
17050b04680fSAndrew Lunn 
17060b04680fSAndrew Lunn 	/* Disable temperature sensor */
1707424ca4c5SRussell King 	ret = __phy_write(phydev, MII_88E1121_MISC_TEST,
17080b04680fSAndrew Lunn 			  ret & ~MII_88E1121_MISC_TEST_TEMP_SENSOR_EN);
17090b04680fSAndrew Lunn 	if (ret < 0)
17100b04680fSAndrew Lunn 		goto error;
17110b04680fSAndrew Lunn 
17120b04680fSAndrew Lunn 	*temp = ((val & MII_88E1121_MISC_TEST_TEMP_MASK) - 5) * 5000;
17130b04680fSAndrew Lunn 
17140b04680fSAndrew Lunn error:
1715424ca4c5SRussell King 	return phy_restore_page(phydev, oldpage, ret);
17160b04680fSAndrew Lunn }
17170b04680fSAndrew Lunn 
17180b04680fSAndrew Lunn static int m88e1121_hwmon_read(struct device *dev,
17190b04680fSAndrew Lunn 			       enum hwmon_sensor_types type,
17200b04680fSAndrew Lunn 			       u32 attr, int channel, long *temp)
17210b04680fSAndrew Lunn {
17220b04680fSAndrew Lunn 	struct phy_device *phydev = dev_get_drvdata(dev);
17230b04680fSAndrew Lunn 	int err;
17240b04680fSAndrew Lunn 
17250b04680fSAndrew Lunn 	switch (attr) {
17260b04680fSAndrew Lunn 	case hwmon_temp_input:
17270b04680fSAndrew Lunn 		err = m88e1121_get_temp(phydev, temp);
17280b04680fSAndrew Lunn 		break;
17290b04680fSAndrew Lunn 	default:
17300b04680fSAndrew Lunn 		return -EOPNOTSUPP;
17310b04680fSAndrew Lunn 	}
17320b04680fSAndrew Lunn 
17330b04680fSAndrew Lunn 	return err;
17340b04680fSAndrew Lunn }
17350b04680fSAndrew Lunn 
17360b04680fSAndrew Lunn static umode_t m88e1121_hwmon_is_visible(const void *data,
17370b04680fSAndrew Lunn 					 enum hwmon_sensor_types type,
17380b04680fSAndrew Lunn 					 u32 attr, int channel)
17390b04680fSAndrew Lunn {
17400b04680fSAndrew Lunn 	if (type != hwmon_temp)
17410b04680fSAndrew Lunn 		return 0;
17420b04680fSAndrew Lunn 
17430b04680fSAndrew Lunn 	switch (attr) {
17440b04680fSAndrew Lunn 	case hwmon_temp_input:
17450b04680fSAndrew Lunn 		return 0444;
17460b04680fSAndrew Lunn 	default:
17470b04680fSAndrew Lunn 		return 0;
17480b04680fSAndrew Lunn 	}
17490b04680fSAndrew Lunn }
17500b04680fSAndrew Lunn 
17510b04680fSAndrew Lunn static u32 m88e1121_hwmon_chip_config[] = {
17520b04680fSAndrew Lunn 	HWMON_C_REGISTER_TZ,
17530b04680fSAndrew Lunn 	0
17540b04680fSAndrew Lunn };
17550b04680fSAndrew Lunn 
17560b04680fSAndrew Lunn static const struct hwmon_channel_info m88e1121_hwmon_chip = {
17570b04680fSAndrew Lunn 	.type = hwmon_chip,
17580b04680fSAndrew Lunn 	.config = m88e1121_hwmon_chip_config,
17590b04680fSAndrew Lunn };
17600b04680fSAndrew Lunn 
17610b04680fSAndrew Lunn static u32 m88e1121_hwmon_temp_config[] = {
17620b04680fSAndrew Lunn 	HWMON_T_INPUT,
17630b04680fSAndrew Lunn 	0
17640b04680fSAndrew Lunn };
17650b04680fSAndrew Lunn 
17660b04680fSAndrew Lunn static const struct hwmon_channel_info m88e1121_hwmon_temp = {
17670b04680fSAndrew Lunn 	.type = hwmon_temp,
17680b04680fSAndrew Lunn 	.config = m88e1121_hwmon_temp_config,
17690b04680fSAndrew Lunn };
17700b04680fSAndrew Lunn 
17710b04680fSAndrew Lunn static const struct hwmon_channel_info *m88e1121_hwmon_info[] = {
17720b04680fSAndrew Lunn 	&m88e1121_hwmon_chip,
17730b04680fSAndrew Lunn 	&m88e1121_hwmon_temp,
17740b04680fSAndrew Lunn 	NULL
17750b04680fSAndrew Lunn };
17760b04680fSAndrew Lunn 
17770b04680fSAndrew Lunn static const struct hwmon_ops m88e1121_hwmon_hwmon_ops = {
17780b04680fSAndrew Lunn 	.is_visible = m88e1121_hwmon_is_visible,
17790b04680fSAndrew Lunn 	.read = m88e1121_hwmon_read,
17800b04680fSAndrew Lunn };
17810b04680fSAndrew Lunn 
17820b04680fSAndrew Lunn static const struct hwmon_chip_info m88e1121_hwmon_chip_info = {
17830b04680fSAndrew Lunn 	.ops = &m88e1121_hwmon_hwmon_ops,
17840b04680fSAndrew Lunn 	.info = m88e1121_hwmon_info,
17850b04680fSAndrew Lunn };
17860b04680fSAndrew Lunn 
17870b04680fSAndrew Lunn static int m88e1510_get_temp(struct phy_device *phydev, long *temp)
17880b04680fSAndrew Lunn {
17890b04680fSAndrew Lunn 	int ret;
17900b04680fSAndrew Lunn 
17910b04680fSAndrew Lunn 	*temp = 0;
17920b04680fSAndrew Lunn 
1793424ca4c5SRussell King 	ret = phy_read_paged(phydev, MII_MARVELL_MISC_TEST_PAGE,
1794424ca4c5SRussell King 			     MII_88E1510_TEMP_SENSOR);
17950b04680fSAndrew Lunn 	if (ret < 0)
1796424ca4c5SRussell King 		return ret;
17970b04680fSAndrew Lunn 
17980b04680fSAndrew Lunn 	*temp = ((ret & MII_88E1510_TEMP_SENSOR_MASK) - 25) * 1000;
17990b04680fSAndrew Lunn 
1800424ca4c5SRussell King 	return 0;
18010b04680fSAndrew Lunn }
18020b04680fSAndrew Lunn 
1803f0a45816SColin Ian King static int m88e1510_get_temp_critical(struct phy_device *phydev, long *temp)
18040b04680fSAndrew Lunn {
18050b04680fSAndrew Lunn 	int ret;
18060b04680fSAndrew Lunn 
18070b04680fSAndrew Lunn 	*temp = 0;
18080b04680fSAndrew Lunn 
1809424ca4c5SRussell King 	ret = phy_read_paged(phydev, MII_MARVELL_MISC_TEST_PAGE,
1810424ca4c5SRussell King 			     MII_88E1121_MISC_TEST);
18110b04680fSAndrew Lunn 	if (ret < 0)
1812424ca4c5SRussell King 		return ret;
18130b04680fSAndrew Lunn 
18140b04680fSAndrew Lunn 	*temp = (((ret & MII_88E1510_MISC_TEST_TEMP_THRESHOLD_MASK) >>
18150b04680fSAndrew Lunn 		  MII_88E1510_MISC_TEST_TEMP_THRESHOLD_SHIFT) * 5) - 25;
18160b04680fSAndrew Lunn 	/* convert to mC */
18170b04680fSAndrew Lunn 	*temp *= 1000;
18180b04680fSAndrew Lunn 
1819424ca4c5SRussell King 	return 0;
18200b04680fSAndrew Lunn }
18210b04680fSAndrew Lunn 
1822f0a45816SColin Ian King static int m88e1510_set_temp_critical(struct phy_device *phydev, long temp)
18230b04680fSAndrew Lunn {
18240b04680fSAndrew Lunn 	temp = temp / 1000;
18250b04680fSAndrew Lunn 	temp = clamp_val(DIV_ROUND_CLOSEST(temp, 5) + 5, 0, 0x1f);
18260b04680fSAndrew Lunn 
1827424ca4c5SRussell King 	return phy_modify_paged(phydev, MII_MARVELL_MISC_TEST_PAGE,
1828424ca4c5SRussell King 				MII_88E1121_MISC_TEST,
1829424ca4c5SRussell King 				MII_88E1510_MISC_TEST_TEMP_THRESHOLD_MASK,
1830424ca4c5SRussell King 				temp << MII_88E1510_MISC_TEST_TEMP_THRESHOLD_SHIFT);
18310b04680fSAndrew Lunn }
18320b04680fSAndrew Lunn 
1833f0a45816SColin Ian King static int m88e1510_get_temp_alarm(struct phy_device *phydev, long *alarm)
18340b04680fSAndrew Lunn {
18350b04680fSAndrew Lunn 	int ret;
18360b04680fSAndrew Lunn 
18370b04680fSAndrew Lunn 	*alarm = false;
18380b04680fSAndrew Lunn 
1839424ca4c5SRussell King 	ret = phy_read_paged(phydev, MII_MARVELL_MISC_TEST_PAGE,
1840424ca4c5SRussell King 			     MII_88E1121_MISC_TEST);
18410b04680fSAndrew Lunn 	if (ret < 0)
1842424ca4c5SRussell King 		return ret;
1843424ca4c5SRussell King 
18440b04680fSAndrew Lunn 	*alarm = !!(ret & MII_88E1510_MISC_TEST_TEMP_IRQ);
18450b04680fSAndrew Lunn 
1846424ca4c5SRussell King 	return 0;
18470b04680fSAndrew Lunn }
18480b04680fSAndrew Lunn 
18490b04680fSAndrew Lunn static int m88e1510_hwmon_read(struct device *dev,
18500b04680fSAndrew Lunn 			       enum hwmon_sensor_types type,
18510b04680fSAndrew Lunn 			       u32 attr, int channel, long *temp)
18520b04680fSAndrew Lunn {
18530b04680fSAndrew Lunn 	struct phy_device *phydev = dev_get_drvdata(dev);
18540b04680fSAndrew Lunn 	int err;
18550b04680fSAndrew Lunn 
18560b04680fSAndrew Lunn 	switch (attr) {
18570b04680fSAndrew Lunn 	case hwmon_temp_input:
18580b04680fSAndrew Lunn 		err = m88e1510_get_temp(phydev, temp);
18590b04680fSAndrew Lunn 		break;
18600b04680fSAndrew Lunn 	case hwmon_temp_crit:
18610b04680fSAndrew Lunn 		err = m88e1510_get_temp_critical(phydev, temp);
18620b04680fSAndrew Lunn 		break;
18630b04680fSAndrew Lunn 	case hwmon_temp_max_alarm:
18640b04680fSAndrew Lunn 		err = m88e1510_get_temp_alarm(phydev, temp);
18650b04680fSAndrew Lunn 		break;
18660b04680fSAndrew Lunn 	default:
18670b04680fSAndrew Lunn 		return -EOPNOTSUPP;
18680b04680fSAndrew Lunn 	}
18690b04680fSAndrew Lunn 
18700b04680fSAndrew Lunn 	return err;
18710b04680fSAndrew Lunn }
18720b04680fSAndrew Lunn 
18730b04680fSAndrew Lunn static int m88e1510_hwmon_write(struct device *dev,
18740b04680fSAndrew Lunn 				enum hwmon_sensor_types type,
18750b04680fSAndrew Lunn 				u32 attr, int channel, long temp)
18760b04680fSAndrew Lunn {
18770b04680fSAndrew Lunn 	struct phy_device *phydev = dev_get_drvdata(dev);
18780b04680fSAndrew Lunn 	int err;
18790b04680fSAndrew Lunn 
18800b04680fSAndrew Lunn 	switch (attr) {
18810b04680fSAndrew Lunn 	case hwmon_temp_crit:
18820b04680fSAndrew Lunn 		err = m88e1510_set_temp_critical(phydev, temp);
18830b04680fSAndrew Lunn 		break;
18840b04680fSAndrew Lunn 	default:
18850b04680fSAndrew Lunn 		return -EOPNOTSUPP;
18860b04680fSAndrew Lunn 	}
18870b04680fSAndrew Lunn 	return err;
18880b04680fSAndrew Lunn }
18890b04680fSAndrew Lunn 
18900b04680fSAndrew Lunn static umode_t m88e1510_hwmon_is_visible(const void *data,
18910b04680fSAndrew Lunn 					 enum hwmon_sensor_types type,
18920b04680fSAndrew Lunn 					 u32 attr, int channel)
18930b04680fSAndrew Lunn {
18940b04680fSAndrew Lunn 	if (type != hwmon_temp)
18950b04680fSAndrew Lunn 		return 0;
18960b04680fSAndrew Lunn 
18970b04680fSAndrew Lunn 	switch (attr) {
18980b04680fSAndrew Lunn 	case hwmon_temp_input:
18990b04680fSAndrew Lunn 	case hwmon_temp_max_alarm:
19000b04680fSAndrew Lunn 		return 0444;
19010b04680fSAndrew Lunn 	case hwmon_temp_crit:
19020b04680fSAndrew Lunn 		return 0644;
19030b04680fSAndrew Lunn 	default:
19040b04680fSAndrew Lunn 		return 0;
19050b04680fSAndrew Lunn 	}
19060b04680fSAndrew Lunn }
19070b04680fSAndrew Lunn 
19080b04680fSAndrew Lunn static u32 m88e1510_hwmon_temp_config[] = {
19090b04680fSAndrew Lunn 	HWMON_T_INPUT | HWMON_T_CRIT | HWMON_T_MAX_ALARM,
19100b04680fSAndrew Lunn 	0
19110b04680fSAndrew Lunn };
19120b04680fSAndrew Lunn 
19130b04680fSAndrew Lunn static const struct hwmon_channel_info m88e1510_hwmon_temp = {
19140b04680fSAndrew Lunn 	.type = hwmon_temp,
19150b04680fSAndrew Lunn 	.config = m88e1510_hwmon_temp_config,
19160b04680fSAndrew Lunn };
19170b04680fSAndrew Lunn 
19180b04680fSAndrew Lunn static const struct hwmon_channel_info *m88e1510_hwmon_info[] = {
19190b04680fSAndrew Lunn 	&m88e1121_hwmon_chip,
19200b04680fSAndrew Lunn 	&m88e1510_hwmon_temp,
19210b04680fSAndrew Lunn 	NULL
19220b04680fSAndrew Lunn };
19230b04680fSAndrew Lunn 
19240b04680fSAndrew Lunn static const struct hwmon_ops m88e1510_hwmon_hwmon_ops = {
19250b04680fSAndrew Lunn 	.is_visible = m88e1510_hwmon_is_visible,
19260b04680fSAndrew Lunn 	.read = m88e1510_hwmon_read,
19270b04680fSAndrew Lunn 	.write = m88e1510_hwmon_write,
19280b04680fSAndrew Lunn };
19290b04680fSAndrew Lunn 
19300b04680fSAndrew Lunn static const struct hwmon_chip_info m88e1510_hwmon_chip_info = {
19310b04680fSAndrew Lunn 	.ops = &m88e1510_hwmon_hwmon_ops,
19320b04680fSAndrew Lunn 	.info = m88e1510_hwmon_info,
19330b04680fSAndrew Lunn };
19340b04680fSAndrew Lunn 
1935fee2d546SAndrew Lunn static int m88e6390_get_temp(struct phy_device *phydev, long *temp)
1936fee2d546SAndrew Lunn {
1937fee2d546SAndrew Lunn 	int sum = 0;
1938fee2d546SAndrew Lunn 	int oldpage;
1939fee2d546SAndrew Lunn 	int ret = 0;
1940fee2d546SAndrew Lunn 	int i;
1941fee2d546SAndrew Lunn 
1942fee2d546SAndrew Lunn 	*temp = 0;
1943fee2d546SAndrew Lunn 
1944fee2d546SAndrew Lunn 	oldpage = phy_select_page(phydev, MII_MARVELL_MISC_TEST_PAGE);
1945fee2d546SAndrew Lunn 	if (oldpage < 0)
1946fee2d546SAndrew Lunn 		goto error;
1947fee2d546SAndrew Lunn 
1948fee2d546SAndrew Lunn 	/* Enable temperature sensor */
1949fee2d546SAndrew Lunn 	ret = __phy_read(phydev, MII_88E6390_MISC_TEST);
1950fee2d546SAndrew Lunn 	if (ret < 0)
1951fee2d546SAndrew Lunn 		goto error;
1952fee2d546SAndrew Lunn 
1953fee2d546SAndrew Lunn 	ret = ret & ~MII_88E6390_MISC_TEST_SAMPLE_MASK;
1954fee2d546SAndrew Lunn 	ret |= MII_88E6390_MISC_TEST_SAMPLE_ENABLE |
1955fee2d546SAndrew Lunn 		MII_88E6390_MISC_TEST_SAMPLE_1S;
1956fee2d546SAndrew Lunn 
1957fee2d546SAndrew Lunn 	ret = __phy_write(phydev, MII_88E6390_MISC_TEST, ret);
1958fee2d546SAndrew Lunn 	if (ret < 0)
1959fee2d546SAndrew Lunn 		goto error;
1960fee2d546SAndrew Lunn 
1961fee2d546SAndrew Lunn 	/* Wait for temperature to stabilize */
1962fee2d546SAndrew Lunn 	usleep_range(10000, 12000);
1963fee2d546SAndrew Lunn 
1964fee2d546SAndrew Lunn 	/* Reading the temperature sense has an errata. You need to read
1965fee2d546SAndrew Lunn 	 * a number of times and take an average.
1966fee2d546SAndrew Lunn 	 */
1967fee2d546SAndrew Lunn 	for (i = 0; i < MII_88E6390_TEMP_SENSOR_SAMPLES; i++) {
1968fee2d546SAndrew Lunn 		ret = __phy_read(phydev, MII_88E6390_TEMP_SENSOR);
1969fee2d546SAndrew Lunn 		if (ret < 0)
1970fee2d546SAndrew Lunn 			goto error;
1971fee2d546SAndrew Lunn 		sum += ret & MII_88E6390_TEMP_SENSOR_MASK;
1972fee2d546SAndrew Lunn 	}
1973fee2d546SAndrew Lunn 
1974fee2d546SAndrew Lunn 	sum /= MII_88E6390_TEMP_SENSOR_SAMPLES;
1975fee2d546SAndrew Lunn 	*temp = (sum  - 75) * 1000;
1976fee2d546SAndrew Lunn 
1977fee2d546SAndrew Lunn 	/* Disable temperature sensor */
1978fee2d546SAndrew Lunn 	ret = __phy_read(phydev, MII_88E6390_MISC_TEST);
1979fee2d546SAndrew Lunn 	if (ret < 0)
1980fee2d546SAndrew Lunn 		goto error;
1981fee2d546SAndrew Lunn 
1982fee2d546SAndrew Lunn 	ret = ret & ~MII_88E6390_MISC_TEST_SAMPLE_MASK;
1983fee2d546SAndrew Lunn 	ret |= MII_88E6390_MISC_TEST_SAMPLE_DISABLE;
1984fee2d546SAndrew Lunn 
1985fee2d546SAndrew Lunn 	ret = __phy_write(phydev, MII_88E6390_MISC_TEST, ret);
1986fee2d546SAndrew Lunn 
1987fee2d546SAndrew Lunn error:
1988fee2d546SAndrew Lunn 	phy_restore_page(phydev, oldpage, ret);
1989fee2d546SAndrew Lunn 
1990fee2d546SAndrew Lunn 	return ret;
1991fee2d546SAndrew Lunn }
1992fee2d546SAndrew Lunn 
1993fee2d546SAndrew Lunn static int m88e6390_hwmon_read(struct device *dev,
1994fee2d546SAndrew Lunn 			       enum hwmon_sensor_types type,
1995fee2d546SAndrew Lunn 			       u32 attr, int channel, long *temp)
1996fee2d546SAndrew Lunn {
1997fee2d546SAndrew Lunn 	struct phy_device *phydev = dev_get_drvdata(dev);
1998fee2d546SAndrew Lunn 	int err;
1999fee2d546SAndrew Lunn 
2000fee2d546SAndrew Lunn 	switch (attr) {
2001fee2d546SAndrew Lunn 	case hwmon_temp_input:
2002fee2d546SAndrew Lunn 		err = m88e6390_get_temp(phydev, temp);
2003fee2d546SAndrew Lunn 		break;
2004fee2d546SAndrew Lunn 	default:
2005fee2d546SAndrew Lunn 		return -EOPNOTSUPP;
2006fee2d546SAndrew Lunn 	}
2007fee2d546SAndrew Lunn 
2008fee2d546SAndrew Lunn 	return err;
2009fee2d546SAndrew Lunn }
2010fee2d546SAndrew Lunn 
2011fee2d546SAndrew Lunn static umode_t m88e6390_hwmon_is_visible(const void *data,
2012fee2d546SAndrew Lunn 					 enum hwmon_sensor_types type,
2013fee2d546SAndrew Lunn 					 u32 attr, int channel)
2014fee2d546SAndrew Lunn {
2015fee2d546SAndrew Lunn 	if (type != hwmon_temp)
2016fee2d546SAndrew Lunn 		return 0;
2017fee2d546SAndrew Lunn 
2018fee2d546SAndrew Lunn 	switch (attr) {
2019fee2d546SAndrew Lunn 	case hwmon_temp_input:
2020fee2d546SAndrew Lunn 		return 0444;
2021fee2d546SAndrew Lunn 	default:
2022fee2d546SAndrew Lunn 		return 0;
2023fee2d546SAndrew Lunn 	}
2024fee2d546SAndrew Lunn }
2025fee2d546SAndrew Lunn 
2026fee2d546SAndrew Lunn static u32 m88e6390_hwmon_temp_config[] = {
2027fee2d546SAndrew Lunn 	HWMON_T_INPUT,
2028fee2d546SAndrew Lunn 	0
2029fee2d546SAndrew Lunn };
2030fee2d546SAndrew Lunn 
2031fee2d546SAndrew Lunn static const struct hwmon_channel_info m88e6390_hwmon_temp = {
2032fee2d546SAndrew Lunn 	.type = hwmon_temp,
2033fee2d546SAndrew Lunn 	.config = m88e6390_hwmon_temp_config,
2034fee2d546SAndrew Lunn };
2035fee2d546SAndrew Lunn 
2036fee2d546SAndrew Lunn static const struct hwmon_channel_info *m88e6390_hwmon_info[] = {
2037fee2d546SAndrew Lunn 	&m88e1121_hwmon_chip,
2038fee2d546SAndrew Lunn 	&m88e6390_hwmon_temp,
2039fee2d546SAndrew Lunn 	NULL
2040fee2d546SAndrew Lunn };
2041fee2d546SAndrew Lunn 
2042fee2d546SAndrew Lunn static const struct hwmon_ops m88e6390_hwmon_hwmon_ops = {
2043fee2d546SAndrew Lunn 	.is_visible = m88e6390_hwmon_is_visible,
2044fee2d546SAndrew Lunn 	.read = m88e6390_hwmon_read,
2045fee2d546SAndrew Lunn };
2046fee2d546SAndrew Lunn 
2047fee2d546SAndrew Lunn static const struct hwmon_chip_info m88e6390_hwmon_chip_info = {
2048fee2d546SAndrew Lunn 	.ops = &m88e6390_hwmon_hwmon_ops,
2049fee2d546SAndrew Lunn 	.info = m88e6390_hwmon_info,
2050fee2d546SAndrew Lunn };
2051fee2d546SAndrew Lunn 
20520b04680fSAndrew Lunn static int marvell_hwmon_name(struct phy_device *phydev)
20530b04680fSAndrew Lunn {
20540b04680fSAndrew Lunn 	struct marvell_priv *priv = phydev->priv;
20550b04680fSAndrew Lunn 	struct device *dev = &phydev->mdio.dev;
20560b04680fSAndrew Lunn 	const char *devname = dev_name(dev);
20570b04680fSAndrew Lunn 	size_t len = strlen(devname);
20580b04680fSAndrew Lunn 	int i, j;
20590b04680fSAndrew Lunn 
20600b04680fSAndrew Lunn 	priv->hwmon_name = devm_kzalloc(dev, len, GFP_KERNEL);
20610b04680fSAndrew Lunn 	if (!priv->hwmon_name)
20620b04680fSAndrew Lunn 		return -ENOMEM;
20630b04680fSAndrew Lunn 
20640b04680fSAndrew Lunn 	for (i = j = 0; i < len && devname[i]; i++) {
20650b04680fSAndrew Lunn 		if (isalnum(devname[i]))
20660b04680fSAndrew Lunn 			priv->hwmon_name[j++] = devname[i];
20670b04680fSAndrew Lunn 	}
20680b04680fSAndrew Lunn 
20690b04680fSAndrew Lunn 	return 0;
20700b04680fSAndrew Lunn }
20710b04680fSAndrew Lunn 
20720b04680fSAndrew Lunn static int marvell_hwmon_probe(struct phy_device *phydev,
20730b04680fSAndrew Lunn 			       const struct hwmon_chip_info *chip)
20740b04680fSAndrew Lunn {
20750b04680fSAndrew Lunn 	struct marvell_priv *priv = phydev->priv;
20760b04680fSAndrew Lunn 	struct device *dev = &phydev->mdio.dev;
20770b04680fSAndrew Lunn 	int err;
20780b04680fSAndrew Lunn 
20790b04680fSAndrew Lunn 	err = marvell_hwmon_name(phydev);
20800b04680fSAndrew Lunn 	if (err)
20810b04680fSAndrew Lunn 		return err;
20820b04680fSAndrew Lunn 
20830b04680fSAndrew Lunn 	priv->hwmon_dev = devm_hwmon_device_register_with_info(
20840b04680fSAndrew Lunn 		dev, priv->hwmon_name, phydev, chip, NULL);
20850b04680fSAndrew Lunn 
20860b04680fSAndrew Lunn 	return PTR_ERR_OR_ZERO(priv->hwmon_dev);
20870b04680fSAndrew Lunn }
20880b04680fSAndrew Lunn 
20890b04680fSAndrew Lunn static int m88e1121_hwmon_probe(struct phy_device *phydev)
20900b04680fSAndrew Lunn {
20910b04680fSAndrew Lunn 	return marvell_hwmon_probe(phydev, &m88e1121_hwmon_chip_info);
20920b04680fSAndrew Lunn }
20930b04680fSAndrew Lunn 
20940b04680fSAndrew Lunn static int m88e1510_hwmon_probe(struct phy_device *phydev)
20950b04680fSAndrew Lunn {
20960b04680fSAndrew Lunn 	return marvell_hwmon_probe(phydev, &m88e1510_hwmon_chip_info);
20970b04680fSAndrew Lunn }
2098fee2d546SAndrew Lunn 
2099fee2d546SAndrew Lunn static int m88e6390_hwmon_probe(struct phy_device *phydev)
2100fee2d546SAndrew Lunn {
2101fee2d546SAndrew Lunn 	return marvell_hwmon_probe(phydev, &m88e6390_hwmon_chip_info);
2102fee2d546SAndrew Lunn }
21030b04680fSAndrew Lunn #else
21040b04680fSAndrew Lunn static int m88e1121_hwmon_probe(struct phy_device *phydev)
21050b04680fSAndrew Lunn {
21060b04680fSAndrew Lunn 	return 0;
21070b04680fSAndrew Lunn }
21080b04680fSAndrew Lunn 
21090b04680fSAndrew Lunn static int m88e1510_hwmon_probe(struct phy_device *phydev)
21100b04680fSAndrew Lunn {
21110b04680fSAndrew Lunn 	return 0;
21120b04680fSAndrew Lunn }
2113fee2d546SAndrew Lunn 
2114fee2d546SAndrew Lunn static int m88e6390_hwmon_probe(struct phy_device *phydev)
2115fee2d546SAndrew Lunn {
2116fee2d546SAndrew Lunn 	return 0;
2117fee2d546SAndrew Lunn }
21180b04680fSAndrew Lunn #endif
21190b04680fSAndrew Lunn 
2120d2fa47d9SAndrew Lunn static int marvell_probe(struct phy_device *phydev)
2121d2fa47d9SAndrew Lunn {
2122d2fa47d9SAndrew Lunn 	struct marvell_priv *priv;
2123d2fa47d9SAndrew Lunn 
2124e5a03bfdSAndrew Lunn 	priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL);
2125d2fa47d9SAndrew Lunn 	if (!priv)
2126d2fa47d9SAndrew Lunn 		return -ENOMEM;
2127d2fa47d9SAndrew Lunn 
2128d2fa47d9SAndrew Lunn 	phydev->priv = priv;
2129d2fa47d9SAndrew Lunn 
2130d2fa47d9SAndrew Lunn 	return 0;
2131d2fa47d9SAndrew Lunn }
2132d2fa47d9SAndrew Lunn 
21330b04680fSAndrew Lunn static int m88e1121_probe(struct phy_device *phydev)
21340b04680fSAndrew Lunn {
21350b04680fSAndrew Lunn 	int err;
21360b04680fSAndrew Lunn 
21370b04680fSAndrew Lunn 	err = marvell_probe(phydev);
21380b04680fSAndrew Lunn 	if (err)
21390b04680fSAndrew Lunn 		return err;
21400b04680fSAndrew Lunn 
21410b04680fSAndrew Lunn 	return m88e1121_hwmon_probe(phydev);
21420b04680fSAndrew Lunn }
21430b04680fSAndrew Lunn 
21440b04680fSAndrew Lunn static int m88e1510_probe(struct phy_device *phydev)
21450b04680fSAndrew Lunn {
21460b04680fSAndrew Lunn 	int err;
21470b04680fSAndrew Lunn 
21480b04680fSAndrew Lunn 	err = marvell_probe(phydev);
21490b04680fSAndrew Lunn 	if (err)
21500b04680fSAndrew Lunn 		return err;
21510b04680fSAndrew Lunn 
21520b04680fSAndrew Lunn 	return m88e1510_hwmon_probe(phydev);
21530b04680fSAndrew Lunn }
21540b04680fSAndrew Lunn 
2155fee2d546SAndrew Lunn static int m88e6390_probe(struct phy_device *phydev)
2156fee2d546SAndrew Lunn {
2157fee2d546SAndrew Lunn 	int err;
2158fee2d546SAndrew Lunn 
2159fee2d546SAndrew Lunn 	err = marvell_probe(phydev);
2160fee2d546SAndrew Lunn 	if (err)
2161fee2d546SAndrew Lunn 		return err;
2162fee2d546SAndrew Lunn 
2163fee2d546SAndrew Lunn 	return m88e6390_hwmon_probe(phydev);
2164fee2d546SAndrew Lunn }
2165fee2d546SAndrew Lunn 
2166e5479239SOlof Johansson static struct phy_driver marvell_drivers[] = {
2167e5479239SOlof Johansson 	{
21682f495c39SBenjamin Herrenschmidt 		.phy_id = MARVELL_PHY_ID_88E1101,
21692f495c39SBenjamin Herrenschmidt 		.phy_id_mask = MARVELL_PHY_ID_MASK,
217000db8189SAndy Fleming 		.name = "Marvell 88E1101",
2171dcdecdcfSHeiner Kallweit 		/* PHY_GBIT_FEATURES */
217218702414SArnd Bergmann 		.probe = marvell_probe,
217379be1a1cSClemens Gruber 		.config_init = &marvell_config_init,
2174f2899788SAndrew Lunn 		.config_aneg = &m88e1101_config_aneg,
217500db8189SAndy Fleming 		.ack_interrupt = &marvell_ack_interrupt,
217600db8189SAndy Fleming 		.config_intr = &marvell_config_intr,
21770898b448SSebastian Hesselbarth 		.resume = &genphy_resume,
21780898b448SSebastian Hesselbarth 		.suspend = &genphy_suspend,
2179424ca4c5SRussell King 		.read_page = marvell_read_page,
2180424ca4c5SRussell King 		.write_page = marvell_write_page,
2181d2fa47d9SAndrew Lunn 		.get_sset_count = marvell_get_sset_count,
2182d2fa47d9SAndrew Lunn 		.get_strings = marvell_get_strings,
2183d2fa47d9SAndrew Lunn 		.get_stats = marvell_get_stats,
2184e5479239SOlof Johansson 	},
2185e5479239SOlof Johansson 	{
21862f495c39SBenjamin Herrenschmidt 		.phy_id = MARVELL_PHY_ID_88E1112,
21872f495c39SBenjamin Herrenschmidt 		.phy_id_mask = MARVELL_PHY_ID_MASK,
218885cfb534SOlof Johansson 		.name = "Marvell 88E1112",
2189dcdecdcfSHeiner Kallweit 		/* PHY_GBIT_FEATURES */
2190d2fa47d9SAndrew Lunn 		.probe = marvell_probe,
219185cfb534SOlof Johansson 		.config_init = &m88e1111_config_init,
219285cfb534SOlof Johansson 		.config_aneg = &marvell_config_aneg,
219385cfb534SOlof Johansson 		.ack_interrupt = &marvell_ack_interrupt,
219485cfb534SOlof Johansson 		.config_intr = &marvell_config_intr,
21950898b448SSebastian Hesselbarth 		.resume = &genphy_resume,
21960898b448SSebastian Hesselbarth 		.suspend = &genphy_suspend,
2197424ca4c5SRussell King 		.read_page = marvell_read_page,
2198424ca4c5SRussell King 		.write_page = marvell_write_page,
2199d2fa47d9SAndrew Lunn 		.get_sset_count = marvell_get_sset_count,
2200d2fa47d9SAndrew Lunn 		.get_strings = marvell_get_strings,
2201d2fa47d9SAndrew Lunn 		.get_stats = marvell_get_stats,
2202262caf47SHeiner Kallweit 		.get_tunable = m88e1011_get_tunable,
2203262caf47SHeiner Kallweit 		.set_tunable = m88e1011_set_tunable,
2204262caf47SHeiner Kallweit 		.link_change_notify = m88e1011_link_change_notify,
220585cfb534SOlof Johansson 	},
220685cfb534SOlof Johansson 	{
22072f495c39SBenjamin Herrenschmidt 		.phy_id = MARVELL_PHY_ID_88E1111,
22082f495c39SBenjamin Herrenschmidt 		.phy_id_mask = MARVELL_PHY_ID_MASK,
220976884679SAndy Fleming 		.name = "Marvell 88E1111",
2210dcdecdcfSHeiner Kallweit 		/* PHY_GBIT_FEATURES */
2211d2fa47d9SAndrew Lunn 		.probe = marvell_probe,
2212e5479239SOlof Johansson 		.config_init = &m88e1111_config_init,
2213d6ab9336SFlorian Fainelli 		.config_aneg = &marvell_config_aneg,
2214be937f1fSAlexandr Smirnov 		.read_status = &marvell_read_status,
221576884679SAndy Fleming 		.ack_interrupt = &marvell_ack_interrupt,
221676884679SAndy Fleming 		.config_intr = &marvell_config_intr,
22170898b448SSebastian Hesselbarth 		.resume = &genphy_resume,
22180898b448SSebastian Hesselbarth 		.suspend = &genphy_suspend,
2219424ca4c5SRussell King 		.read_page = marvell_read_page,
2220424ca4c5SRussell King 		.write_page = marvell_write_page,
2221d2fa47d9SAndrew Lunn 		.get_sset_count = marvell_get_sset_count,
2222d2fa47d9SAndrew Lunn 		.get_strings = marvell_get_strings,
2223d2fa47d9SAndrew Lunn 		.get_stats = marvell_get_stats,
22245c6bc519SHeiner Kallweit 		.get_tunable = m88e1111_get_tunable,
22255c6bc519SHeiner Kallweit 		.set_tunable = m88e1111_set_tunable,
22265c6bc519SHeiner Kallweit 		.link_change_notify = m88e1011_link_change_notify,
2227e5479239SOlof Johansson 	},
2228e5479239SOlof Johansson 	{
22292f495c39SBenjamin Herrenschmidt 		.phy_id = MARVELL_PHY_ID_88E1118,
22302f495c39SBenjamin Herrenschmidt 		.phy_id_mask = MARVELL_PHY_ID_MASK,
2231605f196eSRon Madrid 		.name = "Marvell 88E1118",
2232dcdecdcfSHeiner Kallweit 		/* PHY_GBIT_FEATURES */
2233d2fa47d9SAndrew Lunn 		.probe = marvell_probe,
2234605f196eSRon Madrid 		.config_init = &m88e1118_config_init,
2235605f196eSRon Madrid 		.config_aneg = &m88e1118_config_aneg,
2236605f196eSRon Madrid 		.ack_interrupt = &marvell_ack_interrupt,
2237605f196eSRon Madrid 		.config_intr = &marvell_config_intr,
22380898b448SSebastian Hesselbarth 		.resume = &genphy_resume,
22390898b448SSebastian Hesselbarth 		.suspend = &genphy_suspend,
2240424ca4c5SRussell King 		.read_page = marvell_read_page,
2241424ca4c5SRussell King 		.write_page = marvell_write_page,
2242d2fa47d9SAndrew Lunn 		.get_sset_count = marvell_get_sset_count,
2243d2fa47d9SAndrew Lunn 		.get_strings = marvell_get_strings,
2244d2fa47d9SAndrew Lunn 		.get_stats = marvell_get_stats,
2245605f196eSRon Madrid 	},
2246605f196eSRon Madrid 	{
22472f495c39SBenjamin Herrenschmidt 		.phy_id = MARVELL_PHY_ID_88E1121R,
22482f495c39SBenjamin Herrenschmidt 		.phy_id_mask = MARVELL_PHY_ID_MASK,
2249140bc929SSergei Poselenov 		.name = "Marvell 88E1121R",
2250dcdecdcfSHeiner Kallweit 		/* PHY_GBIT_FEATURES */
225118702414SArnd Bergmann 		.probe = &m88e1121_probe,
225207777246SWang Dongsheng 		.config_init = &marvell_config_init,
2253140bc929SSergei Poselenov 		.config_aneg = &m88e1121_config_aneg,
2254140bc929SSergei Poselenov 		.read_status = &marvell_read_status,
2255140bc929SSergei Poselenov 		.ack_interrupt = &marvell_ack_interrupt,
2256140bc929SSergei Poselenov 		.config_intr = &marvell_config_intr,
2257dcd07be3SAnatolij Gustschin 		.did_interrupt = &m88e1121_did_interrupt,
22580898b448SSebastian Hesselbarth 		.resume = &genphy_resume,
22590898b448SSebastian Hesselbarth 		.suspend = &genphy_suspend,
2260424ca4c5SRussell King 		.read_page = marvell_read_page,
2261424ca4c5SRussell King 		.write_page = marvell_write_page,
2262d2fa47d9SAndrew Lunn 		.get_sset_count = marvell_get_sset_count,
2263d2fa47d9SAndrew Lunn 		.get_strings = marvell_get_strings,
2264d2fa47d9SAndrew Lunn 		.get_stats = marvell_get_stats,
2265911af5e1SHeiner Kallweit 		.get_tunable = m88e1011_get_tunable,
2266911af5e1SHeiner Kallweit 		.set_tunable = m88e1011_set_tunable,
2267911af5e1SHeiner Kallweit 		.link_change_notify = m88e1011_link_change_notify,
2268140bc929SSergei Poselenov 	},
2269140bc929SSergei Poselenov 	{
2270337ac9d5SCyril Chemparathy 		.phy_id = MARVELL_PHY_ID_88E1318S,
22716ba74014SLinus Torvalds 		.phy_id_mask = MARVELL_PHY_ID_MASK,
2272337ac9d5SCyril Chemparathy 		.name = "Marvell 88E1318S",
2273dcdecdcfSHeiner Kallweit 		/* PHY_GBIT_FEATURES */
2274d2fa47d9SAndrew Lunn 		.probe = marvell_probe,
2275dd9a122aSEsben Haabendal 		.config_init = &m88e1318_config_init,
2276337ac9d5SCyril Chemparathy 		.config_aneg = &m88e1318_config_aneg,
22773ff1c259SCyril Chemparathy 		.read_status = &marvell_read_status,
22783ff1c259SCyril Chemparathy 		.ack_interrupt = &marvell_ack_interrupt,
22793ff1c259SCyril Chemparathy 		.config_intr = &marvell_config_intr,
22803ff1c259SCyril Chemparathy 		.did_interrupt = &m88e1121_did_interrupt,
22813871c387SMichael Stapelberg 		.get_wol = &m88e1318_get_wol,
22823871c387SMichael Stapelberg 		.set_wol = &m88e1318_set_wol,
22830898b448SSebastian Hesselbarth 		.resume = &genphy_resume,
22840898b448SSebastian Hesselbarth 		.suspend = &genphy_suspend,
2285424ca4c5SRussell King 		.read_page = marvell_read_page,
2286424ca4c5SRussell King 		.write_page = marvell_write_page,
2287d2fa47d9SAndrew Lunn 		.get_sset_count = marvell_get_sset_count,
2288d2fa47d9SAndrew Lunn 		.get_strings = marvell_get_strings,
2289d2fa47d9SAndrew Lunn 		.get_stats = marvell_get_stats,
22903ff1c259SCyril Chemparathy 	},
22913ff1c259SCyril Chemparathy 	{
22922f495c39SBenjamin Herrenschmidt 		.phy_id = MARVELL_PHY_ID_88E1145,
22932f495c39SBenjamin Herrenschmidt 		.phy_id_mask = MARVELL_PHY_ID_MASK,
229476884679SAndy Fleming 		.name = "Marvell 88E1145",
2295dcdecdcfSHeiner Kallweit 		/* PHY_GBIT_FEATURES */
2296d2fa47d9SAndrew Lunn 		.probe = marvell_probe,
229776884679SAndy Fleming 		.config_init = &m88e1145_config_init,
2298c505873eSZhao Qiang 		.config_aneg = &m88e1101_config_aneg,
229976884679SAndy Fleming 		.read_status = &genphy_read_status,
230076884679SAndy Fleming 		.ack_interrupt = &marvell_ack_interrupt,
230176884679SAndy Fleming 		.config_intr = &marvell_config_intr,
23020898b448SSebastian Hesselbarth 		.resume = &genphy_resume,
23030898b448SSebastian Hesselbarth 		.suspend = &genphy_suspend,
2304424ca4c5SRussell King 		.read_page = marvell_read_page,
2305424ca4c5SRussell King 		.write_page = marvell_write_page,
2306d2fa47d9SAndrew Lunn 		.get_sset_count = marvell_get_sset_count,
2307d2fa47d9SAndrew Lunn 		.get_strings = marvell_get_strings,
2308d2fa47d9SAndrew Lunn 		.get_stats = marvell_get_stats,
2309a319fb52SHeiner Kallweit 		.get_tunable = m88e1111_get_tunable,
2310a319fb52SHeiner Kallweit 		.set_tunable = m88e1111_set_tunable,
2311a319fb52SHeiner Kallweit 		.link_change_notify = m88e1011_link_change_notify,
2312ac8c635aSOlof Johansson 	},
2313ac8c635aSOlof Johansson 	{
231490600732SDavid Daney 		.phy_id = MARVELL_PHY_ID_88E1149R,
231590600732SDavid Daney 		.phy_id_mask = MARVELL_PHY_ID_MASK,
231690600732SDavid Daney 		.name = "Marvell 88E1149R",
2317dcdecdcfSHeiner Kallweit 		/* PHY_GBIT_FEATURES */
2318d2fa47d9SAndrew Lunn 		.probe = marvell_probe,
231990600732SDavid Daney 		.config_init = &m88e1149_config_init,
232090600732SDavid Daney 		.config_aneg = &m88e1118_config_aneg,
232190600732SDavid Daney 		.ack_interrupt = &marvell_ack_interrupt,
232290600732SDavid Daney 		.config_intr = &marvell_config_intr,
23230898b448SSebastian Hesselbarth 		.resume = &genphy_resume,
23240898b448SSebastian Hesselbarth 		.suspend = &genphy_suspend,
2325424ca4c5SRussell King 		.read_page = marvell_read_page,
2326424ca4c5SRussell King 		.write_page = marvell_write_page,
2327d2fa47d9SAndrew Lunn 		.get_sset_count = marvell_get_sset_count,
2328d2fa47d9SAndrew Lunn 		.get_strings = marvell_get_strings,
2329d2fa47d9SAndrew Lunn 		.get_stats = marvell_get_stats,
233090600732SDavid Daney 	},
233190600732SDavid Daney 	{
23322f495c39SBenjamin Herrenschmidt 		.phy_id = MARVELL_PHY_ID_88E1240,
23332f495c39SBenjamin Herrenschmidt 		.phy_id_mask = MARVELL_PHY_ID_MASK,
2334ac8c635aSOlof Johansson 		.name = "Marvell 88E1240",
2335dcdecdcfSHeiner Kallweit 		/* PHY_GBIT_FEATURES */
2336d2fa47d9SAndrew Lunn 		.probe = marvell_probe,
2337ac8c635aSOlof Johansson 		.config_init = &m88e1111_config_init,
2338ac8c635aSOlof Johansson 		.config_aneg = &marvell_config_aneg,
2339ac8c635aSOlof Johansson 		.ack_interrupt = &marvell_ack_interrupt,
2340ac8c635aSOlof Johansson 		.config_intr = &marvell_config_intr,
23410898b448SSebastian Hesselbarth 		.resume = &genphy_resume,
23420898b448SSebastian Hesselbarth 		.suspend = &genphy_suspend,
2343424ca4c5SRussell King 		.read_page = marvell_read_page,
2344424ca4c5SRussell King 		.write_page = marvell_write_page,
2345d2fa47d9SAndrew Lunn 		.get_sset_count = marvell_get_sset_count,
2346d2fa47d9SAndrew Lunn 		.get_strings = marvell_get_strings,
2347d2fa47d9SAndrew Lunn 		.get_stats = marvell_get_stats,
2348ac8c635aSOlof Johansson 	},
23493da09a51SMichal Simek 	{
23503da09a51SMichal Simek 		.phy_id = MARVELL_PHY_ID_88E1116R,
23513da09a51SMichal Simek 		.phy_id_mask = MARVELL_PHY_ID_MASK,
23523da09a51SMichal Simek 		.name = "Marvell 88E1116R",
2353dcdecdcfSHeiner Kallweit 		/* PHY_GBIT_FEATURES */
2354d2fa47d9SAndrew Lunn 		.probe = marvell_probe,
23553da09a51SMichal Simek 		.config_init = &m88e1116r_config_init,
23563da09a51SMichal Simek 		.ack_interrupt = &marvell_ack_interrupt,
23573da09a51SMichal Simek 		.config_intr = &marvell_config_intr,
23580898b448SSebastian Hesselbarth 		.resume = &genphy_resume,
23590898b448SSebastian Hesselbarth 		.suspend = &genphy_suspend,
2360424ca4c5SRussell King 		.read_page = marvell_read_page,
2361424ca4c5SRussell King 		.write_page = marvell_write_page,
2362d2fa47d9SAndrew Lunn 		.get_sset_count = marvell_get_sset_count,
2363d2fa47d9SAndrew Lunn 		.get_strings = marvell_get_strings,
2364d2fa47d9SAndrew Lunn 		.get_stats = marvell_get_stats,
2365262caf47SHeiner Kallweit 		.get_tunable = m88e1011_get_tunable,
2366262caf47SHeiner Kallweit 		.set_tunable = m88e1011_set_tunable,
2367262caf47SHeiner Kallweit 		.link_change_notify = m88e1011_link_change_notify,
23683da09a51SMichal Simek 	},
236910e24caaSMichal Simek 	{
237010e24caaSMichal Simek 		.phy_id = MARVELL_PHY_ID_88E1510,
237110e24caaSMichal Simek 		.phy_id_mask = MARVELL_PHY_ID_MASK,
237210e24caaSMichal Simek 		.name = "Marvell 88E1510",
2373719655a1SAndrew Lunn 		.features = PHY_GBIT_FIBRE_FEATURES,
23740b04680fSAndrew Lunn 		.probe = &m88e1510_probe,
2375930b37eeSStefan Roese 		.config_init = &m88e1510_config_init,
237610e24caaSMichal Simek 		.config_aneg = &m88e1510_config_aneg,
237710e24caaSMichal Simek 		.read_status = &marvell_read_status,
237810e24caaSMichal Simek 		.ack_interrupt = &marvell_ack_interrupt,
237910e24caaSMichal Simek 		.config_intr = &marvell_config_intr,
238010e24caaSMichal Simek 		.did_interrupt = &m88e1121_did_interrupt,
2381f39aac7eSJingju Hou 		.get_wol = &m88e1318_get_wol,
2382f39aac7eSJingju Hou 		.set_wol = &m88e1318_set_wol,
23833758be3dSCharles-Antoine Couret 		.resume = &marvell_resume,
23843758be3dSCharles-Antoine Couret 		.suspend = &marvell_suspend,
2385424ca4c5SRussell King 		.read_page = marvell_read_page,
2386424ca4c5SRussell King 		.write_page = marvell_write_page,
2387d2fa47d9SAndrew Lunn 		.get_sset_count = marvell_get_sset_count,
2388d2fa47d9SAndrew Lunn 		.get_strings = marvell_get_strings,
2389d2fa47d9SAndrew Lunn 		.get_stats = marvell_get_stats,
2390f0f9b4edSLin Yun Sheng 		.set_loopback = genphy_loopback,
2391262caf47SHeiner Kallweit 		.get_tunable = m88e1011_get_tunable,
2392262caf47SHeiner Kallweit 		.set_tunable = m88e1011_set_tunable,
2393262caf47SHeiner Kallweit 		.link_change_notify = m88e1011_link_change_notify,
239410e24caaSMichal Simek 	},
23956b358aedSSebastian Hesselbarth 	{
2396819ec8e1SAndrew Lunn 		.phy_id = MARVELL_PHY_ID_88E1540,
2397819ec8e1SAndrew Lunn 		.phy_id_mask = MARVELL_PHY_ID_MASK,
2398819ec8e1SAndrew Lunn 		.name = "Marvell 88E1540",
2399dcdecdcfSHeiner Kallweit 		/* PHY_GBIT_FEATURES */
240018702414SArnd Bergmann 		.probe = m88e1510_probe,
240179be1a1cSClemens Gruber 		.config_init = &marvell_config_init,
2402819ec8e1SAndrew Lunn 		.config_aneg = &m88e1510_config_aneg,
2403819ec8e1SAndrew Lunn 		.read_status = &marvell_read_status,
2404819ec8e1SAndrew Lunn 		.ack_interrupt = &marvell_ack_interrupt,
2405819ec8e1SAndrew Lunn 		.config_intr = &marvell_config_intr,
2406819ec8e1SAndrew Lunn 		.did_interrupt = &m88e1121_did_interrupt,
2407819ec8e1SAndrew Lunn 		.resume = &genphy_resume,
2408819ec8e1SAndrew Lunn 		.suspend = &genphy_suspend,
2409424ca4c5SRussell King 		.read_page = marvell_read_page,
2410424ca4c5SRussell King 		.write_page = marvell_write_page,
2411d2fa47d9SAndrew Lunn 		.get_sset_count = marvell_get_sset_count,
2412d2fa47d9SAndrew Lunn 		.get_strings = marvell_get_strings,
2413d2fa47d9SAndrew Lunn 		.get_stats = marvell_get_stats,
241469f42be8SHeiner Kallweit 		.get_tunable = m88e1540_get_tunable,
241569f42be8SHeiner Kallweit 		.set_tunable = m88e1540_set_tunable,
2416911af5e1SHeiner Kallweit 		.link_change_notify = m88e1011_link_change_notify,
2417819ec8e1SAndrew Lunn 	},
2418819ec8e1SAndrew Lunn 	{
241960f06fdeSAndrew Lunn 		.phy_id = MARVELL_PHY_ID_88E1545,
242060f06fdeSAndrew Lunn 		.phy_id_mask = MARVELL_PHY_ID_MASK,
242160f06fdeSAndrew Lunn 		.name = "Marvell 88E1545",
242260f06fdeSAndrew Lunn 		.probe = m88e1510_probe,
2423dcdecdcfSHeiner Kallweit 		/* PHY_GBIT_FEATURES */
242460f06fdeSAndrew Lunn 		.config_init = &marvell_config_init,
242560f06fdeSAndrew Lunn 		.config_aneg = &m88e1510_config_aneg,
242660f06fdeSAndrew Lunn 		.read_status = &marvell_read_status,
242760f06fdeSAndrew Lunn 		.ack_interrupt = &marvell_ack_interrupt,
242860f06fdeSAndrew Lunn 		.config_intr = &marvell_config_intr,
242960f06fdeSAndrew Lunn 		.did_interrupt = &m88e1121_did_interrupt,
243060f06fdeSAndrew Lunn 		.resume = &genphy_resume,
243160f06fdeSAndrew Lunn 		.suspend = &genphy_suspend,
2432424ca4c5SRussell King 		.read_page = marvell_read_page,
2433424ca4c5SRussell King 		.write_page = marvell_write_page,
243460f06fdeSAndrew Lunn 		.get_sset_count = marvell_get_sset_count,
243560f06fdeSAndrew Lunn 		.get_strings = marvell_get_strings,
243660f06fdeSAndrew Lunn 		.get_stats = marvell_get_stats,
2437262caf47SHeiner Kallweit 		.get_tunable = m88e1540_get_tunable,
2438262caf47SHeiner Kallweit 		.set_tunable = m88e1540_set_tunable,
2439262caf47SHeiner Kallweit 		.link_change_notify = m88e1011_link_change_notify,
244060f06fdeSAndrew Lunn 	},
244160f06fdeSAndrew Lunn 	{
24426b358aedSSebastian Hesselbarth 		.phy_id = MARVELL_PHY_ID_88E3016,
24436b358aedSSebastian Hesselbarth 		.phy_id_mask = MARVELL_PHY_ID_MASK,
24446b358aedSSebastian Hesselbarth 		.name = "Marvell 88E3016",
2445dcdecdcfSHeiner Kallweit 		/* PHY_BASIC_FEATURES */
2446d2fa47d9SAndrew Lunn 		.probe = marvell_probe,
24476b358aedSSebastian Hesselbarth 		.config_init = &m88e3016_config_init,
24486b358aedSSebastian Hesselbarth 		.aneg_done = &marvell_aneg_done,
24496b358aedSSebastian Hesselbarth 		.read_status = &marvell_read_status,
24506b358aedSSebastian Hesselbarth 		.ack_interrupt = &marvell_ack_interrupt,
24516b358aedSSebastian Hesselbarth 		.config_intr = &marvell_config_intr,
24526b358aedSSebastian Hesselbarth 		.did_interrupt = &m88e1121_did_interrupt,
24536b358aedSSebastian Hesselbarth 		.resume = &genphy_resume,
24546b358aedSSebastian Hesselbarth 		.suspend = &genphy_suspend,
2455424ca4c5SRussell King 		.read_page = marvell_read_page,
2456424ca4c5SRussell King 		.write_page = marvell_write_page,
2457d2fa47d9SAndrew Lunn 		.get_sset_count = marvell_get_sset_count,
2458d2fa47d9SAndrew Lunn 		.get_strings = marvell_get_strings,
2459d2fa47d9SAndrew Lunn 		.get_stats = marvell_get_stats,
24606b358aedSSebastian Hesselbarth 	},
2461e4cf8a38SAndrew Lunn 	{
2462e4cf8a38SAndrew Lunn 		.phy_id = MARVELL_PHY_ID_88E6390,
2463e4cf8a38SAndrew Lunn 		.phy_id_mask = MARVELL_PHY_ID_MASK,
2464e4cf8a38SAndrew Lunn 		.name = "Marvell 88E6390",
2465dcdecdcfSHeiner Kallweit 		/* PHY_GBIT_FEATURES */
2466fee2d546SAndrew Lunn 		.probe = m88e6390_probe,
2467e4cf8a38SAndrew Lunn 		.config_init = &marvell_config_init,
24688cbcdc1aSAndrew Lunn 		.config_aneg = &m88e6390_config_aneg,
2469e4cf8a38SAndrew Lunn 		.read_status = &marvell_read_status,
2470e4cf8a38SAndrew Lunn 		.ack_interrupt = &marvell_ack_interrupt,
2471e4cf8a38SAndrew Lunn 		.config_intr = &marvell_config_intr,
2472e4cf8a38SAndrew Lunn 		.did_interrupt = &m88e1121_did_interrupt,
2473e4cf8a38SAndrew Lunn 		.resume = &genphy_resume,
2474e4cf8a38SAndrew Lunn 		.suspend = &genphy_suspend,
2475424ca4c5SRussell King 		.read_page = marvell_read_page,
2476424ca4c5SRussell King 		.write_page = marvell_write_page,
2477e4cf8a38SAndrew Lunn 		.get_sset_count = marvell_get_sset_count,
2478e4cf8a38SAndrew Lunn 		.get_strings = marvell_get_strings,
2479e4cf8a38SAndrew Lunn 		.get_stats = marvell_get_stats,
248069f42be8SHeiner Kallweit 		.get_tunable = m88e1540_get_tunable,
248169f42be8SHeiner Kallweit 		.set_tunable = m88e1540_set_tunable,
2482911af5e1SHeiner Kallweit 		.link_change_notify = m88e1011_link_change_notify,
2483e4cf8a38SAndrew Lunn 	},
248476884679SAndy Fleming };
248576884679SAndy Fleming 
248650fd7150SJohan Hovold module_phy_driver(marvell_drivers);
24874e4f10f6SDavid Woodhouse 
2488cf93c945SUwe Kleine-König static struct mdio_device_id __maybe_unused marvell_tbl[] = {
2489f5e1cabfSMichal Simek 	{ MARVELL_PHY_ID_88E1101, MARVELL_PHY_ID_MASK },
2490f5e1cabfSMichal Simek 	{ MARVELL_PHY_ID_88E1112, MARVELL_PHY_ID_MASK },
2491f5e1cabfSMichal Simek 	{ MARVELL_PHY_ID_88E1111, MARVELL_PHY_ID_MASK },
2492f5e1cabfSMichal Simek 	{ MARVELL_PHY_ID_88E1118, MARVELL_PHY_ID_MASK },
2493f5e1cabfSMichal Simek 	{ MARVELL_PHY_ID_88E1121R, MARVELL_PHY_ID_MASK },
2494f5e1cabfSMichal Simek 	{ MARVELL_PHY_ID_88E1145, MARVELL_PHY_ID_MASK },
2495f5e1cabfSMichal Simek 	{ MARVELL_PHY_ID_88E1149R, MARVELL_PHY_ID_MASK },
2496f5e1cabfSMichal Simek 	{ MARVELL_PHY_ID_88E1240, MARVELL_PHY_ID_MASK },
2497f5e1cabfSMichal Simek 	{ MARVELL_PHY_ID_88E1318S, MARVELL_PHY_ID_MASK },
24983da09a51SMichal Simek 	{ MARVELL_PHY_ID_88E1116R, MARVELL_PHY_ID_MASK },
249910e24caaSMichal Simek 	{ MARVELL_PHY_ID_88E1510, MARVELL_PHY_ID_MASK },
2500819ec8e1SAndrew Lunn 	{ MARVELL_PHY_ID_88E1540, MARVELL_PHY_ID_MASK },
250160f06fdeSAndrew Lunn 	{ MARVELL_PHY_ID_88E1545, MARVELL_PHY_ID_MASK },
25026b358aedSSebastian Hesselbarth 	{ MARVELL_PHY_ID_88E3016, MARVELL_PHY_ID_MASK },
2503e4cf8a38SAndrew Lunn 	{ MARVELL_PHY_ID_88E6390, MARVELL_PHY_ID_MASK },
25044e4f10f6SDavid Woodhouse 	{ }
25054e4f10f6SDavid Woodhouse };
25064e4f10f6SDavid Woodhouse 
25074e4f10f6SDavid Woodhouse MODULE_DEVICE_TABLE(mdio, marvell_tbl);
2508