xref: /netbsd-src/sys/arch/sun3/dev/zs.c (revision 81b108b45f75f89f1e3ffad9fb6f074e771c0935)
1 /*	$NetBSD: zs.c,v 1.39 1996/08/27 21:57:45 cgd Exp $	*/
2 
3 /*
4  * Copyright (c) 1995 Gordon W. Ross
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. The name of the author may not be used to endorse or promote products
16  *    derived from this software without specific prior written permission.
17  * 4. All advertising materials mentioning features or use of this software
18  *    must display the following acknowledgement:
19  *      This product includes software developed by Gordon Ross
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  * Zilog Z8530 Dual UART driver (machine-dependent part)
35  *
36  * Runs two serial lines per chip using slave drivers.
37  * Plain tty/async lines use the zs_async slave.
38  * Sun keyboard/mouse uses the zs_kbd/zs_ms slaves.
39  */
40 
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/proc.h>
44 #include <sys/device.h>
45 #include <sys/conf.h>
46 #include <sys/file.h>
47 #include <sys/ioctl.h>
48 #include <sys/tty.h>
49 #include <sys/time.h>
50 #include <sys/kernel.h>
51 #include <sys/syslog.h>
52 
53 #include <dev/cons.h>
54 #include <dev/ic/z8530reg.h>
55 #include <machine/z8530var.h>
56 
57 #include <machine/autoconf.h>
58 #include <machine/cpu.h>
59 #include <machine/isr.h>
60 #include <machine/obio.h>
61 #include <machine/mon.h>
62 
63 /*
64  * XXX: Hard code this to make console init easier...
65  */
66 #define	NZS	2		/* XXX */
67 
68 
69 /* The Sun3 provides a 4.9152 MHz clock to the ZS chips. */
70 #define PCLK	(9600 * 512)	/* PCLK pin input clock rate */
71 
72 /*
73  * Define interrupt levels.
74  */
75 #define ZSHARD_PRI	6	/* Wired on the CPU board... */
76 #define ZSSOFT_PRI	3	/* Want tty pri (4) but this is OK. */
77 
78 #define ZS_DELAY()			delay(2)
79 
80 /* The layout of this is hardware-dependent (padding, order). */
81 struct zschan {
82 	volatile u_char	zc_csr;		/* ctrl,status, and indirect access */
83 	u_char		zc_xxx0;
84 	volatile u_char	zc_data;	/* data */
85 	u_char		zc_xxx1;
86 };
87 struct zsdevice {
88 	/* Yes, they are backwards. */
89 	struct	zschan zs_chan_b;
90 	struct	zschan zs_chan_a;
91 };
92 
93 
94 /* Default OBIO addresses. */
95 static int zs_physaddr[NZS] = { OBIO_KEYBD_MS, OBIO_ZS };
96 /* Saved PROM mappings */
97 static struct zsdevice *zsaddr[NZS];	/* See zs_init() */
98 /* Flags from cninit() */
99 static int zs_hwflags[NZS][2];
100 /* Default speed for each channel */
101 static int zs_defspeed[NZS][2] = {
102 	{ 1200, 	/* keyboard */
103 	  1200 },	/* mouse */
104 	{ 9600, 	/* ttya */
105 	  9600 },	/* ttyb */
106 };
107 
108 
109 /* Find PROM mappings (for console support). */
110 void zs_init()
111 {
112 	int i;
113 
114 	for (i = 0; i < NZS; i++) {
115 		zsaddr[i] = (struct zsdevice *)
116 			obio_find_mapping(zs_physaddr[i], OBIO_ZS_SIZE);
117 	}
118 }
119 
120 
121 struct zschan *
122 zs_get_chan_addr(zsc_unit, channel)
123 	int zsc_unit, channel;
124 {
125 	struct zsdevice *addr;
126 	struct zschan *zc;
127 
128 	if (zsc_unit >= NZS)
129 		return NULL;
130 	addr = zsaddr[zsc_unit];
131 	if (addr == NULL)
132 		return NULL;
133 	if (channel == 0) {
134 		zc = &addr->zs_chan_a;
135 	} else {
136 		zc = &addr->zs_chan_b;
137 	}
138 	return (zc);
139 }
140 
141 
142 static u_char zs_init_reg[16] = {
143 	0,	/* 0: CMD (reset, etc.) */
144 	ZSWR1_RIE | ZSWR1_TIE | ZSWR1_SIE,
145 	0x18 + ZSHARD_PRI,	/* IVECT */
146 	ZSWR3_RX_8 | ZSWR3_RX_ENABLE,
147 	ZSWR4_CLK_X16 | ZSWR4_ONESB | ZSWR4_EVENP,
148 	ZSWR5_TX_8 | ZSWR5_TX_ENABLE,
149 	0,	/* 6: TXSYNC/SYNCLO */
150 	0,	/* 7: RXSYNC/SYNCHI */
151 	0,	/* 8: alias for data port */
152 	ZSWR9_MASTER_IE,
153 	0,	/*10: Misc. TX/RX control bits */
154 	ZSWR11_TXCLK_BAUD | ZSWR11_RXCLK_BAUD,
155 	14,	/*12: BAUDLO (default=9600) */
156 	0,	/*13: BAUDHI (default=9600) */
157 	ZSWR14_BAUD_FROM_PCLK | ZSWR14_BAUD_ENA,
158 	ZSWR15_BREAK_IE | ZSWR15_DCD_IE,
159 };
160 
161 
162 /****************************************************************
163  * Autoconfig
164  ****************************************************************/
165 
166 /* Definition of the driver for autoconfig. */
167 static int	zsc_match __P((struct device *, void *, void *));
168 static void	zsc_attach __P((struct device *, struct device *, void *));
169 static int  zsc_print __P((void *, const char *name));
170 
171 struct cfattach zsc_ca = {
172 	sizeof(struct zsc_softc), zsc_match, zsc_attach
173 };
174 
175 struct cfdriver zsc_cd = {
176 	NULL, "zsc", DV_DULL
177 };
178 
179 static int zshard(void *);
180 static int zssoft(void *);
181 
182 
183 /*
184  * Is the zs chip present?
185  */
186 static int
187 zsc_match(parent, vcf, aux)
188 	struct device *parent;
189 	void *vcf, *aux;
190 {
191 	struct cfdata *cf = vcf;
192 	struct confargs *ca = aux;
193 	int pa, unit, x;
194 	void *va;
195 
196 	unit = cf->cf_unit;
197 	if (unit < 0 || unit >= NZS)
198 		return (0);
199 
200 	/*
201 	 * OBIO match functions may be called for every possible
202 	 * physical address, so match only our physical address.
203 	 * This driver only supports its default mappings, so
204 	 * non-default locators must match our defaults.
205 	 */
206 	if ((pa = cf->cf_paddr) == -1) {
207 		/* Use our default PA. */
208 		pa = zs_physaddr[unit];
209 	} else {
210 		/* Validate the given PA. */
211 		if (pa != zs_physaddr[unit])
212 			return (0);
213 	}
214 	if (pa != ca->ca_paddr)
215 		return (0);
216 
217 	/* Make sure zs_init() found mappings. */
218 	va = zsaddr[unit];
219 	if (va == NULL)
220 		return (0);
221 
222 	/* This returns -1 on a fault (bus error). */
223 	x = peek_byte(va);
224 	return (x != -1);
225 }
226 
227 /*
228  * Attach a found zs.
229  *
230  * Match slave number to zs unit number, so that misconfiguration will
231  * not set up the keyboard as ttya, etc.
232  */
233 static void
234 zsc_attach(parent, self, aux)
235 	struct device *parent;
236 	struct device *self;
237 	void *aux;
238 {
239 	struct zsc_softc *zsc = (void *) self;
240 	struct cfdata *cf = self->dv_cfdata;
241 	struct confargs *ca = aux;
242 	struct zsc_attach_args zsc_args;
243 	volatile struct zschan *zc;
244 	struct zs_chanstate *cs;
245 	int zsc_unit, intpri, channel;
246 	int reset, s;
247 	static int didintr;
248 
249 	zsc_unit = zsc->zsc_dev.dv_unit;
250 
251 	if ((intpri = cf->cf_intpri) == -1)
252 		intpri = ZSHARD_PRI;
253 
254 	printf(" level %d (softpri %d)\n", intpri, ZSSOFT_PRI);
255 
256 	/* Use the mapping setup by the Sun PROM. */
257 	if (zsaddr[zsc_unit] == NULL)
258 		panic("zs_attach: zs%d not mapped\n", zsc_unit);
259 
260 	/*
261 	 * Initialize software state for each channel.
262 	 */
263 	for (channel = 0; channel < 2; channel++) {
264 		cs = &zsc->zsc_cs[channel];
265 
266 		zc = zs_get_chan_addr(zsc_unit, channel);
267 		cs->cs_reg_csr  = &zc->zc_csr;
268 		cs->cs_reg_data = &zc->zc_data;
269 
270 		cs->cs_channel = channel;
271 		cs->cs_private = NULL;
272 		cs->cs_ops = &zsops_null;
273 
274 		/* Define BAUD rate clock for the MI code. */
275 		cs->cs_brg_clk = PCLK / 16;
276 
277 		/* XXX: get defspeed from EEPROM instead? */
278 		cs->cs_defspeed = zs_defspeed[zsc_unit][channel];
279 
280 		bcopy(zs_init_reg, cs->cs_creg, 16);
281 		bcopy(zs_init_reg, cs->cs_preg, 16);
282 
283 		/*
284 		 * Clear the master interrupt enable.
285 		 * The INTENA is common to both channels,
286 		 * so just do it on the A channel.
287 		 */
288 		if (channel == 0) {
289 			zs_write_reg(cs, 9, 0);
290 		}
291 
292 		/*
293 		 * Look for a child driver for this channel.
294 		 * The child attach will setup the hardware.
295 		 */
296 		zsc_args.channel = channel;
297 		zsc_args.hwflags = zs_hwflags[zsc_unit][channel];
298 		if (config_found(self, (void *)&zsc_args, zsc_print) == NULL) {
299 			/* No sub-driver.  Just reset it. */
300 			reset = (channel == 0) ?
301 				ZSWR9_A_RESET : ZSWR9_B_RESET;
302 			s = splzs();
303 			zs_write_reg(cs,  9, reset);
304 			splx(s);
305 		}
306 	}
307 
308 	/* Now safe to install interrupt handlers */
309 	if (!didintr) {
310 		didintr = 1;
311 		isr_add_autovect(zssoft, NULL, ZSSOFT_PRI);
312 		isr_add_autovect(zshard, NULL, ZSHARD_PRI);
313 	}
314 
315 	/*
316 	 * Set the master interrupt enable and interrupt vector.
317 	 * (common to both channels, do it on A)
318 	 */
319 	cs = &zsc->zsc_cs[0];
320 	s = splzs();
321 	/* interrupt vector */
322 	zs_write_reg(cs, 2, zs_init_reg[2]);
323 	/* master interrupt control (enable) */
324 	zs_write_reg(cs, 9, zs_init_reg[9]);
325 	splx(s);
326 }
327 
328 static int
329 zsc_print(aux, name)
330 	void *aux;
331 	const char *name;
332 {
333 	struct zsc_attach_args *args = aux;
334 
335 	if (name != NULL)
336 		printf("%s: ", name);
337 
338 	if (args->channel != -1)
339 		printf(" channel %d", args->channel);
340 
341 	return UNCONF;
342 }
343 
344 static int
345 zshard(arg)
346 	void *arg;
347 {
348 	struct zsc_softc *zsc;
349 	int unit, rval;
350 
351 	/* Do ttya/ttyb first, because they go faster. */
352 	rval = 0;
353 	unit = zsc_cd.cd_ndevs;
354 	while (--unit >= 0) {
355 		zsc = zsc_cd.cd_devs[unit];
356 		if (zsc != NULL) {
357 			rval |= zsc_intr_hard(zsc);
358 		}
359 	}
360 	return (rval);
361 }
362 
363 int zssoftpending;
364 
365 void
366 zsc_req_softint(zsc)
367 	struct zsc_softc *zsc;
368 {
369 	if (zssoftpending == 0) {
370 		/* We are at splzs here, so no need to lock. */
371 		zssoftpending = ZSSOFT_PRI;
372 		isr_soft_request(ZSSOFT_PRI);
373 	}
374 }
375 
376 static int
377 zssoft(arg)
378 	void *arg;
379 {
380 	struct zsc_softc *zsc;
381 	int unit;
382 
383 	/* This is not the only ISR on this IPL. */
384 	if (zssoftpending == 0)
385 		return (0);
386 
387 	/*
388 	 * The soft intr. bit will be set by zshard only if
389 	 * the variable zssoftpending is zero.  The order of
390 	 * these next two statements prevents our clearing
391 	 * the soft intr bit just after zshard has set it.
392 	 */
393 	isr_soft_clear(ZSSOFT_PRI);
394 	zssoftpending = 0;
395 
396 	/* Do ttya/ttyb first, because they go faster. */
397 	unit = zsc_cd.cd_ndevs;
398 	while (--unit >= 0) {
399 		zsc = zsc_cd.cd_devs[unit];
400 		if (zsc != NULL) {
401 			(void) zsc_intr_soft(zsc);
402 		}
403 	}
404 	return (1);
405 }
406 
407 
408 /*
409  * Read or write the chip with suitable delays.
410  */
411 
412 u_char
413 zs_read_reg(cs, reg)
414 	struct zs_chanstate *cs;
415 	u_char reg;
416 {
417 	u_char val;
418 
419 	*cs->cs_reg_csr = reg;
420 	ZS_DELAY();
421 	val = *cs->cs_reg_csr;
422 	ZS_DELAY();
423 	return val;
424 }
425 
426 void
427 zs_write_reg(cs, reg, val)
428 	struct zs_chanstate *cs;
429 	u_char reg, val;
430 {
431 	*cs->cs_reg_csr = reg;
432 	ZS_DELAY();
433 	*cs->cs_reg_csr = val;
434 	ZS_DELAY();
435 }
436 
437 u_char zs_read_csr(cs)
438 	struct zs_chanstate *cs;
439 {
440 	register u_char v;
441 
442 	v = *cs->cs_reg_csr;
443 	ZS_DELAY();
444 	return v;
445 }
446 
447 u_char zs_read_data(cs)
448 	struct zs_chanstate *cs;
449 {
450 	register u_char v;
451 
452 	v = *cs->cs_reg_data;
453 	ZS_DELAY();
454 	return v;
455 }
456 
457 void  zs_write_csr(cs, val)
458 	struct zs_chanstate *cs;
459 	u_char val;
460 {
461 	*cs->cs_reg_csr = val;
462 	ZS_DELAY();
463 }
464 
465 void  zs_write_data(cs, val)
466 	struct zs_chanstate *cs;
467 	u_char val;
468 {
469 	*cs->cs_reg_data = val;
470 	ZS_DELAY();
471 }
472 
473 /****************************************************************
474  * Console support functions (Sun3 specific!)
475  ****************************************************************/
476 
477 /*
478  * Polled input char.
479  */
480 int
481 zs_getc(arg)
482 	void *arg;
483 {
484 	register volatile struct zschan *zc = arg;
485 	register int s, c, rr0;
486 
487 	s = splhigh();
488 	/* Wait for a character to arrive. */
489 	do {
490 		rr0 = zc->zc_csr;
491 		ZS_DELAY();
492 	} while ((rr0 & ZSRR0_RX_READY) == 0);
493 
494 	c = zc->zc_data;
495 	ZS_DELAY();
496 	splx(s);
497 
498 	/*
499 	 * This is used by the kd driver to read scan codes,
500 	 * so don't translate '\r' ==> '\n' here...
501 	 */
502 	return (c);
503 }
504 
505 /*
506  * Polled output char.
507  */
508 void
509 zs_putc(arg, c)
510 	void *arg;
511 	int c;
512 {
513 	register volatile struct zschan *zc = arg;
514 	register int s, rr0;
515 
516 	s = splhigh();
517 	/* Wait for transmitter to become ready. */
518 	do {
519 		rr0 = zc->zc_csr;
520 		ZS_DELAY();
521 	} while ((rr0 & ZSRR0_TX_READY) == 0);
522 
523 	zc->zc_data = c;
524 	ZS_DELAY();
525 	splx(s);
526 }
527 
528 extern struct consdev consdev_kd;	/* keyboard/display */
529 extern struct consdev consdev_tty;
530 extern struct consdev *cn_tab;	/* physical console device info */
531 extern void nullcnpollc();
532 
533 void *zs_conschan;
534 
535 /*
536  * This function replaces sys/dev/cninit.c
537  * Determine which device is the console using
538  * the PROM "input source" and "output sink".
539  */
540 void
541 cninit()
542 {
543 	MachMonRomVector *v;
544 	struct zschan *zc;
545 	struct consdev *cn;
546 	int zsc_unit, channel;
547 	char inSource;
548 
549 	v = romVectorPtr;
550 	inSource = *(v->inSource);
551 
552 	if (inSource != *(v->outSink)) {
553 		mon_printf("cninit: mismatched PROM output selector\n");
554 	}
555 
556 	switch (inSource) {
557 
558 	case 1:	/* ttya */
559 	case 2:	/* ttyb */
560 		zsc_unit = 1;
561 		channel = inSource - 1;
562 		cn = &consdev_tty;
563 		cn->cn_dev = makedev(ZSTTY_MAJOR, channel);
564 		cn->cn_pri = CN_REMOTE;
565 		break;
566 
567 	case 3:	/* ttyc (rewired keyboard connector) */
568 	case 4:	/* ttyd (rewired mouse connector)   */
569 		zsc_unit = 0;
570 		channel = inSource - 3;
571 		cn = &consdev_tty;
572 		cn->cn_dev = makedev(ZSTTY_MAJOR, (channel+2));
573 		cn->cn_pri = CN_REMOTE;
574 		break;
575 
576 	default:
577 		mon_printf("cninit: invalid PROM console selector\n");
578 		/* assume keyboard/display */
579 		/* fallthrough */
580 	case 0:	/* keyboard/display */
581 		zsc_unit = 0;
582 		channel = 0;
583 		cn = &consdev_kd;
584 		/* Set cn_dev, cn_pri in kd.c */
585 		break;
586 	}
587 
588 	zc = zs_get_chan_addr(zsc_unit, channel);
589 	if (zc == NULL) {
590 		mon_printf("cninit: zs not mapped.\n");
591 		return;
592 	}
593 	zs_conschan = zc;
594 	zs_hwflags[zsc_unit][channel] = ZS_HWFLAG_CONSOLE;
595 	cn_tab = cn;
596 	(*cn->cn_init)(cn);
597 }
598 
599 
600 /* We never call this. */
601 void
602 nullcnprobe(cn)
603 	struct consdev *cn;
604 {
605 }
606 
607 void
608 zscninit(cn)
609 	struct consdev *cn;
610 {
611 	int unit = minor(cn->cn_dev) & 1;
612 
613 	mon_printf("console is zstty%d (tty%c)\n",
614 		   unit, unit + 'a');
615 }
616 
617 /*
618  * Polled console input putchar.
619  */
620 int
621 zscngetc(dev)
622 	dev_t dev;
623 {
624 	register volatile struct zschan *zc = zs_conschan;
625 	register int c;
626 
627 	c = zs_getc(zc);
628 	return (c);
629 }
630 
631 /*
632  * Polled console output putchar.
633  */
634 void
635 zscnputc(dev, c)
636 	dev_t dev;
637 	int c;
638 {
639 	register volatile struct zschan *zc = zs_conschan;
640 
641 	zs_putc(zc, c);
642 }
643 
644 
645 struct consdev consdev_tty = {
646 	nullcnprobe,
647 	zscninit,
648 	zscngetc,
649 	zscnputc,
650 	nullcnpollc,
651 };
652 
653 
654 /*
655  * Handle user request to enter kernel debugger.
656  */
657 void
658 zs_abort()
659 {
660 	register volatile struct zschan *zc = zs_conschan;
661 	int rr0;
662 
663 	/* Wait for end of break to avoid PROM abort. */
664 	/* XXX - Limit the wait? */
665 	do {
666 		rr0 = zc->zc_csr;
667 		ZS_DELAY();
668 	} while (rr0 & ZSRR0_BREAK);
669 
670 	/* XXX - Always available, but may be the PROM monitor. */
671 	Debugger();
672 }
673