uboot/drivers/net/plb2800_eth.c
<<
>>
Prefs
   1/*
   2 * PLB2800 internal switch ethernet driver.
   3 *
   4 * (C) Copyright 2003
   5 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
   6 *
   7 * See file CREDITS for list of people who contributed to this
   8 * project.
   9 *
  10 * This program is free software; you can redistribute it and/or
  11 * modify it under the terms of the GNU General Public License as
  12 * published by the Free Software Foundation; either version 2 of
  13 * the License, or (at your option) any later version.
  14 *
  15 * This program is distributed in the hope that it will be useful,
  16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18 * GNU General Public License for more details.
  19 *
  20 * You should have received a copy of the GNU General Public License
  21 * along with this program; if not, write to the Free Software
  22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  23 * MA 02111-1307 USA
  24 */
  25
  26#include <common.h>
  27#include <malloc.h>
  28#include <net.h>
  29#include <netdev.h>
  30#include <asm/addrspace.h>
  31
  32
  33#define NUM_RX_DESC     PKTBUFSRX
  34#define TOUT_LOOP       1000000
  35
  36#define LONG_REF(addr) (*((volatile unsigned long*)addr))
  37
  38#define CMAC_CRX_CTRL   LONG_REF(0xb800c870)
  39#define CMAC_CTX_CTRL   LONG_REF(0xb800c874)
  40#define SYS_MAC_ADDR_0  LONG_REF(0xb800c878)
  41#define SYS_MAC_ADDR_1  LONG_REF(0xb800c87c)
  42#define MIPS_H_MASK     LONG_REF(0xB800C810)
  43
  44#define MA_LEARN        LONG_REF(0xb8008004)
  45#define DA_LOOKUP       LONG_REF(0xb8008008)
  46
  47#define CMAC_CRX_CTRL_PD        0x00000001
  48#define CMAC_CRX_CTRL_CG        0x00000002
  49#define CMAC_CRX_CTRL_PL_SHIFT  2
  50#define CMAC_CRIT               0x0
  51#define CMAC_NON_CRIT           0x1
  52#define MBOX_STAT_ID_SHF        28
  53#define MBOX_STAT_CP            0x80000000
  54#define MBOX_STAT_MB            0x00000001
  55#define EN_MA_LEARN             0x02000000
  56#define EN_DA_LKUP              0x01000000
  57#define MA_DEST_SHF             11
  58#define DA_DEST_SHF             11
  59#define DA_STATE_SHF            19
  60#define TSTAMP_MS               0x00000000
  61#define SW_H_MBOX4_MASK         0x08000000
  62#define SW_H_MBOX3_MASK         0x04000000
  63#define SW_H_MBOX2_MASK         0x02000000
  64#define SW_H_MBOX1_MASK         0x01000000
  65
  66typedef volatile struct {
  67  unsigned int stat;
  68  unsigned int cmd;
  69  unsigned int cnt;
  70  unsigned int adr;
  71} mailbox_t;
  72
  73#define MBOX_REG(mb) ((mailbox_t*)(0xb800c830+(mb<<4)))
  74
  75typedef volatile struct {
  76  unsigned int word0;
  77  unsigned int word1;
  78  unsigned int word2;
  79} mbhdr_t;
  80
  81#define MBOX_MEM(mb) ((void*)(0xb800a000+((3-mb)<<11)))
  82
  83
  84static int plb2800_eth_init(struct eth_device *dev, bd_t * bis);
  85static int plb2800_eth_send(struct eth_device *dev, volatile void *packet,
  86                                                  int length);
  87static int plb2800_eth_recv(struct eth_device *dev);
  88static void plb2800_eth_halt(struct eth_device *dev);
  89
  90static void plb2800_set_mac_addr(struct eth_device *dev, unsigned char * addr);
  91static unsigned char * plb2800_get_mac_addr(void);
  92
  93static int rx_new;
  94static int mac_addr_set = 0;
  95
  96
  97int plb2800_eth_initialize(bd_t * bis)
  98{
  99        struct eth_device *dev;
 100        ulong temp;
 101
 102#ifdef DEBUG
 103        printf("Entered plb2800_eth_initialize()\n");
 104#endif
 105
 106        if (!(dev = (struct eth_device *) malloc (sizeof *dev)))
 107        {
 108                printf("Failed to allocate memory\n");
 109                return -1;
 110        }
 111        memset(dev, 0, sizeof(*dev));
 112
 113        sprintf(dev->name, "PLB2800 Switch");
 114        dev->init = plb2800_eth_init;
 115        dev->halt = plb2800_eth_halt;
 116        dev->send = plb2800_eth_send;
 117        dev->recv = plb2800_eth_recv;
 118
 119        eth_register(dev);
 120
 121        /* bug fix */
 122        *(ulong *)0xb800e800 = 0x838;
 123
 124        /* Set MBOX ownership */
 125        temp = CMAC_CRIT << MBOX_STAT_ID_SHF;
 126        MBOX_REG(0)->stat = temp;
 127        MBOX_REG(1)->stat = temp;
 128
 129        temp = CMAC_NON_CRIT << MBOX_STAT_ID_SHF;
 130        MBOX_REG(2)->stat = temp;
 131        MBOX_REG(3)->stat = temp;
 132
 133        plb2800_set_mac_addr(dev, plb2800_get_mac_addr());
 134
 135        /* Disable all Mbox interrupt */
 136        temp = MIPS_H_MASK;
 137        temp &= ~ (SW_H_MBOX1_MASK | SW_H_MBOX2_MASK | SW_H_MBOX3_MASK | SW_H_MBOX4_MASK) ;
 138        MIPS_H_MASK = temp;
 139
 140#ifdef DEBUG
 141        printf("Leaving plb2800_eth_initialize()\n");
 142#endif
 143
 144        return 0;
 145}
 146
 147static int plb2800_eth_init(struct eth_device *dev, bd_t * bis)
 148{
 149#ifdef DEBUG
 150        printf("Entering plb2800_eth_init()\n");
 151#endif
 152
 153        plb2800_set_mac_addr(dev, dev->enetaddr);
 154
 155        rx_new = 0;
 156
 157#ifdef DEBUG
 158        printf("Leaving plb2800_eth_init()\n");
 159#endif
 160
 161        return 0;
 162}
 163
 164
 165static int plb2800_eth_send(struct eth_device *dev, volatile void *packet,
 166                                                  int length)
 167{
 168        int                    i;
 169        int                    res         = -1;
 170        u32                    temp;
 171        mailbox_t *            mb          = MBOX_REG(0);
 172        char      *            mem         = MBOX_MEM(0);
 173
 174#ifdef DEBUG
 175        printf("Entered plb2800_eth_send()\n");
 176#endif
 177
 178        if (length <= 0)
 179        {
 180                printf ("%s: bad packet size: %d\n", dev->name, length);
 181                goto Done;
 182        }
 183
 184        if (length < 64)
 185        {
 186                length = 64;
 187        }
 188
 189        temp = CMAC_CRX_CTRL_CG | ((length + 4) << CMAC_CRX_CTRL_PL_SHIFT);
 190
 191#ifdef DEBUG
 192        printf("0 mb->stat = 0x%x\n",  mb->stat);
 193#endif
 194
 195        for(i = 0; mb->stat & (MBOX_STAT_CP | MBOX_STAT_MB); i++)
 196        {
 197                if (i >= TOUT_LOOP)
 198                {
 199                        printf("%s: tx buffer not ready\n", dev->name);
 200                        printf("1 mb->stat = 0x%x\n",  mb->stat);
 201                        goto Done;
 202                }
 203        }
 204
 205                /* For some strange reason, memcpy doesn't work, here!
 206                 */
 207        do
 208        {
 209                int words = (length >> 2) + 1;
 210                unsigned int* dst = (unsigned int*)(mem);
 211                unsigned int* src = (unsigned int*)(packet);
 212                for (i = 0; i < words; i++)
 213                {
 214                        *dst = *src;
 215                        dst++;
 216                        src++;
 217                };
 218        } while(0);
 219
 220        CMAC_CRX_CTRL = temp;
 221        mb->cmd = MBOX_STAT_CP;
 222
 223#ifdef DEBUG
 224        printf("2 mb->stat = 0x%x\n",  mb->stat);
 225#endif
 226
 227        res = length;
 228Done:
 229
 230#ifdef DEBUG
 231        printf("Leaving plb2800_eth_send()\n");
 232#endif
 233
 234        return res;
 235}
 236
 237
 238static int plb2800_eth_recv(struct eth_device *dev)
 239{
 240        int                    length  = 0;
 241        mailbox_t            * mbox    = MBOX_REG(3);
 242        unsigned char        * hdr     = MBOX_MEM(3);
 243        unsigned int           stat;
 244
 245#ifdef DEBUG
 246        printf("Entered plb2800_eth_recv()\n");
 247#endif
 248
 249        for (;;)
 250        {
 251                stat = mbox->stat;
 252
 253                if (!(stat & MBOX_STAT_CP))
 254                {
 255                        break;
 256                }
 257
 258                length = ((*(hdr + 6) & 0x3f) << 8) + *(hdr + 7);
 259                memcpy((void *)NetRxPackets[rx_new], hdr + 12, length);
 260
 261                stat &= ~MBOX_STAT_CP;
 262                mbox->stat = stat;
 263#ifdef DEBUG
 264                {
 265                        int i;
 266                        for (i=0;i<length - 4;i++)
 267                        {
 268                                if (i % 16 == 0) printf("\n%04x: ", i);
 269                                printf("%02X ", NetRxPackets[rx_new][i]);
 270                        }
 271                        printf("\n");
 272                }
 273#endif
 274
 275                if (length)
 276                {
 277#ifdef DEBUG
 278                        printf("Received %d bytes\n", length);
 279#endif
 280                        NetReceive((void*)(NetRxPackets[rx_new]),
 281                                    length - 4);
 282                }
 283                else
 284                {
 285#if 1
 286                        printf("Zero length!!!\n");
 287#endif
 288                }
 289
 290                rx_new = (rx_new + 1) % NUM_RX_DESC;
 291        }
 292
 293#ifdef DEBUG
 294        printf("Leaving plb2800_eth_recv()\n");
 295#endif
 296
 297        return length;
 298}
 299
 300
 301static void plb2800_eth_halt(struct eth_device *dev)
 302{
 303#ifdef DEBUG
 304        printf("Entered plb2800_eth_halt()\n");
 305#endif
 306
 307#ifdef DEBUG
 308        printf("Leaving plb2800_eth_halt()\n");
 309#endif
 310}
 311
 312static void plb2800_set_mac_addr(struct eth_device *dev, unsigned char * addr)
 313{
 314        char packet[60];
 315        ulong temp;
 316        int ix;
 317
 318        if (mac_addr_set ||
 319            NULL == addr || memcmp(addr, "\0\0\0\0\0\0", 6) == 0)
 320        {
 321                return;
 322        }
 323
 324        /* send one packet through CPU port
 325         * in order to learn system MAC address
 326         */
 327
 328        /* Set DA_LOOKUP register */
 329        temp = EN_MA_LEARN | (0 << DA_STATE_SHF) | (63 << DA_DEST_SHF);
 330        DA_LOOKUP = temp;
 331
 332        /* Set MA_LEARN register */
 333        temp = 50 << MA_DEST_SHF;       /* static entry */
 334        MA_LEARN = temp;
 335
 336        /* set destination address */
 337        for (ix=0;ix<6;ix++)
 338                packet[ix] = 0xff;
 339
 340        /* set source address = system MAC address */
 341        for (ix=0;ix<6;ix++)
 342                packet[6+ix] = addr[ix];
 343
 344        /* set type field */
 345        packet[12]=0xaa;
 346        packet[13]=0x55;
 347
 348        /* set data field */
 349        for(ix=14;ix<60;ix++)
 350                packet[ix] = 0x00;
 351
 352#ifdef DEBUG
 353        for (ix=0;ix<6;ix++)
 354                printf("mac_addr[%d]=%02X\n", ix, (unsigned char)packet[6+ix]);
 355#endif
 356
 357        /* set one packet */
 358        plb2800_eth_send(dev, packet, sizeof(packet));
 359
 360        /* delay for a while */
 361        for(ix=0;ix<65535;ix++)
 362                temp = ~temp;
 363
 364        /* Set CMAC_CTX_CTRL register */
 365        temp = TSTAMP_MS;       /* no autocast */
 366        CMAC_CTX_CTRL = temp;
 367
 368        /* Set DA_LOOKUP register */
 369        temp = EN_DA_LKUP;
 370        DA_LOOKUP = temp;
 371
 372        mac_addr_set = 1;
 373}
 374
 375static unsigned char * plb2800_get_mac_addr(void)
 376{
 377        static unsigned char addr[6];
 378        char *tmp, *end;
 379        int i;
 380
 381        tmp = getenv ("ethaddr");
 382        if (NULL == tmp) return NULL;
 383
 384        for (i=0; i<6; i++) {
 385                addr[i] = tmp ? simple_strtoul(tmp, &end, 16) : 0;
 386                if (tmp)
 387                        tmp = (*end) ? end+1 : end;
 388        }
 389
 390        return addr;
 391}
 392