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