pcc.c revision 1.9 1 /* $NetBSD: pcc.c,v 1.9 1997/03/19 16:24:40 gwr Exp $ */
2
3 /*
4 * Copyright (c) 1996 Jason R. Thorpe
5 * Copyright (c) 1995 Charles D. Cranor
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by Charles D. Cranor.
19 * 4. The name of the author may not be used to endorse or promote products
20 * derived from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33
34 /*
35 * peripheral channel controller
36 */
37
38 #include <sys/param.h>
39 #include <sys/conf.h>
40 #include <sys/ioctl.h>
41 #include <sys/proc.h>
42 #include <sys/user.h>
43 #include <sys/tty.h>
44 #include <sys/uio.h>
45 #include <sys/callout.h>
46 #include <sys/systm.h>
47 #include <sys/kernel.h>
48 #include <sys/syslog.h>
49 #include <sys/fcntl.h>
50 #include <sys/device.h>
51 #include <machine/cpu.h>
52 #include <dev/cons.h>
53
54 #include <mvme68k/mvme68k/isr.h>
55
56 #include <mvme68k/dev/pccreg.h>
57 #include <mvme68k/dev/pccvar.h>
58
59 /*
60 * Autoconfiguration stuff.
61 */
62
63 struct pccsoftc {
64 struct device sc_dev;
65 struct pcc *sc_pcc;
66 };
67
68 void pccattach __P((struct device *, struct device *, void *));
69 int pccmatch __P((struct device *, struct cfdata *, void *));
70 int pccprint __P((void *, const char *));
71
72 struct cfattach pcc_ca = {
73 sizeof(struct pccsoftc), pccmatch, pccattach
74 };
75
76 struct cfdriver pcc_cd = {
77 NULL, "pcc", DV_DULL, 0
78 };
79
80 int pccintr __P((void *));
81
82 /*
83 * globals
84 */
85
86 struct pcc *sys_pcc = NULL;
87
88 /*
89 * Devices that live on the PCC, attached in this order.
90 */
91 struct pcc_device pcc_devices[] = {
92 { "clock", PCC_CLOCK_OFF, 1 },
93 { "zsc", PCC_ZS0_OFF, 1 },
94 { "zsc", PCC_ZS1_OFF, 1 },
95 { "le", PCC_LE_OFF, 2 },
96 { "wdsc", PCC_WDSC_OFF, 1 },
97 { "lpt", PCC_LPT_OFF, 1 },
98 { "vmechip", PCC_VME_OFF, 2 },
99 { NULL, 0, 0 },
100 };
101
102 int
103 pccmatch(parent, cf, args)
104 struct device *parent;
105 struct cfdata *cf;
106 void *args;
107 {
108 char *ma_name = args;
109
110 /* Only attach one PCC. */
111 if (sys_pcc)
112 return (0);
113
114 return (strcmp(ma_name, pcc_cd.cd_name) == 0);
115 }
116
117 void
118 pccattach(parent, self, args)
119 struct device *parent, *self;
120 void *args;
121 {
122 struct pccsoftc *pccsc;
123 struct pcc_attach_args npa;
124 caddr_t kva;
125 int i;
126
127 if (sys_pcc)
128 panic("pccattach: pcc already attached!");
129
130 sys_pcc = (struct pcc *)PCC_VADDR(PCC_REG_OFF);
131
132 /*
133 * link into softc and set up interrupt vector base,
134 * and initialize the chip.
135 */
136 pccsc = (struct pccsoftc *) self;
137 pccsc->sc_pcc = sys_pcc;
138 pccsc->sc_pcc->int_vectr = PCC_VECBASE;
139
140 printf(": Peripheral Channel Controller, "
141 "rev %d, vecbase 0x%x\n", pccsc->sc_pcc->pcc_rev,
142 pccsc->sc_pcc->int_vectr);
143
144 /* Hook up interrupt handler for abort button. */
145 pccintr_establish(PCCV_ABORT, pccintr, 7, NULL);
146
147 /*
148 * Now that the interrupt handler has been established,
149 * enable the ABORT switch interrupt.
150 */
151 pccsc->sc_pcc->abrt_int = PCC_ABORT_IEN | PCC_ABORT_ACK;
152
153 /* Make sure the global interrupt line is hot. */
154 pccsc->sc_pcc->gen_cr |= PCC_GENCR_IEN;
155
156 /*
157 * Attach configured children.
158 */
159 for (i = 0; pcc_devices[i].pcc_name != NULL; ++i) {
160 /*
161 * Note that IPL is filled in by match function.
162 */
163 npa.pa_name = pcc_devices[i].pcc_name;
164 npa.pa_offset = pcc_devices[i].pcc_offset;
165 npa.pa_ipl = -1;
166
167 /* Check for hardware. (XXX is this really necessary?) */
168 kva = PCC_VADDR(npa.pa_offset);
169 if (badaddr(kva, pcc_devices[i].pcc_bytes)) {
170 /*
171 * Hardware not present.
172 */
173 continue;
174 }
175
176 /* Attach the device if configured. */
177 (void)config_found(self, &npa, pccprint);
178 }
179 }
180
181 int
182 pccprint(aux, cp)
183 void *aux;
184 const char *cp;
185 {
186 struct pcc_attach_args *pa = aux;
187
188 if (cp)
189 printf("%s at %s", pa->pa_name, cp);
190
191 printf(" offset 0x%lx", pa->pa_offset);
192 if (pa->pa_ipl != -1)
193 printf(" ipl %d", pa->pa_ipl);
194
195 return (UNCONF);
196 }
197
198 /*
199 * pccintr_establish: establish pcc interrupt
200 */
201 void
202 pccintr_establish(pccvec, hand, lvl, arg)
203 int pccvec;
204 int (*hand) __P((void *)), lvl;
205 void *arg;
206 {
207
208 if ((pccvec < 0) || (pccvec >= PCC_NVEC)) {
209 printf("pcc: illegal vector offset: 0x%x\n", pccvec);
210 panic("pccintr_establish");
211 }
212
213 if ((lvl < 1) || (lvl > 7)) {
214 printf("pcc: illegal interrupt level: %d\n", lvl);
215 panic("pccintr_establish");
216 }
217
218 isrlink_vectored(hand, arg, lvl, pccvec + PCC_VECBASE);
219 }
220
221 void
222 pccintr_disestablish(pccvec)
223 int pccvec;
224 {
225
226 if ((pccvec < 0) || (pccvec >= PCC_NVEC)) {
227 printf("pcc: illegal vector offset: 0x%x\n", pccvec);
228 panic("pccintr_establish");
229 }
230
231 isrunlink_vectored(pccvec + PCC_VECBASE);
232 }
233
234 /*
235 * Handle NMI from abort switch.
236 */
237 int
238 pccintr(frame)
239 void *frame;
240 {
241
242 /* XXX wait until button pops out */
243 sys_pcc->abrt_int = PCC_ABORT_IEN | PCC_ABORT_ACK;
244 nmihand((struct frame *)frame);
245 return (1);
246 }
247