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

📄 ether-smc91x.c

📁 pxa270 NOR FLASH驱动代码
💻 C
📖 第 1 页 / 共 2 页
字号:
// ported by hzh#include <stdio.h>#include <string.h>#include "utils.h"typedef	unsigned long u32;typedef	unsigned short u16;typedef	unsigned char u8;#define	inline	__inline#define	EINVAL	22#define	msleep			mdelay#define readb(a)	(*(volatile u8*)(a))#define readw(a)	(*(volatile u16*)(a))#define readl(a)	(*(volatile u32*)(a))#define writeb(v,a)	(*(volatile u8*)(a)=(v))#define writew(v,a)	(*(volatile u16*)(a)=(v))#define	writel(v,a)	(*(volatile u32*)(a)=(v))#define insb(a,p,l)	({ 			\	int __i;				\	for (__i=0; __i<(l); __i++) 		\		((u8*)(p))[__i]= readb((a)); 	\})#define insw(a,p,l)	({ 			\	int __i;				\	for (__i=0; __i<(l); __i++) 		\		((u16*)(p))[__i] = readw((a)); 	\})#define insl(a,p,l)	{ 			\	int __i;				\	for (__i=0; __i<(l); __i++) 		\		((u32*)(p))[__i] = readl((a)); 	\}#define outsb(a,p,l)	({ 			\	int __i;				\	for (__i=0; __i<(l); __i++)	 	\		writeb(((u8*)(p))[__i],(a)); 	\})#define outsw(a,p,l)	({ 			\	int __i;				\	for (__i=0; __i<(l); __i++) 		\		writew(((u16*)(p))[__i],(a)); 	\})#define outsl(a,p,l)	{	 		\	int __i;				\	for (__i=0; __i<(l); __i++)	 	\		writel(((u32*)(p))[__i],(a));	\}#define	SMC_BASE		0x10000300u8 hwaddress[6];typedef struct {	int (*init)(u32 ioaddr);	int (*rcv)(u8 *buf, int size);	int (*snd)(u8 *buf, int size);	int (*set_ethaddr)(u8 dev_addr[6]);	int (*get_ethaddr)(u8 dev_addr[6]);	int base;} ether_driver_t;//--------------------------------------------------------#define	MAINSTONE#define SMC_DEBUG	0#include "smc91x.h"/*************************************************************************** * defines */#if SMC_DEBUG#	define DBG( x, args... )	if ( dbg>=x ) printf( args )#else#	define DBG( x, args... ) ;#endif/*------------------------------------------------------------------------ . . The internal workings of the driver.  If you are changing anything . here with the SMC stuff, you should have the datasheet and know . what you are doing. . -------------------------------------------------------------------------*/#define CARDNAME "LAN91x"// Use power-down feature of the chip#define POWER_DOWN		1/* . Wait time for memory to be free.  This probably shouldn't be . tuned that much, as waiting for this means nothing else happens . in the system*/#define MEMORY_WAIT_TIME	16/* . This selects whether TX packets are sent one by one to the SMC91x internal . memory ans throttled until transmission completes.  This may prevent . RX overruns a litle by keeping much of the memory free for RX packets . but to the expense of reduced TX throughput and increased IRQ overhead. . Note this is not a cure for a too slow data bus or too high IRQ latency. */#define THROTTLE_TX_PKTS	0/********************************************************************** * Local  */static int smc_chip_base = 0;static int dbg = 3;#if SMC_DEBUGstatic void HEXDUMP(u8 *buf, int length){	int i;	int remainder;	int lines;	lines = length / 16;	remainder = length % 16;	for (i = 0; i < lines ; i ++) {		int cur;		for (cur = 0; cur < 8; cur++) {			u8 a, b;			a = *buf++;			b = *buf++;			printf("%02x%02x ", a, b);		}		printf("\n");	}	for (i = 0; i < remainder/2 ; i++) {		u8 a, b;		a = *buf++;		b = *buf++;		printf("%02x%02x ", a, b );	}	printf("\n");}#else#define HEXDUMP(x...)  do { } while(0)#endif/* this enables an interrupt in the interrupt mask register */#define SMC_ENABLE_INT(x) do {						\	unsigned long flags;						\	unsigned char mask;						\	mask = SMC_GET_INT_MASK();					\	mask |= (x);							\	SMC_SET_INT_MASK(mask);						\} while (0)/* this disables an interrupt from the interrupt mask register */#define SMC_DISABLE_INT(x) do {						\	unsigned long flags;						\	unsigned char mask;						\	mask = SMC_GET_INT_MASK();					\	mask &= ~(x);							\	SMC_SET_INT_MASK(mask);						\} while (0)/* wait while MMU is busy */#define SMC_WAIT_MMU_BUSY() do {					\	if (SMC_GET_MMU_CMD() & MC_BUSY) {				\		long timeout = 0x1000;					\		while (SMC_GET_MMU_CMD() & MC_BUSY) {			\			timeout --;					\			if (!timeout) {					\				printf("%s: timeout %s line %d\n",	\					CARDNAME, __FILE__, __LINE__);	\				break;					\			}						\		}							\	}								\} while (0)/********************************************************************** * Core routines *//* this does a soft reset on the device */static void smc_reset(u32 ioaddr){	DBG(2, "%s: %s\n", CARDNAME, __FUNCTION__);	/* This resets the registers mostly to defaults, but doesn't	   affect EEPROM.  That seems unnecessary */	SMC_SELECT_BANK( 0 );	SMC_SET_RCR( RCR_SOFTRST );	/* Setup the Configuration Register */	/* This is necessary because the CONFIG_REG is not affected */	/* by a soft reset */	SMC_SELECT_BANK( 1 );	SMC_SET_CONFIG( CONFIG_DEFAULT );	/* Setup for fast accesses if requested */	/* If the card/system can't handle it then there will */	/* be no recovery except for a hard reset or power cycle */	SMC_SET_CONFIG( SMC_GET_CONFIG() | CONFIG_NO_WAIT );#ifdef POWER_DOWN	/* Release from possible power-down state */	/* Configuration register is not affected by Soft Reset */	SMC_SELECT_BANK( 1 );	SMC_SET_CONFIG( SMC_GET_CONFIG() | CONFIG_EPH_POWER_EN );#endif	/* this should pause enough for the chip to be happy */	msleep(1);	/* Disable transmit and receive functionality */	SMC_SELECT_BANK( 0 );	SMC_SET_RCR( RCR_CLEAR );	SMC_SET_TCR( TCR_CLEAR );	/* set the control register to automatically	   release successfully transmitted packets, to make the best	   use out of our limited memory */	SMC_SELECT_BANK( 1 );#if ! THROTTLE_TX_PKTS	SMC_SET_CTL( SMC_GET_CTL() | CTL_AUTO_RELEASE );#else	SMC_SET_CTL( SMC_GET_CTL() & ~CTL_AUTO_RELEASE );#endif	/* Disable all interrupts */	SMC_SELECT_BANK( 2 );	SMC_SET_INT_MASK( 0 );	/* Reset the MMU */	SMC_SET_MMU_CMD( MC_RESET );	SMC_WAIT_MMU_BUSY();}/* Enable Interrupts, Receive, and Transmit */static void smc_enable(u32 ioaddr){	int mask;	DBG(2, "%s: %s\n", CARDNAME, __FUNCTION__);	/* see the header file for options in TCR/RCR DEFAULT*/	SMC_SELECT_BANK( 0 );	SMC_SET_TCR( TCR_DEFAULT);	SMC_SET_RCR( RCR_DEFAULT);	/* now, enable interrupts */	mask = IM_EPH_INT|IM_RX_OVRN_INT|IM_RCV_INT;	SMC_SELECT_BANK( 2 );	SMC_SET_INT_MASK( mask );}/* this puts the device in an inactive state */static void smc_shutdown(unsigned long ioaddr){	DBG(2, "%s: %s\n", CARDNAME, __FUNCTION__);	/* no more interrupts for me */	SMC_SELECT_BANK( 2 );	SMC_SET_INT_MASK( 0 );	/* and tell the card to stay away from that nasty outside world */	SMC_SELECT_BANK( 0 );	SMC_SET_RCR( RCR_CLEAR );	SMC_SET_TCR( TCR_CLEAR );#ifdef POWER_DOWN	/* finally, shut the chip down */	SMC_SELECT_BANK( 1 );	SMC_SET_CONFIG( SMC_GET_CONFIG() & ~CONFIG_EPH_POWER_EN );#endif}/* This is the procedure to handle the receipt of a packet. */static inline int smc_rcv(u32 ioaddr, u8 *data, u16 size){	unsigned int packet_number, status, packet_len;	int ret = 0;	DBG(3, "%s: %s\n", CARDNAME, __FUNCTION__);	packet_number = SMC_GET_RXFIFO();	if (packet_number & RXFIFO_REMPTY) {		DBG(1, "%s: smc_rcv with nothing on FIFO.\n", CARDNAME);		return 0;	}	/* read from start of packet */	SMC_SET_PTR( PTR_READ | PTR_RCV | PTR_AUTOINC );	/* First two words are status and packet length */	SMC_GET_PKT_HDR(status, packet_len);	packet_len &= 0x07ff;  /* mask off top bits */	DBG(2, "%s: RX PNR 0x%x STATUS 0x%04x LENGTH 0x%04x (%d)\n",		CARDNAME, packet_number, status,		packet_len, packet_len);	if (status & RS_ERRORS) {		printf(" smc_rcv : RCV error\n");		ret = -1;		goto done;	}	if (status & RS_ODDFRAME)		packet_len ++;	packet_len -= 6;	SMC_PULL_DATA(data, packet_len);	HEXDUMP(data, packet_len);	ret = packet_len;done:	SMC_WAIT_MMU_BUSY();	SMC_SET_MMU_CMD( MC_RELEASE );	return ret;}/* * This is called to actually send a packet to the chip. * Returns non-zero when successful. */static void smc_hardware_send_packet( u32 ioaddr , u8 *data , int size){	unsigned int packet_no, len;	unsigned char *buf;	DBG(3, "%s: %s\n", CARDNAME, __FUNCTION__);	packet_no = SMC_GET_AR();	if (packet_no & AR_FAILED) {		printf("%s: Memory allocation failed.\n", CARDNAME);		return;	}	/* point to the beginning of the packet */	SMC_SET_PN( packet_no );	SMC_SET_PTR( PTR_AUTOINC );	buf = data;	len = size;	DBG(2, "%s: TX PNR 0x%x lENGTH 0x%04x (%d) BUF 0x%p\n",		CARDNAME, packet_no, len, len, buf);	HEXDUMP(buf, len);	/*	 * Send the packet length ( +6 for status words, length, and ctl.	 * The card will pad to 64 bytes with zeroes if packet is too small.	 */	SMC_PUT_PKT_HDR(0, len + 6);	/* send the actual data */	SMC_PUSH_DATA(buf, len & ~1);	/* Send final ctl word with the last byte if there is one */	SMC_outw( ((len & 1) ? (0x2000 | buf[len-1]) : 0), ioaddr, DATA_REG );	/* and let the chipset deal with it */	SMC_SET_MMU_CMD( MC_ENQUEUE );}/* . Since I am not sure if I will have enough room in the chip's ram . to store the packet, I call this routine which either sends it . now, or set the card to generates an interrupt when ready . for the packet. */static intsmc_send( u32 ioaddr, u8 *data, int size ){	unsigned int numPages, poll_count, status, saved_bank;	DBG(3, "%s: %s\n", CARDNAME, __FUNCTION__);	/*	** The MMU wants the number of pages to be the number of 256 bytes	** 'pages', minus 1 ( since a packet can't ever have 0 pages :) )	**	** The 91C111 ignores the size bits, but the code is left intact	** for backwards and future compatibility.	**	** Pkt size for allocating is data length +6 (for additional status	** words, length and ctl!)	**	** If odd size then last byte is included in ctl word.	*/	numPages = ((size & ~1) + (6 - 1)) >> 8;	if (numPages > 7) {		printf("%s: Far too big packet error.\n", CARDNAME);		return 0;	}	/* now, try to allocate the memory */	saved_bank = SMC_CURRENT_BANK();	SMC_SELECT_BANK( 2 );	SMC_SET_MMU_CMD( MC_ALLOC | numPages );	/*	 * Poll the chip for a short amount of time in case the	 * allocation succeeds quickly.	 */	poll_count = MEMORY_WAIT_TIME;	do {		status = SMC_GET_INT();		if (status & IM_ALLOC_INT) {			SMC_ACK_INT( IM_ALLOC_INT );  			break;		}   	} while (--poll_count); 	if (!poll_count) {		printf("smc_send: memory allocation time out.\n");		return -1; 	}	SMC_ENABLE_INT(IM_TX_INT | IM_TX_EMPTY_INT);	smc_hardware_send_packet( ioaddr, data, size );	/* waiting for transmit done */	while ( !((status = SMC_GET_INT()) & (IM_TX_INT|IM_TX_EMPTY_INT)));	if (status & IM_TX_INT) 		SMC_ACK_INT(IM_TX_INT);	if (status & IM_TX_EMPTY_INT) 		SMC_ACK_INT(IM_TX_EMPTY_INT);	SMC_SELECT_BANK( saved_bank );	return 0;}/********************************************************************** * PHY Control and Configuration *//*------------------------------------------------------------ . Debugging function for viewing MII Management serial bitstream .-------------------------------------------------------------*/#if SMC_DEBUG static voidPRINT_MII_STREAM(u8 *bits, int size){	int i;	printf("BIT#:");	for (i = 0; i < size; ++i)		printf("%d", i%10);	printf("\nMDOE:");	for (i = 0; i < size; ++i) {		if (bits[i] & MII_MDOE)			printf("1");		else			printf("0");	}	printf("\nMDO :");	for (i = 0; i < size; ++i) {		if (bits[i] & MII_MDO)			printf("1");		else			printf("0");	}	printf("\nMDI :");	for (i = 0; i < size; ++i) {		if (bits[i] & MII_MDI)			printf("1");		else			printf("0");	}	printf("\n");}#else#define PRINT_MII_STREAM(x...)#endif/*------------------------------------------------------------ . Reads a register from the MII Management serial interface .-------------------------------------------------------------*/static intsmc_read_phy_register(unsigned long ioaddr, int phyaddr, int phyreg){	int oldBank;	int i, mask, mii_reg;	u8 bits[64];	int input_idx, phydata;	int clk_idx = 0;	// 32 consecutive ones on MDO to establish sync	for (i = 0; i < 32; ++i)		bits[clk_idx++] = MII_MDOE | MII_MDO;	// Start code <01>	bits[clk_idx++] = MII_MDOE;	bits[clk_idx++] = MII_MDOE | MII_MDO;	// Read command <10>	bits[clk_idx++] = MII_MDOE | MII_MDO;	bits[clk_idx++] = MII_MDOE;	// Output the PHY address, msb first	mask = 0x10;	for (i = 0; i < 5; ++i) {		if (phyaddr & mask)			bits[clk_idx++] = MII_MDOE | MII_MDO;		else			bits[clk_idx++] = MII_MDOE;		// Shift to next lowest bit		mask >>= 1;	}	// Output the phy register number, msb first	mask = 0x10;	for (i = 0; i < 5; ++i) {		if (phyreg & mask)			bits[clk_idx++] = MII_MDOE | MII_MDO;		else			bits[clk_idx++] = MII_MDOE;		// Shift to next lowest bit		mask >>= 1;	}	// Tristate and turnaround (2 bit times)	bits[clk_idx++] = 0;	//bits[clk_idx++] = 0;	// Input starts at this bit time	input_idx = clk_idx;	// Will input 16 bits	for (i = 0; i < 16; ++i)		bits[clk_idx++] = 0;	// Final clock bit	bits[clk_idx++] = 0;	// Save the current bank	oldBank = SMC_CURRENT_BANK();	// Select bank 3	SMC_SELECT_BANK( 3 );	// Get the current MII register value	mii_reg = SMC_GET_MII();	// Turn off all MII Interface bits	mii_reg &= ~(MII_MDOE|MII_MCLK|MII_MDI|MII_MDO);	// Clock all 64 cycles	for (i = 0; i < sizeof bits; ++i) {		// Clock Low - output data		SMC_SET_MII( mii_reg | bits[i] );		msleep(1);		// Clock Hi - input data		SMC_SET_MII( mii_reg | bits[i] | MII_MCLK );		msleep(1);		bits[i] |= SMC_GET_MII() & MII_MDI;

⌨️ 快捷键说明

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