xref: /netbsd-src/sys/arch/cesfic/dev/zs.c (revision b1c86f5f087524e68db12794ee9c3e3da1ab17a0)
1 /*	$NetBSD: zs.c,v 1.18 2009/10/26 19:16:55 cegger 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  *
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.18 2009/10/26 19:16:55 cegger Exp $");
41 
42 #include "opt_ddb.h"
43 
44 #include <sys/param.h>
45 #include <sys/systm.h>
46 #include <sys/conf.h>
47 #include <sys/device.h>
48 #include <sys/file.h>
49 #include <sys/ioctl.h>
50 #include <sys/kernel.h>
51 #include <sys/malloc.h>
52 #include <sys/proc.h>
53 #include <sys/tty.h>
54 #include <sys/time.h>
55 #include <sys/syslog.h>
56 
57 #include <dev/cons.h>
58 #include <dev/ic/z8530reg.h>
59 
60 #include <machine/cpu.h>
61 
62 #include <machine/z8530var.h>
63 #include <cesfic/dev/zsvar.h>
64 
65 #include "ioconf.h"
66 
67 int zs_getc(void *);
68 void zs_putc(void*, int);
69 
70 static struct zs_chanstate zs_conschan_store;
71 static int zs_hwflags[2][2];
72 
73 static uint8_t zs_init_reg[16] = {
74 	0,	/* 0: CMD (reset, etc.) */
75 	0,	/* 1: No interrupts yet. */
76 	0x18 + ZSHARD_PRI,	/* IVECT */
77 	ZSWR3_RX_8 | ZSWR3_RX_ENABLE,
78 	ZSWR4_CLK_X16 | ZSWR4_ONESB | ZSWR4_EVENP,
79 	ZSWR5_TX_8 | ZSWR5_TX_ENABLE,
80 	0,	/* 6: TXSYNC/SYNCLO */
81 	0,	/* 7: RXSYNC/SYNCHI */
82 	0,	/* 8: alias for data port */
83 	ZSWR9_MASTER_IE,
84 	0,	/*10: Misc. TX/RX control bits */
85 	ZSWR11_TXCLK_BAUD | ZSWR11_RXCLK_BAUD,
86 	11,	/*12: BAUDLO (default=9600) */
87 	0,	/*13: BAUDHI (default=9600) */
88 	ZSWR14_BAUD_ENA | ZSWR14_BAUD_FROM_PCLK,
89 	ZSWR15_BREAK_IE | ZSWR15_DCD_IE,
90 };
91 
92 static int zsc_print(void *, const char *);
93 int zscngetc(dev_t);
94 void zscnputc(dev_t, int);
95 
96 static struct consdev zscons = {
97 	NULL, NULL,
98 	zscngetc, zscnputc, nullcnpollc, NULL, NULL, NULL,
99 	NODEV, 1
100 };
101 
102 void
103 zs_config(struct zsc_softc *zsc, char *base)
104 {
105 	struct zsc_attach_args zsc_args;
106 	struct zs_chanstate *cs;
107 	int zsc_unit, channel, s;
108 
109 	zsc_unit = device_unit(zsc->zsc_dev);
110 	aprint_normal(": Zilog 8530 SCC\n");
111 
112 	/*
113 	 * Initialize software state for each channel.
114 	 */
115 	for (channel = 0; channel < 2; channel++) {
116 		zsc_args.channel = channel;
117 		zsc_args.hwflags = zs_hwflags[zsc_unit][channel];
118 
119 		/*
120 		 * If we're the console, copy the channel state, and
121 		 * adjust the console channel pointer.
122 		 */
123 		if (zsc_args.hwflags & ZS_HWFLAG_CONSOLE) {
124 			cs = &zs_conschan_store;
125 		} else {
126 			cs = malloc(sizeof(struct zs_chanstate),
127 				    M_DEVBUF, M_NOWAIT | M_ZERO);
128 			if(channel==0){
129 				cs->cs_reg_csr  = base + 7;
130 				cs->cs_reg_data = base + 15;
131 			} else {
132 				cs->cs_reg_csr  = base + 3;
133 				cs->cs_reg_data = base + 11;
134 			}
135 			memcpy(cs->cs_creg, zs_init_reg, 16);
136 			memcpy(cs->cs_preg, zs_init_reg, 16);
137 			cs->cs_defspeed = 9600;
138 		}
139 		zsc->zsc_cs[channel] = cs;
140 		zs_lock_init(cs);
141 
142 		cs->cs_defcflag = CREAD | CS8 | HUPCL;
143 
144 		/* Make these correspond to cs_defcflag (-crtscts) */
145 		cs->cs_rr0_dcd = ZSRR0_DCD;
146 		cs->cs_rr0_cts = 0;
147 		cs->cs_wr5_dtr = ZSWR5_DTR | ZSWR5_RTS;
148 		cs->cs_wr5_rts = 0;
149 
150 		cs->cs_channel = channel;
151 		cs->cs_private = NULL;
152 		cs->cs_ops = &zsops_null;
153 		cs->cs_brg_clk = 4000000 / 16;
154 
155 		/*
156 		 * Clear the master interrupt enable.
157 		 * The INTENA is common to both channels,
158 		 * so just do it on the A channel.
159 		 */
160 		if (channel == 0) {
161 			zs_write_reg(cs, 9, 0);
162 		}
163 
164 		/*
165 		 * Look for a child driver for this channel.
166 		 * The child attach will setup the hardware.
167 		 */
168 		if (!config_found(zsc->zsc_dev, (void *)&zsc_args,
169 		    zsc_print)) {
170 			/* No sub-driver.  Just reset it. */
171 			uint8_t reset = (channel == 0) ?
172 				ZSWR9_A_RESET : ZSWR9_B_RESET;
173 			s = splzs();
174 			zs_write_reg(cs,  9, reset);
175 			splx(s);
176 		}
177 	}
178 }
179 
180 static int
181 zsc_print(void *aux, const char *name)
182 {
183 	struct zsc_attach_args *args = aux;
184 
185 	if (name != NULL)
186 		aprint_normal("%s: ", name);
187 
188 	if (args->channel != -1)
189 		aprint_normal(" channel %d", args->channel);
190 
191 	return UNCONF;
192 }
193 
194 int
195 zshard(void *arg)
196 {
197 	struct zsc_softc *zsc;
198 	int unit, rval;
199 
200 	rval = 0;
201 	for (unit = 0; unit < zsc_cd.cd_ndevs; unit++) {
202 		zsc = device_lookup_private(&zsc_cd, unit);
203 		if (zsc == NULL)
204 			continue;
205 		rval |= zsc_intr_hard(zsc);
206 		if ((zsc->zsc_cs[0]->cs_softreq) ||
207 		    (zsc->zsc_cs[1]->cs_softreq)) {
208 			softint_schedule(zsc->zsc_softintr_cookie);
209 		}
210 	}
211 	return (rval);
212 }
213 
214 uint8_t
215 zs_read_reg(struct zs_chanstate *cs, uint8_t reg)
216 {
217 	uint8_t val;
218 
219 	*cs->cs_reg_csr = reg;
220 	ZS_DELAY();
221 	val = *cs->cs_reg_csr;
222 	ZS_DELAY();
223 	return val;
224 }
225 
226 void
227 zs_write_reg(struct zs_chanstate *cs, uint8_t reg, uint8_t val)
228 {
229 	*cs->cs_reg_csr = reg;
230 	ZS_DELAY();
231 	*cs->cs_reg_csr = val;
232 	ZS_DELAY();
233 }
234 
235 uint8_t
236 zs_read_csr(struct zs_chanstate *cs)
237 {
238 	uint8_t val;
239 
240 	val = *cs->cs_reg_csr;
241 	ZS_DELAY();
242 	return val;
243 }
244 
245 void
246 zs_write_csr(struct zs_chanstate *cs, uint8_t val)
247 {
248 
249 	*cs->cs_reg_csr = val;
250 	ZS_DELAY();
251 }
252 
253 uint8_t
254 zs_read_data(struct zs_chanstate *cs)
255 {
256 	uint8_t val;
257 
258 	val = *cs->cs_reg_data;
259 	ZS_DELAY();
260 	return val;
261 }
262 
263 void
264 zs_write_data(struct zs_chanstate *cs, uint8_t val)
265 {
266 
267 	*cs->cs_reg_data = val;
268 	ZS_DELAY();
269 }
270 
271 int
272 zs_set_speed(struct zs_chanstate *cs, int bps)
273 {
274 	int tconst, real_bps;
275 
276 	tconst = BPS_TO_TCONST(cs->cs_brg_clk, bps);
277 
278 	if (tconst < 0)
279 		return (EINVAL);
280 
281 	/* Convert back to make sure we can do it. */
282 	real_bps = TCONST_TO_BPS(cs->cs_brg_clk, tconst);
283 #if 0
284 	/* XXX - Allow some tolerance here? */
285 	if (real_bps != bps)
286 		return (EINVAL);
287 #endif
288 	cs->cs_preg[12] = tconst;
289 	cs->cs_preg[13] = tconst >> 8;
290 
291 	return (0);
292 }
293 
294 int
295 zs_set_modes(struct zs_chanstate *cs, int cflag)
296 {
297 	int s;
298 
299 	/*
300 	 * Output hardware flow control on the chip is horrendous:
301 	 * if carrier detect drops, the receiver is disabled, and if
302 	 * CTS drops, the transmitter is stoped IN MID CHARACTER!
303 	 * Therefore, NEVER set the HFC bit, and instead use the
304 	 * status interrupt to detect CTS changes.
305 	 */
306 	s = splzs();
307 #if 0	/* XXX - See below. */
308 	if (cflag & CLOCAL) {
309 		cs->cs_rr0_dcd = 0;
310 		cs->cs_preg[15] &= ~ZSWR15_DCD_IE;
311 	} else {
312 		/* XXX - Need to notice DCD change here... */
313 		cs->cs_rr0_dcd = ZSRR0_DCD;
314 		cs->cs_preg[15] |= ZSWR15_DCD_IE;
315 	}
316 #endif	/* XXX */
317 	if (cflag & CRTSCTS) {
318 		cs->cs_wr5_dtr = ZSWR5_DTR;
319 		cs->cs_wr5_rts = ZSWR5_RTS;
320 		cs->cs_rr0_cts = ZSRR0_CTS;
321 		cs->cs_preg[15] |= ZSWR15_CTS_IE;
322 	} else {
323 		cs->cs_wr5_dtr = ZSWR5_DTR | ZSWR5_RTS;
324 		cs->cs_wr5_rts = 0;
325 		cs->cs_rr0_cts = 0;
326 		cs->cs_preg[15] &= ~ZSWR15_CTS_IE;
327 	}
328 	splx(s);
329 
330 	/* Caller will stuff the pending registers. */
331 	return (0);
332 }
333 
334 /*
335  * Handle user request to enter kernel debugger.
336  */
337 void
338 zs_abort(struct zs_chanstate *cs)
339 {
340 	int rr0;
341 
342 	/* Wait for end of break to avoid PROM abort. */
343 	/* XXX - Limit the wait? */
344 	do {
345 		rr0 = *cs->cs_reg_csr;
346 		ZS_DELAY();
347 	} while (rr0 & ZSRR0_BREAK);
348 #ifdef DDB
349 	console_debugger();
350 #endif
351 }
352 
353 /*
354  * Polled input char.
355  */
356 int
357 zs_getc(void *arg)
358 {
359 	struct zs_chanstate *cs = arg;
360 	int s, c;
361 	uint8_t rr0, stat;
362 
363 	s = splhigh();
364 top:
365 	/* Wait for a character to arrive. */
366 	do {
367 		rr0 = *cs->cs_reg_csr;
368 		ZS_DELAY();
369 	} while ((rr0 & ZSRR0_RX_READY) == 0);
370 
371 	/* Read error register. */
372 	stat = zs_read_reg(cs, 1) & (ZSRR1_FE | ZSRR1_DO | ZSRR1_PE);
373 	if (stat) {
374 		zs_write_csr(cs, ZSM_RESET_ERR);
375 		goto top;
376 	}
377 
378 	/* Read character. */
379 	c = *cs->cs_reg_data;
380 	ZS_DELAY();
381 	splx(s);
382 
383 	return (c);
384 }
385 
386 /*
387  * Polled output char.
388  */
389 void
390 zs_putc(void *arg, int c)
391 {
392 	struct zs_chanstate *cs = arg;
393 	int s;
394 	uint8_t rr0;
395 
396 	s = splhigh();
397 	/* Wait for transmitter to become ready. */
398 	do {
399 		rr0 = *cs->cs_reg_csr;
400 		ZS_DELAY();
401 	} while ((rr0 & ZSRR0_TX_READY) == 0);
402 
403 	*cs->cs_reg_data = c;
404 	ZS_DELAY();
405 	splx(s);
406 }
407 
408 int
409 zscngetc(dev_t dev)
410 {
411 	struct zs_chanstate *cs = &zs_conschan_store;
412 	int c;
413 
414 	c = zs_getc(cs);
415 	return (c);
416 }
417 
418 void
419 zscnputc(dev_t dev, int c)
420 {
421 	struct zs_chanstate *cs = &zs_conschan_store;
422 
423 	zs_putc(cs, c);
424 }
425 
426 /*
427  * Common parts of console init.
428  */
429 void
430 zs_cninit(void *base)
431 {
432 	struct zs_chanstate *cs;
433 	/*
434 	 * Pointer to channel state.  Later, the console channel
435 	 * state is copied into the softc, and the console channel
436 	 * pointer adjusted to point to the new copy.
437 	 */
438 	cs = &zs_conschan_store;
439 	zs_hwflags[0][0] = ZS_HWFLAG_CONSOLE;
440 
441 	/* Setup temporary chanstate. */
442 	cs->cs_reg_csr  = (uint8_t *)base + 7;
443 	cs->cs_reg_data = (uint8_t *)base + 15;
444 
445 	/* Initialize the pending registers. */
446 	memcpy(cs->cs_preg, zs_init_reg, 16);
447 	cs->cs_preg[5] |= (ZSWR5_DTR | ZSWR5_RTS);
448 
449 	/* XXX: Preserve BAUD rate from boot loader. */
450 	/* XXX: Also, why reset the chip here? -gwr */
451 	/* cs->cs_defspeed = zs_get_speed(cs); */
452 	cs->cs_defspeed = 9600;	/* XXX */
453 
454 	/* Clear the master interrupt enable. */
455 	zs_write_reg(cs, 9, 0);
456 
457 	/* Reset the whole SCC chip. */
458 	zs_write_reg(cs, 9, ZSWR9_HARD_RESET);
459 
460 	/* Copy "pending" to "current" and H/W. */
461 	zs_loadchannelregs(cs);
462 
463 	/* Point the console at the SCC. */
464 	cn_tab = &zscons;
465 }
466