diff mbox series

[10/11] net: dc2114x: Reorganize driver

Message ID 20200419020957.495654-10-marek.vasut+renesas@gmail.com
State New
Headers show
Series [01/11] net: dc2114x: Clean up init code | expand

Commit Message

Marek Vasut April 19, 2020, 2:09 a.m. UTC
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 at gmail.com>
Cc: Joe Hershberger <joe.hershberger at ni.com>
---
 drivers/net/dc2114x.c | 736 ++++++++++++++++++++----------------------
 1 file changed, 357 insertions(+), 379 deletions(-)
diff mbox series

Patch

diff --git a/drivers/net/dc2114x.c b/drivers/net/dc2114x.c
index 2bbe4e5d60..9de9634cd5 100644
--- a/drivers/net/dc2114x.c
+++ b/drivers/net/dc2114x.c
@@ -79,6 +79,30 @@ 
 #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 */