From: Ben Warren <biggerbadderben@gmail.com>
To: u-boot@lists.denx.de
Subject: [U-Boot] [PATCH 2/3] Add EP93xx ethernet driver
Date: Tue, 19 Jan 2010 13:30:21 -0800 [thread overview]
Message-ID: <4B56246D.8060803@gmail.com> (raw)
In-Reply-To: <20100119191622.GL16182@darwin>
Hi Matthias,
Matthias Kaehlcke wrote:
> Added ethernet driver for EP93xx SoCs
>
> Signed-off-by: Matthias Kaehlcke <matthias@kaehlcke.net>
> ---
> drivers/net/Makefile | 1 +
> drivers/net/ep93xx.c | 658 ++++++++++++++++++++++++++++++++++++++++++++++++++
> drivers/net/ep93xx.h | 145 +++++++++++
> include/common.h | 8 +-
> include/netdev.h | 1 +
> 5 files changed, 812 insertions(+), 1 deletions(-)
> create mode 100644 drivers/net/ep93xx.c
> create mode 100644 drivers/net/ep93xx.h
>
> diff --git a/drivers/net/Makefile b/drivers/net/Makefile
> index 904727e..0694133 100644
> --- a/drivers/net/Makefile
> +++ b/drivers/net/Makefile
> @@ -37,6 +37,7 @@ COBJS-$(CONFIG_DNET) += dnet.o
> COBJS-$(CONFIG_E1000) += e1000.o
> COBJS-$(CONFIG_EEPRO100) += eepro100.o
> COBJS-$(CONFIG_ENC28J60) += enc28j60.o
> +COBJS-$(CONFIG_EP93XX) += ep93xx.o
> COBJS-$(CONFIG_FEC_MXC) += fec_mxc.o
> COBJS-$(CONFIG_FSLDMAFEC) += fsl_mcdmafec.o mcfmii.o
> COBJS-$(CONFIG_FTMAC100) += ftmac100.o
> diff --git a/drivers/net/ep93xx.c b/drivers/net/ep93xx.c
> new file mode 100644
> index 0000000..150f7f8
> --- /dev/null
> +++ b/drivers/net/ep93xx.c
> @@ -0,0 +1,658 @@
> +/*
> + * Cirrus Logic EP93xx ethernet MAC / MII driver.
> + *
> + * Copyright (C) 2009 Matthias Kaehlcke <matthias@kaehlcke.net>
> + *
> + * Copyright (C) 2004, 2005
> + * Cory T. Tusar, Videon Central, Inc., <ctusar@videon-central.com>
> + *
> + * Based on the original eth.[ch] Cirrus Logic EP93xx Rev D. Ethernet Driver,
> + * which is
> + *
> + * (C) Copyright 2002 2003
> + * Adam Bezanson, Network Audio Technologies, Inc.
> + * <bezanson@netaudiotech.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.,
> + * 675 Mass Ave, Cambridge, MA 02139, USA.
> + */
> +#include <command.h>
> +#include <common.h>
> +#include <asm/arch/ep93xx.h>
> +#include <asm/io.h>
> +#include <malloc.h>
> +#include <miiphy.h>
> +#include <linux/types.h>
> +#include "ep93xx.h"
>
If the EP93XX is an SOC, you should name this driver something with
extra namespace, e.g. (ep93xx_mac) or whatever the documentation calls
it. The fact that you're including two files with the same name is a
bad sign.
> +
> +static int ep93xx_eth_send_packet(struct eth_device *dev,
> + volatile void * const packet, int const length);
> +static int ep93xx_eth_rcv_packet(struct eth_device *dev);
> +
> +/* ----------------------------------------------------------------------------
> + * EP93xx ethernet MAC functionality
> + */
> +#if defined(CONFIG_DRIVER_EP93XX_MAC)
>
What's this for?
> +
> +/* ep93xx_miiphy ops forward declarations */
> +static int ep93xx_miiphy_read(char * const dev, unsigned char const addr,
> + unsigned char const reg, unsigned short * const value);
> +static int ep93xx_miiphy_write(char * const dev, unsigned char const addr,
> + unsigned char const reg, unsigned short const value);
> +
> +/* Reserve memory for the MAC's private data */
> +static struct ep93xx_mac ep93xx_mac = { 0 };
>
Each instance of the driver should have its own private structure. In
other words, malloc() at runtime.
> +
> +#if defined(EP93XX_MAC_DEBUG)
> +/**
> + * Dump ep93xx_mac values to the terminal.
> + */
> +inline void dump_dev(void)
> +{
> + int i;
> +
> + printf("\ndump_dev()\n");
> + printf(" is_initialized %02X\n", ep93xx_mac.is_initialized);
> + printf(" rx_dq.base %08X\n", ep93xx_mac.rx_dq.base);
> + printf(" rx_dq.current %08X\n", ep93xx_mac.rx_dq.current);
> + printf(" rx_dq.end %08X\n", ep93xx_mac.rx_dq.end);
> + printf(" rx_sq.base %08X\n", ep93xx_mac.rx_sq.base);
> + printf(" rx_sq.current %08X\n", ep93xx_mac.rx_sq.current);
> + printf(" rx_sq.end %08X\n", ep93xx_mac.rx_sq.end);
> +
> + for (i = 0; i < NUMRXDESC; i++)
> + printf(" rx_buffer[%2.d] %08X\n", i, NetRxPackets[i]);
> +
> + printf(" tx_dq.base %08X\n", ep93xx_mac.tx_dq.base);
> + printf(" tx_dq.current %08X\n", ep93xx_mac.tx_dq.current);
> + printf(" tx_dq.end %08X\n", ep93xx_mac.tx_dq.end);
> + printf(" tx_sq.base %08X\n", ep93xx_mac.tx_sq.base);
> + printf(" tx_sq.current %08X\n", ep93xx_mac.tx_sq.current);
> + printf(" tx_sq.end %08X\n", ep93xx_mac.tx_sq.end);
> +}
>
Pass in eth_device and dereference private data instead of using
global. You get the idea...
> +
> +/**
> + * Dump all RX status queue entries to the terminal.
> + */
> +inline void dump_rx_status_queue(void)
> +{
> + int i;
> +
> + printf("\ndump_rx_status_queue()\n");
> + printf(" descriptor address word1 word2\n");
> + for (i = 0; i < NUMRXDESC; i++) {
> + printf(" [ %08X ] %08X %08X\n",
> + (ep93xx_mac.rx_sq.base + i),
> + (ep93xx_mac.rx_sq.base + i)->word1,
> + (ep93xx_mac.rx_sq.base + i)->word2);
> + }
> +}
> +
> +/**
> + * Dump all RX descriptor queue entries to the terminal.
> + */
> +inline void dump_rx_descriptor_queue(void)
> +{
> + int i;
> +
> + printf("\ndump_rx_descriptor_queue()\n");
> + printf(" descriptor address word1 word2\n");
> + for (i = 0; i < NUMRXDESC; i++) {
> + printf(" [ %08X ] %08X %08X\n",
> + (ep93xx_mac.rx_dq.base + i),
> + (ep93xx_mac.rx_dq.base + i)->word1,
> + (ep93xx_mac.rx_dq.base + i)->word2);
> + }
> +}
> +
> +/**
> + * Dump all TX descriptor queue entries to the terminal.
> + */
> +inline void dump_tx_descriptor_queue(void)
> +{
> + int i;
> +
> + printf("\ndump_tx_descriptor_queue()\n");
> + printf(" descriptor address word1 word2\n");
> + for (i = 0; i < NUMTXDESC; i++) {
> + printf(" [ %08X ] %08X %08X\n",
> + (ep93xx_mac.tx_dq.base + i),
> + (ep93xx_mac.tx_dq.base + i)->word1,
> + (ep93xx_mac.tx_dq.base + i)->word2);
> + }
> +}
> +
> +/**
> + * Dump all TX status queue entries to the terminal.
> + */
> +inline void dump_tx_status_queue(void)
> +{
> + int i;
> +
> + printf("\ndump_tx_status_queue()\n");
> + printf(" descriptor address word1\n");
> + for (i = 0; i < NUMTXDESC; i++) {
> + printf(" [ %08X ] %08X\n",
> + (ep93xx_mac.rx_sq.base + i),
> + (ep93xx_mac.rx_sq.base + i)->word1);
> + }
> +}
> +#else
> +#define dump_dev(x)
> +#define dump_rx_descriptor_queue()
> +#define dump_rx_status_queue()
> +#define dump_tx_descriptor_queue()
> +#define dump_tx_status_queue()
> +#endif /* defined(EP93XX_MAC_DEBUG) */
> +
> +/**
> + * Reset the EP93xx MAC by twiddling the soft reset bit and spinning until
> + * it's cleared.
> + */
> +static void ep93xx_mac_reset(void)
> +{
> + struct mac_regs *mac = (struct mac_regs *)MAC_BASE;
> + uint32_t value;
> +
> + debug("+ep93xx_mac_reset");
> +
> + value = readl(&mac->selfctl);
> + value |= SELFCTL_RESET;
> + writel(value, &mac->selfctl);
> +
> + while (readl(&mac->selfctl) & SELFCTL_RESET)
> + ; /* noop */
>
Most people write this as 'nop', but I won't be too picky...
> +
> + debug("-ep93xx_mac_reset");
> +}
> +
> +/* Eth device open */
> +static int ep93xx_eth_open(struct eth_device *dev, bd_t *bd)
> +{
> + struct mac_regs *mac = (struct mac_regs *)MAC_BASE;
>
Get this from dev->priv
> + uchar enetaddr[6];
> + int i;
> +
> + debug("+ep93xx_eth_open");
> +
> + /* Reset the MAC */
> + ep93xx_mac_reset();
> +
> + /* Reset the descriptor queues' current and end address values */
> + ep93xx_mac.tx_dq.current = ep93xx_mac.tx_dq.base;
> + ep93xx_mac.tx_dq.end = (ep93xx_mac.tx_dq.base + NUMTXDESC);
> +
> + ep93xx_mac.tx_sq.current = ep93xx_mac.tx_sq.base;
> + ep93xx_mac.tx_sq.end = (ep93xx_mac.tx_sq.base + NUMTXDESC);
> +
> + ep93xx_mac.rx_dq.current = ep93xx_mac.rx_dq.base;
> + ep93xx_mac.rx_dq.end = (ep93xx_mac.rx_dq.base + NUMRXDESC);
> +
> + ep93xx_mac.rx_sq.current = ep93xx_mac.rx_sq.base;
> + ep93xx_mac.rx_sq.end = (ep93xx_mac.rx_sq.base + NUMRXDESC);
> +
> + /*
> + * Set the transmit descriptor and status queues' base address,
> + * current address, and length registers. Set the maximum frame
> + * length and threshold. Enable the transmit descriptor processor.
> + */
> + writel((uint32_t)ep93xx_mac.tx_dq.base, &mac->txdq.badd);
> + writel((uint32_t)ep93xx_mac.tx_dq.base, &mac->txdq.curadd);
> + writel(sizeof(struct tx_descriptor) * NUMTXDESC, &mac->txdq.blen);
> +
> + writel((uint32_t)ep93xx_mac.tx_sq.base, &mac->txstsq.badd);
> + writel((uint32_t)ep93xx_mac.tx_sq.base, &mac->txstsq.curadd);
> + writel(sizeof(struct tx_status) * NUMTXDESC, &mac->txstsq.blen);
> +
> + writel(0x00040000, &mac->txdthrshld);
> + writel(0x00040000, &mac->txststhrshld);
> +
> + writel((TXSTARTMAX << 0) | (PKTSIZE_ALIGN << 16), &mac->maxfrmlen);
> + writel(BMCTL_TXEN, &mac->bmctl);
> +
> + /*
> + * Set the receive descriptor and status queues' base address,
> + * current address, and length registers. Enable the receive
> + * descriptor processor.
> + */
> + writel((uint32_t)ep93xx_mac.rx_dq.base, &mac->rxdq.badd);
> + writel((uint32_t)ep93xx_mac.rx_dq.base, &mac->rxdq.curadd);
> + writel(sizeof(struct rx_descriptor) * NUMRXDESC, &mac->rxdq.blen);
> +
> + writel((uint32_t)ep93xx_mac.rx_sq.base, &mac->rxstsq.badd);
> + writel((uint32_t)ep93xx_mac.rx_sq.base, &mac->rxstsq.curadd);
> + writel(sizeof(struct rx_status) * NUMRXDESC, &mac->rxstsq.blen);
> +
> + writel(0x00040000, &mac->rxdthrshld);
> +
> + writel(BMCTL_RXEN, &mac->bmctl);
> +
> + writel(0x00040000, &mac->rxststhrshld);
> +
> + /* Wait until the receive descriptor processor is active */
> + while (!(readl(&mac->bmsts) & BMSTS_RXACT))
> + ; /* noop */
> +
> + /*
> + * Initialize the RX descriptor queue. Clear the TX descriptor queue.
> + * Clear the RX and TX status queues. Enqueue the RX descriptor and
> + * status entries to the MAC.
> + */
> + for (i = 0; i < NUMRXDESC; i++) {
> + /* set buffer address */
> + (ep93xx_mac.rx_dq.base + i)->word1 = (uint32_t)NetRxPackets[i];
> +
> + /* set buffer length, clear buffer index and NSOF */
> + (ep93xx_mac.rx_dq.base + i)->word2 = PKTSIZE_ALIGN;
> + }
> +
> + memset(ep93xx_mac.tx_dq.base, 0,
> + (sizeof(struct tx_descriptor) * NUMTXDESC));
> + memset(ep93xx_mac.rx_sq.base, 0,
> + (sizeof(struct rx_status) * NUMRXDESC));
> + memset(ep93xx_mac.tx_sq.base, 0,
> + (sizeof(struct tx_status) * NUMTXDESC));
> +
> + writel(NUMRXDESC, &mac->rxdqenq);
> + writel(NUMRXDESC, &mac->rxstsqenq);
> +
> + /* Set the primary MAC address */
> + writel(AFP_IAPRIMARY, &mac->afp);
> + eth_getenv_enetaddr("ethaddr", enetaddr);
>
Get this from dev->enetaddr.
> + writel(enetaddr[0] | (enetaddr[1] << 8) |
> + (enetaddr[2] << 16) | (enetaddr[3] << 24),
> + &mac->indad);
> + writel(enetaddr[4] | (enetaddr[5] << 8), &mac->indad_upper);
> +
> + /* Turn on RX and TX */
> + writel(RXCTL_IA0 | RXCTL_BA | RXCTL_SRXON |
> + RXCTL_RCRCA | RXCTL_MA, &mac->rxctl);
> + writel(TXCTL_STXON, &mac->txctl);
> +
> + /* Dump data structures if we're debugging */
> + dump_dev();
> + dump_rx_descriptor_queue();
> + dump_rx_status_queue();
> + dump_tx_descriptor_queue();
> + dump_tx_status_queue();
> +
> + debug("-ep93xx_eth_open");
> +
> + return 1;
> +}
> +
> +/**
> + * Halt EP93xx MAC transmit and receive by clearing the TxCTL and RxCTL
> + * registers.
> + */
> +static void ep93xx_eth_close(struct eth_device *dev)
> +{
> + struct mac_regs *mac = (struct mac_regs *)MAC_BASE;
> +
> + debug("+ep93xx_eth_close");
> +
> + writel(0x00000000, &mac->rxctl);
> + writel(0x00000000, &mac->txctl);
> +
> + debug("-ep93xx_eth_close");
> +}
> +
> +#if defined(CONFIG_MII)
> +int ep93xx_miiphy_initialize(bd_t * const bd)
> +{
> + miiphy_register("ep93xx_eth0", ep93xx_miiphy_read, ep93xx_miiphy_write);
> + return 0;
> +}
> +#endif
> +
> +/**
> + * Initialize the EP93xx MAC. The MAC hardware is reset. Buffers are
> + * allocated, if necessary, for the TX and RX descriptor and status queues,
> + * as well as for received packets. The EP93XX MAC hardware is initialized.
> + * Transmit and receive operations are enabled.
> + */
> +int ep93xx_eth_init(bd_t * const bd)
>
Please call this ep93xx_eth_initialize(), as all other drivers do. It
doesn't look like you use bd anywhere, so choose parameters that are
more relevant. Drivers for memory-mapped devices typically pass in a
base address and index (see cs8900.c as an example).
> +{
> + int ret = -1;
> + struct eth_device *dev;
> +
> + debug("+ep93xx_eth_init");
> +
> + /* Parameter check */
> + BUG_ON(bd == NULL);
> +
> + /*
> + * Allocate space for the queues and RX packet buffers if we're not
> + * already initialized
> + */
> + if (!ep93xx_mac.is_initialized) {\
>
As I mentioned earlier, each instance of the driver needs its own
private struct. Please malloc() and attach to dev->priv
> + ep93xx_mac.tx_dq.base = calloc(NUMTXDESC,
> + sizeof(struct tx_descriptor));
> + if (ep93xx_mac.tx_dq.base == NULL) {
> + error("calloc() failed");
> + goto eth_init_failed_0;
> + }
> +
> + ep93xx_mac.tx_sq.base = calloc(NUMTXDESC,
> + sizeof(struct tx_status));
> + if (ep93xx_mac.tx_sq.base == NULL) {
> + error("calloc() failed");
> + goto eth_init_failed_1;
> + }
> +
> + ep93xx_mac.rx_dq.base = calloc(NUMRXDESC,
> + sizeof(struct rx_descriptor));
> + if (ep93xx_mac.rx_dq.base == NULL) {
> + error("calloc() failed");
> + goto eth_init_failed_2;
> + }
> +
> + ep93xx_mac.rx_sq.base = calloc(NUMRXDESC,
> + sizeof(struct rx_status));
> + if (ep93xx_mac.rx_sq.base == NULL) {
> + error("calloc() failed");
> + goto eth_init_failed_3;
> + }
> +
> + dev = malloc(sizeof *dev);
> + if (dev == NULL) {
> + error("malloc() failed");
> + goto eth_init_failed_4;
> + }
> +
> + memset(dev, 0, sizeof *dev);
> + sprintf(dev->name, "ep93xx MAC");
> + dev->iobase = 0;
>
dev->iobase is a convenient place to put your base address.
> + dev->init = ep93xx_eth_open;
> + dev->halt = ep93xx_eth_close;
> + dev->send = ep93xx_eth_send_packet;
> + dev->recv = ep93xx_eth_rcv_packet;
> +
> + eth_register(dev);
> +
> + /*
> + * Set is_initialized flag so we don't go through allocation
> + * portion of init again.
> + */
> + ep93xx_mac.is_initialized = 1;
>
You probably don't need this.
> + }
> +
> + /* Done! */
> + ret = 0;
> + goto eth_init_done;
> +
> +eth_init_failed_4:
> + free(ep93xx_mac.rx_sq.base);
> + /* Fall through */
> +
> +eth_init_failed_3:
> + free(ep93xx_mac.rx_dq.base);
> + /* Fall through */
> +
> +eth_init_failed_2:
> + free(ep93xx_mac.tx_sq.base);
> + /* Fall through */
> +
> +eth_init_failed_1:
> + free(ep93xx_mac.tx_dq.base);
> + /* Fall through */
> +
> +eth_init_failed_0:
> + /* Fall through */
> +
> +eth_init_done:
> + debug("-ep93xx_eth_init %d", ret);
> + return ret;
> +}
> +
> +/**
> + * Copy a frame of data from the MAC into the protocol layer for further
> + * processing.
> + */
> +static int ep93xx_eth_rcv_packet(struct eth_device *dev)
>
Why not move this up higher to avoid the forward declarations?
> +{
> + struct mac_regs *mac = (struct mac_regs *)MAC_BASE;
> + int len = -1;
> +
> + debug("+ep93xx_eth_rcv_packet");
> +
> + if (RX_STATUS_RFP(ep93xx_mac.rx_sq.current)) {
> + if (RX_STATUS_RWE(ep93xx_mac.rx_sq.current)) {
> + /*
> + * We have a good frame. Extract the frame's length
> + * from the current rx_status_queue entry, and copy
> + * the frame's data into NetRxPackets[] of the
> + * protocol stack. We track the total number of
> + * bytes in the frame (nbytes_frame) which will be
> + * used when we pass the data off to the protocol
> + * layer via NetReceive().
> + */
> + len = RX_STATUS_FRAME_LEN(ep93xx_mac.rx_sq.current);
> +
> + NetReceive((uchar *)ep93xx_mac.rx_dq.current->word1,
> + len);
> +
> + debug("reporting %d bytes...\n", len);
> + } else {
> + /* Do we have an erroneous packet? */
> + error("packet rx error, status %08X %08X",
> + ep93xx_mac.rx_sq.current->word1,
> + ep93xx_mac.rx_sq.current->word2);
> + dump_rx_descriptor_queue();
> + dump_rx_status_queue();
> + }
> +
> + /*
> + * Clear the associated status queue entry, and
> + * increment our current pointers to the next RX
> + * descriptor and status queue entries (making sure
> + * we wrap properly).
> + */
> + memset((void *)ep93xx_mac.rx_sq.current, 0,
> + sizeof(struct rx_status));
> +
> + ep93xx_mac.rx_sq.current++;
> + if (ep93xx_mac.rx_sq.current >= ep93xx_mac.rx_sq.end)
> + ep93xx_mac.rx_sq.current = ep93xx_mac.rx_sq.base;
> +
> + ep93xx_mac.rx_dq.current++;
> + if (ep93xx_mac.rx_dq.current >= ep93xx_mac.rx_dq.end)
> + ep93xx_mac.rx_dq.current = ep93xx_mac.rx_dq.base;
> +
> + /*
> + * Finally, return the RX descriptor and status entries
> + * back to the MAC engine, and loop again, checking for
> + * more descriptors to process.
> + */
> + writel(1, &mac->rxdqenq);
> + writel(1, &mac->rxstsqenq);
> + } else {
> + len = 0;
> + }
> +
> + debug("-ep93xx_eth_rcv_packet %d", len);
> + return len;
> +}
> +
> +/**
> + * Send a block of data via ethernet.
> + */
> +static int ep93xx_eth_send_packet(struct eth_device *dev,
> + volatile void * const packet, int const length)
> +{
> + struct mac_regs *mac = (struct mac_regs *)MAC_BASE;
> + int ret = -1;
> +
> + debug("+ep93xx_eth_send_packet");
> +
> + /* Parameter check */
> + BUG_ON(packet == NULL);
> +
> + /*
> + * Initialize the TX descriptor queue with the new packet's info.
> + * Clear the associated status queue entry. Enqueue the packet
> + * to the MAC for transmission.
> + */
> +
> + /* set buffer address */
> + ep93xx_mac.tx_dq.current->word1 = (uint32_t)packet;
> +
> + /* set buffer length and EOF bit */
> + ep93xx_mac.tx_dq.current->word2 = length | TX_DESC_EOF;
> +
> + /* clear tx status */
> + ep93xx_mac.tx_sq.current->word1 = 0;
> +
> + /* enqueue the TX descriptor */
> + writel(1, &mac->txdqenq);
> +
> + /* wait for the frame to become processed */
> + while (!TX_STATUS_TXFP(ep93xx_mac.tx_sq.current))
> + ; /* noop */
> +
> + if (!TX_STATUS_TXWE(ep93xx_mac.tx_sq.current)) {
> + error("packet tx error, status %08X",
> + ep93xx_mac.tx_sq.current->word1);
> + dump_tx_descriptor_queue();
> + dump_tx_status_queue();
> +
> + /* TODO: Add better error handling? */
> + goto eth_send_failed_0;
> + }
> +
> + ret = 0;
> + /* Fall through */
> +
> +eth_send_failed_0:
> + debug("-ep93xx_eth_send_packet %d", ret);
> + return ret;
> +}
> +#endif /* defined(CONFIG_DRIVER_EP93XX_MAC) */
> +
> +/* -----------------------------------------------------------------------------
> + * EP93xx ethernet MII functionality.
> + */
> +#if defined(CONFIG_MII)
> +
> +/**
> + * Maximum MII address we support
> + */
> +#define MII_ADDRESS_MAX (31)
>
Parens not needed
> +
> +/**
> + * Maximum MII register address we support
> + */
> +#define MII_REGISTER_MAX (31)
> +
> +/**
> + * Read a 16-bit value from an MII register.
> + */
> +static int ep93xx_miiphy_read(char * const dev, unsigned char const addr,
> + unsigned char const reg, unsigned short * const value)
> +{
> + struct mac_regs *mac = (struct mac_regs *)MAC_BASE;
> + int ret = -1;
> + uint32_t self_ctl;
> +
> + debug("+ep93xx_miiphy_read");
> +
> + /* Parameter checks */
> + BUG_ON(dev == NULL);
> + BUG_ON(addr > MII_ADDRESS_MAX);
> + BUG_ON(reg > MII_REGISTER_MAX);
> + BUG_ON(value == NULL);
> +
> + /*
> + * Save the current SelfCTL register value. Set MAC to suppress
> + * preamble bits. Wait for any previous MII command to complete
> + * before issuing the new command.
> + */
> + self_ctl = readl(&mac->selfctl);
> +#if defined(CONFIG_MII_SUPPRESS_PREAMBLE)
> + writel(self_ctl & ~(1 << 8), &mac->selfctl);
> +#endif /* defined(CONFIG_MII_SUPPRESS_PREAMBLE) */
> +
> + while (readl(&mac->miists) & MIISTS_BUSY)
> + ; /* noop */
> +
> + /*
> + * Issue the MII 'read' command. Wait for the command to complete.
> + * Read the MII data value.
> + */
> + writel(MIICMD_OPCODE_READ | ((uint32_t)addr << 5) | (uint32_t)reg,
> + &mac->miicmd);
> + while (readl(&mac->miists) & MIISTS_BUSY)
> + ; /* noop */
> +
> + *value = (unsigned short)readl(&mac->miidata);
> +
> + /* Restore the saved SelfCTL value and return. */
> + writel(self_ctl, &mac->selfctl);
> +
> + ret = 0;
> + /* Fall through */
> +
> + debug("-ep93xx_miiphy_read");
> + return ret;
> +}
> +
> +/**
> + * Write a 16-bit value to an MII register.
> + */
> +static int ep93xx_miiphy_write(char * const dev, unsigned char const addr,
> + unsigned char const reg, unsigned short const value)
> +{
> + struct mac_regs *mac = (struct mac_regs *)MAC_BASE;
> + int ret = -1;
> + uint32_t self_ctl;
> +
> + debug("+ep93xx_miiphy_write");
> +
> + /* Parameter checks */
> + BUG_ON(dev == NULL);
> + BUG_ON(addr > MII_ADDRESS_MAX);
> + BUG_ON(reg > MII_REGISTER_MAX);
> +
> + /*
> + * Save the current SelfCTL register value. Set MAC to suppress
> + * preamble bits. Wait for any previous MII command to complete
> + * before issuing the new command.
> + */
> + self_ctl = readl(&mac->selfctl);
> +#if defined(CONFIG_MII_SUPPRESS_PREAMBLE)
> + writel(self_ctl & ~(1 << 8), &mac->selfctl);
> +#endif /* defined(CONFIG_MII_SUPPRESS_PREAMBLE) */
> +
> + while (readl(&mac->miists) & MIISTS_BUSY)
> + ; /* noop */
> +
> + /* Issue the MII 'write' command. Wait for the command to complete. */
> + writel((uint32_t)value, &mac->miidata);
> + writel(MIICMD_OPCODE_WRITE | ((uint32_t)addr << 5) | (uint32_t)reg,
> + &mac->miicmd);
> + while (readl(&mac->miists) & MIISTS_BUSY)
> + ; /* noop */
> +
> + /* Restore the saved SelfCTL value and return. */
> + writel(self_ctl, &mac->selfctl);
> +
> + ret = 0;
> + /* Fall through */
> +
> + debug("-ep93xx_miiphy_write");
> + return ret;
> +}
> +#endif /* defined(CONFIG_MII) */
> diff --git a/drivers/net/ep93xx.h b/drivers/net/ep93xx.h
> new file mode 100644
> index 0000000..ca450ed
> --- /dev/null
> +++ b/drivers/net/ep93xx.h
> @@ -0,0 +1,145 @@
> +/*
> + * Copyright (C) 2009 Matthias Kaehlcke <matthias@kaehlcke.net>
> + *
> + * Copyright (C) 2004, 2005
> + * Cory T. Tusar, Videon Central, Inc., <ctusar@videon-central.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 _ETH_H
> +#define _ETH_H
> +
> +#include <net.h>
> +
> +/**
> + * #define this to dump device status and queue info during initialization and
> + * following errors.
> + */
> +#undef EP93XX_MAC_DEBUG
> +
> +/**
> + * Number of descriptor and status entries in our RX queues.
> + * It must be power of 2 !
> + */
> +#define NUMRXDESC PKTBUFSRX
> +
> +/**
> + * Number of descriptor and status entries in our TX queues.
> + */
> +#define NUMTXDESC 1
> +
> +/**
> + * 944 = (1024 - 64) - 16, Fifo size - Minframesize - 16 (Chip FACT)
> + */
> +#define TXSTARTMAX 944
> +
> +/**
> + * Receive descriptor queue entry
> + */
> +struct rx_descriptor {
> + uint32_t word1;
> + uint32_t word2;
> +} __attribute__((packed));
>
Why do you need to pack 32-bit integers?
> +
> +/**
> + * Receive status queue entry
> + */
> +struct rx_status {
> + uint32_t word1;
> + uint32_t word2;
> +} __attribute__((packed));
> +
> +#define RX_STATUS_RWE(rx_status) ((rx_status->word1 >> 30) & 0x01)
> +#define RX_STATUS_RFP(rx_status) ((rx_status->word1 >> 31) & 0x01)
> +#define RX_STATUS_FRAME_LEN(rx_status) (rx_status->word2 & 0xFFFF)
> +
> +
> +/**
> + * Transmit descriptor queue entry
> + */
> +struct tx_descriptor {
> + uint32_t word1;
> + uint32_t word2;
> +} __attribute__((packed));
> +
> +#define TX_DESC_EOF (1 << 31)
> +
> +/**
> + * Transmit status queue entry
> + */
> +struct tx_status {
> + uint32_t word1;
> +} __attribute__((packed));
> +
> +#define TX_STATUS_TXWE(tx_status) (((tx_status)->word1 >> 30) & 0x01)
> +#define TX_STATUS_TXFP(tx_status) (((tx_status)->word1 >> 31) & 0x01)
> +
> +/**
> + * Transmit descriptor queue
> + */
> +struct tx_descriptor_queue {
> + struct tx_descriptor *base;
> + struct tx_descriptor *current;
> + struct tx_descriptor *end;
> +};
> +
> +/**
> + * Transmit status queue
> + */
> +struct tx_status_queue {
> + struct tx_status *base;
> + volatile struct tx_status *current;
> + struct tx_status *end;
> +};
> +
> +/**
> + * Receive descriptor queue
> + */
> +struct rx_descriptor_queue {
> + struct rx_descriptor *base;
> + struct rx_descriptor *current;
> + struct rx_descriptor *end;
> +};
> +
> +/**
> + * Receive status queue
> + */
> +struct rx_status_queue {
> + struct rx_status *base;
> + volatile struct rx_status *current;
> + struct rx_status *end;
> +};
> +
> +/**
> + * EP93xx MAC private data structure
> + */
> +struct ep93xx_mac {
> + int is_initialized;
> +
> + struct rx_descriptor_queue rx_dq;
> + struct rx_status_queue rx_sq;
> + void *rx_buffer[NUMRXDESC];
> +
> + struct tx_descriptor_queue tx_dq;
> + struct tx_status_queue tx_sq;
> +};
> +
> +#endif
> diff --git a/include/common.h b/include/common.h
> index 391790a..c0dfc45 100644
> --- a/include/common.h
> +++ b/include/common.h
> @@ -123,6 +123,11 @@ typedef volatile unsigned char vu_char;
> #define debugX(level,fmt,args...)
> #endif /* DEBUG */
>
> +#define error(fmt, args...) do { \
> + printf("ERROR: " fmt "\nat %s:%d/%s()\n", \
> + ##args, __FILE__, __LINE__, __func__); \
> +} while (0)
> +
>
Is this really needed?
> #ifndef BUG
> #define BUG() do { \
> printf("BUG: failure at %s:%d/%s()!\n", __FILE__, __LINE__, __FUNCTION__); \
> @@ -502,7 +507,8 @@ ulong get_PCI_freq (void);
> #endif
> #if defined(CONFIG_S3C24X0) || \
> defined(CONFIG_LH7A40X) || \
> - defined(CONFIG_S3C6400)
> + defined(CONFIG_S3C6400) || \
> + defined(CONFIG_EP93XX)
> ulong get_FCLK (void);
> ulong get_HCLK (void);
> ulong get_PCLK (void);
>
I don't see these referenced anywhere. How do they apply to this driver?
> diff --git a/include/netdev.h b/include/netdev.h
> index a9d5ec9..7800ff1 100644
> --- a/include/netdev.h
> +++ b/include/netdev.h
> @@ -49,6 +49,7 @@ int davinci_emac_initialize(void);
> 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 ep93xx_eth_init(bd_t * const bd);
> int eth_3com_initialize (bd_t * bis);
> int fec_initialize (bd_t *bis);
> int fecmxc_initialize (bd_t *bis);
>
regards,
Ben
next prev parent reply other threads:[~2010-01-19 21:30 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <cover.1263903884.git.matthias@kaehlcke.net>
2010-01-19 19:16 ` [U-Boot] [PATCH 1/3] ARM: Add support for EP93xx SoCs Matthias Kaehlcke
2010-01-19 21:52 ` Wolfgang Denk
2010-01-19 19:16 ` [U-Boot] [PATCH 2/3] Add EP93xx ethernet driver Matthias Kaehlcke
2010-01-19 21:30 ` Ben Warren [this message]
2010-01-19 21:42 ` Matthias Kaehlcke
2010-01-19 19:16 ` [U-Boot] [PATCH 3/3] Add support for EDB93xx boards Matthias Kaehlcke
2010-01-19 21:58 ` Wolfgang Denk
[not found] <cover.1265053904.git.matthias@kaehlcke.net>
2010-02-01 20:29 ` [U-Boot] [PATCH 2/3] Add EP93xx ethernet driver Matthias Kaehlcke
[not found] <cover.1264955406.git.matthias@kaehlcke.net>
2010-01-31 16:39 ` Matthias Kaehlcke
2010-02-01 5:24 ` Ben Warren
2010-02-01 7:12 ` Matthias Kaehlcke
[not found] <cover.1264351928.git.matthias@kaehlcke.net>
2010-01-24 16:56 ` Matthias Kaehlcke
2010-01-25 4:09 ` Ben Warren
2009-12-23 19:26 [U-Boot] [PATCH 2/3] Add EP93XX " Matthias Kaehlcke
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4B56246D.8060803@gmail.com \
--to=biggerbadderben@gmail.com \
--cc=u-boot@lists.denx.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.