[U-Boot] [PATCH] net: asix: add support for AX88772B

Marek Vasut marex at denx.de
Mon Aug 20 16:13:06 CEST 2012


Dear Lucas Stach,

> There are multiple changes needed to make AX88772B work:
> 
> 1. add vendor and product ID (trivial)
> 
> 2. We need to read out the MAC address from the EEPROM and write
> it into the NodeID register manually.
> 
> 3. The packet length check has to be adjusted, as all ASIX chips
> only use 11 bits to indicate the length. AX88772B uses the other
> bits to indicate unrelated things, which cause the check to fail.
> This fix is based on a fix for the Linux kernel by Marek Vasut.
> Linux upstream commit: bca0beb9363f8487ac902931a50eb00180a2d14a

Yea, I enjoyed my share with this one. Though the linux patch still doesn't work 
on my hardware completely ... I get some random trouble. Do you get any mess in 
dmesg?

> 4. AX88772B provides several bulk endpoints. Only the first
> IN/OUT endpoints work in the default configuration. So stop
> enumeration after we found them to avoid overwriting the
> endpoint config with a non-working one.

;-)

> This was tested to work on a Colibri T20 board.
> Patch is based on u-boot-net/next.
> 
> Signed-off-by: Lucas Stach <dev at lynxeye.de>
> ---
>  drivers/usb/eth/asix.c | 62
> +++++++++++++++++++++++++++++++++++++++++--------- 1 Datei geändert, 51
> Zeilen hinzugefügt(+), 11 Zeilen entfernt(-)
> 
> diff --git a/drivers/usb/eth/asix.c b/drivers/usb/eth/asix.c
> index 8fb7fc8..86e0f0f 100644
> --- a/drivers/usb/eth/asix.c
> +++ b/drivers/usb/eth/asix.c
> @@ -31,10 +31,12 @@
>  #define AX_CMD_READ_MII_REG		0x07
>  #define AX_CMD_WRITE_MII_REG		0x08
>  #define AX_CMD_SET_HW_MII		0x0a
> +#define AX_CMD_READ_EEPROM		0x0b
>  #define AX_CMD_READ_RX_CTL		0x0f
>  #define AX_CMD_WRITE_RX_CTL		0x10
>  #define AX_CMD_WRITE_IPG0		0x12
>  #define AX_CMD_READ_NODE_ID		0x13
> +#define AX_CMD_WRITE_NODE_ID	0x14
>  #define AX_CMD_READ_PHY_ID		0x19
>  #define AX_CMD_WRITE_MEDIUM_MODE	0x1b
>  #define AX_CMD_WRITE_GPIOS		0x1f
> @@ -322,6 +324,7 @@ static int asix_init(struct eth_device *eth, bd_t *bd)
>  	int timeout = 0;
>  #define TIMEOUT_RESOLUTION 50	/* ms */
>  	int link_detected;
> +	int i;
> 
>  	debug("** %s()\n", __func__);
> 
> @@ -359,6 +362,35 @@ static int asix_init(struct eth_device *eth, bd_t *bd)
>  	rx_ctl = asix_read_rx_ctl(dev);
>  	debug("RX_CTL is 0x%04x setting to 0x0000\n", rx_ctl);
> 
> +	/*
> +	 * For AX88772B to work we have to read the MAC address from the EEPROM
> +	 * and set the node ID manually.
> +	 */
> +	if ((dev->pusb_dev->descriptor.idVendor == 0x0b95) &&
> +	    (dev->pusb_dev->descriptor.idProduct == 0x772b)) {
> +
> +		ALLOC_CACHE_ALIGN_BUFFER(unsigned char, read_buf, 2);
> +		memset(buf, 0, ETH_ALEN);
> +
> +		for (i = 0; i < (ETH_ALEN >> 1); i++) {
> +			memset(read_buf, 0, 2);
> +			if (asix_read_cmd(dev, AX_CMD_READ_EEPROM,
> +			                  0x04 + i, 0, 2, read_buf)) {
> +				debug("Failed to read SROM address 04h.\n");
> +				goto out_err;
> +			}
> +			memcpy((buf + i*2), read_buf, 2);
> +		}
> +
> +		debug("MAC read from EEPROM: %02x:%02x:%02x:%02x:%02x:%02x\n",
> +		       buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]);
> +
> +		if (asix_write_cmd(dev, AX_CMD_WRITE_NODE_ID, 0, 0, ETH_ALEN, 
buf)) {
> +			printf("Failed to set MAC address.\n");
> +			goto out_err;
> +		}
> +	}

