1 /* $NetBSD: vme_two.c,v 1.7 2008/04/28 20:23:54 martin 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.
33 * VME support specific to the VMEchip2 found on all high-end MVME boards
36 #include <sys/cdefs.h>
37 __KERNEL_RCSID(0, "$NetBSD: vme_two.c,v 1.7 2008/04/28 20:23:54 martin Exp $");
41 #include <sys/param.h>
42 #include <sys/kernel.h>
43 #include <sys/systm.h>
44 #include <sys/device.h>
49 #include <dev/vme/vmereg.h>
50 #include <dev/vme/vmevar.h>
52 #include <dev/mvme/mvmebus.h>
53 #include <dev/mvme/vme_tworeg.h>
54 #include <dev/mvme/vme_twovar.h>
56 void vmetwo_master_range(struct vmetwo_softc
*, int, struct mvmebus_range
*);
57 void vmetwo_slave_range(struct vmetwo_softc
*, int, vme_am_t
,
58 struct mvmebus_range
*);
62 vmetwo_init(struct vmetwo_softc
*sc
)
67 /* Initialise stuff for the common mvmebus front-end */
68 sc
->sc_mvmebus
.sc_chip
= sc
;
69 sc
->sc_mvmebus
.sc_nmasters
= VME2_NMASTERS
;
70 sc
->sc_mvmebus
.sc_masters
= &sc
->sc_master
[0];
71 sc
->sc_mvmebus
.sc_nslaves
= VME2_NSLAVES
;
72 sc
->sc_mvmebus
.sc_slaves
= &sc
->sc_slave
[0];
73 sc
->sc_mvmebus
.sc_intr_establish
= vmetwo_intr_establish
;
74 sc
->sc_mvmebus
.sc_intr_disestablish
= vmetwo_intr_disestablish
;
76 /* Initialise interrupts */
79 reg
= vme2_lcsr_read(sc
, VME2LCSR_BOARD_CONTROL
);
80 printf(": Type 2 VMEchip, scon jumper %s\n",
81 (reg
& VME2_BOARD_CONTROL_SCON
) ? "enabled" : "disabled");
84 * Figure out what bits of the VMEbus we can access.
85 * First record the `fixed' maps (if they're enabled)
87 reg
= vme2_lcsr_read(sc
, VME2LCSR_IO_CONTROL
);
88 if (reg
& VME2_IO_CONTROL_I1EN
) {
89 /* This range is fixed to A16, DATA */
90 sc
->sc_master
[0].vr_am
= VME_AM_A16
| MVMEBUS_AM_CAP_DATA
;
92 /* However, SUPER/USER is selectable... */
93 if (reg
& VME2_IO_CONTROL_I1SU
)
94 sc
->sc_master
[0].vr_am
|= MVMEBUS_AM_CAP_SUPER
;
96 sc
->sc_master
[0].vr_am
|= MVMEBUS_AM_CAP_USER
;
98 /* As is the datasize */
99 sc
->sc_master
[0].vr_datasize
= VME_D32
| VME_D16
;
100 if (reg
& VME2_IO_CONTROL_I1D16
)
101 sc
->sc_master
[0].vr_datasize
&= ~VME_D32
;
103 sc
->sc_master
[0].vr_locstart
= VME2_IO0_LOCAL_START
;
104 sc
->sc_master
[0].vr_mask
= VME2_IO0_MASK
;
105 sc
->sc_master
[0].vr_vmestart
= VME2_IO0_VME_START
;
106 sc
->sc_master
[0].vr_vmeend
= VME2_IO0_VME_END
;
108 sc
->sc_master
[0].vr_am
= MVMEBUS_AM_DISABLED
;
110 if (reg
& VME2_IO_CONTROL_I2EN
) {
111 /* These two ranges are fixed to A24D16 and A32D16 */
112 sc
->sc_master
[1].vr_am
= VME_AM_A24
;
113 sc
->sc_master
[1].vr_datasize
= VME_D16
;
114 sc
->sc_master
[2].vr_am
= VME_AM_A32
;
115 sc
->sc_master
[2].vr_datasize
= VME_D16
;
117 /* However, SUPER/USER is selectable */
118 if (reg
& VME2_IO_CONTROL_I2SU
) {
119 sc
->sc_master
[1].vr_am
|= MVMEBUS_AM_CAP_SUPER
;
120 sc
->sc_master
[2].vr_am
|= MVMEBUS_AM_CAP_SUPER
;
122 sc
->sc_master
[1].vr_am
|= MVMEBUS_AM_CAP_USER
;
123 sc
->sc_master
[2].vr_am
|= MVMEBUS_AM_CAP_USER
;
126 /* As is PROGRAM/DATA */
127 if (reg
& VME2_IO_CONTROL_I2PD
) {
128 sc
->sc_master
[1].vr_am
|= MVMEBUS_AM_CAP_PROG
;
129 sc
->sc_master
[2].vr_am
|= MVMEBUS_AM_CAP_PROG
;
131 sc
->sc_master
[1].vr_am
|= MVMEBUS_AM_CAP_DATA
;
132 sc
->sc_master
[2].vr_am
|= MVMEBUS_AM_CAP_DATA
;
135 sc
->sc_master
[1].vr_locstart
= VME2_IO1_LOCAL_START
;
136 sc
->sc_master
[1].vr_mask
= VME2_IO1_MASK
;
137 sc
->sc_master
[1].vr_vmestart
= VME2_IO1_VME_START
;
138 sc
->sc_master
[1].vr_vmeend
= VME2_IO1_VME_END
;
140 sc
->sc_master
[2].vr_locstart
= VME2_IO2_LOCAL_START
;
141 sc
->sc_master
[2].vr_mask
= VME2_IO2_MASK
;
142 sc
->sc_master
[2].vr_vmestart
= VME2_IO2_VME_START
;
143 sc
->sc_master
[2].vr_vmeend
= VME2_IO2_VME_END
;
145 sc
->sc_master
[1].vr_am
= MVMEBUS_AM_DISABLED
;
146 sc
->sc_master
[2].vr_am
= MVMEBUS_AM_DISABLED
;
150 * Now read the progammable maps
152 for (i
= 0; i
< VME2_MASTER_WINDOWS
; i
++)
153 vmetwo_master_range(sc
, i
,
154 &(sc
->sc_master
[i
+ VME2_MASTER_PROG_START
]));
156 /* XXX: No A16 slave yet :XXX */
157 sc
->sc_slave
[VME2_SLAVE_A16
].vr_am
= MVMEBUS_AM_DISABLED
;
159 for (i
= 0; i
< VME2_SLAVE_WINDOWS
; i
++) {
160 vmetwo_slave_range(sc
, i
, VME_AM_A32
,
161 &sc
->sc_slave
[i
+ VME2_SLAVE_PROG_START
]);
162 vmetwo_slave_range(sc
, i
, VME_AM_A24
,
163 &sc
->sc_slave
[i
+ VME2_SLAVE_PROG_START
+ 2]);
166 mvmebus_attach(&sc
->sc_mvmebus
);
170 vmetwo_master_range(struct vmetwo_softc
*sc
, int range
, struct mvmebus_range
*vr
)
172 u_int32_t start
, end
, attr
;
176 * First, check if the range is actually enabled...
178 reg
= vme2_lcsr_read(sc
, VME2LCSR_MASTER_ENABLE
);
179 if ((reg
& VME2_MASTER_ENABLE(range
)) == 0) {
180 vr
->vr_am
= MVMEBUS_AM_DISABLED
;
185 * Fetch and record the range's attributes
187 attr
= vme2_lcsr_read(sc
, VME2LCSR_MASTER_ATTR
);
188 attr
>>= VME2_MASTER_ATTR_AM_SHIFT(range
);
191 * Fix up the datasizes available through this range
193 vr
->vr_datasize
= VME_D32
| VME_D16
;
194 if (attr
& VME2_MASTER_ATTR_D16
)
195 vr
->vr_datasize
&= ~VME_D32
;
196 attr
&= VME2_MASTER_ATTR_AM_MASK
;
198 vr
->vr_am
= (attr
& VME_AM_ADRSIZEMASK
) | MVMEBUS_AM2CAP(attr
);
199 switch (vr
->vr_am
& VME_AM_ADRSIZEMASK
) {
202 vr
->vr_mask
= 0xffffffffu
;
206 vr
->vr_mask
= 0x00ffffffu
;
210 vr
->vr_mask
= 0x0000ffffu
;
216 * It would be nice if users of the MI VMEbus code could pass down
217 * whether they can tolerate Write-Posting to their device(s).
222 * Fetch the local-bus start and end addresses for the range
224 reg
= vme2_lcsr_read(sc
, VME2LCSR_MASTER_ADDRESS(range
));
225 start
= (reg
& VME2_MAST_ADDRESS_START_MASK
);
226 start
<<= VME2_MAST_ADDRESS_START_SHIFT
;
227 vr
->vr_locstart
= start
& ~vr
->vr_mask
;
228 end
= (reg
& VME2_MAST_ADDRESS_END_MASK
);
229 end
<<= VME2_MAST_ADDRESS_END_SHIFT
;
234 * Local->VMEbus map '4' has optional translation bits, so
235 * the VMEbus start and end addresses may need to be adjusted.
237 if (range
== 3 && (reg
= vme2_lcsr_read(sc
, VME2LCSR_MAST4_TRANS
))!=0) {
238 uint32_t addr
, sel
, len
= end
- start
;
240 reg
= vme2_lcsr_read(sc
, VME2LCSR_MAST4_TRANS
);
241 reg
&= VME2_MAST4_TRANS_SELECT_MASK
;
242 sel
= reg
<< VME2_MAST4_TRANS_SELECT_SHIFT
;
244 reg
= vme2_lcsr_read(sc
, VME2LCSR_MAST4_TRANS
);
245 reg
&= VME2_MAST4_TRANS_ADDRESS_MASK
;
246 addr
= reg
<< VME2_MAST4_TRANS_ADDRESS_SHIFT
;
248 start
= (addr
& sel
) | (start
& (~sel
));
250 vr
->vr_mask
&= len
- 1;
253 /* XXX Deal with overlap of onboard RAM address space */
254 /* XXX Then again, 167-Bug warns about this at setup time ... */
257 * Fixup the addresses this range corresponds to
259 vr
->vr_vmestart
= start
& vr
->vr_mask
;
260 vr
->vr_vmeend
= (end
- 1) & vr
->vr_mask
;
264 vmetwo_slave_range(struct vmetwo_softc
*sc
, int range
, vme_am_t am
, struct mvmebus_range
*vr
)
269 * First, check if the range is actually enabled.
270 * Note that bit 1 of `range' is used to indicte if we're
271 * looking for an A24 range (set) or an A32 range (clear).
273 reg
= vme2_lcsr_read(sc
, VME2LCSR_SLAVE_CTRL
);
275 if (am
== VME_AM_A32
&& (reg
& VME2_SLAVE_AMSEL_A32(range
))) {
276 vr
->vr_am
= VME_AM_A32
;
277 vr
->vr_mask
= 0xffffffffu
;
279 if (am
== VME_AM_A24
&& (reg
& VME2_SLAVE_AMSEL_A24(range
))) {
280 vr
->vr_am
= VME_AM_A24
;
281 vr
->vr_mask
= 0x00ffffffu
;
283 /* The range is not enabled */
284 vr
->vr_am
= MVMEBUS_AM_DISABLED
;
288 if ((reg
& VME2_SLAVE_AMSEL_DAT(range
)) != 0)
289 vr
->vr_am
|= MVMEBUS_AM_CAP_DATA
;
291 if ((reg
& VME2_SLAVE_AMSEL_PGM(range
)) != 0)
292 vr
->vr_am
|= MVMEBUS_AM_CAP_PROG
;
294 if ((reg
& VME2_SLAVE_AMSEL_USR(range
)) != 0)
295 vr
->vr_am
|= MVMEBUS_AM_CAP_USER
;
297 if ((reg
& VME2_SLAVE_AMSEL_SUP(range
)) != 0)
298 vr
->vr_am
|= MVMEBUS_AM_CAP_SUPER
;
300 if ((reg
& VME2_SLAVE_AMSEL_BLK(range
)) != 0)
301 vr
->vr_am
|= MVMEBUS_AM_CAP_BLK
;
303 if ((reg
& VME2_SLAVE_AMSEL_BLKD64(range
)) != 0)
304 vr
->vr_am
|= MVMEBUS_AM_CAP_BLKD64
;
306 vr
->vr_datasize
= VME_D32
| VME_D16
| VME_D8
;
309 * Record the VMEbus start and end addresses of the slave image
311 reg
= vme2_lcsr_read(sc
, VME2LCSR_SLAVE_ADDRESS(range
));
312 vr
->vr_vmestart
= reg
& VME2_SLAVE_ADDRESS_START_MASK
;
313 vr
->vr_vmestart
<<= VME2_SLAVE_ADDRESS_START_SHIFT
;
314 vr
->vr_vmestart
&= vr
->vr_mask
;
315 vr
->vr_vmeend
= reg
& VME2_SLAVE_ADDRESS_END_MASK
;
316 vr
->vr_vmeend
<<= VME2_SLAVE_ADDRESS_END_SHIFT
;
317 vr
->vr_vmeend
&= vr
->vr_mask
;
318 vr
->vr_vmeend
|= 0xffffu
;
321 * Now figure out the local-bus address
323 reg
= vme2_lcsr_read(sc
, VME2LCSR_SLAVE_CTRL
);
324 if ((reg
& VME2_SLAVE_CTRL_ADDER(range
)) != 0) {
325 reg
= vme2_lcsr_read(sc
, VME2LCSR_SLAVE_TRANS(range
));
326 reg
&= VME2_SLAVE_TRANS_ADDRESS_MASK
;
327 reg
<<= VME2_SLAVE_TRANS_ADDRESS_SHIFT
;
328 vr
->vr_locstart
= vr
->vr_vmestart
+ reg
;
332 reg
= vme2_lcsr_read(sc
, VME2LCSR_SLAVE_TRANS(range
));
333 sel
= reg
& VME2_SLAVE_TRANS_SELECT_MASK
;
334 sel
<<= VME2_SLAVE_TRANS_SELECT_SHIFT
;
335 addr
= reg
& VME2_SLAVE_TRANS_ADDRESS_MASK
;
336 addr
<<= VME2_SLAVE_TRANS_ADDRESS_SHIFT
;
338 vr
->vr_locstart
= addr
& sel
;
339 vr
->vr_locstart
|= vr
->vr_vmestart
& (~sel
);