xref: /linux/drivers/net/phy/marvell.c (revision ed3174d93c342b8b2eeba6bbd124707d55304a7b)
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 #define MII_M1111_PHY_EXT_CR		0x14
58 #define MII_M1111_RX_DELAY		0x80
59 #define MII_M1111_TX_DELAY		0x2
60 #define MII_M1111_PHY_EXT_SR		0x1b
61 #define MII_M1111_HWCFG_MODE_MASK	0xf
62 #define MII_M1111_HWCFG_MODE_RGMII	0xb
63 #define MII_M1111_HWCFG_MODE_SGMII_NO_CLK	0x4
64 
65 MODULE_DESCRIPTION("Marvell PHY driver");
66 MODULE_AUTHOR("Andy Fleming");
67 MODULE_LICENSE("GPL");
68 
69 static int marvell_ack_interrupt(struct phy_device *phydev)
70 {
71 	int err;
72 
73 	/* Clear the interrupts by reading the reg */
74 	err = phy_read(phydev, MII_M1011_IEVENT);
75 
76 	if (err < 0)
77 		return err;
78 
79 	return 0;
80 }
81 
82 static int marvell_config_intr(struct phy_device *phydev)
83 {
84 	int err;
85 
86 	if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
87 		err = phy_write(phydev, MII_M1011_IMASK, MII_M1011_IMASK_INIT);
88 	else
89 		err = phy_write(phydev, MII_M1011_IMASK, MII_M1011_IMASK_CLEAR);
90 
91 	return err;
92 }
93 
94 static int marvell_config_aneg(struct phy_device *phydev)
95 {
96 	int err;
97 
98 	/* The Marvell PHY has an errata which requires
99 	 * that certain registers get written in order
100 	 * to restart autonegotiation */
101 	err = phy_write(phydev, MII_BMCR, BMCR_RESET);
102 
103 	if (err < 0)
104 		return err;
105 
106 	err = phy_write(phydev, 0x1d, 0x1f);
107 	if (err < 0)
108 		return err;
109 
110 	err = phy_write(phydev, 0x1e, 0x200c);
111 	if (err < 0)
112 		return err;
113 
114 	err = phy_write(phydev, 0x1d, 0x5);
115 	if (err < 0)
116 		return err;
117 
118 	err = phy_write(phydev, 0x1e, 0);
119 	if (err < 0)
120 		return err;
121 
122 	err = phy_write(phydev, 0x1e, 0x100);
123 	if (err < 0)
124 		return err;
125 
126 	err = phy_write(phydev, MII_M1011_PHY_SCR,
127 			MII_M1011_PHY_SCR_AUTO_CROSS);
128 	if (err < 0)
129 		return err;
130 
131 	err = phy_write(phydev, MII_M1111_PHY_LED_CONTROL,
132 			MII_M1111_PHY_LED_DIRECT);
133 	if (err < 0)
134 		return err;
135 
136 	err = genphy_config_aneg(phydev);
137 
138 	return err;
139 }
140 
141 static int m88e1111_config_init(struct phy_device *phydev)
142 {
143 	int err;
144 
145 	if ((phydev->interface == PHY_INTERFACE_MODE_RGMII) ||
146 	    (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) ||
147 	    (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) ||
148 	    (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)) {
149 		int temp;
150 
151 		temp = phy_read(phydev, MII_M1111_PHY_EXT_CR);
152 		if (temp < 0)
153 			return temp;
154 
155 		if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) {
156 			temp |= (MII_M1111_RX_DELAY | MII_M1111_TX_DELAY);
157 		} else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) {
158 			temp &= ~MII_M1111_TX_DELAY;
159 			temp |= MII_M1111_RX_DELAY;
160 		} else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) {
161 			temp &= ~MII_M1111_RX_DELAY;
162 			temp |= MII_M1111_TX_DELAY;
163 		}
164 
165 		err = phy_write(phydev, MII_M1111_PHY_EXT_CR, temp);
166 		if (err < 0)
167 			return err;
168 
169 		temp = phy_read(phydev, MII_M1111_PHY_EXT_SR);
170 		if (temp < 0)
171 			return temp;
172 
173 		temp &= ~(MII_M1111_HWCFG_MODE_MASK);
174 		temp |= MII_M1111_HWCFG_MODE_RGMII;
175 
176 		err = phy_write(phydev, MII_M1111_PHY_EXT_SR, temp);
177 		if (err < 0)
178 			return err;
179 	}
180 
181 	if (phydev->interface == PHY_INTERFACE_MODE_SGMII) {
182 		int temp;
183 
184 		temp = phy_read(phydev, MII_M1111_PHY_EXT_SR);
185 		if (temp < 0)
186 			return temp;
187 
188 		temp &= ~(MII_M1111_HWCFG_MODE_MASK);
189 		temp |= MII_M1111_HWCFG_MODE_SGMII_NO_CLK;
190 
191 		err = phy_write(phydev, MII_M1111_PHY_EXT_SR, temp);
192 		if (err < 0)
193 			return err;
194 	}
195 
196 	err = phy_write(phydev, MII_BMCR, BMCR_RESET);
197 	if (err < 0)
198 		return err;
199 
200 	return 0;
201 }
202 
203 static int m88e1145_config_init(struct phy_device *phydev)
204 {
205 	int err;
206 
207 	/* Take care of errata E0 & E1 */
208 	err = phy_write(phydev, 0x1d, 0x001b);
209 	if (err < 0)
210 		return err;
211 
212 	err = phy_write(phydev, 0x1e, 0x418f);
213 	if (err < 0)
214 		return err;
215 
216 	err = phy_write(phydev, 0x1d, 0x0016);
217 	if (err < 0)
218 		return err;
219 
220 	err = phy_write(phydev, 0x1e, 0xa2da);
221 	if (err < 0)
222 		return err;
223 
224 	if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) {
225 		int temp = phy_read(phydev, MII_M1145_PHY_EXT_CR);
226 		if (temp < 0)
227 			return temp;
228 
229 		temp |= (MII_M1145_RGMII_RX_DELAY | MII_M1145_RGMII_TX_DELAY);
230 
231 		err = phy_write(phydev, MII_M1145_PHY_EXT_CR, temp);
232 		if (err < 0)
233 			return err;
234 
235 		if (phydev->dev_flags & M1145_DEV_FLAGS_RESISTANCE) {
236 			err = phy_write(phydev, 0x1d, 0x0012);
237 			if (err < 0)
238 				return err;
239 
240 			temp = phy_read(phydev, 0x1e);
241 			if (temp < 0)
242 				return temp;
243 
244 			temp &= 0xf03f;
245 			temp |= 2 << 9;	/* 36 ohm */
246 			temp |= 2 << 6;	/* 39 ohm */
247 
248 			err = phy_write(phydev, 0x1e, temp);
249 			if (err < 0)
250 				return err;
251 
252 			err = phy_write(phydev, 0x1d, 0x3);
253 			if (err < 0)
254 				return err;
255 
256 			err = phy_write(phydev, 0x1e, 0x8000);
257 			if (err < 0)
258 				return err;
259 		}
260 	}
261 
262 	return 0;
263 }
264 
265 static struct phy_driver marvell_drivers[] = {
266 	{
267 		.phy_id = 0x01410c60,
268 		.phy_id_mask = 0xfffffff0,
269 		.name = "Marvell 88E1101",
270 		.features = PHY_GBIT_FEATURES,
271 		.flags = PHY_HAS_INTERRUPT,
272 		.config_aneg = &marvell_config_aneg,
273 		.read_status = &genphy_read_status,
274 		.ack_interrupt = &marvell_ack_interrupt,
275 		.config_intr = &marvell_config_intr,
276 		.driver = { .owner = THIS_MODULE },
277 	},
278 	{
279 		.phy_id = 0x01410c90,
280 		.phy_id_mask = 0xfffffff0,
281 		.name = "Marvell 88E1112",
282 		.features = PHY_GBIT_FEATURES,
283 		.flags = PHY_HAS_INTERRUPT,
284 		.config_init = &m88e1111_config_init,
285 		.config_aneg = &marvell_config_aneg,
286 		.read_status = &genphy_read_status,
287 		.ack_interrupt = &marvell_ack_interrupt,
288 		.config_intr = &marvell_config_intr,
289 		.driver = { .owner = THIS_MODULE },
290 	},
291 	{
292 		.phy_id = 0x01410cc0,
293 		.phy_id_mask = 0xfffffff0,
294 		.name = "Marvell 88E1111",
295 		.features = PHY_GBIT_FEATURES,
296 		.flags = PHY_HAS_INTERRUPT,
297 		.config_init = &m88e1111_config_init,
298 		.config_aneg = &marvell_config_aneg,
299 		.read_status = &genphy_read_status,
300 		.ack_interrupt = &marvell_ack_interrupt,
301 		.config_intr = &marvell_config_intr,
302 		.driver = { .owner = THIS_MODULE },
303 	},
304 	{
305 		.phy_id = 0x01410cd0,
306 		.phy_id_mask = 0xfffffff0,
307 		.name = "Marvell 88E1145",
308 		.features = PHY_GBIT_FEATURES,
309 		.flags = PHY_HAS_INTERRUPT,
310 		.config_init = &m88e1145_config_init,
311 		.config_aneg = &marvell_config_aneg,
312 		.read_status = &genphy_read_status,
313 		.ack_interrupt = &marvell_ack_interrupt,
314 		.config_intr = &marvell_config_intr,
315 		.driver = { .owner = THIS_MODULE },
316 	},
317 	{
318 		.phy_id = 0x01410e30,
319 		.phy_id_mask = 0xfffffff0,
320 		.name = "Marvell 88E1240",
321 		.features = PHY_GBIT_FEATURES,
322 		.flags = PHY_HAS_INTERRUPT,
323 		.config_init = &m88e1111_config_init,
324 		.config_aneg = &marvell_config_aneg,
325 		.read_status = &genphy_read_status,
326 		.ack_interrupt = &marvell_ack_interrupt,
327 		.config_intr = &marvell_config_intr,
328 		.driver = { .owner = THIS_MODULE },
329 	},
330 };
331 
332 static int __init marvell_init(void)
333 {
334 	int ret;
335 	int i;
336 
337 	for (i = 0; i < ARRAY_SIZE(marvell_drivers); i++) {
338 		ret = phy_driver_register(&marvell_drivers[i]);
339 
340 		if (ret) {
341 			while (i-- > 0)
342 				phy_driver_unregister(&marvell_drivers[i]);
343 			return ret;
344 		}
345 	}
346 
347 	return 0;
348 }
349 
350 static void __exit marvell_exit(void)
351 {
352 	int i;
353 
354 	for (i = 0; i < ARRAY_SIZE(marvell_drivers); i++)
355 		phy_driver_unregister(&marvell_drivers[i]);
356 }
357 
358 module_init(marvell_init);
359 module_exit(marvell_exit);
360