|
@@ -30,6 +30,215 @@
|
|
|
#include <miiphy.h>
|
|
|
|
|
|
#if defined(CONFIG_MII) || (CONFIG_COMMANDS & CFG_CMD_MII)
|
|
|
+#include <asm/types.h>
|
|
|
+#include <linux/list.h>
|
|
|
+#include <malloc.h>
|
|
|
+#include <net.h>
|
|
|
+
|
|
|
+/* local debug macro */
|
|
|
+#define MII_DEBUG
|
|
|
+#undef MII_DEBUG
|
|
|
+
|
|
|
+#undef debug
|
|
|
+#ifdef MII_DEBUG
|
|
|
+#define debug(fmt,args...) printf (fmt ,##args)
|
|
|
+#else
|
|
|
+#define debug(fmt,args...)
|
|
|
+#endif /* MII_DEBUG */
|
|
|
+
|
|
|
+struct mii_dev {
|
|
|
+ struct list_head link;
|
|
|
+ char *name;
|
|
|
+ int (* read)(char *devname, unsigned char addr,
|
|
|
+ unsigned char reg, unsigned short *value);
|
|
|
+ int (* write)(char *devname, unsigned char addr,
|
|
|
+ unsigned char reg, unsigned short value);
|
|
|
+};
|
|
|
+
|
|
|
+static struct list_head mii_devs;
|
|
|
+static struct mii_dev *current_mii;
|
|
|
+
|
|
|
+/*****************************************************************************
|
|
|
+ *
|
|
|
+ * Register read and write MII access routines for the device <name>.
|
|
|
+ */
|
|
|
+void miiphy_register(char *name,
|
|
|
+ int (* read)(char *devname, unsigned char addr,
|
|
|
+ unsigned char reg, unsigned short *value),
|
|
|
+ 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;
|
|
|
+ static int head_initialized = 0;
|
|
|
+ unsigned int name_len;
|
|
|
+
|
|
|
+ if (head_initialized == 0) {
|
|
|
+ INIT_LIST_HEAD(&mii_devs);
|
|
|
+ current_mii = NULL;
|
|
|
+ head_initialized = 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* 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;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /* allocate memory */
|
|
|
+ name_len = strlen(name);
|
|
|
+ new_dev = (struct mii_dev *)malloc(sizeof(struct mii_dev) + name_len + 1);
|
|
|
+
|
|
|
+ if(new_dev == NULL) {
|
|
|
+ printf("miiphy_register: cannot allocate memory for '%s'\n",
|
|
|
+ name);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ memset(new_dev, 0, sizeof(struct mii_dev) + name_len);
|
|
|
+
|
|
|
+ /* initalize mii_dev struct fields */
|
|
|
+ INIT_LIST_HEAD(&new_dev->link);
|
|
|
+ new_dev->read = read;
|
|
|
+ new_dev->write = write;
|
|
|
+ new_dev->name = (char *)(new_dev + 1);
|
|
|
+ strncpy(new_dev->name, name, name_len);
|
|
|
+ new_dev->name[name_len] = '\0';
|
|
|
+
|
|
|
+ debug("miiphy_register: added '%s', read=0x%08lx, write=0x%08lx\n",
|
|
|
+ new_dev->name, new_dev->read, new_dev->write);
|
|
|
+
|
|
|
+ /* add it to the list */
|
|
|
+ list_add_tail(&new_dev->link, &mii_devs);
|
|
|
+
|
|
|
+ if (!current_mii)
|
|
|
+ current_mii = new_dev;
|
|
|
+}
|
|
|
+
|
|
|
+int miiphy_set_current_dev(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) {
|
|
|
+ current_mii = dev;
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ printf("No such device: %s\n", devname);
|
|
|
+ return 1;
|
|
|
+}
|
|
|
+
|
|
|
+char *miiphy_get_current_dev()
|
|
|
+{
|
|
|
+ if (current_mii)
|
|
|
+ return current_mii->name;
|
|
|
+
|
|
|
+ return NULL;
|
|
|
+}
|
|
|
+
|
|
|
+/*****************************************************************************
|
|
|
+ *
|
|
|
+ * Read to variable <value> from the PHY attached to device <devname>,
|
|
|
+ * use PHY address <addr> and register <reg>.
|
|
|
+ *
|
|
|
+ * Returns:
|
|
|
+ * 0 on success
|
|
|
+ */
|
|
|
+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");
|
|
|
+ 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)
|
|
|
+ printf("No such device: %s\n", devname);
|
|
|
+
|
|
|
+ return ((found_dev) ? read_ret : 1);
|
|
|
+}
|
|
|
+
|
|
|
+/*****************************************************************************
|
|
|
+ *
|
|
|
+ * Write <value> to the PHY attached to device <devname>,
|
|
|
+ * use PHY address <addr> and register <reg>.
|
|
|
+ *
|
|
|
+ * Returns:
|
|
|
+ * 0 on success
|
|
|
+ */
|
|
|
+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");
|
|
|
+ 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;
|
|
|
+ write_ret = dev->write(devname, addr, reg, value);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (found_dev == 0)
|
|
|
+ printf("No such device: %s\n", devname);
|
|
|
+
|
|
|
+ return ((found_dev) ? write_ret : 1);
|
|
|
+}
|
|
|
+
|
|
|
+/*****************************************************************************
|
|
|
+ *
|
|
|
+ * Print out list of registered MII capable devices.
|
|
|
+ */
|
|
|
+void miiphy_listdev(void)
|
|
|
+{
|
|
|
+ struct list_head *entry;
|
|
|
+ struct mii_dev *dev;
|
|
|
+
|
|
|
+ puts("MII devices: ");
|
|
|
+ list_for_each(entry, &mii_devs) {
|
|
|
+ dev = list_entry(entry, struct mii_dev, link);
|
|
|
+ printf("'%s' ", dev->name);
|
|
|
+ }
|
|
|
+ puts("\n");
|
|
|
+
|
|
|
+ if (current_mii)
|
|
|
+ printf("Current device: '%s'\n", current_mii->name);
|
|
|
+}
|
|
|
+
|
|
|
|
|
|
/*****************************************************************************
|
|
|
*
|
|
@@ -42,14 +251,15 @@
|
|
|
* Returns:
|
|
|
* 0 on success
|
|
|
*/
|
|
|
-int miiphy_info (unsigned char addr,
|
|
|
+int miiphy_info (char *devname,
|
|
|
+ unsigned char addr,
|
|
|
unsigned int *oui,
|
|
|
unsigned char *model, unsigned char *rev)
|
|
|
{
|
|
|
unsigned int reg = 0;
|
|
|
unsigned short tmp;
|
|
|
|
|
|
- if (miiphy_read (addr, PHY_PHYIDR2, &tmp) != 0) {
|
|
|
+ if (miiphy_read (devname, addr, PHY_PHYIDR2, &tmp) != 0) {
|
|
|
#ifdef DEBUG
|
|
|
puts ("PHY ID register 2 read failed\n");
|
|
|
#endif
|
|
@@ -65,7 +275,7 @@ int miiphy_info (unsigned char addr,
|
|
|
return (-1);
|
|
|
}
|
|
|
|
|
|
- if (miiphy_read (addr, PHY_PHYIDR1, &tmp) != 0) {
|
|
|
+ if (miiphy_read (devname, addr, PHY_PHYIDR1, &tmp) != 0) {
|
|
|
#ifdef DEBUG
|
|
|
puts ("PHY ID register 1 read failed\n");
|
|
|
#endif
|
|
@@ -88,18 +298,18 @@ int miiphy_info (unsigned char addr,
|
|
|
* Returns:
|
|
|
* 0 on success
|
|
|
*/
|
|
|
-int miiphy_reset (unsigned char addr)
|
|
|
+int miiphy_reset (char *devname, unsigned char addr)
|
|
|
{
|
|
|
unsigned short reg;
|
|
|
int loop_cnt;
|
|
|
|
|
|
- if (miiphy_read (addr, PHY_BMCR, ®) != 0) {
|
|
|
+ if (miiphy_read (devname, addr, PHY_BMCR, ®) != 0) {
|
|
|
#ifdef DEBUG
|
|
|
printf ("PHY status read failed\n");
|
|
|
#endif
|
|
|
return (-1);
|
|
|
}
|
|
|
- if (miiphy_write (addr, PHY_BMCR, reg | 0x8000) != 0) {
|
|
|
+ if (miiphy_write (devname, addr, PHY_BMCR, reg | 0x8000) != 0) {
|
|
|
#ifdef DEBUG
|
|
|
puts ("PHY reset failed\n");
|
|
|
#endif
|
|
@@ -116,7 +326,7 @@ int miiphy_reset (unsigned char addr)
|
|
|
loop_cnt = 0;
|
|
|
reg = 0x8000;
|
|
|
while (((reg & 0x8000) != 0) && (loop_cnt++ < 1000000)) {
|
|
|
- if (miiphy_read (addr, PHY_BMCR, ®) != 0) {
|
|
|
+ if (miiphy_read (devname, addr, PHY_BMCR, ®) != 0) {
|
|
|
# ifdef DEBUG
|
|
|
puts ("PHY status read failed\n");
|
|
|
# endif
|
|
@@ -137,12 +347,12 @@ int miiphy_reset (unsigned char addr)
|
|
|
*
|
|
|
* Determine the ethernet speed (10/100).
|
|
|
*/
|
|
|
-int miiphy_speed (unsigned char addr)
|
|
|
+int miiphy_speed (char *devname, unsigned char addr)
|
|
|
{
|
|
|
unsigned short reg;
|
|
|
|
|
|
#if defined(CONFIG_PHY_GIGE)
|
|
|
- if (miiphy_read (addr, PHY_1000BTSR, ®)) {
|
|
|
+ if (miiphy_read (devname, addr, PHY_1000BTSR, ®)) {
|
|
|
printf ("PHY 1000BT Status read failed\n");
|
|
|
} else {
|
|
|
if (reg != 0xFFFF) {
|
|
@@ -154,14 +364,14 @@ int miiphy_speed (unsigned char addr)
|
|
|
#endif /* CONFIG_PHY_GIGE */
|
|
|
|
|
|
/* Check Basic Management Control Register first. */
|
|
|
- if (miiphy_read (addr, PHY_BMCR, ®)) {
|
|
|
+ if (miiphy_read (devname, addr, PHY_BMCR, ®)) {
|
|
|
puts ("PHY speed read failed, assuming 10bT\n");
|
|
|
return (_10BASET);
|
|
|
}
|
|
|
/* Check if auto-negotiation is on. */
|
|
|
if ((reg & PHY_BMCR_AUTON) != 0) {
|
|
|
/* Get auto-negotiation results. */
|
|
|
- if (miiphy_read (addr, PHY_ANLPAR, ®)) {
|
|
|
+ if (miiphy_read (devname, addr, PHY_ANLPAR, ®)) {
|
|
|
puts ("PHY AN speed read failed, assuming 10bT\n");
|
|
|
return (_10BASET);
|
|
|
}
|
|
@@ -185,12 +395,12 @@ int miiphy_speed (unsigned char addr)
|
|
|
*
|
|
|
* Determine full/half duplex.
|
|
|
*/
|
|
|
-int miiphy_duplex (unsigned char addr)
|
|
|
+int miiphy_duplex (char *devname, unsigned char addr)
|
|
|
{
|
|
|
unsigned short reg;
|
|
|
|
|
|
#if defined(CONFIG_PHY_GIGE)
|
|
|
- if (miiphy_read (addr, PHY_1000BTSR, ®)) {
|
|
|
+ if (miiphy_read (devname, addr, PHY_1000BTSR, ®)) {
|
|
|
printf ("PHY 1000BT Status read failed\n");
|
|
|
} else {
|
|
|
if ( (reg != 0xFFFF) &&
|
|
@@ -205,14 +415,14 @@ int miiphy_duplex (unsigned char addr)
|
|
|
#endif /* CONFIG_PHY_GIGE */
|
|
|
|
|
|
/* Check Basic Management Control Register first. */
|
|
|
- if (miiphy_read (addr, PHY_BMCR, ®)) {
|
|
|
+ if (miiphy_read (devname, addr, PHY_BMCR, ®)) {
|
|
|
puts ("PHY duplex read failed, assuming half duplex\n");
|
|
|
return (HALF);
|
|
|
}
|
|
|
/* Check if auto-negotiation is on. */
|
|
|
if ((reg & PHY_BMCR_AUTON) != 0) {
|
|
|
/* Get auto-negotiation results. */
|
|
|
- if (miiphy_read (addr, PHY_ANLPAR, ®)) {
|
|
|
+ if (miiphy_read (devname, addr, PHY_ANLPAR, ®)) {
|
|
|
puts ("PHY AN duplex read failed, assuming half duplex\n");
|
|
|
return (HALF);
|
|
|
}
|
|
@@ -237,13 +447,13 @@ int miiphy_duplex (unsigned char addr)
|
|
|
*
|
|
|
* Determine link status
|
|
|
*/
|
|
|
-int miiphy_link (unsigned char addr)
|
|
|
+int miiphy_link (char *devname, unsigned char addr)
|
|
|
{
|
|
|
unsigned short reg;
|
|
|
|
|
|
/* dummy read; needed to latch some phys */
|
|
|
- (void)miiphy_read(addr, PHY_BMSR, ®);
|
|
|
- if (miiphy_read (addr, PHY_BMSR, ®)) {
|
|
|
+ (void)miiphy_read(devname, addr, PHY_BMSR, ®);
|
|
|
+ if (miiphy_read (devname, addr, PHY_BMSR, ®)) {
|
|
|
puts ("PHY_BMSR read failed, assuming no link\n");
|
|
|
return (0);
|
|
|
}
|