diff options
Diffstat (limited to 'common/miiphyutil.c')
| -rw-r--r-- | common/miiphyutil.c | 311 | 
1 files changed, 210 insertions, 101 deletions
| diff --git a/common/miiphyutil.c b/common/miiphyutil.c index e282096a1..243cae97a 100644 --- a/common/miiphyutil.c +++ b/common/miiphyutil.c @@ -28,6 +28,7 @@  #include <common.h>  #include <miiphy.h> +#include <phy.h>  #include <asm/types.h>  #include <linux/list.h> @@ -39,27 +40,18 @@  #undef debug  #ifdef MII_DEBUG -#define debug(fmt,args...)	printf (fmt ,##args) +#define debug(fmt, args...)	printf(fmt, ##args)  #else -#define debug(fmt,args...) +#define debug(fmt, args...)  #endif /* MII_DEBUG */ -struct mii_dev { -	struct list_head link; -	const char *name; -	int (*read) (const char *devname, unsigned char addr, -		     unsigned char reg, unsigned short *value); -	int (*write) (const char *devname, unsigned char addr, -		      unsigned char reg, unsigned short value); -}; -  static struct list_head mii_devs;  static struct mii_dev *current_mii;  /*   * Lookup the mii_dev struct by the registered device name.   */ -static struct mii_dev *miiphy_get_dev_by_name(const char *devname, int quiet) +struct mii_dev *miiphy_get_dev_by_name(const char *devname)  {  	struct list_head *entry;  	struct mii_dev *dev; @@ -75,8 +67,6 @@ static struct mii_dev *miiphy_get_dev_by_name(const char *devname, int quiet)  			return dev;  	} -	if (!quiet) -		printf("No such device: %s\n", devname);  	return NULL;  } @@ -86,74 +76,190 @@ static struct mii_dev *miiphy_get_dev_by_name(const char *devname, int quiet)   */  void miiphy_init(void)  { -	INIT_LIST_HEAD (&mii_devs); +	INIT_LIST_HEAD(&mii_devs);  	current_mii = NULL;  } +static int legacy_miiphy_read(struct mii_dev *bus, int addr, int devad, int reg) +{ +	unsigned short val; +	int ret; +	struct legacy_mii_dev *ldev = bus->priv; + +	ret = ldev->read(bus->name, addr, reg, &val); + +	return ret ? -1 : (int)val; +} + +static int legacy_miiphy_write(struct mii_dev *bus, int addr, int devad, +				int reg, u16 val) +{ +	struct legacy_mii_dev *ldev = bus->priv; + +	return ldev->write(bus->name, addr, reg, val); +} +  /*****************************************************************************   *   * Register read and write MII access routines for the device <name>.   */  void miiphy_register(const char *name, -		      int (*read) (const char *devname, unsigned char addr, +		      int (*read)(const char *devname, unsigned char addr,  				   unsigned char reg, unsigned short *value), -		      int (*write) (const char *devname, unsigned char addr, +		      int (*write)(const char *devname, unsigned char addr,  				    unsigned char reg, unsigned short value))  {  	struct mii_dev *new_dev; +	struct legacy_mii_dev *ldev;  	unsigned int name_len; -	char *new_name;  	/* check if we have unique name */ -	new_dev = miiphy_get_dev_by_name(name, 1); +	new_dev = miiphy_get_dev_by_name(name);  	if (new_dev) {  		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); +	name_len = strlen(name); +	if (name_len > MDIO_NAME_LEN - 1) { +		/* Hopefully this won't happen, but if it does, we'll know */ +		printf("miiphy_register: MDIO name was longer than %d\n", +			MDIO_NAME_LEN); +		return; +	} + +	new_dev = mdio_alloc(); +	ldev = malloc(sizeof(*ldev)); -	if (new_dev == NULL) { -		printf ("miiphy_register: cannot allocate memory for '%s'\n", +	if (new_dev == NULL || ldev == 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 = new_name = (char *)(new_dev + 1); -	strncpy (new_name, name, name_len); -	new_name[name_len] = '\0'; +	new_dev->read = legacy_miiphy_read; +	new_dev->write = legacy_miiphy_write; +	sprintf(new_dev->name, name); +	ldev->read = read; +	ldev->write = write; +	new_dev->priv = ldev; -	debug ("miiphy_register: added '%s', read=0x%08lx, write=0x%08lx\n", -	       new_dev->name, new_dev->read, new_dev->write); +	debug("miiphy_register: added '%s', read=0x%08lx, write=0x%08lx\n", +	       new_dev->name, ldev->read, ldev->write);  	/* add it to the list */ -	list_add_tail (&new_dev->link, &mii_devs); +	list_add_tail(&new_dev->link, &mii_devs);  	if (!current_mii)  		current_mii = new_dev;  } +struct mii_dev *mdio_alloc(void) +{ +	struct mii_dev *bus; + +	bus = malloc(sizeof(*bus)); +	if (!bus) +		return bus; + +	memset(bus, 0, sizeof(*bus)); + +	/* initalize mii_dev struct fields */ +	INIT_LIST_HEAD(&bus->link); + +	return bus; +} + +int mdio_register(struct mii_dev *bus) +{ +	if (!bus || !bus->name || !bus->read || !bus->write) +		return -1; + +	/* check if we have unique name */ +	if (miiphy_get_dev_by_name(bus->name)) { +		printf("mdio_register: non unique device name '%s'\n", +			bus->name); +		return -1; +	} + +	/* add it to the list */ +	list_add_tail(&bus->link, &mii_devs); + +	if (!current_mii) +		current_mii = bus; + +	return 0; +} + +void mdio_list_devices(void) +{ +	struct list_head *entry; + +	list_for_each(entry, &mii_devs) { +		int i; +		struct mii_dev *bus = list_entry(entry, struct mii_dev, link); + +		printf("%s:\n", bus->name); + +		for (i = 0; i < PHY_MAX_ADDR; i++) { +			struct phy_device *phydev = bus->phymap[i]; + +			if (phydev) { +				printf("%d - %s", i, phydev->drv->name); + +				if (phydev->dev) +					printf(" <--> %s\n", phydev->dev->name); +				else +					printf("\n"); +			} +		} +	} +} +  int miiphy_set_current_dev(const char *devname)  {  	struct mii_dev *dev; -	dev = miiphy_get_dev_by_name(devname, 0); +	dev = miiphy_get_dev_by_name(devname);  	if (dev) {  		current_mii = dev;  		return 0;  	} +	printf("No such device: %s\n", devname); +  	return 1;  } +struct mii_dev *mdio_get_current_dev(void) +{ +	return current_mii; +} + +struct phy_device *mdio_phydev_for_ethname(const char *ethname) +{ +	struct list_head *entry; +	struct mii_dev *bus; + +	list_for_each(entry, &mii_devs) { +		int i; +		bus = list_entry(entry, struct mii_dev, link); + +		for (i = 0; i < PHY_MAX_ADDR; i++) { +			if (!bus->phymap[i] || !bus->phymap[i]->dev) +				continue; + +			if (strcmp(bus->phymap[i]->dev->name, ethname) == 0) +				return bus->phymap[i]; +		} +	} + +	printf("%s is not a known ethernet\n", ethname); +	return NULL; +} +  const char *miiphy_get_current_dev(void)  {  	if (current_mii) @@ -187,13 +293,15 @@ static struct mii_dev *miiphy_get_active_dev(const char *devname)  int miiphy_read(const char *devname, unsigned char addr, unsigned char reg,  		 unsigned short *value)  { -	struct mii_dev *dev; +	struct mii_dev *bus; -	dev = miiphy_get_active_dev(devname); -	if (dev) -		return dev->read(devname, addr, reg, value); +	bus = miiphy_get_active_dev(devname); +	if (bus) +		*value = bus->read(bus, addr, MDIO_DEVAD_NONE, reg); +	else +		return 1; -	return 1; +	return (*value < 0) ? 1 : 0;  }  /***************************************************************************** @@ -207,11 +315,11 @@ int miiphy_read(const char *devname, unsigned char addr, unsigned char reg,  int miiphy_write(const char *devname, unsigned char addr, unsigned char reg,  		  unsigned short value)  { -	struct mii_dev *dev; +	struct mii_dev *bus; -	dev = miiphy_get_active_dev(devname); -	if (dev) -		return dev->write(devname, addr, reg, value); +	bus = miiphy_get_active_dev(devname); +	if (bus) +		return bus->write(bus, addr, MDIO_DEVAD_NONE, reg, value);  	return 1;  } @@ -220,20 +328,20 @@ int miiphy_write(const char *devname, unsigned char addr, unsigned char reg,   *   * Print out list of registered MII capable devices.   */ -void miiphy_listdev (void) +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("MII devices: "); +	list_for_each(entry, &mii_devs) { +		dev = list_entry(entry, struct mii_dev, link); +		printf("'%s' ", dev->name);  	} -	puts ("\n"); +	puts("\n");  	if (current_mii) -		printf ("Current device: '%s'\n", current_mii->name); +		printf("Current device: '%s'\n", current_mii->name);  }  /***************************************************************************** @@ -253,32 +361,33 @@ int miiphy_info(const char *devname, unsigned char addr, unsigned int *oui,  	unsigned int reg = 0;  	unsigned short tmp; -	if (miiphy_read (devname, addr, MII_PHYSID2, &tmp) != 0) { -		debug ("PHY ID register 2 read failed\n"); -		return (-1); +	if (miiphy_read(devname, addr, MII_PHYSID2, &tmp) != 0) { +		debug("PHY ID register 2 read failed\n"); +		return -1;  	}  	reg = tmp; -	debug ("MII_PHYSID2 @ 0x%x = 0x%04x\n", addr, reg); +	debug("MII_PHYSID2 @ 0x%x = 0x%04x\n", addr, reg);  	if (reg == 0xFFFF) {  		/* No physical device present at this address */ -		return (-1); +		return -1;  	} -	if (miiphy_read (devname, addr, MII_PHYSID1, &tmp) != 0) { -		debug ("PHY ID register 1 read failed\n"); -		return (-1); +	if (miiphy_read(devname, addr, MII_PHYSID1, &tmp) != 0) { +		debug("PHY ID register 1 read failed\n"); +		return -1;  	}  	reg |= tmp << 16; -	debug ("PHY_PHYIDR[1,2] @ 0x%x = 0x%08x\n", addr, reg); +	debug("PHY_PHYIDR[1,2] @ 0x%x = 0x%08x\n", addr, reg);  	*oui = (reg >> 10);  	*model = (unsigned char)((reg >> 4) & 0x0000003F);  	*rev = (unsigned char)(reg & 0x0000000F); -	return (0); +	return 0;  } +#ifndef CONFIG_PHYLIB  /*****************************************************************************   *   * Reset the PHY. @@ -290,16 +399,16 @@ int miiphy_reset(const char *devname, unsigned char addr)  	unsigned short reg;  	int timeout = 500; -	if (miiphy_read (devname, addr, MII_BMCR, ®) != 0) { -		debug ("PHY status read failed\n"); -		return (-1); +	if (miiphy_read(devname, addr, MII_BMCR, ®) != 0) { +		debug("PHY status read failed\n"); +		return -1;  	} -	if (miiphy_write (devname, addr, MII_BMCR, reg | BMCR_RESET) != 0) { -		debug ("PHY reset failed\n"); -		return (-1); +	if (miiphy_write(devname, addr, MII_BMCR, reg | BMCR_RESET) != 0) { +		debug("PHY reset failed\n"); +		return -1;  	}  #ifdef CONFIG_PHY_RESET_DELAY -	udelay (CONFIG_PHY_RESET_DELAY);	/* Intel LXT971A needs this */ +	udelay(CONFIG_PHY_RESET_DELAY);	/* Intel LXT971A needs this */  #endif  	/*  	 * Poll the control register for the reset bit to go to 0 (it is @@ -315,13 +424,14 @@ int miiphy_reset(const char *devname, unsigned char addr)  		udelay(1000);  	}  	if ((reg & 0x8000) == 0) { -		return (0); +		return 0;  	} else { -		puts ("PHY reset timed out\n"); -		return (-1); +		puts("PHY reset timed out\n"); +		return -1;  	} -	return (0); +	return 0;  } +#endif /* !PHYLIB */  /*****************************************************************************   * @@ -338,33 +448,32 @@ int miiphy_speed(const char *devname, unsigned char addr)  	 * Check for 1000BASE-X.  If it is supported, then assume that the speed  	 * is 1000.  	 */ -	if (miiphy_is_1000base_x (devname, addr)) { +	if (miiphy_is_1000base_x(devname, addr))  		return _1000BASET; -	} +  	/*  	 * No 1000BASE-X, so assume 1000BASE-T/100BASE-TX/10BASE-T register set.  	 */  	/* Check for 1000BASE-T. */ -	if (miiphy_read (devname, addr, MII_STAT1000, &btsr)) { -		printf ("PHY 1000BT status"); +	if (miiphy_read(devname, addr, MII_STAT1000, &btsr)) { +		printf("PHY 1000BT status");  		goto miiphy_read_failed;  	}  	if (btsr != 0xFFFF && -	    (btsr & (PHY_1000BTSR_1000FD | PHY_1000BTSR_1000HD))) { +			(btsr & (PHY_1000BTSR_1000FD | PHY_1000BTSR_1000HD)))  		return _1000BASET; -	}  #endif /* CONFIG_PHY_GIGE */  	/* Check Basic Management Control Register first. */ -	if (miiphy_read (devname, addr, MII_BMCR, &bmcr)) { -		printf ("PHY speed"); +	if (miiphy_read(devname, addr, MII_BMCR, &bmcr)) { +		printf("PHY speed");  		goto miiphy_read_failed;  	}  	/* Check if auto-negotiation is on. */  	if (bmcr & BMCR_ANENABLE) {  		/* Get auto-negotiation results. */ -		if (miiphy_read (devname, addr, MII_LPA, &anlpar)) { -			printf ("PHY AN speed"); +		if (miiphy_read(devname, addr, MII_LPA, &anlpar)) { +			printf("PHY AN speed");  			goto miiphy_read_failed;  		}  		return (anlpar & LPA_100) ? _100BASET : _10BASET; @@ -373,7 +482,7 @@ int miiphy_speed(const char *devname, unsigned char addr)  	return (bmcr & BMCR_SPEED100) ? _100BASET : _10BASET;  miiphy_read_failed: -	printf (" read failed, assuming 10BASE-T\n"); +	printf(" read failed, assuming 10BASE-T\n");  	return _10BASET;  } @@ -389,10 +498,10 @@ int miiphy_duplex(const char *devname, unsigned char addr)  	u16 btsr;  	/* Check for 1000BASE-X. */ -	if (miiphy_is_1000base_x (devname, addr)) { +	if (miiphy_is_1000base_x(devname, addr)) {  		/* 1000BASE-X */ -		if (miiphy_read (devname, addr, MII_LPA, &anlpar)) { -			printf ("1000BASE-X PHY AN duplex"); +		if (miiphy_read(devname, addr, MII_LPA, &anlpar)) { +			printf("1000BASE-X PHY AN duplex");  			goto miiphy_read_failed;  		}  	} @@ -400,8 +509,8 @@ int miiphy_duplex(const char *devname, unsigned char addr)  	 * No 1000BASE-X, so assume 1000BASE-T/100BASE-TX/10BASE-T register set.  	 */  	/* Check for 1000BASE-T. */ -	if (miiphy_read (devname, addr, MII_STAT1000, &btsr)) { -		printf ("PHY 1000BT status"); +	if (miiphy_read(devname, addr, MII_STAT1000, &btsr)) { +		printf("PHY 1000BT status");  		goto miiphy_read_failed;  	}  	if (btsr != 0xFFFF) { @@ -414,15 +523,15 @@ int miiphy_duplex(const char *devname, unsigned char addr)  #endif /* CONFIG_PHY_GIGE */  	/* Check Basic Management Control Register first. */ -	if (miiphy_read (devname, addr, MII_BMCR, &bmcr)) { -		puts ("PHY duplex"); +	if (miiphy_read(devname, addr, MII_BMCR, &bmcr)) { +		puts("PHY duplex");  		goto miiphy_read_failed;  	}  	/* Check if auto-negotiation is on. */  	if (bmcr & BMCR_ANENABLE) {  		/* Get auto-negotiation results. */ -		if (miiphy_read (devname, addr, MII_LPA, &anlpar)) { -			puts ("PHY AN duplex"); +		if (miiphy_read(devname, addr, MII_LPA, &anlpar)) { +			puts("PHY AN duplex");  			goto miiphy_read_failed;  		}  		return (anlpar & (LPA_10FULL | LPA_100FULL)) ? @@ -432,7 +541,7 @@ int miiphy_duplex(const char *devname, unsigned char addr)  	return (bmcr & BMCR_FULLDPLX) ? FULL : HALF;  miiphy_read_failed: -	printf (" read failed, assuming half duplex\n"); +	printf(" read failed, assuming half duplex\n");  	return HALF;  } @@ -446,8 +555,8 @@ int miiphy_is_1000base_x(const char *devname, unsigned char addr)  #if defined(CONFIG_PHY_GIGE)  	u16 exsr; -	if (miiphy_read (devname, addr, MII_ESTATUS, &exsr)) { -		printf ("PHY extended status read failed, assuming no " +	if (miiphy_read(devname, addr, MII_ESTATUS, &exsr)) { +		printf("PHY extended status read failed, assuming no "  			"1000BASE-X\n");  		return 0;  	} @@ -467,17 +576,17 @@ int miiphy_link(const char *devname, unsigned char addr)  	unsigned short reg;  	/* dummy read; needed to latch some phys */ -	(void)miiphy_read (devname, addr, MII_BMSR, ®); -	if (miiphy_read (devname, addr, MII_BMSR, ®)) { -		puts ("MII_BMSR read failed, assuming no link\n"); -		return (0); +	(void)miiphy_read(devname, addr, MII_BMSR, ®); +	if (miiphy_read(devname, addr, MII_BMSR, ®)) { +		puts("MII_BMSR read failed, assuming no link\n"); +		return 0;  	}  	/* Determine if a link is active */  	if ((reg & BMSR_LSTATUS) != 0) { -		return (1); +		return 1;  	} else { -		return (0); +		return 0;  	}  }  #endif |