1*1bb92983SJerome Forissier // SPDX-License-Identifier: BSD-2-Clause 23e18f934SJerome Forissier /* 33e18f934SJerome Forissier * Copyright (c) 2016, Linaro Limited 43e18f934SJerome Forissier * All rights reserved. 53e18f934SJerome Forissier * 63e18f934SJerome Forissier * Redistribution and use in source and binary forms, with or without 73e18f934SJerome Forissier * modification, are permitted provided that the following conditions are met: 83e18f934SJerome Forissier * 93e18f934SJerome Forissier * 1. Redistributions of source code must retain the above copyright notice, 103e18f934SJerome Forissier * this list of conditions and the following disclaimer. 113e18f934SJerome Forissier * 123e18f934SJerome Forissier * 2. Redistributions in binary form must reproduce the above copyright notice, 133e18f934SJerome Forissier * this list of conditions and the following disclaimer in the documentation 143e18f934SJerome Forissier * and/or other materials provided with the distribution. 153e18f934SJerome Forissier * 163e18f934SJerome Forissier * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 173e18f934SJerome Forissier * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 183e18f934SJerome Forissier * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 193e18f934SJerome Forissier * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 203e18f934SJerome Forissier * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 213e18f934SJerome Forissier * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 223e18f934SJerome Forissier * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 233e18f934SJerome Forissier * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 243e18f934SJerome Forissier * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 253e18f934SJerome Forissier * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 263e18f934SJerome Forissier * POSSIBILITY OF SUCH DAMAGE. 273e18f934SJerome Forissier */ 28ed7617dfSJerome Forissier #include <assert.h> 293e18f934SJerome Forissier #include <drivers/hi16xx_uart.h> 303e18f934SJerome Forissier #include <io.h> 318d94060aSEtienne Carriere #include <keep.h> 32ed7617dfSJerome Forissier #include <mm/core_mmu.h> 33ed7617dfSJerome Forissier #include <util.h> 343e18f934SJerome Forissier 353e18f934SJerome Forissier /* Register offsets */ 363e18f934SJerome Forissier 373e18f934SJerome Forissier #define UART_RBR 0x00 /* RX data buffer register */ 383e18f934SJerome Forissier #define UART_THR 0x00 /* TX data buffer register */ 393e18f934SJerome Forissier #define UART_DLL 0x00 /* Lower-bit frequency divider register */ 403e18f934SJerome Forissier 413e18f934SJerome Forissier #define UART_IEL 0x04 /* Interrupt enable register */ 423e18f934SJerome Forissier #define UART_DLH 0x04 /* Upper-bit frequency divider register */ 433e18f934SJerome Forissier 443e18f934SJerome Forissier #define UART_FCR 0x08 /* FIFO control register */ 453e18f934SJerome Forissier 463e18f934SJerome Forissier #define UART_LCR 0x0C /* Line control register */ 473e18f934SJerome Forissier 483e18f934SJerome Forissier #define UART_LSR 0x14 /* Line status register */ 493e18f934SJerome Forissier 503e18f934SJerome Forissier #define UART_USR 0x7C /* Status register */ 513e18f934SJerome Forissier 523e18f934SJerome Forissier /* 533e18f934SJerome Forissier * Line control register 543e18f934SJerome Forissier */ 553e18f934SJerome Forissier 563e18f934SJerome Forissier /* Data length selection */ 573e18f934SJerome Forissier #define UART_LCR_DLS5 0x0 /* 5 bits */ 583e18f934SJerome Forissier #define UART_LCR_DLS6 0x1 /* 6 bits */ 593e18f934SJerome Forissier #define UART_LCR_DLS7 0x2 /* 7 bits */ 603e18f934SJerome Forissier #define UART_LCR_DLS8 0x3 /* 8 bits */ 613e18f934SJerome Forissier 623e18f934SJerome Forissier /* Enable access to UART_DLL and UART_DLH */ 633e18f934SJerome Forissier #define UART_LCR_DLAB 0x80 643e18f934SJerome Forissier 653e18f934SJerome Forissier /* 663e18f934SJerome Forissier * FIFO control register 673e18f934SJerome Forissier */ 683e18f934SJerome Forissier 693e18f934SJerome Forissier #define UART_FCR_FIFO_EN 0x1 /* Enable FIFO (depth: 32 bytes) */ 703e18f934SJerome Forissier #define UART_FCR_RX_FIFO_RST 0x2 /* Clear receive FIFO (auto reset) */ 713e18f934SJerome Forissier #define UART_FCR_TX_FIFO_RST 0x4 /* Clear send FIFO (auto reset) */ 723e18f934SJerome Forissier 733e18f934SJerome Forissier 743e18f934SJerome Forissier /* 753e18f934SJerome Forissier * Status register 763e18f934SJerome Forissier */ 773e18f934SJerome Forissier 783e18f934SJerome Forissier #define UART_USR_BUSY_BIT 0 /* 0: idle/non-activated, 1: busy */ 793e18f934SJerome Forissier #define UART_USR_TFNF_BIT 1 /* Transmit FIFO not full bit */ 803e18f934SJerome Forissier #define UART_USR_TFE_BIT 2 /* Transmit FIFO empty bit */ 813e18f934SJerome Forissier #define UART_USR_RFNE_BIT 3 /* Receive FIFO not empty bit */ 823e18f934SJerome Forissier #define UART_USR_RFF_BIT 4 /* Receive FIFO full bit */ 833e18f934SJerome Forissier 84ed7617dfSJerome Forissier static vaddr_t chip_to_base(struct serial_chip *chip) 853e18f934SJerome Forissier { 86ed7617dfSJerome Forissier struct hi16xx_uart_data *pd = 87ed7617dfSJerome Forissier container_of(chip, struct hi16xx_uart_data, chip); 88ed7617dfSJerome Forissier 89ed7617dfSJerome Forissier return io_pa_or_va(&pd->base); 90ed7617dfSJerome Forissier } 91ed7617dfSJerome Forissier 92ed7617dfSJerome Forissier static void hi16xx_uart_flush(struct serial_chip *chip) 93ed7617dfSJerome Forissier { 94ed7617dfSJerome Forissier vaddr_t base = chip_to_base(chip); 95ed7617dfSJerome Forissier 963e18f934SJerome Forissier while (!(read32(base + UART_USR) & UART_USR_TFE_BIT)) 973e18f934SJerome Forissier ; 983e18f934SJerome Forissier } 993e18f934SJerome Forissier 100ed7617dfSJerome Forissier static void hi16xx_uart_putc(struct serial_chip *chip, int ch) 101ed7617dfSJerome Forissier { 102ed7617dfSJerome Forissier vaddr_t base = chip_to_base(chip); 103ed7617dfSJerome Forissier 104ed7617dfSJerome Forissier /* Wait until TX FIFO is empty */ 105ed7617dfSJerome Forissier while (!(read32(base + UART_USR) & UART_USR_TFE_BIT)) 106ed7617dfSJerome Forissier ; 107ed7617dfSJerome Forissier 108ed7617dfSJerome Forissier /* Put character into TX FIFO */ 109ed7617dfSJerome Forissier write32(ch & 0xFF, base + UART_THR); 110ed7617dfSJerome Forissier } 111ed7617dfSJerome Forissier 112ed7617dfSJerome Forissier static bool hi16xx_uart_have_rx_data(struct serial_chip *chip) 113ed7617dfSJerome Forissier { 114ed7617dfSJerome Forissier vaddr_t base = chip_to_base(chip); 115ed7617dfSJerome Forissier 116ed7617dfSJerome Forissier return (read32(base + UART_USR) & UART_USR_RFNE_BIT); 117ed7617dfSJerome Forissier } 118ed7617dfSJerome Forissier 119ed7617dfSJerome Forissier static int hi16xx_uart_getchar(struct serial_chip *chip) 120ed7617dfSJerome Forissier { 121ed7617dfSJerome Forissier vaddr_t base = chip_to_base(chip); 122ed7617dfSJerome Forissier 123ed7617dfSJerome Forissier while (!hi16xx_uart_have_rx_data(chip)) 124ed7617dfSJerome Forissier ; 125ed7617dfSJerome Forissier return read32(base + UART_RBR) & 0xFF; 126ed7617dfSJerome Forissier } 127ed7617dfSJerome Forissier 128ed7617dfSJerome Forissier static const struct serial_ops hi16xx_uart_ops = { 129ed7617dfSJerome Forissier .flush = hi16xx_uart_flush, 130ed7617dfSJerome Forissier .getchar = hi16xx_uart_getchar, 131ed7617dfSJerome Forissier .have_rx_data = hi16xx_uart_have_rx_data, 132ed7617dfSJerome Forissier .putc = hi16xx_uart_putc, 133ed7617dfSJerome Forissier }; 1348d94060aSEtienne Carriere KEEP_PAGER(hi16xx_uart_ops); 135ed7617dfSJerome Forissier 136ed7617dfSJerome Forissier void hi16xx_uart_init(struct hi16xx_uart_data *pd, paddr_t base, 137ed7617dfSJerome Forissier uint32_t uart_clk, uint32_t baud_rate) 1383e18f934SJerome Forissier { 1393e18f934SJerome Forissier uint16_t freq_div = uart_clk / (16 * baud_rate); 1403e18f934SJerome Forissier 141ed7617dfSJerome Forissier pd->base.pa = base; 142ed7617dfSJerome Forissier pd->chip.ops = &hi16xx_uart_ops; 143ed7617dfSJerome Forissier 14430376c57SJerome Forissier /* Enable (and clear) FIFOs */ 14530376c57SJerome Forissier write32(UART_FCR_FIFO_EN, base + UART_FCR); 1463e18f934SJerome Forissier 1473e18f934SJerome Forissier /* Enable access to _DLL and _DLH */ 1483e18f934SJerome Forissier write32(UART_LCR_DLAB, base + UART_LCR); 1493e18f934SJerome Forissier 1503e18f934SJerome Forissier /* Calculate and set UART_DLL */ 1513e18f934SJerome Forissier write32(freq_div & 0xFF, base + UART_DLL); 1523e18f934SJerome Forissier 1533e18f934SJerome Forissier /* Calculate and set UART_DLH */ 1543e18f934SJerome Forissier write32((freq_div >> 8) & 0xFF, base + UART_DLH); 1553e18f934SJerome Forissier 156faca937bSJerome Forissier /* Clear _DLL/_DLH access bit, set data size (8 bits), parity etc. */ 1573e18f934SJerome Forissier write32(UART_LCR_DLS8, base + UART_LCR); 1583e18f934SJerome Forissier 1593e18f934SJerome Forissier /* Disable interrupt mode */ 1603e18f934SJerome Forissier write32(0, base + UART_IEL); 1613e18f934SJerome Forissier 162ed7617dfSJerome Forissier hi16xx_uart_flush(&pd->chip); 1633e18f934SJerome Forissier } 1643e18f934SJerome Forissier 165