[U-Boot] [PATCH 0/3][v3] qong: support for Dave/DENX QongEVB-LITE

These patches add support for Dave/DENX QongEVB-LITE i.MX31-based board.
Signed-off-by: Ilya Yanok yanok@emcraft.com

Added definitions for i.MX31 processor GPIO registers.
Signed-off-by: Ilya Yanok yanok@emcraft.com --- include/asm-arm/arch-mx31/mx31-regs.h | 10 ++++++++++ 1 files changed, 10 insertions(+), 0 deletions(-)
diff --git a/include/asm-arm/arch-mx31/mx31-regs.h b/include/asm-arm/arch-mx31/mx31-regs.h index e736052..3cdaa02 100644 --- a/include/asm-arm/arch-mx31/mx31-regs.h +++ b/include/asm-arm/arch-mx31/mx31-regs.h @@ -87,6 +87,16 @@ #define WDOG_BASE 0x53FDC000
/* + * GPIO + */ +#define GPIO1_BASE 0x53FCC000 +#define GPIO2_BASE 0x53FD0000 +#define GPIO3_BASE 0x53FA4000 +#define GPIO_DR 0x00000000 /* data register */ +#define GPIO_GDIR 0x00000004 /* direction register */ +#define GPIO_PSR 0x00000008 /* pad status register */ + +/* * Signal Multiplexing (IOMUX) */

On 00:59 Sun 08 Feb , Ilya Yanok wrote:
Added definitions for i.MX31 processor GPIO registers.
Signed-off-by: Ilya Yanok yanok@emcraft.com
applied to u-boot-arm
Best Regards, J.

Driver for Dave DNET ethernet controller (used on Dave/DENX QongEVB-LITE board).
Signed-off-by: Ilya Yanok yanok@emcraft.com --- drivers/net/Makefile | 2 + drivers/net/dnet.c | 396 ++++++++++++++++++++++++++++++++++++++++++++++++++ drivers/net/dnet.h | 166 +++++++++++++++++++++ include/netdev.h | 1 + 4 files changed, 565 insertions(+), 0 deletions(-) create mode 100644 drivers/net/dnet.c create mode 100644 drivers/net/dnet.h
diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 128dc11..10e3c6d 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -33,6 +33,7 @@ COBJS-$(CONFIG_BFIN_MAC) += bfin_mac.o COBJS-$(CONFIG_DRIVER_CS8900) += cs8900.o COBJS-$(CONFIG_TULIP) += dc2114x.o COBJS-$(CONFIG_DRIVER_DM9000) += dm9000x.o +COBJS-$(CONFIG_DNET) += dnet.o COBJS-$(CONFIG_E1000) += e1000.o COBJS-$(CONFIG_EEPRO100) += eepro100.o COBJS-$(CONFIG_ENC28J60) += enc28j60.o @@ -69,6 +70,7 @@ COBJS-$(CONFIG_ULI526X) += uli526x.o COBJS-$(CONFIG_VSC7385_ENET) += vsc7385.o COBJS-$(CONFIG_XILINX_EMAC) += xilinx_emac.o COBJS-$(CONFIG_XILINX_EMACLITE) += xilinx_emaclite.o +COBJS-$(CONFIG_SH_ETHER) += sh_eth.o
COBJS := $(COBJS-y) SRCS := $(COBJS:.o=.c) diff --git a/drivers/net/dnet.c b/drivers/net/dnet.c new file mode 100644 index 0000000..efac746 --- /dev/null +++ b/drivers/net/dnet.c @@ -0,0 +1,396 @@ +/* + * Dave Ethernet Controller driver + * + * Copyright (C) 2008 Dave S.r.l. <www.dave.eu> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <common.h> + +#ifndef CONFIG_DNET_AUTONEG_TIMEOUT +#define CONFIG_DNET_AUTONEG_TIMEOUT 5000000 /* default value */ +#endif + +#include <net.h> +#include <malloc.h> +#include <linux/mii.h> + +#include <miiphy.h> +#include <asm/io.h> + +#include "dnet.h" + +struct dnet_device { + struct dnet_registers *regs; + const struct device *dev; + struct eth_device netdev; + unsigned short phy_addr; +}; + +/* get struct dnet_device from given struct netdev */ +#define to_dnet(_nd) container_of(_nd, struct dnet_device, netdev) + +/* function for reading internal MAC register */ +u16 dnet_readw_mac(struct dnet_device *dnet, u16 reg) +{ + u16 data_read; + + /* issue a read */ + writel(reg, &dnet->regs->MACREG_ADDR); + + /* since a read/write op to the MAC is very slow, + * we must wait before reading the data */ + udelay(1); + + /* read data read from the MAC register */ + data_read = readl(&dnet->regs->MACREG_DATA); + + /* all done */ + return data_read; +} + +/* function for writing internal MAC register */ +void dnet_writew_mac(struct dnet_device *dnet, u16 reg, u16 val) +{ + /* load data to write */ + writel(val, &dnet->regs->MACREG_DATA); + + /* issue a write */ + writel(reg | DNET_INTERNAL_WRITE, &dnet->regs->MACREG_ADDR); + + /* since a read/write op to the MAC is very slow, + * we must wait before exiting */ + udelay(1); +} + +static void dnet_mdio_write(struct dnet_device *dnet, u8 reg, u16 value) +{ + u16 tmp; + + debug(DRIVERNAME "dnet_mdio_write %02x:%02x <- %04x\n", + dnet->phy_addr, reg, value); + + while (!(dnet_readw_mac(dnet, DNET_INTERNAL_GMII_MNG_CTL_REG) & + DNET_INTERNAL_GMII_MNG_CMD_FIN)) + ; + + /* prepare for a write operation */ + tmp = (1 << 13); + + /* only 5 bits allowed for register offset */ + reg &= 0x1f; + + /* prepare reg_value for a write */ + tmp |= (dnet->phy_addr << 8); + tmp |= reg; + + /* write data to write first */ + dnet_writew_mac(dnet, DNET_INTERNAL_GMII_MNG_DAT_REG, value); + + /* write control word */ + dnet_writew_mac(dnet, DNET_INTERNAL_GMII_MNG_CTL_REG, tmp); + + while (!(dnet_readw_mac(dnet, DNET_INTERNAL_GMII_MNG_CTL_REG) & + DNET_INTERNAL_GMII_MNG_CMD_FIN)) + ; +} + +static u16 dnet_mdio_read(struct dnet_device *dnet, u8 reg) +{ + u16 value; + + while (!(dnet_readw_mac(dnet, DNET_INTERNAL_GMII_MNG_CTL_REG) & + DNET_INTERNAL_GMII_MNG_CMD_FIN)) + ; + + /* only 5 bits allowed for register offset*/ + reg &= 0x1f; + + /* prepare reg_value for a read */ + value = (dnet->phy_addr << 8); + value |= reg; + + /* write control word */ + dnet_writew_mac(dnet, DNET_INTERNAL_GMII_MNG_CTL_REG, value); + + /* wait for end of transfer */ + while (!(dnet_readw_mac(dnet, DNET_INTERNAL_GMII_MNG_CTL_REG) & + DNET_INTERNAL_GMII_MNG_CMD_FIN)) + ; + + value = dnet_readw_mac(dnet, DNET_INTERNAL_GMII_MNG_DAT_REG); + + debug(DRIVERNAME "dnet_mdio_read %02x:%02x <- %04x\n", + dnet->phy_addr, reg, value); + + return value; +} + +static int dnet_send(struct eth_device *netdev, volatile void *packet, + int length) +{ + struct dnet_device *dnet = to_dnet(netdev); + int i, len, wrsz; + unsigned int *bufp; + unsigned int tx_cmd; + + debug(DRIVERNAME "[%s] Sending %u bytes\n", __func__, length); + + /* frame size (words) */ + len = (length + 3) >> 2; + + bufp = (unsigned int *) (((u32)packet) & 0xFFFFFFFC); + wrsz = (u32)length + 3; + wrsz += ((u32)packet) & 0x3; + wrsz >>= 2; + tx_cmd = ((((unsigned int)(packet)) & 0x03) << 16) | (u32)length; + + /* check if there is enough room for the current frame */ + if (wrsz < (DNET_FIFO_SIZE - readl(&dnet->regs->TX_FIFO_WCNT))) { + for (i = 0; i < wrsz; i++) + writel(*bufp++, &dnet->regs->TX_DATA_FIFO); + /* + * inform MAC that a packet's written and ready + * to be shipped out + */ + writel(tx_cmd, &dnet->regs->TX_LEN_FIFO); + } else { + printf(DRIVERNAME "No free space (actual %d, required %d " + "(words))\n", DNET_FIFO_SIZE - + readl(&dnet->regs->TX_FIFO_WCNT), wrsz); + } + + /* No one cares anyway */ + return 0; +} + + +static int dnet_recv(struct eth_device *netdev) +{ + struct dnet_device *dnet = to_dnet(netdev); + unsigned int *data_ptr; + int pkt_len, poll, i; + u32 cmd_word; + + debug("Waiting for pkt (polling)\n"); + poll = 50; + while ((readl(&dnet->regs->RX_FIFO_WCNT) >> 16) == 0) { + udelay(10); /* wait 10 usec */ + if (--poll == 0) + return 0; /* no pkt available */ + } + + cmd_word = readl(&dnet->regs->RX_LEN_FIFO); + pkt_len = cmd_word & 0xFFFF; + + debug("Got pkt with size %d bytes\n", pkt_len); + + if (cmd_word & 0xDF180000) + printf("%s packet receive error %x\n", __func__, cmd_word); + + data_ptr = (unsigned int *) NetRxPackets[0]; + + for (i = 0; i < (pkt_len + 3) >> 2; i++) + *data_ptr++ = readl(&dnet->regs->RX_DATA_FIFO); + + NetReceive(NetRxPackets[0], pkt_len + 5); /* ok + 5 ?? */ + + return 0; +} + +static void dnet_set_hwaddr(struct eth_device *netdev) +{ + struct dnet_device *dnet = to_dnet(netdev); + u16 tmp; + + tmp = cpu_to_be16(*((u16 *)netdev->enetaddr)); + dnet_writew_mac(dnet, DNET_INTERNAL_MAC_ADDR_0_REG, tmp); + tmp = cpu_to_be16(*((u16 *)(netdev->enetaddr + 2))); + dnet_writew_mac(dnet, DNET_INTERNAL_MAC_ADDR_1_REG, tmp); + tmp = cpu_to_be16(*((u16 *)(netdev->enetaddr + 4))); + dnet_writew_mac(dnet, DNET_INTERNAL_MAC_ADDR_2_REG, tmp); +} + +static void dnet_phy_reset(struct dnet_device *dnet) +{ + struct eth_device *netdev = &dnet->netdev; + int i; + u16 status, adv; + + adv = ADVERTISE_CSMA | ADVERTISE_ALL; + dnet_mdio_write(dnet, MII_ADVERTISE, adv); + printf("%s: Starting autonegotiation...\n", netdev->name); + dnet_mdio_write(dnet, MII_BMCR, (BMCR_ANENABLE + | BMCR_ANRESTART)); + + for (i = 0; i < CONFIG_DNET_AUTONEG_TIMEOUT / 100; i++) { + status = dnet_mdio_read(dnet, MII_BMSR); + if (status & BMSR_ANEGCOMPLETE) + break; + udelay(100); + } + + if (status & BMSR_ANEGCOMPLETE) + printf("%s: Autonegotiation complete\n", netdev->name); + else + printf("%s: Autonegotiation timed out (status=0x%04x)\n", + netdev->name, status); +} + +static int dnet_phy_init(struct dnet_device *dnet) +{ + struct eth_device *netdev = &dnet->netdev; + u16 phy_id, status, adv, lpa; + int media, speed, duplex; + int i; + u32 ctl_reg; + + /* Find a PHY */ + for (i = 0; i < 32; i++) { + dnet->phy_addr = i; + phy_id = dnet_mdio_read(dnet, MII_PHYSID1); + if (phy_id != 0xffff) { + /* ok we found it */ + printf("Found PHY at address %d PHYID (%04x:%04x)\n", + i, phy_id, + dnet_mdio_read(dnet, MII_PHYSID2)); + break; + } + } + + /* Check if the PHY is up to snuff... */ + phy_id = dnet_mdio_read(dnet, MII_PHYSID1); + if (phy_id == 0xffff) { + printf("%s: No PHY present\n", netdev->name); + return -1; + } + + status = dnet_mdio_read(dnet, MII_BMSR); + if (!(status & BMSR_LSTATUS)) { + /* Try to re-negotiate if we don't have link already. */ + dnet_phy_reset(dnet); + + for (i = 0; i < CONFIG_DNET_AUTONEG_TIMEOUT / 100; i++) { + status = dnet_mdio_read(dnet, MII_BMSR); + if (status & BMSR_LSTATUS) + break; + udelay(100); + } + } + + if (!(status & BMSR_LSTATUS)) { + printf("%s: link down (status: 0x%04x)\n", + netdev->name, status); + return -1; + } else { + adv = dnet_mdio_read(dnet, MII_ADVERTISE); + lpa = dnet_mdio_read(dnet, MII_LPA); + media = mii_nway_result(lpa & adv); + speed = (media & (ADVERTISE_100FULL | ADVERTISE_100HALF) + ? 1 : 0); + duplex = (media & ADVERTISE_FULL) ? 1 : 0; + /* 1000BaseT ethernet is not supported */ + printf("%s: link up, %sMbps %s-duplex (lpa: 0x%04x)\n", + netdev->name, + speed ? "100" : "10", + duplex ? "full" : "half", + lpa); + + ctl_reg = dnet_readw_mac(dnet, DNET_INTERNAL_RXTX_CONTROL_REG); + + if (duplex) + ctl_reg &= ~(DNET_INTERNAL_RXTX_CONTROL_ENABLEHALFDUP); + else + ctl_reg |= DNET_INTERNAL_RXTX_CONTROL_ENABLEHALFDUP; + + dnet_writew_mac(dnet, DNET_INTERNAL_RXTX_CONTROL_REG, ctl_reg); + + return 0; + } +} + +static int dnet_init(struct eth_device *netdev, bd_t *bd) +{ + struct dnet_device *dnet = to_dnet(netdev); + u32 config; + + /* + * dnet_halt should have been called at some point before now, + * so we'll assume the controller is idle. + */ + + /* set hardware address */ + dnet_set_hwaddr(netdev); + + if (dnet_phy_init(dnet) < 0) + return -1; + + /* flush rx/tx fifos */ + writel(DNET_SYS_CTL_RXFIFOFLUSH | DNET_SYS_CTL_TXFIFOFLUSH, + &dnet->regs->SYS_CTL); + udelay(1000); + writel(0, &dnet->regs->SYS_CTL); + + config = dnet_readw_mac(dnet, DNET_INTERNAL_RXTX_CONTROL_REG); + + config |= DNET_INTERNAL_RXTX_CONTROL_RXPAUSE | + DNET_INTERNAL_RXTX_CONTROL_RXBROADCAST | + DNET_INTERNAL_RXTX_CONTROL_DROPCONTROL | + DNET_INTERNAL_RXTX_CONTROL_DISCFXFCS; + + dnet_writew_mac(dnet, DNET_INTERNAL_RXTX_CONTROL_REG, config); + + /* Enable TX and RX */ + dnet_writew_mac(dnet, DNET_INTERNAL_MODE_REG, + DNET_INTERNAL_MODE_RXEN | DNET_INTERNAL_MODE_TXEN); + + return 0; +} + +static void dnet_halt(struct eth_device *netdev) +{ + struct dnet_device *dnet = to_dnet(netdev); + + /* Disable TX and RX */ + dnet_writew_mac(dnet, DNET_INTERNAL_MODE_REG, 0); +} + +int dnet_eth_initialize(int id, void *regs, unsigned int phy_addr) +{ + struct dnet_device *dnet; + struct eth_device *netdev; + unsigned int dev_capa; + + dnet = malloc(sizeof(struct dnet_device)); + if (!dnet) { + printf("Error: Failed to allocate memory for DNET%d\n", id); + return -1; + } + memset(dnet, 0, sizeof(struct dnet_device)); + + netdev = &dnet->netdev; + + dnet->regs = (struct dnet_registers *)regs; + dnet->phy_addr = phy_addr; + + sprintf(netdev->name, "dnet%d", id); + netdev->init = dnet_init; + netdev->halt = dnet_halt; + netdev->send = dnet_send; + netdev->recv = dnet_recv; + + dev_capa = readl(&dnet->regs->VERCAPS) & 0xFFFF; + debug("%s: has %smdio, %sirq, %sgigabit, %sdma \n", netdev->name, + (dev_capa & DNET_HAS_MDIO) ? "" : "no ", + (dev_capa & DNET_HAS_IRQ) ? "" : "no ", + (dev_capa & DNET_HAS_GIGABIT) ? "" : "no ", + (dev_capa & DNET_HAS_DMA) ? "" : "no "); + + eth_register(netdev); + + return 0; +} + diff --git a/drivers/net/dnet.h b/drivers/net/dnet.h new file mode 100644 index 0000000..ec88418 --- /dev/null +++ b/drivers/net/dnet.h @@ -0,0 +1,166 @@ +/* + * Dave Ethernet Controller driver + * + * Copyright (C) 2008 Dave S.r.l. <www.dave.eu> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __DRIVERS_DNET_H__ +#define __DRIVERS_DNET_H__ + +#define DRIVERNAME "dnet" + +struct dnet_registers { + /* ALL DNET FIFO REGISTERS */ + u32 RX_LEN_FIFO; + u32 RX_DATA_FIFO; + u32 TX_LEN_FIFO; + u32 TX_DATA_FIFO; + u32 pad1[0x3c]; + /* ALL DNET CONTROL/STATUS REGISTERS */ + u32 VERCAPS; + u32 INTR_SRC; + u32 INTR_ENB; + u32 RX_STATUS; + u32 TX_STATUS; + u32 RX_FRAMES_CNT; + u32 TX_FRAMES_CNT; + u32 RX_FIFO_TH; + u32 TX_FIFO_TH; + u32 SYS_CTL; + u32 PAUSE_TMR; + u32 RX_FIFO_WCNT; + u32 TX_FIFO_WCNT; + u32 pad2[0x33]; + /* ALL DNET MAC REGISTERS */ + u32 MACREG_DATA; /* Mac-Reg Data */ + u32 MACREG_ADDR; /* Mac-Reg Addr */ + u32 pad3[0x3e]; + /* ALL DNET RX STATISTICS COUNTERS */ + u32 RX_PKT_IGNR_CNT; + u32 RX_LEN_CHK_ERR_CNT; + u32 RX_LNG_FRM_CNT; + u32 RX_SHRT_FRM_CNT; + u32 RX_IPG_VIOL_CNT; + u32 RX_CRC_ERR_CNT; + u32 RX_OK_PKT_CNT; + u32 RX_CTL_FRM_CNT; + u32 RX_PAUSE_FRM_CNT; + u32 RX_MULTICAST_CNT; + u32 RX_BROADCAST_CNT; + u32 RX_VLAN_TAG_CNT; + u32 RX_PRE_SHRINK_CNT; + u32 RX_DRIB_NIB_CNT; + u32 RX_UNSUP_OPCD_CNT; + u32 RX_BYTE_CNT; + u32 pad4[0x30]; + /* DNET TX STATISTICS COUNTERS */ + u32 TX_UNICAST_CNT; + u32 TX_PAUSE_FRM_CNT; + u32 TX_MULTICAST_CNT; + u32 TX_BRDCAST_CNT; + u32 TX_VLAN_TAG_CNT; + u32 TX_BAD_FCS_CNT; + u32 TX_JUMBO_CNT; + u32 TX_BYTE_CNT; +} __attribute__((packed)); + +/* SOME INTERNAL MAC-CORE REGISTER */ +#define DNET_INTERNAL_MODE_REG 0x0 +#define DNET_INTERNAL_RXTX_CONTROL_REG 0x2 +#define DNET_INTERNAL_MAX_PKT_SIZE_REG 0x4 +#define DNET_INTERNAL_IGP_REG 0x8 +#define DNET_INTERNAL_MAC_ADDR_0_REG 0xa +#define DNET_INTERNAL_MAC_ADDR_1_REG 0xc +#define DNET_INTERNAL_MAC_ADDR_2_REG 0xe +#define DNET_INTERNAL_TX_RX_STS_REG 0x12 +#define DNET_INTERNAL_GMII_MNG_CTL_REG 0x14 +#define DNET_INTERNAL_GMII_MNG_DAT_REG 0x16 + +#define DNET_INTERNAL_GMII_MNG_CMD_FIN (1 << 14) + +#define DNET_INTERNAL_WRITE (1 << 31) + +/* MAC-CORE REGISTER FIELDS */ + +/* MAC-CORE MODE REGISTER FIELDS */ +#define DNET_INTERNAL_MODE_GBITEN (1 << 0) +#define DNET_INTERNAL_MODE_FCEN (1 << 1) +#define DNET_INTERNAL_MODE_RXEN (1 << 2) +#define DNET_INTERNAL_MODE_TXEN (1 << 3) + +/* MAC-CORE RXTX CONTROL REGISTER FIELDS */ +#define DNET_INTERNAL_RXTX_CONTROL_RXSHORTFRAME (1 << 8) +#define DNET_INTERNAL_RXTX_CONTROL_RXBROADCAST (1 << 7) +#define DNET_INTERNAL_RXTX_CONTROL_RXMULTICAST (1 << 4) +#define DNET_INTERNAL_RXTX_CONTROL_RXPAUSE (1 << 3) +#define DNET_INTERNAL_RXTX_CONTROL_DISTXFCS (1 << 2) +#define DNET_INTERNAL_RXTX_CONTROL_DISCFXFCS (1 << 1) +#define DNET_INTERNAL_RXTX_CONTROL_ENPROMISC (1 << 0) +#define DNET_INTERNAL_RXTX_CONTROL_DROPCONTROL (1 << 6) +#define DNET_INTERNAL_RXTX_CONTROL_ENABLEHALFDUP (1 << 5) + +/* SYSTEM CONTROL REGISTER FIELDS */ +#define DNET_SYS_CTL_IGNORENEXTPKT (1 << 0) +#define DNET_SYS_CTL_SENDPAUSE (1 << 2) +#define DNET_SYS_CTL_RXFIFOFLUSH (1 << 3) +#define DNET_SYS_CTL_TXFIFOFLUSH (1 << 4) + +/* TX STATUS REGISTER FIELDS */ +#define DNET_TX_STATUS_FIFO_ALMOST_EMPTY (1 << 2) +#define DNET_TX_STATUS_FIFO_ALMOST_FULL (1 << 1) + +/* INTERRUPT SOURCE REGISTER FIELDS */ +#define DNET_INTR_SRC_TX_PKTSENT (1 << 0) +#define DNET_INTR_SRC_TX_FIFOAF (1 << 1) +#define DNET_INTR_SRC_TX_FIFOAE (1 << 2) +#define DNET_INTR_SRC_TX_DISCFRM (1 << 3) +#define DNET_INTR_SRC_TX_FIFOFULL (1 << 4) +#define DNET_INTR_SRC_RX_CMDFIFOAF (1 << 8) +#define DNET_INTR_SRC_RX_CMDFIFOFF (1 << 9) +#define DNET_INTR_SRC_RX_DATAFIFOFF (1 << 10) +#define DNET_INTR_SRC_TX_SUMMARY (1 << 16) +#define DNET_INTR_SRC_RX_SUMMARY (1 << 17) +#define DNET_INTR_SRC_PHY (1 << 19) + +/* INTERRUPT ENABLE REGISTER FIELDS */ +#define DNET_INTR_ENB_TX_PKTSENT (1 << 0) +#define DNET_INTR_ENB_TX_FIFOAF (1 << 1) +#define DNET_INTR_ENB_TX_FIFOAE (1 << 2) +#define DNET_INTR_ENB_TX_DISCFRM (1 << 3) +#define DNET_INTR_ENB_TX_FIFOFULL (1 << 4) +#define DNET_INTR_ENB_RX_PKTRDY (1 << 8) +#define DNET_INTR_ENB_RX_FIFOAF (1 << 9) +#define DNET_INTR_ENB_RX_FIFOERR (1 << 10) +#define DNET_INTR_ENB_RX_ERROR (1 << 11) +#define DNET_INTR_ENB_RX_FIFOFULL (1 << 12) +#define DNET_INTR_ENB_RX_FIFOAE (1 << 13) +#define DNET_INTR_ENB_TX_SUMMARY (1 << 16) +#define DNET_INTR_ENB_RX_SUMMARY (1 << 17) +#define DNET_INTR_ENB_GLOBAL_ENABLE (1 << 18) + +/* + * Capabilities. Used by the driver to know the capabilities that + * the ethernet controller inside the FPGA have. + */ + +#define DNET_HAS_MDIO (1 << 0) +#define DNET_HAS_IRQ (1 << 1) +#define DNET_HAS_GIGABIT (1 << 2) +#define DNET_HAS_DMA (1 << 3) + +#define DNET_HAS_MII (1 << 4) /* or GMII */ +#define DNET_HAS_RMII (1 << 5) /* or RGMII */ + +#define DNET_CAPS_MASK 0xFFFF + +#define DNET_FIFO_SIZE 2048 /* 2K x 32 bit */ +#define DNET_FIFO_TX_DATA_AF_TH (DNET_FIFO_SIZE - 384) /* 384 = 1536 / 4 */ +#define DNET_FIFO_TX_DATA_AE_TH (384) + +#define DNET_FIFO_RX_CMD_AF_TH (1 << 16) /* just one frame inside the FIFO */ + +#endif diff --git a/include/netdev.h b/include/netdev.h index ce1ecbd..5c568f3 100644 --- a/include/netdev.h +++ b/include/netdev.h @@ -44,6 +44,7 @@ int cpu_eth_init(bd_t *bis); int au1x00_enet_initialize(bd_t*); int bfin_EMAC_initialize(bd_t *bis); int dc21x4x_initialize(bd_t *bis); +int dnet_eth_initialize(int id, void *regs, unsigned int phy_addr); int e1000_initialize(bd_t *bis); int eepro100_initialize(bd_t *bis); int eth_3com_initialize (bd_t * bis);

