zs.c revision 1.14 1 /* $NetBSD: zs.c,v 1.14 2003/01/01 01:55:42 thorpej 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 * Sun keyboard/mouse uses the zs_kbd/zs_ms slaves.
45 */
46
47 #include "opt_ddb.h"
48
49 #include <sys/param.h>
50 #include <sys/device.h>
51 #include <sys/tty.h>
52 #include <sys/systm.h>
53
54 #include <machine/adrsmap.h>
55 #include <machine/cpu.h>
56 #include <machine/z8530var.h>
57
58 #include <dev/ic/z8530reg.h>
59
60 #define ZS_DELAY() (*zs_delay)()
61
62 int zs_print __P((void *, const char *name));
63 int zshard __P((void *));
64 void zssoft __P((void *));
65 int zs_get_speed __P((struct zs_chanstate *));
66 void Debugger __P((void));
67 void (*zs_delay) __P((void));
68
69 extern struct cfdriver zsc_cd;
70
71 /*
72 * Some warts needed by z8530tty.c -
73 * The default parity REALLY needs to be the same as the PROM uses,
74 * or you can not see messages done with printf during boot-up...
75 */
76 int zs_def_cflag = (CREAD | CS8 | HUPCL);
77
78 int
79 zs_print(aux, name)
80 void *aux;
81 const char *name;
82 {
83 struct zsc_attach_args *args = aux;
84
85 if (name != NULL)
86 aprint_normal("%s: ", name);
87
88 if (args->channel != -1)
89 aprint_normal(" channel %d", args->channel);
90
91 return UNCONF;
92 }
93
94 static volatile int zssoftpending;
95
96 /*
97 * Our ZS chips all share a common, autovectored interrupt,
98 * so we have to look at all of them on each interrupt.
99 */
100 int
101 zshard(arg)
102 void *arg;
103 {
104 register struct zsc_softc *zsc;
105 register int unit, rval, softreq;
106
107 rval = softreq = 0;
108 for (unit = 0; unit < zsc_cd.cd_ndevs; unit++) {
109 zsc = zsc_cd.cd_devs[unit];
110 if (zsc == NULL)
111 continue;
112 rval |= zsc_intr_hard(zsc);
113 softreq |= zsc->zsc_cs[0]->cs_softreq;
114 softreq |= zsc->zsc_cs[1]->cs_softreq;
115 }
116
117 /* We are at splzs here, so no need to lock. */
118 if (softreq && (zssoftpending == 0)) {
119 zssoftpending = 1;
120 setsoftserial();
121 }
122
123 return rval;
124 }
125
126 /*
127 * Similar scheme as for zshard (look at all of them)
128 */
129 void
130 zssoft(arg)
131 void *arg;
132 {
133 register struct zsc_softc *zsc;
134 register int s, unit;
135
136 /* This is not the only ISR on this IPL. */
137 if (zssoftpending == 0)
138 return;
139
140 /*
141 * The soft intr. bit will be set by zshard only if
142 * the variable zssoftpending is zero. The order of
143 * these next two statements prevents our clearing
144 * the soft intr bit just after zshard has set it.
145 */
146 /* clearsoftnet(); */
147 zssoftpending = 0;
148
149 /* Make sure we call the tty layer at spltty. */
150 s = spltty();
151 for (unit = 0; unit < zsc_cd.cd_ndevs; unit++) {
152 zsc = zsc_cd.cd_devs[unit];
153 if (zsc == NULL)
154 continue;
155 (void)zsc_intr_soft(zsc);
156 }
157 splx(s);
158 }
159
160 /*
161 * Compute the current baud rate given a ZS channel.
162 */
163 int
164 zs_get_speed(cs)
165 struct zs_chanstate *cs;
166 {
167 int tconst;
168
169 tconst = zs_read_reg(cs, 12);
170 tconst |= zs_read_reg(cs, 13) << 8;
171 return (TCONST_TO_BPS(cs->cs_brg_clk, tconst));
172 }
173
174 /*
175 * MD functions for setting the baud rate and control modes.
176 */
177 int
178 zs_set_speed(cs, bps)
179 struct zs_chanstate *cs;
180 int bps; /* bits per second */
181 {
182 int tconst, real_bps;
183
184 if (bps == 0)
185 return (0);
186
187 #ifdef DIAGNOSTIC
188 if (cs->cs_brg_clk == 0)
189 panic("zs_set_speed");
190 #endif
191
192 tconst = BPS_TO_TCONST(cs->cs_brg_clk, bps);
193 if (tconst < 0)
194 return (EINVAL);
195
196 /* Convert back to make sure we can do it. */
197 real_bps = TCONST_TO_BPS(cs->cs_brg_clk, tconst);
198
199 /* XXX - Allow some tolerance here? */
200 if (real_bps != bps)
201 return (EINVAL);
202
203 cs->cs_preg[12] = tconst;
204 cs->cs_preg[13] = tconst >> 8;
205
206 /* Caller will stuff the pending registers. */
207 return (0);
208 }
209
210 int
211 zs_set_modes(cs, cflag)
212 struct zs_chanstate *cs;
213 int cflag; /* bits per second */
214 {
215 int s;
216
217 /*
218 * Output hardware flow control on the chip is horrendous:
219 * if carrier detect drops, the receiver is disabled, and if
220 * CTS drops, the transmitter is stoped IN MID CHARACTER!
221 * Therefore, NEVER set the HFC bit, and instead use the
222 * status interrupt to detect CTS changes.
223 */
224 s = splzs();
225 cs->cs_rr0_pps = 0;
226 if ((cflag & (CLOCAL | MDMBUF)) != 0) {
227 cs->cs_rr0_dcd = 0;
228 if ((cflag & MDMBUF) == 0)
229 cs->cs_rr0_pps = ZSRR0_DCD;
230 } else
231 cs->cs_rr0_dcd = ZSRR0_DCD;
232 if ((cflag & CRTSCTS) != 0) {
233 cs->cs_wr5_dtr = ZSWR5_DTR;
234 cs->cs_wr5_rts = ZSWR5_RTS;
235 cs->cs_rr0_cts = ZSRR0_CTS;
236 } else if ((cflag & MDMBUF) != 0) {
237 cs->cs_wr5_dtr = 0;
238 cs->cs_wr5_rts = ZSWR5_DTR;
239 cs->cs_rr0_cts = ZSRR0_DCD;
240 } else {
241 cs->cs_wr5_dtr = ZSWR5_DTR | ZSWR5_RTS;
242 cs->cs_wr5_rts = 0;
243 cs->cs_rr0_cts = 0;
244 }
245 splx(s);
246
247 /* Caller will stuff the pending registers. */
248 return (0);
249 }
250
251 /*
252 * Read or write the chip with suitable delays.
253 */
254
255 u_char
256 zs_read_reg(cs, reg)
257 struct zs_chanstate *cs;
258 u_char reg;
259 {
260 u_char val;
261
262 *cs->cs_reg_csr = reg;
263 ZS_DELAY();
264 val = *cs->cs_reg_csr;
265 ZS_DELAY();
266 return val;
267 }
268
269 void
270 zs_write_reg(cs, reg, val)
271 struct zs_chanstate *cs;
272 u_char reg, val;
273 {
274 *cs->cs_reg_csr = reg;
275 ZS_DELAY();
276 *cs->cs_reg_csr = val;
277 ZS_DELAY();
278 }
279
280 u_char zs_read_csr(cs)
281 struct zs_chanstate *cs;
282 {
283 register u_char val;
284
285 val = *cs->cs_reg_csr;
286 ZS_DELAY();
287 return val;
288 }
289
290 void zs_write_csr(cs, val)
291 struct zs_chanstate *cs;
292 u_char val;
293 {
294 *cs->cs_reg_csr = val;
295 ZS_DELAY();
296 }
297
298 u_char zs_read_data(cs)
299 struct zs_chanstate *cs;
300 {
301 register u_char val;
302
303 val = *cs->cs_reg_data;
304 ZS_DELAY();
305 return val;
306 }
307
308 void zs_write_data(cs, val)
309 struct zs_chanstate *cs;
310 u_char val;
311 {
312 *cs->cs_reg_data = val;
313 ZS_DELAY();
314 }
315
316 void
317 zs_abort(cs)
318 struct zs_chanstate *cs;
319 {
320 #ifdef DDB
321 Debugger();
322 #endif
323 }
324