xref: /openbmc/u-boot/common/miiphyutil.c (revision 7481266e)
1 /*
2  * (C) Copyright 2001
3  * Gerald Van Baren, Custom IDEAS, vanbaren@cideas.com.
4  *
5  * See file CREDITS for list of people who contributed to this
6  * project.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License as
10  * published by the Free Software Foundation; either version 2 of
11  * the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21  * MA 02111-1307 USA
22  */
23 
24 /*
25  * This provides a bit-banged interface to the ethernet MII management
26  * channel.
27  */
28 
29 #include <common.h>
30 #include <miiphy.h>
31 
32 #if defined(CONFIG_MII) || (CONFIG_COMMANDS & CFG_CMD_MII)
33 #include <asm/types.h>
34 #include <linux/list.h>
35 #include <malloc.h>
36 #include <net.h>
37 
38 /* local debug macro */
39 #define MII_DEBUG
40 #undef MII_DEBUG
41 
42 #undef debug
43 #ifdef MII_DEBUG
44 #define debug(fmt,args...)	printf (fmt ,##args)
45 #else
46 #define debug(fmt,args...)
47 #endif /* MII_DEBUG */
48 
49 struct mii_dev {
50 	struct list_head link;
51 	char *name;
52 	int (* read)(char *devname, unsigned char addr,
53 			unsigned char reg, unsigned short *value);
54 	int (* write)(char *devname, unsigned char addr,
55 			unsigned char reg, unsigned short value);
56 };
57 
58 static struct list_head mii_devs;
59 static struct mii_dev *current_mii;
60 
61 /*****************************************************************************
62  *
63  * Initialize global data. Need to be called before any other miiphy routine.
64  */
65 void miiphy_init()
66 {
67 		INIT_LIST_HEAD(&mii_devs);
68 		current_mii = NULL;
69 }
70 
71 /*****************************************************************************
72  *
73  * Register read and write MII access routines for the device <name>.
74  */
75 void miiphy_register(char *name,
76 		int (* read)(char *devname, unsigned char addr,
77 			unsigned char reg, unsigned short *value),
78 		int (* write)(char *devname, unsigned char addr,
79 			unsigned char reg, unsigned short value))
80 {
81 	struct list_head *entry;
82 	struct mii_dev *new_dev;
83 	struct mii_dev *miidev;
84 	unsigned int name_len;
85 
86 	/* check if we have unique name */
87 	list_for_each(entry, &mii_devs) {
88 		miidev = list_entry(entry, struct mii_dev, link);
89 		if (strcmp(miidev->name, name) == 0) {
90 			printf("miiphy_register: non unique device name '%s'\n",
91 					name);
92 			return;
93 		}
94 	}
95 
96 	/* allocate memory */
97 	name_len = strlen(name);
98 	new_dev = (struct mii_dev *)malloc(sizeof(struct mii_dev) + name_len + 1);
99 
100 	if(new_dev == NULL) {
101 		printf("miiphy_register: cannot allocate memory for '%s'\n",
102 				name);
103 		return;
104 	}
105 	memset(new_dev, 0, sizeof(struct mii_dev) + name_len);
106 
107 	/* initalize mii_dev struct fields */
108 	INIT_LIST_HEAD(&new_dev->link);
109 	new_dev->read = read;
110 	new_dev->write = write;
111 	new_dev->name = (char *)(new_dev + 1);
112 	strncpy(new_dev->name, name, name_len);
113 	new_dev->name[name_len] = '\0';
114 
115 	debug("miiphy_register: added '%s', read=0x%08lx, write=0x%08lx\n",
116 			new_dev->name, new_dev->read, new_dev->write);
117 
118 	/* add it to the list */
119 	list_add_tail(&new_dev->link, &mii_devs);
120 
121 	if (!current_mii)
122 		current_mii = new_dev;
123 }
124 
125 int miiphy_set_current_dev(char *devname)
126 {
127 	struct list_head *entry;
128 	struct mii_dev *dev;
129 
130 	list_for_each(entry, &mii_devs) {
131 		dev = list_entry(entry, struct mii_dev, link);
132 
133 		if (strcmp(devname, dev->name) == 0) {
134 			current_mii = dev;
135 			return 0;
136 		}
137 	}
138 
139 	printf("No such device: %s\n", devname);
140 	return 1;
141 }
142 
143 char *miiphy_get_current_dev()
144 {
145 	if (current_mii)
146 		return current_mii->name;
147 
148 	return NULL;
149 }
150 
151 /*****************************************************************************
152  *
153  * Read to variable <value> from the PHY attached to device <devname>,
154  * use PHY address <addr> and register <reg>.
155  *
156  * Returns:
157  *   0 on success
158  */
159 int miiphy_read(char *devname, unsigned char addr, unsigned char reg,
160 		unsigned short *value)
161 {
162 	struct list_head *entry;
163 	struct mii_dev *dev;
164 	int found_dev = 0;
165 	int read_ret = 0;
166 
167 	if (!devname) {
168 		printf("NULL device name!\n");
169 		return 1;
170 	}
171 
172 	list_for_each(entry, &mii_devs) {
173 		dev = list_entry(entry, struct mii_dev, link);
174 
175 		if (strcmp(devname, dev->name) == 0) {
176 			found_dev = 1;
177 			read_ret = dev->read(devname, addr, reg, value);
178 			break;
179 		}
180 	}
181 
182 	if (found_dev == 0)
183 		printf("No such device: %s\n", devname);
184 
185 	return ((found_dev) ? read_ret : 1);
186 }
187 
188 /*****************************************************************************
189  *
190  * Write <value> to the PHY attached to device <devname>,
191  * use PHY address <addr> and register <reg>.
192  *
193  * Returns:
194  *   0 on success
195  */
196 int miiphy_write(char *devname, unsigned char addr, unsigned char reg,
197 		unsigned short value)
198 {
199 	struct list_head *entry;
200 	struct mii_dev *dev;
201 	int found_dev = 0;
202 	int write_ret = 0;
203 
204 	if (!devname) {
205 		printf("NULL device name!\n");
206 		return 1;
207 	}
208 
209 	list_for_each(entry, &mii_devs) {
210 		dev = list_entry(entry, struct mii_dev, link);
211 
212 		if (strcmp(devname, dev->name) == 0) {
213 			found_dev = 1;
214 			write_ret = dev->write(devname, addr, reg, value);
215 			break;
216 		}
217 	}
218 
219 	if (found_dev == 0)
220 		printf("No such device: %s\n", devname);
221 
222 	return ((found_dev) ? write_ret : 1);
223 }
224 
225 /*****************************************************************************
226  *
227  * Print out list of registered MII capable devices.
228  */
229 void miiphy_listdev(void)
230 {
231 	struct list_head *entry;
232 	struct mii_dev *dev;
233 
234 	puts("MII devices: ");
235 	list_for_each(entry, &mii_devs) {
236 		dev = list_entry(entry, struct mii_dev, link);
237 		printf("'%s' ", dev->name);
238 	}
239 	puts("\n");
240 
241 	if (current_mii)
242 		printf("Current device: '%s'\n", current_mii->name);
243 }
244 
245 
246 /*****************************************************************************
247  *
248  * Read the OUI, manufacture's model number, and revision number.
249  *
250  * OUI:     22 bits (unsigned int)
251  * Model:    6 bits (unsigned char)
252  * Revision: 4 bits (unsigned char)
253  *
254  * Returns:
255  *   0 on success
256  */
257 int miiphy_info (char *devname,
258 		 unsigned char addr,
259 		 unsigned int *oui,
260 		 unsigned char *model, unsigned char *rev)
261 {
262 	unsigned int reg = 0;
263 	unsigned short tmp;
264 
265 	if (miiphy_read (devname, addr, PHY_PHYIDR2, &tmp) != 0) {
266 #ifdef DEBUG
267 		puts ("PHY ID register 2 read failed\n");
268 #endif
269 		return (-1);
270 	}
271 	reg = tmp;
272 
273 #ifdef DEBUG
274 	printf ("PHY_PHYIDR2 @ 0x%x = 0x%04x\n", addr, reg);
275 #endif
276 	if (reg == 0xFFFF) {
277 		/* No physical device present at this address */
278 		return (-1);
279 	}
280 
281 	if (miiphy_read (devname, addr, PHY_PHYIDR1, &tmp) != 0) {
282 #ifdef DEBUG
283 		puts ("PHY ID register 1 read failed\n");
284 #endif
285 		return (-1);
286 	}
287 	reg |= tmp << 16;
288 #ifdef DEBUG
289 	printf ("PHY_PHYIDR[1,2] @ 0x%x = 0x%08x\n", addr, reg);
290 #endif
291 	*oui   =                 ( reg >> 10);
292 	*model = (unsigned char) ((reg >>  4) & 0x0000003F);
293 	*rev   = (unsigned char) ( reg        & 0x0000000F);
294 	return (0);
295 }
296 
297 
298 /*****************************************************************************
299  *
300  * Reset the PHY.
301  * Returns:
302  *   0 on success
303  */
304 int miiphy_reset (char *devname, unsigned char addr)
305 {
306 	unsigned short reg;
307 	int loop_cnt;
308 
309 	if (miiphy_read (devname, addr, PHY_BMCR, &reg) != 0) {
310 #ifdef DEBUG
311 		printf ("PHY status read failed\n");
312 #endif
313 		return (-1);
314 	}
315 	if (miiphy_write (devname, addr, PHY_BMCR, reg | 0x8000) != 0) {
316 #ifdef DEBUG
317 		puts ("PHY reset failed\n");
318 #endif
319 		return (-1);
320 	}
321 #ifdef CONFIG_PHY_RESET_DELAY
322 	udelay (CONFIG_PHY_RESET_DELAY);	/* Intel LXT971A needs this */
323 #endif
324 	/*
325 	 * Poll the control register for the reset bit to go to 0 (it is
326 	 * auto-clearing).  This should happen within 0.5 seconds per the
327 	 * IEEE spec.
328 	 */
329 	loop_cnt = 0;
330 	reg = 0x8000;
331 	while (((reg & 0x8000) != 0) && (loop_cnt++ < 1000000)) {
332 		if (miiphy_read (devname, addr, PHY_BMCR, &reg) != 0) {
333 #     ifdef DEBUG
334 			puts ("PHY status read failed\n");
335 #     endif
336 			return (-1);
337 		}
338 	}
339 	if ((reg & 0x8000) == 0) {
340 		return (0);
341 	} else {
342 		puts ("PHY reset timed out\n");
343 		return (-1);
344 	}
345 	return (0);
346 }
347 
348 
349 /*****************************************************************************
350  *
351  * Determine the ethernet speed (10/100).
352  */
353 int miiphy_speed (char *devname, unsigned char addr)
354 {
355 	unsigned short reg;
356 
357 #if defined(CONFIG_PHY_GIGE)
358 	if (miiphy_read (devname, addr, PHY_1000BTSR, &reg)) {
359 		printf ("PHY 1000BT Status read failed\n");
360 	} else {
361 		if (reg != 0xFFFF) {
362 			if ((reg & (PHY_1000BTSR_1000FD | PHY_1000BTSR_1000HD)) !=0) {
363 				return (_1000BASET);
364 			}
365 		}
366 	}
367 #endif /* CONFIG_PHY_GIGE */
368 
369 	/* Check Basic Management Control Register first. */
370 	if (miiphy_read (devname, addr, PHY_BMCR, &reg)) {
371 		puts ("PHY speed read failed, assuming 10bT\n");
372 		return (_10BASET);
373 	}
374 	/* Check if auto-negotiation is on. */
375 	if ((reg & PHY_BMCR_AUTON) != 0) {
376 		/* Get auto-negotiation results. */
377 		if (miiphy_read (devname, addr, PHY_ANLPAR, &reg)) {
378 			puts ("PHY AN speed read failed, assuming 10bT\n");
379 			return (_10BASET);
380 		}
381 		if ((reg & PHY_ANLPAR_100) != 0) {
382 			return (_100BASET);
383 		} else {
384 			return (_10BASET);
385 		}
386 	}
387 	/* Get speed from basic control settings. */
388 	else if (reg & PHY_BMCR_100MB) {
389 		return (_100BASET);
390 	} else {
391 		return (_10BASET);
392 	}
393 
394 }
395 
396 
397 /*****************************************************************************
398  *
399  * Determine full/half duplex.
400  */
401 int miiphy_duplex (char *devname, unsigned char addr)
402 {
403 	unsigned short reg;
404 
405 #if defined(CONFIG_PHY_GIGE)
406 	if (miiphy_read (devname, addr, PHY_1000BTSR, &reg)) {
407 		printf ("PHY 1000BT Status read failed\n");
408 	} else {
409 		if ( (reg != 0xFFFF) &&
410 		     (reg & (PHY_1000BTSR_1000FD | PHY_1000BTSR_1000HD)) ) {
411 			if ((reg & PHY_1000BTSR_1000FD) !=0) {
412 				return (FULL);
413 			} else {
414 				return (HALF);
415 			}
416 		}
417 	}
418 #endif /* CONFIG_PHY_GIGE */
419 
420 	/* Check Basic Management Control Register first. */
421 	if (miiphy_read (devname, addr, PHY_BMCR, &reg)) {
422 		puts ("PHY duplex read failed, assuming half duplex\n");
423 		return (HALF);
424 	}
425 	/* Check if auto-negotiation is on. */
426 	if ((reg & PHY_BMCR_AUTON) != 0) {
427 		/* Get auto-negotiation results. */
428 		if (miiphy_read (devname, addr, PHY_ANLPAR, &reg)) {
429 			puts ("PHY AN duplex read failed, assuming half duplex\n");
430 			return (HALF);
431 		}
432 
433 		if ((reg & (PHY_ANLPAR_10FD | PHY_ANLPAR_TXFD)) != 0) {
434 			return (FULL);
435 		} else {
436 			return (HALF);
437 		}
438 	}
439 	/* Get speed from basic control settings. */
440 	else if (reg & PHY_BMCR_DPLX) {
441 		return (FULL);
442 	} else {
443 		return (HALF);
444 	}
445 
446 }
447 
448 #ifdef CFG_FAULT_ECHO_LINK_DOWN
449 /*****************************************************************************
450  *
451  * Determine link status
452  */
453 int miiphy_link (char *devname, unsigned char addr)
454 {
455 	unsigned short reg;
456 
457 	/* dummy read; needed to latch some phys */
458 	(void)miiphy_read(devname, addr, PHY_BMSR, &reg);
459 	if (miiphy_read (devname, addr, PHY_BMSR, &reg)) {
460 		puts ("PHY_BMSR read failed, assuming no link\n");
461 		return (0);
462 	}
463 
464 	/* Determine if a link is active */
465 	if ((reg & PHY_BMSR_LS) != 0) {
466 		return (1);
467 	} else {
468 		return (0);
469 	}
470 }
471 #endif
472 
473 #endif /* CONFIG_MII || (CONFIG_COMMANDS & CFG_CMD_MII) */
474