1 1.14 thorpej /* $NetBSD: zs_sbdio.c,v 1.14 2021/08/07 16:18:53 thorpej Exp $ */ 2 1.1 tsutsui 3 1.1 tsutsui /*- 4 1.1 tsutsui * Copyright (c) 1996, 2005 The NetBSD Foundation, Inc. 5 1.1 tsutsui * All rights reserved. 6 1.1 tsutsui * 7 1.1 tsutsui * This code is derived from software contributed to The NetBSD Foundation 8 1.1 tsutsui * by Gordon W. Ross. 9 1.1 tsutsui * 10 1.1 tsutsui * Redistribution and use in source and binary forms, with or without 11 1.1 tsutsui * modification, are permitted provided that the following conditions 12 1.1 tsutsui * are met: 13 1.1 tsutsui * 1. Redistributions of source code must retain the above copyright 14 1.1 tsutsui * notice, this list of conditions and the following disclaimer. 15 1.1 tsutsui * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 tsutsui * notice, this list of conditions and the following disclaimer in the 17 1.1 tsutsui * documentation and/or other materials provided with the distribution. 18 1.1 tsutsui * 19 1.1 tsutsui * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 1.1 tsutsui * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 1.1 tsutsui * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 1.1 tsutsui * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 1.1 tsutsui * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 1.1 tsutsui * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 1.1 tsutsui * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.1 tsutsui * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 1.1 tsutsui * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.1 tsutsui * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 1.1 tsutsui * POSSIBILITY OF SUCH DAMAGE. 30 1.1 tsutsui */ 31 1.1 tsutsui 32 1.1 tsutsui /* 33 1.1 tsutsui * Zilog Z8530 Dual UART driver (machine-dependent part) 34 1.1 tsutsui * 35 1.1 tsutsui * Runs two serial lines per chip using slave drivers. 36 1.1 tsutsui * Plain tty/async lines use the zs_async slave. 37 1.1 tsutsui */ 38 1.1 tsutsui 39 1.1 tsutsui #include <sys/cdefs.h> 40 1.14 thorpej __KERNEL_RCSID(0, "$NetBSD: zs_sbdio.c,v 1.14 2021/08/07 16:18:53 thorpej Exp $"); 41 1.1 tsutsui 42 1.1 tsutsui #include <sys/param.h> 43 1.1 tsutsui #include <sys/systm.h> 44 1.1 tsutsui #include <sys/device.h> 45 1.1 tsutsui #include <sys/tty.h> 46 1.1 tsutsui #include <sys/conf.h> 47 1.7 ad #include <sys/intr.h> 48 1.1 tsutsui 49 1.1 tsutsui #include <dev/cons.h> 50 1.1 tsutsui #include <dev/ic/z8530reg.h> 51 1.1 tsutsui 52 1.12 matt #include <mips/locore.h> 53 1.12 matt 54 1.1 tsutsui #include <machine/sbdiovar.h> 55 1.1 tsutsui #include <machine/z8530var.h> 56 1.1 tsutsui 57 1.1 tsutsui #define ZS_DEFSPEED 9600 58 1.1 tsutsui #define PCLK (9600 * 512) /* 4.915200MHz */ 59 1.1 tsutsui 60 1.1 tsutsui /* The layout of this is hardware-dependent (padding, order). */ 61 1.1 tsutsui struct zschan { 62 1.1 tsutsui volatile uint8_t zc_csr; /* ctrl, status, and indirect access */ 63 1.1 tsutsui uint8_t padding1[3]; 64 1.1 tsutsui volatile uint8_t zc_data; /* data */ 65 1.1 tsutsui uint8_t padding2[3]; 66 1.1 tsutsui } __attribute__((__packed__)); 67 1.1 tsutsui 68 1.1 tsutsui struct zsdevice { 69 1.1 tsutsui /* Yes, they are backwards. */ 70 1.1 tsutsui struct zschan zs_chan_b; 71 1.1 tsutsui struct zschan zs_chan_a; 72 1.1 tsutsui } __attribute__((__packed__)); 73 1.1 tsutsui 74 1.1 tsutsui static uint8_t zs_init_reg[16] = { 75 1.1 tsutsui 0, /* 0: CMD (reset, etc.) */ 76 1.1 tsutsui 0, /* 1: No interrupts yet. */ 77 1.1 tsutsui 0, /* 2: IVECT EWS-UX don't set this. */ 78 1.1 tsutsui ZSWR3_RX_8 | ZSWR3_RX_ENABLE, 79 1.1 tsutsui ZSWR4_CLK_X16 | ZSWR4_ONESB | ZSWR4_EVENP, 80 1.1 tsutsui ZSWR5_TX_8 | ZSWR5_TX_ENABLE, 81 1.1 tsutsui 0, /* 6: TXSYNC/SYNCLO */ 82 1.1 tsutsui 0, /* 7: RXSYNC/SYNCHI */ 83 1.1 tsutsui 0, /* 8: alias for data port */ 84 1.1 tsutsui ZSWR9_MASTER_IE, 85 1.1 tsutsui 0, /* 10: Misc. TX/RX control bits */ 86 1.1 tsutsui ZSWR11_TXCLK_BAUD | ZSWR11_RXCLK_BAUD, 87 1.1 tsutsui BPS_TO_TCONST((PCLK/16), ZS_DEFSPEED), /* 12: BAUDLO (default=9600) */ 88 1.1 tsutsui 0, /*13: BAUDHI (default=9600) */ 89 1.1 tsutsui ZSWR14_BAUD_ENA | ZSWR14_BAUD_FROM_PCLK, 90 1.1 tsutsui ZSWR15_BREAK_IE, 91 1.1 tsutsui }; 92 1.1 tsutsui 93 1.8 tsutsui static int zs_sbdio_match(device_t, cfdata_t, void *); 94 1.8 tsutsui static void zs_sbdio_attach(device_t, device_t, void *); 95 1.1 tsutsui 96 1.9 tsutsui CFATTACH_DECL_NEW(zsc_sbdio, sizeof(struct zsc_softc), 97 1.1 tsutsui zs_sbdio_match, zs_sbdio_attach, NULL, NULL); 98 1.1 tsutsui 99 1.1 tsutsui int 100 1.8 tsutsui zs_sbdio_match(device_t parent, cfdata_t cf, void *aux) 101 1.1 tsutsui { 102 1.1 tsutsui struct sbdio_attach_args *sa = aux; 103 1.1 tsutsui 104 1.1 tsutsui return strcmp(sa->sa_name, "zsc") ? 0 : 1; 105 1.1 tsutsui } 106 1.1 tsutsui 107 1.1 tsutsui void 108 1.8 tsutsui zs_sbdio_attach(device_t parent, device_t self, void *aux) 109 1.1 tsutsui { 110 1.9 tsutsui struct zsc_softc *zsc = device_private(self); 111 1.1 tsutsui struct sbdio_attach_args *sa = aux; 112 1.1 tsutsui struct zsc_attach_args zsc_args; 113 1.1 tsutsui struct zschan *zc; 114 1.1 tsutsui struct zs_chanstate *cs; 115 1.1 tsutsui struct zsdevice *zs_addr; 116 1.11 christos int s, channel; 117 1.1 tsutsui 118 1.9 tsutsui zsc->zsc_dev = self; 119 1.8 tsutsui aprint_normal("\n"); 120 1.1 tsutsui 121 1.1 tsutsui zs_addr = (void *)MIPS_PHYS_TO_KSEG1(sa->sa_addr1); 122 1.1 tsutsui zsc->zsc_flags = sa->sa_flags; 123 1.1 tsutsui 124 1.1 tsutsui /* 125 1.1 tsutsui * Initialize software state for each channel. 126 1.1 tsutsui */ 127 1.1 tsutsui for (channel = 0; channel < 2; channel++) { 128 1.1 tsutsui zsc_args.channel = channel; 129 1.1 tsutsui zsc_args.hwflags = 0; 130 1.1 tsutsui cs = &zsc->zsc_cs_store[channel]; 131 1.1 tsutsui zsc->zsc_cs[channel] = cs; 132 1.1 tsutsui 133 1.1 tsutsui cs->cs_channel = channel; 134 1.1 tsutsui cs->cs_private = NULL; 135 1.1 tsutsui cs->cs_ops = &zsops_null; 136 1.1 tsutsui 137 1.1 tsutsui if (channel == 0) 138 1.1 tsutsui zc = &zs_addr->zs_chan_a; 139 1.1 tsutsui else 140 1.1 tsutsui zc = &zs_addr->zs_chan_b; 141 1.1 tsutsui 142 1.1 tsutsui if (zc == zs_consaddr) { 143 1.1 tsutsui memcpy(cs, zs_conscs, sizeof(struct zs_chanstate)); 144 1.1 tsutsui zs_conscs = cs; 145 1.1 tsutsui zsc_args.hwflags = ZS_HWFLAG_CONSOLE; 146 1.1 tsutsui } else { 147 1.1 tsutsui cs->cs_reg_csr = &zc->zc_csr; 148 1.1 tsutsui cs->cs_reg_data = &zc->zc_data; 149 1.1 tsutsui memcpy(cs->cs_creg, zs_init_reg, 16); 150 1.1 tsutsui memcpy(cs->cs_preg, zs_init_reg, 16); 151 1.1 tsutsui cs->cs_defspeed = ZS_DEFSPEED; 152 1.1 tsutsui zsc_args.hwflags = 0; 153 1.1 tsutsui } 154 1.1 tsutsui 155 1.6 ad zs_lock_init(cs); 156 1.1 tsutsui cs->cs_brg_clk = PCLK / 16; 157 1.1 tsutsui cs->cs_defcflag = zs_def_cflag; 158 1.1 tsutsui 159 1.1 tsutsui /* Make these correspond to cs_defcflag (-crtscts) */ 160 1.1 tsutsui cs->cs_rr0_dcd = ZSRR0_DCD; 161 1.1 tsutsui cs->cs_rr0_cts = 0; 162 1.1 tsutsui cs->cs_wr5_dtr = ZSWR5_DTR | ZSWR5_RTS; 163 1.1 tsutsui cs->cs_wr5_rts = 0; 164 1.1 tsutsui 165 1.1 tsutsui /* 166 1.1 tsutsui * Clear the master interrupt enable. 167 1.1 tsutsui * The INTENA is common to both channels, 168 1.1 tsutsui * so just do it on the A channel. 169 1.1 tsutsui */ 170 1.1 tsutsui if (channel == 0) { 171 1.1 tsutsui zs_write_reg(cs, 9, 0); 172 1.1 tsutsui } 173 1.1 tsutsui 174 1.1 tsutsui /* 175 1.1 tsutsui * Look for a child driver for this channel. 176 1.1 tsutsui * The child attach will setup the hardware. 177 1.1 tsutsui */ 178 1.13 thorpej if (!config_found(self, (void *)&zsc_args, zs_print, 179 1.14 thorpej CFARGS_NONE)) { 180 1.1 tsutsui /* No sub-driver. Just reset it. */ 181 1.1 tsutsui uint8_t reset = (channel == 0) ? 182 1.1 tsutsui ZSWR9_A_RESET : ZSWR9_B_RESET; 183 1.1 tsutsui s = splhigh(); 184 1.1 tsutsui zs_write_reg(cs, 9, reset); 185 1.1 tsutsui splx(s); 186 1.1 tsutsui } 187 1.1 tsutsui } 188 1.1 tsutsui 189 1.7 ad zsc->zsc_si = softint_establish(SOFTINT_SERIAL, 190 1.3 tsutsui (void (*)(void *))zsc_intr_soft, zsc); 191 1.3 tsutsui intr_establish(sa->sa_irq, zshard, zsc); 192 1.1 tsutsui 193 1.1 tsutsui /* 194 1.1 tsutsui * Set the master interrupt enable and interrupt vector. 195 1.1 tsutsui * (common to both channels, do it on A) 196 1.1 tsutsui */ 197 1.1 tsutsui cs = zsc->zsc_cs[0]; 198 1.1 tsutsui s = splhigh(); 199 1.1 tsutsui /* interrupt vector */ 200 1.1 tsutsui zs_write_reg(cs, 2, zs_init_reg[2]); 201 1.1 tsutsui /* master interrupt control (enable) */ 202 1.1 tsutsui zs_write_reg(cs, 9, zs_init_reg[9]); 203 1.1 tsutsui splx(s); 204 1.1 tsutsui } 205 1.1 tsutsui 206 1.1 tsutsui /* 207 1.1 tsutsui * console stuff 208 1.1 tsutsui */ 209 1.1 tsutsui 210 1.1 tsutsui static void zs_sbdio_cnprobe(struct consdev *); 211 1.1 tsutsui static void zs_sbdio_cninit(struct consdev *); 212 1.1 tsutsui 213 1.1 tsutsui struct consdev consdev_zs_sbdio = { 214 1.1 tsutsui zs_sbdio_cnprobe, 215 1.1 tsutsui zs_sbdio_cninit, 216 1.1 tsutsui zscngetc, 217 1.1 tsutsui zscnputc, 218 1.1 tsutsui nullcnpollc, 219 1.1 tsutsui NULL, 220 1.1 tsutsui NULL, 221 1.1 tsutsui NULL, 222 1.1 tsutsui NODEV, 223 1.1 tsutsui CN_DEAD 224 1.1 tsutsui }; 225 1.1 tsutsui 226 1.1 tsutsui static void 227 1.1 tsutsui zs_sbdio_cnprobe(struct consdev *cn) 228 1.1 tsutsui { 229 1.1 tsutsui 230 1.1 tsutsui /* not used */ 231 1.1 tsutsui } 232 1.1 tsutsui 233 1.1 tsutsui static void 234 1.1 tsutsui zs_sbdio_cninit(struct consdev *cn) 235 1.1 tsutsui { 236 1.1 tsutsui struct zs_chanstate *cs; 237 1.1 tsutsui struct zschan *zc; 238 1.1 tsutsui 239 1.1 tsutsui zc = zs_consaddr; 240 1.1 tsutsui cs = zs_conscs; 241 1.1 tsutsui 242 1.1 tsutsui /* Setup temporary chanstate. */ 243 1.1 tsutsui cs->cs_reg_csr = &zc->zc_csr; 244 1.1 tsutsui cs->cs_reg_data = &zc->zc_data; 245 1.1 tsutsui 246 1.1 tsutsui /* Initialize the pending registers. */ 247 1.1 tsutsui memcpy(cs->cs_preg, zs_init_reg, 16); 248 1.1 tsutsui cs->cs_preg[5] |= ZSWR5_DTR | ZSWR5_RTS; 249 1.1 tsutsui 250 1.1 tsutsui cs->cs_brg_clk = PCLK / 16; 251 1.1 tsutsui cs->cs_defspeed = ZS_DEFSPEED; 252 1.1 tsutsui zs_set_speed(cs, ZS_DEFSPEED); 253 1.1 tsutsui 254 1.1 tsutsui /* Clear the master interrupt enable. */ 255 1.1 tsutsui zs_write_reg(cs, 9, 0); 256 1.1 tsutsui 257 1.1 tsutsui /* Reset the whole SCC chip. */ 258 1.1 tsutsui zs_write_reg(cs, 9, ZSWR9_HARD_RESET); 259 1.1 tsutsui 260 1.1 tsutsui /* Copy "pending" to "current" and H/W */ 261 1.1 tsutsui zs_loadchannelregs(cs); 262 1.1 tsutsui } 263