1/*	$NetBSD: zs.c,v 1.17 2009/03/18 17:06:43 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.17 2009/03/18 17:06:43 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
67int zs_getc(void *);
68void zs_putc(void*, int);
69
70static struct zs_chanstate zs_conschan_store;
71static int zs_hwflags[2][2];
72
73static 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
92static int zsc_print(void *, const char *);
93int zscngetc(dev_t);
94void zscnputc(dev_t, int);
95
96static struct consdev zscons = {
97	NULL, NULL,
98	zscngetc, zscnputc, nullcnpollc, NULL, NULL, NULL,
99	NODEV, 1
100};
101
102void
103zs_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
180static int
181zsc_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
194int
195zshard(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
214uint8_t
215zs_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
226void
227zs_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
235uint8_t
236zs_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
245void
246zs_write_csr(struct zs_chanstate *cs, uint8_t val)
247{
248
249	*cs->cs_reg_csr = val;
250	ZS_DELAY();
251}
252
253uint8_t
254zs_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
263void
264zs_write_data(struct zs_chanstate *cs, uint8_t val)
265{
266
267	*cs->cs_reg_data = val;
268	ZS_DELAY();
269}
270
271int
272zs_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
294int
295zs_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 */
337void
338zs_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 */
356int
357zs_getc(void *arg)
358{
359	struct zs_chanstate *cs = arg;
360	int s, c;
361	uint8_t rr0, stat;
362
363	s = splhigh();
364top:
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 */
389void
390zs_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
408int
409zscngetc(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
418void
419zscnputc(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 */
429void
430zs_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