mail archive of the barebox mailing list
 help / color / mirror / Atom feed
* [PATCH 0/3] ppc: Freescale TSEC driver.
@ 2012-07-25 16:00 Renaud Barbier
  2012-07-25 16:00 ` [PATCH 1/3] ppc: GIANFAR base address definition Renaud Barbier
                   ` (7 more replies)
  0 siblings, 8 replies; 12+ messages in thread
From: Renaud Barbier @ 2012-07-25 16:00 UTC (permalink / raw)
  To: barebox

This patchset adds support for the Freescale Ethernet driver(TSEC).
It is tested on a P2020RDB board using the eTSEC3 interface(RGMII)
only.

Renaud Barbier (3):
  ppc: GIANFAR base address definition
  net: GIANFAR driver
  ppc: P2020RDB Ethernet configuration

 arch/ppc/boards/freescale-p2020rdb/p2020rdb.c   |   38 ++
 arch/ppc/configs/p2020rdb_defconfig             |    6 +
 arch/ppc/mach-mpc85xx/include/mach/gianfar.h    |   31 ++
 arch/ppc/mach-mpc85xx/include/mach/immap_85xx.h |    7 +
 drivers/net/Kconfig                             |    5 +
 drivers/net/Makefile                            |    1 +
 drivers/net/gianfar.c                           |  558 +++++++++++++++++++++++
 drivers/net/gianfar.h                           |  288 ++++++++++++
 8 files changed, 934 insertions(+), 0 deletions(-)
 create mode 100644 arch/ppc/mach-mpc85xx/include/mach/gianfar.h
 create mode 100644 drivers/net/gianfar.c
 create mode 100644 drivers/net/gianfar.h


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH 1/3] ppc: GIANFAR base address definition
  2012-07-25 16:00 [PATCH 0/3] ppc: Freescale TSEC driver Renaud Barbier
@ 2012-07-25 16:00 ` Renaud Barbier
  2012-07-25 16:01 ` [PATCH 2/3] net: GIANFAR driver Renaud Barbier
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 12+ messages in thread
From: Renaud Barbier @ 2012-07-25 16:00 UTC (permalink / raw)
  To: barebox

In view of the introduction of the GIANFAR Ethernet driver,
the mdio and gianfar base address are defined.

Signed-off-by: Renaud Barbier <renaud.barbier@ge.com>
---
 arch/ppc/mach-mpc85xx/include/mach/immap_85xx.h |    7 +++++++
 1 files changed, 7 insertions(+), 0 deletions(-)

diff --git a/arch/ppc/mach-mpc85xx/include/mach/immap_85xx.h b/arch/ppc/mach-mpc85xx/include/mach/immap_85xx.h
index b802249..bf0f7f5 100644
--- a/arch/ppc/mach-mpc85xx/include/mach/immap_85xx.h
+++ b/arch/ppc/mach-mpc85xx/include/mach/immap_85xx.h
@@ -39,6 +39,11 @@
 
 #define MPC85xx_GPIO_OFFSET	0xf000
 #define MPC85xx_L2_OFFSET	0x20000
+#ifdef CONFIG_TSECV2
+#define TSEC1_OFFSET		0xB0000
+#else
+#define TSEC1_OFFSET		0x24000
+#endif
 
 #define MPC85xx_PIC_OFFSET	0x40000
 #define MPC85xx_GUTS_OFFSET	0xe0000
@@ -129,4 +134,6 @@
 #define		MPC85xx_DEVDISR_TB1	0x00001000
 #define MPC85xx_GUTS_RSTCR_OFFSET	0xb0
 
+#define GFAR_BASE_ADDR		(CFG_IMMR + TSEC1_OFFSET)
+#define MDIO_BASE_ADDR		(CFG_IMMR + 0x24000)
 #endif /*__IMMAP_85xx__*/
