xref: /openbmc/linux/drivers/net/phy/marvell.c (revision 895ee682)
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/slab.h>
2100db8189SAndy Fleming #include <linux/interrupt.h>
2200db8189SAndy Fleming #include <linux/init.h>
2300db8189SAndy Fleming #include <linux/delay.h>
2400db8189SAndy Fleming #include <linux/netdevice.h>
2500db8189SAndy Fleming #include <linux/etherdevice.h>
2600db8189SAndy Fleming #include <linux/skbuff.h>
2700db8189SAndy Fleming #include <linux/spinlock.h>
2800db8189SAndy Fleming #include <linux/mm.h>
2900db8189SAndy Fleming #include <linux/module.h>
3000db8189SAndy Fleming #include <linux/mii.h>
3100db8189SAndy Fleming #include <linux/ethtool.h>
3200db8189SAndy Fleming #include <linux/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 M1145_DEV_FLAGS_RESISTANCE	0x00000001
5376884679SAndy Fleming 
5476884679SAndy Fleming #define MII_M1111_PHY_LED_CONTROL	0x18
5576884679SAndy Fleming #define MII_M1111_PHY_LED_DIRECT	0x4100
5676884679SAndy Fleming #define MII_M1111_PHY_LED_COMBINE	0x411c
57895ee682SKim Phillips #define MII_M1111_PHY_EXT_CR		0x14
58895ee682SKim Phillips #define MII_M1111_RX_DELAY		0x80
59895ee682SKim Phillips #define MII_M1111_TX_DELAY		0x2
60895ee682SKim Phillips #define MII_M1111_PHY_EXT_SR		0x1b
61895ee682SKim Phillips #define MII_M1111_HWCFG_MODE_MASK	0xf
62895ee682SKim Phillips #define MII_M1111_HWCFG_MODE_RGMII	0xb
6376884679SAndy Fleming 
6400db8189SAndy Fleming MODULE_DESCRIPTION("Marvell PHY driver");
6500db8189SAndy Fleming MODULE_AUTHOR("Andy Fleming");
6600db8189SAndy Fleming MODULE_LICENSE("GPL");
6700db8189SAndy Fleming 
6800db8189SAndy Fleming static int marvell_ack_interrupt(struct phy_device *phydev)
6900db8189SAndy Fleming {
7000db8189SAndy Fleming 	int err;
7100db8189SAndy Fleming 
7200db8189SAndy Fleming 	/* Clear the interrupts by reading the reg */
7300db8189SAndy Fleming 	err = phy_read(phydev, MII_M1011_IEVENT);
7400db8189SAndy Fleming 
7500db8189SAndy Fleming 	if (err < 0)
7600db8189SAndy Fleming 		return err;
7700db8189SAndy Fleming 
7800db8189SAndy Fleming 	return 0;
7900db8189SAndy Fleming }
8000db8189SAndy Fleming 
8100db8189SAndy Fleming static int marvell_config_intr(struct phy_device *phydev)
8200db8189SAndy Fleming {
8300db8189SAndy Fleming 	int err;
8400db8189SAndy Fleming 
8500db8189SAndy Fleming 	if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
8600db8189SAndy Fleming 		err = phy_write(phydev, MII_M1011_IMASK, MII_M1011_IMASK_INIT);
8700db8189SAndy Fleming 	else
8800db8189SAndy Fleming 		err = phy_write(phydev, MII_M1011_IMASK, MII_M1011_IMASK_CLEAR);
8900db8189SAndy Fleming 
9000db8189SAndy Fleming 	return err;
9100db8189SAndy Fleming }
9200db8189SAndy Fleming 
9300db8189SAndy Fleming static int marvell_config_aneg(struct phy_device *phydev)
9400db8189SAndy Fleming {
9500db8189SAndy Fleming 	int err;
9600db8189SAndy Fleming 
9700db8189SAndy Fleming 	/* The Marvell PHY has an errata which requires
9800db8189SAndy Fleming 	 * that certain registers get written in order
9900db8189SAndy Fleming 	 * to restart autonegotiation */
10000db8189SAndy Fleming 	err = phy_write(phydev, MII_BMCR, BMCR_RESET);
10100db8189SAndy Fleming 
10200db8189SAndy Fleming 	if (err < 0)
10300db8189SAndy Fleming 		return err;
10400db8189SAndy Fleming 
10500db8189SAndy Fleming 	err = phy_write(phydev, 0x1d, 0x1f);
10600db8189SAndy Fleming 	if (err < 0)
10700db8189SAndy Fleming 		return err;
10800db8189SAndy Fleming 
10900db8189SAndy Fleming 	err = phy_write(phydev, 0x1e, 0x200c);
11000db8189SAndy Fleming 	if (err < 0)
11100db8189SAndy Fleming 		return err;
11200db8189SAndy Fleming 
11300db8189SAndy Fleming 	err = phy_write(phydev, 0x1d, 0x5);
11400db8189SAndy Fleming 	if (err < 0)
11500db8189SAndy Fleming 		return err;
11600db8189SAndy Fleming 
11700db8189SAndy Fleming 	err = phy_write(phydev, 0x1e, 0);
11800db8189SAndy Fleming 	if (err < 0)
11900db8189SAndy Fleming 		return err;
12000db8189SAndy Fleming 
12100db8189SAndy Fleming 	err = phy_write(phydev, 0x1e, 0x100);
12200db8189SAndy Fleming 	if (err < 0)
12300db8189SAndy Fleming 		return err;
12400db8189SAndy Fleming 
12576884679SAndy Fleming 	err = phy_write(phydev, MII_M1011_PHY_SCR,
12676884679SAndy Fleming 			MII_M1011_PHY_SCR_AUTO_CROSS);
12776884679SAndy Fleming 	if (err < 0)
12876884679SAndy Fleming 		return err;
12976884679SAndy Fleming 
13076884679SAndy Fleming 	err = phy_write(phydev, MII_M1111_PHY_LED_CONTROL,
13176884679SAndy Fleming 			MII_M1111_PHY_LED_DIRECT);
13276884679SAndy Fleming 	if (err < 0)
13376884679SAndy Fleming 		return err;
13400db8189SAndy Fleming 
13500db8189SAndy Fleming 	err = genphy_config_aneg(phydev);
13600db8189SAndy Fleming 
13700db8189SAndy Fleming 	return err;
13800db8189SAndy Fleming }
13900db8189SAndy Fleming 
140895ee682SKim Phillips static int m88e1111_config_init(struct phy_device *phydev)
141895ee682SKim Phillips {
142895ee682SKim Phillips 	int err;
143895ee682SKim Phillips 
144895ee682SKim Phillips 	if ((phydev->interface == PHY_INTERFACE_MODE_RGMII) ||
145895ee682SKim Phillips 	    (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)) {
146895ee682SKim Phillips 		int temp;
147895ee682SKim Phillips 
148895ee682SKim Phillips 		if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) {
149895ee682SKim Phillips 			temp = phy_read(phydev, MII_M1111_PHY_EXT_CR);
150895ee682SKim Phillips 			if (temp < 0)
151895ee682SKim Phillips 				return temp;
152895ee682SKim Phillips 
153895ee682SKim Phillips 			temp |= (MII_M1111_RX_DELAY | MII_M1111_TX_DELAY);
154895ee682SKim Phillips 
155895ee682SKim Phillips 			err = phy_write(phydev, MII_M1111_PHY_EXT_CR, temp);
156895ee682SKim Phillips 			if (err < 0)
157895ee682SKim Phillips 				return err;
158895ee682SKim Phillips 		}
159895ee682SKim Phillips 
160895ee682SKim Phillips 		temp = phy_read(phydev, MII_M1111_PHY_EXT_SR);
161895ee682SKim Phillips 		if (temp < 0)
162895ee682SKim Phillips 			return temp;
163895ee682SKim Phillips 
164895ee682SKim Phillips 		temp &= ~(MII_M1111_HWCFG_MODE_MASK);
165895ee682SKim Phillips 		temp |= MII_M1111_HWCFG_MODE_RGMII;
166895ee682SKim Phillips 
167895ee682SKim Phillips 		err = phy_write(phydev, MII_M1111_PHY_EXT_SR, temp);
168895ee682SKim Phillips 		if (err < 0)
169895ee682SKim Phillips 			return err;
170895ee682SKim Phillips 	}
171895ee682SKim Phillips 
172895ee682SKim Phillips 	err = phy_write(phydev, MII_BMCR, BMCR_RESET);
173895ee682SKim Phillips 	if (err < 0)
174895ee682SKim Phillips 		return err;
175895ee682SKim Phillips 
176895ee682SKim Phillips 	return 0;
177895ee682SKim Phillips }
178895ee682SKim Phillips 
17976884679SAndy Fleming static int m88e1145_config_init(struct phy_device *phydev)
18076884679SAndy Fleming {
18176884679SAndy Fleming 	int err;
18276884679SAndy Fleming 
18376884679SAndy Fleming 	/* Take care of errata E0 & E1 */
18476884679SAndy Fleming 	err = phy_write(phydev, 0x1d, 0x001b);
18576884679SAndy Fleming 	if (err < 0)
18676884679SAndy Fleming 		return err;
18776884679SAndy Fleming 
18876884679SAndy Fleming 	err = phy_write(phydev, 0x1e, 0x418f);
18976884679SAndy Fleming 	if (err < 0)
19076884679SAndy Fleming 		return err;
19176884679SAndy Fleming 
19276884679SAndy Fleming 	err = phy_write(phydev, 0x1d, 0x0016);
19376884679SAndy Fleming 	if (err < 0)
19476884679SAndy Fleming 		return err;
19576884679SAndy Fleming 
19676884679SAndy Fleming 	err = phy_write(phydev, 0x1e, 0xa2da);
19776884679SAndy Fleming 	if (err < 0)
19876884679SAndy Fleming 		return err;
19976884679SAndy Fleming 
200895ee682SKim Phillips 	if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) {
20176884679SAndy Fleming 		int temp = phy_read(phydev, MII_M1145_PHY_EXT_CR);
20276884679SAndy Fleming 		if (temp < 0)
20376884679SAndy Fleming 			return temp;
20476884679SAndy Fleming 
20576884679SAndy Fleming 		temp |= (MII_M1145_RGMII_RX_DELAY | MII_M1145_RGMII_TX_DELAY);
20676884679SAndy Fleming 
20776884679SAndy Fleming 		err = phy_write(phydev, MII_M1145_PHY_EXT_CR, temp);
20876884679SAndy Fleming 		if (err < 0)
20976884679SAndy Fleming 			return err;
21076884679SAndy Fleming 
21176884679SAndy Fleming 		if (phydev->dev_flags & M1145_DEV_FLAGS_RESISTANCE) {
21276884679SAndy Fleming 			err = phy_write(phydev, 0x1d, 0x0012);
21376884679SAndy Fleming 			if (err < 0)
21476884679SAndy Fleming 				return err;
21576884679SAndy Fleming 
21676884679SAndy Fleming 			temp = phy_read(phydev, 0x1e);
21776884679SAndy Fleming 			if (temp < 0)
21876884679SAndy Fleming 				return temp;
21976884679SAndy Fleming 
22076884679SAndy Fleming 			temp &= 0xf03f;
22176884679SAndy Fleming 			temp |= 2 << 9;	/* 36 ohm */
22276884679SAndy Fleming 			temp |= 2 << 6;	/* 39 ohm */
22376884679SAndy Fleming 
22476884679SAndy Fleming 			err = phy_write(phydev, 0x1e, temp);
22576884679SAndy Fleming 			if (err < 0)
22676884679SAndy Fleming 				return err;
22776884679SAndy Fleming 
22876884679SAndy Fleming 			err = phy_write(phydev, 0x1d, 0x3);
22976884679SAndy Fleming 			if (err < 0)
23076884679SAndy Fleming 				return err;
23176884679SAndy Fleming 
23276884679SAndy Fleming 			err = phy_write(phydev, 0x1e, 0x8000);
23376884679SAndy Fleming 			if (err < 0)
23476884679SAndy Fleming 				return err;
23576884679SAndy Fleming 		}
23676884679SAndy Fleming 	}
23776884679SAndy Fleming 
23876884679SAndy Fleming 	return 0;
23976884679SAndy Fleming }
24000db8189SAndy Fleming 
24100db8189SAndy Fleming static struct phy_driver m88e1101_driver = {
24276884679SAndy Fleming 	.phy_id = 0x01410c60,
24376884679SAndy Fleming 	.phy_id_mask = 0xfffffff0,
24400db8189SAndy Fleming 	.name = "Marvell 88E1101",
24500db8189SAndy Fleming 	.features = PHY_GBIT_FEATURES,
24600db8189SAndy Fleming 	.flags = PHY_HAS_INTERRUPT,
24700db8189SAndy Fleming 	.config_aneg = &marvell_config_aneg,
24800db8189SAndy Fleming 	.read_status = &genphy_read_status,
24900db8189SAndy Fleming 	.ack_interrupt = &marvell_ack_interrupt,
25000db8189SAndy Fleming 	.config_intr = &marvell_config_intr,
25100db8189SAndy Fleming 	.driver = {.owner = THIS_MODULE,},
25200db8189SAndy Fleming };
25300db8189SAndy Fleming 
254895ee682SKim Phillips static struct phy_driver m88e1111_driver = {
25576884679SAndy Fleming 	.phy_id = 0x01410cc0,
25676884679SAndy Fleming 	.phy_id_mask = 0xfffffff0,
25776884679SAndy Fleming 	.name = "Marvell 88E1111",
25876884679SAndy Fleming 	.features = PHY_GBIT_FEATURES,
25976884679SAndy Fleming 	.flags = PHY_HAS_INTERRUPT,
26076884679SAndy Fleming 	.config_aneg = &marvell_config_aneg,
26176884679SAndy Fleming 	.read_status = &genphy_read_status,
26276884679SAndy Fleming 	.ack_interrupt = &marvell_ack_interrupt,
26376884679SAndy Fleming 	.config_intr = &marvell_config_intr,
264895ee682SKim Phillips 	.config_init = &m88e1111_config_init,
26576884679SAndy Fleming 	.driver = {.owner = THIS_MODULE,},
26676884679SAndy Fleming };
26776884679SAndy Fleming 
26876884679SAndy Fleming static struct phy_driver m88e1145_driver = {
26976884679SAndy Fleming 	.phy_id = 0x01410cd0,
27076884679SAndy Fleming 	.phy_id_mask = 0xfffffff0,
27176884679SAndy Fleming 	.name = "Marvell 88E1145",
27276884679SAndy Fleming 	.features = PHY_GBIT_FEATURES,
27376884679SAndy Fleming 	.flags = PHY_HAS_INTERRUPT,
27476884679SAndy Fleming 	.config_init = &m88e1145_config_init,
27576884679SAndy Fleming 	.config_aneg = &marvell_config_aneg,
27676884679SAndy Fleming 	.read_status = &genphy_read_status,
27776884679SAndy Fleming 	.ack_interrupt = &marvell_ack_interrupt,
27876884679SAndy Fleming 	.config_intr = &marvell_config_intr,
27976884679SAndy Fleming 	.driver = {.owner = THIS_MODULE,},
28076884679SAndy Fleming };
28176884679SAndy Fleming 
28200db8189SAndy Fleming static int __init marvell_init(void)
28300db8189SAndy Fleming {
28476884679SAndy Fleming 	int ret;
28576884679SAndy Fleming 
28676884679SAndy Fleming 	ret = phy_driver_register(&m88e1101_driver);
28776884679SAndy Fleming 	if (ret)
28876884679SAndy Fleming 		return ret;
28976884679SAndy Fleming 
290895ee682SKim Phillips 	ret = phy_driver_register(&m88e1111_driver);
29176884679SAndy Fleming 	if (ret)
292895ee682SKim Phillips 		goto err1111;
29376884679SAndy Fleming 
29476884679SAndy Fleming 	ret = phy_driver_register(&m88e1145_driver);
29576884679SAndy Fleming 	if (ret)
29676884679SAndy Fleming 		goto err1145;
29776884679SAndy Fleming 
29876884679SAndy Fleming 	return 0;
29976884679SAndy Fleming 
30076884679SAndy Fleming err1145:
301895ee682SKim Phillips 	phy_driver_unregister(&m88e1111_driver);
302895ee682SKim Phillips err1111:
30376884679SAndy Fleming 	phy_driver_unregister(&m88e1101_driver);
30476884679SAndy Fleming 	return ret;
30500db8189SAndy Fleming }
30600db8189SAndy Fleming 
30700db8189SAndy Fleming static void __exit marvell_exit(void)
30800db8189SAndy Fleming {
30900db8189SAndy Fleming 	phy_driver_unregister(&m88e1101_driver);
310895ee682SKim Phillips 	phy_driver_unregister(&m88e1111_driver);
31176884679SAndy Fleming 	phy_driver_unregister(&m88e1145_driver);
31200db8189SAndy Fleming }
31300db8189SAndy Fleming 
31400db8189SAndy Fleming module_init(marvell_init);
31500db8189SAndy Fleming module_exit(marvell_exit);
316