Hi Ilya,
This looks much better.
Ilya Yanok wrote:
Driver for Dave DNET ethernet controller (used on Dave/DENX QongEVB-LITE board).
Signed-off-by: Ilya Yanok yanok@emcraft.com
<snip>
drivers/net/Makefile | 2 + drivers/net/dnet.c | 396 ++++++++++++++++++++++++++++++++++++++++++++++++++ drivers/net/dnet.h | 166 +++++++++++++++++++++ include/netdev.h | 1 + 4 files changed, 565 insertions(+), 0 deletions(-) create mode 100644 drivers/net/dnet.c create mode 100644 drivers/net/dnet.h
diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 128dc11..10e3c6d 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -33,6 +33,7 @@ COBJS-$(CONFIG_BFIN_MAC) += bfin_mac.o COBJS-$(CONFIG_DRIVER_CS8900) += cs8900.o COBJS-$(CONFIG_TULIP) += dc2114x.o COBJS-$(CONFIG_DRIVER_DM9000) += dm9000x.o +COBJS-$(CONFIG_DNET) += dnet.o COBJS-$(CONFIG_E1000) += e1000.o COBJS-$(CONFIG_EEPRO100) += eepro100.o COBJS-$(CONFIG_ENC28J60) += enc28j60.o @@ -69,6 +70,7 @@ COBJS-$(CONFIG_ULI526X) += uli526x.o COBJS-$(CONFIG_VSC7385_ENET) += vsc7385.o COBJS-$(CONFIG_XILINX_EMAC) += xilinx_emac.o COBJS-$(CONFIG_XILINX_EMACLITE) += xilinx_emaclite.o +COBJS-$(CONFIG_SH_ETHER) += sh_eth.o
Why is the SH driver affected?, or is this a merge artifact?
<snip>
+struct dnet_registers {
- /* ALL DNET FIFO REGISTERS */
- u32 RX_LEN_FIFO;
- u32 RX_DATA_FIFO;
- u32 TX_LEN_FIFO;
- u32 TX_DATA_FIFO;
- u32 pad1[0x3c];
- /* ALL DNET CONTROL/STATUS REGISTERS */
- u32 VERCAPS;
- u32 INTR_SRC;
- u32 INTR_ENB;
- u32 RX_STATUS;
- u32 TX_STATUS;
- u32 RX_FRAMES_CNT;
- u32 TX_FRAMES_CNT;
- u32 RX_FIFO_TH;
- u32 TX_FIFO_TH;
- u32 SYS_CTL;
- u32 PAUSE_TMR;
- u32 RX_FIFO_WCNT;
- u32 TX_FIFO_WCNT;
- u32 pad2[0x33];
- /* ALL DNET MAC REGISTERS */
- u32 MACREG_DATA; /* Mac-Reg Data */
- u32 MACREG_ADDR; /* Mac-Reg Addr */
- u32 pad3[0x3e];
- /* ALL DNET RX STATISTICS COUNTERS */
- u32 RX_PKT_IGNR_CNT;
- u32 RX_LEN_CHK_ERR_CNT;
- u32 RX_LNG_FRM_CNT;
- u32 RX_SHRT_FRM_CNT;
- u32 RX_IPG_VIOL_CNT;
- u32 RX_CRC_ERR_CNT;
- u32 RX_OK_PKT_CNT;
- u32 RX_CTL_FRM_CNT;
- u32 RX_PAUSE_FRM_CNT;
- u32 RX_MULTICAST_CNT;
- u32 RX_BROADCAST_CNT;
- u32 RX_VLAN_TAG_CNT;
- u32 RX_PRE_SHRINK_CNT;
- u32 RX_DRIB_NIB_CNT;
- u32 RX_UNSUP_OPCD_CNT;
- u32 RX_BYTE_CNT;
- u32 pad4[0x30];
- /* DNET TX STATISTICS COUNTERS */
- u32 TX_UNICAST_CNT;
- u32 TX_PAUSE_FRM_CNT;
- u32 TX_MULTICAST_CNT;
- u32 TX_BRDCAST_CNT;
- u32 TX_VLAN_TAG_CNT;
- u32 TX_BAD_FCS_CNT;
- u32 TX_JUMBO_CNT;
- u32 TX_BYTE_CNT;
+} __attribute__((packed));
Why is this packed? All fields are 32-bit aligned already.
+/* SOME INTERNAL MAC-CORE REGISTER */ +#define DNET_INTERNAL_MODE_REG 0x0 +#define DNET_INTERNAL_RXTX_CONTROL_REG 0x2 +#define DNET_INTERNAL_MAX_PKT_SIZE_REG 0x4 +#define DNET_INTERNAL_IGP_REG 0x8 +#define DNET_INTERNAL_MAC_ADDR_0_REG 0xa +#define DNET_INTERNAL_MAC_ADDR_1_REG 0xc +#define DNET_INTERNAL_MAC_ADDR_2_REG 0xe +#define DNET_INTERNAL_TX_RX_STS_REG 0x12 +#define DNET_INTERNAL_GMII_MNG_CTL_REG 0x14 +#define DNET_INTERNAL_GMII_MNG_DAT_REG 0x16
+#define DNET_INTERNAL_GMII_MNG_CMD_FIN (1 << 14)
+#define DNET_INTERNAL_WRITE (1 << 31)
+/* MAC-CORE REGISTER FIELDS */
+/* MAC-CORE MODE REGISTER FIELDS */ +#define DNET_INTERNAL_MODE_GBITEN (1 << 0) +#define DNET_INTERNAL_MODE_FCEN (1 << 1) +#define DNET_INTERNAL_MODE_RXEN (1 << 2) +#define DNET_INTERNAL_MODE_TXEN (1 << 3)
+/* MAC-CORE RXTX CONTROL REGISTER FIELDS */ +#define DNET_INTERNAL_RXTX_CONTROL_RXSHORTFRAME (1 << 8) +#define DNET_INTERNAL_RXTX_CONTROL_RXBROADCAST (1 << 7) +#define DNET_INTERNAL_RXTX_CONTROL_RXMULTICAST (1 << 4) +#define DNET_INTERNAL_RXTX_CONTROL_RXPAUSE (1 << 3) +#define DNET_INTERNAL_RXTX_CONTROL_DISTXFCS (1 << 2) +#define DNET_INTERNAL_RXTX_CONTROL_DISCFXFCS (1 << 1) +#define DNET_INTERNAL_RXTX_CONTROL_ENPROMISC (1 << 0) +#define DNET_INTERNAL_RXTX_CONTROL_DROPCONTROL (1 << 6) +#define DNET_INTERNAL_RXTX_CONTROL_ENABLEHALFDUP (1 << 5)
+/* SYSTEM CONTROL REGISTER FIELDS */ +#define DNET_SYS_CTL_IGNORENEXTPKT (1 << 0) +#define DNET_SYS_CTL_SENDPAUSE (1 << 2) +#define DNET_SYS_CTL_RXFIFOFLUSH (1 << 3) +#define DNET_SYS_CTL_TXFIFOFLUSH (1 << 4)
+/* TX STATUS REGISTER FIELDS */ +#define DNET_TX_STATUS_FIFO_ALMOST_EMPTY (1 << 2) +#define DNET_TX_STATUS_FIFO_ALMOST_FULL (1 << 1)
+/* INTERRUPT SOURCE REGISTER FIELDS */ +#define DNET_INTR_SRC_TX_PKTSENT (1 << 0) +#define DNET_INTR_SRC_TX_FIFOAF (1 << 1) +#define DNET_INTR_SRC_TX_FIFOAE (1 << 2) +#define DNET_INTR_SRC_TX_DISCFRM (1 << 3) +#define DNET_INTR_SRC_TX_FIFOFULL (1 << 4) +#define DNET_INTR_SRC_RX_CMDFIFOAF (1 << 8) +#define DNET_INTR_SRC_RX_CMDFIFOFF (1 << 9) +#define DNET_INTR_SRC_RX_DATAFIFOFF (1 << 10) +#define DNET_INTR_SRC_TX_SUMMARY (1 << 16) +#define DNET_INTR_SRC_RX_SUMMARY (1 << 17) +#define DNET_INTR_SRC_PHY (1 << 19)
+/* INTERRUPT ENABLE REGISTER FIELDS */ +#define DNET_INTR_ENB_TX_PKTSENT (1 << 0) +#define DNET_INTR_ENB_TX_FIFOAF (1 << 1) +#define DNET_INTR_ENB_TX_FIFOAE (1 << 2) +#define DNET_INTR_ENB_TX_DISCFRM (1 << 3) +#define DNET_INTR_ENB_TX_FIFOFULL (1 << 4) +#define DNET_INTR_ENB_RX_PKTRDY (1 << 8) +#define DNET_INTR_ENB_RX_FIFOAF (1 << 9) +#define DNET_INTR_ENB_RX_FIFOERR (1 << 10) +#define DNET_INTR_ENB_RX_ERROR (1 << 11) +#define DNET_INTR_ENB_RX_FIFOFULL (1 << 12) +#define DNET_INTR_ENB_RX_FIFOAE (1 << 13) +#define DNET_INTR_ENB_TX_SUMMARY (1 << 16) +#define DNET_INTR_ENB_RX_SUMMARY (1 << 17) +#define DNET_INTR_ENB_GLOBAL_ENABLE (1 << 18)
+/*
- Capabilities. Used by the driver to know the capabilities that
- the ethernet controller inside the FPGA have.
- */
+#define DNET_HAS_MDIO (1 << 0) +#define DNET_HAS_IRQ (1 << 1) +#define DNET_HAS_GIGABIT (1 << 2) +#define DNET_HAS_DMA (1 << 3)
+#define DNET_HAS_MII (1 << 4) /* or GMII */ +#define DNET_HAS_RMII (1 << 5) /* or RGMII */
+#define DNET_CAPS_MASK 0xFFFF
+#define DNET_FIFO_SIZE 2048 /* 2K x 32 bit */ +#define DNET_FIFO_TX_DATA_AF_TH (DNET_FIFO_SIZE - 384) /* 384 = 1536 / 4 */ +#define DNET_FIFO_TX_DATA_AE_TH (384)
+#define DNET_FIFO_RX_CMD_AF_TH (1 << 16) /* just one frame inside the FIFO */
+#endif diff --git a/include/netdev.h b/include/netdev.h index ce1ecbd..5c568f3 100644 --- a/include/netdev.h +++ b/include/netdev.h @@ -44,6 +44,7 @@ int cpu_eth_init(bd_t *bis); int au1x00_enet_initialize(bd_t*); int bfin_EMAC_initialize(bd_t *bis); int dc21x4x_initialize(bd_t *bis); +int dnet_eth_initialize(int id, void *regs, unsigned int phy_addr); int e1000_initialize(bd_t *bis); int eepro100_initialize(bd_t *bis); int eth_3com_initialize (bd_t * bis);
regards, Ben

