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