1 /* $NetBSD: if_ie_mvme.c,v 1.15 2009/05/12 13:16:45 cegger Exp $ */
4 * Copyright (c) 1999, 2002 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Steve C. Woodford.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: if_ie_mvme.c,v 1.15 2009/05/12 13:16:45 cegger Exp $");
35 #include <sys/param.h>
36 #include <sys/systm.h>
38 #include <sys/errno.h>
39 #include <sys/device.h>
40 #include <sys/protosw.h>
41 #include <sys/socket.h>
44 #include <net/if_dl.h>
45 #include <net/if_types.h>
46 #include <net/if_ether.h>
47 #include <net/if_media.h>
49 #include <uvm/uvm_extern.h>
51 #include <machine/autoconf.h>
55 #include <dev/ic/i82586reg.h>
56 #include <dev/ic/i82586var.h>
58 #include <dev/mvme/if_iereg.h>
59 #include <dev/mvme/pcctwovar.h>
60 #include <dev/mvme/pcctworeg.h>
63 int ie_pcctwo_match(device_t
, cfdata_t
, void *);
64 void ie_pcctwo_attach(device_t
, device_t
, void *);
66 struct ie_pcctwo_softc
{
67 struct ie_softc ps_ie
;
68 bus_space_tag_t ps_bust
;
69 bus_space_handle_t ps_bush
;
70 struct evcnt ps_evcnt
;
73 CFATTACH_DECL(ie_pcctwo
, sizeof(struct ie_pcctwo_softc
),
74 ie_pcctwo_match
, ie_pcctwo_attach
, NULL
, NULL
);
76 extern struct cfdriver ie_cd
;
79 /* Functions required by the i82586 MI driver */
80 static void ie_reset(struct ie_softc
*, int);
81 static int ie_intrhook(struct ie_softc
*, int);
82 static void ie_hwinit(struct ie_softc
*);
83 static void ie_atten(struct ie_softc
*, int);
85 static void ie_copyin(struct ie_softc
*, void *, int, size_t);
86 static void ie_copyout(struct ie_softc
*, const void *, int, size_t);
88 static u_int16_t
ie_read_16(struct ie_softc
*, int);
89 static void ie_write_16(struct ie_softc
*, int, u_int16_t
);
90 static void ie_write_24(struct ie_softc
*, int, int);
93 * i82596 Support Routines for MVME1[67][27] and MVME187 Boards
96 ie_reset(struct ie_softc
*sc
, int why
)
98 struct ie_pcctwo_softc
*ps
;
101 ps
= (struct ie_pcctwo_softc
*) sc
;
106 bus_space_write_2(ps
->ps_bust
, ps
->ps_bush
, IE_MPUREG_UPPER
,
108 bus_space_write_2(ps
->ps_bust
, ps
->ps_bush
, IE_MPUREG_LOWER
, 0);
112 * Set the BUSY and BUS_USE bytes here, since the MI code
113 * incorrectly assumes it can use byte addressing to set it.
114 * (due to wrong-endianess of the chip)
116 ie_write_16(sc
, IE_ISCP_BUSY(sc
->iscp
), 1);
117 ie_write_16(sc
, IE_SCP_BUS_USE(sc
->scp
), IE_BUS_USE
);
119 scp_addr
= sc
->scp
+ (u_int
) sc
->sc_iobase
;
120 scp_addr
|= IE_PORT_ALT_SCP
;
122 bus_space_write_2(ps
->ps_bust
, ps
->ps_bush
, IE_MPUREG_UPPER
,
124 bus_space_write_2(ps
->ps_bust
, ps
->ps_bush
, IE_MPUREG_LOWER
,
125 (scp_addr
>> 16) & 0xffff);
133 ie_intrhook(struct ie_softc
*sc
, int when
)
135 struct ie_pcctwo_softc
*ps
;
138 ps
= (struct ie_pcctwo_softc
*) sc
;
140 if (when
== INTR_EXIT
) {
141 reg
= pcc2_reg_read(sys_pcctwo
, PCC2REG_ETH_ICSR
);
142 reg
|= PCCTWO_ICR_ICLR
;
143 pcc2_reg_write(sys_pcctwo
, PCC2REG_ETH_ICSR
, reg
);
150 ie_hwinit(struct ie_softc
*sc
)
154 reg
= pcc2_reg_read(sys_pcctwo
, PCC2REG_ETH_ICSR
);
155 reg
|= PCCTWO_ICR_IEN
| PCCTWO_ICR_ICLR
;
156 pcc2_reg_write(sys_pcctwo
, PCC2REG_ETH_ICSR
, reg
);
161 ie_atten(struct ie_softc
*sc
, int reason
)
163 struct ie_pcctwo_softc
*ps
;
165 ps
= (struct ie_pcctwo_softc
*) sc
;
166 bus_space_write_4(ps
->ps_bust
, ps
->ps_bush
, IE_MPUREG_CA
, 0);
170 ie_copyin(struct ie_softc
*sc
, void *dst
, int offset
, size_t size
)
172 if (size
== 0) /* This *can* happen! */
176 bus_space_read_region_1(sc
->bt
, sc
->bh
, offset
, dst
, size
);
178 /* A minor optimisation ;-) */
179 memcpy(dst
, (void *) ((u_long
) sc
->bh
+ (u_long
) offset
), size
);
184 ie_copyout(struct ie_softc
*sc
, const void *src
, int offset
, size_t size
)
186 if (size
== 0) /* This *can* happen! */
190 bus_space_write_region_1(sc
->bt
, sc
->bh
, offset
, src
, size
);
192 /* A minor optimisation ;-) */
193 memcpy((void *) ((u_long
) sc
->bh
+ (u_long
) offset
), src
, size
);
198 ie_read_16(struct ie_softc
*sc
, int offset
)
201 return (bus_space_read_2(sc
->bt
, sc
->bh
, offset
));
205 ie_write_16(struct ie_softc
*sc
, int offset
, u_int16_t value
)
208 bus_space_write_2(sc
->bt
, sc
->bh
, offset
, value
);
212 ie_write_24(struct ie_softc
*sc
, int offset
, int addr
)
215 addr
+= (int) sc
->sc_iobase
;
217 bus_space_write_2(sc
->bt
, sc
->bh
, offset
, addr
& 0xffff);
218 bus_space_write_2(sc
->bt
, sc
->bh
, offset
+ 2, (addr
>> 16) & 0x00ff);
223 ie_pcctwo_match(device_t parent
, cfdata_t cf
, void *args
)
225 struct pcctwo_attach_args
*pa
;
229 if (strcmp(pa
->pa_name
, ie_cd
.cd_name
))
232 pa
->pa_ipl
= cf
->pcctwocf_ipl
;
239 ie_pcctwo_attach(device_t parent
, device_t self
, void *args
)
241 struct pcctwo_attach_args
*pa
;
242 struct ie_pcctwo_softc
*ps
;
244 bus_dma_segment_t seg
;
247 pa
= (struct pcctwo_attach_args
*) args
;
248 ps
= device_private(self
);
249 sc
= device_private(self
);
251 /* Map the MPU controller registers in PCCTWO space */
252 ps
->ps_bust
= pa
->pa_bust
;
253 bus_space_map(pa
->pa_bust
, pa
->pa_offset
, IE_MPUREG_SIZE
,
256 /* Get contiguous DMA-able memory for the IE chip */
257 if (bus_dmamem_alloc(pa
->pa_dmat
, ether_data_buff_size
, PAGE_SIZE
, 0,
259 BUS_DMA_NOWAIT
| BUS_DMA_ONBOARD_RAM
| BUS_DMA_24BIT
) != 0) {
260 aprint_error_dev(self
, "Failed to allocate ether buffer\n");
263 if (bus_dmamem_map(pa
->pa_dmat
, &seg
, rseg
, ether_data_buff_size
,
264 (void **) & sc
->sc_maddr
, BUS_DMA_NOWAIT
| BUS_DMA_COHERENT
)) {
265 aprint_error_dev(self
, "Failed to map ether buffer\n");
266 bus_dmamem_free(pa
->pa_dmat
, &seg
, rseg
);
269 sc
->bt
= pa
->pa_bust
;
270 sc
->bh
= (bus_space_handle_t
) sc
->sc_maddr
; /* XXXSCW Better way? */
271 sc
->sc_iobase
= (void *) seg
.ds_addr
;
272 sc
->sc_msize
= ether_data_buff_size
;
273 memset(sc
->sc_maddr
, 0, ether_data_buff_size
);
275 sc
->hwreset
= ie_reset
;
276 sc
->hwinit
= ie_hwinit
;
277 sc
->chan_attn
= ie_atten
;
278 sc
->intrhook
= ie_intrhook
;
279 sc
->memcopyin
= ie_copyin
;
280 sc
->memcopyout
= ie_copyout
;
281 sc
->ie_bus_barrier
= NULL
;
282 sc
->ie_bus_read16
= ie_read_16
;
283 sc
->ie_bus_write16
= ie_write_16
;
284 sc
->ie_bus_write24
= ie_write_24
;
285 sc
->sc_mediachange
= NULL
;
286 sc
->sc_mediastatus
= NULL
;
289 sc
->iscp
= sc
->scp
+ ((IE_SCP_SZ
+ 15) & ~15);
290 sc
->scb
= sc
->iscp
+ IE_ISCP_SZ
;
291 sc
->buf_area
= sc
->scb
+ IE_SCB_SZ
;
292 sc
->buf_area_sz
= sc
->sc_msize
- (sc
->buf_area
- sc
->scp
);
295 * BUS_USE -> Interrupt Active High (edge-triggered),
296 * Lock function enabled,
297 * Internal bus throttle timer triggering,
298 * 82586 operating mode.
300 ie_write_16(sc
, IE_SCP_BUS_USE(sc
->scp
), IE_BUS_USE
);
301 ie_write_24(sc
, IE_SCP_ISCP(sc
->scp
), sc
->iscp
);
302 ie_write_16(sc
, IE_ISCP_SCB(sc
->iscp
), sc
->scb
);
303 ie_write_24(sc
, IE_ISCP_BASE(sc
->iscp
), sc
->scp
);
305 /* This has the side-effect of resetting the chip */
308 /* Attach the MI back-end */
309 i82586_attach(sc
, "onboard", mvme_ea
, NULL
, 0, 0);
311 /* Register the event counter */
312 evcnt_attach_dynamic(&ps
->ps_evcnt
, EVCNT_TYPE_INTR
,
313 pcctwointr_evcnt(pa
->pa_ipl
), "ether", device_xname(&sc
->sc_dev
));
315 /* Finally, hook the hardware interrupt */
316 pcctwointr_establish(PCCTWOV_LANC_IRQ
, i82586_intr
, pa
->pa_ipl
, sc
,