]>
Commit | Line | Data |
---|---|---|
4e5ca3eb WD |
1 | /* |
2 | * (C) Copyright 2000 | |
3 | * Wolfgang Denk, DENX Software Engineering, [email protected]. | |
4 | * | |
5 | * See file CREDITS for list of people who contributed to this | |
6 | * project. | |
7 | * | |
8 | * This program is free software; you can redistribute it and/or | |
9 | * modify it under the terms of the GNU General Public License as | |
10 | * published by the Free Software Foundation; either version 2 of | |
11 | * the License, or (at your option) any later version. | |
12 | * | |
13 | * This program is distributed in the hope that it will be useful, | |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | * GNU General Public License for more details. | |
17 | * | |
18 | * You should have received a copy of the GNU General Public License | |
19 | * along with this program; if not, write to the Free Software | |
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |
21 | * MA 02111-1307 USA | |
22 | */ | |
23 | ||
24 | #include <common.h> | |
25 | #include <commproc.h> | |
26 | #include <net.h> | |
27 | #include <command.h> | |
28 | ||
29 | ||
4e5ca3eb WD |
30 | /************************************************************** |
31 | * | |
32 | * FEC Ethernet Initialization Routine | |
33 | * | |
34 | *************************************************************/ | |
35 | ||
36 | #define FEC_ECNTRL_ETHER_EN 0x00000002 | |
37 | #define FEC_ECNTRL_RESET 0x00000001 | |
38 | ||
39 | #define FEC_RCNTRL_BC_REJ 0x00000010 | |
40 | #define FEC_RCNTRL_PROM 0x00000008 | |
41 | #define FEC_RCNTRL_MII_MODE 0x00000004 | |
42 | #define FEC_RCNTRL_DRT 0x00000002 | |
43 | #define FEC_RCNTRL_LOOP 0x00000001 | |
44 | ||
45 | #define FEC_TCNTRL_FDEN 0x00000004 | |
46 | #define FEC_TCNTRL_HBC 0x00000002 | |
47 | #define FEC_TCNTRL_GTS 0x00000001 | |
48 | ||
49 | #define FEC_RESET_DELAY 50000 | |
50 | ||
51 | ||
4e5ca3eb WD |
52 | /* Ethernet Transmit and Receive Buffers */ |
53 | #define DBUF_LENGTH 1520 | |
4e5ca3eb | 54 | #define TX_BUF_CNT 2 |
4e5ca3eb WD |
55 | #define TOUT_LOOP 100 |
56 | ||
d4ca31c4 WD |
57 | #define PKT_MAXBUF_SIZE 1518 |
58 | #define PKT_MINBUF_SIZE 64 | |
59 | #define PKT_MAXBLR_SIZE 1520 | |
4e5ca3eb WD |
60 | |
61 | ||
62 | #ifdef CONFIG_M5272 | |
63 | #define FEC_ADDR 0x10000840 | |
64 | #endif | |
65 | #ifdef CONFIG_M5282 | |
66 | #define FEC_ADDR 0x40001000 | |
67 | #endif | |
68 | ||
69 | #undef ET_DEBUG | |
70 | ||
71 | #if (CONFIG_COMMANDS & CFG_CMD_NET) && defined(FEC_ENET) | |
72 | ||
73 | ||
4e5ca3eb WD |
74 | static char txbuf[DBUF_LENGTH]; |
75 | ||
d4ca31c4 WD |
76 | static uint rxIdx; /* index of the current RX buffer */ |
77 | static uint txIdx; /* index of the current TX buffer */ | |
4e5ca3eb WD |
78 | |
79 | /* | |
80 | * FEC Ethernet Tx and Rx buffer descriptors allocated at the | |
81 | * immr->udata_bd address on Dual-Port RAM | |
82 | * Provide for Double Buffering | |
83 | */ | |
84 | ||
85 | typedef volatile struct CommonBufferDescriptor { | |
d4ca31c4 WD |
86 | cbd_t rxbd[PKTBUFSRX]; /* Rx BD */ |
87 | cbd_t txbd[TX_BUF_CNT]; /* Tx BD */ | |
4e5ca3eb WD |
88 | } RTXBD; |
89 | ||
90 | static RTXBD *rtx = 0x380000; | |
91 | ||
92 | ||
d4ca31c4 | 93 | int eth_send (volatile void *packet, int length) |
4e5ca3eb WD |
94 | { |
95 | int j, rc; | |
96 | volatile fec_t *fecp = FEC_ADDR; | |
97 | ||
98 | /* section 16.9.23.3 | |
99 | * Wait for ready | |
100 | */ | |
101 | j = 0; | |
d4ca31c4 WD |
102 | while ((rtx->txbd[txIdx].cbd_sc & BD_ENET_TX_READY) |
103 | && (j < TOUT_LOOP)) { | |
104 | udelay (1); | |
4e5ca3eb WD |
105 | j++; |
106 | } | |
d4ca31c4 WD |
107 | if (j >= TOUT_LOOP) { |
108 | printf ("TX not ready\n"); | |
4e5ca3eb WD |
109 | } |
110 | ||
d4ca31c4 WD |
111 | rtx->txbd[txIdx].cbd_bufaddr = (uint) packet; |
112 | rtx->txbd[txIdx].cbd_datlen = length; | |
4e5ca3eb WD |
113 | rtx->txbd[txIdx].cbd_sc |= BD_ENET_TX_READY | BD_ENET_TX_LAST; |
114 | ||
115 | /* Activate transmit Buffer Descriptor polling */ | |
d4ca31c4 | 116 | fecp->fec_x_des_active = 0x01000000; /* Descriptor polling active */ |
4e5ca3eb WD |
117 | |
118 | j = 0; | |
d4ca31c4 WD |
119 | while ((rtx->txbd[txIdx].cbd_sc & BD_ENET_TX_READY) |
120 | && (j < TOUT_LOOP)) { | |
121 | udelay (1); | |
4e5ca3eb WD |
122 | j++; |
123 | } | |
d4ca31c4 WD |
124 | if (j >= TOUT_LOOP) { |
125 | printf ("TX timeout\n"); | |
4e5ca3eb WD |
126 | } |
127 | #ifdef ET_DEBUG | |
d4ca31c4 WD |
128 | printf ("%s[%d] %s: cycles: %d status: %x retry cnt: %d\n", |
129 | __FILE__, __LINE__, __FUNCTION__, j, rtx->txbd[txIdx].cbd_sc, | |
130 | (rtx->txbd[txIdx].cbd_sc & 0x003C) >> 2); | |
4e5ca3eb | 131 | #endif |
d4ca31c4 | 132 | /* return only status bits */ ; |
4e5ca3eb WD |
133 | rc = (rtx->txbd[txIdx].cbd_sc & BD_ENET_TX_STATS); |
134 | ||
135 | txIdx = (txIdx + 1) % TX_BUF_CNT; | |
136 | ||
137 | return rc; | |
138 | } | |
139 | ||
d4ca31c4 | 140 | int eth_rx (void) |
4e5ca3eb WD |
141 | { |
142 | int length; | |
143 | volatile fec_t *fecp = FEC_ADDR; | |
144 | ||
d4ca31c4 WD |
145 | for (;;) { |
146 | /* section 16.9.23.2 */ | |
147 | if (rtx->rxbd[rxIdx].cbd_sc & BD_ENET_RX_EMPTY) { | |
148 | length = -1; | |
149 | break; /* nothing received - leave for() loop */ | |
150 | } | |
4e5ca3eb | 151 | |
d4ca31c4 | 152 | length = rtx->rxbd[rxIdx].cbd_datlen; |
4e5ca3eb | 153 | |
d4ca31c4 | 154 | if (rtx->rxbd[rxIdx].cbd_sc & 0x003f) { |
4e5ca3eb | 155 | #ifdef ET_DEBUG |
d4ca31c4 WD |
156 | printf ("%s[%d] err: %x\n", |
157 | __FUNCTION__, __LINE__, | |
158 | rtx->rxbd[rxIdx].cbd_sc); | |
4e5ca3eb | 159 | #endif |
d4ca31c4 WD |
160 | } else { |
161 | /* Pass the packet up to the protocol layers. */ | |
162 | NetReceive (NetRxPackets[rxIdx], length - 4); | |
163 | } | |
164 | ||
165 | /* Give the buffer back to the FEC. */ | |
166 | rtx->rxbd[rxIdx].cbd_datlen = 0; | |
167 | ||
168 | /* wrap around buffer index when necessary */ | |
169 | if ((rxIdx + 1) >= PKTBUFSRX) { | |
170 | rtx->rxbd[PKTBUFSRX - 1].cbd_sc = | |
171 | (BD_ENET_RX_WRAP | BD_ENET_RX_EMPTY); | |
172 | rxIdx = 0; | |
173 | } else { | |
174 | rtx->rxbd[rxIdx].cbd_sc = BD_ENET_RX_EMPTY; | |
175 | rxIdx++; | |
176 | } | |
177 | ||
178 | /* Try to fill Buffer Descriptors */ | |
179 | fecp->fec_r_des_active = 0x01000000; /* Descriptor polling active */ | |
4e5ca3eb WD |
180 | } |
181 | ||
d4ca31c4 | 182 | return length; |
4e5ca3eb WD |
183 | } |
184 | ||
185 | ||
186 | int eth_init (bd_t * bd) | |
187 | { | |
188 | ||
189 | int i; | |
190 | volatile fec_t *fecp = FEC_ADDR; | |
d4ca31c4 | 191 | |
4e5ca3eb WD |
192 | /* Whack a reset. |
193 | * A delay is required between a reset of the FEC block and | |
194 | * initialization of other FEC registers because the reset takes | |
195 | * some time to complete. If you don't delay, subsequent writes | |
196 | * to FEC registers might get killed by the reset routine which is | |
197 | * still in progress. | |
198 | */ | |
199 | ||
200 | fecp->fec_ecntrl = FEC_ECNTRL_RESET; | |
201 | for (i = 0; | |
202 | (fecp->fec_ecntrl & FEC_ECNTRL_RESET) && (i < FEC_RESET_DELAY); | |
203 | ++i) { | |
204 | udelay (1); | |
205 | } | |
206 | if (i == FEC_RESET_DELAY) { | |
207 | printf ("FEC_RESET_DELAY timeout\n"); | |
208 | return 0; | |
209 | } | |
210 | ||
211 | /* We use strictly polling mode only | |
212 | */ | |
213 | fecp->fec_imask = 0; | |
d4ca31c4 | 214 | |
4e5ca3eb WD |
215 | /* Clear any pending interrupt */ |
216 | fecp->fec_ievent = 0xffffffff; | |
d4ca31c4 WD |
217 | |
218 | /* Set station address */ | |
4e5ca3eb | 219 | #define ea bd->bi_enetaddr |
d4ca31c4 WD |
220 | fecp->fec_addr_low = (ea[0] << 24) | (ea[1] << 16) | |
221 | (ea[2] << 8) | (ea[3]); | |
222 | fecp->fec_addr_high = (ea[4] << 24) | (ea[5] << 16); | |
4e5ca3eb WD |
223 | #undef ea |
224 | ||
225 | /* Clear multicast address hash table | |
226 | */ | |
227 | fecp->fec_hash_table_high = 0; | |
d4ca31c4 | 228 | fecp->fec_hash_table_low = 0; |
4e5ca3eb WD |
229 | |
230 | /* Set maximum receive buffer size. | |
231 | */ | |
232 | fecp->fec_r_buff_size = PKT_MAXBLR_SIZE; | |
233 | ||
234 | /* | |
235 | * Setup Buffers and Buffer Desriptors | |
236 | */ | |
237 | rxIdx = 0; | |
238 | txIdx = 0; | |
239 | ||
240 | /* | |
241 | * Setup Receiver Buffer Descriptors (13.14.24.18) | |
242 | * Settings: | |
243 | * Empty, Wrap | |
244 | */ | |
245 | for (i = 0; i < PKTBUFSRX; i++) { | |
d4ca31c4 WD |
246 | rtx->rxbd[i].cbd_sc = BD_ENET_RX_EMPTY; |
247 | rtx->rxbd[i].cbd_datlen = 0; /* Reset */ | |
4e5ca3eb WD |
248 | rtx->rxbd[i].cbd_bufaddr = (uint) NetRxPackets[i]; |
249 | } | |
250 | rtx->rxbd[PKTBUFSRX - 1].cbd_sc |= BD_ENET_RX_WRAP; | |
251 | ||
252 | /* | |
253 | * Setup Ethernet Transmitter Buffer Descriptors (13.14.24.19) | |
254 | * Settings: | |
255 | * Last, Tx CRC | |
256 | */ | |
257 | for (i = 0; i < TX_BUF_CNT; i++) { | |
d4ca31c4 WD |
258 | rtx->txbd[i].cbd_sc = BD_ENET_TX_LAST | BD_ENET_TX_TC; |
259 | rtx->txbd[i].cbd_datlen = 0; /* Reset */ | |
4e5ca3eb WD |
260 | rtx->txbd[i].cbd_bufaddr = (uint) (&txbuf[0]); |
261 | } | |
262 | rtx->txbd[TX_BUF_CNT - 1].cbd_sc |= BD_ENET_TX_WRAP; | |
263 | ||
264 | /* Set receive and transmit descriptor base | |
265 | */ | |
266 | fecp->fec_r_des_start = (unsigned int) (&rtx->rxbd[0]); | |
267 | fecp->fec_x_des_start = (unsigned int) (&rtx->txbd[0]); | |
268 | ||
269 | /* Enable MII mode | |
270 | */ | |
271 | ||
272 | /* Half duplex mode */ | |
d4ca31c4 WD |
273 | fecp->fec_r_cntrl = (PKT_MAXBUF_SIZE << 16) | FEC_RCNTRL_MII_MODE; |
274 | fecp->fec_r_cntrl = (PKT_MAXBUF_SIZE << 16) | FEC_RCNTRL_MII_MODE; | |
4e5ca3eb WD |
275 | fecp->fec_x_cntrl = 0; |
276 | ||
277 | fecp->fec_mii_speed = 0; | |
278 | ||
279 | /* Now enable the transmit and receive processing | |
280 | */ | |
281 | fecp->fec_ecntrl = FEC_ECNTRL_ETHER_EN; | |
282 | ||
283 | /* And last, try to fill Rx Buffer Descriptors */ | |
d4ca31c4 | 284 | fecp->fec_r_des_active = 0x01000000; /* Descriptor polling active */ |
4e5ca3eb WD |
285 | |
286 | return 1; | |
287 | } | |
288 | ||
289 | ||
d4ca31c4 | 290 | void eth_halt (void) |
4e5ca3eb WD |
291 | { |
292 | volatile fec_t *fecp = FEC_ADDR; | |
d4ca31c4 | 293 | |
4e5ca3eb WD |
294 | fecp->fec_ecntrl = 0; |
295 | } | |
4e5ca3eb | 296 | #endif |