xref: /netbsd-src/sys/dev/isa/if_fmv_isa.c (revision ce2c90c7c172d95d2402a5b3d96d8f8e6d138a21)
1 /*	$NetBSD: if_fmv_isa.c,v 1.8 2006/10/12 01:31:16 christos Exp $	*/
2 
3 /*
4  * All Rights Reserved, Copyright (C) Fujitsu Limited 1995
5  *
6  * This software may be used, modified, copied, distributed, and sold, in
7  * both source and binary form provided that the above copyright, these
8  * terms and the following disclaimer are retained.  The name of the author
9  * and/or the contributor may not be used to endorse or promote products
10  * derived from this software without specific prior written permission.
11  *
12  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND THE CONTRIBUTOR ``AS IS'' AND
13  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
14  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
15  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR THE CONTRIBUTOR BE LIABLE
16  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
17  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
18  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION.
19  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
20  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
21  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
22  * SUCH DAMAGE.
23  */
24 
25 /*
26  * Portions copyright (C) 1993, David Greenman.  This software may be used,
27  * modified, copied, distributed, and sold, in both source and binary form
28  * provided that the above copyright and these terms are retained.  Under no
29  * circumstances is the author responsible for the proper functioning of this
30  * software, nor does the author assume any responsibility for damages
31  * incurred with its use.
32  */
33 
34 #include <sys/cdefs.h>
35 __KERNEL_RCSID(0, "$NetBSD: if_fmv_isa.c,v 1.8 2006/10/12 01:31:16 christos Exp $");
36 
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/device.h>
40 
41 #include <net/if.h>
42 #include <net/if_ether.h>
43 #include <net/if_media.h>
44 
45 #include <machine/bus.h>
46 #include <machine/intr.h>
47 
48 #include <dev/ic/mb86960reg.h>
49 #include <dev/ic/mb86960var.h>
50 #include <dev/ic/fmvreg.h>
51 #include <dev/ic/fmvvar.h>
52 
53 #include <dev/isa/isavar.h>
54 
55 int	fmv_isa_match(struct device *, struct cfdata *, void *);
56 void	fmv_isa_attach(struct device *, struct device *, void *);
57 
58 struct fmv_isa_softc {
59 	struct	mb86960_softc sc_mb86960;	/* real "mb86960" softc */
60 
61 	/* ISA-specific goo. */
62 	void	*sc_ih;				/* interrupt cookie */
63 };
64 
65 CFATTACH_DECL(fmv_isa, sizeof(struct fmv_isa_softc),
66     fmv_isa_match, fmv_isa_attach, NULL, NULL);
67 
68 struct fe_simple_probe_struct {
69 	uint8_t port;	/* Offset from the base I/O address. */
70 	uint8_t mask;	/* Bits to be checked. */
71 	uint8_t bits;	/* Values to be compared against. */
72 };
73 
74 static inline int fe_simple_probe(bus_space_tag_t, bus_space_handle_t,
75     struct fe_simple_probe_struct const *);
76 static int fmv_find(bus_space_tag_t, bus_space_handle_t, int *, int *);
77 
78 static int const fmv_iomap[8] = {
79 	0x220, 0x240, 0x260, 0x280, 0x2A0, 0x2C0, 0x300, 0x340
80 };
81 #define NFMV_IOMAP (sizeof (fmv_iomap) / sizeof (fmv_iomap[0]))
82 #define FMV_NPORTS 0x20
83 
84 #ifdef FMV_DEBUG
85 #define DPRINTF	printf
86 #else
87 #define DPRINTF	while (/* CONSTCOND */0) printf
88 #endif
89 
90 /*
91  * Hardware probe routines.
92  */
93 
94 /*
95  * Determine if the device is present.
96  */
97 int
98 fmv_isa_match(struct device *parent __unused, struct cfdata *match __unused,
99     void *aux)
100 {
101 	struct isa_attach_args *ia = aux;
102 	bus_space_tag_t iot = ia->ia_iot;
103 	bus_space_handle_t ioh;
104 	int i, iobase, irq, rv = 0;
105 	uint8_t myea[ETHER_ADDR_LEN];
106 
107 	if (ia->ia_nio < 1)
108 		return 0;
109 	if (ia->ia_nirq < 1)
110 		return 0;
111 
112 	if (ISA_DIRECT_CONFIG(ia))
113 		return 0;
114 
115 	/* Disallow wildcarded values. */
116 	if (ia->ia_io[0].ir_addr == ISA_UNKNOWN_PORT)
117 		return 0;
118 
119 	/*
120 	 * See if the sepcified address is valid for FMV-180 series.
121 	 */
122 	for (i = 0; i < NFMV_IOMAP; i++)
123 		if (fmv_iomap[i] == ia->ia_io[0].ir_addr)
124 			break;
125 	if (i == NFMV_IOMAP) {
126 		DPRINTF("fmv_match: unknown iobase 0x%x\n",
127 		    ia->ia_io[0].ir_addr);
128 		return 0;
129 	}
130 
131 	/* Map i/o space. */
132 	if (bus_space_map(iot, ia->ia_io[0].ir_addr, FMV_NPORTS, 0, &ioh)) {
133 		DPRINTF("fmv_match: couldn't map iospace 0x%x\n",
134 		    ia->ia_io[0].ir_addr);
135 		return 0;
136 	}
137 
138 	if (fmv_find(iot, ioh, &iobase, &irq) == 0) {
139 		DPRINTF("fmv_match: fmv_find failed\n");
140 		goto out;
141 	}
142 
143 	if (iobase != ia->ia_io[0].ir_addr) {
144 		DPRINTF("fmv_match: unexpected iobase in board: 0x%x\n",
145 		    iobase);
146 		goto out;
147 	}
148 
149 	if (fmv_detect(iot, ioh, myea) == 0) { /* XXX necessary? */
150 		DPRINTF("fmv_match: fmv_detect failed\n");
151 		goto out;
152 	}
153 
154 	if (ia->ia_irq[0].ir_irq != ISA_UNKNOWN_IRQ) {
155 		if (ia->ia_irq[0].ir_irq != irq) {
156 			printf("fmv_match: irq mismatch; "
157 			    "kernel configured %d != board configured %d\n",
158 			    ia->ia_irq[0].ir_irq, irq);
159 			goto out;
160 		}
161 	} else
162 		ia->ia_irq[0].ir_irq = irq;
163 
164 	ia->ia_nio = 1;
165 	ia->ia_io[0].ir_size = FMV_NPORTS;
166 
167 	ia->ia_nirq = 1;
168 
169 	ia->ia_niomem = 0;
170 	ia->ia_ndrq = 0;
171 
172 	rv = 1;
173 
174  out:
175 	bus_space_unmap(iot, ioh, FMV_NPORTS);
176 	return rv;
177 }
178 
179 /*
180  * Check for specific bits in specific registers have specific values.
181  */
182 static inline int
183 fe_simple_probe(bus_space_tag_t iot, bus_space_handle_t ioh,
184     struct fe_simple_probe_struct const *sp)
185 {
186 	uint8_t val;
187 	struct fe_simple_probe_struct const *p;
188 
189 	for (p = sp; p->mask != 0; p++) {
190 		val = bus_space_read_1(iot, ioh, p->port);
191 		if ((val & p->mask) != p->bits) {
192 			DPRINTF("fe_simple_probe: %x & %x != %x\n",
193 			    val, p->mask, p->bits);
194 			return 0;
195 		}
196 	}
197 
198 	return 1;
199 }
200 
201 /*
202  * Hardware (vendor) specific probe routines.
203  */
204 
205 /*
206  * Probe Fujitsu FMV-180 series boards and get iobase and irq from
207  * board.
208  */
209 static int
210 fmv_find(bus_space_tag_t iot, bus_space_handle_t ioh, int *iobase, int *irq)
211 {
212 	uint8_t config;
213 	static int const fmv_irqmap[4] = { 3, 7, 10, 15 };
214 	static struct fe_simple_probe_struct const probe_table[] = {
215 		{ FE_DLCR2, 0x70, 0x00 },
216 		{ FE_DLCR4, 0x08, 0x00 },
217 	    /*	{ FE_DLCR5, 0x80, 0x00 },	Doesn't work. */
218 
219 		{ FE_FMV0, FE_FMV0_MAGIC_MASK, FE_FMV0_MAGIC_VALUE },
220 		{ FE_FMV1, FE_FMV1_MAGIC_MASK, FE_FMV1_MAGIC_VALUE },
221 		{ FE_FMV3, FE_FMV3_EXTRA_MASK, FE_FMV3_EXTRA_VALUE },
222 #if 1
223 	/*
224 	 * Test *vendor* part of the station address for Fujitsu.
225 	 * The test will gain reliability of probe process, but
226 	 * it rejects FMV-180 clone boards manufactured by other vendors.
227 	 * We have to turn the test off when such cards are made available.
228 	 */
229 		{ FE_FMV4, 0xFF, 0x00 },
230 		{ FE_FMV5, 0xFF, 0x00 },
231 		{ FE_FMV6, 0xFF, 0x0E },
232 #else
233 	/*
234 	 * We can always verify the *first* 2 bits (in Ehternet
235 	 * bit order) are "no multicast" and "no local" even for
236 	 * unknown vendors.
237 	 */
238 		{ FE_FMV4, 0x03, 0x00 },
239 #endif
240 		{ 0,	   0x00, 0x00 },
241 	};
242 
243 	/* Simple probe. */
244 	if (fe_simple_probe(iot, ioh, probe_table) != 0)
245 		return 0;
246 
247 	/* Check if our I/O address matches config info on EEPROM. */
248 	config = bus_space_read_1(iot, ioh, FE_FMV2);
249 	*iobase = fmv_iomap[(config & FE_FMV2_ADDR) >> FE_FMV2_ADDR_SHIFT];
250 
251 	/*
252 	 * Determine which IRQ to be used.
253 	 *
254 	 * In this version, we always get an IRQ assignment from the
255 	 * FMV-180's configuration EEPROM, ignoring that specified in
256 	 * config file.
257 	 */
258 	*irq = fmv_irqmap[(config & FE_FMV2_IRQ) >> FE_FMV2_IRQ_SHIFT];
259 
260 	return 1;
261 }
262 
263 void
264 fmv_isa_attach(struct device *parent __unused, struct device *self __unused,
265     void *aux)
266 {
267 	struct fmv_isa_softc *isc = (struct fmv_isa_softc *)self;
268 	struct mb86960_softc *sc = &isc->sc_mb86960;
269 	struct isa_attach_args *ia = aux;
270 	bus_space_tag_t iot = ia->ia_iot;
271 	bus_space_handle_t ioh;
272 
273 	/* Map i/o space. */
274 	if (bus_space_map(iot, ia->ia_io[0].ir_addr, FMV_NPORTS, 0, &ioh)) {
275 		printf("%s: can't map i/o space\n", sc->sc_dev.dv_xname);
276 		return;
277 	}
278 
279 	sc->sc_bst = iot;
280 	sc->sc_bsh = ioh;
281 
282 	fmv_attach(sc);
283 
284 	/* Establish the interrupt handler. */
285 	isc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq[0].ir_irq,
286 	    IST_EDGE, IPL_NET, mb86960_intr, sc);
287 	if (isc->sc_ih == NULL)
288 		printf("%s: couldn't establish interrupt handler\n",
289 		    sc->sc_dev.dv_xname);
290 }
291