xref: /netbsd-src/sys/arch/vax/vax/ka88.c (revision 23c8222edbfb0f0932d88a8351d3a0cf817dfb9e)
1 /*	$NetBSD: ka88.c,v 1.6 2003/07/15 02:15:04 lukem Exp $	*/
2 
3 /*
4  * Copyright (c) 2000 Ludd, University of Lule}, Sweden. All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. All advertising materials mentioning features or use of this software
15  *    must display the following acknowledgement:
16  *	This product includes software developed at Ludd, University of
17  *	Lule}, Sweden and its contributors.
18  * 4. The name of the author may not be used to endorse or promote products
19  *    derived from this software without specific prior written permission
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 /*
34  * KA88 specific CPU code.
35  */
36 /*
37  * TODO:
38  *	- Machine check code
39  */
40 
41 #include <sys/cdefs.h>
42 __KERNEL_RCSID(0, "$NetBSD: ka88.c,v 1.6 2003/07/15 02:15:04 lukem Exp $");
43 
44 #include "opt_multiprocessor.h"
45 
46 #include <sys/param.h>
47 #include <sys/time.h>
48 #include <sys/kernel.h>
49 #include <sys/device.h>
50 #include <sys/systm.h>
51 #include <sys/conf.h>
52 
53 #include <machine/cpu.h>
54 #include <machine/mtpr.h>
55 #include <machine/nexus.h>
56 #include <machine/clock.h>
57 #include <machine/scb.h>
58 #include <machine/bus.h>
59 #include <machine/sid.h>
60 #include <machine/rpb.h>
61 #include <machine/ka88.h>
62 
63 #include <vax/vax/gencons.h>
64 
65 #include "ioconf.h"
66 #include "locators.h"
67 
68 static void ka88_memerr(void);
69 static void ka88_conf(void);
70 static int ka88_mchk(caddr_t);
71 static void ka88_steal_pages(void);
72 static int ka88_clkread(time_t);
73 static void ka88_clkwrite(void);
74 static void ka88_badaddr(void);
75 #if defined(MULTIPROCESSOR)
76 static void ka88_startslave(struct device *, struct cpu_info *);
77 static void ka88_txrx(int, char *, int);
78 static void ka88_sendstr(int, char *);
79 static void ka88_sergeant(int);
80 static int rxchar(void);
81 static void ka88_putc(int);
82 static void ka88_cnintr(void);
83 cons_decl(gen);
84 #endif
85 
86 static	long *ka88_mcl;
87 static int mastercpu;
88 
89 struct	cpu_dep ka88_calls = {
90 	ka88_steal_pages,
91 	ka88_mchk,
92 	ka88_memerr,
93 	ka88_conf,
94 	ka88_clkread,
95 	ka88_clkwrite,
96 	6,	/* ~VUPS */
97 	64,	/* SCB pages */
98 	0,
99 	0,
100 	0,
101 	0,
102 	0,
103 #if defined(MULTIPROCESSOR)
104 	ka88_startslave,
105 #endif
106 	ka88_badaddr,
107 };
108 
109 struct ka88_softc {
110 	struct device sc_dev;
111 	int sc_slot;
112 };
113 
114 static void
115 ka88_conf(void)
116 {
117 	ka88_mcl = (void *)vax_map_physmem(0x3e000000, 1);
118 	printf("Serial number %d, rev %d\n",
119 	    mfpr(PR_SID) & 65535, (mfpr(PR_SID) >> 16) & 127);
120 }
121 
122 static int
123 ka88_match(struct device *parent, struct cfdata *cf, void *aux)
124 {
125 	struct nmi_attach_args *na = aux;
126 
127 	if (cf->cf_loc[NMICF_SLOT] != NMICF_SLOT_DEFAULT &&
128 	    cf->cf_loc[NMICF_SLOT] != na->slot)
129 		return 0;
130 	if (na->slot >= 20)
131 		return 1;
132 	return 0;
133 }
134 
135 static void
136 ka88_attach(struct device *parent, struct device *self, void *aux)
137 {
138 	struct ka88_softc *sc = (void *)self;
139 	struct nmi_attach_args *na = aux;
140 	char *ms, *lr;
141 
142 	if (((ka88_confdata & KA88_LEFTPRIM) && (na->slot == 20)) ||
143 	    ((ka88_confdata & KA88_LEFTPRIM) == 0 && (na->slot != 20)))
144 		lr = "left";
145 	else
146 		lr = "right";
147 	ms = na->slot == 20 ? "master" : "slave";
148 
149 	printf(": ka88 (%s) (%s)\n", lr, ms);
150 	sc->sc_slot = na->slot;
151 	if (na->slot != mastercpu) {
152 #if defined(MULTIPROCESSOR)
153 		sc->sc_ci = cpu_slavesetup(self);
154 		v_putc = ka88_putc;	/* Need special console handling */
155 #endif
156 		return;
157 	}
158 	curcpu()->ci_dev = self;
159 }
160 
161 CFATTACH_DECL(cpu_nmi, sizeof(struct ka88_softc),
162     ka88_match, ka88_attach, NULL, NULL);
163 
164 struct mem_nmi_softc {
165 	struct device sc_dev;
166 	bus_space_tag_t sc_iot;
167 	bus_space_handle_t sc_ioh;
168 };
169 
170 static int
171 ms88_match(struct device *parent, struct cfdata *cf, void *aux)
172 {
173 	struct nmi_attach_args *na = aux;
174 
175 	if (cf->cf_loc[NMICF_SLOT] != NMICF_SLOT_DEFAULT &&
176 	    cf->cf_loc[NMICF_SLOT] != na->slot)
177 		return 0;
178 	if (na->slot != 10)
179 		return 0;
180 	return 1;
181 }
182 
183 static void
184 ms88_attach(struct device *parent, struct device *self, void *aux)
185 {
186 	printf("\n");
187 }
188 
189 CFATTACH_DECL(mem_nmi, sizeof(struct mem_nmi_softc),
190     ms88_match, ms88_attach, NULL, NULL);
191 
192 static void
193 ka88_badaddr(void)
194 {
195 	volatile int hej;
196 	/*
197 	 * This is some magic to clear the NMI faults, described
198 	 * in section 7.9 in the VAX 8800 System Maintenance Guide.
199 	 */
200 	hej = ka88_mcl[5];
201 	hej = ka88_mcl[0];
202 	ka88_mcl[0] = 0x04000000;
203 	mtpr(1, 0x88);
204 }
205 
206 static void
207 ka88_memerr()
208 {
209 	printf("ka88_memerr\n");
210 }
211 
212 struct mc88frame {
213 	int	mc64_summary;		/* summary parameter */
214 	int	mc64_va;		/* va register */
215 	int	mc64_vb;		/* memory address */
216 	int	mc64_sisr;		/* status word */
217 	int	mc64_state;		/* error pc */
218 	int	mc64_sc;		/* micro pc */
219 	int	mc64_pc;		/* current pc */
220 	int	mc64_psl;		/* current psl */
221 };
222 
223 static int
224 ka88_mchk(caddr_t cmcf)
225 {
226 	return (MCHK_PANIC);
227 }
228 
229 #if defined(MULTIPROCESSOR)
230 #define RXBUF	80
231 static char rxbuf[RXBUF];
232 static int got = 0, taken = 0;
233 static int expect = 0;
234 #endif
235 #if 0
236 /*
237  * Receive a character from logical console.
238  */
239 static void
240 rxcdintr(void *arg)
241 {
242 	int c = mfpr(PR_RXCD);
243 
244 	if (c == 0)
245 		return;
246 
247 #if defined(MULTIPROCESSOR)
248 	if ((c & 0xff) == 0) {
249 		if (curcpu()->ci_flags & CI_MASTERCPU)
250 			ka88_cnintr();
251 		return;
252 	}
253 
254 	if (expect == ((c >> 8) & 0xf))
255 		rxbuf[got++] = c & 0xff;
256 
257 	if (got == RXBUF)
258 		got = 0;
259 #endif
260 }
261 #endif
262 
263 static void
264 tocons(int val)
265 {
266 	int s = splhigh();
267 
268 	while ((mfpr(PR_TXCS) & GC_RDY) == 0)  /* Wait until xmit ready */
269 		;
270 	mtpr(val, PR_TXDB);		/* xmit character */
271 	splx(s);
272 }
273 
274 static int
275 fromcons(int func)
276 {
277 	int ret, s = splhigh();
278 
279 	while (1) {
280 		while ((mfpr(PR_RXCS) & GC_DON) == 0)
281 			;
282 		ret = mfpr(PR_RXDB);
283 		if ((ret & 0xf00) == func)
284 			break;
285 	}
286 	splx(s);
287 	return ret;
288 }
289 
290 static int
291 ka88_clkread(time_t base)
292 {
293 	union {u_int ret;u_char r[4];} u;
294 	int i, s = splhigh();
295 
296 	tocons(KA88_COMM|KA88_TOYREAD);
297 	for (i = 0; i < 4; i++) {
298 		u.r[i] = fromcons(KA88_TOY) & 255;
299 	}
300 	splx(s);
301 	return u.ret;
302 }
303 
304 static void
305 ka88_clkwrite(void)
306 {
307 	union {u_int ret;u_char r[4];} u;
308 	int i, s = splhigh();
309 
310 	u.ret = time.tv_sec - yeartonum(numtoyear(time.tv_sec));
311 	tocons(KA88_COMM|KA88_TOYWRITE);
312 	for (i = 0; i < 4; i++)
313 		tocons(KA88_TOY|u.r[i]);
314 	splx(s);
315 }
316 
317 void
318 ka88_steal_pages(void)
319 {
320 	mtpr(1, PR_COR); /* Cache on */
321 	strcpy(cpu_model, "VAX 8800");
322 	tocons(KA88_COMM|KA88_GETCONF);
323 	ka88_confdata = fromcons(KA88_CONFDATA);
324 	ka88_confdata = mfpr(PR_RXDB);
325 	mastercpu = 20;
326 	if (vax_cputype == VAX_TYP_8NN) {
327 		if (ka88_confdata & KA88_SMALL) {
328 			cpu_model[5] = '5';
329 			if (ka88_confdata & KA88_SLOW) {
330 				vax_boardtype = VAX_BTYP_8500;
331 				cpu_model[6] = '3';
332 			} else {
333 				vax_boardtype = VAX_BTYP_8550;
334 				cpu_model[6] = '5';
335 			}
336 		} else if (ka88_confdata & KA88_SINGLE) {
337 			vax_boardtype = VAX_BTYP_8700;
338 			cpu_model[5] = '7';
339 		}
340 	}
341 }
342 
343 
344 #if defined(MULTIPROCESSOR) && 0
345 int
346 rxchar()
347 {
348 	int ret;
349 
350 	if (got == taken)
351 		return 0;
352 
353 	ret = rxbuf[taken++];
354 	if (taken == RXBUF)
355 		taken = 0;
356 	return ret;
357 }
358 
359 static void
360 ka88_startslave(struct device *dev, struct cpu_info *ci)
361 {
362 	struct ka88_softc *sc = (void *)dev;
363 	int id = sc->sc_binid;
364 	int i;
365 
366 	expect = sc->sc_binid;
367 	/* First empty queue */
368 	for (i = 0; i < 10000; i++)
369 		if (rxchar())
370 			i = 0;
371 	ka88_txrx(id, "\020", 0);		/* Send ^P to get attention */
372 	ka88_txrx(id, "I\r", 0);			/* Init other end */
373 	ka88_txrx(id, "D/I 4 %x\r", ci->ci_istack);	/* Interrupt stack */
374 	ka88_txrx(id, "D/I C %x\r", mfpr(PR_SBR));	/* SBR */
375 	ka88_txrx(id, "D/I D %x\r", mfpr(PR_SLR));	/* SLR */
376 	ka88_txrx(id, "D/I 10 %x\r", (int)ci->ci_pcb);	/* PCB for idle proc */
377 	ka88_txrx(id, "D/I 11 %x\r", mfpr(PR_SCBB));	/* SCB */
378 	ka88_txrx(id, "D/I 38 %x\r", mfpr(PR_MAPEN)); /* Enable MM */
379 	ka88_txrx(id, "S %x\r", (int)&tramp); /* Start! */
380 	expect = 0;
381 	for (i = 0; i < 10000; i++)
382 		if ((volatile)ci->ci_flags & CI_RUNNING)
383 			break;
384 	if (i == 10000)
385 		printf("%s: (ID %d) failed starting??!!??\n",
386 		    dev->dv_xname, sc->sc_binid);
387 }
388 
389 void
390 ka88_txrx(int id, char *fmt, int arg)
391 {
392 	char buf[20];
393 
394 	sprintf(buf, fmt, arg);
395 	ka88_sendstr(id, buf);
396 	ka88_sergeant(id);
397 }
398 
399 void
400 ka88_sendstr(int id, char *buf)
401 {
402 	register u_int utchr; /* Ends up in R11 with PCC */
403 	int ch, i;
404 
405 	while (*buf) {
406 		utchr = *buf | id << 8;
407 
408 		/*
409 		 * It seems like mtpr to TXCD sets the V flag if it fails.
410 		 * Cannot check that flag in C...
411 		 */
412 #ifdef __GNUC__
413 		asm("1:;mtpr %0,$92;bvs 1b" :: "g"(utchr));
414 #else
415 		asm("1:;mtpr r11,$92;bvs 1b");
416 #endif
417 		buf++;
418 		i = 30000;
419 		while ((ch = rxchar()) == 0 && --i)
420 			;
421 		if (ch == 0)
422 			continue; /* failed */
423 	}
424 }
425 
426 void
427 ka88_sergeant(int id)
428 {
429 	int i, ch, nserg;
430 
431 	nserg = 0;
432 	for (i = 0; i < 30000; i++) {
433 		if ((ch = rxchar()) == 0)
434 			continue;
435 		if (ch == '>')
436 			nserg++;
437 		else
438 			nserg = 0;
439 		i = 0;
440 		if (nserg == 3)
441 			break;
442 	}
443 	/* What to do now??? */
444 }
445 
446 /*
447  * Write to master console.
448  * Need no locking here; done in the print functions.
449  */
450 static volatile int ch = 0;
451 
452 void
453 ka88_putc(int c)
454 {
455 	if (curcpu()->ci_flags & CI_MASTERCPU) {
456 		gencnputc(0, c);
457 		return;
458 	}
459 	ch = c;
460 	mtpr(mastercpu << 8, PR_RXCD); /* Send IPI to mastercpu */
461 	while (ch != 0)
462 		; /* Wait for master to handle */
463 }
464 
465 /*
466  * Got character IPI.
467  */
468 void
469 ka88_cnintr()
470 {
471 	if (ch != 0)
472 		gencnputc(0, ch);
473 	ch = 0; /* Release slavecpu */
474 }
475 #endif
476