xref: /netbsd/sys/arch/vax/vax/ka88.c (revision c4a72b64)
1 /*	$NetBSD: ka88.c,v 1.5 2002/10/02 16:02:36 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 CFATTACH_DECL(cpu_nmi, sizeof(struct ka88_softc),
159     ka88_match, ka88_attach, NULL, NULL);
160 
161 struct mem_nmi_softc {
162 	struct device sc_dev;
163 	bus_space_tag_t sc_iot;
164 	bus_space_handle_t sc_ioh;
165 };
166 
167 static int
168 ms88_match(struct device *parent, struct cfdata *cf, void *aux)
169 {
170 	struct nmi_attach_args *na = aux;
171 
172 	if (cf->cf_loc[NMICF_SLOT] != NMICF_SLOT_DEFAULT &&
173 	    cf->cf_loc[NMICF_SLOT] != na->slot)
174 		return 0;
175 	if (na->slot != 10)
176 		return 0;
177 	return 1;
178 }
179 
180 static void
181 ms88_attach(struct device *parent, struct device *self, void *aux)
182 {
183 	printf("\n");
184 }
185 
186 CFATTACH_DECL(mem_nmi, sizeof(struct mem_nmi_softc),
187     ms88_match, ms88_attach, NULL, NULL);
188 
189 static void
190 ka88_badaddr(void)
191 {
192 	volatile int hej;
193 	/*
194 	 * This is some magic to clear the NMI faults, described
195 	 * in section 7.9 in the VAX 8800 System Maintenance Guide.
196 	 */
197 	hej = ka88_mcl[5];
198 	hej = ka88_mcl[0];
199 	ka88_mcl[0] = 0x04000000;
200 	mtpr(1, 0x88);
201 }
202 
203 static void
204 ka88_memerr()
205 {
206 	printf("ka88_memerr\n");
207 }
208 
209 struct mc88frame {
210 	int	mc64_summary;		/* summary parameter */
211 	int	mc64_va;		/* va register */
212 	int	mc64_vb;		/* memory address */
213 	int	mc64_sisr;		/* status word */
214 	int	mc64_state;		/* error pc */
215 	int	mc64_sc;		/* micro pc */
216 	int	mc64_pc;		/* current pc */
217 	int	mc64_psl;		/* current psl */
218 };
219 
220 static int
221 ka88_mchk(caddr_t cmcf)
222 {
223 	return (MCHK_PANIC);
224 }
225 
226 #if defined(MULTIPROCESSOR)
227 #define RXBUF	80
228 static char rxbuf[RXBUF];
229 static int got = 0, taken = 0;
230 static int expect = 0;
231 #endif
232 #if 0
233 /*
234  * Receive a character from logical console.
235  */
236 static void
237 rxcdintr(void *arg)
238 {
239 	int c = mfpr(PR_RXCD);
240 
241 	if (c == 0)
242 		return;
243 
244 #if defined(MULTIPROCESSOR)
245 	if ((c & 0xff) == 0) {
246 		if (curcpu()->ci_flags & CI_MASTERCPU)
247 			ka88_cnintr();
248 		return;
249 	}
250 
251 	if (expect == ((c >> 8) & 0xf))
252 		rxbuf[got++] = c & 0xff;
253 
254 	if (got == RXBUF)
255 		got = 0;
256 #endif
257 }
258 #endif
259 
260 static void
261 tocons(int val)
262 {
263 	int s = splhigh();
264 
265 	while ((mfpr(PR_TXCS) & GC_RDY) == 0)  /* Wait until xmit ready */
266 		;
267 	mtpr(val, PR_TXDB);		/* xmit character */
268 	splx(s);
269 }
270 
271 static int
272 fromcons(int func)
273 {
274 	int ret, s = splhigh();
275 
276 	while (1) {
277 		while ((mfpr(PR_RXCS) & GC_DON) == 0)
278 			;
279 		ret = mfpr(PR_RXDB);
280 		if ((ret & 0xf00) == func)
281 			break;
282 	}
283 	splx(s);
284 	return ret;
285 }
286 
287 static int
288 ka88_clkread(time_t base)
289 {
290 	union {u_int ret;u_char r[4];} u;
291 	int i, s = splhigh();
292 
293 	tocons(KA88_COMM|KA88_TOYREAD);
294 	for (i = 0; i < 4; i++) {
295 		u.r[i] = fromcons(KA88_TOY) & 255;
296 	}
297 	splx(s);
298 	return u.ret;
299 }
300 
301 static void
302 ka88_clkwrite(void)
303 {
304 	union {u_int ret;u_char r[4];} u;
305 	int i, s = splhigh();
306 
307 	u.ret = time.tv_sec - yeartonum(numtoyear(time.tv_sec));
308 	tocons(KA88_COMM|KA88_TOYWRITE);
309 	for (i = 0; i < 4; i++)
310 		tocons(KA88_TOY|u.r[i]);
311 	splx(s);
312 }
313 
314 void
315 ka88_steal_pages(void)
316 {
317 	mtpr(1, PR_COR); /* Cache on */
318 	strcpy(cpu_model, "VAX 8800");
319 	tocons(KA88_COMM|KA88_GETCONF);
320 	ka88_confdata = fromcons(KA88_CONFDATA);
321 	ka88_confdata = mfpr(PR_RXDB);
322 	mastercpu = 20;
323 	if (vax_cputype == VAX_TYP_8NN) {
324 		if (ka88_confdata & KA88_SMALL) {
325 			cpu_model[5] = '5';
326 			if (ka88_confdata & KA88_SLOW) {
327 				vax_boardtype = VAX_BTYP_8500;
328 				cpu_model[6] = '3';
329 			} else {
330 				vax_boardtype = VAX_BTYP_8550;
331 				cpu_model[6] = '5';
332 			}
333 		} else if (ka88_confdata & KA88_SINGLE) {
334 			vax_boardtype = VAX_BTYP_8700;
335 			cpu_model[5] = '7';
336 		}
337 	}
338 }
339 
340 
341 #if defined(MULTIPROCESSOR) && 0
342 int
343 rxchar()
344 {
345 	int ret;
346 
347 	if (got == taken)
348 		return 0;
349 
350 	ret = rxbuf[taken++];
351 	if (taken == RXBUF)
352 		taken = 0;
353 	return ret;
354 }
355 
356 static void
357 ka88_startslave(struct device *dev, struct cpu_info *ci)
358 {
359 	struct ka88_softc *sc = (void *)dev;
360 	int id = sc->sc_binid;
361 	int i;
362 
363 	expect = sc->sc_binid;
364 	/* First empty queue */
365 	for (i = 0; i < 10000; i++)
366 		if (rxchar())
367 			i = 0;
368 	ka88_txrx(id, "\020", 0);		/* Send ^P to get attention */
369 	ka88_txrx(id, "I\r", 0);			/* Init other end */
370 	ka88_txrx(id, "D/I 4 %x\r", ci->ci_istack);	/* Interrupt stack */
371 	ka88_txrx(id, "D/I C %x\r", mfpr(PR_SBR));	/* SBR */
372 	ka88_txrx(id, "D/I D %x\r", mfpr(PR_SLR));	/* SLR */
373 	ka88_txrx(id, "D/I 10 %x\r", (int)ci->ci_pcb);	/* PCB for idle proc */
374 	ka88_txrx(id, "D/I 11 %x\r", mfpr(PR_SCBB));	/* SCB */
375 	ka88_txrx(id, "D/I 38 %x\r", mfpr(PR_MAPEN)); /* Enable MM */
376 	ka88_txrx(id, "S %x\r", (int)&tramp); /* Start! */
377 	expect = 0;
378 	for (i = 0; i < 10000; i++)
379 		if ((volatile)ci->ci_flags & CI_RUNNING)
380 			break;
381 	if (i == 10000)
382 		printf("%s: (ID %d) failed starting??!!??\n",
383 		    dev->dv_xname, sc->sc_binid);
384 }
385 
386 void
387 ka88_txrx(int id, char *fmt, int arg)
388 {
389 	char buf[20];
390 
391 	sprintf(buf, fmt, arg);
392 	ka88_sendstr(id, buf);
393 	ka88_sergeant(id);
394 }
395 
396 void
397 ka88_sendstr(int id, char *buf)
398 {
399 	register u_int utchr; /* Ends up in R11 with PCC */
400 	int ch, i;
401 
402 	while (*buf) {
403 		utchr = *buf | id << 8;
404 
405 		/*
406 		 * It seems like mtpr to TXCD sets the V flag if it fails.
407 		 * Cannot check that flag in C...
408 		 */
409 #ifdef __GNUC__
410 		asm("1:;mtpr %0,$92;bvs 1b" :: "g"(utchr));
411 #else
412 		asm("1:;mtpr r11,$92;bvs 1b");
413 #endif
414 		buf++;
415 		i = 30000;
416 		while ((ch = rxchar()) == 0 && --i)
417 			;
418 		if (ch == 0)
419 			continue; /* failed */
420 	}
421 }
422 
423 void
424 ka88_sergeant(int id)
425 {
426 	int i, ch, nserg;
427 
428 	nserg = 0;
429 	for (i = 0; i < 30000; i++) {
430 		if ((ch = rxchar()) == 0)
431 			continue;
432 		if (ch == '>')
433 			nserg++;
434 		else
435 			nserg = 0;
436 		i = 0;
437 		if (nserg == 3)
438 			break;
439 	}
440 	/* What to do now??? */
441 }
442 
443 /*
444  * Write to master console.
445  * Need no locking here; done in the print functions.
446  */
447 static volatile int ch = 0;
448 
449 void
450 ka88_putc(int c)
451 {
452 	if (curcpu()->ci_flags & CI_MASTERCPU) {
453 		gencnputc(0, c);
454 		return;
455 	}
456 	ch = c;
457 	mtpr(mastercpu << 8, PR_RXCD); /* Send IPI to mastercpu */
458 	while (ch != 0)
459 		; /* Wait for master to handle */
460 }
461 
462 /*
463  * Got character IPI.
464  */
465 void
466 ka88_cnintr()
467 {
468 	if (ch != 0)
469 		gencnputc(0, ch);
470 	ch = 0; /* Release slavecpu */
471 }
472 #endif
473