1/**************************************************************************
2Etherboot -  BOOTP/TFTP Bootstrap Program
3
4TIARA (Fujitsu Etherstar) NIC driver for Etherboot
5Copyright (c) Ken Yap 1998
6
7Information gleaned from:
8
9TIARA.ASM Packet driver by Brian Fisher, Queens U, Kingston, Ontario
10Fujitsu MB86960 spec sheet (different chip but same family)
11***************************************************************************/
12
13/*
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License as
16 * published by the Free Software Foundation; either version 2, or (at
17 * your option) any later version.
18 */
19
20/* to get some global routines like printf */
21#include "etherboot.h"
22/* to get the interface to the body of the program */
23#include "nic.h"
24#include "cards.h"
25
26/*
27	EtherStar I/O Register offsets
28*/
29
30/* Offsets of registers */
31#define	DLCR_XMIT_STAT	0x00
32#define	DLCR_XMIT_MASK	0x01
33#define	DLCR_RECV_STAT	0x02
34#define	DLCR_RECV_MASK	0x03
35#define	DLCR_XMIT_MODE	0x04
36#define	DLCR_RECV_MODE	0x05
37#define	DLCR_ENABLE	0x06
38#define	DLCR_TDR_LOW	0x07
39#define	DLCR_NODE_ID	0x08
40#define	DLCR_TDR_HIGH	0x0F
41#define	BMPR_MEM_PORT	0x10
42#define	BMPR_PKT_LEN	0x12
43#define	BMPR_DMA_ENABLE	0x14
44#define	PROM_ID		0x18
45
46#define	TMST		0x80
47#define	TMT_OK		0x80
48#define	TMT_16COLL	0x02
49#define	BUF_EMPTY	0x40
50
51#define	CARD_DISABLE	0x80	/* written to DLCR_ENABLE to disable card */
52#define	CARD_ENABLE	0	/* written to DLCR_ENABLE to enable card */
53
54#define	CLEAR_STATUS	0x0F	/* used to clear status info */
55/*
56	00001111B
57	!!!!!!!!--------
58	!!!!!!!+--------CLEAR BUS WRITE ERROR
59	!!!!!!+---------CLEAR 16 COLLISION
60	!!!!!+----------CLEAR COLLISION
61	!!!!+-----------CLEAR UNDERFLOW
62	!!!+------------NC
63	!!+-------------NC
64	!+--------------NC
65	+---------------NC
66*/
67
68#define	NO_TX_IRQS	0	/* written to clear transmit IRQs */
69
70#define	CLR_RCV_STATUS	0xCF	/* clears receive status */
71
72#define	EN_RCV_IRQS	0x80	/* enable receive interrupts */
73/*
74	10000000B
75	!!!!!!!!--------
76	!!!!!!!+--------ENABLE OVERFLOW
77	!!!!!!+---------ENABLE CRC
78	!!!!!+----------ENABLE ALIGN
79	!!!!+-----------ENABLE SHORT PKT
80	!!!+------------DISABLE REMOTE RESET
81	!!+-------------RESERVED
82	!+--------------RESERVED
83	+---------------ENABLE PKT READY
84*/
85
86#define	XMIT_MODE	0x02
87/*
88	00000010B
89	!!!!!!!!---------ENABLE CARRIER DETECT
90	!!!!!!!+---------DISABLE LOOPBACK
91*/
92
93#define	RECV_MODE	0x02
94/*
95	00000010B
96	!!!!!!!!---------ACCEPT ALL PACKETS
97	!!!!!!!+---------ACCEPT PHYSICAL, MULTICAST, AND
98	!!!!!!+----------BROADCAST PACKETS
99	!!!!!+-----------DISABLE REMOTE RESET
100	!!!!+------------DISABLE SHORT PACKETS
101	!!!+-------------USE 6 BYTE ADDRESS
102	!!+--------------NC
103	!+---------------NC
104	+----------------DISABLE CRC TEST MODE
105*/
106
107/* NIC specific static variables go here */
108
109static unsigned short	ioaddr;
110
111/**************************************************************************
112RESET - Reset adapter
113***************************************************************************/
114static void tiara_reset(struct nic *nic)
115{
116	int		i;
117
118	outb(CARD_DISABLE, ioaddr + DLCR_ENABLE);
119	outb(CLEAR_STATUS, ioaddr + DLCR_XMIT_STAT);
120	outb(NO_TX_IRQS, ioaddr + DLCR_XMIT_MASK);
121	outb(CLR_RCV_STATUS, ioaddr + DLCR_RECV_STAT);
122	outb(XMIT_MODE, ioaddr + DLCR_XMIT_MODE);
123	outb(RECV_MODE, ioaddr + DLCR_RECV_MODE);
124	/* Vacuum recv buffer */
125	while ((inb(ioaddr + DLCR_RECV_MODE) & BUF_EMPTY) == 0)
126		inb(ioaddr + BMPR_MEM_PORT);
127	/* Set node address */
128	for (i = 0; i < ETH_ALEN; ++i)
129		outb(nic->node_addr[i], ioaddr + DLCR_NODE_ID + i);
130	outb(CLR_RCV_STATUS, ioaddr + DLCR_RECV_STAT);
131	outb(CARD_ENABLE, ioaddr + DLCR_ENABLE);
132}
133
134/**************************************************************************
135POLL - Wait for a frame
136***************************************************************************/
137static int tiara_poll(struct nic *nic)
138{
139	unsigned int		len;
140
141	if (inb(ioaddr + DLCR_RECV_MODE) & BUF_EMPTY)
142		return (0);
143	/* Ack packet */
144	outw(CLR_RCV_STATUS, ioaddr + DLCR_RECV_STAT);
145	len = inw(ioaddr + BMPR_MEM_PORT);		/* throw away status */
146	len = inw(ioaddr + BMPR_MEM_PORT);
147	/* Drop overlength packets */
148	if (len > ETH_FRAME_LEN)
149		return (0);		/* should we drain the buffer? */
150	insw(ioaddr + BMPR_MEM_PORT, nic->packet, len / 2);
151	/* If it's our own, drop it */
152	if (memcmp(nic->packet + ETH_ALEN, nic->node_addr, ETH_ALEN) == 0)
153		return (0);
154	nic->packetlen = len;
155	return (1);
156}
157
158/**************************************************************************
159TRANSMIT - Transmit a frame
160***************************************************************************/
161static void tiara_transmit(
162struct nic *nic,
163const char *d,			/* Destination */
164unsigned int t,			/* Type */
165unsigned int s,			/* size */
166const char *p)			/* Packet */
167{
168	unsigned int	len;
169	unsigned long	time;
170
171	len = s + ETH_HLEN;
172	if (len < ETH_ZLEN)
173		len = ETH_ZLEN;
174	t = htons(t);
175	outsw(ioaddr + BMPR_MEM_PORT, d, ETH_ALEN / 2);
176	outsw(ioaddr + BMPR_MEM_PORT, nic->node_addr, ETH_ALEN / 2);
177	outw(t, ioaddr + BMPR_MEM_PORT);
178	outsw(ioaddr + BMPR_MEM_PORT, p, s / 2);
179	if (s & 1)					/* last byte */
180		outb(p[s-1], ioaddr + BMPR_MEM_PORT);
181	while (s++ < ETH_ZLEN - ETH_HLEN)	/* pad */
182		outb(0, ioaddr + BMPR_MEM_PORT);
183	outw(len | (TMST << 8), ioaddr + BMPR_PKT_LEN);
184	/* wait for transmit complete */
185	time = currticks() + TICKS_PER_SEC;		/* wait one second */
186	while (currticks() < time && (inb(ioaddr) & (TMT_OK|TMT_16COLL)) == 0)
187		;
188	if ((inb(ioaddr) & (TMT_OK|TMT_16COLL)) == 0)
189		printf("Tiara timed out on transmit\n");
190	/* Do we need to ack the transmit? */
191}
192
193/**************************************************************************
194DISABLE - Turn off ethernet interface
195***************************************************************************/
196static void tiara_disable(struct nic *nic)
197{
198	/* Apparently only a power down can do this properly */
199	outb(CARD_DISABLE, ioaddr + DLCR_ENABLE);
200}
201
202static int tiara_probe1(struct nic *nic)
203{
204	/* Hope all the Tiara cards have this vendor prefix */
205	static char	vendor_prefix[] = { 0x08, 0x00, 0x1A };
206	static char	all_ones[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
207	int		i;
208
209	for (i = 0; i < ETH_ALEN; ++i)
210		nic->node_addr[i] = inb(ioaddr + PROM_ID + i);
211	if (memcmp(nic->node_addr, vendor_prefix, sizeof(vendor_prefix)) != 0)
212		return (0);
213	if (memcmp(nic->node_addr, all_ones, sizeof(all_ones)) == 0)
214		return (0);
215	printf("\nTiara ioaddr %#hX, addr %!\n", ioaddr, nic->node_addr);
216	return (1);
217}
218
219/**************************************************************************
220PROBE - Look for an adapter, this routine's visible to the outside
221***************************************************************************/
222struct nic *tiara_probe(struct nic *nic, unsigned short *probe_addrs)
223{
224	/* missing entries are addresses usually already used */
225	static unsigned short	io_addrs[] = {
226		0x100, 0x120, 0x140, 0x160,
227		0x180, 0x1A0, 0x1C0, 0x1E0,
228		0x200, 0x220, 0x240, /*Par*/
229		0x280, 0x2A0, 0x2C0, /*Ser*/
230		0x300, 0x320, 0x340, /*Par*/
231		0x380, /*Vid,Par*/ 0x3C0, /*Ser*/
232		0x0
233	};
234	unsigned short		*p;
235
236	/* if probe_addrs is 0, then routine can use a hardwired default */
237	if (probe_addrs == 0)
238		probe_addrs = io_addrs;
239	for (p = probe_addrs; (ioaddr = *p) != 0; ++p)
240		if (tiara_probe1(nic))
241			break;
242	/* if board found */
243	if (ioaddr != 0)
244	{
245		tiara_reset(nic);
246		/* point to NIC specific routines */
247		nic->reset = tiara_reset;
248		nic->poll = tiara_poll;
249		nic->transmit = tiara_transmit;
250		nic->disable = tiara_disable;
251		return nic;
252	}
253	else
254		return (0);
255}
256