1/*	$NetBSD: z8530sc.c,v 1.29 2009/03/20 16:28:57 tsutsui Exp $	*/
2
3/*
4 * Copyright (c) 1992, 1993
5 *	The Regents of the University of California.  All rights reserved.
6 *
7 * This software was developed by the Computer Systems Engineering group
8 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
9 * contributed to Berkeley.
10 *
11 * All advertising materials mentioning features or use of this software
12 * must display the following acknowledgement:
13 *	This product includes software developed by the University of
14 *	California, Lawrence Berkeley Laboratory.
15 *
16 * Redistribution and use in source and binary forms, with or without
17 * modification, are permitted provided that the following conditions
18 * are met:
19 * 1. Redistributions of source code must retain the above copyright
20 *    notice, this list of conditions and the following disclaimer.
21 * 2. Redistributions in binary form must reproduce the above copyright
22 *    notice, this list of conditions and the following disclaimer in the
23 *    documentation and/or other materials provided with the distribution.
24 * 3. Neither the name of the University nor the names of its contributors
25 *    may be used to endorse or promote products derived from this software
26 *    without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 * SUCH DAMAGE.
39 *
40 *	@(#)zs.c	8.1 (Berkeley) 7/19/93
41 */
42
43/*
44 * Copyright (c) 1994 Gordon W. Ross
45 *
46 * This software was developed by the Computer Systems Engineering group
47 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
48 * contributed to Berkeley.
49 *
50 * All advertising materials mentioning features or use of this software
51 * must display the following acknowledgement:
52 *	This product includes software developed by the University of
53 *	California, Lawrence Berkeley Laboratory.
54 *
55 * Redistribution and use in source and binary forms, with or without
56 * modification, are permitted provided that the following conditions
57 * are met:
58 * 1. Redistributions of source code must retain the above copyright
59 *    notice, this list of conditions and the following disclaimer.
60 * 2. Redistributions in binary form must reproduce the above copyright
61 *    notice, this list of conditions and the following disclaimer in the
62 *    documentation and/or other materials provided with the distribution.
63 * 3. All advertising materials mentioning features or use of this software
64 *    must display the following acknowledgement:
65 *	This product includes software developed by the University of
66 *	California, Berkeley and its contributors.
67 * 4. Neither the name of the University nor the names of its contributors
68 *    may be used to endorse or promote products derived from this software
69 *    without specific prior written permission.
70 *
71 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
72 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
73 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
74 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
75 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
76 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
77 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
78 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
79 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
80 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
81 * SUCH DAMAGE.
82 *
83 *	@(#)zs.c	8.1 (Berkeley) 7/19/93
84 */
85
86/*
87 * Zilog Z8530 Dual UART driver (common part)
88 *
89 * This file contains the machine-independent parts of the
90 * driver common to tty and keyboard/mouse sub-drivers.
91 */
92
93#include <sys/cdefs.h>
94__KERNEL_RCSID(0, "$NetBSD: z8530sc.c,v 1.29 2009/03/20 16:28:57 tsutsui Exp $");
95
96#include <sys/param.h>
97#include <sys/systm.h>
98#include <sys/proc.h>
99#include <sys/device.h>
100#include <sys/conf.h>
101#include <sys/file.h>
102#include <sys/ioctl.h>
103#include <sys/tty.h>
104#include <sys/time.h>
105#include <sys/kernel.h>
106#include <sys/syslog.h>
107
108#include <dev/ic/z8530reg.h>
109#include <machine/z8530var.h>
110
111void
112zs_break(struct zs_chanstate *cs, int set)
113{
114
115	if (set) {
116		cs->cs_preg[5] |= ZSWR5_BREAK;
117		cs->cs_creg[5] |= ZSWR5_BREAK;
118	} else {
119		cs->cs_preg[5] &= ~ZSWR5_BREAK;
120		cs->cs_creg[5] &= ~ZSWR5_BREAK;
121	}
122	zs_write_reg(cs, 5, cs->cs_creg[5]);
123}
124
125
126/*
127 * drain on-chip fifo
128 */
129void
130zs_iflush(struct zs_chanstate *cs)
131{
132	uint8_t c, rr0, rr1;
133	int i;
134
135	/*
136	 * Count how many times we loop. Some systems, such as some
137	 * Apple PowerBooks, claim to have SCC's which they really don't.
138	 */
139	for (i = 0; i < 32; i++) {
140		/* Is there input available? */
141		rr0 = zs_read_csr(cs);
142		if ((rr0 & ZSRR0_RX_READY) == 0)
143			break;
144
145		/*
146		 * First read the status, because reading the data
147		 * destroys the status of this char.
148		 */
149		rr1 = zs_read_reg(cs, 1);
150		c = zs_read_data(cs);
151
152		if (rr1 & (ZSRR1_FE | ZSRR1_DO | ZSRR1_PE)) {
153			/* Clear the receive error. */
154			zs_write_csr(cs, ZSWR0_RESET_ERRORS);
155		}
156	}
157}
158
159
160/*
161 * Write the given register set to the given zs channel in the proper order.
162 * The channel must not be transmitting at the time.  The receiver will
163 * be disabled for the time it takes to write all the registers.
164 * Call this with interrupts disabled.
165 */
166void
167zs_loadchannelregs(struct zs_chanstate *cs)
168{
169	uint8_t *reg, v;
170
171	zs_write_csr(cs, ZSM_RESET_ERR); /* XXX: reset error condition */
172
173#if 1
174	/*
175	 * XXX: Is this really a good idea?
176	 * XXX: Should go elsewhere! -gwr
177	 */
178	zs_iflush(cs);	/* XXX */
179#endif
180
181	if (cs->cs_ctl_chan != NULL)
182		v = ((cs->cs_ctl_chan->cs_creg[5] & (ZSWR5_RTS | ZSWR5_DTR)) !=
183		    (cs->cs_ctl_chan->cs_preg[5] & (ZSWR5_RTS | ZSWR5_DTR)));
184	else
185		v = 0;
186
187	if (memcmp((void *)cs->cs_preg, (void *)cs->cs_creg, 16) == 0 && !v)
188		return;	/* only change if values are different */
189
190	/* Copy "pending" regs to "current" */
191	memcpy((void *)cs->cs_creg, (void *)cs->cs_preg, 16);
192	reg = cs->cs_creg;	/* current regs */
193
194	/* disable interrupts */
195	zs_write_reg(cs, 1, reg[1] & ~ZSWR1_IMASK);
196
197	/* baud clock divisor, stop bits, parity */
198	zs_write_reg(cs, 4, reg[4]);
199
200	/* misc. TX/RX control bits */
201	zs_write_reg(cs, 10, reg[10]);
202
203	/* char size, enable (RX/TX) */
204	zs_write_reg(cs, 3, reg[3] & ~ZSWR3_RX_ENABLE);
205	zs_write_reg(cs, 5, reg[5] & ~ZSWR5_TX_ENABLE);
206
207	/* synchronous mode stuff */
208	zs_write_reg(cs, 6, reg[6]);
209	zs_write_reg(cs, 7, reg[7]);
210
211#if 0
212	/*
213	 * Registers 2 and 9 are special because they are
214	 * actually common to both channels, but must be
215	 * programmed through channel A.  The "zsc" attach
216	 * function takes care of setting these registers
217	 * and they should not be touched thereafter.
218	 */
219	/* interrupt vector */
220	zs_write_reg(cs, 2, reg[2]);
221	/* master interrupt control */
222	zs_write_reg(cs, 9, reg[9]);
223#endif
224
225	/* Shut down the BRG */
226	zs_write_reg(cs, 14, reg[14] & ~ZSWR14_BAUD_ENA);
227
228#ifdef	ZS_MD_SETCLK
229	/* Let the MD code setup any external clock. */
230	ZS_MD_SETCLK(cs);
231#endif	/* ZS_MD_SETCLK */
232
233	/* clock mode control */
234	zs_write_reg(cs, 11, reg[11]);
235
236	/* baud rate (lo/hi) */
237	zs_write_reg(cs, 12, reg[12]);
238	zs_write_reg(cs, 13, reg[13]);
239
240	/* Misc. control bits */
241	zs_write_reg(cs, 14, reg[14]);
242
243	/* which lines cause status interrupts */
244	zs_write_reg(cs, 15, reg[15]);
245
246	/*
247	 * Zilog docs recommend resetting external status twice at this
248	 * point. Mainly as the status bits are latched, and the first
249	 * interrupt clear might unlatch them to new values, generating
250	 * a second interrupt request.
251	 */
252	zs_write_csr(cs, ZSM_RESET_STINT);
253	zs_write_csr(cs, ZSM_RESET_STINT);
254
255	/* char size, enable (RX/TX)*/
256	zs_write_reg(cs, 3, reg[3]);
257	zs_write_reg(cs, 5, reg[5]);
258
259	/* Write the status bits on the alternate channel also. */
260	if (cs->cs_ctl_chan != NULL) {
261		v = cs->cs_ctl_chan->cs_preg[5];
262		cs->cs_ctl_chan->cs_creg[5] = v;
263		zs_write_reg(cs->cs_ctl_chan, 5, v);
264	}
265
266	/* interrupt enables: RX, TX, STATUS */
267	zs_write_reg(cs, 1, reg[1]);
268}
269
270void
271zs_lock_init(struct zs_chanstate *cs)
272{
273
274	mutex_init(&cs->cs_lock, MUTEX_NODEBUG, IPL_ZS);
275}
276
277void
278zs_lock_chan(struct zs_chanstate *cs)
279{
280
281	mutex_spin_enter(&cs->cs_lock);
282}
283
284void
285zs_unlock_chan(struct zs_chanstate *cs)
286{
287
288	mutex_spin_exit(&cs->cs_lock);
289}
290
291/*
292 * ZS hardware interrupt.  Scan all ZS channels.  NB: we know here that
293 * channels are kept in (A,B) pairs.
294 *
295 * Do just a little, then get out; set a software interrupt if more
296 * work is needed.
297 *
298 * We deliberately ignore the vectoring Zilog gives us, and match up
299 * only the number of `reset interrupt under service' operations, not
300 * the order.
301 */
302int
303zsc_intr_hard(void *arg)
304{
305	struct zsc_softc *zsc = arg;
306	struct zs_chanstate *cs0, *cs1;
307	int handled;
308	uint8_t rr3;
309
310	handled = 0;
311
312	/* First look at channel A. */
313	cs0 = zsc->zsc_cs[0];
314	cs1 = zsc->zsc_cs[1];
315
316	/*
317	 * We have to clear interrupt first to avoid a race condition,
318	 * but it will be done in each MD handler.
319	 */
320	for (;;) {
321		/* Lock both channels */
322		mutex_spin_enter(&cs1->cs_lock);
323		mutex_spin_enter(&cs0->cs_lock);
324		/* Note: only channel A has an RR3 */
325		rr3 = zs_read_reg(cs0, 3);
326
327		if ((rr3 & (ZSRR3_IP_A_RX | ZSRR3_IP_A_TX | ZSRR3_IP_A_STAT |
328		    ZSRR3_IP_B_RX | ZSRR3_IP_B_TX | ZSRR3_IP_B_STAT)) == 0) {
329			mutex_spin_exit(&cs0->cs_lock);
330			mutex_spin_exit(&cs1->cs_lock);
331			break;
332		}
333		handled = 1;
334
335		/* First look at channel A. */
336		if (rr3 & (ZSRR3_IP_A_RX | ZSRR3_IP_A_TX | ZSRR3_IP_A_STAT))
337			zs_write_csr(cs0, ZSWR0_CLR_INTR);
338
339		if (rr3 & ZSRR3_IP_A_RX)
340			(*cs0->cs_ops->zsop_rxint)(cs0);
341		if (rr3 & ZSRR3_IP_A_STAT)
342			(*cs0->cs_ops->zsop_stint)(cs0, 0);
343		if (rr3 & ZSRR3_IP_A_TX)
344			(*cs0->cs_ops->zsop_txint)(cs0);
345
346		/* Done with channel A */
347		mutex_spin_exit(&cs0->cs_lock);
348
349		/* Now look at channel B. */
350		if (rr3 & (ZSRR3_IP_B_RX | ZSRR3_IP_B_TX | ZSRR3_IP_B_STAT))
351			zs_write_csr(cs1, ZSWR0_CLR_INTR);
352
353		if (rr3 & ZSRR3_IP_B_RX)
354			(*cs1->cs_ops->zsop_rxint)(cs1);
355		if (rr3 & ZSRR3_IP_B_STAT)
356			(*cs1->cs_ops->zsop_stint)(cs1, 0);
357		if (rr3 & ZSRR3_IP_B_TX)
358			(*cs1->cs_ops->zsop_txint)(cs1);
359
360		mutex_spin_exit(&cs1->cs_lock);
361	}
362
363	/* Note: caller will check cs_x->cs_softreq and DTRT. */
364	return handled;
365}
366
367
368/*
369 * ZS software interrupt.  Scan all channels for deferred interrupts.
370 */
371int
372zsc_intr_soft(void *arg)
373{
374	struct zsc_softc *zsc = arg;
375	struct zs_chanstate *cs;
376	int rval, chan;
377
378	rval = 0;
379	for (chan = 0; chan < 2; chan++) {
380		cs = zsc->zsc_cs[chan];
381
382		/*
383		 * The softint flag can be safely cleared once
384		 * we have decided to call the softint routine.
385		 * (No need to do splzs() first.)
386		 */
387		if (cs->cs_softreq) {
388			cs->cs_softreq = 0;
389			(*cs->cs_ops->zsop_softint)(cs);
390			rval++;
391		}
392	}
393	return (rval);
394}
395
396/*
397 * Provide a null zs "ops" vector.
398 */
399
400static void zsnull_rxint  (struct zs_chanstate *);
401static void zsnull_stint  (struct zs_chanstate *, int);
402static void zsnull_txint  (struct zs_chanstate *);
403static void zsnull_softint(struct zs_chanstate *);
404
405static void
406zsnull_rxint(struct zs_chanstate *cs)
407{
408
409	/* Ask for softint() call. */
410	cs->cs_softreq = 1;
411}
412
413static void
414zsnull_stint(struct zs_chanstate *cs, int force)
415{
416
417	/* Ask for softint() call. */
418	cs->cs_softreq = 1;
419}
420
421static void
422zsnull_txint(struct zs_chanstate *cs)
423{
424
425	/* Ask for softint() call. */
426	cs->cs_softreq = 1;
427}
428
429static void
430zsnull_softint(struct zs_chanstate *cs)
431{
432
433	zs_write_reg(cs,  1, 0);
434	zs_write_reg(cs, 15, 0);
435}
436
437struct zsops zsops_null = {
438	zsnull_rxint,	/* receive char available */
439	zsnull_stint,	/* external/status */
440	zsnull_txint,	/* xmit buffer empty */
441	zsnull_softint,	/* process software interrupt */
442};
443