feat(nuvoton): added support for npcm845x chip

Initial version

Signed-off-by: Margarita Glushkin <rutigl@gmail.com>
Change-Id: If433d325a90b519ae5f02411865bffd368ff2824
diff --git a/plat/nuvoton/npcm845x/npcm845x_serial_port.c b/plat/nuvoton/npcm845x/npcm845x_serial_port.c
new file mode 100644
index 0000000..946e9d0
--- /dev/null
+++ b/plat/nuvoton/npcm845x/npcm845x_serial_port.c
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2015-2023, ARM Limited and Contributors. All rights reserved.
+ *
+ * Copyright (C) 2017-2023 Nuvoton Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdbool.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/arm/gicv2.h>
+#include <drivers/delay_timer.h>
+#include <drivers/generic_delay_timer.h>
+#include <lib/mmio.h>
+#include <lib/psci/psci.h>
+#include <npcm845x_clock.h>
+#include <npcm845x_gcr.h>
+#include <npcm845x_lpuart.h>
+#include <plat_npcm845x.h>
+
+
+uintptr_t npcm845x_get_base_uart(UART_DEV_T devNum)
+{
+	return 0xF0000000 + devNum * 0x1000;
+}
+
+uintptr_t npcm845x_get_base_clk(void)
+{
+	return 0xF0801000;
+}
+
+uintptr_t npcm845x_get_base_gcr(void)
+{
+	return 0xF0800000;
+}
+
+void npcm845x_wait_for_empty(int uart_n)
+{
+	volatile struct npcmX50_uart *uart = (struct npcmX50_uart *)npcm845x_get_base_uart(uart_n);
+
+	while ((*(uint8_t *)(uintptr_t)(&uart->lsr) & 0x40) == 0x00) {
+/*
+ * wait for THRE (Transmitter Holding Register Empty)
+ * and TSR (Transmitter Shift Register) to be empty.
+ * Some delay. notice needed some delay so UartUpdateTool
+ * will pass w/o error log
+ */
+	}
+
+	volatile int delay;
+
+	for (delay = 0; delay < 10000; delay++) {
+		;
+	}
+}
+
+int UART_Init(UART_DEV_T devNum,  UART_BAUDRATE_T baudRate)
+{
+	uint32_t val = 0;
+	uintptr_t clk_base = npcm845x_get_base_clk();
+	uintptr_t gcr_base =  npcm845x_get_base_gcr();
+	uintptr_t uart_base = npcm845x_get_base_uart(devNum);
+	volatile struct npcmX50_uart *uart = (struct npcmX50_uart *)uart_base;
+
+/* Use  CLKREF to be independent of CPU frequency */
+	volatile struct clk_ctl *clk_ctl_obj = (struct clk_ctl *)clk_base;
+	volatile struct npcm845x_gcr *gcr_ctl_obj =
+		(struct npcm845x_gcr *)gcr_base;
+
+	clk_ctl_obj->clksel = clk_ctl_obj->clksel & ~(0x3 << 8);
+	clk_ctl_obj->clksel = clk_ctl_obj->clksel | (0x2 << 8);
+
+	/* Set devider according to baudrate */
+	clk_ctl_obj->clkdiv1 =
+		(unsigned int)(clk_ctl_obj->clkdiv1 & ~(0x1F << 16));
+
+	/* clear bits 11-15 - set value 0 */
+	if (devNum == UART3_DEV) {
+		clk_ctl_obj->clkdiv2 =
+			(unsigned int)(clk_ctl_obj->clkdiv2 & ~(0x1F << 11));
+	}
+
+	npcm845x_wait_for_empty(devNum);
+
+	val = (uint32_t)LCR_WLS_8bit;
+	mmio_write_8((uintptr_t)&uart->lcr, (uint8_t)val);
+
+	/* disable all interrupts */
+	mmio_write_8((uintptr_t)&uart->ier, 0);
+
+	/*
+	 * Set the RX FIFO trigger level, reset RX, TX FIFO
+	 */
+	val = (uint32_t)(FCR_FME | FCR_RFR | FCR_TFR | FCR_RFITL_4B);
+
+	/* reset TX and RX FIFO */
+	mmio_write_8((uintptr_t)(&uart->fcr), (uint8_t)val);
+
+	/* Set port for 8 bit, 1 stop, no parity */
+	val = (uint32_t)LCR_WLS_8bit;
+
+	/* Set DLAB bit; Accesses the Divisor Latch Registers (DLL, DLM). */
+	val |= 0x80;
+	mmio_write_8((uintptr_t)(&uart->lcr), (uint8_t)val);
+
+	/* Baud Rate = UART Clock 24MHz / (16 * (11+2)) = 115384 */
+	mmio_write_8((uintptr_t)(&uart->dll), 11);
+	mmio_write_8((uintptr_t)(&uart->dlm), 0x00);
+
+	val = mmio_read_8((uintptr_t)&uart->lcr);
+
+	/* Clear DLAB bit; Accesses RBR, THR or IER registers. */
+	val &= 0x7F;
+	mmio_write_8((uintptr_t)(&uart->lcr), (uint8_t)val);
+
+	if (devNum == UART0_DEV) {
+		gcr_ctl_obj->mfsel4 &= ~(1 << 1);
+		gcr_ctl_obj->mfsel1 |= 1 << 9;
+	} else if (devNum == UART3_DEV) {
+		/* Pin Mux */
+		gcr_ctl_obj->mfsel4 &= ~(1 << 1);
+		gcr_ctl_obj->mfsel1 |= 1 << 11;
+		gcr_ctl_obj->spswc &= (7 << 0);
+		gcr_ctl_obj->spswc |= (2 << 0);
+	} else {
+		/* halt */
+		while (1) {
+			;
+		}
+	}
+
+	return 0;
+}