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