xref: /openbmc/u-boot/drivers/net/dm9000x.c (revision 0e38c938)
12439e4bfSJean-Christophe PLAGNIOL-VILLARD /*
22439e4bfSJean-Christophe PLAGNIOL-VILLARD   dm9000.c: Version 1.2 12/15/2003
32439e4bfSJean-Christophe PLAGNIOL-VILLARD 
42439e4bfSJean-Christophe PLAGNIOL-VILLARD 	A Davicom DM9000 ISA NIC fast Ethernet driver for Linux.
52439e4bfSJean-Christophe PLAGNIOL-VILLARD 	Copyright (C) 1997  Sten Wang
62439e4bfSJean-Christophe PLAGNIOL-VILLARD 
72439e4bfSJean-Christophe PLAGNIOL-VILLARD 	This program is free software; you can redistribute it and/or
82439e4bfSJean-Christophe PLAGNIOL-VILLARD 	modify it under the terms of the GNU General Public License
92439e4bfSJean-Christophe PLAGNIOL-VILLARD 	as published by the Free Software Foundation; either version 2
102439e4bfSJean-Christophe PLAGNIOL-VILLARD 	of the License, or (at your option) any later version.
112439e4bfSJean-Christophe PLAGNIOL-VILLARD 
122439e4bfSJean-Christophe PLAGNIOL-VILLARD 	This program is distributed in the hope that it will be useful,
132439e4bfSJean-Christophe PLAGNIOL-VILLARD 	but WITHOUT ANY WARRANTY; without even the implied warranty of
142439e4bfSJean-Christophe PLAGNIOL-VILLARD 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
152439e4bfSJean-Christophe PLAGNIOL-VILLARD 	GNU General Public License for more details.
162439e4bfSJean-Christophe PLAGNIOL-VILLARD 
172439e4bfSJean-Christophe PLAGNIOL-VILLARD   (C)Copyright 1997-1998 DAVICOM Semiconductor,Inc. All Rights Reserved.
182439e4bfSJean-Christophe PLAGNIOL-VILLARD 
192439e4bfSJean-Christophe PLAGNIOL-VILLARD V0.11	06/20/2001	REG_0A bit3=1, default enable BP with DA match
202439e4bfSJean-Christophe PLAGNIOL-VILLARD 	06/22/2001	Support DM9801 progrmming
212439e4bfSJean-Christophe PLAGNIOL-VILLARD 			E3: R25 = ((R24 + NF) & 0x00ff) | 0xf000
222439e4bfSJean-Christophe PLAGNIOL-VILLARD 			E4: R25 = ((R24 + NF) & 0x00ff) | 0xc200
232439e4bfSJean-Christophe PLAGNIOL-VILLARD 		R17 = (R17 & 0xfff0) | NF + 3
242439e4bfSJean-Christophe PLAGNIOL-VILLARD 			E5: R25 = ((R24 + NF - 3) & 0x00ff) | 0xc200
252439e4bfSJean-Christophe PLAGNIOL-VILLARD 		R17 = (R17 & 0xfff0) | NF
262439e4bfSJean-Christophe PLAGNIOL-VILLARD 
272439e4bfSJean-Christophe PLAGNIOL-VILLARD v1.00			modify by simon 2001.9.5
282439e4bfSJean-Christophe PLAGNIOL-VILLARD 	                change for kernel 2.4.x
292439e4bfSJean-Christophe PLAGNIOL-VILLARD 
302439e4bfSJean-Christophe PLAGNIOL-VILLARD v1.1   11/09/2001	fix force mode bug
312439e4bfSJean-Christophe PLAGNIOL-VILLARD 
322439e4bfSJean-Christophe PLAGNIOL-VILLARD v1.2   03/18/2003       Weilun Huang <weilun_huang@davicom.com.tw>:
332439e4bfSJean-Christophe PLAGNIOL-VILLARD 			Fixed phy reset.
342439e4bfSJean-Christophe PLAGNIOL-VILLARD 			Added tx/rx 32 bit mode.
352439e4bfSJean-Christophe PLAGNIOL-VILLARD 			Cleaned up for kernel merge.
362439e4bfSJean-Christophe PLAGNIOL-VILLARD 
372439e4bfSJean-Christophe PLAGNIOL-VILLARD --------------------------------------
382439e4bfSJean-Christophe PLAGNIOL-VILLARD 
39a101361bSRemy Bohmer        12/15/2003       Initial port to u-boot by
40a101361bSRemy Bohmer        			Sascha Hauer <saschahauer@web.de>
41a101361bSRemy Bohmer 
42a101361bSRemy Bohmer        06/03/2008	Remy Bohmer <linux@bohmer.net>
43850ba755SRemy Bohmer 			- Fixed the driver to work with DM9000A.
44850ba755SRemy Bohmer 			  (check on ISR receive status bit before reading the
45850ba755SRemy Bohmer 			  FIFO as described in DM9000 programming guide and
46850ba755SRemy Bohmer 			  application notes)
47a101361bSRemy Bohmer 			- Added autodetect of databus width.
48134e2662SRemy Bohmer 			- Made debug code compile again.
49acba3184SRemy Bohmer 			- Adapt eth_send such that it matches the DM9000*
50acba3184SRemy Bohmer 			  application notes. Needed to make it work properly
51acba3184SRemy Bohmer 			  for DM9000A.
52fbcb7eceSRemy Bohmer 			- Adapted reset procedure to match DM9000 application
53fbcb7eceSRemy Bohmer 			  notes (i.e. double reset)
5498291e2eSRemy Bohmer 			- some minor code cleanups
55a101361bSRemy Bohmer 			These changes are tested with DM9000{A,EP,E} together
56a101361bSRemy Bohmer 			with a 200MHz Atmel AT91SAM92161 core
572439e4bfSJean-Christophe PLAGNIOL-VILLARD 
582439e4bfSJean-Christophe PLAGNIOL-VILLARD TODO: Homerun NIC and longrun NIC are not functional, only internal at the
592439e4bfSJean-Christophe PLAGNIOL-VILLARD       moment.
602439e4bfSJean-Christophe PLAGNIOL-VILLARD */
612439e4bfSJean-Christophe PLAGNIOL-VILLARD 
622439e4bfSJean-Christophe PLAGNIOL-VILLARD #include <common.h>
632439e4bfSJean-Christophe PLAGNIOL-VILLARD #include <command.h>
642439e4bfSJean-Christophe PLAGNIOL-VILLARD #include <net.h>
652439e4bfSJean-Christophe PLAGNIOL-VILLARD #include <asm/io.h>
662439e4bfSJean-Christophe PLAGNIOL-VILLARD 
672439e4bfSJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_DRIVER_DM9000
682439e4bfSJean-Christophe PLAGNIOL-VILLARD 
692439e4bfSJean-Christophe PLAGNIOL-VILLARD #include "dm9000x.h"
702439e4bfSJean-Christophe PLAGNIOL-VILLARD 
712439e4bfSJean-Christophe PLAGNIOL-VILLARD /* Board/System/Debug information/definition ---------------- */
722439e4bfSJean-Christophe PLAGNIOL-VILLARD 
732439e4bfSJean-Christophe PLAGNIOL-VILLARD #define DM9801_NOISE_FLOOR	0x08
742439e4bfSJean-Christophe PLAGNIOL-VILLARD #define DM9802_NOISE_FLOOR	0x05
752439e4bfSJean-Christophe PLAGNIOL-VILLARD 
762439e4bfSJean-Christophe PLAGNIOL-VILLARD /* #define CONFIG_DM9000_DEBUG */
772439e4bfSJean-Christophe PLAGNIOL-VILLARD 
782439e4bfSJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_DM9000_DEBUG
792439e4bfSJean-Christophe PLAGNIOL-VILLARD #define DM9000_DBG(fmt,args...) printf(fmt, ##args)
80134e2662SRemy Bohmer #define DM9000_DMP_PACKET(func,packet,length)  \
81134e2662SRemy Bohmer 	do { \
82134e2662SRemy Bohmer 		int i; 							\
83134e2662SRemy Bohmer 		printf(func ": length: %d\n", length);			\
84134e2662SRemy Bohmer 		for (i = 0; i < length; i++) {				\
85134e2662SRemy Bohmer 			if (i % 8 == 0)					\
86134e2662SRemy Bohmer 				printf("\n%s: %02x: ", func, i);	\
87134e2662SRemy Bohmer 			printf("%02x ", ((unsigned char *) packet)[i]);	\
88134e2662SRemy Bohmer 		} printf("\n");						\
89134e2662SRemy Bohmer 	} while(0)
90134e2662SRemy Bohmer #else
912439e4bfSJean-Christophe PLAGNIOL-VILLARD #define DM9000_DBG(fmt,args...)
92134e2662SRemy Bohmer #define DM9000_DMP_PACKET(func,packet,length)
93134e2662SRemy Bohmer #endif
94134e2662SRemy Bohmer 
952439e4bfSJean-Christophe PLAGNIOL-VILLARD enum DM9000_PHY_mode { DM9000_10MHD = 0, DM9000_100MHD =
962439e4bfSJean-Christophe PLAGNIOL-VILLARD 	    1, DM9000_10MFD = 4, DM9000_100MFD = 5, DM9000_AUTO =
972439e4bfSJean-Christophe PLAGNIOL-VILLARD 	    8, DM9000_1M_HPNA = 0x10
982439e4bfSJean-Christophe PLAGNIOL-VILLARD };
992439e4bfSJean-Christophe PLAGNIOL-VILLARD enum DM9000_NIC_TYPE { FASTETHER_NIC = 0, HOMERUN_NIC = 1, LONGRUN_NIC = 2
1002439e4bfSJean-Christophe PLAGNIOL-VILLARD };
1012439e4bfSJean-Christophe PLAGNIOL-VILLARD 
1022439e4bfSJean-Christophe PLAGNIOL-VILLARD /* Structure/enum declaration ------------------------------- */
1032439e4bfSJean-Christophe PLAGNIOL-VILLARD typedef struct board_info {
1042439e4bfSJean-Christophe PLAGNIOL-VILLARD 	u32 runt_length_counter;	/* counter: RX length < 64byte */
1052439e4bfSJean-Christophe PLAGNIOL-VILLARD 	u32 long_length_counter;	/* counter: RX length > 1514byte */
1062439e4bfSJean-Christophe PLAGNIOL-VILLARD 	u32 reset_counter;	/* counter: RESET */
1072439e4bfSJean-Christophe PLAGNIOL-VILLARD 	u32 reset_tx_timeout;	/* RESET caused by TX Timeout */
1082439e4bfSJean-Christophe PLAGNIOL-VILLARD 	u32 reset_rx_status;	/* RESET caused by RX Statsus wrong */
1092439e4bfSJean-Christophe PLAGNIOL-VILLARD 	u16 tx_pkt_cnt;
1102439e4bfSJean-Christophe PLAGNIOL-VILLARD 	u16 queue_start_addr;
1112439e4bfSJean-Christophe PLAGNIOL-VILLARD 	u16 dbug_cnt;
1122439e4bfSJean-Christophe PLAGNIOL-VILLARD 	u8 phy_addr;
1132439e4bfSJean-Christophe PLAGNIOL-VILLARD 	u8 device_wait_reset;	/* device state */
1142439e4bfSJean-Christophe PLAGNIOL-VILLARD 	u8 nic_type;		/* NIC type */
1152439e4bfSJean-Christophe PLAGNIOL-VILLARD 	unsigned char srom[128];
116*0e38c938SRemy Bohmer 	void (*outblk)(volatile void *data_ptr, int count);
117a101361bSRemy Bohmer 	void (*inblk)(void *data_ptr, int count);
118a101361bSRemy Bohmer 	void (*rx_status)(u16 *RxStatus, u16 *RxLen);
1192439e4bfSJean-Christophe PLAGNIOL-VILLARD } board_info_t;
120a101361bSRemy Bohmer static board_info_t dm9000_info;
1212439e4bfSJean-Christophe PLAGNIOL-VILLARD 
1222439e4bfSJean-Christophe PLAGNIOL-VILLARD /* For module input parameter */
1232439e4bfSJean-Christophe PLAGNIOL-VILLARD static int media_mode = DM9000_AUTO;
1242439e4bfSJean-Christophe PLAGNIOL-VILLARD static u8 nfloor = 0;
1252439e4bfSJean-Christophe PLAGNIOL-VILLARD 
1262439e4bfSJean-Christophe PLAGNIOL-VILLARD /* function declaration ------------------------------------- */
1272439e4bfSJean-Christophe PLAGNIOL-VILLARD int eth_init(bd_t * bd);
1282439e4bfSJean-Christophe PLAGNIOL-VILLARD int eth_send(volatile void *, int);
1292439e4bfSJean-Christophe PLAGNIOL-VILLARD int eth_rx(void);
1302439e4bfSJean-Christophe PLAGNIOL-VILLARD void eth_halt(void);
1312439e4bfSJean-Christophe PLAGNIOL-VILLARD static int dm9000_probe(void);
1322439e4bfSJean-Christophe PLAGNIOL-VILLARD static u16 phy_read(int);
1332439e4bfSJean-Christophe PLAGNIOL-VILLARD static void phy_write(int, u16);
1342439e4bfSJean-Christophe PLAGNIOL-VILLARD u16 read_srom_word(int);
1352439e4bfSJean-Christophe PLAGNIOL-VILLARD static u8 DM9000_ior(int);
1362439e4bfSJean-Christophe PLAGNIOL-VILLARD static void DM9000_iow(int reg, u8 value);
1372439e4bfSJean-Christophe PLAGNIOL-VILLARD 
1382439e4bfSJean-Christophe PLAGNIOL-VILLARD /* DM9000 network board routine ---------------------------- */
1392439e4bfSJean-Christophe PLAGNIOL-VILLARD 
1402439e4bfSJean-Christophe PLAGNIOL-VILLARD #define DM9000_outb(d,r) ( *(volatile u8 *)r = d )
1412439e4bfSJean-Christophe PLAGNIOL-VILLARD #define DM9000_outw(d,r) ( *(volatile u16 *)r = d )
1422439e4bfSJean-Christophe PLAGNIOL-VILLARD #define DM9000_outl(d,r) ( *(volatile u32 *)r = d )
1432439e4bfSJean-Christophe PLAGNIOL-VILLARD #define DM9000_inb(r) (*(volatile u8 *)r)
1442439e4bfSJean-Christophe PLAGNIOL-VILLARD #define DM9000_inw(r) (*(volatile u16 *)r)
1452439e4bfSJean-Christophe PLAGNIOL-VILLARD #define DM9000_inl(r) (*(volatile u32 *)r)
1462439e4bfSJean-Christophe PLAGNIOL-VILLARD 
1472439e4bfSJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_DM9000_DEBUG
1482439e4bfSJean-Christophe PLAGNIOL-VILLARD static void
1492439e4bfSJean-Christophe PLAGNIOL-VILLARD dump_regs(void)
1502439e4bfSJean-Christophe PLAGNIOL-VILLARD {
1512439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DM9000_DBG("\n");
1522439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DM9000_DBG("NCR   (0x00): %02x\n", DM9000_ior(0));
1532439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DM9000_DBG("NSR   (0x01): %02x\n", DM9000_ior(1));
1542439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DM9000_DBG("TCR   (0x02): %02x\n", DM9000_ior(2));
1552439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DM9000_DBG("TSRI  (0x03): %02x\n", DM9000_ior(3));
1562439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DM9000_DBG("TSRII (0x04): %02x\n", DM9000_ior(4));
1572439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DM9000_DBG("RCR   (0x05): %02x\n", DM9000_ior(5));
1582439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DM9000_DBG("RSR   (0x06): %02x\n", DM9000_ior(6));
159134e2662SRemy Bohmer 	DM9000_DBG("ISR   (0xFE): %02x\n", DM9000_ior(DM9000_ISR));
1602439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DM9000_DBG("\n");
1612439e4bfSJean-Christophe PLAGNIOL-VILLARD }
162a101361bSRemy Bohmer #endif
163a101361bSRemy Bohmer 
164*0e38c938SRemy Bohmer static void dm9000_outblk_8bit(volatile void *data_ptr, int count)
165a101361bSRemy Bohmer {
166a101361bSRemy Bohmer 	int i;
167a101361bSRemy Bohmer 	for (i = 0; i < count; i++)
168a101361bSRemy Bohmer 		DM9000_outb((((u8 *) data_ptr)[i] & 0xff), DM9000_DATA);
169a101361bSRemy Bohmer }
170a101361bSRemy Bohmer 
171*0e38c938SRemy Bohmer static void dm9000_outblk_16bit(volatile void *data_ptr, int count)
172a101361bSRemy Bohmer {
173a101361bSRemy Bohmer 	int i;
174a101361bSRemy Bohmer 	u32 tmplen = (count + 1) / 2;
175a101361bSRemy Bohmer 
176a101361bSRemy Bohmer 	for (i = 0; i < tmplen; i++)
177a101361bSRemy Bohmer 		DM9000_outw(((u16 *) data_ptr)[i], DM9000_DATA);
178a101361bSRemy Bohmer }
179*0e38c938SRemy Bohmer static void dm9000_outblk_32bit(volatile void *data_ptr, int count)
180a101361bSRemy Bohmer {
181a101361bSRemy Bohmer 	int i;
182a101361bSRemy Bohmer 	u32 tmplen = (count + 3) / 4;
183a101361bSRemy Bohmer 
184a101361bSRemy Bohmer 	for (i = 0; i < tmplen; i++)
185a101361bSRemy Bohmer 		DM9000_outl(((u32 *) data_ptr)[i], DM9000_DATA);
186a101361bSRemy Bohmer }
187a101361bSRemy Bohmer 
188a101361bSRemy Bohmer static void dm9000_inblk_8bit(void *data_ptr, int count)
189a101361bSRemy Bohmer {
190a101361bSRemy Bohmer 	int i;
191a101361bSRemy Bohmer 	for (i = 0; i < count; i++)
192a101361bSRemy Bohmer 		((u8 *) data_ptr)[i] = DM9000_inb(DM9000_DATA);
193a101361bSRemy Bohmer }
194a101361bSRemy Bohmer 
195a101361bSRemy Bohmer static void dm9000_inblk_16bit(void *data_ptr, int count)
196a101361bSRemy Bohmer {
197a101361bSRemy Bohmer 	int i;
198a101361bSRemy Bohmer 	u32 tmplen = (count + 1) / 2;
199a101361bSRemy Bohmer 
200a101361bSRemy Bohmer 	for (i = 0; i < tmplen; i++)
201a101361bSRemy Bohmer 		((u16 *) data_ptr)[i] = DM9000_inw(DM9000_DATA);
202a101361bSRemy Bohmer }
203a101361bSRemy Bohmer static void dm9000_inblk_32bit(void *data_ptr, int count)
204a101361bSRemy Bohmer {
205a101361bSRemy Bohmer 	int i;
206a101361bSRemy Bohmer 	u32 tmplen = (count + 3) / 4;
207a101361bSRemy Bohmer 
208a101361bSRemy Bohmer 	for (i = 0; i < tmplen; i++)
209a101361bSRemy Bohmer 		((u32 *) data_ptr)[i] = DM9000_inl(DM9000_DATA);
210a101361bSRemy Bohmer }
211a101361bSRemy Bohmer 
212a101361bSRemy Bohmer static void dm9000_rx_status_32bit(u16 *RxStatus, u16 *RxLen)
213a101361bSRemy Bohmer {
214d6ee5fa4SRemy Bohmer 	u32 tmpdata;
215a101361bSRemy Bohmer 
216a101361bSRemy Bohmer 	DM9000_outb(DM9000_MRCMD, DM9000_IO);
217a101361bSRemy Bohmer 
218d6ee5fa4SRemy Bohmer 	tmpdata = DM9000_inl(DM9000_DATA);
219a101361bSRemy Bohmer 	*RxStatus = tmpdata;
220a101361bSRemy Bohmer 	*RxLen = tmpdata >> 16;
221a101361bSRemy Bohmer }
222a101361bSRemy Bohmer 
223a101361bSRemy Bohmer static void dm9000_rx_status_16bit(u16 *RxStatus, u16 *RxLen)
224a101361bSRemy Bohmer {
225a101361bSRemy Bohmer 	DM9000_outb(DM9000_MRCMD, DM9000_IO);
226a101361bSRemy Bohmer 
227a101361bSRemy Bohmer 	*RxStatus = DM9000_inw(DM9000_DATA);
228a101361bSRemy Bohmer 	*RxLen = DM9000_inw(DM9000_DATA);
229a101361bSRemy Bohmer }
230a101361bSRemy Bohmer 
231a101361bSRemy Bohmer static void dm9000_rx_status_8bit(u16 *RxStatus, u16 *RxLen)
232a101361bSRemy Bohmer {
233a101361bSRemy Bohmer 	DM9000_outb(DM9000_MRCMD, DM9000_IO);
234a101361bSRemy Bohmer 
235a101361bSRemy Bohmer 	*RxStatus = DM9000_inb(DM9000_DATA) + (DM9000_inb(DM9000_DATA) << 8);
236a101361bSRemy Bohmer 	*RxLen = DM9000_inb(DM9000_DATA) + (DM9000_inb(DM9000_DATA) << 8);
237a101361bSRemy Bohmer }
2382439e4bfSJean-Christophe PLAGNIOL-VILLARD 
2392439e4bfSJean-Christophe PLAGNIOL-VILLARD /*
2402439e4bfSJean-Christophe PLAGNIOL-VILLARD   Search DM9000 board, allocate space and register it
2412439e4bfSJean-Christophe PLAGNIOL-VILLARD */
2422439e4bfSJean-Christophe PLAGNIOL-VILLARD int
2432439e4bfSJean-Christophe PLAGNIOL-VILLARD dm9000_probe(void)
2442439e4bfSJean-Christophe PLAGNIOL-VILLARD {
2452439e4bfSJean-Christophe PLAGNIOL-VILLARD 	u32 id_val;
2462439e4bfSJean-Christophe PLAGNIOL-VILLARD 	id_val = DM9000_ior(DM9000_VIDL);
2472439e4bfSJean-Christophe PLAGNIOL-VILLARD 	id_val |= DM9000_ior(DM9000_VIDH) << 8;
2482439e4bfSJean-Christophe PLAGNIOL-VILLARD 	id_val |= DM9000_ior(DM9000_PIDL) << 16;
2492439e4bfSJean-Christophe PLAGNIOL-VILLARD 	id_val |= DM9000_ior(DM9000_PIDH) << 24;
2502439e4bfSJean-Christophe PLAGNIOL-VILLARD 	if (id_val == DM9000_ID) {
2512439e4bfSJean-Christophe PLAGNIOL-VILLARD 		printf("dm9000 i/o: 0x%x, id: 0x%x \n", CONFIG_DM9000_BASE,
2522439e4bfSJean-Christophe PLAGNIOL-VILLARD 		       id_val);
2532439e4bfSJean-Christophe PLAGNIOL-VILLARD 		return 0;
2542439e4bfSJean-Christophe PLAGNIOL-VILLARD 	} else {
2552439e4bfSJean-Christophe PLAGNIOL-VILLARD 		printf("dm9000 not found at 0x%08x id: 0x%08x\n",
2562439e4bfSJean-Christophe PLAGNIOL-VILLARD 		       CONFIG_DM9000_BASE, id_val);
2572439e4bfSJean-Christophe PLAGNIOL-VILLARD 		return -1;
2582439e4bfSJean-Christophe PLAGNIOL-VILLARD 	}
2592439e4bfSJean-Christophe PLAGNIOL-VILLARD }
2602439e4bfSJean-Christophe PLAGNIOL-VILLARD 
2612439e4bfSJean-Christophe PLAGNIOL-VILLARD /* Set PHY operationg mode
2622439e4bfSJean-Christophe PLAGNIOL-VILLARD */
2632439e4bfSJean-Christophe PLAGNIOL-VILLARD static void
2642439e4bfSJean-Christophe PLAGNIOL-VILLARD set_PHY_mode(void)
2652439e4bfSJean-Christophe PLAGNIOL-VILLARD {
2662439e4bfSJean-Christophe PLAGNIOL-VILLARD 	u16 phy_reg4 = 0x01e1, phy_reg0 = 0x1000;
2672439e4bfSJean-Christophe PLAGNIOL-VILLARD 	if (!(media_mode & DM9000_AUTO)) {
2682439e4bfSJean-Christophe PLAGNIOL-VILLARD 		switch (media_mode) {
2692439e4bfSJean-Christophe PLAGNIOL-VILLARD 		case DM9000_10MHD:
2702439e4bfSJean-Christophe PLAGNIOL-VILLARD 			phy_reg4 = 0x21;
2712439e4bfSJean-Christophe PLAGNIOL-VILLARD 			phy_reg0 = 0x0000;
2722439e4bfSJean-Christophe PLAGNIOL-VILLARD 			break;
2732439e4bfSJean-Christophe PLAGNIOL-VILLARD 		case DM9000_10MFD:
2742439e4bfSJean-Christophe PLAGNIOL-VILLARD 			phy_reg4 = 0x41;
2752439e4bfSJean-Christophe PLAGNIOL-VILLARD 			phy_reg0 = 0x1100;
2762439e4bfSJean-Christophe PLAGNIOL-VILLARD 			break;
2772439e4bfSJean-Christophe PLAGNIOL-VILLARD 		case DM9000_100MHD:
2782439e4bfSJean-Christophe PLAGNIOL-VILLARD 			phy_reg4 = 0x81;
2792439e4bfSJean-Christophe PLAGNIOL-VILLARD 			phy_reg0 = 0x2000;
2802439e4bfSJean-Christophe PLAGNIOL-VILLARD 			break;
2812439e4bfSJean-Christophe PLAGNIOL-VILLARD 		case DM9000_100MFD:
2822439e4bfSJean-Christophe PLAGNIOL-VILLARD 			phy_reg4 = 0x101;
2832439e4bfSJean-Christophe PLAGNIOL-VILLARD 			phy_reg0 = 0x3100;
2842439e4bfSJean-Christophe PLAGNIOL-VILLARD 			break;
2852439e4bfSJean-Christophe PLAGNIOL-VILLARD 		}
2862439e4bfSJean-Christophe PLAGNIOL-VILLARD 		phy_write(4, phy_reg4);	/* Set PHY media mode */
2872439e4bfSJean-Christophe PLAGNIOL-VILLARD 		phy_write(0, phy_reg0);	/*  Tmp */
2882439e4bfSJean-Christophe PLAGNIOL-VILLARD 	}
2892439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DM9000_iow(DM9000_GPCR, 0x01);	/* Let GPIO0 output */
2902439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DM9000_iow(DM9000_GPR, 0x00);	/* Enable PHY */
2912439e4bfSJean-Christophe PLAGNIOL-VILLARD }
2922439e4bfSJean-Christophe PLAGNIOL-VILLARD 
2932439e4bfSJean-Christophe PLAGNIOL-VILLARD /*
2942439e4bfSJean-Christophe PLAGNIOL-VILLARD 	Init HomeRun DM9801
2952439e4bfSJean-Christophe PLAGNIOL-VILLARD */
2962439e4bfSJean-Christophe PLAGNIOL-VILLARD static void
2972439e4bfSJean-Christophe PLAGNIOL-VILLARD program_dm9801(u16 HPNA_rev)
2982439e4bfSJean-Christophe PLAGNIOL-VILLARD {
2992439e4bfSJean-Christophe PLAGNIOL-VILLARD 	__u16 reg16, reg17, reg24, reg25;
3002439e4bfSJean-Christophe PLAGNIOL-VILLARD 	if (!nfloor)
3012439e4bfSJean-Christophe PLAGNIOL-VILLARD 		nfloor = DM9801_NOISE_FLOOR;
3022439e4bfSJean-Christophe PLAGNIOL-VILLARD 	reg16 = phy_read(16);
3032439e4bfSJean-Christophe PLAGNIOL-VILLARD 	reg17 = phy_read(17);
3042439e4bfSJean-Christophe PLAGNIOL-VILLARD 	reg24 = phy_read(24);
3052439e4bfSJean-Christophe PLAGNIOL-VILLARD 	reg25 = phy_read(25);
3062439e4bfSJean-Christophe PLAGNIOL-VILLARD 	switch (HPNA_rev) {
3072439e4bfSJean-Christophe PLAGNIOL-VILLARD 	case 0xb900:		/* DM9801 E3 */
3082439e4bfSJean-Christophe PLAGNIOL-VILLARD 		reg16 |= 0x1000;
3092439e4bfSJean-Christophe PLAGNIOL-VILLARD 		reg25 = ((reg24 + nfloor) & 0x00ff) | 0xf000;
3102439e4bfSJean-Christophe PLAGNIOL-VILLARD 		break;
3112439e4bfSJean-Christophe PLAGNIOL-VILLARD 	case 0xb901:		/* DM9801 E4 */
3122439e4bfSJean-Christophe PLAGNIOL-VILLARD 		reg25 = ((reg24 + nfloor) & 0x00ff) | 0xc200;
3132439e4bfSJean-Christophe PLAGNIOL-VILLARD 		reg17 = (reg17 & 0xfff0) + nfloor + 3;
3142439e4bfSJean-Christophe PLAGNIOL-VILLARD 		break;
3152439e4bfSJean-Christophe PLAGNIOL-VILLARD 	case 0xb902:		/* DM9801 E5 */
3162439e4bfSJean-Christophe PLAGNIOL-VILLARD 	case 0xb903:		/* DM9801 E6 */
3172439e4bfSJean-Christophe PLAGNIOL-VILLARD 	default:
3182439e4bfSJean-Christophe PLAGNIOL-VILLARD 		reg16 |= 0x1000;
3192439e4bfSJean-Christophe PLAGNIOL-VILLARD 		reg25 = ((reg24 + nfloor - 3) & 0x00ff) | 0xc200;
3202439e4bfSJean-Christophe PLAGNIOL-VILLARD 		reg17 = (reg17 & 0xfff0) + nfloor;
3212439e4bfSJean-Christophe PLAGNIOL-VILLARD 	}
3222439e4bfSJean-Christophe PLAGNIOL-VILLARD 	phy_write(16, reg16);
3232439e4bfSJean-Christophe PLAGNIOL-VILLARD 	phy_write(17, reg17);
3242439e4bfSJean-Christophe PLAGNIOL-VILLARD 	phy_write(25, reg25);
3252439e4bfSJean-Christophe PLAGNIOL-VILLARD }
3262439e4bfSJean-Christophe PLAGNIOL-VILLARD 
3272439e4bfSJean-Christophe PLAGNIOL-VILLARD /*
3282439e4bfSJean-Christophe PLAGNIOL-VILLARD 	Init LongRun DM9802
3292439e4bfSJean-Christophe PLAGNIOL-VILLARD */
3302439e4bfSJean-Christophe PLAGNIOL-VILLARD static void
3312439e4bfSJean-Christophe PLAGNIOL-VILLARD program_dm9802(void)
3322439e4bfSJean-Christophe PLAGNIOL-VILLARD {
3332439e4bfSJean-Christophe PLAGNIOL-VILLARD 	__u16 reg25;
3342439e4bfSJean-Christophe PLAGNIOL-VILLARD 	if (!nfloor)
3352439e4bfSJean-Christophe PLAGNIOL-VILLARD 		nfloor = DM9802_NOISE_FLOOR;
3362439e4bfSJean-Christophe PLAGNIOL-VILLARD 	reg25 = phy_read(25);
3372439e4bfSJean-Christophe PLAGNIOL-VILLARD 	reg25 = (reg25 & 0xff00) + nfloor;
3382439e4bfSJean-Christophe PLAGNIOL-VILLARD 	phy_write(25, reg25);
3392439e4bfSJean-Christophe PLAGNIOL-VILLARD }
3402439e4bfSJean-Christophe PLAGNIOL-VILLARD 
3412439e4bfSJean-Christophe PLAGNIOL-VILLARD /* Identify NIC type
3422439e4bfSJean-Christophe PLAGNIOL-VILLARD */
3432439e4bfSJean-Christophe PLAGNIOL-VILLARD static void
3442439e4bfSJean-Christophe PLAGNIOL-VILLARD identify_nic(void)
3452439e4bfSJean-Christophe PLAGNIOL-VILLARD {
346a101361bSRemy Bohmer 	struct board_info *db = &dm9000_info;
3472439e4bfSJean-Christophe PLAGNIOL-VILLARD 	u16 phy_reg3;
3482439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DM9000_iow(DM9000_NCR, NCR_EXT_PHY);
3492439e4bfSJean-Christophe PLAGNIOL-VILLARD 	phy_reg3 = phy_read(3);
3502439e4bfSJean-Christophe PLAGNIOL-VILLARD 	switch (phy_reg3 & 0xfff0) {
3512439e4bfSJean-Christophe PLAGNIOL-VILLARD 	case 0xb900:
3522439e4bfSJean-Christophe PLAGNIOL-VILLARD 		if (phy_read(31) == 0x4404) {
3532439e4bfSJean-Christophe PLAGNIOL-VILLARD 			db->nic_type = HOMERUN_NIC;
3542439e4bfSJean-Christophe PLAGNIOL-VILLARD 			program_dm9801(phy_reg3);
3552439e4bfSJean-Christophe PLAGNIOL-VILLARD 			DM9000_DBG("found homerun NIC\n");
3562439e4bfSJean-Christophe PLAGNIOL-VILLARD 		} else {
3572439e4bfSJean-Christophe PLAGNIOL-VILLARD 			db->nic_type = LONGRUN_NIC;
3582439e4bfSJean-Christophe PLAGNIOL-VILLARD 			DM9000_DBG("found longrun NIC\n");
3592439e4bfSJean-Christophe PLAGNIOL-VILLARD 			program_dm9802();
3602439e4bfSJean-Christophe PLAGNIOL-VILLARD 		}
3612439e4bfSJean-Christophe PLAGNIOL-VILLARD 		break;
3622439e4bfSJean-Christophe PLAGNIOL-VILLARD 	default:
3632439e4bfSJean-Christophe PLAGNIOL-VILLARD 		db->nic_type = FASTETHER_NIC;
3642439e4bfSJean-Christophe PLAGNIOL-VILLARD 		break;
3652439e4bfSJean-Christophe PLAGNIOL-VILLARD 	}
3662439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DM9000_iow(DM9000_NCR, 0);
3672439e4bfSJean-Christophe PLAGNIOL-VILLARD }
3682439e4bfSJean-Christophe PLAGNIOL-VILLARD 
3692439e4bfSJean-Christophe PLAGNIOL-VILLARD /* General Purpose dm9000 reset routine */
3702439e4bfSJean-Christophe PLAGNIOL-VILLARD static void
3712439e4bfSJean-Christophe PLAGNIOL-VILLARD dm9000_reset(void)
3722439e4bfSJean-Christophe PLAGNIOL-VILLARD {
373fbcb7eceSRemy Bohmer 	DM9000_DBG("resetting DM9000\n");
374fbcb7eceSRemy Bohmer 
375fbcb7eceSRemy Bohmer 	/* Reset DM9000,
376fbcb7eceSRemy Bohmer 	   see DM9000 Application Notes V1.22 Jun 11, 2004 page 29 */
377fbcb7eceSRemy Bohmer 
378fbcb7eceSRemy Bohmer 	/* DEBUG: Make all GPIO pins outputs */
379fbcb7eceSRemy Bohmer 	DM9000_iow(DM9000_GPCR, 0x0F);
380fbcb7eceSRemy Bohmer 	/* Step 1: Power internal PHY by writing 0 to GPIO0 pin */
381fbcb7eceSRemy Bohmer 	DM9000_iow(DM9000_GPR, 0);
382fbcb7eceSRemy Bohmer 	/* Step 2: Software reset */
383fbcb7eceSRemy Bohmer 	DM9000_iow(DM9000_NCR, 3);
384fbcb7eceSRemy Bohmer 
385fbcb7eceSRemy Bohmer 	do {
386fbcb7eceSRemy Bohmer 		DM9000_DBG("resetting the DM9000, 1st reset\n");
387fbcb7eceSRemy Bohmer 		udelay(25); /* Wait at least 20 us */
388fbcb7eceSRemy Bohmer 	} while (DM9000_ior(DM9000_NCR) & 1);
389fbcb7eceSRemy Bohmer 
390fbcb7eceSRemy Bohmer 	DM9000_iow(DM9000_NCR, 0);
391fbcb7eceSRemy Bohmer 	DM9000_iow(DM9000_NCR, 3); /* Issue a second reset */
392fbcb7eceSRemy Bohmer 
393fbcb7eceSRemy Bohmer 	do {
394fbcb7eceSRemy Bohmer 		DM9000_DBG("resetting the DM9000, 2nd reset\n");
395fbcb7eceSRemy Bohmer 		udelay(25); /* Wait at least 20 us */
396fbcb7eceSRemy Bohmer 	} while (DM9000_ior(DM9000_NCR) & 1);
397fbcb7eceSRemy Bohmer 
398fbcb7eceSRemy Bohmer 	/* Check whether the ethernet controller is present */
399fbcb7eceSRemy Bohmer 	if ((DM9000_ior(DM9000_PIDL) != 0x0) ||
400fbcb7eceSRemy Bohmer 	    (DM9000_ior(DM9000_PIDH) != 0x90))
401fbcb7eceSRemy Bohmer 		printf("ERROR: resetting DM9000 -> not responding\n");
4022439e4bfSJean-Christophe PLAGNIOL-VILLARD }
4032439e4bfSJean-Christophe PLAGNIOL-VILLARD 
4042439e4bfSJean-Christophe PLAGNIOL-VILLARD /* Initilize dm9000 board
4052439e4bfSJean-Christophe PLAGNIOL-VILLARD */
4062439e4bfSJean-Christophe PLAGNIOL-VILLARD int
4072439e4bfSJean-Christophe PLAGNIOL-VILLARD eth_init(bd_t * bd)
4082439e4bfSJean-Christophe PLAGNIOL-VILLARD {
4092439e4bfSJean-Christophe PLAGNIOL-VILLARD 	int i, oft, lnk;
410a101361bSRemy Bohmer 	u8 io_mode;
411a101361bSRemy Bohmer 	struct board_info *db = &dm9000_info;
412a101361bSRemy Bohmer 
4132439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DM9000_DBG("eth_init()\n");
4142439e4bfSJean-Christophe PLAGNIOL-VILLARD 
4152439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* RESET device */
4162439e4bfSJean-Christophe PLAGNIOL-VILLARD 	dm9000_reset();
4172439e4bfSJean-Christophe PLAGNIOL-VILLARD 	dm9000_probe();
4182439e4bfSJean-Christophe PLAGNIOL-VILLARD 
419a101361bSRemy Bohmer 	/* Auto-detect 8/16/32 bit mode, ISR Bit 6+7 indicate bus width */
420a101361bSRemy Bohmer 	io_mode = DM9000_ior(DM9000_ISR) >> 6;
421a101361bSRemy Bohmer 
422a101361bSRemy Bohmer 	switch (io_mode) {
423a101361bSRemy Bohmer 	case 0x0:  /* 16-bit mode */
424a101361bSRemy Bohmer 		printf("DM9000: running in 16 bit mode\n");
425a101361bSRemy Bohmer 		db->outblk    = dm9000_outblk_16bit;
426a101361bSRemy Bohmer 		db->inblk     = dm9000_inblk_16bit;
427a101361bSRemy Bohmer 		db->rx_status = dm9000_rx_status_16bit;
428a101361bSRemy Bohmer 		break;
429a101361bSRemy Bohmer 	case 0x01:  /* 32-bit mode */
430a101361bSRemy Bohmer 		printf("DM9000: running in 32 bit mode\n");
431a101361bSRemy Bohmer 		db->outblk    = dm9000_outblk_32bit;
432a101361bSRemy Bohmer 		db->inblk     = dm9000_inblk_32bit;
433a101361bSRemy Bohmer 		db->rx_status = dm9000_rx_status_32bit;
434a101361bSRemy Bohmer 		break;
435a101361bSRemy Bohmer 	case 0x02: /* 8 bit mode */
436a101361bSRemy Bohmer 		printf("DM9000: running in 8 bit mode\n");
437a101361bSRemy Bohmer 		db->outblk    = dm9000_outblk_8bit;
438a101361bSRemy Bohmer 		db->inblk     = dm9000_inblk_8bit;
439a101361bSRemy Bohmer 		db->rx_status = dm9000_rx_status_8bit;
440a101361bSRemy Bohmer 		break;
441a101361bSRemy Bohmer 	default:
442a101361bSRemy Bohmer 		/* Assume 8 bit mode, will probably not work anyway */
443a101361bSRemy Bohmer 		printf("DM9000: Undefined IO-mode:0x%x\n", io_mode);
444a101361bSRemy Bohmer 		db->outblk    = dm9000_outblk_8bit;
445a101361bSRemy Bohmer 		db->inblk     = dm9000_inblk_8bit;
446a101361bSRemy Bohmer 		db->rx_status = dm9000_rx_status_8bit;
447a101361bSRemy Bohmer 		break;
448a101361bSRemy Bohmer 	}
449a101361bSRemy Bohmer 
4502439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* NIC Type: FASTETHER, HOMERUN, LONGRUN */
4512439e4bfSJean-Christophe PLAGNIOL-VILLARD 	identify_nic();
4522439e4bfSJean-Christophe PLAGNIOL-VILLARD 
4532439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* GPIO0 on pre-activate PHY */
4542439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DM9000_iow(DM9000_GPR, 0x00);	/*REG_1F bit0 activate phyxcer */
4552439e4bfSJean-Christophe PLAGNIOL-VILLARD 
4562439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* Set PHY */
4572439e4bfSJean-Christophe PLAGNIOL-VILLARD 	set_PHY_mode();
4582439e4bfSJean-Christophe PLAGNIOL-VILLARD 
45998291e2eSRemy Bohmer 	/* Program operating register, only intern phy supported by now */
46098291e2eSRemy Bohmer 	DM9000_iow(DM9000_NCR, 0x0);
46198291e2eSRemy Bohmer 	/* TX Polling clear */
46298291e2eSRemy Bohmer 	DM9000_iow(DM9000_TCR, 0);
46398291e2eSRemy Bohmer 	/* Less 3Kb, 200us */
46498291e2eSRemy Bohmer 	DM9000_iow(DM9000_BPTR, 0x3f);
46598291e2eSRemy Bohmer 	/* Flow Control : High/Low Water */
46698291e2eSRemy Bohmer 	DM9000_iow(DM9000_FCTR, FCTR_HWOT(3) | FCTR_LWOT(8));
46798291e2eSRemy Bohmer 	/* SH FIXME: This looks strange! Flow Control */
46898291e2eSRemy Bohmer 	DM9000_iow(DM9000_FCR, 0x0);
46998291e2eSRemy Bohmer 	/* Special Mode */
47098291e2eSRemy Bohmer 	DM9000_iow(DM9000_SMCR, 0);
47198291e2eSRemy Bohmer 	/* clear TX status */
47298291e2eSRemy Bohmer 	DM9000_iow(DM9000_NSR, NSR_WAKEST | NSR_TX2END | NSR_TX1END);
47398291e2eSRemy Bohmer 	/* Clear interrupt status */
47498291e2eSRemy Bohmer 	DM9000_iow(DM9000_ISR, 0x0f);
4752439e4bfSJean-Christophe PLAGNIOL-VILLARD 
4762439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* Set Node address */
4772439e4bfSJean-Christophe PLAGNIOL-VILLARD 	for (i = 0; i < 6; i++)
4782439e4bfSJean-Christophe PLAGNIOL-VILLARD 		((u16 *) bd->bi_enetaddr)[i] = read_srom_word(i);
4792439e4bfSJean-Christophe PLAGNIOL-VILLARD 
4802439e4bfSJean-Christophe PLAGNIOL-VILLARD 	if (is_zero_ether_addr(bd->bi_enetaddr) ||
4812439e4bfSJean-Christophe PLAGNIOL-VILLARD 	    is_multicast_ether_addr(bd->bi_enetaddr)) {
4822439e4bfSJean-Christophe PLAGNIOL-VILLARD 		/* try reading from environment */
4832439e4bfSJean-Christophe PLAGNIOL-VILLARD 		u8 i;
4842439e4bfSJean-Christophe PLAGNIOL-VILLARD 		char *s, *e;
4852439e4bfSJean-Christophe PLAGNIOL-VILLARD 		s = getenv ("ethaddr");
4862439e4bfSJean-Christophe PLAGNIOL-VILLARD 		for (i = 0; i < 6; ++i) {
4872439e4bfSJean-Christophe PLAGNIOL-VILLARD 			bd->bi_enetaddr[i] = s ?
4882439e4bfSJean-Christophe PLAGNIOL-VILLARD 				simple_strtoul (s, &e, 16) : 0;
4892439e4bfSJean-Christophe PLAGNIOL-VILLARD 			if (s)
4902439e4bfSJean-Christophe PLAGNIOL-VILLARD 				s = (*e) ? e + 1 : e;
4912439e4bfSJean-Christophe PLAGNIOL-VILLARD 		}
4922439e4bfSJean-Christophe PLAGNIOL-VILLARD 	}
4932439e4bfSJean-Christophe PLAGNIOL-VILLARD 
4942439e4bfSJean-Christophe PLAGNIOL-VILLARD 	printf("MAC: %02x:%02x:%02x:%02x:%02x:%02x\n", bd->bi_enetaddr[0],
4952439e4bfSJean-Christophe PLAGNIOL-VILLARD 	       bd->bi_enetaddr[1], bd->bi_enetaddr[2], bd->bi_enetaddr[3],
4962439e4bfSJean-Christophe PLAGNIOL-VILLARD 	       bd->bi_enetaddr[4], bd->bi_enetaddr[5]);
4972439e4bfSJean-Christophe PLAGNIOL-VILLARD 	for (i = 0, oft = 0x10; i < 6; i++, oft++)
4982439e4bfSJean-Christophe PLAGNIOL-VILLARD 		DM9000_iow(oft, bd->bi_enetaddr[i]);
4992439e4bfSJean-Christophe PLAGNIOL-VILLARD 	for (i = 0, oft = 0x16; i < 8; i++, oft++)
5002439e4bfSJean-Christophe PLAGNIOL-VILLARD 		DM9000_iow(oft, 0xff);
5012439e4bfSJean-Christophe PLAGNIOL-VILLARD 
5022439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* read back mac, just to be sure */
5032439e4bfSJean-Christophe PLAGNIOL-VILLARD 	for (i = 0, oft = 0x10; i < 6; i++, oft++)
5042439e4bfSJean-Christophe PLAGNIOL-VILLARD 		DM9000_DBG("%02x:", DM9000_ior(oft));
5052439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DM9000_DBG("\n");
5062439e4bfSJean-Christophe PLAGNIOL-VILLARD 
5072439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* Activate DM9000 */
50898291e2eSRemy Bohmer 	/* RX enable */
50998291e2eSRemy Bohmer 	DM9000_iow(DM9000_RCR, RCR_DIS_LONG | RCR_DIS_CRC | RCR_RXEN);
51098291e2eSRemy Bohmer 	/* Enable TX/RX interrupt mask */
51198291e2eSRemy Bohmer 	DM9000_iow(DM9000_IMR, IMR_PAR);
51298291e2eSRemy Bohmer 
5132439e4bfSJean-Christophe PLAGNIOL-VILLARD 	i = 0;
5142439e4bfSJean-Christophe PLAGNIOL-VILLARD 	while (!(phy_read(1) & 0x20)) {	/* autonegation complete bit */
5152439e4bfSJean-Christophe PLAGNIOL-VILLARD 		udelay(1000);
5162439e4bfSJean-Christophe PLAGNIOL-VILLARD 		i++;
5172439e4bfSJean-Christophe PLAGNIOL-VILLARD 		if (i == 10000) {
5182439e4bfSJean-Christophe PLAGNIOL-VILLARD 			printf("could not establish link\n");
5192439e4bfSJean-Christophe PLAGNIOL-VILLARD 			return 0;
5202439e4bfSJean-Christophe PLAGNIOL-VILLARD 		}
5212439e4bfSJean-Christophe PLAGNIOL-VILLARD 	}
5222439e4bfSJean-Christophe PLAGNIOL-VILLARD 
5232439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* see what we've got */
5242439e4bfSJean-Christophe PLAGNIOL-VILLARD 	lnk = phy_read(17) >> 12;
5252439e4bfSJean-Christophe PLAGNIOL-VILLARD 	printf("operating at ");
5262439e4bfSJean-Christophe PLAGNIOL-VILLARD 	switch (lnk) {
5272439e4bfSJean-Christophe PLAGNIOL-VILLARD 	case 1:
5282439e4bfSJean-Christophe PLAGNIOL-VILLARD 		printf("10M half duplex ");
5292439e4bfSJean-Christophe PLAGNIOL-VILLARD 		break;
5302439e4bfSJean-Christophe PLAGNIOL-VILLARD 	case 2:
5312439e4bfSJean-Christophe PLAGNIOL-VILLARD 		printf("10M full duplex ");
5322439e4bfSJean-Christophe PLAGNIOL-VILLARD 		break;
5332439e4bfSJean-Christophe PLAGNIOL-VILLARD 	case 4:
5342439e4bfSJean-Christophe PLAGNIOL-VILLARD 		printf("100M half duplex ");
5352439e4bfSJean-Christophe PLAGNIOL-VILLARD 		break;
5362439e4bfSJean-Christophe PLAGNIOL-VILLARD 	case 8:
5372439e4bfSJean-Christophe PLAGNIOL-VILLARD 		printf("100M full duplex ");
5382439e4bfSJean-Christophe PLAGNIOL-VILLARD 		break;
5392439e4bfSJean-Christophe PLAGNIOL-VILLARD 	default:
5402439e4bfSJean-Christophe PLAGNIOL-VILLARD 		printf("unknown: %d ", lnk);
5412439e4bfSJean-Christophe PLAGNIOL-VILLARD 		break;
5422439e4bfSJean-Christophe PLAGNIOL-VILLARD 	}
5432439e4bfSJean-Christophe PLAGNIOL-VILLARD 	printf("mode\n");
5442439e4bfSJean-Christophe PLAGNIOL-VILLARD 	return 0;
5452439e4bfSJean-Christophe PLAGNIOL-VILLARD }
5462439e4bfSJean-Christophe PLAGNIOL-VILLARD 
5472439e4bfSJean-Christophe PLAGNIOL-VILLARD /*
5482439e4bfSJean-Christophe PLAGNIOL-VILLARD   Hardware start transmission.
5492439e4bfSJean-Christophe PLAGNIOL-VILLARD   Send a packet to media from the upper layer.
5502439e4bfSJean-Christophe PLAGNIOL-VILLARD */
5512439e4bfSJean-Christophe PLAGNIOL-VILLARD int
5522439e4bfSJean-Christophe PLAGNIOL-VILLARD eth_send(volatile void *packet, int length)
5532439e4bfSJean-Christophe PLAGNIOL-VILLARD {
5542439e4bfSJean-Christophe PLAGNIOL-VILLARD 	int tmo;
555a101361bSRemy Bohmer 	struct board_info *db = &dm9000_info;
556a101361bSRemy Bohmer 
557134e2662SRemy Bohmer 	DM9000_DMP_PACKET("eth_send", packet, length);
5582439e4bfSJean-Christophe PLAGNIOL-VILLARD 
559acba3184SRemy Bohmer 	DM9000_iow(DM9000_ISR, IMR_PTM); /* Clear Tx bit in ISR */
560acba3184SRemy Bohmer 
5612439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* Move data to DM9000 TX RAM */
562acba3184SRemy Bohmer 	DM9000_outb(DM9000_MWCMD, DM9000_IO); /* Prepare for TX-data */
5632439e4bfSJean-Christophe PLAGNIOL-VILLARD 
564a101361bSRemy Bohmer 	/* push the data to the TX-fifo */
565*0e38c938SRemy Bohmer 	(db->outblk)(packet, length);
5662439e4bfSJean-Christophe PLAGNIOL-VILLARD 
5672439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* Set TX length to DM9000 */
5682439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DM9000_iow(DM9000_TXPLL, length & 0xff);
5692439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DM9000_iow(DM9000_TXPLH, (length >> 8) & 0xff);
5702439e4bfSJean-Christophe PLAGNIOL-VILLARD 
5712439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* Issue TX polling command */
5722439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DM9000_iow(DM9000_TCR, TCR_TXREQ); /* Cleared after TX complete */
5732439e4bfSJean-Christophe PLAGNIOL-VILLARD 
5742439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* wait for end of transmission */
5752439e4bfSJean-Christophe PLAGNIOL-VILLARD 	tmo = get_timer(0) + 5 * CFG_HZ;
576acba3184SRemy Bohmer 	while ( !(DM9000_ior(DM9000_NSR) & (NSR_TX1END | NSR_TX2END)) ||
577acba3184SRemy Bohmer 		!(DM9000_ior(DM9000_ISR) & IMR_PTM) ) {
5782439e4bfSJean-Christophe PLAGNIOL-VILLARD 		if (get_timer(0) >= tmo) {
5792439e4bfSJean-Christophe PLAGNIOL-VILLARD 			printf("transmission timeout\n");
5802439e4bfSJean-Christophe PLAGNIOL-VILLARD 			break;
5812439e4bfSJean-Christophe PLAGNIOL-VILLARD 		}
5822439e4bfSJean-Christophe PLAGNIOL-VILLARD 	}
583acba3184SRemy Bohmer 	DM9000_iow(DM9000_ISR, IMR_PTM); /* Clear Tx bit in ISR */
584acba3184SRemy Bohmer 
5852439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DM9000_DBG("transmit done\n\n");
5862439e4bfSJean-Christophe PLAGNIOL-VILLARD 	return 0;
5872439e4bfSJean-Christophe PLAGNIOL-VILLARD }
5882439e4bfSJean-Christophe PLAGNIOL-VILLARD 
5892439e4bfSJean-Christophe PLAGNIOL-VILLARD /*
5902439e4bfSJean-Christophe PLAGNIOL-VILLARD   Stop the interface.
5912439e4bfSJean-Christophe PLAGNIOL-VILLARD   The interface is stopped when it is brought.
5922439e4bfSJean-Christophe PLAGNIOL-VILLARD */
5932439e4bfSJean-Christophe PLAGNIOL-VILLARD void
5942439e4bfSJean-Christophe PLAGNIOL-VILLARD eth_halt(void)
5952439e4bfSJean-Christophe PLAGNIOL-VILLARD {
5962439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DM9000_DBG("eth_halt\n");
5972439e4bfSJean-Christophe PLAGNIOL-VILLARD 
5982439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* RESET devie */
5992439e4bfSJean-Christophe PLAGNIOL-VILLARD 	phy_write(0, 0x8000);	/* PHY RESET */
6002439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DM9000_iow(DM9000_GPR, 0x01);	/* Power-Down PHY */
6012439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DM9000_iow(DM9000_IMR, 0x80);	/* Disable all interrupt */
6022439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DM9000_iow(DM9000_RCR, 0x00);	/* Disable RX */
6032439e4bfSJean-Christophe PLAGNIOL-VILLARD }
6042439e4bfSJean-Christophe PLAGNIOL-VILLARD 
6052439e4bfSJean-Christophe PLAGNIOL-VILLARD /*
6062439e4bfSJean-Christophe PLAGNIOL-VILLARD   Received a packet and pass to upper layer
6072439e4bfSJean-Christophe PLAGNIOL-VILLARD */
6082439e4bfSJean-Christophe PLAGNIOL-VILLARD int
6092439e4bfSJean-Christophe PLAGNIOL-VILLARD eth_rx(void)
6102439e4bfSJean-Christophe PLAGNIOL-VILLARD {
6112439e4bfSJean-Christophe PLAGNIOL-VILLARD 	u8 rxbyte, *rdptr = (u8 *) NetRxPackets[0];
6122439e4bfSJean-Christophe PLAGNIOL-VILLARD 	u16 RxStatus, RxLen = 0;
613a101361bSRemy Bohmer 	struct board_info *db = &dm9000_info;
6142439e4bfSJean-Christophe PLAGNIOL-VILLARD 
615850ba755SRemy Bohmer 	/* Check packet ready or not, we must check
616850ba755SRemy Bohmer 	   the ISR status first for DM9000A */
617850ba755SRemy Bohmer 	if (!(DM9000_ior(DM9000_ISR) & 0x01)) /* Rx-ISR bit must be set. */
6182439e4bfSJean-Christophe PLAGNIOL-VILLARD 		return 0;
6192439e4bfSJean-Christophe PLAGNIOL-VILLARD 
620850ba755SRemy Bohmer 	DM9000_iow(DM9000_ISR, 0x01); /* clear PR status latched in bit 0 */
621850ba755SRemy Bohmer 
622850ba755SRemy Bohmer 	/* There is _at least_ 1 package in the fifo, read them all */
623850ba755SRemy Bohmer 	for (;;) {
624850ba755SRemy Bohmer 		DM9000_ior(DM9000_MRCMDX);	/* Dummy read */
625850ba755SRemy Bohmer 
626*0e38c938SRemy Bohmer 		/* Get most updated data,
627*0e38c938SRemy Bohmer 		   only look at bits 0:1, See application notes DM9000 */
628*0e38c938SRemy Bohmer 		rxbyte = DM9000_inb(DM9000_DATA) & 0x03;
629850ba755SRemy Bohmer 
6302439e4bfSJean-Christophe PLAGNIOL-VILLARD 		/* Status check: this byte must be 0 or 1 */
631850ba755SRemy Bohmer 		if (rxbyte > DM9000_PKT_RDY) {
6322439e4bfSJean-Christophe PLAGNIOL-VILLARD 			DM9000_iow(DM9000_RCR, 0x00);	/* Stop Device */
6332439e4bfSJean-Christophe PLAGNIOL-VILLARD 			DM9000_iow(DM9000_ISR, 0x80);	/* Stop INT request */
634850ba755SRemy Bohmer 			printf("DM9000 error: status check fail: 0x%x\n",
635850ba755SRemy Bohmer 				rxbyte);
636850ba755SRemy Bohmer 			return 0;
6372439e4bfSJean-Christophe PLAGNIOL-VILLARD 		}
638850ba755SRemy Bohmer 
639850ba755SRemy Bohmer 		if (rxbyte != DM9000_PKT_RDY)
640850ba755SRemy Bohmer 			return 0; /* No packet received, ignore */
641850ba755SRemy Bohmer 
6422439e4bfSJean-Christophe PLAGNIOL-VILLARD 		DM9000_DBG("receiving packet\n");
6432439e4bfSJean-Christophe PLAGNIOL-VILLARD 
6442439e4bfSJean-Christophe PLAGNIOL-VILLARD 		/* A packet ready now  & Get status/length */
645a101361bSRemy Bohmer 		(db->rx_status)(&RxStatus, &RxLen);
6462439e4bfSJean-Christophe PLAGNIOL-VILLARD 
6472439e4bfSJean-Christophe PLAGNIOL-VILLARD 		DM9000_DBG("rx status: 0x%04x rx len: %d\n", RxStatus, RxLen);
6482439e4bfSJean-Christophe PLAGNIOL-VILLARD 
6492439e4bfSJean-Christophe PLAGNIOL-VILLARD 		/* Move data from DM9000 */
6502439e4bfSJean-Christophe PLAGNIOL-VILLARD 		/* Read received packet from RX SRAM */
651a101361bSRemy Bohmer 		(db->inblk)(rdptr, RxLen);
6522439e4bfSJean-Christophe PLAGNIOL-VILLARD 
6532439e4bfSJean-Christophe PLAGNIOL-VILLARD 		if ((RxStatus & 0xbf00) || (RxLen < 0x40)
6542439e4bfSJean-Christophe PLAGNIOL-VILLARD 			|| (RxLen > DM9000_PKT_MAX)) {
6552439e4bfSJean-Christophe PLAGNIOL-VILLARD 			if (RxStatus & 0x100) {
6562439e4bfSJean-Christophe PLAGNIOL-VILLARD 				printf("rx fifo error\n");
6572439e4bfSJean-Christophe PLAGNIOL-VILLARD 			}
6582439e4bfSJean-Christophe PLAGNIOL-VILLARD 			if (RxStatus & 0x200) {
6592439e4bfSJean-Christophe PLAGNIOL-VILLARD 				printf("rx crc error\n");
6602439e4bfSJean-Christophe PLAGNIOL-VILLARD 			}
6612439e4bfSJean-Christophe PLAGNIOL-VILLARD 			if (RxStatus & 0x8000) {
6622439e4bfSJean-Christophe PLAGNIOL-VILLARD 				printf("rx length error\n");
6632439e4bfSJean-Christophe PLAGNIOL-VILLARD 			}
6642439e4bfSJean-Christophe PLAGNIOL-VILLARD 			if (RxLen > DM9000_PKT_MAX) {
6652439e4bfSJean-Christophe PLAGNIOL-VILLARD 				printf("rx length too big\n");
6662439e4bfSJean-Christophe PLAGNIOL-VILLARD 				dm9000_reset();
6672439e4bfSJean-Christophe PLAGNIOL-VILLARD 			}
6682439e4bfSJean-Christophe PLAGNIOL-VILLARD 		} else {
669134e2662SRemy Bohmer 			DM9000_DMP_PACKET("eth_rx", rdptr, RxLen);
6702439e4bfSJean-Christophe PLAGNIOL-VILLARD 
6712439e4bfSJean-Christophe PLAGNIOL-VILLARD 			DM9000_DBG("passing packet to upper layer\n");
6722439e4bfSJean-Christophe PLAGNIOL-VILLARD 			NetReceive(NetRxPackets[0], RxLen);
673850ba755SRemy Bohmer 		}
6742439e4bfSJean-Christophe PLAGNIOL-VILLARD 	}
6752439e4bfSJean-Christophe PLAGNIOL-VILLARD 	return 0;
6762439e4bfSJean-Christophe PLAGNIOL-VILLARD }
6772439e4bfSJean-Christophe PLAGNIOL-VILLARD 
6782439e4bfSJean-Christophe PLAGNIOL-VILLARD /*
6792439e4bfSJean-Christophe PLAGNIOL-VILLARD   Read a word data from SROM
6802439e4bfSJean-Christophe PLAGNIOL-VILLARD */
6812439e4bfSJean-Christophe PLAGNIOL-VILLARD u16
6822439e4bfSJean-Christophe PLAGNIOL-VILLARD read_srom_word(int offset)
6832439e4bfSJean-Christophe PLAGNIOL-VILLARD {
6842439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DM9000_iow(DM9000_EPAR, offset);
6852439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DM9000_iow(DM9000_EPCR, 0x4);
6862439e4bfSJean-Christophe PLAGNIOL-VILLARD 	udelay(8000);
6872439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DM9000_iow(DM9000_EPCR, 0x0);
6882439e4bfSJean-Christophe PLAGNIOL-VILLARD 	return (DM9000_ior(DM9000_EPDRL) + (DM9000_ior(DM9000_EPDRH) << 8));
6892439e4bfSJean-Christophe PLAGNIOL-VILLARD }
6902439e4bfSJean-Christophe PLAGNIOL-VILLARD 
6912439e4bfSJean-Christophe PLAGNIOL-VILLARD void
6922439e4bfSJean-Christophe PLAGNIOL-VILLARD write_srom_word(int offset, u16 val)
6932439e4bfSJean-Christophe PLAGNIOL-VILLARD {
6942439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DM9000_iow(DM9000_EPAR, offset);
6952439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DM9000_iow(DM9000_EPDRH, ((val >> 8) & 0xff));
6962439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DM9000_iow(DM9000_EPDRL, (val & 0xff));
6972439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DM9000_iow(DM9000_EPCR, 0x12);
6982439e4bfSJean-Christophe PLAGNIOL-VILLARD 	udelay(8000);
6992439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DM9000_iow(DM9000_EPCR, 0);
7002439e4bfSJean-Christophe PLAGNIOL-VILLARD }
7012439e4bfSJean-Christophe PLAGNIOL-VILLARD 
7022439e4bfSJean-Christophe PLAGNIOL-VILLARD 
7032439e4bfSJean-Christophe PLAGNIOL-VILLARD /*
7042439e4bfSJean-Christophe PLAGNIOL-VILLARD    Read a byte from I/O port
7052439e4bfSJean-Christophe PLAGNIOL-VILLARD */
7062439e4bfSJean-Christophe PLAGNIOL-VILLARD static u8
7072439e4bfSJean-Christophe PLAGNIOL-VILLARD DM9000_ior(int reg)
7082439e4bfSJean-Christophe PLAGNIOL-VILLARD {
7092439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DM9000_outb(reg, DM9000_IO);
7102439e4bfSJean-Christophe PLAGNIOL-VILLARD 	return DM9000_inb(DM9000_DATA);
7112439e4bfSJean-Christophe PLAGNIOL-VILLARD }
7122439e4bfSJean-Christophe PLAGNIOL-VILLARD 
7132439e4bfSJean-Christophe PLAGNIOL-VILLARD /*
7142439e4bfSJean-Christophe PLAGNIOL-VILLARD    Write a byte to I/O port
7152439e4bfSJean-Christophe PLAGNIOL-VILLARD */
7162439e4bfSJean-Christophe PLAGNIOL-VILLARD static void
7172439e4bfSJean-Christophe PLAGNIOL-VILLARD DM9000_iow(int reg, u8 value)
7182439e4bfSJean-Christophe PLAGNIOL-VILLARD {
7192439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DM9000_outb(reg, DM9000_IO);
7202439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DM9000_outb(value, DM9000_DATA);
7212439e4bfSJean-Christophe PLAGNIOL-VILLARD }
7222439e4bfSJean-Christophe PLAGNIOL-VILLARD 
7232439e4bfSJean-Christophe PLAGNIOL-VILLARD /*
7242439e4bfSJean-Christophe PLAGNIOL-VILLARD    Read a word from phyxcer
7252439e4bfSJean-Christophe PLAGNIOL-VILLARD */
7262439e4bfSJean-Christophe PLAGNIOL-VILLARD static u16
7272439e4bfSJean-Christophe PLAGNIOL-VILLARD phy_read(int reg)
7282439e4bfSJean-Christophe PLAGNIOL-VILLARD {
7292439e4bfSJean-Christophe PLAGNIOL-VILLARD 	u16 val;
7302439e4bfSJean-Christophe PLAGNIOL-VILLARD 
7312439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* Fill the phyxcer register into REG_0C */
7322439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DM9000_iow(DM9000_EPAR, DM9000_PHY | reg);
7332439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DM9000_iow(DM9000_EPCR, 0xc);	/* Issue phyxcer read command */
7342439e4bfSJean-Christophe PLAGNIOL-VILLARD 	udelay(100);			/* Wait read complete */
7352439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DM9000_iow(DM9000_EPCR, 0x0);	/* Clear phyxcer read command */
7362439e4bfSJean-Christophe PLAGNIOL-VILLARD 	val = (DM9000_ior(DM9000_EPDRH) << 8) | DM9000_ior(DM9000_EPDRL);
7372439e4bfSJean-Christophe PLAGNIOL-VILLARD 
7382439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* The read data keeps on REG_0D & REG_0E */
739134e2662SRemy Bohmer 	DM9000_DBG("phy_read(0x%x): 0x%x\n", reg, val);
7402439e4bfSJean-Christophe PLAGNIOL-VILLARD 	return val;
7412439e4bfSJean-Christophe PLAGNIOL-VILLARD }
7422439e4bfSJean-Christophe PLAGNIOL-VILLARD 
7432439e4bfSJean-Christophe PLAGNIOL-VILLARD /*
7442439e4bfSJean-Christophe PLAGNIOL-VILLARD    Write a word to phyxcer
7452439e4bfSJean-Christophe PLAGNIOL-VILLARD */
7462439e4bfSJean-Christophe PLAGNIOL-VILLARD static void
7472439e4bfSJean-Christophe PLAGNIOL-VILLARD phy_write(int reg, u16 value)
7482439e4bfSJean-Christophe PLAGNIOL-VILLARD {
7492439e4bfSJean-Christophe PLAGNIOL-VILLARD 
7502439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* Fill the phyxcer register into REG_0C */
7512439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DM9000_iow(DM9000_EPAR, DM9000_PHY | reg);
7522439e4bfSJean-Christophe PLAGNIOL-VILLARD 
7532439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* Fill the written data into REG_0D & REG_0E */
7542439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DM9000_iow(DM9000_EPDRL, (value & 0xff));
7552439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DM9000_iow(DM9000_EPDRH, ((value >> 8) & 0xff));
7562439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DM9000_iow(DM9000_EPCR, 0xa);	/* Issue phyxcer write command */
7572439e4bfSJean-Christophe PLAGNIOL-VILLARD 	udelay(500);			/* Wait write complete */
7582439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DM9000_iow(DM9000_EPCR, 0x0);	/* Clear phyxcer write command */
759134e2662SRemy Bohmer 	DM9000_DBG("phy_write(reg:0x%x, value:0x%x)\n", reg, value);
7602439e4bfSJean-Christophe PLAGNIOL-VILLARD }
7612439e4bfSJean-Christophe PLAGNIOL-VILLARD #endif	/* CONFIG_DRIVER_DM9000 */
762