xref: /linux/drivers/net/phy/marvell.c (revision c537b994505099b7197e7d3125b942ecbcc51eb6)
1 /*
2  * drivers/net/phy/marvell.c
3  *
4  * Driver for Marvell PHYs
5  *
6  * Author: Andy Fleming
7  *
8  * Copyright (c) 2004 Freescale Semiconductor, Inc.
9  *
10  * This program is free software; you can redistribute  it and/or modify it
11  * under  the terms of  the GNU General  Public License as published by the
12  * Free Software Foundation;  either version 2 of the  License, or (at your
13  * option) any later version.
14  *
15  */
16 #include <linux/kernel.h>
17 #include <linux/string.h>
18 #include <linux/errno.h>
19 #include <linux/unistd.h>
20 #include <linux/slab.h>
21 #include <linux/interrupt.h>
22 #include <linux/init.h>
23 #include <linux/delay.h>
24 #include <linux/netdevice.h>
25 #include <linux/etherdevice.h>
26 #include <linux/skbuff.h>
27 #include <linux/spinlock.h>
28 #include <linux/mm.h>
29 #include <linux/module.h>
30 #include <linux/mii.h>
31 #include <linux/ethtool.h>
32 #include <linux/phy.h>
33 
34 #include <asm/io.h>
35 #include <asm/irq.h>
36 #include <asm/uaccess.h>
37 
38 #define MII_M1011_IEVENT		0x13
39 #define MII_M1011_IEVENT_CLEAR		0x0000
40 
41 #define MII_M1011_IMASK			0x12
42 #define MII_M1011_IMASK_INIT		0x6400
43 #define MII_M1011_IMASK_CLEAR		0x0000
44 
45 #define MII_M1011_PHY_SCR		0x10
46 #define MII_M1011_PHY_SCR_AUTO_CROSS	0x0060
47 
48 #define MII_M1145_PHY_EXT_CR		0x14
49 #define MII_M1145_RGMII_RX_DELAY	0x0080
50 #define MII_M1145_RGMII_TX_DELAY	0x0002
51 
52 #define M1145_DEV_FLAGS_RESISTANCE	0x00000001
53 
54 #define MII_M1111_PHY_LED_CONTROL	0x18
55 #define MII_M1111_PHY_LED_DIRECT	0x4100
56 #define MII_M1111_PHY_LED_COMBINE	0x411c
57 
58 MODULE_DESCRIPTION("Marvell PHY driver");
59 MODULE_AUTHOR("Andy Fleming");
60 MODULE_LICENSE("GPL");
61 
62 static int marvell_ack_interrupt(struct phy_device *phydev)
63 {
64 	int err;
65 
66 	/* Clear the interrupts by reading the reg */
67 	err = phy_read(phydev, MII_M1011_IEVENT);
68 
69 	if (err < 0)
70 		return err;
71 
72 	return 0;
73 }
74 
75 static int marvell_config_intr(struct phy_device *phydev)
76 {
77 	int err;
78 
79 	if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
80 		err = phy_write(phydev, MII_M1011_IMASK, MII_M1011_IMASK_INIT);
81 	else
82 		err = phy_write(phydev, MII_M1011_IMASK, MII_M1011_IMASK_CLEAR);
83 
84 	return err;
85 }
86 
87 static int marvell_config_aneg(struct phy_device *phydev)
88 {
89 	int err;
90 
91 	/* The Marvell PHY has an errata which requires
92 	 * that certain registers get written in order
93 	 * to restart autonegotiation */
94 	err = phy_write(phydev, MII_BMCR, BMCR_RESET);
95 
96 	if (err < 0)
97 		return err;
98 
99 	err = phy_write(phydev, 0x1d, 0x1f);
100 	if (err < 0)
101 		return err;
102 
103 	err = phy_write(phydev, 0x1e, 0x200c);
104 	if (err < 0)
105 		return err;
106 
107 	err = phy_write(phydev, 0x1d, 0x5);
108 	if (err < 0)
109 		return err;
110 
111 	err = phy_write(phydev, 0x1e, 0);
112 	if (err < 0)
113 		return err;
114 
115 	err = phy_write(phydev, 0x1e, 0x100);
116 	if (err < 0)
117 		return err;
118 
119 	err = phy_write(phydev, MII_M1011_PHY_SCR,
120 			MII_M1011_PHY_SCR_AUTO_CROSS);
121 	if (err < 0)
122 		return err;
123 
124 	err = phy_write(phydev, MII_M1111_PHY_LED_CONTROL,
125 			MII_M1111_PHY_LED_DIRECT);
126 	if (err < 0)
127 		return err;
128 
129 	err = genphy_config_aneg(phydev);
130 
131 	return err;
132 }
133 
134 static int m88e1145_config_init(struct phy_device *phydev)
135 {
136 	int err;
137 
138 	/* Take care of errata E0 & E1 */
139 	err = phy_write(phydev, 0x1d, 0x001b);
140 	if (err < 0)
141 		return err;
142 
143 	err = phy_write(phydev, 0x1e, 0x418f);
144 	if (err < 0)
145 		return err;
146 
147 	err = phy_write(phydev, 0x1d, 0x0016);
148 	if (err < 0)
149 		return err;
150 
151 	err = phy_write(phydev, 0x1e, 0xa2da);
152 	if (err < 0)
153 		return err;
154 
155 	if (phydev->interface == PHY_INTERFACE_MODE_RGMII) {
156 		int temp = phy_read(phydev, MII_M1145_PHY_EXT_CR);
157 		if (temp < 0)
158 			return temp;
159 
160 		temp |= (MII_M1145_RGMII_RX_DELAY | MII_M1145_RGMII_TX_DELAY);
161 
162 		err = phy_write(phydev, MII_M1145_PHY_EXT_CR, temp);
163 		if (err < 0)
164 			return err;
165 
166 		if (phydev->dev_flags & M1145_DEV_FLAGS_RESISTANCE) {
167 			err = phy_write(phydev, 0x1d, 0x0012);
168 			if (err < 0)
169 				return err;
170 
171 			temp = phy_read(phydev, 0x1e);
172 			if (temp < 0)
173 				return temp;
174 
175 			temp &= 0xf03f;
176 			temp |= 2 << 9;	/* 36 ohm */
177 			temp |= 2 << 6;	/* 39 ohm */
178 
179 			err = phy_write(phydev, 0x1e, temp);
180 			if (err < 0)
181 				return err;
182 
183 			err = phy_write(phydev, 0x1d, 0x3);
184 			if (err < 0)
185 				return err;
186 
187 			err = phy_write(phydev, 0x1e, 0x8000);
188 			if (err < 0)
189 				return err;
190 		}
191 	}
192 
193 	return 0;
194 }
195 
196 static struct phy_driver m88e1101_driver = {
197 	.phy_id = 0x01410c60,
198 	.phy_id_mask = 0xfffffff0,
199 	.name = "Marvell 88E1101",
200 	.features = PHY_GBIT_FEATURES,
201 	.flags = PHY_HAS_INTERRUPT,
202 	.config_aneg = &marvell_config_aneg,
203 	.read_status = &genphy_read_status,
204 	.ack_interrupt = &marvell_ack_interrupt,
205 	.config_intr = &marvell_config_intr,
206 	.driver = {.owner = THIS_MODULE,},
207 };
208 
209 static struct phy_driver m88e1111s_driver = {
210 	.phy_id = 0x01410cc0,
211 	.phy_id_mask = 0xfffffff0,
212 	.name = "Marvell 88E1111",
213 	.features = PHY_GBIT_FEATURES,
214 	.flags = PHY_HAS_INTERRUPT,
215 	.config_aneg = &marvell_config_aneg,
216 	.read_status = &genphy_read_status,
217 	.ack_interrupt = &marvell_ack_interrupt,
218 	.config_intr = &marvell_config_intr,
219 	.driver = {.owner = THIS_MODULE,},
220 };
221 
222 static struct phy_driver m88e1145_driver = {
223 	.phy_id = 0x01410cd0,
224 	.phy_id_mask = 0xfffffff0,
225 	.name = "Marvell 88E1145",
226 	.features = PHY_GBIT_FEATURES,
227 	.flags = PHY_HAS_INTERRUPT,
228 	.config_init = &m88e1145_config_init,
229 	.config_aneg = &marvell_config_aneg,
230 	.read_status = &genphy_read_status,
231 	.ack_interrupt = &marvell_ack_interrupt,
232 	.config_intr = &marvell_config_intr,
233 	.driver = {.owner = THIS_MODULE,},
234 };
235 
236 static int __init marvell_init(void)
237 {
238 	int ret;
239 
240 	ret = phy_driver_register(&m88e1101_driver);
241 	if (ret)
242 		return ret;
243 
244 	ret = phy_driver_register(&m88e1111s_driver);
245 	if (ret)
246 		goto err1111s;
247 
248 	ret = phy_driver_register(&m88e1145_driver);
249 	if (ret)
250 		goto err1145;
251 
252 	return 0;
253 
254       err1145:
255 	phy_driver_unregister(&m88e1111s_driver);
256       err1111s:
257 	phy_driver_unregister(&m88e1101_driver);
258 	return ret;
259 }
260 
261 static void __exit marvell_exit(void)
262 {
263 	phy_driver_unregister(&m88e1101_driver);
264 	phy_driver_unregister(&m88e1111s_driver);
265 	phy_driver_unregister(&m88e1145_driver);
266 }
267 
268 module_init(marvell_init);
269 module_exit(marvell_exit);
270