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

📄 ethernet_smsc91c111.c

📁 Intrisyc 公司的PXA255-bootloader,源码易懂
💻 C
📖 第 1 页 / 共 3 页
字号:
/***************************************************************************** * Copyright (c) 2002, Intrinsyc Software Inc * * FILE: ethernet_smsc91c111.c * * PURPOSE: * 	The purpose of this driver is to be the Ethernet driver for this * 	bootloader. * * REQUIRES: * 	24LC64 EEPROM Driver * * CREATED BY: * 	Brad Remedios * * SPECIAL NOTES: * 	The original Hardware that this was being used / tested on had a small * 	defect in that only 32-bit accesses would work.  Since then, that * 	defect has been fixed.  The appropriate way to access the SMSC * 	registers is the REG8/16/32. * * 	The hardware that this was initially used and tested on was slightly * 	broken.  All accesses to the SMSC have to be 32-bit aligned, even * 	though 8 and 16 bit accesses are totally valid. * * 	Additionally, the autoincrement functionality of the SMSC LAN91C111 * 	was seen to work correctly only in the 32-bit accesses case.  If * 	the auto-increment is fixed, immediate performance increases can be * 	relized by modifing read_mmu_data and write_mmu_data as the * 	performance will increase in the unaligned cases (no performance * 	change for 32-bit aligned accesses). ****************************************************************************/#include <string.h>#include <ethernet_smsc91c111.h>#include <ethernet.h>#include <arp.h>#include <timer.h>#include <debug.h>#ifdef TAGGED_EEPROM#include <eeprom.h>#include <eeprom_24lc64.h>#else#warning You are using obsolete EEPROM code#include <eeprom_24lc64.h>#endif#define ERROR(x...) itc_printf("ERROR: "x)#if DEBUG_LEVEL >= 3// Print the Ethernet registers for debuggingstatic voidprint_registers(void){        int bank,reg;        u16 _temp;        itc_printf("91C111 registers:\r\n");        for (bank=0; bank <= 3; ++bank)        {            SETUP_BANK(bank);            itc_printf("%x-\r\n", bank);            for (reg=0; reg < 0xe; reg += 2)            {                READ_REG16(reg, _temp);                itc_printf("%x: %x\r\n", reg, _temp);            }            itc_printf("\r\n");        }}// Print the phy registers for debuggingstatic voidprint_phy_registers(void){        int reg;        u16 _temp;        itc_printf("PHY registers:\r\n");        for (reg=0; reg < 5; ++reg)        {            read_phy_register (reg, &_temp);            itc_printf("%x: %x\r\n", reg, _temp);        }        itc_printf("\r\n");}#endif/*  * These are debugging calls and aren't needed in normal operation *static int print_data (unsigned char *data, unsigned short size); */int init_ethernet(u16 *macaddr){	int retval;	int counter;	unsigned short _temp;	unsigned short rpc_mode = 0;	unsigned short phy_data;	unsigned short phy_stat;	/*	 * Can we find a SMSC 91C111?	 */	retval = probe_smsc91c111 ((unsigned int *)SMSC91C111_WINDOW_ADDR);#if DEBUG_LEVEL >= 4        print_registers();        print_phy_registers();#endif	if (retval == 0)	{		ERROR("No SMSC LAN91C111 was detected at %x\r\n",		      SMSC91C111_WINDOW_ADDR);		return 0;	}	/*	 * Reset the SMSC Ethernet Chip MAC.  Cases like Watchdog or Software	 * Reset could leave it in a bad state otherwise.	 */	SETUP_BANK(BANK_RCR);	WRITE_REG16(OFFSET_RCR, BIT_RCR_SOFTRST);	WRITE_REG16(OFFSET_RCR, 0);	SETUP_BANK(BANK_CNFGR);	WRITE_REG16(OFFSET_CNFGR, BIT_CNFGR_EPH_PWR_EN);	/*	 * Promiscuous Mode - This is only here for testing.	 *//*	SETUP_BANK(BANK_RCR);	READ_REG16(OFFSET_RCR, _temp);	_temp |= BIT_RCR_PRMS;	WRITE_REG16(OFFSET_RCR, _temp);*/		/*	 * Turn off the transmitter and set the TCR to a known state	 */	SETUP_BANK(BANK_TCR);	WRITE_REG16(OFFSET_TCR, 0);		/*	 * Automatically deallocate memory for TX packets so we don't have to	 * NOTE: if this is enabled, then the 91C111 doesn't generate	 * BIT_ISR_TX_INT, which is undocumented behaviour and messes up	 * the TX completion check in tx_packet_ethernet.	 *//*	SETUP_BANK(BANK_CR);	READ_REG16(OFFSET_CR, _temp);	_temp |= BIT_CR_AUTO_RELEASE;	WRITE_REG16(OFFSET_CR, _temp);*/	/*	 * Busy wait for MMU to become free, then Reset the MMU.	 */        flush_ethernet();	/*	 * Disable All Interrupts.  IBoot has no knowledge of them	 * so we can't use them	 */	SETUP_BANK(BANK_IMR);	WRITE_REG16(OFFSET_IMR, 0);	/*	 * We set up the Receiver to Strip CRC's off but DO NOT turn on	 * the Receive Enable.  Because we poll the card, the SMSC's Memory	 * will fill up quickly if we turn on RX Enable (only can store 4	 * packets and will read broadcast.)	 * Enable collision abort so we don't get half packets.	 */	SETUP_BANK(BANK_RCR);	REG16(OFFSET_RCR) |= (BIT_RCR_STRIP_CRC | BIT_RCR_ABORT_ENB);	/*	 * Enable TXEN so that we may send out packets	 */	SETUP_BANK(BANK_TCR);	READ_REG16(OFFSET_TCR, _temp);	_temp |= BIT_TCR_TXENA | BIT_TCR_PAD_EN;	WRITE_REG16(OFFSET_TCR, _temp);		/*	 * Reset the PHY and wait for it to complete.	 */	SETUP_BANK(BANK_MI);	write_phy_register (PHY_CR, PHY_CR_RST);		counter = PHY_RESET_WAIT;	do	{		read_phy_register (PHY_CR, &phy_data);	} while ((phy_data & PHY_CR_RST) && --counter);	if (!counter)	{		ERROR ("PHY Failed to Reset\r\n");	}#ifdef SECOND_ETHERNET	if ((retval = read_mac_ethernet (macaddr,1)) == 0)#else	if ((retval = read_mac_ethernet (macaddr,0)) == 0)#endif	{		ERROR("Unable to read MAC address\r\n");		return retval;	}	/*	 * Sometimes (~1 in 6 times) the PHY appears to ignore the first	 * write after a reset, so do a sacrificial write by writing the	 * default values.	 */	write_phy_register (PHY_CR,	                    PHY_CR_SPEED | PHY_CR_ANEG_EN | PHY_CR_MII_DIS);	/* enable auto neg */	SETUP_BANK(BANK_RPCR);	WRITE_REG16(OFFSET_RPCR,  		(RPCR_TX_RX_LED << 5) | (RPCR_LINK_LED << 2) | BIT_RPCR_ANEG);	/* is auto neg supported? */	read_phy_register( PHY_SR, &phy_stat);	if( phy_stat & PHY_SR_CAP_ANEG)	{		int autoneg_ok = 0;		u16 ad_caps = PHY_ANAR_CSMA;		u16 phy_int;		u16 phy_aneg;		/* Gather the capabilities we want to advertise */		if( phy_stat & PHY_SR_CAP_T4)			ad_caps |= PHY_ANAR_T4;		if( phy_stat & PHY_SR_CAP_TXF)			ad_caps |= PHY_ANAR_TX_FDX;		if( phy_stat & PHY_SR_CAP_TXH)			ad_caps |= PHY_ANAR_TX_HDX;		if( phy_stat & PHY_SR_CAP_TF)			ad_caps |= PHY_ANAR_10_FDX;		if( phy_stat & PHY_SR_CAP_TH)			ad_caps |= PHY_ANAR_10_HDX;		DEBUG_2 ("PHY phy stat %x\r\n", phy_stat);		DEBUG_2 ("PHY ad  caps %x\r\n", ad_caps);		/* advertise our capabilities */		write_phy_register( PHY_ANAR, ad_caps);		/* reset the auto-negotiation sequence */		write_phy_register (PHY_CR, PHY_CR_ANEG_EN | PHY_CR_ANEG_RST);		/* wait for auto neg ack or timeout */		counter = MAX_ANEG_WAIT;		do		{			udelay(200);			read_phy_register (PHY_ANAR, &phy_aneg);		} while ( ((phy_aneg & PHY_ANAR_ACK)==0) && --counter);		if (!counter)		{			itc_printf ("PHY auto-negotiation timed out\r\n");		}		else		{			DEBUG_2 ("PHY auto-negotiation ack'd\r\n");			autoneg_ok = 1;		}#if DEBUG_LEVEL >= 3		read_phy_register (PHY_SR, &phy_stat);		read_phy_register (PHY_ANAR, &phy_aneg);		itc_printf ("phy_stat  %x\r\n", phy_stat);		itc_printf ("phy_aneg  %x\r\n", phy_aneg);#endif		read_phy_register (PHY_SR, &phy_stat);		if( phy_stat & PHY_SR_REM_FLT)		{			itc_printf ("PHY auto-negotiation remote fault detected.\r\n");		}		if( autoneg_ok)		{			/* wait a bit for status output to be updated */			delay(1);			read_phy_register (PHY_INT, &phy_int);			DEBUG_2 ("PHY phy_int %x\r\n", phy_int);			itc_printf ("Auto-negotiation result: ");			if( phy_int & PHY_INT_SPDDET)			{				itc_printf ("100BaseT");				rpc_mode |= BIT_RPCR_SPEED;			}			else			{				itc_printf ("10BaseT");			}			if( phy_int & PHY_INT_DPLXDET)			{				itc_printf (" Full-Duplex");				rpc_mode |= BIT_RPCR_DPLX;				SETUP_BANK(BANK_TCR);				READ_REG16(OFFSET_TCR, _temp);				_temp |= BIT_TCR_SWFDUP;				WRITE_REG16(OFFSET_TCR, _temp);			}				else			{				itc_printf (" Half-Duplex");			}			itc_printf ("\r\n");		}		else		{			itc_printf ("Auto-negotiation result: failed (using 10BaseT Half-Duplex)\r\n");		}	}	/*	 * Setup MAC Address in SMSC LAN91C111	 */  	SETUP_BANK(BANK_IAR);	WRITE_REG16(OFFSET_IAR01, macaddr[0]);	WRITE_REG16(OFFSET_IAR23, macaddr[1]);	WRITE_REG16(OFFSET_IAR45, macaddr[2]);	/*	 * Setup Transmit Protocol Options:	 * 	LEDA = TX/RX, LEDB = 100MBit Link	 */	SETUP_BANK(BANK_RPCR);        _temp = ((RPCR_TX_RX_LED << 5) | (RPCR_LINK_LED << 2) | rpc_mode);	WRITE_REG16(OFFSET_RPCR, _temp);	/*	 * It takes upwards of a second for the chip to detect whether a link	 * is available.  Problems ensue if you try to use the link	 * before it's detected, so we'd better wait.	 */	counter = MAX_LINK_WAIT;	do	{		udelay(200);		read_phy_register (PHY_SR, &_temp);	} while ( ((_temp & PHY_SR_LINK)==0) && --counter);		if (_temp & PHY_SR_LINK)	{		itc_printf ("Ethernet Link Detected\r\n");	}	else	{		itc_printf ("No Ethernet Link Detected\r\n");	}#if DEBUG_LEVEL >= 3        print_registers();        print_phy_registers();#endif	return 1;}  // End of init_ethernetint tx_packet_ethernet(u8 *data, u16 size){	unsigned char packet_number;	unsigned int _temp;	unsigned char _temp8;	int retry=0,counter;        DEBUG_4 ("Tx...");retransmit:	/*	 * Both RXEN and TXEN should be on, I will double check though	 */	SETUP_BANK(BANK_TCR);	if (!(REG16(OFFSET_TCR) & BIT_TCR_TXENA))	{		REG16(OFFSET_TCR) |= BIT_TCR_TXENA;	}	SETUP_BANK(BANK_RCR);	if (!(REG16(OFFSET_RCR) & BIT_RCR_RXEN))	{                //ERROR ("RXEN was off\r\n");		REG16(OFFSET_RCR) |= BIT_RCR_RXEN;	}#if DEBUG_LEVEL >= 5        SETUP_BANK(BANK_ISR);        READ_REG8(OFFSET_ISR, _temp8);        if (_temp8 & BIT_ISR_TX_INT)        {                ERROR("Hey--TX_INT is set! %x\r\n", _temp8);                // Clear the TX interrupt bit                //SETUP_BANK (BANK_ISR);                //WRITE_REG8 (OFFSET_IRQAR, BIT_ISR_TX_INT);        }#endif	/*	 * Try to Allocate Memory for a packet in the MMU.  If this fails	 * we cannot continue.  	 *	 * If this fails we most likely have no more memory left.	 */	if (!allocate_tx (&packet_number))	{		ERROR("%s: Could not allocate packet for TX\r\n",				__FUNCTION__);		return 0;	}	SETUP_BANK(BANK_PNR);	WRITE_REG8(OFFSET_PNR, packet_number);	if (!write_mmu_data (packet_number, data, size))	{		ERROR("%s: Error Writing Data to MMU\r\n", __FUNCTION__);		return 0;	}	SETUP_BANK(BANK_MMUCR);	WRITE_REG16(OFFSET_MMUCR, OPCODE_MMUCR_ENQUEUE_TX);#if DEBUG_LEVEL >= 5        SETUP_BANK(BANK_ISR);        READ_REG8(OFFSET_ISR, _temp8);        if (_temp8 & BIT_ISR_TX_INT)        {		ERROR("TX_INT is already set! %x\r\n", _temp8);                // Clear the TX interrupt bit                //SETUP_BANK (BANK_ISR);                //WRITE_REG8 (OFFSET_IRQAR, BIT_ISR_TX_INT);        }#endif	/*	 * Wait for packet to be done transmitting	 * This is not possible if BIT_CR_AUTO_RELEASE is set.	 */        SETUP_BANK(BANK_ISR);        counter=MAX_ISR_COUNTER;        do        {                READ_REG8(OFFSET_ISR, _temp8);        } while	(!(_temp8 & BIT_ISR_TX_INT) && --counter);        if (!counter)        {                SETUP_BANK(BANK_EPHSR);                READ_REG16(OFFSET_EPHSR, _temp);                ERROR ("Timeout on TX\r\n");                DEBUG_2("EPHSR %x\r\n", _temp);                if (_temp & BIT_EPHSR_TXUNRUN)                {                        ERROR ("Tx Under Run Occurred\r\n");                }                DEBUG_2("ISR is %x\r\n", _temp8);                if (!(_temp & BIT_EPHSR_TX_SUC))                        ERROR ("No Tx Success\r\n");                SETUP_BANK(BANK_TCR);                READ_REG16(OFFSET_TCR, _temp);                if (!(_temp & BIT_TCR_TXENA))                {                        ERROR ("Transmit Enabled not set\r\n");                }                return 0;

⌨️ 快捷键说明

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