]> git.ipfire.org Git - people/ms/u-boot.git/blame - common/miiphyutil.c
Merge git://git.denx.de/u-boot-marvell
[people/ms/u-boot.git] / common / miiphyutil.c
CommitLineData
c609719b
WD
1/*
2 * (C) Copyright 2001
3 * Gerald Van Baren, Custom IDEAS, vanbaren@cideas.com.
4 *
1a459660 5 * SPDX-License-Identifier: GPL-2.0+
c609719b
WD
6 */
7
8/*
9 * This provides a bit-banged interface to the ethernet MII management
10 * channel.
11 */
12
13#include <common.h>
c74c8e66 14#include <dm.h>
c609719b 15#include <miiphy.h>
5f184715 16#include <phy.h>
c609719b 17
63ff004c
MB
18#include <asm/types.h>
19#include <linux/list.h>
20#include <malloc.h>
21#include <net.h>
22
23/* local debug macro */
63ff004c
MB
24#undef MII_DEBUG
25
26#undef debug
27#ifdef MII_DEBUG
16a53238 28#define debug(fmt, args...) printf(fmt, ##args)
63ff004c 29#else
16a53238 30#define debug(fmt, args...)
63ff004c
MB
31#endif /* MII_DEBUG */
32
63ff004c
MB
33static struct list_head mii_devs;
34static struct mii_dev *current_mii;
35
0daac978
MF
36/*
37 * Lookup the mii_dev struct by the registered device name.
38 */
5f184715 39struct mii_dev *miiphy_get_dev_by_name(const char *devname)
0daac978
MF
40{
41 struct list_head *entry;
42 struct mii_dev *dev;
43
44 if (!devname) {
45 printf("NULL device name!\n");
46 return NULL;
47 }
48
49 list_for_each(entry, &mii_devs) {
50 dev = list_entry(entry, struct mii_dev, link);
51 if (strcmp(dev->name, devname) == 0)
52 return dev;
53 }
54
0daac978
MF
55 return NULL;
56}
57
d9785c14
MB
58/*****************************************************************************
59 *
60 * Initialize global data. Need to be called before any other miiphy routine.
61 */
5700bb63 62void miiphy_init(void)
d9785c14 63{
16a53238 64 INIT_LIST_HEAD(&mii_devs);
298035df 65 current_mii = NULL;
d9785c14
MB
66}
67
5f184715
AF
68static int legacy_miiphy_read(struct mii_dev *bus, int addr, int devad, int reg)
69{
70 unsigned short val;
71 int ret;
72 struct legacy_mii_dev *ldev = bus->priv;
73
74 ret = ldev->read(bus->name, addr, reg, &val);
75
76 return ret ? -1 : (int)val;
77}
78
79static int legacy_miiphy_write(struct mii_dev *bus, int addr, int devad,
80 int reg, u16 val)
81{
82 struct legacy_mii_dev *ldev = bus->priv;
83
84 return ldev->write(bus->name, addr, reg, val);
85}
86
63ff004c
MB
87/*****************************************************************************
88 *
89 * Register read and write MII access routines for the device <name>.
1cdabc4b 90 * This API is now deprecated. Please use mdio_alloc and mdio_register, instead.
63ff004c 91 */
5700bb63 92void miiphy_register(const char *name,
16a53238 93 int (*read)(const char *devname, unsigned char addr,
f915c931 94 unsigned char reg, unsigned short *value),
16a53238 95 int (*write)(const char *devname, unsigned char addr,
f915c931 96 unsigned char reg, unsigned short value))
63ff004c 97{
63ff004c 98 struct mii_dev *new_dev;
5f184715 99 struct legacy_mii_dev *ldev;
07c07635
LW
100
101 BUG_ON(strlen(name) >= MDIO_NAME_LEN);
63ff004c 102
63ff004c 103 /* check if we have unique name */
5f184715 104 new_dev = miiphy_get_dev_by_name(name);
0daac978
MF
105 if (new_dev) {
106 printf("miiphy_register: non unique device name '%s'\n", name);
107 return;
63ff004c
MB
108 }
109
110 /* allocate memory */
5f184715
AF
111 new_dev = mdio_alloc();
112 ldev = malloc(sizeof(*ldev));
63ff004c 113
5f184715 114 if (new_dev == NULL || ldev == NULL) {
16a53238 115 printf("miiphy_register: cannot allocate memory for '%s'\n",
298035df 116 name);
63ff004c
MB
117 return;
118 }
63ff004c
MB
119
120 /* initalize mii_dev struct fields */
5f184715
AF
121 new_dev->read = legacy_miiphy_read;
122 new_dev->write = legacy_miiphy_write;
07c07635
LW
123 strncpy(new_dev->name, name, MDIO_NAME_LEN);
124 new_dev->name[MDIO_NAME_LEN - 1] = 0;
5f184715
AF
125 ldev->read = read;
126 ldev->write = write;
127 new_dev->priv = ldev;
63ff004c 128
16a53238 129 debug("miiphy_register: added '%s', read=0x%08lx, write=0x%08lx\n",
5f184715 130 new_dev->name, ldev->read, ldev->write);
63ff004c
MB
131
132 /* add it to the list */
16a53238 133 list_add_tail(&new_dev->link, &mii_devs);
63ff004c
MB
134
135 if (!current_mii)
136 current_mii = new_dev;
137}
138
5f184715
AF
139struct mii_dev *mdio_alloc(void)
140{
141 struct mii_dev *bus;
142
143 bus = malloc(sizeof(*bus));
144 if (!bus)
145 return bus;
146
147 memset(bus, 0, sizeof(*bus));
148
149 /* initalize mii_dev struct fields */
150 INIT_LIST_HEAD(&bus->link);
151
152 return bus;
153}
154
155int mdio_register(struct mii_dev *bus)
156{
157 if (!bus || !bus->name || !bus->read || !bus->write)
158 return -1;
159
160 /* check if we have unique name */
161 if (miiphy_get_dev_by_name(bus->name)) {
162 printf("mdio_register: non unique device name '%s'\n",
163 bus->name);
164 return -1;
165 }
166
167 /* add it to the list */
168 list_add_tail(&bus->link, &mii_devs);
169
170 if (!current_mii)
171 current_mii = bus;
172
173 return 0;
174}
175
176void mdio_list_devices(void)
177{
178 struct list_head *entry;
179
180 list_for_each(entry, &mii_devs) {
181 int i;
182 struct mii_dev *bus = list_entry(entry, struct mii_dev, link);
183
184 printf("%s:\n", bus->name);
185
186 for (i = 0; i < PHY_MAX_ADDR; i++) {
187 struct phy_device *phydev = bus->phymap[i];
188
189 if (phydev) {
190 printf("%d - %s", i, phydev->drv->name);
191
192 if (phydev->dev)
193 printf(" <--> %s\n", phydev->dev->name);
194 else
195 printf("\n");
196 }
197 }
198 }
199}
200
5700bb63 201int miiphy_set_current_dev(const char *devname)
63ff004c 202{
63ff004c
MB
203 struct mii_dev *dev;
204
5f184715 205 dev = miiphy_get_dev_by_name(devname);
0daac978
MF
206 if (dev) {
207 current_mii = dev;
208 return 0;
63ff004c
MB
209 }
210
5f184715
AF
211 printf("No such device: %s\n", devname);
212
63ff004c
MB
213 return 1;
214}
215
5f184715
AF
216struct mii_dev *mdio_get_current_dev(void)
217{
218 return current_mii;
219}
220
221struct phy_device *mdio_phydev_for_ethname(const char *ethname)
222{
223 struct list_head *entry;
224 struct mii_dev *bus;
225
226 list_for_each(entry, &mii_devs) {
227 int i;
228 bus = list_entry(entry, struct mii_dev, link);
229
230 for (i = 0; i < PHY_MAX_ADDR; i++) {
231 if (!bus->phymap[i] || !bus->phymap[i]->dev)
232 continue;
233
234 if (strcmp(bus->phymap[i]->dev->name, ethname) == 0)
235 return bus->phymap[i];
236 }
237 }
238
239 printf("%s is not a known ethernet\n", ethname);
240 return NULL;
241}
242
5700bb63 243const char *miiphy_get_current_dev(void)
63ff004c
MB
244{
245 if (current_mii)
246 return current_mii->name;
247
248 return NULL;
249}
250
ede16ea3
MF
251static struct mii_dev *miiphy_get_active_dev(const char *devname)
252{
253 /* If the current mii is the one we want, return it */
254 if (current_mii)
255 if (strcmp(current_mii->name, devname) == 0)
256 return current_mii;
257
258 /* Otherwise, set the active one to the one we want */
259 if (miiphy_set_current_dev(devname))
260 return NULL;
261 else
262 return current_mii;
263}
264
63ff004c
MB
265/*****************************************************************************
266 *
267 * Read to variable <value> from the PHY attached to device <devname>,
268 * use PHY address <addr> and register <reg>.
269 *
1cdabc4b
AF
270 * This API is deprecated. Use phy_read on a phy_device found via phy_connect
271 *
63ff004c
MB
272 * Returns:
273 * 0 on success
274 */
f915c931 275int miiphy_read(const char *devname, unsigned char addr, unsigned char reg,
298035df 276 unsigned short *value)
63ff004c 277{
5f184715 278 struct mii_dev *bus;
d67d5d52 279 int ret;
63ff004c 280
5f184715 281 bus = miiphy_get_active_dev(devname);
d67d5d52 282 if (!bus)
5f184715 283 return 1;
63ff004c 284
d67d5d52
AG
285 ret = bus->read(bus, addr, MDIO_DEVAD_NONE, reg);
286 if (ret < 0)
287 return 1;
288
289 *value = (unsigned short)ret;
290 return 0;
63ff004c
MB
291}
292
293/*****************************************************************************
294 *
295 * Write <value> to the PHY attached to device <devname>,
296 * use PHY address <addr> and register <reg>.
297 *
1cdabc4b
AF
298 * This API is deprecated. Use phy_write on a phy_device found by phy_connect
299 *
63ff004c
MB
300 * Returns:
301 * 0 on success
302 */
f915c931 303int miiphy_write(const char *devname, unsigned char addr, unsigned char reg,
298035df 304 unsigned short value)
63ff004c 305{
5f184715 306 struct mii_dev *bus;
63ff004c 307
5f184715
AF
308 bus = miiphy_get_active_dev(devname);
309 if (bus)
310 return bus->write(bus, addr, MDIO_DEVAD_NONE, reg, value);
63ff004c 311
0daac978 312 return 1;
63ff004c
MB
313}
314
315/*****************************************************************************
316 *
317 * Print out list of registered MII capable devices.
318 */
16a53238 319void miiphy_listdev(void)
63ff004c
MB
320{
321 struct list_head *entry;
322 struct mii_dev *dev;
323
16a53238
AF
324 puts("MII devices: ");
325 list_for_each(entry, &mii_devs) {
326 dev = list_entry(entry, struct mii_dev, link);
327 printf("'%s' ", dev->name);
63ff004c 328 }
16a53238 329 puts("\n");
63ff004c
MB
330
331 if (current_mii)
16a53238 332 printf("Current device: '%s'\n", current_mii->name);
63ff004c
MB
333}
334
c609719b
WD
335/*****************************************************************************
336 *
337 * Read the OUI, manufacture's model number, and revision number.
338 *
339 * OUI: 22 bits (unsigned int)
340 * Model: 6 bits (unsigned char)
341 * Revision: 4 bits (unsigned char)
342 *
1cdabc4b
AF
343 * This API is deprecated.
344 *
c609719b
WD
345 * Returns:
346 * 0 on success
347 */
5700bb63 348int miiphy_info(const char *devname, unsigned char addr, unsigned int *oui,
c609719b
WD
349 unsigned char *model, unsigned char *rev)
350{
351 unsigned int reg = 0;
8bf3b005 352 unsigned short tmp;
c609719b 353
16a53238
AF
354 if (miiphy_read(devname, addr, MII_PHYSID2, &tmp) != 0) {
355 debug("PHY ID register 2 read failed\n");
356 return -1;
c609719b 357 }
8bf3b005 358 reg = tmp;
c609719b 359
16a53238 360 debug("MII_PHYSID2 @ 0x%x = 0x%04x\n", addr, reg);
26c7bab8 361
c609719b
WD
362 if (reg == 0xFFFF) {
363 /* No physical device present at this address */
16a53238 364 return -1;
c609719b
WD
365 }
366
16a53238
AF
367 if (miiphy_read(devname, addr, MII_PHYSID1, &tmp) != 0) {
368 debug("PHY ID register 1 read failed\n");
369 return -1;
c609719b 370 }
8bf3b005 371 reg |= tmp << 16;
16a53238 372 debug("PHY_PHYIDR[1,2] @ 0x%x = 0x%08x\n", addr, reg);
26c7bab8 373
298035df
LJ
374 *oui = (reg >> 10);
375 *model = (unsigned char)((reg >> 4) & 0x0000003F);
376 *rev = (unsigned char)(reg & 0x0000000F);
16a53238 377 return 0;
c609719b
WD
378}
379
5f184715 380#ifndef CONFIG_PHYLIB
c609719b
WD
381/*****************************************************************************
382 *
383 * Reset the PHY.
1cdabc4b
AF
384 *
385 * This API is deprecated. Use PHYLIB.
386 *
c609719b
WD
387 * Returns:
388 * 0 on success
389 */
5700bb63 390int miiphy_reset(const char *devname, unsigned char addr)
c609719b
WD
391{
392 unsigned short reg;
ab5a0dcb 393 int timeout = 500;
c609719b 394
16a53238
AF
395 if (miiphy_read(devname, addr, MII_BMCR, &reg) != 0) {
396 debug("PHY status read failed\n");
397 return -1;
f89920c3 398 }
16a53238
AF
399 if (miiphy_write(devname, addr, MII_BMCR, reg | BMCR_RESET) != 0) {
400 debug("PHY reset failed\n");
401 return -1;
c609719b 402 }
5653fc33 403#ifdef CONFIG_PHY_RESET_DELAY
16a53238 404 udelay(CONFIG_PHY_RESET_DELAY); /* Intel LXT971A needs this */
5653fc33 405#endif
c609719b
WD
406 /*
407 * Poll the control register for the reset bit to go to 0 (it is
408 * auto-clearing). This should happen within 0.5 seconds per the
409 * IEEE spec.
410 */
c609719b 411 reg = 0x8000;
ab5a0dcb 412 while (((reg & 0x8000) != 0) && timeout--) {
8ef583a0 413 if (miiphy_read(devname, addr, MII_BMCR, &reg) != 0) {
ab5a0dcb
SR
414 debug("PHY status read failed\n");
415 return -1;
c609719b 416 }
ab5a0dcb 417 udelay(1000);
c609719b
WD
418 }
419 if ((reg & 0x8000) == 0) {
16a53238 420 return 0;
c609719b 421 } else {
16a53238
AF
422 puts("PHY reset timed out\n");
423 return -1;
c609719b 424 }
16a53238 425 return 0;
c609719b 426}
5f184715 427#endif /* !PHYLIB */
c609719b 428
c609719b
WD
429/*****************************************************************************
430 *
71bc6e64 431 * Determine the ethernet speed (10/100/1000). Return 10 on error.
c609719b 432 */
5700bb63 433int miiphy_speed(const char *devname, unsigned char addr)
c609719b 434{
71bc6e64 435 u16 bmcr, anlpar;
c609719b 436
6fb6af6d 437#if defined(CONFIG_PHY_GIGE)
71bc6e64
LJ
438 u16 btsr;
439
440 /*
441 * Check for 1000BASE-X. If it is supported, then assume that the speed
442 * is 1000.
443 */
16a53238 444 if (miiphy_is_1000base_x(devname, addr))
71bc6e64 445 return _1000BASET;
16a53238 446
71bc6e64
LJ
447 /*
448 * No 1000BASE-X, so assume 1000BASE-T/100BASE-TX/10BASE-T register set.
449 */
450 /* Check for 1000BASE-T. */
16a53238
AF
451 if (miiphy_read(devname, addr, MII_STAT1000, &btsr)) {
452 printf("PHY 1000BT status");
71bc6e64
LJ
453 goto miiphy_read_failed;
454 }
455 if (btsr != 0xFFFF &&
16a53238 456 (btsr & (PHY_1000BTSR_1000FD | PHY_1000BTSR_1000HD)))
71bc6e64 457 return _1000BASET;
6fb6af6d 458#endif /* CONFIG_PHY_GIGE */
855a496f 459
a56bd922 460 /* Check Basic Management Control Register first. */
16a53238
AF
461 if (miiphy_read(devname, addr, MII_BMCR, &bmcr)) {
462 printf("PHY speed");
71bc6e64 463 goto miiphy_read_failed;
c609719b 464 }
a56bd922 465 /* Check if auto-negotiation is on. */
8ef583a0 466 if (bmcr & BMCR_ANENABLE) {
a56bd922 467 /* Get auto-negotiation results. */
16a53238
AF
468 if (miiphy_read(devname, addr, MII_LPA, &anlpar)) {
469 printf("PHY AN speed");
71bc6e64 470 goto miiphy_read_failed;
a56bd922 471 }
8ef583a0 472 return (anlpar & LPA_100) ? _100BASET : _10BASET;
a56bd922
WD
473 }
474 /* Get speed from basic control settings. */
8ef583a0 475 return (bmcr & BMCR_SPEED100) ? _100BASET : _10BASET;
a56bd922 476
5f841959 477miiphy_read_failed:
16a53238 478 printf(" read failed, assuming 10BASE-T\n");
71bc6e64 479 return _10BASET;
c609719b
WD
480}
481
c609719b
WD
482/*****************************************************************************
483 *
71bc6e64 484 * Determine full/half duplex. Return half on error.
c609719b 485 */
5700bb63 486int miiphy_duplex(const char *devname, unsigned char addr)
c609719b 487{
71bc6e64 488 u16 bmcr, anlpar;
c609719b 489
6fb6af6d 490#if defined(CONFIG_PHY_GIGE)
71bc6e64
LJ
491 u16 btsr;
492
493 /* Check for 1000BASE-X. */
16a53238 494 if (miiphy_is_1000base_x(devname, addr)) {
71bc6e64 495 /* 1000BASE-X */
16a53238
AF
496 if (miiphy_read(devname, addr, MII_LPA, &anlpar)) {
497 printf("1000BASE-X PHY AN duplex");
71bc6e64
LJ
498 goto miiphy_read_failed;
499 }
500 }
501 /*
502 * No 1000BASE-X, so assume 1000BASE-T/100BASE-TX/10BASE-T register set.
503 */
504 /* Check for 1000BASE-T. */
16a53238
AF
505 if (miiphy_read(devname, addr, MII_STAT1000, &btsr)) {
506 printf("PHY 1000BT status");
71bc6e64
LJ
507 goto miiphy_read_failed;
508 }
509 if (btsr != 0xFFFF) {
510 if (btsr & PHY_1000BTSR_1000FD) {
511 return FULL;
512 } else if (btsr & PHY_1000BTSR_1000HD) {
513 return HALF;
855a496f
WD
514 }
515 }
6fb6af6d 516#endif /* CONFIG_PHY_GIGE */
855a496f 517
a56bd922 518 /* Check Basic Management Control Register first. */
16a53238
AF
519 if (miiphy_read(devname, addr, MII_BMCR, &bmcr)) {
520 puts("PHY duplex");
71bc6e64 521 goto miiphy_read_failed;
c609719b 522 }
a56bd922 523 /* Check if auto-negotiation is on. */
8ef583a0 524 if (bmcr & BMCR_ANENABLE) {
a56bd922 525 /* Get auto-negotiation results. */
16a53238
AF
526 if (miiphy_read(devname, addr, MII_LPA, &anlpar)) {
527 puts("PHY AN duplex");
71bc6e64 528 goto miiphy_read_failed;
a56bd922 529 }
8ef583a0 530 return (anlpar & (LPA_10FULL | LPA_100FULL)) ?
71bc6e64 531 FULL : HALF;
a56bd922
WD
532 }
533 /* Get speed from basic control settings. */
8ef583a0 534 return (bmcr & BMCR_FULLDPLX) ? FULL : HALF;
71bc6e64 535
5f841959 536miiphy_read_failed:
16a53238 537 printf(" read failed, assuming half duplex\n");
71bc6e64
LJ
538 return HALF;
539}
a56bd922 540
71bc6e64
LJ
541/*****************************************************************************
542 *
543 * Return 1 if PHY supports 1000BASE-X, 0 if PHY supports 10BASE-T/100BASE-TX/
544 * 1000BASE-T, or on error.
545 */
5700bb63 546int miiphy_is_1000base_x(const char *devname, unsigned char addr)
71bc6e64
LJ
547{
548#if defined(CONFIG_PHY_GIGE)
549 u16 exsr;
550
16a53238
AF
551 if (miiphy_read(devname, addr, MII_ESTATUS, &exsr)) {
552 printf("PHY extended status read failed, assuming no "
71bc6e64
LJ
553 "1000BASE-X\n");
554 return 0;
555 }
8ef583a0 556 return 0 != (exsr & (ESTATUS_1000XF | ESTATUS_1000XH));
71bc6e64
LJ
557#else
558 return 0;
559#endif
c609719b
WD
560}
561
6d0f6bcf 562#ifdef CONFIG_SYS_FAULT_ECHO_LINK_DOWN
fc3e2165
WD
563/*****************************************************************************
564 *
565 * Determine link status
566 */
5700bb63 567int miiphy_link(const char *devname, unsigned char addr)
fc3e2165
WD
568{
569 unsigned short reg;
570
a3d991bd 571 /* dummy read; needed to latch some phys */
16a53238
AF
572 (void)miiphy_read(devname, addr, MII_BMSR, &reg);
573 if (miiphy_read(devname, addr, MII_BMSR, &reg)) {
574 puts("MII_BMSR read failed, assuming no link\n");
575 return 0;
fc3e2165
WD
576 }
577
578 /* Determine if a link is active */
8ef583a0 579 if ((reg & BMSR_LSTATUS) != 0) {
16a53238 580 return 1;
fc3e2165 581 } else {
16a53238 582 return 0;
fc3e2165
WD
583 }
584}
585#endif