1a61a8196SReinhard Meyer /*
2a61a8196SReinhard Meyer * (C) Copyright 2010
3a61a8196SReinhard Meyer * Reinhard Meyer, EMK Elektronik, reinhard.meyer@emk-elektronik.de
4a61a8196SReinhard Meyer * Martin Krause, Martin.Krause@tqs.de
5a61a8196SReinhard Meyer * reworked original enc28j60.c
6a61a8196SReinhard Meyer *
71a459660SWolfgang Denk * SPDX-License-Identifier: GPL-2.0+
8a61a8196SReinhard Meyer */
9a61a8196SReinhard Meyer
10a61a8196SReinhard Meyer #include <common.h>
11a61a8196SReinhard Meyer #include <net.h>
12a61a8196SReinhard Meyer #include <spi.h>
13a61a8196SReinhard Meyer #include <malloc.h>
14a61a8196SReinhard Meyer #include <netdev.h>
15a61a8196SReinhard Meyer #include <miiphy.h>
16a61a8196SReinhard Meyer #include "enc28j60.h"
17a61a8196SReinhard Meyer
18a61a8196SReinhard Meyer /*
19a61a8196SReinhard Meyer * IMPORTANT: spi_claim_bus() and spi_release_bus()
20a61a8196SReinhard Meyer * are called at begin and end of each of the following functions:
21a61a8196SReinhard Meyer * enc_miiphy_read(), enc_miiphy_write(), enc_write_hwaddr(),
22a61a8196SReinhard Meyer * enc_init(), enc_recv(), enc_send(), enc_halt()
23a61a8196SReinhard Meyer * ALL other functions assume that the bus has already been claimed!
241fd92db8SJoe Hershberger * Since net_process_received_packet() might call enc_send() in return, the bus
251fd92db8SJoe Hershberger * must be released, net_process_received_packet() called and claimed again.
26a61a8196SReinhard Meyer */
27a61a8196SReinhard Meyer
28a61a8196SReinhard Meyer /*
29a61a8196SReinhard Meyer * Controller memory layout.
30a61a8196SReinhard Meyer * We only allow 1 frame for transmission and reserve the rest
31a61a8196SReinhard Meyer * for reception to handle as many broadcast packets as possible.
32a61a8196SReinhard Meyer * Also use the memory from 0x0000 for receiver buffer. See errata pt. 5
33a61a8196SReinhard Meyer * 0x0000 - 0x19ff 6656 bytes receive buffer
34a61a8196SReinhard Meyer * 0x1a00 - 0x1fff 1536 bytes transmit buffer =
35a61a8196SReinhard Meyer * control(1)+frame(1518)+status(7)+reserve(10).
36a61a8196SReinhard Meyer */
37a61a8196SReinhard Meyer #define ENC_RX_BUF_START 0x0000
38a61a8196SReinhard Meyer #define ENC_RX_BUF_END 0x19ff
39a61a8196SReinhard Meyer #define ENC_TX_BUF_START 0x1a00
40a61a8196SReinhard Meyer #define ENC_TX_BUF_END 0x1fff
41a61a8196SReinhard Meyer #define ENC_MAX_FRM_LEN 1518
42a61a8196SReinhard Meyer #define RX_RESET_COUNTER 1000
43a61a8196SReinhard Meyer
44a61a8196SReinhard Meyer /*
45a61a8196SReinhard Meyer * For non data transfer functions, like phy read/write, set hwaddr, init
46a61a8196SReinhard Meyer * we do not need a full, time consuming init including link ready wait.
47a61a8196SReinhard Meyer * This enum helps to bring the chip through the minimum necessary inits.
48a61a8196SReinhard Meyer */
49a61a8196SReinhard Meyer enum enc_initstate {none=0, setupdone, linkready};
50a61a8196SReinhard Meyer typedef struct enc_device {
51a61a8196SReinhard Meyer struct eth_device *dev; /* back pointer */
52a61a8196SReinhard Meyer struct spi_slave *slave;
53a61a8196SReinhard Meyer int rx_reset_counter;
54a61a8196SReinhard Meyer u16 next_pointer;
55a61a8196SReinhard Meyer u8 bank; /* current bank in enc28j60 */
56a61a8196SReinhard Meyer enum enc_initstate initstate;
57a61a8196SReinhard Meyer } enc_dev_t;
58a61a8196SReinhard Meyer
59a61a8196SReinhard Meyer /*
60a61a8196SReinhard Meyer * enc_bset: set bits in a common register
61a61a8196SReinhard Meyer * enc_bclr: clear bits in a common register
62a61a8196SReinhard Meyer *
63a61a8196SReinhard Meyer * making the reg parameter u8 will give a compile time warning if the
64a61a8196SReinhard Meyer * functions are called with a register not accessible in all Banks
65a61a8196SReinhard Meyer */
enc_bset(enc_dev_t * enc,const u8 reg,const u8 data)66a61a8196SReinhard Meyer static void enc_bset(enc_dev_t *enc, const u8 reg, const u8 data)
67a61a8196SReinhard Meyer {
68a61a8196SReinhard Meyer u8 dout[2];
69a61a8196SReinhard Meyer
70a61a8196SReinhard Meyer dout[0] = CMD_BFS(reg);
71a61a8196SReinhard Meyer dout[1] = data;
72a61a8196SReinhard Meyer spi_xfer(enc->slave, 2 * 8, dout, NULL,
73a61a8196SReinhard Meyer SPI_XFER_BEGIN | SPI_XFER_END);
74a61a8196SReinhard Meyer }
75a61a8196SReinhard Meyer
enc_bclr(enc_dev_t * enc,const u8 reg,const u8 data)76a61a8196SReinhard Meyer static void enc_bclr(enc_dev_t *enc, const u8 reg, const u8 data)
77a61a8196SReinhard Meyer {
78a61a8196SReinhard Meyer u8 dout[2];
79a61a8196SReinhard Meyer
80a61a8196SReinhard Meyer dout[0] = CMD_BFC(reg);
81a61a8196SReinhard Meyer dout[1] = data;
82a61a8196SReinhard Meyer spi_xfer(enc->slave, 2 * 8, dout, NULL,
83a61a8196SReinhard Meyer SPI_XFER_BEGIN | SPI_XFER_END);
84a61a8196SReinhard Meyer }
85a61a8196SReinhard Meyer
86a61a8196SReinhard Meyer /*
87a61a8196SReinhard Meyer * high byte of the register contains bank number:
88a61a8196SReinhard Meyer * 0: no bank switch necessary
89a61a8196SReinhard Meyer * 1: switch to bank 0
90a61a8196SReinhard Meyer * 2: switch to bank 1
91a61a8196SReinhard Meyer * 3: switch to bank 2
92a61a8196SReinhard Meyer * 4: switch to bank 3
93a61a8196SReinhard Meyer */
enc_set_bank(enc_dev_t * enc,const u16 reg)94a61a8196SReinhard Meyer static void enc_set_bank(enc_dev_t *enc, const u16 reg)
95a61a8196SReinhard Meyer {
96a61a8196SReinhard Meyer u8 newbank = reg >> 8;
97a61a8196SReinhard Meyer
98a61a8196SReinhard Meyer if (newbank == 0 || newbank == enc->bank)
99a61a8196SReinhard Meyer return;
100a61a8196SReinhard Meyer switch (newbank) {
101a61a8196SReinhard Meyer case 1:
102a61a8196SReinhard Meyer enc_bclr(enc, CTL_REG_ECON1,
103a61a8196SReinhard Meyer ENC_ECON1_BSEL0 | ENC_ECON1_BSEL1);
104a61a8196SReinhard Meyer break;
105a61a8196SReinhard Meyer case 2:
106a61a8196SReinhard Meyer enc_bset(enc, CTL_REG_ECON1, ENC_ECON1_BSEL0);
107a61a8196SReinhard Meyer enc_bclr(enc, CTL_REG_ECON1, ENC_ECON1_BSEL1);
108a61a8196SReinhard Meyer break;
109a61a8196SReinhard Meyer case 3:
110a61a8196SReinhard Meyer enc_bclr(enc, CTL_REG_ECON1, ENC_ECON1_BSEL0);
111a61a8196SReinhard Meyer enc_bset(enc, CTL_REG_ECON1, ENC_ECON1_BSEL1);
112a61a8196SReinhard Meyer break;
113a61a8196SReinhard Meyer case 4:
114a61a8196SReinhard Meyer enc_bset(enc, CTL_REG_ECON1,
115a61a8196SReinhard Meyer ENC_ECON1_BSEL0 | ENC_ECON1_BSEL1);
116a61a8196SReinhard Meyer break;
117a61a8196SReinhard Meyer }
118a61a8196SReinhard Meyer enc->bank = newbank;
119a61a8196SReinhard Meyer }
120a61a8196SReinhard Meyer
121a61a8196SReinhard Meyer /*
122a61a8196SReinhard Meyer * local functions to access SPI
123a61a8196SReinhard Meyer *
124a61a8196SReinhard Meyer * reg: register inside ENC28J60
125a61a8196SReinhard Meyer * data: 8/16 bits to write
126a61a8196SReinhard Meyer * c: number of retries
127a61a8196SReinhard Meyer *
128a61a8196SReinhard Meyer * enc_r8: read 8 bits
129a61a8196SReinhard Meyer * enc_r16: read 16 bits
130a61a8196SReinhard Meyer * enc_w8: write 8 bits
131a61a8196SReinhard Meyer * enc_w16: write 16 bits
132a61a8196SReinhard Meyer * enc_w8_retry: write 8 bits, verify and retry
133a61a8196SReinhard Meyer * enc_rbuf: read from ENC28J60 into buffer
134a61a8196SReinhard Meyer * enc_wbuf: write from buffer into ENC28J60
135a61a8196SReinhard Meyer */
136a61a8196SReinhard Meyer
137a61a8196SReinhard Meyer /*
138a61a8196SReinhard Meyer * MAC and MII registers need a 3 byte SPI transfer to read,
139a61a8196SReinhard Meyer * all other registers need a 2 byte SPI transfer.
140a61a8196SReinhard Meyer */
enc_reg2nbytes(const u16 reg)141a61a8196SReinhard Meyer static int enc_reg2nbytes(const u16 reg)
142a61a8196SReinhard Meyer {
143a61a8196SReinhard Meyer /* check if MAC or MII register */
144a61a8196SReinhard Meyer return ((reg >= CTL_REG_MACON1 && reg <= CTL_REG_MIRDH) ||
145a61a8196SReinhard Meyer (reg >= CTL_REG_MAADR1 && reg <= CTL_REG_MAADR4) ||
146a61a8196SReinhard Meyer (reg == CTL_REG_MISTAT)) ? 3 : 2;
147a61a8196SReinhard Meyer }
148a61a8196SReinhard Meyer
149a61a8196SReinhard Meyer /*
150a61a8196SReinhard Meyer * Read a byte register
151a61a8196SReinhard Meyer */
enc_r8(enc_dev_t * enc,const u16 reg)152a61a8196SReinhard Meyer static u8 enc_r8(enc_dev_t *enc, const u16 reg)
153a61a8196SReinhard Meyer {
154a61a8196SReinhard Meyer u8 dout[3];
155a61a8196SReinhard Meyer u8 din[3];
156a61a8196SReinhard Meyer int nbytes = enc_reg2nbytes(reg);
157a61a8196SReinhard Meyer
158a61a8196SReinhard Meyer enc_set_bank(enc, reg);
159a61a8196SReinhard Meyer dout[0] = CMD_RCR(reg);
160a61a8196SReinhard Meyer spi_xfer(enc->slave, nbytes * 8, dout, din,
161a61a8196SReinhard Meyer SPI_XFER_BEGIN | SPI_XFER_END);
162a61a8196SReinhard Meyer return din[nbytes-1];
163a61a8196SReinhard Meyer }
164a61a8196SReinhard Meyer
165a61a8196SReinhard Meyer /*
166a61a8196SReinhard Meyer * Read a L/H register pair and return a word.
167a61a8196SReinhard Meyer * Must be called with the L register's address.
168a61a8196SReinhard Meyer */
enc_r16(enc_dev_t * enc,const u16 reg)169a61a8196SReinhard Meyer static u16 enc_r16(enc_dev_t *enc, const u16 reg)
170a61a8196SReinhard Meyer {
171a61a8196SReinhard Meyer u8 dout[3];
172a61a8196SReinhard Meyer u8 din[3];
173a61a8196SReinhard Meyer u16 result;
174a61a8196SReinhard Meyer int nbytes = enc_reg2nbytes(reg);
175a61a8196SReinhard Meyer
176a61a8196SReinhard Meyer enc_set_bank(enc, reg);
177a61a8196SReinhard Meyer dout[0] = CMD_RCR(reg);
178a61a8196SReinhard Meyer spi_xfer(enc->slave, nbytes * 8, dout, din,
179a61a8196SReinhard Meyer SPI_XFER_BEGIN | SPI_XFER_END);
180a61a8196SReinhard Meyer result = din[nbytes-1];
181a61a8196SReinhard Meyer dout[0]++; /* next register */
182a61a8196SReinhard Meyer spi_xfer(enc->slave, nbytes * 8, dout, din,
183a61a8196SReinhard Meyer SPI_XFER_BEGIN | SPI_XFER_END);
184a61a8196SReinhard Meyer result |= din[nbytes-1] << 8;
185a61a8196SReinhard Meyer return result;
186a61a8196SReinhard Meyer }
187a61a8196SReinhard Meyer
188a61a8196SReinhard Meyer /*
189a61a8196SReinhard Meyer * Write a byte register
190a61a8196SReinhard Meyer */
enc_w8(enc_dev_t * enc,const u16 reg,const u8 data)191a61a8196SReinhard Meyer static void enc_w8(enc_dev_t *enc, const u16 reg, const u8 data)
192a61a8196SReinhard Meyer {
193a61a8196SReinhard Meyer u8 dout[2];
194a61a8196SReinhard Meyer
195a61a8196SReinhard Meyer enc_set_bank(enc, reg);
196a61a8196SReinhard Meyer dout[0] = CMD_WCR(reg);
197a61a8196SReinhard Meyer dout[1] = data;
198a61a8196SReinhard Meyer spi_xfer(enc->slave, 2 * 8, dout, NULL,
199a61a8196SReinhard Meyer SPI_XFER_BEGIN | SPI_XFER_END);
200a61a8196SReinhard Meyer }
201a61a8196SReinhard Meyer
202a61a8196SReinhard Meyer /*
203a61a8196SReinhard Meyer * Write a L/H register pair.
204a61a8196SReinhard Meyer * Must be called with the L register's address.
205a61a8196SReinhard Meyer */
enc_w16(enc_dev_t * enc,const u16 reg,const u16 data)206a61a8196SReinhard Meyer static void enc_w16(enc_dev_t *enc, const u16 reg, const u16 data)
207a61a8196SReinhard Meyer {
208a61a8196SReinhard Meyer u8 dout[2];
209a61a8196SReinhard Meyer
210a61a8196SReinhard Meyer enc_set_bank(enc, reg);
211a61a8196SReinhard Meyer dout[0] = CMD_WCR(reg);
212a61a8196SReinhard Meyer dout[1] = data;
213a61a8196SReinhard Meyer spi_xfer(enc->slave, 2 * 8, dout, NULL,
214a61a8196SReinhard Meyer SPI_XFER_BEGIN | SPI_XFER_END);
215a61a8196SReinhard Meyer dout[0]++; /* next register */
216a61a8196SReinhard Meyer dout[1] = data >> 8;
217a61a8196SReinhard Meyer spi_xfer(enc->slave, 2 * 8, dout, NULL,
218a61a8196SReinhard Meyer SPI_XFER_BEGIN | SPI_XFER_END);
219a61a8196SReinhard Meyer }
220a61a8196SReinhard Meyer
221a61a8196SReinhard Meyer /*
222a61a8196SReinhard Meyer * Write a byte register, verify and retry
223a61a8196SReinhard Meyer */
enc_w8_retry(enc_dev_t * enc,const u16 reg,const u8 data,const int c)224a61a8196SReinhard Meyer static void enc_w8_retry(enc_dev_t *enc, const u16 reg, const u8 data, const int c)
225a61a8196SReinhard Meyer {
226a61a8196SReinhard Meyer u8 dout[2];
227a61a8196SReinhard Meyer u8 readback;
228a61a8196SReinhard Meyer int i;
229a61a8196SReinhard Meyer
230a61a8196SReinhard Meyer enc_set_bank(enc, reg);
231a61a8196SReinhard Meyer for (i = 0; i < c; i++) {
232a61a8196SReinhard Meyer dout[0] = CMD_WCR(reg);
233a61a8196SReinhard Meyer dout[1] = data;
234a61a8196SReinhard Meyer spi_xfer(enc->slave, 2 * 8, dout, NULL,
235a61a8196SReinhard Meyer SPI_XFER_BEGIN | SPI_XFER_END);
236a61a8196SReinhard Meyer readback = enc_r8(enc, reg);
237a61a8196SReinhard Meyer if (readback == data)
238a61a8196SReinhard Meyer break;
239a61a8196SReinhard Meyer /* wait 1ms */
240a61a8196SReinhard Meyer udelay(1000);
241a61a8196SReinhard Meyer }
242a61a8196SReinhard Meyer if (i == c) {
243a61a8196SReinhard Meyer printf("%s: write reg 0x%03x failed\n", enc->dev->name, reg);
244a61a8196SReinhard Meyer }
245a61a8196SReinhard Meyer }
246a61a8196SReinhard Meyer
247a61a8196SReinhard Meyer /*
248a61a8196SReinhard Meyer * Read ENC RAM into buffer
249a61a8196SReinhard Meyer */
enc_rbuf(enc_dev_t * enc,const u16 length,u8 * buf)250a61a8196SReinhard Meyer static void enc_rbuf(enc_dev_t *enc, const u16 length, u8 *buf)
251a61a8196SReinhard Meyer {
252a61a8196SReinhard Meyer u8 dout[1];
253a61a8196SReinhard Meyer
254a61a8196SReinhard Meyer dout[0] = CMD_RBM;
255a61a8196SReinhard Meyer spi_xfer(enc->slave, 8, dout, NULL, SPI_XFER_BEGIN);
256a61a8196SReinhard Meyer spi_xfer(enc->slave, length * 8, NULL, buf, SPI_XFER_END);
257a61a8196SReinhard Meyer #ifdef DEBUG
258a61a8196SReinhard Meyer puts("Rx:\n");
259a61a8196SReinhard Meyer print_buffer(0, buf, 1, length, 0);
260a61a8196SReinhard Meyer #endif
261a61a8196SReinhard Meyer }
262a61a8196SReinhard Meyer
263a61a8196SReinhard Meyer /*
264a61a8196SReinhard Meyer * Write buffer into ENC RAM
265a61a8196SReinhard Meyer */
enc_wbuf(enc_dev_t * enc,const u16 length,const u8 * buf,const u8 control)266a61a8196SReinhard Meyer static void enc_wbuf(enc_dev_t *enc, const u16 length, const u8 *buf, const u8 control)
267a61a8196SReinhard Meyer {
268a61a8196SReinhard Meyer u8 dout[2];
269a61a8196SReinhard Meyer dout[0] = CMD_WBM;
270a61a8196SReinhard Meyer dout[1] = control;
271a61a8196SReinhard Meyer spi_xfer(enc->slave, 2 * 8, dout, NULL, SPI_XFER_BEGIN);
272a61a8196SReinhard Meyer spi_xfer(enc->slave, length * 8, buf, NULL, SPI_XFER_END);
273a61a8196SReinhard Meyer #ifdef DEBUG
274a61a8196SReinhard Meyer puts("Tx:\n");
275a61a8196SReinhard Meyer print_buffer(0, buf, 1, length, 0);
276a61a8196SReinhard Meyer #endif
277a61a8196SReinhard Meyer }
278a61a8196SReinhard Meyer
279a61a8196SReinhard Meyer /*
280a61a8196SReinhard Meyer * Try to claim the SPI bus.
281a61a8196SReinhard Meyer * Print error message on failure.
282a61a8196SReinhard Meyer */
enc_claim_bus(enc_dev_t * enc)283a61a8196SReinhard Meyer static int enc_claim_bus(enc_dev_t *enc)
284a61a8196SReinhard Meyer {
285a61a8196SReinhard Meyer int rc = spi_claim_bus(enc->slave);
286a61a8196SReinhard Meyer if (rc)
287a61a8196SReinhard Meyer printf("%s: failed to claim SPI bus\n", enc->dev->name);
288a61a8196SReinhard Meyer return rc;
289a61a8196SReinhard Meyer }
290a61a8196SReinhard Meyer
291a61a8196SReinhard Meyer /*
292a61a8196SReinhard Meyer * Release previously claimed SPI bus.
293a61a8196SReinhard Meyer * This function is mainly for symmetry to enc_claim_bus().
294a61a8196SReinhard Meyer * Let the toolchain decide to inline it...
295a61a8196SReinhard Meyer */
enc_release_bus(enc_dev_t * enc)296a61a8196SReinhard Meyer static void enc_release_bus(enc_dev_t *enc)
297a61a8196SReinhard Meyer {
298a61a8196SReinhard Meyer spi_release_bus(enc->slave);
299a61a8196SReinhard Meyer }
300a61a8196SReinhard Meyer
301a61a8196SReinhard Meyer /*
302a61a8196SReinhard Meyer * Read PHY register
303a61a8196SReinhard Meyer */
enc_phy_read(enc_dev_t * enc,const u8 addr)30409c04c20SAndy Fleming static u16 enc_phy_read(enc_dev_t *enc, const u8 addr)
305a61a8196SReinhard Meyer {
306a61a8196SReinhard Meyer uint64_t etime;
307a61a8196SReinhard Meyer u8 status;
308a61a8196SReinhard Meyer
309a61a8196SReinhard Meyer enc_w8(enc, CTL_REG_MIREGADR, addr);
310a61a8196SReinhard Meyer enc_w8(enc, CTL_REG_MICMD, ENC_MICMD_MIIRD);
311a61a8196SReinhard Meyer /* 1 second timeout - only happens on hardware problem */
312a61a8196SReinhard Meyer etime = get_ticks() + get_tbclk();
313a61a8196SReinhard Meyer /* poll MISTAT.BUSY bit until operation is complete */
314a61a8196SReinhard Meyer do
315a61a8196SReinhard Meyer {
316a61a8196SReinhard Meyer status = enc_r8(enc, CTL_REG_MISTAT);
317a61a8196SReinhard Meyer } while (get_ticks() <= etime && (status & ENC_MISTAT_BUSY));
318a61a8196SReinhard Meyer if (status & ENC_MISTAT_BUSY) {
319a61a8196SReinhard Meyer printf("%s: timeout reading phy\n", enc->dev->name);
320a61a8196SReinhard Meyer return 0;
321a61a8196SReinhard Meyer }
322a61a8196SReinhard Meyer enc_w8(enc, CTL_REG_MICMD, 0);
323a61a8196SReinhard Meyer return enc_r16(enc, CTL_REG_MIRDL);
324a61a8196SReinhard Meyer }
325a61a8196SReinhard Meyer
326a61a8196SReinhard Meyer /*
327a61a8196SReinhard Meyer * Write PHY register
328a61a8196SReinhard Meyer */
enc_phy_write(enc_dev_t * enc,const u8 addr,const u16 data)32909c04c20SAndy Fleming static void enc_phy_write(enc_dev_t *enc, const u8 addr, const u16 data)
330a61a8196SReinhard Meyer {
331a61a8196SReinhard Meyer uint64_t etime;
332a61a8196SReinhard Meyer u8 status;
333a61a8196SReinhard Meyer
334a61a8196SReinhard Meyer enc_w8(enc, CTL_REG_MIREGADR, addr);
335a61a8196SReinhard Meyer enc_w16(enc, CTL_REG_MIWRL, data);
336a61a8196SReinhard Meyer /* 1 second timeout - only happens on hardware problem */
337a61a8196SReinhard Meyer etime = get_ticks() + get_tbclk();
338a61a8196SReinhard Meyer /* poll MISTAT.BUSY bit until operation is complete */
339a61a8196SReinhard Meyer do
340a61a8196SReinhard Meyer {
341a61a8196SReinhard Meyer status = enc_r8(enc, CTL_REG_MISTAT);
342a61a8196SReinhard Meyer } while (get_ticks() <= etime && (status & ENC_MISTAT_BUSY));
343a61a8196SReinhard Meyer if (status & ENC_MISTAT_BUSY) {
344a61a8196SReinhard Meyer printf("%s: timeout writing phy\n", enc->dev->name);
345a61a8196SReinhard Meyer return;
346a61a8196SReinhard Meyer }
347a61a8196SReinhard Meyer }
348a61a8196SReinhard Meyer
349a61a8196SReinhard Meyer /*
350a61a8196SReinhard Meyer * Verify link status, wait if necessary
351a61a8196SReinhard Meyer *
352a61a8196SReinhard Meyer * Note: with a 10 MBit/s only PHY there is no autonegotiation possible,
353a61a8196SReinhard Meyer * half/full duplex is a pure setup matter. For the time being, this driver
354a61a8196SReinhard Meyer * will setup in half duplex mode only.
355a61a8196SReinhard Meyer */
enc_phy_link_wait(enc_dev_t * enc)356a61a8196SReinhard Meyer static int enc_phy_link_wait(enc_dev_t *enc)
357a61a8196SReinhard Meyer {
358a61a8196SReinhard Meyer u16 status;
359a61a8196SReinhard Meyer int duplex;
360a61a8196SReinhard Meyer uint64_t etime;
361a61a8196SReinhard Meyer
362a61a8196SReinhard Meyer #ifdef CONFIG_ENC_SILENTLINK
363a61a8196SReinhard Meyer /* check if we have a link, then just return */
36409c04c20SAndy Fleming status = enc_phy_read(enc, PHY_REG_PHSTAT1);
365a61a8196SReinhard Meyer if (status & ENC_PHSTAT1_LLSTAT)
366a61a8196SReinhard Meyer return 0;
367a61a8196SReinhard Meyer #endif
368a61a8196SReinhard Meyer
369a61a8196SReinhard Meyer /* wait for link with 1 second timeout */
370a61a8196SReinhard Meyer etime = get_ticks() + get_tbclk();
371a61a8196SReinhard Meyer while (get_ticks() <= etime) {
37209c04c20SAndy Fleming status = enc_phy_read(enc, PHY_REG_PHSTAT1);
373a61a8196SReinhard Meyer if (status & ENC_PHSTAT1_LLSTAT) {
374a61a8196SReinhard Meyer /* now we have a link */
37509c04c20SAndy Fleming status = enc_phy_read(enc, PHY_REG_PHSTAT2);
376a61a8196SReinhard Meyer duplex = (status & ENC_PHSTAT2_DPXSTAT) ? 1 : 0;
377a61a8196SReinhard Meyer printf("%s: link up, 10Mbps %s-duplex\n",
378a61a8196SReinhard Meyer enc->dev->name, duplex ? "full" : "half");
379a61a8196SReinhard Meyer return 0;
380a61a8196SReinhard Meyer }
381a61a8196SReinhard Meyer udelay(1000);
382a61a8196SReinhard Meyer }
383a61a8196SReinhard Meyer
384eae4b2b6SVagrant Cascadian /* timeout occurred */
385a61a8196SReinhard Meyer printf("%s: link down\n", enc->dev->name);
386a61a8196SReinhard Meyer return 1;
387a61a8196SReinhard Meyer }
388a61a8196SReinhard Meyer
389a61a8196SReinhard Meyer /*
390a61a8196SReinhard Meyer * This function resets the receiver only.
391a61a8196SReinhard Meyer */
enc_reset_rx(enc_dev_t * enc)392a61a8196SReinhard Meyer static void enc_reset_rx(enc_dev_t *enc)
393a61a8196SReinhard Meyer {
394a61a8196SReinhard Meyer u8 econ1;
395a61a8196SReinhard Meyer
396a61a8196SReinhard Meyer econ1 = enc_r8(enc, CTL_REG_ECON1);
397a61a8196SReinhard Meyer if ((econ1 & ENC_ECON1_RXRST) == 0) {
398a61a8196SReinhard Meyer enc_bset(enc, CTL_REG_ECON1, ENC_ECON1_RXRST);
399a61a8196SReinhard Meyer enc->rx_reset_counter = RX_RESET_COUNTER;
400a61a8196SReinhard Meyer }
401a61a8196SReinhard Meyer }
402a61a8196SReinhard Meyer
403a61a8196SReinhard Meyer /*
404a61a8196SReinhard Meyer * Reset receiver and reenable it.
405a61a8196SReinhard Meyer */
enc_reset_rx_call(enc_dev_t * enc)406a61a8196SReinhard Meyer static void enc_reset_rx_call(enc_dev_t *enc)
407a61a8196SReinhard Meyer {
408a61a8196SReinhard Meyer enc_bclr(enc, CTL_REG_ECON1, ENC_ECON1_RXRST);
409a61a8196SReinhard Meyer enc_bset(enc, CTL_REG_ECON1, ENC_ECON1_RXEN);
410a61a8196SReinhard Meyer }
411a61a8196SReinhard Meyer
412a61a8196SReinhard Meyer /*
413a61a8196SReinhard Meyer * Copy a packet from the receive ring and forward it to
414a61a8196SReinhard Meyer * the protocol stack.
415a61a8196SReinhard Meyer */
enc_receive(enc_dev_t * enc)416a61a8196SReinhard Meyer static void enc_receive(enc_dev_t *enc)
417a61a8196SReinhard Meyer {
4181fd92db8SJoe Hershberger u8 *packet = (u8 *)net_rx_packets[0];
419a61a8196SReinhard Meyer u16 pkt_len;
420a61a8196SReinhard Meyer u16 copy_len;
421a61a8196SReinhard Meyer u16 status;
422a61a8196SReinhard Meyer u8 pkt_cnt = 0;
423a61a8196SReinhard Meyer u16 rxbuf_rdpt;
424a61a8196SReinhard Meyer u8 hbuf[6];
425a61a8196SReinhard Meyer
426a61a8196SReinhard Meyer enc_w16(enc, CTL_REG_ERDPTL, enc->next_pointer);
427a61a8196SReinhard Meyer do {
428a61a8196SReinhard Meyer enc_rbuf(enc, 6, hbuf);
429a61a8196SReinhard Meyer enc->next_pointer = hbuf[0] | (hbuf[1] << 8);
430a61a8196SReinhard Meyer pkt_len = hbuf[2] | (hbuf[3] << 8);
431a61a8196SReinhard Meyer status = hbuf[4] | (hbuf[5] << 8);
432a61a8196SReinhard Meyer debug("next_pointer=$%04x pkt_len=%u status=$%04x\n",
433a61a8196SReinhard Meyer enc->next_pointer, pkt_len, status);
434a61a8196SReinhard Meyer if (pkt_len <= ENC_MAX_FRM_LEN)
435a61a8196SReinhard Meyer copy_len = pkt_len;
436a61a8196SReinhard Meyer else
437a61a8196SReinhard Meyer copy_len = 0;
438a61a8196SReinhard Meyer if ((status & (1L << 7)) == 0) /* check Received Ok bit */
439a61a8196SReinhard Meyer copy_len = 0;
440a61a8196SReinhard Meyer /* check if next pointer is resonable */
441a61a8196SReinhard Meyer if (enc->next_pointer >= ENC_TX_BUF_START)
442a61a8196SReinhard Meyer copy_len = 0;
443a61a8196SReinhard Meyer if (copy_len > 0) {
444a61a8196SReinhard Meyer enc_rbuf(enc, copy_len, packet);
445a61a8196SReinhard Meyer }
446a61a8196SReinhard Meyer /* advance read pointer to next pointer */
447a61a8196SReinhard Meyer enc_w16(enc, CTL_REG_ERDPTL, enc->next_pointer);
448a61a8196SReinhard Meyer /* decrease packet counter */
449a61a8196SReinhard Meyer enc_bset(enc, CTL_REG_ECON2, ENC_ECON2_PKTDEC);
450a61a8196SReinhard Meyer /*
451a61a8196SReinhard Meyer * Only odd values should be written to ERXRDPTL,
452a61a8196SReinhard Meyer * see errata B4 pt.13
453a61a8196SReinhard Meyer */
454a61a8196SReinhard Meyer rxbuf_rdpt = enc->next_pointer - 1;
455a61a8196SReinhard Meyer if ((rxbuf_rdpt < enc_r16(enc, CTL_REG_ERXSTL)) ||
456a61a8196SReinhard Meyer (rxbuf_rdpt > enc_r16(enc, CTL_REG_ERXNDL))) {
457a61a8196SReinhard Meyer enc_w16(enc, CTL_REG_ERXRDPTL,
458a61a8196SReinhard Meyer enc_r16(enc, CTL_REG_ERXNDL));
459a61a8196SReinhard Meyer } else {
460a61a8196SReinhard Meyer enc_w16(enc, CTL_REG_ERXRDPTL, rxbuf_rdpt);
461a61a8196SReinhard Meyer }
462a61a8196SReinhard Meyer /* read pktcnt */
463a61a8196SReinhard Meyer pkt_cnt = enc_r8(enc, CTL_REG_EPKTCNT);
464a61a8196SReinhard Meyer if (copy_len == 0) {
465da540665SAnatolij Gustschin (void)enc_r8(enc, CTL_REG_EIR);
466a61a8196SReinhard Meyer enc_reset_rx(enc);
467a61a8196SReinhard Meyer printf("%s: receive copy_len=0\n", enc->dev->name);
468a61a8196SReinhard Meyer continue;
469a61a8196SReinhard Meyer }
470a61a8196SReinhard Meyer /*
4711fd92db8SJoe Hershberger * Because net_process_received_packet() might call enc_send(),
4721fd92db8SJoe Hershberger * we need to release the SPI bus, call
4731fd92db8SJoe Hershberger * net_process_received_packet(), reclaim the bus.
474a61a8196SReinhard Meyer */
475a61a8196SReinhard Meyer enc_release_bus(enc);
4761fd92db8SJoe Hershberger net_process_received_packet(packet, pkt_len);
477a61a8196SReinhard Meyer if (enc_claim_bus(enc))
478a61a8196SReinhard Meyer return;
479da540665SAnatolij Gustschin (void)enc_r8(enc, CTL_REG_EIR);
480a61a8196SReinhard Meyer } while (pkt_cnt);
481a61a8196SReinhard Meyer /* Use EPKTCNT not EIR.PKTIF flag, see errata pt. 6 */
482a61a8196SReinhard Meyer }
483a61a8196SReinhard Meyer
484a61a8196SReinhard Meyer /*
485a61a8196SReinhard Meyer * Poll for completely received packets.
486a61a8196SReinhard Meyer */
enc_poll(enc_dev_t * enc)487a61a8196SReinhard Meyer static void enc_poll(enc_dev_t *enc)
488a61a8196SReinhard Meyer {
489a61a8196SReinhard Meyer u8 eir_reg;
490a61a8196SReinhard Meyer u8 pkt_cnt;
491a61a8196SReinhard Meyer
492da540665SAnatolij Gustschin (void)enc_r8(enc, CTL_REG_ESTAT);
493a61a8196SReinhard Meyer eir_reg = enc_r8(enc, CTL_REG_EIR);
494a61a8196SReinhard Meyer if (eir_reg & ENC_EIR_TXIF) {
495a61a8196SReinhard Meyer /* clear TXIF bit in EIR */
496a61a8196SReinhard Meyer enc_bclr(enc, CTL_REG_EIR, ENC_EIR_TXIF);
497a61a8196SReinhard Meyer }
498a61a8196SReinhard Meyer /* We have to use pktcnt and not pktif bit, see errata pt. 6 */
499a61a8196SReinhard Meyer pkt_cnt = enc_r8(enc, CTL_REG_EPKTCNT);
500a61a8196SReinhard Meyer if (pkt_cnt > 0) {
501a61a8196SReinhard Meyer if ((eir_reg & ENC_EIR_PKTIF) == 0) {
502a61a8196SReinhard Meyer debug("enc_poll: pkt cnt > 0, but pktif not set\n");
503a61a8196SReinhard Meyer }
504a61a8196SReinhard Meyer enc_receive(enc);
505a61a8196SReinhard Meyer /*
506a61a8196SReinhard Meyer * clear PKTIF bit in EIR, this should not need to be done
507a61a8196SReinhard Meyer * but it seems like we get problems if we do not
508a61a8196SReinhard Meyer */
509a61a8196SReinhard Meyer enc_bclr(enc, CTL_REG_EIR, ENC_EIR_PKTIF);
510a61a8196SReinhard Meyer }
511a61a8196SReinhard Meyer if (eir_reg & ENC_EIR_RXERIF) {
512a61a8196SReinhard Meyer printf("%s: rx error\n", enc->dev->name);
513a61a8196SReinhard Meyer enc_bclr(enc, CTL_REG_EIR, ENC_EIR_RXERIF);
514a61a8196SReinhard Meyer }
515a61a8196SReinhard Meyer if (eir_reg & ENC_EIR_TXERIF) {
516a61a8196SReinhard Meyer printf("%s: tx error\n", enc->dev->name);
517a61a8196SReinhard Meyer enc_bclr(enc, CTL_REG_EIR, ENC_EIR_TXERIF);
518a61a8196SReinhard Meyer }
519a61a8196SReinhard Meyer }
520a61a8196SReinhard Meyer
521a61a8196SReinhard Meyer /*
522a61a8196SReinhard Meyer * Completely Reset the ENC
523a61a8196SReinhard Meyer */
enc_reset(enc_dev_t * enc)524a61a8196SReinhard Meyer static void enc_reset(enc_dev_t *enc)
525a61a8196SReinhard Meyer {
526a61a8196SReinhard Meyer u8 dout[1];
527a61a8196SReinhard Meyer
528a61a8196SReinhard Meyer dout[0] = CMD_SRC;
529a61a8196SReinhard Meyer spi_xfer(enc->slave, 8, dout, NULL,
530a61a8196SReinhard Meyer SPI_XFER_BEGIN | SPI_XFER_END);
531a61a8196SReinhard Meyer /* sleep 1 ms. See errata pt. 2 */
532a61a8196SReinhard Meyer udelay(1000);
533a61a8196SReinhard Meyer }
534a61a8196SReinhard Meyer
535a61a8196SReinhard Meyer /*
536a61a8196SReinhard Meyer * Initialisation data for most of the ENC registers
537a61a8196SReinhard Meyer */
538a61a8196SReinhard Meyer static const u16 enc_initdata[] = {
539a61a8196SReinhard Meyer /*
540a61a8196SReinhard Meyer * Setup the buffer space. The reset values are valid for the
541a61a8196SReinhard Meyer * other pointers.
542a61a8196SReinhard Meyer *
543a61a8196SReinhard Meyer * We shall not write to ERXST, see errata pt. 5. Instead we
544a61a8196SReinhard Meyer * have to make sure that ENC_RX_BUS_START is 0.
545a61a8196SReinhard Meyer */
546a61a8196SReinhard Meyer CTL_REG_ERXSTL, ENC_RX_BUF_START,
547a61a8196SReinhard Meyer CTL_REG_ERXSTH, ENC_RX_BUF_START >> 8,
548a61a8196SReinhard Meyer CTL_REG_ERXNDL, ENC_RX_BUF_END,
549a61a8196SReinhard Meyer CTL_REG_ERXNDH, ENC_RX_BUF_END >> 8,
550a61a8196SReinhard Meyer CTL_REG_ERDPTL, ENC_RX_BUF_START,
551a61a8196SReinhard Meyer CTL_REG_ERDPTH, ENC_RX_BUF_START >> 8,
552a61a8196SReinhard Meyer /*
553a61a8196SReinhard Meyer * Set the filter to receive only good-CRC, unicast and broadcast
554a61a8196SReinhard Meyer * frames.
555a61a8196SReinhard Meyer * Note: some DHCP servers return their answers as broadcasts!
556a61a8196SReinhard Meyer * So its unwise to remove broadcast from this. This driver
557a61a8196SReinhard Meyer * might incur receiver overruns with packet loss on a broadcast
558a61a8196SReinhard Meyer * flooded network.
559a61a8196SReinhard Meyer */
560a61a8196SReinhard Meyer CTL_REG_ERXFCON, ENC_RFR_BCEN | ENC_RFR_UCEN | ENC_RFR_CRCEN,
561a61a8196SReinhard Meyer
562a61a8196SReinhard Meyer /* enable MAC to receive frames */
563a61a8196SReinhard Meyer CTL_REG_MACON1,
564a61a8196SReinhard Meyer ENC_MACON1_MARXEN | ENC_MACON1_TXPAUS | ENC_MACON1_RXPAUS,
565a61a8196SReinhard Meyer
566a61a8196SReinhard Meyer /* configure pad, tx-crc and duplex */
567a61a8196SReinhard Meyer CTL_REG_MACON3,
568a61a8196SReinhard Meyer ENC_MACON3_PADCFG0 | ENC_MACON3_TXCRCEN |
569a61a8196SReinhard Meyer ENC_MACON3_FRMLNEN,
570a61a8196SReinhard Meyer
571a61a8196SReinhard Meyer /* Allow infinite deferals if the medium is continously busy */
572a61a8196SReinhard Meyer CTL_REG_MACON4, ENC_MACON4_DEFER,
573a61a8196SReinhard Meyer
574a61a8196SReinhard Meyer /* Late collisions occur beyond 63 bytes */
575a61a8196SReinhard Meyer CTL_REG_MACLCON2, 63,
576a61a8196SReinhard Meyer
577a61a8196SReinhard Meyer /*
578a61a8196SReinhard Meyer * Set (low byte) Non-Back-to_Back Inter-Packet Gap.
579a61a8196SReinhard Meyer * Recommended 0x12
580a61a8196SReinhard Meyer */
581a61a8196SReinhard Meyer CTL_REG_MAIPGL, 0x12,
582a61a8196SReinhard Meyer
583a61a8196SReinhard Meyer /*
584a61a8196SReinhard Meyer * Set (high byte) Non-Back-to_Back Inter-Packet Gap.
585a61a8196SReinhard Meyer * Recommended 0x0c for half-duplex. Nothing for full-duplex
586a61a8196SReinhard Meyer */
587a61a8196SReinhard Meyer CTL_REG_MAIPGH, 0x0C,
588a61a8196SReinhard Meyer
589a61a8196SReinhard Meyer /* set maximum frame length */
590a61a8196SReinhard Meyer CTL_REG_MAMXFLL, ENC_MAX_FRM_LEN,
591a61a8196SReinhard Meyer CTL_REG_MAMXFLH, ENC_MAX_FRM_LEN >> 8,
592a61a8196SReinhard Meyer
593a61a8196SReinhard Meyer /*
594a61a8196SReinhard Meyer * Set MAC back-to-back inter-packet gap.
595a61a8196SReinhard Meyer * Recommended 0x12 for half duplex
596a61a8196SReinhard Meyer * and 0x15 for full duplex.
597a61a8196SReinhard Meyer */
598a61a8196SReinhard Meyer CTL_REG_MABBIPG, 0x12,
599a61a8196SReinhard Meyer
600a61a8196SReinhard Meyer /* end of table */
601a61a8196SReinhard Meyer 0xffff
602a61a8196SReinhard Meyer };
603a61a8196SReinhard Meyer
604a61a8196SReinhard Meyer /*
605a61a8196SReinhard Meyer * Wait for the XTAL oscillator to become ready
606a61a8196SReinhard Meyer */
enc_clock_wait(enc_dev_t * enc)607a61a8196SReinhard Meyer static int enc_clock_wait(enc_dev_t *enc)
608a61a8196SReinhard Meyer {
609a61a8196SReinhard Meyer uint64_t etime;
610a61a8196SReinhard Meyer
611a61a8196SReinhard Meyer /* one second timeout */
612a61a8196SReinhard Meyer etime = get_ticks() + get_tbclk();
613a61a8196SReinhard Meyer
614a61a8196SReinhard Meyer /*
615a61a8196SReinhard Meyer * Wait for CLKRDY to become set (i.e., check that we can
616a61a8196SReinhard Meyer * communicate with the ENC)
617a61a8196SReinhard Meyer */
618a61a8196SReinhard Meyer do
619a61a8196SReinhard Meyer {
620a61a8196SReinhard Meyer if (enc_r8(enc, CTL_REG_ESTAT) & ENC_ESTAT_CLKRDY)
621a61a8196SReinhard Meyer return 0;
622a61a8196SReinhard Meyer } while (get_ticks() <= etime);
623a61a8196SReinhard Meyer
624a61a8196SReinhard Meyer printf("%s: timeout waiting for CLKRDY\n", enc->dev->name);
625a61a8196SReinhard Meyer return -1;
626a61a8196SReinhard Meyer }
627a61a8196SReinhard Meyer
628a61a8196SReinhard Meyer /*
629a61a8196SReinhard Meyer * Write the MAC address into the ENC
630a61a8196SReinhard Meyer */
enc_write_macaddr(enc_dev_t * enc)631a61a8196SReinhard Meyer static int enc_write_macaddr(enc_dev_t *enc)
632a61a8196SReinhard Meyer {
633a61a8196SReinhard Meyer unsigned char *p = enc->dev->enetaddr;
634a61a8196SReinhard Meyer
635a61a8196SReinhard Meyer enc_w8_retry(enc, CTL_REG_MAADR5, *p++, 5);
636a61a8196SReinhard Meyer enc_w8_retry(enc, CTL_REG_MAADR4, *p++, 5);
637a61a8196SReinhard Meyer enc_w8_retry(enc, CTL_REG_MAADR3, *p++, 5);
638a61a8196SReinhard Meyer enc_w8_retry(enc, CTL_REG_MAADR2, *p++, 5);
639a61a8196SReinhard Meyer enc_w8_retry(enc, CTL_REG_MAADR1, *p++, 5);
640a61a8196SReinhard Meyer enc_w8_retry(enc, CTL_REG_MAADR0, *p, 5);
641a61a8196SReinhard Meyer return 0;
642a61a8196SReinhard Meyer }
643a61a8196SReinhard Meyer
644a61a8196SReinhard Meyer /*
645a61a8196SReinhard Meyer * Setup most of the ENC registers
646a61a8196SReinhard Meyer */
enc_setup(enc_dev_t * enc)647a61a8196SReinhard Meyer static int enc_setup(enc_dev_t *enc)
648a61a8196SReinhard Meyer {
649a61a8196SReinhard Meyer u16 phid1 = 0;
650a61a8196SReinhard Meyer u16 phid2 = 0;
651a61a8196SReinhard Meyer const u16 *tp;
652a61a8196SReinhard Meyer
653a61a8196SReinhard Meyer /* reset enc struct values */
654a61a8196SReinhard Meyer enc->next_pointer = ENC_RX_BUF_START;
655a61a8196SReinhard Meyer enc->rx_reset_counter = RX_RESET_COUNTER;
656a61a8196SReinhard Meyer enc->bank = 0xff; /* invalidate current bank in enc28j60 */
657a61a8196SReinhard Meyer
658a61a8196SReinhard Meyer /* verify PHY identification */
65909c04c20SAndy Fleming phid1 = enc_phy_read(enc, PHY_REG_PHID1);
66009c04c20SAndy Fleming phid2 = enc_phy_read(enc, PHY_REG_PHID2) & ENC_PHID2_MASK;
661a61a8196SReinhard Meyer if (phid1 != ENC_PHID1_VALUE || phid2 != ENC_PHID2_VALUE) {
662a61a8196SReinhard Meyer printf("%s: failed to identify PHY. Found %04x:%04x\n",
663a61a8196SReinhard Meyer enc->dev->name, phid1, phid2);
664a61a8196SReinhard Meyer return -1;
665a61a8196SReinhard Meyer }
666a61a8196SReinhard Meyer
667a61a8196SReinhard Meyer /* now program registers */
668a61a8196SReinhard Meyer for (tp = enc_initdata; *tp != 0xffff; tp += 2)
669a61a8196SReinhard Meyer enc_w8_retry(enc, tp[0], tp[1], 10);
670a61a8196SReinhard Meyer
671a61a8196SReinhard Meyer /*
672a61a8196SReinhard Meyer * Prevent automatic loopback of data beeing transmitted by setting
673a61a8196SReinhard Meyer * ENC_PHCON2_HDLDIS
674a61a8196SReinhard Meyer */
67509c04c20SAndy Fleming enc_phy_write(enc, PHY_REG_PHCON2, (1<<8));
676a61a8196SReinhard Meyer
677a61a8196SReinhard Meyer /*
678a61a8196SReinhard Meyer * LEDs configuration
679a61a8196SReinhard Meyer * LEDA: LACFG = 0100 -> display link status
680a61a8196SReinhard Meyer * LEDB: LBCFG = 0111 -> display TX & RX activity
681a61a8196SReinhard Meyer * STRCH = 1 -> LED pulses
682a61a8196SReinhard Meyer */
68309c04c20SAndy Fleming enc_phy_write(enc, PHY_REG_PHLCON, 0x0472);
684a61a8196SReinhard Meyer
685a61a8196SReinhard Meyer /* Reset PDPXMD-bit => half duplex */
68609c04c20SAndy Fleming enc_phy_write(enc, PHY_REG_PHCON1, 0);
687a61a8196SReinhard Meyer
688a61a8196SReinhard Meyer return 0;
689a61a8196SReinhard Meyer }
690a61a8196SReinhard Meyer
691a61a8196SReinhard Meyer /*
692a61a8196SReinhard Meyer * Check if ENC has been initialized.
693a61a8196SReinhard Meyer * If not, try to initialize it.
694a61a8196SReinhard Meyer * Remember initialized state in struct.
695a61a8196SReinhard Meyer */
enc_initcheck(enc_dev_t * enc,const enum enc_initstate requiredstate)696a61a8196SReinhard Meyer static int enc_initcheck(enc_dev_t *enc, const enum enc_initstate requiredstate)
697a61a8196SReinhard Meyer {
698a61a8196SReinhard Meyer if (enc->initstate >= requiredstate)
699a61a8196SReinhard Meyer return 0;
700a61a8196SReinhard Meyer
701a61a8196SReinhard Meyer if (enc->initstate < setupdone) {
702a61a8196SReinhard Meyer /* Initialize the ENC only */
703a61a8196SReinhard Meyer enc_reset(enc);
704a61a8196SReinhard Meyer /* if any of functions fails, skip the rest and return an error */
705a61a8196SReinhard Meyer if (enc_clock_wait(enc) || enc_setup(enc) || enc_write_macaddr(enc)) {
706a61a8196SReinhard Meyer return -1;
707a61a8196SReinhard Meyer }
708a61a8196SReinhard Meyer enc->initstate = setupdone;
709a61a8196SReinhard Meyer }
710a61a8196SReinhard Meyer /* if that's all we need, return here */
711a61a8196SReinhard Meyer if (enc->initstate >= requiredstate)
712a61a8196SReinhard Meyer return 0;
713a61a8196SReinhard Meyer
714a61a8196SReinhard Meyer /* now wait for link ready condition */
715a61a8196SReinhard Meyer if (enc_phy_link_wait(enc)) {
716a61a8196SReinhard Meyer return -1;
717a61a8196SReinhard Meyer }
718a61a8196SReinhard Meyer enc->initstate = linkready;
719a61a8196SReinhard Meyer return 0;
720a61a8196SReinhard Meyer }
721a61a8196SReinhard Meyer
722a61a8196SReinhard Meyer #if defined(CONFIG_CMD_MII)
723a61a8196SReinhard Meyer /*
724a61a8196SReinhard Meyer * Read a PHY register.
725a61a8196SReinhard Meyer *
726a61a8196SReinhard Meyer * This function is registered with miiphy_register().
727a61a8196SReinhard Meyer */
enc_miiphy_read(struct mii_dev * bus,int phy_adr,int devad,int reg)728*5a49f174SJoe Hershberger int enc_miiphy_read(struct mii_dev *bus, int phy_adr, int devad, int reg)
729a61a8196SReinhard Meyer {
730*5a49f174SJoe Hershberger u16 value = 0;
731*5a49f174SJoe Hershberger struct eth_device *dev = eth_get_dev_by_name(bus->name);
732a61a8196SReinhard Meyer enc_dev_t *enc;
733a61a8196SReinhard Meyer
734a61a8196SReinhard Meyer if (!dev || phy_adr != 0)
735a61a8196SReinhard Meyer return -1;
736a61a8196SReinhard Meyer
737a61a8196SReinhard Meyer enc = dev->priv;
738a61a8196SReinhard Meyer if (enc_claim_bus(enc))
739a61a8196SReinhard Meyer return -1;
740a61a8196SReinhard Meyer if (enc_initcheck(enc, setupdone)) {
741a61a8196SReinhard Meyer enc_release_bus(enc);
742a61a8196SReinhard Meyer return -1;
743a61a8196SReinhard Meyer }
744*5a49f174SJoe Hershberger value = enc_phy_read(enc, reg);
745a61a8196SReinhard Meyer enc_release_bus(enc);
746*5a49f174SJoe Hershberger return value;
747a61a8196SReinhard Meyer }
748a61a8196SReinhard Meyer
749a61a8196SReinhard Meyer /*
750a61a8196SReinhard Meyer * Write a PHY register.
751a61a8196SReinhard Meyer *
752a61a8196SReinhard Meyer * This function is registered with miiphy_register().
753a61a8196SReinhard Meyer */
enc_miiphy_write(struct mii_dev * bus,int phy_adr,int devad,int reg,u16 value)754*5a49f174SJoe Hershberger int enc_miiphy_write(struct mii_dev *bus, int phy_adr, int devad, int reg,
755*5a49f174SJoe Hershberger u16 value)
756a61a8196SReinhard Meyer {
757*5a49f174SJoe Hershberger struct eth_device *dev = eth_get_dev_by_name(bus->name);
758a61a8196SReinhard Meyer enc_dev_t *enc;
759a61a8196SReinhard Meyer
760a61a8196SReinhard Meyer if (!dev || phy_adr != 0)
761a61a8196SReinhard Meyer return -1;
762a61a8196SReinhard Meyer
763a61a8196SReinhard Meyer enc = dev->priv;
764a61a8196SReinhard Meyer if (enc_claim_bus(enc))
765a61a8196SReinhard Meyer return -1;
766a61a8196SReinhard Meyer if (enc_initcheck(enc, setupdone)) {
767a61a8196SReinhard Meyer enc_release_bus(enc);
768a61a8196SReinhard Meyer return -1;
769a61a8196SReinhard Meyer }
77009c04c20SAndy Fleming enc_phy_write(enc, reg, value);
771a61a8196SReinhard Meyer enc_release_bus(enc);
772a61a8196SReinhard Meyer return 0;
773a61a8196SReinhard Meyer }
774a61a8196SReinhard Meyer #endif
775a61a8196SReinhard Meyer
776a61a8196SReinhard Meyer /*
777a61a8196SReinhard Meyer * Write hardware (MAC) address.
778a61a8196SReinhard Meyer *
779a61a8196SReinhard Meyer * This function entered into eth_device structure.
780a61a8196SReinhard Meyer */
enc_write_hwaddr(struct eth_device * dev)781a61a8196SReinhard Meyer static int enc_write_hwaddr(struct eth_device *dev)
782a61a8196SReinhard Meyer {
783a61a8196SReinhard Meyer enc_dev_t *enc = dev->priv;
784a61a8196SReinhard Meyer
785a61a8196SReinhard Meyer if (enc_claim_bus(enc))
786a61a8196SReinhard Meyer return -1;
787a61a8196SReinhard Meyer if (enc_initcheck(enc, setupdone)) {
788a61a8196SReinhard Meyer enc_release_bus(enc);
789a61a8196SReinhard Meyer return -1;
790a61a8196SReinhard Meyer }
791a61a8196SReinhard Meyer enc_release_bus(enc);
792a61a8196SReinhard Meyer return 0;
793a61a8196SReinhard Meyer }
794a61a8196SReinhard Meyer
795a61a8196SReinhard Meyer /*
796a61a8196SReinhard Meyer * Initialize ENC28J60 for use.
797a61a8196SReinhard Meyer *
798a61a8196SReinhard Meyer * This function entered into eth_device structure.
799a61a8196SReinhard Meyer */
enc_init(struct eth_device * dev,bd_t * bis)800a61a8196SReinhard Meyer static int enc_init(struct eth_device *dev, bd_t *bis)
801a61a8196SReinhard Meyer {
802a61a8196SReinhard Meyer enc_dev_t *enc = dev->priv;
803a61a8196SReinhard Meyer
804a61a8196SReinhard Meyer if (enc_claim_bus(enc))
805a61a8196SReinhard Meyer return -1;
806a61a8196SReinhard Meyer if (enc_initcheck(enc, linkready)) {
807a61a8196SReinhard Meyer enc_release_bus(enc);
808a61a8196SReinhard Meyer return -1;
809a61a8196SReinhard Meyer }
810a61a8196SReinhard Meyer /* enable receive */
811a61a8196SReinhard Meyer enc_bset(enc, CTL_REG_ECON1, ENC_ECON1_RXEN);
812a61a8196SReinhard Meyer enc_release_bus(enc);
813a61a8196SReinhard Meyer return 0;
814a61a8196SReinhard Meyer }
815a61a8196SReinhard Meyer
816a61a8196SReinhard Meyer /*
817a61a8196SReinhard Meyer * Check for received packets.
818a61a8196SReinhard Meyer *
819a61a8196SReinhard Meyer * This function entered into eth_device structure.
820a61a8196SReinhard Meyer */
enc_recv(struct eth_device * dev)821a61a8196SReinhard Meyer static int enc_recv(struct eth_device *dev)
822a61a8196SReinhard Meyer {
823a61a8196SReinhard Meyer enc_dev_t *enc = dev->priv;
824a61a8196SReinhard Meyer
825a61a8196SReinhard Meyer if (enc_claim_bus(enc))
826a61a8196SReinhard Meyer return -1;
827a61a8196SReinhard Meyer if (enc_initcheck(enc, linkready)) {
828a61a8196SReinhard Meyer enc_release_bus(enc);
829a61a8196SReinhard Meyer return -1;
830a61a8196SReinhard Meyer }
831a61a8196SReinhard Meyer /* Check for dead receiver */
832a61a8196SReinhard Meyer if (enc->rx_reset_counter > 0)
833a61a8196SReinhard Meyer enc->rx_reset_counter--;
834a61a8196SReinhard Meyer else
835a61a8196SReinhard Meyer enc_reset_rx_call(enc);
836a61a8196SReinhard Meyer enc_poll(enc);
837a61a8196SReinhard Meyer enc_release_bus(enc);
838a61a8196SReinhard Meyer return 0;
839a61a8196SReinhard Meyer }
840a61a8196SReinhard Meyer
841a61a8196SReinhard Meyer /*
842a61a8196SReinhard Meyer * Send a packet.
843a61a8196SReinhard Meyer *
844a61a8196SReinhard Meyer * This function entered into eth_device structure.
845a61a8196SReinhard Meyer *
846a61a8196SReinhard Meyer * Should we wait here until we have a Link? Or shall we leave that to
847a61a8196SReinhard Meyer * protocol retries?
848a61a8196SReinhard Meyer */
enc_send(struct eth_device * dev,void * packet,int length)849a61a8196SReinhard Meyer static int enc_send(
850a61a8196SReinhard Meyer struct eth_device *dev,
851b58cab34SJoe Hershberger void *packet,
852a61a8196SReinhard Meyer int length)
853a61a8196SReinhard Meyer {
854a61a8196SReinhard Meyer enc_dev_t *enc = dev->priv;
855a61a8196SReinhard Meyer
856a61a8196SReinhard Meyer if (enc_claim_bus(enc))
857a61a8196SReinhard Meyer return -1;
858a61a8196SReinhard Meyer if (enc_initcheck(enc, linkready)) {
859a61a8196SReinhard Meyer enc_release_bus(enc);
860a61a8196SReinhard Meyer return -1;
861a61a8196SReinhard Meyer }
862a61a8196SReinhard Meyer /* setup transmit pointers */
863a61a8196SReinhard Meyer enc_w16(enc, CTL_REG_EWRPTL, ENC_TX_BUF_START);
864a61a8196SReinhard Meyer enc_w16(enc, CTL_REG_ETXNDL, length + ENC_TX_BUF_START);
865a61a8196SReinhard Meyer enc_w16(enc, CTL_REG_ETXSTL, ENC_TX_BUF_START);
866a61a8196SReinhard Meyer /* write packet to ENC */
867a61a8196SReinhard Meyer enc_wbuf(enc, length, (u8 *) packet, 0x00);
868a61a8196SReinhard Meyer /*
869a61a8196SReinhard Meyer * Check that the internal transmit logic has not been altered
870a61a8196SReinhard Meyer * by excessive collisions. Reset transmitter if so.
871a61a8196SReinhard Meyer * See Errata B4 12 and 14.
872a61a8196SReinhard Meyer */
873a61a8196SReinhard Meyer if (enc_r8(enc, CTL_REG_EIR) & ENC_EIR_TXERIF) {
874a61a8196SReinhard Meyer enc_bset(enc, CTL_REG_ECON1, ENC_ECON1_TXRST);
875a61a8196SReinhard Meyer enc_bclr(enc, CTL_REG_ECON1, ENC_ECON1_TXRST);
876a61a8196SReinhard Meyer }
877a61a8196SReinhard Meyer enc_bclr(enc, CTL_REG_EIR, (ENC_EIR_TXERIF | ENC_EIR_TXIF));
878a61a8196SReinhard Meyer /* start transmitting */
879a61a8196SReinhard Meyer enc_bset(enc, CTL_REG_ECON1, ENC_ECON1_TXRTS);
880a61a8196SReinhard Meyer enc_release_bus(enc);
881a61a8196SReinhard Meyer return 0;
882a61a8196SReinhard Meyer }
883a61a8196SReinhard Meyer
884a61a8196SReinhard Meyer /*
885a61a8196SReinhard Meyer * Finish use of ENC.
886a61a8196SReinhard Meyer *
887a61a8196SReinhard Meyer * This function entered into eth_device structure.
888a61a8196SReinhard Meyer */
enc_halt(struct eth_device * dev)889a61a8196SReinhard Meyer static void enc_halt(struct eth_device *dev)
890a61a8196SReinhard Meyer {
891a61a8196SReinhard Meyer enc_dev_t *enc = dev->priv;
892a61a8196SReinhard Meyer
893a61a8196SReinhard Meyer if (enc_claim_bus(enc))
894a61a8196SReinhard Meyer return;
895a61a8196SReinhard Meyer /* Just disable receiver */
896a61a8196SReinhard Meyer enc_bclr(enc, CTL_REG_ECON1, ENC_ECON1_RXEN);
897a61a8196SReinhard Meyer enc_release_bus(enc);
898a61a8196SReinhard Meyer }
899a61a8196SReinhard Meyer
900a61a8196SReinhard Meyer /*
901a61a8196SReinhard Meyer * This is the only exported function.
902a61a8196SReinhard Meyer *
903a61a8196SReinhard Meyer * It may be called several times with different bus:cs combinations.
904a61a8196SReinhard Meyer */
enc28j60_initialize(unsigned int bus,unsigned int cs,unsigned int max_hz,unsigned int mode)905a61a8196SReinhard Meyer int enc28j60_initialize(unsigned int bus, unsigned int cs,
906a61a8196SReinhard Meyer unsigned int max_hz, unsigned int mode)
907a61a8196SReinhard Meyer {
908a61a8196SReinhard Meyer struct eth_device *dev;
909a61a8196SReinhard Meyer enc_dev_t *enc;
910a61a8196SReinhard Meyer
911a61a8196SReinhard Meyer /* try to allocate, check and clear eth_device object */
912a61a8196SReinhard Meyer dev = malloc(sizeof(*dev));
913a61a8196SReinhard Meyer if (!dev) {
914a61a8196SReinhard Meyer return -1;
915a61a8196SReinhard Meyer }
916a61a8196SReinhard Meyer memset(dev, 0, sizeof(*dev));
917a61a8196SReinhard Meyer
918a61a8196SReinhard Meyer /* try to allocate, check and clear enc_dev_t object */
919a61a8196SReinhard Meyer enc = malloc(sizeof(*enc));
920a61a8196SReinhard Meyer if (!enc) {
921a61a8196SReinhard Meyer free(dev);
922a61a8196SReinhard Meyer return -1;
923a61a8196SReinhard Meyer }
924a61a8196SReinhard Meyer memset(enc, 0, sizeof(*enc));
925a61a8196SReinhard Meyer
926a61a8196SReinhard Meyer /* try to setup the SPI slave */
927a61a8196SReinhard Meyer enc->slave = spi_setup_slave(bus, cs, max_hz, mode);
928a61a8196SReinhard Meyer if (!enc->slave) {
929a61a8196SReinhard Meyer printf("enc28j60: invalid SPI device %i:%i\n", bus, cs);
930a61a8196SReinhard Meyer free(enc);
931a61a8196SReinhard Meyer free(dev);
932a61a8196SReinhard Meyer return -1;
933a61a8196SReinhard Meyer }
934a61a8196SReinhard Meyer
935a61a8196SReinhard Meyer enc->dev = dev;
936a61a8196SReinhard Meyer /* now fill the eth_device object */
937a61a8196SReinhard Meyer dev->priv = enc;
938a61a8196SReinhard Meyer dev->init = enc_init;
939a61a8196SReinhard Meyer dev->halt = enc_halt;
940a61a8196SReinhard Meyer dev->send = enc_send;
941a61a8196SReinhard Meyer dev->recv = enc_recv;
942a61a8196SReinhard Meyer dev->write_hwaddr = enc_write_hwaddr;
943a61a8196SReinhard Meyer sprintf(dev->name, "enc%i.%i", bus, cs);
944a61a8196SReinhard Meyer eth_register(dev);
945a61a8196SReinhard Meyer #if defined(CONFIG_CMD_MII)
946*5a49f174SJoe Hershberger int retval;
947*5a49f174SJoe Hershberger struct mii_dev *mdiodev = mdio_alloc();
948*5a49f174SJoe Hershberger if (!mdiodev)
949*5a49f174SJoe Hershberger return -ENOMEM;
950*5a49f174SJoe Hershberger strncpy(mdiodev->name, dev->name, MDIO_NAME_LEN);
951*5a49f174SJoe Hershberger mdiodev->read = enc_miiphy_read;
952*5a49f174SJoe Hershberger mdiodev->write = enc_miiphy_write;
953*5a49f174SJoe Hershberger
954*5a49f174SJoe Hershberger retval = mdio_register(mdiodev);
955*5a49f174SJoe Hershberger if (retval < 0)
956*5a49f174SJoe Hershberger return retval;
957a61a8196SReinhard Meyer #endif
958a61a8196SReinhard Meyer return 0;
959a61a8196SReinhard Meyer }
960