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