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