1 1.24 andvar /* $NetBSD: zs.c,v 1.24 2021/09/11 20:28:03 andvar Exp $ */ 2 1.1 drochner 3 1.1 drochner /*- 4 1.1 drochner * Copyright (c) 1996 The NetBSD Foundation, Inc. 5 1.1 drochner * All rights reserved. 6 1.1 drochner * 7 1.1 drochner * This code is derived from software contributed to The NetBSD Foundation 8 1.1 drochner * by Gordon W. Ross. 9 1.1 drochner * 10 1.1 drochner * Redistribution and use in source and binary forms, with or without 11 1.1 drochner * modification, are permitted provided that the following conditions 12 1.1 drochner * are met: 13 1.1 drochner * 1. Redistributions of source code must retain the above copyright 14 1.1 drochner * notice, this list of conditions and the following disclaimer. 15 1.1 drochner * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 drochner * notice, this list of conditions and the following disclaimer in the 17 1.1 drochner * documentation and/or other materials provided with the distribution. 18 1.1 drochner * 19 1.1 drochner * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 1.1 drochner * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 1.1 drochner * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 1.1 drochner * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 1.1 drochner * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 1.1 drochner * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 1.1 drochner * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.1 drochner * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 1.1 drochner * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.1 drochner * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 1.1 drochner * POSSIBILITY OF SUCH DAMAGE. 30 1.1 drochner */ 31 1.1 drochner 32 1.1 drochner /* 33 1.1 drochner * Zilog Z8530 Dual UART driver (machine-dependent part) 34 1.1 drochner * 35 1.1 drochner * Runs two serial lines per chip using slave drivers. 36 1.1 drochner * Plain tty/async lines use the zs_async slave. 37 1.1 drochner */ 38 1.8 lukem 39 1.8 lukem #include <sys/cdefs.h> 40 1.24 andvar __KERNEL_RCSID(0, "$NetBSD: zs.c,v 1.24 2021/09/11 20:28:03 andvar Exp $"); 41 1.1 drochner 42 1.1 drochner #include "opt_ddb.h" 43 1.1 drochner 44 1.1 drochner #include <sys/param.h> 45 1.1 drochner #include <sys/systm.h> 46 1.1 drochner #include <sys/conf.h> 47 1.1 drochner #include <sys/device.h> 48 1.1 drochner #include <sys/file.h> 49 1.1 drochner #include <sys/ioctl.h> 50 1.1 drochner #include <sys/kernel.h> 51 1.21 thorpej #include <sys/kmem.h> 52 1.1 drochner #include <sys/proc.h> 53 1.1 drochner #include <sys/tty.h> 54 1.1 drochner #include <sys/time.h> 55 1.1 drochner #include <sys/syslog.h> 56 1.1 drochner 57 1.1 drochner #include <dev/cons.h> 58 1.1 drochner #include <dev/ic/z8530reg.h> 59 1.1 drochner 60 1.1 drochner #include <machine/cpu.h> 61 1.1 drochner 62 1.1 drochner #include <machine/z8530var.h> 63 1.1 drochner #include <cesfic/dev/zsvar.h> 64 1.1 drochner 65 1.14 tsutsui #include "ioconf.h" 66 1.14 tsutsui 67 1.14 tsutsui int zs_getc(void *); 68 1.14 tsutsui void zs_putc(void*, int); 69 1.1 drochner 70 1.1 drochner static struct zs_chanstate zs_conschan_store; 71 1.1 drochner static int zs_hwflags[2][2]; 72 1.1 drochner 73 1.14 tsutsui static uint8_t zs_init_reg[16] = { 74 1.1 drochner 0, /* 0: CMD (reset, etc.) */ 75 1.1 drochner 0, /* 1: No interrupts yet. */ 76 1.1 drochner 0x18 + ZSHARD_PRI, /* IVECT */ 77 1.1 drochner ZSWR3_RX_8 | ZSWR3_RX_ENABLE, 78 1.1 drochner ZSWR4_CLK_X16 | ZSWR4_ONESB | ZSWR4_EVENP, 79 1.1 drochner ZSWR5_TX_8 | ZSWR5_TX_ENABLE, 80 1.1 drochner 0, /* 6: TXSYNC/SYNCLO */ 81 1.1 drochner 0, /* 7: RXSYNC/SYNCHI */ 82 1.1 drochner 0, /* 8: alias for data port */ 83 1.1 drochner ZSWR9_MASTER_IE, 84 1.1 drochner 0, /*10: Misc. TX/RX control bits */ 85 1.1 drochner ZSWR11_TXCLK_BAUD | ZSWR11_RXCLK_BAUD, 86 1.1 drochner 11, /*12: BAUDLO (default=9600) */ 87 1.1 drochner 0, /*13: BAUDHI (default=9600) */ 88 1.1 drochner ZSWR14_BAUD_ENA | ZSWR14_BAUD_FROM_PCLK, 89 1.1 drochner ZSWR15_BREAK_IE | ZSWR15_DCD_IE, 90 1.1 drochner }; 91 1.1 drochner 92 1.14 tsutsui static int zsc_print(void *, const char *); 93 1.14 tsutsui int zscngetc(dev_t); 94 1.14 tsutsui void zscnputc(dev_t, int); 95 1.1 drochner 96 1.7 drochner static struct consdev zscons = { 97 1.7 drochner NULL, NULL, 98 1.7 drochner zscngetc, zscnputc, nullcnpollc, NULL, NULL, NULL, 99 1.7 drochner NODEV, 1 100 1.7 drochner }; 101 1.1 drochner 102 1.1 drochner void 103 1.14 tsutsui zs_config(struct zsc_softc *zsc, char *base) 104 1.1 drochner { 105 1.1 drochner struct zsc_attach_args zsc_args; 106 1.1 drochner struct zs_chanstate *cs; 107 1.1 drochner int zsc_unit, channel, s; 108 1.1 drochner 109 1.14 tsutsui zsc_unit = device_unit(zsc->zsc_dev); 110 1.14 tsutsui aprint_normal(": Zilog 8530 SCC\n"); 111 1.1 drochner 112 1.1 drochner /* 113 1.1 drochner * Initialize software state for each channel. 114 1.1 drochner */ 115 1.1 drochner for (channel = 0; channel < 2; channel++) { 116 1.1 drochner zsc_args.channel = channel; 117 1.1 drochner zsc_args.hwflags = zs_hwflags[zsc_unit][channel]; 118 1.1 drochner 119 1.1 drochner /* 120 1.1 drochner * If we're the console, copy the channel state, and 121 1.1 drochner * adjust the console channel pointer. 122 1.1 drochner */ 123 1.1 drochner if (zsc_args.hwflags & ZS_HWFLAG_CONSOLE) { 124 1.1 drochner cs = &zs_conschan_store; 125 1.1 drochner } else { 126 1.21 thorpej cs = kmem_zalloc(sizeof(*cs), KM_SLEEP); 127 1.1 drochner if(channel==0){ 128 1.14 tsutsui cs->cs_reg_csr = base + 7; 129 1.14 tsutsui cs->cs_reg_data = base + 15; 130 1.1 drochner } else { 131 1.14 tsutsui cs->cs_reg_csr = base + 3; 132 1.14 tsutsui cs->cs_reg_data = base + 11; 133 1.1 drochner } 134 1.14 tsutsui memcpy(cs->cs_creg, zs_init_reg, 16); 135 1.14 tsutsui memcpy(cs->cs_preg, zs_init_reg, 16); 136 1.1 drochner cs->cs_defspeed = 9600; 137 1.1 drochner } 138 1.1 drochner zsc->zsc_cs[channel] = cs; 139 1.12 ad zs_lock_init(cs); 140 1.1 drochner 141 1.1 drochner cs->cs_defcflag = CREAD | CS8 | HUPCL; 142 1.1 drochner 143 1.1 drochner /* Make these correspond to cs_defcflag (-crtscts) */ 144 1.1 drochner cs->cs_rr0_dcd = ZSRR0_DCD; 145 1.1 drochner cs->cs_rr0_cts = 0; 146 1.1 drochner cs->cs_wr5_dtr = ZSWR5_DTR | ZSWR5_RTS; 147 1.1 drochner cs->cs_wr5_rts = 0; 148 1.1 drochner 149 1.1 drochner cs->cs_channel = channel; 150 1.1 drochner cs->cs_private = NULL; 151 1.1 drochner cs->cs_ops = &zsops_null; 152 1.1 drochner cs->cs_brg_clk = 4000000 / 16; 153 1.1 drochner 154 1.1 drochner /* 155 1.1 drochner * Clear the master interrupt enable. 156 1.1 drochner * The INTENA is common to both channels, 157 1.1 drochner * so just do it on the A channel. 158 1.1 drochner */ 159 1.1 drochner if (channel == 0) { 160 1.1 drochner zs_write_reg(cs, 9, 0); 161 1.1 drochner } 162 1.1 drochner 163 1.1 drochner /* 164 1.1 drochner * Look for a child driver for this channel. 165 1.1 drochner * The child attach will setup the hardware. 166 1.1 drochner */ 167 1.14 tsutsui if (!config_found(zsc->zsc_dev, (void *)&zsc_args, 168 1.23 thorpej zsc_print, CFARGS_NONE)) { 169 1.1 drochner /* No sub-driver. Just reset it. */ 170 1.14 tsutsui uint8_t reset = (channel == 0) ? 171 1.1 drochner ZSWR9_A_RESET : ZSWR9_B_RESET; 172 1.1 drochner s = splzs(); 173 1.1 drochner zs_write_reg(cs, 9, reset); 174 1.1 drochner splx(s); 175 1.1 drochner } 176 1.1 drochner } 177 1.1 drochner } 178 1.1 drochner 179 1.1 drochner static int 180 1.14 tsutsui zsc_print(void *aux, const char *name) 181 1.1 drochner { 182 1.1 drochner struct zsc_attach_args *args = aux; 183 1.1 drochner 184 1.1 drochner if (name != NULL) 185 1.5 thorpej aprint_normal("%s: ", name); 186 1.1 drochner 187 1.1 drochner if (args->channel != -1) 188 1.5 thorpej aprint_normal(" channel %d", args->channel); 189 1.1 drochner 190 1.1 drochner return UNCONF; 191 1.1 drochner } 192 1.1 drochner 193 1.1 drochner int 194 1.14 tsutsui zshard(void *arg) 195 1.1 drochner { 196 1.14 tsutsui struct zsc_softc *zsc; 197 1.14 tsutsui int unit, rval; 198 1.1 drochner 199 1.1 drochner rval = 0; 200 1.1 drochner for (unit = 0; unit < zsc_cd.cd_ndevs; unit++) { 201 1.16 cegger zsc = device_lookup_private(&zsc_cd, unit); 202 1.1 drochner if (zsc == NULL) 203 1.1 drochner continue; 204 1.1 drochner rval |= zsc_intr_hard(zsc); 205 1.1 drochner if ((zsc->zsc_cs[0]->cs_softreq) || 206 1.11 tsutsui (zsc->zsc_cs[1]->cs_softreq)) { 207 1.13 ad softint_schedule(zsc->zsc_softintr_cookie); 208 1.1 drochner } 209 1.1 drochner } 210 1.1 drochner return (rval); 211 1.1 drochner } 212 1.1 drochner 213 1.14 tsutsui uint8_t 214 1.14 tsutsui zs_read_reg(struct zs_chanstate *cs, uint8_t reg) 215 1.1 drochner { 216 1.14 tsutsui uint8_t val; 217 1.1 drochner 218 1.1 drochner *cs->cs_reg_csr = reg; 219 1.1 drochner ZS_DELAY(); 220 1.1 drochner val = *cs->cs_reg_csr; 221 1.1 drochner ZS_DELAY(); 222 1.1 drochner return val; 223 1.1 drochner } 224 1.1 drochner 225 1.1 drochner void 226 1.14 tsutsui zs_write_reg(struct zs_chanstate *cs, uint8_t reg, uint8_t val) 227 1.1 drochner { 228 1.1 drochner *cs->cs_reg_csr = reg; 229 1.1 drochner ZS_DELAY(); 230 1.1 drochner *cs->cs_reg_csr = val; 231 1.1 drochner ZS_DELAY(); 232 1.1 drochner } 233 1.1 drochner 234 1.14 tsutsui uint8_t 235 1.14 tsutsui zs_read_csr(struct zs_chanstate *cs) 236 1.1 drochner { 237 1.14 tsutsui uint8_t val; 238 1.1 drochner 239 1.1 drochner val = *cs->cs_reg_csr; 240 1.1 drochner ZS_DELAY(); 241 1.1 drochner return val; 242 1.1 drochner } 243 1.1 drochner 244 1.14 tsutsui void 245 1.14 tsutsui zs_write_csr(struct zs_chanstate *cs, uint8_t val) 246 1.1 drochner { 247 1.14 tsutsui 248 1.1 drochner *cs->cs_reg_csr = val; 249 1.1 drochner ZS_DELAY(); 250 1.1 drochner } 251 1.1 drochner 252 1.14 tsutsui uint8_t 253 1.14 tsutsui zs_read_data(struct zs_chanstate *cs) 254 1.1 drochner { 255 1.14 tsutsui uint8_t val; 256 1.1 drochner 257 1.1 drochner val = *cs->cs_reg_data; 258 1.1 drochner ZS_DELAY(); 259 1.1 drochner return val; 260 1.1 drochner } 261 1.1 drochner 262 1.14 tsutsui void 263 1.14 tsutsui zs_write_data(struct zs_chanstate *cs, uint8_t val) 264 1.1 drochner { 265 1.14 tsutsui 266 1.1 drochner *cs->cs_reg_data = val; 267 1.1 drochner ZS_DELAY(); 268 1.1 drochner } 269 1.1 drochner 270 1.1 drochner int 271 1.14 tsutsui zs_set_speed(struct zs_chanstate *cs, int bps) 272 1.1 drochner { 273 1.19 christos int tconst; 274 1.1 drochner 275 1.1 drochner tconst = BPS_TO_TCONST(cs->cs_brg_clk, bps); 276 1.1 drochner 277 1.1 drochner if (tconst < 0) 278 1.1 drochner return (EINVAL); 279 1.1 drochner 280 1.19 christos #if 0 281 1.1 drochner /* Convert back to make sure we can do it. */ 282 1.19 christos int real_bps = TCONST_TO_BPS(cs->cs_brg_clk, tconst); 283 1.1 drochner /* XXX - Allow some tolerance here? */ 284 1.1 drochner if (real_bps != bps) 285 1.1 drochner return (EINVAL); 286 1.1 drochner #endif 287 1.1 drochner cs->cs_preg[12] = tconst; 288 1.1 drochner cs->cs_preg[13] = tconst >> 8; 289 1.1 drochner 290 1.1 drochner return (0); 291 1.1 drochner } 292 1.1 drochner 293 1.1 drochner int 294 1.14 tsutsui zs_set_modes(struct zs_chanstate *cs, int cflag) 295 1.1 drochner { 296 1.1 drochner int s; 297 1.1 drochner 298 1.1 drochner /* 299 1.1 drochner * Output hardware flow control on the chip is horrendous: 300 1.1 drochner * if carrier detect drops, the receiver is disabled, and if 301 1.24 andvar * CTS drops, the transmitter is stopped IN MID CHARACTER! 302 1.1 drochner * Therefore, NEVER set the HFC bit, and instead use the 303 1.1 drochner * status interrupt to detect CTS changes. 304 1.1 drochner */ 305 1.1 drochner s = splzs(); 306 1.1 drochner #if 0 /* XXX - See below. */ 307 1.1 drochner if (cflag & CLOCAL) { 308 1.1 drochner cs->cs_rr0_dcd = 0; 309 1.1 drochner cs->cs_preg[15] &= ~ZSWR15_DCD_IE; 310 1.1 drochner } else { 311 1.1 drochner /* XXX - Need to notice DCD change here... */ 312 1.1 drochner cs->cs_rr0_dcd = ZSRR0_DCD; 313 1.1 drochner cs->cs_preg[15] |= ZSWR15_DCD_IE; 314 1.1 drochner } 315 1.1 drochner #endif /* XXX */ 316 1.1 drochner if (cflag & CRTSCTS) { 317 1.1 drochner cs->cs_wr5_dtr = ZSWR5_DTR; 318 1.1 drochner cs->cs_wr5_rts = ZSWR5_RTS; 319 1.1 drochner cs->cs_rr0_cts = ZSRR0_CTS; 320 1.1 drochner cs->cs_preg[15] |= ZSWR15_CTS_IE; 321 1.1 drochner } else { 322 1.1 drochner cs->cs_wr5_dtr = ZSWR5_DTR | ZSWR5_RTS; 323 1.1 drochner cs->cs_wr5_rts = 0; 324 1.1 drochner cs->cs_rr0_cts = 0; 325 1.1 drochner cs->cs_preg[15] &= ~ZSWR15_CTS_IE; 326 1.1 drochner } 327 1.1 drochner splx(s); 328 1.1 drochner 329 1.1 drochner /* Caller will stuff the pending registers. */ 330 1.1 drochner return (0); 331 1.1 drochner } 332 1.1 drochner 333 1.1 drochner /* 334 1.1 drochner * Handle user request to enter kernel debugger. 335 1.1 drochner */ 336 1.1 drochner void 337 1.14 tsutsui zs_abort(struct zs_chanstate *cs) 338 1.1 drochner { 339 1.1 drochner int rr0; 340 1.1 drochner 341 1.1 drochner /* Wait for end of break to avoid PROM abort. */ 342 1.1 drochner /* XXX - Limit the wait? */ 343 1.1 drochner do { 344 1.1 drochner rr0 = *cs->cs_reg_csr; 345 1.1 drochner ZS_DELAY(); 346 1.1 drochner } while (rr0 & ZSRR0_BREAK); 347 1.1 drochner #ifdef DDB 348 1.1 drochner console_debugger(); 349 1.1 drochner #endif 350 1.1 drochner } 351 1.1 drochner 352 1.1 drochner /* 353 1.1 drochner * Polled input char. 354 1.1 drochner */ 355 1.1 drochner int 356 1.14 tsutsui zs_getc(void *arg) 357 1.1 drochner { 358 1.14 tsutsui struct zs_chanstate *cs = arg; 359 1.14 tsutsui int s, c; 360 1.14 tsutsui uint8_t rr0, stat; 361 1.1 drochner 362 1.1 drochner s = splhigh(); 363 1.1 drochner top: 364 1.1 drochner /* Wait for a character to arrive. */ 365 1.1 drochner do { 366 1.1 drochner rr0 = *cs->cs_reg_csr; 367 1.1 drochner ZS_DELAY(); 368 1.1 drochner } while ((rr0 & ZSRR0_RX_READY) == 0); 369 1.1 drochner 370 1.1 drochner /* Read error register. */ 371 1.1 drochner stat = zs_read_reg(cs, 1) & (ZSRR1_FE | ZSRR1_DO | ZSRR1_PE); 372 1.1 drochner if (stat) { 373 1.1 drochner zs_write_csr(cs, ZSM_RESET_ERR); 374 1.1 drochner goto top; 375 1.1 drochner } 376 1.1 drochner 377 1.1 drochner /* Read character. */ 378 1.1 drochner c = *cs->cs_reg_data; 379 1.1 drochner ZS_DELAY(); 380 1.1 drochner splx(s); 381 1.1 drochner 382 1.1 drochner return (c); 383 1.1 drochner } 384 1.1 drochner 385 1.1 drochner /* 386 1.1 drochner * Polled output char. 387 1.1 drochner */ 388 1.1 drochner void 389 1.14 tsutsui zs_putc(void *arg, int c) 390 1.1 drochner { 391 1.14 tsutsui struct zs_chanstate *cs = arg; 392 1.14 tsutsui int s; 393 1.14 tsutsui uint8_t rr0; 394 1.1 drochner 395 1.1 drochner s = splhigh(); 396 1.1 drochner /* Wait for transmitter to become ready. */ 397 1.1 drochner do { 398 1.1 drochner rr0 = *cs->cs_reg_csr; 399 1.1 drochner ZS_DELAY(); 400 1.1 drochner } while ((rr0 & ZSRR0_TX_READY) == 0); 401 1.1 drochner 402 1.1 drochner *cs->cs_reg_data = c; 403 1.1 drochner ZS_DELAY(); 404 1.1 drochner splx(s); 405 1.1 drochner } 406 1.1 drochner 407 1.14 tsutsui int 408 1.14 tsutsui zscngetc(dev_t dev) 409 1.1 drochner { 410 1.14 tsutsui struct zs_chanstate *cs = &zs_conschan_store; 411 1.14 tsutsui int c; 412 1.1 drochner 413 1.1 drochner c = zs_getc(cs); 414 1.1 drochner return (c); 415 1.1 drochner } 416 1.1 drochner 417 1.14 tsutsui void 418 1.14 tsutsui zscnputc(dev_t dev, int c) 419 1.1 drochner { 420 1.14 tsutsui struct zs_chanstate *cs = &zs_conschan_store; 421 1.1 drochner 422 1.1 drochner zs_putc(cs, c); 423 1.1 drochner } 424 1.1 drochner 425 1.1 drochner /* 426 1.1 drochner * Common parts of console init. 427 1.1 drochner */ 428 1.1 drochner void 429 1.14 tsutsui zs_cninit(void *base) 430 1.1 drochner { 431 1.1 drochner struct zs_chanstate *cs; 432 1.1 drochner /* 433 1.1 drochner * Pointer to channel state. Later, the console channel 434 1.1 drochner * state is copied into the softc, and the console channel 435 1.1 drochner * pointer adjusted to point to the new copy. 436 1.1 drochner */ 437 1.1 drochner cs = &zs_conschan_store; 438 1.1 drochner zs_hwflags[0][0] = ZS_HWFLAG_CONSOLE; 439 1.1 drochner 440 1.1 drochner /* Setup temporary chanstate. */ 441 1.14 tsutsui cs->cs_reg_csr = (uint8_t *)base + 7; 442 1.14 tsutsui cs->cs_reg_data = (uint8_t *)base + 15; 443 1.1 drochner 444 1.1 drochner /* Initialize the pending registers. */ 445 1.18 cegger memcpy(cs->cs_preg, zs_init_reg, 16); 446 1.1 drochner cs->cs_preg[5] |= (ZSWR5_DTR | ZSWR5_RTS); 447 1.1 drochner 448 1.1 drochner /* XXX: Preserve BAUD rate from boot loader. */ 449 1.1 drochner /* XXX: Also, why reset the chip here? -gwr */ 450 1.1 drochner /* cs->cs_defspeed = zs_get_speed(cs); */ 451 1.1 drochner cs->cs_defspeed = 9600; /* XXX */ 452 1.1 drochner 453 1.1 drochner /* Clear the master interrupt enable. */ 454 1.1 drochner zs_write_reg(cs, 9, 0); 455 1.1 drochner 456 1.1 drochner /* Reset the whole SCC chip. */ 457 1.1 drochner zs_write_reg(cs, 9, ZSWR9_HARD_RESET); 458 1.1 drochner 459 1.1 drochner /* Copy "pending" to "current" and H/W. */ 460 1.1 drochner zs_loadchannelregs(cs); 461 1.1 drochner 462 1.1 drochner /* Point the console at the SCC. */ 463 1.1 drochner cn_tab = &zscons; 464 1.1 drochner } 465