xref: /netbsd-src/sys/arch/ews4800mips/dev/zs.c (revision 207defd0369f03b80f291e7c291be1f3b7ab3397)
1 /*	$NetBSD: zs.c,v 1.6 2021/09/11 20:28:03 andvar Exp $	*/
2 
3 /*-
4  * Copyright (c) 1996, 2005 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  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 /*
33  * Zilog Z8530 Dual UART driver (machine-dependent part)
34  *
35  * Runs two serial lines per chip using slave drivers.
36  * Plain tty/async lines use the zs_async slave.
37  */
38 
39 #include <sys/cdefs.h>
40 __KERNEL_RCSID(0, "$NetBSD: zs.c,v 1.6 2021/09/11 20:28:03 andvar Exp $");
41 
42 #include "opt_ddb.h"
43 
44 #include <sys/param.h>
45 #include <sys/device.h>
46 #include <sys/tty.h>
47 #include <sys/systm.h>
48 #include <sys/intr.h>
49 
50 #include <machine/z8530var.h>
51 #include <dev/ic/z8530reg.h>
52 
53 #include "ioconf.h"
54 
55 /* console status for consinit() */
56 static struct zs_chanstate zs_conscs_store;
57 struct zs_chanstate *zs_conscs = &zs_conscs_store;
58 void *zs_consaddr;
59 
60 /*
61  * Some warts needed by z8530tty.c -
62  * The default parity REALLY needs to be the same as the PROM uses,
63  * or you can not see messages done with printf during boot-up...
64  */
65 int zs_def_cflag = (CREAD | CS8 | HUPCL);
66 
67 int
zs_print(void * aux,const char * name)68 zs_print(void *aux, const char *name)
69 {
70 	struct zsc_attach_args *args = aux;
71 
72 	if (name != NULL)
73 		aprint_normal("%s: ", name);
74 
75 	if (args->channel != -1)
76 		aprint_normal(" channel %d", args->channel);
77 
78 	return UNCONF;
79 }
80 
81 int
zshard(void * arg)82 zshard(void *arg)
83 {
84 	struct zsc_softc *zsc;
85 	int rval;
86 
87 	zsc = arg;
88 	rval = zsc_intr_hard(zsc);
89 	if (zsc->zsc_cs[0]->cs_softreq || zsc->zsc_cs[1]->cs_softreq)
90 		softint_schedule(zsc->zsc_si);
91 
92 	return rval;
93 }
94 
95 /*
96  * Compute the current baud rate given a ZS channel.
97  */
98 int
zs_get_speed(struct zs_chanstate * cs)99 zs_get_speed(struct zs_chanstate *cs)
100 {
101 	int tconst;
102 
103 	tconst = zs_read_reg(cs, 12);
104 	tconst |= zs_read_reg(cs, 13) << 8;
105 	return TCONST_TO_BPS(cs->cs_brg_clk, tconst);
106 }
107 
108 /*
109  * MD functions for setting the baud rate and control modes.
110  */
111 int
zs_set_speed(struct zs_chanstate * cs,int bps)112 zs_set_speed(struct zs_chanstate *cs, int bps)
113 {
114 	int tconst, real_bps;
115 
116 	if (bps == 0)
117 		return 0;
118 
119 #ifdef	DIAGNOSTIC
120 	if (cs->cs_brg_clk == 0)
121 		panic("zs_set_speed");
122 #endif
123 
124 	tconst = BPS_TO_TCONST(cs->cs_brg_clk, bps);
125 	if (tconst < 0)
126 		return EINVAL;
127 
128 	/* Convert back to make sure we can do it. */
129 	real_bps = TCONST_TO_BPS(cs->cs_brg_clk, tconst);
130 
131 	/* XXX - Allow some tolerance here? */
132 	if (real_bps != bps)
133 		return EINVAL;
134 
135 	cs->cs_preg[12] = tconst;
136 	cs->cs_preg[13] = tconst >> 8;
137 
138 	/* Caller will stuff the pending registers. */
139 	return 0;
140 }
141 
142 int
zs_set_modes(struct zs_chanstate * cs,int cflag)143 zs_set_modes(struct zs_chanstate *cs, int cflag)
144 {
145 	int s;
146 
147 	/*
148 	 * Output hardware flow control on the chip is horrendous:
149 	 * if carrier detect drops, the receiver is disabled, and if
150 	 * CTS drops, the transmitter is stopped IN MID CHARACTER!
151 	 * Therefore, NEVER set the HFC bit, and instead use the
152 	 * status interrupt to detect CTS changes.
153 	 */
154 	s = splserial();
155 	cs->cs_rr0_pps = 0;
156 	if ((cflag & (CLOCAL | MDMBUF)) != 0) {
157 		cs->cs_rr0_dcd = 0;
158 		if ((cflag & MDMBUF) == 0)
159 			cs->cs_rr0_pps = ZSRR0_DCD;
160 	} else
161 		cs->cs_rr0_dcd = ZSRR0_DCD;
162 	if ((cflag & CRTSCTS) != 0) {
163 		cs->cs_wr5_dtr = ZSWR5_DTR;
164 		cs->cs_wr5_rts = ZSWR5_RTS;
165 		cs->cs_rr0_cts = ZSRR0_CTS;
166 	} else if ((cflag & MDMBUF) != 0) {
167 		cs->cs_wr5_dtr = 0;
168 		cs->cs_wr5_rts = ZSWR5_DTR;
169 		cs->cs_rr0_cts = ZSRR0_DCD;
170 	} else {
171 		cs->cs_wr5_dtr = ZSWR5_DTR | ZSWR5_RTS;
172 		cs->cs_wr5_rts = 0;
173 		cs->cs_rr0_cts = 0;
174 	}
175 	splx(s);
176 
177 	/* Caller will stuff the pending registers. */
178 	return 0;
179 }
180 
181 /*
182  * Read or write the chip with suitable delays.
183  */
184 uint8_t
zs_read_reg(struct zs_chanstate * cs,uint8_t reg)185 zs_read_reg(struct zs_chanstate *cs, uint8_t reg)
186 {
187 	uint8_t val;
188 
189 	*cs->cs_reg_csr = reg;
190 
191 	val = *cs->cs_reg_csr;
192 
193 	return val;
194 }
195 
196 void
zs_write_reg(struct zs_chanstate * cs,uint8_t reg,uint8_t val)197 zs_write_reg(struct zs_chanstate *cs, uint8_t reg, uint8_t val)
198 {
199 
200 	*cs->cs_reg_csr = reg;
201 
202 	*cs->cs_reg_csr = val;
203 
204 }
205 
206 uint8_t
zs_read_csr(struct zs_chanstate * cs)207 zs_read_csr(struct zs_chanstate *cs)
208 {
209 	uint8_t val;
210 
211 	val = *cs->cs_reg_csr;
212 
213 	return val;
214 }
215 
216 void
zs_write_csr(struct zs_chanstate * cs,uint8_t val)217 zs_write_csr(struct zs_chanstate *cs, uint8_t val)
218 {
219 
220 	*cs->cs_reg_csr = val;
221 
222 }
223 
224 uint8_t
zs_read_data(struct zs_chanstate * cs)225 zs_read_data(struct zs_chanstate *cs)
226 {
227 	uint8_t val;
228 
229 	val = *cs->cs_reg_data;
230 
231 	return val;
232 }
233 
234 void
zs_write_data(struct zs_chanstate * cs,uint8_t val)235 zs_write_data(struct zs_chanstate *cs, uint8_t val)
236 {
237 
238 	*cs->cs_reg_data = val;
239 }
240 
241 void
zs_abort(struct zs_chanstate * cs)242 zs_abort(struct zs_chanstate *cs)
243 {
244 
245 #ifdef DDB
246 	Debugger();
247 #endif
248 }
249 
250 /*
251  * Polled input char.
252  */
253 int
zs_getc(void * arg)254 zs_getc(void *arg)
255 {
256 	struct zs_chanstate *cs = arg;
257 	int s, c;
258 	uint8_t rr0;
259 
260 	s = splhigh();
261 	/* Wait for a character to arrive. */
262 	do {
263 		rr0 = *cs->cs_reg_csr;
264 		ZS_DELAY();
265 	} while ((rr0 & ZSRR0_RX_READY) == 0);
266 
267 	c = *cs->cs_reg_data;
268 	ZS_DELAY();
269 	splx(s);
270 
271 	/*
272 	 * This could be used by the kd driver to read scan codes,
273 	 * so don't translate '\r' ==> '\n' here...
274 	 */
275 	return c;
276 }
277 
278 /*
279  * Polled output char.
280  */
281 void
zs_putc(void * arg,int c)282 zs_putc(void *arg, int c)
283 {
284 	struct zs_chanstate *cs = arg;
285 	int s;
286 	uint8_t rr0;
287 
288 	s = splhigh();
289 	/* Wait for transmitter to become ready. */
290 	do {
291 		rr0 = *cs->cs_reg_csr;
292 		ZS_DELAY();
293 	} while ((rr0 & ZSRR0_TX_READY) == 0);
294 
295 	*cs->cs_reg_data = c;
296 	ZS_DELAY();
297 	splx(s);
298 }
299 
300 int
zscngetc(dev_t dev)301 zscngetc(dev_t dev)
302 {
303 
304 	return zs_getc((void *)zs_conscs);
305 }
306 
307 void
zscnputc(dev_t dev,int c)308 zscnputc(dev_t dev, int c)
309 {
310 
311 	zs_putc((void *)zs_conscs, c);
312 }
313