software/bios: add Ethernet PHY MDIO read/write/dump commands
authorFlorent Kermarrec <florent@enjoy-digital.fr>
Fri, 9 Aug 2019 07:26:41 +0000 (09:26 +0200)
committerFlorent Kermarrec <florent@enjoy-digital.fr>
Fri, 9 Aug 2019 07:26:41 +0000 (09:26 +0200)
litex/soc/software/bios/main.c
litex/soc/software/include/base/mdio.h [new file with mode: 0644]
litex/soc/software/libbase/Makefile
litex/soc/software/libbase/mdio.c [new file with mode: 0644]

index a93b4e132a3a13bd897bc4f2c766fc99fb601a54..600819b55f30d4dd337d3a8b2a3de395c4109c89 100644 (file)
@@ -1,12 +1,11 @@
 // This file is Copyright (c) 2013-2014 Sebastien Bourdeauducq <sb@m-labs.hk>
+// This file is Copyright (c) 2014-2019 Florent Kermarrec <florent@enjoy-digital.fr>
 // This file is Copyright (c) 2015 Yann Sionneau <ys@m-labs.hk>
 // This file is Copyright (c) 2015 whitequark <whitequark@whitequark.org>
 // This file is Copyright (c) 2019 Ambroz Bizjak <ambrop7@gmail.com>
 // This file is Copyright (c) 2019 Caleb Jamison <cbjamo@gmail.com>
 // This file is Copyright (c) 2018 Dolu1990 <charles.papon.90@gmail.com>
 // This file is Copyright (c) 2018 Felix Held <felix-github@felixheld.de>
-// This file is Copyright (c) 2014 Florent Kermarec <florent@enjoy-digital.fr>
-// This file is Copyright (c) 2014-2019 Florent Kermarrec <florent@enjoy-digital.fr>
 // This file is Copyright (c) 2019 Gabriel L. Somlo <gsomlo@gmail.com>
 // This file is Copyright (c) 2018 Jean-François Nguyen <jf@lambdaconcept.fr>
 // This file is Copyright (c) 2018 Sergiusz Bazanski <q3k@q3k.org>
 #include <spiflash.h>
 #endif
 
+#ifdef CSR_ETHPHY_MDIO_W_ADDR
+#include <mdio.h>
+#endif
+
 #include "sdram.h"
 #include "boot.h"
 
@@ -141,6 +144,40 @@ static void mw(char *addr, char *value, char *count)
        for (i=0;i<count2;i++) *addr2++ = value2;
 }
 
+static void mc(char *dstaddr, char *srcaddr, char *count)
+{
+       char *c;
+       unsigned int *dstaddr2;
+       unsigned int *srcaddr2;
+       unsigned int count2;
+       unsigned int i;
+
+       if((*dstaddr == 0) || (*srcaddr == 0)) {
+               printf("mc <dst> <src> [count]\n");
+               return;
+       }
+       dstaddr2 = (unsigned int *)strtoul(dstaddr, &c, 0);
+       if(*c != 0) {
+               printf("incorrect destination address\n");
+               return;
+       }
+       srcaddr2 = (unsigned int *)strtoul(srcaddr, &c, 0);
+       if(*c != 0) {
+               printf("incorrect source address\n");
+               return;
+       }
+       if(*count == 0) {
+               count2 = 1;
+       } else {
+               count2 = strtoul(count, &c, 0);
+               if(*c != 0) {
+                       printf("incorrect count\n");
+                       return;
+               }
+       }
+       for (i=0;i<count2;i++) *dstaddr2++ = *srcaddr2++;
+}
+
 #if (defined CSR_SPIFLASH_BASE && defined SPIFLASH_PAGE_SIZE)
 static void fw(char *addr, char *value, char *count)
 {
@@ -177,39 +214,90 @@ static void fw(char *addr, char *value, char *count)
 }
 #endif
 
