Skip to contentSkip to conversation

DM9000 support for multiple interfaces

PATCH Superseded Andrew Ruder 5 participants 15 messages Oct 20, 2014 – Aug 11, 2015 Network drivers

v1 of 2 Superseded Latest is v2 →

lore
Share & tools
lore
#0 lore raw

cover DM9000 support for multiple interfaces

This is a rework of the DM9000 driver to support registering interfaces dynamically (i.e. determine how many ethernet chips we have at boot and register 0, 1, 2, or more). It was tested on a yet-to-be-submitted board which is based on the PXA270 + 0, 1, or 2 DM9000 chips.

To maintain backwards compatibility with older board files, we add a new initialize function taking the io address, data address, and availability of a SROM chip. The old initialize function is now a shim around this new initialize function but provides the parameters based on the old DM9000 preprocessor symbols.

I have compile-tested this on all the arm-based boards.

Cc Joe Hershberger <[email protected]>

Andrew Ruder (3):
dm9000: mark dump_regs() function as unused
dm9000: Add struct eth_device * to SROM functions
dm9000: rework dm9000 to support multiple devices

 board/trizepsiv/eeprom.c |   5 +-
 drivers/net/dm9000x.c    | 382 +++++++++++++++++++++++++++--------------------
 include/dm9000.h         |   8 +-
 include/netdev.h         |   1 +
 4 files changed, 224 insertions(+), 172 deletions(-)
Signature · 1 line
2.1.1
#1 lore raw

PATCH 1/3 dm9000: mark dump_regs() function as unused

dump_regs() is a handy function to keep around for bringing up a new dm9000-based board, but defining CONFIG_DM9000_DEBUG only adds the function - nowhere currently uses it. Rather than remove a potentially useful function, let's just tell gcc to not emit a warning when it is unused.

Cc Joe Hershberger <[email protected]>
---
 drivers/net/dm9000x.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/dm9000x.c +1 -1
index 4de9d41..50a36f3 100644
@@ -126,7 +126,7 @@ static void DM9000_iow(int reg, u8 value);
 
 #ifdef CONFIG_DM9000_DEBUG
 static void