Hi Ben,
thanks for review.
Ben Warren wrote:
@@ -69,6 +70,7 @@ COBJS-$(CONFIG_ULI526X) += uli526x.o COBJS-$(CONFIG_VSC7385_ENET) += vsc7385.o COBJS-$(CONFIG_XILINX_EMAC) += xilinx_emac.o COBJS-$(CONFIG_XILINX_EMACLITE) += xilinx_emaclite.o +COBJS-$(CONFIG_SH_ETHER) += sh_eth.o
Why is the SH driver affected?, or is this a merge artifact?
Uh... Sorry. Yes, it's merge artifact.
<snip> > +struct dnet_registers { > + /* ALL DNET FIFO REGISTERS */ > + u32 RX_LEN_FIFO; > + u32 RX_DATA_FIFO; > + u32 TX_LEN_FIFO; > + u32 TX_DATA_FIFO; > + u32 pad1[0x3c]; > + /* ALL DNET CONTROL/STATUS REGISTERS */ > + u32 VERCAPS; > + u32 INTR_SRC; > + u32 INTR_ENB; > + u32 RX_STATUS; > + u32 TX_STATUS; > + u32 RX_FRAMES_CNT; > + u32 TX_FRAMES_CNT; > + u32 RX_FIFO_TH; > + u32 TX_FIFO_TH; > + u32 SYS_CTL; > + u32 PAUSE_TMR; > + u32 RX_FIFO_WCNT; > + u32 TX_FIFO_WCNT; > + u32 pad2[0x33]; > + /* ALL DNET MAC REGISTERS */ > + u32 MACREG_DATA; /* Mac-Reg Data */ > + u32 MACREG_ADDR; /* Mac-Reg Addr */ > + u32 pad3[0x3e]; > + /* ALL DNET RX STATISTICS COUNTERS */ > + u32 RX_PKT_IGNR_CNT; > + u32 RX_LEN_CHK_ERR_CNT; > + u32 RX_LNG_FRM_CNT; > + u32 RX_SHRT_FRM_CNT; > + u32 RX_IPG_VIOL_CNT; > + u32 RX_CRC_ERR_CNT; > + u32 RX_OK_PKT_CNT; > + u32 RX_CTL_FRM_CNT; > + u32 RX_PAUSE_FRM_CNT; > + u32 RX_MULTICAST_CNT; > + u32 RX_BROADCAST_CNT; > + u32 RX_VLAN_TAG_CNT; > + u32 RX_PRE_SHRINK_CNT; > + u32 RX_DRIB_NIB_CNT; > + u32 RX_UNSUP_OPCD_CNT; > + u32 RX_BYTE_CNT; > + u32 pad4[0x30]; > + /* DNET TX STATISTICS COUNTERS */ > + u32 TX_UNICAST_CNT; > + u32 TX_PAUSE_FRM_CNT; > + u32 TX_MULTICAST_CNT; > + u32 TX_BRDCAST_CNT; > + u32 TX_VLAN_TAG_CNT; > + u32 TX_BAD_FCS_CNT; > + u32 TX_JUMBO_CNT; > + u32 TX_BYTE_CNT; > +} __attribute__((packed)); > Why is this packed? All fields are 32-bit aligned already.
Generally, I prefer declaring such structures with ((packed)) regardless of if it's really do something. Just to show that it should be packed.
Regards, Ilya.

Dear Ilya,
In message 49902403.2010406@emcraft.com you wrote:
...
- u32 TX_JUMBO_CNT;
- u32 TX_BYTE_CNT;
+} __attribute__((packed));
Why is this packed? All fields are 32-bit aligned already.
Generally, I prefer declaring such structures with ((packed)) regardless of if it's really do something. Just to show that it should be packed.
Can you please verify that it works as well without the "packed", and if it does (as expected) resubmit without it?
Thanks.
Best regards,
Wolfgang Denk

Hi Wolfgang,
Wolfgang Denk wrote:
- u32 TX_JUMBO_CNT;
- u32 TX_BYTE_CNT;
+} __attribute__((packed));
Why is this packed? All fields are 32-bit aligned already.
Generally, I prefer declaring such structures with ((packed)) regardless of if it's really do something. Just to show that it should be packed.
Can you please verify that it works as well without the "packed", and if it does (as expected) resubmit without it?
Ok. It works as expected. I'll post the updated patch soon.
Regards, Ilya.

