123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391 |
- /*
- * 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>
- #include <malloc.h>
- #include <net.h>
- #include <netdev.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 0x01000000
- typedef 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 -1;
- }
- 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 0;
- }
- 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;
- }
|