xref: /netbsd-src/sys/arch/vax/vax/ka88.c (revision 8b0f9554ff8762542c4defc4f70e1eb76fb508fa)
1 /*	$NetBSD: ka88.c,v 1.11 2007/03/04 06:01:01 christos 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.11 2007/03/04 06:01:01 christos 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(void *);
71 static void ka88_steal_pages(void);
72 static int ka88_gettime(volatile struct timeval *);
73 static void ka88_settime(volatile struct timeval *);
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, const char *, int);
78 static void ka88_sendstr(int, const 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_gettime,
95 	ka88_settime,
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(void *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_gettime(volatile struct timeval *tvp)
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 	tvp->tv_sec = u.ret;
302 	return 0;
303 }
304 
305 static void
306 ka88_settime(volatile struct timeval *tvp)
307 {
308 	union {u_int ret;u_char r[4];} u;
309 	int i, s = splhigh();
310 
311 	u.ret = tvp->tv_sec - yeartonum(numtoyear(tvp->tv_sec));
312 	tocons(KA88_COMM|KA88_TOYWRITE);
313 	for (i = 0; i < 4; i++)
314 		tocons(KA88_TOY|u.r[i]);
315 	splx(s);
316 }
317 
318 void
319 ka88_steal_pages(void)
320 {
321 	mtpr(1, PR_COR); /* Cache on */
322 	strcpy(cpu_model, "VAX 8800");
323 	tocons(KA88_COMM|KA88_GETCONF);
324 	ka88_confdata = fromcons(KA88_CONFDATA);
325 	ka88_confdata = mfpr(PR_RXDB);
326 	mastercpu = 20;
327 	if (vax_cputype == VAX_TYP_8NN) {
328 		if (ka88_confdata & KA88_SMALL) {
329 			cpu_model[5] = '5';
330 			if (ka88_confdata & KA88_SLOW) {
331 				vax_boardtype = VAX_BTYP_8500;
332 				cpu_model[6] = '3';
333 			} else {
334 				vax_boardtype = VAX_BTYP_8550;
335 				cpu_model[6] = '5';
336 			}
337 		} else if (ka88_confdata & KA88_SINGLE) {
338 			vax_boardtype = VAX_BTYP_8700;
339 			cpu_model[5] = '7';
340 		}
341 	}
342 }
343 
344 
345 #if defined(MULTIPROCESSOR) && 0
346 int
347 rxchar()
348 {
349 	int ret;
350 
351 	if (got == taken)
352 		return 0;
353 
354 	ret = rxbuf[taken++];
355 	if (taken == RXBUF)
356 		taken = 0;
357 	return ret;
358 }
359 
360 static void
361 ka88_startslave(struct device *dev, struct cpu_info *ci)
362 {
363 	struct ka88_softc *sc = (void *)dev;
364 	int id = sc->sc_binid;
365 	int i;
366 
367 	expect = sc->sc_binid;
368 	/* First empty queue */
369 	for (i = 0; i < 10000; i++)
370 		if (rxchar())
371 			i = 0;
372 	ka88_txrx(id, "\020", 0);		/* Send ^P to get attention */
373 	ka88_txrx(id, "I\r", 0);			/* Init other end */
374 	ka88_txrx(id, "D/I 4 %x\r", ci->ci_istack);	/* Interrupt stack */
375 	ka88_txrx(id, "D/I C %x\r", mfpr(PR_SBR));	/* SBR */
376 	ka88_txrx(id, "D/I D %x\r", mfpr(PR_SLR));	/* SLR */
377 	ka88_txrx(id, "D/I 10 %x\r", (int)ci->ci_pcb);	/* PCB for idle proc */
378 	ka88_txrx(id, "D/I 11 %x\r", mfpr(PR_SCBB));	/* SCB */
379 	ka88_txrx(id, "D/I 38 %x\r", mfpr(PR_MAPEN)); /* Enable MM */
380 	ka88_txrx(id, "S %x\r", (int)&vax_mp_tramp); /* Start! */
381 	expect = 0;
382 	for (i = 0; i < 10000; i++)
383 		if ((volatile)ci->ci_flags & CI_RUNNING)
384 			break;
385 	if (i == 10000)
386 		printf("%s: (ID %d) failed starting??!!??\n",
387 		    dev->dv_xname, sc->sc_binid);
388 }
389 
390 void
391 ka88_txrx(int id, const char *fmt, int arg)
392 {
393 	char buf[20];
394 
395 	sprintf(buf, fmt, arg);
396 	ka88_sendstr(id, buf);
397 	ka88_sergeant(id);
398 }
399 
400 void
401 ka88_sendstr(int id, const char *buf)
402 {
403 	register u_int utchr; /* Ends up in R11 with PCC */
404 	int ch, i;
405 
406 	while (*buf) {
407 		utchr = *buf | id << 8;
408 
409 		/*
410 		 * It seems like mtpr to TXCD sets the V flag if it fails.
411 		 * Cannot check that flag in C...
412 		 */
413 #ifdef __GNUC__
414 		__asm("1:;mtpr %0,$92;bvs 1b" :: "g"(utchr));
415 #else
416 		__asm("1:;mtpr r11,$92;bvs 1b");
417 #endif
418 		buf++;
419 		i = 30000;
420 		while ((ch = rxchar()) == 0 && --i)
421 			;
422 		if (ch == 0)
423 			continue; /* failed */
424 	}
425 }
426 
427 void
428 ka88_sergeant(int id)
429 {
430 	int i, ch, nserg;
431 
432 	nserg = 0;
433 	for (i = 0; i < 30000; i++) {
434 		if ((ch = rxchar()) == 0)
435 			continue;
436 		if (ch == '>')
437 			nserg++;
438 		else
439 			nserg = 0;
440 		i = 0;
441 		if (nserg == 3)
442 			break;
443 	}
444 	/* What to do now??? */
445 }
446 
447 /*
448  * Write to master console.
449  * Need no locking here; done in the print functions.
450  */
451 static volatile int ch = 0;
452 
453 void
454 ka88_putc(int c)
455 {
456 	if (curcpu()->ci_flags & CI_MASTERCPU) {
457 		gencnputc(0, c);
458 		return;
459 	}
460 	ch = c;
461 	mtpr(mastercpu << 8, PR_RXCD); /* Send IPI to mastercpu */
462 	while (ch != 0)
463 		; /* Wait for master to handle */
464 }
465 
466 /*
467  * Got character IPI.
468  */
469 void
470 ka88_cnintr()
471 {
472 	if (ch != 0)
473 		gencnputc(0, ch);
474 	ch = 0; /* Release slavecpu */
475 }
476 #endif
477