xref: /openbmc/linux/drivers/net/phy/marvell.c (revision 337ac9d5)
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  *
1000db8189SAndy Fleming  * This program is free software; you can redistribute  it and/or modify it
1100db8189SAndy Fleming  * under  the terms of  the GNU General  Public License as published by the
1200db8189SAndy Fleming  * Free Software Foundation;  either version 2 of the  License, or (at your
1300db8189SAndy Fleming  * option) any later version.
1400db8189SAndy Fleming  *
1500db8189SAndy Fleming  */
1600db8189SAndy Fleming #include <linux/kernel.h>
1700db8189SAndy Fleming #include <linux/string.h>
1800db8189SAndy Fleming #include <linux/errno.h>
1900db8189SAndy Fleming #include <linux/unistd.h>
2000db8189SAndy Fleming #include <linux/interrupt.h>
2100db8189SAndy Fleming #include <linux/init.h>
2200db8189SAndy Fleming #include <linux/delay.h>
2300db8189SAndy Fleming #include <linux/netdevice.h>
2400db8189SAndy Fleming #include <linux/etherdevice.h>
2500db8189SAndy Fleming #include <linux/skbuff.h>
2600db8189SAndy Fleming #include <linux/spinlock.h>
2700db8189SAndy Fleming #include <linux/mm.h>
2800db8189SAndy Fleming #include <linux/module.h>
2900db8189SAndy Fleming #include <linux/mii.h>
3000db8189SAndy Fleming #include <linux/ethtool.h>
3100db8189SAndy Fleming #include <linux/phy.h>
322f495c39SBenjamin Herrenschmidt #include <linux/marvell_phy.h>
3300db8189SAndy Fleming 
3400db8189SAndy Fleming #include <asm/io.h>
3500db8189SAndy Fleming #include <asm/irq.h>
3600db8189SAndy Fleming #include <asm/uaccess.h>
3700db8189SAndy Fleming 
3800db8189SAndy Fleming #define MII_M1011_IEVENT		0x13
3900db8189SAndy Fleming #define MII_M1011_IEVENT_CLEAR		0x0000
4000db8189SAndy Fleming 
4100db8189SAndy Fleming #define MII_M1011_IMASK			0x12
4200db8189SAndy Fleming #define MII_M1011_IMASK_INIT		0x6400
4300db8189SAndy Fleming #define MII_M1011_IMASK_CLEAR		0x0000
4400db8189SAndy Fleming 
4576884679SAndy Fleming #define MII_M1011_PHY_SCR		0x10
4676884679SAndy Fleming #define MII_M1011_PHY_SCR_AUTO_CROSS	0x0060
4776884679SAndy Fleming 
4876884679SAndy Fleming #define MII_M1145_PHY_EXT_CR		0x14
4976884679SAndy Fleming #define MII_M1145_RGMII_RX_DELAY	0x0080
5076884679SAndy Fleming #define MII_M1145_RGMII_TX_DELAY	0x0002
5176884679SAndy Fleming 
5276884679SAndy Fleming #define MII_M1111_PHY_LED_CONTROL	0x18
5376884679SAndy Fleming #define MII_M1111_PHY_LED_DIRECT	0x4100
5476884679SAndy Fleming #define MII_M1111_PHY_LED_COMBINE	0x411c
55895ee682SKim Phillips #define MII_M1111_PHY_EXT_CR		0x14
56895ee682SKim Phillips #define MII_M1111_RX_DELAY		0x80
57895ee682SKim Phillips #define MII_M1111_TX_DELAY		0x2
58895ee682SKim Phillips #define MII_M1111_PHY_EXT_SR		0x1b
59be937f1fSAlexandr Smirnov 
60895ee682SKim Phillips #define MII_M1111_HWCFG_MODE_MASK		0xf
61be937f1fSAlexandr Smirnov #define MII_M1111_HWCFG_MODE_COPPER_RGMII	0xb
62be937f1fSAlexandr Smirnov #define MII_M1111_HWCFG_MODE_FIBER_RGMII	0x3
634117b5beSKapil Juneja #define MII_M1111_HWCFG_MODE_SGMII_NO_CLK	0x4
645f8cbc13SLiu Yu-B13201 #define MII_M1111_HWCFG_MODE_COPPER_RTBI	0x9
65be937f1fSAlexandr Smirnov #define MII_M1111_HWCFG_FIBER_COPPER_AUTO	0x8000
66be937f1fSAlexandr Smirnov #define MII_M1111_HWCFG_FIBER_COPPER_RES	0x2000
67be937f1fSAlexandr Smirnov 
68be937f1fSAlexandr Smirnov #define MII_M1111_COPPER		0
69be937f1fSAlexandr Smirnov #define MII_M1111_FIBER			1
70be937f1fSAlexandr Smirnov 
71c477d044SCyril Chemparathy #define MII_88E1121_PHY_MSCR_PAGE	2
72c477d044SCyril Chemparathy #define MII_88E1121_PHY_MSCR_REG	21
73c477d044SCyril Chemparathy #define MII_88E1121_PHY_MSCR_RX_DELAY	BIT(5)
74c477d044SCyril Chemparathy #define MII_88E1121_PHY_MSCR_TX_DELAY	BIT(4)
75c477d044SCyril Chemparathy #define MII_88E1121_PHY_MSCR_DELAY_MASK	(~(0x3 << 4))
76c477d044SCyril Chemparathy 
77337ac9d5SCyril Chemparathy #define MII_88E1318S_PHY_MSCR1_REG	16
78337ac9d5SCyril Chemparathy #define MII_88E1318S_PHY_MSCR1_PAD_ODD	BIT(6)
793ff1c259SCyril Chemparathy 
80140bc929SSergei Poselenov #define MII_88E1121_PHY_LED_CTRL	16
81140bc929SSergei Poselenov #define MII_88E1121_PHY_LED_PAGE	3
82140bc929SSergei Poselenov #define MII_88E1121_PHY_LED_DEF		0x0030
83140bc929SSergei Poselenov #define MII_88E1121_PHY_PAGE		22
84140bc929SSergei Poselenov 
85be937f1fSAlexandr Smirnov #define MII_M1011_PHY_STATUS		0x11
86be937f1fSAlexandr Smirnov #define MII_M1011_PHY_STATUS_1000	0x8000
87be937f1fSAlexandr Smirnov #define MII_M1011_PHY_STATUS_100	0x4000
88be937f1fSAlexandr Smirnov #define MII_M1011_PHY_STATUS_SPD_MASK	0xc000
89be937f1fSAlexandr Smirnov #define MII_M1011_PHY_STATUS_FULLDUPLEX	0x2000
90be937f1fSAlexandr Smirnov #define MII_M1011_PHY_STATUS_RESOLVED	0x0800
91be937f1fSAlexandr Smirnov #define MII_M1011_PHY_STATUS_LINK	0x0400
92be937f1fSAlexandr Smirnov 
9376884679SAndy Fleming 
9400db8189SAndy Fleming MODULE_DESCRIPTION("Marvell PHY driver");
9500db8189SAndy Fleming MODULE_AUTHOR("Andy Fleming");
9600db8189SAndy Fleming MODULE_LICENSE("GPL");
9700db8189SAndy Fleming 
9800db8189SAndy Fleming static int marvell_ack_interrupt(struct phy_device *phydev)
9900db8189SAndy Fleming {
10000db8189SAndy Fleming 	int err;
10100db8189SAndy Fleming 
10200db8189SAndy Fleming 	/* Clear the interrupts by reading the reg */
10300db8189SAndy Fleming 	err = phy_read(phydev, MII_M1011_IEVENT);
10400db8189SAndy Fleming 
10500db8189SAndy Fleming 	if (err < 0)
10600db8189SAndy Fleming 		return err;
10700db8189SAndy Fleming 
10800db8189SAndy Fleming 	return 0;
10900db8189SAndy Fleming }
11000db8189SAndy Fleming 
11100db8189SAndy Fleming static int marvell_config_intr(struct phy_device *phydev)
11200db8189SAndy Fleming {
11300db8189SAndy Fleming 	int err;
11400db8189SAndy Fleming 
11500db8189SAndy Fleming 	if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
11600db8189SAndy Fleming 		err = phy_write(phydev, MII_M1011_IMASK, MII_M1011_IMASK_INIT);
11700db8189SAndy Fleming 	else
11800db8189SAndy Fleming 		err = phy_write(phydev, MII_M1011_IMASK, MII_M1011_IMASK_CLEAR);
11900db8189SAndy Fleming 
12000db8189SAndy Fleming 	return err;
12100db8189SAndy Fleming }
12200db8189SAndy Fleming 
12300db8189SAndy Fleming static int marvell_config_aneg(struct phy_device *phydev)
12400db8189SAndy Fleming {
12500db8189SAndy Fleming 	int err;
12600db8189SAndy Fleming 
12700db8189SAndy Fleming 	/* The Marvell PHY has an errata which requires
12800db8189SAndy Fleming 	 * that certain registers get written in order
12900db8189SAndy Fleming 	 * to restart autonegotiation */
13000db8189SAndy Fleming 	err = phy_write(phydev, MII_BMCR, BMCR_RESET);
13100db8189SAndy Fleming 
13200db8189SAndy Fleming 	if (err < 0)
13300db8189SAndy Fleming 		return err;
13400db8189SAndy Fleming 
13500db8189SAndy Fleming 	err = phy_write(phydev, 0x1d, 0x1f);
13600db8189SAndy Fleming 	if (err < 0)
13700db8189SAndy Fleming 		return err;
13800db8189SAndy Fleming 
13900db8189SAndy Fleming 	err = phy_write(phydev, 0x1e, 0x200c);
14000db8189SAndy Fleming 	if (err < 0)
14100db8189SAndy Fleming 		return err;
14200db8189SAndy Fleming 
14300db8189SAndy Fleming 	err = phy_write(phydev, 0x1d, 0x5);
14400db8189SAndy Fleming 	if (err < 0)
14500db8189SAndy Fleming 		return err;
14600db8189SAndy Fleming 
14700db8189SAndy Fleming 	err = phy_write(phydev, 0x1e, 0);
14800db8189SAndy Fleming 	if (err < 0)
14900db8189SAndy Fleming 		return err;
15000db8189SAndy Fleming 
15100db8189SAndy Fleming 	err = phy_write(phydev, 0x1e, 0x100);
15200db8189SAndy Fleming 	if (err < 0)
15300db8189SAndy Fleming 		return err;
15400db8189SAndy Fleming 
15576884679SAndy Fleming 	err = phy_write(phydev, MII_M1011_PHY_SCR,
15676884679SAndy Fleming 			MII_M1011_PHY_SCR_AUTO_CROSS);
15776884679SAndy Fleming 	if (err < 0)
15876884679SAndy Fleming 		return err;
15976884679SAndy Fleming 
16076884679SAndy Fleming 	err = phy_write(phydev, MII_M1111_PHY_LED_CONTROL,
16176884679SAndy Fleming 			MII_M1111_PHY_LED_DIRECT);
16276884679SAndy Fleming 	if (err < 0)
16376884679SAndy Fleming 		return err;
16400db8189SAndy Fleming 
16500db8189SAndy Fleming 	err = genphy_config_aneg(phydev);
1668ff44985SAnton Vorontsov 	if (err < 0)
16700db8189SAndy Fleming 		return err;
1688ff44985SAnton Vorontsov 
1698ff44985SAnton Vorontsov 	if (phydev->autoneg != AUTONEG_ENABLE) {
1708ff44985SAnton Vorontsov 		int bmcr;
1718ff44985SAnton Vorontsov 
1728ff44985SAnton Vorontsov 		/*
1738ff44985SAnton Vorontsov 		 * A write to speed/duplex bits (that is performed by
1748ff44985SAnton Vorontsov 		 * genphy_config_aneg() call above) must be followed by
1758ff44985SAnton Vorontsov 		 * a software reset. Otherwise, the write has no effect.
1768ff44985SAnton Vorontsov 		 */
1778ff44985SAnton Vorontsov 		bmcr = phy_read(phydev, MII_BMCR);
1788ff44985SAnton Vorontsov 		if (bmcr < 0)
1798ff44985SAnton Vorontsov 			return bmcr;
1808ff44985SAnton Vorontsov 
1818ff44985SAnton Vorontsov 		err = phy_write(phydev, MII_BMCR, bmcr | BMCR_RESET);
1828ff44985SAnton Vorontsov 		if (err < 0)
1838ff44985SAnton Vorontsov 			return err;
1848ff44985SAnton Vorontsov 	}
1858ff44985SAnton Vorontsov 
1868ff44985SAnton Vorontsov 	return 0;
18700db8189SAndy Fleming }
18800db8189SAndy Fleming 
189140bc929SSergei Poselenov static int m88e1121_config_aneg(struct phy_device *phydev)
190140bc929SSergei Poselenov {
191c477d044SCyril Chemparathy 	int err, oldpage, mscr;
192c477d044SCyril Chemparathy 
193c477d044SCyril Chemparathy 	oldpage = phy_read(phydev, MII_88E1121_PHY_PAGE);
194c477d044SCyril Chemparathy 
195c477d044SCyril Chemparathy 	err = phy_write(phydev, MII_88E1121_PHY_PAGE,
196c477d044SCyril Chemparathy 			MII_88E1121_PHY_MSCR_PAGE);
197c477d044SCyril Chemparathy 	if (err < 0)
198c477d044SCyril Chemparathy 		return err;
199be8c6480SArnaud Patard 
200be8c6480SArnaud Patard 	if ((phydev->interface == PHY_INTERFACE_MODE_RGMII) ||
201be8c6480SArnaud Patard 	    (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) ||
202be8c6480SArnaud Patard 	    (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) ||
203be8c6480SArnaud Patard 	    (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)) {
204be8c6480SArnaud Patard 
205c477d044SCyril Chemparathy 		mscr = phy_read(phydev, MII_88E1121_PHY_MSCR_REG) &
206c477d044SCyril Chemparathy 			MII_88E1121_PHY_MSCR_DELAY_MASK;
207c477d044SCyril Chemparathy 
208c477d044SCyril Chemparathy 		if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)
209c477d044SCyril Chemparathy 			mscr |= (MII_88E1121_PHY_MSCR_RX_DELAY |
210c477d044SCyril Chemparathy 				 MII_88E1121_PHY_MSCR_TX_DELAY);
211c477d044SCyril Chemparathy 		else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID)
212c477d044SCyril Chemparathy 			mscr |= MII_88E1121_PHY_MSCR_RX_DELAY;
213c477d044SCyril Chemparathy 		else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)
214c477d044SCyril Chemparathy 			mscr |= MII_88E1121_PHY_MSCR_TX_DELAY;
215c477d044SCyril Chemparathy 
216c477d044SCyril Chemparathy 		err = phy_write(phydev, MII_88E1121_PHY_MSCR_REG, mscr);
217c477d044SCyril Chemparathy 		if (err < 0)
218c477d044SCyril Chemparathy 			return err;
219be8c6480SArnaud Patard 	}
220c477d044SCyril Chemparathy 
221c477d044SCyril Chemparathy 	phy_write(phydev, MII_88E1121_PHY_PAGE, oldpage);
222140bc929SSergei Poselenov 
223140bc929SSergei Poselenov 	err = phy_write(phydev, MII_BMCR, BMCR_RESET);
224140bc929SSergei Poselenov 	if (err < 0)
225140bc929SSergei Poselenov 		return err;
226140bc929SSergei Poselenov 
227140bc929SSergei Poselenov 	err = phy_write(phydev, MII_M1011_PHY_SCR,
228140bc929SSergei Poselenov 			MII_M1011_PHY_SCR_AUTO_CROSS);
229140bc929SSergei Poselenov 	if (err < 0)
230140bc929SSergei Poselenov 		return err;
231140bc929SSergei Poselenov 
232c477d044SCyril Chemparathy 	oldpage = phy_read(phydev, MII_88E1121_PHY_PAGE);
233140bc929SSergei Poselenov 
234140bc929SSergei Poselenov 	phy_write(phydev, MII_88E1121_PHY_PAGE, MII_88E1121_PHY_LED_PAGE);
235140bc929SSergei Poselenov 	phy_write(phydev, MII_88E1121_PHY_LED_CTRL, MII_88E1121_PHY_LED_DEF);
236c477d044SCyril Chemparathy 	phy_write(phydev, MII_88E1121_PHY_PAGE, oldpage);
237140bc929SSergei Poselenov 
238140bc929SSergei Poselenov 	err = genphy_config_aneg(phydev);
239140bc929SSergei Poselenov 
240140bc929SSergei Poselenov 	return err;
241140bc929SSergei Poselenov }
242140bc929SSergei Poselenov 
243337ac9d5SCyril Chemparathy static int m88e1318_config_aneg(struct phy_device *phydev)
2443ff1c259SCyril Chemparathy {
2453ff1c259SCyril Chemparathy 	int err, oldpage, mscr;
2463ff1c259SCyril Chemparathy 
2473ff1c259SCyril Chemparathy 	oldpage = phy_read(phydev, MII_88E1121_PHY_PAGE);
2483ff1c259SCyril Chemparathy 
2493ff1c259SCyril Chemparathy 	err = phy_write(phydev, MII_88E1121_PHY_PAGE,
2503ff1c259SCyril Chemparathy 			MII_88E1121_PHY_MSCR_PAGE);
2513ff1c259SCyril Chemparathy 	if (err < 0)
2523ff1c259SCyril Chemparathy 		return err;
2533ff1c259SCyril Chemparathy 
254337ac9d5SCyril Chemparathy 	mscr = phy_read(phydev, MII_88E1318S_PHY_MSCR1_REG);
255337ac9d5SCyril Chemparathy 	mscr |= MII_88E1318S_PHY_MSCR1_PAD_ODD;
2563ff1c259SCyril Chemparathy 
257337ac9d5SCyril Chemparathy 	err = phy_write(phydev, MII_88E1318S_PHY_MSCR1_REG, mscr);
2583ff1c259SCyril Chemparathy 	if (err < 0)
2593ff1c259SCyril Chemparathy 		return err;
2603ff1c259SCyril Chemparathy 
2613ff1c259SCyril Chemparathy 	err = phy_write(phydev, MII_88E1121_PHY_PAGE, oldpage);
2623ff1c259SCyril Chemparathy 	if (err < 0)
2633ff1c259SCyril Chemparathy 		return err;
2643ff1c259SCyril Chemparathy 
2653ff1c259SCyril Chemparathy 	return m88e1121_config_aneg(phydev);
2663ff1c259SCyril Chemparathy }
2673ff1c259SCyril Chemparathy 
268895ee682SKim Phillips static int m88e1111_config_init(struct phy_device *phydev)
269895ee682SKim Phillips {
270895ee682SKim Phillips 	int err;
271be937f1fSAlexandr Smirnov 	int temp;
272be937f1fSAlexandr Smirnov 
273be937f1fSAlexandr Smirnov 	/* Enable Fiber/Copper auto selection */
274be937f1fSAlexandr Smirnov 	temp = phy_read(phydev, MII_M1111_PHY_EXT_SR);
2759cf8fa43SWang Jian 	temp &= ~MII_M1111_HWCFG_FIBER_COPPER_AUTO;
276be937f1fSAlexandr Smirnov 	phy_write(phydev, MII_M1111_PHY_EXT_SR, temp);
277be937f1fSAlexandr Smirnov 
278be937f1fSAlexandr Smirnov 	temp = phy_read(phydev, MII_BMCR);
279be937f1fSAlexandr Smirnov 	temp |= BMCR_RESET;
280be937f1fSAlexandr Smirnov 	phy_write(phydev, MII_BMCR, temp);
281895ee682SKim Phillips 
282895ee682SKim Phillips 	if ((phydev->interface == PHY_INTERFACE_MODE_RGMII) ||
2839daf5a76SKim Phillips 	    (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) ||
2849daf5a76SKim Phillips 	    (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) ||
2859daf5a76SKim Phillips 	    (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)) {
286895ee682SKim Phillips 
287895ee682SKim Phillips 		temp = phy_read(phydev, MII_M1111_PHY_EXT_CR);
288895ee682SKim Phillips 		if (temp < 0)
289895ee682SKim Phillips 			return temp;
290895ee682SKim Phillips 
2919daf5a76SKim Phillips 		if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) {
292895ee682SKim Phillips 			temp |= (MII_M1111_RX_DELAY | MII_M1111_TX_DELAY);
2939daf5a76SKim Phillips 		} else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) {
2949daf5a76SKim Phillips 			temp &= ~MII_M1111_TX_DELAY;
2959daf5a76SKim Phillips 			temp |= MII_M1111_RX_DELAY;
2969daf5a76SKim Phillips 		} else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) {
2979daf5a76SKim Phillips 			temp &= ~MII_M1111_RX_DELAY;
2989daf5a76SKim Phillips 			temp |= MII_M1111_TX_DELAY;
2999daf5a76SKim Phillips 		}
300895ee682SKim Phillips 
301895ee682SKim Phillips 		err = phy_write(phydev, MII_M1111_PHY_EXT_CR, temp);
302895ee682SKim Phillips 		if (err < 0)
303895ee682SKim Phillips 			return err;
304895ee682SKim Phillips 
305895ee682SKim Phillips 		temp = phy_read(phydev, MII_M1111_PHY_EXT_SR);
306895ee682SKim Phillips 		if (temp < 0)
307895ee682SKim Phillips 			return temp;
308895ee682SKim Phillips 
309895ee682SKim Phillips 		temp &= ~(MII_M1111_HWCFG_MODE_MASK);
310be937f1fSAlexandr Smirnov 
3117239016dSWang Jian 		if (temp & MII_M1111_HWCFG_FIBER_COPPER_RES)
312be937f1fSAlexandr Smirnov 			temp |= MII_M1111_HWCFG_MODE_FIBER_RGMII;
313be937f1fSAlexandr Smirnov 		else
314be937f1fSAlexandr Smirnov 			temp |= MII_M1111_HWCFG_MODE_COPPER_RGMII;
315895ee682SKim Phillips 
316895ee682SKim Phillips 		err = phy_write(phydev, MII_M1111_PHY_EXT_SR, temp);
317895ee682SKim Phillips 		if (err < 0)
318895ee682SKim Phillips 			return err;
319895ee682SKim Phillips 	}
320895ee682SKim Phillips 
3214117b5beSKapil Juneja 	if (phydev->interface == PHY_INTERFACE_MODE_SGMII) {
3224117b5beSKapil Juneja 		temp = phy_read(phydev, MII_M1111_PHY_EXT_SR);
3234117b5beSKapil Juneja 		if (temp < 0)
3244117b5beSKapil Juneja 			return temp;
3254117b5beSKapil Juneja 
3264117b5beSKapil Juneja 		temp &= ~(MII_M1111_HWCFG_MODE_MASK);
3274117b5beSKapil Juneja 		temp |= MII_M1111_HWCFG_MODE_SGMII_NO_CLK;
32832d0c1e1SHaiying Wang 		temp |= MII_M1111_HWCFG_FIBER_COPPER_AUTO;
3294117b5beSKapil Juneja 
3304117b5beSKapil Juneja 		err = phy_write(phydev, MII_M1111_PHY_EXT_SR, temp);
3314117b5beSKapil Juneja 		if (err < 0)
3324117b5beSKapil Juneja 			return err;
3334117b5beSKapil Juneja 	}
3344117b5beSKapil Juneja 
3355f8cbc13SLiu Yu-B13201 	if (phydev->interface == PHY_INTERFACE_MODE_RTBI) {
3365f8cbc13SLiu Yu-B13201 		temp = phy_read(phydev, MII_M1111_PHY_EXT_CR);
3375f8cbc13SLiu Yu-B13201 		if (temp < 0)
3385f8cbc13SLiu Yu-B13201 			return temp;
3395f8cbc13SLiu Yu-B13201 		temp |= (MII_M1111_RX_DELAY | MII_M1111_TX_DELAY);
3405f8cbc13SLiu Yu-B13201 		err = phy_write(phydev, MII_M1111_PHY_EXT_CR, temp);
3415f8cbc13SLiu Yu-B13201 		if (err < 0)
3425f8cbc13SLiu Yu-B13201 			return err;
3435f8cbc13SLiu Yu-B13201 
3445f8cbc13SLiu Yu-B13201 		temp = phy_read(phydev, MII_M1111_PHY_EXT_SR);
3455f8cbc13SLiu Yu-B13201 		if (temp < 0)
3465f8cbc13SLiu Yu-B13201 			return temp;
3475f8cbc13SLiu Yu-B13201 		temp &= ~(MII_M1111_HWCFG_MODE_MASK | MII_M1111_HWCFG_FIBER_COPPER_RES);
3485f8cbc13SLiu Yu-B13201 		temp |= 0x7 | MII_M1111_HWCFG_FIBER_COPPER_AUTO;
3495f8cbc13SLiu Yu-B13201 		err = phy_write(phydev, MII_M1111_PHY_EXT_SR, temp);
3505f8cbc13SLiu Yu-B13201 		if (err < 0)
3515f8cbc13SLiu Yu-B13201 			return err;
3525f8cbc13SLiu Yu-B13201 
3535f8cbc13SLiu Yu-B13201 		/* soft reset */
3545f8cbc13SLiu Yu-B13201 		err = phy_write(phydev, MII_BMCR, BMCR_RESET);
3555f8cbc13SLiu Yu-B13201 		if (err < 0)
3565f8cbc13SLiu Yu-B13201 			return err;
3575f8cbc13SLiu Yu-B13201 		do
3585f8cbc13SLiu Yu-B13201 			temp = phy_read(phydev, MII_BMCR);
3595f8cbc13SLiu Yu-B13201 		while (temp & BMCR_RESET);
3605f8cbc13SLiu Yu-B13201 
3615f8cbc13SLiu Yu-B13201 		temp = phy_read(phydev, MII_M1111_PHY_EXT_SR);
3625f8cbc13SLiu Yu-B13201 		if (temp < 0)
3635f8cbc13SLiu Yu-B13201 			return temp;
3645f8cbc13SLiu Yu-B13201 		temp &= ~(MII_M1111_HWCFG_MODE_MASK | MII_M1111_HWCFG_FIBER_COPPER_RES);
3655f8cbc13SLiu Yu-B13201 		temp |= MII_M1111_HWCFG_MODE_COPPER_RTBI | MII_M1111_HWCFG_FIBER_COPPER_AUTO;
3665f8cbc13SLiu Yu-B13201 		err = phy_write(phydev, MII_M1111_PHY_EXT_SR, temp);
3675f8cbc13SLiu Yu-B13201 		if (err < 0)
3685f8cbc13SLiu Yu-B13201 			return err;
3695f8cbc13SLiu Yu-B13201 	}
3705f8cbc13SLiu Yu-B13201 
3715f8cbc13SLiu Yu-B13201 
372895ee682SKim Phillips 	err = phy_write(phydev, MII_BMCR, BMCR_RESET);
373895ee682SKim Phillips 	if (err < 0)
374895ee682SKim Phillips 		return err;
375895ee682SKim Phillips 
376895ee682SKim Phillips 	return 0;
377895ee682SKim Phillips }
378895ee682SKim Phillips 
379605f196eSRon Madrid static int m88e1118_config_aneg(struct phy_device *phydev)
380605f196eSRon Madrid {
381605f196eSRon Madrid 	int err;
382605f196eSRon Madrid 
383605f196eSRon Madrid 	err = phy_write(phydev, MII_BMCR, BMCR_RESET);
384605f196eSRon Madrid 	if (err < 0)
385605f196eSRon Madrid 		return err;
386605f196eSRon Madrid 
387605f196eSRon Madrid 	err = phy_write(phydev, MII_M1011_PHY_SCR,
388605f196eSRon Madrid 			MII_M1011_PHY_SCR_AUTO_CROSS);
389605f196eSRon Madrid 	if (err < 0)
390605f196eSRon Madrid 		return err;
391605f196eSRon Madrid 
392605f196eSRon Madrid 	err = genphy_config_aneg(phydev);
393605f196eSRon Madrid 	return 0;
394605f196eSRon Madrid }
395605f196eSRon Madrid 
396605f196eSRon Madrid static int m88e1118_config_init(struct phy_device *phydev)
397605f196eSRon Madrid {
398605f196eSRon Madrid 	int err;
399605f196eSRon Madrid 
400605f196eSRon Madrid 	/* Change address */
401605f196eSRon Madrid 	err = phy_write(phydev, 0x16, 0x0002);
402605f196eSRon Madrid 	if (err < 0)
403605f196eSRon Madrid 		return err;
404605f196eSRon Madrid 
405605f196eSRon Madrid 	/* Enable 1000 Mbit */
406605f196eSRon Madrid 	err = phy_write(phydev, 0x15, 0x1070);
407605f196eSRon Madrid 	if (err < 0)
408605f196eSRon Madrid 		return err;
409605f196eSRon Madrid 
410605f196eSRon Madrid 	/* Change address */
411605f196eSRon Madrid 	err = phy_write(phydev, 0x16, 0x0003);
412605f196eSRon Madrid 	if (err < 0)
413605f196eSRon Madrid 		return err;
414605f196eSRon Madrid 
415605f196eSRon Madrid 	/* Adjust LED Control */
4162f495c39SBenjamin Herrenschmidt 	if (phydev->dev_flags & MARVELL_PHY_M1118_DNS323_LEDS)
4172f495c39SBenjamin Herrenschmidt 		err = phy_write(phydev, 0x10, 0x1100);
4182f495c39SBenjamin Herrenschmidt 	else
419605f196eSRon Madrid 		err = phy_write(phydev, 0x10, 0x021e);
420605f196eSRon Madrid 	if (err < 0)
421605f196eSRon Madrid 		return err;
422605f196eSRon Madrid 
423605f196eSRon Madrid 	/* Reset address */
424605f196eSRon Madrid 	err = phy_write(phydev, 0x16, 0x0);
425605f196eSRon Madrid 	if (err < 0)
426605f196eSRon Madrid 		return err;
427605f196eSRon Madrid 
428605f196eSRon Madrid 	err = phy_write(phydev, MII_BMCR, BMCR_RESET);
429605f196eSRon Madrid 	if (err < 0)
430605f196eSRon Madrid 		return err;
431605f196eSRon Madrid 
432605f196eSRon Madrid 	return 0;
433605f196eSRon Madrid }
434605f196eSRon Madrid 
43576884679SAndy Fleming static int m88e1145_config_init(struct phy_device *phydev)
43676884679SAndy Fleming {
43776884679SAndy Fleming 	int err;
43876884679SAndy Fleming 
43976884679SAndy Fleming 	/* Take care of errata E0 & E1 */
44076884679SAndy Fleming 	err = phy_write(phydev, 0x1d, 0x001b);
44176884679SAndy Fleming 	if (err < 0)
44276884679SAndy Fleming 		return err;
44376884679SAndy Fleming 
44476884679SAndy Fleming 	err = phy_write(phydev, 0x1e, 0x418f);
44576884679SAndy Fleming 	if (err < 0)
44676884679SAndy Fleming 		return err;
44776884679SAndy Fleming 
44876884679SAndy Fleming 	err = phy_write(phydev, 0x1d, 0x0016);
44976884679SAndy Fleming 	if (err < 0)
45076884679SAndy Fleming 		return err;
45176884679SAndy Fleming 
45276884679SAndy Fleming 	err = phy_write(phydev, 0x1e, 0xa2da);
45376884679SAndy Fleming 	if (err < 0)
45476884679SAndy Fleming 		return err;
45576884679SAndy Fleming 
456895ee682SKim Phillips 	if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) {
45776884679SAndy Fleming 		int temp = phy_read(phydev, MII_M1145_PHY_EXT_CR);
45876884679SAndy Fleming 		if (temp < 0)
45976884679SAndy Fleming 			return temp;
46076884679SAndy Fleming 
46176884679SAndy Fleming 		temp |= (MII_M1145_RGMII_RX_DELAY | MII_M1145_RGMII_TX_DELAY);
46276884679SAndy Fleming 
46376884679SAndy Fleming 		err = phy_write(phydev, MII_M1145_PHY_EXT_CR, temp);
46476884679SAndy Fleming 		if (err < 0)
46576884679SAndy Fleming 			return err;
46676884679SAndy Fleming 
4672f495c39SBenjamin Herrenschmidt 		if (phydev->dev_flags & MARVELL_PHY_M1145_FLAGS_RESISTANCE) {
46876884679SAndy Fleming 			err = phy_write(phydev, 0x1d, 0x0012);
46976884679SAndy Fleming 			if (err < 0)
47076884679SAndy Fleming 				return err;
47176884679SAndy Fleming 
47276884679SAndy Fleming 			temp = phy_read(phydev, 0x1e);
47376884679SAndy Fleming 			if (temp < 0)
47476884679SAndy Fleming 				return temp;
47576884679SAndy Fleming 
47676884679SAndy Fleming 			temp &= 0xf03f;
47776884679SAndy Fleming 			temp |= 2 << 9;	/* 36 ohm */
47876884679SAndy Fleming 			temp |= 2 << 6;	/* 39 ohm */
47976884679SAndy Fleming 
48076884679SAndy Fleming 			err = phy_write(phydev, 0x1e, temp);
48176884679SAndy Fleming 			if (err < 0)
48276884679SAndy Fleming 				return err;
48376884679SAndy Fleming 
48476884679SAndy Fleming 			err = phy_write(phydev, 0x1d, 0x3);
48576884679SAndy Fleming 			if (err < 0)
48676884679SAndy Fleming 				return err;
48776884679SAndy Fleming 
48876884679SAndy Fleming 			err = phy_write(phydev, 0x1e, 0x8000);
48976884679SAndy Fleming 			if (err < 0)
49076884679SAndy Fleming 				return err;
49176884679SAndy Fleming 		}
49276884679SAndy Fleming 	}
49376884679SAndy Fleming 
49476884679SAndy Fleming 	return 0;
49576884679SAndy Fleming }
49600db8189SAndy Fleming 
497be937f1fSAlexandr Smirnov /* marvell_read_status
498be937f1fSAlexandr Smirnov  *
499be937f1fSAlexandr Smirnov  * Generic status code does not detect Fiber correctly!
500be937f1fSAlexandr Smirnov  * Description:
501be937f1fSAlexandr Smirnov  *   Check the link, then figure out the current state
502be937f1fSAlexandr Smirnov  *   by comparing what we advertise with what the link partner
503be937f1fSAlexandr Smirnov  *   advertises.  Start by checking the gigabit possibilities,
504be937f1fSAlexandr Smirnov  *   then move on to 10/100.
505be937f1fSAlexandr Smirnov  */
506be937f1fSAlexandr Smirnov static int marvell_read_status(struct phy_device *phydev)
507be937f1fSAlexandr Smirnov {
508be937f1fSAlexandr Smirnov 	int adv;
509be937f1fSAlexandr Smirnov 	int err;
510be937f1fSAlexandr Smirnov 	int lpa;
511be937f1fSAlexandr Smirnov 	int status = 0;
512be937f1fSAlexandr Smirnov 
513be937f1fSAlexandr Smirnov 	/* Update the link, but return if there
514be937f1fSAlexandr Smirnov 	 * was an error */
515be937f1fSAlexandr Smirnov 	err = genphy_update_link(phydev);
516be937f1fSAlexandr Smirnov 	if (err)
517be937f1fSAlexandr Smirnov 		return err;
518be937f1fSAlexandr Smirnov 
519be937f1fSAlexandr Smirnov 	if (AUTONEG_ENABLE == phydev->autoneg) {
520be937f1fSAlexandr Smirnov 		status = phy_read(phydev, MII_M1011_PHY_STATUS);
521be937f1fSAlexandr Smirnov 		if (status < 0)
522be937f1fSAlexandr Smirnov 			return status;
523be937f1fSAlexandr Smirnov 
524be937f1fSAlexandr Smirnov 		lpa = phy_read(phydev, MII_LPA);
525be937f1fSAlexandr Smirnov 		if (lpa < 0)
526be937f1fSAlexandr Smirnov 			return lpa;
527be937f1fSAlexandr Smirnov 
528be937f1fSAlexandr Smirnov 		adv = phy_read(phydev, MII_ADVERTISE);
529be937f1fSAlexandr Smirnov 		if (adv < 0)
530be937f1fSAlexandr Smirnov 			return adv;
531be937f1fSAlexandr Smirnov 
532be937f1fSAlexandr Smirnov 		lpa &= adv;
533be937f1fSAlexandr Smirnov 
534be937f1fSAlexandr Smirnov 		if (status & MII_M1011_PHY_STATUS_FULLDUPLEX)
535be937f1fSAlexandr Smirnov 			phydev->duplex = DUPLEX_FULL;
536be937f1fSAlexandr Smirnov 		else
537be937f1fSAlexandr Smirnov 			phydev->duplex = DUPLEX_HALF;
538be937f1fSAlexandr Smirnov 
539be937f1fSAlexandr Smirnov 		status = status & MII_M1011_PHY_STATUS_SPD_MASK;
540be937f1fSAlexandr Smirnov 		phydev->pause = phydev->asym_pause = 0;
541be937f1fSAlexandr Smirnov 
542be937f1fSAlexandr Smirnov 		switch (status) {
543be937f1fSAlexandr Smirnov 		case MII_M1011_PHY_STATUS_1000:
544be937f1fSAlexandr Smirnov 			phydev->speed = SPEED_1000;
545be937f1fSAlexandr Smirnov 			break;
546be937f1fSAlexandr Smirnov 
547be937f1fSAlexandr Smirnov 		case MII_M1011_PHY_STATUS_100:
548be937f1fSAlexandr Smirnov 			phydev->speed = SPEED_100;
549be937f1fSAlexandr Smirnov 			break;
550be937f1fSAlexandr Smirnov 
551be937f1fSAlexandr Smirnov 		default:
552be937f1fSAlexandr Smirnov 			phydev->speed = SPEED_10;
553be937f1fSAlexandr Smirnov 			break;
554be937f1fSAlexandr Smirnov 		}
555be937f1fSAlexandr Smirnov 
556be937f1fSAlexandr Smirnov 		if (phydev->duplex == DUPLEX_FULL) {
557be937f1fSAlexandr Smirnov 			phydev->pause = lpa & LPA_PAUSE_CAP ? 1 : 0;
558be937f1fSAlexandr Smirnov 			phydev->asym_pause = lpa & LPA_PAUSE_ASYM ? 1 : 0;
559be937f1fSAlexandr Smirnov 		}
560be937f1fSAlexandr Smirnov 	} else {
561be937f1fSAlexandr Smirnov 		int bmcr = phy_read(phydev, MII_BMCR);
562be937f1fSAlexandr Smirnov 
563be937f1fSAlexandr Smirnov 		if (bmcr < 0)
564be937f1fSAlexandr Smirnov 			return bmcr;
565be937f1fSAlexandr Smirnov 
566be937f1fSAlexandr Smirnov 		if (bmcr & BMCR_FULLDPLX)
567be937f1fSAlexandr Smirnov 			phydev->duplex = DUPLEX_FULL;
568be937f1fSAlexandr Smirnov 		else
569be937f1fSAlexandr Smirnov 			phydev->duplex = DUPLEX_HALF;
570be937f1fSAlexandr Smirnov 
571be937f1fSAlexandr Smirnov 		if (bmcr & BMCR_SPEED1000)
572be937f1fSAlexandr Smirnov 			phydev->speed = SPEED_1000;
573be937f1fSAlexandr Smirnov 		else if (bmcr & BMCR_SPEED100)
574be937f1fSAlexandr Smirnov 			phydev->speed = SPEED_100;
575be937f1fSAlexandr Smirnov 		else
576be937f1fSAlexandr Smirnov 			phydev->speed = SPEED_10;
577be937f1fSAlexandr Smirnov 
578be937f1fSAlexandr Smirnov 		phydev->pause = phydev->asym_pause = 0;
579be937f1fSAlexandr Smirnov 	}
580be937f1fSAlexandr Smirnov 
581be937f1fSAlexandr Smirnov 	return 0;
582be937f1fSAlexandr Smirnov }
583be937f1fSAlexandr Smirnov 
584dcd07be3SAnatolij Gustschin static int m88e1121_did_interrupt(struct phy_device *phydev)
585dcd07be3SAnatolij Gustschin {
586dcd07be3SAnatolij Gustschin 	int imask;
587dcd07be3SAnatolij Gustschin 
588dcd07be3SAnatolij Gustschin 	imask = phy_read(phydev, MII_M1011_IEVENT);
589dcd07be3SAnatolij Gustschin 
590dcd07be3SAnatolij Gustschin 	if (imask & MII_M1011_IMASK_INIT)
591dcd07be3SAnatolij Gustschin 		return 1;
592dcd07be3SAnatolij Gustschin 
593dcd07be3SAnatolij Gustschin 	return 0;
594dcd07be3SAnatolij Gustschin }
595dcd07be3SAnatolij Gustschin 
596e5479239SOlof Johansson static struct phy_driver marvell_drivers[] = {
597e5479239SOlof Johansson 	{
5982f495c39SBenjamin Herrenschmidt 		.phy_id = MARVELL_PHY_ID_88E1101,
5992f495c39SBenjamin Herrenschmidt 		.phy_id_mask = MARVELL_PHY_ID_MASK,
60000db8189SAndy Fleming 		.name = "Marvell 88E1101",
60100db8189SAndy Fleming 		.features = PHY_GBIT_FEATURES,
60200db8189SAndy Fleming 		.flags = PHY_HAS_INTERRUPT,
60300db8189SAndy Fleming 		.config_aneg = &marvell_config_aneg,
60400db8189SAndy Fleming 		.read_status = &genphy_read_status,
60500db8189SAndy Fleming 		.ack_interrupt = &marvell_ack_interrupt,
60600db8189SAndy Fleming 		.config_intr = &marvell_config_intr,
607ac8c635aSOlof Johansson 		.driver = { .owner = THIS_MODULE },
608e5479239SOlof Johansson 	},
609e5479239SOlof Johansson 	{
6102f495c39SBenjamin Herrenschmidt 		.phy_id = MARVELL_PHY_ID_88E1112,
6112f495c39SBenjamin Herrenschmidt 		.phy_id_mask = MARVELL_PHY_ID_MASK,
61285cfb534SOlof Johansson 		.name = "Marvell 88E1112",
61385cfb534SOlof Johansson 		.features = PHY_GBIT_FEATURES,
61485cfb534SOlof Johansson 		.flags = PHY_HAS_INTERRUPT,
61585cfb534SOlof Johansson 		.config_init = &m88e1111_config_init,
61685cfb534SOlof Johansson 		.config_aneg = &marvell_config_aneg,
61785cfb534SOlof Johansson 		.read_status = &genphy_read_status,
61885cfb534SOlof Johansson 		.ack_interrupt = &marvell_ack_interrupt,
61985cfb534SOlof Johansson 		.config_intr = &marvell_config_intr,
620ac8c635aSOlof Johansson 		.driver = { .owner = THIS_MODULE },
62185cfb534SOlof Johansson 	},
62285cfb534SOlof Johansson 	{
6232f495c39SBenjamin Herrenschmidt 		.phy_id = MARVELL_PHY_ID_88E1111,
6242f495c39SBenjamin Herrenschmidt 		.phy_id_mask = MARVELL_PHY_ID_MASK,
62576884679SAndy Fleming 		.name = "Marvell 88E1111",
62676884679SAndy Fleming 		.features = PHY_GBIT_FEATURES,
62776884679SAndy Fleming 		.flags = PHY_HAS_INTERRUPT,
628e5479239SOlof Johansson 		.config_init = &m88e1111_config_init,
62976884679SAndy Fleming 		.config_aneg = &marvell_config_aneg,
630be937f1fSAlexandr Smirnov 		.read_status = &marvell_read_status,
63176884679SAndy Fleming 		.ack_interrupt = &marvell_ack_interrupt,
63276884679SAndy Fleming 		.config_intr = &marvell_config_intr,
633ac8c635aSOlof Johansson 		.driver = { .owner = THIS_MODULE },
634e5479239SOlof Johansson 	},
635e5479239SOlof Johansson 	{
6362f495c39SBenjamin Herrenschmidt 		.phy_id = MARVELL_PHY_ID_88E1118,
6372f495c39SBenjamin Herrenschmidt 		.phy_id_mask = MARVELL_PHY_ID_MASK,
638605f196eSRon Madrid 		.name = "Marvell 88E1118",
639605f196eSRon Madrid 		.features = PHY_GBIT_FEATURES,
640605f196eSRon Madrid 		.flags = PHY_HAS_INTERRUPT,
641605f196eSRon Madrid 		.config_init = &m88e1118_config_init,
642605f196eSRon Madrid 		.config_aneg = &m88e1118_config_aneg,
643605f196eSRon Madrid 		.read_status = &genphy_read_status,
644605f196eSRon Madrid 		.ack_interrupt = &marvell_ack_interrupt,
645605f196eSRon Madrid 		.config_intr = &marvell_config_intr,
646605f196eSRon Madrid 		.driver = {.owner = THIS_MODULE,},
647605f196eSRon Madrid 	},
648605f196eSRon Madrid 	{
6492f495c39SBenjamin Herrenschmidt 		.phy_id = MARVELL_PHY_ID_88E1121R,
6502f495c39SBenjamin Herrenschmidt 		.phy_id_mask = MARVELL_PHY_ID_MASK,
651140bc929SSergei Poselenov 		.name = "Marvell 88E1121R",
652140bc929SSergei Poselenov 		.features = PHY_GBIT_FEATURES,
653140bc929SSergei Poselenov 		.flags = PHY_HAS_INTERRUPT,
654140bc929SSergei Poselenov 		.config_aneg = &m88e1121_config_aneg,
655140bc929SSergei Poselenov 		.read_status = &marvell_read_status,
656140bc929SSergei Poselenov 		.ack_interrupt = &marvell_ack_interrupt,
657140bc929SSergei Poselenov 		.config_intr = &marvell_config_intr,
658dcd07be3SAnatolij Gustschin 		.did_interrupt = &m88e1121_did_interrupt,
659140bc929SSergei Poselenov 		.driver = { .owner = THIS_MODULE },
660140bc929SSergei Poselenov 	},
661140bc929SSergei Poselenov 	{
662337ac9d5SCyril Chemparathy 		.phy_id = MARVELL_PHY_ID_88E1318S,
6636ba74014SLinus Torvalds 		.phy_id_mask = MARVELL_PHY_ID_MASK,
664337ac9d5SCyril Chemparathy 		.name = "Marvell 88E1318S",
6653ff1c259SCyril Chemparathy 		.features = PHY_GBIT_FEATURES,
6663ff1c259SCyril Chemparathy 		.flags = PHY_HAS_INTERRUPT,
667337ac9d5SCyril Chemparathy 		.config_aneg = &m88e1318_config_aneg,
6683ff1c259SCyril Chemparathy 		.read_status = &marvell_read_status,
6693ff1c259SCyril Chemparathy 		.ack_interrupt = &marvell_ack_interrupt,
6703ff1c259SCyril Chemparathy 		.config_intr = &marvell_config_intr,
6713ff1c259SCyril Chemparathy 		.did_interrupt = &m88e1121_did_interrupt,
6723ff1c259SCyril Chemparathy 		.driver = { .owner = THIS_MODULE },
6733ff1c259SCyril Chemparathy 	},
6743ff1c259SCyril Chemparathy 	{
6752f495c39SBenjamin Herrenschmidt 		.phy_id = MARVELL_PHY_ID_88E1145,
6762f495c39SBenjamin Herrenschmidt 		.phy_id_mask = MARVELL_PHY_ID_MASK,
67776884679SAndy Fleming 		.name = "Marvell 88E1145",
67876884679SAndy Fleming 		.features = PHY_GBIT_FEATURES,
67976884679SAndy Fleming 		.flags = PHY_HAS_INTERRUPT,
68076884679SAndy Fleming 		.config_init = &m88e1145_config_init,
68176884679SAndy Fleming 		.config_aneg = &marvell_config_aneg,
68276884679SAndy Fleming 		.read_status = &genphy_read_status,
68376884679SAndy Fleming 		.ack_interrupt = &marvell_ack_interrupt,
68476884679SAndy Fleming 		.config_intr = &marvell_config_intr,
685ac8c635aSOlof Johansson 		.driver = { .owner = THIS_MODULE },
686ac8c635aSOlof Johansson 	},
687ac8c635aSOlof Johansson 	{
6882f495c39SBenjamin Herrenschmidt 		.phy_id = MARVELL_PHY_ID_88E1240,
6892f495c39SBenjamin Herrenschmidt 		.phy_id_mask = MARVELL_PHY_ID_MASK,
690ac8c635aSOlof Johansson 		.name = "Marvell 88E1240",
691ac8c635aSOlof Johansson 		.features = PHY_GBIT_FEATURES,
692ac8c635aSOlof Johansson 		.flags = PHY_HAS_INTERRUPT,
693ac8c635aSOlof Johansson 		.config_init = &m88e1111_config_init,
694ac8c635aSOlof Johansson 		.config_aneg = &marvell_config_aneg,
695ac8c635aSOlof Johansson 		.read_status = &genphy_read_status,
696ac8c635aSOlof Johansson 		.ack_interrupt = &marvell_ack_interrupt,
697ac8c635aSOlof Johansson 		.config_intr = &marvell_config_intr,
698ac8c635aSOlof Johansson 		.driver = { .owner = THIS_MODULE },
699ac8c635aSOlof Johansson 	},
70076884679SAndy Fleming };
70176884679SAndy Fleming 
70200db8189SAndy Fleming static int __init marvell_init(void)
70300db8189SAndy Fleming {
70476884679SAndy Fleming 	int ret;
705e5479239SOlof Johansson 	int i;
70676884679SAndy Fleming 
707e5479239SOlof Johansson 	for (i = 0; i < ARRAY_SIZE(marvell_drivers); i++) {
708e5479239SOlof Johansson 		ret = phy_driver_register(&marvell_drivers[i]);
709e5479239SOlof Johansson 
710e5479239SOlof Johansson 		if (ret) {
711e5479239SOlof Johansson 			while (i-- > 0)
712e5479239SOlof Johansson 				phy_driver_unregister(&marvell_drivers[i]);
71376884679SAndy Fleming 			return ret;
714e5479239SOlof Johansson 		}
715e5479239SOlof Johansson 	}
71676884679SAndy Fleming 
71776884679SAndy Fleming 	return 0;
71800db8189SAndy Fleming }
71900db8189SAndy Fleming 
72000db8189SAndy Fleming static void __exit marvell_exit(void)
72100db8189SAndy Fleming {
722e5479239SOlof Johansson 	int i;
723e5479239SOlof Johansson 
724e5479239SOlof Johansson 	for (i = 0; i < ARRAY_SIZE(marvell_drivers); i++)
725e5479239SOlof Johansson 		phy_driver_unregister(&marvell_drivers[i]);
72600db8189SAndy Fleming }
72700db8189SAndy Fleming 
72800db8189SAndy Fleming module_init(marvell_init);
72900db8189SAndy Fleming module_exit(marvell_exit);
7304e4f10f6SDavid Woodhouse 
731cf93c945SUwe Kleine-König static struct mdio_device_id __maybe_unused marvell_tbl[] = {
7324e4f10f6SDavid Woodhouse 	{ 0x01410c60, 0xfffffff0 },
7334e4f10f6SDavid Woodhouse 	{ 0x01410c90, 0xfffffff0 },
7344e4f10f6SDavid Woodhouse 	{ 0x01410cc0, 0xfffffff0 },
7354e4f10f6SDavid Woodhouse 	{ 0x01410e10, 0xfffffff0 },
7364e4f10f6SDavid Woodhouse 	{ 0x01410cb0, 0xfffffff0 },
7374e4f10f6SDavid Woodhouse 	{ 0x01410cd0, 0xfffffff0 },
7384e4f10f6SDavid Woodhouse 	{ 0x01410e30, 0xfffffff0 },
7393ff1c259SCyril Chemparathy 	{ 0x01410e90, 0xfffffff0 },
7404e4f10f6SDavid Woodhouse 	{ }
7414e4f10f6SDavid Woodhouse };
7424e4f10f6SDavid Woodhouse 
7434e4f10f6SDavid Woodhouse MODULE_DEVICE_TABLE(mdio, marvell_tbl);
744