Driver for Dave DNET ethernet controller (used on Dave/DENX QongEVB-LITE board).
Signed-off-by: Ilya Yanok yanok@emcraft.com --- drivers/net/Makefile | 1 + drivers/net/dnet.c | 396 ++++++++++++++++++++++++++++++++++++++++++++++++++ drivers/net/dnet.h | 166 +++++++++++++++++++++ include/netdev.h | 1 + 4 files changed, 564 insertions(+), 0 deletions(-) create mode 100644 drivers/net/dnet.c create mode 100644 drivers/net/dnet.h
diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 128dc11..a360a50 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -33,6 +33,7 @@ COBJS-$(CONFIG_BFIN_MAC) += bfin_mac.o COBJS-$(CONFIG_DRIVER_CS8900) += cs8900.o COBJS-$(CONFIG_TULIP) += dc2114x.o COBJS-$(CONFIG_DRIVER_DM9000) += dm9000x.o +COBJS-$(CONFIG_DNET) += dnet.o COBJS-$(CONFIG_E1000) += e1000.o COBJS-$(CONFIG_EEPRO100) += eepro100.o COBJS-$(CONFIG_ENC28J60) += enc28j60.o diff --git a/drivers/net/dnet.c b/drivers/net/dnet.c new file mode 100644 index 0000000..efac746 --- /dev/null +++ b/drivers/net/dnet.c @@ -0,0 +1,396 @@ +/* + * Dave Ethernet Controller driver + * + * Copyright (C) 2008 Dave S.r.l. <www.dave.eu> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <common.h> + +#ifndef CONFIG_DNET_AUTONEG_TIMEOUT +#define CONFIG_DNET_AUTONEG_TIMEOUT 5000000 /* default value */ +#endif + +#include <net.h> +#include <malloc.h> +#include <linux/mii.h> + +#include <miiphy.h> +#include <asm/io.h> + +#include "dnet.h" + +struct dnet_device { + struct dnet_registers *regs; + const struct device *dev; + struct eth_device netdev; + unsigned short phy_addr; +}; + +/* get struct dnet_device from given struct netdev */ +#define to_dnet(_nd) container_of(_nd, struct dnet_device, netdev) + +/* function for reading internal MAC register */ +u16 dnet_readw_mac(struct dnet_device *dnet, u16 reg) +{ + u16 data_read; + + /* issue a read */ + writel(reg, &dnet->regs->MACREG_ADDR); + + /* since a read/write op to the MAC is very slow, + * we must wait before reading the data */ + udelay(1); + + /* read data read from the MAC register */ + data_read = readl(&dnet->regs->MACREG_DATA); + + /* all done */ + return data_read; +} + +/* function for writing internal MAC register */ +void dnet_writew_mac(struct dnet_device *dnet, u16 reg, u16 val) +{ + /* load data to write */ + writel(val, &dnet->regs->MACREG_DATA); + + /* issue a write */ + writel(reg | DNET_INTERNAL_WRITE, &dnet->regs->MACREG_ADDR); + + /* since a read/write op to the MAC is very slow, + * we must wait before exiting */ + udelay(1); +} + +static void dnet_mdio_write(struct dnet_device *dnet, u8 reg, u16 value) +{ + u16 tmp; + + debug(DRIVERNAME "dnet_mdio_write %02x:%02x <- %04x\n", + dnet->phy_addr, reg, value); + + while (!(dnet_readw_mac(dnet, DNET_INTERNAL_GMII_MNG_CTL_REG) & + DNET_INTERNAL_GMII_MNG_CMD_FIN)) + ; + + /* prepare for a write operation */ + tmp = (1 << 13); + + /* only 5 bits allowed for register offset */ + reg &= 0x1f; + + /* prepare reg_value for a write */ + tmp |= (dnet->phy_addr << 8); + tmp |= reg; + + /* write data to write first */ + dnet_writew_mac(dnet, DNET_INTERNAL_GMII_MNG_DAT_REG, value); + + /* write control word */ + dnet_writew_mac(dnet, DNET_INTERNAL_GMII_MNG_CTL_REG, tmp); + + while (!(dnet_readw_mac(dnet, DNET_INTERNAL_GMII_MNG_CTL_REG) & + DNET_INTERNAL_GMII_MNG_CMD_FIN)) + ; +} + +static u16 dnet_mdio_read(struct dnet_device *dnet, u8 reg) +{ + u16 value; + + while (!(dnet_readw_mac(dnet, DNET_INTERNAL_GMII_MNG_CTL_REG) & + DNET_INTERNAL_GMII_MNG_CMD_FIN)) + ; + + /* only 5 bits allowed for register offset*/ + reg &= 0x1f; + + /* prepare reg_value for a read */ + value = (dnet->phy_addr << 8); + value |= reg; + + /* write control word */ + dnet_writew_mac(dnet, DNET_INTERNAL_GMII_MNG_CTL_REG, value); + + /* wait for end of transfer */ + while (!(dnet_readw_mac(dnet, DNET_INTERNAL_GMII_MNG_CTL_REG) & + DNET_INTERNAL_GMII_MNG_CMD_FIN)) + ; + + value = dnet_readw_mac(dnet, DNET_INTERNAL_GMII_MNG_DAT_REG); + + debug(DRIVERNAME "dnet_mdio_read %02x:%02x <- %04x\n", + dnet->phy_addr, reg, value); + + return value; +} + +static int dnet_send(struct eth_device *netdev, volatile void *packet, + int length) +{ + struct dnet_device *dnet = to_dnet(netdev); + int i, len, wrsz; + unsigned int *bufp; + unsigned int tx_cmd; + + debug(DRIVERNAME "[%s] Sending %u bytes\n", __func__, length); + + /* frame size (words) */ + len = (length + 3) >> 2; + + bufp = (unsigned int *) (((u32)packet) & 0xFFFFFFFC); + wrsz = (u32)length + 3; + wrsz += ((u32)packet) & 0x3; + wrsz >>= 2; + tx_cmd = ((((unsigned int)(packet)) & 0x03) << 16) | (u32)length; + + /* check if there is enough room for the current frame */ + if (wrsz < (DNET_FIFO_SIZE - readl(&dnet->regs->TX_FIFO_WCNT))) { + for (i = 0; i < wrsz; i++) + writel(*bufp++, &dnet->regs->TX_DATA_FIFO); + /* + * inform MAC that a packet's written and ready + * to be shipped out + */ + writel(tx_cmd, &dnet->regs->TX_LEN_FIFO); + } else { + printf(DRIVERNAME "No free space (actual %d, required %d " + "(words))\n", DNET_FIFO_SIZE - + readl(&dnet->regs->TX_FIFO_WCNT), wrsz); + } + + /* No one cares anyway */ + return 0; +} + + +static int dnet_recv(struct eth_device *netdev) +{ + struct dnet_device *dnet = to_dnet(netdev); + unsigned int *data_ptr; + int pkt_len, poll, i; + u32 cmd_word; + + debug("Waiting for pkt (polling)\n"); + poll = 50; + while ((readl(&dnet->regs->RX_FIFO_WCNT) >> 16) == 0) { + udelay(10); /* wait 10 usec */ + if (--poll == 0) + return 0; /* no pkt available */ + } + + cmd_word = readl(&dnet->regs->RX_LEN_FIFO); + pkt_len = cmd_word & 0xFFFF; + + debug("Got pkt with size %d bytes\n", pkt_len); + + if (cmd_word & 0xDF180000) + printf("%s packet receive error %x\n", __func__, cmd_word); + + data_ptr = (unsigned int *) NetRxPackets[0]; + + for (i = 0; i < (pkt_len + 3) >> 2; i++) + *data_ptr++ = readl(&dnet->regs->RX_DATA_FIFO); + + NetReceive(NetRxPackets[0], pkt_len + 5); /* ok + 5 ?? */ + + return 0; +} + +static void dnet_set_hwaddr(struct eth_device *netdev) +{ + struct dnet_device *dnet = to_dnet(netdev); + u16 tmp; + + tmp = cpu_to_be16(*((u16 *)netdev->enetaddr)); + dnet_writew_mac(dnet, DNET_INTERNAL_MAC_ADDR_0_REG, tmp); + tmp = cpu_to_be16(*((u16 *)(netdev->enetaddr + 2))); + dnet_writew_mac(dnet, DNET_INTERNAL_MAC_ADDR_1_REG, tmp); + tmp = cpu_to_be16(*((u16 *)(netdev->enetaddr + 4))); + dnet_writew_mac(dnet, DNET_INTERNAL_MAC_ADDR_2_REG, tmp); +} + +static void dnet_phy_reset(struct dnet_device *dnet) +{ + struct eth_device *netdev = &dnet->netdev; + int i; + u16 status, adv; + + adv = ADVERTISE_CSMA | ADVERTISE_ALL; + dnet_mdio_write(dnet, MII_ADVERTISE, adv); + printf("%s: Starting autonegotiation...\n", netdev->name); + dnet_mdio_write(dnet, MII_BMCR, (BMCR_ANENABLE + | BMCR_ANRESTART)); + + for (i = 0; i < CONFIG_DNET_AUTONEG_TIMEOUT / 100; i++) { + status = dnet_mdio_read(dnet, MII_BMSR); + if (status & BMSR_ANEGCOMPLETE) + break; + udelay(100); + } + + if (status & BMSR_ANEGCOMPLETE) + printf("%s: Autonegotiation complete\n", netdev->name); + else + printf("%s: Autonegotiation timed out (status=0x%04x)\n", + netdev->name, status); +} + +static int dnet_phy_init(struct dnet_device *dnet) +{ + struct eth_device *netdev = &dnet->netdev; + u16 phy_id, status, adv, lpa; + int media, speed, duplex; + int i; + u32 ctl_reg; + + /* Find a PHY */ + for (i = 0; i < 32; i++) { + dnet->phy_addr = i; + phy_id = dnet_mdio_read(dnet, MII_PHYSID1); + if (phy_id != 0xffff) { + /* ok we found it */ + printf("Found PHY at address %d PHYID (%04x:%04x)\n", + i, phy_id, + dnet_mdio_read(dnet, MII_PHYSID2)); + break; + } + } + + /* Check if the PHY is up to snuff... */ + phy_id = dnet_mdio_read(dnet, MII_PHYSID1); + if (phy_id == 0xffff) { + printf("%s: No PHY present\n", netdev->name); + return -1; + } + + status = dnet_mdio_read(dnet, MII_BMSR); + if (!(status & BMSR_LSTATUS)) { + /* Try to re-negotiate if we don't have link already. */ + dnet_phy_reset(dnet); + + for (i = 0; i < CONFIG_DNET_AUTONEG_TIMEOUT / 100; i++) { + status = dnet_mdio_read(dnet, MII_BMSR); + if (status & BMSR_LSTATUS) + break; + udelay(100); + } + } + + if (!(status & BMSR_LSTATUS)) { + printf("%s: link down (status: 0x%04x)\n", + netdev->name, status); + return -1; + } else { + adv = dnet_mdio_read(dnet, MII_ADVERTISE); + lpa = dnet_mdio_read(dnet, MII_LPA); + media = mii_nway_result(lpa & adv); + speed = (media & (ADVERTISE_100FULL | ADVERTISE_100HALF) + ? 1 : 0); + duplex = (media & ADVERTISE_FULL) ? 1 : 0; + /* 1000BaseT ethernet is not supported */ + printf("%s: link up, %sMbps %s-duplex (lpa: 0x%04x)\n", + netdev->name, + speed ? "100" : "10", + duplex ? "full" : "half", + lpa); + + ctl_reg = dnet_readw_mac(dnet, DNET_INTERNAL_RXTX_CONTROL_REG); + + if (duplex) + ctl_reg &= ~(DNET_INTERNAL_RXTX_CONTROL_ENABLEHALFDUP); + else + ctl_reg |= DNET_INTERNAL_RXTX_CONTROL_ENABLEHALFDUP; + + dnet_writew_mac(dnet, DNET_INTERNAL_RXTX_CONTROL_REG, ctl_reg); + + return 0; + } +} + +static int dnet_init(struct eth_device *netdev, bd_t *bd) +{ + struct dnet_device *dnet = to_dnet(netdev); + u32 config; + + /* + * dnet_halt should have been called at some point before now, + * so we'll assume the controller is idle. + */ + + /* set hardware address */ + dnet_set_hwaddr(netdev); + + if (dnet_phy_init(dnet) < 0) + return -1; + + /* flush rx/tx fifos */ + writel(DNET_SYS_CTL_RXFIFOFLUSH | DNET_SYS_CTL_TXFIFOFLUSH, + &dnet->regs->SYS_CTL); + udelay(1000); + writel(0, &dnet->regs->SYS_CTL); + + config = dnet_readw_mac(dnet, DNET_INTERNAL_RXTX_CONTROL_REG); + + config |= DNET_INTERNAL_RXTX_CONTROL_RXPAUSE | + DNET_INTERNAL_RXTX_CONTROL_RXBROADCAST | + DNET_INTERNAL_RXTX_CONTROL_DROPCONTROL | + DNET_INTERNAL_RXTX_CONTROL_DISCFXFCS; + + dnet_writew_mac(dnet, DNET_INTERNAL_RXTX_CONTROL_REG, config); + + /* Enable TX and RX */ + dnet_writew_mac(dnet, DNET_INTERNAL_MODE_REG, + DNET_INTERNAL_MODE_RXEN | DNET_INTERNAL_MODE_TXEN); + + return 0; +} + +static void dnet_halt(struct eth_device *netdev) +{ + struct dnet_device *dnet = to_dnet(netdev); + + /* Disable TX and RX */ + dnet_writew_mac(dnet, DNET_INTERNAL_MODE_REG, 0); +} + +int dnet_eth_initialize(int id, void *regs, unsigned int phy_addr) +{ + struct dnet_device *dnet; + struct eth_device *netdev; + unsigned int dev_capa; + + dnet = malloc(sizeof(struct dnet_device)); + if (!dnet) { + printf("Error: Failed to allocate memory for DNET%d\n", id); + return -1; + } + memset(dnet, 0, sizeof(struct dnet_device)); + + netdev = &dnet->netdev; + + dnet->regs = (struct dnet_registers *)regs; + dnet->phy_addr = phy_addr; + + sprintf(netdev->name, "dnet%d", id); + netdev->init = dnet_init; + netdev->halt = dnet_halt; + netdev->send = dnet_send; + netdev->recv = dnet_recv; + + dev_capa = readl(&dnet->regs->VERCAPS) & 0xFFFF; + debug("%s: has %smdio, %sirq, %sgigabit, %sdma \n", netdev->name, + (dev_capa & DNET_HAS_MDIO) ? "" : "no ", + (dev_capa & DNET_HAS_IRQ) ? "" : "no ", + (dev_capa & DNET_HAS_GIGABIT) ? "" : "no ", + (dev_capa & DNET_HAS_DMA) ? "" : "no "); + + eth_register(netdev); + + return 0; +} + diff --git a/drivers/net/dnet.h b/drivers/net/dnet.h new file mode 100644 index 0000000..9522675 --- /dev/null +++ b/drivers/net/dnet.h @@ -0,0 +1,166 @@ +/* + * Dave Ethernet Controller driver + * + * Copyright (C) 2008 Dave S.r.l. <www.dave.eu> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __DRIVERS_DNET_H__ +#define __DRIVERS_DNET_H__ + +#define DRIVERNAME "dnet" + +struct dnet_registers { + /* ALL DNET FIFO REGISTERS */ + u32 RX_LEN_FIFO; + u32 RX_DATA_FIFO; + u32 TX_LEN_FIFO; + u32 TX_DATA_FIFO; + u32 pad1[0x3c]; + /* ALL DNET CONTROL/STATUS REGISTERS */ + u32 VERCAPS; + u32 INTR_SRC; + u32 INTR_ENB; + u32 RX_STATUS; + u32 TX_STATUS; + u32 RX_FRAMES_CNT; + u32 TX_FRAMES_CNT; + u32 RX_FIFO_TH; + u32 TX_FIFO_TH; + u32 SYS_CTL; + u32 PAUSE_TMR; + u32 RX_FIFO_WCNT; + u32 TX_FIFO_WCNT; + u32 pad2[0x33]; + /* ALL DNET MAC REGISTERS */ + u32 MACREG_DATA; /* Mac-Reg Data */ + u32 MACREG_ADDR; /* Mac-Reg Addr */ + u32 pad3[0x3e]; + /* ALL DNET RX STATISTICS COUNTERS */ + u32 RX_PKT_IGNR_CNT; + u32 RX_LEN_CHK_ERR_CNT; + u32 RX_LNG_FRM_CNT; + u32 RX_SHRT_FRM_CNT; + u32 RX_IPG_VIOL_CNT; + u32 RX_CRC_ERR_CNT; + u32 RX_OK_PKT_CNT; + u32 RX_CTL_FRM_CNT; + u32 RX_PAUSE_FRM_CNT; + u32 RX_MULTICAST_CNT; + u32 RX_BROADCAST_CNT; + u32 RX_VLAN_TAG_CNT; + u32 RX_PRE_SHRINK_CNT; + u32 RX_DRIB_NIB_CNT; + u32 RX_UNSUP_OPCD_CNT; + u32 RX_BYTE_CNT; + u32 pad4[0x30]; + /* DNET TX STATISTICS COUNTERS */ + u32 TX_UNICAST_CNT; + u32 TX_PAUSE_FRM_CNT; + u32 TX_MULTICAST_CNT; + u32 TX_BRDCAST_CNT; + u32 TX_VLAN_TAG_CNT; + u32 TX_BAD_FCS_CNT; + u32 TX_JUMBO_CNT; + u32 TX_BYTE_CNT; +} __attribute__((packed)); + +/* SOME INTERNAL MAC-CORE REGISTER */ +#define DNET_INTERNAL_MODE_REG 0x0 +#define DNET_INTERNAL_RXTX_CONTROL_REG 0x2 +#define DNET_INTERNAL_MAX_PKT_SIZE_REG 0x4 +#define DNET_INTERNAL_IGP_REG 0x8 +#define DNET_INTERNAL_MAC_ADDR_0_REG 0xa +#define DNET_INTERNAL_MAC_ADDR_1_REG 0xc +#define DNET_INTERNAL_MAC_ADDR_2_REG 0xe +#define DNET_INTERNAL_TX_RX_STS_REG 0x12 +#define DNET_INTERNAL_GMII_MNG_CTL_REG 0x14 +#define DNET_INTERNAL_GMII_MNG_DAT_REG 0x16 + +#define DNET_INTERNAL_GMII_MNG_CMD_FIN (1 << 14) + +#define DNET_INTERNAL_WRITE (1 << 31) + +/* MAC-CORE REGISTER FIELDS */ + +/* MAC-CORE MODE REGISTER FIELDS */ +#define DNET_INTERNAL_MODE_GBITEN (1 << 0) +#define DNET_INTERNAL_MODE_FCEN (1 << 1) +#define DNET_INTERNAL_MODE_RXEN (1 << 2) +#define DNET_INTERNAL_MODE_TXEN (1 << 3) + +/* MAC-CORE RXTX CONTROL REGISTER FIELDS */ +#define DNET_INTERNAL_RXTX_CONTROL_RXSHORTFRAME (1 << 8) +#define DNET_INTERNAL_RXTX_CONTROL_RXBROADCAST (1 << 7) +#define DNET_INTERNAL_RXTX_CONTROL_RXMULTICAST (1 << 4) +#define DNET_INTERNAL_RXTX_CONTROL_RXPAUSE (1 << 3) +#define DNET_INTERNAL_RXTX_CONTROL_DISTXFCS (1 << 2) +#define DNET_INTERNAL_RXTX_CONTROL_DISCFXFCS (1 << 1) +#define DNET_INTERNAL_RXTX_CONTROL_ENPROMISC (1 << 0) +#define DNET_INTERNAL_RXTX_CONTROL_DROPCONTROL (1 << 6) +#define DNET_INTERNAL_RXTX_CONTROL_ENABLEHALFDUP (1 << 5) + +/* SYSTEM CONTROL REGISTER FIELDS */ +#define DNET_SYS_CTL_IGNORENEXTPKT (1 << 0) +#define DNET_SYS_CTL_SENDPAUSE (1 << 2) +#define DNET_SYS_CTL_RXFIFOFLUSH (1 << 3) +#define DNET_SYS_CTL_TXFIFOFLUSH (1 << 4) + +/* TX STATUS REGISTER FIELDS */ +#define DNET_TX_STATUS_FIFO_ALMOST_EMPTY (1 << 2) +#define DNET_TX_STATUS_FIFO_ALMOST_FULL (1 << 1) + +/* INTERRUPT SOURCE REGISTER FIELDS */ +#define DNET_INTR_SRC_TX_PKTSENT (1 << 0) +#define DNET_INTR_SRC_TX_FIFOAF (1 << 1) +#define DNET_INTR_SRC_TX_FIFOAE (1 << 2) +#define DNET_INTR_SRC_TX_DISCFRM (1 << 3) +#define DNET_INTR_SRC_TX_FIFOFULL (1 << 4) +#define DNET_INTR_SRC_RX_CMDFIFOAF (1 << 8) +#define DNET_INTR_SRC_RX_CMDFIFOFF (1 << 9) +#define DNET_INTR_SRC_RX_DATAFIFOFF (1 << 10) +#define DNET_INTR_SRC_TX_SUMMARY (1 << 16) +#define DNET_INTR_SRC_RX_SUMMARY (1 << 17) +#define DNET_INTR_SRC_PHY (1 << 19) + +/* INTERRUPT ENABLE REGISTER FIELDS */ +#define DNET_INTR_ENB_TX_PKTSENT (1 << 0) +#define DNET_INTR_ENB_TX_FIFOAF (1 << 1) +#define DNET_INTR_ENB_TX_FIFOAE (1 << 2) +#define DNET_INTR_ENB_TX_DISCFRM (1 << 3) +#define DNET_INTR_ENB_TX_FIFOFULL (1 << 4) +#define DNET_INTR_ENB_RX_PKTRDY (1 << 8) +#define DNET_INTR_ENB_RX_FIFOAF (1 << 9) +#define DNET_INTR_ENB_RX_FIFOERR (1 << 10) +#define DNET_INTR_ENB_RX_ERROR (1 << 11) +#define DNET_INTR_ENB_RX_FIFOFULL (1 << 12) +#define DNET_INTR_ENB_RX_FIFOAE (1 << 13) +#define DNET_INTR_ENB_TX_SUMMARY (1 << 16) +#define DNET_INTR_ENB_RX_SUMMARY (1 << 17) +#define DNET_INTR_ENB_GLOBAL_ENABLE (1 << 18) + +/* + * Capabilities. Used by the driver to know the capabilities that + * the ethernet controller inside the FPGA have. + */ + +#define DNET_HAS_MDIO (1 << 0) +#define DNET_HAS_IRQ (1 << 1) +#define DNET_HAS_GIGABIT (1 << 2) +#define DNET_HAS_DMA (1 << 3) + +#define DNET_HAS_MII (1 << 4) /* or GMII */ +#define DNET_HAS_RMII (1 << 5) /* or RGMII */ + +#define DNET_CAPS_MASK 0xFFFF + +#define DNET_FIFO_SIZE 2048 /* 2K x 32 bit */ +#define DNET_FIFO_TX_DATA_AF_TH (DNET_FIFO_SIZE - 384) /* 384 = 1536 / 4 */ +#define DNET_FIFO_TX_DATA_AE_TH (384) + +#define DNET_FIFO_RX_CMD_AF_TH (1 << 16) /* just one frame inside the FIFO */ + +#endif diff --git a/include/netdev.h b/include/netdev.h index ce1ecbd..5c568f3 100644 --- a/include/netdev.h +++ b/include/netdev.h @@ -44,6 +44,7 @@ int cpu_eth_init(bd_t *bis); int au1x00_enet_initialize(bd_t*); int bfin_EMAC_initialize(bd_t *bis); int dc21x4x_initialize(bd_t *bis); +int dnet_eth_initialize(int id, void *regs, unsigned int phy_addr); int e1000_initialize(bd_t *bis); int eepro100_initialize(bd_t *bis); int eth_3com_initialize (bd_t * bis);

