Commit a61a81967f57cb657dea9289a1b0810c668bf9ae
Committed by
Ben Warren
1 parent
f29c181cd4
Exists in
master
and in
54 other branches
NET: add ENC28J60 driver using SPI framework
V3: further refinements: - use priv member instead of container method - allow setting of MAC address by write_hwaddr method - avoid shutting down link between commands Signed-off-by: Reinhard Meyer <u-boot@emk-elektronik.de> Signed-off-by: Ben Warren <biggerbadderben@gmail.com>
Showing 4 changed files with 1232 additions and 0 deletions Side-by-side Diff
drivers/net/Makefile
... | ... | @@ -39,6 +39,7 @@ |
39 | 39 | COBJS-$(CONFIG_DNET) += dnet.o |
40 | 40 | COBJS-$(CONFIG_E1000) += e1000.o |
41 | 41 | COBJS-$(CONFIG_EEPRO100) += eepro100.o |
42 | +COBJS-$(CONFIG_ENC28J60) += enc28j60.o | |
42 | 43 | COBJS-$(CONFIG_ENC28J60_LPC2292) += enc28j60_lpc2292.o |
43 | 44 | COBJS-$(CONFIG_EP93XX) += ep93xx_eth.o |
44 | 45 | COBJS-$(CONFIG_ETHOC) += ethoc.o |
drivers/net/enc28j60.c
1 | +/* | |
2 | + * (C) Copyright 2010 | |
3 | + * Reinhard Meyer, EMK Elektronik, reinhard.meyer@emk-elektronik.de | |
4 | + * Martin Krause, Martin.Krause@tqs.de | |
5 | + * reworked original enc28j60.c | |
6 | + * | |
7 | + * This program is free software; you can redistribute it and/or | |
8 | + * modify it under the terms of the GNU General Public License as | |
9 | + * published by the Free Software Foundation; either version 2 of | |
10 | + * the License, or (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., 59 Temple Place, Suite 330, Boston, | |
20 | + * MA 02111-1307 USA | |
21 | + */ | |
22 | + | |
23 | +#include <common.h> | |
24 | +#include <net.h> | |
25 | +#include <spi.h> | |
26 | +#include <malloc.h> | |
27 | +#include <netdev.h> | |
28 | +#include <miiphy.h> | |
29 | +#include "enc28j60.h" | |
30 | + | |
31 | +/* | |
32 | + * IMPORTANT: spi_claim_bus() and spi_release_bus() | |
33 | + * are called at begin and end of each of the following functions: | |
34 | + * enc_miiphy_read(), enc_miiphy_write(), enc_write_hwaddr(), | |
35 | + * enc_init(), enc_recv(), enc_send(), enc_halt() | |
36 | + * ALL other functions assume that the bus has already been claimed! | |
37 | + * Since NetReceive() might call enc_send() in return, the bus must be | |
38 | + * released, NetReceive() called and claimed again. | |
39 | + */ | |
40 | + | |
41 | +/* | |
42 | + * Controller memory layout. | |
43 | + * We only allow 1 frame for transmission and reserve the rest | |
44 | + * for reception to handle as many broadcast packets as possible. | |
45 | + * Also use the memory from 0x0000 for receiver buffer. See errata pt. 5 | |
46 | + * 0x0000 - 0x19ff 6656 bytes receive buffer | |
47 | + * 0x1a00 - 0x1fff 1536 bytes transmit buffer = | |
48 | + * control(1)+frame(1518)+status(7)+reserve(10). | |
49 | + */ | |
50 | +#define ENC_RX_BUF_START 0x0000 | |
51 | +#define ENC_RX_BUF_END 0x19ff | |
52 | +#define ENC_TX_BUF_START 0x1a00 | |
53 | +#define ENC_TX_BUF_END 0x1fff | |
54 | +#define ENC_MAX_FRM_LEN 1518 | |
55 | +#define RX_RESET_COUNTER 1000 | |
56 | + | |
57 | +/* | |
58 | + * For non data transfer functions, like phy read/write, set hwaddr, init | |
59 | + * we do not need a full, time consuming init including link ready wait. | |
60 | + * This enum helps to bring the chip through the minimum necessary inits. | |
61 | + */ | |
62 | +enum enc_initstate {none=0, setupdone, linkready}; | |
63 | +typedef struct enc_device { | |
64 | + struct eth_device *dev; /* back pointer */ | |
65 | + struct spi_slave *slave; | |
66 | + int rx_reset_counter; | |
67 | + u16 next_pointer; | |
68 | + u8 bank; /* current bank in enc28j60 */ | |
69 | + enum enc_initstate initstate; | |
70 | +} enc_dev_t; | |
71 | + | |
72 | +/* | |
73 | + * enc_bset: set bits in a common register | |
74 | + * enc_bclr: clear bits in a common register | |
75 | + * | |
76 | + * making the reg parameter u8 will give a compile time warning if the | |
77 | + * functions are called with a register not accessible in all Banks | |
78 | + */ | |
79 | +static void enc_bset(enc_dev_t *enc, const u8 reg, const u8 data) | |
80 | +{ | |
81 | + u8 dout[2]; | |
82 | + | |
83 | + dout[0] = CMD_BFS(reg); | |
84 | + dout[1] = data; | |
85 | + spi_xfer(enc->slave, 2 * 8, dout, NULL, | |
86 | + SPI_XFER_BEGIN | SPI_XFER_END); | |
87 | +} | |
88 | + | |
89 | +static void enc_bclr(enc_dev_t *enc, const u8 reg, const u8 data) | |
90 | +{ | |
91 | + u8 dout[2]; | |
92 | + | |
93 | + dout[0] = CMD_BFC(reg); | |
94 | + dout[1] = data; | |
95 | + spi_xfer(enc->slave, 2 * 8, dout, NULL, | |
96 | + SPI_XFER_BEGIN | SPI_XFER_END); | |
97 | +} | |
98 | + | |
99 | +/* | |
100 | + * high byte of the register contains bank number: | |
101 | + * 0: no bank switch necessary | |
102 | + * 1: switch to bank 0 | |
103 | + * 2: switch to bank 1 | |
104 | + * 3: switch to bank 2 | |
105 | + * 4: switch to bank 3 | |
106 | + */ | |
107 | +static void enc_set_bank(enc_dev_t *enc, const u16 reg) | |
108 | +{ | |
109 | + u8 newbank = reg >> 8; | |
110 | + | |
111 | + if (newbank == 0 || newbank == enc->bank) | |
112 | + return; | |
113 | + switch (newbank) { | |
114 | + case 1: | |
115 | + enc_bclr(enc, CTL_REG_ECON1, | |
116 | + ENC_ECON1_BSEL0 | ENC_ECON1_BSEL1); | |
117 | + break; | |
118 | + case 2: | |
119 | + enc_bset(enc, CTL_REG_ECON1, ENC_ECON1_BSEL0); | |
120 | + enc_bclr(enc, CTL_REG_ECON1, ENC_ECON1_BSEL1); | |
121 | + break; | |
122 | + case 3: | |
123 | + enc_bclr(enc, CTL_REG_ECON1, ENC_ECON1_BSEL0); | |
124 | + enc_bset(enc, CTL_REG_ECON1, ENC_ECON1_BSEL1); | |
125 | + break; | |
126 | + case 4: | |
127 | + enc_bset(enc, CTL_REG_ECON1, | |
128 | + ENC_ECON1_BSEL0 | ENC_ECON1_BSEL1); | |
129 | + break; | |
130 | + } | |
131 | + enc->bank = newbank; | |
132 | +} | |
133 | + | |
134 | +/* | |
135 | + * local functions to access SPI | |
136 | + * | |
137 | + * reg: register inside ENC28J60 | |
138 | + * data: 8/16 bits to write | |
139 | + * c: number of retries | |
140 | + * | |
141 | + * enc_r8: read 8 bits | |
142 | + * enc_r16: read 16 bits | |
143 | + * enc_w8: write 8 bits | |
144 | + * enc_w16: write 16 bits | |
145 | + * enc_w8_retry: write 8 bits, verify and retry | |
146 | + * enc_rbuf: read from ENC28J60 into buffer | |
147 | + * enc_wbuf: write from buffer into ENC28J60 | |
148 | + */ | |
149 | + | |
150 | +/* | |
151 | + * MAC and MII registers need a 3 byte SPI transfer to read, | |
152 | + * all other registers need a 2 byte SPI transfer. | |
153 | + */ | |
154 | +static int enc_reg2nbytes(const u16 reg) | |
155 | +{ | |
156 | + /* check if MAC or MII register */ | |
157 | + return ((reg >= CTL_REG_MACON1 && reg <= CTL_REG_MIRDH) || | |
158 | + (reg >= CTL_REG_MAADR1 && reg <= CTL_REG_MAADR4) || | |
159 | + (reg == CTL_REG_MISTAT)) ? 3 : 2; | |
160 | +} | |
161 | + | |
162 | +/* | |
163 | + * Read a byte register | |
164 | + */ | |
165 | +static u8 enc_r8(enc_dev_t *enc, const u16 reg) | |
166 | +{ | |
167 | + u8 dout[3]; | |
168 | + u8 din[3]; | |
169 | + int nbytes = enc_reg2nbytes(reg); | |
170 | + | |
171 | + enc_set_bank(enc, reg); | |
172 | + dout[0] = CMD_RCR(reg); | |
173 | + spi_xfer(enc->slave, nbytes * 8, dout, din, | |
174 | + SPI_XFER_BEGIN | SPI_XFER_END); | |
175 | + return din[nbytes-1]; | |
176 | +} | |
177 | + | |
178 | +/* | |
179 | + * Read a L/H register pair and return a word. | |
180 | + * Must be called with the L register's address. | |
181 | + */ | |
182 | +static u16 enc_r16(enc_dev_t *enc, const u16 reg) | |
183 | +{ | |
184 | + u8 dout[3]; | |
185 | + u8 din[3]; | |
186 | + u16 result; | |
187 | + int nbytes = enc_reg2nbytes(reg); | |
188 | + | |
189 | + enc_set_bank(enc, reg); | |
190 | + dout[0] = CMD_RCR(reg); | |
191 | + spi_xfer(enc->slave, nbytes * 8, dout, din, | |
192 | + SPI_XFER_BEGIN | SPI_XFER_END); | |
193 | + result = din[nbytes-1]; | |
194 | + dout[0]++; /* next register */ | |
195 | + spi_xfer(enc->slave, nbytes * 8, dout, din, | |
196 | + SPI_XFER_BEGIN | SPI_XFER_END); | |
197 | + result |= din[nbytes-1] << 8; | |
198 | + return result; | |
199 | +} | |
200 | + | |
201 | +/* | |
202 | + * Write a byte register | |
203 | + */ | |
204 | +static void enc_w8(enc_dev_t *enc, const u16 reg, const u8 data) | |
205 | +{ | |
206 | + u8 dout[2]; | |
207 | + | |
208 | + enc_set_bank(enc, reg); | |
209 | + dout[0] = CMD_WCR(reg); | |
210 | + dout[1] = data; | |
211 | + spi_xfer(enc->slave, 2 * 8, dout, NULL, | |
212 | + SPI_XFER_BEGIN | SPI_XFER_END); | |
213 | +} | |
214 | + | |
215 | +/* | |
216 | + * Write a L/H register pair. | |
217 | + * Must be called with the L register's address. | |
218 | + */ | |
219 | +static void enc_w16(enc_dev_t *enc, const u16 reg, const u16 data) | |
220 | +{ | |
221 | + u8 dout[2]; | |
222 | + | |
223 | + enc_set_bank(enc, reg); | |
224 | + dout[0] = CMD_WCR(reg); | |
225 | + dout[1] = data; | |
226 | + spi_xfer(enc->slave, 2 * 8, dout, NULL, | |
227 | + SPI_XFER_BEGIN | SPI_XFER_END); | |
228 | + dout[0]++; /* next register */ | |
229 | + dout[1] = data >> 8; | |
230 | + spi_xfer(enc->slave, 2 * 8, dout, NULL, | |
231 | + SPI_XFER_BEGIN | SPI_XFER_END); | |
232 | +} | |
233 | + | |
234 | +/* | |
235 | + * Write a byte register, verify and retry | |
236 | + */ | |
237 | +static void enc_w8_retry(enc_dev_t *enc, const u16 reg, const u8 data, const int c) | |
238 | +{ | |
239 | + u8 dout[2]; | |
240 | + u8 readback; | |
241 | + int i; | |
242 | + | |
243 | + enc_set_bank(enc, reg); | |
244 | + for (i = 0; i < c; i++) { | |
245 | + dout[0] = CMD_WCR(reg); | |
246 | + dout[1] = data; | |
247 | + spi_xfer(enc->slave, 2 * 8, dout, NULL, | |
248 | + SPI_XFER_BEGIN | SPI_XFER_END); | |
249 | + readback = enc_r8(enc, reg); | |
250 | + if (readback == data) | |
251 | + break; | |
252 | + /* wait 1ms */ | |
253 | + udelay(1000); | |
254 | + } | |
255 | + if (i == c) { | |
256 | + printf("%s: write reg 0x%03x failed\n", enc->dev->name, reg); | |
257 | + } | |
258 | +} | |
259 | + | |
260 | +/* | |
261 | + * Read ENC RAM into buffer | |
262 | + */ | |
263 | +static void enc_rbuf(enc_dev_t *enc, const u16 length, u8 *buf) | |
264 | +{ | |
265 | + u8 dout[1]; | |
266 | + | |
267 | + dout[0] = CMD_RBM; | |
268 | + spi_xfer(enc->slave, 8, dout, NULL, SPI_XFER_BEGIN); | |
269 | + spi_xfer(enc->slave, length * 8, NULL, buf, SPI_XFER_END); | |
270 | +#ifdef DEBUG | |
271 | + puts("Rx:\n"); | |
272 | + print_buffer(0, buf, 1, length, 0); | |
273 | +#endif | |
274 | +} | |
275 | + | |
276 | +/* | |
277 | + * Write buffer into ENC RAM | |
278 | + */ | |
279 | +static void enc_wbuf(enc_dev_t *enc, const u16 length, const u8 *buf, const u8 control) | |
280 | +{ | |
281 | + u8 dout[2]; | |
282 | + dout[0] = CMD_WBM; | |
283 | + dout[1] = control; | |
284 | + spi_xfer(enc->slave, 2 * 8, dout, NULL, SPI_XFER_BEGIN); | |
285 | + spi_xfer(enc->slave, length * 8, buf, NULL, SPI_XFER_END); | |
286 | +#ifdef DEBUG | |
287 | + puts("Tx:\n"); | |
288 | + print_buffer(0, buf, 1, length, 0); | |
289 | +#endif | |
290 | +} | |
291 | + | |
292 | +/* | |
293 | + * Try to claim the SPI bus. | |
294 | + * Print error message on failure. | |
295 | + */ | |
296 | +static int enc_claim_bus(enc_dev_t *enc) | |
297 | +{ | |
298 | + int rc = spi_claim_bus(enc->slave); | |
299 | + if (rc) | |
300 | + printf("%s: failed to claim SPI bus\n", enc->dev->name); | |
301 | + return rc; | |
302 | +} | |
303 | + | |
304 | +/* | |
305 | + * Release previously claimed SPI bus. | |
306 | + * This function is mainly for symmetry to enc_claim_bus(). | |
307 | + * Let the toolchain decide to inline it... | |
308 | + */ | |
309 | +static void enc_release_bus(enc_dev_t *enc) | |
310 | +{ | |
311 | + spi_release_bus(enc->slave); | |
312 | +} | |
313 | + | |
314 | +/* | |
315 | + * Read PHY register | |
316 | + */ | |
317 | +static u16 phy_read(enc_dev_t *enc, const u8 addr) | |
318 | +{ | |
319 | + uint64_t etime; | |
320 | + u8 status; | |
321 | + | |
322 | + enc_w8(enc, CTL_REG_MIREGADR, addr); | |
323 | + enc_w8(enc, CTL_REG_MICMD, ENC_MICMD_MIIRD); | |
324 | + /* 1 second timeout - only happens on hardware problem */ | |
325 | + etime = get_ticks() + get_tbclk(); | |
326 | + /* poll MISTAT.BUSY bit until operation is complete */ | |
327 | + do | |
328 | + { | |
329 | + status = enc_r8(enc, CTL_REG_MISTAT); | |
330 | + } while (get_ticks() <= etime && (status & ENC_MISTAT_BUSY)); | |
331 | + if (status & ENC_MISTAT_BUSY) { | |
332 | + printf("%s: timeout reading phy\n", enc->dev->name); | |
333 | + return 0; | |
334 | + } | |
335 | + enc_w8(enc, CTL_REG_MICMD, 0); | |
336 | + return enc_r16(enc, CTL_REG_MIRDL); | |
337 | +} | |
338 | + | |
339 | +/* | |
340 | + * Write PHY register | |
341 | + */ | |
342 | +static void phy_write(enc_dev_t *enc, const u8 addr, const u16 data) | |
343 | +{ | |
344 | + uint64_t etime; | |
345 | + u8 status; | |
346 | + | |
347 | + enc_w8(enc, CTL_REG_MIREGADR, addr); | |
348 | + enc_w16(enc, CTL_REG_MIWRL, data); | |
349 | + /* 1 second timeout - only happens on hardware problem */ | |
350 | + etime = get_ticks() + get_tbclk(); | |
351 | + /* poll MISTAT.BUSY bit until operation is complete */ | |
352 | + do | |
353 | + { | |
354 | + status = enc_r8(enc, CTL_REG_MISTAT); | |
355 | + } while (get_ticks() <= etime && (status & ENC_MISTAT_BUSY)); | |
356 | + if (status & ENC_MISTAT_BUSY) { | |
357 | + printf("%s: timeout writing phy\n", enc->dev->name); | |
358 | + return; | |
359 | + } | |
360 | +} | |
361 | + | |
362 | +/* | |
363 | + * Verify link status, wait if necessary | |
364 | + * | |
365 | + * Note: with a 10 MBit/s only PHY there is no autonegotiation possible, | |
366 | + * half/full duplex is a pure setup matter. For the time being, this driver | |
367 | + * will setup in half duplex mode only. | |
368 | + */ | |
369 | +static int enc_phy_link_wait(enc_dev_t *enc) | |
370 | +{ | |
371 | + u16 status; | |
372 | + int duplex; | |
373 | + uint64_t etime; | |
374 | + | |
375 | +#ifdef CONFIG_ENC_SILENTLINK | |
376 | + /* check if we have a link, then just return */ | |
377 | + status = phy_read(enc, PHY_REG_PHSTAT1); | |
378 | + if (status & ENC_PHSTAT1_LLSTAT) | |
379 | + return 0; | |
380 | +#endif | |
381 | + | |
382 | + /* wait for link with 1 second timeout */ | |
383 | + etime = get_ticks() + get_tbclk(); | |
384 | + while (get_ticks() <= etime) { | |
385 | + status = phy_read(enc, PHY_REG_PHSTAT1); | |
386 | + if (status & ENC_PHSTAT1_LLSTAT) { | |
387 | + /* now we have a link */ | |
388 | + status = phy_read(enc, PHY_REG_PHSTAT2); | |
389 | + duplex = (status & ENC_PHSTAT2_DPXSTAT) ? 1 : 0; | |
390 | + printf("%s: link up, 10Mbps %s-duplex\n", | |
391 | + enc->dev->name, duplex ? "full" : "half"); | |
392 | + return 0; | |
393 | + } | |
394 | + udelay(1000); | |
395 | + } | |
396 | + | |
397 | + /* timeout occured */ | |
398 | + printf("%s: link down\n", enc->dev->name); | |
399 | + return 1; | |
400 | +} | |
401 | + | |
402 | +/* | |
403 | + * This function resets the receiver only. | |
404 | + */ | |
405 | +static void enc_reset_rx(enc_dev_t *enc) | |
406 | +{ | |
407 | + u8 econ1; | |
408 | + | |
409 | + econ1 = enc_r8(enc, CTL_REG_ECON1); | |
410 | + if ((econ1 & ENC_ECON1_RXRST) == 0) { | |
411 | + enc_bset(enc, CTL_REG_ECON1, ENC_ECON1_RXRST); | |
412 | + enc->rx_reset_counter = RX_RESET_COUNTER; | |
413 | + } | |
414 | +} | |
415 | + | |
416 | +/* | |
417 | + * Reset receiver and reenable it. | |
418 | + */ | |
419 | +static void enc_reset_rx_call(enc_dev_t *enc) | |
420 | +{ | |
421 | + enc_bclr(enc, CTL_REG_ECON1, ENC_ECON1_RXRST); | |
422 | + enc_bset(enc, CTL_REG_ECON1, ENC_ECON1_RXEN); | |
423 | +} | |
424 | + | |
425 | +/* | |
426 | + * Copy a packet from the receive ring and forward it to | |
427 | + * the protocol stack. | |
428 | + */ | |
429 | +static void enc_receive(enc_dev_t *enc) | |
430 | +{ | |
431 | + u8 *packet = (u8 *)NetRxPackets[0]; | |
432 | + u16 pkt_len; | |
433 | + u16 copy_len; | |
434 | + u16 status; | |
435 | + u8 eir_reg; | |
436 | + u8 pkt_cnt = 0; | |
437 | + u16 rxbuf_rdpt; | |
438 | + u8 hbuf[6]; | |
439 | + | |
440 | + enc_w16(enc, CTL_REG_ERDPTL, enc->next_pointer); | |
441 | + do { | |
442 | + enc_rbuf(enc, 6, hbuf); | |
443 | + enc->next_pointer = hbuf[0] | (hbuf[1] << 8); | |
444 | + pkt_len = hbuf[2] | (hbuf[3] << 8); | |
445 | + status = hbuf[4] | (hbuf[5] << 8); | |
446 | + debug("next_pointer=$%04x pkt_len=%u status=$%04x\n", | |
447 | + enc->next_pointer, pkt_len, status); | |
448 | + if (pkt_len <= ENC_MAX_FRM_LEN) | |
449 | + copy_len = pkt_len; | |
450 | + else | |
451 | + copy_len = 0; | |
452 | + if ((status & (1L << 7)) == 0) /* check Received Ok bit */ | |
453 | + copy_len = 0; | |
454 | + /* check if next pointer is resonable */ | |
455 | + if (enc->next_pointer >= ENC_TX_BUF_START) | |
456 | + copy_len = 0; | |
457 | + if (copy_len > 0) { | |
458 | + enc_rbuf(enc, copy_len, packet); | |
459 | + } | |
460 | + /* advance read pointer to next pointer */ | |
461 | + enc_w16(enc, CTL_REG_ERDPTL, enc->next_pointer); | |
462 | + /* decrease packet counter */ | |
463 | + enc_bset(enc, CTL_REG_ECON2, ENC_ECON2_PKTDEC); | |
464 | + /* | |
465 | + * Only odd values should be written to ERXRDPTL, | |
466 | + * see errata B4 pt.13 | |
467 | + */ | |
468 | + rxbuf_rdpt = enc->next_pointer - 1; | |
469 | + if ((rxbuf_rdpt < enc_r16(enc, CTL_REG_ERXSTL)) || | |
470 | + (rxbuf_rdpt > enc_r16(enc, CTL_REG_ERXNDL))) { | |
471 | + enc_w16(enc, CTL_REG_ERXRDPTL, | |
472 | + enc_r16(enc, CTL_REG_ERXNDL)); | |
473 | + } else { | |
474 | + enc_w16(enc, CTL_REG_ERXRDPTL, rxbuf_rdpt); | |
475 | + } | |
476 | + /* read pktcnt */ | |
477 | + pkt_cnt = enc_r8(enc, CTL_REG_EPKTCNT); | |
478 | + if (copy_len == 0) { | |
479 | + eir_reg = enc_r8(enc, CTL_REG_EIR); | |
480 | + enc_reset_rx(enc); | |
481 | + printf("%s: receive copy_len=0\n", enc->dev->name); | |
482 | + continue; | |
483 | + } | |
484 | + /* | |
485 | + * Because NetReceive() might call enc_send(), we need to | |
486 | + * release the SPI bus, call NetReceive(), reclaim the bus | |
487 | + */ | |
488 | + enc_release_bus(enc); | |
489 | + NetReceive(packet, pkt_len); | |
490 | + if (enc_claim_bus(enc)) | |
491 | + return; | |
492 | + eir_reg = enc_r8(enc, CTL_REG_EIR); | |
493 | + } while (pkt_cnt); | |
494 | + /* Use EPKTCNT not EIR.PKTIF flag, see errata pt. 6 */ | |
495 | +} | |
496 | + | |
497 | +/* | |
498 | + * Poll for completely received packets. | |
499 | + */ | |
500 | +static void enc_poll(enc_dev_t *enc) | |
501 | +{ | |
502 | + u8 eir_reg; | |
503 | + u8 estat_reg; | |
504 | + u8 pkt_cnt; | |
505 | + | |
506 | +#ifdef CONFIG_USE_IRQ | |
507 | + /* clear global interrupt enable bit in enc28j60 */ | |
508 | + enc_bclr(enc, CTL_REG_EIE, ENC_EIE_INTIE); | |
509 | +#endif | |
510 | + estat_reg = enc_r8(enc, CTL_REG_ESTAT); | |
511 | + eir_reg = enc_r8(enc, CTL_REG_EIR); | |
512 | + if (eir_reg & ENC_EIR_TXIF) { | |
513 | + /* clear TXIF bit in EIR */ | |
514 | + enc_bclr(enc, CTL_REG_EIR, ENC_EIR_TXIF); | |
515 | + } | |
516 | + /* We have to use pktcnt and not pktif bit, see errata pt. 6 */ | |
517 | + pkt_cnt = enc_r8(enc, CTL_REG_EPKTCNT); | |
518 | + if (pkt_cnt > 0) { | |
519 | + if ((eir_reg & ENC_EIR_PKTIF) == 0) { | |
520 | + debug("enc_poll: pkt cnt > 0, but pktif not set\n"); | |
521 | + } | |
522 | + enc_receive(enc); | |
523 | + /* | |
524 | + * clear PKTIF bit in EIR, this should not need to be done | |
525 | + * but it seems like we get problems if we do not | |
526 | + */ | |
527 | + enc_bclr(enc, CTL_REG_EIR, ENC_EIR_PKTIF); | |
528 | + } | |
529 | + if (eir_reg & ENC_EIR_RXERIF) { | |
530 | + printf("%s: rx error\n", enc->dev->name); | |
531 | + enc_bclr(enc, CTL_REG_EIR, ENC_EIR_RXERIF); | |
532 | + } | |
533 | + if (eir_reg & ENC_EIR_TXERIF) { | |
534 | + printf("%s: tx error\n", enc->dev->name); | |
535 | + enc_bclr(enc, CTL_REG_EIR, ENC_EIR_TXERIF); | |
536 | + } | |
537 | +#ifdef CONFIG_USE_IRQ | |
538 | + /* set global interrupt enable bit in enc28j60 */ | |
539 | + enc_bset(enc, CTL_REG_EIE, ENC_EIE_INTIE); | |
540 | +#endif | |
541 | +} | |
542 | + | |
543 | +/* | |
544 | + * Completely Reset the ENC | |
545 | + */ | |
546 | +static void enc_reset(enc_dev_t *enc) | |
547 | +{ | |
548 | + u8 dout[1]; | |
549 | + | |
550 | + dout[0] = CMD_SRC; | |
551 | + spi_xfer(enc->slave, 8, dout, NULL, | |
552 | + SPI_XFER_BEGIN | SPI_XFER_END); | |
553 | + /* sleep 1 ms. See errata pt. 2 */ | |
554 | + udelay(1000); | |
555 | +} | |
556 | + | |
557 | +/* | |
558 | + * Initialisation data for most of the ENC registers | |
559 | + */ | |
560 | +static const u16 enc_initdata[] = { | |
561 | + /* | |
562 | + * Setup the buffer space. The reset values are valid for the | |
563 | + * other pointers. | |
564 | + * | |
565 | + * We shall not write to ERXST, see errata pt. 5. Instead we | |
566 | + * have to make sure that ENC_RX_BUS_START is 0. | |
567 | + */ | |
568 | + CTL_REG_ERXSTL, ENC_RX_BUF_START, | |
569 | + CTL_REG_ERXSTH, ENC_RX_BUF_START >> 8, | |
570 | + CTL_REG_ERXNDL, ENC_RX_BUF_END, | |
571 | + CTL_REG_ERXNDH, ENC_RX_BUF_END >> 8, | |
572 | + CTL_REG_ERDPTL, ENC_RX_BUF_START, | |
573 | + CTL_REG_ERDPTH, ENC_RX_BUF_START >> 8, | |
574 | + /* | |
575 | + * Set the filter to receive only good-CRC, unicast and broadcast | |
576 | + * frames. | |
577 | + * Note: some DHCP servers return their answers as broadcasts! | |
578 | + * So its unwise to remove broadcast from this. This driver | |
579 | + * might incur receiver overruns with packet loss on a broadcast | |
580 | + * flooded network. | |
581 | + */ | |
582 | + CTL_REG_ERXFCON, ENC_RFR_BCEN | ENC_RFR_UCEN | ENC_RFR_CRCEN, | |
583 | + | |
584 | + /* enable MAC to receive frames */ | |
585 | + CTL_REG_MACON1, | |
586 | + ENC_MACON1_MARXEN | ENC_MACON1_TXPAUS | ENC_MACON1_RXPAUS, | |
587 | + | |
588 | + /* configure pad, tx-crc and duplex */ | |
589 | + CTL_REG_MACON3, | |
590 | + ENC_MACON3_PADCFG0 | ENC_MACON3_TXCRCEN | | |
591 | + ENC_MACON3_FRMLNEN, | |
592 | + | |
593 | + /* Allow infinite deferals if the medium is continously busy */ | |
594 | + CTL_REG_MACON4, ENC_MACON4_DEFER, | |
595 | + | |
596 | + /* Late collisions occur beyond 63 bytes */ | |
597 | + CTL_REG_MACLCON2, 63, | |
598 | + | |
599 | + /* | |
600 | + * Set (low byte) Non-Back-to_Back Inter-Packet Gap. | |
601 | + * Recommended 0x12 | |
602 | + */ | |
603 | + CTL_REG_MAIPGL, 0x12, | |
604 | + | |
605 | + /* | |
606 | + * Set (high byte) Non-Back-to_Back Inter-Packet Gap. | |
607 | + * Recommended 0x0c for half-duplex. Nothing for full-duplex | |
608 | + */ | |
609 | + CTL_REG_MAIPGH, 0x0C, | |
610 | + | |
611 | + /* set maximum frame length */ | |
612 | + CTL_REG_MAMXFLL, ENC_MAX_FRM_LEN, | |
613 | + CTL_REG_MAMXFLH, ENC_MAX_FRM_LEN >> 8, | |
614 | + | |
615 | + /* | |
616 | + * Set MAC back-to-back inter-packet gap. | |
617 | + * Recommended 0x12 for half duplex | |
618 | + * and 0x15 for full duplex. | |
619 | + */ | |
620 | + CTL_REG_MABBIPG, 0x12, | |
621 | + | |
622 | + /* end of table */ | |
623 | + 0xffff | |
624 | +}; | |
625 | + | |
626 | +/* | |
627 | + * Wait for the XTAL oscillator to become ready | |
628 | + */ | |
629 | +static int enc_clock_wait(enc_dev_t *enc) | |
630 | +{ | |
631 | + uint64_t etime; | |
632 | + | |
633 | + /* one second timeout */ | |
634 | + etime = get_ticks() + get_tbclk(); | |
635 | + | |
636 | + /* | |
637 | + * Wait for CLKRDY to become set (i.e., check that we can | |
638 | + * communicate with the ENC) | |
639 | + */ | |
640 | + do | |
641 | + { | |
642 | + if (enc_r8(enc, CTL_REG_ESTAT) & ENC_ESTAT_CLKRDY) | |
643 | + return 0; | |
644 | + } while (get_ticks() <= etime); | |
645 | + | |
646 | + printf("%s: timeout waiting for CLKRDY\n", enc->dev->name); | |
647 | + return -1; | |
648 | +} | |
649 | + | |
650 | +/* | |
651 | + * Write the MAC address into the ENC | |
652 | + */ | |
653 | +static int enc_write_macaddr(enc_dev_t *enc) | |
654 | +{ | |
655 | + unsigned char *p = enc->dev->enetaddr; | |
656 | + | |
657 | + enc_w8_retry(enc, CTL_REG_MAADR5, *p++, 5); | |
658 | + enc_w8_retry(enc, CTL_REG_MAADR4, *p++, 5); | |
659 | + enc_w8_retry(enc, CTL_REG_MAADR3, *p++, 5); | |
660 | + enc_w8_retry(enc, CTL_REG_MAADR2, *p++, 5); | |
661 | + enc_w8_retry(enc, CTL_REG_MAADR1, *p++, 5); | |
662 | + enc_w8_retry(enc, CTL_REG_MAADR0, *p, 5); | |
663 | + return 0; | |
664 | +} | |
665 | + | |
666 | +/* | |
667 | + * Setup most of the ENC registers | |
668 | + */ | |
669 | +static int enc_setup(enc_dev_t *enc) | |
670 | +{ | |
671 | + u16 phid1 = 0; | |
672 | + u16 phid2 = 0; | |
673 | + const u16 *tp; | |
674 | + | |
675 | + /* reset enc struct values */ | |
676 | + enc->next_pointer = ENC_RX_BUF_START; | |
677 | + enc->rx_reset_counter = RX_RESET_COUNTER; | |
678 | + enc->bank = 0xff; /* invalidate current bank in enc28j60 */ | |
679 | + | |
680 | + /* verify PHY identification */ | |
681 | + phid1 = phy_read(enc, PHY_REG_PHID1); | |
682 | + phid2 = phy_read(enc, PHY_REG_PHID2) & ENC_PHID2_MASK; | |
683 | + if (phid1 != ENC_PHID1_VALUE || phid2 != ENC_PHID2_VALUE) { | |
684 | + printf("%s: failed to identify PHY. Found %04x:%04x\n", | |
685 | + enc->dev->name, phid1, phid2); | |
686 | + return -1; | |
687 | + } | |
688 | + | |
689 | + /* now program registers */ | |
690 | + for (tp = enc_initdata; *tp != 0xffff; tp += 2) | |
691 | + enc_w8_retry(enc, tp[0], tp[1], 10); | |
692 | + | |
693 | + /* | |
694 | + * Prevent automatic loopback of data beeing transmitted by setting | |
695 | + * ENC_PHCON2_HDLDIS | |
696 | + */ | |
697 | + phy_write(enc, PHY_REG_PHCON2, (1<<8)); | |
698 | + | |
699 | + /* | |
700 | + * LEDs configuration | |
701 | + * LEDA: LACFG = 0100 -> display link status | |
702 | + * LEDB: LBCFG = 0111 -> display TX & RX activity | |
703 | + * STRCH = 1 -> LED pulses | |
704 | + */ | |
705 | + phy_write(enc, PHY_REG_PHLCON, 0x0472); | |
706 | + | |
707 | + /* Reset PDPXMD-bit => half duplex */ | |
708 | + phy_write(enc, PHY_REG_PHCON1, 0); | |
709 | + | |
710 | +#ifdef CONFIG_USE_IRQ | |
711 | + /* enable interrupts */ | |
712 | + enc_bset(enc, CTL_REG_EIE, ENC_EIE_PKTIE); | |
713 | + enc_bset(enc, CTL_REG_EIE, ENC_EIE_TXIE); | |
714 | + enc_bset(enc, CTL_REG_EIE, ENC_EIE_RXERIE); | |
715 | + enc_bset(enc, CTL_REG_EIE, ENC_EIE_TXERIE); | |
716 | + enc_bset(enc, CTL_REG_EIE, ENC_EIE_INTIE); | |
717 | +#endif | |
718 | + | |
719 | + return 0; | |
720 | +} | |
721 | + | |
722 | +/* | |
723 | + * Check if ENC has been initialized. | |
724 | + * If not, try to initialize it. | |
725 | + * Remember initialized state in struct. | |
726 | + */ | |
727 | +static int enc_initcheck(enc_dev_t *enc, const enum enc_initstate requiredstate) | |
728 | +{ | |
729 | + if (enc->initstate >= requiredstate) | |
730 | + return 0; | |
731 | + | |
732 | + if (enc->initstate < setupdone) { | |
733 | + /* Initialize the ENC only */ | |
734 | + enc_reset(enc); | |
735 | + /* if any of functions fails, skip the rest and return an error */ | |
736 | + if (enc_clock_wait(enc) || enc_setup(enc) || enc_write_macaddr(enc)) { | |
737 | + return -1; | |
738 | + } | |
739 | + enc->initstate = setupdone; | |
740 | + } | |
741 | + /* if that's all we need, return here */ | |
742 | + if (enc->initstate >= requiredstate) | |
743 | + return 0; | |
744 | + | |
745 | + /* now wait for link ready condition */ | |
746 | + if (enc_phy_link_wait(enc)) { | |
747 | + return -1; | |
748 | + } | |
749 | + enc->initstate = linkready; | |
750 | + return 0; | |
751 | +} | |
752 | + | |
753 | +#if defined(CONFIG_CMD_MII) | |
754 | +/* | |
755 | + * Read a PHY register. | |
756 | + * | |
757 | + * This function is registered with miiphy_register(). | |
758 | + */ | |
759 | +int enc_miiphy_read(const char *devname, u8 phy_adr, u8 reg, u16 *value) | |
760 | +{ | |
761 | + struct eth_device *dev = eth_get_dev_by_name(devname); | |
762 | + enc_dev_t *enc; | |
763 | + | |
764 | + if (!dev || phy_adr != 0) | |
765 | + return -1; | |
766 | + | |
767 | + enc = dev->priv; | |
768 | + if (enc_claim_bus(enc)) | |
769 | + return -1; | |
770 | + if (enc_initcheck(enc, setupdone)) { | |
771 | + enc_release_bus(enc); | |
772 | + return -1; | |
773 | + } | |
774 | + *value = phy_read(enc, reg); | |
775 | + enc_release_bus(enc); | |
776 | + return 0; | |
777 | +} | |
778 | + | |
779 | +/* | |
780 | + * Write a PHY register. | |
781 | + * | |
782 | + * This function is registered with miiphy_register(). | |
783 | + */ | |
784 | +int enc_miiphy_write(const char *devname, u8 phy_adr, u8 reg, u16 value) | |
785 | +{ | |
786 | + struct eth_device *dev = eth_get_dev_by_name(devname); | |
787 | + enc_dev_t *enc; | |
788 | + | |
789 | + if (!dev || phy_adr != 0) | |
790 | + return -1; | |
791 | + | |
792 | + enc = dev->priv; | |
793 | + if (enc_claim_bus(enc)) | |
794 | + return -1; | |
795 | + if (enc_initcheck(enc, setupdone)) { | |
796 | + enc_release_bus(enc); | |
797 | + return -1; | |
798 | + } | |
799 | + phy_write(enc, reg, value); | |
800 | + enc_release_bus(enc); | |
801 | + return 0; | |
802 | +} | |
803 | +#endif | |
804 | + | |
805 | +/* | |
806 | + * Write hardware (MAC) address. | |
807 | + * | |
808 | + * This function entered into eth_device structure. | |
809 | + */ | |
810 | +static int enc_write_hwaddr(struct eth_device *dev) | |
811 | +{ | |
812 | + enc_dev_t *enc = dev->priv; | |
813 | + | |
814 | + if (enc_claim_bus(enc)) | |
815 | + return -1; | |
816 | + if (enc_initcheck(enc, setupdone)) { | |
817 | + enc_release_bus(enc); | |
818 | + return -1; | |
819 | + } | |
820 | + enc_release_bus(enc); | |
821 | + return 0; | |
822 | +} | |
823 | + | |
824 | +/* | |
825 | + * Initialize ENC28J60 for use. | |
826 | + * | |
827 | + * This function entered into eth_device structure. | |
828 | + */ | |
829 | +static int enc_init(struct eth_device *dev, bd_t *bis) | |
830 | +{ | |
831 | + enc_dev_t *enc = dev->priv; | |
832 | + | |
833 | + if (enc_claim_bus(enc)) | |
834 | + return -1; | |
835 | + if (enc_initcheck(enc, linkready)) { | |
836 | + enc_release_bus(enc); | |
837 | + return -1; | |
838 | + } | |
839 | + /* enable receive */ | |
840 | + enc_bset(enc, CTL_REG_ECON1, ENC_ECON1_RXEN); | |
841 | + enc_release_bus(enc); | |
842 | + return 0; | |
843 | +} | |
844 | + | |
845 | +/* | |
846 | + * Check for received packets. | |
847 | + * | |
848 | + * This function entered into eth_device structure. | |
849 | + */ | |
850 | +static int enc_recv(struct eth_device *dev) | |
851 | +{ | |
852 | + enc_dev_t *enc = dev->priv; | |
853 | + | |
854 | + if (enc_claim_bus(enc)) | |
855 | + return -1; | |
856 | + if (enc_initcheck(enc, linkready)) { | |
857 | + enc_release_bus(enc); | |
858 | + return -1; | |
859 | + } | |
860 | + /* Check for dead receiver */ | |
861 | + if (enc->rx_reset_counter > 0) | |
862 | + enc->rx_reset_counter--; | |
863 | + else | |
864 | + enc_reset_rx_call(enc); | |
865 | + enc_poll(enc); | |
866 | + enc_release_bus(enc); | |
867 | + return 0; | |
868 | +} | |
869 | + | |
870 | +/* | |
871 | + * Send a packet. | |
872 | + * | |
873 | + * This function entered into eth_device structure. | |
874 | + * | |
875 | + * Should we wait here until we have a Link? Or shall we leave that to | |
876 | + * protocol retries? | |
877 | + */ | |
878 | +static int enc_send( | |
879 | + struct eth_device *dev, | |
880 | + volatile void *packet, | |
881 | + int length) | |
882 | +{ | |
883 | + enc_dev_t *enc = dev->priv; | |
884 | + | |
885 | + if (enc_claim_bus(enc)) | |
886 | + return -1; | |
887 | + if (enc_initcheck(enc, linkready)) { | |
888 | + enc_release_bus(enc); | |
889 | + return -1; | |
890 | + } | |
891 | + /* setup transmit pointers */ | |
892 | + enc_w16(enc, CTL_REG_EWRPTL, ENC_TX_BUF_START); | |
893 | + enc_w16(enc, CTL_REG_ETXNDL, length + ENC_TX_BUF_START); | |
894 | + enc_w16(enc, CTL_REG_ETXSTL, ENC_TX_BUF_START); | |
895 | + /* write packet to ENC */ | |
896 | + enc_wbuf(enc, length, (u8 *) packet, 0x00); | |
897 | + /* | |
898 | + * Check that the internal transmit logic has not been altered | |
899 | + * by excessive collisions. Reset transmitter if so. | |
900 | + * See Errata B4 12 and 14. | |
901 | + */ | |
902 | + if (enc_r8(enc, CTL_REG_EIR) & ENC_EIR_TXERIF) { | |
903 | + enc_bset(enc, CTL_REG_ECON1, ENC_ECON1_TXRST); | |
904 | + enc_bclr(enc, CTL_REG_ECON1, ENC_ECON1_TXRST); | |
905 | + } | |
906 | + enc_bclr(enc, CTL_REG_EIR, (ENC_EIR_TXERIF | ENC_EIR_TXIF)); | |
907 | + /* start transmitting */ | |
908 | + enc_bset(enc, CTL_REG_ECON1, ENC_ECON1_TXRTS); | |
909 | + enc_release_bus(enc); | |
910 | + return 0; | |
911 | +} | |
912 | + | |
913 | +/* | |
914 | + * Finish use of ENC. | |
915 | + * | |
916 | + * This function entered into eth_device structure. | |
917 | + */ | |
918 | +static void enc_halt(struct eth_device *dev) | |
919 | +{ | |
920 | + enc_dev_t *enc = dev->priv; | |
921 | + | |
922 | + if (enc_claim_bus(enc)) | |
923 | + return; | |
924 | + /* Just disable receiver */ | |
925 | + enc_bclr(enc, CTL_REG_ECON1, ENC_ECON1_RXEN); | |
926 | + enc_release_bus(enc); | |
927 | +} | |
928 | + | |
929 | +/* | |
930 | + * This is the only exported function. | |
931 | + * | |
932 | + * It may be called several times with different bus:cs combinations. | |
933 | + */ | |
934 | +int enc28j60_initialize(unsigned int bus, unsigned int cs, | |
935 | + unsigned int max_hz, unsigned int mode) | |
936 | +{ | |
937 | + struct eth_device *dev; | |
938 | + enc_dev_t *enc; | |
939 | + | |
940 | + /* try to allocate, check and clear eth_device object */ | |
941 | + dev = malloc(sizeof(*dev)); | |
942 | + if (!dev) { | |
943 | + return -1; | |
944 | + } | |
945 | + memset(dev, 0, sizeof(*dev)); | |
946 | + | |
947 | + /* try to allocate, check and clear enc_dev_t object */ | |
948 | + enc = malloc(sizeof(*enc)); | |
949 | + if (!enc) { | |
950 | + free(dev); | |
951 | + return -1; | |
952 | + } | |
953 | + memset(enc, 0, sizeof(*enc)); | |
954 | + | |
955 | + /* try to setup the SPI slave */ | |
956 | + enc->slave = spi_setup_slave(bus, cs, max_hz, mode); | |
957 | + if (!enc->slave) { | |
958 | + printf("enc28j60: invalid SPI device %i:%i\n", bus, cs); | |
959 | + free(enc); | |
960 | + free(dev); | |
961 | + return -1; | |
962 | + } | |
963 | + | |
964 | + enc->dev = dev; | |
965 | + /* now fill the eth_device object */ | |
966 | + dev->priv = enc; | |
967 | + dev->init = enc_init; | |
968 | + dev->halt = enc_halt; | |
969 | + dev->send = enc_send; | |
970 | + dev->recv = enc_recv; | |
971 | + dev->write_hwaddr = enc_write_hwaddr; | |
972 | + sprintf(dev->name, "enc%i.%i", bus, cs); | |
973 | + eth_register(dev); | |
974 | +#if defined(CONFIG_CMD_MII) | |
975 | + miiphy_register(dev->name, enc_miiphy_read, enc_miiphy_write); | |
976 | +#endif | |
977 | + return 0; | |
978 | +} |
drivers/net/enc28j60.h
1 | +/* | |
2 | + * (X) extracted from enc28j60.c | |
3 | + * Reinhard Meyer, EMK Elektronik, reinhard.meyer@emk-elektronik.de | |
4 | + * | |
5 | + * This program is free software; you can redistribute it and/or | |
6 | + * modify it under the terms of the GNU General Public License as | |
7 | + * published by the Free Software Foundation; either version 2 of | |
8 | + * the License, or (at your option) any later version. | |
9 | + * | |
10 | + * This program is distributed in the hope that it will be useful, | |
11 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | + * GNU General Public License for more details. | |
14 | + * | |
15 | + * You should have received a copy of the GNU General Public License | |
16 | + * along with this program; if not, write to the Free Software | |
17 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |
18 | + * MA 02111-1307 USA | |
19 | + */ | |
20 | + | |
21 | +#ifndef _enc28j60_h | |
22 | +#define _enc28j60_h | |
23 | + | |
24 | +/* | |
25 | + * SPI Commands | |
26 | + * | |
27 | + * Bits 7-5: Command | |
28 | + * Bits 4-0: Register | |
29 | + */ | |
30 | +#define CMD_RCR(x) (0x00+((x)&0x1f)) /* Read Control Register */ | |
31 | +#define CMD_RBM 0x3a /* Read Buffer Memory */ | |
32 | +#define CMD_WCR(x) (0x40+((x)&0x1f)) /* Write Control Register */ | |
33 | +#define CMD_WBM 0x7a /* Write Buffer Memory */ | |
34 | +#define CMD_BFS(x) (0x80+((x)&0x1f)) /* Bit Field Set */ | |
35 | +#define CMD_BFC(x) (0xa0+((x)&0x1f)) /* Bit Field Clear */ | |
36 | +#define CMD_SRC 0xff /* System Reset Command */ | |
37 | + | |
38 | +/* NEW: encode (bank number+1) in upper byte */ | |
39 | + | |
40 | +/* Common Control Registers accessible in all Banks */ | |
41 | +#define CTL_REG_EIE 0x01B | |
42 | +#define CTL_REG_EIR 0x01C | |
43 | +#define CTL_REG_ESTAT 0x01D | |
44 | +#define CTL_REG_ECON2 0x01E | |
45 | +#define CTL_REG_ECON1 0x01F | |
46 | + | |
47 | +/* Control Registers accessible in Bank 0 */ | |
48 | +#define CTL_REG_ERDPTL 0x100 | |
49 | +#define CTL_REG_ERDPTH 0x101 | |
50 | +#define CTL_REG_EWRPTL 0x102 | |
51 | +#define CTL_REG_EWRPTH 0x103 | |
52 | +#define CTL_REG_ETXSTL 0x104 | |
53 | +#define CTL_REG_ETXSTH 0x105 | |
54 | +#define CTL_REG_ETXNDL 0x106 | |
55 | +#define CTL_REG_ETXNDH 0x107 | |
56 | +#define CTL_REG_ERXSTL 0x108 | |
57 | +#define CTL_REG_ERXSTH 0x109 | |
58 | +#define CTL_REG_ERXNDL 0x10A | |
59 | +#define CTL_REG_ERXNDH 0x10B | |
60 | +#define CTL_REG_ERXRDPTL 0x10C | |
61 | +#define CTL_REG_ERXRDPTH 0x10D | |
62 | +#define CTL_REG_ERXWRPTL 0x10E | |
63 | +#define CTL_REG_ERXWRPTH 0x10F | |
64 | +#define CTL_REG_EDMASTL 0x110 | |
65 | +#define CTL_REG_EDMASTH 0x111 | |
66 | +#define CTL_REG_EDMANDL 0x112 | |
67 | +#define CTL_REG_EDMANDH 0x113 | |
68 | +#define CTL_REG_EDMADSTL 0x114 | |
69 | +#define CTL_REG_EDMADSTH 0x115 | |
70 | +#define CTL_REG_EDMACSL 0x116 | |
71 | +#define CTL_REG_EDMACSH 0x117 | |
72 | + | |
73 | +/* Control Registers accessible in Bank 1 */ | |
74 | +#define CTL_REG_EHT0 0x200 | |
75 | +#define CTL_REG_EHT1 0x201 | |
76 | +#define CTL_REG_EHT2 0x202 | |
77 | +#define CTL_REG_EHT3 0x203 | |
78 | +#define CTL_REG_EHT4 0x204 | |
79 | +#define CTL_REG_EHT5 0x205 | |
80 | +#define CTL_REG_EHT6 0x206 | |
81 | +#define CTL_REG_EHT7 0x207 | |
82 | +#define CTL_REG_EPMM0 0x208 | |
83 | +#define CTL_REG_EPMM1 0x209 | |
84 | +#define CTL_REG_EPMM2 0x20A | |
85 | +#define CTL_REG_EPMM3 0x20B | |
86 | +#define CTL_REG_EPMM4 0x20C | |
87 | +#define CTL_REG_EPMM5 0x20D | |
88 | +#define CTL_REG_EPMM6 0x20E | |
89 | +#define CTL_REG_EPMM7 0x20F | |
90 | +#define CTL_REG_EPMCSL 0x210 | |
91 | +#define CTL_REG_EPMCSH 0x211 | |
92 | +#define CTL_REG_EPMOL 0x214 | |
93 | +#define CTL_REG_EPMOH 0x215 | |
94 | +#define CTL_REG_EWOLIE 0x216 | |
95 | +#define CTL_REG_EWOLIR 0x217 | |
96 | +#define CTL_REG_ERXFCON 0x218 | |
97 | +#define CTL_REG_EPKTCNT 0x219 | |
98 | + | |
99 | +/* Control Registers accessible in Bank 2 */ | |
100 | +#define CTL_REG_MACON1 0x300 | |
101 | +#define CTL_REG_MACON2 0x301 | |
102 | +#define CTL_REG_MACON3 0x302 | |
103 | +#define CTL_REG_MACON4 0x303 | |
104 | +#define CTL_REG_MABBIPG 0x304 | |
105 | +#define CTL_REG_MAIPGL 0x306 | |
106 | +#define CTL_REG_MAIPGH 0x307 | |
107 | +#define CTL_REG_MACLCON1 0x308 | |
108 | +#define CTL_REG_MACLCON2 0x309 | |
109 | +#define CTL_REG_MAMXFLL 0x30A | |
110 | +#define CTL_REG_MAMXFLH 0x30B | |
111 | +#define CTL_REG_MAPHSUP 0x30D | |
112 | +#define CTL_REG_MICON 0x311 | |
113 | +#define CTL_REG_MICMD 0x312 | |
114 | +#define CTL_REG_MIREGADR 0x314 | |
115 | +#define CTL_REG_MIWRL 0x316 | |
116 | +#define CTL_REG_MIWRH 0x317 | |
117 | +#define CTL_REG_MIRDL 0x318 | |
118 | +#define CTL_REG_MIRDH 0x319 | |
119 | + | |
120 | +/* Control Registers accessible in Bank 3 */ | |
121 | +#define CTL_REG_MAADR1 0x400 | |
122 | +#define CTL_REG_MAADR0 0x401 | |
123 | +#define CTL_REG_MAADR3 0x402 | |
124 | +#define CTL_REG_MAADR2 0x403 | |
125 | +#define CTL_REG_MAADR5 0x404 | |
126 | +#define CTL_REG_MAADR4 0x405 | |
127 | +#define CTL_REG_EBSTSD 0x406 | |
128 | +#define CTL_REG_EBSTCON 0x407 | |
129 | +#define CTL_REG_EBSTCSL 0x408 | |
130 | +#define CTL_REG_EBSTCSH 0x409 | |
131 | +#define CTL_REG_MISTAT 0x40A | |
132 | +#define CTL_REG_EREVID 0x412 | |
133 | +#define CTL_REG_ECOCON 0x415 | |
134 | +#define CTL_REG_EFLOCON 0x417 | |
135 | +#define CTL_REG_EPAUSL 0x418 | |
136 | +#define CTL_REG_EPAUSH 0x419 | |
137 | + | |
138 | +/* PHY Register */ | |
139 | +#define PHY_REG_PHCON1 0x00 | |
140 | +#define PHY_REG_PHSTAT1 0x01 | |
141 | +#define PHY_REG_PHID1 0x02 | |
142 | +#define PHY_REG_PHID2 0x03 | |
143 | +#define PHY_REG_PHCON2 0x10 | |
144 | +#define PHY_REG_PHSTAT2 0x11 | |
145 | +#define PHY_REG_PHLCON 0x14 | |
146 | + | |
147 | +/* Receive Filter Register (ERXFCON) bits */ | |
148 | +#define ENC_RFR_UCEN 0x80 | |
149 | +#define ENC_RFR_ANDOR 0x40 | |
150 | +#define ENC_RFR_CRCEN 0x20 | |
151 | +#define ENC_RFR_PMEN 0x10 | |
152 | +#define ENC_RFR_MPEN 0x08 | |
153 | +#define ENC_RFR_HTEN 0x04 | |
154 | +#define ENC_RFR_MCEN 0x02 | |
155 | +#define ENC_RFR_BCEN 0x01 | |
156 | + | |
157 | +/* ECON1 Register Bits */ | |
158 | +#define ENC_ECON1_TXRST 0x80 | |
159 | +#define ENC_ECON1_RXRST 0x40 | |
160 | +#define ENC_ECON1_DMAST 0x20 | |
161 | +#define ENC_ECON1_CSUMEN 0x10 | |
162 | +#define ENC_ECON1_TXRTS 0x08 | |
163 | +#define ENC_ECON1_RXEN 0x04 | |
164 | +#define ENC_ECON1_BSEL1 0x02 | |
165 | +#define ENC_ECON1_BSEL0 0x01 | |
166 | + | |
167 | +/* ECON2 Register Bits */ | |
168 | +#define ENC_ECON2_AUTOINC 0x80 | |
169 | +#define ENC_ECON2_PKTDEC 0x40 | |
170 | +#define ENC_ECON2_PWRSV 0x20 | |
171 | +#define ENC_ECON2_VRPS 0x08 | |
172 | + | |
173 | +/* EIR Register Bits */ | |
174 | +#define ENC_EIR_PKTIF 0x40 | |
175 | +#define ENC_EIR_DMAIF 0x20 | |
176 | +#define ENC_EIR_LINKIF 0x10 | |
177 | +#define ENC_EIR_TXIF 0x08 | |
178 | +#define ENC_EIR_WOLIF 0x04 | |
179 | +#define ENC_EIR_TXERIF 0x02 | |
180 | +#define ENC_EIR_RXERIF 0x01 | |
181 | + | |
182 | +/* ESTAT Register Bits */ | |
183 | +#define ENC_ESTAT_INT 0x80 | |
184 | +#define ENC_ESTAT_LATECOL 0x10 | |
185 | +#define ENC_ESTAT_RXBUSY 0x04 | |
186 | +#define ENC_ESTAT_TXABRT 0x02 | |
187 | +#define ENC_ESTAT_CLKRDY 0x01 | |
188 | + | |
189 | +/* EIE Register Bits */ | |
190 | +#define ENC_EIE_INTIE 0x80 | |
191 | +#define ENC_EIE_PKTIE 0x40 | |
192 | +#define ENC_EIE_DMAIE 0x20 | |
193 | +#define ENC_EIE_LINKIE 0x10 | |
194 | +#define ENC_EIE_TXIE 0x08 | |
195 | +#define ENC_EIE_WOLIE 0x04 | |
196 | +#define ENC_EIE_TXERIE 0x02 | |
197 | +#define ENC_EIE_RXERIE 0x01 | |
198 | + | |
199 | +/* MACON1 Register Bits */ | |
200 | +#define ENC_MACON1_LOOPBK 0x10 | |
201 | +#define ENC_MACON1_TXPAUS 0x08 | |
202 | +#define ENC_MACON1_RXPAUS 0x04 | |
203 | +#define ENC_MACON1_PASSALL 0x02 | |
204 | +#define ENC_MACON1_MARXEN 0x01 | |
205 | + | |
206 | +/* MACON2 Register Bits */ | |
207 | +#define ENC_MACON2_MARST 0x80 | |
208 | +#define ENC_MACON2_RNDRST 0x40 | |
209 | +#define ENC_MACON2_MARXRST 0x08 | |
210 | +#define ENC_MACON2_RFUNRST 0x04 | |
211 | +#define ENC_MACON2_MATXRST 0x02 | |
212 | +#define ENC_MACON2_TFUNRST 0x01 | |
213 | + | |
214 | +/* MACON3 Register Bits */ | |
215 | +#define ENC_MACON3_PADCFG2 0x80 | |
216 | +#define ENC_MACON3_PADCFG1 0x40 | |
217 | +#define ENC_MACON3_PADCFG0 0x20 | |
218 | +#define ENC_MACON3_TXCRCEN 0x10 | |
219 | +#define ENC_MACON3_PHDRLEN 0x08 | |
220 | +#define ENC_MACON3_HFRMEN 0x04 | |
221 | +#define ENC_MACON3_FRMLNEN 0x02 | |
222 | +#define ENC_MACON3_FULDPX 0x01 | |
223 | + | |
224 | +/* MACON4 Register Bits */ | |
225 | +#define ENC_MACON4_DEFER 0x40 | |
226 | + | |
227 | +/* MICMD Register Bits */ | |
228 | +#define ENC_MICMD_MIISCAN 0x02 | |
229 | +#define ENC_MICMD_MIIRD 0x01 | |
230 | + | |
231 | +/* MISTAT Register Bits */ | |
232 | +#define ENC_MISTAT_NVALID 0x04 | |
233 | +#define ENC_MISTAT_SCAN 0x02 | |
234 | +#define ENC_MISTAT_BUSY 0x01 | |
235 | + | |
236 | +/* PHID1 and PHID2 values */ | |
237 | +#define ENC_PHID1_VALUE 0x0083 | |
238 | +#define ENC_PHID2_VALUE 0x1400 | |
239 | +#define ENC_PHID2_MASK 0xFC00 | |
240 | + | |
241 | +/* PHCON1 values */ | |
242 | +#define ENC_PHCON1_PDPXMD 0x0100 | |
243 | + | |
244 | +/* PHSTAT1 values */ | |
245 | +#define ENC_PHSTAT1_LLSTAT 0x0004 | |
246 | + | |
247 | +/* PHSTAT2 values */ | |
248 | +#define ENC_PHSTAT2_LSTAT 0x0400 | |
249 | +#define ENC_PHSTAT2_DPXSTAT 0x0200 | |
250 | + | |
251 | +#endif |
include/netdev.h
... | ... | @@ -54,6 +54,8 @@ |
54 | 54 | int dnet_eth_initialize(int id, void *regs, unsigned int phy_addr); |
55 | 55 | int e1000_initialize(bd_t *bis); |
56 | 56 | int eepro100_initialize(bd_t *bis); |
57 | +int enc28j60_initialize(unsigned int bus, unsigned int cs, | |
58 | + unsigned int max_hz, unsigned int mode); | |
57 | 59 | int ep93xx_eth_initialize(u8 dev_num, int base_addr); |
58 | 60 | int ethoc_initialize(u8 dev_num, int base_addr); |
59 | 61 | int eth_3com_initialize (bd_t * bis); |