1 1.30 tsutsui /* $NetBSD: zs_hb.c,v 1.30 2023/10/25 12:59:09 tsutsui Exp $ */ 2 1.1 tsubai 3 1.1 tsubai /*- 4 1.1 tsubai * Copyright (c) 1996 The NetBSD Foundation, Inc. 5 1.1 tsubai * All rights reserved. 6 1.1 tsubai * 7 1.1 tsubai * This code is derived from software contributed to The NetBSD Foundation 8 1.1 tsubai * by Gordon W. Ross. 9 1.1 tsubai * 10 1.1 tsubai * Redistribution and use in source and binary forms, with or without 11 1.1 tsubai * modification, are permitted provided that the following conditions 12 1.1 tsubai * are met: 13 1.1 tsubai * 1. Redistributions of source code must retain the above copyright 14 1.1 tsubai * notice, this list of conditions and the following disclaimer. 15 1.1 tsubai * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 tsubai * notice, this list of conditions and the following disclaimer in the 17 1.1 tsubai * documentation and/or other materials provided with the distribution. 18 1.1 tsubai * 19 1.1 tsubai * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 1.1 tsubai * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 1.1 tsubai * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 1.1 tsubai * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 1.1 tsubai * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 1.1 tsubai * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 1.1 tsubai * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.1 tsubai * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 1.1 tsubai * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.1 tsubai * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 1.1 tsubai * POSSIBILITY OF SUCH DAMAGE. 30 1.1 tsubai */ 31 1.1 tsubai 32 1.1 tsubai /* 33 1.1 tsubai * Zilog Z8530 Dual UART driver (machine-dependent part) 34 1.1 tsubai * 35 1.1 tsubai * Runs two serial lines per chip using slave drivers. 36 1.1 tsubai * Plain tty/async lines use the zs_async slave. 37 1.1 tsubai * Sun keyboard/mouse uses the zs_kbd/zs_ms slaves. 38 1.1 tsubai */ 39 1.17 lukem 40 1.17 lukem #include <sys/cdefs.h> 41 1.30 tsutsui __KERNEL_RCSID(0, "$NetBSD: zs_hb.c,v 1.30 2023/10/25 12:59:09 tsutsui Exp $"); 42 1.1 tsubai 43 1.1 tsubai #include <sys/param.h> 44 1.1 tsubai #include <sys/systm.h> 45 1.1 tsubai #include <sys/device.h> 46 1.1 tsubai #include <sys/tty.h> 47 1.5 gehenna #include <sys/conf.h> 48 1.23 ad #include <sys/cpu.h> 49 1.23 ad #include <sys/intr.h> 50 1.1 tsubai 51 1.27 christos #include <mips/locore.h> 52 1.27 christos 53 1.1 tsubai #include <machine/adrsmap.h> 54 1.1 tsubai #include <machine/z8530var.h> 55 1.1 tsubai 56 1.1 tsubai #include <dev/cons.h> 57 1.1 tsubai #include <dev/ic/z8530reg.h> 58 1.1 tsubai 59 1.12 tsutsui #include <newsmips/dev/hbvar.h> 60 1.12 tsutsui 61 1.1 tsubai #include "zsc.h" /* NZSC */ 62 1.1 tsubai #define NZS NZSC 63 1.1 tsubai 64 1.1 tsubai /* Make life easier for the initialized arrays here. */ 65 1.1 tsubai #if NZS < 2 66 1.1 tsubai #undef NZS 67 1.1 tsubai #define NZS 2 68 1.1 tsubai #endif 69 1.1 tsubai 70 1.3 tsubai #define ZSCFLAG_EX 0x01 /* expansion board */ 71 1.3 tsubai 72 1.1 tsubai /* 73 1.1 tsubai * The news3400 provides a 4.9152 MHz clock to the ZS chips. 74 1.1 tsubai */ 75 1.3 tsubai #define PCLK (9600 * 512) /* PCLK pin input clock rate */ 76 1.3 tsubai #define PCLK_EX (9600 * 384) 77 1.1 tsubai 78 1.1 tsubai /* 79 1.1 tsubai * Define interrupt levels. 80 1.1 tsubai */ 81 1.1 tsubai #define ZSHARD_PRI 64 82 1.1 tsubai 83 1.1 tsubai #define ZS_DELAY() {(void)*(volatile char *)INTEN1; delay(2);} 84 1.1 tsubai 85 1.1 tsubai /* The layout of this is hardware-dependent (padding, order). */ 86 1.1 tsubai struct zschan { 87 1.24 tsutsui volatile uint8_t zc_csr; /* ctrl,status, and indirect access */ 88 1.24 tsutsui volatile uint8_t zc_data; /* data */ 89 1.1 tsubai }; 90 1.1 tsubai struct zsdevice { 91 1.1 tsubai /* Yes, they are backwards. */ 92 1.1 tsubai struct zschan zs_chan_b; 93 1.1 tsubai struct zschan zs_chan_a; 94 1.1 tsubai }; 95 1.1 tsubai 96 1.1 tsubai extern int zs_def_cflag; 97 1.1 tsubai 98 1.1 tsubai static struct zsdevice *zsaddr[NZS]; 99 1.1 tsubai 100 1.1 tsubai /* Flags from cninit() */ 101 1.1 tsubai static int zs_hwflags[NZS][2]; 102 1.1 tsubai 103 1.1 tsubai /* Default speed for all channels */ 104 1.1 tsubai static int zs_defspeed = 9600; 105 1.1 tsubai 106 1.24 tsutsui static uint8_t zs_init_reg[16] = { 107 1.1 tsubai 0, /* 0: CMD (reset, etc.) */ 108 1.1 tsubai 0, /* 1: No interrupts yet. */ 109 1.1 tsubai ZSHARD_PRI, /* IVECT */ 110 1.1 tsubai ZSWR3_RX_8 | ZSWR3_RX_ENABLE, 111 1.1 tsubai ZSWR4_CLK_X16 | ZSWR4_ONESB | ZSWR4_EVENP, 112 1.1 tsubai ZSWR5_TX_8 | ZSWR5_TX_ENABLE, 113 1.1 tsubai 0, /* 6: TXSYNC/SYNCLO */ 114 1.1 tsubai 0, /* 7: RXSYNC/SYNCHI */ 115 1.1 tsubai 0, /* 8: alias for data port */ 116 1.1 tsubai ZSWR9_MASTER_IE, 117 1.1 tsubai 0, /*10: Misc. TX/RX control bits */ 118 1.1 tsubai ZSWR11_TXCLK_BAUD | ZSWR11_RXCLK_BAUD, 119 1.3 tsubai ((PCLK/32)/9600)-2, /*12: BAUDLO (default=9600) */ 120 1.1 tsubai 0, /*13: BAUDHI (default=9600) */ 121 1.1 tsubai ZSWR14_BAUD_ENA | ZSWR14_BAUD_FROM_PCLK, 122 1.1 tsubai ZSWR15_BREAK_IE, 123 1.1 tsubai }; 124 1.1 tsubai 125 1.18 tsutsui static struct zschan * zs_get_chan_addr(int, int); 126 1.18 tsutsui static void zs_hb_delay(void); 127 1.18 tsutsui static int zshard_hb(void *); 128 1.18 tsutsui static int zs_getc(void *); 129 1.18 tsutsui static void zs_putc(void *, int); 130 1.1 tsubai 131 1.2 tsubai struct zschan * 132 1.18 tsutsui zs_get_chan_addr(int zs_unit, int channel) 133 1.1 tsubai { 134 1.1 tsubai struct zsdevice *addr; 135 1.1 tsubai struct zschan *zc; 136 1.1 tsubai 137 1.1 tsubai if (zs_unit >= NZS) 138 1.1 tsubai return NULL; 139 1.1 tsubai addr = zsaddr[zs_unit]; 140 1.1 tsubai if (addr == NULL) 141 1.1 tsubai return NULL; 142 1.1 tsubai if (channel == 0) { 143 1.1 tsubai zc = &addr->zs_chan_a; 144 1.1 tsubai } else { 145 1.1 tsubai zc = &addr->zs_chan_b; 146 1.1 tsubai } 147 1.18 tsutsui return zc; 148 1.1 tsubai } 149 1.1 tsubai 150 1.11 tsutsui static void 151 1.18 tsutsui zs_hb_delay(void) 152 1.1 tsubai { 153 1.11 tsutsui 154 1.1 tsubai ZS_DELAY(); 155 1.1 tsubai } 156 1.1 tsubai 157 1.1 tsubai /**************************************************************** 158 1.1 tsubai * Autoconfig 159 1.1 tsubai ****************************************************************/ 160 1.1 tsubai 161 1.1 tsubai /* Definition of the driver for autoconfig. */ 162 1.24 tsutsui int zs_hb_match(device_t, cfdata_t, void *); 163 1.24 tsutsui void zs_hb_attach(device_t, device_t, void *); 164 1.1 tsubai 165 1.24 tsutsui CFATTACH_DECL_NEW(zsc_hb, sizeof(struct zsc_softc), 166 1.7 thorpej zs_hb_match, zs_hb_attach, NULL, NULL); 167 1.1 tsubai 168 1.1 tsubai /* 169 1.1 tsubai * Is the zs chip present? 170 1.1 tsubai */ 171 1.1 tsubai int 172 1.24 tsutsui zs_hb_match(device_t parent, cfdata_t cf, void *aux) 173 1.1 tsubai { 174 1.12 tsutsui struct hb_attach_args *ha = aux; 175 1.1 tsubai 176 1.12 tsutsui if (strcmp(ha->ha_name, "zsc")) 177 1.1 tsubai return 0; 178 1.1 tsubai 179 1.1 tsubai /* This returns -1 on a fault (bus error). */ 180 1.12 tsutsui if (hb_badaddr((char *)ha->ha_addr, 1)) 181 1.1 tsubai return 0; 182 1.1 tsubai 183 1.1 tsubai return 1; 184 1.1 tsubai } 185 1.1 tsubai 186 1.1 tsubai /* 187 1.1 tsubai * Attach a found zs. 188 1.1 tsubai * 189 1.1 tsubai * Match slave number to zs unit number, so that misconfiguration will 190 1.1 tsubai * not set up the keyboard as ttya, etc. 191 1.1 tsubai */ 192 1.1 tsubai void 193 1.24 tsutsui zs_hb_attach(device_t parent, device_t self, void *aux) 194 1.1 tsubai { 195 1.24 tsutsui struct zsc_softc *zsc = device_private(self); 196 1.12 tsutsui struct hb_attach_args *ha = aux; 197 1.1 tsubai struct zsc_attach_args zsc_args; 198 1.1 tsubai volatile struct zschan *zc; 199 1.1 tsubai struct zs_chanstate *cs; 200 1.1 tsubai int s, zs_unit, channel, intlevel; 201 1.1 tsubai 202 1.24 tsutsui zsc->zsc_dev = self; 203 1.24 tsutsui zs_unit = device_unit(self); 204 1.12 tsutsui intlevel = ha->ha_level; 205 1.12 tsutsui zsaddr[zs_unit] = (void *)ha->ha_addr; 206 1.1 tsubai 207 1.1 tsubai if (intlevel == -1) { 208 1.1 tsubai #if 0 209 1.24 tsutsui aprint_error(": interrupt level not configured\n"); 210 1.1 tsubai return; 211 1.1 tsubai #else 212 1.24 tsutsui aprint_error(": interrupt level not configured; using"); 213 1.1 tsubai intlevel = 1; 214 1.1 tsubai #endif 215 1.1 tsubai } 216 1.1 tsubai 217 1.30 tsutsui aprint_normal(" level %d\n", intlevel); 218 1.1 tsubai 219 1.1 tsubai zs_delay = zs_hb_delay; 220 1.1 tsubai 221 1.1 tsubai /* 222 1.1 tsubai * Initialize software state for each channel. 223 1.1 tsubai */ 224 1.1 tsubai for (channel = 0; channel < 2; channel++) { 225 1.1 tsubai zsc_args.channel = channel; 226 1.1 tsubai zsc_args.hwflags = zs_hwflags[zs_unit][channel]; 227 1.1 tsubai cs = &zsc->zsc_cs_store[channel]; 228 1.1 tsubai zsc->zsc_cs[channel] = cs; 229 1.1 tsubai 230 1.22 ad zs_lock_init(cs); 231 1.1 tsubai cs->cs_channel = channel; 232 1.1 tsubai cs->cs_private = NULL; 233 1.1 tsubai cs->cs_ops = &zsops_null; 234 1.24 tsutsui if ((device_cfdata(self)->cf_flags & ZSCFLAG_EX) == 0) 235 1.3 tsubai cs->cs_brg_clk = PCLK / 16; 236 1.1 tsubai else 237 1.3 tsubai cs->cs_brg_clk = PCLK_EX / 16; 238 1.1 tsubai 239 1.1 tsubai zc = zs_get_chan_addr(zs_unit, channel); 240 1.1 tsubai cs->cs_reg_csr = &zc->zc_csr; 241 1.1 tsubai cs->cs_reg_data = &zc->zc_data; 242 1.1 tsubai 243 1.18 tsutsui memcpy(cs->cs_creg, zs_init_reg, 16); 244 1.18 tsutsui memcpy(cs->cs_preg, zs_init_reg, 16); 245 1.1 tsubai 246 1.1 tsubai /* XXX: Get these from the EEPROM instead? */ 247 1.1 tsubai /* XXX: See the mvme167 code. Better. */ 248 1.1 tsubai if (zsc_args.hwflags & ZS_HWFLAG_CONSOLE) 249 1.1 tsubai cs->cs_defspeed = zs_get_speed(cs); 250 1.1 tsubai else 251 1.1 tsubai cs->cs_defspeed = zs_defspeed; 252 1.1 tsubai cs->cs_defcflag = zs_def_cflag; 253 1.1 tsubai 254 1.1 tsubai /* Make these correspond to cs_defcflag (-crtscts) */ 255 1.1 tsubai cs->cs_rr0_dcd = ZSRR0_DCD; 256 1.1 tsubai cs->cs_rr0_cts = 0; 257 1.1 tsubai cs->cs_wr5_dtr = ZSWR5_DTR | ZSWR5_RTS; 258 1.1 tsubai cs->cs_wr5_rts = 0; 259 1.1 tsubai 260 1.1 tsubai /* 261 1.1 tsubai * Clear the master interrupt enable. 262 1.1 tsubai * The INTENA is common to both channels, 263 1.1 tsubai * so just do it on the A channel. 264 1.1 tsubai */ 265 1.1 tsubai if (channel == 0) { 266 1.1 tsubai zs_write_reg(cs, 9, 0); 267 1.1 tsubai } 268 1.1 tsubai 269 1.1 tsubai /* 270 1.1 tsubai * Look for a child driver for this channel. 271 1.1 tsubai * The child attach will setup the hardware. 272 1.1 tsubai */ 273 1.28 thorpej if (!config_found(self, (void *)&zsc_args, zs_print, 274 1.29 thorpej CFARGS_NONE)) { 275 1.1 tsubai /* No sub-driver. Just reset it. */ 276 1.24 tsutsui uint8_t reset = (channel == 0) ? 277 1.24 tsutsui ZSWR9_A_RESET : ZSWR9_B_RESET; 278 1.1 tsubai s = splhigh(); 279 1.1 tsubai zs_write_reg(cs, 9, reset); 280 1.1 tsubai splx(s); 281 1.1 tsubai } 282 1.1 tsubai } 283 1.1 tsubai 284 1.1 tsubai /* 285 1.1 tsubai * Now safe to install interrupt handlers. Note the arguments 286 1.1 tsubai * to the interrupt handlers aren't used. Note, we only do this 287 1.1 tsubai * once since both SCCs interrupt at the same level and vector. 288 1.1 tsubai */ 289 1.26 tsutsui zsc->zsc_si = softint_establish(SOFTINT_SERIAL, 290 1.26 tsutsui (void (*)(void *))zsc_intr_soft, zsc); 291 1.26 tsutsui hb_intr_establish(intlevel, INTST1_SCC, IPL_SERIAL, zshard_hb, zsc); 292 1.1 tsubai /* XXX; evcnt_attach() ? */ 293 1.1 tsubai 294 1.1 tsubai /* 295 1.1 tsubai * Set the master interrupt enable and interrupt vector. 296 1.1 tsubai * (common to both channels, do it on A) 297 1.1 tsubai */ 298 1.1 tsubai cs = zsc->zsc_cs[0]; 299 1.1 tsubai s = splhigh(); 300 1.1 tsubai /* interrupt vector */ 301 1.1 tsubai zs_write_reg(cs, 2, zs_init_reg[2]); 302 1.1 tsubai /* master interrupt control (enable) */ 303 1.1 tsubai zs_write_reg(cs, 9, zs_init_reg[9]); 304 1.1 tsubai splx(s); 305 1.1 tsubai } 306 1.1 tsubai 307 1.1 tsubai static int 308 1.18 tsutsui zshard_hb(void *arg) 309 1.1 tsubai { 310 1.14 tsutsui int rv; 311 1.14 tsutsui 312 1.1 tsubai (void) *(volatile u_char *)SCCVECT; 313 1.14 tsutsui rv = zshard(arg); 314 1.14 tsutsui 315 1.14 tsutsui /* XXX news3400 sometimes losts zs interrupt */ 316 1.14 tsutsui if (rv) 317 1.14 tsutsui zshard(arg); 318 1.1 tsubai 319 1.14 tsutsui return rv; 320 1.1 tsubai } 321 1.1 tsubai 322 1.1 tsubai /* 323 1.1 tsubai * Polled input char. 324 1.1 tsubai */ 325 1.1 tsubai int 326 1.18 tsutsui zs_getc(void *arg) 327 1.1 tsubai { 328 1.11 tsutsui volatile struct zschan *zc = arg; 329 1.11 tsutsui int s, c, rr0; 330 1.1 tsubai 331 1.1 tsubai s = splhigh(); 332 1.1 tsubai /* Wait for a character to arrive. */ 333 1.1 tsubai do { 334 1.1 tsubai rr0 = zc->zc_csr; 335 1.1 tsubai ZS_DELAY(); 336 1.1 tsubai } while ((rr0 & ZSRR0_RX_READY) == 0); 337 1.1 tsubai 338 1.1 tsubai c = zc->zc_data; 339 1.1 tsubai ZS_DELAY(); 340 1.1 tsubai splx(s); 341 1.1 tsubai 342 1.1 tsubai /* 343 1.1 tsubai * This is used by the kd driver to read scan codes, 344 1.1 tsubai * so don't translate '\r' ==> '\n' here... 345 1.1 tsubai */ 346 1.18 tsutsui return c; 347 1.1 tsubai } 348 1.1 tsubai 349 1.1 tsubai /* 350 1.1 tsubai * Polled output char. 351 1.1 tsubai */ 352 1.1 tsubai void 353 1.18 tsutsui zs_putc(void *arg, int c) 354 1.1 tsubai { 355 1.11 tsutsui volatile struct zschan *zc = arg; 356 1.11 tsutsui int s, rr0; 357 1.1 tsubai 358 1.1 tsubai s = splhigh(); 359 1.1 tsubai /* Wait for transmitter to become ready. */ 360 1.1 tsubai do { 361 1.1 tsubai rr0 = zc->zc_csr; 362 1.1 tsubai ZS_DELAY(); 363 1.1 tsubai } while ((rr0 & ZSRR0_TX_READY) == 0); 364 1.1 tsubai 365 1.1 tsubai zc->zc_data = c; 366 1.1 tsubai ZS_DELAY(); 367 1.1 tsubai splx(s); 368 1.1 tsubai } 369 1.1 tsubai 370 1.1 tsubai /*****************************************************************/ 371 1.1 tsubai 372 1.18 tsutsui static void zscnprobe(struct consdev *); 373 1.18 tsutsui static void zscninit(struct consdev *); 374 1.18 tsutsui static int zscngetc(dev_t); 375 1.18 tsutsui static void zscnputc(dev_t, int); 376 1.1 tsubai 377 1.1 tsubai struct consdev consdev_zs = { 378 1.1 tsubai zscnprobe, 379 1.1 tsubai zscninit, 380 1.1 tsubai zscngetc, 381 1.1 tsubai zscnputc, 382 1.11 tsutsui nullcnpollc, 383 1.11 tsutsui NULL, 384 1.11 tsutsui NULL, 385 1.4 thorpej NULL, 386 1.11 tsutsui NODEV, 387 1.11 tsutsui CN_DEAD 388 1.1 tsubai }; 389 1.1 tsubai 390 1.11 tsutsui static void 391 1.18 tsutsui zscnprobe(struct consdev *cn) 392 1.1 tsubai { 393 1.1 tsubai } 394 1.1 tsubai 395 1.11 tsutsui static void 396 1.18 tsutsui zscninit(struct consdev *cn) 397 1.1 tsubai { 398 1.5 gehenna extern const struct cdevsw zstty_cdevsw; 399 1.5 gehenna 400 1.5 gehenna cn->cn_dev = makedev(cdevsw_lookup_major(&zstty_cdevsw), 0); 401 1.1 tsubai cn->cn_pri = CN_REMOTE; 402 1.1 tsubai zs_hwflags[0][0] = ZS_HWFLAG_CONSOLE; 403 1.1 tsubai } 404 1.1 tsubai 405 1.11 tsutsui static int 406 1.18 tsutsui zscngetc(dev_t dev) 407 1.1 tsubai { 408 1.11 tsutsui 409 1.1 tsubai return zs_getc((void *)SCCPORT0A); 410 1.1 tsubai } 411 1.1 tsubai 412 1.11 tsutsui static void 413 1.18 tsutsui zscnputc(dev_t dev, int c) 414 1.1 tsubai { 415 1.11 tsutsui 416 1.1 tsubai zs_putc((void *)SCCPORT0A, c); 417 1.1 tsubai } 418