• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * drivers/net/ibm_newemac/phy.c
3  *
4  * Driver for PowerPC 4xx on-chip ethernet controller, PHY support.
5  * Borrowed from sungem_phy.c, though I only kept the generic MII
6  * driver for now.
7  *
8  * This file should be shared with other drivers or eventually
9  * merged as the "low level" part of miilib
10  *
11  * Copyright 2007 Benjamin Herrenschmidt, IBM Corp.
12  *                <benh@kernel.crashing.org>
13  *
14  * Based on the arch/ppc version of the driver:
15  *
16  * (c) 2003, Benjamin Herrenscmidt (benh@kernel.crashing.org)
17  * (c) 2004-2005, Eugene Surovegin <ebs@ebshome.net>
18  *
19  */
20 #include <linux/module.h>
21 #include <linux/kernel.h>
22 #include <linux/types.h>
23 #include <linux/netdevice.h>
24 #include <linux/mii.h>
25 #include <linux/ethtool.h>
26 #include <linux/delay.h>
27 
28 #include "emac.h"
29 #include "phy.h"
30 
phy_read(struct mii_phy * phy,int reg)31 static inline int phy_read(struct mii_phy *phy, int reg)
32 {
33 	return phy->mdio_read(phy->dev, phy->address, reg);
34 }
35 
phy_write(struct mii_phy * phy,int reg,int val)36 static inline void phy_write(struct mii_phy *phy, int reg, int val)
37 {
38 	phy->mdio_write(phy->dev, phy->address, reg, val);
39 }
40 
gpcs_phy_read(struct mii_phy * phy,int reg)41 static inline int gpcs_phy_read(struct mii_phy *phy, int reg)
42 {
43 	return phy->mdio_read(phy->dev, phy->gpcs_address, reg);
44 }
45 
gpcs_phy_write(struct mii_phy * phy,int reg,int val)46 static inline void gpcs_phy_write(struct mii_phy *phy, int reg, int val)
47 {
48 	phy->mdio_write(phy->dev, phy->gpcs_address, reg, val);
49 }
50 
emac_mii_reset_phy(struct mii_phy * phy)51 int emac_mii_reset_phy(struct mii_phy *phy)
52 {
53 	int val;
54 	int limit = 10000;
55 
56 	val = phy_read(phy, MII_BMCR);
57 	val &= ~(BMCR_ISOLATE | BMCR_ANENABLE);
58 	val |= BMCR_RESET;
59 	phy_write(phy, MII_BMCR, val);
60 
61 	udelay(300);
62 
63 	while (--limit) {
64 		val = phy_read(phy, MII_BMCR);
65 		if (val >= 0 && (val & BMCR_RESET) == 0)
66 			break;
67 		udelay(10);
68 	}
69 	if ((val & BMCR_ISOLATE) && limit > 0)
70 		phy_write(phy, MII_BMCR, val & ~BMCR_ISOLATE);
71 
72 	return limit <= 0;
73 }
74 
emac_mii_reset_gpcs(struct mii_phy * phy)75 int emac_mii_reset_gpcs(struct mii_phy *phy)
76 {
77 	int val;
78 	int limit = 10000;
79 
80 	val = gpcs_phy_read(phy, MII_BMCR);
81 	val &= ~(BMCR_ISOLATE | BMCR_ANENABLE);
82 	val |= BMCR_RESET;
83 	gpcs_phy_write(phy, MII_BMCR, val);
84 
85 	udelay(300);
86 
87 	while (--limit) {
88 		val = gpcs_phy_read(phy, MII_BMCR);
89 		if (val >= 0 && (val & BMCR_RESET) == 0)
90 			break;
91 		udelay(10);
92 	}
93 	if ((val & BMCR_ISOLATE) && limit > 0)
94 		gpcs_phy_write(phy, MII_BMCR, val & ~BMCR_ISOLATE);
95 
96 	if (limit > 0 && phy->mode == PHY_MODE_SGMII) {
97 		/* Configure GPCS interface to recommended setting for SGMII */
98 		gpcs_phy_write(phy, 0x04, 0x8120); /* AsymPause, FDX */
99 		gpcs_phy_write(phy, 0x07, 0x2801); /* msg_pg, toggle */
100 		gpcs_phy_write(phy, 0x00, 0x0140); /* 1Gbps, FDX     */
101 	}
102 
103 	return limit <= 0;
104 }
105 
genmii_setup_aneg(struct mii_phy * phy,u32 advertise)106 static int genmii_setup_aneg(struct mii_phy *phy, u32 advertise)
107 {
108 	int ctl, adv;
109 
110 	phy->autoneg = AUTONEG_ENABLE;
111 	phy->speed = SPEED_10;
112 	phy->duplex = DUPLEX_HALF;
113 	phy->pause = phy->asym_pause = 0;
114 	phy->advertising = advertise;
115 
116 	ctl = phy_read(phy, MII_BMCR);
117 	if (ctl < 0)
118 		return ctl;
119 	ctl &= ~(BMCR_FULLDPLX | BMCR_SPEED100 | BMCR_SPEED1000 | BMCR_ANENABLE);
120 
121 	/* First clear the PHY */
122 	phy_write(phy, MII_BMCR, ctl);
123 
124 	/* Setup standard advertise */
125 	adv = phy_read(phy, MII_ADVERTISE);
126 	if (adv < 0)
127 		return adv;
128 	adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4 | ADVERTISE_PAUSE_CAP |
129 		 ADVERTISE_PAUSE_ASYM);
130 	if (advertise & ADVERTISED_10baseT_Half)
131 		adv |= ADVERTISE_10HALF;
132 	if (advertise & ADVERTISED_10baseT_Full)
133 		adv |= ADVERTISE_10FULL;
134 	if (advertise & ADVERTISED_100baseT_Half)
135 		adv |= ADVERTISE_100HALF;
136 	if (advertise & ADVERTISED_100baseT_Full)
137 		adv |= ADVERTISE_100FULL;
138 	if (advertise & ADVERTISED_Pause)
139 		adv |= ADVERTISE_PAUSE_CAP;
140 	if (advertise & ADVERTISED_Asym_Pause)
141 		adv |= ADVERTISE_PAUSE_ASYM;
142 	phy_write(phy, MII_ADVERTISE, adv);
143 
144 	if (phy->features &
145 	    (SUPPORTED_1000baseT_Full | SUPPORTED_1000baseT_Half)) {
146 		adv = phy_read(phy, MII_CTRL1000);
147 		if (adv < 0)
148 			return adv;
149 		adv &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF);
150 		if (advertise & ADVERTISED_1000baseT_Full)
151 			adv |= ADVERTISE_1000FULL;
152 		if (advertise & ADVERTISED_1000baseT_Half)
153 			adv |= ADVERTISE_1000HALF;
154 		phy_write(phy, MII_CTRL1000, adv);
155 	}
156 
157 	/* Start/Restart aneg */
158 	ctl = phy_read(phy, MII_BMCR);
159 	ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
160 	phy_write(phy, MII_BMCR, ctl);
161 
162 	return 0;
163 }
164 
genmii_setup_forced(struct mii_phy * phy,int speed,int fd)165 static int genmii_setup_forced(struct mii_phy *phy, int speed, int fd)
166 {
167 	int ctl;
168 
169 	phy->autoneg = AUTONEG_DISABLE;
170 	phy->speed = speed;
171 	phy->duplex = fd;
172 	phy->pause = phy->asym_pause = 0;
173 
174 	ctl = phy_read(phy, MII_BMCR);
175 	if (ctl < 0)
176 		return ctl;
177 	ctl &= ~(BMCR_FULLDPLX | BMCR_SPEED100 | BMCR_SPEED1000 | BMCR_ANENABLE);
178 
179 	/* First clear the PHY */
180 	phy_write(phy, MII_BMCR, ctl | BMCR_RESET);
181 
182 	/* Select speed & duplex */
183 	switch (speed) {
184 	case SPEED_10:
185 		break;
186 	case SPEED_100:
187 		ctl |= BMCR_SPEED100;
188 		break;
189 	case SPEED_1000:
190 		ctl |= BMCR_SPEED1000;
191 		break;
192 	default:
193 		return -EINVAL;
194 	}
195 	if (fd == DUPLEX_FULL)
196 		ctl |= BMCR_FULLDPLX;
197 	phy_write(phy, MII_BMCR, ctl);
198 
199 	return 0;
200 }
201 
genmii_poll_link(struct mii_phy * phy)202 static int genmii_poll_link(struct mii_phy *phy)
203 {
204 	int status;
205 
206 	/* Clear latched value with dummy read */
207 	phy_read(phy, MII_BMSR);
208 	status = phy_read(phy, MII_BMSR);
209 	if (status < 0 || (status & BMSR_LSTATUS) == 0)
210 		return 0;
211 	if (phy->autoneg == AUTONEG_ENABLE && !(status & BMSR_ANEGCOMPLETE))
212 		return 0;
213 	return 1;
214 }
215 
genmii_read_link(struct mii_phy * phy)216 static int genmii_read_link(struct mii_phy *phy)
217 {
218 	if (phy->autoneg == AUTONEG_ENABLE) {
219 		int glpa = 0;
220 		int lpa = phy_read(phy, MII_LPA) & phy_read(phy, MII_ADVERTISE);
221 		if (lpa < 0)
222 			return lpa;
223 
224 		if (phy->features &
225 		    (SUPPORTED_1000baseT_Full | SUPPORTED_1000baseT_Half)) {
226 			int adv = phy_read(phy, MII_CTRL1000);
227 			glpa = phy_read(phy, MII_STAT1000);
228 
229 			if (glpa < 0 || adv < 0)
230 				return adv;
231 
232 			glpa &= adv << 2;
233 		}
234 
235 		phy->speed = SPEED_10;
236 		phy->duplex = DUPLEX_HALF;
237 		phy->pause = phy->asym_pause = 0;
238 
239 		if (glpa & (LPA_1000FULL | LPA_1000HALF)) {
240 			phy->speed = SPEED_1000;
241 			if (glpa & LPA_1000FULL)
242 				phy->duplex = DUPLEX_FULL;
243 		} else if (lpa & (LPA_100FULL | LPA_100HALF)) {
244 			phy->speed = SPEED_100;
245 			if (lpa & LPA_100FULL)
246 				phy->duplex = DUPLEX_FULL;
247 		} else if (lpa & LPA_10FULL)
248 			phy->duplex = DUPLEX_FULL;
249 
250 		if (phy->duplex == DUPLEX_FULL) {
251 			phy->pause = lpa & LPA_PAUSE_CAP ? 1 : 0;
252 			phy->asym_pause = lpa & LPA_PAUSE_ASYM ? 1 : 0;
253 		}
254 	} else {
255 		int bmcr = phy_read(phy, MII_BMCR);
256 		if (bmcr < 0)
257 			return bmcr;
258 
259 		if (bmcr & BMCR_FULLDPLX)
260 			phy->duplex = DUPLEX_FULL;
261 		else
262 			phy->duplex = DUPLEX_HALF;
263 		if (bmcr & BMCR_SPEED1000)
264 			phy->speed = SPEED_1000;
265 		else if (bmcr & BMCR_SPEED100)
266 			phy->speed = SPEED_100;
267 		else
268 			phy->speed = SPEED_10;
269 
270 		phy->pause = phy->asym_pause = 0;
271 	}
272 	return 0;
273 }
274 
275 /* Generic implementation for most 10/100/1000 PHYs */
276 static struct mii_phy_ops generic_phy_ops = {
277 	.setup_aneg	= genmii_setup_aneg,
278 	.setup_forced	= genmii_setup_forced,
279 	.poll_link	= genmii_poll_link,
280 	.read_link	= genmii_read_link
281 };
282 
283 static struct mii_phy_def genmii_phy_def = {
284 	.phy_id		= 0x00000000,
285 	.phy_id_mask	= 0x00000000,
286 	.name		= "Generic MII",
287 	.ops		= &generic_phy_ops
288 };
289 
290 /* CIS8201 */
291 #define MII_CIS8201_10BTCSR	0x16
292 #define  TENBTCSR_ECHO_DISABLE	0x2000
293 #define MII_CIS8201_EPCR	0x17
294 #define  EPCR_MODE_MASK		0x3000
295 #define  EPCR_GMII_MODE		0x0000
296 #define  EPCR_RGMII_MODE	0x1000
297 #define  EPCR_TBI_MODE		0x2000
298 #define  EPCR_RTBI_MODE		0x3000
299 #define MII_CIS8201_ACSR	0x1c
300 #define  ACSR_PIN_PRIO_SELECT	0x0004
301 
cis8201_init(struct mii_phy * phy)302 static int cis8201_init(struct mii_phy *phy)
303 {
304 	int epcr;
305 
306 	epcr = phy_read(phy, MII_CIS8201_EPCR);
307 	if (epcr < 0)
308 		return epcr;
309 
310 	epcr &= ~EPCR_MODE_MASK;
311 
312 	switch (phy->mode) {
313 	case PHY_MODE_TBI:
314 		epcr |= EPCR_TBI_MODE;
315 		break;
316 	case PHY_MODE_RTBI:
317 		epcr |= EPCR_RTBI_MODE;
318 		break;
319 	case PHY_MODE_GMII:
320 		epcr |= EPCR_GMII_MODE;
321 		break;
322 	case PHY_MODE_RGMII:
323 	default:
324 		epcr |= EPCR_RGMII_MODE;
325 	}
326 
327 	phy_write(phy, MII_CIS8201_EPCR, epcr);
328 
329 	/* MII regs override strap pins */
330 	phy_write(phy, MII_CIS8201_ACSR,
331 		  phy_read(phy, MII_CIS8201_ACSR) | ACSR_PIN_PRIO_SELECT);
332 
333 	/* Disable TX_EN -> CRS echo mode, otherwise 10/HDX doesn't work */
334 	phy_write(phy, MII_CIS8201_10BTCSR,
335 		  phy_read(phy, MII_CIS8201_10BTCSR) | TENBTCSR_ECHO_DISABLE);
336 
337 	return 0;
338 }
339 
340 static struct mii_phy_ops cis8201_phy_ops = {
341 	.init		= cis8201_init,
342 	.setup_aneg	= genmii_setup_aneg,
343 	.setup_forced	= genmii_setup_forced,
344 	.poll_link	= genmii_poll_link,
345 	.read_link	= genmii_read_link
346 };
347 
348 static struct mii_phy_def cis8201_phy_def = {
349 	.phy_id		= 0x000fc410,
350 	.phy_id_mask	= 0x000ffff0,
351 	.name		= "CIS8201 Gigabit Ethernet",
352 	.ops		= &cis8201_phy_ops
353 };
354 
355 static struct mii_phy_def bcm5248_phy_def = {
356 
357 	.phy_id		= 0x0143bc00,
358 	.phy_id_mask	= 0x0ffffff0,
359 	.name		= "BCM5248 10/100 SMII Ethernet",
360 	.ops		= &generic_phy_ops
361 };
362 
m88e1111_init(struct mii_phy * phy)363 static int m88e1111_init(struct mii_phy *phy)
364 {
365 	pr_debug("%s: Marvell 88E1111 Ethernet\n", __func__);
366 	phy_write(phy, 0x14, 0x0ce3);
367 	phy_write(phy, 0x18, 0x4101);
368 	phy_write(phy, 0x09, 0x0e00);
369 	phy_write(phy, 0x04, 0x01e1);
370 	phy_write(phy, 0x00, 0x9140);
371 	phy_write(phy, 0x00, 0x1140);
372 
373 	return  0;
374 }
375 
m88e1112_init(struct mii_phy * phy)376 static int m88e1112_init(struct mii_phy *phy)
377 {
378 	/*
379 	 * Marvell 88E1112 PHY needs to have the SGMII MAC
380 	 * interace (page 2) properly configured to
381 	 * communicate with the 460EX/GT GPCS interface.
382 	 */
383 
384 	u16 reg_short;
385 
386 	pr_debug("%s: Marvell 88E1112 Ethernet\n", __func__);
387 
388 	/* Set access to Page 2 */
389 	phy_write(phy, 0x16, 0x0002);
390 
391 	phy_write(phy, 0x00, 0x0040); /* 1Gbps */
392 	reg_short = (u16)(phy_read(phy, 0x1a));
393 	reg_short |= 0x8000; /* bypass Auto-Negotiation */
394 	phy_write(phy, 0x1a, reg_short);
395 	emac_mii_reset_phy(phy); /* reset MAC interface */
396 
397 	/* Reset access to Page 0 */
398 	phy_write(phy, 0x16, 0x0000);
399 
400 	return  0;
401 }
402 
et1011c_init(struct mii_phy * phy)403 static int et1011c_init(struct mii_phy *phy)
404 {
405 	u16 reg_short;
406 
407 	reg_short = (u16)(phy_read(phy, 0x16));
408 	reg_short &= ~(0x7);
409 	reg_short |= 0x6;	/* RGMII Trace Delay*/
410 	phy_write(phy, 0x16, reg_short);
411 
412 	reg_short = (u16)(phy_read(phy, 0x17));
413 	reg_short &= ~(0x40);
414 	phy_write(phy, 0x17, reg_short);
415 
416 	phy_write(phy, 0x1c, 0x74f0);
417 	return 0;
418 }
419 
420 static struct mii_phy_ops et1011c_phy_ops = {
421 	.init		= et1011c_init,
422 	.setup_aneg	= genmii_setup_aneg,
423 	.setup_forced	= genmii_setup_forced,
424 	.poll_link	= genmii_poll_link,
425 	.read_link	= genmii_read_link
426 };
427 
428 static struct mii_phy_def et1011c_phy_def = {
429 	.phy_id		= 0x0282f000,
430 	.phy_id_mask	= 0x0fffff00,
431 	.name		= "ET1011C Gigabit Ethernet",
432 	.ops		= &et1011c_phy_ops
433 };
434 
435 
436 
437 
438 
439 static struct mii_phy_ops m88e1111_phy_ops = {
440 	.init		= m88e1111_init,
441 	.setup_aneg	= genmii_setup_aneg,
442 	.setup_forced	= genmii_setup_forced,
443 	.poll_link	= genmii_poll_link,
444 	.read_link	= genmii_read_link
445 };
446 
447 static struct mii_phy_def m88e1111_phy_def = {
448 
449 	.phy_id		= 0x01410CC0,
450 	.phy_id_mask	= 0x0ffffff0,
451 	.name		= "Marvell 88E1111 Ethernet",
452 	.ops		= &m88e1111_phy_ops,
453 };
454 
455 static struct mii_phy_ops m88e1112_phy_ops = {
456 	.init		= m88e1112_init,
457 	.setup_aneg	= genmii_setup_aneg,
458 	.setup_forced	= genmii_setup_forced,
459 	.poll_link	= genmii_poll_link,
460 	.read_link	= genmii_read_link
461 };
462 
463 static struct mii_phy_def m88e1112_phy_def = {
464 	.phy_id		= 0x01410C90,
465 	.phy_id_mask	= 0x0ffffff0,
466 	.name		= "Marvell 88E1112 Ethernet",
467 	.ops		= &m88e1112_phy_ops,
468 };
469 
470 static struct mii_phy_def *mii_phy_table[] = {
471 	&et1011c_phy_def,
472 	&cis8201_phy_def,
473 	&bcm5248_phy_def,
474 	&m88e1111_phy_def,
475 	&m88e1112_phy_def,
476 	&genmii_phy_def,
477 	NULL
478 };
479 
emac_mii_phy_probe(struct mii_phy * phy,int address)480 int emac_mii_phy_probe(struct mii_phy *phy, int address)
481 {
482 	struct mii_phy_def *def;
483 	int i;
484 	u32 id;
485 
486 	phy->autoneg = AUTONEG_DISABLE;
487 	phy->advertising = 0;
488 	phy->address = address;
489 	phy->speed = SPEED_10;
490 	phy->duplex = DUPLEX_HALF;
491 	phy->pause = phy->asym_pause = 0;
492 
493 	/* Take PHY out of isolate mode and reset it. */
494 	if (emac_mii_reset_phy(phy))
495 		return -ENODEV;
496 
497 	/* Read ID and find matching entry */
498 	id = (phy_read(phy, MII_PHYSID1) << 16) | phy_read(phy, MII_PHYSID2);
499 	for (i = 0; (def = mii_phy_table[i]) != NULL; i++)
500 		if ((id & def->phy_id_mask) == def->phy_id)
501 			break;
502 	/* Should never be NULL (we have a generic entry), but... */
503 	if (!def)
504 		return -ENODEV;
505 
506 	phy->def = def;
507 
508 	/* Determine PHY features if needed */
509 	phy->features = def->features;
510 	if (!phy->features) {
511 		u16 bmsr = phy_read(phy, MII_BMSR);
512 		if (bmsr & BMSR_ANEGCAPABLE)
513 			phy->features |= SUPPORTED_Autoneg;
514 		if (bmsr & BMSR_10HALF)
515 			phy->features |= SUPPORTED_10baseT_Half;
516 		if (bmsr & BMSR_10FULL)
517 			phy->features |= SUPPORTED_10baseT_Full;
518 		if (bmsr & BMSR_100HALF)
519 			phy->features |= SUPPORTED_100baseT_Half;
520 		if (bmsr & BMSR_100FULL)
521 			phy->features |= SUPPORTED_100baseT_Full;
522 		if (bmsr & BMSR_ESTATEN) {
523 			u16 esr = phy_read(phy, MII_ESTATUS);
524 			if (esr & ESTATUS_1000_TFULL)
525 				phy->features |= SUPPORTED_1000baseT_Full;
526 			if (esr & ESTATUS_1000_THALF)
527 				phy->features |= SUPPORTED_1000baseT_Half;
528 		}
529 		phy->features |= SUPPORTED_MII;
530 	}
531 
532 	/* Setup default advertising */
533 	phy->advertising = phy->features;
534 
535 	return 0;
536 }
537 
538 MODULE_LICENSE("GPL");
539