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