1 /* $NetBSD: zs.c,v 1.1 2005/12/29 15:20:08 tsutsui Exp $ */ 2 3 /*- 4 * Copyright (c) 1996, 2005 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 */ 45 46 #include <sys/cdefs.h> 47 __KERNEL_RCSID(0, "$NetBSD: zs.c,v 1.1 2005/12/29 15:20:08 tsutsui Exp $"); 48 49 #include "opt_ddb.h" 50 51 #include <sys/param.h> 52 #include <sys/device.h> 53 #include <sys/tty.h> 54 #include <sys/systm.h> 55 56 #include <machine/z8530var.h> 57 #include <dev/ic/z8530reg.h> 58 59 #include "ioconf.h" 60 61 /* console status for consinit() */ 62 static struct zs_chanstate zs_conscs_store; 63 struct zs_chanstate *zs_conscs = &zs_conscs_store; 64 void *zs_consaddr; 65 66 /* 67 * Some warts needed by z8530tty.c - 68 * The default parity REALLY needs to be the same as the PROM uses, 69 * or you can not see messages done with printf during boot-up... 70 */ 71 int zs_def_cflag = (CREAD | CS8 | HUPCL); 72 73 int 74 zs_print(void *aux, 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(void *arg) 93 { 94 struct zsc_softc *zsc; 95 int unit, rval, softreq; 96 97 rval = 0; 98 for (unit = 0; unit < zsc_cd.cd_ndevs; unit++) { 99 zsc = zsc_cd.cd_devs[unit]; 100 if (zsc == NULL) 101 continue; 102 rval |= zsc_intr_hard(zsc); 103 softreq = zsc->zsc_cs[0]->cs_softreq; 104 softreq |= zsc->zsc_cs[1]->cs_softreq; 105 if (softreq) 106 softintr_schedule(zsc->zsc_si); 107 } 108 109 return rval; 110 } 111 112 /* 113 * Similar scheme as for zshard (look at all of them) 114 */ 115 void 116 zssoft(void *arg) 117 { 118 struct zsc_softc *zsc; 119 int s, unit; 120 121 /* Make sure we call the tty layer at spltty. */ 122 s = spltty(); 123 for (unit = 0; unit < zsc_cd.cd_ndevs; unit++) { 124 zsc = zsc_cd.cd_devs[unit]; 125 if (zsc == NULL) 126 continue; 127 (void)zsc_intr_soft(zsc); 128 } 129 splx(s); 130 } 131 132 /* 133 * Compute the current baud rate given a ZS channel. 134 */ 135 int 136 zs_get_speed(struct zs_chanstate *cs) 137 { 138 int tconst; 139 140 tconst = zs_read_reg(cs, 12); 141 tconst |= zs_read_reg(cs, 13) << 8; 142 return TCONST_TO_BPS(cs->cs_brg_clk, tconst); 143 } 144 145 /* 146 * MD functions for setting the baud rate and control modes. 147 */ 148 int 149 zs_set_speed(struct zs_chanstate *cs, int bps) 150 { 151 int tconst, real_bps; 152 153 if (bps == 0) 154 return 0; 155 156 #ifdef DIAGNOSTIC 157 if (cs->cs_brg_clk == 0) 158 panic("zs_set_speed"); 159 #endif 160 161 tconst = BPS_TO_TCONST(cs->cs_brg_clk, bps); 162 if (tconst < 0) 163 return EINVAL; 164 165 /* Convert back to make sure we can do it. */ 166 real_bps = TCONST_TO_BPS(cs->cs_brg_clk, tconst); 167 168 /* XXX - Allow some tolerance here? */ 169 if (real_bps != bps) 170 return EINVAL; 171 172 cs->cs_preg[12] = tconst; 173 cs->cs_preg[13] = tconst >> 8; 174 175 /* Caller will stuff the pending registers. */ 176 return 0; 177 } 178 179 int 180 zs_set_modes(struct zs_chanstate *cs, int cflag) 181 { 182 int s; 183 184 /* 185 * Output hardware flow control on the chip is horrendous: 186 * if carrier detect drops, the receiver is disabled, and if 187 * CTS drops, the transmitter is stoped IN MID CHARACTER! 188 * Therefore, NEVER set the HFC bit, and instead use the 189 * status interrupt to detect CTS changes. 190 */ 191 s = splserial(); 192 cs->cs_rr0_pps = 0; 193 if ((cflag & (CLOCAL | MDMBUF)) != 0) { 194 cs->cs_rr0_dcd = 0; 195 if ((cflag & MDMBUF) == 0) 196 cs->cs_rr0_pps = ZSRR0_DCD; 197 } else 198 cs->cs_rr0_dcd = ZSRR0_DCD; 199 if ((cflag & CRTSCTS) != 0) { 200 cs->cs_wr5_dtr = ZSWR5_DTR; 201 cs->cs_wr5_rts = ZSWR5_RTS; 202 cs->cs_rr0_cts = ZSRR0_CTS; 203 } else if ((cflag & MDMBUF) != 0) { 204 cs->cs_wr5_dtr = 0; 205 cs->cs_wr5_rts = ZSWR5_DTR; 206 cs->cs_rr0_cts = ZSRR0_DCD; 207 } else { 208 cs->cs_wr5_dtr = ZSWR5_DTR | ZSWR5_RTS; 209 cs->cs_wr5_rts = 0; 210 cs->cs_rr0_cts = 0; 211 } 212 splx(s); 213 214 /* Caller will stuff the pending registers. */ 215 return 0; 216 } 217 218 /* 219 * Read or write the chip with suitable delays. 220 */ 221 uint8_t 222 zs_read_reg(struct zs_chanstate *cs, uint8_t reg) 223 { 224 uint8_t val; 225 226 *cs->cs_reg_csr = reg; 227 228 val = *cs->cs_reg_csr; 229 230 return val; 231 } 232 233 void 234 zs_write_reg(struct zs_chanstate *cs, uint8_t reg, uint8_t val) 235 { 236 237 *cs->cs_reg_csr = reg; 238 239 *cs->cs_reg_csr = val; 240 241 } 242 243 uint8_t 244 zs_read_csr(struct zs_chanstate *cs) 245 { 246 uint8_t val; 247 248 val = *cs->cs_reg_csr; 249 250 return val; 251 } 252 253 void 254 zs_write_csr(struct zs_chanstate *cs, uint8_t val) 255 { 256 257 *cs->cs_reg_csr = val; 258 259 } 260 261 uint8_t 262 zs_read_data(struct zs_chanstate *cs) 263 { 264 uint8_t val; 265 266 val = *cs->cs_reg_data; 267 268 return val; 269 } 270 271 void 272 zs_write_data(struct zs_chanstate *cs, uint8_t val) 273 { 274 275 *cs->cs_reg_data = val; 276 } 277 278 void 279 zs_abort(struct zs_chanstate *cs) 280 { 281 282 #ifdef DDB 283 Debugger(); 284 #endif 285 } 286 287 /* 288 * Polled input char. 289 */ 290 int 291 zs_getc(void *arg) 292 { 293 struct zs_chanstate *cs = arg; 294 int s, c, rr0; 295 296 s = splhigh(); 297 /* Wait for a character to arrive. */ 298 do { 299 rr0 = *cs->cs_reg_csr; 300 ZS_DELAY(); 301 } while ((rr0 & ZSRR0_RX_READY) == 0); 302 303 c = *cs->cs_reg_data; 304 ZS_DELAY(); 305 splx(s); 306 307 /* 308 * This could be used by the kd driver to read scan codes, 309 * so don't translate '\r' ==> '\n' here... 310 */ 311 return c; 312 } 313 314 /* 315 * Polled output char. 316 */ 317 void 318 zs_putc(void *arg, int c) 319 { 320 struct zs_chanstate *cs = arg; 321 int s, rr0; 322 323 s = splhigh(); 324 /* Wait for transmitter to become ready. */ 325 do { 326 rr0 = *cs->cs_reg_csr; 327 ZS_DELAY(); 328 } while ((rr0 & ZSRR0_TX_READY) == 0); 329 330 *cs->cs_reg_data = c; 331 ZS_DELAY(); 332 splx(s); 333 } 334 335 int 336 zscngetc(dev_t dev) 337 { 338 339 return zs_getc((void *)zs_conscs); 340 } 341 342 void 343 zscnputc(dev_t dev, int c) 344 { 345 346 zs_putc((void *)zs_conscs, c); 347 } 348