1 /* $NetBSD: zs.c,v 1.5 2008/04/28 20:23:18 martin 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 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* 33 * Zilog Z8530 Dual UART driver (machine-dependent part) 34 * 35 * Runs two serial lines per chip using slave drivers. 36 * Plain tty/async lines use the zs_async slave. 37 */ 38 39 #include <sys/cdefs.h> 40 __KERNEL_RCSID(0, "$NetBSD: zs.c,v 1.5 2008/04/28 20:23:18 martin Exp $"); 41 42 #include "opt_ddb.h" 43 44 #include <sys/param.h> 45 #include <sys/device.h> 46 #include <sys/tty.h> 47 #include <sys/systm.h> 48 #include <sys/intr.h> 49 50 #include <machine/z8530var.h> 51 #include <dev/ic/z8530reg.h> 52 53 #include "ioconf.h" 54 55 /* console status for consinit() */ 56 static struct zs_chanstate zs_conscs_store; 57 struct zs_chanstate *zs_conscs = &zs_conscs_store; 58 void *zs_consaddr; 59 60 /* 61 * Some warts needed by z8530tty.c - 62 * The default parity REALLY needs to be the same as the PROM uses, 63 * or you can not see messages done with printf during boot-up... 64 */ 65 int zs_def_cflag = (CREAD | CS8 | HUPCL); 66 67 int 68 zs_print(void *aux, const char *name) 69 { 70 struct zsc_attach_args *args = aux; 71 72 if (name != NULL) 73 aprint_normal("%s: ", name); 74 75 if (args->channel != -1) 76 aprint_normal(" channel %d", args->channel); 77 78 return UNCONF; 79 } 80 81 int 82 zshard(void *arg) 83 { 84 struct zsc_softc *zsc; 85 int rval; 86 87 zsc = arg; 88 rval = zsc_intr_hard(zsc); 89 if (zsc->zsc_cs[0]->cs_softreq || zsc->zsc_cs[1]->cs_softreq) 90 softint_schedule(zsc->zsc_si); 91 92 return rval; 93 } 94 95 /* 96 * Compute the current baud rate given a ZS channel. 97 */ 98 int 99 zs_get_speed(struct zs_chanstate *cs) 100 { 101 int tconst; 102 103 tconst = zs_read_reg(cs, 12); 104 tconst |= zs_read_reg(cs, 13) << 8; 105 return TCONST_TO_BPS(cs->cs_brg_clk, tconst); 106 } 107 108 /* 109 * MD functions for setting the baud rate and control modes. 110 */ 111 int 112 zs_set_speed(struct zs_chanstate *cs, int bps) 113 { 114 int tconst, real_bps; 115 116 if (bps == 0) 117 return 0; 118 119 #ifdef DIAGNOSTIC 120 if (cs->cs_brg_clk == 0) 121 panic("zs_set_speed"); 122 #endif 123 124 tconst = BPS_TO_TCONST(cs->cs_brg_clk, bps); 125 if (tconst < 0) 126 return EINVAL; 127 128 /* Convert back to make sure we can do it. */ 129 real_bps = TCONST_TO_BPS(cs->cs_brg_clk, tconst); 130 131 /* XXX - Allow some tolerance here? */ 132 if (real_bps != bps) 133 return EINVAL; 134 135 cs->cs_preg[12] = tconst; 136 cs->cs_preg[13] = tconst >> 8; 137 138 /* Caller will stuff the pending registers. */ 139 return 0; 140 } 141 142 int 143 zs_set_modes(struct zs_chanstate *cs, int cflag) 144 { 145 int s; 146 147 /* 148 * Output hardware flow control on the chip is horrendous: 149 * if carrier detect drops, the receiver is disabled, and if 150 * CTS drops, the transmitter is stoped IN MID CHARACTER! 151 * Therefore, NEVER set the HFC bit, and instead use the 152 * status interrupt to detect CTS changes. 153 */ 154 s = splserial(); 155 cs->cs_rr0_pps = 0; 156 if ((cflag & (CLOCAL | MDMBUF)) != 0) { 157 cs->cs_rr0_dcd = 0; 158 if ((cflag & MDMBUF) == 0) 159 cs->cs_rr0_pps = ZSRR0_DCD; 160 } else 161 cs->cs_rr0_dcd = ZSRR0_DCD; 162 if ((cflag & CRTSCTS) != 0) { 163 cs->cs_wr5_dtr = ZSWR5_DTR; 164 cs->cs_wr5_rts = ZSWR5_RTS; 165 cs->cs_rr0_cts = ZSRR0_CTS; 166 } else if ((cflag & MDMBUF) != 0) { 167 cs->cs_wr5_dtr = 0; 168 cs->cs_wr5_rts = ZSWR5_DTR; 169 cs->cs_rr0_cts = ZSRR0_DCD; 170 } else { 171 cs->cs_wr5_dtr = ZSWR5_DTR | ZSWR5_RTS; 172 cs->cs_wr5_rts = 0; 173 cs->cs_rr0_cts = 0; 174 } 175 splx(s); 176 177 /* Caller will stuff the pending registers. */ 178 return 0; 179 } 180 181 /* 182 * Read or write the chip with suitable delays. 183 */ 184 uint8_t 185 zs_read_reg(struct zs_chanstate *cs, uint8_t reg) 186 { 187 uint8_t val; 188 189 *cs->cs_reg_csr = reg; 190 191 val = *cs->cs_reg_csr; 192 193 return val; 194 } 195 196 void 197 zs_write_reg(struct zs_chanstate *cs, uint8_t reg, uint8_t val) 198 { 199 200 *cs->cs_reg_csr = reg; 201 202 *cs->cs_reg_csr = val; 203 204 } 205 206 uint8_t 207 zs_read_csr(struct zs_chanstate *cs) 208 { 209 uint8_t val; 210 211 val = *cs->cs_reg_csr; 212 213 return val; 214 } 215 216 void 217 zs_write_csr(struct zs_chanstate *cs, uint8_t val) 218 { 219 220 *cs->cs_reg_csr = val; 221 222 } 223 224 uint8_t 225 zs_read_data(struct zs_chanstate *cs) 226 { 227 uint8_t val; 228 229 val = *cs->cs_reg_data; 230 231 return val; 232 } 233 234 void 235 zs_write_data(struct zs_chanstate *cs, uint8_t val) 236 { 237 238 *cs->cs_reg_data = val; 239 } 240 241 void 242 zs_abort(struct zs_chanstate *cs) 243 { 244 245 #ifdef DDB 246 Debugger(); 247 #endif 248 } 249 250 /* 251 * Polled input char. 252 */ 253 int 254 zs_getc(void *arg) 255 { 256 struct zs_chanstate *cs = arg; 257 int s, c; 258 uint8_t rr0; 259 260 s = splhigh(); 261 /* Wait for a character to arrive. */ 262 do { 263 rr0 = *cs->cs_reg_csr; 264 ZS_DELAY(); 265 } while ((rr0 & ZSRR0_RX_READY) == 0); 266 267 c = *cs->cs_reg_data; 268 ZS_DELAY(); 269 splx(s); 270 271 /* 272 * This could be used by the kd driver to read scan codes, 273 * so don't translate '\r' ==> '\n' here... 274 */ 275 return c; 276 } 277 278 /* 279 * Polled output char. 280 */ 281 void 282 zs_putc(void *arg, int c) 283 { 284 struct zs_chanstate *cs = arg; 285 int s; 286 uint8_t rr0; 287 288 s = splhigh(); 289 /* Wait for transmitter to become ready. */ 290 do { 291 rr0 = *cs->cs_reg_csr; 292 ZS_DELAY(); 293 } while ((rr0 & ZSRR0_TX_READY) == 0); 294 295 *cs->cs_reg_data = c; 296 ZS_DELAY(); 297 splx(s); 298 } 299 300 int 301 zscngetc(dev_t dev) 302 { 303 304 return zs_getc((void *)zs_conscs); 305 } 306 307 void 308 zscnputc(dev_t dev, int c) 309 { 310 311 zs_putc((void *)zs_conscs, c); 312 } 313