12061Sjkh/*	$NetBSD: wd80x3.c,v 1.9 2008/04/28 20:23:25 martin Exp $	*/
250479Speter
32061Sjkh/*-
438666Sjb * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
532427Sjb * All rights reserved.
6111131Sru *
7111131Sru * This code is derived from software contributed to The NetBSD Foundation
8217733Sbz * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
9217733Sbz * NASA Ames Research Center.
1038666Sjb *
1138666Sjb * Redistribution and use in source and binary forms, with or without
1238666Sjb * modification, are permitted provided that the following conditions
13159363Strhodes * are met:
1464049Salex * 1. Redistributions of source code must retain the above copyright
1564049Salex *    notice, this list of conditions and the following disclaimer.
16116679Ssimokawa * 2. Redistributions in binary form must reproduce the above copyright
1766071Smarkm *    notice, this list of conditions and the following disclaimer in the
18116679Ssimokawa *    documentation and/or other materials provided with the distribution.
1973504Sobrien *
20204661Simp * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21232907Sjmallett * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22158962Snetchild * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23223148Sru * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24169597Sdes * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25169597Sdes * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26169597Sdes * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27169597Sdes * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28231821Spluknet * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29169597Sdes * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30169597Sdes * POSSIBILITY OF SUCH DAMAGE.
31169597Sdes */
32217815Sbz
33217815Sbz/*
34218524Sjhb * Device driver for National Semiconductor DS8390/WD83C690 based ethernet
35253002Salfred * adapters.
36253002Salfred *
37253002Salfred * Copyright (c) 1994, 1995 Charles M. Hannum.  All rights reserved.
38253002Salfred *
39253002Salfred * Copyright (C) 1993, David Greenman.  This software may be used, modified,
40253003Salfred * copied, distributed, and sold, in both source and binary form provided that
4132427Sjb * the above copyright and these terms are retained.  Under no circumstances is
4238666Sjb * the author responsible for the proper functioning of this software, nor does
43108451Sschweikh * the author assume any responsibility for damages incurred with its use.
4438666Sjb */
4538666Sjb
4638666Sjb/*
4738666Sjb * Device driver for the Western Digital/SMC 8003 and 8013 series,
4817308Speter * and the SMC Elite Ultra (8216).
49217273Simp */
50217294Simp
5119175Sbde#include <sys/types.h>
5296205Sjwd#include <machine/pio.h>
53217297Simp
54217297Simp#include <lib/libsa/stand.h>
5538042Sbde#include <libi386.h>
5696205Sjwd
5796205Sjwd#ifdef _STANDALONE
5838042Sbde#include <lib/libkern/libkern.h>
5996205Sjwd#include <bootinfo.h>
60159363Strhodes#endif
61159363Strhodes
6217308Speter#include "etherdrv.h"
6396205Sjwd#include <dev/ic/dp8390reg.h>
6496205Sjwd#include "dp8390.h"
6517308Speter#include <dev/ic/wereg.h>
66148330Snetchild
67148330Snetchild#ifndef BASEREG
68148330Snetchild#define BASEREG 0x240
69148330Snetchild#define BASEMEM 0xd0000
70159831Sobrien#endif
71148330Snetchild
72148330Snetchild#define	WD_BASEREG BASEREG
73148330Snetchild#define	WD_BASEMEM BASEMEM
74251107Screes
75251107Screes#ifndef _STANDALONE
76148330Snetchildextern int mapio(void);
77148330Snetchild#endif
7896205Sjwd
7996205Sjwdu_char eth_myaddr[6];
8096205Sjwd
81162147Srustatic uint8_t we_type;
82162147Srustatic int we_is16bit;
8398723Sdillon
8498723Sdillon#ifdef _STANDALONE
8598723Sdillonstatic struct btinfo_netif bi_netif;
8638666Sjb#endif
8738666Sjb
8817308Speterconst char *
89123311Speterwe_params(void)
90123311Speter{
91123311Speter	const char *typestr;
92123311Speter
93175833Sjhb	dp8390_memsize = 8192;
94175833Sjhb
95169597Sdes	we_type = inb(WD_BASEREG + WE_CARD_ID);
96169597Sdes	switch (we_type) {
97169597Sdes#ifdef SUPPORT_WD80X3
98169597Sdes	case WE_TYPE_WD8003S:
99219177Snwhitehorn		typestr = "WD8003S";
100219177Snwhitehorn		break;
101238051Sobrien	case WE_TYPE_WD8003E:
102219177Snwhitehorn		typestr = "WD8003E";
103219177Snwhitehorn		break;
104158962Snetchild	case WE_TYPE_WD8003EB:
105156840Sru		typestr = "WD8003EB";
106123311Speter		break;
107137288Speter	case WE_TYPE_WD8003W:
108209128Sraj		typestr = "WD8003W";
109209128Sraj		break;
110156740Sru	case WE_TYPE_WD8013EBT:
1112061Sjkh		typestr = "WD8013EBT";
11297769Sru		dp8390_memsize = 16384;
11397252Sru		we_is16bit = 1;
114119579Sru		break;
11597252Sru	case WE_TYPE_WD8013W:
11695730Sru		typestr = "WD8013W";
11795793Sru		dp8390_memsize = 16384;
118111617Sru		we_is16bit = 1;
11995730Sru		break;
120116679Ssimokawa	case WE_TYPE_WD8013EP:		/* also WD8003EP */
12195730Sru		if (inb(WD_BASEREG + WE_ICR) & WE_ICR_16BIT) {
122116679Ssimokawa			we_is16bit = 1;
12395730Sru			dp8390_memsize = 16384;
124110035Sru			typestr = "WD8013EP";
125107516Sru		} else
126138921Sru			typestr = "WD8003EP";
127156145Syar		break;
128138921Sru	case WE_TYPE_WD8013WC:
129133942Sru		typestr = "WD8013WC";
130133942Sru		dp8390_memsize = 16384;
131156145Syar		we_is16bit = 1;
132133942Sru		break;
133253616Ssjg	case WE_TYPE_WD8013EBP:
134253616Ssjg		typestr = "WD8013EBP";
135253616Ssjg		dp8390_memsize = 16384;
136253616Ssjg		we_is16bit = 1;
137253616Ssjg		break;
138253616Ssjg	case WE_TYPE_WD8013EPC:
139253616Ssjg		typestr = "WD8013EPC";
140253616Ssjg		dp8390_memsize = 16384;
141253616Ssjg		we_is16bit = 1;
142253616Ssjg		break;
143253616Ssjg#endif
144253616Ssjg#ifdef SUPPORT_SMC_ULTRA
145253616Ssjg	case WE_TYPE_SMC8216C:
146253616Ssjg	case WE_TYPE_SMC8216T:
147253616Ssjg	    {
148253616Ssjg		uint8_t hwr;
149253616Ssjg
150253616Ssjg		typestr = (we_type == WE_TYPE_SMC8216C) ?
151253616Ssjg		    "SMC8216/SMC8216C" : "SMC8216T";
152253616Ssjg
153253616Ssjg		hwr = inb(WD_BASEREG + WE790_HWR);
154253616Ssjg		outb(WD_BASEREG + WE790_HWR, hwr | WE790_HWR_SWH);
155117229Sru		switch (inb(WD_BASEREG + WE790_RAR) & WE790_RAR_SZ64) {
156253616Ssjg		case WE790_RAR_SZ64:
157253616Ssjg			dp8390_memsize = 65536;
158253616Ssjg			break;
15954324Smarcel		case WE790_RAR_SZ32:
160253616Ssjg			dp8390_memsize = 32768;
161253616Ssjg			break;
162218130Simp		case WE790_RAR_SZ16:
163218130Simp			dp8390_memsize = 16384;
164233644Sjmallett			break;
165218130Simp		case WE790_RAR_SZ8:
166218130Simp			/* 8216 has 16K shared mem -- 8416 has 8K */
167239272Sgonzo			typestr = (we_type == WE_TYPE_SMC8216C) ?
168218130Simp			    "SMC8416C/SMC8416BT" : "SMC8416T";
169233644Sjmallett			dp8390_memsize = 8192;
170218130Simp			break;
171233644Sjmallett		}
172233644Sjmallett		outb(WD_BASEREG + WE790_HWR, hwr);
173233644Sjmallett
174218130Simp		we_is16bit = 1;
175233644Sjmallett#ifdef SUPPORT_WD80X3
176233644Sjmallett		dp8390_is790 = 1;
177218130Simp#endif
178218130Simp		break;
179218130Simp	    }
180218130Simp#endif
181218130Simp	default:
182218130Simp		/* Not one we recognize. */
183218130Simp		return NULL;
184218130Simp	}
185218130Simp
186218130Simp	/*
187218130Simp	 * Make some adjustments to initial values depending on what is
188218130Simp	 * found in the ICR.
189218130Simp	 */
190218130Simp	if (we_is16bit && (we_type != WE_TYPE_WD8013EBT) &&
191218130Simp	    (inb(WD_BASEREG + WE_ICR) & WE_ICR_16BIT) == 0) {
192218130Simp		we_is16bit = 0;
19317308Speter		dp8390_memsize = 8192;
194119519Smarcel	}
195119519Smarcel
196119519Smarcel#ifdef WE_DEBUG
197119519Smarcel	{
198119519Smarcel		int i;
199119519Smarcel
200119579Sru		printf("we_params: type = 0x%x, typestr = %s, is16bit = %d, "
201119519Smarcel		    "memsize = %d\n", we_type, typestr, we_is16bit, dp8390_memsize);
202119519Smarcel		for (i = 0; i < 8; i++)
203119519Smarcel			printf("     %d -> 0x%x\n", i,
204119519Smarcel			    inb(WD_BASEREG + i));
205119519Smarcel	}
206126031Sgad#endif
207126024Sgad
208126024Sgad	return typestr;
209126024Sgad}
210126024Sgad
211126024Sgadint
212126024SgadEtherInit(unsigned char *myadr)
213126024Sgad{
214227771Sgjb	const char *typestr;
215126024Sgad	uint8_t x;
216126024Sgad	int i;
217227769Sgjb	uint8_t laar_proto;
218227771Sgjb	uint8_t msr_proto;
219227771Sgjb
220126024Sgad	dp8390_iobase = WD_BASEREG + WE_NIC_OFFSET;
221126024Sgad	dp8390_membase = WD_BASEMEM;
222126031Sgad
223126024Sgad#ifndef _STANDALONE
224126024Sgad	if (mapio()) {
225126024Sgad		printf("no IO access\n");
226172744Sdelphij		return 0;
227126024Sgad	}
228126024Sgad#endif
229126024Sgad
230133376Sharti	for (x = 0, i = 0; i < 8; i++)
231126024Sgad		x += inb(WD_BASEREG + WE_PROM + i);
232126024Sgad
233172744Sdelphij	if (x != WE_ROM_CHECKSUM_TOTAL)
234126024Sgad		return 0;
235126024Sgad
236125885Sgad	/* reset the ethernet card */
237125885Sgad	outb(WD_BASEREG + WE_MSR, WE_MSR_RST);
23838666Sjb	delay(100);
23917308Speter	outb(WD_BASEREG + WE_MSR, inb(WD_BASEREG + WE_MSR) & ~WE_MSR_RST);
240119519Smarcel	delay(5000);
241251750Ssjg
242251750Ssjg	typestr = we_params();
243251750Ssjg	if (!typestr)
244251750Ssjg		return 0;
245254417Ssjg
246251750Ssjg	printf("Using %s board, port 0x%x, iomem 0x%x, iosiz %d\n",
247251750Ssjg	       typestr, WD_BASEREG, WD_BASEMEM, dp8390_memsize);
248119579Sru
249218206Simp	/* get ethernet address */
2502302Spaul	for (i = 0; i < 6; i++)
25139206Sjkh		eth_myaddr[i] = myadr[i]= inb(WD_BASEREG + WE_PROM + i);
25239206Sjkh
25339206Sjkh	/*
254133945Sru	 * Set upper address bits and 8/16 bit access to shared memory.
255240403Sobrien	 */
256177609Sru	if (dp8390_is790) {
257177609Sru		laar_proto = inb(WD_BASEREG + WE_LAAR) & ~WE_LAAR_M16EN;
258177609Sru		outb(WD_BASEREG + WE_LAAR, laar_proto |
259133945Sru		     (we_is16bit ? WE_LAAR_M16EN : 0));
260132358Smarkm	} else if ((we_type & WE_SOFTCONFIG) ||
26117308Speter		   (we_type == WE_TYPE_WD8013EBT)) {
26254324Smarcel		laar_proto = (WD_BASEMEM >> 19) & WE_LAAR_ADDRHI;
26354324Smarcel		if (we_is16bit)
264132234Smarcel			laar_proto |= WE_LAAR_L16EN;
265132234Smarcel		outb(WD_BASEREG + WE_LAAR, laar_proto |
266132234Smarcel		     (we_is16bit ? WE_LAAR_M16EN : 0));
267132234Smarcel	}
26854324Smarcel
26954324Smarcel	/*
27054324Smarcel	 * Set address and enable interface shared memory.
271118531Sru	 */
27254324Smarcel	if (dp8390_is790) {
27354324Smarcel		/* XXX MAGIC CONSTANTS XXX */
27454324Smarcel		x = inb(WD_BASEREG + 0x04);
27554324Smarcel		outb(WD_BASEREG + 0x04, x | 0x80);
27654324Smarcel		outb(WD_BASEREG + 0x0b,
27754324Smarcel		    ((WD_BASEMEM >> 13) & 0x0f) |
278133376Sharti		    ((WD_BASEMEM >> 11) & 0x40) |
27954324Smarcel		    (inb(WD_BASEREG + 0x0b) & 0xb0));
280133376Sharti		outb(WD_BASEREG + 0x04, x);
281133376Sharti		msr_proto = 0x00;
28254324Smarcel		dp8390_cr_proto = 0x00;
28354324Smarcel	} else {
28454324Smarcel		msr_proto = (WD_BASEMEM >> 13) & WE_MSR_ADDR;
28554324Smarcel		dp8390_cr_proto = ED_CR_RD2;
28654324Smarcel	}
287133376Sharti
28854324Smarcel	outb(WD_BASEREG +  WE_MSR, msr_proto | WE_MSR_MENB);
28954324Smarcel	delay(2);
29054324Smarcel
291118531Sru	/*
292118531Sru	 * DCR gets:
29354324Smarcel	 *
294132234Smarcel	 *	FIFO threshold to 8, No auto-init Remote DMA,
295132234Smarcel	 *	byte order=80x86.
296132234Smarcel	 *
297132234Smarcel	 * 16-bit cards also get word-wide DMA transfers.
298132234Smarcel	 */
299132588Skensmith	dp8390_dcr_reg = ED_DCR_FT1 | ED_DCR_LS | (we_is16bit ? ED_DCR_WTS : 0);
300132358Smarkm
301132234Smarcel	if (dp8390_config())
302132358Smarkm		return 0;
303132234Smarcel
304132234Smarcel#ifdef _STANDALONE
305132234Smarcel	strncpy(bi_netif.ifname, "we", sizeof(bi_netif.ifname));
30654324Smarcel	bi_netif.bus = BI_BUS_ISA;
30754324Smarcel	bi_netif.addr.iobase = WD_BASEREG;
30895730Sru
30995730Sru	BI_ADD(&bi_netif, BTINFO_NETIF, sizeof(bi_netif));
31095730Sru#endif
31195730Sru	return 1;
31295730Sru}
31395730Sru
31495730Sru/*
31538666Sjb * Stop ethernet board
316107374Sru */
31717308Spetervoid
318253616SsjgEtherStop(void) {
319253616Ssjg	/* stop dp8390, followed by a board reset */
320253616Ssjg	dp8390_stop();
32155678Smarcel	outb(WD_BASEREG + WE_MSR, WE_MSR_RST);
322253616Ssjg	outb(WD_BASEREG + WE_MSR, 0);
323253616Ssjg}
324253616Ssjg