2 * Copyright (c) 1994-2000
3 * Paul Richards. All rights reserved.
5 * PC-98 port by Chiharu Shibata & FreeBSD(98) porting team.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer,
12 * verbatim and that no modifications are made prior to this
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. The name Paul Richards may not be used to endorse or promote products
18 * derived from this software without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY PAUL RICHARDS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL PAUL RICHARDS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * from: FreeBSD: src/sys/dev/lnc/if_lnc_cbus.c,v 1.12 2005/11/12 19:14:21
35 #include <sys/cdefs.h>
36 __FBSDID("$FreeBSD$");
38 #include <sys/param.h>
39 #include <sys/systm.h>
41 #include <sys/endian.h>
42 #include <sys/kernel.h>
44 #include <sys/module.h>
45 #include <sys/mutex.h>
46 #include <sys/resource.h>
48 #include <sys/socket.h>
50 #include <net/ethernet.h>
52 #include <net/if_media.h>
54 #include <machine/bus.h>
55 #include <machine/resource.h>
57 #include <isa/isavar.h>
59 #include <dev/le/lancereg.h>
60 #include <dev/le/lancevar.h>
61 #include <dev/le/am7990var.h>
63 #define LE_CBUS_MEMSIZE (16*1024)
64 #define CNET98S_IOSIZE 32
65 #define CNET98S_RDP 0x10
66 #define CNET98S_RAP 0x12
67 #define CNET98S_RESET 0x14
68 #define CNET98S_BDP 0x16
70 struct le_cbus_softc
{
71 struct am7990_softc sc_am7990
; /* glue to MI code */
74 struct resource
*sc_rres
;
75 bus_space_tag_t sc_regt
;
76 bus_space_handle_t sc_regh
;
79 struct resource
*sc_ires
;
82 bus_dma_tag_t sc_pdmat
;
83 bus_dma_tag_t sc_dmat
;
87 static device_probe_t le_cbus_probe
;
88 static device_attach_t le_cbus_attach
;
89 static device_detach_t le_cbus_detach
;
90 static device_resume_t le_cbus_resume
;
91 static device_suspend_t le_cbus_suspend
;
93 static device_method_t le_cbus_methods
[] = {
94 /* Device interface */
95 DEVMETHOD(device_probe
, le_cbus_probe
),
96 DEVMETHOD(device_attach
, le_cbus_attach
),
97 DEVMETHOD(device_detach
, le_cbus_detach
),
98 /* We can just use the suspend method here. */
99 DEVMETHOD(device_shutdown
, le_cbus_suspend
),
100 DEVMETHOD(device_suspend
, le_cbus_suspend
),
101 DEVMETHOD(device_resume
, le_cbus_resume
),
106 DEFINE_CLASS_0(le
, le_cbus_driver
, le_cbus_methods
, sizeof(struct le_cbus_softc
));
107 DRIVER_MODULE(le
, isa
, le_cbus_driver
, le_devclass
, 0, 0);
108 MODULE_DEPEND(le
, ether
, 1, 1, 1);
110 static bus_addr_t le_ioaddr_cnet98s
[CNET98S_IOSIZE
] = {
111 0x000, 0x001, 0x002, 0x003, 0x004, 0x005, 0x006, 0x007,
112 0x008, 0x009, 0x00a, 0x00b, 0x00c, 0x00d, 0x00e, 0x00f,
113 0x400, 0x401, 0x402, 0x403, 0x404, 0x405, 0x406, 0x407,
114 0x408, 0x409, 0x40a, 0x40b, 0x40c, 0x40d, 0x40e, 0x40f,
117 static void le_cbus_wrbcr(struct lance_softc
*, uint16_t, uint16_t);
119 static uint16_t le_cbus_rdbcr(struct lance_softc
*, uint16_t);
121 static void le_cbus_wrcsr(struct lance_softc
*, uint16_t, uint16_t);
122 static uint16_t le_cbus_rdcsr(struct lance_softc
*, uint16_t);
123 static void le_cbus_hwreset(struct lance_softc
*);
124 static bus_dmamap_callback_t le_cbus_dma_callback
;
127 le_cbus_wrbcr(struct lance_softc
*sc
, uint16_t port
, uint16_t val
)
129 struct le_cbus_softc
*lesc
= (struct le_cbus_softc
*)sc
;
131 bus_space_write_2(lesc
->sc_regt
, lesc
->sc_regh
, CNET98S_RAP
, port
);
132 bus_space_barrier(lesc
->sc_regt
, lesc
->sc_regh
, CNET98S_RAP
, 2,
133 BUS_SPACE_BARRIER_WRITE
);
134 bus_space_write_2(lesc
->sc_regt
, lesc
->sc_regh
, CNET98S_BDP
, val
);
139 le_cbus_rdbcr(struct lance_softc
*sc
, uint16_t port
)
141 struct le_cbus_softc
*lesc
= (struct le_cbus_softc
*)sc
;
143 bus_space_write_2(lesc
->sc_regt
, lesc
->sc_regh
, CNET98S_RAP
, port
);
144 bus_space_barrier(lesc
->sc_regt
, lesc
->sc_regh
, CNET98S_RAP
, 2,
145 BUS_SPACE_BARRIER_WRITE
);
146 return (bus_space_read_2(lesc
->sc_regt
, lesc
->sc_regh
, CNET98S_BDP
));
151 le_cbus_wrcsr(struct lance_softc
*sc
, uint16_t port
, uint16_t val
)
153 struct le_cbus_softc
*lesc
= (struct le_cbus_softc
*)sc
;
155 bus_space_write_2(lesc
->sc_regt
, lesc
->sc_regh
, CNET98S_RAP
, port
);
156 bus_space_barrier(lesc
->sc_regt
, lesc
->sc_regh
, CNET98S_RAP
, 2,
157 BUS_SPACE_BARRIER_WRITE
);
158 bus_space_write_2(lesc
->sc_regt
, lesc
->sc_regh
, CNET98S_RDP
, val
);
162 le_cbus_rdcsr(struct lance_softc
*sc
, uint16_t port
)
164 struct le_cbus_softc
*lesc
= (struct le_cbus_softc
*)sc
;
166 bus_space_write_2(lesc
->sc_regt
, lesc
->sc_regh
, CNET98S_RAP
, port
);
167 bus_space_barrier(lesc
->sc_regt
, lesc
->sc_regh
, CNET98S_RAP
, 2,
168 BUS_SPACE_BARRIER_WRITE
);
169 return (bus_space_read_2(lesc
->sc_regt
, lesc
->sc_regh
, CNET98S_RDP
));
173 le_cbus_hwreset(struct lance_softc
*sc
)
175 struct le_cbus_softc
*lesc
= (struct le_cbus_softc
*)sc
;
178 * NB: These are Contec C-NET(98)S only.
181 /* Reset the chip. */
182 bus_space_write_2(lesc
->sc_regt
, lesc
->sc_regh
, CNET98S_RESET
,
183 bus_space_read_2(lesc
->sc_regt
, lesc
->sc_regh
, CNET98S_RESET
));
186 /* ISA bus configuration */
187 /* ISACSR0 - set Master Mode Read Active time to 300ns. */
188 le_cbus_wrbcr(sc
, LE_BCR0
, 0x0006);
189 /* ISACSR1 - set Master Mode Write Active time to 300ns. */
190 le_cbus_wrbcr(sc
, LE_BCR1
, 0x0006);
192 device_printf(dev
, "ISACSR2=0x%x\n", le_cbus_rdbcr(sc
, LE_BCR2
));
195 le_cbus_wrbcr(sc
, LE_BCR5
, LE_B4_PSE
| LE_B4_XMTE
);
197 le_cbus_wrbcr(sc
, LE_BCR6
, LE_B4_PSE
| LE_B4_RCVE
);
199 le_cbus_wrbcr(sc
, LE_BCR7
, LE_B4_PSE
| LE_B4_COLE
);
203 le_cbus_dma_callback(void *xsc
, bus_dma_segment_t
*segs
, int nsegs
, int error
)
205 struct lance_softc
*sc
= (struct lance_softc
*)xsc
;
209 KASSERT(nsegs
== 1, ("%s: bad DMA segment count", __func__
));
210 sc
->sc_addr
= segs
[0].ds_addr
;
214 le_cbus_probe(device_t dev
)
216 struct le_cbus_softc
*lesc
;
217 struct lance_softc
*sc
;
221 * Skip PnP devices as some wedge when trying to probe them as
224 if (isa_get_vendorid(dev
))
227 lesc
= device_get_softc(dev
);
228 sc
= &lesc
->sc_am7990
.lsc
;
231 lesc
->sc_rres
= isa_alloc_resourcev(dev
, SYS_RES_IOPORT
, &lesc
->sc_rrid
,
232 le_ioaddr_cnet98s
, CNET98S_IOSIZE
, RF_ACTIVE
);
233 if (lesc
->sc_rres
== NULL
)
235 isa_load_resourcev(lesc
->sc_rres
, le_ioaddr_cnet98s
, CNET98S_IOSIZE
);
236 lesc
->sc_regt
= rman_get_bustag(lesc
->sc_rres
);
237 lesc
->sc_regh
= rman_get_bushandle(lesc
->sc_rres
);
239 /* Reset the chip. */
240 bus_space_write_2(lesc
->sc_regt
, lesc
->sc_regh
, CNET98S_RESET
,
241 bus_space_read_2(lesc
->sc_regt
, lesc
->sc_regh
, CNET98S_RESET
));
244 /* Stop the chip and put it in a known state. */
245 le_cbus_wrcsr(sc
, LE_CSR0
, LE_C0_STOP
);
247 if (le_cbus_rdcsr(sc
, LE_CSR0
) != LE_C0_STOP
) {
251 le_cbus_wrcsr(sc
, LE_CSR3
, 0);
252 device_set_desc(dev
, "C-NET(98)S");
253 error
= BUS_PROBE_DEFAULT
;
256 bus_release_resource(dev
, SYS_RES_IOPORT
, lesc
->sc_rrid
, lesc
->sc_rres
);
261 le_cbus_attach(device_t dev
)
263 struct le_cbus_softc
*lesc
;
264 struct lance_softc
*sc
;
267 lesc
= device_get_softc(dev
);
268 sc
= &lesc
->sc_am7990
.lsc
;
270 LE_LOCK_INIT(sc
, device_get_nameunit(dev
));
273 lesc
->sc_rres
= isa_alloc_resourcev(dev
, SYS_RES_IOPORT
, &lesc
->sc_rrid
,
274 le_ioaddr_cnet98s
, CNET98S_IOSIZE
, RF_ACTIVE
);
275 if (lesc
->sc_rres
== NULL
) {
276 device_printf(dev
, "cannot allocate registers\n");
280 isa_load_resourcev(lesc
->sc_rres
, le_ioaddr_cnet98s
, CNET98S_IOSIZE
);
281 lesc
->sc_regt
= rman_get_bustag(lesc
->sc_rres
);
282 lesc
->sc_regh
= rman_get_bushandle(lesc
->sc_rres
);
285 if ((lesc
->sc_ires
= bus_alloc_resource_any(dev
, SYS_RES_IRQ
,
286 &lesc
->sc_irid
, RF_SHAREABLE
| RF_ACTIVE
)) == NULL
) {
287 device_printf(dev
, "cannot allocate interrupt\n");
292 error
= bus_dma_tag_create(
293 bus_get_dma_tag(dev
), /* parent */
294 1, 0, /* alignment, boundary */
295 BUS_SPACE_MAXADDR_24BIT
, /* lowaddr */
296 BUS_SPACE_MAXADDR
, /* highaddr */
297 NULL
, NULL
, /* filter, filterarg */
298 BUS_SPACE_MAXSIZE_32BIT
, /* maxsize */
300 BUS_SPACE_MAXSIZE_32BIT
, /* maxsegsize */
302 NULL
, NULL
, /* lockfunc, lockarg */
305 device_printf(dev
, "cannot allocate parent DMA tag\n");
309 sc
->sc_memsize
= LE_CBUS_MEMSIZE
;
311 * For Am79C90, Am79C961 and Am79C961A the init block must be 2-byte
312 * aligned and the ring descriptors must be 8-byte aligned.
314 error
= bus_dma_tag_create(
315 lesc
->sc_pdmat
, /* parent */
316 8, 0, /* alignment, boundary */
317 BUS_SPACE_MAXADDR_24BIT
, /* lowaddr */
318 BUS_SPACE_MAXADDR
, /* highaddr */
319 NULL
, NULL
, /* filter, filterarg */
320 sc
->sc_memsize
, /* maxsize */
322 sc
->sc_memsize
, /* maxsegsize */
324 NULL
, NULL
, /* lockfunc, lockarg */
327 device_printf(dev
, "cannot allocate buffer DMA tag\n");
331 error
= bus_dmamem_alloc(lesc
->sc_dmat
, (void **)&sc
->sc_mem
,
332 BUS_DMA_WAITOK
| BUS_DMA_COHERENT
, &lesc
->sc_dmam
);
334 device_printf(dev
, "cannot allocate DMA buffer memory\n");
339 error
= bus_dmamap_load(lesc
->sc_dmat
, lesc
->sc_dmam
, sc
->sc_mem
,
340 sc
->sc_memsize
, le_cbus_dma_callback
, sc
, 0);
341 if (error
!= 0 || sc
->sc_addr
== 0) {
342 device_printf(dev
, "cannot load DMA buffer map\n");
350 * Extract the physical MAC address from the ROM.
352 for (i
= 0; i
< sizeof(sc
->sc_enaddr
); i
++)
353 sc
->sc_enaddr
[i
] = bus_space_read_1(lesc
->sc_regt
,
354 lesc
->sc_regh
, i
* 2);
356 sc
->sc_copytodesc
= lance_copytobuf_contig
;
357 sc
->sc_copyfromdesc
= lance_copyfrombuf_contig
;
358 sc
->sc_copytobuf
= lance_copytobuf_contig
;
359 sc
->sc_copyfrombuf
= lance_copyfrombuf_contig
;
360 sc
->sc_zerobuf
= lance_zerobuf_contig
;
362 sc
->sc_rdcsr
= le_cbus_rdcsr
;
363 sc
->sc_wrcsr
= le_cbus_wrcsr
;
364 sc
->sc_hwreset
= le_cbus_hwreset
;
365 sc
->sc_hwinit
= NULL
;
366 sc
->sc_hwintr
= NULL
;
367 sc
->sc_nocarrier
= NULL
;
368 sc
->sc_mediachange
= NULL
;
369 sc
->sc_mediastatus
= NULL
;
370 sc
->sc_supmedia
= NULL
;
372 error
= am7990_config(&lesc
->sc_am7990
, device_get_name(dev
),
373 device_get_unit(dev
));
375 device_printf(dev
, "cannot attach Am7990\n");
379 error
= bus_setup_intr(dev
, lesc
->sc_ires
, INTR_TYPE_NET
| INTR_MPSAFE
,
380 NULL
, am7990_intr
, sc
, &lesc
->sc_ih
);
382 device_printf(dev
, "cannot set up interrupt\n");
389 am7990_detach(&lesc
->sc_am7990
);
391 bus_dmamap_unload(lesc
->sc_dmat
, lesc
->sc_dmam
);
393 bus_dmamem_free(lesc
->sc_dmat
, sc
->sc_mem
, lesc
->sc_dmam
);
395 bus_dma_tag_destroy(lesc
->sc_dmat
);
397 bus_dma_tag_destroy(lesc
->sc_pdmat
);
399 bus_release_resource(dev
, SYS_RES_IRQ
, lesc
->sc_irid
, lesc
->sc_ires
);
401 bus_release_resource(dev
, SYS_RES_IOPORT
, lesc
->sc_rrid
, lesc
->sc_rres
);
408 le_cbus_detach(device_t dev
)
410 struct le_cbus_softc
*lesc
;
411 struct lance_softc
*sc
;
413 lesc
= device_get_softc(dev
);
414 sc
= &lesc
->sc_am7990
.lsc
;
416 bus_teardown_intr(dev
, lesc
->sc_ires
, lesc
->sc_ih
);
417 am7990_detach(&lesc
->sc_am7990
);
418 bus_dmamap_unload(lesc
->sc_dmat
, lesc
->sc_dmam
);
419 bus_dmamem_free(lesc
->sc_dmat
, sc
->sc_mem
, lesc
->sc_dmam
);
420 bus_dma_tag_destroy(lesc
->sc_dmat
);
421 bus_dma_tag_destroy(lesc
->sc_pdmat
);
422 bus_release_resource(dev
, SYS_RES_IRQ
, lesc
->sc_irid
, lesc
->sc_ires
);
423 bus_release_resource(dev
, SYS_RES_IOPORT
, lesc
->sc_rrid
, lesc
->sc_rres
);
430 le_cbus_suspend(device_t dev
)
432 struct le_cbus_softc
*lesc
;
434 lesc
= device_get_softc(dev
);
436 lance_suspend(&lesc
->sc_am7990
.lsc
);
442 le_cbus_resume(device_t dev
)
444 struct le_cbus_softc
*lesc
;
446 lesc
= device_get_softc(dev
);
448 lance_resume(&lesc
->sc_am7990
.lsc
);