pcc.c revision 1.5 1 /* $NetBSD: pcc.c,v 1.5 1996/08/27 21:56:18 cgd 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 *, void *, 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, vcf, args)
104 struct device *parent;
105 void *vcf, *args;
106 {
107 char *ma_name = args;
108
109 /* Only attach one PCC. */
110 if (sys_pcc)
111 return (0);
112
113 return (strcmp(ma_name, pcc_cd.cd_name) == 0);
114 }
115
116 void
117 pccattach(parent, self, args)
118 struct device *parent, *self;
119 void *args;
120 {
121 struct pccsoftc *pccsc;
122 struct pcc_attach_args npa;
123 caddr_t kva;
124 int i, error;
125
126 if (sys_pcc)
127 panic("pccattach: pcc already attached!");
128
129 sys_pcc = (struct pcc *)PCC_VADDR(PCC_REG_OFF);
130
131 /*
132 * link into softc and set up interrupt vector base,
133 * and initialize the chip.
134 */
135 pccsc = (struct pccsoftc *) self;
136 pccsc->sc_pcc = sys_pcc;
137 pccsc->sc_pcc->int_vectr = PCC_VECBASE;
138
139 printf(": Peripheral Channel Controller, "
140 "rev %d, vecbase 0x%x\n", pccsc->sc_pcc->pcc_rev,
141 pccsc->sc_pcc->int_vectr);
142
143 /* Hook up interrupt handler for abort button. */
144 pccintr_establish(PCCV_ABORT, pccintr, 7, NULL);
145
146 /*
147 * Now that the interrupt handler has been established,
148 * enable the ABORT switch interrupt.
149 */
150 pccsc->sc_pcc->abrt_int = PCC_ABORT_IEN | PCC_ABORT_ACK;
151
152 /* Make sure the global interrupt line is hot. */
153 pccsc->sc_pcc->gen_cr |= PCC_GENCR_IEN;
154
155 /*
156 * Attach configured children.
157 */
158 for (i = 0; pcc_devices[i].pcc_name != NULL; ++i) {
159 /*
160 * Note that IPL is filled in by match function.
161 */
162 npa.pa_name = pcc_devices[i].pcc_name;
163 npa.pa_offset = pcc_devices[i].pcc_offset;
164 npa.pa_ipl = -1;
165
166 /* Check for hardware. (XXX is this really necessary?) */
167 kva = PCC_VADDR(npa.pa_offset);
168 /* XXX should change interface to badaddr() */
169 switch (pcc_devices[i].pcc_bytes) {
170 case 1:
171 error = badbaddr(kva);
172 break;
173
174 case 2:
175 error = badaddr(kva);
176 break;
177
178 default:
179 panic("pccattach: bad probe size");
180 }
181 if (error) {
182 /*
183 * Hardware not present.
184 */
185 continue;
186 }
187
188 /* Attach the device if configured. */
189 (void)config_found(self, &npa, pccprint);
190 }
191 }
192
193 int
194 pccprint(aux, cp)
195 void *aux;
196 const char *cp;
197 {
198 struct pcc_attach_args *pa = aux;
199
200 if (cp)
201 printf("%s at %s", pa->pa_name, cp);
202
203 printf(" offset 0x%lx", pa->pa_offset);
204 if (pa->pa_ipl != -1)
205 printf(" ipl %d", pa->pa_ipl);
206
207 return (UNCONF);
208 }
209
210 /*
211 * pccintr_establish: establish pcc interrupt
212 */
213 void
214 pccintr_establish(pccvec, hand, lvl, arg)
215 int pccvec;
216 int (*hand) __P((void *)), lvl;
217 void *arg;
218 {
219
220 if ((pccvec < 0) || (pccvec >= PCC_NVEC)) {
221 printf("pcc: illegal vector offset: 0x%x\n", pccvec);
222 panic("pccintr_establish");
223 }
224
225 if ((lvl < 1) || (lvl > 7)) {
226 printf("pcc: illegal interrupt level: %d\n", lvl);
227 panic("pccintr_establish");
228 }
229
230 isrlink_vectored(hand, arg, lvl, pccvec + PCC_VECBASE);
231 }
232
233 void
234 pccintr_disestablish(pccvec)
235 int pccvec;
236 {
237
238 if ((pccvec < 0) || (pccvec >= PCC_NVEC)) {
239 printf("pcc: illegal vector offset: 0x%x\n", pccvec);
240 panic("pccintr_establish");
241 }
242
243 isrunlink_vectored(pccvec + PCC_VECBASE);
244 }
245
246 /*
247 * Handle NMI from abort switch.
248 */
249 int
250 pccintr(frame)
251 void *frame;
252 {
253
254 /* XXX wait until button pops out */
255 sys_pcc->abrt_int = PCC_ABORT_IEN | PCC_ABORT_ACK;
256 nmihand((struct frame *)frame);
257 return (1);
258 }
259