diff options
Diffstat (limited to 'core/arch/arm/plat-rzn1/rzn1_ns16550.c')
-rw-r--r-- | core/arch/arm/plat-rzn1/rzn1_ns16550.c | 160 |
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; +} |