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 struct ftmac100_txdes txdes[1]; 34 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 struct ftmac100_txdes *txdes = priv->txdes; 92 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 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 ftmac100_send(struct eth_device *dev, void *packet, int length) 194 { 195 struct ftmac100 *ftmac100 = (struct ftmac100 *)dev->iobase; 196 struct ftmac100_data *priv = dev->priv; 197 struct ftmac100_txdes *curr_des = priv->txdes; 198 ulong start; 199 200 if (curr_des->txdes0 & FTMAC100_TXDES0_TXDMA_OWN) { 201 debug ("%s(): no TX descriptor available\n", __func__); 202 return -1; 203 } 204 205 debug ("%s(%x, %x)\n", __func__, (int)packet, length); 206 207 length = (length < ETH_ZLEN) ? ETH_ZLEN : length; 208 209 /* initiate a transmit sequence */ 210 211 curr_des->txdes2 = (unsigned int)packet; /* TXBUF_BADR */ 212 213 curr_des->txdes1 &= FTMAC100_TXDES1_EDOTR; 214 curr_des->txdes1 |= FTMAC100_TXDES1_FTS | 215 FTMAC100_TXDES1_LTS | 216 FTMAC100_TXDES1_TXBUF_SIZE (length); 217 218 curr_des->txdes0 = FTMAC100_TXDES0_TXDMA_OWN; 219 220 /* start transmit */ 221 222 writel (1, &ftmac100->txpd); 223 224 /* wait for transfer to succeed */ 225 226 start = get_timer(0); 227 while (curr_des->txdes0 & FTMAC100_TXDES0_TXDMA_OWN) { 228 if (get_timer(start) >= 5) { 229 debug ("%s(): timed out\n", __func__); 230 return -1; 231 } 232 } 233 234 debug ("%s(): packet sent\n", __func__); 235 236 return 0; 237 } 238 239 int ftmac100_initialize (bd_t *bd) 240 { 241 struct eth_device *dev; 242 struct ftmac100_data *priv; 243 244 dev = malloc (sizeof *dev); 245 if (!dev) { 246 printf ("%s(): failed to allocate dev\n", __func__); 247 goto out; 248 } 249 250 /* Transmit and receive descriptors should align to 16 bytes */ 251 252 priv = memalign (16, sizeof (struct ftmac100_data)); 253 if (!priv) { 254 printf ("%s(): failed to allocate priv\n", __func__); 255 goto free_dev; 256 } 257 258 memset (dev, 0, sizeof (*dev)); 259 memset (priv, 0, sizeof (*priv)); 260 261 sprintf (dev->name, "FTMAC100"); 262 dev->iobase = CONFIG_FTMAC100_BASE; 263 dev->init = ftmac100_init; 264 dev->halt = ftmac100_halt; 265 dev->send = ftmac100_send; 266 dev->recv = ftmac100_recv; 267 dev->priv = priv; 268 269 eth_register (dev); 270 271 return 1; 272 273 free_dev: 274 free (dev); 275 out: 276 return 0; 277 } 278