-- 
1.7.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH 2/3] net: GIANFAR driver
  2012-07-25 16:00 [PATCH 0/3] ppc: Freescale TSEC driver Renaud Barbier
  2012-07-25 16:00 ` [PATCH 1/3] ppc: GIANFAR base address definition Renaud Barbier
@ 2012-07-25 16:01 ` Renaud Barbier
  2012-07-27  7:43   ` Sascha Hauer
  2012-07-25 16:01 ` [PATCH 3/3] ppc: P2020RDB Ethernet configuration Renaud Barbier
                   ` (5 subsequent siblings)
  7 siblings, 1 reply; 12+ messages in thread
From: Renaud Barbier @ 2012-07-25 16:01 UTC (permalink / raw)
  To: barebox

This update adds the GIANFAR driver along with the configuration
and build files.

Signed-off-by: Renaud Barbier <renaud.barbier@ge.com>
---
 arch/ppc/mach-mpc85xx/include/mach/gianfar.h |   31 ++
 drivers/net/Kconfig                          |    5 +
 drivers/net/Makefile                         |    1 +
 drivers/net/gianfar.c                        |  558 ++++++++++++++++++++++++++
 drivers/net/gianfar.h                        |  288 +++++++++++++
 5 files changed, 883 insertions(+), 0 deletions(-)
 create mode 100644 arch/ppc/mach-mpc85xx/include/mach/gianfar.h
 create mode 100644 drivers/net/gianfar.c
 create mode 100644 drivers/net/gianfar.h

diff --git a/arch/ppc/mach-mpc85xx/include/mach/gianfar.h b/arch/ppc/mach-mpc85xx/include/mach/gianfar.h
new file mode 100644
index 0000000..1527536
--- /dev/null
+++ b/arch/ppc/mach-mpc85xx/include/mach/gianfar.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2012 GE Intelligent Platforms, Inc.
+ * Copyright 2004, 2007, 2009  Freescale Semiconductor, Inc.
+ * (C) Copyright 2003, Motorola, Inc.
+ * based on tsec.h by Xianghua Xiao and Andy Fleming 2003-2009
+ *
+ * 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
+ *
+ * Platform data for the Motorola Triple Speed Ethernet Controller
+ */
+
+struct gfar_info_struct {
+	unsigned int phyaddr;
+	unsigned int tbiana;
+	unsigned int tbicr;
+	u32 flags;
+	int (*get_mac)(struct gfar_info_struct *, unsigned char *);
+};
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 749ea6a..7d21ed8 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -124,6 +124,11 @@ config DRIVER_NET_DESIGNWARE_ALTDESCRIPTOR
 	depends on DRIVER_NET_DESIGNWARE
 	default n
 
+config DRIVER_NET_GIANFAR
+	bool "Gianfar Ethernet"
+	depends on ARCH_MPC85XX
+	select MIIDEV
+
 source "drivers/net/usb/Kconfig"
 
 endmenu
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 29727b7..4d960e8 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -14,3 +14,4 @@ obj-$(CONFIG_NET_USB)			+= usb/
 obj-$(CONFIG_DRIVER_NET_TSE)		+= altera_tse.o
 obj-$(CONFIG_DRIVER_NET_KS8851_MLL)	+= ks8851_mll.o
 obj-$(CONFIG_DRIVER_NET_DESIGNWARE)	+= designware.o
+obj-$(CONFIG_DRIVER_NET_GIANFAR)	+= gianfar.o
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
new file mode 100644
index 0000000..d12c18d
--- /dev/null
+++ b/drivers/net/gianfar.c
@@ -0,0 +1,558 @@
+/*
+ * Freescale Three Speed Ethernet Controller driver
+ *
+ * This software may be used and distributed according to the
+ * terms of the GNU Public License, Version 2, incorporated
+ * herein by reference.
+ *
+ * Copyright 2012 GE Intelligent Platforms, Inc.
+ * based on work by Andy Fleming
+ */
+
+#include <config.h>
+#include <common.h>
+#include <malloc.h>
+#include <net.h>
+#include <init.h>
+#include <driver.h>
+#include <miidev.h>
+#include <command.h>
+#include <errno.h>
+#include <asm/io.h>
+#include "gianfar.h"
+
+#define TX_BUF_CNT	2
+#define RX_BUF_CNT 	PKTBUFSRX
+#define BUF_ALIGN	8
+
+/*
+ * Initialize required registers to appropriate values, zeroing
+ * those we don't care about (unless zero is bad, in which case,
+ * choose a more appropriate value)
+ */
+static void init_registers(void __iomem *regs)
+{
+	out_be32(regs + GFAR_IEVENT_OFFSET, GFAR_IEVENT_INIT_CLEAR);
+
+	out_be32(regs + GFAR_IMASK_OFFSET, GFAR_IMASK_INIT_CLEAR);
+
+	out_be32(regs + GFAR_IADDR(0), 0);
+	out_be32(regs + GFAR_IADDR(1), 0);
+	out_be32(regs + GFAR_IADDR(2), 0);
+	out_be32(regs + GFAR_IADDR(3), 0);
+	out_be32(regs + GFAR_IADDR(4), 0);
+	out_be32(regs + GFAR_IADDR(5), 0);
+	out_be32(regs + GFAR_IADDR(6), 0);
+	out_be32(regs + GFAR_IADDR(7), 0);
+
+	out_be32(regs + GFAR_GADDR(0), 0);
+	out_be32(regs + GFAR_GADDR(1), 0);
+	out_be32(regs + GFAR_GADDR(2), 0);
+	out_be32(regs + GFAR_GADDR(3), 0);
+	out_be32(regs + GFAR_GADDR(4), 0);
+	out_be32(regs + GFAR_GADDR(5), 0);
+	out_be32(regs + GFAR_GADDR(6), 0);
+	out_be32(regs + GFAR_GADDR(7), 0);
+
+	out_be32(regs + GFAR_RCTRL_OFFSET, 0x00000000);
+
+	memset((void *)(regs + GFAR_TR64_OFFSET), 0,
+			GFAR_CAM2_OFFSET - GFAR_TR64_OFFSET);
+
+	out_be32(regs + GFAR_CAM1_OFFSET, 0xffffffff);
+	out_be32(regs + GFAR_CAM2_OFFSET, 0xffffffff);
+
+	out_be32(regs + GFAR_MRBLR_OFFSET, MRBLR_INIT_SETTINGS);
+
+	out_be32(regs + GFAR_MINFLR_OFFSET, MINFLR_INIT_SETTINGS);
+
+	out_be32(regs + GFAR_ATTR_OFFSET, ATTR_INIT_SETTINGS);
+	out_be32(regs + GFAR_ATTRELI_OFFSET, ATTRELI_INIT_SETTINGS);
+}
+
+/*
+ * Configure maccfg2 based on negotiated speed and duplex
+ * reported by PHY handling code
+ */
+static void adjust_link(struct eth_device *dev)
+{
+	struct gfar_private *priv = (struct gfar_private *)dev->priv;
+	void __iomem *regs = priv->regs;
+	u32 ecntrl, maccfg2;
+	uint32_t status;
+
+	status = miidev_get_status(&priv->miidev);
+
+	priv->link = status & MIIDEV_STATUS_IS_UP;
+	if (status & MIIDEV_STATUS_IS_FULL_DUPLEX)
+		priv->duplexity = 1;
+	else
+		priv->duplexity = 0;
+
+	if (status & MIIDEV_STATUS_IS_1000MBIT)
+		priv->speed = 1000;
+	else if (status & MIIDEV_STATUS_IS_100MBIT)
+		priv->speed = 100;
+	else
+		priv->speed = 10;
+
+	if (priv->link) {
+		/* clear all bits relative with interface mode */
+		ecntrl = in_be32(regs + GFAR_ECNTRL_OFFSET);
+		ecntrl &= ~GFAR_ECNTRL_R100;
+
+		maccfg2 = in_be32(regs + GFAR_MACCFG2_OFFSET);
+		maccfg2 &= ~(GFAR_MACCFG2_IF | GFAR_MACCFG2_FULL_DUPLEX);
+
+		if (priv->duplexity != 0)
+			maccfg2 |= GFAR_MACCFG2_FULL_DUPLEX;
+		else
+			maccfg2 &= ~(GFAR_MACCFG2_FULL_DUPLEX);
+
+		switch (priv->speed) {
+		case 1000:
+			maccfg2 |= GFAR_MACCFG2_GMII;
+			break;
+		case 100:
+		case 10:
+			maccfg2 |= GFAR_MACCFG2_MII;
+			/*
+			 * Set R100 bit in all modes although
+			 * it is only used in RGMII mode
+			 */
+			if (priv->speed == 100)
+				ecntrl |= GFAR_ECNTRL_R100;
+			break;
+		default:
+			printf("%s: Speed was bad\n", dev->dev.name);
+			break;
+		}
+
+		out_be32(regs + GFAR_ECNTRL_OFFSET, ecntrl);
+		out_be32(regs + GFAR_MACCFG2_OFFSET, maccfg2);
+
+		printf("Speed: %d, %s duplex\n", priv->speed,
+		       (priv->duplexity) ? "full" : "half");
+
+	} else {
+		printf("%s: No link.\n", dev->dev.name);
+	}
+}
+
+/* Stop the interface */
+static void gfar_halt(struct eth_device *dev)
+{
+	struct gfar_private *priv = (struct gfar_private *)dev->priv;
+	void __iomem *regs = priv->regs;
+	int value;
+
+	clrbits_be32(regs + GFAR_DMACTRL_OFFSET, GFAR_DMACTRL_GRS |
+			GFAR_DMACTRL_GTS);
+	setbits_be32(regs + GFAR_DMACTRL_OFFSET, GFAR_DMACTRL_GRS |
+			GFAR_DMACTRL_GTS);
+
+	value = in_be32(regs + GFAR_IEVENT_OFFSET);
+	value &= (GFAR_IEVENT_GRSC | GFAR_IEVENT_GTSC);
+
+	while (value != (GFAR_IEVENT_GRSC | GFAR_IEVENT_GTSC)) {
+		value = in_be32(regs + GFAR_IEVENT_OFFSET);
+		value &= (GFAR_IEVENT_GRSC | GFAR_IEVENT_GTSC);
+	}
+
+	clrbits_be32(regs + GFAR_MACCFG1_OFFSET,
+			GFAR_MACCFG1_TX_EN | GFAR_MACCFG1_RX_EN);
+}
+
+/* Initializes registers for the controller. */
+static int gfar_init(struct eth_device *dev)
+{
+	struct gfar_private *priv = (struct gfar_private *)dev->priv;
+	void __iomem *regs = priv->regs;
+
+	gfar_halt(dev);
+
+	/* Init MACCFG2. Default to GMII */
+	out_be32(regs + GFAR_MACCFG2_OFFSET, MACCFG2_INIT_SETTINGS);
+	out_be32(regs + GFAR_ECNTRL_OFFSET, ECNTRL_INIT_SETTINGS);
+
+	priv->rxIdx = 0;
+	priv->txIdx = 0;
+
+	init_registers(regs);
+
+	miidev_restart_aneg(&priv->miidev);
+
+	return  0;
+}
+
+static int gfar_open(struct eth_device *dev)
+{
+	int ix;
+	struct gfar_private *priv = (struct gfar_private *)dev->priv;
+	void __iomem *regs = priv->regs;
+
+	/* Point to the buffer descriptors */
+	out_be32(regs + GFAR_TBASE0_OFFSET, (unsigned int)priv->txbd);
+	out_be32(regs + GFAR_RBASE0_OFFSET, (unsigned int)priv->rxbd);
+
+	/* Initialize the Rx Buffer descriptors */
+	for (ix = 0; ix < RX_BUF_CNT; ix++) {
+		priv->rxbd[ix].status = RXBD_EMPTY;
+		priv->rxbd[ix].length = 0;
+		priv->rxbd[ix].bufPtr = (uint) NetRxPackets[ix];
+	}
+	priv->rxbd[RX_BUF_CNT - 1].status |= RXBD_WRAP;
+
+	/* Initialize the TX Buffer Descriptors */
+	for (ix = 0; ix < TX_BUF_CNT; ix++) {
+		priv->txbd[ix].status = 0;
+		priv->txbd[ix].length = 0;
+		priv->txbd[ix].bufPtr = 0;
+	}
+	priv->txbd[TX_BUF_CNT - 1].status |= TXBD_WRAP;
+
+	miidev_wait_aneg(&priv->miidev);
+	adjust_link(dev);
+
+	/* Enable Transmit and Receive */
+	setbits_be32(regs + GFAR_MACCFG1_OFFSET, GFAR_MACCFG1_RX_EN |
+			GFAR_MACCFG1_TX_EN);
+
+	/* Tell the DMA it is clear to go */
+	setbits_be32(regs + GFAR_DMACTRL_OFFSET, DMACTRL_INIT_SETTINGS);
+	out_be32(regs + GFAR_TSTAT_OFFSET, GFAR_TSTAT_CLEAR_THALT);
+	out_be32(regs + GFAR_RSTAT_OFFSET, GFAR_RSTAT_CLEAR_RHALT);
+	clrbits_be32(regs + GFAR_DMACTRL_OFFSET, GFAR_DMACTRL_GRS |
+			GFAR_DMACTRL_GTS);
+
+	return 0;
+}
+
+static int gfar_get_ethaddr(struct eth_device *dev, unsigned char *mac)
+{
+	struct device_d *edev = dev->parent;
+	struct gfar_info_struct *gfar_info =
+		(struct gfar_info_struct *)edev->platform_data;
+	int (*get_mac)(struct gfar_info_struct *, unsigned char *) =
+		gfar_info->get_mac;
+
+	if (get_mac)
+		get_mac(gfar_info, mac);
+	else
+		return -ENODEV;
+
+	return 0;
+}
+
+static int gfar_set_ethaddr(struct eth_device *dev, unsigned char *mac)
+{
+	struct gfar_private *priv = (struct gfar_private *)dev->priv;
+	void __iomem *regs = priv->regs;
+	char tmpbuf[MAC_ADDR_LEN];
+	uint tempval;
+	int ix;
+
+	for (ix = 0; ix < MAC_ADDR_LEN; ix++)
+		tmpbuf[MAC_ADDR_LEN - 1 - ix] = mac[ix];
+
+	tempval = (tmpbuf[0] << 24) | (tmpbuf[1] << 16) | (tmpbuf[2] << 8) |
+		  tmpbuf[3];
+
+	out_be32(regs + GFAR_MACSTRADDR1_OFFSET, tempval);
+
+	tempval = *((uint *)(tmpbuf + 4));
+
+	out_be32(regs + GFAR_MACSTRADDR2_OFFSET, tempval);
+
+	return 0;
+}
+
+/* Writes the given phy's reg with value, using the specified MDIO regs */
+static int gfar_local_mdio_write(void __iomem *phyregs, uint addr, uint reg,
+				uint value)
+{
+	uint64_t start;
+
+	out_be32(phyregs + GFAR_MIIMADD_OFFSET, (addr << 8) | (reg & 0x1f));
+	out_be32(phyregs + GFAR_MIIMCON_OFFSET, value);
+
+	start = get_time_ns();
+
+	while (!is_timeout(start, 10 * MSECOND)) {
+		if (!(in_be32(phyregs + GFAR_MIIMMIND_OFFSET) &
+					GFAR_MIIMIND_BUSY))
+			return 0;
+	}
+
+	return -EIO;
+}
+
+/*
+ * Reads register regnum on the device's PHY through the
+ * specified registers. It lowers and raises the read
+ * command, and waits for the data to become valid (miimind
+ * notvalid bit cleared), and the bus to cease activity (miimind
+ * busy bit cleared), and then returns the value
+ */
+static uint gfar_local_mdio_read(void __iomem *phyregs, uint phyid, uint regnum)
+{
+	uint64_t start;
+
+	/* Put the address of the phy, and the register number into MIIMADD */
+	out_be32(phyregs + GFAR_MIIMADD_OFFSET, (phyid << 8) | (regnum & 0x1f));
+
+	/* Clear the command register, and wait */
+	out_be32(phyregs + GFAR_MIIMCOM_OFFSET, 0);
+
+	/* Initiate a read command, and wait */
+	out_be32(phyregs + GFAR_MIIMCOM_OFFSET, GFAR_MIIM_READ_COMMAND);
+
+	start = get_time_ns();
+
+	while (!is_timeout(start, 10 * MSECOND)) {
+		if (!(in_be32(phyregs + GFAR_MIIMMIND_OFFSET) &
+			(GFAR_MIIMIND_NOTVALID | GFAR_MIIMIND_BUSY)))
+			return in_be32(phyregs + GFAR_MIIMSTAT_OFFSET);
+	}
+	return -EIO;
+}
+
+static void gfar_configure_serdes(struct gfar_private *priv)
+{
+	gfar_local_mdio_write(priv->phyregs_sgmii,
+			in_be32(priv->regs + GFAR_TBIPA_OFFSET), GFAR_TBI_ANA,
+			priv->tbiana);
+	gfar_local_mdio_write(priv->phyregs_sgmii,
+			in_be32(priv->regs + GFAR_TBIPA_OFFSET),
+			GFAR_TBI_TBICON, GFAR_TBICON_CLK_SELECT);
+	gfar_local_mdio_write(priv->phyregs_sgmii,
+			in_be32(priv->regs + GFAR_TBIPA_OFFSET), GFAR_TBI_CR,
+			priv->tbicr);
+}
+
+/* Reset the internal and external PHYs. */
+static void init_phy(struct eth_device *dev)
+{
+	struct gfar_private *priv = (struct gfar_private *)dev->priv;
+	void __iomem *regs = priv->regs;
+	uint64_t start;
+
+	/* Assign a Physical address to the TBI */
+	out_be32(regs + GFAR_TBIPA_OFFSET, GFAR_TBIPA_VALUE);
+
+	/* Reset MII (due to new addresses) */
+	out_be32(priv->phyregs + GFAR_MIIMCFG_OFFSET, GFAR_MIIMCFG_RESET);
+	out_be32(priv->phyregs + GFAR_MIIMCFG_OFFSET, GFAR_MIIMCFG_INIT_VALUE);
+
+	start = get_time_ns();
+	while (!is_timeout(start, 10 * MSECOND)) {
+		if (!(in_be32(priv->phyregs + GFAR_MIIMMIND_OFFSET) &
+			GFAR_MIIMIND_BUSY))
+			break;
+	}
+
+	gfar_local_mdio_write(priv->phyregs, priv->phyaddr, GFAR_MIIM_CR,
+			GFAR_MIIM_CR_RST);
+
+	start = get_time_ns();
+	while (!is_timeout(start, 10 * MSECOND)) {
+		if (!(gfar_local_mdio_read(priv->phyregs, priv->phyaddr,
+					GFAR_MIIM_CR) & GFAR_MIIM_CR_RST))
+			break;
+	}
+
+	if (in_be32(regs + GFAR_ECNTRL_OFFSET) & GFAR_ECNTRL_SGMII_MODE)
+		gfar_configure_serdes(priv);
+}
+
+static int gfar_send(struct eth_device *dev, void *packet, int length)
+{
+	int ix;
+	struct gfar_private *priv = (struct gfar_private *)dev->priv;
+	void __iomem *regs = priv->regs;
+
+	/* Find an empty buffer descriptor */
+	for (ix = 0; priv->txbd[priv->txIdx].status & TXBD_READY; ix++) {
+		if (ix >= TOUT_LOOP) {
+			debug("gfar: tx buffers full\n");
+			return -EBUSY;
+		}
+	}
+
+	priv->txbd[priv->txIdx].bufPtr = (uint) packet;
+	priv->txbd[priv->txIdx].length = length;
+	priv->txbd[priv->txIdx].status |= (TXBD_READY | TXBD_LAST | TXBD_CRC);
+
+	/* Tell the DMA to go */
+	out_be32(regs + GFAR_TSTAT_OFFSET, GFAR_TSTAT_CLEAR_THALT);
+
+	/* Wait for buffer to be transmitted */
+	for (ix = 0; priv->txbd[priv->txIdx].status & TXBD_READY; ix++) {
+		if (ix >= TOUT_LOOP) {
+			debug("gfar: tx error: 0x%x\n",
+				priv->txbd[priv->txIdx].status);
+			return -EBUSY;
+		}
+	}
+
+	if (priv->txbd[priv->txIdx].status & TXBD_STATS) {
+		printf("TX error: 0x%x\n", priv->txbd[priv->txIdx].status);
+		return -EIO;
+	}
+
+	priv->txIdx = (priv->txIdx + 1) % TX_BUF_CNT;
+
+	return 0;
+}
+
+static int gfar_recv(struct eth_device *dev)
+{
+	int length;
+	struct gfar_private *priv = (struct gfar_private *)dev->priv;
+	void __iomem *regs = priv->regs;
+
+	while (!(priv->rxbd[priv->rxIdx].status & RXBD_EMPTY)) {
+		length = priv->rxbd[priv->rxIdx].length;
+
+		/* Send the packet up if there were no errors */
+		if (!(priv->rxbd[priv->rxIdx].status & RXBD_STATS)) {
+			net_receive(NetRxPackets[priv->rxIdx], length - 4);
+		} else {
+			printf("Got error %x\n",
+			       (priv->rxbd[priv->rxIdx].status & RXBD_STATS));
+		}
+
+		priv->rxbd[priv->rxIdx].length = 0;
+
+		/* Set the wrap bit if this is the last element in the list */
+		if ((priv->rxIdx + 1) == RX_BUF_CNT)
+			priv->rxbd[priv->rxIdx].status = RXBD_WRAP;
+		else
+			priv->rxbd[priv->rxIdx].status = 0;
+
+		priv->rxbd[priv->rxIdx].status |= RXBD_EMPTY;
+		priv->rxIdx = (priv->rxIdx + 1) % RX_BUF_CNT;
+	}
+
+	if (in_be32(regs + GFAR_IEVENT_OFFSET) & GFAR_IEVENT_BSY) {
+		out_be32(regs + GFAR_IEVENT_OFFSET, GFAR_IEVENT_BSY);
+		out_be32(regs + GFAR_RSTAT_OFFSET, GFAR_RSTAT_CLEAR_RHALT);
+	}
+
+	return 0;
+}
+
+/* Read a MII PHY register. */
+static int gfar_miiphy_read(struct mii_device *mdev, int addr, int reg)
+{
+	unsigned short ret;
+	struct eth_device *edev = mdev->edev;
+	struct gfar_private *priv = (struct gfar_private *)edev->priv;
+
+	if (NULL == priv) {
+		printf("Can't read PHY at address %d\n", addr);
+		return -1;
+	}
+
+	return gfar_local_mdio_read(priv->phyregs, addr, reg);
+}
+
+/* Write a MII PHY register.  */
+static int gfar_miiphy_write(struct mii_device *mdev, int addr,
+			     int reg, int value)
+{
+	struct eth_device *edev = mdev->edev;
+	struct gfar_private *priv = (struct gfar_private *)edev->priv;
+	unsigned short val = value;
+
+	if (NULL == priv) {
+		printf("Can't write PHY at address %d\n", addr);
+		return -1;
+	}
+
+	gfar_local_mdio_write(priv->phyregs, addr, reg, val);
+
+	return 0;
+}
+
+/*
+ * Initialize device structure. Returns success if
+ * initialization succeeded.
+ */
+static int gfar_probe(struct device_d *dev)
+{
+	struct gfar_info_struct *gfar_info =
+		(struct gfar_info_struct *)dev->platform_data;
+	struct eth_device *edev;
+	struct gfar_private *priv;
+	size_t size;
+	char *p;
+
+	edev = (struct eth_device *)xzalloc(sizeof(struct eth_device) +
+					    sizeof(struct gfar_private));
+
+	if (NULL == edev)
+		return -ENODEV;
+
+	priv = (struct gfar_private *)(edev + 1);
+
+	priv->regs = dev_request_mem_region(dev, 0);
+	priv->phyregs = dev_request_mem_region(dev, 1);
+	priv->phyregs_sgmii = dev_request_mem_region(dev, 2);
+
+	priv->phyaddr = gfar_info->phyaddr;
+	priv->flags = gfar_info->flags;
+	priv->tbicr = gfar_info->tbicr;
+	priv->tbiana = gfar_info->tbiana;
+
+	/* Allocate descriptors. 64-byte aligned. */
+	size = (TX_BUF_CNT * (sizeof(struct txbd8) +
+		(RX_BUF_CNT * sizeof(struct rxbd8)))) + BUF_ALIGN;
+	p = (char *)xzalloc(size);
+	p += BUF_ALIGN;
+	p = (char *)((ulong)p & (~(BUF_ALIGN - 1)));
+
+	priv->txbd = (struct txbd8 *)p;
+	priv->rxbd = (struct rxbd8 *)(p +
+			(TX_BUF_CNT * sizeof(struct txbd8)));
+
+	edev->priv = priv;
+	edev->init = gfar_init;
+	edev->open = gfar_open;
+	edev->halt = gfar_halt;
+	edev->send = gfar_send;
+	edev->recv = gfar_recv;
+	edev->get_ethaddr = gfar_get_ethaddr;
+	edev->set_ethaddr = gfar_set_ethaddr;
+	edev->parent = dev;
+
+	setbits_be32(priv->regs + GFAR_MACCFG1_OFFSET, GFAR_MACCFG1_SOFT_RESET);
+	udelay(2);
+	clrbits_be32(priv->regs + GFAR_MACCFG1_OFFSET, GFAR_MACCFG1_SOFT_RESET);
+
+	priv->miidev.read = gfar_miiphy_read;
+	priv->miidev.write = gfar_miiphy_write;
+	priv->miidev.address = priv->phyaddr;
+	priv->miidev.flags = 0;
+	priv->miidev.edev = edev;
+	priv->miidev.parent = dev;
+
+	init_phy(edev);
+
+	mii_register(&priv->miidev);
+
+	return eth_register(edev);
+}
+
+static struct driver_d gfar_eth_driver = {
+	.name  = "gfar",
+	.probe = gfar_probe,
+};
+
+static int gfar_eth_init(void)
+{
+	register_driver(&gfar_eth_driver);
+	return 0;
+}
+
+device_initcall(gfar_eth_init);
diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h
new file mode 100644
index 0000000..9edbd12
--- /dev/null
+++ b/drivers/net/gianfar.h
@@ -0,0 +1,288 @@
+/*
+ *  gianfar.h
+ *
+ *  Driver for the Motorola Triple Speed Ethernet Controller
+ *
+ *  This software may be used and distributed according to the
+ *  terms of the GNU Public License, Version 2, incorporated
+ *  herein by reference.
+ *
+ * Copyright 2012 GE Intelligent Platforms, Inc.
+ * Copyright 2004, 2007, 2009  Freescale Semiconductor, Inc.
+ * (C) Copyright 2003, Motorola, Inc.
+ * based on tsec.h by Xianghua Xiao and Andy Fleming 2003-2009
+ */
+
+#ifndef __GIANFAR_H
+#define __GIANFAR_H
+
+#include <net.h>
+#include <config.h>
+#include <mach/gianfar.h>
+
+#define MAC_ADDR_LEN 6
+
+#define TOUT_LOOP	1000000
+
+#define PHY_AUTONEGOTIATE_TIMEOUT	5000 /* in ms */
+
+/* TBI register addresses */
+#define GFAR_TBI_CR		0x00
+#define GFAR_TBI_SR		0x01
+#define GFAR_TBI_ANA		0x04
+#define GFAR_TBI_ANLPBPA	0x05
+#define GFAR_TBI_ANEX		0x06
+#define GFAR_TBI_TBICON		0x11
+
+/* TBI MDIO register bit fields*/
+#define GFAR_TBICON_CLK_SELECT		0x0020
+#define GFAR_TBIANA_ASYMMETRIC_PAUSE	0x0100
+#define GFAR_TBIANA_SYMMETRIC_PAUSE	0x0080
+#define GFAR_TBIANA_HALF_DUPLEX		0x0040
+#define GFAR_TBIANA_FULL_DUPLEX		0x0020
+/* The two reserved bits below are used in AN3869 to enable SGMII. */
+#define GFAR_TBIANA_RESERVED1		0x4000
+#define GFAR_TBIANA_RESERVED15		0x0001
+#define GFAR_TBICR_PHY_RESET		0x8000
+#define GFAR_TBICR_ANEG_ENABLE		0x1000
+#define GFAR_TBICR_RESTART_ANEG		0x0200
+#define GFAR_TBICR_FULL_DUPLEX		0x0100
+#define GFAR_TBICR_SPEED1_SET		0x0040
+
+/* MAC register bits */
+#define GFAR_MACCFG1_SOFT_RESET		0x80000000
+#define GFAR_MACCFG1_RESET_RX_MC	0x00080000
+#define GFAR_MACCFG1_RESET_TX_MC	0x00040000
+#define GFAR_MACCFG1_RESET_RX_FUN	0x00020000
+#define TESC_MACCFG1_RESET_TX_FUN	0x00010000
+#define GFAR_MACCFG1_LOOPBACK		0x00000100
+#define GFAR_MACCFG1_RX_FLOW		0x00000020
+#define GFAR_MACCFG1_TX_FLOW		0x00000010
+#define GFAR_MACCFG1_SYNCD_RX_EN	0x00000008
+#define GFAR_MACCFG1_RX_EN		0x00000004
+#define GFAR_MACCFG1_SYNCD_TX_EN	0x00000002
+#define GFAR_MACCFG1_TX_EN		0x00000001
+
+#define MACCFG2_INIT_SETTINGS		0x00007205
+#define GFAR_MACCFG2_FULL_DUPLEX	0x00000001
+#define GFAR_MACCFG2_IF			0x00000300
+#define GFAR_MACCFG2_GMII		0x00000200
+#define GFAR_MACCFG2_MII		0x00000100
+
+#define ECNTRL_INIT_SETTINGS		0x00001000
+#define GFAR_ECNTRL_TBI_MODE		0x00000020
+#define GFAR_ECNTRL_R100		0x00000008
+#define GFAR_ECNTRL_SGMII_MODE		0x00000002
+
+#ifndef GFAR_TBIPA_VALUE
+	#define GFAR_TBIPA_VALUE	0x1f
+#endif
+#define GFAR_MIIMCFG_INIT_VALUE		0x00000003
+#define GFAR_MIIMCFG_RESET		0x80000000
+
+#define GFAR_MIIMIND_BUSY		0x00000001
+#define GFAR_MIIMIND_NOTVALID		0x00000004
+
+#define GFAR_MIIM_CONTROL		0x00000000
+#define GFAR_MIIM_CONTROL_RESET		0x00009140
+#define GFAR_MIIM_CONTROL_INIT		0x00001140
+#define GFAR_MIIM_CONTROL_RESTART	0x00001340
+#define GFAR_MIIM_ANEN			0x00001000
+
+#define GFAR_MIIM_CR			0x00000000
+#define GFAR_MIIM_CR_RST		0x00008000
+#define GFAR_MIIM_CR_INIT		0x00001000
+
+#define GFAR_MIIM_STATUS		0x1
+#define GFAR_MIIM_STATUS_AN_DONE	0x00000020
+#define GFAR_MIIM_STATUS_LINK		0x0004
+
+#define GFAR_MIIM_PHYIR1		0x2
+#define GFAR_MIIM_PHYIR2		0x3
+
+#define GFAR_MIIM_ANAR			0x4
+#define GFAR_MIIM_ANAR_INIT		0x1e1
+
+#define GFAR_MIIM_TBI_ANLPBPA		0x5
+#define GFAR_MIIM_TBI_ANLPBPA_HALF	0x00000040
+#define GFAR_MIIM_TBI_ANLPBPA_FULL	0x00000020
+
+#define GFAR_MIIM_TBI_ANEX		0x6
+#define GFAR_MIIM_TBI_ANEX_NP		0x00000004
+#define GFAR_MIIM_TBI_ANEX_PRX		0x00000002
+
+#define GFAR_MIIM_GBIT_CONTROL		0x9
+#define GFAR_MIIM_GBIT_CONTROL_INIT	0xe00
+
+#define GFAR_MIIM_EXT_PAGE_ACCESS	0x1f
+
+#define GFAR_MIIM_GBIT_CON		0x09
+#define GFAR_MIIM_GBIT_CON_ADVERT	0x0e00
+
+#define GFAR_MIIM_READ_COMMAND		0x00000001
+
+#define MRBLR_INIT_SETTINGS	1536
+
+#define MINFLR_INIT_SETTINGS	0x00000040
+
+#define DMACTRL_INIT_SETTINGS	0x000000c3
+#define GFAR_DMACTRL_GRS	0x00000010
+#define GFAR_DMACTRL_GTS	0x00000008
+
+#define GFAR_TSTAT_CLEAR_THALT	0x80000000
+#define GFAR_RSTAT_CLEAR_RHALT	0x00800000
+
+#define GFAR_IEVENT_INIT_CLEAR	0xffffffff
+#define GFAR_IEVENT_BABR	0x80000000
+#define GFAR_IEVENT_RXC		0x40000000
+#define GFAR_IEVENT_BSY		0x20000000
+#define GFAR_IEVENT_EBERR	0x10000000
+#define GFAR_IEVENT_MSRO	0x04000000
+#define GFAR_IEVENT_GTSC	0x02000000
+#define GFAR_IEVENT_BABT	0x01000000
+#define GFAR_IEVENT_TXC		0x00800000
+#define GFAR_IEVENT_TXE		0x00400000
+#define GFAR_IEVENT_TXB		0x00200000
+#define GFAR_IEVENT_TXF		0x00100000
+#define GFAR_IEVENT_IE		0x00080000
+#define GFAR_IEVENT_LC		0x00040000
+#define GFAR_IEVENT_CRL		0x00020000
+#define GFAR_IEVENT_XFUN	0x00010000
+#define GFAR_IEVENT_RXB0	0x00008000
+#define GFAR_IEVENT_GRSC	0x00000100
+#define GFAR_IEVENT_RXF0	0x00000080
+
+#define GFAR_IMASK_INIT_CLEAR	0x00000000
+
+/* Default Attribute fields */
+#define ATTR_INIT_SETTINGS     0x000000c0
+#define ATTRELI_INIT_SETTINGS  0x00000000
+
+/* TxBD status field bits */
+#define TXBD_READY		0x8000
+#define TXBD_PADCRC		0x4000
+#define TXBD_WRAP		0x2000
+#define TXBD_INTERRUPT		0x1000
+#define TXBD_LAST		0x0800
+#define TXBD_CRC		0x0400
+#define TXBD_DEF		0x0200
+#define TXBD_HUGEFRAME		0x0080
+#define TXBD_LATECOLLISION	0x0080
+#define TXBD_RETRYLIMIT		0x0040
+#define	TXBD_RETRYCOUNTMASK	0x003c
+#define TXBD_UNDERRUN		0x0002
+#define TXBD_STATS		0x03ff
+
+/* RxBD status field bits */
+#define RXBD_EMPTY		0x8000
+#define RXBD_RO1		0x4000
+#define RXBD_WRAP		0x2000
+#define RXBD_INTERRUPT		0x1000
+#define RXBD_LAST		0x0800
+#define RXBD_FIRST		0x0400
+#define RXBD_MISS		0x0100
+#define RXBD_BROADCAST		0x0080
+#define RXBD_MULTICAST		0x0040
+#define RXBD_LARGE		0x0020
+#define RXBD_NONOCTET		0x0010
+#define RXBD_SHORT		0x0008
+#define RXBD_CRCERR		0x0004
+#define RXBD_OVERRUN		0x0002
+#define RXBD_TRUNCATED		0x0001
+#define RXBD_STATS		0x003f
+
+struct txbd8 {
+	ushort	     status;	     /* Status Fields */
+	ushort	     length;	     /* Buffer length */
+	uint	     bufPtr;	     /* Buffer Pointer */
+};
+
+struct rxbd8 {
+	ushort	     status;	     /* Status Fields */
+	ushort	     length;	     /* Buffer Length */
+	uint	     bufPtr;	     /* Buffer Pointer */
+};
+
+/* eTSEC general control and status registers */
+#define GFAR_IEVENT_OFFSET	0x010	/* Interrupt Event */
+#define GFAR_IMASK_OFFSET	0x014	/* Interrupt Mask */
+#define GFAR_ECNTRL_OFFSET	0x020	/* Ethernet Control */
+#define GFAR_MINFLR_OFFSET	0x024	/* Minimum Frame Length */
+#define GFAR_DMACTRL_OFFSET	0x02c	/* DMA Control */
+#define GFAR_TBIPA_OFFSET	0x030	/* TBI PHY address */
+
+/* eTSEC transmit control and status register */
+#define GFAR_TSTAT_OFFSET	0x104	/* transmit status register */
+#define GFAR_TBASE0_OFFSET	0x204	/* TxBD Base Address */
+
+/* eTSEC receive control and status register */
+#define GFAR_RCTRL_OFFSET	0x300	/* Receive Control */
+#define GFAR_RSTAT_OFFSET	0x304	/* transmit status register */
+#define GFAR_MRBLR_OFFSET	0x340	/* Maximum Receive Buffer Length */
+#define GFAR_RBASE0_OFFSET	0x404	/* RxBD Base Address */
+
+/* eTSEC MAC registers */
+#define GFAR_MACCFG1_OFFSET	0x500	/* MAC Configuration #1 */
+#define GFAR_MACCFG2_OFFSET	0x504	/* MAC Configuration #2 */
+#define GFAR_MIIMCFG_OFFSET	0x520	/* MII management configuration */
+#define GFAR_MIIMCOM_OFFSET	0x524	/* MII management command */
+#define GFAR_MIIMADD_OFFSET	0x528	/* MII management address */
+#define GFAR_MIIMCON_OFFSET	0x52c	/* MII management control */
+#define GFAR_MIIMSTAT_OFFSET	0x530	/* MII management status */
+#define GFAR_MIIMMIND_OFFSET	0x534	/* MII management indicator */
+#define GFAR_MACSTRADDR1_OFFSET 0x540	/* MAC station address #1 */
+#define GFAR_MACSTRADDR2_OFFSET 0x544	/* MAC station address #2 */
+
+/* eTSEC transmit and receive counters registers. */
+#define GFAR_TR64_OFFSET	0x680
+/* eTSEC counter control and TOE statistics registers */
+#define GFAR_CAM1_OFFSET	0x738
+#define GFAR_CAM2_OFFSET	0x73c
+
+/* Individual/group address registers */
+#define GFAR_IADDR0_OFFSET	0x800
+#define GFAR_IADDR1_OFFSET	0x804
+#define GFAR_IADDR2_OFFSET	0x808
+#define GFAR_IADDR3_OFFSET	0x80c
+#define GFAR_IADDR4_OFFSET	0x810
+#define GFAR_IADDR5_OFFSET	0x814
+#define GFAR_IADDR6_OFFSET	0x818
+#define GFAR_IADDR7_OFFSET	0x81c
+
+#define GFAR_IADDR(REGNUM) (GFAR_IADDR##REGNUM##_OFFSET)
+
+/* Group address registers */
+#define GFAR_GADDR0_OFFSET	0x880
+#define GFAR_GADDR1_OFFSET	0x884
+#define GFAR_GADDR2_OFFSET	0x888
+#define GFAR_GADDR3_OFFSET	0x88c
+#define GFAR_GADDR4_OFFSET	0x890
+#define GFAR_GADDR5_OFFSET	0x894
+#define GFAR_GADDR6_OFFSET	0x898
+#define GFAR_GADDR7_OFFSET	0x89c
+
+#define GFAR_GADDR(REGNUM) (GFAR_GADDR##REGNUM##_OFFSET)
+
+/* eTSEC DMA attributes registers */
+#define GFAR_ATTR_OFFSET	0xbf8	/* Default Attribute Register */
+#define GFAR_ATTRELI_OFFSET	0xbfc	/* Default Attribute Extract Len/Idx */
+
+struct gfar_private {
+	void __iomem *regs;
+	void __iomem *phyregs;
+	void __iomem *phyregs_sgmii;
+	struct phy_info *phyinfo;
+	struct mii_device miidev;
+	volatile struct txbd8 *txbd;
+	volatile struct rxbd8 *rxbd;
+	uint txIdx;
+	uint rxIdx;
+	uint phyaddr;
+	uint tbicr;
+	uint tbiana;
+	u32 flags;
+	uint link;
+	uint duplexity;
+	uint speed;
+};
+#endif /* __GIANFAR_H */
-- 
1.7.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH 3/3] ppc: P2020RDB Ethernet configuration
  2012-07-25 16:00 [PATCH 0/3] ppc: Freescale TSEC driver Renaud Barbier
  2012-07-25 16:00 ` [PATCH 1/3] ppc: GIANFAR base address definition Renaud Barbier
  2012-07-25 16:01 ` [PATCH 2/3] net: GIANFAR driver Renaud Barbier
@ 2012-07-25 16:01 ` Renaud Barbier
  2012-07-27  7:45   ` Sascha Hauer
  2012-08-07 14:30 ` [PATCH V2 0/4] ppc: Freescale TSEC driver Renaud Barbier
                   ` (4 subsequent siblings)
  7 siblings, 1 reply; 12+ messages in thread
From: Renaud Barbier @ 2012-07-25 16:01 UTC (permalink / raw)
  To: barebox

Minimal support of the Ethernet interface on the P2020RDB board. Only
the eTSEC3 interface is supported.

Signed-off-by: Renaud Barbier <renaud.barbier@ge.com>
---
 arch/ppc/boards/freescale-p2020rdb/p2020rdb.c |   38 +++++++++++++++++++++++++
 arch/ppc/configs/p2020rdb_defconfig           |    6 ++++
 2 files changed, 44 insertions(+), 0 deletions(-)

diff --git a/arch/ppc/boards/freescale-p2020rdb/p2020rdb.c b/arch/ppc/boards/freescale-p2020rdb/p2020rdb.c
index 20897cb..201220f 100644
--- a/arch/ppc/boards/freescale-p2020rdb/p2020rdb.c
+++ b/arch/ppc/boards/freescale-p2020rdb/p2020rdb.c
@@ -35,6 +35,7 @@
 #include <mach/mmu.h>
 #include <mach/immap_85xx.h>
 #include <mach/clocks.h>
+#include <mach/gianfar.h>
 #include <mach/early_udelay.h>
 
 #define VSC7385_RST_SET		0x00080000
@@ -61,10 +62,47 @@
 #define SYSCLK_50	50000000
 #define SYSCLK_100	100000000
 
+/* Ethernet. Use eTSEC3 */
+static struct gfar_info_struct gfar_info[] = {
+	{
+	.phyaddr = 1,
+	.tbiana = 0,
+	.tbicr = 0,
+	.flags = 0,
+	},
+};
+
+static int board_eth_init(int num, int idx)
+{
+	struct resource *res;
+
+	res = xzalloc(3 * sizeof(struct resource));
+	/* TSEC interface registers */
+	res[0].start = GFAR_BASE_ADDR + ((num - 1) * 0x1000);
+	res[0].end = res[0].start + 0x1000;
+	res[0].flags = IORESOURCE_MEM;
+	/* External PHY access always through eTSEC1 */
+	res[1].start = MDIO_BASE_ADDR;
+	res[1].end = res[1].start + 0x1000;
+	res[1].flags = IORESOURCE_MEM;
+	/* Access to TBI/RTBI interface. */
+	res[2].start = MDIO_BASE_ADDR + ((num - 1) * 0x1000);
+	res[2].end = res[2].start + 0x1000;
+	res[2].flags = IORESOURCE_MEM;
+
+	add_generic_device_res("gfar", DEVICE_ID_DYNAMIC, res, 3,
+				&gfar_info[idx]);
+
+	return 0;
+}
+
 static int devices_init(void)
 {
 	add_cfi_flash_device(-1, CFG_FLASH_BASE, 16 << 20, 0);
 
+	/* eTSEC3 */
+	board_eth_init(3, 0);
+
 	devfs_add_partition("nor0", 0xf80000, 0x80000, DEVFS_PARTITION_FIXED,
 			    "self0");
 	return 0;
diff --git a/arch/ppc/configs/p2020rdb_defconfig b/arch/ppc/configs/p2020rdb_defconfig
index f8a0687..d025a40 100644
--- a/arch/ppc/configs/p2020rdb_defconfig
+++ b/arch/ppc/configs/p2020rdb_defconfig
@@ -21,3 +21,9 @@ CONFIG_MALLOC_SIZE=0x200000
 CONFIG_BAUDRATE=115200
 CONFIG_DRIVER_SERIAL_NS16550=y
 CONFIG_RELOCATABLE=y
+CONFIG_DRIVER_NET_GIANFAR=y
+CONFIG_NET=y
+CONFIG_NET_PING=y
+CONFIG_NET_TFTP=y
+CONFIG_PING=y
+CONFIG_TFTP=y
-- 
1.7.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 2/3] net: GIANFAR driver
  2012-07-25 16:01 ` [PATCH 2/3] net: GIANFAR driver Renaud Barbier
