blob: 85f3c079ec1f6dcf7bb8e55c96d9fcdf16895ce1 [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
wdenk281e00a2004-08-01 22:48:16 +00002/*
Marek Vasuta7bebf82022-04-13 04:15:29 +02003 * 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 *
8 * (C)Copyright 1997-1998 DAVICOM Semiconductor,Inc. All Rights Reserved.
9 *
10 * V0.11 06/20/2001 REG_0A bit3=1, default enable BP with DA match
11 * 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
17 *
18 * v1.00 modify by simon 2001.9.5
19 * change for kernel 2.4.x
20 *
21 * v1.1 11/09/2001 fix force mode bug
22 *
23 * v1.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 *
30 * 12/15/2003 Initial port to u-boot by
31 * Sascha Hauer <saschahauer@web.de>
32 *
33 * 06/03/2008 Remy Bohmer <linux@bohmer.net>
34 * - 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)
38 * - Added autodetect of databus width.
39 * - Made debug code compile again.
40 * - Adapt eth_send such that it matches the DM9000*
41 * application notes. Needed to make it work properly
42 * for DM9000A.
43 * - Adapted reset procedure to match DM9000 application
44 * notes (i.e. double reset)
45 * - some minor code cleanups
46 * These changes are tested with DM9000{A,EP,E} together
47 * with a 200MHz Atmel AT91SAM9261 core
48 *
49 * TODO: external MII is not functional, only internal at the moment.
50 */
wdenk281e00a2004-08-01 22:48:16 +000051
52#include <common.h>
53#include <command.h>
54#include <net.h>
55#include <asm/io.h>
Remy Bohmere5a3bc22009-05-03 12:11:40 +020056#include <dm9000.h>
Simon Glassc05ed002020-05-10 11:40:11 -060057#include <linux/delay.h>
wdenk281e00a2004-08-01 22:48:16 +000058
wdenk281e00a2004-08-01 22:48:16 +000059#include "dm9000x.h"
60
wdenk281e00a2004-08-01 22:48:16 +000061/* Structure/enum declaration ------------------------------- */
Marek Vasuta7bebf82022-04-13 04:15:29 +020062struct board_info {
wdenk281e00a2004-08-01 22:48:16 +000063 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 */
wdenk281e00a2004-08-01 22:48:16 +000073 unsigned char srom[128];
Marek Vasut6d3de0f2022-04-13 04:15:28 +020074 void (*outblk)(void *data_ptr, int count);
Remy Bohmera1013612008-06-03 15:26:21 +020075 void (*inblk)(void *data_ptr, int count);
Marek Vasutd8f21b22022-04-13 04:15:25 +020076 void (*rx_status)(u16 *rxstatus, u16 *rxlen);
Remy Bohmer60f61e62009-05-02 21:49:18 +020077 struct eth_device netdev;
Marek Vasuta7bebf82022-04-13 04:15:29 +020078};
wdenk281e00a2004-08-01 22:48:16 +000079
Marek Vasuta7bebf82022-04-13 04:15:29 +020080static struct board_info dm9000_info;
Remy Bohmer60f61e62009-05-02 21:49:18 +020081
wdenk281e00a2004-08-01 22:48:16 +000082/* DM9000 network board routine ---------------------------- */
Jason Jin5c1d0822011-08-25 15:46:43 +080083#ifndef CONFIG_DM9000_BYTE_SWAPPED
Marek Vasuta7bebf82022-04-13 04:15:29 +020084#define dm9000_outb(d, r) writeb((d), (r))
85#define dm9000_outw(d, r) writew((d), (r))
86#define dm9000_outl(d, r) writel((d), (r))
Marek Vasut6d3de0f2022-04-13 04:15:28 +020087#define dm9000_inb(r) readb(r)
88#define dm9000_inw(r) readw(r)
89#define dm9000_inl(r) readl(r)
Jason Jin5c1d0822011-08-25 15:46:43 +080090#else
Marek Vasutff61d4e2022-04-13 04:15:23 +020091#define dm9000_outb(d, r) __raw_writeb(d, r)
92#define dm9000_outw(d, r) __raw_writew(d, r)
93#define dm9000_outl(d, r) __raw_writel(d, r)
94#define dm9000_inb(r) __raw_readb(r)
95#define dm9000_inw(r) __raw_readw(r)
96#define dm9000_inl(r) __raw_readl(r)
Jason Jin5c1d0822011-08-25 15:46:43 +080097#endif
wdenk281e00a2004-08-01 22:48:16 +000098
Marek Vasutc7b7ee52022-04-13 04:15:27 +020099#ifdef DEBUG
100static void dm9000_dump_packet(const char *func, u8 *packet, int length)
101{
102 int i;
103
104 printf("%s: length: %d\n", func, length);
105
106 for (i = 0; i < length; i++) {
107 if (i % 8 == 0)
108 printf("\n%s: %02x: ", func, i);
109 printf("%02x ", packet[i]);
110 }
111
112 printf("\n");
113}
114#else
115static void dm9000_dump_packet(const char *func, u8 *packet, int length) {}
116#endif
117
Marek Vasut6d3de0f2022-04-13 04:15:28 +0200118static void dm9000_outblk_8bit(void *data_ptr, int count)
Remy Bohmera1013612008-06-03 15:26:21 +0200119{
120 int i;
Marek Vasuta7bebf82022-04-13 04:15:29 +0200121
Remy Bohmera1013612008-06-03 15:26:21 +0200122 for (i = 0; i < count; i++)
Marek Vasuta7bebf82022-04-13 04:15:29 +0200123 dm9000_outb((((u8 *)data_ptr)[i] & 0xff), DM9000_DATA);
Remy Bohmera1013612008-06-03 15:26:21 +0200124}
125
Marek Vasut6d3de0f2022-04-13 04:15:28 +0200126static void dm9000_outblk_16bit(void *data_ptr, int count)
Remy Bohmera1013612008-06-03 15:26:21 +0200127{
128 int i;
129 u32 tmplen = (count + 1) / 2;
130
131 for (i = 0; i < tmplen; i++)
Marek Vasuta7bebf82022-04-13 04:15:29 +0200132 dm9000_outw(((u16 *)data_ptr)[i], DM9000_DATA);
Remy Bohmera1013612008-06-03 15:26:21 +0200133}
Marek Vasuta7bebf82022-04-13 04:15:29 +0200134
Marek Vasut6d3de0f2022-04-13 04:15:28 +0200135static void dm9000_outblk_32bit(void *data_ptr, int count)
Remy Bohmera1013612008-06-03 15:26:21 +0200136{
137 int i;
138 u32 tmplen = (count + 3) / 4;
139
140 for (i = 0; i < tmplen; i++)
Marek Vasuta7bebf82022-04-13 04:15:29 +0200141 dm9000_outl(((u32 *)data_ptr)[i], DM9000_DATA);
Remy Bohmera1013612008-06-03 15:26:21 +0200142}
143
144static void dm9000_inblk_8bit(void *data_ptr, int count)
145{
146 int i;
Marek Vasuta7bebf82022-04-13 04:15:29 +0200147
Remy Bohmera1013612008-06-03 15:26:21 +0200148 for (i = 0; i < count; i++)
Marek Vasuta7bebf82022-04-13 04:15:29 +0200149 ((u8 *)data_ptr)[i] = dm9000_inb(DM9000_DATA);
Remy Bohmera1013612008-06-03 15:26:21 +0200150}
151
152static void dm9000_inblk_16bit(void *data_ptr, int count)
153{
154 int i;
155 u32 tmplen = (count + 1) / 2;
156
157 for (i = 0; i < tmplen; i++)
Marek Vasuta7bebf82022-04-13 04:15:29 +0200158 ((u16 *)data_ptr)[i] = dm9000_inw(DM9000_DATA);
Remy Bohmera1013612008-06-03 15:26:21 +0200159}
Marek Vasuta7bebf82022-04-13 04:15:29 +0200160
Remy Bohmera1013612008-06-03 15:26:21 +0200161static void dm9000_inblk_32bit(void *data_ptr, int count)
162{
163 int i;
164 u32 tmplen = (count + 3) / 4;
165
166 for (i = 0; i < tmplen; i++)
Marek Vasuta7bebf82022-04-13 04:15:29 +0200167 ((u32 *)data_ptr)[i] = dm9000_inl(DM9000_DATA);
Remy Bohmera1013612008-06-03 15:26:21 +0200168}
169
Marek Vasutd8f21b22022-04-13 04:15:25 +0200170static void dm9000_rx_status_32bit(u16 *rxstatus, u16 *rxlen)
Remy Bohmera1013612008-06-03 15:26:21 +0200171{
Remy Bohmerd6ee5fa2008-06-04 10:47:25 +0200172 u32 tmpdata;
Remy Bohmera1013612008-06-03 15:26:21 +0200173
Marek Vasutff61d4e2022-04-13 04:15:23 +0200174 dm9000_outb(DM9000_MRCMD, DM9000_IO);
Remy Bohmera1013612008-06-03 15:26:21 +0200175
Marek Vasutff61d4e2022-04-13 04:15:23 +0200176 tmpdata = dm9000_inl(DM9000_DATA);
Marek Vasutd8f21b22022-04-13 04:15:25 +0200177 *rxstatus = __le16_to_cpu(tmpdata);
178 *rxlen = __le16_to_cpu(tmpdata >> 16);
Remy Bohmera1013612008-06-03 15:26:21 +0200179}
180
Marek Vasutd8f21b22022-04-13 04:15:25 +0200181static void dm9000_rx_status_16bit(u16 *rxstatus, u16 *rxlen)
Remy Bohmera1013612008-06-03 15:26:21 +0200182{
Marek Vasutff61d4e2022-04-13 04:15:23 +0200183 dm9000_outb(DM9000_MRCMD, DM9000_IO);
Remy Bohmera1013612008-06-03 15:26:21 +0200184
Marek Vasutd8f21b22022-04-13 04:15:25 +0200185 *rxstatus = __le16_to_cpu(dm9000_inw(DM9000_DATA));
186 *rxlen = __le16_to_cpu(dm9000_inw(DM9000_DATA));
Remy Bohmera1013612008-06-03 15:26:21 +0200187}
188
Marek Vasutd8f21b22022-04-13 04:15:25 +0200189static void dm9000_rx_status_8bit(u16 *rxstatus, u16 *rxlen)
Remy Bohmera1013612008-06-03 15:26:21 +0200190{
Marek Vasutff61d4e2022-04-13 04:15:23 +0200191 dm9000_outb(DM9000_MRCMD, DM9000_IO);
Remy Bohmera1013612008-06-03 15:26:21 +0200192
Marek Vasutd8f21b22022-04-13 04:15:25 +0200193 *rxstatus =
Marek Vasutff61d4e2022-04-13 04:15:23 +0200194 __le16_to_cpu(dm9000_inb(DM9000_DATA) +
195 (dm9000_inb(DM9000_DATA) << 8));
Marek Vasutd8f21b22022-04-13 04:15:25 +0200196 *rxlen =
Marek Vasutff61d4e2022-04-13 04:15:23 +0200197 __le16_to_cpu(dm9000_inb(DM9000_DATA) +
198 (dm9000_inb(DM9000_DATA) << 8));
Remy Bohmera1013612008-06-03 15:26:21 +0200199}
wdenk281e00a2004-08-01 22:48:16 +0000200
201/*
Marek Vasuta2e92302022-04-13 04:15:30 +0200202 * Read a byte from I/O port
203 */
204static u8 dm9000_ior(int reg)
205{
206 dm9000_outb(reg, DM9000_IO);
207 return dm9000_inb(DM9000_DATA);
208}
209
210/*
211 * Write a byte to I/O port
212 */
213static void dm9000_iow(int reg, u8 value)
214{
215 dm9000_outb(reg, DM9000_IO);
216 dm9000_outb(value, DM9000_DATA);
217}
218
219/*
220 * Read a word from phyxcer
221 */
222static u16 dm9000_phy_read(int reg)
223{
224 u16 val;
225
226 /* Fill the phyxcer register into REG_0C */
227 dm9000_iow(DM9000_EPAR, DM9000_PHY | reg);
228 dm9000_iow(DM9000_EPCR, 0xc); /* Issue phyxcer read command */
229 udelay(100); /* Wait read complete */
230 dm9000_iow(DM9000_EPCR, 0x0); /* Clear phyxcer read command */
231 val = (dm9000_ior(DM9000_EPDRH) << 8) | dm9000_ior(DM9000_EPDRL);
232
233 /* The read data keeps on REG_0D & REG_0E */
234 debug("%s(0x%x): 0x%x\n", __func__, reg, val);
235 return val;
236}
237
238/*
239 * Write a word to phyxcer
240 */
241static void dm9000_phy_write(int reg, u16 value)
242{
243 /* Fill the phyxcer register into REG_0C */
244 dm9000_iow(DM9000_EPAR, DM9000_PHY | reg);
245
246 /* Fill the written data into REG_0D & REG_0E */
247 dm9000_iow(DM9000_EPDRL, (value & 0xff));
248 dm9000_iow(DM9000_EPDRH, ((value >> 8) & 0xff));
249 dm9000_iow(DM9000_EPCR, 0xa); /* Issue phyxcer write command */
250 udelay(500); /* Wait write complete */
251 dm9000_iow(DM9000_EPCR, 0x0); /* Clear phyxcer write command */
252 debug("%s(reg:0x%x, value:0x%x)\n", __func__, reg, value);
253}
254
255/*
Marek Vasuta7bebf82022-04-13 04:15:29 +0200256 * Search DM9000 board, allocate space and register it
257 */
Marek Vasuta2e92302022-04-13 04:15:30 +0200258static int dm9000_probe(void)
wdenk281e00a2004-08-01 22:48:16 +0000259{
260 u32 id_val;
Marek Vasuta7bebf82022-04-13 04:15:29 +0200261
Marek Vasutff61d4e2022-04-13 04:15:23 +0200262 id_val = dm9000_ior(DM9000_VIDL);
263 id_val |= dm9000_ior(DM9000_VIDH) << 8;
264 id_val |= dm9000_ior(DM9000_PIDL) << 16;
265 id_val |= dm9000_ior(DM9000_PIDH) << 24;
Marek Vasuta7bebf82022-04-13 04:15:29 +0200266 if (id_val != DM9000_ID) {
wdenk281e00a2004-08-01 22:48:16 +0000267 printf("dm9000 not found at 0x%08x id: 0x%08x\n",
268 CONFIG_DM9000_BASE, id_val);
269 return -1;
270 }
Marek Vasuta7bebf82022-04-13 04:15:29 +0200271
272 printf("dm9000 i/o: 0x%x, id: 0x%x\n", CONFIG_DM9000_BASE, id_val);
273 return 0;
wdenk281e00a2004-08-01 22:48:16 +0000274}
275
wdenk281e00a2004-08-01 22:48:16 +0000276/* General Purpose dm9000 reset routine */
277static void
278dm9000_reset(void)
279{
Marek Vasut42a7e0f2022-04-13 04:15:24 +0200280 debug("resetting DM9000\n");
Remy Bohmerfbcb7ec2008-06-03 15:26:24 +0200281
Marek Vasuta7bebf82022-04-13 04:15:29 +0200282 /*
283 * Reset DM9000,
284 * see DM9000 Application Notes V1.22 Jun 11, 2004 page 29
285 */
Remy Bohmerfbcb7ec2008-06-03 15:26:24 +0200286
Andrew Dyerd26b7392008-08-26 17:03:38 -0500287 /* DEBUG: Make all GPIO0 outputs, all others inputs */
Marek Vasutff61d4e2022-04-13 04:15:23 +0200288 dm9000_iow(DM9000_GPCR, GPCR_GPIO0_OUT);
Remy Bohmerfbcb7ec2008-06-03 15:26:24 +0200289 /* Step 1: Power internal PHY by writing 0 to GPIO0 pin */
Marek Vasutff61d4e2022-04-13 04:15:23 +0200290 dm9000_iow(DM9000_GPR, 0);
Remy Bohmerfbcb7ec2008-06-03 15:26:24 +0200291 /* Step 2: Software reset */
Marek Vasutff61d4e2022-04-13 04:15:23 +0200292 dm9000_iow(DM9000_NCR, (NCR_LBK_INT_MAC | NCR_RST));
Remy Bohmerfbcb7ec2008-06-03 15:26:24 +0200293
294 do {
Marek Vasut42a7e0f2022-04-13 04:15:24 +0200295 debug("resetting the DM9000, 1st reset\n");
Remy Bohmerfbcb7ec2008-06-03 15:26:24 +0200296 udelay(25); /* Wait at least 20 us */
Marek Vasutff61d4e2022-04-13 04:15:23 +0200297 } while (dm9000_ior(DM9000_NCR) & 1);
Remy Bohmerfbcb7ec2008-06-03 15:26:24 +0200298
Marek Vasutff61d4e2022-04-13 04:15:23 +0200299 dm9000_iow(DM9000_NCR, 0);
300 dm9000_iow(DM9000_NCR, (NCR_LBK_INT_MAC | NCR_RST)); /* Issue a second reset */
Remy Bohmerfbcb7ec2008-06-03 15:26:24 +0200301
302 do {
Marek Vasut42a7e0f2022-04-13 04:15:24 +0200303 debug("resetting the DM9000, 2nd reset\n");
Remy Bohmerfbcb7ec2008-06-03 15:26:24 +0200304 udelay(25); /* Wait at least 20 us */
Marek Vasutff61d4e2022-04-13 04:15:23 +0200305 } while (dm9000_ior(DM9000_NCR) & 1);
Remy Bohmerfbcb7ec2008-06-03 15:26:24 +0200306
307 /* Check whether the ethernet controller is present */
Marek Vasutff61d4e2022-04-13 04:15:23 +0200308 if ((dm9000_ior(DM9000_PIDL) != 0x0) ||
309 (dm9000_ior(DM9000_PIDH) != 0x90))
Remy Bohmerfbcb7ec2008-06-03 15:26:24 +0200310 printf("ERROR: resetting DM9000 -> not responding\n");
wdenk281e00a2004-08-01 22:48:16 +0000311}
312
Marek Vasuta7bebf82022-04-13 04:15:29 +0200313/* Initialize dm9000 board */
Masahiro Yamadab75d8dc2020-06-26 15:13:33 +0900314static int dm9000_init(struct eth_device *dev, struct bd_info *bd)
wdenk281e00a2004-08-01 22:48:16 +0000315{
316 int i, oft, lnk;
Remy Bohmera1013612008-06-03 15:26:21 +0200317 u8 io_mode;
318 struct board_info *db = &dm9000_info;
319
wdenk281e00a2004-08-01 22:48:16 +0000320 /* RESET device */
321 dm9000_reset();
Andrew Dyerd26b7392008-08-26 17:03:38 -0500322
323 if (dm9000_probe() < 0)
324 return -1;
wdenk281e00a2004-08-01 22:48:16 +0000325
Remy Bohmera1013612008-06-03 15:26:21 +0200326 /* Auto-detect 8/16/32 bit mode, ISR Bit 6+7 indicate bus width */
Marek Vasutff61d4e2022-04-13 04:15:23 +0200327 io_mode = dm9000_ior(DM9000_ISR) >> 6;
Remy Bohmera1013612008-06-03 15:26:21 +0200328
329 switch (io_mode) {
330 case 0x0: /* 16-bit mode */
331 printf("DM9000: running in 16 bit mode\n");
332 db->outblk = dm9000_outblk_16bit;
333 db->inblk = dm9000_inblk_16bit;
334 db->rx_status = dm9000_rx_status_16bit;
335 break;
336 case 0x01: /* 32-bit mode */
337 printf("DM9000: running in 32 bit mode\n");
338 db->outblk = dm9000_outblk_32bit;
339 db->inblk = dm9000_inblk_32bit;
340 db->rx_status = dm9000_rx_status_32bit;
341 break;
342 case 0x02: /* 8 bit mode */
343 printf("DM9000: running in 8 bit mode\n");
344 db->outblk = dm9000_outblk_8bit;
345 db->inblk = dm9000_inblk_8bit;
346 db->rx_status = dm9000_rx_status_8bit;
347 break;
348 default:
349 /* Assume 8 bit mode, will probably not work anyway */
350 printf("DM9000: Undefined IO-mode:0x%x\n", io_mode);
351 db->outblk = dm9000_outblk_8bit;
352 db->inblk = dm9000_inblk_8bit;
353 db->rx_status = dm9000_rx_status_8bit;
354 break;
355 }
356
Andrew Dyerd26b7392008-08-26 17:03:38 -0500357 /* Program operating register, only internal phy supported */
Marek Vasutff61d4e2022-04-13 04:15:23 +0200358 dm9000_iow(DM9000_NCR, 0x0);
Remy Bohmer98291e22008-06-03 15:26:26 +0200359 /* TX Polling clear */
Marek Vasutff61d4e2022-04-13 04:15:23 +0200360 dm9000_iow(DM9000_TCR, 0);
Remy Bohmer98291e22008-06-03 15:26:26 +0200361 /* Less 3Kb, 200us */
Marek Vasutff61d4e2022-04-13 04:15:23 +0200362 dm9000_iow(DM9000_BPTR, BPTR_BPHW(3) | BPTR_JPT_600US);
Remy Bohmer98291e22008-06-03 15:26:26 +0200363 /* Flow Control : High/Low Water */
Marek Vasutff61d4e2022-04-13 04:15:23 +0200364 dm9000_iow(DM9000_FCTR, FCTR_HWOT(3) | FCTR_LWOT(8));
Remy Bohmer98291e22008-06-03 15:26:26 +0200365 /* SH FIXME: This looks strange! Flow Control */
Marek Vasutff61d4e2022-04-13 04:15:23 +0200366 dm9000_iow(DM9000_FCR, 0x0);
Remy Bohmer98291e22008-06-03 15:26:26 +0200367 /* Special Mode */
Marek Vasutff61d4e2022-04-13 04:15:23 +0200368 dm9000_iow(DM9000_SMCR, 0);
Remy Bohmer98291e22008-06-03 15:26:26 +0200369 /* clear TX status */
Marek Vasutff61d4e2022-04-13 04:15:23 +0200370 dm9000_iow(DM9000_NSR, NSR_WAKEST | NSR_TX2END | NSR_TX1END);
Remy Bohmer98291e22008-06-03 15:26:26 +0200371 /* Clear interrupt status */
Marek Vasutff61d4e2022-04-13 04:15:23 +0200372 dm9000_iow(DM9000_ISR, ISR_ROOS | ISR_ROS | ISR_PTS | ISR_PRS);
wdenk281e00a2004-08-01 22:48:16 +0000373
Ben Warren07754372009-10-21 21:53:39 -0700374 printf("MAC: %pM\n", dev->enetaddr);
Marek Vasuta7bebf82022-04-13 04:15:29 +0200375 if (!is_valid_ethaddr(dev->enetaddr))
Andrew Ruderc583ee12013-10-22 19:09:02 -0500376 printf("WARNING: Bad MAC address (uninitialized EEPROM?)\n");
Andrew Dyerd26b7392008-08-26 17:03:38 -0500377
378 /* fill device MAC address registers */
379 for (i = 0, oft = DM9000_PAR; i < 6; i++, oft++)
Marek Vasutff61d4e2022-04-13 04:15:23 +0200380 dm9000_iow(oft, dev->enetaddr[i]);
wdenk281e00a2004-08-01 22:48:16 +0000381 for (i = 0, oft = 0x16; i < 8; i++, oft++)
Marek Vasutff61d4e2022-04-13 04:15:23 +0200382 dm9000_iow(oft, 0xff);
wdenk281e00a2004-08-01 22:48:16 +0000383
384 /* read back mac, just to be sure */
385 for (i = 0, oft = 0x10; i < 6; i++, oft++)
Marek Vasut42a7e0f2022-04-13 04:15:24 +0200386 debug("%02x:", dm9000_ior(oft));
387 debug("\n");
wdenk281e00a2004-08-01 22:48:16 +0000388
389 /* Activate DM9000 */
Remy Bohmer98291e22008-06-03 15:26:26 +0200390 /* RX enable */
Marek Vasutff61d4e2022-04-13 04:15:23 +0200391 dm9000_iow(DM9000_RCR, RCR_DIS_LONG | RCR_DIS_CRC | RCR_RXEN);
Remy Bohmer98291e22008-06-03 15:26:26 +0200392 /* Enable TX/RX interrupt mask */
Marek Vasutff61d4e2022-04-13 04:15:23 +0200393 dm9000_iow(DM9000_IMR, IMR_PAR);
Remy Bohmer98291e22008-06-03 15:26:26 +0200394
wdenk281e00a2004-08-01 22:48:16 +0000395 i = 0;
Andy Fleming09c04c22011-03-22 22:49:13 -0500396 while (!(dm9000_phy_read(1) & 0x20)) { /* autonegation complete bit */
wdenk281e00a2004-08-01 22:48:16 +0000397 udelay(1000);
398 i++;
399 if (i == 10000) {
400 printf("could not establish link\n");
401 return 0;
402 }
403 }
404
405 /* see what we've got */
Andy Fleming09c04c22011-03-22 22:49:13 -0500406 lnk = dm9000_phy_read(17) >> 12;
wdenk281e00a2004-08-01 22:48:16 +0000407 printf("operating at ");
408 switch (lnk) {
409 case 1:
410 printf("10M half duplex ");
411 break;
412 case 2:
413 printf("10M full duplex ");
414 break;
415 case 4:
416 printf("100M half duplex ");
417 break;
418 case 8:
419 printf("100M full duplex ");
420 break;
421 default:
422 printf("unknown: %d ", lnk);
423 break;
424 }
425 printf("mode\n");
426 return 0;
427}
428
429/*
Marek Vasuta7bebf82022-04-13 04:15:29 +0200430 * Hardware start transmission.
431 * Send a packet to media from the upper layer.
432 */
Joe Hershberger7f9a8a62012-05-21 14:45:23 +0000433static int dm9000_send(struct eth_device *netdev, void *packet, int length)
wdenk281e00a2004-08-01 22:48:16 +0000434{
wdenk281e00a2004-08-01 22:48:16 +0000435 int tmo;
Remy Bohmera1013612008-06-03 15:26:21 +0200436 struct board_info *db = &dm9000_info;
437
Marek Vasuta7bebf82022-04-13 04:15:29 +0200438 dm9000_dump_packet(__func__, packet, length);
wdenk281e00a2004-08-01 22:48:16 +0000439
Marek Vasutff61d4e2022-04-13 04:15:23 +0200440 dm9000_iow(DM9000_ISR, IMR_PTM); /* Clear Tx bit in ISR */
Remy Bohmeracba3182008-06-03 15:26:23 +0200441
wdenk281e00a2004-08-01 22:48:16 +0000442 /* Move data to DM9000 TX RAM */
Marek Vasutff61d4e2022-04-13 04:15:23 +0200443 dm9000_outb(DM9000_MWCMD, DM9000_IO); /* Prepare for TX-data */
wdenk281e00a2004-08-01 22:48:16 +0000444
Remy Bohmera1013612008-06-03 15:26:21 +0200445 /* push the data to the TX-fifo */
Marek Vasuta7bebf82022-04-13 04:15:29 +0200446 db->outblk(packet, length);
wdenk281e00a2004-08-01 22:48:16 +0000447
448 /* Set TX length to DM9000 */
Marek Vasutff61d4e2022-04-13 04:15:23 +0200449 dm9000_iow(DM9000_TXPLL, length & 0xff);
450 dm9000_iow(DM9000_TXPLH, (length >> 8) & 0xff);
wdenk281e00a2004-08-01 22:48:16 +0000451
452 /* Issue TX polling command */
Marek Vasutff61d4e2022-04-13 04:15:23 +0200453 dm9000_iow(DM9000_TCR, TCR_TXREQ); /* Cleared after TX complete */
wdenk281e00a2004-08-01 22:48:16 +0000454
455 /* wait for end of transmission */
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200456 tmo = get_timer(0) + 5 * CONFIG_SYS_HZ;
Marek Vasuta7bebf82022-04-13 04:15:29 +0200457 while (!(dm9000_ior(DM9000_NSR) & (NSR_TX1END | NSR_TX2END)) ||
458 !(dm9000_ior(DM9000_ISR) & IMR_PTM)) {
wdenk281e00a2004-08-01 22:48:16 +0000459 if (get_timer(0) >= tmo) {
460 printf("transmission timeout\n");
461 break;
462 }
463 }
Marek Vasutff61d4e2022-04-13 04:15:23 +0200464 dm9000_iow(DM9000_ISR, IMR_PTM); /* Clear Tx bit in ISR */
Remy Bohmeracba3182008-06-03 15:26:23 +0200465
Marek Vasut42a7e0f2022-04-13 04:15:24 +0200466 debug("transmit done\n\n");
wdenk281e00a2004-08-01 22:48:16 +0000467 return 0;
468}
469
470/*
Marek Vasuta7bebf82022-04-13 04:15:29 +0200471 * Stop the interface.
472 * The interface is stopped when it is brought.
473 */
Remy Bohmer60f61e62009-05-02 21:49:18 +0200474static void dm9000_halt(struct eth_device *netdev)
wdenk281e00a2004-08-01 22:48:16 +0000475{
Marek Vasuta7bebf82022-04-13 04:15:29 +0200476 /* RESET device */
Andy Fleming09c04c22011-03-22 22:49:13 -0500477 dm9000_phy_write(0, 0x8000); /* PHY RESET */
Marek Vasutff61d4e2022-04-13 04:15:23 +0200478 dm9000_iow(DM9000_GPR, 0x01); /* Power-Down PHY */
479 dm9000_iow(DM9000_IMR, 0x80); /* Disable all interrupt */
480 dm9000_iow(DM9000_RCR, 0x00); /* Disable RX */
wdenk281e00a2004-08-01 22:48:16 +0000481}
482
483/*
Marek Vasuta7bebf82022-04-13 04:15:29 +0200484 * Received a packet and pass to upper layer
485 */
Remy Bohmer60f61e62009-05-02 21:49:18 +0200486static int dm9000_rx(struct eth_device *netdev)
wdenk281e00a2004-08-01 22:48:16 +0000487{
Joe Hershberger1fd92db2015-04-08 01:41:06 -0500488 u8 rxbyte;
489 u8 *rdptr = (u8 *)net_rx_packets[0];
Marek Vasutd8f21b22022-04-13 04:15:25 +0200490 u16 rxstatus, rxlen = 0;
Remy Bohmera1013612008-06-03 15:26:21 +0200491 struct board_info *db = &dm9000_info;
wdenk281e00a2004-08-01 22:48:16 +0000492
Marek Vasuta7bebf82022-04-13 04:15:29 +0200493 /*
494 * Check packet ready or not, we must check
495 * the ISR status first for DM9000A
496 */
Marek Vasutff61d4e2022-04-13 04:15:23 +0200497 if (!(dm9000_ior(DM9000_ISR) & 0x01)) /* Rx-ISR bit must be set. */
wdenk281e00a2004-08-01 22:48:16 +0000498 return 0;
499
Marek Vasutff61d4e2022-04-13 04:15:23 +0200500 dm9000_iow(DM9000_ISR, 0x01); /* clear PR status latched in bit 0 */
wdenk281e00a2004-08-01 22:48:16 +0000501
Remy Bohmer850ba752008-06-03 15:26:25 +0200502 /* There is _at least_ 1 package in the fifo, read them all */
503 for (;;) {
Marek Vasutff61d4e2022-04-13 04:15:23 +0200504 dm9000_ior(DM9000_MRCMDX); /* Dummy read */
wdenk281e00a2004-08-01 22:48:16 +0000505
Marek Vasuta7bebf82022-04-13 04:15:29 +0200506 /*
507 * Get most updated data,
508 * only look at bits 0:1, See application notes DM9000
509 */
Marek Vasutff61d4e2022-04-13 04:15:23 +0200510 rxbyte = dm9000_inb(DM9000_DATA) & 0x03;
wdenk281e00a2004-08-01 22:48:16 +0000511
Remy Bohmer850ba752008-06-03 15:26:25 +0200512 /* Status check: this byte must be 0 or 1 */
513 if (rxbyte > DM9000_PKT_RDY) {
Marek Vasutff61d4e2022-04-13 04:15:23 +0200514 dm9000_iow(DM9000_RCR, 0x00); /* Stop Device */
515 dm9000_iow(DM9000_ISR, 0x80); /* Stop INT request */
Remy Bohmer850ba752008-06-03 15:26:25 +0200516 printf("DM9000 error: status check fail: 0x%x\n",
Marek Vasuta7bebf82022-04-13 04:15:29 +0200517 rxbyte);
Remy Bohmer850ba752008-06-03 15:26:25 +0200518 return 0;
wdenk281e00a2004-08-01 22:48:16 +0000519 }
wdenk281e00a2004-08-01 22:48:16 +0000520
Remy Bohmer850ba752008-06-03 15:26:25 +0200521 if (rxbyte != DM9000_PKT_RDY)
522 return 0; /* No packet received, ignore */
523
Marek Vasut42a7e0f2022-04-13 04:15:24 +0200524 debug("receiving packet\n");
Remy Bohmer850ba752008-06-03 15:26:25 +0200525
526 /* A packet ready now & Get status/length */
Marek Vasuta7bebf82022-04-13 04:15:29 +0200527 db->rx_status(&rxstatus, &rxlen);
Remy Bohmer850ba752008-06-03 15:26:25 +0200528
Marek Vasutd8f21b22022-04-13 04:15:25 +0200529 debug("rx status: 0x%04x rx len: %d\n", rxstatus, rxlen);
Remy Bohmer850ba752008-06-03 15:26:25 +0200530
531 /* Move data from DM9000 */
532 /* Read received packet from RX SRAM */
Marek Vasuta7bebf82022-04-13 04:15:29 +0200533 db->inblk(rdptr, rxlen);
Remy Bohmer850ba752008-06-03 15:26:25 +0200534
Marek Vasuta7bebf82022-04-13 04:15:29 +0200535 if (rxstatus & 0xbf00 || rxlen < 0x40 ||
536 rxlen > DM9000_PKT_MAX) {
537 if (rxstatus & 0x100)
Remy Bohmer850ba752008-06-03 15:26:25 +0200538 printf("rx fifo error\n");
Marek Vasuta7bebf82022-04-13 04:15:29 +0200539 if (rxstatus & 0x200)
Remy Bohmer850ba752008-06-03 15:26:25 +0200540 printf("rx crc error\n");
Marek Vasuta7bebf82022-04-13 04:15:29 +0200541 if (rxstatus & 0x8000)
Remy Bohmer850ba752008-06-03 15:26:25 +0200542 printf("rx length error\n");
Marek Vasutd8f21b22022-04-13 04:15:25 +0200543 if (rxlen > DM9000_PKT_MAX) {
Remy Bohmer850ba752008-06-03 15:26:25 +0200544 printf("rx length too big\n");
545 dm9000_reset();
546 }
547 } else {
Marek Vasuta7bebf82022-04-13 04:15:29 +0200548 dm9000_dump_packet(__func__, rdptr, rxlen);
Remy Bohmer850ba752008-06-03 15:26:25 +0200549
Marek Vasut42a7e0f2022-04-13 04:15:24 +0200550 debug("passing packet to upper layer\n");
Marek Vasutd8f21b22022-04-13 04:15:25 +0200551 net_process_received_packet(net_rx_packets[0], rxlen);
Remy Bohmer850ba752008-06-03 15:26:25 +0200552 }
wdenk281e00a2004-08-01 22:48:16 +0000553 }
554 return 0;
555}
556
557/*
Marek Vasuta7bebf82022-04-13 04:15:29 +0200558 * Read a word data from SROM
559 */
Remy Bohmere5a3bc22009-05-03 12:11:40 +0200560#if !defined(CONFIG_DM9000_NO_SROM)
561void dm9000_read_srom_word(int offset, u8 *to)
wdenk281e00a2004-08-01 22:48:16 +0000562{
Marek Vasutff61d4e2022-04-13 04:15:23 +0200563 dm9000_iow(DM9000_EPAR, offset);
564 dm9000_iow(DM9000_EPCR, 0x4);
Marek Vasuta7bebf82022-04-13 04:15:29 +0200565 mdelay(8);
Marek Vasutff61d4e2022-04-13 04:15:23 +0200566 dm9000_iow(DM9000_EPCR, 0x0);
567 to[0] = dm9000_ior(DM9000_EPDRL);
568 to[1] = dm9000_ior(DM9000_EPDRH);
wdenk281e00a2004-08-01 22:48:16 +0000569}
570
Remy Bohmere5a3bc22009-05-03 12:11:40 +0200571void dm9000_write_srom_word(int offset, u16 val)
stefano babic5e5803e2007-08-30 23:01:49 +0200572{
Marek Vasutff61d4e2022-04-13 04:15:23 +0200573 dm9000_iow(DM9000_EPAR, offset);
574 dm9000_iow(DM9000_EPDRH, ((val >> 8) & 0xff));
575 dm9000_iow(DM9000_EPDRL, (val & 0xff));
576 dm9000_iow(DM9000_EPCR, 0x12);
Marek Vasuta7bebf82022-04-13 04:15:29 +0200577 mdelay(8);
Marek Vasutff61d4e2022-04-13 04:15:23 +0200578 dm9000_iow(DM9000_EPCR, 0);
stefano babic5e5803e2007-08-30 23:01:49 +0200579}
stefano babic5e5803e2007-08-30 23:01:49 +0200580
Ben Warren07754372009-10-21 21:53:39 -0700581static void dm9000_get_enetaddr(struct eth_device *dev)
582{
Ben Warren07754372009-10-21 21:53:39 -0700583 int i;
Marek Vasuta7bebf82022-04-13 04:15:29 +0200584
Ben Warren07754372009-10-21 21:53:39 -0700585 for (i = 0; i < 3; i++)
586 dm9000_read_srom_word(i, dev->enetaddr + (2 * i));
Ben Warren07754372009-10-21 21:53:39 -0700587}
Marek Vasuta7bebf82022-04-13 04:15:29 +0200588#else
589static void dm9000_get_enetaddr(struct eth_device *dev) {}
590#endif
Ben Warren07754372009-10-21 21:53:39 -0700591
Masahiro Yamadab75d8dc2020-06-26 15:13:33 +0900592int dm9000_initialize(struct bd_info *bis)
Remy Bohmer60f61e62009-05-02 21:49:18 +0200593{
Marek Vasuta7bebf82022-04-13 04:15:29 +0200594 struct eth_device *dev = &dm9000_info.netdev;
Remy Bohmer60f61e62009-05-02 21:49:18 +0200595
Ben Warren07754372009-10-21 21:53:39 -0700596 /* Load MAC address from EEPROM */
597 dm9000_get_enetaddr(dev);
598
Remy Bohmer60f61e62009-05-02 21:49:18 +0200599 dev->init = dm9000_init;
600 dev->halt = dm9000_halt;
601 dev->send = dm9000_send;
602 dev->recv = dm9000_rx;
Ben Whitten192bc692015-12-30 13:05:58 +0000603 strcpy(dev->name, "dm9000");
Remy Bohmer60f61e62009-05-02 21:49:18 +0200604
605 eth_register(dev);
606
607 return 0;
608}