blob: a99a901e828b4be35d556b75fb610c6891b980ab [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
wdenk7ac16102004-08-01 22:48:16 +00002/*
3 dm9000.c: Version 1.2 12/15/2003
4
5 A Davicom DM9000 ISA NIC fast Ethernet driver for Linux.
6 Copyright (C) 1997 Sten Wang
7
wdenk7ac16102004-08-01 22:48:16 +00008 (C)Copyright 1997-1998 DAVICOM Semiconductor,Inc. All Rights Reserved.
9
10V0.11 06/20/2001 REG_0A bit3=1, default enable BP with DA match
Wolfgang Denka1be4762008-05-20 16:00:29 +020011 06/22/2001 Support DM9801 progrmming
12 E3: R25 = ((R24 + NF) & 0x00ff) | 0xf000
13 E4: R25 = ((R24 + NF) & 0x00ff) | 0xc200
14 R17 = (R17 & 0xfff0) | NF + 3
15 E5: R25 = ((R24 + NF - 3) & 0x00ff) | 0xc200
16 R17 = (R17 & 0xfff0) | NF
wdenk7ac16102004-08-01 22:48:16 +000017
Wolfgang Denka1be4762008-05-20 16:00:29 +020018v1.00 modify by simon 2001.9.5
Wolfgang Denkec7fbf52013-10-04 17:43:24 +020019 change for kernel 2.4.x
wdenk7ac16102004-08-01 22:48:16 +000020
Wolfgang Denka1be4762008-05-20 16:00:29 +020021v1.1 11/09/2001 fix force mode bug
wdenk7ac16102004-08-01 22:48:16 +000022
23v1.2 03/18/2003 Weilun Huang <weilun_huang@davicom.com.tw>:
24 Fixed phy reset.
25 Added tx/rx 32 bit mode.
26 Cleaned up for kernel merge.
27
28--------------------------------------
29
Remy Bohmer5f63bf42008-06-03 15:26:21 +020030 12/15/2003 Initial port to u-boot by
Wolfgang Denk62fb2b42021-09-27 17:42:39 +020031 Sascha Hauer <saschahauer@web.de>
Remy Bohmer5f63bf42008-06-03 15:26:21 +020032
33 06/03/2008 Remy Bohmer <linux@bohmer.net>
Remy Bohmereec38a12008-06-03 15:26:25 +020034 - Fixed the driver to work with DM9000A.
35 (check on ISR receive status bit before reading the
36 FIFO as described in DM9000 programming guide and
37 application notes)
Remy Bohmer5f63bf42008-06-03 15:26:21 +020038 - Added autodetect of databus width.
Remy Bohmerf4329dc2008-06-03 15:26:22 +020039 - Made debug code compile again.
Remy Bohmer16cb2642008-06-03 15:26:23 +020040 - Adapt eth_send such that it matches the DM9000*
41 application notes. Needed to make it work properly
42 for DM9000A.
Remy Bohmer2f13d2c2008-06-03 15:26:24 +020043 - Adapted reset procedure to match DM9000 application
44 notes (i.e. double reset)
Remy Bohmer61b8dbd2008-06-03 15:26:26 +020045 - some minor code cleanups
Remy Bohmer5f63bf42008-06-03 15:26:21 +020046 These changes are tested with DM9000{A,EP,E} together
Remy Bohmercd9a36c2009-05-03 12:11:40 +020047 with a 200MHz Atmel AT91SAM9261 core
wdenk7ac16102004-08-01 22:48:16 +000048
Andrew Dyera62f5d42008-08-26 17:03:38 -050049TODO: external MII is not functional, only internal at the moment.
wdenk7ac16102004-08-01 22:48:16 +000050*/
51
52#include <common.h>
53#include <command.h>
54#include <net.h>
55#include <asm/io.h>
Remy Bohmercd9a36c2009-05-03 12:11:40 +020056#include <dm9000.h>
Simon Glassdbd79542020-05-10 11:40:11 -060057#include <linux/delay.h>
wdenk7ac16102004-08-01 22:48:16 +000058
wdenk7ac16102004-08-01 22:48:16 +000059#include "dm9000x.h"
60
61/* Board/System/Debug information/definition ---------------- */
62
wdenk7ac16102004-08-01 22:48:16 +000063/* #define CONFIG_DM9000_DEBUG */
64
65#ifdef CONFIG_DM9000_DEBUG
Remy Bohmerf4329dc2008-06-03 15:26:22 +020066#define DM9000_DMP_PACKET(func,packet,length) \
67 do { \
Wolfgang Denk62fb2b42021-09-27 17:42:39 +020068 int i; \
Thomas Weberc1ff5292009-12-09 09:38:04 +010069 printf("%s: length: %d\n", func, length); \
Remy Bohmerf4329dc2008-06-03 15:26:22 +020070 for (i = 0; i < length; i++) { \
71 if (i % 8 == 0) \
72 printf("\n%s: %02x: ", func, i); \
73 printf("%02x ", ((unsigned char *) packet)[i]); \
74 } printf("\n"); \
75 } while(0)
76#else
Remy Bohmerf4329dc2008-06-03 15:26:22 +020077#define DM9000_DMP_PACKET(func,packet,length)
78#endif
79
wdenk7ac16102004-08-01 22:48:16 +000080/* Structure/enum declaration ------------------------------- */
81typedef struct board_info {
82 u32 runt_length_counter; /* counter: RX length < 64byte */
83 u32 long_length_counter; /* counter: RX length > 1514byte */
84 u32 reset_counter; /* counter: RESET */
85 u32 reset_tx_timeout; /* RESET caused by TX Timeout */
86 u32 reset_rx_status; /* RESET caused by RX Statsus wrong */
87 u16 tx_pkt_cnt;
88 u16 queue_start_addr;
89 u16 dbug_cnt;
90 u8 phy_addr;
91 u8 device_wait_reset; /* device state */
wdenk7ac16102004-08-01 22:48:16 +000092 unsigned char srom[128];
Remy Bohmer90d1fed2008-06-05 13:03:36 +020093 void (*outblk)(volatile void *data_ptr, int count);
Remy Bohmer5f63bf42008-06-03 15:26:21 +020094 void (*inblk)(void *data_ptr, int count);
Marek Vasut5248e562022-04-13 04:15:25 +020095 void (*rx_status)(u16 *rxstatus, u16 *rxlen);
Remy Bohmer7eefd922009-05-02 21:49:18 +020096 struct eth_device netdev;
Remy Bohmer61b8dbd2008-06-03 15:26:26 +020097} board_info_t;
Remy Bohmer5f63bf42008-06-03 15:26:21 +020098static board_info_t dm9000_info;
wdenk7ac16102004-08-01 22:48:16 +000099
Remy Bohmer7eefd922009-05-02 21:49:18 +0200100
wdenk7ac16102004-08-01 22:48:16 +0000101/* function declaration ------------------------------------- */
wdenk7ac16102004-08-01 22:48:16 +0000102static int dm9000_probe(void);
Andy Fleming0d2df962011-03-22 22:49:13 -0500103static u16 dm9000_phy_read(int);
104static void dm9000_phy_write(int, u16);
Marek Vasuteb2749a2022-04-13 04:15:23 +0200105static u8 dm9000_ior(int);
106static void dm9000_iow(int reg, u8 value);
wdenk7ac16102004-08-01 22:48:16 +0000107
108/* DM9000 network board routine ---------------------------- */
Jason Jinc74c4362011-08-25 15:46:43 +0800109#ifndef CONFIG_DM9000_BYTE_SWAPPED
Marek Vasuteb2749a2022-04-13 04:15:23 +0200110#define dm9000_outb(d,r) writeb(d, (volatile u8 *)(r))
111#define dm9000_outw(d,r) writew(d, (volatile u16 *)(r))
112#define dm9000_outl(d,r) writel(d, (volatile u32 *)(r))
113#define dm9000_inb(r) readb((volatile u8 *)(r))
114#define dm9000_inw(r) readw((volatile u16 *)(r))
115#define dm9000_inl(r) readl((volatile u32 *)(r))
Jason Jinc74c4362011-08-25 15:46:43 +0800116#else
Marek Vasuteb2749a2022-04-13 04:15:23 +0200117#define dm9000_outb(d, r) __raw_writeb(d, r)
118#define dm9000_outw(d, r) __raw_writew(d, r)
119#define dm9000_outl(d, r) __raw_writel(d, r)
120#define dm9000_inb(r) __raw_readb(r)
121#define dm9000_inw(r) __raw_readw(r)
122#define dm9000_inl(r) __raw_readl(r)
Jason Jinc74c4362011-08-25 15:46:43 +0800123#endif
wdenk7ac16102004-08-01 22:48:16 +0000124
125#ifdef CONFIG_DM9000_DEBUG
126static void
127dump_regs(void)
128{
Marek Vasuted761222022-04-13 04:15:24 +0200129 debug("\n");
130 debug("NCR (0x00): %02x\n", dm9000_ior(0));
131 debug("NSR (0x01): %02x\n", dm9000_ior(1));
132 debug("TCR (0x02): %02x\n", dm9000_ior(2));
133 debug("TSRI (0x03): %02x\n", dm9000_ior(3));
134 debug("TSRII (0x04): %02x\n", dm9000_ior(4));
135 debug("RCR (0x05): %02x\n", dm9000_ior(5));
136 debug("RSR (0x06): %02x\n", dm9000_ior(6));
137 debug("ISR (0xFE): %02x\n", dm9000_ior(DM9000_ISR));
138 debug("\n");
wdenk7ac16102004-08-01 22:48:16 +0000139}
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200140#endif
141
Remy Bohmer90d1fed2008-06-05 13:03:36 +0200142static void dm9000_outblk_8bit(volatile void *data_ptr, int count)
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200143{
144 int i;
145 for (i = 0; i < count; i++)
Marek Vasuteb2749a2022-04-13 04:15:23 +0200146 dm9000_outb((((u8 *) data_ptr)[i] & 0xff), DM9000_DATA);
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200147}
148
Remy Bohmer90d1fed2008-06-05 13:03:36 +0200149static void dm9000_outblk_16bit(volatile void *data_ptr, int count)
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200150{
151 int i;
152 u32 tmplen = (count + 1) / 2;
153
154 for (i = 0; i < tmplen; i++)
Marek Vasuteb2749a2022-04-13 04:15:23 +0200155 dm9000_outw(((u16 *) data_ptr)[i], DM9000_DATA);
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200156}
Remy Bohmer90d1fed2008-06-05 13:03:36 +0200157static void dm9000_outblk_32bit(volatile void *data_ptr, int count)
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200158{
159 int i;
160 u32 tmplen = (count + 3) / 4;
161
162 for (i = 0; i < tmplen; i++)
Marek Vasuteb2749a2022-04-13 04:15:23 +0200163 dm9000_outl(((u32 *) data_ptr)[i], DM9000_DATA);
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200164}
165
166static void dm9000_inblk_8bit(void *data_ptr, int count)
167{
168 int i;
169 for (i = 0; i < count; i++)
Marek Vasuteb2749a2022-04-13 04:15:23 +0200170 ((u8 *) data_ptr)[i] = dm9000_inb(DM9000_DATA);
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200171}
172
173static void dm9000_inblk_16bit(void *data_ptr, int count)
174{
175 int i;
176 u32 tmplen = (count + 1) / 2;
177
178 for (i = 0; i < tmplen; i++)
Marek Vasuteb2749a2022-04-13 04:15:23 +0200179 ((u16 *) data_ptr)[i] = dm9000_inw(DM9000_DATA);
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200180}
181static void dm9000_inblk_32bit(void *data_ptr, int count)
182{
183 int i;
184 u32 tmplen = (count + 3) / 4;
185
186 for (i = 0; i < tmplen; i++)
Marek Vasuteb2749a2022-04-13 04:15:23 +0200187 ((u32 *) data_ptr)[i] = dm9000_inl(DM9000_DATA);
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200188}
189
Marek Vasut5248e562022-04-13 04:15:25 +0200190static void dm9000_rx_status_32bit(u16 *rxstatus, u16 *rxlen)
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200191{
Remy Bohmer2e1604f2008-06-04 10:47:25 +0200192 u32 tmpdata;
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200193
Marek Vasuteb2749a2022-04-13 04:15:23 +0200194 dm9000_outb(DM9000_MRCMD, DM9000_IO);
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200195
Marek Vasuteb2749a2022-04-13 04:15:23 +0200196 tmpdata = dm9000_inl(DM9000_DATA);
Marek Vasut5248e562022-04-13 04:15:25 +0200197 *rxstatus = __le16_to_cpu(tmpdata);
198 *rxlen = __le16_to_cpu(tmpdata >> 16);
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200199}
200
Marek Vasut5248e562022-04-13 04:15:25 +0200201static void dm9000_rx_status_16bit(u16 *rxstatus, u16 *rxlen)
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200202{
Marek Vasuteb2749a2022-04-13 04:15:23 +0200203 dm9000_outb(DM9000_MRCMD, DM9000_IO);
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200204
Marek Vasut5248e562022-04-13 04:15:25 +0200205 *rxstatus = __le16_to_cpu(dm9000_inw(DM9000_DATA));
206 *rxlen = __le16_to_cpu(dm9000_inw(DM9000_DATA));
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200207}
208
Marek Vasut5248e562022-04-13 04:15:25 +0200209static void dm9000_rx_status_8bit(u16 *rxstatus, u16 *rxlen)
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200210{
Marek Vasuteb2749a2022-04-13 04:15:23 +0200211 dm9000_outb(DM9000_MRCMD, DM9000_IO);
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200212
Marek Vasut5248e562022-04-13 04:15:25 +0200213 *rxstatus =
Marek Vasuteb2749a2022-04-13 04:15:23 +0200214 __le16_to_cpu(dm9000_inb(DM9000_DATA) +
215 (dm9000_inb(DM9000_DATA) << 8));
Marek Vasut5248e562022-04-13 04:15:25 +0200216 *rxlen =
Marek Vasuteb2749a2022-04-13 04:15:23 +0200217 __le16_to_cpu(dm9000_inb(DM9000_DATA) +
218 (dm9000_inb(DM9000_DATA) << 8));
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200219}
wdenk7ac16102004-08-01 22:48:16 +0000220
221/*
222 Search DM9000 board, allocate space and register it
223*/
224int
225dm9000_probe(void)
226{
227 u32 id_val;
Marek Vasuteb2749a2022-04-13 04:15:23 +0200228 id_val = dm9000_ior(DM9000_VIDL);
229 id_val |= dm9000_ior(DM9000_VIDH) << 8;
230 id_val |= dm9000_ior(DM9000_PIDL) << 16;
231 id_val |= dm9000_ior(DM9000_PIDH) << 24;
wdenk7ac16102004-08-01 22:48:16 +0000232 if (id_val == DM9000_ID) {
233 printf("dm9000 i/o: 0x%x, id: 0x%x \n", CONFIG_DM9000_BASE,
234 id_val);
235 return 0;
236 } else {
237 printf("dm9000 not found at 0x%08x id: 0x%08x\n",
238 CONFIG_DM9000_BASE, id_val);
239 return -1;
240 }
wdenk7ac16102004-08-01 22:48:16 +0000241}
242
243/* General Purpose dm9000 reset routine */
244static void
245dm9000_reset(void)
246{
Marek Vasuted761222022-04-13 04:15:24 +0200247 debug("resetting DM9000\n");
Remy Bohmer2f13d2c2008-06-03 15:26:24 +0200248
249 /* Reset DM9000,
250 see DM9000 Application Notes V1.22 Jun 11, 2004 page 29 */
251
Andrew Dyera62f5d42008-08-26 17:03:38 -0500252 /* DEBUG: Make all GPIO0 outputs, all others inputs */
Marek Vasuteb2749a2022-04-13 04:15:23 +0200253 dm9000_iow(DM9000_GPCR, GPCR_GPIO0_OUT);
Remy Bohmer2f13d2c2008-06-03 15:26:24 +0200254 /* Step 1: Power internal PHY by writing 0 to GPIO0 pin */
Marek Vasuteb2749a2022-04-13 04:15:23 +0200255 dm9000_iow(DM9000_GPR, 0);
Remy Bohmer2f13d2c2008-06-03 15:26:24 +0200256 /* Step 2: Software reset */
Marek Vasuteb2749a2022-04-13 04:15:23 +0200257 dm9000_iow(DM9000_NCR, (NCR_LBK_INT_MAC | NCR_RST));
Remy Bohmer2f13d2c2008-06-03 15:26:24 +0200258
259 do {
Marek Vasuted761222022-04-13 04:15:24 +0200260 debug("resetting the DM9000, 1st reset\n");
Remy Bohmer2f13d2c2008-06-03 15:26:24 +0200261 udelay(25); /* Wait at least 20 us */
Marek Vasuteb2749a2022-04-13 04:15:23 +0200262 } while (dm9000_ior(DM9000_NCR) & 1);
Remy Bohmer2f13d2c2008-06-03 15:26:24 +0200263
Marek Vasuteb2749a2022-04-13 04:15:23 +0200264 dm9000_iow(DM9000_NCR, 0);
265 dm9000_iow(DM9000_NCR, (NCR_LBK_INT_MAC | NCR_RST)); /* Issue a second reset */
Remy Bohmer2f13d2c2008-06-03 15:26:24 +0200266
267 do {
Marek Vasuted761222022-04-13 04:15:24 +0200268 debug("resetting the DM9000, 2nd reset\n");
Remy Bohmer2f13d2c2008-06-03 15:26:24 +0200269 udelay(25); /* Wait at least 20 us */
Marek Vasuteb2749a2022-04-13 04:15:23 +0200270 } while (dm9000_ior(DM9000_NCR) & 1);
Remy Bohmer2f13d2c2008-06-03 15:26:24 +0200271
272 /* Check whether the ethernet controller is present */
Marek Vasuteb2749a2022-04-13 04:15:23 +0200273 if ((dm9000_ior(DM9000_PIDL) != 0x0) ||
274 (dm9000_ior(DM9000_PIDH) != 0x90))
Remy Bohmer2f13d2c2008-06-03 15:26:24 +0200275 printf("ERROR: resetting DM9000 -> not responding\n");
wdenk7ac16102004-08-01 22:48:16 +0000276}
277
Remy Bohmer7eefd922009-05-02 21:49:18 +0200278/* Initialize dm9000 board
wdenk7ac16102004-08-01 22:48:16 +0000279*/
Masahiro Yamadaf7ed78b2020-06-26 15:13:33 +0900280static int dm9000_init(struct eth_device *dev, struct bd_info *bd)
wdenk7ac16102004-08-01 22:48:16 +0000281{
282 int i, oft, lnk;
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200283 u8 io_mode;
284 struct board_info *db = &dm9000_info;
285
Marek Vasuted761222022-04-13 04:15:24 +0200286 debug("%s\n", __func__);
wdenk7ac16102004-08-01 22:48:16 +0000287
288 /* RESET device */
289 dm9000_reset();
Andrew Dyera62f5d42008-08-26 17:03:38 -0500290
291 if (dm9000_probe() < 0)
292 return -1;
wdenk7ac16102004-08-01 22:48:16 +0000293
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200294 /* Auto-detect 8/16/32 bit mode, ISR Bit 6+7 indicate bus width */
Marek Vasuteb2749a2022-04-13 04:15:23 +0200295 io_mode = dm9000_ior(DM9000_ISR) >> 6;
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200296
297 switch (io_mode) {
298 case 0x0: /* 16-bit mode */
299 printf("DM9000: running in 16 bit mode\n");
300 db->outblk = dm9000_outblk_16bit;
301 db->inblk = dm9000_inblk_16bit;
302 db->rx_status = dm9000_rx_status_16bit;
303 break;
304 case 0x01: /* 32-bit mode */
305 printf("DM9000: running in 32 bit mode\n");
306 db->outblk = dm9000_outblk_32bit;
307 db->inblk = dm9000_inblk_32bit;
308 db->rx_status = dm9000_rx_status_32bit;
309 break;
310 case 0x02: /* 8 bit mode */
311 printf("DM9000: running in 8 bit mode\n");
312 db->outblk = dm9000_outblk_8bit;
313 db->inblk = dm9000_inblk_8bit;
314 db->rx_status = dm9000_rx_status_8bit;
315 break;
316 default:
317 /* Assume 8 bit mode, will probably not work anyway */
318 printf("DM9000: Undefined IO-mode:0x%x\n", io_mode);
319 db->outblk = dm9000_outblk_8bit;
320 db->inblk = dm9000_inblk_8bit;
321 db->rx_status = dm9000_rx_status_8bit;
322 break;
323 }
324
Andrew Dyera62f5d42008-08-26 17:03:38 -0500325 /* Program operating register, only internal phy supported */
Marek Vasuteb2749a2022-04-13 04:15:23 +0200326 dm9000_iow(DM9000_NCR, 0x0);
Remy Bohmer61b8dbd2008-06-03 15:26:26 +0200327 /* TX Polling clear */
Marek Vasuteb2749a2022-04-13 04:15:23 +0200328 dm9000_iow(DM9000_TCR, 0);
Remy Bohmer61b8dbd2008-06-03 15:26:26 +0200329 /* Less 3Kb, 200us */
Marek Vasuteb2749a2022-04-13 04:15:23 +0200330 dm9000_iow(DM9000_BPTR, BPTR_BPHW(3) | BPTR_JPT_600US);
Remy Bohmer61b8dbd2008-06-03 15:26:26 +0200331 /* Flow Control : High/Low Water */
Marek Vasuteb2749a2022-04-13 04:15:23 +0200332 dm9000_iow(DM9000_FCTR, FCTR_HWOT(3) | FCTR_LWOT(8));
Remy Bohmer61b8dbd2008-06-03 15:26:26 +0200333 /* SH FIXME: This looks strange! Flow Control */
Marek Vasuteb2749a2022-04-13 04:15:23 +0200334 dm9000_iow(DM9000_FCR, 0x0);
Remy Bohmer61b8dbd2008-06-03 15:26:26 +0200335 /* Special Mode */
Marek Vasuteb2749a2022-04-13 04:15:23 +0200336 dm9000_iow(DM9000_SMCR, 0);
Remy Bohmer61b8dbd2008-06-03 15:26:26 +0200337 /* clear TX status */
Marek Vasuteb2749a2022-04-13 04:15:23 +0200338 dm9000_iow(DM9000_NSR, NSR_WAKEST | NSR_TX2END | NSR_TX1END);
Remy Bohmer61b8dbd2008-06-03 15:26:26 +0200339 /* Clear interrupt status */
Marek Vasuteb2749a2022-04-13 04:15:23 +0200340 dm9000_iow(DM9000_ISR, ISR_ROOS | ISR_ROS | ISR_PTS | ISR_PRS);
wdenk7ac16102004-08-01 22:48:16 +0000341
Ben Warren8707f622009-10-21 21:53:39 -0700342 printf("MAC: %pM\n", dev->enetaddr);
Joe Hershberger8ecdbed2015-04-08 01:41:04 -0500343 if (!is_valid_ethaddr(dev->enetaddr)) {
Andrew Ruder1c377d12013-10-22 19:09:02 -0500344 printf("WARNING: Bad MAC address (uninitialized EEPROM?)\n");
Andrew Ruder1c377d12013-10-22 19:09:02 -0500345 }
Andrew Dyera62f5d42008-08-26 17:03:38 -0500346
347 /* fill device MAC address registers */
348 for (i = 0, oft = DM9000_PAR; i < 6; i++, oft++)
Marek Vasuteb2749a2022-04-13 04:15:23 +0200349 dm9000_iow(oft, dev->enetaddr[i]);
wdenk7ac16102004-08-01 22:48:16 +0000350 for (i = 0, oft = 0x16; i < 8; i++, oft++)
Marek Vasuteb2749a2022-04-13 04:15:23 +0200351 dm9000_iow(oft, 0xff);
wdenk7ac16102004-08-01 22:48:16 +0000352
353 /* read back mac, just to be sure */
354 for (i = 0, oft = 0x10; i < 6; i++, oft++)
Marek Vasuted761222022-04-13 04:15:24 +0200355 debug("%02x:", dm9000_ior(oft));
356 debug("\n");
wdenk7ac16102004-08-01 22:48:16 +0000357
358 /* Activate DM9000 */
Remy Bohmer61b8dbd2008-06-03 15:26:26 +0200359 /* RX enable */
Marek Vasuteb2749a2022-04-13 04:15:23 +0200360 dm9000_iow(DM9000_RCR, RCR_DIS_LONG | RCR_DIS_CRC | RCR_RXEN);
Remy Bohmer61b8dbd2008-06-03 15:26:26 +0200361 /* Enable TX/RX interrupt mask */
Marek Vasuteb2749a2022-04-13 04:15:23 +0200362 dm9000_iow(DM9000_IMR, IMR_PAR);
Remy Bohmer61b8dbd2008-06-03 15:26:26 +0200363
wdenk7ac16102004-08-01 22:48:16 +0000364 i = 0;
Andy Fleming0d2df962011-03-22 22:49:13 -0500365 while (!(dm9000_phy_read(1) & 0x20)) { /* autonegation complete bit */
wdenk7ac16102004-08-01 22:48:16 +0000366 udelay(1000);
367 i++;
368 if (i == 10000) {
369 printf("could not establish link\n");
370 return 0;
371 }
372 }
373
374 /* see what we've got */
Andy Fleming0d2df962011-03-22 22:49:13 -0500375 lnk = dm9000_phy_read(17) >> 12;
wdenk7ac16102004-08-01 22:48:16 +0000376 printf("operating at ");
377 switch (lnk) {
378 case 1:
379 printf("10M half duplex ");
380 break;
381 case 2:
382 printf("10M full duplex ");
383 break;
384 case 4:
385 printf("100M half duplex ");
386 break;
387 case 8:
388 printf("100M full duplex ");
389 break;
390 default:
391 printf("unknown: %d ", lnk);
392 break;
393 }
394 printf("mode\n");
395 return 0;
396}
397
398/*
399 Hardware start transmission.
400 Send a packet to media from the upper layer.
401*/
Joe Hershbergerab1ac412012-05-21 14:45:23 +0000402static int dm9000_send(struct eth_device *netdev, void *packet, int length)
wdenk7ac16102004-08-01 22:48:16 +0000403{
wdenk7ac16102004-08-01 22:48:16 +0000404 int tmo;
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200405 struct board_info *db = &dm9000_info;
406
Remy Bohmer7eefd922009-05-02 21:49:18 +0200407 DM9000_DMP_PACKET(__func__ , packet, length);
wdenk7ac16102004-08-01 22:48:16 +0000408
Marek Vasuteb2749a2022-04-13 04:15:23 +0200409 dm9000_iow(DM9000_ISR, IMR_PTM); /* Clear Tx bit in ISR */
Remy Bohmer16cb2642008-06-03 15:26:23 +0200410
wdenk7ac16102004-08-01 22:48:16 +0000411 /* Move data to DM9000 TX RAM */
Marek Vasuteb2749a2022-04-13 04:15:23 +0200412 dm9000_outb(DM9000_MWCMD, DM9000_IO); /* Prepare for TX-data */
wdenk7ac16102004-08-01 22:48:16 +0000413
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200414 /* push the data to the TX-fifo */
Remy Bohmer90d1fed2008-06-05 13:03:36 +0200415 (db->outblk)(packet, length);
wdenk7ac16102004-08-01 22:48:16 +0000416
417 /* Set TX length to DM9000 */
Marek Vasuteb2749a2022-04-13 04:15:23 +0200418 dm9000_iow(DM9000_TXPLL, length & 0xff);
419 dm9000_iow(DM9000_TXPLH, (length >> 8) & 0xff);
wdenk7ac16102004-08-01 22:48:16 +0000420
421 /* Issue TX polling command */
Marek Vasuteb2749a2022-04-13 04:15:23 +0200422 dm9000_iow(DM9000_TCR, TCR_TXREQ); /* Cleared after TX complete */
wdenk7ac16102004-08-01 22:48:16 +0000423
424 /* wait for end of transmission */
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200425 tmo = get_timer(0) + 5 * CONFIG_SYS_HZ;
Marek Vasuteb2749a2022-04-13 04:15:23 +0200426 while ( !(dm9000_ior(DM9000_NSR) & (NSR_TX1END | NSR_TX2END)) ||
427 !(dm9000_ior(DM9000_ISR) & IMR_PTM) ) {
wdenk7ac16102004-08-01 22:48:16 +0000428 if (get_timer(0) >= tmo) {
429 printf("transmission timeout\n");
430 break;
431 }
432 }
Marek Vasuteb2749a2022-04-13 04:15:23 +0200433 dm9000_iow(DM9000_ISR, IMR_PTM); /* Clear Tx bit in ISR */
Remy Bohmer16cb2642008-06-03 15:26:23 +0200434
Marek Vasuted761222022-04-13 04:15:24 +0200435 debug("transmit done\n\n");
wdenk7ac16102004-08-01 22:48:16 +0000436 return 0;
437}
438
439/*
440 Stop the interface.
441 The interface is stopped when it is brought.
442*/
Remy Bohmer7eefd922009-05-02 21:49:18 +0200443static void dm9000_halt(struct eth_device *netdev)
wdenk7ac16102004-08-01 22:48:16 +0000444{
Marek Vasuted761222022-04-13 04:15:24 +0200445 debug("%s\n", __func__);
wdenk7ac16102004-08-01 22:48:16 +0000446
447 /* RESET devie */
Andy Fleming0d2df962011-03-22 22:49:13 -0500448 dm9000_phy_write(0, 0x8000); /* PHY RESET */
Marek Vasuteb2749a2022-04-13 04:15:23 +0200449 dm9000_iow(DM9000_GPR, 0x01); /* Power-Down PHY */
450 dm9000_iow(DM9000_IMR, 0x80); /* Disable all interrupt */
451 dm9000_iow(DM9000_RCR, 0x00); /* Disable RX */
wdenk7ac16102004-08-01 22:48:16 +0000452}
453
454/*
455 Received a packet and pass to upper layer
456*/
Remy Bohmer7eefd922009-05-02 21:49:18 +0200457static int dm9000_rx(struct eth_device *netdev)
wdenk7ac16102004-08-01 22:48:16 +0000458{
Joe Hershberger9f09a362015-04-08 01:41:06 -0500459 u8 rxbyte;
460 u8 *rdptr = (u8 *)net_rx_packets[0];
Marek Vasut5248e562022-04-13 04:15:25 +0200461 u16 rxstatus, rxlen = 0;
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200462 struct board_info *db = &dm9000_info;
wdenk7ac16102004-08-01 22:48:16 +0000463
Remy Bohmereec38a12008-06-03 15:26:25 +0200464 /* Check packet ready or not, we must check
465 the ISR status first for DM9000A */
Marek Vasuteb2749a2022-04-13 04:15:23 +0200466 if (!(dm9000_ior(DM9000_ISR) & 0x01)) /* Rx-ISR bit must be set. */
wdenk7ac16102004-08-01 22:48:16 +0000467 return 0;
468
Marek Vasuteb2749a2022-04-13 04:15:23 +0200469 dm9000_iow(DM9000_ISR, 0x01); /* clear PR status latched in bit 0 */
wdenk7ac16102004-08-01 22:48:16 +0000470
Remy Bohmereec38a12008-06-03 15:26:25 +0200471 /* There is _at least_ 1 package in the fifo, read them all */
472 for (;;) {
Marek Vasuteb2749a2022-04-13 04:15:23 +0200473 dm9000_ior(DM9000_MRCMDX); /* Dummy read */
wdenk7ac16102004-08-01 22:48:16 +0000474
Remy Bohmer90d1fed2008-06-05 13:03:36 +0200475 /* Get most updated data,
476 only look at bits 0:1, See application notes DM9000 */
Marek Vasuteb2749a2022-04-13 04:15:23 +0200477 rxbyte = dm9000_inb(DM9000_DATA) & 0x03;
wdenk7ac16102004-08-01 22:48:16 +0000478
Remy Bohmereec38a12008-06-03 15:26:25 +0200479 /* Status check: this byte must be 0 or 1 */
480 if (rxbyte > DM9000_PKT_RDY) {
Marek Vasuteb2749a2022-04-13 04:15:23 +0200481 dm9000_iow(DM9000_RCR, 0x00); /* Stop Device */
482 dm9000_iow(DM9000_ISR, 0x80); /* Stop INT request */
Remy Bohmereec38a12008-06-03 15:26:25 +0200483 printf("DM9000 error: status check fail: 0x%x\n",
484 rxbyte);
485 return 0;
486 }
wdenk7ac16102004-08-01 22:48:16 +0000487
Remy Bohmereec38a12008-06-03 15:26:25 +0200488 if (rxbyte != DM9000_PKT_RDY)
489 return 0; /* No packet received, ignore */
wdenk7ac16102004-08-01 22:48:16 +0000490
Marek Vasuted761222022-04-13 04:15:24 +0200491 debug("receiving packet\n");
Remy Bohmereec38a12008-06-03 15:26:25 +0200492
493 /* A packet ready now & Get status/length */
Marek Vasut5248e562022-04-13 04:15:25 +0200494 (db->rx_status)(&rxstatus, &rxlen);
wdenk7ac16102004-08-01 22:48:16 +0000495
Marek Vasut5248e562022-04-13 04:15:25 +0200496 debug("rx status: 0x%04x rx len: %d\n", rxstatus, rxlen);
Remy Bohmereec38a12008-06-03 15:26:25 +0200497
498 /* Move data from DM9000 */
499 /* Read received packet from RX SRAM */
Marek Vasut5248e562022-04-13 04:15:25 +0200500 (db->inblk)(rdptr, rxlen);
Remy Bohmereec38a12008-06-03 15:26:25 +0200501
Marek Vasut5248e562022-04-13 04:15:25 +0200502 if ((rxstatus & 0xbf00) || (rxlen < 0x40)
503 || (rxlen > DM9000_PKT_MAX)) {
504 if (rxstatus & 0x100) {
Remy Bohmereec38a12008-06-03 15:26:25 +0200505 printf("rx fifo error\n");
506 }
Marek Vasut5248e562022-04-13 04:15:25 +0200507 if (rxstatus & 0x200) {
Remy Bohmereec38a12008-06-03 15:26:25 +0200508 printf("rx crc error\n");
509 }
Marek Vasut5248e562022-04-13 04:15:25 +0200510 if (rxstatus & 0x8000) {
Remy Bohmereec38a12008-06-03 15:26:25 +0200511 printf("rx length error\n");
512 }
Marek Vasut5248e562022-04-13 04:15:25 +0200513 if (rxlen > DM9000_PKT_MAX) {
Remy Bohmereec38a12008-06-03 15:26:25 +0200514 printf("rx length too big\n");
515 dm9000_reset();
516 }
517 } else {
Marek Vasut5248e562022-04-13 04:15:25 +0200518 DM9000_DMP_PACKET(__func__ , rdptr, rxlen);
Remy Bohmereec38a12008-06-03 15:26:25 +0200519
Marek Vasuted761222022-04-13 04:15:24 +0200520 debug("passing packet to upper layer\n");
Marek Vasut5248e562022-04-13 04:15:25 +0200521 net_process_received_packet(net_rx_packets[0], rxlen);
Remy Bohmereec38a12008-06-03 15:26:25 +0200522 }
wdenk7ac16102004-08-01 22:48:16 +0000523 }
524 return 0;
525}
526
527/*
528 Read a word data from SROM
529*/
Remy Bohmercd9a36c2009-05-03 12:11:40 +0200530#if !defined(CONFIG_DM9000_NO_SROM)
531void dm9000_read_srom_word(int offset, u8 *to)
wdenk7ac16102004-08-01 22:48:16 +0000532{
Marek Vasuteb2749a2022-04-13 04:15:23 +0200533 dm9000_iow(DM9000_EPAR, offset);
534 dm9000_iow(DM9000_EPCR, 0x4);
stefano babicedb06872007-08-21 15:50:33 +0200535 udelay(8000);
Marek Vasuteb2749a2022-04-13 04:15:23 +0200536 dm9000_iow(DM9000_EPCR, 0x0);
537 to[0] = dm9000_ior(DM9000_EPDRL);
538 to[1] = dm9000_ior(DM9000_EPDRH);
wdenk7ac16102004-08-01 22:48:16 +0000539}
540
Remy Bohmercd9a36c2009-05-03 12:11:40 +0200541void dm9000_write_srom_word(int offset, u16 val)
stefano babic6708a602007-08-30 23:01:49 +0200542{
Marek Vasuteb2749a2022-04-13 04:15:23 +0200543 dm9000_iow(DM9000_EPAR, offset);
544 dm9000_iow(DM9000_EPDRH, ((val >> 8) & 0xff));
545 dm9000_iow(DM9000_EPDRL, (val & 0xff));
546 dm9000_iow(DM9000_EPCR, 0x12);
stefano babic6708a602007-08-30 23:01:49 +0200547 udelay(8000);
Marek Vasuteb2749a2022-04-13 04:15:23 +0200548 dm9000_iow(DM9000_EPCR, 0);
stefano babic6708a602007-08-30 23:01:49 +0200549}
Remy Bohmercd9a36c2009-05-03 12:11:40 +0200550#endif
Ben Warren8707f622009-10-21 21:53:39 -0700551
552static void dm9000_get_enetaddr(struct eth_device *dev)
553{
554#if !defined(CONFIG_DM9000_NO_SROM)
555 int i;
556 for (i = 0; i < 3; i++)
557 dm9000_read_srom_word(i, dev->enetaddr + (2 * i));
558#endif
559}
stefano babic6708a602007-08-30 23:01:49 +0200560
wdenk7ac16102004-08-01 22:48:16 +0000561/*
562 Read a byte from I/O port
563*/
564static u8
Marek Vasuteb2749a2022-04-13 04:15:23 +0200565dm9000_ior(int reg)
wdenk7ac16102004-08-01 22:48:16 +0000566{
Marek Vasuteb2749a2022-04-13 04:15:23 +0200567 dm9000_outb(reg, DM9000_IO);
568 return dm9000_inb(DM9000_DATA);
wdenk7ac16102004-08-01 22:48:16 +0000569}
570
571/*
572 Write a byte to I/O port
573*/
574static void
Marek Vasuteb2749a2022-04-13 04:15:23 +0200575dm9000_iow(int reg, u8 value)
wdenk7ac16102004-08-01 22:48:16 +0000576{
Marek Vasuteb2749a2022-04-13 04:15:23 +0200577 dm9000_outb(reg, DM9000_IO);
578 dm9000_outb(value, DM9000_DATA);
wdenk7ac16102004-08-01 22:48:16 +0000579}
580
581/*
582 Read a word from phyxcer
583*/
584static u16
Andy Fleming0d2df962011-03-22 22:49:13 -0500585dm9000_phy_read(int reg)
wdenk7ac16102004-08-01 22:48:16 +0000586{
587 u16 val;
588
589 /* Fill the phyxcer register into REG_0C */
Marek Vasuteb2749a2022-04-13 04:15:23 +0200590 dm9000_iow(DM9000_EPAR, DM9000_PHY | reg);
591 dm9000_iow(DM9000_EPCR, 0xc); /* Issue phyxcer read command */
Remy Bohmer61b8dbd2008-06-03 15:26:26 +0200592 udelay(100); /* Wait read complete */
Marek Vasuteb2749a2022-04-13 04:15:23 +0200593 dm9000_iow(DM9000_EPCR, 0x0); /* Clear phyxcer read command */
594 val = (dm9000_ior(DM9000_EPDRH) << 8) | dm9000_ior(DM9000_EPDRL);
wdenk7ac16102004-08-01 22:48:16 +0000595
596 /* The read data keeps on REG_0D & REG_0E */
Marek Vasuted761222022-04-13 04:15:24 +0200597 debug("dm9000_phy_read(0x%x): 0x%x\n", reg, val);
wdenk7ac16102004-08-01 22:48:16 +0000598 return val;
599}
600
601/*
602 Write a word to phyxcer
603*/
604static void
Andy Fleming0d2df962011-03-22 22:49:13 -0500605dm9000_phy_write(int reg, u16 value)
wdenk7ac16102004-08-01 22:48:16 +0000606{
607
608 /* Fill the phyxcer register into REG_0C */
Marek Vasuteb2749a2022-04-13 04:15:23 +0200609 dm9000_iow(DM9000_EPAR, DM9000_PHY | reg);
wdenk7ac16102004-08-01 22:48:16 +0000610
611 /* Fill the written data into REG_0D & REG_0E */
Marek Vasuteb2749a2022-04-13 04:15:23 +0200612 dm9000_iow(DM9000_EPDRL, (value & 0xff));
613 dm9000_iow(DM9000_EPDRH, ((value >> 8) & 0xff));
614 dm9000_iow(DM9000_EPCR, 0xa); /* Issue phyxcer write command */
Remy Bohmer61b8dbd2008-06-03 15:26:26 +0200615 udelay(500); /* Wait write complete */
Marek Vasuteb2749a2022-04-13 04:15:23 +0200616 dm9000_iow(DM9000_EPCR, 0x0); /* Clear phyxcer write command */
Marek Vasuted761222022-04-13 04:15:24 +0200617 debug("dm9000_phy_write(reg:0x%x, value:0x%x)\n", reg, value);
wdenk7ac16102004-08-01 22:48:16 +0000618}
Remy Bohmer7eefd922009-05-02 21:49:18 +0200619
Masahiro Yamadaf7ed78b2020-06-26 15:13:33 +0900620int dm9000_initialize(struct bd_info *bis)
Remy Bohmer7eefd922009-05-02 21:49:18 +0200621{
622 struct eth_device *dev = &(dm9000_info.netdev);
623
Ben Warren8707f622009-10-21 21:53:39 -0700624 /* Load MAC address from EEPROM */
625 dm9000_get_enetaddr(dev);
626
Remy Bohmer7eefd922009-05-02 21:49:18 +0200627 dev->init = dm9000_init;
628 dev->halt = dm9000_halt;
629 dev->send = dm9000_send;
630 dev->recv = dm9000_rx;
Ben Whitten34fd6c92015-12-30 13:05:58 +0000631 strcpy(dev->name, "dm9000");
Remy Bohmer7eefd922009-05-02 21:49:18 +0200632
633 eth_register(dev);
634
635 return 0;
636}