aboutsummaryrefslogtreecommitdiff
path: root/core/arch/arm/plat-rzn1/rzn1_ns16550.c
diff options
context:
space:
mode:
Diffstat (limited to 'core/arch/arm/plat-rzn1/rzn1_ns16550.c')
-rw-r--r--core/arch/arm/plat-rzn1/rzn1_ns16550.c160
1 files changed, 160 insertions, 0 deletions
diff --git a/core/arch/arm/plat-rzn1/rzn1_ns16550.c b/core/arch/arm/plat-rzn1/rzn1_ns16550.c
new file mode 100644
index 00000000..0bf7e52d
--- /dev/null
+++ b/core/arch/arm/plat-rzn1/rzn1_ns16550.c
@@ -0,0 +1,160 @@
+// SPDX-License-Identifier: BSD-2-Clause
+/*
+ * Copyright (C) 2015 Freescale Semiconductor, Inc.
+ * Copyright (c) 2017, Linaro Limited
+ * Copyright (c) 2018, Schneider Electric
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "rzn1_ns16550.h"
+#include <io.h>
+#include <keep.h>
+#include <initcall.h>
+#include <util.h>
+#include <drivers/gic.h>
+
+#define IT_CONSOLE_UART (GIC_PPI + 6)
+
+// RZN1 uart register defines
+#define UART_RBR 0x00
+#define UART_THR 0x00
+#define UART_IER 0x04
+#define UART_IIR 0x08
+#define UART_FCR 0x08
+#define UART_LCR 0x0c
+#define UART_MCR 0x10
+#define UART_LSR 0x14
+#define UART_MSR 0x18
+#define UART_SPR 0x1c
+
+/* uart status register bits */
+#define UART_IER_DR 0x01 /* Data Ready */
+#define UART_FCR_EN 0x01 /* Enable */
+#define UART_LSR_DR 0x01 /* Data Ready */
+#define UART_LSR_THRE 0x20 /* Transmit-hold-register empty */
+
+static vaddr_t chip_to_base(struct serial_chip *chip)
+{
+ struct rzn1_ns16550_data *pd =
+ container_of(chip, struct rzn1_ns16550_data, chip);
+
+ return io_pa_or_va(&pd->base);
+}
+
+static void rzn1_ns16550_flush(struct serial_chip *chip)
+{
+ vaddr_t base = chip_to_base(chip);
+
+ while ((read8(base + UART_LSR) & UART_LSR_THRE) == 0)
+ ;
+}
+
+static void rzn1_ns16550_putc(struct serial_chip *chip, int ch)
+{
+ vaddr_t base = chip_to_base(chip);
+
+ rzn1_ns16550_flush(chip);
+
+ /* write out charset to Transmit-hold-register */
+ write32(ch, base + UART_THR);
+}
+
+static int rzn1_ns16550_getc(struct serial_chip *chip)
+{
+ struct rzn1_ns16550_data *pd;
+
+ pd = container_of(chip, struct rzn1_ns16550_data, chip);
+ if ( pd->rxput == pd->rxget ) return -1;
+
+ return pd->rxbuf[pd->rxget++];
+}
+
+static bool rzn1_ns16550_tstc(struct serial_chip *chip)
+{
+ struct rzn1_ns16550_data *pd;
+
+ pd = container_of(chip, struct rzn1_ns16550_data, chip);
+ return ( pd->rxput != pd->rxget );
+}
+
+static enum itr_return console_itr_cb(struct itr_handler *h)
+{
+ struct rzn1_ns16550_data *pd = h->data;
+ vaddr_t base = io_pa_or_va(&pd->base); // sb. always va !!
+ unsigned int cause = read8(base + UART_IIR) & 15;
+
+ if ( cause == 4 ) {
+ while (read8(base + UART_LSR) & UART_LSR_DR) {
+ unsigned char byte = read32(base + UART_RBR);
+ unsigned char next = pd->rxput + 1;
+ if ( next != pd->rxget ) {
+ pd->rxbuf[pd->rxput] = byte;
+ pd->rxput = next;
+ byte = pd->rxput - pd->rxget;
+ }
+ }
+ } else {
+ DMSG("Unexpected UART IRQ %u", cause);
+ }
+ return ITRR_HANDLED;
+}
+
+static struct itr_handler console_itr = {
+ .flags = ITRF_TRIGGER_LEVEL,
+ .handler = console_itr_cb,
+};
+KEEP_PAGER(console_itr);
+
+static TEE_Result init_console_itr(void)
+{
+ itr_add(&console_itr);
+ itr_enable(console_itr.it);
+ return TEE_SUCCESS;
+}
+driver_init(init_console_itr);
+
+static const struct serial_ops rzn1_ns16550_ops = {
+ .flush = rzn1_ns16550_flush,
+ .putc = rzn1_ns16550_putc,
+ .getchar = rzn1_ns16550_getc,
+ .have_rx_data = rzn1_ns16550_tstc,
+};
+KEEP_PAGER(rzn1_ns16550_ops);
+
+void rzn1_ns16550_init(struct rzn1_ns16550_data *pd, paddr_t base, int irq)
+{
+ vaddr_t vbase;
+ pd->base.pa = base;
+ pd->chip.ops = &rzn1_ns16550_ops;
+
+ /* Uart driver is not shared with normal world, it is managed here */
+ vbase = io_pa_or_va(&pd->base);
+ write32(UART_FCR_EN, vbase + UART_FCR);
+ write32(UART_IER_DR, vbase + UART_IER);
+
+ /* Insert into nterrupt system */
+ console_itr.it = irq;
+ console_itr.data = pd;
+}