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) */