uboot/drivers/net/ftmac100.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Faraday FTMAC100 Ethernet
   4 *
   5 * (C) Copyright 2009 Faraday Technology
   6 * Po-Yu Chuang <ratbert@faraday-tech.com>
   7 */
   8
   9#include <config.h>
  10#include <common.h>
  11#include <cpu_func.h>
  12#include <env.h>
  13#include <malloc.h>
  14#include <net.h>
  15#include <linux/delay.h>
  16#include <linux/io.h>
  17
  18#include "ftmac100.h"
  19#ifdef CONFIG_DM_ETH
  20#include <dm.h>
  21DECLARE_GLOBAL_DATA_PTR;
  22#endif
  23#define ETH_ZLEN        60
  24
  25struct ftmac100_data {
  26        struct ftmac100_txdes txdes[1];
  27        struct ftmac100_rxdes rxdes[PKTBUFSRX];
  28        int rx_index;
  29        const char *name;
  30        phys_addr_t iobase;
  31};
  32
  33/*
  34 * Reset MAC
  35 */
  36static void ftmac100_reset(struct ftmac100_data *priv)
  37{
  38        struct ftmac100 *ftmac100 = (struct ftmac100 *)priv->iobase;
  39
  40        debug ("%s()\n", __func__);
  41
  42        writel (FTMAC100_MACCR_SW_RST, &ftmac100->maccr);
  43
  44        while (readl (&ftmac100->maccr) & FTMAC100_MACCR_SW_RST)
  45                mdelay(1);
  46        /*
  47         * When soft reset complete, write mac address immediately maybe fail somehow
  48         *  Wait for a while can avoid this problem
  49         */
  50        mdelay(1);
  51}
  52
  53/*
  54 * Set MAC address
  55 */
  56static void ftmac100_set_mac(struct ftmac100_data *priv ,
  57        const unsigned char *mac)
  58{
  59        struct ftmac100 *ftmac100 = (struct ftmac100 *)priv->iobase;
  60        unsigned int maddr = mac[0] << 8 | mac[1];
  61        unsigned int laddr = mac[2] << 24 | mac[3] << 16 | mac[4] << 8 | mac[5];
  62
  63        debug ("%s(%x %x)\n", __func__, maddr, laddr);
  64
  65        writel (maddr, &ftmac100->mac_madr);
  66        writel (laddr, &ftmac100->mac_ladr);
  67}
  68
  69/*
  70 * Disable MAC
  71 */
  72static void _ftmac100_halt(struct ftmac100_data *priv)
  73{
  74        struct ftmac100 *ftmac100 = (struct ftmac100 *)priv->iobase;
  75        debug ("%s()\n", __func__);
  76        writel (0, &ftmac100->maccr);
  77}
  78
  79/*
  80 * Initialize MAC
  81 */
  82static int _ftmac100_init(struct ftmac100_data *priv, unsigned char enetaddr[6])
  83{
  84        struct ftmac100 *ftmac100 = (struct ftmac100 *)priv->iobase;
  85        struct ftmac100_txdes *txdes = priv->txdes;
  86        struct ftmac100_rxdes *rxdes = priv->rxdes;
  87        unsigned int maccr;
  88        int i;
  89        debug ("%s()\n", __func__);
  90
  91        ftmac100_reset(priv);
  92
  93        /* set the ethernet address */
  94        ftmac100_set_mac(priv, enetaddr);
  95
  96
  97        /* disable all interrupts */
  98
  99        writel (0, &ftmac100->imr);
 100
 101        /* initialize descriptors */
 102
 103        priv->rx_index = 0;
 104
 105        txdes[0].txdes1                 = FTMAC100_TXDES1_EDOTR;
 106        rxdes[PKTBUFSRX - 1].rxdes1     = FTMAC100_RXDES1_EDORR;
 107
 108        for (i = 0; i < PKTBUFSRX; i++) {
 109                /* RXBUF_BADR */
 110                rxdes[i].rxdes2 = (unsigned int)(unsigned long)net_rx_packets[i];
 111                rxdes[i].rxdes1 |= FTMAC100_RXDES1_RXBUF_SIZE (PKTSIZE_ALIGN);
 112                rxdes[i].rxdes0 = FTMAC100_RXDES0_RXDMA_OWN;
 113        }
 114
 115        /* transmit ring */
 116
 117        writel ((unsigned long)txdes, &ftmac100->txr_badr);
 118
 119        /* receive ring */
 120
 121        writel ((unsigned long)rxdes, &ftmac100->rxr_badr);
 122
 123        /* poll receive descriptor automatically */
 124
 125        writel (FTMAC100_APTC_RXPOLL_CNT (1), &ftmac100->aptc);
 126
 127        /* enable transmitter, receiver */
 128
 129        maccr = FTMAC100_MACCR_XMT_EN |
 130                FTMAC100_MACCR_RCV_EN |
 131                FTMAC100_MACCR_XDMA_EN |
 132                FTMAC100_MACCR_RDMA_EN |
 133                FTMAC100_MACCR_CRC_APD |
 134                FTMAC100_MACCR_ENRX_IN_HALFTX |
 135                FTMAC100_MACCR_RX_RUNT |
 136                FTMAC100_MACCR_RX_BROADPKT;
 137
 138        writel (maccr, &ftmac100->maccr);
 139
 140        return 0;
 141}
 142
 143/*
 144 * Free receiving buffer
 145 */
 146static int _ftmac100_free_pkt(struct ftmac100_data *priv)
 147{
 148        struct ftmac100_rxdes *curr_des;
 149        curr_des = &priv->rxdes[priv->rx_index];
 150        /* release buffer to DMA */
 151        curr_des->rxdes0 |= FTMAC100_RXDES0_RXDMA_OWN;
 152        priv->rx_index = (priv->rx_index + 1) % PKTBUFSRX;
 153        return 0;
 154}
 155
 156/*
 157 * Receive a data block via Ethernet
 158 */
 159static int __ftmac100_recv(struct ftmac100_data *priv)
 160{
 161        struct ftmac100_rxdes *curr_des;
 162        unsigned short rxlen;
 163
 164        curr_des = &priv->rxdes[priv->rx_index];
 165        if (curr_des->rxdes0 & FTMAC100_RXDES0_RXDMA_OWN)
 166                return 0;
 167
 168        if (curr_des->rxdes0 & (FTMAC100_RXDES0_RX_ERR |
 169                                FTMAC100_RXDES0_CRC_ERR |
 170                                FTMAC100_RXDES0_FTL |
 171                                FTMAC100_RXDES0_RUNT |
 172                                FTMAC100_RXDES0_RX_ODD_NB)) {
 173                return 0;
 174        }
 175
 176        rxlen = FTMAC100_RXDES0_RFL (curr_des->rxdes0);
 177        invalidate_dcache_range(curr_des->rxdes2,curr_des->rxdes2+rxlen);
 178        debug ("%s(): RX buffer %d, %x received\n",
 179               __func__, priv->rx_index, rxlen);
 180
 181        return rxlen;
 182}
 183
 184/*
 185 * Send a data block via Ethernet
 186 */
 187static int _ftmac100_send(struct ftmac100_data *priv, void *packet, int length)
 188{
 189        struct ftmac100 *ftmac100 = (struct ftmac100 *)priv->iobase;
 190        struct ftmac100_txdes *curr_des = priv->txdes;
 191        ulong start;
 192
 193        if (curr_des->txdes0 & FTMAC100_TXDES0_TXDMA_OWN) {
 194                debug ("%s(): no TX descriptor available\n", __func__);
 195                return -1;
 196        }
 197
 198        debug ("%s(%lx, %x)\n", __func__, (unsigned long)packet, length);
 199
 200        length = (length < ETH_ZLEN) ? ETH_ZLEN : length;
 201
 202        /* initiate a transmit sequence */
 203
 204        flush_dcache_range((unsigned long)packet,(unsigned long)packet+length);
 205        curr_des->txdes2 = (unsigned int)(unsigned long)packet; /* TXBUF_BADR */
 206
 207        curr_des->txdes1 &= FTMAC100_TXDES1_EDOTR;
 208        curr_des->txdes1 |= FTMAC100_TXDES1_FTS |
 209                            FTMAC100_TXDES1_LTS |
 210                            FTMAC100_TXDES1_TXBUF_SIZE (length);
 211
 212        curr_des->txdes0 = FTMAC100_TXDES0_TXDMA_OWN;
 213
 214        /* start transmit */
 215
 216        writel (1, &ftmac100->txpd);
 217
 218        /* wait for transfer to succeed */
 219
 220        start = get_timer(0);
 221        while (curr_des->txdes0 & FTMAC100_TXDES0_TXDMA_OWN) {
 222                if (get_timer(start) >= 5) {
 223                        debug ("%s(): timed out\n", __func__);
 224                        return -1;
 225                }
 226        }
 227
 228        debug ("%s(): packet sent\n", __func__);
 229
 230        return 0;
 231}
 232
 233#ifndef CONFIG_DM_ETH
 234/*
 235 * disable transmitter, receiver
 236 */
 237static void ftmac100_halt(struct eth_device *dev)
 238{
 239        struct ftmac100_data *priv = dev->priv;
 240        return _ftmac100_halt(priv);
 241}
 242
 243static int ftmac100_init(struct eth_device *dev, struct bd_info *bd)
 244{
 245        struct ftmac100_data *priv = dev->priv;
 246        return _ftmac100_init(priv , dev->enetaddr);
 247}
 248
 249static int _ftmac100_recv(struct ftmac100_data *priv)
 250{
 251        struct ftmac100_rxdes *curr_des;
 252        unsigned short len;
 253        curr_des = &priv->rxdes[priv->rx_index];
 254        len = __ftmac100_recv(priv);
 255        if (len) {
 256                /* pass the packet up to the protocol layers. */
 257                net_process_received_packet((void *)curr_des->rxdes2, len);
 258                _ftmac100_free_pkt(priv);
 259        }
 260        return len ? 1 : 0;
 261}
 262
 263/*
 264 * Get a data block via Ethernet
 265 */
 266static int ftmac100_recv(struct eth_device *dev)
 267{
 268        struct ftmac100_data *priv = dev->priv;
 269        return _ftmac100_recv(priv);
 270}
 271
 272/*
 273 * Send a data block via Ethernet
 274 */
 275static int ftmac100_send(struct eth_device *dev, void *packet, int length)
 276{
 277        struct ftmac100_data *priv = dev->priv;
 278        return _ftmac100_send(priv , packet , length);
 279}
 280
 281int ftmac100_initialize (struct bd_info *bd)
 282{
 283        struct eth_device *dev;
 284        struct ftmac100_data *priv;
 285        dev = malloc (sizeof *dev);
 286        if (!dev) {
 287                printf ("%s(): failed to allocate dev\n", __func__);
 288                goto out;
 289        }
 290        /* Transmit and receive descriptors should align to 16 bytes */
 291        priv = memalign (16, sizeof (struct ftmac100_data));
 292        if (!priv) {
 293                printf ("%s(): failed to allocate priv\n", __func__);
 294                goto free_dev;
 295        }
 296        memset (dev, 0, sizeof (*dev));
 297        memset (priv, 0, sizeof (*priv));
 298
 299        strcpy(dev->name, "FTMAC100");
 300        dev->iobase     = CONFIG_FTMAC100_BASE;
 301        dev->init       = ftmac100_init;
 302        dev->halt       = ftmac100_halt;
 303        dev->send       = ftmac100_send;
 304        dev->recv       = ftmac100_recv;
 305        dev->priv       = priv;
 306        priv->iobase    = dev->iobase;
 307        eth_register (dev);
 308
 309        return 1;
 310
 311free_dev:
 312        free (dev);
 313out:
 314        return 0;
 315}
 316#endif
 317
 318#ifdef CONFIG_DM_ETH
 319static int ftmac100_start(struct udevice *dev)
 320{
 321        struct eth_pdata *plat = dev_get_platdata(dev);
 322        struct ftmac100_data *priv = dev_get_priv(dev);
 323
 324        return _ftmac100_init(priv, plat->enetaddr);
 325}
 326
 327static void ftmac100_stop(struct udevice *dev)
 328{
 329        struct ftmac100_data *priv = dev_get_priv(dev);
 330        _ftmac100_halt(priv);
 331}
 332
 333static int ftmac100_send(struct udevice *dev, void *packet, int length)
 334{
 335        struct ftmac100_data *priv = dev_get_priv(dev);
 336        int ret;
 337        ret = _ftmac100_send(priv , packet , length);
 338        return ret ? 0 : -ETIMEDOUT;
 339}
 340
 341static int ftmac100_recv(struct udevice *dev, int flags, uchar **packetp)
 342{
 343        struct ftmac100_data *priv = dev_get_priv(dev);
 344        struct ftmac100_rxdes *curr_des;
 345        curr_des = &priv->rxdes[priv->rx_index];
 346        int len;
 347        len = __ftmac100_recv(priv);
 348        if (len)
 349                *packetp = (uchar *)(unsigned long)curr_des->rxdes2;
 350
 351        return len ? len : -EAGAIN;
 352}
 353
 354static int ftmac100_free_pkt(struct udevice *dev, uchar *packet, int length)
 355{
 356        struct ftmac100_data *priv = dev_get_priv(dev);
 357        _ftmac100_free_pkt(priv);
 358        return 0;
 359}
 360
 361int ftmac100_read_rom_hwaddr(struct udevice *dev)
 362{
 363        struct eth_pdata *pdata = dev_get_platdata(dev);
 364        eth_env_get_enetaddr("ethaddr", pdata->enetaddr);
 365        return 0;
 366}
 367
 368static const char *dtbmacaddr(u32 ifno)
 369{
 370        int node, len;
 371        char enet[16];
 372        const char *mac;
 373        const char *path;
 374        if (gd->fdt_blob == NULL) {
 375                printf("%s: don't have a valid gd->fdt_blob!\n", __func__);
 376                return NULL;
 377        }
 378        node = fdt_path_offset(gd->fdt_blob, "/aliases");
 379        if (node < 0)
 380                return NULL;
 381
 382        sprintf(enet, "ethernet%d", ifno);
 383        path = fdt_getprop(gd->fdt_blob, node, enet, NULL);
 384        if (!path) {
 385                printf("no alias for %s\n", enet);
 386                return NULL;
 387        }
 388        node = fdt_path_offset(gd->fdt_blob, path);
 389        mac = fdt_getprop(gd->fdt_blob, node, "mac-address", &len);
 390        if (mac && is_valid_ethaddr((u8 *)mac))
 391                return mac;
 392
 393        return NULL;
 394}
 395
 396static int ftmac100_ofdata_to_platdata(struct udevice *dev)
 397{
 398        struct ftmac100_data *priv = dev_get_priv(dev);
 399        struct eth_pdata *pdata = dev_get_platdata(dev);
 400        const char *mac;
 401        pdata->iobase = dev_read_addr(dev);
 402        priv->iobase = pdata->iobase;
 403        mac = dtbmacaddr(0);
 404        if (mac)
 405                memcpy(pdata->enetaddr , mac , 6);
 406
 407        return 0;
 408}
 409
 410static int ftmac100_probe(struct udevice *dev)
 411{
 412        struct ftmac100_data *priv = dev_get_priv(dev);
 413        priv->name = dev->name;
 414        return 0;
 415}
 416
 417static int ftmac100_bind(struct udevice *dev)
 418{
 419        return device_set_name(dev, dev->name);
 420}
 421
 422static const struct eth_ops ftmac100_ops = {
 423        .start  = ftmac100_start,
 424        .send   = ftmac100_send,
 425        .recv   = ftmac100_recv,
 426        .stop   = ftmac100_stop,
 427        .free_pkt = ftmac100_free_pkt,
 428};
 429
 430static const struct udevice_id ftmac100_ids[] = {
 431        { .compatible = "andestech,atmac100" },
 432        { }
 433};
 434
 435U_BOOT_DRIVER(ftmac100) = {
 436        .name   = "nds32_mac",
 437        .id     = UCLASS_ETH,
 438        .of_match = ftmac100_ids,
 439        .bind   = ftmac100_bind,
 440        .ofdata_to_platdata = ftmac100_ofdata_to_platdata,
 441        .probe  = ftmac100_probe,
 442        .ops    = &ftmac100_ops,
 443        .priv_auto_alloc_size = sizeof(struct ftmac100_data),
 444        .platdata_auto_alloc_size = sizeof(struct eth_pdata),
 445        .flags  = DM_FLAG_ALLOC_PRIV_DMA,
 446};
 447#endif
 448