Home | History | Annotate | Line # | Download | only in dev
zs.c revision 1.14
      1 /*	$NetBSD: zs.c,v 1.14 2003/01/01 01:55:42 thorpej 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  * 3. All advertising materials mentioning features or use of this software
     19  *    must display the following acknowledgement:
     20  *        This product includes software developed by the NetBSD
     21  *        Foundation, Inc. and its contributors.
     22  * 4. Neither the name of The NetBSD Foundation nor the names of its
     23  *    contributors may be used to endorse or promote products derived
     24  *    from this software without specific prior written permission.
     25  *
     26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     36  * POSSIBILITY OF SUCH DAMAGE.
     37  */
     38 
     39 /*
     40  * Zilog Z8530 Dual UART driver (machine-dependent part)
     41  *
     42  * Runs two serial lines per chip using slave drivers.
     43  * Plain tty/async lines use the zs_async slave.
     44  * Sun keyboard/mouse uses the zs_kbd/zs_ms slaves.
     45  */
     46 
     47 #include "opt_ddb.h"
     48 
     49 #include <sys/param.h>
     50 #include <sys/device.h>
     51 #include <sys/tty.h>
     52 #include <sys/systm.h>
     53 
     54 #include <machine/adrsmap.h>
     55 #include <machine/cpu.h>
     56 #include <machine/z8530var.h>
     57 
     58 #include <dev/ic/z8530reg.h>
     59 
     60 #define ZS_DELAY() (*zs_delay)()
     61 
     62 int zs_print __P((void *, const char *name));
     63 int zshard __P((void *));
     64 void zssoft __P((void *));
     65 int zs_get_speed __P((struct zs_chanstate *));
     66 void Debugger __P((void));
     67 void (*zs_delay) __P((void));
     68 
     69 extern struct cfdriver zsc_cd;
     70 
     71 /*
     72  * Some warts needed by z8530tty.c -
     73  * The default parity REALLY needs to be the same as the PROM uses,
     74  * or you can not see messages done with printf during boot-up...
     75  */
     76 int zs_def_cflag = (CREAD | CS8 | HUPCL);
     77 
     78 int
     79 zs_print(aux, name)
     80 	void *aux;
     81 	const char *name;
     82 {
     83 	struct zsc_attach_args *args = aux;
     84 
     85 	if (name != NULL)
     86 		aprint_normal("%s: ", name);
     87 
     88 	if (args->channel != -1)
     89 		aprint_normal(" channel %d", args->channel);
     90 
     91 	return UNCONF;
     92 }
     93 
     94 static volatile int zssoftpending;
     95 
     96 /*
     97  * Our ZS chips all share a common, autovectored interrupt,
     98  * so we have to look at all of them on each interrupt.
     99  */
    100 int
    101 zshard(arg)
    102 	void *arg;
    103 {
    104 	register struct zsc_softc *zsc;
    105 	register int unit, rval, softreq;
    106 
    107 	rval = softreq = 0;
    108 	for (unit = 0; unit < zsc_cd.cd_ndevs; unit++) {
    109 		zsc = zsc_cd.cd_devs[unit];
    110 		if (zsc == NULL)
    111 			continue;
    112 		rval |= zsc_intr_hard(zsc);
    113 		softreq |= zsc->zsc_cs[0]->cs_softreq;
    114 		softreq |= zsc->zsc_cs[1]->cs_softreq;
    115 	}
    116 
    117 	/* We are at splzs here, so no need to lock. */
    118 	if (softreq && (zssoftpending == 0)) {
    119 		zssoftpending = 1;
    120 		setsoftserial();
    121 	}
    122 
    123 	return rval;
    124 }
    125 
    126 /*
    127  * Similar scheme as for zshard (look at all of them)
    128  */
    129 void
    130 zssoft(arg)
    131 	void *arg;
    132 {
    133 	register struct zsc_softc *zsc;
    134 	register int s, unit;
    135 
    136 	/* This is not the only ISR on this IPL. */
    137 	if (zssoftpending == 0)
    138 		return;
    139 
    140 	/*
    141 	 * The soft intr. bit will be set by zshard only if
    142 	 * the variable zssoftpending is zero.  The order of
    143 	 * these next two statements prevents our clearing
    144 	 * the soft intr bit just after zshard has set it.
    145 	 */
    146 	/* clearsoftnet(); */
    147 	zssoftpending = 0;
    148 
    149 	/* Make sure we call the tty layer at spltty. */
    150 	s = spltty();
    151 	for (unit = 0; unit < zsc_cd.cd_ndevs; unit++) {
    152 		zsc = zsc_cd.cd_devs[unit];
    153 		if (zsc == NULL)
    154 			continue;
    155 		(void)zsc_intr_soft(zsc);
    156 	}
    157 	splx(s);
    158 }
    159 
    160 /*
    161  * Compute the current baud rate given a ZS channel.
    162  */
    163 int
    164 zs_get_speed(cs)
    165 	struct zs_chanstate *cs;
    166 {
    167 	int tconst;
    168 
    169 	tconst = zs_read_reg(cs, 12);
    170 	tconst |= zs_read_reg(cs, 13) << 8;
    171 	return (TCONST_TO_BPS(cs->cs_brg_clk, tconst));
    172 }
    173 
    174 /*
    175  * MD functions for setting the baud rate and control modes.
    176  */
    177 int
    178 zs_set_speed(cs, bps)
    179 	struct zs_chanstate *cs;
    180 	int bps;	/* bits per second */
    181 {
    182 	int tconst, real_bps;
    183 
    184 	if (bps == 0)
    185 		return (0);
    186 
    187 #ifdef	DIAGNOSTIC
    188 	if (cs->cs_brg_clk == 0)
    189 		panic("zs_set_speed");
    190 #endif
    191 
    192 	tconst = BPS_TO_TCONST(cs->cs_brg_clk, bps);
    193 	if (tconst < 0)
    194 		return (EINVAL);
    195 
    196 	/* Convert back to make sure we can do it. */
    197 	real_bps = TCONST_TO_BPS(cs->cs_brg_clk, tconst);
    198 
    199 	/* XXX - Allow some tolerance here? */
    200 	if (real_bps != bps)
    201 		return (EINVAL);
    202 
    203 	cs->cs_preg[12] = tconst;
    204 	cs->cs_preg[13] = tconst >> 8;
    205 
    206 	/* Caller will stuff the pending registers. */
    207 	return (0);
    208 }
    209 
    210 int
    211 zs_set_modes(cs, cflag)
    212 	struct zs_chanstate *cs;
    213 	int cflag;	/* bits per second */
    214 {
    215 	int s;
    216 
    217 	/*
    218 	 * Output hardware flow control on the chip is horrendous:
    219 	 * if carrier detect drops, the receiver is disabled, and if
    220 	 * CTS drops, the transmitter is stoped IN MID CHARACTER!
    221 	 * Therefore, NEVER set the HFC bit, and instead use the
    222 	 * status interrupt to detect CTS changes.
    223 	 */
    224 	s = splzs();
    225 	cs->cs_rr0_pps = 0;
    226 	if ((cflag & (CLOCAL | MDMBUF)) != 0) {
    227 		cs->cs_rr0_dcd = 0;
    228 		if ((cflag & MDMBUF) == 0)
    229 			cs->cs_rr0_pps = ZSRR0_DCD;
    230 	} else
    231 		cs->cs_rr0_dcd = ZSRR0_DCD;
    232 	if ((cflag & CRTSCTS) != 0) {
    233 		cs->cs_wr5_dtr = ZSWR5_DTR;
    234 		cs->cs_wr5_rts = ZSWR5_RTS;
    235 		cs->cs_rr0_cts = ZSRR0_CTS;
    236 	} else if ((cflag & MDMBUF) != 0) {
    237 		cs->cs_wr5_dtr = 0;
    238 		cs->cs_wr5_rts = ZSWR5_DTR;
    239 		cs->cs_rr0_cts = ZSRR0_DCD;
    240 	} else {
    241 		cs->cs_wr5_dtr = ZSWR5_DTR | ZSWR5_RTS;
    242 		cs->cs_wr5_rts = 0;
    243 		cs->cs_rr0_cts = 0;
    244 	}
    245 	splx(s);
    246 
    247 	/* Caller will stuff the pending registers. */
    248 	return (0);
    249 }
    250 
    251 /*
    252  * Read or write the chip with suitable delays.
    253  */
    254 
    255 u_char
    256 zs_read_reg(cs, reg)
    257 	struct zs_chanstate *cs;
    258 	u_char reg;
    259 {
    260 	u_char val;
    261 
    262 	*cs->cs_reg_csr = reg;
    263 	ZS_DELAY();
    264 	val = *cs->cs_reg_csr;
    265 	ZS_DELAY();
    266 	return val;
    267 }
    268 
    269 void
    270 zs_write_reg(cs, reg, val)
    271 	struct zs_chanstate *cs;
    272 	u_char reg, val;
    273 {
    274 	*cs->cs_reg_csr = reg;
    275 	ZS_DELAY();
    276 	*cs->cs_reg_csr = val;
    277 	ZS_DELAY();
    278 }
    279 
    280 u_char zs_read_csr(cs)
    281 	struct zs_chanstate *cs;
    282 {
    283 	register u_char val;
    284 
    285 	val = *cs->cs_reg_csr;
    286 	ZS_DELAY();
    287 	return val;
    288 }
    289 
    290 void  zs_write_csr(cs, val)
    291 	struct zs_chanstate *cs;
    292 	u_char val;
    293 {
    294 	*cs->cs_reg_csr = val;
    295 	ZS_DELAY();
    296 }
    297 
    298 u_char zs_read_data(cs)
    299 	struct zs_chanstate *cs;
    300 {
    301 	register u_char val;
    302 
    303 	val = *cs->cs_reg_data;
    304 	ZS_DELAY();
    305 	return val;
    306 }
    307 
    308 void  zs_write_data(cs, val)
    309 	struct zs_chanstate *cs;
    310 	u_char val;
    311 {
    312 	*cs->cs_reg_data = val;
    313 	ZS_DELAY();
    314 }
    315 
    316 void
    317 zs_abort(cs)
    318 	struct zs_chanstate *cs;
    319 {
    320 #ifdef DDB
    321 	Debugger();
    322 #endif
    323 }
    324