xref: /rk3399_rockchip-uboot/drivers/net/ne2000_base.c (revision 35affd7a2ff9a77b9946bf93b616228fcf218d60)
1702c85b0SNobuhiro Iwamatsu /*
2702c85b0SNobuhiro Iwamatsu Ported to U-Boot by Christian Pellegrin <chri@ascensit.com>
3702c85b0SNobuhiro Iwamatsu 
4702c85b0SNobuhiro Iwamatsu Based on sources from the Linux kernel (pcnet_cs.c, 8390.h) and
5702c85b0SNobuhiro Iwamatsu eCOS(if_dp83902a.c, if_dp83902a.h). Both of these 2 wonderful world
6702c85b0SNobuhiro Iwamatsu are GPL, so this is, of course, GPL.
7702c85b0SNobuhiro Iwamatsu 
8702c85b0SNobuhiro Iwamatsu ==========================================================================
9702c85b0SNobuhiro Iwamatsu 
10702c85b0SNobuhiro Iwamatsu dev/if_dp83902a.c
11702c85b0SNobuhiro Iwamatsu 
12702c85b0SNobuhiro Iwamatsu Ethernet device driver for NS DP83902a ethernet controller
13702c85b0SNobuhiro Iwamatsu 
14702c85b0SNobuhiro Iwamatsu ==========================================================================
15702c85b0SNobuhiro Iwamatsu ####ECOSGPLCOPYRIGHTBEGIN####
16702c85b0SNobuhiro Iwamatsu -------------------------------------------
17702c85b0SNobuhiro Iwamatsu This file is part of eCos, the Embedded Configurable Operating System.
18702c85b0SNobuhiro Iwamatsu Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
19702c85b0SNobuhiro Iwamatsu 
20702c85b0SNobuhiro Iwamatsu eCos is free software; you can redistribute it and/or modify it under
21702c85b0SNobuhiro Iwamatsu the terms of the GNU General Public License as published by the Free
22702c85b0SNobuhiro Iwamatsu Software Foundation; either version 2 or (at your option) any later version.
23702c85b0SNobuhiro Iwamatsu 
24702c85b0SNobuhiro Iwamatsu eCos is distributed in the hope that it will be useful, but WITHOUT ANY
25702c85b0SNobuhiro Iwamatsu WARRANTY; without even the implied warranty of MERCHANTABILITY or
26702c85b0SNobuhiro Iwamatsu FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
27702c85b0SNobuhiro Iwamatsu for more details.
28702c85b0SNobuhiro Iwamatsu 
29702c85b0SNobuhiro Iwamatsu You should have received a copy of the GNU General Public License along
30702c85b0SNobuhiro Iwamatsu with eCos; if not, write to the Free Software Foundation, Inc.,
31702c85b0SNobuhiro Iwamatsu 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
32702c85b0SNobuhiro Iwamatsu 
33702c85b0SNobuhiro Iwamatsu As a special exception, if other files instantiate templates or use macros
34702c85b0SNobuhiro Iwamatsu or inline functions from this file, or you compile this file and link it
35702c85b0SNobuhiro Iwamatsu with other works to produce a work based on this file, this file does not
36702c85b0SNobuhiro Iwamatsu by itself cause the resulting work to be covered by the GNU General Public
37702c85b0SNobuhiro Iwamatsu License. However the source code for this file must still be made available
38702c85b0SNobuhiro Iwamatsu in accordance with section (3) of the GNU General Public License.
39702c85b0SNobuhiro Iwamatsu 
40702c85b0SNobuhiro Iwamatsu This exception does not invalidate any other reasons why a work based on
41702c85b0SNobuhiro Iwamatsu this file might be covered by the GNU General Public License.
42702c85b0SNobuhiro Iwamatsu 
43702c85b0SNobuhiro Iwamatsu Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
44702c85b0SNobuhiro Iwamatsu at http://sources.redhat.com/ecos/ecos-license/
45702c85b0SNobuhiro Iwamatsu -------------------------------------------
46702c85b0SNobuhiro Iwamatsu ####ECOSGPLCOPYRIGHTEND####
47702c85b0SNobuhiro Iwamatsu ####BSDCOPYRIGHTBEGIN####
48702c85b0SNobuhiro Iwamatsu 
49702c85b0SNobuhiro Iwamatsu -------------------------------------------
50702c85b0SNobuhiro Iwamatsu 
51702c85b0SNobuhiro Iwamatsu Portions of this software may have been derived from OpenBSD or other sources,
52702c85b0SNobuhiro Iwamatsu and are covered by the appropriate copyright disclaimers included herein.
53702c85b0SNobuhiro Iwamatsu 
54702c85b0SNobuhiro Iwamatsu -------------------------------------------
55702c85b0SNobuhiro Iwamatsu 
56702c85b0SNobuhiro Iwamatsu ####BSDCOPYRIGHTEND####
57702c85b0SNobuhiro Iwamatsu ==========================================================================
58702c85b0SNobuhiro Iwamatsu #####DESCRIPTIONBEGIN####
59702c85b0SNobuhiro Iwamatsu 
60702c85b0SNobuhiro Iwamatsu Author(s):	gthomas
61702c85b0SNobuhiro Iwamatsu Contributors:	gthomas, jskov, rsandifo
62702c85b0SNobuhiro Iwamatsu Date:		2001-06-13
63702c85b0SNobuhiro Iwamatsu Purpose:
64702c85b0SNobuhiro Iwamatsu Description:
65702c85b0SNobuhiro Iwamatsu 
66702c85b0SNobuhiro Iwamatsu FIXME:		Will fail if pinged with large packets (1520 bytes)
67702c85b0SNobuhiro Iwamatsu Add promisc config
68702c85b0SNobuhiro Iwamatsu Add SNMP
69702c85b0SNobuhiro Iwamatsu 
70702c85b0SNobuhiro Iwamatsu ####DESCRIPTIONEND####
71702c85b0SNobuhiro Iwamatsu 
72702c85b0SNobuhiro Iwamatsu ==========================================================================
73702c85b0SNobuhiro Iwamatsu */
74702c85b0SNobuhiro Iwamatsu 
75702c85b0SNobuhiro Iwamatsu #include <common.h>
76702c85b0SNobuhiro Iwamatsu #include <command.h>
77702c85b0SNobuhiro Iwamatsu #include <net.h>
78702c85b0SNobuhiro Iwamatsu #include <malloc.h>
794eaf172eSWolfgang Denk #include <linux/compiler.h>
80702c85b0SNobuhiro Iwamatsu 
81702c85b0SNobuhiro Iwamatsu /* forward definition of function used for the uboot interface */
82702c85b0SNobuhiro Iwamatsu void uboot_push_packet_len(int len);
83702c85b0SNobuhiro Iwamatsu void uboot_push_tx_done(int key, int val);
84702c85b0SNobuhiro Iwamatsu 
85702c85b0SNobuhiro Iwamatsu /* NE2000 base header file */
86702c85b0SNobuhiro Iwamatsu #include "ne2000_base.h"
87702c85b0SNobuhiro Iwamatsu 
88702c85b0SNobuhiro Iwamatsu #if defined(CONFIG_DRIVER_AX88796L)
89702c85b0SNobuhiro Iwamatsu /* AX88796L support */
90702c85b0SNobuhiro Iwamatsu #include "ax88796.h"
91702c85b0SNobuhiro Iwamatsu #else
92702c85b0SNobuhiro Iwamatsu /* Basic NE2000 chip support */
93702c85b0SNobuhiro Iwamatsu #include "ne2000.h"
94702c85b0SNobuhiro Iwamatsu #endif
95702c85b0SNobuhiro Iwamatsu 
96702c85b0SNobuhiro Iwamatsu static dp83902a_priv_data_t nic; /* just one instance of the card supported */
97702c85b0SNobuhiro Iwamatsu 
98d0201692SBernhard Kaindl /**
99d0201692SBernhard Kaindl  * This function reads the MAC address from the serial EEPROM,
100d0201692SBernhard Kaindl  * used if PROM read fails. Does nothing for ax88796 chips (sh boards)
101d0201692SBernhard Kaindl  */
102702c85b0SNobuhiro Iwamatsu static bool
dp83902a_init(unsigned char * enetaddr)103d0201692SBernhard Kaindl dp83902a_init(unsigned char *enetaddr)
104702c85b0SNobuhiro Iwamatsu {
105702c85b0SNobuhiro Iwamatsu 	dp83902a_priv_data_t *dp = &nic;
106702c85b0SNobuhiro Iwamatsu 	u8* base;
107702c85b0SNobuhiro Iwamatsu #if defined(NE2000_BASIC_INIT)
108702c85b0SNobuhiro Iwamatsu 	int i;
109702c85b0SNobuhiro Iwamatsu #endif
110702c85b0SNobuhiro Iwamatsu 
111702c85b0SNobuhiro Iwamatsu 	DEBUG_FUNCTION();
112702c85b0SNobuhiro Iwamatsu 
113702c85b0SNobuhiro Iwamatsu 	base = dp->base;
114702c85b0SNobuhiro Iwamatsu 	if (!base)
115702c85b0SNobuhiro Iwamatsu 		return false;	/* No device found */
116702c85b0SNobuhiro Iwamatsu 
117702c85b0SNobuhiro Iwamatsu 	DEBUG_LINE();
118702c85b0SNobuhiro Iwamatsu 
119702c85b0SNobuhiro Iwamatsu #if defined(NE2000_BASIC_INIT)
120702c85b0SNobuhiro Iwamatsu 	/* AX88796L doesn't need */
121702c85b0SNobuhiro Iwamatsu 	/* Prepare ESA */
122702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_PAGE1);	/* Select page 1 */
123702c85b0SNobuhiro Iwamatsu 	/* Use the address from the serial EEPROM */
124702c85b0SNobuhiro Iwamatsu 	for (i = 0; i < 6; i++)
125702c85b0SNobuhiro Iwamatsu 		DP_IN(base, DP_P1_PAR0+i, dp->esa[i]);
126702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_PAGE0);	/* Select page 0 */
127702c85b0SNobuhiro Iwamatsu 
128702c85b0SNobuhiro Iwamatsu 	printf("NE2000 - %s ESA: %02x:%02x:%02x:%02x:%02x:%02x\n",
129702c85b0SNobuhiro Iwamatsu 		"eeprom",
130702c85b0SNobuhiro Iwamatsu 		dp->esa[0],
131702c85b0SNobuhiro Iwamatsu 		dp->esa[1],
132702c85b0SNobuhiro Iwamatsu 		dp->esa[2],
133702c85b0SNobuhiro Iwamatsu 		dp->esa[3],
134702c85b0SNobuhiro Iwamatsu 		dp->esa[4],
135702c85b0SNobuhiro Iwamatsu 		dp->esa[5] );
136702c85b0SNobuhiro Iwamatsu 
137d0201692SBernhard Kaindl 	memcpy(enetaddr, dp->esa, 6); /* Use MAC from serial EEPROM */
138702c85b0SNobuhiro Iwamatsu #endif	/* NE2000_BASIC_INIT */
139702c85b0SNobuhiro Iwamatsu 	return true;
140702c85b0SNobuhiro Iwamatsu }
141702c85b0SNobuhiro Iwamatsu 
142702c85b0SNobuhiro Iwamatsu static void
dp83902a_stop(void)143702c85b0SNobuhiro Iwamatsu dp83902a_stop(void)
144702c85b0SNobuhiro Iwamatsu {
145702c85b0SNobuhiro Iwamatsu 	dp83902a_priv_data_t *dp = &nic;
146702c85b0SNobuhiro Iwamatsu 	u8 *base = dp->base;
147702c85b0SNobuhiro Iwamatsu 
148702c85b0SNobuhiro Iwamatsu 	DEBUG_FUNCTION();
149702c85b0SNobuhiro Iwamatsu 
150702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_STOP);	/* Brutal */
151702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_ISR, 0xFF);		/* Clear any pending interrupts */
152702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_IMR, 0x00);		/* Disable all interrupts */
153702c85b0SNobuhiro Iwamatsu 
154702c85b0SNobuhiro Iwamatsu 	dp->running = false;
155702c85b0SNobuhiro Iwamatsu }
156702c85b0SNobuhiro Iwamatsu 
157702c85b0SNobuhiro Iwamatsu /*
158702c85b0SNobuhiro Iwamatsu  * This function is called to "start up" the interface. It may be called
159702c85b0SNobuhiro Iwamatsu  * multiple times, even when the hardware is already running. It will be
160702c85b0SNobuhiro Iwamatsu  * called whenever something "hardware oriented" changes and should leave
161702c85b0SNobuhiro Iwamatsu  * the hardware ready to send/receive packets.
162702c85b0SNobuhiro Iwamatsu  */
163702c85b0SNobuhiro Iwamatsu static void
dp83902a_start(u8 * enaddr)164702c85b0SNobuhiro Iwamatsu dp83902a_start(u8 * enaddr)
165702c85b0SNobuhiro Iwamatsu {
166702c85b0SNobuhiro Iwamatsu 	dp83902a_priv_data_t *dp = &nic;
167702c85b0SNobuhiro Iwamatsu 	u8 *base = dp->base;
168702c85b0SNobuhiro Iwamatsu 	int i;
169702c85b0SNobuhiro Iwamatsu 
170d0201692SBernhard Kaindl 	debug("The MAC is %pM\n", enaddr);
171d0201692SBernhard Kaindl 
172702c85b0SNobuhiro Iwamatsu 	DEBUG_FUNCTION();
173702c85b0SNobuhiro Iwamatsu 
174702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_STOP); /* Brutal */
175702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_DCR, DP_DCR_INIT);
176702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_RBCH, 0);		/* Remote byte count */
177702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_RBCL, 0);
178702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_RCR, DP_RCR_MON);	/* Accept no packets */
179702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_TCR, DP_TCR_LOCAL);	/* Transmitter [virtually] off */
180702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_TPSR, dp->tx_buf1);	/* Transmitter start page */
181702c85b0SNobuhiro Iwamatsu 	dp->tx1 = dp->tx2 = 0;
182702c85b0SNobuhiro Iwamatsu 	dp->tx_next = dp->tx_buf1;
183702c85b0SNobuhiro Iwamatsu 	dp->tx_started = false;
184702c85b0SNobuhiro Iwamatsu 	dp->running = true;
185702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_PSTART, dp->rx_buf_start); /* Receive ring start page */
186702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_BNDRY, dp->rx_buf_end - 1); /* Receive ring boundary */
187702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_PSTOP, dp->rx_buf_end);	/* Receive ring end page */
188702c85b0SNobuhiro Iwamatsu 	dp->rx_next = dp->rx_buf_start - 1;
189702c85b0SNobuhiro Iwamatsu 	dp->running = true;
190702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_ISR, 0xFF);		/* Clear any pending interrupts */
191702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_IMR, DP_IMR_All);	/* Enable all interrupts */
192702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_PAGE1 | DP_CR_STOP);	/* Select page 1 */
193702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_P1_CURP, dp->rx_buf_start);	/* Current page - next free page for Rx */
194702c85b0SNobuhiro Iwamatsu 	dp->running = true;
195702c85b0SNobuhiro Iwamatsu 	for (i = 0; i < ETHER_ADDR_LEN; i++) {
196702c85b0SNobuhiro Iwamatsu 		/* FIXME */
197702c85b0SNobuhiro Iwamatsu 		/*((vu_short*)( base + ((DP_P1_PAR0 + i) * 2) +
198702c85b0SNobuhiro Iwamatsu 		 * 0x1400)) = enaddr[i];*/
199702c85b0SNobuhiro Iwamatsu 		DP_OUT(base, DP_P1_PAR0+i, enaddr[i]);
200702c85b0SNobuhiro Iwamatsu 	}
201702c85b0SNobuhiro Iwamatsu 	/* Enable and start device */
202702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START);
203702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_TCR, DP_TCR_NORMAL); /* Normal transmit operations */
204702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_RCR, DP_RCR_AB); /* Accept broadcast, no errors, no multicast */
205702c85b0SNobuhiro Iwamatsu 	dp->running = true;
206702c85b0SNobuhiro Iwamatsu }
207702c85b0SNobuhiro Iwamatsu 
208702c85b0SNobuhiro Iwamatsu /*
209702c85b0SNobuhiro Iwamatsu  * This routine is called to start the transmitter. It is split out from the
210702c85b0SNobuhiro Iwamatsu  * data handling routine so it may be called either when data becomes first
211702c85b0SNobuhiro Iwamatsu  * available or when an Tx interrupt occurs
212702c85b0SNobuhiro Iwamatsu  */
213702c85b0SNobuhiro Iwamatsu 
214702c85b0SNobuhiro Iwamatsu static void
dp83902a_start_xmit(int start_page,int len)215702c85b0SNobuhiro Iwamatsu dp83902a_start_xmit(int start_page, int len)
216702c85b0SNobuhiro Iwamatsu {
217702c85b0SNobuhiro Iwamatsu 	dp83902a_priv_data_t *dp = (dp83902a_priv_data_t *) &nic;
218702c85b0SNobuhiro Iwamatsu 	u8 *base = dp->base;
219702c85b0SNobuhiro Iwamatsu 
220702c85b0SNobuhiro Iwamatsu 	DEBUG_FUNCTION();
221702c85b0SNobuhiro Iwamatsu 
222702c85b0SNobuhiro Iwamatsu #if DEBUG & 1
223702c85b0SNobuhiro Iwamatsu 	printf("Tx pkt %d len %d\n", start_page, len);
224702c85b0SNobuhiro Iwamatsu 	if (dp->tx_started)
225702c85b0SNobuhiro Iwamatsu 		printf("TX already started?!?\n");
226702c85b0SNobuhiro Iwamatsu #endif
227702c85b0SNobuhiro Iwamatsu 
228702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_ISR, (DP_ISR_TxP | DP_ISR_TxE));
229702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START);
230702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_TBCL, len & 0xFF);
231702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_TBCH, len >> 8);
232702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_TPSR, start_page);
233702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_TXPKT | DP_CR_START);
234702c85b0SNobuhiro Iwamatsu 
235702c85b0SNobuhiro Iwamatsu 	dp->tx_started = true;
236702c85b0SNobuhiro Iwamatsu }
237702c85b0SNobuhiro Iwamatsu 
238702c85b0SNobuhiro Iwamatsu /*
239702c85b0SNobuhiro Iwamatsu  * This routine is called to send data to the hardware. It is known a-priori
240702c85b0SNobuhiro Iwamatsu  * that there is free buffer space (dp->tx_next).
241702c85b0SNobuhiro Iwamatsu  */
242702c85b0SNobuhiro Iwamatsu static void
dp83902a_send(u8 * data,int total_len,u32 key)243702c85b0SNobuhiro Iwamatsu dp83902a_send(u8 *data, int total_len, u32 key)
244702c85b0SNobuhiro Iwamatsu {
245702c85b0SNobuhiro Iwamatsu 	struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic;
246702c85b0SNobuhiro Iwamatsu 	u8 *base = dp->base;
247702c85b0SNobuhiro Iwamatsu 	int len, start_page, pkt_len, i, isr;
248702c85b0SNobuhiro Iwamatsu #if DEBUG & 4
249702c85b0SNobuhiro Iwamatsu 	int dx;
250702c85b0SNobuhiro Iwamatsu #endif
251702c85b0SNobuhiro Iwamatsu 
252702c85b0SNobuhiro Iwamatsu 	DEBUG_FUNCTION();
253702c85b0SNobuhiro Iwamatsu 
254702c85b0SNobuhiro Iwamatsu 	len = pkt_len = total_len;
255702c85b0SNobuhiro Iwamatsu 	if (pkt_len < IEEE_8023_MIN_FRAME)
256702c85b0SNobuhiro Iwamatsu 		pkt_len = IEEE_8023_MIN_FRAME;
257702c85b0SNobuhiro Iwamatsu 
258702c85b0SNobuhiro Iwamatsu 	start_page = dp->tx_next;
259702c85b0SNobuhiro Iwamatsu 	if (dp->tx_next == dp->tx_buf1) {
260702c85b0SNobuhiro Iwamatsu 		dp->tx1 = start_page;
261702c85b0SNobuhiro Iwamatsu 		dp->tx1_len = pkt_len;
262702c85b0SNobuhiro Iwamatsu 		dp->tx1_key = key;
263702c85b0SNobuhiro Iwamatsu 		dp->tx_next = dp->tx_buf2;
264702c85b0SNobuhiro Iwamatsu 	} else {
265702c85b0SNobuhiro Iwamatsu 		dp->tx2 = start_page;
266702c85b0SNobuhiro Iwamatsu 		dp->tx2_len = pkt_len;
267702c85b0SNobuhiro Iwamatsu 		dp->tx2_key = key;
268702c85b0SNobuhiro Iwamatsu 		dp->tx_next = dp->tx_buf1;
269702c85b0SNobuhiro Iwamatsu 	}
270702c85b0SNobuhiro Iwamatsu 
271702c85b0SNobuhiro Iwamatsu #if DEBUG & 5
272702c85b0SNobuhiro Iwamatsu 	printf("TX prep page %d len %d\n", start_page, pkt_len);
273702c85b0SNobuhiro Iwamatsu #endif
274702c85b0SNobuhiro Iwamatsu 
275702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_ISR, DP_ISR_RDC);	/* Clear end of DMA */
276702c85b0SNobuhiro Iwamatsu 	{
277702c85b0SNobuhiro Iwamatsu 		/*
278702c85b0SNobuhiro Iwamatsu 		 * Dummy read. The manual sez something slightly different,
279702c85b0SNobuhiro Iwamatsu 		 * but the code is extended a bit to do what Hitachi's monitor
280702c85b0SNobuhiro Iwamatsu 		 * does (i.e., also read data).
281702c85b0SNobuhiro Iwamatsu 		 */
282702c85b0SNobuhiro Iwamatsu 
2834eaf172eSWolfgang Denk 		__maybe_unused u16 tmp;
284702c85b0SNobuhiro Iwamatsu 		int len = 1;
285702c85b0SNobuhiro Iwamatsu 
286702c85b0SNobuhiro Iwamatsu 		DP_OUT(base, DP_RSAL, 0x100 - len);
287702c85b0SNobuhiro Iwamatsu 		DP_OUT(base, DP_RSAH, (start_page - 1) & 0xff);
288702c85b0SNobuhiro Iwamatsu 		DP_OUT(base, DP_RBCL, len);
289702c85b0SNobuhiro Iwamatsu 		DP_OUT(base, DP_RBCH, 0);
290702c85b0SNobuhiro Iwamatsu 		DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_RDMA | DP_CR_START);
291702c85b0SNobuhiro Iwamatsu 		DP_IN_DATA(dp->data, tmp);
292702c85b0SNobuhiro Iwamatsu 	}
293702c85b0SNobuhiro Iwamatsu 
294702c85b0SNobuhiro Iwamatsu #ifdef CYGHWR_NS_DP83902A_PLF_BROKEN_TX_DMA
295702c85b0SNobuhiro Iwamatsu 	/*
296702c85b0SNobuhiro Iwamatsu 	 * Stall for a bit before continuing to work around random data
297702c85b0SNobuhiro Iwamatsu 	 * corruption problems on some platforms.
298702c85b0SNobuhiro Iwamatsu 	 */
299702c85b0SNobuhiro Iwamatsu 	CYGACC_CALL_IF_DELAY_US(1);
300702c85b0SNobuhiro Iwamatsu #endif
301702c85b0SNobuhiro Iwamatsu 
302702c85b0SNobuhiro Iwamatsu 	/* Send data to device buffer(s) */
303702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_RSAL, 0);
304702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_RSAH, start_page);
305702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_RBCL, pkt_len & 0xFF);
306702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_RBCH, pkt_len >> 8);
307702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_CR, DP_CR_WDMA | DP_CR_START);
308702c85b0SNobuhiro Iwamatsu 
309702c85b0SNobuhiro Iwamatsu 	/* Put data into buffer */
310702c85b0SNobuhiro Iwamatsu #if DEBUG & 4
311702c85b0SNobuhiro Iwamatsu 	printf(" sg buf %08lx len %08x\n ", (u32)data, len);
312702c85b0SNobuhiro Iwamatsu 	dx = 0;
313702c85b0SNobuhiro Iwamatsu #endif
314702c85b0SNobuhiro Iwamatsu 	while (len > 0) {
315702c85b0SNobuhiro Iwamatsu #if DEBUG & 4
316702c85b0SNobuhiro Iwamatsu 		printf(" %02x", *data);
317702c85b0SNobuhiro Iwamatsu 		if (0 == (++dx % 16)) printf("\n ");
318702c85b0SNobuhiro Iwamatsu #endif
319702c85b0SNobuhiro Iwamatsu 
320702c85b0SNobuhiro Iwamatsu 		DP_OUT_DATA(dp->data, *data++);
321702c85b0SNobuhiro Iwamatsu 		len--;
322702c85b0SNobuhiro Iwamatsu 	}
323702c85b0SNobuhiro Iwamatsu #if DEBUG & 4
324702c85b0SNobuhiro Iwamatsu 	printf("\n");
325702c85b0SNobuhiro Iwamatsu #endif
326702c85b0SNobuhiro Iwamatsu 	if (total_len < pkt_len) {
327702c85b0SNobuhiro Iwamatsu #if DEBUG & 4
328702c85b0SNobuhiro Iwamatsu 		printf("  + %d bytes of padding\n", pkt_len - total_len);
329702c85b0SNobuhiro Iwamatsu #endif
330702c85b0SNobuhiro Iwamatsu 		/* Padding to 802.3 length was required */
331702c85b0SNobuhiro Iwamatsu 		for (i = total_len; i < pkt_len;) {
332702c85b0SNobuhiro Iwamatsu 			i++;
333702c85b0SNobuhiro Iwamatsu 			DP_OUT_DATA(dp->data, 0);
334702c85b0SNobuhiro Iwamatsu 		}
335702c85b0SNobuhiro Iwamatsu 	}
336702c85b0SNobuhiro Iwamatsu 
337702c85b0SNobuhiro Iwamatsu #ifdef CYGHWR_NS_DP83902A_PLF_BROKEN_TX_DMA
338702c85b0SNobuhiro Iwamatsu 	/*
339702c85b0SNobuhiro Iwamatsu 	 * After last data write, delay for a bit before accessing the
340702c85b0SNobuhiro Iwamatsu 	 * device again, or we may get random data corruption in the last
341702c85b0SNobuhiro Iwamatsu 	 * datum (on some platforms).
342702c85b0SNobuhiro Iwamatsu 	 */
343702c85b0SNobuhiro Iwamatsu 	CYGACC_CALL_IF_DELAY_US(1);
344702c85b0SNobuhiro Iwamatsu #endif
345702c85b0SNobuhiro Iwamatsu 
346702c85b0SNobuhiro Iwamatsu 	/* Wait for DMA to complete */
347702c85b0SNobuhiro Iwamatsu 	do {
348702c85b0SNobuhiro Iwamatsu 		DP_IN(base, DP_ISR, isr);
349702c85b0SNobuhiro Iwamatsu 	} while ((isr & DP_ISR_RDC) == 0);
350702c85b0SNobuhiro Iwamatsu 
351702c85b0SNobuhiro Iwamatsu 	/* Then disable DMA */
352702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START);
353702c85b0SNobuhiro Iwamatsu 
354702c85b0SNobuhiro Iwamatsu 	/* Start transmit if not already going */
355702c85b0SNobuhiro Iwamatsu 	if (!dp->tx_started) {
356702c85b0SNobuhiro Iwamatsu 		if (start_page == dp->tx1) {
357702c85b0SNobuhiro Iwamatsu 			dp->tx_int = 1; /* Expecting interrupt from BUF1 */
358702c85b0SNobuhiro Iwamatsu 		} else {
359702c85b0SNobuhiro Iwamatsu 			dp->tx_int = 2; /* Expecting interrupt from BUF2 */
360702c85b0SNobuhiro Iwamatsu 		}
361702c85b0SNobuhiro Iwamatsu 		dp83902a_start_xmit(start_page, pkt_len);
362702c85b0SNobuhiro Iwamatsu 	}
363702c85b0SNobuhiro Iwamatsu }
364702c85b0SNobuhiro Iwamatsu 
365702c85b0SNobuhiro Iwamatsu /*
366702c85b0SNobuhiro Iwamatsu  * This function is called when a packet has been received. It's job is
367702c85b0SNobuhiro Iwamatsu  * to prepare to unload the packet from the hardware. Once the length of
368702c85b0SNobuhiro Iwamatsu  * the packet is known, the upper layer of the driver can be told. When
369702c85b0SNobuhiro Iwamatsu  * the upper layer is ready to unload the packet, the internal function
370702c85b0SNobuhiro Iwamatsu  * 'dp83902a_recv' will be called to actually fetch it from the hardware.
371702c85b0SNobuhiro Iwamatsu  */
372702c85b0SNobuhiro Iwamatsu static void
dp83902a_RxEvent(void)373702c85b0SNobuhiro Iwamatsu dp83902a_RxEvent(void)
374702c85b0SNobuhiro Iwamatsu {
375702c85b0SNobuhiro Iwamatsu 	struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic;
376702c85b0SNobuhiro Iwamatsu 	u8 *base = dp->base;
3774eaf172eSWolfgang Denk 	__maybe_unused u8 rsr;
378702c85b0SNobuhiro Iwamatsu 	u8 rcv_hdr[4];
379702c85b0SNobuhiro Iwamatsu 	int i, len, pkt, cur;
380702c85b0SNobuhiro Iwamatsu 
381702c85b0SNobuhiro Iwamatsu 	DEBUG_FUNCTION();
382702c85b0SNobuhiro Iwamatsu 
383702c85b0SNobuhiro Iwamatsu 	DP_IN(base, DP_RSR, rsr);
384702c85b0SNobuhiro Iwamatsu 	while (true) {
385702c85b0SNobuhiro Iwamatsu 		/* Read incoming packet header */
386702c85b0SNobuhiro Iwamatsu 		DP_OUT(base, DP_CR, DP_CR_PAGE1 | DP_CR_NODMA | DP_CR_START);
387702c85b0SNobuhiro Iwamatsu 		DP_IN(base, DP_P1_CURP, cur);
388702c85b0SNobuhiro Iwamatsu 		DP_OUT(base, DP_P1_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START);
389702c85b0SNobuhiro Iwamatsu 		DP_IN(base, DP_BNDRY, pkt);
390702c85b0SNobuhiro Iwamatsu 
391702c85b0SNobuhiro Iwamatsu 		pkt += 1;
392702c85b0SNobuhiro Iwamatsu 		if (pkt == dp->rx_buf_end)
393702c85b0SNobuhiro Iwamatsu 			pkt = dp->rx_buf_start;
394702c85b0SNobuhiro Iwamatsu 
395702c85b0SNobuhiro Iwamatsu 		if (pkt == cur) {
396702c85b0SNobuhiro Iwamatsu 			break;
397702c85b0SNobuhiro Iwamatsu 		}
398702c85b0SNobuhiro Iwamatsu 		DP_OUT(base, DP_RBCL, sizeof(rcv_hdr));
399702c85b0SNobuhiro Iwamatsu 		DP_OUT(base, DP_RBCH, 0);
400702c85b0SNobuhiro Iwamatsu 		DP_OUT(base, DP_RSAL, 0);
401702c85b0SNobuhiro Iwamatsu 		DP_OUT(base, DP_RSAH, pkt);
402702c85b0SNobuhiro Iwamatsu 		if (dp->rx_next == pkt) {
403702c85b0SNobuhiro Iwamatsu 			if (cur == dp->rx_buf_start)
404702c85b0SNobuhiro Iwamatsu 				DP_OUT(base, DP_BNDRY, dp->rx_buf_end - 1);
405702c85b0SNobuhiro Iwamatsu 			else
406702c85b0SNobuhiro Iwamatsu 				DP_OUT(base, DP_BNDRY, cur - 1); /* Update pointer */
407702c85b0SNobuhiro Iwamatsu 			return;
408702c85b0SNobuhiro Iwamatsu 		}
409702c85b0SNobuhiro Iwamatsu 		dp->rx_next = pkt;
410702c85b0SNobuhiro Iwamatsu 		DP_OUT(base, DP_ISR, DP_ISR_RDC); /* Clear end of DMA */
411702c85b0SNobuhiro Iwamatsu 		DP_OUT(base, DP_CR, DP_CR_RDMA | DP_CR_START);
412702c85b0SNobuhiro Iwamatsu #ifdef CYGHWR_NS_DP83902A_PLF_BROKEN_RX_DMA
413702c85b0SNobuhiro Iwamatsu 		CYGACC_CALL_IF_DELAY_US(10);
414702c85b0SNobuhiro Iwamatsu #endif
415702c85b0SNobuhiro Iwamatsu 
416702c85b0SNobuhiro Iwamatsu 		/* read header (get data size)*/
417702c85b0SNobuhiro Iwamatsu 		for (i = 0; i < sizeof(rcv_hdr);) {
418702c85b0SNobuhiro Iwamatsu 			DP_IN_DATA(dp->data, rcv_hdr[i++]);
419702c85b0SNobuhiro Iwamatsu 		}
420702c85b0SNobuhiro Iwamatsu 
421702c85b0SNobuhiro Iwamatsu #if DEBUG & 5
422702c85b0SNobuhiro Iwamatsu 		printf("rx hdr %02x %02x %02x %02x\n",
423702c85b0SNobuhiro Iwamatsu 			rcv_hdr[0], rcv_hdr[1], rcv_hdr[2], rcv_hdr[3]);
424702c85b0SNobuhiro Iwamatsu #endif
425702c85b0SNobuhiro Iwamatsu 		len = ((rcv_hdr[3] << 8) | rcv_hdr[2]) - sizeof(rcv_hdr);
426702c85b0SNobuhiro Iwamatsu 
427702c85b0SNobuhiro Iwamatsu 		/* data read */
428702c85b0SNobuhiro Iwamatsu 		uboot_push_packet_len(len);
429702c85b0SNobuhiro Iwamatsu 
430702c85b0SNobuhiro Iwamatsu 		if (rcv_hdr[1] == dp->rx_buf_start)
431702c85b0SNobuhiro Iwamatsu 			DP_OUT(base, DP_BNDRY, dp->rx_buf_end - 1);
432702c85b0SNobuhiro Iwamatsu 		else
433702c85b0SNobuhiro Iwamatsu 			DP_OUT(base, DP_BNDRY, rcv_hdr[1] - 1); /* Update pointer */
434702c85b0SNobuhiro Iwamatsu 	}
435702c85b0SNobuhiro Iwamatsu }
436702c85b0SNobuhiro Iwamatsu 
437702c85b0SNobuhiro Iwamatsu /*
438702c85b0SNobuhiro Iwamatsu  * This function is called as a result of the "eth_drv_recv()" call above.
439702c85b0SNobuhiro Iwamatsu  * It's job is to actually fetch data for a packet from the hardware once
440702c85b0SNobuhiro Iwamatsu  * memory buffers have been allocated for the packet. Note that the buffers
441702c85b0SNobuhiro Iwamatsu  * may come in pieces, using a scatter-gather list. This allows for more
442702c85b0SNobuhiro Iwamatsu  * efficient processing in the upper layers of the stack.
443702c85b0SNobuhiro Iwamatsu  */
444702c85b0SNobuhiro Iwamatsu static void
dp83902a_recv(u8 * data,int len)445702c85b0SNobuhiro Iwamatsu dp83902a_recv(u8 *data, int len)
446702c85b0SNobuhiro Iwamatsu {
447702c85b0SNobuhiro Iwamatsu 	struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic;
448702c85b0SNobuhiro Iwamatsu 	u8 *base = dp->base;
449702c85b0SNobuhiro Iwamatsu 	int i, mlen;
450702c85b0SNobuhiro Iwamatsu 	u8 saved_char = 0;
451702c85b0SNobuhiro Iwamatsu 	bool saved;
452702c85b0SNobuhiro Iwamatsu #if DEBUG & 4
453702c85b0SNobuhiro Iwamatsu 	int dx;
454702c85b0SNobuhiro Iwamatsu #endif
455702c85b0SNobuhiro Iwamatsu 
456702c85b0SNobuhiro Iwamatsu 	DEBUG_FUNCTION();
457702c85b0SNobuhiro Iwamatsu 
458702c85b0SNobuhiro Iwamatsu #if DEBUG & 5
459702c85b0SNobuhiro Iwamatsu 	printf("Rx packet %d length %d\n", dp->rx_next, len);
460702c85b0SNobuhiro Iwamatsu #endif
461702c85b0SNobuhiro Iwamatsu 
462702c85b0SNobuhiro Iwamatsu 	/* Read incoming packet data */
463702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START);
464702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_RBCL, len & 0xFF);
465702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_RBCH, len >> 8);
466702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_RSAL, 4);		/* Past header */
467702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_RSAH, dp->rx_next);
468702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_ISR, DP_ISR_RDC); /* Clear end of DMA */
469702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_CR, DP_CR_RDMA | DP_CR_START);
470702c85b0SNobuhiro Iwamatsu #ifdef CYGHWR_NS_DP83902A_PLF_BROKEN_RX_DMA
471702c85b0SNobuhiro Iwamatsu 	CYGACC_CALL_IF_DELAY_US(10);
472702c85b0SNobuhiro Iwamatsu #endif
473702c85b0SNobuhiro Iwamatsu 
474702c85b0SNobuhiro Iwamatsu 	saved = false;
475702c85b0SNobuhiro Iwamatsu 	for (i = 0; i < 1; i++) {
476702c85b0SNobuhiro Iwamatsu 		if (data) {
477702c85b0SNobuhiro Iwamatsu 			mlen = len;
478702c85b0SNobuhiro Iwamatsu #if DEBUG & 4
479702c85b0SNobuhiro Iwamatsu 			printf(" sg buf %08lx len %08x \n", (u32) data, mlen);
480702c85b0SNobuhiro Iwamatsu 			dx = 0;
481702c85b0SNobuhiro Iwamatsu #endif
482702c85b0SNobuhiro Iwamatsu 			while (0 < mlen) {
483702c85b0SNobuhiro Iwamatsu 				/* Saved byte from previous loop? */
484702c85b0SNobuhiro Iwamatsu 				if (saved) {
485702c85b0SNobuhiro Iwamatsu 					*data++ = saved_char;
486702c85b0SNobuhiro Iwamatsu 					mlen--;
487702c85b0SNobuhiro Iwamatsu 					saved = false;
488702c85b0SNobuhiro Iwamatsu 					continue;
489702c85b0SNobuhiro Iwamatsu 				}
490702c85b0SNobuhiro Iwamatsu 
491702c85b0SNobuhiro Iwamatsu 				{
492702c85b0SNobuhiro Iwamatsu 					u8 tmp;
493702c85b0SNobuhiro Iwamatsu 					DP_IN_DATA(dp->data, tmp);
494702c85b0SNobuhiro Iwamatsu #if DEBUG & 4
495702c85b0SNobuhiro Iwamatsu 					printf(" %02x", tmp);
496702c85b0SNobuhiro Iwamatsu 					if (0 == (++dx % 16)) printf("\n ");
497702c85b0SNobuhiro Iwamatsu #endif
49851855e89SMasahiro Yamada 					*data++ = tmp;
499702c85b0SNobuhiro Iwamatsu 					mlen--;
500702c85b0SNobuhiro Iwamatsu 				}
501702c85b0SNobuhiro Iwamatsu 			}
502702c85b0SNobuhiro Iwamatsu #if DEBUG & 4
503702c85b0SNobuhiro Iwamatsu 			printf("\n");
504702c85b0SNobuhiro Iwamatsu #endif
505702c85b0SNobuhiro Iwamatsu 		}
506702c85b0SNobuhiro Iwamatsu 	}
507702c85b0SNobuhiro Iwamatsu }
508702c85b0SNobuhiro Iwamatsu 
509702c85b0SNobuhiro Iwamatsu static void
dp83902a_TxEvent(void)510702c85b0SNobuhiro Iwamatsu dp83902a_TxEvent(void)
511702c85b0SNobuhiro Iwamatsu {
512702c85b0SNobuhiro Iwamatsu 	struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic;
513702c85b0SNobuhiro Iwamatsu 	u8 *base = dp->base;
5144eaf172eSWolfgang Denk 	__maybe_unused u8 tsr;
515702c85b0SNobuhiro Iwamatsu 	u32 key;
516702c85b0SNobuhiro Iwamatsu 
517702c85b0SNobuhiro Iwamatsu 	DEBUG_FUNCTION();
518702c85b0SNobuhiro Iwamatsu 
519702c85b0SNobuhiro Iwamatsu 	DP_IN(base, DP_TSR, tsr);
520702c85b0SNobuhiro Iwamatsu 	if (dp->tx_int == 1) {
521702c85b0SNobuhiro Iwamatsu 		key = dp->tx1_key;
522702c85b0SNobuhiro Iwamatsu 		dp->tx1 = 0;
523702c85b0SNobuhiro Iwamatsu 	} else {
524702c85b0SNobuhiro Iwamatsu 		key = dp->tx2_key;
525702c85b0SNobuhiro Iwamatsu 		dp->tx2 = 0;
526702c85b0SNobuhiro Iwamatsu 	}
527702c85b0SNobuhiro Iwamatsu 	/* Start next packet if one is ready */
528702c85b0SNobuhiro Iwamatsu 	dp->tx_started = false;
529702c85b0SNobuhiro Iwamatsu 	if (dp->tx1) {
530702c85b0SNobuhiro Iwamatsu 		dp83902a_start_xmit(dp->tx1, dp->tx1_len);
531702c85b0SNobuhiro Iwamatsu 		dp->tx_int = 1;
532702c85b0SNobuhiro Iwamatsu 	} else if (dp->tx2) {
533702c85b0SNobuhiro Iwamatsu 		dp83902a_start_xmit(dp->tx2, dp->tx2_len);
534702c85b0SNobuhiro Iwamatsu 		dp->tx_int = 2;
535702c85b0SNobuhiro Iwamatsu 	} else {
536702c85b0SNobuhiro Iwamatsu 		dp->tx_int = 0;
537702c85b0SNobuhiro Iwamatsu 	}
538702c85b0SNobuhiro Iwamatsu 	/* Tell higher level we sent this packet */
539702c85b0SNobuhiro Iwamatsu 	uboot_push_tx_done(key, 0);
540702c85b0SNobuhiro Iwamatsu }
541702c85b0SNobuhiro Iwamatsu 
542702c85b0SNobuhiro Iwamatsu /*
543702c85b0SNobuhiro Iwamatsu  * Read the tally counters to clear them. Called in response to a CNT
544702c85b0SNobuhiro Iwamatsu  * interrupt.
545702c85b0SNobuhiro Iwamatsu  */
546702c85b0SNobuhiro Iwamatsu static void
dp83902a_ClearCounters(void)547702c85b0SNobuhiro Iwamatsu dp83902a_ClearCounters(void)
548702c85b0SNobuhiro Iwamatsu {
549702c85b0SNobuhiro Iwamatsu 	struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic;
550702c85b0SNobuhiro Iwamatsu 	u8 *base = dp->base;
5514eaf172eSWolfgang Denk 	__maybe_unused u8 cnt1, cnt2, cnt3;
552702c85b0SNobuhiro Iwamatsu 
553702c85b0SNobuhiro Iwamatsu 	DP_IN(base, DP_FER, cnt1);
554702c85b0SNobuhiro Iwamatsu 	DP_IN(base, DP_CER, cnt2);
555702c85b0SNobuhiro Iwamatsu 	DP_IN(base, DP_MISSED, cnt3);
556702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_ISR, DP_ISR_CNT);
557702c85b0SNobuhiro Iwamatsu }
558702c85b0SNobuhiro Iwamatsu 
559702c85b0SNobuhiro Iwamatsu /*
560702c85b0SNobuhiro Iwamatsu  * Deal with an overflow condition. This code follows the procedure set
561702c85b0SNobuhiro Iwamatsu  * out in section 7.0 of the datasheet.
562702c85b0SNobuhiro Iwamatsu  */
563702c85b0SNobuhiro Iwamatsu static void
dp83902a_Overflow(void)564702c85b0SNobuhiro Iwamatsu dp83902a_Overflow(void)
565702c85b0SNobuhiro Iwamatsu {
566702c85b0SNobuhiro Iwamatsu 	struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *)&nic;
567702c85b0SNobuhiro Iwamatsu 	u8 *base = dp->base;
568702c85b0SNobuhiro Iwamatsu 	u8 isr;
569702c85b0SNobuhiro Iwamatsu 
570702c85b0SNobuhiro Iwamatsu 	/* Issue a stop command and wait 1.6ms for it to complete. */
571702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_CR, DP_CR_STOP | DP_CR_NODMA);
572702c85b0SNobuhiro Iwamatsu 	CYGACC_CALL_IF_DELAY_US(1600);
573702c85b0SNobuhiro Iwamatsu 
574702c85b0SNobuhiro Iwamatsu 	/* Clear the remote byte counter registers. */
575702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_RBCL, 0);
576702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_RBCH, 0);
577702c85b0SNobuhiro Iwamatsu 
578702c85b0SNobuhiro Iwamatsu 	/* Enter loopback mode while we clear the buffer. */
579702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_TCR, DP_TCR_LOCAL);
580702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_CR, DP_CR_START | DP_CR_NODMA);
581702c85b0SNobuhiro Iwamatsu 
582702c85b0SNobuhiro Iwamatsu 	/*
583702c85b0SNobuhiro Iwamatsu 	 * Read in as many packets as we can and acknowledge any and receive
584702c85b0SNobuhiro Iwamatsu 	 * interrupts. Since the buffer has overflowed, a receive event of
585eae4b2b6SVagrant Cascadian 	 * some kind will have occurred.
586702c85b0SNobuhiro Iwamatsu 	 */
587702c85b0SNobuhiro Iwamatsu 	dp83902a_RxEvent();
588702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_ISR, DP_ISR_RxP|DP_ISR_RxE);
589702c85b0SNobuhiro Iwamatsu 
590702c85b0SNobuhiro Iwamatsu 	/* Clear the overflow condition and leave loopback mode. */
591702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_ISR, DP_ISR_OFLW);
592702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_TCR, DP_TCR_NORMAL);
593702c85b0SNobuhiro Iwamatsu 
594702c85b0SNobuhiro Iwamatsu 	/*
595eae4b2b6SVagrant Cascadian 	 * If a transmit command was issued, but no transmit event has occurred,
596702c85b0SNobuhiro Iwamatsu 	 * restart it here.
597702c85b0SNobuhiro Iwamatsu 	 */
598702c85b0SNobuhiro Iwamatsu 	DP_IN(base, DP_ISR, isr);
599702c85b0SNobuhiro Iwamatsu 	if (dp->tx_started && !(isr & (DP_ISR_TxP|DP_ISR_TxE))) {
600702c85b0SNobuhiro Iwamatsu 		DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_TXPKT | DP_CR_START);
601702c85b0SNobuhiro Iwamatsu 	}
602702c85b0SNobuhiro Iwamatsu }
603702c85b0SNobuhiro Iwamatsu 
604702c85b0SNobuhiro Iwamatsu static void
dp83902a_poll(void)605702c85b0SNobuhiro Iwamatsu dp83902a_poll(void)
606702c85b0SNobuhiro Iwamatsu {
607702c85b0SNobuhiro Iwamatsu 	struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic;
608702c85b0SNobuhiro Iwamatsu 	u8 *base = dp->base;
609702c85b0SNobuhiro Iwamatsu 	u8 isr;
610702c85b0SNobuhiro Iwamatsu 
611702c85b0SNobuhiro Iwamatsu 	DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_PAGE0 | DP_CR_START);
612702c85b0SNobuhiro Iwamatsu 	DP_IN(base, DP_ISR, isr);
613702c85b0SNobuhiro Iwamatsu 	while (0 != isr) {
614702c85b0SNobuhiro Iwamatsu 		/*
615702c85b0SNobuhiro Iwamatsu 		 * The CNT interrupt triggers when the MSB of one of the error
616702c85b0SNobuhiro Iwamatsu 		 * counters is set. We don't much care about these counters, but
617702c85b0SNobuhiro Iwamatsu 		 * we should read their values to reset them.
618702c85b0SNobuhiro Iwamatsu 		 */
619702c85b0SNobuhiro Iwamatsu 		if (isr & DP_ISR_CNT) {
620702c85b0SNobuhiro Iwamatsu 			dp83902a_ClearCounters();
621702c85b0SNobuhiro Iwamatsu 		}
622702c85b0SNobuhiro Iwamatsu 		/*
623702c85b0SNobuhiro Iwamatsu 		 * Check for overflow. It's a special case, since there's a
624702c85b0SNobuhiro Iwamatsu 		 * particular procedure that must be followed to get back into
625702c85b0SNobuhiro Iwamatsu 		 * a running state.a
626702c85b0SNobuhiro Iwamatsu 		 */
627702c85b0SNobuhiro Iwamatsu 		if (isr & DP_ISR_OFLW) {
628702c85b0SNobuhiro Iwamatsu 			dp83902a_Overflow();
629702c85b0SNobuhiro Iwamatsu 		} else {
630702c85b0SNobuhiro Iwamatsu 			/*
631702c85b0SNobuhiro Iwamatsu 			 * Other kinds of interrupts can be acknowledged simply by
632702c85b0SNobuhiro Iwamatsu 			 * clearing the relevant bits of the ISR. Do that now, then
633702c85b0SNobuhiro Iwamatsu 			 * handle the interrupts we care about.
634702c85b0SNobuhiro Iwamatsu 			 */
635702c85b0SNobuhiro Iwamatsu 			DP_OUT(base, DP_ISR, isr);	/* Clear set bits */
636702c85b0SNobuhiro Iwamatsu 			if (!dp->running) break;	/* Is this necessary? */
637702c85b0SNobuhiro Iwamatsu 			/*
638702c85b0SNobuhiro Iwamatsu 			 * Check for tx_started on TX event since these may happen
639702c85b0SNobuhiro Iwamatsu 			 * spuriously it seems.
640702c85b0SNobuhiro Iwamatsu 			 */
641702c85b0SNobuhiro Iwamatsu 			if (isr & (DP_ISR_TxP|DP_ISR_TxE) && dp->tx_started) {
642702c85b0SNobuhiro Iwamatsu 				dp83902a_TxEvent();
643702c85b0SNobuhiro Iwamatsu 			}
644702c85b0SNobuhiro Iwamatsu 			if (isr & (DP_ISR_RxP|DP_ISR_RxE)) {
645702c85b0SNobuhiro Iwamatsu 				dp83902a_RxEvent();
646702c85b0SNobuhiro Iwamatsu 			}
647702c85b0SNobuhiro Iwamatsu 		}
648702c85b0SNobuhiro Iwamatsu 		DP_IN(base, DP_ISR, isr);
649702c85b0SNobuhiro Iwamatsu 	}
650702c85b0SNobuhiro Iwamatsu }
651702c85b0SNobuhiro Iwamatsu 
652702c85b0SNobuhiro Iwamatsu 
653a187559eSBin Meng /* U-Boot specific routines */
654702c85b0SNobuhiro Iwamatsu static u8 *pbuf = NULL;
655702c85b0SNobuhiro Iwamatsu 
656702c85b0SNobuhiro Iwamatsu static int pkey = -1;
657702c85b0SNobuhiro Iwamatsu static int initialized = 0;
658702c85b0SNobuhiro Iwamatsu 
uboot_push_packet_len(int len)659702c85b0SNobuhiro Iwamatsu void uboot_push_packet_len(int len) {
660702c85b0SNobuhiro Iwamatsu 	PRINTK("pushed len = %d\n", len);
661702c85b0SNobuhiro Iwamatsu 	if (len >= 2000) {
662702c85b0SNobuhiro Iwamatsu 		printf("NE2000: packet too big\n");
663702c85b0SNobuhiro Iwamatsu 		return;
664702c85b0SNobuhiro Iwamatsu 	}
665702c85b0SNobuhiro Iwamatsu 	dp83902a_recv(&pbuf[0], len);
666702c85b0SNobuhiro Iwamatsu 
667702c85b0SNobuhiro Iwamatsu 	/*Just pass it to the upper layer*/
6681fd92db8SJoe Hershberger 	net_process_received_packet(&pbuf[0], len);
669702c85b0SNobuhiro Iwamatsu }
670702c85b0SNobuhiro Iwamatsu 
uboot_push_tx_done(int key,int val)671702c85b0SNobuhiro Iwamatsu void uboot_push_tx_done(int key, int val) {
672702c85b0SNobuhiro Iwamatsu 	PRINTK("pushed key = %d\n", key);
673702c85b0SNobuhiro Iwamatsu 	pkey = key;
674702c85b0SNobuhiro Iwamatsu }
675702c85b0SNobuhiro Iwamatsu 
676d0201692SBernhard Kaindl /**
677d0201692SBernhard Kaindl  * Setup the driver and init MAC address according to doc/README.enetaddr
678d0201692SBernhard Kaindl  * Called by ne2k_register() before registering the driver @eth layer
679d0201692SBernhard Kaindl  *
680d0201692SBernhard Kaindl  * @param struct ethdevice of this instance of the driver for dev->enetaddr
681d0201692SBernhard Kaindl  * @return 0 on success, -1 on error (causing caller to print error msg)
682d0201692SBernhard Kaindl  */
ne2k_setup_driver(struct eth_device * dev)683d0201692SBernhard Kaindl static int ne2k_setup_driver(struct eth_device *dev)
684d0201692SBernhard Kaindl {
685d0201692SBernhard Kaindl 	PRINTK("### ne2k_setup_driver\n");
686702c85b0SNobuhiro Iwamatsu 
687702c85b0SNobuhiro Iwamatsu 	if (!pbuf) {
688702c85b0SNobuhiro Iwamatsu 		pbuf = malloc(2000);
689702c85b0SNobuhiro Iwamatsu 		if (!pbuf) {
690702c85b0SNobuhiro Iwamatsu 			printf("Cannot allocate rx buffer\n");
691702c85b0SNobuhiro Iwamatsu 			return -1;
692702c85b0SNobuhiro Iwamatsu 		}
693702c85b0SNobuhiro Iwamatsu 	}
694702c85b0SNobuhiro Iwamatsu 
695702c85b0SNobuhiro Iwamatsu #ifdef CONFIG_DRIVER_NE2000_CCR
696702c85b0SNobuhiro Iwamatsu 	{
697702c85b0SNobuhiro Iwamatsu 		vu_char *p = (vu_char *) CONFIG_DRIVER_NE2000_CCR;
698702c85b0SNobuhiro Iwamatsu 
699702c85b0SNobuhiro Iwamatsu 		PRINTK("CCR before is %x\n", *p);
700702c85b0SNobuhiro Iwamatsu 		*p = CONFIG_DRIVER_NE2000_VAL;
701702c85b0SNobuhiro Iwamatsu 		PRINTK("CCR after is %x\n", *p);
702702c85b0SNobuhiro Iwamatsu 	}
703702c85b0SNobuhiro Iwamatsu #endif
704702c85b0SNobuhiro Iwamatsu 
705702c85b0SNobuhiro Iwamatsu 	nic.base = (u8 *) CONFIG_DRIVER_NE2000_BASE;
706702c85b0SNobuhiro Iwamatsu 
707702c85b0SNobuhiro Iwamatsu 	nic.data = nic.base + DP_DATA;
708702c85b0SNobuhiro Iwamatsu 	nic.tx_buf1 = START_PG;
709702c85b0SNobuhiro Iwamatsu 	nic.tx_buf2 = START_PG2;
710702c85b0SNobuhiro Iwamatsu 	nic.rx_buf_start = RX_START;
711702c85b0SNobuhiro Iwamatsu 	nic.rx_buf_end = RX_END;
712702c85b0SNobuhiro Iwamatsu 
713d0201692SBernhard Kaindl 	/*
714d0201692SBernhard Kaindl 	 * According to doc/README.enetaddr, drivers shall give priority
715d0201692SBernhard Kaindl 	 * to the MAC address value in the environment, so we do not read
716d0201692SBernhard Kaindl 	 * it from the prom or eeprom if it is specified in the environment.
717d0201692SBernhard Kaindl 	 */
718*35affd7aSSimon Glass 	if (!eth_env_get_enetaddr("ethaddr", dev->enetaddr)) {
719d0201692SBernhard Kaindl 		/* If the MAC address is not in the environment, get it: */
720d0201692SBernhard Kaindl 		if (!get_prom(dev->enetaddr, nic.base)) /* get MAC from prom */
721d0201692SBernhard Kaindl 			dp83902a_init(dev->enetaddr);   /* fallback: seeprom */
722d0201692SBernhard Kaindl 		/* And write it into the environment otherwise eth_write_hwaddr
723*35affd7aSSimon Glass 		 * returns -1 due to eth_env_get_enetaddr_by_index() failing,
724d0201692SBernhard Kaindl 		 * and this causes "Warning: failed to set MAC address", and
725d0201692SBernhard Kaindl 		 * cmd_bdinfo has no ethaddr value which it can show: */
726fd1e959eSSimon Glass 		eth_env_set_enetaddr("ethaddr", dev->enetaddr);
727d0201692SBernhard Kaindl 	}
728702c85b0SNobuhiro Iwamatsu 	return 0;
729702c85b0SNobuhiro Iwamatsu }
730702c85b0SNobuhiro Iwamatsu 
ne2k_init(struct eth_device * dev,bd_t * bd)731d0201692SBernhard Kaindl static int ne2k_init(struct eth_device *dev, bd_t *bd)
732d0201692SBernhard Kaindl {
733d0201692SBernhard Kaindl 	dp83902a_start(dev->enetaddr);
734d0201692SBernhard Kaindl 	initialized = 1;
735d0201692SBernhard Kaindl 	return 0;
736d0201692SBernhard Kaindl }
737702c85b0SNobuhiro Iwamatsu 
ne2k_halt(struct eth_device * dev)738d0201692SBernhard Kaindl static void ne2k_halt(struct eth_device *dev)
739d0201692SBernhard Kaindl {
740d0201692SBernhard Kaindl 	debug("### ne2k_halt\n");
741702c85b0SNobuhiro Iwamatsu 	if(initialized)
742702c85b0SNobuhiro Iwamatsu 		dp83902a_stop();
743702c85b0SNobuhiro Iwamatsu 	initialized = 0;
744702c85b0SNobuhiro Iwamatsu }
745702c85b0SNobuhiro Iwamatsu 
ne2k_recv(struct eth_device * dev)746d0201692SBernhard Kaindl static int ne2k_recv(struct eth_device *dev)
747d0201692SBernhard Kaindl {
748702c85b0SNobuhiro Iwamatsu 	dp83902a_poll();
749702c85b0SNobuhiro Iwamatsu 	return 1;
750702c85b0SNobuhiro Iwamatsu }
751702c85b0SNobuhiro Iwamatsu 
ne2k_send(struct eth_device * dev,void * packet,int length)75210cbe3b6SJoe Hershberger static int ne2k_send(struct eth_device *dev, void *packet, int length)
753d0201692SBernhard Kaindl {
754702c85b0SNobuhiro Iwamatsu 	int tmo;
755702c85b0SNobuhiro Iwamatsu 
756d0201692SBernhard Kaindl 	debug("### ne2k_send\n");
757702c85b0SNobuhiro Iwamatsu 
758702c85b0SNobuhiro Iwamatsu 	pkey = -1;
759702c85b0SNobuhiro Iwamatsu 
760702c85b0SNobuhiro Iwamatsu 	dp83902a_send((u8 *) packet, length, 666);
7616d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 	tmo = get_timer (0) + TOUT * CONFIG_SYS_HZ;
762702c85b0SNobuhiro Iwamatsu 	while(1) {
763702c85b0SNobuhiro Iwamatsu 		dp83902a_poll();
764702c85b0SNobuhiro Iwamatsu 		if (pkey != -1) {
765702c85b0SNobuhiro Iwamatsu 			PRINTK("Packet sucesfully sent\n");
766702c85b0SNobuhiro Iwamatsu 			return 0;
767702c85b0SNobuhiro Iwamatsu 		}
768702c85b0SNobuhiro Iwamatsu 		if (get_timer (0) >= tmo) {
769702c85b0SNobuhiro Iwamatsu 			printf("transmission error (timoeut)\n");
770702c85b0SNobuhiro Iwamatsu 			return 0;
771702c85b0SNobuhiro Iwamatsu 		}
772702c85b0SNobuhiro Iwamatsu 
773702c85b0SNobuhiro Iwamatsu 	}
774702c85b0SNobuhiro Iwamatsu 	return 0;
775702c85b0SNobuhiro Iwamatsu }
776d0201692SBernhard Kaindl 
777d0201692SBernhard Kaindl /**
778d0201692SBernhard Kaindl  * Setup the driver for use and register it with the eth layer
779d0201692SBernhard Kaindl  * @return 0 on success, -1 on error (causing caller to print error msg)
780d0201692SBernhard Kaindl  */
ne2k_register(void)781d0201692SBernhard Kaindl int ne2k_register(void)
782d0201692SBernhard Kaindl {
783d0201692SBernhard Kaindl 	struct eth_device *dev;
784d0201692SBernhard Kaindl 
785d0201692SBernhard Kaindl 	dev = calloc(sizeof(*dev), 1);
786d0201692SBernhard Kaindl 	if (dev == NULL)
787d0201692SBernhard Kaindl 		return -1;
788d0201692SBernhard Kaindl 
789d0201692SBernhard Kaindl 	if (ne2k_setup_driver(dev))
790d0201692SBernhard Kaindl 		return -1;
791d0201692SBernhard Kaindl 
792d0201692SBernhard Kaindl 	dev->init = ne2k_init;
793d0201692SBernhard Kaindl 	dev->halt = ne2k_halt;
794d0201692SBernhard Kaindl 	dev->send = ne2k_send;
795d0201692SBernhard Kaindl 	dev->recv = ne2k_recv;
796d0201692SBernhard Kaindl 
797192bc694SBen Whitten 	strcpy(dev->name, "NE2000");
798d0201692SBernhard Kaindl 
799d0201692SBernhard Kaindl 	return eth_register(dev);
800d0201692SBernhard Kaindl }
801