1 /* $NetBSD: zs.c,v 1.19 2003/07/15 02:59:30 lukem Exp $ */ 2 3 /*- 4 * Copyright (c) 1996 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Gordon W. Ross. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 /* 40 * Zilog Z8530 Dual UART driver (machine-dependent part) 41 * 42 * Runs two serial lines per chip using slave drivers. 43 * Plain tty/async lines use the zs_async slave. 44 * Sun keyboard/mouse uses the zs_kbd/zs_ms slaves. 45 */ 46 47 #include <sys/cdefs.h> 48 __KERNEL_RCSID(0, "$NetBSD: zs.c,v 1.19 2003/07/15 02:59:30 lukem Exp $"); 49 50 #include "opt_ddb.h" 51 52 #include <sys/param.h> 53 #include <sys/device.h> 54 #include <sys/tty.h> 55 #include <sys/systm.h> 56 57 #include <machine/adrsmap.h> 58 #include <machine/cpu.h> 59 #include <machine/z8530var.h> 60 61 #include <dev/ic/z8530reg.h> 62 63 #define ZS_DELAY() (*zs_delay)() 64 65 extern struct cfdriver zsc_cd; 66 67 /* 68 * Some warts needed by z8530tty.c - 69 * The default parity REALLY needs to be the same as the PROM uses, 70 * or you can not see messages done with printf during boot-up... 71 */ 72 int zs_def_cflag = (CREAD | CS8 | HUPCL); 73 74 int 75 zs_print(aux, name) 76 void *aux; 77 const char *name; 78 { 79 struct zsc_attach_args *args = aux; 80 81 if (name != NULL) 82 aprint_normal("%s: ", name); 83 84 if (args->channel != -1) 85 aprint_normal(" channel %d", args->channel); 86 87 return UNCONF; 88 } 89 90 /* 91 * Our ZS chips all share a common, autovectored interrupt, 92 * so we have to look at all of them on each interrupt. 93 */ 94 int 95 zshard(arg) 96 void *arg; 97 { 98 struct zsc_softc *zsc; 99 int unit, rval, softreq; 100 101 rval = 0; 102 for (unit = 0; unit < zsc_cd.cd_ndevs; unit++) { 103 zsc = zsc_cd.cd_devs[unit]; 104 if (zsc == NULL) 105 continue; 106 rval |= zsc_intr_hard(zsc); 107 softreq = zsc->zsc_cs[0]->cs_softreq; 108 softreq |= zsc->zsc_cs[1]->cs_softreq; 109 if (softreq) 110 softintr_schedule(zsc->zsc_si); 111 } 112 113 return rval; 114 } 115 116 /* 117 * Similar scheme as for zshard (look at all of them) 118 */ 119 void 120 zssoft(arg) 121 void *arg; 122 { 123 struct zsc_softc *zsc; 124 int s, unit; 125 126 /* Make sure we call the tty layer at spltty. */ 127 s = spltty(); 128 for (unit = 0; unit < zsc_cd.cd_ndevs; unit++) { 129 zsc = zsc_cd.cd_devs[unit]; 130 if (zsc == NULL) 131 continue; 132 (void)zsc_intr_soft(zsc); 133 } 134 splx(s); 135 } 136 137 /* 138 * Compute the current baud rate given a ZS channel. 139 */ 140 int 141 zs_get_speed(cs) 142 struct zs_chanstate *cs; 143 { 144 int tconst; 145 146 tconst = zs_read_reg(cs, 12); 147 tconst |= zs_read_reg(cs, 13) << 8; 148 return (TCONST_TO_BPS(cs->cs_brg_clk, tconst)); 149 } 150 151 /* 152 * MD functions for setting the baud rate and control modes. 153 */ 154 int 155 zs_set_speed(cs, bps) 156 struct zs_chanstate *cs; 157 int bps; /* bits per second */ 158 { 159 int tconst, real_bps; 160 161 if (bps == 0) 162 return (0); 163 164 #ifdef DIAGNOSTIC 165 if (cs->cs_brg_clk == 0) 166 panic("zs_set_speed"); 167 #endif 168 169 tconst = BPS_TO_TCONST(cs->cs_brg_clk, bps); 170 if (tconst < 0) 171 return (EINVAL); 172 173 /* Convert back to make sure we can do it. */ 174 real_bps = TCONST_TO_BPS(cs->cs_brg_clk, tconst); 175 176 /* XXX - Allow some tolerance here? */ 177 if (real_bps != bps) 178 return (EINVAL); 179 180 cs->cs_preg[12] = tconst; 181 cs->cs_preg[13] = tconst >> 8; 182 183 /* Caller will stuff the pending registers. */ 184 return (0); 185 } 186 187 int 188 zs_set_modes(cs, cflag) 189 struct zs_chanstate *cs; 190 int cflag; /* bits per second */ 191 { 192 int s; 193 194 /* 195 * Output hardware flow control on the chip is horrendous: 196 * if carrier detect drops, the receiver is disabled, and if 197 * CTS drops, the transmitter is stoped IN MID CHARACTER! 198 * Therefore, NEVER set the HFC bit, and instead use the 199 * status interrupt to detect CTS changes. 200 */ 201 s = splserial(); 202 cs->cs_rr0_pps = 0; 203 if ((cflag & (CLOCAL | MDMBUF)) != 0) { 204 cs->cs_rr0_dcd = 0; 205 if ((cflag & MDMBUF) == 0) 206 cs->cs_rr0_pps = ZSRR0_DCD; 207 } else 208 cs->cs_rr0_dcd = ZSRR0_DCD; 209 if ((cflag & CRTSCTS) != 0) { 210 cs->cs_wr5_dtr = ZSWR5_DTR; 211 cs->cs_wr5_rts = ZSWR5_RTS; 212 cs->cs_rr0_cts = ZSRR0_CTS; 213 } else if ((cflag & MDMBUF) != 0) { 214 cs->cs_wr5_dtr = 0; 215 cs->cs_wr5_rts = ZSWR5_DTR; 216 cs->cs_rr0_cts = ZSRR0_DCD; 217 } else { 218 cs->cs_wr5_dtr = ZSWR5_DTR | ZSWR5_RTS; 219 cs->cs_wr5_rts = 0; 220 cs->cs_rr0_cts = 0; 221 } 222 splx(s); 223 224 /* Caller will stuff the pending registers. */ 225 return (0); 226 } 227 228 /* 229 * Read or write the chip with suitable delays. 230 */ 231 232 u_char 233 zs_read_reg(cs, reg) 234 struct zs_chanstate *cs; 235 u_char reg; 236 { 237 u_char val; 238 239 *cs->cs_reg_csr = reg; 240 ZS_DELAY(); 241 val = *cs->cs_reg_csr; 242 ZS_DELAY(); 243 return val; 244 } 245 246 void 247 zs_write_reg(cs, reg, val) 248 struct zs_chanstate *cs; 249 u_char reg, val; 250 { 251 *cs->cs_reg_csr = reg; 252 ZS_DELAY(); 253 *cs->cs_reg_csr = val; 254 ZS_DELAY(); 255 } 256 257 u_char zs_read_csr(cs) 258 struct zs_chanstate *cs; 259 { 260 u_char val; 261 262 val = *cs->cs_reg_csr; 263 ZS_DELAY(); 264 return val; 265 } 266 267 void zs_write_csr(cs, val) 268 struct zs_chanstate *cs; 269 u_char val; 270 { 271 *cs->cs_reg_csr = val; 272 ZS_DELAY(); 273 } 274 275 u_char zs_read_data(cs) 276 struct zs_chanstate *cs; 277 { 278 u_char val; 279 280 val = *cs->cs_reg_data; 281 ZS_DELAY(); 282 return val; 283 } 284 285 void zs_write_data(cs, val) 286 struct zs_chanstate *cs; 287 u_char val; 288 { 289 *cs->cs_reg_data = val; 290 ZS_DELAY(); 291 } 292 293 void 294 zs_abort(cs) 295 struct zs_chanstate *cs; 296 { 297 #ifdef DDB 298 Debugger(); 299 #endif 300 } 301