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