📄 plb2800_eth.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 + -