xref: /openbmc/linux/drivers/net/phy/marvell.c (revision cc90cb3b)
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>
33cf41a51dSDavid Daney #include <linux/of.h>
3400db8189SAndy Fleming 
3500db8189SAndy Fleming #include <asm/io.h>
3600db8189SAndy Fleming #include <asm/irq.h>
3700db8189SAndy Fleming #include <asm/uaccess.h>
3800db8189SAndy Fleming 
3927d916d6SDavid Daney #define MII_MARVELL_PHY_PAGE		22
4027d916d6SDavid Daney 
4100db8189SAndy Fleming #define MII_M1011_IEVENT		0x13
4200db8189SAndy Fleming #define MII_M1011_IEVENT_CLEAR		0x0000
4300db8189SAndy Fleming 
4400db8189SAndy Fleming #define MII_M1011_IMASK			0x12
4500db8189SAndy Fleming #define MII_M1011_IMASK_INIT		0x6400
4600db8189SAndy Fleming #define MII_M1011_IMASK_CLEAR		0x0000
4700db8189SAndy Fleming 
4876884679SAndy Fleming #define MII_M1011_PHY_SCR		0x10
4976884679SAndy Fleming #define MII_M1011_PHY_SCR_AUTO_CROSS	0x0060
5076884679SAndy Fleming 
5176884679SAndy Fleming #define MII_M1145_PHY_EXT_CR		0x14
5276884679SAndy Fleming #define MII_M1145_RGMII_RX_DELAY	0x0080
5376884679SAndy Fleming #define MII_M1145_RGMII_TX_DELAY	0x0002
5476884679SAndy Fleming 
5576884679SAndy Fleming #define MII_M1111_PHY_LED_CONTROL	0x18
5676884679SAndy Fleming #define MII_M1111_PHY_LED_DIRECT	0x4100
5776884679SAndy Fleming #define MII_M1111_PHY_LED_COMBINE	0x411c
58895ee682SKim Phillips #define MII_M1111_PHY_EXT_CR		0x14
59895ee682SKim Phillips #define MII_M1111_RX_DELAY		0x80
60895ee682SKim Phillips #define MII_M1111_TX_DELAY		0x2
61895ee682SKim Phillips #define MII_M1111_PHY_EXT_SR		0x1b
62be937f1fSAlexandr Smirnov 
63895ee682SKim Phillips #define MII_M1111_HWCFG_MODE_MASK		0xf
64be937f1fSAlexandr Smirnov #define MII_M1111_HWCFG_MODE_COPPER_RGMII	0xb
65be937f1fSAlexandr Smirnov #define MII_M1111_HWCFG_MODE_FIBER_RGMII	0x3
664117b5beSKapil Juneja #define MII_M1111_HWCFG_MODE_SGMII_NO_CLK	0x4
675f8cbc13SLiu Yu-B13201 #define MII_M1111_HWCFG_MODE_COPPER_RTBI	0x9
68be937f1fSAlexandr Smirnov #define MII_M1111_HWCFG_FIBER_COPPER_AUTO	0x8000
69be937f1fSAlexandr Smirnov #define MII_M1111_HWCFG_FIBER_COPPER_RES	0x2000
70be937f1fSAlexandr Smirnov 
71be937f1fSAlexandr Smirnov #define MII_M1111_COPPER		0
72be937f1fSAlexandr Smirnov #define MII_M1111_FIBER			1
73be937f1fSAlexandr Smirnov 
74c477d044SCyril Chemparathy #define MII_88E1121_PHY_MSCR_PAGE	2
75c477d044SCyril Chemparathy #define MII_88E1121_PHY_MSCR_REG	21
76c477d044SCyril Chemparathy #define MII_88E1121_PHY_MSCR_RX_DELAY	BIT(5)
77c477d044SCyril Chemparathy #define MII_88E1121_PHY_MSCR_TX_DELAY	BIT(4)
78c477d044SCyril Chemparathy #define MII_88E1121_PHY_MSCR_DELAY_MASK	(~(0x3 << 4))
79c477d044SCyril Chemparathy 
80337ac9d5SCyril Chemparathy #define MII_88E1318S_PHY_MSCR1_REG	16
81337ac9d5SCyril Chemparathy #define MII_88E1318S_PHY_MSCR1_PAD_ODD	BIT(6)
823ff1c259SCyril Chemparathy 
83140bc929SSergei Poselenov #define MII_88E1121_PHY_LED_CTRL	16
84140bc929SSergei Poselenov #define MII_88E1121_PHY_LED_PAGE	3
85140bc929SSergei Poselenov #define MII_88E1121_PHY_LED_DEF		0x0030
86140bc929SSergei Poselenov 
87be937f1fSAlexandr Smirnov #define MII_M1011_PHY_STATUS		0x11
88be937f1fSAlexandr Smirnov #define MII_M1011_PHY_STATUS_1000	0x8000
89be937f1fSAlexandr Smirnov #define MII_M1011_PHY_STATUS_100	0x4000
90be937f1fSAlexandr Smirnov #define MII_M1011_PHY_STATUS_SPD_MASK	0xc000
91be937f1fSAlexandr Smirnov #define MII_M1011_PHY_STATUS_FULLDUPLEX	0x2000
92be937f1fSAlexandr Smirnov #define MII_M1011_PHY_STATUS_RESOLVED	0x0800
93be937f1fSAlexandr Smirnov #define MII_M1011_PHY_STATUS_LINK	0x0400
94be937f1fSAlexandr Smirnov 
9576884679SAndy Fleming 
9600db8189SAndy Fleming MODULE_DESCRIPTION("Marvell PHY driver");
9700db8189SAndy Fleming MODULE_AUTHOR("Andy Fleming");
9800db8189SAndy Fleming MODULE_LICENSE("GPL");
9900db8189SAndy Fleming 
10000db8189SAndy Fleming static int marvell_ack_interrupt(struct phy_device *phydev)
10100db8189SAndy Fleming {
10200db8189SAndy Fleming 	int err;
10300db8189SAndy Fleming 
10400db8189SAndy Fleming 	/* Clear the interrupts by reading the reg */
10500db8189SAndy Fleming 	err = phy_read(phydev, MII_M1011_IEVENT);
10600db8189SAndy Fleming 
10700db8189SAndy Fleming 	if (err < 0)
10800db8189SAndy Fleming 		return err;
10900db8189SAndy Fleming 
11000db8189SAndy Fleming 	return 0;
11100db8189SAndy Fleming }
11200db8189SAndy Fleming 
11300db8189SAndy Fleming static int marvell_config_intr(struct phy_device *phydev)
11400db8189SAndy Fleming {
11500db8189SAndy Fleming 	int err;
11600db8189SAndy Fleming 
11700db8189SAndy Fleming 	if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
11800db8189SAndy Fleming 		err = phy_write(phydev, MII_M1011_IMASK, MII_M1011_IMASK_INIT);
11900db8189SAndy Fleming 	else
12000db8189SAndy Fleming 		err = phy_write(phydev, MII_M1011_IMASK, MII_M1011_IMASK_CLEAR);
12100db8189SAndy Fleming 
12200db8189SAndy Fleming 	return err;
12300db8189SAndy Fleming }
12400db8189SAndy Fleming 
12500db8189SAndy Fleming static int marvell_config_aneg(struct phy_device *phydev)
12600db8189SAndy Fleming {
12700db8189SAndy Fleming 	int err;
12800db8189SAndy Fleming 
12900db8189SAndy Fleming 	/* The Marvell PHY has an errata which requires
13000db8189SAndy Fleming 	 * that certain registers get written in order
13100db8189SAndy Fleming 	 * to restart autonegotiation */
13200db8189SAndy Fleming 	err = phy_write(phydev, MII_BMCR, BMCR_RESET);
13300db8189SAndy Fleming 
13400db8189SAndy Fleming 	if (err < 0)
13500db8189SAndy Fleming 		return err;
13600db8189SAndy Fleming 
13700db8189SAndy Fleming 	err = phy_write(phydev, 0x1d, 0x1f);
13800db8189SAndy Fleming 	if (err < 0)
13900db8189SAndy Fleming 		return err;
14000db8189SAndy Fleming 
14100db8189SAndy Fleming 	err = phy_write(phydev, 0x1e, 0x200c);
14200db8189SAndy Fleming 	if (err < 0)
14300db8189SAndy Fleming 		return err;
14400db8189SAndy Fleming 
14500db8189SAndy Fleming 	err = phy_write(phydev, 0x1d, 0x5);
14600db8189SAndy Fleming 	if (err < 0)
14700db8189SAndy Fleming 		return err;
14800db8189SAndy Fleming 
14900db8189SAndy Fleming 	err = phy_write(phydev, 0x1e, 0);
15000db8189SAndy Fleming 	if (err < 0)
15100db8189SAndy Fleming 		return err;
15200db8189SAndy Fleming 
15300db8189SAndy Fleming 	err = phy_write(phydev, 0x1e, 0x100);
15400db8189SAndy Fleming 	if (err < 0)
15500db8189SAndy Fleming 		return err;
15600db8189SAndy Fleming 
15776884679SAndy Fleming 	err = phy_write(phydev, MII_M1011_PHY_SCR,
15876884679SAndy Fleming 			MII_M1011_PHY_SCR_AUTO_CROSS);
15976884679SAndy Fleming 	if (err < 0)
16076884679SAndy Fleming 		return err;
16176884679SAndy Fleming 
16276884679SAndy Fleming 	err = phy_write(phydev, MII_M1111_PHY_LED_CONTROL,
16376884679SAndy Fleming 			MII_M1111_PHY_LED_DIRECT);
16476884679SAndy Fleming 	if (err < 0)
16576884679SAndy Fleming 		return err;
16600db8189SAndy Fleming 
16700db8189SAndy Fleming 	err = genphy_config_aneg(phydev);
1688ff44985SAnton Vorontsov 	if (err < 0)
16900db8189SAndy Fleming 		return err;
1708ff44985SAnton Vorontsov 
1718ff44985SAnton Vorontsov 	if (phydev->autoneg != AUTONEG_ENABLE) {
1728ff44985SAnton Vorontsov 		int bmcr;
1738ff44985SAnton Vorontsov 
1748ff44985SAnton Vorontsov 		/*
1758ff44985SAnton Vorontsov 		 * A write to speed/duplex bits (that is performed by
1768ff44985SAnton Vorontsov 		 * genphy_config_aneg() call above) must be followed by
1778ff44985SAnton Vorontsov 		 * a software reset. Otherwise, the write has no effect.
1788ff44985SAnton Vorontsov 		 */
1798ff44985SAnton Vorontsov 		bmcr = phy_read(phydev, MII_BMCR);
1808ff44985SAnton Vorontsov 		if (bmcr < 0)
1818ff44985SAnton Vorontsov 			return bmcr;
1828ff44985SAnton Vorontsov 
1838ff44985SAnton Vorontsov 		err = phy_write(phydev, MII_BMCR, bmcr | BMCR_RESET);
1848ff44985SAnton Vorontsov 		if (err < 0)
1858ff44985SAnton Vorontsov 			return err;
1868ff44985SAnton Vorontsov 	}
1878ff44985SAnton Vorontsov 
1888ff44985SAnton Vorontsov 	return 0;
18900db8189SAndy Fleming }
19000db8189SAndy Fleming 
191cf41a51dSDavid Daney #ifdef CONFIG_OF_MDIO
192cf41a51dSDavid Daney /*
193cf41a51dSDavid Daney  * Set and/or override some configuration registers based on the
194cf41a51dSDavid Daney  * marvell,reg-init property stored in the of_node for the phydev.
195cf41a51dSDavid Daney  *
196cf41a51dSDavid Daney  * marvell,reg-init = <reg-page reg mask value>,...;
197cf41a51dSDavid Daney  *
198cf41a51dSDavid Daney  * There may be one or more sets of <reg-page reg mask value>:
199cf41a51dSDavid Daney  *
200cf41a51dSDavid Daney  * reg-page: which register bank to use.
201cf41a51dSDavid Daney  * reg: the register.
202cf41a51dSDavid Daney  * mask: if non-zero, ANDed with existing register value.
203cf41a51dSDavid Daney  * value: ORed with the masked value and written to the regiser.
204cf41a51dSDavid Daney  *
205cf41a51dSDavid Daney  */
206cf41a51dSDavid Daney static int marvell_of_reg_init(struct phy_device *phydev)
207cf41a51dSDavid Daney {
208cf41a51dSDavid Daney 	const __be32 *paddr;
209cf41a51dSDavid Daney 	int len, i, saved_page, current_page, page_changed, ret;
210cf41a51dSDavid Daney 
211cf41a51dSDavid Daney 	if (!phydev->dev.of_node)
212cf41a51dSDavid Daney 		return 0;
213cf41a51dSDavid Daney 
214cf41a51dSDavid Daney 	paddr = of_get_property(phydev->dev.of_node, "marvell,reg-init", &len);
215cf41a51dSDavid Daney 	if (!paddr || len < (4 * sizeof(*paddr)))
216cf41a51dSDavid Daney 		return 0;
217cf41a51dSDavid Daney 
218cf41a51dSDavid Daney 	saved_page = phy_read(phydev, MII_MARVELL_PHY_PAGE);
219cf41a51dSDavid Daney 	if (saved_page < 0)
220cf41a51dSDavid Daney 		return saved_page;
221cf41a51dSDavid Daney 	page_changed = 0;
222cf41a51dSDavid Daney 	current_page = saved_page;
223cf41a51dSDavid Daney 
224cf41a51dSDavid Daney 	ret = 0;
225cf41a51dSDavid Daney 	len /= sizeof(*paddr);
226cf41a51dSDavid Daney 	for (i = 0; i < len - 3; i += 4) {
227cf41a51dSDavid Daney 		u16 reg_page = be32_to_cpup(paddr + i);
228cf41a51dSDavid Daney 		u16 reg = be32_to_cpup(paddr + i + 1);
229cf41a51dSDavid Daney 		u16 mask = be32_to_cpup(paddr + i + 2);
230cf41a51dSDavid Daney 		u16 val_bits = be32_to_cpup(paddr + i + 3);
231cf41a51dSDavid Daney 		int val;
232cf41a51dSDavid Daney 
233cf41a51dSDavid Daney 		if (reg_page != current_page) {
234cf41a51dSDavid Daney 			current_page = reg_page;
235cf41a51dSDavid Daney 			page_changed = 1;
236cf41a51dSDavid Daney 			ret = phy_write(phydev, MII_MARVELL_PHY_PAGE, reg_page);
237cf41a51dSDavid Daney 			if (ret < 0)
238cf41a51dSDavid Daney 				goto err;
239cf41a51dSDavid Daney 		}
240cf41a51dSDavid Daney 
241cf41a51dSDavid Daney 		val = 0;
242cf41a51dSDavid Daney 		if (mask) {
243cf41a51dSDavid Daney 			val = phy_read(phydev, reg);
244cf41a51dSDavid Daney 			if (val < 0) {
245cf41a51dSDavid Daney 				ret = val;
246cf41a51dSDavid Daney 				goto err;
247cf41a51dSDavid Daney 			}
248cf41a51dSDavid Daney 			val &= mask;
249cf41a51dSDavid Daney 		}
250cf41a51dSDavid Daney 		val |= val_bits;
251cf41a51dSDavid Daney 
252cf41a51dSDavid Daney 		ret = phy_write(phydev, reg, val);
253cf41a51dSDavid Daney 		if (ret < 0)
254cf41a51dSDavid Daney 			goto err;
255cf41a51dSDavid Daney 
256cf41a51dSDavid Daney 	}
257cf41a51dSDavid Daney err:
258cf41a51dSDavid Daney 	if (page_changed) {
259cf41a51dSDavid Daney 		i = phy_write(phydev, MII_MARVELL_PHY_PAGE, saved_page);
260cf41a51dSDavid Daney 		if (ret == 0)
261cf41a51dSDavid Daney 			ret = i;
262cf41a51dSDavid Daney 	}
263cf41a51dSDavid Daney 	return ret;
264cf41a51dSDavid Daney }
265cf41a51dSDavid Daney #else
266cf41a51dSDavid Daney static int marvell_of_reg_init(struct phy_device *phydev)
267cf41a51dSDavid Daney {
268cf41a51dSDavid Daney 	return 0;
269cf41a51dSDavid Daney }
270cf41a51dSDavid Daney #endif /* CONFIG_OF_MDIO */
271cf41a51dSDavid Daney 
272140bc929SSergei Poselenov static int m88e1121_config_aneg(struct phy_device *phydev)
273140bc929SSergei Poselenov {
274c477d044SCyril Chemparathy 	int err, oldpage, mscr;
275c477d044SCyril Chemparathy 
27627d916d6SDavid Daney 	oldpage = phy_read(phydev, MII_MARVELL_PHY_PAGE);
277c477d044SCyril Chemparathy 
27827d916d6SDavid Daney 	err = phy_write(phydev, MII_MARVELL_PHY_PAGE,
279c477d044SCyril Chemparathy 			MII_88E1121_PHY_MSCR_PAGE);
280c477d044SCyril Chemparathy 	if (err < 0)
281c477d044SCyril Chemparathy 		return err;
282be8c6480SArnaud Patard 
283be8c6480SArnaud Patard 	if ((phydev->interface == PHY_INTERFACE_MODE_RGMII) ||
284be8c6480SArnaud Patard 	    (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) ||
285be8c6480SArnaud Patard 	    (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) ||
286be8c6480SArnaud Patard 	    (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)) {
287be8c6480SArnaud Patard 
288c477d044SCyril Chemparathy 		mscr = phy_read(phydev, MII_88E1121_PHY_MSCR_REG) &
289c477d044SCyril Chemparathy 			MII_88E1121_PHY_MSCR_DELAY_MASK;
290c477d044SCyril Chemparathy 
291c477d044SCyril Chemparathy 		if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)
292c477d044SCyril Chemparathy 			mscr |= (MII_88E1121_PHY_MSCR_RX_DELAY |
293c477d044SCyril Chemparathy 				 MII_88E1121_PHY_MSCR_TX_DELAY);
294c477d044SCyril Chemparathy 		else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID)
295c477d044SCyril Chemparathy 			mscr |= MII_88E1121_PHY_MSCR_RX_DELAY;
296c477d044SCyril Chemparathy 		else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)
297c477d044SCyril Chemparathy 			mscr |= MII_88E1121_PHY_MSCR_TX_DELAY;
298c477d044SCyril Chemparathy 
299c477d044SCyril Chemparathy 		err = phy_write(phydev, MII_88E1121_PHY_MSCR_REG, mscr);
300c477d044SCyril Chemparathy 		if (err < 0)
301c477d044SCyril Chemparathy 			return err;
302be8c6480SArnaud Patard 	}
303c477d044SCyril Chemparathy 
30427d916d6SDavid Daney 	phy_write(phydev, MII_MARVELL_PHY_PAGE, oldpage);
305140bc929SSergei Poselenov 
306140bc929SSergei Poselenov 	err = phy_write(phydev, MII_BMCR, BMCR_RESET);
307140bc929SSergei Poselenov 	if (err < 0)
308140bc929SSergei Poselenov 		return err;
309140bc929SSergei Poselenov 
310140bc929SSergei Poselenov 	err = phy_write(phydev, MII_M1011_PHY_SCR,
311140bc929SSergei Poselenov 			MII_M1011_PHY_SCR_AUTO_CROSS);
312140bc929SSergei Poselenov 	if (err < 0)
313140bc929SSergei Poselenov 		return err;
314140bc929SSergei Poselenov 
31527d916d6SDavid Daney 	oldpage = phy_read(phydev, MII_MARVELL_PHY_PAGE);
316140bc929SSergei Poselenov 
31727d916d6SDavid Daney 	phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_88E1121_PHY_LED_PAGE);
318140bc929SSergei Poselenov 	phy_write(phydev, MII_88E1121_PHY_LED_CTRL, MII_88E1121_PHY_LED_DEF);
31927d916d6SDavid Daney 	phy_write(phydev, MII_MARVELL_PHY_PAGE, oldpage);
320140bc929SSergei Poselenov 
321140bc929SSergei Poselenov 	err = genphy_config_aneg(phydev);
322140bc929SSergei Poselenov 
323140bc929SSergei Poselenov 	return err;
324140bc929SSergei Poselenov }
325140bc929SSergei Poselenov 
326337ac9d5SCyril Chemparathy static int m88e1318_config_aneg(struct phy_device *phydev)
3273ff1c259SCyril Chemparathy {
3283ff1c259SCyril Chemparathy 	int err, oldpage, mscr;
3293ff1c259SCyril Chemparathy 
33027d916d6SDavid Daney 	oldpage = phy_read(phydev, MII_MARVELL_PHY_PAGE);
3313ff1c259SCyril Chemparathy 
33227d916d6SDavid Daney 	err = phy_write(phydev, MII_MARVELL_PHY_PAGE,
3333ff1c259SCyril Chemparathy 			MII_88E1121_PHY_MSCR_PAGE);
3343ff1c259SCyril Chemparathy 	if (err < 0)
3353ff1c259SCyril Chemparathy 		return err;
3363ff1c259SCyril Chemparathy 
337337ac9d5SCyril Chemparathy 	mscr = phy_read(phydev, MII_88E1318S_PHY_MSCR1_REG);
338337ac9d5SCyril Chemparathy 	mscr |= MII_88E1318S_PHY_MSCR1_PAD_ODD;
3393ff1c259SCyril Chemparathy 
340337ac9d5SCyril Chemparathy 	err = phy_write(phydev, MII_88E1318S_PHY_MSCR1_REG, mscr);
3413ff1c259SCyril Chemparathy 	if (err < 0)
3423ff1c259SCyril Chemparathy 		return err;
3433ff1c259SCyril Chemparathy 
34427d916d6SDavid Daney 	err = phy_write(phydev, MII_MARVELL_PHY_PAGE, oldpage);
3453ff1c259SCyril Chemparathy 	if (err < 0)
3463ff1c259SCyril Chemparathy 		return err;
3473ff1c259SCyril Chemparathy 
3483ff1c259SCyril Chemparathy 	return m88e1121_config_aneg(phydev);
3493ff1c259SCyril Chemparathy }
3503ff1c259SCyril Chemparathy 
351895ee682SKim Phillips static int m88e1111_config_init(struct phy_device *phydev)
352895ee682SKim Phillips {
353895ee682SKim Phillips 	int err;
354be937f1fSAlexandr Smirnov 	int temp;
355be937f1fSAlexandr Smirnov 
356be937f1fSAlexandr Smirnov 	/* Enable Fiber/Copper auto selection */
357be937f1fSAlexandr Smirnov 	temp = phy_read(phydev, MII_M1111_PHY_EXT_SR);
3589cf8fa43SWang Jian 	temp &= ~MII_M1111_HWCFG_FIBER_COPPER_AUTO;
359be937f1fSAlexandr Smirnov 	phy_write(phydev, MII_M1111_PHY_EXT_SR, temp);
360be937f1fSAlexandr Smirnov 
361be937f1fSAlexandr Smirnov 	temp = phy_read(phydev, MII_BMCR);
362be937f1fSAlexandr Smirnov 	temp |= BMCR_RESET;
363be937f1fSAlexandr Smirnov 	phy_write(phydev, MII_BMCR, temp);
364895ee682SKim Phillips 
365895ee682SKim Phillips 	if ((phydev->interface == PHY_INTERFACE_MODE_RGMII) ||
3669daf5a76SKim Phillips 	    (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) ||
3679daf5a76SKim Phillips 	    (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) ||
3689daf5a76SKim Phillips 	    (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)) {
369895ee682SKim Phillips 
370895ee682SKim Phillips 		temp = phy_read(phydev, MII_M1111_PHY_EXT_CR);
371895ee682SKim Phillips 		if (temp < 0)
372895ee682SKim Phillips 			return temp;
373895ee682SKim Phillips 
3749daf5a76SKim Phillips 		if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) {
375895ee682SKim Phillips 			temp |= (MII_M1111_RX_DELAY | MII_M1111_TX_DELAY);
3769daf5a76SKim Phillips 		} else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) {
3779daf5a76SKim Phillips 			temp &= ~MII_M1111_TX_DELAY;
3789daf5a76SKim Phillips 			temp |= MII_M1111_RX_DELAY;
3799daf5a76SKim Phillips 		} else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) {
3809daf5a76SKim Phillips 			temp &= ~MII_M1111_RX_DELAY;
3819daf5a76SKim Phillips 			temp |= MII_M1111_TX_DELAY;
3829daf5a76SKim Phillips 		}
383895ee682SKim Phillips 
384895ee682SKim Phillips 		err = phy_write(phydev, MII_M1111_PHY_EXT_CR, temp);
385895ee682SKim Phillips 		if (err < 0)
386895ee682SKim Phillips 			return err;
387895ee682SKim Phillips 
388895ee682SKim Phillips 		temp = phy_read(phydev, MII_M1111_PHY_EXT_SR);
389895ee682SKim Phillips 		if (temp < 0)
390895ee682SKim Phillips 			return temp;
391895ee682SKim Phillips 
392895ee682SKim Phillips 		temp &= ~(MII_M1111_HWCFG_MODE_MASK);
393be937f1fSAlexandr Smirnov 
3947239016dSWang Jian 		if (temp & MII_M1111_HWCFG_FIBER_COPPER_RES)
395be937f1fSAlexandr Smirnov 			temp |= MII_M1111_HWCFG_MODE_FIBER_RGMII;
396be937f1fSAlexandr Smirnov 		else
397be937f1fSAlexandr Smirnov 			temp |= MII_M1111_HWCFG_MODE_COPPER_RGMII;
398895ee682SKim Phillips 
399895ee682SKim Phillips 		err = phy_write(phydev, MII_M1111_PHY_EXT_SR, temp);
400895ee682SKim Phillips 		if (err < 0)
401895ee682SKim Phillips 			return err;
402895ee682SKim Phillips 	}
403895ee682SKim Phillips 
4044117b5beSKapil Juneja 	if (phydev->interface == PHY_INTERFACE_MODE_SGMII) {
4054117b5beSKapil Juneja 		temp = phy_read(phydev, MII_M1111_PHY_EXT_SR);
4064117b5beSKapil Juneja 		if (temp < 0)
4074117b5beSKapil Juneja 			return temp;
4084117b5beSKapil Juneja 
4094117b5beSKapil Juneja 		temp &= ~(MII_M1111_HWCFG_MODE_MASK);
4104117b5beSKapil Juneja 		temp |= MII_M1111_HWCFG_MODE_SGMII_NO_CLK;
41132d0c1e1SHaiying Wang 		temp |= MII_M1111_HWCFG_FIBER_COPPER_AUTO;
4124117b5beSKapil Juneja 
4134117b5beSKapil Juneja 		err = phy_write(phydev, MII_M1111_PHY_EXT_SR, temp);
4144117b5beSKapil Juneja 		if (err < 0)
4154117b5beSKapil Juneja 			return err;
4164117b5beSKapil Juneja 	}
4174117b5beSKapil Juneja 
4185f8cbc13SLiu Yu-B13201 	if (phydev->interface == PHY_INTERFACE_MODE_RTBI) {
4195f8cbc13SLiu Yu-B13201 		temp = phy_read(phydev, MII_M1111_PHY_EXT_CR);
4205f8cbc13SLiu Yu-B13201 		if (temp < 0)
4215f8cbc13SLiu Yu-B13201 			return temp;
4225f8cbc13SLiu Yu-B13201 		temp |= (MII_M1111_RX_DELAY | MII_M1111_TX_DELAY);
4235f8cbc13SLiu Yu-B13201 		err = phy_write(phydev, MII_M1111_PHY_EXT_CR, temp);
4245f8cbc13SLiu Yu-B13201 		if (err < 0)
4255f8cbc13SLiu Yu-B13201 			return err;
4265f8cbc13SLiu Yu-B13201 
4275f8cbc13SLiu Yu-B13201 		temp = phy_read(phydev, MII_M1111_PHY_EXT_SR);
4285f8cbc13SLiu Yu-B13201 		if (temp < 0)
4295f8cbc13SLiu Yu-B13201 			return temp;
4305f8cbc13SLiu Yu-B13201 		temp &= ~(MII_M1111_HWCFG_MODE_MASK | MII_M1111_HWCFG_FIBER_COPPER_RES);
4315f8cbc13SLiu Yu-B13201 		temp |= 0x7 | MII_M1111_HWCFG_FIBER_COPPER_AUTO;
4325f8cbc13SLiu Yu-B13201 		err = phy_write(phydev, MII_M1111_PHY_EXT_SR, temp);
4335f8cbc13SLiu Yu-B13201 		if (err < 0)
4345f8cbc13SLiu Yu-B13201 			return err;
4355f8cbc13SLiu Yu-B13201 
4365f8cbc13SLiu Yu-B13201 		/* soft reset */
4375f8cbc13SLiu Yu-B13201 		err = phy_write(phydev, MII_BMCR, BMCR_RESET);
4385f8cbc13SLiu Yu-B13201 		if (err < 0)
4395f8cbc13SLiu Yu-B13201 			return err;
4405f8cbc13SLiu Yu-B13201 		do
4415f8cbc13SLiu Yu-B13201 			temp = phy_read(phydev, MII_BMCR);
4425f8cbc13SLiu Yu-B13201 		while (temp & BMCR_RESET);
4435f8cbc13SLiu Yu-B13201 
4445f8cbc13SLiu Yu-B13201 		temp = phy_read(phydev, MII_M1111_PHY_EXT_SR);
4455f8cbc13SLiu Yu-B13201 		if (temp < 0)
4465f8cbc13SLiu Yu-B13201 			return temp;
4475f8cbc13SLiu Yu-B13201 		temp &= ~(MII_M1111_HWCFG_MODE_MASK | MII_M1111_HWCFG_FIBER_COPPER_RES);
4485f8cbc13SLiu Yu-B13201 		temp |= MII_M1111_HWCFG_MODE_COPPER_RTBI | MII_M1111_HWCFG_FIBER_COPPER_AUTO;
4495f8cbc13SLiu Yu-B13201 		err = phy_write(phydev, MII_M1111_PHY_EXT_SR, temp);
4505f8cbc13SLiu Yu-B13201 		if (err < 0)
4515f8cbc13SLiu Yu-B13201 			return err;
4525f8cbc13SLiu Yu-B13201 	}
4535f8cbc13SLiu Yu-B13201 
454cf41a51dSDavid Daney 	err = marvell_of_reg_init(phydev);
455cf41a51dSDavid Daney 	if (err < 0)
456cf41a51dSDavid Daney 		return err;
4575f8cbc13SLiu Yu-B13201 
458cc90cb3bSSrinivas Kandagatla 	return phy_write(phydev, MII_BMCR, BMCR_RESET);
459895ee682SKim Phillips }
460895ee682SKim Phillips 
461605f196eSRon Madrid static int m88e1118_config_aneg(struct phy_device *phydev)
462605f196eSRon Madrid {
463605f196eSRon Madrid 	int err;
464605f196eSRon Madrid 
465605f196eSRon Madrid 	err = phy_write(phydev, MII_BMCR, BMCR_RESET);
466605f196eSRon Madrid 	if (err < 0)
467605f196eSRon Madrid 		return err;
468605f196eSRon Madrid 
469605f196eSRon Madrid 	err = phy_write(phydev, MII_M1011_PHY_SCR,
470605f196eSRon Madrid 			MII_M1011_PHY_SCR_AUTO_CROSS);
471605f196eSRon Madrid 	if (err < 0)
472605f196eSRon Madrid 		return err;
473605f196eSRon Madrid 
474605f196eSRon Madrid 	err = genphy_config_aneg(phydev);
475605f196eSRon Madrid 	return 0;
476605f196eSRon Madrid }
477605f196eSRon Madrid 
478605f196eSRon Madrid static int m88e1118_config_init(struct phy_device *phydev)
479605f196eSRon Madrid {
480605f196eSRon Madrid 	int err;
481605f196eSRon Madrid 
482605f196eSRon Madrid 	/* Change address */
48327d916d6SDavid Daney 	err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0002);
484605f196eSRon Madrid 	if (err < 0)
485605f196eSRon Madrid 		return err;
486605f196eSRon Madrid 
487605f196eSRon Madrid 	/* Enable 1000 Mbit */
488605f196eSRon Madrid 	err = phy_write(phydev, 0x15, 0x1070);
489605f196eSRon Madrid 	if (err < 0)
490605f196eSRon Madrid 		return err;
491605f196eSRon Madrid 
492605f196eSRon Madrid 	/* Change address */
49327d916d6SDavid Daney 	err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0003);
494605f196eSRon Madrid 	if (err < 0)
495605f196eSRon Madrid 		return err;
496605f196eSRon Madrid 
497605f196eSRon Madrid 	/* Adjust LED Control */
4982f495c39SBenjamin Herrenschmidt 	if (phydev->dev_flags & MARVELL_PHY_M1118_DNS323_LEDS)
4992f495c39SBenjamin Herrenschmidt 		err = phy_write(phydev, 0x10, 0x1100);
5002f495c39SBenjamin Herrenschmidt 	else
501605f196eSRon Madrid 		err = phy_write(phydev, 0x10, 0x021e);
502605f196eSRon Madrid 	if (err < 0)
503605f196eSRon Madrid 		return err;
504605f196eSRon Madrid 
505cf41a51dSDavid Daney 	err = marvell_of_reg_init(phydev);
506cf41a51dSDavid Daney 	if (err < 0)
507cf41a51dSDavid Daney 		return err;
508cf41a51dSDavid Daney 
509605f196eSRon Madrid 	/* Reset address */
51027d916d6SDavid Daney 	err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0);
511605f196eSRon Madrid 	if (err < 0)
512605f196eSRon Madrid 		return err;
513605f196eSRon Madrid 
514cc90cb3bSSrinivas Kandagatla 	return phy_write(phydev, MII_BMCR, BMCR_RESET);
515605f196eSRon Madrid }
516605f196eSRon Madrid 
51790600732SDavid Daney static int m88e1149_config_init(struct phy_device *phydev)
51890600732SDavid Daney {
51990600732SDavid Daney 	int err;
52090600732SDavid Daney 
52190600732SDavid Daney 	/* Change address */
52290600732SDavid Daney 	err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0002);
52390600732SDavid Daney 	if (err < 0)
52490600732SDavid Daney 		return err;
52590600732SDavid Daney 
52690600732SDavid Daney 	/* Enable 1000 Mbit */
52790600732SDavid Daney 	err = phy_write(phydev, 0x15, 0x1048);
52890600732SDavid Daney 	if (err < 0)
52990600732SDavid Daney 		return err;
53090600732SDavid Daney 
531cf41a51dSDavid Daney 	err = marvell_of_reg_init(phydev);
532cf41a51dSDavid Daney 	if (err < 0)
533cf41a51dSDavid Daney 		return err;
534cf41a51dSDavid Daney 
53590600732SDavid Daney 	/* Reset address */
53690600732SDavid Daney 	err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0);
53790600732SDavid Daney 	if (err < 0)
53890600732SDavid Daney 		return err;
53990600732SDavid Daney 
540cc90cb3bSSrinivas Kandagatla 	return phy_write(phydev, MII_BMCR, BMCR_RESET);
54190600732SDavid Daney }
54290600732SDavid Daney 
54376884679SAndy Fleming static int m88e1145_config_init(struct phy_device *phydev)
54476884679SAndy Fleming {
54576884679SAndy Fleming 	int err;
54676884679SAndy Fleming 
54776884679SAndy Fleming 	/* Take care of errata E0 & E1 */
54876884679SAndy Fleming 	err = phy_write(phydev, 0x1d, 0x001b);
54976884679SAndy Fleming 	if (err < 0)
55076884679SAndy Fleming 		return err;
55176884679SAndy Fleming 
55276884679SAndy Fleming 	err = phy_write(phydev, 0x1e, 0x418f);
55376884679SAndy Fleming 	if (err < 0)
55476884679SAndy Fleming 		return err;
55576884679SAndy Fleming 
55676884679SAndy Fleming 	err = phy_write(phydev, 0x1d, 0x0016);
55776884679SAndy Fleming 	if (err < 0)
55876884679SAndy Fleming 		return err;
55976884679SAndy Fleming 
56076884679SAndy Fleming 	err = phy_write(phydev, 0x1e, 0xa2da);
56176884679SAndy Fleming 	if (err < 0)
56276884679SAndy Fleming 		return err;
56376884679SAndy Fleming 
564895ee682SKim Phillips 	if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) {
56576884679SAndy Fleming 		int temp = phy_read(phydev, MII_M1145_PHY_EXT_CR);
56676884679SAndy Fleming 		if (temp < 0)
56776884679SAndy Fleming 			return temp;
56876884679SAndy Fleming 
56976884679SAndy Fleming 		temp |= (MII_M1145_RGMII_RX_DELAY | MII_M1145_RGMII_TX_DELAY);
57076884679SAndy Fleming 
57176884679SAndy Fleming 		err = phy_write(phydev, MII_M1145_PHY_EXT_CR, temp);
57276884679SAndy Fleming 		if (err < 0)
57376884679SAndy Fleming 			return err;
57476884679SAndy Fleming 
5752f495c39SBenjamin Herrenschmidt 		if (phydev->dev_flags & MARVELL_PHY_M1145_FLAGS_RESISTANCE) {
57676884679SAndy Fleming 			err = phy_write(phydev, 0x1d, 0x0012);
57776884679SAndy Fleming 			if (err < 0)
57876884679SAndy Fleming 				return err;
57976884679SAndy Fleming 
58076884679SAndy Fleming 			temp = phy_read(phydev, 0x1e);
58176884679SAndy Fleming 			if (temp < 0)
58276884679SAndy Fleming 				return temp;
58376884679SAndy Fleming 
58476884679SAndy Fleming 			temp &= 0xf03f;
58576884679SAndy Fleming 			temp |= 2 << 9;	/* 36 ohm */
58676884679SAndy Fleming 			temp |= 2 << 6;	/* 39 ohm */
58776884679SAndy Fleming 
58876884679SAndy Fleming 			err = phy_write(phydev, 0x1e, temp);
58976884679SAndy Fleming 			if (err < 0)
59076884679SAndy Fleming 				return err;
59176884679SAndy Fleming 
59276884679SAndy Fleming 			err = phy_write(phydev, 0x1d, 0x3);
59376884679SAndy Fleming 			if (err < 0)
59476884679SAndy Fleming 				return err;
59576884679SAndy Fleming 
59676884679SAndy Fleming 			err = phy_write(phydev, 0x1e, 0x8000);
59776884679SAndy Fleming 			if (err < 0)
59876884679SAndy Fleming 				return err;
59976884679SAndy Fleming 		}
60076884679SAndy Fleming 	}
60176884679SAndy Fleming 
602cf41a51dSDavid Daney 	err = marvell_of_reg_init(phydev);
603cf41a51dSDavid Daney 	if (err < 0)
604cf41a51dSDavid Daney 		return err;
605cf41a51dSDavid Daney 
60676884679SAndy Fleming 	return 0;
60776884679SAndy Fleming }
60800db8189SAndy Fleming 
609be937f1fSAlexandr Smirnov /* marvell_read_status
610be937f1fSAlexandr Smirnov  *
611be937f1fSAlexandr Smirnov  * Generic status code does not detect Fiber correctly!
612be937f1fSAlexandr Smirnov  * Description:
613be937f1fSAlexandr Smirnov  *   Check the link, then figure out the current state
614be937f1fSAlexandr Smirnov  *   by comparing what we advertise with what the link partner
615be937f1fSAlexandr Smirnov  *   advertises.  Start by checking the gigabit possibilities,
616be937f1fSAlexandr Smirnov  *   then move on to 10/100.
617be937f1fSAlexandr Smirnov  */
618be937f1fSAlexandr Smirnov static int marvell_read_status(struct phy_device *phydev)
619be937f1fSAlexandr Smirnov {
620be937f1fSAlexandr Smirnov 	int adv;
621be937f1fSAlexandr Smirnov 	int err;
622be937f1fSAlexandr Smirnov 	int lpa;
623be937f1fSAlexandr Smirnov 	int status = 0;
624be937f1fSAlexandr Smirnov 
625be937f1fSAlexandr Smirnov 	/* Update the link, but return if there
626be937f1fSAlexandr Smirnov 	 * was an error */
627be937f1fSAlexandr Smirnov 	err = genphy_update_link(phydev);
628be937f1fSAlexandr Smirnov 	if (err)
629be937f1fSAlexandr Smirnov 		return err;
630be937f1fSAlexandr Smirnov 
631be937f1fSAlexandr Smirnov 	if (AUTONEG_ENABLE == phydev->autoneg) {
632be937f1fSAlexandr Smirnov 		status = phy_read(phydev, MII_M1011_PHY_STATUS);
633be937f1fSAlexandr Smirnov 		if (status < 0)
634be937f1fSAlexandr Smirnov 			return status;
635be937f1fSAlexandr Smirnov 
636be937f1fSAlexandr Smirnov 		lpa = phy_read(phydev, MII_LPA);
637be937f1fSAlexandr Smirnov 		if (lpa < 0)
638be937f1fSAlexandr Smirnov 			return lpa;
639be937f1fSAlexandr Smirnov 
640be937f1fSAlexandr Smirnov 		adv = phy_read(phydev, MII_ADVERTISE);
641be937f1fSAlexandr Smirnov 		if (adv < 0)
642be937f1fSAlexandr Smirnov 			return adv;
643be937f1fSAlexandr Smirnov 
644be937f1fSAlexandr Smirnov 		lpa &= adv;
645be937f1fSAlexandr Smirnov 
646be937f1fSAlexandr Smirnov 		if (status & MII_M1011_PHY_STATUS_FULLDUPLEX)
647be937f1fSAlexandr Smirnov 			phydev->duplex = DUPLEX_FULL;
648be937f1fSAlexandr Smirnov 		else
649be937f1fSAlexandr Smirnov 			phydev->duplex = DUPLEX_HALF;
650be937f1fSAlexandr Smirnov 
651be937f1fSAlexandr Smirnov 		status = status & MII_M1011_PHY_STATUS_SPD_MASK;
652be937f1fSAlexandr Smirnov 		phydev->pause = phydev->asym_pause = 0;
653be937f1fSAlexandr Smirnov 
654be937f1fSAlexandr Smirnov 		switch (status) {
655be937f1fSAlexandr Smirnov 		case MII_M1011_PHY_STATUS_1000:
656be937f1fSAlexandr Smirnov 			phydev->speed = SPEED_1000;
657be937f1fSAlexandr Smirnov 			break;
658be937f1fSAlexandr Smirnov 
659be937f1fSAlexandr Smirnov 		case MII_M1011_PHY_STATUS_100:
660be937f1fSAlexandr Smirnov 			phydev->speed = SPEED_100;
661be937f1fSAlexandr Smirnov 			break;
662be937f1fSAlexandr Smirnov 
663be937f1fSAlexandr Smirnov 		default:
664be937f1fSAlexandr Smirnov 			phydev->speed = SPEED_10;
665be937f1fSAlexandr Smirnov 			break;
666be937f1fSAlexandr Smirnov 		}
667be937f1fSAlexandr Smirnov 
668be937f1fSAlexandr Smirnov 		if (phydev->duplex == DUPLEX_FULL) {
669be937f1fSAlexandr Smirnov 			phydev->pause = lpa & LPA_PAUSE_CAP ? 1 : 0;
670be937f1fSAlexandr Smirnov 			phydev->asym_pause = lpa & LPA_PAUSE_ASYM ? 1 : 0;
671be937f1fSAlexandr Smirnov 		}
672be937f1fSAlexandr Smirnov 	} else {
673be937f1fSAlexandr Smirnov 		int bmcr = phy_read(phydev, MII_BMCR);
674be937f1fSAlexandr Smirnov 
675be937f1fSAlexandr Smirnov 		if (bmcr < 0)
676be937f1fSAlexandr Smirnov 			return bmcr;
677be937f1fSAlexandr Smirnov 
678be937f1fSAlexandr Smirnov 		if (bmcr & BMCR_FULLDPLX)
679be937f1fSAlexandr Smirnov 			phydev->duplex = DUPLEX_FULL;
680be937f1fSAlexandr Smirnov 		else
681be937f1fSAlexandr Smirnov 			phydev->duplex = DUPLEX_HALF;
682be937f1fSAlexandr Smirnov 
683be937f1fSAlexandr Smirnov 		if (bmcr & BMCR_SPEED1000)
684be937f1fSAlexandr Smirnov 			phydev->speed = SPEED_1000;
685be937f1fSAlexandr Smirnov 		else if (bmcr & BMCR_SPEED100)
686be937f1fSAlexandr Smirnov 			phydev->speed = SPEED_100;
687be937f1fSAlexandr Smirnov 		else
688be937f1fSAlexandr Smirnov 			phydev->speed = SPEED_10;
689be937f1fSAlexandr Smirnov 
690be937f1fSAlexandr Smirnov 		phydev->pause = phydev->asym_pause = 0;
691be937f1fSAlexandr Smirnov 	}
692be937f1fSAlexandr Smirnov 
693be937f1fSAlexandr Smirnov 	return 0;
694be937f1fSAlexandr Smirnov }
695be937f1fSAlexandr Smirnov 
696dcd07be3SAnatolij Gustschin static int m88e1121_did_interrupt(struct phy_device *phydev)
697dcd07be3SAnatolij Gustschin {
698dcd07be3SAnatolij Gustschin 	int imask;
699dcd07be3SAnatolij Gustschin 
700dcd07be3SAnatolij Gustschin 	imask = phy_read(phydev, MII_M1011_IEVENT);
701dcd07be3SAnatolij Gustschin 
702dcd07be3SAnatolij Gustschin 	if (imask & MII_M1011_IMASK_INIT)
703dcd07be3SAnatolij Gustschin 		return 1;
704dcd07be3SAnatolij Gustschin 
705dcd07be3SAnatolij Gustschin 	return 0;
706dcd07be3SAnatolij Gustschin }
707dcd07be3SAnatolij Gustschin 
708e5479239SOlof Johansson static struct phy_driver marvell_drivers[] = {
709e5479239SOlof Johansson 	{
7102f495c39SBenjamin Herrenschmidt 		.phy_id = MARVELL_PHY_ID_88E1101,
7112f495c39SBenjamin Herrenschmidt 		.phy_id_mask = MARVELL_PHY_ID_MASK,
71200db8189SAndy Fleming 		.name = "Marvell 88E1101",
71300db8189SAndy Fleming 		.features = PHY_GBIT_FEATURES,
71400db8189SAndy Fleming 		.flags = PHY_HAS_INTERRUPT,
71500db8189SAndy Fleming 		.config_aneg = &marvell_config_aneg,
71600db8189SAndy Fleming 		.read_status = &genphy_read_status,
71700db8189SAndy Fleming 		.ack_interrupt = &marvell_ack_interrupt,
71800db8189SAndy Fleming 		.config_intr = &marvell_config_intr,
719ac8c635aSOlof Johansson 		.driver = { .owner = THIS_MODULE },
720e5479239SOlof Johansson 	},
721e5479239SOlof Johansson 	{
7222f495c39SBenjamin Herrenschmidt 		.phy_id = MARVELL_PHY_ID_88E1112,
7232f495c39SBenjamin Herrenschmidt 		.phy_id_mask = MARVELL_PHY_ID_MASK,
72485cfb534SOlof Johansson 		.name = "Marvell 88E1112",
72585cfb534SOlof Johansson 		.features = PHY_GBIT_FEATURES,
72685cfb534SOlof Johansson 		.flags = PHY_HAS_INTERRUPT,
72785cfb534SOlof Johansson 		.config_init = &m88e1111_config_init,
72885cfb534SOlof Johansson 		.config_aneg = &marvell_config_aneg,
72985cfb534SOlof Johansson 		.read_status = &genphy_read_status,
73085cfb534SOlof Johansson 		.ack_interrupt = &marvell_ack_interrupt,
73185cfb534SOlof Johansson 		.config_intr = &marvell_config_intr,
732ac8c635aSOlof Johansson 		.driver = { .owner = THIS_MODULE },
73385cfb534SOlof Johansson 	},
73485cfb534SOlof Johansson 	{
7352f495c39SBenjamin Herrenschmidt 		.phy_id = MARVELL_PHY_ID_88E1111,
7362f495c39SBenjamin Herrenschmidt 		.phy_id_mask = MARVELL_PHY_ID_MASK,
73776884679SAndy Fleming 		.name = "Marvell 88E1111",
73876884679SAndy Fleming 		.features = PHY_GBIT_FEATURES,
73976884679SAndy Fleming 		.flags = PHY_HAS_INTERRUPT,
740e5479239SOlof Johansson 		.config_init = &m88e1111_config_init,
74176884679SAndy Fleming 		.config_aneg = &marvell_config_aneg,
742be937f1fSAlexandr Smirnov 		.read_status = &marvell_read_status,
74376884679SAndy Fleming 		.ack_interrupt = &marvell_ack_interrupt,
74476884679SAndy Fleming 		.config_intr = &marvell_config_intr,
745ac8c635aSOlof Johansson 		.driver = { .owner = THIS_MODULE },
746e5479239SOlof Johansson 	},
747e5479239SOlof Johansson 	{
7482f495c39SBenjamin Herrenschmidt 		.phy_id = MARVELL_PHY_ID_88E1118,
7492f495c39SBenjamin Herrenschmidt 		.phy_id_mask = MARVELL_PHY_ID_MASK,
750605f196eSRon Madrid 		.name = "Marvell 88E1118",
751605f196eSRon Madrid 		.features = PHY_GBIT_FEATURES,
752605f196eSRon Madrid 		.flags = PHY_HAS_INTERRUPT,
753605f196eSRon Madrid 		.config_init = &m88e1118_config_init,
754605f196eSRon Madrid 		.config_aneg = &m88e1118_config_aneg,
755605f196eSRon Madrid 		.read_status = &genphy_read_status,
756605f196eSRon Madrid 		.ack_interrupt = &marvell_ack_interrupt,
757605f196eSRon Madrid 		.config_intr = &marvell_config_intr,
758605f196eSRon Madrid 		.driver = {.owner = THIS_MODULE,},
759605f196eSRon Madrid 	},
760605f196eSRon Madrid 	{
7612f495c39SBenjamin Herrenschmidt 		.phy_id = MARVELL_PHY_ID_88E1121R,
7622f495c39SBenjamin Herrenschmidt 		.phy_id_mask = MARVELL_PHY_ID_MASK,
763140bc929SSergei Poselenov 		.name = "Marvell 88E1121R",
764140bc929SSergei Poselenov 		.features = PHY_GBIT_FEATURES,
765140bc929SSergei Poselenov 		.flags = PHY_HAS_INTERRUPT,
766140bc929SSergei Poselenov 		.config_aneg = &m88e1121_config_aneg,
767140bc929SSergei Poselenov 		.read_status = &marvell_read_status,
768140bc929SSergei Poselenov 		.ack_interrupt = &marvell_ack_interrupt,
769140bc929SSergei Poselenov 		.config_intr = &marvell_config_intr,
770dcd07be3SAnatolij Gustschin 		.did_interrupt = &m88e1121_did_interrupt,
771140bc929SSergei Poselenov 		.driver = { .owner = THIS_MODULE },
772140bc929SSergei Poselenov 	},
773140bc929SSergei Poselenov 	{
774337ac9d5SCyril Chemparathy 		.phy_id = MARVELL_PHY_ID_88E1318S,
7756ba74014SLinus Torvalds 		.phy_id_mask = MARVELL_PHY_ID_MASK,
776337ac9d5SCyril Chemparathy 		.name = "Marvell 88E1318S",
7773ff1c259SCyril Chemparathy 		.features = PHY_GBIT_FEATURES,
7783ff1c259SCyril Chemparathy 		.flags = PHY_HAS_INTERRUPT,
779337ac9d5SCyril Chemparathy 		.config_aneg = &m88e1318_config_aneg,
7803ff1c259SCyril Chemparathy 		.read_status = &marvell_read_status,
7813ff1c259SCyril Chemparathy 		.ack_interrupt = &marvell_ack_interrupt,
7823ff1c259SCyril Chemparathy 		.config_intr = &marvell_config_intr,
7833ff1c259SCyril Chemparathy 		.did_interrupt = &m88e1121_did_interrupt,
7843ff1c259SCyril Chemparathy 		.driver = { .owner = THIS_MODULE },
7853ff1c259SCyril Chemparathy 	},
7863ff1c259SCyril Chemparathy 	{
7872f495c39SBenjamin Herrenschmidt 		.phy_id = MARVELL_PHY_ID_88E1145,
7882f495c39SBenjamin Herrenschmidt 		.phy_id_mask = MARVELL_PHY_ID_MASK,
78976884679SAndy Fleming 		.name = "Marvell 88E1145",
79076884679SAndy Fleming 		.features = PHY_GBIT_FEATURES,
79176884679SAndy Fleming 		.flags = PHY_HAS_INTERRUPT,
79276884679SAndy Fleming 		.config_init = &m88e1145_config_init,
79376884679SAndy Fleming 		.config_aneg = &marvell_config_aneg,
79476884679SAndy Fleming 		.read_status = &genphy_read_status,
79576884679SAndy Fleming 		.ack_interrupt = &marvell_ack_interrupt,
79676884679SAndy Fleming 		.config_intr = &marvell_config_intr,
797ac8c635aSOlof Johansson 		.driver = { .owner = THIS_MODULE },
798ac8c635aSOlof Johansson 	},
799ac8c635aSOlof Johansson 	{
80090600732SDavid Daney 		.phy_id = MARVELL_PHY_ID_88E1149R,
80190600732SDavid Daney 		.phy_id_mask = MARVELL_PHY_ID_MASK,
80290600732SDavid Daney 		.name = "Marvell 88E1149R",
80390600732SDavid Daney 		.features = PHY_GBIT_FEATURES,
80490600732SDavid Daney 		.flags = PHY_HAS_INTERRUPT,
80590600732SDavid Daney 		.config_init = &m88e1149_config_init,
80690600732SDavid Daney 		.config_aneg = &m88e1118_config_aneg,
80790600732SDavid Daney 		.read_status = &genphy_read_status,
80890600732SDavid Daney 		.ack_interrupt = &marvell_ack_interrupt,
80990600732SDavid Daney 		.config_intr = &marvell_config_intr,
81090600732SDavid Daney 		.driver = { .owner = THIS_MODULE },
81190600732SDavid Daney 	},
81290600732SDavid Daney 	{
8132f495c39SBenjamin Herrenschmidt 		.phy_id = MARVELL_PHY_ID_88E1240,
8142f495c39SBenjamin Herrenschmidt 		.phy_id_mask = MARVELL_PHY_ID_MASK,
815ac8c635aSOlof Johansson 		.name = "Marvell 88E1240",
816ac8c635aSOlof Johansson 		.features = PHY_GBIT_FEATURES,
817ac8c635aSOlof Johansson 		.flags = PHY_HAS_INTERRUPT,
818ac8c635aSOlof Johansson 		.config_init = &m88e1111_config_init,
819ac8c635aSOlof Johansson 		.config_aneg = &marvell_config_aneg,
820ac8c635aSOlof Johansson 		.read_status = &genphy_read_status,
821ac8c635aSOlof Johansson 		.ack_interrupt = &marvell_ack_interrupt,
822ac8c635aSOlof Johansson 		.config_intr = &marvell_config_intr,
823ac8c635aSOlof Johansson 		.driver = { .owner = THIS_MODULE },
824ac8c635aSOlof Johansson 	},
82576884679SAndy Fleming };
82676884679SAndy Fleming 
82700db8189SAndy Fleming static int __init marvell_init(void)
82800db8189SAndy Fleming {
82976884679SAndy Fleming 	int ret;
830e5479239SOlof Johansson 	int i;
83176884679SAndy Fleming 
832e5479239SOlof Johansson 	for (i = 0; i < ARRAY_SIZE(marvell_drivers); i++) {
833e5479239SOlof Johansson 		ret = phy_driver_register(&marvell_drivers[i]);
834e5479239SOlof Johansson 
835e5479239SOlof Johansson 		if (ret) {
836e5479239SOlof Johansson 			while (i-- > 0)
837e5479239SOlof Johansson 				phy_driver_unregister(&marvell_drivers[i]);
83876884679SAndy Fleming 			return ret;
839e5479239SOlof Johansson 		}
840e5479239SOlof Johansson 	}
84176884679SAndy Fleming 
84276884679SAndy Fleming 	return 0;
84300db8189SAndy Fleming }
84400db8189SAndy Fleming 
84500db8189SAndy Fleming static void __exit marvell_exit(void)
84600db8189SAndy Fleming {
847e5479239SOlof Johansson 	int i;
848e5479239SOlof Johansson 
849e5479239SOlof Johansson 	for (i = 0; i < ARRAY_SIZE(marvell_drivers); i++)
850e5479239SOlof Johansson 		phy_driver_unregister(&marvell_drivers[i]);
85100db8189SAndy Fleming }
85200db8189SAndy Fleming 
85300db8189SAndy Fleming module_init(marvell_init);
85400db8189SAndy Fleming module_exit(marvell_exit);
8554e4f10f6SDavid Woodhouse 
856cf93c945SUwe Kleine-König static struct mdio_device_id __maybe_unused marvell_tbl[] = {
8574e4f10f6SDavid Woodhouse 	{ 0x01410c60, 0xfffffff0 },
8584e4f10f6SDavid Woodhouse 	{ 0x01410c90, 0xfffffff0 },
8594e4f10f6SDavid Woodhouse 	{ 0x01410cc0, 0xfffffff0 },
8604e4f10f6SDavid Woodhouse 	{ 0x01410e10, 0xfffffff0 },
8614e4f10f6SDavid Woodhouse 	{ 0x01410cb0, 0xfffffff0 },
8624e4f10f6SDavid Woodhouse 	{ 0x01410cd0, 0xfffffff0 },
86390600732SDavid Daney 	{ 0x01410e50, 0xfffffff0 },
8644e4f10f6SDavid Woodhouse 	{ 0x01410e30, 0xfffffff0 },
8653ff1c259SCyril Chemparathy 	{ 0x01410e90, 0xfffffff0 },
8664e4f10f6SDavid Woodhouse 	{ }
8674e4f10f6SDavid Woodhouse };
8684e4f10f6SDavid Woodhouse 
8694e4f10f6SDavid Woodhouse MODULE_DEVICE_TABLE(mdio, marvell_tbl);
870