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

📄 plb2800_eth.c

📁 F:worksip2440a board可启动u-boot-like.tar.gz F:worksip2440a board可启动u-boot-like.tar.gz
💻 C
字号:
/* * PLB2800 internal switch ethernet driver. * * (C) Copyright 2003 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. * * 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>#if (CONFIG_COMMANDS & CFG_CMD_NET) && defined(CONFIG_NET_MULTI) \	&& defined(CONFIG_PLB2800_ETHER)#include <malloc.h>#include <net.h>#include <asm/addrspace.h>#define NUM_RX_DESC	PKTBUFSRX#define TOUT_LOOP	1000000#define LONG_REF(addr) (*((volatile unsigned long*)addr))#define CMAC_CRX_CTRL	LONG_REF(0xb800c870)#define CMAC_CTX_CTRL	LONG_REF(0xb800c874)#define SYS_MAC_ADDR_0	LONG_REF(0xb800c878)#define SYS_MAC_ADDR_1	LONG_REF(0xb800c87c)#define MIPS_H_MASK	LONG_REF(0xB800C810)#define MA_LEARN	LONG_REF(0xb8008004)#define DA_LOOKUP	LONG_REF(0xb8008008)#define CMAC_CRX_CTRL_PD	0x00000001#define CMAC_CRX_CTRL_CG	0x00000002#define CMAC_CRX_CTRL_PL_SHIFT	2#define CMAC_CRIT		0x0#define CMAC_NON_CRIT		0x1#define MBOX_STAT_ID_SHF	28#define MBOX_STAT_CP		0x80000000#define MBOX_STAT_MB		0x00000001#define EN_MA_LEARN		0x02000000#define EN_DA_LKUP		0x01000000#define MA_DEST_SHF		11#define DA_DEST_SHF		11#define DA_STATE_SHF		19#define TSTAMP_MS		0x00000000#define SW_H_MBOX4_MASK		0x08000000#define SW_H_MBOX3_MASK		0x04000000#define SW_H_MBOX2_MASK		0x02000000#define SW_H_MBOX1_MASK		0x01000000typedef volatile struct {  unsigned int stat;  unsigned int cmd;  unsigned int cnt;  unsigned int adr;} mailbox_t;#define MBOX_REG(mb) ((mailbox_t*)(0xb800c830+(mb<<4)))typedef volatile struct {  unsigned int word0;  unsigned int word1;  unsigned int word2;} mbhdr_t;#define MBOX_MEM(mb) ((void*)(0xb800a000+((3-mb)<<11)))static int plb2800_eth_init(struct eth_device *dev, bd_t * bis);static int plb2800_eth_send(struct eth_device *dev, volatile void *packet,						  int length);static int plb2800_eth_recv(struct eth_device *dev);static void plb2800_eth_halt(struct eth_device *dev);static void plb2800_set_mac_addr(struct eth_device *dev, unsigned char * addr);static unsigned char * plb2800_get_mac_addr(void);static int rx_new;static int mac_addr_set = 0;int plb2800_eth_initialize(bd_t * bis){	struct eth_device *dev;	ulong temp;#ifdef DEBUG	printf("Entered plb2800_eth_initialize()\n");#endif	if (!(dev = (struct eth_device *) malloc (sizeof *dev)))	{		printf("Failed to allocate memory\n");		return 0;	}	memset(dev, 0, sizeof(*dev));	sprintf(dev->name, "PLB2800 Switch");	dev->init = plb2800_eth_init;	dev->halt = plb2800_eth_halt;	dev->send = plb2800_eth_send;	dev->recv = plb2800_eth_recv;	eth_register(dev);	/* bug fix */	*(ulong *)0xb800e800 = 0x838;	/* Set MBOX ownership */	temp = CMAC_CRIT << MBOX_STAT_ID_SHF;	MBOX_REG(0)->stat = temp;	MBOX_REG(1)->stat = temp;	temp = CMAC_NON_CRIT << MBOX_STAT_ID_SHF;	MBOX_REG(2)->stat = temp;	MBOX_REG(3)->stat = temp;	plb2800_set_mac_addr(dev, plb2800_get_mac_addr());	/* Disable all Mbox interrupt */	temp = MIPS_H_MASK;	temp &= ~ (SW_H_MBOX1_MASK | SW_H_MBOX2_MASK | SW_H_MBOX3_MASK | SW_H_MBOX4_MASK) ;	MIPS_H_MASK = temp;#ifdef DEBUG	printf("Leaving plb2800_eth_initialize()\n");#endif	return 1;}static int plb2800_eth_init(struct eth_device *dev, bd_t * bis){#ifdef DEBUG	printf("Entering plb2800_eth_init()\n");#endif	plb2800_set_mac_addr(dev, dev->enetaddr);	rx_new = 0;#ifdef DEBUG	printf("Leaving plb2800_eth_init()\n");#endif	return 0;}static int plb2800_eth_send(struct eth_device *dev, volatile void *packet,						  int length){	int                    i;	int                    res         = -1;	u32                    temp;	mailbox_t *            mb          = MBOX_REG(0);	char      *            mem         = MBOX_MEM(0);#ifdef DEBUG	printf("Entered plb2800_eth_send()\n");#endif	if (length <= 0)	{		printf ("%s: bad packet size: %d\n", dev->name, length);		goto Done;	}	if (length < 64)	{		length = 64;	}	temp = CMAC_CRX_CTRL_CG | ((length + 4) << CMAC_CRX_CTRL_PL_SHIFT);#ifdef DEBUG	printf("0 mb->stat = 0x%x\n",  mb->stat);#endif	for(i = 0; mb->stat & (MBOX_STAT_CP | MBOX_STAT_MB); i++)	{		if (i >= TOUT_LOOP)		{			printf("%s: tx buffer not ready\n", dev->name);			printf("1 mb->stat = 0x%x\n",  mb->stat);			goto Done;		}	}		/* For some strange reason, memcpy doesn't work, here!		 */	do	{		int words = (length >> 2) + 1;		unsigned int* dst = (unsigned int*)(mem);		unsigned int* src = (unsigned int*)(packet);		for (i = 0; i < words; i++)		{			*dst = *src;			dst++;			src++;		};	} while(0);	CMAC_CRX_CTRL = temp;	mb->cmd = MBOX_STAT_CP;#ifdef DEBUG	printf("2 mb->stat = 0x%x\n",  mb->stat);#endif	res = length;Done:#ifdef DEBUG	printf("Leaving plb2800_eth_send()\n");#endif	return res;}static int plb2800_eth_recv(struct eth_device *dev){	int                    length  = 0;	mailbox_t            * mbox    = MBOX_REG(3);	unsigned char        * hdr     = MBOX_MEM(3);	unsigned int           stat;#ifdef DEBUG	printf("Entered plb2800_eth_recv()\n");#endif	for (;;)	{		stat = mbox->stat;		if (!(stat & MBOX_STAT_CP))		{			break;		}		length = ((*(hdr + 6) & 0x3f) << 8) + *(hdr + 7);		memcpy((void *)NetRxPackets[rx_new], hdr + 12, length);		stat &= ~MBOX_STAT_CP;		mbox->stat = stat;#ifdef DEBUG		{			int i;			for (i=0;i<length - 4;i++)			{				if (i % 16 == 0) printf("\n%04x: ", i);				printf("%02X ", NetRxPackets[rx_new][i]);			}			printf("\n");		}#endif		if (length)		{#ifdef DEBUG			printf("Received %d bytes\n", length);#endif			NetReceive((void*)(NetRxPackets[rx_new]),			            length - 4);		}		else		{#if 1			printf("Zero length!!!\n");#endif		}		rx_new = (rx_new + 1) % NUM_RX_DESC;	}#ifdef DEBUG	printf("Leaving plb2800_eth_recv()\n");#endif	return length;}static void plb2800_eth_halt(struct eth_device *dev){#ifdef DEBUG	printf("Entered plb2800_eth_halt()\n");#endif#ifdef DEBUG	printf("Leaving plb2800_eth_halt()\n");#endif}static void plb2800_set_mac_addr(struct eth_device *dev, unsigned char * addr){	char packet[60];	ulong temp;	int ix;	if (mac_addr_set ||	    NULL == addr || memcmp(addr, "\0\0\0\0\0\0", 6) == 0)	{		return;	}	/* send one packet through CPU port	 * in order to learn system MAC address	 */	/* Set DA_LOOKUP register */	temp = EN_MA_LEARN | (0 << DA_STATE_SHF) | (63 << DA_DEST_SHF);	DA_LOOKUP = temp;	/* Set MA_LEARN register */	temp = 50 << MA_DEST_SHF; 	/* static entry */	MA_LEARN = temp;	/* set destination address */	for (ix=0;ix<6;ix++)		packet[ix] = 0xff;	/* set source address = system MAC address */	for (ix=0;ix<6;ix++)		packet[6+ix] = addr[ix];	/* set type field */	packet[12]=0xaa;	packet[13]=0x55;	/* set data field */	for(ix=14;ix<60;ix++)		packet[ix] = 0x00;#ifdef DEBUG	for (ix=0;ix<6;ix++)		printf("mac_addr[%d]=%02X\n", ix, (unsigned char)packet[6+ix]);#endif	/* set one packet */	plb2800_eth_send(dev, packet, sizeof(packet));	/* delay for a while */	for(ix=0;ix<65535;ix++)		temp = ~temp;	/* Set CMAC_CTX_CTRL register */	temp = TSTAMP_MS;	/* no autocast */	CMAC_CTX_CTRL = temp;	/* Set DA_LOOKUP register */	temp = EN_DA_LKUP;	DA_LOOKUP = temp;	mac_addr_set = 1;}static unsigned char * plb2800_get_mac_addr(void){	static unsigned char addr[6];	char *tmp, *end;	int i;	tmp = getenv ("ethaddr");	if (NULL == tmp) return NULL;	for (i=0; i<6; i++) {		addr[i] = tmp ? simple_strtoul(tmp, &end, 16) : 0;		if (tmp)			tmp = (*end) ? end+1 : end;	}	return addr;}#endif /* CONFIG_PLB2800_ETHER */

⌨️ 快捷键说明

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