On Sun, Jul 01, 2018 at 04:38:35PM +0200, Mark Kettenis wrote:
> Since the ARM SBSA Generic UART is effectively a PL011 UART, the
> expectation is that most arm64 servers will actually have pluart(4) as
> their serial console instead of com(4). So we need a glue for
> acpi(4). This provides that glue and moves the shared code from
> dev/fdt to dev/ic.
>
> ok?
>
ok mlarkin.
> P.S. This driver needs some cleanup. But that should be done separately.
>
Yeah, you're not kidding there...
>
> Index: conf/files
> ===================================================================
> RCS file: /cvs/src/sys/conf/files,v
> retrieving revision 1.661
> diff -u -p -r1.661 files
> --- conf/files 20 Apr 2018 04:37:21 -0000 1.661
> +++ conf/files 1 Jul 2018 14:29:40 -0000
> @@ -324,6 +324,10 @@ device com: tty
> file dev/ic/com.c com & (com | com_cardbus | com_gsc |
> com_isapnp) needs-flag
>
> +# ARM PrimeCell PL011 UART
> +device pluart: tty
> +file dev/ic/pluart.c pluart
> +
> # PC-like keyboard controller
> define pckbcslot {[slot = -1]}
> device pckbc: pckbcslot
> Index: dev/acpi/files.acpi
> ===================================================================
> RCS file: /cvs/src/sys/dev/acpi/files.acpi,v
> retrieving revision 1.45
> diff -u -p -r1.45 files.acpi
> --- dev/acpi/files.acpi 1 Jul 2018 10:29:30 -0000 1.45
> +++ dev/acpi/files.acpi 1 Jul 2018 14:29:40 -0000
> @@ -137,9 +137,17 @@ device ccpmic
> attach ccpmic at i2c
> file dev/acpi/ccpmic.c ccpmic
>
> # NS16550 compatible UART
> attach com at acpi with com_acpi
> file dev/acpi/com_acpi.c com_acpi
> +
> +# PL011 UART
> +attach pluart at acpi with pluart_acpi
> +file dev/acpi/pluart_acpi.c pluart_acpi
>
> # SD Host Controller
> attach sdhc at acpi with sdhc_acpi
> Index: dev/acpi/pluart_acpi.c
> ===================================================================
> RCS file: dev/acpi/pluart_acpi.c
> diff -N dev/acpi/pluart_acpi.c
> --- /dev/null 1 Jan 1970 00:00:00 -0000
> +++ dev/acpi/pluart_acpi.c 1 Jul 2018 14:29:40 -0000
> @@ -0,0 +1,153 @@
> +/* $OpenBSD$ */
> +/*
> + * Copyright (c) 2018 Mark Kettenis
> + *
> + * Permission to use, copy, modify, and distribute this software for any
> + * purpose with or without fee is hereby granted, provided that the above
> + * copyright notice and this permission notice appear in all copies.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
> + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
> + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
> + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
> + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
> + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
> + */
> +
> +#include <sys/param.h>
> +#include <sys/malloc.h>
> +#include <sys/systm.h>
> +#include <sys/tty.h>
> +
> +#include <dev/acpi/acpireg.h>
> +#include <dev/acpi/acpivar.h>
> +#include <dev/acpi/acpidev.h>
> +#include <dev/acpi/amltypes.h>
> +#include <dev/acpi/dsdt.h>
> +
> +#undef DEVNAME
> +#include <dev/fdt/pluartvar.h>
> +#include <dev/cons.h>
> +
> +struct pluart_acpi_softc {
> + struct pluart_softc sc;
> + struct acpi_softc *sc_acpi;
> + struct aml_node *sc_node;
> +
> + bus_addr_t sc_addr;
> + bus_size_t sc_size;
> +
> + int sc_irq;
> + int sc_irq_flags;
> + void *sc_ih;
> +};
> +
> +int pluart_acpi_match(struct device *, void *, void *);
> +void pluart_acpi_attach(struct device *, struct device *, void *);
> +
> +struct cfattach pluart_acpi_ca = {
> + sizeof(struct pluart_acpi_softc), pluart_acpi_match, pluart_acpi_attach
> +};
> +
> +const char *pluart_hids[] = {
> + "AMDI0511",
> + NULL
> +};
> +
> +int pluart_acpi_parse_resources(int, union acpi_resource *, void *);
> +int pluart_acpi_is_console(struct pluart_acpi_softc *);
> +
> +int
> +pluart_acpi_match(struct device *parent, void *match, void *aux)
> +{
> + struct acpi_attach_args *aaa = aux;
> + struct cfdata *cf = match;
> +
> + return acpi_matchhids(aaa, pluart_hids, cf->cf_driver->cd_name);
> +}
> +
> +void
> +pluart_acpi_attach(struct device *parent, struct device *self, void *aux)
> +{
> + struct acpi_attach_args *aaa = aux;
> + struct pluart_acpi_softc *sc = (struct pluart_acpi_softc *)self;
> + struct aml_value res;
> +
> + sc->sc_acpi = (struct acpi_softc *)parent;
> + sc->sc_node = aaa->aaa_node;
> + printf(" %s", sc->sc_node->name);
> +
> + if (aml_evalname(sc->sc_acpi, sc->sc_node, "_CRS", 0, NULL, &res)) {
> + printf(": can't find registers\n");
> + return;
> + }
> +
> + aml_parse_resource(&res, pluart_acpi_parse_resources, sc);
> + printf(" addr 0x%lx/0x%lx", sc->sc_addr, sc->sc_size);
> + if (sc->sc_addr == 0 || sc->sc_size == 0) {
> + printf("\n");
> + return;
> + }
> +
> + printf(" irq %d", sc->sc_irq);
> +
> + sc->sc.sc_iot = aaa->aaa_memt;
> + if (bus_space_map(sc->sc.sc_iot, sc->sc_addr, sc->sc_size, 0,
> + &sc->sc.sc_ioh)) {
> + printf(": can't map registers\n");
> + return;
> + }
> +
> + sc->sc_ih = acpi_intr_establish(sc->sc_irq, sc->sc_irq_flags, IPL_TTY,
> + pluart_intr, sc, sc->sc.sc_dev.dv_xname);
> + if (sc->sc_ih == NULL) {
> + printf(": can't establish interrupt\n");
> + return;
> + }
> +
> + pluart_attach_common(&sc->sc, pluart_acpi_is_console(sc));
> +}
> +
> +int
> +pluart_acpi_parse_resources(int crsidx, union acpi_resource *crs, void *arg)
> +{
> + struct pluart_acpi_softc *sc = arg;
> + int type = AML_CRSTYPE(crs);
> +
> + switch (type) {
> + case LR_MEM32FIXED:
> + sc->sc_addr = crs->lr_m32fixed._bas;
> + sc->sc_size = crs->lr_m32fixed._len;
> + break;
> + case LR_EXTIRQ:
> + sc->sc_irq = crs->lr_extirq.irq[0];
> + sc->sc_irq_flags = crs->lr_extirq.flags;
> + break;
> + }
> +
> + return 0;
> +}
> +
> +int
> +pluart_acpi_is_console(struct pluart_acpi_softc *sc)
> +{
> + struct acpi_table_header *hdr;
> + struct acpi_spcr *spcr;
> + struct acpi_gas *base;
> + struct acpi_q *entry;
> +
> + SIMPLEQ_FOREACH(entry, &sc->sc_acpi->sc_tables, q_next) {
> + hdr = entry->q_table;
> + if (strncmp(hdr->signature, SPCR_SIG,
> + sizeof(hdr->signature)) == 0) {
> + spcr = entry->q_table;
> + base = &spcr->base_address;
> + if (base->address_space_id == GAS_SYSTEM_MEMORY &&
> + base->address == sc->sc_addr)
> + return 1;
> + }
> + }
> +
> + return 0;
> +}
> Index: dev/fdt/files.fdt
> ===================================================================
> RCS file: /cvs/src/sys/dev/fdt/files.fdt,v
> retrieving revision 1.64
> diff -u -p -r1.64 files.fdt
> --- dev/fdt/files.fdt 16 Jun 2018 14:11:35 -0000 1.64
> +++ dev/fdt/files.fdt 1 Jul 2018 14:29:40 -0000
> @@ -79,9 +79,8 @@ attach plrtc at fdt
> file dev/fdt/plrtc.c plrtc
>
> # ARM PrimeCell PL011 UART
> -device pluart
> -attach pluart at fdt
> -file dev/fdt/pluart.c pluart
> +attach pluart at fdt with pluart_fdt
> +file dev/fdt/pluart_fdt.c pluart_fdt
>
> # ARM Power State Coordination Interface
> device psci
> Index: dev/fdt/pluart.c
> ===================================================================
> RCS file: dev/fdt/pluart.c
> diff -N dev/fdt/pluart.c
> --- dev/fdt/pluart.c 5 Jun 2018 20:41:19 -0000 1.1
> +++ /dev/null 1 Jan 1970 00:00:00 -0000
> @@ -1,912 +0,0 @@
> -/* $OpenBSD: pluart.c,v 1.1 2018/06/05 20:41:19 kettenis Exp $ */
> -
> -/*
> - * Copyright (c) 2014 Patrick Wildt <[email protected]>
> - * Copyright (c) 2005 Dale Rahn <[email protected]>
> - *
> - * Permission to use, copy, modify, and distribute this software for any
> - * purpose with or without fee is hereby granted, provided that the above
> - * copyright notice and this permission notice appear in all copies.
> - *
> - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
> - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
> - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
> - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
> - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
> - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
> - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
> - */
> -
> -#include <sys/param.h>
> -#include <sys/ioctl.h>
> -#include <sys/proc.h>
> -#include <sys/tty.h>
> -#include <sys/uio.h>
> -#include <sys/systm.h>
> -#include <sys/time.h>
> -#include <sys/device.h>
> -#include <sys/syslog.h>
> -#include <sys/conf.h>
> -#include <sys/fcntl.h>
> -#include <sys/select.h>
> -#include <sys/kernel.h>
> -
> -#include <machine/bus.h>
> -#include <machine/fdt.h>
> -
> -#include <dev/cons.h>
> -
> -#ifdef DDB
> -#include <ddb/db_var.h>
> -#endif
> -
> -#include <dev/ofw/fdt.h>
> -#include <dev/ofw/openfirm.h>
> -
> -#define DEVUNIT(x) (minor(x) & 0x7f)
> -#define DEVCUA(x) (minor(x) & 0x80)
> -
> -#define UART_DR 0x00 /* Data register */
> -#define UART_DR_DATA(x) ((x) & 0xf)
> -#define UART_DR_FE (1 << 8) /* Framing error */
> -#define UART_DR_PE (1 << 9) /* Parity error */
> -#define UART_DR_BE (1 << 10) /* Break error */
> -#define UART_DR_OE (1 << 11) /* Overrun error */
> -#define UART_RSR 0x04 /* Receive status register */
> -#define UART_RSR_FE (1 << 0) /* Framing error */
> -#define UART_RSR_PE (1 << 1) /* Parity error */
> -#define UART_RSR_BE (1 << 2) /* Break error */
> -#define UART_RSR_OE (1 << 3) /* Overrun error */
> -#define UART_ECR 0x04 /* Error clear register */
> -#define UART_ECR_FE (1 << 0) /* Framing error */
> -#define UART_ECR_PE (1 << 1) /* Parity error */
> -#define UART_ECR_BE (1 << 2) /* Break error */
> -#define UART_ECR_OE (1 << 3) /* Overrun error */
> -#define UART_FR 0x18 /* Flag register */
> -#define UART_FR_CTS (1 << 0) /* Clear to send */
> -#define UART_FR_DSR (1 << 1) /* Data set ready */
> -#define UART_FR_DCD (1 << 2) /* Data carrier detect */
> -#define UART_FR_BUSY (1 << 3) /* UART busy */
> -#define UART_FR_RXFE (1 << 4) /* Receive FIFO empty */
> -#define UART_FR_TXFF (1 << 5) /* Transmit FIFO full */
> -#define UART_FR_RXFF (1 << 6) /* Receive FIFO full */
> -#define UART_FR_TXFE (1 << 7) /* Transmit FIFO empty */
> -#define UART_FR_RI (1 << 8) /* Ring indicator */
> -#define UART_ILPR 0x20 /* IrDA low-power counter
> register */
> -#define UART_ILPR_ILPDVSR ((x) & 0xf) /* IrDA low-power divisor */
> -#define UART_IBRD 0x24 /* Integer baud rate register */
> -#define UART_IBRD_DIVINT ((x) & 0xff) /* Integer baud rate divisor */
> -#define UART_FBRD 0x28 /* Fractional baud rate
> register */
> -#define UART_FBRD_DIVFRAC ((x) & 0x3f) /* Fractional baud rate divisor
> */
> -#define UART_LCR_H 0x2c /* Line control register */
> -#define UART_LCR_H_BRK (1 << 0) /* Send break */
> -#define UART_LCR_H_PEN (1 << 1) /* Parity enable */
> -#define UART_LCR_H_EPS (1 << 2) /* Even parity select */
> -#define UART_LCR_H_STP2 (1 << 3) /* Two stop bits select
> */
> -#define UART_LCR_H_FEN (1 << 4) /* Enable FIFOs */
> -#define UART_LCR_H_WLEN5 (0x0 << 5) /* Word length: 5 bits */
> -#define UART_LCR_H_WLEN6 (0x1 << 5) /* Word length: 6 bits */
> -#define UART_LCR_H_WLEN7 (0x2 << 5) /* Word length: 7 bits */
> -#define UART_LCR_H_WLEN8 (0x3 << 5) /* Word length: 8 bits */
> -#define UART_LCR_H_SPS (1 << 7) /* Stick parity select
> */
> -#define UART_CR 0x30 /* Control register */
> -#define UART_CR_UARTEN (1 << 0) /* UART enable */
> -#define UART_CR_SIREN (1 << 1) /* SIR enable */
> -#define UART_CR_SIRLP (1 << 2) /* IrDA SIR low power
> mode */
> -#define UART_CR_LBE (1 << 7) /* Loop back enable */
> -#define UART_CR_TXE (1 << 8) /* Transmit enable */
> -#define UART_CR_RXE (1 << 9) /* Receive enable */
> -#define UART_CR_DTR (1 << 10) /* Data transmit enable */
> -#define UART_CR_RTS (1 << 11) /* Request to send */
> -#define UART_CR_OUT1 (1 << 12)
> -#define UART_CR_OUT2 (1 << 13)
> -#define UART_CR_CTSE (1 << 14) /* CTS hardware flow control
> enable */
> -#define UART_CR_RTSE (1 << 15) /* RTS hardware flow control
> enable */
> -#define UART_IFLS 0x34 /* Interrupt FIFO level select
> register */
> -#define UART_IMSC 0x38 /* Interrupt mask set/clear
> register */
> -#define UART_IMSC_RIMIM (1 << 0)
> -#define UART_IMSC_CTSMIM (1 << 1)
> -#define UART_IMSC_DCDMIM (1 << 2)
> -#define UART_IMSC_DSRMIM (1 << 3)
> -#define UART_IMSC_RXIM (1 << 4)
> -#define UART_IMSC_TXIM (1 << 5)
> -#define UART_IMSC_RTIM (1 << 6)
> -#define UART_IMSC_FEIM (1 << 7)
> -#define UART_IMSC_PEIM (1 << 8)
> -#define UART_IMSC_BEIM (1 << 9)
> -#define UART_IMSC_OEIM (1 << 10)
> -#define UART_RIS 0x3c /* Raw interrupt status
> register */
> -#define UART_MIS 0x40 /* Masked interrupt status
> register */
> -#define UART_ICR 0x44 /* Interrupt clear register */
> -#define UART_DMACR 0x48 /* DMA control register */
> -#define UART_SPACE 0x100
> -
> -struct pluart_softc {
> - struct device sc_dev;
> - bus_space_tag_t sc_iot;
> - bus_space_handle_t sc_ioh;
> - struct soft_intrhand *sc_si;
> - void *sc_irq;
> - struct tty *sc_tty;
> - struct timeout sc_diag_tmo;
> - struct timeout sc_dtr_tmo;
> - int sc_overflows;
> - int sc_floods;
> - int sc_errors;
> - int sc_halt;
> - u_int16_t sc_ucr1;
> - u_int16_t sc_ucr2;
> - u_int16_t sc_ucr3;
> - u_int16_t sc_ucr4;
> - u_int8_t sc_hwflags;
> -#define COM_HW_NOIEN 0x01
> -#define COM_HW_FIFO 0x02
> -#define COM_HW_SIR 0x20
> -#define COM_HW_CONSOLE 0x40
> - u_int8_t sc_swflags;
> -#define COM_SW_SOFTCAR 0x01
> -#define COM_SW_CLOCAL 0x02
> -#define COM_SW_CRTSCTS 0x04
> -#define COM_SW_MDMBUF 0x08
> -#define COM_SW_PPS 0x10
> - int sc_fifolen;
> -
> - u_int8_t sc_initialize;
> - u_int8_t sc_cua;
> - u_int16_t *sc_ibuf, *sc_ibufp, *sc_ibufhigh, *sc_ibufend;
> -#define UART_IBUFSIZE 128
> -#define UART_IHIGHWATER 100
> - u_int16_t sc_ibufs[2][UART_IBUFSIZE];
> -
> - struct clk *sc_clk;
> -};
> -
> -int pluartprobe(struct device *parent, void *self, void *aux);
> -void pluartattach(struct device *parent, struct device *self, void *aux);
> -
> -void pluartcnprobe(struct consdev *cp);
> -void pluartcninit(struct consdev *cp);
> -int pluartcnattach(bus_space_tag_t iot, bus_addr_t iobase, int rate,
> - tcflag_t cflag);
> -int pluartcngetc(dev_t dev);
> -void pluartcnputc(dev_t dev, int c);
> -void pluartcnpollc(dev_t dev, int on);
> -int pluart_param(struct tty *tp, struct termios *t);
> -void pluart_start(struct tty *);
> -void pluart_pwroff(struct pluart_softc *sc);
> -void pluart_diag(void *arg);
> -void pluart_raisedtr(void *arg);
> -void pluart_softint(void *arg);
> -struct pluart_softc *pluart_sc(dev_t dev);
> -
> -int pluart_intr(void *);
> -
> -/* XXX - we imitate 'com' serial ports and take over their entry points */
> -/* XXX: These belong elsewhere */
> -cdev_decl(com);
> -cdev_decl(pluart);
> -
> -struct cfdriver pluart_cd = {
> - NULL, "pluart", DV_TTY
> -};
> -
> -struct cfattach pluart_ca = {
> - sizeof(struct pluart_softc), pluartprobe, pluartattach
> -};
> -
> -bus_space_tag_t pluartconsiot;
> -bus_space_handle_t pluartconsioh;
> -bus_addr_t pluartconsaddr;
> -tcflag_t pluartconscflag = TTYDEF_CFLAG;
> -int pluartdefaultrate = B38400;
> -
> -void
> -pluart_init_cons(void)
> -{
> - struct fdt_reg reg;
> - void *node;
> -
> - if ((node = fdt_find_cons("arm,pl011")) == NULL)
> - return;
> - if (fdt_get_reg(node, 0, ®))
> - return;
> -
> - pluartcnattach(fdt_cons_bs_tag, reg.addr, B115200, TTYDEF_CFLAG);
> -}
> -
> -int
> -pluartprobe(struct device *parent, void *self, void *aux)
> -{
> - struct fdt_attach_args *faa = aux;
> -
> - return OF_is_compatible(faa->fa_node, "arm,pl011");
> -}
> -
> -struct cdevsw pluartdev =
> - cdev_tty_init(3/*XXX NUART */ ,pluart); /* 12: serial port */
> -
> -void
> -pluartattach(struct device *parent, struct device *self, void *aux)
> -{
> - struct fdt_attach_args *faa = aux;
> - struct pluart_softc *sc = (struct pluart_softc *) self;
> - int maj;
> -
> - if (faa->fa_nreg < 1) {
> - printf(": no register data\n");
> - return;
> - }
> -
> - sc->sc_irq = arm_intr_establish_fdt(faa->fa_node, IPL_TTY, pluart_intr,
> - sc, sc->sc_dev.dv_xname);
> -
> - sc->sc_iot = faa->fa_iot;
> - if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, faa->fa_reg[0].size,
> - 0, &sc->sc_ioh))
> - panic("pluartattach: bus_space_map failed!");
> -
> - if (stdout_node == faa->fa_node) {
> - /* Locate the major number. */
> - for (maj = 0; maj < nchrdev; maj++)
> - if (cdevsw[maj].d_open == pluartopen)
> - break;
> - cn_tab->cn_dev = makedev(maj, sc->sc_dev.dv_unit);
> -
> - printf(": console");
> - SET(sc->sc_hwflags, COM_HW_CONSOLE);
> - }
> -
> - timeout_set(&sc->sc_diag_tmo, pluart_diag, sc);
> - timeout_set(&sc->sc_dtr_tmo, pluart_raisedtr, sc);
> - sc->sc_si = softintr_establish(IPL_TTY, pluart_softint, sc);
> -
> - if(sc->sc_si == NULL)
> - panic("%s: can't establish soft interrupt.",
> - sc->sc_dev.dv_xname);
> -
> - bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_IMSC, (UART_IMSC_RXIM |
> UART_IMSC_TXIM));
> - bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_ICR, 0x7ff);
> - bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_LCR_H,
> - bus_space_read_4(sc->sc_iot, sc->sc_ioh, UART_LCR_H) &
> - ~UART_LCR_H_FEN);
> -
> - printf("\n");
> -}
> -
> -int
> -pluart_intr(void *arg)
> -{
> - struct pluart_softc *sc = arg;
> - bus_space_tag_t iot = sc->sc_iot;
> - bus_space_handle_t ioh = sc->sc_ioh;
> - struct tty *tp = sc->sc_tty;
> - u_int16_t fr;
> - u_int16_t *p;
> - u_int16_t c;
> -
> - bus_space_write_4(iot, ioh, UART_ICR, -1);
> -
> - if (sc->sc_tty == NULL)
> - return(0);
> -
> - fr = bus_space_read_4(iot, ioh, UART_FR);
> - if (ISSET(fr, UART_FR_TXFE) && ISSET(tp->t_state, TS_BUSY)) {
> - CLR(tp->t_state, TS_BUSY | TS_FLUSH);
> - if (sc->sc_halt > 0)
> - wakeup(&tp->t_outq);
> - (*linesw[tp->t_line].l_start)(tp);
> - }
> -
> - if(!ISSET(bus_space_read_4(iot, ioh, UART_FR), UART_FR_RXFF))
> - return 0;
> -
> - p = sc->sc_ibufp;
> -
> - while (ISSET(bus_space_read_4(iot, ioh, UART_FR), UART_FR_RXFF)) {
> - c = bus_space_read_2(iot, ioh, UART_DR);
> - if (c & UART_DR_BE) {
> -#ifdef DDB
> - if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) {
> - if (db_console)
> - db_enter();
> - continue;
> - }
> -#endif
> - c = 0;
> - }
> - if (p >= sc->sc_ibufend) {
> - sc->sc_floods++;
> - if (sc->sc_errors++ == 0)
> - timeout_add(&sc->sc_diag_tmo, 60 * hz);
> - } else {
> - *p++ = c;
> - if (p == sc->sc_ibufhigh && ISSET(tp->t_cflag,
> CRTSCTS)) {
> - /* XXX */
> - //CLR(sc->sc_ucr3, IMXUART_CR3_DSR);
> - //bus_space_write_4(iot, ioh, IMXUART_UCR3,
> - // sc->sc_ucr3);
> - }
> - }
> - /* XXX - msr stuff ? */
> - }
> - sc->sc_ibufp = p;
> -
> - softintr_schedule(sc->sc_si);
> -
> - return 1;
> -}
> -
> -int
> -pluart_param(struct tty *tp, struct termios *t)
> -{
> - struct pluart_softc *sc = pluart_cd.cd_devs[DEVUNIT(tp->t_dev)];
> - //bus_space_tag_t iot = sc->sc_iot;
> - //bus_space_handle_t ioh = sc->sc_ioh;
> - int ospeed = t->c_ospeed;
> - int error;
> - tcflag_t oldcflag;
> -
> -
> - if (t->c_ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
> - return EINVAL;
> -
> - switch (ISSET(t->c_cflag, CSIZE)) {
> - case CS5:
> - return EINVAL;
> - case CS6:
> - return EINVAL;
> - case CS7:
> - //CLR(sc->sc_ucr2, IMXUART_CR2_WS);
> - break;
> - case CS8:
> - //SET(sc->sc_ucr2, IMXUART_CR2_WS);
> - break;
> - }
> -// bus_space_write_4(iot, ioh, IMXUART_UCR2, sc->sc_ucr2);
> -
> - /*
> - if (ISSET(t->c_cflag, PARENB)) {
> - SET(sc->sc_ucr2, IMXUART_CR2_PREN);
> - bus_space_write_4(iot, ioh, IMXUART_UCR2, sc->sc_ucr2);
> - }
> - */
> - /* STOPB - XXX */
> - if (ospeed == 0) {
> - /* lower dtr */
> - }
> -
> - if (ospeed != 0) {
> - while (ISSET(tp->t_state, TS_BUSY)) {
> - ++sc->sc_halt;
> - error = ttysleep(tp, &tp->t_outq,
> - TTOPRI | PCATCH, "pluartprm", 0);
> - --sc->sc_halt;
> - if (error) {
> - pluart_start(tp);
> - return (error);
> - }
> - }
> - /* set speed */
> - }
> -
> - /* setup fifo */
> -
> - /* When not using CRTSCTS, RTS follows DTR. */
> - /* sc->sc_dtr = MCR_DTR; */
> -
> -
> - /* and copy to tty */
> - tp->t_ispeed = t->c_ispeed;
> - tp->t_ospeed = t->c_ospeed;
> - oldcflag = tp->t_cflag;
> - tp->t_cflag = t->c_cflag;
> -
> - /*
> - * If DCD is off and MDMBUF is changed, ask the tty layer if we should
> - * stop the device.
> - */
> - /* XXX */
> -
> - pluart_start(tp);
> -
> - return 0;
> -}
> -
> -void
> -pluart_start(struct tty *tp)
> -{
> - struct pluart_softc *sc = pluart_cd.cd_devs[DEVUNIT(tp->t_dev)];
> - bus_space_tag_t iot = sc->sc_iot;
> - bus_space_handle_t ioh = sc->sc_ioh;
> -
> - int s;
> - s = spltty();
> - if (ISSET(tp->t_state, TS_BUSY | TS_TIMEOUT | TS_TTSTOP))
> - goto out;
> - if (tp->t_outq.c_cc <= tp->t_lowat) {
> - if (ISSET(tp->t_state, TS_ASLEEP)) {
> - CLR(tp->t_state, TS_ASLEEP);
> - wakeup(&tp->t_outq);
> - }
> - if (tp->t_outq.c_cc == 0)
> - goto out;
> - selwakeup(&tp->t_wsel);
> - }
> - SET(tp->t_state, TS_BUSY);
> -
> - if (ISSET(sc->sc_hwflags, COM_HW_FIFO)) {
> - u_char buffer[64]; /* largest fifo */
> - int i, n;
> -
> - n = q_to_b(&tp->t_outq, buffer,
> - min(sc->sc_fifolen, sizeof buffer));
> - for (i = 0; i < n; i++) {
> - bus_space_write_4(iot, ioh, UART_DR, buffer[i]);
> - }
> - bzero(buffer, n);
> - } else if (tp->t_outq.c_cc != 0)
> - bus_space_write_4(iot, ioh, UART_DR, getc(&tp->t_outq));
> -
> -out:
> - splx(s);
> -}
> -
> -void
> -pluart_pwroff(struct pluart_softc *sc)
> -{
> -}
> -
> -void
> -pluart_diag(void *arg)
> -{
> - struct pluart_softc *sc = arg;
> - int overflows, floods;
> - int s;
> -
> - s = spltty();
> - sc->sc_errors = 0;
> - overflows = sc->sc_overflows;
> - sc->sc_overflows = 0;
> - floods = sc->sc_floods;
> - sc->sc_floods = 0;
> - splx(s);
> - log(LOG_WARNING, "%s: %d silo overflow%s, %d ibuf overflow%s\n",
> - sc->sc_dev.dv_xname,
> - overflows, overflows == 1 ? "" : "s",
> - floods, floods == 1 ? "" : "s");
> -}
> -
> -void
> -pluart_raisedtr(void *arg)
> -{
> - //struct pluart_softc *sc = arg;
> -
> - //SET(sc->sc_ucr3, IMXUART_CR3_DSR); /* XXX */
> - //bus_space_write_4(sc->sc_iot, sc->sc_ioh, IMXUART_UCR3, sc->sc_ucr3);
> -}
> -
> -void
> -pluart_softint(void *arg)
> -{
> - struct pluart_softc *sc = arg;
> - struct tty *tp;
> - u_int16_t *ibufp;
> - u_int16_t *ibufend;
> - int c;
> - int err;
> - int s;
> -
> - if (sc == NULL || sc->sc_ibufp == sc->sc_ibuf)
> - return;
> -
> - tp = sc->sc_tty;
> - s = spltty();
> -
> - ibufp = sc->sc_ibuf;
> - ibufend = sc->sc_ibufp;
> -
> - if (ibufp == ibufend || tp == NULL || !ISSET(tp->t_state, TS_ISOPEN)) {
> - splx(s);
> - return;
> - }
> -
> - sc->sc_ibufp = sc->sc_ibuf = (ibufp == sc->sc_ibufs[0]) ?
> - sc->sc_ibufs[1] : sc->sc_ibufs[0];
> - sc->sc_ibufhigh = sc->sc_ibuf + UART_IHIGHWATER;
> - sc->sc_ibufend = sc->sc_ibuf + UART_IBUFSIZE;
> -
> -#if 0
> - if (ISSET(tp->t_cflag, CRTSCTS) &&
> - !ISSET(sc->sc_ucr3, IMXUART_CR3_DSR)) {
> - /* XXX */
> - SET(sc->sc_ucr3, IMXUART_CR3_DSR);
> - bus_space_write_4(sc->sc_iot, sc->sc_ioh, IMXUART_UCR3,
> - sc->sc_ucr3);
> - }
> -#endif
> -
> - splx(s);
> -
> - while (ibufp < ibufend) {
> - c = *ibufp++;
> - /*
> - if (ISSET(c, IMXUART_RX_OVERRUN)) {
> - sc->sc_overflows++;
> - if (sc->sc_errors++ == 0)
> - timeout_add(&sc->sc_diag_tmo, 60 * hz);
> - }
> - */
> - /* This is ugly, but fast. */
> -
> - err = 0;
> - /*
> - if (ISSET(c, IMXUART_RX_PRERR))
> - err |= TTY_PE;
> - if (ISSET(c, IMXUART_RX_FRMERR))
> - err |= TTY_FE;
> - */
> - c = (c & 0xff) | err;
> - (*linesw[tp->t_line].l_rint)(c, tp);
> - }
> -}
> -
> -int
> -pluartopen(dev_t dev, int flag, int mode, struct proc *p)
> -{
> - int unit = DEVUNIT(dev);
> - struct pluart_softc *sc;
> - bus_space_tag_t iot;
> - bus_space_handle_t ioh;
> - struct tty *tp;
> - int s;
> - int error = 0;
> -
> - if (unit >= pluart_cd.cd_ndevs)
> - return ENXIO;
> - sc = pluart_cd.cd_devs[unit];
> - if (sc == NULL)
> - return ENXIO;
> -
> - s = spltty();
> - if (sc->sc_tty == NULL)
> - tp = sc->sc_tty = ttymalloc(0);
> - else
> - tp = sc->sc_tty;
> -
> - splx(s);
> -
> - tp->t_oproc = pluart_start;
> - tp->t_param = pluart_param;
> - tp->t_dev = dev;
> -
> - if (!ISSET(tp->t_state, TS_ISOPEN)) {
> - SET(tp->t_state, TS_WOPEN);
> - ttychars(tp);
> - tp->t_iflag = TTYDEF_IFLAG;
> - tp->t_oflag = TTYDEF_OFLAG;
> -
> - if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE))
> - tp->t_cflag = pluartconscflag;
> - else
> - tp->t_cflag = TTYDEF_CFLAG;
> - if (ISSET(sc->sc_swflags, COM_SW_CLOCAL))
> - SET(tp->t_cflag, CLOCAL);
> - if (ISSET(sc->sc_swflags, COM_SW_CRTSCTS))
> - SET(tp->t_cflag, CRTSCTS);
> - if (ISSET(sc->sc_swflags, COM_SW_MDMBUF))
> - SET(tp->t_cflag, MDMBUF);
> - tp->t_lflag = TTYDEF_LFLAG;
> - tp->t_ispeed = tp->t_ospeed = pluartdefaultrate;
> -
> - s = spltty();
> -
> - sc->sc_initialize = 1;
> - pluart_param(tp, &tp->t_termios);
> - ttsetwater(tp);
> - sc->sc_ibufp = sc->sc_ibuf = sc->sc_ibufs[0];
> - sc->sc_ibufhigh = sc->sc_ibuf + UART_IHIGHWATER;
> - sc->sc_ibufend = sc->sc_ibuf + UART_IBUFSIZE;
> -
> - iot = sc->sc_iot;
> - ioh = sc->sc_ioh;
> -
> -#if 0
> - sc->sc_ucr1 = bus_space_read_4(iot, ioh, IMXUART_UCR1);
> - sc->sc_ucr2 = bus_space_read_4(iot, ioh, IMXUART_UCR2);
> - sc->sc_ucr3 = bus_space_read_4(iot, ioh, IMXUART_UCR3);
> - sc->sc_ucr4 = bus_space_read_4(iot, ioh, IMXUART_UCR4);
> -
> - /* interrupt after one char on tx/rx */
> - /* reference frequency divider: 1 */
> - bus_space_write_4(iot, ioh, IMXUART_UFCR,
> - 1 << IMXUART_FCR_TXTL_SH |
> - 5 << IMXUART_FCR_RFDIV_SH |
> - 1 << IMXUART_FCR_RXTL_SH);
> -
> - bus_space_write_4(iot, ioh, IMXUART_UBIR,
> - (pluartdefaultrate / 100) - 1);
> -
> - /* formula: clk / (rfdiv * 1600) */
> - bus_space_write_4(iot, ioh, IMXUART_UBMR,
> - (clk_get_rate(sc->sc_clk) * 1000) / 1600);
> -
> - SET(sc->sc_ucr1, IMXUART_CR1_EN|IMXUART_CR1_RRDYEN);
> - SET(sc->sc_ucr2, IMXUART_CR2_TXEN|IMXUART_CR2_RXEN);
> - bus_space_write_4(iot, ioh, IMXUART_UCR1, sc->sc_ucr1);
> - bus_space_write_4(iot, ioh, IMXUART_UCR2, sc->sc_ucr2);
> -
> - /* sc->sc_mcr = MCR_DTR | MCR_RTS; XXX */
> - SET(sc->sc_ucr3, IMXUART_CR3_DSR); /* XXX */
> - bus_space_write_4(iot, ioh, IMXUART_UCR3, sc->sc_ucr3);
> -#endif
> -
> - SET(tp->t_state, TS_CARR_ON); /* XXX */
> -
> -
> - } else if (ISSET(tp->t_state, TS_XCLUDE) && p->p_ucred->cr_uid != 0)
> - return EBUSY;
> - else
> - s = spltty();
> -
> - if (DEVCUA(dev)) {
> - if (ISSET(tp->t_state, TS_ISOPEN)) {
> - splx(s);
> - return EBUSY;
> - }
> - sc->sc_cua = 1;
> - } else {
> - /* tty (not cua) device; wait for carrier if necessary */
> - if (ISSET(flag, O_NONBLOCK)) {
> - if (sc->sc_cua) {
> - /* Opening TTY non-blocking... but the CUA is
> busy */
> - splx(s);
> - return EBUSY;
> - }
> - } else {
> - while (sc->sc_cua ||
> - (!ISSET(tp->t_cflag, CLOCAL) &&
> - !ISSET(tp->t_state, TS_CARR_ON))) {
> - SET(tp->t_state, TS_WOPEN);
> - error = ttysleep(tp, &tp->t_rawq,
> - TTIPRI | PCATCH, ttopen, 0);
> - /*
> - * If TS_WOPEN has been reset, that means the
> - * cua device has been closed. We don't want
> - * to fail in that case,
> - * so just go around again.
> - */
> - if (error && ISSET(tp->t_state, TS_WOPEN)) {
> - CLR(tp->t_state, TS_WOPEN);
> - if (!sc->sc_cua && !ISSET(tp->t_state,
> - TS_ISOPEN))
> - pluart_pwroff(sc);
> - splx(s);
> - return error;
> - }
> - }
> - }
> - }
> - splx(s);
> - return (*linesw[tp->t_line].l_open)(dev,tp,p);
> -}
> -
> -int
> -pluartclose(dev_t dev, int flag, int mode, struct proc *p)
> -{
> - int unit = DEVUNIT(dev);
> - struct pluart_softc *sc = pluart_cd.cd_devs[unit];
> - //bus_space_tag_t iot = sc->sc_iot;
> - //bus_space_handle_t ioh = sc->sc_ioh;
> - struct tty *tp = sc->sc_tty;
> - int s;
> -
> - /* XXX This is for cons.c. */
> - if (!ISSET(tp->t_state, TS_ISOPEN))
> - return 0;
> -
> - (*linesw[tp->t_line].l_close)(tp, flag, p);
> - s = spltty();
> - if (ISSET(tp->t_state, TS_WOPEN)) {
> - /* tty device is waiting for carrier; drop dtr then re-raise */
> - //CLR(sc->sc_ucr3, IMXUART_CR3_DSR);
> - //bus_space_write_4(iot, ioh, IMXUART_UCR3, sc->sc_ucr3);
> - timeout_add(&sc->sc_dtr_tmo, hz * 2);
> - } else {
> - /* no one else waiting; turn off the uart */
> - pluart_pwroff(sc);
> - }
> - CLR(tp->t_state, TS_BUSY | TS_FLUSH);
> -
> - sc->sc_cua = 0;
> - splx(s);
> - ttyclose(tp);
> -
> - return 0;
> -}
> -
> -int
> -pluartread(dev_t dev, struct uio *uio, int flag)
> -{
> - struct tty *tty;
> -
> - tty = pluarttty(dev);
> - if (tty == NULL)
> - return ENODEV;
> -
> - return((*linesw[tty->t_line].l_read)(tty, uio, flag));
> -}
> -
> -int
> -pluartwrite(dev_t dev, struct uio *uio, int flag)
> -{
> - struct tty *tty;
> -
> - tty = pluarttty(dev);
> - if (tty == NULL)
> - return ENODEV;
> -
> - return((*linesw[tty->t_line].l_write)(tty, uio, flag));
> -}
> -
> -int
> -pluartioctl( dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
> -{
> - struct pluart_softc *sc;
> - struct tty *tp;
> - int error;
> -
> - sc = pluart_sc(dev);
> - if (sc == NULL)
> - return (ENODEV);
> -
> - tp = sc->sc_tty;
> - if (tp == NULL)
> - return (ENXIO);
> -
> - error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
> - if (error >= 0)
> - return (error);
> -
> - error = ttioctl(tp, cmd, data, flag, p);
> - if (error >= 0)
> - return (error);
> -
> - switch(cmd) {
> - case TIOCSBRK:
> - break;
> - case TIOCCBRK:
> - break;
> - case TIOCSDTR:
> - break;
> - case TIOCCDTR:
> - break;
> - case TIOCMSET:
> - break;
> - case TIOCMBIS:
> - break;
> - case TIOCMBIC:
> - break;
> - case TIOCMGET:
> - break;
> - case TIOCGFLAGS:
> - break;
> - case TIOCSFLAGS:
> - error = suser(p);
> - if (error != 0)
> - return(EPERM);
> - break;
> - default:
> - return (ENOTTY);
> - }
> -
> - return 0;
> -}
> -
> -int
> -pluartstop(struct tty *tp, int flag)
> -{
> - return 0;
> -}
> -
> -struct tty *
> -pluarttty(dev_t dev)
> -{
> - int unit;
> - struct pluart_softc *sc;
> - unit = DEVUNIT(dev);
> - if (unit >= pluart_cd.cd_ndevs)
> - return NULL;
> - sc = (struct pluart_softc *)pluart_cd.cd_devs[unit];
> - if (sc == NULL)
> - return NULL;
> - return sc->sc_tty;
> -}
> -
> -struct pluart_softc *
> -pluart_sc(dev_t dev)
> -{
> - int unit;
> - struct pluart_softc *sc;
> - unit = DEVUNIT(dev);
> - if (unit >= pluart_cd.cd_ndevs)
> - return NULL;
> - sc = (struct pluart_softc *)pluart_cd.cd_devs[unit];
> - return sc;
> -}
> -
> -
> -/* serial console */
> -void
> -pluartcnprobe(struct consdev *cp)
> -{
> -}
> -
> -void
> -pluartcninit(struct consdev *cp)
> -{
> -}
> -
> -int
> -pluartcnattach(bus_space_tag_t iot, bus_addr_t iobase, int rate, tcflag_t
> cflag)
> -{
> - static struct consdev pluartcons = {
> - NULL, NULL, pluartcngetc, pluartcnputc, pluartcnpollc, NULL,
> - NODEV, CN_MIDPRI
> - };
> - int maj;
> -
> - if (bus_space_map(iot, iobase, UART_SPACE, 0, &pluartconsioh))
> - return ENOMEM;
> -
> - /* Disable FIFO. */
> - bus_space_write_4(iot, pluartconsioh, UART_LCR_H,
> - bus_space_read_4(iot, pluartconsioh, UART_LCR_H) & ~UART_LCR_H_FEN);
> -
> - /* Look for major of com(4) to replace. */
> - for (maj = 0; maj < nchrdev; maj++)
> - if (cdevsw[maj].d_open == comopen)
> - break;
> - if (maj == nchrdev)
> - return ENXIO;
> -
> - cn_tab = &pluartcons;
> - cn_tab->cn_dev = makedev(maj, 0);
> - cdevsw[12] = pluartdev; /* KLUDGE */
> -
> - pluartconsiot = iot;
> - pluartconsaddr = iobase;
> - pluartconscflag = cflag;
> -
> - return 0;
> -}
> -
> -int
> -pluartcngetc(dev_t dev)
> -{
> - int c;
> - int s;
> - s = splhigh();
> - while((bus_space_read_4(pluartconsiot, pluartconsioh, UART_FR) &
> - UART_FR_RXFF) == 0)
> - ;
> - c = bus_space_read_4(pluartconsiot, pluartconsioh, UART_DR);
> - splx(s);
> - return c;
> -}
> -
> -void
> -pluartcnputc(dev_t dev, int c)
> -{
> - int s;
> - s = splhigh();
> - while((bus_space_read_4(pluartconsiot, pluartconsioh, UART_FR) &
> - UART_FR_TXFE) == 0)
> - ;
> - bus_space_write_4(pluartconsiot, pluartconsioh, UART_DR, (uint8_t)c);
> - splx(s);
> -}
> -
> -void
> -pluartcnpollc(dev_t dev, int on)
> -{
> -}
> Index: dev/fdt/pluart_fdt.c
> ===================================================================
> RCS file: dev/fdt/pluart_fdt.c
> diff -N dev/fdt/pluart_fdt.c
> --- /dev/null 1 Jan 1970 00:00:00 -0000
> +++ dev/fdt/pluart_fdt.c 1 Jul 2018 14:29:40 -0000
> @@ -0,0 +1,80 @@
> +/* $OpenBSD: pluart.c,v 1.1 2018/06/05 20:41:19 kettenis Exp $ */
> +/*
> + * Copyright (c) 2014 Patrick Wildt <[email protected]>
> + * Copyright (c) 2005 Dale Rahn <[email protected]>
> + *
> + * Permission to use, copy, modify, and distribute this software for any
> + * purpose with or without fee is hereby granted, provided that the above
> + * copyright notice and this permission notice appear in all copies.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
> + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
> + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
> + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
> + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
> + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
> + */
> +
> +#include <sys/param.h>
> +#include <sys/systm.h>
> +#include <sys/tty.h>
> +
> +#include <machine/bus.h>
> +#include <machine/fdt.h>
> +
> +#include <dev/ic/pluartvar.h>
> +
> +#include <dev/ofw/fdt.h>
> +#include <dev/ofw/openfirm.h>
> +
> +int pluart_fdt_match(struct device *, void *, void *);
> +void pluart_fdt_attach(struct device *, struct device *, void *);
> +
> +struct cfattach pluart_fdt_ca = {
> + sizeof(struct pluart_softc), pluart_fdt_match, pluart_fdt_attach
> +};
> +
> +void
> +pluart_init_cons(void)
> +{
> + struct fdt_reg reg;
> + void *node;
> +
> + if ((node = fdt_find_cons("arm,pl011")) == NULL)
> + return;
> + if (fdt_get_reg(node, 0, ®))
> + return;
> +
> + pluartcnattach(fdt_cons_bs_tag, reg.addr, B115200, TTYDEF_CFLAG);
> +}
> +
> +int
> +pluart_fdt_match(struct device *parent, void *self, void *aux)
> +{
> + struct fdt_attach_args *faa = aux;
> +
> + return OF_is_compatible(faa->fa_node, "arm,pl011");
> +}
> +
> +void
> +pluart_fdt_attach(struct device *parent, struct device *self, void *aux)
> +{
> + struct fdt_attach_args *faa = aux;
> + struct pluart_softc *sc = (struct pluart_softc *) self;
> +
> + if (faa->fa_nreg < 1) {
> + printf(": no registers\n");
> + return;
> + }
> +
> + sc->sc_irq = arm_intr_establish_fdt(faa->fa_node, IPL_TTY, pluart_intr,
> + sc, sc->sc_dev.dv_xname);
> +
> + sc->sc_iot = faa->fa_iot;
> + if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, faa->fa_reg[0].size,
> + 0, &sc->sc_ioh))
> + panic("pluartattach: bus_space_map failed!");
> +
> + pluart_attach_common(sc, stdout_node == faa->fa_node);
> +}
> Index: dev/ic/pluart.c
> ===================================================================
> RCS file: dev/ic/pluart.c
> diff -N dev/ic/pluart.c
> --- /dev/null 1 Jan 1970 00:00:00 -0000
> +++ dev/ic/pluart.c 1 Jul 2018 14:29:40 -0000
> @@ -0,0 +1,820 @@
> +/* $OpenBSD: pluart.c,v 1.1 2018/06/05 20:41:19 kettenis Exp $ */
> +/*
> + * Copyright (c) 2014 Patrick Wildt <[email protected]>
> + * Copyright (c) 2005 Dale Rahn <[email protected]>
> + *
> + * Permission to use, copy, modify, and distribute this software for any
> + * purpose with or without fee is hereby granted, provided that the above
> + * copyright notice and this permission notice appear in all copies.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
> + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
> + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
> + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
> + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
> + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
> + */
> +
> +#include <sys/param.h>
> +#include <sys/ioctl.h>
> +#include <sys/proc.h>
> +#include <sys/tty.h>
> +#include <sys/uio.h>
> +#include <sys/systm.h>
> +#include <sys/time.h>
> +#include <sys/device.h>
> +#include <sys/syslog.h>
> +#include <sys/conf.h>
> +#include <sys/fcntl.h>
> +#include <sys/select.h>
> +#include <sys/kernel.h>
> +
> +#include <machine/bus.h>
> +
> +#include <dev/ic/pluartvar.h>
> +#include <dev/cons.h>
> +
> +#ifdef DDB
> +#include <ddb/db_var.h>
> +#endif
> +
> +#define DEVUNIT(x) (minor(x) & 0x7f)
> +#define DEVCUA(x) (minor(x) & 0x80)
> +
> +#define UART_DR 0x00 /* Data register */
> +#define UART_DR_DATA(x) ((x) & 0xf)
> +#define UART_DR_FE (1 << 8) /* Framing error */
> +#define UART_DR_PE (1 << 9) /* Parity error */
> +#define UART_DR_BE (1 << 10) /* Break error */
> +#define UART_DR_OE (1 << 11) /* Overrun error */
> +#define UART_RSR 0x04 /* Receive status register */
> +#define UART_RSR_FE (1 << 0) /* Framing error */
> +#define UART_RSR_PE (1 << 1) /* Parity error */
> +#define UART_RSR_BE (1 << 2) /* Break error */
> +#define UART_RSR_OE (1 << 3) /* Overrun error */
> +#define UART_ECR 0x04 /* Error clear register */
> +#define UART_ECR_FE (1 << 0) /* Framing error */
> +#define UART_ECR_PE (1 << 1) /* Parity error */
> +#define UART_ECR_BE (1 << 2) /* Break error */
> +#define UART_ECR_OE (1 << 3) /* Overrun error */
> +#define UART_FR 0x18 /* Flag register */
> +#define UART_FR_CTS (1 << 0) /* Clear to send */
> +#define UART_FR_DSR (1 << 1) /* Data set ready */
> +#define UART_FR_DCD (1 << 2) /* Data carrier detect */
> +#define UART_FR_BUSY (1 << 3) /* UART busy */
> +#define UART_FR_RXFE (1 << 4) /* Receive FIFO empty */
> +#define UART_FR_TXFF (1 << 5) /* Transmit FIFO full */
> +#define UART_FR_RXFF (1 << 6) /* Receive FIFO full */
> +#define UART_FR_TXFE (1 << 7) /* Transmit FIFO empty */
> +#define UART_FR_RI (1 << 8) /* Ring indicator */
> +#define UART_ILPR 0x20 /* IrDA low-power counter
> register */
> +#define UART_ILPR_ILPDVSR ((x) & 0xf) /* IrDA low-power divisor */
> +#define UART_IBRD 0x24 /* Integer baud rate register */
> +#define UART_IBRD_DIVINT ((x) & 0xff) /* Integer baud rate divisor */
> +#define UART_FBRD 0x28 /* Fractional baud rate
> register */
> +#define UART_FBRD_DIVFRAC ((x) & 0x3f) /* Fractional baud rate divisor
> */
> +#define UART_LCR_H 0x2c /* Line control register */
> +#define UART_LCR_H_BRK (1 << 0) /* Send break */
> +#define UART_LCR_H_PEN (1 << 1) /* Parity enable */
> +#define UART_LCR_H_EPS (1 << 2) /* Even parity select */
> +#define UART_LCR_H_STP2 (1 << 3) /* Two stop bits select
> */
> +#define UART_LCR_H_FEN (1 << 4) /* Enable FIFOs */
> +#define UART_LCR_H_WLEN5 (0x0 << 5) /* Word length: 5 bits */
> +#define UART_LCR_H_WLEN6 (0x1 << 5) /* Word length: 6 bits */
> +#define UART_LCR_H_WLEN7 (0x2 << 5) /* Word length: 7 bits */
> +#define UART_LCR_H_WLEN8 (0x3 << 5) /* Word length: 8 bits */
> +#define UART_LCR_H_SPS (1 << 7) /* Stick parity select
> */
> +#define UART_CR 0x30 /* Control register */
> +#define UART_CR_UARTEN (1 << 0) /* UART enable */
> +#define UART_CR_SIREN (1 << 1) /* SIR enable */
> +#define UART_CR_SIRLP (1 << 2) /* IrDA SIR low power
> mode */
> +#define UART_CR_LBE (1 << 7) /* Loop back enable */
> +#define UART_CR_TXE (1 << 8) /* Transmit enable */
> +#define UART_CR_RXE (1 << 9) /* Receive enable */
> +#define UART_CR_DTR (1 << 10) /* Data transmit enable */
> +#define UART_CR_RTS (1 << 11) /* Request to send */
> +#define UART_CR_OUT1 (1 << 12)
> +#define UART_CR_OUT2 (1 << 13)
> +#define UART_CR_CTSE (1 << 14) /* CTS hardware flow control
> enable */
> +#define UART_CR_RTSE (1 << 15) /* RTS hardware flow control
> enable */
> +#define UART_IFLS 0x34 /* Interrupt FIFO level select
> register */
> +#define UART_IMSC 0x38 /* Interrupt mask set/clear
> register */
> +#define UART_IMSC_RIMIM (1 << 0)
> +#define UART_IMSC_CTSMIM (1 << 1)
> +#define UART_IMSC_DCDMIM (1 << 2)
> +#define UART_IMSC_DSRMIM (1 << 3)
> +#define UART_IMSC_RXIM (1 << 4)
> +#define UART_IMSC_TXIM (1 << 5)
> +#define UART_IMSC_RTIM (1 << 6)
> +#define UART_IMSC_FEIM (1 << 7)
> +#define UART_IMSC_PEIM (1 << 8)
> +#define UART_IMSC_BEIM (1 << 9)
> +#define UART_IMSC_OEIM (1 << 10)
> +#define UART_RIS 0x3c /* Raw interrupt status
> register */
> +#define UART_MIS 0x40 /* Masked interrupt status
> register */
> +#define UART_ICR 0x44 /* Interrupt clear register */
> +#define UART_DMACR 0x48 /* DMA control register */
> +#define UART_SPACE 0x100
> +
> +void pluartcnprobe(struct consdev *cp);
> +void pluartcninit(struct consdev *cp);
> +int pluartcngetc(dev_t dev);
> +void pluartcnputc(dev_t dev, int c);
> +void pluartcnpollc(dev_t dev, int on);
> +int pluart_param(struct tty *tp, struct termios *t);
> +void pluart_start(struct tty *);
> +void pluart_pwroff(struct pluart_softc *sc);
> +void pluart_diag(void *arg);
> +void pluart_raisedtr(void *arg);
> +void pluart_softint(void *arg);
> +struct pluart_softc *pluart_sc(dev_t dev);
> +
> +/* XXX - we imitate 'com' serial ports and take over their entry points */
> +/* XXX: These belong elsewhere */
> +cdev_decl(com);
> +cdev_decl(pluart);
> +
> +struct cfdriver pluart_cd = {
> + NULL, "pluart", DV_TTY
> +};
> +
> +bus_space_tag_t pluartconsiot;
> +bus_space_handle_t pluartconsioh;
> +bus_addr_t pluartconsaddr;
> +tcflag_t pluartconscflag = TTYDEF_CFLAG;
> +int pluartdefaultrate = B38400;
> +
> +struct cdevsw pluartdev =
> + cdev_tty_init(3/*XXX NUART */ ,pluart); /* 12: serial port */
> +
> +void
> +pluart_attach_common(struct pluart_softc *sc, int console)
> +{
> + int maj;
> +
> + if (console) {
> + /* Locate the major number. */
> + for (maj = 0; maj < nchrdev; maj++)
> + if (cdevsw[maj].d_open == pluartopen)
> + break;
> + cn_tab->cn_dev = makedev(maj, sc->sc_dev.dv_unit);
> +
> + printf(": console");
> + SET(sc->sc_hwflags, COM_HW_CONSOLE);
> + }
> +
> + timeout_set(&sc->sc_diag_tmo, pluart_diag, sc);
> + timeout_set(&sc->sc_dtr_tmo, pluart_raisedtr, sc);
> + sc->sc_si = softintr_establish(IPL_TTY, pluart_softint, sc);
> +
> + if(sc->sc_si == NULL)
> + panic("%s: can't establish soft interrupt.",
> + sc->sc_dev.dv_xname);
> +
> + bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_IMSC, (UART_IMSC_RXIM |
> UART_IMSC_TXIM));
> + bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_ICR, 0x7ff);
> + bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_LCR_H,
> + bus_space_read_4(sc->sc_iot, sc->sc_ioh, UART_LCR_H) &
> + ~UART_LCR_H_FEN);
> +
> + printf("\n");
> +}
> +
> +int
> +pluart_intr(void *arg)
> +{
> + struct pluart_softc *sc = arg;
> + bus_space_tag_t iot = sc->sc_iot;
> + bus_space_handle_t ioh = sc->sc_ioh;
> + struct tty *tp = sc->sc_tty;
> + u_int16_t fr;
> + u_int16_t *p;
> + u_int16_t c;
> +
> + bus_space_write_4(iot, ioh, UART_ICR, -1);
> +
> + if (sc->sc_tty == NULL)
> + return(0);
> +
> + fr = bus_space_read_4(iot, ioh, UART_FR);
> + if (ISSET(fr, UART_FR_TXFE) && ISSET(tp->t_state, TS_BUSY)) {
> + CLR(tp->t_state, TS_BUSY | TS_FLUSH);
> + if (sc->sc_halt > 0)
> + wakeup(&tp->t_outq);
> + (*linesw[tp->t_line].l_start)(tp);
> + }
> +
> + if(!ISSET(bus_space_read_4(iot, ioh, UART_FR), UART_FR_RXFF))
> + return 0;
> +
> + p = sc->sc_ibufp;
> +
> + while (ISSET(bus_space_read_4(iot, ioh, UART_FR), UART_FR_RXFF)) {
> + c = bus_space_read_2(iot, ioh, UART_DR);
> + if (c & UART_DR_BE) {
> +#ifdef DDB
> + if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) {
> + if (db_console)
> + db_enter();
> + continue;
> + }
> +#endif
> + c = 0;
> + }
> + if (p >= sc->sc_ibufend) {
> + sc->sc_floods++;
> + if (sc->sc_errors++ == 0)
> + timeout_add(&sc->sc_diag_tmo, 60 * hz);
> + } else {
> + *p++ = c;
> + if (p == sc->sc_ibufhigh && ISSET(tp->t_cflag,
> CRTSCTS)) {
> + /* XXX */
> + //CLR(sc->sc_ucr3, IMXUART_CR3_DSR);
> + //bus_space_write_4(iot, ioh, IMXUART_UCR3,
> + // sc->sc_ucr3);
> + }
> + }
> + /* XXX - msr stuff ? */
> + }
> + sc->sc_ibufp = p;
> +
> + softintr_schedule(sc->sc_si);
> +
> + return 1;
> +}
> +
> +int
> +pluart_param(struct tty *tp, struct termios *t)
> +{
> + struct pluart_softc *sc = pluart_cd.cd_devs[DEVUNIT(tp->t_dev)];
> + //bus_space_tag_t iot = sc->sc_iot;
> + //bus_space_handle_t ioh = sc->sc_ioh;
> + int ospeed = t->c_ospeed;
> + int error;
> + tcflag_t oldcflag;
> +
> +
> + if (t->c_ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
> + return EINVAL;
> +
> + switch (ISSET(t->c_cflag, CSIZE)) {
> + case CS5:
> + return EINVAL;
> + case CS6:
> + return EINVAL;
> + case CS7:
> + //CLR(sc->sc_ucr2, IMXUART_CR2_WS);
> + break;
> + case CS8:
> + //SET(sc->sc_ucr2, IMXUART_CR2_WS);
> + break;
> + }
> +// bus_space_write_4(iot, ioh, IMXUART_UCR2, sc->sc_ucr2);
> +
> + /*
> + if (ISSET(t->c_cflag, PARENB)) {
> + SET(sc->sc_ucr2, IMXUART_CR2_PREN);
> + bus_space_write_4(iot, ioh, IMXUART_UCR2, sc->sc_ucr2);
> + }
> + */
> + /* STOPB - XXX */
> + if (ospeed == 0) {
> + /* lower dtr */
> + }
> +
> + if (ospeed != 0) {
> + while (ISSET(tp->t_state, TS_BUSY)) {
> + ++sc->sc_halt;
> + error = ttysleep(tp, &tp->t_outq,
> + TTOPRI | PCATCH, "pluartprm", 0);
> + --sc->sc_halt;
> + if (error) {
> + pluart_start(tp);
> + return (error);
> + }
> + }
> + /* set speed */
> + }
> +
> + /* setup fifo */
> +
> + /* When not using CRTSCTS, RTS follows DTR. */
> + /* sc->sc_dtr = MCR_DTR; */
> +
> +
> + /* and copy to tty */
> + tp->t_ispeed = t->c_ispeed;
> + tp->t_ospeed = t->c_ospeed;
> + oldcflag = tp->t_cflag;
> + tp->t_cflag = t->c_cflag;
> +
> + /*
> + * If DCD is off and MDMBUF is changed, ask the tty layer if we should
> + * stop the device.
> + */
> + /* XXX */
> +
> + pluart_start(tp);
> +
> + return 0;
> +}
> +
> +void
> +pluart_start(struct tty *tp)
> +{
> + struct pluart_softc *sc = pluart_cd.cd_devs[DEVUNIT(tp->t_dev)];
> + bus_space_tag_t iot = sc->sc_iot;
> + bus_space_handle_t ioh = sc->sc_ioh;
> +
> + int s;
> + s = spltty();
> + if (ISSET(tp->t_state, TS_BUSY | TS_TIMEOUT | TS_TTSTOP))
> + goto out;
> + if (tp->t_outq.c_cc <= tp->t_lowat) {
> + if (ISSET(tp->t_state, TS_ASLEEP)) {
> + CLR(tp->t_state, TS_ASLEEP);
> + wakeup(&tp->t_outq);
> + }
> + if (tp->t_outq.c_cc == 0)
> + goto out;
> + selwakeup(&tp->t_wsel);
> + }
> + SET(tp->t_state, TS_BUSY);
> +
> + if (ISSET(sc->sc_hwflags, COM_HW_FIFO)) {
> + u_char buffer[64]; /* largest fifo */
> + int i, n;
> +
> + n = q_to_b(&tp->t_outq, buffer,
> + min(sc->sc_fifolen, sizeof buffer));
> + for (i = 0; i < n; i++) {
> + bus_space_write_4(iot, ioh, UART_DR, buffer[i]);
> + }
> + bzero(buffer, n);
> + } else if (tp->t_outq.c_cc != 0)
> + bus_space_write_4(iot, ioh, UART_DR, getc(&tp->t_outq));
> +
> +out:
> + splx(s);
> +}
> +
> +void
> +pluart_pwroff(struct pluart_softc *sc)
> +{
> +}
> +
> +void
> +pluart_diag(void *arg)
> +{
> + struct pluart_softc *sc = arg;
> + int overflows, floods;
> + int s;
> +
> + s = spltty();
> + sc->sc_errors = 0;
> + overflows = sc->sc_overflows;
> + sc->sc_overflows = 0;
> + floods = sc->sc_floods;
> + sc->sc_floods = 0;
> + splx(s);
> + log(LOG_WARNING, "%s: %d silo overflow%s, %d ibuf overflow%s\n",
> + sc->sc_dev.dv_xname,
> + overflows, overflows == 1 ? "" : "s",
> + floods, floods == 1 ? "" : "s");
> +}
> +
> +void
> +pluart_raisedtr(void *arg)
> +{
> + //struct pluart_softc *sc = arg;
> +
> + //SET(sc->sc_ucr3, IMXUART_CR3_DSR); /* XXX */
> + //bus_space_write_4(sc->sc_iot, sc->sc_ioh, IMXUART_UCR3, sc->sc_ucr3);
> +}
> +
> +void
> +pluart_softint(void *arg)
> +{
> + struct pluart_softc *sc = arg;
> + struct tty *tp;
> + u_int16_t *ibufp;
> + u_int16_t *ibufend;
> + int c;
> + int err;
> + int s;
> +
> + if (sc == NULL || sc->sc_ibufp == sc->sc_ibuf)
> + return;
> +
> + tp = sc->sc_tty;
> + s = spltty();
> +
> + ibufp = sc->sc_ibuf;
> + ibufend = sc->sc_ibufp;
> +
> + if (ibufp == ibufend || tp == NULL || !ISSET(tp->t_state, TS_ISOPEN)) {
> + splx(s);
> + return;
> + }
> +
> + sc->sc_ibufp = sc->sc_ibuf = (ibufp == sc->sc_ibufs[0]) ?
> + sc->sc_ibufs[1] : sc->sc_ibufs[0];
> + sc->sc_ibufhigh = sc->sc_ibuf + UART_IHIGHWATER;
> + sc->sc_ibufend = sc->sc_ibuf + UART_IBUFSIZE;
> +
> +#if 0
> + if (ISSET(tp->t_cflag, CRTSCTS) &&
> + !ISSET(sc->sc_ucr3, IMXUART_CR3_DSR)) {
> + /* XXX */
> + SET(sc->sc_ucr3, IMXUART_CR3_DSR);
> + bus_space_write_4(sc->sc_iot, sc->sc_ioh, IMXUART_UCR3,
> + sc->sc_ucr3);
> + }
> +#endif
> +
> + splx(s);
> +
> + while (ibufp < ibufend) {
> + c = *ibufp++;
> + /*
> + if (ISSET(c, IMXUART_RX_OVERRUN)) {
> + sc->sc_overflows++;
> + if (sc->sc_errors++ == 0)
> + timeout_add(&sc->sc_diag_tmo, 60 * hz);
> + }
> + */
> + /* This is ugly, but fast. */
> +
> + err = 0;
> + /*
> + if (ISSET(c, IMXUART_RX_PRERR))
> + err |= TTY_PE;
> + if (ISSET(c, IMXUART_RX_FRMERR))
> + err |= TTY_FE;
> + */
> + c = (c & 0xff) | err;
> + (*linesw[tp->t_line].l_rint)(c, tp);
> + }
> +}
> +
> +int
> +pluartopen(dev_t dev, int flag, int mode, struct proc *p)
> +{
> + int unit = DEVUNIT(dev);
> + struct pluart_softc *sc;
> + bus_space_tag_t iot;
> + bus_space_handle_t ioh;
> + struct tty *tp;
> + int s;
> + int error = 0;
> +
> + if (unit >= pluart_cd.cd_ndevs)
> + return ENXIO;
> + sc = pluart_cd.cd_devs[unit];
> + if (sc == NULL)
> + return ENXIO;
> +
> + s = spltty();
> + if (sc->sc_tty == NULL)
> + tp = sc->sc_tty = ttymalloc(0);
> + else
> + tp = sc->sc_tty;
> +
> + splx(s);
> +
> + tp->t_oproc = pluart_start;
> + tp->t_param = pluart_param;
> + tp->t_dev = dev;
> +
> + if (!ISSET(tp->t_state, TS_ISOPEN)) {
> + SET(tp->t_state, TS_WOPEN);
> + ttychars(tp);
> + tp->t_iflag = TTYDEF_IFLAG;
> + tp->t_oflag = TTYDEF_OFLAG;
> +
> + if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE))
> + tp->t_cflag = pluartconscflag;
> + else
> + tp->t_cflag = TTYDEF_CFLAG;
> + if (ISSET(sc->sc_swflags, COM_SW_CLOCAL))
> + SET(tp->t_cflag, CLOCAL);
> + if (ISSET(sc->sc_swflags, COM_SW_CRTSCTS))
> + SET(tp->t_cflag, CRTSCTS);
> + if (ISSET(sc->sc_swflags, COM_SW_MDMBUF))
> + SET(tp->t_cflag, MDMBUF);
> + tp->t_lflag = TTYDEF_LFLAG;
> + tp->t_ispeed = tp->t_ospeed = pluartdefaultrate;
> +
> + s = spltty();
> +
> + sc->sc_initialize = 1;
> + pluart_param(tp, &tp->t_termios);
> + ttsetwater(tp);
> + sc->sc_ibufp = sc->sc_ibuf = sc->sc_ibufs[0];
> + sc->sc_ibufhigh = sc->sc_ibuf + UART_IHIGHWATER;
> + sc->sc_ibufend = sc->sc_ibuf + UART_IBUFSIZE;
> +
> + iot = sc->sc_iot;
> + ioh = sc->sc_ioh;
> +
> +#if 0
> + sc->sc_ucr1 = bus_space_read_4(iot, ioh, IMXUART_UCR1);
> + sc->sc_ucr2 = bus_space_read_4(iot, ioh, IMXUART_UCR2);
> + sc->sc_ucr3 = bus_space_read_4(iot, ioh, IMXUART_UCR3);
> + sc->sc_ucr4 = bus_space_read_4(iot, ioh, IMXUART_UCR4);
> +
> + /* interrupt after one char on tx/rx */
> + /* reference frequency divider: 1 */
> + bus_space_write_4(iot, ioh, IMXUART_UFCR,
> + 1 << IMXUART_FCR_TXTL_SH |
> + 5 << IMXUART_FCR_RFDIV_SH |
> + 1 << IMXUART_FCR_RXTL_SH);
> +
> + bus_space_write_4(iot, ioh, IMXUART_UBIR,
> + (pluartdefaultrate / 100) - 1);
> +
> + /* formula: clk / (rfdiv * 1600) */
> + bus_space_write_4(iot, ioh, IMXUART_UBMR,
> + (clk_get_rate(sc->sc_clk) * 1000) / 1600);
> +
> + SET(sc->sc_ucr1, IMXUART_CR1_EN|IMXUART_CR1_RRDYEN);
> + SET(sc->sc_ucr2, IMXUART_CR2_TXEN|IMXUART_CR2_RXEN);
> + bus_space_write_4(iot, ioh, IMXUART_UCR1, sc->sc_ucr1);
> + bus_space_write_4(iot, ioh, IMXUART_UCR2, sc->sc_ucr2);
> +
> + /* sc->sc_mcr = MCR_DTR | MCR_RTS; XXX */
> + SET(sc->sc_ucr3, IMXUART_CR3_DSR); /* XXX */
> + bus_space_write_4(iot, ioh, IMXUART_UCR3, sc->sc_ucr3);
> +#endif
> +
> + SET(tp->t_state, TS_CARR_ON); /* XXX */
> +
> +
> + } else if (ISSET(tp->t_state, TS_XCLUDE) && p->p_ucred->cr_uid != 0)
> + return EBUSY;
> + else
> + s = spltty();
> +
> + if (DEVCUA(dev)) {
> + if (ISSET(tp->t_state, TS_ISOPEN)) {
> + splx(s);
> + return EBUSY;
> + }
> + sc->sc_cua = 1;
> + } else {
> + /* tty (not cua) device; wait for carrier if necessary */
> + if (ISSET(flag, O_NONBLOCK)) {
> + if (sc->sc_cua) {
> + /* Opening TTY non-blocking... but the CUA is
> busy */
> + splx(s);
> + return EBUSY;
> + }
> + } else {
> + while (sc->sc_cua ||
> + (!ISSET(tp->t_cflag, CLOCAL) &&
> + !ISSET(tp->t_state, TS_CARR_ON))) {
> + SET(tp->t_state, TS_WOPEN);
> + error = ttysleep(tp, &tp->t_rawq,
> + TTIPRI | PCATCH, ttopen, 0);
> + /*
> + * If TS_WOPEN has been reset, that means the
> + * cua device has been closed. We don't want
> + * to fail in that case,
> + * so just go around again.
> + */
> + if (error && ISSET(tp->t_state, TS_WOPEN)) {
> + CLR(tp->t_state, TS_WOPEN);
> + if (!sc->sc_cua && !ISSET(tp->t_state,
> + TS_ISOPEN))
> + pluart_pwroff(sc);
> + splx(s);
> + return error;
> + }
> + }
> + }
> + }
> + splx(s);
> + return (*linesw[tp->t_line].l_open)(dev,tp,p);
> +}
> +
> +int
> +pluartclose(dev_t dev, int flag, int mode, struct proc *p)
> +{
> + int unit = DEVUNIT(dev);
> + struct pluart_softc *sc = pluart_cd.cd_devs[unit];
> + //bus_space_tag_t iot = sc->sc_iot;
> + //bus_space_handle_t ioh = sc->sc_ioh;
> + struct tty *tp = sc->sc_tty;
> + int s;
> +
> + /* XXX This is for cons.c. */
> + if (!ISSET(tp->t_state, TS_ISOPEN))
> + return 0;
> +
> + (*linesw[tp->t_line].l_close)(tp, flag, p);
> + s = spltty();
> + if (ISSET(tp->t_state, TS_WOPEN)) {
> + /* tty device is waiting for carrier; drop dtr then re-raise */
> + //CLR(sc->sc_ucr3, IMXUART_CR3_DSR);
> + //bus_space_write_4(iot, ioh, IMXUART_UCR3, sc->sc_ucr3);
> + timeout_add(&sc->sc_dtr_tmo, hz * 2);
> + } else {
> + /* no one else waiting; turn off the uart */
> + pluart_pwroff(sc);
> + }
> + CLR(tp->t_state, TS_BUSY | TS_FLUSH);
> +
> + sc->sc_cua = 0;
> + splx(s);
> + ttyclose(tp);
> +
> + return 0;
> +}
> +
> +int
> +pluartread(dev_t dev, struct uio *uio, int flag)
> +{
> + struct tty *tty;
> +
> + tty = pluarttty(dev);
> + if (tty == NULL)
> + return ENODEV;
> +
> + return((*linesw[tty->t_line].l_read)(tty, uio, flag));
> +}
> +
> +int
> +pluartwrite(dev_t dev, struct uio *uio, int flag)
> +{
> + struct tty *tty;
> +
> + tty = pluarttty(dev);
> + if (tty == NULL)
> + return ENODEV;
> +
> + return((*linesw[tty->t_line].l_write)(tty, uio, flag));
> +}
> +
> +int
> +pluartioctl( dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
> +{
> + struct pluart_softc *sc;
> + struct tty *tp;
> + int error;
> +
> + sc = pluart_sc(dev);
> + if (sc == NULL)
> + return (ENODEV);
> +
> + tp = sc->sc_tty;
> + if (tp == NULL)
> + return (ENXIO);
> +
> + error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
> + if (error >= 0)
> + return (error);
> +
> + error = ttioctl(tp, cmd, data, flag, p);
> + if (error >= 0)
> + return (error);
> +
> + switch(cmd) {
> + case TIOCSBRK:
> + break;
> + case TIOCCBRK:
> + break;
> + case TIOCSDTR:
> + break;
> + case TIOCCDTR:
> + break;
> + case TIOCMSET:
> + break;
> + case TIOCMBIS:
> + break;
> + case TIOCMBIC:
> + break;
> + case TIOCMGET:
> + break;
> + case TIOCGFLAGS:
> + break;
> + case TIOCSFLAGS:
> + error = suser(p);
> + if (error != 0)
> + return(EPERM);
> + break;
> + default:
> + return (ENOTTY);
> + }
> +
> + return 0;
> +}
> +
> +int
> +pluartstop(struct tty *tp, int flag)
> +{
> + return 0;
> +}
> +
> +struct tty *
> +pluarttty(dev_t dev)
> +{
> + int unit;
> + struct pluart_softc *sc;
> + unit = DEVUNIT(dev);
> + if (unit >= pluart_cd.cd_ndevs)
> + return NULL;
> + sc = (struct pluart_softc *)pluart_cd.cd_devs[unit];
> + if (sc == NULL)
> + return NULL;
> + return sc->sc_tty;
> +}
> +
> +struct pluart_softc *
> +pluart_sc(dev_t dev)
> +{
> + int unit;
> + struct pluart_softc *sc;
> + unit = DEVUNIT(dev);
> + if (unit >= pluart_cd.cd_ndevs)
> + return NULL;
> + sc = (struct pluart_softc *)pluart_cd.cd_devs[unit];
> + return sc;
> +}
> +
> +
> +/* serial console */
> +void
> +pluartcnprobe(struct consdev *cp)
> +{
> +}
> +
> +void
> +pluartcninit(struct consdev *cp)
> +{
> +}
> +
> +int
> +pluartcnattach(bus_space_tag_t iot, bus_addr_t iobase, int rate, tcflag_t
> cflag)
> +{
> + static struct consdev pluartcons = {
> + NULL, NULL, pluartcngetc, pluartcnputc, pluartcnpollc, NULL,
> + NODEV, CN_MIDPRI
> + };
> + int maj;
> +
> + if (bus_space_map(iot, iobase, UART_SPACE, 0, &pluartconsioh))
> + return ENOMEM;
> +
> + /* Disable FIFO. */
> + bus_space_write_4(iot, pluartconsioh, UART_LCR_H,
> + bus_space_read_4(iot, pluartconsioh, UART_LCR_H) & ~UART_LCR_H_FEN);
> +
> + /* Look for major of com(4) to replace. */
> + for (maj = 0; maj < nchrdev; maj++)
> + if (cdevsw[maj].d_open == comopen)
> + break;
> + if (maj == nchrdev)
> + return ENXIO;
> +
> + cn_tab = &pluartcons;
> + cn_tab->cn_dev = makedev(maj, 0);
> + cdevsw[12] = pluartdev; /* KLUDGE */
> +
> + pluartconsiot = iot;
> + pluartconsaddr = iobase;
> + pluartconscflag = cflag;
> +
> + return 0;
> +}
> +
> +int
> +pluartcngetc(dev_t dev)
> +{
> + int c;
> + int s;
> + s = splhigh();
> + while((bus_space_read_4(pluartconsiot, pluartconsioh, UART_FR) &
> + UART_FR_RXFF) == 0)
> + ;
> + c = bus_space_read_4(pluartconsiot, pluartconsioh, UART_DR);
> + splx(s);
> + return c;
> +}
> +
> +void
> +pluartcnputc(dev_t dev, int c)
> +{
> + int s;
> + s = splhigh();
> + while((bus_space_read_4(pluartconsiot, pluartconsioh, UART_FR) &
> + UART_FR_TXFE) == 0)
> + ;
> + bus_space_write_4(pluartconsiot, pluartconsioh, UART_DR, (uint8_t)c);
> + splx(s);
> +}
> +
> +void
> +pluartcnpollc(dev_t dev, int on)
> +{
> +}
> Index: dev/ic/pluartvar.h
> ===================================================================
> RCS file: dev/ic/pluartvar.h
> diff -N dev/ic/pluartvar.h
> --- /dev/null 1 Jan 1970 00:00:00 -0000
> +++ dev/ic/pluartvar.h 1 Jul 2018 14:29:40 -0000
> @@ -0,0 +1,63 @@
> +/* $OpenBSD$ */
> +/*
> + * Copyright (c) 2014 Patrick Wildt <[email protected]>
> + * Copyright (c) 2005 Dale Rahn <[email protected]>
> + *
> + * Permission to use, copy, modify, and distribute this software for any
> + * purpose with or without fee is hereby granted, provided that the above
> + * copyright notice and this permission notice appear in all copies.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
> + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
> + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
> + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
> + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
> + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
> + */
> +
> +struct pluart_softc {
> + struct device sc_dev;
> + bus_space_tag_t sc_iot;
> + bus_space_handle_t sc_ioh;
> + struct soft_intrhand *sc_si;
> + void *sc_irq;
> + struct tty *sc_tty;
> + struct timeout sc_diag_tmo;
> + struct timeout sc_dtr_tmo;
> + int sc_overflows;
> + int sc_floods;
> + int sc_errors;
> + int sc_halt;
> + u_int16_t sc_ucr1;
> + u_int16_t sc_ucr2;
> + u_int16_t sc_ucr3;
> + u_int16_t sc_ucr4;
> + u_int8_t sc_hwflags;
> +#define COM_HW_NOIEN 0x01
> +#define COM_HW_FIFO 0x02
> +#define COM_HW_SIR 0x20
> +#define COM_HW_CONSOLE 0x40
> + u_int8_t sc_swflags;
> +#define COM_SW_SOFTCAR 0x01
> +#define COM_SW_CLOCAL 0x02
> +#define COM_SW_CRTSCTS 0x04
> +#define COM_SW_MDMBUF 0x08
> +#define COM_SW_PPS 0x10
> + int sc_fifolen;
> +
> + u_int8_t sc_initialize;
> + u_int8_t sc_cua;
> + u_int16_t *sc_ibuf, *sc_ibufp, *sc_ibufhigh, *sc_ibufend;
> +#define UART_IBUFSIZE 128
> +#define UART_IHIGHWATER 100
> + u_int16_t sc_ibufs[2][UART_IBUFSIZE];
> +
> + struct clk *sc_clk;
> +};
> +
> +void pluart_attach_common(struct pluart_softc *, int);
> +int pluart_intr(void *);
> +
> +int pluartcnattach(bus_space_tag_t iot, bus_addr_t iobase, int rate,
> + tcflag_t cflag);
>