-static void mc(char *dstaddr, char *srcaddr, char *count)
+#ifdef CSR_ETHPHY_MDIO_W_ADDR
+static void mdiow(char *phyadr, char *reg, char *val)
 {
        char *c;
-       unsigned int *dstaddr2;
-       unsigned int *srcaddr2;
+       unsigned int phyadr2;
+       unsigned int reg2;
+       unsigned int val2;
+
+       if((*phyadr == 0) || (*reg == 0) || (*val == 0)) {
+               printf("mdiow <phyadr> <reg> <value>\n");
+               return;
+       }
+       phyadr2 = strtoul(phyadr, &c, 0);
+       if(*c != 0) {
+               printf("incorrect phyadr\n");
+               return;
+       }
+       reg2 = strtoul(reg, &c, 0);
+       if(*c != 0) {
+               printf("incorrect reg\n");
+               return;
+       }
+       val2 = strtoul(val, &c, 0);
+       if(*c != 0) {
+               printf("incorrect val\n");
+               return;
+       }
+       mdio_write(phyadr2, reg2, val2);
+}
+
+static void mdior(char *phyadr, char *reg)
+{
+       char *c;
+       unsigned int phyadr2;
+       unsigned int reg2;
+       unsigned int val;
+
+       if((*phyadr == 0) || (*reg == 0)) {
+               printf("mdior <phyadr> <reg>\n");
+               return;
+       }
+       phyadr2 = strtoul(phyadr, &c, 0);
+       if(*c != 0) {
+               printf("incorrect phyadr\n");
+               return;
+       }
+       reg2 = strtoul(reg, &c, 0);
+       if(*c != 0) {
+               printf("incorrect reg\n");
+               return;
+       }
+       val = mdio_read(phyadr2, reg2);
+       printf("reg %d: 0x%04x\n", reg2, val);
+}
+
+static void mdiod(char *phyadr, char *count)
+{
+       char *c;
+       unsigned int phyadr2;
        unsigned int count2;
-       unsigned int i;
+       unsigned int val;
+       int i;
 
-       if((*dstaddr == 0) || (*srcaddr == 0)) {
-               printf("mc <dst> <src> [count]\n");
+       if((*phyadr == 0) || (*count == 0)) {
+               printf("mdiod <phyadr> <count>\n");
                return;
        }
-       dstaddr2 = (unsigned int *)strtoul(dstaddr, &c, 0);
+       phyadr2 = strtoul(phyadr, &c, 0);
        if(*c != 0) {
-               printf("incorrect destination address\n");
+               printf("incorrect phyadr\n");
                return;
        }
-       srcaddr2 = (unsigned int *)strtoul(srcaddr, &c, 0);
+       count2 = strtoul(count, &c, 0);
        if(*c != 0) {
-               printf("incorrect source address\n");
+               printf("incorrect count\n");
                return;
        }
-       if(*count == 0) {
-               count2 = 1;
-       } else {
-               count2 = strtoul(count, &c, 0);
-               if(*c != 0) {
-                       printf("incorrect count\n");
-                       return;
-               }
+       printf("MDIO dump @0x%x:\n", phyadr2);
+       for (i=0; i<count2; i++) {
+               val = mdio_read(phyadr2, i);
+               printf("reg %d: 0x%04x\n", i, val);
        }
-       for (i=0;i<count2;i++) *dstaddr2++ = *srcaddr2++;
 }
+#endif
 
 static void crc(char *startaddr, char *len)
 {
@@ -253,6 +341,11 @@ static void help(void)
        puts("mc         - copy address space");
 #if (defined CSR_SPIFLASH_BASE && defined SPIFLASH_PAGE_SIZE)
        puts("fw         - write to flash");
+#endif
+#ifdef CSR_ETHPHY_MDIO_W_ADDR
+       puts("mdiow      - write MDIO register");
+       puts("mdior      - read MDIO register");
+       puts("mdiod      - dump MDIO registers");
 #endif
        puts("");
        puts("crc        - compute CRC32 of a part of the address space");
@@ -311,6 +404,11 @@ static void do_command(char *c)
        else if(strcmp(token, "mc") == 0) mc(get_token(&c), get_token(&c), get_token(&c));
 #if (defined CSR_SPIFLASH_BASE && defined SPIFLASH_PAGE_SIZE)
        else if(strcmp(token, "fw") == 0) fw(get_token(&c), get_token(&c), get_token(&c));
+#endif
+#ifdef CSR_ETHPHY_MDIO_W_ADDR
+       else if(strcmp(token, "mdiow") == 0) mdiow(get_token(&c), get_token(&c), get_token(&c));
+       else if(strcmp(token, "mdior") == 0) mdior(get_token(&c), get_token(&c));
+       else if(strcmp(token, "mdiod") == 0) mdiod(get_token(&c), get_token(&c));
 #endif
        else if(strcmp(token, "crc") == 0) crc(get_token(&c), get_token(&c));
        else if(strcmp(token, "ident") == 0) ident();
diff --git a/litex/soc/software/include/base/mdio.h b/litex/soc/software/include/base/mdio.h
new file mode 100644 (file)
index 0000000..875e53c
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef __MDIO_H
+#define __MDIO_H
+
+#define MDIO_CLK 0x01
+#define MDIO_OE        0x02
+#define MDIO_DO        0x04
+
+#define MDIO_DI        0x01
+
+void mdio_write(int phyadr, int reg, int val);
+int mdio_read(int phyadr, int reg);
+
+#endif /* __MDIO_H */
index a5f736401ea562074fc6106317f637ef7f0985f7..5cc816004fc4df900d90b264625a27fc08574121 100755 (executable)
@@ -2,7 +2,7 @@ include ../include/generated/variables.mak
 include $(SOC_DIRECTORY)/software/common.mak
 
 OBJECTS=exception.o libc.o errno.o crc16.o crc32.o console.o \
-       system.o id.o uart.o time.o qsort.o strtod.o spiflash.o strcasecmp.o
+       system.o id.o uart.o time.o qsort.o strtod.o spiflash.o strcasecmp.o mdio.o
 
 all: crt0-$(CPU)-ctr.o crt0-$(CPU)-xip.o libbase.a libbase-nofloat.a
 
diff --git a/litex/soc/software/libbase/mdio.c b/litex/soc/software/libbase/mdio.c
new file mode 100644 (file)
index 0000000..9748734
--- /dev/null
@@ -0,0 +1,91 @@
+#include <generated/csr.h>
+#ifdef CSR_ETHPHY_MDIO_W_ADDR
+#include "mdio.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+static void delay(void)
+{
+/* no delay FIXME */
+}
+
+static void raw_write(unsigned int word, int bitcount)
+{
+       word <<= 32 - bitcount;
+       while(bitcount > 0) {
+               if(word & 0x80000000) {
+                       ethphy_mdio_w_write(MDIO_CLK|MDIO_DO|MDIO_OE);
+                       delay();
+                       ethphy_mdio_w_write(MDIO_DO|MDIO_OE);
+                       delay();
+               } else {
+                       ethphy_mdio_w_write(MDIO_CLK|MDIO_OE);
+                       delay();
+                       ethphy_mdio_w_write(MDIO_OE);
+                       delay();
+               }
+               word <<= 1;
+               bitcount--;
+       }
+}
+
+static unsigned int raw_read(void)
+{
+       unsigned int word;
+       unsigned int i;
+
+       word = 0;
+       for(i=0;i<16;i++) {
+               word <<= 1;
+               ethphy_mdio_w_write(MDIO_CLK);
+               delay();
+               ethphy_mdio_w_write(0);
+               delay();
+               if(ethphy_mdio_r_read() & MDIO_DI)
+                       word |= 1;
+       }
+       return word;
+}
+
+static void raw_turnaround(void)
+{
+       ethphy_mdio_w_write(MDIO_CLK);
+       delay();
+       ethphy_mdio_w_write(0);
+       delay();
+       ethphy_mdio_w_write(MDIO_CLK);
+       delay();
+       ethphy_mdio_w_write(0);
+       delay();
+}
+
+void mdio_write(int phyadr, int reg, int val)
+{
+       ethphy_mdio_w_write(MDIO_OE);
+       raw_write(0xffffffff, 32); /* < sync */
+       raw_write(0x05, 4); /* < start + write */
+       raw_write(phyadr, 5);
+       raw_write(reg, 5);
+       raw_write(0x02, 2); /* < turnaround */
+       raw_write(val, 16);
+       raw_turnaround();
+}
+
+int mdio_read(int phyadr, int reg)
+{
+       int r;
+
+       ethphy_mdio_w_write(MDIO_OE);
+       raw_write(0xffffffff, 32); /* < sync */
+       raw_write(0x06, 4); /* < start + read */
+       raw_write(phyadr, 5);
+       raw_write(reg, 5);
+       raw_turnaround();
+       r = raw_read();
+       raw_turnaround();
+
+       return r;
+}
+
+#endif
\ No newline at end of file