drivers: serial: ns16550: fill full fifo

Put the maximum number of bytes into Tx FIFO in the fill_fifo routine
to reduce CPU usage.

Previously, the THRE bit was checked in a loop, but, according to doc -
"In the FIFO mode, it is set when the XMIT FIFO is empty, and is
cleared when at least one byte is written to XMIT FIFO.", so only one
byte was transferred every interrupt. That was generating a big amount
of interrupts, which consumes CPU time.

Signed-off-by: Dawid Niedzwiecki <dn@semihalf.com>
diff --git a/drivers/serial/uart_ns16550.c b/drivers/serial/uart_ns16550.c
index 484ed60..707a0ad 100644
--- a/drivers/serial/uart_ns16550.c
+++ b/drivers/serial/uart_ns16550.c
@@ -87,6 +87,7 @@
 #define IIR_LS    0x06 /* receiver line status interrupt */
 #define IIR_MASK  0x07 /* interrupt id bits mask  */
 #define IIR_ID    0x06 /* interrupt ID mask without NIP */
+#define IIR_FE    0xC0 /* FIFO mode enabled */
 
 /* equates for FIFO control register */
 
@@ -262,6 +263,7 @@
 #endif
 	struct uart_config uart_config;
 	struct k_spinlock lock;
+	uint8_t fifo_size;
 
 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
 	uint8_t iir_cache;	/**< cache of IIR since it clears when read */
@@ -464,6 +466,16 @@
 #endif
 		);
 
+	if ((INBYTE(IIR(dev)) & IIR_FE) == IIR_FE) {
+#ifdef CONFIG_UART_NS16750
+		dev_data->fifo_size = 64;
+#else
+		dev_data->fifo_size = 16;
+#endif
+	} else {
+		dev_data->fifo_size = 1;
+	}
+
 	/* clear the port */
 	INBYTE(RDR(dev));
 
@@ -601,7 +613,7 @@
 	int i;
 	k_spinlock_key_t key = k_spin_lock(&DEV_DATA(dev)->lock);
 
-	for (i = 0; (i < size) && (INBYTE(LSR(dev)) & LSR_THRE) != 0; i++) {
+	for (i = 0; (i < size) && (i < DEV_DATA(dev)->fifo_size); i++) {
 		OUTBYTE(THR(dev), tx_data[i]);
 	}