blob: da16b64610b888ecfc0d87129daeac307c773f22 [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
wdenk7ac16102004-08-01 22:48:16 +000061/* Structure/enum declaration ------------------------------- */
62typedef struct board_info {
63 u32 runt_length_counter; /* counter: RX length < 64byte */
64 u32 long_length_counter; /* counter: RX length > 1514byte */
65 u32 reset_counter; /* counter: RESET */
66 u32 reset_tx_timeout; /* RESET caused by TX Timeout */
67 u32 reset_rx_status; /* RESET caused by RX Statsus wrong */
68 u16 tx_pkt_cnt;
69 u16 queue_start_addr;
70 u16 dbug_cnt;
71 u8 phy_addr;
72 u8 device_wait_reset; /* device state */
wdenk7ac16102004-08-01 22:48:16 +000073 unsigned char srom[128];
Remy Bohmer90d1fed2008-06-05 13:03:36 +020074 void (*outblk)(volatile void *data_ptr, int count);
Remy Bohmer5f63bf42008-06-03 15:26:21 +020075 void (*inblk)(void *data_ptr, int count);
Marek Vasut5248e562022-04-13 04:15:25 +020076 void (*rx_status)(u16 *rxstatus, u16 *rxlen);
Remy Bohmer7eefd922009-05-02 21:49:18 +020077 struct eth_device netdev;
Remy Bohmer61b8dbd2008-06-03 15:26:26 +020078} board_info_t;
Remy Bohmer5f63bf42008-06-03 15:26:21 +020079static board_info_t dm9000_info;
wdenk7ac16102004-08-01 22:48:16 +000080
Remy Bohmer7eefd922009-05-02 21:49:18 +020081
wdenk7ac16102004-08-01 22:48:16 +000082/* function declaration ------------------------------------- */
wdenk7ac16102004-08-01 22:48:16 +000083static int dm9000_probe(void);
Andy Fleming0d2df962011-03-22 22:49:13 -050084static u16 dm9000_phy_read(int);
85static void dm9000_phy_write(int, u16);
Marek Vasuteb2749a2022-04-13 04:15:23 +020086static u8 dm9000_ior(int);
87static void dm9000_iow(int reg, u8 value);
wdenk7ac16102004-08-01 22:48:16 +000088
89/* DM9000 network board routine ---------------------------- */
Jason Jinc74c4362011-08-25 15:46:43 +080090#ifndef CONFIG_DM9000_BYTE_SWAPPED
Marek Vasuteb2749a2022-04-13 04:15:23 +020091#define dm9000_outb(d,r) writeb(d, (volatile u8 *)(r))
92#define dm9000_outw(d,r) writew(d, (volatile u16 *)(r))
93#define dm9000_outl(d,r) writel(d, (volatile u32 *)(r))
94#define dm9000_inb(r) readb((volatile u8 *)(r))
95#define dm9000_inw(r) readw((volatile u16 *)(r))
96#define dm9000_inl(r) readl((volatile u32 *)(r))
Jason Jinc74c4362011-08-25 15:46:43 +080097#else
Marek Vasuteb2749a2022-04-13 04:15:23 +020098#define dm9000_outb(d, r) __raw_writeb(d, r)
99#define dm9000_outw(d, r) __raw_writew(d, r)
100#define dm9000_outl(d, r) __raw_writel(d, r)
101#define dm9000_inb(r) __raw_readb(r)
102#define dm9000_inw(r) __raw_readw(r)
103#define dm9000_inl(r) __raw_readl(r)
Jason Jinc74c4362011-08-25 15:46:43 +0800104#endif
wdenk7ac16102004-08-01 22:48:16 +0000105
Marek Vasut52006d22022-04-13 04:15:27 +0200106#ifdef DEBUG
107static void dm9000_dump_packet(const char *func, u8 *packet, int length)
108{
109 int i;
110
111 printf("%s: length: %d\n", func, length);
112
113 for (i = 0; i < length; i++) {
114 if (i % 8 == 0)
115 printf("\n%s: %02x: ", func, i);
116 printf("%02x ", packet[i]);
117 }
118
119 printf("\n");
120}
121#else
122static void dm9000_dump_packet(const char *func, u8 *packet, int length) {}
123#endif
124
Remy Bohmer90d1fed2008-06-05 13:03:36 +0200125static void dm9000_outblk_8bit(volatile void *data_ptr, int count)
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200126{
127 int i;
128 for (i = 0; i < count; i++)
Marek Vasuteb2749a2022-04-13 04:15:23 +0200129 dm9000_outb((((u8 *) data_ptr)[i] & 0xff), DM9000_DATA);
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200130}
131
Remy Bohmer90d1fed2008-06-05 13:03:36 +0200132static void dm9000_outblk_16bit(volatile void *data_ptr, int count)
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200133{
134 int i;
135 u32 tmplen = (count + 1) / 2;
136
137 for (i = 0; i < tmplen; i++)
Marek Vasuteb2749a2022-04-13 04:15:23 +0200138 dm9000_outw(((u16 *) data_ptr)[i], DM9000_DATA);
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200139}
Remy Bohmer90d1fed2008-06-05 13:03:36 +0200140static void dm9000_outblk_32bit(volatile void *data_ptr, int count)
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200141{
142 int i;
143 u32 tmplen = (count + 3) / 4;
144
145 for (i = 0; i < tmplen; i++)
Marek Vasuteb2749a2022-04-13 04:15:23 +0200146 dm9000_outl(((u32 *) data_ptr)[i], DM9000_DATA);
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200147}
148
149static void dm9000_inblk_8bit(void *data_ptr, int count)
150{
151 int i;
152 for (i = 0; i < count; i++)
Marek Vasuteb2749a2022-04-13 04:15:23 +0200153 ((u8 *) data_ptr)[i] = dm9000_inb(DM9000_DATA);
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200154}
155
156static void dm9000_inblk_16bit(void *data_ptr, int count)
157{
158 int i;
159 u32 tmplen = (count + 1) / 2;
160
161 for (i = 0; i < tmplen; i++)
Marek Vasuteb2749a2022-04-13 04:15:23 +0200162 ((u16 *) data_ptr)[i] = dm9000_inw(DM9000_DATA);
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200163}
164static void dm9000_inblk_32bit(void *data_ptr, int count)
165{
166 int i;
167 u32 tmplen = (count + 3) / 4;
168
169 for (i = 0; i < tmplen; i++)
Marek Vasuteb2749a2022-04-13 04:15:23 +0200170 ((u32 *) data_ptr)[i] = dm9000_inl(DM9000_DATA);
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200171}
172
Marek Vasut5248e562022-04-13 04:15:25 +0200173static void dm9000_rx_status_32bit(u16 *rxstatus, u16 *rxlen)
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200174{
Remy Bohmer2e1604f2008-06-04 10:47:25 +0200175 u32 tmpdata;
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200176
Marek Vasuteb2749a2022-04-13 04:15:23 +0200177 dm9000_outb(DM9000_MRCMD, DM9000_IO);
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200178
Marek Vasuteb2749a2022-04-13 04:15:23 +0200179 tmpdata = dm9000_inl(DM9000_DATA);
Marek Vasut5248e562022-04-13 04:15:25 +0200180 *rxstatus = __le16_to_cpu(tmpdata);
181 *rxlen = __le16_to_cpu(tmpdata >> 16);
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200182}
183
Marek Vasut5248e562022-04-13 04:15:25 +0200184static void dm9000_rx_status_16bit(u16 *rxstatus, u16 *rxlen)
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200185{
Marek Vasuteb2749a2022-04-13 04:15:23 +0200186 dm9000_outb(DM9000_MRCMD, DM9000_IO);
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200187
Marek Vasut5248e562022-04-13 04:15:25 +0200188 *rxstatus = __le16_to_cpu(dm9000_inw(DM9000_DATA));
189 *rxlen = __le16_to_cpu(dm9000_inw(DM9000_DATA));
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200190}
191
Marek Vasut5248e562022-04-13 04:15:25 +0200192static void dm9000_rx_status_8bit(u16 *rxstatus, u16 *rxlen)
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 Vasut5248e562022-04-13 04:15:25 +0200196 *rxstatus =
Marek Vasuteb2749a2022-04-13 04:15:23 +0200197 __le16_to_cpu(dm9000_inb(DM9000_DATA) +
198 (dm9000_inb(DM9000_DATA) << 8));
Marek Vasut5248e562022-04-13 04:15:25 +0200199 *rxlen =
Marek Vasuteb2749a2022-04-13 04:15:23 +0200200 __le16_to_cpu(dm9000_inb(DM9000_DATA) +
201 (dm9000_inb(DM9000_DATA) << 8));
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200202}
wdenk7ac16102004-08-01 22:48:16 +0000203
204/*
205 Search DM9000 board, allocate space and register it
206*/
207int
208dm9000_probe(void)
209{
210 u32 id_val;
Marek Vasuteb2749a2022-04-13 04:15:23 +0200211 id_val = dm9000_ior(DM9000_VIDL);
212 id_val |= dm9000_ior(DM9000_VIDH) << 8;
213 id_val |= dm9000_ior(DM9000_PIDL) << 16;
214 id_val |= dm9000_ior(DM9000_PIDH) << 24;
wdenk7ac16102004-08-01 22:48:16 +0000215 if (id_val == DM9000_ID) {
216 printf("dm9000 i/o: 0x%x, id: 0x%x \n", CONFIG_DM9000_BASE,
217 id_val);
218 return 0;
219 } else {
220 printf("dm9000 not found at 0x%08x id: 0x%08x\n",
221 CONFIG_DM9000_BASE, id_val);
222 return -1;
223 }
wdenk7ac16102004-08-01 22:48:16 +0000224}
225
226/* General Purpose dm9000 reset routine */
227static void
228dm9000_reset(void)
229{
Marek Vasuted761222022-04-13 04:15:24 +0200230 debug("resetting DM9000\n");
Remy Bohmer2f13d2c2008-06-03 15:26:24 +0200231
232 /* Reset DM9000,
233 see DM9000 Application Notes V1.22 Jun 11, 2004 page 29 */
234
Andrew Dyera62f5d42008-08-26 17:03:38 -0500235 /* DEBUG: Make all GPIO0 outputs, all others inputs */
Marek Vasuteb2749a2022-04-13 04:15:23 +0200236 dm9000_iow(DM9000_GPCR, GPCR_GPIO0_OUT);
Remy Bohmer2f13d2c2008-06-03 15:26:24 +0200237 /* Step 1: Power internal PHY by writing 0 to GPIO0 pin */
Marek Vasuteb2749a2022-04-13 04:15:23 +0200238 dm9000_iow(DM9000_GPR, 0);
Remy Bohmer2f13d2c2008-06-03 15:26:24 +0200239 /* Step 2: Software reset */
Marek Vasuteb2749a2022-04-13 04:15:23 +0200240 dm9000_iow(DM9000_NCR, (NCR_LBK_INT_MAC | NCR_RST));
Remy Bohmer2f13d2c2008-06-03 15:26:24 +0200241
242 do {
Marek Vasuted761222022-04-13 04:15:24 +0200243 debug("resetting the DM9000, 1st reset\n");
Remy Bohmer2f13d2c2008-06-03 15:26:24 +0200244 udelay(25); /* Wait at least 20 us */
Marek Vasuteb2749a2022-04-13 04:15:23 +0200245 } while (dm9000_ior(DM9000_NCR) & 1);
Remy Bohmer2f13d2c2008-06-03 15:26:24 +0200246
Marek Vasuteb2749a2022-04-13 04:15:23 +0200247 dm9000_iow(DM9000_NCR, 0);
248 dm9000_iow(DM9000_NCR, (NCR_LBK_INT_MAC | NCR_RST)); /* Issue a second reset */
Remy Bohmer2f13d2c2008-06-03 15:26:24 +0200249
250 do {
Marek Vasuted761222022-04-13 04:15:24 +0200251 debug("resetting the DM9000, 2nd reset\n");
Remy Bohmer2f13d2c2008-06-03 15:26:24 +0200252 udelay(25); /* Wait at least 20 us */
Marek Vasuteb2749a2022-04-13 04:15:23 +0200253 } while (dm9000_ior(DM9000_NCR) & 1);
Remy Bohmer2f13d2c2008-06-03 15:26:24 +0200254
255 /* Check whether the ethernet controller is present */
Marek Vasuteb2749a2022-04-13 04:15:23 +0200256 if ((dm9000_ior(DM9000_PIDL) != 0x0) ||
257 (dm9000_ior(DM9000_PIDH) != 0x90))
Remy Bohmer2f13d2c2008-06-03 15:26:24 +0200258 printf("ERROR: resetting DM9000 -> not responding\n");
wdenk7ac16102004-08-01 22:48:16 +0000259}
260
Remy Bohmer7eefd922009-05-02 21:49:18 +0200261/* Initialize dm9000 board
wdenk7ac16102004-08-01 22:48:16 +0000262*/
Masahiro Yamadaf7ed78b2020-06-26 15:13:33 +0900263static int dm9000_init(struct eth_device *dev, struct bd_info *bd)
wdenk7ac16102004-08-01 22:48:16 +0000264{
265 int i, oft, lnk;
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200266 u8 io_mode;
267 struct board_info *db = &dm9000_info;
268
Marek Vasuted761222022-04-13 04:15:24 +0200269 debug("%s\n", __func__);
wdenk7ac16102004-08-01 22:48:16 +0000270
271 /* RESET device */
272 dm9000_reset();
Andrew Dyera62f5d42008-08-26 17:03:38 -0500273
274 if (dm9000_probe() < 0)
275 return -1;
wdenk7ac16102004-08-01 22:48:16 +0000276
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200277 /* Auto-detect 8/16/32 bit mode, ISR Bit 6+7 indicate bus width */
Marek Vasuteb2749a2022-04-13 04:15:23 +0200278 io_mode = dm9000_ior(DM9000_ISR) >> 6;
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200279
280 switch (io_mode) {
281 case 0x0: /* 16-bit mode */
282 printf("DM9000: running in 16 bit mode\n");
283 db->outblk = dm9000_outblk_16bit;
284 db->inblk = dm9000_inblk_16bit;
285 db->rx_status = dm9000_rx_status_16bit;
286 break;
287 case 0x01: /* 32-bit mode */
288 printf("DM9000: running in 32 bit mode\n");
289 db->outblk = dm9000_outblk_32bit;
290 db->inblk = dm9000_inblk_32bit;
291 db->rx_status = dm9000_rx_status_32bit;
292 break;
293 case 0x02: /* 8 bit mode */
294 printf("DM9000: running in 8 bit mode\n");
295 db->outblk = dm9000_outblk_8bit;
296 db->inblk = dm9000_inblk_8bit;
297 db->rx_status = dm9000_rx_status_8bit;
298 break;
299 default:
300 /* Assume 8 bit mode, will probably not work anyway */
301 printf("DM9000: Undefined IO-mode:0x%x\n", io_mode);
302 db->outblk = dm9000_outblk_8bit;
303 db->inblk = dm9000_inblk_8bit;
304 db->rx_status = dm9000_rx_status_8bit;
305 break;
306 }
307
Andrew Dyera62f5d42008-08-26 17:03:38 -0500308 /* Program operating register, only internal phy supported */
Marek Vasuteb2749a2022-04-13 04:15:23 +0200309 dm9000_iow(DM9000_NCR, 0x0);
Remy Bohmer61b8dbd2008-06-03 15:26:26 +0200310 /* TX Polling clear */
Marek Vasuteb2749a2022-04-13 04:15:23 +0200311 dm9000_iow(DM9000_TCR, 0);
Remy Bohmer61b8dbd2008-06-03 15:26:26 +0200312 /* Less 3Kb, 200us */
Marek Vasuteb2749a2022-04-13 04:15:23 +0200313 dm9000_iow(DM9000_BPTR, BPTR_BPHW(3) | BPTR_JPT_600US);
Remy Bohmer61b8dbd2008-06-03 15:26:26 +0200314 /* Flow Control : High/Low Water */
Marek Vasuteb2749a2022-04-13 04:15:23 +0200315 dm9000_iow(DM9000_FCTR, FCTR_HWOT(3) | FCTR_LWOT(8));
Remy Bohmer61b8dbd2008-06-03 15:26:26 +0200316 /* SH FIXME: This looks strange! Flow Control */
Marek Vasuteb2749a2022-04-13 04:15:23 +0200317 dm9000_iow(DM9000_FCR, 0x0);
Remy Bohmer61b8dbd2008-06-03 15:26:26 +0200318 /* Special Mode */
Marek Vasuteb2749a2022-04-13 04:15:23 +0200319 dm9000_iow(DM9000_SMCR, 0);
Remy Bohmer61b8dbd2008-06-03 15:26:26 +0200320 /* clear TX status */
Marek Vasuteb2749a2022-04-13 04:15:23 +0200321 dm9000_iow(DM9000_NSR, NSR_WAKEST | NSR_TX2END | NSR_TX1END);
Remy Bohmer61b8dbd2008-06-03 15:26:26 +0200322 /* Clear interrupt status */
Marek Vasuteb2749a2022-04-13 04:15:23 +0200323 dm9000_iow(DM9000_ISR, ISR_ROOS | ISR_ROS | ISR_PTS | ISR_PRS);
wdenk7ac16102004-08-01 22:48:16 +0000324
Ben Warren8707f622009-10-21 21:53:39 -0700325 printf("MAC: %pM\n", dev->enetaddr);
Joe Hershberger8ecdbed2015-04-08 01:41:04 -0500326 if (!is_valid_ethaddr(dev->enetaddr)) {
Andrew Ruder1c377d12013-10-22 19:09:02 -0500327 printf("WARNING: Bad MAC address (uninitialized EEPROM?)\n");
Andrew Ruder1c377d12013-10-22 19:09:02 -0500328 }
Andrew Dyera62f5d42008-08-26 17:03:38 -0500329
330 /* fill device MAC address registers */
331 for (i = 0, oft = DM9000_PAR; i < 6; i++, oft++)
Marek Vasuteb2749a2022-04-13 04:15:23 +0200332 dm9000_iow(oft, dev->enetaddr[i]);
wdenk7ac16102004-08-01 22:48:16 +0000333 for (i = 0, oft = 0x16; i < 8; i++, oft++)
Marek Vasuteb2749a2022-04-13 04:15:23 +0200334 dm9000_iow(oft, 0xff);
wdenk7ac16102004-08-01 22:48:16 +0000335
336 /* read back mac, just to be sure */
337 for (i = 0, oft = 0x10; i < 6; i++, oft++)
Marek Vasuted761222022-04-13 04:15:24 +0200338 debug("%02x:", dm9000_ior(oft));
339 debug("\n");
wdenk7ac16102004-08-01 22:48:16 +0000340
341 /* Activate DM9000 */
Remy Bohmer61b8dbd2008-06-03 15:26:26 +0200342 /* RX enable */
Marek Vasuteb2749a2022-04-13 04:15:23 +0200343 dm9000_iow(DM9000_RCR, RCR_DIS_LONG | RCR_DIS_CRC | RCR_RXEN);
Remy Bohmer61b8dbd2008-06-03 15:26:26 +0200344 /* Enable TX/RX interrupt mask */
Marek Vasuteb2749a2022-04-13 04:15:23 +0200345 dm9000_iow(DM9000_IMR, IMR_PAR);
Remy Bohmer61b8dbd2008-06-03 15:26:26 +0200346
wdenk7ac16102004-08-01 22:48:16 +0000347 i = 0;
Andy Fleming0d2df962011-03-22 22:49:13 -0500348 while (!(dm9000_phy_read(1) & 0x20)) { /* autonegation complete bit */
wdenk7ac16102004-08-01 22:48:16 +0000349 udelay(1000);
350 i++;
351 if (i == 10000) {
352 printf("could not establish link\n");
353 return 0;
354 }
355 }
356
357 /* see what we've got */
Andy Fleming0d2df962011-03-22 22:49:13 -0500358 lnk = dm9000_phy_read(17) >> 12;
wdenk7ac16102004-08-01 22:48:16 +0000359 printf("operating at ");
360 switch (lnk) {
361 case 1:
362 printf("10M half duplex ");
363 break;
364 case 2:
365 printf("10M full duplex ");
366 break;
367 case 4:
368 printf("100M half duplex ");
369 break;
370 case 8:
371 printf("100M full duplex ");
372 break;
373 default:
374 printf("unknown: %d ", lnk);
375 break;
376 }
377 printf("mode\n");
378 return 0;
379}
380
381/*
382 Hardware start transmission.
383 Send a packet to media from the upper layer.
384*/
Joe Hershbergerab1ac412012-05-21 14:45:23 +0000385static int dm9000_send(struct eth_device *netdev, void *packet, int length)
wdenk7ac16102004-08-01 22:48:16 +0000386{
wdenk7ac16102004-08-01 22:48:16 +0000387 int tmo;
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200388 struct board_info *db = &dm9000_info;
389
Marek Vasut52006d22022-04-13 04:15:27 +0200390 dm9000_dump_packet(__func__ , packet, length);
wdenk7ac16102004-08-01 22:48:16 +0000391
Marek Vasuteb2749a2022-04-13 04:15:23 +0200392 dm9000_iow(DM9000_ISR, IMR_PTM); /* Clear Tx bit in ISR */
Remy Bohmer16cb2642008-06-03 15:26:23 +0200393
wdenk7ac16102004-08-01 22:48:16 +0000394 /* Move data to DM9000 TX RAM */
Marek Vasuteb2749a2022-04-13 04:15:23 +0200395 dm9000_outb(DM9000_MWCMD, DM9000_IO); /* Prepare for TX-data */
wdenk7ac16102004-08-01 22:48:16 +0000396
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200397 /* push the data to the TX-fifo */
Remy Bohmer90d1fed2008-06-05 13:03:36 +0200398 (db->outblk)(packet, length);
wdenk7ac16102004-08-01 22:48:16 +0000399
400 /* Set TX length to DM9000 */
Marek Vasuteb2749a2022-04-13 04:15:23 +0200401 dm9000_iow(DM9000_TXPLL, length & 0xff);
402 dm9000_iow(DM9000_TXPLH, (length >> 8) & 0xff);
wdenk7ac16102004-08-01 22:48:16 +0000403
404 /* Issue TX polling command */
Marek Vasuteb2749a2022-04-13 04:15:23 +0200405 dm9000_iow(DM9000_TCR, TCR_TXREQ); /* Cleared after TX complete */
wdenk7ac16102004-08-01 22:48:16 +0000406
407 /* wait for end of transmission */
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200408 tmo = get_timer(0) + 5 * CONFIG_SYS_HZ;
Marek Vasuteb2749a2022-04-13 04:15:23 +0200409 while ( !(dm9000_ior(DM9000_NSR) & (NSR_TX1END | NSR_TX2END)) ||
410 !(dm9000_ior(DM9000_ISR) & IMR_PTM) ) {
wdenk7ac16102004-08-01 22:48:16 +0000411 if (get_timer(0) >= tmo) {
412 printf("transmission timeout\n");
413 break;
414 }
415 }
Marek Vasuteb2749a2022-04-13 04:15:23 +0200416 dm9000_iow(DM9000_ISR, IMR_PTM); /* Clear Tx bit in ISR */
Remy Bohmer16cb2642008-06-03 15:26:23 +0200417
Marek Vasuted761222022-04-13 04:15:24 +0200418 debug("transmit done\n\n");
wdenk7ac16102004-08-01 22:48:16 +0000419 return 0;
420}
421
422/*
423 Stop the interface.
424 The interface is stopped when it is brought.
425*/
Remy Bohmer7eefd922009-05-02 21:49:18 +0200426static void dm9000_halt(struct eth_device *netdev)
wdenk7ac16102004-08-01 22:48:16 +0000427{
Marek Vasuted761222022-04-13 04:15:24 +0200428 debug("%s\n", __func__);
wdenk7ac16102004-08-01 22:48:16 +0000429
430 /* RESET devie */
Andy Fleming0d2df962011-03-22 22:49:13 -0500431 dm9000_phy_write(0, 0x8000); /* PHY RESET */
Marek Vasuteb2749a2022-04-13 04:15:23 +0200432 dm9000_iow(DM9000_GPR, 0x01); /* Power-Down PHY */
433 dm9000_iow(DM9000_IMR, 0x80); /* Disable all interrupt */
434 dm9000_iow(DM9000_RCR, 0x00); /* Disable RX */
wdenk7ac16102004-08-01 22:48:16 +0000435}
436
437/*
438 Received a packet and pass to upper layer
439*/
Remy Bohmer7eefd922009-05-02 21:49:18 +0200440static int dm9000_rx(struct eth_device *netdev)
wdenk7ac16102004-08-01 22:48:16 +0000441{
Joe Hershberger9f09a362015-04-08 01:41:06 -0500442 u8 rxbyte;
443 u8 *rdptr = (u8 *)net_rx_packets[0];
Marek Vasut5248e562022-04-13 04:15:25 +0200444 u16 rxstatus, rxlen = 0;
Remy Bohmer5f63bf42008-06-03 15:26:21 +0200445 struct board_info *db = &dm9000_info;
wdenk7ac16102004-08-01 22:48:16 +0000446
Remy Bohmereec38a12008-06-03 15:26:25 +0200447 /* Check packet ready or not, we must check
448 the ISR status first for DM9000A */
Marek Vasuteb2749a2022-04-13 04:15:23 +0200449 if (!(dm9000_ior(DM9000_ISR) & 0x01)) /* Rx-ISR bit must be set. */
wdenk7ac16102004-08-01 22:48:16 +0000450 return 0;
451
Marek Vasuteb2749a2022-04-13 04:15:23 +0200452 dm9000_iow(DM9000_ISR, 0x01); /* clear PR status latched in bit 0 */
wdenk7ac16102004-08-01 22:48:16 +0000453
Remy Bohmereec38a12008-06-03 15:26:25 +0200454 /* There is _at least_ 1 package in the fifo, read them all */
455 for (;;) {
Marek Vasuteb2749a2022-04-13 04:15:23 +0200456 dm9000_ior(DM9000_MRCMDX); /* Dummy read */
wdenk7ac16102004-08-01 22:48:16 +0000457
Remy Bohmer90d1fed2008-06-05 13:03:36 +0200458 /* Get most updated data,
459 only look at bits 0:1, See application notes DM9000 */
Marek Vasuteb2749a2022-04-13 04:15:23 +0200460 rxbyte = dm9000_inb(DM9000_DATA) & 0x03;
wdenk7ac16102004-08-01 22:48:16 +0000461
Remy Bohmereec38a12008-06-03 15:26:25 +0200462 /* Status check: this byte must be 0 or 1 */
463 if (rxbyte > DM9000_PKT_RDY) {
Marek Vasuteb2749a2022-04-13 04:15:23 +0200464 dm9000_iow(DM9000_RCR, 0x00); /* Stop Device */
465 dm9000_iow(DM9000_ISR, 0x80); /* Stop INT request */
Remy Bohmereec38a12008-06-03 15:26:25 +0200466 printf("DM9000 error: status check fail: 0x%x\n",
467 rxbyte);
468 return 0;
469 }
wdenk7ac16102004-08-01 22:48:16 +0000470
Remy Bohmereec38a12008-06-03 15:26:25 +0200471 if (rxbyte != DM9000_PKT_RDY)
472 return 0; /* No packet received, ignore */
wdenk7ac16102004-08-01 22:48:16 +0000473
Marek Vasuted761222022-04-13 04:15:24 +0200474 debug("receiving packet\n");
Remy Bohmereec38a12008-06-03 15:26:25 +0200475
476 /* A packet ready now & Get status/length */
Marek Vasut5248e562022-04-13 04:15:25 +0200477 (db->rx_status)(&rxstatus, &rxlen);
wdenk7ac16102004-08-01 22:48:16 +0000478
Marek Vasut5248e562022-04-13 04:15:25 +0200479 debug("rx status: 0x%04x rx len: %d\n", rxstatus, rxlen);
Remy Bohmereec38a12008-06-03 15:26:25 +0200480
481 /* Move data from DM9000 */
482 /* Read received packet from RX SRAM */
Marek Vasut5248e562022-04-13 04:15:25 +0200483 (db->inblk)(rdptr, rxlen);
Remy Bohmereec38a12008-06-03 15:26:25 +0200484
Marek Vasut5248e562022-04-13 04:15:25 +0200485 if ((rxstatus & 0xbf00) || (rxlen < 0x40)
486 || (rxlen > DM9000_PKT_MAX)) {
487 if (rxstatus & 0x100) {
Remy Bohmereec38a12008-06-03 15:26:25 +0200488 printf("rx fifo error\n");
489 }
Marek Vasut5248e562022-04-13 04:15:25 +0200490 if (rxstatus & 0x200) {
Remy Bohmereec38a12008-06-03 15:26:25 +0200491 printf("rx crc error\n");
492 }
Marek Vasut5248e562022-04-13 04:15:25 +0200493 if (rxstatus & 0x8000) {
Remy Bohmereec38a12008-06-03 15:26:25 +0200494 printf("rx length error\n");
495 }
Marek Vasut5248e562022-04-13 04:15:25 +0200496 if (rxlen > DM9000_PKT_MAX) {
Remy Bohmereec38a12008-06-03 15:26:25 +0200497 printf("rx length too big\n");
498 dm9000_reset();
499 }
500 } else {
Marek Vasut52006d22022-04-13 04:15:27 +0200501 dm9000_dump_packet(__func__ , rdptr, rxlen);
Remy Bohmereec38a12008-06-03 15:26:25 +0200502
Marek Vasuted761222022-04-13 04:15:24 +0200503 debug("passing packet to upper layer\n");
Marek Vasut5248e562022-04-13 04:15:25 +0200504 net_process_received_packet(net_rx_packets[0], rxlen);
Remy Bohmereec38a12008-06-03 15:26:25 +0200505 }
wdenk7ac16102004-08-01 22:48:16 +0000506 }
507 return 0;
508}
509
510/*
511 Read a word data from SROM
512*/
Remy Bohmercd9a36c2009-05-03 12:11:40 +0200513#if !defined(CONFIG_DM9000_NO_SROM)
514void dm9000_read_srom_word(int offset, u8 *to)
wdenk7ac16102004-08-01 22:48:16 +0000515{
Marek Vasuteb2749a2022-04-13 04:15:23 +0200516 dm9000_iow(DM9000_EPAR, offset);
517 dm9000_iow(DM9000_EPCR, 0x4);
stefano babicedb06872007-08-21 15:50:33 +0200518 udelay(8000);
Marek Vasuteb2749a2022-04-13 04:15:23 +0200519 dm9000_iow(DM9000_EPCR, 0x0);
520 to[0] = dm9000_ior(DM9000_EPDRL);
521 to[1] = dm9000_ior(DM9000_EPDRH);
wdenk7ac16102004-08-01 22:48:16 +0000522}
523
Remy Bohmercd9a36c2009-05-03 12:11:40 +0200524void dm9000_write_srom_word(int offset, u16 val)
stefano babic6708a602007-08-30 23:01:49 +0200525{
Marek Vasuteb2749a2022-04-13 04:15:23 +0200526 dm9000_iow(DM9000_EPAR, offset);
527 dm9000_iow(DM9000_EPDRH, ((val >> 8) & 0xff));
528 dm9000_iow(DM9000_EPDRL, (val & 0xff));
529 dm9000_iow(DM9000_EPCR, 0x12);
stefano babic6708a602007-08-30 23:01:49 +0200530 udelay(8000);
Marek Vasuteb2749a2022-04-13 04:15:23 +0200531 dm9000_iow(DM9000_EPCR, 0);
stefano babic6708a602007-08-30 23:01:49 +0200532}
Remy Bohmercd9a36c2009-05-03 12:11:40 +0200533#endif
Ben Warren8707f622009-10-21 21:53:39 -0700534
535static void dm9000_get_enetaddr(struct eth_device *dev)
536{
537#if !defined(CONFIG_DM9000_NO_SROM)
538 int i;
539 for (i = 0; i < 3; i++)
540 dm9000_read_srom_word(i, dev->enetaddr + (2 * i));
541#endif
542}
stefano babic6708a602007-08-30 23:01:49 +0200543
wdenk7ac16102004-08-01 22:48:16 +0000544/*
545 Read a byte from I/O port
546*/
547static u8
Marek Vasuteb2749a2022-04-13 04:15:23 +0200548dm9000_ior(int reg)
wdenk7ac16102004-08-01 22:48:16 +0000549{
Marek Vasuteb2749a2022-04-13 04:15:23 +0200550 dm9000_outb(reg, DM9000_IO);
551 return dm9000_inb(DM9000_DATA);
wdenk7ac16102004-08-01 22:48:16 +0000552}
553
554/*
555 Write a byte to I/O port
556*/
557static void
Marek Vasuteb2749a2022-04-13 04:15:23 +0200558dm9000_iow(int reg, u8 value)
wdenk7ac16102004-08-01 22:48:16 +0000559{
Marek Vasuteb2749a2022-04-13 04:15:23 +0200560 dm9000_outb(reg, DM9000_IO);
561 dm9000_outb(value, DM9000_DATA);
wdenk7ac16102004-08-01 22:48:16 +0000562}
563
564/*
565 Read a word from phyxcer
566*/
567static u16
Andy Fleming0d2df962011-03-22 22:49:13 -0500568dm9000_phy_read(int reg)
wdenk7ac16102004-08-01 22:48:16 +0000569{
570 u16 val;
571
572 /* Fill the phyxcer register into REG_0C */
Marek Vasuteb2749a2022-04-13 04:15:23 +0200573 dm9000_iow(DM9000_EPAR, DM9000_PHY | reg);
574 dm9000_iow(DM9000_EPCR, 0xc); /* Issue phyxcer read command */
Remy Bohmer61b8dbd2008-06-03 15:26:26 +0200575 udelay(100); /* Wait read complete */
Marek Vasuteb2749a2022-04-13 04:15:23 +0200576 dm9000_iow(DM9000_EPCR, 0x0); /* Clear phyxcer read command */
577 val = (dm9000_ior(DM9000_EPDRH) << 8) | dm9000_ior(DM9000_EPDRL);
wdenk7ac16102004-08-01 22:48:16 +0000578
579 /* The read data keeps on REG_0D & REG_0E */
Marek Vasuted761222022-04-13 04:15:24 +0200580 debug("dm9000_phy_read(0x%x): 0x%x\n", reg, val);
wdenk7ac16102004-08-01 22:48:16 +0000581 return val;
582}
583
584/*
585 Write a word to phyxcer
586*/
587static void
Andy Fleming0d2df962011-03-22 22:49:13 -0500588dm9000_phy_write(int reg, u16 value)
wdenk7ac16102004-08-01 22:48:16 +0000589{
590
591 /* Fill the phyxcer register into REG_0C */
Marek Vasuteb2749a2022-04-13 04:15:23 +0200592 dm9000_iow(DM9000_EPAR, DM9000_PHY | reg);
wdenk7ac16102004-08-01 22:48:16 +0000593
594 /* Fill the written data into REG_0D & REG_0E */
Marek Vasuteb2749a2022-04-13 04:15:23 +0200595 dm9000_iow(DM9000_EPDRL, (value & 0xff));
596 dm9000_iow(DM9000_EPDRH, ((value >> 8) & 0xff));
597 dm9000_iow(DM9000_EPCR, 0xa); /* Issue phyxcer write command */
Remy Bohmer61b8dbd2008-06-03 15:26:26 +0200598 udelay(500); /* Wait write complete */
Marek Vasuteb2749a2022-04-13 04:15:23 +0200599 dm9000_iow(DM9000_EPCR, 0x0); /* Clear phyxcer write command */
Marek Vasuted761222022-04-13 04:15:24 +0200600 debug("dm9000_phy_write(reg:0x%x, value:0x%x)\n", reg, value);
wdenk7ac16102004-08-01 22:48:16 +0000601}
Remy Bohmer7eefd922009-05-02 21:49:18 +0200602
Masahiro Yamadaf7ed78b2020-06-26 15:13:33 +0900603int dm9000_initialize(struct bd_info *bis)
Remy Bohmer7eefd922009-05-02 21:49:18 +0200604{
605 struct eth_device *dev = &(dm9000_info.netdev);
606
Ben Warren8707f622009-10-21 21:53:39 -0700607 /* Load MAC address from EEPROM */
608 dm9000_get_enetaddr(dev);
609
Remy Bohmer7eefd922009-05-02 21:49:18 +0200610 dev->init = dm9000_init;
611 dev->halt = dm9000_halt;
612 dev->send = dm9000_send;
613 dev->recv = dm9000_rx;
Ben Whitten34fd6c92015-12-30 13:05:58 +0000614 strcpy(dev->name, "dm9000");
Remy Bohmer7eefd922009-05-02 21:49:18 +0200615
616 eth_register(dev);
617
618 return 0;
619}