Hello All,
Sorry guys, it looks like I posted the wrong version. Please discard [v4] patch. I'll post [v5] version soon.
Regards, Ilya.

Driver for Dave DNET ethernet controller (used on Dave/DENX QongEVB-LITE board).
Signed-off-by: Ilya Yanok yanok@emcraft.com --- drivers/net/Makefile | 1 + drivers/net/dnet.c | 396 ++++++++++++++++++++++++++++++++++++++++++++++++++ drivers/net/dnet.h | 166 +++++++++++++++++++++ include/netdev.h | 1 + 4 files changed, 564 insertions(+), 0 deletions(-) create mode 100644 drivers/net/dnet.c create mode 100644 drivers/net/dnet.h
diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 128dc11..a360a50 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -33,6 +33,7 @@ COBJS-$(CONFIG_BFIN_MAC) += bfin_mac.o COBJS-$(CONFIG_DRIVER_CS8900) += cs8900.o COBJS-$(CONFIG_TULIP) += dc2114x.o COBJS-$(CONFIG_DRIVER_DM9000) += dm9000x.o +COBJS-$(CONFIG_DNET) += dnet.o COBJS-$(CONFIG_E1000) += e1000.o COBJS-$(CONFIG_EEPRO100) += eepro100.o COBJS-$(CONFIG_ENC28J60) += enc28j60.o diff --git a/drivers/net/dnet.c b/drivers/net/dnet.c new file mode 100644 index 0000000..efac746 --- /dev/null +++ b/drivers/net/dnet.c @@ -0,0 +1,396 @@ +/* + * Dave Ethernet Controller driver + * + * Copyright (C) 2008 Dave S.r.l. <www.dave.eu> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <common.h> + +#ifndef CONFIG_DNET_AUTONEG_TIMEOUT +#define CONFIG_DNET_AUTONEG_TIMEOUT 5000000 /* default value */ +#endif + +#include <net.h> +#include <malloc.h> +#include <linux/mii.h> + +#include <miiphy.h> +#include <asm/io.h> + +#include "dnet.h" + +struct dnet_device { + struct dnet_registers *regs; + const struct device *dev; + struct eth_device netdev; + unsigned short phy_addr; +}; + +/* get struct dnet_device from given struct netdev */ +#define to_dnet(_nd) container_of(_nd, struct dnet_device, netdev) + +/* function for reading internal MAC register */ +u16 dnet_readw_mac(struct dnet_device *dnet, u16 reg) +{ + u16 data_read; + + /* issue a read */ + writel(reg, &dnet->regs->MACREG_ADDR); + + /* since a read/write op to the MAC is very slow, + * we must wait before reading the data */ + udelay(1); + + /* read data read from the MAC register */ + data_read = readl(&dnet->regs->MACREG_DATA); + + /* all done */ + return data_read; +} + +/* function for writing internal MAC register */ +void dnet_writew_mac(struct dnet_device *dnet, u16 reg, u16 val) +{ + /* load data to write */ + writel(val, &dnet->regs->MACREG_DATA); + + /* issue a write */ + writel(reg | DNET_INTERNAL_WRITE, &dnet->regs->MACREG_ADDR); + + /* since a read/write op to the MAC is very slow, + * we must wait before exiting */ + udelay(1); +} + +static void dnet_mdio_write(struct dnet_device *dnet, u8 reg, u16 value) +{ + u16 tmp; + + debug(DRIVERNAME "dnet_mdio_write %02x:%02x <- %04x\n", + dnet->phy_addr, reg, value); + + while (!(dnet_readw_mac(dnet, DNET_INTERNAL_GMII_MNG_CTL_REG) & + DNET_INTERNAL_GMII_MNG_CMD_FIN)) + ; + + /* prepare for a write operation */ + tmp = (1 << 13); + + /* only 5 bits allowed for register offset */ + reg &= 0x1f; + + /* prepare reg_value for a write */ + tmp |= (dnet->phy_addr << 8); + tmp |= reg; + + /* write data to write first */ + dnet_writew_mac(dnet, DNET_INTERNAL_GMII_MNG_DAT_REG, value); + + /* write control word */ + dnet_writew_mac(dnet, DNET_INTERNAL_GMII_MNG_CTL_REG, tmp); + + while (!(dnet_readw_mac(dnet, DNET_INTERNAL_GMII_MNG_CTL_REG) & + DNET_INTERNAL_GMII_MNG_CMD_FIN)) + ; +} + +static u16 dnet_mdio_read(struct dnet_device *dnet, u8 reg) +{ + u16 value; + + while (!(dnet_readw_mac(dnet, DNET_INTERNAL_GMII_MNG_CTL_REG) & + DNET_INTERNAL_GMII_MNG_CMD_FIN)) + ; + + /* only 5 bits allowed for register offset*/ + reg &= 0x1f; + + /* prepare reg_value for a read */ + value = (dnet->phy_addr << 8); + value |= reg; + + /* write control word */ + dnet_writew_mac(dnet, DNET_INTERNAL_GMII_MNG_CTL_REG, value); + + /* wait for end of transfer */ + while (!(dnet_readw_mac(dnet, DNET_INTERNAL_GMII_MNG_CTL_REG) & + DNET_INTERNAL_GMII_MNG_CMD_FIN)) + ; + + value = dnet_readw_mac(dnet, DNET_INTERNAL_GMII_MNG_DAT_REG); + + debug(DRIVERNAME "dnet_mdio_read %02x:%02x <- %04x\n", + dnet->phy_addr, reg, value); + + return value; +} + +static int dnet_send(struct eth_device *netdev, volatile void *packet, + int length) +{ + struct dnet_device *dnet = to_dnet(netdev); + int i, len, wrsz; + unsigned int *bufp; + unsigned int tx_cmd; + + debug(DRIVERNAME "[%s] Sending %u bytes\n", __func__, length); + + /* frame size (words) */ + len = (length + 3) >> 2; + + bufp = (unsigned int *) (((u32)packet) & 0xFFFFFFFC); + wrsz = (u32)length + 3; + wrsz += ((u32)packet) & 0x3; + wrsz >>= 2; + tx_cmd = ((((unsigned int)(packet)) & 0x03) << 16) | (u32)length; + + /* check if there is enough room for the current frame */ + if (wrsz < (DNET_FIFO_SIZE - readl(&dnet->regs->TX_FIFO_WCNT))) { + for (i = 0; i < wrsz; i++) + writel(*bufp++, &dnet->regs->TX_DATA_FIFO); + /* + * inform MAC that a packet's written and ready + * to be shipped out + */ + writel(tx_cmd, &dnet->regs->TX_LEN_FIFO); + } else { + printf(DRIVERNAME "No free space (actual %d, required %d " + "(words))\n", DNET_FIFO_SIZE - + readl(&dnet->regs->TX_FIFO_WCNT), wrsz); + } + + /* No one cares anyway */ + return 0; +} + + +static int dnet_recv(struct eth_device *netdev) +{ + struct dnet_device *dnet = to_dnet(netdev); + unsigned int *data_ptr; + int pkt_len, poll, i; + u32 cmd_word; + + debug("Waiting for pkt (polling)\n"); + poll = 50; + while ((readl(&dnet->regs->RX_FIFO_WCNT) >> 16) == 0) { + udelay(10); /* wait 10 usec */ + if (--poll == 0) + return 0; /* no pkt available */ + } + + cmd_word = readl(&dnet->regs->RX_LEN_FIFO); + pkt_len = cmd_word & 0xFFFF; + + debug("Got pkt with size %d bytes\n", pkt_len); + + if (cmd_word & 0xDF180000) + printf("%s packet receive error %x\n", __func__, cmd_word); + + data_ptr = (unsigned int *) NetRxPackets[0]; + + for (i = 0; i < (pkt_len + 3) >> 2; i++) + *data_ptr++ = readl(&dnet->regs->RX_DATA_FIFO); + + NetReceive(NetRxPackets[0], pkt_len + 5); /* ok + 5 ?? */ + + return 0; +} + +static void dnet_set_hwaddr(struct eth_device *netdev) +{ + struct dnet_device *dnet = to_dnet(netdev); + u16 tmp; + + tmp = cpu_to_be16(*((u16 *)netdev->enetaddr)); + dnet_writew_mac(dnet, DNET_INTERNAL_MAC_ADDR_0_REG, tmp); + tmp = cpu_to_be16(*((u16 *)(netdev->enetaddr + 2))); + dnet_writew_mac(dnet, DNET_INTERNAL_MAC_ADDR_1_REG, tmp); + tmp = cpu_to_be16(*((u16 *)(netdev->enetaddr + 4))); + dnet_writew_mac(dnet, DNET_INTERNAL_MAC_ADDR_2_REG, tmp); +} + +static void dnet_phy_reset(struct dnet_device *dnet) +{ + struct eth_device *netdev = &dnet->netdev; + int i; + u16 status, adv; + + adv = ADVERTISE_CSMA | ADVERTISE_ALL; + dnet_mdio_write(dnet, MII_ADVERTISE, adv); + printf("%s: Starting autonegotiation...\n", netdev->name); + dnet_mdio_write(dnet, MII_BMCR, (BMCR_ANENABLE + | BMCR_ANRESTART)); + + for (i = 0; i < CONFIG_DNET_AUTONEG_TIMEOUT / 100; i++) { + status = dnet_mdio_read(dnet, MII_BMSR); + if (status & BMSR_ANEGCOMPLETE) + break; + udelay(100); + } + + if (status & BMSR_ANEGCOMPLETE) + printf("%s: Autonegotiation complete\n", netdev->name); + else + printf("%s: Autonegotiation timed out (status=0x%04x)\n", + netdev->name, status); +} + +static int dnet_phy_init(struct dnet_device *dnet) +{ + struct eth_device *netdev = &dnet->netdev; + u16 phy_id, status, adv, lpa; + int media, speed, duplex; + int i; + u32 ctl_reg; + + /* Find a PHY */ + for (i = 0; i < 32; i++) { + dnet->phy_addr = i; + phy_id = dnet_mdio_read(dnet, MII_PHYSID1); + if (phy_id != 0xffff) { + /* ok we found it */ + printf("Found PHY at address %d PHYID (%04x:%04x)\n", + i, phy_id, + dnet_mdio_read(dnet, MII_PHYSID2)); + break; + } + } + + /* Check if the PHY is up to snuff... */ + phy_id = dnet_mdio_read(dnet, MII_PHYSID1); + if (phy_id == 0xffff) { + printf("%s: No PHY present\n", netdev->name); + return -1; + } + + status = dnet_mdio_read(dnet, MII_BMSR); + if (!(status & BMSR_LSTATUS)) { + /* Try to re-negotiate if we don't have link already. */ + dnet_phy_reset(dnet); + + for (i = 0; i < CONFIG_DNET_AUTONEG_TIMEOUT / 100; i++) { + status = dnet_mdio_read(dnet, MII_BMSR); + if (status & BMSR_LSTATUS) + break; + udelay(100); + } + } + + if (!(status & BMSR_LSTATUS)) { + printf("%s: link down (status: 0x%04x)\n", + netdev->name, status); + return -1; + } else { + adv = dnet_mdio_read(dnet, MII_ADVERTISE); + lpa = dnet_mdio_read(dnet, MII_LPA); + media = mii_nway_result(lpa & adv); + speed = (media & (ADVERTISE_100FULL | ADVERTISE_100HALF) + ? 1 : 0); + duplex = (media & ADVERTISE_FULL) ? 1 : 0; + /* 1000BaseT ethernet is not supported */ + printf("%s: link up, %sMbps %s-duplex (lpa: 0x%04x)\n", + netdev->name, + speed ? "100" : "10", + duplex ? "full" : "half", + lpa); + + ctl_reg = dnet_readw_mac(dnet, DNET_INTERNAL_RXTX_CONTROL_REG); + + if (duplex) + ctl_reg &= ~(DNET_INTERNAL_RXTX_CONTROL_ENABLEHALFDUP); + else + ctl_reg |= DNET_INTERNAL_RXTX_CONTROL_ENABLEHALFDUP; + + dnet_writew_mac(dnet, DNET_INTERNAL_RXTX_CONTROL_REG, ctl_reg); + + return 0; + } +} + +static int dnet_init(struct eth_device *netdev, bd_t *bd) +{ + struct dnet_device *dnet = to_dnet(netdev); + u32 config; + + /* + * dnet_halt should have been called at some point before now, + * so we'll assume the controller is idle. + */ + + /* set hardware address */ + dnet_set_hwaddr(netdev); + + if (dnet_phy_init(dnet) < 0) + return -1; + + /* flush rx/tx fifos */ + writel(DNET_SYS_CTL_RXFIFOFLUSH | DNET_SYS_CTL_TXFIFOFLUSH, + &dnet->regs->SYS_CTL); + udelay(1000); + writel(0, &dnet->regs->SYS_CTL); + + config = dnet_readw_mac(dnet, DNET_INTERNAL_RXTX_CONTROL_REG); + + config |= DNET_INTERNAL_RXTX_CONTROL_RXPAUSE | + DNET_INTERNAL_RXTX_CONTROL_RXBROADCAST | + DNET_INTERNAL_RXTX_CONTROL_DROPCONTROL | + DNET_INTERNAL_RXTX_CONTROL_DISCFXFCS; + + dnet_writew_mac(dnet, DNET_INTERNAL_RXTX_CONTROL_REG, config); + + /* Enable TX and RX */ + dnet_writew_mac(dnet, DNET_INTERNAL_MODE_REG, + DNET_INTERNAL_MODE_RXEN | DNET_INTERNAL_MODE_TXEN); + + return 0; +} + +static void dnet_halt(struct eth_device *netdev) +{ + struct dnet_device *dnet = to_dnet(netdev); + + /* Disable TX and RX */ + dnet_writew_mac(dnet, DNET_INTERNAL_MODE_REG, 0); +} + +int dnet_eth_initialize(int id, void *regs, unsigned int phy_addr) +{ + struct dnet_device *dnet; + struct eth_device *netdev; + unsigned int dev_capa; + + dnet = malloc(sizeof(struct dnet_device)); + if (!dnet) { + printf("Error: Failed to allocate memory for DNET%d\n", id); + return -1; + } + memset(dnet, 0, sizeof(struct dnet_device)); + + netdev = &dnet->netdev; + + dnet->regs = (struct dnet_registers *)regs; + dnet->phy_addr = phy_addr; + + sprintf(netdev->name, "dnet%d", id); + netdev->init = dnet_init; + netdev->halt = dnet_halt; + netdev->send = dnet_send; + netdev->recv = dnet_recv; + + dev_capa = readl(&dnet->regs->VERCAPS) & 0xFFFF; + debug("%s: has %smdio, %sirq, %sgigabit, %sdma \n", netdev->name, + (dev_capa & DNET_HAS_MDIO) ? "" : "no ", + (dev_capa & DNET_HAS_IRQ) ? "" : "no ", + (dev_capa & DNET_HAS_GIGABIT) ? "" : "no ", + (dev_capa & DNET_HAS_DMA) ? "" : "no "); + + eth_register(netdev); + + return 0; +} + diff --git a/drivers/net/dnet.h b/drivers/net/dnet.h new file mode 100644 index 0000000..fdb4fd2 --- /dev/null +++ b/drivers/net/dnet.h @@ -0,0 +1,166 @@ +/* + * Dave Ethernet Controller driver + * + * Copyright (C) 2008 Dave S.r.l. <www.dave.eu> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __DRIVERS_DNET_H__ +#define __DRIVERS_DNET_H__ + +#define DRIVERNAME "dnet" + +struct dnet_registers { + /* ALL DNET FIFO REGISTERS */ + u32 RX_LEN_FIFO; + u32 RX_DATA_FIFO; + u32 TX_LEN_FIFO; + u32 TX_DATA_FIFO; + u32 pad1[0x3c]; + /* ALL DNET CONTROL/STATUS REGISTERS */ + u32 VERCAPS; + u32 INTR_SRC; + u32 INTR_ENB; + u32 RX_STATUS; + u32 TX_STATUS; + u32 RX_FRAMES_CNT; + u32 TX_FRAMES_CNT; + u32 RX_FIFO_TH; + u32 TX_FIFO_TH; + u32 SYS_CTL; + u32 PAUSE_TMR; + u32 RX_FIFO_WCNT; + u32 TX_FIFO_WCNT; + u32 pad2[0x33]; + /* ALL DNET MAC REGISTERS */ + u32 MACREG_DATA; /* Mac-Reg Data */ + u32 MACREG_ADDR; /* Mac-Reg Addr */ + u32 pad3[0x3e]; + /* ALL DNET RX STATISTICS COUNTERS */ + u32 RX_PKT_IGNR_CNT; + u32 RX_LEN_CHK_ERR_CNT; + u32 RX_LNG_FRM_CNT; + u32 RX_SHRT_FRM_CNT; + u32 RX_IPG_VIOL_CNT; + u32 RX_CRC_ERR_CNT; + u32 RX_OK_PKT_CNT; + u32 RX_CTL_FRM_CNT; + u32 RX_PAUSE_FRM_CNT; + u32 RX_MULTICAST_CNT; + u32 RX_BROADCAST_CNT; + u32 RX_VLAN_TAG_CNT; + u32 RX_PRE_SHRINK_CNT; + u32 RX_DRIB_NIB_CNT; + u32 RX_UNSUP_OPCD_CNT; + u32 RX_BYTE_CNT; + u32 pad4[0x30]; + /* DNET TX STATISTICS COUNTERS */ + u32 TX_UNICAST_CNT; + u32 TX_PAUSE_FRM_CNT; + u32 TX_MULTICAST_CNT; + u32 TX_BRDCAST_CNT; + u32 TX_VLAN_TAG_CNT; + u32 TX_BAD_FCS_CNT; + u32 TX_JUMBO_CNT; + u32 TX_BYTE_CNT; +}; + +/* SOME INTERNAL MAC-CORE REGISTER */ +#define DNET_INTERNAL_MODE_REG 0x0 +#define DNET_INTERNAL_RXTX_CONTROL_REG 0x2 +#define DNET_INTERNAL_MAX_PKT_SIZE_REG 0x4 +#define DNET_INTERNAL_IGP_REG 0x8 +#define DNET_INTERNAL_MAC_ADDR_0_REG 0xa +#define DNET_INTERNAL_MAC_ADDR_1_REG 0xc +#define DNET_INTERNAL_MAC_ADDR_2_REG 0xe +#define DNET_INTERNAL_TX_RX_STS_REG 0x12 +#define DNET_INTERNAL_GMII_MNG_CTL_REG 0x14 +#define DNET_INTERNAL_GMII_MNG_DAT_REG 0x16 + +#define DNET_INTERNAL_GMII_MNG_CMD_FIN (1 << 14) + +#define DNET_INTERNAL_WRITE (1 << 31) + +/* MAC-CORE REGISTER FIELDS */ + +/* MAC-CORE MODE REGISTER FIELDS */ +#define DNET_INTERNAL_MODE_GBITEN (1 << 0) +#define DNET_INTERNAL_MODE_FCEN (1 << 1) +#define DNET_INTERNAL_MODE_RXEN (1 << 2) +#define DNET_INTERNAL_MODE_TXEN (1 << 3) + +/* MAC-CORE RXTX CONTROL REGISTER FIELDS */ +#define DNET_INTERNAL_RXTX_CONTROL_RXSHORTFRAME (1 << 8) +#define DNET_INTERNAL_RXTX_CONTROL_RXBROADCAST (1 << 7) +#define DNET_INTERNAL_RXTX_CONTROL_RXMULTICAST (1 << 4) +#define DNET_INTERNAL_RXTX_CONTROL_RXPAUSE (1 << 3) +#define DNET_INTERNAL_RXTX_CONTROL_DISTXFCS (1 << 2) +#define DNET_INTERNAL_RXTX_CONTROL_DISCFXFCS (1 << 1) +#define DNET_INTERNAL_RXTX_CONTROL_ENPROMISC (1 << 0) +#define DNET_INTERNAL_RXTX_CONTROL_DROPCONTROL (1 << 6) +#define DNET_INTERNAL_RXTX_CONTROL_ENABLEHALFDUP (1 << 5) + +/* SYSTEM CONTROL REGISTER FIELDS */ +#define DNET_SYS_CTL_IGNORENEXTPKT (1 << 0) +#define DNET_SYS_CTL_SENDPAUSE (1 << 2) +#define DNET_SYS_CTL_RXFIFOFLUSH (1 << 3) +#define DNET_SYS_CTL_TXFIFOFLUSH (1 << 4) + +/* TX STATUS REGISTER FIELDS */ +#define DNET_TX_STATUS_FIFO_ALMOST_EMPTY (1 << 2) +#define DNET_TX_STATUS_FIFO_ALMOST_FULL (1 << 1) + +/* INTERRUPT SOURCE REGISTER FIELDS */ +#define DNET_INTR_SRC_TX_PKTSENT (1 << 0) +#define DNET_INTR_SRC_TX_FIFOAF (1 << 1) +#define DNET_INTR_SRC_TX_FIFOAE (1 << 2) +#define DNET_INTR_SRC_TX_DISCFRM (1 << 3) +#define DNET_INTR_SRC_TX_FIFOFULL (1 << 4) +#define DNET_INTR_SRC_RX_CMDFIFOAF (1 << 8) +#define DNET_INTR_SRC_RX_CMDFIFOFF (1 << 9) +#define DNET_INTR_SRC_RX_DATAFIFOFF (1 << 10) +#define DNET_INTR_SRC_TX_SUMMARY (1 << 16) +#define DNET_INTR_SRC_RX_SUMMARY (1 << 17) +#define DNET_INTR_SRC_PHY (1 << 19) + +/* INTERRUPT ENABLE REGISTER FIELDS */ +#define DNET_INTR_ENB_TX_PKTSENT (1 << 0) +#define DNET_INTR_ENB_TX_FIFOAF (1 << 1) +#define DNET_INTR_ENB_TX_FIFOAE (1 << 2) +#define DNET_INTR_ENB_TX_DISCFRM (1 << 3) +#define DNET_INTR_ENB_TX_FIFOFULL (1 << 4) +#define DNET_INTR_ENB_RX_PKTRDY (1 << 8) +#define DNET_INTR_ENB_RX_FIFOAF (1 << 9) +#define DNET_INTR_ENB_RX_FIFOERR (1 << 10) +#define DNET_INTR_ENB_RX_ERROR (1 << 11) +#define DNET_INTR_ENB_RX_FIFOFULL (1 << 12) +#define DNET_INTR_ENB_RX_FIFOAE (1 << 13) +#define DNET_INTR_ENB_TX_SUMMARY (1 << 16) +#define DNET_INTR_ENB_RX_SUMMARY (1 << 17) +#define DNET_INTR_ENB_GLOBAL_ENABLE (1 << 18) + +/* + * Capabilities. Used by the driver to know the capabilities that + * the ethernet controller inside the FPGA have. + */ + +#define DNET_HAS_MDIO (1 << 0) +#define DNET_HAS_IRQ (1 << 1) +#define DNET_HAS_GIGABIT (1 << 2) +#define DNET_HAS_DMA (1 << 3) + +#define DNET_HAS_MII (1 << 4) /* or GMII */ +#define DNET_HAS_RMII (1 << 5) /* or RGMII */ + +#define DNET_CAPS_MASK 0xFFFF + +#define DNET_FIFO_SIZE 2048 /* 2K x 32 bit */ +#define DNET_FIFO_TX_DATA_AF_TH (DNET_FIFO_SIZE - 384) /* 384 = 1536 / 4 */ +#define DNET_FIFO_TX_DATA_AE_TH (384) + +#define DNET_FIFO_RX_CMD_AF_TH (1 << 16) /* just one frame inside the FIFO */ + +#endif diff --git a/include/netdev.h b/include/netdev.h index ce1ecbd..5c568f3 100644 --- a/include/netdev.h +++ b/include/netdev.h @@ -44,6 +44,7 @@ int cpu_eth_init(bd_t *bis); int au1x00_enet_initialize(bd_t*); int bfin_EMAC_initialize(bd_t *bis); int dc21x4x_initialize(bd_t *bis); +int dnet_eth_initialize(int id, void *regs, unsigned int phy_addr); int e1000_initialize(bd_t *bis); int eepro100_initialize(bd_t *bis); int eth_3com_initialize (bd_t * bis);

