xref: /openbmc/linux/drivers/net/phy/marvell.c (revision 0898b448)
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
5176884679SAndy Fleming #define MII_M1011_PHY_SCR_AUTO_CROSS	0x0060
5276884679SAndy Fleming 
5376884679SAndy Fleming #define MII_M1145_PHY_EXT_CR		0x14
5476884679SAndy Fleming #define MII_M1145_RGMII_RX_DELAY	0x0080
5576884679SAndy Fleming #define MII_M1145_RGMII_TX_DELAY	0x0002
5676884679SAndy Fleming 
5776884679SAndy Fleming #define MII_M1111_PHY_LED_CONTROL	0x18
5876884679SAndy Fleming #define MII_M1111_PHY_LED_DIRECT	0x4100
5976884679SAndy Fleming #define MII_M1111_PHY_LED_COMBINE	0x411c
60895ee682SKim Phillips #define MII_M1111_PHY_EXT_CR		0x14
61895ee682SKim Phillips #define MII_M1111_RX_DELAY		0x80
62895ee682SKim Phillips #define MII_M1111_TX_DELAY		0x2
63895ee682SKim Phillips #define MII_M1111_PHY_EXT_SR		0x1b
64be937f1fSAlexandr Smirnov 
65895ee682SKim Phillips #define MII_M1111_HWCFG_MODE_MASK		0xf
66be937f1fSAlexandr Smirnov #define MII_M1111_HWCFG_MODE_COPPER_RGMII	0xb
67be937f1fSAlexandr Smirnov #define MII_M1111_HWCFG_MODE_FIBER_RGMII	0x3
684117b5beSKapil Juneja #define MII_M1111_HWCFG_MODE_SGMII_NO_CLK	0x4
695f8cbc13SLiu Yu-B13201 #define MII_M1111_HWCFG_MODE_COPPER_RTBI	0x9
70be937f1fSAlexandr Smirnov #define MII_M1111_HWCFG_FIBER_COPPER_AUTO	0x8000
71be937f1fSAlexandr Smirnov #define MII_M1111_HWCFG_FIBER_COPPER_RES	0x2000
72be937f1fSAlexandr Smirnov 
73be937f1fSAlexandr Smirnov #define MII_M1111_COPPER		0
74be937f1fSAlexandr Smirnov #define MII_M1111_FIBER			1
75be937f1fSAlexandr Smirnov 
76c477d044SCyril Chemparathy #define MII_88E1121_PHY_MSCR_PAGE	2
77c477d044SCyril Chemparathy #define MII_88E1121_PHY_MSCR_REG	21
78c477d044SCyril Chemparathy #define MII_88E1121_PHY_MSCR_RX_DELAY	BIT(5)
79c477d044SCyril Chemparathy #define MII_88E1121_PHY_MSCR_TX_DELAY	BIT(4)
80c477d044SCyril Chemparathy #define MII_88E1121_PHY_MSCR_DELAY_MASK	(~(0x3 << 4))
81c477d044SCyril Chemparathy 
82337ac9d5SCyril Chemparathy #define MII_88E1318S_PHY_MSCR1_REG	16
83337ac9d5SCyril Chemparathy #define MII_88E1318S_PHY_MSCR1_PAD_ODD	BIT(6)
843ff1c259SCyril Chemparathy 
853871c387SMichael Stapelberg /* Copper Specific Interrupt Enable Register */
863871c387SMichael Stapelberg #define MII_88E1318S_PHY_CSIER                              0x12
873871c387SMichael Stapelberg /* WOL Event Interrupt Enable */
883871c387SMichael Stapelberg #define MII_88E1318S_PHY_CSIER_WOL_EIE                      BIT(7)
893871c387SMichael Stapelberg 
903871c387SMichael Stapelberg /* LED Timer Control Register */
913871c387SMichael Stapelberg #define MII_88E1318S_PHY_LED_PAGE                           0x03
923871c387SMichael Stapelberg #define MII_88E1318S_PHY_LED_TCR                            0x12
933871c387SMichael Stapelberg #define MII_88E1318S_PHY_LED_TCR_FORCE_INT                  BIT(15)
943871c387SMichael Stapelberg #define MII_88E1318S_PHY_LED_TCR_INTn_ENABLE                BIT(7)
953871c387SMichael Stapelberg #define MII_88E1318S_PHY_LED_TCR_INT_ACTIVE_LOW             BIT(11)
963871c387SMichael Stapelberg 
973871c387SMichael Stapelberg /* Magic Packet MAC address registers */
983871c387SMichael Stapelberg #define MII_88E1318S_PHY_MAGIC_PACKET_WORD2                 0x17
993871c387SMichael Stapelberg #define MII_88E1318S_PHY_MAGIC_PACKET_WORD1                 0x18
1003871c387SMichael Stapelberg #define MII_88E1318S_PHY_MAGIC_PACKET_WORD0                 0x19
1013871c387SMichael Stapelberg 
1023871c387SMichael Stapelberg #define MII_88E1318S_PHY_WOL_PAGE                           0x11
1033871c387SMichael Stapelberg #define MII_88E1318S_PHY_WOL_CTRL                           0x10
1043871c387SMichael Stapelberg #define MII_88E1318S_PHY_WOL_CTRL_CLEAR_WOL_STATUS          BIT(12)
1053871c387SMichael Stapelberg #define MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE BIT(14)
1063871c387SMichael Stapelberg 
107140bc929SSergei Poselenov #define MII_88E1121_PHY_LED_CTRL	16
108140bc929SSergei Poselenov #define MII_88E1121_PHY_LED_PAGE	3
109140bc929SSergei Poselenov #define MII_88E1121_PHY_LED_DEF		0x0030
110140bc929SSergei Poselenov 
111be937f1fSAlexandr Smirnov #define MII_M1011_PHY_STATUS		0x11
112be937f1fSAlexandr Smirnov #define MII_M1011_PHY_STATUS_1000	0x8000
113be937f1fSAlexandr Smirnov #define MII_M1011_PHY_STATUS_100	0x4000
114be937f1fSAlexandr Smirnov #define MII_M1011_PHY_STATUS_SPD_MASK	0xc000
115be937f1fSAlexandr Smirnov #define MII_M1011_PHY_STATUS_FULLDUPLEX	0x2000
116be937f1fSAlexandr Smirnov #define MII_M1011_PHY_STATUS_RESOLVED	0x0800
117be937f1fSAlexandr Smirnov #define MII_M1011_PHY_STATUS_LINK	0x0400
118be937f1fSAlexandr Smirnov 
1193da09a51SMichal Simek #define MII_M1116R_CONTROL_REG_MAC	21
1203da09a51SMichal Simek 
12176884679SAndy Fleming 
12200db8189SAndy Fleming MODULE_DESCRIPTION("Marvell PHY driver");
12300db8189SAndy Fleming MODULE_AUTHOR("Andy Fleming");
12400db8189SAndy Fleming MODULE_LICENSE("GPL");
12500db8189SAndy Fleming 
12600db8189SAndy Fleming static int marvell_ack_interrupt(struct phy_device *phydev)
12700db8189SAndy Fleming {
12800db8189SAndy Fleming 	int err;
12900db8189SAndy Fleming 
13000db8189SAndy Fleming 	/* Clear the interrupts by reading the reg */
13100db8189SAndy Fleming 	err = phy_read(phydev, MII_M1011_IEVENT);
13200db8189SAndy Fleming 
13300db8189SAndy Fleming 	if (err < 0)
13400db8189SAndy Fleming 		return err;
13500db8189SAndy Fleming 
13600db8189SAndy Fleming 	return 0;
13700db8189SAndy Fleming }
13800db8189SAndy Fleming 
13900db8189SAndy Fleming static int marvell_config_intr(struct phy_device *phydev)
14000db8189SAndy Fleming {
14100db8189SAndy Fleming 	int err;
14200db8189SAndy Fleming 
14300db8189SAndy Fleming 	if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
14400db8189SAndy Fleming 		err = phy_write(phydev, MII_M1011_IMASK, MII_M1011_IMASK_INIT);
14500db8189SAndy Fleming 	else
14600db8189SAndy Fleming 		err = phy_write(phydev, MII_M1011_IMASK, MII_M1011_IMASK_CLEAR);
14700db8189SAndy Fleming 
14800db8189SAndy Fleming 	return err;
14900db8189SAndy Fleming }
15000db8189SAndy Fleming 
15100db8189SAndy Fleming static int marvell_config_aneg(struct phy_device *phydev)
15200db8189SAndy Fleming {
15300db8189SAndy Fleming 	int err;
15400db8189SAndy Fleming 
15500db8189SAndy Fleming 	/* The Marvell PHY has an errata which requires
15600db8189SAndy Fleming 	 * that certain registers get written in order
15700db8189SAndy Fleming 	 * to restart autonegotiation */
15800db8189SAndy Fleming 	err = phy_write(phydev, MII_BMCR, BMCR_RESET);
15900db8189SAndy Fleming 
16000db8189SAndy Fleming 	if (err < 0)
16100db8189SAndy Fleming 		return err;
16200db8189SAndy Fleming 
16300db8189SAndy Fleming 	err = phy_write(phydev, 0x1d, 0x1f);
16400db8189SAndy Fleming 	if (err < 0)
16500db8189SAndy Fleming 		return err;
16600db8189SAndy Fleming 
16700db8189SAndy Fleming 	err = phy_write(phydev, 0x1e, 0x200c);
16800db8189SAndy Fleming 	if (err < 0)
16900db8189SAndy Fleming 		return err;
17000db8189SAndy Fleming 
17100db8189SAndy Fleming 	err = phy_write(phydev, 0x1d, 0x5);
17200db8189SAndy Fleming 	if (err < 0)
17300db8189SAndy Fleming 		return err;
17400db8189SAndy Fleming 
17500db8189SAndy Fleming 	err = phy_write(phydev, 0x1e, 0);
17600db8189SAndy Fleming 	if (err < 0)
17700db8189SAndy Fleming 		return err;
17800db8189SAndy Fleming 
17900db8189SAndy Fleming 	err = phy_write(phydev, 0x1e, 0x100);
18000db8189SAndy Fleming 	if (err < 0)
18100db8189SAndy Fleming 		return err;
18200db8189SAndy Fleming 
18376884679SAndy Fleming 	err = phy_write(phydev, MII_M1011_PHY_SCR,
18476884679SAndy Fleming 			MII_M1011_PHY_SCR_AUTO_CROSS);
18576884679SAndy Fleming 	if (err < 0)
18676884679SAndy Fleming 		return err;
18776884679SAndy Fleming 
18876884679SAndy Fleming 	err = phy_write(phydev, MII_M1111_PHY_LED_CONTROL,
18976884679SAndy Fleming 			MII_M1111_PHY_LED_DIRECT);
19076884679SAndy Fleming 	if (err < 0)
19176884679SAndy Fleming 		return err;
19200db8189SAndy Fleming 
19300db8189SAndy Fleming 	err = genphy_config_aneg(phydev);
1948ff44985SAnton Vorontsov 	if (err < 0)
19500db8189SAndy Fleming 		return err;
1968ff44985SAnton Vorontsov 
1978ff44985SAnton Vorontsov 	if (phydev->autoneg != AUTONEG_ENABLE) {
1988ff44985SAnton Vorontsov 		int bmcr;
1998ff44985SAnton Vorontsov 
2008ff44985SAnton Vorontsov 		/*
2018ff44985SAnton Vorontsov 		 * A write to speed/duplex bits (that is performed by
2028ff44985SAnton Vorontsov 		 * genphy_config_aneg() call above) must be followed by
2038ff44985SAnton Vorontsov 		 * a software reset. Otherwise, the write has no effect.
2048ff44985SAnton Vorontsov 		 */
2058ff44985SAnton Vorontsov 		bmcr = phy_read(phydev, MII_BMCR);
2068ff44985SAnton Vorontsov 		if (bmcr < 0)
2078ff44985SAnton Vorontsov 			return bmcr;
2088ff44985SAnton Vorontsov 
2098ff44985SAnton Vorontsov 		err = phy_write(phydev, MII_BMCR, bmcr | BMCR_RESET);
2108ff44985SAnton Vorontsov 		if (err < 0)
2118ff44985SAnton Vorontsov 			return err;
2128ff44985SAnton Vorontsov 	}
2138ff44985SAnton Vorontsov 
2148ff44985SAnton Vorontsov 	return 0;
21500db8189SAndy Fleming }
21600db8189SAndy Fleming 
217cf41a51dSDavid Daney #ifdef CONFIG_OF_MDIO
218cf41a51dSDavid Daney /*
219cf41a51dSDavid Daney  * Set and/or override some configuration registers based on the
220cf41a51dSDavid Daney  * marvell,reg-init property stored in the of_node for the phydev.
221cf41a51dSDavid Daney  *
222cf41a51dSDavid Daney  * marvell,reg-init = <reg-page reg mask value>,...;
223cf41a51dSDavid Daney  *
224cf41a51dSDavid Daney  * There may be one or more sets of <reg-page reg mask value>:
225cf41a51dSDavid Daney  *
226cf41a51dSDavid Daney  * reg-page: which register bank to use.
227cf41a51dSDavid Daney  * reg: the register.
228cf41a51dSDavid Daney  * mask: if non-zero, ANDed with existing register value.
229cf41a51dSDavid Daney  * value: ORed with the masked value and written to the regiser.
230cf41a51dSDavid Daney  *
231cf41a51dSDavid Daney  */
232cf41a51dSDavid Daney static int marvell_of_reg_init(struct phy_device *phydev)
233cf41a51dSDavid Daney {
234cf41a51dSDavid Daney 	const __be32 *paddr;
235cf41a51dSDavid Daney 	int len, i, saved_page, current_page, page_changed, ret;
236cf41a51dSDavid Daney 
237cf41a51dSDavid Daney 	if (!phydev->dev.of_node)
238cf41a51dSDavid Daney 		return 0;
239cf41a51dSDavid Daney 
240cf41a51dSDavid Daney 	paddr = of_get_property(phydev->dev.of_node, "marvell,reg-init", &len);
241cf41a51dSDavid Daney 	if (!paddr || len < (4 * sizeof(*paddr)))
242cf41a51dSDavid Daney 		return 0;
243cf41a51dSDavid Daney 
244cf41a51dSDavid Daney 	saved_page = phy_read(phydev, MII_MARVELL_PHY_PAGE);
245cf41a51dSDavid Daney 	if (saved_page < 0)
246cf41a51dSDavid Daney 		return saved_page;
247cf41a51dSDavid Daney 	page_changed = 0;
248cf41a51dSDavid Daney 	current_page = saved_page;
249cf41a51dSDavid Daney 
250cf41a51dSDavid Daney 	ret = 0;
251cf41a51dSDavid Daney 	len /= sizeof(*paddr);
252cf41a51dSDavid Daney 	for (i = 0; i < len - 3; i += 4) {
253cf41a51dSDavid Daney 		u16 reg_page = be32_to_cpup(paddr + i);
254cf41a51dSDavid Daney 		u16 reg = be32_to_cpup(paddr + i + 1);
255cf41a51dSDavid Daney 		u16 mask = be32_to_cpup(paddr + i + 2);
256cf41a51dSDavid Daney 		u16 val_bits = be32_to_cpup(paddr + i + 3);
257cf41a51dSDavid Daney 		int val;
258cf41a51dSDavid Daney 
259cf41a51dSDavid Daney 		if (reg_page != current_page) {
260cf41a51dSDavid Daney 			current_page = reg_page;
261cf41a51dSDavid Daney 			page_changed = 1;
262cf41a51dSDavid Daney 			ret = phy_write(phydev, MII_MARVELL_PHY_PAGE, reg_page);
263cf41a51dSDavid Daney 			if (ret < 0)
264cf41a51dSDavid Daney 				goto err;
265cf41a51dSDavid Daney 		}
266cf41a51dSDavid Daney 
267cf41a51dSDavid Daney 		val = 0;
268cf41a51dSDavid Daney 		if (mask) {
269cf41a51dSDavid Daney 			val = phy_read(phydev, reg);
270cf41a51dSDavid Daney 			if (val < 0) {
271cf41a51dSDavid Daney 				ret = val;
272cf41a51dSDavid Daney 				goto err;
273cf41a51dSDavid Daney 			}
274cf41a51dSDavid Daney 			val &= mask;
275cf41a51dSDavid Daney 		}
276cf41a51dSDavid Daney 		val |= val_bits;
277cf41a51dSDavid Daney 
278cf41a51dSDavid Daney 		ret = phy_write(phydev, reg, val);
279cf41a51dSDavid Daney 		if (ret < 0)
280cf41a51dSDavid Daney 			goto err;
281cf41a51dSDavid Daney 
282cf41a51dSDavid Daney 	}
283cf41a51dSDavid Daney err:
284cf41a51dSDavid Daney 	if (page_changed) {
285cf41a51dSDavid Daney 		i = phy_write(phydev, MII_MARVELL_PHY_PAGE, saved_page);
286cf41a51dSDavid Daney 		if (ret == 0)
287cf41a51dSDavid Daney 			ret = i;
288cf41a51dSDavid Daney 	}
289cf41a51dSDavid Daney 	return ret;
290cf41a51dSDavid Daney }
291cf41a51dSDavid Daney #else
292cf41a51dSDavid Daney static int marvell_of_reg_init(struct phy_device *phydev)
293cf41a51dSDavid Daney {
294cf41a51dSDavid Daney 	return 0;
295cf41a51dSDavid Daney }
296cf41a51dSDavid Daney #endif /* CONFIG_OF_MDIO */
297cf41a51dSDavid Daney 
298140bc929SSergei Poselenov static int m88e1121_config_aneg(struct phy_device *phydev)
299140bc929SSergei Poselenov {
300c477d044SCyril Chemparathy 	int err, oldpage, mscr;
301c477d044SCyril Chemparathy 
30227d916d6SDavid Daney 	oldpage = phy_read(phydev, MII_MARVELL_PHY_PAGE);
303c477d044SCyril Chemparathy 
30427d916d6SDavid Daney 	err = phy_write(phydev, MII_MARVELL_PHY_PAGE,
305c477d044SCyril Chemparathy 			MII_88E1121_PHY_MSCR_PAGE);
306c477d044SCyril Chemparathy 	if (err < 0)
307c477d044SCyril Chemparathy 		return err;
308be8c6480SArnaud Patard 
309be8c6480SArnaud Patard 	if ((phydev->interface == PHY_INTERFACE_MODE_RGMII) ||
310be8c6480SArnaud Patard 	    (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) ||
311be8c6480SArnaud Patard 	    (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) ||
312be8c6480SArnaud Patard 	    (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)) {
313be8c6480SArnaud Patard 
314c477d044SCyril Chemparathy 		mscr = phy_read(phydev, MII_88E1121_PHY_MSCR_REG) &
315c477d044SCyril Chemparathy 			MII_88E1121_PHY_MSCR_DELAY_MASK;
316c477d044SCyril Chemparathy 
317c477d044SCyril Chemparathy 		if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)
318c477d044SCyril Chemparathy 			mscr |= (MII_88E1121_PHY_MSCR_RX_DELAY |
319c477d044SCyril Chemparathy 				 MII_88E1121_PHY_MSCR_TX_DELAY);
320c477d044SCyril Chemparathy 		else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID)
321c477d044SCyril Chemparathy 			mscr |= MII_88E1121_PHY_MSCR_RX_DELAY;
322c477d044SCyril Chemparathy 		else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)
323c477d044SCyril Chemparathy 			mscr |= MII_88E1121_PHY_MSCR_TX_DELAY;
324c477d044SCyril Chemparathy 
325c477d044SCyril Chemparathy 		err = phy_write(phydev, MII_88E1121_PHY_MSCR_REG, mscr);
326c477d044SCyril Chemparathy 		if (err < 0)
327c477d044SCyril Chemparathy 			return err;
328be8c6480SArnaud Patard 	}
329c477d044SCyril Chemparathy 
33027d916d6SDavid Daney 	phy_write(phydev, MII_MARVELL_PHY_PAGE, oldpage);
331140bc929SSergei Poselenov 
332140bc929SSergei Poselenov 	err = phy_write(phydev, MII_BMCR, BMCR_RESET);
333140bc929SSergei Poselenov 	if (err < 0)
334140bc929SSergei Poselenov 		return err;
335140bc929SSergei Poselenov 
336140bc929SSergei Poselenov 	err = phy_write(phydev, MII_M1011_PHY_SCR,
337140bc929SSergei Poselenov 			MII_M1011_PHY_SCR_AUTO_CROSS);
338140bc929SSergei Poselenov 	if (err < 0)
339140bc929SSergei Poselenov 		return err;
340140bc929SSergei Poselenov 
34127d916d6SDavid Daney 	oldpage = phy_read(phydev, MII_MARVELL_PHY_PAGE);
342140bc929SSergei Poselenov 
34327d916d6SDavid Daney 	phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_88E1121_PHY_LED_PAGE);
344140bc929SSergei Poselenov 	phy_write(phydev, MII_88E1121_PHY_LED_CTRL, MII_88E1121_PHY_LED_DEF);
34527d916d6SDavid Daney 	phy_write(phydev, MII_MARVELL_PHY_PAGE, oldpage);
346140bc929SSergei Poselenov 
347140bc929SSergei Poselenov 	err = genphy_config_aneg(phydev);
348140bc929SSergei Poselenov 
349140bc929SSergei Poselenov 	return err;
350140bc929SSergei Poselenov }
351140bc929SSergei Poselenov 
352337ac9d5SCyril Chemparathy static int m88e1318_config_aneg(struct phy_device *phydev)
3533ff1c259SCyril Chemparathy {
3543ff1c259SCyril Chemparathy 	int err, oldpage, mscr;
3553ff1c259SCyril Chemparathy 
35627d916d6SDavid Daney 	oldpage = phy_read(phydev, MII_MARVELL_PHY_PAGE);
3573ff1c259SCyril Chemparathy 
35827d916d6SDavid Daney 	err = phy_write(phydev, MII_MARVELL_PHY_PAGE,
3593ff1c259SCyril Chemparathy 			MII_88E1121_PHY_MSCR_PAGE);
3603ff1c259SCyril Chemparathy 	if (err < 0)
3613ff1c259SCyril Chemparathy 		return err;
3623ff1c259SCyril Chemparathy 
363337ac9d5SCyril Chemparathy 	mscr = phy_read(phydev, MII_88E1318S_PHY_MSCR1_REG);
364337ac9d5SCyril Chemparathy 	mscr |= MII_88E1318S_PHY_MSCR1_PAD_ODD;
3653ff1c259SCyril Chemparathy 
366337ac9d5SCyril Chemparathy 	err = phy_write(phydev, MII_88E1318S_PHY_MSCR1_REG, mscr);
3673ff1c259SCyril Chemparathy 	if (err < 0)
3683ff1c259SCyril Chemparathy 		return err;
3693ff1c259SCyril Chemparathy 
37027d916d6SDavid Daney 	err = phy_write(phydev, MII_MARVELL_PHY_PAGE, oldpage);
3713ff1c259SCyril Chemparathy 	if (err < 0)
3723ff1c259SCyril Chemparathy 		return err;
3733ff1c259SCyril Chemparathy 
3743ff1c259SCyril Chemparathy 	return m88e1121_config_aneg(phydev);
3753ff1c259SCyril Chemparathy }
3763ff1c259SCyril Chemparathy 
37710e24caaSMichal Simek static int m88e1510_config_aneg(struct phy_device *phydev)
37810e24caaSMichal Simek {
37910e24caaSMichal Simek 	int err;
38010e24caaSMichal Simek 
38110e24caaSMichal Simek 	err = m88e1318_config_aneg(phydev);
38210e24caaSMichal Simek 	if (err < 0)
38310e24caaSMichal Simek 		return err;
38410e24caaSMichal Simek 
38510e24caaSMichal Simek 	return marvell_of_reg_init(phydev);
38610e24caaSMichal Simek }
38710e24caaSMichal Simek 
3883da09a51SMichal Simek static int m88e1116r_config_init(struct phy_device *phydev)
3893da09a51SMichal Simek {
3903da09a51SMichal Simek 	int temp;
3913da09a51SMichal Simek 	int err;
3923da09a51SMichal Simek 
3933da09a51SMichal Simek 	temp = phy_read(phydev, MII_BMCR);
3943da09a51SMichal Simek 	temp |= BMCR_RESET;
3953da09a51SMichal Simek 	err = phy_write(phydev, MII_BMCR, temp);
3963da09a51SMichal Simek 	if (err < 0)
3973da09a51SMichal Simek 		return err;
3983da09a51SMichal Simek 
3993da09a51SMichal Simek 	mdelay(500);
4003da09a51SMichal Simek 
4013da09a51SMichal Simek 	err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0);
4023da09a51SMichal Simek 	if (err < 0)
4033da09a51SMichal Simek 		return err;
4043da09a51SMichal Simek 
4053da09a51SMichal Simek 	temp = phy_read(phydev, MII_M1011_PHY_SCR);
4063da09a51SMichal Simek 	temp |= (7 << 12);	/* max number of gigabit attempts */
4073da09a51SMichal Simek 	temp |= (1 << 11);	/* enable downshift */
4083da09a51SMichal Simek 	temp |= MII_M1011_PHY_SCR_AUTO_CROSS;
4093da09a51SMichal Simek 	err = phy_write(phydev, MII_M1011_PHY_SCR, temp);
4103da09a51SMichal Simek 	if (err < 0)
4113da09a51SMichal Simek 		return err;
4123da09a51SMichal Simek 
4133da09a51SMichal Simek 	err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 2);
4143da09a51SMichal Simek 	if (err < 0)
4153da09a51SMichal Simek 		return err;
4163da09a51SMichal Simek 	temp = phy_read(phydev, MII_M1116R_CONTROL_REG_MAC);
4173da09a51SMichal Simek 	temp |= (1 << 5);
4183da09a51SMichal Simek 	temp |= (1 << 4);
4193da09a51SMichal Simek 	err = phy_write(phydev, MII_M1116R_CONTROL_REG_MAC, temp);
4203da09a51SMichal Simek 	if (err < 0)
4213da09a51SMichal Simek 		return err;
4223da09a51SMichal Simek 	err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0);
4233da09a51SMichal Simek 	if (err < 0)
4243da09a51SMichal Simek 		return err;
4253da09a51SMichal Simek 
4263da09a51SMichal Simek 	temp = phy_read(phydev, MII_BMCR);
4273da09a51SMichal Simek 	temp |= BMCR_RESET;
4283da09a51SMichal Simek 	err = phy_write(phydev, MII_BMCR, temp);
4293da09a51SMichal Simek 	if (err < 0)
4303da09a51SMichal Simek 		return err;
4313da09a51SMichal Simek 
4323da09a51SMichal Simek 	mdelay(500);
4333da09a51SMichal Simek 
4343da09a51SMichal Simek 	return 0;
4353da09a51SMichal Simek }
4363da09a51SMichal Simek 
437895ee682SKim Phillips static int m88e1111_config_init(struct phy_device *phydev)
438895ee682SKim Phillips {
439895ee682SKim Phillips 	int err;
440be937f1fSAlexandr Smirnov 	int temp;
441be937f1fSAlexandr Smirnov 
442895ee682SKim Phillips 	if ((phydev->interface == PHY_INTERFACE_MODE_RGMII) ||
4439daf5a76SKim Phillips 	    (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) ||
4449daf5a76SKim Phillips 	    (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) ||
4459daf5a76SKim Phillips 	    (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)) {
446895ee682SKim Phillips 
447895ee682SKim Phillips 		temp = phy_read(phydev, MII_M1111_PHY_EXT_CR);
448895ee682SKim Phillips 		if (temp < 0)
449895ee682SKim Phillips 			return temp;
450895ee682SKim Phillips 
4519daf5a76SKim Phillips 		if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) {
452895ee682SKim Phillips 			temp |= (MII_M1111_RX_DELAY | MII_M1111_TX_DELAY);
4539daf5a76SKim Phillips 		} else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) {
4549daf5a76SKim Phillips 			temp &= ~MII_M1111_TX_DELAY;
4559daf5a76SKim Phillips 			temp |= MII_M1111_RX_DELAY;
4569daf5a76SKim Phillips 		} else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) {
4579daf5a76SKim Phillips 			temp &= ~MII_M1111_RX_DELAY;
4589daf5a76SKim Phillips 			temp |= MII_M1111_TX_DELAY;
4599daf5a76SKim Phillips 		}
460895ee682SKim Phillips 
461895ee682SKim Phillips 		err = phy_write(phydev, MII_M1111_PHY_EXT_CR, temp);
462895ee682SKim Phillips 		if (err < 0)
463895ee682SKim Phillips 			return err;
464895ee682SKim Phillips 
465895ee682SKim Phillips 		temp = phy_read(phydev, MII_M1111_PHY_EXT_SR);
466895ee682SKim Phillips 		if (temp < 0)
467895ee682SKim Phillips 			return temp;
468895ee682SKim Phillips 
469895ee682SKim Phillips 		temp &= ~(MII_M1111_HWCFG_MODE_MASK);
470be937f1fSAlexandr Smirnov 
4717239016dSWang Jian 		if (temp & MII_M1111_HWCFG_FIBER_COPPER_RES)
472be937f1fSAlexandr Smirnov 			temp |= MII_M1111_HWCFG_MODE_FIBER_RGMII;
473be937f1fSAlexandr Smirnov 		else
474be937f1fSAlexandr Smirnov 			temp |= MII_M1111_HWCFG_MODE_COPPER_RGMII;
475895ee682SKim Phillips 
476895ee682SKim Phillips 		err = phy_write(phydev, MII_M1111_PHY_EXT_SR, temp);
477895ee682SKim Phillips 		if (err < 0)
478895ee682SKim Phillips 			return err;
479895ee682SKim Phillips 	}
480895ee682SKim Phillips 
4814117b5beSKapil Juneja 	if (phydev->interface == PHY_INTERFACE_MODE_SGMII) {
4824117b5beSKapil Juneja 		temp = phy_read(phydev, MII_M1111_PHY_EXT_SR);
4834117b5beSKapil Juneja 		if (temp < 0)
4844117b5beSKapil Juneja 			return temp;
4854117b5beSKapil Juneja 
4864117b5beSKapil Juneja 		temp &= ~(MII_M1111_HWCFG_MODE_MASK);
4874117b5beSKapil Juneja 		temp |= MII_M1111_HWCFG_MODE_SGMII_NO_CLK;
48832d0c1e1SHaiying Wang 		temp |= MII_M1111_HWCFG_FIBER_COPPER_AUTO;
4894117b5beSKapil Juneja 
4904117b5beSKapil Juneja 		err = phy_write(phydev, MII_M1111_PHY_EXT_SR, temp);
4914117b5beSKapil Juneja 		if (err < 0)
4924117b5beSKapil Juneja 			return err;
4934117b5beSKapil Juneja 	}
4944117b5beSKapil Juneja 
4955f8cbc13SLiu Yu-B13201 	if (phydev->interface == PHY_INTERFACE_MODE_RTBI) {
4965f8cbc13SLiu Yu-B13201 		temp = phy_read(phydev, MII_M1111_PHY_EXT_CR);
4975f8cbc13SLiu Yu-B13201 		if (temp < 0)
4985f8cbc13SLiu Yu-B13201 			return temp;
4995f8cbc13SLiu Yu-B13201 		temp |= (MII_M1111_RX_DELAY | MII_M1111_TX_DELAY);
5005f8cbc13SLiu Yu-B13201 		err = phy_write(phydev, MII_M1111_PHY_EXT_CR, temp);
5015f8cbc13SLiu Yu-B13201 		if (err < 0)
5025f8cbc13SLiu Yu-B13201 			return err;
5035f8cbc13SLiu Yu-B13201 
5045f8cbc13SLiu Yu-B13201 		temp = phy_read(phydev, MII_M1111_PHY_EXT_SR);
5055f8cbc13SLiu Yu-B13201 		if (temp < 0)
5065f8cbc13SLiu Yu-B13201 			return temp;
5075f8cbc13SLiu Yu-B13201 		temp &= ~(MII_M1111_HWCFG_MODE_MASK | MII_M1111_HWCFG_FIBER_COPPER_RES);
5085f8cbc13SLiu Yu-B13201 		temp |= 0x7 | MII_M1111_HWCFG_FIBER_COPPER_AUTO;
5095f8cbc13SLiu Yu-B13201 		err = phy_write(phydev, MII_M1111_PHY_EXT_SR, temp);
5105f8cbc13SLiu Yu-B13201 		if (err < 0)
5115f8cbc13SLiu Yu-B13201 			return err;
5125f8cbc13SLiu Yu-B13201 
5135f8cbc13SLiu Yu-B13201 		/* soft reset */
5145f8cbc13SLiu Yu-B13201 		err = phy_write(phydev, MII_BMCR, BMCR_RESET);
5155f8cbc13SLiu Yu-B13201 		if (err < 0)
5165f8cbc13SLiu Yu-B13201 			return err;
5175f8cbc13SLiu Yu-B13201 		do
5185f8cbc13SLiu Yu-B13201 			temp = phy_read(phydev, MII_BMCR);
5195f8cbc13SLiu Yu-B13201 		while (temp & BMCR_RESET);
5205f8cbc13SLiu Yu-B13201 
5215f8cbc13SLiu Yu-B13201 		temp = phy_read(phydev, MII_M1111_PHY_EXT_SR);
5225f8cbc13SLiu Yu-B13201 		if (temp < 0)
5235f8cbc13SLiu Yu-B13201 			return temp;
5245f8cbc13SLiu Yu-B13201 		temp &= ~(MII_M1111_HWCFG_MODE_MASK | MII_M1111_HWCFG_FIBER_COPPER_RES);
5255f8cbc13SLiu Yu-B13201 		temp |= MII_M1111_HWCFG_MODE_COPPER_RTBI | MII_M1111_HWCFG_FIBER_COPPER_AUTO;
5265f8cbc13SLiu Yu-B13201 		err = phy_write(phydev, MII_M1111_PHY_EXT_SR, temp);
5275f8cbc13SLiu Yu-B13201 		if (err < 0)
5285f8cbc13SLiu Yu-B13201 			return err;
5295f8cbc13SLiu Yu-B13201 	}
5305f8cbc13SLiu Yu-B13201 
531cf41a51dSDavid Daney 	err = marvell_of_reg_init(phydev);
532cf41a51dSDavid Daney 	if (err < 0)
533cf41a51dSDavid Daney 		return err;
5345f8cbc13SLiu Yu-B13201 
535cc90cb3bSSrinivas Kandagatla 	return phy_write(phydev, MII_BMCR, BMCR_RESET);
536895ee682SKim Phillips }
537895ee682SKim Phillips 
538605f196eSRon Madrid static int m88e1118_config_aneg(struct phy_device *phydev)
539605f196eSRon Madrid {
540605f196eSRon Madrid 	int err;
541605f196eSRon Madrid 
542605f196eSRon Madrid 	err = phy_write(phydev, MII_BMCR, BMCR_RESET);
543605f196eSRon Madrid 	if (err < 0)
544605f196eSRon Madrid 		return err;
545605f196eSRon Madrid 
546605f196eSRon Madrid 	err = phy_write(phydev, MII_M1011_PHY_SCR,
547605f196eSRon Madrid 			MII_M1011_PHY_SCR_AUTO_CROSS);
548605f196eSRon Madrid 	if (err < 0)
549605f196eSRon Madrid 		return err;
550605f196eSRon Madrid 
551605f196eSRon Madrid 	err = genphy_config_aneg(phydev);
552605f196eSRon Madrid 	return 0;
553605f196eSRon Madrid }
554605f196eSRon Madrid 
555605f196eSRon Madrid static int m88e1118_config_init(struct phy_device *phydev)
556605f196eSRon Madrid {
557605f196eSRon Madrid 	int err;
558605f196eSRon Madrid 
559605f196eSRon Madrid 	/* Change address */
56027d916d6SDavid Daney 	err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0002);
561605f196eSRon Madrid 	if (err < 0)
562605f196eSRon Madrid 		return err;
563605f196eSRon Madrid 
564605f196eSRon Madrid 	/* Enable 1000 Mbit */
565605f196eSRon Madrid 	err = phy_write(phydev, 0x15, 0x1070);
566605f196eSRon Madrid 	if (err < 0)
567605f196eSRon Madrid 		return err;
568605f196eSRon Madrid 
569605f196eSRon Madrid 	/* Change address */
57027d916d6SDavid Daney 	err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0003);
571605f196eSRon Madrid 	if (err < 0)
572605f196eSRon Madrid 		return err;
573605f196eSRon Madrid 
574605f196eSRon Madrid 	/* Adjust LED Control */
5752f495c39SBenjamin Herrenschmidt 	if (phydev->dev_flags & MARVELL_PHY_M1118_DNS323_LEDS)
5762f495c39SBenjamin Herrenschmidt 		err = phy_write(phydev, 0x10, 0x1100);
5772f495c39SBenjamin Herrenschmidt 	else
578605f196eSRon Madrid 		err = phy_write(phydev, 0x10, 0x021e);
579605f196eSRon Madrid 	if (err < 0)
580605f196eSRon Madrid 		return err;
581605f196eSRon Madrid 
582cf41a51dSDavid Daney 	err = marvell_of_reg_init(phydev);
583cf41a51dSDavid Daney 	if (err < 0)
584cf41a51dSDavid Daney 		return err;
585cf41a51dSDavid Daney 
586605f196eSRon Madrid 	/* Reset address */
58727d916d6SDavid Daney 	err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0);
588605f196eSRon Madrid 	if (err < 0)
589605f196eSRon Madrid 		return err;
590605f196eSRon Madrid 
591cc90cb3bSSrinivas Kandagatla 	return phy_write(phydev, MII_BMCR, BMCR_RESET);
592605f196eSRon Madrid }
593605f196eSRon Madrid 
59490600732SDavid Daney static int m88e1149_config_init(struct phy_device *phydev)
59590600732SDavid Daney {
59690600732SDavid Daney 	int err;
59790600732SDavid Daney 
59890600732SDavid Daney 	/* Change address */
59990600732SDavid Daney 	err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0002);
60090600732SDavid Daney 	if (err < 0)
60190600732SDavid Daney 		return err;
60290600732SDavid Daney 
60390600732SDavid Daney 	/* Enable 1000 Mbit */
60490600732SDavid Daney 	err = phy_write(phydev, 0x15, 0x1048);
60590600732SDavid Daney 	if (err < 0)
60690600732SDavid Daney 		return err;
60790600732SDavid Daney 
608cf41a51dSDavid Daney 	err = marvell_of_reg_init(phydev);
609cf41a51dSDavid Daney 	if (err < 0)
610cf41a51dSDavid Daney 		return err;
611cf41a51dSDavid Daney 
61290600732SDavid Daney 	/* Reset address */
61390600732SDavid Daney 	err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0);
61490600732SDavid Daney 	if (err < 0)
61590600732SDavid Daney 		return err;
61690600732SDavid Daney 
617cc90cb3bSSrinivas Kandagatla 	return phy_write(phydev, MII_BMCR, BMCR_RESET);
61890600732SDavid Daney }
61990600732SDavid Daney 
62076884679SAndy Fleming static int m88e1145_config_init(struct phy_device *phydev)
62176884679SAndy Fleming {
62276884679SAndy Fleming 	int err;
62376884679SAndy Fleming 
62476884679SAndy Fleming 	/* Take care of errata E0 & E1 */
62576884679SAndy Fleming 	err = phy_write(phydev, 0x1d, 0x001b);
62676884679SAndy Fleming 	if (err < 0)
62776884679SAndy Fleming 		return err;
62876884679SAndy Fleming 
62976884679SAndy Fleming 	err = phy_write(phydev, 0x1e, 0x418f);
63076884679SAndy Fleming 	if (err < 0)
63176884679SAndy Fleming 		return err;
63276884679SAndy Fleming 
63376884679SAndy Fleming 	err = phy_write(phydev, 0x1d, 0x0016);
63476884679SAndy Fleming 	if (err < 0)
63576884679SAndy Fleming 		return err;
63676884679SAndy Fleming 
63776884679SAndy Fleming 	err = phy_write(phydev, 0x1e, 0xa2da);
63876884679SAndy Fleming 	if (err < 0)
63976884679SAndy Fleming 		return err;
64076884679SAndy Fleming 
641895ee682SKim Phillips 	if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) {
64276884679SAndy Fleming 		int temp = phy_read(phydev, MII_M1145_PHY_EXT_CR);
64376884679SAndy Fleming 		if (temp < 0)
64476884679SAndy Fleming 			return temp;
64576884679SAndy Fleming 
64676884679SAndy Fleming 		temp |= (MII_M1145_RGMII_RX_DELAY | MII_M1145_RGMII_TX_DELAY);
64776884679SAndy Fleming 
64876884679SAndy Fleming 		err = phy_write(phydev, MII_M1145_PHY_EXT_CR, temp);
64976884679SAndy Fleming 		if (err < 0)
65076884679SAndy Fleming 			return err;
65176884679SAndy Fleming 
6522f495c39SBenjamin Herrenschmidt 		if (phydev->dev_flags & MARVELL_PHY_M1145_FLAGS_RESISTANCE) {
65376884679SAndy Fleming 			err = phy_write(phydev, 0x1d, 0x0012);
65476884679SAndy Fleming 			if (err < 0)
65576884679SAndy Fleming 				return err;
65676884679SAndy Fleming 
65776884679SAndy Fleming 			temp = phy_read(phydev, 0x1e);
65876884679SAndy Fleming 			if (temp < 0)
65976884679SAndy Fleming 				return temp;
66076884679SAndy Fleming 
66176884679SAndy Fleming 			temp &= 0xf03f;
66276884679SAndy Fleming 			temp |= 2 << 9;	/* 36 ohm */
66376884679SAndy Fleming 			temp |= 2 << 6;	/* 39 ohm */
66476884679SAndy Fleming 
66576884679SAndy Fleming 			err = phy_write(phydev, 0x1e, temp);
66676884679SAndy Fleming 			if (err < 0)
66776884679SAndy Fleming 				return err;
66876884679SAndy Fleming 
66976884679SAndy Fleming 			err = phy_write(phydev, 0x1d, 0x3);
67076884679SAndy Fleming 			if (err < 0)
67176884679SAndy Fleming 				return err;
67276884679SAndy Fleming 
67376884679SAndy Fleming 			err = phy_write(phydev, 0x1e, 0x8000);
67476884679SAndy Fleming 			if (err < 0)
67576884679SAndy Fleming 				return err;
67676884679SAndy Fleming 		}
67776884679SAndy Fleming 	}
67876884679SAndy Fleming 
679cf41a51dSDavid Daney 	err = marvell_of_reg_init(phydev);
680cf41a51dSDavid Daney 	if (err < 0)
681cf41a51dSDavid Daney 		return err;
682cf41a51dSDavid Daney 
68376884679SAndy Fleming 	return 0;
68476884679SAndy Fleming }
68500db8189SAndy Fleming 
686be937f1fSAlexandr Smirnov /* marvell_read_status
687be937f1fSAlexandr Smirnov  *
688be937f1fSAlexandr Smirnov  * Generic status code does not detect Fiber correctly!
689be937f1fSAlexandr Smirnov  * Description:
690be937f1fSAlexandr Smirnov  *   Check the link, then figure out the current state
691be937f1fSAlexandr Smirnov  *   by comparing what we advertise with what the link partner
692be937f1fSAlexandr Smirnov  *   advertises.  Start by checking the gigabit possibilities,
693be937f1fSAlexandr Smirnov  *   then move on to 10/100.
694be937f1fSAlexandr Smirnov  */
695be937f1fSAlexandr Smirnov static int marvell_read_status(struct phy_device *phydev)
696be937f1fSAlexandr Smirnov {
697be937f1fSAlexandr Smirnov 	int adv;
698be937f1fSAlexandr Smirnov 	int err;
699be937f1fSAlexandr Smirnov 	int lpa;
700be937f1fSAlexandr Smirnov 	int status = 0;
701be937f1fSAlexandr Smirnov 
702be937f1fSAlexandr Smirnov 	/* Update the link, but return if there
703be937f1fSAlexandr Smirnov 	 * was an error */
704be937f1fSAlexandr Smirnov 	err = genphy_update_link(phydev);
705be937f1fSAlexandr Smirnov 	if (err)
706be937f1fSAlexandr Smirnov 		return err;
707be937f1fSAlexandr Smirnov 
708be937f1fSAlexandr Smirnov 	if (AUTONEG_ENABLE == phydev->autoneg) {
709be937f1fSAlexandr Smirnov 		status = phy_read(phydev, MII_M1011_PHY_STATUS);
710be937f1fSAlexandr Smirnov 		if (status < 0)
711be937f1fSAlexandr Smirnov 			return status;
712be937f1fSAlexandr Smirnov 
713be937f1fSAlexandr Smirnov 		lpa = phy_read(phydev, MII_LPA);
714be937f1fSAlexandr Smirnov 		if (lpa < 0)
715be937f1fSAlexandr Smirnov 			return lpa;
716be937f1fSAlexandr Smirnov 
717be937f1fSAlexandr Smirnov 		adv = phy_read(phydev, MII_ADVERTISE);
718be937f1fSAlexandr Smirnov 		if (adv < 0)
719be937f1fSAlexandr Smirnov 			return adv;
720be937f1fSAlexandr Smirnov 
721be937f1fSAlexandr Smirnov 		lpa &= adv;
722be937f1fSAlexandr Smirnov 
723be937f1fSAlexandr Smirnov 		if (status & MII_M1011_PHY_STATUS_FULLDUPLEX)
724be937f1fSAlexandr Smirnov 			phydev->duplex = DUPLEX_FULL;
725be937f1fSAlexandr Smirnov 		else
726be937f1fSAlexandr Smirnov 			phydev->duplex = DUPLEX_HALF;
727be937f1fSAlexandr Smirnov 
728be937f1fSAlexandr Smirnov 		status = status & MII_M1011_PHY_STATUS_SPD_MASK;
729be937f1fSAlexandr Smirnov 		phydev->pause = phydev->asym_pause = 0;
730be937f1fSAlexandr Smirnov 
731be937f1fSAlexandr Smirnov 		switch (status) {
732be937f1fSAlexandr Smirnov 		case MII_M1011_PHY_STATUS_1000:
733be937f1fSAlexandr Smirnov 			phydev->speed = SPEED_1000;
734be937f1fSAlexandr Smirnov 			break;
735be937f1fSAlexandr Smirnov 
736be937f1fSAlexandr Smirnov 		case MII_M1011_PHY_STATUS_100:
737be937f1fSAlexandr Smirnov 			phydev->speed = SPEED_100;
738be937f1fSAlexandr Smirnov 			break;
739be937f1fSAlexandr Smirnov 
740be937f1fSAlexandr Smirnov 		default:
741be937f1fSAlexandr Smirnov 			phydev->speed = SPEED_10;
742be937f1fSAlexandr Smirnov 			break;
743be937f1fSAlexandr Smirnov 		}
744be937f1fSAlexandr Smirnov 
745be937f1fSAlexandr Smirnov 		if (phydev->duplex == DUPLEX_FULL) {
746be937f1fSAlexandr Smirnov 			phydev->pause = lpa & LPA_PAUSE_CAP ? 1 : 0;
747be937f1fSAlexandr Smirnov 			phydev->asym_pause = lpa & LPA_PAUSE_ASYM ? 1 : 0;
748be937f1fSAlexandr Smirnov 		}
749be937f1fSAlexandr Smirnov 	} else {
750be937f1fSAlexandr Smirnov 		int bmcr = phy_read(phydev, MII_BMCR);
751be937f1fSAlexandr Smirnov 
752be937f1fSAlexandr Smirnov 		if (bmcr < 0)
753be937f1fSAlexandr Smirnov 			return bmcr;
754be937f1fSAlexandr Smirnov 
755be937f1fSAlexandr Smirnov 		if (bmcr & BMCR_FULLDPLX)
756be937f1fSAlexandr Smirnov 			phydev->duplex = DUPLEX_FULL;
757be937f1fSAlexandr Smirnov 		else
758be937f1fSAlexandr Smirnov 			phydev->duplex = DUPLEX_HALF;
759be937f1fSAlexandr Smirnov 
760be937f1fSAlexandr Smirnov 		if (bmcr & BMCR_SPEED1000)
761be937f1fSAlexandr Smirnov 			phydev->speed = SPEED_1000;
762be937f1fSAlexandr Smirnov 		else if (bmcr & BMCR_SPEED100)
763be937f1fSAlexandr Smirnov 			phydev->speed = SPEED_100;
764be937f1fSAlexandr Smirnov 		else
765be937f1fSAlexandr Smirnov 			phydev->speed = SPEED_10;
766be937f1fSAlexandr Smirnov 
767be937f1fSAlexandr Smirnov 		phydev->pause = phydev->asym_pause = 0;
768be937f1fSAlexandr Smirnov 	}
769be937f1fSAlexandr Smirnov 
770be937f1fSAlexandr Smirnov 	return 0;
771be937f1fSAlexandr Smirnov }
772be937f1fSAlexandr Smirnov 
773dcd07be3SAnatolij Gustschin static int m88e1121_did_interrupt(struct phy_device *phydev)
774dcd07be3SAnatolij Gustschin {
775dcd07be3SAnatolij Gustschin 	int imask;
776dcd07be3SAnatolij Gustschin 
777dcd07be3SAnatolij Gustschin 	imask = phy_read(phydev, MII_M1011_IEVENT);
778dcd07be3SAnatolij Gustschin 
779dcd07be3SAnatolij Gustschin 	if (imask & MII_M1011_IMASK_INIT)
780dcd07be3SAnatolij Gustschin 		return 1;
781dcd07be3SAnatolij Gustschin 
782dcd07be3SAnatolij Gustschin 	return 0;
783dcd07be3SAnatolij Gustschin }
784dcd07be3SAnatolij Gustschin 
7853871c387SMichael Stapelberg static void m88e1318_get_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol)
7863871c387SMichael Stapelberg {
7873871c387SMichael Stapelberg 	wol->supported = WAKE_MAGIC;
7883871c387SMichael Stapelberg 	wol->wolopts = 0;
7893871c387SMichael Stapelberg 
7903871c387SMichael Stapelberg 	if (phy_write(phydev, MII_MARVELL_PHY_PAGE,
7913871c387SMichael Stapelberg 		      MII_88E1318S_PHY_WOL_PAGE) < 0)
7923871c387SMichael Stapelberg 		return;
7933871c387SMichael Stapelberg 
7943871c387SMichael Stapelberg 	if (phy_read(phydev, MII_88E1318S_PHY_WOL_CTRL) &
7953871c387SMichael Stapelberg 	    MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE)
7963871c387SMichael Stapelberg 		wol->wolopts |= WAKE_MAGIC;
7973871c387SMichael Stapelberg 
7983871c387SMichael Stapelberg 	if (phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x00) < 0)
7993871c387SMichael Stapelberg 		return;
8003871c387SMichael Stapelberg }
8013871c387SMichael Stapelberg 
8023871c387SMichael Stapelberg static int m88e1318_set_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol)
8033871c387SMichael Stapelberg {
8043871c387SMichael Stapelberg 	int err, oldpage, temp;
8053871c387SMichael Stapelberg 
8063871c387SMichael Stapelberg 	oldpage = phy_read(phydev, MII_MARVELL_PHY_PAGE);
8073871c387SMichael Stapelberg 
8083871c387SMichael Stapelberg 	if (wol->wolopts & WAKE_MAGIC) {
8093871c387SMichael Stapelberg 		/* Explicitly switch to page 0x00, just to be sure */
8103871c387SMichael Stapelberg 		err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x00);
8113871c387SMichael Stapelberg 		if (err < 0)
8123871c387SMichael Stapelberg 			return err;
8133871c387SMichael Stapelberg 
8143871c387SMichael Stapelberg 		/* Enable the WOL interrupt */
8153871c387SMichael Stapelberg 		temp = phy_read(phydev, MII_88E1318S_PHY_CSIER);
8163871c387SMichael Stapelberg 		temp |= MII_88E1318S_PHY_CSIER_WOL_EIE;
8173871c387SMichael Stapelberg 		err = phy_write(phydev, MII_88E1318S_PHY_CSIER, temp);
8183871c387SMichael Stapelberg 		if (err < 0)
8193871c387SMichael Stapelberg 			return err;
8203871c387SMichael Stapelberg 
8213871c387SMichael Stapelberg 		err = phy_write(phydev, MII_MARVELL_PHY_PAGE,
8223871c387SMichael Stapelberg 				MII_88E1318S_PHY_LED_PAGE);
8233871c387SMichael Stapelberg 		if (err < 0)
8243871c387SMichael Stapelberg 			return err;
8253871c387SMichael Stapelberg 
8263871c387SMichael Stapelberg 		/* Setup LED[2] as interrupt pin (active low) */
8273871c387SMichael Stapelberg 		temp = phy_read(phydev, MII_88E1318S_PHY_LED_TCR);
8283871c387SMichael Stapelberg 		temp &= ~MII_88E1318S_PHY_LED_TCR_FORCE_INT;
8293871c387SMichael Stapelberg 		temp |= MII_88E1318S_PHY_LED_TCR_INTn_ENABLE;
8303871c387SMichael Stapelberg 		temp |= MII_88E1318S_PHY_LED_TCR_INT_ACTIVE_LOW;
8313871c387SMichael Stapelberg 		err = phy_write(phydev, MII_88E1318S_PHY_LED_TCR, temp);
8323871c387SMichael Stapelberg 		if (err < 0)
8333871c387SMichael Stapelberg 			return err;
8343871c387SMichael Stapelberg 
8353871c387SMichael Stapelberg 		err = phy_write(phydev, MII_MARVELL_PHY_PAGE,
8363871c387SMichael Stapelberg 				MII_88E1318S_PHY_WOL_PAGE);
8373871c387SMichael Stapelberg 		if (err < 0)
8383871c387SMichael Stapelberg 			return err;
8393871c387SMichael Stapelberg 
8403871c387SMichael Stapelberg 		/* Store the device address for the magic packet */
8413871c387SMichael Stapelberg 		err = phy_write(phydev, MII_88E1318S_PHY_MAGIC_PACKET_WORD2,
8423871c387SMichael Stapelberg 				((phydev->attached_dev->dev_addr[5] << 8) |
8433871c387SMichael Stapelberg 				 phydev->attached_dev->dev_addr[4]));
8443871c387SMichael Stapelberg 		if (err < 0)
8453871c387SMichael Stapelberg 			return err;
8463871c387SMichael Stapelberg 		err = phy_write(phydev, MII_88E1318S_PHY_MAGIC_PACKET_WORD1,
8473871c387SMichael Stapelberg 				((phydev->attached_dev->dev_addr[3] << 8) |
8483871c387SMichael Stapelberg 				 phydev->attached_dev->dev_addr[2]));
8493871c387SMichael Stapelberg 		if (err < 0)
8503871c387SMichael Stapelberg 			return err;
8513871c387SMichael Stapelberg 		err = phy_write(phydev, MII_88E1318S_PHY_MAGIC_PACKET_WORD0,
8523871c387SMichael Stapelberg 				((phydev->attached_dev->dev_addr[1] << 8) |
8533871c387SMichael Stapelberg 				 phydev->attached_dev->dev_addr[0]));
8543871c387SMichael Stapelberg 		if (err < 0)
8553871c387SMichael Stapelberg 			return err;
8563871c387SMichael Stapelberg 
8573871c387SMichael Stapelberg 		/* Clear WOL status and enable magic packet matching */
8583871c387SMichael Stapelberg 		temp = phy_read(phydev, MII_88E1318S_PHY_WOL_CTRL);
8593871c387SMichael Stapelberg 		temp |= MII_88E1318S_PHY_WOL_CTRL_CLEAR_WOL_STATUS;
8603871c387SMichael Stapelberg 		temp |= MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE;
8613871c387SMichael Stapelberg 		err = phy_write(phydev, MII_88E1318S_PHY_WOL_CTRL, temp);
8623871c387SMichael Stapelberg 		if (err < 0)
8633871c387SMichael Stapelberg 			return err;
8643871c387SMichael Stapelberg 	} else {
8653871c387SMichael Stapelberg 		err = phy_write(phydev, MII_MARVELL_PHY_PAGE,
8663871c387SMichael Stapelberg 				MII_88E1318S_PHY_WOL_PAGE);
8673871c387SMichael Stapelberg 		if (err < 0)
8683871c387SMichael Stapelberg 			return err;
8693871c387SMichael Stapelberg 
8703871c387SMichael Stapelberg 		/* Clear WOL status and disable magic packet matching */
8713871c387SMichael Stapelberg 		temp = phy_read(phydev, MII_88E1318S_PHY_WOL_CTRL);
8723871c387SMichael Stapelberg 		temp |= MII_88E1318S_PHY_WOL_CTRL_CLEAR_WOL_STATUS;
8733871c387SMichael Stapelberg 		temp &= ~MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE;
8743871c387SMichael Stapelberg 		err = phy_write(phydev, MII_88E1318S_PHY_WOL_CTRL, temp);
8753871c387SMichael Stapelberg 		if (err < 0)
8763871c387SMichael Stapelberg 			return err;
8773871c387SMichael Stapelberg 	}
8783871c387SMichael Stapelberg 
8793871c387SMichael Stapelberg 	err = phy_write(phydev, MII_MARVELL_PHY_PAGE, oldpage);
8803871c387SMichael Stapelberg 	if (err < 0)
8813871c387SMichael Stapelberg 		return err;
8823871c387SMichael Stapelberg 
8833871c387SMichael Stapelberg 	return 0;
8843871c387SMichael Stapelberg }
8853871c387SMichael Stapelberg 
886e5479239SOlof Johansson static struct phy_driver marvell_drivers[] = {
887e5479239SOlof Johansson 	{
8882f495c39SBenjamin Herrenschmidt 		.phy_id = MARVELL_PHY_ID_88E1101,
8892f495c39SBenjamin Herrenschmidt 		.phy_id_mask = MARVELL_PHY_ID_MASK,
89000db8189SAndy Fleming 		.name = "Marvell 88E1101",
89100db8189SAndy Fleming 		.features = PHY_GBIT_FEATURES,
89200db8189SAndy Fleming 		.flags = PHY_HAS_INTERRUPT,
89300db8189SAndy Fleming 		.config_aneg = &marvell_config_aneg,
89400db8189SAndy Fleming 		.read_status = &genphy_read_status,
89500db8189SAndy Fleming 		.ack_interrupt = &marvell_ack_interrupt,
89600db8189SAndy Fleming 		.config_intr = &marvell_config_intr,
8970898b448SSebastian Hesselbarth 		.resume = &genphy_resume,
8980898b448SSebastian Hesselbarth 		.suspend = &genphy_suspend,
899ac8c635aSOlof Johansson 		.driver = { .owner = THIS_MODULE },
900e5479239SOlof Johansson 	},
901e5479239SOlof Johansson 	{
9022f495c39SBenjamin Herrenschmidt 		.phy_id = MARVELL_PHY_ID_88E1112,
9032f495c39SBenjamin Herrenschmidt 		.phy_id_mask = MARVELL_PHY_ID_MASK,
90485cfb534SOlof Johansson 		.name = "Marvell 88E1112",
90585cfb534SOlof Johansson 		.features = PHY_GBIT_FEATURES,
90685cfb534SOlof Johansson 		.flags = PHY_HAS_INTERRUPT,
90785cfb534SOlof Johansson 		.config_init = &m88e1111_config_init,
90885cfb534SOlof Johansson 		.config_aneg = &marvell_config_aneg,
90985cfb534SOlof Johansson 		.read_status = &genphy_read_status,
91085cfb534SOlof Johansson 		.ack_interrupt = &marvell_ack_interrupt,
91185cfb534SOlof Johansson 		.config_intr = &marvell_config_intr,
9120898b448SSebastian Hesselbarth 		.resume = &genphy_resume,
9130898b448SSebastian Hesselbarth 		.suspend = &genphy_suspend,
914ac8c635aSOlof Johansson 		.driver = { .owner = THIS_MODULE },
91585cfb534SOlof Johansson 	},
91685cfb534SOlof Johansson 	{
9172f495c39SBenjamin Herrenschmidt 		.phy_id = MARVELL_PHY_ID_88E1111,
9182f495c39SBenjamin Herrenschmidt 		.phy_id_mask = MARVELL_PHY_ID_MASK,
91976884679SAndy Fleming 		.name = "Marvell 88E1111",
92076884679SAndy Fleming 		.features = PHY_GBIT_FEATURES,
92176884679SAndy Fleming 		.flags = PHY_HAS_INTERRUPT,
922e5479239SOlof Johansson 		.config_init = &m88e1111_config_init,
92376884679SAndy Fleming 		.config_aneg = &marvell_config_aneg,
924be937f1fSAlexandr Smirnov 		.read_status = &marvell_read_status,
92576884679SAndy Fleming 		.ack_interrupt = &marvell_ack_interrupt,
92676884679SAndy Fleming 		.config_intr = &marvell_config_intr,
9270898b448SSebastian Hesselbarth 		.resume = &genphy_resume,
9280898b448SSebastian Hesselbarth 		.suspend = &genphy_suspend,
929ac8c635aSOlof Johansson 		.driver = { .owner = THIS_MODULE },
930e5479239SOlof Johansson 	},
931e5479239SOlof Johansson 	{
9322f495c39SBenjamin Herrenschmidt 		.phy_id = MARVELL_PHY_ID_88E1118,
9332f495c39SBenjamin Herrenschmidt 		.phy_id_mask = MARVELL_PHY_ID_MASK,
934605f196eSRon Madrid 		.name = "Marvell 88E1118",
935605f196eSRon Madrid 		.features = PHY_GBIT_FEATURES,
936605f196eSRon Madrid 		.flags = PHY_HAS_INTERRUPT,
937605f196eSRon Madrid 		.config_init = &m88e1118_config_init,
938605f196eSRon Madrid 		.config_aneg = &m88e1118_config_aneg,
939605f196eSRon Madrid 		.read_status = &genphy_read_status,
940605f196eSRon Madrid 		.ack_interrupt = &marvell_ack_interrupt,
941605f196eSRon Madrid 		.config_intr = &marvell_config_intr,
9420898b448SSebastian Hesselbarth 		.resume = &genphy_resume,
9430898b448SSebastian Hesselbarth 		.suspend = &genphy_suspend,
944605f196eSRon Madrid 		.driver = {.owner = THIS_MODULE,},
945605f196eSRon Madrid 	},
946605f196eSRon Madrid 	{
9472f495c39SBenjamin Herrenschmidt 		.phy_id = MARVELL_PHY_ID_88E1121R,
9482f495c39SBenjamin Herrenschmidt 		.phy_id_mask = MARVELL_PHY_ID_MASK,
949140bc929SSergei Poselenov 		.name = "Marvell 88E1121R",
950140bc929SSergei Poselenov 		.features = PHY_GBIT_FEATURES,
951140bc929SSergei Poselenov 		.flags = PHY_HAS_INTERRUPT,
952140bc929SSergei Poselenov 		.config_aneg = &m88e1121_config_aneg,
953140bc929SSergei Poselenov 		.read_status = &marvell_read_status,
954140bc929SSergei Poselenov 		.ack_interrupt = &marvell_ack_interrupt,
955140bc929SSergei Poselenov 		.config_intr = &marvell_config_intr,
956dcd07be3SAnatolij Gustschin 		.did_interrupt = &m88e1121_did_interrupt,
9570898b448SSebastian Hesselbarth 		.resume = &genphy_resume,
9580898b448SSebastian Hesselbarth 		.suspend = &genphy_suspend,
959140bc929SSergei Poselenov 		.driver = { .owner = THIS_MODULE },
960140bc929SSergei Poselenov 	},
961140bc929SSergei Poselenov 	{
962337ac9d5SCyril Chemparathy 		.phy_id = MARVELL_PHY_ID_88E1318S,
9636ba74014SLinus Torvalds 		.phy_id_mask = MARVELL_PHY_ID_MASK,
964337ac9d5SCyril Chemparathy 		.name = "Marvell 88E1318S",
9653ff1c259SCyril Chemparathy 		.features = PHY_GBIT_FEATURES,
9663ff1c259SCyril Chemparathy 		.flags = PHY_HAS_INTERRUPT,
967337ac9d5SCyril Chemparathy 		.config_aneg = &m88e1318_config_aneg,
9683ff1c259SCyril Chemparathy 		.read_status = &marvell_read_status,
9693ff1c259SCyril Chemparathy 		.ack_interrupt = &marvell_ack_interrupt,
9703ff1c259SCyril Chemparathy 		.config_intr = &marvell_config_intr,
9713ff1c259SCyril Chemparathy 		.did_interrupt = &m88e1121_did_interrupt,
9723871c387SMichael Stapelberg 		.get_wol = &m88e1318_get_wol,
9733871c387SMichael Stapelberg 		.set_wol = &m88e1318_set_wol,
9740898b448SSebastian Hesselbarth 		.resume = &genphy_resume,
9750898b448SSebastian Hesselbarth 		.suspend = &genphy_suspend,
9763ff1c259SCyril Chemparathy 		.driver = { .owner = THIS_MODULE },
9773ff1c259SCyril Chemparathy 	},
9783ff1c259SCyril Chemparathy 	{
9792f495c39SBenjamin Herrenschmidt 		.phy_id = MARVELL_PHY_ID_88E1145,
9802f495c39SBenjamin Herrenschmidt 		.phy_id_mask = MARVELL_PHY_ID_MASK,
98176884679SAndy Fleming 		.name = "Marvell 88E1145",
98276884679SAndy Fleming 		.features = PHY_GBIT_FEATURES,
98376884679SAndy Fleming 		.flags = PHY_HAS_INTERRUPT,
98476884679SAndy Fleming 		.config_init = &m88e1145_config_init,
98576884679SAndy Fleming 		.config_aneg = &marvell_config_aneg,
98676884679SAndy Fleming 		.read_status = &genphy_read_status,
98776884679SAndy Fleming 		.ack_interrupt = &marvell_ack_interrupt,
98876884679SAndy Fleming 		.config_intr = &marvell_config_intr,
9890898b448SSebastian Hesselbarth 		.resume = &genphy_resume,
9900898b448SSebastian Hesselbarth 		.suspend = &genphy_suspend,
991ac8c635aSOlof Johansson 		.driver = { .owner = THIS_MODULE },
992ac8c635aSOlof Johansson 	},
993ac8c635aSOlof Johansson 	{
99490600732SDavid Daney 		.phy_id = MARVELL_PHY_ID_88E1149R,
99590600732SDavid Daney 		.phy_id_mask = MARVELL_PHY_ID_MASK,
99690600732SDavid Daney 		.name = "Marvell 88E1149R",
99790600732SDavid Daney 		.features = PHY_GBIT_FEATURES,
99890600732SDavid Daney 		.flags = PHY_HAS_INTERRUPT,
99990600732SDavid Daney 		.config_init = &m88e1149_config_init,
100090600732SDavid Daney 		.config_aneg = &m88e1118_config_aneg,
100190600732SDavid Daney 		.read_status = &genphy_read_status,
100290600732SDavid Daney 		.ack_interrupt = &marvell_ack_interrupt,
100390600732SDavid Daney 		.config_intr = &marvell_config_intr,
10040898b448SSebastian Hesselbarth 		.resume = &genphy_resume,
10050898b448SSebastian Hesselbarth 		.suspend = &genphy_suspend,
100690600732SDavid Daney 		.driver = { .owner = THIS_MODULE },
100790600732SDavid Daney 	},
100890600732SDavid Daney 	{
10092f495c39SBenjamin Herrenschmidt 		.phy_id = MARVELL_PHY_ID_88E1240,
10102f495c39SBenjamin Herrenschmidt 		.phy_id_mask = MARVELL_PHY_ID_MASK,
1011ac8c635aSOlof Johansson 		.name = "Marvell 88E1240",
1012ac8c635aSOlof Johansson 		.features = PHY_GBIT_FEATURES,
1013ac8c635aSOlof Johansson 		.flags = PHY_HAS_INTERRUPT,
1014ac8c635aSOlof Johansson 		.config_init = &m88e1111_config_init,
1015ac8c635aSOlof Johansson 		.config_aneg = &marvell_config_aneg,
1016ac8c635aSOlof Johansson 		.read_status = &genphy_read_status,
1017ac8c635aSOlof Johansson 		.ack_interrupt = &marvell_ack_interrupt,
1018ac8c635aSOlof Johansson 		.config_intr = &marvell_config_intr,
10190898b448SSebastian Hesselbarth 		.resume = &genphy_resume,
10200898b448SSebastian Hesselbarth 		.suspend = &genphy_suspend,
1021ac8c635aSOlof Johansson 		.driver = { .owner = THIS_MODULE },
1022ac8c635aSOlof Johansson 	},
10233da09a51SMichal Simek 	{
10243da09a51SMichal Simek 		.phy_id = MARVELL_PHY_ID_88E1116R,
10253da09a51SMichal Simek 		.phy_id_mask = MARVELL_PHY_ID_MASK,
10263da09a51SMichal Simek 		.name = "Marvell 88E1116R",
10273da09a51SMichal Simek 		.features = PHY_GBIT_FEATURES,
10283da09a51SMichal Simek 		.flags = PHY_HAS_INTERRUPT,
10293da09a51SMichal Simek 		.config_init = &m88e1116r_config_init,
10303da09a51SMichal Simek 		.config_aneg = &genphy_config_aneg,
10313da09a51SMichal Simek 		.read_status = &genphy_read_status,
10323da09a51SMichal Simek 		.ack_interrupt = &marvell_ack_interrupt,
10333da09a51SMichal Simek 		.config_intr = &marvell_config_intr,
10340898b448SSebastian Hesselbarth 		.resume = &genphy_resume,
10350898b448SSebastian Hesselbarth 		.suspend = &genphy_suspend,
10363da09a51SMichal Simek 		.driver = { .owner = THIS_MODULE },
10373da09a51SMichal Simek 	},
103810e24caaSMichal Simek 	{
103910e24caaSMichal Simek 		.phy_id = MARVELL_PHY_ID_88E1510,
104010e24caaSMichal Simek 		.phy_id_mask = MARVELL_PHY_ID_MASK,
104110e24caaSMichal Simek 		.name = "Marvell 88E1510",
104210e24caaSMichal Simek 		.features = PHY_GBIT_FEATURES,
104310e24caaSMichal Simek 		.flags = PHY_HAS_INTERRUPT,
104410e24caaSMichal Simek 		.config_aneg = &m88e1510_config_aneg,
104510e24caaSMichal Simek 		.read_status = &marvell_read_status,
104610e24caaSMichal Simek 		.ack_interrupt = &marvell_ack_interrupt,
104710e24caaSMichal Simek 		.config_intr = &marvell_config_intr,
104810e24caaSMichal Simek 		.did_interrupt = &m88e1121_did_interrupt,
10490898b448SSebastian Hesselbarth 		.resume = &genphy_resume,
10500898b448SSebastian Hesselbarth 		.suspend = &genphy_suspend,
105110e24caaSMichal Simek 		.driver = { .owner = THIS_MODULE },
105210e24caaSMichal Simek 	},
105376884679SAndy Fleming };
105476884679SAndy Fleming 
105500db8189SAndy Fleming static int __init marvell_init(void)
105600db8189SAndy Fleming {
1057d5bf9071SChristian Hohnstaedt 	return phy_drivers_register(marvell_drivers,
1058d5bf9071SChristian Hohnstaedt 		 ARRAY_SIZE(marvell_drivers));
105900db8189SAndy Fleming }
106000db8189SAndy Fleming 
106100db8189SAndy Fleming static void __exit marvell_exit(void)
106200db8189SAndy Fleming {
1063d5bf9071SChristian Hohnstaedt 	phy_drivers_unregister(marvell_drivers,
1064d5bf9071SChristian Hohnstaedt 		 ARRAY_SIZE(marvell_drivers));
106500db8189SAndy Fleming }
106600db8189SAndy Fleming 
106700db8189SAndy Fleming module_init(marvell_init);
106800db8189SAndy Fleming module_exit(marvell_exit);
10694e4f10f6SDavid Woodhouse 
1070cf93c945SUwe Kleine-König static struct mdio_device_id __maybe_unused marvell_tbl[] = {
1071f5e1cabfSMichal Simek 	{ MARVELL_PHY_ID_88E1101, MARVELL_PHY_ID_MASK },
1072f5e1cabfSMichal Simek 	{ MARVELL_PHY_ID_88E1112, MARVELL_PHY_ID_MASK },
1073f5e1cabfSMichal Simek 	{ MARVELL_PHY_ID_88E1111, MARVELL_PHY_ID_MASK },
1074f5e1cabfSMichal Simek 	{ MARVELL_PHY_ID_88E1118, MARVELL_PHY_ID_MASK },
1075f5e1cabfSMichal Simek 	{ MARVELL_PHY_ID_88E1121R, MARVELL_PHY_ID_MASK },
1076f5e1cabfSMichal Simek 	{ MARVELL_PHY_ID_88E1145, MARVELL_PHY_ID_MASK },
1077f5e1cabfSMichal Simek 	{ MARVELL_PHY_ID_88E1149R, MARVELL_PHY_ID_MASK },
1078f5e1cabfSMichal Simek 	{ MARVELL_PHY_ID_88E1240, MARVELL_PHY_ID_MASK },
1079f5e1cabfSMichal Simek 	{ MARVELL_PHY_ID_88E1318S, MARVELL_PHY_ID_MASK },
10803da09a51SMichal Simek 	{ MARVELL_PHY_ID_88E1116R, MARVELL_PHY_ID_MASK },
108110e24caaSMichal Simek 	{ MARVELL_PHY_ID_88E1510, MARVELL_PHY_ID_MASK },
10824e4f10f6SDavid Woodhouse 	{ }
10834e4f10f6SDavid Woodhouse };
10844e4f10f6SDavid Woodhouse 
10854e4f10f6SDavid Woodhouse MODULE_DEVICE_TABLE(mdio, marvell_tbl);
1086