1 /* $NetBSD: zs.c,v 1.3 2007/11/26 23:29:37 ad 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.3 2007/11/26 23:29:37 ad 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 #include <sys/intr.h> 56 57 #include <machine/z8530var.h> 58 #include <dev/ic/z8530reg.h> 59 60 #include "ioconf.h" 61 62 /* console status for consinit() */ 63 static struct zs_chanstate zs_conscs_store; 64 struct zs_chanstate *zs_conscs = &zs_conscs_store; 65 void *zs_consaddr; 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(void *aux, const char *name) 76 { 77 struct zsc_attach_args *args = aux; 78 79 if (name != NULL) 80 aprint_normal("%s: ", name); 81 82 if (args->channel != -1) 83 aprint_normal(" channel %d", args->channel); 84 85 return UNCONF; 86 } 87 88 int 89 zshard(void *arg) 90 { 91 struct zsc_softc *zsc; 92 int rval; 93 94 zsc = arg; 95 rval = zsc_intr_hard(zsc); 96 if (zsc->zsc_cs[0]->cs_softreq || zsc->zsc_cs[1]->cs_softreq) 97 softint_schedule(zsc->zsc_si); 98 99 return rval; 100 } 101 102 /* 103 * Compute the current baud rate given a ZS channel. 104 */ 105 int 106 zs_get_speed(struct zs_chanstate *cs) 107 { 108 int tconst; 109 110 tconst = zs_read_reg(cs, 12); 111 tconst |= zs_read_reg(cs, 13) << 8; 112 return TCONST_TO_BPS(cs->cs_brg_clk, tconst); 113 } 114 115 /* 116 * MD functions for setting the baud rate and control modes. 117 */ 118 int 119 zs_set_speed(struct zs_chanstate *cs, int bps) 120 { 121 int tconst, real_bps; 122 123 if (bps == 0) 124 return 0; 125 126 #ifdef DIAGNOSTIC 127 if (cs->cs_brg_clk == 0) 128 panic("zs_set_speed"); 129 #endif 130 131 tconst = BPS_TO_TCONST(cs->cs_brg_clk, bps); 132 if (tconst < 0) 133 return EINVAL; 134 135 /* Convert back to make sure we can do it. */ 136 real_bps = TCONST_TO_BPS(cs->cs_brg_clk, tconst); 137 138 /* XXX - Allow some tolerance here? */ 139 if (real_bps != bps) 140 return EINVAL; 141 142 cs->cs_preg[12] = tconst; 143 cs->cs_preg[13] = tconst >> 8; 144 145 /* Caller will stuff the pending registers. */ 146 return 0; 147 } 148 149 int 150 zs_set_modes(struct zs_chanstate *cs, int cflag) 151 { 152 int s; 153 154 /* 155 * Output hardware flow control on the chip is horrendous: 156 * if carrier detect drops, the receiver is disabled, and if 157 * CTS drops, the transmitter is stoped IN MID CHARACTER! 158 * Therefore, NEVER set the HFC bit, and instead use the 159 * status interrupt to detect CTS changes. 160 */ 161 s = splserial(); 162 cs->cs_rr0_pps = 0; 163 if ((cflag & (CLOCAL | MDMBUF)) != 0) { 164 cs->cs_rr0_dcd = 0; 165 if ((cflag & MDMBUF) == 0) 166 cs->cs_rr0_pps = ZSRR0_DCD; 167 } else 168 cs->cs_rr0_dcd = ZSRR0_DCD; 169 if ((cflag & CRTSCTS) != 0) { 170 cs->cs_wr5_dtr = ZSWR5_DTR; 171 cs->cs_wr5_rts = ZSWR5_RTS; 172 cs->cs_rr0_cts = ZSRR0_CTS; 173 } else if ((cflag & MDMBUF) != 0) { 174 cs->cs_wr5_dtr = 0; 175 cs->cs_wr5_rts = ZSWR5_DTR; 176 cs->cs_rr0_cts = ZSRR0_DCD; 177 } else { 178 cs->cs_wr5_dtr = ZSWR5_DTR | ZSWR5_RTS; 179 cs->cs_wr5_rts = 0; 180 cs->cs_rr0_cts = 0; 181 } 182 splx(s); 183 184 /* Caller will stuff the pending registers. */ 185 return 0; 186 } 187 188 /* 189 * Read or write the chip with suitable delays. 190 */ 191 uint8_t 192 zs_read_reg(struct zs_chanstate *cs, uint8_t reg) 193 { 194 uint8_t val; 195 196 *cs->cs_reg_csr = reg; 197 198 val = *cs->cs_reg_csr; 199 200 return val; 201 } 202 203 void 204 zs_write_reg(struct zs_chanstate *cs, uint8_t reg, uint8_t val) 205 { 206 207 *cs->cs_reg_csr = reg; 208 209 *cs->cs_reg_csr = val; 210 211 } 212 213 uint8_t 214 zs_read_csr(struct zs_chanstate *cs) 215 { 216 uint8_t val; 217 218 val = *cs->cs_reg_csr; 219 220 return val; 221 } 222 223 void 224 zs_write_csr(struct zs_chanstate *cs, uint8_t val) 225 { 226 227 *cs->cs_reg_csr = val; 228 229 } 230 231 uint8_t 232 zs_read_data(struct zs_chanstate *cs) 233 { 234 uint8_t val; 235 236 val = *cs->cs_reg_data; 237 238 return val; 239 } 240 241 void 242 zs_write_data(struct zs_chanstate *cs, uint8_t val) 243 { 244 245 *cs->cs_reg_data = val; 246 } 247 248 void 249 zs_abort(struct zs_chanstate *cs) 250 { 251 252 #ifdef DDB 253 Debugger(); 254 #endif 255 } 256 257 /* 258 * Polled input char. 259 */ 260 int 261 zs_getc(void *arg) 262 { 263 struct zs_chanstate *cs = arg; 264 int s, c, rr0; 265 266 s = splhigh(); 267 /* Wait for a character to arrive. */ 268 do { 269 rr0 = *cs->cs_reg_csr; 270 ZS_DELAY(); 271 } while ((rr0 & ZSRR0_RX_READY) == 0); 272 273 c = *cs->cs_reg_data; 274 ZS_DELAY(); 275 splx(s); 276 277 /* 278 * This could be used by the kd driver to read scan codes, 279 * so don't translate '\r' ==> '\n' here... 280 */ 281 return c; 282 } 283 284 /* 285 * Polled output char. 286 */ 287 void 288 zs_putc(void *arg, int c) 289 { 290 struct zs_chanstate *cs = arg; 291 int s, rr0; 292 293 s = splhigh(); 294 /* Wait for transmitter to become ready. */ 295 do { 296 rr0 = *cs->cs_reg_csr; 297 ZS_DELAY(); 298 } while ((rr0 & ZSRR0_TX_READY) == 0); 299 300 *cs->cs_reg_data = c; 301 ZS_DELAY(); 302 splx(s); 303 } 304 305 int 306 zscngetc(dev_t dev) 307 { 308 309 return zs_getc((void *)zs_conscs); 310 } 311 312 void 313 zscnputc(dev_t dev, int c) 314 { 315 316 zs_putc((void *)zs_conscs, c); 317 } 318