xref: /openbsd/sys/arch/macppc/dev/zs.c (revision 9593dc34)
1 /*	$OpenBSD: zs.c,v 1.34 2024/09/04 07:54:51 mglocker Exp $	*/
2 /*	$NetBSD: zs.c,v 1.17 2001/06/19 13:42:15 wiz Exp $	*/
3 
4 /*
5  * Copyright (c) 1996, 1998 Bill Studenmund
6  * Copyright (c) 1995 Gordon W. Ross
7  * All rights reserved.
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  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 /*
31  * Zilog Z8530 Dual UART driver (machine-dependent part)
32  *
33  * Runs two serial lines per chip using slave drivers.
34  * Plain tty/async lines use the zstty slave.
35  * Sun keyboard/mouse uses the zskbd/zsms slaves.
36  * Other ports use their own mice & keyboard slaves.
37  *
38  * Credits & history:
39  *
40  * With NetBSD 1.1, port-mac68k started using a port of the port-sparc
41  * (port-sun3?) zs.c driver (which was in turn based on code in the
42  * Berkeley 4.4 Lite release). Bill Studenmund did the port, with
43  * help from Allen Briggs and Gordon Ross <gwr@netbsd.org>. Noud de
44  * Brouwer field-tested the driver at a local ISP.
45  *
46  * Bill Studenmund and Gordon Ross then ported the machine-independent
47  * z8530 driver to work with port-mac68k. NetBSD 1.2 contained an
48  * intermediate version (mac68k using a local, patched version of
49  * the m.i. drivers), with NetBSD 1.3 containing a full version.
50  */
51 
52 #include <sys/param.h>
53 #include <sys/systm.h>
54 #include <sys/proc.h>
55 #include <sys/device.h>
56 #include <sys/conf.h>
57 #include <sys/ioctl.h>
58 #include <sys/tty.h>
59 #include <sys/time.h>
60 #include <sys/kernel.h>
61 #include <sys/syslog.h>
62 
63 #include <dev/cons.h>
64 #include <dev/ofw/openfirm.h>
65 #include <dev/ic/z8530reg.h>
66 
67 #include <machine/z8530var.h>
68 #include <machine/autoconf.h>
69 #include <machine/cpu.h>
70 
71 #include "zs.h"
72 
73 /*
74  * Some warts needed by z8530tty.c -
75  */
76 int zs_def_cflag = (CREAD | CS8 | HUPCL);
77 int zs_major = 7;
78 
79 struct zsdevice {
80 	/* Yes, they are backwards. */
81 	struct	zschan zs_chan_b;
82 	struct	zschan zs_chan_a;
83 };
84 
85 /* Flags from cninit() */
86 static int zs_hwflags[NZS][2];
87 /* Default speed for each channel */
88 static int zs_defspeed[NZS][2] = {
89 	{ 38400,	/* tty00 */
90 	  38400 },	/* tty01 */
91 };
92 
93 /* console stuff */
94 void	*zs_conschan = 0;
95 #ifdef	ZS_CONSOLE_ABORT
96 int	zs_cons_canabort = 1;
97 #else
98 int	zs_cons_canabort = 0;
99 #endif /* ZS_CONSOLE_ABORT*/
100 
101 /* device to which the console is attached--if serial. */
102 /* Mac stuff */
103 
104 int zs_get_speed(struct zs_chanstate *);
105 
106 /*
107  * Even though zsparam will set up the clock multiples, etc., we
108  * still set them here as: 1) mice & keyboards don't use zsparam,
109  * and 2) the console stuff uses these defaults before device
110  * attach.
111  */
112 
113 static u_char zs_init_reg[16] = {
114 	0,	/* 0: CMD (reset, etc.) */
115 	ZSWR1_RIE | ZSWR1_TIE | ZSWR1_SIE, 	/* 1: No interrupts yet. ??? */
116 	0,	/* IVECT */
117 	ZSWR3_RX_8 | ZSWR3_RX_ENABLE,
118 	ZSWR4_CLK_X16 | ZSWR4_ONESB | ZSWR4_EVENP,
119 	ZSWR5_TX_8 | ZSWR5_TX_ENABLE,
120 	0,	/* 6: TXSYNC/SYNCLO */
121 	0,	/* 7: RXSYNC/SYNCHI */
122 	0,	/* 8: alias for data port */
123 	ZSWR9_MASTER_IE,
124 	0,	/*10: Misc. TX/RX control bits */
125 	ZSWR11_TXCLK_BAUD | ZSWR11_RXCLK_BAUD,
126 	((PCLK/32)/38400)-2,	/*12: BAUDLO (default=38400) */
127 	0,			/*13: BAUDHI (default=38400) */
128 	ZSWR14_BAUD_ENA,
129 	ZSWR15_BREAK_IE,
130 };
131 
132 /****************************************************************
133  * Autoconfig
134  ****************************************************************/
135 
136 struct cfdriver zs_cd = {
137 	NULL, "zs", DV_TTY
138 };
139 
140 /* Definition of the driver for autoconfig. */
141 int	zs_match(struct device *, void *, void *);
142 void	zs_attach(struct device *, struct device *, void *);
143 int	zs_print(void *, const char *name);
144 
145 /* Power management hooks */
146 int  zs_enable (struct zs_chanstate *);
147 void zs_disable (struct zs_chanstate *);
148 
149 const struct cfattach zs_ca = {
150 	sizeof(struct zsc_softc), zs_match, zs_attach
151 };
152 
153 int zshard(void *);
154 void zssoft(void *);
155 #ifdef ZS_TXDMA
156 int zs_txdma_int(void *);
157 #endif
158 
159 /*
160  * Is the zs chip present?
161  */
162 int
zs_match(struct device * parent,void * match,void * aux)163 zs_match(struct device *parent, void *match, void *aux)
164 {
165 	struct confargs *ca = aux;
166 	struct cfdata *cf = match;
167 
168 	if (strcmp(ca->ca_name, "escc") != 0)
169 		return 0;
170 
171 	if (ca->ca_nreg < 8)
172 		return 0;
173 
174 	if (cf->cf_unit > 1)
175 		return 0;
176 
177 	return 1;
178 }
179 
180 /*
181  * Attach a found zs.
182  *
183  * Match slave number to zs unit number, so that misconfiguration will
184  * not set up the keyboard as ttya, etc.
185  */
186 void
zs_attach(struct device * parent,struct device * self,void * aux)187 zs_attach(struct device *parent, struct device *self, void *aux)
188 {
189 	struct zsc_softc *zsc = (void *)self;
190 	struct confargs *ca = aux;
191 	struct zsc_attach_args zsc_args;
192 	volatile struct zschan *zc;
193 	struct xzs_chanstate *xcs;
194 	struct zs_chanstate *cs;
195 	struct zsdevice *zsd;
196 	int zs_unit, channel;
197 	int s;
198 	int node, intr[3][3];
199 	u_int regs[16];
200 
201 	zs_unit = zsc->zsc_dev.dv_unit;
202 
203 	zsd = mapiodev(ca->ca_baseaddr + ca->ca_reg[0], ca->ca_reg[1]);
204 	node = OF_child(ca->ca_node);	/* ch-a */
205 
206 	for (channel = 0; channel < 2; channel++) {
207 		if (OF_getprop(node, "AAPL,interrupts",
208 			       intr[channel], sizeof(intr[0])) == -1 &&
209 		    OF_getprop(node, "interrupts",
210 			       intr[channel], sizeof(intr[0])) == -1) {
211 			printf(": cannot find interrupt property\n");
212 			return;
213 		}
214 
215 		if (OF_getprop(node, "reg", regs, sizeof(regs)) < 24) {
216 			printf(": cannot find reg property\n");
217 			return;
218 		}
219 		regs[2] += ca->ca_baseaddr;
220 		regs[4] += ca->ca_baseaddr;
221 #ifdef ZS_TXDMA
222 		zsc->zsc_txdmareg[channel] = mapiodev(regs[2], regs[3]);
223 		zsc->zsc_txdmacmd[channel] =
224 			dbdma_alloc(sizeof(dbdma_command_t) * 3);
225 		memset(zsc->zsc_txdmacmd[channel], 0,
226 			sizeof(dbdma_command_t) * 3);
227 		dbdma_reset(zsc->zsc_txdmareg[channel]);
228 #endif
229 		node = OF_peer(node);	/* ch-b */
230 	}
231 
232 	printf(": irq %d,%d\n", intr[0][0], intr[1][0]);
233 
234 	/*
235 	 * Initialize software state for each channel.
236 	 */
237 	for (channel = 0; channel < 2; channel++) {
238 		zsc_args.channel = channel;
239 		zsc_args.hwflags = zs_hwflags[zs_unit][channel];
240 		xcs = &zsc->xzsc_xcs_store[channel];
241 		cs  = &xcs->xzs_cs;
242 		zsc->zsc_cs[channel] = cs;
243 
244 		cs->cs_channel = channel;
245 		cs->cs_private = NULL;
246 		cs->cs_ops = &zsops_null;
247 
248 		zc = (channel == 0) ? &zsd->zs_chan_a : &zsd->zs_chan_b;
249 
250 		cs->cs_reg_csr  = &zc->zc_csr;
251 		cs->cs_reg_data = &zc->zc_data;
252 
253 		memcpy(cs->cs_creg, zs_init_reg, 16);
254 		memcpy(cs->cs_preg, zs_init_reg, 16);
255 
256 		/* Current BAUD rate generator clock. */
257 		/* RTxC is 230400*16, so use 230400 */
258 		cs->cs_brg_clk = PCLK / 16;
259 		if (zsc_args.hwflags & ZS_HWFLAG_CONSOLE)
260 			cs->cs_defspeed = zs_get_speed(cs);
261 		else
262 			cs->cs_defspeed =
263 			    zs_defspeed[zs_unit][channel];
264 		cs->cs_defcflag = zs_def_cflag;
265 
266 		/* Make these correspond to cs_defcflag (-crtscts) */
267 		cs->cs_rr0_dcd = ZSRR0_DCD;
268 		cs->cs_rr0_cts = 0;
269 		cs->cs_wr5_dtr = ZSWR5_DTR;
270 		cs->cs_wr5_rts = 0;
271 
272 #ifdef __notyet__
273 		cs->cs_slave_type = ZS_SLAVE_NONE;
274 #endif
275 
276 		/* Define BAUD rate stuff. */
277 		xcs->cs_clocks[0].clk = PCLK;
278 		xcs->cs_clocks[0].flags = ZSC_RTXBRG | ZSC_RTXDIV;
279 		xcs->cs_clocks[1].flags =
280 			ZSC_RTXBRG | ZSC_RTXDIV | ZSC_VARIABLE | ZSC_EXTERN;
281 		xcs->cs_clocks[2].flags = ZSC_TRXDIV | ZSC_VARIABLE;
282 		xcs->cs_clock_count = 3;
283 		if (channel == 0) {
284 			/*xcs->cs_clocks[1].clk = mac68k_machine.modem_dcd_clk;*/
285 			/*xcs->cs_clocks[2].clk = mac68k_machine.modem_cts_clk;*/
286 			xcs->cs_clocks[1].clk = 0;
287 			xcs->cs_clocks[2].clk = 0;
288 		} else {
289 			xcs->cs_clocks[1].flags = ZSC_VARIABLE;
290 			/*
291 			 * Yes, we aren't defining ANY clock source enables for the
292 			 * printer's DCD clock in. The hardware won't let us
293 			 * use it. But a clock will freak out the chip, so we
294 			 * let you set it, telling us to bar interrupts on the line.
295 			 */
296 			/*xcs->cs_clocks[1].clk = mac68k_machine.print_dcd_clk;*/
297 			/*xcs->cs_clocks[2].clk = mac68k_machine.print_cts_clk;*/
298 			xcs->cs_clocks[1].clk = 0;
299 			xcs->cs_clocks[2].clk = 0;
300 		}
301 		if (xcs->cs_clocks[1].clk)
302 			zsc_args.hwflags |= ZS_HWFLAG_NO_DCD;
303 		if (xcs->cs_clocks[2].clk)
304 			zsc_args.hwflags |= ZS_HWFLAG_NO_CTS;
305 
306 		/* Set defaults in our "extended" chanstate. */
307 		xcs->cs_csource = 0;
308 		xcs->cs_psource = 0;
309 		xcs->cs_cclk_flag = 0;  /* Nothing fancy by default */
310 		xcs->cs_pclk_flag = 0;
311 
312 		/*
313 		 * We used to disable chip interrupts here, but we now
314 		 * do that in zscnprobe, just in case MacOS left the chip on.
315 		 */
316 
317 		xcs->cs_chip = 0;
318 
319 		/* Stash away a copy of the final H/W flags. */
320 		xcs->cs_hwflags = zsc_args.hwflags;
321 
322 		/*
323 		 * Look for a child driver for this channel.
324 		 * The child attach will setup the hardware.
325 		 */
326 		if (!config_found(self, (void *)&zsc_args, zs_print)) {
327 			/* No sub-driver.  Just reset it. */
328 			u_char reset = (channel == 0) ?
329 				ZSWR9_A_RESET : ZSWR9_B_RESET;
330 			s = splzs();
331 			zs_write_reg(cs, 9, reset);
332 			splx(s);
333 		}
334 	}
335 
336 	/* XXX - Now safe to install interrupt handlers. */
337 	mac_intr_establish(parent, intr[0][0], IST_LEVEL, IPL_TTY,
338 	    zshard, NULL, "zs0");
339 	mac_intr_establish(parent, intr[1][0], IST_LEVEL, IPL_TTY,
340 	    zshard, NULL, "zs1");
341 #ifdef ZS_TXDMA
342 	mac_intr_establish(parent, intr[0][1], IST_LEVEL, IPL_TTY,
343 	    zs_txdma_int, NULL, "zsdma0");
344 	mac_intr_establish(parent, intr[1][1], IST_LEVEL, IPL_TTY,
345 	    zs_txdma_int, (void *)1, "zsdma1");
346 #endif
347 	zsc->zsc_softintr = softintr_establish(IPL_SOFTTTY, zssoft, zsc);
348 	if (zsc->zsc_softintr == NULL)
349 		panic("zsattach: could not establish soft interrupt");
350 
351 	/*
352 	 * Set the master interrupt enable and interrupt vector.
353 	 * (common to both channels, do it on A)
354 	 */
355 	cs = zsc->zsc_cs[0];
356 	s = splzs();
357 	/* interrupt vector */
358 	zs_write_reg(cs, 2, zs_init_reg[2]);
359 	/* master interrupt control (enable) */
360 	zs_write_reg(cs, 9, zs_init_reg[9]);
361 	splx(s);
362 
363 	/* connect power management for port 0 */
364 	cs->enable = zs_enable;
365 	cs->disable = zs_disable;
366 }
367 
368 int
zs_print(void * aux,const char * name)369 zs_print(void *aux, const char *name)
370 {
371 	struct zsc_attach_args *args = aux;
372 
373 	if (name != NULL)
374 		printf("%s: ", name);
375 
376 	if (args->channel != -1)
377 		printf(" channel %d", args->channel);
378 
379 	return UNCONF;
380 }
381 
382 int
zsmdioctl(struct zs_chanstate * cs,u_long cmd,caddr_t data)383 zsmdioctl(struct zs_chanstate *cs, u_long cmd, caddr_t data)
384 {
385 	switch (cmd) {
386 	default:
387 		return (-1);
388 	}
389 	return (0);
390 }
391 
392 void
zsmd_setclock(struct zs_chanstate * cs)393 zsmd_setclock(struct zs_chanstate *cs)
394 {
395 #ifdef NOTYET
396 	struct xzs_chanstate *xcs = (void *)cs;
397 
398 	if (cs->cs_channel != 0)
399 		return;
400 
401 	/*
402 	 * If the new clock has the external bit set, then select the
403 	 * external source.
404 	 */
405 	via_set_modem((xcs->cs_pclk_flag & ZSC_EXTERN) ? 1 : 0);
406 #endif
407 }
408 
409 static int zssoftpending;
410 
411 /*
412  * Our ZS chips all share a common, autovectored interrupt,
413  * so we have to look at all of them on each interrupt.
414  */
415 int
zshard(void * arg)416 zshard(void *arg)
417 {
418 	struct zsc_softc *zsc;
419 	int unit, rval;
420 
421 	rval = 0;
422 	for (unit = 0; unit < zs_cd.cd_ndevs; unit++) {
423 		zsc = zs_cd.cd_devs[unit];
424 		if (zsc == NULL)
425 			continue;
426 		rval |= zsc_intr_hard(zsc);
427 		if (zsc->zsc_cs[0]->cs_softreq)
428 		{
429 			/* zs_req_softint(zsc); */
430 			/* We are at splzs here, so no need to lock. */
431 			if (zssoftpending == 0) {
432 				zssoftpending = 1;
433 				softintr_schedule(zsc->zsc_softintr);
434 			}
435 		}
436 	}
437 	return (rval);
438 }
439 
440 /*
441  * Similar scheme as for zshard (look at all of them)
442  */
443 void
zssoft(void * arg)444 zssoft(void *arg)
445 {
446 	struct zsc_softc *zsc;
447 	int unit;
448 
449 	/* This is not the only ISR on this IPL. */
450 	if (zssoftpending == 0)
451 		return;
452 
453 	/*
454 	 * The soft intr. bit will be set by zshard only if
455 	 * the variable zssoftpending is zero.
456 	 */
457 	zssoftpending = 0;
458 
459 	for (unit = 0; unit < zs_cd.cd_ndevs; ++unit) {
460 		zsc = zs_cd.cd_devs[unit];
461 		if (zsc == NULL)
462 			continue;
463 		(void) zsc_intr_soft(zsc);
464 	}
465 }
466 
467 #ifdef ZS_TXDMA
468 int
zs_txdma_int(void * arg)469 zs_txdma_int(void *arg)
470 {
471 	int ch = (int)arg;
472 	struct zsc_softc *zsc;
473 	struct zs_chanstate *cs;
474 	int unit = 0;			/* XXX */
475 	extern int zstty_txdma_int();
476 
477 	zsc = zs_cd.cd_devs[unit];
478 	if (zsc == NULL)
479 		panic("zs_txdma_int");
480 
481 	cs = zsc->zsc_cs[ch];
482 	zstty_txdma_int(cs);
483 
484 	if (cs->cs_softreq) {
485 		if (zssoftpending == 0) {
486 			zssoftpending = 1;
487 			softintr_schedule(zsc->zsc_softintr);
488 		}
489 	}
490 	return 1;
491 }
492 
493 void
zs_dma_setup(struct zs_chanstate * cs,caddr_t pa,int len)494 zs_dma_setup(struct zs_chanstate *cs, caddr_t pa, int len)
495 {
496 	struct zsc_softc *zsc;
497 	dbdma_command_t *cmdp;
498 	int ch = cs->cs_channel;
499 
500 	zsc = zs_cd.cd_devs[ch];
501 	cmdp = zsc->zsc_txdmacmd[ch];
502 
503 	DBDMA_BUILD(cmdp, DBDMA_CMD_OUT_LAST, 0, len, kvtop(pa),
504 		DBDMA_INT_ALWAYS, DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER);
505 	cmdp++;
506 	DBDMA_BUILD(cmdp, DBDMA_CMD_STOP, 0, 0, 0,
507 		DBDMA_INT_NEVER, DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER);
508 
509 	__asm volatile("eieio");
510 
511 	dbdma_start(zsc->zsc_txdmareg[ch], zsc->zsc_txdmacmd[ch]);
512 }
513 #endif
514 
515 /*
516  * Compute the current baud rate given a ZS channel.
517  * XXX Assume internal BRG.
518  */
519 int
zs_get_speed(struct zs_chanstate * cs)520 zs_get_speed(struct zs_chanstate *cs)
521 {
522 	int tconst;
523 
524 	tconst = zs_read_reg(cs, 12);
525 	tconst |= zs_read_reg(cs, 13) << 8;
526 	return TCONST_TO_BPS(cs->cs_brg_clk, tconst);
527 }
528 
529 #ifndef ZS_TOLERANCE
530 #define ZS_TOLERANCE 51
531 /* 5% in tenths of a %, plus 1 so that exactly 5% will be ok. */
532 #endif
533 
534 /*
535  * Search through the signal sources in the channel, and
536  * pick the best one for the baud rate requested. Return
537  * a -1 if not achievable in tolerance. Otherwise return 0
538  * and fill in the values.
539  *
540  * This routine draws inspiration from the Atari port's zs.c
541  * driver in NetBSD 1.1 which did the same type of source switching.
542  * Tolerance code inspired by comspeed routine in isa/com.c.
543  *
544  * By Bill Studenmund, 1996-05-12
545  */
546 int
zs_set_speed(struct zs_chanstate * cs,int bps)547 zs_set_speed(struct zs_chanstate *cs, int bps)
548 {
549 	struct xzs_chanstate *xcs = (void *)cs;
550 	int i, tc, tc0 = 0, tc1, s, sf = 0;
551 	int src, rate0, rate1, err, tol;
552 
553 	if (bps == 0)
554 		return (0);
555 
556 	src = -1;		/* no valid source yet */
557 	tol = ZS_TOLERANCE;
558 
559 	/*
560 	 * Step through all the sources and see which one matches
561 	 * the best. A source has to match BETTER than tol to be chosen.
562 	 * Thus if two sources give the same error, the first one will be
563 	 * chosen. Also, allow for the possibility that one source might run
564 	 * both the BRG and the direct divider (i.e. RTxC).
565 	 */
566 	for (i = 0; i < xcs->cs_clock_count; i++) {
567 		if (xcs->cs_clocks[i].clk <= 0)
568 			continue;	/* skip non-existent or bad clocks */
569 		if (xcs->cs_clocks[i].flags & ZSC_BRG) {
570 			/* check out BRG at /16 */
571 			tc1 = BPS_TO_TCONST(xcs->cs_clocks[i].clk >> 4, bps);
572 			if (tc1 >= 0) {
573 				rate1 = TCONST_TO_BPS(xcs->cs_clocks[i].clk >> 4, tc1);
574 				err = abs(((rate1 - bps)*1000)/bps);
575 				if (err < tol) {
576 					tol = err;
577 					src = i;
578 					sf = xcs->cs_clocks[i].flags & ~ZSC_DIV;
579 					tc0 = tc1;
580 					rate0 = rate1;
581 				}
582 			}
583 		}
584 		if (xcs->cs_clocks[i].flags & ZSC_DIV) {
585 			/*
586 			 * Check out either /1, /16, /32, or /64
587 			 * Note: for /1, you'd better be using a synchronized
588 			 * clock!
589 			 */
590 			int b0 = xcs->cs_clocks[i].clk, e0 = abs(b0-bps);
591 			int b1 = b0 >> 4, e1 = abs(b1-bps);
592 			int b2 = b1 >> 1, e2 = abs(b2-bps);
593 			int b3 = b2 >> 1, e3 = abs(b3-bps);
594 
595 			if (e0 < e1 && e0 < e2 && e0 < e3) {
596 				err = e0;
597 				rate1 = b0;
598 				tc1 = ZSWR4_CLK_X1;
599 			} else if (e0 > e1 && e1 < e2  && e1 < e3) {
600 				err = e1;
601 				rate1 = b1;
602 				tc1 = ZSWR4_CLK_X16;
603 			} else if (e0 > e2 && e1 > e2 && e2 < e3) {
604 				err = e2;
605 				rate1 = b2;
606 				tc1 = ZSWR4_CLK_X32;
607 			} else {
608 				err = e3;
609 				rate1 = b3;
610 				tc1 = ZSWR4_CLK_X64;
611 			}
612 
613 			err = (err * 1000)/bps;
614 			if (err < tol) {
615 				tol = err;
616 				src = i;
617 				sf = xcs->cs_clocks[i].flags & ~ZSC_BRG;
618 				tc0 = tc1;
619 				rate0 = rate1;
620 			}
621 		}
622 	}
623 #ifdef ZSMACDEBUG
624 	printf("Checking for rate %d. Found source #%d.\n",bps, src);
625 #endif
626 	if (src == -1)
627 		return (EINVAL); /* no can do */
628 
629 	/*
630 	 * The M.I. layer likes to keep cs_brg_clk current, even though
631 	 * we are the only ones who should be touching the BRG's rate.
632 	 *
633 	 * Note: we are assuming that any ZSC_EXTERN signal source comes in
634 	 * on the RTxC pin. Correct for the mac68k obio zsc.
635 	 */
636 	if (sf & ZSC_EXTERN)
637 		cs->cs_brg_clk = xcs->cs_clocks[i].clk >> 4;
638 	else
639 		cs->cs_brg_clk = PCLK / 16;
640 
641 	/*
642 	 * Now we have a source, so set it up.
643 	 */
644 	s = splzs();
645 	xcs->cs_psource = src;
646 	xcs->cs_pclk_flag = sf;
647 	bps = rate0;
648 	if (sf & ZSC_BRG) {
649 		cs->cs_preg[4] = ZSWR4_CLK_X16;
650 		cs->cs_preg[11]= ZSWR11_RXCLK_BAUD | ZSWR11_TXCLK_BAUD;
651 		if (sf & ZSC_PCLK) {
652 			cs->cs_preg[14] = ZSWR14_BAUD_ENA | ZSWR14_BAUD_FROM_PCLK;
653 		} else {
654 			cs->cs_preg[14] = ZSWR14_BAUD_ENA;
655 		}
656 		tc = tc0;
657 	} else {
658 		cs->cs_preg[4] = tc0;
659 		if (sf & ZSC_RTXDIV) {
660 			cs->cs_preg[11] = ZSWR11_RXCLK_RTXC | ZSWR11_TXCLK_RTXC;
661 		} else {
662 			cs->cs_preg[11] = ZSWR11_RXCLK_TRXC | ZSWR11_TXCLK_TRXC;
663 		}
664 		cs->cs_preg[14]= 0;
665 		tc = 0xffff;
666 	}
667 	/* Set the BAUD rate divisor. */
668 	cs->cs_preg[12] = tc;
669 	cs->cs_preg[13] = tc >> 8;
670 	splx(s);
671 
672 #ifdef ZSMACDEBUG
673 	printf("Rate is %7d, tc is %7d, source no. %2d, flags %4x\n", \
674 	    bps, tc, src, sf);
675 	printf("Registers are: 4 %x, 11 %x, 14 %x\n\n",
676 		cs->cs_preg[4], cs->cs_preg[11], cs->cs_preg[14]);
677 #endif
678 
679 	cs->cs_preg[5] |= ZSWR5_RTS;	/* Make sure the drivers are on! */
680 
681 	/* Caller will stuff the pending registers. */
682 	return (0);
683 }
684 
685 int
zs_set_modes(struct zs_chanstate * cs,int cflag)686 zs_set_modes(struct zs_chanstate *cs, int cflag)
687 {
688 	struct xzs_chanstate *xcs = (void*)cs;
689 	int s;
690 
691 	/*
692 	 * Make sure we don't enable hfc on a signal line we're ignoring.
693 	 * As we enable CTS interrupts only if we have CRTSCTS or CDTRCTS,
694 	 * this code also effectively turns off ZSWR15_CTS_IE.
695 	 *
696 	 * Also, disable DCD interrupts if we've been told to ignore
697 	 * the DCD pin. Happens on mac68k because the input line for
698 	 * DCD can also be used as a clock input.  (Just set CLOCAL.)
699 	 *
700 	 * If someone tries to turn an invalid flow mode on, Just Say No
701 	 * (Suggested by gwr)
702 	 */
703 	if (xcs->cs_hwflags & ZS_HWFLAG_NO_DCD) {
704 		if (cflag & MDMBUF)
705 			return (EINVAL);
706 		cflag |= CLOCAL;
707 	}
708 #if 0
709 	if ((xcs->cs_hwflags & ZS_HWFLAG_NO_CTS) && (cflag & CRTSCTS))
710 		return (EINVAL);
711 #endif
712 
713 	/*
714 	 * Output hardware flow control on the chip is horrendous:
715 	 * if carrier detect drops, the receiver is disabled, and if
716 	 * CTS drops, the transmitter is stopped IN MID CHARACTER!
717 	 * Therefore, NEVER set the HFC bit, and instead use the
718 	 * status interrupt to detect CTS changes.
719 	 */
720 	s = splzs();
721 	if ((cflag & (CLOCAL | MDMBUF)) != 0)
722 		cs->cs_rr0_dcd = 0;
723 	else
724 		cs->cs_rr0_dcd = ZSRR0_DCD;
725 	/*
726 	 * The mac hardware only has one output, DTR (HSKo in Mac
727 	 * parlance). In HFC mode, we use it for the functions
728 	 * typically served by RTS and DTR on other ports, so we
729 	 * have to fake the upper layer out some.
730 	 *
731 	 * CRTSCTS we use CTS as an input which tells us when to shut up.
732 	 * We make no effort to shut up the other side of the connection.
733 	 * DTR is used to hang up the modem.
734 	 *
735 	 * In CDTRCTS, we use CTS to tell us to stop, but we use DTR to
736 	 * shut up the other side.
737 	 */
738 	if ((cflag & CRTSCTS) != 0) {
739 		cs->cs_wr5_dtr = ZSWR5_DTR;
740 		cs->cs_wr5_rts = 0;
741 		cs->cs_rr0_cts = ZSRR0_CTS;
742 #if 0
743 	} else if ((cflag & CDTRCTS) != 0) {
744 		cs->cs_wr5_dtr = 0;
745 		cs->cs_wr5_rts = ZSWR5_DTR;
746 		cs->cs_rr0_cts = ZSRR0_CTS;
747 #endif
748 	} else if ((cflag & MDMBUF) != 0) {
749 		cs->cs_wr5_dtr = 0;
750 		cs->cs_wr5_rts = ZSWR5_DTR;
751 		cs->cs_rr0_cts = ZSRR0_DCD;
752 	} else {
753 		cs->cs_wr5_dtr = ZSWR5_DTR;
754 		cs->cs_wr5_rts = 0;
755 		cs->cs_rr0_cts = 0;
756 	}
757 	splx(s);
758 
759 	/* Caller will stuff the pending registers. */
760 	return (0);
761 }
762 
763 
764 /*
765  * Read or write the chip with suitable delays.
766  * MacII hardware has the delay built in.
767  * No need for extra delay. :-) However, some clock-chirped
768  * macs, or zsc's on serial add-on boards might need it.
769  */
770 #define	ZS_DELAY()
771 
772 u_char
zs_read_reg(struct zs_chanstate * cs,u_char reg)773 zs_read_reg(struct zs_chanstate *cs, u_char reg)
774 {
775 	u_char val;
776 
777 	out8(cs->cs_reg_csr, reg);
778 	ZS_DELAY();
779 	val = in8(cs->cs_reg_csr);
780 	ZS_DELAY();
781 	return val;
782 }
783 
784 void
zs_write_reg(struct zs_chanstate * cs,u_char reg,u_char val)785 zs_write_reg(struct zs_chanstate *cs, u_char reg, u_char val)
786 {
787 	out8(cs->cs_reg_csr, reg);
788 	ZS_DELAY();
789 	out8(cs->cs_reg_csr, val);
790 	ZS_DELAY();
791 }
792 
793 u_char
zs_read_csr(struct zs_chanstate * cs)794 zs_read_csr(struct zs_chanstate *cs)
795 {
796 	u_char val;
797 
798 	val = in8(cs->cs_reg_csr);
799 	ZS_DELAY();
800 	/* make up for the fact CTS is wired backwards */
801 	val ^= ZSRR0_CTS;
802 	return val;
803 }
804 
805 void
zs_write_csr(struct zs_chanstate * cs,u_char val)806 zs_write_csr(struct zs_chanstate *cs, u_char val)
807 {
808 	/* Note, the csr does not write CTS... */
809 	out8(cs->cs_reg_csr, val);
810 	ZS_DELAY();
811 }
812 
813 u_char
zs_read_data(struct zs_chanstate * cs)814 zs_read_data(struct zs_chanstate *cs)
815 {
816 	u_char val;
817 
818 	val = in8(cs->cs_reg_data);
819 	ZS_DELAY();
820 	return val;
821 }
822 
823 void
zs_write_data(struct zs_chanstate * cs,u_char val)824 zs_write_data(struct zs_chanstate *cs, u_char val)
825 {
826 	out8(cs->cs_reg_data, val);
827 	ZS_DELAY();
828 }
829 
830 /*
831  * Power management hooks for zsopen() and zsclose().
832  * We use them to power on/off the ports, if necessary.
833  * This should be modified to turn on/off modem in PBG4, etc.
834  */
835 void macobio_modem_power(int enable);
836 
837 int
zs_enable(struct zs_chanstate * cs)838 zs_enable(struct zs_chanstate *cs)
839 {
840 	macobio_modem_power(1); /* Whee */
841 	cs->enabled = 1;
842 	return(0);
843 }
844 
845 void
zs_disable(struct zs_chanstate * cs)846 zs_disable(struct zs_chanstate *cs)
847 {
848 	macobio_modem_power(0); /* Whee */
849 	cs->enabled = 0;
850 }
851 
852 
853 /****************************************************************
854  * Console support functions (powermac specific!)
855  * Note: this code is allowed to know about the layout of
856  * the chip registers, and uses that to keep things simple.
857  * XXX - I think I like the mvme167 code better. -gwr
858  * XXX - Well :-P  :-)  -wrs
859  ****************************************************************/
860 
861 cons_decl(zs);
862 
863 void	zs_putc(volatile struct zschan *, int);
864 int	zs_getc(volatile struct zschan *);
865 extern int	zsopen( dev_t dev, int flags, int mode, struct proc *p);
866 
867 static int stdin, stdout;
868 
869 /*
870  * Console functions.
871  */
872 
873 /*
874  * zscnprobe is the routine which gets called as the kernel is trying to
875  * figure out where the console should be. Each io driver which might
876  * be the console (as defined in mac68k/conf.c) gets probed. The probe
877  * fills in the consdev structure. Important parts are the device #,
878  * and the console priority. Values are CN_DEAD (don't touch me),
879  * CN_LOWPRI (I'm here, but elsewhere might be better), CN_MIDPRI
880  * (the video, better than CN_LOWPRI), and CN_HIGHPRI (pick me!)
881  *
882  * As the mac's a bit different, we do extra work here. We mainly check
883  * to see if we have serial echo going on. Also could check for default
884  * speeds.
885  */
886 
887 /*
888  * Polled input char.
889  */
890 int
zs_getc(volatile struct zschan * zc)891 zs_getc(volatile struct zschan *zc)
892 {
893 	register int s, c, rr0;
894 
895 	s = splhigh();
896 	/* Wait for a character to arrive. */
897 	do {
898 		rr0 = in8(&zc->zc_csr);
899 		ZS_DELAY();
900 	} while ((rr0 & ZSRR0_RX_READY) == 0);
901 
902 	c = in8(&zc->zc_data);
903 	ZS_DELAY();
904 	splx(s);
905 
906 	return (c);
907 }
908 
909 /*
910  * Polled output char.
911  */
912 void
zs_putc(volatile struct zschan * zc,int c)913 zs_putc(volatile struct zschan *zc, int c)
914 {
915 	register int s, rr0;
916 	register long wait = 0;
917 
918 	s = splhigh();
919 	/* Wait for transmitter to become ready. */
920 	do {
921 		rr0 = in8(&zc->zc_csr);
922 		ZS_DELAY();
923 	} while (((rr0 & ZSRR0_TX_READY) == 0) && (wait++ < 1000000));
924 
925 	if ((rr0 & ZSRR0_TX_READY) != 0) {
926 		out8(&zc->zc_data, c);
927 		ZS_DELAY();
928 	}
929 	splx(s);
930 }
931 
932 
933 /*
934  * Polled console input putchar.
935  */
936 int
zscngetc(dev_t dev)937 zscngetc(dev_t dev)
938 {
939 	register volatile struct zschan *zc = zs_conschan;
940 	register int c;
941 
942 	if (zc) {
943 		c = zs_getc(zc);
944 	} else {
945 		char ch = 0;
946 		OF_read(stdin, &ch, 1);
947 		c = ch;
948 	}
949 	return c;
950 }
951 
952 /*
953  * Polled console output putchar.
954  */
955 void
zscnputc(dev_t dev,int c)956 zscnputc(dev_t dev, int c)
957 {
958 	register volatile struct zschan *zc = zs_conschan;
959 
960 	if (zc) {
961 		zs_putc(zc, c);
962 	} else {
963 		char ch = c;
964 		OF_write(stdout, &ch, 1);
965 	}
966 }
967 
968 void
zscnprobe(struct consdev * cp)969 zscnprobe(struct consdev *cp)
970 {
971 	int chosen, pkg;
972 	int unit = 0;
973 	int maj;
974 	char name[16];
975 
976 	if ((chosen = OF_finddevice("/chosen")) == -1)
977 		return;
978 
979 	if (OF_getprop(chosen, "stdin", &stdin, sizeof(stdin)) == -1)
980 		return;
981 	if (OF_getprop(chosen, "stdout", &stdout, sizeof(stdout)) == -1)
982 		return;
983 
984 	if ((pkg = OF_instance_to_package(stdin)) == -1)
985 		return;
986 
987 	bzero(name, sizeof(name));
988 	if (OF_getprop(pkg, "device_type", name, sizeof(name)) == -1)
989 		return;
990 
991 	if (strcmp(name, "serial") != 0)
992 		return;
993 
994 	bzero(name, sizeof(name));
995 	if (OF_getprop(pkg, "name", name, sizeof(name)) == -1)
996 		return;
997 
998 	if (strcmp(name, "ch-b") == 0)
999 		unit = 1;
1000 
1001 	/* locate the major number */
1002 	for (maj = 0; maj < nchrdev; maj++)
1003 		if (cdevsw[maj].d_open == zsopen)
1004 			break;
1005 
1006 	cp->cn_dev = makedev(maj, unit);
1007 	cp->cn_pri = CN_HIGHPRI;
1008 }
1009 
1010 
1011 void
zscninit(struct consdev * cp)1012 zscninit(struct consdev *cp)
1013 {
1014 	int escc, escc_ch, obio;
1015 	unsigned int zs_offset, zs_size;
1016 	int ch = 0;
1017 	u_int32_t reg[5];
1018 	char name[16];
1019 
1020 	if ((escc_ch = OF_instance_to_package(stdin)) == -1)
1021 		return;
1022 
1023 	bzero(name, sizeof(name));
1024 	if (OF_getprop(escc_ch, "name", name, sizeof(name)) == -1)
1025 		return;
1026 
1027 	if (strcmp(name, "ch-b") == 0)
1028 		ch = 1;
1029 
1030 	if (OF_getprop(escc_ch, "reg", reg, sizeof(reg)) < 8)
1031 		return;
1032 	zs_offset = reg[0];
1033 	zs_size   = reg[1];
1034 
1035 	escc = OF_parent(escc_ch);
1036 	obio = OF_parent(escc);
1037 
1038 	if (OF_getprop(obio, "assigned-addresses", reg, sizeof(reg)) < 12)
1039 		return;
1040 	zs_conschan = mapiodev(reg[2] + zs_offset, zs_size);
1041 
1042 	zs_hwflags[0][ch] = ZS_HWFLAG_CONSOLE;
1043 }
1044 
1045 void
zs_abort(struct zs_chanstate * channel)1046 zs_abort(struct zs_chanstate *channel)
1047 {
1048 	volatile struct zschan *zc = zs_conschan;
1049 	int rr0;
1050 
1051 	/* Wait for end of break to avoid PROM abort. */
1052 	/* XXX - Limit the wait? */
1053 	do {
1054 		rr0 = zc->zc_csr;
1055 		ZS_DELAY();
1056 	} while (rr0 & ZSRR0_BREAK);
1057 
1058 #if defined(DDB)
1059 	if (!db_active)
1060 		db_enter();
1061 #endif
1062 }
1063 
1064 /* copied from sparc - XXX? */
1065 void
zscnpollc(dev_t dev,int on)1066 zscnpollc(dev_t dev, int on)
1067 {
1068 	/*
1069 	 * Need to tell zs driver to acknowledge all interrupts or we get
1070 	 * annoying spurious interrupt messages.  This is because mucking
1071 	 * with spl() levels during polling does not prevent interrupts from
1072 	 * being generated.
1073 	 */
1074 
1075 #if 0
1076 	if (on)
1077 		swallow_zsintrs++;
1078 	else
1079 		swallow_zsintrs--;
1080 #endif
1081 }
1082