-dump_regs(void)
+dump_regs(void) __attribute__ ((unused))
 {
 	DM9000_DBG("\n");
 	DM9000_DBG("NCR   (0x00): %02x\n", DM9000_ior(0));
Signature · 1 line
2.1.1
#2 lore raw

PATCH 1/3 dm9000: mark dump_regs() function as unused

Quoted 17 lines · Andrew Ruder

dump_regs() is a handy function to keep around for bringing up a new dm9000-based board, but defining CONFIG_DM9000_DEBUG only adds the function - nowhere currently uses it. Rather than remove a potentially useful function, let's just tell gcc to not emit a warning when it is unused.

Cc Joe Hershberger <[email protected]>
---
 drivers/net/dm9000x.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/dm9000x.c +0 -0
index 4de9d41..50a36f3 100644

drivers/net/dm9000x.c static void DM9000_iow(int reg, u8 value); · line 132

Quoted 8 lines
drivers/net/dm9000x.c +1 -1
@@ -126,7 +126,7 @@ static void DM9000_iow(int reg, u8 value);
 
 #ifdef CONFIG_DM9000_DEBUG
 static void
-dump_regs(void)
+dump_regs(void) __attribute__ ((unused))
 {
 	DM9000_DBG("\n");
 	DM9000_DBG("NCR   (0x00): %02x\n", DM9000_ior(0));

Please make sure we have <linux/compiler.h> and use __unused (or __maybe_unused?) here, thanks!

Signature · 8 lines
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20141020/df19f48d/attachment.pgp>
#3 lore raw

PATCH 2/3 dm9000: Add struct eth_device * to SROM functions

In reply to Andrew Ruder

Currently this argument is not used. To eventually support multiple DM9000's these public-facing functions will need a new argument - the ethernet device. Fix-up the one board using this part of the DM9000 API. Compile-tested only.

Cc Joe Hershberger <[email protected]>
Cc Stefano Babic <[email protected]>
---
 board/trizepsiv/eeprom.c |  5 +++--
 drivers/net/dm9000x.c    | 10 +++++-----
 include/dm9000.h         |  8 ++++----
 3 files changed, 12 insertions(+), 11 deletions(-)
board/trizepsiv/eeprom.c +3 -2
index 1318edc..d9045dd 100644
@@ -8,6 +8,7 @@
 #include <common.h>
 #include <command.h>
 #include <dm9000.h>
+#include <net.h>
 
 static int do_read_dm9000_eeprom ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) {
 	unsigned int i;
@@ -16,7 +17,7 @@ static int do_read_dm9000_eeprom ( cmd_tbl_t *cmdtp, int flag, int argc, char *
 	for (i=0; i < 0x40; i++) {
 		if (!(i % 0x10))
 			printf("\n%08x:", i);
-		dm9000_read_srom_word(i, data);
+		dm9000_read_srom_word(eth_get_dev_by_index(0), i, data);
 		printf(" %02x%02x", data[1], data[0]);
 	}
 	printf ("\n");
@@ -35,7 +36,7 @@ static int do_write_dm9000_eeprom ( cmd_tbl_t *cmdtp, int flag, int argc, char *
 		printf("Wrong offset : 0x%x\n",offset);
 		return cmd_usage(cmdtp);
 	}
-	dm9000_write_srom_word(offset, value);
+	dm9000_write_srom_word(eth_get_dev_by_index(0), offset, value);
 	return (0);
 }
 
drivers/net/dm9000x.c +5 -5
index 50a36f3..230f368 100644
@@ -534,9 +534,9 @@ static int dm9000_rx(struct eth_device *netdev)
 /*
   Read a word data from SROM
 */
-#if !defined(CONFIG_DM9000_NO_SROM)
-void dm9000_read_srom_word(int offset, u8 *to)
+void dm9000_read_srom_word(struct eth_device *dev, int offset, u8 *to)
 {
+	(void)dev;
 	DM9000_iow(DM9000_EPAR, offset);
 	DM9000_iow(DM9000_EPCR, 0x4);
 	udelay(8000);
@@ -545,8 +545,9 @@ void dm9000_read_srom_word(int offset, u8 *to)
 	to[1] = DM9000_ior(DM9000_EPDRH);
 }
 
-void dm9000_write_srom_word(int offset, u16 val)
+void dm9000_write_srom_word(struct eth_device *dev, int offset, u16 val)
 {
+	(void)dev;
 	DM9000_iow(DM9000_EPAR, offset);
 	DM9000_iow(DM9000_EPDRH, ((val >> 8) & 0xff));
 	DM9000_iow(DM9000_EPDRL, (val & 0xff));
@@ -554,14 +555,13 @@ void dm9000_write_srom_word(int offset, u16 val)
 	udelay(8000);
 	DM9000_iow(DM9000_EPCR, 0);
 }
-#endif
 
 static void dm9000_get_enetaddr(struct eth_device *dev)
 {
 #if !defined(CONFIG_DM9000_NO_SROM)
 	int i;
 	for (i = 0; i < 3; i++)
-		dm9000_read_srom_word(i, dev->enetaddr + (2 * i));
+		dm9000_read_srom_word(dev, i, dev->enetaddr + (2 * i));
 #endif
 }
 
include/dm9000.h +4 -4
index 42b04fa..825c32a 100644
@@ -8,10 +8,10 @@
 #ifndef __DM9000_H__
 #define __DM9000_H__
 
+struct eth_device;
+
 /******************  function prototypes **********************/
-#if !defined(CONFIG_DM9000_NO_SROM)
-void dm9000_write_srom_word(int offset, u16 val);
-void dm9000_read_srom_word(int offset, u8 *to);
-#endif
+void dm9000_write_srom_word(struct eth_device *dev, int offset, u16 val);
+void dm9000_read_srom_word(struct eth_device *dev, int offset, u8 *to);
 
 #endif /* __DM9000_H__ */
Signature · 1 line
2.1.1
#4 lore raw

PATCH 2/3 dm9000: Add struct eth_device * to SROM functions

Hi Andrew,

Quoted 9 lines · Andrew Ruder

Currently this argument is not used. To eventually support multiple DM9000's these public-facing functions will need a new argument - the ethernet device. Fix-up the one board using this part of the DM9000 API. Compile-tested only.

Cc Joe Hershberger <[email protected]>
Cc Stefano Babic <[email protected]>

---

Best regards,
Stefano Babic

Signature · 5 lines
=====================================================================
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: +49-8142-66989-53 Fax: +49-8142-66989-80 Email: sbabic at denx.de
=====================================================================
#5 lore raw

PATCH 2/3 dm9000: Add struct eth_device * to SROM functions

In reply to Andrew Ruder
Quoted 4 lines · Andrew Ruder

Currently this argument is not used. To eventually support multiple DM9000's these public-facing functions will need a new argument - the ethernet device. Fix-up the one board using this part of the DM9000 API. Compile-tested only.

[snip]

drivers/net/dm9000x.c static int dm9000_rx(struct eth_device *netdev) · line 539

Quoted 4 lines
drivers/net/dm9000x.c +2 -1
-void dm9000_read_srom_word(int offset, u8 *to)
+void dm9000_read_srom_word(struct eth_device *dev, int offset, u8 *to)
 {
+	(void)dev;

You shouldn't have to add this to avoid a warning I think. And frankly, if it does for some reason since 3/3 makes use of dev, I'm OK with a bisect adding a trivial warning like this, rather than do compiler games.

Signature · 8 lines
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20141020/af3ddb84/attachment.pgp>
#6 lore raw

PATCH 2/3 dm9000: Add struct eth_device * to SROM functions

Quoted 4 lines · Tom Rini

You shouldn't have to add this to avoid a warning I think. And frankly, if it does for some reason since 3/3 makes use of dev, I'm OK with a bisect adding a trivial warning like this, rather than do compiler games.

Fair enough, the more I look at it, the more it looks like I probably missed a warning on this patch + CONFIG_DM9000_NO_SROM (defined but not used) so it is still pretty easy to trigger a warning on this patch. I'll just remove the indicated parts in v2 of the series and let the warnings get cleaned up in 3/3 as you have suggested.

Will send a v2 of series in a bit after seeing if there is any feedback on the approaches used in 3/3.

- Andy

#7 lore raw

PATCH 3/3 dm9000: rework dm9000 to support multiple devices

In reply to Andrew Ruder

The DM9000 was hard-coded to only support one DM9000 device. This patch adds a new initialization function - dm9000_initialize_ex() - to support registering multiple (and possibly dynamic) numbers of dm9000 devices. This patch consists of:

* Change the board_info struct to a private struct under eth_device.
* Add io address/data address/srom availability information to this private struct.
* Replace all uses of DM9000_IO/DM9000_DATA with new members, ensure that the eth_device struct propagates down to all helper functions.
* Make dm9000_initialize() call dm9000_initialize_ex() with filled in information from the old preprocessor symbols (DM9000_IO, DM9000_DATA, etc.)

Overall the following parameters have been moved over to being a per-chip setting:

    DM9000_IO, DM9000_DATA, CONFIG_DM9000_NO_SROM

while the following is still a global setting affecting all chips:

    CONFIG_DM9000_BYTE_SWAPPED

And the following has been removed entirely:

CONFIG_DM9000_BASE (was only used in a single printf)

Cc Joe Hershberger <[email protected]>
---
 drivers/net/dm9000x.c | 378 ++++++++++++++++++++++++++++----------------------
 include/netdev.h      |   1 +
 2 files changed, 215 insertions(+), 164 deletions(-)
drivers/net/dm9000x.c +214 -164
index 230f368..2ed3121 100644
@@ -55,6 +55,7 @@ TODO: external MII is not functional, only internal at the moment.
 #include <net.h>
 #include <asm/io.h>
 #include <dm9000.h>
+#include <malloc.h>
 
 #include "dm9000x.h"
 
@@ -80,7 +81,9 @@ TODO: external MII is not functional, only internal at the moment.
 #endif
 
 /* Structure/enum declaration ------------------------------- */
-typedef struct board_info {
+struct dm9000_priv {
+	ulong data_base;
+	ulong io_base;
 	u32 runt_length_counter;	/* counter: RX length < 64byte */
 	u32 long_length_counter;	/* counter: RX length > 1514byte */
 	u32 reset_counter;	/* counter: RESET */
@@ -89,23 +92,22 @@ typedef struct board_info {
 	u16 tx_pkt_cnt;
 	u16 queue_start_addr;
 	u16 dbug_cnt;
+	u8 has_srom;
 	u8 phy_addr;
 	u8 device_wait_reset;	/* device state */
 	unsigned char srom[128];
-	void (*outblk)(volatile void *data_ptr, int count);
-	void (*inblk)(void *data_ptr, int count);
-	void (*rx_status)(u16 *RxStatus, u16 *RxLen);
-	struct eth_device netdev;
-} board_info_t;
-static board_info_t dm9000_info;
+	void (*outblk)(struct eth_device *dev, volatile void *data_ptr, int count);
+	void (*inblk)(struct eth_device *dev, void *data_ptr, int count);
+	void (*rx_status)(struct eth_device *dev, u16 *RxStatus, u16 *RxLen);
+};
 
 
 /* function declaration ------------------------------------- */
-static int dm9000_probe(void);
-static u16 dm9000_phy_read(int);
-static void dm9000_phy_write(int, u16);
-static u8 DM9000_ior(int);
-static void DM9000_iow(int reg, u8 value);
+static int dm9000_probe(struct eth_device *);
+static u16 dm9000_phy_read(struct eth_device *, int);
+static void dm9000_phy_write(struct eth_device *, int, u16);
+static u8 DM9000_ior(struct eth_device *, int);
+static void DM9000_iow(struct eth_device *, int reg, u8 value);
 
 /* DM9000 network board routine ---------------------------- */
 #ifndef CONFIG_DM9000_BYTE_SWAPPED
@@ -126,125 +128,138 @@ static void DM9000_iow(int reg, u8 value);
 
 #ifdef CONFIG_DM9000_DEBUG
 static void
-dump_regs(void) __attribute__ ((unused))
+dump_regs(struct eth_device *dev) __attribute__ ((unused))
 {
 	DM9000_DBG("\n");
-	DM9000_DBG("NCR   (0x00): %02x\n", DM9000_ior(0));
-	DM9000_DBG("NSR   (0x01): %02x\n", DM9000_ior(1));
-	DM9000_DBG("TCR   (0x02): %02x\n", DM9000_ior(2));
-	DM9000_DBG("TSRI  (0x03): %02x\n", DM9000_ior(3));
-	DM9000_DBG("TSRII (0x04): %02x\n", DM9000_ior(4));
-	DM9000_DBG("RCR   (0x05): %02x\n", DM9000_ior(5));
-	DM9000_DBG("RSR   (0x06): %02x\n", DM9000_ior(6));
-	DM9000_DBG("ISR   (0xFE): %02x\n", DM9000_ior(DM9000_ISR));
+	DM9000_DBG("NCR   (0x00): %02x\n", DM9000_ior(dev, 0));
+	DM9000_DBG("NSR   (0x01): %02x\n", DM9000_ior(dev, 1));
+	DM9000_DBG("TCR   (0x02): %02x\n", DM9000_ior(dev, 2));
+	DM9000_DBG("TSRI  (0x03): %02x\n", DM9000_ior(dev, 3));
+	DM9000_DBG("TSRII (0x04): %02x\n", DM9000_ior(dev, 4));
+	DM9000_DBG("RCR   (0x05): %02x\n", DM9000_ior(dev, 5));
+	DM9000_DBG("RSR   (0x06): %02x\n", DM9000_ior(dev, 6));
+	DM9000_DBG("ISR   (0xFE): %02x\n", DM9000_ior(dev, DM9000_ISR));
 	DM9000_DBG("\n");
 }
 #endif
 
-static void dm9000_outblk_8bit(volatile void *data_ptr, int count)
+static void dm9000_outblk_8bit(struct eth_device *dev, volatile void *data_ptr, int count)
 {
 	int i;
+	struct dm9000_priv *priv = dev->priv;
 	for (i = 0; i < count; i++)
-		DM9000_outb((((u8 *) data_ptr)[i] & 0xff), DM9000_DATA);
+		DM9000_outb((((u8 *) data_ptr)[i] & 0xff), priv->data_base);
 }
 
-static void dm9000_outblk_16bit(volatile void *data_ptr, int count)
+static void dm9000_outblk_16bit(struct eth_device *dev, volatile void *data_ptr, int count)
 {
 	int i;
 	u32 tmplen = (count + 1) / 2;
+	struct dm9000_priv *priv = dev->priv;
 
 	for (i = 0; i < tmplen; i++)
-		DM9000_outw(((u16 *) data_ptr)[i], DM9000_DATA);
+		DM9000_outw(((u16 *) data_ptr)[i], priv->data_base);
 }
-static void dm9000_outblk_32bit(volatile void *data_ptr, int count)
+static void dm9000_outblk_32bit(struct eth_device *dev, volatile void *data_ptr, int count)
 {
 	int i;
 	u32 tmplen = (count + 3) / 4;
+	struct dm9000_priv *priv = dev->priv;
 
 	for (i = 0; i < tmplen; i++)
-		DM9000_outl(((u32 *) data_ptr)[i], DM9000_DATA);
+		DM9000_outl(((u32 *) data_ptr)[i], priv->data_base);
 }
 
-static void dm9000_inblk_8bit(void *data_ptr, int count)
+static void dm9000_inblk_8bit(struct eth_device *dev, void *data_ptr, int count)
 {
 	int i;
+	struct dm9000_priv *priv = dev->priv;
+
 	for (i = 0; i < count; i++)
-		((u8 *) data_ptr)[i] = DM9000_inb(DM9000_DATA);
+		((u8 *) data_ptr)[i] = DM9000_inb(priv->data_base);
 }
 
-static void dm9000_inblk_16bit(void *data_ptr, int count)
+static void dm9000_inblk_16bit(struct eth_device *dev, void *data_ptr, int count)
 {
 	int i;
 	u32 tmplen = (count + 1) / 2;
+	struct dm9000_priv *priv = dev->priv;
 
 	for (i = 0; i < tmplen; i++)
-		((u16 *) data_ptr)[i] = DM9000_inw(DM9000_DATA);
+		((u16 *) data_ptr)[i] = DM9000_inw(priv->data_base);
 }
-static void dm9000_inblk_32bit(void *data_ptr, int count)
+static void dm9000_inblk_32bit(struct eth_device *dev, void *data_ptr, int count)
 {
 	int i;
 	u32 tmplen = (count + 3) / 4;
+	struct dm9000_priv *priv = dev->priv;
 
 	for (i = 0; i < tmplen; i++)
-		((u32 *) data_ptr)[i] = DM9000_inl(DM9000_DATA);
+		((u32 *) data_ptr)[i] = DM9000_inl(priv->data_base);
 }
 
-static void dm9000_rx_status_32bit(u16 *RxStatus, u16 *RxLen)
+static void dm9000_rx_status_32bit(struct eth_device *dev, u16 *RxStatus, u16 *RxLen)
 {
 	u32 tmpdata;
+	struct dm9000_priv *priv = dev->priv;
 
-	DM9000_outb(DM9000_MRCMD, DM9000_IO);
+	DM9000_outb(DM9000_MRCMD, priv->io_base);
 
-	tmpdata = DM9000_inl(DM9000_DATA);
+	tmpdata = DM9000_inl(priv->data_base);
 	*RxStatus = __le16_to_cpu(tmpdata);
 	*RxLen = __le16_to_cpu(tmpdata >> 16);
 }
 
-static void dm9000_rx_status_16bit(u16 *RxStatus, u16 *RxLen)
+static void dm9000_rx_status_16bit(struct eth_device *dev, u16 *RxStatus, u16 *RxLen)
 {
-	DM9000_outb(DM9000_MRCMD, DM9000_IO);
+	struct dm9000_priv *priv = dev->priv;
+
+	DM9000_outb(DM9000_MRCMD, priv->io_base);
 
-	*RxStatus = __le16_to_cpu(DM9000_inw(DM9000_DATA));
-	*RxLen = __le16_to_cpu(DM9000_inw(DM9000_DATA));
+	*RxStatus = __le16_to_cpu(DM9000_inw(priv->data_base));
+	*RxLen = __le16_to_cpu(DM9000_inw(priv->data_base));
 }
 
-static void dm9000_rx_status_8bit(u16 *RxStatus, u16 *RxLen)
+static void dm9000_rx_status_8bit(struct eth_device *dev, u16 *RxStatus, u16 *RxLen)
 {
-	DM9000_outb(DM9000_MRCMD, DM9000_IO);
+	struct dm9000_priv *priv = dev->priv;
+
+	DM9000_outb(DM9000_MRCMD, priv->io_base);
 
 	*RxStatus =
-	    __le16_to_cpu(DM9000_inb(DM9000_DATA) +
-			  (DM9000_inb(DM9000_DATA) << 8));
+	    __le16_to_cpu(DM9000_inb(priv->data_base) +
+			  (DM9000_inb(priv->data_base) << 8));
 	*RxLen =
-	    __le16_to_cpu(DM9000_inb(DM9000_DATA) +
-			  (DM9000_inb(DM9000_DATA) << 8));
+	    __le16_to_cpu(DM9000_inb(priv->data_base) +
+			  (DM9000_inb(priv->data_base) << 8));
 }
 
 /*
   Search DM9000 board, allocate space and register it
 */
 int
-dm9000_probe(void)
+dm9000_probe(struct eth_device *dev)
 {
+	struct dm9000_priv *priv = dev->priv;
 	u32 id_val;
-	id_val = DM9000_ior(DM9000_VIDL);
-	id_val |= DM9000_ior(DM9000_VIDH) << 8;
-	id_val |= DM9000_ior(DM9000_PIDL) << 16;
-	id_val |= DM9000_ior(DM9000_PIDH) << 24;
+	id_val = DM9000_ior(dev, DM9000_VIDL);
+	id_val |= DM9000_ior(dev, DM9000_VIDH) << 8;
+	id_val |= DM9000_ior(dev, DM9000_PIDL) << 16;
+	id_val |= DM9000_ior(dev, DM9000_PIDH) << 24;
 	if (id_val == DM9000_ID) {
-		printf("dm9000 i/o: 0x%x, id: 0x%x \n", CONFIG_DM9000_BASE,
+		printf("dm9000 i/o: 0x%lx, id: 0x%x \n", priv->io_base,
 		       id_val);
 		return 0;
 	} else {
-		printf("dm9000 not found at 0x%08x id: 0x%08x\n",
-		       CONFIG_DM9000_BASE, id_val);
+		printf("dm9000 not found at 0x%08lx id: 0x%08x\n",
+		       priv->io_base, id_val);
 		return -1;
 	}
 }
 
 /* General Purpose dm9000 reset routine */
 static void
-dm9000_reset(void)
+dm9000_reset(struct eth_device *dev)
 {
 	DM9000_DBG("resetting DM9000\n");
 
@@ -252,28 +267,28 @@ dm9000_reset(void)
 	   see DM9000 Application Notes V1.22 Jun 11, 2004 page 29 */
 
 	/* DEBUG: Make all GPIO0 outputs, all others inputs */
-	DM9000_iow(DM9000_GPCR, GPCR_GPIO0_OUT);
+	DM9000_iow(dev, DM9000_GPCR, GPCR_GPIO0_OUT);
 	/* Step 1: Power internal PHY by writing 0 to GPIO0 pin */
-	DM9000_iow(DM9000_GPR, 0);
+	DM9000_iow(dev, DM9000_GPR, 0);
 	/* Step 2: Software reset */
-	DM9000_iow(DM9000_NCR, (NCR_LBK_INT_MAC | NCR_RST));
+	DM9000_iow(dev, DM9000_NCR, (NCR_LBK_INT_MAC | NCR_RST));
 
 	do {
 		DM9000_DBG("resetting the DM9000, 1st reset\n");
 		udelay(25); /* Wait at least 20 us */
-	} while (DM9000_ior(DM9000_NCR) & 1);
+	} while (DM9000_ior(dev, DM9000_NCR) & 1);
 
-	DM9000_iow(DM9000_NCR, 0);
-	DM9000_iow(DM9000_NCR, (NCR_LBK_INT_MAC | NCR_RST)); /* Issue a second reset */
+	DM9000_iow(dev, DM9000_NCR, 0);
+	DM9000_iow(dev, DM9000_NCR, (NCR_LBK_INT_MAC | NCR_RST)); /* Issue a second reset */
 
 	do {
 		DM9000_DBG("resetting the DM9000, 2nd reset\n");
 		udelay(25); /* Wait at least 20 us */
-	} while (DM9000_ior(DM9000_NCR) & 1);
+	} while (DM9000_ior(dev, DM9000_NCR) & 1);
 
 	/* Check whether the ethernet controller is present */
-	if ((DM9000_ior(DM9000_PIDL) != 0x0) ||
-	    (DM9000_ior(DM9000_PIDH) != 0x90))
+	if ((DM9000_ior(dev, DM9000_PIDL) != 0x0) ||
+	    (DM9000_ior(dev, DM9000_PIDH) != 0x90))
 		printf("ERROR: resetting DM9000 -> not responding\n");
 }
 
@@ -283,63 +298,63 @@ static int dm9000_init(struct eth_device *dev, bd_t *bd)
 {
 	int i, oft, lnk;
 	u8 io_mode;
-	struct board_info *db = &dm9000_info;
+	struct dm9000_priv *priv = dev->priv;
 
 	DM9000_DBG("%s\n", __func__);
 
 	/* RESET device */
-	dm9000_reset();
+	dm9000_reset(dev);
 
-	if (dm9000_probe() < 0)
+	if (dm9000_probe(dev) < 0)
 		return -1;
 
 	/* Auto-detect 8/16/32 bit mode, ISR Bit 6+7 indicate bus width */
-	io_mode = DM9000_ior(DM9000_ISR) >> 6;
+	io_mode = DM9000_ior(dev, DM9000_ISR) >> 6;
 
 	switch (io_mode) {
 	case 0x0:  /* 16-bit mode */
 		printf("DM9000: running in 16 bit mode\n");
-		db->outblk    = dm9000_outblk_16bit;
-		db->inblk     = dm9000_inblk_16bit;
-		db->rx_status = dm9000_rx_status_16bit;
+		priv->outblk    = dm9000_outblk_16bit;
+		priv->inblk     = dm9000_inblk_16bit;
+		priv->rx_status = dm9000_rx_status_16bit;
 		break;
 	case 0x01:  /* 32-bit mode */
 		printf("DM9000: running in 32 bit mode\n");
-		db->outblk    = dm9000_outblk_32bit;
-		db->inblk     = dm9000_inblk_32bit;
-		db->rx_status = dm9000_rx_status_32bit;
+		priv->outblk    = dm9000_outblk_32bit;
+		priv->inblk     = dm9000_inblk_32bit;
+		priv->rx_status = dm9000_rx_status_32bit;
 		break;
 	case 0x02: /* 8 bit mode */
 		printf("DM9000: running in 8 bit mode\n");
-		db->outblk    = dm9000_outblk_8bit;
-		db->inblk     = dm9000_inblk_8bit;
-		db->rx_status = dm9000_rx_status_8bit;
+		priv->outblk    = dm9000_outblk_8bit;
+		priv->inblk     = dm9000_inblk_8bit;
+		priv->rx_status = dm9000_rx_status_8bit;
 		break;
 	default:
 		/* Assume 8 bit mode, will probably not work anyway */
 		printf("DM9000: Undefined IO-mode:0x%x\n", io_mode);
-		db->outblk    = dm9000_outblk_8bit;
-		db->inblk     = dm9000_inblk_8bit;
-		db->rx_status = dm9000_rx_status_8bit;
+		priv->outblk    = dm9000_outblk_8bit;
+		priv->inblk     = dm9000_inblk_8bit;
+		priv->rx_status = dm9000_rx_status_8bit;
 		break;
 	}
 
 	/* Program operating register, only internal phy supported */
-	DM9000_iow(DM9000_NCR, 0x0);
+	DM9000_iow(dev, DM9000_NCR, 0x0);
 	/* TX Polling clear */
-	DM9000_iow(DM9000_TCR, 0);
+	DM9000_iow(dev, DM9000_TCR, 0);
 	/* Less 3Kb, 200us */
-	DM9000_iow(DM9000_BPTR, BPTR_BPHW(3) | BPTR_JPT_600US);
+	DM9000_iow(dev, DM9000_BPTR, BPTR_BPHW(3) | BPTR_JPT_600US);
 	/* Flow Control : High/Low Water */
-	DM9000_iow(DM9000_FCTR, FCTR_HWOT(3) | FCTR_LWOT(8));
+	DM9000_iow(dev, DM9000_FCTR, FCTR_HWOT(3) | FCTR_LWOT(8));
 	/* SH FIXME: This looks strange! Flow Control */
-	DM9000_iow(DM9000_FCR, 0x0);
+	DM9000_iow(dev, DM9000_FCR, 0x0);
 	/* Special Mode */
-	DM9000_iow(DM9000_SMCR, 0);
+	DM9000_iow(dev, DM9000_SMCR, 0);
 	/* clear TX status */
-	DM9000_iow(DM9000_NSR, NSR_WAKEST | NSR_TX2END | NSR_TX1END);
+	DM9000_iow(dev, DM9000_NSR, NSR_WAKEST | NSR_TX2END | NSR_TX1END);
 	/* Clear interrupt status */
-	DM9000_iow(DM9000_ISR, ISR_ROOS | ISR_ROS | ISR_PTS | ISR_PRS);
+	DM9000_iow(dev, DM9000_ISR, ISR_ROOS | ISR_ROS | ISR_PTS | ISR_PRS);
 
 	printf("MAC: %pM\n", dev->enetaddr);
 	if (!is_valid_ether_addr(dev->enetaddr)) {
@@ -354,23 +369,23 @@ static int dm9000_init(struct eth_device *dev, bd_t *bd)
 
 	/* fill device MAC address registers */
 	for (i = 0, oft = DM9000_PAR; i < 6; i++, oft++)
-		DM9000_iow(oft, dev->enetaddr[i]);
+		DM9000_iow(dev, oft, dev->enetaddr[i]);
 	for (i = 0, oft = 0x16; i < 8; i++, oft++)
-		DM9000_iow(oft, 0xff);
+		DM9000_iow(dev, oft, 0xff);
 
 	/* read back mac, just to be sure */
 	for (i = 0, oft = 0x10; i < 6; i++, oft++)
-		DM9000_DBG("%02x:", DM9000_ior(oft));
+		DM9000_DBG("%02x:", DM9000_ior(dev, oft));
 	DM9000_DBG("\n");
 
 	/* Activate DM9000 */
 	/* RX enable */
-	DM9000_iow(DM9000_RCR, RCR_DIS_LONG | RCR_DIS_CRC | RCR_RXEN);
+	DM9000_iow(dev, DM9000_RCR, RCR_DIS_LONG | RCR_DIS_CRC | RCR_RXEN);
 	/* Enable TX/RX interrupt mask */
-	DM9000_iow(DM9000_IMR, IMR_PAR);
+	DM9000_iow(dev, DM9000_IMR, IMR_PAR);
 
 	i = 0;
-	while (!(dm9000_phy_read(1) & 0x20)) {	/* autonegation complete bit */
+	while (!(dm9000_phy_read(dev, 1) & 0x20)) {	/* autonegation complete bit */
 		udelay(1000);
 		i++;
 		if (i == 10000) {
@@ -380,7 +395,7 @@ static int dm9000_init(struct eth_device *dev, bd_t *bd)
 	}
 
 	/* see what we've got */
-	lnk = dm9000_phy_read(17) >> 12;
+	lnk = dm9000_phy_read(dev, 17) >> 12;
 	printf("operating at ");
 	switch (lnk) {
 	case 1:
@@ -407,38 +422,38 @@ static int dm9000_init(struct eth_device *dev, bd_t *bd)
   Hardware start transmission.
   Send a packet to media from the upper layer.
 */
-static int dm9000_send(struct eth_device *netdev, void *packet, int length)
+static int dm9000_send(struct eth_device *dev, void *packet, int length)
 {
 	int tmo;
-	struct board_info *db = &dm9000_info;
+	struct dm9000_priv *priv = dev->priv;
 
 	DM9000_DMP_PACKET(__func__ , packet, length);
 
-	DM9000_iow(DM9000_ISR, IMR_PTM); /* Clear Tx bit in ISR */
+	DM9000_iow(dev, DM9000_ISR, IMR_PTM); /* Clear Tx bit in ISR */
 
 	/* Move data to DM9000 TX RAM */
-	DM9000_outb(DM9000_MWCMD, DM9000_IO); /* Prepare for TX-data */
+	DM9000_outb(DM9000_MWCMD, priv->io_base); /* Prepare for TX-data */
 
 	/* push the data to the TX-fifo */
-	(db->outblk)(packet, length);
+	(priv->outblk)(dev, packet, length);
 
 	/* Set TX length to DM9000 */
-	DM9000_iow(DM9000_TXPLL, length & 0xff);
-	DM9000_iow(DM9000_TXPLH, (length >> 8) & 0xff);
+	DM9000_iow(dev, DM9000_TXPLL, length & 0xff);
+	DM9000_iow(dev, DM9000_TXPLH, (length >> 8) & 0xff);
 
 	/* Issue TX polling command */
-	DM9000_iow(DM9000_TCR, TCR_TXREQ); /* Cleared after TX complete */
+	DM9000_iow(dev, DM9000_TCR, TCR_TXREQ); /* Cleared after TX complete */
 
 	/* wait for end of transmission */
 	tmo = get_timer(0) + 5 * CONFIG_SYS_HZ;
-	while ( !(DM9000_ior(DM9000_NSR) & (NSR_TX1END | NSR_TX2END)) ||
-		!(DM9000_ior(DM9000_ISR) & IMR_PTM) ) {
+	while ( !(DM9000_ior(dev, DM9000_NSR) & (NSR_TX1END | NSR_TX2END)) ||
+		!(DM9000_ior(dev, DM9000_ISR) & IMR_PTM) ) {
 		if (get_timer(0) >= tmo) {
 			printf("transmission timeout\n");
 			break;
 		}
 	}
-	DM9000_iow(DM9000_ISR, IMR_PTM); /* Clear Tx bit in ISR */
+	DM9000_iow(dev, DM9000_ISR, IMR_PTM); /* Clear Tx bit in ISR */
 
 	DM9000_DBG("transmit done\n\n");
 	return 0;
@@ -448,45 +463,45 @@ static int dm9000_send(struct eth_device *netdev, void *packet, int length)
   Stop the interface.
   The interface is stopped when it is brought.
 */
-static void dm9000_halt(struct eth_device *netdev)
+static void dm9000_halt(struct eth_device *dev)
 {
 	DM9000_DBG("%s\n", __func__);
 
 	/* RESET devie */
-	dm9000_phy_write(0, 0x8000);	/* PHY RESET */
-	DM9000_iow(DM9000_GPR, 0x01);	/* Power-Down PHY */
-	DM9000_iow(DM9000_IMR, 0x80);	/* Disable all interrupt */
-	DM9000_iow(DM9000_RCR, 0x00);	/* Disable RX */
+	dm9000_phy_write(dev, 0, 0x8000);	/* PHY RESET */
+	DM9000_iow(dev, DM9000_GPR, 0x01);	/* Power-Down PHY */
+	DM9000_iow(dev, DM9000_IMR, 0x80);	/* Disable all interrupt */
+	DM9000_iow(dev, DM9000_RCR, 0x00);	/* Disable RX */
 }
 
 /*
   Received a packet and pass to upper layer
 */
-static int dm9000_rx(struct eth_device *netdev)
+static int dm9000_rx(struct eth_device *dev)
 {
 	u8 rxbyte, *rdptr = (u8 *) NetRxPackets[0];
 	u16 RxStatus, RxLen = 0;
-	struct board_info *db = &dm9000_info;
+	struct dm9000_priv *priv = dev->priv;
 
 	/* Check packet ready or not, we must check
 	   the ISR status first for DM9000A */
-	if (!(DM9000_ior(DM9000_ISR) & 0x01)) /* Rx-ISR bit must be set. */
+	if (!(DM9000_ior(dev, DM9000_ISR) & 0x01)) /* Rx-ISR bit must be set. */
 		return 0;
 
-	DM9000_iow(DM9000_ISR, 0x01); /* clear PR status latched in bit 0 */
+	DM9000_iow(dev, DM9000_ISR, 0x01); /* clear PR status latched in bit 0 */
 
 	/* There is _at least_ 1 package in the fifo, read them all */
 	for (;;) {
-		DM9000_ior(DM9000_MRCMDX);	/* Dummy read */
+		DM9000_ior(dev, DM9000_MRCMDX);	/* Dummy read */
 
 		/* Get most updated data,
 		   only look at bits 0:1, See application notes DM9000 */
-		rxbyte = DM9000_inb(DM9000_DATA) & 0x03;
+		rxbyte = DM9000_inb(priv->data_base) & 0x03;
 
 		/* Status check: this byte must be 0 or 1 */
 		if (rxbyte > DM9000_PKT_RDY) {
-			DM9000_iow(DM9000_RCR, 0x00);	/* Stop Device */
-			DM9000_iow(DM9000_ISR, 0x80);	/* Stop INT request */
+			DM9000_iow(dev, DM9000_RCR, 0x00);	/* Stop Device */
+			DM9000_iow(dev, DM9000_ISR, 0x80);	/* Stop INT request */
 			printf("DM9000 error: status check fail: 0x%x\n",
 				rxbyte);
 			return 0;
@@ -498,13 +513,13 @@ static int dm9000_rx(struct eth_device *netdev)
 		DM9000_DBG("receiving packet\n");
 
 		/* A packet ready now  & Get status/length */
-		(db->rx_status)(&RxStatus, &RxLen);
+		(priv->rx_status)(dev, &RxStatus, &RxLen);
 
 		DM9000_DBG("rx status: 0x%04x rx len: %d\n", RxStatus, RxLen);
 
 		/* Move data from DM9000 */
 		/* Read received packet from RX SRAM */
-		(db->inblk)(rdptr, RxLen);
+		(priv->inblk)(dev, rdptr, RxLen);
 
 		if ((RxStatus & 0xbf00) || (RxLen < 0x40)
 			|| (RxLen > DM9000_PKT_MAX)) {
@@ -519,7 +534,7 @@ static int dm9000_rx(struct eth_device *netdev)
 			}
 			if (RxLen > DM9000_PKT_MAX) {
 				printf("rx length too big\n");
-				dm9000_reset();
+				dm9000_reset(dev);
 			}
 		} else {
 			DM9000_DMP_PACKET(__func__ , rdptr, RxLen);
@@ -536,69 +551,72 @@ static int dm9000_rx(struct eth_device *netdev)
 */
 void dm9000_read_srom_word(struct eth_device *dev, int offset, u8 *to)
 {
-	(void)dev;
-	DM9000_iow(DM9000_EPAR, offset);
-	DM9000_iow(DM9000_EPCR, 0x4);
+	DM9000_iow(dev, DM9000_EPAR, offset);
+	DM9000_iow(dev, DM9000_EPCR, 0x4);
 	udelay(8000);
-	DM9000_iow(DM9000_EPCR, 0x0);
-	to[0] = DM9000_ior(DM9000_EPDRL);
-	to[1] = DM9000_ior(DM9000_EPDRH);
+	DM9000_iow(dev, DM9000_EPCR, 0x0);
+	to[0] = DM9000_ior(dev, DM9000_EPDRL);
+	to[1] = DM9000_ior(dev, DM9000_EPDRH);
 }
 
 void dm9000_write_srom_word(struct eth_device *dev, int offset, u16 val)
 {
-	(void)dev;
-	DM9000_iow(DM9000_EPAR, offset);
-	DM9000_iow(DM9000_EPDRH, ((val >> 8) & 0xff));
-	DM9000_iow(DM9000_EPDRL, (val & 0xff));
-	DM9000_iow(DM9000_EPCR, 0x12);
+	DM9000_iow(dev, DM9000_EPAR, offset);
+	DM9000_iow(dev, DM9000_EPDRH, ((val >> 8) & 0xff));
+	DM9000_iow(dev, DM9000_EPDRL, (val & 0xff));
+	DM9000_iow(dev, DM9000_EPCR, 0x12);
 	udelay(8000);
-	DM9000_iow(DM9000_EPCR, 0);
+	DM9000_iow(dev, DM9000_EPCR, 0);
 }
 
 static void dm9000_get_enetaddr(struct eth_device *dev)
 {
-#if !defined(CONFIG_DM9000_NO_SROM)
-	int i;
-	for (i = 0; i < 3; i++)
-		dm9000_read_srom_word(dev, i, dev->enetaddr + (2 * i));
-#endif
+	struct dm9000_priv *priv = dev->priv;
+	if (priv->has_srom) {
+		int i;
+		for (i = 0; i < 3; i++)
+			dm9000_read_srom_word(dev, i, dev->enetaddr + (2 * i));
+	}
 }
 
 /*
    Read a byte from I/O port
 */
 static u8
-DM9000_ior(int reg)
+DM9000_ior(struct eth_device *dev, int reg)
 {
-	DM9000_outb(reg, DM9000_IO);
-	return DM9000_inb(DM9000_DATA);
+	struct dm9000_priv *priv = dev->priv;
+
+	DM9000_outb(reg, priv->io_base);
+	return DM9000_inb(priv->data_base);
 }
 
 /*
    Write a byte to I/O port
 */
 static void
-DM9000_iow(int reg, u8 value)
+DM9000_iow(struct eth_device *dev, int reg, u8 value)
 {
-	DM9000_outb(reg, DM9000_IO);
-	DM9000_outb(value, DM9000_DATA);
+	struct dm9000_priv *priv = dev->priv;
+
+	DM9000_outb(reg, priv->io_base);
+	DM9000_outb(value, priv->data_base);
 }
 
 /*
    Read a word from phyxcer
 */
 static u16
-dm9000_phy_read(int reg)
+dm9000_phy_read(struct eth_device *dev, int reg)
 {
 	u16 val;
 
 	/* Fill the phyxcer register into REG_0C */
-	DM9000_iow(DM9000_EPAR, DM9000_PHY | reg);
-	DM9000_iow(DM9000_EPCR, 0xc);	/* Issue phyxcer read command */
+	DM9000_iow(dev, DM9000_EPAR, DM9000_PHY | reg);
+	DM9000_iow(dev, DM9000_EPCR, 0xc);	/* Issue phyxcer read command */
 	udelay(100);			/* Wait read complete */
-	DM9000_iow(DM9000_EPCR, 0x0);	/* Clear phyxcer read command */
-	val = (DM9000_ior(DM9000_EPDRH) << 8) | DM9000_ior(DM9000_EPDRL);
+	DM9000_iow(dev, DM9000_EPCR, 0x0);	/* Clear phyxcer read command */
+	val = (DM9000_ior(dev, DM9000_EPDRH) << 8) | DM9000_ior(dev, DM9000_EPDRL);
 
 	/* The read data keeps on REG_0D & REG_0E */
 	DM9000_DBG("dm9000_phy_read(0x%x): 0x%x\n", reg, val);
@@ -609,35 +627,67 @@ dm9000_phy_read(int reg)
    Write a word to phyxcer
 */
 static void
-dm9000_phy_write(int reg, u16 value)
+dm9000_phy_write(struct eth_device *dev, int reg, u16 value)
 {
-
 	/* Fill the phyxcer register into REG_0C */
-	DM9000_iow(DM9000_EPAR, DM9000_PHY | reg);
+	DM9000_iow(dev, DM9000_EPAR, DM9000_PHY | reg);
 
 	/* Fill the written data into REG_0D & REG_0E */
-	DM9000_iow(DM9000_EPDRL, (value & 0xff));
-	DM9000_iow(DM9000_EPDRH, ((value >> 8) & 0xff));
-	DM9000_iow(DM9000_EPCR, 0xa);	/* Issue phyxcer write command */
+	DM9000_iow(dev, DM9000_EPDRL, (value & 0xff));
+	DM9000_iow(dev, DM9000_EPDRH, ((value >> 8) & 0xff));
+	DM9000_iow(dev, DM9000_EPCR, 0xa);	/* Issue phyxcer write command */
 	udelay(500);			/* Wait write complete */
-	DM9000_iow(DM9000_EPCR, 0x0);	/* Clear phyxcer write command */
+	DM9000_iow(dev, DM9000_EPCR, 0x0);	/* Clear phyxcer write command */
 	DM9000_DBG("dm9000_phy_write(reg:0x%x, value:0x%x)\n", reg, value);
 }
 
-int dm9000_initialize(bd_t *bis)
+int dm9000_initialize_ex(u8 dev_num, ulong addr, ulong data, u8 has_srom)
 {
-	struct eth_device *dev = &(dm9000_info.netdev);
+	struct eth_device *dev;
+	struct dm9000_priv *priv;
+
+	priv = malloc(sizeof(*priv));
+	if (!priv)
+		return 1;
+	dev = malloc(sizeof(*dev));
+	if (!dev) {
+		free(priv);
+		return 2;
+	}
 
-	/* Load MAC address from EEPROM */
-	dm9000_get_enetaddr(dev);
+	memset(dev, 0, sizeof(*dev));
+	memset(priv, 0, sizeof(*priv));
 
+	priv->io_base = addr;
+	priv->data_base = data;
+	priv->has_srom = has_srom;
+	dev->priv = priv;
 	dev->init = dm9000_init;
 	dev->halt = dm9000_halt;
 	dev->send = dm9000_send;
 	dev->recv = dm9000_rx;
-	sprintf(dev->name, "dm9000");
+	if (dev_num > 0) {
+		sprintf(dev->name, "dm9000-%hu", dev_num);
+	} else {
+		sprintf(dev->name, "dm9000");
+	}
 
-	eth_register(dev);
+	/* Load MAC address from EEPROM */
+	dm9000_get_enetaddr(dev);
 
-	return 0;
+	return eth_register(dev);
+}
+
+int dm9000_initialize(bd_t *bis)
+{
+#if defined(DM9000_IO) && defined(DM9000_DATA)
+#ifdef CONFIG_DM9000_NO_SROM
+	u8 has_srom = 0;
+#else
+	u8 has_srom = 1;
+#endif
+	return dm9000_initialize_ex(0, DM9000_IO, DM9000_DATA, has_srom);
+#else
+	return 1;
+#endif
 }
include/netdev.h +1 -0
index a887bfb..5985516 100644
@@ -39,6 +39,7 @@ int davinci_emac_initialize(void);
 int dc21x4x_initialize(bd_t *bis);
 int designware_initialize(ulong base_addr, u32 interface);
 int dm9000_initialize(bd_t *bis);
+int dm9000_initialize_ex(u8 dev_num, ulong addr, ulong data, u8 has_srom);
 int dnet_eth_initialize(int id, void *regs, unsigned int phy_addr);
 int e1000_initialize(bd_t *bis);
 int eepro100_initialize(bd_t *bis);
Signature · 1 line
2.1.1
#8 lore raw

PATCH 3/3 dm9000: rework dm9000 to support multiple devices

This one triggered a whole bunch of check-patch issues that I need to clean-up mostly due to dm9000x.c not originally meeting all of the coding conventions. I'll send a V2 of this momentarily.

- Andy

#9 lore raw

PATCH v2 3/3 dm9000: rework dm9000 to support multiple devices

In reply to Andrew Ruder

The DM9000 was hard-coded to only support one DM9000 device. This patch adds a new initialization function - dm9000_initialize_ex() - to support registering multiple (and possibly dynamic) numbers of dm9000 devices. This patch consists of:

* Change the board_info struct to a private struct under eth_device.
* Add io address/data address/srom availability information to this private struct.
* Replace all uses of DM9000_IO/DM9000_DATA with new members, ensure that the eth_device struct propagates down to all helper functions.
* Make dm9000_initialize() call dm9000_initialize_ex() with filled in information from the old preprocessor symbols (DM9000_IO, DM9000_DATA, etc.)

Overall the following parameters have been moved over to being a per-chip setting:

    DM9000_IO, DM9000_DATA, CONFIG_DM9000_NO_SROM

while the following is still a global setting affecting all chips:

    CONFIG_DM9000_BYTE_SWAPPED

And the following has been removed entirely:

CONFIG_DM9000_BASE (was only used in a single printf)

Cc Joe Hershberger <[email protected]>

---

Maybe a useful exercise anyway, this patch is significantly more messy with all the whitespace cleanups. See the v1 for the changes without the noise. :)

 drivers/net/dm9000x.c | 468 +++++++++++++++++++++++++++++---------------------
 include/netdev.h      |   1 +
 2 files changed, 269 insertions(+), 200 deletions(-)
drivers/net/dm9000x.c +268 -200
index 230f368..89528a8 100644
@@ -29,7 +29,7 @@ v1.2   03/18/2003       Weilun Huang <[email protected]>:
 --------------------------------------
 
        12/15/2003       Initial port to u-boot by
-       			Sascha Hauer <[email protected]>
+			Sascha Hauer <[email protected]>
 
        06/03/2008	Remy Bohmer <[email protected]>
 			- Fixed the driver to work with DM9000A.
@@ -55,6 +55,7 @@ TODO: external MII is not functional, only internal at the moment.
 #include <net.h>
 #include <asm/io.h>
 #include <dm9000.h>
+#include <malloc.h>
 
 #include "dm9000x.h"
 
@@ -63,24 +64,26 @@ TODO: external MII is not functional, only internal at the moment.
 /* #define CONFIG_DM9000_DEBUG */
 
 #ifdef CONFIG_DM9000_DEBUG
-#define DM9000_DBG(fmt,args...) printf(fmt, ##args)
-#define DM9000_DMP_PACKET(func,packet,length)  \
+#define DM9000_DBG(fmt, args...) printf(fmt, ##args)
+#define DM9000_DMP_PACKET(func, packet, length)  \
 	do { \
-		int i; 							\
+		int i;							\
 		printf("%s: length: %d\n", func, length);		\
 		for (i = 0; i < length; i++) {				\
 			if (i % 8 == 0)					\
 				printf("\n%s: %02x: ", func, i);	\
-			printf("%02x ", ((unsigned char *) packet)[i]);	\
+			printf("%02x ", ((unsigned char *)packet)[i]);	\
 		} printf("\n");						\
-	} while(0)
+	} while (0)
 #else
-#define DM9000_DBG(fmt,args...)
-#define DM9000_DMP_PACKET(func,packet,length)
+#define DM9000_DBG(fmt, args...) do {} while (0)
+#define DM9000_DMP_PACKET(func, packet, length) do {} while (0)
 #endif
 
 /* Structure/enum declaration ------------------------------- */
-typedef struct board_info {
+struct dm9000_priv {
+	ulong data_base;
+	ulong io_base;
 	u32 runt_length_counter;	/* counter: RX length < 64byte */
 	u32 long_length_counter;	/* counter: RX length > 1514byte */
 	u32 reset_counter;	/* counter: RESET */
@@ -89,32 +92,31 @@ typedef struct board_info {
 	u16 tx_pkt_cnt;
 	u16 queue_start_addr;
 	u16 dbug_cnt;
+	u8 has_srom;
 	u8 phy_addr;
 	u8 device_wait_reset;	/* device state */
 	unsigned char srom[128];
-	void (*outblk)(volatile void *data_ptr, int count);
-	void (*inblk)(void *data_ptr, int count);
-	void (*rx_status)(u16 *RxStatus, u16 *RxLen);
-	struct eth_device netdev;
-} board_info_t;
-static board_info_t dm9000_info;
+	void (*outblk)(struct eth_device *dev, void *data_ptr, int count);
+	void (*inblk)(struct eth_device *dev, void *data_ptr, int count);
+	void (*rx_status)(struct eth_device *dev, u16 *rxstatus, u16 *rxlen);
+};
 
 
 /* function declaration ------------------------------------- */
-static int dm9000_probe(void);
-static u16 dm9000_phy_read(int);
-static void dm9000_phy_write(int, u16);
-static u8 DM9000_ior(int);
-static void DM9000_iow(int reg, u8 value);
+static int dm9000_probe(struct eth_device *);
+static u16 dm9000_phy_read(struct eth_device *, int);
+static void dm9000_phy_write(struct eth_device *, int, u16);
+static u8 DM9000_ior(struct eth_device *, int);
+static void DM9000_iow(struct eth_device *, int reg, u8 value);
 
 /* DM9000 network board routine ---------------------------- */
 #ifndef CONFIG_DM9000_BYTE_SWAPPED
-#define DM9000_outb(d,r) writeb(d, (volatile u8 *)(r))
-#define DM9000_outw(d,r) writew(d, (volatile u16 *)(r))
-#define DM9000_outl(d,r) writel(d, (volatile u32 *)(r))
-#define DM9000_inb(r) readb((volatile u8 *)(r))
-#define DM9000_inw(r) readw((volatile u16 *)(r))
-#define DM9000_inl(r) readl((volatile u32 *)(r))
+#define DM9000_outb(d, r) writeb(d, (u8 *)(r))
+#define DM9000_outw(d, r) writew(d, (u16 *)(r))
+#define DM9000_outl(d, r) writel(d, (u32 *)(r))
+#define DM9000_inb(r) readb((u8 *)(r))
+#define DM9000_inw(r) readw((u16 *)(r))
+#define DM9000_inl(r) readl((u32 *)(r))
 #else
 #define DM9000_outb(d, r) __raw_writeb(d, r)
 #define DM9000_outw(d, r) __raw_writew(d, r)
@@ -125,126 +127,149 @@ static void DM9000_iow(int reg, u8 value);
 #endif
 
 #ifdef CONFIG_DM9000_DEBUG
+static void dump_regs(struct eth_device *dev) __attribute__ ((unused));
 static void
-dump_regs(void) __attribute__ ((unused))
+dump_regs(struct eth_device *dev)
 {
 	DM9000_DBG("\n");
-	DM9000_DBG("NCR   (0x00): %02x\n", DM9000_ior(0));
-	DM9000_DBG("NSR   (0x01): %02x\n", DM9000_ior(1));
-	DM9000_DBG("TCR   (0x02): %02x\n", DM9000_ior(2));
-	DM9000_DBG("TSRI  (0x03): %02x\n", DM9000_ior(3));
-	DM9000_DBG("TSRII (0x04): %02x\n", DM9000_ior(4));
-	DM9000_DBG("RCR   (0x05): %02x\n", DM9000_ior(5));
-	DM9000_DBG("RSR   (0x06): %02x\n", DM9000_ior(6));
-	DM9000_DBG("ISR   (0xFE): %02x\n", DM9000_ior(DM9000_ISR));
+	DM9000_DBG("NCR   (0x00): %02x\n", DM9000_ior(dev, 0));
+	DM9000_DBG("NSR   (0x01): %02x\n", DM9000_ior(dev, 1));
+	DM9000_DBG("TCR   (0x02): %02x\n", DM9000_ior(dev, 2));
+	DM9000_DBG("TSRI  (0x03): %02x\n", DM9000_ior(dev, 3));
+	DM9000_DBG("TSRII (0x04): %02x\n", DM9000_ior(dev, 4));
+	DM9000_DBG("RCR   (0x05): %02x\n", DM9000_ior(dev, 5));
+	DM9000_DBG("RSR   (0x06): %02x\n", DM9000_ior(dev, 6));
+	DM9000_DBG("ISR   (0xFE): %02x\n", DM9000_ior(dev, DM9000_ISR));
 	DM9000_DBG("\n");
 }
 #endif
 
-static void dm9000_outblk_8bit(volatile void *data_ptr, int count)
+static void
+dm9000_outblk_8bit(struct eth_device *dev, void *data_ptr, int count)
 {
 	int i;
+	struct dm9000_priv *priv = dev->priv;
 	for (i = 0; i < count; i++)
-		DM9000_outb((((u8 *) data_ptr)[i] & 0xff), DM9000_DATA);
+		DM9000_outb((((u8 *)data_ptr)[i] & 0xff), priv->data_base);
 }
 
-static void dm9000_outblk_16bit(volatile void *data_ptr, int count)
+static void
+dm9000_outblk_16bit(struct eth_device *dev, void *data_ptr, int count)
 {
 	int i;
 	u32 tmplen = (count + 1) / 2;
+	struct dm9000_priv *priv = dev->priv;
 
 	for (i = 0; i < tmplen; i++)
-		DM9000_outw(((u16 *) data_ptr)[i], DM9000_DATA);
+		DM9000_outw(((u16 *)data_ptr)[i], priv->data_base);
 }
-static void dm9000_outblk_32bit(volatile void *data_ptr, int count)
+static void
+dm9000_outblk_32bit(struct eth_device *dev, void *data_ptr, int count)
 {
 	int i;
 	u32 tmplen = (count + 3) / 4;
+	struct dm9000_priv *priv = dev->priv;
 
 	for (i = 0; i < tmplen; i++)
-		DM9000_outl(((u32 *) data_ptr)[i], DM9000_DATA);
+		DM9000_outl(((u32 *)data_ptr)[i], priv->data_base);
 }
 
-static void dm9000_inblk_8bit(void *data_ptr, int count)
+static void
+dm9000_inblk_8bit(struct eth_device *dev, void *data_ptr, int count)
 {
 	int i;
+	struct dm9000_priv *priv = dev->priv;
+
 	for (i = 0; i < count; i++)
-		((u8 *) data_ptr)[i] = DM9000_inb(DM9000_DATA);
+		((u8 *)data_ptr)[i] = DM9000_inb(priv->data_base);
 }
 
-static void dm9000_inblk_16bit(void *data_ptr, int count)
+static void
+dm9000_inblk_16bit(struct eth_device *dev, void *data_ptr, int count)
 {
 	int i;
 	u32 tmplen = (count + 1) / 2;
+	struct dm9000_priv *priv = dev->priv;
 
 	for (i = 0; i < tmplen; i++)
-		((u16 *) data_ptr)[i] = DM9000_inw(DM9000_DATA);
+		((u16 *)data_ptr)[i] = DM9000_inw(priv->data_base);
 }
-static void dm9000_inblk_32bit(void *data_ptr, int count)
+static void
+dm9000_inblk_32bit(struct eth_device *dev, void *data_ptr, int count)
 {
 	int i;
 	u32 tmplen = (count + 3) / 4;
+	struct dm9000_priv *priv = dev->priv;
 
 	for (i = 0; i < tmplen; i++)
-		((u32 *) data_ptr)[i] = DM9000_inl(DM9000_DATA);
+		((u32 *)data_ptr)[i] = DM9000_inl(priv->data_base);
 }
 
-static void dm9000_rx_status_32bit(u16 *RxStatus, u16 *RxLen)
+static void
+dm9000_rx_status_32bit(struct eth_device *dev, u16 *rxstatus, u16 *rxlen)
 {
 	u32 tmpdata;
+	struct dm9000_priv *priv = dev->priv;
 
-	DM9000_outb(DM9000_MRCMD, DM9000_IO);
+	DM9000_outb(DM9000_MRCMD, priv->io_base);
 
-	tmpdata = DM9000_inl(DM9000_DATA);
-	*RxStatus = __le16_to_cpu(tmpdata);
-	*RxLen = __le16_to_cpu(tmpdata >> 16);
+	tmpdata = DM9000_inl(priv->data_base);
+	*rxstatus = __le16_to_cpu(tmpdata);
+	*rxlen = __le16_to_cpu(tmpdata >> 16);
 }
 
-static void dm9000_rx_status_16bit(u16 *RxStatus, u16 *RxLen)
+static void
+dm9000_rx_status_16bit(struct eth_device *dev, u16 *rxstatus, u16 *rxlen)
 {
-	DM9000_outb(DM9000_MRCMD, DM9000_IO);
+	struct dm9000_priv *priv = dev->priv;
+
+	DM9000_outb(DM9000_MRCMD, priv->io_base);
 
-	*RxStatus = __le16_to_cpu(DM9000_inw(DM9000_DATA));
-	*RxLen = __le16_to_cpu(DM9000_inw(DM9000_DATA));
+	*rxstatus = __le16_to_cpu(DM9000_inw(priv->data_base));
+	*rxlen = __le16_to_cpu(DM9000_inw(priv->data_base));
 }
 
-static void dm9000_rx_status_8bit(u16 *RxStatus, u16 *RxLen)
+static void
+dm9000_rx_status_8bit(struct eth_device *dev, u16 *rxstatus, u16 *rxlen)
 {
-	DM9000_outb(DM9000_MRCMD, DM9000_IO);
-
-	*RxStatus =
-	    __le16_to_cpu(DM9000_inb(DM9000_DATA) +
-			  (DM9000_inb(DM9000_DATA) << 8));
-	*RxLen =
-	    __le16_to_cpu(DM9000_inb(DM9000_DATA) +
-			  (DM9000_inb(DM9000_DATA) << 8));
+	struct dm9000_priv *priv = dev->priv;
+
+	DM9000_outb(DM9000_MRCMD, priv->io_base);
+
+	*rxstatus =
+	    __le16_to_cpu(DM9000_inb(priv->data_base) +
+			  (DM9000_inb(priv->data_base) << 8));
+	*rxlen =
+	    __le16_to_cpu(DM9000_inb(priv->data_base) +
+			  (DM9000_inb(priv->data_base) << 8));
 }
 
 /*
   Search DM9000 board, allocate space and register it
 */
 int
-dm9000_probe(void)
+dm9000_probe(struct eth_device *dev)
 {
+	struct dm9000_priv *priv = dev->priv;
 	u32 id_val;
-	id_val = DM9000_ior(DM9000_VIDL);
-	id_val |= DM9000_ior(DM9000_VIDH) << 8;
-	id_val |= DM9000_ior(DM9000_PIDL) << 16;
-	id_val |= DM9000_ior(DM9000_PIDH) << 24;
+	id_val = DM9000_ior(dev, DM9000_VIDL);
+	id_val |= DM9000_ior(dev, DM9000_VIDH) << 8;
+	id_val |= DM9000_ior(dev, DM9000_PIDL) << 16;
+	id_val |= DM9000_ior(dev, DM9000_PIDH) << 24;
 	if (id_val == DM9000_ID) {
-		printf("dm9000 i/o: 0x%x, id: 0x%x \n", CONFIG_DM9000_BASE,
+		printf("dm9000 i/o: 0x%lx, id: 0x%x\n", priv->io_base,
 		       id_val);
 		return 0;
 	} else {
-		printf("dm9000 not found at 0x%08x id: 0x%08x\n",
-		       CONFIG_DM9000_BASE, id_val);
+		printf("dm9000 not found at 0x%08lx id: 0x%08x\n",
+		       priv->io_base, id_val);
 		return -1;
 	}
 }
 
 /* General Purpose dm9000 reset routine */
 static void
-dm9000_reset(void)
+dm9000_reset(struct eth_device *dev)
 {
 	DM9000_DBG("resetting DM9000\n");
 
@@ -252,28 +277,29 @@ dm9000_reset(void)
 	   see DM9000 Application Notes V1.22 Jun 11, 2004 page 29 */
 
 	/* DEBUG: Make all GPIO0 outputs, all others inputs */
-	DM9000_iow(DM9000_GPCR, GPCR_GPIO0_OUT);
+	DM9000_iow(dev, DM9000_GPCR, GPCR_GPIO0_OUT);
 	/* Step 1: Power internal PHY by writing 0 to GPIO0 pin */
-	DM9000_iow(DM9000_GPR, 0);
+	DM9000_iow(dev, DM9000_GPR, 0);
 	/* Step 2: Software reset */
-	DM9000_iow(DM9000_NCR, (NCR_LBK_INT_MAC | NCR_RST));
+	DM9000_iow(dev, DM9000_NCR, (NCR_LBK_INT_MAC | NCR_RST));
 
 	do {
 		DM9000_DBG("resetting the DM9000, 1st reset\n");
 		udelay(25); /* Wait at least 20 us */
-	} while (DM9000_ior(DM9000_NCR) & 1);
+	} while (DM9000_ior(dev, DM9000_NCR) & 1);
 
-	DM9000_iow(DM9000_NCR, 0);
-	DM9000_iow(DM9000_NCR, (NCR_LBK_INT_MAC | NCR_RST)); /* Issue a second reset */
+	DM9000_iow(dev, DM9000_NCR, 0);
+	/* Issue a second reset */
+	DM9000_iow(dev, DM9000_NCR, (NCR_LBK_INT_MAC | NCR_RST));
 
 	do {
 		DM9000_DBG("resetting the DM9000, 2nd reset\n");
 		udelay(25); /* Wait at least 20 us */
-	} while (DM9000_ior(DM9000_NCR) & 1);
+	} while (DM9000_ior(dev, DM9000_NCR) & 1);
 
 	/* Check whether the ethernet controller is present */
-	if ((DM9000_ior(DM9000_PIDL) != 0x0) ||
-	    (DM9000_ior(DM9000_PIDH) != 0x90))
+	if ((DM9000_ior(dev, DM9000_PIDL) != 0x0) ||
+	    (DM9000_ior(dev, DM9000_PIDH) != 0x90))
 		printf("ERROR: resetting DM9000 -> not responding\n");
 }
 
@@ -283,63 +309,63 @@ static int dm9000_init(struct eth_device *dev, bd_t *bd)
 {
 	int i, oft, lnk;
 	u8 io_mode;
-	struct board_info *db = &dm9000_info;
+	struct dm9000_priv *priv = dev->priv;
 
 	DM9000_DBG("%s\n", __func__);
 
 	/* RESET device */
-	dm9000_reset();
+	dm9000_reset(dev);
 
-	if (dm9000_probe() < 0)
+	if (dm9000_probe(dev) < 0)
 		return -1;
 
 	/* Auto-detect 8/16/32 bit mode, ISR Bit 6+7 indicate bus width */
-	io_mode = DM9000_ior(DM9000_ISR) >> 6;
+	io_mode = DM9000_ior(dev, DM9000_ISR) >> 6;
 
 	switch (io_mode) {
 	case 0x0:  /* 16-bit mode */
 		printf("DM9000: running in 16 bit mode\n");
-		db->outblk    = dm9000_outblk_16bit;
-		db->inblk     = dm9000_inblk_16bit;
-		db->rx_status = dm9000_rx_status_16bit;
+		priv->outblk    = dm9000_outblk_16bit;
+		priv->inblk     = dm9000_inblk_16bit;
+		priv->rx_status = dm9000_rx_status_16bit;
 		break;
 	case 0x01:  /* 32-bit mode */
 		printf("DM9000: running in 32 bit mode\n");
-		db->outblk    = dm9000_outblk_32bit;
-		db->inblk     = dm9000_inblk_32bit;
-		db->rx_status = dm9000_rx_status_32bit;
+		priv->outblk    = dm9000_outblk_32bit;
+		priv->inblk     = dm9000_inblk_32bit;
+		priv->rx_status = dm9000_rx_status_32bit;
 		break;
 	case 0x02: /* 8 bit mode */
 		printf("DM9000: running in 8 bit mode\n");
-		db->outblk    = dm9000_outblk_8bit;
-		db->inblk     = dm9000_inblk_8bit;
-		db->rx_status = dm9000_rx_status_8bit;
+		priv->outblk    = dm9000_outblk_8bit;
+		priv->inblk     = dm9000_inblk_8bit;
+		priv->rx_status = dm9000_rx_status_8bit;
 		break;
 	default:
 		/* Assume 8 bit mode, will probably not work anyway */
 		printf("DM9000: Undefined IO-mode:0x%x\n", io_mode);
-		db->outblk    = dm9000_outblk_8bit;
-		db->inblk     = dm9000_inblk_8bit;
-		db->rx_status = dm9000_rx_status_8bit;
+		priv->outblk    = dm9000_outblk_8bit;
+		priv->inblk     = dm9000_inblk_8bit;
+		priv->rx_status = dm9000_rx_status_8bit;
 		break;
 	}
 
 	/* Program operating register, only internal phy supported */
-	DM9000_iow(DM9000_NCR, 0x0);
+	DM9000_iow(dev, DM9000_NCR, 0x0);
 	/* TX Polling clear */
-	DM9000_iow(DM9000_TCR, 0);
+	DM9000_iow(dev, DM9000_TCR, 0);
 	/* Less 3Kb, 200us */
-	DM9000_iow(DM9000_BPTR, BPTR_BPHW(3) | BPTR_JPT_600US);
+	DM9000_iow(dev, DM9000_BPTR, BPTR_BPHW(3) | BPTR_JPT_600US);
 	/* Flow Control : High/Low Water */
-	DM9000_iow(DM9000_FCTR, FCTR_HWOT(3) | FCTR_LWOT(8));
+	DM9000_iow(dev, DM9000_FCTR, FCTR_HWOT(3) | FCTR_LWOT(8));
 	/* SH FIXME: This looks strange! Flow Control */
-	DM9000_iow(DM9000_FCR, 0x0);
+	DM9000_iow(dev, DM9000_FCR, 0x0);
 	/* Special Mode */
-	DM9000_iow(DM9000_SMCR, 0);
+	DM9000_iow(dev, DM9000_SMCR, 0);
 	/* clear TX status */
-	DM9000_iow(DM9000_NSR, NSR_WAKEST | NSR_TX2END | NSR_TX1END);
+	DM9000_iow(dev, DM9000_NSR, NSR_WAKEST | NSR_TX2END | NSR_TX1END);
 	/* Clear interrupt status */
-	DM9000_iow(DM9000_ISR, ISR_ROOS | ISR_ROS | ISR_PTS | ISR_PRS);
+	DM9000_iow(dev, DM9000_ISR, ISR_ROOS | ISR_ROS | ISR_PTS | ISR_PRS);
 
 	printf("MAC: %pM\n", dev->enetaddr);
 	if (!is_valid_ether_addr(dev->enetaddr)) {
@@ -354,23 +380,24 @@ static int dm9000_init(struct eth_device *dev, bd_t *bd)
 
 	/* fill device MAC address registers */
 	for (i = 0, oft = DM9000_PAR; i < 6; i++, oft++)
-		DM9000_iow(oft, dev->enetaddr[i]);
+		DM9000_iow(dev, oft, dev->enetaddr[i]);
 	for (i = 0, oft = 0x16; i < 8; i++, oft++)
-		DM9000_iow(oft, 0xff);
+		DM9000_iow(dev, oft, 0xff);
 
 	/* read back mac, just to be sure */
 	for (i = 0, oft = 0x10; i < 6; i++, oft++)
-		DM9000_DBG("%02x:", DM9000_ior(oft));
+		DM9000_DBG("%02x:", DM9000_ior(dev, oft));
 	DM9000_DBG("\n");
 
 	/* Activate DM9000 */
 	/* RX enable */
-	DM9000_iow(DM9000_RCR, RCR_DIS_LONG | RCR_DIS_CRC | RCR_RXEN);
+	DM9000_iow(dev, DM9000_RCR, RCR_DIS_LONG | RCR_DIS_CRC | RCR_RXEN);
 	/* Enable TX/RX interrupt mask */
-	DM9000_iow(DM9000_IMR, IMR_PAR);
+	DM9000_iow(dev, DM9000_IMR, IMR_PAR);
 
 	i = 0;
-	while (!(dm9000_phy_read(1) & 0x20)) {	/* autonegation complete bit */
+	while (!(dm9000_phy_read(dev, 1) & 0x20)) {
+		/* autonegotiation complete bit */
 		udelay(1000);
 		i++;
 		if (i == 10000) {
@@ -380,7 +407,7 @@ static int dm9000_init(struct eth_device *dev, bd_t *bd)
 	}
 
 	/* see what we've got */
-	lnk = dm9000_phy_read(17) >> 12;
+	lnk = dm9000_phy_read(dev, 17) >> 12;
 	printf("operating at ");
 	switch (lnk) {
 	case 1:
@@ -407,38 +434,38 @@ static int dm9000_init(struct eth_device *dev, bd_t *bd)
   Hardware start transmission.
   Send a packet to media from the upper layer.
 */
-static int dm9000_send(struct eth_device *netdev, void *packet, int length)
+static int dm9000_send(struct eth_device *dev, void *packet, int length)
 {
 	int tmo;
-	struct board_info *db = &dm9000_info;
+	struct dm9000_priv *priv = dev->priv;
 
 	DM9000_DMP_PACKET(__func__ , packet, length);
 
-	DM9000_iow(DM9000_ISR, IMR_PTM); /* Clear Tx bit in ISR */
+	DM9000_iow(dev, DM9000_ISR, IMR_PTM); /* Clear Tx bit in ISR */
 
 	/* Move data to DM9000 TX RAM */
-	DM9000_outb(DM9000_MWCMD, DM9000_IO); /* Prepare for TX-data */
+	DM9000_outb(DM9000_MWCMD, priv->io_base); /* Prepare for TX-data */
 
 	/* push the data to the TX-fifo */
-	(db->outblk)(packet, length);
+	(priv->outblk)(dev, packet, length);
 
 	/* Set TX length to DM9000 */
-	DM9000_iow(DM9000_TXPLL, length & 0xff);
-	DM9000_iow(DM9000_TXPLH, (length >> 8) & 0xff);
+	DM9000_iow(dev, DM9000_TXPLL, length & 0xff);
+	DM9000_iow(dev, DM9000_TXPLH, (length >> 8) & 0xff);
 
 	/* Issue TX polling command */
-	DM9000_iow(DM9000_TCR, TCR_TXREQ); /* Cleared after TX complete */
+	DM9000_iow(dev, DM9000_TCR, TCR_TXREQ); /* Cleared after TX complete */
 
 	/* wait for end of transmission */
 	tmo = get_timer(0) + 5 * CONFIG_SYS_HZ;
-	while ( !(DM9000_ior(DM9000_NSR) & (NSR_TX1END | NSR_TX2END)) ||
-		!(DM9000_ior(DM9000_ISR) & IMR_PTM) ) {
+	while (!(DM9000_ior(dev, DM9000_NSR) & (NSR_TX1END | NSR_TX2END)) ||
+		!(DM9000_ior(dev, DM9000_ISR) & IMR_PTM)) {
 		if (get_timer(0) >= tmo) {
 			printf("transmission timeout\n");
 			break;
 		}
 	}
-	DM9000_iow(DM9000_ISR, IMR_PTM); /* Clear Tx bit in ISR */
+	DM9000_iow(dev, DM9000_ISR, IMR_PTM); /* Clear Tx bit in ISR */
 
 	DM9000_DBG("transmit done\n\n");
 	return 0;
@@ -448,47 +475,50 @@ static int dm9000_send(struct eth_device *netdev, void *packet, int length)
   Stop the interface.
   The interface is stopped when it is brought.
 */
-static void dm9000_halt(struct eth_device *netdev)
+static void dm9000_halt(struct eth_device *dev)
 {
 	DM9000_DBG("%s\n", __func__);
 
 	/* RESET devie */
-	dm9000_phy_write(0, 0x8000);	/* PHY RESET */
-	DM9000_iow(DM9000_GPR, 0x01);	/* Power-Down PHY */
-	DM9000_iow(DM9000_IMR, 0x80);	/* Disable all interrupt */
-	DM9000_iow(DM9000_RCR, 0x00);	/* Disable RX */
+	dm9000_phy_write(dev, 0, 0x8000);	/* PHY RESET */
+	DM9000_iow(dev, DM9000_GPR, 0x01);	/* Power-Down PHY */
+	DM9000_iow(dev, DM9000_IMR, 0x80);	/* Disable all interrupt */
+	DM9000_iow(dev, DM9000_RCR, 0x00);	/* Disable RX */
 }
 
 /*
   Received a packet and pass to upper layer
 */
-static int dm9000_rx(struct eth_device *netdev)
+static int dm9000_rx(struct eth_device *dev)
 {
-	u8 rxbyte, *rdptr = (u8 *) NetRxPackets[0];
-	u16 RxStatus, RxLen = 0;
-	struct board_info *db = &dm9000_info;
+	u8 rxbyte, *rdptr = (u8 *)NetRxPackets[0];
+	u16 rxstatus, rxlen = 0;
+	struct dm9000_priv *priv = dev->priv;
 
 	/* Check packet ready or not, we must check
 	   the ISR status first for DM9000A */
-	if (!(DM9000_ior(DM9000_ISR) & 0x01)) /* Rx-ISR bit must be set. */
+	if (!(DM9000_ior(dev, DM9000_ISR) & 0x01)) /* Rx-ISR bit must be set. */
 		return 0;
 
-	DM9000_iow(DM9000_ISR, 0x01); /* clear PR status latched in bit 0 */
+	/* clear PR status latched in bit 0 */
+	DM9000_iow(dev, DM9000_ISR, 0x01);
 
 	/* There is _at least_ 1 package in the fifo, read them all */
 	for (;;) {
-		DM9000_ior(DM9000_MRCMDX);	/* Dummy read */
+		DM9000_ior(dev, DM9000_MRCMDX);	/* Dummy read */
 
 		/* Get most updated data,
 		   only look at bits 0:1, See application notes DM9000 */
-		rxbyte = DM9000_inb(DM9000_DATA) & 0x03;
+		rxbyte = DM9000_inb(priv->data_base) & 0x03;
 
 		/* Status check: this byte must be 0 or 1 */
 		if (rxbyte > DM9000_PKT_RDY) {
-			DM9000_iow(DM9000_RCR, 0x00);	/* Stop Device */
-			DM9000_iow(DM9000_ISR, 0x80);	/* Stop INT request */
+			/* Stop Device */
+			DM9000_iow(dev, DM9000_RCR, 0x00);
+			/* Stop INT request */
+			DM9000_iow(dev, DM9000_ISR, 0x80);
 			printf("DM9000 error: status check fail: 0x%x\n",
-				rxbyte);
+			       rxbyte);
 			return 0;
 		}
 
@@ -498,34 +528,31 @@ static int dm9000_rx(struct eth_device *netdev)
 		DM9000_DBG("receiving packet\n");
 
 		/* A packet ready now  & Get status/length */
-		(db->rx_status)(&RxStatus, &RxLen);
+		(priv->rx_status)(dev, &rxstatus, &rxlen);
 
-		DM9000_DBG("rx status: 0x%04x rx len: %d\n", RxStatus, RxLen);
+		DM9000_DBG("rx status: 0x%04x rx len: %d\n", rxstatus, rxlen);
 
 		/* Move data from DM9000 */
 		/* Read received packet from RX SRAM */
-		(db->inblk)(rdptr, RxLen);
+		(priv->inblk)(dev, rdptr, rxlen);
 
-		if ((RxStatus & 0xbf00) || (RxLen < 0x40)
-			|| (RxLen > DM9000_PKT_MAX)) {
-			if (RxStatus & 0x100) {
+		if ((rxstatus & 0xbf00) || (rxlen < 0x40) ||
+		    (rxlen > DM9000_PKT_MAX)) {
+			if (rxstatus & 0x100)
 				printf("rx fifo error\n");
-			}
-			if (RxStatus & 0x200) {
+			if (rxstatus & 0x200)
 				printf("rx crc error\n");
-			}
-			if (RxStatus & 0x8000) {
+			if (rxstatus & 0x8000)
 				printf("rx length error\n");
-			}
-			if (RxLen > DM9000_PKT_MAX) {
+			if (rxlen > DM9000_PKT_MAX) {
 				printf("rx length too big\n");
-				dm9000_reset();
+				dm9000_reset(dev);
 			}
 		} else {
-			DM9000_DMP_PACKET(__func__ , rdptr, RxLen);
+			DM9000_DMP_PACKET(__func__ , rdptr, rxlen);
 
 			DM9000_DBG("passing packet to upper layer\n");
-			NetReceive(NetRxPackets[0], RxLen);
+			NetReceive(NetRxPackets[0], rxlen);
 		}
 	}
 	return 0;
@@ -536,69 +563,76 @@ static int dm9000_rx(struct eth_device *netdev)
 */
 void dm9000_read_srom_word(struct eth_device *dev, int offset, u8 *to)
 {
-	(void)dev;
-	DM9000_iow(DM9000_EPAR, offset);
-	DM9000_iow(DM9000_EPCR, 0x4);
+	DM9000_iow(dev, DM9000_EPAR, offset);
+	DM9000_iow(dev, DM9000_EPCR, 0x4);
 	udelay(8000);
-	DM9000_iow(DM9000_EPCR, 0x0);
-	to[0] = DM9000_ior(DM9000_EPDRL);
-	to[1] = DM9000_ior(DM9000_EPDRH);
+	DM9000_iow(dev, DM9000_EPCR, 0x0);
+	to[0] = DM9000_ior(dev, DM9000_EPDRL);
+	to[1] = DM9000_ior(dev, DM9000_EPDRH);
 }
 
 void dm9000_write_srom_word(struct eth_device *dev, int offset, u16 val)
 {
-	(void)dev;
-	DM9000_iow(DM9000_EPAR, offset);
-	DM9000_iow(DM9000_EPDRH, ((val >> 8) & 0xff));
-	DM9000_iow(DM9000_EPDRL, (val & 0xff));
-	DM9000_iow(DM9000_EPCR, 0x12);
+	DM9000_iow(dev, DM9000_EPAR, offset);
+	DM9000_iow(dev, DM9000_EPDRH, ((val >> 8) & 0xff));
+	DM9000_iow(dev, DM9000_EPDRL, (val & 0xff));
+	DM9000_iow(dev, DM9000_EPCR, 0x12);
 	udelay(8000);
-	DM9000_iow(DM9000_EPCR, 0);
+	DM9000_iow(dev, DM9000_EPCR, 0);
 }
 
 static void dm9000_get_enetaddr(struct eth_device *dev)
 {
-#if !defined(CONFIG_DM9000_NO_SROM)
-	int i;
-	for (i = 0; i < 3; i++)
-		dm9000_read_srom_word(dev, i, dev->enetaddr + (2 * i));
-#endif
+	struct dm9000_priv *priv = dev->priv;
+	if (priv->has_srom) {
+		int i;
+		for (i = 0; i < 3; i++)
+			dm9000_read_srom_word(dev, i, dev->enetaddr + (2 * i));
+	}
 }
 
 /*
    Read a byte from I/O port
 */
 static u8
-DM9000_ior(int reg)
+DM9000_ior(struct eth_device *dev, int reg)
 {
-	DM9000_outb(reg, DM9000_IO);
-	return DM9000_inb(DM9000_DATA);
+	struct dm9000_priv *priv = dev->priv;
+
+	DM9000_outb(reg, priv->io_base);
+	return DM9000_inb(priv->data_base);
 }
 
 /*
    Write a byte to I/O port
 */
 static void
-DM9000_iow(int reg, u8 value)
+DM9000_iow(struct eth_device *dev, int reg, u8 value)
 {
-	DM9000_outb(reg, DM9000_IO);
-	DM9000_outb(value, DM9000_DATA);
+	struct dm9000_priv *priv = dev->priv;
+
+	DM9000_outb(reg, priv->io_base);
+	DM9000_outb(value, priv->data_base);
 }
 
 /*
    Read a word from phyxcer
 */
 static u16
-dm9000_phy_read(int reg)
+dm9000_phy_read(struct eth_device *dev, int reg)
 {
 	u16 val;
 
 	/* Fill the phyxcer register into REG_0C */
-	DM9000_iow(DM9000_EPAR, DM9000_PHY | reg);
-	DM9000_iow(DM9000_EPCR, 0xc);	/* Issue phyxcer read command */
-	udelay(100);			/* Wait read complete */
-	DM9000_iow(DM9000_EPCR, 0x0);	/* Clear phyxcer read command */
-	val = (DM9000_ior(DM9000_EPDRH) << 8) | DM9000_ior(DM9000_EPDRL);
+	DM9000_iow(dev, DM9000_EPAR, DM9000_PHY | reg);
+	/* Issue phyxcer read command */
+	DM9000_iow(dev, DM9000_EPCR, 0xc);
+	/* Wait read complete */
+	udelay(100);
+	/* Clear phyxcer read command */
+	DM9000_iow(dev, DM9000_EPCR, 0x0);
+	val = (DM9000_ior(dev, DM9000_EPDRH) << 8) |
+		DM9000_ior(dev, DM9000_EPDRL);
 
 	/* The read data keeps on REG_0D & REG_0E */
 	DM9000_DBG("dm9000_phy_read(0x%x): 0x%x\n", reg, val);
@@ -609,35 +643,69 @@ dm9000_phy_read(int reg)
    Write a word to phyxcer
 */
 static void
-dm9000_phy_write(int reg, u16 value)
+dm9000_phy_write(struct eth_device *dev, int reg, u16 value)
 {
-
 	/* Fill the phyxcer register into REG_0C */
-	DM9000_iow(DM9000_EPAR, DM9000_PHY | reg);
+	DM9000_iow(dev, DM9000_EPAR, DM9000_PHY | reg);
 
 	/* Fill the written data into REG_0D & REG_0E */
-	DM9000_iow(DM9000_EPDRL, (value & 0xff));
-	DM9000_iow(DM9000_EPDRH, ((value >> 8) & 0xff));
-	DM9000_iow(DM9000_EPCR, 0xa);	/* Issue phyxcer write command */
-	udelay(500);			/* Wait write complete */
-	DM9000_iow(DM9000_EPCR, 0x0);	/* Clear phyxcer write command */
+	DM9000_iow(dev, DM9000_EPDRL, (value & 0xff));
+	DM9000_iow(dev, DM9000_EPDRH, ((value >> 8) & 0xff));
+	/* Issue phyxcer write command */
+	DM9000_iow(dev, DM9000_EPCR, 0xa);
+	/* Wait write complete */
+	udelay(500);
+	/* Clear phyxcer write command */
+	DM9000_iow(dev, DM9000_EPCR, 0x0);
 	DM9000_DBG("dm9000_phy_write(reg:0x%x, value:0x%x)\n", reg, value);
 }
 
-int dm9000_initialize(bd_t *bis)
+int dm9000_initialize_ex(u8 dev_num, ulong addr, ulong data, u8 has_srom)
 {
-	struct eth_device *dev = &(dm9000_info.netdev);
+	struct eth_device *dev;
+	struct dm9000_priv *priv;
+
+	priv = malloc(sizeof(*priv));
+	if (!priv)
+		return 1;
+	dev = malloc(sizeof(*dev));
+	if (!dev) {
+		free(priv);
+		return 2;
+	}
 
-	/* Load MAC address from EEPROM */
-	dm9000_get_enetaddr(dev);
+	memset(dev, 0, sizeof(*dev));
+	memset(priv, 0, sizeof(*priv));
 
+	priv->io_base = addr;
+	priv->data_base = data;
+	priv->has_srom = has_srom;
+	dev->priv = priv;
 	dev->init = dm9000_init;
 	dev->halt = dm9000_halt;
 	dev->send = dm9000_send;
 	dev->recv = dm9000_rx;
-	sprintf(dev->name, "dm9000");
+	if (dev_num > 0)
+		sprintf(dev->name, "dm9000-%hu", dev_num);
+	else
+		sprintf(dev->name, "dm9000");
+
+	/* Load MAC address from EEPROM */
+	dm9000_get_enetaddr(dev);
 
-	eth_register(dev);
+	return eth_register(dev);
+}
 
-	return 0;
+int dm9000_initialize(bd_t *bis)
+{
+#if defined(DM9000_IO) && defined(DM9000_DATA)
+#ifdef CONFIG_DM9000_NO_SROM
+	u8 has_srom = 0;
+#else
+	u8 has_srom = 1;
+#endif
+	return dm9000_initialize_ex(0, DM9000_IO, DM9000_DATA, has_srom);
+#else
+	return 1;
+#endif
 }
include/netdev.h +1 -0
index a887bfb..5985516 100644
@@ -39,6 +39,7 @@ int davinci_emac_initialize(void);
 int dc21x4x_initialize(bd_t *bis);
 int designware_initialize(ulong base_addr, u32 interface);
 int dm9000_initialize(bd_t *bis);
+int dm9000_initialize_ex(u8 dev_num, ulong addr, ulong data, u8 has_srom);
 int dnet_eth_initialize(int id, void *regs, unsigned int phy_addr);
 int e1000_initialize(bd_t *bis);
 int eepro100_initialize(bd_t *bis);
Signature · 1 line
2.1.1
#10 lore raw

PATCH v2 3/3 dm9000: rework dm9000 to support multiple devices

Quoted 5 lines · Andrew Ruder

The DM9000 was hard-coded to only support one DM9000 device. This patch adds a new initialization function - dm9000_initialize_ex() - to support registering multiple (and possibly dynamic) numbers of dm9000 devices. This patch consists of:

Quoted 8 lines

* Change the board_info struct to a private struct under eth_device.
* Add io address/data address/srom availability information to this private struct.
* Replace all uses of DM9000_IO/DM9000_DATA with new members, ensure that the eth_device struct propagates down to all helper functions.
* Make dm9000_initialize() call dm9000_initialize_ex() with filled in information from the old preprocessor symbols (DM9000_IO, DM9000_DATA, etc.)

So, on new platforms we call dm9000_initialize with the right IO/DATA locations for the given device, yes? I think I'd rather update everyone else to call things the right and new way, rather than work-around supporting both.

Signature · 8 lines
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20141020/c99d859f/attachment.pgp>
#11 lore raw

PATCH v2 3/3 dm9000: rework dm9000 to support multiple devices

Quoted 4 lines · Tom Rini

So, on new platforms we call dm9000_initialize with the right IO/DATA locations for the given device, yes? I think I'd rather update everyone else to call things the right and new way, rather than work-around supporting both.

The expectation is that new platforms would move over to dm9000_initialize_ex(), dm9000_initialize() just being a shim to use what used to be #define'd in the board config.h for backwards compatibility with older boards.

There's really 3 options that I fought with:

1.) Change dm9000_initialize() to dm9000_initialize(x, y, z). PATCH #3 then also includes changes to all of the various boards.

2.) Add dm9000_initialize_ex(x, y, z), make dm9000_initialize() call dm9000_initiailize_ex(x, y, z). No boards need to change. This is what I chose.

3.) Hybrid approach, do #2, make another patch (#4) that moves everything over to dm9000_initialize_ex(x, y, z) while renaming it to dm9000_initialize(x, y, z). Seems more round-about than #1 with the same end-result, but sometimes I feel like it is a little easier to review the meat of this change (#3) without it also dealing with tons of board churn.

Thoughts?

- Andy

#12 lore raw

PATCH v2 3/3 dm9000: rework dm9000 to support multiple devices

Quoted 20 lines · Andrew Ruder
Quoted 4 lines · Tom Rini

So, on new platforms we call dm9000_initialize with the right IO/DATA locations for the given device, yes? I think I'd rather update everyone else to call things the right and new way, rather than work-around supporting both.

The expectation is that new platforms would move over to dm9000_initialize_ex(), dm9000_initialize() just being a shim to use what used to be #define'd in the board config.h for backwards compatibility with older boards.

There's really 3 options that I fought with:

1.) Change dm9000_initialize() to dm9000_initialize(x, y, z). PATCH #3 then also includes changes to all of the various boards.

2.) Add dm9000_initialize_ex(x, y, z), make dm9000_initialize() call dm9000_initiailize_ex(x, y, z). No boards need to change. This is what I chose.

Quoted 8 lines

3.) Hybrid approach, do #2, make another patch (#4) that moves everything over to dm9000_initialize_ex(x, y, z) while renaming it to dm9000_initialize(x, y, z). Seems more round-about than #1 with the same end-result, but sometimes I feel like it is a little easier to review the meat of this change (#3) without it also dealing with tons of board churn.

Thoughts?

How about step 1 is checkpatch re-formatting only, step 2 is dm9000_initalize(x, y, z) but y/z aren't used, step 3 is passing around 'dev' and step 4 is the rest of the changes (so that y/z are used, if I follow all of the logic right). This splits the whitespace/etc churn out from everything else, then makes it easy enough to review that boards are converted right to the new logic.

Signature · 8 lines
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20141020/2e419c5c/attachment.pgp>
#13 lore raw

PATCH v2 3/3 dm9000: rework dm9000 to support multiple devices

Hi Andrew,

Quoted 28 lines · Tom Rini
Quoted 27 lines · Andrew Ruder
Quoted 4 lines · Tom Rini

So, on new platforms we call dm9000_initialize with the right IO/DATA locations for the given device, yes? I think I'd rather update everyone else to call things the right and new way, rather than work-around supporting both.

The expectation is that new platforms would move over to dm9000_initialize_ex(), dm9000_initialize() just being a shim to use what used to be #define'd in the board config.h for backwards compatibility with older boards.

There's really 3 options that I fought with:

1.) Change dm9000_initialize() to dm9000_initialize(x, y, z). PATCH #3 then also includes changes to all of the various boards.

2.) Add dm9000_initialize_ex(x, y, z), make dm9000_initialize() call dm9000_initiailize_ex(x, y, z). No boards need to change. This is what I chose.

3.) Hybrid approach, do #2, make another patch (#4) that moves everything over to dm9000_initialize_ex(x, y, z) while renaming it to dm9000_initialize(x, y, z). Seems more round-about than #1 with the same end-result, but sometimes I feel like it is a little easier to review the meat of this change (#3) without it also dealing with tons of board churn.

Quoted 8 lines
Quoted 1 line

Thoughts?

How about step 1 is checkpatch re-formatting only, step 2 is dm9000_initalize(x, y, z) but y/z aren't used, step 3 is passing around 'dev' and step 4 is the rest of the changes (so that y/z are used, if I follow all of the logic right). This splits the whitespace/etc churn out from everything else, then makes it easy enough to review that boards are converted right to the new logic.

What ever became of this series?

Thanks,
-Joe

#14 lore raw

PATCH v2 3/3 dm9000: rework dm9000 to support multiple devices

Quoted 1 line · Joe Hershberger

What ever became of this series?

I failed to ever email it in... I have a redone series, let me clean it up and give it a quick test and make sure it works on latest... Needed to rebase on about 10 months of upstream.