xref: /linux/drivers/net/phy/marvell.c (revision 2b8232ce512105e28453f301d1510de8363bccd1)
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 		int temp;
148 
149 		if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) {
150 			temp = phy_read(phydev, MII_M1111_PHY_EXT_CR);
151 			if (temp < 0)
152 				return temp;
153 
154 			temp |= (MII_M1111_RX_DELAY | MII_M1111_TX_DELAY);
155 
156 			err = phy_write(phydev, MII_M1111_PHY_EXT_CR, temp);
157 			if (err < 0)
158 				return err;
159 		}
160 
161 		temp = phy_read(phydev, MII_M1111_PHY_EXT_SR);
162 		if (temp < 0)
163 			return temp;
164 
165 		temp &= ~(MII_M1111_HWCFG_MODE_MASK);
166 		temp |= MII_M1111_HWCFG_MODE_RGMII;
167 
168 		err = phy_write(phydev, MII_M1111_PHY_EXT_SR, temp);
169 		if (err < 0)
170 			return err;
171 	}
172 
173 	if (phydev->interface == PHY_INTERFACE_MODE_SGMII) {
174 		int temp;
175 
176 		temp = phy_read(phydev, MII_M1111_PHY_EXT_SR);
177 		if (temp < 0)
178 			return temp;
179 
180 		temp &= ~(MII_M1111_HWCFG_MODE_MASK);
181 		temp |= MII_M1111_HWCFG_MODE_SGMII_NO_CLK;
182 
183 		err = phy_write(phydev, MII_M1111_PHY_EXT_SR, temp);
184 		if (err < 0)
185 			return err;
186 	}
187 
188 	err = phy_write(phydev, MII_BMCR, BMCR_RESET);
189 	if (err < 0)
190 		return err;
191 
192 	return 0;
193 }
194 
195 static int m88e1145_config_init(struct phy_device *phydev)
196 {
197 	int err;
198 
199 	/* Take care of errata E0 & E1 */
200 	err = phy_write(phydev, 0x1d, 0x001b);
201 	if (err < 0)
202 		return err;
203 
204 	err = phy_write(phydev, 0x1e, 0x418f);
205 	if (err < 0)
206 		return err;
207 
208 	err = phy_write(phydev, 0x1d, 0x0016);
209 	if (err < 0)
210 		return err;
211 
212 	err = phy_write(phydev, 0x1e, 0xa2da);
213 	if (err < 0)
214 		return err;
215 
216 	if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) {
217 		int temp = phy_read(phydev, MII_M1145_PHY_EXT_CR);
218 		if (temp < 0)
219 			return temp;
220 
221 		temp |= (MII_M1145_RGMII_RX_DELAY | MII_M1145_RGMII_TX_DELAY);
222 
223 		err = phy_write(phydev, MII_M1145_PHY_EXT_CR, temp);
224 		if (err < 0)
225 			return err;
226 
227 		if (phydev->dev_flags & M1145_DEV_FLAGS_RESISTANCE) {
228 			err = phy_write(phydev, 0x1d, 0x0012);
229 			if (err < 0)
230 				return err;
231 
232 			temp = phy_read(phydev, 0x1e);
233 			if (temp < 0)
234 				return temp;
235 
236 			temp &= 0xf03f;
237 			temp |= 2 << 9;	/* 36 ohm */
238 			temp |= 2 << 6;	/* 39 ohm */
239 
240 			err = phy_write(phydev, 0x1e, temp);
241 			if (err < 0)
242 				return err;
243 
244 			err = phy_write(phydev, 0x1d, 0x3);
245 			if (err < 0)
246 				return err;
247 
248 			err = phy_write(phydev, 0x1e, 0x8000);
249 			if (err < 0)
250 				return err;
251 		}
252 	}
253 
254 	return 0;
255 }
256 
257 static struct phy_driver marvell_drivers[] = {
258 	{
259 		.phy_id = 0x01410c60,
260 		.phy_id_mask = 0xfffffff0,
261 		.name = "Marvell 88E1101",
262 		.features = PHY_GBIT_FEATURES,
263 		.flags = PHY_HAS_INTERRUPT,
264 		.config_aneg = &marvell_config_aneg,
265 		.read_status = &genphy_read_status,
266 		.ack_interrupt = &marvell_ack_interrupt,
267 		.config_intr = &marvell_config_intr,
268 		.driver = {.owner = THIS_MODULE,},
269 	},
270 	{
271 		.phy_id = 0x01410c90,
272 		.phy_id_mask = 0xfffffff0,
273 		.name = "Marvell 88E1112",
274 		.features = PHY_GBIT_FEATURES,
275 		.flags = PHY_HAS_INTERRUPT,
276 		.config_init = &m88e1111_config_init,
277 		.config_aneg = &marvell_config_aneg,
278 		.read_status = &genphy_read_status,
279 		.ack_interrupt = &marvell_ack_interrupt,
280 		.config_intr = &marvell_config_intr,
281 		.driver = {.owner = THIS_MODULE,},
282 	},
283 	{
284 		.phy_id = 0x01410cc0,
285 		.phy_id_mask = 0xfffffff0,
286 		.name = "Marvell 88E1111",
287 		.features = PHY_GBIT_FEATURES,
288 		.flags = PHY_HAS_INTERRUPT,
289 		.config_init = &m88e1111_config_init,
290 		.config_aneg = &marvell_config_aneg,
291 		.read_status = &genphy_read_status,
292 		.ack_interrupt = &marvell_ack_interrupt,
293 		.config_intr = &marvell_config_intr,
294 		.driver = {.owner = THIS_MODULE,},
295 	},
296 	{
297 		.phy_id = 0x01410cd0,
298 		.phy_id_mask = 0xfffffff0,
299 		.name = "Marvell 88E1145",
300 		.features = PHY_GBIT_FEATURES,
301 		.flags = PHY_HAS_INTERRUPT,
302 		.config_init = &m88e1145_config_init,
303 		.config_aneg = &marvell_config_aneg,
304 		.read_status = &genphy_read_status,
305 		.ack_interrupt = &marvell_ack_interrupt,
306 		.config_intr = &marvell_config_intr,
307 		.driver = {.owner = THIS_MODULE,},
308 	}
309 };
310 
311 static int __init marvell_init(void)
312 {
313 	int ret;
314 	int i;
315 
316 	for (i = 0; i < ARRAY_SIZE(marvell_drivers); i++) {
317 		ret = phy_driver_register(&marvell_drivers[i]);
318 
319 		if (ret) {
320 			while (i-- > 0)
321 				phy_driver_unregister(&marvell_drivers[i]);
322 			return ret;
323 		}
324 	}
325 
326 	return 0;
327 }
328 
329 static void __exit marvell_exit(void)
330 {
331 	int i;
332 
333 	for (i = 0; i < ARRAY_SIZE(marvell_drivers); i++)
334 		phy_driver_unregister(&marvell_drivers[i]);
335 }
336 
337 module_init(marvell_init);
338 module_exit(marvell_exit);
339