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