xref: /netbsd/sys/dev/isa/if_fmv_isa.c (revision c4a72b64)
1 /*	$NetBSD: if_fmv_isa.c,v 1.2 2002/10/05 17:52:32 tsutsui 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.2 2002/10/05 17:52:32 tsutsui 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 __P((struct device *, struct cfdata *, void *));
56 void	fmv_isa_attach __P((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 	u_int8_t port;	/* Offset from the base I/O address. */
70 	u_int8_t mask;	/* Bits to be checked. */
71 	u_int8_t bits;	/* Values to be compared against. */
72 };
73 
74 static __inline__ int fe_simple_probe __P((bus_space_tag_t,
75     bus_space_handle_t, struct fe_simple_probe_struct const *));
76 static int fmv_find __P((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 /*
85  * Hardware probe routines.
86  */
87 
88 /*
89  * Determine if the device is present.
90  */
91 int
92 fmv_isa_match(parent, match, aux)
93 	struct device *parent;
94 	struct cfdata *match;
95 	void *aux;
96 {
97 	struct isa_attach_args *ia = aux;
98 	bus_space_tag_t iot = ia->ia_iot;
99 	bus_space_handle_t ioh;
100 	int i, iobase, irq, rv = 0;
101 	u_int8_t myea[ETHER_ADDR_LEN];
102 
103 	if (ia->ia_nio < 1)
104 		return (0);
105 	if (ia->ia_nirq < 1)
106 		return (0);
107 
108 	if (ISA_DIRECT_CONFIG(ia))
109 		return (0);
110 
111 	/* Disallow wildcarded values. */
112 	if (ia->ia_io[0].ir_addr == ISACF_PORT_DEFAULT)
113 		return (0);
114 
115 	/*
116 	 * See if the sepcified address is valid for FMV-180 series.
117 	 */
118 	for (i = 0; i < NFMV_IOMAP; i++)
119 		if (fmv_iomap[i] == ia->ia_io[0].ir_addr)
120 			break;
121 	if (i == NFMV_IOMAP) {
122 #ifdef FMV_DEBUG
123 		printf("fmv_match: unknown iobase 0x%x\n",
124 		    ia->ia_io[0].ir_addr);
125 #endif
126 		return (0);
127 	}
128 
129 	/* Map i/o space. */
130 	if (bus_space_map(iot, ia->ia_io[0].ir_addr, FMV_NPORTS, 0, &ioh)) {
131 #ifdef FMV_DEBUG
132 		printf("fmv_match: couldn't map iospace 0x%x\n",
133 		    ia->ia_io[0].ir_addr);
134 #endif
135 		return (0);
136 	}
137 
138 	if (fmv_find(iot, ioh, &iobase, &irq) == 0) {
139 #ifdef FMV_DEBUG
140 		printf("fmv_match: fmv_find failed\n");
141 #endif
142 		goto out;
143 	}
144 
145 	if (iobase != ia->ia_io[0].ir_addr) {
146 #ifdef FMV_DEBUG
147 		printf("fmv_match: unexpected iobase in board: 0x%x\n",
148 		    iobase);
149 #endif
150 		goto out;
151 	}
152 
153 	if (fmv_detect(iot, ioh, myea) == 0) { /* XXX necessary? */
154 #ifdef FMV_DEBUG
155 		printf("fmv_match: fmv_detect failed\n");
156 #endif
157 		goto out;
158 	}
159 
160 	if (ia->ia_irq[0].ir_irq != ISACF_IRQ_DEFAULT) {
161 		if (ia->ia_irq[0].ir_irq != irq) {
162 			printf("fmv_match: irq mismatch; "
163 			    "kernel configured %d != board configured %d\n",
164 			    ia->ia_irq[0].ir_irq, irq);
165 			goto out;
166 		}
167 	} else
168 		ia->ia_irq[0].ir_irq = irq;
169 
170 	ia->ia_nio = 1;
171 	ia->ia_io[0].ir_size = FMV_NPORTS;
172 
173 	ia->ia_nirq = 1;
174 
175 	ia->ia_niomem = 0;
176 	ia->ia_ndrq = 0;
177 
178 	rv = 1;
179 
180  out:
181 	bus_space_unmap(iot, ioh, FMV_NPORTS);
182 	return (rv);
183 }
184 
185 /*
186  * Check for specific bits in specific registers have specific values.
187  */
188 static __inline__ int
189 fe_simple_probe (iot, ioh, sp)
190 	bus_space_tag_t iot;
191 	bus_space_handle_t ioh;
192 	struct fe_simple_probe_struct const *sp;
193 {
194 	u_int8_t val;
195 	struct fe_simple_probe_struct const *p;
196 
197 	for (p = sp; p->mask != 0; p++) {
198 		val = bus_space_read_1(iot, ioh, p->port);
199 		if ((val & p->mask) != p->bits) {
200 #ifdef FMV_DEBUG
201 			printf("fe_simple_probe: %x & %x != %x\n",
202 			    val, p->mask, p->bits);
203 #endif
204 			return (0);
205 		}
206 	}
207 
208 	return (1);
209 }
210 
211 /*
212  * Hardware (vendor) specific probe routines.
213  */
214 
215 /*
216  * Probe Fujitsu FMV-180 series boards and get iobase and irq from
217  * board.
218  */
219 static int
220 fmv_find(iot, ioh, iobase, irq)
221 	bus_space_tag_t iot;
222 	bus_space_handle_t ioh;
223 	int *iobase, *irq;
224 {
225 	u_int8_t config;
226 	static int const fmv_irqmap[4] = { 3, 7, 10, 15 };
227 	static struct fe_simple_probe_struct const probe_table[] = {
228 		{ FE_DLCR2, 0x70, 0x00 },
229 		{ FE_DLCR4, 0x08, 0x00 },
230 	    /*	{ FE_DLCR5, 0x80, 0x00 },	Doesn't work. */
231 
232 		{ FE_FMV0, FE_FMV0_MAGIC_MASK, FE_FMV0_MAGIC_VALUE },
233 		{ FE_FMV1, FE_FMV1_MAGIC_MASK, FE_FMV1_MAGIC_VALUE },
234 		{ FE_FMV3, FE_FMV3_EXTRA_MASK, FE_FMV3_EXTRA_VALUE },
235 #if 1
236 	/*
237 	 * Test *vendor* part of the station address for Fujitsu.
238 	 * The test will gain reliability of probe process, but
239 	 * it rejects FMV-180 clone boards manufactured by other vendors.
240 	 * We have to turn the test off when such cards are made available.
241 	 */
242 		{ FE_FMV4, 0xFF, 0x00 },
243 		{ FE_FMV5, 0xFF, 0x00 },
244 		{ FE_FMV6, 0xFF, 0x0E },
245 #else
246 	/*
247 	 * We can always verify the *first* 2 bits (in Ehternet
248 	 * bit order) are "no multicast" and "no local" even for
249 	 * unknown vendors.
250 	 */
251 		{ FE_FMV4, 0x03, 0x00 },
252 #endif
253 		{ 0 }
254 	};
255 
256 	/* Simple probe. */
257 	if (!fe_simple_probe(iot, ioh, probe_table))
258 		return (0);
259 
260 	/* Check if our I/O address matches config info on EEPROM. */
261 	config = bus_space_read_1(iot, ioh, FE_FMV2);
262 	*iobase = fmv_iomap[(config & FE_FMV2_ADDR) >> FE_FMV2_ADDR_SHIFT];
263 
264 	/*
265 	 * Determine which IRQ to be used.
266 	 *
267 	 * In this version, we always get an IRQ assignment from the
268 	 * FMV-180's configuration EEPROM, ignoring that specified in
269 	 * config file.
270 	 */
271 	*irq = fmv_irqmap[(config & FE_FMV2_IRQ) >> FE_FMV2_IRQ_SHIFT];
272 
273 	return (1);
274 }
275 
276 void
277 fmv_isa_attach(parent, self, aux)
278 	struct device *parent, *self;
279 	void *aux;
280 {
281 	struct fmv_isa_softc *isc = (struct fmv_isa_softc *)self;
282 	struct mb86960_softc *sc = &isc->sc_mb86960;
283 	struct isa_attach_args *ia = aux;
284 	bus_space_tag_t iot = ia->ia_iot;
285 	bus_space_handle_t ioh;
286 
287 	/* Map i/o space. */
288 	if (bus_space_map(iot, ia->ia_io[0].ir_addr, FMV_NPORTS, 0, &ioh)) {
289 		printf("%s: can't map i/o space\n", sc->sc_dev.dv_xname);
290 		return;
291 	}
292 
293 	sc->sc_bst = iot;
294 	sc->sc_bsh = ioh;
295 
296 	fmv_attach(sc);
297 
298 	/* Establish the interrupt handler. */
299 	isc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq[0].ir_irq,
300 	    IST_EDGE, IPL_NET, mb86960_intr, sc);
301 	if (isc->sc_ih == NULL)
302 		printf("%s: couldn't establish interrupt handler\n",
303 		    sc->sc_dev.dv_xname);
304 }
305