[U-Boot-Users] [PATCH 1/2] Add support for 802.3ae to MII-PHY code

Ben Warren bwarren at qstreams.com
Tue Jan 23 00:20:43 CET 2007


Hello,

This patch adds 'IEEE 802.3ae clause 25' capabilities to the MIIPHY
driver, which is needed for communicating with some 10GbE PHYs.  There
are two main differences between this and the standard 802.3 PHY
framing:

1.	802.3ae devices use a start bit sequence of '00' instead of '01'
2.	Register addressing is indirect.  Read and write requests must be
preceded by an 'address' write, which sets page and offset.  The 'read'
opcode is now auto-incrementing.  A new 'fixed read' opcode is used for
successive reads of a single address.
	
Signed-off-by: Ben Warren <bwarren at qstreams.com>
---
 common/cmd_mii.c    |   72 ++++++++++++++++---
 common/miiphyutil.c |  189 +++++++++++++++++++++++++++++++++++++++------------
 include/miiphy.h    |   26 +++++++
 3 files changed, 233 insertions(+), 54 deletions(-)

diff --git a/common/cmd_mii.c b/common/cmd_mii.c
index e659536..aade843 100644
--- a/common/cmd_mii.c
+++ b/common/cmd_mii.c
@@ -126,11 +126,23 @@ #endif
 		} else {
 			printf ("%04X\n", data & 0x0000FFFF);
 		}
+	} else if (op == 'R') {
+		if (miiphy_read_fixed (devname, addr, reg, &data) != 0) {
+			puts ("Error reading from the PHY\n");
+			rcode = 1;
+		} else {
+			printf ("%04X\n", data & 0x0000FFFF);
+		}
 	} else if (op == 'w') {
 		if (miiphy_write (devname, addr, reg, data) != 0) {
 			puts ("Error writing to the PHY\n");
 			rcode = 1;
 		}
+	} else if (op == 'a') {
+		if (miiphy_ind_address (devname, addr, reg, data) != 0) {
+			puts ("Error writing to the PHY\n");
+			rcode = 1;
+		}
 	} else if (op == 'd') {
 		if (argc == 2)
 			miiphy_listdev ();
@@ -157,11 +169,13 @@ #endif
 U_BOOT_CMD(
 	mii,	5,	1,	do_mii,
 	"mii     - MII utility commands\n",
-	"device                     - list available devices\n"
-	"mii device <devname>           - set current device\n"
-	"mii info   <addr>              - display MII PHY info\n"
-	"mii read   <addr> <reg>        - read  MII PHY <addr> register <reg>\n"
-	"mii write  <addr> <reg> <data> - write MII PHY <addr> register <reg>\n"
+	"device                      - list available devices\n"
+	"mii device  <devname>           - set current device\n"
+	"mii info    <addr>              - display MII PHY info\n"
+	"mii read    <addr> <reg>        - read  MII PHY register\n"
+	"mii write   <addr> <reg> <data> - write MII PHY register\n"
+	"mii Read    <addr>              - read  MII PHY (fixed-address)\n"
+	"mii address <addr> <page> <reg> - set   MII PHY page and offset\n"
 );
 
 #else /* ! CONFIG_TERSE_MII ================================================= */
@@ -522,6 +536,28 @@ #endif
 			if ((addrlo != addrhi) && (reglo != reghi))
 				printf("\n");
 		}
+	} else if (op[0] == 'R') {
+		for (addr = addrlo; addr <= addrhi; addr++) {
+			for (reg = reglo; reg <= reghi; reg++) {
+				data = 0xffff;
+				if (miiphy_read_fixed(devname, addr, 
+							reg, &data) != 0) {
+					printf(
+					"Error reading from the PHY "
+					"addr=%02x reg=%02x\n", addr, reg);
+					rcode = 1;
+				} else {
+					if ((addrlo != addrhi) || 
+						(reglo != reghi))
+						printf(
+						"addr=%02x reg=%02x data=", 
+							(uint)addr, (uint)reg);
+					printf("%04X\n", data & 0x0000FFFF);
+				}
+			}
+			if ((addrlo != addrhi) && (reglo != reghi))
+				printf("\n");
+		}
 	} else if (op[0] == 'w') {
 		for (addr = addrlo; addr <= addrhi; addr++) {
 			for (reg = reglo; reg <= reghi; reg++) {
@@ -532,6 +568,18 @@ #endif
 				}
 			}
 		}