Can this be split into separate function?

>  	/* Get the MAC address */
>  	if (asix_read_cmd(dev, AX_CMD_READ_NODE_ID,
>  				0, 0, ETH_ALEN, buf) < 0) {
> @@ -493,13 +525,13 @@ static int asix_recv(struct eth_device *eth)
>  		}
>  		memcpy(&packet_len, buf_ptr, sizeof(packet_len));
>  		le32_to_cpus(&packet_len);
> -		if (((packet_len >> 16) ^ 0xffff) != (packet_len & 0xffff)) {
> +		if (((~packet_len >> 16) & 0x7ff) != (packet_len & 0x7ff)) {
>  			debug("Rx: malformed packet length: %#x (%#x:%#x)\n",
> -			      packet_len, (packet_len >> 16) ^ 0xffff,
> -			      packet_len & 0xffff);
> +			      packet_len, (~packet_len >> 16) & 0x7ff,
> +			      packet_len & 0x7ff);
>  			return -1;
>  		}
> -		packet_len = packet_len & 0xffff;
> +		packet_len = packet_len & 0x7ff;
>  		if (packet_len > actual_len - sizeof(packet_len)) {
>  			debug("Rx: too large packet: %d\n", packet_len);
>  			return -1;
> @@ -546,6 +578,7 @@ static struct asix_dongle asix_dongles[] = {
>  	{ 0x13b1, 0x0018 },	/* Linksys 200M v2.1 */
>  	{ 0x1557, 0x7720 },	/* 0Q0 cable ethernet */
>  	{ 0x2001, 0x3c05 },	/* DLink DUB-E100 H/W Ver B1 Alternate */
> +	{ 0x0b95, 0x772b },	/* ASIX 88772B */

Maybe this list should be extended by caps as it is in linux?

>  	{ 0x0000, 0x0000 }	/* END - Do not remove */
>  };
> 
> @@ -555,6 +588,7 @@ int asix_eth_probe(struct usb_device *dev, unsigned int
> ifnum, {
>  	struct usb_interface *iface;
>  	struct usb_interface_descriptor *iface_desc;
> +	int ep_in_found = 0, ep_out_found = 0;
>  	int i;
> 
>  	/* let's examine the device now */
> @@ -591,13 +625,19 @@ int asix_eth_probe(struct usb_device *dev, unsigned
> int ifnum, /* is it an BULK endpoint? */
>  		if ((iface->ep_desc[i].bmAttributes &
>  		     USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK) {
> -			if (iface->ep_desc[i].bEndpointAddress & USB_DIR_IN)
> -				ss->ep_in = iface->ep_desc[i].bEndpointAddress &
> -					USB_ENDPOINT_NUMBER_MASK;
> -			else
> -				ss->ep_out =
> -					iface->ep_desc[i].bEndpointAddress &
> -					USB_ENDPOINT_NUMBER_MASK;
> +			if (iface->ep_desc[i].bEndpointAddress & USB_DIR_IN) {
> +				if (!ep_in_found) {
> +					ss->ep_in = iface-
>ep_desc[i].bEndpointAddress &
> +					            USB_ENDPOINT_NUMBER_MASK;
> +					ep_in_found = 1;
> +				}
> +			} else {
> +				if (!ep_out_found) {
> +					ss->ep_out = iface-
>ep_desc[i].bEndpointAddress &
> +					             USB_ENDPOINT_NUMBER_MASK;
> +					ep_out_found = 1;
> +				}
> +			}
>  		}
> 
>  		/* is it an interrupt endpoint? */

Best regards,
Marek Vasut


More information about the U-Boot mailing list