xref: /openbmc/linux/drivers/net/phy/marvell.c (revision 3ec0a0f1)
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 
14100db8189SAndy Fleming MODULE_DESCRIPTION("Marvell PHY driver");
14200db8189SAndy Fleming MODULE_AUTHOR("Andy Fleming");
14300db8189SAndy Fleming MODULE_LICENSE("GPL");
14400db8189SAndy Fleming 
145d2fa47d9SAndrew Lunn struct marvell_hw_stat {
146d2fa47d9SAndrew Lunn 	const char *string;
147d2fa47d9SAndrew Lunn 	u8 page;
148d2fa47d9SAndrew Lunn 	u8 reg;
149d2fa47d9SAndrew Lunn 	u8 bits;
150d2fa47d9SAndrew Lunn };
151d2fa47d9SAndrew Lunn 
152d2fa47d9SAndrew Lunn static struct marvell_hw_stat marvell_hw_stats[] = {
153d2fa47d9SAndrew Lunn 	{ "phy_receive_errors", 0, 21, 16},
154d2fa47d9SAndrew Lunn 	{ "phy_idle_errors", 0, 10, 8 },
155d2fa47d9SAndrew Lunn };
156d2fa47d9SAndrew Lunn 
157d2fa47d9SAndrew Lunn struct marvell_priv {
158d2fa47d9SAndrew Lunn 	u64 stats[ARRAY_SIZE(marvell_hw_stats)];
159d2fa47d9SAndrew Lunn };
160d2fa47d9SAndrew Lunn 
16100db8189SAndy Fleming static int marvell_ack_interrupt(struct phy_device *phydev)
16200db8189SAndy Fleming {
16300db8189SAndy Fleming 	int err;
16400db8189SAndy Fleming 
16500db8189SAndy Fleming 	/* Clear the interrupts by reading the reg */
16600db8189SAndy Fleming 	err = phy_read(phydev, MII_M1011_IEVENT);
16700db8189SAndy Fleming 
16800db8189SAndy Fleming 	if (err < 0)
16900db8189SAndy Fleming 		return err;
17000db8189SAndy Fleming 
17100db8189SAndy Fleming 	return 0;
17200db8189SAndy Fleming }
17300db8189SAndy Fleming 
17400db8189SAndy Fleming static int marvell_config_intr(struct phy_device *phydev)
17500db8189SAndy Fleming {
17600db8189SAndy Fleming 	int err;
17700db8189SAndy Fleming 
17800db8189SAndy Fleming 	if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
17900db8189SAndy Fleming 		err = phy_write(phydev, MII_M1011_IMASK, MII_M1011_IMASK_INIT);
18000db8189SAndy Fleming 	else
18100db8189SAndy Fleming 		err = phy_write(phydev, MII_M1011_IMASK, MII_M1011_IMASK_CLEAR);
18200db8189SAndy Fleming 
18300db8189SAndy Fleming 	return err;
18400db8189SAndy Fleming }
18500db8189SAndy Fleming 
186239aa55bSDavid Thomson static int marvell_set_polarity(struct phy_device *phydev, int polarity)
187239aa55bSDavid Thomson {
188239aa55bSDavid Thomson 	int reg;
189239aa55bSDavid Thomson 	int err;
190239aa55bSDavid Thomson 	int val;
191239aa55bSDavid Thomson 
192239aa55bSDavid Thomson 	/* get the current settings */
193239aa55bSDavid Thomson 	reg = phy_read(phydev, MII_M1011_PHY_SCR);
194239aa55bSDavid Thomson 	if (reg < 0)
195239aa55bSDavid Thomson 		return reg;
196239aa55bSDavid Thomson 
197239aa55bSDavid Thomson 	val = reg;
198239aa55bSDavid Thomson 	val &= ~MII_M1011_PHY_SCR_AUTO_CROSS;
199239aa55bSDavid Thomson 	switch (polarity) {
200239aa55bSDavid Thomson 	case ETH_TP_MDI:
201239aa55bSDavid Thomson 		val |= MII_M1011_PHY_SCR_MDI;
202239aa55bSDavid Thomson 		break;
203239aa55bSDavid Thomson 	case ETH_TP_MDI_X:
204239aa55bSDavid Thomson 		val |= MII_M1011_PHY_SCR_MDI_X;
205239aa55bSDavid Thomson 		break;
206239aa55bSDavid Thomson 	case ETH_TP_MDI_AUTO:
207239aa55bSDavid Thomson 	case ETH_TP_MDI_INVALID:
208239aa55bSDavid Thomson 	default:
209239aa55bSDavid Thomson 		val |= MII_M1011_PHY_SCR_AUTO_CROSS;
210239aa55bSDavid Thomson 		break;
211239aa55bSDavid Thomson 	}
212239aa55bSDavid Thomson 
213239aa55bSDavid Thomson 	if (val != reg) {
214239aa55bSDavid Thomson 		/* Set the new polarity value in the register */
215239aa55bSDavid Thomson 		err = phy_write(phydev, MII_M1011_PHY_SCR, val);
216239aa55bSDavid Thomson 		if (err)
217239aa55bSDavid Thomson 			return err;
218239aa55bSDavid Thomson 	}
219239aa55bSDavid Thomson 
220239aa55bSDavid Thomson 	return 0;
221239aa55bSDavid Thomson }
222239aa55bSDavid Thomson 
22300db8189SAndy Fleming static int marvell_config_aneg(struct phy_device *phydev)
22400db8189SAndy Fleming {
22500db8189SAndy Fleming 	int err;
22600db8189SAndy Fleming 
22700db8189SAndy Fleming 	/* The Marvell PHY has an errata which requires
22800db8189SAndy Fleming 	 * that certain registers get written in order
22900db8189SAndy Fleming 	 * to restart autonegotiation */
23000db8189SAndy Fleming 	err = phy_write(phydev, MII_BMCR, BMCR_RESET);
23100db8189SAndy Fleming 
23200db8189SAndy Fleming 	if (err < 0)
23300db8189SAndy Fleming 		return err;
23400db8189SAndy Fleming 
23500db8189SAndy Fleming 	err = phy_write(phydev, 0x1d, 0x1f);
23600db8189SAndy Fleming 	if (err < 0)
23700db8189SAndy Fleming 		return err;
23800db8189SAndy Fleming 
23900db8189SAndy Fleming 	err = phy_write(phydev, 0x1e, 0x200c);
24000db8189SAndy Fleming 	if (err < 0)
24100db8189SAndy Fleming 		return err;
24200db8189SAndy Fleming 
24300db8189SAndy Fleming 	err = phy_write(phydev, 0x1d, 0x5);
24400db8189SAndy Fleming 	if (err < 0)
24500db8189SAndy Fleming 		return err;
24600db8189SAndy Fleming 
24700db8189SAndy Fleming 	err = phy_write(phydev, 0x1e, 0);
24800db8189SAndy Fleming 	if (err < 0)
24900db8189SAndy Fleming 		return err;
25000db8189SAndy Fleming 
25100db8189SAndy Fleming 	err = phy_write(phydev, 0x1e, 0x100);
25200db8189SAndy Fleming 	if (err < 0)
25300db8189SAndy Fleming 		return err;
25400db8189SAndy Fleming 
255239aa55bSDavid Thomson 	err = marvell_set_polarity(phydev, phydev->mdix);
25676884679SAndy Fleming 	if (err < 0)
25776884679SAndy Fleming 		return err;
25876884679SAndy Fleming 
25976884679SAndy Fleming 	err = phy_write(phydev, MII_M1111_PHY_LED_CONTROL,
26076884679SAndy Fleming 			MII_M1111_PHY_LED_DIRECT);
26176884679SAndy Fleming 	if (err < 0)
26276884679SAndy Fleming 		return err;
26300db8189SAndy Fleming 
26400db8189SAndy Fleming 	err = genphy_config_aneg(phydev);
2658ff44985SAnton Vorontsov 	if (err < 0)
26600db8189SAndy Fleming 		return err;
2678ff44985SAnton Vorontsov 
2688ff44985SAnton Vorontsov 	if (phydev->autoneg != AUTONEG_ENABLE) {
2698ff44985SAnton Vorontsov 		int bmcr;
2708ff44985SAnton Vorontsov 
2718ff44985SAnton Vorontsov 		/*
2728ff44985SAnton Vorontsov 		 * A write to speed/duplex bits (that is performed by
2738ff44985SAnton Vorontsov 		 * genphy_config_aneg() call above) must be followed by
2748ff44985SAnton Vorontsov 		 * a software reset. Otherwise, the write has no effect.
2758ff44985SAnton Vorontsov 		 */
2768ff44985SAnton Vorontsov 		bmcr = phy_read(phydev, MII_BMCR);
2778ff44985SAnton Vorontsov 		if (bmcr < 0)
2788ff44985SAnton Vorontsov 			return bmcr;
2798ff44985SAnton Vorontsov 
2808ff44985SAnton Vorontsov 		err = phy_write(phydev, MII_BMCR, bmcr | BMCR_RESET);
2818ff44985SAnton Vorontsov 		if (err < 0)
2828ff44985SAnton Vorontsov 			return err;
2838ff44985SAnton Vorontsov 	}
2848ff44985SAnton Vorontsov 
2858ff44985SAnton Vorontsov 	return 0;
28600db8189SAndy Fleming }
28700db8189SAndy Fleming 
2883ec0a0f1SHarini Katakam static int m88e1111_config_aneg(struct phy_device *phydev)
2893ec0a0f1SHarini Katakam {
2903ec0a0f1SHarini Katakam 	int err;
2913ec0a0f1SHarini Katakam 
2923ec0a0f1SHarini Katakam 	/* The Marvell PHY has an errata which requires
2933ec0a0f1SHarini Katakam 	 * that certain registers get written in order
2943ec0a0f1SHarini Katakam 	 * to restart autonegotiation
2953ec0a0f1SHarini Katakam 	 */
2963ec0a0f1SHarini Katakam 	err = phy_write(phydev, MII_BMCR, BMCR_RESET);
2973ec0a0f1SHarini Katakam 
2983ec0a0f1SHarini Katakam 	err = marvell_set_polarity(phydev, phydev->mdix);
2993ec0a0f1SHarini Katakam 	if (err < 0)
3003ec0a0f1SHarini Katakam 		return err;
3013ec0a0f1SHarini Katakam 
3023ec0a0f1SHarini Katakam 	err = phy_write(phydev, MII_M1111_PHY_LED_CONTROL,
3033ec0a0f1SHarini Katakam 			MII_M1111_PHY_LED_DIRECT);
3043ec0a0f1SHarini Katakam 	if (err < 0)
3053ec0a0f1SHarini Katakam 		return err;
3063ec0a0f1SHarini Katakam 
3073ec0a0f1SHarini Katakam 	err = genphy_config_aneg(phydev);
3083ec0a0f1SHarini Katakam 	if (err < 0)
3093ec0a0f1SHarini Katakam 		return err;
3103ec0a0f1SHarini Katakam 
3113ec0a0f1SHarini Katakam 	if (phydev->autoneg != AUTONEG_ENABLE) {
3123ec0a0f1SHarini Katakam 		int bmcr;
3133ec0a0f1SHarini Katakam 
3143ec0a0f1SHarini Katakam 		/* A write to speed/duplex bits (that is performed by
3153ec0a0f1SHarini Katakam 		 * genphy_config_aneg() call above) must be followed by
3163ec0a0f1SHarini Katakam 		 * a software reset. Otherwise, the write has no effect.
3173ec0a0f1SHarini Katakam 		 */
3183ec0a0f1SHarini Katakam 		bmcr = phy_read(phydev, MII_BMCR);
3193ec0a0f1SHarini Katakam 		if (bmcr < 0)
3203ec0a0f1SHarini Katakam 			return bmcr;
3213ec0a0f1SHarini Katakam 
3223ec0a0f1SHarini Katakam 		err = phy_write(phydev, MII_BMCR, bmcr | BMCR_RESET);
3233ec0a0f1SHarini Katakam 		if (err < 0)
3243ec0a0f1SHarini Katakam 			return err;
3253ec0a0f1SHarini Katakam 	}
3263ec0a0f1SHarini Katakam 
3273ec0a0f1SHarini Katakam 	return 0;
3283ec0a0f1SHarini Katakam }
3293ec0a0f1SHarini Katakam 
330cf41a51dSDavid Daney #ifdef CONFIG_OF_MDIO
331cf41a51dSDavid Daney /*
332cf41a51dSDavid Daney  * Set and/or override some configuration registers based on the
333cf41a51dSDavid Daney  * marvell,reg-init property stored in the of_node for the phydev.
334cf41a51dSDavid Daney  *
335cf41a51dSDavid Daney  * marvell,reg-init = <reg-page reg mask value>,...;
336cf41a51dSDavid Daney  *
337cf41a51dSDavid Daney  * There may be one or more sets of <reg-page reg mask value>:
338cf41a51dSDavid Daney  *
339cf41a51dSDavid Daney  * reg-page: which register bank to use.
340cf41a51dSDavid Daney  * reg: the register.
341cf41a51dSDavid Daney  * mask: if non-zero, ANDed with existing register value.
342cf41a51dSDavid Daney  * value: ORed with the masked value and written to the regiser.
343cf41a51dSDavid Daney  *
344cf41a51dSDavid Daney  */
345cf41a51dSDavid Daney static int marvell_of_reg_init(struct phy_device *phydev)
346cf41a51dSDavid Daney {
347cf41a51dSDavid Daney 	const __be32 *paddr;
348cf41a51dSDavid Daney 	int len, i, saved_page, current_page, page_changed, ret;
349cf41a51dSDavid Daney 
350e5a03bfdSAndrew Lunn 	if (!phydev->mdio.dev.of_node)
351cf41a51dSDavid Daney 		return 0;
352cf41a51dSDavid Daney 
353e5a03bfdSAndrew Lunn 	paddr = of_get_property(phydev->mdio.dev.of_node,
354e5a03bfdSAndrew Lunn 				"marvell,reg-init", &len);
355cf41a51dSDavid Daney 	if (!paddr || len < (4 * sizeof(*paddr)))
356cf41a51dSDavid Daney 		return 0;
357cf41a51dSDavid Daney 
358cf41a51dSDavid Daney 	saved_page = phy_read(phydev, MII_MARVELL_PHY_PAGE);
359cf41a51dSDavid Daney 	if (saved_page < 0)
360cf41a51dSDavid Daney 		return saved_page;
361cf41a51dSDavid Daney 	page_changed = 0;
362cf41a51dSDavid Daney 	current_page = saved_page;
363cf41a51dSDavid Daney 
364cf41a51dSDavid Daney 	ret = 0;
365cf41a51dSDavid Daney 	len /= sizeof(*paddr);
366cf41a51dSDavid Daney 	for (i = 0; i < len - 3; i += 4) {
367cf41a51dSDavid Daney 		u16 reg_page = be32_to_cpup(paddr + i);
368cf41a51dSDavid Daney 		u16 reg = be32_to_cpup(paddr + i + 1);
369cf41a51dSDavid Daney 		u16 mask = be32_to_cpup(paddr + i + 2);
370cf41a51dSDavid Daney 		u16 val_bits = be32_to_cpup(paddr + i + 3);
371cf41a51dSDavid Daney 		int val;
372cf41a51dSDavid Daney 
373cf41a51dSDavid Daney 		if (reg_page != current_page) {
374cf41a51dSDavid Daney 			current_page = reg_page;
375cf41a51dSDavid Daney 			page_changed = 1;
376cf41a51dSDavid Daney 			ret = phy_write(phydev, MII_MARVELL_PHY_PAGE, reg_page);
377cf41a51dSDavid Daney 			if (ret < 0)
378cf41a51dSDavid Daney 				goto err;
379cf41a51dSDavid Daney 		}
380cf41a51dSDavid Daney 
381cf41a51dSDavid Daney 		val = 0;
382cf41a51dSDavid Daney 		if (mask) {
383cf41a51dSDavid Daney 			val = phy_read(phydev, reg);
384cf41a51dSDavid Daney 			if (val < 0) {
385cf41a51dSDavid Daney 				ret = val;
386cf41a51dSDavid Daney 				goto err;
387cf41a51dSDavid Daney 			}
388cf41a51dSDavid Daney 			val &= mask;
389cf41a51dSDavid Daney 		}
390cf41a51dSDavid Daney 		val |= val_bits;
391cf41a51dSDavid Daney 
392cf41a51dSDavid Daney 		ret = phy_write(phydev, reg, val);
393cf41a51dSDavid Daney 		if (ret < 0)
394cf41a51dSDavid Daney 			goto err;
395cf41a51dSDavid Daney 
396cf41a51dSDavid Daney 	}
397cf41a51dSDavid Daney err:
398cf41a51dSDavid Daney 	if (page_changed) {
399cf41a51dSDavid Daney 		i = phy_write(phydev, MII_MARVELL_PHY_PAGE, saved_page);
400cf41a51dSDavid Daney 		if (ret == 0)
401cf41a51dSDavid Daney 			ret = i;
402cf41a51dSDavid Daney 	}
403cf41a51dSDavid Daney 	return 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 
412140bc929SSergei Poselenov static int m88e1121_config_aneg(struct phy_device *phydev)
413140bc929SSergei Poselenov {
414c477d044SCyril Chemparathy 	int err, oldpage, mscr;
415c477d044SCyril Chemparathy 
41627d916d6SDavid Daney 	oldpage = phy_read(phydev, MII_MARVELL_PHY_PAGE);
417c477d044SCyril Chemparathy 
41827d916d6SDavid Daney 	err = phy_write(phydev, MII_MARVELL_PHY_PAGE,
419c477d044SCyril Chemparathy 			MII_88E1121_PHY_MSCR_PAGE);
420c477d044SCyril Chemparathy 	if (err < 0)
421c477d044SCyril Chemparathy 		return err;
422be8c6480SArnaud Patard 
42332a64161SFlorian Fainelli 	if (phy_interface_is_rgmii(phydev)) {
424be8c6480SArnaud Patard 
425c477d044SCyril Chemparathy 		mscr = phy_read(phydev, MII_88E1121_PHY_MSCR_REG) &
426c477d044SCyril Chemparathy 			MII_88E1121_PHY_MSCR_DELAY_MASK;
427c477d044SCyril Chemparathy 
428c477d044SCyril Chemparathy 		if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)
429c477d044SCyril Chemparathy 			mscr |= (MII_88E1121_PHY_MSCR_RX_DELAY |
430c477d044SCyril Chemparathy 				 MII_88E1121_PHY_MSCR_TX_DELAY);
431c477d044SCyril Chemparathy 		else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID)
432c477d044SCyril Chemparathy 			mscr |= MII_88E1121_PHY_MSCR_RX_DELAY;
433c477d044SCyril Chemparathy 		else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)
434c477d044SCyril Chemparathy 			mscr |= MII_88E1121_PHY_MSCR_TX_DELAY;
435c477d044SCyril Chemparathy 
436c477d044SCyril Chemparathy 		err = phy_write(phydev, MII_88E1121_PHY_MSCR_REG, mscr);
437c477d044SCyril Chemparathy 		if (err < 0)
438c477d044SCyril Chemparathy 			return err;
439be8c6480SArnaud Patard 	}
440c477d044SCyril Chemparathy 
44127d916d6SDavid Daney 	phy_write(phydev, MII_MARVELL_PHY_PAGE, oldpage);
442140bc929SSergei Poselenov 
443140bc929SSergei Poselenov 	err = phy_write(phydev, MII_BMCR, BMCR_RESET);
444140bc929SSergei Poselenov 	if (err < 0)
445140bc929SSergei Poselenov 		return err;
446140bc929SSergei Poselenov 
447140bc929SSergei Poselenov 	err = phy_write(phydev, MII_M1011_PHY_SCR,
448140bc929SSergei Poselenov 			MII_M1011_PHY_SCR_AUTO_CROSS);
449140bc929SSergei Poselenov 	if (err < 0)
450140bc929SSergei Poselenov 		return err;
451140bc929SSergei Poselenov 
452fdecf36fSClemens Gruber 	return genphy_config_aneg(phydev);
453140bc929SSergei Poselenov }
454140bc929SSergei Poselenov 
455337ac9d5SCyril Chemparathy static int m88e1318_config_aneg(struct phy_device *phydev)
4563ff1c259SCyril Chemparathy {
4573ff1c259SCyril Chemparathy 	int err, oldpage, mscr;
4583ff1c259SCyril Chemparathy 
45927d916d6SDavid Daney 	oldpage = phy_read(phydev, MII_MARVELL_PHY_PAGE);
4603ff1c259SCyril Chemparathy 
46127d916d6SDavid Daney 	err = phy_write(phydev, MII_MARVELL_PHY_PAGE,
4623ff1c259SCyril Chemparathy 			MII_88E1121_PHY_MSCR_PAGE);
4633ff1c259SCyril Chemparathy 	if (err < 0)
4643ff1c259SCyril Chemparathy 		return err;
4653ff1c259SCyril Chemparathy 
466337ac9d5SCyril Chemparathy 	mscr = phy_read(phydev, MII_88E1318S_PHY_MSCR1_REG);
467337ac9d5SCyril Chemparathy 	mscr |= MII_88E1318S_PHY_MSCR1_PAD_ODD;
4683ff1c259SCyril Chemparathy 
469337ac9d5SCyril Chemparathy 	err = phy_write(phydev, MII_88E1318S_PHY_MSCR1_REG, mscr);
4703ff1c259SCyril Chemparathy 	if (err < 0)
4713ff1c259SCyril Chemparathy 		return err;
4723ff1c259SCyril Chemparathy 
47327d916d6SDavid Daney 	err = phy_write(phydev, MII_MARVELL_PHY_PAGE, oldpage);
4743ff1c259SCyril Chemparathy 	if (err < 0)
4753ff1c259SCyril Chemparathy 		return err;
4763ff1c259SCyril Chemparathy 
4773ff1c259SCyril Chemparathy 	return m88e1121_config_aneg(phydev);
4783ff1c259SCyril Chemparathy }
4793ff1c259SCyril Chemparathy 
48010e24caaSMichal Simek static int m88e1510_config_aneg(struct phy_device *phydev)
48110e24caaSMichal Simek {
48210e24caaSMichal Simek 	int err;
48310e24caaSMichal Simek 
48410e24caaSMichal Simek 	err = m88e1318_config_aneg(phydev);
48510e24caaSMichal Simek 	if (err < 0)
48610e24caaSMichal Simek 		return err;
48710e24caaSMichal Simek 
48879be1a1cSClemens Gruber 	return 0;
48979be1a1cSClemens Gruber }
49079be1a1cSClemens Gruber 
49179be1a1cSClemens Gruber static int marvell_config_init(struct phy_device *phydev)
49279be1a1cSClemens Gruber {
49379be1a1cSClemens Gruber 	/* Set registers from marvell,reg-init DT property */
49410e24caaSMichal Simek 	return marvell_of_reg_init(phydev);
49510e24caaSMichal Simek }
49610e24caaSMichal Simek 
4973da09a51SMichal Simek static int m88e1116r_config_init(struct phy_device *phydev)
4983da09a51SMichal Simek {
4993da09a51SMichal Simek 	int temp;
5003da09a51SMichal Simek 	int err;
5013da09a51SMichal Simek 
5023da09a51SMichal Simek 	temp = phy_read(phydev, MII_BMCR);
5033da09a51SMichal Simek 	temp |= BMCR_RESET;
5043da09a51SMichal Simek 	err = phy_write(phydev, MII_BMCR, temp);
5053da09a51SMichal Simek 	if (err < 0)
5063da09a51SMichal Simek 		return err;
5073da09a51SMichal Simek 
5083da09a51SMichal Simek 	mdelay(500);
5093da09a51SMichal Simek 
5103da09a51SMichal Simek 	err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0);
5113da09a51SMichal Simek 	if (err < 0)
5123da09a51SMichal Simek 		return err;
5133da09a51SMichal Simek 
5143da09a51SMichal Simek 	temp = phy_read(phydev, MII_M1011_PHY_SCR);
5153da09a51SMichal Simek 	temp |= (7 << 12);	/* max number of gigabit attempts */
5163da09a51SMichal Simek 	temp |= (1 << 11);	/* enable downshift */
5173da09a51SMichal Simek 	temp |= MII_M1011_PHY_SCR_AUTO_CROSS;
5183da09a51SMichal Simek 	err = phy_write(phydev, MII_M1011_PHY_SCR, temp);
5193da09a51SMichal Simek 	if (err < 0)
5203da09a51SMichal Simek 		return err;
5213da09a51SMichal Simek 
5223da09a51SMichal Simek 	err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 2);
5233da09a51SMichal Simek 	if (err < 0)
5243da09a51SMichal Simek 		return err;
5253da09a51SMichal Simek 	temp = phy_read(phydev, MII_M1116R_CONTROL_REG_MAC);
5263da09a51SMichal Simek 	temp |= (1 << 5);
5273da09a51SMichal Simek 	temp |= (1 << 4);
5283da09a51SMichal Simek 	err = phy_write(phydev, MII_M1116R_CONTROL_REG_MAC, temp);
5293da09a51SMichal Simek 	if (err < 0)
5303da09a51SMichal Simek 		return err;
5313da09a51SMichal Simek 	err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0);
5323da09a51SMichal Simek 	if (err < 0)
5333da09a51SMichal Simek 		return err;
5343da09a51SMichal Simek 
5353da09a51SMichal Simek 	temp = phy_read(phydev, MII_BMCR);
5363da09a51SMichal Simek 	temp |= BMCR_RESET;
5373da09a51SMichal Simek 	err = phy_write(phydev, MII_BMCR, temp);
5383da09a51SMichal Simek 	if (err < 0)
5393da09a51SMichal Simek 		return err;
5403da09a51SMichal Simek 
5413da09a51SMichal Simek 	mdelay(500);
5423da09a51SMichal Simek 
54379be1a1cSClemens Gruber 	return marvell_config_init(phydev);
5443da09a51SMichal Simek }
5453da09a51SMichal Simek 
5466b358aedSSebastian Hesselbarth static int m88e3016_config_init(struct phy_device *phydev)
5476b358aedSSebastian Hesselbarth {
5486b358aedSSebastian Hesselbarth 	int reg;
5496b358aedSSebastian Hesselbarth 
5506b358aedSSebastian Hesselbarth 	/* Enable Scrambler and Auto-Crossover */
5516b358aedSSebastian Hesselbarth 	reg = phy_read(phydev, MII_88E3016_PHY_SPEC_CTRL);
5526b358aedSSebastian Hesselbarth 	if (reg < 0)
5536b358aedSSebastian Hesselbarth 		return reg;
5546b358aedSSebastian Hesselbarth 
5556b358aedSSebastian Hesselbarth 	reg &= ~MII_88E3016_DISABLE_SCRAMBLER;
5566b358aedSSebastian Hesselbarth 	reg |= MII_88E3016_AUTO_MDIX_CROSSOVER;
5576b358aedSSebastian Hesselbarth 
5586b358aedSSebastian Hesselbarth 	reg = phy_write(phydev, MII_88E3016_PHY_SPEC_CTRL, reg);
5596b358aedSSebastian Hesselbarth 	if (reg < 0)
5606b358aedSSebastian Hesselbarth 		return reg;
5616b358aedSSebastian Hesselbarth 
56279be1a1cSClemens Gruber 	return marvell_config_init(phydev);
5636b358aedSSebastian Hesselbarth }
5646b358aedSSebastian Hesselbarth 
565895ee682SKim Phillips static int m88e1111_config_init(struct phy_device *phydev)
566895ee682SKim Phillips {
567895ee682SKim Phillips 	int err;
568be937f1fSAlexandr Smirnov 	int temp;
569be937f1fSAlexandr Smirnov 
57032a64161SFlorian Fainelli 	if (phy_interface_is_rgmii(phydev)) {
571895ee682SKim Phillips 
572895ee682SKim Phillips 		temp = phy_read(phydev, MII_M1111_PHY_EXT_CR);
573895ee682SKim Phillips 		if (temp < 0)
574895ee682SKim Phillips 			return temp;
575895ee682SKim Phillips 
5769daf5a76SKim Phillips 		if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) {
577895ee682SKim Phillips 			temp |= (MII_M1111_RX_DELAY | MII_M1111_TX_DELAY);
5789daf5a76SKim Phillips 		} else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) {
5799daf5a76SKim Phillips 			temp &= ~MII_M1111_TX_DELAY;
5809daf5a76SKim Phillips 			temp |= MII_M1111_RX_DELAY;
5819daf5a76SKim Phillips 		} else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) {
5829daf5a76SKim Phillips 			temp &= ~MII_M1111_RX_DELAY;
5839daf5a76SKim Phillips 			temp |= MII_M1111_TX_DELAY;
5849daf5a76SKim Phillips 		}
585895ee682SKim Phillips 
586895ee682SKim Phillips 		err = phy_write(phydev, MII_M1111_PHY_EXT_CR, temp);
587895ee682SKim Phillips 		if (err < 0)
588895ee682SKim Phillips 			return err;
589895ee682SKim Phillips 
590895ee682SKim Phillips 		temp = phy_read(phydev, MII_M1111_PHY_EXT_SR);
591895ee682SKim Phillips 		if (temp < 0)
592895ee682SKim Phillips 			return temp;
593895ee682SKim Phillips 
594895ee682SKim Phillips 		temp &= ~(MII_M1111_HWCFG_MODE_MASK);
595be937f1fSAlexandr Smirnov 
5967239016dSWang Jian 		if (temp & MII_M1111_HWCFG_FIBER_COPPER_RES)
597be937f1fSAlexandr Smirnov 			temp |= MII_M1111_HWCFG_MODE_FIBER_RGMII;
598be937f1fSAlexandr Smirnov 		else
599be937f1fSAlexandr Smirnov 			temp |= MII_M1111_HWCFG_MODE_COPPER_RGMII;
600895ee682SKim Phillips 
601895ee682SKim Phillips 		err = phy_write(phydev, MII_M1111_PHY_EXT_SR, temp);
602895ee682SKim Phillips 		if (err < 0)
603895ee682SKim Phillips 			return err;
604895ee682SKim Phillips 	}
605895ee682SKim Phillips 
6064117b5beSKapil Juneja 	if (phydev->interface == PHY_INTERFACE_MODE_SGMII) {
6074117b5beSKapil Juneja 		temp = phy_read(phydev, MII_M1111_PHY_EXT_SR);
6084117b5beSKapil Juneja 		if (temp < 0)
6094117b5beSKapil Juneja 			return temp;
6104117b5beSKapil Juneja 
6114117b5beSKapil Juneja 		temp &= ~(MII_M1111_HWCFG_MODE_MASK);
6124117b5beSKapil Juneja 		temp |= MII_M1111_HWCFG_MODE_SGMII_NO_CLK;
61332d0c1e1SHaiying Wang 		temp |= MII_M1111_HWCFG_FIBER_COPPER_AUTO;
6144117b5beSKapil Juneja 
6154117b5beSKapil Juneja 		err = phy_write(phydev, MII_M1111_PHY_EXT_SR, temp);
6164117b5beSKapil Juneja 		if (err < 0)
6174117b5beSKapil Juneja 			return err;
61807151bc9SMadalin Bucur 
61907151bc9SMadalin Bucur 		/* make sure copper is selected */
62007151bc9SMadalin Bucur 		err = phy_read(phydev, MII_M1145_PHY_EXT_ADDR_PAGE);
62107151bc9SMadalin Bucur 		if (err < 0)
62207151bc9SMadalin Bucur 			return err;
62307151bc9SMadalin Bucur 
62407151bc9SMadalin Bucur 		err = phy_write(phydev, MII_M1145_PHY_EXT_ADDR_PAGE,
62507151bc9SMadalin Bucur 				err & (~0xff));
62607151bc9SMadalin Bucur 		if (err < 0)
62707151bc9SMadalin Bucur 			return err;
6284117b5beSKapil Juneja 	}
6294117b5beSKapil Juneja 
6305f8cbc13SLiu Yu-B13201 	if (phydev->interface == PHY_INTERFACE_MODE_RTBI) {
6315f8cbc13SLiu Yu-B13201 		temp = phy_read(phydev, MII_M1111_PHY_EXT_CR);
6325f8cbc13SLiu Yu-B13201 		if (temp < 0)
6335f8cbc13SLiu Yu-B13201 			return temp;
6345f8cbc13SLiu Yu-B13201 		temp |= (MII_M1111_RX_DELAY | MII_M1111_TX_DELAY);
6355f8cbc13SLiu Yu-B13201 		err = phy_write(phydev, MII_M1111_PHY_EXT_CR, temp);
6365f8cbc13SLiu Yu-B13201 		if (err < 0)
6375f8cbc13SLiu Yu-B13201 			return err;
6385f8cbc13SLiu Yu-B13201 
6395f8cbc13SLiu Yu-B13201 		temp = phy_read(phydev, MII_M1111_PHY_EXT_SR);
6405f8cbc13SLiu Yu-B13201 		if (temp < 0)
6415f8cbc13SLiu Yu-B13201 			return temp;
6425f8cbc13SLiu Yu-B13201 		temp &= ~(MII_M1111_HWCFG_MODE_MASK | MII_M1111_HWCFG_FIBER_COPPER_RES);
6435f8cbc13SLiu Yu-B13201 		temp |= 0x7 | MII_M1111_HWCFG_FIBER_COPPER_AUTO;
6445f8cbc13SLiu Yu-B13201 		err = phy_write(phydev, MII_M1111_PHY_EXT_SR, temp);
6455f8cbc13SLiu Yu-B13201 		if (err < 0)
6465f8cbc13SLiu Yu-B13201 			return err;
6475f8cbc13SLiu Yu-B13201 
6485f8cbc13SLiu Yu-B13201 		/* soft reset */
6495f8cbc13SLiu Yu-B13201 		err = phy_write(phydev, MII_BMCR, BMCR_RESET);
6505f8cbc13SLiu Yu-B13201 		if (err < 0)
6515f8cbc13SLiu Yu-B13201 			return err;
6525f8cbc13SLiu Yu-B13201 		do
6535f8cbc13SLiu Yu-B13201 			temp = phy_read(phydev, MII_BMCR);
6545f8cbc13SLiu Yu-B13201 		while (temp & BMCR_RESET);
6555f8cbc13SLiu Yu-B13201 
6565f8cbc13SLiu Yu-B13201 		temp = phy_read(phydev, MII_M1111_PHY_EXT_SR);
6575f8cbc13SLiu Yu-B13201 		if (temp < 0)
6585f8cbc13SLiu Yu-B13201 			return temp;
6595f8cbc13SLiu Yu-B13201 		temp &= ~(MII_M1111_HWCFG_MODE_MASK | MII_M1111_HWCFG_FIBER_COPPER_RES);
6605f8cbc13SLiu Yu-B13201 		temp |= MII_M1111_HWCFG_MODE_COPPER_RTBI | MII_M1111_HWCFG_FIBER_COPPER_AUTO;
6615f8cbc13SLiu Yu-B13201 		err = phy_write(phydev, MII_M1111_PHY_EXT_SR, temp);
6625f8cbc13SLiu Yu-B13201 		if (err < 0)
6635f8cbc13SLiu Yu-B13201 			return err;
6645f8cbc13SLiu Yu-B13201 	}
6655f8cbc13SLiu Yu-B13201 
666cf41a51dSDavid Daney 	err = marvell_of_reg_init(phydev);
667cf41a51dSDavid Daney 	if (err < 0)
668cf41a51dSDavid Daney 		return err;
6695f8cbc13SLiu Yu-B13201 
670cc90cb3bSSrinivas Kandagatla 	return phy_write(phydev, MII_BMCR, BMCR_RESET);
671895ee682SKim Phillips }
672895ee682SKim Phillips 
673fdecf36fSClemens Gruber static int m88e1121_config_init(struct phy_device *phydev)
674fdecf36fSClemens Gruber {
675fdecf36fSClemens Gruber 	int err, oldpage;
676fdecf36fSClemens Gruber 
677fdecf36fSClemens Gruber 	oldpage = phy_read(phydev, MII_MARVELL_PHY_PAGE);
678fdecf36fSClemens Gruber 
679fdecf36fSClemens Gruber 	err = phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_88E1121_PHY_LED_PAGE);
680fdecf36fSClemens Gruber 	if (err < 0)
681fdecf36fSClemens Gruber 		return err;
682fdecf36fSClemens Gruber 
683fdecf36fSClemens Gruber 	/* Default PHY LED config: LED[0] .. Link, LED[1] .. Activity */
684fdecf36fSClemens Gruber 	err = phy_write(phydev, MII_88E1121_PHY_LED_CTRL,
685fdecf36fSClemens Gruber 			MII_88E1121_PHY_LED_DEF);
686fdecf36fSClemens Gruber 	if (err < 0)
687fdecf36fSClemens Gruber 		return err;
688fdecf36fSClemens Gruber 
689fdecf36fSClemens Gruber 	phy_write(phydev, MII_MARVELL_PHY_PAGE, oldpage);
690fdecf36fSClemens Gruber 
691fdecf36fSClemens Gruber 	/* Set marvell,reg-init configuration from device tree */
692fdecf36fSClemens Gruber 	return marvell_config_init(phydev);
693fdecf36fSClemens Gruber }
694fdecf36fSClemens Gruber 
695407353ecSClemens Gruber static int m88e1510_config_init(struct phy_device *phydev)
696407353ecSClemens Gruber {
697407353ecSClemens Gruber 	int err;
698407353ecSClemens Gruber 	int temp;
699407353ecSClemens Gruber 
700407353ecSClemens Gruber 	/* SGMII-to-Copper mode initialization */
701407353ecSClemens Gruber 	if (phydev->interface == PHY_INTERFACE_MODE_SGMII) {
702407353ecSClemens Gruber 		/* Select page 18 */
703407353ecSClemens Gruber 		err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 18);
704407353ecSClemens Gruber 		if (err < 0)
705407353ecSClemens Gruber 			return err;
706407353ecSClemens Gruber 
707407353ecSClemens Gruber 		/* In reg 20, write MODE[2:0] = 0x1 (SGMII to Copper) */
708407353ecSClemens Gruber 		temp = phy_read(phydev, MII_88E1510_GEN_CTRL_REG_1);
709407353ecSClemens Gruber 		temp &= ~MII_88E1510_GEN_CTRL_REG_1_MODE_MASK;
710407353ecSClemens Gruber 		temp |= MII_88E1510_GEN_CTRL_REG_1_MODE_SGMII;
711407353ecSClemens Gruber 		err = phy_write(phydev, MII_88E1510_GEN_CTRL_REG_1, temp);
712407353ecSClemens Gruber 		if (err < 0)
713407353ecSClemens Gruber 			return err;
714407353ecSClemens Gruber 
715407353ecSClemens Gruber 		/* PHY reset is necessary after changing MODE[2:0] */
716407353ecSClemens Gruber 		temp |= MII_88E1510_GEN_CTRL_REG_1_RESET;
717407353ecSClemens Gruber 		err = phy_write(phydev, MII_88E1510_GEN_CTRL_REG_1, temp);
718407353ecSClemens Gruber 		if (err < 0)
719407353ecSClemens Gruber 			return err;
720407353ecSClemens Gruber 
721407353ecSClemens Gruber 		/* Reset page selection */
722407353ecSClemens Gruber 		err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0);
723407353ecSClemens Gruber 		if (err < 0)
724407353ecSClemens Gruber 			return err;
725407353ecSClemens Gruber 	}
726407353ecSClemens Gruber 
727fdecf36fSClemens Gruber 	return m88e1121_config_init(phydev);
728407353ecSClemens Gruber }
729407353ecSClemens Gruber 
730605f196eSRon Madrid static int m88e1118_config_aneg(struct phy_device *phydev)
731605f196eSRon Madrid {
732605f196eSRon Madrid 	int err;
733605f196eSRon Madrid 
734605f196eSRon Madrid 	err = phy_write(phydev, MII_BMCR, BMCR_RESET);
735605f196eSRon Madrid 	if (err < 0)
736605f196eSRon Madrid 		return err;
737605f196eSRon Madrid 
738605f196eSRon Madrid 	err = phy_write(phydev, MII_M1011_PHY_SCR,
739605f196eSRon Madrid 			MII_M1011_PHY_SCR_AUTO_CROSS);
740605f196eSRon Madrid 	if (err < 0)
741605f196eSRon Madrid 		return err;
742605f196eSRon Madrid 
743605f196eSRon Madrid 	err = genphy_config_aneg(phydev);
744605f196eSRon Madrid 	return 0;
745605f196eSRon Madrid }
746605f196eSRon Madrid 
747605f196eSRon Madrid static int m88e1118_config_init(struct phy_device *phydev)
748605f196eSRon Madrid {
749605f196eSRon Madrid 	int err;
750605f196eSRon Madrid 
751605f196eSRon Madrid 	/* Change address */
75227d916d6SDavid Daney 	err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0002);
753605f196eSRon Madrid 	if (err < 0)
754605f196eSRon Madrid 		return err;
755605f196eSRon Madrid 
756605f196eSRon Madrid 	/* Enable 1000 Mbit */
757605f196eSRon Madrid 	err = phy_write(phydev, 0x15, 0x1070);
758605f196eSRon Madrid 	if (err < 0)
759605f196eSRon Madrid 		return err;
760605f196eSRon Madrid 
761605f196eSRon Madrid 	/* Change address */
76227d916d6SDavid Daney 	err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0003);
763605f196eSRon Madrid 	if (err < 0)
764605f196eSRon Madrid 		return err;
765605f196eSRon Madrid 
766605f196eSRon Madrid 	/* Adjust LED Control */
7672f495c39SBenjamin Herrenschmidt 	if (phydev->dev_flags & MARVELL_PHY_M1118_DNS323_LEDS)
7682f495c39SBenjamin Herrenschmidt 		err = phy_write(phydev, 0x10, 0x1100);
7692f495c39SBenjamin Herrenschmidt 	else
770605f196eSRon Madrid 		err = phy_write(phydev, 0x10, 0x021e);
771605f196eSRon Madrid 	if (err < 0)
772605f196eSRon Madrid 		return err;
773605f196eSRon Madrid 
774cf41a51dSDavid Daney 	err = marvell_of_reg_init(phydev);
775cf41a51dSDavid Daney 	if (err < 0)
776cf41a51dSDavid Daney 		return err;
777cf41a51dSDavid Daney 
778605f196eSRon Madrid 	/* Reset address */
77927d916d6SDavid Daney 	err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0);
780605f196eSRon Madrid 	if (err < 0)
781605f196eSRon Madrid 		return err;
782605f196eSRon Madrid 
783cc90cb3bSSrinivas Kandagatla 	return phy_write(phydev, MII_BMCR, BMCR_RESET);
784605f196eSRon Madrid }
785605f196eSRon Madrid 
78690600732SDavid Daney static int m88e1149_config_init(struct phy_device *phydev)
78790600732SDavid Daney {
78890600732SDavid Daney 	int err;
78990600732SDavid Daney 
79090600732SDavid Daney 	/* Change address */
79190600732SDavid Daney 	err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0002);
79290600732SDavid Daney 	if (err < 0)
79390600732SDavid Daney 		return err;
79490600732SDavid Daney 
79590600732SDavid Daney 	/* Enable 1000 Mbit */
79690600732SDavid Daney 	err = phy_write(phydev, 0x15, 0x1048);
79790600732SDavid Daney 	if (err < 0)
79890600732SDavid Daney 		return err;
79990600732SDavid Daney 
800cf41a51dSDavid Daney 	err = marvell_of_reg_init(phydev);
801cf41a51dSDavid Daney 	if (err < 0)
802cf41a51dSDavid Daney 		return err;
803cf41a51dSDavid Daney 
80490600732SDavid Daney 	/* Reset address */
80590600732SDavid Daney 	err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0);
80690600732SDavid Daney 	if (err < 0)
80790600732SDavid Daney 		return err;
80890600732SDavid Daney 
809cc90cb3bSSrinivas Kandagatla 	return phy_write(phydev, MII_BMCR, BMCR_RESET);
81090600732SDavid Daney }
81190600732SDavid Daney 
81276884679SAndy Fleming static int m88e1145_config_init(struct phy_device *phydev)
81376884679SAndy Fleming {
81476884679SAndy Fleming 	int err;
815b0224175SViet Nga Dao 	int temp;
81676884679SAndy Fleming 
81776884679SAndy Fleming 	/* Take care of errata E0 & E1 */
81876884679SAndy Fleming 	err = phy_write(phydev, 0x1d, 0x001b);
81976884679SAndy Fleming 	if (err < 0)
82076884679SAndy Fleming 		return err;
82176884679SAndy Fleming 
82276884679SAndy Fleming 	err = phy_write(phydev, 0x1e, 0x418f);
82376884679SAndy Fleming 	if (err < 0)
82476884679SAndy Fleming 		return err;
82576884679SAndy Fleming 
82676884679SAndy Fleming 	err = phy_write(phydev, 0x1d, 0x0016);
82776884679SAndy Fleming 	if (err < 0)
82876884679SAndy Fleming 		return err;
82976884679SAndy Fleming 
83076884679SAndy Fleming 	err = phy_write(phydev, 0x1e, 0xa2da);
83176884679SAndy Fleming 	if (err < 0)
83276884679SAndy Fleming 		return err;
83376884679SAndy Fleming 
834895ee682SKim Phillips 	if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) {
83576884679SAndy Fleming 		int temp = phy_read(phydev, MII_M1145_PHY_EXT_CR);
83676884679SAndy Fleming 		if (temp < 0)
83776884679SAndy Fleming 			return temp;
83876884679SAndy Fleming 
83976884679SAndy Fleming 		temp |= (MII_M1145_RGMII_RX_DELAY | MII_M1145_RGMII_TX_DELAY);
84076884679SAndy Fleming 
84176884679SAndy Fleming 		err = phy_write(phydev, MII_M1145_PHY_EXT_CR, temp);
84276884679SAndy Fleming 		if (err < 0)
84376884679SAndy Fleming 			return err;
84476884679SAndy Fleming 
8452f495c39SBenjamin Herrenschmidt 		if (phydev->dev_flags & MARVELL_PHY_M1145_FLAGS_RESISTANCE) {
84676884679SAndy Fleming 			err = phy_write(phydev, 0x1d, 0x0012);
84776884679SAndy Fleming 			if (err < 0)
84876884679SAndy Fleming 				return err;
84976884679SAndy Fleming 
85076884679SAndy Fleming 			temp = phy_read(phydev, 0x1e);
85176884679SAndy Fleming 			if (temp < 0)
85276884679SAndy Fleming 				return temp;
85376884679SAndy Fleming 
85476884679SAndy Fleming 			temp &= 0xf03f;
85576884679SAndy Fleming 			temp |= 2 << 9;	/* 36 ohm */
85676884679SAndy Fleming 			temp |= 2 << 6;	/* 39 ohm */
85776884679SAndy Fleming 
85876884679SAndy Fleming 			err = phy_write(phydev, 0x1e, temp);
85976884679SAndy Fleming 			if (err < 0)
86076884679SAndy Fleming 				return err;
86176884679SAndy Fleming 
86276884679SAndy Fleming 			err = phy_write(phydev, 0x1d, 0x3);
86376884679SAndy Fleming 			if (err < 0)
86476884679SAndy Fleming 				return err;
86576884679SAndy Fleming 
86676884679SAndy Fleming 			err = phy_write(phydev, 0x1e, 0x8000);
86776884679SAndy Fleming 			if (err < 0)
86876884679SAndy Fleming 				return err;
86976884679SAndy Fleming 		}
87076884679SAndy Fleming 	}
87176884679SAndy Fleming 
872b0224175SViet Nga Dao 	if (phydev->interface == PHY_INTERFACE_MODE_SGMII) {
873b0224175SViet Nga Dao 		temp = phy_read(phydev, MII_M1145_PHY_EXT_SR);
874b0224175SViet Nga Dao 		if (temp < 0)
875b0224175SViet Nga Dao 			return temp;
876b0224175SViet Nga Dao 
87799d881f9SVince Bridgers 		temp &= ~MII_M1145_HWCFG_MODE_MASK;
878b0224175SViet Nga Dao 		temp |= MII_M1145_HWCFG_MODE_SGMII_NO_CLK;
879b0224175SViet Nga Dao 		temp |= MII_M1145_HWCFG_FIBER_COPPER_AUTO;
880b0224175SViet Nga Dao 
881b0224175SViet Nga Dao 		err = phy_write(phydev, MII_M1145_PHY_EXT_SR, temp);
882b0224175SViet Nga Dao 		if (err < 0)
883b0224175SViet Nga Dao 			return err;
884b0224175SViet Nga Dao 	}
885b0224175SViet Nga Dao 
886cf41a51dSDavid Daney 	err = marvell_of_reg_init(phydev);
887cf41a51dSDavid Daney 	if (err < 0)
888cf41a51dSDavid Daney 		return err;
889cf41a51dSDavid Daney 
89076884679SAndy Fleming 	return 0;
89176884679SAndy Fleming }
89200db8189SAndy Fleming 
893be937f1fSAlexandr Smirnov /* marvell_read_status
894be937f1fSAlexandr Smirnov  *
895be937f1fSAlexandr Smirnov  * Generic status code does not detect Fiber correctly!
896be937f1fSAlexandr Smirnov  * Description:
897be937f1fSAlexandr Smirnov  *   Check the link, then figure out the current state
898be937f1fSAlexandr Smirnov  *   by comparing what we advertise with what the link partner
899be937f1fSAlexandr Smirnov  *   advertises.  Start by checking the gigabit possibilities,
900be937f1fSAlexandr Smirnov  *   then move on to 10/100.
901be937f1fSAlexandr Smirnov  */
902be937f1fSAlexandr Smirnov static int marvell_read_status(struct phy_device *phydev)
903be937f1fSAlexandr Smirnov {
904be937f1fSAlexandr Smirnov 	int adv;
905be937f1fSAlexandr Smirnov 	int err;
906be937f1fSAlexandr Smirnov 	int lpa;
907357cd64cSRussell King 	int lpagb;
908be937f1fSAlexandr Smirnov 	int status = 0;
909be937f1fSAlexandr Smirnov 
910be937f1fSAlexandr Smirnov 	/* Update the link, but return if there
911be937f1fSAlexandr Smirnov 	 * was an error */
912be937f1fSAlexandr Smirnov 	err = genphy_update_link(phydev);
913be937f1fSAlexandr Smirnov 	if (err)
914be937f1fSAlexandr Smirnov 		return err;
915be937f1fSAlexandr Smirnov 
916be937f1fSAlexandr Smirnov 	if (AUTONEG_ENABLE == phydev->autoneg) {
917be937f1fSAlexandr Smirnov 		status = phy_read(phydev, MII_M1011_PHY_STATUS);
918be937f1fSAlexandr Smirnov 		if (status < 0)
919be937f1fSAlexandr Smirnov 			return status;
920be937f1fSAlexandr Smirnov 
921be937f1fSAlexandr Smirnov 		lpa = phy_read(phydev, MII_LPA);
922be937f1fSAlexandr Smirnov 		if (lpa < 0)
923be937f1fSAlexandr Smirnov 			return lpa;
924be937f1fSAlexandr Smirnov 
925357cd64cSRussell King 		lpagb = phy_read(phydev, MII_STAT1000);
926357cd64cSRussell King 		if (lpagb < 0)
927357cd64cSRussell King 			return lpagb;
928357cd64cSRussell King 
929be937f1fSAlexandr Smirnov 		adv = phy_read(phydev, MII_ADVERTISE);
930be937f1fSAlexandr Smirnov 		if (adv < 0)
931be937f1fSAlexandr Smirnov 			return adv;
932be937f1fSAlexandr Smirnov 
933357cd64cSRussell King 		phydev->lp_advertising = mii_stat1000_to_ethtool_lpa_t(lpagb) |
934357cd64cSRussell King 					 mii_lpa_to_ethtool_lpa_t(lpa);
935357cd64cSRussell King 
936be937f1fSAlexandr Smirnov 		lpa &= adv;
937be937f1fSAlexandr Smirnov 
938be937f1fSAlexandr Smirnov 		if (status & MII_M1011_PHY_STATUS_FULLDUPLEX)
939be937f1fSAlexandr Smirnov 			phydev->duplex = DUPLEX_FULL;
940be937f1fSAlexandr Smirnov 		else
941be937f1fSAlexandr Smirnov 			phydev->duplex = DUPLEX_HALF;
942be937f1fSAlexandr Smirnov 
943be937f1fSAlexandr Smirnov 		status = status & MII_M1011_PHY_STATUS_SPD_MASK;
944be937f1fSAlexandr Smirnov 		phydev->pause = phydev->asym_pause = 0;
945be937f1fSAlexandr Smirnov 
946be937f1fSAlexandr Smirnov 		switch (status) {
947be937f1fSAlexandr Smirnov 		case MII_M1011_PHY_STATUS_1000:
948be937f1fSAlexandr Smirnov 			phydev->speed = SPEED_1000;
949be937f1fSAlexandr Smirnov 			break;
950be937f1fSAlexandr Smirnov 
951be937f1fSAlexandr Smirnov 		case MII_M1011_PHY_STATUS_100:
952be937f1fSAlexandr Smirnov 			phydev->speed = SPEED_100;
953be937f1fSAlexandr Smirnov 			break;
954be937f1fSAlexandr Smirnov 
955be937f1fSAlexandr Smirnov 		default:
956be937f1fSAlexandr Smirnov 			phydev->speed = SPEED_10;
957be937f1fSAlexandr Smirnov 			break;
958be937f1fSAlexandr Smirnov 		}
959be937f1fSAlexandr Smirnov 
960be937f1fSAlexandr Smirnov 		if (phydev->duplex == DUPLEX_FULL) {
961be937f1fSAlexandr Smirnov 			phydev->pause = lpa & LPA_PAUSE_CAP ? 1 : 0;
962be937f1fSAlexandr Smirnov 			phydev->asym_pause = lpa & LPA_PAUSE_ASYM ? 1 : 0;
963be937f1fSAlexandr Smirnov 		}
964be937f1fSAlexandr Smirnov 	} else {
965be937f1fSAlexandr Smirnov 		int bmcr = phy_read(phydev, MII_BMCR);
966be937f1fSAlexandr Smirnov 
967be937f1fSAlexandr Smirnov 		if (bmcr < 0)
968be937f1fSAlexandr Smirnov 			return bmcr;
969be937f1fSAlexandr Smirnov 
970be937f1fSAlexandr Smirnov 		if (bmcr & BMCR_FULLDPLX)
971be937f1fSAlexandr Smirnov 			phydev->duplex = DUPLEX_FULL;
972be937f1fSAlexandr Smirnov 		else
973be937f1fSAlexandr Smirnov 			phydev->duplex = DUPLEX_HALF;
974be937f1fSAlexandr Smirnov 
975be937f1fSAlexandr Smirnov 		if (bmcr & BMCR_SPEED1000)
976be937f1fSAlexandr Smirnov 			phydev->speed = SPEED_1000;
977be937f1fSAlexandr Smirnov 		else if (bmcr & BMCR_SPEED100)
978be937f1fSAlexandr Smirnov 			phydev->speed = SPEED_100;
979be937f1fSAlexandr Smirnov 		else
980be937f1fSAlexandr Smirnov 			phydev->speed = SPEED_10;
981be937f1fSAlexandr Smirnov 
982be937f1fSAlexandr Smirnov 		phydev->pause = phydev->asym_pause = 0;
983357cd64cSRussell King 		phydev->lp_advertising = 0;
984be937f1fSAlexandr Smirnov 	}
985be937f1fSAlexandr Smirnov 
986be937f1fSAlexandr Smirnov 	return 0;
987be937f1fSAlexandr Smirnov }
988be937f1fSAlexandr Smirnov 
9896b358aedSSebastian Hesselbarth static int marvell_aneg_done(struct phy_device *phydev)
9906b358aedSSebastian Hesselbarth {
9916b358aedSSebastian Hesselbarth 	int retval = phy_read(phydev, MII_M1011_PHY_STATUS);
9926b358aedSSebastian Hesselbarth 	return (retval < 0) ? retval : (retval & MII_M1011_PHY_STATUS_RESOLVED);
9936b358aedSSebastian Hesselbarth }
9946b358aedSSebastian Hesselbarth 
995dcd07be3SAnatolij Gustschin static int m88e1121_did_interrupt(struct phy_device *phydev)
996dcd07be3SAnatolij Gustschin {
997dcd07be3SAnatolij Gustschin 	int imask;
998dcd07be3SAnatolij Gustschin 
999dcd07be3SAnatolij Gustschin 	imask = phy_read(phydev, MII_M1011_IEVENT);
1000dcd07be3SAnatolij Gustschin 
1001dcd07be3SAnatolij Gustschin 	if (imask & MII_M1011_IMASK_INIT)
1002dcd07be3SAnatolij Gustschin 		return 1;
1003dcd07be3SAnatolij Gustschin 
1004dcd07be3SAnatolij Gustschin 	return 0;
1005dcd07be3SAnatolij Gustschin }
1006dcd07be3SAnatolij Gustschin 
10073871c387SMichael Stapelberg static void m88e1318_get_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol)
10083871c387SMichael Stapelberg {
10093871c387SMichael Stapelberg 	wol->supported = WAKE_MAGIC;
10103871c387SMichael Stapelberg 	wol->wolopts = 0;
10113871c387SMichael Stapelberg 
10123871c387SMichael Stapelberg 	if (phy_write(phydev, MII_MARVELL_PHY_PAGE,
10133871c387SMichael Stapelberg 		      MII_88E1318S_PHY_WOL_PAGE) < 0)
10143871c387SMichael Stapelberg 		return;
10153871c387SMichael Stapelberg 
10163871c387SMichael Stapelberg 	if (phy_read(phydev, MII_88E1318S_PHY_WOL_CTRL) &
10173871c387SMichael Stapelberg 	    MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE)
10183871c387SMichael Stapelberg 		wol->wolopts |= WAKE_MAGIC;
10193871c387SMichael Stapelberg 
10203871c387SMichael Stapelberg 	if (phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x00) < 0)
10213871c387SMichael Stapelberg 		return;
10223871c387SMichael Stapelberg }
10233871c387SMichael Stapelberg 
10243871c387SMichael Stapelberg static int m88e1318_set_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol)
10253871c387SMichael Stapelberg {
10263871c387SMichael Stapelberg 	int err, oldpage, temp;
10273871c387SMichael Stapelberg 
10283871c387SMichael Stapelberg 	oldpage = phy_read(phydev, MII_MARVELL_PHY_PAGE);
10293871c387SMichael Stapelberg 
10303871c387SMichael Stapelberg 	if (wol->wolopts & WAKE_MAGIC) {
10313871c387SMichael Stapelberg 		/* Explicitly switch to page 0x00, just to be sure */
10323871c387SMichael Stapelberg 		err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x00);
10333871c387SMichael Stapelberg 		if (err < 0)
10343871c387SMichael Stapelberg 			return err;
10353871c387SMichael Stapelberg 
10363871c387SMichael Stapelberg 		/* Enable the WOL interrupt */
10373871c387SMichael Stapelberg 		temp = phy_read(phydev, MII_88E1318S_PHY_CSIER);
10383871c387SMichael Stapelberg 		temp |= MII_88E1318S_PHY_CSIER_WOL_EIE;
10393871c387SMichael Stapelberg 		err = phy_write(phydev, MII_88E1318S_PHY_CSIER, temp);
10403871c387SMichael Stapelberg 		if (err < 0)
10413871c387SMichael Stapelberg 			return err;
10423871c387SMichael Stapelberg 
10433871c387SMichael Stapelberg 		err = phy_write(phydev, MII_MARVELL_PHY_PAGE,
10443871c387SMichael Stapelberg 				MII_88E1318S_PHY_LED_PAGE);
10453871c387SMichael Stapelberg 		if (err < 0)
10463871c387SMichael Stapelberg 			return err;
10473871c387SMichael Stapelberg 
10483871c387SMichael Stapelberg 		/* Setup LED[2] as interrupt pin (active low) */
10493871c387SMichael Stapelberg 		temp = phy_read(phydev, MII_88E1318S_PHY_LED_TCR);
10503871c387SMichael Stapelberg 		temp &= ~MII_88E1318S_PHY_LED_TCR_FORCE_INT;
10513871c387SMichael Stapelberg 		temp |= MII_88E1318S_PHY_LED_TCR_INTn_ENABLE;
10523871c387SMichael Stapelberg 		temp |= MII_88E1318S_PHY_LED_TCR_INT_ACTIVE_LOW;
10533871c387SMichael Stapelberg 		err = phy_write(phydev, MII_88E1318S_PHY_LED_TCR, temp);
10543871c387SMichael Stapelberg 		if (err < 0)
10553871c387SMichael Stapelberg 			return err;
10563871c387SMichael Stapelberg 
10573871c387SMichael Stapelberg 		err = phy_write(phydev, MII_MARVELL_PHY_PAGE,
10583871c387SMichael Stapelberg 				MII_88E1318S_PHY_WOL_PAGE);
10593871c387SMichael Stapelberg 		if (err < 0)
10603871c387SMichael Stapelberg 			return err;
10613871c387SMichael Stapelberg 
10623871c387SMichael Stapelberg 		/* Store the device address for the magic packet */
10633871c387SMichael Stapelberg 		err = phy_write(phydev, MII_88E1318S_PHY_MAGIC_PACKET_WORD2,
10643871c387SMichael Stapelberg 				((phydev->attached_dev->dev_addr[5] << 8) |
10653871c387SMichael Stapelberg 				 phydev->attached_dev->dev_addr[4]));
10663871c387SMichael Stapelberg 		if (err < 0)
10673871c387SMichael Stapelberg 			return err;
10683871c387SMichael Stapelberg 		err = phy_write(phydev, MII_88E1318S_PHY_MAGIC_PACKET_WORD1,
10693871c387SMichael Stapelberg 				((phydev->attached_dev->dev_addr[3] << 8) |
10703871c387SMichael Stapelberg 				 phydev->attached_dev->dev_addr[2]));
10713871c387SMichael Stapelberg 		if (err < 0)
10723871c387SMichael Stapelberg 			return err;
10733871c387SMichael Stapelberg 		err = phy_write(phydev, MII_88E1318S_PHY_MAGIC_PACKET_WORD0,
10743871c387SMichael Stapelberg 				((phydev->attached_dev->dev_addr[1] << 8) |
10753871c387SMichael Stapelberg 				 phydev->attached_dev->dev_addr[0]));
10763871c387SMichael Stapelberg 		if (err < 0)
10773871c387SMichael Stapelberg 			return err;
10783871c387SMichael Stapelberg 
10793871c387SMichael Stapelberg 		/* Clear WOL status and enable magic packet matching */
10803871c387SMichael Stapelberg 		temp = phy_read(phydev, MII_88E1318S_PHY_WOL_CTRL);
10813871c387SMichael Stapelberg 		temp |= MII_88E1318S_PHY_WOL_CTRL_CLEAR_WOL_STATUS;
10823871c387SMichael Stapelberg 		temp |= MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE;
10833871c387SMichael Stapelberg 		err = phy_write(phydev, MII_88E1318S_PHY_WOL_CTRL, temp);
10843871c387SMichael Stapelberg 		if (err < 0)
10853871c387SMichael Stapelberg 			return err;
10863871c387SMichael Stapelberg 	} else {
10873871c387SMichael Stapelberg 		err = phy_write(phydev, MII_MARVELL_PHY_PAGE,
10883871c387SMichael Stapelberg 				MII_88E1318S_PHY_WOL_PAGE);
10893871c387SMichael Stapelberg 		if (err < 0)
10903871c387SMichael Stapelberg 			return err;
10913871c387SMichael Stapelberg 
10923871c387SMichael Stapelberg 		/* Clear WOL status and disable magic packet matching */
10933871c387SMichael Stapelberg 		temp = phy_read(phydev, MII_88E1318S_PHY_WOL_CTRL);
10943871c387SMichael Stapelberg 		temp |= MII_88E1318S_PHY_WOL_CTRL_CLEAR_WOL_STATUS;
10953871c387SMichael Stapelberg 		temp &= ~MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE;
10963871c387SMichael Stapelberg 		err = phy_write(phydev, MII_88E1318S_PHY_WOL_CTRL, temp);
10973871c387SMichael Stapelberg 		if (err < 0)
10983871c387SMichael Stapelberg 			return err;
10993871c387SMichael Stapelberg 	}
11003871c387SMichael Stapelberg 
11013871c387SMichael Stapelberg 	err = phy_write(phydev, MII_MARVELL_PHY_PAGE, oldpage);
11023871c387SMichael Stapelberg 	if (err < 0)
11033871c387SMichael Stapelberg 		return err;
11043871c387SMichael Stapelberg 
11053871c387SMichael Stapelberg 	return 0;
11063871c387SMichael Stapelberg }
11073871c387SMichael Stapelberg 
1108d2fa47d9SAndrew Lunn static int marvell_get_sset_count(struct phy_device *phydev)
1109d2fa47d9SAndrew Lunn {
1110d2fa47d9SAndrew Lunn 	return ARRAY_SIZE(marvell_hw_stats);
1111d2fa47d9SAndrew Lunn }
1112d2fa47d9SAndrew Lunn 
1113d2fa47d9SAndrew Lunn static void marvell_get_strings(struct phy_device *phydev, u8 *data)
1114d2fa47d9SAndrew Lunn {
1115d2fa47d9SAndrew Lunn 	int i;
1116d2fa47d9SAndrew Lunn 
1117d2fa47d9SAndrew Lunn 	for (i = 0; i < ARRAY_SIZE(marvell_hw_stats); i++) {
1118d2fa47d9SAndrew Lunn 		memcpy(data + i * ETH_GSTRING_LEN,
1119d2fa47d9SAndrew Lunn 		       marvell_hw_stats[i].string, ETH_GSTRING_LEN);
1120d2fa47d9SAndrew Lunn 	}
1121d2fa47d9SAndrew Lunn }
1122d2fa47d9SAndrew Lunn 
1123d2fa47d9SAndrew Lunn #ifndef UINT64_MAX
1124d2fa47d9SAndrew Lunn #define UINT64_MAX              (u64)(~((u64)0))
1125d2fa47d9SAndrew Lunn #endif
1126d2fa47d9SAndrew Lunn static u64 marvell_get_stat(struct phy_device *phydev, int i)
1127d2fa47d9SAndrew Lunn {
1128d2fa47d9SAndrew Lunn 	struct marvell_hw_stat stat = marvell_hw_stats[i];
1129d2fa47d9SAndrew Lunn 	struct marvell_priv *priv = phydev->priv;
1130321b4d4bSAndrew Lunn 	int err, oldpage, val;
1131321b4d4bSAndrew Lunn 	u64 ret;
1132d2fa47d9SAndrew Lunn 
1133d2fa47d9SAndrew Lunn 	oldpage = phy_read(phydev, MII_MARVELL_PHY_PAGE);
1134d2fa47d9SAndrew Lunn 	err = phy_write(phydev, MII_MARVELL_PHY_PAGE,
1135d2fa47d9SAndrew Lunn 			stat.page);
1136d2fa47d9SAndrew Lunn 	if (err < 0)
1137d2fa47d9SAndrew Lunn 		return UINT64_MAX;
1138d2fa47d9SAndrew Lunn 
1139d2fa47d9SAndrew Lunn 	val = phy_read(phydev, stat.reg);
1140d2fa47d9SAndrew Lunn 	if (val < 0) {
1141321b4d4bSAndrew Lunn 		ret = UINT64_MAX;
1142d2fa47d9SAndrew Lunn 	} else {
1143d2fa47d9SAndrew Lunn 		val = val & ((1 << stat.bits) - 1);
1144d2fa47d9SAndrew Lunn 		priv->stats[i] += val;
1145321b4d4bSAndrew Lunn 		ret = priv->stats[i];
1146d2fa47d9SAndrew Lunn 	}
1147d2fa47d9SAndrew Lunn 
1148d2fa47d9SAndrew Lunn 	phy_write(phydev, MII_MARVELL_PHY_PAGE, oldpage);
1149d2fa47d9SAndrew Lunn 
1150321b4d4bSAndrew Lunn 	return ret;
1151d2fa47d9SAndrew Lunn }
1152d2fa47d9SAndrew Lunn 
1153d2fa47d9SAndrew Lunn static void marvell_get_stats(struct phy_device *phydev,
1154d2fa47d9SAndrew Lunn 			      struct ethtool_stats *stats, u64 *data)
1155d2fa47d9SAndrew Lunn {
1156d2fa47d9SAndrew Lunn 	int i;
1157d2fa47d9SAndrew Lunn 
1158d2fa47d9SAndrew Lunn 	for (i = 0; i < ARRAY_SIZE(marvell_hw_stats); i++)
1159d2fa47d9SAndrew Lunn 		data[i] = marvell_get_stat(phydev, i);
1160d2fa47d9SAndrew Lunn }
1161d2fa47d9SAndrew Lunn 
1162d2fa47d9SAndrew Lunn static int marvell_probe(struct phy_device *phydev)
1163d2fa47d9SAndrew Lunn {
1164d2fa47d9SAndrew Lunn 	struct marvell_priv *priv;
1165d2fa47d9SAndrew Lunn 
1166e5a03bfdSAndrew Lunn 	priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL);
1167d2fa47d9SAndrew Lunn 	if (!priv)
1168d2fa47d9SAndrew Lunn 		return -ENOMEM;
1169d2fa47d9SAndrew Lunn 
1170d2fa47d9SAndrew Lunn 	phydev->priv = priv;
1171d2fa47d9SAndrew Lunn 
1172d2fa47d9SAndrew Lunn 	return 0;
1173d2fa47d9SAndrew Lunn }
1174d2fa47d9SAndrew Lunn 
1175e5479239SOlof Johansson static struct phy_driver marvell_drivers[] = {
1176e5479239SOlof Johansson 	{
11772f495c39SBenjamin Herrenschmidt 		.phy_id = MARVELL_PHY_ID_88E1101,
11782f495c39SBenjamin Herrenschmidt 		.phy_id_mask = MARVELL_PHY_ID_MASK,
117900db8189SAndy Fleming 		.name = "Marvell 88E1101",
118000db8189SAndy Fleming 		.features = PHY_GBIT_FEATURES,
1181d2fa47d9SAndrew Lunn 		.probe = marvell_probe,
118200db8189SAndy Fleming 		.flags = PHY_HAS_INTERRUPT,
118379be1a1cSClemens Gruber 		.config_init = &marvell_config_init,
118400db8189SAndy Fleming 		.config_aneg = &marvell_config_aneg,
118500db8189SAndy Fleming 		.read_status = &genphy_read_status,
118600db8189SAndy Fleming 		.ack_interrupt = &marvell_ack_interrupt,
118700db8189SAndy Fleming 		.config_intr = &marvell_config_intr,
11880898b448SSebastian Hesselbarth 		.resume = &genphy_resume,
11890898b448SSebastian Hesselbarth 		.suspend = &genphy_suspend,
1190d2fa47d9SAndrew Lunn 		.get_sset_count = marvell_get_sset_count,
1191d2fa47d9SAndrew Lunn 		.get_strings = marvell_get_strings,
1192d2fa47d9SAndrew Lunn 		.get_stats = marvell_get_stats,
1193e5479239SOlof Johansson 	},
1194e5479239SOlof Johansson 	{
11952f495c39SBenjamin Herrenschmidt 		.phy_id = MARVELL_PHY_ID_88E1112,
11962f495c39SBenjamin Herrenschmidt 		.phy_id_mask = MARVELL_PHY_ID_MASK,
119785cfb534SOlof Johansson 		.name = "Marvell 88E1112",
119885cfb534SOlof Johansson 		.features = PHY_GBIT_FEATURES,
119985cfb534SOlof Johansson 		.flags = PHY_HAS_INTERRUPT,
1200d2fa47d9SAndrew Lunn 		.probe = marvell_probe,
120185cfb534SOlof Johansson 		.config_init = &m88e1111_config_init,
120285cfb534SOlof Johansson 		.config_aneg = &marvell_config_aneg,
120385cfb534SOlof Johansson 		.read_status = &genphy_read_status,
120485cfb534SOlof Johansson 		.ack_interrupt = &marvell_ack_interrupt,
120585cfb534SOlof Johansson 		.config_intr = &marvell_config_intr,
12060898b448SSebastian Hesselbarth 		.resume = &genphy_resume,
12070898b448SSebastian Hesselbarth 		.suspend = &genphy_suspend,
1208d2fa47d9SAndrew Lunn 		.get_sset_count = marvell_get_sset_count,
1209d2fa47d9SAndrew Lunn 		.get_strings = marvell_get_strings,
1210d2fa47d9SAndrew Lunn 		.get_stats = marvell_get_stats,
121185cfb534SOlof Johansson 	},
121285cfb534SOlof Johansson 	{
12132f495c39SBenjamin Herrenschmidt 		.phy_id = MARVELL_PHY_ID_88E1111,
12142f495c39SBenjamin Herrenschmidt 		.phy_id_mask = MARVELL_PHY_ID_MASK,
121576884679SAndy Fleming 		.name = "Marvell 88E1111",
121676884679SAndy Fleming 		.features = PHY_GBIT_FEATURES,
121776884679SAndy Fleming 		.flags = PHY_HAS_INTERRUPT,
1218d2fa47d9SAndrew Lunn 		.probe = marvell_probe,
1219e5479239SOlof Johansson 		.config_init = &m88e1111_config_init,
12203ec0a0f1SHarini Katakam 		.config_aneg = &m88e1111_config_aneg,
1221be937f1fSAlexandr Smirnov 		.read_status = &marvell_read_status,
122276884679SAndy Fleming 		.ack_interrupt = &marvell_ack_interrupt,
122376884679SAndy Fleming 		.config_intr = &marvell_config_intr,
12240898b448SSebastian Hesselbarth 		.resume = &genphy_resume,
12250898b448SSebastian Hesselbarth 		.suspend = &genphy_suspend,
1226d2fa47d9SAndrew Lunn 		.get_sset_count = marvell_get_sset_count,
1227d2fa47d9SAndrew Lunn 		.get_strings = marvell_get_strings,
1228d2fa47d9SAndrew Lunn 		.get_stats = marvell_get_stats,
1229e5479239SOlof Johansson 	},
1230e5479239SOlof Johansson 	{
12312f495c39SBenjamin Herrenschmidt 		.phy_id = MARVELL_PHY_ID_88E1118,
12322f495c39SBenjamin Herrenschmidt 		.phy_id_mask = MARVELL_PHY_ID_MASK,
1233605f196eSRon Madrid 		.name = "Marvell 88E1118",
1234605f196eSRon Madrid 		.features = PHY_GBIT_FEATURES,
1235605f196eSRon Madrid 		.flags = PHY_HAS_INTERRUPT,
1236d2fa47d9SAndrew Lunn 		.probe = marvell_probe,
1237605f196eSRon Madrid 		.config_init = &m88e1118_config_init,
1238605f196eSRon Madrid 		.config_aneg = &m88e1118_config_aneg,
1239605f196eSRon Madrid 		.read_status = &genphy_read_status,
1240605f196eSRon Madrid 		.ack_interrupt = &marvell_ack_interrupt,
1241605f196eSRon Madrid 		.config_intr = &marvell_config_intr,
12420898b448SSebastian Hesselbarth 		.resume = &genphy_resume,
12430898b448SSebastian Hesselbarth 		.suspend = &genphy_suspend,
1244d2fa47d9SAndrew Lunn 		.get_sset_count = marvell_get_sset_count,
1245d2fa47d9SAndrew Lunn 		.get_strings = marvell_get_strings,
1246d2fa47d9SAndrew Lunn 		.get_stats = marvell_get_stats,
1247605f196eSRon Madrid 	},
1248605f196eSRon Madrid 	{
12492f495c39SBenjamin Herrenschmidt 		.phy_id = MARVELL_PHY_ID_88E1121R,
12502f495c39SBenjamin Herrenschmidt 		.phy_id_mask = MARVELL_PHY_ID_MASK,
1251140bc929SSergei Poselenov 		.name = "Marvell 88E1121R",
1252140bc929SSergei Poselenov 		.features = PHY_GBIT_FEATURES,
1253140bc929SSergei Poselenov 		.flags = PHY_HAS_INTERRUPT,
1254d2fa47d9SAndrew Lunn 		.probe = marvell_probe,
1255fdecf36fSClemens Gruber 		.config_init = &m88e1121_config_init,
1256140bc929SSergei Poselenov 		.config_aneg = &m88e1121_config_aneg,
1257140bc929SSergei Poselenov 		.read_status = &marvell_read_status,
1258140bc929SSergei Poselenov 		.ack_interrupt = &marvell_ack_interrupt,
1259140bc929SSergei Poselenov 		.config_intr = &marvell_config_intr,
1260dcd07be3SAnatolij Gustschin 		.did_interrupt = &m88e1121_did_interrupt,
12610898b448SSebastian Hesselbarth 		.resume = &genphy_resume,
12620898b448SSebastian Hesselbarth 		.suspend = &genphy_suspend,
1263d2fa47d9SAndrew Lunn 		.get_sset_count = marvell_get_sset_count,
1264d2fa47d9SAndrew Lunn 		.get_strings = marvell_get_strings,
1265d2fa47d9SAndrew Lunn 		.get_stats = marvell_get_stats,
1266140bc929SSergei Poselenov 	},
1267140bc929SSergei Poselenov 	{
1268337ac9d5SCyril Chemparathy 		.phy_id = MARVELL_PHY_ID_88E1318S,
12696ba74014SLinus Torvalds 		.phy_id_mask = MARVELL_PHY_ID_MASK,
1270337ac9d5SCyril Chemparathy 		.name = "Marvell 88E1318S",
12713ff1c259SCyril Chemparathy 		.features = PHY_GBIT_FEATURES,
12723ff1c259SCyril Chemparathy 		.flags = PHY_HAS_INTERRUPT,
1273d2fa47d9SAndrew Lunn 		.probe = marvell_probe,
1274fdecf36fSClemens Gruber 		.config_init = &m88e1121_config_init,
1275337ac9d5SCyril Chemparathy 		.config_aneg = &m88e1318_config_aneg,
12763ff1c259SCyril Chemparathy 		.read_status = &marvell_read_status,
12773ff1c259SCyril Chemparathy 		.ack_interrupt = &marvell_ack_interrupt,
12783ff1c259SCyril Chemparathy 		.config_intr = &marvell_config_intr,
12793ff1c259SCyril Chemparathy 		.did_interrupt = &m88e1121_did_interrupt,
12803871c387SMichael Stapelberg 		.get_wol = &m88e1318_get_wol,
12813871c387SMichael Stapelberg 		.set_wol = &m88e1318_set_wol,
12820898b448SSebastian Hesselbarth 		.resume = &genphy_resume,
12830898b448SSebastian Hesselbarth 		.suspend = &genphy_suspend,
1284d2fa47d9SAndrew Lunn 		.get_sset_count = marvell_get_sset_count,
1285d2fa47d9SAndrew Lunn 		.get_strings = marvell_get_strings,
1286d2fa47d9SAndrew Lunn 		.get_stats = marvell_get_stats,
12873ff1c259SCyril Chemparathy 	},
12883ff1c259SCyril Chemparathy 	{
12892f495c39SBenjamin Herrenschmidt 		.phy_id = MARVELL_PHY_ID_88E1145,
12902f495c39SBenjamin Herrenschmidt 		.phy_id_mask = MARVELL_PHY_ID_MASK,
129176884679SAndy Fleming 		.name = "Marvell 88E1145",
129276884679SAndy Fleming 		.features = PHY_GBIT_FEATURES,
129376884679SAndy Fleming 		.flags = PHY_HAS_INTERRUPT,
1294d2fa47d9SAndrew Lunn 		.probe = marvell_probe,
129576884679SAndy Fleming 		.config_init = &m88e1145_config_init,
129676884679SAndy Fleming 		.config_aneg = &marvell_config_aneg,
129776884679SAndy Fleming 		.read_status = &genphy_read_status,
129876884679SAndy Fleming 		.ack_interrupt = &marvell_ack_interrupt,
129976884679SAndy Fleming 		.config_intr = &marvell_config_intr,
13000898b448SSebastian Hesselbarth 		.resume = &genphy_resume,
13010898b448SSebastian Hesselbarth 		.suspend = &genphy_suspend,
1302d2fa47d9SAndrew Lunn 		.get_sset_count = marvell_get_sset_count,
1303d2fa47d9SAndrew Lunn 		.get_strings = marvell_get_strings,
1304d2fa47d9SAndrew Lunn 		.get_stats = marvell_get_stats,
1305ac8c635aSOlof Johansson 	},
1306ac8c635aSOlof Johansson 	{
130790600732SDavid Daney 		.phy_id = MARVELL_PHY_ID_88E1149R,
130890600732SDavid Daney 		.phy_id_mask = MARVELL_PHY_ID_MASK,
130990600732SDavid Daney 		.name = "Marvell 88E1149R",
131090600732SDavid Daney 		.features = PHY_GBIT_FEATURES,
131190600732SDavid Daney 		.flags = PHY_HAS_INTERRUPT,
1312d2fa47d9SAndrew Lunn 		.probe = marvell_probe,
131390600732SDavid Daney 		.config_init = &m88e1149_config_init,
131490600732SDavid Daney 		.config_aneg = &m88e1118_config_aneg,
131590600732SDavid Daney 		.read_status = &genphy_read_status,
131690600732SDavid Daney 		.ack_interrupt = &marvell_ack_interrupt,
131790600732SDavid Daney 		.config_intr = &marvell_config_intr,
13180898b448SSebastian Hesselbarth 		.resume = &genphy_resume,
13190898b448SSebastian Hesselbarth 		.suspend = &genphy_suspend,
1320d2fa47d9SAndrew Lunn 		.get_sset_count = marvell_get_sset_count,
1321d2fa47d9SAndrew Lunn 		.get_strings = marvell_get_strings,
1322d2fa47d9SAndrew Lunn 		.get_stats = marvell_get_stats,
132390600732SDavid Daney 	},
132490600732SDavid Daney 	{
13252f495c39SBenjamin Herrenschmidt 		.phy_id = MARVELL_PHY_ID_88E1240,
13262f495c39SBenjamin Herrenschmidt 		.phy_id_mask = MARVELL_PHY_ID_MASK,
1327ac8c635aSOlof Johansson 		.name = "Marvell 88E1240",
1328ac8c635aSOlof Johansson 		.features = PHY_GBIT_FEATURES,
1329ac8c635aSOlof Johansson 		.flags = PHY_HAS_INTERRUPT,
1330d2fa47d9SAndrew Lunn 		.probe = marvell_probe,
1331ac8c635aSOlof Johansson 		.config_init = &m88e1111_config_init,
1332ac8c635aSOlof Johansson 		.config_aneg = &marvell_config_aneg,
1333ac8c635aSOlof Johansson 		.read_status = &genphy_read_status,
1334ac8c635aSOlof Johansson 		.ack_interrupt = &marvell_ack_interrupt,
1335ac8c635aSOlof Johansson 		.config_intr = &marvell_config_intr,
13360898b448SSebastian Hesselbarth 		.resume = &genphy_resume,
13370898b448SSebastian Hesselbarth 		.suspend = &genphy_suspend,
1338d2fa47d9SAndrew Lunn 		.get_sset_count = marvell_get_sset_count,
1339d2fa47d9SAndrew Lunn 		.get_strings = marvell_get_strings,
1340d2fa47d9SAndrew Lunn 		.get_stats = marvell_get_stats,
1341ac8c635aSOlof Johansson 	},
13423da09a51SMichal Simek 	{
13433da09a51SMichal Simek 		.phy_id = MARVELL_PHY_ID_88E1116R,
13443da09a51SMichal Simek 		.phy_id_mask = MARVELL_PHY_ID_MASK,
13453da09a51SMichal Simek 		.name = "Marvell 88E1116R",
13463da09a51SMichal Simek 		.features = PHY_GBIT_FEATURES,
13473da09a51SMichal Simek 		.flags = PHY_HAS_INTERRUPT,
1348d2fa47d9SAndrew Lunn 		.probe = marvell_probe,
13493da09a51SMichal Simek 		.config_init = &m88e1116r_config_init,
13503da09a51SMichal Simek 		.config_aneg = &genphy_config_aneg,
13513da09a51SMichal Simek 		.read_status = &genphy_read_status,
13523da09a51SMichal Simek 		.ack_interrupt = &marvell_ack_interrupt,
13533da09a51SMichal Simek 		.config_intr = &marvell_config_intr,
13540898b448SSebastian Hesselbarth 		.resume = &genphy_resume,
13550898b448SSebastian Hesselbarth 		.suspend = &genphy_suspend,
1356d2fa47d9SAndrew Lunn 		.get_sset_count = marvell_get_sset_count,
1357d2fa47d9SAndrew Lunn 		.get_strings = marvell_get_strings,
1358d2fa47d9SAndrew Lunn 		.get_stats = marvell_get_stats,
13593da09a51SMichal Simek 	},
136010e24caaSMichal Simek 	{
136110e24caaSMichal Simek 		.phy_id = MARVELL_PHY_ID_88E1510,
136210e24caaSMichal Simek 		.phy_id_mask = MARVELL_PHY_ID_MASK,
136310e24caaSMichal Simek 		.name = "Marvell 88E1510",
136410e24caaSMichal Simek 		.features = PHY_GBIT_FEATURES,
136510e24caaSMichal Simek 		.flags = PHY_HAS_INTERRUPT,
1366d2fa47d9SAndrew Lunn 		.probe = marvell_probe,
1367930b37eeSStefan Roese 		.config_init = &m88e1510_config_init,
136810e24caaSMichal Simek 		.config_aneg = &m88e1510_config_aneg,
136910e24caaSMichal Simek 		.read_status = &marvell_read_status,
137010e24caaSMichal Simek 		.ack_interrupt = &marvell_ack_interrupt,
137110e24caaSMichal Simek 		.config_intr = &marvell_config_intr,
137210e24caaSMichal Simek 		.did_interrupt = &m88e1121_did_interrupt,
13730898b448SSebastian Hesselbarth 		.resume = &genphy_resume,
13740898b448SSebastian Hesselbarth 		.suspend = &genphy_suspend,
1375d2fa47d9SAndrew Lunn 		.get_sset_count = marvell_get_sset_count,
1376d2fa47d9SAndrew Lunn 		.get_strings = marvell_get_strings,
1377d2fa47d9SAndrew Lunn 		.get_stats = marvell_get_stats,
137810e24caaSMichal Simek 	},
13796b358aedSSebastian Hesselbarth 	{
1380819ec8e1SAndrew Lunn 		.phy_id = MARVELL_PHY_ID_88E1540,
1381819ec8e1SAndrew Lunn 		.phy_id_mask = MARVELL_PHY_ID_MASK,
1382819ec8e1SAndrew Lunn 		.name = "Marvell 88E1540",
1383819ec8e1SAndrew Lunn 		.features = PHY_GBIT_FEATURES,
1384819ec8e1SAndrew Lunn 		.flags = PHY_HAS_INTERRUPT,
1385d2fa47d9SAndrew Lunn 		.probe = marvell_probe,
138679be1a1cSClemens Gruber 		.config_init = &marvell_config_init,
1387819ec8e1SAndrew Lunn 		.config_aneg = &m88e1510_config_aneg,
1388819ec8e1SAndrew Lunn 		.read_status = &marvell_read_status,
1389819ec8e1SAndrew Lunn 		.ack_interrupt = &marvell_ack_interrupt,
1390819ec8e1SAndrew Lunn 		.config_intr = &marvell_config_intr,
1391819ec8e1SAndrew Lunn 		.did_interrupt = &m88e1121_did_interrupt,
1392819ec8e1SAndrew Lunn 		.resume = &genphy_resume,
1393819ec8e1SAndrew Lunn 		.suspend = &genphy_suspend,
1394d2fa47d9SAndrew Lunn 		.get_sset_count = marvell_get_sset_count,
1395d2fa47d9SAndrew Lunn 		.get_strings = marvell_get_strings,
1396d2fa47d9SAndrew Lunn 		.get_stats = marvell_get_stats,
1397819ec8e1SAndrew Lunn 	},
1398819ec8e1SAndrew Lunn 	{
13996b358aedSSebastian Hesselbarth 		.phy_id = MARVELL_PHY_ID_88E3016,
14006b358aedSSebastian Hesselbarth 		.phy_id_mask = MARVELL_PHY_ID_MASK,
14016b358aedSSebastian Hesselbarth 		.name = "Marvell 88E3016",
14026b358aedSSebastian Hesselbarth 		.features = PHY_BASIC_FEATURES,
14036b358aedSSebastian Hesselbarth 		.flags = PHY_HAS_INTERRUPT,
1404d2fa47d9SAndrew Lunn 		.probe = marvell_probe,
14056b358aedSSebastian Hesselbarth 		.config_aneg = &genphy_config_aneg,
14066b358aedSSebastian Hesselbarth 		.config_init = &m88e3016_config_init,
14076b358aedSSebastian Hesselbarth 		.aneg_done = &marvell_aneg_done,
14086b358aedSSebastian Hesselbarth 		.read_status = &marvell_read_status,
14096b358aedSSebastian Hesselbarth 		.ack_interrupt = &marvell_ack_interrupt,
14106b358aedSSebastian Hesselbarth 		.config_intr = &marvell_config_intr,
14116b358aedSSebastian Hesselbarth 		.did_interrupt = &m88e1121_did_interrupt,
14126b358aedSSebastian Hesselbarth 		.resume = &genphy_resume,
14136b358aedSSebastian Hesselbarth 		.suspend = &genphy_suspend,
1414d2fa47d9SAndrew Lunn 		.get_sset_count = marvell_get_sset_count,
1415d2fa47d9SAndrew Lunn 		.get_strings = marvell_get_strings,
1416d2fa47d9SAndrew Lunn 		.get_stats = marvell_get_stats,
14176b358aedSSebastian Hesselbarth 	},
141876884679SAndy Fleming };
141976884679SAndy Fleming 
142050fd7150SJohan Hovold module_phy_driver(marvell_drivers);
14214e4f10f6SDavid Woodhouse 
1422cf93c945SUwe Kleine-König static struct mdio_device_id __maybe_unused marvell_tbl[] = {
1423f5e1cabfSMichal Simek 	{ MARVELL_PHY_ID_88E1101, MARVELL_PHY_ID_MASK },
1424f5e1cabfSMichal Simek 	{ MARVELL_PHY_ID_88E1112, MARVELL_PHY_ID_MASK },
1425f5e1cabfSMichal Simek 	{ MARVELL_PHY_ID_88E1111, MARVELL_PHY_ID_MASK },
1426f5e1cabfSMichal Simek 	{ MARVELL_PHY_ID_88E1118, MARVELL_PHY_ID_MASK },
1427f5e1cabfSMichal Simek 	{ MARVELL_PHY_ID_88E1121R, MARVELL_PHY_ID_MASK },
1428f5e1cabfSMichal Simek 	{ MARVELL_PHY_ID_88E1145, MARVELL_PHY_ID_MASK },
1429f5e1cabfSMichal Simek 	{ MARVELL_PHY_ID_88E1149R, MARVELL_PHY_ID_MASK },
1430f5e1cabfSMichal Simek 	{ MARVELL_PHY_ID_88E1240, MARVELL_PHY_ID_MASK },
1431f5e1cabfSMichal Simek 	{ MARVELL_PHY_ID_88E1318S, MARVELL_PHY_ID_MASK },
14323da09a51SMichal Simek 	{ MARVELL_PHY_ID_88E1116R, MARVELL_PHY_ID_MASK },
143310e24caaSMichal Simek 	{ MARVELL_PHY_ID_88E1510, MARVELL_PHY_ID_MASK },
1434819ec8e1SAndrew Lunn 	{ MARVELL_PHY_ID_88E1540, MARVELL_PHY_ID_MASK },
14356b358aedSSebastian Hesselbarth 	{ MARVELL_PHY_ID_88E3016, MARVELL_PHY_ID_MASK },
14364e4f10f6SDavid Woodhouse 	{ }
14374e4f10f6SDavid Woodhouse };
14384e4f10f6SDavid Woodhouse 
14394e4f10f6SDavid Woodhouse MODULE_DEVICE_TABLE(mdio, marvell_tbl);
1440