+	} else if (op[0] == 'a') {
+		for (addr = addrlo; addr <= addrhi; addr++) {
+			for (reg = reglo; reg <= reghi; reg++) {
+				if (miiphy_ind_address(devname, addr, 
+					reg, data) != 0) {
+					printf(
+					"Error writing to the PHY "
+					"addr=%02x reg=%02x\n", addr, reg);
+					rcode = 1;
+				}
+			}
+		}
 	} else if (strncmp(op, "du", 2) == 0) {
 		ushort regs[6];
 		int ok = 1;
@@ -584,12 +632,14 @@ #endif
 U_BOOT_CMD(
 	mii,	5,	1,	do_mii,
 	"mii     - MII utility commands\n",
-	"device                     - list available devices\n"
-	"mii device <devname>           - set current device\n"
-	"mii info   <addr>              - display MII PHY info\n"
-	"mii read   <addr> <reg>        - read  MII PHY <addr> register <reg>\n"
-	"mii write  <addr> <reg> <data> - write MII PHY <addr> register <reg>\n"
-	"mii dump   <addr> <reg>        - pretty-print <addr> <reg> (0-5 only)\n"
+	"device                       - list available devices\n"
+	"mii device   <devname>           - set current device\n"
+	"mii info     <addr>              - display MII PHY info\n"
+	"mii read     <addr> <reg>        - read  MII PHY register\n"
+	"mii write    <addr> <reg> <data> - write MII PHY register \n"
+	"mii Read     <addr>              - read  MII PHY (fixed-address)\n"
+	"mii address  <addr> <page> <reg> - set   MII PHY page and offset\n"
+	"mii dump     <addr> <reg>        - pretty-print > (0-5 only)\n"
 	"Addr and/or reg may be ranges, e.g. 2-7.\n"
 );
 
diff --git a/common/miiphyutil.c b/common/miiphyutil.c
index e411e57..5ff093a 100644
--- a/common/miiphyutil.c
+++ b/common/miiphyutil.c
@@ -53,11 +53,31 @@ struct mii_dev {
 			unsigned char reg, unsigned short *value);
 	int (* write)(char *devname, unsigned char addr,
 			unsigned char reg, unsigned short value);
+	int (* ind_address)(char *devname, unsigned char addr,
+			unsigned char reg, unsigned short value);
+	int (* read_fixed)(char *devname, unsigned char addr,
+			unsigned char reg, unsigned short *value);
+	unsigned int	flags;
 };
 
 static struct list_head mii_devs;
 static struct mii_dev *current_mii;
 
+static struct mii_dev *find_miiphy(char *devname)
+{
+	struct list_head *entry;
+	struct mii_dev *dev;
+
+	list_for_each(entry, &mii_devs) {
+		dev = list_entry(entry, struct mii_dev, link);
+
+		if (strcmp(devname, dev->name) == 0) {
+			return dev;
+		}
+	}
+	return NULL;
+}
+	
 /*****************************************************************************
  *
  * Initialize global data. Need to be called before any other miiphy routine.
@@ -78,19 +98,13 @@ void miiphy_register(char *name,
 		int (* write)(char *devname, unsigned char addr,
 			unsigned char reg, unsigned short value))
 {
-	struct list_head *entry;
 	struct mii_dev *new_dev;
-	struct mii_dev *miidev;
 	unsigned int name_len;
 
 	/* check if we have unique name */