On 18:45 Mon 09 Feb , Ilya Yanok wrote:
Driver for Dave DNET ethernet controller (used on Dave/DENX QongEVB-LITE board).
Signed-off-by: Ilya Yanok yanok@emcraft.com
Ben If it's ok with you I'll apply it at the same time of the board
Best Regards, J.

Jean-Christophe PLAGNIOL-VILLARD wrote:
On 18:45 Mon 09 Feb , Ilya Yanok wrote:
Driver for Dave DNET ethernet controller (used on Dave/DENX QongEVB-LITE board).
Signed-off-by: Ilya Yanok yanok@emcraft.com
Ben If it's ok with you I'll apply it at the same time of the board
Best Regards, J.
Acked-by: Ben Warren biggerbadderben@gmail.com

This patch adds support for Dave/DENX QongEVB-LITE i.MX31-based board.
Signed-off-by: Ilya Yanok yanok@emcraft.com --- MAINTAINERS | 3 + MAKEALL | 1 + Makefile | 4 + board/davedenx/qong/Makefile | 53 +++++++++ board/davedenx/qong/config.mk | 1 + board/davedenx/qong/lowlevel_init.S | 172 ++++++++++++++++++++++++++++ board/davedenx/qong/qong.c | 168 +++++++++++++++++++++++++++ board/davedenx/qong/qong_fpga.h | 41 +++++++ board/davedenx/qong/u-boot.lds | 58 ++++++++++ include/configs/qong.h | 215 +++++++++++++++++++++++++++++++++++ 10 files changed, 716 insertions(+), 0 deletions(-) create mode 100644 board/davedenx/qong/Makefile create mode 100644 board/davedenx/qong/config.mk create mode 100644 board/davedenx/qong/lowlevel_init.S create mode 100644 board/davedenx/qong/qong.c create mode 100644 board/davedenx/qong/qong_fpga.h create mode 100644 board/davedenx/qong/u-boot.lds create mode 100644 include/configs/qong.h
diff --git a/MAINTAINERS b/MAINTAINERS index 38feac8..c3157d9 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -655,6 +655,9 @@ Sergey Lapin slapin@ossfans.org
afeb9260 ARM926EJS (AT91SAM9260 SoC)
+Wolfgang Denk wd@denx.de + qong i.MX31 + -------------------------------------------------------------------------
Unknown / orphaned boards: diff --git a/MAKEALL b/MAKEALL index cf05133..73974f7 100755 --- a/MAKEALL +++ b/MAKEALL @@ -542,6 +542,7 @@ LIST_ARM11=" \ imx31_litekit \ imx31_phycore \ mx31ads \ + qong \ smdk6400 \ "
diff --git a/Makefile b/Makefile index 787c5f2..7508e1d 100644 --- a/Makefile +++ b/Makefile @@ -3034,6 +3034,10 @@ mx31ads_config : unconfig omap2420h4_config : unconfig @$(MKCONFIG) $(@:_config=) arm arm1136 omap2420h4 NULL omap24xx
+qong_config : unconfig + @$(MKCONFIG) $(@:_config=) arm arm1136 qong davedenx mx31 + + ######################################################################### ## ARM1176 Systems ######################################################################### diff --git a/board/davedenx/qong/Makefile b/board/davedenx/qong/Makefile new file mode 100644 index 0000000..93e1985 --- /dev/null +++ b/board/davedenx/qong/Makefile @@ -0,0 +1,53 @@ +# +# (C) Copyright 2009 +# Ilya Yanok, Emcraft Systems Ltd, yanok@emcraft.com +# (C) Copyright 2000-2006 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# See file CREDITS for list of people who contributed to this +# project. +# +# 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. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# + +include $(TOPDIR)/config.mk + +LIB = $(obj)lib$(BOARD).a + +COBJS := qong.o +SOBJS := lowlevel_init.o + +SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c) +OBJS := $(addprefix $(obj),$(COBJS)) +SOBJS := $(addprefix $(obj),$(SOBJS)) + +$(LIB): $(obj).depend $(OBJS) $(SOBJS) + $(AR) $(ARFLAGS) $@ $(OBJS) $(SOBJS) + +clean: + rm -f $(SOBJS) $(OBJS) + +distclean: clean + rm -f $(LIB) core *.bak .depend + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/board/davedenx/qong/config.mk b/board/davedenx/qong/config.mk new file mode 100644 index 0000000..d8d0a57 --- /dev/null +++ b/board/davedenx/qong/config.mk @@ -0,0 +1 @@ +TEXT_BASE = 0x8ff00000 diff --git a/board/davedenx/qong/lowlevel_init.S b/board/davedenx/qong/lowlevel_init.S new file mode 100644 index 0000000..0601ac4 --- /dev/null +++ b/board/davedenx/qong/lowlevel_init.S @@ -0,0 +1,172 @@ +/* + * Copyright (C) 2009, Emcraft Systems, Ilya Yanok yanok@emcraft.com + * + * Based on board/freescale/mx31ads/lowlevel_init.S + * by Guennadi Liakhovetski. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <asm/arch/mx31-regs.h> + +.macro REG reg, val + ldr r2, =\reg + ldr r3, =\val + str r3, [r2] +.endm + +.macro REG8 reg, val + ldr r2, =\reg + ldr r3, =\val + strb r3, [r2] +.endm + +.macro DELAY loops + ldr r2, =\loops +1: + subs r2, r2, #1 + nop + bcs 1b +.endm + +/* RedBoot: To support 133MHz DDR */ +.macro init_drive_strength + /* + * Disable maximum drive strength SDRAM/DDR lines by clearing DSE1 bits + * in SW_PAD_CTL registers + */ + + /* SDCLK */ + ldr r1, =IOMUXC_SW_PAD_CTL(0x2b) + ldr r0, [r1, #0x6C] + bic r0, r0, #(1 << 12) + str r0, [r1, #0x6C] + + /* CAS */ + ldr r0, [r1, #0x70] + bic r0, r0, #(1 << 22) + str r0, [r1, #0x70] + + /* RAS */ + ldr r0, [r1, #0x74] + bic r0, r0, #(1 << 2) + str r0, [r1, #0x74] + + /* CS2 (CSD0) */ + ldr r0, [r1, #0x7C] + bic r0, r0, #(1 << 22) + str r0, [r1, #0x7C] + + /* DQM3 */ + ldr r0, [r1, #0x84] + bic r0, r0, #(1 << 22) + str r0, [r1, #0x84] + + /* DQM2, DQM1, DQM0, SD31-SD0, A25-A0, MA10 (0x288..0x2DC) */ + ldr r2, =22 /* (0x2E0 - 0x288) / 4 = 22 */ +pad_loop: + ldr r0, [r1, #0x88] + bic r0, r0, #(1 << 22) + bic r0, r0, #(1 << 12) + bic r0, r0, #(1 << 2) + str r0, [r1, #0x88] + add r1, r1, #4 + subs r2, r2, #0x1 + bne pad_loop +.endm /* init_drive_strength */ + +.globl lowlevel_init +lowlevel_init: + + init_drive_strength + + /* Image Processing Unit: */ + /* Too early to switch display on? */ + /* Switch on Display Interface */ + REG IPU_CONF, IPU_CONF_DI_EN + /* Clock Control Module: */ + REG CCM_CCMR, 0x074B0BF5 /* Use CKIH, MCU PLL off */ + + DELAY 0x40000 + + REG CCM_CCMR, 0x074B0BF5 | CCMR_MPE /* MCU PLL on */ + /* Switch to MCU PLL */ + REG CCM_CCMR, (0x074B0BF5 | CCMR_MPE) & ~CCMR_MDS + + /* 399-133-66.5 */ + ldr r0, =CCM_BASE + ldr r1, =0xFF871650 + /* PDR0 */ + str r1, [r0, #0x4] + ldr r1, MPCTL_PARAM_399 + /* MPCTL */ + str r1, [r0, #0x10] + + /* Set UPLL=240MHz, USB=60MHz */ + ldr r1, =0x49FCFE7F + /* PDR1 */ + str r1, [r0, #0x8] + ldr r1, UPCTL_PARAM_240 + /* UPCTL */ + str r1, [r0, #0x14] + /* default CLKO to 1/8 of the ARM core */ + mov r1, #0x00000208 + /* COSR */ + str r1, [r0, #0x1c] + + /* Default: 1, 4, 12, 1 */ + REG CCM_SPCTL, PLL_PD(1) | PLL_MFD(4) | PLL_MFI(12) | PLL_MFN(1) + + /* B8xxxxxx - NAND, 8xxxxxxx - CSD0 RAM */ + REG 0xB8001010, 0x00000004 + REG 0xB8001004, ((3 << 21) | /* tXP */ \ + (0 << 20) | /* tWTR */ \ + (2 << 18) | /* tRP */ \ + (1 << 16) | /* tMRD */ \ + (0 << 15) | /* tWR */ \ + (5 << 12) | /* tRAS */ \ + (1 << 10) | /* tRRD */ \ + (3 << 8) | /* tCAS */ \ + (2 << 4) | /* tRCD */ \ + (7 << 0) /* tRC */ ) + REG 0xB8001000, 0x92100000 + REG 0x80000f00, 0x12344321 + REG 0xB8001000, 0xa2100000 + REG 0x80000000, 0x12344321 + REG 0x80000000, 0x12344321 + REG 0xB8001000, 0xb2100000 + REG8 0x80000033, 0xda + REG8 0x81000000, 0xff + REG 0xB8001000, ((1 << 31) | \ + (0 << 28) | \ + (0 << 27) | \ + (3 << 24) | /* 14 rows */ \ + (2 << 20) | /* 10 cols */ \ + (2 << 16) | \ + (4 << 13) | /* 3.91us (64ms/16384) */ \ + (0 << 10) | \ + (0 << 8) | \ + (1 << 7) | \ + (0 << 0)) + REG 0x80000000, 0xDEADBEEF + REG 0xB8001010, 0x0000000c + + mov pc, lr + +MPCTL_PARAM_399: + .word (((1-1) << 26) + ((52-1) << 16) + (7 << 10) + (35 << 0)) +UPCTL_PARAM_240: + .word (((2-1) << 26) + ((13-1) << 16) + (9 << 10) + (3 << 0)) diff --git a/board/davedenx/qong/qong.c b/board/davedenx/qong/qong.c new file mode 100644 index 0000000..85af83b --- /dev/null +++ b/board/davedenx/qong/qong.c @@ -0,0 +1,168 @@ +/* + * + * (c) 2009 Emcraft Systems, Ilya Yanok yanok@emcraft.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + + +#include <common.h> +#include <netdev.h> +#include <asm/arch/mx31.h> +#include <asm/arch/mx31-regs.h> +#include "qong_fpga.h" + +DECLARE_GLOBAL_DATA_PTR; + +int dram_init (void) +{ + gd->bd->bi_dram[0].start = PHYS_SDRAM_1; + gd->bd->bi_dram[0].size = get_ram_size((volatile void *)PHYS_SDRAM_1, + PHYS_SDRAM_1_SIZE); + + return 0; +} + +int board_init (void) +{ + /* Chip selects */ + /* CS0: Nor Flash #0 - it must be init'ed when executing from DDR */ + /* Assumptions: HCLK = 133 MHz, tACC = 130ns */ + __REG(CSCR_U(0)) = ((0 << 31) | /* SP */ + (0 << 30) | /* WP */ + (0 << 28) | /* BCD */ + (0 << 24) | /* BCS */ + (0 << 22) | /* PSZ */ + (0 << 21) | /* PME */ + (0 << 20) | /* SYNC */ + (0 << 16) | /* DOL */ + (3 << 14) | /* CNC */ + (21 << 8) | /* WSC */ + (0 << 7) | /* EW */ + (0 << 4) | /* WWS */ + (6 << 0) /* EDC */ + ); + + __REG(CSCR_L(0)) = ((2 << 28) | /* OEA */ + (1 << 24) | /* OEN */ + (3 << 20) | /* EBWA */ + (3 << 16) | /* EBWN */ + (1 << 12) | /* CSA */ + (1 << 11) | /* EBC */ + (5 << 8) | /* DSZ */ + (1 << 4) | /* CSN */ + (0 << 3) | /* PSR */ + (0 << 2) | /* CRE */ + (0 << 1) | /* WRAP */ + (1 << 0) /* CSEN */ + ); + + __REG(CSCR_A(0)) = ((2 << 28) | /* EBRA */ + (1 << 24) | /* EBRN */ + (2 << 20) | /* RWA */ + (2 << 16) | /* RWN */ + (0 << 15) | /* MUM */ + (0 << 13) | /* LAH */ + (2 << 10) | /* LBN */ + (0 << 8) | /* LBA */ + (0 << 6) | /* DWW */ + (0 << 4) | /* DCT */ + (0 << 3) | /* WWU */ + (0 << 2) | /* AGE */ + (0 << 1) | /* CNC2 */ + (0 << 0) /* FCE */ + ); + +#ifdef CONFIG_QONG_FPGA + /* CS1: FPGA/Network Controller/GPIO */ + /* 16-bit, no DTACK */ + __REG(CSCR_U(1)) = 0x00000A01; + __REG(CSCR_L(1)) = 0x20040501; + __REG(CSCR_A(1)) = 0x04020C00; + + /* setup pins for FPGA */ + mx31_gpio_mux(IOMUX_MODE(0x76, MUX_CTL_GPIO)); + mx31_gpio_mux(IOMUX_MODE(0x7e, MUX_CTL_GPIO)); + mx31_gpio_mux(IOMUX_MODE(0x91, MUX_CTL_OUT_FUNC | MUX_CTL_IN_GPIO)); + mx31_gpio_mux(IOMUX_MODE(0x92, MUX_CTL_GPIO)); + mx31_gpio_mux(IOMUX_MODE(0x93, MUX_CTL_GPIO)); +#endif + + /* setup pins for UART1 */ + mx31_gpio_mux(MUX_RXD1__UART1_RXD_MUX); + mx31_gpio_mux(MUX_TXD1__UART1_TXD_MUX); + mx31_gpio_mux(MUX_RTS1__UART1_RTS_B); + mx31_gpio_mux(MUX_CTS1__UART1_CTS_B); + + /* board id for linux */ + gd->bd->bi_arch_number = MACH_TYPE_QONG; + gd->bd->bi_boot_params = (0x80000100); /* adress of boot parameters */ + + return 0; +} + +int checkboard (void) +{ + printf("Board: DAVE/DENX QongEVB-LITE\n"); + return 0; +} + +int misc_init_r (void) +{ +#ifdef CONFIG_QONG_FPGA + u32 tmp; + + /* FPGA reset */ + /* rstn = 0 */ + tmp = __REG(GPIO2_BASE + GPIO_DR); + tmp &= (~(1 << QONG_FPGA_RST_PIN)); + __REG(GPIO2_BASE + GPIO_DR) = tmp; + /* set the GPIO as output */ + tmp = __REG(GPIO2_BASE + GPIO_GDIR); + tmp |= (1 << QONG_FPGA_RST_PIN); + __REG(GPIO2_BASE + GPIO_GDIR) = tmp; + /* wait */ + udelay(30); + /* rstn = 1 */ + tmp = __REG(GPIO2_BASE + GPIO_DR); + tmp |= (1 << QONG_FPGA_RST_PIN); + __REG(GPIO2_BASE + GPIO_DR) = tmp; + /* set interrupt pin as input */ + __REG(GPIO2_BASE + GPIO_GDIR) = tmp | (1 << QONG_FPGA_IRQ_PIN); + /* wait while the FPGA starts */ + udelay(300); + + tmp = *(volatile u32*)QONG_FPGA_CTRL_VERSION; + printf("FPGA: "); + printf("version register = %u.%u.%u\n", + (tmp & 0xF000) >> 12, (tmp & 0x0F00) >> 8, tmp & 0x00FF); +#endif + + return 0; +} + +int board_eth_init(bd_t *bis) +{ +#if defined(CONFIG_QONG_FPGA) && defined(CONFIG_DNET) + return dnet_eth_initialize(0, (void *)CONFIG_DNET_BASE, -1); +#else + return 0; +#endif +} + diff --git a/board/davedenx/qong/qong_fpga.h b/board/davedenx/qong/qong_fpga.h new file mode 100644 index 0000000..b1cb08a --- /dev/null +++ b/board/davedenx/qong/qong_fpga.h @@ -0,0 +1,41 @@ +/* + * + * (c) 2009 Emcraft Systems, Ilya Yanok yanok@emcraft.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef QONG_FPGA_H +#define QONG_FPGA_H + +#ifdef CONFIG_QONG_FPGA +#define QONG_FPGA_CTRL_BASE CONFIG_FPGA_BASE +#define QONG_FPGA_CTRL_VERSION (QONG_FPGA_CTRL_BASE + 0x00000000) +#define QONG_FPGA_PERIPH_SIZE (1 << 24) + +#define QONG_FPGA_TCK_PIN 26 +#define QONG_FPGA_TMS_PIN 25 +#define QONG_FPGA_TDI_PIN 8 +#define QONG_FPGA_TDO_PIN 7 +#define QONG_FPGA_RST_PIN 16 +#define QONG_FPGA_IRQ_PIN 8 +#endif + +#endif /* QONG_FPGA_H */ + diff --git a/board/davedenx/qong/u-boot.lds b/board/davedenx/qong/u-boot.lds new file mode 100644 index 0000000..8bf08ca --- /dev/null +++ b/board/davedenx/qong/u-boot.lds @@ -0,0 +1,58 @@ +/* + * (C) Copyright 2009 + * Ilya Yanok, Emcraft Systems Ltd, yanok@emcraft.com + * (C) Copyright 2002 + * Gary Jennejohn, DENX Software Engineering, gj@denx.de + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") +OUTPUT_ARCH(arm) +ENTRY(_start) +SECTIONS +{ + . = 0x00000000; + + . = ALIGN(4); + .text : + { + cpu/arm1136/start.o (.text) + *(.text) + } + + . = ALIGN(4); + .rodata : { *(.rodata) } + + . = ALIGN(4); + .data : { *(.data) } + + . = ALIGN(4); + .got : { *(.got) } + + . = .; + __u_boot_cmd_start = .; + .u_boot_cmd : { *(.u_boot_cmd) } + __u_boot_cmd_end = .; + + . = ALIGN(4); + __bss_start = .; + .bss : { *(.bss) } + _end = .; +} diff --git a/include/configs/qong.h b/include/configs/qong.h new file mode 100644 index 0000000..fc6e33a --- /dev/null +++ b/include/configs/qong.h @@ -0,0 +1,215 @@ +/* + * Copyright (C) 2009, Ilya Yanok, Emcraft Systems, yanok@emcraft.com + * + * Configuration settings for the Dave/DENX QongEVB-LITE board. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef __CONFIG_H +#define __CONFIG_H + +#include <asm/arch/mx31-regs.h> + + /* High Level Configuration Options */ +#define CONFIG_ARM1136 1 /* This is an arm1136 CPU core */ +#define CONFIG_MX31 1 /* in a mx31 */ +#define CONFIG_QONG 1 +#define CONFIG_MX31_HCLK_FREQ 26000000 /* 26MHz */ +#define CONFIG_MX31_CLK32 32768 + +#define CONFIG_DISPLAY_CPUINFO +#define CONFIG_DISPLAY_BOARDINFO + +#define CONFIG_CMDLINE_TAG 1 /* enable passing of ATAGs */ +#define CONFIG_SETUP_MEMORY_TAGS 1 +#define CONFIG_INITRD_TAG 1 + +/* + * Size of malloc() pool + */ +#define CONFIG_SYS_MALLOC_LEN (CONFIG_ENV_SIZE + 128 * 1024) +/* size in bytes reserved for initial data */ +#define CONFIG_SYS_GBL_DATA_SIZE 128 + +/* + * Hardware drivers + */ + +#define CONFIG_MX31_UART 1 +#define CONFIG_SYS_MX31_UART1 1 + +/* FPGA */ +#define CONFIG_QONG_FPGA 1 +#define CONFIG_FPGA_BASE (CS1_BASE) + +#ifdef CONFIG_QONG_FPGA +/* Ethernet */ +#define CONFIG_DNET 1 +#define CONFIG_DNET_BASE (CS1_BASE + QONG_FPGA_PERIPH_SIZE) +#define CONFIG_NET_MULTI 1 + +/* + * Reducing the ARP timeout from default 5 seconds to 200ms we speed up the + * initial TFTP transfer, should the user wish one, significantly. + */ +#define CONFIG_ARP_TIMEOUT 200UL + +#endif /* CONFIG_QONG_FPGA */ + +#define CONFIG_CONS_INDEX 1 +#define CONFIG_BAUDRATE 115200 +#define CONFIG_SYS_BAUDRATE_TABLE {9600, 19200, 38400, 57600, 115200} + +/*********************************************************** + * Command definition + ***********************************************************/ + +#include <config_cmd_default.h> + +#define CONFIG_CMD_PING +#define CONFIG_CMD_DHCP +#define CONFIG_CMD_NET +#define CONFIG_CMD_MII + +/* + * You can compile in a MAC address and your custom net settings by using + * the following syntax. + * + * #define CONFIG_ETHADDR xx:xx:xx:xx:xx:xx + * #define CONFIG_SERVERIP <server ip> + * #define CONFIG_IPADDR <board ip> + * #define CONFIG_GATEWAYIP <gateway ip> + * #define CONFIG_NETMASK <your netmask> + */ + +#define CONFIG_BOOTDELAY 5 + +#define CONFIG_LOADADDR 0x80800000 /* loadaddr env var */ + +#define xstr(s) str(s) +#define str(s) #s + +#define CONFIG_EXTRA_ENV_SETTINGS \ + "netdev=eth0\0" \ + "nfsargs=setenv bootargs root=/dev/nfs rw " \ + "nfsroot=${serverip}:${rootpath}\0" \ + "ramargs=setenv bootargs root=/dev/ram rw\0" \ + "addip=setenv bootargs ${bootargs} " \ + "ip=${ipaddr}:${serverip}:${gatewayip}:${netmask}" \ + ":${hostname}:${netdev}:off panic=1\0" \ + "addtty=setenv bootargs ${bootargs}" \ + " console=ttymxc0,${baudrate}\0" \ + "addmisc=setenv bootargs ${bootargs}\0" \ + "uboot_addr=a0000000\0" \ + "kernel_addr=a0080000\0" \ + "ramdisk_addr=a0300000\0" \ + "uboot=qong/u-boot.bin\0" \ + "kernel_addr_r=80800000\0" \ + "hostname=qong\0" \ + "bootfile=qong/uImage\0" \ + "rootpath=/opt/eldk-4.2-arm/armVFP\0" \ + "flash_self=run ramargs addip addtty addmisc;" \ + "bootm ${kernel_addr} ${ramdisk_addr}\0" \ + "flash_nfs=run nfsargs addip addtty addmisc;" \ + "bootm ${kernel_addr}\0" \ + "net_nfs=tftp ${kernel_addr_r} ${bootfile};" \ + "run nfsargs addip addtty addmisc;" \ + "bootm\0" \ + "load=tftp ${loadaddr} ${uboot}\0" \ + "update=protect off " xstr(CONFIG_SYS_MONITOR_BASE) \ + " +${filesize};era " xstr(CONFIG_SYS_MONITOR_BASE) \ + " +${filesize};cp.b ${fileaddr} " \ + xstr(CONFIG_SYS_MONITOR_BASE) " ${filesize};" \ + "setenv filesize;saveenv\0" \ + "upd=run load update\0" \ + +/* + * Miscellaneous configurable options + */ +#define CONFIG_SYS_LONGHELP /* undef to save memory */ +#define CONFIG_SYS_PROMPT "=> " +#define CONFIG_SYS_CBSIZE 256 /* Console I/O Buffer Size */ +/* Print Buffer Size */ +#define CONFIG_SYS_PBSIZE (CONFIG_SYS_CBSIZE + \ + sizeof(CONFIG_SYS_PROMPT) + 16) +#define CONFIG_SYS_MAXARGS 32 /* max number of command args */ +/* Boot Argument Buffer Size */ +#define CONFIG_SYS_BARGSIZE CONFIG_SYS_CBSIZE + +/* memtest works on first 255MB of RAM */ +#define CONFIG_SYS_MEMTEST_START PHYS_SDRAM_1 +#define CONFIG_SYS_MEMTEST_END (PHYS_SDRAM_1 + 0xff000000) + +#define CONFIG_SYS_LOAD_ADDR CONFIG_LOADADDR + +#define CONFIG_SYS_HZ 1000 + +#define CONFIG_CMDLINE_EDITING 1 + +#define CONFIG_MISC_INIT_R 1 +/*----------------------------------------------------------------------- + * Stack sizes + * + * The stack sizes are set up in start.S using the settings below + */ +#define CONFIG_STACKSIZE (128 * 1024) /* regular stack */ + +/*----------------------------------------------------------------------- + * Physical Memory Map + */ +#define CONFIG_NR_DRAM_BANKS 1 +#define PHYS_SDRAM_1 CSD0_BASE +#define PHYS_SDRAM_1_SIZE 0x10000000 /* 256 MB */ + +/*----------------------------------------------------------------------- + * FLASH and environment organization + */ +#define CONFIG_SYS_FLASH_BASE CS0_BASE +#define CONFIG_SYS_MAX_FLASH_BANKS 1 /* max number of memory banks */ +/* max number of sectors on one chip */ +#define CONFIG_SYS_MAX_FLASH_SECT 1024 +/* Monitor at beginning of flash */ +#define CONFIG_SYS_MONITOR_BASE CONFIG_SYS_FLASH_BASE +#define CONFIG_SYS_MONITOR_LEN 0x40000 /* Reserve 256KiB */ + +#define CONFIG_ENV_IS_IN_FLASH 1 +#define CONFIG_ENV_SECT_SIZE 0x20000 +#define CONFIG_ENV_SIZE CONFIG_ENV_SECT_SIZE +#define CONFIG_ENV_ADDR (CONFIG_SYS_FLASH_BASE + 0x40000) + +/* Address and size of Redundant Environment Sector */ +#define CONFIG_ENV_OFFSET_REDUND (CONFIG_ENV_OFFSET + CONFIG_ENV_SIZE) +#define CONFIG_ENV_SIZE_REDUND CONFIG_ENV_SIZE + +/*----------------------------------------------------------------------- + * CFI FLASH driver setup + */ +/* Flash memory is CFI compliant */ +#define CONFIG_SYS_FLASH_CFI 1 +/* Use drivers/cfi_flash.c */ +#define CONFIG_FLASH_CFI_DRIVER 1 +/* Use buffered writes (~10x faster) */ +#define CONFIG_SYS_FLASH_USE_BUFFER_WRITE 1 +/* Use hardware sector protection */ +#define CONFIG_SYS_FLASH_PROTECTION 1 + +/* + * JFFS2 partitions + */ +#define CONFIG_JFFS2_CMDLINE + +#endif /* __CONFIG_H */

On 00:59 Sun 08 Feb , Ilya Yanok wrote:
These patches add support for Dave/DENX QongEVB-LITE i.MX31-based board.
Signed-off-by: Ilya Yanok yanok@emcraft.com
applied to u-boot-arm
Best Regards, J.
participants (4)
-
Ben Warren
-
Ilya Yanok
-
Jean-Christophe PLAGNIOL-VILLARD
-
Wolfgang Denk