]>
Commit | Line | Data |
---|---|---|
750326e5 PYC |
1 | /* |
2 | * Faraday FTMAC100 Ethernet | |
3 | * | |
4 | * (C) Copyright 2009 Faraday Technology | |
5 | * Po-Yu Chuang <ratbert@faraday-tech.com> | |
6 | * | |
1a459660 | 7 | * SPDX-License-Identifier: GPL-2.0+ |
750326e5 PYC |
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 { | |
6f6e6e09 PYC |
21 | struct ftmac100_txdes txdes[1]; |
22 | struct ftmac100_rxdes rxdes[PKTBUFSRX]; | |
750326e5 PYC |
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; | |
6f6e6e09 PYC |
79 | struct ftmac100_txdes *txdes = priv->txdes; |
80 | struct ftmac100_rxdes *rxdes = priv->rxdes; | |
750326e5 PYC |
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 */ | |
1fd92db8 | 105 | rxdes[i].rxdes2 = (unsigned int)net_rx_packets[i]; |
750326e5 PYC |
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; | |
6f6e6e09 | 144 | struct ftmac100_rxdes *curr_des; |
750326e5 PYC |
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 | ||
1fd92db8 | 167 | net_process_received_packet((void *)curr_des->rxdes2, rxlen); |
750326e5 PYC |
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 | */ | |
99ec7728 | 181 | static int ftmac100_send(struct eth_device *dev, void *packet, int length) |
750326e5 PYC |
182 | { |
183 | struct ftmac100 *ftmac100 = (struct ftmac100 *)dev->iobase; | |
184 | struct ftmac100_data *priv = dev->priv; | |
6f6e6e09 | 185 | struct ftmac100_txdes *curr_des = priv->txdes; |
8d8fd5b6 | 186 | ulong start; |
750326e5 PYC |
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 | ||
8d8fd5b6 | 214 | start = get_timer(0); |
750326e5 | 215 | while (curr_des->txdes0 & FTMAC100_TXDES0_TXDMA_OWN) { |
8d8fd5b6 | 216 | if (get_timer(start) >= 5) { |
750326e5 PYC |
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 | ||
192bc694 | 249 | strcpy(dev->name, "FTMAC100"); |
750326e5 PYC |
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 | } |