1 /*
2 * Copyright (c) 2019-2025 Allwinner Technology Co., Ltd. ALL rights reserved.
3 *
4 * Allwinner is a trademark of Allwinner Technology Co.,Ltd., registered in
5 * the the People's Republic of China and other countries.
6 * All Allwinner Technology Co.,Ltd. trademarks are used with permission.
7 *
8 * DISCLAIMER
9 * THIRD PARTY LICENCES MAY BE REQUIRED TO IMPLEMENT THE SOLUTION/PRODUCT.
10 * IF YOU NEED TO INTEGRATE THIRD PARTY’S TECHNOLOGY (SONY, DTS, DOLBY, AVS OR MPEGLA, ETC.)
11 * IN ALLWINNERS’SDK OR PRODUCTS, YOU SHALL BE SOLELY RESPONSIBLE TO OBTAIN
12 * ALL APPROPRIATELY REQUIRED THIRD PARTY LICENCES.
13 * ALLWINNER SHALL HAVE NO WARRANTY, INDEMNITY OR OTHER OBLIGATIONS WITH RESPECT TO MATTERS
14 * COVERED UNDER ANY REQUIRED THIRD PARTY LICENSE.
15 * YOU ARE SOLELY RESPONSIBLE FOR YOUR USAGE OF THIRD PARTY’S TECHNOLOGY.
16 *
17 *
18 * THIS SOFTWARE IS PROVIDED BY ALLWINNER"AS IS" AND TO THE MAXIMUM EXTENT
19 * PERMITTED BY LAW, ALLWINNER EXPRESSLY DISCLAIMS ALL WARRANTIES OF ANY KIND,
20 * WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING WITHOUT LIMITATION REGARDING
21 * THE TITLE, NON-INFRINGEMENT, ACCURACY, CONDITION, COMPLETENESS, PERFORMANCE
22 * OR MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
23 * IN NO EVENT SHALL ALLWINNER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 * LOSS OF USE, DATA, OR PROFITS, OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
28 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
30 * OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 //#include <common.h>
34 #include <typedef.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <stdint.h>
38 #include <string.h>
39 #include <hal_thread.h>
40 #include <sunxi_hal_common.h>
41 #include <sunxi_hal_miiphy.h>
42 #include <sunxi_hal_phy.h>
43
44 //#include <asm/types.h>
45 //#include <list.h>
46 #include <hal_mem.h>
47 //#include <net.h>
48
49 /* local debug macro */
50 #undef MII_DEBUG
51
52 #undef debug
53 #ifdef MII_DEBUG
54 #define debug(fmt, args...) printf(fmt, ##args)
55 #else
56 #define debug(fmt, args...)
57 #endif /* MII_DEBUG */
58
59 static struct list_head mii_devs;
60 static struct mii_dev *current_mii;
61
62 /*
63 * Lookup the mii_dev struct by the registered device name.
64 */
miiphy_get_dev_by_name(const char * devname)65 struct mii_dev *miiphy_get_dev_by_name(const char *devname)
66 {
67 struct list_head *entry;
68 struct mii_dev *dev;
69
70 if (!devname) {
71 printf("NULL device name!\n");
72 return NULL;
73 }
74
75 list_for_each(entry, &mii_devs) {
76 dev = list_entry(entry, struct mii_dev, link);
77 if (strcmp(dev->name, devname) == 0)
78 return dev;
79 }
80
81 return NULL;
82 }
83
84 /*****************************************************************************
85 *
86 * Initialize global data. Need to be called before any other miiphy routine.
87 */
miiphy_init(void)88 void miiphy_init(void)
89 {
90 INIT_LIST_HEAD(&mii_devs);
91 current_mii = NULL;
92 }
93
legacy_miiphy_read(struct mii_dev * bus,int addr,int devad,int reg)94 static int legacy_miiphy_read(struct mii_dev *bus, int addr, int devad, int reg)
95 {
96 unsigned short val;
97 int ret;
98 struct legacy_mii_dev *ldev = bus->priv;
99
100 ret = ldev->read(bus->name, addr, reg, &val);
101
102 return ret ? -1 : (int)val;
103 }
104
legacy_miiphy_write(struct mii_dev * bus,int addr,int devad,int reg,uint16_t val)105 static int legacy_miiphy_write(struct mii_dev *bus, int addr, int devad,
106 int reg, uint16_t val)
107 {
108 struct legacy_mii_dev *ldev = bus->priv;
109
110 return ldev->write(bus->name, addr, reg, val);
111 }
112
113 /*****************************************************************************
114 *
115 * Register read and write MII access routines for the device <name>.
116 * This API is now deprecated. Please use mdio_alloc and mdio_register, instead.
117 */
miiphy_register(const char * name,int (* read)(const char * devname,unsigned char addr,unsigned char reg,unsigned short * value),int (* write)(const char * devname,unsigned char addr,unsigned char reg,unsigned short value))118 void miiphy_register(const char *name,
119 int (*read)(const char *devname, unsigned char addr,
120 unsigned char reg, unsigned short *value),
121 int (*write)(const char *devname, unsigned char addr,
122 unsigned char reg, unsigned short value))
123 {
124 struct mii_dev *new_dev;
125 struct legacy_mii_dev *ldev;
126
127 BUG_ON(strlen(name) >= MDIO_NAME_LEN);
128
129 /* check if we have unique name */
130 new_dev = miiphy_get_dev_by_name(name);
131 if (new_dev) {
132 printf("miiphy_register: non unique device name '%s'\n", name);
133 return;
134 }
135
136 /* allocate memory */
137 new_dev = mdio_alloc();
138 ldev = malloc(sizeof(*ldev));
139
140 if (new_dev == NULL || ldev == NULL) {
141 printf("miiphy_register: cannot allocate memory for '%s'\n",
142 name);
143 return;
144 }
145
146 /* initalize mii_dev struct fields */
147 new_dev->read = legacy_miiphy_read;
148 new_dev->write = legacy_miiphy_write;
149 strncpy(new_dev->name, name, MDIO_NAME_LEN);
150 new_dev->name[MDIO_NAME_LEN - 1] = 0;
151 ldev->read = read;
152 ldev->write = write;
153 new_dev->priv = ldev;
154
155 printf("miiphy_register: added '%s', read=0x%08lx, write=0x%08lx\n",
156 new_dev->name, ldev->read, ldev->write);
157
158 /* add it to the list */
159 list_add_tail(&new_dev->link, &mii_devs);
160
161 if (!current_mii)
162 current_mii = new_dev;
163 }
164
mdio_alloc(void)165 struct mii_dev *mdio_alloc(void)
166 {
167 struct mii_dev *bus;
168
169 bus = malloc(sizeof(*bus));
170 if (!bus)
171 return bus;
172
173 memset(bus, 0, sizeof(*bus));
174
175 /* initalize mii_dev struct fields */
176 INIT_LIST_HEAD(&bus->link);
177
178 return bus;
179 }
180
mdio_register(struct mii_dev * bus)181 int mdio_register(struct mii_dev *bus)
182 {
183 if (!bus || !bus->name || !bus->read || !bus->write)
184 return -1;
185
186 /* check if we have unique name */
187 if (miiphy_get_dev_by_name(bus->name)) {
188 printf("mdio_register: non unique device name '%s'\n",
189 bus->name);
190 return -1;
191 }
192
193 /* add it to the list */
194 list_add_tail(&bus->link, &mii_devs);
195
196 if (!current_mii)
197 current_mii = bus;
198
199 return 0;
200 }
201
mdio_list_devices(void)202 void mdio_list_devices(void)
203 {
204 struct list_head *entry;
205
206 list_for_each(entry, &mii_devs) {
207 int i;
208 struct mii_dev *bus = list_entry(entry, struct mii_dev, link);
209
210 printf("%s:\n", bus->name);
211
212 for (i = 0; i < PHY_MAX_ADDR; i++) {
213 struct phy_device *phydev = bus->phymap[i];
214
215 if (phydev) {
216 printf("%d - %s", i, phydev->drv->name);
217
218 if (phydev->dev)
219 printf(" <--> %s\n", "eth0");
220 else
221 printf("\n");
222 }
223 }
224 }
225 }
226
miiphy_set_current_dev(const char * devname)227 int miiphy_set_current_dev(const char *devname)
228 {
229 struct mii_dev *dev;
230
231 dev = miiphy_get_dev_by_name(devname);
232 if (dev) {
233 current_mii = dev;
234 return 0;
235 }
236
237 printf("No such device: %s\n", devname);
238
239 return 1;
240 }
241
mdio_get_current_dev(void)242 struct mii_dev *mdio_get_current_dev(void)
243 {
244 return current_mii;
245 }
246
mdio_phydev_for_ethname(const char * ethname)247 struct phy_device *mdio_phydev_for_ethname(const char *ethname)
248 {
249 struct list_head *entry;
250 struct mii_dev *bus;
251
252 list_for_each(entry, &mii_devs) {
253 int i;
254 bus = list_entry(entry, struct mii_dev, link);
255
256 for (i = 0; i < PHY_MAX_ADDR; i++) {
257 if (!bus->phymap[i] || !bus->phymap[i]->dev)
258 continue;
259
260 /*if (strcmp(bus->phymap[i]->dev->name, ethname) == 0)
261 return bus->phymap[i];*/
262 }
263 }
264
265 printf("%s is not a known ethernet\n", ethname);
266 return NULL;
267 }
268
miiphy_get_current_dev(void)269 const char *miiphy_get_current_dev(void)
270 {
271 if (current_mii)
272 return current_mii->name;
273
274 return NULL;
275 }
276
miiphy_get_active_dev(const char * devname)277 static struct mii_dev *miiphy_get_active_dev(const char *devname)
278 {
279 /* If the current mii is the one we want, return it */
280 if (current_mii)
281 if (strcmp(current_mii->name, devname) == 0)
282 return current_mii;
283
284 /* Otherwise, set the active one to the one we want */
285 if (miiphy_set_current_dev(devname))
286 return NULL;
287 else
288 return current_mii;
289 }
290
291 /*****************************************************************************
292 *
293 * Read to variable <value> from the PHY attached to device <devname>,
294 * use PHY address <addr> and register <reg>.
295 *
296 * This API is deprecated. Use phy_read on a phy_device found via phy_connect
297 *
298 * Returns:
299 * 0 on success
300 */
miiphy_read(const char * devname,unsigned char addr,unsigned char reg,unsigned short * value)301 int miiphy_read(const char *devname, unsigned char addr, unsigned char reg,
302 unsigned short *value)
303 {
304 struct mii_dev *bus;
305 int ret;
306
307 bus = miiphy_get_active_dev(devname);
308 if (!bus)
309 return 1;
310
311 ret = bus->read(bus, addr, MDIO_DEVAD_NONE, reg);
312 if (ret < 0)
313 return 1;
314
315 *value = (unsigned short)ret;
316 return 0;
317 }
318
319 /*****************************************************************************
320 *
321 * Write <value> to the PHY attached to device <devname>,
322 * use PHY address <addr> and register <reg>.
323 *
324 * This API is deprecated. Use phy_write on a phy_device found by phy_connect
325 *
326 * Returns:
327 * 0 on success
328 */
miiphy_write(const char * devname,unsigned char addr,unsigned char reg,unsigned short value)329 int miiphy_write(const char *devname, unsigned char addr, unsigned char reg,
330 unsigned short value)
331 {
332 struct mii_dev *bus;
333
334 bus = miiphy_get_active_dev(devname);
335 if (bus)
336 return bus->write(bus, addr, MDIO_DEVAD_NONE, reg, value);
337
338 return 1;
339 }
340
341 /*****************************************************************************
342 *
343 * Print out list of registered MII capable devices.
344 */
miiphy_listdev(void)345 void miiphy_listdev(void)
346 {
347 struct list_head *entry;
348 struct mii_dev *dev;
349
350 puts("MII devices: ");
351 list_for_each(entry, &mii_devs) {
352 dev = list_entry(entry, struct mii_dev, link);
353 printf("'%s' ", dev->name);
354 }
355 puts("\n");
356
357 if (current_mii)
358 printf("Current device: '%s'\n", current_mii->name);
359 }
360
361 /*****************************************************************************
362 *
363 * Read the OUI, manufacture's model number, and revision number.
364 *
365 * OUI: 22 bits (unsigned int)
366 * Model: 6 bits (unsigned char)
367 * Revision: 4 bits (unsigned char)
368 *
369 * This API is deprecated.
370 *
371 * Returns:
372 * 0 on success
373 */
miiphy_info(const char * devname,unsigned char addr,unsigned int * oui,unsigned char * model,unsigned char * rev)374 int miiphy_info(const char *devname, unsigned char addr, unsigned int *oui,
375 unsigned char *model, unsigned char *rev)
376 {
377 unsigned int reg = 0;
378 unsigned short tmp;
379
380 if (miiphy_read(devname, addr, MII_PHYSID2, &tmp) != 0) {
381 printf("PHY ID register 2 read failed\n");
382 return -1;
383 }
384 reg = tmp;
385
386 printf("MII_PHYSID2 @ 0x%x = 0x%04x\n", addr, reg);
387
388 if (reg == 0xFFFF) {
389 /* No physical device present at this address */
390 return -1;
391 }
392
393 if (miiphy_read(devname, addr, MII_PHYSID1, &tmp) != 0) {
394 printf("PHY ID register 1 read failed\n");
395 return -1;
396 }
397 reg |= tmp << 16;
398 printf("PHY_PHYIDR[1,2] @ 0x%x = 0x%08x\n", addr, reg);
399
400 *oui = (reg >> 10);
401 *model = (unsigned char)((reg >> 4) & 0x0000003F);
402 *rev = (unsigned char)(reg & 0x0000000F);
403 return 0;
404 }
405
406 #ifndef CONFIG_PHYLIB
407 /*****************************************************************************
408 *
409 * Reset the PHY.
410 *
411 * This API is deprecated. Use PHYLIB.
412 *
413 * Returns:
414 * 0 on success
415 */
416 #if 0
417 int miiphy_reset(const char *devname, unsigned char addr)
418 {
419 unsigned short reg;
420 int timeout = 500;
421
422 if (miiphy_read(devname, addr, MII_BMCR, ®) != 0) {
423 printf("PHY status read failed\n");
424 return -1;
425 }
426 if (miiphy_write(devname, addr, MII_BMCR, reg | BMCR_RESET) != 0) {
427 printf("PHY reset failed\n");
428 return -1;
429 }
430 #ifdef CONFIG_PHY_RESET_DELAY
431 udelay(CONFIG_PHY_RESET_DELAY); /* Intel LXT971A needs this */
432 #endif
433 /*
434 * Poll the control register for the reset bit to go to 0 (it is
435 * auto-clearing). This should happen within 0.5 seconds per the
436 * IEEE spec.
437 */
438 reg = 0x8000;
439 while (((reg & 0x8000) != 0) && timeout--) {
440 if (miiphy_read(devname, addr, MII_BMCR, ®) != 0) {
441 printf("PHY status read failed\n");
442 return -1;
443 }
444 udelay(1000);
445 }
446 if ((reg & 0x8000) == 0) {
447 return 0;
448 } else {
449 printf("PHY reset timed out\n");
450 return -1;
451 }
452 return 0;
453 }
454 #endif
455 #endif /* !PHYLIB */
456
457 /*****************************************************************************
458 *
459 * Determine the ethernet speed (10/100/1000). Return 10 on error.
460 */
miiphy_speed(const char * devname,unsigned char addr)461 int miiphy_speed(const char *devname, unsigned char addr)
462 {
463 uint16_t bmcr, anlpar;
464
465 #if defined(CONFIG_PHY_GIGE)
466 uint16_t btsr;
467
468 /*
469 * Check for 1000BASE-X. If it is supported, then assume that the speed
470 * is 1000.
471 */
472 if (miiphy_is_1000base_x(devname, addr))
473 return _1000BASET;
474
475 /*
476 * No 1000BASE-X, so assume 1000BASE-T/100BASE-TX/10BASE-T register set.
477 */
478 /* Check for 1000BASE-T. */
479 if (miiphy_read(devname, addr, MII_STAT1000, &btsr)) {
480 printf("PHY 1000BT status");
481 goto miiphy_read_failed;
482 }
483 if (btsr != 0xFFFF &&
484 (btsr & (PHY_1000BTSR_1000FD | PHY_1000BTSR_1000HD)))
485 return _1000BASET;
486 #endif /* CONFIG_PHY_GIGE */
487
488 /* Check Basic Management Control Register first. */
489 if (miiphy_read(devname, addr, MII_BMCR, &bmcr)) {
490 printf("PHY speed");
491 goto miiphy_read_failed;
492 }
493 /* Check if auto-negotiation is on. */
494 if (bmcr & BMCR_ANENABLE) {
495 /* Get auto-negotiation results. */
496 if (miiphy_read(devname, addr, MII_LPA, &anlpar)) {
497 printf("PHY AN speed");
498 goto miiphy_read_failed;
499 }
500 return (anlpar & LPA_100) ? _100BASET : _10BASET;
501 }
502 /* Get speed from basic control settings. */
503 return (bmcr & BMCR_SPEED100) ? _100BASET : _10BASET;
504
505 miiphy_read_failed:
506 printf(" read failed, assuming 10BASE-T\n");
507 return _10BASET;
508 }
509
510 /*****************************************************************************
511 *
512 * Determine full/half duplex. Return half on error.
513 */
miiphy_duplex(const char * devname,unsigned char addr)514 int miiphy_duplex(const char *devname, unsigned char addr)
515 {
516 uint16_t bmcr, anlpar;
517
518 #if defined(CONFIG_PHY_GIGE)
519 uint16_t btsr;
520
521 /* Check for 1000BASE-X. */
522 if (miiphy_is_1000base_x(devname, addr)) {
523 /* 1000BASE-X */
524 if (miiphy_read(devname, addr, MII_LPA, &anlpar)) {
525 printf("1000BASE-X PHY AN duplex");
526 goto miiphy_read_failed;
527 }
528 }
529 /*
530 * No 1000BASE-X, so assume 1000BASE-T/100BASE-TX/10BASE-T register set.
531 */
532 /* Check for 1000BASE-T. */
533 if (miiphy_read(devname, addr, MII_STAT1000, &btsr)) {
534 printf("PHY 1000BT status");
535 goto miiphy_read_failed;
536 }
537 if (btsr != 0xFFFF) {
538 if (btsr & PHY_1000BTSR_1000FD) {
539 return FULL;
540 } else if (btsr & PHY_1000BTSR_1000HD) {
541 return HALF;
542 }
543 }
544 #endif /* CONFIG_PHY_GIGE */
545
546 /* Check Basic Management Control Register first. */
547 if (miiphy_read(devname, addr, MII_BMCR, &bmcr)) {
548 printf("PHY duplex");
549 goto miiphy_read_failed;
550 }
551 /* Check if auto-negotiation is on. */
552 if (bmcr & BMCR_ANENABLE) {
553 /* Get auto-negotiation results. */
554 if (miiphy_read(devname, addr, MII_LPA, &anlpar)) {
555 printf("PHY AN duplex");
556 goto miiphy_read_failed;
557 }
558 return (anlpar & (LPA_10FULL | LPA_100FULL)) ?
559 FULL : HALF;
560 }
561 /* Get speed from basic control settings. */
562 return (bmcr & BMCR_FULLDPLX) ? FULL : HALF;
563
564 miiphy_read_failed:
565 printf(" read failed, assuming half duplex\n");
566 return HALF;
567 }
568
569 /*****************************************************************************
570 *
571 * Return 1 if PHY supports 1000BASE-X, 0 if PHY supports 10BASE-T/100BASE-TX/
572 * 1000BASE-T, or on error.
573 */
miiphy_is_1000base_x(const char * devname,unsigned char addr)574 int miiphy_is_1000base_x(const char *devname, unsigned char addr)
575 {
576 #if defined(CONFIG_PHY_GIGE)
577 uint16_t exsr;
578
579 if (miiphy_read(devname, addr, MII_ESTATUS, &exsr)) {
580 printf("PHY extended status read failed, assuming no "
581 "1000BASE-X\n");
582 return 0;
583 }
584 return 0 != (exsr & (ESTATUS_1000XF | ESTATUS_1000XH));
585 #else
586 return 0;
587 #endif
588 }
589
590 #ifdef CONFIG_SYS_FAULT_ECHO_LINK_DOWN
591 /*****************************************************************************
592 *
593 * Determine link status
594 */
miiphy_link(const char * devname,unsigned char addr)595 int miiphy_link(const char *devname, unsigned char addr)
596 {
597 unsigned short reg;
598
599 /* dummy read; needed to latch some phys */
600 (void)miiphy_read(devname, addr, MII_BMSR, ®);
601 if (miiphy_read(devname, addr, MII_BMSR, ®)) {
602 printf("MII_BMSR read failed, assuming no link\n");
603 return 0;
604 }
605
606 /* Determine if a link is active */
607 if ((reg & BMSR_LSTATUS) != 0) {
608 return 1;
609 } else {
610 return 0;
611 }
612 }
613 #endif
614