xref: /rk3399_rockchip-uboot/drivers/net/ne2000.c (revision e710185aae90c64d39c2d453e40e58ceefe4f250)
12439e4bfSJean-Christophe PLAGNIOL-VILLARD /*
22439e4bfSJean-Christophe PLAGNIOL-VILLARD Ported to U-Boot  by Christian Pellegrin <chri@ascensit.com>
32439e4bfSJean-Christophe PLAGNIOL-VILLARD 
42439e4bfSJean-Christophe PLAGNIOL-VILLARD Based on sources from the Linux kernel (pcnet_cs.c, 8390.h) and
52439e4bfSJean-Christophe PLAGNIOL-VILLARD eCOS(if_dp83902a.c, if_dp83902a.h). Both of these 2 wonderful world
62439e4bfSJean-Christophe PLAGNIOL-VILLARD are GPL, so this is, of course, GPL.
72439e4bfSJean-Christophe PLAGNIOL-VILLARD 
82439e4bfSJean-Christophe PLAGNIOL-VILLARD 
92439e4bfSJean-Christophe PLAGNIOL-VILLARD ==========================================================================
102439e4bfSJean-Christophe PLAGNIOL-VILLARD 
112439e4bfSJean-Christophe PLAGNIOL-VILLARD dev/if_dp83902a.c
122439e4bfSJean-Christophe PLAGNIOL-VILLARD 
132439e4bfSJean-Christophe PLAGNIOL-VILLARD Ethernet device driver for NS DP83902a ethernet controller
142439e4bfSJean-Christophe PLAGNIOL-VILLARD 
152439e4bfSJean-Christophe PLAGNIOL-VILLARD ==========================================================================
162439e4bfSJean-Christophe PLAGNIOL-VILLARD ####ECOSGPLCOPYRIGHTBEGIN####
172439e4bfSJean-Christophe PLAGNIOL-VILLARD -------------------------------------------
182439e4bfSJean-Christophe PLAGNIOL-VILLARD This file is part of eCos, the Embedded Configurable Operating System.
192439e4bfSJean-Christophe PLAGNIOL-VILLARD Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
202439e4bfSJean-Christophe PLAGNIOL-VILLARD 
212439e4bfSJean-Christophe PLAGNIOL-VILLARD eCos is free software; you can redistribute it and/or modify it under
222439e4bfSJean-Christophe PLAGNIOL-VILLARD the terms of the GNU General Public License as published by the Free
232439e4bfSJean-Christophe PLAGNIOL-VILLARD Software Foundation; either version 2 or (at your option) any later version.
242439e4bfSJean-Christophe PLAGNIOL-VILLARD 
252439e4bfSJean-Christophe PLAGNIOL-VILLARD eCos is distributed in the hope that it will be useful, but WITHOUT ANY
262439e4bfSJean-Christophe PLAGNIOL-VILLARD WARRANTY; without even the implied warranty of MERCHANTABILITY or
272439e4bfSJean-Christophe PLAGNIOL-VILLARD FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
282439e4bfSJean-Christophe PLAGNIOL-VILLARD for more details.
292439e4bfSJean-Christophe PLAGNIOL-VILLARD 
302439e4bfSJean-Christophe PLAGNIOL-VILLARD You should have received a copy of the GNU General Public License along
312439e4bfSJean-Christophe PLAGNIOL-VILLARD with eCos; if not, write to the Free Software Foundation, Inc.,
322439e4bfSJean-Christophe PLAGNIOL-VILLARD 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
332439e4bfSJean-Christophe PLAGNIOL-VILLARD 
342439e4bfSJean-Christophe PLAGNIOL-VILLARD As a special exception, if other files instantiate templates or use macros
352439e4bfSJean-Christophe PLAGNIOL-VILLARD or inline functions from this file, or you compile this file and link it
362439e4bfSJean-Christophe PLAGNIOL-VILLARD with other works to produce a work based on this file, this file does not
372439e4bfSJean-Christophe PLAGNIOL-VILLARD by itself cause the resulting work to be covered by the GNU General Public
382439e4bfSJean-Christophe PLAGNIOL-VILLARD License. However the source code for this file must still be made available
392439e4bfSJean-Christophe PLAGNIOL-VILLARD in accordance with section (3) of the GNU General Public License.
402439e4bfSJean-Christophe PLAGNIOL-VILLARD 
412439e4bfSJean-Christophe PLAGNIOL-VILLARD This exception does not invalidate any other reasons why a work based on
422439e4bfSJean-Christophe PLAGNIOL-VILLARD this file might be covered by the GNU General Public License.
432439e4bfSJean-Christophe PLAGNIOL-VILLARD 
442439e4bfSJean-Christophe PLAGNIOL-VILLARD Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
452439e4bfSJean-Christophe PLAGNIOL-VILLARD at http://sources.redhat.com/ecos/ecos-license/
462439e4bfSJean-Christophe PLAGNIOL-VILLARD -------------------------------------------
472439e4bfSJean-Christophe PLAGNIOL-VILLARD ####ECOSGPLCOPYRIGHTEND####
482439e4bfSJean-Christophe PLAGNIOL-VILLARD ####BSDCOPYRIGHTBEGIN####
492439e4bfSJean-Christophe PLAGNIOL-VILLARD 
502439e4bfSJean-Christophe PLAGNIOL-VILLARD -------------------------------------------
512439e4bfSJean-Christophe PLAGNIOL-VILLARD 
522439e4bfSJean-Christophe PLAGNIOL-VILLARD Portions of this software may have been derived from OpenBSD or other sources,
532439e4bfSJean-Christophe PLAGNIOL-VILLARD and are covered by the appropriate copyright disclaimers included herein.
542439e4bfSJean-Christophe PLAGNIOL-VILLARD 
552439e4bfSJean-Christophe PLAGNIOL-VILLARD -------------------------------------------
562439e4bfSJean-Christophe PLAGNIOL-VILLARD 
572439e4bfSJean-Christophe PLAGNIOL-VILLARD ####BSDCOPYRIGHTEND####
582439e4bfSJean-Christophe PLAGNIOL-VILLARD ==========================================================================
592439e4bfSJean-Christophe PLAGNIOL-VILLARD #####DESCRIPTIONBEGIN####
602439e4bfSJean-Christophe PLAGNIOL-VILLARD 
612439e4bfSJean-Christophe PLAGNIOL-VILLARD Author(s):    gthomas
622439e4bfSJean-Christophe PLAGNIOL-VILLARD Contributors: gthomas, jskov, rsandifo
632439e4bfSJean-Christophe PLAGNIOL-VILLARD Date:	      2001-06-13
642439e4bfSJean-Christophe PLAGNIOL-VILLARD Purpose:
652439e4bfSJean-Christophe PLAGNIOL-VILLARD Description:
662439e4bfSJean-Christophe PLAGNIOL-VILLARD 
672439e4bfSJean-Christophe PLAGNIOL-VILLARD FIXME:	      Will fail if pinged with large packets (1520 bytes)
682439e4bfSJean-Christophe PLAGNIOL-VILLARD Add promisc config
692439e4bfSJean-Christophe PLAGNIOL-VILLARD Add SNMP
702439e4bfSJean-Christophe PLAGNIOL-VILLARD 
712439e4bfSJean-Christophe PLAGNIOL-VILLARD ####DESCRIPTIONEND####
722439e4bfSJean-Christophe PLAGNIOL-VILLARD 
732439e4bfSJean-Christophe PLAGNIOL-VILLARD 
742439e4bfSJean-Christophe PLAGNIOL-VILLARD ==========================================================================
752439e4bfSJean-Christophe PLAGNIOL-VILLARD 
762439e4bfSJean-Christophe PLAGNIOL-VILLARD */
772439e4bfSJean-Christophe PLAGNIOL-VILLARD 
782439e4bfSJean-Christophe PLAGNIOL-VILLARD #include <common.h>
792439e4bfSJean-Christophe PLAGNIOL-VILLARD #include <command.h>
802439e4bfSJean-Christophe PLAGNIOL-VILLARD #include <net.h>
812439e4bfSJean-Christophe PLAGNIOL-VILLARD #include <malloc.h>
822439e4bfSJean-Christophe PLAGNIOL-VILLARD 
832439e4bfSJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_DRIVER_NE2000
842439e4bfSJean-Christophe PLAGNIOL-VILLARD 
85*e710185aSgoda.yusuke #define mdelay(n)       udelay((n)*1000)
862439e4bfSJean-Christophe PLAGNIOL-VILLARD /* forward definition of function used for the uboot interface */
872439e4bfSJean-Christophe PLAGNIOL-VILLARD void uboot_push_packet_len(int len);
882439e4bfSJean-Christophe PLAGNIOL-VILLARD void uboot_push_tx_done(int key, int val);
892439e4bfSJean-Christophe PLAGNIOL-VILLARD 
902439e4bfSJean-Christophe PLAGNIOL-VILLARD /*
912439e4bfSJean-Christophe PLAGNIOL-VILLARD   ------------------------------------------------------------------------
922439e4bfSJean-Christophe PLAGNIOL-VILLARD   Debugging details
932439e4bfSJean-Christophe PLAGNIOL-VILLARD 
942439e4bfSJean-Christophe PLAGNIOL-VILLARD   Set to perms of:
952439e4bfSJean-Christophe PLAGNIOL-VILLARD   0 disables all debug output
962439e4bfSJean-Christophe PLAGNIOL-VILLARD   1 for process debug output
972439e4bfSJean-Christophe PLAGNIOL-VILLARD   2 for added data IO output: get_reg, put_reg
982439e4bfSJean-Christophe PLAGNIOL-VILLARD   4 for packet allocation/free output
992439e4bfSJean-Christophe PLAGNIOL-VILLARD   8 for only startup status, so we can tell we're installed OK
1002439e4bfSJean-Christophe PLAGNIOL-VILLARD */
1012439e4bfSJean-Christophe PLAGNIOL-VILLARD /*#define DEBUG 0xf*/
1022439e4bfSJean-Christophe PLAGNIOL-VILLARD #define DEBUG 0
1032439e4bfSJean-Christophe PLAGNIOL-VILLARD 
1042439e4bfSJean-Christophe PLAGNIOL-VILLARD #if DEBUG & 1
1052439e4bfSJean-Christophe PLAGNIOL-VILLARD #define DEBUG_FUNCTION() do { printf("%s\n", __FUNCTION__); } while (0)
1062439e4bfSJean-Christophe PLAGNIOL-VILLARD #define DEBUG_LINE() do { printf("%d\n", __LINE__); } while (0)
107*e710185aSgoda.yusuke #define PRINTK(args...) printf(args)
1082439e4bfSJean-Christophe PLAGNIOL-VILLARD #else
1092439e4bfSJean-Christophe PLAGNIOL-VILLARD #define DEBUG_FUNCTION() do {} while(0)
1102439e4bfSJean-Christophe PLAGNIOL-VILLARD #define DEBUG_LINE() do {} while(0)
1112439e4bfSJean-Christophe PLAGNIOL-VILLARD #define PRINTK(args...)
1122439e4bfSJean-Christophe PLAGNIOL-VILLARD #endif
1132439e4bfSJean-Christophe PLAGNIOL-VILLARD 
114*e710185aSgoda.yusuke /* NE2000 base header file */
115*e710185aSgoda.yusuke #include "ne2000_base.h"
116*e710185aSgoda.yusuke 
117*e710185aSgoda.yusuke /* Basic NE2000 chip support */
118*e710185aSgoda.yusuke #include "ne2000.h"
119*e710185aSgoda.yusuke 
1202439e4bfSJean-Christophe PLAGNIOL-VILLARD static dp83902a_priv_data_t nic; /* just one instance of the card supported */
1212439e4bfSJean-Christophe PLAGNIOL-VILLARD 
1222439e4bfSJean-Christophe PLAGNIOL-VILLARD static bool
1232439e4bfSJean-Christophe PLAGNIOL-VILLARD dp83902a_init(void)
1242439e4bfSJean-Christophe PLAGNIOL-VILLARD {
1252439e4bfSJean-Christophe PLAGNIOL-VILLARD 	dp83902a_priv_data_t *dp = &nic;
126*e710185aSgoda.yusuke 	u8* base;
1272439e4bfSJean-Christophe PLAGNIOL-VILLARD 
1282439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DEBUG_FUNCTION();
1292439e4bfSJean-Christophe PLAGNIOL-VILLARD 
1302439e4bfSJean-Christophe PLAGNIOL-VILLARD 	base = dp->base;
1312439e4bfSJean-Christophe PLAGNIOL-VILLARD 	if (!base) return false;  /* No device found */
1322439e4bfSJean-Christophe PLAGNIOL-VILLARD 
1332439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DEBUG_LINE();
1342439e4bfSJean-Christophe PLAGNIOL-VILLARD 
135*e710185aSgoda.yusuke #if defined(NE2000_BASIC_INIT)
1362439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* Prepare ESA */
1372439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_PAGE1);  /* Select page 1 */
1382439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* Use the address from the serial EEPROM */
1392439e4bfSJean-Christophe PLAGNIOL-VILLARD 	for (i = 0; i < 6; i++)
1402439e4bfSJean-Christophe PLAGNIOL-VILLARD 		DP_IN(base, DP_P1_PAR0+i, dp->esa[i]);
1412439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_PAGE0);  /* Select page 0 */
1422439e4bfSJean-Christophe PLAGNIOL-VILLARD 
1432439e4bfSJean-Christophe PLAGNIOL-VILLARD 	printf("NE2000 - %s ESA: %02x:%02x:%02x:%02x:%02x:%02x\n",
1442439e4bfSJean-Christophe PLAGNIOL-VILLARD 	       "eeprom",
1452439e4bfSJean-Christophe PLAGNIOL-VILLARD 	       dp->esa[0],
1462439e4bfSJean-Christophe PLAGNIOL-VILLARD 	       dp->esa[1],
1472439e4bfSJean-Christophe PLAGNIOL-VILLARD 	       dp->esa[2],
1482439e4bfSJean-Christophe PLAGNIOL-VILLARD 	       dp->esa[3],
1492439e4bfSJean-Christophe PLAGNIOL-VILLARD 	       dp->esa[4],
1502439e4bfSJean-Christophe PLAGNIOL-VILLARD 	       dp->esa[5] );
1512439e4bfSJean-Christophe PLAGNIOL-VILLARD 
152*e710185aSgoda.yusuke #endif	/* NE2000_BASIC_INIT */
1532439e4bfSJean-Christophe PLAGNIOL-VILLARD 	return true;
1542439e4bfSJean-Christophe PLAGNIOL-VILLARD }
1552439e4bfSJean-Christophe PLAGNIOL-VILLARD 
1562439e4bfSJean-Christophe PLAGNIOL-VILLARD static void
1572439e4bfSJean-Christophe PLAGNIOL-VILLARD dp83902a_stop(void)
1582439e4bfSJean-Christophe PLAGNIOL-VILLARD {
1592439e4bfSJean-Christophe PLAGNIOL-VILLARD 	dp83902a_priv_data_t *dp = &nic;
160*e710185aSgoda.yusuke 	u8 *base = dp->base;
1612439e4bfSJean-Christophe PLAGNIOL-VILLARD 
1622439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DEBUG_FUNCTION();
1632439e4bfSJean-Christophe PLAGNIOL-VILLARD 
1642439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_STOP);  /* Brutal */
1652439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DP_OUT(base, DP_ISR, 0xFF);		/* Clear any pending interrupts */
1662439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DP_OUT(base, DP_IMR, 0x00);		/* Disable all interrupts */
1672439e4bfSJean-Christophe PLAGNIOL-VILLARD 
1682439e4bfSJean-Christophe PLAGNIOL-VILLARD 	dp->running = false;
1692439e4bfSJean-Christophe PLAGNIOL-VILLARD }
1702439e4bfSJean-Christophe PLAGNIOL-VILLARD 
1712439e4bfSJean-Christophe PLAGNIOL-VILLARD /*
1722439e4bfSJean-Christophe PLAGNIOL-VILLARD   This function is called to "start up" the interface.  It may be called
1732439e4bfSJean-Christophe PLAGNIOL-VILLARD   multiple times, even when the hardware is already running.  It will be
1742439e4bfSJean-Christophe PLAGNIOL-VILLARD   called whenever something "hardware oriented" changes and should leave
1752439e4bfSJean-Christophe PLAGNIOL-VILLARD   the hardware ready to send/receive packets.
1762439e4bfSJean-Christophe PLAGNIOL-VILLARD */
1772439e4bfSJean-Christophe PLAGNIOL-VILLARD static void
178*e710185aSgoda.yusuke dp83902a_start(u8 * enaddr)
1792439e4bfSJean-Christophe PLAGNIOL-VILLARD {
1802439e4bfSJean-Christophe PLAGNIOL-VILLARD 	dp83902a_priv_data_t *dp = &nic;
181*e710185aSgoda.yusuke 	u8 *base = dp->base;
1822439e4bfSJean-Christophe PLAGNIOL-VILLARD 	int i;
1832439e4bfSJean-Christophe PLAGNIOL-VILLARD 
1842439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DEBUG_FUNCTION();
1852439e4bfSJean-Christophe PLAGNIOL-VILLARD 
1862439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_STOP); /* Brutal */
1872439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DP_OUT(base, DP_DCR, DP_DCR_INIT);
1882439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DP_OUT(base, DP_RBCH, 0);		/* Remote byte count */
1892439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DP_OUT(base, DP_RBCL, 0);
1902439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DP_OUT(base, DP_RCR, DP_RCR_MON);	/* Accept no packets */
1912439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DP_OUT(base, DP_TCR, DP_TCR_LOCAL);	/* Transmitter [virtually] off */
1922439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DP_OUT(base, DP_TPSR, dp->tx_buf1);	/* Transmitter start page */
1932439e4bfSJean-Christophe PLAGNIOL-VILLARD 	dp->tx1 = dp->tx2 = 0;
1942439e4bfSJean-Christophe PLAGNIOL-VILLARD 	dp->tx_next = dp->tx_buf1;
1952439e4bfSJean-Christophe PLAGNIOL-VILLARD 	dp->tx_started = false;
196*e710185aSgoda.yusuke 	dp->running = true;
1972439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DP_OUT(base, DP_PSTART, dp->rx_buf_start); /* Receive ring start page */
1982439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DP_OUT(base, DP_BNDRY, dp->rx_buf_end-1); /* Receive ring boundary */
1992439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DP_OUT(base, DP_PSTOP, dp->rx_buf_end);	/* Receive ring end page */
2002439e4bfSJean-Christophe PLAGNIOL-VILLARD 	dp->rx_next = dp->rx_buf_start-1;
201*e710185aSgoda.yusuke 	dp->running = true;
2022439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DP_OUT(base, DP_ISR, 0xFF);		/* Clear any pending interrupts */
2032439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DP_OUT(base, DP_IMR, DP_IMR_All);	/* Enable all interrupts */
2042439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_PAGE1 | DP_CR_STOP);  /* Select page 1 */
2052439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DP_OUT(base, DP_P1_CURP, dp->rx_buf_start);   /* Current page - next free page for Rx */
206*e710185aSgoda.yusuke 	dp->running = true;
2072439e4bfSJean-Christophe PLAGNIOL-VILLARD 	for (i = 0;  i < ETHER_ADDR_LEN;  i++) {
208*e710185aSgoda.yusuke 		/* FIXME */
209*e710185aSgoda.yusuke 		//*((vu_short*)( base + ((DP_P1_PAR0 + i) * 2) +  0x1400)) = enaddr[i];
2102439e4bfSJean-Christophe PLAGNIOL-VILLARD 		DP_OUT(base, DP_P1_PAR0+i, enaddr[i]);
2112439e4bfSJean-Christophe PLAGNIOL-VILLARD 	}
2122439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* Enable and start device */
2132439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START);
2142439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DP_OUT(base, DP_TCR, DP_TCR_NORMAL); /* Normal transmit operations */
2152439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DP_OUT(base, DP_RCR, DP_RCR_AB);  /* Accept broadcast, no errors, no multicast */
2162439e4bfSJean-Christophe PLAGNIOL-VILLARD 	dp->running = true;
217*e710185aSgoda.yusuke 
2182439e4bfSJean-Christophe PLAGNIOL-VILLARD }
2192439e4bfSJean-Christophe PLAGNIOL-VILLARD 
2202439e4bfSJean-Christophe PLAGNIOL-VILLARD /*
2212439e4bfSJean-Christophe PLAGNIOL-VILLARD   This routine is called to start the transmitter.  It is split out from the
2222439e4bfSJean-Christophe PLAGNIOL-VILLARD   data handling routine so it may be called either when data becomes first
2232439e4bfSJean-Christophe PLAGNIOL-VILLARD   available or when an Tx interrupt occurs
2242439e4bfSJean-Christophe PLAGNIOL-VILLARD */
2252439e4bfSJean-Christophe PLAGNIOL-VILLARD 
2262439e4bfSJean-Christophe PLAGNIOL-VILLARD static void
2272439e4bfSJean-Christophe PLAGNIOL-VILLARD dp83902a_start_xmit(int start_page, int len)
2282439e4bfSJean-Christophe PLAGNIOL-VILLARD {
2292439e4bfSJean-Christophe PLAGNIOL-VILLARD 	dp83902a_priv_data_t *dp = (dp83902a_priv_data_t *) &nic;
230*e710185aSgoda.yusuke 	u8 *base = dp->base;
2312439e4bfSJean-Christophe PLAGNIOL-VILLARD 
2322439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DEBUG_FUNCTION();
2332439e4bfSJean-Christophe PLAGNIOL-VILLARD 
2342439e4bfSJean-Christophe PLAGNIOL-VILLARD #if DEBUG & 1
2352439e4bfSJean-Christophe PLAGNIOL-VILLARD 	printf("Tx pkt %d len %d\n", start_page, len);
2362439e4bfSJean-Christophe PLAGNIOL-VILLARD 	if (dp->tx_started)
2372439e4bfSJean-Christophe PLAGNIOL-VILLARD 		printf("TX already started?!?\n");
2382439e4bfSJean-Christophe PLAGNIOL-VILLARD #endif
2392439e4bfSJean-Christophe PLAGNIOL-VILLARD 
2402439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DP_OUT(base, DP_ISR, (DP_ISR_TxP | DP_ISR_TxE));
2412439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START);
2422439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DP_OUT(base, DP_TBCL, len & 0xFF);
2432439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DP_OUT(base, DP_TBCH, len >> 8);
2442439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DP_OUT(base, DP_TPSR, start_page);
2452439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_TXPKT | DP_CR_START);
2462439e4bfSJean-Christophe PLAGNIOL-VILLARD 
2472439e4bfSJean-Christophe PLAGNIOL-VILLARD 	dp->tx_started = true;
2482439e4bfSJean-Christophe PLAGNIOL-VILLARD }
2492439e4bfSJean-Christophe PLAGNIOL-VILLARD 
2502439e4bfSJean-Christophe PLAGNIOL-VILLARD /*
2512439e4bfSJean-Christophe PLAGNIOL-VILLARD   This routine is called to send data to the hardware.  It is known a-priori
2522439e4bfSJean-Christophe PLAGNIOL-VILLARD   that there is free buffer space (dp->tx_next).
2532439e4bfSJean-Christophe PLAGNIOL-VILLARD */
2542439e4bfSJean-Christophe PLAGNIOL-VILLARD static void
255*e710185aSgoda.yusuke dp83902a_send(u8 *data, int total_len, u32 key)
2562439e4bfSJean-Christophe PLAGNIOL-VILLARD {
2572439e4bfSJean-Christophe PLAGNIOL-VILLARD 	struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic;
258*e710185aSgoda.yusuke 	u8 *base = dp->base;
2592439e4bfSJean-Christophe PLAGNIOL-VILLARD 	int len, start_page, pkt_len, i, isr;
2602439e4bfSJean-Christophe PLAGNIOL-VILLARD #if DEBUG & 4
2612439e4bfSJean-Christophe PLAGNIOL-VILLARD 	int dx;
2622439e4bfSJean-Christophe PLAGNIOL-VILLARD #endif
2632439e4bfSJean-Christophe PLAGNIOL-VILLARD 
2642439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DEBUG_FUNCTION();
2652439e4bfSJean-Christophe PLAGNIOL-VILLARD 
2662439e4bfSJean-Christophe PLAGNIOL-VILLARD 	len = pkt_len = total_len;
2672439e4bfSJean-Christophe PLAGNIOL-VILLARD 	if (pkt_len < IEEE_8023_MIN_FRAME) pkt_len = IEEE_8023_MIN_FRAME;
2682439e4bfSJean-Christophe PLAGNIOL-VILLARD 
2692439e4bfSJean-Christophe PLAGNIOL-VILLARD 	start_page = dp->tx_next;
2702439e4bfSJean-Christophe PLAGNIOL-VILLARD 	if (dp->tx_next == dp->tx_buf1) {
2712439e4bfSJean-Christophe PLAGNIOL-VILLARD 		dp->tx1 = start_page;
2722439e4bfSJean-Christophe PLAGNIOL-VILLARD 		dp->tx1_len = pkt_len;
2732439e4bfSJean-Christophe PLAGNIOL-VILLARD 		dp->tx1_key = key;
2742439e4bfSJean-Christophe PLAGNIOL-VILLARD 		dp->tx_next = dp->tx_buf2;
2752439e4bfSJean-Christophe PLAGNIOL-VILLARD 	} else {
2762439e4bfSJean-Christophe PLAGNIOL-VILLARD 		dp->tx2 = start_page;
2772439e4bfSJean-Christophe PLAGNIOL-VILLARD 		dp->tx2_len = pkt_len;
2782439e4bfSJean-Christophe PLAGNIOL-VILLARD 		dp->tx2_key = key;
2792439e4bfSJean-Christophe PLAGNIOL-VILLARD 		dp->tx_next = dp->tx_buf1;
2802439e4bfSJean-Christophe PLAGNIOL-VILLARD 	}
2812439e4bfSJean-Christophe PLAGNIOL-VILLARD 
2822439e4bfSJean-Christophe PLAGNIOL-VILLARD #if DEBUG & 5
2832439e4bfSJean-Christophe PLAGNIOL-VILLARD 	printf("TX prep page %d len %d\n", start_page, pkt_len);
2842439e4bfSJean-Christophe PLAGNIOL-VILLARD #endif
2852439e4bfSJean-Christophe PLAGNIOL-VILLARD 
2862439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DP_OUT(base, DP_ISR, DP_ISR_RDC);  /* Clear end of DMA */
2872439e4bfSJean-Christophe PLAGNIOL-VILLARD 	{
2882439e4bfSJean-Christophe PLAGNIOL-VILLARD 		/* Dummy read. The manual sez something slightly different, */
2892439e4bfSJean-Christophe PLAGNIOL-VILLARD 		/* but the code is extended a bit to do what Hitachi's monitor */
2902439e4bfSJean-Christophe PLAGNIOL-VILLARD 		/* does (i.e., also read data). */
2912439e4bfSJean-Christophe PLAGNIOL-VILLARD 
292*e710185aSgoda.yusuke 		u16 tmp;
2932439e4bfSJean-Christophe PLAGNIOL-VILLARD 		int len = 1;
2942439e4bfSJean-Christophe PLAGNIOL-VILLARD 
2952439e4bfSJean-Christophe PLAGNIOL-VILLARD 		DP_OUT(base, DP_RSAL, 0x100-len);
2962439e4bfSJean-Christophe PLAGNIOL-VILLARD 		DP_OUT(base, DP_RSAH, (start_page-1) & 0xff);
2972439e4bfSJean-Christophe PLAGNIOL-VILLARD 		DP_OUT(base, DP_RBCL, len);
2982439e4bfSJean-Christophe PLAGNIOL-VILLARD 		DP_OUT(base, DP_RBCH, 0);
2992439e4bfSJean-Christophe PLAGNIOL-VILLARD 		DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_RDMA | DP_CR_START);
3002439e4bfSJean-Christophe PLAGNIOL-VILLARD 		DP_IN_DATA(dp->data, tmp);
3012439e4bfSJean-Christophe PLAGNIOL-VILLARD 	}
3022439e4bfSJean-Christophe PLAGNIOL-VILLARD 
3032439e4bfSJean-Christophe PLAGNIOL-VILLARD #ifdef CYGHWR_NS_DP83902A_PLF_BROKEN_TX_DMA
3042439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* Stall for a bit before continuing to work around random data */
3052439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* corruption problems on some platforms. */
3062439e4bfSJean-Christophe PLAGNIOL-VILLARD 	CYGACC_CALL_IF_DELAY_US(1);
3072439e4bfSJean-Christophe PLAGNIOL-VILLARD #endif
3082439e4bfSJean-Christophe PLAGNIOL-VILLARD 
3092439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* Send data to device buffer(s) */
3102439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DP_OUT(base, DP_RSAL, 0);
3112439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DP_OUT(base, DP_RSAH, start_page);
3122439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DP_OUT(base, DP_RBCL, pkt_len & 0xFF);
3132439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DP_OUT(base, DP_RBCH, pkt_len >> 8);
3142439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DP_OUT(base, DP_CR, DP_CR_WDMA | DP_CR_START);
3152439e4bfSJean-Christophe PLAGNIOL-VILLARD 
3162439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* Put data into buffer */
3172439e4bfSJean-Christophe PLAGNIOL-VILLARD #if DEBUG & 4
318*e710185aSgoda.yusuke 	printf(" sg buf %08lx len %08x\n ", (u32)data, len);
3192439e4bfSJean-Christophe PLAGNIOL-VILLARD 	dx = 0;
3202439e4bfSJean-Christophe PLAGNIOL-VILLARD #endif
3212439e4bfSJean-Christophe PLAGNIOL-VILLARD 	while (len > 0) {
3222439e4bfSJean-Christophe PLAGNIOL-VILLARD #if DEBUG & 4
3232439e4bfSJean-Christophe PLAGNIOL-VILLARD 		printf(" %02x", *data);
3242439e4bfSJean-Christophe PLAGNIOL-VILLARD 		if (0 == (++dx % 16)) printf("\n ");
3252439e4bfSJean-Christophe PLAGNIOL-VILLARD #endif
326*e710185aSgoda.yusuke 
3272439e4bfSJean-Christophe PLAGNIOL-VILLARD 		DP_OUT_DATA(dp->data, *data++);
3282439e4bfSJean-Christophe PLAGNIOL-VILLARD 		len--;
3292439e4bfSJean-Christophe PLAGNIOL-VILLARD 	}
3302439e4bfSJean-Christophe PLAGNIOL-VILLARD #if DEBUG & 4
3312439e4bfSJean-Christophe PLAGNIOL-VILLARD 	printf("\n");
3322439e4bfSJean-Christophe PLAGNIOL-VILLARD #endif
3332439e4bfSJean-Christophe PLAGNIOL-VILLARD 	if (total_len < pkt_len) {
3342439e4bfSJean-Christophe PLAGNIOL-VILLARD #if DEBUG & 4
3352439e4bfSJean-Christophe PLAGNIOL-VILLARD 		printf("  + %d bytes of padding\n", pkt_len - total_len);
3362439e4bfSJean-Christophe PLAGNIOL-VILLARD #endif
3372439e4bfSJean-Christophe PLAGNIOL-VILLARD 		/* Padding to 802.3 length was required */
3382439e4bfSJean-Christophe PLAGNIOL-VILLARD 		for (i = total_len;  i < pkt_len;) {
3392439e4bfSJean-Christophe PLAGNIOL-VILLARD 			i++;
3402439e4bfSJean-Christophe PLAGNIOL-VILLARD 			DP_OUT_DATA(dp->data, 0);
3412439e4bfSJean-Christophe PLAGNIOL-VILLARD 		}
3422439e4bfSJean-Christophe PLAGNIOL-VILLARD 	}
3432439e4bfSJean-Christophe PLAGNIOL-VILLARD 
3442439e4bfSJean-Christophe PLAGNIOL-VILLARD #ifdef CYGHWR_NS_DP83902A_PLF_BROKEN_TX_DMA
3452439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* After last data write, delay for a bit before accessing the */
3462439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* device again, or we may get random data corruption in the last */
3472439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* datum (on some platforms). */
3482439e4bfSJean-Christophe PLAGNIOL-VILLARD 	CYGACC_CALL_IF_DELAY_US(1);
3492439e4bfSJean-Christophe PLAGNIOL-VILLARD #endif
3502439e4bfSJean-Christophe PLAGNIOL-VILLARD 
3512439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* Wait for DMA to complete */
3522439e4bfSJean-Christophe PLAGNIOL-VILLARD 	do {
3532439e4bfSJean-Christophe PLAGNIOL-VILLARD 		DP_IN(base, DP_ISR, isr);
3542439e4bfSJean-Christophe PLAGNIOL-VILLARD 	} while ((isr & DP_ISR_RDC) == 0);
355*e710185aSgoda.yusuke 
3562439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* Then disable DMA */
3572439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START);
3582439e4bfSJean-Christophe PLAGNIOL-VILLARD 
3592439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* Start transmit if not already going */
3602439e4bfSJean-Christophe PLAGNIOL-VILLARD 	if (!dp->tx_started) {
3612439e4bfSJean-Christophe PLAGNIOL-VILLARD 		if (start_page == dp->tx1) {
3622439e4bfSJean-Christophe PLAGNIOL-VILLARD 			dp->tx_int = 1;  /* Expecting interrupt from BUF1 */
3632439e4bfSJean-Christophe PLAGNIOL-VILLARD 		} else {
3642439e4bfSJean-Christophe PLAGNIOL-VILLARD 			dp->tx_int = 2;  /* Expecting interrupt from BUF2 */
3652439e4bfSJean-Christophe PLAGNIOL-VILLARD 		}
3662439e4bfSJean-Christophe PLAGNIOL-VILLARD 		dp83902a_start_xmit(start_page, pkt_len);
3672439e4bfSJean-Christophe PLAGNIOL-VILLARD 	}
3682439e4bfSJean-Christophe PLAGNIOL-VILLARD }
3692439e4bfSJean-Christophe PLAGNIOL-VILLARD 
3702439e4bfSJean-Christophe PLAGNIOL-VILLARD /*
3712439e4bfSJean-Christophe PLAGNIOL-VILLARD   This function is called when a packet has been received.  It's job is
3722439e4bfSJean-Christophe PLAGNIOL-VILLARD   to prepare to unload the packet from the hardware.  Once the length of
3732439e4bfSJean-Christophe PLAGNIOL-VILLARD   the packet is known, the upper layer of the driver can be told.  When
3742439e4bfSJean-Christophe PLAGNIOL-VILLARD   the upper layer is ready to unload the packet, the internal function
3752439e4bfSJean-Christophe PLAGNIOL-VILLARD   'dp83902a_recv' will be called to actually fetch it from the hardware.
3762439e4bfSJean-Christophe PLAGNIOL-VILLARD */
3772439e4bfSJean-Christophe PLAGNIOL-VILLARD static void
3782439e4bfSJean-Christophe PLAGNIOL-VILLARD dp83902a_RxEvent(void)
3792439e4bfSJean-Christophe PLAGNIOL-VILLARD {
3802439e4bfSJean-Christophe PLAGNIOL-VILLARD 	struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic;
381*e710185aSgoda.yusuke 	u8 *base = dp->base;
382*e710185aSgoda.yusuke 	u8 rsr;
383*e710185aSgoda.yusuke 	u8 rcv_hdr[4];
3842439e4bfSJean-Christophe PLAGNIOL-VILLARD 	int i, len, pkt, cur;
3852439e4bfSJean-Christophe PLAGNIOL-VILLARD 
3862439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DEBUG_FUNCTION();
3872439e4bfSJean-Christophe PLAGNIOL-VILLARD 
3882439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DP_IN(base, DP_RSR, rsr);
3892439e4bfSJean-Christophe PLAGNIOL-VILLARD 	while (true) {
3902439e4bfSJean-Christophe PLAGNIOL-VILLARD 		/* Read incoming packet header */
3912439e4bfSJean-Christophe PLAGNIOL-VILLARD 		DP_OUT(base, DP_CR, DP_CR_PAGE1 | DP_CR_NODMA | DP_CR_START);
3922439e4bfSJean-Christophe PLAGNIOL-VILLARD 		DP_IN(base, DP_P1_CURP, cur);
3932439e4bfSJean-Christophe PLAGNIOL-VILLARD 		DP_OUT(base, DP_P1_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START);
3942439e4bfSJean-Christophe PLAGNIOL-VILLARD 		DP_IN(base, DP_BNDRY, pkt);
3952439e4bfSJean-Christophe PLAGNIOL-VILLARD 
3962439e4bfSJean-Christophe PLAGNIOL-VILLARD 		pkt += 1;
3972439e4bfSJean-Christophe PLAGNIOL-VILLARD 		if (pkt == dp->rx_buf_end)
3982439e4bfSJean-Christophe PLAGNIOL-VILLARD 			pkt = dp->rx_buf_start;
3992439e4bfSJean-Christophe PLAGNIOL-VILLARD 
4002439e4bfSJean-Christophe PLAGNIOL-VILLARD 		if (pkt == cur) {
4012439e4bfSJean-Christophe PLAGNIOL-VILLARD 			break;
4022439e4bfSJean-Christophe PLAGNIOL-VILLARD 		}
4032439e4bfSJean-Christophe PLAGNIOL-VILLARD 		DP_OUT(base, DP_RBCL, sizeof(rcv_hdr));
4042439e4bfSJean-Christophe PLAGNIOL-VILLARD 		DP_OUT(base, DP_RBCH, 0);
4052439e4bfSJean-Christophe PLAGNIOL-VILLARD 		DP_OUT(base, DP_RSAL, 0);
4062439e4bfSJean-Christophe PLAGNIOL-VILLARD 		DP_OUT(base, DP_RSAH, pkt);
4072439e4bfSJean-Christophe PLAGNIOL-VILLARD 		if (dp->rx_next == pkt) {
4082439e4bfSJean-Christophe PLAGNIOL-VILLARD 			if (cur == dp->rx_buf_start)
4092439e4bfSJean-Christophe PLAGNIOL-VILLARD 				DP_OUT(base, DP_BNDRY, dp->rx_buf_end-1);
4102439e4bfSJean-Christophe PLAGNIOL-VILLARD 			else
4112439e4bfSJean-Christophe PLAGNIOL-VILLARD 				DP_OUT(base, DP_BNDRY, cur-1); /* Update pointer */
4122439e4bfSJean-Christophe PLAGNIOL-VILLARD 			return;
4132439e4bfSJean-Christophe PLAGNIOL-VILLARD 		}
4142439e4bfSJean-Christophe PLAGNIOL-VILLARD 		dp->rx_next = pkt;
4152439e4bfSJean-Christophe PLAGNIOL-VILLARD 		DP_OUT(base, DP_ISR, DP_ISR_RDC); /* Clear end of DMA */
4162439e4bfSJean-Christophe PLAGNIOL-VILLARD 		DP_OUT(base, DP_CR, DP_CR_RDMA | DP_CR_START);
4172439e4bfSJean-Christophe PLAGNIOL-VILLARD #ifdef CYGHWR_NS_DP83902A_PLF_BROKEN_RX_DMA
4182439e4bfSJean-Christophe PLAGNIOL-VILLARD 		CYGACC_CALL_IF_DELAY_US(10);
4192439e4bfSJean-Christophe PLAGNIOL-VILLARD #endif
4202439e4bfSJean-Christophe PLAGNIOL-VILLARD 
421*e710185aSgoda.yusuke 		/* read header (get data size)*/
4222439e4bfSJean-Christophe PLAGNIOL-VILLARD 		for (i = 0;  i < sizeof(rcv_hdr);) {
4232439e4bfSJean-Christophe PLAGNIOL-VILLARD 			DP_IN_DATA(dp->data, rcv_hdr[i++]);
4242439e4bfSJean-Christophe PLAGNIOL-VILLARD 		}
4252439e4bfSJean-Christophe PLAGNIOL-VILLARD 
4262439e4bfSJean-Christophe PLAGNIOL-VILLARD #if DEBUG & 5
4272439e4bfSJean-Christophe PLAGNIOL-VILLARD 		printf("rx hdr %02x %02x %02x %02x\n",
4282439e4bfSJean-Christophe PLAGNIOL-VILLARD 		       rcv_hdr[0], rcv_hdr[1], rcv_hdr[2], rcv_hdr[3]);
4292439e4bfSJean-Christophe PLAGNIOL-VILLARD #endif
4302439e4bfSJean-Christophe PLAGNIOL-VILLARD 		len = ((rcv_hdr[3] << 8) | rcv_hdr[2]) - sizeof(rcv_hdr);
431*e710185aSgoda.yusuke 
432*e710185aSgoda.yusuke 		/* data read */
4332439e4bfSJean-Christophe PLAGNIOL-VILLARD 		uboot_push_packet_len(len);
434*e710185aSgoda.yusuke 
4352439e4bfSJean-Christophe PLAGNIOL-VILLARD 		if (rcv_hdr[1] == dp->rx_buf_start)
4362439e4bfSJean-Christophe PLAGNIOL-VILLARD 			DP_OUT(base, DP_BNDRY, dp->rx_buf_end-1);
4372439e4bfSJean-Christophe PLAGNIOL-VILLARD 		else
4382439e4bfSJean-Christophe PLAGNIOL-VILLARD 			DP_OUT(base, DP_BNDRY, rcv_hdr[1]-1); /* Update pointer */
4392439e4bfSJean-Christophe PLAGNIOL-VILLARD 	}
4402439e4bfSJean-Christophe PLAGNIOL-VILLARD }
4412439e4bfSJean-Christophe PLAGNIOL-VILLARD 
4422439e4bfSJean-Christophe PLAGNIOL-VILLARD /*
4432439e4bfSJean-Christophe PLAGNIOL-VILLARD   This function is called as a result of the "eth_drv_recv()" call above.
4442439e4bfSJean-Christophe PLAGNIOL-VILLARD   It's job is to actually fetch data for a packet from the hardware once
4452439e4bfSJean-Christophe PLAGNIOL-VILLARD   memory buffers have been allocated for the packet.  Note that the buffers
4462439e4bfSJean-Christophe PLAGNIOL-VILLARD   may come in pieces, using a scatter-gather list.  This allows for more
4472439e4bfSJean-Christophe PLAGNIOL-VILLARD   efficient processing in the upper layers of the stack.
4482439e4bfSJean-Christophe PLAGNIOL-VILLARD */
4492439e4bfSJean-Christophe PLAGNIOL-VILLARD static void
450*e710185aSgoda.yusuke dp83902a_recv(u8 *data, int len)
4512439e4bfSJean-Christophe PLAGNIOL-VILLARD {
4522439e4bfSJean-Christophe PLAGNIOL-VILLARD 	struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic;
453*e710185aSgoda.yusuke 	u8 *base = dp->base;
4542439e4bfSJean-Christophe PLAGNIOL-VILLARD 	int i, mlen;
455*e710185aSgoda.yusuke 	u8 saved_char = 0;
4562439e4bfSJean-Christophe PLAGNIOL-VILLARD 	bool saved;
4572439e4bfSJean-Christophe PLAGNIOL-VILLARD #if DEBUG & 4
4582439e4bfSJean-Christophe PLAGNIOL-VILLARD 	int dx;
4592439e4bfSJean-Christophe PLAGNIOL-VILLARD #endif
4602439e4bfSJean-Christophe PLAGNIOL-VILLARD 
4612439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DEBUG_FUNCTION();
4622439e4bfSJean-Christophe PLAGNIOL-VILLARD 
4632439e4bfSJean-Christophe PLAGNIOL-VILLARD #if DEBUG & 5
4642439e4bfSJean-Christophe PLAGNIOL-VILLARD 	printf("Rx packet %d length %d\n", dp->rx_next, len);
4652439e4bfSJean-Christophe PLAGNIOL-VILLARD #endif
4662439e4bfSJean-Christophe PLAGNIOL-VILLARD 
4672439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* Read incoming packet data */
4682439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START);
4692439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DP_OUT(base, DP_RBCL, len & 0xFF);
4702439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DP_OUT(base, DP_RBCH, len >> 8);
4712439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DP_OUT(base, DP_RSAL, 4);		/* Past header */
4722439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DP_OUT(base, DP_RSAH, dp->rx_next);
4732439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DP_OUT(base, DP_ISR, DP_ISR_RDC); /* Clear end of DMA */
4742439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DP_OUT(base, DP_CR, DP_CR_RDMA | DP_CR_START);
4752439e4bfSJean-Christophe PLAGNIOL-VILLARD #ifdef CYGHWR_NS_DP83902A_PLF_BROKEN_RX_DMA
4762439e4bfSJean-Christophe PLAGNIOL-VILLARD 	CYGACC_CALL_IF_DELAY_US(10);
4772439e4bfSJean-Christophe PLAGNIOL-VILLARD #endif
4782439e4bfSJean-Christophe PLAGNIOL-VILLARD 
4792439e4bfSJean-Christophe PLAGNIOL-VILLARD 	saved = false;
4802439e4bfSJean-Christophe PLAGNIOL-VILLARD 	for (i = 0;  i < 1;  i++) {
4812439e4bfSJean-Christophe PLAGNIOL-VILLARD 		if (data) {
4822439e4bfSJean-Christophe PLAGNIOL-VILLARD 			mlen = len;
4832439e4bfSJean-Christophe PLAGNIOL-VILLARD #if DEBUG & 4
484*e710185aSgoda.yusuke 			printf(" sg buf %08lx len %08x \n", (u32) data, mlen);
4852439e4bfSJean-Christophe PLAGNIOL-VILLARD 			dx = 0;
4862439e4bfSJean-Christophe PLAGNIOL-VILLARD #endif
4872439e4bfSJean-Christophe PLAGNIOL-VILLARD 			while (0 < mlen) {
4882439e4bfSJean-Christophe PLAGNIOL-VILLARD 				/* Saved byte from previous loop? */
4892439e4bfSJean-Christophe PLAGNIOL-VILLARD 				if (saved) {
4902439e4bfSJean-Christophe PLAGNIOL-VILLARD 					*data++ = saved_char;
4912439e4bfSJean-Christophe PLAGNIOL-VILLARD 					mlen--;
4922439e4bfSJean-Christophe PLAGNIOL-VILLARD 					saved = false;
4932439e4bfSJean-Christophe PLAGNIOL-VILLARD 					continue;
4942439e4bfSJean-Christophe PLAGNIOL-VILLARD 				}
4952439e4bfSJean-Christophe PLAGNIOL-VILLARD 
4962439e4bfSJean-Christophe PLAGNIOL-VILLARD 				{
497*e710185aSgoda.yusuke 					u8 tmp;
4982439e4bfSJean-Christophe PLAGNIOL-VILLARD 					DP_IN_DATA(dp->data, tmp);
4992439e4bfSJean-Christophe PLAGNIOL-VILLARD #if DEBUG & 4
5002439e4bfSJean-Christophe PLAGNIOL-VILLARD 					printf(" %02x", tmp);
5012439e4bfSJean-Christophe PLAGNIOL-VILLARD 					if (0 == (++dx % 16)) printf("\n ");
5022439e4bfSJean-Christophe PLAGNIOL-VILLARD #endif
5032439e4bfSJean-Christophe PLAGNIOL-VILLARD 					*data++ = tmp;;
5042439e4bfSJean-Christophe PLAGNIOL-VILLARD 					mlen--;
5052439e4bfSJean-Christophe PLAGNIOL-VILLARD 				}
5062439e4bfSJean-Christophe PLAGNIOL-VILLARD 			}
5072439e4bfSJean-Christophe PLAGNIOL-VILLARD #if DEBUG & 4
5082439e4bfSJean-Christophe PLAGNIOL-VILLARD 			printf("\n");
5092439e4bfSJean-Christophe PLAGNIOL-VILLARD #endif
5102439e4bfSJean-Christophe PLAGNIOL-VILLARD 		}
5112439e4bfSJean-Christophe PLAGNIOL-VILLARD 	}
5122439e4bfSJean-Christophe PLAGNIOL-VILLARD }
5132439e4bfSJean-Christophe PLAGNIOL-VILLARD 
5142439e4bfSJean-Christophe PLAGNIOL-VILLARD static void
5152439e4bfSJean-Christophe PLAGNIOL-VILLARD dp83902a_TxEvent(void)
5162439e4bfSJean-Christophe PLAGNIOL-VILLARD {
5172439e4bfSJean-Christophe PLAGNIOL-VILLARD 	struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic;
518*e710185aSgoda.yusuke 	u8 *base = dp->base;
519*e710185aSgoda.yusuke 	u8 tsr;
520*e710185aSgoda.yusuke 	u32 key;
5212439e4bfSJean-Christophe PLAGNIOL-VILLARD 
5222439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DEBUG_FUNCTION();
5232439e4bfSJean-Christophe PLAGNIOL-VILLARD 
5242439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DP_IN(base, DP_TSR, tsr);
5252439e4bfSJean-Christophe PLAGNIOL-VILLARD 	if (dp->tx_int == 1) {
5262439e4bfSJean-Christophe PLAGNIOL-VILLARD 		key = dp->tx1_key;
5272439e4bfSJean-Christophe PLAGNIOL-VILLARD 		dp->tx1 = 0;
5282439e4bfSJean-Christophe PLAGNIOL-VILLARD 	} else {
5292439e4bfSJean-Christophe PLAGNIOL-VILLARD 		key = dp->tx2_key;
5302439e4bfSJean-Christophe PLAGNIOL-VILLARD 		dp->tx2 = 0;
5312439e4bfSJean-Christophe PLAGNIOL-VILLARD 	}
5322439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* Start next packet if one is ready */
5332439e4bfSJean-Christophe PLAGNIOL-VILLARD 	dp->tx_started = false;
5342439e4bfSJean-Christophe PLAGNIOL-VILLARD 	if (dp->tx1) {
5352439e4bfSJean-Christophe PLAGNIOL-VILLARD 		dp83902a_start_xmit(dp->tx1, dp->tx1_len);
5362439e4bfSJean-Christophe PLAGNIOL-VILLARD 		dp->tx_int = 1;
5372439e4bfSJean-Christophe PLAGNIOL-VILLARD 	} else if (dp->tx2) {
5382439e4bfSJean-Christophe PLAGNIOL-VILLARD 		dp83902a_start_xmit(dp->tx2, dp->tx2_len);
5392439e4bfSJean-Christophe PLAGNIOL-VILLARD 		dp->tx_int = 2;
5402439e4bfSJean-Christophe PLAGNIOL-VILLARD 	} else {
5412439e4bfSJean-Christophe PLAGNIOL-VILLARD 		dp->tx_int = 0;
5422439e4bfSJean-Christophe PLAGNIOL-VILLARD 	}
5432439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* Tell higher level we sent this packet */
5442439e4bfSJean-Christophe PLAGNIOL-VILLARD 	uboot_push_tx_done(key, 0);
5452439e4bfSJean-Christophe PLAGNIOL-VILLARD }
5462439e4bfSJean-Christophe PLAGNIOL-VILLARD 
5472439e4bfSJean-Christophe PLAGNIOL-VILLARD /* Read the tally counters to clear them.  Called in response to a CNT */
5482439e4bfSJean-Christophe PLAGNIOL-VILLARD /* interrupt. */
5492439e4bfSJean-Christophe PLAGNIOL-VILLARD static void
5502439e4bfSJean-Christophe PLAGNIOL-VILLARD dp83902a_ClearCounters(void)
5512439e4bfSJean-Christophe PLAGNIOL-VILLARD {
5522439e4bfSJean-Christophe PLAGNIOL-VILLARD 	struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic;
553*e710185aSgoda.yusuke 	u8 *base = dp->base;
554*e710185aSgoda.yusuke 	u8 cnt1, cnt2, cnt3;
5552439e4bfSJean-Christophe PLAGNIOL-VILLARD 
5562439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DP_IN(base, DP_FER, cnt1);
5572439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DP_IN(base, DP_CER, cnt2);
5582439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DP_IN(base, DP_MISSED, cnt3);
5592439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DP_OUT(base, DP_ISR, DP_ISR_CNT);
5602439e4bfSJean-Christophe PLAGNIOL-VILLARD }
5612439e4bfSJean-Christophe PLAGNIOL-VILLARD 
5622439e4bfSJean-Christophe PLAGNIOL-VILLARD /* Deal with an overflow condition.  This code follows the procedure set */
5632439e4bfSJean-Christophe PLAGNIOL-VILLARD /* out in section 7.0 of the datasheet. */
5642439e4bfSJean-Christophe PLAGNIOL-VILLARD static void
5652439e4bfSJean-Christophe PLAGNIOL-VILLARD dp83902a_Overflow(void)
5662439e4bfSJean-Christophe PLAGNIOL-VILLARD {
5672439e4bfSJean-Christophe PLAGNIOL-VILLARD 	struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *)&nic;
568*e710185aSgoda.yusuke 	u8 *base = dp->base;
569*e710185aSgoda.yusuke 	u8 isr;
5702439e4bfSJean-Christophe PLAGNIOL-VILLARD 
5712439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* Issue a stop command and wait 1.6ms for it to complete. */
5722439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DP_OUT(base, DP_CR, DP_CR_STOP | DP_CR_NODMA);
5732439e4bfSJean-Christophe PLAGNIOL-VILLARD 	CYGACC_CALL_IF_DELAY_US(1600);
5742439e4bfSJean-Christophe PLAGNIOL-VILLARD 
5752439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* Clear the remote byte counter registers. */
5762439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DP_OUT(base, DP_RBCL, 0);
5772439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DP_OUT(base, DP_RBCH, 0);
5782439e4bfSJean-Christophe PLAGNIOL-VILLARD 
5792439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* Enter loopback mode while we clear the buffer. */
5802439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DP_OUT(base, DP_TCR, DP_TCR_LOCAL);
5812439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DP_OUT(base, DP_CR, DP_CR_START | DP_CR_NODMA);
5822439e4bfSJean-Christophe PLAGNIOL-VILLARD 
5832439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* Read in as many packets as we can and acknowledge any and receive */
5842439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* interrupts.  Since the buffer has overflowed, a receive event of */
5852439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* some kind will have occured. */
5862439e4bfSJean-Christophe PLAGNIOL-VILLARD 	dp83902a_RxEvent();
5872439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DP_OUT(base, DP_ISR, DP_ISR_RxP|DP_ISR_RxE);
5882439e4bfSJean-Christophe PLAGNIOL-VILLARD 
5892439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* Clear the overflow condition and leave loopback mode. */
5902439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DP_OUT(base, DP_ISR, DP_ISR_OFLW);
5912439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DP_OUT(base, DP_TCR, DP_TCR_NORMAL);
5922439e4bfSJean-Christophe PLAGNIOL-VILLARD 
5932439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* If a transmit command was issued, but no transmit event has occured, */
5942439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* restart it here. */
5952439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DP_IN(base, DP_ISR, isr);
5962439e4bfSJean-Christophe PLAGNIOL-VILLARD 	if (dp->tx_started && !(isr & (DP_ISR_TxP|DP_ISR_TxE))) {
5972439e4bfSJean-Christophe PLAGNIOL-VILLARD 		DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_TXPKT | DP_CR_START);
5982439e4bfSJean-Christophe PLAGNIOL-VILLARD 	}
5992439e4bfSJean-Christophe PLAGNIOL-VILLARD }
6002439e4bfSJean-Christophe PLAGNIOL-VILLARD 
6012439e4bfSJean-Christophe PLAGNIOL-VILLARD static void
6022439e4bfSJean-Christophe PLAGNIOL-VILLARD dp83902a_poll(void)
6032439e4bfSJean-Christophe PLAGNIOL-VILLARD {
6042439e4bfSJean-Christophe PLAGNIOL-VILLARD 	struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic;
605*e710185aSgoda.yusuke 	u8 *base = dp->base;
606*e710185aSgoda.yusuke 	u8 isr;
6072439e4bfSJean-Christophe PLAGNIOL-VILLARD 
6082439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_PAGE0 | DP_CR_START);
6092439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DP_IN(base, DP_ISR, isr);
6102439e4bfSJean-Christophe PLAGNIOL-VILLARD 	while (0 != isr) {
6112439e4bfSJean-Christophe PLAGNIOL-VILLARD 		/* The CNT interrupt triggers when the MSB of one of the error */
6122439e4bfSJean-Christophe PLAGNIOL-VILLARD 		/* counters is set.  We don't much care about these counters, but */
6132439e4bfSJean-Christophe PLAGNIOL-VILLARD 		/* we should read their values to reset them. */
6142439e4bfSJean-Christophe PLAGNIOL-VILLARD 		if (isr & DP_ISR_CNT) {
6152439e4bfSJean-Christophe PLAGNIOL-VILLARD 			dp83902a_ClearCounters();
6162439e4bfSJean-Christophe PLAGNIOL-VILLARD 		}
6172439e4bfSJean-Christophe PLAGNIOL-VILLARD 		/* Check for overflow.  It's a special case, since there's a */
6182439e4bfSJean-Christophe PLAGNIOL-VILLARD 		/* particular procedure that must be followed to get back into */
6192439e4bfSJean-Christophe PLAGNIOL-VILLARD 		/* a running state.a */
6202439e4bfSJean-Christophe PLAGNIOL-VILLARD 		if (isr & DP_ISR_OFLW) {
6212439e4bfSJean-Christophe PLAGNIOL-VILLARD 			dp83902a_Overflow();
6222439e4bfSJean-Christophe PLAGNIOL-VILLARD 		} else {
6232439e4bfSJean-Christophe PLAGNIOL-VILLARD 			/* Other kinds of interrupts can be acknowledged simply by */
6242439e4bfSJean-Christophe PLAGNIOL-VILLARD 			/* clearing the relevant bits of the ISR.  Do that now, then */
6252439e4bfSJean-Christophe PLAGNIOL-VILLARD 			/* handle the interrupts we care about. */
6262439e4bfSJean-Christophe PLAGNIOL-VILLARD 			DP_OUT(base, DP_ISR, isr);      /* Clear set bits */
6272439e4bfSJean-Christophe PLAGNIOL-VILLARD 			if (!dp->running) break;	/* Is this necessary? */
6282439e4bfSJean-Christophe PLAGNIOL-VILLARD 			/* Check for tx_started on TX event since these may happen */
6292439e4bfSJean-Christophe PLAGNIOL-VILLARD 			/* spuriously it seems. */
6302439e4bfSJean-Christophe PLAGNIOL-VILLARD 			if (isr & (DP_ISR_TxP|DP_ISR_TxE) && dp->tx_started) {
6312439e4bfSJean-Christophe PLAGNIOL-VILLARD 				dp83902a_TxEvent();
6322439e4bfSJean-Christophe PLAGNIOL-VILLARD 			}
6332439e4bfSJean-Christophe PLAGNIOL-VILLARD 			if (isr & (DP_ISR_RxP|DP_ISR_RxE)) {
6342439e4bfSJean-Christophe PLAGNIOL-VILLARD 				dp83902a_RxEvent();
6352439e4bfSJean-Christophe PLAGNIOL-VILLARD 			}
6362439e4bfSJean-Christophe PLAGNIOL-VILLARD 		}
6372439e4bfSJean-Christophe PLAGNIOL-VILLARD 		DP_IN(base, DP_ISR, isr);
6382439e4bfSJean-Christophe PLAGNIOL-VILLARD 	}
6392439e4bfSJean-Christophe PLAGNIOL-VILLARD }
6402439e4bfSJean-Christophe PLAGNIOL-VILLARD 
6412439e4bfSJean-Christophe PLAGNIOL-VILLARD /* find prom (taken from pc_net_cs.c from Linux) */
6422439e4bfSJean-Christophe PLAGNIOL-VILLARD 
6432439e4bfSJean-Christophe PLAGNIOL-VILLARD #include "8390.h"
644*e710185aSgoda.yusuke /*
6452439e4bfSJean-Christophe PLAGNIOL-VILLARD typedef struct hw_info_t {
6462439e4bfSJean-Christophe PLAGNIOL-VILLARD 	u_int	offset;
6472439e4bfSJean-Christophe PLAGNIOL-VILLARD 	u_char	a0, a1, a2;
6482439e4bfSJean-Christophe PLAGNIOL-VILLARD 	u_int	flags;
6492439e4bfSJean-Christophe PLAGNIOL-VILLARD } hw_info_t;
650*e710185aSgoda.yusuke */
6512439e4bfSJean-Christophe PLAGNIOL-VILLARD #define DELAY_OUTPUT	0x01
6522439e4bfSJean-Christophe PLAGNIOL-VILLARD #define HAS_MISC_REG	0x02
6532439e4bfSJean-Christophe PLAGNIOL-VILLARD #define USE_BIG_BUF	0x04
6542439e4bfSJean-Christophe PLAGNIOL-VILLARD #define HAS_IBM_MISC	0x08
6552439e4bfSJean-Christophe PLAGNIOL-VILLARD #define IS_DL10019	0x10
6562439e4bfSJean-Christophe PLAGNIOL-VILLARD #define IS_DL10022	0x20
6572439e4bfSJean-Christophe PLAGNIOL-VILLARD #define HAS_MII		0x40
6582439e4bfSJean-Christophe PLAGNIOL-VILLARD #define USE_SHMEM	0x80	/* autodetected */
6592439e4bfSJean-Christophe PLAGNIOL-VILLARD 
6602439e4bfSJean-Christophe PLAGNIOL-VILLARD #define AM79C9XX_HOME_PHY	0x00006B90  /* HomePNA PHY */
6612439e4bfSJean-Christophe PLAGNIOL-VILLARD #define AM79C9XX_ETH_PHY	0x00006B70  /* 10baseT PHY */
6622439e4bfSJean-Christophe PLAGNIOL-VILLARD #define MII_PHYID_REV_MASK	0xfffffff0
6632439e4bfSJean-Christophe PLAGNIOL-VILLARD #define MII_PHYID_REG1		0x02
6642439e4bfSJean-Christophe PLAGNIOL-VILLARD #define MII_PHYID_REG2		0x03
6652439e4bfSJean-Christophe PLAGNIOL-VILLARD 
6662439e4bfSJean-Christophe PLAGNIOL-VILLARD static hw_info_t hw_info[] = {
6672439e4bfSJean-Christophe PLAGNIOL-VILLARD 	{ /* Accton EN2212 */ 0x0ff0, 0x00, 0x00, 0xe8, DELAY_OUTPUT },
6682439e4bfSJean-Christophe PLAGNIOL-VILLARD 	{ /* Allied Telesis LA-PCM */ 0x0ff0, 0x00, 0x00, 0xf4, 0 },
6692439e4bfSJean-Christophe PLAGNIOL-VILLARD 	{ /* APEX MultiCard */ 0x03f4, 0x00, 0x20, 0xe5, 0 },
6702439e4bfSJean-Christophe PLAGNIOL-VILLARD 	{ /* ASANTE FriendlyNet */ 0x4910, 0x00, 0x00, 0x94,
6712439e4bfSJean-Christophe PLAGNIOL-VILLARD 	  DELAY_OUTPUT | HAS_IBM_MISC },
6722439e4bfSJean-Christophe PLAGNIOL-VILLARD 	{ /* Danpex EN-6200P2 */ 0x0110, 0x00, 0x40, 0xc7, 0 },
6732439e4bfSJean-Christophe PLAGNIOL-VILLARD 	{ /* DataTrek NetCard */ 0x0ff0, 0x00, 0x20, 0xe8, 0 },
6742439e4bfSJean-Christophe PLAGNIOL-VILLARD 	{ /* Dayna CommuniCard E */ 0x0110, 0x00, 0x80, 0x19, 0 },
6752439e4bfSJean-Christophe PLAGNIOL-VILLARD 	{ /* D-Link DE-650 */ 0x0040, 0x00, 0x80, 0xc8, 0 },
6762439e4bfSJean-Christophe PLAGNIOL-VILLARD 	{ /* EP-210 Ethernet */ 0x0110, 0x00, 0x40, 0x33, 0 },
6772439e4bfSJean-Christophe PLAGNIOL-VILLARD 	{ /* EP4000 Ethernet */ 0x01c0, 0x00, 0x00, 0xb4, 0 },
6782439e4bfSJean-Christophe PLAGNIOL-VILLARD 	{ /* Epson EEN10B */ 0x0ff0, 0x00, 0x00, 0x48,
6792439e4bfSJean-Christophe PLAGNIOL-VILLARD 	  HAS_MISC_REG | HAS_IBM_MISC },
6802439e4bfSJean-Christophe PLAGNIOL-VILLARD 	{ /* ELECOM Laneed LD-CDWA */ 0xb8, 0x08, 0x00, 0x42, 0 },
6812439e4bfSJean-Christophe PLAGNIOL-VILLARD 	{ /* Hypertec Ethernet */ 0x01c0, 0x00, 0x40, 0x4c, 0 },
6822439e4bfSJean-Christophe PLAGNIOL-VILLARD 	{ /* IBM CCAE */ 0x0ff0, 0x08, 0x00, 0x5a,
6832439e4bfSJean-Christophe PLAGNIOL-VILLARD 	  HAS_MISC_REG | HAS_IBM_MISC },
6842439e4bfSJean-Christophe PLAGNIOL-VILLARD 	{ /* IBM CCAE */ 0x0ff0, 0x00, 0x04, 0xac,
6852439e4bfSJean-Christophe PLAGNIOL-VILLARD 	  HAS_MISC_REG | HAS_IBM_MISC },
6862439e4bfSJean-Christophe PLAGNIOL-VILLARD 	{ /* IBM CCAE */ 0x0ff0, 0x00, 0x06, 0x29,
6872439e4bfSJean-Christophe PLAGNIOL-VILLARD 	  HAS_MISC_REG | HAS_IBM_MISC },
6882439e4bfSJean-Christophe PLAGNIOL-VILLARD 	{ /* IBM FME */ 0x0374, 0x08, 0x00, 0x5a,
6892439e4bfSJean-Christophe PLAGNIOL-VILLARD 	  HAS_MISC_REG | HAS_IBM_MISC },
6902439e4bfSJean-Christophe PLAGNIOL-VILLARD 	{ /* IBM FME */ 0x0374, 0x00, 0x04, 0xac,
6912439e4bfSJean-Christophe PLAGNIOL-VILLARD 	  HAS_MISC_REG | HAS_IBM_MISC },
6922439e4bfSJean-Christophe PLAGNIOL-VILLARD 	{ /* Kansai KLA-PCM/T */ 0x0ff0, 0x00, 0x60, 0x87,
6932439e4bfSJean-Christophe PLAGNIOL-VILLARD 	  HAS_MISC_REG | HAS_IBM_MISC },
6942439e4bfSJean-Christophe PLAGNIOL-VILLARD 	{ /* NSC DP83903 */ 0x0374, 0x08, 0x00, 0x17,
6952439e4bfSJean-Christophe PLAGNIOL-VILLARD 	  HAS_MISC_REG | HAS_IBM_MISC },
6962439e4bfSJean-Christophe PLAGNIOL-VILLARD 	{ /* NSC DP83903 */ 0x0374, 0x00, 0xc0, 0xa8,
6972439e4bfSJean-Christophe PLAGNIOL-VILLARD 	  HAS_MISC_REG | HAS_IBM_MISC },
6982439e4bfSJean-Christophe PLAGNIOL-VILLARD 	{ /* NSC DP83903 */ 0x0374, 0x00, 0xa0, 0xb0,
6992439e4bfSJean-Christophe PLAGNIOL-VILLARD 	  HAS_MISC_REG | HAS_IBM_MISC },
7002439e4bfSJean-Christophe PLAGNIOL-VILLARD 	{ /* NSC DP83903 */ 0x0198, 0x00, 0x20, 0xe0,
7012439e4bfSJean-Christophe PLAGNIOL-VILLARD 	  HAS_MISC_REG | HAS_IBM_MISC },
7022439e4bfSJean-Christophe PLAGNIOL-VILLARD 	{ /* I-O DATA PCLA/T */ 0x0ff0, 0x00, 0xa0, 0xb0, 0 },
7032439e4bfSJean-Christophe PLAGNIOL-VILLARD 	{ /* Katron PE-520 */ 0x0110, 0x00, 0x40, 0xf6, 0 },
7042439e4bfSJean-Christophe PLAGNIOL-VILLARD 	{ /* Kingston KNE-PCM/x */ 0x0ff0, 0x00, 0xc0, 0xf0,
7052439e4bfSJean-Christophe PLAGNIOL-VILLARD 	  HAS_MISC_REG | HAS_IBM_MISC },
7062439e4bfSJean-Christophe PLAGNIOL-VILLARD 	{ /* Kingston KNE-PCM/x */ 0x0ff0, 0xe2, 0x0c, 0x0f,
7072439e4bfSJean-Christophe PLAGNIOL-VILLARD 	  HAS_MISC_REG | HAS_IBM_MISC },
7082439e4bfSJean-Christophe PLAGNIOL-VILLARD 	{ /* Kingston KNE-PC2 */ 0x0180, 0x00, 0xc0, 0xf0, 0 },
7092439e4bfSJean-Christophe PLAGNIOL-VILLARD 	{ /* Maxtech PCN2000 */ 0x5000, 0x00, 0x00, 0xe8, 0 },
7102439e4bfSJean-Christophe PLAGNIOL-VILLARD 	{ /* NDC Instant-Link */ 0x003a, 0x00, 0x80, 0xc6, 0 },
7112439e4bfSJean-Christophe PLAGNIOL-VILLARD 	{ /* NE2000 Compatible */ 0x0ff0, 0x00, 0xa0, 0x0c, 0 },
7122439e4bfSJean-Christophe PLAGNIOL-VILLARD 	{ /* Network General Sniffer */ 0x0ff0, 0x00, 0x00, 0x65,
7132439e4bfSJean-Christophe PLAGNIOL-VILLARD 	  HAS_MISC_REG | HAS_IBM_MISC },
7142439e4bfSJean-Christophe PLAGNIOL-VILLARD 	{ /* Panasonic VEL211 */ 0x0ff0, 0x00, 0x80, 0x45,
7152439e4bfSJean-Christophe PLAGNIOL-VILLARD 	  HAS_MISC_REG | HAS_IBM_MISC },
7162439e4bfSJean-Christophe PLAGNIOL-VILLARD 	{ /* PreMax PE-200 */ 0x07f0, 0x00, 0x20, 0xe0, 0 },
7172439e4bfSJean-Christophe PLAGNIOL-VILLARD 	{ /* RPTI EP400 */ 0x0110, 0x00, 0x40, 0x95, 0 },
7182439e4bfSJean-Christophe PLAGNIOL-VILLARD 	{ /* SCM Ethernet */ 0x0ff0, 0x00, 0x20, 0xcb, 0 },
7192439e4bfSJean-Christophe PLAGNIOL-VILLARD 	{ /* Socket EA */ 0x4000, 0x00, 0xc0, 0x1b,
7202439e4bfSJean-Christophe PLAGNIOL-VILLARD 	  DELAY_OUTPUT | HAS_MISC_REG | USE_BIG_BUF },
7212439e4bfSJean-Christophe PLAGNIOL-VILLARD 	{ /* Socket LP-E CF+ */ 0x01c0, 0x00, 0xc0, 0x1b, 0 },
7222439e4bfSJean-Christophe PLAGNIOL-VILLARD 	{ /* SuperSocket RE450T */ 0x0110, 0x00, 0xe0, 0x98, 0 },
7232439e4bfSJean-Christophe PLAGNIOL-VILLARD 	{ /* Volktek NPL-402CT */ 0x0060, 0x00, 0x40, 0x05, 0 },
7242439e4bfSJean-Christophe PLAGNIOL-VILLARD 	{ /* NEC PC-9801N-J12 */ 0x0ff0, 0x00, 0x00, 0x4c, 0 },
7252439e4bfSJean-Christophe PLAGNIOL-VILLARD 	{ /* PCMCIA Technology OEM */ 0x01c8, 0x00, 0xa0, 0x0c, 0 },
7262439e4bfSJean-Christophe PLAGNIOL-VILLARD 	{ /* Qemu */ 0x0, 0x52, 0x54, 0x00, 0 }
7272439e4bfSJean-Christophe PLAGNIOL-VILLARD };
7282439e4bfSJean-Christophe PLAGNIOL-VILLARD 
7292439e4bfSJean-Christophe PLAGNIOL-VILLARD #define NR_INFO		(sizeof(hw_info)/sizeof(hw_info_t))
7302439e4bfSJean-Christophe PLAGNIOL-VILLARD 
7312439e4bfSJean-Christophe PLAGNIOL-VILLARD static hw_info_t default_info = { 0, 0, 0, 0, 0 };
7322439e4bfSJean-Christophe PLAGNIOL-VILLARD 
733*e710185aSgoda.yusuke u8 dev_addr[6];
7342439e4bfSJean-Christophe PLAGNIOL-VILLARD 
7352439e4bfSJean-Christophe PLAGNIOL-VILLARD #define PCNET_CMD	0x00
7362439e4bfSJean-Christophe PLAGNIOL-VILLARD #define PCNET_DATAPORT	0x10	/* NatSemi-defined port window offset. */
7372439e4bfSJean-Christophe PLAGNIOL-VILLARD #define PCNET_RESET	0x1f	/* Issue a read to reset, a write to clear. */
7382439e4bfSJean-Christophe PLAGNIOL-VILLARD #define PCNET_MISC	0x18	/* For IBM CCAE and Socket EA cards */
7392439e4bfSJean-Christophe PLAGNIOL-VILLARD 
740*e710185aSgoda.yusuke u32 nic_base;
7412439e4bfSJean-Christophe PLAGNIOL-VILLARD 
7422439e4bfSJean-Christophe PLAGNIOL-VILLARD /* U-boot specific routines */
743*e710185aSgoda.yusuke static u8 *pbuf = NULL;
7442439e4bfSJean-Christophe PLAGNIOL-VILLARD 
7452439e4bfSJean-Christophe PLAGNIOL-VILLARD static int pkey = -1;
7462439e4bfSJean-Christophe PLAGNIOL-VILLARD static int initialized=0;
7472439e4bfSJean-Christophe PLAGNIOL-VILLARD 
7482439e4bfSJean-Christophe PLAGNIOL-VILLARD void uboot_push_packet_len(int len) {
7492439e4bfSJean-Christophe PLAGNIOL-VILLARD 	PRINTK("pushed len = %d\n", len);
7502439e4bfSJean-Christophe PLAGNIOL-VILLARD 	if (len>=2000) {
7512439e4bfSJean-Christophe PLAGNIOL-VILLARD 		printf("NE2000: packet too big\n");
7522439e4bfSJean-Christophe PLAGNIOL-VILLARD 		return;
7532439e4bfSJean-Christophe PLAGNIOL-VILLARD 	}
7542439e4bfSJean-Christophe PLAGNIOL-VILLARD 	dp83902a_recv(&pbuf[0], len);
7552439e4bfSJean-Christophe PLAGNIOL-VILLARD 
7562439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/*Just pass it to the upper layer*/
7572439e4bfSJean-Christophe PLAGNIOL-VILLARD 	NetReceive(&pbuf[0], len);
7582439e4bfSJean-Christophe PLAGNIOL-VILLARD }
7592439e4bfSJean-Christophe PLAGNIOL-VILLARD 
7602439e4bfSJean-Christophe PLAGNIOL-VILLARD void uboot_push_tx_done(int key, int val) {
7612439e4bfSJean-Christophe PLAGNIOL-VILLARD 	PRINTK("pushed key = %d\n", key);
7622439e4bfSJean-Christophe PLAGNIOL-VILLARD 	pkey = key;
7632439e4bfSJean-Christophe PLAGNIOL-VILLARD }
7642439e4bfSJean-Christophe PLAGNIOL-VILLARD 
7652439e4bfSJean-Christophe PLAGNIOL-VILLARD int eth_init(bd_t *bd) {
7662439e4bfSJean-Christophe PLAGNIOL-VILLARD 	static hw_info_t * r;
7672439e4bfSJean-Christophe PLAGNIOL-VILLARD 	char ethaddr[20];
7682439e4bfSJean-Christophe PLAGNIOL-VILLARD 
7692439e4bfSJean-Christophe PLAGNIOL-VILLARD 	PRINTK("### eth_init\n");
7702439e4bfSJean-Christophe PLAGNIOL-VILLARD 
7712439e4bfSJean-Christophe PLAGNIOL-VILLARD 	if (!pbuf) {
7722439e4bfSJean-Christophe PLAGNIOL-VILLARD 		pbuf = malloc(2000);
7732439e4bfSJean-Christophe PLAGNIOL-VILLARD 		if (!pbuf) {
7742439e4bfSJean-Christophe PLAGNIOL-VILLARD 			printf("Cannot allocate rx buffer\n");
7752439e4bfSJean-Christophe PLAGNIOL-VILLARD 			return -1;
7762439e4bfSJean-Christophe PLAGNIOL-VILLARD 		}
7772439e4bfSJean-Christophe PLAGNIOL-VILLARD 	}
7782439e4bfSJean-Christophe PLAGNIOL-VILLARD 
7792439e4bfSJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_DRIVER_NE2000_CCR
7802439e4bfSJean-Christophe PLAGNIOL-VILLARD 	{
781*e710185aSgoda.yusuke 		vu_char *p =  (vu_char *) CONFIG_DRIVER_NE2000_CCR;
7822439e4bfSJean-Christophe PLAGNIOL-VILLARD 
7832439e4bfSJean-Christophe PLAGNIOL-VILLARD 		PRINTK("CCR before is %x\n", *p);
7842439e4bfSJean-Christophe PLAGNIOL-VILLARD 		*p = CONFIG_DRIVER_NE2000_VAL;
7852439e4bfSJean-Christophe PLAGNIOL-VILLARD 		PRINTK("CCR after is %x\n", *p);
7862439e4bfSJean-Christophe PLAGNIOL-VILLARD 	}
7872439e4bfSJean-Christophe PLAGNIOL-VILLARD #endif
7882439e4bfSJean-Christophe PLAGNIOL-VILLARD 
7892439e4bfSJean-Christophe PLAGNIOL-VILLARD 	nic_base = CONFIG_DRIVER_NE2000_BASE;
790*e710185aSgoda.yusuke 	nic.base = (u8 *) CONFIG_DRIVER_NE2000_BASE;
7912439e4bfSJean-Christophe PLAGNIOL-VILLARD 
792*e710185aSgoda.yusuke 	r = get_prom(dev_addr);
7932439e4bfSJean-Christophe PLAGNIOL-VILLARD 	if (!r)
7942439e4bfSJean-Christophe PLAGNIOL-VILLARD 		return -1;
7952439e4bfSJean-Christophe PLAGNIOL-VILLARD 
7962439e4bfSJean-Christophe PLAGNIOL-VILLARD 	sprintf (ethaddr, "%02X:%02X:%02X:%02X:%02X:%02X",
7972439e4bfSJean-Christophe PLAGNIOL-VILLARD 		 dev_addr[0], dev_addr[1],
7982439e4bfSJean-Christophe PLAGNIOL-VILLARD 		 dev_addr[2], dev_addr[3],
7992439e4bfSJean-Christophe PLAGNIOL-VILLARD 		 dev_addr[4], dev_addr[5]) ;
8002439e4bfSJean-Christophe PLAGNIOL-VILLARD 	PRINTK("Set environment from HW MAC addr = \"%s\"\n", ethaddr);
8012439e4bfSJean-Christophe PLAGNIOL-VILLARD 	setenv ("ethaddr", ethaddr);
8022439e4bfSJean-Christophe PLAGNIOL-VILLARD 
8032439e4bfSJean-Christophe PLAGNIOL-VILLARD 	nic.data = nic.base + DP_DATA;
804*e710185aSgoda.yusuke 	nic.tx_buf1 = START_PG;
805*e710185aSgoda.yusuke 	nic.tx_buf2 = START_PG2;
806*e710185aSgoda.yusuke 	nic.rx_buf_start = RX_START;
807*e710185aSgoda.yusuke 	nic.rx_buf_end = RX_END;
8082439e4bfSJean-Christophe PLAGNIOL-VILLARD 
8092439e4bfSJean-Christophe PLAGNIOL-VILLARD 	if (dp83902a_init() == false)
8102439e4bfSJean-Christophe PLAGNIOL-VILLARD 		return -1;
811*e710185aSgoda.yusuke 
8122439e4bfSJean-Christophe PLAGNIOL-VILLARD 	dp83902a_start(dev_addr);
8132439e4bfSJean-Christophe PLAGNIOL-VILLARD 	initialized=1;
814*e710185aSgoda.yusuke 
8152439e4bfSJean-Christophe PLAGNIOL-VILLARD 	return 0;
8162439e4bfSJean-Christophe PLAGNIOL-VILLARD }
8172439e4bfSJean-Christophe PLAGNIOL-VILLARD 
8182439e4bfSJean-Christophe PLAGNIOL-VILLARD void eth_halt() {
819*e710185aSgoda.yusuke 
8202439e4bfSJean-Christophe PLAGNIOL-VILLARD 	PRINTK("### eth_halt\n");
8212439e4bfSJean-Christophe PLAGNIOL-VILLARD 	if(initialized)
8222439e4bfSJean-Christophe PLAGNIOL-VILLARD 		dp83902a_stop();
8232439e4bfSJean-Christophe PLAGNIOL-VILLARD 	initialized=0;
8242439e4bfSJean-Christophe PLAGNIOL-VILLARD }
8252439e4bfSJean-Christophe PLAGNIOL-VILLARD 
8262439e4bfSJean-Christophe PLAGNIOL-VILLARD int eth_rx() {
8272439e4bfSJean-Christophe PLAGNIOL-VILLARD 	dp83902a_poll();
8282439e4bfSJean-Christophe PLAGNIOL-VILLARD 	return 1;
8292439e4bfSJean-Christophe PLAGNIOL-VILLARD }
8302439e4bfSJean-Christophe PLAGNIOL-VILLARD 
8312439e4bfSJean-Christophe PLAGNIOL-VILLARD int eth_send(volatile void *packet, int length) {
8322439e4bfSJean-Christophe PLAGNIOL-VILLARD 	int tmo;
8332439e4bfSJean-Christophe PLAGNIOL-VILLARD 
8342439e4bfSJean-Christophe PLAGNIOL-VILLARD 	PRINTK("### eth_send\n");
8352439e4bfSJean-Christophe PLAGNIOL-VILLARD 
8362439e4bfSJean-Christophe PLAGNIOL-VILLARD 	pkey = -1;
8372439e4bfSJean-Christophe PLAGNIOL-VILLARD 
838*e710185aSgoda.yusuke 	dp83902a_send((u8 *) packet, length, 666);
8392439e4bfSJean-Christophe PLAGNIOL-VILLARD 	tmo = get_timer (0) + TOUT * CFG_HZ;
8402439e4bfSJean-Christophe PLAGNIOL-VILLARD 	while(1) {
8412439e4bfSJean-Christophe PLAGNIOL-VILLARD 		dp83902a_poll();
8422439e4bfSJean-Christophe PLAGNIOL-VILLARD 		if (pkey != -1) {
8432439e4bfSJean-Christophe PLAGNIOL-VILLARD 			PRINTK("Packet sucesfully sent\n");
8442439e4bfSJean-Christophe PLAGNIOL-VILLARD 			return 0;
8452439e4bfSJean-Christophe PLAGNIOL-VILLARD 		}
8462439e4bfSJean-Christophe PLAGNIOL-VILLARD 		if (get_timer (0) >= tmo) {
8472439e4bfSJean-Christophe PLAGNIOL-VILLARD 			printf("transmission error (timoeut)\n");
8482439e4bfSJean-Christophe PLAGNIOL-VILLARD 			return 0;
8492439e4bfSJean-Christophe PLAGNIOL-VILLARD 		}
8502439e4bfSJean-Christophe PLAGNIOL-VILLARD 
8512439e4bfSJean-Christophe PLAGNIOL-VILLARD 	}
8522439e4bfSJean-Christophe PLAGNIOL-VILLARD 	return 0;
8532439e4bfSJean-Christophe PLAGNIOL-VILLARD }
8542439e4bfSJean-Christophe PLAGNIOL-VILLARD #endif
855