uboot/drivers/net/ftmac100.c
<<
>>
Prefs
   1/*
   2 * Faraday FTMAC100 Ethernet
   3 *
   4 * (C) Copyright 2009 Faraday Technology
   5 * Po-Yu Chuang <ratbert@faraday-tech.com>
   6 *
   7 * SPDX-License-Identifier:     GPL-2.0+
   8 */
   9
  10#include <config.h>
  11#include <common.h>
  12#include <malloc.h>
  13#include <net.h>
  14#include <asm/io.h>
  15
  16#include "ftmac100.h"
  17
  18#define ETH_ZLEN        60
  19
  20struct ftmac100_data {
  21        struct ftmac100_txdes txdes[1];
  22        struct ftmac100_rxdes rxdes[PKTBUFSRX];
  23        int rx_index;
  24};
  25
  26/*
  27 * Reset MAC
  28 */
  29static void ftmac100_reset (struct eth_device *dev)
  30{
  31        struct ftmac100 *ftmac100 = (struct ftmac100 *)dev->iobase;
  32
  33        debug ("%s()\n", __func__);
  34
  35        writel (FTMAC100_MACCR_SW_RST, &ftmac100->maccr);
  36
  37        while (readl (&ftmac100->maccr) & FTMAC100_MACCR_SW_RST)
  38                ;
  39}
  40
  41/*
  42 * Set MAC address
  43 */
  44static void ftmac100_set_mac (struct eth_device *dev, const unsigned char *mac)
  45{
  46        struct ftmac100 *ftmac100 = (struct ftmac100 *)dev->iobase;
  47        unsigned int maddr = mac[0] << 8 | mac[1];
  48        unsigned int laddr = mac[2] << 24 | mac[3] << 16 | mac[4] << 8 | mac[5];
  49
  50        debug ("%s(%x %x)\n", __func__, maddr, laddr);
  51
  52        writel (maddr, &ftmac100->mac_madr);
  53        writel (laddr, &ftmac100->mac_ladr);
  54}
  55
  56static void ftmac100_set_mac_from_env (struct eth_device *dev)
  57{
  58        eth_getenv_enetaddr ("ethaddr", dev->enetaddr);
  59
  60        ftmac100_set_mac (dev, dev->enetaddr);
  61}
  62
  63/*
  64 * disable transmitter, receiver
  65 */
  66static void ftmac100_halt (struct eth_device *dev)
  67{
  68        struct ftmac100 *ftmac100 = (struct ftmac100 *)dev->iobase;
  69
  70        debug ("%s()\n", __func__);
  71
  72        writel (0, &ftmac100->maccr);
  73}
  74
  75static int ftmac100_init (struct eth_device *dev, bd_t *bd)
  76{
  77        struct ftmac100 *ftmac100 = (struct ftmac100 *)dev->iobase;
  78        struct ftmac100_data *priv = dev->priv;
  79        struct ftmac100_txdes *txdes = priv->txdes;
  80        struct ftmac100_rxdes *rxdes = priv->rxdes;
  81        unsigned int maccr;
  82        int i;
  83
  84        debug ("%s()\n", __func__);
  85
  86        ftmac100_reset (dev);
  87
  88        /* set the ethernet address */
  89
  90        ftmac100_set_mac_from_env (dev);
  91
  92        /* disable all interrupts */
  93
  94        writel (0, &ftmac100->imr);
  95
  96        /* initialize descriptors */
  97
  98        priv->rx_index = 0;
  99
 100        txdes[0].txdes1                 = FTMAC100_TXDES1_EDOTR;
 101        rxdes[PKTBUFSRX - 1].rxdes1     = FTMAC100_RXDES1_EDORR;
 102
 103        for (i = 0; i < PKTBUFSRX; i++) {
 104                /* RXBUF_BADR */
 105                rxdes[i].rxdes2 = (unsigned int)net_rx_packets[i];
 106                rxdes[i].rxdes1 |= FTMAC100_RXDES1_RXBUF_SIZE (PKTSIZE_ALIGN);
 107                rxdes[i].rxdes0 = FTMAC100_RXDES0_RXDMA_OWN;
 108        }
 109
 110        /* transmit ring */
 111
 112        writel ((unsigned int)txdes, &ftmac100->txr_badr);
 113
 114        /* receive ring */
 115
 116        writel ((unsigned int)rxdes, &ftmac100->rxr_badr);
 117
 118        /* poll receive descriptor automatically */
 119
 120        writel (FTMAC100_APTC_RXPOLL_CNT (1), &ftmac100->aptc);
 121
 122        /* enable transmitter, receiver */
 123
 124        maccr = FTMAC100_MACCR_XMT_EN |
 125                FTMAC100_MACCR_RCV_EN |
 126                FTMAC100_MACCR_XDMA_EN |
 127                FTMAC100_MACCR_RDMA_EN |
 128                FTMAC100_MACCR_CRC_APD |
 129                FTMAC100_MACCR_ENRX_IN_HALFTX |
 130                FTMAC100_MACCR_RX_RUNT |
 131                FTMAC100_MACCR_RX_BROADPKT;
 132
 133        writel (maccr, &ftmac100->maccr);
 134
 135        return 0;
 136}
 137
 138/*
 139 * Get a data block via Ethernet
 140 */
 141static int ftmac100_recv (struct eth_device *dev)
 142{
 143        struct ftmac100_data *priv = dev->priv;
 144        struct ftmac100_rxdes *curr_des;
 145        unsigned short rxlen;
 146
 147        curr_des = &priv->rxdes[priv->rx_index];
 148
 149        if (curr_des->rxdes0 & FTMAC100_RXDES0_RXDMA_OWN)
 150                return -1;
 151
 152        if (curr_des->rxdes0 & (FTMAC100_RXDES0_RX_ERR |
 153                                FTMAC100_RXDES0_CRC_ERR |
 154                                FTMAC100_RXDES0_FTL |
 155                                FTMAC100_RXDES0_RUNT |
 156                                FTMAC100_RXDES0_RX_ODD_NB)) {
 157                return -1;
 158        }
 159
 160        rxlen = FTMAC100_RXDES0_RFL (curr_des->rxdes0);
 161
 162        debug ("%s(): RX buffer %d, %x received\n",
 163               __func__, priv->rx_index, rxlen);
 164
 165        /* pass the packet up to the protocol layers. */
 166
 167        net_process_received_packet((void *)curr_des->rxdes2, rxlen);
 168
 169        /* release buffer to DMA */
 170
 171        curr_des->rxdes0 |= FTMAC100_RXDES0_RXDMA_OWN;
 172
 173        priv->rx_index = (priv->rx_index + 1) % PKTBUFSRX;
 174
 175        return 0;
 176}
 177
 178/*
 179 * Send a data block via Ethernet
 180 */
 181static int ftmac100_send(struct eth_device *dev, void *packet, int length)
 182{
 183        struct ftmac100 *ftmac100 = (struct ftmac100 *)dev->iobase;
 184        struct ftmac100_data *priv = dev->priv;
 185        struct ftmac100_txdes *curr_des = priv->txdes;
 186        ulong start;
 187
 188        if (curr_des->txdes0 & FTMAC100_TXDES0_TXDMA_OWN) {
 189                debug ("%s(): no TX descriptor available\n", __func__);
 190                return -1;
 191        }
 192
 193        debug ("%s(%x, %x)\n", __func__, (int)packet, length);
 194
 195        length = (length < ETH_ZLEN) ? ETH_ZLEN : length;
 196
 197        /* initiate a transmit sequence */
 198
 199        curr_des->txdes2 = (unsigned int)packet;        /* TXBUF_BADR */
 200
 201        curr_des->txdes1 &= FTMAC100_TXDES1_EDOTR;
 202        curr_des->txdes1 |= FTMAC100_TXDES1_FTS |
 203                            FTMAC100_TXDES1_LTS |
 204                            FTMAC100_TXDES1_TXBUF_SIZE (length);
 205
 206        curr_des->txdes0 = FTMAC100_TXDES0_TXDMA_OWN;
 207
 208        /* start transmit */
 209
 210        writel (1, &ftmac100->txpd);
 211
 212        /* wait for transfer to succeed */
 213
 214        start = get_timer(0);
 215        while (curr_des->txdes0 & FTMAC100_TXDES0_TXDMA_OWN) {
 216                if (get_timer(start) >= 5) {
 217                        debug ("%s(): timed out\n", __func__);
 218                        return -1;
 219                }
 220        }
 221
 222        debug ("%s(): packet sent\n", __func__);
 223
 224        return 0;
 225}
 226
 227int ftmac100_initialize (bd_t *bd)
 228{
 229        struct eth_device *dev;
 230        struct ftmac100_data *priv;
 231
 232        dev = malloc (sizeof *dev);
 233        if (!dev) {
 234                printf ("%s(): failed to allocate dev\n", __func__);
 235                goto out;
 236        }
 237
 238        /* Transmit and receive descriptors should align to 16 bytes */
 239
 240        priv = memalign (16, sizeof (struct ftmac100_data));
 241        if (!priv) {
 242                printf ("%s(): failed to allocate priv\n", __func__);
 243                goto free_dev;
 244        }
 245
 246        memset (dev, 0, sizeof (*dev));
 247        memset (priv, 0, sizeof (*priv));
 248
 249        strcpy(dev->name, "FTMAC100");
 250        dev->iobase     = CONFIG_FTMAC100_BASE;
 251        dev->init       = ftmac100_init;
 252        dev->halt       = ftmac100_halt;
 253        dev->send       = ftmac100_send;
 254        dev->recv       = ftmac100_recv;
 255        dev->priv       = priv;
 256
 257        eth_register (dev);
 258
 259        return 1;
 260
 261free_dev:
 262        free (dev);
 263out:
 264        return 0;
 265}
 266