@ 2012-07-27  7:43   ` Sascha Hauer
  0 siblings, 0 replies; 12+ messages in thread
From: Sascha Hauer @ 2012-07-27  7:43 UTC (permalink / raw)
  To: Renaud Barbier; +Cc: barebox

Hi Renaud,

comments inline.


> + * those we don't care about (unless zero is bad, in which case,
> + * choose a more appropriate value)
> + */
> +static void init_registers(void __iomem *regs)

Not really important, but could you add a gfar_ prefix consistently to
all functions?

> +{
> +	out_be32(regs + GFAR_IEVENT_OFFSET, GFAR_IEVENT_INIT_CLEAR);
> +
> +	out_be32(regs + GFAR_IMASK_OFFSET, GFAR_IMASK_INIT_CLEAR);
> +
> +	out_be32(regs + GFAR_IADDR(0), 0);
> +	out_be32(regs + GFAR_IADDR(1), 0);
> +	out_be32(regs + GFAR_IADDR(2), 0);
> +	out_be32(regs + GFAR_IADDR(3), 0);
> +	out_be32(regs + GFAR_IADDR(4), 0);
> +	out_be32(regs + GFAR_IADDR(5), 0);
> +	out_be32(regs + GFAR_IADDR(6), 0);
> +	out_be32(regs + GFAR_IADDR(7), 0);
> +
> +	out_be32(regs + GFAR_GADDR(0), 0);
> +	out_be32(regs + GFAR_GADDR(1), 0);
> +	out_be32(regs + GFAR_GADDR(2), 0);
> +	out_be32(regs + GFAR_GADDR(3), 0);
> +	out_be32(regs + GFAR_GADDR(4), 0);
> +	out_be32(regs + GFAR_GADDR(5), 0);
> +	out_be32(regs + GFAR_GADDR(6), 0);
> +	out_be32(regs + GFAR_GADDR(7), 0);
> +
> +	out_be32(regs + GFAR_RCTRL_OFFSET, 0x00000000);
> +
> +	memset((void *)(regs + GFAR_TR64_OFFSET), 0,
> +			GFAR_CAM2_OFFSET - GFAR_TR64_OFFSET);
> +
> +	out_be32(regs + GFAR_CAM1_OFFSET, 0xffffffff);
> +	out_be32(regs + GFAR_CAM2_OFFSET, 0xffffffff);
> +
> +	out_be32(regs + GFAR_MRBLR_OFFSET, MRBLR_INIT_SETTINGS);
> +
> +	out_be32(regs + GFAR_MINFLR_OFFSET, MINFLR_INIT_SETTINGS);
> +
> +	out_be32(regs + GFAR_ATTR_OFFSET, ATTR_INIT_SETTINGS);
> +	out_be32(regs + GFAR_ATTRELI_OFFSET, ATTRELI_INIT_SETTINGS);
> +}
> +
> +/*
> + * Configure maccfg2 based on negotiated speed and duplex
> + * reported by PHY handling code
> + */
> +static void adjust_link(struct eth_device *dev)
> +{
> +	struct gfar_private *priv = (struct gfar_private *)dev->priv;
> +	void __iomem *regs = priv->regs;
> +	u32 ecntrl, maccfg2;
> +	uint32_t status;
> +
> +	status = miidev_get_status(&priv->miidev);
> +
> +	priv->link = status & MIIDEV_STATUS_IS_UP;
> +	if (status & MIIDEV_STATUS_IS_FULL_DUPLEX)
> +		priv->duplexity = 1;
> +	else
> +		priv->duplexity = 0;
> +
> +	if (status & MIIDEV_STATUS_IS_1000MBIT)
> +		priv->speed = 1000;
> +	else if (status & MIIDEV_STATUS_IS_100MBIT)
> +		priv->speed = 100;
> +	else
> +		priv->speed = 10;
> +
> +	if (priv->link) {
> +		/* clear all bits relative with interface mode */
> +		ecntrl = in_be32(regs + GFAR_ECNTRL_OFFSET);
> +		ecntrl &= ~GFAR_ECNTRL_R100;
> +
> +		maccfg2 = in_be32(regs + GFAR_MACCFG2_OFFSET);
> +		maccfg2 &= ~(GFAR_MACCFG2_IF | GFAR_MACCFG2_FULL_DUPLEX);
> +
> +		if (priv->duplexity != 0)
> +			maccfg2 |= GFAR_MACCFG2_FULL_DUPLEX;
> +		else
> +			maccfg2 &= ~(GFAR_MACCFG2_FULL_DUPLEX);
> +
> +		switch (priv->speed) {
> +		case 1000:
> +			maccfg2 |= GFAR_MACCFG2_GMII;
> +			break;
> +		case 100:
> +		case 10:
> +			maccfg2 |= GFAR_MACCFG2_MII;
> +			/*
> +			 * Set R100 bit in all modes although
> +			 * it is only used in RGMII mode
> +			 */
> +			if (priv->speed == 100)
> +				ecntrl |= GFAR_ECNTRL_R100;
> +			break;
> +		default:
> +			printf("%s: Speed was bad\n", dev->dev.name);
> +			break;
> +		}
> +
> +		out_be32(regs + GFAR_ECNTRL_OFFSET, ecntrl);
> +		out_be32(regs + GFAR_MACCFG2_OFFSET, maccfg2);
> +
> +		printf("Speed: %d, %s duplex\n", priv->speed,
> +		       (priv->duplexity) ? "full" : "half");
> +
> +	} else {
> +		printf("%s: No link.\n", dev->dev.name);
> +	}
> +}
> +
> +/* Stop the interface */
> +static void gfar_halt(struct eth_device *dev)
> +{
> +	struct gfar_private *priv = (struct gfar_private *)dev->priv;
> +	void __iomem *regs = priv->regs;
> +	int value;
> +
> +	clrbits_be32(regs + GFAR_DMACTRL_OFFSET, GFAR_DMACTRL_GRS |
> +			GFAR_DMACTRL_GTS);
> +	setbits_be32(regs + GFAR_DMACTRL_OFFSET, GFAR_DMACTRL_GRS |
> +			GFAR_DMACTRL_GTS);
> +
> +	value = in_be32(regs + GFAR_IEVENT_OFFSET);
> +	value &= (GFAR_IEVENT_GRSC | GFAR_IEVENT_GTSC);
> +
> +	while (value != (GFAR_IEVENT_GRSC | GFAR_IEVENT_GTSC)) {
> +		value = in_be32(regs + GFAR_IEVENT_OFFSET);
> +		value &= (GFAR_IEVENT_GRSC | GFAR_IEVENT_GTSC);
> +	}
> +
> +	clrbits_be32(regs + GFAR_MACCFG1_OFFSET,
> +			GFAR_MACCFG1_TX_EN | GFAR_MACCFG1_RX_EN);
> +}
> +
> +/* Initializes registers for the controller. */
> +static int gfar_init(struct eth_device *dev)
> +{
> +	struct gfar_private *priv = (struct gfar_private *)dev->priv;
> +	void __iomem *regs = priv->regs;
> +
> +	gfar_halt(dev);
> +
> +	/* Init MACCFG2. Default to GMII */
> +	out_be32(regs + GFAR_MACCFG2_OFFSET, MACCFG2_INIT_SETTINGS);
> +	out_be32(regs + GFAR_ECNTRL_OFFSET, ECNTRL_INIT_SETTINGS);
> +
> +	priv->rxIdx = 0;
> +	priv->txIdx = 0;

No camel case variable names please.

> +
> +	init_registers(regs);
> +
> +	miidev_restart_aneg(&priv->miidev);
> +
> +	return  0;
> +}
> +
> +static int gfar_open(struct eth_device *dev)
> +{
> +	int ix;
> +	struct gfar_private *priv = (struct gfar_private *)dev->priv;

unnecessary cast.

> +	void __iomem *regs = priv->regs;
> +
> +	/* Point to the buffer descriptors */
> +	out_be32(regs + GFAR_TBASE0_OFFSET, (unsigned int)priv->txbd);
> +	out_be32(regs + GFAR_RBASE0_OFFSET, (unsigned int)priv->rxbd);
> +
> +	/* Initialize the Rx Buffer descriptors */
> +	for (ix = 0; ix < RX_BUF_CNT; ix++) {
> +		priv->rxbd[ix].status = RXBD_EMPTY;
> +		priv->rxbd[ix].length = 0;
> +		priv->rxbd[ix].bufPtr = (uint) NetRxPackets[ix];
> +	}
> +	priv->rxbd[RX_BUF_CNT - 1].status |= RXBD_WRAP;
> +
> +	/* Initialize the TX Buffer Descriptors */
> +	for (ix = 0; ix < TX_BUF_CNT; ix++) {
> +		priv->txbd[ix].status = 0;
> +		priv->txbd[ix].length = 0;
> +		priv->txbd[ix].bufPtr = 0;
> +	}
> +	priv->txbd[TX_BUF_CNT - 1].status |= TXBD_WRAP;
> +
> +	miidev_wait_aneg(&priv->miidev);
> +	adjust_link(dev);
> +
> +	/* Enable Transmit and Receive */
> +	setbits_be32(regs + GFAR_MACCFG1_OFFSET, GFAR_MACCFG1_RX_EN |
> +			GFAR_MACCFG1_TX_EN);
> +
> +	/* Tell the DMA it is clear to go */
> +	setbits_be32(regs + GFAR_DMACTRL_OFFSET, DMACTRL_INIT_SETTINGS);
> +	out_be32(regs + GFAR_TSTAT_OFFSET, GFAR_TSTAT_CLEAR_THALT);
> +	out_be32(regs + GFAR_RSTAT_OFFSET, GFAR_RSTAT_CLEAR_RHALT);
> +	clrbits_be32(regs + GFAR_DMACTRL_OFFSET, GFAR_DMACTRL_GRS |
> +			GFAR_DMACTRL_GTS);
> +
> +	return 0;
> +}
> +
> +static int gfar_get_ethaddr(struct eth_device *dev, unsigned char *mac)
> +{
> +	struct device_d *edev = dev->parent;
> +	struct gfar_info_struct *gfar_info =
> +		(struct gfar_info_struct *)edev->platform_data;
> +	int (*get_mac)(struct gfar_info_struct *, unsigned char *) =
> +		gfar_info->get_mac;
> +
> +	if (get_mac)
> +		get_mac(gfar_info, mac);
> +	else
> +		return -ENODEV;
> +
> +	return 0;
> +}
> +
> +static int gfar_set_ethaddr(struct eth_device *dev, unsigned char *mac)
> +{
> +	struct gfar_private *priv = (struct gfar_private *)dev->priv;
> +	void __iomem *regs = priv->regs;
> +	char tmpbuf[MAC_ADDR_LEN];
> +	uint tempval;
> +	int ix;
> +
> +	for (ix = 0; ix < MAC_ADDR_LEN; ix++)
> +		tmpbuf[MAC_ADDR_LEN - 1 - ix] = mac[ix];
> +
> +	tempval = (tmpbuf[0] << 24) | (tmpbuf[1] << 16) | (tmpbuf[2] << 8) |
> +		  tmpbuf[3];
> +
> +	out_be32(regs + GFAR_MACSTRADDR1_OFFSET, tempval);
> +
> +	tempval = *((uint *)(tmpbuf + 4));
> +
> +	out_be32(regs + GFAR_MACSTRADDR2_OFFSET, tempval);
> +
> +	return 0;
> +}
> +
> +/* Writes the given phy's reg with value, using the specified MDIO regs */
> +static int gfar_local_mdio_write(void __iomem *phyregs, uint addr, uint reg,
> +				uint value)
> +{
> +	uint64_t start;
> +
> +	out_be32(phyregs + GFAR_MIIMADD_OFFSET, (addr << 8) | (reg & 0x1f));
> +	out_be32(phyregs + GFAR_MIIMCON_OFFSET, value);
> +
> +	start = get_time_ns();
> +
> +	while (!is_timeout(start, 10 * MSECOND)) {
> +		if (!(in_be32(phyregs + GFAR_MIIMMIND_OFFSET) &
> +					GFAR_MIIMIND_BUSY))
> +			return 0;
> +	}
> +
> +	return -EIO;
> +}
> +
> +/*
> + * Reads register regnum on the device's PHY through the
> + * specified registers. It lowers and raises the read
> + * command, and waits for the data to become valid (miimind
> + * notvalid bit cleared), and the bus to cease activity (miimind
> + * busy bit cleared), and then returns the value
> + */
> +static uint gfar_local_mdio_read(void __iomem *phyregs, uint phyid, uint regnum)
> +{
> +	uint64_t start;
> +
> +	/* Put the address of the phy, and the register number into MIIMADD */
> +	out_be32(phyregs + GFAR_MIIMADD_OFFSET, (phyid << 8) | (regnum & 0x1f));
> +
> +	/* Clear the command register, and wait */
> +	out_be32(phyregs + GFAR_MIIMCOM_OFFSET, 0);
> +
> +	/* Initiate a read command, and wait */
> +	out_be32(phyregs + GFAR_MIIMCOM_OFFSET, GFAR_MIIM_READ_COMMAND);
> +
> +	start = get_time_ns();
> +
> +	while (!is_timeout(start, 10 * MSECOND)) {
> +		if (!(in_be32(phyregs + GFAR_MIIMMIND_OFFSET) &
> +			(GFAR_MIIMIND_NOTVALID | GFAR_MIIMIND_BUSY)))
> +			return in_be32(phyregs + GFAR_MIIMSTAT_OFFSET);
> +	}
> +	return -EIO;
> +}
> +
> +static void gfar_configure_serdes(struct gfar_private *priv)
> +{
> +	gfar_local_mdio_write(priv->phyregs_sgmii,
> +			in_be32(priv->regs + GFAR_TBIPA_OFFSET), GFAR_TBI_ANA,
> +			priv->tbiana);
> +	gfar_local_mdio_write(priv->phyregs_sgmii,
> +			in_be32(priv->regs + GFAR_TBIPA_OFFSET),
> +			GFAR_TBI_TBICON, GFAR_TBICON_CLK_SELECT);
> +	gfar_local_mdio_write(priv->phyregs_sgmii,
> +			in_be32(priv->regs + GFAR_TBIPA_OFFSET), GFAR_TBI_CR,
> +			priv->tbicr);
> +}
> +
> +/* Reset the internal and external PHYs. */
> +static void init_phy(struct eth_device *dev)
> +{
> +	struct gfar_private *priv = (struct gfar_private *)dev->priv;
> +	void __iomem *regs = priv->regs;
> +	uint64_t start;
> +
> +	/* Assign a Physical address to the TBI */
> +	out_be32(regs + GFAR_TBIPA_OFFSET, GFAR_TBIPA_VALUE);
> +
> +	/* Reset MII (due to new addresses) */
> +	out_be32(priv->phyregs + GFAR_MIIMCFG_OFFSET, GFAR_MIIMCFG_RESET);
> +	out_be32(priv->phyregs + GFAR_MIIMCFG_OFFSET, GFAR_MIIMCFG_INIT_VALUE);
> +
> +	start = get_time_ns();
> +	while (!is_timeout(start, 10 * MSECOND)) {
> +		if (!(in_be32(priv->phyregs + GFAR_MIIMMIND_OFFSET) &
> +			GFAR_MIIMIND_BUSY))
> +			break;
> +	}
> +
> +	gfar_local_mdio_write(priv->phyregs, priv->phyaddr, GFAR_MIIM_CR,
> +			GFAR_MIIM_CR_RST);
> +
> +	start = get_time_ns();
> +	while (!is_timeout(start, 10 * MSECOND)) {
> +		if (!(gfar_local_mdio_read(priv->phyregs, priv->phyaddr,
> +					GFAR_MIIM_CR) & GFAR_MIIM_CR_RST))
> +			break;
> +	}
> +
> +	if (in_be32(regs + GFAR_ECNTRL_OFFSET) & GFAR_ECNTRL_SGMII_MODE)
> +		gfar_configure_serdes(priv);
> +}
> +
> +static int gfar_send(struct eth_device *dev, void *packet, int length)
> +{
> +	int ix;
> +	struct gfar_private *priv = (struct gfar_private *)dev->priv;
> +	void __iomem *regs = priv->regs;
> +
> +	/* Find an empty buffer descriptor */
> +	for (ix = 0; priv->txbd[priv->txIdx].status & TXBD_READY; ix++) {
> +		if (ix >= TOUT_LOOP) {
> +			debug("gfar: tx buffers full\n");
> +			return -EBUSY;
> +		}
> +	}

This seems unnecessary. After initialization the tx buffer is ready. The
second time you get here the tx buffer is also ready, because you waited
for it to become ready below.

> +
> +	priv->txbd[priv->txIdx].bufPtr = (uint) packet;
> +	priv->txbd[priv->txIdx].length = length;
> +	priv->txbd[priv->txIdx].status |= (TXBD_READY | TXBD_LAST | TXBD_CRC);
> +
> +	/* Tell the DMA to go */
> +	out_be32(regs + GFAR_TSTAT_OFFSET, GFAR_TSTAT_CLEAR_THALT);
> +
> +	/* Wait for buffer to be transmitted */
> +	for (ix = 0; priv->txbd[priv->txIdx].status & TXBD_READY; ix++) {
> +		if (ix >= TOUT_LOOP) {
> +			debug("gfar: tx error: 0x%x\n",
> +				priv->txbd[priv->txIdx].status);
> +			return -EBUSY;
> +		}

Add a proper timeout loop here.

> +	}
> +
> +	if (priv->txbd[priv->txIdx].status & TXBD_STATS) {
> +		printf("TX error: 0x%x\n", priv->txbd[priv->txIdx].status);
> +		return -EIO;
> +	}
> +
> +	priv->txIdx = (priv->txIdx + 1) % TX_BUF_CNT;

Remove this and use a single tx buffer only. The driver doesn't make use
of more buffers anyway, since it polls for a buffer to be ready before
queuing another one.

> +
> +	return 0;
> +}
> +
> +static int gfar_recv(struct eth_device *dev)
> +{
> +	int length;
> +	struct gfar_private *priv = (struct gfar_private *)dev->priv;
> +	void __iomem *regs = priv->regs;
> +
> +	while (!(priv->rxbd[priv->rxIdx].status & RXBD_EMPTY)) {
> +		length = priv->rxbd[priv->rxIdx].length;
> +
> +		/* Send the packet up if there were no errors */
> +		if (!(priv->rxbd[priv->rxIdx].status & RXBD_STATS)) {
> +			net_receive(NetRxPackets[priv->rxIdx], length - 4);
> +		} else {
> +			printf("Got error %x\n",
> +			       (priv->rxbd[priv->rxIdx].status & RXBD_STATS));

Please use dev_dbg/dev_info and friends inside drivers.

> +		}
> +
> +		priv->rxbd[priv->rxIdx].length = 0;
> +
> +		/* Set the wrap bit if this is the last element in the list */
> +		if ((priv->rxIdx + 1) == RX_BUF_CNT)
> +			priv->rxbd[priv->rxIdx].status = RXBD_WRAP;
> +		else
> +			priv->rxbd[priv->rxIdx].status = 0;
> +
> +		priv->rxbd[priv->rxIdx].status |= RXBD_EMPTY;
> +		priv->rxIdx = (priv->rxIdx + 1) % RX_BUF_CNT;
> +	}

Don't loop here until you receive packets. The caller will do this for
you (which also handles the ctrl-c case).

> +
> +	if (in_be32(regs + GFAR_IEVENT_OFFSET) & GFAR_IEVENT_BSY) {
> +		out_be32(regs + GFAR_IEVENT_OFFSET, GFAR_IEVENT_BSY);
> +		out_be32(regs + GFAR_RSTAT_OFFSET, GFAR_RSTAT_CLEAR_RHALT);
> +	}
> +
> +	return 0;
> +}
> +
> +/* Read a MII PHY register. */
> +static int gfar_miiphy_read(struct mii_device *mdev, int addr, int reg)
> +{
> +	unsigned short ret;
> +	struct eth_device *edev = mdev->edev;
> +	struct gfar_private *priv = (struct gfar_private *)edev->priv;
> +
> +	if (NULL == priv) {
> +		printf("Can't read PHY at address %d\n", addr);
> +		return -1;
> +	}

This should never happen. You can drop this test.

> +
> +	return gfar_local_mdio_read(priv->phyregs, addr, reg);
> +}
> +
> +/* Write a MII PHY register.  */
> +static int gfar_miiphy_write(struct mii_device *mdev, int addr,
> +			     int reg, int value)
> +{
> +	struct eth_device *edev = mdev->edev;
> +	struct gfar_private *priv = (struct gfar_private *)edev->priv;
> +	unsigned short val = value;
> +
> +	if (NULL == priv) {
> +		printf("Can't write PHY at address %d\n", addr);
> +		return -1;
> +	}
> +
> +	gfar_local_mdio_write(priv->phyregs, addr, reg, val);
> +
> +	return 0;
> +}
> +
> +/*
> + * Initialize device structure. Returns success if
> + * initialization succeeded.
> + */
> +static int gfar_probe(struct device_d *dev)
> +{
> +	struct gfar_info_struct *gfar_info =
> +		(struct gfar_info_struct *)dev->platform_data;
> +	struct eth_device *edev;
> +	struct gfar_private *priv;
> +	size_t size;
> +	char *p;
> +
> +	edev = (struct eth_device *)xzalloc(sizeof(struct eth_device) +
> +					    sizeof(struct gfar_private));
> +
> +	if (NULL == edev)
> +		return -ENODEV;
> +
> +	priv = (struct gfar_private *)(edev + 1);

You should embed a struct eth_device in struct gfar_private instead,
it's cleaner.

> +
> +	priv->regs = dev_request_mem_region(dev, 0);
> +	priv->phyregs = dev_request_mem_region(dev, 1);
> +	priv->phyregs_sgmii = dev_request_mem_region(dev, 2);
> +
> +	priv->phyaddr = gfar_info->phyaddr;
> +	priv->flags = gfar_info->flags;
> +	priv->tbicr = gfar_info->tbicr;
> +	priv->tbiana = gfar_info->tbiana;
> +
> +	/* Allocate descriptors. 64-byte aligned. */
> +	size = (TX_BUF_CNT * (sizeof(struct txbd8) +
> +		(RX_BUF_CNT * sizeof(struct rxbd8)))) + BUF_ALIGN;
> +	p = (char *)xzalloc(size);
> +	p += BUF_ALIGN;
> +	p = (char *)((ulong)p & (~(BUF_ALIGN - 1)));

Use memalign instead.

> +
> +	priv->txbd = (struct txbd8 *)p;
> +	priv->rxbd = (struct rxbd8 *)(p +
> +			(TX_BUF_CNT * sizeof(struct txbd8)));
> +
> +	edev->priv = priv;
> +	edev->init = gfar_init;
> +	edev->open = gfar_open;
> +	edev->halt = gfar_halt;
> +	edev->send = gfar_send;
> +	edev->recv = gfar_recv;
> +	edev->get_ethaddr = gfar_get_ethaddr;
> +	edev->set_ethaddr = gfar_set_ethaddr;
> +	edev->parent = dev;
> +
> +	setbits_be32(priv->regs + GFAR_MACCFG1_OFFSET, GFAR_MACCFG1_SOFT_RESET);
> +	udelay(2);
> +	clrbits_be32(priv->regs + GFAR_MACCFG1_OFFSET, GFAR_MACCFG1_SOFT_RESET);
> +
> +	priv->miidev.read = gfar_miiphy_read;
> +	priv->miidev.write = gfar_miiphy_write;
> +	priv->miidev.address = priv->phyaddr;
> +	priv->miidev.flags = 0;
> +	priv->miidev.edev = edev;
> +	priv->miidev.parent = dev;
> +
> +	init_phy(edev);
> +
> +	mii_register(&priv->miidev);
> +
> +	return eth_register(edev);
> +}
> +
> +static struct driver_d gfar_eth_driver = {
> +	.name  = "gfar",
> +	.probe = gfar_probe,
> +};
> +
> +static int gfar_eth_init(void)
> +{
> +	register_driver(&gfar_eth_driver);
> +	return 0;
> +}
> +
> +device_initcall(gfar_eth_init);
> diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h
> new file mode 100644
> index 0000000..9edbd12
> --- /dev/null
> +++ b/drivers/net/gianfar.h
> @@ -0,0 +1,288 @@
> +/*
> + *  gianfar.h
> + *
> + *  Driver for the Motorola Triple Speed Ethernet Controller
> + *
> + *  This software may be used and distributed according to the
> + *  terms of the GNU Public License, Version 2, incorporated
> + *  herein by reference.
> + *
> + * Copyright 2012 GE Intelligent Platforms, Inc.
> + * Copyright 2004, 2007, 2009  Freescale Semiconductor, Inc.
> + * (C) Copyright 2003, Motorola, Inc.
> + * based on tsec.h by Xianghua Xiao and Andy Fleming 2003-2009
> + */
> +
> +#ifndef __GIANFAR_H
> +#define __GIANFAR_H
> +
> +#include <net.h>
> +#include <config.h>
> +#include <mach/gianfar.h>
> +
> +#define MAC_ADDR_LEN 6
> +
> +#define TOUT_LOOP	1000000
> +
> +#define PHY_AUTONEGOTIATE_TIMEOUT	5000 /* in ms */

Unused define

Sascha

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 3/3] ppc: P2020RDB Ethernet configuration
  2012-07-25 16:01 ` [PATCH 3/3] ppc: P2020RDB Ethernet configuration Renaud Barbier
