|
|
|
@ -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); |
|
|
|
|
} |
|
|
|
|