uboot/board/keymile/km8xx/km8xx_hdlc_enet.c
<<
>>
Prefs
   1/*
   2 * (C) Copyright 2008
   3 * Gary Jennejohn, DENX Software Engineering GmbH, garyj@denx.de.
   4 *
   5 * Based in part on cpu/mpc8xx/scc.c.
   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>     /* commproc.h is included here */
  27#include <malloc.h>
  28#include <net.h>
  29
  30#ifdef CONFIG_KEYMILE_HDLC_ENET
  31
  32#include "../common/keymile_hdlc_enet.h"
  33
  34char keymile_slot;      /* our slot number in the backplane */
  35
  36/*
  37 * Since, except during initialization, ethact is always HDLC ETHERNET
  38 * while we're in the driver, just use serial_printf() everywhere for
  39 * output.  This avoids possible conflicts when netconsole is being
  40 * used.
  41 */
  42#define dprintf(fmt, args...)   serial_printf(fmt, ##args)
  43
  44static int already_inited;
  45
  46/*
  47  * SCC Ethernet Tx and Rx buffer descriptors allocated at the
  48  *  immr->udata_bd address on Dual-Port RAM
  49  * Provide for Double Buffering
  50  */
  51typedef volatile struct CommonBufferDescriptor {
  52    cbd_t txbd;                 /* Tx BD */
  53    cbd_t rxbd[HDLC_PKTBUFSRX]; /* Rx BD */
  54} RTXBD;
  55
  56static RTXBD *rtx;
  57
  58int keymile_hdlc_enet_init(struct eth_device *, bd_t *);
  59void keymile_hdlc_enet_halt(struct eth_device *);
  60extern void keymile_hdlc_enet_init_bds(RTXBD *);
  61extern void initCachedNumbers(int);
  62
  63/* Use SCC4 */
  64#define MGS_CPM_CR_HDLC CPM_CR_CH_SCC4
  65#define MGS_PROFF_HDLC  PROFF_SCC4
  66#define MGS_SCC_HDLC    3       /* Index, not number! */
  67
  68int keymile_hdlc_enet_init(struct eth_device *dev, bd_t *bis)
  69{
  70        /* int i; */
  71        /* volatile cbd_t *bdp; */
  72        volatile cpm8xx_t *cp;
  73        volatile scc_t *sccp;
  74        volatile hdlc_pram_t *hpr;
  75        volatile iop8xx_t *iop;
  76
  77        if (already_inited)
  78                return 0;
  79
  80        cp = (cpm8xx_t *)&(((volatile immap_t *)CONFIG_SYS_IMMR)->im_cpm);
  81        hpr = (hdlc_pram_t *)(&cp->cp_dparam[MGS_PROFF_HDLC]);
  82        sccp = (volatile scc_t *)(&cp->cp_scc[MGS_SCC_HDLC]);
  83        iop = (iop8xx_t *)&(((volatile immap_t *)CONFIG_SYS_IMMR)->im_ioport);
  84
  85        /*
  86         * Disable receive and transmit just in case.
  87         */
  88        sccp->scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
  89
  90#ifndef CONFIG_SYS_ALLOC_DPRAM
  91#error "CONFIG_SYS_ALLOC_DPRAM must be defined"
  92#else
  93        /*
  94         * Avoid exhausting DPRAM, which would cause a panic.
  95         * Actually this isn't really necessary, but leave it here
  96         * for safety's sake.
  97         */
  98        if (rtx == NULL) {
  99                rtx = (RTXBD *) (cp->cp_dpmem +
 100                         dpram_alloc_align(sizeof(RTXBD), 8));
 101                if (rtx == (RTXBD *)CPM_DP_NOSPACE)
 102                        return -1;
 103                memset((void *)rtx, 0, sizeof(RTXBD));
 104        }
 105#endif /* !CONFIG_SYS_ALLOC_DPRAM */
 106
 107        /* We need the slot number for addressing. */
 108        keymile_slot = *(char *)(CONFIG_SYS_SLOT_ID_BASE +
 109                CONFIG_SYS_SLOT_ID_OFF) & CONFIG_SYS_SLOT_ID_MASK;
 110        /*
 111         * Be consistent with the Linux driver and set
 112         * only enetaddr[0].
 113         *
 114         * Always add 1 to the slot number so that
 115         * there are no problems with an ethaddr which
 116         * is all 0s.  This should be acceptable because
 117         * a board should never have a slot number of 255,
 118         * which is the broadcast address.  The HDLC addressing
 119         * uses only the slot number.
 120         */
 121        dev->enetaddr[0] = keymile_slot + 1;
 122
 123#ifdef TEST_IT
 124        dprintf("slot %d\n", keymile_slot);
 125#endif
 126
 127        /* use pa8, pa9 pins for TXD4, RXD4 respectively */
 128        iop->iop_papar |= ((0x8000 >> 8) | (0x8000 >> 9));
 129        iop->iop_padir &= ~((0x8000 >> 8) | (0x8000 >> 9));
 130        iop->iop_paodr &= ~((0x8000 >> 8) | (0x8000 >> 9));
 131
 132        /* also use pa0 as CLK8 */
 133        iop->iop_papar |= 0x8000;
 134        iop->iop_padir &= ~0x8000;
 135        iop->iop_paodr &= ~0x8000;
 136
 137        /* use pc5 as CTS4 */
 138        iop->iop_pcpar &= ~(0x8000 >> 5);
 139        iop->iop_pcdir &= ~(0x8000 >> 5);
 140        iop->iop_pcso  |= (0x8000 >> 5);
 141
 142        /*
 143         * SI clock routing
 144         * use CLK8
 145         * this also connects SCC4 to NMSI
 146         */
 147        cp->cp_sicr = (cp->cp_sicr & ~0xff000000) | 0x3f000000;
 148
 149        /* keymile_rxIdx = 0; */
 150
 151        /*
 152         * Initialize function code registers for big-endian.
 153         */
 154        hpr->rfcr = SCC_EB;
 155        hpr->tfcr = SCC_EB;
 156
 157        /*
 158         * Set maximum bytes per receive buffer.
 159         */
 160        hpr->mrblr = MAX_FRAME_LENGTH;
 161
 162        /* Setup CRC generator values for HDLC */
 163        hpr->c_mask = 0x0000F0B8;
 164        hpr->c_pres = 0x0000FFFF;
 165
 166        /* Initialize all error counters to 0 */
 167        hpr->disfc = 0;
 168        hpr->crcec = 0;
 169        hpr->abtsc = 0;
 170        hpr->nmarc = 0;
 171        hpr->retrc = 0;
 172
 173        /* Set maximum frame length size */
 174        hpr->mflr = MAX_FRAME_LENGTH;
 175
 176        /* set to 1 for per frame processing change later if needed */
 177        hpr->rfthr = 1;
 178
 179        hpr->hmask = 0xff;
 180
 181        hpr->haddr2 = SET_HDLC_UUA(keymile_slot);
 182        hpr->haddr3 = hpr->haddr2;
 183        hpr->haddr4 = hpr->haddr2;
 184        /* broadcast */
 185        hpr->haddr1 = HDLC_BCAST;
 186
 187        hpr->rbase = (unsigned int) &rtx->rxbd[0];
 188        hpr->tbase = (unsigned int) &rtx->txbd;
 189
 190#if 0
 191        /*
 192         * Initialize the buffer descriptors.
 193         */
 194        bdp = &rtx->txbd;
 195        bdp->cbd_sc = 0;
 196        bdp->cbd_bufaddr = 0;
 197        bdp->cbd_sc = BD_SC_WRAP;
 198
 199        /*
 200         *      Setup RX packet buffers, aligned correctly.
 201         *      Borrowed from net/net.c.
 202         */
 203        MyRxPackets[0] = &MyPktBuf[0] + (PKTALIGN - 1);
 204        MyRxPackets[0] -= (ulong)MyRxPackets[0] % PKTALIGN;
 205        for (i = 1; i < HDLC_PKTBUFSRX; i++)
 206                MyRxPackets[i] = MyRxPackets[0] + i * PKT_MAXBLR_SIZE;
 207
 208        bdp = &rtx->rxbd[0];
 209        for (i = 0; i < HDLC_PKTBUFSRX; i++) {
 210                bdp->cbd_sc = BD_SC_EMPTY;
 211                /* Leave space at the start for INET header. */
 212                bdp->cbd_bufaddr = (unsigned int)(MyRxPackets[i] +
 213                        INET_HDR_ALIGN);
 214                bdp++;
 215        }
 216        bdp--;
 217        bdp->cbd_sc |= BD_SC_WRAP;
 218#else
 219        keymile_hdlc_enet_init_bds(rtx);
 220#endif
 221
 222        /* Let's re-initialize the channel now.  We have to do it later
 223         * than the manual describes because we have just now finished
 224         * the BD initialization.
 225         */
 226        cp->cp_cpcr = mk_cr_cmd(MGS_CPM_CR_HDLC, CPM_CR_INIT_TRX) | CPM_CR_FLG;
 227        while (cp->cp_cpcr & CPM_CR_FLG);
 228
 229        sccp->scc_gsmrl = SCC_GSMRL_MODE_HDLC;
 230        /* CTSS=1 */
 231        sccp->scc_gsmrh = SCC_GSMRH_CTSS;
 232        /* NOF=0, RTE=1, DRT=0, BUS=1 */
 233        sccp->scc_psmr = ((0x8000 >> 6) | (0x8000 >> 10));
 234
 235/* loopback for local testing */
 236#ifdef GJTEST
 237        dprintf("LOOPBACK!\n");
 238        sccp->scc_gsmrl |= SCC_GSMRL_DIAG_LOOP;
 239#endif
 240
 241        /*
 242         * Disable all interrupts and clear all pending
 243         * events.
 244         */
 245        sccp->scc_sccm = 0;
 246        sccp->scc_scce = 0xffff;
 247
 248        /*
 249         * And last, enable the transmit and receive processing.
 250         */
 251        sccp->scc_gsmrl |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT);
 252
 253        dprintf("%s: HDLC ENET Version 0.3 on SCC%d\n", dev->name,
 254                MGS_SCC_HDLC + 1);
 255
 256        /*
 257         * We may not get an ARP packet because ARP was already done on
 258         * a different interface, so initialize the cached values now.
 259         */
 260        initCachedNumbers(1);
 261
 262        already_inited = 1;
 263
 264        return 0;
 265}
 266
 267void keymile_hdlc_enet_halt(struct eth_device *dev)
 268{
 269#if 0 /* just return, but keep this for reference */
 270        volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
 271
 272        /* maybe should do a graceful stop here? */
 273        immr->im_cpm.cp_scc[MGS_SCC_HDLC].scc_gsmrl &=
 274                ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
 275#endif
 276}
 277
 278#endif /* CONFIG_KEYMILE_HDLC_ENET */
 279