@ 2012-07-27  7:45   ` Sascha Hauer
  0 siblings, 0 replies; 12+ messages in thread
From: Sascha Hauer @ 2012-07-27  7:45 UTC (permalink / raw)
  To: Renaud Barbier; +Cc: barebox

On Wed, Jul 25, 2012 at 05:01:01PM +0100, Renaud Barbier wrote:
> Minimal support of the Ethernet interface on the P2020RDB board. Only
> the eTSEC3 interface is supported.
> 
> Signed-off-by: Renaud Barbier <renaud.barbier@ge.com>
> ---
>  arch/ppc/boards/freescale-p2020rdb/p2020rdb.c |   38 +++++++++++++++++++++++++
>  arch/ppc/configs/p2020rdb_defconfig           |    6 ++++
>  2 files changed, 44 insertions(+), 0 deletions(-)
> 
> diff --git a/arch/ppc/boards/freescale-p2020rdb/p2020rdb.c b/arch/ppc/boards/freescale-p2020rdb/p2020rdb.c
> index 20897cb..201220f 100644
> --- a/arch/ppc/boards/freescale-p2020rdb/p2020rdb.c
> +++ b/arch/ppc/boards/freescale-p2020rdb/p2020rdb.c
> @@ -35,6 +35,7 @@
>  #include <mach/mmu.h>
>  #include <mach/immap_85xx.h>
>  #include <mach/clocks.h>
> +#include <mach/gianfar.h>
>  #include <mach/early_udelay.h>
>  
>  #define VSC7385_RST_SET		0x00080000
> @@ -61,10 +62,47 @@
>  #define SYSCLK_50	50000000
>  #define SYSCLK_100	100000000
>  
> +/* Ethernet. Use eTSEC3 */
> +static struct gfar_info_struct gfar_info[] = {
> +	{
> +	.phyaddr = 1,
> +	.tbiana = 0,
> +	.tbicr = 0,
> +	.flags = 0,
> +	},

Please use tabs for indention.

> +};
> +
> +static int board_eth_init(int num, int idx)
> +{
> +	struct resource *res;
> +
> +	res = xzalloc(3 * sizeof(struct resource));
> +	/* TSEC interface registers */
> +	res[0].start = GFAR_BASE_ADDR + ((num - 1) * 0x1000);
> +	res[0].end = res[0].start + 0x1000;
> +	res[0].flags = IORESOURCE_MEM;
> +	/* External PHY access always through eTSEC1 */
> +	res[1].start = MDIO_BASE_ADDR;
> +	res[1].end = res[1].start + 0x1000;
> +	res[1].flags = IORESOURCE_MEM;
> +	/* Access to TBI/RTBI interface. */
> +	res[2].start = MDIO_BASE_ADDR + ((num - 1) * 0x1000);
> +	res[2].end = res[2].start + 0x1000;
> +	res[2].flags = IORESOURCE_MEM;
> +
> +	add_generic_device_res("gfar", DEVICE_ID_DYNAMIC, res, 3,
> +				&gfar_info[idx]);
> +
> +	return 0;
> +}

It's probably worth to make this a SoC specific function somewhere. It
could be used by other boards aswell, right?

Sascha

> +
>  static int devices_init(void)
>  {
>  	add_cfi_flash_device(-1, CFG_FLASH_BASE, 16 << 20, 0);
>  
> +	/* eTSEC3 */
> +	board_eth_init(3, 0);
> +
>  	devfs_add_partition("nor0", 0xf80000, 0x80000, DEVFS_PARTITION_FIXED,
>  			    "self0");
>  	return 0;
> diff --git a/arch/ppc/configs/p2020rdb_defconfig b/arch/ppc/configs/p2020rdb_defconfig
> index f8a0687..d025a40 100644
> --- a/arch/ppc/configs/p2020rdb_defconfig
> +++ b/arch/ppc/configs/p2020rdb_defconfig
> @@ -21,3 +21,9 @@ CONFIG_MALLOC_SIZE=0x200000
>  CONFIG_BAUDRATE=115200
>  CONFIG_DRIVER_SERIAL_NS16550=y
>  CONFIG_RELOCATABLE=y
> +CONFIG_DRIVER_NET_GIANFAR=y
> +CONFIG_NET=y
> +CONFIG_NET_PING=y
> +CONFIG_NET_TFTP=y
> +CONFIG_PING=y
> +CONFIG_TFTP=y
> -- 
> 1.7.1
> 
> 
> _______________________________________________
> barebox mailing list
> barebox@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/barebox
> 

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH V2 0/4] ppc: Freescale TSEC driver
  2012-07-25 16:00 [PATCH 0/3] ppc: Freescale TSEC driver Renaud Barbier
                   ` (2 preceding siblings ...)
  2012-07-25 16:01 ` [PATCH 3/3] ppc: P2020RDB Ethernet configuration Renaud Barbier
@ 2012-08-07 14:30 ` Renaud Barbier
  2012-08-10 19:16   ` Sascha Hauer
  2012-08-07 14:30 ` [PATCH 1/4] ppc: GIANFAR base address definition Renaud Barbier
                   ` (3 subsequent siblings)
  7 siblings, 1 reply; 12+ messages in thread
From: Renaud Barbier @ 2012-08-07 14:30 UTC (permalink / raw)
  To: barebox

The patchset v2 addresses the comments from version 1. 'printf' in the
Ethernet driver are replaced by dev_dbg, dev_err or dev_info and excessive
NULL checkings are removed. The platform Ethernet initialization is a
generic architecture function (moved to mach-mpc85xx).
Finally, the send function uses 'is_timeout' to wait for packet 
transmission but the send function still uses 2 descriptors as using only
one fails.

Renaud Barbier (4):
  ppc: GIANFAR base address definition
  net: GIANFAR driver
  fsl: Freescale TSEC specific initialization.
  ppc: P2020RDB Ethernet configuration

 arch/ppc/boards/freescale-p2020rdb/p2020rdb.c   |   14 +
 arch/ppc/configs/p2020rdb_defconfig             |    6 +
 arch/ppc/mach-mpc85xx/Makefile                  |    1 +
 arch/ppc/mach-mpc85xx/eth-devices.c             |   49 ++
 arch/ppc/mach-mpc85xx/include/mach/gianfar.h    |   31 ++
 arch/ppc/mach-mpc85xx/include/mach/immap_85xx.h |    7 +
 drivers/net/Kconfig                             |    5 +
 drivers/net/Makefile                            |    1 +
 drivers/net/gianfar.c                           |  548 +++++++++++++++++++++++
 drivers/net/gianfar.h                           |  284 ++++++++++++
 10 files changed, 946 insertions(+), 0 deletions(-)
 create mode 100644 arch/ppc/mach-mpc85xx/eth-devices.c
 create mode 100644 arch/ppc/mach-mpc85xx/include/mach/gianfar.h
 create mode 100644 drivers/net/gianfar.c
 create mode 100644 drivers/net/gianfar.h


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH 1/4] ppc: GIANFAR base address definition
  2012-07-25 16:00 [PATCH 0/3] ppc: Freescale TSEC driver Renaud Barbier
                   ` (3 preceding siblings ...)
  2012-08-07 14:30 ` [PATCH V2 0/4] ppc: Freescale TSEC driver Renaud Barbier
@ 2012-08-07 14:30 ` Renaud Barbier
  2012-08-07 14:30 ` [PATCH 2/4] net: GIANFAR driver Renaud Barbier
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 12+ messages in thread
From: Renaud Barbier @ 2012-08-07 14:30 UTC (permalink / raw)
  To: barebox

In view of the introduction of the GIANFAR Ethernet driver,
the mdio and gianfar base address are defined.

Signed-off-by: Renaud Barbier <renaud.barbier@ge.com>
---
 arch/ppc/mach-mpc85xx/include/mach/immap_85xx.h |    7 +++++++
 1 files changed, 7 insertions(+), 0 deletions(-)

diff --git a/arch/ppc/mach-mpc85xx/include/mach/immap_85xx.h b/arch/ppc/mach-mpc85xx/include/mach/immap_85xx.h
index b802249..bf0f7f5 100644
--- a/arch/ppc/mach-mpc85xx/include/mach/immap_85xx.h
+++ b/arch/ppc/mach-mpc85xx/include/mach/immap_85xx.h
@@ -39,6 +39,11 @@
 
 #define MPC85xx_GPIO_OFFSET	0xf000
 #define MPC85xx_L2_OFFSET	0x20000
+#ifdef CONFIG_TSECV2
+#define TSEC1_OFFSET		0xB0000
+#else
+#define TSEC1_OFFSET		0x24000
+#endif
 
 #define MPC85xx_PIC_OFFSET	0x40000
 #define MPC85xx_GUTS_OFFSET	0xe0000
@@ -129,4 +134,6 @@
 #define		MPC85xx_DEVDISR_TB1	0x00001000
 #define MPC85xx_GUTS_RSTCR_OFFSET	0xb0
 
+#define GFAR_BASE_ADDR		(CFG_IMMR + TSEC1_OFFSET)
+#define MDIO_BASE_ADDR		(CFG_IMMR + 0x24000)
 #endif /*__IMMAP_85xx__*/
-- 
1.7.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH 2/4] net: GIANFAR driver
  2012-07-25 16:00 [PATCH 0/3] ppc: Freescale TSEC driver Renaud Barbier
                   ` (4 preceding siblings ...)
  2012-08-07 14:30 ` [PATCH 1/4] ppc: GIANFAR base address definition Renaud Barbier
@ 2012-08-07 14:30 ` Renaud Barbier
  2012-08-07 14:30 ` [PATCH 3/4] fsl: Freescale TSEC specific initialization Renaud Barbier
  2012-08-07 14:30 ` [PATCH 4/4] ppc: P2020RDB Ethernet configuration Renaud Barbier
  7 siblings, 0 replies; 12+ messages in thread
From: Renaud Barbier @ 2012-08-07 14:30 UTC (permalink / raw)
  To: barebox

This update adds the GIANFAR driver along with the configuration
and build files.

Signed-off-by: Renaud Barbier <renaud.barbier@ge.com>
---
 arch/ppc/mach-mpc85xx/include/mach/gianfar.h |   31 ++
 drivers/net/Kconfig                          |    5 +
 drivers/net/Makefile                         |    1 +
 drivers/net/gianfar.c                        |  548 ++++++++++++++++++++++++++
 drivers/net/gianfar.h                        |  284 +++++++++++++
 5 files changed, 869 insertions(+), 0 deletions(-)
 create mode 100644 arch/ppc/mach-mpc85xx/include/mach/gianfar.h
 create mode 100644 drivers/net/gianfar.c
 create mode 100644 drivers/net/gianfar.h

diff --git a/arch/ppc/mach-mpc85xx/include/mach/gianfar.h b/arch/ppc/mach-mpc85xx/include/mach/gianfar.h
new file mode 100644
index 0000000..ae31638
--- /dev/null
+++ b/arch/ppc/mach-mpc85xx/include/mach/gianfar.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2012 GE Intelligent Platforms, Inc.
+ * Copyright 2004, 2007, 2009  Freescale Semiconductor, Inc.
+ * (C) Copyright 2003, Motorola, Inc.
+ * based on tsec.h by Xianghua Xiao and Andy Fleming 2003-2009
+ *
+ * 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
+ *
+ * Platform data for the Motorola Triple Speed Ethernet Controller
+ */
+
+struct gfar_info_struct {
+	unsigned int phyaddr;
+	unsigned int tbiana;
+	unsigned int tbicr;
+};
+
+int fsl_eth_init(int num, struct gfar_info_struct *gf);
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 749ea6a..7d21ed8 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -124,6 +124,11 @@ config DRIVER_NET_DESIGNWARE_ALTDESCRIPTOR
 	depends on DRIVER_NET_DESIGNWARE
 	default n
 
+config DRIVER_NET_GIANFAR
+	bool "Gianfar Ethernet"
+	depends on ARCH_MPC85XX
+	select MIIDEV
+
 source "drivers/net/usb/Kconfig"
 
 endmenu
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 29727b7..4d960e8 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -14,3 +14,4 @@ obj-$(CONFIG_NET_USB)			+= usb/
 obj-$(CONFIG_DRIVER_NET_TSE)		+= altera_tse.o
 obj-$(CONFIG_DRIVER_NET_KS8851_MLL)	+= ks8851_mll.o
 obj-$(CONFIG_DRIVER_NET_DESIGNWARE)	+= designware.o
+obj-$(CONFIG_DRIVER_NET_GIANFAR)	+= gianfar.o
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
new file mode 100644
index 0000000..6572400
--- /dev/null
+++ b/drivers/net/gianfar.c
@@ -0,0 +1,548 @@
+/*
+ * Freescale Three Speed Ethernet Controller driver
+ *
+ * This software may be used and distributed according to the
+ * terms of the GNU Public License, Version 2, incorporated
+ * herein by reference.
+ *
+ * Copyright 2012 GE Intelligent Platforms, Inc.
+ * Copyright 2004-2010 Freescale Semiconductor, Inc.
+ * (C) Copyright 2003, Motorola, Inc.
+ * based on work by Andy Fleming
+ */
+
+#include <config.h>
+#include <common.h>
+#include <malloc.h>
+#include <net.h>
+#include <init.h>
+#include <driver.h>
+#include <miidev.h>
+#include <command.h>
+#include <errno.h>
+#include <asm/io.h>
+#include "gianfar.h"
+
+/* 2 seems to be the minimum number of TX descriptors to make it work. */
+#define TX_BUF_CNT 	2
+#define RX_BUF_CNT 	PKTBUFSRX
+#define BUF_ALIGN	8
+
+/*
+ * Initialize required registers to appropriate values, zeroing
+ * those we don't care about (unless zero is bad, in which case,
+ * choose a more appropriate value)
+ */
+static void gfar_init_registers(void __iomem *regs)
+{
+	out_be32(regs + GFAR_IEVENT_OFFSET, GFAR_IEVENT_INIT_CLEAR);
+
+	out_be32(regs + GFAR_IMASK_OFFSET, GFAR_IMASK_INIT_CLEAR);
+
+	out_be32(regs + GFAR_IADDR(0), 0);
+	out_be32(regs + GFAR_IADDR(1), 0);
+	out_be32(regs + GFAR_IADDR(2), 0);
+	out_be32(regs + GFAR_IADDR(3), 0);
+	out_be32(regs + GFAR_IADDR(4), 0);
+	out_be32(regs + GFAR_IADDR(5), 0);
+	out_be32(regs + GFAR_IADDR(6), 0);
+	out_be32(regs + GFAR_IADDR(7), 0);
+
+	out_be32(regs + GFAR_GADDR(0), 0);
+	out_be32(regs + GFAR_GADDR(1), 0);
+	out_be32(regs + GFAR_GADDR(2), 0);
+	out_be32(regs + GFAR_GADDR(3), 0);
+	out_be32(regs + GFAR_GADDR(4), 0);
+	out_be32(regs + GFAR_GADDR(5), 0);
+	out_be32(regs + GFAR_GADDR(6), 0);
+	out_be32(regs + GFAR_GADDR(7), 0);
+
+	out_be32(regs + GFAR_RCTRL_OFFSET, 0x00000000);
+
+	memset((void *)(regs + GFAR_TR64_OFFSET), 0,
+			GFAR_CAM2_OFFSET - GFAR_TR64_OFFSET);
+
+	out_be32(regs + GFAR_CAM1_OFFSET, 0xffffffff);
+	out_be32(regs + GFAR_CAM2_OFFSET, 0xffffffff);
+
+	out_be32(regs + GFAR_MRBLR_OFFSET, MRBLR_INIT_SETTINGS);
+
+	out_be32(regs + GFAR_MINFLR_OFFSET, MINFLR_INIT_SETTINGS);
+
+	out_be32(regs + GFAR_ATTR_OFFSET, ATTR_INIT_SETTINGS);
+	out_be32(regs + GFAR_ATTRELI_OFFSET, ATTRELI_INIT_SETTINGS);
+}
+
+/*
+ * Configure maccfg2 based on negotiated speed and duplex
+ * reported by PHY handling code
+ */
+static void gfar_adjust_link(struct eth_device *edev)
+{
+	struct gfar_private *priv = edev->priv;
+	struct device_d *mdev = priv->miidev.parent;
+	void __iomem *regs = priv->regs;
+	u32 ecntrl, maccfg2;
+	uint32_t status;
+
+	status = miidev_get_status(&priv->miidev);
+
+	priv->link = status & MIIDEV_STATUS_IS_UP;
+	if (status & MIIDEV_STATUS_IS_FULL_DUPLEX)
+		priv->duplexity = 1;
+	else
+		priv->duplexity = 0;
+
+	if (status & MIIDEV_STATUS_IS_1000MBIT)
+		priv->speed = 1000;
+	else if (status & MIIDEV_STATUS_IS_100MBIT)
+		priv->speed = 100;
+	else
+		priv->speed = 10;
+
+	if (priv->link) {
+		/* clear all bits relative with interface mode */
+		ecntrl = in_be32(regs + GFAR_ECNTRL_OFFSET);
+		ecntrl &= ~GFAR_ECNTRL_R100;
+
+		maccfg2 = in_be32(regs + GFAR_MACCFG2_OFFSET);
+		maccfg2 &= ~(GFAR_MACCFG2_IF | GFAR_MACCFG2_FULL_DUPLEX);
+
+		if (priv->duplexity != 0)
+			maccfg2 |= GFAR_MACCFG2_FULL_DUPLEX;
+		else
+			maccfg2 &= ~(GFAR_MACCFG2_FULL_DUPLEX);
+
+		switch (priv->speed) {
+		case 1000:
+			maccfg2 |= GFAR_MACCFG2_GMII;
+			break;
+		case 100:
+		case 10:
+			maccfg2 |= GFAR_MACCFG2_MII;
+			/*
+			 * Set R100 bit in all modes although
+			 * it is only used in RGMII mode
+			 */
+			if (priv->speed == 100)
+				ecntrl |= GFAR_ECNTRL_R100;
+			break;
+		default:
+			dev_info(mdev, "Speed is unknown\n");
+			break;
+		}
+
+		out_be32(regs + GFAR_ECNTRL_OFFSET, ecntrl);
+		out_be32(regs + GFAR_MACCFG2_OFFSET, maccfg2);
+
+		dev_info(mdev, "Speed: %d, %s duplex\n", priv->speed,
+		       (priv->duplexity) ? "full" : "half");
+
+	} else {
+		dev_info(mdev, "No link.\n");
+	}
+}
+
+/* Stop the interface */
+static void gfar_halt(struct eth_device *edev)
+{
+	struct gfar_private *priv = edev->priv;
+	void __iomem *regs = priv->regs;
+	int value;
+
+	clrbits_be32(regs + GFAR_DMACTRL_OFFSET, GFAR_DMACTRL_GRS |
+			GFAR_DMACTRL_GTS);
+	setbits_be32(regs + GFAR_DMACTRL_OFFSET, GFAR_DMACTRL_GRS |
+			GFAR_DMACTRL_GTS);
+
+	value = in_be32(regs + GFAR_IEVENT_OFFSET);
+	value &= (GFAR_IEVENT_GRSC | GFAR_IEVENT_GTSC);
+
+	while (value != (GFAR_IEVENT_GRSC | GFAR_IEVENT_GTSC)) {
+		value = in_be32(regs + GFAR_IEVENT_OFFSET);
+		value &= (GFAR_IEVENT_GRSC | GFAR_IEVENT_GTSC);
+	}
+
+	clrbits_be32(regs + GFAR_MACCFG1_OFFSET,
+			GFAR_MACCFG1_TX_EN | GFAR_MACCFG1_RX_EN);
+}
+
+/* Initializes registers for the controller. */
+static int gfar_init(struct eth_device *edev)
+{
+	struct gfar_private *priv = edev->priv;
+	void __iomem *regs = priv->regs;
+
+	gfar_halt(edev);
+
+	/* Init MACCFG2. Default to GMII */
+	out_be32(regs + GFAR_MACCFG2_OFFSET, MACCFG2_INIT_SETTINGS);
+	out_be32(regs + GFAR_ECNTRL_OFFSET, ECNTRL_INIT_SETTINGS);
+
+	priv->rxidx = 0;
+	priv->txidx = 0;
+
+	gfar_init_registers(regs);
+
+	miidev_restart_aneg(&priv->miidev);
+
+	return  0;
+}
+
+static int gfar_open(struct eth_device *edev)
+{
+	int ix;
+	struct gfar_private *priv = edev->priv;
+	void __iomem *regs = priv->regs;
+
+	/* Point to the buffer descriptors */
+	out_be32(regs + GFAR_TBASE0_OFFSET, (unsigned int)priv->txbd);
+	out_be32(regs + GFAR_RBASE0_OFFSET, (unsigned int)priv->rxbd);
+
+	/* Initialize the Rx Buffer descriptors */
+	for (ix = 0; ix < RX_BUF_CNT; ix++) {
+		priv->rxbd[ix].status = RXBD_EMPTY;
+		priv->rxbd[ix].length = 0;
+		priv->rxbd[ix].bufPtr = (uint) NetRxPackets[ix];
+	}
+	priv->rxbd[RX_BUF_CNT - 1].status |= RXBD_WRAP;
+
+	/* Initialize the TX Buffer Descriptors */
+	for (ix = 0; ix < TX_BUF_CNT; ix++) {
+		priv->txbd[ix].status = 0;
+		priv->txbd[ix].length = 0;
+		priv->txbd[ix].bufPtr = 0;
+	}
+	priv->txbd[TX_BUF_CNT - 1].status |= TXBD_WRAP;
+
+	miidev_wait_aneg(&priv->miidev);
+	gfar_adjust_link(edev);
+
+	/* Enable Transmit and Receive */
+	setbits_be32(regs + GFAR_MACCFG1_OFFSET, GFAR_MACCFG1_RX_EN |
+			GFAR_MACCFG1_TX_EN);
+
+	/* Tell the DMA it is clear to go */
+	setbits_be32(regs + GFAR_DMACTRL_OFFSET, DMACTRL_INIT_SETTINGS);
+	out_be32(regs + GFAR_TSTAT_OFFSET, GFAR_TSTAT_CLEAR_THALT);
+	out_be32(regs + GFAR_RSTAT_OFFSET, GFAR_RSTAT_CLEAR_RHALT);
+	clrbits_be32(regs + GFAR_DMACTRL_OFFSET, GFAR_DMACTRL_GRS |
+			GFAR_DMACTRL_GTS);
+
+	return 0;
+}
+
+static int gfar_get_ethaddr(struct eth_device *edev, unsigned char *mac)
+{
+	return -ENODEV;
+}
+
+static int gfar_set_ethaddr(struct eth_device *edev, unsigned char *mac)
+{
+	struct gfar_private *priv = edev->priv;
+	void __iomem *regs = priv->regs;
+	char tmpbuf[MAC_ADDR_LEN];
+	uint tempval;
+	int ix;
+
+	for (ix = 0; ix < MAC_ADDR_LEN; ix++)
+		tmpbuf[MAC_ADDR_LEN - 1 - ix] = mac[ix];
+
+	tempval = (tmpbuf[0] << 24) | (tmpbuf[1] << 16) | (tmpbuf[2] << 8) |
+		  tmpbuf[3];
+
+	out_be32(regs + GFAR_MACSTRADDR1_OFFSET, tempval);
+
+	tempval = *((uint *)(tmpbuf + 4));
+
+	out_be32(regs + GFAR_MACSTRADDR2_OFFSET, tempval);
+
+	return 0;
+}
+
+/* Writes the given phy's reg with value, using the specified MDIO regs */
+static int gfar_local_mdio_write(void __iomem *phyregs, uint addr, uint reg,
+				uint value)
+{
+	uint64_t start;
+
+	out_be32(phyregs + GFAR_MIIMADD_OFFSET, (addr << 8) | (reg & 0x1f));
+	out_be32(phyregs + GFAR_MIIMCON_OFFSET, value);
+
+	start = get_time_ns();
+	while (!is_timeout(start, 10 * MSECOND)) {
+		if (!(in_be32(phyregs + GFAR_MIIMMIND_OFFSET) &
+					GFAR_MIIMIND_BUSY))
+			return 0;
+	}
+
+	return -EIO;
+}
+
+/*
+ * Reads register regnum on the device's PHY through the
+ * specified registers. It lowers and raises the read
+ * command, and waits for the data to become valid (miimind
+ * notvalid bit cleared), and the bus to cease activity (miimind
+ * busy bit cleared), and then returns the value
+ */
+static uint gfar_local_mdio_read(void __iomem *phyregs, uint phyid, uint regnum)
+{
+	uint64_t start;
+
+	/* Put the address of the phy, and the register number into MIIMADD */
+	out_be32(phyregs + GFAR_MIIMADD_OFFSET, (phyid << 8) | (regnum & 0x1f));
+
+	/* Clear the command register, and wait */
+	out_be32(phyregs + GFAR_MIIMCOM_OFFSET, 0);
+
+	/* Initiate a read command, and wait */
+	out_be32(phyregs + GFAR_MIIMCOM_OFFSET, GFAR_MIIM_READ_COMMAND);
+
+	start = get_time_ns();
+	while (!is_timeout(start, 10 * MSECOND)) {
+		if (!(in_be32(phyregs + GFAR_MIIMMIND_OFFSET) &
+			(GFAR_MIIMIND_NOTVALID | GFAR_MIIMIND_BUSY)))
+			return in_be32(phyregs + GFAR_MIIMSTAT_OFFSET);
+	}
+
+	return -EIO;
+}
+
+static void gfar_configure_serdes(struct gfar_private *priv)
+{
+	gfar_local_mdio_write(priv->phyregs_sgmii,
+			in_be32(priv->regs + GFAR_TBIPA_OFFSET), GFAR_TBI_ANA,
+			priv->tbiana);
+	gfar_local_mdio_write(priv->phyregs_sgmii,
+			in_be32(priv->regs + GFAR_TBIPA_OFFSET),
+			GFAR_TBI_TBICON, GFAR_TBICON_CLK_SELECT);
+	gfar_local_mdio_write(priv->phyregs_sgmii,
+			in_be32(priv->regs + GFAR_TBIPA_OFFSET), GFAR_TBI_CR,
+			priv->tbicr);
+}
+
+/* Reset the internal and external PHYs. */
+static void gfar_init_phy(struct eth_device *dev)
+{
+	struct gfar_private *priv = dev->priv;
+	void __iomem *regs = priv->regs;
+	uint64_t start;
+
+	/* Assign a Physical address to the TBI */
+	out_be32(regs + GFAR_TBIPA_OFFSET, GFAR_TBIPA_VALUE);
+
+	/* Reset MII (due to new addresses) */
+	out_be32(priv->phyregs + GFAR_MIIMCFG_OFFSET, GFAR_MIIMCFG_RESET);
+	out_be32(priv->phyregs + GFAR_MIIMCFG_OFFSET, GFAR_MIIMCFG_INIT_VALUE);
+
+	start = get_time_ns();
+	while (!is_timeout(start, 10 * MSECOND)) {
+		if (!(in_be32(priv->phyregs + GFAR_MIIMMIND_OFFSET) &
+			GFAR_MIIMIND_BUSY))
+			break;
+	}
+
+	gfar_local_mdio_write(priv->phyregs, priv->phyaddr, GFAR_MIIM_CR,
+			GFAR_MIIM_CR_RST);
+
+	start = get_time_ns();
+	while (!is_timeout(start, 10 * MSECOND)) {
+		if (!(gfar_local_mdio_read(priv->phyregs, priv->phyaddr,
+					GFAR_MIIM_CR) & GFAR_MIIM_CR_RST))
+			break;
+	}
+
+	if (in_be32(regs + GFAR_ECNTRL_OFFSET) & GFAR_ECNTRL_SGMII_MODE)
+		gfar_configure_serdes(priv);
+}
+
+static int gfar_send(struct eth_device *edev, void *packet, int length)
+{
+	struct gfar_private *priv = edev->priv;
+	void __iomem *regs = priv->regs;
+	struct device_d *dev = edev->parent;
+	uint64_t start;
+	uint tidx;
+
+	tidx = priv->txidx;
+	priv->txbd[tidx].bufPtr = (uint) packet;
+	priv->txbd[tidx].length = length;
+	priv->txbd[tidx].status |= (TXBD_READY | TXBD_LAST |
+				TXBD_CRC | TXBD_INTERRUPT);
+
+	/* Tell the DMA to go */
+	out_be32(regs + GFAR_TSTAT_OFFSET, GFAR_TSTAT_CLEAR_THALT);
+
+	/* Wait for buffer to be transmitted */
+	start = get_time_ns();
+	while (priv->txbd[tidx].status & TXBD_READY) {
+		if (is_timeout(start, 5 * MSECOND)) {
+			break;
+		}
+	}
+
+	if (priv->txbd[tidx].status & TXBD_READY) {
+		dev_err(dev, "tx timeout: 0x%x\n", priv->txbd[tidx].status);
+		return -EBUSY;
+	}
+	else if (priv->txbd[tidx].status & TXBD_STATS) {
+		dev_err(dev, "TX error: 0x%x\n", priv->txbd[tidx].status);
+		return -EIO;
+	}
+
+	priv->txidx = (priv->txidx + 1) % TX_BUF_CNT;
+
+	return 0;
+}
+
+static int gfar_recv(struct eth_device *edev)
+{
+	struct gfar_private *priv = edev->priv;
+	struct device_d *dev = edev->parent;
+	void __iomem *regs = priv->regs;
+	int length;
+
+	if (priv->rxbd[priv->rxidx].status & RXBD_EMPTY) {
+		return 0; /* no data */
+	}
+
+	length = priv->rxbd[priv->rxidx].length;
+
+	/* Send the packet up if there were no errors */
+	if (!(priv->rxbd[priv->rxidx].status & RXBD_STATS)) {
+		net_receive(NetRxPackets[priv->rxidx], length - 4);
+	} else {
+		dev_err(dev, "Got error %x\n",
+		       (priv->rxbd[priv->rxidx].status & RXBD_STATS));
+	}
+
+	priv->rxbd[priv->rxidx].length = 0;
+
+	/* Set the wrap bit if this is the last element in the list */
+	if ((priv->rxidx + 1) == RX_BUF_CNT)
+		priv->rxbd[priv->rxidx].status = RXBD_WRAP;
+	else
+		priv->rxbd[priv->rxidx].status = 0;
+
+	priv->rxbd[priv->rxidx].status |= RXBD_EMPTY;
+	priv->rxidx = (priv->rxidx + 1) % RX_BUF_CNT;
+
+	if (in_be32(regs + GFAR_IEVENT_OFFSET) & GFAR_IEVENT_BSY) {
+		out_be32(regs + GFAR_IEVENT_OFFSET, GFAR_IEVENT_BSY);
+		out_be32(regs + GFAR_RSTAT_OFFSET, GFAR_RSTAT_CLEAR_RHALT);
+	}
+
+	return 0;
+}
+
+/* Read a MII PHY register. */
+static int gfar_miiphy_read(struct mii_device *mdev, int addr, int reg)
+{
+	struct eth_device *edev = mdev->edev;
+	struct device_d *dev = edev->parent;
+	struct gfar_private *priv = edev->priv;
+	int ret;
+
+	ret = gfar_local_mdio_read(priv->phyregs, addr, reg);
+	if (ret == -EIO)
+		dev_err(dev, "Can't read PHY at address %d\n", addr);
+
+	return ret;
+}
+
+/* Write a MII PHY register.  */
+static int gfar_miiphy_write(struct mii_device *mdev, int addr, int reg,
+				int value)
+{
+	struct eth_device *edev = mdev->edev;
+	struct device_d *dev = edev->parent;
+	struct gfar_private *priv = edev->priv;
+	unsigned short val = value;
+	int ret;
+
+	ret = gfar_local_mdio_write(priv->phyregs, addr, reg, val);
+
+	if (ret)
+		dev_err(dev, "Can't write PHY at address %d\n", addr);
+
+	return 0;
+}
+
+/*
+ * Initialize device structure. Returns success if
+ * initialization succeeded.
+ */
+static int gfar_probe(struct device_d *dev)
+{
+	struct gfar_info_struct *gfar_info = dev->platform_data;
+	struct eth_device *edev;
+	struct gfar_private *priv;
+	size_t size;
+	char *p;
+
+	priv = xzalloc(sizeof(struct gfar_private));
+
+	if (NULL == priv)
+		return -ENODEV;
+
+	edev = &priv->edev;
+
+	priv->regs = dev_request_mem_region(dev, 0);
+	priv->phyregs = dev_request_mem_region(dev, 1);
+	priv->phyregs_sgmii = dev_request_mem_region(dev, 2);
+
+	priv->phyaddr = gfar_info->phyaddr;
+	priv->tbicr = gfar_info->tbicr;
+	priv->tbiana = gfar_info->tbiana;
+
+	/*
+	 * Allocate descriptors 64-bit aligned. Descriptors 
+	 * are 8 bytes in size.
+	 */
+	size = ((TX_BUF_CNT * sizeof(struct txbd8)) +
+		(RX_BUF_CNT * sizeof(struct rxbd8))) + BUF_ALIGN;
+	p = (char *)xmemalign(BUF_ALIGN, size);
+	priv->txbd = (struct txbd8 *)p;
+	priv->rxbd = (struct rxbd8 *)(p + (TX_BUF_CNT * sizeof(struct txbd8)));
+
+	edev->priv = priv;
+	edev->init = gfar_init;
+	edev->open = gfar_open;
+	edev->halt = gfar_halt;
+	edev->send = gfar_send;
+	edev->recv = gfar_recv;
+	edev->get_ethaddr = gfar_get_ethaddr;
+	edev->set_ethaddr = gfar_set_ethaddr;
+	edev->parent = dev;
+
+	setbits_be32(priv->regs + GFAR_MACCFG1_OFFSET, GFAR_MACCFG1_SOFT_RESET);
+	udelay(2);
+	clrbits_be32(priv->regs + GFAR_MACCFG1_OFFSET, GFAR_MACCFG1_SOFT_RESET);
+
+	priv->miidev.read = gfar_miiphy_read;
+	priv->miidev.write = gfar_miiphy_write;
+	priv->miidev.address = priv->phyaddr;
+	priv->miidev.flags = 0;
+	priv->miidev.edev = edev;
+	priv->miidev.parent = dev;
+
+	gfar_init_phy(edev);
+
+	mii_register(&priv->miidev);
+
+	return eth_register(edev);
+}
+
+static struct driver_d gfar_eth_driver = {
+	.name  = "gfar",
+	.probe = gfar_probe,
+};
+
+static int gfar_eth_init(void)
+{
+	register_driver(&gfar_eth_driver);
+	return 0;
+}
+
+device_initcall(gfar_eth_init);
diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h
new file mode 100644
index 0000000..a4ad99e
--- /dev/null
+++ b/drivers/net/gianfar.h
@@ -0,0 +1,284 @@
+/*
+ *  gianfar.h
+ *
+ *  Driver for the Motorola Triple Speed Ethernet Controller
+ *
+ *  This software may be used and distributed according to the
+ *  terms of the GNU Public License, Version 2, incorporated
+ *  herein by reference.
+ *
+ * Copyright 2012 GE Intelligent Platforms, Inc.
+ * Copyright 2004, 2007, 2009  Freescale Semiconductor, Inc.
+ * (C) Copyright 2003, Motorola, Inc.
+ * based on tsec.h by Xianghua Xiao and Andy Fleming 2003-2009
+ */
+
+#ifndef __GIANFAR_H
+#define __GIANFAR_H
+
+#include <net.h>
+#include <config.h>
+#include <mach/gianfar.h>
+
+#define MAC_ADDR_LEN 6
+
+/* TBI register addresses */
+#define GFAR_TBI_CR		0x00
+#define GFAR_TBI_SR		0x01
+#define GFAR_TBI_ANA		0x04
+#define GFAR_TBI_ANLPBPA	0x05
+#define GFAR_TBI_ANEX		0x06
+#define GFAR_TBI_TBICON		0x11
+
+/* TBI MDIO register bit fields*/
+#define GFAR_TBICON_CLK_SELECT		0x0020
+#define GFAR_TBIANA_ASYMMETRIC_PAUSE	0x0100
+#define GFAR_TBIANA_SYMMETRIC_PAUSE	0x0080
+#define GFAR_TBIANA_HALF_DUPLEX		0x0040
+#define GFAR_TBIANA_FULL_DUPLEX		0x0020
+/* The two reserved bits below are used in AN3869 to enable SGMII. */
+#define GFAR_TBIANA_RESERVED1		0x4000
+#define GFAR_TBIANA_RESERVED15		0x0001
+#define GFAR_TBICR_PHY_RESET		0x8000
+#define GFAR_TBICR_ANEG_ENABLE		0x1000
+#define GFAR_TBICR_RESTART_ANEG		0x0200
+#define GFAR_TBICR_FULL_DUPLEX		0x0100
+#define GFAR_TBICR_SPEED1_SET		0x0040
+
+/* MAC register bits */
+#define GFAR_MACCFG1_SOFT_RESET		0x80000000
+#define GFAR_MACCFG1_RESET_RX_MC	0x00080000
+#define GFAR_MACCFG1_RESET_TX_MC	0x00040000
+#define GFAR_MACCFG1_RESET_RX_FUN	0x00020000
+#define TESC_MACCFG1_RESET_TX_FUN	0x00010000
+#define GFAR_MACCFG1_LOOPBACK		0x00000100
+#define GFAR_MACCFG1_RX_FLOW		0x00000020
+#define GFAR_MACCFG1_TX_FLOW		0x00000010
+#define GFAR_MACCFG1_SYNCD_RX_EN	0x00000008
+#define GFAR_MACCFG1_RX_EN		0x00000004
+#define GFAR_MACCFG1_SYNCD_TX_EN	0x00000002
+#define GFAR_MACCFG1_TX_EN		0x00000001
+
+#define MACCFG2_INIT_SETTINGS		0x00007205
+#define GFAR_MACCFG2_FULL_DUPLEX	0x00000001
+#define GFAR_MACCFG2_IF			0x00000300
+#define GFAR_MACCFG2_GMII		0x00000200
+#define GFAR_MACCFG2_MII		0x00000100
+
+#define ECNTRL_INIT_SETTINGS		0x00001000
+#define GFAR_ECNTRL_TBI_MODE		0x00000020
+#define GFAR_ECNTRL_R100		0x00000008
+#define GFAR_ECNTRL_SGMII_MODE		0x00000002
+
+#ifndef GFAR_TBIPA_VALUE
+	#define GFAR_TBIPA_VALUE	0x1f
+#endif
+#define GFAR_MIIMCFG_INIT_VALUE		0x00000003
+#define GFAR_MIIMCFG_RESET		0x80000000
+
+#define GFAR_MIIMIND_BUSY		0x00000001
+#define GFAR_MIIMIND_NOTVALID		0x00000004
+
+#define GFAR_MIIM_CONTROL		0x00000000
+#define GFAR_MIIM_CONTROL_RESET		0x00009140
+#define GFAR_MIIM_CONTROL_INIT		0x00001140
+#define GFAR_MIIM_CONTROL_RESTART	0x00001340
+#define GFAR_MIIM_ANEN			0x00001000
+
+#define GFAR_MIIM_CR			0x00000000
+#define GFAR_MIIM_CR_RST		0x00008000
+#define GFAR_MIIM_CR_INIT		0x00001000
+
+#define GFAR_MIIM_STATUS		0x1
+#define GFAR_MIIM_STATUS_AN_DONE	0x00000020
+#define GFAR_MIIM_STATUS_LINK		0x0004
+
+#define GFAR_MIIM_PHYIR1		0x2
+#define GFAR_MIIM_PHYIR2		0x3
+
+#define GFAR_MIIM_ANAR			0x4
+#define GFAR_MIIM_ANAR_INIT		0x1e1
+
+#define GFAR_MIIM_TBI_ANLPBPA		0x5
+#define GFAR_MIIM_TBI_ANLPBPA_HALF	0x00000040
+#define GFAR_MIIM_TBI_ANLPBPA_FULL	0x00000020
+
+#define GFAR_MIIM_TBI_ANEX		0x6
+#define GFAR_MIIM_TBI_ANEX_NP		0x00000004
+#define GFAR_MIIM_TBI_ANEX_PRX		0x00000002
+
+#define GFAR_MIIM_GBIT_CONTROL		0x9
+#define GFAR_MIIM_GBIT_CONTROL_INIT	0xe00
+
+#define GFAR_MIIM_EXT_PAGE_ACCESS	0x1f
+
+#define GFAR_MIIM_GBIT_CON		0x09
+#define GFAR_MIIM_GBIT_CON_ADVERT	0x0e00
+
+#define GFAR_MIIM_READ_COMMAND		0x00000001
+
+#define MRBLR_INIT_SETTINGS	1536
+
+#define MINFLR_INIT_SETTINGS	0x00000040
+
+#define DMACTRL_INIT_SETTINGS	0x000000c3
+#define GFAR_DMACTRL_GRS	0x00000010
+#define GFAR_DMACTRL_GTS	0x00000008
+
+#define GFAR_TSTAT_CLEAR_THALT	0x80000000
+#define GFAR_RSTAT_CLEAR_RHALT	0x00800000
+
+#define GFAR_IEVENT_INIT_CLEAR	0xffffffff
+#define GFAR_IEVENT_BABR	0x80000000
+#define GFAR_IEVENT_RXC		0x40000000
+#define GFAR_IEVENT_BSY		0x20000000
+#define GFAR_IEVENT_EBERR	0x10000000
+#define GFAR_IEVENT_MSRO	0x04000000
+#define GFAR_IEVENT_GTSC	0x02000000
+#define GFAR_IEVENT_BABT	0x01000000
+#define GFAR_IEVENT_TXC		0x00800000
+#define GFAR_IEVENT_TXE		0x00400000
+#define GFAR_IEVENT_TXB		0x00200000
+#define GFAR_IEVENT_TXF		0x00100000
+#define GFAR_IEVENT_IE		0x00080000
+#define GFAR_IEVENT_LC		0x00040000
+#define GFAR_IEVENT_CRL		0x00020000
+#define GFAR_IEVENT_XFUN	0x00010000
+#define GFAR_IEVENT_RXB0	0x00008000
+#define GFAR_IEVENT_GRSC	0x00000100
+#define GFAR_IEVENT_RXF0	0x00000080
+
+#define GFAR_IMASK_INIT_CLEAR	0x00000000
+
+/* Default Attribute fields */
+#define ATTR_INIT_SETTINGS     0x000000c0
+#define ATTRELI_INIT_SETTINGS  0x00000000
+
+/* TxBD status field bits */
+#define TXBD_READY		0x8000
+#define TXBD_PADCRC		0x4000
+#define TXBD_WRAP		0x2000
+#define TXBD_INTERRUPT		0x1000
+#define TXBD_LAST		0x0800
+#define TXBD_CRC		0x0400
+#define TXBD_DEF		0x0200
+#define TXBD_HUGEFRAME		0x0080
+#define TXBD_LATECOLLISION	0x0080
+#define TXBD_RETRYLIMIT		0x0040
+#define	TXBD_RETRYCOUNTMASK	0x003c
+#define TXBD_UNDERRUN		0x0002
+#define TXBD_STATS		0x03ff
+
+/* RxBD status field bits */
+#define RXBD_EMPTY		0x8000
+#define RXBD_RO1		0x4000
+#define RXBD_WRAP		0x2000
+#define RXBD_INTERRUPT		0x1000
+#define RXBD_LAST		0x0800
+#define RXBD_FIRST		0x0400
+#define RXBD_MISS		0x0100
+#define RXBD_BROADCAST		0x0080
+#define RXBD_MULTICAST		0x0040
+#define RXBD_LARGE		0x0020
+#define RXBD_NONOCTET		0x0010
+#define RXBD_SHORT		0x0008
+#define RXBD_CRCERR		0x0004
+#define RXBD_OVERRUN		0x0002
+#define RXBD_TRUNCATED		0x0001
+#define RXBD_STATS		0x003f
+
+struct txbd8 {
+	ushort	     status;	     /* Status Fields */
+	ushort	     length;	     /* Buffer length */
+	uint	     bufPtr;	     /* Buffer Pointer */
+};
+
+struct rxbd8 {
+	ushort	     status;	     /* Status Fields */
+	ushort	     length;	     /* Buffer Length */
+	uint	     bufPtr;	     /* Buffer Pointer */
+};
+
+/* eTSEC general control and status registers */
+#define GFAR_IEVENT_OFFSET	0x010	/* Interrupt Event */
+#define GFAR_IMASK_OFFSET	0x014	/* Interrupt Mask */
+#define GFAR_ECNTRL_OFFSET	0x020	/* Ethernet Control */
+#define GFAR_MINFLR_OFFSET	0x024	/* Minimum Frame Length */
+#define GFAR_DMACTRL_OFFSET	0x02c	/* DMA Control */
+#define GFAR_TBIPA_OFFSET	0x030	/* TBI PHY address */
+
+/* eTSEC transmit control and status register */
+#define GFAR_TSTAT_OFFSET	0x104	/* transmit status register */
+#define GFAR_TBASE0_OFFSET	0x204	/* TxBD Base Address */
+
+/* eTSEC receive control and status register */
+#define GFAR_RCTRL_OFFSET	0x300	/* Receive Control */
+#define GFAR_RSTAT_OFFSET	0x304	/* transmit status register */
+#define GFAR_MRBLR_OFFSET	0x340	/* Maximum Receive Buffer Length */
+#define GFAR_RBASE0_OFFSET	0x404	/* RxBD Base Address */
+
+/* eTSEC MAC registers */
+#define GFAR_MACCFG1_OFFSET	0x500	/* MAC Configuration #1 */
+#define GFAR_MACCFG2_OFFSET	0x504	/* MAC Configuration #2 */
+#define GFAR_MIIMCFG_OFFSET	0x520	/* MII management configuration */
+#define GFAR_MIIMCOM_OFFSET	0x524	/* MII management command */
+#define GFAR_MIIMADD_OFFSET	0x528	/* MII management address */
+#define GFAR_MIIMCON_OFFSET	0x52c	/* MII management control */
+#define GFAR_MIIMSTAT_OFFSET	0x530	/* MII management status */
+#define GFAR_MIIMMIND_OFFSET	0x534	/* MII management indicator */
+#define GFAR_MACSTRADDR1_OFFSET 0x540	/* MAC station address #1 */
+#define GFAR_MACSTRADDR2_OFFSET 0x544	/* MAC station address #2 */
+
+/* eTSEC transmit and receive counters registers. */
+#define GFAR_TR64_OFFSET	0x680
+/* eTSEC counter control and TOE statistics registers */
+#define GFAR_CAM1_OFFSET	0x738
+#define GFAR_CAM2_OFFSET	0x73c
+
+/* Individual/group address registers */
+#define GFAR_IADDR0_OFFSET	0x800
+#define GFAR_IADDR1_OFFSET	0x804
+#define GFAR_IADDR2_OFFSET	0x808
+#define GFAR_IADDR3_OFFSET	0x80c
+#define GFAR_IADDR4_OFFSET	0x810
+#define GFAR_IADDR5_OFFSET	0x814
+#define GFAR_IADDR6_OFFSET	0x818
+#define GFAR_IADDR7_OFFSET	0x81c
+
+#define GFAR_IADDR(REGNUM) (GFAR_IADDR##REGNUM##_OFFSET)
+
+/* Group address registers */
+#define GFAR_GADDR0_OFFSET	0x880
+#define GFAR_GADDR1_OFFSET	0x884
+#define GFAR_GADDR2_OFFSET	0x888
+#define GFAR_GADDR3_OFFSET	0x88c
+#define GFAR_GADDR4_OFFSET	0x890
+#define GFAR_GADDR5_OFFSET	0x894
+#define GFAR_GADDR6_OFFSET	0x898
+#define GFAR_GADDR7_OFFSET	0x89c
+
+#define GFAR_GADDR(REGNUM) (GFAR_GADDR##REGNUM##_OFFSET)
+
+/* eTSEC DMA attributes registers */
+#define GFAR_ATTR_OFFSET	0xbf8	/* Default Attribute Register */
+#define GFAR_ATTRELI_OFFSET	0xbfc	/* Default Attribute Extract Len/Idx */
+
+struct gfar_private {
+	struct eth_device edev;
+	void __iomem *regs;
+	void __iomem *phyregs;
+	void __iomem *phyregs_sgmii;
+	struct phy_info *phyinfo;
+	struct mii_device miidev;
+	volatile struct txbd8 *txbd;
+	volatile struct rxbd8 *rxbd;
+	uint txidx;
+	uint rxidx;
+	uint phyaddr;
+	uint tbicr;
+	uint tbiana;
+	uint link;
+	uint duplexity;
+	uint speed;
+};
+#endif /* __GIANFAR_H */
-- 
1.7.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH 3/4] fsl: Freescale TSEC specific initialization.
  2012-07-25 16:00 [PATCH 0/3] ppc: Freescale TSEC driver Renaud Barbier
                   ` (5 preceding siblings ...)
  2012-08-07 14:30 ` [PATCH 2/4] net: GIANFAR driver Renaud Barbier
