[sw, dif] Improve UART initialisation routine

This change allows to specify the behaviour of the UART initialisation
routine. It might be desirable to keep the peripheral configuration
state after the jump from boot_rom to flash.

Fixes #1505

Signed-off-by: Silvestrs Timofejevs <silvestrst@lowrisc.org>
diff --git a/sw/device/lib/dif/dif_uart.c b/sw/device/lib/dif/dif_uart.c
index 7c4e601..a555464 100644
--- a/sw/device/lib/dif/dif_uart.c
+++ b/sw/device/lib/dif/dif_uart.c
@@ -12,6 +12,8 @@
 #define UART_RX_FIFO_SIZE_BYTES 32u
 #define UART_TX_FIFO_SIZE_BYTES 32u
 
+#define UART_INTR_STATE_MASK 0xffffffffu
+
 static bool uart_tx_full(const dif_uart_t *uart) {
   return mmio_region_get_bit32(uart->base_addr, UART_STATUS_REG_OFFSET,
                                UART_STATUS_TXFULL);
@@ -80,6 +82,19 @@
   return true;
 }
 
+static void uart_reset(const dif_uart_t *uart) {
+  mmio_region_write32(uart->base_addr, UART_CTRL_REG_OFFSET, 0u);
+  // Write to the relevant bits clears the FIFOs
+  mmio_region_write32(
+      uart->base_addr, UART_FIFO_CTRL_REG_OFFSET,
+      (1u << UART_FIFO_CTRL_RXRST) | (1u << UART_FIFO_CTRL_TXRST));
+  mmio_region_write32(uart->base_addr, UART_OVRD_REG_OFFSET, 0u);
+  mmio_region_write32(uart->base_addr, UART_TIMEOUT_CTRL_REG_OFFSET, 0u);
+  mmio_region_write32(uart->base_addr, UART_INTR_ENABLE_REG_OFFSET, 0u);
+  mmio_region_write32(uart->base_addr, UART_INTR_STATE_REG_OFFSET,
+                      UART_INTR_STATE_MASK);
+}
+
 /**
  * Performs fundamental UART configuration.
  */
@@ -98,6 +113,9 @@
     return false;
   }
 
+  // Must be called before the first write to any of the UART registers
+  uart_reset(uart);
+
   // Set baudrate, enable RX and TX, configure parity
   uint32_t reg = (nco_masked << UART_CTRL_NCO_OFFSET);
   reg |= (1u << UART_CTRL_TX);