From: Ben Warren <bwarren@qstreams.com>
To: u-boot@lists.denx.de
Subject: [U-Boot-Users] [PATCH] net: sh: Renesas SH7763 Ethernet device support
Date: Mon, 09 Jun 2008 23:20:18 -0700 [thread overview]
Message-ID: <484E1D22.3060809@qstreams.com> (raw)
In-Reply-To: <4848E49C.9020709@renesas.com>
Hi Nobuhiro,
Nobuhiro Iwamatsu wrote:
> Renesas SH7763 has 2 channel Ethernet device.
> This is 10/100/1000 Base support.
> But this patch check 10/100 Base only.
>
> Signed-off-by: Nobuhiro Iwamatsu <iwamatsu.nobuhiro@renesas.com>
> ---
> drivers/net/Makefile | 1 +
> drivers/net/sh_eth.c | 599 ++++++++++++++++++++++++++++++++++++++++++++++++++
> drivers/net/sh_eth.h | 195 ++++++++++++++++
>
Where's the code that has this driver being initialized by net/eth.c? Is
it in another patch or should I just go to bed?
> 3 files changed, 795 insertions(+), 0 deletions(-)
> create mode 100644 drivers/net/sh_eth.c
> create mode 100644 drivers/net/sh_eth.h
>
> diff --git a/drivers/net/Makefile b/drivers/net/Makefile
> index 5b031c9..e2a6b35 100644
> --- a/drivers/net/Makefile
> +++ b/drivers/net/Makefile
> @@ -66,6 +66,7 @@ COBJS-y += uli526x.o
> COBJS-y += 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/sh_eth.c b/drivers/net/sh_eth.c
> new file mode 100644
> index 0000000..869a8f0
> --- /dev/null
> +++ b/drivers/net/sh_eth.c
> @@ -0,0 +1,599 @@
> +/*
> + * sh_eth.c - Driver for Renesas SH7763's ethernet controler.
> + *
> + * Copyright (C) 2008 Renesas Solutions Corp.
> + * Copyright (c) 2008 Nobuhiro Iwamatsu
> + * Copyright (c) 2007 Carlos Munoz <carlos@kenati.com>
> + *
> + * 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 <config.h>
> +#include <common.h>
> +#include <malloc.h>
> +#include <net.h>
> +#include <asm/errno.h>
> +
> +#include "sh_eth.h"
> +
> +#ifndef CONFIG_SH_ETHER_USE_PORT
> +# error "Please define CONFIG_SH_ETHER_USE_PORT"
> +#endif
> +#ifndef CONFIG_SH_ETHER_PHY_ADDR
> +# error "Please define CONFIG_SH_ETHER_PHY_ADDR"
> +#endif
> +
> +extern int eth_init(bd_t *bd);
> +extern void eth_halt(void);
> +extern int eth_rx(void);
> +extern int eth_send(volatile void *packet, int length);
> +
> +static struct dev_info_s *dev;
> +
> +/*
> + * Bits are written to the PHY serially using the
> + * PIR register, just like a bit banger.
> + */
> +static void sh_eth_mii_write_phy_bits(int port, u32 val, int len)
> +{
> + int i;
> + u32 pir;
> +
> + /* Bit positions is 1 less than the number of bits */
> + for (i = len - 1; i >= 0; i--) {
> + /* Write direction, bit to write, clock is low */
> + pir = 2 | ((val & 1 << i) ? 1 << 2 : 0);
> + OUT32(PIR(port), pir);
> + PHY_DELAY;
> + /* Write direction, bit to write, clock is high */
> + pir = 3 | ((val & 1 << i) ? 1 << 2 : 0);
> + OUT32(PIR(port), pir);
> + PHY_DELAY;
> + /* Write direction, bit to write, clock is low */
> + pir = 2 | ((val & 1 << i) ? 1 << 2 : 0);
> + OUT32(PIR(port), pir);
> + PHY_DELAY;
> + }
> +}
> +
> +static void sh_eth_mii_bus_release(int port)
> +{
> + /* Read direction, clock is low */
> + OUT32(PIR(port), 0);
> + PHY_DELAY;
> + /* Read direction, clock is high */
> + OUT32(PIR(port), 1);
> + PHY_DELAY;
> + /* Read direction, clock is low */
> + OUT32(PIR(port), 0);
> + PHY_DELAY;
> +}
> +
> +static void sh_eth_mii_ind_bus_release(int port)
> +{
> + /* Read direction, clock is low */
> + OUT32(PIR(port), 0);
> + PHY_DELAY;
> +}
> +
> +static int sh_eth_mii_read_phy_bits(int port, u32 * val, int len)
> +{
> + int i;
> + u32 pir;
> +
> + *val = 0;
> + for (i = len - 1; i >= 0; i--) {
> + /* Read direction, clock is high */
> + OUT32(PIR(port), 1);
> + PHY_DELAY;
> + /* Read bit */
> + pir = IN32(PIR(port));
> + *val |= (pir & 8) ? 1 << i : 0;
> + /* Read direction, clock is low */
> + OUT32(PIR(port), 0);
> + PHY_DELAY;
> + }
> +
> + return 0;
> +}
> +
> +/* To read a phy register, mii managements frames are sent to the phy.
> + The frames look like this:
> + pre (32 bits): 0xffff ffff
> + st (2 bits): 01
> + op (2bits): 10: read 01: write
> + phyad (5 bits): xxxxx
> + regad (5 bits): xxxxx
> + ta (Bus release):
> + data (16 bits): read data */
> +static u32 sh_eth_mii_read_phy_reg(int port, u8 phy_addr, int reg)
> +{
> + u32 val;
> +
> + /* Sent mii management frame */
> + /* pre */
> + sh_eth_mii_write_phy_bits(port, 0xffffffff, 32);
> + /* st (start of frame) */
> + sh_eth_mii_write_phy_bits(port, 0x1, 2);
> + /* op (code) */
> + sh_eth_mii_write_phy_bits(port, 0x2, 2);
> + /* phy address */
> + sh_eth_mii_write_phy_bits(port, phy_addr, 5);
> + /* Register to read */
> + sh_eth_mii_write_phy_bits(port, reg, 5);
> +
> + /* Bus release */
> + sh_eth_mii_bus_release(port);
> +
> + /* Read register */
> + sh_eth_mii_read_phy_bits(port, &val, 16);
> +
> + return val;
> +}
> +
> +/* To write a phy register, mii managements frames are sent to the phy.
> + The frames look like this:
> + pre (32 bits): 0xffff ffff
> + st (2 bits): 01
> + op (2bits): 10: read 01: write
> + phyad (5 bits): xxxxx
> + regad (5 bits): xxxxx
> + ta (2 bits): 10
> + data (16 bits): write data
> + idle (Independent bus release) */
> +static void sh_eth_mii_write_phy_reg(int port, u8 phy_addr, int reg, u16 val)
> +{
> + /* Sent mii management frame */
> + /* pre */
> + sh_eth_mii_write_phy_bits(port, 0xffffffff, 32);
> + /* st (start of frame) */
> + sh_eth_mii_write_phy_bits(port, 0x1, 2);
> + /* op (code) */
> + sh_eth_mii_write_phy_bits(port, 0x1, 2);
> + /* phy address */
> + sh_eth_mii_write_phy_bits(port, phy_addr, 5);
> + /* Register to read */
> + sh_eth_mii_write_phy_bits(port, reg, 5);
> + /* ta */
> + sh_eth_mii_write_phy_bits(port, 0x2, 2);
> + /* Write register data */
> + sh_eth_mii_write_phy_bits(port, val, 16);
> +
> + /* Independent bus release */
> + sh_eth_mii_ind_bus_release(port);
> +}
> +
> +void eth_halt(void)
> +{
> +}
> +
> +int eth_send(volatile void *packet, int len)
> +{
> + int port = dev->port;
> + struct port_info_s *port_info = &dev->port_info[port];
> + int timeout;
> + int rc = 0;
> +
> + if (!packet || len > 0xffff) {
> + printf("eth_send: Invalid argument\n");
> + return -EINVAL;
> + }
> +
> + /* packet must be a 4 byte boundary */
> + if ((int)packet & (4 - 1)) {
> + printf("eth_send: packet not 4 byte alligned\n");
> + return -EFAULT;
> + }
> +
> + /* Update tx descriptor */
> + port_info->tx_desc_cur->td2 = ADDR_TO_PHY(packet);
> + port_info->tx_desc_cur->td1 = len << 16;
> + /* Must preserve the end of descriptor list indication */
> + if (port_info->tx_desc_cur->td0 & TDLE)
> + port_info->tx_desc_cur->td0 = TACT | TFP | TDLE;
> + else
> + port_info->tx_desc_cur->td0 = TACT | TFP;
> +
> + /* Restart the transmitter if disabled */
> + if (!(IN32(EDTRR(port)) & 0x3))
> + OUT32(EDTRR(port), 0x3);
> +
> + /* Wait until packet is transmitted */
> + timeout = 1000;
> + while (port_info->tx_desc_cur->td0 & TACT && timeout--)
> + udelay(100);
> +
> + if (timeout < 0) {
> + printf("eth_send: transmit timeout\n");
> + rc = -1;
> + goto err;
> + }
> +
> + err:
> + port_info->tx_desc_cur++;
> + if (port_info->tx_desc_cur >= port_info->tx_desc_base + NUM_TX_DESC)
> + port_info->tx_desc_cur = port_info->tx_desc_base;
> +
> + return rc;
> +}
> +
> +int eth_rx(void)
> +{
> + int port = dev->port;
> + struct port_info_s *port_info = &dev->port_info[port];
> + int len = 0;
> + volatile u8 *packet;
> +
> + /* Check if the rx descriptor is ready */
> + if (!(port_info->rx_desc_cur->rd0 & RACT)) {
> + /* Check for errors */
> + if (!(port_info->rx_desc_cur->rd0 & RFE)) {
> + len = port_info->rx_desc_cur->rd1 & 0xffff;
> + packet = (volatile u8 *)
> + ADDR_TO_P2(port_info->rx_desc_cur->rd2);
> + NetReceive(packet, len);
> + }
> +
> + /* Make current descriptor available again */
> + if (port_info->rx_desc_cur->rd0 & RDLE)
> + port_info->rx_desc_cur->rd0 = RACT | RDLE;
> + else
> + port_info->rx_desc_cur->rd0 = RACT;
> +
> + /* Point to the next descriptor */
> + port_info->rx_desc_cur++;
> + if (port_info->rx_desc_cur >=
> + port_info->rx_desc_base + NUM_RX_DESC)
> + port_info->rx_desc_cur = port_info->rx_desc_base;
> + }
> +
> + /* Restart the receiver if disabled */
> + if (!(IN32(EDRRR(port)) & 0x1))
> + OUT32(EDRRR(port), 0x1);
> +
> + return len;
> +}
> +
> +static int sh_eth_reset(struct dev_info_s *dev)
> +{
> + int port = dev->port;
> + int i;
> +
> + /* Start e-dmac transmitter and receiver */
> + OUT32(EDSR(port), 0x3);
> +
> + /* Perform a software reset and wait for it to complete */
> + OUT32(EDMR(port), 0x3);
> + for (i = 0; i < 1000; i++) {
> + if (!(IN32(EDMR(port)) & 0x3))
> + break;
> +
> + udelay(1000);
> + }
> +
> + if (i == 100) {
> + printf("Error: Software reset timeout\n");
> + return -1;
> + }
> +
> + return 0;
> +}
> +
> +static int sh_eth_tx_desc_init(struct dev_info_s *dev)
> +{
> + int port = dev->port;
> + struct port_info_s *port_info = &dev->port_info[port];
> + u32 tmp_addr;
> + struct tx_desc_s *cur_tx_desc;
> + int i;
> +
> + /* Allocate tx descriptors. They must be TX_DESC_SIZE bytes
> + aligned */
> + if (!(port_info->tx_desc_malloc = malloc(NUM_TX_DESC *
> + sizeof(struct tx_desc_s) +
> + TX_DESC_SIZE - 1))) {
> + printf("Error: malloc failed\n");
> + return -ENOMEM;
> + }
> + tmp_addr = (u32) (((int)port_info->tx_desc_malloc + TX_DESC_SIZE - 1) &
> + ~(TX_DESC_SIZE - 1));
> + /* Make sure we use a P2 address (non-cacheable) */
> + port_info->tx_desc_base = (struct tx_desc_s *)ADDR_TO_P2(tmp_addr);
> +
> + port_info->tx_desc_cur = port_info->tx_desc_base;
> +
> + /* Initialize all descriptors */
> + for (cur_tx_desc = port_info->tx_desc_base, i = 0; i < NUM_TX_DESC;
> + cur_tx_desc++, i++) {
> + cur_tx_desc->td0 = 0;
> + cur_tx_desc->td1 = 0;
> + cur_tx_desc->td2 = 0;
> + }
> +
> + /* Mark the end of the descriptors */
> + cur_tx_desc--;
> + cur_tx_desc->td0 |= TDLE;
> +
> + /* Point the controller to the tx descriptor list. Must use physical
> + addresses */
> + OUT32(TDLAR(port), ADDR_TO_PHY(port_info->tx_desc_base));
> + OUT32(TDFAR(port), ADDR_TO_PHY(port_info->tx_desc_base));
> + OUT32(TDFXR(port), ADDR_TO_PHY(cur_tx_desc));
> + OUT32(TDFFR(port), 0x0000001);
> +
> + return 0;
> +}
> +
> +static int sh_eth_rx_desc_init(struct dev_info_s *dev)
> +{
> + int port = dev->port;
> + struct port_info_s *port_info = &dev->port_info[port];
> + u32 tmp_addr;
> + struct rx_desc_s *cur_rx_desc;
> + u8 *rx_buf;
> + int i;
> +
> + /* Allocate rx descriptors. They must be RX_DESC_SIZE bytes
> + aligned */
> + if (!(port_info->rx_desc_malloc = malloc(NUM_RX_DESC *
> + sizeof(struct rx_desc_s) +
> + RX_DESC_SIZE - 1))) {
> + printf("Error: malloc failed\n");
> + return -ENOMEM;
> + }
> + tmp_addr = (u32) (((int)port_info->rx_desc_malloc + RX_DESC_SIZE - 1) &
> + ~(RX_DESC_SIZE - 1));
> + /* Make sure we use a P2 address (non-cacheable) */
> + port_info->rx_desc_base = (struct rx_desc_s *)ADDR_TO_P2(tmp_addr);
> +
> + port_info->rx_desc_cur = port_info->rx_desc_base;
> +
> + /* Allocate rx data buffers. They must be 32 bytes aligned and in
> + P2 area */
> + if (!(port_info->rx_buf_malloc = malloc(NUM_RX_DESC * MAX_BUF_SIZE +
> + 31))) {
> + printf("Error: malloc failed\n");
> + free(port_info->rx_desc_malloc);
> + port_info->rx_desc_malloc = NULL;
> + return -ENOMEM;
> + }
> + tmp_addr = (u32) (((int)port_info->rx_buf_malloc + (32 - 1)) &
> + ~(32 - 1));
> + port_info->rx_buf_base = (u8 *) ADDR_TO_P2(tmp_addr);
> +
> + /* Initialize all descriptors */
> + for (cur_rx_desc = port_info->rx_desc_base,
> + rx_buf = port_info->rx_buf_base, i = 0;
> + i < NUM_RX_DESC; cur_rx_desc++, rx_buf += MAX_BUF_SIZE, i++) {
> + cur_rx_desc->rd0 = RACT;
> + cur_rx_desc->rd1 = MAX_BUF_SIZE << 16;
> + cur_rx_desc->rd2 = (u32) ADDR_TO_PHY(rx_buf);
> + }
> +
> + /* Mark the end of the descriptors */
> + cur_rx_desc--;
> + cur_rx_desc->rd0 |= RDLE;
> +
> + /* Point the controller to the rx descriptor list */
> + OUT32(RDLAR(port), ADDR_TO_PHY(port_info->rx_desc_base));
> + OUT32(RDFAR(port), ADDR_TO_PHY(port_info->rx_desc_base));
> + OUT32(RDFXR(port), ADDR_TO_PHY(cur_rx_desc));
> + OUT32(RDFFR(port), 0x00000001);
> +
> + return 0;
> +}
> +
> +static void sh_eth_desc_free(struct dev_info_s *dev)
> +{
> + int port = dev->port;
> + struct port_info_s *port_info = &dev->port_info[port];
> +
> + if (port_info->tx_desc_malloc) {
> + free(port_info->tx_desc_malloc);
> + port_info->tx_desc_malloc = NULL;
> + }
> +
> + if (port_info->rx_desc_malloc) {
> + free(port_info->rx_desc_malloc);
> + port_info->rx_desc_malloc = NULL;
> + }
> +
> + if (port_info->rx_buf_malloc) {
> + free(port_info->rx_buf_malloc);
> + port_info->rx_buf_malloc = NULL;
> + }
> +}
> +
> +static int sh_eth_desc_init(struct dev_info_s *dev)
> +{
> + int rc;
> +
> + if ((rc = sh_eth_tx_desc_init(dev)) || (rc = sh_eth_rx_desc_init(dev))) {
> + sh_eth_desc_free(dev);
> + return rc;
> + }
> +
> + return 0;
> +}
> +
> +static int sh_eth_phy_config(struct dev_info_s *dev)
> +{
> + int port = dev->port;
> + struct port_info_s *port_info = &dev->port_info[port];
> + int timeout;
> + u32 val;
> +
> + /* Reset phy */
> + sh_eth_mii_write_phy_reg(port, port_info->phy_addr, 0, 0x8000);
>
This code has quite a few magic numbers. Considering that you're
submitting a header file too, it's hard to justify not adding mnemonics.
> + timeout = 10;
> + while (timeout--) {
> + val = sh_eth_mii_read_phy_reg(port, port_info->phy_addr, 0);
> + if (!(val & 0x8000))
> + break;
> + udelay(50000);
> + }
> + if (timeout < 0) {
> + printf("sh_eth_phy_config() phy reset timeout\n");
> + return -1;
> + }
> +
> + /* Advertise 100/10 baseT full/half duplex */
> + sh_eth_mii_write_phy_reg(port, port_info->phy_addr, 4, 0x01e1);
> +
> + /* Autonegotiation, normal operation, full duplex, enable tx */
> + sh_eth_mii_write_phy_reg(port, port_info->phy_addr, 0, 0x1200);
> +
> + /* Wait for autonegotiation to complete */
> + timeout = 100;
> + while (timeout--) {
> + val = sh_eth_mii_read_phy_reg(port, port_info->phy_addr, 1);
> + if (val & 0x0020)
>
Another magic number that should be a #defined bit mask
> + break;
> + udelay(50000);
> + }
> + if (timeout < 0) {
> + printf("sh_eth_phy_config() phy auto-negotiation failed\n");
> + return -1;
> + }
> +
> + return 0;
> +}
> +
> +static int sh_eth_config(struct dev_info_s *dev, bd_t * bd)
> +{
> + int port = dev->port;
> + struct port_info_s *port_info = &dev->port_info[port];
> + u32 val;
> + u32 phy_status;
> + int rc;
> +
> + /* Configure e-dmac registers */
> + OUT32(EDMR(port), (IN32(EDMR(port)) & ~0x00000030) | 0x00000040);
> + OUT32(EESIPR(port), 0);
> + OUT32(TRSCER(port), 0);
> + OUT32(TFTR(port), 0);
> + OUT32(FDR(port), 0x0000071f);
> + OUT32(RMCR(port), 1);
> + OUT32(RPADIR(port), 0);
> + OUT32(FCFTR(port), 0x00170007);
> +
> + /* Configure e-mac registers */
> + OUT32(ECSIPR(port), 0);
> +
> + val = bd->bi_enetaddr[0] << 24 | bd->bi_enetaddr[1] << 16 |
> + bd->bi_enetaddr[2] << 8 | bd->bi_enetaddr[3];
> + OUT32(MAHR(port), val);
> +
> + val = bd->bi_enetaddr[4] << 8 | bd->bi_enetaddr[5];
> + OUT32(MALR(port), val);
> +
> + OUT32(RFLR(port), 0x000005ee);
> + OUT32(PIPR(port), 0);
> + OUT32(APR(port), 4);
> + OUT32(MPR(port), 6);
> + OUT32(TPAUSER(port), 6);
> +
> + /* Configure phy */
> + if ((rc = sh_eth_phy_config(dev)))
> + return rc;
> +
> + /* Read phy status to finish configuring the e-mac */
> + phy_status = sh_eth_mii_read_phy_reg(dev->port,
> + dev->port_info[dev->port].phy_addr,
> + 1);
> +
> + /* Set the transfer speed */
> + if (phy_status & 0x6000) {
> + printf("100Base/");
> + OUT32(GECMR(port), 0x4);
> + } else {
> + printf("10Base/");
> + OUT32(GECMR(port), 0x0);
> + }
> + /* Check if full duplex mode is supported by the phy */
> + if (phy_status & 0x5000) {
> + printf("Full\n");
> + OUT32(ECMR(port), 0x041f2062);
> + } else {
> + printf("Half\n");
> + OUT32(ECMR(port), 0x041f2060);
> + }
> + return 0;
> +}
> +
> +static int sh_eth_start(struct dev_info_s *dev)
> +{
> + int port = dev->port;
> +
> + /*
> + * Enable the e-dmac receiver only. The transmitter will be enabled when
> + * we have something to transmit
> + */
> + OUT32(EDRRR(port), 0x1);
> +
> + return 0;
> +}
> +
> +static int sh_eth_get_mac(bd_t *bd)
> +{
> + char *s, *e;
> + int i;
> +
> + s = getenv("ethaddr");
> + if (s != NULL) {
> + for (i = 0; i < 6; ++i) {
> + bd->bi_enetaddr[i] = s ? simple_strtoul(s, &e, 16) : 0;
> + if (s)
> + s = (*e) ? e + 1 : e;
> + }
> + } else {
> + puts("Please set MAC address\n");
> + }
> + return 0;
> +}
> +
> +int eth_init(bd_t * bd)
> +{
> + int rc;
> +
> + /* Allocate main device information structure */
> + if (!(dev = malloc(sizeof(*dev)))) {
> + printf("eth_init: malloc failed\n");
> + return -ENOMEM;
> + }
> +
> + memset(dev, 0, sizeof(*dev));
> +
> + dev->port = CONFIG_SH_ETHER_USE_PORT;
> + dev->port_info[dev->port].phy_addr = CONFIG_SH_ETHER_PHY_ADDR;
> +
> + sh_eth_get_mac(bd);
> +
> + if ((rc = sh_eth_reset(dev)) || (rc = sh_eth_desc_init(dev)))
> + goto err;
> +
> + if ((rc = sh_eth_config(dev, bd)) || (rc = sh_eth_start(dev)))
> + goto err_desc;
> +
> + return 0;
> +
> +err_desc:
> + sh_eth_desc_free(dev);
> +err:
> + free(dev);
> + printf("eth_init: Failed\n");
> + return rc;
> +
> +}
> diff --git a/drivers/net/sh_eth.h b/drivers/net/sh_eth.h
> new file mode 100644
> index 0000000..12a4528
> --- /dev/null
> +++ b/drivers/net/sh_eth.h
> @@ -0,0 +1,195 @@
> +/*
> + * gether.h - Driver for Renesas SH7763's gigabit ethernet controler.
> + *
> + * Copyright (c) 2007 Carlos Munoz <carlos@kenati.com>
> + * Copyright (c) 2008 Nobuhiro Iwamatsu
> + *
> + * 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 <asm/types.h>
> +
> +#define SHETHER_NAME "sh_eth"
> +
> +/* Malloc returns addresses in the P1 area (cacheable). However we need to
> + use area P2 (non-cacheable) */
> +#define ADDR_TO_P2(addr) ((((int)(addr) & ~0xe0000000) | 0xa0000000))
> +
> +/* The ethernet controller needs to use physical addresses */
> +#define ADDR_TO_PHY(addr) ((int)(addr) & ~0xe0000000)
> +
> +/* Number of supported ports */
> +#define MAX_PORT_NUM 2
> +
> +/* Buffers must be big enough to hold the largest ethernet frame. Also, rx
> + buffers must be a multiple of 32 bytes */
> +#define MAX_BUF_SIZE (48 * 32)
> +
> +/* The number of tx descriptors must be large enough to point to 5 or more
> + frames. If each frame uses 2 descriptors, at least 10 descriptors are needed.
> + We use one descriptor per frame */
> +#define NUM_TX_DESC 8
> +
> +/* The size of the tx descriptor is determined by how much padding is used.
> + 4, 20, or 52 bytes of padding can be used */
> +#define TX_DESC_PADDING 4
> +#define TX_DESC_SIZE (12 + TX_DESC_PADDING)
> +
> +/* Tx descriptor. We always use 4 bytes of padding */
> +struct tx_desc_s {
> + volatile u32 td0;
> + u32 td1;
> + u32 td2; /* Buffer start */
> + u32 padding;
> +};
> +
> +/* TD0 */
> +#define TACT (0x1 << 31) /* Valid/invalid */
> +#define TDLE (0x1 << 30) /* List end */
> +#define TFP (0x3 << 28) /* Frame position */
> +#define TFP_END (0x1 << 28) /* End of frame */
> +#define TFP_START (0x2 << 28) /* Start of frame */
> +#define TFE (0x1 << 27) /* Error occurrence */
> +#define TWBI (0x1 << 26) /* Write-back completion int */
> +#define TFS (0xfff << 0) /* Frame status */
> +#define TFS_UNFLW (0x1 << 9) /* Underflow */
> +#define TFS_ABORT (0x1 << 8) /* Abort */
> +
> +/* TD1 */
> +#define TDL (0xffff << 16) /* Buffer data length */
> +
> +/* There is no limitation in the number of rx descriptors */
> +#define NUM_RX_DESC 8
> +
> +/* The size of the rx descriptor is determined by how much padding is used.
> + 4, 20, or 52 bytes of padding can be used */
> +#define RX_DESC_PADDING 4
> +#define RX_DESC_SIZE (12 + RX_DESC_PADDING)
> +
> +/* Rx descriptor. We always use 4 bytes of padding */
> +struct rx_desc_s {
> + volatile u32 rd0;
> + volatile u32 rd1;
> + u32 rd2; /* Buffer start */
> + u32 padding;
> +};
> +
> +/* RD0 */
> +#define RACT (0x1 << 31) /* Valid/invalid */
> +#define RDLE (0x1 << 30) /* List end */
> +#define RFP (0x3 << 28) /* Frame position */
> +#define RFP_END (0x1 << 28) /* End of frame */
> +#define RFP_START (0x2 << 28) /* Start of frame */
> +#define RFE (0x1 << 27) /* Error occurrence */
> +#define PV (0x1 << 26) /* Padding Insertion */
> +#define RFS (0xfff << 0) /* Frame status */
> +#define RFS_OVFLW (0x1 << 9) /* Overflow */
> +#define RFS_ABORT (0x1 << 8) /* Abort */
> +#define RFS_MCAST (0x1 << 7) /* Multicast Address */
> +#define RFS_CEXT (0x1 << 6) /* Carrier ext error */
> +#define RFS_CELOSS (0x1 << 5) /* Carrier ext loss */
> +#define RFS_RBF (0x1 << 4) /* Residual-bit frame error */
> +#define RFS_LONG (0x1 << 3) /* Long frame */
> +#define RFS_SHORT (0x1 << 2) /* Short frame */
> +#define RFS_PHY (0x1 << 1) /* PHY rx error */
> +#define RFS_CRC (0x1 << 0) /* CRC error */
> +
> +/* RD1 */
> +#define RBL (0xffff << 16) /* Buffer length */
> +#define RDL (0xffff << 0) /* Buffer data length */
> +
> +struct port_info_s {
> + struct tx_desc_s *tx_desc_malloc;
> + struct tx_desc_s *tx_desc_base;
> + struct tx_desc_s *tx_desc_cur;
> + struct rx_desc_s *rx_desc_malloc;
> + struct rx_desc_s *rx_desc_base;
> + struct rx_desc_s *rx_desc_cur;
> + u8 *rx_buf_malloc;
> + u8 *rx_buf_base;
> + u8 mac_addr[6];
> + u8 phy_addr;
> +};
> +
> +struct dev_info_s {
> + int port;
> + struct port_info_s port_info[MAX_PORT_NUM];
> +};
> +
> +#define IN16(reg) (*(u16 *)(reg))
> +#define IN32(reg) (*(u32 *)(reg))
> +#define OUT16(reg, val) (*(u16 *)(reg) = (val))
> +#define OUT32(reg, val) (*(u32 *)(reg) = (val))
> +
>
Please use the accessors in include/asm-sh/io.h instead of defining your
own.
> +#define PDCR 0xffef0006
> +#define PECR 0xffef0008
> +#define PFCR 0xffef000a
> +#define PGCR 0xffef000c
> +#define PHCR 0xffef000e
> +#define PJCR 0xffef0012
> +#define PKCR 0xffef0014
> +#define PLCR 0xffef0016
> +#define PMCR 0xffef0018
> +#define PSEL1 0xffef0072
> +#define PSEL2 0xffef0074
> +#define PSEL3 0xffef0076
> +
> +#define BASE_IO_ADDR 0xfee00000
> +
> +#define EDSR(port) (BASE_IO_ADDR + 0x800 * (port) + 0x0000)
> +
> +#define TDLAR(port) (BASE_IO_ADDR + 0x800 * (port) + 0x0010)
> +#define TDFAR(port) (BASE_IO_ADDR + 0x800 * (port) + 0x0014)
> +#define TDFXR(port) (BASE_IO_ADDR + 0x800 * (port) + 0x0018)
> +#define TDFFR(port) (BASE_IO_ADDR + 0x800 * (port) + 0x001c)
> +
> +#define RDLAR(port) (BASE_IO_ADDR + 0x800 * (port) + 0x0030)
> +#define RDFAR(port) (BASE_IO_ADDR + 0x800 * (port) + 0x0034)
> +#define RDFXR(port) (BASE_IO_ADDR + 0x800 * (port) + 0x0038)
> +#define RDFFR(port) (BASE_IO_ADDR + 0x800 * (port) + 0x003c)
> +
> +#define EDMR(port) (BASE_IO_ADDR + 0x800 * (port) + 0x0400)
> +#define EDTRR(port) (BASE_IO_ADDR + 0x800 * (port) + 0x0408)
> +#define EDRRR(port) (BASE_IO_ADDR + 0x800 * (port) + 0x0410)
> +#define EESR(port) (BASE_IO_ADDR + 0x800 * (port) + 0x0428)
> +#define EESIPR(port) (BASE_IO_ADDR + 0x800 * (port) + 0x0430)
> +#define TRSCER(port) (BASE_IO_ADDR + 0x800 * (port) + 0x0438)
> +#define TFTR(port) (BASE_IO_ADDR + 0x800 * (port) + 0x0448)
> +#define FDR(port) (BASE_IO_ADDR + 0x800 * (port) + 0x0450)
> +#define RMCR(port) (BASE_IO_ADDR + 0x800 * (port) + 0x0458)
> +#define RPADIR(port) (BASE_IO_ADDR + 0x800 * (port) + 0x0460)
> +#define FCFTR(port) (BASE_IO_ADDR + 0x800 * (port) + 0x0468)
> +#define ECMR(port) (BASE_IO_ADDR + 0x800 * (port) + 0x0500)
> +#define RFLR(port) (BASE_IO_ADDR + 0x800 * (port) + 0x0508)
> +#define ECSIPR(port) (BASE_IO_ADDR + 0x800 * (port) + 0x0518)
> +#define PIR(port) (BASE_IO_ADDR + 0x800 * (port) + 0x0520)
> +#define PIPR(port) (BASE_IO_ADDR + 0x800 * (port) + 0x052c)
> +#define APR(port) (BASE_IO_ADDR + 0x800 * (port) + 0x0554)
> +#define MPR(port) (BASE_IO_ADDR + 0x800 * (port) + 0x0558)
> +#define TPAUSER(port) (BASE_IO_ADDR + 0x800 * (port) + 0x0564)
> +#define GECMR(port) (BASE_IO_ADDR + 0x800 * (port) + 0x05b0)
> +#define MALR(port) (BASE_IO_ADDR + 0x800 * (port) + 0x05c8)
> +#define MAHR(port) (BASE_IO_ADDR + 0x800 * (port) + 0x05c0)
> +
> +/* Bit values for EESR */
> +#define EESR_CERF (0x1 << 0)
> +#define EESR_PRE (0x1 << 1)
> +#define EESR_RTSF (0x1 << 2)
> +#define EESR_RTLF (0x1 << 3)
> +#define EESR_RFOF (0x1 << 16)
> +#define EESR_FR (1 << 18)
> +
> +/* PHY values */
> +#define PHY_DELAY udelay(1)
>
As I already mentioned, please put more bit definitions here.
regards,
Ben
next prev parent reply other threads:[~2008-06-10 6:20 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2008-06-06 7:17 [U-Boot-Users] [PATCH] net: sh: Renesas SH7763 Ethernet device support Nobuhiro Iwamatsu
2008-06-09 20:21 ` Nobuhiro Iwamatsu
2008-06-09 20:33 ` Ben Warren
2008-06-10 6:20 ` Ben Warren [this message]
2008-06-11 11:59 ` Nobuhiro Iwamatsu
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=484E1D22.3060809@qstreams.com \
--to=bwarren@qstreams.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.