zs_sbdio.c revision 1.9 1 1.9 tsutsui /* $NetBSD: zs_sbdio.c,v 1.9 2008/03/29 19:15:34 tsutsui Exp $ */
2 1.1 tsutsui
3 1.1 tsutsui /*-
4 1.1 tsutsui * Copyright (c) 1996, 2005 The NetBSD Foundation, Inc.
5 1.1 tsutsui * All rights reserved.
6 1.1 tsutsui *
7 1.1 tsutsui * This code is derived from software contributed to The NetBSD Foundation
8 1.1 tsutsui * by Gordon W. Ross.
9 1.1 tsutsui *
10 1.1 tsutsui * Redistribution and use in source and binary forms, with or without
11 1.1 tsutsui * modification, are permitted provided that the following conditions
12 1.1 tsutsui * are met:
13 1.1 tsutsui * 1. Redistributions of source code must retain the above copyright
14 1.1 tsutsui * notice, this list of conditions and the following disclaimer.
15 1.1 tsutsui * 2. Redistributions in binary form must reproduce the above copyright
16 1.1 tsutsui * notice, this list of conditions and the following disclaimer in the
17 1.1 tsutsui * documentation and/or other materials provided with the distribution.
18 1.1 tsutsui * 3. All advertising materials mentioning features or use of this software
19 1.1 tsutsui * must display the following acknowledgement:
20 1.1 tsutsui * This product includes software developed by the NetBSD
21 1.1 tsutsui * Foundation, Inc. and its contributors.
22 1.1 tsutsui * 4. Neither the name of The NetBSD Foundation nor the names of its
23 1.1 tsutsui * contributors may be used to endorse or promote products derived
24 1.1 tsutsui * from this software without specific prior written permission.
25 1.1 tsutsui *
26 1.1 tsutsui * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 1.1 tsutsui * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 1.1 tsutsui * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 1.1 tsutsui * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 1.1 tsutsui * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 1.1 tsutsui * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 1.1 tsutsui * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 1.1 tsutsui * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 1.1 tsutsui * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 1.1 tsutsui * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 1.1 tsutsui * POSSIBILITY OF SUCH DAMAGE.
37 1.1 tsutsui */
38 1.1 tsutsui
39 1.1 tsutsui /*
40 1.1 tsutsui * Zilog Z8530 Dual UART driver (machine-dependent part)
41 1.1 tsutsui *
42 1.1 tsutsui * Runs two serial lines per chip using slave drivers.
43 1.1 tsutsui * Plain tty/async lines use the zs_async slave.
44 1.1 tsutsui */
45 1.1 tsutsui
46 1.1 tsutsui #include <sys/cdefs.h>
47 1.9 tsutsui __KERNEL_RCSID(0, "$NetBSD: zs_sbdio.c,v 1.9 2008/03/29 19:15:34 tsutsui Exp $");
48 1.1 tsutsui
49 1.1 tsutsui #include <sys/param.h>
50 1.1 tsutsui #include <sys/systm.h>
51 1.1 tsutsui #include <sys/device.h>
52 1.1 tsutsui #include <sys/tty.h>
53 1.1 tsutsui #include <sys/conf.h>
54 1.7 ad #include <sys/intr.h>
55 1.1 tsutsui
56 1.1 tsutsui #include <dev/cons.h>
57 1.1 tsutsui #include <dev/ic/z8530reg.h>
58 1.1 tsutsui
59 1.1 tsutsui #include <machine/sbdiovar.h>
60 1.1 tsutsui #include <machine/z8530var.h>
61 1.1 tsutsui
62 1.1 tsutsui #define ZS_DEFSPEED 9600
63 1.1 tsutsui #define PCLK (9600 * 512) /* 4.915200MHz */
64 1.1 tsutsui
65 1.1 tsutsui /* The layout of this is hardware-dependent (padding, order). */
66 1.1 tsutsui struct zschan {
67 1.1 tsutsui volatile uint8_t zc_csr; /* ctrl, status, and indirect access */
68 1.1 tsutsui uint8_t padding1[3];
69 1.1 tsutsui volatile uint8_t zc_data; /* data */
70 1.1 tsutsui uint8_t padding2[3];
71 1.1 tsutsui } __attribute__((__packed__));
72 1.1 tsutsui
73 1.1 tsutsui struct zsdevice {
74 1.1 tsutsui /* Yes, they are backwards. */
75 1.1 tsutsui struct zschan zs_chan_b;
76 1.1 tsutsui struct zschan zs_chan_a;
77 1.1 tsutsui } __attribute__((__packed__));
78 1.1 tsutsui
79 1.1 tsutsui static uint8_t zs_init_reg[16] = {
80 1.1 tsutsui 0, /* 0: CMD (reset, etc.) */
81 1.1 tsutsui 0, /* 1: No interrupts yet. */
82 1.1 tsutsui 0, /* 2: IVECT EWS-UX don't set this. */
83 1.1 tsutsui ZSWR3_RX_8 | ZSWR3_RX_ENABLE,
84 1.1 tsutsui ZSWR4_CLK_X16 | ZSWR4_ONESB | ZSWR4_EVENP,
85 1.1 tsutsui ZSWR5_TX_8 | ZSWR5_TX_ENABLE,
86 1.1 tsutsui 0, /* 6: TXSYNC/SYNCLO */
87 1.1 tsutsui 0, /* 7: RXSYNC/SYNCHI */
88 1.1 tsutsui 0, /* 8: alias for data port */
89 1.1 tsutsui ZSWR9_MASTER_IE,
90 1.1 tsutsui 0, /* 10: Misc. TX/RX control bits */
91 1.1 tsutsui ZSWR11_TXCLK_BAUD | ZSWR11_RXCLK_BAUD,
92 1.1 tsutsui BPS_TO_TCONST((PCLK/16), ZS_DEFSPEED), /* 12: BAUDLO (default=9600) */
93 1.1 tsutsui 0, /*13: BAUDHI (default=9600) */
94 1.1 tsutsui ZSWR14_BAUD_ENA | ZSWR14_BAUD_FROM_PCLK,
95 1.1 tsutsui ZSWR15_BREAK_IE,
96 1.1 tsutsui };
97 1.1 tsutsui
98 1.8 tsutsui static int zs_sbdio_match(device_t, cfdata_t, void *);
99 1.8 tsutsui static void zs_sbdio_attach(device_t, device_t, void *);
100 1.1 tsutsui
101 1.9 tsutsui CFATTACH_DECL_NEW(zsc_sbdio, sizeof(struct zsc_softc),
102 1.1 tsutsui zs_sbdio_match, zs_sbdio_attach, NULL, NULL);
103 1.1 tsutsui
104 1.1 tsutsui int
105 1.8 tsutsui zs_sbdio_match(device_t parent, cfdata_t cf, void *aux)
106 1.1 tsutsui {
107 1.1 tsutsui struct sbdio_attach_args *sa = aux;
108 1.1 tsutsui
109 1.1 tsutsui return strcmp(sa->sa_name, "zsc") ? 0 : 1;
110 1.1 tsutsui }
111 1.1 tsutsui
112 1.1 tsutsui void
113 1.8 tsutsui zs_sbdio_attach(device_t parent, device_t self, void *aux)
114 1.1 tsutsui {
115 1.9 tsutsui struct zsc_softc *zsc = device_private(self);
116 1.1 tsutsui struct sbdio_attach_args *sa = aux;
117 1.1 tsutsui struct zsc_attach_args zsc_args;
118 1.1 tsutsui struct zschan *zc;
119 1.1 tsutsui struct zs_chanstate *cs;
120 1.1 tsutsui struct zsdevice *zs_addr;
121 1.1 tsutsui int s, zs_unit, channel;
122 1.1 tsutsui
123 1.9 tsutsui zsc->zsc_dev = self;
124 1.8 tsutsui aprint_normal("\n");
125 1.1 tsutsui
126 1.8 tsutsui zs_unit = device_unit(self);
127 1.1 tsutsui zs_addr = (void *)MIPS_PHYS_TO_KSEG1(sa->sa_addr1);
128 1.1 tsutsui zsc->zsc_flags = sa->sa_flags;
129 1.1 tsutsui
130 1.1 tsutsui /*
131 1.1 tsutsui * Initialize software state for each channel.
132 1.1 tsutsui */
133 1.1 tsutsui for (channel = 0; channel < 2; channel++) {
134 1.1 tsutsui zsc_args.channel = channel;
135 1.1 tsutsui zsc_args.hwflags = 0;
136 1.1 tsutsui cs = &zsc->zsc_cs_store[channel];
137 1.1 tsutsui zsc->zsc_cs[channel] = cs;
138 1.1 tsutsui
139 1.1 tsutsui cs->cs_channel = channel;
140 1.1 tsutsui cs->cs_private = NULL;
141 1.1 tsutsui cs->cs_ops = &zsops_null;
142 1.1 tsutsui
143 1.1 tsutsui if (channel == 0)
144 1.1 tsutsui zc = &zs_addr->zs_chan_a;
145 1.1 tsutsui else
146 1.1 tsutsui zc = &zs_addr->zs_chan_b;
147 1.1 tsutsui
148 1.1 tsutsui if (zc == zs_consaddr) {
149 1.1 tsutsui memcpy(cs, zs_conscs, sizeof(struct zs_chanstate));
150 1.1 tsutsui zs_conscs = cs;
151 1.1 tsutsui zsc_args.hwflags = ZS_HWFLAG_CONSOLE;
152 1.1 tsutsui } else {
153 1.1 tsutsui cs->cs_reg_csr = &zc->zc_csr;
154 1.1 tsutsui cs->cs_reg_data = &zc->zc_data;
155 1.1 tsutsui memcpy(cs->cs_creg, zs_init_reg, 16);
156 1.1 tsutsui memcpy(cs->cs_preg, zs_init_reg, 16);
157 1.1 tsutsui cs->cs_defspeed = ZS_DEFSPEED;
158 1.1 tsutsui zsc_args.hwflags = 0;
159 1.1 tsutsui }
160 1.1 tsutsui
161 1.6 ad zs_lock_init(cs);
162 1.1 tsutsui cs->cs_brg_clk = PCLK / 16;
163 1.1 tsutsui cs->cs_defcflag = zs_def_cflag;
164 1.1 tsutsui
165 1.1 tsutsui /* Make these correspond to cs_defcflag (-crtscts) */
166 1.1 tsutsui cs->cs_rr0_dcd = ZSRR0_DCD;
167 1.1 tsutsui cs->cs_rr0_cts = 0;
168 1.1 tsutsui cs->cs_wr5_dtr = ZSWR5_DTR | ZSWR5_RTS;
169 1.1 tsutsui cs->cs_wr5_rts = 0;
170 1.1 tsutsui
171 1.1 tsutsui /*
172 1.1 tsutsui * Clear the master interrupt enable.
173 1.1 tsutsui * The INTENA is common to both channels,
174 1.1 tsutsui * so just do it on the A channel.
175 1.1 tsutsui */
176 1.1 tsutsui if (channel == 0) {
177 1.1 tsutsui zs_write_reg(cs, 9, 0);
178 1.1 tsutsui }
179 1.1 tsutsui
180 1.1 tsutsui /*
181 1.1 tsutsui * Look for a child driver for this channel.
182 1.1 tsutsui * The child attach will setup the hardware.
183 1.1 tsutsui */
184 1.1 tsutsui if (!config_found(self, (void *)&zsc_args, zs_print)) {
185 1.1 tsutsui /* No sub-driver. Just reset it. */
186 1.1 tsutsui uint8_t reset = (channel == 0) ?
187 1.1 tsutsui ZSWR9_A_RESET : ZSWR9_B_RESET;
188 1.1 tsutsui s = splhigh();
189 1.1 tsutsui zs_write_reg(cs, 9, reset);
190 1.1 tsutsui splx(s);
191 1.1 tsutsui }
192 1.1 tsutsui }
193 1.1 tsutsui
194 1.7 ad zsc->zsc_si = softint_establish(SOFTINT_SERIAL,
195 1.3 tsutsui (void (*)(void *))zsc_intr_soft, zsc);
196 1.3 tsutsui intr_establish(sa->sa_irq, zshard, zsc);
197 1.1 tsutsui
198 1.1 tsutsui /*
199 1.1 tsutsui * Set the master interrupt enable and interrupt vector.
200 1.1 tsutsui * (common to both channels, do it on A)
201 1.1 tsutsui */
202 1.1 tsutsui cs = zsc->zsc_cs[0];
203 1.1 tsutsui s = splhigh();
204 1.1 tsutsui /* interrupt vector */
205 1.1 tsutsui zs_write_reg(cs, 2, zs_init_reg[2]);
206 1.1 tsutsui /* master interrupt control (enable) */
207 1.1 tsutsui zs_write_reg(cs, 9, zs_init_reg[9]);
208 1.1 tsutsui splx(s);
209 1.1 tsutsui }
210 1.1 tsutsui
211 1.1 tsutsui /*
212 1.1 tsutsui * console stuff
213 1.1 tsutsui */
214 1.1 tsutsui
215 1.1 tsutsui static void zs_sbdio_cnprobe(struct consdev *);
216 1.1 tsutsui static void zs_sbdio_cninit(struct consdev *);
217 1.1 tsutsui
218 1.1 tsutsui struct consdev consdev_zs_sbdio = {
219 1.1 tsutsui zs_sbdio_cnprobe,
220 1.1 tsutsui zs_sbdio_cninit,
221 1.1 tsutsui zscngetc,
222 1.1 tsutsui zscnputc,
223 1.1 tsutsui nullcnpollc,
224 1.1 tsutsui NULL,
225 1.1 tsutsui NULL,
226 1.1 tsutsui NULL,
227 1.1 tsutsui NODEV,
228 1.1 tsutsui CN_DEAD
229 1.1 tsutsui };
230 1.1 tsutsui
231 1.1 tsutsui static void
232 1.1 tsutsui zs_sbdio_cnprobe(struct consdev *cn)
233 1.1 tsutsui {
234 1.1 tsutsui
235 1.1 tsutsui /* not used */
236 1.1 tsutsui }
237 1.1 tsutsui
238 1.1 tsutsui static void
239 1.1 tsutsui zs_sbdio_cninit(struct consdev *cn)
240 1.1 tsutsui {
241 1.1 tsutsui struct zs_chanstate *cs;
242 1.1 tsutsui struct zschan *zc;
243 1.1 tsutsui
244 1.1 tsutsui zc = zs_consaddr;
245 1.1 tsutsui cs = zs_conscs;
246 1.1 tsutsui
247 1.1 tsutsui /* Setup temporary chanstate. */
248 1.1 tsutsui cs->cs_reg_csr = &zc->zc_csr;
249 1.1 tsutsui cs->cs_reg_data = &zc->zc_data;
250 1.1 tsutsui
251 1.1 tsutsui /* Initialize the pending registers. */
252 1.1 tsutsui memcpy(cs->cs_preg, zs_init_reg, 16);
253 1.1 tsutsui cs->cs_preg[5] |= ZSWR5_DTR | ZSWR5_RTS;
254 1.1 tsutsui
255 1.1 tsutsui cs->cs_brg_clk = PCLK / 16;
256 1.1 tsutsui cs->cs_defspeed = ZS_DEFSPEED;
257 1.1 tsutsui zs_set_speed(cs, ZS_DEFSPEED);
258 1.1 tsutsui
259 1.1 tsutsui /* Clear the master interrupt enable. */
260 1.1 tsutsui zs_write_reg(cs, 9, 0);
261 1.1 tsutsui
262 1.1 tsutsui /* Reset the whole SCC chip. */
263 1.1 tsutsui zs_write_reg(cs, 9, ZSWR9_HARD_RESET);
264 1.1 tsutsui
265 1.1 tsutsui /* Copy "pending" to "current" and H/W */
266 1.1 tsutsui zs_loadchannelregs(cs);
267 1.1 tsutsui }
268