xref: /netbsd/sys/arch/vax/vax/ka6400.c (revision bf9ec67e)
1 /*	$NetBSD: ka6400.c,v 1.1 2000/07/06 17:40:00 ragge 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  * KA6400 specific CPU code.
35  */
36 /*
37  * TODO:
38  *	- Machine check code
39  *	- Vector processor code
40  */
41 
42 #include "opt_multiprocessor.h"
43 
44 #include <sys/param.h>
45 #include <sys/time.h>
46 #include <sys/kernel.h>
47 #include <sys/device.h>
48 #include <sys/systm.h>
49 #include <sys/conf.h>
50 
51 #include <machine/ka670.h>
52 #include <machine/cpu.h>
53 #include <machine/mtpr.h>
54 #include <machine/nexus.h>
55 #include <machine/clock.h>
56 #include <machine/scb.h>
57 #include <machine/bus.h>
58 #include <machine/sid.h>
59 #include <machine/cca.h>
60 #include <machine/rpb.h>
61 
62 #include <dev/xmi/xmireg.h>
63 #include <dev/xmi/xmivar.h>
64 
65 #include "ioconf.h"
66 #include "locators.h"
67 
68 static int *rssc;
69 struct cca *cca;
70 
71 static int ka6400_match(struct device *, struct cfdata *, void *);
72 static void ka6400_attach(struct device *, struct device *, void*);
73 static void ka6400_memerr(void);
74 static void ka6400_conf(void);
75 static int ka6400_mchk(caddr_t);
76 static void ka6400_steal_pages(void);
77 #if defined(MULTIPROCESSOR)
78 static void ka6400_startslave(struct device *, struct cpu_info *);
79 static void ka6400_txrx(int, char *, int);
80 static void ka6400_sendstr(int, char *);
81 static void ka6400_sergeant(int);
82 static int rxchar(void);
83 static void ka6400_putc(int);
84 static void ka6400_cnintr(void);
85 cons_decl(gen);
86 #endif
87 
88 struct	cpu_dep ka6400_calls = {
89 	ka6400_steal_pages,
90 	ka6400_mchk,
91 	ka6400_memerr,
92 	ka6400_conf,
93 	generic_clkread,
94 	generic_clkwrite,
95 	6,	/* ~VUPS */
96 	16,	/* SCB pages */
97 	0,
98 	0,
99 	0,
100 	0,
101 	0,
102 #if defined(MULTIPROCESSOR)
103 	ka6400_startslave,
104 #endif
105 };
106 
107 struct ka6400_softc {
108 	struct device sc_dev;
109 	struct cpu_info *sc_ci;
110 	int sc_nodeid;		/* CPU node ID */
111 };
112 
113 struct cfattach cpu_xmi_ca = {
114 	sizeof(struct ka6400_softc), ka6400_match, ka6400_attach
115 };
116 
117 static int
118 ka6400_match(struct device *parent, struct cfdata *cf, void *aux)
119 {
120 	struct xmi_attach_args *xa = aux;
121 
122 	if (bus_space_read_2(xa->xa_iot, xa->xa_ioh, XMI_TYPE) != XMIDT_KA64)
123 		return 0;
124 
125 	if (cf->cf_loc[XMICF_NODE] != XMICF_NODE_DEFAULT &&
126 	    cf->cf_loc[XMICF_NODE] != xa->xa_nodenr)
127 		return 0;
128 
129 	return 1;
130 }
131 
132 static void
133 ka6400_attach(struct device *parent, struct device *self, void *aux)
134 {
135 	struct ka6400_softc *sc = (void *)self;
136 	struct xmi_attach_args *xa = aux;
137 	int vp;
138 
139 	vp = (cca->cca_vecenab & (1 << xa->xa_nodenr));
140 	printf("\n%s: ka6400 (%s) rev %d%s\n", self->dv_xname,
141 	    mastercpu == xa->xa_nodenr ? "master" : "slave",
142 	    bus_space_read_4(xa->xa_iot, xa->xa_ioh, XMI_TYPE) >> 16,
143 	    (vp ? ", vector processor present" : ""));
144 
145 	sc->sc_nodeid = xa->xa_nodenr;
146 
147 	if (xa->xa_nodenr != mastercpu) {
148 #if defined(MULTIPROCESSOR)
149 		sc->sc_ci = cpu_slavesetup(self);
150 		v_putc = ka6400_putc;	/* Need special console handling */
151 #endif
152 		return;
153 	}
154 
155 	mtpr(0, PR_VPSR); /* Can't use vector processor */
156 	curcpu()->ci_dev = self;
157 }
158 
159 void
160 ka6400_conf()
161 {
162 	int mapaddr;
163 
164 	rssc = (void *)vax_map_physmem(RSSC_ADDR, 1);
165 	mastercpu = rssc[RSSC_IPORT/4] & 15;
166 	mapaddr = (cca ? (int)cca : rpb.cca_addr);
167 	cca = (void *)vax_map_physmem(mapaddr, vax_btoc(sizeof(struct cca)));
168 }
169 
170 /*
171  * MS62 support.
172  * This code should:
173  *	1: Be completed.
174  *	2: (eventually) move to dev/xmi/; it is used by Mips also.
175  */
176 #define MEMRD(reg) bus_space_read_4(sc->sc_iot, sc->sc_ioh, (reg))
177 #define MEMWR(reg, val) bus_space_write_4(sc->sc_iot, sc->sc_ioh, (reg), (val))
178 
179 #define MS62_TYPE	0
180 #define MS62_XBE	4
181 #define MS62_SEADR	16
182 #define	MS62_CTL1	20
183 #define MS62_ECCERR	24
184 #define MS62_ECCEA	28
185 #define MS62_ILK0	32
186 #define MS62_ILK1	36
187 #define MS62_ILK2	40
188 #define MS62_ILK3	44
189 #define MS62_CTL2	48
190 
191 static int ms6400_match(struct device *, struct cfdata *, void *);
192 static void ms6400_attach(struct device *, struct device *, void*);
193 
194 struct mem_xmi_softc {
195 	struct device sc_dev;
196 	bus_space_tag_t sc_iot;
197 	bus_space_handle_t sc_ioh;
198 };
199 
200 struct cfattach mem_xmi_ca = {
201 	sizeof(struct mem_xmi_softc), ms6400_match, ms6400_attach
202 };
203 
204 static int
205 ms6400_match(struct device *parent, struct cfdata *cf, void *aux)
206 {
207 	struct xmi_attach_args *xa = aux;
208 
209 	if (bus_space_read_2(xa->xa_iot, xa->xa_ioh, XMI_TYPE) != XMIDT_MS62)
210 		return 0;
211 
212 	if (cf->cf_loc[XMICF_NODE] != XMICF_NODE_DEFAULT &&
213 	    cf->cf_loc[XMICF_NODE] != xa->xa_nodenr)
214 		return 0;
215 
216 	return 1;
217 }
218 
219 static void
220 ms6400_attach(struct device *parent, struct device *self, void *aux)
221 {
222 	struct mem_xmi_softc *sc = (void *)self;
223 	struct xmi_attach_args *xa = aux;
224 
225 	sc->sc_iot = xa->xa_iot;
226 	sc->sc_ioh = xa->xa_ioh;
227 	printf("\n%s: MS62, rev %d, size 32MB\n", self->dv_xname,
228 	    MEMRD(MS62_TYPE) >> 16);
229 }
230 
231 static void
232 ka6400_memerr()
233 {
234 	printf("ka6400_memerr\n");
235 }
236 
237 struct mc6400frame {
238 	int	mc64_summary;		/* summary parameter */
239 	int	mc64_va;		/* va register */
240 	int	mc64_vb;		/* memory address */
241 	int	mc64_sisr;		/* status word */
242 	int	mc64_state;		/* error pc */
243 	int	mc64_sc;		/* micro pc */
244 	int	mc64_pc;		/* current pc */
245 	int	mc64_psl;		/* current psl */
246 };
247 
248 static int
249 ka6400_mchk(caddr_t cmcf)
250 {
251 	return (MCHK_PANIC);
252 }
253 
254 #if defined(MULTIPROCESSOR)
255 #define RXBUF	80
256 static char rxbuf[RXBUF];
257 static int got = 0, taken = 0;
258 static int expect = 0;
259 #endif
260 #if 0
261 /*
262  * Receive a character from logical console.
263  */
264 static void
265 rxcdintr(void *arg)
266 {
267 	int c = mfpr(PR_RXCD);
268 
269 	if (c == 0)
270 		return;
271 
272 #if defined(MULTIPROCESSOR)
273 	if ((c & 0xff) == 0) {
274 		if (curcpu()->ci_flags & CI_MASTERCPU)
275 			ka6400_cnintr();
276 		return;
277 	}
278 
279 	if (expect == ((c >> 8) & 0xf))
280 		rxbuf[got++] = c & 0xff;
281 
282 	if (got == RXBUF)
283 		got = 0;
284 #endif
285 }
286 #endif
287 
288 /*
289  * From ka670, which has the same cache structure.
290  */
291 static void
292 ka6400_enable_cache(void)
293 {
294 	mtpr(KA670_PCS_REFRESH, PR_PCSTS);	/* disable primary cache */
295 	mtpr(mfpr(PR_PCSTS), PR_PCSTS);		/* clear error flags */
296 	mtpr(8, PR_BCCTL);			/* disable backup cache */
297 	mtpr(0, PR_BCFBTS);	/* flush backup cache tag store */
298 	mtpr(0, PR_BCFPTS);	/* flush primary cache tag store */
299 	mtpr(0x0e, PR_BCCTL);	/* enable backup cache */
300 	mtpr(KA670_PCS_FLUSH | KA670_PCS_REFRESH, PR_PCSTS);	/* flush primary cache */
301 	mtpr(KA670_PCS_ENABLE | KA670_PCS_REFRESH, PR_PCSTS);	/* flush primary cache */
302 }
303 
304 void
305 ka6400_steal_pages(void)
306 {
307 	int i, ncpu;
308 
309 	ka6400_enable_cache(); /* Turn on cache early */
310 	if (cca == 0)
311 		cca = (void *)rpb.cca_addr;
312 	/* Is there any way to get number of CPUs easier??? */
313 	for (i = ncpu = 0; i < cca->cca_maxcpu; i++)
314 		if (cca->cca_console & (1 << i))
315 			ncpu++;
316 	sprintf(cpu_model, "VAX 6000/4%x0", ncpu + 1);
317 }
318 
319 
320 #if defined(MULTIPROCESSOR) && 0
321 int
322 rxchar()
323 {
324 	int ret;
325 
326 	if (got == taken)
327 		return 0;
328 
329 	ret = rxbuf[taken++];
330 	if (taken == RXBUF)
331 		taken = 0;
332 	return ret;
333 }
334 
335 static void
336 ka6400_startslave(struct device *dev, struct cpu_info *ci)
337 {
338 	struct ka6400_softc *sc = (void *)dev;
339 	int id = sc->sc_binid;
340 	int i;
341 
342 	expect = sc->sc_binid;
343 	/* First empty queue */
344 	for (i = 0; i < 10000; i++)
345 		if (rxchar())
346 			i = 0;
347 	ka6400_txrx(id, "\020", 0);		/* Send ^P to get attention */
348 	ka6400_txrx(id, "I\r", 0);			/* Init other end */
349 	ka6400_txrx(id, "D/I 4 %x\r", ci->ci_istack);	/* Interrupt stack */
350 	ka6400_txrx(id, "D/I C %x\r", mfpr(PR_SBR));	/* SBR */
351 	ka6400_txrx(id, "D/I D %x\r", mfpr(PR_SLR));	/* SLR */
352 	ka6400_txrx(id, "D/I 10 %x\r", (int)ci->ci_pcb);	/* PCB for idle proc */
353 	ka6400_txrx(id, "D/I 11 %x\r", mfpr(PR_SCBB));	/* SCB */
354 	ka6400_txrx(id, "D/I 38 %x\r", mfpr(PR_MAPEN)); /* Enable MM */
355 	ka6400_txrx(id, "S %x\r", (int)&tramp); /* Start! */
356 	expect = 0;
357 	for (i = 0; i < 10000; i++)
358 		if ((volatile)ci->ci_flags & CI_RUNNING)
359 			break;
360 	if (i == 10000)
361 		printf("%s: (ID %d) failed starting??!!??\n",
362 		    dev->dv_xname, sc->sc_binid);
363 }
364 
365 void
366 ka6400_txrx(int id, char *fmt, int arg)
367 {
368 	char buf[20];
369 
370 	sprintf(buf, fmt, arg);
371 	ka6400_sendstr(id, buf);
372 	ka6400_sergeant(id);
373 }
374 
375 void
376 ka6400_sendstr(int id, char *buf)
377 {
378 	register u_int utchr; /* Ends up in R11 with PCC */
379 	int ch, i;
380 
381 	while (*buf) {
382 		utchr = *buf | id << 8;
383 
384 		/*
385 		 * It seems like mtpr to TXCD sets the V flag if it fails.
386 		 * Cannot check that flag in C...
387 		 */
388 #ifdef __GNUC__
389 		asm("1:;mtpr %0,$92;bvs 1b" :: "g"(utchr));
390 #else
391 		asm("1:;mtpr r11,$92;bvs 1b");
392 #endif
393 		buf++;
394 		i = 30000;
395 		while ((ch = rxchar()) == 0 && --i)
396 			;
397 		if (ch == 0)
398 			continue; /* failed */
399 	}
400 }
401 
402 void
403 ka6400_sergeant(int id)
404 {
405 	int i, ch, nserg;
406 
407 	nserg = 0;
408 	for (i = 0; i < 30000; i++) {
409 		if ((ch = rxchar()) == 0)
410 			continue;
411 		if (ch == '>')
412 			nserg++;
413 		else
414 			nserg = 0;
415 		i = 0;
416 		if (nserg == 3)
417 			break;
418 	}
419 	/* What to do now??? */
420 }
421 
422 /*
423  * Write to master console.
424  * Need no locking here; done in the print functions.
425  */
426 static volatile int ch = 0;
427 
428 void
429 ka6400_putc(int c)
430 {
431 	if (curcpu()->ci_flags & CI_MASTERCPU) {
432 		gencnputc(0, c);
433 		return;
434 	}
435 	ch = c;
436 	mtpr(mastercpu << 8, PR_RXCD); /* Send IPI to mastercpu */
437 	while (ch != 0)
438 		; /* Wait for master to handle */
439 }
440 
441 /*
442  * Got character IPI.
443  */
444 void
445 ka6400_cnintr()
446 {
447 	if (ch != 0)
448 		gencnputc(0, ch);
449 	ch = 0; /* Release slavecpu */
450 }
451 #endif
452