1*9593dc34Smglocker /* $OpenBSD: zs.c,v 1.34 2024/09/04 07:54:51 mglocker Exp $ */ 2ac0d0272Smickey /* $NetBSD: zs.c,v 1.17 2001/06/19 13:42:15 wiz Exp $ */ 3ac0d0272Smickey 4ac0d0272Smickey /* 5ac0d0272Smickey * Copyright (c) 1996, 1998 Bill Studenmund 6ac0d0272Smickey * Copyright (c) 1995 Gordon W. Ross 7ac0d0272Smickey * All rights reserved. 8ac0d0272Smickey * 9ac0d0272Smickey * Redistribution and use in source and binary forms, with or without 10ac0d0272Smickey * modification, are permitted provided that the following conditions 11ac0d0272Smickey * are met: 12ac0d0272Smickey * 1. Redistributions of source code must retain the above copyright 13ac0d0272Smickey * notice, this list of conditions and the following disclaimer. 14ac0d0272Smickey * 2. Redistributions in binary form must reproduce the above copyright 15ac0d0272Smickey * notice, this list of conditions and the following disclaimer in the 16ac0d0272Smickey * documentation and/or other materials provided with the distribution. 17ac0d0272Smickey * 18ac0d0272Smickey * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19ac0d0272Smickey * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20ac0d0272Smickey * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21ac0d0272Smickey * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22ac0d0272Smickey * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23ac0d0272Smickey * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24ac0d0272Smickey * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25ac0d0272Smickey * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26ac0d0272Smickey * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27ac0d0272Smickey * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28ac0d0272Smickey */ 29ac0d0272Smickey 30ac0d0272Smickey /* 31ac0d0272Smickey * Zilog Z8530 Dual UART driver (machine-dependent part) 32ac0d0272Smickey * 33ac0d0272Smickey * Runs two serial lines per chip using slave drivers. 34f65f21afSmiod * Plain tty/async lines use the zstty slave. 35f65f21afSmiod * Sun keyboard/mouse uses the zskbd/zsms slaves. 36ac0d0272Smickey * Other ports use their own mice & keyboard slaves. 37ac0d0272Smickey * 38ac0d0272Smickey * Credits & history: 39ac0d0272Smickey * 40ac0d0272Smickey * With NetBSD 1.1, port-mac68k started using a port of the port-sparc 41ac0d0272Smickey * (port-sun3?) zs.c driver (which was in turn based on code in the 42ac0d0272Smickey * Berkeley 4.4 Lite release). Bill Studenmund did the port, with 43ac0d0272Smickey * help from Allen Briggs and Gordon Ross <gwr@netbsd.org>. Noud de 44ac0d0272Smickey * Brouwer field-tested the driver at a local ISP. 45ac0d0272Smickey * 4672928848Sdavid * Bill Studenmund and Gordon Ross then ported the machine-independent 47ac0d0272Smickey * z8530 driver to work with port-mac68k. NetBSD 1.2 contained an 48ac0d0272Smickey * intermediate version (mac68k using a local, patched version of 49ac0d0272Smickey * the m.i. drivers), with NetBSD 1.3 containing a full version. 50ac0d0272Smickey */ 51ac0d0272Smickey 52ac0d0272Smickey #include <sys/param.h> 53ac0d0272Smickey #include <sys/systm.h> 54ac0d0272Smickey #include <sys/proc.h> 55ac0d0272Smickey #include <sys/device.h> 56ac0d0272Smickey #include <sys/conf.h> 57ac0d0272Smickey #include <sys/ioctl.h> 58ac0d0272Smickey #include <sys/tty.h> 59ac0d0272Smickey #include <sys/time.h> 60ac0d0272Smickey #include <sys/kernel.h> 61ac0d0272Smickey #include <sys/syslog.h> 62ac0d0272Smickey 63ac0d0272Smickey #include <dev/cons.h> 64ac0d0272Smickey #include <dev/ofw/openfirm.h> 65ac0d0272Smickey #include <dev/ic/z8530reg.h> 66ac0d0272Smickey 67ac0d0272Smickey #include <machine/z8530var.h> 68ac0d0272Smickey #include <machine/autoconf.h> 69ac0d0272Smickey #include <machine/cpu.h> 70ac0d0272Smickey 7101ee03d1Smpi #include "zs.h" 72ac0d0272Smickey 73ac0d0272Smickey /* 74ac0d0272Smickey * Some warts needed by z8530tty.c - 75ac0d0272Smickey */ 76ac0d0272Smickey int zs_def_cflag = (CREAD | CS8 | HUPCL); 77e7f17214Ssebastia int zs_major = 7; 78ac0d0272Smickey 79ac0d0272Smickey struct zsdevice { 80ac0d0272Smickey /* Yes, they are backwards. */ 81ac0d0272Smickey struct zschan zs_chan_b; 82ac0d0272Smickey struct zschan zs_chan_a; 83ac0d0272Smickey }; 84ac0d0272Smickey 85ac0d0272Smickey /* Flags from cninit() */ 8601ee03d1Smpi static int zs_hwflags[NZS][2]; 87ac0d0272Smickey /* Default speed for each channel */ 8801ee03d1Smpi static int zs_defspeed[NZS][2] = { 89ac0d0272Smickey { 38400, /* tty00 */ 90ac0d0272Smickey 38400 }, /* tty01 */ 91ac0d0272Smickey }; 92ac0d0272Smickey 93ac0d0272Smickey /* console stuff */ 94ac0d0272Smickey void *zs_conschan = 0; 95ac0d0272Smickey #ifdef ZS_CONSOLE_ABORT 96ac0d0272Smickey int zs_cons_canabort = 1; 97ac0d0272Smickey #else 98ac0d0272Smickey int zs_cons_canabort = 0; 99ac0d0272Smickey #endif /* ZS_CONSOLE_ABORT*/ 100ac0d0272Smickey 101ac0d0272Smickey /* device to which the console is attached--if serial. */ 102ac0d0272Smickey /* Mac stuff */ 103ac0d0272Smickey 1043851afa1Sdrahn int zs_get_speed(struct zs_chanstate *); 105ac0d0272Smickey 106ac0d0272Smickey /* 107ac0d0272Smickey * Even though zsparam will set up the clock multiples, etc., we 108ac0d0272Smickey * still set them here as: 1) mice & keyboards don't use zsparam, 109ac0d0272Smickey * and 2) the console stuff uses these defaults before device 110ac0d0272Smickey * attach. 111ac0d0272Smickey */ 112ac0d0272Smickey 113ac0d0272Smickey static u_char zs_init_reg[16] = { 114ac0d0272Smickey 0, /* 0: CMD (reset, etc.) */ 1158321791aSdrahn ZSWR1_RIE | ZSWR1_TIE | ZSWR1_SIE, /* 1: No interrupts yet. ??? */ 116ac0d0272Smickey 0, /* IVECT */ 117ac0d0272Smickey ZSWR3_RX_8 | ZSWR3_RX_ENABLE, 118ac0d0272Smickey ZSWR4_CLK_X16 | ZSWR4_ONESB | ZSWR4_EVENP, 119ac0d0272Smickey ZSWR5_TX_8 | ZSWR5_TX_ENABLE, 120ac0d0272Smickey 0, /* 6: TXSYNC/SYNCLO */ 121ac0d0272Smickey 0, /* 7: RXSYNC/SYNCHI */ 122ac0d0272Smickey 0, /* 8: alias for data port */ 123ac0d0272Smickey ZSWR9_MASTER_IE, 124ac0d0272Smickey 0, /*10: Misc. TX/RX control bits */ 125ac0d0272Smickey ZSWR11_TXCLK_BAUD | ZSWR11_RXCLK_BAUD, 126ac0d0272Smickey ((PCLK/32)/38400)-2, /*12: BAUDLO (default=38400) */ 127ac0d0272Smickey 0, /*13: BAUDHI (default=38400) */ 128ac0d0272Smickey ZSWR14_BAUD_ENA, 129ac0d0272Smickey ZSWR15_BREAK_IE, 130ac0d0272Smickey }; 131ac0d0272Smickey 132ac0d0272Smickey /**************************************************************** 133ac0d0272Smickey * Autoconfig 134ac0d0272Smickey ****************************************************************/ 135ac0d0272Smickey 13601ee03d1Smpi struct cfdriver zs_cd = { 13701ee03d1Smpi NULL, "zs", DV_TTY 138ac0d0272Smickey }; 139ac0d0272Smickey 140ac0d0272Smickey /* Definition of the driver for autoconfig. */ 14101ee03d1Smpi int zs_match(struct device *, void *, void *); 14201ee03d1Smpi void zs_attach(struct device *, struct device *, void *); 14301ee03d1Smpi int zs_print(void *, const char *name); 144ac0d0272Smickey 1453851afa1Sdrahn /* Power management hooks */ 1463851afa1Sdrahn int zs_enable (struct zs_chanstate *); 1473851afa1Sdrahn void zs_disable (struct zs_chanstate *); 1483851afa1Sdrahn 14989ed722cSmpi const struct cfattach zs_ca = { 15001ee03d1Smpi sizeof(struct zsc_softc), zs_match, zs_attach 151ac0d0272Smickey }; 152ac0d0272Smickey 153c4071fd1Smillert int zshard(void *); 154b9d85be1Skettenis void zssoft(void *); 155ac0d0272Smickey #ifdef ZS_TXDMA 1563851afa1Sdrahn int zs_txdma_int(void *); 157ac0d0272Smickey #endif 158ac0d0272Smickey 159ac0d0272Smickey /* 160ac0d0272Smickey * Is the zs chip present? 161ac0d0272Smickey */ 162ac0d0272Smickey int 16301ee03d1Smpi zs_match(struct device *parent, void *match, void *aux) 164ac0d0272Smickey { 165ac0d0272Smickey struct confargs *ca = aux; 166ac0d0272Smickey struct cfdata *cf = match; 167ac0d0272Smickey 168ac0d0272Smickey if (strcmp(ca->ca_name, "escc") != 0) 169ac0d0272Smickey return 0; 170ac0d0272Smickey 17184b94647Smiod if (ca->ca_nreg < 8) 17284b94647Smiod return 0; 17384b94647Smiod 174ac0d0272Smickey if (cf->cf_unit > 1) 175ac0d0272Smickey return 0; 176ac0d0272Smickey 177ac0d0272Smickey return 1; 178ac0d0272Smickey } 179ac0d0272Smickey 180ac0d0272Smickey /* 181ac0d0272Smickey * Attach a found zs. 182ac0d0272Smickey * 183ac0d0272Smickey * Match slave number to zs unit number, so that misconfiguration will 184ac0d0272Smickey * not set up the keyboard as ttya, etc. 185ac0d0272Smickey */ 186ac0d0272Smickey void 18701ee03d1Smpi zs_attach(struct device *parent, struct device *self, void *aux) 188ac0d0272Smickey { 189ac0d0272Smickey struct zsc_softc *zsc = (void *)self; 190ac0d0272Smickey struct confargs *ca = aux; 191ac0d0272Smickey struct zsc_attach_args zsc_args; 192ac0d0272Smickey volatile struct zschan *zc; 1933851afa1Sdrahn struct xzs_chanstate *xcs; 194ac0d0272Smickey struct zs_chanstate *cs; 195ac0d0272Smickey struct zsdevice *zsd; 19601ee03d1Smpi int zs_unit, channel; 197f65f21afSmiod int s; 1985183802aSmickey int node, intr[3][3]; 1995183802aSmickey u_int regs[16]; 200ac0d0272Smickey 20101ee03d1Smpi zs_unit = zsc->zsc_dev.dv_unit; 2023851afa1Sdrahn 2035183802aSmickey zsd = mapiodev(ca->ca_baseaddr + ca->ca_reg[0], ca->ca_reg[1]); 204ac0d0272Smickey node = OF_child(ca->ca_node); /* ch-a */ 205ac0d0272Smickey 206ac0d0272Smickey for (channel = 0; channel < 2; channel++) { 207ac0d0272Smickey if (OF_getprop(node, "AAPL,interrupts", 208ac0d0272Smickey intr[channel], sizeof(intr[0])) == -1 && 209ac0d0272Smickey OF_getprop(node, "interrupts", 210ac0d0272Smickey intr[channel], sizeof(intr[0])) == -1) { 211ac0d0272Smickey printf(": cannot find interrupt property\n"); 212ac0d0272Smickey return; 213ac0d0272Smickey } 214ac0d0272Smickey 215ac0d0272Smickey if (OF_getprop(node, "reg", regs, sizeof(regs)) < 24) { 216ac0d0272Smickey printf(": cannot find reg property\n"); 217ac0d0272Smickey return; 218ac0d0272Smickey } 219ac0d0272Smickey regs[2] += ca->ca_baseaddr; 220ac0d0272Smickey regs[4] += ca->ca_baseaddr; 221ac0d0272Smickey #ifdef ZS_TXDMA 222ac0d0272Smickey zsc->zsc_txdmareg[channel] = mapiodev(regs[2], regs[3]); 223ac0d0272Smickey zsc->zsc_txdmacmd[channel] = 224ac0d0272Smickey dbdma_alloc(sizeof(dbdma_command_t) * 3); 225ac0d0272Smickey memset(zsc->zsc_txdmacmd[channel], 0, 226ac0d0272Smickey sizeof(dbdma_command_t) * 3); 227ac0d0272Smickey dbdma_reset(zsc->zsc_txdmareg[channel]); 228ac0d0272Smickey #endif 229ac0d0272Smickey node = OF_peer(node); /* ch-b */ 230ac0d0272Smickey } 231ac0d0272Smickey 232ac0d0272Smickey printf(": irq %d,%d\n", intr[0][0], intr[1][0]); 233ac0d0272Smickey 234ac0d0272Smickey /* 235ac0d0272Smickey * Initialize software state for each channel. 236ac0d0272Smickey */ 237ac0d0272Smickey for (channel = 0; channel < 2; channel++) { 238ac0d0272Smickey zsc_args.channel = channel; 23901ee03d1Smpi zsc_args.hwflags = zs_hwflags[zs_unit][channel]; 2403851afa1Sdrahn xcs = &zsc->xzsc_xcs_store[channel]; 2413851afa1Sdrahn cs = &xcs->xzs_cs; 2423851afa1Sdrahn zsc->zsc_cs[channel] = cs; 243ac0d0272Smickey 244ac0d0272Smickey cs->cs_channel = channel; 245ac0d0272Smickey cs->cs_private = NULL; 246ac0d0272Smickey cs->cs_ops = &zsops_null; 247ac0d0272Smickey 248ac0d0272Smickey zc = (channel == 0) ? &zsd->zs_chan_a : &zsd->zs_chan_b; 249ac0d0272Smickey 250ac0d0272Smickey cs->cs_reg_csr = &zc->zc_csr; 251ac0d0272Smickey cs->cs_reg_data = &zc->zc_data; 252ac0d0272Smickey 253ac0d0272Smickey memcpy(cs->cs_creg, zs_init_reg, 16); 254ac0d0272Smickey memcpy(cs->cs_preg, zs_init_reg, 16); 255ac0d0272Smickey 256ac0d0272Smickey /* Current BAUD rate generator clock. */ 2573851afa1Sdrahn /* RTxC is 230400*16, so use 230400 */ 2583851afa1Sdrahn cs->cs_brg_clk = PCLK / 16; 259ac0d0272Smickey if (zsc_args.hwflags & ZS_HWFLAG_CONSOLE) 260ac0d0272Smickey cs->cs_defspeed = zs_get_speed(cs); 261ac0d0272Smickey else 2623851afa1Sdrahn cs->cs_defspeed = 26301ee03d1Smpi zs_defspeed[zs_unit][channel]; 2643851afa1Sdrahn cs->cs_defcflag = zs_def_cflag; 2653851afa1Sdrahn 2663851afa1Sdrahn /* Make these correspond to cs_defcflag (-crtscts) */ 2673851afa1Sdrahn cs->cs_rr0_dcd = ZSRR0_DCD; 2683851afa1Sdrahn cs->cs_rr0_cts = 0; 2693851afa1Sdrahn cs->cs_wr5_dtr = ZSWR5_DTR; 2703851afa1Sdrahn cs->cs_wr5_rts = 0; 2713851afa1Sdrahn 2723851afa1Sdrahn #ifdef __notyet__ 2733851afa1Sdrahn cs->cs_slave_type = ZS_SLAVE_NONE; 2743851afa1Sdrahn #endif 2753851afa1Sdrahn 276ac0d0272Smickey /* Define BAUD rate stuff. */ 277ac0d0272Smickey xcs->cs_clocks[0].clk = PCLK; 278ac0d0272Smickey xcs->cs_clocks[0].flags = ZSC_RTXBRG | ZSC_RTXDIV; 279ac0d0272Smickey xcs->cs_clocks[1].flags = 280ac0d0272Smickey ZSC_RTXBRG | ZSC_RTXDIV | ZSC_VARIABLE | ZSC_EXTERN; 281ac0d0272Smickey xcs->cs_clocks[2].flags = ZSC_TRXDIV | ZSC_VARIABLE; 282ac0d0272Smickey xcs->cs_clock_count = 3; 283ac0d0272Smickey if (channel == 0) { 284ac0d0272Smickey /*xcs->cs_clocks[1].clk = mac68k_machine.modem_dcd_clk;*/ 285ac0d0272Smickey /*xcs->cs_clocks[2].clk = mac68k_machine.modem_cts_clk;*/ 286ac0d0272Smickey xcs->cs_clocks[1].clk = 0; 287ac0d0272Smickey xcs->cs_clocks[2].clk = 0; 288ac0d0272Smickey } else { 289ac0d0272Smickey xcs->cs_clocks[1].flags = ZSC_VARIABLE; 290ac0d0272Smickey /* 291ac0d0272Smickey * Yes, we aren't defining ANY clock source enables for the 292ac0d0272Smickey * printer's DCD clock in. The hardware won't let us 293ac0d0272Smickey * use it. But a clock will freak out the chip, so we 294ac0d0272Smickey * let you set it, telling us to bar interrupts on the line. 295ac0d0272Smickey */ 296ac0d0272Smickey /*xcs->cs_clocks[1].clk = mac68k_machine.print_dcd_clk;*/ 297ac0d0272Smickey /*xcs->cs_clocks[2].clk = mac68k_machine.print_cts_clk;*/ 298ac0d0272Smickey xcs->cs_clocks[1].clk = 0; 299ac0d0272Smickey xcs->cs_clocks[2].clk = 0; 300ac0d0272Smickey } 3013851afa1Sdrahn if (xcs->cs_clocks[1].clk) 3023851afa1Sdrahn zsc_args.hwflags |= ZS_HWFLAG_NO_DCD; 3033851afa1Sdrahn if (xcs->cs_clocks[2].clk) 3043851afa1Sdrahn zsc_args.hwflags |= ZS_HWFLAG_NO_CTS; 305ac0d0272Smickey 306ac0d0272Smickey /* Set defaults in our "extended" chanstate. */ 307ac0d0272Smickey xcs->cs_csource = 0; 308ac0d0272Smickey xcs->cs_psource = 0; 309ac0d0272Smickey xcs->cs_cclk_flag = 0; /* Nothing fancy by default */ 310ac0d0272Smickey xcs->cs_pclk_flag = 0; 3113851afa1Sdrahn 312ac0d0272Smickey /* 3133851afa1Sdrahn * We used to disable chip interrupts here, but we now 3143851afa1Sdrahn * do that in zscnprobe, just in case MacOS left the chip on. 3153851afa1Sdrahn */ 3163851afa1Sdrahn 3173851afa1Sdrahn xcs->cs_chip = 0; 3183851afa1Sdrahn 3193851afa1Sdrahn /* Stash away a copy of the final H/W flags. */ 3203851afa1Sdrahn xcs->cs_hwflags = zsc_args.hwflags; 3213851afa1Sdrahn 3223851afa1Sdrahn /* 323ac0d0272Smickey * Look for a child driver for this channel. 324ac0d0272Smickey * The child attach will setup the hardware. 325ac0d0272Smickey */ 32601ee03d1Smpi if (!config_found(self, (void *)&zsc_args, zs_print)) { 327ac0d0272Smickey /* No sub-driver. Just reset it. */ 328ac0d0272Smickey u_char reset = (channel == 0) ? 329ac0d0272Smickey ZSWR9_A_RESET : ZSWR9_B_RESET; 330ac0d0272Smickey s = splzs(); 331ac0d0272Smickey zs_write_reg(cs, 9, reset); 332ac0d0272Smickey splx(s); 333ac0d0272Smickey } 334ac0d0272Smickey } 335ac0d0272Smickey 336ac0d0272Smickey /* XXX - Now safe to install interrupt handlers. */ 337ac0d0272Smickey mac_intr_establish(parent, intr[0][0], IST_LEVEL, IPL_TTY, 3383851afa1Sdrahn zshard, NULL, "zs0"); 339ac0d0272Smickey mac_intr_establish(parent, intr[1][0], IST_LEVEL, IPL_TTY, 3403851afa1Sdrahn zshard, NULL, "zs1"); 341ac0d0272Smickey #ifdef ZS_TXDMA 342ac0d0272Smickey mac_intr_establish(parent, intr[0][1], IST_LEVEL, IPL_TTY, 34314bf419fSkrw zs_txdma_int, NULL, "zsdma0"); 344ac0d0272Smickey mac_intr_establish(parent, intr[1][1], IST_LEVEL, IPL_TTY, 3453851afa1Sdrahn zs_txdma_int, (void *)1, "zsdma1"); 346ac0d0272Smickey #endif 347b9d85be1Skettenis zsc->zsc_softintr = softintr_establish(IPL_SOFTTTY, zssoft, zsc); 348b9d85be1Skettenis if (zsc->zsc_softintr == NULL) 349b9d85be1Skettenis panic("zsattach: could not establish soft interrupt"); 350ac0d0272Smickey 351ac0d0272Smickey /* 352ac0d0272Smickey * Set the master interrupt enable and interrupt vector. 353ac0d0272Smickey * (common to both channels, do it on A) 354ac0d0272Smickey */ 3553851afa1Sdrahn cs = zsc->zsc_cs[0]; 356ac0d0272Smickey s = splzs(); 357ac0d0272Smickey /* interrupt vector */ 358ac0d0272Smickey zs_write_reg(cs, 2, zs_init_reg[2]); 359ac0d0272Smickey /* master interrupt control (enable) */ 360ac0d0272Smickey zs_write_reg(cs, 9, zs_init_reg[9]); 361ac0d0272Smickey splx(s); 3623851afa1Sdrahn 3633851afa1Sdrahn /* connect power management for port 0 */ 3643851afa1Sdrahn cs->enable = zs_enable; 3653851afa1Sdrahn cs->disable = zs_disable; 366ac0d0272Smickey } 367ac0d0272Smickey 368ac0d0272Smickey int 36901ee03d1Smpi zs_print(void *aux, const char *name) 370ac0d0272Smickey { 371ac0d0272Smickey struct zsc_attach_args *args = aux; 372ac0d0272Smickey 373ac0d0272Smickey if (name != NULL) 374ac0d0272Smickey printf("%s: ", name); 375ac0d0272Smickey 376ac0d0272Smickey if (args->channel != -1) 377ac0d0272Smickey printf(" channel %d", args->channel); 378ac0d0272Smickey 379ac0d0272Smickey return UNCONF; 380ac0d0272Smickey } 381ac0d0272Smickey 382ac0d0272Smickey int 383093da1aaSdrahn zsmdioctl(struct zs_chanstate *cs, u_long cmd, caddr_t data) 384ac0d0272Smickey { 385ac0d0272Smickey switch (cmd) { 386ac0d0272Smickey default: 387ac0d0272Smickey return (-1); 388ac0d0272Smickey } 389ac0d0272Smickey return (0); 390ac0d0272Smickey } 391ac0d0272Smickey 392ac0d0272Smickey void 393093da1aaSdrahn zsmd_setclock(struct zs_chanstate *cs) 394ac0d0272Smickey { 395ac0d0272Smickey #ifdef NOTYET 396ac0d0272Smickey struct xzs_chanstate *xcs = (void *)cs; 397ac0d0272Smickey 398ac0d0272Smickey if (cs->cs_channel != 0) 399ac0d0272Smickey return; 400ac0d0272Smickey 401ac0d0272Smickey /* 402ac0d0272Smickey * If the new clock has the external bit set, then select the 403ac0d0272Smickey * external source. 404ac0d0272Smickey */ 405ac0d0272Smickey via_set_modem((xcs->cs_pclk_flag & ZSC_EXTERN) ? 1 : 0); 406ac0d0272Smickey #endif 407ac0d0272Smickey } 408ac0d0272Smickey 409ac0d0272Smickey static int zssoftpending; 410ac0d0272Smickey 411ac0d0272Smickey /* 412ac0d0272Smickey * Our ZS chips all share a common, autovectored interrupt, 413ac0d0272Smickey * so we have to look at all of them on each interrupt. 414ac0d0272Smickey */ 415ac0d0272Smickey int 416093da1aaSdrahn zshard(void *arg) 417ac0d0272Smickey { 418093da1aaSdrahn struct zsc_softc *zsc; 419093da1aaSdrahn int unit, rval; 420ac0d0272Smickey 421ac0d0272Smickey rval = 0; 42201ee03d1Smpi for (unit = 0; unit < zs_cd.cd_ndevs; unit++) { 42301ee03d1Smpi zsc = zs_cd.cd_devs[unit]; 424ac0d0272Smickey if (zsc == NULL) 425ac0d0272Smickey continue; 426ac0d0272Smickey rval |= zsc_intr_hard(zsc); 4276a1aaa0fSderaadt if (zsc->zsc_cs[0]->cs_softreq) 4286a1aaa0fSderaadt { 42901ee03d1Smpi /* zs_req_softint(zsc); */ 430ac0d0272Smickey /* We are at splzs here, so no need to lock. */ 431ac0d0272Smickey if (zssoftpending == 0) { 432ac0d0272Smickey zssoftpending = 1; 433b9d85be1Skettenis softintr_schedule(zsc->zsc_softintr); 434ac0d0272Smickey } 435ac0d0272Smickey } 436ac0d0272Smickey } 437ac0d0272Smickey return (rval); 438ac0d0272Smickey } 439ac0d0272Smickey 440ac0d0272Smickey /* 441ac0d0272Smickey * Similar scheme as for zshard (look at all of them) 442ac0d0272Smickey */ 443b9d85be1Skettenis void 444b8c10385Sderaadt zssoft(void *arg) 445ac0d0272Smickey { 446093da1aaSdrahn struct zsc_softc *zsc; 447093da1aaSdrahn int unit; 448ac0d0272Smickey 449ac0d0272Smickey /* This is not the only ISR on this IPL. */ 450ac0d0272Smickey if (zssoftpending == 0) 451b9d85be1Skettenis return; 452ac0d0272Smickey 453ac0d0272Smickey /* 454ac0d0272Smickey * The soft intr. bit will be set by zshard only if 455ac0d0272Smickey * the variable zssoftpending is zero. 456ac0d0272Smickey */ 457ac0d0272Smickey zssoftpending = 0; 458ac0d0272Smickey 45901ee03d1Smpi for (unit = 0; unit < zs_cd.cd_ndevs; ++unit) { 46001ee03d1Smpi zsc = zs_cd.cd_devs[unit]; 461ac0d0272Smickey if (zsc == NULL) 462ac0d0272Smickey continue; 463ac0d0272Smickey (void) zsc_intr_soft(zsc); 464ac0d0272Smickey } 465ac0d0272Smickey } 466ac0d0272Smickey 467ac0d0272Smickey #ifdef ZS_TXDMA 468ac0d0272Smickey int 469b8c10385Sderaadt zs_txdma_int(void *arg) 470ac0d0272Smickey { 471ac0d0272Smickey int ch = (int)arg; 472ac0d0272Smickey struct zsc_softc *zsc; 473ac0d0272Smickey struct zs_chanstate *cs; 474ac0d0272Smickey int unit = 0; /* XXX */ 475ac0d0272Smickey extern int zstty_txdma_int(); 476ac0d0272Smickey 47701ee03d1Smpi zsc = zs_cd.cd_devs[unit]; 478ac0d0272Smickey if (zsc == NULL) 479ac0d0272Smickey panic("zs_txdma_int"); 480ac0d0272Smickey 481ac0d0272Smickey cs = zsc->zsc_cs[ch]; 482ac0d0272Smickey zstty_txdma_int(cs); 483ac0d0272Smickey 484ac0d0272Smickey if (cs->cs_softreq) { 485ac0d0272Smickey if (zssoftpending == 0) { 486ac0d0272Smickey zssoftpending = 1; 487b9d85be1Skettenis softintr_schedule(zsc->zsc_softintr); 488ac0d0272Smickey } 489ac0d0272Smickey } 490ac0d0272Smickey return 1; 491ac0d0272Smickey } 492ac0d0272Smickey 493ac0d0272Smickey void 494b8c10385Sderaadt zs_dma_setup(struct zs_chanstate *cs, caddr_t pa, int len) 495ac0d0272Smickey { 496ac0d0272Smickey struct zsc_softc *zsc; 497ac0d0272Smickey dbdma_command_t *cmdp; 498ac0d0272Smickey int ch = cs->cs_channel; 499ac0d0272Smickey 50001ee03d1Smpi zsc = zs_cd.cd_devs[ch]; 501ac0d0272Smickey cmdp = zsc->zsc_txdmacmd[ch]; 502ac0d0272Smickey 503ac0d0272Smickey DBDMA_BUILD(cmdp, DBDMA_CMD_OUT_LAST, 0, len, kvtop(pa), 504ac0d0272Smickey DBDMA_INT_ALWAYS, DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER); 505ac0d0272Smickey cmdp++; 506ac0d0272Smickey DBDMA_BUILD(cmdp, DBDMA_CMD_STOP, 0, 0, 0, 507ac0d0272Smickey DBDMA_INT_NEVER, DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER); 508ac0d0272Smickey 5092df76cc2Sguenther __asm volatile("eieio"); 510ac0d0272Smickey 511ac0d0272Smickey dbdma_start(zsc->zsc_txdmareg[ch], zsc->zsc_txdmacmd[ch]); 512ac0d0272Smickey } 513ac0d0272Smickey #endif 514ac0d0272Smickey 515ac0d0272Smickey /* 516ac0d0272Smickey * Compute the current baud rate given a ZS channel. 517ac0d0272Smickey * XXX Assume internal BRG. 518ac0d0272Smickey */ 519ac0d0272Smickey int 520b8c10385Sderaadt zs_get_speed(struct zs_chanstate *cs) 521ac0d0272Smickey { 522ac0d0272Smickey int tconst; 523ac0d0272Smickey 524ac0d0272Smickey tconst = zs_read_reg(cs, 12); 525ac0d0272Smickey tconst |= zs_read_reg(cs, 13) << 8; 526ac0d0272Smickey return TCONST_TO_BPS(cs->cs_brg_clk, tconst); 527ac0d0272Smickey } 528ac0d0272Smickey 5293851afa1Sdrahn #ifndef ZS_TOLERANCE 5303851afa1Sdrahn #define ZS_TOLERANCE 51 5313851afa1Sdrahn /* 5% in tenths of a %, plus 1 so that exactly 5% will be ok. */ 5323851afa1Sdrahn #endif 5333851afa1Sdrahn 5343851afa1Sdrahn /* 5353851afa1Sdrahn * Search through the signal sources in the channel, and 5363851afa1Sdrahn * pick the best one for the baud rate requested. Return 5373851afa1Sdrahn * a -1 if not achievable in tolerance. Otherwise return 0 5383851afa1Sdrahn * and fill in the values. 5393851afa1Sdrahn * 5403851afa1Sdrahn * This routine draws inspiration from the Atari port's zs.c 5413851afa1Sdrahn * driver in NetBSD 1.1 which did the same type of source switching. 5423851afa1Sdrahn * Tolerance code inspired by comspeed routine in isa/com.c. 5433851afa1Sdrahn * 5443851afa1Sdrahn * By Bill Studenmund, 1996-05-12 5453851afa1Sdrahn */ 5463851afa1Sdrahn int 547b8c10385Sderaadt zs_set_speed(struct zs_chanstate *cs, int bps) 5483851afa1Sdrahn { 5493851afa1Sdrahn struct xzs_chanstate *xcs = (void *)cs; 5503851afa1Sdrahn int i, tc, tc0 = 0, tc1, s, sf = 0; 5513851afa1Sdrahn int src, rate0, rate1, err, tol; 5523851afa1Sdrahn 5533851afa1Sdrahn if (bps == 0) 5543851afa1Sdrahn return (0); 5553851afa1Sdrahn 5563851afa1Sdrahn src = -1; /* no valid source yet */ 5573851afa1Sdrahn tol = ZS_TOLERANCE; 5583851afa1Sdrahn 5593851afa1Sdrahn /* 5603851afa1Sdrahn * Step through all the sources and see which one matches 5613851afa1Sdrahn * the best. A source has to match BETTER than tol to be chosen. 5623851afa1Sdrahn * Thus if two sources give the same error, the first one will be 56336fd90dcSjsg * chosen. Also, allow for the possibility that one source might run 5643851afa1Sdrahn * both the BRG and the direct divider (i.e. RTxC). 5653851afa1Sdrahn */ 5663851afa1Sdrahn for (i = 0; i < xcs->cs_clock_count; i++) { 5673851afa1Sdrahn if (xcs->cs_clocks[i].clk <= 0) 5683851afa1Sdrahn continue; /* skip non-existent or bad clocks */ 5693851afa1Sdrahn if (xcs->cs_clocks[i].flags & ZSC_BRG) { 5703851afa1Sdrahn /* check out BRG at /16 */ 5713851afa1Sdrahn tc1 = BPS_TO_TCONST(xcs->cs_clocks[i].clk >> 4, bps); 5723851afa1Sdrahn if (tc1 >= 0) { 5733851afa1Sdrahn rate1 = TCONST_TO_BPS(xcs->cs_clocks[i].clk >> 4, tc1); 5743851afa1Sdrahn err = abs(((rate1 - bps)*1000)/bps); 5753851afa1Sdrahn if (err < tol) { 5763851afa1Sdrahn tol = err; 5773851afa1Sdrahn src = i; 5783851afa1Sdrahn sf = xcs->cs_clocks[i].flags & ~ZSC_DIV; 5793851afa1Sdrahn tc0 = tc1; 5803851afa1Sdrahn rate0 = rate1; 5813851afa1Sdrahn } 5823851afa1Sdrahn } 5833851afa1Sdrahn } 5843851afa1Sdrahn if (xcs->cs_clocks[i].flags & ZSC_DIV) { 5853851afa1Sdrahn /* 5863851afa1Sdrahn * Check out either /1, /16, /32, or /64 5873851afa1Sdrahn * Note: for /1, you'd better be using a synchronized 5883851afa1Sdrahn * clock! 5893851afa1Sdrahn */ 5903851afa1Sdrahn int b0 = xcs->cs_clocks[i].clk, e0 = abs(b0-bps); 5913851afa1Sdrahn int b1 = b0 >> 4, e1 = abs(b1-bps); 5923851afa1Sdrahn int b2 = b1 >> 1, e2 = abs(b2-bps); 5933851afa1Sdrahn int b3 = b2 >> 1, e3 = abs(b3-bps); 5943851afa1Sdrahn 5953851afa1Sdrahn if (e0 < e1 && e0 < e2 && e0 < e3) { 5963851afa1Sdrahn err = e0; 5973851afa1Sdrahn rate1 = b0; 5983851afa1Sdrahn tc1 = ZSWR4_CLK_X1; 5993851afa1Sdrahn } else if (e0 > e1 && e1 < e2 && e1 < e3) { 6003851afa1Sdrahn err = e1; 6013851afa1Sdrahn rate1 = b1; 6023851afa1Sdrahn tc1 = ZSWR4_CLK_X16; 6033851afa1Sdrahn } else if (e0 > e2 && e1 > e2 && e2 < e3) { 6043851afa1Sdrahn err = e2; 6053851afa1Sdrahn rate1 = b2; 6063851afa1Sdrahn tc1 = ZSWR4_CLK_X32; 6073851afa1Sdrahn } else { 6083851afa1Sdrahn err = e3; 6093851afa1Sdrahn rate1 = b3; 6103851afa1Sdrahn tc1 = ZSWR4_CLK_X64; 6113851afa1Sdrahn } 6123851afa1Sdrahn 6133851afa1Sdrahn err = (err * 1000)/bps; 6143851afa1Sdrahn if (err < tol) { 6153851afa1Sdrahn tol = err; 6163851afa1Sdrahn src = i; 6173851afa1Sdrahn sf = xcs->cs_clocks[i].flags & ~ZSC_BRG; 6183851afa1Sdrahn tc0 = tc1; 6193851afa1Sdrahn rate0 = rate1; 6203851afa1Sdrahn } 6213851afa1Sdrahn } 6223851afa1Sdrahn } 6233851afa1Sdrahn #ifdef ZSMACDEBUG 624427916e3Smartin printf("Checking for rate %d. Found source #%d.\n",bps, src); 6253851afa1Sdrahn #endif 6263851afa1Sdrahn if (src == -1) 6273851afa1Sdrahn return (EINVAL); /* no can do */ 6283851afa1Sdrahn 6293851afa1Sdrahn /* 6303851afa1Sdrahn * The M.I. layer likes to keep cs_brg_clk current, even though 6313851afa1Sdrahn * we are the only ones who should be touching the BRG's rate. 6323851afa1Sdrahn * 6333851afa1Sdrahn * Note: we are assuming that any ZSC_EXTERN signal source comes in 6343851afa1Sdrahn * on the RTxC pin. Correct for the mac68k obio zsc. 6353851afa1Sdrahn */ 6363851afa1Sdrahn if (sf & ZSC_EXTERN) 6373851afa1Sdrahn cs->cs_brg_clk = xcs->cs_clocks[i].clk >> 4; 6383851afa1Sdrahn else 6393851afa1Sdrahn cs->cs_brg_clk = PCLK / 16; 6403851afa1Sdrahn 6413851afa1Sdrahn /* 6423851afa1Sdrahn * Now we have a source, so set it up. 6433851afa1Sdrahn */ 6443851afa1Sdrahn s = splzs(); 6453851afa1Sdrahn xcs->cs_psource = src; 6463851afa1Sdrahn xcs->cs_pclk_flag = sf; 6473851afa1Sdrahn bps = rate0; 6483851afa1Sdrahn if (sf & ZSC_BRG) { 6493851afa1Sdrahn cs->cs_preg[4] = ZSWR4_CLK_X16; 6503851afa1Sdrahn cs->cs_preg[11]= ZSWR11_RXCLK_BAUD | ZSWR11_TXCLK_BAUD; 6513851afa1Sdrahn if (sf & ZSC_PCLK) { 6523851afa1Sdrahn cs->cs_preg[14] = ZSWR14_BAUD_ENA | ZSWR14_BAUD_FROM_PCLK; 6533851afa1Sdrahn } else { 6543851afa1Sdrahn cs->cs_preg[14] = ZSWR14_BAUD_ENA; 6553851afa1Sdrahn } 6563851afa1Sdrahn tc = tc0; 6573851afa1Sdrahn } else { 6583851afa1Sdrahn cs->cs_preg[4] = tc0; 6593851afa1Sdrahn if (sf & ZSC_RTXDIV) { 6603851afa1Sdrahn cs->cs_preg[11] = ZSWR11_RXCLK_RTXC | ZSWR11_TXCLK_RTXC; 6613851afa1Sdrahn } else { 6623851afa1Sdrahn cs->cs_preg[11] = ZSWR11_RXCLK_TRXC | ZSWR11_TXCLK_TRXC; 6633851afa1Sdrahn } 6643851afa1Sdrahn cs->cs_preg[14]= 0; 6653851afa1Sdrahn tc = 0xffff; 6663851afa1Sdrahn } 6673851afa1Sdrahn /* Set the BAUD rate divisor. */ 6683851afa1Sdrahn cs->cs_preg[12] = tc; 6693851afa1Sdrahn cs->cs_preg[13] = tc >> 8; 6703851afa1Sdrahn splx(s); 6713851afa1Sdrahn 6723851afa1Sdrahn #ifdef ZSMACDEBUG 673427916e3Smartin printf("Rate is %7d, tc is %7d, source no. %2d, flags %4x\n", \ 6743851afa1Sdrahn bps, tc, src, sf); 675427916e3Smartin printf("Registers are: 4 %x, 11 %x, 14 %x\n\n", 6763851afa1Sdrahn cs->cs_preg[4], cs->cs_preg[11], cs->cs_preg[14]); 6773851afa1Sdrahn #endif 6783851afa1Sdrahn 6793851afa1Sdrahn cs->cs_preg[5] |= ZSWR5_RTS; /* Make sure the drivers are on! */ 6803851afa1Sdrahn 6813851afa1Sdrahn /* Caller will stuff the pending registers. */ 6823851afa1Sdrahn return (0); 6833851afa1Sdrahn } 6843851afa1Sdrahn 6853851afa1Sdrahn int 686b8c10385Sderaadt zs_set_modes(struct zs_chanstate *cs, int cflag) 6873851afa1Sdrahn { 6883851afa1Sdrahn struct xzs_chanstate *xcs = (void*)cs; 6893851afa1Sdrahn int s; 6903851afa1Sdrahn 6913851afa1Sdrahn /* 6923851afa1Sdrahn * Make sure we don't enable hfc on a signal line we're ignoring. 6933851afa1Sdrahn * As we enable CTS interrupts only if we have CRTSCTS or CDTRCTS, 694*9593dc34Smglocker * this code also effectively turns off ZSWR15_CTS_IE. 6953851afa1Sdrahn * 6963851afa1Sdrahn * Also, disable DCD interrupts if we've been told to ignore 6973851afa1Sdrahn * the DCD pin. Happens on mac68k because the input line for 6983851afa1Sdrahn * DCD can also be used as a clock input. (Just set CLOCAL.) 6993851afa1Sdrahn * 7003851afa1Sdrahn * If someone tries to turn an invalid flow mode on, Just Say No 7013851afa1Sdrahn * (Suggested by gwr) 7023851afa1Sdrahn */ 7033851afa1Sdrahn if (xcs->cs_hwflags & ZS_HWFLAG_NO_DCD) { 7043851afa1Sdrahn if (cflag & MDMBUF) 7053851afa1Sdrahn return (EINVAL); 7063851afa1Sdrahn cflag |= CLOCAL; 7073851afa1Sdrahn } 7083851afa1Sdrahn #if 0 7093851afa1Sdrahn if ((xcs->cs_hwflags & ZS_HWFLAG_NO_CTS) && (cflag & CRTSCTS)) 7103851afa1Sdrahn return (EINVAL); 7113851afa1Sdrahn #endif 7123851afa1Sdrahn 7133851afa1Sdrahn /* 7143851afa1Sdrahn * Output hardware flow control on the chip is horrendous: 7153851afa1Sdrahn * if carrier detect drops, the receiver is disabled, and if 71689f5d949Sjsing * CTS drops, the transmitter is stopped IN MID CHARACTER! 7173851afa1Sdrahn * Therefore, NEVER set the HFC bit, and instead use the 7183851afa1Sdrahn * status interrupt to detect CTS changes. 7193851afa1Sdrahn */ 7203851afa1Sdrahn s = splzs(); 7213851afa1Sdrahn if ((cflag & (CLOCAL | MDMBUF)) != 0) 7223851afa1Sdrahn cs->cs_rr0_dcd = 0; 7233851afa1Sdrahn else 7243851afa1Sdrahn cs->cs_rr0_dcd = ZSRR0_DCD; 7253851afa1Sdrahn /* 7263851afa1Sdrahn * The mac hardware only has one output, DTR (HSKo in Mac 7273851afa1Sdrahn * parlance). In HFC mode, we use it for the functions 7283851afa1Sdrahn * typically served by RTS and DTR on other ports, so we 7293851afa1Sdrahn * have to fake the upper layer out some. 7303851afa1Sdrahn * 7313851afa1Sdrahn * CRTSCTS we use CTS as an input which tells us when to shut up. 7323851afa1Sdrahn * We make no effort to shut up the other side of the connection. 7333851afa1Sdrahn * DTR is used to hang up the modem. 7343851afa1Sdrahn * 7353851afa1Sdrahn * In CDTRCTS, we use CTS to tell us to stop, but we use DTR to 7363851afa1Sdrahn * shut up the other side. 7373851afa1Sdrahn */ 7383851afa1Sdrahn if ((cflag & CRTSCTS) != 0) { 7393851afa1Sdrahn cs->cs_wr5_dtr = ZSWR5_DTR; 7403851afa1Sdrahn cs->cs_wr5_rts = 0; 7413851afa1Sdrahn cs->cs_rr0_cts = ZSRR0_CTS; 7423851afa1Sdrahn #if 0 7433851afa1Sdrahn } else if ((cflag & CDTRCTS) != 0) { 7443851afa1Sdrahn cs->cs_wr5_dtr = 0; 7453851afa1Sdrahn cs->cs_wr5_rts = ZSWR5_DTR; 7463851afa1Sdrahn cs->cs_rr0_cts = ZSRR0_CTS; 7473851afa1Sdrahn #endif 7483851afa1Sdrahn } else if ((cflag & MDMBUF) != 0) { 7493851afa1Sdrahn cs->cs_wr5_dtr = 0; 7503851afa1Sdrahn cs->cs_wr5_rts = ZSWR5_DTR; 7513851afa1Sdrahn cs->cs_rr0_cts = ZSRR0_DCD; 7523851afa1Sdrahn } else { 7533851afa1Sdrahn cs->cs_wr5_dtr = ZSWR5_DTR; 7543851afa1Sdrahn cs->cs_wr5_rts = 0; 7553851afa1Sdrahn cs->cs_rr0_cts = 0; 7563851afa1Sdrahn } 7573851afa1Sdrahn splx(s); 7583851afa1Sdrahn 7593851afa1Sdrahn /* Caller will stuff the pending registers. */ 7603851afa1Sdrahn return (0); 7613851afa1Sdrahn } 7623851afa1Sdrahn 7633851afa1Sdrahn 764ac0d0272Smickey /* 765ac0d0272Smickey * Read or write the chip with suitable delays. 766ac0d0272Smickey * MacII hardware has the delay built in. 767ac0d0272Smickey * No need for extra delay. :-) However, some clock-chirped 768ac0d0272Smickey * macs, or zsc's on serial add-on boards might need it. 769ac0d0272Smickey */ 770ac0d0272Smickey #define ZS_DELAY() 771ac0d0272Smickey 772ac0d0272Smickey u_char 773b8c10385Sderaadt zs_read_reg(struct zs_chanstate *cs, u_char reg) 774ac0d0272Smickey { 775ac0d0272Smickey u_char val; 776ac0d0272Smickey 777ac0d0272Smickey out8(cs->cs_reg_csr, reg); 778ac0d0272Smickey ZS_DELAY(); 779ac0d0272Smickey val = in8(cs->cs_reg_csr); 780ac0d0272Smickey ZS_DELAY(); 781ac0d0272Smickey return val; 782ac0d0272Smickey } 783ac0d0272Smickey 784ac0d0272Smickey void 785b8c10385Sderaadt zs_write_reg(struct zs_chanstate *cs, u_char reg, u_char val) 786ac0d0272Smickey { 787ac0d0272Smickey out8(cs->cs_reg_csr, reg); 788ac0d0272Smickey ZS_DELAY(); 789ac0d0272Smickey out8(cs->cs_reg_csr, val); 790ac0d0272Smickey ZS_DELAY(); 791ac0d0272Smickey } 792ac0d0272Smickey 793f65f21afSmiod u_char 794b8c10385Sderaadt zs_read_csr(struct zs_chanstate *cs) 795ac0d0272Smickey { 796093da1aaSdrahn u_char val; 797ac0d0272Smickey 798ac0d0272Smickey val = in8(cs->cs_reg_csr); 799ac0d0272Smickey ZS_DELAY(); 800ac0d0272Smickey /* make up for the fact CTS is wired backwards */ 801ac0d0272Smickey val ^= ZSRR0_CTS; 802ac0d0272Smickey return val; 803ac0d0272Smickey } 804ac0d0272Smickey 805f65f21afSmiod void 806b8c10385Sderaadt zs_write_csr(struct zs_chanstate *cs, u_char val) 807ac0d0272Smickey { 808ac0d0272Smickey /* Note, the csr does not write CTS... */ 809ac0d0272Smickey out8(cs->cs_reg_csr, val); 810ac0d0272Smickey ZS_DELAY(); 811ac0d0272Smickey } 812ac0d0272Smickey 813f65f21afSmiod u_char 814b8c10385Sderaadt zs_read_data(struct zs_chanstate *cs) 815ac0d0272Smickey { 816093da1aaSdrahn u_char val; 817ac0d0272Smickey 818ac0d0272Smickey val = in8(cs->cs_reg_data); 819ac0d0272Smickey ZS_DELAY(); 820ac0d0272Smickey return val; 821ac0d0272Smickey } 822ac0d0272Smickey 823f65f21afSmiod void 824b8c10385Sderaadt zs_write_data(struct zs_chanstate *cs, u_char val) 825ac0d0272Smickey { 826ac0d0272Smickey out8(cs->cs_reg_data, val); 827ac0d0272Smickey ZS_DELAY(); 828ac0d0272Smickey } 829ac0d0272Smickey 8303851afa1Sdrahn /* 8313851afa1Sdrahn * Power management hooks for zsopen() and zsclose(). 8323851afa1Sdrahn * We use them to power on/off the ports, if necessary. 8333851afa1Sdrahn * This should be modified to turn on/off modem in PBG4, etc. 8343851afa1Sdrahn */ 8353851afa1Sdrahn void macobio_modem_power(int enable); 8363851afa1Sdrahn 8373851afa1Sdrahn int 838b8c10385Sderaadt zs_enable(struct zs_chanstate *cs) 8393851afa1Sdrahn { 8403851afa1Sdrahn macobio_modem_power(1); /* Whee */ 8413851afa1Sdrahn cs->enabled = 1; 8423851afa1Sdrahn return(0); 8433851afa1Sdrahn } 8443851afa1Sdrahn 8453851afa1Sdrahn void 846b8c10385Sderaadt zs_disable(struct zs_chanstate *cs) 8473851afa1Sdrahn { 8483851afa1Sdrahn macobio_modem_power(0); /* Whee */ 8493851afa1Sdrahn cs->enabled = 0; 8503851afa1Sdrahn } 8513851afa1Sdrahn 8523851afa1Sdrahn 853ac0d0272Smickey /**************************************************************** 854ac0d0272Smickey * Console support functions (powermac specific!) 855ac0d0272Smickey * Note: this code is allowed to know about the layout of 856ac0d0272Smickey * the chip registers, and uses that to keep things simple. 857ac0d0272Smickey * XXX - I think I like the mvme167 code better. -gwr 858ac0d0272Smickey * XXX - Well :-P :-) -wrs 859ac0d0272Smickey ****************************************************************/ 860ac0d0272Smickey 861ac0d0272Smickey cons_decl(zs); 862ac0d0272Smickey 863093da1aaSdrahn void zs_putc(volatile struct zschan *, int); 864093da1aaSdrahn int zs_getc(volatile struct zschan *); 865c4071fd1Smillert extern int zsopen( dev_t dev, int flags, int mode, struct proc *p); 866ac0d0272Smickey 867ac0d0272Smickey static int stdin, stdout; 868ac0d0272Smickey 869ac0d0272Smickey /* 870ac0d0272Smickey * Console functions. 871ac0d0272Smickey */ 872ac0d0272Smickey 873ac0d0272Smickey /* 874ac0d0272Smickey * zscnprobe is the routine which gets called as the kernel is trying to 875ac0d0272Smickey * figure out where the console should be. Each io driver which might 876ac0d0272Smickey * be the console (as defined in mac68k/conf.c) gets probed. The probe 877ac0d0272Smickey * fills in the consdev structure. Important parts are the device #, 878ac0d0272Smickey * and the console priority. Values are CN_DEAD (don't touch me), 879713cf266Sjsing * CN_LOWPRI (I'm here, but elsewhere might be better), CN_MIDPRI 880713cf266Sjsing * (the video, better than CN_LOWPRI), and CN_HIGHPRI (pick me!) 881ac0d0272Smickey * 882ac0d0272Smickey * As the mac's a bit different, we do extra work here. We mainly check 883*9593dc34Smglocker * to see if we have serial echo going on. Also could check for default 884ac0d0272Smickey * speeds. 885ac0d0272Smickey */ 886ac0d0272Smickey 887ac0d0272Smickey /* 888ac0d0272Smickey * Polled input char. 889ac0d0272Smickey */ 890ac0d0272Smickey int 891b8c10385Sderaadt zs_getc(volatile struct zschan *zc) 892ac0d0272Smickey { 893ac0d0272Smickey register int s, c, rr0; 894ac0d0272Smickey 895ac0d0272Smickey s = splhigh(); 896ac0d0272Smickey /* Wait for a character to arrive. */ 897ac0d0272Smickey do { 898ac0d0272Smickey rr0 = in8(&zc->zc_csr); 899ac0d0272Smickey ZS_DELAY(); 900ac0d0272Smickey } while ((rr0 & ZSRR0_RX_READY) == 0); 901ac0d0272Smickey 902ac0d0272Smickey c = in8(&zc->zc_data); 903ac0d0272Smickey ZS_DELAY(); 904ac0d0272Smickey splx(s); 905ac0d0272Smickey 906ac0d0272Smickey return (c); 907ac0d0272Smickey } 908ac0d0272Smickey 909ac0d0272Smickey /* 910ac0d0272Smickey * Polled output char. 911ac0d0272Smickey */ 912ac0d0272Smickey void 913b8c10385Sderaadt zs_putc(volatile struct zschan *zc, int c) 914ac0d0272Smickey { 915ac0d0272Smickey register int s, rr0; 916ac0d0272Smickey register long wait = 0; 917ac0d0272Smickey 918ac0d0272Smickey s = splhigh(); 919ac0d0272Smickey /* Wait for transmitter to become ready. */ 920ac0d0272Smickey do { 921ac0d0272Smickey rr0 = in8(&zc->zc_csr); 922ac0d0272Smickey ZS_DELAY(); 923ac0d0272Smickey } while (((rr0 & ZSRR0_TX_READY) == 0) && (wait++ < 1000000)); 924ac0d0272Smickey 925ac0d0272Smickey if ((rr0 & ZSRR0_TX_READY) != 0) { 926ac0d0272Smickey out8(&zc->zc_data, c); 927ac0d0272Smickey ZS_DELAY(); 928ac0d0272Smickey } 929ac0d0272Smickey splx(s); 930ac0d0272Smickey } 931ac0d0272Smickey 932ac0d0272Smickey 933ac0d0272Smickey /* 934ac0d0272Smickey * Polled console input putchar. 935ac0d0272Smickey */ 936ac0d0272Smickey int 937b8c10385Sderaadt zscngetc(dev_t dev) 938ac0d0272Smickey { 939ac0d0272Smickey register volatile struct zschan *zc = zs_conschan; 940ac0d0272Smickey register int c; 941ac0d0272Smickey 942ac0d0272Smickey if (zc) { 943ac0d0272Smickey c = zs_getc(zc); 944ac0d0272Smickey } else { 945ac0d0272Smickey char ch = 0; 946ac0d0272Smickey OF_read(stdin, &ch, 1); 947ac0d0272Smickey c = ch; 948ac0d0272Smickey } 949ac0d0272Smickey return c; 950ac0d0272Smickey } 951ac0d0272Smickey 952ac0d0272Smickey /* 953ac0d0272Smickey * Polled console output putchar. 954ac0d0272Smickey */ 955ac0d0272Smickey void 956b8c10385Sderaadt zscnputc(dev_t dev, int c) 957ac0d0272Smickey { 958ac0d0272Smickey register volatile struct zschan *zc = zs_conschan; 959ac0d0272Smickey 960ac0d0272Smickey if (zc) { 961ac0d0272Smickey zs_putc(zc, c); 962ac0d0272Smickey } else { 963ac0d0272Smickey char ch = c; 964ac0d0272Smickey OF_write(stdout, &ch, 1); 965ac0d0272Smickey } 966ac0d0272Smickey } 967ac0d0272Smickey 968ac0d0272Smickey void 969b8c10385Sderaadt zscnprobe(struct consdev *cp) 970ac0d0272Smickey { 971ac0d0272Smickey int chosen, pkg; 972ac0d0272Smickey int unit = 0; 9733851afa1Sdrahn int maj; 974ac0d0272Smickey char name[16]; 975ac0d0272Smickey 976ac0d0272Smickey if ((chosen = OF_finddevice("/chosen")) == -1) 977ac0d0272Smickey return; 978ac0d0272Smickey 979ac0d0272Smickey if (OF_getprop(chosen, "stdin", &stdin, sizeof(stdin)) == -1) 980ac0d0272Smickey return; 981ac0d0272Smickey if (OF_getprop(chosen, "stdout", &stdout, sizeof(stdout)) == -1) 982ac0d0272Smickey return; 983ac0d0272Smickey 984ac0d0272Smickey if ((pkg = OF_instance_to_package(stdin)) == -1) 985ac0d0272Smickey return; 986ac0d0272Smickey 987d7949865Sjasper bzero(name, sizeof(name)); 988ac0d0272Smickey if (OF_getprop(pkg, "device_type", name, sizeof(name)) == -1) 989ac0d0272Smickey return; 990ac0d0272Smickey 991ac0d0272Smickey if (strcmp(name, "serial") != 0) 992ac0d0272Smickey return; 993ac0d0272Smickey 994d7949865Sjasper bzero(name, sizeof(name)); 995ac0d0272Smickey if (OF_getprop(pkg, "name", name, sizeof(name)) == -1) 996ac0d0272Smickey return; 997ac0d0272Smickey 998ac0d0272Smickey if (strcmp(name, "ch-b") == 0) 999ac0d0272Smickey unit = 1; 1000ac0d0272Smickey 10013851afa1Sdrahn /* locate the major number */ 10023851afa1Sdrahn for (maj = 0; maj < nchrdev; maj++) 10033851afa1Sdrahn if (cdevsw[maj].d_open == zsopen) 10043851afa1Sdrahn break; 10053851afa1Sdrahn 10063851afa1Sdrahn cp->cn_dev = makedev(maj, unit); 1007713cf266Sjsing cp->cn_pri = CN_HIGHPRI; 1008ac0d0272Smickey } 1009ac0d0272Smickey 10103851afa1Sdrahn 1011ac0d0272Smickey void 1012b8c10385Sderaadt zscninit(struct consdev *cp) 1013ac0d0272Smickey { 10143851afa1Sdrahn int escc, escc_ch, obio; 10153851afa1Sdrahn unsigned int zs_offset, zs_size; 1016ac0d0272Smickey int ch = 0; 1017ac0d0272Smickey u_int32_t reg[5]; 1018ac0d0272Smickey char name[16]; 1019ac0d0272Smickey 1020ac0d0272Smickey if ((escc_ch = OF_instance_to_package(stdin)) == -1) 1021ac0d0272Smickey return; 1022ac0d0272Smickey 1023d7949865Sjasper bzero(name, sizeof(name)); 1024ac0d0272Smickey if (OF_getprop(escc_ch, "name", name, sizeof(name)) == -1) 1025ac0d0272Smickey return; 1026ac0d0272Smickey 1027ac0d0272Smickey if (strcmp(name, "ch-b") == 0) 1028ac0d0272Smickey ch = 1; 1029ac0d0272Smickey 10303851afa1Sdrahn if (OF_getprop(escc_ch, "reg", reg, sizeof(reg)) < 8) 1031ac0d0272Smickey return; 1032ac0d0272Smickey zs_offset = reg[0]; 1033337e2fafSdrahn zs_size = reg[1]; 1034ac0d0272Smickey 1035ac0d0272Smickey escc = OF_parent(escc_ch); 1036ac0d0272Smickey obio = OF_parent(escc); 1037ac0d0272Smickey 1038ac0d0272Smickey if (OF_getprop(obio, "assigned-addresses", reg, sizeof(reg)) < 12) 1039ac0d0272Smickey return; 1040337e2fafSdrahn zs_conschan = mapiodev(reg[2] + zs_offset, zs_size); 1041ac0d0272Smickey 1042ac0d0272Smickey zs_hwflags[0][ch] = ZS_HWFLAG_CONSOLE; 1043ac0d0272Smickey } 1044ac0d0272Smickey 1045ac0d0272Smickey void 10463851afa1Sdrahn zs_abort(struct zs_chanstate *channel) 1047ac0d0272Smickey { 1048362ea72eSkettenis volatile struct zschan *zc = zs_conschan; 1049362ea72eSkettenis int rr0; 1050ac0d0272Smickey 1051362ea72eSkettenis /* Wait for end of break to avoid PROM abort. */ 1052362ea72eSkettenis /* XXX - Limit the wait? */ 1053362ea72eSkettenis do { 1054362ea72eSkettenis rr0 = zc->zc_csr; 1055362ea72eSkettenis ZS_DELAY(); 1056362ea72eSkettenis } while (rr0 & ZSRR0_BREAK); 1057362ea72eSkettenis 1058362ea72eSkettenis #if defined(DDB) 1059362ea72eSkettenis if (!db_active) 1060e97088d6Smpi db_enter(); 1061362ea72eSkettenis #endif 1062ac0d0272Smickey } 10633851afa1Sdrahn 10643851afa1Sdrahn /* copied from sparc - XXX? */ 10653851afa1Sdrahn void 1066b8c10385Sderaadt zscnpollc(dev_t dev, int on) 10673851afa1Sdrahn { 10683851afa1Sdrahn /* 10693851afa1Sdrahn * Need to tell zs driver to acknowledge all interrupts or we get 10703851afa1Sdrahn * annoying spurious interrupt messages. This is because mucking 10713851afa1Sdrahn * with spl() levels during polling does not prevent interrupts from 10723851afa1Sdrahn * being generated. 10733851afa1Sdrahn */ 10743851afa1Sdrahn 10753851afa1Sdrahn #if 0 10763851afa1Sdrahn if (on) 10773851afa1Sdrahn swallow_zsintrs++; 10783851afa1Sdrahn else 10793851afa1Sdrahn swallow_zsintrs--; 10803851afa1Sdrahn #endif 10813851afa1Sdrahn } 1082