vme_pcc.c revision 1.19 1 /* $NetBSD: vme_pcc.c,v 1.19 2004/02/13 11:36:15 wiz Exp $ */
2
3 /*-
4 * Copyright (c) 1996-2000 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Jason R. Thorpe and Steve C. Woodford.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
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.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 /*
40 * VME support specific to the Type 1 VMEchip found on the
41 * MVME-147.
42 *
43 * For a manual on the MVME-147, call: 408.991.8634. (Yes, this
44 * is the Sunnyvale sales office.)
45 */
46
47 #include <sys/cdefs.h>
48 __KERNEL_RCSID(0, "$NetBSD: vme_pcc.c,v 1.19 2004/02/13 11:36:15 wiz Exp $");
49
50 #include <sys/param.h>
51 #include <sys/kernel.h>
52 #include <sys/systm.h>
53 #include <sys/device.h>
54 #include <sys/malloc.h>
55 #include <sys/kcore.h>
56
57 #include <machine/cpu.h>
58 #include <machine/bus.h>
59
60 #include <dev/vme/vmereg.h>
61 #include <dev/vme/vmevar.h>
62
63 #include <mvme68k/dev/pccreg.h>
64 #include <mvme68k/dev/pccvar.h>
65
66 #include <dev/mvme/mvmebus.h>
67 #include <mvme68k/dev/vme_pccreg.h>
68 #include <mvme68k/dev/vme_pccvar.h>
69
70
71 int vme_pcc_match(struct device *, struct cfdata *, void *);
72 void vme_pcc_attach(struct device *, struct device *, void *);
73
74 CFATTACH_DECL(vmepcc, sizeof(struct vme_pcc_softc),
75 vme_pcc_match, vme_pcc_attach, NULL, NULL);
76
77 extern struct cfdriver vmepcc_cd;
78
79 extern phys_ram_seg_t mem_clusters[];
80 static int vme_pcc_attached;
81
82 void vme_pcc_intr_establish(void *, int, int, int, int,
83 int (*)(void *), void *, struct evcnt *);
84 void vme_pcc_intr_disestablish(void *, int, int, int, struct evcnt *);
85
86
87 static struct mvmebus_range vme_pcc_masters[] = {
88 {VME_AM_A24 |
89 MVMEBUS_AM_CAP_DATA | MVMEBUS_AM_CAP_PROG |
90 MVMEBUS_AM_CAP_SUPER | MVMEBUS_AM_CAP_USER,
91 VME_D32 | VME_D16 | VME_D8,
92 VME1_A24D32_LOC_START,
93 VME1_A24_MASK,
94 VME1_A24D32_START,
95 VME1_A24D32_END},
96
97 {VME_AM_A32 |
98 MVMEBUS_AM_CAP_DATA | MVMEBUS_AM_CAP_PROG |
99 MVMEBUS_AM_CAP_SUPER | MVMEBUS_AM_CAP_USER,
100 VME_D32 | VME_D16 | VME_D8,
101 VME1_A32D32_LOC_START,
102 VME1_A32_MASK,
103 VME1_A32D32_START,
104 VME1_A32D32_END},
105
106 {VME_AM_A24 |
107 MVMEBUS_AM_CAP_DATA | MVMEBUS_AM_CAP_PROG |
108 MVMEBUS_AM_CAP_SUPER | MVMEBUS_AM_CAP_USER,
109 VME_D16 | VME_D8,
110 VME1_A24D16_LOC_START,
111 VME1_A24_MASK,
112 VME1_A24D16_START,
113 VME1_A24D16_END},
114
115 {VME_AM_A32 |
116 MVMEBUS_AM_CAP_DATA | MVMEBUS_AM_CAP_PROG |
117 MVMEBUS_AM_CAP_SUPER | MVMEBUS_AM_CAP_USER,
118 VME_D16 | VME_D8,
119 VME1_A32D16_LOC_START,
120 VME1_A32_MASK,
121 VME1_A32D16_START,
122 VME1_A32D16_END},
123
124 {VME_AM_A16 |
125 MVMEBUS_AM_CAP_DATA |
126 MVMEBUS_AM_CAP_SUPER | MVMEBUS_AM_CAP_USER,
127 VME_D16 | VME_D8,
128 VME1_A16D16_LOC_START,
129 VME1_A16_MASK,
130 VME1_A16D16_START,
131 VME1_A16D16_END}
132 };
133 #define VME1_NMASTERS (sizeof(vme_pcc_masters)/sizeof(struct mvmebus_range))
134
135
136 /* ARGSUSED */
137 int
138 vme_pcc_match(parent, cf, aux)
139 struct device *parent;
140 struct cfdata *cf;
141 void *aux;
142 {
143 struct pcc_attach_args *pa;
144
145 pa = aux;
146
147 /* Only one VME chip, please. */
148 if (vme_pcc_attached)
149 return (0);
150
151 if (strcmp(pa->pa_name, vmepcc_cd.cd_name))
152 return (0);
153
154 return (1);
155 }
156
157 void
158 vme_pcc_attach(parent, self, aux)
159 struct device *parent;
160 struct device *self;
161 void *aux;
162 {
163 struct pcc_attach_args *pa;
164 struct vme_pcc_softc *sc;
165 vme_am_t am;
166 u_int8_t reg;
167
168 sc = (struct vme_pcc_softc *) self;
169 pa = aux;
170
171 /* Map the VMEchip's registers */
172 bus_space_map(pa->pa_bust, pa->pa_offset, VME1REG_SIZE, 0,
173 &sc->sc_bush);
174
175 /* Initialise stuff used by the mvme68k common VMEbus front-end */
176 sc->sc_mvmebus.sc_bust = pa->pa_bust;
177 sc->sc_mvmebus.sc_dmat = pa->pa_dmat;
178 sc->sc_mvmebus.sc_chip = sc;
179 sc->sc_mvmebus.sc_nmasters = VME1_NMASTERS;
180 sc->sc_mvmebus.sc_masters = &vme_pcc_masters[0];
181 sc->sc_mvmebus.sc_nslaves = VME1_NSLAVES;
182 sc->sc_mvmebus.sc_slaves = &sc->sc_slave[0];
183 sc->sc_mvmebus.sc_intr_establish = vme_pcc_intr_establish;
184 sc->sc_mvmebus.sc_intr_disestablish = vme_pcc_intr_disestablish;
185
186 /* Initialize the chip. */
187 reg = vme1_reg_read(sc, VME1REG_SCON) & ~VME1_SCON_SYSFAIL;
188 vme1_reg_write(sc, VME1REG_SCON, reg);
189
190 printf(": Type 1 VMEchip, scon jumper %s\n",
191 (reg & VME1_SCON_SWITCH) ? "enabled" : "disabled");
192
193 /*
194 * Adjust the start address of the first range in vme_pcc_masters[]
195 * according to how much onboard memory exists. Disable the first
196 * range if onboard memory >= 16Mb, and adjust the start of the
197 * second range (A32D32).
198 */
199 vme_pcc_masters[0].vr_vmestart = (vme_addr_t) mem_clusters[0].size;
200 if (mem_clusters[0].size >= 0x01000000) {
201 vme_pcc_masters[0].vr_am = MVMEBUS_AM_DISABLED;
202 vme_pcc_masters[1].vr_vmestart +=
203 (vme_addr_t) (mem_clusters[0].size - 0x01000000);
204 }
205
206 am = 0;
207 reg = vme1_reg_read(sc, VME1REG_SLADDRMOD);
208 if ((reg & VME1_SLMOD_DATA) != 0)
209 am |= MVMEBUS_AM_CAP_DATA;
210 if ((reg & VME1_SLMOD_PRGRM) != 0)
211 am |= MVMEBUS_AM_CAP_PROG;
212 if ((reg & VME1_SLMOD_SUPER) != 0)
213 am |= MVMEBUS_AM_CAP_SUPER;
214 if ((reg & VME1_SLMOD_USER) != 0)
215 am |= MVMEBUS_AM_CAP_USER;
216 if ((reg & VME1_SLMOD_BLOCK) != 0)
217 am |= MVMEBUS_AM_CAP_BLK;
218
219 #ifdef notyet
220 if ((reg & VME1_SLMOD_SHORT) != 0) {
221 sc->sc_slave[VME1_SLAVE_A16].vr_am = am | VME_AM_A16;
222 sc->sc_slave[VME1_SLAVE_A16].vr_mask = 0xffffu;
223 } else
224 #endif
225 sc->sc_slave[VME1_SLAVE_A16].vr_am = MVMEBUS_AM_DISABLED;
226
227 if (pcc_slave_base_addr < 0x01000000u && (reg & VME1_SLMOD_STND) != 0) {
228 sc->sc_slave[VME1_SLAVE_A24].vr_am = am | VME_AM_A24;
229 sc->sc_slave[VME1_SLAVE_A24].vr_datasize = VME_D32 |
230 VME_D16 | VME_D8;
231 sc->sc_slave[VME1_SLAVE_A24].vr_mask = 0xffffffu;
232 sc->sc_slave[VME1_SLAVE_A24].vr_locstart = 0;
233 sc->sc_slave[VME1_SLAVE_A24].vr_vmestart = pcc_slave_base_addr;
234 sc->sc_slave[VME1_SLAVE_A24].vr_vmeend = (pcc_slave_base_addr +
235 mem_clusters[0].size - 1) & 0x00ffffffu;
236 } else
237 sc->sc_slave[VME1_SLAVE_A24].vr_am = MVMEBUS_AM_DISABLED;
238
239 if ((reg & VME1_SLMOD_EXTED) != 0) {
240 sc->sc_slave[VME1_SLAVE_A32].vr_am = am | VME_AM_A32;
241 sc->sc_slave[VME1_SLAVE_A32].vr_datasize = VME_D32 |
242 VME_D16 | VME_D8;
243 sc->sc_slave[VME1_SLAVE_A32].vr_mask = 0xffffffffu;
244 sc->sc_slave[VME1_SLAVE_A32].vr_locstart = 0;
245 sc->sc_slave[VME1_SLAVE_A32].vr_vmestart = pcc_slave_base_addr;
246 sc->sc_slave[VME1_SLAVE_A32].vr_vmeend =
247 pcc_slave_base_addr + mem_clusters[0].size - 1;
248 } else
249 sc->sc_slave[VME1_SLAVE_A32].vr_am = MVMEBUS_AM_DISABLED;
250
251 vme_pcc_attached = 1;
252
253 mvmebus_attach(&sc->sc_mvmebus);
254 }
255
256 void
257 vme_pcc_intr_establish(csc, prior, level, vector, first, func, arg, evcnt)
258 void *csc;
259 int prior, level, vector, first;
260 int (*func)(void *);
261 void *arg;
262 struct evcnt *evcnt;
263 {
264 struct vme_pcc_softc *sc = csc;
265
266 if (prior != level)
267 panic("vme_pcc_intr_establish: CPU priority != VMEbus irq level");
268
269 isrlink_vectored(func, arg, prior, vector, evcnt);
270
271 if (first) {
272 evcnt_attach_dynamic(evcnt, EVCNT_TYPE_INTR,
273 isrlink_evcnt(prior), sc->sc_mvmebus.sc_dev.dv_xname,
274 mvmebus_irq_name[level]);
275
276 /*
277 * There had better not be another VMEbus master responding
278 * to this interrupt level...
279 */
280 vme1_reg_write(sc, VME1REG_IRQEN,
281 vme1_reg_read(sc, VME1REG_IRQEN) | VME1_IRQ_VME(level));
282 }
283 }
284
285 void
286 vme_pcc_intr_disestablish(csc, level, vector, last, evcnt)
287 void *csc;
288 int level, vector, last;
289 struct evcnt *evcnt;
290 {
291 struct vme_pcc_softc *sc = csc;
292
293 isrunlink_vectored(vector);
294
295 if (last) {
296 vme1_reg_write(sc, VME1REG_IRQEN,
297 vme1_reg_read(sc, VME1REG_IRQEN) & ~VME1_IRQ_VME(level));
298 evcnt_detach(evcnt);
299 }
300 }
301