From: Renaud Barbier <renaud.barbier@ge.com>
To: barebox@lists.infradead.org
Subject: [PATCH 2/3] net: GIANFAR driver
Date: Wed, 25 Jul 2012 17:01:00 +0100 [thread overview]
Message-ID: <1343232061-1789-3-git-send-email-renaud.barbier@ge.com> (raw)
In-Reply-To: <1343232061-1789-1-git-send-email-renaud.barbier@ge.com>
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
next prev parent reply other threads:[~2012-07-25 16:01 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
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 [this message]
2012-07-27 7:43 ` [PATCH 2/3] net: GIANFAR driver 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
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1343232061-1789-3-git-send-email-renaud.barbier@ge.com \
--to=renaud.barbier@ge.com \
--cc=barebox@lists.infradead.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox