xref: /rk3399_rockchip-uboot/drivers/net/enc28j60.c (revision 01abae4d04868dede60947867699bf096a1831ff)
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