1 /* $NetBSD: zs.c,v 1.9 2005/12/11 12:17:05 christos 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 */ 45 46 #include <sys/cdefs.h> 47 __KERNEL_RCSID(0, "$NetBSD: zs.c,v 1.9 2005/12/11 12:17:05 christos Exp $"); 48 49 #include "opt_ddb.h" 50 51 #include <sys/param.h> 52 #include <sys/systm.h> 53 #include <sys/conf.h> 54 #include <sys/device.h> 55 #include <sys/file.h> 56 #include <sys/ioctl.h> 57 #include <sys/kernel.h> 58 #include <sys/malloc.h> 59 #include <sys/proc.h> 60 #include <sys/tty.h> 61 #include <sys/time.h> 62 #include <sys/syslog.h> 63 64 #include <dev/cons.h> 65 #include <dev/ic/z8530reg.h> 66 67 #include <machine/cpu.h> 68 69 #include <machine/z8530var.h> 70 #include <cesfic/dev/zsvar.h> 71 72 int zs_getc __P((void*)); 73 void zs_putc __P((void*, int)); 74 75 static struct zs_chanstate zs_conschan_store; 76 static int zs_hwflags[2][2]; 77 int zssoftpending; 78 79 extern struct cfdriver zsc_cd; 80 81 u_char zs_init_reg[16] = { 82 0, /* 0: CMD (reset, etc.) */ 83 0, /* 1: No interrupts yet. */ 84 0x18 + ZSHARD_PRI, /* IVECT */ 85 ZSWR3_RX_8 | ZSWR3_RX_ENABLE, 86 ZSWR4_CLK_X16 | ZSWR4_ONESB | ZSWR4_EVENP, 87 ZSWR5_TX_8 | ZSWR5_TX_ENABLE, 88 0, /* 6: TXSYNC/SYNCLO */ 89 0, /* 7: RXSYNC/SYNCHI */ 90 0, /* 8: alias for data port */ 91 ZSWR9_MASTER_IE, 92 0, /*10: Misc. TX/RX control bits */ 93 ZSWR11_TXCLK_BAUD | ZSWR11_RXCLK_BAUD, 94 11, /*12: BAUDLO (default=9600) */ 95 0, /*13: BAUDHI (default=9600) */ 96 ZSWR14_BAUD_ENA | ZSWR14_BAUD_FROM_PCLK, 97 ZSWR15_BREAK_IE | ZSWR15_DCD_IE, 98 }; 99 100 static int zsc_print __P((void *, const char *)); 101 int zscngetc __P((dev_t)); 102 void zscnputc __P((dev_t, int)); 103 104 static struct consdev zscons = { 105 NULL, NULL, 106 zscngetc, zscnputc, nullcnpollc, NULL, NULL, NULL, 107 NODEV, 1 108 }; 109 110 void 111 zs_config(zsc, base) 112 struct zsc_softc *zsc; 113 char *base; 114 { 115 struct zsc_attach_args zsc_args; 116 struct zs_chanstate *cs; 117 int zsc_unit, channel, s; 118 119 zsc_unit = zsc->zsc_dev.dv_unit; 120 printf(": Zilog 8530 SCC\n"); 121 122 /* 123 * Initialize software state for each channel. 124 */ 125 for (channel = 0; channel < 2; channel++) { 126 zsc_args.channel = channel; 127 zsc_args.hwflags = zs_hwflags[zsc_unit][channel]; 128 129 /* 130 * If we're the console, copy the channel state, and 131 * adjust the console channel pointer. 132 */ 133 if (zsc_args.hwflags & ZS_HWFLAG_CONSOLE) { 134 cs = &zs_conschan_store; 135 } else { 136 cs = malloc(sizeof(struct zs_chanstate), 137 M_DEVBUF, M_NOWAIT | M_ZERO); 138 if(channel==0){ 139 cs->cs_reg_csr = base+7; 140 cs->cs_reg_data = base+15; 141 } else { 142 cs->cs_reg_csr = base+3; 143 cs->cs_reg_data = base+11; 144 } 145 bcopy(zs_init_reg, cs->cs_creg, 16); 146 bcopy(zs_init_reg, cs->cs_preg, 16); 147 cs->cs_defspeed = 9600; 148 } 149 zsc->zsc_cs[channel] = cs; 150 simple_lock_init(&cs->cs_lock); 151 152 cs->cs_defcflag = CREAD | CS8 | HUPCL; 153 154 /* Make these correspond to cs_defcflag (-crtscts) */ 155 cs->cs_rr0_dcd = ZSRR0_DCD; 156 cs->cs_rr0_cts = 0; 157 cs->cs_wr5_dtr = ZSWR5_DTR | ZSWR5_RTS; 158 cs->cs_wr5_rts = 0; 159 160 cs->cs_channel = channel; 161 cs->cs_private = NULL; 162 cs->cs_ops = &zsops_null; 163 cs->cs_brg_clk = 4000000 / 16; 164 165 /* 166 * Clear the master interrupt enable. 167 * The INTENA is common to both channels, 168 * so just do it on the A channel. 169 */ 170 if (channel == 0) { 171 zs_write_reg(cs, 9, 0); 172 } 173 174 /* 175 * Look for a child driver for this channel. 176 * The child attach will setup the hardware. 177 */ 178 if (!config_found(&zsc->zsc_dev, (void *)&zsc_args, zsc_print)) { 179 /* No sub-driver. Just reset it. */ 180 u_char reset = (channel == 0) ? 181 ZSWR9_A_RESET : ZSWR9_B_RESET; 182 s = splzs(); 183 zs_write_reg(cs, 9, reset); 184 splx(s); 185 } 186 } 187 } 188 189 static int 190 zsc_print(aux, name) 191 void *aux; 192 const char *name; 193 { 194 struct zsc_attach_args *args = aux; 195 196 if (name != NULL) 197 aprint_normal("%s: ", name); 198 199 if (args->channel != -1) 200 aprint_normal(" channel %d", args->channel); 201 202 return UNCONF; 203 } 204 205 int 206 zshard(arg) 207 void *arg; 208 { 209 register struct zsc_softc *zsc; 210 register int unit, rval; 211 212 rval = 0; 213 for (unit = 0; unit < zsc_cd.cd_ndevs; unit++) { 214 zsc = zsc_cd.cd_devs[unit]; 215 if (zsc == NULL) 216 continue; 217 rval |= zsc_intr_hard(zsc); 218 if ((zsc->zsc_cs[0]->cs_softreq) || 219 (zsc->zsc_cs[1]->cs_softreq)) 220 { 221 /* zsc_req_softint(zsc); */ 222 /* We are at splzs here, so no need to lock. */ 223 if (zssoftpending == 0) { 224 zssoftpending = 1; 225 setsoftzs(); 226 } 227 } 228 } 229 return (rval); 230 } 231 232 void 233 softzs() 234 { 235 register struct zsc_softc *zsc; 236 register int unit; 237 238 /* This is not the only ISR on this IPL. */ 239 if (zssoftpending == 0) 240 return; 241 242 /* 243 * The soft intr. bit will be set by zshard only if 244 * the variable zssoftpending is zero. 245 */ 246 zssoftpending = 0; 247 248 for (unit = 0; unit < zsc_cd.cd_ndevs; ++unit) { 249 zsc = zsc_cd.cd_devs[unit]; 250 if (zsc == NULL) 251 continue; 252 (void) zsc_intr_soft(zsc); 253 } 254 return; 255 } 256 257 u_char 258 zs_read_reg(cs, reg) 259 struct zs_chanstate *cs; 260 u_char reg; 261 { 262 u_char val; 263 264 *cs->cs_reg_csr = reg; 265 ZS_DELAY(); 266 val = *cs->cs_reg_csr; 267 ZS_DELAY(); 268 return val; 269 } 270 271 void 272 zs_write_reg(cs, reg, val) 273 struct zs_chanstate *cs; 274 u_char reg, val; 275 { 276 *cs->cs_reg_csr = reg; 277 ZS_DELAY(); 278 *cs->cs_reg_csr = val; 279 ZS_DELAY(); 280 } 281 282 u_char zs_read_csr(cs) 283 struct zs_chanstate *cs; 284 { 285 register u_char val; 286 287 val = *cs->cs_reg_csr; 288 ZS_DELAY(); 289 return val; 290 } 291 292 void zs_write_csr(cs, val) 293 struct zs_chanstate *cs; 294 u_char val; 295 { 296 *cs->cs_reg_csr = val; 297 ZS_DELAY(); 298 } 299 300 u_char zs_read_data(cs) 301 struct zs_chanstate *cs; 302 { 303 register u_char val; 304 305 val = *cs->cs_reg_data; 306 ZS_DELAY(); 307 return val; 308 } 309 310 void zs_write_data(cs, val) 311 struct zs_chanstate *cs; 312 u_char val; 313 { 314 *cs->cs_reg_data = val; 315 ZS_DELAY(); 316 } 317 318 int 319 zs_set_speed(cs, bps) 320 struct zs_chanstate *cs; 321 int bps; /* bits per second */ 322 { 323 int tconst, real_bps; 324 325 tconst = BPS_TO_TCONST(cs->cs_brg_clk, bps); 326 327 if (tconst < 0) 328 return (EINVAL); 329 330 /* Convert back to make sure we can do it. */ 331 real_bps = TCONST_TO_BPS(cs->cs_brg_clk, tconst); 332 #if 0 333 /* XXX - Allow some tolerance here? */ 334 if (real_bps != bps) 335 return (EINVAL); 336 #endif 337 cs->cs_preg[12] = tconst; 338 cs->cs_preg[13] = tconst >> 8; 339 340 return (0); 341 } 342 343 int 344 zs_set_modes(cs, cflag) 345 struct zs_chanstate *cs; 346 int cflag; /* bits per second */ 347 { 348 int s; 349 350 /* 351 * Output hardware flow control on the chip is horrendous: 352 * if carrier detect drops, the receiver is disabled, and if 353 * CTS drops, the transmitter is stoped IN MID CHARACTER! 354 * Therefore, NEVER set the HFC bit, and instead use the 355 * status interrupt to detect CTS changes. 356 */ 357 s = splzs(); 358 #if 0 /* XXX - See below. */ 359 if (cflag & CLOCAL) { 360 cs->cs_rr0_dcd = 0; 361 cs->cs_preg[15] &= ~ZSWR15_DCD_IE; 362 } else { 363 /* XXX - Need to notice DCD change here... */ 364 cs->cs_rr0_dcd = ZSRR0_DCD; 365 cs->cs_preg[15] |= ZSWR15_DCD_IE; 366 } 367 #endif /* XXX */ 368 if (cflag & CRTSCTS) { 369 cs->cs_wr5_dtr = ZSWR5_DTR; 370 cs->cs_wr5_rts = ZSWR5_RTS; 371 cs->cs_rr0_cts = ZSRR0_CTS; 372 cs->cs_preg[15] |= ZSWR15_CTS_IE; 373 } else { 374 cs->cs_wr5_dtr = ZSWR5_DTR | ZSWR5_RTS; 375 cs->cs_wr5_rts = 0; 376 cs->cs_rr0_cts = 0; 377 cs->cs_preg[15] &= ~ZSWR15_CTS_IE; 378 } 379 splx(s); 380 381 /* Caller will stuff the pending registers. */ 382 return (0); 383 } 384 385 /* 386 * Handle user request to enter kernel debugger. 387 */ 388 void 389 zs_abort(cs) 390 struct zs_chanstate *cs; 391 { 392 int rr0; 393 394 /* Wait for end of break to avoid PROM abort. */ 395 /* XXX - Limit the wait? */ 396 do { 397 rr0 = *cs->cs_reg_csr; 398 ZS_DELAY(); 399 } while (rr0 & ZSRR0_BREAK); 400 #ifdef DDB 401 console_debugger(); 402 #endif 403 } 404 405 /* 406 * Polled input char. 407 */ 408 int 409 zs_getc(arg) 410 void *arg; 411 { 412 register struct zs_chanstate *cs = arg; 413 register int s, c, rr0, stat; 414 415 s = splhigh(); 416 top: 417 /* Wait for a character to arrive. */ 418 do { 419 rr0 = *cs->cs_reg_csr; 420 ZS_DELAY(); 421 } while ((rr0 & ZSRR0_RX_READY) == 0); 422 423 /* Read error register. */ 424 stat = zs_read_reg(cs, 1) & (ZSRR1_FE | ZSRR1_DO | ZSRR1_PE); 425 if (stat) { 426 zs_write_csr(cs, ZSM_RESET_ERR); 427 goto top; 428 } 429 430 /* Read character. */ 431 c = *cs->cs_reg_data; 432 ZS_DELAY(); 433 splx(s); 434 435 return (c); 436 } 437 438 /* 439 * Polled output char. 440 */ 441 void 442 zs_putc(arg, c) 443 void *arg; 444 int c; 445 { 446 register struct zs_chanstate *cs = arg; 447 register int s, rr0; 448 449 s = splhigh(); 450 /* Wait for transmitter to become ready. */ 451 do { 452 rr0 = *cs->cs_reg_csr; 453 ZS_DELAY(); 454 } while ((rr0 & ZSRR0_TX_READY) == 0); 455 456 *cs->cs_reg_data = c; 457 ZS_DELAY(); 458 splx(s); 459 } 460 461 int zscngetc(dev) 462 dev_t dev; 463 { 464 register struct zs_chanstate *cs = &zs_conschan_store; 465 register int c; 466 467 c = zs_getc(cs); 468 return (c); 469 } 470 471 void zscnputc(dev, c) 472 dev_t dev; 473 int c; 474 { 475 register struct zs_chanstate *cs = &zs_conschan_store; 476 477 zs_putc(cs, c); 478 } 479 480 /* 481 * Common parts of console init. 482 */ 483 void 484 zs_cninit(base) 485 void *base; 486 { 487 struct zs_chanstate *cs; 488 /* 489 * Pointer to channel state. Later, the console channel 490 * state is copied into the softc, and the console channel 491 * pointer adjusted to point to the new copy. 492 */ 493 cs = &zs_conschan_store; 494 zs_hwflags[0][0] = ZS_HWFLAG_CONSOLE; 495 496 /* Setup temporary chanstate. */ 497 cs->cs_reg_csr = (char *)base + 7; 498 cs->cs_reg_data = (char *)base + 15; 499 500 /* Initialize the pending registers. */ 501 bcopy(zs_init_reg, cs->cs_preg, 16); 502 cs->cs_preg[5] |= (ZSWR5_DTR | ZSWR5_RTS); 503 504 /* XXX: Preserve BAUD rate from boot loader. */ 505 /* XXX: Also, why reset the chip here? -gwr */ 506 /* cs->cs_defspeed = zs_get_speed(cs); */ 507 cs->cs_defspeed = 9600; /* XXX */ 508 509 /* Clear the master interrupt enable. */ 510 zs_write_reg(cs, 9, 0); 511 512 /* Reset the whole SCC chip. */ 513 zs_write_reg(cs, 9, ZSWR9_HARD_RESET); 514 515 /* Copy "pending" to "current" and H/W. */ 516 zs_loadchannelregs(cs); 517 518 /* Point the console at the SCC. */ 519 cn_tab = &zscons; 520 } 521