1 /* $NetBSD: if_ne_mb.c,v 1.3 2021/08/17 22:00:27 andvar Exp $ */
2
3 /*
4 * Copyright (c) 2010 Izumi Tsutsui. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27 /*
28 * Device driver for the EtherNEC,
29 * NE2000 in 8bit mode over Atari ROM cartridge slot.
30 * http://hardware.atari.org/ether/
31 */
32
33 #include <sys/cdefs.h>
34 __KERNEL_RCSID(0, "$NetBSD: if_ne_mb.c,v 1.3 2021/08/17 22:00:27 andvar Exp $");
35
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/device.h>
39 #include <sys/kernel.h>
40 #include <sys/callout.h>
41
42 #include <sys/bus.h>
43 #include <sys/intr.h>
44
45 #include <net/if.h>
46 #include <net/if_dl.h>
47 #include <net/if_ether.h>
48 #include <net/if_media.h>
49
50 #include <machine/cpu.h>
51 #include <machine/iomap.h>
52
53 #include <atari/atari/device.h>
54
55 #include <dev/ic/dp8390reg.h>
56 #include <dev/ic/dp8390var.h>
57 #include <dev/ic/ne2000reg.h>
58 #include <dev/ic/ne2000var.h>
59
60 /*
61 * EtherNEC specific address configuration
62 */
63
64 /* I/O read ops are through /ROM4 area (0xFA0000) */
65 #define AD_CART_ROM4 (AD_CART + 0x00000)
66 #define ETHERNEC_READ_PORT AD_CART_ROM4
67
68 /* I/O write ops are through /ROM3 area (0xFB0000) */
69 #define AD_CART_ROM3 (AD_CART + 0x10000)
70 #define ETHERNEC_WRITE_PORT AD_CART_ROM3
71
72 /* CPU address lines A13-A9 are connected to ISA A4-A0 */
73 #define ETHERNEC_PORT_STRIDE 9
74
75 /* Using A8-A1 lines to specify write data (no A0 but UDS/LDS on m68k) */
76 #define ETHERNEC_WR_ADDR_SHIFT 1
77
78 /* interrupt polling per HZ */
79 #define ETHERNEC_TICK 1
80
81 static int ne_mb_probe(device_t, cfdata_t, void *);
82 static void ne_mb_attach(device_t, device_t, void *);
83
84 static void ne_mb_poll(void *);
85
86 static bus_space_tag_t ethernec_init_bus_space_tag(bus_space_tag_t);
87 static void ethernec_bus_space_unimpl(void);
88
89 static int ethernec_bus_space_peek_1(bus_space_tag_t, bus_space_handle_t,
90 bus_size_t);
91 static uint8_t ethernec_bus_space_read_1(bus_space_tag_t, bus_space_handle_t,
92 bus_size_t);
93 static void ethernec_bus_space_write_1(bus_space_tag_t, bus_space_handle_t,
94 bus_size_t, uint8_t);
95 static void ethernec_bus_space_read_multi_1(bus_space_tag_t,
96 bus_space_handle_t, bus_size_t, uint8_t *, bus_size_t);
97 static void ethernec_bus_space_read_multi_2(bus_space_tag_t,
98 bus_space_handle_t, bus_size_t, uint16_t *, bus_size_t);
99 static void ethernec_bus_space_write_multi_1(bus_space_tag_t,
100 bus_space_handle_t, bus_size_t, const uint8_t *, bus_size_t);
101 static void ethernec_bus_space_write_multi_2(bus_space_tag_t,
102 bus_space_handle_t, bus_size_t, const uint16_t *, bus_size_t);
103
104 struct ne_mb_softc {
105 struct ne2000_softc sc_ne2000; /* MI ne2000 softc */
106
107 struct atari_bus_space sc_bs;
108 struct callout sc_poll;
109 };
110
111 CFATTACH_DECL_NEW(ne_mb, sizeof(struct ne_mb_softc),
112 ne_mb_probe, ne_mb_attach, NULL, NULL);
113
114 static int
ne_mb_probe(device_t parent,cfdata_t cf,void * aux)115 ne_mb_probe(device_t parent, cfdata_t cf, void *aux)
116 {
117 static bool ne_matched = false;
118 struct atari_bus_space bs;
119 bus_space_tag_t iot, asict;
120 bus_space_handle_t ioh, iowh, asich;
121 int netype, rv;
122
123 rv = 0;
124
125 if (!atari_realconfig)
126 goto out;
127 if (strcmp("ne", aux) || ne_matched)
128 goto out;
129
130 iot = ethernec_init_bus_space_tag(&bs);
131
132 /* map I/O space for read ops */
133 if (bus_space_map(iot, ETHERNEC_READ_PORT,
134 NE2000_NPORTS << ETHERNEC_PORT_STRIDE, 0, &ioh) != 0)
135 goto out;
136
137 /* map I/O space for write ops */
138 if (bus_space_map(iot, ETHERNEC_WRITE_PORT,
139 NE2000_NPORTS << ETHERNEC_PORT_STRIDE, 0, &iowh) != 0)
140 goto out1;
141
142 /* XXX abuse stride for offset of write ports from read ones */
143 iot->stride =
144 (vaddr_t)bus_space_vaddr(iot, iowh) -
145 (vaddr_t)bus_space_vaddr(iot, ioh);
146
147 /* check if register regions are valid */
148 if (bus_space_peek_1(iot, ioh, 0) == 0)
149 goto out2;
150
151 asict = iot;
152 if (bus_space_subregion(iot, ioh,
153 NE2000_ASIC_OFFSET << ETHERNEC_PORT_STRIDE,
154 NE2000_ASIC_NPORTS << ETHERNEC_PORT_STRIDE, &asich))
155 goto out2;
156
157 /* Look for an NE2000 compatible card */
158 netype = ne2000_detect(iot, ioh, asict, asich);
159 switch (netype) {
160 /* XXX should we reject non RTL8019 variants? */
161 case NE2000_TYPE_NE1000:
162 case NE2000_TYPE_NE2000:
163 case NE2000_TYPE_RTL8019:
164 ne_matched = true;
165 rv = 1;
166 break;
167 default:
168 break;
169 }
170
171 out2:
172 bus_space_unmap(iot, iowh, NE2000_NPORTS << ETHERNEC_PORT_STRIDE);
173 out1:
174 bus_space_unmap(iot, ioh, NE2000_NPORTS << ETHERNEC_PORT_STRIDE);
175 out:
176 return rv;
177 }
178
179 static void
ne_mb_attach(device_t parent,device_t self,void * aux)180 ne_mb_attach(device_t parent, device_t self, void *aux)
181 {
182 struct ne_mb_softc *sc = device_private(self);
183 struct ne2000_softc *nsc = &sc->sc_ne2000;
184 struct dp8390_softc *dsc = &nsc->sc_dp8390;
185 bus_space_tag_t iot, asict;
186 bus_space_handle_t ioh, iowh, asich;
187 const char *typestr;
188 int netype;
189
190 dsc->sc_dev = self;
191 aprint_normal(": EtherNEC on Atari ROM cartridge slot\n");
192
193 iot = ethernec_init_bus_space_tag(&sc->sc_bs);
194
195 /* map I/O space for read ops */
196 if (bus_space_map(iot, ETHERNEC_READ_PORT,
197 NE2000_NPORTS << ETHERNEC_PORT_STRIDE, 0, &ioh) != 0)
198 goto out;
199
200 /* map I/O space for write ops */
201 if (bus_space_map(iot, ETHERNEC_WRITE_PORT,
202 NE2000_NPORTS << ETHERNEC_PORT_STRIDE, 0, &iowh) != 0)
203 goto out1;
204
205 /* XXX abuse stride */
206 iot->stride =
207 (vaddr_t)bus_space_vaddr(iot, iowh) -
208 (vaddr_t)bus_space_vaddr(iot, ioh);
209
210 asict = iot;
211 if (bus_space_subregion(iot, ioh,
212 NE2000_ASIC_OFFSET << ETHERNEC_PORT_STRIDE,
213 NE2000_ASIC_NPORTS << ETHERNEC_PORT_STRIDE, &asich))
214 goto out2;
215
216 dsc->sc_regt = iot;
217 dsc->sc_regh = ioh;
218
219 nsc->sc_asict = asict;
220 nsc->sc_asich = asich;
221
222 /* EtherNEC uses 8-bit data bus */
223 nsc->sc_quirk = NE2000_QUIRK_8BIT;
224
225 /*
226 * detect it again, so we can print some information about
227 * the interface.
228 * XXX: Should we accept only RTL8019?
229 */
230 netype = ne2000_detect(iot, ioh, asict, asich);
231 switch (netype) {
232 case NE2000_TYPE_NE1000:
233 typestr = "NE1000";
234 break;
235
236 case NE2000_TYPE_NE2000:
237 typestr = "NE2000";
238 break;
239
240 case NE2000_TYPE_RTL8019:
241 typestr = "NE2000 (RTL8019)";
242 break;
243
244 default:
245 aprint_error_dev(self, "where did the card go?!\n");
246 goto out2;
247 }
248
249 aprint_normal_dev(self, "%s Ethernet (8-bit)\n", typestr);
250
251 /* this interface is always enabled */
252 dsc->sc_enabled = 1;
253
254 /* call MI ne2000 attach function */
255 ne2000_attach(nsc, NULL);
256
257 /* emulate interrupts by callout(9) */
258 aprint_normal_dev(self, "using %d Hz polling\n", hz / ETHERNEC_TICK);
259 callout_init(&sc->sc_poll, 0);
260 callout_reset(&sc->sc_poll, ETHERNEC_TICK, ne_mb_poll, sc);
261
262 return;
263
264 out2:
265 bus_space_unmap(iot, iowh, NE2000_NPORTS << ETHERNEC_PORT_STRIDE);
266 out1:
267 bus_space_unmap(iot, ioh, NE2000_NPORTS << ETHERNEC_PORT_STRIDE);
268 out:
269 return;
270 }
271
272 static void
ne_mb_poll(void * arg)273 ne_mb_poll(void *arg)
274 {
275 struct ne_mb_softc *sc;
276 struct ne2000_softc *nsc;
277 struct dp8390_softc *dsc;
278 int s;
279
280 sc = arg;
281 nsc = &sc->sc_ne2000;
282 dsc = &nsc->sc_dp8390;
283
284 s = splnet();
285 (void)dp8390_intr(dsc);
286 splx(s);
287
288 callout_schedule(&sc->sc_poll, ETHERNEC_TICK);
289 }
290
291 /*
292 * bus_space(9) functions for EtherNEC
293 *
294 * XXX: should these belong to an independent cartridge slot bus?
295 */
296 static bus_space_tag_t
ethernec_init_bus_space_tag(bus_space_tag_t en_t)297 ethernec_init_bus_space_tag(bus_space_tag_t en_t)
298 {
299
300 if (en_t == NULL)
301 return NULL;
302
303 memset(en_t, 0, sizeof(*en_t));
304
305 /* XXX: implement functions used by MI ne2000 and dp8390 only */
306 en_t->abs_p_1 = ethernec_bus_space_peek_1;
307 en_t->abs_p_2 = (void *)ethernec_bus_space_unimpl;
308 en_t->abs_p_4 = (void *)ethernec_bus_space_unimpl;
309 en_t->abs_p_8 = (void *)ethernec_bus_space_unimpl;
310 en_t->abs_r_1 = ethernec_bus_space_read_1;
311 en_t->abs_r_2 = (void *)ethernec_bus_space_unimpl;
312 en_t->abs_r_4 = (void *)ethernec_bus_space_unimpl;
313 en_t->abs_r_8 = (void *)ethernec_bus_space_unimpl;
314 en_t->abs_rs_1 = ethernec_bus_space_read_1;
315 en_t->abs_rs_2 = (void *)ethernec_bus_space_unimpl;
316 en_t->abs_rs_4 = (void *)ethernec_bus_space_unimpl;
317 en_t->abs_rs_8 = (void *)ethernec_bus_space_unimpl;
318 en_t->abs_rm_1 = ethernec_bus_space_read_multi_1;
319 en_t->abs_rm_2 = (void *)ethernec_bus_space_unimpl;
320 en_t->abs_rm_4 = (void *)ethernec_bus_space_unimpl;
321 en_t->abs_rm_8 = (void *)ethernec_bus_space_unimpl;
322 en_t->abs_rms_1 = ethernec_bus_space_read_multi_1;
323 en_t->abs_rms_2 = ethernec_bus_space_read_multi_2; /* XXX dummy */
324 en_t->abs_rms_4 = (void *)ethernec_bus_space_unimpl;
325 en_t->abs_rms_8 = (void *)ethernec_bus_space_unimpl;
326 en_t->abs_rr_1 = (void *)ethernec_bus_space_unimpl;
327 en_t->abs_rr_2 = (void *)ethernec_bus_space_unimpl;
328 en_t->abs_rr_4 = (void *)ethernec_bus_space_unimpl;
329 en_t->abs_rr_8 = (void *)ethernec_bus_space_unimpl;
330 en_t->abs_rrs_1 = (void *)ethernec_bus_space_unimpl;
331 en_t->abs_rrs_2 = (void *)ethernec_bus_space_unimpl;
332 en_t->abs_rrs_4 = (void *)ethernec_bus_space_unimpl;
333 en_t->abs_rrs_8 = (void *)ethernec_bus_space_unimpl;
334 en_t->abs_w_1 = ethernec_bus_space_write_1;
335 en_t->abs_w_2 = (void *)ethernec_bus_space_unimpl;
336 en_t->abs_w_4 = (void *)ethernec_bus_space_unimpl;
337 en_t->abs_w_8 = (void *)ethernec_bus_space_unimpl;
338 en_t->abs_ws_1 = ethernec_bus_space_write_1;
339 en_t->abs_ws_2 = (void *)ethernec_bus_space_unimpl;
340 en_t->abs_ws_4 = (void *)ethernec_bus_space_unimpl;
341 en_t->abs_ws_8 = (void *)ethernec_bus_space_unimpl;
342 en_t->abs_wm_1 = ethernec_bus_space_write_multi_1;
343 en_t->abs_wm_2 = (void *)ethernec_bus_space_unimpl;
344 en_t->abs_wm_4 = (void *)ethernec_bus_space_unimpl;
345 en_t->abs_wm_8 = (void *)ethernec_bus_space_unimpl;
346 en_t->abs_wms_1 = ethernec_bus_space_write_multi_1;
347 en_t->abs_wms_2 = ethernec_bus_space_write_multi_2; /* XXX dummy */
348 en_t->abs_wms_4 = (void *)ethernec_bus_space_unimpl;
349 en_t->abs_wms_8 = (void *)ethernec_bus_space_unimpl;
350 en_t->abs_wr_1 = (void *)ethernec_bus_space_unimpl;
351 en_t->abs_wr_2 = (void *)ethernec_bus_space_unimpl;
352 en_t->abs_wr_4 = (void *)ethernec_bus_space_unimpl;
353 en_t->abs_wr_8 = (void *)ethernec_bus_space_unimpl;
354 en_t->abs_wrs_1 = (void *)ethernec_bus_space_unimpl;
355 en_t->abs_wrs_2 = (void *)ethernec_bus_space_unimpl;
356 en_t->abs_wrs_4 = (void *)ethernec_bus_space_unimpl;
357 en_t->abs_wrs_8 = (void *)ethernec_bus_space_unimpl;
358 en_t->abs_sm_1 = (void *)ethernec_bus_space_unimpl;
359 en_t->abs_sm_2 = (void *)ethernec_bus_space_unimpl;
360 en_t->abs_sm_4 = (void *)ethernec_bus_space_unimpl;
361 en_t->abs_sm_8 = (void *)ethernec_bus_space_unimpl;
362 en_t->abs_sr_1 = (void *)ethernec_bus_space_unimpl;
363 en_t->abs_sr_2 = (void *)ethernec_bus_space_unimpl;
364 en_t->abs_sr_4 = (void *)ethernec_bus_space_unimpl;
365 en_t->abs_sr_8 = (void *)ethernec_bus_space_unimpl;
366
367 return en_t;
368 }
369
370 static void
ethernec_bus_space_unimpl(void)371 ethernec_bus_space_unimpl(void)
372 {
373
374 panic("%s: unimplemented EtherNEC bus_space(9) function called",
375 __func__);
376 }
377
378 static int
ethernec_bus_space_peek_1(bus_space_tag_t bt,bus_space_handle_t bh,bus_size_t reg)379 ethernec_bus_space_peek_1(bus_space_tag_t bt, bus_space_handle_t bh,
380 bus_size_t reg)
381 {
382 uint8_t *va;
383
384 va = (uint8_t *)(bh + (reg << ETHERNEC_PORT_STRIDE));
385
386 return !badbaddr(va, sizeof(uint8_t));
387 }
388
389 static uint8_t
ethernec_bus_space_read_1(bus_space_tag_t bt,bus_space_handle_t bh,bus_size_t reg)390 ethernec_bus_space_read_1(bus_space_tag_t bt, bus_space_handle_t bh,
391 bus_size_t reg)
392 {
393 volatile uint8_t *ba;
394
395 ba = (volatile uint8_t *)(bh + (reg << ETHERNEC_PORT_STRIDE));
396
397 return *ba;
398 }
399
400 static void
ethernec_bus_space_write_1(bus_space_tag_t bt,bus_space_handle_t bh,bus_size_t reg,uint8_t val)401 ethernec_bus_space_write_1(bus_space_tag_t bt, bus_space_handle_t bh,
402 bus_size_t reg, uint8_t val)
403 {
404 volatile uint8_t *wport;
405
406 /*
407 * Write ops are done by read against write region (ROM3) address.
408 * 8-bit write data is specified via lower address bits.
409 */
410 wport = (volatile uint8_t *)(bh +
411 bt->stride + (reg << ETHERNEC_PORT_STRIDE));
412 wport += (u_int)val << ETHERNEC_WR_ADDR_SHIFT;
413
414 (void)*wport;
415 }
416
417 static void
ethernec_bus_space_read_multi_1(bus_space_tag_t bt,bus_space_handle_t bh,bus_size_t reg,uint8_t * a,bus_size_t c)418 ethernec_bus_space_read_multi_1(bus_space_tag_t bt, bus_space_handle_t bh,
419 bus_size_t reg, uint8_t *a, bus_size_t c)
420 {
421 volatile uint8_t *ba;
422
423 ba = (volatile uint8_t *)(bh + (reg << ETHERNEC_PORT_STRIDE));
424 for (; c != 0; c--)
425 *a++ = *ba;
426 }
427
428 static void
ethernec_bus_space_read_multi_2(bus_space_tag_t bt,bus_space_handle_t bh,bus_size_t reg,uint16_t * a,bus_size_t c)429 ethernec_bus_space_read_multi_2(bus_space_tag_t bt, bus_space_handle_t bh,
430 bus_size_t reg, uint16_t *a, bus_size_t c)
431 {
432
433 /* XXX: dummy function for probe ops in ne2000_detect() */
434 }
435
436 static void
ethernec_bus_space_write_multi_1(bus_space_tag_t bt,bus_space_handle_t bh,bus_size_t reg,const uint8_t * a,bus_size_t c)437 ethernec_bus_space_write_multi_1(bus_space_tag_t bt, bus_space_handle_t bh,
438 bus_size_t reg, const uint8_t *a, bus_size_t c)
439 {
440 volatile uint8_t *ba, *wport;
441 u_int val;
442
443 ba = (volatile uint8_t *)(bh +
444 bt->stride + (reg << ETHERNEC_PORT_STRIDE));
445
446 for (; c != 0; c--) {
447 val = *a++;
448 wport = ba + (val << ETHERNEC_WR_ADDR_SHIFT);
449 (void)*wport;
450 }
451 }
452
453 static void
ethernec_bus_space_write_multi_2(bus_space_tag_t bt,bus_space_handle_t bh,bus_size_t reg,const uint16_t * a,bus_size_t c)454 ethernec_bus_space_write_multi_2(bus_space_tag_t bt, bus_space_handle_t bh,
455 bus_size_t reg, const uint16_t *a, bus_size_t c)
456 {
457
458 /* XXX: dummy function for probe ops in ne2000_detect() */
459 }
460