xref: /netbsd-src/sys/arch/sparc/dev/zs.c (revision 89c5a767f8fc7a4633b2d409966e2becbb98ff92)
1 /*	$NetBSD: zs.c,v 1.74 2000/03/06 21:36:11 thorpej Exp $	*/
2 
3 /*-
4  * Copyright (c) 1996 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Gordon W. Ross.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *        This product includes software developed by the NetBSD
21  *        Foundation, Inc. and its contributors.
22  * 4. Neither the name of The NetBSD Foundation nor the names of its
23  *    contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  */
38 
39 /*
40  * Zilog Z8530 Dual UART driver (machine-dependent part)
41  *
42  * Runs two serial lines per chip using slave drivers.
43  * Plain tty/async lines use the zs_async slave.
44  * Sun keyboard/mouse uses the zs_kbd/zs_ms slaves.
45  */
46 
47 #include "opt_ddb.h"
48 
49 #include <sys/param.h>
50 #include <sys/systm.h>
51 #include <sys/conf.h>
52 #include <sys/device.h>
53 #include <sys/file.h>
54 #include <sys/ioctl.h>
55 #include <sys/kernel.h>
56 #include <sys/proc.h>
57 #include <sys/tty.h>
58 #include <sys/time.h>
59 #include <sys/syslog.h>
60 
61 #include <machine/bsd_openprom.h>
62 #include <machine/autoconf.h>
63 #include <machine/conf.h>
64 #include <machine/cpu.h>
65 #include <machine/eeprom.h>
66 #include <machine/psl.h>
67 #include <machine/z8530var.h>
68 
69 #include <dev/cons.h>
70 #include <dev/ic/z8530reg.h>
71 
72 #include <sparc/sparc/vaddrs.h>
73 #include <sparc/sparc/auxreg.h>
74 #include <sparc/dev/cons.h>
75 
76 #include "kbd.h"	/* NKBD */
77 #include "zs.h" 	/* NZS */
78 
79 /* Make life easier for the initialized arrays here. */
80 #if NZS < 3
81 #undef  NZS
82 #define NZS 3
83 #endif
84 
85 /*
86  * Some warts needed by z8530tty.c -
87  * The default parity REALLY needs to be the same as the PROM uses,
88  * or you can not see messages done with printf during boot-up...
89  */
90 int zs_def_cflag = (CREAD | CS8 | HUPCL);
91 int zs_major = 12;
92 
93 /*
94  * The Sun provides a 4.9152 MHz clock to the ZS chips.
95  */
96 #define PCLK	(9600 * 512)	/* PCLK pin input clock rate */
97 
98 /*
99  * Select software interrupt bit based on TTY ipl.
100  */
101 #if PIL_TTY == 1
102 # define IE_ZSSOFT IE_L1
103 #elif PIL_TTY == 4
104 # define IE_ZSSOFT IE_L4
105 #elif PIL_TTY == 6
106 # define IE_ZSSOFT IE_L6
107 #else
108 # error "no suitable software interrupt bit"
109 #endif
110 
111 #define	ZS_DELAY()		(CPU_ISSUN4C ? (0) : delay(2))
112 
113 /* The layout of this is hardware-dependent (padding, order). */
114 struct zschan {
115 	volatile u_char	zc_csr;		/* ctrl,status, and indirect access */
116 	u_char		zc_xxx0;
117 	volatile u_char	zc_data;	/* data */
118 	u_char		zc_xxx1;
119 };
120 struct zsdevice {
121 	/* Yes, they are backwards. */
122 	struct	zschan zs_chan_b;
123 	struct	zschan zs_chan_a;
124 };
125 
126 /* ZS channel used as the console device (if any) */
127 void *zs_conschan;
128 
129 /* Default speed for each channel */
130 static int zs_defspeed[NZS][2] = {
131 	{ 9600, 	/* ttya */
132 	  9600 },	/* ttyb */
133 	{ 1200, 	/* keyboard */
134 	  1200 },	/* mouse */
135 	{ 9600, 	/* ttyc */
136 	  9600 },	/* ttyd */
137 };
138 
139 static u_char zs_init_reg[16] = {
140 	0,	/* 0: CMD (reset, etc.) */
141 	0,	/* 1: No interrupts yet. */
142 	0,	/* 2: IVECT */
143 	ZSWR3_RX_8 | ZSWR3_RX_ENABLE,
144 	ZSWR4_CLK_X16 | ZSWR4_ONESB | ZSWR4_EVENP,
145 	ZSWR5_TX_8 | ZSWR5_TX_ENABLE,
146 	0,	/* 6: TXSYNC/SYNCLO */
147 	0,	/* 7: RXSYNC/SYNCHI */
148 	0,	/* 8: alias for data port */
149 	ZSWR9_MASTER_IE | ZSWR9_NO_VECTOR,
150 	0,	/*10: Misc. TX/RX control bits */
151 	ZSWR11_TXCLK_BAUD | ZSWR11_RXCLK_BAUD,
152 	((PCLK/32)/9600)-2,	/*12: BAUDLO (default=9600) */
153 	0,			/*13: BAUDHI (default=9600) */
154 	ZSWR14_BAUD_ENA | ZSWR14_BAUD_FROM_PCLK,
155 	ZSWR15_BREAK_IE,
156 };
157 
158 
159 /****************************************************************
160  * Autoconfig
161  ****************************************************************/
162 
163 /* Definition of the driver for autoconfig. */
164 static int  zs_match_mainbus __P((struct device *, struct cfdata *, void *));
165 static int  zs_match_obio __P((struct device *, struct cfdata *, void *));
166 static void zs_attach_mainbus __P((struct device *, struct device *, void *));
167 static void zs_attach_obio __P((struct device *, struct device *, void *));
168 
169 static void zs_attach __P((struct zsc_softc *, struct zsdevice *, int));
170 static int  zs_print __P((void *, const char *name));
171 
172 struct cfattach zs_mainbus_ca = {
173 	sizeof(struct zsc_softc), zs_match_mainbus, zs_attach_mainbus
174 };
175 
176 struct cfattach zs_obio_ca = {
177 	sizeof(struct zsc_softc), zs_match_obio, zs_attach_obio
178 };
179 
180 extern struct cfdriver zs_cd;
181 
182 /* Interrupt handlers. */
183 static int zshard __P((void *));
184 static int zssoft __P((void *));
185 static struct intrhand levelsoft = { zssoft };
186 
187 static int zs_get_speed __P((struct zs_chanstate *));
188 
189 
190 /*
191  * Is the zs chip present?
192  */
193 static int
194 zs_match_mainbus(parent, cf, aux)
195 	struct device *parent;
196 	struct cfdata *cf;
197 	void *aux;
198 {
199 	struct mainbus_attach_args *ma = aux;
200 
201 	if (strcmp(cf->cf_driver->cd_name, ma->ma_name) != 0)
202 		return (0);
203 
204 	return (1);
205 }
206 
207 static int
208 zs_match_obio(parent, cf, aux)
209 	struct device *parent;
210 	struct cfdata *cf;
211 	void *aux;
212 {
213 	union obio_attach_args *uoba = aux;
214 	struct obio4_attach_args *oba;
215 
216 	if (uoba->uoba_isobio4 == 0) {
217 		struct sbus_attach_args *sa = &uoba->uoba_sbus;
218 
219 		if (strcmp(cf->cf_driver->cd_name, sa->sa_name) != 0)
220 			return (0);
221 
222 		return (1);
223 	}
224 
225 	oba = &uoba->uoba_oba4;
226 	return (bus_space_probe(oba->oba_bustag, 0, oba->oba_paddr,
227 			        1, 0, 0, NULL, NULL));
228 }
229 
230 static void
231 zs_attach_mainbus(parent, self, aux)
232 	struct device *parent;
233 	struct device *self;
234 	void *aux;
235 {
236 	struct zsc_softc *zsc = (void *) self;
237 	struct mainbus_attach_args *ma = aux;
238 
239 	zsc->zsc_bustag = ma->ma_bustag;
240 	zsc->zsc_dmatag = ma->ma_dmatag;
241 
242 	/*
243 	 * For machines with zs on mainbus (all sun4c models), we expect
244 	 * the device registers to be mapped by the PROM.
245 	 */
246 	zs_attach(zsc, ma->ma_promvaddr, ma->ma_pri);
247 }
248 
249 static void
250 zs_attach_obio(parent, self, aux)
251 	struct device *parent;
252 	struct device *self;
253 	void *aux;
254 {
255 	struct zsc_softc *zsc = (void *) self;
256 	union obio_attach_args *uoba = aux;
257 
258 	if (uoba->uoba_isobio4 == 0) {
259 		struct sbus_attach_args *sa = &uoba->uoba_sbus;
260 		void *va;
261 
262 		if (sa->sa_nintr == 0) {
263 			printf(" no interrupt lines\n");
264 			return;
265 		}
266 
267 		/*
268 		 * Some sun4m models (Javastations) may not map the zs device.
269 		 */
270 		if (sa->sa_npromvaddrs > 0)
271 			va = (void *)sa->sa_promvaddr;
272 		else {
273 			bus_space_handle_t bh;
274 
275 			if (sbus_bus_map(sa->sa_bustag,
276 					  sa->sa_slot,
277 					  sa->sa_offset,
278 					  sa->sa_size,
279 					  BUS_SPACE_MAP_LINEAR,
280 					  0, &bh) != 0) {
281 				printf(" cannot map zs registers\n");
282 				return;
283 			}
284 			va = (void *)bh;
285 		}
286 
287 		zsc->zsc_bustag = sa->sa_bustag;
288 		zsc->zsc_dmatag = sa->sa_dmatag;
289 		zs_attach(zsc, va, sa->sa_pri);
290 	} else {
291 		struct obio4_attach_args *oba = &uoba->uoba_oba4;
292 		bus_space_handle_t bh;
293 
294 		/*
295 		 * As for zs on mainbus, we require a PROM mapping.
296 		 */
297 		if (bus_space_map(oba->oba_bustag,
298 				  oba->oba_paddr,
299 				  sizeof(struct zsdevice),
300 				  BUS_SPACE_MAP_LINEAR | OBIO_BUS_MAP_USE_ROM,
301 				  &bh) != 0) {
302 			printf(" cannot map zs registers\n");
303 			return;
304 		}
305 		zsc->zsc_bustag = oba->oba_bustag;
306 		zsc->zsc_dmatag = oba->oba_dmatag;
307 		zs_attach(zsc, (void *)bh, oba->oba_pri);
308 	}
309 }
310 /*
311  * Attach a found zs.
312  *
313  * USE ROM PROPERTIES port-a-ignore-cd AND port-b-ignore-cd FOR
314  * SOFT CARRIER, AND keyboard PROPERTY FOR KEYBOARD/MOUSE?
315  */
316 static void
317 zs_attach(zsc, zsd, pri)
318 	struct zsc_softc *zsc;
319 	struct zsdevice *zsd;
320 	int pri;
321 {
322 	struct zsc_attach_args zsc_args;
323 	struct zs_chanstate *cs;
324 	int s, zs_unit, channel;
325 	static int didintr, prevpri;
326 
327 	if (zsd == NULL) {
328 		printf("configuration incomplete\n");
329 		return;
330 	}
331 
332 	printf(" softpri %d\n", PIL_TTY);
333 
334 	/*
335 	 * Initialize software state for each channel.
336 	 */
337 	zs_unit = zsc->zsc_dev.dv_unit;
338 	for (channel = 0; channel < 2; channel++) {
339 		volatile struct zschan *zc;
340 
341 		zsc_args.channel = channel;
342 		zsc_args.hwflags = 0;
343 		cs = &zsc->zsc_cs_store[channel];
344 		zsc->zsc_cs[channel] = cs;
345 
346 		cs->cs_channel = channel;
347 		cs->cs_private = NULL;
348 		cs->cs_ops = &zsops_null;
349 		cs->cs_brg_clk = PCLK / 16;
350 
351 		zc = (channel == 0) ? &zsd->zs_chan_a : &zsd->zs_chan_b;
352 		if (zc == zs_conschan)
353 			zsc_args.hwflags |= ZS_HWFLAG_CONSOLE;
354 
355 		cs->cs_reg_csr  = &zc->zc_csr;
356 		cs->cs_reg_data = &zc->zc_data;
357 
358 		bcopy(zs_init_reg, cs->cs_creg, 16);
359 		bcopy(zs_init_reg, cs->cs_preg, 16);
360 
361 		/* XXX: Get these from the PROM properties! */
362 		/* XXX: See the mvme167 code.  Better. */
363 		if (zsc_args.hwflags & ZS_HWFLAG_CONSOLE)
364 			cs->cs_defspeed = zs_get_speed(cs);
365 		else
366 			cs->cs_defspeed = zs_defspeed[zs_unit][channel];
367 		cs->cs_defcflag = zs_def_cflag;
368 
369 		/* Make these correspond to cs_defcflag (-crtscts) */
370 		cs->cs_rr0_dcd = ZSRR0_DCD;
371 		cs->cs_rr0_cts = 0;
372 		cs->cs_wr5_dtr = ZSWR5_DTR | ZSWR5_RTS;
373 		cs->cs_wr5_rts = 0;
374 
375 		/*
376 		 * Clear the master interrupt enable.
377 		 * The INTENA is common to both channels,
378 		 * so just do it on the A channel.
379 		 */
380 		if (channel == 0) {
381 			zs_write_reg(cs, 9, 0);
382 		}
383 
384 		/*
385 		 * Look for a child driver for this channel.
386 		 * The child attach will setup the hardware.
387 		 */
388 		if (!config_found(&zsc->zsc_dev, (void *)&zsc_args, zs_print)) {
389 			/* No sub-driver.  Just reset it. */
390 			u_char reset = (channel == 0) ?
391 				ZSWR9_A_RESET : ZSWR9_B_RESET;
392 			s = splzs();
393 			zs_write_reg(cs,  9, reset);
394 			splx(s);
395 		}
396 	}
397 
398 	/*
399 	 * Now safe to install interrupt handlers.  Note the arguments
400 	 * to the interrupt handlers aren't used.  Note, we only do this
401 	 * once since both SCCs interrupt at the same level and vector.
402 	 */
403 	if (!didintr) {
404 		didintr = 1;
405 		prevpri = pri;
406 		bus_intr_establish(zsc->zsc_bustag, pri, 0, zshard, NULL);
407 		intr_establish(PIL_TTY, &levelsoft);
408 	} else if (pri != prevpri)
409 		panic("broken zs interrupt scheme");
410 
411 	evcnt_attach(&zsc->zsc_dev, "intr", &zsc->zsc_intrcnt);
412 
413 	/*
414 	 * Set the master interrupt enable and interrupt vector.
415 	 * (common to both channels, do it on A)
416 	 */
417 	cs = zsc->zsc_cs[0];
418 	s = splhigh();
419 	/* interrupt vector */
420 	zs_write_reg(cs, 2, zs_init_reg[2]);
421 	/* master interrupt control (enable) */
422 	zs_write_reg(cs, 9, zs_init_reg[9]);
423 	splx(s);
424 
425 #if 0
426 	/*
427 	 * XXX: L1A hack - We would like to be able to break into
428 	 * the debugger during the rest of autoconfiguration, so
429 	 * lower interrupts just enough to let zs interrupts in.
430 	 * This is done after both zs devices are attached.
431 	 */
432 	if (zs_unit == 1) {
433 		printf("zs1: enabling zs interrupts\n");
434 		(void)splfd(); /* XXX: splzs - 1 */
435 	}
436 #endif
437 }
438 
439 static int
440 zs_print(aux, name)
441 	void *aux;
442 	const char *name;
443 {
444 	struct zsc_attach_args *args = aux;
445 
446 	if (name != NULL)
447 		printf("%s: ", name);
448 
449 	if (args->channel != -1)
450 		printf(" channel %d", args->channel);
451 
452 	return (UNCONF);
453 }
454 
455 static volatile int zssoftpending;
456 
457 /*
458  * Our ZS chips all share a common, autovectored interrupt,
459  * so we have to look at all of them on each interrupt.
460  */
461 static int
462 zshard(arg)
463 	void *arg;
464 {
465 	register struct zsc_softc *zsc;
466 	register int unit, rr3, rval, softreq;
467 
468 	rval = softreq = 0;
469 	for (unit = 0; unit < zs_cd.cd_ndevs; unit++) {
470 		zsc = zs_cd.cd_devs[unit];
471 		if (zsc == NULL)
472 			continue;
473 		rr3 = zsc_intr_hard(zsc);
474 		/* Count up the interrupts. */
475 		if (rr3) {
476 			rval |= rr3;
477 			zsc->zsc_intrcnt.ev_count++;
478 		}
479 		softreq |= zsc->zsc_cs[0]->cs_softreq;
480 		softreq |= zsc->zsc_cs[1]->cs_softreq;
481 	}
482 
483 	/* We are at splzs here, so no need to lock. */
484 	if (softreq && (zssoftpending == 0)) {
485 		zssoftpending = IE_ZSSOFT;
486 #if defined(SUN4M)
487 		if (CPU_ISSUN4M)
488 			raise(0, PIL_TTY);
489 		else
490 #endif
491 			ienab_bis(IE_ZSSOFT);
492 	}
493 	return (rval);
494 }
495 
496 /*
497  * Similar scheme as for zshard (look at all of them)
498  */
499 static int
500 zssoft(arg)
501 	void *arg;
502 {
503 	register struct zsc_softc *zsc;
504 	register int s, unit;
505 
506 	/* This is not the only ISR on this IPL. */
507 	if (zssoftpending == 0)
508 		return (0);
509 
510 	/*
511 	 * The soft intr. bit will be set by zshard only if
512 	 * the variable zssoftpending is zero.  The order of
513 	 * these next two statements prevents our clearing
514 	 * the soft intr bit just after zshard has set it.
515 	 */
516 	/* ienab_bic(IE_ZSSOFT); */
517 	zssoftpending = 0;
518 
519 	/* Make sure we call the tty layer at spltty. */
520 	s = spltty();
521 	for (unit = 0; unit < zs_cd.cd_ndevs; unit++) {
522 		zsc = zs_cd.cd_devs[unit];
523 		if (zsc == NULL)
524 			continue;
525 		(void)zsc_intr_soft(zsc);
526 	}
527 	splx(s);
528 	return (1);
529 }
530 
531 
532 /*
533  * Compute the current baud rate given a ZS channel.
534  */
535 static int
536 zs_get_speed(cs)
537 	struct zs_chanstate *cs;
538 {
539 	int tconst;
540 
541 	tconst = zs_read_reg(cs, 12);
542 	tconst |= zs_read_reg(cs, 13) << 8;
543 	return (TCONST_TO_BPS(cs->cs_brg_clk, tconst));
544 }
545 
546 /*
547  * MD functions for setting the baud rate and control modes.
548  */
549 int
550 zs_set_speed(cs, bps)
551 	struct zs_chanstate *cs;
552 	int bps;	/* bits per second */
553 {
554 	int tconst, real_bps;
555 
556 	if (bps == 0)
557 		return (0);
558 
559 #ifdef	DIAGNOSTIC
560 	if (cs->cs_brg_clk == 0)
561 		panic("zs_set_speed");
562 #endif
563 
564 	tconst = BPS_TO_TCONST(cs->cs_brg_clk, bps);
565 	if (tconst < 0)
566 		return (EINVAL);
567 
568 	/* Convert back to make sure we can do it. */
569 	real_bps = TCONST_TO_BPS(cs->cs_brg_clk, tconst);
570 
571 	/* XXX - Allow some tolerance here? */
572 	if (real_bps != bps)
573 		return (EINVAL);
574 
575 	cs->cs_preg[12] = tconst;
576 	cs->cs_preg[13] = tconst >> 8;
577 
578 	/* Caller will stuff the pending registers. */
579 	return (0);
580 }
581 
582 int
583 zs_set_modes(cs, cflag)
584 	struct zs_chanstate *cs;
585 	int cflag;	/* bits per second */
586 {
587 	int s;
588 
589 	/*
590 	 * Output hardware flow control on the chip is horrendous:
591 	 * if carrier detect drops, the receiver is disabled, and if
592 	 * CTS drops, the transmitter is stoped IN MID CHARACTER!
593 	 * Therefore, NEVER set the HFC bit, and instead use the
594 	 * status interrupt to detect CTS changes.
595 	 */
596 	s = splzs();
597 	cs->cs_rr0_pps = 0;
598 	if ((cflag & (CLOCAL | MDMBUF)) != 0) {
599 		cs->cs_rr0_dcd = 0;
600 		if ((cflag & MDMBUF) == 0)
601 			cs->cs_rr0_pps = ZSRR0_DCD;
602 	} else
603 		cs->cs_rr0_dcd = ZSRR0_DCD;
604 	if ((cflag & CRTSCTS) != 0) {
605 		cs->cs_wr5_dtr = ZSWR5_DTR;
606 		cs->cs_wr5_rts = ZSWR5_RTS;
607 		cs->cs_rr0_cts = ZSRR0_CTS;
608 	} else if ((cflag & CDTRCTS) != 0) {
609 		cs->cs_wr5_dtr = 0;
610 		cs->cs_wr5_rts = ZSWR5_DTR;
611 		cs->cs_rr0_cts = ZSRR0_CTS;
612 	} else if ((cflag & MDMBUF) != 0) {
613 		cs->cs_wr5_dtr = 0;
614 		cs->cs_wr5_rts = ZSWR5_DTR;
615 		cs->cs_rr0_cts = ZSRR0_DCD;
616 	} else {
617 		cs->cs_wr5_dtr = ZSWR5_DTR | ZSWR5_RTS;
618 		cs->cs_wr5_rts = 0;
619 		cs->cs_rr0_cts = 0;
620 	}
621 	splx(s);
622 
623 	/* Caller will stuff the pending registers. */
624 	return (0);
625 }
626 
627 
628 /*
629  * Read or write the chip with suitable delays.
630  */
631 
632 u_char
633 zs_read_reg(cs, reg)
634 	struct zs_chanstate *cs;
635 	u_char reg;
636 {
637 	u_char val;
638 
639 	*cs->cs_reg_csr = reg;
640 	ZS_DELAY();
641 	val = *cs->cs_reg_csr;
642 	ZS_DELAY();
643 	return (val);
644 }
645 
646 void
647 zs_write_reg(cs, reg, val)
648 	struct zs_chanstate *cs;
649 	u_char reg, val;
650 {
651 	*cs->cs_reg_csr = reg;
652 	ZS_DELAY();
653 	*cs->cs_reg_csr = val;
654 	ZS_DELAY();
655 }
656 
657 u_char
658 zs_read_csr(cs)
659 	struct zs_chanstate *cs;
660 {
661 	register u_char val;
662 
663 	val = *cs->cs_reg_csr;
664 	ZS_DELAY();
665 	return (val);
666 }
667 
668 void  zs_write_csr(cs, val)
669 	struct zs_chanstate *cs;
670 	u_char val;
671 {
672 	*cs->cs_reg_csr = val;
673 	ZS_DELAY();
674 }
675 
676 u_char zs_read_data(cs)
677 	struct zs_chanstate *cs;
678 {
679 	register u_char val;
680 
681 	val = *cs->cs_reg_data;
682 	ZS_DELAY();
683 	return (val);
684 }
685 
686 void  zs_write_data(cs, val)
687 	struct zs_chanstate *cs;
688 	u_char val;
689 {
690 	*cs->cs_reg_data = val;
691 	ZS_DELAY();
692 }
693 
694 /****************************************************************
695  * Console support functions (Sun specific!)
696  * Note: this code is allowed to know about the layout of
697  * the chip registers, and uses that to keep things simple.
698  * XXX - I think I like the mvme167 code better. -gwr
699  ****************************************************************/
700 
701 /*
702  * Handle user request to enter kernel debugger.
703  */
704 void
705 zs_abort(cs)
706 	struct zs_chanstate *cs;
707 {
708 	register volatile struct zschan *zc = zs_conschan;
709 	int rr0;
710 
711 	/* Wait for end of break to avoid PROM abort. */
712 	/* XXX - Limit the wait? */
713 	do {
714 		rr0 = zc->zc_csr;
715 		ZS_DELAY();
716 	} while (rr0 & ZSRR0_BREAK);
717 
718 #if defined(KGDB)
719 	zskgdb(cs);
720 #elif defined(DDB)
721 	Debugger();
722 #else
723 	printf("stopping on keyboard abort\n");
724 	callrom();
725 #endif
726 }
727 
728 /*
729  * Polled input char.
730  */
731 int
732 zs_getc(arg)
733 	void *arg;
734 {
735 	register volatile struct zschan *zc = arg;
736 	register int s, c, rr0;
737 
738 	s = splhigh();
739 	/* Wait for a character to arrive. */
740 	do {
741 		rr0 = zc->zc_csr;
742 		ZS_DELAY();
743 	} while ((rr0 & ZSRR0_RX_READY) == 0);
744 
745 	c = zc->zc_data;
746 	ZS_DELAY();
747 	splx(s);
748 
749 	/*
750 	 * This is used by the kd driver to read scan codes,
751 	 * so don't translate '\r' ==> '\n' here...
752 	 */
753 	return (c);
754 }
755 
756 /*
757  * Polled output char.
758  */
759 void
760 zs_putc(arg, c)
761 	void *arg;
762 	int c;
763 {
764 	register volatile struct zschan *zc = arg;
765 	register int s, rr0;
766 
767 	s = splhigh();
768 
769 	/* Wait for transmitter to become ready. */
770 	do {
771 		rr0 = zc->zc_csr;
772 		ZS_DELAY();
773 	} while ((rr0 & ZSRR0_TX_READY) == 0);
774 
775 	/*
776 	 * Send the next character.
777 	 * Now you'd think that this could be followed by a ZS_DELAY()
778 	 * just like all the other chip accesses, but it turns out that
779 	 * the `transmit-ready' interrupt isn't de-asserted until
780 	 * some period of time after the register write completes
781 	 * (more than a couple instructions).  So to avoid stray
782 	 * interrupts we put in the 2us delay regardless of cpu model.
783 	 */
784 	zc->zc_data = c;
785 	delay(2);
786 
787 	splx(s);
788 }
789 
790 /*****************************************************************/
791 
792 static void zscninit __P((struct consdev *));
793 static int  zscngetc __P((dev_t));
794 static void zscnputc __P((dev_t, int));
795 
796 /*
797  * Console table shared by ttya, ttyb
798  */
799 struct consdev consdev_tty = {
800 	nullcnprobe,
801 	zscninit,
802 	zscngetc,
803 	zscnputc,
804 	nullcnpollc,
805 	NULL,
806 };
807 
808 static void
809 zscninit(cn)
810 	struct consdev *cn;
811 {
812 }
813 
814 /*
815  * Polled console input putchar.
816  */
817 static int
818 zscngetc(dev)
819 	dev_t dev;
820 {
821 	return (zs_getc(zs_conschan));
822 }
823 
824 /*
825  * Polled console output putchar.
826  */
827 static void
828 zscnputc(dev, c)
829 	dev_t dev;
830 	int c;
831 {
832 	zs_putc(zs_conschan, c);
833 }
834 
835 /*****************************************************************/
836 
837 static void prom_cninit __P((struct consdev *));
838 static int  prom_cngetc __P((dev_t));
839 static void prom_cnputc __P((dev_t, int));
840 
841 /*
842  * The console is set to this one initially,
843  * which lets us use the PROM until consinit()
844  * is called to select a real console.
845  */
846 struct consdev consdev_prom = {
847 	nullcnprobe,
848 	prom_cninit,
849 	prom_cngetc,
850 	prom_cnputc,
851 	nullcnpollc,
852 };
853 
854 /*
855  * The console table pointer is statically initialized
856  * to point to the PROM (output only) table, so that
857  * early calls to printf will work.
858  */
859 struct consdev *cn_tab = &consdev_prom;
860 
861 void
862 nullcnprobe(cn)
863 	struct consdev *cn;
864 {
865 }
866 
867 static void
868 prom_cninit(cn)
869 	struct consdev *cn;
870 {
871 }
872 
873 /*
874  * PROM console input putchar.
875  * (dummy - this is output only) (WHY?????!)
876  */
877 static int
878 prom_cngetc(dev)
879 	dev_t dev;
880 {
881 	return (prom_getchar());
882 }
883 
884 /*
885  * PROM console output putchar.
886  */
887 static void
888 prom_cnputc(dev, c)
889 	dev_t dev;
890 	int c;
891 {
892 
893 	prom_putchar(c);
894 }
895 
896 /*****************************************************************/
897 
898 extern struct consdev consdev_kd;
899 
900 static char *prom_inSrc_name[] = {
901 	"keyboard/display",
902 	"ttya", "ttyb",
903 	"ttyc", "ttyd" };
904 
905 
906 static int get_serial_promdev __P((int));
907 
908 int
909 get_serial_promdev(io)
910 	int io;
911 {
912 	char *prop, *cp, buffer[128];
913 	int node;
914 
915 	node = findroot();
916 	prop = (io == 0) ? "stdin-path" : "stdout-path";
917 
918 	cp = getpropstringA(node, prop, buffer, sizeof buffer);
919 
920 	/*
921 	 * At this point we assume the device path is in the form
922 	 *   ....device@x,y:a for ttya and ...device@x,y:b for ttyb, etc.
923 	 */
924 	if (cp[0] != '\0' && cp[1] != '\0') {
925 		while (*cp != '\0')
926 			cp++;
927 		cp -= 2;
928 	} else {
929 		/*
930 		 * If don't have at least a 2 character string at cp, then
931 		 *  we default to using using the string ":a" for ttya.
932 		 */
933 		cp[0] = ':';
934 		cp[1] = 'a';
935 		cp[2] = '\0';
936 	}
937 
938 	if (cp >= buffer) {
939 		/* XXX: only allows tty's a->z, assumes PROMDEV_TTYx contig */
940 		if (cp[0] == ':' && cp[1] >= 'a' && cp[1] <= 'z')
941 			return (PROMDEV_TTYA + (cp[1] - 'a'));
942 	}
943 
944 	printf("Warning: unparseable %s property\n", prop);
945 	return (-1);
946 }
947 
948 /*
949  * This function replaces sys/dev/cninit.c
950  * Determine which device is the console using
951  * the PROM "input source" and "output sink".
952  */
953 void
954 consinit()
955 {
956 	struct zschan *zc;
957 	struct zsdevice *zsd;
958 	struct consdev *cn;
959 	int channel, promzs_unit, zstty_unit;
960 	int inSource, outSink;
961 	int node;
962 	char *devtype;
963 	extern int fbnode;
964 
965 	switch (prom_version()) {
966 	case PROM_OLDMON:
967 	case PROM_OBP_V0:
968 		/* The stdio handles identify the device type */
969 		inSource = prom_stdin();
970 		outSink  = prom_stdout();
971 		break;
972 	case PROM_OBP_V2:
973 	case PROM_OBP_V3:
974 	case PROM_OPENFIRM:
975 		/*
976 		 * We need to probe the PROM device tree.
977 		 *
978 		 * Translate the STDIO package instance (`ihandle') -- that
979 		 * the PROM has already opened for us -- to a device tree
980 		 * node (i.e. a `phandle').
981 		 */
982 
983 		if ((node = prom_instance_to_package(prom_stdin())) == 0) {
984 			printf("consinit: cannot convert stdin ihandle\n");
985 			inSource = -1;
986 			goto setup_output;
987 		}
988 
989 		if (prom_node_has_property(node, "keyboard")) {
990 			inSource = PROMDEV_KBD;
991 		} else if (strcmp(getpropstring(node, "device_type"),
992 				  "serial") == 0) {
993 			inSource = get_serial_promdev(0);
994 		} else {
995 			/* not serial, not keyboard. what is it?!? */
996 			inSource = -1;
997 		}
998 
999 setup_output:
1000 		if ((node = prom_instance_to_package(prom_stdout())) == 0) {
1001 			printf("consinit: cannot convert stdout ihandle\n");
1002 			outSink = -1;
1003 			goto setup_console;
1004 		}
1005 		devtype = getpropstring(node, "device_type");
1006 		if (strcmp(devtype, "display") == 0) {
1007 			/* frame buffer output */
1008 			outSink = PROMDEV_SCREEN;
1009 			fbnode = node;
1010 		} else if (strcmp(devtype, "serial") == 0) {
1011 			outSink = get_serial_promdev(1);
1012 		} else {
1013 			/* not screen, not serial. Whatzit? */
1014 			outSink = -1;
1015 		}
1016 		break;
1017 
1018 	default:
1019 		inSource = -1;
1020 		outSink = -1;
1021 	}
1022 
1023 setup_console:
1024 	if (inSource != outSink) {
1025 		printf("cninit: mismatched PROM output selector\n");
1026 		printf("inSource=%x; Sink=%x\n", inSource, outSink);
1027 	}
1028 
1029 	switch (inSource) {
1030 	default:
1031 		printf("cninit: invalid inSource=0x%x\n", inSource);
1032 		prom_abort();
1033 		inSource = PROMDEV_KBD;
1034 		/* fall through */
1035 
1036 	case 0:	/* keyboard/display */
1037 #if NKBD > 0
1038 		promzs_unit = 1;	/* XXX - config info! */
1039 		channel = 0;
1040 		cn = &consdev_kd;
1041 		/* Set cn_dev, cn_pri in kd.c */
1042 		break;
1043 #else	/* NKBD */
1044 		printf("cninit: kdb/display not configured\n");
1045 		callrom();
1046 		inSource = PROMDEV_TTYA;
1047 		/* fall through */
1048 #endif	/* NKBD */
1049 
1050 	case PROMDEV_TTYA:
1051 	case PROMDEV_TTYB:
1052 		zstty_unit = inSource - PROMDEV_TTYA;
1053 		promzs_unit = 0;	/* XXX - config info! */
1054 		channel = zstty_unit & 1;
1055 		cn = &consdev_tty;
1056 		cn->cn_dev = makedev(zs_major, zstty_unit);
1057 		cn->cn_pri = CN_REMOTE;
1058 		break;
1059 
1060 	}
1061 	/* Now that inSource has been validated, print it. */
1062 	printf("console is %s\n", prom_inSrc_name[inSource]);
1063 
1064 	zsd = findzs(promzs_unit);
1065 	if (zsd == NULL) {
1066 		printf("cninit: zs not mapped.\n");
1067 		return;
1068 	}
1069 	zc = (channel == 0) ? &zsd->zs_chan_a : &zsd->zs_chan_b;
1070 	zs_conschan = zc;
1071 	cn_tab = cn;
1072 	(*cn->cn_init)(cn);
1073 #ifdef	KGDB
1074 	zs_kgdb_init();
1075 #endif
1076 }
1077