@ 2012-08-07 14:30 ` Renaud Barbier
  2012-08-07 14:30 ` [PATCH 4/4] ppc: P2020RDB Ethernet configuration Renaud Barbier
  7 siblings, 0 replies; 12+ messages in thread
From: Renaud Barbier @ 2012-08-07 14:30 UTC (permalink / raw)
  To: barebox

The fsl_eth_init function maps the TSEC registers (MAC, TBI and
external PHY access registers). It also passes the PHY address and
TBI registers initialization values.

Signed-off-by: Renaud Barbier <renaud.barbier@ge.com>
---
 arch/ppc/mach-mpc85xx/Makefile      |    1 +
 arch/ppc/mach-mpc85xx/eth-devices.c |   49 +++++++++++++++++++++++++++++++++++
 2 files changed, 50 insertions(+), 0 deletions(-)
 create mode 100644 arch/ppc/mach-mpc85xx/eth-devices.c

diff --git a/arch/ppc/mach-mpc85xx/Makefile b/arch/ppc/mach-mpc85xx/Makefile
index 03addaf..af9be29 100644
--- a/arch/ppc/mach-mpc85xx/Makefile
+++ b/arch/ppc/mach-mpc85xx/Makefile
@@ -6,3 +6,4 @@ obj-y			+= fsl_law.o
 obj-y			+= speed.o
 obj-y			+=time.o
 obj-$(CONFIG_MP)	+= mp.o
+obj-$(CONFIG_DRIVER_NET_GIANFAR) += eth-devices.o
diff --git a/arch/ppc/mach-mpc85xx/eth-devices.c b/arch/ppc/mach-mpc85xx/eth-devices.c
new file mode 100644
index 0000000..02a3722
--- /dev/null
+++ b/arch/ppc/mach-mpc85xx/eth-devices.c
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2012 GE Intelligent Platforms, Inc
+ *
+ * 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 <driver.h>
+#include <mach/immap_85xx.h>
+#include <mach/gianfar.h>
+
+int fsl_eth_init(int num, struct gfar_info_struct *gf)
+{
+	struct resource *res;
+
+	res = xzalloc(3 * sizeof(struct resource));
+	/* TSEC interface registers */
+	res[0].start = GFAR_BASE_ADDR + ((num - 1) * 0x1000);
+	res[0].end = res[0].start + 0x1000;
+	res[0].flags = IORESOURCE_MEM;
+	/* External PHY access always through eTSEC1 */
+	res[1].start = MDIO_BASE_ADDR;
+	res[1].end = res[1].start + 0x1000;
+	res[1].flags = IORESOURCE_MEM;
+	/* Access to TBI/RTBI interface. */
+	res[2].start = MDIO_BASE_ADDR + ((num - 1) * 0x1000);
+	res[2].end = res[2].start + 0x1000;
+	res[2].flags = IORESOURCE_MEM;
+
+	add_generic_device_res("gfar", DEVICE_ID_DYNAMIC, res, 3, gf);
+
+	return 0;
+}
-- 
1.7.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH 4/4] ppc: P2020RDB Ethernet configuration
  2012-07-25 16:00 [PATCH 0/3] ppc: Freescale TSEC driver Renaud Barbier
                   ` (6 preceding siblings ...)
  2012-08-07 14:30 ` [PATCH 3/4] fsl: Freescale TSEC specific initialization Renaud Barbier
@ 2012-08-07 14:30 ` Renaud Barbier
  7 siblings, 0 replies; 12+ messages in thread
From: Renaud Barbier @ 2012-08-07 14:30 UTC (permalink / raw)
  To: barebox

Minimal support of the Ethernet interface on the P2020RDB board. Only
the eTSEC3 interface is supported.

Signed-off-by: Renaud Barbier <renaud.barbier@ge.com>
---
 arch/ppc/boards/freescale-p2020rdb/p2020rdb.c |   14 ++++++++++++++
 arch/ppc/configs/p2020rdb_defconfig           |    6 ++++++
 2 files changed, 20 insertions(+), 0 deletions(-)

diff --git a/arch/ppc/boards/freescale-p2020rdb/p2020rdb.c b/arch/ppc/boards/freescale-p2020rdb/p2020rdb.c
index 20897cb..4cebf79 100644
--- a/arch/ppc/boards/freescale-p2020rdb/p2020rdb.c
+++ b/arch/ppc/boards/freescale-p2020rdb/p2020rdb.c
@@ -35,6 +35,7 @@
 #include <mach/mmu.h>
 #include <mach/immap_85xx.h>
 #include <mach/clocks.h>
+#include <mach/gianfar.h>
 #include <mach/early_udelay.h>
 
 #define VSC7385_RST_SET		0x00080000
@@ -61,10 +62,23 @@
 #define SYSCLK_50	50000000
 #define SYSCLK_100	100000000
 
+/* Ethernet. Use eTSEC3 */
+static struct gfar_info_struct gfar_info[] = {
+	{
+		.phyaddr = 1,
+		.tbiana = 0,
+		.tbicr = 0,
+	},
+};
+
+
 static int devices_init(void)
 {
 	add_cfi_flash_device(-1, CFG_FLASH_BASE, 16 << 20, 0);
 
+	/* eTSEC3 */
+	fsl_eth_init(3, &gfar_info[0]);
+
 	devfs_add_partition("nor0", 0xf80000, 0x80000, DEVFS_PARTITION_FIXED,
 			    "self0");
 	return 0;
diff --git a/arch/ppc/configs/p2020rdb_defconfig b/arch/ppc/configs/p2020rdb_defconfig
index f8a0687..d025a40 100644
--- a/arch/ppc/configs/p2020rdb_defconfig
+++ b/arch/ppc/configs/p2020rdb_defconfig
@@ -21,3 +21,9 @@ CONFIG_MALLOC_SIZE=0x200000
 CONFIG_BAUDRATE=115200
 CONFIG_DRIVER_SERIAL_NS16550=y
 CONFIG_RELOCATABLE=y
+CONFIG_DRIVER_NET_GIANFAR=y
+CONFIG_NET=y
+CONFIG_NET_PING=y
+CONFIG_NET_TFTP=y
+CONFIG_PING=y
+CONFIG_TFTP=y
-- 
1.7.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH V2 0/4] ppc: Freescale TSEC driver
  2012-08-07 14:30 ` [PATCH V2 0/4] ppc: Freescale TSEC driver Renaud Barbier
@ 2012-08-10 19:16   ` Sascha Hauer
  0 siblings, 0 replies; 12+ messages in thread
From: Sascha Hauer @ 2012-08-10 19:16 UTC (permalink / raw)
  To: Renaud Barbier; +Cc: barebox

On Tue, Aug 07, 2012 at 03:30:54PM +0100, Renaud Barbier wrote:
> The patchset v2 addresses the comments from version 1. 'printf' in the
> Ethernet driver are replaced by dev_dbg, dev_err or dev_info and excessive
> NULL checkings are removed. The platform Ethernet initialization is a
> generic architecture function (moved to mach-mpc85xx).
> Finally, the send function uses 'is_timeout' to wait for packet 
> transmission but the send function still uses 2 descriptors as using only
> one fails.
> 
> Renaud Barbier (4):
>   ppc: GIANFAR base address definition
>   net: GIANFAR driver
>   fsl: Freescale TSEC specific initialization.
>   ppc: P2020RDB Ethernet configuration

Applied, thanks

Sascha

> 
>  arch/ppc/boards/freescale-p2020rdb/p2020rdb.c   |   14 +
>  arch/ppc/configs/p2020rdb_defconfig             |    6 +
>  arch/ppc/mach-mpc85xx/Makefile                  |    1 +
>  arch/ppc/mach-mpc85xx/eth-devices.c             |   49 ++
>  arch/ppc/mach-mpc85xx/include/mach/gianfar.h    |   31 ++
>  arch/ppc/mach-mpc85xx/include/mach/immap_85xx.h |    7 +
>  drivers/net/Kconfig                             |    5 +
>  drivers/net/Makefile                            |    1 +
>  drivers/net/gianfar.c                           |  548 +++++++++++++++++++++++
>  drivers/net/gianfar.h                           |  284 ++++++++++++
>  10 files changed, 946 insertions(+), 0 deletions(-)
>  create mode 100644 arch/ppc/mach-mpc85xx/eth-devices.c
>  create mode 100644 arch/ppc/mach-mpc85xx/include/mach/gianfar.h
>  create mode 100644 drivers/net/gianfar.c
>  create mode 100644 drivers/net/gianfar.h
> 
> 
> _______________________________________________
> barebox mailing list
> barebox@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/barebox
> 

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2012-08-10 19:16 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-07-25 16:00 [PATCH 0/3] ppc: Freescale TSEC driver Renaud Barbier
2012-07-25 16:00 ` [PATCH 1/3] ppc: GIANFAR base address definition Renaud Barbier
2012-07-25 16:01 ` [PATCH 2/3] net: GIANFAR driver Renaud Barbier
2012-07-27  7:43   ` Sascha Hauer
2012-07-25 16:01 ` [PATCH 3/3] ppc: P2020RDB Ethernet configuration Renaud Barbier
2012-07-27  7:45   ` Sascha Hauer
2012-08-07 14:30 ` [PATCH V2 0/4] ppc: Freescale TSEC driver Renaud Barbier
2012-08-10 19:16   ` Sascha Hauer
2012-08-07 14:30 ` [PATCH 1/4] ppc: GIANFAR base address definition Renaud Barbier
2012-08-07 14:30 ` [PATCH 2/4] net: GIANFAR driver Renaud Barbier
2012-08-07 14:30 ` [PATCH 3/4] fsl: Freescale TSEC specific initialization Renaud Barbier
2012-08-07 14:30 ` [PATCH 4/4] ppc: P2020RDB Ethernet configuration Renaud Barbier

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox