uboot/arch/powerpc/cpu/mpc8xx/scc.c
<<
>>
Prefs
   1/*
   2 * File:  scc.c
   3 * Description:
   4 *      Basic ET HW initialization and packet RX/TX routines
   5 *
   6 * NOTE  <<<IMPORTANT:  PLEASE READ>>>:
   7 *     Do not cache Rx/Tx buffers!
   8 */
   9
  10/*
  11 * MPC823 <-> MC68160 Connections:
  12 *
  13 * Setup MPC823 to work with MC68160 Enhanced Ethernet
  14 * Serial Tranceiver as follows:
  15 *
  16 * MPC823 Signal                MC68160  Comments
  17 * ------ ------                -------  --------
  18 * PA-12 ETHTX    -------->   TX       Eth. Port Transmit Data
  19 * PB-18 E_TENA   -------->   TENA     Eth. Transmit Port Enable
  20 * PA-5 ETHTCK    <--------   TCLK     Eth. Port Transmit Clock
  21 * PA-13 ETHRX    <--------   RX       Eth. Port Receive Data
  22 * PC-8 E_RENA    <--------   RENA     Eth. Receive Enable
  23 * PA-6 ETHRCK    <--------   RCLK     Eth. Port Receive Clock
  24 * PC-9 E_CLSN    <--------   CLSN     Eth. Port Collision Indication
  25 *
  26 * FADS Board Signal              MC68160  Comments
  27 * -----------------              -------  --------
  28 * (BCSR1) ETHEN*     -------->  CS2      Eth. Port Enable
  29 * (BSCR4) TPSQEL*    -------->  TPSQEL   Twisted Pair Signal Quality Error Test Enable
  30 * (BCSR4) TPFLDL*    -------->  TPFLDL   Twisted Pair Full-Duplex
  31 * (BCSR4) ETHLOOP    -------->  LOOP     Eth. Port Diagnostic Loop-Back
  32 *
  33 */
  34
  35#include <common.h>
  36#include <malloc.h>
  37#include <commproc.h>
  38#include <net.h>
  39#include <command.h>
  40
  41#if defined(CONFIG_CMD_NET) && defined(SCC_ENET)
  42
  43/* Ethernet Transmit and Receive Buffers */
  44#define DBUF_LENGTH  1520
  45
  46#define TX_BUF_CNT 2
  47
  48#define TOUT_LOOP 10000 /* 10 ms to have a packet sent */
  49
  50static char txbuf[DBUF_LENGTH];
  51
  52static uint rxIdx;      /* index of the current RX buffer */
  53static uint txIdx;      /* index of the current TX buffer */
  54
  55/*
  56  * SCC Ethernet Tx and Rx buffer descriptors allocated at the
  57  *  immr->udata_bd address on Dual-Port RAM
  58  * Provide for Double Buffering
  59  */
  60
  61typedef volatile struct CommonBufferDescriptor {
  62    cbd_t rxbd[PKTBUFSRX];      /* Rx BD */
  63    cbd_t txbd[TX_BUF_CNT];     /* Tx BD */
  64} RTXBD;
  65
  66static RTXBD *rtx;
  67
  68static int scc_send(struct eth_device *dev, void *packet, int length);
  69static int scc_recv(struct eth_device* dev);
  70static int scc_init (struct eth_device* dev, bd_t * bd);
  71static void scc_halt(struct eth_device* dev);
  72
  73int scc_initialize(bd_t *bis)
  74{
  75        struct eth_device* dev;
  76
  77        dev = (struct eth_device*) malloc(sizeof *dev);
  78        memset(dev, 0, sizeof *dev);
  79
  80        strcpy(dev->name, "SCC");
  81        dev->iobase = 0;
  82        dev->priv   = 0;
  83        dev->init   = scc_init;
  84        dev->halt   = scc_halt;
  85        dev->send   = scc_send;
  86        dev->recv   = scc_recv;
  87
  88        eth_register(dev);
  89
  90        return 1;
  91}
  92
  93static int scc_send(struct eth_device *dev, void *packet, int length)
  94{
  95        int i, j=0;
  96#if 0
  97        volatile char *in, *out;
  98#endif
  99
 100        /* section 16.9.23.3
 101         * Wait for ready
 102         */
 103#if 0
 104        while (rtx->txbd[txIdx].cbd_sc & BD_ENET_TX_READY);
 105        out = (char *)(rtx->txbd[txIdx].cbd_bufaddr);
 106        in = packet;
 107        for(i = 0; i < length; i++) {
 108                *out++ = *in++;
 109        }
 110        rtx->txbd[txIdx].cbd_datlen = length;
 111        rtx->txbd[txIdx].cbd_sc |= (BD_ENET_TX_READY | BD_ENET_TX_LAST);
 112        while (rtx->txbd[txIdx].cbd_sc & BD_ENET_TX_READY) j++;
 113
 114#ifdef ET_DEBUG
 115        printf("cycles: %d    status: %x\n", j, rtx->txbd[txIdx].cbd_sc);
 116#endif
 117        i = (rtx->txbd[txIdx++].cbd_sc & BD_ENET_TX_STATS) /* return only status bits */;
 118
 119        /* wrap around buffer index when necessary */
 120        if (txIdx >= TX_BUF_CNT) txIdx = 0;
 121#endif
 122
 123        while ((rtx->txbd[txIdx].cbd_sc & BD_ENET_TX_READY) && (j<TOUT_LOOP)) {
 124                udelay (1);     /* will also trigger Wd if needed */
 125                j++;
 126        }
 127        if (j>=TOUT_LOOP) printf("TX not ready\n");
 128        rtx->txbd[txIdx].cbd_bufaddr = (uint)packet;
 129        rtx->txbd[txIdx].cbd_datlen = length;
 130        rtx->txbd[txIdx].cbd_sc |= (BD_ENET_TX_READY | BD_ENET_TX_LAST |BD_ENET_TX_WRAP);
 131        while ((rtx->txbd[txIdx].cbd_sc & BD_ENET_TX_READY) && (j<TOUT_LOOP)) {
 132                udelay (1);     /* will also trigger Wd if needed */
 133                j++;
 134        }
 135        if (j>=TOUT_LOOP) printf("TX timeout\n");
 136#ifdef ET_DEBUG
 137        printf("cycles: %d    status: %x\n", j, rtx->txbd[txIdx].cbd_sc);
 138#endif
 139        i = (rtx->txbd[txIdx].cbd_sc & BD_ENET_TX_STATS) /* return only status bits */;
 140        return i;
 141}
 142
 143static int scc_recv (struct eth_device *dev)
 144{
 145        int length;
 146
 147        for (;;) {
 148                /* section 16.9.23.2 */
 149                if (rtx->rxbd[rxIdx].cbd_sc & BD_ENET_RX_EMPTY) {
 150                        length = -1;
 151                        break;  /* nothing received - leave for() loop */
 152                }
 153
 154                length = rtx->rxbd[rxIdx].cbd_datlen;
 155
 156                if (rtx->rxbd[rxIdx].cbd_sc & 0x003f) {
 157#ifdef ET_DEBUG
 158                        printf ("err: %x\n", rtx->rxbd[rxIdx].cbd_sc);
 159#endif
 160                } else {
 161                        /* Pass the packet up to the protocol layers. */
 162                        net_process_received_packet(net_rx_packets[rxIdx],
 163                                                    length - 4);
 164                }
 165
 166
 167                /* Give the buffer back to the SCC. */
 168                rtx->rxbd[rxIdx].cbd_datlen = 0;
 169
 170                /* wrap around buffer index when necessary */
 171                if ((rxIdx + 1) >= PKTBUFSRX) {
 172                        rtx->rxbd[PKTBUFSRX - 1].cbd_sc =
 173                                (BD_ENET_RX_WRAP | BD_ENET_RX_EMPTY);
 174                        rxIdx = 0;
 175                } else {
 176                        rtx->rxbd[rxIdx].cbd_sc = BD_ENET_RX_EMPTY;
 177                        rxIdx++;
 178                }
 179        }
 180        return length;
 181}
 182
 183/**************************************************************
 184  *
 185  * SCC Ethernet Initialization Routine
 186  *
 187  *************************************************************/
 188
 189static int scc_init (struct eth_device *dev, bd_t * bis)
 190{
 191
 192        int i;
 193        scc_enet_t *pram_ptr;
 194
 195        volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
 196
 197        pram_ptr = (scc_enet_t *) & (immr->im_cpm.cp_dparam[PROFF_ENET]);
 198
 199        rxIdx = 0;
 200        txIdx = 0;
 201
 202        if (!rtx)
 203                rtx = (RTXBD *)(immr->im_cpm.cp_dpmem + CPM_SCC_BASE);
 204
 205#if (defined(PA_ENET_RXD) && defined(PA_ENET_TXD))
 206        /* Configure port A pins for Txd and Rxd.
 207         */
 208        immr->im_ioport.iop_papar |= (PA_ENET_RXD | PA_ENET_TXD);
 209        immr->im_ioport.iop_padir &= ~(PA_ENET_RXD | PA_ENET_TXD);
 210        immr->im_ioport.iop_paodr &= ~PA_ENET_TXD;
 211#elif (defined(PB_ENET_RXD) && defined(PB_ENET_TXD))
 212        /* Configure port B pins for Txd and Rxd.
 213         */
 214        immr->im_cpm.cp_pbpar |= (PB_ENET_RXD | PB_ENET_TXD);
 215        immr->im_cpm.cp_pbdir &= ~(PB_ENET_RXD | PB_ENET_TXD);
 216        immr->im_cpm.cp_pbodr &= ~PB_ENET_TXD;
 217#else
 218#error Configuration Error: exactly ONE of PA_ENET_[RT]XD, PB_ENET_[RT]XD must be defined
 219#endif
 220
 221#if defined(PC_ENET_LBK)
 222        /* Configure port C pins to disable External Loopback
 223         */
 224        immr->im_ioport.iop_pcpar &= ~PC_ENET_LBK;
 225        immr->im_ioport.iop_pcdir |= PC_ENET_LBK;
 226        immr->im_ioport.iop_pcso &= ~PC_ENET_LBK;
 227        immr->im_ioport.iop_pcdat &= ~PC_ENET_LBK;      /* Disable Loopback */
 228#endif /* PC_ENET_LBK */
 229
 230        /* Configure port C pins to enable CLSN and RENA.
 231         */
 232        immr->im_ioport.iop_pcpar &= ~(PC_ENET_CLSN | PC_ENET_RENA);
 233        immr->im_ioport.iop_pcdir &= ~(PC_ENET_CLSN | PC_ENET_RENA);
 234        immr->im_ioport.iop_pcso |= (PC_ENET_CLSN | PC_ENET_RENA);
 235
 236        /* Configure port A for TCLK and RCLK.
 237         */
 238        immr->im_ioport.iop_papar |= (PA_ENET_TCLK | PA_ENET_RCLK);
 239        immr->im_ioport.iop_padir &= ~(PA_ENET_TCLK | PA_ENET_RCLK);
 240
 241        /*
 242         * Configure Serial Interface clock routing -- see section 16.7.5.3
 243         * First, clear all SCC bits to zero, then set the ones we want.
 244         */
 245
 246        immr->im_cpm.cp_sicr &= ~SICR_ENET_MASK;
 247        immr->im_cpm.cp_sicr |= SICR_ENET_CLKRT;
 248
 249
 250        /*
 251         * Initialize SDCR -- see section 16.9.23.7
 252         * SDMA configuration register
 253         */
 254        immr->im_siu_conf.sc_sdcr = 0x01;
 255
 256
 257        /*
 258         * Setup SCC Ethernet Parameter RAM
 259         */
 260
 261        pram_ptr->sen_genscc.scc_rfcr = 0x18;   /* Normal Operation and Mot byte ordering */
 262        pram_ptr->sen_genscc.scc_tfcr = 0x18;   /* Mot byte ordering, Normal access */
 263
 264        pram_ptr->sen_genscc.scc_mrblr = DBUF_LENGTH;   /* max. ET package len 1520 */
 265
 266        pram_ptr->sen_genscc.scc_rbase = (unsigned int) (&rtx->rxbd[0]);        /* Set RXBD tbl start at Dual Port */
 267        pram_ptr->sen_genscc.scc_tbase = (unsigned int) (&rtx->txbd[0]);        /* Set TXBD tbl start at Dual Port */
 268
 269        /*
 270         * Setup Receiver Buffer Descriptors (13.14.24.18)
 271         * Settings:
 272         *     Empty, Wrap
 273         */
 274
 275        for (i = 0; i < PKTBUFSRX; i++) {
 276                rtx->rxbd[i].cbd_sc = BD_ENET_RX_EMPTY;
 277                rtx->rxbd[i].cbd_datlen = 0;    /* Reset */
 278                rtx->rxbd[i].cbd_bufaddr = (uint) net_rx_packets[i];
 279        }
 280
 281        rtx->rxbd[PKTBUFSRX - 1].cbd_sc |= BD_ENET_RX_WRAP;
 282
 283        /*
 284         * Setup Ethernet Transmitter Buffer Descriptors (13.14.24.19)
 285         * Settings:
 286         *    Add PADs to Short FRAMES, Wrap, Last, Tx CRC
 287         */
 288
 289        for (i = 0; i < TX_BUF_CNT; i++) {
 290                rtx->txbd[i].cbd_sc =
 291                        (BD_ENET_TX_PAD | BD_ENET_TX_LAST | BD_ENET_TX_TC);
 292                rtx->txbd[i].cbd_datlen = 0;    /* Reset */
 293                rtx->txbd[i].cbd_bufaddr = (uint) (&txbuf[0]);
 294        }
 295
 296        rtx->txbd[TX_BUF_CNT - 1].cbd_sc |= BD_ENET_TX_WRAP;
 297
 298        /*
 299         * Enter Command:  Initialize Rx Params for SCC
 300         */
 301
 302        do {                    /* Spin until ready to issue command    */
 303                __asm__ ("eieio");
 304        } while (immr->im_cpm.cp_cpcr & CPM_CR_FLG);
 305        /* Issue command */
 306        immr->im_cpm.cp_cpcr =
 307                ((CPM_CR_INIT_RX << 8) | (CPM_CR_ENET << 4) | CPM_CR_FLG);
 308        do {                    /* Spin until command processed         */
 309                __asm__ ("eieio");
 310        } while (immr->im_cpm.cp_cpcr & CPM_CR_FLG);
 311
 312        /*
 313         * Ethernet Specific Parameter RAM
 314         *     see table 13-16, pg. 660,
 315         *     pg. 681 (example with suggested settings)
 316         */
 317
 318        pram_ptr->sen_cpres = ~(0x0);   /* Preset CRC */
 319        pram_ptr->sen_cmask = 0xdebb20e3;       /* Constant Mask for CRC */
 320        pram_ptr->sen_crcec = 0x0;      /* Error Counter CRC (unused) */
 321        pram_ptr->sen_alec = 0x0;       /* Alignment Error Counter (unused) */
 322        pram_ptr->sen_disfc = 0x0;      /* Discard Frame Counter (unused) */
 323        pram_ptr->sen_pads = 0x8888;    /* Short Frame PAD Characters */
 324
 325        pram_ptr->sen_retlim = 15;      /* Retry Limit Threshold */
 326        pram_ptr->sen_maxflr = 1518;    /* MAX Frame Length Register */
 327        pram_ptr->sen_minflr = 64;      /* MIN Frame Length Register */
 328
 329        pram_ptr->sen_maxd1 = DBUF_LENGTH;      /* MAX DMA1 Length Register */
 330        pram_ptr->sen_maxd2 = DBUF_LENGTH;      /* MAX DMA2 Length Register */
 331
 332        pram_ptr->sen_gaddr1 = 0x0;     /* Group Address Filter 1 (unused) */
 333        pram_ptr->sen_gaddr2 = 0x0;     /* Group Address Filter 2 (unused) */
 334        pram_ptr->sen_gaddr3 = 0x0;     /* Group Address Filter 3 (unused) */
 335        pram_ptr->sen_gaddr4 = 0x0;     /* Group Address Filter 4 (unused) */
 336
 337#define ea eth_get_ethaddr()
 338        pram_ptr->sen_paddrh = (ea[5] << 8) + ea[4];
 339        pram_ptr->sen_paddrm = (ea[3] << 8) + ea[2];
 340        pram_ptr->sen_paddrl = (ea[1] << 8) + ea[0];
 341#undef ea
 342
 343        pram_ptr->sen_pper = 0x0;       /* Persistence (unused) */
 344        pram_ptr->sen_iaddr1 = 0x0;     /* Individual Address Filter 1 (unused) */
 345        pram_ptr->sen_iaddr2 = 0x0;     /* Individual Address Filter 2 (unused) */
 346        pram_ptr->sen_iaddr3 = 0x0;     /* Individual Address Filter 3 (unused) */
 347        pram_ptr->sen_iaddr4 = 0x0;     /* Individual Address Filter 4 (unused) */
 348        pram_ptr->sen_taddrh = 0x0;     /* Tmp Address (MSB) (unused) */
 349        pram_ptr->sen_taddrm = 0x0;     /* Tmp Address (unused) */
 350        pram_ptr->sen_taddrl = 0x0;     /* Tmp Address (LSB) (unused) */
 351
 352        /*
 353         * Enter Command:  Initialize Tx Params for SCC
 354         */
 355
 356        do {                    /* Spin until ready to issue command    */
 357                __asm__ ("eieio");
 358        } while (immr->im_cpm.cp_cpcr & CPM_CR_FLG);
 359        /* Issue command */
 360        immr->im_cpm.cp_cpcr =
 361                ((CPM_CR_INIT_TX << 8) | (CPM_CR_ENET << 4) | CPM_CR_FLG);
 362        do {                    /* Spin until command processed         */
 363                __asm__ ("eieio");
 364        } while (immr->im_cpm.cp_cpcr & CPM_CR_FLG);
 365
 366        /*
 367         * Mask all Events in SCCM - we use polling mode
 368         */
 369        immr->im_cpm.cp_scc[SCC_ENET].scc_sccm = 0;
 370
 371        /*
 372         * Clear Events in SCCE -- Clear bits by writing 1's
 373         */
 374
 375        immr->im_cpm.cp_scc[SCC_ENET].scc_scce = ~(0x0);
 376
 377
 378        /*
 379         * Initialize GSMR High 32-Bits
 380         * Settings:  Normal Mode
 381         */
 382
 383        immr->im_cpm.cp_scc[SCC_ENET].scc_gsmrh = 0;
 384
 385        /*
 386         * Initialize GSMR Low 32-Bits, but do not Enable Transmit/Receive
 387         * Settings:
 388         *     TCI = Invert
 389         *     TPL =  48 bits
 390         *     TPP = Repeating 10's
 391         *     MODE = Ethernet
 392         */
 393
 394        immr->im_cpm.cp_scc[SCC_ENET].scc_gsmrl = (SCC_GSMRL_TCI |
 395                                                   SCC_GSMRL_TPL_48 |
 396                                                   SCC_GSMRL_TPP_10 |
 397                                                   SCC_GSMRL_MODE_ENET);
 398
 399        /*
 400         * Initialize the DSR -- see section 13.14.4 (pg. 513) v0.4
 401         */
 402
 403        immr->im_cpm.cp_scc[SCC_ENET].scc_dsr = 0xd555;
 404
 405        /*
 406         * Initialize the PSMR
 407         * Settings:
 408         *  CRC = 32-Bit CCITT
 409         *  NIB = Begin searching for SFD 22 bits after RENA
 410         *  FDE = Full Duplex Enable
 411         *  LPB = Loopback Enable (Needed when FDE is set)
 412         *  BRO = Reject broadcast packets
 413         *  PROMISCOUS = Catch all packets regardless of dest. MAC adress
 414         */
 415        immr->im_cpm.cp_scc[SCC_ENET].scc_psmr = SCC_PSMR_ENCRC |
 416                SCC_PSMR_NIB22 |
 417#if defined(CONFIG_SCC_ENET_FULL_DUPLEX)
 418                SCC_PSMR_FDE | SCC_PSMR_LPB |
 419#endif
 420#if defined(CONFIG_SCC_ENET_NO_BROADCAST)
 421                SCC_PSMR_BRO |
 422#endif
 423#if defined(CONFIG_SCC_ENET_PROMISCOUS)
 424                SCC_PSMR_PRO |
 425#endif
 426                0;
 427
 428        /*
 429         * Configure Ethernet TENA Signal
 430         */
 431
 432#if (defined(PC_ENET_TENA) && !defined(PB_ENET_TENA))
 433        immr->im_ioport.iop_pcpar |= PC_ENET_TENA;
 434        immr->im_ioport.iop_pcdir &= ~PC_ENET_TENA;
 435#elif (defined(PB_ENET_TENA) && !defined(PC_ENET_TENA))
 436        immr->im_cpm.cp_pbpar |= PB_ENET_TENA;
 437        immr->im_cpm.cp_pbdir |= PB_ENET_TENA;
 438#else
 439#error Configuration Error: exactly ONE of PB_ENET_TENA, PC_ENET_TENA must be defined
 440#endif
 441
 442        /*
 443         * Set the ENT/ENR bits in the GSMR Low -- Enable Transmit/Receive
 444         */
 445
 446        immr->im_cpm.cp_scc[SCC_ENET].scc_gsmrl |=
 447                (SCC_GSMRL_ENR | SCC_GSMRL_ENT);
 448
 449        return 1;
 450}
 451
 452
 453static void scc_halt (struct eth_device *dev)
 454{
 455        volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
 456
 457        immr->im_cpm.cp_scc[SCC_ENET].scc_gsmrl &=
 458                ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
 459
 460        immr->im_ioport.iop_pcso  &=  ~(PC_ENET_CLSN | PC_ENET_RENA);
 461}
 462
 463#if 0
 464void restart (void)
 465{
 466        volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
 467
 468        immr->im_cpm.cp_scc[SCC_ENET].scc_gsmrl |=
 469                (SCC_GSMRL_ENR | SCC_GSMRL_ENT);
 470}
 471#endif
 472#endif
 473