xref: /openbmc/linux/drivers/net/phy/marvell.c (revision fdecf36f)
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 
288cf41a51dSDavid Daney #ifdef CONFIG_OF_MDIO
289cf41a51dSDavid Daney /*
290cf41a51dSDavid Daney  * Set and/or override some configuration registers based on the
291cf41a51dSDavid Daney  * marvell,reg-init property stored in the of_node for the phydev.
292cf41a51dSDavid Daney  *
293cf41a51dSDavid Daney  * marvell,reg-init = <reg-page reg mask value>,...;
294cf41a51dSDavid Daney  *
295cf41a51dSDavid Daney  * There may be one or more sets of <reg-page reg mask value>:
296cf41a51dSDavid Daney  *
297cf41a51dSDavid Daney  * reg-page: which register bank to use.
298cf41a51dSDavid Daney  * reg: the register.
299cf41a51dSDavid Daney  * mask: if non-zero, ANDed with existing register value.
300cf41a51dSDavid Daney  * value: ORed with the masked value and written to the regiser.
301cf41a51dSDavid Daney  *
302cf41a51dSDavid Daney  */
303cf41a51dSDavid Daney static int marvell_of_reg_init(struct phy_device *phydev)
304cf41a51dSDavid Daney {
305cf41a51dSDavid Daney 	const __be32 *paddr;
306cf41a51dSDavid Daney 	int len, i, saved_page, current_page, page_changed, ret;
307cf41a51dSDavid Daney 
308e5a03bfdSAndrew Lunn 	if (!phydev->mdio.dev.of_node)
309cf41a51dSDavid Daney 		return 0;
310cf41a51dSDavid Daney 
311e5a03bfdSAndrew Lunn 	paddr = of_get_property(phydev->mdio.dev.of_node,
312e5a03bfdSAndrew Lunn 				"marvell,reg-init", &len);
313cf41a51dSDavid Daney 	if (!paddr || len < (4 * sizeof(*paddr)))
314cf41a51dSDavid Daney 		return 0;
315cf41a51dSDavid Daney 
316cf41a51dSDavid Daney 	saved_page = phy_read(phydev, MII_MARVELL_PHY_PAGE);
317cf41a51dSDavid Daney 	if (saved_page < 0)
318cf41a51dSDavid Daney 		return saved_page;
319cf41a51dSDavid Daney 	page_changed = 0;
320cf41a51dSDavid Daney 	current_page = saved_page;
321cf41a51dSDavid Daney 
322cf41a51dSDavid Daney 	ret = 0;
323cf41a51dSDavid Daney 	len /= sizeof(*paddr);
324cf41a51dSDavid Daney 	for (i = 0; i < len - 3; i += 4) {
325cf41a51dSDavid Daney 		u16 reg_page = be32_to_cpup(paddr + i);
326cf41a51dSDavid Daney 		u16 reg = be32_to_cpup(paddr + i + 1);
327cf41a51dSDavid Daney 		u16 mask = be32_to_cpup(paddr + i + 2);
328cf41a51dSDavid Daney 		u16 val_bits = be32_to_cpup(paddr + i + 3);
329cf41a51dSDavid Daney 		int val;
330cf41a51dSDavid Daney 
331cf41a51dSDavid Daney 		if (reg_page != current_page) {
332cf41a51dSDavid Daney 			current_page = reg_page;
333cf41a51dSDavid Daney 			page_changed = 1;
334cf41a51dSDavid Daney 			ret = phy_write(phydev, MII_MARVELL_PHY_PAGE, reg_page);
335cf41a51dSDavid Daney 			if (ret < 0)
336cf41a51dSDavid Daney 				goto err;
337cf41a51dSDavid Daney 		}
338cf41a51dSDavid Daney 
339cf41a51dSDavid Daney 		val = 0;
340cf41a51dSDavid Daney 		if (mask) {
341cf41a51dSDavid Daney 			val = phy_read(phydev, reg);
342cf41a51dSDavid Daney 			if (val < 0) {
343cf41a51dSDavid Daney 				ret = val;
344cf41a51dSDavid Daney 				goto err;
345cf41a51dSDavid Daney 			}
346cf41a51dSDavid Daney 			val &= mask;
347cf41a51dSDavid Daney 		}
348cf41a51dSDavid Daney 		val |= val_bits;
349cf41a51dSDavid Daney 
350cf41a51dSDavid Daney 		ret = phy_write(phydev, reg, val);
351cf41a51dSDavid Daney 		if (ret < 0)
352cf41a51dSDavid Daney 			goto err;
353cf41a51dSDavid Daney 
354cf41a51dSDavid Daney 	}
355cf41a51dSDavid Daney err:
356cf41a51dSDavid Daney 	if (page_changed) {
357cf41a51dSDavid Daney 		i = phy_write(phydev, MII_MARVELL_PHY_PAGE, saved_page);
358cf41a51dSDavid Daney 		if (ret == 0)
359cf41a51dSDavid Daney 			ret = i;
360cf41a51dSDavid Daney 	}
361cf41a51dSDavid Daney 	return ret;
362cf41a51dSDavid Daney }
363cf41a51dSDavid Daney #else
364cf41a51dSDavid Daney static int marvell_of_reg_init(struct phy_device *phydev)
365cf41a51dSDavid Daney {
366cf41a51dSDavid Daney 	return 0;
367cf41a51dSDavid Daney }
368cf41a51dSDavid Daney #endif /* CONFIG_OF_MDIO */
369cf41a51dSDavid Daney 
370140bc929SSergei Poselenov static int m88e1121_config_aneg(struct phy_device *phydev)
371140bc929SSergei Poselenov {
372c477d044SCyril Chemparathy 	int err, oldpage, mscr;
373c477d044SCyril Chemparathy 
37427d916d6SDavid Daney 	oldpage = phy_read(phydev, MII_MARVELL_PHY_PAGE);
375c477d044SCyril Chemparathy 
37627d916d6SDavid Daney 	err = phy_write(phydev, MII_MARVELL_PHY_PAGE,
377c477d044SCyril Chemparathy 			MII_88E1121_PHY_MSCR_PAGE);
378c477d044SCyril Chemparathy 	if (err < 0)
379c477d044SCyril Chemparathy 		return err;
380be8c6480SArnaud Patard 
38132a64161SFlorian Fainelli 	if (phy_interface_is_rgmii(phydev)) {
382be8c6480SArnaud Patard 
383c477d044SCyril Chemparathy 		mscr = phy_read(phydev, MII_88E1121_PHY_MSCR_REG) &
384c477d044SCyril Chemparathy 			MII_88E1121_PHY_MSCR_DELAY_MASK;
385c477d044SCyril Chemparathy 
386c477d044SCyril Chemparathy 		if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)
387c477d044SCyril Chemparathy 			mscr |= (MII_88E1121_PHY_MSCR_RX_DELAY |
388c477d044SCyril Chemparathy 				 MII_88E1121_PHY_MSCR_TX_DELAY);
389c477d044SCyril Chemparathy 		else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID)
390c477d044SCyril Chemparathy 			mscr |= MII_88E1121_PHY_MSCR_RX_DELAY;
391c477d044SCyril Chemparathy 		else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)
392c477d044SCyril Chemparathy 			mscr |= MII_88E1121_PHY_MSCR_TX_DELAY;
393c477d044SCyril Chemparathy 
394c477d044SCyril Chemparathy 		err = phy_write(phydev, MII_88E1121_PHY_MSCR_REG, mscr);
395c477d044SCyril Chemparathy 		if (err < 0)
396c477d044SCyril Chemparathy 			return err;
397be8c6480SArnaud Patard 	}
398c477d044SCyril Chemparathy 
39927d916d6SDavid Daney 	phy_write(phydev, MII_MARVELL_PHY_PAGE, oldpage);
400140bc929SSergei Poselenov 
401140bc929SSergei Poselenov 	err = phy_write(phydev, MII_BMCR, BMCR_RESET);
402140bc929SSergei Poselenov 	if (err < 0)
403140bc929SSergei Poselenov 		return err;
404140bc929SSergei Poselenov 
405140bc929SSergei Poselenov 	err = phy_write(phydev, MII_M1011_PHY_SCR,
406140bc929SSergei Poselenov 			MII_M1011_PHY_SCR_AUTO_CROSS);
407140bc929SSergei Poselenov 	if (err < 0)
408140bc929SSergei Poselenov 		return err;
409140bc929SSergei Poselenov 
410fdecf36fSClemens Gruber 	return genphy_config_aneg(phydev);
411140bc929SSergei Poselenov }
412140bc929SSergei Poselenov 
413337ac9d5SCyril Chemparathy static int m88e1318_config_aneg(struct phy_device *phydev)
4143ff1c259SCyril Chemparathy {
4153ff1c259SCyril Chemparathy 	int err, oldpage, mscr;
4163ff1c259SCyril Chemparathy 
41727d916d6SDavid Daney 	oldpage = phy_read(phydev, MII_MARVELL_PHY_PAGE);
4183ff1c259SCyril Chemparathy 
41927d916d6SDavid Daney 	err = phy_write(phydev, MII_MARVELL_PHY_PAGE,
4203ff1c259SCyril Chemparathy 			MII_88E1121_PHY_MSCR_PAGE);
4213ff1c259SCyril Chemparathy 	if (err < 0)
4223ff1c259SCyril Chemparathy 		return err;
4233ff1c259SCyril Chemparathy 
424337ac9d5SCyril Chemparathy 	mscr = phy_read(phydev, MII_88E1318S_PHY_MSCR1_REG);
425337ac9d5SCyril Chemparathy 	mscr |= MII_88E1318S_PHY_MSCR1_PAD_ODD;
4263ff1c259SCyril Chemparathy 
427337ac9d5SCyril Chemparathy 	err = phy_write(phydev, MII_88E1318S_PHY_MSCR1_REG, mscr);
4283ff1c259SCyril Chemparathy 	if (err < 0)
4293ff1c259SCyril Chemparathy 		return err;
4303ff1c259SCyril Chemparathy 
43127d916d6SDavid Daney 	err = phy_write(phydev, MII_MARVELL_PHY_PAGE, oldpage);
4323ff1c259SCyril Chemparathy 	if (err < 0)
4333ff1c259SCyril Chemparathy 		return err;
4343ff1c259SCyril Chemparathy 
4353ff1c259SCyril Chemparathy 	return m88e1121_config_aneg(phydev);
4363ff1c259SCyril Chemparathy }
4373ff1c259SCyril Chemparathy 
43810e24caaSMichal Simek static int m88e1510_config_aneg(struct phy_device *phydev)
43910e24caaSMichal Simek {
44010e24caaSMichal Simek 	int err;
44110e24caaSMichal Simek 
44210e24caaSMichal Simek 	err = m88e1318_config_aneg(phydev);
44310e24caaSMichal Simek 	if (err < 0)
44410e24caaSMichal Simek 		return err;
44510e24caaSMichal Simek 
44679be1a1cSClemens Gruber 	return 0;
44779be1a1cSClemens Gruber }
44879be1a1cSClemens Gruber 
44979be1a1cSClemens Gruber static int marvell_config_init(struct phy_device *phydev)
45079be1a1cSClemens Gruber {
45179be1a1cSClemens Gruber 	/* Set registers from marvell,reg-init DT property */
45210e24caaSMichal Simek 	return marvell_of_reg_init(phydev);
45310e24caaSMichal Simek }
45410e24caaSMichal Simek 
4553da09a51SMichal Simek static int m88e1116r_config_init(struct phy_device *phydev)
4563da09a51SMichal Simek {
4573da09a51SMichal Simek 	int temp;
4583da09a51SMichal Simek 	int err;
4593da09a51SMichal Simek 
4603da09a51SMichal Simek 	temp = phy_read(phydev, MII_BMCR);
4613da09a51SMichal Simek 	temp |= BMCR_RESET;
4623da09a51SMichal Simek 	err = phy_write(phydev, MII_BMCR, temp);
4633da09a51SMichal Simek 	if (err < 0)
4643da09a51SMichal Simek 		return err;
4653da09a51SMichal Simek 
4663da09a51SMichal Simek 	mdelay(500);
4673da09a51SMichal Simek 
4683da09a51SMichal Simek 	err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0);
4693da09a51SMichal Simek 	if (err < 0)
4703da09a51SMichal Simek 		return err;
4713da09a51SMichal Simek 
4723da09a51SMichal Simek 	temp = phy_read(phydev, MII_M1011_PHY_SCR);
4733da09a51SMichal Simek 	temp |= (7 << 12);	/* max number of gigabit attempts */
4743da09a51SMichal Simek 	temp |= (1 << 11);	/* enable downshift */
4753da09a51SMichal Simek 	temp |= MII_M1011_PHY_SCR_AUTO_CROSS;
4763da09a51SMichal Simek 	err = phy_write(phydev, MII_M1011_PHY_SCR, temp);
4773da09a51SMichal Simek 	if (err < 0)
4783da09a51SMichal Simek 		return err;
4793da09a51SMichal Simek 
4803da09a51SMichal Simek 	err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 2);
4813da09a51SMichal Simek 	if (err < 0)
4823da09a51SMichal Simek 		return err;
4833da09a51SMichal Simek 	temp = phy_read(phydev, MII_M1116R_CONTROL_REG_MAC);
4843da09a51SMichal Simek 	temp |= (1 << 5);
4853da09a51SMichal Simek 	temp |= (1 << 4);
4863da09a51SMichal Simek 	err = phy_write(phydev, MII_M1116R_CONTROL_REG_MAC, temp);
4873da09a51SMichal Simek 	if (err < 0)
4883da09a51SMichal Simek 		return err;
4893da09a51SMichal Simek 	err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0);
4903da09a51SMichal Simek 	if (err < 0)
4913da09a51SMichal Simek 		return err;
4923da09a51SMichal Simek 
4933da09a51SMichal Simek 	temp = phy_read(phydev, MII_BMCR);
4943da09a51SMichal Simek 	temp |= BMCR_RESET;
4953da09a51SMichal Simek 	err = phy_write(phydev, MII_BMCR, temp);
4963da09a51SMichal Simek 	if (err < 0)
4973da09a51SMichal Simek 		return err;
4983da09a51SMichal Simek 
4993da09a51SMichal Simek 	mdelay(500);
5003da09a51SMichal Simek 
50179be1a1cSClemens Gruber 	return marvell_config_init(phydev);
5023da09a51SMichal Simek }
5033da09a51SMichal Simek 
5046b358aedSSebastian Hesselbarth static int m88e3016_config_init(struct phy_device *phydev)
5056b358aedSSebastian Hesselbarth {
5066b358aedSSebastian Hesselbarth 	int reg;
5076b358aedSSebastian Hesselbarth 
5086b358aedSSebastian Hesselbarth 	/* Enable Scrambler and Auto-Crossover */
5096b358aedSSebastian Hesselbarth 	reg = phy_read(phydev, MII_88E3016_PHY_SPEC_CTRL);
5106b358aedSSebastian Hesselbarth 	if (reg < 0)
5116b358aedSSebastian Hesselbarth 		return reg;
5126b358aedSSebastian Hesselbarth 
5136b358aedSSebastian Hesselbarth 	reg &= ~MII_88E3016_DISABLE_SCRAMBLER;
5146b358aedSSebastian Hesselbarth 	reg |= MII_88E3016_AUTO_MDIX_CROSSOVER;
5156b358aedSSebastian Hesselbarth 
5166b358aedSSebastian Hesselbarth 	reg = phy_write(phydev, MII_88E3016_PHY_SPEC_CTRL, reg);
5176b358aedSSebastian Hesselbarth 	if (reg < 0)
5186b358aedSSebastian Hesselbarth 		return reg;
5196b358aedSSebastian Hesselbarth 
52079be1a1cSClemens Gruber 	return marvell_config_init(phydev);
5216b358aedSSebastian Hesselbarth }
5226b358aedSSebastian Hesselbarth 
523895ee682SKim Phillips static int m88e1111_config_init(struct phy_device *phydev)
524895ee682SKim Phillips {
525895ee682SKim Phillips 	int err;
526be937f1fSAlexandr Smirnov 	int temp;
527be937f1fSAlexandr Smirnov 
52832a64161SFlorian Fainelli 	if (phy_interface_is_rgmii(phydev)) {
529895ee682SKim Phillips 
530895ee682SKim Phillips 		temp = phy_read(phydev, MII_M1111_PHY_EXT_CR);
531895ee682SKim Phillips 		if (temp < 0)
532895ee682SKim Phillips 			return temp;
533895ee682SKim Phillips 
5349daf5a76SKim Phillips 		if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) {
535895ee682SKim Phillips 			temp |= (MII_M1111_RX_DELAY | MII_M1111_TX_DELAY);
5369daf5a76SKim Phillips 		} else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) {
5379daf5a76SKim Phillips 			temp &= ~MII_M1111_TX_DELAY;
5389daf5a76SKim Phillips 			temp |= MII_M1111_RX_DELAY;
5399daf5a76SKim Phillips 		} else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) {
5409daf5a76SKim Phillips 			temp &= ~MII_M1111_RX_DELAY;
5419daf5a76SKim Phillips 			temp |= MII_M1111_TX_DELAY;
5429daf5a76SKim Phillips 		}
543895ee682SKim Phillips 
544895ee682SKim Phillips 		err = phy_write(phydev, MII_M1111_PHY_EXT_CR, temp);
545895ee682SKim Phillips 		if (err < 0)
546895ee682SKim Phillips 			return err;
547895ee682SKim Phillips 
548895ee682SKim Phillips 		temp = phy_read(phydev, MII_M1111_PHY_EXT_SR);
549895ee682SKim Phillips 		if (temp < 0)
550895ee682SKim Phillips 			return temp;
551895ee682SKim Phillips 
552895ee682SKim Phillips 		temp &= ~(MII_M1111_HWCFG_MODE_MASK);
553be937f1fSAlexandr Smirnov 
5547239016dSWang Jian 		if (temp & MII_M1111_HWCFG_FIBER_COPPER_RES)
555be937f1fSAlexandr Smirnov 			temp |= MII_M1111_HWCFG_MODE_FIBER_RGMII;
556be937f1fSAlexandr Smirnov 		else
557be937f1fSAlexandr Smirnov 			temp |= MII_M1111_HWCFG_MODE_COPPER_RGMII;
558895ee682SKim Phillips 
559895ee682SKim Phillips 		err = phy_write(phydev, MII_M1111_PHY_EXT_SR, temp);
560895ee682SKim Phillips 		if (err < 0)
561895ee682SKim Phillips 			return err;
562895ee682SKim Phillips 	}
563895ee682SKim Phillips 
5644117b5beSKapil Juneja 	if (phydev->interface == PHY_INTERFACE_MODE_SGMII) {
5654117b5beSKapil Juneja 		temp = phy_read(phydev, MII_M1111_PHY_EXT_SR);
5664117b5beSKapil Juneja 		if (temp < 0)
5674117b5beSKapil Juneja 			return temp;
5684117b5beSKapil Juneja 
5694117b5beSKapil Juneja 		temp &= ~(MII_M1111_HWCFG_MODE_MASK);
5704117b5beSKapil Juneja 		temp |= MII_M1111_HWCFG_MODE_SGMII_NO_CLK;
57132d0c1e1SHaiying Wang 		temp |= MII_M1111_HWCFG_FIBER_COPPER_AUTO;
5724117b5beSKapil Juneja 
5734117b5beSKapil Juneja 		err = phy_write(phydev, MII_M1111_PHY_EXT_SR, temp);
5744117b5beSKapil Juneja 		if (err < 0)
5754117b5beSKapil Juneja 			return err;
57607151bc9SMadalin Bucur 
57707151bc9SMadalin Bucur 		/* make sure copper is selected */
57807151bc9SMadalin Bucur 		err = phy_read(phydev, MII_M1145_PHY_EXT_ADDR_PAGE);
57907151bc9SMadalin Bucur 		if (err < 0)
58007151bc9SMadalin Bucur 			return err;
58107151bc9SMadalin Bucur 
58207151bc9SMadalin Bucur 		err = phy_write(phydev, MII_M1145_PHY_EXT_ADDR_PAGE,
58307151bc9SMadalin Bucur 				err & (~0xff));
58407151bc9SMadalin Bucur 		if (err < 0)
58507151bc9SMadalin Bucur 			return err;
5864117b5beSKapil Juneja 	}
5874117b5beSKapil Juneja 
5885f8cbc13SLiu Yu-B13201 	if (phydev->interface == PHY_INTERFACE_MODE_RTBI) {
5895f8cbc13SLiu Yu-B13201 		temp = phy_read(phydev, MII_M1111_PHY_EXT_CR);
5905f8cbc13SLiu Yu-B13201 		if (temp < 0)
5915f8cbc13SLiu Yu-B13201 			return temp;
5925f8cbc13SLiu Yu-B13201 		temp |= (MII_M1111_RX_DELAY | MII_M1111_TX_DELAY);
5935f8cbc13SLiu Yu-B13201 		err = phy_write(phydev, MII_M1111_PHY_EXT_CR, temp);
5945f8cbc13SLiu Yu-B13201 		if (err < 0)
5955f8cbc13SLiu Yu-B13201 			return err;
5965f8cbc13SLiu Yu-B13201 
5975f8cbc13SLiu Yu-B13201 		temp = phy_read(phydev, MII_M1111_PHY_EXT_SR);
5985f8cbc13SLiu Yu-B13201 		if (temp < 0)
5995f8cbc13SLiu Yu-B13201 			return temp;
6005f8cbc13SLiu Yu-B13201 		temp &= ~(MII_M1111_HWCFG_MODE_MASK | MII_M1111_HWCFG_FIBER_COPPER_RES);
6015f8cbc13SLiu Yu-B13201 		temp |= 0x7 | MII_M1111_HWCFG_FIBER_COPPER_AUTO;
6025f8cbc13SLiu Yu-B13201 		err = phy_write(phydev, MII_M1111_PHY_EXT_SR, temp);
6035f8cbc13SLiu Yu-B13201 		if (err < 0)
6045f8cbc13SLiu Yu-B13201 			return err;
6055f8cbc13SLiu Yu-B13201 
6065f8cbc13SLiu Yu-B13201 		/* soft reset */
6075f8cbc13SLiu Yu-B13201 		err = phy_write(phydev, MII_BMCR, BMCR_RESET);
6085f8cbc13SLiu Yu-B13201 		if (err < 0)
6095f8cbc13SLiu Yu-B13201 			return err;
6105f8cbc13SLiu Yu-B13201 		do
6115f8cbc13SLiu Yu-B13201 			temp = phy_read(phydev, MII_BMCR);
6125f8cbc13SLiu Yu-B13201 		while (temp & BMCR_RESET);
6135f8cbc13SLiu Yu-B13201 
6145f8cbc13SLiu Yu-B13201 		temp = phy_read(phydev, MII_M1111_PHY_EXT_SR);
6155f8cbc13SLiu Yu-B13201 		if (temp < 0)
6165f8cbc13SLiu Yu-B13201 			return temp;
6175f8cbc13SLiu Yu-B13201 		temp &= ~(MII_M1111_HWCFG_MODE_MASK | MII_M1111_HWCFG_FIBER_COPPER_RES);
6185f8cbc13SLiu Yu-B13201 		temp |= MII_M1111_HWCFG_MODE_COPPER_RTBI | MII_M1111_HWCFG_FIBER_COPPER_AUTO;
6195f8cbc13SLiu Yu-B13201 		err = phy_write(phydev, MII_M1111_PHY_EXT_SR, temp);
6205f8cbc13SLiu Yu-B13201 		if (err < 0)
6215f8cbc13SLiu Yu-B13201 			return err;
6225f8cbc13SLiu Yu-B13201 	}
6235f8cbc13SLiu Yu-B13201 
624cf41a51dSDavid Daney 	err = marvell_of_reg_init(phydev);
625cf41a51dSDavid Daney 	if (err < 0)
626cf41a51dSDavid Daney 		return err;
6275f8cbc13SLiu Yu-B13201 
628cc90cb3bSSrinivas Kandagatla 	return phy_write(phydev, MII_BMCR, BMCR_RESET);
629895ee682SKim Phillips }
630895ee682SKim Phillips 
631fdecf36fSClemens Gruber static int m88e1121_config_init(struct phy_device *phydev)
632fdecf36fSClemens Gruber {
633fdecf36fSClemens Gruber 	int err, oldpage;
634fdecf36fSClemens Gruber 
635fdecf36fSClemens Gruber 	oldpage = phy_read(phydev, MII_MARVELL_PHY_PAGE);
636fdecf36fSClemens Gruber 
637fdecf36fSClemens Gruber 	err = phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_88E1121_PHY_LED_PAGE);
638fdecf36fSClemens Gruber 	if (err < 0)
639fdecf36fSClemens Gruber 		return err;
640fdecf36fSClemens Gruber 
641fdecf36fSClemens Gruber 	/* Default PHY LED config: LED[0] .. Link, LED[1] .. Activity */
642fdecf36fSClemens Gruber 	err = phy_write(phydev, MII_88E1121_PHY_LED_CTRL,
643fdecf36fSClemens Gruber 			MII_88E1121_PHY_LED_DEF);
644fdecf36fSClemens Gruber 	if (err < 0)
645fdecf36fSClemens Gruber 		return err;
646fdecf36fSClemens Gruber 
647fdecf36fSClemens Gruber 	phy_write(phydev, MII_MARVELL_PHY_PAGE, oldpage);
648fdecf36fSClemens Gruber 
649fdecf36fSClemens Gruber 	/* Set marvell,reg-init configuration from device tree */
650fdecf36fSClemens Gruber 	return marvell_config_init(phydev);
651fdecf36fSClemens Gruber }
652fdecf36fSClemens Gruber 
653407353ecSClemens Gruber static int m88e1510_config_init(struct phy_device *phydev)
654407353ecSClemens Gruber {
655407353ecSClemens Gruber 	int err;
656407353ecSClemens Gruber 	int temp;
657407353ecSClemens Gruber 
658407353ecSClemens Gruber 	/* SGMII-to-Copper mode initialization */
659407353ecSClemens Gruber 	if (phydev->interface == PHY_INTERFACE_MODE_SGMII) {
660407353ecSClemens Gruber 		/* Select page 18 */
661407353ecSClemens Gruber 		err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 18);
662407353ecSClemens Gruber 		if (err < 0)
663407353ecSClemens Gruber 			return err;
664407353ecSClemens Gruber 
665407353ecSClemens Gruber 		/* In reg 20, write MODE[2:0] = 0x1 (SGMII to Copper) */
666407353ecSClemens Gruber 		temp = phy_read(phydev, MII_88E1510_GEN_CTRL_REG_1);
667407353ecSClemens Gruber 		temp &= ~MII_88E1510_GEN_CTRL_REG_1_MODE_MASK;
668407353ecSClemens Gruber 		temp |= MII_88E1510_GEN_CTRL_REG_1_MODE_SGMII;
669407353ecSClemens Gruber 		err = phy_write(phydev, MII_88E1510_GEN_CTRL_REG_1, temp);
670407353ecSClemens Gruber 		if (err < 0)
671407353ecSClemens Gruber 			return err;
672407353ecSClemens Gruber 
673407353ecSClemens Gruber 		/* PHY reset is necessary after changing MODE[2:0] */
674407353ecSClemens Gruber 		temp |= MII_88E1510_GEN_CTRL_REG_1_RESET;
675407353ecSClemens Gruber 		err = phy_write(phydev, MII_88E1510_GEN_CTRL_REG_1, temp);
676407353ecSClemens Gruber 		if (err < 0)
677407353ecSClemens Gruber 			return err;
678407353ecSClemens Gruber 
679407353ecSClemens Gruber 		/* Reset page selection */
680407353ecSClemens Gruber 		err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0);
681407353ecSClemens Gruber 		if (err < 0)
682407353ecSClemens Gruber 			return err;
683407353ecSClemens Gruber 	}
684407353ecSClemens Gruber 
685fdecf36fSClemens Gruber 	return m88e1121_config_init(phydev);
686407353ecSClemens Gruber }
687407353ecSClemens Gruber 
688605f196eSRon Madrid static int m88e1118_config_aneg(struct phy_device *phydev)
689605f196eSRon Madrid {
690605f196eSRon Madrid 	int err;
691605f196eSRon Madrid 
692605f196eSRon Madrid 	err = phy_write(phydev, MII_BMCR, BMCR_RESET);
693605f196eSRon Madrid 	if (err < 0)
694605f196eSRon Madrid 		return err;
695605f196eSRon Madrid 
696605f196eSRon Madrid 	err = phy_write(phydev, MII_M1011_PHY_SCR,
697605f196eSRon Madrid 			MII_M1011_PHY_SCR_AUTO_CROSS);
698605f196eSRon Madrid 	if (err < 0)
699605f196eSRon Madrid 		return err;
700605f196eSRon Madrid 
701605f196eSRon Madrid 	err = genphy_config_aneg(phydev);
702605f196eSRon Madrid 	return 0;
703605f196eSRon Madrid }
704605f196eSRon Madrid 
705605f196eSRon Madrid static int m88e1118_config_init(struct phy_device *phydev)
706605f196eSRon Madrid {
707605f196eSRon Madrid 	int err;
708605f196eSRon Madrid 
709605f196eSRon Madrid 	/* Change address */
71027d916d6SDavid Daney 	err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0002);
711605f196eSRon Madrid 	if (err < 0)
712605f196eSRon Madrid 		return err;
713605f196eSRon Madrid 
714605f196eSRon Madrid 	/* Enable 1000 Mbit */
715605f196eSRon Madrid 	err = phy_write(phydev, 0x15, 0x1070);
716605f196eSRon Madrid 	if (err < 0)
717605f196eSRon Madrid 		return err;
718605f196eSRon Madrid 
719605f196eSRon Madrid 	/* Change address */
72027d916d6SDavid Daney 	err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0003);
721605f196eSRon Madrid 	if (err < 0)
722605f196eSRon Madrid 		return err;
723605f196eSRon Madrid 
724605f196eSRon Madrid 	/* Adjust LED Control */
7252f495c39SBenjamin Herrenschmidt 	if (phydev->dev_flags & MARVELL_PHY_M1118_DNS323_LEDS)
7262f495c39SBenjamin Herrenschmidt 		err = phy_write(phydev, 0x10, 0x1100);
7272f495c39SBenjamin Herrenschmidt 	else
728605f196eSRon Madrid 		err = phy_write(phydev, 0x10, 0x021e);
729605f196eSRon Madrid 	if (err < 0)
730605f196eSRon Madrid 		return err;
731605f196eSRon Madrid 
732cf41a51dSDavid Daney 	err = marvell_of_reg_init(phydev);
733cf41a51dSDavid Daney 	if (err < 0)
734cf41a51dSDavid Daney 		return err;
735cf41a51dSDavid Daney 
736605f196eSRon Madrid 	/* Reset address */
73727d916d6SDavid Daney 	err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0);
738605f196eSRon Madrid 	if (err < 0)
739605f196eSRon Madrid 		return err;
740605f196eSRon Madrid 
741cc90cb3bSSrinivas Kandagatla 	return phy_write(phydev, MII_BMCR, BMCR_RESET);
742605f196eSRon Madrid }
743605f196eSRon Madrid 
74490600732SDavid Daney static int m88e1149_config_init(struct phy_device *phydev)
74590600732SDavid Daney {
74690600732SDavid Daney 	int err;
74790600732SDavid Daney 
74890600732SDavid Daney 	/* Change address */
74990600732SDavid Daney 	err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0002);
75090600732SDavid Daney 	if (err < 0)
75190600732SDavid Daney 		return err;
75290600732SDavid Daney 
75390600732SDavid Daney 	/* Enable 1000 Mbit */
75490600732SDavid Daney 	err = phy_write(phydev, 0x15, 0x1048);
75590600732SDavid Daney 	if (err < 0)
75690600732SDavid Daney 		return err;
75790600732SDavid Daney 
758cf41a51dSDavid Daney 	err = marvell_of_reg_init(phydev);
759cf41a51dSDavid Daney 	if (err < 0)
760cf41a51dSDavid Daney 		return err;
761cf41a51dSDavid Daney 
76290600732SDavid Daney 	/* Reset address */
76390600732SDavid Daney 	err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0);
76490600732SDavid Daney 	if (err < 0)
76590600732SDavid Daney 		return err;
76690600732SDavid Daney 
767cc90cb3bSSrinivas Kandagatla 	return phy_write(phydev, MII_BMCR, BMCR_RESET);
76890600732SDavid Daney }
76990600732SDavid Daney 
77076884679SAndy Fleming static int m88e1145_config_init(struct phy_device *phydev)
77176884679SAndy Fleming {
77276884679SAndy Fleming 	int err;
773b0224175SViet Nga Dao 	int temp;
77476884679SAndy Fleming 
77576884679SAndy Fleming 	/* Take care of errata E0 & E1 */
77676884679SAndy Fleming 	err = phy_write(phydev, 0x1d, 0x001b);
77776884679SAndy Fleming 	if (err < 0)
77876884679SAndy Fleming 		return err;
77976884679SAndy Fleming 
78076884679SAndy Fleming 	err = phy_write(phydev, 0x1e, 0x418f);
78176884679SAndy Fleming 	if (err < 0)
78276884679SAndy Fleming 		return err;
78376884679SAndy Fleming 
78476884679SAndy Fleming 	err = phy_write(phydev, 0x1d, 0x0016);
78576884679SAndy Fleming 	if (err < 0)
78676884679SAndy Fleming 		return err;
78776884679SAndy Fleming 
78876884679SAndy Fleming 	err = phy_write(phydev, 0x1e, 0xa2da);
78976884679SAndy Fleming 	if (err < 0)
79076884679SAndy Fleming 		return err;
79176884679SAndy Fleming 
792895ee682SKim Phillips 	if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) {
79376884679SAndy Fleming 		int temp = phy_read(phydev, MII_M1145_PHY_EXT_CR);
79476884679SAndy Fleming 		if (temp < 0)
79576884679SAndy Fleming 			return temp;
79676884679SAndy Fleming 
79776884679SAndy Fleming 		temp |= (MII_M1145_RGMII_RX_DELAY | MII_M1145_RGMII_TX_DELAY);
79876884679SAndy Fleming 
79976884679SAndy Fleming 		err = phy_write(phydev, MII_M1145_PHY_EXT_CR, temp);
80076884679SAndy Fleming 		if (err < 0)
80176884679SAndy Fleming 			return err;
80276884679SAndy Fleming 
8032f495c39SBenjamin Herrenschmidt 		if (phydev->dev_flags & MARVELL_PHY_M1145_FLAGS_RESISTANCE) {
80476884679SAndy Fleming 			err = phy_write(phydev, 0x1d, 0x0012);
80576884679SAndy Fleming 			if (err < 0)
80676884679SAndy Fleming 				return err;
80776884679SAndy Fleming 
80876884679SAndy Fleming 			temp = phy_read(phydev, 0x1e);
80976884679SAndy Fleming 			if (temp < 0)
81076884679SAndy Fleming 				return temp;
81176884679SAndy Fleming 
81276884679SAndy Fleming 			temp &= 0xf03f;
81376884679SAndy Fleming 			temp |= 2 << 9;	/* 36 ohm */
81476884679SAndy Fleming 			temp |= 2 << 6;	/* 39 ohm */
81576884679SAndy Fleming 
81676884679SAndy Fleming 			err = phy_write(phydev, 0x1e, temp);
81776884679SAndy Fleming 			if (err < 0)
81876884679SAndy Fleming 				return err;
81976884679SAndy Fleming 
82076884679SAndy Fleming 			err = phy_write(phydev, 0x1d, 0x3);
82176884679SAndy Fleming 			if (err < 0)
82276884679SAndy Fleming 				return err;
82376884679SAndy Fleming 
82476884679SAndy Fleming 			err = phy_write(phydev, 0x1e, 0x8000);
82576884679SAndy Fleming 			if (err < 0)
82676884679SAndy Fleming 				return err;
82776884679SAndy Fleming 		}
82876884679SAndy Fleming 	}
82976884679SAndy Fleming 
830b0224175SViet Nga Dao 	if (phydev->interface == PHY_INTERFACE_MODE_SGMII) {
831b0224175SViet Nga Dao 		temp = phy_read(phydev, MII_M1145_PHY_EXT_SR);
832b0224175SViet Nga Dao 		if (temp < 0)
833b0224175SViet Nga Dao 			return temp;
834b0224175SViet Nga Dao 
83599d881f9SVince Bridgers 		temp &= ~MII_M1145_HWCFG_MODE_MASK;
836b0224175SViet Nga Dao 		temp |= MII_M1145_HWCFG_MODE_SGMII_NO_CLK;
837b0224175SViet Nga Dao 		temp |= MII_M1145_HWCFG_FIBER_COPPER_AUTO;
838b0224175SViet Nga Dao 
839b0224175SViet Nga Dao 		err = phy_write(phydev, MII_M1145_PHY_EXT_SR, temp);
840b0224175SViet Nga Dao 		if (err < 0)
841b0224175SViet Nga Dao 			return err;
842b0224175SViet Nga Dao 	}
843b0224175SViet Nga Dao 
844cf41a51dSDavid Daney 	err = marvell_of_reg_init(phydev);
845cf41a51dSDavid Daney 	if (err < 0)
846cf41a51dSDavid Daney 		return err;
847cf41a51dSDavid Daney 
84876884679SAndy Fleming 	return 0;
84976884679SAndy Fleming }
85000db8189SAndy Fleming 
851be937f1fSAlexandr Smirnov /* marvell_read_status
852be937f1fSAlexandr Smirnov  *
853be937f1fSAlexandr Smirnov  * Generic status code does not detect Fiber correctly!
854be937f1fSAlexandr Smirnov  * Description:
855be937f1fSAlexandr Smirnov  *   Check the link, then figure out the current state
856be937f1fSAlexandr Smirnov  *   by comparing what we advertise with what the link partner
857be937f1fSAlexandr Smirnov  *   advertises.  Start by checking the gigabit possibilities,
858be937f1fSAlexandr Smirnov  *   then move on to 10/100.
859be937f1fSAlexandr Smirnov  */
860be937f1fSAlexandr Smirnov static int marvell_read_status(struct phy_device *phydev)
861be937f1fSAlexandr Smirnov {
862be937f1fSAlexandr Smirnov 	int adv;
863be937f1fSAlexandr Smirnov 	int err;
864be937f1fSAlexandr Smirnov 	int lpa;
865357cd64cSRussell King 	int lpagb;
866be937f1fSAlexandr Smirnov 	int status = 0;
867be937f1fSAlexandr Smirnov 
868be937f1fSAlexandr Smirnov 	/* Update the link, but return if there
869be937f1fSAlexandr Smirnov 	 * was an error */
870be937f1fSAlexandr Smirnov 	err = genphy_update_link(phydev);
871be937f1fSAlexandr Smirnov 	if (err)
872be937f1fSAlexandr Smirnov 		return err;
873be937f1fSAlexandr Smirnov 
874be937f1fSAlexandr Smirnov 	if (AUTONEG_ENABLE == phydev->autoneg) {
875be937f1fSAlexandr Smirnov 		status = phy_read(phydev, MII_M1011_PHY_STATUS);
876be937f1fSAlexandr Smirnov 		if (status < 0)
877be937f1fSAlexandr Smirnov 			return status;
878be937f1fSAlexandr Smirnov 
879be937f1fSAlexandr Smirnov 		lpa = phy_read(phydev, MII_LPA);
880be937f1fSAlexandr Smirnov 		if (lpa < 0)
881be937f1fSAlexandr Smirnov 			return lpa;
882be937f1fSAlexandr Smirnov 
883357cd64cSRussell King 		lpagb = phy_read(phydev, MII_STAT1000);
884357cd64cSRussell King 		if (lpagb < 0)
885357cd64cSRussell King 			return lpagb;
886357cd64cSRussell King 
887be937f1fSAlexandr Smirnov 		adv = phy_read(phydev, MII_ADVERTISE);
888be937f1fSAlexandr Smirnov 		if (adv < 0)
889be937f1fSAlexandr Smirnov 			return adv;
890be937f1fSAlexandr Smirnov 
891357cd64cSRussell King 		phydev->lp_advertising = mii_stat1000_to_ethtool_lpa_t(lpagb) |
892357cd64cSRussell King 					 mii_lpa_to_ethtool_lpa_t(lpa);
893357cd64cSRussell King 
894be937f1fSAlexandr Smirnov 		lpa &= adv;
895be937f1fSAlexandr Smirnov 
896be937f1fSAlexandr Smirnov 		if (status & MII_M1011_PHY_STATUS_FULLDUPLEX)
897be937f1fSAlexandr Smirnov 			phydev->duplex = DUPLEX_FULL;
898be937f1fSAlexandr Smirnov 		else
899be937f1fSAlexandr Smirnov 			phydev->duplex = DUPLEX_HALF;
900be937f1fSAlexandr Smirnov 
901be937f1fSAlexandr Smirnov 		status = status & MII_M1011_PHY_STATUS_SPD_MASK;
902be937f1fSAlexandr Smirnov 		phydev->pause = phydev->asym_pause = 0;
903be937f1fSAlexandr Smirnov 
904be937f1fSAlexandr Smirnov 		switch (status) {
905be937f1fSAlexandr Smirnov 		case MII_M1011_PHY_STATUS_1000:
906be937f1fSAlexandr Smirnov 			phydev->speed = SPEED_1000;
907be937f1fSAlexandr Smirnov 			break;
908be937f1fSAlexandr Smirnov 
909be937f1fSAlexandr Smirnov 		case MII_M1011_PHY_STATUS_100:
910be937f1fSAlexandr Smirnov 			phydev->speed = SPEED_100;
911be937f1fSAlexandr Smirnov 			break;
912be937f1fSAlexandr Smirnov 
913be937f1fSAlexandr Smirnov 		default:
914be937f1fSAlexandr Smirnov 			phydev->speed = SPEED_10;
915be937f1fSAlexandr Smirnov 			break;
916be937f1fSAlexandr Smirnov 		}
917be937f1fSAlexandr Smirnov 
918be937f1fSAlexandr Smirnov 		if (phydev->duplex == DUPLEX_FULL) {
919be937f1fSAlexandr Smirnov 			phydev->pause = lpa & LPA_PAUSE_CAP ? 1 : 0;
920be937f1fSAlexandr Smirnov 			phydev->asym_pause = lpa & LPA_PAUSE_ASYM ? 1 : 0;
921be937f1fSAlexandr Smirnov 		}
922be937f1fSAlexandr Smirnov 	} else {
923be937f1fSAlexandr Smirnov 		int bmcr = phy_read(phydev, MII_BMCR);
924be937f1fSAlexandr Smirnov 
925be937f1fSAlexandr Smirnov 		if (bmcr < 0)
926be937f1fSAlexandr Smirnov 			return bmcr;
927be937f1fSAlexandr Smirnov 
928be937f1fSAlexandr Smirnov 		if (bmcr & BMCR_FULLDPLX)
929be937f1fSAlexandr Smirnov 			phydev->duplex = DUPLEX_FULL;
930be937f1fSAlexandr Smirnov 		else
931be937f1fSAlexandr Smirnov 			phydev->duplex = DUPLEX_HALF;
932be937f1fSAlexandr Smirnov 
933be937f1fSAlexandr Smirnov 		if (bmcr & BMCR_SPEED1000)
934be937f1fSAlexandr Smirnov 			phydev->speed = SPEED_1000;
935be937f1fSAlexandr Smirnov 		else if (bmcr & BMCR_SPEED100)
936be937f1fSAlexandr Smirnov 			phydev->speed = SPEED_100;
937be937f1fSAlexandr Smirnov 		else
938be937f1fSAlexandr Smirnov 			phydev->speed = SPEED_10;
939be937f1fSAlexandr Smirnov 
940be937f1fSAlexandr Smirnov 		phydev->pause = phydev->asym_pause = 0;
941357cd64cSRussell King 		phydev->lp_advertising = 0;
942be937f1fSAlexandr Smirnov 	}
943be937f1fSAlexandr Smirnov 
944be937f1fSAlexandr Smirnov 	return 0;
945be937f1fSAlexandr Smirnov }
946be937f1fSAlexandr Smirnov 
9476b358aedSSebastian Hesselbarth static int marvell_aneg_done(struct phy_device *phydev)
9486b358aedSSebastian Hesselbarth {
9496b358aedSSebastian Hesselbarth 	int retval = phy_read(phydev, MII_M1011_PHY_STATUS);
9506b358aedSSebastian Hesselbarth 	return (retval < 0) ? retval : (retval & MII_M1011_PHY_STATUS_RESOLVED);
9516b358aedSSebastian Hesselbarth }
9526b358aedSSebastian Hesselbarth 
953dcd07be3SAnatolij Gustschin static int m88e1121_did_interrupt(struct phy_device *phydev)
954dcd07be3SAnatolij Gustschin {
955dcd07be3SAnatolij Gustschin 	int imask;
956dcd07be3SAnatolij Gustschin 
957dcd07be3SAnatolij Gustschin 	imask = phy_read(phydev, MII_M1011_IEVENT);
958dcd07be3SAnatolij Gustschin 
959dcd07be3SAnatolij Gustschin 	if (imask & MII_M1011_IMASK_INIT)
960dcd07be3SAnatolij Gustschin 		return 1;
961dcd07be3SAnatolij Gustschin 
962dcd07be3SAnatolij Gustschin 	return 0;
963dcd07be3SAnatolij Gustschin }
964dcd07be3SAnatolij Gustschin 
9653871c387SMichael Stapelberg static void m88e1318_get_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol)
9663871c387SMichael Stapelberg {
9673871c387SMichael Stapelberg 	wol->supported = WAKE_MAGIC;
9683871c387SMichael Stapelberg 	wol->wolopts = 0;
9693871c387SMichael Stapelberg 
9703871c387SMichael Stapelberg 	if (phy_write(phydev, MII_MARVELL_PHY_PAGE,
9713871c387SMichael Stapelberg 		      MII_88E1318S_PHY_WOL_PAGE) < 0)
9723871c387SMichael Stapelberg 		return;
9733871c387SMichael Stapelberg 
9743871c387SMichael Stapelberg 	if (phy_read(phydev, MII_88E1318S_PHY_WOL_CTRL) &
9753871c387SMichael Stapelberg 	    MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE)
9763871c387SMichael Stapelberg 		wol->wolopts |= WAKE_MAGIC;
9773871c387SMichael Stapelberg 
9783871c387SMichael Stapelberg 	if (phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x00) < 0)
9793871c387SMichael Stapelberg 		return;
9803871c387SMichael Stapelberg }
9813871c387SMichael Stapelberg 
9823871c387SMichael Stapelberg static int m88e1318_set_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol)
9833871c387SMichael Stapelberg {
9843871c387SMichael Stapelberg 	int err, oldpage, temp;
9853871c387SMichael Stapelberg 
9863871c387SMichael Stapelberg 	oldpage = phy_read(phydev, MII_MARVELL_PHY_PAGE);
9873871c387SMichael Stapelberg 
9883871c387SMichael Stapelberg 	if (wol->wolopts & WAKE_MAGIC) {
9893871c387SMichael Stapelberg 		/* Explicitly switch to page 0x00, just to be sure */
9903871c387SMichael Stapelberg 		err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x00);
9913871c387SMichael Stapelberg 		if (err < 0)
9923871c387SMichael Stapelberg 			return err;
9933871c387SMichael Stapelberg 
9943871c387SMichael Stapelberg 		/* Enable the WOL interrupt */
9953871c387SMichael Stapelberg 		temp = phy_read(phydev, MII_88E1318S_PHY_CSIER);
9963871c387SMichael Stapelberg 		temp |= MII_88E1318S_PHY_CSIER_WOL_EIE;
9973871c387SMichael Stapelberg 		err = phy_write(phydev, MII_88E1318S_PHY_CSIER, temp);
9983871c387SMichael Stapelberg 		if (err < 0)
9993871c387SMichael Stapelberg 			return err;
10003871c387SMichael Stapelberg 
10013871c387SMichael Stapelberg 		err = phy_write(phydev, MII_MARVELL_PHY_PAGE,
10023871c387SMichael Stapelberg 				MII_88E1318S_PHY_LED_PAGE);
10033871c387SMichael Stapelberg 		if (err < 0)
10043871c387SMichael Stapelberg 			return err;
10053871c387SMichael Stapelberg 
10063871c387SMichael Stapelberg 		/* Setup LED[2] as interrupt pin (active low) */
10073871c387SMichael Stapelberg 		temp = phy_read(phydev, MII_88E1318S_PHY_LED_TCR);
10083871c387SMichael Stapelberg 		temp &= ~MII_88E1318S_PHY_LED_TCR_FORCE_INT;
10093871c387SMichael Stapelberg 		temp |= MII_88E1318S_PHY_LED_TCR_INTn_ENABLE;
10103871c387SMichael Stapelberg 		temp |= MII_88E1318S_PHY_LED_TCR_INT_ACTIVE_LOW;
10113871c387SMichael Stapelberg 		err = phy_write(phydev, MII_88E1318S_PHY_LED_TCR, temp);
10123871c387SMichael Stapelberg 		if (err < 0)
10133871c387SMichael Stapelberg 			return err;
10143871c387SMichael Stapelberg 
10153871c387SMichael Stapelberg 		err = phy_write(phydev, MII_MARVELL_PHY_PAGE,
10163871c387SMichael Stapelberg 				MII_88E1318S_PHY_WOL_PAGE);
10173871c387SMichael Stapelberg 		if (err < 0)
10183871c387SMichael Stapelberg 			return err;
10193871c387SMichael Stapelberg 
10203871c387SMichael Stapelberg 		/* Store the device address for the magic packet */
10213871c387SMichael Stapelberg 		err = phy_write(phydev, MII_88E1318S_PHY_MAGIC_PACKET_WORD2,
10223871c387SMichael Stapelberg 				((phydev->attached_dev->dev_addr[5] << 8) |
10233871c387SMichael Stapelberg 				 phydev->attached_dev->dev_addr[4]));
10243871c387SMichael Stapelberg 		if (err < 0)
10253871c387SMichael Stapelberg 			return err;
10263871c387SMichael Stapelberg 		err = phy_write(phydev, MII_88E1318S_PHY_MAGIC_PACKET_WORD1,
10273871c387SMichael Stapelberg 				((phydev->attached_dev->dev_addr[3] << 8) |
10283871c387SMichael Stapelberg 				 phydev->attached_dev->dev_addr[2]));
10293871c387SMichael Stapelberg 		if (err < 0)
10303871c387SMichael Stapelberg 			return err;
10313871c387SMichael Stapelberg 		err = phy_write(phydev, MII_88E1318S_PHY_MAGIC_PACKET_WORD0,
10323871c387SMichael Stapelberg 				((phydev->attached_dev->dev_addr[1] << 8) |
10333871c387SMichael Stapelberg 				 phydev->attached_dev->dev_addr[0]));
10343871c387SMichael Stapelberg 		if (err < 0)
10353871c387SMichael Stapelberg 			return err;
10363871c387SMichael Stapelberg 
10373871c387SMichael Stapelberg 		/* Clear WOL status and enable magic packet matching */
10383871c387SMichael Stapelberg 		temp = phy_read(phydev, MII_88E1318S_PHY_WOL_CTRL);
10393871c387SMichael Stapelberg 		temp |= MII_88E1318S_PHY_WOL_CTRL_CLEAR_WOL_STATUS;
10403871c387SMichael Stapelberg 		temp |= MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE;
10413871c387SMichael Stapelberg 		err = phy_write(phydev, MII_88E1318S_PHY_WOL_CTRL, temp);
10423871c387SMichael Stapelberg 		if (err < 0)
10433871c387SMichael Stapelberg 			return err;
10443871c387SMichael Stapelberg 	} else {
10453871c387SMichael Stapelberg 		err = phy_write(phydev, MII_MARVELL_PHY_PAGE,
10463871c387SMichael Stapelberg 				MII_88E1318S_PHY_WOL_PAGE);
10473871c387SMichael Stapelberg 		if (err < 0)
10483871c387SMichael Stapelberg 			return err;
10493871c387SMichael Stapelberg 
10503871c387SMichael Stapelberg 		/* Clear WOL status and disable magic packet matching */
10513871c387SMichael Stapelberg 		temp = phy_read(phydev, MII_88E1318S_PHY_WOL_CTRL);
10523871c387SMichael Stapelberg 		temp |= MII_88E1318S_PHY_WOL_CTRL_CLEAR_WOL_STATUS;
10533871c387SMichael Stapelberg 		temp &= ~MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE;
10543871c387SMichael Stapelberg 		err = phy_write(phydev, MII_88E1318S_PHY_WOL_CTRL, temp);
10553871c387SMichael Stapelberg 		if (err < 0)
10563871c387SMichael Stapelberg 			return err;
10573871c387SMichael Stapelberg 	}
10583871c387SMichael Stapelberg 
10593871c387SMichael Stapelberg 	err = phy_write(phydev, MII_MARVELL_PHY_PAGE, oldpage);
10603871c387SMichael Stapelberg 	if (err < 0)
10613871c387SMichael Stapelberg 		return err;
10623871c387SMichael Stapelberg 
10633871c387SMichael Stapelberg 	return 0;
10643871c387SMichael Stapelberg }
10653871c387SMichael Stapelberg 
1066d2fa47d9SAndrew Lunn static int marvell_get_sset_count(struct phy_device *phydev)
1067d2fa47d9SAndrew Lunn {
1068d2fa47d9SAndrew Lunn 	return ARRAY_SIZE(marvell_hw_stats);
1069d2fa47d9SAndrew Lunn }
1070d2fa47d9SAndrew Lunn 
1071d2fa47d9SAndrew Lunn static void marvell_get_strings(struct phy_device *phydev, u8 *data)
1072d2fa47d9SAndrew Lunn {
1073d2fa47d9SAndrew Lunn 	int i;
1074d2fa47d9SAndrew Lunn 
1075d2fa47d9SAndrew Lunn 	for (i = 0; i < ARRAY_SIZE(marvell_hw_stats); i++) {
1076d2fa47d9SAndrew Lunn 		memcpy(data + i * ETH_GSTRING_LEN,
1077d2fa47d9SAndrew Lunn 		       marvell_hw_stats[i].string, ETH_GSTRING_LEN);
1078d2fa47d9SAndrew Lunn 	}
1079d2fa47d9SAndrew Lunn }
1080d2fa47d9SAndrew Lunn 
1081d2fa47d9SAndrew Lunn #ifndef UINT64_MAX
1082d2fa47d9SAndrew Lunn #define UINT64_MAX              (u64)(~((u64)0))
1083d2fa47d9SAndrew Lunn #endif
1084d2fa47d9SAndrew Lunn static u64 marvell_get_stat(struct phy_device *phydev, int i)
1085d2fa47d9SAndrew Lunn {
1086d2fa47d9SAndrew Lunn 	struct marvell_hw_stat stat = marvell_hw_stats[i];
1087d2fa47d9SAndrew Lunn 	struct marvell_priv *priv = phydev->priv;
1088321b4d4bSAndrew Lunn 	int err, oldpage, val;
1089321b4d4bSAndrew Lunn 	u64 ret;
1090d2fa47d9SAndrew Lunn 
1091d2fa47d9SAndrew Lunn 	oldpage = phy_read(phydev, MII_MARVELL_PHY_PAGE);
1092d2fa47d9SAndrew Lunn 	err = phy_write(phydev, MII_MARVELL_PHY_PAGE,
1093d2fa47d9SAndrew Lunn 			stat.page);
1094d2fa47d9SAndrew Lunn 	if (err < 0)
1095d2fa47d9SAndrew Lunn 		return UINT64_MAX;
1096d2fa47d9SAndrew Lunn 
1097d2fa47d9SAndrew Lunn 	val = phy_read(phydev, stat.reg);
1098d2fa47d9SAndrew Lunn 	if (val < 0) {
1099321b4d4bSAndrew Lunn 		ret = UINT64_MAX;
1100d2fa47d9SAndrew Lunn 	} else {
1101d2fa47d9SAndrew Lunn 		val = val & ((1 << stat.bits) - 1);
1102d2fa47d9SAndrew Lunn 		priv->stats[i] += val;
1103321b4d4bSAndrew Lunn 		ret = priv->stats[i];
1104d2fa47d9SAndrew Lunn 	}
1105d2fa47d9SAndrew Lunn 
1106d2fa47d9SAndrew Lunn 	phy_write(phydev, MII_MARVELL_PHY_PAGE, oldpage);
1107d2fa47d9SAndrew Lunn 
1108321b4d4bSAndrew Lunn 	return ret;
1109d2fa47d9SAndrew Lunn }
1110d2fa47d9SAndrew Lunn 
1111d2fa47d9SAndrew Lunn static void marvell_get_stats(struct phy_device *phydev,
1112d2fa47d9SAndrew Lunn 			      struct ethtool_stats *stats, u64 *data)
1113d2fa47d9SAndrew Lunn {
1114d2fa47d9SAndrew Lunn 	int i;
1115d2fa47d9SAndrew Lunn 
1116d2fa47d9SAndrew Lunn 	for (i = 0; i < ARRAY_SIZE(marvell_hw_stats); i++)
1117d2fa47d9SAndrew Lunn 		data[i] = marvell_get_stat(phydev, i);
1118d2fa47d9SAndrew Lunn }
1119d2fa47d9SAndrew Lunn 
1120d2fa47d9SAndrew Lunn static int marvell_probe(struct phy_device *phydev)
1121d2fa47d9SAndrew Lunn {
1122d2fa47d9SAndrew Lunn 	struct marvell_priv *priv;
1123d2fa47d9SAndrew Lunn 
1124e5a03bfdSAndrew Lunn 	priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL);
1125d2fa47d9SAndrew Lunn 	if (!priv)
1126d2fa47d9SAndrew Lunn 		return -ENOMEM;
1127d2fa47d9SAndrew Lunn 
1128d2fa47d9SAndrew Lunn 	phydev->priv = priv;
1129d2fa47d9SAndrew Lunn 
1130d2fa47d9SAndrew Lunn 	return 0;
1131d2fa47d9SAndrew Lunn }
1132d2fa47d9SAndrew Lunn 
1133e5479239SOlof Johansson static struct phy_driver marvell_drivers[] = {
1134e5479239SOlof Johansson 	{
11352f495c39SBenjamin Herrenschmidt 		.phy_id = MARVELL_PHY_ID_88E1101,
11362f495c39SBenjamin Herrenschmidt 		.phy_id_mask = MARVELL_PHY_ID_MASK,
113700db8189SAndy Fleming 		.name = "Marvell 88E1101",
113800db8189SAndy Fleming 		.features = PHY_GBIT_FEATURES,
1139d2fa47d9SAndrew Lunn 		.probe = marvell_probe,
114000db8189SAndy Fleming 		.flags = PHY_HAS_INTERRUPT,
114179be1a1cSClemens Gruber 		.config_init = &marvell_config_init,
114200db8189SAndy Fleming 		.config_aneg = &marvell_config_aneg,
114300db8189SAndy Fleming 		.read_status = &genphy_read_status,
114400db8189SAndy Fleming 		.ack_interrupt = &marvell_ack_interrupt,
114500db8189SAndy Fleming 		.config_intr = &marvell_config_intr,
11460898b448SSebastian Hesselbarth 		.resume = &genphy_resume,
11470898b448SSebastian Hesselbarth 		.suspend = &genphy_suspend,
1148d2fa47d9SAndrew Lunn 		.get_sset_count = marvell_get_sset_count,
1149d2fa47d9SAndrew Lunn 		.get_strings = marvell_get_strings,
1150d2fa47d9SAndrew Lunn 		.get_stats = marvell_get_stats,
1151e5479239SOlof Johansson 	},
1152e5479239SOlof Johansson 	{
11532f495c39SBenjamin Herrenschmidt 		.phy_id = MARVELL_PHY_ID_88E1112,
11542f495c39SBenjamin Herrenschmidt 		.phy_id_mask = MARVELL_PHY_ID_MASK,
115585cfb534SOlof Johansson 		.name = "Marvell 88E1112",
115685cfb534SOlof Johansson 		.features = PHY_GBIT_FEATURES,
115785cfb534SOlof Johansson 		.flags = PHY_HAS_INTERRUPT,
1158d2fa47d9SAndrew Lunn 		.probe = marvell_probe,
115985cfb534SOlof Johansson 		.config_init = &m88e1111_config_init,
116085cfb534SOlof Johansson 		.config_aneg = &marvell_config_aneg,
116185cfb534SOlof Johansson 		.read_status = &genphy_read_status,
116285cfb534SOlof Johansson 		.ack_interrupt = &marvell_ack_interrupt,
116385cfb534SOlof Johansson 		.config_intr = &marvell_config_intr,
11640898b448SSebastian Hesselbarth 		.resume = &genphy_resume,
11650898b448SSebastian Hesselbarth 		.suspend = &genphy_suspend,
1166d2fa47d9SAndrew Lunn 		.get_sset_count = marvell_get_sset_count,
1167d2fa47d9SAndrew Lunn 		.get_strings = marvell_get_strings,
1168d2fa47d9SAndrew Lunn 		.get_stats = marvell_get_stats,
116985cfb534SOlof Johansson 	},
117085cfb534SOlof Johansson 	{
11712f495c39SBenjamin Herrenschmidt 		.phy_id = MARVELL_PHY_ID_88E1111,
11722f495c39SBenjamin Herrenschmidt 		.phy_id_mask = MARVELL_PHY_ID_MASK,
117376884679SAndy Fleming 		.name = "Marvell 88E1111",
117476884679SAndy Fleming 		.features = PHY_GBIT_FEATURES,
117576884679SAndy Fleming 		.flags = PHY_HAS_INTERRUPT,
1176d2fa47d9SAndrew Lunn 		.probe = marvell_probe,
1177e5479239SOlof Johansson 		.config_init = &m88e1111_config_init,
117876884679SAndy Fleming 		.config_aneg = &marvell_config_aneg,
1179be937f1fSAlexandr Smirnov 		.read_status = &marvell_read_status,
118076884679SAndy Fleming 		.ack_interrupt = &marvell_ack_interrupt,
118176884679SAndy Fleming 		.config_intr = &marvell_config_intr,
11820898b448SSebastian Hesselbarth 		.resume = &genphy_resume,
11830898b448SSebastian Hesselbarth 		.suspend = &genphy_suspend,
1184d2fa47d9SAndrew Lunn 		.get_sset_count = marvell_get_sset_count,
1185d2fa47d9SAndrew Lunn 		.get_strings = marvell_get_strings,
1186d2fa47d9SAndrew Lunn 		.get_stats = marvell_get_stats,
1187e5479239SOlof Johansson 	},
1188e5479239SOlof Johansson 	{
11892f495c39SBenjamin Herrenschmidt 		.phy_id = MARVELL_PHY_ID_88E1118,
11902f495c39SBenjamin Herrenschmidt 		.phy_id_mask = MARVELL_PHY_ID_MASK,
1191605f196eSRon Madrid 		.name = "Marvell 88E1118",
1192605f196eSRon Madrid 		.features = PHY_GBIT_FEATURES,
1193605f196eSRon Madrid 		.flags = PHY_HAS_INTERRUPT,
1194d2fa47d9SAndrew Lunn 		.probe = marvell_probe,
1195605f196eSRon Madrid 		.config_init = &m88e1118_config_init,
1196605f196eSRon Madrid 		.config_aneg = &m88e1118_config_aneg,
1197605f196eSRon Madrid 		.read_status = &genphy_read_status,
1198605f196eSRon Madrid 		.ack_interrupt = &marvell_ack_interrupt,
1199605f196eSRon Madrid 		.config_intr = &marvell_config_intr,
12000898b448SSebastian Hesselbarth 		.resume = &genphy_resume,
12010898b448SSebastian Hesselbarth 		.suspend = &genphy_suspend,
1202d2fa47d9SAndrew Lunn 		.get_sset_count = marvell_get_sset_count,
1203d2fa47d9SAndrew Lunn 		.get_strings = marvell_get_strings,
1204d2fa47d9SAndrew Lunn 		.get_stats = marvell_get_stats,
1205605f196eSRon Madrid 	},
1206605f196eSRon Madrid 	{
12072f495c39SBenjamin Herrenschmidt 		.phy_id = MARVELL_PHY_ID_88E1121R,
12082f495c39SBenjamin Herrenschmidt 		.phy_id_mask = MARVELL_PHY_ID_MASK,
1209140bc929SSergei Poselenov 		.name = "Marvell 88E1121R",
1210140bc929SSergei Poselenov 		.features = PHY_GBIT_FEATURES,
1211140bc929SSergei Poselenov 		.flags = PHY_HAS_INTERRUPT,
1212d2fa47d9SAndrew Lunn 		.probe = marvell_probe,
1213fdecf36fSClemens Gruber 		.config_init = &m88e1121_config_init,
1214140bc929SSergei Poselenov 		.config_aneg = &m88e1121_config_aneg,
1215140bc929SSergei Poselenov 		.read_status = &marvell_read_status,
1216140bc929SSergei Poselenov 		.ack_interrupt = &marvell_ack_interrupt,
1217140bc929SSergei Poselenov 		.config_intr = &marvell_config_intr,
1218dcd07be3SAnatolij Gustschin 		.did_interrupt = &m88e1121_did_interrupt,
12190898b448SSebastian Hesselbarth 		.resume = &genphy_resume,
12200898b448SSebastian Hesselbarth 		.suspend = &genphy_suspend,
1221d2fa47d9SAndrew Lunn 		.get_sset_count = marvell_get_sset_count,
1222d2fa47d9SAndrew Lunn 		.get_strings = marvell_get_strings,
1223d2fa47d9SAndrew Lunn 		.get_stats = marvell_get_stats,
1224140bc929SSergei Poselenov 	},
1225140bc929SSergei Poselenov 	{
1226337ac9d5SCyril Chemparathy 		.phy_id = MARVELL_PHY_ID_88E1318S,
12276ba74014SLinus Torvalds 		.phy_id_mask = MARVELL_PHY_ID_MASK,
1228337ac9d5SCyril Chemparathy 		.name = "Marvell 88E1318S",
12293ff1c259SCyril Chemparathy 		.features = PHY_GBIT_FEATURES,
12303ff1c259SCyril Chemparathy 		.flags = PHY_HAS_INTERRUPT,
1231d2fa47d9SAndrew Lunn 		.probe = marvell_probe,
1232fdecf36fSClemens Gruber 		.config_init = &m88e1121_config_init,
1233337ac9d5SCyril Chemparathy 		.config_aneg = &m88e1318_config_aneg,
12343ff1c259SCyril Chemparathy 		.read_status = &marvell_read_status,
12353ff1c259SCyril Chemparathy 		.ack_interrupt = &marvell_ack_interrupt,
12363ff1c259SCyril Chemparathy 		.config_intr = &marvell_config_intr,
12373ff1c259SCyril Chemparathy 		.did_interrupt = &m88e1121_did_interrupt,
12383871c387SMichael Stapelberg 		.get_wol = &m88e1318_get_wol,
12393871c387SMichael Stapelberg 		.set_wol = &m88e1318_set_wol,
12400898b448SSebastian Hesselbarth 		.resume = &genphy_resume,
12410898b448SSebastian Hesselbarth 		.suspend = &genphy_suspend,
1242d2fa47d9SAndrew Lunn 		.get_sset_count = marvell_get_sset_count,
1243d2fa47d9SAndrew Lunn 		.get_strings = marvell_get_strings,
1244d2fa47d9SAndrew Lunn 		.get_stats = marvell_get_stats,
12453ff1c259SCyril Chemparathy 	},
12463ff1c259SCyril Chemparathy 	{
12472f495c39SBenjamin Herrenschmidt 		.phy_id = MARVELL_PHY_ID_88E1145,
12482f495c39SBenjamin Herrenschmidt 		.phy_id_mask = MARVELL_PHY_ID_MASK,
124976884679SAndy Fleming 		.name = "Marvell 88E1145",
125076884679SAndy Fleming 		.features = PHY_GBIT_FEATURES,
125176884679SAndy Fleming 		.flags = PHY_HAS_INTERRUPT,
1252d2fa47d9SAndrew Lunn 		.probe = marvell_probe,
125376884679SAndy Fleming 		.config_init = &m88e1145_config_init,
125476884679SAndy Fleming 		.config_aneg = &marvell_config_aneg,
125576884679SAndy Fleming 		.read_status = &genphy_read_status,
125676884679SAndy Fleming 		.ack_interrupt = &marvell_ack_interrupt,
125776884679SAndy Fleming 		.config_intr = &marvell_config_intr,
12580898b448SSebastian Hesselbarth 		.resume = &genphy_resume,
12590898b448SSebastian Hesselbarth 		.suspend = &genphy_suspend,
1260d2fa47d9SAndrew Lunn 		.get_sset_count = marvell_get_sset_count,
1261d2fa47d9SAndrew Lunn 		.get_strings = marvell_get_strings,
1262d2fa47d9SAndrew Lunn 		.get_stats = marvell_get_stats,
1263ac8c635aSOlof Johansson 	},
1264ac8c635aSOlof Johansson 	{
126590600732SDavid Daney 		.phy_id = MARVELL_PHY_ID_88E1149R,
126690600732SDavid Daney 		.phy_id_mask = MARVELL_PHY_ID_MASK,
126790600732SDavid Daney 		.name = "Marvell 88E1149R",
126890600732SDavid Daney 		.features = PHY_GBIT_FEATURES,
126990600732SDavid Daney 		.flags = PHY_HAS_INTERRUPT,
1270d2fa47d9SAndrew Lunn 		.probe = marvell_probe,
127190600732SDavid Daney 		.config_init = &m88e1149_config_init,
127290600732SDavid Daney 		.config_aneg = &m88e1118_config_aneg,
127390600732SDavid Daney 		.read_status = &genphy_read_status,
127490600732SDavid Daney 		.ack_interrupt = &marvell_ack_interrupt,
127590600732SDavid Daney 		.config_intr = &marvell_config_intr,
12760898b448SSebastian Hesselbarth 		.resume = &genphy_resume,
12770898b448SSebastian Hesselbarth 		.suspend = &genphy_suspend,
1278d2fa47d9SAndrew Lunn 		.get_sset_count = marvell_get_sset_count,
1279d2fa47d9SAndrew Lunn 		.get_strings = marvell_get_strings,
1280d2fa47d9SAndrew Lunn 		.get_stats = marvell_get_stats,
128190600732SDavid Daney 	},
128290600732SDavid Daney 	{
12832f495c39SBenjamin Herrenschmidt 		.phy_id = MARVELL_PHY_ID_88E1240,
12842f495c39SBenjamin Herrenschmidt 		.phy_id_mask = MARVELL_PHY_ID_MASK,
1285ac8c635aSOlof Johansson 		.name = "Marvell 88E1240",
1286ac8c635aSOlof Johansson 		.features = PHY_GBIT_FEATURES,
1287ac8c635aSOlof Johansson 		.flags = PHY_HAS_INTERRUPT,
1288d2fa47d9SAndrew Lunn 		.probe = marvell_probe,
1289ac8c635aSOlof Johansson 		.config_init = &m88e1111_config_init,
1290ac8c635aSOlof Johansson 		.config_aneg = &marvell_config_aneg,
1291ac8c635aSOlof Johansson 		.read_status = &genphy_read_status,
1292ac8c635aSOlof Johansson 		.ack_interrupt = &marvell_ack_interrupt,
1293ac8c635aSOlof Johansson 		.config_intr = &marvell_config_intr,
12940898b448SSebastian Hesselbarth 		.resume = &genphy_resume,
12950898b448SSebastian Hesselbarth 		.suspend = &genphy_suspend,
1296d2fa47d9SAndrew Lunn 		.get_sset_count = marvell_get_sset_count,
1297d2fa47d9SAndrew Lunn 		.get_strings = marvell_get_strings,
1298d2fa47d9SAndrew Lunn 		.get_stats = marvell_get_stats,
1299ac8c635aSOlof Johansson 	},
13003da09a51SMichal Simek 	{
13013da09a51SMichal Simek 		.phy_id = MARVELL_PHY_ID_88E1116R,
13023da09a51SMichal Simek 		.phy_id_mask = MARVELL_PHY_ID_MASK,
13033da09a51SMichal Simek 		.name = "Marvell 88E1116R",
13043da09a51SMichal Simek 		.features = PHY_GBIT_FEATURES,
13053da09a51SMichal Simek 		.flags = PHY_HAS_INTERRUPT,
1306d2fa47d9SAndrew Lunn 		.probe = marvell_probe,
13073da09a51SMichal Simek 		.config_init = &m88e1116r_config_init,
13083da09a51SMichal Simek 		.config_aneg = &genphy_config_aneg,
13093da09a51SMichal Simek 		.read_status = &genphy_read_status,
13103da09a51SMichal Simek 		.ack_interrupt = &marvell_ack_interrupt,
13113da09a51SMichal Simek 		.config_intr = &marvell_config_intr,
13120898b448SSebastian Hesselbarth 		.resume = &genphy_resume,
13130898b448SSebastian Hesselbarth 		.suspend = &genphy_suspend,
1314d2fa47d9SAndrew Lunn 		.get_sset_count = marvell_get_sset_count,
1315d2fa47d9SAndrew Lunn 		.get_strings = marvell_get_strings,
1316d2fa47d9SAndrew Lunn 		.get_stats = marvell_get_stats,
13173da09a51SMichal Simek 	},
131810e24caaSMichal Simek 	{
131910e24caaSMichal Simek 		.phy_id = MARVELL_PHY_ID_88E1510,
132010e24caaSMichal Simek 		.phy_id_mask = MARVELL_PHY_ID_MASK,
132110e24caaSMichal Simek 		.name = "Marvell 88E1510",
132210e24caaSMichal Simek 		.features = PHY_GBIT_FEATURES,
132310e24caaSMichal Simek 		.flags = PHY_HAS_INTERRUPT,
1324d2fa47d9SAndrew Lunn 		.probe = marvell_probe,
1325930b37eeSStefan Roese 		.config_init = &m88e1510_config_init,
132610e24caaSMichal Simek 		.config_aneg = &m88e1510_config_aneg,
132710e24caaSMichal Simek 		.read_status = &marvell_read_status,
132810e24caaSMichal Simek 		.ack_interrupt = &marvell_ack_interrupt,
132910e24caaSMichal Simek 		.config_intr = &marvell_config_intr,
133010e24caaSMichal Simek 		.did_interrupt = &m88e1121_did_interrupt,
13310898b448SSebastian Hesselbarth 		.resume = &genphy_resume,
13320898b448SSebastian Hesselbarth 		.suspend = &genphy_suspend,
1333d2fa47d9SAndrew Lunn 		.get_sset_count = marvell_get_sset_count,
1334d2fa47d9SAndrew Lunn 		.get_strings = marvell_get_strings,
1335d2fa47d9SAndrew Lunn 		.get_stats = marvell_get_stats,
133610e24caaSMichal Simek 	},
13376b358aedSSebastian Hesselbarth 	{
1338819ec8e1SAndrew Lunn 		.phy_id = MARVELL_PHY_ID_88E1540,
1339819ec8e1SAndrew Lunn 		.phy_id_mask = MARVELL_PHY_ID_MASK,
1340819ec8e1SAndrew Lunn 		.name = "Marvell 88E1540",
1341819ec8e1SAndrew Lunn 		.features = PHY_GBIT_FEATURES,
1342819ec8e1SAndrew Lunn 		.flags = PHY_HAS_INTERRUPT,
1343d2fa47d9SAndrew Lunn 		.probe = marvell_probe,
134479be1a1cSClemens Gruber 		.config_init = &marvell_config_init,
1345819ec8e1SAndrew Lunn 		.config_aneg = &m88e1510_config_aneg,
1346819ec8e1SAndrew Lunn 		.read_status = &marvell_read_status,
1347819ec8e1SAndrew Lunn 		.ack_interrupt = &marvell_ack_interrupt,
1348819ec8e1SAndrew Lunn 		.config_intr = &marvell_config_intr,
1349819ec8e1SAndrew Lunn 		.did_interrupt = &m88e1121_did_interrupt,
1350819ec8e1SAndrew Lunn 		.resume = &genphy_resume,
1351819ec8e1SAndrew Lunn 		.suspend = &genphy_suspend,
1352d2fa47d9SAndrew Lunn 		.get_sset_count = marvell_get_sset_count,
1353d2fa47d9SAndrew Lunn 		.get_strings = marvell_get_strings,
1354d2fa47d9SAndrew Lunn 		.get_stats = marvell_get_stats,
1355819ec8e1SAndrew Lunn 	},
1356819ec8e1SAndrew Lunn 	{
13576b358aedSSebastian Hesselbarth 		.phy_id = MARVELL_PHY_ID_88E3016,
13586b358aedSSebastian Hesselbarth 		.phy_id_mask = MARVELL_PHY_ID_MASK,
13596b358aedSSebastian Hesselbarth 		.name = "Marvell 88E3016",
13606b358aedSSebastian Hesselbarth 		.features = PHY_BASIC_FEATURES,
13616b358aedSSebastian Hesselbarth 		.flags = PHY_HAS_INTERRUPT,
1362d2fa47d9SAndrew Lunn 		.probe = marvell_probe,
13636b358aedSSebastian Hesselbarth 		.config_aneg = &genphy_config_aneg,
13646b358aedSSebastian Hesselbarth 		.config_init = &m88e3016_config_init,
13656b358aedSSebastian Hesselbarth 		.aneg_done = &marvell_aneg_done,
13666b358aedSSebastian Hesselbarth 		.read_status = &marvell_read_status,
13676b358aedSSebastian Hesselbarth 		.ack_interrupt = &marvell_ack_interrupt,
13686b358aedSSebastian Hesselbarth 		.config_intr = &marvell_config_intr,
13696b358aedSSebastian Hesselbarth 		.did_interrupt = &m88e1121_did_interrupt,
13706b358aedSSebastian Hesselbarth 		.resume = &genphy_resume,
13716b358aedSSebastian Hesselbarth 		.suspend = &genphy_suspend,
1372d2fa47d9SAndrew Lunn 		.get_sset_count = marvell_get_sset_count,
1373d2fa47d9SAndrew Lunn 		.get_strings = marvell_get_strings,
1374d2fa47d9SAndrew Lunn 		.get_stats = marvell_get_stats,
13756b358aedSSebastian Hesselbarth 	},
137676884679SAndy Fleming };
137776884679SAndy Fleming 
137850fd7150SJohan Hovold module_phy_driver(marvell_drivers);
13794e4f10f6SDavid Woodhouse 
1380cf93c945SUwe Kleine-König static struct mdio_device_id __maybe_unused marvell_tbl[] = {
1381f5e1cabfSMichal Simek 	{ MARVELL_PHY_ID_88E1101, MARVELL_PHY_ID_MASK },
1382f5e1cabfSMichal Simek 	{ MARVELL_PHY_ID_88E1112, MARVELL_PHY_ID_MASK },
1383f5e1cabfSMichal Simek 	{ MARVELL_PHY_ID_88E1111, MARVELL_PHY_ID_MASK },
1384f5e1cabfSMichal Simek 	{ MARVELL_PHY_ID_88E1118, MARVELL_PHY_ID_MASK },
1385f5e1cabfSMichal Simek 	{ MARVELL_PHY_ID_88E1121R, MARVELL_PHY_ID_MASK },
1386f5e1cabfSMichal Simek 	{ MARVELL_PHY_ID_88E1145, MARVELL_PHY_ID_MASK },
1387f5e1cabfSMichal Simek 	{ MARVELL_PHY_ID_88E1149R, MARVELL_PHY_ID_MASK },
1388f5e1cabfSMichal Simek 	{ MARVELL_PHY_ID_88E1240, MARVELL_PHY_ID_MASK },
1389f5e1cabfSMichal Simek 	{ MARVELL_PHY_ID_88E1318S, MARVELL_PHY_ID_MASK },
13903da09a51SMichal Simek 	{ MARVELL_PHY_ID_88E1116R, MARVELL_PHY_ID_MASK },
139110e24caaSMichal Simek 	{ MARVELL_PHY_ID_88E1510, MARVELL_PHY_ID_MASK },
1392819ec8e1SAndrew Lunn 	{ MARVELL_PHY_ID_88E1540, MARVELL_PHY_ID_MASK },
13936b358aedSSebastian Hesselbarth 	{ MARVELL_PHY_ID_88E3016, MARVELL_PHY_ID_MASK },
13944e4f10f6SDavid Woodhouse 	{ }
13954e4f10f6SDavid Woodhouse };
13964e4f10f6SDavid Woodhouse 
13974e4f10f6SDavid Woodhouse MODULE_DEVICE_TABLE(mdio, marvell_tbl);
1398