[U-Boot] [PATCH] serial: ns16550: Enhancements to the RX interrupt buffer support

Stefan Roese sr at denx.de
Tue Aug 15 09:33:44 UTC 2017


This patch changes the RX interrupt buffer support in these ways, mostly
suggested by Bin Meng a few weeks ago:

- The RX interrupt buffers size is now configurable via Kconfig
  (default still at 256 bytes)
- For NS16550 devices on the PCI bus, the interrupt number will be
  read from the PCI config space. Please note that this might not
  result in the correct non-zero interrupt number for this PCI
  device, as the UART init code is called very early, currently on
  x86 before the PCI config registers are initialized via U-Boot
- If the interrupt number is not provided, the code falls back to
  the normal polling mode
- The RX interrupt generation is disabled in the UART in the remove
  function

While reworking this RX interrupt buffer support, the "default n" is
also removed from Kconfig as its not needed as pointed out by Bin Meng.
Also, a missing comment for the 'irq' variable is added to the
header.

Signed-off-by: Stefan Roese <sr at denx.de>
Cc: Simon Glass <sjg at chromium.org>
Cc: Bin Meng <bmeng.cn at gmail.com>
Cc: Tom Rini <trini at konsulko.com>
---
 drivers/serial/Kconfig   |  8 +++++++-
 drivers/serial/ns16550.c | 41 +++++++++++++++++++++++++++++++----------
 include/ns16550.h        |  2 +-
 3 files changed, 39 insertions(+), 12 deletions(-)

diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index a8e997834a..1b19b24f10 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -67,13 +67,19 @@ config DM_SERIAL
 config SERIAL_IRQ_BUFFER
 	bool "Enable RX interrupt buffer for serial input"
 	depends on DM_SERIAL
-	default n
 	help
 	  Enable RX interrupt buffer support for the serial driver.
 	  This enables pasting longer strings, even when the RX FIFO
 	  of the UART is not big enough (e.g. 16 bytes on the normal
 	  NS16550).
 
+config SERIAL_IRQ_BUFFER_SIZE
+	int "RX interrupt buffer size"
+	depends on SERIAL_IRQ_BUFFER
+	default 256
+	help
+	  The size of the RX interrupt buffer
+
 config SPL_DM_SERIAL
 	bool "Enable Driver Model for serial drivers in SPL"
 	depends on DM_SERIAL
diff --git a/drivers/serial/ns16550.c b/drivers/serial/ns16550.c
index 607a1b8c1d..a24ba75031 100644
--- a/drivers/serial/ns16550.c
+++ b/drivers/serial/ns16550.c
@@ -453,11 +453,13 @@ int ns16550_serial_probe(struct udevice *dev)
 		/* Allocate the RX buffer */
 		plat->buf = malloc(BUF_COUNT);
 
-		/* Install the interrupt handler */
-		irq_install_handler(plat->irq, ns16550_handle_irq, dev);
+		if (plat->irq) {
+			/* Install the interrupt handler */
+			irq_install_handler(plat->irq, ns16550_handle_irq, dev);
 
-		/* Enable RX interrupts */
-		serial_out(UART_IER_RDI, &com_port->ier);
+			/* Enable RX interrupts */
+			serial_out(UART_IER_RDI, &com_port->ier);
+		}
 	}
 #endif
 
@@ -469,9 +471,13 @@ int ns16550_serial_probe(struct udevice *dev)
 static int ns16550_serial_remove(struct udevice *dev)
 {
 #if CONFIG_IS_ENABLED(SERIAL_IRQ_BUFFER)
-	if (gd->flags & GD_FLG_RELOC) {
-		struct ns16550_platdata *plat = dev->platdata;
+	struct ns16550_platdata *plat = dev->platdata;
+
+	if ((gd->flags & GD_FLG_RELOC) && (plat->irq)) {
+		struct NS16550 *const com_port = dev_get_priv(dev);
 
+		/* Disable RX interrupts */
+		serial_out(CONFIG_SYS_NS16550_IER, &com_port->ier);
 		irq_free_handler(plat->irq);
 	}
 #endif
@@ -504,6 +510,7 @@ int ns16550_serial_ofdata_to_platdata(struct udevice *dev)
 		struct fdt_pci_addr pci_addr;
 		u32 bar;
 		int ret;
+		u8 irq;
 
 		/* we prefer to use a memory-mapped register */
 		ret = fdtdec_get_pci_addr(gd->fdt_blob, dev_of_offset(dev),
@@ -524,6 +531,10 @@ int ns16550_serial_ofdata_to_platdata(struct udevice *dev)
 			return ret;
 
 		addr = bar;
+
+		/* Try to get the PCI interrupt number */
+		dm_pci_read_config8(dev, PCI_INTERRUPT_LINE, &irq);
+		plat->irq = irq;
 	}
 #endif
 
@@ -562,12 +573,22 @@ int ns16550_serial_ofdata_to_platdata(struct udevice *dev)
 		plat->fcr |= UART_FCR_UME;
 
 #if CONFIG_IS_ENABLED(SERIAL_IRQ_BUFFER)
-	plat->irq = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev),
-				   "interrupts", 0);
+	/*
+	 * If the interrupt is not provided via PCI, read the number from
+	 * the DT instead
+	 */
 	if (!plat->irq) {
-		debug("ns16550 interrupt not provided\n");
-		return -EINVAL;
+		plat->irq = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev),
+					   "interrupts", 0);
 	}
+
+	/*
+	 * If no interrupt is provided the RX interrupt buffer code is
+	 * still used, but the interrupt is not enabled and registered.
+	 * The RX buffer code will be usedin polling mode in this case.
+	 */
+	if (!plat->irq)
+		debug("ns16550 interrupt not provided, using polling\n");
 #endif
 
 	return 0;
diff --git a/include/ns16550.h b/include/ns16550.h
index 7e9944d0d9..15f9899d90 100644
--- a/include/ns16550.h
+++ b/include/ns16550.h
@@ -52,6 +52,7 @@
  * @reg_shift:		Shift size of registers (0=byte, 1=16bit, 2=32bit...)
  * @clock:		UART base clock speed in Hz
  *
+ * @irq:		Interrupt number for this UART
  * @buf:		Pointer to the RX interrupt buffer
  * @rd_ptr:		Read pointer in the RX interrupt buffer
  * @wr_ptr:		Write pointer in the RX interrupt buffer
@@ -64,7 +65,6 @@ struct ns16550_platdata {
 	u32 fcr;
 
 	int irq;
-
 	char *buf;
 	int rd_ptr;
 	int wr_ptr;
-- 
2.14.1



More information about the U-Boot mailing list