-	list_for_each(entry, &mii_devs) {
-		miidev = list_entry(entry, struct mii_dev, link);
-		if (strcmp(miidev->name, name) == 0) {
-			printf("miiphy_register: non unique device name '%s'\n",
-					name);
-			return;
-		}
+	if (find_miiphy(name) != NULL) {
+		printf("miiphy_register: non unique device name '%s'\n", name);
+		return;
 	}
 
 	/* allocate memory */
@@ -122,18 +136,51 @@ void miiphy_register(char *name,
 		current_mii = new_dev;
 }
 
-int miiphy_set_current_dev(char *devname)
+int miiphy_set_attribute(char *devname, enum miiphy_attr attr, void *value)
 {
-	struct list_head *entry;
+
 	struct mii_dev *dev;
 
-	list_for_each(entry, &mii_devs) {
-		dev = list_entry(entry, struct mii_dev, link);
+	if (!devname) {
+		puts("miiphy_set_attribute: NULL device name!\n");
+		return 1;
+	}
 
-		if (strcmp(devname, dev->name) == 0) {
-			current_mii = dev;
-			return 0;
-		}
+	if ((dev = find_miiphy(devname)) == NULL) {
+		puts("miiphy_set_attribute: Device not found!\n");
+		return 2;
+	}
+
+	switch (attr) {
+		case MIIPHY_NAME:
+			dev->name = (char *)value;
+			break;
+		case MIIPHY_READ_FUNC:
+			dev->read = value;
+			break;
+		case MIIPHY_WRITE_FUNC:
+			dev->write = value;
+			break;
+		case MIIPHY_IND_ADDR_FUNC:
+			dev->ind_address = value;
+			break;
+		case MIIPHY_READ_FIXED_FUNC:
+			dev->read_fixed = value;
+			break;
+		case MIIPHY_FLAGS:
+			dev->flags = (unsigned int)value;
+			break;
+	}
+	return 0;
+}
+
+int miiphy_set_current_dev(char *devname)
+{
+	struct mii_dev *dev;
+
+	if ((dev = find_miiphy(devname)) != NULL) {
+		current_mii = dev;
+		return 0;
 	}
 
 	printf("No such device: %s\n", devname);
@@ -148,10 +195,23 @@ char *miiphy_get_current_dev()
 	return NULL;
 }
 
+unsigned char miiphy_get_flags(char *devname)
+{
+	struct mii_dev *dev;
+
+	if ((dev = find_miiphy(devname)) != NULL) {
+		return dev->flags;
+	}
+
+	printf("No such device: %s\n", devname);
+	return 0;
+}
+
 /*****************************************************************************
  *
  * Read to variable <value> from the PHY attached to device <devname>,
  * use PHY address <addr> and register <reg>.
+ * Note: If using 802.3ae framing, this read is auto-incrementing
  *
  * Returns:
  *   0 on success
@@ -159,30 +219,20 @@ char *miiphy_get_current_dev()
 int miiphy_read(char *devname, unsigned char addr, unsigned char reg,
 		unsigned short *value)
 {
-	struct list_head *entry;
 	struct mii_dev *dev;
-	int found_dev = 0;
 	int read_ret = 0;
 
 	if (!devname) {
-		printf("NULL device name!\n");
+		puts("NULL device name!\n");
 		return 1;
 	}
 
-	list_for_each(entry, &mii_devs) {
-		dev = list_entry(entry, struct mii_dev, link);
-
-		if (strcmp(devname, dev->name) == 0) {
-			found_dev = 1;
-			read_ret = dev->read(devname, addr, reg, value);
-			break;
-		}
-	}
-
-	if (found_dev == 0)
+	if ((dev = find_miiphy(devname)) != NULL)
+		read_ret = dev->read(devname, addr, reg, value);
+	else
 		printf("No such device: %s\n", devname);
 
-	return ((found_dev) ? read_ret : 1);
+	return (dev ? read_ret : 1);
 }
 
 /*****************************************************************************
@@ -196,30 +246,83 @@ int miiphy_read(char *devname, unsigned 
 int miiphy_write(char *devname, unsigned char addr, unsigned char reg,
 		unsigned short value)
 {
-	struct list_head *entry;
 	struct mii_dev *dev;
-	int found_dev = 0;
 	int write_ret = 0;
 
 	if (!devname) {
-		printf("NULL device name!\n");
+		puts("NULL device name!\n");
 		return 1;
 	}
 
-	list_for_each(entry, &mii_devs) {
-		dev = list_entry(entry, struct mii_dev, link);
+	if ((dev = find_miiphy(devname)) != NULL)
+		write_ret = dev->write(devname, addr, reg, value);
+	else
+		printf("No such device: %s\n", devname);
 
-		if (strcmp(devname, dev->name) == 0) {
-			found_dev = 1;
-			write_ret = dev->write(devname, addr, reg, value);
-			break;
+	return (dev ? write_ret : 1);
+}
+/*****************************************************************************
+ *
+ * Set the offset for indirect addressing of PHY registers (802.3ae only )
+ * use PHY address <addr> and register <reg>.
+ *
+ * Returns:
+ *   0 on success
+ */
+int miiphy_ind_address(char *devname, unsigned char addr, unsigned char reg,
+		unsigned short value)
+{
+	struct mii_dev *dev;
+	int addr_ret = 0;
+
+	if (!devname) {
+		puts("NULL device name!\n");
+		return 1;
+	}
+
+	if ((dev = find_miiphy(devname)) != NULL) {
+		if (dev->ind_address) 
+			addr_ret = dev->ind_address(devname, addr, reg, value);
+		else {
+			puts("Indirect addressing not supported\n");
+			addr_ret = 1;
 		}
+	} else
+		printf("No such device: %s\n", devname);
+
+	return (dev ? addr_ret : 1);
+}
+
+/*****************************************************************************
+ *
+ * Perform a fixed-address read  of PHY registers (802.3ae only )
+ * use PHY address <addr> and register <reg>.
+ *
+ * Returns:
+ *   0 on success
+ */
+int miiphy_read_fixed(char *devname, unsigned char addr, unsigned char reg,
+		unsigned short *value)
+{
+	struct mii_dev *dev;
+	int read_ret = 0;
+
+	if (!devname) {
+		puts("NULL device name!\n");
+		return 1;
 	}
 
-	if (found_dev == 0)
+	if ((dev = find_miiphy(devname)) != NULL) {
+		if (dev->read_fixed) 
+			read_ret = dev->read_fixed(devname, addr, reg, value);
+		else {
+			puts("Fixed read not supported on this device\n");
+			read_ret = 1;
+		}
+	} else
 		printf("No such device: %s\n", devname);
 
-	return ((found_dev) ? write_ret : 1);
+	return (dev ? read_ret : 1);
 }
 
 /*****************************************************************************
diff --git a/include/miiphy.h b/include/miiphy.h
index 71716b0..9e7e35f 100644
--- a/include/miiphy.h
+++ b/include/miiphy.h
@@ -40,10 +40,31 @@ #define _miiphy_h_
 
 #include <net.h>
 
+enum miiphy_attr
+{
+	MIIPHY_NAME = 0,
+	MIIPHY_READ_FUNC,
+	MIIPHY_WRITE_FUNC,
+	MIIPHY_IND_ADDR_FUNC,
+	MIIPHY_READ_FIXED_FUNC,
+	MIIPHY_FLAGS,
+};
+
+#define MII_FLAG_802_3ae 0x01
+
+/* Direct read of an MIIPHY register */
 int  miiphy_read(char *devname, unsigned char addr, unsigned char reg,
 		unsigned short *value);
+/* Direct write of an MIIPHY register */
 int  miiphy_write(char *devname, unsigned char addr, unsigned char reg,
 		unsigned short value);
+/* Set the address for indirect access */
+int  miiphy_ind_address(char *devname, unsigned char addr,
+		unsigned char reg, unsigned short value);
+/* Fixed-address read of an MIIPHY register */
+int  miiphy_read_fixed(char *devname, unsigned char addr,
+		unsigned char reg, unsigned short *value);
+
 int  miiphy_info(char *devname, unsigned char addr, unsigned int  *oui,
 		unsigned char *model, unsigned char *rev);
 int  miiphy_reset(char *devname, unsigned char addr);
@@ -61,9 +82,14 @@ void miiphy_register(char *devname,
 	int (* write)(char *devname, unsigned char addr,
 		unsigned char reg, unsigned short value));
 
+int miiphy_set_attribute(char *devname, 
+		enum miiphy_attr attr, void *value);
+
 int miiphy_set_current_dev(char *devname);
 char *miiphy_get_current_dev(void);
 
+unsigned char miiphy_get_flags(char *devname);
+
 void miiphy_listdev(void);
 
 #define BB_MII_DEVNAME	"bbmii"
-- 
1.4.1






More information about the U-Boot mailing list