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