1 /* $NetBSD: zs_sbdio.c,v 1.9 2008/03/29 19:15:34 tsutsui Exp $ */
4 * Copyright (c) 1996, 2005 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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.
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.
33 * Zilog Z8530 Dual UART driver (machine-dependent part)
35 * Runs two serial lines per chip using slave drivers.
36 * Plain tty/async lines use the zs_async slave.
39 #include <sys/cdefs.h>
40 __KERNEL_RCSID(0, "$NetBSD: zs_sbdio.c,v 1.9 2008/03/29 19:15:34 tsutsui Exp $");
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/device.h>
50 #include <dev/ic/z8530reg.h>
52 #include <machine/sbdiovar.h>
53 #include <machine/z8530var.h>
55 #define ZS_DEFSPEED 9600
56 #define PCLK (9600 * 512) /* 4.915200MHz */
58 /* The layout of this is hardware-dependent (padding, order). */
60 volatile uint8_t zc_csr
; /* ctrl, status, and indirect access */
62 volatile uint8_t zc_data
; /* data */
64 } __attribute__((__packed__
));
67 /* Yes, they are backwards. */
68 struct zschan zs_chan_b
;
69 struct zschan zs_chan_a
;
70 } __attribute__((__packed__
));
72 static 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 */
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
,
91 static int zs_sbdio_match(device_t
, cfdata_t
, void *);
92 static void zs_sbdio_attach(device_t
, device_t
, void *);
94 CFATTACH_DECL_NEW(zsc_sbdio
, sizeof(struct zsc_softc
),
95 zs_sbdio_match
, zs_sbdio_attach
, NULL
, NULL
);
98 zs_sbdio_match(device_t parent
, cfdata_t cf
, void *aux
)
100 struct sbdio_attach_args
*sa
= aux
;
102 return strcmp(sa
->sa_name
, "zsc") ? 0 : 1;
106 zs_sbdio_attach(device_t parent
, device_t self
, void *aux
)
108 struct zsc_softc
*zsc
= device_private(self
);
109 struct sbdio_attach_args
*sa
= aux
;
110 struct zsc_attach_args zsc_args
;
112 struct zs_chanstate
*cs
;
113 struct zsdevice
*zs_addr
;
114 int s
, zs_unit
, channel
;
119 zs_unit
= device_unit(self
);
120 zs_addr
= (void *)MIPS_PHYS_TO_KSEG1(sa
->sa_addr1
);
121 zsc
->zsc_flags
= sa
->sa_flags
;
124 * Initialize software state for each channel.
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
;
132 cs
->cs_channel
= channel
;
133 cs
->cs_private
= NULL
;
134 cs
->cs_ops
= &zsops_null
;
137 zc
= &zs_addr
->zs_chan_a
;
139 zc
= &zs_addr
->zs_chan_b
;
141 if (zc
== zs_consaddr
) {
142 memcpy(cs
, zs_conscs
, sizeof(struct zs_chanstate
));
144 zsc_args
.hwflags
= ZS_HWFLAG_CONSOLE
;
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;
155 cs
->cs_brg_clk
= PCLK
/ 16;
156 cs
->cs_defcflag
= zs_def_cflag
;
158 /* Make these correspond to cs_defcflag (-crtscts) */
159 cs
->cs_rr0_dcd
= ZSRR0_DCD
;
161 cs
->cs_wr5_dtr
= ZSWR5_DTR
| ZSWR5_RTS
;
165 * Clear the master interrupt enable.
166 * The INTENA is common to both channels,
167 * so just do it on the A channel.
170 zs_write_reg(cs
, 9, 0);
174 * Look for a child driver for this channel.
175 * The child attach will setup the hardware.
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
;
182 zs_write_reg(cs
, 9, reset
);
187 zsc
->zsc_si
= softint_establish(SOFTINT_SERIAL
,
188 (void (*)(void *))zsc_intr_soft
, zsc
);
189 intr_establish(sa
->sa_irq
, zshard
, zsc
);
192 * Set the master interrupt enable and interrupt vector.
193 * (common to both channels, do it on A)
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]);
208 static void zs_sbdio_cnprobe(struct consdev
*);
209 static void zs_sbdio_cninit(struct consdev
*);
211 struct consdev consdev_zs_sbdio
= {
225 zs_sbdio_cnprobe(struct consdev
*cn
)
232 zs_sbdio_cninit(struct consdev
*cn
)
234 struct zs_chanstate
*cs
;
240 /* Setup temporary chanstate. */
241 cs
->cs_reg_csr
= &zc
->zc_csr
;
242 cs
->cs_reg_data
= &zc
->zc_data
;
244 /* Initialize the pending registers. */
245 memcpy(cs
->cs_preg
, zs_init_reg
, 16);
246 cs
->cs_preg
[5] |= ZSWR5_DTR
| ZSWR5_RTS
;
248 cs
->cs_brg_clk
= PCLK
/ 16;
249 cs
->cs_defspeed
= ZS_DEFSPEED
;
250 zs_set_speed(cs
, ZS_DEFSPEED
);
252 /* Clear the master interrupt enable. */
253 zs_write_reg(cs
, 9, 0);
255 /* Reset the whole SCC chip. */
256 zs_write_reg(cs
, 9, ZSWR9_HARD_RESET
);
258 /* Copy "pending" to "current" and H/W */
259 zs_loadchannelregs(cs
);