1750326e5SPo-Yu Chuang /* 2750326e5SPo-Yu Chuang * Faraday FTMAC100 Ethernet 3750326e5SPo-Yu Chuang * 4750326e5SPo-Yu Chuang * (C) Copyright 2009 Faraday Technology 5750326e5SPo-Yu Chuang * Po-Yu Chuang <ratbert@faraday-tech.com> 6750326e5SPo-Yu Chuang * 71a459660SWolfgang Denk * SPDX-License-Identifier: GPL-2.0+ 8750326e5SPo-Yu Chuang */ 9750326e5SPo-Yu Chuang 10750326e5SPo-Yu Chuang #include <config.h> 11750326e5SPo-Yu Chuang #include <common.h> 12750326e5SPo-Yu Chuang #include <malloc.h> 13750326e5SPo-Yu Chuang #include <net.h> 14750326e5SPo-Yu Chuang #include <asm/io.h> 15750326e5SPo-Yu Chuang 16750326e5SPo-Yu Chuang #include "ftmac100.h" 17750326e5SPo-Yu Chuang 18750326e5SPo-Yu Chuang #define ETH_ZLEN 60 19750326e5SPo-Yu Chuang 20750326e5SPo-Yu Chuang struct ftmac100_data { 216f6e6e09SPo-Yu Chuang struct ftmac100_txdes txdes[1]; 226f6e6e09SPo-Yu Chuang struct ftmac100_rxdes rxdes[PKTBUFSRX]; 23750326e5SPo-Yu Chuang int rx_index; 24750326e5SPo-Yu Chuang }; 25750326e5SPo-Yu Chuang 26750326e5SPo-Yu Chuang /* 27750326e5SPo-Yu Chuang * Reset MAC 28750326e5SPo-Yu Chuang */ 29750326e5SPo-Yu Chuang static void ftmac100_reset (struct eth_device *dev) 30750326e5SPo-Yu Chuang { 31750326e5SPo-Yu Chuang struct ftmac100 *ftmac100 = (struct ftmac100 *)dev->iobase; 32750326e5SPo-Yu Chuang 33750326e5SPo-Yu Chuang debug ("%s()\n", __func__); 34750326e5SPo-Yu Chuang 35750326e5SPo-Yu Chuang writel (FTMAC100_MACCR_SW_RST, &ftmac100->maccr); 36750326e5SPo-Yu Chuang 37750326e5SPo-Yu Chuang while (readl (&ftmac100->maccr) & FTMAC100_MACCR_SW_RST) 38750326e5SPo-Yu Chuang ; 39750326e5SPo-Yu Chuang } 40750326e5SPo-Yu Chuang 41750326e5SPo-Yu Chuang /* 42750326e5SPo-Yu Chuang * Set MAC address 43750326e5SPo-Yu Chuang */ 44750326e5SPo-Yu Chuang static void ftmac100_set_mac (struct eth_device *dev, const unsigned char *mac) 45750326e5SPo-Yu Chuang { 46750326e5SPo-Yu Chuang struct ftmac100 *ftmac100 = (struct ftmac100 *)dev->iobase; 47750326e5SPo-Yu Chuang unsigned int maddr = mac[0] << 8 | mac[1]; 48750326e5SPo-Yu Chuang unsigned int laddr = mac[2] << 24 | mac[3] << 16 | mac[4] << 8 | mac[5]; 49750326e5SPo-Yu Chuang 50750326e5SPo-Yu Chuang debug ("%s(%x %x)\n", __func__, maddr, laddr); 51750326e5SPo-Yu Chuang 52750326e5SPo-Yu Chuang writel (maddr, &ftmac100->mac_madr); 53750326e5SPo-Yu Chuang writel (laddr, &ftmac100->mac_ladr); 54750326e5SPo-Yu Chuang } 55750326e5SPo-Yu Chuang 56750326e5SPo-Yu Chuang static void ftmac100_set_mac_from_env (struct eth_device *dev) 57750326e5SPo-Yu Chuang { 58750326e5SPo-Yu Chuang eth_getenv_enetaddr ("ethaddr", dev->enetaddr); 59750326e5SPo-Yu Chuang 60750326e5SPo-Yu Chuang ftmac100_set_mac (dev, dev->enetaddr); 61750326e5SPo-Yu Chuang } 62750326e5SPo-Yu Chuang 63750326e5SPo-Yu Chuang /* 64750326e5SPo-Yu Chuang * disable transmitter, receiver 65750326e5SPo-Yu Chuang */ 66750326e5SPo-Yu Chuang static void ftmac100_halt (struct eth_device *dev) 67750326e5SPo-Yu Chuang { 68750326e5SPo-Yu Chuang struct ftmac100 *ftmac100 = (struct ftmac100 *)dev->iobase; 69750326e5SPo-Yu Chuang 70750326e5SPo-Yu Chuang debug ("%s()\n", __func__); 71750326e5SPo-Yu Chuang 72750326e5SPo-Yu Chuang writel (0, &ftmac100->maccr); 73750326e5SPo-Yu Chuang } 74750326e5SPo-Yu Chuang 75750326e5SPo-Yu Chuang static int ftmac100_init (struct eth_device *dev, bd_t *bd) 76750326e5SPo-Yu Chuang { 77750326e5SPo-Yu Chuang struct ftmac100 *ftmac100 = (struct ftmac100 *)dev->iobase; 78750326e5SPo-Yu Chuang struct ftmac100_data *priv = dev->priv; 796f6e6e09SPo-Yu Chuang struct ftmac100_txdes *txdes = priv->txdes; 806f6e6e09SPo-Yu Chuang struct ftmac100_rxdes *rxdes = priv->rxdes; 81750326e5SPo-Yu Chuang unsigned int maccr; 82750326e5SPo-Yu Chuang int i; 83750326e5SPo-Yu Chuang 84750326e5SPo-Yu Chuang debug ("%s()\n", __func__); 85750326e5SPo-Yu Chuang 86750326e5SPo-Yu Chuang ftmac100_reset (dev); 87750326e5SPo-Yu Chuang 88750326e5SPo-Yu Chuang /* set the ethernet address */ 89750326e5SPo-Yu Chuang 90750326e5SPo-Yu Chuang ftmac100_set_mac_from_env (dev); 91750326e5SPo-Yu Chuang 92750326e5SPo-Yu Chuang /* disable all interrupts */ 93750326e5SPo-Yu Chuang 94750326e5SPo-Yu Chuang writel (0, &ftmac100->imr); 95750326e5SPo-Yu Chuang 96750326e5SPo-Yu Chuang /* initialize descriptors */ 97750326e5SPo-Yu Chuang 98750326e5SPo-Yu Chuang priv->rx_index = 0; 99750326e5SPo-Yu Chuang 100750326e5SPo-Yu Chuang txdes[0].txdes1 = FTMAC100_TXDES1_EDOTR; 101750326e5SPo-Yu Chuang rxdes[PKTBUFSRX - 1].rxdes1 = FTMAC100_RXDES1_EDORR; 102750326e5SPo-Yu Chuang 103750326e5SPo-Yu Chuang for (i = 0; i < PKTBUFSRX; i++) { 104750326e5SPo-Yu Chuang /* RXBUF_BADR */ 105*1fd92db8SJoe Hershberger rxdes[i].rxdes2 = (unsigned int)net_rx_packets[i]; 106750326e5SPo-Yu Chuang rxdes[i].rxdes1 |= FTMAC100_RXDES1_RXBUF_SIZE (PKTSIZE_ALIGN); 107750326e5SPo-Yu Chuang rxdes[i].rxdes0 = FTMAC100_RXDES0_RXDMA_OWN; 108750326e5SPo-Yu Chuang } 109750326e5SPo-Yu Chuang 110750326e5SPo-Yu Chuang /* transmit ring */ 111750326e5SPo-Yu Chuang 112750326e5SPo-Yu Chuang writel ((unsigned int)txdes, &ftmac100->txr_badr); 113750326e5SPo-Yu Chuang 114750326e5SPo-Yu Chuang /* receive ring */ 115750326e5SPo-Yu Chuang 116750326e5SPo-Yu Chuang writel ((unsigned int)rxdes, &ftmac100->rxr_badr); 117750326e5SPo-Yu Chuang 118750326e5SPo-Yu Chuang /* poll receive descriptor automatically */ 119750326e5SPo-Yu Chuang 120750326e5SPo-Yu Chuang writel (FTMAC100_APTC_RXPOLL_CNT (1), &ftmac100->aptc); 121750326e5SPo-Yu Chuang 122750326e5SPo-Yu Chuang /* enable transmitter, receiver */ 123750326e5SPo-Yu Chuang 124750326e5SPo-Yu Chuang maccr = FTMAC100_MACCR_XMT_EN | 125750326e5SPo-Yu Chuang FTMAC100_MACCR_RCV_EN | 126750326e5SPo-Yu Chuang FTMAC100_MACCR_XDMA_EN | 127750326e5SPo-Yu Chuang FTMAC100_MACCR_RDMA_EN | 128750326e5SPo-Yu Chuang FTMAC100_MACCR_CRC_APD | 129750326e5SPo-Yu Chuang FTMAC100_MACCR_ENRX_IN_HALFTX | 130750326e5SPo-Yu Chuang FTMAC100_MACCR_RX_RUNT | 131750326e5SPo-Yu Chuang FTMAC100_MACCR_RX_BROADPKT; 132750326e5SPo-Yu Chuang 133750326e5SPo-Yu Chuang writel (maccr, &ftmac100->maccr); 134750326e5SPo-Yu Chuang 135750326e5SPo-Yu Chuang return 0; 136750326e5SPo-Yu Chuang } 137750326e5SPo-Yu Chuang 138750326e5SPo-Yu Chuang /* 139750326e5SPo-Yu Chuang * Get a data block via Ethernet 140750326e5SPo-Yu Chuang */ 141750326e5SPo-Yu Chuang static int ftmac100_recv (struct eth_device *dev) 142750326e5SPo-Yu Chuang { 143750326e5SPo-Yu Chuang struct ftmac100_data *priv = dev->priv; 1446f6e6e09SPo-Yu Chuang struct ftmac100_rxdes *curr_des; 145750326e5SPo-Yu Chuang unsigned short rxlen; 146750326e5SPo-Yu Chuang 147750326e5SPo-Yu Chuang curr_des = &priv->rxdes[priv->rx_index]; 148750326e5SPo-Yu Chuang 149750326e5SPo-Yu Chuang if (curr_des->rxdes0 & FTMAC100_RXDES0_RXDMA_OWN) 150750326e5SPo-Yu Chuang return -1; 151750326e5SPo-Yu Chuang 152750326e5SPo-Yu Chuang if (curr_des->rxdes0 & (FTMAC100_RXDES0_RX_ERR | 153750326e5SPo-Yu Chuang FTMAC100_RXDES0_CRC_ERR | 154750326e5SPo-Yu Chuang FTMAC100_RXDES0_FTL | 155750326e5SPo-Yu Chuang FTMAC100_RXDES0_RUNT | 156750326e5SPo-Yu Chuang FTMAC100_RXDES0_RX_ODD_NB)) { 157750326e5SPo-Yu Chuang return -1; 158750326e5SPo-Yu Chuang } 159750326e5SPo-Yu Chuang 160750326e5SPo-Yu Chuang rxlen = FTMAC100_RXDES0_RFL (curr_des->rxdes0); 161750326e5SPo-Yu Chuang 162750326e5SPo-Yu Chuang debug ("%s(): RX buffer %d, %x received\n", 163750326e5SPo-Yu Chuang __func__, priv->rx_index, rxlen); 164750326e5SPo-Yu Chuang 165750326e5SPo-Yu Chuang /* pass the packet up to the protocol layers. */ 166750326e5SPo-Yu Chuang 167*1fd92db8SJoe Hershberger net_process_received_packet((void *)curr_des->rxdes2, rxlen); 168750326e5SPo-Yu Chuang 169750326e5SPo-Yu Chuang /* release buffer to DMA */ 170750326e5SPo-Yu Chuang 171750326e5SPo-Yu Chuang curr_des->rxdes0 |= FTMAC100_RXDES0_RXDMA_OWN; 172750326e5SPo-Yu Chuang 173750326e5SPo-Yu Chuang priv->rx_index = (priv->rx_index + 1) % PKTBUFSRX; 174750326e5SPo-Yu Chuang 175750326e5SPo-Yu Chuang return 0; 176750326e5SPo-Yu Chuang } 177750326e5SPo-Yu Chuang 178750326e5SPo-Yu Chuang /* 179750326e5SPo-Yu Chuang * Send a data block via Ethernet 180750326e5SPo-Yu Chuang */ 18199ec7728SJoe Hershberger static int ftmac100_send(struct eth_device *dev, void *packet, int length) 182750326e5SPo-Yu Chuang { 183750326e5SPo-Yu Chuang struct ftmac100 *ftmac100 = (struct ftmac100 *)dev->iobase; 184750326e5SPo-Yu Chuang struct ftmac100_data *priv = dev->priv; 1856f6e6e09SPo-Yu Chuang struct ftmac100_txdes *curr_des = priv->txdes; 1868d8fd5b6SPo-Yu Chuang ulong start; 187750326e5SPo-Yu Chuang 188750326e5SPo-Yu Chuang if (curr_des->txdes0 & FTMAC100_TXDES0_TXDMA_OWN) { 189750326e5SPo-Yu Chuang debug ("%s(): no TX descriptor available\n", __func__); 190750326e5SPo-Yu Chuang return -1; 191750326e5SPo-Yu Chuang } 192750326e5SPo-Yu Chuang 193750326e5SPo-Yu Chuang debug ("%s(%x, %x)\n", __func__, (int)packet, length); 194750326e5SPo-Yu Chuang 195750326e5SPo-Yu Chuang length = (length < ETH_ZLEN) ? ETH_ZLEN : length; 196750326e5SPo-Yu Chuang 197750326e5SPo-Yu Chuang /* initiate a transmit sequence */ 198750326e5SPo-Yu Chuang 199750326e5SPo-Yu Chuang curr_des->txdes2 = (unsigned int)packet; /* TXBUF_BADR */ 200750326e5SPo-Yu Chuang 201750326e5SPo-Yu Chuang curr_des->txdes1 &= FTMAC100_TXDES1_EDOTR; 202750326e5SPo-Yu Chuang curr_des->txdes1 |= FTMAC100_TXDES1_FTS | 203750326e5SPo-Yu Chuang FTMAC100_TXDES1_LTS | 204750326e5SPo-Yu Chuang FTMAC100_TXDES1_TXBUF_SIZE (length); 205750326e5SPo-Yu Chuang 206750326e5SPo-Yu Chuang curr_des->txdes0 = FTMAC100_TXDES0_TXDMA_OWN; 207750326e5SPo-Yu Chuang 208750326e5SPo-Yu Chuang /* start transmit */ 209750326e5SPo-Yu Chuang 210750326e5SPo-Yu Chuang writel (1, &ftmac100->txpd); 211750326e5SPo-Yu Chuang 212750326e5SPo-Yu Chuang /* wait for transfer to succeed */ 213750326e5SPo-Yu Chuang 2148d8fd5b6SPo-Yu Chuang start = get_timer(0); 215750326e5SPo-Yu Chuang while (curr_des->txdes0 & FTMAC100_TXDES0_TXDMA_OWN) { 2168d8fd5b6SPo-Yu Chuang if (get_timer(start) >= 5) { 217750326e5SPo-Yu Chuang debug ("%s(): timed out\n", __func__); 218750326e5SPo-Yu Chuang return -1; 219750326e5SPo-Yu Chuang } 220750326e5SPo-Yu Chuang } 221750326e5SPo-Yu Chuang 222750326e5SPo-Yu Chuang debug ("%s(): packet sent\n", __func__); 223750326e5SPo-Yu Chuang 224750326e5SPo-Yu Chuang return 0; 225750326e5SPo-Yu Chuang } 226750326e5SPo-Yu Chuang 227750326e5SPo-Yu Chuang int ftmac100_initialize (bd_t *bd) 228750326e5SPo-Yu Chuang { 229750326e5SPo-Yu Chuang struct eth_device *dev; 230750326e5SPo-Yu Chuang struct ftmac100_data *priv; 231750326e5SPo-Yu Chuang 232750326e5SPo-Yu Chuang dev = malloc (sizeof *dev); 233750326e5SPo-Yu Chuang if (!dev) { 234750326e5SPo-Yu Chuang printf ("%s(): failed to allocate dev\n", __func__); 235750326e5SPo-Yu Chuang goto out; 236750326e5SPo-Yu Chuang } 237750326e5SPo-Yu Chuang 238750326e5SPo-Yu Chuang /* Transmit and receive descriptors should align to 16 bytes */ 239750326e5SPo-Yu Chuang 240750326e5SPo-Yu Chuang priv = memalign (16, sizeof (struct ftmac100_data)); 241750326e5SPo-Yu Chuang if (!priv) { 242750326e5SPo-Yu Chuang printf ("%s(): failed to allocate priv\n", __func__); 243750326e5SPo-Yu Chuang goto free_dev; 244750326e5SPo-Yu Chuang } 245750326e5SPo-Yu Chuang 246750326e5SPo-Yu Chuang memset (dev, 0, sizeof (*dev)); 247750326e5SPo-Yu Chuang memset (priv, 0, sizeof (*priv)); 248750326e5SPo-Yu Chuang 249750326e5SPo-Yu Chuang sprintf (dev->name, "FTMAC100"); 250750326e5SPo-Yu Chuang dev->iobase = CONFIG_FTMAC100_BASE; 251750326e5SPo-Yu Chuang dev->init = ftmac100_init; 252750326e5SPo-Yu Chuang dev->halt = ftmac100_halt; 253750326e5SPo-Yu Chuang dev->send = ftmac100_send; 254750326e5SPo-Yu Chuang dev->recv = ftmac100_recv; 255750326e5SPo-Yu Chuang dev->priv = priv; 256750326e5SPo-Yu Chuang 257750326e5SPo-Yu Chuang eth_register (dev); 258750326e5SPo-Yu Chuang 259750326e5SPo-Yu Chuang return 1; 260750326e5SPo-Yu Chuang 261750326e5SPo-Yu Chuang free_dev: 262750326e5SPo-Yu Chuang free (dev); 263750326e5SPo-Yu Chuang out: 264750326e5SPo-Yu Chuang return 0; 265750326e5SPo-Yu Chuang } 266