xref: /openbmc/u-boot/drivers/net/ftmac100.c (revision fd697ecf)
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)NetRxPackets[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 	NetReceive ((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 	sprintf (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