diff options
Diffstat (limited to 'common/miiphyutil.c')
| -rw-r--r-- | common/miiphyutil.c | 249 | 
1 files changed, 231 insertions, 18 deletions
| diff --git a/common/miiphyutil.c b/common/miiphyutil.c index 13b9c65dc..e411e573c 100644 --- a/common/miiphyutil.c +++ b/common/miiphyutil.c @@ -30,6 +30,218 @@  #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; + +/***************************************************************************** + * + * Initialize global data. Need to be called before any other miiphy routine. + */ +void miiphy_init() +{ +		INIT_LIST_HEAD(&mii_devs); +		current_mii = NULL; +} + +/***************************************************************************** + * + * 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; +	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; +		} +	} + +	/* 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 +254,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 +278,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 +301,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 +329,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 +350,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 +367,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 +398,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 +418,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 +450,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);  	} |