[USB] Added asix driver. Only probe function written. MAC address read
authorBalaji Rao <balajirrao@gmail.com>
Wed, 2 Jul 2008 01:35:15 +0000 (07:05 +0530)
committerroot <root@fedora.yogi>
Wed, 2 Jul 2008 01:35:15 +0000 (07:05 +0530)
successfully.

src/Makefile
src/drivers/net/usb/asix.c [new file with mode: 0644]
src/drivers/net/usb/asix.h [new file with mode: 0644]
src/drivers/net/usb/pegasus.c
src/include/gpxe/errfile.h

index f5cf596..22024aa 100644 (file)
@@ -8,7 +8,7 @@ MAKEDEPS        := Makefile .toolcheck .echocheck
 SRCDIRS                :=
 SRCS           :=
 NON_AUTO_SRCS  :=
-DRIVERS                := dm9601 pegasus
+DRIVERS                := dm9601 pegasus asix
 ROMS           :=
 MEDIA          :=
 NON_AUTO_MEDIA :=
diff --git a/src/drivers/net/usb/asix.c b/src/drivers/net/usb/asix.c
new file mode 100644 (file)
index 0000000..c0136a1
--- /dev/null
@@ -0,0 +1,400 @@
+#include <unistd.h>
+#include <stdlib.h>
+#include <gpxe/if_ether.h>
+#include <gpxe/usb.h>
+#include <gpxe/malloc.h>
+#include <gpxe/ethernet.h>
+#include <gpxe/iobuf.h>
+#include <mii.h>
+#include <errno.h>
+#include <little_bswap.h>
+
+#include "asix.h"
+
+static const char driver_name[] = "asix";
+
+static int asix_read_cmd(struct asix *asix, uint8_t cmd, uint16_t value, u16 index,
+                           uint16_t size, void *data)
+{
+       void *buf;
+       int err = -ENOMEM;
+
+       DBG("asix_read_cmd() cmd=0x%02x value=0x%04x index=0x%04x size=%d\n",
+               cmd, value, index, size);
+
+       buf = malloc_dma(size,1);
+       if (!buf)
+               goto out;
+
+       err = usb_control_msg(asix->udev, &asix->udev->ep_0_in, cmd,
+                       USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, value,
+                       index,  buf, size);
+
+       memcpy(data, buf, size);
+       free_dma(buf, size);
+out:
+       return err;
+}
+
+static int asix_write_cmd(struct asix *asix, uint8_t cmd, uint16_t value, u16 index,
+                            uint16_t size, void *data)
+{
+       void *buf = NULL;
+       int err = -ENOMEM;
+
+       DBG("asix_write_cmd() cmd=0x%02x value=0x%04x index=0x%04x size=%d\n",
+               cmd, value, index, size);
+
+       if (data) {
+               buf = malloc_dma(size, 1);
+               if (!buf)
+                       goto out;
+               memcpy(buf, data, size);
+       }
+
+       err = usb_control_msg(asix->udev, &asix->udev->ep_0_out, cmd,
+                       USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                       value, index, buf, size);
+       free_dma(buf, size);
+
+out:
+       return err;
+}
+
+static int asix_write_gpio(struct asix *asix, uint16_t value, int sleep)
+{
+       int ret;
+
+       DBG("asix_write_gpio() - value = 0x%04x\n", value);
+       ret = asix_write_cmd(asix, AX_CMD_WRITE_GPIOS, value, 0, 0, NULL);
+       if (ret < 0)
+               DBG("Failed to write GPIO value 0x%04x: %02x\n",
+                       value, ret);
+
+       if (sleep)
+               mdelay(sleep);
+
+       return ret;
+}
+
+static inline int asix_set_sw_mii(struct asix *asix)
+{
+       int ret;
+       ret = asix_write_cmd(asix, AX_CMD_SET_SW_MII, 0x0000, 0, 0, NULL);
+       if (ret < 0)
+               DBG("Failed to enable software MII access");
+       return ret;
+}
+
+static inline int asix_set_hw_mii(struct asix *asix)
+{
+       int ret;
+       ret = asix_write_cmd(asix, AX_CMD_SET_HW_MII, 0x0000, 0, 0, NULL);
+       if (ret < 0)
+               DBG("Failed to enable hardware MII access");
+       return ret;
+}
+
+static void
+asix_mdio_write(struct net_device *netdev, int phy_id, int loc, int val)
+{
+       struct asix *asix = netdev_priv(netdev);
+       uint16_t res = cpu_to_le16(val);
+
+       DBG("asix_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x\n", phy_id, loc, val);
+       asix_set_sw_mii(asix);
+       asix_write_cmd(asix, AX_CMD_WRITE_MII_REG, phy_id, (uint16_t)loc, 2, &res);
+       asix_set_hw_mii(asix);
+}
+
+static int asix_mdio_read(struct net_device *netdev, int phy_id, int loc)
+{
+       struct asix *asix = netdev_priv(netdev);
+       uint16_t res;
+
+       asix_set_sw_mii(asix);
+       asix_read_cmd(asix, AX_CMD_READ_MII_REG, phy_id,
+                               (uint16_t)loc, 2, &res);
+       asix_set_hw_mii(asix);
+
+       DBG("asix_mdio_read() phy_id=0x%02x, loc=0x%02x, returns=0x%04x\n", phy_id, loc, le16_to_cpu(res));
+
+       return le16_to_cpu(res);
+}
+
+
+static int asix_write_medium_mode(struct asix *asix, uint16_t mode)
+{
+       int ret;
+
+       DBG("asix_write_medium_mode() - mode = 0x%04x\n", mode);
+       ret = asix_write_cmd(asix, AX_CMD_WRITE_MEDIUM_MODE, mode, 0, 0, NULL);
+       if (ret < 0)
+               DBG("Failed to write Medium Mode mode to 0x%04x: %02x\n",
+                       mode, ret);
+
+       return ret;
+}
+
+static inline int asix_get_phy_addr(struct asix *asix)
+{
+       uint8_t buf[2];
+       int ret = asix_read_cmd(asix, AX_CMD_READ_PHY_ID, 0, 0, 2, buf);
+
+       DBG("asix_get_phy_addr()");
+
+       if (ret < 0) {
+               DBG("Error reading PHYID register: %02x\n", ret);
+               goto out;
+       }
+       DBG("asix_get_phy_addr() returning 0x%04x\n", *((uint16_t *)buf));
+       ret = buf[1];
+
+out:
+       return ret;
+}
+
+int asix_open ( struct net_device *netdev __unused)
+{
+
+       return 0;
+}
+
+void asix_remove(struct usb_device *udev __unused)
+{
+
+}
+
+void asix_close ( struct net_device *netdev ) {
+       
+       netdev++;
+}
+
+int asix_transmit ( struct net_device *netdev __unused,
+                         struct io_buffer *iobuf __unused)
+{
+       DBG("TX!!! Yea\n");
+       return 0;
+}
+
+void asix_poll ( struct net_device *netdev __unused) {
+
+}
+
+/* asix net device operations */
+static struct net_device_operations asix_operations = {
+       .open           = asix_open,
+       .close          = asix_close,
+       .transmit       = asix_transmit,
+       .poll           = asix_poll,
+};
+
+static int asix_sw_reset(struct asix *asix, uint8_t flags)
+{
+       int ret;
+
+        ret = asix_write_cmd(asix, AX_CMD_SW_RESET, flags, 0, 0, NULL);
+       if (ret < 0)
+               DBG("Failed to send software reset: %02x\n", ret);
+
+       return ret;
+}
+
+static int asix_write_rx_ctl(struct asix *asix, uint16_t mode)
+{
+       int ret;
+
+       DBG("asix_write_rx_ctl() - mode = 0x%04x\n", mode);
+       ret = asix_write_cmd(asix, AX_CMD_WRITE_RX_CTL, mode, 0, 0, NULL);
+       if (ret < 0)
+               DBG("Failed to write RX_CTL mode to 0x%04x: %02x\n",
+                      mode, ret);
+
+       return ret;
+}
+
+/* Get the PHY Identifier from the PHYSID1 & PHYSID2 MII registers */
+static u32 asix_get_phyid(struct asix *asix)
+{
+       int phy_reg;
+       u32 phy_id;
+
+       phy_reg = asix_mdio_read(asix->net, asix_get_phy_addr(asix), MII_PHYSID1);
+       if (phy_reg < 0)
+               return 0;
+
+       phy_id = (phy_reg & 0xffff) << 16;
+
+       phy_reg = asix_mdio_read(asix->net, asix_get_phy_addr(asix), MII_PHYSID2);
+       if (phy_reg < 0)
+               return 0;
+
+       phy_id |= (phy_reg & 0xffff);
+
+       return phy_id;
+}
+
+static int marvell_phy_init(struct asix *asix)
+{
+       uint16_t reg;
+
+       DBG("marvell_phy_init()");
+
+       reg = asix_mdio_read(asix->net, asix_get_phy_addr(asix), MII_MARVELL_STATUS);
+       DBG("MII_MARVELL_STATUS = 0x%04x\n", reg);
+
+       asix_mdio_write(asix->net, asix_get_phy_addr(asix), MII_MARVELL_CTRL,
+                       MARVELL_CTRL_RXDELAY | MARVELL_CTRL_TXDELAY);
+
+       return 0;
+}
+
+static int mii_nway_restart (struct asix *asix)
+{
+       int bmcr;
+       int r = -EINVAL;
+
+       /* if autoneg is off, it's an error */
+       bmcr = asix_mdio_read(asix->net, 0, MII_BMCR);
+
+       if (bmcr & BMCR_ANENABLE) {
+               bmcr |= BMCR_ANRESTART;
+               asix_mdio_write(asix->net, 0, MII_BMCR, bmcr);
+               r = 0;
+       }
+
+       return r;
+}
+
+int asix_probe(struct usb_device *udev,
+                       const struct usb_device_id *id __unused)
+{
+       struct net_device *netdev;
+       struct asix *asix;
+       unsigned int i;
+       uint8_t buf[ETH_ALEN];
+       uint16_t eeprom;
+       uint8_t status;
+       int gpio0 = 0;
+       uint32_t phyid;
+       int ret;
+
+       netdev = alloc_etherdev(sizeof(*asix));
+       netdev_init(netdev, &asix_operations);
+
+       if (!netdev) {
+               DBG("can't allocate %s\n\n", "device");
+               goto out;
+       }
+
+       asix = netdev_priv(netdev);
+       INIT_LIST_HEAD(&asix->tx_queue);
+       INIT_LIST_HEAD(&asix->rx_done_queue);
+       INIT_LIST_HEAD(&asix->rx_queue);
+
+       asix->udev = udev;
+       asix->net = netdev;
+       netdev->dev = &udev->dev;
+
+       for(i = 0;i < udev->num_endpoints; i++) {
+               if (usb_ep_xfertype(udev->endpoints[i]) == USB_ENDPOINT_XFER_BULK &&
+                               usb_ep_dir(udev->endpoints[i]) == USB_DIR_IN)
+                       asix->in = udev->endpoints[i];
+
+               if (usb_ep_xfertype(udev->endpoints[i]) == USB_ENDPOINT_XFER_BULK &&
+                               usb_ep_dir(udev->endpoints[i]) == USB_DIR_OUT)
+                       asix->out = udev->endpoints[i];
+       }
+       asix->maxpacket = le16_to_cpu(asix->in->desc.wMaxPacketSize);
+
+       asix_read_cmd(asix, AX_CMD_READ_GPIOS, 0, 0, 1, &status);
+       DBG("GPIO Status: 0x%04x\n", status);
+
+       asix_write_cmd(asix, AX_CMD_WRITE_ENABLE, 0, 0, 0, NULL);
+       asix_read_cmd(asix, AX_CMD_READ_EEPROM, 0x0017, 0, 2, &eeprom);
+       asix_write_cmd(asix, AX_CMD_WRITE_DISABLE, 0, 0, 0, NULL);
+
+       DBG("EEPROM index 0x17 is 0x%04x\n", eeprom);
+
+       if (eeprom == cpu_to_le16(0xffff)) {
+               asix->phy = PHY_MODE_MARVELL;
+               gpio0 = 1;
+       } else {
+               asix->phy = le16_to_cpu(eeprom) & 7;
+               gpio0 = (le16_to_cpu(eeprom) & 0x80) ? 0 : 1;
+       }
+       
+       asix_write_gpio(asix, AX_GPIO_RSE | AX_GPIO_GPO_1 | AX_GPIO_GPO1EN, 40);
+       if ((le16_to_cpu(eeprom) >> 8) != 1) {
+               asix_write_gpio(asix, 0x003c, 30);
+               asix_write_gpio(asix, 0x001c, 300);
+               asix_write_gpio(asix, 0x003c, 30);
+       } else {
+               DBG("gpio phymode == 1 path");
+               asix_write_gpio(asix, AX_GPIO_GPO1EN, 30);
+               asix_write_gpio(asix, AX_GPIO_GPO1EN | AX_GPIO_GPO_1, 30);
+       }
+
+       asix_sw_reset(asix, 0);
+       mdelay(150);
+
+       asix_sw_reset(asix, AX_SWRESET_PRL | AX_SWRESET_IPPD);
+       mdelay(150);
+
+       asix_write_rx_ctl(asix, 0);
+
+       /* Get the MAC address */
+       if ((ret = asix_read_cmd(asix, AX_CMD_READ_NODE_ID,
+                               0, 0, ETH_ALEN, buf)) < 0) {
+               DBG("Failed to read MAC address: %d\n", ret);
+               goto out;
+       }
+       memcpy(netdev->ll_addr, buf, ETH_ALEN);
+       
+       phyid = asix_get_phyid(asix);
+       DBG("PHYID=0x%08lx\n", phyid);
+
+       if (asix->phy == PHY_MODE_MARVELL) {
+               marvell_phy_init(asix);
+               mdelay(60);
+       }
+
+       asix_mdio_write(asix->net, asix_get_phy_addr(asix), MII_BMCR,
+                       BMCR_RESET | BMCR_ANENABLE);
+       asix_mdio_write(asix->net, asix_get_phy_addr(asix), MII_ADVERTISE,
+                       ADVERTISE_ALL | ADVERTISE_CSMA);
+
+       mii_nway_restart(asix);
+
+       if ((ret = asix_write_medium_mode(asix, AX88178_MEDIUM_DEFAULT)) < 0)
+               goto out;
+
+       if ((ret = asix_write_rx_ctl(asix, AX_DEFAULT_RX_CTL)) < 0)
+               goto out;
+       
+       /* Register network device */
+       if ((ret = register_netdev(netdev)) != 0) {
+               return -1;
+       }
+
+       netdev_link_up(netdev);
+       return 0;
+
+out:
+       return ret;
+}
+
+static struct usb_device_id asix_ids[] = {
+//     {"ASIX AX88178\n",      ,0x0b95, 0x1780},
+//     {"Linksys USB1000"      ,0x1737, 0x0039},
+//     {"IO-DATA ETG-US2"      ,0x04bb, 0x0930},
+       {"Belkin F5D5055"       ,0x050d, 0x5055},
+};
+
+struct usb_driver asix_usb_driver __usb_driver = {
+       .ids = asix_ids,
+       .id_count = (sizeof(asix_ids) / sizeof(asix_ids[0])),
+       .probe = asix_probe,
+       .remove = asix_remove,
+};
+
diff --git a/src/drivers/net/usb/asix.h b/src/drivers/net/usb/asix.h
new file mode 100644 (file)
index 0000000..8c27ee8
--- /dev/null
@@ -0,0 +1,147 @@
+#ifndef _GPXE_ASIX_H
+#define _GPXE_ASIX_H
+
+#define AX_CMD_SET_SW_MII              0x06
+#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_WRITE_EEPROM            0x0c
+#define AX_CMD_WRITE_ENABLE            0x0d
+#define AX_CMD_WRITE_DISABLE           0x0e
+#define AX_CMD_READ_RX_CTL             0x0f
+#define AX_CMD_WRITE_RX_CTL            0x10
+#define AX_CMD_READ_IPG012             0x11
+#define AX_CMD_WRITE_IPG0              0x12
+#define AX_CMD_WRITE_IPG1              0x13
+#define AX_CMD_READ_NODE_ID            0x13
+#define AX_CMD_WRITE_IPG2              0x14
+#define AX_CMD_WRITE_MULTI_FILTER      0x16
+#define AX88172_CMD_READ_NODE_ID       0x17
+#define AX_CMD_READ_PHY_ID             0x19
+#define AX_CMD_READ_MEDIUM_STATUS      0x1a
+#define AX_CMD_WRITE_MEDIUM_MODE       0x1b
+#define AX_CMD_READ_MONITOR_MODE       0x1c
+#define AX_CMD_WRITE_MONITOR_MODE      0x1d
+#define AX_CMD_READ_GPIOS              0x1e
+#define AX_CMD_WRITE_GPIOS             0x1f
+#define AX_CMD_SW_RESET                        0x20
+#define AX_CMD_SW_PHY_STATUS           0x21
+#define AX_CMD_SW_PHY_SELECT           0x22
+
+#define AX_MONITOR_MODE                        0x01
+#define AX_MONITOR_LINK                        0x02
+#define AX_MONITOR_MAGIC               0x04
+#define AX_MONITOR_HSFS                        0x10
+
+/* AX88172 Medium Status Register values */
+#define AX88172_MEDIUM_FD              0x02
+#define AX88172_MEDIUM_TX              0x04
+#define AX88172_MEDIUM_FC              0x10
+#define AX88172_MEDIUM_DEFAULT \
+               ( AX88172_MEDIUM_FD | AX88172_MEDIUM_TX | AX88172_MEDIUM_FC )
+
+#define AX_MCAST_FILTER_SIZE           8
+#define AX_MAX_MCAST                   64
+
+#define AX_SWRESET_CLEAR               0x00
+#define AX_SWRESET_RR                  0x01
+#define AX_SWRESET_RT                  0x02
+#define AX_SWRESET_PRTE                        0x04
+#define AX_SWRESET_PRL                 0x08
+#define AX_SWRESET_BZ                  0x10
+#define AX_SWRESET_IPRL                        0x20
+#define AX_SWRESET_IPPD                        0x40
+
+#define AX88772_IPG0_DEFAULT           0x15
+#define AX88772_IPG1_DEFAULT           0x0c
+#define AX88772_IPG2_DEFAULT           0x12
+
+/* AX88772 & AX88178 Medium Mode Register */
+#define AX_MEDIUM_PF           0x0080
+#define AX_MEDIUM_JFE          0x0040
+#define AX_MEDIUM_TFC          0x0020
+#define AX_MEDIUM_RFC          0x0010
+#define AX_MEDIUM_ENCK         0x0008
+#define AX_MEDIUM_AC           0x0004
+#define AX_MEDIUM_FD           0x0002
+#define AX_MEDIUM_GM           0x0001
+#define AX_MEDIUM_SM           0x1000
+#define AX_MEDIUM_SBP          0x0800
+#define AX_MEDIUM_PS           0x0200
+#define AX_MEDIUM_RE           0x0100
+
+#define AX88178_MEDIUM_DEFAULT \
+       (AX_MEDIUM_PS | AX_MEDIUM_FD | AX_MEDIUM_AC | \
+        AX_MEDIUM_RFC | AX_MEDIUM_TFC | AX_MEDIUM_JFE | \
+        AX_MEDIUM_RE )
+
+#define AX88772_MEDIUM_DEFAULT \
+       (AX_MEDIUM_FD | AX_MEDIUM_RFC | \
+        AX_MEDIUM_TFC | AX_MEDIUM_PS | \
+        AX_MEDIUM_AC | AX_MEDIUM_RE )
+
+/* AX88772 & AX88178 RX_CTL values */
+#define AX_RX_CTL_SO                   0x0080
+#define AX_RX_CTL_AP                   0x0020
+#define AX_RX_CTL_AM                   0x0010
+#define AX_RX_CTL_AB                   0x0008
+#define AX_RX_CTL_SEP                  0x0004
+#define AX_RX_CTL_AMALL                        0x0002
+#define AX_RX_CTL_PRO                  0x0001
+#define AX_RX_CTL_MFB_2048             0x0000
+#define AX_RX_CTL_MFB_4096             0x0100
+#define AX_RX_CTL_MFB_8192             0x0200
+#define AX_RX_CTL_MFB_16384            0x0300
+
+#define AX_DEFAULT_RX_CTL      \
+       (AX_RX_CTL_SO | AX_RX_CTL_AB )
+
+/* GPIO 0 .. 2 toggles */
+#define AX_GPIO_GPO0EN         0x01    /* GPIO0 Output enable */
+#define AX_GPIO_GPO_0          0x02    /* GPIO0 Output value */
+#define AX_GPIO_GPO1EN         0x04    /* GPIO1 Output enable */
+#define AX_GPIO_GPO_1          0x08    /* GPIO1 Output value */
+#define AX_GPIO_GPO2EN         0x10    /* GPIO2 Output enable */
+#define AX_GPIO_GPO_2          0x20    /* GPIO2 Output value */
+#define AX_GPIO_RESERVED       0x40    /* Reserved */
+#define AX_GPIO_RSE            0x80    /* Reload serial EEPROM */
+
+#define AX_EEPROM_MAGIC                0xdeadbeef
+#define AX88172_EEPROM_LEN     0x40
+#define AX88772_EEPROM_LEN     0xff
+
+#define PHY_MODE_MARVELL       0x0000
+#define MII_MARVELL_LED_CTRL   0x0018
+#define MII_MARVELL_STATUS     0x001b
+#define MII_MARVELL_CTRL       0x0014
+
+#define MARVELL_LED_MANUAL     0x0019
+
+#define MARVELL_STATUS_HWCFG   0x0004
+
+#define MARVELL_CTRL_TXDELAY   0x0002
+#define MARVELL_CTRL_RXDELAY   0x0080
+
+struct asix {
+       struct usb_device       *udev;
+       struct usb_interface    *intf;
+       struct net_device       *net;
+       
+       struct usb_host_endpoint *in;
+       struct usb_host_endpoint *out;
+
+       unsigned                flags;
+       unsigned                features;
+       uint8_t                 phy;
+       int                     chip;
+       int                     dev_index;
+       uint16_t                maxpacket;
+       uint8_t                 rx_urb_size;
+
+       struct list_head        tx_queue;
+       struct list_head        rx_queue;
+       struct list_head        rx_done_queue;
+};
+
+#endif
index 84e69f1..eed79c5 100644 (file)
@@ -548,11 +548,6 @@ out:
        return res;
 }
 
-int belklin_probe(struct usb_device *udev) {
-       return pegasus_probe(udev, pegasus_ids + 22);
-}
-
-
 struct usb_driver pegasus_usb_driver  __usb_driver = {
        .ids = pegasus_ids,
        .id_count = (sizeof(pegasus_ids) / sizeof(pegasus_ids[0])),
index 9d841a0..836cf03 100644 (file)
 #define ERRFILE_mtnic               ( ERRFILE_DRIVER | 0x004a0000 )
 #define ERRFILE_dm9601              ( ERRFILE_DRIVER | 0x004b0000 )
 #define ERRFILE_pegasus                     ( ERRFILE_DRIVER | 0x004c0000 )
+#define ERRFILE_asix                ( ERRFILE_DRIVER | 0x004d0000 )
 
 #define ERRFILE_scsi                ( ERRFILE_DRIVER | 0x00700000 )
 #define ERRFILE_arbel               ( ERRFILE_DRIVER | 0x00710000 )