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