1 /* $NetBSD: zs.c,v 1.18 2003/05/25 14:02:48 tsutsui 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 "opt_ddb.h" 48 49 #include <sys/param.h> 50 #include <sys/device.h> 51 #include <sys/tty.h> 52 #include <sys/systm.h> 53 54 #include <machine/adrsmap.h> 55 #include <machine/cpu.h> 56 #include <machine/z8530var.h> 57 58 #include <dev/ic/z8530reg.h> 59 60 #define ZS_DELAY() (*zs_delay)() 61 62 extern struct cfdriver zsc_cd; 63 64 /* 65 * Some warts needed by z8530tty.c - 66 * The default parity REALLY needs to be the same as the PROM uses, 67 * or you can not see messages done with printf during boot-up... 68 */ 69 int zs_def_cflag = (CREAD | CS8 | HUPCL); 70 71 int 72 zs_print(aux, name) 73 void *aux; 74 const char *name; 75 { 76 struct zsc_attach_args *args = aux; 77 78 if (name != NULL) 79 aprint_normal("%s: ", name); 80 81 if (args->channel != -1) 82 aprint_normal(" channel %d", args->channel); 83 84 return UNCONF; 85 } 86 87 /* 88 * Our ZS chips all share a common, autovectored interrupt, 89 * so we have to look at all of them on each interrupt. 90 */ 91 int 92 zshard(arg) 93 void *arg; 94 { 95 struct zsc_softc *zsc; 96 int unit, rval, softreq; 97 98 rval = 0; 99 for (unit = 0; unit < zsc_cd.cd_ndevs; unit++) { 100 zsc = zsc_cd.cd_devs[unit]; 101 if (zsc == NULL) 102 continue; 103 rval |= zsc_intr_hard(zsc); 104 softreq = zsc->zsc_cs[0]->cs_softreq; 105 softreq |= zsc->zsc_cs[1]->cs_softreq; 106 if (softreq) 107 softintr_schedule(zsc->zsc_si); 108 } 109 110 return rval; 111 } 112 113 /* 114 * Similar scheme as for zshard (look at all of them) 115 */ 116 void 117 zssoft(arg) 118 void *arg; 119 { 120 struct zsc_softc *zsc; 121 int s, unit; 122 123 /* Make sure we call the tty layer at spltty. */ 124 s = spltty(); 125 for (unit = 0; unit < zsc_cd.cd_ndevs; unit++) { 126 zsc = zsc_cd.cd_devs[unit]; 127 if (zsc == NULL) 128 continue; 129 (void)zsc_intr_soft(zsc); 130 } 131 splx(s); 132 } 133 134 /* 135 * Compute the current baud rate given a ZS channel. 136 */ 137 int 138 zs_get_speed(cs) 139 struct zs_chanstate *cs; 140 { 141 int tconst; 142 143 tconst = zs_read_reg(cs, 12); 144 tconst |= zs_read_reg(cs, 13) << 8; 145 return (TCONST_TO_BPS(cs->cs_brg_clk, tconst)); 146 } 147 148 /* 149 * MD functions for setting the baud rate and control modes. 150 */ 151 int 152 zs_set_speed(cs, bps) 153 struct zs_chanstate *cs; 154 int bps; /* bits per second */ 155 { 156 int tconst, real_bps; 157 158 if (bps == 0) 159 return (0); 160 161 #ifdef DIAGNOSTIC 162 if (cs->cs_brg_clk == 0) 163 panic("zs_set_speed"); 164 #endif 165 166 tconst = BPS_TO_TCONST(cs->cs_brg_clk, bps); 167 if (tconst < 0) 168 return (EINVAL); 169 170 /* Convert back to make sure we can do it. */ 171 real_bps = TCONST_TO_BPS(cs->cs_brg_clk, tconst); 172 173 /* XXX - Allow some tolerance here? */ 174 if (real_bps != bps) 175 return (EINVAL); 176 177 cs->cs_preg[12] = tconst; 178 cs->cs_preg[13] = tconst >> 8; 179 180 /* Caller will stuff the pending registers. */ 181 return (0); 182 } 183 184 int 185 zs_set_modes(cs, cflag) 186 struct zs_chanstate *cs; 187 int cflag; /* bits per second */ 188 { 189 int s; 190 191 /* 192 * Output hardware flow control on the chip is horrendous: 193 * if carrier detect drops, the receiver is disabled, and if 194 * CTS drops, the transmitter is stoped IN MID CHARACTER! 195 * Therefore, NEVER set the HFC bit, and instead use the 196 * status interrupt to detect CTS changes. 197 */ 198 s = splserial(); 199 cs->cs_rr0_pps = 0; 200 if ((cflag & (CLOCAL | MDMBUF)) != 0) { 201 cs->cs_rr0_dcd = 0; 202 if ((cflag & MDMBUF) == 0) 203 cs->cs_rr0_pps = ZSRR0_DCD; 204 } else 205 cs->cs_rr0_dcd = ZSRR0_DCD; 206 if ((cflag & CRTSCTS) != 0) { 207 cs->cs_wr5_dtr = ZSWR5_DTR; 208 cs->cs_wr5_rts = ZSWR5_RTS; 209 cs->cs_rr0_cts = ZSRR0_CTS; 210 } else if ((cflag & MDMBUF) != 0) { 211 cs->cs_wr5_dtr = 0; 212 cs->cs_wr5_rts = ZSWR5_DTR; 213 cs->cs_rr0_cts = ZSRR0_DCD; 214 } else { 215 cs->cs_wr5_dtr = ZSWR5_DTR | ZSWR5_RTS; 216 cs->cs_wr5_rts = 0; 217 cs->cs_rr0_cts = 0; 218 } 219 splx(s); 220 221 /* Caller will stuff the pending registers. */ 222 return (0); 223 } 224 225 /* 226 * Read or write the chip with suitable delays. 227 */ 228 229 u_char 230 zs_read_reg(cs, reg) 231 struct zs_chanstate *cs; 232 u_char reg; 233 { 234 u_char val; 235 236 *cs->cs_reg_csr = reg; 237 ZS_DELAY(); 238 val = *cs->cs_reg_csr; 239 ZS_DELAY(); 240 return val; 241 } 242 243 void 244 zs_write_reg(cs, reg, val) 245 struct zs_chanstate *cs; 246 u_char reg, val; 247 { 248 *cs->cs_reg_csr = reg; 249 ZS_DELAY(); 250 *cs->cs_reg_csr = val; 251 ZS_DELAY(); 252 } 253 254 u_char zs_read_csr(cs) 255 struct zs_chanstate *cs; 256 { 257 u_char val; 258 259 val = *cs->cs_reg_csr; 260 ZS_DELAY(); 261 return val; 262 } 263 264 void zs_write_csr(cs, val) 265 struct zs_chanstate *cs; 266 u_char val; 267 { 268 *cs->cs_reg_csr = val; 269 ZS_DELAY(); 270 } 271 272 u_char zs_read_data(cs) 273 struct zs_chanstate *cs; 274 { 275 u_char val; 276 277 val = *cs->cs_reg_data; 278 ZS_DELAY(); 279 return val; 280 } 281 282 void zs_write_data(cs, val) 283 struct zs_chanstate *cs; 284 u_char val; 285 { 286 *cs->cs_reg_data = val; 287 ZS_DELAY(); 288 } 289 290 void 291 zs_abort(cs) 292 struct zs_chanstate *cs; 293 { 294 #ifdef DDB 295 Debugger(); 296 #endif 297 } 298