1*207defd0Sandvar /* $NetBSD: zs.c,v 1.6 2021/09/11 20:28:03 andvar Exp $ */
204faabf0Stsutsui
304faabf0Stsutsui /*-
404faabf0Stsutsui * Copyright (c) 1996, 2005 The NetBSD Foundation, Inc.
504faabf0Stsutsui * All rights reserved.
604faabf0Stsutsui *
704faabf0Stsutsui * This code is derived from software contributed to The NetBSD Foundation
804faabf0Stsutsui * by Gordon W. Ross.
904faabf0Stsutsui *
1004faabf0Stsutsui * Redistribution and use in source and binary forms, with or without
1104faabf0Stsutsui * modification, are permitted provided that the following conditions
1204faabf0Stsutsui * are met:
1304faabf0Stsutsui * 1. Redistributions of source code must retain the above copyright
1404faabf0Stsutsui * notice, this list of conditions and the following disclaimer.
1504faabf0Stsutsui * 2. Redistributions in binary form must reproduce the above copyright
1604faabf0Stsutsui * notice, this list of conditions and the following disclaimer in the
1704faabf0Stsutsui * documentation and/or other materials provided with the distribution.
1804faabf0Stsutsui *
1904faabf0Stsutsui * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
2004faabf0Stsutsui * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
2104faabf0Stsutsui * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2204faabf0Stsutsui * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
2304faabf0Stsutsui * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2404faabf0Stsutsui * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2504faabf0Stsutsui * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2604faabf0Stsutsui * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2704faabf0Stsutsui * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2804faabf0Stsutsui * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2904faabf0Stsutsui * POSSIBILITY OF SUCH DAMAGE.
3004faabf0Stsutsui */
3104faabf0Stsutsui
3204faabf0Stsutsui /*
3304faabf0Stsutsui * Zilog Z8530 Dual UART driver (machine-dependent part)
3404faabf0Stsutsui *
3504faabf0Stsutsui * Runs two serial lines per chip using slave drivers.
3604faabf0Stsutsui * Plain tty/async lines use the zs_async slave.
3704faabf0Stsutsui */
3804faabf0Stsutsui
3904faabf0Stsutsui #include <sys/cdefs.h>
40*207defd0Sandvar __KERNEL_RCSID(0, "$NetBSD: zs.c,v 1.6 2021/09/11 20:28:03 andvar Exp $");
4104faabf0Stsutsui
4204faabf0Stsutsui #include "opt_ddb.h"
4304faabf0Stsutsui
4404faabf0Stsutsui #include <sys/param.h>
4504faabf0Stsutsui #include <sys/device.h>
4604faabf0Stsutsui #include <sys/tty.h>
4704faabf0Stsutsui #include <sys/systm.h>
4834db2867Sad #include <sys/intr.h>
4904faabf0Stsutsui
5004faabf0Stsutsui #include <machine/z8530var.h>
5104faabf0Stsutsui #include <dev/ic/z8530reg.h>
5204faabf0Stsutsui
5304faabf0Stsutsui #include "ioconf.h"
5404faabf0Stsutsui
5504faabf0Stsutsui /* console status for consinit() */
5604faabf0Stsutsui static struct zs_chanstate zs_conscs_store;
5704faabf0Stsutsui struct zs_chanstate *zs_conscs = &zs_conscs_store;
5804faabf0Stsutsui void *zs_consaddr;
5904faabf0Stsutsui
6004faabf0Stsutsui /*
6104faabf0Stsutsui * Some warts needed by z8530tty.c -
6204faabf0Stsutsui * The default parity REALLY needs to be the same as the PROM uses,
6304faabf0Stsutsui * or you can not see messages done with printf during boot-up...
6404faabf0Stsutsui */
6504faabf0Stsutsui int zs_def_cflag = (CREAD | CS8 | HUPCL);
6604faabf0Stsutsui
6704faabf0Stsutsui int
zs_print(void * aux,const char * name)6804faabf0Stsutsui zs_print(void *aux, const char *name)
6904faabf0Stsutsui {
7004faabf0Stsutsui struct zsc_attach_args *args = aux;
7104faabf0Stsutsui
7204faabf0Stsutsui if (name != NULL)
7304faabf0Stsutsui aprint_normal("%s: ", name);
7404faabf0Stsutsui
7504faabf0Stsutsui if (args->channel != -1)
7604faabf0Stsutsui aprint_normal(" channel %d", args->channel);
7704faabf0Stsutsui
7804faabf0Stsutsui return UNCONF;
7904faabf0Stsutsui }
8004faabf0Stsutsui
8104faabf0Stsutsui int
zshard(void * arg)8204faabf0Stsutsui zshard(void *arg)
8304faabf0Stsutsui {
8404faabf0Stsutsui struct zsc_softc *zsc;
8557a0051fStsutsui int rval;
8604faabf0Stsutsui
8757a0051fStsutsui zsc = arg;
8857a0051fStsutsui rval = zsc_intr_hard(zsc);
8957a0051fStsutsui if (zsc->zsc_cs[0]->cs_softreq || zsc->zsc_cs[1]->cs_softreq)
9034db2867Sad softint_schedule(zsc->zsc_si);
9104faabf0Stsutsui
9204faabf0Stsutsui return rval;
9304faabf0Stsutsui }
9404faabf0Stsutsui
9504faabf0Stsutsui /*
9604faabf0Stsutsui * Compute the current baud rate given a ZS channel.
9704faabf0Stsutsui */
9804faabf0Stsutsui int
zs_get_speed(struct zs_chanstate * cs)9904faabf0Stsutsui zs_get_speed(struct zs_chanstate *cs)
10004faabf0Stsutsui {
10104faabf0Stsutsui int tconst;
10204faabf0Stsutsui
10304faabf0Stsutsui tconst = zs_read_reg(cs, 12);
10404faabf0Stsutsui tconst |= zs_read_reg(cs, 13) << 8;
10504faabf0Stsutsui return TCONST_TO_BPS(cs->cs_brg_clk, tconst);
10604faabf0Stsutsui }
10704faabf0Stsutsui
10804faabf0Stsutsui /*
10904faabf0Stsutsui * MD functions for setting the baud rate and control modes.
11004faabf0Stsutsui */
11104faabf0Stsutsui int
zs_set_speed(struct zs_chanstate * cs,int bps)11204faabf0Stsutsui zs_set_speed(struct zs_chanstate *cs, int bps)
11304faabf0Stsutsui {
11404faabf0Stsutsui int tconst, real_bps;
11504faabf0Stsutsui
11604faabf0Stsutsui if (bps == 0)
11704faabf0Stsutsui return 0;
11804faabf0Stsutsui
11904faabf0Stsutsui #ifdef DIAGNOSTIC
12004faabf0Stsutsui if (cs->cs_brg_clk == 0)
12104faabf0Stsutsui panic("zs_set_speed");
12204faabf0Stsutsui #endif
12304faabf0Stsutsui
12404faabf0Stsutsui tconst = BPS_TO_TCONST(cs->cs_brg_clk, bps);
12504faabf0Stsutsui if (tconst < 0)
12604faabf0Stsutsui return EINVAL;
12704faabf0Stsutsui
12804faabf0Stsutsui /* Convert back to make sure we can do it. */
12904faabf0Stsutsui real_bps = TCONST_TO_BPS(cs->cs_brg_clk, tconst);
13004faabf0Stsutsui
13104faabf0Stsutsui /* XXX - Allow some tolerance here? */
13204faabf0Stsutsui if (real_bps != bps)
13304faabf0Stsutsui return EINVAL;
13404faabf0Stsutsui
13504faabf0Stsutsui cs->cs_preg[12] = tconst;
13604faabf0Stsutsui cs->cs_preg[13] = tconst >> 8;
13704faabf0Stsutsui
13804faabf0Stsutsui /* Caller will stuff the pending registers. */
13904faabf0Stsutsui return 0;
14004faabf0Stsutsui }
14104faabf0Stsutsui
14204faabf0Stsutsui int
zs_set_modes(struct zs_chanstate * cs,int cflag)14304faabf0Stsutsui zs_set_modes(struct zs_chanstate *cs, int cflag)
14404faabf0Stsutsui {
14504faabf0Stsutsui int s;
14604faabf0Stsutsui
14704faabf0Stsutsui /*
14804faabf0Stsutsui * Output hardware flow control on the chip is horrendous:
14904faabf0Stsutsui * if carrier detect drops, the receiver is disabled, and if
150*207defd0Sandvar * CTS drops, the transmitter is stopped IN MID CHARACTER!
15104faabf0Stsutsui * Therefore, NEVER set the HFC bit, and instead use the
15204faabf0Stsutsui * status interrupt to detect CTS changes.
15304faabf0Stsutsui */
15404faabf0Stsutsui s = splserial();
15504faabf0Stsutsui cs->cs_rr0_pps = 0;
15604faabf0Stsutsui if ((cflag & (CLOCAL | MDMBUF)) != 0) {
15704faabf0Stsutsui cs->cs_rr0_dcd = 0;
15804faabf0Stsutsui if ((cflag & MDMBUF) == 0)
15904faabf0Stsutsui cs->cs_rr0_pps = ZSRR0_DCD;
16004faabf0Stsutsui } else
16104faabf0Stsutsui cs->cs_rr0_dcd = ZSRR0_DCD;
16204faabf0Stsutsui if ((cflag & CRTSCTS) != 0) {
16304faabf0Stsutsui cs->cs_wr5_dtr = ZSWR5_DTR;
16404faabf0Stsutsui cs->cs_wr5_rts = ZSWR5_RTS;
16504faabf0Stsutsui cs->cs_rr0_cts = ZSRR0_CTS;
16604faabf0Stsutsui } else if ((cflag & MDMBUF) != 0) {
16704faabf0Stsutsui cs->cs_wr5_dtr = 0;
16804faabf0Stsutsui cs->cs_wr5_rts = ZSWR5_DTR;
16904faabf0Stsutsui cs->cs_rr0_cts = ZSRR0_DCD;
17004faabf0Stsutsui } else {
17104faabf0Stsutsui cs->cs_wr5_dtr = ZSWR5_DTR | ZSWR5_RTS;
17204faabf0Stsutsui cs->cs_wr5_rts = 0;
17304faabf0Stsutsui cs->cs_rr0_cts = 0;
17404faabf0Stsutsui }
17504faabf0Stsutsui splx(s);
17604faabf0Stsutsui
17704faabf0Stsutsui /* Caller will stuff the pending registers. */
17804faabf0Stsutsui return 0;
17904faabf0Stsutsui }
18004faabf0Stsutsui
18104faabf0Stsutsui /*
18204faabf0Stsutsui * Read or write the chip with suitable delays.
18304faabf0Stsutsui */
18404faabf0Stsutsui uint8_t
zs_read_reg(struct zs_chanstate * cs,uint8_t reg)18504faabf0Stsutsui zs_read_reg(struct zs_chanstate *cs, uint8_t reg)
18604faabf0Stsutsui {
18704faabf0Stsutsui uint8_t val;
18804faabf0Stsutsui
18904faabf0Stsutsui *cs->cs_reg_csr = reg;
19004faabf0Stsutsui
19104faabf0Stsutsui val = *cs->cs_reg_csr;
19204faabf0Stsutsui
19304faabf0Stsutsui return val;
19404faabf0Stsutsui }
19504faabf0Stsutsui
19604faabf0Stsutsui void
zs_write_reg(struct zs_chanstate * cs,uint8_t reg,uint8_t val)19704faabf0Stsutsui zs_write_reg(struct zs_chanstate *cs, uint8_t reg, uint8_t val)
19804faabf0Stsutsui {
19904faabf0Stsutsui
20004faabf0Stsutsui *cs->cs_reg_csr = reg;
20104faabf0Stsutsui
20204faabf0Stsutsui *cs->cs_reg_csr = val;
20304faabf0Stsutsui
20404faabf0Stsutsui }
20504faabf0Stsutsui
20604faabf0Stsutsui uint8_t
zs_read_csr(struct zs_chanstate * cs)20704faabf0Stsutsui zs_read_csr(struct zs_chanstate *cs)
20804faabf0Stsutsui {
20904faabf0Stsutsui uint8_t val;
21004faabf0Stsutsui
21104faabf0Stsutsui val = *cs->cs_reg_csr;
21204faabf0Stsutsui
21304faabf0Stsutsui return val;
21404faabf0Stsutsui }
21504faabf0Stsutsui
21604faabf0Stsutsui void
zs_write_csr(struct zs_chanstate * cs,uint8_t val)21704faabf0Stsutsui zs_write_csr(struct zs_chanstate *cs, uint8_t val)
21804faabf0Stsutsui {
21904faabf0Stsutsui
22004faabf0Stsutsui *cs->cs_reg_csr = val;
22104faabf0Stsutsui
22204faabf0Stsutsui }
22304faabf0Stsutsui
22404faabf0Stsutsui uint8_t
zs_read_data(struct zs_chanstate * cs)22504faabf0Stsutsui zs_read_data(struct zs_chanstate *cs)
22604faabf0Stsutsui {
22704faabf0Stsutsui uint8_t val;
22804faabf0Stsutsui
22904faabf0Stsutsui val = *cs->cs_reg_data;
23004faabf0Stsutsui
23104faabf0Stsutsui return val;
23204faabf0Stsutsui }
23304faabf0Stsutsui
23404faabf0Stsutsui void
zs_write_data(struct zs_chanstate * cs,uint8_t val)23504faabf0Stsutsui zs_write_data(struct zs_chanstate *cs, uint8_t val)
23604faabf0Stsutsui {
23704faabf0Stsutsui
23804faabf0Stsutsui *cs->cs_reg_data = val;
23904faabf0Stsutsui }
24004faabf0Stsutsui
24104faabf0Stsutsui void
zs_abort(struct zs_chanstate * cs)24204faabf0Stsutsui zs_abort(struct zs_chanstate *cs)
24304faabf0Stsutsui {
24404faabf0Stsutsui
24504faabf0Stsutsui #ifdef DDB
24604faabf0Stsutsui Debugger();
24704faabf0Stsutsui #endif
24804faabf0Stsutsui }
24904faabf0Stsutsui
25004faabf0Stsutsui /*
25104faabf0Stsutsui * Polled input char.
25204faabf0Stsutsui */
25304faabf0Stsutsui int
zs_getc(void * arg)25404faabf0Stsutsui zs_getc(void *arg)
25504faabf0Stsutsui {
25604faabf0Stsutsui struct zs_chanstate *cs = arg;
25702cb47caStsutsui int s, c;
25802cb47caStsutsui uint8_t rr0;
25904faabf0Stsutsui
26004faabf0Stsutsui s = splhigh();
26104faabf0Stsutsui /* Wait for a character to arrive. */
26204faabf0Stsutsui do {
26304faabf0Stsutsui rr0 = *cs->cs_reg_csr;
26404faabf0Stsutsui ZS_DELAY();
26504faabf0Stsutsui } while ((rr0 & ZSRR0_RX_READY) == 0);
26604faabf0Stsutsui
26704faabf0Stsutsui c = *cs->cs_reg_data;
26804faabf0Stsutsui ZS_DELAY();
26904faabf0Stsutsui splx(s);
27004faabf0Stsutsui
27104faabf0Stsutsui /*
27204faabf0Stsutsui * This could be used by the kd driver to read scan codes,
27304faabf0Stsutsui * so don't translate '\r' ==> '\n' here...
27404faabf0Stsutsui */
27504faabf0Stsutsui return c;
27604faabf0Stsutsui }
27704faabf0Stsutsui
27804faabf0Stsutsui /*
27904faabf0Stsutsui * Polled output char.
28004faabf0Stsutsui */
28104faabf0Stsutsui void
zs_putc(void * arg,int c)28204faabf0Stsutsui zs_putc(void *arg, int c)
28304faabf0Stsutsui {
28404faabf0Stsutsui struct zs_chanstate *cs = arg;
28502cb47caStsutsui int s;
28602cb47caStsutsui uint8_t rr0;
28704faabf0Stsutsui
28804faabf0Stsutsui s = splhigh();
28904faabf0Stsutsui /* Wait for transmitter to become ready. */
29004faabf0Stsutsui do {
29104faabf0Stsutsui rr0 = *cs->cs_reg_csr;
29204faabf0Stsutsui ZS_DELAY();
29304faabf0Stsutsui } while ((rr0 & ZSRR0_TX_READY) == 0);
29404faabf0Stsutsui
29504faabf0Stsutsui *cs->cs_reg_data = c;
29604faabf0Stsutsui ZS_DELAY();
29704faabf0Stsutsui splx(s);
29804faabf0Stsutsui }
29904faabf0Stsutsui
30004faabf0Stsutsui int
zscngetc(dev_t dev)30104faabf0Stsutsui zscngetc(dev_t dev)
30204faabf0Stsutsui {
30304faabf0Stsutsui
30404faabf0Stsutsui return zs_getc((void *)zs_conscs);
30504faabf0Stsutsui }
30604faabf0Stsutsui
30704faabf0Stsutsui void
zscnputc(dev_t dev,int c)30804faabf0Stsutsui zscnputc(dev_t dev, int c)
30904faabf0Stsutsui {
31004faabf0Stsutsui
31104faabf0Stsutsui zs_putc((void *)zs_conscs, c);
31204faabf0Stsutsui }
313