xref: /openbmc/linux/drivers/net/phy/marvell.c (revision 78301ebe)
100db8189SAndy Fleming /*
200db8189SAndy Fleming  * drivers/net/phy/marvell.c
300db8189SAndy Fleming  *
400db8189SAndy Fleming  * Driver for Marvell PHYs
500db8189SAndy Fleming  *
600db8189SAndy Fleming  * Author: Andy Fleming
700db8189SAndy Fleming  *
800db8189SAndy Fleming  * Copyright (c) 2004 Freescale Semiconductor, Inc.
900db8189SAndy Fleming  *
103871c387SMichael Stapelberg  * Copyright (c) 2013 Michael Stapelberg <michael@stapelberg.de>
113871c387SMichael Stapelberg  *
1200db8189SAndy Fleming  * This program is free software; you can redistribute  it and/or modify it
1300db8189SAndy Fleming  * under  the terms of  the GNU General  Public License as published by the
1400db8189SAndy Fleming  * Free Software Foundation;  either version 2 of the  License, or (at your
1500db8189SAndy Fleming  * option) any later version.
1600db8189SAndy Fleming  *
1700db8189SAndy Fleming  */
1800db8189SAndy Fleming #include <linux/kernel.h>
1900db8189SAndy Fleming #include <linux/string.h>
2000db8189SAndy Fleming #include <linux/errno.h>
2100db8189SAndy Fleming #include <linux/unistd.h>
2200db8189SAndy Fleming #include <linux/interrupt.h>
2300db8189SAndy Fleming #include <linux/init.h>
2400db8189SAndy Fleming #include <linux/delay.h>
2500db8189SAndy Fleming #include <linux/netdevice.h>
2600db8189SAndy Fleming #include <linux/etherdevice.h>
2700db8189SAndy Fleming #include <linux/skbuff.h>
2800db8189SAndy Fleming #include <linux/spinlock.h>
2900db8189SAndy Fleming #include <linux/mm.h>
3000db8189SAndy Fleming #include <linux/module.h>
3100db8189SAndy Fleming #include <linux/mii.h>
3200db8189SAndy Fleming #include <linux/ethtool.h>
3300db8189SAndy Fleming #include <linux/phy.h>
342f495c39SBenjamin Herrenschmidt #include <linux/marvell_phy.h>
35cf41a51dSDavid Daney #include <linux/of.h>
3600db8189SAndy Fleming 
37eea3b201SAvinash Kumar #include <linux/io.h>
3800db8189SAndy Fleming #include <asm/irq.h>
39eea3b201SAvinash Kumar #include <linux/uaccess.h>
4000db8189SAndy Fleming 
4127d916d6SDavid Daney #define MII_MARVELL_PHY_PAGE		22
4227d916d6SDavid Daney 
4300db8189SAndy Fleming #define MII_M1011_IEVENT		0x13
4400db8189SAndy Fleming #define MII_M1011_IEVENT_CLEAR		0x0000
4500db8189SAndy Fleming 
4600db8189SAndy Fleming #define MII_M1011_IMASK			0x12
4700db8189SAndy Fleming #define MII_M1011_IMASK_INIT		0x6400
4800db8189SAndy Fleming #define MII_M1011_IMASK_CLEAR		0x0000
4900db8189SAndy Fleming 
5076884679SAndy Fleming #define MII_M1011_PHY_SCR		0x10
51239aa55bSDavid Thomson #define MII_M1011_PHY_SCR_MDI		0x0000
52239aa55bSDavid Thomson #define MII_M1011_PHY_SCR_MDI_X		0x0020
5376884679SAndy Fleming #define MII_M1011_PHY_SCR_AUTO_CROSS	0x0060
5476884679SAndy Fleming 
5507151bc9SMadalin Bucur #define MII_M1145_PHY_EXT_ADDR_PAGE	0x16
56b0224175SViet Nga Dao #define MII_M1145_PHY_EXT_SR		0x1b
5776884679SAndy Fleming #define MII_M1145_PHY_EXT_CR		0x14
5876884679SAndy Fleming #define MII_M1145_RGMII_RX_DELAY	0x0080
5976884679SAndy Fleming #define MII_M1145_RGMII_TX_DELAY	0x0002
60b0224175SViet Nga Dao #define MII_M1145_HWCFG_MODE_SGMII_NO_CLK	0x4
61b0224175SViet Nga Dao #define MII_M1145_HWCFG_MODE_MASK		0xf
62b0224175SViet Nga Dao #define MII_M1145_HWCFG_FIBER_COPPER_AUTO	0x8000
6376884679SAndy Fleming 
6499d881f9SVince Bridgers #define MII_M1145_HWCFG_MODE_SGMII_NO_CLK	0x4
6599d881f9SVince Bridgers #define MII_M1145_HWCFG_MODE_MASK		0xf
6699d881f9SVince Bridgers #define MII_M1145_HWCFG_FIBER_COPPER_AUTO	0x8000
6799d881f9SVince Bridgers 
6876884679SAndy Fleming #define MII_M1111_PHY_LED_CONTROL	0x18
6976884679SAndy Fleming #define MII_M1111_PHY_LED_DIRECT	0x4100
7076884679SAndy Fleming #define MII_M1111_PHY_LED_COMBINE	0x411c
71895ee682SKim Phillips #define MII_M1111_PHY_EXT_CR		0x14
72895ee682SKim Phillips #define MII_M1111_RX_DELAY		0x80
73895ee682SKim Phillips #define MII_M1111_TX_DELAY		0x2
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_COPPER_RGMII	0xb
78be937f1fSAlexandr Smirnov #define MII_M1111_HWCFG_MODE_FIBER_RGMII	0x3
794117b5beSKapil Juneja #define MII_M1111_HWCFG_MODE_SGMII_NO_CLK	0x4
805f8cbc13SLiu Yu-B13201 #define MII_M1111_HWCFG_MODE_COPPER_RTBI	0x9
81be937f1fSAlexandr Smirnov #define MII_M1111_HWCFG_FIBER_COPPER_AUTO	0x8000
82be937f1fSAlexandr Smirnov #define MII_M1111_HWCFG_FIBER_COPPER_RES	0x2000
83be937f1fSAlexandr Smirnov 
84be937f1fSAlexandr Smirnov #define MII_M1111_COPPER		0
85be937f1fSAlexandr Smirnov #define MII_M1111_FIBER			1
86be937f1fSAlexandr Smirnov 
87c477d044SCyril Chemparathy #define MII_88E1121_PHY_MSCR_PAGE	2
88c477d044SCyril Chemparathy #define MII_88E1121_PHY_MSCR_REG	21
89c477d044SCyril Chemparathy #define MII_88E1121_PHY_MSCR_RX_DELAY	BIT(5)
90c477d044SCyril Chemparathy #define MII_88E1121_PHY_MSCR_TX_DELAY	BIT(4)
91c477d044SCyril Chemparathy #define MII_88E1121_PHY_MSCR_DELAY_MASK	(~(0x3 << 4))
92c477d044SCyril Chemparathy 
93337ac9d5SCyril Chemparathy #define MII_88E1318S_PHY_MSCR1_REG	16
94337ac9d5SCyril Chemparathy #define MII_88E1318S_PHY_MSCR1_PAD_ODD	BIT(6)
953ff1c259SCyril Chemparathy 
963871c387SMichael Stapelberg /* Copper Specific Interrupt Enable Register */
973871c387SMichael Stapelberg #define MII_88E1318S_PHY_CSIER                              0x12
983871c387SMichael Stapelberg /* WOL Event Interrupt Enable */
993871c387SMichael Stapelberg #define MII_88E1318S_PHY_CSIER_WOL_EIE                      BIT(7)
1003871c387SMichael Stapelberg 
1013871c387SMichael Stapelberg /* LED Timer Control Register */
1023871c387SMichael Stapelberg #define MII_88E1318S_PHY_LED_PAGE                           0x03
1033871c387SMichael Stapelberg #define MII_88E1318S_PHY_LED_TCR                            0x12
1043871c387SMichael Stapelberg #define MII_88E1318S_PHY_LED_TCR_FORCE_INT                  BIT(15)
1053871c387SMichael Stapelberg #define MII_88E1318S_PHY_LED_TCR_INTn_ENABLE                BIT(7)
1063871c387SMichael Stapelberg #define MII_88E1318S_PHY_LED_TCR_INT_ACTIVE_LOW             BIT(11)
1073871c387SMichael Stapelberg 
1083871c387SMichael Stapelberg /* Magic Packet MAC address registers */
1093871c387SMichael Stapelberg #define MII_88E1318S_PHY_MAGIC_PACKET_WORD2                 0x17
1103871c387SMichael Stapelberg #define MII_88E1318S_PHY_MAGIC_PACKET_WORD1                 0x18
1113871c387SMichael Stapelberg #define MII_88E1318S_PHY_MAGIC_PACKET_WORD0                 0x19
1123871c387SMichael Stapelberg 
1133871c387SMichael Stapelberg #define MII_88E1318S_PHY_WOL_PAGE                           0x11
1143871c387SMichael Stapelberg #define MII_88E1318S_PHY_WOL_CTRL                           0x10
1153871c387SMichael Stapelberg #define MII_88E1318S_PHY_WOL_CTRL_CLEAR_WOL_STATUS          BIT(12)
1163871c387SMichael Stapelberg #define MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE BIT(14)
1173871c387SMichael Stapelberg 
118140bc929SSergei Poselenov #define MII_88E1121_PHY_LED_CTRL	16
119140bc929SSergei Poselenov #define MII_88E1121_PHY_LED_PAGE	3
120140bc929SSergei Poselenov #define MII_88E1121_PHY_LED_DEF		0x0030
121140bc929SSergei Poselenov 
122be937f1fSAlexandr Smirnov #define MII_M1011_PHY_STATUS		0x11
123be937f1fSAlexandr Smirnov #define MII_M1011_PHY_STATUS_1000	0x8000
124be937f1fSAlexandr Smirnov #define MII_M1011_PHY_STATUS_100	0x4000
125be937f1fSAlexandr Smirnov #define MII_M1011_PHY_STATUS_SPD_MASK	0xc000
126be937f1fSAlexandr Smirnov #define MII_M1011_PHY_STATUS_FULLDUPLEX	0x2000
127be937f1fSAlexandr Smirnov #define MII_M1011_PHY_STATUS_RESOLVED	0x0800
128be937f1fSAlexandr Smirnov #define MII_M1011_PHY_STATUS_LINK	0x0400
129be937f1fSAlexandr Smirnov 
1303da09a51SMichal Simek #define MII_M1116R_CONTROL_REG_MAC	21
1313da09a51SMichal Simek 
1326b358aedSSebastian Hesselbarth #define MII_88E3016_PHY_SPEC_CTRL	0x10
1336b358aedSSebastian Hesselbarth #define MII_88E3016_DISABLE_SCRAMBLER	0x0200
1346b358aedSSebastian Hesselbarth #define MII_88E3016_AUTO_MDIX_CROSSOVER	0x0030
13576884679SAndy Fleming 
136930b37eeSStefan Roese #define MII_88E1510_GEN_CTRL_REG_1		0x14
137930b37eeSStefan Roese #define MII_88E1510_GEN_CTRL_REG_1_MODE_MASK	0x7
138930b37eeSStefan Roese #define MII_88E1510_GEN_CTRL_REG_1_MODE_SGMII	0x1	/* SGMII to copper */
139930b37eeSStefan Roese #define MII_88E1510_GEN_CTRL_REG_1_RESET	0x8000	/* Soft reset */
140930b37eeSStefan Roese 
1416cfb3bccSCharles-Antoine Couret #define LPA_FIBER_1000HALF	0x40
1426cfb3bccSCharles-Antoine Couret #define LPA_FIBER_1000FULL	0x20
1436cfb3bccSCharles-Antoine Couret 
1446cfb3bccSCharles-Antoine Couret #define LPA_PAUSE_FIBER	0x180
1456cfb3bccSCharles-Antoine Couret #define LPA_PAUSE_ASYM_FIBER	0x100
1466cfb3bccSCharles-Antoine Couret 
1476cfb3bccSCharles-Antoine Couret #define ADVERTISE_FIBER_1000HALF	0x40
1486cfb3bccSCharles-Antoine Couret #define ADVERTISE_FIBER_1000FULL	0x20
1496cfb3bccSCharles-Antoine Couret 
1506cfb3bccSCharles-Antoine Couret #define ADVERTISE_PAUSE_FIBER		0x180
1516cfb3bccSCharles-Antoine Couret #define ADVERTISE_PAUSE_ASYM_FIBER	0x100
1526cfb3bccSCharles-Antoine Couret 
1536cfb3bccSCharles-Antoine Couret #define REGISTER_LINK_STATUS	0x400
1542170fef7SCharles-Antoine Couret #define NB_FIBER_STATS	1
1556cfb3bccSCharles-Antoine Couret 
15600db8189SAndy Fleming MODULE_DESCRIPTION("Marvell PHY driver");
15700db8189SAndy Fleming MODULE_AUTHOR("Andy Fleming");
15800db8189SAndy Fleming MODULE_LICENSE("GPL");
15900db8189SAndy Fleming 
160d2fa47d9SAndrew Lunn struct marvell_hw_stat {
161d2fa47d9SAndrew Lunn 	const char *string;
162d2fa47d9SAndrew Lunn 	u8 page;
163d2fa47d9SAndrew Lunn 	u8 reg;
164d2fa47d9SAndrew Lunn 	u8 bits;
165d2fa47d9SAndrew Lunn };
166d2fa47d9SAndrew Lunn 
167d2fa47d9SAndrew Lunn static struct marvell_hw_stat marvell_hw_stats[] = {
1682170fef7SCharles-Antoine Couret 	{ "phy_receive_errors_copper", 0, 21, 16},
169d2fa47d9SAndrew Lunn 	{ "phy_idle_errors", 0, 10, 8 },
1702170fef7SCharles-Antoine Couret 	{ "phy_receive_errors_fiber", 1, 21, 16},
171d2fa47d9SAndrew Lunn };
172d2fa47d9SAndrew Lunn 
173d2fa47d9SAndrew Lunn struct marvell_priv {
174d2fa47d9SAndrew Lunn 	u64 stats[ARRAY_SIZE(marvell_hw_stats)];
175d2fa47d9SAndrew Lunn };
176d2fa47d9SAndrew Lunn 
17700db8189SAndy Fleming static int marvell_ack_interrupt(struct phy_device *phydev)
17800db8189SAndy Fleming {
17900db8189SAndy Fleming 	int err;
18000db8189SAndy Fleming 
18100db8189SAndy Fleming 	/* Clear the interrupts by reading the reg */
18200db8189SAndy Fleming 	err = phy_read(phydev, MII_M1011_IEVENT);
18300db8189SAndy Fleming 
18400db8189SAndy Fleming 	if (err < 0)
18500db8189SAndy Fleming 		return err;
18600db8189SAndy Fleming 
18700db8189SAndy Fleming 	return 0;
18800db8189SAndy Fleming }
18900db8189SAndy Fleming 
19000db8189SAndy Fleming static int marvell_config_intr(struct phy_device *phydev)
19100db8189SAndy Fleming {
19200db8189SAndy Fleming 	int err;
19300db8189SAndy Fleming 
19400db8189SAndy Fleming 	if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
19500db8189SAndy Fleming 		err = phy_write(phydev, MII_M1011_IMASK, MII_M1011_IMASK_INIT);
19600db8189SAndy Fleming 	else
19700db8189SAndy Fleming 		err = phy_write(phydev, MII_M1011_IMASK, MII_M1011_IMASK_CLEAR);
19800db8189SAndy Fleming 
19900db8189SAndy Fleming 	return err;
20000db8189SAndy Fleming }
20100db8189SAndy Fleming 
202239aa55bSDavid Thomson static int marvell_set_polarity(struct phy_device *phydev, int polarity)
203239aa55bSDavid Thomson {
204239aa55bSDavid Thomson 	int reg;
205239aa55bSDavid Thomson 	int err;
206239aa55bSDavid Thomson 	int val;
207239aa55bSDavid Thomson 
208239aa55bSDavid Thomson 	/* get the current settings */
209239aa55bSDavid Thomson 	reg = phy_read(phydev, MII_M1011_PHY_SCR);
210239aa55bSDavid Thomson 	if (reg < 0)
211239aa55bSDavid Thomson 		return reg;
212239aa55bSDavid Thomson 
213239aa55bSDavid Thomson 	val = reg;
214239aa55bSDavid Thomson 	val &= ~MII_M1011_PHY_SCR_AUTO_CROSS;
215239aa55bSDavid Thomson 	switch (polarity) {
216239aa55bSDavid Thomson 	case ETH_TP_MDI:
217239aa55bSDavid Thomson 		val |= MII_M1011_PHY_SCR_MDI;
218239aa55bSDavid Thomson 		break;
219239aa55bSDavid Thomson 	case ETH_TP_MDI_X:
220239aa55bSDavid Thomson 		val |= MII_M1011_PHY_SCR_MDI_X;
221239aa55bSDavid Thomson 		break;
222239aa55bSDavid Thomson 	case ETH_TP_MDI_AUTO:
223239aa55bSDavid Thomson 	case ETH_TP_MDI_INVALID:
224239aa55bSDavid Thomson 	default:
225239aa55bSDavid Thomson 		val |= MII_M1011_PHY_SCR_AUTO_CROSS;
226239aa55bSDavid Thomson 		break;
227239aa55bSDavid Thomson 	}
228239aa55bSDavid Thomson 
229239aa55bSDavid Thomson 	if (val != reg) {
230239aa55bSDavid Thomson 		/* Set the new polarity value in the register */
231239aa55bSDavid Thomson 		err = phy_write(phydev, MII_M1011_PHY_SCR, val);
232239aa55bSDavid Thomson 		if (err)
233239aa55bSDavid Thomson 			return err;
234239aa55bSDavid Thomson 	}
235239aa55bSDavid Thomson 
236239aa55bSDavid Thomson 	return 0;
237239aa55bSDavid Thomson }
238239aa55bSDavid Thomson 
23900db8189SAndy Fleming static int marvell_config_aneg(struct phy_device *phydev)
24000db8189SAndy Fleming {
24100db8189SAndy Fleming 	int err;
24200db8189SAndy Fleming 
24300db8189SAndy Fleming 	/* The Marvell PHY has an errata which requires
24400db8189SAndy Fleming 	 * that certain registers get written in order
24500db8189SAndy Fleming 	 * to restart autonegotiation */
24600db8189SAndy Fleming 	err = phy_write(phydev, MII_BMCR, BMCR_RESET);
24700db8189SAndy Fleming 
24800db8189SAndy Fleming 	if (err < 0)
24900db8189SAndy Fleming 		return err;
25000db8189SAndy Fleming 
25100db8189SAndy Fleming 	err = phy_write(phydev, 0x1d, 0x1f);
25200db8189SAndy Fleming 	if (err < 0)
25300db8189SAndy Fleming 		return err;
25400db8189SAndy Fleming 
25500db8189SAndy Fleming 	err = phy_write(phydev, 0x1e, 0x200c);
25600db8189SAndy Fleming 	if (err < 0)
25700db8189SAndy Fleming 		return err;
25800db8189SAndy Fleming 
25900db8189SAndy Fleming 	err = phy_write(phydev, 0x1d, 0x5);
26000db8189SAndy Fleming 	if (err < 0)
26100db8189SAndy Fleming 		return err;
26200db8189SAndy Fleming 
26300db8189SAndy Fleming 	err = phy_write(phydev, 0x1e, 0);
26400db8189SAndy Fleming 	if (err < 0)
26500db8189SAndy Fleming 		return err;
26600db8189SAndy Fleming 
26700db8189SAndy Fleming 	err = phy_write(phydev, 0x1e, 0x100);
26800db8189SAndy Fleming 	if (err < 0)
26900db8189SAndy Fleming 		return err;
27000db8189SAndy Fleming 
271239aa55bSDavid Thomson 	err = marvell_set_polarity(phydev, phydev->mdix);
27276884679SAndy Fleming 	if (err < 0)
27376884679SAndy Fleming 		return err;
27476884679SAndy Fleming 
27576884679SAndy Fleming 	err = phy_write(phydev, MII_M1111_PHY_LED_CONTROL,
27676884679SAndy Fleming 			MII_M1111_PHY_LED_DIRECT);
27776884679SAndy Fleming 	if (err < 0)
27876884679SAndy Fleming 		return err;
27900db8189SAndy Fleming 
28000db8189SAndy Fleming 	err = genphy_config_aneg(phydev);
2818ff44985SAnton Vorontsov 	if (err < 0)
28200db8189SAndy Fleming 		return err;
2838ff44985SAnton Vorontsov 
2848ff44985SAnton Vorontsov 	if (phydev->autoneg != AUTONEG_ENABLE) {
2858ff44985SAnton Vorontsov 		int bmcr;
2868ff44985SAnton Vorontsov 
2878ff44985SAnton Vorontsov 		/*
2888ff44985SAnton Vorontsov 		 * A write to speed/duplex bits (that is performed by
2898ff44985SAnton Vorontsov 		 * genphy_config_aneg() call above) must be followed by
2908ff44985SAnton Vorontsov 		 * a software reset. Otherwise, the write has no effect.
2918ff44985SAnton Vorontsov 		 */
2928ff44985SAnton Vorontsov 		bmcr = phy_read(phydev, MII_BMCR);
2938ff44985SAnton Vorontsov 		if (bmcr < 0)
2948ff44985SAnton Vorontsov 			return bmcr;
2958ff44985SAnton Vorontsov 
2968ff44985SAnton Vorontsov 		err = phy_write(phydev, MII_BMCR, bmcr | BMCR_RESET);
2978ff44985SAnton Vorontsov 		if (err < 0)
2988ff44985SAnton Vorontsov 			return err;
2998ff44985SAnton Vorontsov 	}
3008ff44985SAnton Vorontsov 
3018ff44985SAnton Vorontsov 	return 0;
30200db8189SAndy Fleming }
30300db8189SAndy Fleming 
3043ec0a0f1SHarini Katakam static int m88e1111_config_aneg(struct phy_device *phydev)
3053ec0a0f1SHarini Katakam {
3063ec0a0f1SHarini Katakam 	int err;
3073ec0a0f1SHarini Katakam 
3083ec0a0f1SHarini Katakam 	/* The Marvell PHY has an errata which requires
3093ec0a0f1SHarini Katakam 	 * that certain registers get written in order
3103ec0a0f1SHarini Katakam 	 * to restart autonegotiation
3113ec0a0f1SHarini Katakam 	 */
3123ec0a0f1SHarini Katakam 	err = phy_write(phydev, MII_BMCR, BMCR_RESET);
3133ec0a0f1SHarini Katakam 
3143ec0a0f1SHarini Katakam 	err = marvell_set_polarity(phydev, phydev->mdix);
3153ec0a0f1SHarini Katakam 	if (err < 0)
3163ec0a0f1SHarini Katakam 		return err;
3173ec0a0f1SHarini Katakam 
3183ec0a0f1SHarini Katakam 	err = phy_write(phydev, MII_M1111_PHY_LED_CONTROL,
3193ec0a0f1SHarini Katakam 			MII_M1111_PHY_LED_DIRECT);
3203ec0a0f1SHarini Katakam 	if (err < 0)
3213ec0a0f1SHarini Katakam 		return err;
3223ec0a0f1SHarini Katakam 
3233ec0a0f1SHarini Katakam 	err = genphy_config_aneg(phydev);
3243ec0a0f1SHarini Katakam 	if (err < 0)
3253ec0a0f1SHarini Katakam 		return err;
3263ec0a0f1SHarini Katakam 
3273ec0a0f1SHarini Katakam 	if (phydev->autoneg != AUTONEG_ENABLE) {
3283ec0a0f1SHarini Katakam 		int bmcr;
3293ec0a0f1SHarini Katakam 
3303ec0a0f1SHarini Katakam 		/* A write to speed/duplex bits (that is performed by
3313ec0a0f1SHarini Katakam 		 * genphy_config_aneg() call above) must be followed by
3323ec0a0f1SHarini Katakam 		 * a software reset. Otherwise, the write has no effect.
3333ec0a0f1SHarini Katakam 		 */
3343ec0a0f1SHarini Katakam 		bmcr = phy_read(phydev, MII_BMCR);
3353ec0a0f1SHarini Katakam 		if (bmcr < 0)
3363ec0a0f1SHarini Katakam 			return bmcr;
3373ec0a0f1SHarini Katakam 
3383ec0a0f1SHarini Katakam 		err = phy_write(phydev, MII_BMCR, bmcr | BMCR_RESET);
3393ec0a0f1SHarini Katakam 		if (err < 0)
3403ec0a0f1SHarini Katakam 			return err;
3413ec0a0f1SHarini Katakam 	}
3423ec0a0f1SHarini Katakam 
3433ec0a0f1SHarini Katakam 	return 0;
3443ec0a0f1SHarini Katakam }
3453ec0a0f1SHarini Katakam 
346cf41a51dSDavid Daney #ifdef CONFIG_OF_MDIO
347cf41a51dSDavid Daney /*
348cf41a51dSDavid Daney  * Set and/or override some configuration registers based on the
349cf41a51dSDavid Daney  * marvell,reg-init property stored in the of_node for the phydev.
350cf41a51dSDavid Daney  *
351cf41a51dSDavid Daney  * marvell,reg-init = <reg-page reg mask value>,...;
352cf41a51dSDavid Daney  *
353cf41a51dSDavid Daney  * There may be one or more sets of <reg-page reg mask value>:
354cf41a51dSDavid Daney  *
355cf41a51dSDavid Daney  * reg-page: which register bank to use.
356cf41a51dSDavid Daney  * reg: the register.
357cf41a51dSDavid Daney  * mask: if non-zero, ANDed with existing register value.
358cf41a51dSDavid Daney  * value: ORed with the masked value and written to the regiser.
359cf41a51dSDavid Daney  *
360cf41a51dSDavid Daney  */
361cf41a51dSDavid Daney static int marvell_of_reg_init(struct phy_device *phydev)
362cf41a51dSDavid Daney {
363cf41a51dSDavid Daney 	const __be32 *paddr;
364cf41a51dSDavid Daney 	int len, i, saved_page, current_page, page_changed, ret;
365cf41a51dSDavid Daney 
366e5a03bfdSAndrew Lunn 	if (!phydev->mdio.dev.of_node)
367cf41a51dSDavid Daney 		return 0;
368cf41a51dSDavid Daney 
369e5a03bfdSAndrew Lunn 	paddr = of_get_property(phydev->mdio.dev.of_node,
370e5a03bfdSAndrew Lunn 				"marvell,reg-init", &len);
371cf41a51dSDavid Daney 	if (!paddr || len < (4 * sizeof(*paddr)))
372cf41a51dSDavid Daney 		return 0;
373cf41a51dSDavid Daney 
374cf41a51dSDavid Daney 	saved_page = phy_read(phydev, MII_MARVELL_PHY_PAGE);
375cf41a51dSDavid Daney 	if (saved_page < 0)
376cf41a51dSDavid Daney 		return saved_page;
377cf41a51dSDavid Daney 	page_changed = 0;
378cf41a51dSDavid Daney 	current_page = saved_page;
379cf41a51dSDavid Daney 
380cf41a51dSDavid Daney 	ret = 0;
381cf41a51dSDavid Daney 	len /= sizeof(*paddr);
382cf41a51dSDavid Daney 	for (i = 0; i < len - 3; i += 4) {
383cf41a51dSDavid Daney 		u16 reg_page = be32_to_cpup(paddr + i);
384cf41a51dSDavid Daney 		u16 reg = be32_to_cpup(paddr + i + 1);
385cf41a51dSDavid Daney 		u16 mask = be32_to_cpup(paddr + i + 2);
386cf41a51dSDavid Daney 		u16 val_bits = be32_to_cpup(paddr + i + 3);
387cf41a51dSDavid Daney 		int val;
388cf41a51dSDavid Daney 
389cf41a51dSDavid Daney 		if (reg_page != current_page) {
390cf41a51dSDavid Daney 			current_page = reg_page;
391cf41a51dSDavid Daney 			page_changed = 1;
392cf41a51dSDavid Daney 			ret = phy_write(phydev, MII_MARVELL_PHY_PAGE, reg_page);
393cf41a51dSDavid Daney 			if (ret < 0)
394cf41a51dSDavid Daney 				goto err;
395cf41a51dSDavid Daney 		}
396cf41a51dSDavid Daney 
397cf41a51dSDavid Daney 		val = 0;
398cf41a51dSDavid Daney 		if (mask) {
399cf41a51dSDavid Daney 			val = phy_read(phydev, reg);
400cf41a51dSDavid Daney 			if (val < 0) {
401cf41a51dSDavid Daney 				ret = val;
402cf41a51dSDavid Daney 				goto err;
403cf41a51dSDavid Daney 			}
404cf41a51dSDavid Daney 			val &= mask;
405cf41a51dSDavid Daney 		}
406cf41a51dSDavid Daney 		val |= val_bits;
407cf41a51dSDavid Daney 
408cf41a51dSDavid Daney 		ret = phy_write(phydev, reg, val);
409cf41a51dSDavid Daney 		if (ret < 0)
410cf41a51dSDavid Daney 			goto err;
411cf41a51dSDavid Daney 
412cf41a51dSDavid Daney 	}
413cf41a51dSDavid Daney err:
414cf41a51dSDavid Daney 	if (page_changed) {
415cf41a51dSDavid Daney 		i = phy_write(phydev, MII_MARVELL_PHY_PAGE, saved_page);
416cf41a51dSDavid Daney 		if (ret == 0)
417cf41a51dSDavid Daney 			ret = i;
418cf41a51dSDavid Daney 	}
419cf41a51dSDavid Daney 	return ret;
420cf41a51dSDavid Daney }
421cf41a51dSDavid Daney #else
422cf41a51dSDavid Daney static int marvell_of_reg_init(struct phy_device *phydev)
423cf41a51dSDavid Daney {
424cf41a51dSDavid Daney 	return 0;
425cf41a51dSDavid Daney }
426cf41a51dSDavid Daney #endif /* CONFIG_OF_MDIO */
427cf41a51dSDavid Daney 
428140bc929SSergei Poselenov static int m88e1121_config_aneg(struct phy_device *phydev)
429140bc929SSergei Poselenov {
430c477d044SCyril Chemparathy 	int err, oldpage, mscr;
431c477d044SCyril Chemparathy 
43227d916d6SDavid Daney 	oldpage = phy_read(phydev, MII_MARVELL_PHY_PAGE);
433c477d044SCyril Chemparathy 
43427d916d6SDavid Daney 	err = phy_write(phydev, MII_MARVELL_PHY_PAGE,
435c477d044SCyril Chemparathy 			MII_88E1121_PHY_MSCR_PAGE);
436c477d044SCyril Chemparathy 	if (err < 0)
437c477d044SCyril Chemparathy 		return err;
438be8c6480SArnaud Patard 
43932a64161SFlorian Fainelli 	if (phy_interface_is_rgmii(phydev)) {
440be8c6480SArnaud Patard 
441c477d044SCyril Chemparathy 		mscr = phy_read(phydev, MII_88E1121_PHY_MSCR_REG) &
442c477d044SCyril Chemparathy 			MII_88E1121_PHY_MSCR_DELAY_MASK;
443c477d044SCyril Chemparathy 
444c477d044SCyril Chemparathy 		if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)
445c477d044SCyril Chemparathy 			mscr |= (MII_88E1121_PHY_MSCR_RX_DELAY |
446c477d044SCyril Chemparathy 				 MII_88E1121_PHY_MSCR_TX_DELAY);
447c477d044SCyril Chemparathy 		else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID)
448c477d044SCyril Chemparathy 			mscr |= MII_88E1121_PHY_MSCR_RX_DELAY;
449c477d044SCyril Chemparathy 		else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)
450c477d044SCyril Chemparathy 			mscr |= MII_88E1121_PHY_MSCR_TX_DELAY;
451c477d044SCyril Chemparathy 
452c477d044SCyril Chemparathy 		err = phy_write(phydev, MII_88E1121_PHY_MSCR_REG, mscr);
453c477d044SCyril Chemparathy 		if (err < 0)
454c477d044SCyril Chemparathy 			return err;
455be8c6480SArnaud Patard 	}
456c477d044SCyril Chemparathy 
45727d916d6SDavid Daney 	phy_write(phydev, MII_MARVELL_PHY_PAGE, oldpage);
458140bc929SSergei Poselenov 
459140bc929SSergei Poselenov 	err = phy_write(phydev, MII_BMCR, BMCR_RESET);
460140bc929SSergei Poselenov 	if (err < 0)
461140bc929SSergei Poselenov 		return err;
462140bc929SSergei Poselenov 
463140bc929SSergei Poselenov 	err = phy_write(phydev, MII_M1011_PHY_SCR,
464140bc929SSergei Poselenov 			MII_M1011_PHY_SCR_AUTO_CROSS);
465140bc929SSergei Poselenov 	if (err < 0)
466140bc929SSergei Poselenov 		return err;
467140bc929SSergei Poselenov 
468fdecf36fSClemens Gruber 	return genphy_config_aneg(phydev);
469140bc929SSergei Poselenov }
470140bc929SSergei Poselenov 
471337ac9d5SCyril Chemparathy static int m88e1318_config_aneg(struct phy_device *phydev)
4723ff1c259SCyril Chemparathy {
4733ff1c259SCyril Chemparathy 	int err, oldpage, mscr;
4743ff1c259SCyril Chemparathy 
47527d916d6SDavid Daney 	oldpage = phy_read(phydev, MII_MARVELL_PHY_PAGE);
4763ff1c259SCyril Chemparathy 
47727d916d6SDavid Daney 	err = phy_write(phydev, MII_MARVELL_PHY_PAGE,
4783ff1c259SCyril Chemparathy 			MII_88E1121_PHY_MSCR_PAGE);
4793ff1c259SCyril Chemparathy 	if (err < 0)
4803ff1c259SCyril Chemparathy 		return err;
4813ff1c259SCyril Chemparathy 
482337ac9d5SCyril Chemparathy 	mscr = phy_read(phydev, MII_88E1318S_PHY_MSCR1_REG);
483337ac9d5SCyril Chemparathy 	mscr |= MII_88E1318S_PHY_MSCR1_PAD_ODD;
4843ff1c259SCyril Chemparathy 
485337ac9d5SCyril Chemparathy 	err = phy_write(phydev, MII_88E1318S_PHY_MSCR1_REG, mscr);
4863ff1c259SCyril Chemparathy 	if (err < 0)
4873ff1c259SCyril Chemparathy 		return err;
4883ff1c259SCyril Chemparathy 
48927d916d6SDavid Daney 	err = phy_write(phydev, MII_MARVELL_PHY_PAGE, oldpage);
4903ff1c259SCyril Chemparathy 	if (err < 0)
4913ff1c259SCyril Chemparathy 		return err;
4923ff1c259SCyril Chemparathy 
4933ff1c259SCyril Chemparathy 	return m88e1121_config_aneg(phydev);
4943ff1c259SCyril Chemparathy }
4953ff1c259SCyril Chemparathy 
49678301ebeSCharles-Antoine Couret /**
49778301ebeSCharles-Antoine Couret  * ethtool_adv_to_fiber_adv_t
49878301ebeSCharles-Antoine Couret  * @ethadv: the ethtool advertisement settings
49978301ebeSCharles-Antoine Couret  *
50078301ebeSCharles-Antoine Couret  * A small helper function that translates ethtool advertisement
50178301ebeSCharles-Antoine Couret  * settings to phy autonegotiation advertisements for the
50278301ebeSCharles-Antoine Couret  * MII_ADV register for fiber link.
50378301ebeSCharles-Antoine Couret  */
50478301ebeSCharles-Antoine Couret static inline u32 ethtool_adv_to_fiber_adv_t(u32 ethadv)
50578301ebeSCharles-Antoine Couret {
50678301ebeSCharles-Antoine Couret 	u32 result = 0;
50778301ebeSCharles-Antoine Couret 
50878301ebeSCharles-Antoine Couret 	if (ethadv & ADVERTISED_1000baseT_Half)
50978301ebeSCharles-Antoine Couret 		result |= ADVERTISE_FIBER_1000HALF;
51078301ebeSCharles-Antoine Couret 	if (ethadv & ADVERTISED_1000baseT_Full)
51178301ebeSCharles-Antoine Couret 		result |= ADVERTISE_FIBER_1000FULL;
51278301ebeSCharles-Antoine Couret 
51378301ebeSCharles-Antoine Couret 	if ((ethadv & ADVERTISE_PAUSE_ASYM) && (ethadv & ADVERTISE_PAUSE_CAP))
51478301ebeSCharles-Antoine Couret 		result |= LPA_PAUSE_ASYM_FIBER;
51578301ebeSCharles-Antoine Couret 	else if (ethadv & ADVERTISE_PAUSE_CAP)
51678301ebeSCharles-Antoine Couret 		result |= (ADVERTISE_PAUSE_FIBER
51778301ebeSCharles-Antoine Couret 			   & (~ADVERTISE_PAUSE_ASYM_FIBER));
51878301ebeSCharles-Antoine Couret 
51978301ebeSCharles-Antoine Couret 	return result;
52078301ebeSCharles-Antoine Couret }
52178301ebeSCharles-Antoine Couret 
52278301ebeSCharles-Antoine Couret /**
52378301ebeSCharles-Antoine Couret  * marvell_config_aneg_fiber - restart auto-negotiation or write BMCR
52478301ebeSCharles-Antoine Couret  * @phydev: target phy_device struct
52578301ebeSCharles-Antoine Couret  *
52678301ebeSCharles-Antoine Couret  * Description: If auto-negotiation is enabled, we configure the
52778301ebeSCharles-Antoine Couret  *   advertising, and then restart auto-negotiation.  If it is not
52878301ebeSCharles-Antoine Couret  *   enabled, then we write the BMCR. Adapted for fiber link in
52978301ebeSCharles-Antoine Couret  *   some Marvell's devices.
53078301ebeSCharles-Antoine Couret  */
53178301ebeSCharles-Antoine Couret static int marvell_config_aneg_fiber(struct phy_device *phydev)
53278301ebeSCharles-Antoine Couret {
53378301ebeSCharles-Antoine Couret 	int changed = 0;
53478301ebeSCharles-Antoine Couret 	int err;
53578301ebeSCharles-Antoine Couret 	int adv, oldadv;
53678301ebeSCharles-Antoine Couret 	u32 advertise;
53778301ebeSCharles-Antoine Couret 
53878301ebeSCharles-Antoine Couret 	if (phydev->autoneg != AUTONEG_ENABLE)
53978301ebeSCharles-Antoine Couret 		return genphy_setup_forced(phydev);
54078301ebeSCharles-Antoine Couret 
54178301ebeSCharles-Antoine Couret 	/* Only allow advertising what this PHY supports */
54278301ebeSCharles-Antoine Couret 	phydev->advertising &= phydev->supported;
54378301ebeSCharles-Antoine Couret 	advertise = phydev->advertising;
54478301ebeSCharles-Antoine Couret 
54578301ebeSCharles-Antoine Couret 	/* Setup fiber advertisement */
54678301ebeSCharles-Antoine Couret 	adv = phy_read(phydev, MII_ADVERTISE);
54778301ebeSCharles-Antoine Couret 	if (adv < 0)
54878301ebeSCharles-Antoine Couret 		return adv;
54978301ebeSCharles-Antoine Couret 
55078301ebeSCharles-Antoine Couret 	oldadv = adv;
55178301ebeSCharles-Antoine Couret 	adv &= ~(ADVERTISE_FIBER_1000HALF | ADVERTISE_FIBER_1000FULL
55278301ebeSCharles-Antoine Couret 		| LPA_PAUSE_FIBER);
55378301ebeSCharles-Antoine Couret 	adv |= ethtool_adv_to_fiber_adv_t(advertise);
55478301ebeSCharles-Antoine Couret 
55578301ebeSCharles-Antoine Couret 	if (adv != oldadv) {
55678301ebeSCharles-Antoine Couret 		err = phy_write(phydev, MII_ADVERTISE, adv);
55778301ebeSCharles-Antoine Couret 		if (err < 0)
55878301ebeSCharles-Antoine Couret 			return err;
55978301ebeSCharles-Antoine Couret 
56078301ebeSCharles-Antoine Couret 		changed = 1;
56178301ebeSCharles-Antoine Couret 	}
56278301ebeSCharles-Antoine Couret 
56378301ebeSCharles-Antoine Couret 	if (changed == 0) {
56478301ebeSCharles-Antoine Couret 		/* Advertisement hasn't changed, but maybe aneg was never on to
56578301ebeSCharles-Antoine Couret 		 * begin with?  Or maybe phy was isolated?
56678301ebeSCharles-Antoine Couret 		 */
56778301ebeSCharles-Antoine Couret 		int ctl = phy_read(phydev, MII_BMCR);
56878301ebeSCharles-Antoine Couret 
56978301ebeSCharles-Antoine Couret 		if (ctl < 0)
57078301ebeSCharles-Antoine Couret 			return ctl;
57178301ebeSCharles-Antoine Couret 
57278301ebeSCharles-Antoine Couret 		if (!(ctl & BMCR_ANENABLE) || (ctl & BMCR_ISOLATE))
57378301ebeSCharles-Antoine Couret 			changed = 1; /* do restart aneg */
57478301ebeSCharles-Antoine Couret 	}
57578301ebeSCharles-Antoine Couret 
57678301ebeSCharles-Antoine Couret 	/* Only restart aneg if we are advertising something different
57778301ebeSCharles-Antoine Couret 	 * than we were before.
57878301ebeSCharles-Antoine Couret 	 */
57978301ebeSCharles-Antoine Couret 	if (changed > 0)
58078301ebeSCharles-Antoine Couret 		changed = genphy_restart_aneg(phydev);
58178301ebeSCharles-Antoine Couret 
58278301ebeSCharles-Antoine Couret 	return changed;
58378301ebeSCharles-Antoine Couret }
58478301ebeSCharles-Antoine Couret 
58510e24caaSMichal Simek static int m88e1510_config_aneg(struct phy_device *phydev)
58610e24caaSMichal Simek {
58710e24caaSMichal Simek 	int err;
58810e24caaSMichal Simek 
58978301ebeSCharles-Antoine Couret 	err = phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_M1111_COPPER);
59078301ebeSCharles-Antoine Couret 	if (err < 0)
59178301ebeSCharles-Antoine Couret 		goto error;
59278301ebeSCharles-Antoine Couret 
59378301ebeSCharles-Antoine Couret 	/* Configure the copper link first */
59410e24caaSMichal Simek 	err = m88e1318_config_aneg(phydev);
59510e24caaSMichal Simek 	if (err < 0)
59678301ebeSCharles-Antoine Couret 		goto error;
59710e24caaSMichal Simek 
59878301ebeSCharles-Antoine Couret 	/* Then the fiber link */
59978301ebeSCharles-Antoine Couret 	err = phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_M1111_FIBER);
60078301ebeSCharles-Antoine Couret 	if (err < 0)
60178301ebeSCharles-Antoine Couret 		goto error;
60278301ebeSCharles-Antoine Couret 
60378301ebeSCharles-Antoine Couret 	err = marvell_config_aneg_fiber(phydev);
60478301ebeSCharles-Antoine Couret 	if (err < 0)
60578301ebeSCharles-Antoine Couret 		goto error;
60678301ebeSCharles-Antoine Couret 
60778301ebeSCharles-Antoine Couret 	return phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_M1111_COPPER);
60878301ebeSCharles-Antoine Couret 
60978301ebeSCharles-Antoine Couret error:
61078301ebeSCharles-Antoine Couret 	phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_M1111_COPPER);
61178301ebeSCharles-Antoine Couret 	return err;
61279be1a1cSClemens Gruber }
61379be1a1cSClemens Gruber 
61479be1a1cSClemens Gruber static int marvell_config_init(struct phy_device *phydev)
61579be1a1cSClemens Gruber {
61679be1a1cSClemens Gruber 	/* Set registers from marvell,reg-init DT property */
61710e24caaSMichal Simek 	return marvell_of_reg_init(phydev);
61810e24caaSMichal Simek }
61910e24caaSMichal Simek 
6203da09a51SMichal Simek static int m88e1116r_config_init(struct phy_device *phydev)
6213da09a51SMichal Simek {
6223da09a51SMichal Simek 	int temp;
6233da09a51SMichal Simek 	int err;
6243da09a51SMichal Simek 
6253da09a51SMichal Simek 	temp = phy_read(phydev, MII_BMCR);
6263da09a51SMichal Simek 	temp |= BMCR_RESET;
6273da09a51SMichal Simek 	err = phy_write(phydev, MII_BMCR, temp);
6283da09a51SMichal Simek 	if (err < 0)
6293da09a51SMichal Simek 		return err;
6303da09a51SMichal Simek 
6313da09a51SMichal Simek 	mdelay(500);
6323da09a51SMichal Simek 
6333da09a51SMichal Simek 	err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0);
6343da09a51SMichal Simek 	if (err < 0)
6353da09a51SMichal Simek 		return err;
6363da09a51SMichal Simek 
6373da09a51SMichal Simek 	temp = phy_read(phydev, MII_M1011_PHY_SCR);
6383da09a51SMichal Simek 	temp |= (7 << 12);	/* max number of gigabit attempts */
6393da09a51SMichal Simek 	temp |= (1 << 11);	/* enable downshift */
6403da09a51SMichal Simek 	temp |= MII_M1011_PHY_SCR_AUTO_CROSS;
6413da09a51SMichal Simek 	err = phy_write(phydev, MII_M1011_PHY_SCR, temp);
6423da09a51SMichal Simek 	if (err < 0)
6433da09a51SMichal Simek 		return err;
6443da09a51SMichal Simek 
6453da09a51SMichal Simek 	err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 2);
6463da09a51SMichal Simek 	if (err < 0)
6473da09a51SMichal Simek 		return err;
6483da09a51SMichal Simek 	temp = phy_read(phydev, MII_M1116R_CONTROL_REG_MAC);
6493da09a51SMichal Simek 	temp |= (1 << 5);
6503da09a51SMichal Simek 	temp |= (1 << 4);
6513da09a51SMichal Simek 	err = phy_write(phydev, MII_M1116R_CONTROL_REG_MAC, temp);
6523da09a51SMichal Simek 	if (err < 0)
6533da09a51SMichal Simek 		return err;
6543da09a51SMichal Simek 	err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0);
6553da09a51SMichal Simek 	if (err < 0)
6563da09a51SMichal Simek 		return err;
6573da09a51SMichal Simek 
6583da09a51SMichal Simek 	temp = phy_read(phydev, MII_BMCR);
6593da09a51SMichal Simek 	temp |= BMCR_RESET;
6603da09a51SMichal Simek 	err = phy_write(phydev, MII_BMCR, temp);
6613da09a51SMichal Simek 	if (err < 0)
6623da09a51SMichal Simek 		return err;
6633da09a51SMichal Simek 
6643da09a51SMichal Simek 	mdelay(500);
6653da09a51SMichal Simek 
66679be1a1cSClemens Gruber 	return marvell_config_init(phydev);
6673da09a51SMichal Simek }
6683da09a51SMichal Simek 
6696b358aedSSebastian Hesselbarth static int m88e3016_config_init(struct phy_device *phydev)
6706b358aedSSebastian Hesselbarth {
6716b358aedSSebastian Hesselbarth 	int reg;
6726b358aedSSebastian Hesselbarth 
6736b358aedSSebastian Hesselbarth 	/* Enable Scrambler and Auto-Crossover */
6746b358aedSSebastian Hesselbarth 	reg = phy_read(phydev, MII_88E3016_PHY_SPEC_CTRL);
6756b358aedSSebastian Hesselbarth 	if (reg < 0)
6766b358aedSSebastian Hesselbarth 		return reg;
6776b358aedSSebastian Hesselbarth 
6786b358aedSSebastian Hesselbarth 	reg &= ~MII_88E3016_DISABLE_SCRAMBLER;
6796b358aedSSebastian Hesselbarth 	reg |= MII_88E3016_AUTO_MDIX_CROSSOVER;
6806b358aedSSebastian Hesselbarth 
6816b358aedSSebastian Hesselbarth 	reg = phy_write(phydev, MII_88E3016_PHY_SPEC_CTRL, reg);
6826b358aedSSebastian Hesselbarth 	if (reg < 0)
6836b358aedSSebastian Hesselbarth 		return reg;
6846b358aedSSebastian Hesselbarth 
68579be1a1cSClemens Gruber 	return marvell_config_init(phydev);
6866b358aedSSebastian Hesselbarth }
6876b358aedSSebastian Hesselbarth 
688895ee682SKim Phillips static int m88e1111_config_init(struct phy_device *phydev)
689895ee682SKim Phillips {
690895ee682SKim Phillips 	int err;
691be937f1fSAlexandr Smirnov 	int temp;
692be937f1fSAlexandr Smirnov 
69332a64161SFlorian Fainelli 	if (phy_interface_is_rgmii(phydev)) {
694895ee682SKim Phillips 
695895ee682SKim Phillips 		temp = phy_read(phydev, MII_M1111_PHY_EXT_CR);
696895ee682SKim Phillips 		if (temp < 0)
697895ee682SKim Phillips 			return temp;
698895ee682SKim Phillips 
6999daf5a76SKim Phillips 		if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) {
700895ee682SKim Phillips 			temp |= (MII_M1111_RX_DELAY | MII_M1111_TX_DELAY);
7019daf5a76SKim Phillips 		} else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) {
7029daf5a76SKim Phillips 			temp &= ~MII_M1111_TX_DELAY;
7039daf5a76SKim Phillips 			temp |= MII_M1111_RX_DELAY;
7049daf5a76SKim Phillips 		} else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) {
7059daf5a76SKim Phillips 			temp &= ~MII_M1111_RX_DELAY;
7069daf5a76SKim Phillips 			temp |= MII_M1111_TX_DELAY;
7079daf5a76SKim Phillips 		}
708895ee682SKim Phillips 
709895ee682SKim Phillips 		err = phy_write(phydev, MII_M1111_PHY_EXT_CR, temp);
710895ee682SKim Phillips 		if (err < 0)
711895ee682SKim Phillips 			return err;
712895ee682SKim Phillips 
713895ee682SKim Phillips 		temp = phy_read(phydev, MII_M1111_PHY_EXT_SR);
714895ee682SKim Phillips 		if (temp < 0)
715895ee682SKim Phillips 			return temp;
716895ee682SKim Phillips 
717895ee682SKim Phillips 		temp &= ~(MII_M1111_HWCFG_MODE_MASK);
718be937f1fSAlexandr Smirnov 
7197239016dSWang Jian 		if (temp & MII_M1111_HWCFG_FIBER_COPPER_RES)
720be937f1fSAlexandr Smirnov 			temp |= MII_M1111_HWCFG_MODE_FIBER_RGMII;
721be937f1fSAlexandr Smirnov 		else
722be937f1fSAlexandr Smirnov 			temp |= MII_M1111_HWCFG_MODE_COPPER_RGMII;
723895ee682SKim Phillips 
724895ee682SKim Phillips 		err = phy_write(phydev, MII_M1111_PHY_EXT_SR, temp);
725895ee682SKim Phillips 		if (err < 0)
726895ee682SKim Phillips 			return err;
727895ee682SKim Phillips 	}
728895ee682SKim Phillips 
7294117b5beSKapil Juneja 	if (phydev->interface == PHY_INTERFACE_MODE_SGMII) {
7304117b5beSKapil Juneja 		temp = phy_read(phydev, MII_M1111_PHY_EXT_SR);
7314117b5beSKapil Juneja 		if (temp < 0)
7324117b5beSKapil Juneja 			return temp;
7334117b5beSKapil Juneja 
7344117b5beSKapil Juneja 		temp &= ~(MII_M1111_HWCFG_MODE_MASK);
7354117b5beSKapil Juneja 		temp |= MII_M1111_HWCFG_MODE_SGMII_NO_CLK;
73632d0c1e1SHaiying Wang 		temp |= MII_M1111_HWCFG_FIBER_COPPER_AUTO;
7374117b5beSKapil Juneja 
7384117b5beSKapil Juneja 		err = phy_write(phydev, MII_M1111_PHY_EXT_SR, temp);
7394117b5beSKapil Juneja 		if (err < 0)
7404117b5beSKapil Juneja 			return err;
74107151bc9SMadalin Bucur 
74207151bc9SMadalin Bucur 		/* make sure copper is selected */
74307151bc9SMadalin Bucur 		err = phy_read(phydev, MII_M1145_PHY_EXT_ADDR_PAGE);
74407151bc9SMadalin Bucur 		if (err < 0)
74507151bc9SMadalin Bucur 			return err;
74607151bc9SMadalin Bucur 
74707151bc9SMadalin Bucur 		err = phy_write(phydev, MII_M1145_PHY_EXT_ADDR_PAGE,
74807151bc9SMadalin Bucur 				err & (~0xff));
74907151bc9SMadalin Bucur 		if (err < 0)
75007151bc9SMadalin Bucur 			return err;
7514117b5beSKapil Juneja 	}
7524117b5beSKapil Juneja 
7535f8cbc13SLiu Yu-B13201 	if (phydev->interface == PHY_INTERFACE_MODE_RTBI) {
7545f8cbc13SLiu Yu-B13201 		temp = phy_read(phydev, MII_M1111_PHY_EXT_CR);
7555f8cbc13SLiu Yu-B13201 		if (temp < 0)
7565f8cbc13SLiu Yu-B13201 			return temp;
7575f8cbc13SLiu Yu-B13201 		temp |= (MII_M1111_RX_DELAY | MII_M1111_TX_DELAY);
7585f8cbc13SLiu Yu-B13201 		err = phy_write(phydev, MII_M1111_PHY_EXT_CR, temp);
7595f8cbc13SLiu Yu-B13201 		if (err < 0)
7605f8cbc13SLiu Yu-B13201 			return err;
7615f8cbc13SLiu Yu-B13201 
7625f8cbc13SLiu Yu-B13201 		temp = phy_read(phydev, MII_M1111_PHY_EXT_SR);
7635f8cbc13SLiu Yu-B13201 		if (temp < 0)
7645f8cbc13SLiu Yu-B13201 			return temp;
7655f8cbc13SLiu Yu-B13201 		temp &= ~(MII_M1111_HWCFG_MODE_MASK | MII_M1111_HWCFG_FIBER_COPPER_RES);
7665f8cbc13SLiu Yu-B13201 		temp |= 0x7 | MII_M1111_HWCFG_FIBER_COPPER_AUTO;
7675f8cbc13SLiu Yu-B13201 		err = phy_write(phydev, MII_M1111_PHY_EXT_SR, temp);
7685f8cbc13SLiu Yu-B13201 		if (err < 0)
7695f8cbc13SLiu Yu-B13201 			return err;
7705f8cbc13SLiu Yu-B13201 
7715f8cbc13SLiu Yu-B13201 		/* soft reset */
7725f8cbc13SLiu Yu-B13201 		err = phy_write(phydev, MII_BMCR, BMCR_RESET);
7735f8cbc13SLiu Yu-B13201 		if (err < 0)
7745f8cbc13SLiu Yu-B13201 			return err;
7755f8cbc13SLiu Yu-B13201 		do
7765f8cbc13SLiu Yu-B13201 			temp = phy_read(phydev, MII_BMCR);
7775f8cbc13SLiu Yu-B13201 		while (temp & BMCR_RESET);
7785f8cbc13SLiu Yu-B13201 
7795f8cbc13SLiu Yu-B13201 		temp = phy_read(phydev, MII_M1111_PHY_EXT_SR);
7805f8cbc13SLiu Yu-B13201 		if (temp < 0)
7815f8cbc13SLiu Yu-B13201 			return temp;
7825f8cbc13SLiu Yu-B13201 		temp &= ~(MII_M1111_HWCFG_MODE_MASK | MII_M1111_HWCFG_FIBER_COPPER_RES);
7835f8cbc13SLiu Yu-B13201 		temp |= MII_M1111_HWCFG_MODE_COPPER_RTBI | MII_M1111_HWCFG_FIBER_COPPER_AUTO;
7845f8cbc13SLiu Yu-B13201 		err = phy_write(phydev, MII_M1111_PHY_EXT_SR, temp);
7855f8cbc13SLiu Yu-B13201 		if (err < 0)
7865f8cbc13SLiu Yu-B13201 			return err;
7875f8cbc13SLiu Yu-B13201 	}
7885f8cbc13SLiu Yu-B13201 
789cf41a51dSDavid Daney 	err = marvell_of_reg_init(phydev);
790cf41a51dSDavid Daney 	if (err < 0)
791cf41a51dSDavid Daney 		return err;
7925f8cbc13SLiu Yu-B13201 
793cc90cb3bSSrinivas Kandagatla 	return phy_write(phydev, MII_BMCR, BMCR_RESET);
794895ee682SKim Phillips }
795895ee682SKim Phillips 
796fdecf36fSClemens Gruber static int m88e1121_config_init(struct phy_device *phydev)
797fdecf36fSClemens Gruber {
798fdecf36fSClemens Gruber 	int err, oldpage;
799fdecf36fSClemens Gruber 
800fdecf36fSClemens Gruber 	oldpage = phy_read(phydev, MII_MARVELL_PHY_PAGE);
801fdecf36fSClemens Gruber 
802fdecf36fSClemens Gruber 	err = phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_88E1121_PHY_LED_PAGE);
803fdecf36fSClemens Gruber 	if (err < 0)
804fdecf36fSClemens Gruber 		return err;
805fdecf36fSClemens Gruber 
806fdecf36fSClemens Gruber 	/* Default PHY LED config: LED[0] .. Link, LED[1] .. Activity */
807fdecf36fSClemens Gruber 	err = phy_write(phydev, MII_88E1121_PHY_LED_CTRL,
808fdecf36fSClemens Gruber 			MII_88E1121_PHY_LED_DEF);
809fdecf36fSClemens Gruber 	if (err < 0)
810fdecf36fSClemens Gruber 		return err;
811fdecf36fSClemens Gruber 
812fdecf36fSClemens Gruber 	phy_write(phydev, MII_MARVELL_PHY_PAGE, oldpage);
813fdecf36fSClemens Gruber 
814fdecf36fSClemens Gruber 	/* Set marvell,reg-init configuration from device tree */
815fdecf36fSClemens Gruber 	return marvell_config_init(phydev);
816fdecf36fSClemens Gruber }
817fdecf36fSClemens Gruber 
818407353ecSClemens Gruber static int m88e1510_config_init(struct phy_device *phydev)
819407353ecSClemens Gruber {
820407353ecSClemens Gruber 	int err;
821407353ecSClemens Gruber 	int temp;
822407353ecSClemens Gruber 
823407353ecSClemens Gruber 	/* SGMII-to-Copper mode initialization */
824407353ecSClemens Gruber 	if (phydev->interface == PHY_INTERFACE_MODE_SGMII) {
825407353ecSClemens Gruber 		/* Select page 18 */
826407353ecSClemens Gruber 		err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 18);
827407353ecSClemens Gruber 		if (err < 0)
828407353ecSClemens Gruber 			return err;
829407353ecSClemens Gruber 
830407353ecSClemens Gruber 		/* In reg 20, write MODE[2:0] = 0x1 (SGMII to Copper) */
831407353ecSClemens Gruber 		temp = phy_read(phydev, MII_88E1510_GEN_CTRL_REG_1);
832407353ecSClemens Gruber 		temp &= ~MII_88E1510_GEN_CTRL_REG_1_MODE_MASK;
833407353ecSClemens Gruber 		temp |= MII_88E1510_GEN_CTRL_REG_1_MODE_SGMII;
834407353ecSClemens Gruber 		err = phy_write(phydev, MII_88E1510_GEN_CTRL_REG_1, temp);
835407353ecSClemens Gruber 		if (err < 0)
836407353ecSClemens Gruber 			return err;
837407353ecSClemens Gruber 
838407353ecSClemens Gruber 		/* PHY reset is necessary after changing MODE[2:0] */
839407353ecSClemens Gruber 		temp |= MII_88E1510_GEN_CTRL_REG_1_RESET;
840407353ecSClemens Gruber 		err = phy_write(phydev, MII_88E1510_GEN_CTRL_REG_1, temp);
841407353ecSClemens Gruber 		if (err < 0)
842407353ecSClemens Gruber 			return err;
843407353ecSClemens Gruber 
844407353ecSClemens Gruber 		/* Reset page selection */
845407353ecSClemens Gruber 		err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0);
846407353ecSClemens Gruber 		if (err < 0)
847407353ecSClemens Gruber 			return err;
848407353ecSClemens Gruber 	}
849407353ecSClemens Gruber 
850fdecf36fSClemens Gruber 	return m88e1121_config_init(phydev);
851407353ecSClemens Gruber }
852407353ecSClemens Gruber 
853605f196eSRon Madrid static int m88e1118_config_aneg(struct phy_device *phydev)
854605f196eSRon Madrid {
855605f196eSRon Madrid 	int err;
856605f196eSRon Madrid 
857605f196eSRon Madrid 	err = phy_write(phydev, MII_BMCR, BMCR_RESET);
858605f196eSRon Madrid 	if (err < 0)
859605f196eSRon Madrid 		return err;
860605f196eSRon Madrid 
861605f196eSRon Madrid 	err = phy_write(phydev, MII_M1011_PHY_SCR,
862605f196eSRon Madrid 			MII_M1011_PHY_SCR_AUTO_CROSS);
863605f196eSRon Madrid 	if (err < 0)
864605f196eSRon Madrid 		return err;
865605f196eSRon Madrid 
866605f196eSRon Madrid 	err = genphy_config_aneg(phydev);
867605f196eSRon Madrid 	return 0;
868605f196eSRon Madrid }
869605f196eSRon Madrid 
870605f196eSRon Madrid static int m88e1118_config_init(struct phy_device *phydev)
871605f196eSRon Madrid {
872605f196eSRon Madrid 	int err;
873605f196eSRon Madrid 
874605f196eSRon Madrid 	/* Change address */
87527d916d6SDavid Daney 	err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0002);
876605f196eSRon Madrid 	if (err < 0)
877605f196eSRon Madrid 		return err;
878605f196eSRon Madrid 
879605f196eSRon Madrid 	/* Enable 1000 Mbit */
880605f196eSRon Madrid 	err = phy_write(phydev, 0x15, 0x1070);
881605f196eSRon Madrid 	if (err < 0)
882605f196eSRon Madrid 		return err;
883605f196eSRon Madrid 
884605f196eSRon Madrid 	/* Change address */
88527d916d6SDavid Daney 	err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0003);
886605f196eSRon Madrid 	if (err < 0)
887605f196eSRon Madrid 		return err;
888605f196eSRon Madrid 
889605f196eSRon Madrid 	/* Adjust LED Control */
8902f495c39SBenjamin Herrenschmidt 	if (phydev->dev_flags & MARVELL_PHY_M1118_DNS323_LEDS)
8912f495c39SBenjamin Herrenschmidt 		err = phy_write(phydev, 0x10, 0x1100);
8922f495c39SBenjamin Herrenschmidt 	else
893605f196eSRon Madrid 		err = phy_write(phydev, 0x10, 0x021e);
894605f196eSRon Madrid 	if (err < 0)
895605f196eSRon Madrid 		return err;
896605f196eSRon Madrid 
897cf41a51dSDavid Daney 	err = marvell_of_reg_init(phydev);
898cf41a51dSDavid Daney 	if (err < 0)
899cf41a51dSDavid Daney 		return err;
900cf41a51dSDavid Daney 
901605f196eSRon Madrid 	/* Reset address */
90227d916d6SDavid Daney 	err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0);
903605f196eSRon Madrid 	if (err < 0)
904605f196eSRon Madrid 		return err;
905605f196eSRon Madrid 
906cc90cb3bSSrinivas Kandagatla 	return phy_write(phydev, MII_BMCR, BMCR_RESET);
907605f196eSRon Madrid }
908605f196eSRon Madrid 
90990600732SDavid Daney static int m88e1149_config_init(struct phy_device *phydev)
91090600732SDavid Daney {
91190600732SDavid Daney 	int err;
91290600732SDavid Daney 
91390600732SDavid Daney 	/* Change address */
91490600732SDavid Daney 	err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0002);
91590600732SDavid Daney 	if (err < 0)
91690600732SDavid Daney 		return err;
91790600732SDavid Daney 
91890600732SDavid Daney 	/* Enable 1000 Mbit */
91990600732SDavid Daney 	err = phy_write(phydev, 0x15, 0x1048);
92090600732SDavid Daney 	if (err < 0)
92190600732SDavid Daney 		return err;
92290600732SDavid Daney 
923cf41a51dSDavid Daney 	err = marvell_of_reg_init(phydev);
924cf41a51dSDavid Daney 	if (err < 0)
925cf41a51dSDavid Daney 		return err;
926cf41a51dSDavid Daney 
92790600732SDavid Daney 	/* Reset address */
92890600732SDavid Daney 	err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0);
92990600732SDavid Daney 	if (err < 0)
93090600732SDavid Daney 		return err;
93190600732SDavid Daney 
932cc90cb3bSSrinivas Kandagatla 	return phy_write(phydev, MII_BMCR, BMCR_RESET);
93390600732SDavid Daney }
93490600732SDavid Daney 
93576884679SAndy Fleming static int m88e1145_config_init(struct phy_device *phydev)
93676884679SAndy Fleming {
93776884679SAndy Fleming 	int err;
938b0224175SViet Nga Dao 	int temp;
93976884679SAndy Fleming 
94076884679SAndy Fleming 	/* Take care of errata E0 & E1 */
94176884679SAndy Fleming 	err = phy_write(phydev, 0x1d, 0x001b);
94276884679SAndy Fleming 	if (err < 0)
94376884679SAndy Fleming 		return err;
94476884679SAndy Fleming 
94576884679SAndy Fleming 	err = phy_write(phydev, 0x1e, 0x418f);
94676884679SAndy Fleming 	if (err < 0)
94776884679SAndy Fleming 		return err;
94876884679SAndy Fleming 
94976884679SAndy Fleming 	err = phy_write(phydev, 0x1d, 0x0016);
95076884679SAndy Fleming 	if (err < 0)
95176884679SAndy Fleming 		return err;
95276884679SAndy Fleming 
95376884679SAndy Fleming 	err = phy_write(phydev, 0x1e, 0xa2da);
95476884679SAndy Fleming 	if (err < 0)
95576884679SAndy Fleming 		return err;
95676884679SAndy Fleming 
957895ee682SKim Phillips 	if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) {
95876884679SAndy Fleming 		int temp = phy_read(phydev, MII_M1145_PHY_EXT_CR);
95976884679SAndy Fleming 		if (temp < 0)
96076884679SAndy Fleming 			return temp;
96176884679SAndy Fleming 
96276884679SAndy Fleming 		temp |= (MII_M1145_RGMII_RX_DELAY | MII_M1145_RGMII_TX_DELAY);
96376884679SAndy Fleming 
96476884679SAndy Fleming 		err = phy_write(phydev, MII_M1145_PHY_EXT_CR, temp);
96576884679SAndy Fleming 		if (err < 0)
96676884679SAndy Fleming 			return err;
96776884679SAndy Fleming 
9682f495c39SBenjamin Herrenschmidt 		if (phydev->dev_flags & MARVELL_PHY_M1145_FLAGS_RESISTANCE) {
96976884679SAndy Fleming 			err = phy_write(phydev, 0x1d, 0x0012);
97076884679SAndy Fleming 			if (err < 0)
97176884679SAndy Fleming 				return err;
97276884679SAndy Fleming 
97376884679SAndy Fleming 			temp = phy_read(phydev, 0x1e);
97476884679SAndy Fleming 			if (temp < 0)
97576884679SAndy Fleming 				return temp;
97676884679SAndy Fleming 
97776884679SAndy Fleming 			temp &= 0xf03f;
97876884679SAndy Fleming 			temp |= 2 << 9;	/* 36 ohm */
97976884679SAndy Fleming 			temp |= 2 << 6;	/* 39 ohm */
98076884679SAndy Fleming 
98176884679SAndy Fleming 			err = phy_write(phydev, 0x1e, temp);
98276884679SAndy Fleming 			if (err < 0)
98376884679SAndy Fleming 				return err;
98476884679SAndy Fleming 
98576884679SAndy Fleming 			err = phy_write(phydev, 0x1d, 0x3);
98676884679SAndy Fleming 			if (err < 0)
98776884679SAndy Fleming 				return err;
98876884679SAndy Fleming 
98976884679SAndy Fleming 			err = phy_write(phydev, 0x1e, 0x8000);
99076884679SAndy Fleming 			if (err < 0)
99176884679SAndy Fleming 				return err;
99276884679SAndy Fleming 		}
99376884679SAndy Fleming 	}
99476884679SAndy Fleming 
995b0224175SViet Nga Dao 	if (phydev->interface == PHY_INTERFACE_MODE_SGMII) {
996b0224175SViet Nga Dao 		temp = phy_read(phydev, MII_M1145_PHY_EXT_SR);
997b0224175SViet Nga Dao 		if (temp < 0)
998b0224175SViet Nga Dao 			return temp;
999b0224175SViet Nga Dao 
100099d881f9SVince Bridgers 		temp &= ~MII_M1145_HWCFG_MODE_MASK;
1001b0224175SViet Nga Dao 		temp |= MII_M1145_HWCFG_MODE_SGMII_NO_CLK;
1002b0224175SViet Nga Dao 		temp |= MII_M1145_HWCFG_FIBER_COPPER_AUTO;
1003b0224175SViet Nga Dao 
1004b0224175SViet Nga Dao 		err = phy_write(phydev, MII_M1145_PHY_EXT_SR, temp);
1005b0224175SViet Nga Dao 		if (err < 0)
1006b0224175SViet Nga Dao 			return err;
1007b0224175SViet Nga Dao 	}
1008b0224175SViet Nga Dao 
1009cf41a51dSDavid Daney 	err = marvell_of_reg_init(phydev);
1010cf41a51dSDavid Daney 	if (err < 0)
1011cf41a51dSDavid Daney 		return err;
1012cf41a51dSDavid Daney 
101376884679SAndy Fleming 	return 0;
101476884679SAndy Fleming }
101500db8189SAndy Fleming 
10166cfb3bccSCharles-Antoine Couret /**
10176cfb3bccSCharles-Antoine Couret  * fiber_lpa_to_ethtool_lpa_t
10186cfb3bccSCharles-Antoine Couret  * @lpa: value of the MII_LPA register for fiber link
1019be937f1fSAlexandr Smirnov  *
10206cfb3bccSCharles-Antoine Couret  * A small helper function that translates MII_LPA
10216cfb3bccSCharles-Antoine Couret  * bits to ethtool LP advertisement settings.
10226cfb3bccSCharles-Antoine Couret  */
10236cfb3bccSCharles-Antoine Couret static u32 fiber_lpa_to_ethtool_lpa_t(u32 lpa)
10246cfb3bccSCharles-Antoine Couret {
10256cfb3bccSCharles-Antoine Couret 	u32 result = 0;
10266cfb3bccSCharles-Antoine Couret 
10276cfb3bccSCharles-Antoine Couret 	if (lpa & LPA_FIBER_1000HALF)
10286cfb3bccSCharles-Antoine Couret 		result |= ADVERTISED_1000baseT_Half;
10296cfb3bccSCharles-Antoine Couret 	if (lpa & LPA_FIBER_1000FULL)
10306cfb3bccSCharles-Antoine Couret 		result |= ADVERTISED_1000baseT_Full;
10316cfb3bccSCharles-Antoine Couret 
10326cfb3bccSCharles-Antoine Couret 	return result;
10336cfb3bccSCharles-Antoine Couret }
10346cfb3bccSCharles-Antoine Couret 
10356cfb3bccSCharles-Antoine Couret /**
10366cfb3bccSCharles-Antoine Couret  * marvell_update_link - update link status in real time in @phydev
10376cfb3bccSCharles-Antoine Couret  * @phydev: target phy_device struct
10386cfb3bccSCharles-Antoine Couret  *
10396cfb3bccSCharles-Antoine Couret  * Description: Update the value in phydev->link to reflect the
10406cfb3bccSCharles-Antoine Couret  *   current link value.
10416cfb3bccSCharles-Antoine Couret  */
10426cfb3bccSCharles-Antoine Couret static int marvell_update_link(struct phy_device *phydev, int fiber)
10436cfb3bccSCharles-Antoine Couret {
10446cfb3bccSCharles-Antoine Couret 	int status;
10456cfb3bccSCharles-Antoine Couret 
10466cfb3bccSCharles-Antoine Couret 	/* Use the generic register for copper link, or specific
10476cfb3bccSCharles-Antoine Couret 	 * register for fiber case */
10486cfb3bccSCharles-Antoine Couret 	if (fiber) {
10496cfb3bccSCharles-Antoine Couret 		status = phy_read(phydev, MII_M1011_PHY_STATUS);
10506cfb3bccSCharles-Antoine Couret 		if (status < 0)
10516cfb3bccSCharles-Antoine Couret 			return status;
10526cfb3bccSCharles-Antoine Couret 
10536cfb3bccSCharles-Antoine Couret 		if ((status & REGISTER_LINK_STATUS) == 0)
10546cfb3bccSCharles-Antoine Couret 			phydev->link = 0;
10556cfb3bccSCharles-Antoine Couret 		else
10566cfb3bccSCharles-Antoine Couret 			phydev->link = 1;
10576cfb3bccSCharles-Antoine Couret 	} else {
10586cfb3bccSCharles-Antoine Couret 		return genphy_update_link(phydev);
10596cfb3bccSCharles-Antoine Couret 	}
10606cfb3bccSCharles-Antoine Couret 
10616cfb3bccSCharles-Antoine Couret 	return 0;
10626cfb3bccSCharles-Antoine Couret }
10636cfb3bccSCharles-Antoine Couret 
10646cfb3bccSCharles-Antoine Couret /* marvell_read_status_page
10656cfb3bccSCharles-Antoine Couret  *
1066be937f1fSAlexandr Smirnov  * Description:
1067be937f1fSAlexandr Smirnov  *   Check the link, then figure out the current state
1068be937f1fSAlexandr Smirnov  *   by comparing what we advertise with what the link partner
1069be937f1fSAlexandr Smirnov  *   advertises.  Start by checking the gigabit possibilities,
1070be937f1fSAlexandr Smirnov  *   then move on to 10/100.
1071be937f1fSAlexandr Smirnov  */
10726cfb3bccSCharles-Antoine Couret static int marvell_read_status_page(struct phy_device *phydev, int page)
1073be937f1fSAlexandr Smirnov {
1074be937f1fSAlexandr Smirnov 	int adv;
1075be937f1fSAlexandr Smirnov 	int err;
1076be937f1fSAlexandr Smirnov 	int lpa;
1077357cd64cSRussell King 	int lpagb;
1078be937f1fSAlexandr Smirnov 	int status = 0;
10796cfb3bccSCharles-Antoine Couret 	int fiber;
1080be937f1fSAlexandr Smirnov 
10816cfb3bccSCharles-Antoine Couret 	/* Detect and update the link, but return if there
1082be937f1fSAlexandr Smirnov 	 * was an error */
10836cfb3bccSCharles-Antoine Couret 	if (page == MII_M1111_FIBER)
10846cfb3bccSCharles-Antoine Couret 		fiber = 1;
10856cfb3bccSCharles-Antoine Couret 	else
10866cfb3bccSCharles-Antoine Couret 		fiber = 0;
10876cfb3bccSCharles-Antoine Couret 
10886cfb3bccSCharles-Antoine Couret 	err = marvell_update_link(phydev, fiber);
1089be937f1fSAlexandr Smirnov 	if (err)
1090be937f1fSAlexandr Smirnov 		return err;
1091be937f1fSAlexandr Smirnov 
1092be937f1fSAlexandr Smirnov 	if (AUTONEG_ENABLE == phydev->autoneg) {
1093be937f1fSAlexandr Smirnov 		status = phy_read(phydev, MII_M1011_PHY_STATUS);
1094be937f1fSAlexandr Smirnov 		if (status < 0)
1095be937f1fSAlexandr Smirnov 			return status;
1096be937f1fSAlexandr Smirnov 
1097be937f1fSAlexandr Smirnov 		lpa = phy_read(phydev, MII_LPA);
1098be937f1fSAlexandr Smirnov 		if (lpa < 0)
1099be937f1fSAlexandr Smirnov 			return lpa;
1100be937f1fSAlexandr Smirnov 
1101357cd64cSRussell King 		lpagb = phy_read(phydev, MII_STAT1000);
1102357cd64cSRussell King 		if (lpagb < 0)
1103357cd64cSRussell King 			return lpagb;
1104357cd64cSRussell King 
1105be937f1fSAlexandr Smirnov 		adv = phy_read(phydev, MII_ADVERTISE);
1106be937f1fSAlexandr Smirnov 		if (adv < 0)
1107be937f1fSAlexandr Smirnov 			return adv;
1108be937f1fSAlexandr Smirnov 
1109be937f1fSAlexandr Smirnov 		lpa &= adv;
1110be937f1fSAlexandr Smirnov 
1111be937f1fSAlexandr Smirnov 		if (status & MII_M1011_PHY_STATUS_FULLDUPLEX)
1112be937f1fSAlexandr Smirnov 			phydev->duplex = DUPLEX_FULL;
1113be937f1fSAlexandr Smirnov 		else
1114be937f1fSAlexandr Smirnov 			phydev->duplex = DUPLEX_HALF;
1115be937f1fSAlexandr Smirnov 
1116be937f1fSAlexandr Smirnov 		status = status & MII_M1011_PHY_STATUS_SPD_MASK;
1117be937f1fSAlexandr Smirnov 		phydev->pause = phydev->asym_pause = 0;
1118be937f1fSAlexandr Smirnov 
1119be937f1fSAlexandr Smirnov 		switch (status) {
1120be937f1fSAlexandr Smirnov 		case MII_M1011_PHY_STATUS_1000:
1121be937f1fSAlexandr Smirnov 			phydev->speed = SPEED_1000;
1122be937f1fSAlexandr Smirnov 			break;
1123be937f1fSAlexandr Smirnov 
1124be937f1fSAlexandr Smirnov 		case MII_M1011_PHY_STATUS_100:
1125be937f1fSAlexandr Smirnov 			phydev->speed = SPEED_100;
1126be937f1fSAlexandr Smirnov 			break;
1127be937f1fSAlexandr Smirnov 
1128be937f1fSAlexandr Smirnov 		default:
1129be937f1fSAlexandr Smirnov 			phydev->speed = SPEED_10;
1130be937f1fSAlexandr Smirnov 			break;
1131be937f1fSAlexandr Smirnov 		}
1132be937f1fSAlexandr Smirnov 
11336cfb3bccSCharles-Antoine Couret 		if (!fiber) {
11346cfb3bccSCharles-Antoine Couret 			phydev->lp_advertising = mii_stat1000_to_ethtool_lpa_t(lpagb) |
11356cfb3bccSCharles-Antoine Couret 					 mii_lpa_to_ethtool_lpa_t(lpa);
11366cfb3bccSCharles-Antoine Couret 
1137be937f1fSAlexandr Smirnov 			if (phydev->duplex == DUPLEX_FULL) {
1138be937f1fSAlexandr Smirnov 				phydev->pause = lpa & LPA_PAUSE_CAP ? 1 : 0;
1139be937f1fSAlexandr Smirnov 				phydev->asym_pause = lpa & LPA_PAUSE_ASYM ? 1 : 0;
1140be937f1fSAlexandr Smirnov 			}
1141be937f1fSAlexandr Smirnov 		} else {
11426cfb3bccSCharles-Antoine Couret 			/* The fiber link is only 1000M capable */
11436cfb3bccSCharles-Antoine Couret 			phydev->lp_advertising = fiber_lpa_to_ethtool_lpa_t(lpa);
11446cfb3bccSCharles-Antoine Couret 
11456cfb3bccSCharles-Antoine Couret 			if (phydev->duplex == DUPLEX_FULL) {
11466cfb3bccSCharles-Antoine Couret 				if (!(lpa & LPA_PAUSE_FIBER)) {
11476cfb3bccSCharles-Antoine Couret 					phydev->pause = 0;
11486cfb3bccSCharles-Antoine Couret 					phydev->asym_pause = 0;
11496cfb3bccSCharles-Antoine Couret 				} else if ((lpa & LPA_PAUSE_ASYM_FIBER)) {
11506cfb3bccSCharles-Antoine Couret 					phydev->pause = 1;
11516cfb3bccSCharles-Antoine Couret 					phydev->asym_pause = 1;
11526cfb3bccSCharles-Antoine Couret 				} else {
11536cfb3bccSCharles-Antoine Couret 					phydev->pause = 1;
11546cfb3bccSCharles-Antoine Couret 					phydev->asym_pause = 0;
11556cfb3bccSCharles-Antoine Couret 				}
11566cfb3bccSCharles-Antoine Couret 			}
11576cfb3bccSCharles-Antoine Couret 		}
11586cfb3bccSCharles-Antoine Couret 	} else {
1159be937f1fSAlexandr Smirnov 		int bmcr = phy_read(phydev, MII_BMCR);
1160be937f1fSAlexandr Smirnov 
1161be937f1fSAlexandr Smirnov 		if (bmcr < 0)
1162be937f1fSAlexandr Smirnov 			return bmcr;
1163be937f1fSAlexandr Smirnov 
1164be937f1fSAlexandr Smirnov 		if (bmcr & BMCR_FULLDPLX)
1165be937f1fSAlexandr Smirnov 			phydev->duplex = DUPLEX_FULL;
1166be937f1fSAlexandr Smirnov 		else
1167be937f1fSAlexandr Smirnov 			phydev->duplex = DUPLEX_HALF;
1168be937f1fSAlexandr Smirnov 
1169be937f1fSAlexandr Smirnov 		if (bmcr & BMCR_SPEED1000)
1170be937f1fSAlexandr Smirnov 			phydev->speed = SPEED_1000;
1171be937f1fSAlexandr Smirnov 		else if (bmcr & BMCR_SPEED100)
1172be937f1fSAlexandr Smirnov 			phydev->speed = SPEED_100;
1173be937f1fSAlexandr Smirnov 		else
1174be937f1fSAlexandr Smirnov 			phydev->speed = SPEED_10;
1175be937f1fSAlexandr Smirnov 
1176be937f1fSAlexandr Smirnov 		phydev->pause = phydev->asym_pause = 0;
1177357cd64cSRussell King 		phydev->lp_advertising = 0;
1178be937f1fSAlexandr Smirnov 	}
1179be937f1fSAlexandr Smirnov 
1180be937f1fSAlexandr Smirnov 	return 0;
1181be937f1fSAlexandr Smirnov }
1182be937f1fSAlexandr Smirnov 
11836cfb3bccSCharles-Antoine Couret /* marvell_read_status
11846cfb3bccSCharles-Antoine Couret  *
11856cfb3bccSCharles-Antoine Couret  * Some Marvell's phys have two modes: fiber and copper.
11866cfb3bccSCharles-Antoine Couret  * Both need status checked.
11876cfb3bccSCharles-Antoine Couret  * Description:
11886cfb3bccSCharles-Antoine Couret  *   First, check the fiber link and status.
11896cfb3bccSCharles-Antoine Couret  *   If the fiber link is down, check the copper link and status which
11906cfb3bccSCharles-Antoine Couret  *   will be the default value if both link are down.
11916cfb3bccSCharles-Antoine Couret  */
11926cfb3bccSCharles-Antoine Couret static int marvell_read_status(struct phy_device *phydev)
11936cfb3bccSCharles-Antoine Couret {
11946cfb3bccSCharles-Antoine Couret 	int err;
11956cfb3bccSCharles-Antoine Couret 
11966cfb3bccSCharles-Antoine Couret 	/* Check the fiber mode first */
11976cfb3bccSCharles-Antoine Couret 	if (phydev->supported & SUPPORTED_FIBRE) {
11986cfb3bccSCharles-Antoine Couret 		err = phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_M1111_FIBER);
11996cfb3bccSCharles-Antoine Couret 		if (err < 0)
12006cfb3bccSCharles-Antoine Couret 			goto error;
12016cfb3bccSCharles-Antoine Couret 
12026cfb3bccSCharles-Antoine Couret 		err = marvell_read_status_page(phydev, MII_M1111_FIBER);
12036cfb3bccSCharles-Antoine Couret 		if (err < 0)
12046cfb3bccSCharles-Antoine Couret 			goto error;
12056cfb3bccSCharles-Antoine Couret 
12066cfb3bccSCharles-Antoine Couret 		/* If the fiber link is up, it is the selected and used link.
12076cfb3bccSCharles-Antoine Couret 		 * In this case, we need to stay in the fiber page.
12086cfb3bccSCharles-Antoine Couret 		 * Please to be careful about that, avoid to restore Copper page
12096cfb3bccSCharles-Antoine Couret 		 * in other functions which could break the behaviour
12106cfb3bccSCharles-Antoine Couret 		 * for some fiber phy like 88E1512.
12116cfb3bccSCharles-Antoine Couret 		 * */
12126cfb3bccSCharles-Antoine Couret 		if (phydev->link)
12136cfb3bccSCharles-Antoine Couret 			return 0;
12146cfb3bccSCharles-Antoine Couret 
12156cfb3bccSCharles-Antoine Couret 		/* If fiber link is down, check and save copper mode state */
12166cfb3bccSCharles-Antoine Couret 		err = phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_M1111_COPPER);
12176cfb3bccSCharles-Antoine Couret 		if (err < 0)
12186cfb3bccSCharles-Antoine Couret 			goto error;
12196cfb3bccSCharles-Antoine Couret 	}
12206cfb3bccSCharles-Antoine Couret 
12216cfb3bccSCharles-Antoine Couret 	return marvell_read_status_page(phydev, MII_M1111_COPPER);
12226cfb3bccSCharles-Antoine Couret 
12236cfb3bccSCharles-Antoine Couret error:
12246cfb3bccSCharles-Antoine Couret 	phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_M1111_COPPER);
12256cfb3bccSCharles-Antoine Couret 	return err;
12266cfb3bccSCharles-Antoine Couret }
12276b358aedSSebastian Hesselbarth static int marvell_aneg_done(struct phy_device *phydev)
12286b358aedSSebastian Hesselbarth {
12296b358aedSSebastian Hesselbarth 	int retval = phy_read(phydev, MII_M1011_PHY_STATUS);
12306b358aedSSebastian Hesselbarth 	return (retval < 0) ? retval : (retval & MII_M1011_PHY_STATUS_RESOLVED);
12316b358aedSSebastian Hesselbarth }
12326b358aedSSebastian Hesselbarth 
1233dcd07be3SAnatolij Gustschin static int m88e1121_did_interrupt(struct phy_device *phydev)
1234dcd07be3SAnatolij Gustschin {
1235dcd07be3SAnatolij Gustschin 	int imask;
1236dcd07be3SAnatolij Gustschin 
1237dcd07be3SAnatolij Gustschin 	imask = phy_read(phydev, MII_M1011_IEVENT);
1238dcd07be3SAnatolij Gustschin 
1239dcd07be3SAnatolij Gustschin 	if (imask & MII_M1011_IMASK_INIT)
1240dcd07be3SAnatolij Gustschin 		return 1;
1241dcd07be3SAnatolij Gustschin 
1242dcd07be3SAnatolij Gustschin 	return 0;
1243dcd07be3SAnatolij Gustschin }
1244dcd07be3SAnatolij Gustschin 
12453871c387SMichael Stapelberg static void m88e1318_get_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol)
12463871c387SMichael Stapelberg {
12473871c387SMichael Stapelberg 	wol->supported = WAKE_MAGIC;
12483871c387SMichael Stapelberg 	wol->wolopts = 0;
12493871c387SMichael Stapelberg 
12503871c387SMichael Stapelberg 	if (phy_write(phydev, MII_MARVELL_PHY_PAGE,
12513871c387SMichael Stapelberg 		      MII_88E1318S_PHY_WOL_PAGE) < 0)
12523871c387SMichael Stapelberg 		return;
12533871c387SMichael Stapelberg 
12543871c387SMichael Stapelberg 	if (phy_read(phydev, MII_88E1318S_PHY_WOL_CTRL) &
12553871c387SMichael Stapelberg 	    MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE)
12563871c387SMichael Stapelberg 		wol->wolopts |= WAKE_MAGIC;
12573871c387SMichael Stapelberg 
12583871c387SMichael Stapelberg 	if (phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x00) < 0)
12593871c387SMichael Stapelberg 		return;
12603871c387SMichael Stapelberg }
12613871c387SMichael Stapelberg 
12623871c387SMichael Stapelberg static int m88e1318_set_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol)
12633871c387SMichael Stapelberg {
12643871c387SMichael Stapelberg 	int err, oldpage, temp;
12653871c387SMichael Stapelberg 
12663871c387SMichael Stapelberg 	oldpage = phy_read(phydev, MII_MARVELL_PHY_PAGE);
12673871c387SMichael Stapelberg 
12683871c387SMichael Stapelberg 	if (wol->wolopts & WAKE_MAGIC) {
12693871c387SMichael Stapelberg 		/* Explicitly switch to page 0x00, just to be sure */
12703871c387SMichael Stapelberg 		err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x00);
12713871c387SMichael Stapelberg 		if (err < 0)
12723871c387SMichael Stapelberg 			return err;
12733871c387SMichael Stapelberg 
12743871c387SMichael Stapelberg 		/* Enable the WOL interrupt */
12753871c387SMichael Stapelberg 		temp = phy_read(phydev, MII_88E1318S_PHY_CSIER);
12763871c387SMichael Stapelberg 		temp |= MII_88E1318S_PHY_CSIER_WOL_EIE;
12773871c387SMichael Stapelberg 		err = phy_write(phydev, MII_88E1318S_PHY_CSIER, temp);
12783871c387SMichael Stapelberg 		if (err < 0)
12793871c387SMichael Stapelberg 			return err;
12803871c387SMichael Stapelberg 
12813871c387SMichael Stapelberg 		err = phy_write(phydev, MII_MARVELL_PHY_PAGE,
12823871c387SMichael Stapelberg 				MII_88E1318S_PHY_LED_PAGE);
12833871c387SMichael Stapelberg 		if (err < 0)
12843871c387SMichael Stapelberg 			return err;
12853871c387SMichael Stapelberg 
12863871c387SMichael Stapelberg 		/* Setup LED[2] as interrupt pin (active low) */
12873871c387SMichael Stapelberg 		temp = phy_read(phydev, MII_88E1318S_PHY_LED_TCR);
12883871c387SMichael Stapelberg 		temp &= ~MII_88E1318S_PHY_LED_TCR_FORCE_INT;
12893871c387SMichael Stapelberg 		temp |= MII_88E1318S_PHY_LED_TCR_INTn_ENABLE;
12903871c387SMichael Stapelberg 		temp |= MII_88E1318S_PHY_LED_TCR_INT_ACTIVE_LOW;
12913871c387SMichael Stapelberg 		err = phy_write(phydev, MII_88E1318S_PHY_LED_TCR, temp);
12923871c387SMichael Stapelberg 		if (err < 0)
12933871c387SMichael Stapelberg 			return err;
12943871c387SMichael Stapelberg 
12953871c387SMichael Stapelberg 		err = phy_write(phydev, MII_MARVELL_PHY_PAGE,
12963871c387SMichael Stapelberg 				MII_88E1318S_PHY_WOL_PAGE);
12973871c387SMichael Stapelberg 		if (err < 0)
12983871c387SMichael Stapelberg 			return err;
12993871c387SMichael Stapelberg 
13003871c387SMichael Stapelberg 		/* Store the device address for the magic packet */
13013871c387SMichael Stapelberg 		err = phy_write(phydev, MII_88E1318S_PHY_MAGIC_PACKET_WORD2,
13023871c387SMichael Stapelberg 				((phydev->attached_dev->dev_addr[5] << 8) |
13033871c387SMichael Stapelberg 				 phydev->attached_dev->dev_addr[4]));
13043871c387SMichael Stapelberg 		if (err < 0)
13053871c387SMichael Stapelberg 			return err;
13063871c387SMichael Stapelberg 		err = phy_write(phydev, MII_88E1318S_PHY_MAGIC_PACKET_WORD1,
13073871c387SMichael Stapelberg 				((phydev->attached_dev->dev_addr[3] << 8) |
13083871c387SMichael Stapelberg 				 phydev->attached_dev->dev_addr[2]));
13093871c387SMichael Stapelberg 		if (err < 0)
13103871c387SMichael Stapelberg 			return err;
13113871c387SMichael Stapelberg 		err = phy_write(phydev, MII_88E1318S_PHY_MAGIC_PACKET_WORD0,
13123871c387SMichael Stapelberg 				((phydev->attached_dev->dev_addr[1] << 8) |
13133871c387SMichael Stapelberg 				 phydev->attached_dev->dev_addr[0]));
13143871c387SMichael Stapelberg 		if (err < 0)
13153871c387SMichael Stapelberg 			return err;
13163871c387SMichael Stapelberg 
13173871c387SMichael Stapelberg 		/* Clear WOL status and enable magic packet matching */
13183871c387SMichael Stapelberg 		temp = phy_read(phydev, MII_88E1318S_PHY_WOL_CTRL);
13193871c387SMichael Stapelberg 		temp |= MII_88E1318S_PHY_WOL_CTRL_CLEAR_WOL_STATUS;
13203871c387SMichael Stapelberg 		temp |= MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE;
13213871c387SMichael Stapelberg 		err = phy_write(phydev, MII_88E1318S_PHY_WOL_CTRL, temp);
13223871c387SMichael Stapelberg 		if (err < 0)
13233871c387SMichael Stapelberg 			return err;
13243871c387SMichael Stapelberg 	} else {
13253871c387SMichael Stapelberg 		err = phy_write(phydev, MII_MARVELL_PHY_PAGE,
13263871c387SMichael Stapelberg 				MII_88E1318S_PHY_WOL_PAGE);
13273871c387SMichael Stapelberg 		if (err < 0)
13283871c387SMichael Stapelberg 			return err;
13293871c387SMichael Stapelberg 
13303871c387SMichael Stapelberg 		/* Clear WOL status and disable magic packet matching */
13313871c387SMichael Stapelberg 		temp = phy_read(phydev, MII_88E1318S_PHY_WOL_CTRL);
13323871c387SMichael Stapelberg 		temp |= MII_88E1318S_PHY_WOL_CTRL_CLEAR_WOL_STATUS;
13333871c387SMichael Stapelberg 		temp &= ~MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE;
13343871c387SMichael Stapelberg 		err = phy_write(phydev, MII_88E1318S_PHY_WOL_CTRL, temp);
13353871c387SMichael Stapelberg 		if (err < 0)
13363871c387SMichael Stapelberg 			return err;
13373871c387SMichael Stapelberg 	}
13383871c387SMichael Stapelberg 
13393871c387SMichael Stapelberg 	err = phy_write(phydev, MII_MARVELL_PHY_PAGE, oldpage);
13403871c387SMichael Stapelberg 	if (err < 0)
13413871c387SMichael Stapelberg 		return err;
13423871c387SMichael Stapelberg 
13433871c387SMichael Stapelberg 	return 0;
13443871c387SMichael Stapelberg }
13453871c387SMichael Stapelberg 
1346d2fa47d9SAndrew Lunn static int marvell_get_sset_count(struct phy_device *phydev)
1347d2fa47d9SAndrew Lunn {
13482170fef7SCharles-Antoine Couret 	if (phydev->supported & SUPPORTED_FIBRE)
1349d2fa47d9SAndrew Lunn 		return ARRAY_SIZE(marvell_hw_stats);
13502170fef7SCharles-Antoine Couret 	else
13512170fef7SCharles-Antoine Couret 		return ARRAY_SIZE(marvell_hw_stats) - NB_FIBER_STATS;
1352d2fa47d9SAndrew Lunn }
1353d2fa47d9SAndrew Lunn 
1354d2fa47d9SAndrew Lunn static void marvell_get_strings(struct phy_device *phydev, u8 *data)
1355d2fa47d9SAndrew Lunn {
1356d2fa47d9SAndrew Lunn 	int i;
1357d2fa47d9SAndrew Lunn 
1358d2fa47d9SAndrew Lunn 	for (i = 0; i < ARRAY_SIZE(marvell_hw_stats); i++) {
1359d2fa47d9SAndrew Lunn 		memcpy(data + i * ETH_GSTRING_LEN,
1360d2fa47d9SAndrew Lunn 		       marvell_hw_stats[i].string, ETH_GSTRING_LEN);
1361d2fa47d9SAndrew Lunn 	}
1362d2fa47d9SAndrew Lunn }
1363d2fa47d9SAndrew Lunn 
1364d2fa47d9SAndrew Lunn #ifndef UINT64_MAX
1365d2fa47d9SAndrew Lunn #define UINT64_MAX              (u64)(~((u64)0))
1366d2fa47d9SAndrew Lunn #endif
1367d2fa47d9SAndrew Lunn static u64 marvell_get_stat(struct phy_device *phydev, int i)
1368d2fa47d9SAndrew Lunn {
1369d2fa47d9SAndrew Lunn 	struct marvell_hw_stat stat = marvell_hw_stats[i];
1370d2fa47d9SAndrew Lunn 	struct marvell_priv *priv = phydev->priv;
1371321b4d4bSAndrew Lunn 	int err, oldpage, val;
1372321b4d4bSAndrew Lunn 	u64 ret;
1373d2fa47d9SAndrew Lunn 
1374d2fa47d9SAndrew Lunn 	oldpage = phy_read(phydev, MII_MARVELL_PHY_PAGE);
1375d2fa47d9SAndrew Lunn 	err = phy_write(phydev, MII_MARVELL_PHY_PAGE,
1376d2fa47d9SAndrew Lunn 			stat.page);
1377d2fa47d9SAndrew Lunn 	if (err < 0)
1378d2fa47d9SAndrew Lunn 		return UINT64_MAX;
1379d2fa47d9SAndrew Lunn 
1380d2fa47d9SAndrew Lunn 	val = phy_read(phydev, stat.reg);
1381d2fa47d9SAndrew Lunn 	if (val < 0) {
1382321b4d4bSAndrew Lunn 		ret = UINT64_MAX;
1383d2fa47d9SAndrew Lunn 	} else {
1384d2fa47d9SAndrew Lunn 		val = val & ((1 << stat.bits) - 1);
1385d2fa47d9SAndrew Lunn 		priv->stats[i] += val;
1386321b4d4bSAndrew Lunn 		ret = priv->stats[i];
1387d2fa47d9SAndrew Lunn 	}
1388d2fa47d9SAndrew Lunn 
1389d2fa47d9SAndrew Lunn 	phy_write(phydev, MII_MARVELL_PHY_PAGE, oldpage);
1390d2fa47d9SAndrew Lunn 
1391321b4d4bSAndrew Lunn 	return ret;
1392d2fa47d9SAndrew Lunn }
1393d2fa47d9SAndrew Lunn 
1394d2fa47d9SAndrew Lunn static void marvell_get_stats(struct phy_device *phydev,
1395d2fa47d9SAndrew Lunn 			      struct ethtool_stats *stats, u64 *data)
1396d2fa47d9SAndrew Lunn {
1397d2fa47d9SAndrew Lunn 	int i;
1398d2fa47d9SAndrew Lunn 
1399d2fa47d9SAndrew Lunn 	for (i = 0; i < ARRAY_SIZE(marvell_hw_stats); i++)
1400d2fa47d9SAndrew Lunn 		data[i] = marvell_get_stat(phydev, i);
1401d2fa47d9SAndrew Lunn }
1402d2fa47d9SAndrew Lunn 
1403d2fa47d9SAndrew Lunn static int marvell_probe(struct phy_device *phydev)
1404d2fa47d9SAndrew Lunn {
1405d2fa47d9SAndrew Lunn 	struct marvell_priv *priv;
1406d2fa47d9SAndrew Lunn 
1407e5a03bfdSAndrew Lunn 	priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL);
1408d2fa47d9SAndrew Lunn 	if (!priv)
1409d2fa47d9SAndrew Lunn 		return -ENOMEM;
1410d2fa47d9SAndrew Lunn 
1411d2fa47d9SAndrew Lunn 	phydev->priv = priv;
1412d2fa47d9SAndrew Lunn 
1413d2fa47d9SAndrew Lunn 	return 0;
1414d2fa47d9SAndrew Lunn }
1415d2fa47d9SAndrew Lunn 
1416e5479239SOlof Johansson static struct phy_driver marvell_drivers[] = {
1417e5479239SOlof Johansson 	{
14182f495c39SBenjamin Herrenschmidt 		.phy_id = MARVELL_PHY_ID_88E1101,
14192f495c39SBenjamin Herrenschmidt 		.phy_id_mask = MARVELL_PHY_ID_MASK,
142000db8189SAndy Fleming 		.name = "Marvell 88E1101",
142100db8189SAndy Fleming 		.features = PHY_GBIT_FEATURES,
1422d2fa47d9SAndrew Lunn 		.probe = marvell_probe,
142300db8189SAndy Fleming 		.flags = PHY_HAS_INTERRUPT,
142479be1a1cSClemens Gruber 		.config_init = &marvell_config_init,
142500db8189SAndy Fleming 		.config_aneg = &marvell_config_aneg,
142600db8189SAndy Fleming 		.read_status = &genphy_read_status,
142700db8189SAndy Fleming 		.ack_interrupt = &marvell_ack_interrupt,
142800db8189SAndy Fleming 		.config_intr = &marvell_config_intr,
14290898b448SSebastian Hesselbarth 		.resume = &genphy_resume,
14300898b448SSebastian Hesselbarth 		.suspend = &genphy_suspend,
1431d2fa47d9SAndrew Lunn 		.get_sset_count = marvell_get_sset_count,
1432d2fa47d9SAndrew Lunn 		.get_strings = marvell_get_strings,
1433d2fa47d9SAndrew Lunn 		.get_stats = marvell_get_stats,
1434e5479239SOlof Johansson 	},
1435e5479239SOlof Johansson 	{
14362f495c39SBenjamin Herrenschmidt 		.phy_id = MARVELL_PHY_ID_88E1112,
14372f495c39SBenjamin Herrenschmidt 		.phy_id_mask = MARVELL_PHY_ID_MASK,
143885cfb534SOlof Johansson 		.name = "Marvell 88E1112",
143985cfb534SOlof Johansson 		.features = PHY_GBIT_FEATURES,
144085cfb534SOlof Johansson 		.flags = PHY_HAS_INTERRUPT,
1441d2fa47d9SAndrew Lunn 		.probe = marvell_probe,
144285cfb534SOlof Johansson 		.config_init = &m88e1111_config_init,
144385cfb534SOlof Johansson 		.config_aneg = &marvell_config_aneg,
144485cfb534SOlof Johansson 		.read_status = &genphy_read_status,
144585cfb534SOlof Johansson 		.ack_interrupt = &marvell_ack_interrupt,
144685cfb534SOlof Johansson 		.config_intr = &marvell_config_intr,
14470898b448SSebastian Hesselbarth 		.resume = &genphy_resume,
14480898b448SSebastian Hesselbarth 		.suspend = &genphy_suspend,
1449d2fa47d9SAndrew Lunn 		.get_sset_count = marvell_get_sset_count,
1450d2fa47d9SAndrew Lunn 		.get_strings = marvell_get_strings,
1451d2fa47d9SAndrew Lunn 		.get_stats = marvell_get_stats,
145285cfb534SOlof Johansson 	},
145385cfb534SOlof Johansson 	{
14542f495c39SBenjamin Herrenschmidt 		.phy_id = MARVELL_PHY_ID_88E1111,
14552f495c39SBenjamin Herrenschmidt 		.phy_id_mask = MARVELL_PHY_ID_MASK,
145676884679SAndy Fleming 		.name = "Marvell 88E1111",
145776884679SAndy Fleming 		.features = PHY_GBIT_FEATURES,
145876884679SAndy Fleming 		.flags = PHY_HAS_INTERRUPT,
1459d2fa47d9SAndrew Lunn 		.probe = marvell_probe,
1460e5479239SOlof Johansson 		.config_init = &m88e1111_config_init,
14613ec0a0f1SHarini Katakam 		.config_aneg = &m88e1111_config_aneg,
1462be937f1fSAlexandr Smirnov 		.read_status = &marvell_read_status,
146376884679SAndy Fleming 		.ack_interrupt = &marvell_ack_interrupt,
146476884679SAndy Fleming 		.config_intr = &marvell_config_intr,
14650898b448SSebastian Hesselbarth 		.resume = &genphy_resume,
14660898b448SSebastian Hesselbarth 		.suspend = &genphy_suspend,
1467d2fa47d9SAndrew Lunn 		.get_sset_count = marvell_get_sset_count,
1468d2fa47d9SAndrew Lunn 		.get_strings = marvell_get_strings,
1469d2fa47d9SAndrew Lunn 		.get_stats = marvell_get_stats,
1470e5479239SOlof Johansson 	},
1471e5479239SOlof Johansson 	{
14722f495c39SBenjamin Herrenschmidt 		.phy_id = MARVELL_PHY_ID_88E1118,
14732f495c39SBenjamin Herrenschmidt 		.phy_id_mask = MARVELL_PHY_ID_MASK,
1474605f196eSRon Madrid 		.name = "Marvell 88E1118",
1475605f196eSRon Madrid 		.features = PHY_GBIT_FEATURES,
1476605f196eSRon Madrid 		.flags = PHY_HAS_INTERRUPT,
1477d2fa47d9SAndrew Lunn 		.probe = marvell_probe,
1478605f196eSRon Madrid 		.config_init = &m88e1118_config_init,
1479605f196eSRon Madrid 		.config_aneg = &m88e1118_config_aneg,
1480605f196eSRon Madrid 		.read_status = &genphy_read_status,
1481605f196eSRon Madrid 		.ack_interrupt = &marvell_ack_interrupt,
1482605f196eSRon Madrid 		.config_intr = &marvell_config_intr,
14830898b448SSebastian Hesselbarth 		.resume = &genphy_resume,
14840898b448SSebastian Hesselbarth 		.suspend = &genphy_suspend,
1485d2fa47d9SAndrew Lunn 		.get_sset_count = marvell_get_sset_count,
1486d2fa47d9SAndrew Lunn 		.get_strings = marvell_get_strings,
1487d2fa47d9SAndrew Lunn 		.get_stats = marvell_get_stats,
1488605f196eSRon Madrid 	},
1489605f196eSRon Madrid 	{
14902f495c39SBenjamin Herrenschmidt 		.phy_id = MARVELL_PHY_ID_88E1121R,
14912f495c39SBenjamin Herrenschmidt 		.phy_id_mask = MARVELL_PHY_ID_MASK,
1492140bc929SSergei Poselenov 		.name = "Marvell 88E1121R",
1493140bc929SSergei Poselenov 		.features = PHY_GBIT_FEATURES,
1494140bc929SSergei Poselenov 		.flags = PHY_HAS_INTERRUPT,
1495d2fa47d9SAndrew Lunn 		.probe = marvell_probe,
1496fdecf36fSClemens Gruber 		.config_init = &m88e1121_config_init,
1497140bc929SSergei Poselenov 		.config_aneg = &m88e1121_config_aneg,
1498140bc929SSergei Poselenov 		.read_status = &marvell_read_status,
1499140bc929SSergei Poselenov 		.ack_interrupt = &marvell_ack_interrupt,
1500140bc929SSergei Poselenov 		.config_intr = &marvell_config_intr,
1501dcd07be3SAnatolij Gustschin 		.did_interrupt = &m88e1121_did_interrupt,
15020898b448SSebastian Hesselbarth 		.resume = &genphy_resume,
15030898b448SSebastian Hesselbarth 		.suspend = &genphy_suspend,
1504d2fa47d9SAndrew Lunn 		.get_sset_count = marvell_get_sset_count,
1505d2fa47d9SAndrew Lunn 		.get_strings = marvell_get_strings,
1506d2fa47d9SAndrew Lunn 		.get_stats = marvell_get_stats,
1507140bc929SSergei Poselenov 	},
1508140bc929SSergei Poselenov 	{
1509337ac9d5SCyril Chemparathy 		.phy_id = MARVELL_PHY_ID_88E1318S,
15106ba74014SLinus Torvalds 		.phy_id_mask = MARVELL_PHY_ID_MASK,
1511337ac9d5SCyril Chemparathy 		.name = "Marvell 88E1318S",
15123ff1c259SCyril Chemparathy 		.features = PHY_GBIT_FEATURES,
15133ff1c259SCyril Chemparathy 		.flags = PHY_HAS_INTERRUPT,
1514d2fa47d9SAndrew Lunn 		.probe = marvell_probe,
1515fdecf36fSClemens Gruber 		.config_init = &m88e1121_config_init,
1516337ac9d5SCyril Chemparathy 		.config_aneg = &m88e1318_config_aneg,
15173ff1c259SCyril Chemparathy 		.read_status = &marvell_read_status,
15183ff1c259SCyril Chemparathy 		.ack_interrupt = &marvell_ack_interrupt,
15193ff1c259SCyril Chemparathy 		.config_intr = &marvell_config_intr,
15203ff1c259SCyril Chemparathy 		.did_interrupt = &m88e1121_did_interrupt,
15213871c387SMichael Stapelberg 		.get_wol = &m88e1318_get_wol,
15223871c387SMichael Stapelberg 		.set_wol = &m88e1318_set_wol,
15230898b448SSebastian Hesselbarth 		.resume = &genphy_resume,
15240898b448SSebastian Hesselbarth 		.suspend = &genphy_suspend,
1525d2fa47d9SAndrew Lunn 		.get_sset_count = marvell_get_sset_count,
1526d2fa47d9SAndrew Lunn 		.get_strings = marvell_get_strings,
1527d2fa47d9SAndrew Lunn 		.get_stats = marvell_get_stats,
15283ff1c259SCyril Chemparathy 	},
15293ff1c259SCyril Chemparathy 	{
15302f495c39SBenjamin Herrenschmidt 		.phy_id = MARVELL_PHY_ID_88E1145,
15312f495c39SBenjamin Herrenschmidt 		.phy_id_mask = MARVELL_PHY_ID_MASK,
153276884679SAndy Fleming 		.name = "Marvell 88E1145",
153376884679SAndy Fleming 		.features = PHY_GBIT_FEATURES,
153476884679SAndy Fleming 		.flags = PHY_HAS_INTERRUPT,
1535d2fa47d9SAndrew Lunn 		.probe = marvell_probe,
153676884679SAndy Fleming 		.config_init = &m88e1145_config_init,
153776884679SAndy Fleming 		.config_aneg = &marvell_config_aneg,
153876884679SAndy Fleming 		.read_status = &genphy_read_status,
153976884679SAndy Fleming 		.ack_interrupt = &marvell_ack_interrupt,
154076884679SAndy Fleming 		.config_intr = &marvell_config_intr,
15410898b448SSebastian Hesselbarth 		.resume = &genphy_resume,
15420898b448SSebastian Hesselbarth 		.suspend = &genphy_suspend,
1543d2fa47d9SAndrew Lunn 		.get_sset_count = marvell_get_sset_count,
1544d2fa47d9SAndrew Lunn 		.get_strings = marvell_get_strings,
1545d2fa47d9SAndrew Lunn 		.get_stats = marvell_get_stats,
1546ac8c635aSOlof Johansson 	},
1547ac8c635aSOlof Johansson 	{
154890600732SDavid Daney 		.phy_id = MARVELL_PHY_ID_88E1149R,
154990600732SDavid Daney 		.phy_id_mask = MARVELL_PHY_ID_MASK,
155090600732SDavid Daney 		.name = "Marvell 88E1149R",
155190600732SDavid Daney 		.features = PHY_GBIT_FEATURES,
155290600732SDavid Daney 		.flags = PHY_HAS_INTERRUPT,
1553d2fa47d9SAndrew Lunn 		.probe = marvell_probe,
155490600732SDavid Daney 		.config_init = &m88e1149_config_init,
155590600732SDavid Daney 		.config_aneg = &m88e1118_config_aneg,
155690600732SDavid Daney 		.read_status = &genphy_read_status,
155790600732SDavid Daney 		.ack_interrupt = &marvell_ack_interrupt,
155890600732SDavid Daney 		.config_intr = &marvell_config_intr,
15590898b448SSebastian Hesselbarth 		.resume = &genphy_resume,
15600898b448SSebastian Hesselbarth 		.suspend = &genphy_suspend,
1561d2fa47d9SAndrew Lunn 		.get_sset_count = marvell_get_sset_count,
1562d2fa47d9SAndrew Lunn 		.get_strings = marvell_get_strings,
1563d2fa47d9SAndrew Lunn 		.get_stats = marvell_get_stats,
156490600732SDavid Daney 	},
156590600732SDavid Daney 	{
15662f495c39SBenjamin Herrenschmidt 		.phy_id = MARVELL_PHY_ID_88E1240,
15672f495c39SBenjamin Herrenschmidt 		.phy_id_mask = MARVELL_PHY_ID_MASK,
1568ac8c635aSOlof Johansson 		.name = "Marvell 88E1240",
1569ac8c635aSOlof Johansson 		.features = PHY_GBIT_FEATURES,
1570ac8c635aSOlof Johansson 		.flags = PHY_HAS_INTERRUPT,
1571d2fa47d9SAndrew Lunn 		.probe = marvell_probe,
1572ac8c635aSOlof Johansson 		.config_init = &m88e1111_config_init,
1573ac8c635aSOlof Johansson 		.config_aneg = &marvell_config_aneg,
1574ac8c635aSOlof Johansson 		.read_status = &genphy_read_status,
1575ac8c635aSOlof Johansson 		.ack_interrupt = &marvell_ack_interrupt,
1576ac8c635aSOlof Johansson 		.config_intr = &marvell_config_intr,
15770898b448SSebastian Hesselbarth 		.resume = &genphy_resume,
15780898b448SSebastian Hesselbarth 		.suspend = &genphy_suspend,
1579d2fa47d9SAndrew Lunn 		.get_sset_count = marvell_get_sset_count,
1580d2fa47d9SAndrew Lunn 		.get_strings = marvell_get_strings,
1581d2fa47d9SAndrew Lunn 		.get_stats = marvell_get_stats,
1582ac8c635aSOlof Johansson 	},
15833da09a51SMichal Simek 	{
15843da09a51SMichal Simek 		.phy_id = MARVELL_PHY_ID_88E1116R,
15853da09a51SMichal Simek 		.phy_id_mask = MARVELL_PHY_ID_MASK,
15863da09a51SMichal Simek 		.name = "Marvell 88E1116R",
15873da09a51SMichal Simek 		.features = PHY_GBIT_FEATURES,
15883da09a51SMichal Simek 		.flags = PHY_HAS_INTERRUPT,
1589d2fa47d9SAndrew Lunn 		.probe = marvell_probe,
15903da09a51SMichal Simek 		.config_init = &m88e1116r_config_init,
15913da09a51SMichal Simek 		.config_aneg = &genphy_config_aneg,
15923da09a51SMichal Simek 		.read_status = &genphy_read_status,
15933da09a51SMichal Simek 		.ack_interrupt = &marvell_ack_interrupt,
15943da09a51SMichal Simek 		.config_intr = &marvell_config_intr,
15950898b448SSebastian Hesselbarth 		.resume = &genphy_resume,
15960898b448SSebastian Hesselbarth 		.suspend = &genphy_suspend,
1597d2fa47d9SAndrew Lunn 		.get_sset_count = marvell_get_sset_count,
1598d2fa47d9SAndrew Lunn 		.get_strings = marvell_get_strings,
1599d2fa47d9SAndrew Lunn 		.get_stats = marvell_get_stats,
16003da09a51SMichal Simek 	},
160110e24caaSMichal Simek 	{
160210e24caaSMichal Simek 		.phy_id = MARVELL_PHY_ID_88E1510,
160310e24caaSMichal Simek 		.phy_id_mask = MARVELL_PHY_ID_MASK,
160410e24caaSMichal Simek 		.name = "Marvell 88E1510",
16056cfb3bccSCharles-Antoine Couret 		.features = PHY_GBIT_FEATURES | SUPPORTED_FIBRE,
160610e24caaSMichal Simek 		.flags = PHY_HAS_INTERRUPT,
1607d2fa47d9SAndrew Lunn 		.probe = marvell_probe,
1608930b37eeSStefan Roese 		.config_init = &m88e1510_config_init,
160910e24caaSMichal Simek 		.config_aneg = &m88e1510_config_aneg,
161010e24caaSMichal Simek 		.read_status = &marvell_read_status,
161110e24caaSMichal Simek 		.ack_interrupt = &marvell_ack_interrupt,
161210e24caaSMichal Simek 		.config_intr = &marvell_config_intr,
161310e24caaSMichal Simek 		.did_interrupt = &m88e1121_did_interrupt,
16140898b448SSebastian Hesselbarth 		.resume = &genphy_resume,
16150898b448SSebastian Hesselbarth 		.suspend = &genphy_suspend,
1616d2fa47d9SAndrew Lunn 		.get_sset_count = marvell_get_sset_count,
1617d2fa47d9SAndrew Lunn 		.get_strings = marvell_get_strings,
1618d2fa47d9SAndrew Lunn 		.get_stats = marvell_get_stats,
161910e24caaSMichal Simek 	},
16206b358aedSSebastian Hesselbarth 	{
1621819ec8e1SAndrew Lunn 		.phy_id = MARVELL_PHY_ID_88E1540,
1622819ec8e1SAndrew Lunn 		.phy_id_mask = MARVELL_PHY_ID_MASK,
1623819ec8e1SAndrew Lunn 		.name = "Marvell 88E1540",
1624819ec8e1SAndrew Lunn 		.features = PHY_GBIT_FEATURES,
1625819ec8e1SAndrew Lunn 		.flags = PHY_HAS_INTERRUPT,
1626d2fa47d9SAndrew Lunn 		.probe = marvell_probe,
162779be1a1cSClemens Gruber 		.config_init = &marvell_config_init,
1628819ec8e1SAndrew Lunn 		.config_aneg = &m88e1510_config_aneg,
1629819ec8e1SAndrew Lunn 		.read_status = &marvell_read_status,
1630819ec8e1SAndrew Lunn 		.ack_interrupt = &marvell_ack_interrupt,
1631819ec8e1SAndrew Lunn 		.config_intr = &marvell_config_intr,
1632819ec8e1SAndrew Lunn 		.did_interrupt = &m88e1121_did_interrupt,
1633819ec8e1SAndrew Lunn 		.resume = &genphy_resume,
1634819ec8e1SAndrew Lunn 		.suspend = &genphy_suspend,
1635d2fa47d9SAndrew Lunn 		.get_sset_count = marvell_get_sset_count,
1636d2fa47d9SAndrew Lunn 		.get_strings = marvell_get_strings,
1637d2fa47d9SAndrew Lunn 		.get_stats = marvell_get_stats,
1638819ec8e1SAndrew Lunn 	},
1639819ec8e1SAndrew Lunn 	{
16406b358aedSSebastian Hesselbarth 		.phy_id = MARVELL_PHY_ID_88E3016,
16416b358aedSSebastian Hesselbarth 		.phy_id_mask = MARVELL_PHY_ID_MASK,
16426b358aedSSebastian Hesselbarth 		.name = "Marvell 88E3016",
16436b358aedSSebastian Hesselbarth 		.features = PHY_BASIC_FEATURES,
16446b358aedSSebastian Hesselbarth 		.flags = PHY_HAS_INTERRUPT,
1645d2fa47d9SAndrew Lunn 		.probe = marvell_probe,
16466b358aedSSebastian Hesselbarth 		.config_aneg = &genphy_config_aneg,
16476b358aedSSebastian Hesselbarth 		.config_init = &m88e3016_config_init,
16486b358aedSSebastian Hesselbarth 		.aneg_done = &marvell_aneg_done,
16496b358aedSSebastian Hesselbarth 		.read_status = &marvell_read_status,
16506b358aedSSebastian Hesselbarth 		.ack_interrupt = &marvell_ack_interrupt,
16516b358aedSSebastian Hesselbarth 		.config_intr = &marvell_config_intr,
16526b358aedSSebastian Hesselbarth 		.did_interrupt = &m88e1121_did_interrupt,
16536b358aedSSebastian Hesselbarth 		.resume = &genphy_resume,
16546b358aedSSebastian Hesselbarth 		.suspend = &genphy_suspend,
1655d2fa47d9SAndrew Lunn 		.get_sset_count = marvell_get_sset_count,
1656d2fa47d9SAndrew Lunn 		.get_strings = marvell_get_strings,
1657d2fa47d9SAndrew Lunn 		.get_stats = marvell_get_stats,
16586b358aedSSebastian Hesselbarth 	},
165976884679SAndy Fleming };
166076884679SAndy Fleming 
166150fd7150SJohan Hovold module_phy_driver(marvell_drivers);
16624e4f10f6SDavid Woodhouse 
1663cf93c945SUwe Kleine-König static struct mdio_device_id __maybe_unused marvell_tbl[] = {
1664f5e1cabfSMichal Simek 	{ MARVELL_PHY_ID_88E1101, MARVELL_PHY_ID_MASK },
1665f5e1cabfSMichal Simek 	{ MARVELL_PHY_ID_88E1112, MARVELL_PHY_ID_MASK },
1666f5e1cabfSMichal Simek 	{ MARVELL_PHY_ID_88E1111, MARVELL_PHY_ID_MASK },
1667f5e1cabfSMichal Simek 	{ MARVELL_PHY_ID_88E1118, MARVELL_PHY_ID_MASK },
1668f5e1cabfSMichal Simek 	{ MARVELL_PHY_ID_88E1121R, MARVELL_PHY_ID_MASK },
1669f5e1cabfSMichal Simek 	{ MARVELL_PHY_ID_88E1145, MARVELL_PHY_ID_MASK },
1670f5e1cabfSMichal Simek 	{ MARVELL_PHY_ID_88E1149R, MARVELL_PHY_ID_MASK },
1671f5e1cabfSMichal Simek 	{ MARVELL_PHY_ID_88E1240, MARVELL_PHY_ID_MASK },
1672f5e1cabfSMichal Simek 	{ MARVELL_PHY_ID_88E1318S, MARVELL_PHY_ID_MASK },
16733da09a51SMichal Simek 	{ MARVELL_PHY_ID_88E1116R, MARVELL_PHY_ID_MASK },
167410e24caaSMichal Simek 	{ MARVELL_PHY_ID_88E1510, MARVELL_PHY_ID_MASK },
1675819ec8e1SAndrew Lunn 	{ MARVELL_PHY_ID_88E1540, MARVELL_PHY_ID_MASK },
16766b358aedSSebastian Hesselbarth 	{ MARVELL_PHY_ID_88E3016, MARVELL_PHY_ID_MASK },
16774e4f10f6SDavid Woodhouse 	{ }
16784e4f10f6SDavid Woodhouse };
16794e4f10f6SDavid Woodhouse 
16804e4f10f6SDavid Woodhouse MODULE_DEVICE_TABLE(mdio, marvell_tbl);
1681