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 * 7750326e5SPo-Yu Chuang * This program is free software; you can redistribute it and/or modify 8750326e5SPo-Yu Chuang * it under the terms of the GNU General Public License as published by 9750326e5SPo-Yu Chuang * the Free Software Foundation; either version 2 of the License, or 10750326e5SPo-Yu Chuang * (at your option) any later version. 11750326e5SPo-Yu Chuang * 12750326e5SPo-Yu Chuang * This program is distributed in the hope that it will be useful, 13750326e5SPo-Yu Chuang * but WITHOUT ANY WARRANTY; without even the implied warranty of 14750326e5SPo-Yu Chuang * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15750326e5SPo-Yu Chuang * GNU General Public License for more details. 16750326e5SPo-Yu Chuang * 17750326e5SPo-Yu Chuang * You should have received a copy of the GNU General Public License 18750326e5SPo-Yu Chuang * along with this program; if not, write to the Free Software 19750326e5SPo-Yu Chuang * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 20750326e5SPo-Yu Chuang */ 21750326e5SPo-Yu Chuang 22750326e5SPo-Yu Chuang #include <config.h> 23750326e5SPo-Yu Chuang #include <common.h> 24750326e5SPo-Yu Chuang #include <malloc.h> 25750326e5SPo-Yu Chuang #include <net.h> 26750326e5SPo-Yu Chuang #include <asm/io.h> 27750326e5SPo-Yu Chuang 28750326e5SPo-Yu Chuang #include "ftmac100.h" 29750326e5SPo-Yu Chuang 30750326e5SPo-Yu Chuang #define ETH_ZLEN 60 31750326e5SPo-Yu Chuang 32750326e5SPo-Yu Chuang struct ftmac100_data { 336f6e6e09SPo-Yu Chuang struct ftmac100_txdes txdes[1]; 346f6e6e09SPo-Yu Chuang struct ftmac100_rxdes rxdes[PKTBUFSRX]; 35750326e5SPo-Yu Chuang int rx_index; 36750326e5SPo-Yu Chuang }; 37750326e5SPo-Yu Chuang 38750326e5SPo-Yu Chuang /* 39750326e5SPo-Yu Chuang * Reset MAC 40750326e5SPo-Yu Chuang */ 41750326e5SPo-Yu Chuang static void ftmac100_reset (struct eth_device *dev) 42750326e5SPo-Yu Chuang { 43750326e5SPo-Yu Chuang struct ftmac100 *ftmac100 = (struct ftmac100 *)dev->iobase; 44750326e5SPo-Yu Chuang 45750326e5SPo-Yu Chuang debug ("%s()\n", __func__); 46750326e5SPo-Yu Chuang 47750326e5SPo-Yu Chuang writel (FTMAC100_MACCR_SW_RST, &ftmac100->maccr); 48750326e5SPo-Yu Chuang 49750326e5SPo-Yu Chuang while (readl (&ftmac100->maccr) & FTMAC100_MACCR_SW_RST) 50750326e5SPo-Yu Chuang ; 51750326e5SPo-Yu Chuang } 52750326e5SPo-Yu Chuang 53750326e5SPo-Yu Chuang /* 54750326e5SPo-Yu Chuang * Set MAC address 55750326e5SPo-Yu Chuang */ 56750326e5SPo-Yu Chuang static void ftmac100_set_mac (struct eth_device *dev, const unsigned char *mac) 57750326e5SPo-Yu Chuang { 58750326e5SPo-Yu Chuang struct ftmac100 *ftmac100 = (struct ftmac100 *)dev->iobase; 59750326e5SPo-Yu Chuang unsigned int maddr = mac[0] << 8 | mac[1]; 60750326e5SPo-Yu Chuang unsigned int laddr = mac[2] << 24 | mac[3] << 16 | mac[4] << 8 | mac[5]; 61750326e5SPo-Yu Chuang 62750326e5SPo-Yu Chuang debug ("%s(%x %x)\n", __func__, maddr, laddr); 63750326e5SPo-Yu Chuang 64750326e5SPo-Yu Chuang writel (maddr, &ftmac100->mac_madr); 65750326e5SPo-Yu Chuang writel (laddr, &ftmac100->mac_ladr); 66750326e5SPo-Yu Chuang } 67750326e5SPo-Yu Chuang 68750326e5SPo-Yu Chuang static void ftmac100_set_mac_from_env (struct eth_device *dev) 69750326e5SPo-Yu Chuang { 70750326e5SPo-Yu Chuang eth_getenv_enetaddr ("ethaddr", dev->enetaddr); 71750326e5SPo-Yu Chuang 72750326e5SPo-Yu Chuang ftmac100_set_mac (dev, dev->enetaddr); 73750326e5SPo-Yu Chuang } 74750326e5SPo-Yu Chuang 75750326e5SPo-Yu Chuang /* 76750326e5SPo-Yu Chuang * disable transmitter, receiver 77750326e5SPo-Yu Chuang */ 78750326e5SPo-Yu Chuang static void ftmac100_halt (struct eth_device *dev) 79750326e5SPo-Yu Chuang { 80750326e5SPo-Yu Chuang struct ftmac100 *ftmac100 = (struct ftmac100 *)dev->iobase; 81750326e5SPo-Yu Chuang 82750326e5SPo-Yu Chuang debug ("%s()\n", __func__); 83750326e5SPo-Yu Chuang 84750326e5SPo-Yu Chuang writel (0, &ftmac100->maccr); 85750326e5SPo-Yu Chuang } 86750326e5SPo-Yu Chuang 87750326e5SPo-Yu Chuang static int ftmac100_init (struct eth_device *dev, bd_t *bd) 88750326e5SPo-Yu Chuang { 89750326e5SPo-Yu Chuang struct ftmac100 *ftmac100 = (struct ftmac100 *)dev->iobase; 90750326e5SPo-Yu Chuang struct ftmac100_data *priv = dev->priv; 916f6e6e09SPo-Yu Chuang struct ftmac100_txdes *txdes = priv->txdes; 926f6e6e09SPo-Yu Chuang struct ftmac100_rxdes *rxdes = priv->rxdes; 93750326e5SPo-Yu Chuang unsigned int maccr; 94750326e5SPo-Yu Chuang int i; 95750326e5SPo-Yu Chuang 96750326e5SPo-Yu Chuang debug ("%s()\n", __func__); 97750326e5SPo-Yu Chuang 98750326e5SPo-Yu Chuang ftmac100_reset (dev); 99750326e5SPo-Yu Chuang 100750326e5SPo-Yu Chuang /* set the ethernet address */ 101750326e5SPo-Yu Chuang 102750326e5SPo-Yu Chuang ftmac100_set_mac_from_env (dev); 103750326e5SPo-Yu Chuang 104750326e5SPo-Yu Chuang /* disable all interrupts */ 105750326e5SPo-Yu Chuang 106750326e5SPo-Yu Chuang writel (0, &ftmac100->imr); 107750326e5SPo-Yu Chuang 108750326e5SPo-Yu Chuang /* initialize descriptors */ 109750326e5SPo-Yu Chuang 110750326e5SPo-Yu Chuang priv->rx_index = 0; 111750326e5SPo-Yu Chuang 112750326e5SPo-Yu Chuang txdes[0].txdes1 = FTMAC100_TXDES1_EDOTR; 113750326e5SPo-Yu Chuang rxdes[PKTBUFSRX - 1].rxdes1 = FTMAC100_RXDES1_EDORR; 114750326e5SPo-Yu Chuang 115750326e5SPo-Yu Chuang for (i = 0; i < PKTBUFSRX; i++) { 116750326e5SPo-Yu Chuang /* RXBUF_BADR */ 117750326e5SPo-Yu Chuang rxdes[i].rxdes2 = (unsigned int)NetRxPackets[i]; 118750326e5SPo-Yu Chuang rxdes[i].rxdes1 |= FTMAC100_RXDES1_RXBUF_SIZE (PKTSIZE_ALIGN); 119750326e5SPo-Yu Chuang rxdes[i].rxdes0 = FTMAC100_RXDES0_RXDMA_OWN; 120750326e5SPo-Yu Chuang } 121750326e5SPo-Yu Chuang 122750326e5SPo-Yu Chuang /* transmit ring */ 123750326e5SPo-Yu Chuang 124750326e5SPo-Yu Chuang writel ((unsigned int)txdes, &ftmac100->txr_badr); 125750326e5SPo-Yu Chuang 126750326e5SPo-Yu Chuang /* receive ring */ 127750326e5SPo-Yu Chuang 128750326e5SPo-Yu Chuang writel ((unsigned int)rxdes, &ftmac100->rxr_badr); 129750326e5SPo-Yu Chuang 130750326e5SPo-Yu Chuang /* poll receive descriptor automatically */ 131750326e5SPo-Yu Chuang 132750326e5SPo-Yu Chuang writel (FTMAC100_APTC_RXPOLL_CNT (1), &ftmac100->aptc); 133750326e5SPo-Yu Chuang 134750326e5SPo-Yu Chuang /* enable transmitter, receiver */ 135750326e5SPo-Yu Chuang 136750326e5SPo-Yu Chuang maccr = FTMAC100_MACCR_XMT_EN | 137750326e5SPo-Yu Chuang FTMAC100_MACCR_RCV_EN | 138750326e5SPo-Yu Chuang FTMAC100_MACCR_XDMA_EN | 139750326e5SPo-Yu Chuang FTMAC100_MACCR_RDMA_EN | 140750326e5SPo-Yu Chuang FTMAC100_MACCR_CRC_APD | 141750326e5SPo-Yu Chuang FTMAC100_MACCR_ENRX_IN_HALFTX | 142750326e5SPo-Yu Chuang FTMAC100_MACCR_RX_RUNT | 143750326e5SPo-Yu Chuang FTMAC100_MACCR_RX_BROADPKT; 144750326e5SPo-Yu Chuang 145750326e5SPo-Yu Chuang writel (maccr, &ftmac100->maccr); 146750326e5SPo-Yu Chuang 147750326e5SPo-Yu Chuang return 0; 148750326e5SPo-Yu Chuang } 149750326e5SPo-Yu Chuang 150750326e5SPo-Yu Chuang /* 151750326e5SPo-Yu Chuang * Get a data block via Ethernet 152750326e5SPo-Yu Chuang */ 153750326e5SPo-Yu Chuang static int ftmac100_recv (struct eth_device *dev) 154750326e5SPo-Yu Chuang { 155750326e5SPo-Yu Chuang struct ftmac100_data *priv = dev->priv; 1566f6e6e09SPo-Yu Chuang struct ftmac100_rxdes *curr_des; 157750326e5SPo-Yu Chuang unsigned short rxlen; 158750326e5SPo-Yu Chuang 159750326e5SPo-Yu Chuang curr_des = &priv->rxdes[priv->rx_index]; 160750326e5SPo-Yu Chuang 161750326e5SPo-Yu Chuang if (curr_des->rxdes0 & FTMAC100_RXDES0_RXDMA_OWN) 162750326e5SPo-Yu Chuang return -1; 163750326e5SPo-Yu Chuang 164750326e5SPo-Yu Chuang if (curr_des->rxdes0 & (FTMAC100_RXDES0_RX_ERR | 165750326e5SPo-Yu Chuang FTMAC100_RXDES0_CRC_ERR | 166750326e5SPo-Yu Chuang FTMAC100_RXDES0_FTL | 167750326e5SPo-Yu Chuang FTMAC100_RXDES0_RUNT | 168750326e5SPo-Yu Chuang FTMAC100_RXDES0_RX_ODD_NB)) { 169750326e5SPo-Yu Chuang return -1; 170750326e5SPo-Yu Chuang } 171750326e5SPo-Yu Chuang 172750326e5SPo-Yu Chuang rxlen = FTMAC100_RXDES0_RFL (curr_des->rxdes0); 173750326e5SPo-Yu Chuang 174750326e5SPo-Yu Chuang debug ("%s(): RX buffer %d, %x received\n", 175750326e5SPo-Yu Chuang __func__, priv->rx_index, rxlen); 176750326e5SPo-Yu Chuang 177750326e5SPo-Yu Chuang /* pass the packet up to the protocol layers. */ 178750326e5SPo-Yu Chuang 179750326e5SPo-Yu Chuang NetReceive ((void *)curr_des->rxdes2, rxlen); 180750326e5SPo-Yu Chuang 181750326e5SPo-Yu Chuang /* release buffer to DMA */ 182750326e5SPo-Yu Chuang 183750326e5SPo-Yu Chuang curr_des->rxdes0 |= FTMAC100_RXDES0_RXDMA_OWN; 184750326e5SPo-Yu Chuang 185750326e5SPo-Yu Chuang priv->rx_index = (priv->rx_index + 1) % PKTBUFSRX; 186750326e5SPo-Yu Chuang 187750326e5SPo-Yu Chuang return 0; 188750326e5SPo-Yu Chuang } 189750326e5SPo-Yu Chuang 190750326e5SPo-Yu Chuang /* 191750326e5SPo-Yu Chuang * Send a data block via Ethernet 192750326e5SPo-Yu Chuang */ 193750326e5SPo-Yu Chuang static int 194750326e5SPo-Yu Chuang ftmac100_send (struct eth_device *dev, volatile void *packet, int length) 195750326e5SPo-Yu Chuang { 196750326e5SPo-Yu Chuang struct ftmac100 *ftmac100 = (struct ftmac100 *)dev->iobase; 197750326e5SPo-Yu Chuang struct ftmac100_data *priv = dev->priv; 1986f6e6e09SPo-Yu Chuang struct ftmac100_txdes *curr_des = priv->txdes; 199*8d8fd5b6SPo-Yu Chuang ulong start; 200750326e5SPo-Yu Chuang 201750326e5SPo-Yu Chuang if (curr_des->txdes0 & FTMAC100_TXDES0_TXDMA_OWN) { 202750326e5SPo-Yu Chuang debug ("%s(): no TX descriptor available\n", __func__); 203750326e5SPo-Yu Chuang return -1; 204750326e5SPo-Yu Chuang } 205750326e5SPo-Yu Chuang 206750326e5SPo-Yu Chuang debug ("%s(%x, %x)\n", __func__, (int)packet, length); 207750326e5SPo-Yu Chuang 208750326e5SPo-Yu Chuang length = (length < ETH_ZLEN) ? ETH_ZLEN : length; 209750326e5SPo-Yu Chuang 210750326e5SPo-Yu Chuang /* initiate a transmit sequence */ 211750326e5SPo-Yu Chuang 212750326e5SPo-Yu Chuang curr_des->txdes2 = (unsigned int)packet; /* TXBUF_BADR */ 213750326e5SPo-Yu Chuang 214750326e5SPo-Yu Chuang curr_des->txdes1 &= FTMAC100_TXDES1_EDOTR; 215750326e5SPo-Yu Chuang curr_des->txdes1 |= FTMAC100_TXDES1_FTS | 216750326e5SPo-Yu Chuang FTMAC100_TXDES1_LTS | 217750326e5SPo-Yu Chuang FTMAC100_TXDES1_TXBUF_SIZE (length); 218750326e5SPo-Yu Chuang 219750326e5SPo-Yu Chuang curr_des->txdes0 = FTMAC100_TXDES0_TXDMA_OWN; 220750326e5SPo-Yu Chuang 221750326e5SPo-Yu Chuang /* start transmit */ 222750326e5SPo-Yu Chuang 223750326e5SPo-Yu Chuang writel (1, &ftmac100->txpd); 224750326e5SPo-Yu Chuang 225750326e5SPo-Yu Chuang /* wait for transfer to succeed */ 226750326e5SPo-Yu Chuang 227*8d8fd5b6SPo-Yu Chuang start = get_timer(0); 228750326e5SPo-Yu Chuang while (curr_des->txdes0 & FTMAC100_TXDES0_TXDMA_OWN) { 229*8d8fd5b6SPo-Yu Chuang if (get_timer(start) >= 5) { 230750326e5SPo-Yu Chuang debug ("%s(): timed out\n", __func__); 231750326e5SPo-Yu Chuang return -1; 232750326e5SPo-Yu Chuang } 233750326e5SPo-Yu Chuang } 234750326e5SPo-Yu Chuang 235750326e5SPo-Yu Chuang debug ("%s(): packet sent\n", __func__); 236750326e5SPo-Yu Chuang 237750326e5SPo-Yu Chuang return 0; 238750326e5SPo-Yu Chuang } 239750326e5SPo-Yu Chuang 240750326e5SPo-Yu Chuang int ftmac100_initialize (bd_t *bd) 241750326e5SPo-Yu Chuang { 242750326e5SPo-Yu Chuang struct eth_device *dev; 243750326e5SPo-Yu Chuang struct ftmac100_data *priv; 244750326e5SPo-Yu Chuang 245750326e5SPo-Yu Chuang dev = malloc (sizeof *dev); 246750326e5SPo-Yu Chuang if (!dev) { 247750326e5SPo-Yu Chuang printf ("%s(): failed to allocate dev\n", __func__); 248750326e5SPo-Yu Chuang goto out; 249750326e5SPo-Yu Chuang } 250750326e5SPo-Yu Chuang 251750326e5SPo-Yu Chuang /* Transmit and receive descriptors should align to 16 bytes */ 252750326e5SPo-Yu Chuang 253750326e5SPo-Yu Chuang priv = memalign (16, sizeof (struct ftmac100_data)); 254750326e5SPo-Yu Chuang if (!priv) { 255750326e5SPo-Yu Chuang printf ("%s(): failed to allocate priv\n", __func__); 256750326e5SPo-Yu Chuang goto free_dev; 257750326e5SPo-Yu Chuang } 258750326e5SPo-Yu Chuang 259750326e5SPo-Yu Chuang memset (dev, 0, sizeof (*dev)); 260750326e5SPo-Yu Chuang memset (priv, 0, sizeof (*priv)); 261750326e5SPo-Yu Chuang 262750326e5SPo-Yu Chuang sprintf (dev->name, "FTMAC100"); 263750326e5SPo-Yu Chuang dev->iobase = CONFIG_FTMAC100_BASE; 264750326e5SPo-Yu Chuang dev->init = ftmac100_init; 265750326e5SPo-Yu Chuang dev->halt = ftmac100_halt; 266750326e5SPo-Yu Chuang dev->send = ftmac100_send; 267750326e5SPo-Yu Chuang dev->recv = ftmac100_recv; 268750326e5SPo-Yu Chuang dev->priv = priv; 269750326e5SPo-Yu Chuang 270750326e5SPo-Yu Chuang eth_register (dev); 271750326e5SPo-Yu Chuang 272750326e5SPo-Yu Chuang return 1; 273750326e5SPo-Yu Chuang 274750326e5SPo-Yu Chuang free_dev: 275750326e5SPo-Yu Chuang free (dev); 276750326e5SPo-Yu Chuang out: 277750326e5SPo-Yu Chuang return 0; 278750326e5SPo-Yu Chuang } 279