xref: /openbmc/u-boot/drivers/net/dm9000x.c (revision 192bc694)
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 
71a459660SWolfgang Denk  * SPDX-License-Identifier:	GPL-2.0+
82439e4bfSJean-Christophe PLAGNIOL-VILLARD 
92439e4bfSJean-Christophe PLAGNIOL-VILLARD   (C)Copyright 1997-1998 DAVICOM Semiconductor,Inc. All Rights Reserved.
102439e4bfSJean-Christophe PLAGNIOL-VILLARD 
112439e4bfSJean-Christophe PLAGNIOL-VILLARD V0.11	06/20/2001	REG_0A bit3=1, default enable BP with DA match
122439e4bfSJean-Christophe PLAGNIOL-VILLARD 	06/22/2001	Support DM9801 progrmming
132439e4bfSJean-Christophe PLAGNIOL-VILLARD 			E3: R25 = ((R24 + NF) & 0x00ff) | 0xf000
142439e4bfSJean-Christophe PLAGNIOL-VILLARD 			E4: R25 = ((R24 + NF) & 0x00ff) | 0xc200
152439e4bfSJean-Christophe PLAGNIOL-VILLARD 		R17 = (R17 & 0xfff0) | NF + 3
162439e4bfSJean-Christophe PLAGNIOL-VILLARD 			E5: R25 = ((R24 + NF - 3) & 0x00ff) | 0xc200
172439e4bfSJean-Christophe PLAGNIOL-VILLARD 		R17 = (R17 & 0xfff0) | NF
182439e4bfSJean-Christophe PLAGNIOL-VILLARD 
192439e4bfSJean-Christophe PLAGNIOL-VILLARD v1.00			modify by simon 2001.9.5
202439e4bfSJean-Christophe PLAGNIOL-VILLARD 			change for kernel 2.4.x
212439e4bfSJean-Christophe PLAGNIOL-VILLARD 
222439e4bfSJean-Christophe PLAGNIOL-VILLARD v1.1   11/09/2001	fix force mode bug
232439e4bfSJean-Christophe PLAGNIOL-VILLARD 
242439e4bfSJean-Christophe PLAGNIOL-VILLARD v1.2   03/18/2003       Weilun Huang <weilun_huang@davicom.com.tw>:
252439e4bfSJean-Christophe PLAGNIOL-VILLARD 			Fixed phy reset.
262439e4bfSJean-Christophe PLAGNIOL-VILLARD 			Added tx/rx 32 bit mode.
272439e4bfSJean-Christophe PLAGNIOL-VILLARD 			Cleaned up for kernel merge.
282439e4bfSJean-Christophe PLAGNIOL-VILLARD 
292439e4bfSJean-Christophe PLAGNIOL-VILLARD --------------------------------------
302439e4bfSJean-Christophe PLAGNIOL-VILLARD 
31a101361bSRemy Bohmer        12/15/2003       Initial port to u-boot by
32a101361bSRemy Bohmer        			Sascha Hauer <saschahauer@web.de>
33a101361bSRemy Bohmer 
34a101361bSRemy Bohmer        06/03/2008	Remy Bohmer <linux@bohmer.net>
35850ba755SRemy Bohmer 			- Fixed the driver to work with DM9000A.
36850ba755SRemy Bohmer 			  (check on ISR receive status bit before reading the
37850ba755SRemy Bohmer 			  FIFO as described in DM9000 programming guide and
38850ba755SRemy Bohmer 			  application notes)
39a101361bSRemy Bohmer 			- Added autodetect of databus width.
40134e2662SRemy Bohmer 			- Made debug code compile again.
41acba3184SRemy Bohmer 			- Adapt eth_send such that it matches the DM9000*
42acba3184SRemy Bohmer 			  application notes. Needed to make it work properly
43acba3184SRemy Bohmer 			  for DM9000A.
44fbcb7eceSRemy Bohmer 			- Adapted reset procedure to match DM9000 application
45fbcb7eceSRemy Bohmer 			  notes (i.e. double reset)
4698291e2eSRemy Bohmer 			- some minor code cleanups
47a101361bSRemy Bohmer 			These changes are tested with DM9000{A,EP,E} together
48e5a3bc24SRemy Bohmer 			with a 200MHz Atmel AT91SAM9261 core
492439e4bfSJean-Christophe PLAGNIOL-VILLARD 
50d26b739aSAndrew Dyer TODO: external MII is not functional, only internal at the moment.
512439e4bfSJean-Christophe PLAGNIOL-VILLARD */
522439e4bfSJean-Christophe PLAGNIOL-VILLARD 
532439e4bfSJean-Christophe PLAGNIOL-VILLARD #include <common.h>
542439e4bfSJean-Christophe PLAGNIOL-VILLARD #include <command.h>
552439e4bfSJean-Christophe PLAGNIOL-VILLARD #include <net.h>
562439e4bfSJean-Christophe PLAGNIOL-VILLARD #include <asm/io.h>
57e5a3bc24SRemy Bohmer #include <dm9000.h>
582439e4bfSJean-Christophe PLAGNIOL-VILLARD 
592439e4bfSJean-Christophe PLAGNIOL-VILLARD #include "dm9000x.h"
602439e4bfSJean-Christophe PLAGNIOL-VILLARD 
612439e4bfSJean-Christophe PLAGNIOL-VILLARD /* Board/System/Debug information/definition ---------------- */
622439e4bfSJean-Christophe PLAGNIOL-VILLARD 
632439e4bfSJean-Christophe PLAGNIOL-VILLARD /* #define CONFIG_DM9000_DEBUG */
642439e4bfSJean-Christophe PLAGNIOL-VILLARD 
652439e4bfSJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_DM9000_DEBUG
662439e4bfSJean-Christophe PLAGNIOL-VILLARD #define DM9000_DBG(fmt,args...) printf(fmt, ##args)
67134e2662SRemy Bohmer #define DM9000_DMP_PACKET(func,packet,length)  \
68134e2662SRemy Bohmer 	do { \
69134e2662SRemy Bohmer 		int i; 							\
70076cd24cSThomas Weber 		printf("%s: length: %d\n", func, length);		\
71134e2662SRemy Bohmer 		for (i = 0; i < length; i++) {				\
72134e2662SRemy Bohmer 			if (i % 8 == 0)					\
73134e2662SRemy Bohmer 				printf("\n%s: %02x: ", func, i);	\
74134e2662SRemy Bohmer 			printf("%02x ", ((unsigned char *) packet)[i]);	\
75134e2662SRemy Bohmer 		} printf("\n");						\
76134e2662SRemy Bohmer 	} while(0)
77134e2662SRemy Bohmer #else
782439e4bfSJean-Christophe PLAGNIOL-VILLARD #define DM9000_DBG(fmt,args...)
79134e2662SRemy Bohmer #define DM9000_DMP_PACKET(func,packet,length)
80134e2662SRemy Bohmer #endif
81134e2662SRemy Bohmer 
822439e4bfSJean-Christophe PLAGNIOL-VILLARD /* Structure/enum declaration ------------------------------- */
832439e4bfSJean-Christophe PLAGNIOL-VILLARD typedef struct board_info {
842439e4bfSJean-Christophe PLAGNIOL-VILLARD 	u32 runt_length_counter;	/* counter: RX length < 64byte */
852439e4bfSJean-Christophe PLAGNIOL-VILLARD 	u32 long_length_counter;	/* counter: RX length > 1514byte */
862439e4bfSJean-Christophe PLAGNIOL-VILLARD 	u32 reset_counter;	/* counter: RESET */
872439e4bfSJean-Christophe PLAGNIOL-VILLARD 	u32 reset_tx_timeout;	/* RESET caused by TX Timeout */
882439e4bfSJean-Christophe PLAGNIOL-VILLARD 	u32 reset_rx_status;	/* RESET caused by RX Statsus wrong */
892439e4bfSJean-Christophe PLAGNIOL-VILLARD 	u16 tx_pkt_cnt;
902439e4bfSJean-Christophe PLAGNIOL-VILLARD 	u16 queue_start_addr;
912439e4bfSJean-Christophe PLAGNIOL-VILLARD 	u16 dbug_cnt;
922439e4bfSJean-Christophe PLAGNIOL-VILLARD 	u8 phy_addr;
932439e4bfSJean-Christophe PLAGNIOL-VILLARD 	u8 device_wait_reset;	/* device state */
942439e4bfSJean-Christophe PLAGNIOL-VILLARD 	unsigned char srom[128];
950e38c938SRemy Bohmer 	void (*outblk)(volatile void *data_ptr, int count);
96a101361bSRemy Bohmer 	void (*inblk)(void *data_ptr, int count);
97a101361bSRemy Bohmer 	void (*rx_status)(u16 *RxStatus, u16 *RxLen);
9860f61e6dSRemy Bohmer 	struct eth_device netdev;
992439e4bfSJean-Christophe PLAGNIOL-VILLARD } board_info_t;
100a101361bSRemy Bohmer static board_info_t dm9000_info;
1012439e4bfSJean-Christophe PLAGNIOL-VILLARD 
10260f61e6dSRemy Bohmer 
1032439e4bfSJean-Christophe PLAGNIOL-VILLARD /* function declaration ------------------------------------- */
1042439e4bfSJean-Christophe PLAGNIOL-VILLARD static int dm9000_probe(void);
10509c04c20SAndy Fleming static u16 dm9000_phy_read(int);
10609c04c20SAndy Fleming static void dm9000_phy_write(int, u16);
1072439e4bfSJean-Christophe PLAGNIOL-VILLARD static u8 DM9000_ior(int);
1082439e4bfSJean-Christophe PLAGNIOL-VILLARD static void DM9000_iow(int reg, u8 value);
1092439e4bfSJean-Christophe PLAGNIOL-VILLARD 
1102439e4bfSJean-Christophe PLAGNIOL-VILLARD /* DM9000 network board routine ---------------------------- */
1115c1d082bSJason Jin #ifndef CONFIG_DM9000_BYTE_SWAPPED
11267bee2fbSMike Frysinger #define DM9000_outb(d,r) writeb(d, (volatile u8 *)(r))
11367bee2fbSMike Frysinger #define DM9000_outw(d,r) writew(d, (volatile u16 *)(r))
11467bee2fbSMike Frysinger #define DM9000_outl(d,r) writel(d, (volatile u32 *)(r))
11567bee2fbSMike Frysinger #define DM9000_inb(r) readb((volatile u8 *)(r))
11667bee2fbSMike Frysinger #define DM9000_inw(r) readw((volatile u16 *)(r))
11767bee2fbSMike Frysinger #define DM9000_inl(r) readl((volatile u32 *)(r))
1185c1d082bSJason Jin #else
1195c1d082bSJason Jin #define DM9000_outb(d, r) __raw_writeb(d, r)
1205c1d082bSJason Jin #define DM9000_outw(d, r) __raw_writew(d, r)
1215c1d082bSJason Jin #define DM9000_outl(d, r) __raw_writel(d, r)
1225c1d082bSJason Jin #define DM9000_inb(r) __raw_readb(r)
1235c1d082bSJason Jin #define DM9000_inw(r) __raw_readw(r)
1245c1d082bSJason Jin #define DM9000_inl(r) __raw_readl(r)
1255c1d082bSJason Jin #endif
1262439e4bfSJean-Christophe PLAGNIOL-VILLARD 
1272439e4bfSJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_DM9000_DEBUG
1282439e4bfSJean-Christophe PLAGNIOL-VILLARD static void
1292439e4bfSJean-Christophe PLAGNIOL-VILLARD dump_regs(void)
1302439e4bfSJean-Christophe PLAGNIOL-VILLARD {
1312439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DM9000_DBG("\n");
1322439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DM9000_DBG("NCR   (0x00): %02x\n", DM9000_ior(0));
1332439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DM9000_DBG("NSR   (0x01): %02x\n", DM9000_ior(1));
1342439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DM9000_DBG("TCR   (0x02): %02x\n", DM9000_ior(2));
1352439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DM9000_DBG("TSRI  (0x03): %02x\n", DM9000_ior(3));
1362439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DM9000_DBG("TSRII (0x04): %02x\n", DM9000_ior(4));
1372439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DM9000_DBG("RCR   (0x05): %02x\n", DM9000_ior(5));
1382439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DM9000_DBG("RSR   (0x06): %02x\n", DM9000_ior(6));
139134e2662SRemy Bohmer 	DM9000_DBG("ISR   (0xFE): %02x\n", DM9000_ior(DM9000_ISR));
1402439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DM9000_DBG("\n");
1412439e4bfSJean-Christophe PLAGNIOL-VILLARD }
142a101361bSRemy Bohmer #endif
143a101361bSRemy Bohmer 
1440e38c938SRemy Bohmer static void dm9000_outblk_8bit(volatile void *data_ptr, int count)
145a101361bSRemy Bohmer {
146a101361bSRemy Bohmer 	int i;
147a101361bSRemy Bohmer 	for (i = 0; i < count; i++)
148a101361bSRemy Bohmer 		DM9000_outb((((u8 *) data_ptr)[i] & 0xff), DM9000_DATA);
149a101361bSRemy Bohmer }
150a101361bSRemy Bohmer 
1510e38c938SRemy Bohmer static void dm9000_outblk_16bit(volatile void *data_ptr, int count)
152a101361bSRemy Bohmer {
153a101361bSRemy Bohmer 	int i;
154a101361bSRemy Bohmer 	u32 tmplen = (count + 1) / 2;
155a101361bSRemy Bohmer 
156a101361bSRemy Bohmer 	for (i = 0; i < tmplen; i++)
157a101361bSRemy Bohmer 		DM9000_outw(((u16 *) data_ptr)[i], DM9000_DATA);
158a101361bSRemy Bohmer }
1590e38c938SRemy Bohmer static void dm9000_outblk_32bit(volatile void *data_ptr, int count)
160a101361bSRemy Bohmer {
161a101361bSRemy Bohmer 	int i;
162a101361bSRemy Bohmer 	u32 tmplen = (count + 3) / 4;
163a101361bSRemy Bohmer 
164a101361bSRemy Bohmer 	for (i = 0; i < tmplen; i++)
165a101361bSRemy Bohmer 		DM9000_outl(((u32 *) data_ptr)[i], DM9000_DATA);
166a101361bSRemy Bohmer }
167a101361bSRemy Bohmer 
168a101361bSRemy Bohmer static void dm9000_inblk_8bit(void *data_ptr, int count)
169a101361bSRemy Bohmer {
170a101361bSRemy Bohmer 	int i;
171a101361bSRemy Bohmer 	for (i = 0; i < count; i++)
172a101361bSRemy Bohmer 		((u8 *) data_ptr)[i] = DM9000_inb(DM9000_DATA);
173a101361bSRemy Bohmer }
174a101361bSRemy Bohmer 
175a101361bSRemy Bohmer static void dm9000_inblk_16bit(void *data_ptr, int count)
176a101361bSRemy Bohmer {
177a101361bSRemy Bohmer 	int i;
178a101361bSRemy Bohmer 	u32 tmplen = (count + 1) / 2;
179a101361bSRemy Bohmer 
180a101361bSRemy Bohmer 	for (i = 0; i < tmplen; i++)
181a101361bSRemy Bohmer 		((u16 *) data_ptr)[i] = DM9000_inw(DM9000_DATA);
182a101361bSRemy Bohmer }
183a101361bSRemy Bohmer static void dm9000_inblk_32bit(void *data_ptr, int count)
184a101361bSRemy Bohmer {
185a101361bSRemy Bohmer 	int i;
186a101361bSRemy Bohmer 	u32 tmplen = (count + 3) / 4;
187a101361bSRemy Bohmer 
188a101361bSRemy Bohmer 	for (i = 0; i < tmplen; i++)
189a101361bSRemy Bohmer 		((u32 *) data_ptr)[i] = DM9000_inl(DM9000_DATA);
190a101361bSRemy Bohmer }
191a101361bSRemy Bohmer 
192a101361bSRemy Bohmer static void dm9000_rx_status_32bit(u16 *RxStatus, u16 *RxLen)
193a101361bSRemy Bohmer {
194d6ee5fa4SRemy Bohmer 	u32 tmpdata;
195a101361bSRemy Bohmer 
196a101361bSRemy Bohmer 	DM9000_outb(DM9000_MRCMD, DM9000_IO);
197a101361bSRemy Bohmer 
198d6ee5fa4SRemy Bohmer 	tmpdata = DM9000_inl(DM9000_DATA);
199943b825bSTsiChung Liew 	*RxStatus = __le16_to_cpu(tmpdata);
200943b825bSTsiChung Liew 	*RxLen = __le16_to_cpu(tmpdata >> 16);
201a101361bSRemy Bohmer }
202a101361bSRemy Bohmer 
203a101361bSRemy Bohmer static void dm9000_rx_status_16bit(u16 *RxStatus, u16 *RxLen)
204a101361bSRemy Bohmer {
205a101361bSRemy Bohmer 	DM9000_outb(DM9000_MRCMD, DM9000_IO);
206a101361bSRemy Bohmer 
207943b825bSTsiChung Liew 	*RxStatus = __le16_to_cpu(DM9000_inw(DM9000_DATA));
208943b825bSTsiChung Liew 	*RxLen = __le16_to_cpu(DM9000_inw(DM9000_DATA));
209a101361bSRemy Bohmer }
210a101361bSRemy Bohmer 
211a101361bSRemy Bohmer static void dm9000_rx_status_8bit(u16 *RxStatus, u16 *RxLen)
212a101361bSRemy Bohmer {
213a101361bSRemy Bohmer 	DM9000_outb(DM9000_MRCMD, DM9000_IO);
214a101361bSRemy Bohmer 
215943b825bSTsiChung Liew 	*RxStatus =
216943b825bSTsiChung Liew 	    __le16_to_cpu(DM9000_inb(DM9000_DATA) +
217943b825bSTsiChung Liew 			  (DM9000_inb(DM9000_DATA) << 8));
218943b825bSTsiChung Liew 	*RxLen =
219943b825bSTsiChung Liew 	    __le16_to_cpu(DM9000_inb(DM9000_DATA) +
220943b825bSTsiChung Liew 			  (DM9000_inb(DM9000_DATA) << 8));
221a101361bSRemy Bohmer }
2222439e4bfSJean-Christophe PLAGNIOL-VILLARD 
2232439e4bfSJean-Christophe PLAGNIOL-VILLARD /*
2242439e4bfSJean-Christophe PLAGNIOL-VILLARD   Search DM9000 board, allocate space and register it
2252439e4bfSJean-Christophe PLAGNIOL-VILLARD */
2262439e4bfSJean-Christophe PLAGNIOL-VILLARD int
2272439e4bfSJean-Christophe PLAGNIOL-VILLARD dm9000_probe(void)
2282439e4bfSJean-Christophe PLAGNIOL-VILLARD {
2292439e4bfSJean-Christophe PLAGNIOL-VILLARD 	u32 id_val;
2302439e4bfSJean-Christophe PLAGNIOL-VILLARD 	id_val = DM9000_ior(DM9000_VIDL);
2312439e4bfSJean-Christophe PLAGNIOL-VILLARD 	id_val |= DM9000_ior(DM9000_VIDH) << 8;
2322439e4bfSJean-Christophe PLAGNIOL-VILLARD 	id_val |= DM9000_ior(DM9000_PIDL) << 16;
2332439e4bfSJean-Christophe PLAGNIOL-VILLARD 	id_val |= DM9000_ior(DM9000_PIDH) << 24;
2342439e4bfSJean-Christophe PLAGNIOL-VILLARD 	if (id_val == DM9000_ID) {
2352439e4bfSJean-Christophe PLAGNIOL-VILLARD 		printf("dm9000 i/o: 0x%x, id: 0x%x \n", CONFIG_DM9000_BASE,
2362439e4bfSJean-Christophe PLAGNIOL-VILLARD 		       id_val);
2372439e4bfSJean-Christophe PLAGNIOL-VILLARD 		return 0;
2382439e4bfSJean-Christophe PLAGNIOL-VILLARD 	} else {
2392439e4bfSJean-Christophe PLAGNIOL-VILLARD 		printf("dm9000 not found at 0x%08x id: 0x%08x\n",
2402439e4bfSJean-Christophe PLAGNIOL-VILLARD 		       CONFIG_DM9000_BASE, id_val);
2412439e4bfSJean-Christophe PLAGNIOL-VILLARD 		return -1;
2422439e4bfSJean-Christophe PLAGNIOL-VILLARD 	}
2432439e4bfSJean-Christophe PLAGNIOL-VILLARD }
2442439e4bfSJean-Christophe PLAGNIOL-VILLARD 
2452439e4bfSJean-Christophe PLAGNIOL-VILLARD /* General Purpose dm9000 reset routine */
2462439e4bfSJean-Christophe PLAGNIOL-VILLARD static void
2472439e4bfSJean-Christophe PLAGNIOL-VILLARD dm9000_reset(void)
2482439e4bfSJean-Christophe PLAGNIOL-VILLARD {
249fbcb7eceSRemy Bohmer 	DM9000_DBG("resetting DM9000\n");
250fbcb7eceSRemy Bohmer 
251fbcb7eceSRemy Bohmer 	/* Reset DM9000,
252fbcb7eceSRemy Bohmer 	   see DM9000 Application Notes V1.22 Jun 11, 2004 page 29 */
253fbcb7eceSRemy Bohmer 
254d26b739aSAndrew Dyer 	/* DEBUG: Make all GPIO0 outputs, all others inputs */
255d26b739aSAndrew Dyer 	DM9000_iow(DM9000_GPCR, GPCR_GPIO0_OUT);
256fbcb7eceSRemy Bohmer 	/* Step 1: Power internal PHY by writing 0 to GPIO0 pin */
257fbcb7eceSRemy Bohmer 	DM9000_iow(DM9000_GPR, 0);
258fbcb7eceSRemy Bohmer 	/* Step 2: Software reset */
259d26b739aSAndrew Dyer 	DM9000_iow(DM9000_NCR, (NCR_LBK_INT_MAC | NCR_RST));
260fbcb7eceSRemy Bohmer 
261fbcb7eceSRemy Bohmer 	do {
262fbcb7eceSRemy Bohmer 		DM9000_DBG("resetting the DM9000, 1st reset\n");
263fbcb7eceSRemy Bohmer 		udelay(25); /* Wait at least 20 us */
264fbcb7eceSRemy Bohmer 	} while (DM9000_ior(DM9000_NCR) & 1);
265fbcb7eceSRemy Bohmer 
266fbcb7eceSRemy Bohmer 	DM9000_iow(DM9000_NCR, 0);
267d26b739aSAndrew Dyer 	DM9000_iow(DM9000_NCR, (NCR_LBK_INT_MAC | NCR_RST)); /* Issue a second reset */
268fbcb7eceSRemy Bohmer 
269fbcb7eceSRemy Bohmer 	do {
270fbcb7eceSRemy Bohmer 		DM9000_DBG("resetting the DM9000, 2nd reset\n");
271fbcb7eceSRemy Bohmer 		udelay(25); /* Wait at least 20 us */
272fbcb7eceSRemy Bohmer 	} while (DM9000_ior(DM9000_NCR) & 1);
273fbcb7eceSRemy Bohmer 
274fbcb7eceSRemy Bohmer 	/* Check whether the ethernet controller is present */
275fbcb7eceSRemy Bohmer 	if ((DM9000_ior(DM9000_PIDL) != 0x0) ||
276fbcb7eceSRemy Bohmer 	    (DM9000_ior(DM9000_PIDH) != 0x90))
277fbcb7eceSRemy Bohmer 		printf("ERROR: resetting DM9000 -> not responding\n");
2782439e4bfSJean-Christophe PLAGNIOL-VILLARD }
2792439e4bfSJean-Christophe PLAGNIOL-VILLARD 
28060f61e6dSRemy Bohmer /* Initialize dm9000 board
2812439e4bfSJean-Christophe PLAGNIOL-VILLARD */
28260f61e6dSRemy Bohmer static int dm9000_init(struct eth_device *dev, bd_t *bd)
2832439e4bfSJean-Christophe PLAGNIOL-VILLARD {
2842439e4bfSJean-Christophe PLAGNIOL-VILLARD 	int i, oft, lnk;
285a101361bSRemy Bohmer 	u8 io_mode;
286a101361bSRemy Bohmer 	struct board_info *db = &dm9000_info;
287a101361bSRemy Bohmer 
28860f61e6dSRemy Bohmer 	DM9000_DBG("%s\n", __func__);
2892439e4bfSJean-Christophe PLAGNIOL-VILLARD 
2902439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* RESET device */
2912439e4bfSJean-Christophe PLAGNIOL-VILLARD 	dm9000_reset();
292d26b739aSAndrew Dyer 
293d26b739aSAndrew Dyer 	if (dm9000_probe() < 0)
294d26b739aSAndrew Dyer 		return -1;
2952439e4bfSJean-Christophe PLAGNIOL-VILLARD 
296a101361bSRemy Bohmer 	/* Auto-detect 8/16/32 bit mode, ISR Bit 6+7 indicate bus width */
297a101361bSRemy Bohmer 	io_mode = DM9000_ior(DM9000_ISR) >> 6;
298a101361bSRemy Bohmer 
299a101361bSRemy Bohmer 	switch (io_mode) {
300a101361bSRemy Bohmer 	case 0x0:  /* 16-bit mode */
301a101361bSRemy Bohmer 		printf("DM9000: running in 16 bit mode\n");
302a101361bSRemy Bohmer 		db->outblk    = dm9000_outblk_16bit;
303a101361bSRemy Bohmer 		db->inblk     = dm9000_inblk_16bit;
304a101361bSRemy Bohmer 		db->rx_status = dm9000_rx_status_16bit;
305a101361bSRemy Bohmer 		break;
306a101361bSRemy Bohmer 	case 0x01:  /* 32-bit mode */
307a101361bSRemy Bohmer 		printf("DM9000: running in 32 bit mode\n");
308a101361bSRemy Bohmer 		db->outblk    = dm9000_outblk_32bit;
309a101361bSRemy Bohmer 		db->inblk     = dm9000_inblk_32bit;
310a101361bSRemy Bohmer 		db->rx_status = dm9000_rx_status_32bit;
311a101361bSRemy Bohmer 		break;
312a101361bSRemy Bohmer 	case 0x02: /* 8 bit mode */
313a101361bSRemy Bohmer 		printf("DM9000: running in 8 bit mode\n");
314a101361bSRemy Bohmer 		db->outblk    = dm9000_outblk_8bit;
315a101361bSRemy Bohmer 		db->inblk     = dm9000_inblk_8bit;
316a101361bSRemy Bohmer 		db->rx_status = dm9000_rx_status_8bit;
317a101361bSRemy Bohmer 		break;
318a101361bSRemy Bohmer 	default:
319a101361bSRemy Bohmer 		/* Assume 8 bit mode, will probably not work anyway */
320a101361bSRemy Bohmer 		printf("DM9000: Undefined IO-mode:0x%x\n", io_mode);
321a101361bSRemy Bohmer 		db->outblk    = dm9000_outblk_8bit;
322a101361bSRemy Bohmer 		db->inblk     = dm9000_inblk_8bit;
323a101361bSRemy Bohmer 		db->rx_status = dm9000_rx_status_8bit;
324a101361bSRemy Bohmer 		break;
325a101361bSRemy Bohmer 	}
326a101361bSRemy Bohmer 
327d26b739aSAndrew Dyer 	/* Program operating register, only internal phy supported */
32898291e2eSRemy Bohmer 	DM9000_iow(DM9000_NCR, 0x0);
32998291e2eSRemy Bohmer 	/* TX Polling clear */
33098291e2eSRemy Bohmer 	DM9000_iow(DM9000_TCR, 0);
33198291e2eSRemy Bohmer 	/* Less 3Kb, 200us */
332d26b739aSAndrew Dyer 	DM9000_iow(DM9000_BPTR, BPTR_BPHW(3) | BPTR_JPT_600US);
33398291e2eSRemy Bohmer 	/* Flow Control : High/Low Water */
33498291e2eSRemy Bohmer 	DM9000_iow(DM9000_FCTR, FCTR_HWOT(3) | FCTR_LWOT(8));
33598291e2eSRemy Bohmer 	/* SH FIXME: This looks strange! Flow Control */
33698291e2eSRemy Bohmer 	DM9000_iow(DM9000_FCR, 0x0);
33798291e2eSRemy Bohmer 	/* Special Mode */
33898291e2eSRemy Bohmer 	DM9000_iow(DM9000_SMCR, 0);
33998291e2eSRemy Bohmer 	/* clear TX status */
34098291e2eSRemy Bohmer 	DM9000_iow(DM9000_NSR, NSR_WAKEST | NSR_TX2END | NSR_TX1END);
34198291e2eSRemy Bohmer 	/* Clear interrupt status */
342d26b739aSAndrew Dyer 	DM9000_iow(DM9000_ISR, ISR_ROOS | ISR_ROS | ISR_PTS | ISR_PRS);
3432439e4bfSJean-Christophe PLAGNIOL-VILLARD 
34407754372SBen Warren 	printf("MAC: %pM\n", dev->enetaddr);
3450adb5b76SJoe Hershberger 	if (!is_valid_ethaddr(dev->enetaddr)) {
346c583ee16SAndrew Ruder 		printf("WARNING: Bad MAC address (uninitialized EEPROM?)\n");
347c583ee16SAndrew Ruder 	}
348d26b739aSAndrew Dyer 
349d26b739aSAndrew Dyer 	/* fill device MAC address registers */
350d26b739aSAndrew Dyer 	for (i = 0, oft = DM9000_PAR; i < 6; i++, oft++)
35107754372SBen Warren 		DM9000_iow(oft, dev->enetaddr[i]);
3522439e4bfSJean-Christophe PLAGNIOL-VILLARD 	for (i = 0, oft = 0x16; i < 8; i++, oft++)
3532439e4bfSJean-Christophe PLAGNIOL-VILLARD 		DM9000_iow(oft, 0xff);
3542439e4bfSJean-Christophe PLAGNIOL-VILLARD 
3552439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* read back mac, just to be sure */
3562439e4bfSJean-Christophe PLAGNIOL-VILLARD 	for (i = 0, oft = 0x10; i < 6; i++, oft++)
3572439e4bfSJean-Christophe PLAGNIOL-VILLARD 		DM9000_DBG("%02x:", DM9000_ior(oft));
3582439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DM9000_DBG("\n");
3592439e4bfSJean-Christophe PLAGNIOL-VILLARD 
3602439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* Activate DM9000 */
36198291e2eSRemy Bohmer 	/* RX enable */
36298291e2eSRemy Bohmer 	DM9000_iow(DM9000_RCR, RCR_DIS_LONG | RCR_DIS_CRC | RCR_RXEN);
36398291e2eSRemy Bohmer 	/* Enable TX/RX interrupt mask */
36498291e2eSRemy Bohmer 	DM9000_iow(DM9000_IMR, IMR_PAR);
36598291e2eSRemy Bohmer 
3662439e4bfSJean-Christophe PLAGNIOL-VILLARD 	i = 0;
36709c04c20SAndy Fleming 	while (!(dm9000_phy_read(1) & 0x20)) {	/* autonegation complete bit */
3682439e4bfSJean-Christophe PLAGNIOL-VILLARD 		udelay(1000);
3692439e4bfSJean-Christophe PLAGNIOL-VILLARD 		i++;
3702439e4bfSJean-Christophe PLAGNIOL-VILLARD 		if (i == 10000) {
3712439e4bfSJean-Christophe PLAGNIOL-VILLARD 			printf("could not establish link\n");
3722439e4bfSJean-Christophe PLAGNIOL-VILLARD 			return 0;
3732439e4bfSJean-Christophe PLAGNIOL-VILLARD 		}
3742439e4bfSJean-Christophe PLAGNIOL-VILLARD 	}
3752439e4bfSJean-Christophe PLAGNIOL-VILLARD 
3762439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* see what we've got */
37709c04c20SAndy Fleming 	lnk = dm9000_phy_read(17) >> 12;
3782439e4bfSJean-Christophe PLAGNIOL-VILLARD 	printf("operating at ");
3792439e4bfSJean-Christophe PLAGNIOL-VILLARD 	switch (lnk) {
3802439e4bfSJean-Christophe PLAGNIOL-VILLARD 	case 1:
3812439e4bfSJean-Christophe PLAGNIOL-VILLARD 		printf("10M half duplex ");
3822439e4bfSJean-Christophe PLAGNIOL-VILLARD 		break;
3832439e4bfSJean-Christophe PLAGNIOL-VILLARD 	case 2:
3842439e4bfSJean-Christophe PLAGNIOL-VILLARD 		printf("10M full duplex ");
3852439e4bfSJean-Christophe PLAGNIOL-VILLARD 		break;
3862439e4bfSJean-Christophe PLAGNIOL-VILLARD 	case 4:
3872439e4bfSJean-Christophe PLAGNIOL-VILLARD 		printf("100M half duplex ");
3882439e4bfSJean-Christophe PLAGNIOL-VILLARD 		break;
3892439e4bfSJean-Christophe PLAGNIOL-VILLARD 	case 8:
3902439e4bfSJean-Christophe PLAGNIOL-VILLARD 		printf("100M full duplex ");
3912439e4bfSJean-Christophe PLAGNIOL-VILLARD 		break;
3922439e4bfSJean-Christophe PLAGNIOL-VILLARD 	default:
3932439e4bfSJean-Christophe PLAGNIOL-VILLARD 		printf("unknown: %d ", lnk);
3942439e4bfSJean-Christophe PLAGNIOL-VILLARD 		break;
3952439e4bfSJean-Christophe PLAGNIOL-VILLARD 	}
3962439e4bfSJean-Christophe PLAGNIOL-VILLARD 	printf("mode\n");
3972439e4bfSJean-Christophe PLAGNIOL-VILLARD 	return 0;
3982439e4bfSJean-Christophe PLAGNIOL-VILLARD }
3992439e4bfSJean-Christophe PLAGNIOL-VILLARD 
4002439e4bfSJean-Christophe PLAGNIOL-VILLARD /*
4012439e4bfSJean-Christophe PLAGNIOL-VILLARD   Hardware start transmission.
4022439e4bfSJean-Christophe PLAGNIOL-VILLARD   Send a packet to media from the upper layer.
4032439e4bfSJean-Christophe PLAGNIOL-VILLARD */
4047f9a8a67SJoe Hershberger static int dm9000_send(struct eth_device *netdev, void *packet, int length)
4052439e4bfSJean-Christophe PLAGNIOL-VILLARD {
4062439e4bfSJean-Christophe PLAGNIOL-VILLARD 	int tmo;
407a101361bSRemy Bohmer 	struct board_info *db = &dm9000_info;
408a101361bSRemy Bohmer 
40960f61e6dSRemy Bohmer 	DM9000_DMP_PACKET(__func__ , packet, length);
4102439e4bfSJean-Christophe PLAGNIOL-VILLARD 
411acba3184SRemy Bohmer 	DM9000_iow(DM9000_ISR, IMR_PTM); /* Clear Tx bit in ISR */
412acba3184SRemy Bohmer 
4132439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* Move data to DM9000 TX RAM */
414acba3184SRemy Bohmer 	DM9000_outb(DM9000_MWCMD, DM9000_IO); /* Prepare for TX-data */
4152439e4bfSJean-Christophe PLAGNIOL-VILLARD 
416a101361bSRemy Bohmer 	/* push the data to the TX-fifo */
4170e38c938SRemy Bohmer 	(db->outblk)(packet, length);
4182439e4bfSJean-Christophe PLAGNIOL-VILLARD 
4192439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* Set TX length to DM9000 */
4202439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DM9000_iow(DM9000_TXPLL, length & 0xff);
4212439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DM9000_iow(DM9000_TXPLH, (length >> 8) & 0xff);
4222439e4bfSJean-Christophe PLAGNIOL-VILLARD 
4232439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* Issue TX polling command */
4242439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DM9000_iow(DM9000_TCR, TCR_TXREQ); /* Cleared after TX complete */
4252439e4bfSJean-Christophe PLAGNIOL-VILLARD 
4262439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* wait for end of transmission */
4276d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 	tmo = get_timer(0) + 5 * CONFIG_SYS_HZ;
428acba3184SRemy Bohmer 	while ( !(DM9000_ior(DM9000_NSR) & (NSR_TX1END | NSR_TX2END)) ||
429acba3184SRemy Bohmer 		!(DM9000_ior(DM9000_ISR) & IMR_PTM) ) {
4302439e4bfSJean-Christophe PLAGNIOL-VILLARD 		if (get_timer(0) >= tmo) {
4312439e4bfSJean-Christophe PLAGNIOL-VILLARD 			printf("transmission timeout\n");
4322439e4bfSJean-Christophe PLAGNIOL-VILLARD 			break;
4332439e4bfSJean-Christophe PLAGNIOL-VILLARD 		}
4342439e4bfSJean-Christophe PLAGNIOL-VILLARD 	}
435acba3184SRemy Bohmer 	DM9000_iow(DM9000_ISR, IMR_PTM); /* Clear Tx bit in ISR */
436acba3184SRemy Bohmer 
4372439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DM9000_DBG("transmit done\n\n");
4382439e4bfSJean-Christophe PLAGNIOL-VILLARD 	return 0;
4392439e4bfSJean-Christophe PLAGNIOL-VILLARD }
4402439e4bfSJean-Christophe PLAGNIOL-VILLARD 
4412439e4bfSJean-Christophe PLAGNIOL-VILLARD /*
4422439e4bfSJean-Christophe PLAGNIOL-VILLARD   Stop the interface.
4432439e4bfSJean-Christophe PLAGNIOL-VILLARD   The interface is stopped when it is brought.
4442439e4bfSJean-Christophe PLAGNIOL-VILLARD */
44560f61e6dSRemy Bohmer static void dm9000_halt(struct eth_device *netdev)
4462439e4bfSJean-Christophe PLAGNIOL-VILLARD {
44760f61e6dSRemy Bohmer 	DM9000_DBG("%s\n", __func__);
4482439e4bfSJean-Christophe PLAGNIOL-VILLARD 
4492439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* RESET devie */
45009c04c20SAndy Fleming 	dm9000_phy_write(0, 0x8000);	/* PHY RESET */
4512439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DM9000_iow(DM9000_GPR, 0x01);	/* Power-Down PHY */
4522439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DM9000_iow(DM9000_IMR, 0x80);	/* Disable all interrupt */
4532439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DM9000_iow(DM9000_RCR, 0x00);	/* Disable RX */
4542439e4bfSJean-Christophe PLAGNIOL-VILLARD }
4552439e4bfSJean-Christophe PLAGNIOL-VILLARD 
4562439e4bfSJean-Christophe PLAGNIOL-VILLARD /*
4572439e4bfSJean-Christophe PLAGNIOL-VILLARD   Received a packet and pass to upper layer
4582439e4bfSJean-Christophe PLAGNIOL-VILLARD */
45960f61e6dSRemy Bohmer static int dm9000_rx(struct eth_device *netdev)
4602439e4bfSJean-Christophe PLAGNIOL-VILLARD {
4611fd92db8SJoe Hershberger 	u8 rxbyte;
4621fd92db8SJoe Hershberger 	u8 *rdptr = (u8 *)net_rx_packets[0];
4632439e4bfSJean-Christophe PLAGNIOL-VILLARD 	u16 RxStatus, RxLen = 0;
464a101361bSRemy Bohmer 	struct board_info *db = &dm9000_info;
4652439e4bfSJean-Christophe PLAGNIOL-VILLARD 
466850ba755SRemy Bohmer 	/* Check packet ready or not, we must check
467850ba755SRemy Bohmer 	   the ISR status first for DM9000A */
468850ba755SRemy Bohmer 	if (!(DM9000_ior(DM9000_ISR) & 0x01)) /* Rx-ISR bit must be set. */
4692439e4bfSJean-Christophe PLAGNIOL-VILLARD 		return 0;
4702439e4bfSJean-Christophe PLAGNIOL-VILLARD 
471850ba755SRemy Bohmer 	DM9000_iow(DM9000_ISR, 0x01); /* clear PR status latched in bit 0 */
472850ba755SRemy Bohmer 
473850ba755SRemy Bohmer 	/* There is _at least_ 1 package in the fifo, read them all */
474850ba755SRemy Bohmer 	for (;;) {
475850ba755SRemy Bohmer 		DM9000_ior(DM9000_MRCMDX);	/* Dummy read */
476850ba755SRemy Bohmer 
4770e38c938SRemy Bohmer 		/* Get most updated data,
4780e38c938SRemy Bohmer 		   only look at bits 0:1, See application notes DM9000 */
4790e38c938SRemy Bohmer 		rxbyte = DM9000_inb(DM9000_DATA) & 0x03;
480850ba755SRemy Bohmer 
4812439e4bfSJean-Christophe PLAGNIOL-VILLARD 		/* Status check: this byte must be 0 or 1 */
482850ba755SRemy Bohmer 		if (rxbyte > DM9000_PKT_RDY) {
4832439e4bfSJean-Christophe PLAGNIOL-VILLARD 			DM9000_iow(DM9000_RCR, 0x00);	/* Stop Device */
4842439e4bfSJean-Christophe PLAGNIOL-VILLARD 			DM9000_iow(DM9000_ISR, 0x80);	/* Stop INT request */
485850ba755SRemy Bohmer 			printf("DM9000 error: status check fail: 0x%x\n",
486850ba755SRemy Bohmer 				rxbyte);
487850ba755SRemy Bohmer 			return 0;
4882439e4bfSJean-Christophe PLAGNIOL-VILLARD 		}
489850ba755SRemy Bohmer 
490850ba755SRemy Bohmer 		if (rxbyte != DM9000_PKT_RDY)
491850ba755SRemy Bohmer 			return 0; /* No packet received, ignore */
492850ba755SRemy Bohmer 
4932439e4bfSJean-Christophe PLAGNIOL-VILLARD 		DM9000_DBG("receiving packet\n");
4942439e4bfSJean-Christophe PLAGNIOL-VILLARD 
4952439e4bfSJean-Christophe PLAGNIOL-VILLARD 		/* A packet ready now  & Get status/length */
496a101361bSRemy Bohmer 		(db->rx_status)(&RxStatus, &RxLen);
4972439e4bfSJean-Christophe PLAGNIOL-VILLARD 
4982439e4bfSJean-Christophe PLAGNIOL-VILLARD 		DM9000_DBG("rx status: 0x%04x rx len: %d\n", RxStatus, RxLen);
4992439e4bfSJean-Christophe PLAGNIOL-VILLARD 
5002439e4bfSJean-Christophe PLAGNIOL-VILLARD 		/* Move data from DM9000 */
5012439e4bfSJean-Christophe PLAGNIOL-VILLARD 		/* Read received packet from RX SRAM */
502a101361bSRemy Bohmer 		(db->inblk)(rdptr, RxLen);
5032439e4bfSJean-Christophe PLAGNIOL-VILLARD 
5042439e4bfSJean-Christophe PLAGNIOL-VILLARD 		if ((RxStatus & 0xbf00) || (RxLen < 0x40)
5052439e4bfSJean-Christophe PLAGNIOL-VILLARD 			|| (RxLen > DM9000_PKT_MAX)) {
5062439e4bfSJean-Christophe PLAGNIOL-VILLARD 			if (RxStatus & 0x100) {
5072439e4bfSJean-Christophe PLAGNIOL-VILLARD 				printf("rx fifo error\n");
5082439e4bfSJean-Christophe PLAGNIOL-VILLARD 			}
5092439e4bfSJean-Christophe PLAGNIOL-VILLARD 			if (RxStatus & 0x200) {
5102439e4bfSJean-Christophe PLAGNIOL-VILLARD 				printf("rx crc error\n");
5112439e4bfSJean-Christophe PLAGNIOL-VILLARD 			}
5122439e4bfSJean-Christophe PLAGNIOL-VILLARD 			if (RxStatus & 0x8000) {
5132439e4bfSJean-Christophe PLAGNIOL-VILLARD 				printf("rx length error\n");
5142439e4bfSJean-Christophe PLAGNIOL-VILLARD 			}
5152439e4bfSJean-Christophe PLAGNIOL-VILLARD 			if (RxLen > DM9000_PKT_MAX) {
5162439e4bfSJean-Christophe PLAGNIOL-VILLARD 				printf("rx length too big\n");
5172439e4bfSJean-Christophe PLAGNIOL-VILLARD 				dm9000_reset();
5182439e4bfSJean-Christophe PLAGNIOL-VILLARD 			}
5192439e4bfSJean-Christophe PLAGNIOL-VILLARD 		} else {
52060f61e6dSRemy Bohmer 			DM9000_DMP_PACKET(__func__ , rdptr, RxLen);
5212439e4bfSJean-Christophe PLAGNIOL-VILLARD 
5222439e4bfSJean-Christophe PLAGNIOL-VILLARD 			DM9000_DBG("passing packet to upper layer\n");
5231fd92db8SJoe Hershberger 			net_process_received_packet(net_rx_packets[0], RxLen);
524850ba755SRemy Bohmer 		}
5252439e4bfSJean-Christophe PLAGNIOL-VILLARD 	}
5262439e4bfSJean-Christophe PLAGNIOL-VILLARD 	return 0;
5272439e4bfSJean-Christophe PLAGNIOL-VILLARD }
5282439e4bfSJean-Christophe PLAGNIOL-VILLARD 
5292439e4bfSJean-Christophe PLAGNIOL-VILLARD /*
5302439e4bfSJean-Christophe PLAGNIOL-VILLARD   Read a word data from SROM
5312439e4bfSJean-Christophe PLAGNIOL-VILLARD */
532e5a3bc24SRemy Bohmer #if !defined(CONFIG_DM9000_NO_SROM)
533e5a3bc24SRemy Bohmer void dm9000_read_srom_word(int offset, u8 *to)
5342439e4bfSJean-Christophe PLAGNIOL-VILLARD {
5352439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DM9000_iow(DM9000_EPAR, offset);
5362439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DM9000_iow(DM9000_EPCR, 0x4);
5372439e4bfSJean-Christophe PLAGNIOL-VILLARD 	udelay(8000);
5382439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DM9000_iow(DM9000_EPCR, 0x0);
539ad74cae9SDavid Brownell 	to[0] = DM9000_ior(DM9000_EPDRL);
540ad74cae9SDavid Brownell 	to[1] = DM9000_ior(DM9000_EPDRH);
5412439e4bfSJean-Christophe PLAGNIOL-VILLARD }
5422439e4bfSJean-Christophe PLAGNIOL-VILLARD 
543e5a3bc24SRemy Bohmer void dm9000_write_srom_word(int offset, u16 val)
5442439e4bfSJean-Christophe PLAGNIOL-VILLARD {
5452439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DM9000_iow(DM9000_EPAR, offset);
5462439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DM9000_iow(DM9000_EPDRH, ((val >> 8) & 0xff));
5472439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DM9000_iow(DM9000_EPDRL, (val & 0xff));
5482439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DM9000_iow(DM9000_EPCR, 0x12);
5492439e4bfSJean-Christophe PLAGNIOL-VILLARD 	udelay(8000);
5502439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DM9000_iow(DM9000_EPCR, 0);
5512439e4bfSJean-Christophe PLAGNIOL-VILLARD }
552e5a3bc24SRemy Bohmer #endif
5532439e4bfSJean-Christophe PLAGNIOL-VILLARD 
55407754372SBen Warren static void dm9000_get_enetaddr(struct eth_device *dev)
55507754372SBen Warren {
55607754372SBen Warren #if !defined(CONFIG_DM9000_NO_SROM)
55707754372SBen Warren 	int i;
55807754372SBen Warren 	for (i = 0; i < 3; i++)
55907754372SBen Warren 		dm9000_read_srom_word(i, dev->enetaddr + (2 * i));
56007754372SBen Warren #endif
56107754372SBen Warren }
56207754372SBen Warren 
5632439e4bfSJean-Christophe PLAGNIOL-VILLARD /*
5642439e4bfSJean-Christophe PLAGNIOL-VILLARD    Read a byte from I/O port
5652439e4bfSJean-Christophe PLAGNIOL-VILLARD */
5662439e4bfSJean-Christophe PLAGNIOL-VILLARD static u8
5672439e4bfSJean-Christophe PLAGNIOL-VILLARD DM9000_ior(int reg)
5682439e4bfSJean-Christophe PLAGNIOL-VILLARD {
5692439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DM9000_outb(reg, DM9000_IO);
5702439e4bfSJean-Christophe PLAGNIOL-VILLARD 	return DM9000_inb(DM9000_DATA);
5712439e4bfSJean-Christophe PLAGNIOL-VILLARD }
5722439e4bfSJean-Christophe PLAGNIOL-VILLARD 
5732439e4bfSJean-Christophe PLAGNIOL-VILLARD /*
5742439e4bfSJean-Christophe PLAGNIOL-VILLARD    Write a byte to I/O port
5752439e4bfSJean-Christophe PLAGNIOL-VILLARD */
5762439e4bfSJean-Christophe PLAGNIOL-VILLARD static void
5772439e4bfSJean-Christophe PLAGNIOL-VILLARD DM9000_iow(int reg, u8 value)
5782439e4bfSJean-Christophe PLAGNIOL-VILLARD {
5792439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DM9000_outb(reg, DM9000_IO);
5802439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DM9000_outb(value, DM9000_DATA);
5812439e4bfSJean-Christophe PLAGNIOL-VILLARD }
5822439e4bfSJean-Christophe PLAGNIOL-VILLARD 
5832439e4bfSJean-Christophe PLAGNIOL-VILLARD /*
5842439e4bfSJean-Christophe PLAGNIOL-VILLARD    Read a word from phyxcer
5852439e4bfSJean-Christophe PLAGNIOL-VILLARD */
5862439e4bfSJean-Christophe PLAGNIOL-VILLARD static u16
58709c04c20SAndy Fleming dm9000_phy_read(int reg)
5882439e4bfSJean-Christophe PLAGNIOL-VILLARD {
5892439e4bfSJean-Christophe PLAGNIOL-VILLARD 	u16 val;
5902439e4bfSJean-Christophe PLAGNIOL-VILLARD 
5912439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* Fill the phyxcer register into REG_0C */
5922439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DM9000_iow(DM9000_EPAR, DM9000_PHY | reg);
5932439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DM9000_iow(DM9000_EPCR, 0xc);	/* Issue phyxcer read command */
5942439e4bfSJean-Christophe PLAGNIOL-VILLARD 	udelay(100);			/* Wait read complete */
5952439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DM9000_iow(DM9000_EPCR, 0x0);	/* Clear phyxcer read command */
5962439e4bfSJean-Christophe PLAGNIOL-VILLARD 	val = (DM9000_ior(DM9000_EPDRH) << 8) | DM9000_ior(DM9000_EPDRL);
5972439e4bfSJean-Christophe PLAGNIOL-VILLARD 
5982439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* The read data keeps on REG_0D & REG_0E */
59909c04c20SAndy Fleming 	DM9000_DBG("dm9000_phy_read(0x%x): 0x%x\n", reg, val);
6002439e4bfSJean-Christophe PLAGNIOL-VILLARD 	return val;
6012439e4bfSJean-Christophe PLAGNIOL-VILLARD }
6022439e4bfSJean-Christophe PLAGNIOL-VILLARD 
6032439e4bfSJean-Christophe PLAGNIOL-VILLARD /*
6042439e4bfSJean-Christophe PLAGNIOL-VILLARD    Write a word to phyxcer
6052439e4bfSJean-Christophe PLAGNIOL-VILLARD */
6062439e4bfSJean-Christophe PLAGNIOL-VILLARD static void
60709c04c20SAndy Fleming dm9000_phy_write(int reg, u16 value)
6082439e4bfSJean-Christophe PLAGNIOL-VILLARD {
6092439e4bfSJean-Christophe PLAGNIOL-VILLARD 
6102439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* Fill the phyxcer register into REG_0C */
6112439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DM9000_iow(DM9000_EPAR, DM9000_PHY | reg);
6122439e4bfSJean-Christophe PLAGNIOL-VILLARD 
6132439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* Fill the written data into REG_0D & REG_0E */
6142439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DM9000_iow(DM9000_EPDRL, (value & 0xff));
6152439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DM9000_iow(DM9000_EPDRH, ((value >> 8) & 0xff));
6162439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DM9000_iow(DM9000_EPCR, 0xa);	/* Issue phyxcer write command */
6172439e4bfSJean-Christophe PLAGNIOL-VILLARD 	udelay(500);			/* Wait write complete */
6182439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DM9000_iow(DM9000_EPCR, 0x0);	/* Clear phyxcer write command */
61909c04c20SAndy Fleming 	DM9000_DBG("dm9000_phy_write(reg:0x%x, value:0x%x)\n", reg, value);
6202439e4bfSJean-Christophe PLAGNIOL-VILLARD }
62160f61e6dSRemy Bohmer 
62260f61e6dSRemy Bohmer int dm9000_initialize(bd_t *bis)
62360f61e6dSRemy Bohmer {
62460f61e6dSRemy Bohmer 	struct eth_device *dev = &(dm9000_info.netdev);
62560f61e6dSRemy Bohmer 
62607754372SBen Warren 	/* Load MAC address from EEPROM */
62707754372SBen Warren 	dm9000_get_enetaddr(dev);
62807754372SBen Warren 
62960f61e6dSRemy Bohmer 	dev->init = dm9000_init;
63060f61e6dSRemy Bohmer 	dev->halt = dm9000_halt;
63160f61e6dSRemy Bohmer 	dev->send = dm9000_send;
63260f61e6dSRemy Bohmer 	dev->recv = dm9000_rx;
633*192bc694SBen Whitten 	strcpy(dev->name, "dm9000");
63460f61e6dSRemy Bohmer 
63560f61e6dSRemy Bohmer 	eth_register(dev);
63660f61e6dSRemy Bohmer 
63760f61e6dSRemy Bohmer 	return 0;
63860f61e6dSRemy Bohmer }
639