1/*	$NetBSD: zs_sbdio.c,v 1.9 2008/03/29 19:15:34 tsutsui 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_sbdio.c,v 1.9 2008/03/29 19:15:34 tsutsui Exp $");
41
42#include <sys/param.h>
43#include <sys/systm.h>
44#include <sys/device.h>
45#include <sys/tty.h>
46#include <sys/conf.h>
47#include <sys/intr.h>
48
49#include <dev/cons.h>
50#include <dev/ic/z8530reg.h>
51
52#include <machine/sbdiovar.h>
53#include <machine/z8530var.h>
54
55#define ZS_DEFSPEED	9600
56#define PCLK		(9600 * 512)		/* 4.915200MHz */
57
58/* The layout of this is hardware-dependent (padding, order). */
59struct zschan {
60	volatile uint8_t zc_csr;	/* ctrl, status, and indirect access */
61	uint8_t padding1[3];
62	volatile uint8_t zc_data;	/* data */
63	uint8_t padding2[3];
64} __attribute__((__packed__));
65
66struct zsdevice {
67	/* Yes, they are backwards. */
68	struct	zschan zs_chan_b;
69	struct	zschan zs_chan_a;
70} __attribute__((__packed__));
71
72static uint8_t zs_init_reg[16] = {
73	0,				/*  0: CMD (reset, etc.) */
74	0,				/*  1: No interrupts yet. */
75	0,				/*  2: IVECT EWS-UX don't set this. */
76	ZSWR3_RX_8 | ZSWR3_RX_ENABLE,
77	ZSWR4_CLK_X16 | ZSWR4_ONESB | ZSWR4_EVENP,
78	ZSWR5_TX_8 | ZSWR5_TX_ENABLE,
79	0,				/*  6: TXSYNC/SYNCLO */
80	0,				/*  7: RXSYNC/SYNCHI */
81	0,				/*  8: alias for data port */
82	ZSWR9_MASTER_IE,
83	0,				/* 10: Misc. TX/RX control bits */
84	ZSWR11_TXCLK_BAUD | ZSWR11_RXCLK_BAUD,
85	BPS_TO_TCONST((PCLK/16), ZS_DEFSPEED), /* 12: BAUDLO (default=9600) */
86	0,				/*13: BAUDHI (default=9600) */
87	ZSWR14_BAUD_ENA | ZSWR14_BAUD_FROM_PCLK,
88	ZSWR15_BREAK_IE,
89};
90
91static int zs_sbdio_match(device_t, cfdata_t, void *);
92static void zs_sbdio_attach(device_t, device_t, void *);
93
94CFATTACH_DECL_NEW(zsc_sbdio, sizeof(struct zsc_softc),
95    zs_sbdio_match, zs_sbdio_attach, NULL, NULL);
96
97int
98zs_sbdio_match(device_t parent, cfdata_t cf, void *aux)
99{
100	struct sbdio_attach_args *sa = aux;
101
102	return strcmp(sa->sa_name, "zsc") ? 0 : 1;
103}
104
105void
106zs_sbdio_attach(device_t parent, device_t self, void *aux)
107{
108	struct zsc_softc *zsc = device_private(self);
109	struct sbdio_attach_args *sa = aux;
110	struct zsc_attach_args zsc_args;
111	struct zschan *zc;
112	struct zs_chanstate *cs;
113	struct zsdevice *zs_addr;
114	int s, zs_unit, channel;
115
116	zsc->zsc_dev = self;
117	aprint_normal("\n");
118
119	zs_unit = device_unit(self);
120	zs_addr = (void *)MIPS_PHYS_TO_KSEG1(sa->sa_addr1);
121	zsc->zsc_flags = sa->sa_flags;
122
123	/*
124	 * Initialize software state for each channel.
125	 */
126	for (channel = 0; channel < 2; channel++) {
127		zsc_args.channel = channel;
128		zsc_args.hwflags = 0;
129		cs = &zsc->zsc_cs_store[channel];
130		zsc->zsc_cs[channel] = cs;
131
132		cs->cs_channel = channel;
133		cs->cs_private = NULL;
134		cs->cs_ops = &zsops_null;
135
136		if (channel == 0)
137			zc = &zs_addr->zs_chan_a;
138		else
139			zc = &zs_addr->zs_chan_b;
140
141		if (zc == zs_consaddr) {
142			memcpy(cs, zs_conscs, sizeof(struct zs_chanstate));
143			zs_conscs = cs;
144			zsc_args.hwflags = ZS_HWFLAG_CONSOLE;
145		} else {
146			cs->cs_reg_csr  = &zc->zc_csr;
147			cs->cs_reg_data = &zc->zc_data;
148			memcpy(cs->cs_creg, zs_init_reg, 16);
149			memcpy(cs->cs_preg, zs_init_reg, 16);
150			cs->cs_defspeed = ZS_DEFSPEED;
151			zsc_args.hwflags = 0;
152		}
153
154		zs_lock_init(cs);
155		cs->cs_brg_clk = PCLK / 16;
156		cs->cs_defcflag = zs_def_cflag;
157
158		/* Make these correspond to cs_defcflag (-crtscts) */
159		cs->cs_rr0_dcd = ZSRR0_DCD;
160		cs->cs_rr0_cts = 0;
161		cs->cs_wr5_dtr = ZSWR5_DTR | ZSWR5_RTS;
162		cs->cs_wr5_rts = 0;
163
164		/*
165		 * Clear the master interrupt enable.
166		 * The INTENA is common to both channels,
167		 * so just do it on the A channel.
168		 */
169		if (channel == 0) {
170			zs_write_reg(cs, 9, 0);
171		}
172
173		/*
174		 * Look for a child driver for this channel.
175		 * The child attach will setup the hardware.
176		 */
177		if (!config_found(self, (void *)&zsc_args, zs_print)) {
178			/* No sub-driver.  Just reset it. */
179			uint8_t reset = (channel == 0) ?
180			    ZSWR9_A_RESET : ZSWR9_B_RESET;
181			s = splhigh();
182			zs_write_reg(cs, 9, reset);
183			splx(s);
184		}
185	}
186
187	zsc->zsc_si = softint_establish(SOFTINT_SERIAL,
188	    (void (*)(void *))zsc_intr_soft, zsc);
189	intr_establish(sa->sa_irq, zshard, zsc);
190
191	/*
192	 * Set the master interrupt enable and interrupt vector.
193	 * (common to both channels, do it on A)
194	 */
195	cs = zsc->zsc_cs[0];
196	s = splhigh();
197	/* interrupt vector */
198	zs_write_reg(cs, 2, zs_init_reg[2]);
199	/* master interrupt control (enable) */
200	zs_write_reg(cs, 9, zs_init_reg[9]);
201	splx(s);
202}
203
204/*
205 * console stuff
206 */
207
208static void zs_sbdio_cnprobe(struct consdev *);
209static void zs_sbdio_cninit(struct consdev *);
210
211struct consdev consdev_zs_sbdio = {
212	zs_sbdio_cnprobe,
213	zs_sbdio_cninit,
214	zscngetc,
215	zscnputc,
216	nullcnpollc,
217	NULL,
218	NULL,
219	NULL,
220	NODEV,
221	CN_DEAD
222};
223
224static void
225zs_sbdio_cnprobe(struct consdev *cn)
226{
227
228	/* not used */
229}
230
231static void
232zs_sbdio_cninit(struct consdev *cn)
233{
234	struct zs_chanstate *cs;
235	struct zschan *zc;
236
237	zc = zs_consaddr;
238	cs = zs_conscs;
239
240	/* Setup temporary chanstate. */
241	cs->cs_reg_csr  = &zc->zc_csr;
242	cs->cs_reg_data = &zc->zc_data;
243
244	/* Initialize the pending registers. */
245	memcpy(cs->cs_preg, zs_init_reg, 16);
246	cs->cs_preg[5] |= ZSWR5_DTR | ZSWR5_RTS;
247
248	cs->cs_brg_clk = PCLK / 16;
249	cs->cs_defspeed = ZS_DEFSPEED;
250	zs_set_speed(cs, ZS_DEFSPEED);
251
252	/* Clear the master interrupt enable. */
253	zs_write_reg(cs, 9, 0);
254
255	/* Reset the whole SCC chip. */
256	zs_write_reg(cs, 9, ZSWR9_HARD_RESET);
257
258	/* Copy "pending" to "current" and H/W */
259	zs_loadchannelregs(cs);
260}
261