mail archive of the barebox mailing list
 help / color / mirror / Atom feed
* [PATCH] Add support for the more recent Davicom DM9000A and DM9000B
@ 2011-12-12  9:27 Juergen Beisert
  2011-12-12  9:27 ` [PATCH 1/2] Add support for more recent Davicom DM9k devices Juergen Beisert
  2011-12-12  9:27 ` [PATCH 2/2] Remove the obsolet driver for the DM9000E ethernet device Juergen Beisert
  0 siblings, 2 replies; 4+ messages in thread
From: Juergen Beisert @ 2011-12-12  9:27 UTC (permalink / raw)
  To: barebox

The current Davicom DM9000 support covers the DM9000E device only. This patch
series adds support of for the more recent DM9000A and DM9000B variants.
The DM9000E variant is still supported.

Tested on Mini2440 with the DM9000E variant and Mini6410 with the DM9000A variant.

Comments are welcome.

Juergen


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH 1/2] Add support for more recent Davicom DM9k devices
  2011-12-12  9:27 [PATCH] Add support for the more recent Davicom DM9000A and DM9000B Juergen Beisert
@ 2011-12-12  9:27 ` Juergen Beisert
  2011-12-12 10:42   ` Sascha Hauer
  2011-12-12  9:27 ` [PATCH 2/2] Remove the obsolet driver for the DM9000E ethernet device Juergen Beisert
  1 sibling, 1 reply; 4+ messages in thread
From: Juergen Beisert @ 2011-12-12  9:27 UTC (permalink / raw)
  To: barebox

This patch adds support for the more recent DM9000A and DM9000B types, and keeps
support for the older DM9000E device. As this patch is more or less a complete
re-wrote of the existing driver I add a new source file instead of fixing the
existing one. In a later patch the old driver will be removed.

Signed-off-by: Juergen Beisert <jbe@pengutronix.de>
---
 drivers/net/Kconfig  |    5 +
 drivers/net/Makefile |    1 +
 drivers/net/dm9k.c   |  784 ++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 790 insertions(+), 0 deletions(-)
 create mode 100644 drivers/net/dm9k.c

diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 19e35db..6c697a9 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -51,6 +51,11 @@ config DRIVER_NET_DM9000
 	depends on HAS_DM9000
 	select MIIDEV
 
+config DRIVER_NET_DM9K
+	bool "Davicom dm9k[E|A|B] ethernet driver"
+	depends on HAS_DM9000
+	select MIIDEV
+
 config DRIVER_NET_NETX
 	bool "Hilscher Netx ethernet driver"
 	depends on HAS_NETX_ETHER
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index f02618b..d3bc7b0 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -2,6 +2,7 @@ obj-$(CONFIG_DRIVER_NET_CS8900)		+= cs8900.o
 obj-$(CONFIG_DRIVER_NET_SMC911X)	+= smc911x.o
 obj-$(CONFIG_DRIVER_NET_SMC91111)	+= smc91111.o
 obj-$(CONFIG_DRIVER_NET_DM9000)		+= dm9000.o
+obj-$(CONFIG_DRIVER_NET_DM9K)		+= dm9k.o
 obj-$(CONFIG_DRIVER_NET_NETX)		+= netx_eth.o
 obj-$(CONFIG_DRIVER_NET_AT91_ETHER)	+= at91_ether.o
 obj-$(CONFIG_DRIVER_NET_MPC5200)	+= fec_mpc5200.o
diff --git a/drivers/net/dm9k.c b/drivers/net/dm9k.c
new file mode 100644
index 0000000..8efaa5a
--- /dev/null
+++ b/drivers/net/dm9k.c
@@ -0,0 +1,784 @@
+/*
+ * Copyright (C) 2011 Juergen Beisert, Pengutronix
+ *
+ * Davicom DM9000(E/A/B) NIC fast Ethernet driver for Barebox
+ *
+ * In some ways inspired by code
+ *
+ *   Copyright (C) 1997  Sten Wang
+ *   1997-1998 DAVICOM Semiconductor,Inc.
+ *   2003 Weilun Huang <weilun_huang@davicom.com.tw>
+ *   2003 <saschahauer@web.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#undef DEBUG
+
+#include <init.h>
+#include <common.h>
+#include <driver.h>
+#include <miidev.h>
+#include <net.h>
+#include <io.h>
+#include <xfuncs.h>
+#include <dm9000.h>
+#include <errno.h>
+
+#define DM9K_ID		0x90000A46
+#define CHIPR_DM9000A	0x19
+#define CHIPR_DM9000B	0x1A
+
+#define DM9K_PKT_NONE	0x00	/* no packet received (end marker) */
+#define DM9K_PKT_RDY	0x01	/* packet ready to read */
+#define DM9K_PKT_ERR	0x02	/* chip error */
+#define DM9K_PKT_MAX	1536	/* packet max size */
+
+#define DM9K_NCR	0x00
+# define NCR_EXT_PHY	(1 << 7)
+# define NCR_WAKEEN	(1 << 6)
+# define NCR_FCOL	(1 << 4)
+# define NCR_FDX	(1 << 3)
+# define NCR_LBK	(3 << 1)
+# define NCR_RST	(1 << 0)
+
+#define DM9K_NSR	0x01
+# define NSR_SPEED	(1 << 7)
+# define NSR_LINKST	(1 << 6)
+# define NSR_WAKEST	(1 << 5)
+# define NSR_TX2END	(1 << 3)
+# define NSR_TX1END	(1 << 2)
+# define NSR_RXOV	(1 << 1)
+
+#define DM9K_TCR	0x02
+# define TCR_TJDIS	(1 << 6)
+# define TCR_EXCECM	(1 << 5)
+# define TCR_PAD_DIS2	(1 << 4)
+# define TCR_CRC_DIS2	(1 << 3)
+# define TCR_PAD_DIS1	(1 << 2)
+# define TCR_CRC_DIS1	(1 << 1)
+# define TCR_TXREQ	(1 << 0)
+
+#define DM9K_TSR1	0x03
+#define DM9K_TSR2	0x04
+# define TSR_TJTO	(1 << 7)
+# define TSR_LC		(1 << 6)
+# define TSR_NC		(1 << 5)
+# define TSR_LCOL	(1 << 4)
+# define TSR_COL	(1 << 3)
+# define TSR_EC		(1 << 2)
+
+#define DM9K_RCR	0x05
+# define RCR_WTDIS	(1 << 6)
+# define RCR_DIS_LONG	(1 << 5)
+# define RCR_DIS_CRC	(1 << 4)
+# define RCR_ALL	(1 << 3)
+# define RCR_RUNT	(1 << 2)
+# define RCR_PRMSC	(1 << 1)
+# define RCR_RXEN	(1 << 0)
+
+#define DM9K_RSR	0x06
+# define RSR_RF		(1 << 7)
+# define RSR_MF		(1 << 6)
+# define RSR_LCS	(1 << 5)
+# define RSR_RWTO	(1 << 4)
+# define RSR_PLE	(1 << 3)
+# define RSR_AE		(1 << 2)
+# define RSR_CE		(1 << 1)
+# define RSR_FOE	(1 << 0)
+# define RSR_ERR_MASK (RSR_FOE | RSR_CE | RSR_AE | RSR_PLE | RSR_RWTO | RSR_LCS | RSR_RF)
+
+#define DM9K_ROCR	0x07
+#define DM9K_BPTR	0x08
+#define DM9K_FCTR	0x09
+#define DM9K_FCR	0x0A
+#define DM9K_EPCR	0x0B
+#define DM9K_EPAR	0x0C
+#define DM9K_EPDRL	0x0D
+#define DM9K_EPDRH	0x0E
+#define DM9K_WCR	0x0F
+
+#define DM9K_PAR	0x10
+#define DM9K_MAR	0x16
+
+#define DM9K_GPCR	0x1e
+#define DM9K_GPR	0x1f
+#define DM9K_TRPAL	0x22
+#define DM9K_TRPAH	0x23
+#define DM9K_RWPAL	0x24
+#define DM9K_RWPAH	0x25
+
+#define DM9K_VIDL	0x28
+#define DM9K_VIDH	0x29
+#define DM9K_PIDL	0x2A
+#define DM9K_PIDH	0x2B
+
+#define DM9K_CHIPR	0x2C
+#define DM9K_SMCR	0x2F
+
+#define DM9K_PHY	0x40	/* PHY address 0x01 */
+
+#define DM9K_MRCMDX	0xF0
+#define DM9K_MRCMD	0xF2
+#define DM9K_MRRL	0xF4
+#define DM9K_MRRH	0xF5
+#define DM9K_MWCMDX	0xF6
+#define DM9K_MWCMD	0xF8
+#define DM9K_MWRL	0xFA
+#define DM9K_MWRH	0xFB
+#define DM9K_TXPLL	0xFC
+#define DM9K_TXPLH	0xFD
+
+#define DM9K_ISR	0xFE
+# define ISR_IOM0	(1 << 7) /* 0: 16 bit, 1: 8 bit*/
+# define ISR_LNKCHG	(1 << 5) /* link status change */
+# define ISR_UDRUN	(1 << 4) /* transmitt underrun */
+# define ISR_ROO	(1 << 3) /* receive overflow counter overflow */
+# define ISR_ROS	(1 << 2) /* receive overflow */
+# define ISR_PT		(1 << 1) /* packet transmitted */
+# define ISR_PR		(1 << 0) /* packet received */
+# define ISR_CLEAR_MASK (ISR_PR | ISR_PT | ISR_ROS | ISR_ROO | ISR_UDRUN | ISR_LNKCHG)
+
+#define DM9K_IMR	0xFF
+# define IMR_PAR	(1 << 7)
+# define IMR_ROOM	(1 << 3)
+# define IMR_ROM	(1 << 2)
+# define IMR_PTM	(1 << 1)
+# define IMR_PRM	(1 << 0)
+
+#define FCTR_HWOT(ot)	(( ot & 0xf ) << 4 )
+#define FCTR_LWOT(ot)	( ot & 0xf )
+
+struct dm9k {
+	void __iomem *iobase;
+	void __iomem *iodata;
+	struct mii_device miidev;
+	int buswidth;
+	int srom;
+	uint8_t pckt[2048];
+};
+
+/* ------------------ register access functions -------------------------- */
+
+static uint8_t dm9k_ior(struct dm9k *priv, int reg)
+{
+	writeb(reg, priv->iobase);
+	return readb(priv->iodata);
+}
+
+static void dm9k_iow(struct dm9k *priv, int reg, uint8_t value)
+{
+	writeb(reg, priv->iobase);
+	writeb(value, priv->iodata);
+}
+
+/* ------------------- data move functions ---------------------------- */
+
+static void dm9k_wd_8(void __iomem *port, const void *src, int length)
+{
+	const uint8_t *from = (const uint8_t *)src;
+
+	while (length--)
+		writeb(*from++, port);
+}
+
+static void dm9k_rd_8(void __iomem *port, void *dst, unsigned length)
+{
+	uint8_t *to = (uint8_t *)dst;
+
+	while (length--)
+		*to++ = readb(port);
+}
+
+static void dm9k_dump_8(void __iomem *port, unsigned length)
+{
+	while (length--)
+		readb(port);
+}
+
+static unsigned dm9k_read_packet_status_8(void __iomem *port, unsigned *status)
+{
+	uint16_t st, le;
+
+	dm9k_rd_8(port, &st, sizeof(st));
+	dm9k_rd_8(port, &le, sizeof(le));
+
+	*status = st >> 8;
+	return le;
+}
+
+static void dm9k_wd_16(void __iomem *port, const void *src, int length)
+{
+	const uint16_t *from = (const uint16_t *)src;
+
+	length += 1;
+	length /= 2;
+	while (length--)
+		writew(*from++, port);
+}
+
+static void dm9k_rd_16(void __iomem *port, void *dst, unsigned length)
+{
+	uint16_t *to = (uint16_t *)dst;
+
+	length += 1;
+	length >>= 1;
+	while (length--)
+		*to++ = readw(port);
+}
+
+static void dm9k_dump_16(void __iomem *port, unsigned length)
+{
+	length += 1;
+	length >>= 1;
+	while (length--)
+		readw(port);
+}
+
+static unsigned dm9k_read_packet_status_16(void __iomem *port, unsigned *status)
+{
+	*status = readw(port) >> 8;
+	return le16_to_cpu(readw(port));
+}
+
+static void dm9k_wd_32(void __iomem *port, const void *src, int length)
+{
+	const uint32_t *from = (const uint32_t *)src;
+
+	length += 3;
+	length /= 4;
+	while (length--)
+		writel(*from++, port);
+}
+
+static void dm9k_rd_32(void __iomem *port, void *dst, unsigned length)
+{
+	uint32_t *to = (uint32_t *)dst;
+
+	length += 3;
+	length >>= 2;
+	while (length--)
+		*to++ = readl(port);
+}
+
+static void dm9k_dump_32(void __iomem *port, unsigned length)
+{
+	length += 3;
+	length >>= 2;
+	while (length--)
+		readl(port);
+}
+
+static unsigned dm9k_read_packet_status_32(void __iomem *port, unsigned *status)
+{
+	uint32_t tmp = readl(port);
+
+	*status = (tmp >> 8) & 0xff;
+	return tmp >> 16;
+}
+
+static unsigned dm9k_read_packet_status(int b_width, void __iomem *port, unsigned *status)
+{
+	unsigned rc;
+
+	switch (b_width) {
+	case IORESOURCE_MEM_8BIT:
+		rc = dm9k_read_packet_status_8(port, status);
+		break;
+	case IORESOURCE_MEM_16BIT:
+		rc = dm9k_read_packet_status_16(port, status);
+		break;
+	case IORESOURCE_MEM_32BIT:
+		rc = dm9k_read_packet_status_32(port, status);
+		break;
+	}
+
+	return rc;
+}
+
+static void dm9k_dump(int b_width, void __iomem *port, unsigned length)
+{
+	switch (b_width) {
+	case IORESOURCE_MEM_8BIT:
+		dm9k_dump_8(port, length);
+		break;
+	case IORESOURCE_MEM_16BIT:
+		dm9k_dump_16(port, length);
+		break;
+	case IORESOURCE_MEM_32BIT:
+		dm9k_dump_32(port, length);
+		break;
+	}
+}
+
+static void dm9k_rd(int b_width, void __iomem *port, void *dst, unsigned length)
+{
+	switch (b_width) {
+	case IORESOURCE_MEM_8BIT:
+		dm9k_rd_8(port, dst, length);
+		break;
+	case IORESOURCE_MEM_16BIT:
+		dm9k_rd_16(port, dst, length);
+		break;
+	case IORESOURCE_MEM_32BIT:
+		dm9k_rd_32(port, dst, length);
+		break;
+	}
+}
+
+static void dm9k_wd(int b_width, void __iomem *port, const void *src, int length)
+{
+	switch (b_width) {
+	case IORESOURCE_MEM_8BIT:
+		dm9k_wd_8(port, src, length);
+		break;
+	case IORESOURCE_MEM_16BIT:
+		dm9k_wd_16(port, src, length);
+		break;
+	case IORESOURCE_MEM_32BIT:
+		dm9k_wd_32(port, src, length);
+		break;
+	}
+}
+
+/* ----------------- end of data move functions -------------------------- */
+
+static int dm9k_phy_read(struct mii_device *mdev, int addr, int reg)
+{
+	unsigned val;
+	struct eth_device *edev = mdev->edev;
+	struct dm9k *priv = edev->priv;
+
+	/* Fill the phyxcer register into REG_0C */
+	dm9k_iow(priv, DM9K_EPAR, DM9K_PHY | reg);
+	dm9k_iow(priv, DM9K_EPCR, 0xc);	/* Issue phyxcer read command */
+	udelay(100);			/* Wait read complete */
+	dm9k_iow(priv, DM9K_EPCR, 0x0);	/* Clear phyxcer read command */
+	val = dm9k_ior(priv, DM9K_EPDRH);
+	val <<= 8;
+	val |= dm9k_ior(priv, DM9K_EPDRL);
+
+	/* The read data keeps on REG_0D & REG_0E */
+	debug("phy_read(%d): %d\n", reg, val);
+	return val;
+}
+
+static int dm9k_phy_write(struct mii_device *mdev, int addr, int reg, int val)
+{
+	struct eth_device *edev = mdev->edev;
+	struct dm9k *priv = edev->priv;
+
+	/* Fill the phyxcer register into REG_0C */
+	dm9k_iow(priv, DM9K_EPAR, DM9K_PHY | reg);
+
+	/* Fill the written data into REG_0D & REG_0E */
+	dm9k_iow(priv, DM9K_EPDRL, val);
+	dm9k_iow(priv, DM9K_EPDRH, val >> 8);
+	dm9k_iow(priv, DM9K_EPCR, 0xa);	/* Issue phyxcer write command */
+	udelay(500);			/* Wait write complete */
+	dm9k_iow(priv, DM9K_EPCR, 0x0);	/* Clear phyxcer write command */
+
+	pr_debug("phy_write(reg:%d, value:%d)\n", reg, val);
+
+	return 0;
+}
+
+static int dm9k_check_id(struct dm9k *priv)
+{
+	u32 id;
+	char c;
+
+	id = dm9k_ior(priv, DM9K_VIDL);
+	id |= dm9k_ior(priv, DM9K_VIDH) << 8;
+	id |= dm9k_ior(priv, DM9K_PIDL) << 16;
+	id |= dm9k_ior(priv, DM9K_PIDH) << 24;
+
+	if (id != DM9K_ID) {
+		pr_err("dm9000 not found at 0x%p id: 0x%08x\n", priv->iobase, id);
+		return -ENODEV;
+	}
+
+	id = dm9k_ior(priv, DM9K_CHIPR);
+	pr_debug("dm9000 revision 0x%02x\n", id);
+
+	switch (id) {
+	case CHIPR_DM9000A:
+		c = 'A';
+		break;
+	case CHIPR_DM9000B:
+		c = 'B';
+		break;
+	default:
+		c = 'E';
+	}
+	pr_info("Found DM9000%c at i/o: 0x%p\n", c, priv->iobase);
+
+	return 0;
+}
+
+static void dm9k_enable(struct dm9k *priv)
+{
+	/* only intern phy supported by now */
+	dm9k_iow(priv, DM9K_NCR, 0x00);
+	/* TX Polling clear */
+	dm9k_iow(priv, DM9K_TCR, 0x00);
+	/* Less 3Kb, 200us */
+	dm9k_iow(priv, DM9K_BPTR, 0x3f);
+	/* Flow Control : High/Low Water */
+	dm9k_iow(priv, DM9K_FCTR, FCTR_HWOT(3) | FCTR_LWOT(8));
+	/* SH FIXME: This looks strange! Flow Control */
+	dm9k_iow(priv, DM9K_FCR, 0x00);
+	/* Special Mode */
+	dm9k_iow(priv, DM9K_SMCR, 0x00);
+	/* clear TX status */
+	dm9k_iow(priv, DM9K_NSR, NSR_WAKEST | NSR_TX2END | NSR_TX1END);
+	/* Clear interrupt status */
+	dm9k_iow(priv, DM9K_IMR, IMR_PAR);
+	dm9k_iow(priv, DM9K_ISR, ISR_CLEAR_MASK);
+
+	/* Activate DM9000 */
+	dm9k_iow(priv, DM9K_GPCR, 0x01); /* Let GPIO0 output */
+	dm9k_iow(priv, DM9K_GPR, 0x00);	/* Enable PHY */
+	/* RX enable */
+	dm9k_iow(priv, DM9K_RCR, RCR_DIS_LONG | RCR_DIS_CRC | RCR_RXEN);
+	/* Enable TX/RX interrupt mask */
+	dm9k_iow(priv, DM9K_IMR, IMR_PAR | IMR_PRM | IMR_PTM);
+}
+
+static void dm9k_reset(struct dm9k *priv)
+{
+	pr_debug("%s\n", __func__);
+	dm9k_iow(priv, DM9K_NCR, NCR_RST);
+	udelay(1000);		/* delay 1ms */
+}
+
+static int dm9k_eth_open(struct eth_device *edev)
+{
+	struct dm9k *priv = (struct dm9k *)edev->priv;
+
+	miidev_wait_aneg(&priv->miidev);
+	miidev_print_status(&priv->miidev);
+	return 0;
+}
+
+static void dm9k_write_length(struct dm9k *priv, unsigned length)
+{
+	dm9k_iow(priv, DM9K_TXPLL, length);
+	dm9k_iow(priv, DM9K_TXPLH, length >> 8);
+}
+
+static int dm9k_wait_for_trans_end(struct dm9k *priv)
+{
+	static const uint64_t toffs = 5 * SECOND;	/* FIXME too long */
+	uint8_t status;
+	uint64_t start = get_time_ns();
+
+	do {
+		status = dm9k_ior(priv, DM9K_NSR);
+		if (status & (NSR_TX1END | NSR_TX2END)) {
+			pr_debug("transmitt done\n");
+			return 0;
+		}
+		status = dm9k_ior(priv, DM9K_ISR);
+		if (status & IMR_PTM) {
+			/* Clear Tx bit in ISR */
+			dm9k_iow(priv, DM9K_ISR, IMR_PTM);
+			pr_debug("transmitt done\n");
+			return 0;
+		}
+	} while (!is_timeout(start, toffs));
+
+	return -ETIMEDOUT;
+}
+
+static int dm9k_eth_send(struct eth_device *edev, void *packet, int length)
+{
+	struct dm9k *priv = (struct dm9k *)edev->priv;
+
+	pr_debug("%s: %d bytes\n", __func__, length);
+
+	/* arm the Tx bit */
+	dm9k_iow(priv, DM9K_ISR, IMR_PTM);
+
+	/* Prepare for TX-data */
+	writeb(DM9K_MWCMD, priv->iobase);
+
+	/* Move the packet into the DM9k's TX RAM */
+	dm9k_wd(priv->buswidth, priv->iodata, packet, length);
+
+	/* Set TX length of the packet */
+	dm9k_write_length(priv, length);
+
+	/* Issue TX polling command */
+	dm9k_iow(priv, DM9K_TCR, TCR_TXREQ); /* Cleared after TX complete */
+
+	/* wait for end of transmission */
+	return dm9k_wait_for_trans_end(priv);
+}
+
+static int dm9k_check_for_rx_packet(struct dm9k *priv)
+{
+	uint8_t status;
+
+	status = dm9k_ior(priv, DM9K_ISR);
+	if (!(status & ISR_PR))
+		return 0;	/* no packet */
+
+	pr_debug("Packet present\n");
+	dm9k_iow(priv, DM9K_ISR, ISR_PR); /* clear PR status latched in bit 0 */
+	return 1; /* packet present */
+}
+
+static int dm9k_validate_entry(struct dm9k *priv)
+{
+	uint8_t p_stat;
+	/*
+	 * setup read pointer to current packet
+	 * but without address increment
+	 */
+	dm9k_ior(priv, DM9K_MRCMDX);
+
+	/* read the entry's status according to the app note */
+	p_stat = readb(priv->iodata) & 0x03;
+	pr_debug("%s packet status %02X\n", __func__, p_stat);
+
+	switch (p_stat) {
+	case DM9K_PKT_NONE: /* there is no packet (or the last in the chain) */
+		return 0;
+
+	case DM9K_PKT_ERR: /* chip in invalid state. Needs a software reset */
+		pr_debug("Confused chip.\n");
+		dm9k_iow(priv, DM9K_RCR, 0x00);	/* Stop Device */
+		dm9k_iow(priv, DM9K_ISR, 0x80);	/* Stop INT request */
+		dm9k_reset(priv);
+		dm9k_enable(priv);
+		return 0;
+	}
+
+	return 1; /* entry is valid */
+}
+
+static int dm9k_eth_rx(struct eth_device *edev)
+{
+	struct dm9k *priv = (struct dm9k *)edev->priv;
+	unsigned rx_stat = 0, rx_len = 0;
+	bool p_valid;
+
+	if (dm9k_check_for_rx_packet(priv) == 0)
+		return 0;	/* no data present */
+
+	do {
+		if (!dm9k_validate_entry(priv))
+			return 0;
+
+		/* assume this packet is valid */
+		p_valid = true;
+
+		 /* read with automatic address increment now */
+		writeb(DM9K_MRCMD, priv->iobase);
+		rx_len = dm9k_read_packet_status(priv->buswidth, priv->iodata, &rx_stat);
+		if (rx_len < 0x40) {
+			pr_debug("Packet too short (%u bytes)\n", rx_len);
+			p_valid = false;
+		}
+
+		/* validate packet */
+		if (rx_stat & RSR_ERR_MASK) {
+			if (rx_stat & RSR_FOE)
+				pr_warn("rx fifo overflow error\n");
+			if (rx_stat & RSR_CE)
+				pr_warn("rx crc error\n");
+			if (rx_stat & RSR_AE)
+				pr_warn("rx Alignment Error error\n");
+			if (rx_stat & RSR_PLE)
+				pr_warn("rx Physical Layer Error error\n");
+			if (rx_stat & RSR_RWTO)
+				pr_warn("rx Receive Watchdog Time Out error\n");
+			if (rx_stat & RSR_LCS)
+				pr_warn("rx Late Collision Seen error\n");
+			if (rx_stat & RSR_RF)
+				pr_warn("rx length error (runt frame)\n");
+			p_valid = false;
+		}
+
+		if (rx_len > DM9K_PKT_MAX) {
+			pr_warn("rx length too big\n");
+			/* discard packet */
+			dm9k_dump(priv->buswidth, priv->iodata, rx_len);
+			dm9k_reset(priv);
+			dm9k_enable(priv);
+			return 0;
+		}
+
+		if (p_valid == true) {
+			pr_debug("Receiving packet\n");
+			dm9k_rd(priv->buswidth, priv->iodata, priv->pckt, rx_len);
+			pr_debug("passing %u bytes packet to upper layer\n", rx_len);
+			net_receive(priv->pckt, rx_len);
+		} else {
+			pr_debug("Discarding packet\n");
+			dm9k_dump(priv->buswidth, priv->iodata, rx_len); /* discard packet */
+		}
+	} while (1);
+
+	return 0;
+}
+
+
+static void dm9k_eth_halt(struct eth_device *edev)
+{
+	pr_debug("eth_halt\n");
+#if 0
+	phy_write(0, 0x8000);	/* PHY RESET */
+	dm9k_iow(DM9K_GPR, 0x01);	/* Power-Down PHY */
+	dm9k_iow(DM9K_IMR, 0x80);	/* Disable all interrupt */
+	dm9k_iow(DM9K_RCR, 0x00);	/* Disable RX */
+#endif
+}
+
+static u16 read_srom_word(struct dm9k *priv, int offset)
+{
+	dm9k_iow(priv, DM9K_EPAR, offset);
+	dm9k_iow(priv, DM9K_EPCR, 0x4);
+	udelay(200);
+	dm9k_iow(priv, DM9K_EPCR, 0x0);
+	return (dm9k_ior(priv, DM9K_EPDRL) + (dm9k_ior(priv, DM9K_EPDRH) << 8));
+}
+
+static int dm9k_get_ethaddr(struct eth_device *edev, unsigned char *adr)
+{
+	struct dm9k *priv = (struct dm9k *)edev->priv;
+	int i, oft;
+
+	if (priv->srom) {
+		for (i = 0; i < 3; i++)
+			((u16 *) adr)[i] = read_srom_word(priv, i);
+	} else {
+		for (i = 0, oft = DM9K_PAR; i < 6; i++, oft++)
+			adr[i] = dm9k_ior(priv, oft);
+	}
+
+	return 0;
+}
+
+static int dm9k_set_ethaddr(struct eth_device *edev, unsigned char *adr)
+{
+	struct dm9k *priv = (struct dm9k *)edev->priv;
+	int i, oft;
+
+	for (i = 0, oft = DM9K_PAR; i < 6; i++, oft++)
+		dm9k_iow(priv, oft, adr[i]);
+	for (i = 0, oft = DM9K_MAR; i < 8; i++, oft++)
+		dm9k_iow(priv, oft, 0xff);
+
+	return 0;
+}
+
+static int dm9k_init_dev(struct eth_device *edev)
+{
+	struct dm9k *priv = (struct dm9k *)edev->priv;
+
+	miidev_restart_aneg(&priv->miidev);
+	return 0;
+}
+
+static int dm9000_probe(struct device_d *dev)
+{
+	unsigned io_mode;
+	struct eth_device *edev;
+	struct dm9k *priv;
+	struct dm9000_platform_data *pdata;
+
+	if (!dev->platform_data) {
+		pr_err("DM9k: no platform_data\n");
+		return -ENODEV;
+	}
+
+	if (dev->num_resources < 2) {
+		pr_err("DM9k: need 2 resources base and data");
+		return -ENODEV;
+	}
+
+	edev = xzalloc(sizeof(struct eth_device) + sizeof(struct dm9k));
+	dev->type_data = edev;
+	edev->priv = (struct dm9k *)(edev + 1);
+
+	pdata = dev->platform_data;
+
+	priv = edev->priv;
+
+	priv->buswidth = dev->resource[0].flags & IORESOURCE_MEM_TYPE_MASK;
+	priv->iodata = dev_request_mem_region(dev, 1);
+	priv->iobase = dev_request_mem_region(dev, 0);
+	priv->srom = pdata->srom;
+
+	edev->init = dm9k_init_dev;
+	edev->open = dm9k_eth_open;
+	edev->send = dm9k_eth_send;
+	edev->recv = dm9k_eth_rx;
+	edev->halt = dm9k_eth_halt;
+	edev->set_ethaddr = dm9k_set_ethaddr;
+	edev->get_ethaddr = dm9k_get_ethaddr;
+	edev->parent = dev;
+
+	/* RESET device */
+	dm9k_reset(priv);
+	if(dm9k_check_id(priv))
+		return -ENODEV;
+
+	io_mode = dm9k_ior(priv, DM9K_ISR) >> 6;
+	switch (io_mode) {
+	case 0:
+		pr_debug("DM9k: 16 bit data bus\n");
+		if (priv->buswidth != IORESOURCE_MEM_16BIT)
+			pr_err("DM9k: Wrong databus width defined at compile time\n");
+		break;
+	case 1:
+		pr_debug("DM9k: 32 bit data bus\n");
+		if (priv->buswidth != IORESOURCE_MEM_32BIT)
+			pr_err("DM9k: Wrong databus width defined at compile time\n");
+		break;
+	case 2:
+		pr_debug("DM9k: 8 bit data bus\n");
+		if (priv->buswidth != IORESOURCE_MEM_32BIT)
+			pr_err("DM9k: Wrong databus width defined at compile time\n");
+		break;
+	default:
+		pr_info("DM9K: Unknown data width\n");
+	}
+
+	dm9k_enable(priv);
+
+	priv->miidev.read = dm9k_phy_read;
+	priv->miidev.write = dm9k_phy_write;
+	priv->miidev.address = 0;
+	priv->miidev.flags = 0;
+	priv->miidev.edev = edev;
+	priv->miidev.parent = dev;
+
+	mii_register(&priv->miidev);
+	eth_register(edev);
+
+	return 0;
+}
+
+static struct driver_d dm9000_driver = {
+	.name  = "dm9000",
+	.probe = dm9000_probe,
+};
+
+static int dm9000_init(void)
+{
+	register_driver(&dm9000_driver);
+	return 0;
+}
+
+device_initcall(dm9000_init);
-- 
1.7.7.3


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH 2/2] Remove the obsolet driver for the DM9000E ethernet device
  2011-12-12  9:27 [PATCH] Add support for the more recent Davicom DM9000A and DM9000B Juergen Beisert
  2011-12-12  9:27 ` [PATCH 1/2] Add support for more recent Davicom DM9k devices Juergen Beisert
@ 2011-12-12  9:27 ` Juergen Beisert
  1 sibling, 0 replies; 4+ messages in thread
From: Juergen Beisert @ 2011-12-12  9:27 UTC (permalink / raw)
  To: barebox

Suppot for the old DM9000E device is now part of the new dm9k.c driver.

Signed-off-by: Juergen Beisert <jbe@pengutronix.de>
---
 drivers/net/Kconfig  |    5 -
 drivers/net/Makefile |    1 -
 drivers/net/dm9000.c |  564 --------------------------------------------------
 3 files changed, 0 insertions(+), 570 deletions(-)
 delete mode 100644 drivers/net/dm9000.c

diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 6c697a9..b236d17 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -46,11 +46,6 @@ config DRIVER_NET_SMC91111
 	  This option enables support for the SMSC LAN91C111
 	  ethernet chip.
 
-config DRIVER_NET_DM9000
-	bool "Davicom dm9000 ethernet driver"
-	depends on HAS_DM9000
-	select MIIDEV
-
 config DRIVER_NET_DM9K
 	bool "Davicom dm9k[E|A|B] ethernet driver"
 	depends on HAS_DM9000
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index d3bc7b0..a84d3dc 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -1,7 +1,6 @@
 obj-$(CONFIG_DRIVER_NET_CS8900)		+= cs8900.o
 obj-$(CONFIG_DRIVER_NET_SMC911X)	+= smc911x.o
 obj-$(CONFIG_DRIVER_NET_SMC91111)	+= smc91111.o
-obj-$(CONFIG_DRIVER_NET_DM9000)		+= dm9000.o
 obj-$(CONFIG_DRIVER_NET_DM9K)		+= dm9k.o
 obj-$(CONFIG_DRIVER_NET_NETX)		+= netx_eth.o
 obj-$(CONFIG_DRIVER_NET_AT91_ETHER)	+= at91_ether.o
diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c
deleted file mode 100644
index f327781..0000000
--- a/drivers/net/dm9000.c
+++ /dev/null
@@ -1,564 +0,0 @@
-/*
- *	dm9000.c
- *
- *	A Davicom DM9000 ISA NIC fast Ethernet driver for Linux.
- *	Copyright (C) 1997  Sten Wang
- *
- *	This program is free software; you can redistribute it and/or
- *	modify it under the terms of the GNU General Public License
- *	as published by the Free Software Foundation; either version 2
- *	of the License, or (at your option) any later version.
- *
- *	This program is distributed in the hope that it will be useful,
- *	but WITHOUT ANY WARRANTY; without even the implied warranty of
- *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *	GNU General Public License for more details.
- *
- * (C)Copyright 1997-1998 DAVICOM Semiconductor,Inc. All Rights Reserved.
- *
- * V0.11	06/20/2001	REG_0A bit3=1, default enable BP with DA match
- *		06/22/2001 	Support DM9801 progrmming
- *	 	 		E3: R25 = ((R24 + NF) & 0x00ff) | 0xf000
- *		 		E4: R25 = ((R24 + NF) & 0x00ff) | 0xc200
- *				R17 = (R17 & 0xfff0) | NF + 3
- *		 		E5: R25 = ((R24 + NF - 3) & 0x00ff) | 0xc200
- *     				R17 = (R17 & 0xfff0) | NF
- *
- * v1.00			modify by simon 2001.9.5
- *				change for kernel 2.4.x
- *
- *  v1.1	11/09/2001      fix force mode bug
- *
- *  v1.2	03/18/2003	Weilun Huang <weilun_huang@davicom.com.tw>:
- *				Fixed phy reset.
- *				Added tx/rx 32 bit mode.
- *				Cleaned up for kernel merge.
- *
- *
- *
- *		12/15/2003      Initial port to barebox by Sascha Hauer
- *				<saschahauer@web.de>
- *
- * ... see commit logs
- */
-
-#include <common.h>
-#include <command.h>
-#include <driver.h>
-#include <clock.h>
-#include <miidev.h>
-#include <malloc.h>
-#include <net.h>
-#include <init.h>
-#include <io.h>
-#include <xfuncs.h>
-#include <dm9000.h>
-#include <errno.h>
-
-#define DM9000_ID		0x90000A46
-#define DM9000_PKT_MAX		1536	/* Received packet max size */
-#define DM9000_PKT_RDY		0x01	/* Packet ready to receive */
-
-#define DM9000_NCR             0x00
-#define DM9000_NSR             0x01
-#define DM9000_TCR             0x02
-#define DM9000_TSR1            0x03
-#define DM9000_TSR2            0x04
-#define DM9000_RCR             0x05
-#define DM9000_RSR             0x06
-#define DM9000_ROCR            0x07
-#define DM9000_BPTR            0x08
-#define DM9000_FCTR            0x09
-#define DM9000_FCR             0x0A
-#define DM9000_EPCR            0x0B
-#define DM9000_EPAR            0x0C
-#define DM9000_EPDRL           0x0D
-#define DM9000_EPDRH           0x0E
-#define DM9000_WCR             0x0F
-
-#define DM9000_PAR             0x10
-#define DM9000_MAR             0x16
-
-#define DM9000_GPCR            0x1e
-#define DM9000_GPR             0x1f
-#define DM9000_TRPAL           0x22
-#define DM9000_TRPAH           0x23
-#define DM9000_RWPAL           0x24
-#define DM9000_RWPAH           0x25
-
-#define DM9000_VIDL            0x28
-#define DM9000_VIDH            0x29
-#define DM9000_PIDL            0x2A
-#define DM9000_PIDH            0x2B
-
-#define DM9000_CHIPR           0x2C
-#define DM9000_SMCR            0x2F
-
-#define DM9000_PHY		0x40	/* PHY address 0x01 */
-
-#define DM9000_MRCMDX          0xF0
-#define DM9000_MRCMD           0xF2
-#define DM9000_MRRL            0xF4
-#define DM9000_MRRH            0xF5
-#define DM9000_MWCMDX			0xF6
-#define DM9000_MWCMD           0xF8
-#define DM9000_MWRL            0xFA
-#define DM9000_MWRH            0xFB
-#define DM9000_TXPLL           0xFC
-#define DM9000_TXPLH           0xFD
-#define DM9000_ISR             0xFE
-#define DM9000_IMR             0xFF
-
-#define NCR_EXT_PHY		(1<<7)
-#define NCR_WAKEEN		(1<<6)
-#define NCR_FCOL		(1<<4)
-#define NCR_FDX			(1<<3)
-#define NCR_LBK			(3<<1)
-#define NCR_RST			(1<<0)
-
-#define NSR_SPEED		(1<<7)
-#define NSR_LINKST		(1<<6)
-#define NSR_WAKEST		(1<<5)
-#define NSR_TX2END		(1<<3)
-#define NSR_TX1END		(1<<2)
-#define NSR_RXOV		(1<<1)
-
-#define TCR_TJDIS		(1<<6)
-#define TCR_EXCECM		(1<<5)
-#define TCR_PAD_DIS2		(1<<4)
-#define TCR_CRC_DIS2		(1<<3)
-#define TCR_PAD_DIS1		(1<<2)
-#define TCR_CRC_DIS1		(1<<1)
-#define TCR_TXREQ		(1<<0)
-
-#define TSR_TJTO		(1<<7)
-#define TSR_LC			(1<<6)
-#define TSR_NC			(1<<5)
-#define TSR_LCOL		(1<<4)
-#define TSR_COL			(1<<3)
-#define TSR_EC			(1<<2)
-
-#define RCR_WTDIS		(1<<6)
-#define RCR_DIS_LONG		(1<<5)
-#define RCR_DIS_CRC		(1<<4)
-#define RCR_ALL			(1<<3)
-#define RCR_RUNT		(1<<2)
-#define RCR_PRMSC		(1<<1)
-#define RCR_RXEN		(1<<0)
-
-#define RSR_RF			(1<<7)
-#define RSR_MF			(1<<6)
-#define RSR_LCS			(1<<5)
-#define RSR_RWTO		(1<<4)
-#define RSR_PLE			(1<<3)
-#define RSR_AE			(1<<2)
-#define RSR_CE			(1<<1)
-#define RSR_FOE			(1<<0)
-
-#define FCTR_HWOT(ot)	(( ot & 0xf ) << 4 )
-#define FCTR_LWOT(ot)	( ot & 0xf )
-
-#define IMR_PAR			(1<<7)
-#define IMR_ROOM		(1<<3)
-#define IMR_ROM			(1<<2)
-#define IMR_PTM			(1<<1)
-#define IMR_PRM			(1<<0)
-
-struct dm9000_priv {
-	void __iomem *iobase;
-	void __iomem *iodata;
-	struct mii_device miidev;
-	int buswidth;
-	int srom;
-};
-
-#ifdef CONFIG_DM9000_DEBUG
-static void
-dump_regs(void)
-{
-	debug("\n");
-	debug("NCR   (0x00): %02x\n", DM9000_ior(0));
-	debug("NSR   (0x01): %02x\n", DM9000_ior(1));
-	debug("TCR   (0x02): %02x\n", DM9000_ior(2));
-	debug("TSRI  (0x03): %02x\n", DM9000_ior(3));
-	debug("TSRII (0x04): %02x\n", DM9000_ior(4));
-	debug("RCR   (0x05): %02x\n", DM9000_ior(5));
-	debug("RSR   (0x06): %02x\n", DM9000_ior(6));
-	debug("ISR   (0xFE): %02x\n", DM9000_ior(ISR));
-	debug("\n");
-}
-#endif
-
-static u8 DM9000_ior(struct dm9000_priv *priv, int reg)
-{
-	writeb(reg, priv->iobase);
-	return readb(priv->iodata);
-}
-
-static void DM9000_iow(struct dm9000_priv *priv, int reg, u8 value)
-{
-	writeb(reg, priv->iobase);
-	writeb(value, priv->iodata);
-}
-
-static int dm9000_phy_read(struct mii_device *mdev, int addr, int reg)
-{
-	int val;
-	struct eth_device *edev = mdev->edev;
-	struct dm9000_priv *priv = edev->priv;
-
-	/* Fill the phyxcer register into REG_0C */
-	DM9000_iow(priv, DM9000_EPAR, DM9000_PHY | reg);
-	DM9000_iow(priv, DM9000_EPCR, 0xc);	/* Issue phyxcer read command */
-	udelay(100);			/* Wait read complete */
-	DM9000_iow(priv, DM9000_EPCR, 0x0);	/* Clear phyxcer read command */
-	val = (DM9000_ior(priv, DM9000_EPDRH) << 8) | DM9000_ior(priv, DM9000_EPDRL);
-
-	/* The read data keeps on REG_0D & REG_0E */
-	debug("phy_read(%d): %d\n", reg, val);
-	return val;
-}
-
-static int dm9000_phy_write(struct mii_device *mdev, int addr, int reg, int val)
-{
-	struct eth_device *edev = mdev->edev;
-	struct dm9000_priv *priv = edev->priv;
-
-	/* Fill the phyxcer register into REG_0C */
-	DM9000_iow(priv, DM9000_EPAR, DM9000_PHY | reg);
-
-	/* Fill the written data into REG_0D & REG_0E */
-	DM9000_iow(priv, DM9000_EPDRL, (val & 0xff));
-	DM9000_iow(priv, DM9000_EPDRH, ((val >> 8) & 0xff));
-	DM9000_iow(priv, DM9000_EPCR, 0xa);	/* Issue phyxcer write command */
-	udelay(500);			/* Wait write complete */
-	DM9000_iow(priv, DM9000_EPCR, 0x0);	/* Clear phyxcer write command */
-
-	debug("phy_write(reg:%d, value:%d)\n", reg, value);
-
-	return 0;
-}
-
-static int dm9000_check_id(struct dm9000_priv *priv)
-{
-	u32 id_val;
-	id_val = DM9000_ior(priv, DM9000_VIDL);
-	id_val |= DM9000_ior(priv, DM9000_VIDH) << 8;
-	id_val |= DM9000_ior(priv, DM9000_PIDL) << 16;
-	id_val |= DM9000_ior(priv, DM9000_PIDH) << 24;
-	if (id_val == DM9000_ID) {
-		printf("dm9000 i/o: 0x%p, id: 0x%x \n", priv->iobase,
-		       id_val);
-		return 0;
-	} else {
-		printf("dm9000 not found at 0x%p id: 0x%08x\n",
-		       priv->iobase, id_val);
-		return -1;
-	}
-}
-
-static void dm9000_reset(struct dm9000_priv *priv)
-{
-	debug("resetting\n");
-	DM9000_iow(priv, DM9000_NCR, NCR_RST);
-	udelay(1000);		/* delay 1ms */
-}
-
-static int dm9000_eth_open(struct eth_device *edev)
-{
-	struct dm9000_priv *priv = (struct dm9000_priv *)edev->priv;
-
-	miidev_wait_aneg(&priv->miidev);
-	miidev_print_status(&priv->miidev);
-	return 0;
-}
-
-static int dm9000_eth_send (struct eth_device *edev,
-		void *packet, int length)
-{
-	struct dm9000_priv *priv = (struct dm9000_priv *)edev->priv;
-	char *data_ptr;
-	u32 tmplen, i;
-	uint64_t tmo;
-
-	debug("eth_send: length: %d\n", length);
-
-	for (i = 0; i < length; i++) {
-		if (i % 8 == 0)
-			debug("\nSend: 02x: ", i);
-		debug("%02x ", ((unsigned char *) packet)[i]);
-	} debug("\n");
-
-	/* Move data to DM9000 TX RAM */
-	data_ptr = (char *) packet;
-	writeb(DM9000_MWCMD, priv->iobase);
-
-	switch (priv->buswidth) {
-	case IORESOURCE_MEM_8BIT:
-		for (i = 0; i < length; i++)
-			writeb(data_ptr[i] & 0xff, priv->iodata);
-		break;
-	case IORESOURCE_MEM_16BIT:
-		tmplen = (length + 1) / 2;
-		for (i = 0; i < tmplen; i++)
-			writew(((u16 *)data_ptr)[i], priv->iodata);
-		break;
-	case IORESOURCE_MEM_32BIT:
-		tmplen = (length + 3) / 4;
-		for (i = 0; i < tmplen; i++)
-			writel(((u32 *) data_ptr)[i], priv->iodata);
-		break;
-	default:
-		/* dm9000_probe makes sure this cannot happen */
-		return -EINVAL;
-	}
-
-	/* Set TX length to DM9000 */
-	DM9000_iow(priv, DM9000_TXPLL, length & 0xff);
-	DM9000_iow(priv, DM9000_TXPLH, (length >> 8) & 0xff);
-
-	/* Issue TX polling command */
-	DM9000_iow(priv, DM9000_TCR, TCR_TXREQ);	/* Cleared after TX complete */
-
-	/* wait for end of transmission */
-	tmo = get_time_ns();
-	while (DM9000_ior(priv, DM9000_TCR) & TCR_TXREQ) {
-		if (is_timeout(tmo, 5 * SECOND)) {
-			printf("transmission timeout\n");
-			break;
-		}
-	}
-	debug("transmit done\n\n");
-	return 0;
-}
-
-static void dm9000_eth_halt (struct eth_device *edev)
-{
-	debug("eth_halt\n");
-#if 0
-	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 */
-#endif
-}
-
-static int dm9000_eth_rx (struct eth_device *edev)
-{
-	struct dm9000_priv *priv = (struct dm9000_priv *)edev->priv;
-	u8 rxbyte, *rdptr = (u8 *) NetRxPackets[0];
-	u16 RxStatus, RxLen = 0;
-	u32 tmplen, i;
-	u32 tmpdata;
-
-	/* Check packet ready or not */
-	DM9000_ior(priv, DM9000_MRCMDX);	/* Dummy read */
-	rxbyte = readb(priv->iodata);	/* Got most updated data */
-	if (rxbyte == 0)
-		return 0;
-
-	/* Status check: this byte must be 0 or 1 */
-	if (rxbyte > 1) {
-		DM9000_iow(priv, DM9000_RCR, 0x00);	/* Stop Device */
-		DM9000_iow(priv, DM9000_ISR, 0x80);	/* Stop INT request */
-		debug("rx status check: %d\n", rxbyte);
-	}
-	debug("receiving packet\n");
-
-	/* A packet ready now  & Get status/length */
-	writeb(DM9000_MRCMD, priv->iobase);
-
-	/* Move data from DM9000 */
-	/* Read received packet from RX SRAM */
-	switch (priv->buswidth) {
-	case IORESOURCE_MEM_8BIT:
-		RxStatus = readb(priv->iodata) + (readb(priv->iodata) << 8);
-		RxLen = readb(priv->iodata) + (readb(priv->iodata) << 8);
-		for (i = 0; i < RxLen; i++)
-			rdptr[i] = readb(priv->iodata);
-		break;
-	case IORESOURCE_MEM_16BIT:
-		RxStatus = readw(priv->iodata);
-		RxLen = readw(priv->iodata);
-		tmplen = (RxLen + 1) / 2;
-		for (i = 0; i < tmplen; i++)
-			((u16 *) rdptr)[i] = readw(priv->iodata);
-		break;
-	case IORESOURCE_MEM_32BIT:
-		tmpdata = readl(priv->iodata);
-		RxStatus = tmpdata;
-		RxLen = tmpdata >> 16;
-		tmplen = (RxLen + 3) / 4;
-		for (i = 0; i < tmplen; i++)
-			((u32 *) rdptr)[i] = readl(priv->iodata);
-		break;
-	default:
-		/* dm9000_probe makes sure this cannot happen */
-		return -EINVAL;
-	}
-
-	if ((RxStatus & 0xbf00) || (RxLen < 0x40)
-	    || (RxLen > DM9000_PKT_MAX)) {
-		if (RxStatus & 0x100) {
-			printf("rx fifo error\n");
-		}
-		if (RxStatus & 0x200) {
-			printf("rx crc error\n");
-		}
-		if (RxStatus & 0x8000) {
-			printf("rx length error\n");
-		}
-		if (RxLen > DM9000_PKT_MAX) {
-			printf("rx length too big\n");
-			dm9000_reset(priv);
-		}
-	} else {
-
-		/* Pass to upper layer */
-		debug("passing packet to upper layer\n");
-		net_receive(NetRxPackets[0], RxLen);
-		return RxLen;
-	}
-	return 0;
-}
-
-static u16 read_srom_word(struct dm9000_priv *priv, int offset)
-{
-	DM9000_iow(priv, DM9000_EPAR, offset);
-	DM9000_iow(priv, DM9000_EPCR, 0x4);
-	udelay(200);
-	DM9000_iow(priv, DM9000_EPCR, 0x0);
-	return (DM9000_ior(priv, DM9000_EPDRL) + (DM9000_ior(priv, DM9000_EPDRH) << 8));
-}
-
-static int dm9000_get_ethaddr(struct eth_device *edev, unsigned char *adr)
-{
-	struct dm9000_priv *priv = (struct dm9000_priv *)edev->priv;
-	int i, oft;
-
-	if (priv->srom) {
-		for (i = 0; i < 3; i++)
-			((u16 *) adr)[i] = read_srom_word(priv, i);
-	} else {
-		for (i = 0, oft = 0x10; i < 6; i++, oft++)
-			adr[i] = DM9000_ior(priv, oft);
-	}
-
-	return 0;
-}
-
-static int dm9000_set_ethaddr(struct eth_device *edev, unsigned char *adr)
-{
-	struct dm9000_priv *priv = (struct dm9000_priv *)edev->priv;
-	int i, oft;
-
-	debug("%s\n", __FUNCTION__);
-
-	for (i = 0, oft = 0x10; i < 6; i++, oft++)
-		DM9000_iow(priv, oft, adr[i]);
-	for (i = 0, oft = 0x16; i < 8; i++, oft++)
-		DM9000_iow(priv, oft, 0xff);
-
-#if 0
-	for (i = 0; i < 5; i++)
-		printf ("%02x:", adr[i]);
-	printf ("%02x\n", adr[5]);
-#endif
-	return 0;
-}
-
-static int dm9000_init_dev(struct eth_device *edev)
-{
-	struct dm9000_priv *priv = (struct dm9000_priv *)edev->priv;
-
-	miidev_restart_aneg(&priv->miidev);
-	return 0;
-}
-
-static int dm9000_probe(struct device_d *dev)
-{
-	struct eth_device *edev;
-	struct dm9000_priv *priv;
-	struct dm9000_platform_data *pdata;
-
-	debug("dm9000_eth_init()\n");
-
-	edev = xzalloc(sizeof(struct eth_device) + sizeof(struct dm9000_priv));
-	dev->type_data = edev;
-	edev->priv = (struct dm9000_priv *)(edev + 1);
-
-	if (!dev->platform_data) {
-		printf("dm9000: no platform_data\n");
-		return -ENODEV;
-	}
-
-	if (dev->num_resources < 2) {
-		printf("dm9000: need 2 resources base and data");
-		return -ENODEV;
-	}
-
-	pdata = dev->platform_data;
-
-	priv = edev->priv;
-
-	priv->buswidth = dev->resource[0].flags & IORESOURCE_MEM_TYPE_MASK;
-	priv->iodata = dev_request_mem_region(dev, 1);
-	priv->iobase = dev_request_mem_region(dev, 0);
-	priv->srom = pdata->srom;
-
-	edev->init = dm9000_init_dev;
-	edev->open = dm9000_eth_open;
-	edev->send = dm9000_eth_send;
-	edev->recv = dm9000_eth_rx;
-	edev->halt = dm9000_eth_halt;
-	edev->set_ethaddr = dm9000_set_ethaddr;
-	edev->get_ethaddr = dm9000_get_ethaddr;
-	edev->parent = dev;
-
-	/* RESET device */
-	dm9000_reset(priv);
-	if(dm9000_check_id(priv))
-		return -1;
-
-	/* Program operating register */
-	DM9000_iow(priv, DM9000_NCR, 0x0);	/* only intern phy supported by now */
-	DM9000_iow(priv, DM9000_TCR, 0);	/* TX Polling clear */
-	DM9000_iow(priv, DM9000_BPTR, 0x3f);	/* Less 3Kb, 200us */
-	DM9000_iow(priv, DM9000_FCTR, FCTR_HWOT(3) | FCTR_LWOT(8));	/* Flow Control : High/Low Water */
-	DM9000_iow(priv, DM9000_FCR, 0x0);	/* SH FIXME: This looks strange! Flow Control */
-	DM9000_iow(priv, DM9000_SMCR, 0);	/* Special Mode */
-	DM9000_iow(priv, DM9000_NSR, NSR_WAKEST | NSR_TX2END | NSR_TX1END);	/* clear TX status */
-	DM9000_iow(priv, DM9000_ISR, 0x0f);	/* Clear interrupt status */
-
-	/* Activate DM9000 */
-	DM9000_iow(priv, DM9000_GPCR, 0x01);	/* Let GPIO0 output */
-	DM9000_iow(priv, DM9000_GPR, 0x00);	/* Enable PHY */
-	DM9000_iow(priv, DM9000_RCR, RCR_DIS_LONG | RCR_DIS_CRC | RCR_RXEN);	/* RX enable */
-	DM9000_iow(priv, DM9000_IMR, IMR_PAR);	/* Enable TX/RX interrupt mask */
-
-	priv->miidev.read = dm9000_phy_read;
-	priv->miidev.write = dm9000_phy_write;
-	priv->miidev.address = 0;
-	priv->miidev.flags = 0;
-	priv->miidev.edev = edev;
-	priv->miidev.parent = dev;
-
-	mii_register(&priv->miidev);
-	eth_register(edev);
-
-        return 0;
-}
-
-static struct driver_d dm9000_driver = {
-        .name  = "dm9000",
-        .probe = dm9000_probe,
-};
-
-static int dm9000_init(void)
-{
-        register_driver(&dm9000_driver);
-        return 0;
-}
-
-device_initcall(dm9000_init);
-
-- 
1.7.7.3


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH 1/2] Add support for more recent Davicom DM9k devices
  2011-12-12  9:27 ` [PATCH 1/2] Add support for more recent Davicom DM9k devices Juergen Beisert
@ 2011-12-12 10:42   ` Sascha Hauer
  0 siblings, 0 replies; 4+ messages in thread
From: Sascha Hauer @ 2011-12-12 10:42 UTC (permalink / raw)
  To: Juergen Beisert; +Cc: barebox

On Mon, Dec 12, 2011 at 10:27:36AM +0100, Juergen Beisert wrote:
> This patch adds support for the more recent DM9000A and DM9000B types, and keeps
> support for the older DM9000E device. As this patch is more or less a complete
> re-wrote of the existing driver I add a new source file instead of fixing the
> existing one. In a later patch the old driver will be removed.
> 
> Signed-off-by: Juergen Beisert <jbe@pengutronix.de>
> ---
>  drivers/net/Kconfig  |    5 +
>  drivers/net/Makefile |    1 +
>  drivers/net/dm9k.c   |  784 ++++++++++++++++++++++++++++++++++++++++++++++++++

Please completely switch to dev_dbg and friends.

> diff --git a/drivers/net/dm9k.c b/drivers/net/dm9k.c
> new file mode 100644
> index 0000000..8efaa5a
> --- /dev/null
> +++ b/drivers/net/dm9k.c
> @@ -0,0 +1,784 @@
> +/*
> + * Copyright (C) 2011 Juergen Beisert, Pengutronix
> + *
> + * Davicom DM9000(E/A/B) NIC fast Ethernet driver for Barebox
> + *
> + * In some ways inspired by code
> + *
> + *   Copyright (C) 1997  Sten Wang
> + *   1997-1998 DAVICOM Semiconductor,Inc.
> + *   2003 Weilun Huang <weilun_huang@davicom.com.tw>
> + *   2003 <saschahauer@web.de>
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation; either version 2 of
> + * the License, or (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + */
> +
> +#undef DEBUG
> +
> +#include <init.h>
> +#include <common.h>
> +#include <driver.h>
> +#include <miidev.h>
> +#include <net.h>
> +#include <io.h>
> +#include <xfuncs.h>
> +#include <dm9000.h>
> +#include <errno.h>
> +
> +#define DM9K_ID		0x90000A46
> +#define CHIPR_DM9000A	0x19
> +#define CHIPR_DM9000B	0x1A
> +
> +#define DM9K_PKT_NONE	0x00	/* no packet received (end marker) */
> +#define DM9K_PKT_RDY	0x01	/* packet ready to read */
> +#define DM9K_PKT_ERR	0x02	/* chip error */
> +#define DM9K_PKT_MAX	1536	/* packet max size */
> +
> +#define DM9K_NCR	0x00
> +# define NCR_EXT_PHY	(1 << 7)
> +# define NCR_WAKEEN	(1 << 6)
> +# define NCR_FCOL	(1 << 4)
> +# define NCR_FDX	(1 << 3)
> +# define NCR_LBK	(3 << 1)
> +# define NCR_RST	(1 << 0)
> +
> +#define DM9K_NSR	0x01
> +# define NSR_SPEED	(1 << 7)
> +# define NSR_LINKST	(1 << 6)
> +# define NSR_WAKEST	(1 << 5)
> +# define NSR_TX2END	(1 << 3)
> +# define NSR_TX1END	(1 << 2)
> +# define NSR_RXOV	(1 << 1)
> +
> +#define DM9K_TCR	0x02
> +# define TCR_TJDIS	(1 << 6)
> +# define TCR_EXCECM	(1 << 5)
> +# define TCR_PAD_DIS2	(1 << 4)
> +# define TCR_CRC_DIS2	(1 << 3)
> +# define TCR_PAD_DIS1	(1 << 2)
> +# define TCR_CRC_DIS1	(1 << 1)
> +# define TCR_TXREQ	(1 << 0)
> +
> +#define DM9K_TSR1	0x03
> +#define DM9K_TSR2	0x04
> +# define TSR_TJTO	(1 << 7)
> +# define TSR_LC		(1 << 6)
> +# define TSR_NC		(1 << 5)
> +# define TSR_LCOL	(1 << 4)
> +# define TSR_COL	(1 << 3)
> +# define TSR_EC		(1 << 2)
> +
> +#define DM9K_RCR	0x05
> +# define RCR_WTDIS	(1 << 6)
> +# define RCR_DIS_LONG	(1 << 5)
> +# define RCR_DIS_CRC	(1 << 4)
> +# define RCR_ALL	(1 << 3)
> +# define RCR_RUNT	(1 << 2)
> +# define RCR_PRMSC	(1 << 1)
> +# define RCR_RXEN	(1 << 0)
> +
> +#define DM9K_RSR	0x06
> +# define RSR_RF		(1 << 7)
> +# define RSR_MF		(1 << 6)
> +# define RSR_LCS	(1 << 5)
> +# define RSR_RWTO	(1 << 4)
> +# define RSR_PLE	(1 << 3)
> +# define RSR_AE		(1 << 2)
> +# define RSR_CE		(1 << 1)
> +# define RSR_FOE	(1 << 0)
> +# define RSR_ERR_MASK (RSR_FOE | RSR_CE | RSR_AE | RSR_PLE | RSR_RWTO | RSR_LCS | RSR_RF)
> +
> +#define DM9K_ROCR	0x07
> +#define DM9K_BPTR	0x08
> +#define DM9K_FCTR	0x09
> +#define DM9K_FCR	0x0A
> +#define DM9K_EPCR	0x0B
> +#define DM9K_EPAR	0x0C
> +#define DM9K_EPDRL	0x0D
> +#define DM9K_EPDRH	0x0E
> +#define DM9K_WCR	0x0F
> +
> +#define DM9K_PAR	0x10
> +#define DM9K_MAR	0x16
> +
> +#define DM9K_GPCR	0x1e
> +#define DM9K_GPR	0x1f
> +#define DM9K_TRPAL	0x22
> +#define DM9K_TRPAH	0x23
> +#define DM9K_RWPAL	0x24
> +#define DM9K_RWPAH	0x25
> +
> +#define DM9K_VIDL	0x28
> +#define DM9K_VIDH	0x29
> +#define DM9K_PIDL	0x2A
> +#define DM9K_PIDH	0x2B
> +
> +#define DM9K_CHIPR	0x2C
> +#define DM9K_SMCR	0x2F
> +
> +#define DM9K_PHY	0x40	/* PHY address 0x01 */
> +
> +#define DM9K_MRCMDX	0xF0
> +#define DM9K_MRCMD	0xF2
> +#define DM9K_MRRL	0xF4
> +#define DM9K_MRRH	0xF5
> +#define DM9K_MWCMDX	0xF6
> +#define DM9K_MWCMD	0xF8
> +#define DM9K_MWRL	0xFA
> +#define DM9K_MWRH	0xFB
> +#define DM9K_TXPLL	0xFC
> +#define DM9K_TXPLH	0xFD
> +
> +#define DM9K_ISR	0xFE
> +# define ISR_IOM0	(1 << 7) /* 0: 16 bit, 1: 8 bit*/
> +# define ISR_LNKCHG	(1 << 5) /* link status change */
> +# define ISR_UDRUN	(1 << 4) /* transmitt underrun */
> +# define ISR_ROO	(1 << 3) /* receive overflow counter overflow */
> +# define ISR_ROS	(1 << 2) /* receive overflow */
> +# define ISR_PT		(1 << 1) /* packet transmitted */
> +# define ISR_PR		(1 << 0) /* packet received */
> +# define ISR_CLEAR_MASK (ISR_PR | ISR_PT | ISR_ROS | ISR_ROO | ISR_UDRUN | ISR_LNKCHG)
> +
> +#define DM9K_IMR	0xFF
> +# define IMR_PAR	(1 << 7)
> +# define IMR_ROOM	(1 << 3)
> +# define IMR_ROM	(1 << 2)
> +# define IMR_PTM	(1 << 1)
> +# define IMR_PRM	(1 << 0)
> +
> +#define FCTR_HWOT(ot)	(( ot & 0xf ) << 4 )
> +#define FCTR_LWOT(ot)	( ot & 0xf )
> +
> +struct dm9k {
> +	void __iomem *iobase;
> +	void __iomem *iodata;
> +	struct mii_device miidev;
> +	int buswidth;
> +	int srom;
> +	uint8_t pckt[2048];
> +};
> +
> +/* ------------------ register access functions -------------------------- */
> +
> +static uint8_t dm9k_ior(struct dm9k *priv, int reg)
> +{
> +	writeb(reg, priv->iobase);
> +	return readb(priv->iodata);
> +}
> +
> +static void dm9k_iow(struct dm9k *priv, int reg, uint8_t value)
> +{
> +	writeb(reg, priv->iobase);
> +	writeb(value, priv->iodata);
> +}
> +
> +/* ------------------- data move functions ---------------------------- */
> +
> +static void dm9k_wd_8(void __iomem *port, const void *src, int length)
> +{
> +	const uint8_t *from = (const uint8_t *)src;
> +
> +	while (length--)
> +		writeb(*from++, port);
> +}
> +
> +static void dm9k_rd_8(void __iomem *port, void *dst, unsigned length)
> +{
> +	uint8_t *to = (uint8_t *)dst;
> +
> +	while (length--)
> +		*to++ = readb(port);
> +}
> +
> +static void dm9k_dump_8(void __iomem *port, unsigned length)
> +{
> +	while (length--)
> +		readb(port);
> +}
> +
> +static unsigned dm9k_read_packet_status_8(void __iomem *port, unsigned *status)
> +{
> +	uint16_t st, le;
> +
> +	dm9k_rd_8(port, &st, sizeof(st));
> +	dm9k_rd_8(port, &le, sizeof(le));
> +
> +	*status = st >> 8;
> +	return le;
> +}
> +
> +static void dm9k_wd_16(void __iomem *port, const void *src, int length)
> +{
> +	const uint16_t *from = (const uint16_t *)src;
> +
> +	length += 1;
> +	length /= 2;
> +	while (length--)
> +		writew(*from++, port);
> +}
> +
> +static void dm9k_rd_16(void __iomem *port, void *dst, unsigned length)
> +{
> +	uint16_t *to = (uint16_t *)dst;
> +
> +	length += 1;
> +	length >>= 1;
> +	while (length--)
> +		*to++ = readw(port);
> +}
> +
> +static void dm9k_dump_16(void __iomem *port, unsigned length)
> +{
> +	length += 1;
> +	length >>= 1;
> +	while (length--)
> +		readw(port);
> +}
> +
> +static unsigned dm9k_read_packet_status_16(void __iomem *port, unsigned *status)
> +{
> +	*status = readw(port) >> 8;
> +	return le16_to_cpu(readw(port));
> +}
> +
> +static void dm9k_wd_32(void __iomem *port, const void *src, int length)
> +{
> +	const uint32_t *from = (const uint32_t *)src;
> +
> +	length += 3;
> +	length /= 4;
> +	while (length--)
> +		writel(*from++, port);
> +}
> +
> +static void dm9k_rd_32(void __iomem *port, void *dst, unsigned length)
> +{
> +	uint32_t *to = (uint32_t *)dst;
> +
> +	length += 3;
> +	length >>= 2;
> +	while (length--)
> +		*to++ = readl(port);
> +}
> +
> +static void dm9k_dump_32(void __iomem *port, unsigned length)
> +{
> +	length += 3;
> +	length >>= 2;
> +	while (length--)
> +		readl(port);
> +}
> +
> +static unsigned dm9k_read_packet_status_32(void __iomem *port, unsigned *status)
> +{
> +	uint32_t tmp = readl(port);
> +
> +	*status = (tmp >> 8) & 0xff;
> +	return tmp >> 16;
> +}
> +
> +static unsigned dm9k_read_packet_status(int b_width, void __iomem *port, unsigned *status)
> +{
> +	unsigned rc;
> +
> +	switch (b_width) {
> +	case IORESOURCE_MEM_8BIT:
> +		rc = dm9k_read_packet_status_8(port, status);
> +		break;
> +	case IORESOURCE_MEM_16BIT:
> +		rc = dm9k_read_packet_status_16(port, status);
> +		break;
> +	case IORESOURCE_MEM_32BIT:
> +		rc = dm9k_read_packet_status_32(port, status);
> +		break;
> +	}
> +
> +	return rc;
> +}
> +
> +static void dm9k_dump(int b_width, void __iomem *port, unsigned length)
> +{
> +	switch (b_width) {
> +	case IORESOURCE_MEM_8BIT:
> +		dm9k_dump_8(port, length);
> +		break;
> +	case IORESOURCE_MEM_16BIT:
> +		dm9k_dump_16(port, length);
> +		break;
> +	case IORESOURCE_MEM_32BIT:
> +		dm9k_dump_32(port, length);
> +		break;
> +	}
> +}
> +
> +static void dm9k_rd(int b_width, void __iomem *port, void *dst, unsigned length)
> +{
> +	switch (b_width) {
> +	case IORESOURCE_MEM_8BIT:
> +		dm9k_rd_8(port, dst, length);
> +		break;
> +	case IORESOURCE_MEM_16BIT:
> +		dm9k_rd_16(port, dst, length);
> +		break;
> +	case IORESOURCE_MEM_32BIT:
> +		dm9k_rd_32(port, dst, length);
> +		break;
> +	}
> +}
> +
> +static void dm9k_wd(int b_width, void __iomem *port, const void *src, int length)
> +{
> +	switch (b_width) {
> +	case IORESOURCE_MEM_8BIT:
> +		dm9k_wd_8(port, src, length);
> +		break;
> +	case IORESOURCE_MEM_16BIT:
> +		dm9k_wd_16(port, src, length);
> +		break;
> +	case IORESOURCE_MEM_32BIT:
> +		dm9k_wd_32(port, src, length);
> +		break;
> +	}
> +}
> +
> +/* ----------------- end of data move functions -------------------------- */
> +
> +static int dm9k_phy_read(struct mii_device *mdev, int addr, int reg)
> +{
> +	unsigned val;
> +	struct eth_device *edev = mdev->edev;
> +	struct dm9k *priv = edev->priv;
> +
> +	/* Fill the phyxcer register into REG_0C */
> +	dm9k_iow(priv, DM9K_EPAR, DM9K_PHY | reg);
> +	dm9k_iow(priv, DM9K_EPCR, 0xc);	/* Issue phyxcer read command */
> +	udelay(100);			/* Wait read complete */
> +	dm9k_iow(priv, DM9K_EPCR, 0x0);	/* Clear phyxcer read command */
> +	val = dm9k_ior(priv, DM9K_EPDRH);
> +	val <<= 8;
> +	val |= dm9k_ior(priv, DM9K_EPDRL);
> +
> +	/* The read data keeps on REG_0D & REG_0E */
> +	debug("phy_read(%d): %d\n", reg, val);
> +	return val;
> +}
> +
> +static int dm9k_phy_write(struct mii_device *mdev, int addr, int reg, int val)
> +{
> +	struct eth_device *edev = mdev->edev;
> +	struct dm9k *priv = edev->priv;
> +
> +	/* Fill the phyxcer register into REG_0C */
> +	dm9k_iow(priv, DM9K_EPAR, DM9K_PHY | reg);
> +
> +	/* Fill the written data into REG_0D & REG_0E */
> +	dm9k_iow(priv, DM9K_EPDRL, val);
> +	dm9k_iow(priv, DM9K_EPDRH, val >> 8);
> +	dm9k_iow(priv, DM9K_EPCR, 0xa);	/* Issue phyxcer write command */
> +	udelay(500);			/* Wait write complete */
> +	dm9k_iow(priv, DM9K_EPCR, 0x0);	/* Clear phyxcer write command */
> +
> +	pr_debug("phy_write(reg:%d, value:%d)\n", reg, val);
> +
> +	return 0;
> +}
> +
> +static int dm9k_check_id(struct dm9k *priv)
> +{
> +	u32 id;
> +	char c;
> +
> +	id = dm9k_ior(priv, DM9K_VIDL);
> +	id |= dm9k_ior(priv, DM9K_VIDH) << 8;
> +	id |= dm9k_ior(priv, DM9K_PIDL) << 16;
> +	id |= dm9k_ior(priv, DM9K_PIDH) << 24;
> +
> +	if (id != DM9K_ID) {
> +		pr_err("dm9000 not found at 0x%p id: 0x%08x\n", priv->iobase, id);
> +		return -ENODEV;
> +	}
> +
> +	id = dm9k_ior(priv, DM9K_CHIPR);
> +	pr_debug("dm9000 revision 0x%02x\n", id);
> +
> +	switch (id) {
> +	case CHIPR_DM9000A:
> +		c = 'A';
> +		break;
> +	case CHIPR_DM9000B:
> +		c = 'B';
> +		break;
> +	default:
> +		c = 'E';
> +	}
> +	pr_info("Found DM9000%c at i/o: 0x%p\n", c, priv->iobase);
> +
> +	return 0;
> +}
> +
> +static void dm9k_enable(struct dm9k *priv)
> +{
> +	/* only intern phy supported by now */
> +	dm9k_iow(priv, DM9K_NCR, 0x00);
> +	/* TX Polling clear */
> +	dm9k_iow(priv, DM9K_TCR, 0x00);
> +	/* Less 3Kb, 200us */
> +	dm9k_iow(priv, DM9K_BPTR, 0x3f);
> +	/* Flow Control : High/Low Water */
> +	dm9k_iow(priv, DM9K_FCTR, FCTR_HWOT(3) | FCTR_LWOT(8));
> +	/* SH FIXME: This looks strange! Flow Control */
> +	dm9k_iow(priv, DM9K_FCR, 0x00);
> +	/* Special Mode */
> +	dm9k_iow(priv, DM9K_SMCR, 0x00);
> +	/* clear TX status */
> +	dm9k_iow(priv, DM9K_NSR, NSR_WAKEST | NSR_TX2END | NSR_TX1END);
> +	/* Clear interrupt status */
> +	dm9k_iow(priv, DM9K_IMR, IMR_PAR);
> +	dm9k_iow(priv, DM9K_ISR, ISR_CLEAR_MASK);
> +
> +	/* Activate DM9000 */
> +	dm9k_iow(priv, DM9K_GPCR, 0x01); /* Let GPIO0 output */
> +	dm9k_iow(priv, DM9K_GPR, 0x00);	/* Enable PHY */
> +	/* RX enable */
> +	dm9k_iow(priv, DM9K_RCR, RCR_DIS_LONG | RCR_DIS_CRC | RCR_RXEN);
> +	/* Enable TX/RX interrupt mask */
> +	dm9k_iow(priv, DM9K_IMR, IMR_PAR | IMR_PRM | IMR_PTM);
> +}
> +
> +static void dm9k_reset(struct dm9k *priv)
> +{
> +	pr_debug("%s\n", __func__);
> +	dm9k_iow(priv, DM9K_NCR, NCR_RST);
> +	udelay(1000);		/* delay 1ms */
> +}
> +
> +static int dm9k_eth_open(struct eth_device *edev)
> +{
> +	struct dm9k *priv = (struct dm9k *)edev->priv;
> +
> +	miidev_wait_aneg(&priv->miidev);
> +	miidev_print_status(&priv->miidev);
> +	return 0;
> +}
> +
> +static void dm9k_write_length(struct dm9k *priv, unsigned length)
> +{
> +	dm9k_iow(priv, DM9K_TXPLL, length);
> +	dm9k_iow(priv, DM9K_TXPLH, length >> 8);
> +}
> +
> +static int dm9k_wait_for_trans_end(struct dm9k *priv)
> +{
> +	static const uint64_t toffs = 5 * SECOND;	/* FIXME too long */

Then please make the timeout shorter.

> +	uint8_t status;
> +	uint64_t start = get_time_ns();
> +
> +	do {
> +		status = dm9k_ior(priv, DM9K_NSR);
> +		if (status & (NSR_TX1END | NSR_TX2END)) {
> +			pr_debug("transmitt done\n");

s/transmitt/transmit/

> +			return 0;
> +		}
> +		status = dm9k_ior(priv, DM9K_ISR);
> +		if (status & IMR_PTM) {
> +			/* Clear Tx bit in ISR */
> +			dm9k_iow(priv, DM9K_ISR, IMR_PTM);
> +			pr_debug("transmitt done\n");
> +			return 0;
> +		}
> +	} while (!is_timeout(start, toffs));
> +
> +	return -ETIMEDOUT;
> +}
> +
> +static int dm9k_eth_send(struct eth_device *edev, void *packet, int length)
> +{
> +	struct dm9k *priv = (struct dm9k *)edev->priv;
> +
> +	pr_debug("%s: %d bytes\n", __func__, length);
> +
> +	/* arm the Tx bit */
> +	dm9k_iow(priv, DM9K_ISR, IMR_PTM);
> +
> +	/* Prepare for TX-data */
> +	writeb(DM9K_MWCMD, priv->iobase);
> +
> +	/* Move the packet into the DM9k's TX RAM */
> +	dm9k_wd(priv->buswidth, priv->iodata, packet, length);
> +
> +	/* Set TX length of the packet */
> +	dm9k_write_length(priv, length);
> +
> +	/* Issue TX polling command */
> +	dm9k_iow(priv, DM9K_TCR, TCR_TXREQ); /* Cleared after TX complete */
> +
> +	/* wait for end of transmission */
> +	return dm9k_wait_for_trans_end(priv);
> +}
> +
> +static int dm9k_check_for_rx_packet(struct dm9k *priv)
> +{
> +	uint8_t status;
> +
> +	status = dm9k_ior(priv, DM9K_ISR);
> +	if (!(status & ISR_PR))
> +		return 0;	/* no packet */
> +
> +	pr_debug("Packet present\n");
> +	dm9k_iow(priv, DM9K_ISR, ISR_PR); /* clear PR status latched in bit 0 */
> +	return 1; /* packet present */
> +}
> +
> +static int dm9k_validate_entry(struct dm9k *priv)
> +{
> +	uint8_t p_stat;
> +	/*
> +	 * setup read pointer to current packet
> +	 * but without address increment
> +	 */
> +	dm9k_ior(priv, DM9K_MRCMDX);
> +
> +	/* read the entry's status according to the app note */
> +	p_stat = readb(priv->iodata) & 0x03;
> +	pr_debug("%s packet status %02X\n", __func__, p_stat);
> +
> +	switch (p_stat) {
> +	case DM9K_PKT_NONE: /* there is no packet (or the last in the chain) */
> +		return 0;
> +
> +	case DM9K_PKT_ERR: /* chip in invalid state. Needs a software reset */
> +		pr_debug("Confused chip.\n");
> +		dm9k_iow(priv, DM9K_RCR, 0x00);	/* Stop Device */
> +		dm9k_iow(priv, DM9K_ISR, 0x80);	/* Stop INT request */
> +		dm9k_reset(priv);
> +		dm9k_enable(priv);
> +		return 0;
> +	}
> +
> +	return 1; /* entry is valid */
> +}
> +
> +static int dm9k_eth_rx(struct eth_device *edev)
> +{
> +	struct dm9k *priv = (struct dm9k *)edev->priv;
> +	unsigned rx_stat = 0, rx_len = 0;
> +	bool p_valid;
> +
> +	if (dm9k_check_for_rx_packet(priv) == 0)
> +		return 0;	/* no data present */
> +
> +	do {
> +		if (!dm9k_validate_entry(priv))
> +			return 0;
> +
> +		/* assume this packet is valid */
> +		p_valid = true;
> +
> +		 /* read with automatic address increment now */
> +		writeb(DM9K_MRCMD, priv->iobase);
> +		rx_len = dm9k_read_packet_status(priv->buswidth, priv->iodata, &rx_stat);
> +		if (rx_len < 0x40) {
> +			pr_debug("Packet too short (%u bytes)\n", rx_len);
> +			p_valid = false;
> +		}
> +
> +		/* validate packet */
> +		if (rx_stat & RSR_ERR_MASK) {
> +			if (rx_stat & RSR_FOE)
> +				pr_warn("rx fifo overflow error\n");
> +			if (rx_stat & RSR_CE)
> +				pr_warn("rx crc error\n");
> +			if (rx_stat & RSR_AE)
> +				pr_warn("rx Alignment Error error\n");
> +			if (rx_stat & RSR_PLE)
> +				pr_warn("rx Physical Layer Error error\n");
> +			if (rx_stat & RSR_RWTO)
> +				pr_warn("rx Receive Watchdog Time Out error\n");
> +			if (rx_stat & RSR_LCS)
> +				pr_warn("rx Late Collision Seen error\n");
> +			if (rx_stat & RSR_RF)
> +				pr_warn("rx length error (runt frame)\n");
> +			p_valid = false;
> +		}
> +
> +		if (rx_len > DM9K_PKT_MAX) {
> +			pr_warn("rx length too big\n");
> +			/* discard packet */
> +			dm9k_dump(priv->buswidth, priv->iodata, rx_len);
> +			dm9k_reset(priv);
> +			dm9k_enable(priv);
> +			return 0;
> +		}
> +
> +		if (p_valid == true) {
> +			pr_debug("Receiving packet\n");
> +			dm9k_rd(priv->buswidth, priv->iodata, priv->pckt, rx_len);
> +			pr_debug("passing %u bytes packet to upper layer\n", rx_len);
> +			net_receive(priv->pckt, rx_len);
> +		} else {
> +			pr_debug("Discarding packet\n");
> +			dm9k_dump(priv->buswidth, priv->iodata, rx_len); /* discard packet */
> +		}
> +	} while (1);
> +
> +	return 0;
> +}
> +
> +
> +static void dm9k_eth_halt(struct eth_device *edev)
> +{
> +	pr_debug("eth_halt\n");
> +#if 0
> +	phy_write(0, 0x8000);	/* PHY RESET */
> +	dm9k_iow(DM9K_GPR, 0x01);	/* Power-Down PHY */
> +	dm9k_iow(DM9K_IMR, 0x80);	/* Disable all interrupt */
> +	dm9k_iow(DM9K_RCR, 0x00);	/* Disable RX */
> +#endif

You should take the chance and properly disable the chip here. You can
skip the phy_write here.

> +}
> +
> +static u16 read_srom_word(struct dm9k *priv, int offset)
> +{
> +	dm9k_iow(priv, DM9K_EPAR, offset);
> +	dm9k_iow(priv, DM9K_EPCR, 0x4);
> +	udelay(200);
> +	dm9k_iow(priv, DM9K_EPCR, 0x0);
> +	return (dm9k_ior(priv, DM9K_EPDRL) + (dm9k_ior(priv, DM9K_EPDRH) << 8));
> +}
> +
> +static int dm9k_get_ethaddr(struct eth_device *edev, unsigned char *adr)
> +{
> +	struct dm9k *priv = (struct dm9k *)edev->priv;
> +	int i, oft;
> +
> +	if (priv->srom) {
> +		for (i = 0; i < 3; i++)
> +			((u16 *) adr)[i] = read_srom_word(priv, i);
> +	} else {
> +		for (i = 0, oft = DM9K_PAR; i < 6; i++, oft++)
> +			adr[i] = dm9k_ior(priv, oft);
> +	}
> +
> +	return 0;
> +}
> +
> +static int dm9k_set_ethaddr(struct eth_device *edev, unsigned char *adr)
> +{
> +	struct dm9k *priv = (struct dm9k *)edev->priv;
> +	int i, oft;
> +
> +	for (i = 0, oft = DM9K_PAR; i < 6; i++, oft++)
> +		dm9k_iow(priv, oft, adr[i]);
> +	for (i = 0, oft = DM9K_MAR; i < 8; i++, oft++)
> +		dm9k_iow(priv, oft, 0xff);
> +
> +	return 0;
> +}
> +
> +static int dm9k_init_dev(struct eth_device *edev)
> +{
> +	struct dm9k *priv = (struct dm9k *)edev->priv;
> +
> +	miidev_restart_aneg(&priv->miidev);
> +	return 0;
> +}
> +
> +static int dm9000_probe(struct device_d *dev)
> +{
> +	unsigned io_mode;
> +	struct eth_device *edev;
> +	struct dm9k *priv;
> +	struct dm9000_platform_data *pdata;
> +
> +	if (!dev->platform_data) {
> +		pr_err("DM9k: no platform_data\n");
> +		return -ENODEV;
> +	}
> +
> +	if (dev->num_resources < 2) {
> +		pr_err("DM9k: need 2 resources base and data");
> +		return -ENODEV;
> +	}
> +
> +	edev = xzalloc(sizeof(struct eth_device) + sizeof(struct dm9k));
> +	dev->type_data = edev;
> +	edev->priv = (struct dm9k *)(edev + 1);
> +
> +	pdata = dev->platform_data;
> +
> +	priv = edev->priv;
> +
> +	priv->buswidth = dev->resource[0].flags & IORESOURCE_MEM_TYPE_MASK;
> +	priv->iodata = dev_request_mem_region(dev, 1);
> +	priv->iobase = dev_request_mem_region(dev, 0);
> +	priv->srom = pdata->srom;
> +
> +	edev->init = dm9k_init_dev;
> +	edev->open = dm9k_eth_open;
> +	edev->send = dm9k_eth_send;
> +	edev->recv = dm9k_eth_rx;
> +	edev->halt = dm9k_eth_halt;
> +	edev->set_ethaddr = dm9k_set_ethaddr;
> +	edev->get_ethaddr = dm9k_get_ethaddr;
> +	edev->parent = dev;
> +
> +	/* RESET device */
> +	dm9k_reset(priv);
> +	if(dm9k_check_id(priv))
> +		return -ENODEV;
> +
> +	io_mode = dm9k_ior(priv, DM9K_ISR) >> 6;
> +	switch (io_mode) {
> +	case 0:
> +		pr_debug("DM9k: 16 bit data bus\n");
> +		if (priv->buswidth != IORESOURCE_MEM_16BIT)
> +			pr_err("DM9k: Wrong databus width defined at compile time\n");
> +		break;
> +	case 1:
> +		pr_debug("DM9k: 32 bit data bus\n");
> +		if (priv->buswidth != IORESOURCE_MEM_32BIT)
> +			pr_err("DM9k: Wrong databus width defined at compile time\n");
> +		break;
> +	case 2:
> +		pr_debug("DM9k: 8 bit data bus\n");
> +		if (priv->buswidth != IORESOURCE_MEM_32BIT)
> +			pr_err("DM9k: Wrong databus width defined at compile time\n");
> +		break;
> +	default:
> +		pr_info("DM9K: Unknown data width\n");
> +	}
> +
> +	dm9k_enable(priv);
> +
> +	priv->miidev.read = dm9k_phy_read;
> +	priv->miidev.write = dm9k_phy_write;
> +	priv->miidev.address = 0;
> +	priv->miidev.flags = 0;
> +	priv->miidev.edev = edev;
> +	priv->miidev.parent = dev;
> +
> +	mii_register(&priv->miidev);
> +	eth_register(edev);
> +
> +	return 0;
> +}
> +
> +static struct driver_d dm9000_driver = {
> +	.name  = "dm9000",
> +	.probe = dm9000_probe,
> +};
> +
> +static int dm9000_init(void)
> +{
> +	register_driver(&dm9000_driver);
> +	return 0;
> +}
> +
> +device_initcall(dm9000_init);
> -- 
> 1.7.7.3
> 
> 
> _______________________________________________
> barebox mailing list
> barebox@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/barebox
> 

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2011-12-12 10:43 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-12-12  9:27 [PATCH] Add support for the more recent Davicom DM9000A and DM9000B Juergen Beisert
2011-12-12  9:27 ` [PATCH 1/2] Add support for more recent Davicom DM9k devices Juergen Beisert
2011-12-12 10:42   ` Sascha Hauer
2011-12-12  9:27 ` [PATCH 2/2] Remove the obsolet driver for the DM9000E ethernet device Juergen Beisert

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox