All of lore.kernel.org
 help / color / mirror / Atom feed
From: Nobuhiro Iwamatsu <iwamatsu.nobuhiro@renesas.com>
To: u-boot@lists.denx.de
Subject: [U-Boot-Users] [PATCH v2] net: sh: Renesas SH7763 Ethernet device support
Date: Wed, 11 Jun 2008 21:05:00 +0900	[thread overview]
Message-ID: <484FBF6C.6020305@renesas.com> (raw)

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 |  603 ++++++++++++++++++++++++++++++++++++++++++++++++++
 drivers/net/sh_eth.h |  446 +++++++++++++++++++++++++++++++++++++
 3 files changed, 1050 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..097c6c3
--- /dev/null
+++ b/drivers/net/sh_eth.c
@@ -0,0 +1,603 @@
+/*
+ * 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 <asm/io.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);
+		outl(pir, PIR(port));
+		udelay(1);
+		/* Write direction, bit to write, clock is high */
+		pir = 3 | ((val & 1 << i) ? 1 << 2 : 0);
+		outl(pir, PIR(port));
+		udelay(1);
+		/* Write direction, bit to write, clock is low */
+		pir = 2 | ((val & 1 << i) ? 1 << 2 : 0);
+		outl(pir, PIR(port));
+		udelay(1);
+	}
+}
+
+static void sh_eth_mii_bus_release(int port)
+{
+	/* Read direction, clock is low */
+	outl(0, PIR(port));
+	udelay(1);
+	/* Read direction, clock is high */
+	outl(1, PIR(port));
+	udelay(1);
+	/* Read direction, clock is low */
+	outl(0, PIR(port));
+	udelay(1);
+}
+
+static void sh_eth_mii_ind_bus_release(int port)
+{
+	/* Read direction, clock is low */
+	outl(0, PIR(port));
+	udelay(1);
+}
+
+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 */
+		outl(1, PIR(port));
+		udelay(1);
+		/* Read bit */
+		pir = inl(PIR(port));
+		*val |= (pir & 8) ? 1 << i : 0;
+		/* Read direction, clock is low */
+		outl(0, PIR(port));
+		udelay(1);
+	}
+
+	return 0;
+}
+
+#define PHY_INIT	0xFFFFFFFF
+#define PHY_READ	0x02
+#define PHY_WRITE	0x01
+/*
+ * 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, PHY_INIT, 32);
+	/* st (start of frame) */
+	sh_eth_mii_write_phy_bits(port, 0x1, 2);
+	/* op (code) */
+	sh_eth_mii_write_phy_bits(port, PHY_READ, 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, PHY_INIT, 32);
+	/* st (start of frame) */
+	sh_eth_mii_write_phy_bits(port, 0x1, 2);
+	/* op (code) */
+	sh_eth_mii_write_phy_bits(port, PHY_WRITE, 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, PHY_READ, 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 & TD_TDLE)
+		port_info->tx_desc_cur->td0 = TD_TACT | TD_TFP | TD_TDLE;
+	else
+		port_info->tx_desc_cur->td0 = TD_TACT | TD_TFP;
+
+	/* Restart the transmitter if disabled */
+	if (!(inl(EDTRR(port)) & EDTRR_TRNS))
+		outl(EDTRR_TRNS, EDTRR(port));
+
+	/* Wait until packet is transmitted */
+	timeout = 1000;
+	while (port_info->tx_desc_cur->td0 & TD_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 & RD_RACT)) {
+		/* Check for errors */
+		if (!(port_info->rx_desc_cur->rd0 & RD_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 & RD_RDLE)
+			port_info->rx_desc_cur->rd0 = RD_RACT | RD_RDLE;
+		else
+			port_info->rx_desc_cur->rd0 = RD_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 (!(inl(EDRRR(port)) & EDRRR_R))
+		outl(EDRRR_R, EDRRR(port));
+
+	return len;
+}
+
+#define EDMR_INIT_CNT 1000
+static int sh_eth_reset(struct dev_info_s *dev)
+{
+	int port = dev->port;
+	int i;
+
+	/* Start e-dmac transmitter and receiver */
+	outl(EDSR_ENALL, EDSR(port));
+
+	/* Perform a software reset and wait for it to complete */
+	outl(EDMR_SRST, EDMR(port));
+	for (i = 0; i < EDMR_INIT_CNT; i++) {
+		if (!(inl(EDMR(port)) & EDMR_SRST))
+			break;
+		udelay(1000);
+	}
+
+	if (i == EDMR_INIT_CNT) {
+		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 = 0x00;
+		cur_tx_desc->td1 = 0x00;
+		cur_tx_desc->td2 = 0x00;
+	}
+
+	/* Mark the end of the descriptors */
+	cur_tx_desc--;
+	cur_tx_desc->td0 |= TD_TDLE;
+
+	/* Point the controller to the tx descriptor list. Must use physical
+	   addresses */
+	outl(ADDR_TO_PHY(port_info->tx_desc_base), TDLAR(port));
+	outl(ADDR_TO_PHY(port_info->tx_desc_base), TDFAR(port));
+	outl(ADDR_TO_PHY(cur_tx_desc), TDFXR(port));
+	outl(0x01, TDFFR(port));/* Last discriptor bit */
+
+	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 = RD_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 |= RD_RDLE;
+
+	/* Point the controller to the rx descriptor list */
+	outl(ADDR_TO_PHY(port_info->rx_desc_base), RDLAR(port));
+	outl(ADDR_TO_PHY(port_info->rx_desc_base), RDFAR(port));
+	outl(ADDR_TO_PHY(cur_rx_desc), RDFXR(port));
+	outl(RDFFR_RDLF, RDFFR(port));
+
+	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, PHY_CTRL, PHY_C_RESET);
+	timeout = 10;
+	while (timeout--) {
+		val = sh_eth_mii_read_phy_reg(port, port_info->phy_addr, PHY_CTRL);
+		if (!(val & PHY_C_RESET))
+			break;
+		udelay(50000);
+	}
+	if (timeout < 0) {
+		printf("%s phy reset timeout\n", __func__);
+		return -1;
+	}
+
+	/* Advertise 100/10 baseT full/half duplex */
+	sh_eth_mii_write_phy_reg(port, port_info->phy_addr, PHY_ANA,
+		(PHY_A_FDX|PHY_A_HDX|PHY_A_10FDX|PHY_A_10HDX|PHY_A_EXT));
+	/* Autonegotiation, normal operation, full duplex, enable tx */
+	sh_eth_mii_write_phy_reg(port, port_info->phy_addr, PHY_CTRL,
+		(PHY_C_ANEGEN|PHY_C_RANEG));
+	/* Wait for autonegotiation to complete */
+	timeout = 100;
+	while (timeout--) {
+		val = sh_eth_mii_read_phy_reg(port, port_info->phy_addr, 1);
+		if (val & PHY_S_ANEGC)
+			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 */
+	outl((inl(EDMR(port)) & ~EMDR_DESC_R) | EDMR_EL, EDMR(port));
+	outl(0, EESIPR(port));
+	outl(0, TRSCER(port));
+	outl(0, TFTR(port));
+	outl((FIFO_SIZE_T | FIFO_SIZE_R), FDR(port));
+	outl(RMCR_RST, RMCR(port));
+	outl(0, RPADIR(port));
+	outl((FIFO_F_D_RFF | FIFO_F_D_RFD), FCFTR(port));
+
+	/* Configure e-mac registers */
+	outl(0, ECSIPR(port));
+
+	/* Set Mac address */
+	val = bd->bi_enetaddr[0] << 24 | bd->bi_enetaddr[1] << 16 |
+	    bd->bi_enetaddr[2] << 8 | bd->bi_enetaddr[3];
+	outl(val, MAHR(port));
+
+	val = bd->bi_enetaddr[4] << 8 | bd->bi_enetaddr[5];
+	outl(val, MALR(port));
+
+	outl(RFLR_RFL_MIN, RFLR(port));
+	outl(0, PIPR(port));
+	outl(APR_AP, APR(port));
+	outl(MPR_MP, MPR(port));
+	outl(TPAUSER_TPAUSE, TPAUSER(port));
+
+	/* 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 & (PHY_S_100X_F|PHY_S_100X_H)) {
+		printf("100Base/");
+		outl(GECMR_100B, GECMR(port));
+	} else {
+		printf("10Base/");
+		outl(GECMR_10B, GECMR(port));
+	}
+
+	/* Check if full duplex mode is supported by the phy */
+	if (phy_status & (PHY_S_100X_F|PHY_S_10T_F)) {
+		printf("Full\n");
+		outl((ECMR_CHG_DM|ECMR_RE|ECMR_TE|ECMR_DM), ECMR(port));
+	} else {
+		printf("Half\n");
+		outl((ECMR_CHG_DM|ECMR_RE|ECMR_TE),  ECMR(port));
+	}
+	return 0;
+}
+
+static int sh_eth_start(struct dev_info_s *dev)
+{
+	/*
+	 * Enable the e-dmac receiver only. The transmitter will be enabled when
+	 * we have something to transmit
+	 */
+	outl(EDRRR_R, EDRRR(dev->port));
+
+	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..4ccae83
--- /dev/null
+++ b/drivers/net/sh_eth.h
@@ -0,0 +1,446 @@
+/*
+ * sh_eth.h - Driver for Renesas SH7763's gigabit 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 <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;
+};
+
+/* 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;
+};
+
+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];
+};
+
+/* Register Address */
+#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)
+
+/*
+ * Register's bits
+ * Copy from Linux driver source code
+ */
+#ifdef CONFIG_CPU_SH7763
+/* EDSR */
+enum EDSR_BIT {
+	EDSR_ENT = 0x01, EDSR_ENR = 0x02,
+};
+#define EDSR_ENALL (EDSR_ENT|EDSR_ENR)
+#endif
+
+/* EDMR */
+enum DMAC_M_BIT {
+	EDMR_DL1 = 0x20, EDMR_DL0 = 0x10,
+#ifdef CONFIG_CPU_SH7763
+	EDMR_SRST	= 0x03,
+	EMDR_DESC_R	= 0x30, /* Descriptor reserve size */
+	EDMR_EL		= 0x40, /* Litte endian */
+#else /* CONFIG_CPU_SH7763 */
+	EDMR_SRST = 0x01,
+#endif
+};
+
+/* RFLR */
+#define RFLR_RFL_MIN	0x05EE	/* Recv Frame length 1518 byte */
+
+/* EDTRR */
+enum DMAC_T_BIT {
+#ifdef CONFIG_CPU_SH7763
+	EDTRR_TRNS = 0x03,
+#else
+	EDTRR_TRNS = 0x01,
+#endif
+};
+
+/* GECMR */
+enum GECMR_BIT {
+	GECMR_1000B = 0x01, GECMR_100B = 0x40, GECMR_10B = 0x00,
+};
+
+/* EDRRR*/
+enum EDRRR_R_BIT {
+	EDRRR_R = 0x01,
+};
+
+/* TPAUSER */
+enum TPAUSER_BIT {
+	TPAUSER_TPAUSE = 0x0000ffff,
+	TPAUSER_UNLIMITED = 0,
+};
+
+/* BCFR */
+enum BCFR_BIT {
+	BCFR_RPAUSE = 0x0000ffff,
+	BCFR_UNLIMITED = 0,
+};
+
+/* PIR */
+enum PIR_BIT {
+	PIR_MDI = 0x08, PIR_MDO = 0x04, PIR_MMD = 0x02, PIR_MDC = 0x01,
+};
+
+/* PSR */
+enum PHY_STATUS_BIT { PHY_ST_LINK = 0x01, };
+
+/* EESR */
+enum EESR_BIT {
+#ifndef CONFIG_CPU_SH7763
+	EESR_TWB  = 0x40000000,
+#else
+	EESR_TWB  = 0xC0000000,
+	EESR_TC1  = 0x20000000,
+	EESR_TUC  = 0x10000000,
+	EESR_ROC  = 0x80000000,
+#endif
+	EESR_TABT = 0x04000000,
+	EESR_RABT = 0x02000000, EESR_RFRMER = 0x01000000,
+#ifndef CONFIG_CPU_SH7763
+	EESR_ADE  = 0x00800000,
+#endif
+	EESR_ECI  = 0x00400000,
+	EESR_FTC  = 0x00200000, EESR_TDE  = 0x00100000,
+	EESR_TFE  = 0x00080000, EESR_FRC  = 0x00040000,
+	EESR_RDE  = 0x00020000, EESR_RFE  = 0x00010000,
+#ifndef CONFIG_CPU_SH7763
+	EESR_CND  = 0x00000800,
+#endif
+	EESR_DLC  = 0x00000400,
+	EESR_CD   = 0x00000200, EESR_RTO  = 0x00000100,
+	EESR_RMAF = 0x00000080, EESR_CEEF = 0x00000040,
+	EESR_CELF = 0x00000020, EESR_RRF  = 0x00000010,
+	rESR_RTLF = 0x00000008, EESR_RTSF = 0x00000004,
+	EESR_PRE  = 0x00000002, EESR_CERF = 0x00000001,
+};
+
+
+#ifdef CONFIG_CPU_SH7763
+# define TX_CHECK (EESR_TC1 | EESR_FTC)
+# define EESR_ERR_CHECK	(EESR_TWB | EESR_TABT | EESR_RABT | EESR_RDE \
+		| EESR_RFRMER | EESR_TFE | EESR_TDE | EESR_ECI)
+# define TX_ERROR_CEHCK (EESR_TWB | EESR_TABT | EESR_TDE | EESR_TFE)
+
+#else
+# define TX_CHECK (EESR_FTC | EESR_CND | EESR_DLC | EESR_CD | EESR_RTO)
+# define EESR_ERR_CHECK	(EESR_TWB | EESR_TABT | EESR_RABT | EESR_RDE \
+		| EESR_RFRMER | EESR_ADE | EESR_TFE | EESR_TDE | EESR_ECI)
+# define TX_ERROR_CEHCK (EESR_TWB | EESR_TABT | EESR_ADE | EESR_TDE | EESR_TFE)
+#endif
+
+/* EESIPR */
+enum DMAC_IM_BIT {
+	DMAC_M_TWB = 0x40000000, DMAC_M_TABT = 0x04000000,
+	DMAC_M_RABT = 0x02000000,
+	DMAC_M_RFRMER = 0x01000000, DMAC_M_ADF = 0x00800000,
+	DMAC_M_ECI = 0x00400000, DMAC_M_FTC = 0x00200000,
+	DMAC_M_TDE = 0x00100000, DMAC_M_TFE = 0x00080000,
+	DMAC_M_FRC = 0x00040000, DMAC_M_RDE = 0x00020000,
+	DMAC_M_RFE = 0x00010000, DMAC_M_TINT4 = 0x00000800,
+	DMAC_M_TINT3 = 0x00000400, DMAC_M_TINT2 = 0x00000200,
+	DMAC_M_TINT1 = 0x00000100, DMAC_M_RINT8 = 0x00000080,
+	DMAC_M_RINT5 = 0x00000010, DMAC_M_RINT4 = 0x00000008,
+	DMAC_M_RINT3 = 0x00000004, DMAC_M_RINT2 = 0x00000002,
+	DMAC_M_RINT1 = 0x00000001,
+};
+
+/* Receive descriptor bit */
+enum RD_STS_BIT {
+	RD_RACT = 0x80000000, RD_RDLE = 0x40000000,
+	RD_RFP1 = 0x20000000, RD_RFP0 = 0x10000000,
+	RD_RFE = 0x08000000, RD_RFS10 = 0x00000200,
+	RD_RFS9 = 0x00000100, RD_RFS8 = 0x00000080,
+	RD_RFS7 = 0x00000040, RD_RFS6 = 0x00000020,
+	RD_RFS5 = 0x00000010, RD_RFS4 = 0x00000008,
+	RD_RFS3 = 0x00000004, RD_RFS2 = 0x00000002,
+	RD_RFS1 = 0x00000001,
+};
+#define RDF1ST	RD_RFP1
+#define RDFEND	RD_RFP0
+#define RD_RFP	(RD_RFP1|RD_RFP0)
+
+/* RDFFR*/
+enum RDFFR_BIT {
+	RDFFR_RDLF = 0x01,
+};
+
+/* FCFTR */
+enum FCFTR_BIT {
+	FCFTR_RFF2 = 0x00040000, FCFTR_RFF1 = 0x00020000,
+	FCFTR_RFF0 = 0x00010000, FCFTR_RFD2 = 0x00000004,
+	FCFTR_RFD1 = 0x00000002, FCFTR_RFD0 = 0x00000001,
+};
+#define FIFO_F_D_RFF	(FCFTR_RFF2|FCFTR_RFF1|FCFTR_RFF0)
+#define FIFO_F_D_RFD	(FCFTR_RFD2|FCFTR_RFD1|FCFTR_RFD0)
+
+/* Transfer descriptor bit */
+enum TD_STS_BIT {
+#ifdef CONFIG_CPU_SH7763
+	TD_TACT = 0x80000000,
+#else
+	TD_TACT = 0x7fffffff,
+#endif
+	TD_TDLE = 0x40000000, TD_TFP1 = 0x20000000,
+	TD_TFP0 = 0x10000000,
+};
+#define TDF1ST	TD_TFP1
+#define TDFEND	TD_TFP0
+#define TD_TFP	(TD_TFP1|TD_TFP0)
+
+/* RMCR */
+enum RECV_RST_BIT { RMCR_RST = 0x01, };
+/* ECMR */
+enum FELIC_MODE_BIT {
+#ifdef CONFIG_CPU_SH7763
+	ECMR_TRCCM=0x04000000, ECMR_RCSC= 0x00800000, ECMR_DPAD= 0x00200000,
+	ECMR_RZPF = 0x00100000,	
+#endif
+	ECMR_ZPF = 0x00080000, ECMR_PFR = 0x00040000, ECMR_RXF = 0x00020000,
+	ECMR_TXF = 0x00010000, ECMR_MCT = 0x00002000, ECMR_PRCEF = 0x00001000,
+	ECMR_PMDE = 0x00000200, ECMR_RE = 0x00000040, ECMR_TE = 0x00000020,
+	ECMR_ILB = 0x00000008, ECMR_ELB = 0x00000004, ECMR_DM = 0x00000002,
+	ECMR_PRM = 0x00000001,
+};
+
+#ifdef CONFIG_CPU_SH7763
+#define ECMR_CHG_DM	(ECMR_TRCCM | ECMR_RZPF | ECMR_ZPF | ECMR_PFR | ECMR_RXF | \
+						ECMR_TXF | ECMR_MCT)
+#else
+#define ECMR_CHG_DM	(ECMR_ZPF | ECMR_PFR ECMR_RXF | ECMR_TXF | ECMR_MCT)
+#endif
+
+/* ECSR */
+enum ECSR_STATUS_BIT {
+#ifndef CONFIG_CPU_SH7763
+	ECSR_BRCRX = 0x20, ECSR_PSRTO = 0x10,
+#endif
+	ECSR_LCHNG = 0x04,
+	ECSR_MPD = 0x02, ECSR_ICD = 0x01,
+};
+
+#ifdef CONFIG_CPU_SH7763
+# define ECSR_INIT (ECSR_ICD | ECSIPR_MPDIP)
+#else
+# define ECSR_INIT (ECSR_BRCRX | ECSR_PSRTO | \
+			ECSR_LCHNG | ECSR_ICD | ECSIPR_MPDIP)
+#endif
+
+/* ECSIPR */
+enum ECSIPR_STATUS_MASK_BIT {
+#ifndef CONFIG_CPU_SH7763
+	ECSIPR_BRCRXIP = 0x20, ECSIPR_PSRTOIP = 0x10,
+#endif
+	ECSIPR_LCHNGIP = 0x04,
+	ECSIPR_MPDIP = 0x02, ECSIPR_ICDIP = 0x01,
+};
+
+#ifdef CONFIG_CPU_SH7763
+# define ECSIPR_INIT (ECSIPR_LCHNGIP | ECSIPR_ICDIP | ECSIPR_MPDIP)
+#else
+# define ECSIPR_INIT (ECSIPR_BRCRXIP | ECSIPR_PSRTOIP | ECSIPR_LCHNGIP | \
+				ECSIPR_ICDIP | ECSIPR_MPDIP)
+#endif
+
+/* APR */
+enum APR_BIT {
+	APR_AP = 0x00000004,
+};
+
+/* MPR */
+enum MPR_BIT {
+	MPR_MP = 0x00000006,
+};
+
+/* TRSCER */
+enum DESC_I_BIT {
+	DESC_I_TINT4 = 0x0800, DESC_I_TINT3 = 0x0400, DESC_I_TINT2 = 0x0200,
+	DESC_I_TINT1 = 0x0100, DESC_I_RINT8 = 0x0080, DESC_I_RINT5 = 0x0010,
+	DESC_I_RINT4 = 0x0008, DESC_I_RINT3 = 0x0004, DESC_I_RINT2 = 0x0002,
+	DESC_I_RINT1 = 0x0001,
+};
+
+/* RPADIR */
+enum RPADIR_BIT {
+	RPADIR_PADS1 = 0x20000, RPADIR_PADS0 = 0x10000,
+	RPADIR_PADR = 0x0003f,
+};
+
+#ifdef CONFIG_CPU_SH7763
+# define RPADIR_INIT (0x00)
+#else
+# define RPADIR_INIT (RPADIR_PADS1)
+#endif
+
+/* FDR */
+enum FIFO_SIZE_BIT {
+	FIFO_SIZE_T = 0x00000700, FIFO_SIZE_R = 0x00000007,
+};
+
+enum PHY_OFFSETS {
+	PHY_CTRL = 0, PHY_STAT = 1, PHY_IDT1 = 2, PHY_IDT2 = 3,
+	PHY_ANA = 4, PHY_ANL = 5, PHY_ANE = 6,
+	PHY_16 = 16,
+};
+
+/* PHY_CTRL */
+enum PHY_CTRL_BIT {
+	PHY_C_RESET = 0x8000, PHY_C_LOOPBK = 0x4000, PHY_C_SPEEDSL = 0x2000,
+	PHY_C_ANEGEN = 0x1000, PHY_C_PWRDN = 0x0800, PHY_C_ISO = 0x0400,
+	PHY_C_RANEG = 0x0200, PHY_C_DUPLEX = 0x0100, PHY_C_COLT = 0x0080,
+};
+#define DM9161_PHY_C_ANEGEN 0	/* auto nego special */
+
+/* PHY_STAT */
+enum PHY_STAT_BIT {
+	PHY_S_100T4 = 0x8000, PHY_S_100X_F = 0x4000, PHY_S_100X_H = 0x2000,
+	PHY_S_10T_F = 0x1000, PHY_S_10T_H = 0x0800, PHY_S_ANEGC = 0x0020,
+	PHY_S_RFAULT = 0x0010, PHY_S_ANEGA = 0x0008, PHY_S_LINK = 0x0004,
+	PHY_S_JAB = 0x0002, PHY_S_EXTD = 0x0001,
+};
+
+/* PHY_ANA */
+enum PHY_ANA_BIT {
+	PHY_A_NP = 0x8000, PHY_A_ACK = 0x4000, PHY_A_RF = 0x2000,
+	PHY_A_FCS = 0x0400, PHY_A_T4 = 0x0200, PHY_A_FDX = 0x0100,
+	PHY_A_HDX = 0x0080, PHY_A_10FDX = 0x0040, PHY_A_10HDX = 0x0020,
+	PHY_A_SEL = 0x001e,
+	PHY_A_EXT = 0x0001,
+};
+
+/* PHY_ANL */
+enum PHY_ANL_BIT {
+	PHY_L_NP = 0x8000, PHY_L_ACK = 0x4000, PHY_L_RF = 0x2000,
+	PHY_L_FCS = 0x0400, PHY_L_T4 = 0x0200, PHY_L_FDX = 0x0100,
+	PHY_L_HDX = 0x0080, PHY_L_10FDX = 0x0040, PHY_L_10HDX = 0x0020,
+	PHY_L_SEL = 0x001f,
+};
+
+/* PHY_ANE */
+enum PHY_ANE_BIT {
+	PHY_E_PDF = 0x0010, PHY_E_LPNPA = 0x0008, PHY_E_NPA = 0x0004,
+	PHY_E_PRX = 0x0002, PHY_E_LPANEGA = 0x0001,
+};
+
+/* DM9161 */
+enum PHY_16_BIT {
+	PHY_16_BP4B45 = 0x8000, PHY_16_BPSCR = 0x4000, PHY_16_BPALIGN = 0x2000,
+	PHY_16_BP_ADPOK = 0x1000, PHY_16_Repeatmode = 0x0800,
+	PHY_16_TXselect = 0x0400,
+	PHY_16_Rsvd = 0x0200, PHY_16_RMIIEnable = 0x0100,
+	PHY_16_Force100LNK = 0x0080,
+	PHY_16_APDLED_CTL = 0x0040, PHY_16_COLLED_CTL = 0x0020,
+	PHY_16_RPDCTR_EN = 0x0010,
+	PHY_16_ResetStMch = 0x0008, PHY_16_PreamSupr = 0x0004,
+	PHY_16_Sleepmode = 0x0002,
+	PHY_16_RemoteLoopOut = 0x0001,
+};
-- 
1.5.5.1

             reply	other threads:[~2008-06-11 12:05 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2008-06-11 12:05 Nobuhiro Iwamatsu [this message]
2008-07-07  6:51 ` [U-Boot-Users] [PATCH v2] net: sh: Renesas SH7763 Ethernet device support Ben Warren

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=484FBF6C.6020305@renesas.com \
    --to=iwamatsu.nobuhiro@renesas.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.