* [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