Platform: Implement UART uninitialize function

This patch introduces an uninitialize function for the UART
peripheral to restore it's default state before passing
execution to runtime image from MCUBoot.

Change-Id: Iaf239b575be82402b9c142e990fb0ea30ffe9a88
Signed-off-by: David Vincze <david.vincze@arm.com>
diff --git a/platform/ext/common/uart_stdout.c b/platform/ext/common/uart_stdout.c
index 75e8b18..7a41f1e 100755
--- a/platform/ext/common/uart_stdout.c
+++ b/platform/ext/common/uart_stdout.c
@@ -77,3 +77,10 @@
     ASSERT_HIGH(ret);

 }

 

+void stdio_uninit(void)

+{

+    int32_t ret = ARM_DRIVER_OK;

+    ret = TFM_DRIVER_STDIO.Uninitialize();

+    ASSERT_HIGH(ret);

+}

+

diff --git a/platform/ext/common/uart_stdout.h b/platform/ext/common/uart_stdout.h
index dcced8a..5d79398 100644
--- a/platform/ext/common/uart_stdout.h
+++ b/platform/ext/common/uart_stdout.h
@@ -35,4 +35,9 @@
  */

 void stdio_init(void);

 

+/**

+ * \brief Uninitializes the STDIO.

+ */

+void stdio_uninit(void);

+

 #endif /* __UART_STDOUT_H__ */

diff --git a/platform/ext/target/musca_a/CMSIS_Driver/Driver_USART.c b/platform/ext/target/musca_a/CMSIS_Driver/Driver_USART.c
index 79e6428..866ea9e 100755
--- a/platform/ext/target/musca_a/CMSIS_Driver/Driver_USART.c
+++ b/platform/ext/target/musca_a/CMSIS_Driver/Driver_USART.c
@@ -88,6 +88,14 @@
     return ARM_DRIVER_OK;
 }
 
+static int32_t ARM_USARTx_Uninitialize(UARTx_Resources* uart_dev)
+{
+    /* Disables and uninitializes generic UART driver */
+    uart_pl011_uninit(uart_dev->dev);
+
+    return ARM_DRIVER_OK;
+}
+
 static int32_t ARM_USARTx_PowerControl(UARTx_Resources* uart_dev,
                                        ARM_POWER_STATE state)
 {
@@ -100,9 +108,8 @@
     case ARM_POWER_FULL:
         /* Nothing to be done */
         return ARM_DRIVER_OK;
-    /* default:  The default is not defined intentionally to force the
-     *           compiler to check that all the enumeration values are
-     *           covered in the switch.*/
+    default:
+        return ARM_DRIVER_ERROR_PARAMETER;
     }
 }
 
@@ -232,8 +239,7 @@
 
 static int32_t ARM_USART0_Uninitialize(void)
 {
-    /* Nothing to be done */
-    return ARM_DRIVER_OK;
+    return ARM_USARTx_Uninitialize(&USART0_DEV);
 }
 
 static int32_t ARM_USART0_PowerControl(ARM_POWER_STATE state)
@@ -330,8 +336,7 @@
 
 static int32_t ARM_USART1_Uninitialize(void)
 {
-    /* Nothing to be done */
-    return ARM_DRIVER_OK;
+    return ARM_USARTx_Uninitialize(&USART1_DEV);
 }
 
 static int32_t ARM_USART1_PowerControl(ARM_POWER_STATE state)
diff --git a/platform/ext/target/musca_a/Native_Driver/uart_pl011_drv.c b/platform/ext/target/musca_a/Native_Driver/uart_pl011_drv.c
index 829e420..01feaa4 100755
--- a/platform/ext/target/musca_a/Native_Driver/uart_pl011_drv.c
+++ b/platform/ext/target/musca_a/Native_Driver/uart_pl011_drv.c
@@ -152,6 +152,19 @@
 #define UART_PL011_UARTDMACR_TX_MASK (                  \
             0x1u<<UART_PL011_UARTDMACR_TXEN_OFF)
 
+/* Default register values of UART PL011 */
+#define UART_PL011_DATA_REG_RESET_VALUE     (0x0u)
+#define UART_PL011_ECR_REG_CLEAR_VALUE      (0xFFu)
+#define UART_PL011_ILPR_REG_RESET_VALUE     (0x0u)
+#define UART_PL011_IBRD_REG_RESET_VALUE     (0x0u)
+#define UART_PL011_FBRD_REG_RESET_VALUE     (0x0u)
+#define UART_PL011_LCR_H_REG_RESET_VALUE    (0x0u)
+#define UART_PL011_CR_REG_RESET_VALUE       (0x0300u)
+#define UART_PL011_IFLS_REG_RESET_VALUE     (0x12u)
+#define UART_PL011_IMSC_REG_RESET_VALUE     (0x0u)
+#define UART_PL011_ICR_REG_CLEAR_VALUE      (0x7FFu)
+#define UART_PL011_DMACR_REG_RESET_VALUE    (0x0u)
+
 static void _uart_pl011_enable(struct _uart_pl011_reg_map_t* p_uart)
 {
     p_uart->uartcr |=  UART_PL011_UARTCR_EN_MASK;
@@ -182,6 +195,11 @@
     return (bool)(p_uart->uartlcr_h & UART_PL011_UARTLCR_H_FEN_MASK);
 }
 
+static bool _uart_pl011_is_busy(struct _uart_pl011_reg_map_t* p_uart)
+{
+    return (bool)(p_uart->uartfr & UART_PL011_UARTFR_BUSYBIT);
+}
+
 static enum uart_pl011_error_t _uart_pl011_set_baudrate(
                     struct _uart_pl011_reg_map_t* p_uart,
                     uint32_t clk, uint32_t baudrate)
@@ -318,6 +336,27 @@
     }
 }
 
+static void _uart_pl011_reset_regs(struct _uart_pl011_reg_map_t* p_uart)
+{
+    /* Restore the default value of UART registers, the registers which
+     * are not listed below are Read-Only */
+
+    /* Will disable the UART */
+    p_uart->uartcr      = UART_PL011_CR_REG_RESET_VALUE;
+    p_uart->uartdr      = UART_PL011_DATA_REG_RESET_VALUE;
+    /* Clear all the errors */
+    p_uart->uartecr     = UART_PL011_ECR_REG_CLEAR_VALUE;
+    p_uart->uartilpr    = UART_PL011_ILPR_REG_RESET_VALUE;
+    p_uart->uartibrd    = UART_PL011_IBRD_REG_RESET_VALUE;
+    p_uart->uartfbrd    = UART_PL011_FBRD_REG_RESET_VALUE;
+    p_uart->uartlcr_h   = UART_PL011_LCR_H_REG_RESET_VALUE;
+    p_uart->uartifls    = UART_PL011_IFLS_REG_RESET_VALUE;
+    p_uart->uartimsc    = UART_PL011_IMSC_REG_RESET_VALUE;
+    /* Clear all the interrupts */
+    p_uart->uarticr     = UART_PL011_ICR_REG_CLEAR_VALUE;
+    p_uart->uartdmacr   = UART_PL011_DMACR_REG_RESET_VALUE;
+}
+
 enum uart_pl011_error_t uart_pl011_init(struct uart_pl011_dev_t* dev,
                     uint32_t uart_clk)
 {
@@ -364,7 +403,10 @@
     struct _uart_pl011_reg_map_t* p_uart =
         (struct _uart_pl011_reg_map_t*)dev->cfg->base;
 
-    _uart_pl011_disable(p_uart);
+    while(_uart_pl011_is_busy(p_uart));
+
+    /* Disable and restore the default configuration of the peripheral */
+    _uart_pl011_reset_regs(p_uart);
 
     dev->data->state = UART_PL011_UNINITIALIZED;