[PATCH 2/3] net: GIANFAR driver

Renaud Barbier renaud.barbier at ge.com
Wed Jul 25 12:01:00 EDT 2012


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

Signed-off-by: Renaud Barbier <renaud.barbier at 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




More information about the barebox mailing list