* [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; 6+ 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] 6+ 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; 6+ 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] 6+ 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; 6+ 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] 6+ 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; 6+ 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] 6+ messages in thread
* [PATCH v2] Add support for the more recent Davicom DM9000A and DM9000 @ 2011-12-12 11:21 Juergen Beisert 2011-12-12 11:21 ` [PATCH 2/2] Remove the obsolet driver for the DM9000E ethernet device Juergen Beisert 0 siblings, 1 reply; 6+ messages in thread From: Juergen Beisert @ 2011-12-12 11:21 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 and scb9328 with the DM9000E variant and Mini6410 with the DM9000A variant. This is v2 of the patch series, as the first one has forgotten to switch all users of the existing DM9000 driver to the new one. Comments are welcome. _______________________________________________ barebox mailing list barebox@lists.infradead.org http://lists.infradead.org/mailman/listinfo/barebox ^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH 2/2] Remove the obsolet driver for the DM9000E ethernet device 2011-12-12 11:21 [PATCH v2] Add support for the more recent Davicom DM9000A and DM9000 Juergen Beisert @ 2011-12-12 11:21 ` Juergen Beisert 0 siblings, 0 replies; 6+ messages in thread From: Juergen Beisert @ 2011-12-12 11:21 UTC (permalink / raw) To: barebox Support for the old DM9000E device is now part of the new dm9k.c driver. So, remove the old driver source and switch all users to the new driver. Signed-off-by: Juergen Beisert <jbe@pengutronix.de> --- arch/arm/boards/at91sam9261ek/init.c | 4 +- arch/arm/boards/pm9261/init.c | 4 +- arch/arm/configs/at91sam9261ek_defconfig | 2 +- arch/arm/configs/at91sam9g10ek_defconfig | 2 +- arch/arm/configs/mini2440_defconfig | 2 +- arch/arm/configs/pm9261_defconfig | 2 +- arch/arm/configs/scb9328_defconfig | 2 +- drivers/base/resource.c | 2 +- drivers/net/Kconfig | 5 - drivers/net/Makefile | 1 - drivers/net/dm9000.c | 564 ------------------------------ include/driver.h | 2 +- 12 files changed, 11 insertions(+), 581 deletions(-) delete mode 100644 drivers/net/dm9000.c diff --git a/arch/arm/boards/at91sam9261ek/init.c b/arch/arm/boards/at91sam9261ek/init.c index 0bef84d..0854eea 100644 --- a/arch/arm/boards/at91sam9261ek/init.c +++ b/arch/arm/boards/at91sam9261ek/init.c @@ -87,7 +87,7 @@ static void ek_add_device_nand(void) /* * DM9000 ethernet device */ -#if defined(CONFIG_DRIVER_NET_DM9000) +#if defined(CONFIG_DRIVER_NET_DM9K) static struct dm9000_platform_data dm9000_data = { .srom = 0, }; @@ -130,7 +130,7 @@ static void __init ek_add_device_dm9000(void) } #else static void __init ek_add_device_dm9000(void) {} -#endif /* CONFIG_DRIVER_NET_DM9000 */ +#endif /* CONFIG_DRIVER_NET_DM9K */ static int at91sam9261ek_mem_init(void) { diff --git a/arch/arm/boards/pm9261/init.c b/arch/arm/boards/pm9261/init.c index 2766f47..23ed44e 100644 --- a/arch/arm/boards/pm9261/init.c +++ b/arch/arm/boards/pm9261/init.c @@ -87,7 +87,7 @@ static void pm_add_device_nand(void) /* * DM9000 ethernet device */ -#if defined(CONFIG_DRIVER_NET_DM9000) +#if defined(CONFIG_DRIVER_NET_DM9K) static struct dm9000_platform_data dm9000_data = { .srom = 1, }; @@ -124,7 +124,7 @@ static void __init pm_add_device_dm9000(void) } #else static void __init ek_add_device_dm9000(void) {} -#endif /* CONFIG_DRIVER_NET_DM9000 */ +#endif /* CONFIG_DRIVER_NET_DM9K */ static int pm9261_mem_init(void) { diff --git a/arch/arm/configs/at91sam9261ek_defconfig b/arch/arm/configs/at91sam9261ek_defconfig index a4adee9..b60407f 100644 --- a/arch/arm/configs/at91sam9261ek_defconfig +++ b/arch/arm/configs/at91sam9261ek_defconfig @@ -41,7 +41,7 @@ CONFIG_NET_PING=y CONFIG_NET_TFTP=y CONFIG_NET_TFTP_PUSH=y CONFIG_NET_RESOLV=y -CONFIG_DRIVER_NET_DM9000=y +CONFIG_DRIVER_NET_DM9K=y # CONFIG_SPI is not set CONFIG_MTD=y CONFIG_NAND=y diff --git a/arch/arm/configs/at91sam9g10ek_defconfig b/arch/arm/configs/at91sam9g10ek_defconfig index 9271b68..d54e42c 100644 --- a/arch/arm/configs/at91sam9g10ek_defconfig +++ b/arch/arm/configs/at91sam9g10ek_defconfig @@ -33,7 +33,7 @@ CONFIG_NET_DHCP=y CONFIG_NET_NFS=y CONFIG_NET_PING=y CONFIG_NET_TFTP=y -CONFIG_DRIVER_NET_DM9000=y +CONFIG_DRIVER_NET_DM9K=y # CONFIG_SPI is not set CONFIG_MTD=y CONFIG_NAND=y diff --git a/arch/arm/configs/mini2440_defconfig b/arch/arm/configs/mini2440_defconfig index e770871..869df6a 100644 --- a/arch/arm/configs/mini2440_defconfig +++ b/arch/arm/configs/mini2440_defconfig @@ -33,7 +33,7 @@ CONFIG_NET=y CONFIG_NET_DHCP=y CONFIG_NET_PING=y CONFIG_NET_TFTP=y -CONFIG_DRIVER_NET_DM9000=y +CONFIG_DRIVER_NET_DM9K=y # CONFIG_SPI is not set CONFIG_MCI=y CONFIG_MCI_S3C=y diff --git a/arch/arm/configs/pm9261_defconfig b/arch/arm/configs/pm9261_defconfig index 89aa033..39f401f 100644 --- a/arch/arm/configs/pm9261_defconfig +++ b/arch/arm/configs/pm9261_defconfig @@ -42,7 +42,7 @@ CONFIG_NET_PING=y CONFIG_NET_TFTP=y CONFIG_NET_TFTP_PUSH=y CONFIG_NET_RESOLV=y -CONFIG_DRIVER_NET_DM9000=y +CONFIG_DRIVER_NET_DM9K=y # CONFIG_SPI is not set CONFIG_DRIVER_CFI=y CONFIG_CFI_BUFFER_WRITE=y diff --git a/arch/arm/configs/scb9328_defconfig b/arch/arm/configs/scb9328_defconfig index 4955646..d852b26 100644 --- a/arch/arm/configs/scb9328_defconfig +++ b/arch/arm/configs/scb9328_defconfig @@ -39,7 +39,7 @@ CONFIG_NET_TFTP=y CONFIG_NET_TFTP_PUSH=y CONFIG_NET_NETCONSOLE=y CONFIG_NET_RESOLV=y -CONFIG_DRIVER_NET_DM9000=y +CONFIG_DRIVER_NET_DM9K=y CONFIG_DRIVER_CFI=y # CONFIG_DRIVER_CFI_BANK_WIDTH_4 is not set CONFIG_CFI_BUFFER_WRITE=y diff --git a/drivers/base/resource.c b/drivers/base/resource.c index 5c9c16c..d2f7a07 100644 --- a/drivers/base/resource.c +++ b/drivers/base/resource.c @@ -69,7 +69,7 @@ struct device_d *add_generic_device_res(const char* devname, int id, } EXPORT_SYMBOL(add_generic_device_res); -#ifdef CONFIG_DRIVER_NET_DM9000 +#ifdef CONFIG_DRIVER_NET_DM9K struct device_d *add_dm9000_device(int id, resource_size_t base, resource_size_t data, int flags, void *pdata) { 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); - diff --git a/include/driver.h b/include/driver.h index bbe7248..b3a7a1f 100644 --- a/include/driver.h +++ b/include/driver.h @@ -232,7 +232,7 @@ static inline struct device_d *add_ns16550_device(int id, resource_size_t start, IORESOURCE_MEM | flags, pdata); } -#ifdef CONFIG_DRIVER_NET_DM9000 +#ifdef CONFIG_DRIVER_NET_DM9K struct device_d *add_dm9000_device(int id, resource_size_t base, resource_size_t data, int flags, void *pdata); #else -- 1.7.7.3 _______________________________________________ barebox mailing list barebox@lists.infradead.org http://lists.infradead.org/mailman/listinfo/barebox ^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v3] Add support for the more recent Davicom DM9000A and DM9000 @ 2011-12-12 16:31 Juergen Beisert 2011-12-12 16:31 ` [PATCH 2/2] Remove the obsolet driver for the DM9000E ethernet device Juergen Beisert 0 siblings, 1 reply; 6+ messages in thread From: Juergen Beisert @ 2011-12-12 16:31 UTC (permalink / raw) To: barebox The current Davicom DM9000 support covers the DM9000E device only. This patch series adds support for the more recent DM9000A and DM9000B variants. The DM9000E variant is still supported. Tested on Mini2440 and scb9328 with the DM9000E variant and Mini6410 with the DM9000A variant. This is v3 of the patch series. It now uses the dev_* functions to output debug or status messages, fixes some typos, cut timeout values and disables the DM9k device on halt. Comments are welcome. _______________________________________________ barebox mailing list barebox@lists.infradead.org http://lists.infradead.org/mailman/listinfo/barebox ^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH 2/2] Remove the obsolet driver for the DM9000E ethernet device 2011-12-12 16:31 [PATCH v3] Add support for the more recent Davicom DM9000A and DM9000 Juergen Beisert @ 2011-12-12 16:31 ` Juergen Beisert 0 siblings, 0 replies; 6+ messages in thread From: Juergen Beisert @ 2011-12-12 16:31 UTC (permalink / raw) To: barebox Support for the old DM9000E device is now part of the new dm9k.c driver. So, remove the old driver source and switch all users to the new driver. Signed-off-by: Juergen Beisert <jbe@pengutronix.de> --- arch/arm/boards/at91sam9261ek/init.c | 4 +- arch/arm/boards/pm9261/init.c | 4 +- arch/arm/configs/at91sam9261ek_defconfig | 2 +- arch/arm/configs/at91sam9g10ek_defconfig | 2 +- arch/arm/configs/mini2440_defconfig | 2 +- arch/arm/configs/pm9261_defconfig | 2 +- arch/arm/configs/scb9328_defconfig | 2 +- drivers/base/resource.c | 2 +- drivers/net/Kconfig | 5 - drivers/net/Makefile | 1 - drivers/net/dm9000.c | 564 ------------------------------ include/driver.h | 2 +- 12 files changed, 11 insertions(+), 581 deletions(-) delete mode 100644 drivers/net/dm9000.c diff --git a/arch/arm/boards/at91sam9261ek/init.c b/arch/arm/boards/at91sam9261ek/init.c index 0bef84d..0854eea 100644 --- a/arch/arm/boards/at91sam9261ek/init.c +++ b/arch/arm/boards/at91sam9261ek/init.c @@ -87,7 +87,7 @@ static void ek_add_device_nand(void) /* * DM9000 ethernet device */ -#if defined(CONFIG_DRIVER_NET_DM9000) +#if defined(CONFIG_DRIVER_NET_DM9K) static struct dm9000_platform_data dm9000_data = { .srom = 0, }; @@ -130,7 +130,7 @@ static void __init ek_add_device_dm9000(void) } #else static void __init ek_add_device_dm9000(void) {} -#endif /* CONFIG_DRIVER_NET_DM9000 */ +#endif /* CONFIG_DRIVER_NET_DM9K */ static int at91sam9261ek_mem_init(void) { diff --git a/arch/arm/boards/pm9261/init.c b/arch/arm/boards/pm9261/init.c index 2766f47..23ed44e 100644 --- a/arch/arm/boards/pm9261/init.c +++ b/arch/arm/boards/pm9261/init.c @@ -87,7 +87,7 @@ static void pm_add_device_nand(void) /* * DM9000 ethernet device */ -#if defined(CONFIG_DRIVER_NET_DM9000) +#if defined(CONFIG_DRIVER_NET_DM9K) static struct dm9000_platform_data dm9000_data = { .srom = 1, }; @@ -124,7 +124,7 @@ static void __init pm_add_device_dm9000(void) } #else static void __init ek_add_device_dm9000(void) {} -#endif /* CONFIG_DRIVER_NET_DM9000 */ +#endif /* CONFIG_DRIVER_NET_DM9K */ static int pm9261_mem_init(void) { diff --git a/arch/arm/configs/at91sam9261ek_defconfig b/arch/arm/configs/at91sam9261ek_defconfig index a4adee9..b60407f 100644 --- a/arch/arm/configs/at91sam9261ek_defconfig +++ b/arch/arm/configs/at91sam9261ek_defconfig @@ -41,7 +41,7 @@ CONFIG_NET_PING=y CONFIG_NET_TFTP=y CONFIG_NET_TFTP_PUSH=y CONFIG_NET_RESOLV=y -CONFIG_DRIVER_NET_DM9000=y +CONFIG_DRIVER_NET_DM9K=y # CONFIG_SPI is not set CONFIG_MTD=y CONFIG_NAND=y diff --git a/arch/arm/configs/at91sam9g10ek_defconfig b/arch/arm/configs/at91sam9g10ek_defconfig index 9271b68..d54e42c 100644 --- a/arch/arm/configs/at91sam9g10ek_defconfig +++ b/arch/arm/configs/at91sam9g10ek_defconfig @@ -33,7 +33,7 @@ CONFIG_NET_DHCP=y CONFIG_NET_NFS=y CONFIG_NET_PING=y CONFIG_NET_TFTP=y -CONFIG_DRIVER_NET_DM9000=y +CONFIG_DRIVER_NET_DM9K=y # CONFIG_SPI is not set CONFIG_MTD=y CONFIG_NAND=y diff --git a/arch/arm/configs/mini2440_defconfig b/arch/arm/configs/mini2440_defconfig index e770871..869df6a 100644 --- a/arch/arm/configs/mini2440_defconfig +++ b/arch/arm/configs/mini2440_defconfig @@ -33,7 +33,7 @@ CONFIG_NET=y CONFIG_NET_DHCP=y CONFIG_NET_PING=y CONFIG_NET_TFTP=y -CONFIG_DRIVER_NET_DM9000=y +CONFIG_DRIVER_NET_DM9K=y # CONFIG_SPI is not set CONFIG_MCI=y CONFIG_MCI_S3C=y diff --git a/arch/arm/configs/pm9261_defconfig b/arch/arm/configs/pm9261_defconfig index 89aa033..39f401f 100644 --- a/arch/arm/configs/pm9261_defconfig +++ b/arch/arm/configs/pm9261_defconfig @@ -42,7 +42,7 @@ CONFIG_NET_PING=y CONFIG_NET_TFTP=y CONFIG_NET_TFTP_PUSH=y CONFIG_NET_RESOLV=y -CONFIG_DRIVER_NET_DM9000=y +CONFIG_DRIVER_NET_DM9K=y # CONFIG_SPI is not set CONFIG_DRIVER_CFI=y CONFIG_CFI_BUFFER_WRITE=y diff --git a/arch/arm/configs/scb9328_defconfig b/arch/arm/configs/scb9328_defconfig index 4955646..d852b26 100644 --- a/arch/arm/configs/scb9328_defconfig +++ b/arch/arm/configs/scb9328_defconfig @@ -39,7 +39,7 @@ CONFIG_NET_TFTP=y CONFIG_NET_TFTP_PUSH=y CONFIG_NET_NETCONSOLE=y CONFIG_NET_RESOLV=y -CONFIG_DRIVER_NET_DM9000=y +CONFIG_DRIVER_NET_DM9K=y CONFIG_DRIVER_CFI=y # CONFIG_DRIVER_CFI_BANK_WIDTH_4 is not set CONFIG_CFI_BUFFER_WRITE=y diff --git a/drivers/base/resource.c b/drivers/base/resource.c index 5c9c16c..d2f7a07 100644 --- a/drivers/base/resource.c +++ b/drivers/base/resource.c @@ -69,7 +69,7 @@ struct device_d *add_generic_device_res(const char* devname, int id, } EXPORT_SYMBOL(add_generic_device_res); -#ifdef CONFIG_DRIVER_NET_DM9000 +#ifdef CONFIG_DRIVER_NET_DM9K struct device_d *add_dm9000_device(int id, resource_size_t base, resource_size_t data, int flags, void *pdata) { 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); - diff --git a/include/driver.h b/include/driver.h index bbe7248..b3a7a1f 100644 --- a/include/driver.h +++ b/include/driver.h @@ -232,7 +232,7 @@ static inline struct device_d *add_ns16550_device(int id, resource_size_t start, IORESOURCE_MEM | flags, pdata); } -#ifdef CONFIG_DRIVER_NET_DM9000 +#ifdef CONFIG_DRIVER_NET_DM9K struct device_d *add_dm9000_device(int id, resource_size_t base, resource_size_t data, int flags, void *pdata); #else -- 1.7.7.3 _______________________________________________ barebox mailing list barebox@lists.infradead.org http://lists.infradead.org/mailman/listinfo/barebox ^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2011-12-12 16:31 UTC | newest] Thread overview: 6+ 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 2011-12-12 11:21 [PATCH v2] Add support for the more recent Davicom DM9000A and DM9000 Juergen Beisert 2011-12-12 11:21 ` [PATCH 2/2] Remove the obsolet driver for the DM9000E ethernet device Juergen Beisert 2011-12-12 16:31 [PATCH v3] Add support for the more recent Davicom DM9000A and DM9000 Juergen Beisert 2011-12-12 16:31 ` [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