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