zs_sbdio.c revision 1.13 1 1.13 thorpej /* $NetBSD: zs_sbdio.c,v 1.13 2021/04/24 23:36:37 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.13 thorpej __KERNEL_RCSID(0, "$NetBSD: zs_sbdio.c,v 1.13 2021/04/24 23:36:37 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.13 thorpej CFARG_EOL)) {
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