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, void *packet, int length);
  86static int plb2800_eth_recv(struct eth_device *dev);
  87static void plb2800_eth_halt(struct eth_device *dev);
  88
  89static void plb2800_set_mac_addr(struct eth_device *dev, unsigned char * addr);
  90static unsigned char * plb2800_get_mac_addr(void);
  91
  92static int rx_new;
  93static int mac_addr_set = 0;
  94
  95
  96int plb2800_eth_initialize(bd_t * bis)
  97{
  98        struct eth_device *dev;
  99        ulong temp;
 100
 101#ifdef DEBUG
 102        printf("Entered plb2800_eth_initialize()\n");
 103#endif
 104
 105        if (!(dev = (struct eth_device *) malloc (sizeof *dev)))
 106        {
 107                printf("Failed to allocate memory\n");
 108                return -1;
 109        }
 110        memset(dev, 0, sizeof(*dev));
 111
 112        sprintf(dev->name, "PLB2800 Switch");
 113        dev->init = plb2800_eth_init;
 114        dev->halt = plb2800_eth_halt;
 115        dev->send = plb2800_eth_send;
 116        dev->recv = plb2800_eth_recv;
 117
 118        eth_register(dev);
 119
 120        /* bug fix */
 121        *(ulong *)0xb800e800 = 0x838;
 122
 123        /* Set MBOX ownership */
 124        temp = CMAC_CRIT << MBOX_STAT_ID_SHF;
 125        MBOX_REG(0)->stat = temp;
 126        MBOX_REG(1)->stat = temp;
 127
 128        temp = CMAC_NON_CRIT << MBOX_STAT_ID_SHF;
 129        MBOX_REG(2)->stat = temp;
 130        MBOX_REG(3)->stat = temp;
 131
 132        plb2800_set_mac_addr(dev, plb2800_get_mac_addr());
 133
 134        /* Disable all Mbox interrupt */
 135        temp = MIPS_H_MASK;
 136        temp &= ~ (SW_H_MBOX1_MASK | SW_H_MBOX2_MASK | SW_H_MBOX3_MASK | SW_H_MBOX4_MASK) ;
 137        MIPS_H_MASK = temp;
 138
 139#ifdef DEBUG
 140        printf("Leaving plb2800_eth_initialize()\n");
 141#endif
 142
 143        return 0;
 144}
 145
 146static int plb2800_eth_init(struct eth_device *dev, bd_t * bis)
 147{
 148#ifdef DEBUG
 149        printf("Entering plb2800_eth_init()\n");
 150#endif
 151
 152        plb2800_set_mac_addr(dev, dev->enetaddr);
 153
 154        rx_new = 0;
 155
 156#ifdef DEBUG
 157        printf("Leaving plb2800_eth_init()\n");
 158#endif
 159
 160        return 0;
 161}
 162
 163
 164static int plb2800_eth_send(struct eth_device *dev, void *packet, int length)
 165{
 166        int                    i;
 167        int                    res         = -1;
 168        u32                    temp;
 169        mailbox_t *            mb          = MBOX_REG(0);
 170        char      *            mem         = MBOX_MEM(0);
 171
 172#ifdef DEBUG
 173        printf("Entered plb2800_eth_send()\n");
 174#endif
 175
 176        if (length <= 0)
 177        {
 178                printf ("%s: bad packet size: %d\n", dev->name, length);
 179                goto Done;
 180        }
 181
 182        if (length < 64)
 183        {
 184                length = 64;
 185        }
 186
 187        temp = CMAC_CRX_CTRL_CG | ((length + 4) << CMAC_CRX_CTRL_PL_SHIFT);
 188
 189#ifdef DEBUG
 190        printf("0 mb->stat = 0x%x\n",  mb->stat);
 191#endif
 192
 193        for(i = 0; mb->stat & (MBOX_STAT_CP | MBOX_STAT_MB); i++)
 194        {
 195                if (i >= TOUT_LOOP)
 196                {
 197                        printf("%s: tx buffer not ready\n", dev->name);
 198                        printf("1 mb->stat = 0x%x\n",  mb->stat);
 199                        goto Done;
 200                }
 201        }
 202
 203                /* For some strange reason, memcpy doesn't work, here!
 204                 */
 205        do
 206        {
 207                int words = (length >> 2) + 1;
 208                unsigned int* dst = (unsigned int*)(mem);
 209                unsigned int* src = (unsigned int*)(packet);
 210                for (i = 0; i < words; i++)
 211                {
 212                        *dst = *src;
 213                        dst++;
 214                        src++;
 215                };
 216        } while(0);
 217
 218        CMAC_CRX_CTRL = temp;
 219        mb->cmd = MBOX_STAT_CP;
 220
 221#ifdef DEBUG
 222        printf("2 mb->stat = 0x%x\n",  mb->stat);
 223#endif
 224
 225        res = length;
 226Done:
 227
 228#ifdef DEBUG
 229        printf("Leaving plb2800_eth_send()\n");
 230#endif
 231
 232        return res;
 233}
 234
 235
 236static int plb2800_eth_recv(struct eth_device *dev)
 237{
 238        int                    length  = 0;
 239        mailbox_t            * mbox    = MBOX_REG(3);
 240        unsigned char        * hdr     = MBOX_MEM(3);
 241        unsigned int           stat;
 242
 243#ifdef DEBUG
 244        printf("Entered plb2800_eth_recv()\n");
 245#endif
 246
 247        for (;;)
 248        {
 249                stat = mbox->stat;
 250
 251                if (!(stat & MBOX_STAT_CP))
 252                {
 253                        break;
 254                }
 255
 256                length = ((*(hdr + 6) & 0x3f) << 8) + *(hdr + 7);
 257                memcpy((void *)NetRxPackets[rx_new], hdr + 12, length);
 258
 259                stat &= ~MBOX_STAT_CP;
 260                mbox->stat = stat;
 261#ifdef DEBUG
 262                {
 263                        int i;
 264                        for (i=0;i<length - 4;i++)
 265                        {
 266                                if (i % 16 == 0) printf("\n%04x: ", i);
 267                                printf("%02X ", NetRxPackets[rx_new][i]);
 268                        }
 269                        printf("\n");
 270                }
 271#endif
 272
 273                if (length)
 274                {
 275#ifdef DEBUG
 276                        printf("Received %d bytes\n", length);
 277#endif
 278                        NetReceive((void*)(NetRxPackets[rx_new]),
 279                                    length - 4);
 280                }
 281                else
 282                {
 283#if 1
 284                        printf("Zero length!!!\n");
 285#endif
 286                }
 287
 288                rx_new = (rx_new + 1) % NUM_RX_DESC;
 289        }
 290
 291#ifdef DEBUG
 292        printf("Leaving plb2800_eth_recv()\n");
 293#endif
 294
 295        return length;
 296}
 297
 298
 299static void plb2800_eth_halt(struct eth_device *dev)
 300{
 301#ifdef DEBUG
 302        printf("Entered plb2800_eth_halt()\n");
 303#endif
 304
 305#ifdef DEBUG
 306        printf("Leaving plb2800_eth_halt()\n");
 307#endif
 308}
 309
 310static void plb2800_set_mac_addr(struct eth_device *dev, unsigned char * addr)
 311{
 312        char packet[60];
 313        ulong temp;
 314        int ix;
 315
 316        if (mac_addr_set ||
 317            NULL == addr || memcmp(addr, "\0\0\0\0\0\0", 6) == 0)
 318        {
 319                return;
 320        }
 321
 322        /* send one packet through CPU port
 323         * in order to learn system MAC address
 324         */
 325
 326        /* Set DA_LOOKUP register */
 327        temp = EN_MA_LEARN | (0 << DA_STATE_SHF) | (63 << DA_DEST_SHF);
 328        DA_LOOKUP = temp;
 329
 330        /* Set MA_LEARN register */
 331        temp = 50 << MA_DEST_SHF;       /* static entry */
 332        MA_LEARN = temp;
 333
 334        /* set destination address */
 335        for (ix=0;ix<6;ix++)
 336                packet[ix] = 0xff;
 337
 338        /* set source address = system MAC address */
 339        for (ix=0;ix<6;ix++)
 340                packet[6+ix] = addr[ix];
 341
 342        /* set type field */
 343        packet[12]=0xaa;
 344        packet[13]=0x55;
 345
 346        /* set data field */
 347        for(ix=14;ix<60;ix++)
 348                packet[ix] = 0x00;
 349
 350#ifdef DEBUG
 351        for (ix=0;ix<6;ix++)
 352                printf("mac_addr[%d]=%02X\n", ix, (unsigned char)packet[6+ix]);
 353#endif
 354
 355        /* set one packet */
 356        plb2800_eth_send(dev, packet, sizeof(packet));
 357
 358        /* delay for a while */
 359        for(ix=0;ix<65535;ix++)
 360                temp = ~temp;
 361
 362        /* Set CMAC_CTX_CTRL register */
 363        temp = TSTAMP_MS;       /* no autocast */
 364        CMAC_CTX_CTRL = temp;
 365
 366        /* Set DA_LOOKUP register */
 367        temp = EN_DA_LKUP;
 368        DA_LOOKUP = temp;
 369
 370        mac_addr_set = 1;
 371}
 372
 373static unsigned char * plb2800_get_mac_addr(void)
 374{
 375        static unsigned char addr[6];
 376        char *tmp, *end;
 377        int i;
 378
 379        tmp = getenv ("ethaddr");
 380        if (NULL == tmp) return NULL;
 381
 382        for (i=0; i<6; i++) {
 383                addr[i] = tmp ? simple_strtoul(tmp, &end, 16) : 0;
 384                if (tmp)
 385                        tmp = (*end) ? end+1 : end;
 386        }
 387
 388        return addr;
 389}
 390