1 /* $NetBSD: zs.c,v 1.11 1999/12/26 09:05:39 tsubai 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 int zs_print __P((void *, const char *name)); 63 int zshard __P((void *)); 64 void zssoft __P((void *)); 65 int zs_get_speed __P((struct zs_chanstate *)); 66 void Debugger __P((void)); 67 void (*zs_delay) __P((void)); 68 69 extern struct cfdriver zsc_cd; 70 71 /* 72 * Some warts needed by z8530tty.c - 73 * The default parity REALLY needs to be the same as the PROM uses, 74 * or you can not see messages done with printf during boot-up... 75 */ 76 int zs_def_cflag = (CREAD | CS8 | HUPCL); 77 int zs_major = 1; 78 79 int 80 zs_print(aux, name) 81 void *aux; 82 const char *name; 83 { 84 struct zsc_attach_args *args = aux; 85 86 if (name != NULL) 87 printf("%s: ", name); 88 89 if (args->channel != -1) 90 printf(" channel %d", args->channel); 91 92 return UNCONF; 93 } 94 95 static volatile int zssoftpending; 96 97 #define setsoftserial() \ 98 { \ 99 int s; \ 100 extern int softisr; \ 101 \ 102 s = splhigh(); \ 103 softisr |= SOFTISR_ZS; \ 104 splx(s); \ 105 } 106 107 /* 108 * Our ZS chips all share a common, autovectored interrupt, 109 * so we have to look at all of them on each interrupt. 110 */ 111 int 112 zshard(arg) 113 void *arg; 114 { 115 register struct zsc_softc *zsc; 116 register int unit, rval, softreq; 117 118 rval = softreq = 0; 119 for (unit = 0; unit < zsc_cd.cd_ndevs; unit++) { 120 zsc = zsc_cd.cd_devs[unit]; 121 if (zsc == NULL) 122 continue; 123 rval |= zsc_intr_hard(zsc); 124 softreq |= zsc->zsc_cs[0]->cs_softreq; 125 softreq |= zsc->zsc_cs[1]->cs_softreq; 126 } 127 128 /* We are at splzs here, so no need to lock. */ 129 if (softreq && (zssoftpending == 0)) { 130 zssoftpending = 1; 131 setsoftserial(); 132 } 133 134 return rval; 135 } 136 137 /* 138 * Similar scheme as for zshard (look at all of them) 139 */ 140 void 141 zssoft(arg) 142 void *arg; 143 { 144 register struct zsc_softc *zsc; 145 register int s, unit; 146 147 /* This is not the only ISR on this IPL. */ 148 if (zssoftpending == 0) 149 return; 150 151 /* 152 * The soft intr. bit will be set by zshard only if 153 * the variable zssoftpending is zero. The order of 154 * these next two statements prevents our clearing 155 * the soft intr bit just after zshard has set it. 156 */ 157 /* clearsoftnet(); */ 158 zssoftpending = 0; 159 160 /* Make sure we call the tty layer at spltty. */ 161 s = spltty(); 162 for (unit = 0; unit < zsc_cd.cd_ndevs; unit++) { 163 zsc = zsc_cd.cd_devs[unit]; 164 if (zsc == NULL) 165 continue; 166 (void)zsc_intr_soft(zsc); 167 } 168 splx(s); 169 } 170 171 /* 172 * Compute the current baud rate given a ZS channel. 173 */ 174 int 175 zs_get_speed(cs) 176 struct zs_chanstate *cs; 177 { 178 int tconst; 179 180 tconst = zs_read_reg(cs, 12); 181 tconst |= zs_read_reg(cs, 13) << 8; 182 return (TCONST_TO_BPS(cs->cs_brg_clk, tconst)); 183 } 184 185 /* 186 * MD functions for setting the baud rate and control modes. 187 */ 188 int 189 zs_set_speed(cs, bps) 190 struct zs_chanstate *cs; 191 int bps; /* bits per second */ 192 { 193 int tconst, real_bps; 194 195 if (bps == 0) 196 return (0); 197 198 #ifdef DIAGNOSTIC 199 if (cs->cs_brg_clk == 0) 200 panic("zs_set_speed"); 201 #endif 202 203 tconst = BPS_TO_TCONST(cs->cs_brg_clk, bps); 204 if (tconst < 0) 205 return (EINVAL); 206 207 /* Convert back to make sure we can do it. */ 208 real_bps = TCONST_TO_BPS(cs->cs_brg_clk, tconst); 209 210 /* XXX - Allow some tolerance here? */ 211 if (real_bps != bps) 212 return (EINVAL); 213 214 cs->cs_preg[12] = tconst; 215 cs->cs_preg[13] = tconst >> 8; 216 217 /* Caller will stuff the pending registers. */ 218 return (0); 219 } 220 221 int 222 zs_set_modes(cs, cflag) 223 struct zs_chanstate *cs; 224 int cflag; /* bits per second */ 225 { 226 int s; 227 228 /* 229 * Output hardware flow control on the chip is horrendous: 230 * if carrier detect drops, the receiver is disabled, and if 231 * CTS drops, the transmitter is stoped IN MID CHARACTER! 232 * Therefore, NEVER set the HFC bit, and instead use the 233 * status interrupt to detect CTS changes. 234 */ 235 s = splzs(); 236 cs->cs_rr0_pps = 0; 237 if ((cflag & (CLOCAL | MDMBUF)) != 0) { 238 cs->cs_rr0_dcd = 0; 239 if ((cflag & MDMBUF) == 0) 240 cs->cs_rr0_pps = ZSRR0_DCD; 241 } else 242 cs->cs_rr0_dcd = ZSRR0_DCD; 243 if ((cflag & CRTSCTS) != 0) { 244 cs->cs_wr5_dtr = ZSWR5_DTR; 245 cs->cs_wr5_rts = ZSWR5_RTS; 246 cs->cs_rr0_cts = ZSRR0_CTS; 247 } else if ((cflag & MDMBUF) != 0) { 248 cs->cs_wr5_dtr = 0; 249 cs->cs_wr5_rts = ZSWR5_DTR; 250 cs->cs_rr0_cts = ZSRR0_DCD; 251 } else { 252 cs->cs_wr5_dtr = ZSWR5_DTR | ZSWR5_RTS; 253 cs->cs_wr5_rts = 0; 254 cs->cs_rr0_cts = 0; 255 } 256 splx(s); 257 258 /* Caller will stuff the pending registers. */ 259 return (0); 260 } 261 262 /* 263 * Read or write the chip with suitable delays. 264 */ 265 266 u_char 267 zs_read_reg(cs, reg) 268 struct zs_chanstate *cs; 269 u_char reg; 270 { 271 u_char val; 272 273 *cs->cs_reg_csr = reg; 274 ZS_DELAY(); 275 val = *cs->cs_reg_csr; 276 ZS_DELAY(); 277 return val; 278 } 279 280 void 281 zs_write_reg(cs, reg, val) 282 struct zs_chanstate *cs; 283 u_char reg, val; 284 { 285 *cs->cs_reg_csr = reg; 286 ZS_DELAY(); 287 *cs->cs_reg_csr = val; 288 ZS_DELAY(); 289 } 290 291 u_char zs_read_csr(cs) 292 struct zs_chanstate *cs; 293 { 294 register u_char val; 295 296 val = *cs->cs_reg_csr; 297 ZS_DELAY(); 298 return val; 299 } 300 301 void zs_write_csr(cs, val) 302 struct zs_chanstate *cs; 303 u_char val; 304 { 305 *cs->cs_reg_csr = val; 306 ZS_DELAY(); 307 } 308 309 u_char zs_read_data(cs) 310 struct zs_chanstate *cs; 311 { 312 register u_char val; 313 314 val = *cs->cs_reg_data; 315 ZS_DELAY(); 316 return val; 317 } 318 319 void zs_write_data(cs, val) 320 struct zs_chanstate *cs; 321 u_char val; 322 { 323 *cs->cs_reg_data = val; 324 ZS_DELAY(); 325 } 326 327 void 328 zs_abort(cs) 329 struct zs_chanstate *cs; 330 { 331 #ifdef DDB 332 Debugger(); 333 #endif 334 } 335