Home | History | Annotate | Line # | Download | only in vax
      1 /*	$NetBSD: ka820.c,v 1.58 2022/03/03 06:28:26 riastradh Exp $	*/
      2 /*
      3  * Copyright (c) 1988 Regents of the University of California.
      4  * All rights reserved.
      5  *
      6  * This code is derived from software contributed to Berkeley by
      7  * Chris Torek.
      8  *
      9  * Redistribution and use in source and binary forms, with or without
     10  * modification, are permitted provided that the following conditions
     11  * are met:
     12  * 1. Redistributions of source code must retain the above copyright
     13  *    notice, this list of conditions and the following disclaimer.
     14  * 2. Redistributions in binary form must reproduce the above copyright
     15  *    notice, this list of conditions and the following disclaimer in the
     16  *    documentation and/or other materials provided with the distribution.
     17  * 3. Neither the name of the University nor the names of its contributors
     18  *    may be used to endorse or promote products derived from this software
     19  *    without specific prior written permission.
     20  *
     21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     31  * SUCH DAMAGE.
     32  *
     33  *	@(#)ka820.c	7.4 (Berkeley) 12/16/90
     34  */
     35 
     36 /*
     37  * KA820 specific CPU code.  (Note that the VAX8200 uses a KA820, not
     38  * a KA8200.  Sigh.)
     39  */
     40 
     41 #include <sys/cdefs.h>
     42 __KERNEL_RCSID(0, "$NetBSD: ka820.c,v 1.58 2022/03/03 06:28:26 riastradh Exp $");
     43 
     44 #include "opt_multiprocessor.h"
     45 
     46 #include <sys/param.h>
     47 #include <sys/systm.h>
     48 #include <sys/bus.h>
     49 #include <sys/cpu.h>
     50 #include <sys/device.h>
     51 #include <sys/kernel.h>
     52 #include <sys/proc.h>
     53 
     54 #include <machine/ka820.h>
     55 #include <machine/nexus.h>
     56 #include <machine/clock.h>
     57 #include <machine/scb.h>
     58 #include <machine/mainbus.h>
     59 
     60 #include <dev/cons.h>
     61 
     62 #include <dev/bi/bireg.h>
     63 #include <dev/bi/bivar.h>
     64 
     65 #include <vax/vax/crx.h>
     66 
     67 #include "ioconf.h"
     68 #include "locators.h"
     69 
     70 struct ka820port *ka820port_ptr;
     71 struct rx50device *rx50device_ptr;
     72 static volatile struct ka820clock *ka820_clkpage;
     73 static int mastercpu;
     74 
     75 static int ka820_match(device_t, cfdata_t, void *);
     76 static void ka820_attach(device_t, device_t, void*);
     77 static void ka820_memerr(void);
     78 static void ka820_conf(void);
     79 static int ka820_mchk(void *);
     80 static int ka820_gettime(struct timeval *);
     81 static void ka820_settime(struct timeval *);
     82 static void rxcdintr(void *);
     83 static void vaxbierr(void *);
     84 
     85 static const char * const ka820_devs[] = { "bi", NULL };
     86 
     87 const struct cpu_dep ka820_calls = {
     88 	.cpu_mchk	= ka820_mchk,
     89 	.cpu_memerr	= ka820_memerr,
     90 	.cpu_conf	= ka820_conf,
     91 	.cpu_gettime	= ka820_gettime,
     92 	.cpu_settime	= ka820_settime,
     93 	.cpu_devs	= ka820_devs,
     94 	.cpu_vups	= 3,      /* ~VUPS */
     95 	.cpu_scbsz	= 5,	/* SCB pages */
     96 };
     97 
     98 #if defined(MULTIPROCESSOR)
     99 static void ka820_startslave(struct cpu_info *);
    100 static void ka820_send_ipi(struct cpu_info *);
    101 static void ka820_txrx(int, const char *, ...) __printflike(2, 3);
    102 static void ka820_sendstr(int, const char *);
    103 static void ka820_sergeant(int);
    104 static int rxchar(void);
    105 static void ka820_putc(int);
    106 static void ka820_cnintr(void);
    107 static void ka820_ipintr(void *);
    108 cons_decl(gen);
    109 
    110 const struct cpu_mp_dep ka820_mp_dep = {
    111 	.cpu_startslave	= ka820_startslave,
    112 	.cpu_send_ipi	= ka820_send_ipi,
    113 	.cpu_cnintr	= ka820_cnintr,
    114 };
    115 #endif
    116 
    117 CFATTACH_DECL_NEW(cpu_bi, 0,
    118     ka820_match, ka820_attach, NULL, NULL);
    119 
    120 #ifdef notyet
    121 extern struct pte BRAMmap[];
    122 extern struct pte EEPROMmap[];
    123 char bootram[KA820_BRPAGES * VAX_NBPG];
    124 char eeprom[KA820_EEPAGES * VAX_NBPG];
    125 #endif
    126 
    127 static int
    128 ka820_match(device_t parent, cfdata_t cf, void *aux)
    129 {
    130 	struct bi_attach_args * const ba = aux;
    131 
    132 	if (bus_space_read_2(ba->ba_iot, ba->ba_ioh, BIREG_DTYPE) != BIDT_KA820)
    133 		return 0;
    134 
    135 	if (cf->cf_loc[BICF_NODE] != BICF_NODE_DEFAULT &&
    136 	    cf->cf_loc[BICF_NODE] != ba->ba_nodenr)
    137 		return 0;
    138 
    139 	return 1;
    140 }
    141 
    142 static void
    143 ka820_attach(device_t parent, device_t self, void *aux)
    144 {
    145 	struct bi_attach_args * const ba = aux;
    146 	struct cpu_info *ci;
    147 	char c;
    148 	int csr;
    149 	u_short rev;
    150 
    151 	rev = bus_space_read_4(ba->ba_iot, ba->ba_ioh, BIREG_DTYPE) >> 16;
    152 	c = rev & 0x8000 ? '5' : '0';
    153 	mastercpu = mfpr(PR_BINID);
    154 	cpu_setmodel("VAX 82%c0", c);
    155 	printf(": ka82%c (%s) CPU rev %d, u patch rev %d, sec patch %d\n",
    156 	    c, mastercpu == ba->ba_nodenr ? "master" : "slave",
    157 	    ((rev >> 11) & 15), ((rev >> 1) &1023), rev & 1);
    158 
    159 	/* Allow for IPINTR */
    160 	bus_space_write_4(ba->ba_iot, ba->ba_ioh,
    161 	    BIREG_IPINTRMSK, BIIPINTR_MASK);
    162 
    163 #if defined(MULTIPROCESSOR)
    164 	if (ba->ba_nodenr != mastercpu) {
    165 		v_putc = ka820_putc;	/* Need special console handling */
    166 		cpu_slavesetup(self, ba->ba_nodenr);
    167 		return;
    168 	}
    169 #endif
    170 
    171 	ci = curcpu();
    172 	device_set_private(self, ci);	/* eww. but curcpu() is already too */
    173 					/* entrenched to change */
    174 	ci->ci_slotid = ba->ba_nodenr;
    175 	ci->ci_cpuid = device_unit(self);
    176 	ci->ci_dev = self;
    177 
    178 #if defined(MULTIPROCESSOR)
    179 	/*
    180 	 * Catch interprocessor interrupts.
    181 	 */
    182 	scb_vecalloc(KA820_INT_IPINTR, ka820_ipintr, ci, SCB_ISTACK, NULL);
    183 #endif
    184 	/* reset the console and enable the RX50 */
    185 	ka820port_ptr = (void *)vax_map_physmem(KA820_PORTADDR, 1);
    186 	csr = ka820port_ptr->csr;
    187 	csr &= ~KA820PORT_RSTHALT;	/* ??? */
    188 	csr |= KA820PORT_CONSCLR | KA820PORT_CRDCLR | KA820PORT_CONSEN |
    189 		KA820PORT_RXIE;
    190 	ka820port_ptr->csr = csr;
    191 	bus_space_write_4(ba->ba_iot, ba->ba_ioh,
    192 	    BIREG_INTRDES, ba->ba_intcpu);
    193 	bus_space_write_4(ba->ba_iot, ba->ba_ioh, BIREG_VAXBICSR,
    194 	    bus_space_read_4(ba->ba_iot, ba->ba_ioh, BIREG_VAXBICSR) |
    195 	    BICSR_SEIE | BICSR_HEIE);
    196 }
    197 
    198 void
    199 ka820_conf(void)
    200 {
    201 	/*
    202 	 * Setup parameters necessary to read time from clock chip.
    203 	 */
    204 	ka820_clkpage = (void *)vax_map_physmem(KA820_CLOCKADDR, 1);
    205 
    206 	/* Enable cache */
    207 	mtpr(0, PR_CADR);
    208 
    209 	/* Steal the interrupt vectors that are unique for us */
    210 	scb_vecalloc(KA820_INT_RXCD, rxcdintr, NULL, SCB_ISTACK, NULL);
    211 	scb_vecalloc(0x50, vaxbierr, NULL, SCB_ISTACK, NULL);
    212 
    213 	/* XXX - should be done somewhere else */
    214 	scb_vecalloc(SCB_RX50, crxintr, NULL, SCB_ISTACK, NULL);
    215 	rx50device_ptr = (void *)vax_map_physmem(KA820_RX50ADDR, 1);
    216 #if defined(MULTIPROCESSOR)
    217 	mp_dep_call = &ka820_mp_dep;
    218 #endif
    219 }
    220 
    221 void
    222 vaxbierr(void *arg)
    223 {
    224 	if (cold == 0)
    225 		panic("vaxbierr");
    226 }
    227 
    228 #ifdef notdef
    229 /*
    230  * MS820 support.
    231  */
    232 struct ms820regs {
    233 	struct	biiregs biic;		/* BI interface chip */
    234 	u_long	ms_gpr[4];		/* the four gprs (unused) */
    235 	int	ms_csr1;		/* control/status register 1 */
    236 	int	ms_csr2;		/* control/status register 2 */
    237 };
    238 #endif
    239 
    240 #define	MEMRD(reg) bus_space_read_4(sc->sc_iot, sc->sc_ioh, (reg))
    241 #define MEMWR(reg, val) bus_space_write_4(sc->sc_iot, sc->sc_ioh, (reg), (val))
    242 
    243 #define	MSREG_CSR1	0x100
    244 #define	MSREG_CSR2	0x104
    245 /*
    246  * Bits in CSR1.
    247  */
    248 #define MS1_ERRSUM	0x80000000	/* error summary (ro) */
    249 #define MS1_ECCDIAG	0x40000000	/* ecc diagnostic (rw) */
    250 #define MS1_ECCDISABLE	0x20000000	/* ecc disable (rw) */
    251 #define MS1_MSIZEMASK	0x1ffc0000	/* mask for memory size (ro) */
    252 #define MS1_RAMTYMASK	0x00030000	/* mask for ram type (ro) */
    253 #define MS1_RAMTY64K	0x00000000	/* 64K chips */
    254 #define MS1_RAMTY256K	0x00010000	/* 256K chips */
    255 #define MS1_RAMTY1MB	0x00020000	/* 1MB chips */
    256 					/* type 3 reserved */
    257 #define MS1_CRDINH	0x00008000	/* inhibit crd interrupts (rw) */
    258 #define MS1_MEMVALID	0x00004000	/* memory has been written (ro) */
    259 #define MS1_INTLK	0x00002000	/* interlock flag (ro) */
    260 #define MS1_BROKE	0x00001000	/* broken (rw) */
    261 #define MS1_MBZ		0x00000880	/* zero */
    262 #define MS1_MWRITEERR	0x00000400	/* rds during masked write (rw) */
    263 #define MS1_CNTLERR	0x00000200	/* internal timing busted (rw) */
    264 #define MS1_INTLV	0x00000100	/* internally interleaved (ro) */
    265 #define MS1_DIAGC	0x0000007f	/* ecc diagnostic bits (rw) */
    266 
    267 /*
    268  * Bits in CSR2.
    269  */
    270 #define MS2_RDSERR	0x80000000	/* rds error (rw) */
    271 #define MS2_HIERR	0x40000000	/* high error rate (rw) */
    272 #define MS2_CRDERR	0x20000000	/* crd error (rw) */
    273 #define MS2_ADRSERR	0x10000000	/* rds due to addr par err (rw) */
    274 #define MS2_MBZ		0x0f000080	/* zero */
    275 #define MS2_ADDR	0x00fffe00	/* address in error (relative) (ro) */
    276 #define MS2_INTLVADDR	0x00000100	/* error was in bank 1 (ro) */
    277 #define MS2_SYN		0x0000007f	/* error syndrome (ro, rw diag) */
    278 
    279 static int ms820_match(device_t, cfdata_t, void *);
    280 static void ms820_attach(device_t, device_t, void*);
    281 
    282 struct mem_bi_softc {
    283 	device_t sc_dev;
    284 	bus_space_tag_t sc_iot;
    285 	bus_space_handle_t sc_ioh;
    286 };
    287 
    288 CFATTACH_DECL_NEW(mem_bi, sizeof(struct mem_bi_softc),
    289     ms820_match, ms820_attach, NULL, NULL);
    290 
    291 static int
    292 ms820_match(device_t parent, cfdata_t cf, void *aux)
    293 {
    294 	struct bi_attach_args * const ba = aux;
    295 
    296 	if (bus_space_read_2(ba->ba_iot, ba->ba_ioh, BIREG_DTYPE) != BIDT_MS820)
    297 		return 0;
    298 
    299 	if (cf->cf_loc[BICF_NODE] != BICF_NODE_DEFAULT &&
    300 	    cf->cf_loc[BICF_NODE] != ba->ba_nodenr)
    301 		return 0;
    302 
    303 	return 1;
    304 }
    305 
    306 static void
    307 ms820_attach(device_t parent, device_t self, void *aux)
    308 {
    309 	struct mem_bi_softc * const sc = device_private(self);
    310 	struct bi_attach_args * const ba = aux;
    311 
    312 	sc->sc_dev = self;
    313 	sc->sc_iot = ba->ba_iot;
    314 	sc->sc_ioh = ba->ba_ioh;
    315 
    316 	if ((MEMRD(BIREG_VAXBICSR) & BICSR_STS) == 0)
    317 		aprint_error(": failed self test\n");
    318 	else
    319 		aprint_normal(": size %dMB, %s chips\n", ((MEMRD(MSREG_CSR1) &
    320 		    MS1_MSIZEMASK) >> 20), (MEMRD(MSREG_CSR1) & MS1_RAMTYMASK
    321 		    ? MEMRD(MSREG_CSR1) & MS1_RAMTY256K ? "256K":"1M":"64K"));
    322 
    323 	MEMWR(BIREG_INTRDES, ba->ba_intcpu);
    324 	MEMWR(BIREG_VAXBICSR, MEMRD(BIREG_VAXBICSR) | BICSR_SEIE | BICSR_HEIE);
    325 
    326 	MEMWR(MSREG_CSR1, MS1_MWRITEERR | MS1_CNTLERR);
    327 	MEMWR(MSREG_CSR2, MS2_RDSERR | MS2_HIERR | MS2_CRDERR | MS2_ADRSERR);
    328 }
    329 
    330 static void
    331 ka820_memerr(void)
    332 {
    333 	struct mem_bi_softc *sc;
    334 	int m, hard, csr1, csr2;
    335 	const char *type;
    336 
    337 static const char b1[] = "\20\40ERRSUM\37ECCDIAG\36ECCDISABLE\20CRDINH\17VALID\
    338 \16INTLK\15BROKE\13MWRITEERR\12CNTLERR\11INTLV";
    339 static const char b2[] = "\20\40RDS\37HIERR\36CRD\35ADRS";
    340 
    341 	char sbuf[sizeof(b1) + 64], sbuf2[sizeof(b2) + 64];
    342 
    343 	for (m = 0; m < mem_cd.cd_ndevs; m++) {
    344 		sc = device_lookup_private(&mem_cd, m);
    345 		if (sc == NULL)
    346 			continue;
    347 		csr1 = MEMRD(MSREG_CSR1);
    348 		csr2 = MEMRD(MSREG_CSR2);
    349 		snprintb(sbuf, sizeof(sbuf), b1, csr1);
    350 		snprintb(sbuf2, sizeof(sbuf2), b2, csr2);
    351 		aprint_error_dev(sc->sc_dev, "csr1=%s csr2=%s\n", sbuf, sbuf2);
    352 		if ((csr1 & MS1_ERRSUM) == 0)
    353 			continue;
    354 		hard = 1;
    355 		if (csr1 & MS1_BROKE)
    356 			type = "broke";
    357 		else if (csr1 & MS1_CNTLERR)
    358 			type = "cntl err";
    359 		else if (csr2 & MS2_ADRSERR)
    360 			type = "address parity err";
    361 		else if (csr2 & MS2_RDSERR)
    362 			type = "rds err";
    363 		else if (csr2 & MS2_CRDERR) {
    364 			hard = 0;
    365 			type = "";
    366 		} else
    367 			type = "mysterious error";
    368 		aprint_error_dev(sc->sc_dev, "%s%s%s addr %x bank %x syn %x\n",
    369 		    hard ? "hard error: " : "soft ecc",
    370 		    type, csr2 & MS2_HIERR ?  " (+ other rds or crd err)" : "",
    371 		    ((csr2 & MS2_ADDR) + MEMRD(BIREG_SADR)) >> 9,
    372 		    (csr2 & MS2_INTLVADDR) != 0, csr2 & MS2_SYN);
    373 		MEMWR(MSREG_CSR1, csr1 | MS1_CRDINH);
    374 		MEMWR(MSREG_CSR2, csr2);
    375 	}
    376 }
    377 
    378 /* these are bits 0 to 6 in the summary field */
    379 const char * const mc8200[] = {
    380 	"cpu bad ipl",		"ucode lost err",
    381 	"ucode par err",	"DAL par err",
    382 	"BI bus err",		"BTB tag par",
    383 	"cache tag par",
    384 };
    385 #define MC8200_BADIPL	0x01
    386 #define MC8200_UERR	0x02
    387 #define MC8200_UPAR	0x04
    388 #define MC8200_DPAR	0x08
    389 #define MC8200_BIERR	0x10
    390 #define MC8200_BTAGPAR	0x20
    391 #define MC8200_CTAGPAR	0x40
    392 
    393 struct mc8200frame {
    394 	int	mc82_bcnt;		/* byte count == 0x20 */
    395 	int	mc82_summary;		/* summary parameter */
    396 	int	mc82_param1;		/* parameter 1 */
    397 	int	mc82_va;		/* va register */
    398 	int	mc82_vap;		/* va prime register */
    399 	int	mc82_ma;		/* memory address */
    400 	int	mc82_status;		/* status word */
    401 	int	mc82_epc;		/* error pc */
    402 	int	mc82_upc;		/* micro pc */
    403 	int	mc82_pc;		/* current pc */
    404 	int	mc82_psl;		/* current psl */
    405 };
    406 
    407 static int
    408 ka820_mchk(void *cmcf)
    409 {
    410 	struct mc8200frame *mcf = (struct mc8200frame *)cmcf;
    411 	int i, type = mcf->mc82_summary;
    412 
    413 	/* ignore BI bus errors during configuration */
    414 	if (cold && type == MC8200_BIERR) {
    415 		mtpr(PR_MCESR, 0xf);
    416 		return (MCHK_RECOVERED);
    417 	}
    418 
    419 	/*
    420 	 * SOME ERRORS ARE RECOVERABLE
    421 	 * do it later
    422 	 */
    423 	printf("machine check %x: ", type);
    424 	for (i = 0; i < sizeof (mc8200) / sizeof (mc8200[0]); i++)
    425 		if (type & (1 << i))
    426 			printf(" %s,", mc8200[i]);
    427 	printf(" param1 %x\n", mcf->mc82_param1);
    428 	printf(
    429 "\tva %x va' %x ma %x pc %x psl %x\n\tstatus %x errpc %x upc %x\n",
    430 		mcf->mc82_va, mcf->mc82_vap, mcf->mc82_ma,
    431 		mcf->mc82_pc, mcf->mc82_psl,
    432 		mcf->mc82_status, mcf->mc82_epc, mcf->mc82_upc);
    433 	return (MCHK_PANIC);
    434 }
    435 
    436 #if defined(MULTIPROCESSOR)
    437 #define	RXBUF	80
    438 static char rxbuf[RXBUF];
    439 static int got = 0, taken = 0;
    440 static int expect = 0;
    441 #endif
    442 /*
    443  * Receive a character from logical console.
    444  */
    445 static void
    446 rxcdintr(void *arg)
    447 {
    448 	int c = mfpr(PR_RXCD);
    449 
    450 	if (c == 0)
    451 		return;
    452 
    453 #if defined(MULTIPROCESSOR)
    454 	if (expect == ((c >> 8) & 0xf))
    455 		rxbuf[got++] = c & 0xff;
    456 
    457 	if (got == RXBUF)
    458 		got = 0;
    459 #endif
    460 }
    461 
    462 #if defined(MULTIPROCESSOR)
    463 int
    464 rxchar(void)
    465 {
    466 	int ret;
    467 
    468 	if (got == taken)
    469 		return 0;
    470 
    471 	ret = rxbuf[taken++];
    472 	if (taken == RXBUF)
    473 		taken = 0;
    474 	return ret;
    475 }
    476 #endif
    477 
    478 int
    479 ka820_gettime(struct timeval *tvp)
    480 {
    481 	struct clock_ymdhms c;
    482 	int s;
    483 
    484 	while (ka820_clkpage->csr0 & KA820CLK_0_BUSY)
    485 		;
    486 
    487 	s = splhigh();
    488 	c.dt_sec  = ka820_clkpage->sec;
    489 	c.dt_min  = ka820_clkpage->min;
    490 	c.dt_hour = ka820_clkpage->hr;
    491 	c.dt_wday = ka820_clkpage->dayofwk;
    492 	c.dt_day  = ka820_clkpage->day;
    493 	c.dt_mon  = ka820_clkpage->mon;
    494 	c.dt_year = ka820_clkpage->yr;
    495 	splx(s);
    496 
    497 	/* strange conversion */
    498 	c.dt_sec  = ((c.dt_sec  << 7) | (c.dt_sec  >> 1)) & 0377;
    499 	c.dt_min  = ((c.dt_min  << 7) | (c.dt_min  >> 1)) & 0377;
    500 	c.dt_hour = ((c.dt_hour << 7) | (c.dt_hour >> 1)) & 0377;
    501 	c.dt_wday = ((c.dt_wday << 7) | (c.dt_wday >> 1)) & 0377;
    502 	c.dt_day  = ((c.dt_day  << 7) | (c.dt_day  >> 1)) & 0377;
    503 	c.dt_mon  = ((c.dt_mon  << 7) | (c.dt_mon  >> 1)) & 0377;
    504 	c.dt_year = ((c.dt_year << 7) | (c.dt_year >> 1)) & 0377;
    505 
    506 	tvp->tv_sec = clock_ymdhms_to_secs(&c);
    507 	return 0;
    508 }
    509 
    510 void
    511 ka820_settime(struct timeval *tvp)
    512 {
    513 	struct clock_ymdhms c;
    514 
    515 	clock_secs_to_ymdhms(tvp->tv_sec, &c);
    516 
    517 	ka820_clkpage->csr1    = KA820CLK_1_SET;
    518 	ka820_clkpage->sec     = ((c.dt_sec  << 1) | (c.dt_sec  >> 7)) & 0377;
    519 	ka820_clkpage->min     = ((c.dt_min  << 1) | (c.dt_min  >> 7)) & 0377;
    520 	ka820_clkpage->hr      = ((c.dt_hour << 1) | (c.dt_hour >> 7)) & 0377;
    521 	ka820_clkpage->dayofwk = ((c.dt_wday << 1) | (c.dt_wday >> 7)) & 0377;
    522 	ka820_clkpage->day     = ((c.dt_day  << 1) | (c.dt_day  >> 7)) & 0377;
    523 	ka820_clkpage->mon     = ((c.dt_mon  << 1) | (c.dt_mon  >> 7)) & 0377;
    524 	ka820_clkpage->yr      = ((c.dt_year << 1) | (c.dt_year >> 7)) & 0377;
    525 
    526 	ka820_clkpage->csr1    = KA820CLK_1_GO;
    527 }
    528 
    529 #if defined(MULTIPROCESSOR)
    530 static void
    531 ka820_startslave(struct cpu_info *ci)
    532 {
    533 	const struct pcb *pcb = lwp_getpcb(ci->ci_onproc);
    534 	const int id = ci->ci_slotid;
    535 	int i;
    536 
    537 	expect = id;
    538 	/* First empty queue */
    539 	for (i = 0; i < 10000; i++)
    540 		if (rxchar())
    541 			i = 0;
    542 	ka820_txrx(id, "\020");		/* Send ^P to get attention */
    543 	ka820_txrx(id, "I\r");			/* Init other end */
    544 	ka820_txrx(id, "D/I 4 %x\r", (int)ci->ci_istack);	/* Interrupt stack */
    545 	ka820_txrx(id, "D/I C %x\r", mfpr(PR_SBR));	/* SBR */
    546 	ka820_txrx(id, "D/I D %x\r", mfpr(PR_SLR));	/* SLR */
    547 	ka820_txrx(id, "D/I 10 %x\r", (int)pcb->pcb_paddr);	/* PCB for idle proc */
    548 	ka820_txrx(id, "D/I 11 %x\r", mfpr(PR_SCBB));	/* SCB */
    549 	ka820_txrx(id, "D/I 38 %x\r", mfpr(PR_MAPEN));	/* Enable MM */
    550 	ka820_txrx(id, "S %x\r", (int)&vax_mp_tramp);	/* Start! */
    551 	expect = 0;
    552 	for (i = 0; i < 10000; i++)
    553 		if (ci->ci_flags & CI_RUNNING)
    554 			break;
    555 	if (i == 10000)
    556 		aprint_error_dev(ci->ci_dev, "(ID %d) failed starting??\n", id);
    557 }
    558 
    559 void
    560 ka820_txrx(int id, const char *fmt, ...)
    561 {
    562 	char buf[20];
    563 	va_list ap;
    564 
    565 	va_start(ap, fmt);
    566 	vsnprintf(buf, sizeof(buf), fmt, ap);
    567 	va_end(ap);
    568 	ka820_sendstr(id, buf);
    569 	ka820_sergeant(id);
    570 }
    571 
    572 static void
    573 ka820_sendchr(int chr)
    574 {
    575 	/*
    576 	 * It seems like mtpr to TXCD sets the V flag if it fails.
    577 	 * Cannot check that flag in C...
    578 	 */
    579 	__asm volatile("1:;mtpr %0,$92;bvs 1b" :: "g"(chr));
    580 }
    581 
    582 void
    583 ka820_sendstr(int id, const char *buf)
    584 {
    585 	u_int utchr;
    586 	int ch, i;
    587 
    588 	while (*buf) {
    589 		utchr = *buf | id << 8;
    590 
    591 		ka820_sendchr(utchr);
    592 		buf++;
    593 		i = 30000;
    594 		while ((ch = rxchar()) == 0 && --i)
    595 			;
    596 		if (ch == 0)
    597 			continue; /* failed */
    598 	}
    599 }
    600 
    601 void
    602 ka820_sergeant(int id)
    603 {
    604 	int i, ch, nserg;
    605 
    606 	nserg = 0;
    607 	for (i = 0; i < 30000; i++) {
    608 		if ((ch = rxchar()) == 0)
    609 			continue;
    610 		if (ch == '>')
    611 			nserg++;
    612 		else
    613 			nserg = 0;
    614 		i = 0;
    615 		if (nserg == 3)
    616 			break;
    617 	}
    618 	/* What to do now??? */
    619 }
    620 
    621 /*
    622  * Write to master console.
    623  */
    624 static volatile int ch = 0;
    625 
    626 void
    627 ka820_putc(int c)
    628 {
    629 	if (curcpu()->ci_flags & CI_MASTERCPU) {
    630 		gencnputc(0, c);
    631 		return;
    632 	}
    633 	ch = c;
    634 
    635 	cpu_send_ipi(IPI_DEST_MASTER, IPI_SEND_CNCHAR);
    636 	while (ch != 0)
    637 		; /* Wait for master to handle */
    638 }
    639 
    640 /*
    641  * Got character IPI.
    642  */
    643 void
    644 ka820_cnintr(void)
    645 {
    646 	if (ch != 0)
    647 		gencnputc(0, ch);
    648 	ch = 0; /* Release slavecpu */
    649 }
    650 
    651 void
    652 ka820_send_ipi(struct cpu_info *ci)
    653 {
    654 	mtpr(1 << ci->ci_cpuid, PR_IPIR);
    655 }
    656 
    657 void
    658 ka820_ipintr(void *arg)
    659 {
    660 	cpu_handle_ipi();
    661 }
    662 #endif
    663