diff options
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/Makefile | 2 | ||||
| -rw-r--r-- | drivers/cfi_flash.c | 4 | ||||
| -rw-r--r-- | drivers/ct69000.c | 14 | ||||
| -rw-r--r-- | drivers/pci_indirect.c | 2 | ||||
| -rw-r--r-- | drivers/ti_pci1410a.c | 6 | ||||
| -rw-r--r-- | drivers/tsec.c | 1073 | ||||
| -rw-r--r-- | drivers/tsec.h | 505 | 
7 files changed, 1590 insertions, 16 deletions
| diff --git a/drivers/Makefile b/drivers/Makefile index 3461bb1c8..26a556e59 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -45,7 +45,7 @@ OBJS	= 3c589.o 5701rls.o ali512x.o \  	  serial_pl010.o serial_pl011.o serial_xuartlite.o \  	  sl811_usb.o sm501.o smc91111.o smiLynxEM.o \  	  status_led.o sym53c8xx.o \ -	  ti_pci1410a.o tigon3.o \ +	  ti_pci1410a.o tigon3.o tsec.o \  	  usbdcore.o usbdcore_ep0.o usbdcore_omap1510.o usbtty.o \  	  videomodes.o w83c553f.o \  	  ks8695eth.o diff --git a/drivers/cfi_flash.c b/drivers/cfi_flash.c index d8489d46c..3d0f20450 100644 --- a/drivers/cfi_flash.c +++ b/drivers/cfi_flash.c @@ -557,7 +557,7 @@ int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt)  		i = buffered_size > cnt ? cnt : buffered_size;  		if ((rc = flash_write_cfibuffer (info, wp, src, i)) != ERR_OK)  			return rc; -		i -= (i % info->portwidth); +		i -= i & (info->portwidth - 1);  		wp += i;  		src += i;  		cnt -= i; @@ -805,7 +805,7 @@ static void flash_make_cmd (flash_info_t * info, uchar cmd, void *cmdbuf)  	uchar *cp = (uchar *) cmdbuf;  	for (i = 0; i < info->portwidth; i++) -		*cp++ = ((i + 1) % info->chipwidth) ? '\0' : cmd; +		*cp++ = ((i + 1) & (info->chipwidth - 1)) ? '\0' : cmd;  #if defined(__LITTLE_ENDIAN)  	switch (info->portwidth) {  	case FLASH_CFI_8BIT: diff --git a/drivers/ct69000.c b/drivers/ct69000.c index f510f371d..7bcf19f5d 100644 --- a/drivers/ct69000.c +++ b/drivers/ct69000.c @@ -1,6 +1,8 @@ -/* - * (C) Copyright 2002 - * Denis Peter, MPL AG Switzerland +/* ported from ctfb.c (linux kernel): + * Created in Jan - July 2000 by Thomas Höhenleitner <th@visuelle-maschinen.de> + * + * Ported to U-Boot: + * (C) Copyright 2002 Denis Peter, MPL AG Switzerland   *   * See file CREDITS for list of people who contributed to this   * project. @@ -21,12 +23,6 @@   * MA 02111-1307 USA   */ -/* - * ported from ctfb.c (linux kernel) for the U-Boot - * - */ - -  #include <common.h>  #ifdef CONFIG_VIDEO diff --git a/drivers/pci_indirect.c b/drivers/pci_indirect.c index 584a4fc84..5987ac46a 100644 --- a/drivers/pci_indirect.c +++ b/drivers/pci_indirect.c @@ -52,7 +52,7 @@ indirect_##rw##_config_##size(struct pci_controller *hose,               \  	cfg_##rw(val, hose->cfg_data + (offset & mask), type, op);       \  	return 0;                                                        \  } -#elif defined(CONFIG_440_GX) +#elif defined(CONFIG_440GX) || defined(CONFIG_440EP) || defined(CONFIG_440GR)  #define INDIRECT_PCI_OP(rw, size, type, op, mask)			 \  static int								 \  indirect_##rw##_config_##size(struct pci_controller *hose, 		 \ diff --git a/drivers/ti_pci1410a.c b/drivers/ti_pci1410a.c index c67238275..d5297b572 100644 --- a/drivers/ti_pci1410a.c +++ b/drivers/ti_pci1410a.c @@ -88,8 +88,8 @@ const char *indent = "\t   ";  int do_pinit(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])  { -#ifndef CFG_FISRT_PCMCIA_BUS -# define CFG_FISRT_PCMCIA_BUS 0 +#ifndef CFG_FIRST_PCMCIA_BUS +# define CFG_FIRST_PCMCIA_BUS 0  #endif  	int rcode = 0; @@ -99,7 +99,7 @@ int do_pinit(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])  		return 1;  	}  	if (strcmp(argv[1],"on") == 0) { -		rcode = pcmcia_on(CFG_FISRT_PCMCIA_BUS); +		rcode = pcmcia_on(CFG_FIRST_PCMCIA_BUS);  	} else if (strcmp(argv[1],"off") == 0) {  		rcode = pcmcia_off();  	} else { diff --git a/drivers/tsec.c b/drivers/tsec.c new file mode 100644 index 000000000..0c8b0de58 --- /dev/null +++ b/drivers/tsec.c @@ -0,0 +1,1073 @@ +/* + * tsec.c + * 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 2004 Freescale Semiconductor. + * (C) Copyright 2003, Motorola, Inc. + * author Andy Fleming + * + */ + +#include <config.h> +#include <mpc85xx.h> +#include <common.h> +#include <malloc.h> +#include <net.h> +#include <command.h> + +#if defined(CONFIG_TSEC_ENET) +#include "tsec.h" + +#define TX_BUF_CNT 2 + +static uint rxIdx;	/* index of the current RX buffer */ +static uint txIdx;	/* index of the current TX buffer */ + +typedef volatile struct rtxbd { +	txbd8_t txbd[TX_BUF_CNT]; +	rxbd8_t rxbd[PKTBUFSRX]; +}  RTXBD; + +struct tsec_info_struct { +	unsigned int phyaddr; +	u32 flags; +	unsigned int phyregidx; +}; + + +/* The tsec_info structure contains 3 values which the + * driver uses to determine how to operate a given ethernet + * device.  For now, the structure is initialized with the + * knowledge that all current implementations have 2 TSEC + * devices, and one FEC.  The information needed is: + *  phyaddr - The address of the PHY which is attached to + *	the given device. + * + *  flags - This variable indicates whether the device + *	supports gigabit speed ethernet, and whether it should be + *	in reduced mode. + * + *  phyregidx - This variable specifies which ethernet device + *	controls the MII Management registers which are connected + *	to the PHY.  For 8540/8560, only TSEC1 (index 0) has + *	access to the PHYs, so all of the entries have "0". + * + * The values specified in the table are taken from the board's + * config file in include/configs/.  When implementing a new + * board with ethernet capability, it is necessary to define: + *   TSEC1_PHY_ADDR + *   TSEC1_PHYIDX + *   TSEC2_PHY_ADDR + *   TSEC2_PHYIDX + * + * and for 8560: + *   FEC_PHY_ADDR + *   FEC_PHYIDX + */ +static struct tsec_info_struct tsec_info[] = { +#if defined(CONFIG_MPC85XX_TSEC1) || defined(CONFIG_MPC83XX_TSEC1) +	{TSEC1_PHY_ADDR, TSEC_GIGABIT, TSEC1_PHYIDX}, +#else +	{ 0, 0, 0}, +#endif +#if defined(CONFIG_MPC85XX_TSEC2) || defined(CONFIG_MPC83XX_TSEC2) +	{TSEC2_PHY_ADDR, TSEC_GIGABIT, TSEC2_PHYIDX}, +#else +	{ 0, 0, 0}, +#endif +#ifdef CONFIG_MPC85XX_FEC +	{FEC_PHY_ADDR, 0, FEC_PHYIDX}, +#else +#    if defined(CONFIG_MPC85XX_TSEC3) || defined(CONFIG_MPC83XX_TSEC3) +	{TSEC3_PHY_ADDR, TSEC_GIGABIT | TSEC_REDUCED, TSEC3_PHYIDX}, +#    else +	{ 0, 0, 0}, +#    endif +#    if defined(CONFIG_MPC85XX_TSEC4) || defined(CONFIG_MPC83XX_TSEC4) +	{TSEC4_PHY_ADDR, TSEC_REDUCED, TSEC4_PHYIDX}, +#    else +	{ 0, 0, 0}, +#    endif +#endif +}; + +#define MAXCONTROLLERS	(4) + +static int relocated = 0; + +static struct tsec_private *privlist[MAXCONTROLLERS]; + +#ifdef __GNUC__ +static RTXBD rtx __attribute__ ((aligned(8))); +#else +#error "rtx must be 64-bit aligned" +#endif + +static int tsec_send(struct eth_device* dev, volatile void *packet, int length); +static int tsec_recv(struct eth_device* dev); +static int tsec_init(struct eth_device* dev, bd_t * bd); +static void tsec_halt(struct eth_device* dev); +static void init_registers(volatile tsec_t *regs); +static void startup_tsec(struct eth_device *dev); +static int init_phy(struct eth_device *dev); +void write_phy_reg(struct tsec_private *priv, uint regnum, uint value); +uint read_phy_reg(struct tsec_private *priv, uint regnum); +struct phy_info * get_phy_info(struct eth_device *dev); +void phy_run_commands(struct tsec_private *priv, struct phy_cmd *cmd); +static void adjust_link(struct eth_device *dev); +static void relocate_cmds(void); + +/* Initialize device structure. Returns success if PHY + * initialization succeeded (i.e. if it recognizes the PHY) + */ +int tsec_initialize(bd_t *bis, int index, char *devname) +{ +	struct eth_device* dev; +	int i; +	struct tsec_private *priv; + +	dev = (struct eth_device*) malloc(sizeof *dev); + +	if(NULL == dev) +		return 0; + +	memset(dev, 0, sizeof *dev); + +	priv = (struct tsec_private *) malloc(sizeof(*priv)); + +	if(NULL == priv) +		return 0; + +	privlist[index] = priv; +	priv->regs = (volatile tsec_t *)(TSEC_BASE_ADDR + index*TSEC_SIZE); +	priv->phyregs = (volatile tsec_t *)(TSEC_BASE_ADDR + +			tsec_info[index].phyregidx*TSEC_SIZE); + +	priv->phyaddr = tsec_info[index].phyaddr; +	priv->flags = tsec_info[index].flags; + +	sprintf(dev->name, devname); +	dev->iobase = 0; +	dev->priv   = priv; +	dev->init   = tsec_init; +	dev->halt   = tsec_halt; +	dev->send   = tsec_send; +	dev->recv   = tsec_recv; + +	/* Tell u-boot to get the addr from the env */ +	for(i=0;i<6;i++) +		dev->enetaddr[i] = 0; + +	eth_register(dev); + + +	/* Reset the MAC */ +	priv->regs->maccfg1 |= MACCFG1_SOFT_RESET; +	priv->regs->maccfg1 &= ~(MACCFG1_SOFT_RESET); + +	/* Try to initialize PHY here, and return */ +	return init_phy(dev); +} + + +/* Initializes data structures and registers for the controller, + * and brings the interface up.	 Returns the link status, meaning + * that it returns success if the link is up, failure otherwise. + * This allows u-boot to find the first active controller. */ +int tsec_init(struct eth_device* dev, bd_t * bd) +{ +	uint tempval; +	char tmpbuf[MAC_ADDR_LEN]; +	int i; +	struct tsec_private *priv = (struct tsec_private *)dev->priv; +	volatile tsec_t *regs = priv->regs; + +	/* Make sure the controller is stopped */ +	tsec_halt(dev); + +	/* Init MACCFG2.  Defaults to GMII */ +	regs->maccfg2 = MACCFG2_INIT_SETTINGS; + +	/* Init ECNTRL */ +	regs->ecntrl = ECNTRL_INIT_SETTINGS; + +	/* Copy the station address into the address registers. +	 * Backwards, because little endian MACS are dumb */ +	for(i=0;i<MAC_ADDR_LEN;i++) { +		tmpbuf[MAC_ADDR_LEN - 1 - i] = dev->enetaddr[i]; +	} +	(uint)(regs->macstnaddr1) = *((uint *)(tmpbuf)); + +	tempval = *((uint *)(tmpbuf +4)); + +	(uint)(regs->macstnaddr2) = tempval; + +	/* reset the indices to zero */ +	rxIdx = 0; +	txIdx = 0; + +	/* Clear out (for the most part) the other registers */ +	init_registers(regs); + +	/* Ready the device for tx/rx */ +	startup_tsec(dev); + +	/* If there's no link, fail */ +	return priv->link; + +} + + +/* Write value to the device's PHY through the registers + * specified in priv, modifying the register specified in regnum. + * It will wait for the write to be done (or for a timeout to + * expire) before exiting + */ +void write_phy_reg(struct tsec_private *priv, uint regnum, uint value) +{ +	volatile tsec_t *regbase = priv->phyregs; +	uint phyid = priv->phyaddr; +	int timeout=1000000; + +	regbase->miimadd = (phyid << 8) | regnum; +	regbase->miimcon = value; +	asm("sync"); + +	timeout=1000000; +	while((regbase->miimind & MIIMIND_BUSY) && timeout--); +} + + +/* Reads register regnum on the device's PHY through the + * registers specified in priv.	 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 + */ +uint read_phy_reg(struct tsec_private *priv, uint regnum) +{ +	uint value; +	volatile tsec_t *regbase = priv->phyregs; +	uint phyid = priv->phyaddr; + +	/* Put the address of the phy, and the register +	 * number into MIIMADD */ +	regbase->miimadd = (phyid << 8) | regnum; + +	/* Clear the command register, and wait */ +	regbase->miimcom = 0; +	asm("sync"); + +	/* Initiate a read command, and wait */ +	regbase->miimcom = MIIM_READ_COMMAND; +	asm("sync"); + +	/* Wait for the the indication that the read is done */ +	while((regbase->miimind & (MIIMIND_NOTVALID | MIIMIND_BUSY))); + +	/* Grab the value read from the PHY */ +	value = regbase->miimstat; + +	return value; +} + + +/* Discover which PHY is attached to the device, and configure it + * properly.  If the PHY is not recognized, then return 0 + * (failure).  Otherwise, return 1 + */ +static int init_phy(struct eth_device *dev) +{ +	struct tsec_private *priv = (struct tsec_private *)dev->priv; +	struct phy_info *curphy; + +	/* Assign a Physical address to the TBI */ + +	{ +		volatile tsec_t *regs = (volatile tsec_t *)(TSEC_BASE_ADDR); +		regs->tbipa = TBIPA_VALUE; +		regs = (volatile tsec_t *)(TSEC_BASE_ADDR + TSEC_SIZE); +		regs->tbipa = TBIPA_VALUE; +		asm("sync"); +	} + +	/* Reset MII (due to new addresses) */ +	priv->phyregs->miimcfg = MIIMCFG_RESET; +	asm("sync"); +	priv->phyregs->miimcfg = MIIMCFG_INIT_VALUE; +	asm("sync"); +	while(priv->phyregs->miimind & MIIMIND_BUSY); + +	if(0 == relocated) +		relocate_cmds(); + +	/* Get the cmd structure corresponding to the attached +	 * PHY */ +	curphy = get_phy_info(dev); + +	if(NULL == curphy) { +		printf("%s: No PHY found\n", dev->name); + +		return 0; +	} + +	priv->phyinfo = curphy; + +	phy_run_commands(priv, priv->phyinfo->config); + +	return 1; +} + + +/* Returns which value to write to the control register. */ +/* For 10/100, the value is slightly different */ +uint mii_cr_init(uint mii_reg, struct tsec_private *priv) +{ +	if(priv->flags & TSEC_GIGABIT) +		return MIIM_CONTROL_INIT; +	else +		return MIIM_CR_INIT; +} + + +/* Parse the status register for link, and then do + * auto-negotiation */ +uint mii_parse_sr(uint mii_reg, struct tsec_private *priv) +{ +	uint timeout = TSEC_TIMEOUT; + +	if(mii_reg & MIIM_STATUS_LINK) +		priv->link = 1; +	else +		priv->link = 0; + +	if(priv->link) { +		while((!(mii_reg & MIIM_STATUS_AN_DONE)) && timeout--) +			mii_reg = read_phy_reg(priv, MIIM_STATUS); +	} + +	return 0; +} + + +/* Parse the 88E1011's status register for speed and duplex + * information */ +uint mii_parse_88E1011_psr(uint mii_reg, struct tsec_private *priv) +{ +	uint speed; + +	if(mii_reg & MIIM_88E1011_PHYSTAT_DUPLEX) +		priv->duplexity = 1; +	else +		priv->duplexity = 0; + +	speed = (mii_reg &MIIM_88E1011_PHYSTAT_SPEED); + +	switch(speed) { +		case MIIM_88E1011_PHYSTAT_GBIT: +			priv->speed = 1000; +			break; +		case MIIM_88E1011_PHYSTAT_100: +			priv->speed = 100; +			break; +		default: +			priv->speed = 10; +	} + +	return 0; +} + + +/* Parse the cis8201's status register for speed and duplex + * information */ +uint mii_parse_cis8201(uint mii_reg, struct tsec_private *priv) +{ +	uint speed; + +	if(mii_reg & MIIM_CIS8201_AUXCONSTAT_DUPLEX) +		priv->duplexity = 1; +	else +		priv->duplexity = 0; + +	speed = mii_reg & MIIM_CIS8201_AUXCONSTAT_SPEED; +	switch(speed) { +		case MIIM_CIS8201_AUXCONSTAT_GBIT: +			priv->speed = 1000; +			break; +		case MIIM_CIS8201_AUXCONSTAT_100: +			priv->speed = 100; +			break; +		default: +			priv->speed = 10; +			break; +	} + +	return 0; +} + + +/* Parse the DM9161's status register for speed and duplex + * information */ +uint mii_parse_dm9161_scsr(uint mii_reg, struct tsec_private *priv) +{ +	if(mii_reg & (MIIM_DM9161_SCSR_100F | MIIM_DM9161_SCSR_100H)) +		priv->speed = 100; +	else +		priv->speed = 10; + +	if(mii_reg & (MIIM_DM9161_SCSR_100F | MIIM_DM9161_SCSR_10F)) +		priv->duplexity = 1; +	else +		priv->duplexity = 0; + +	return 0; +} + + +/* Hack to write all 4 PHYs with the LED values */ +uint mii_cis8204_fixled(uint mii_reg, struct tsec_private *priv) +{ +	uint phyid; +	volatile tsec_t *regbase = priv->phyregs; +	int timeout=1000000; + +	for(phyid=0;phyid<4;phyid++) { +		regbase->miimadd = (phyid << 8) | mii_reg; +		regbase->miimcon = MIIM_CIS8204_SLEDCON_INIT; +		asm("sync"); + +		timeout=1000000; +		while((regbase->miimind & MIIMIND_BUSY) && timeout--); +	} + +	return MIIM_CIS8204_SLEDCON_INIT; +} + +uint mii_cis8204_setmode(uint mii_reg, struct tsec_private *priv) +{ +	if (priv->flags & TSEC_REDUCED) +		return MIIM_CIS8204_EPHYCON_INIT | MIIM_CIS8204_EPHYCON_RGMII; +	else +		return MIIM_CIS8204_EPHYCON_INIT; +} + +/* Initialized 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(volatile tsec_t *regs) +{ +	/* Clear IEVENT */ +	regs->ievent = IEVENT_INIT_CLEAR; + +	regs->imask = IMASK_INIT_CLEAR; + +	regs->hash.iaddr0 = 0; +	regs->hash.iaddr1 = 0; +	regs->hash.iaddr2 = 0; +	regs->hash.iaddr3 = 0; +	regs->hash.iaddr4 = 0; +	regs->hash.iaddr5 = 0; +	regs->hash.iaddr6 = 0; +	regs->hash.iaddr7 = 0; + +	regs->hash.gaddr0 = 0; +	regs->hash.gaddr1 = 0; +	regs->hash.gaddr2 = 0; +	regs->hash.gaddr3 = 0; +	regs->hash.gaddr4 = 0; +	regs->hash.gaddr5 = 0; +	regs->hash.gaddr6 = 0; +	regs->hash.gaddr7 = 0; + +	regs->rctrl = 0x00000000; + +	/* Init RMON mib registers */ +	memset((void *)&(regs->rmon), 0, sizeof(rmon_mib_t)); + +	regs->rmon.cam1 = 0xffffffff; +	regs->rmon.cam2 = 0xffffffff; + +	regs->mrblr = MRBLR_INIT_SETTINGS; + +	regs->minflr = MINFLR_INIT_SETTINGS; + +	regs->attr = ATTR_INIT_SETTINGS; +	regs->attreli = 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 tsec_private *priv = (struct tsec_private *)dev->priv; +	volatile tsec_t *regs = priv->regs; + +	if(priv->link) { +		if(priv->duplexity != 0) +			regs->maccfg2 |= MACCFG2_FULL_DUPLEX; +		else +			regs->maccfg2 &= ~(MACCFG2_FULL_DUPLEX); + +		switch(priv->speed) { +			case 1000: +				regs->maccfg2 = ((regs->maccfg2&~(MACCFG2_IF)) +					| MACCFG2_GMII); +				break; +			case 100: +			case 10: +				regs->maccfg2 = ((regs->maccfg2&~(MACCFG2_IF)) +					| MACCFG2_MII); + +				/* If We're in reduced mode, we need +				 * to say whether we're 10 or 100 MB. +				 */ +				if ((priv->speed == 100) +				    && (priv->flags & TSEC_REDUCED)) +					regs->ecntrl |= ECNTRL_R100; +				else +					regs->ecntrl &= ~(ECNTRL_R100); +				break; +			default: +				printf("%s: Speed was bad\n", dev->name); +				break; +		} + +		printf("Speed: %d, %s duplex\n", priv->speed, +				(priv->duplexity) ? "full" : "half"); + +	} else { +		printf("%s: No link.\n", dev->name); +	} +} + + +/* Set up the buffers and their descriptors, and bring up the + * interface */ +static void startup_tsec(struct eth_device *dev) +{ +	int i; +	struct tsec_private *priv = (struct tsec_private *)dev->priv; +	volatile tsec_t *regs = priv->regs; + +	/* Point to the buffer descriptors */ +	regs->tbase = (unsigned int)(&rtx.txbd[txIdx]); +	regs->rbase = (unsigned int)(&rtx.rxbd[rxIdx]); + +	/* Initialize the Rx Buffer descriptors */ +	for (i = 0; i < PKTBUFSRX; i++) { +		rtx.rxbd[i].status = RXBD_EMPTY; +		rtx.rxbd[i].length = 0; +		rtx.rxbd[i].bufPtr = (uint)NetRxPackets[i]; +	} +	rtx.rxbd[PKTBUFSRX -1].status |= RXBD_WRAP; + +	/* Initialize the TX Buffer Descriptors */ +	for(i=0; i<TX_BUF_CNT; i++) { +		rtx.txbd[i].status = 0; +		rtx.txbd[i].length = 0; +		rtx.txbd[i].bufPtr = 0; +	} +	rtx.txbd[TX_BUF_CNT -1].status |= TXBD_WRAP; + +	/* Start up the PHY */ +	phy_run_commands(priv, priv->phyinfo->startup); +	adjust_link(dev); + +	/* Enable Transmit and Receive */ +	regs->maccfg1 |= (MACCFG1_RX_EN | MACCFG1_TX_EN); + +	/* Tell the DMA it is clear to go */ +	regs->dmactrl |= DMACTRL_INIT_SETTINGS; +	regs->tstat = TSTAT_CLEAR_THALT; +	regs->dmactrl &= ~(DMACTRL_GRS | DMACTRL_GTS); +} + +/* This returns the status bits of the device.	The return value + * is never checked, and this is what the 8260 driver did, so we + * do the same.	 Presumably, this would be zero if there were no + * errors */ +static int tsec_send(struct eth_device* dev, volatile void *packet, int length) +{ +	int i; +	int result = 0; +	struct tsec_private *priv = (struct tsec_private *)dev->priv; +	volatile tsec_t *regs = priv->regs; + +	/* Find an empty buffer descriptor */ +	for(i=0; rtx.txbd[txIdx].status & TXBD_READY; i++) { +		if (i >= TOUT_LOOP) { +			debug ("%s: tsec: tx buffers full\n", dev->name); +			return result; +		} +	} + +	rtx.txbd[txIdx].bufPtr = (uint)packet; +	rtx.txbd[txIdx].length = length; +	rtx.txbd[txIdx].status |= (TXBD_READY | TXBD_LAST | TXBD_CRC | TXBD_INTERRUPT); + +	/* Tell the DMA to go */ +	regs->tstat = TSTAT_CLEAR_THALT; + +	/* Wait for buffer to be transmitted */ +	for(i=0; rtx.txbd[txIdx].status & TXBD_READY; i++) { +		if (i >= TOUT_LOOP) { +			debug ("%s: tsec: tx error\n", dev->name); +			return result; +		} +	} + +	txIdx = (txIdx + 1) % TX_BUF_CNT; +	result = rtx.txbd[txIdx].status & TXBD_STATS; + +	return result; +} + +static int tsec_recv(struct eth_device* dev) +{ +	int length; +	struct tsec_private *priv = (struct tsec_private *)dev->priv; +	volatile tsec_t *regs = priv->regs; + +	while(!(rtx.rxbd[rxIdx].status & RXBD_EMPTY)) { + +		length = rtx.rxbd[rxIdx].length; + +		/* Send the packet up if there were no errors */ +		if (!(rtx.rxbd[rxIdx].status & RXBD_STATS)) { +			NetReceive(NetRxPackets[rxIdx], length - 4); +		} else { +			printf("Got error %x\n", +					(rtx.rxbd[rxIdx].status & RXBD_STATS)); +		} + +		rtx.rxbd[rxIdx].length = 0; + +		/* Set the wrap bit if this is the last element in the list */ +		rtx.rxbd[rxIdx].status = RXBD_EMPTY | (((rxIdx + 1) == PKTBUFSRX) ? RXBD_WRAP : 0); + +		rxIdx = (rxIdx + 1) % PKTBUFSRX; +	} + +	if(regs->ievent&IEVENT_BSY) { +		regs->ievent = IEVENT_BSY; +		regs->rstat = RSTAT_CLEAR_RHALT; +	} + +	return -1; + +} + + +/* Stop the interface */ +static void tsec_halt(struct eth_device* dev) +{ +	struct tsec_private *priv = (struct tsec_private *)dev->priv; +	volatile tsec_t *regs = priv->regs; + +	regs->dmactrl &= ~(DMACTRL_GRS | DMACTRL_GTS); +	regs->dmactrl |= (DMACTRL_GRS | DMACTRL_GTS); + +	while(!(regs->ievent & (IEVENT_GRSC | IEVENT_GTSC))); + +	regs->maccfg1 &= ~(MACCFG1_TX_EN | MACCFG1_RX_EN); + +	/* Shut down the PHY, as needed */ +	phy_run_commands(priv, priv->phyinfo->shutdown); +} + + +struct phy_info phy_info_M88E1011S = { +	0x01410c6, +	"Marvell 88E1011S", +	4, +	(struct phy_cmd[]) { /* config */ +		/* Reset and configure the PHY */ +		{MIIM_CONTROL, MIIM_CONTROL_RESET, NULL}, +		{0x1d, 0x1f, NULL}, +		{0x1e, 0x200c, NULL}, +		{0x1d, 0x5, NULL}, +		{0x1e, 0x0, NULL}, +		{0x1e, 0x100, NULL}, +		{MIIM_GBIT_CONTROL, MIIM_GBIT_CONTROL_INIT, NULL}, +		{MIIM_ANAR, MIIM_ANAR_INIT, NULL}, +		{MIIM_CONTROL, MIIM_CONTROL_RESET, NULL}, +		{MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init}, +		{miim_end,} +	}, +	(struct phy_cmd[]) { /* startup */ +		/* Status is read once to clear old link state */ +		{MIIM_STATUS, miim_read, NULL}, +		/* Auto-negotiate */ +		{MIIM_STATUS, miim_read, &mii_parse_sr}, +		/* Read the status */ +		{MIIM_88E1011_PHY_STATUS, miim_read, &mii_parse_88E1011_psr}, +		{miim_end,} +	}, +	(struct phy_cmd[]) { /* shutdown */ +		{miim_end,} +	}, +}; + +struct phy_info phy_info_M88E1111S = { +	0x01410cc, +	"Marvell 88E1111S", +	4, +	(struct phy_cmd[]) { /* config */ +	  /* Reset and configure the PHY */ +		{MIIM_CONTROL, MIIM_CONTROL_RESET, NULL}, +		{0x1d, 0x1f, NULL}, +		{0x1e, 0x200c, NULL}, +		{0x1d, 0x5, NULL}, +		{0x1e, 0x0, NULL}, +		{0x1e, 0x100, NULL}, +		{MIIM_GBIT_CONTROL, MIIM_GBIT_CONTROL_INIT, NULL}, +		{MIIM_ANAR, MIIM_ANAR_INIT, NULL}, +		{MIIM_CONTROL, MIIM_CONTROL_RESET, NULL}, +		{MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init}, +		{miim_end,} +	}, +	(struct phy_cmd[]) { /* startup */ +	  /* Status is read once to clear old link state */ +		{MIIM_STATUS, miim_read, NULL}, +		/* Auto-negotiate */ +		{MIIM_STATUS, miim_read, &mii_parse_sr}, +		/* Read the status */ +		{MIIM_88E1011_PHY_STATUS, miim_read, &mii_parse_88E1011_psr}, +		{miim_end,} +	}, +	(struct phy_cmd[]) { /* shutdown */ +		{miim_end,} +	}, +}; + +struct phy_info phy_info_cis8204 = { +	0x3f11, +	"Cicada Cis8204", +	6, +	(struct phy_cmd[]) { /* config */ +		/* Override PHY config settings */ +		{MIIM_CIS8201_AUX_CONSTAT, MIIM_CIS8201_AUXCONSTAT_INIT, NULL}, +		/* Configure some basic stuff */ +		{MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init}, +		{MIIM_CIS8204_SLED_CON, MIIM_CIS8204_SLEDCON_INIT, &mii_cis8204_fixled}, +		{MIIM_CIS8204_EPHY_CON, MIIM_CIS8204_EPHYCON_INIT, &mii_cis8204_setmode}, +		{miim_end,} +	}, +	(struct phy_cmd[]) { /* startup */ +		/* Read the Status (2x to make sure link is right) */ +		{MIIM_STATUS, miim_read, NULL}, +		/* Auto-negotiate */ +		{MIIM_STATUS, miim_read, &mii_parse_sr}, +		/* Read the status */ +		{MIIM_CIS8201_AUX_CONSTAT, miim_read, &mii_parse_cis8201}, +		{miim_end,} +	}, +	(struct phy_cmd[]) { /* shutdown */ +		{miim_end,} +	}, +}; + +/* Cicada 8201 */ +struct phy_info phy_info_cis8201 = { +	0xfc41, +	"CIS8201", +	4, +	(struct phy_cmd[]) { /* config */ +		/* Override PHY config settings */ +		{MIIM_CIS8201_AUX_CONSTAT, MIIM_CIS8201_AUXCONSTAT_INIT, NULL}, +		/* Set up the interface mode */ +		{MIIM_CIS8201_EXT_CON1, MIIM_CIS8201_EXTCON1_INIT, NULL}, +		/* Configure some basic stuff */ +		{MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init}, +		{miim_end,} +	}, +	(struct phy_cmd[]) { /* startup */ +		/* Read the Status (2x to make sure link is right) */ +		{MIIM_STATUS, miim_read, NULL}, +		/* Auto-negotiate */ +		{MIIM_STATUS, miim_read, &mii_parse_sr}, +		/* Read the status */ +		{MIIM_CIS8201_AUX_CONSTAT, miim_read, &mii_parse_cis8201}, +		{miim_end,} +	}, +	(struct phy_cmd[]) { /* shutdown */ +		{miim_end,} +	}, +}; + + +struct phy_info phy_info_dm9161 = { +	0x0181b88, +	"Davicom DM9161E", +	4, +	(struct phy_cmd[]) { /* config */ +		{MIIM_CONTROL, MIIM_DM9161_CR_STOP, NULL}, +		/* Do not bypass the scrambler/descrambler */ +		{MIIM_DM9161_SCR, MIIM_DM9161_SCR_INIT, NULL}, +		/* Clear 10BTCSR to default */ +		{MIIM_DM9161_10BTCSR, MIIM_DM9161_10BTCSR_INIT, NULL}, +		/* Configure some basic stuff */ +		{MIIM_CONTROL, MIIM_CR_INIT, NULL}, +		/* Restart Auto Negotiation */ +		{MIIM_CONTROL, MIIM_DM9161_CR_RSTAN, NULL}, +		{miim_end,} +	}, +	(struct phy_cmd[]) { /* startup */ +		/* Status is read once to clear old link state */ +		{MIIM_STATUS, miim_read, NULL}, +		/* Auto-negotiate */ +		{MIIM_STATUS, miim_read, &mii_parse_sr}, +		/* Read the status */ +		{MIIM_DM9161_SCSR, miim_read, &mii_parse_dm9161_scsr}, +		{miim_end,} +	}, +	(struct phy_cmd[]) { /* shutdown */ +		{miim_end,} +	}, +}; + +uint mii_parse_lxt971_sr2(uint mii_reg, struct tsec_private *priv) +{ +	unsigned int speed; +	if (priv->link) { +		speed = mii_reg & MIIM_LXT971_SR2_SPEED_MASK; + +		switch (speed) { +		case MIIM_LXT971_SR2_10HDX: +			priv->speed = 10; +			priv->duplexity = 0; +			break; +		case MIIM_LXT971_SR2_10FDX: +			priv->speed = 10; +			priv->duplexity = 1; +			break; +		case MIIM_LXT971_SR2_100HDX: +			priv->speed = 100; +			priv->duplexity = 0; +		default: +			priv->speed = 100; +			priv->duplexity = 1; +			break; +		} +	} else { +		priv->speed = 0; +		priv->duplexity = 0; +	} + +	return 0; +} + +static struct phy_info phy_info_lxt971 = { +	0x0001378e, +	"LXT971", +	4, +	(struct phy_cmd []) {  /* config */ +		{ MIIM_CR, MIIM_CR_INIT, mii_cr_init }, /* autonegotiate */ +		{ miim_end, } +	}, +	(struct phy_cmd []) {  /* startup - enable interrupts */ +		/* { 0x12, 0x00f2, NULL }, */ +		{ MIIM_STATUS, miim_read, NULL }, +		{ MIIM_STATUS, miim_read, &mii_parse_sr }, +		{ MIIM_LXT971_SR2, miim_read, &mii_parse_lxt971_sr2 }, +		{ miim_end, } +	}, +	(struct phy_cmd []) {  /* shutdown - disable interrupts */ +		{ miim_end, } +	}, +}; + +struct phy_info *phy_info[] = { +#if 0 +	&phy_info_cis8201, +#endif +	&phy_info_cis8204, +	&phy_info_M88E1011S, +	&phy_info_M88E1111S, +	&phy_info_dm9161, +	&phy_info_lxt971, +	NULL +}; + + +/* Grab the identifier of the device's PHY, and search through + * all of the known PHYs to see if one matches.	 If so, return + * it, if not, return NULL */ +struct phy_info * get_phy_info(struct eth_device *dev) +{ +	struct tsec_private *priv = (struct tsec_private *)dev->priv; +	uint phy_reg, phy_ID; +	int i; +	struct phy_info *theInfo = NULL; + +	/* Grab the bits from PHYIR1, and put them in the upper half */ +	phy_reg = read_phy_reg(priv, MIIM_PHYIR1); +	phy_ID = (phy_reg & 0xffff) << 16; + +	/* Grab the bits from PHYIR2, and put them in the lower half */ +	phy_reg = read_phy_reg(priv, MIIM_PHYIR2); +	phy_ID |= (phy_reg & 0xffff); + +	/* loop through all the known PHY types, and find one that */ +	/* matches the ID we read from the PHY. */ +	for(i=0; phy_info[i]; i++) { +		if(phy_info[i]->id == (phy_ID >> phy_info[i]->shift)) +			theInfo = phy_info[i]; +	} + +	if(theInfo == NULL) +	{ +		printf("%s: PHY id %x is not supported!\n", dev->name, phy_ID); +		return NULL; +	} else { +		printf("%s: PHY is %s (%x)\n", dev->name, theInfo->name, +				phy_ID); +	} + +	return theInfo; +} + + +/* Execute the given series of commands on the given device's + * PHY, running functions as necessary*/ +void phy_run_commands(struct tsec_private *priv, struct phy_cmd *cmd) +{ +	int i; +	uint result; +	volatile tsec_t *phyregs = priv->phyregs; + +	phyregs->miimcfg = MIIMCFG_RESET; + +	phyregs->miimcfg = MIIMCFG_INIT_VALUE; + +	while(phyregs->miimind & MIIMIND_BUSY); + +	for(i=0;cmd->mii_reg != miim_end;i++) { +		if(cmd->mii_data == miim_read) { +			result = read_phy_reg(priv, cmd->mii_reg); + +			if(cmd->funct != NULL) +				(*(cmd->funct))(result, priv); + +		} else { +			if(cmd->funct != NULL) +				result = (*(cmd->funct))(cmd->mii_reg, priv); +			else +				result = cmd->mii_data; + +			write_phy_reg(priv, cmd->mii_reg, result); + +		} +		cmd++; +	} +} + + +/* Relocate the function pointers in the phy cmd lists */ +static void relocate_cmds(void) +{ +	struct phy_cmd **cmdlistptr; +	struct phy_cmd *cmd; +	int i,j,k; +	DECLARE_GLOBAL_DATA_PTR; + +	for(i=0; phy_info[i]; i++) { +		/* First thing's first: relocate the pointers to the +		 * PHY command structures (the structs were done) */ +		phy_info[i] = (struct phy_info *) ((uint)phy_info[i] +				+ gd->reloc_off); +		phy_info[i]->name += gd->reloc_off; +		phy_info[i]->config = +			(struct phy_cmd *)((uint)phy_info[i]->config +					   + gd->reloc_off); +		phy_info[i]->startup = +			(struct phy_cmd *)((uint)phy_info[i]->startup +					   + gd->reloc_off); +		phy_info[i]->shutdown = +			(struct phy_cmd *)((uint)phy_info[i]->shutdown +					   + gd->reloc_off); + +		cmdlistptr = &phy_info[i]->config; +		j=0; +		for(;cmdlistptr <= &phy_info[i]->shutdown;cmdlistptr++) { +			k=0; +			for(cmd=*cmdlistptr;cmd->mii_reg != miim_end;cmd++) { +				/* Only relocate non-NULL pointers */ +				if(cmd->funct) +					cmd->funct += gd->reloc_off; + +				k++; +			} +			j++; +		} +	} + +	relocated = 1; +} + + +#ifndef CONFIG_BITBANGMII + +struct tsec_private * get_priv_for_phy(unsigned char phyaddr) +{ +	int i; + +	for(i=0;i<MAXCONTROLLERS;i++) { +		if(privlist[i]->phyaddr == phyaddr) +			return privlist[i]; +	} + +	return NULL; +} + +/* + * Read a MII PHY register. + * + * Returns: + *  0 on success + */ +int miiphy_read(unsigned char addr, unsigned char reg, unsigned short *value) +{ +	unsigned short ret; +	struct tsec_private *priv = get_priv_for_phy(addr); + +	if(NULL == priv) { +		printf("Can't read PHY at address %d\n", addr); +		return -1; +	} + +	ret = (unsigned short)read_phy_reg(priv, reg); +	*value = ret; + +	return 0; +} + +/* + * Write a MII PHY register. + * + * Returns: + *  0 on success + */ +int miiphy_write(unsigned char addr, unsigned char reg, unsigned short value) +{ +	struct tsec_private *priv = get_priv_for_phy(addr); + +	if(NULL == priv) { +		printf("Can't write PHY at address %d\n", addr); +		return -1; +	} + +	write_phy_reg(priv, reg, value); + +	return 0; +} + +#endif /* CONFIG_BITBANGMII */ + +#endif /* CONFIG_TSEC_ENET */ diff --git a/drivers/tsec.h b/drivers/tsec.h new file mode 100644 index 000000000..15961d73d --- /dev/null +++ b/drivers/tsec.h @@ -0,0 +1,505 @@ +/* + *  tsec.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 2004 Freescale Semiconductor. + * (C) Copyright 2003, Motorola, Inc. + * maintained by Xianghua Xiao (x.xiao@motorola.com) + * author Andy Fleming + * + */ + +#ifndef __TSEC_H +#define __TSEC_H + +#include <net.h> +#include <config.h> + +#ifndef CFG_TSEC1_OFFSET +    #define CFG_TSEC1_OFFSET	(0x24000) +#endif + +#define TSEC_SIZE	0x01000 + +/* FIXME:  Should these be pushed back to 83xx and 85xx config files? */ +#if defined(CONFIG_MPC85xx) +    #define TSEC_BASE_ADDR	(CFG_IMMR + CFG_TSEC1_OFFSET) +#elif defined(CONFIG_MPC83XX) +    #define TSEC_BASE_ADDR	(CFG_IMMRBAR + CFG_TSEC1_OFFSET) +#endif + + +#define MAC_ADDR_LEN 6 + +/* #define TSEC_TIMEOUT 	1000000 */ +#define TSEC_TIMEOUT 1000 +#define TOUT_LOOP 	1000000 + +/* MAC register bits */ +#define MACCFG1_SOFT_RESET	0x80000000 +#define MACCFG1_RESET_RX_MC	0x00080000 +#define MACCFG1_RESET_TX_MC	0x00040000 +#define MACCFG1_RESET_RX_FUN	0x00020000 +#define	MACCFG1_RESET_TX_FUN	0x00010000 +#define MACCFG1_LOOPBACK	0x00000100 +#define MACCFG1_RX_FLOW		0x00000020 +#define MACCFG1_TX_FLOW		0x00000010 +#define MACCFG1_SYNCD_RX_EN	0x00000008 +#define MACCFG1_RX_EN		0x00000004 +#define MACCFG1_SYNCD_TX_EN	0x00000002 +#define MACCFG1_TX_EN		0x00000001 + +#define MACCFG2_INIT_SETTINGS	0x00007205 +#define MACCFG2_FULL_DUPLEX	0x00000001 +#define MACCFG2_IF              0x00000300 +#define MACCFG2_GMII		0x00000200 +#define MACCFG2_MII             0x00000100 + +#define ECNTRL_INIT_SETTINGS	0x00001000 +#define ECNTRL_TBI_MODE         0x00000020 +#define ECNTRL_R100		0x00000008 + +#define miim_end -2 +#define miim_read -1 + +#define TBIPA_VALUE		0x1f +#define MIIMCFG_INIT_VALUE	0x00000003 +#define MIIMCFG_RESET		0x80000000 + +#define MIIMIND_BUSY            0x00000001 +#define MIIMIND_NOTVALID        0x00000004 + +#define MIIM_CONTROL            0x00 +#define MIIM_CONTROL_RESET	0x00009140 +#define MIIM_CONTROL_INIT       0x00001140 +#define MIIM_ANEN               0x00001000 + +#define MIIM_CR                 0x00 +#define MIIM_CR_RST		0x00008000 +#define MIIM_CR_INIT	        0x00001000 + +#define MIIM_STATUS		0x1 +#define MIIM_STATUS_AN_DONE 	0x00000020 +#define MIIM_STATUS_LINK	0x0004 + +#define MIIM_PHYIR1		0x2 +#define MIIM_PHYIR2		0x3 + +#define MIIM_ANAR		0x4 +#define MIIM_ANAR_INIT		0x1e1 + +#define MIIM_TBI_ANLPBPA	0x5 +#define MIIM_TBI_ANLPBPA_HALF	0x00000040 +#define MIIM_TBI_ANLPBPA_FULL	0x00000020 + +#define MIIM_TBI_ANEX		0x6 +#define MIIM_TBI_ANEX_NP	0x00000004 +#define MIIM_TBI_ANEX_PRX	0x00000002 + +#define MIIM_GBIT_CONTROL	0x9 +#define MIIM_GBIT_CONTROL_INIT	0xe00 + +/* Cicada Auxiliary Control/Status Register */ +#define MIIM_CIS8201_AUX_CONSTAT        0x1c +#define MIIM_CIS8201_AUXCONSTAT_INIT    0x0004 +#define MIIM_CIS8201_AUXCONSTAT_DUPLEX  0x0020 +#define MIIM_CIS8201_AUXCONSTAT_SPEED   0x0018 +#define MIIM_CIS8201_AUXCONSTAT_GBIT    0x0010 +#define MIIM_CIS8201_AUXCONSTAT_100     0x0008 + +/* Cicada Extended Control Register 1 */ +#define MIIM_CIS8201_EXT_CON1           0x17 +#define MIIM_CIS8201_EXTCON1_INIT       0x0000 + +/* Cicada 8204 Extended PHY Control Register 1 */ +#define MIIM_CIS8204_EPHY_CON		0x17 +#define MIIM_CIS8204_EPHYCON_INIT	0x0006 +#define MIIM_CIS8204_EPHYCON_RGMII	0x1000 + +/* Cicada 8204 Serial LED Control Register */ +#define MIIM_CIS8204_SLED_CON		0x1b +#define MIIM_CIS8204_SLEDCON_INIT	0x1115 + +#define MIIM_GBIT_CON		0x09 +#define MIIM_GBIT_CON_ADVERT	0x0e00 + +/* 88E1011 PHY Status Register */ +#define MIIM_88E1011_PHY_STATUS         0x11 +#define MIIM_88E1011_PHYSTAT_SPEED      0xc000 +#define MIIM_88E1011_PHYSTAT_GBIT       0x8000 +#define MIIM_88E1011_PHYSTAT_100        0x4000 +#define MIIM_88E1011_PHYSTAT_DUPLEX     0x2000 +#define MIIM_88E1011_PHYSTAT_SPDDONE	0x0800 +#define MIIM_88E1011_PHYSTAT_LINK	0x0400 + +/* DM9161 Control register values */ +#define MIIM_DM9161_CR_STOP	0x0400 +#define MIIM_DM9161_CR_RSTAN	0x1200 + +#define MIIM_DM9161_SCR		0x10 +#define MIIM_DM9161_SCR_INIT	0x0610 + +/* DM9161 Specified Configuration and Status Register */ +#define MIIM_DM9161_SCSR	0x11 +#define MIIM_DM9161_SCSR_100F	0x8000 +#define MIIM_DM9161_SCSR_100H	0x4000 +#define MIIM_DM9161_SCSR_10F	0x2000 +#define MIIM_DM9161_SCSR_10H	0x1000 + +/* DM9161 10BT Configuration/Status */ +#define MIIM_DM9161_10BTCSR	0x12 +#define MIIM_DM9161_10BTCSR_INIT	0x7800 + +/* LXT971 Status 2 registers */ +#define MIIM_LXT971_SR2       	17  /* Status Register 2  */ +#define MIIM_LXT971_SR2_SPEED_MASK	0xf000 +#define MIIM_LXT971_SR2_10HDX	0x1000  /* 10 Mbit half duplex selected */ +#define MIIM_LXT971_SR2_10FDX	0x2000  /* 10 Mbit full duplex selected */ +#define MIIM_LXT971_SR2_100HDX	0x4000  /* 100 Mbit half duplex selected */ +#define MIIM_LXT971_SR2_100FDX	0x8000  /* 100 Mbit full duplex selected */ + +#define MIIM_READ_COMMAND       0x00000001 + +#define MRBLR_INIT_SETTINGS	PKTSIZE_ALIGN + +#define MINFLR_INIT_SETTINGS	0x00000040 + +#define DMACTRL_INIT_SETTINGS   0x000000c3 +#define DMACTRL_GRS             0x00000010 +#define DMACTRL_GTS             0x00000008 + +#define TSTAT_CLEAR_THALT       0x80000000 +#define RSTAT_CLEAR_RHALT       0x00800000 + + +#define IEVENT_INIT_CLEAR	0xffffffff +#define IEVENT_BABR		0x80000000 +#define IEVENT_RXC		0x40000000 +#define IEVENT_BSY		0x20000000 +#define IEVENT_EBERR		0x10000000 +#define IEVENT_MSRO		0x04000000 +#define IEVENT_GTSC		0x02000000 +#define IEVENT_BABT		0x01000000 +#define IEVENT_TXC		0x00800000 +#define IEVENT_TXE		0x00400000 +#define IEVENT_TXB		0x00200000 +#define IEVENT_TXF		0x00100000 +#define IEVENT_IE		0x00080000 +#define IEVENT_LC		0x00040000 +#define IEVENT_CRL		0x00020000 +#define IEVENT_XFUN		0x00010000 +#define IEVENT_RXB0		0x00008000 +#define IEVENT_GRSC		0x00000100 +#define IEVENT_RXF0		0x00000080 + +#define IMASK_INIT_CLEAR	0x00000000 +#define IMASK_TXEEN		0x00400000 +#define IMASK_TXBEN		0x00200000 +#define IMASK_TXFEN             0x00100000 +#define IMASK_RXFEN0		0x00000080 + + +/* 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 + +typedef struct txbd8 +{ +	ushort       status;         /* Status Fields */ +	ushort       length;         /* Buffer length */ +	uint         bufPtr;         /* Buffer Pointer */ +} txbd8_t; + +typedef struct rxbd8 +{ +	ushort       status;         /* Status Fields */ +	ushort       length;         /* Buffer Length */ +	uint         bufPtr;         /* Buffer Pointer */ +} rxbd8_t; + +typedef struct rmon_mib +{ +	/* Transmit and Receive Counters */ +	uint	tr64;		/* Transmit and Receive 64-byte Frame Counter */ +	uint	tr127;		/* Transmit and Receive 65-127 byte Frame Counter */ +	uint	tr255;		/* Transmit and Receive 128-255 byte Frame Counter */ +	uint	tr511;		/* Transmit and Receive 256-511 byte Frame Counter */ +	uint	tr1k;		/* Transmit and Receive 512-1023 byte Frame Counter */ +	uint	trmax;		/* Transmit and Receive 1024-1518 byte Frame Counter */ +	uint	trmgv;		/* Transmit and Receive 1519-1522 byte Good VLAN Frame */ +	/* Receive Counters */ +	uint	rbyt;		/* Receive Byte Counter */ +	uint	rpkt;		/* Receive Packet Counter */ +	uint	rfcs;		/* Receive FCS Error Counter */ +	uint	rmca;		/* Receive Multicast Packet (Counter) */ +	uint	rbca;		/* Receive Broadcast Packet */ +	uint	rxcf;		/* Receive Control Frame Packet */ +	uint	rxpf;		/* Receive Pause Frame Packet */ +	uint	rxuo;		/* Receive Unknown OP Code */ +	uint	raln;		/* Receive Alignment Error */ +	uint	rflr;		/* Receive Frame Length Error */ +	uint	rcde;		/* Receive Code Error */ +	uint	rcse;		/* Receive Carrier Sense Error */ +	uint	rund;		/* Receive Undersize Packet */ +	uint	rovr;		/* Receive Oversize Packet */ +	uint	rfrg;		/* Receive Fragments */ +	uint	rjbr;		/* Receive Jabber */ +	uint	rdrp;		/* Receive Drop */ +	/* Transmit Counters */ +	uint	tbyt;		/* Transmit Byte Counter */ +	uint	tpkt;		/* Transmit Packet */ +	uint	tmca;		/* Transmit Multicast Packet */ +	uint	tbca;		/* Transmit Broadcast Packet */ +	uint	txpf;		/* Transmit Pause Control Frame */ +	uint	tdfr;		/* Transmit Deferral Packet */ +	uint	tedf;		/* Transmit Excessive Deferral Packet */ +	uint	tscl;		/* Transmit Single Collision Packet */ +	/* (0x2_n700) */ +	uint	tmcl;		/* Transmit Multiple Collision Packet */ +	uint	tlcl;		/* Transmit Late Collision Packet */ +	uint	txcl;		/* Transmit Excessive Collision Packet */ +	uint	tncl;		/* Transmit Total Collision */ + +	uint	res2; + +	uint	tdrp;		/* Transmit Drop Frame */ +	uint	tjbr;		/* Transmit Jabber Frame */ +	uint	tfcs;		/* Transmit FCS Error */ +	uint	txcf;		/* Transmit Control Frame */ +	uint	tovr;		/* Transmit Oversize Frame */ +	uint	tund;		/* Transmit Undersize Frame */ +	uint	tfrg;		/* Transmit Fragments Frame */ +	/* General Registers */ +	uint	car1;		/* Carry Register One */ +	uint	car2;		/* Carry Register Two */ +	uint	cam1;		/* Carry Register One Mask */ +	uint	cam2;		/* Carry Register Two Mask */ +} rmon_mib_t; + +typedef struct tsec_hash_regs +{ +	uint	iaddr0;		/* Individual Address Register 0 */ +	uint	iaddr1;		/* Individual Address Register 1 */ +	uint	iaddr2;		/* Individual Address Register 2 */ +	uint	iaddr3;		/* Individual Address Register 3 */ +	uint	iaddr4;		/* Individual Address Register 4 */ +	uint	iaddr5;		/* Individual Address Register 5 */ +	uint	iaddr6;		/* Individual Address Register 6 */ +	uint	iaddr7;		/* Individual Address Register 7 */ +	uint	res1[24]; +	uint	gaddr0;		/* Group Address Register 0 */ +	uint	gaddr1;		/* Group Address Register 1 */ +	uint	gaddr2;		/* Group Address Register 2 */ +	uint	gaddr3;		/* Group Address Register 3 */ +	uint	gaddr4;		/* Group Address Register 4 */ +	uint	gaddr5;		/* Group Address Register 5 */ +	uint	gaddr6;		/* Group Address Register 6 */ +	uint	gaddr7;		/* Group Address Register 7 */ +	uint	res2[24]; +} tsec_hash_t; + +typedef struct tsec +{ +	/* General Control and Status Registers (0x2_n000) */ +	uint	res000[4]; + +	uint	ievent;		/* Interrupt Event */ +	uint	imask;		/* Interrupt Mask */ +	uint	edis;		/* Error Disabled */ +	uint	res01c; +	uint	ecntrl;		/* Ethernet Control */ +	uint	minflr;		/* Minimum Frame Length */ +	uint	ptv;		/* Pause Time Value */ +	uint	dmactrl;	/* DMA Control */ +	uint	tbipa;		/* TBI PHY Address */ + +	uint	res034[3]; +	uint	res040[48]; + +	/* Transmit Control and Status Registers (0x2_n100) */ +	uint	tctrl;		/* Transmit Control */ +	uint 	tstat;		/* Transmit Status */ +	uint	res108; +	uint	tbdlen;		/* Tx BD Data Length */ +	uint	res110[5]; +	uint	ctbptr;	        /* Current TxBD Pointer */ +	uint	res128[23]; +	uint	tbptr;		/* TxBD Pointer */ +	uint	res188[30]; +	/* (0x2_n200) */ +	uint        res200; +	uint	tbase;		/* TxBD Base Address */ +	uint	res208[42]; +	uint	ostbd;		/* Out of Sequence TxBD */ +	uint	ostbdp;		/* Out of Sequence Tx Data Buffer Pointer */ +	uint        res2b8[18]; + +	/* Receive Control and Status Registers (0x2_n300) */ +	uint	rctrl;		/* Receive Control */ +	uint	rstat;		/* Receive Status */ +	uint	res308; +	uint	rbdlen;		/* RxBD Data Length */ +	uint	res310[4]; +	uint        res320; +	uint	crbptr; 	/* Current Receive Buffer Pointer */ +	uint	res328[6]; +	uint	mrblr;  	/* Maximum Receive Buffer Length */ +	uint	res344[16]; +	uint	rbptr;   	/* RxBD Pointer */ +	uint        res388[30]; +	/* (0x2_n400) */ +	uint        res400; +	uint	rbase;  	/* RxBD Base Address */ +	uint        res408[62]; + +	/* MAC Registers (0x2_n500) */ +	uint	maccfg1;	/* MAC Configuration #1 */ +	uint	maccfg2;	/* MAC Configuration #2 */ +	uint	ipgifg;		/* Inter Packet Gap/Inter Frame Gap */ +	uint	hafdup;		/* Half-duplex */ +	uint	maxfrm;		/* Maximum Frame */ +	uint	res514; +	uint	res518; + +	uint	res51c; + +	uint	miimcfg;	/* MII Management: Configuration */ +	uint	miimcom;	/* MII Management: Command */ +	uint	miimadd;	/* MII Management: Address */ +	uint	miimcon;	/* MII Management: Control */ +	uint	miimstat;	/* MII Management: Status */ +	uint	miimind;	/* MII Management: Indicators */ + +	uint	res538; + +	uint	ifstat;		/* Interface Status */ +	uint	macstnaddr1;	/* Station Address, part 1 */ +	uint	macstnaddr2;	/* Station Address, part 2 */ +	uint	res548[46]; + +	/* (0x2_n600) */ +	uint	res600[32]; + +	/* RMON MIB Registers (0x2_n680-0x2_n73c) */ +	rmon_mib_t	rmon; +	uint	res740[48]; + +	/* Hash Function Registers (0x2_n800) */ +	tsec_hash_t	hash; + +	uint        res900[128]; + +	/* Pattern Registers (0x2_nb00) */ +	uint        resb00[62]; +	uint        attr;          /* Default Attribute Register */ +	uint        attreli;       /* Default Attribute Extract Length and Index */ + +	/* TSEC Future Expansion Space (0x2_nc00-0x2_nffc) */ +	uint	resc00[256]; +} tsec_t; + +#define TSEC_GIGABIT (1) + +/* This flag currently only has + * meaning if we're using the eTSEC */ +#define TSEC_REDUCED (1 << 1) + +struct tsec_private { +	volatile tsec_t *regs; +	volatile tsec_t *phyregs; +	struct phy_info *phyinfo; +	uint phyaddr; +	u32 flags; +	uint link; +	uint duplexity; +	uint speed; +}; + + +/* + * struct phy_cmd:  A command for reading or writing a PHY register + * + * mii_reg:  The register to read or write + * + * mii_data:  For writes, the value to put in the register. + * 	A value of -1 indicates this is a read. + * + * funct: A function pointer which is invoked for each command. + * 	For reads, this function will be passed the value read + *	from the PHY, and process it. + *	For writes, the result of this function will be written + *	to the PHY register + */ +struct phy_cmd { +    uint mii_reg; +    uint mii_data; +    uint (*funct) (uint mii_reg, struct tsec_private* priv); +}; + +/* struct phy_info: a structure which defines attributes for a PHY + * + * id will contain a number which represents the PHY.  During + * startup, the driver will poll the PHY to find out what its + * UID--as defined by registers 2 and 3--is.  The 32-bit result + * gotten from the PHY will be shifted right by "shift" bits to + * discard any bits which may change based on revision numbers + * unimportant to functionality + * + * The struct phy_cmd entries represent pointers to an arrays of + * commands which tell the driver what to do to the PHY. + */ +struct phy_info { +    uint id; +    char *name; +    uint shift; +    /* Called to configure the PHY, and modify the controller +     * based on the results */ +    struct phy_cmd *config; + +    /* Called when starting up the controller */ +    struct phy_cmd *startup; + +    /* Called when bringing down the controller */ +    struct phy_cmd *shutdown; +}; + +#endif /* __TSEC_H */ |