9
0
Fork 0

Merge branch 'for-next/ppc'

Conflicts:
	arch/ppc/boards/freescale-p2020rdb/p2020rdb.c
	arch/ppc/configs/p2020rdb_defconfig
	arch/ppc/mach-mpc85xx/include/mach/immap_85xx.h
This commit is contained in:
Sascha Hauer 2012-09-05 12:59:54 +02:00
commit 6662e16dbb
10 changed files with 946 additions and 0 deletions

View File

@ -35,6 +35,7 @@
#include <mach/mpc85xx.h>
#include <mach/mmu.h>
#include <mach/immap_85xx.h>
#include <mach/gianfar.h>
#include <mach/clock.h>
#include <mach/early_udelay.h>
@ -62,6 +63,15 @@
#define SYSCLK_50 50000000
#define SYSCLK_100 100000000
/* Ethernet. Use eTSEC3 */
static struct gfar_info_struct gfar_info[] = {
{
.phyaddr = 1,
.tbiana = 0,
.tbicr = 0,
},
};
/* I2C busses. */
struct i2c_platform_data i2cplat = {
.bitrate = 400000,
@ -76,6 +86,9 @@ static int devices_init(void)
add_generic_device("i2c-fsl", 1, NULL, I2C2_BASE_ADDR,
0x100, IORESOURCE_MEM, &i2cplat);
/* eTSEC3 */
fsl_eth_init(3, &gfar_info[0]);
devfs_add_partition("nor0", 0xf80000, 0x80000, DEVFS_PARTITION_FIXED,
"self0");
return 0;

View File

@ -21,6 +21,12 @@ 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
CONFIG_I2C=y
CONFIG_I2C_IMX=y
CONFIG_CMD_I2C=y

View File

@ -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

View File

@ -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;
}

View File

@ -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);

View File

@ -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,6 +134,9 @@
#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)
#define I2C1_BASE_ADDR (CFG_IMMR + 0x3000)
#define I2C2_BASE_ADDR (CFG_IMMR + 0x3100)

View File

@ -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

View File

@ -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

548
drivers/net/gianfar.c Normal file
View File

@ -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);

284
drivers/net/gianfar.h Normal file
View File

@ -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 */