⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tsec.c.svn-base

📁 u-boot for S3c2443 processor
💻 SVN-BASE
字号:
/* * tsec.c * Motorola 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. * * (C) Copyright 2003, Motorola, Inc. * maintained by Xianghua Xiao (x.xiao@motorola.com) * 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#undef TSEC_DEBUG#ifdef TSEC_DEBUG#define DBGPRINT(x) printf(x)#else#define DBGPRINT(x)#endifstatic 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;#ifdef __GNUC__static RTXBD rtx __attribute__ ((aligned(8)));#else#error "rtx must be 64-bit aligned"#endifstatic 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(tsec_t *regs);static void startup_tsec(tsec_t *regs);static void init_phy(tsec_t *regs);uint read_phy_reg(tsec_t *regbase, uint phyid, uint offset);static int	phy_id = -1;/* Initialize device structure.  returns 0 on failure, 1 on * success */int tsec_initialize(bd_t *bis){	struct eth_device* dev;	int i;	tsec_t *regs = (tsec_t *)(TSEC_BASE_ADDR);	dev = (struct eth_device*) malloc(sizeof *dev);	if(dev == NULL)		return 0;	memset(dev, 0, sizeof *dev);	sprintf(dev->name, "MOTO ETHERNET");	dev->iobase = 0;	dev->priv   = 0;	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);	/* Reconfigure the PHY to advertise everything here	 * so that it works with both gigabit and 10/100 */#ifdef CONFIG_PHY_M88E1011	/* Assign a Physical address to the TBI */	regs->tbipa=TBIPA_VALUE;	/* reset the management interface */	regs->miimcfg=MIIMCFG_RESET;	regs->miimcfg=MIIMCFG_INIT_VALUE;	/* Wait until the bus is free */	while(regs->miimind & MIIMIND_BUSY);	/* Locate PHYs.  Skip TBIPA, which we know is 31.	*/	for (i=0; i<31; i++) {		if (read_phy_reg(regs, i, 2) == 0x141) {			if (phy_id == -1)				phy_id = i;#ifdef TSEC_DEBUG			printf("Found Marvell PHY at 0x%02x\n", i);#endif		}	}#ifdef TSEC_DEBUG	printf("Using PHY ID 0x%02x\n", phy_id);#endif	write_phy_reg(regs, phy_id, MIIM_CONTROL, MIIM_CONTROL_RESET);	RESET_ERRATA(regs, phy_id);	/* Configure the PHY to advertise gbit and 10/100 */	write_phy_reg(regs, phy_id, MIIM_GBIT_CONTROL, MIIM_GBIT_CONTROL_INIT);	write_phy_reg(regs, phy_id, MIIM_ANAR, MIIM_ANAR_INIT);	/* Reset the PHY so the new settings take effect */	write_phy_reg(regs, phy_id, MIIM_CONTROL, MIIM_CONTROL_RESET);#endif	return 1;}/* Initializes data structures and registers for the controller, * and brings the interface up */int tsec_init(struct eth_device* dev, bd_t * bd){	tsec_t *regs;	uint tempval;	char tmpbuf[MAC_ADDR_LEN];	int i;	regs = (tsec_t *)(TSEC_BASE_ADDR);	/* Make sure the controller is stopped */	tsec_halt(dev);	/* Reset the MAC */	regs->maccfg1 |= MACCFG1_SOFT_RESET;	/* Clear MACCFG1[Soft_Reset] */	regs->maccfg1 &= ~(MACCFG1_SOFT_RESET);	/* Init MACCFG2.  Defaults to GMII/MII */	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] = bd->bi_enetaddr[i];	}	(uint)(regs->macstnaddr1) = *((uint *)(tmpbuf));	tempval = *((uint *)(tmpbuf +4));	(uint)(regs->macstnaddr2) = tempval;	/* Initialize the PHY */	init_phy(regs);	/* 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(regs);	return 1;}/* Reads from the register at offset in the PHY at phyid, *//* using the register set defined in regbase.  It waits until the *//* bits in the miimstat are valid (miimind notvalid bit cleared), *//* and then passes those bits on to the variable specified in *//* value *//* Before it does the read, it needs to clear the command field */uint read_phy_reg(tsec_t *regbase, uint phyid, uint offset){	uint value;	/* Put the address of the phy, and the register number into	 * MIIMADD	 */	regbase->miimadd = (phyid << 8) | offset;	/* Clear the command register, and wait */	regbase->miimcom = 0;	asm("msync");	/* Initiate a read command, and wait */	regbase->miimcom = MIIM_READ_COMMAND;	asm("msync");	/* 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;}/* Setup the PHY */static void init_phy(tsec_t *regs){	uint testval;	unsigned int timeout = TSEC_TIMEOUT;	/* Assign a Physical address to the TBI */	regs->tbipa=TBIPA_VALUE;	/* reset the management interface */	regs->miimcfg=MIIMCFG_RESET;	regs->miimcfg=MIIMCFG_INIT_VALUE;	/* Wait until the bus is free */	while(regs->miimind & MIIMIND_BUSY);#ifdef CONFIG_PHY_CIS8201	/* override PHY config settings */	write_phy_reg(regs, 0, MIIM_AUX_CONSTAT, MIIM_AUXCONSTAT_INIT);	/* Set up interface mode */	write_phy_reg(regs, 0, MIIM_EXT_CON1, MIIM_EXTCON1_INIT);#endif	/* Set the PHY to gigabit, full duplex, Auto-negotiate */	write_phy_reg(regs, phy_id, MIIM_CONTROL, MIIM_CONTROL_INIT);	/* Wait until STATUS indicates Auto-Negotiation is done */	DBGPRINT("Waiting for Auto-negotiation to complete\n");	testval=read_phy_reg(regs, phy_id, MIIM_STATUS);	while((!(testval & MIIM_STATUS_AN_DONE))&& timeout--) {		testval=read_phy_reg(regs, phy_id, MIIM_STATUS);	}	if(testval & MIIM_STATUS_AN_DONE)		DBGPRINT("Auto-negotiation done\n");	else		DBGPRINT("Auto-negotiation timed-out.\n");#ifdef CONFIG_PHY_CIS8201	/* Find out what duplexity (duplicity?) we have */	/* Read it twice to make sure */	testval=read_phy_reg(regs, phy_id, MIIM_AUX_CONSTAT);	if(testval & MIIM_AUXCONSTAT_DUPLEX) {		DBGPRINT("Enet starting in full duplex\n");		regs->maccfg2 |= MACCFG2_FULL_DUPLEX;	} else {		DBGPRINT("Enet starting in half duplex\n");		regs->maccfg2 &= ~MACCFG2_FULL_DUPLEX;	}	/* Also, we look to see what speed we are at	 * if Gigabit, MACCFG2 goes in GMII, otherwise,	 * MII mode.	 */	if((testval & MIIM_AUXCONSTAT_SPEED) != MIIM_AUXCONSTAT_GBIT) {		if((testval & MIIM_AUXCONSTAT_SPEED) == MIIM_AUXCONSTAT_100)			DBGPRINT("Enet starting in 100BT\n");		else			DBGPRINT("Enet starting in 10BT\n");		/* mark the mode in MACCFG2 */		regs->maccfg2 = ((regs->maccfg2&~(MACCFG2_IF)) | MACCFG2_MII);	} else {		DBGPRINT("Enet starting in 1000BT\n");	}#endif#ifdef CONFIG_PHY_M88E1011	/* Read the PHY to see what speed and duplex we are */	testval=read_phy_reg(regs, phy_id, MIIM_PHY_STATUS);	timeout = TSEC_TIMEOUT;	while((!(testval & MIIM_PHYSTAT_SPDDONE)) && timeout--) {		testval = read_phy_reg(regs,phy_id,MIIM_PHY_STATUS);	}	if(!(testval & MIIM_PHYSTAT_SPDDONE))		DBGPRINT("Enet: Speed not resolved\n");	testval=read_phy_reg(regs, phy_id, MIIM_PHY_STATUS);	if(testval & MIIM_PHYSTAT_DUPLEX) {		DBGPRINT("Enet starting in Full Duplex\n");		regs->maccfg2 |= MACCFG2_FULL_DUPLEX;	} else {		DBGPRINT("Enet starting in Half Duplex\n");		regs->maccfg2 &= ~MACCFG2_FULL_DUPLEX;	}	if(!((testval&MIIM_PHYSTAT_SPEED) == MIIM_PHYSTAT_GBIT)) {		if((testval & MIIM_PHYSTAT_SPEED) == MIIM_PHYSTAT_100)			DBGPRINT("Enet starting in 100BT\n");		else			DBGPRINT("Enet starting in 10BT\n");		regs->maccfg2 = ((regs->maccfg2&~(MACCFG2_IF)) | MACCFG2_MII);	} else {		DBGPRINT("Enet starting in 1000BT\n");	}#endif}static void init_registers(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;}static void startup_tsec(tsec_t *regs){	int i;	/* 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;	/* 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;	tsec_t * regs = (tsec_t *)(TSEC_BASE_ADDR);	/* Find an empty buffer descriptor */	for(i=0; rtx.txbd[txIdx].status & TXBD_READY; i++) {		if (i >= TOUT_LOOP) {			DBGPRINT("tsec: tx buffers full\n");			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) {			DBGPRINT("tsec: tx error\n");			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;	tsec_t *regs = (tsec_t *)(TSEC_BASE_ADDR);	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);		}		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;}static void tsec_halt(struct eth_device* dev){	tsec_t *regs = (tsec_t *)(TSEC_BASE_ADDR);	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);}#ifndef CONFIG_BITBANGMII/* * Read a MII PHY register. * * Returns: *   0 on success */int miiphy_read(unsigned char  addr,		unsigned char  reg,		unsigned short *value){	tsec_t *regs;	unsigned short rv;	regs = (tsec_t *)(TSEC_BASE_ADDR);	rv = (unsigned short)read_phy_reg(regs, addr, reg);	*value = rv;	return 0;}/* * Write a MII PHY register. * * Returns: *   0 on success */int miiphy_write(unsigned char  addr,		 unsigned char  reg,		 unsigned short value){	tsec_t *regs;	regs = (tsec_t *)(TSEC_BASE_ADDR);	write_phy_reg(regs, addr, reg, value);	return 0;}#endif /* CONFIG_BITBANGMII */#endif /* CONFIG_TSEC_ENET */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -