Hi, the Synopsys Designware UART, which is used on a bunch of SoCs, is mostly compatible to com(4). Currently we use sxiuart, a driver based on another driver, modified to work on sunxi. I would like to replace sxiuart with com(4). This diff disables sxiuart and implements the Allwinner and Synopsys specific code in the existing com(4) wrapper for OMAP. In a follow up diff we can remove sxiuart completely. Also, we might want to move it to some other folder and/or rename it. That should be part of a follow up diff.
There's only a slight twist: The controller has a busy interrupt we need to handle. Otherwise we will get flooded with interrupts. mglocker@ is currently experiencing that issue with the sxiuart driver as well. This diff also implements this busy indicator in com(4). I guess the com(4) and the armv7 changes should be committed separately. This diff combines both to show what it will be used for. I tested it on BBB and Lamobo R1. mglocker@ reported success on his sunxi-based CHIP. ok? Comments? Patrick diff --git a/sys/arch/armv7/armv7/platform.c b/sys/arch/armv7/armv7/platform.c index f122c1f..390d907 100644 --- a/sys/arch/armv7/armv7/platform.c +++ b/sys/arch/armv7/armv7/platform.c @@ -37,7 +37,6 @@ static struct armv7_platform *platform; void exuart_init_cons(void); void imxuart_init_cons(void); void omapuart_init_cons(void); -void sxiuart_init_cons(void); void pl011_init_cons(void); struct armv7_platform *imx_platform_match(void); @@ -102,7 +101,6 @@ platform_init_cons(void) exuart_init_cons(); imxuart_init_cons(); omapuart_init_cons(); - sxiuart_init_cons(); pl011_init_cons(); } diff --git a/sys/arch/armv7/conf/GENERIC b/sys/arch/armv7/conf/GENERIC index c3f0311..5ddaea7 100644 --- a/sys/arch/armv7/conf/GENERIC +++ b/sys/arch/armv7/conf/GENERIC @@ -91,7 +91,7 @@ sxiccmu* at sunxi? # Clock Control Module/Unit sxitimer* at sunxi? sxidog* at sunxi? # watchdog timer sxirtc* at sunxi? # Real Time Clock -sxiuart* at fdt? # onboard UARTs +#sxiuart* at fdt? # onboard UARTs sxie* at fdt? ahci* at sunxi? # AHCI/SATA (shim) ehci* at sunxi? # EHCI (shim) diff --git a/sys/arch/armv7/conf/RAMDISK b/sys/arch/armv7/conf/RAMDISK index 4a3c53e..36fb0dc 100644 --- a/sys/arch/armv7/conf/RAMDISK +++ b/sys/arch/armv7/conf/RAMDISK @@ -90,7 +90,7 @@ sxiccmu* at sunxi? # Clock Control Module/Unit sxitimer* at sunxi? sxidog* at sunxi? # watchdog timer sxirtc* at sunxi? # Real Time Clock -sxiuart* at fdt? # onboard UARTs +#sxiuart* at fdt? # onboard UARTs sxie* at fdt? ahci* at sunxi? # AHCI/SATA (shim) ehci* at sunxi? # EHCI (shim) diff --git a/sys/arch/armv7/omap/omap_com.c b/sys/arch/armv7/omap/omap_com.c index 20a51b4..5aa82f7 100644 --- a/sys/arch/armv7/omap/omap_com.c +++ b/sys/arch/armv7/omap/omap_com.c @@ -76,14 +76,23 @@ omapuart_init_cons(void) { struct fdt_reg reg; void *node; + int freq = 48000000; - if ((node = fdt_find_cons("ti,omap3-uart")) == NULL) - if ((node = fdt_find_cons("ti,omap4-uart")) == NULL) + if ((node = fdt_find_cons("ti,omap3-uart")) == NULL && + (node = fdt_find_cons("ti,omap4-uart")) == NULL && + (node = fdt_find_cons("snps,dw-apb-uart")) == NULL) return; if (fdt_get_reg(node, 0, ®)) return; - comcnattach(&armv7_a4x_bs_tag, reg.addr, comcnspeed, 48000000, + if ((node = fdt_find_node("/")) != NULL && + (fdt_is_compatible(node, "allwinner,sun4i-a10") || + fdt_is_compatible(node, "allwinner,sun5i-a10s") || + fdt_is_compatible(node, "allwinner,sun5i-r8") || + fdt_is_compatible(node, "allwinner,sun7i-a20"))) + freq = 24000000; + + comcnattach(&armv7_a4x_bs_tag, reg.addr, comcnspeed, freq, comcnmode); comdefaultrate = comcnspeed; } @@ -94,7 +103,8 @@ omapuart_match(struct device *parent, void *match, void *aux) struct fdt_attach_args *faa = aux; return (OF_is_compatible(faa->fa_node, "ti,omap3-uart") || - OF_is_compatible(faa->fa_node, "ti,omap4-uart")); + OF_is_compatible(faa->fa_node, "ti,omap4-uart") || + OF_is_compatible(faa->fa_node, "snps,dw-apb-uart")); } void @@ -102,7 +112,7 @@ omapuart_attach(struct device *parent, struct device *self, void *aux) { struct com_softc *sc = (struct com_softc *)self; struct fdt_attach_args *faa = aux; - int irq; + int irq, node; if (faa->fa_nreg != 1 || (faa->fa_nintr != 1 && faa->fa_nintr != 3)) return; @@ -123,7 +133,21 @@ omapuart_attach(struct device *parent, struct device *self, void *aux) return; } - sitara_cm_pinctrlbyname(faa->fa_node, "default"); + if (OF_is_compatible(faa->fa_node, "ti,omap3-uart") || + OF_is_compatible(faa->fa_node, "ti,omap4-uart")) + sitara_cm_pinctrlbyname(faa->fa_node, "default"); + + if (OF_is_compatible(faa->fa_node, "snps,dw-apb-uart")) { + sc->sc_hwflags |= COM_HW_IIR_BUSY; + sc->sc_uarttype = COM_UART_16550; + } + + if ((node = OF_finddevice("/")) != 0 && + (OF_is_compatible(node, "allwinner,sun4i-a10") || + OF_is_compatible(node, "allwinner,sun5i-a10s") || + OF_is_compatible(node, "allwinner,sun5i-r8") || + OF_is_compatible(node, "allwinner,sun7i-a20"))) + sc->sc_frequency = 24000000; com_attach_subr(sc); diff --git a/sys/dev/ic/com.c b/sys/dev/ic/com.c index 000eea3..0bf7181 100644 --- a/sys/dev/ic/com.c +++ b/sys/dev/ic/com.c @@ -1219,12 +1219,30 @@ comintr(void *arg) bus_space_tag_t iot = sc->sc_iot; bus_space_handle_t ioh = sc->sc_ioh; struct tty *tp; - u_char lsr, data, msr, delta; + u_char iir, lsr, data, msr, delta; + int timeout; + + iir = bus_space_read_1(iot, ioh, com_iir); + + /* Handle ns16750-specific busy interrupt. */ + if (ISSET(sc->sc_hwflags, COM_HW_IIR_BUSY) && + (iir & IIR_BUSY) == IIR_BUSY) { + for (timeout = 10000; + (bus_space_read_1(iot, ioh, com_usr) & 0x1) != 0; + timeout--) + if (timeout <= 0) { + printf("%s: timeout while waiting for BUSY " + "interrupt acknowledge\n", + sc->sc_dev.dv_xname); + return (0); + } + iir = bus_space_read_1(iot, ioh, com_iir); + } if (!sc->sc_tty) return (0); /* Can't do squat. */ - if (ISSET(bus_space_read_1(iot, ioh, com_iir), IIR_NOPEND)) + if (ISSET(iir, IIR_NOPEND)) return (0); tp = sc->sc_tty; diff --git a/sys/dev/ic/comreg.h b/sys/dev/ic/comreg.h index 6084698..d2e52a0 100644 --- a/sys/dev/ic/comreg.h +++ b/sys/dev/ic/comreg.h @@ -82,6 +82,7 @@ #define IIR_MLSC 0x0 /* Modem status */ #define IIR_NOPEND 0x1 /* No pending interrupts */ #define IIR_FIFO_MASK 0xc0 /* set if FIFOs are enabled */ +#define IIR_BUSY 0x7 /* NS16750: Busy indicator */ /* fifo control register */ #define FIFO_ENABLE 0x01 /* Turn the FIFO on */ diff --git a/sys/dev/ic/comvar.h b/sys/dev/ic/comvar.h index 893ffde..5f7e5fe 100644 --- a/sys/dev/ic/comvar.h +++ b/sys/dev/ic/comvar.h @@ -106,6 +106,7 @@ struct com_softc { u_char sc_hwflags; #define COM_HW_NOIEN 0x01 #define COM_HW_FIFO 0x02 +#define COM_HW_IIR_BUSY 0x04 #define COM_HW_SIR 0x20 #define COM_HW_CONSOLE 0x40 #define COM_HW_KGDB 0x80 @@ -117,7 +118,7 @@ struct com_softc { #define COM_SW_PPS 0x10 #define COM_SW_DEAD 0x20 int sc_fifolen; - u_char sc_msr, sc_mcr, sc_lcr, sc_ier; + u_char sc_msr, sc_mcr, sc_lcr, sc_ier, sc_iir; u_char sc_dtr; u_char sc_cua; diff --git a/sys/dev/ic/ns16550reg.h b/sys/dev/ic/ns16550reg.h index 5db1a27..d8eb8b3 100644 --- a/sys/dev/ic/ns16550reg.h +++ b/sys/dev/ic/ns16550reg.h @@ -50,3 +50,4 @@ #define com_lsr 5 /* line status register (R/W) */ #define com_msr 6 /* modem status register (R/W) */ #define com_scratch 7 /* scratch register (R/W) */ +#define com_usr 31 /* NS16750: status register (R) */