net: dc2114x: Reorganize driver
authorMarek Vasut <marek.vasut+renesas@gmail.com>
Sun, 19 Apr 2020 02:00:49 +0000 (04:00 +0200)
committermarex <marex@desktop.lan>
Fri, 1 May 2020 10:35:21 +0000 (12:35 +0200)
Move the functions in the driver around to better fit future DM
conversion, drop function forward declarations. No functional
change.

Signed-off-by: Marek Vasut <marek.vasut+renesas@gmail.com>
Cc: Joe Hershberger <joe.hershberger@ni.com>
drivers/net/dc2114x.c

index 2bbe4e5d6021418b7cc10957727e0fffa89a4067..9de9634cd5177a604eb955d1c01dec3d4eb23c96 100644 (file)
 #define phys_to_bus(a) pci_phys_to_mem((pci_dev_t)dev->priv, a)
 #endif
 
+#define NUM_RX_DESC PKTBUFSRX
+#define NUM_TX_DESC 1                  /* Number of TX descriptors   */
+#define RX_BUFF_SZ  PKTSIZE_ALIGN
+
+#define TOUT_LOOP   1000000
+
+#define SETUP_FRAME_LEN 192
+
+struct de4x5_desc {
+       volatile s32 status;
+       u32 des1;
+       u32 buf;
+       u32 next;
+};
+
+/* RX and TX descriptor ring */
+static struct de4x5_desc rx_ring[NUM_RX_DESC] __aligned(32);
+static struct de4x5_desc tx_ring[NUM_TX_DESC] __aligned(32);
+static int rx_new;     /* RX descriptor ring pointer */
+static int tx_new;     /* TX descriptor ring pointer */
+
+static char rx_ring_size;
+static char tx_ring_size;
+
 static u32 dc2114x_inl(struct eth_device *dev, u32 addr)
 {
        return le32_to_cpu(*(volatile u32 *)(addr + dev->iobase));
@@ -126,191 +150,267 @@ static void stop_de4x5(struct eth_device *dev)
        dc2114x_outl(dev, omr, DE4X5_OMR);      /* Disable the TX and/or RX */
 }
 
-#define NUM_RX_DESC PKTBUFSRX
-#define NUM_TX_DESC 1                  /* Number of TX descriptors   */
-#define RX_BUFF_SZ  PKTSIZE_ALIGN
-
-#define TOUT_LOOP   1000000
+/* SROM Read and write routines. */
+static void sendto_srom(struct eth_device *dev, u_int command, u_long addr)
+{
+       dc2114x_outl(dev, command, addr);
+       udelay(1);
+}
 
-#define SETUP_FRAME_LEN 192
+static int getfrom_srom(struct eth_device *dev, u_long addr)
+{
+       u32 tmp = dc2114x_inl(dev, addr);
 
-struct de4x5_desc {
-       volatile s32 status;
-       u32 des1;
-       u32 buf;
-       u32 next;
-};
+       udelay(1);
+       return tmp;
+}
 
-/* RX and TX descriptor ring */
-static struct de4x5_desc rx_ring[NUM_RX_DESC] __aligned(32);
-static struct de4x5_desc tx_ring[NUM_TX_DESC] __aligned(32);
-static int rx_new;     /* RX descriptor ring pointer */
-static int tx_new;     /* TX descriptor ring pointer */
+/* Note: this routine returns extra data bits for size detection. */
+static int do_read_eeprom(struct eth_device *dev, u_long ioaddr, int location,
+                         int addr_len)
+{
+       int read_cmd = location | (SROM_READ_CMD << addr_len);
+       unsigned int retval = 0;
+       int i;
 
-static char rx_ring_size;
-static char tx_ring_size;
+       sendto_srom(dev, SROM_RD | SROM_SR, ioaddr);
+       sendto_srom(dev, SROM_RD | SROM_SR | DT_CS, ioaddr);
 
-static void  sendto_srom(struct eth_device *dev, u_int command, u_long addr);
-static int   getfrom_srom(struct eth_device *dev, u_long addr);
-static int   do_eeprom_cmd(struct eth_device *dev, u_long ioaddr,
-                          int cmd, int cmd_len);
-static int   do_read_eeprom(struct eth_device *dev, u_long ioaddr,
-                           int location, int addr_len);
-#ifdef UPDATE_SROM
-static int   write_srom(struct eth_device *dev, u_long ioaddr,
-                       int index, int new_value);
-static void  update_srom(struct eth_device *dev, bd_t *bis);
+#ifdef DEBUG_SROM
+       printf(" EEPROM read at %d ", location);
 #endif
-static int   read_srom(struct eth_device *dev, u_long ioaddr, int index);
-static void  read_hw_addr(struct eth_device *dev, bd_t *bis);
-static void  send_setup_frame(struct eth_device *dev, bd_t *bis);
 
-static int   dc21x4x_init(struct eth_device *dev, bd_t *bis);
-static int   dc21x4x_send(struct eth_device *dev, void *packet, int length);
-static int   dc21x4x_recv(struct eth_device *dev);
-static void  dc21x4x_halt(struct eth_device *dev);
+       /* Shift the read command bits out. */
+       for (i = 4 + addr_len; i >= 0; i--) {
+               short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
 
-static struct pci_device_id supported[] = {
-       { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP_FAST },
-       { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21142 },
-       { }
-};
+               sendto_srom(dev, SROM_RD | SROM_SR | DT_CS | dataval,
+                           ioaddr);
+               udelay(10);
+               sendto_srom(dev, SROM_RD | SROM_SR | DT_CS | dataval | DT_CLK,
+                           ioaddr);
+               udelay(10);
+#ifdef DEBUG_SROM2
+               printf("%X", getfrom_srom(dev, ioaddr) & 15);
+#endif
+               retval = (retval << 1) |
+                        !!(getfrom_srom(dev, ioaddr) & EE_DATA_READ);
+       }
 
-int dc21x4x_initialize(bd_t *bis)
-{
-       struct eth_device *dev;
-       unsigned short status;
-       unsigned char timer;
-       unsigned int iobase;
-       int card_number = 0;
-       pci_dev_t devbusfn;
-       unsigned int cfrv;
-       int idx = 0;
+       sendto_srom(dev, SROM_RD | SROM_SR | DT_CS, ioaddr);
 
-       while (1) {
-               devbusfn = pci_find_devices(supported, idx++);
-               if (devbusfn == -1)
-                       break;
+#ifdef DEBUG_SROM2
+       printf(" :%X:", getfrom_srom(dev, ioaddr) & 15);
+#endif
 
-               /* Get the chip configuration revision register. */
-               pci_read_config_dword(devbusfn, PCI_REVISION_ID, &cfrv);
+       for (i = 16; i > 0; i--) {
+               sendto_srom(dev, SROM_RD | SROM_SR | DT_CS | DT_CLK, ioaddr);
+               udelay(10);
+#ifdef DEBUG_SROM2
+               printf("%X", getfrom_srom(dev, ioaddr) & 15);
+#endif
+               retval = (retval << 1) |
+                        !!(getfrom_srom(dev, ioaddr) & EE_DATA_READ);
+               sendto_srom(dev, SROM_RD | SROM_SR | DT_CS, ioaddr);
+               udelay(10);
+       }
 
-               if ((cfrv & CFRV_RN) < DC2114x_BRK) {
-                       printf("Error: The chip is not DC21143.\n");
-                       continue;
-               }
+       /* Terminate the EEPROM access. */
+       sendto_srom(dev, SROM_RD | SROM_SR, ioaddr);
 
-               pci_read_config_word(devbusfn, PCI_COMMAND, &status);
-               status |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
-               pci_write_config_word(devbusfn, PCI_COMMAND, status);
+#ifdef DEBUG_SROM2
+       printf(" EEPROM value at %d is %5.5x.\n", location, retval);
+#endif
 
-               pci_read_config_word(devbusfn, PCI_COMMAND, &status);
-               if (!(status & PCI_COMMAND_MEMORY)) {
-                       printf("Error: Can not enable MEMORY access.\n");
-                       continue;
-               }
+       return retval;
+}
 
-               if (!(status & PCI_COMMAND_MASTER)) {
-                       printf("Error: Can not enable Bus Mastering.\n");
-                       continue;
-               }
+/*
+ * This executes a generic EEPROM command, typically a write or write
+ * enable. It returns the data output from the EEPROM, and thus may
+ * also be used for reads.
+ */
+static int do_eeprom_cmd(struct eth_device *dev, u_long ioaddr, int cmd,
+                        int cmd_len)
+{
+       unsigned int retval = 0;
 
-               /* Check the latency timer for values >= 0x60. */
-               pci_read_config_byte(devbusfn, PCI_LATENCY_TIMER, &timer);
+#ifdef DEBUG_SROM
+       printf(" EEPROM op 0x%x: ", cmd);
+#endif
 
-               if (timer < 0x60) {
-                       pci_write_config_byte(devbusfn, PCI_LATENCY_TIMER,
-                                             0x60);
-               }
+       sendto_srom(dev, SROM_RD | SROM_SR | DT_CS | DT_CLK, ioaddr);
 
-               /* read BAR for memory space access */
-               pci_read_config_dword(devbusfn, PCI_BASE_ADDRESS_1, &iobase);
-               iobase &= PCI_BASE_ADDRESS_MEM_MASK;
-               debug("dc21x4x: DEC 21142 PCI Device @0x%x\n", iobase);
+       /* Shift the command bits out. */
+       do {
+               short dataval = (cmd & BIT(cmd_len)) ? EE_WRITE_1 : EE_WRITE_0;
 
-               dev = (struct eth_device *)malloc(sizeof(*dev));
-               if (!dev) {
-                       printf("Can not allocalte memory of dc21x4x\n");
-                       break;
-               }
+               sendto_srom(dev, dataval, ioaddr);
+               udelay(10);
 
-               memset(dev, 0, sizeof(*dev));
+#ifdef DEBUG_SROM2
+               printf("%X", getfrom_srom(dev, ioaddr) & 15);
+#endif
 
-               sprintf(dev->name, "dc21x4x#%d", card_number);
+               sendto_srom(dev, dataval | DT_CLK, ioaddr);
+               udelay(10);
+               retval = (retval << 1) |
+                        !!(getfrom_srom(dev, ioaddr) & EE_DATA_READ);
+       } while (--cmd_len >= 0);
 
-               dev->iobase = pci_mem_to_phys(devbusfn, iobase);
-               dev->priv = (void *)devbusfn;
-               dev->init = dc21x4x_init;
-               dev->halt = dc21x4x_halt;
-               dev->send = dc21x4x_send;
-               dev->recv = dc21x4x_recv;
+       sendto_srom(dev, SROM_RD | SROM_SR | DT_CS, ioaddr);
 
-               /* Ensure we're not sleeping. */
-               pci_write_config_byte(devbusfn, PCI_CFDA_PSM, WAKEUP);
+       /* Terminate the EEPROM access. */
+       sendto_srom(dev, SROM_RD | SROM_SR, ioaddr);
 
-               udelay(10 * 1000);
+#ifdef DEBUG_SROM
+       printf(" EEPROM result is 0x%5.5x.\n", retval);
+#endif
 
-               read_hw_addr(dev, bis);
+       return retval;
+}
 
-               eth_register(dev);
+static int read_srom(struct eth_device *dev, u_long ioaddr, int index)
+{
+       int ee_addr_size;
 
-               card_number++;
-       }
+       ee_addr_size = (do_read_eeprom(dev, ioaddr, 0xff, 8) & BIT(18)) ? 8 : 6;
 
-       return card_number;
+       return do_eeprom_cmd(dev, ioaddr, 0xffff |
+                            (((SROM_READ_CMD << ee_addr_size) | index) << 16),
+                            3 + ee_addr_size + 16);
 }
 
-static int dc21x4x_init(struct eth_device *dev, bd_t *bis)
+#ifdef UPDATE_SROM
+static int write_srom(struct eth_device *dev, u_long ioaddr, int index,
+                     int new_value)
 {
+       unsigned short newval;
+       int ee_addr_size;
        int i;
-       int devbusfn = (int)dev->priv;
 
-       /* Ensure we're not sleeping. */
-       pci_write_config_byte(devbusfn, PCI_CFDA_PSM, WAKEUP);
+       ee_addr_size = (do_read_eeprom(dev, ioaddr, 0xff, 8) & BIT(18)) ? 8 : 6;
 
-       reset_de4x5(dev);
+       udelay(10 * 1000); /* test-only */
 
-       if (dc2114x_inl(dev, DE4X5_STS) & (STS_TS | STS_RS)) {
-               printf("Error: Cannot reset ethernet controller.\n");
-               return -1;
-       }
+#ifdef DEBUG_SROM
+       printf("ee_addr_size=%d.\n", ee_addr_size);
+       printf("Writing new entry 0x%4.4x to offset %d.\n", new_value, index);
+#endif
 
-       dc2114x_outl(dev, OMR_SDP | OMR_PS | OMR_PM, DE4X5_OMR);
+       /* Enable programming modes. */
+       do_eeprom_cmd(dev, ioaddr, 0x4f << (ee_addr_size - 4),
+                     3 + ee_addr_size);
 
-       for (i = 0; i < NUM_RX_DESC; i++) {
-               rx_ring[i].status = cpu_to_le32(R_OWN);
-               rx_ring[i].des1 = cpu_to_le32(RX_BUFF_SZ);
-               rx_ring[i].buf =
-                       cpu_to_le32(phys_to_bus((u32)net_rx_packets[i]));
-               rx_ring[i].next = 0;
+       /* Do the actual write. */
+       do_eeprom_cmd(dev, ioaddr, new_value |
+                     (((SROM_WRITE_CMD << ee_addr_size) | index) << 16),
+                     3 + ee_addr_size + 16);
+
+       /* Poll for write finished. */
+       sendto_srom(dev, SROM_RD | SROM_SR | DT_CS, ioaddr);
+       for (i = 0; i < 10000; i++) {   /* Typical 2000 ticks */
+               if (getfrom_srom(dev, ioaddr) & EE_DATA_READ)
+                       break;
        }
 
-       for (i = 0; i < NUM_TX_DESC; i++) {
-               tx_ring[i].status = 0;
-               tx_ring[i].des1 = 0;
-               tx_ring[i].buf = 0;
-               tx_ring[i].next = 0;
+#ifdef DEBUG_SROM
+       printf(" Write finished after %d ticks.\n", i);
+#endif
+
+       /* Disable programming. */
+       do_eeprom_cmd(dev, ioaddr, (0x40 << (ee_addr_size - 4)),
+                     3 + ee_addr_size);
+
+       /* And read the result. */
+       newval = do_eeprom_cmd(dev, ioaddr,
+                              (((SROM_READ_CMD << ee_addr_size) | index) << 16)
+                              | 0xffff, 3 + ee_addr_size + 16);
+#ifdef DEBUG_SROM
+       printf("  New value at offset %d is %4.4x.\n", index, newval);
+#endif
+
+       return 1;
+}
+
+static void update_srom(struct eth_device *dev, bd_t *bis)
+{
+       static unsigned short eeprom[0x40] = {
+               0x140b, 0x6610, 0x0000, 0x0000, /* 00 */
+               0x0000, 0x0000, 0x0000, 0x0000, /* 04 */
+               0x00a3, 0x0103, 0x0000, 0x0000, /* 08 */
+               0x0000, 0x1f00, 0x0000, 0x0000, /* 0c */
+               0x0108, 0x038d, 0x0000, 0x0000, /* 10 */
+               0xe078, 0x0001, 0x0040, 0x0018, /* 14 */
+               0x0000, 0x0000, 0x0000, 0x0000, /* 18 */
+               0x0000, 0x0000, 0x0000, 0x0000, /* 1c */
+               0x0000, 0x0000, 0x0000, 0x0000, /* 20 */
+               0x0000, 0x0000, 0x0000, 0x0000, /* 24 */
+               0x0000, 0x0000, 0x0000, 0x0000, /* 28 */
+               0x0000, 0x0000, 0x0000, 0x0000, /* 2c */
+               0x0000, 0x0000, 0x0000, 0x0000, /* 30 */
+               0x0000, 0x0000, 0x0000, 0x0000, /* 34 */
+               0x0000, 0x0000, 0x0000, 0x0000, /* 38 */
+               0x0000, 0x0000, 0x0000, 0x4e07, /* 3c */
+       };
+       uchar enetaddr[6];
+       int i;
+
+       /* Ethernet Addr... */
+       if (!eth_env_get_enetaddr("ethaddr", enetaddr))
+               return;
+
+       eeprom[0x0a] = (enetaddr[1] << 8) | enetaddr[0];
+       eeprom[0x0b] = (enetaddr[3] << 8) | enetaddr[2];
+       eeprom[0x0c] = (enetaddr[5] << 8) | enetaddr[4];
+
+       for (i = 0; i < 0x40; i++)
+               write_srom(dev, DE4X5_APROM, i, eeprom[i]);
+}
+#endif /* UPDATE_SROM */
+
+static void send_setup_frame(struct eth_device *dev, bd_t *bis)
+{
+       char setup_frame[SETUP_FRAME_LEN];
+       char *pa = &setup_frame[0];
+       int i;
+
+       memset(pa, 0xff, SETUP_FRAME_LEN);
+
+       for (i = 0; i < ETH_ALEN; i++) {
+               *(pa + (i & 1)) = dev->enetaddr[i];
+               if (i & 0x01)
+                       pa += 4;
        }
 
-       rx_ring_size = NUM_RX_DESC;
-       tx_ring_size = NUM_TX_DESC;
+       for (i = 0; tx_ring[tx_new].status & cpu_to_le32(T_OWN); i++) {
+               if (i < TOUT_LOOP)
+                       continue;
 
-       /* Write the end of list marker to the descriptor lists. */
-       rx_ring[rx_ring_size - 1].des1 |= cpu_to_le32(RD_RER);
-       tx_ring[tx_ring_size - 1].des1 |= cpu_to_le32(TD_TER);
+               printf("%s: tx error buffer not ready\n", dev->name);
+               return;
+       }
 
-       /* Tell the adapter where the TX/RX rings are located. */
-       dc2114x_outl(dev, phys_to_bus((u32)&rx_ring), DE4X5_RRBA);
-       dc2114x_outl(dev, phys_to_bus((u32)&tx_ring), DE4X5_TRBA);
+       tx_ring[tx_new].buf = cpu_to_le32(phys_to_bus((u32)&setup_frame[0]));
+       tx_ring[tx_new].des1 = cpu_to_le32(TD_TER | TD_SET | SETUP_FRAME_LEN);
+       tx_ring[tx_new].status = cpu_to_le32(T_OWN);
 
-       start_de4x5(dev);
+       dc2114x_outl(dev, POLL_DEMAND, DE4X5_TPD);
 
-       tx_new = 0;
-       rx_new = 0;
+       for (i = 0; tx_ring[tx_new].status & cpu_to_le32(T_OWN); i++) {
+               if (i < TOUT_LOOP)
+                       continue;
 
-       send_setup_frame(dev, bis);
+               printf("%s: tx buffer not ready\n", dev->name);
+               return;
+       }
 
-       return 0;
+       if (le32_to_cpu(tx_ring[tx_new].status) != 0x7FFFFFFF) {
+               printf("TX error status2 = 0x%08X\n",
+                      le32_to_cpu(tx_ring[tx_new].status));
+       }
+
+       tx_new = (tx_new + 1) % NUM_TX_DESC;
 }
 
 static int dc21x4x_send(struct eth_device *dev, void *packet, int length)
@@ -397,297 +497,175 @@ static int dc21x4x_recv(struct eth_device *dev)
        return length;
 }
 
-static void dc21x4x_halt(struct eth_device *dev)
+static int dc21x4x_init(struct eth_device *dev, bd_t *bis)
 {
+       int i;
        int devbusfn = (int)dev->priv;
 
-       stop_de4x5(dev);
-       dc2114x_outl(dev, 0, DE4X5_SICR);
+       /* Ensure we're not sleeping. */
+       pci_write_config_byte(devbusfn, PCI_CFDA_PSM, WAKEUP);
 
-       pci_write_config_byte(devbusfn, PCI_CFDA_PSM, SLEEP);
-}
+       reset_de4x5(dev);
 
-static void send_setup_frame(struct eth_device *dev, bd_t *bis)
-{
-       char setup_frame[SETUP_FRAME_LEN];
-       char *pa = &setup_frame[0];
-       int i;
+       if (dc2114x_inl(dev, DE4X5_STS) & (STS_TS | STS_RS)) {
+               printf("Error: Cannot reset ethernet controller.\n");
+               return -1;
+       }
 
-       memset(pa, 0xff, SETUP_FRAME_LEN);
+       dc2114x_outl(dev, OMR_SDP | OMR_PS | OMR_PM, DE4X5_OMR);
 
-       for (i = 0; i < ETH_ALEN; i++) {
-               *(pa + (i & 1)) = dev->enetaddr[i];
-               if (i & 0x01)
-                       pa += 4;
+       for (i = 0; i < NUM_RX_DESC; i++) {
+               rx_ring[i].status = cpu_to_le32(R_OWN);
+               rx_ring[i].des1 = cpu_to_le32(RX_BUFF_SZ);
+               rx_ring[i].buf =
+                       cpu_to_le32(phys_to_bus((u32)net_rx_packets[i]));
+               rx_ring[i].next = 0;
        }
 
-       for (i = 0; tx_ring[tx_new].status & cpu_to_le32(T_OWN); i++) {
-               if (i < TOUT_LOOP)
-                       continue;
-
-               printf("%s: tx error buffer not ready\n", dev->name);
-               return;
+       for (i = 0; i < NUM_TX_DESC; i++) {
+               tx_ring[i].status = 0;
+               tx_ring[i].des1 = 0;
+               tx_ring[i].buf = 0;
+               tx_ring[i].next = 0;
        }
 
-       tx_ring[tx_new].buf = cpu_to_le32(phys_to_bus((u32)&setup_frame[0]));
-       tx_ring[tx_new].des1 = cpu_to_le32(TD_TER | TD_SET | SETUP_FRAME_LEN);
-       tx_ring[tx_new].status = cpu_to_le32(T_OWN);
+       rx_ring_size = NUM_RX_DESC;
+       tx_ring_size = NUM_TX_DESC;
 
-       dc2114x_outl(dev, POLL_DEMAND, DE4X5_TPD);
+       /* Write the end of list marker to the descriptor lists. */
+       rx_ring[rx_ring_size - 1].des1 |= cpu_to_le32(RD_RER);
+       tx_ring[tx_ring_size - 1].des1 |= cpu_to_le32(TD_TER);
 
-       for (i = 0; tx_ring[tx_new].status & cpu_to_le32(T_OWN); i++) {
-               if (i < TOUT_LOOP)
-                       continue;
+       /* Tell the adapter where the TX/RX rings are located. */
+       dc2114x_outl(dev, phys_to_bus((u32)&rx_ring), DE4X5_RRBA);
+       dc2114x_outl(dev, phys_to_bus((u32)&tx_ring), DE4X5_TRBA);
 
-               printf("%s: tx buffer not ready\n", dev->name);
-               return;
-       }
+       start_de4x5(dev);
 
-       if (le32_to_cpu(tx_ring[tx_new].status) != 0x7FFFFFFF) {
-               printf("TX error status2 = 0x%08X\n",
-                      le32_to_cpu(tx_ring[tx_new].status));
-       }
+       tx_new = 0;
+       rx_new = 0;
 
-       tx_new = (tx_new + 1) % NUM_TX_DESC;
-}
+       send_setup_frame(dev, bis);
 
-/* SROM Read and write routines. */
-static void sendto_srom(struct eth_device *dev, u_int command, u_long addr)
-{
-       dc2114x_outl(dev, command, addr);
-       udelay(1);
+       return 0;
 }
 
-static int getfrom_srom(struct eth_device *dev, u_long addr)
+static void dc21x4x_halt(struct eth_device *dev)
 {
-       u32 tmp = dc2114x_inl(dev, addr);
+       int devbusfn = (int)dev->priv;
 
-       udelay(1);
-       return tmp;
+       stop_de4x5(dev);
+       dc2114x_outl(dev, 0, DE4X5_SICR);
+
+       pci_write_config_byte(devbusfn, PCI_CFDA_PSM, SLEEP);
 }
 
-/* Note: this routine returns extra data bits for size detection. */
-static int do_read_eeprom(struct eth_device *dev, u_long ioaddr, int location,
-                         int addr_len)
+static void read_hw_addr(struct eth_device *dev, bd_t *bis)
 {
-       int read_cmd = location | (SROM_READ_CMD << addr_len);
-       unsigned int retval = 0;
-       int i;
-
-       sendto_srom(dev, SROM_RD | SROM_SR, ioaddr);
-       sendto_srom(dev, SROM_RD | SROM_SR | DT_CS, ioaddr);
-
-#ifdef DEBUG_SROM
-       printf(" EEPROM read at %d ", location);
-#endif
-
-       /* Shift the read command bits out. */
-       for (i = 4 + addr_len; i >= 0; i--) {
-               short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
+       u_short tmp, *p = (u_short *)(&dev->enetaddr[0]);
+       int i, j = 0;
 
-               sendto_srom(dev, SROM_RD | SROM_SR | DT_CS | dataval,
-                           ioaddr);
-               udelay(10);
-               sendto_srom(dev, SROM_RD | SROM_SR | DT_CS | dataval | DT_CLK,
-                           ioaddr);
-               udelay(10);
-#ifdef DEBUG_SROM2
-               printf("%X", getfrom_srom(dev, ioaddr) & 15);
-#endif
-               retval = (retval << 1) |
-                        !!(getfrom_srom(dev, ioaddr) & EE_DATA_READ);
+       for (i = 0; i < (ETH_ALEN >> 1); i++) {
+               tmp = read_srom(dev, DE4X5_APROM, (SROM_HWADD >> 1) + i);
+               *p = le16_to_cpu(tmp);
+               j += *p++;
        }
 
-       sendto_srom(dev, SROM_RD | SROM_SR | DT_CS, ioaddr);
-
-#ifdef DEBUG_SROM2
-       printf(" :%X:", getfrom_srom(dev, ioaddr) & 15);
-#endif
-
-       for (i = 16; i > 0; i--) {
-               sendto_srom(dev, SROM_RD | SROM_SR | DT_CS | DT_CLK, ioaddr);
-               udelay(10);
-#ifdef DEBUG_SROM2
-               printf("%X", getfrom_srom(dev, ioaddr) & 15);
+       if (!j || j == 0x2fffd) {
+               memset(dev->enetaddr, 0, ETH_ALEN);
+               debug("Warning: can't read HW address from SROM.\n");
+#ifdef UPDATE_SROM
+               update_srom(dev, bis);
 #endif
-               retval = (retval << 1) |
-                        !!(getfrom_srom(dev, ioaddr) & EE_DATA_READ);
-               sendto_srom(dev, SROM_RD | SROM_SR | DT_CS, ioaddr);
-               udelay(10);
        }
-
-       /* Terminate the EEPROM access. */
-       sendto_srom(dev, SROM_RD | SROM_SR, ioaddr);
-
-#ifdef DEBUG_SROM2
-       printf(" EEPROM value at %d is %5.5x.\n", location, retval);
-#endif
-
-       return retval;
 }
 
-/*
- * This executes a generic EEPROM command, typically a write or write
- * enable. It returns the data output from the EEPROM, and thus may
- * also be used for reads.
- */
-static int do_eeprom_cmd(struct eth_device *dev, u_long ioaddr, int cmd,
-                        int cmd_len)
-{
-       unsigned int retval = 0;
-
-#ifdef DEBUG_SROM
-       printf(" EEPROM op 0x%x: ", cmd);
-#endif
-
-       sendto_srom(dev, SROM_RD | SROM_SR | DT_CS | DT_CLK, ioaddr);
-
-       /* Shift the command bits out. */
-       do {
-               short dataval = (cmd & BIT(cmd_len)) ? EE_WRITE_1 : EE_WRITE_0;
-
-               sendto_srom(dev, dataval, ioaddr);
-               udelay(10);
-
-#ifdef DEBUG_SROM2
-               printf("%X", getfrom_srom(dev, ioaddr) & 15);
-#endif
-
-               sendto_srom(dev, dataval | DT_CLK, ioaddr);
-               udelay(10);
-               retval = (retval << 1) |
-                        !!(getfrom_srom(dev, ioaddr) & EE_DATA_READ);
-       } while (--cmd_len >= 0);
-
-       sendto_srom(dev, SROM_RD | SROM_SR | DT_CS, ioaddr);
-
-       /* Terminate the EEPROM access. */
-       sendto_srom(dev, SROM_RD | SROM_SR, ioaddr);
-
-#ifdef DEBUG_SROM
-       printf(" EEPROM result is 0x%5.5x.\n", retval);
-#endif
-
-       return retval;
-}
+static struct pci_device_id supported[] = {
+       { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP_FAST },
+       { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21142 },
+       { }
+};
 
-static int read_srom(struct eth_device *dev, u_long ioaddr, int index)
+int dc21x4x_initialize(bd_t *bis)
 {
-       int ee_addr_size;
-
-       ee_addr_size = (do_read_eeprom(dev, ioaddr, 0xff, 8) & BIT(18)) ? 8 : 6;
+       struct eth_device *dev;
+       unsigned short status;
+       unsigned char timer;
+       unsigned int iobase;
+       int card_number = 0;
+       pci_dev_t devbusfn;
+       unsigned int cfrv;
+       int idx = 0;
 
-       return do_eeprom_cmd(dev, ioaddr, 0xffff |
-                            (((SROM_READ_CMD << ee_addr_size) | index) << 16),
-                            3 + ee_addr_size + 16);
-}
+       while (1) {
+               devbusfn = pci_find_devices(supported, idx++);
+               if (devbusfn == -1)
+                       break;
 
-#ifdef UPDATE_SROM
-static int write_srom(struct eth_device *dev, u_long ioaddr, int index,
-                     int new_value)
-{
-       unsigned short newval;
-       int ee_addr_size;
-       int i;
+               /* Get the chip configuration revision register. */
+               pci_read_config_dword(devbusfn, PCI_REVISION_ID, &cfrv);
 
-       ee_addr_size = (do_read_eeprom(dev, ioaddr, 0xff, 8) & BIT(18)) ? 8 : 6;
+               if ((cfrv & CFRV_RN) < DC2114x_BRK) {
+                       printf("Error: The chip is not DC21143.\n");
+                       continue;
+               }
 
-       udelay(10 * 1000); /* test-only */
+               pci_read_config_word(devbusfn, PCI_COMMAND, &status);
+               status |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
+               pci_write_config_word(devbusfn, PCI_COMMAND, status);
 
-#ifdef DEBUG_SROM
-       printf("ee_addr_size=%d.\n", ee_addr_size);
-       printf("Writing new entry 0x%4.4x to offset %d.\n", new_value, index);
-#endif
+               pci_read_config_word(devbusfn, PCI_COMMAND, &status);
+               if (!(status & PCI_COMMAND_MEMORY)) {
+                       printf("Error: Can not enable MEMORY access.\n");
+                       continue;
+               }
 
-       /* Enable programming modes. */
-       do_eeprom_cmd(dev, ioaddr, 0x4f << (ee_addr_size - 4),
-                     3 + ee_addr_size);
+               if (!(status & PCI_COMMAND_MASTER)) {
+                       printf("Error: Can not enable Bus Mastering.\n");
+                       continue;
+               }
 
-       /* Do the actual write. */
-       do_eeprom_cmd(dev, ioaddr, new_value |
-                     (((SROM_WRITE_CMD << ee_addr_size) | index) << 16),
-                     3 + ee_addr_size + 16);
+               /* Check the latency timer for values >= 0x60. */
+               pci_read_config_byte(devbusfn, PCI_LATENCY_TIMER, &timer);
 
-       /* Poll for write finished. */
-       sendto_srom(dev, SROM_RD | SROM_SR | DT_CS, ioaddr);
-       for (i = 0; i < 10000; i++) {   /* Typical 2000 ticks */
-               if (getfrom_srom(dev, ioaddr) & EE_DATA_READ)
-                       break;
-       }
+               if (timer < 0x60) {
+                       pci_write_config_byte(devbusfn, PCI_LATENCY_TIMER,
+                                             0x60);
+               }
 
-#ifdef DEBUG_SROM
-       printf(" Write finished after %d ticks.\n", i);
-#endif
+               /* read BAR for memory space access */
+               pci_read_config_dword(devbusfn, PCI_BASE_ADDRESS_1, &iobase);
+               iobase &= PCI_BASE_ADDRESS_MEM_MASK;
+               debug("dc21x4x: DEC 21142 PCI Device @0x%x\n", iobase);
 
-       /* Disable programming. */
-       do_eeprom_cmd(dev, ioaddr, (0x40 << (ee_addr_size - 4)),
-                     3 + ee_addr_size);
+               dev = (struct eth_device *)malloc(sizeof(*dev));
+               if (!dev) {
+                       printf("Can not allocalte memory of dc21x4x\n");
+                       break;
+               }
 
-       /* And read the result. */
-       newval = do_eeprom_cmd(dev, ioaddr,
-                              (((SROM_READ_CMD << ee_addr_size) | index) << 16)
-                              | 0xffff, 3 + ee_addr_size + 16);
-#ifdef DEBUG_SROM
-       printf("  New value at offset %d is %4.4x.\n", index, newval);
-#endif
+               memset(dev, 0, sizeof(*dev));
 
-       return 1;
-}
-#endif
+               sprintf(dev->name, "dc21x4x#%d", card_number);
 
-static void read_hw_addr(struct eth_device *dev, bd_t *bis)
-{
-       u_short tmp, *p = (u_short *)(&dev->enetaddr[0]);
-       int i, j = 0;
+               dev->iobase = pci_mem_to_phys(devbusfn, iobase);
+               dev->priv = (void *)devbusfn;
+               dev->init = dc21x4x_init;
+               dev->halt = dc21x4x_halt;
+               dev->send = dc21x4x_send;
+               dev->recv = dc21x4x_recv;
 
-       for (i = 0; i < (ETH_ALEN >> 1); i++) {
-               tmp = read_srom(dev, DE4X5_APROM, (SROM_HWADD >> 1) + i);
-               *p = le16_to_cpu(tmp);
-               j += *p++;
-       }
+               /* Ensure we're not sleeping. */
+               pci_write_config_byte(devbusfn, PCI_CFDA_PSM, WAKEUP);
 
-       if (!j || j == 0x2fffd) {
-               memset(dev->enetaddr, 0, ETH_ALEN);
-               debug("Warning: can't read HW address from SROM.\n");
-#ifdef UPDATE_SROM
-               update_srom(dev, bis);
-#endif
-       }
-}
+               udelay(10 * 1000);
 
-#ifdef UPDATE_SROM
-static void update_srom(struct eth_device *dev, bd_t *bis)
-{
-       static unsigned short eeprom[0x40] = {
-               0x140b, 0x6610, 0x0000, 0x0000, /* 00 */
-               0x0000, 0x0000, 0x0000, 0x0000, /* 04 */
-               0x00a3, 0x0103, 0x0000, 0x0000, /* 08 */
-               0x0000, 0x1f00, 0x0000, 0x0000, /* 0c */
-               0x0108, 0x038d, 0x0000, 0x0000, /* 10 */
-               0xe078, 0x0001, 0x0040, 0x0018, /* 14 */
-               0x0000, 0x0000, 0x0000, 0x0000, /* 18 */
-               0x0000, 0x0000, 0x0000, 0x0000, /* 1c */
-               0x0000, 0x0000, 0x0000, 0x0000, /* 20 */
-               0x0000, 0x0000, 0x0000, 0x0000, /* 24 */
-               0x0000, 0x0000, 0x0000, 0x0000, /* 28 */
-               0x0000, 0x0000, 0x0000, 0x0000, /* 2c */
-               0x0000, 0x0000, 0x0000, 0x0000, /* 30 */
-               0x0000, 0x0000, 0x0000, 0x0000, /* 34 */
-               0x0000, 0x0000, 0x0000, 0x0000, /* 38 */
-               0x0000, 0x0000, 0x0000, 0x4e07, /* 3c */
-       };
-       uchar enetaddr[6];
-       int i;
+               read_hw_addr(dev, bis);
 
-       /* Ethernet Addr... */
-       if (!eth_env_get_enetaddr("ethaddr", enetaddr))
-               return;
+               eth_register(dev);
 
-       eeprom[0x0a] = (enetaddr[1] << 8) | enetaddr[0];
-       eeprom[0x0b] = (enetaddr[3] << 8) | enetaddr[2];
-       eeprom[0x0c] = (enetaddr[5] << 8) | enetaddr[4];
+               card_number++;
+       }
 
-       for (i = 0; i < 0x40; i++)
-               write_srom(dev, DE4X5_APROM, i, eeprom[i]);
+       return card_number;
 }
-#endif /* UPDATE_SROM */