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