11bb92983SJerome Forissier // SPDX-License-Identifier: BSD-2-Clause 23e18f934SJerome Forissier /* 33e18f934SJerome Forissier * Copyright (c) 2016, Linaro Limited 43e18f934SJerome Forissier */ 5ed7617dfSJerome Forissier #include <assert.h> 63e18f934SJerome Forissier #include <drivers/hi16xx_uart.h> 73e18f934SJerome Forissier #include <io.h> 88d94060aSEtienne Carriere #include <keep.h> 9ed7617dfSJerome Forissier #include <mm/core_mmu.h> 10ed7617dfSJerome Forissier #include <util.h> 113e18f934SJerome Forissier 123e18f934SJerome Forissier /* Register offsets */ 133e18f934SJerome Forissier 143e18f934SJerome Forissier #define UART_RBR 0x00 /* RX data buffer register */ 153e18f934SJerome Forissier #define UART_THR 0x00 /* TX data buffer register */ 163e18f934SJerome Forissier #define UART_DLL 0x00 /* Lower-bit frequency divider register */ 173e18f934SJerome Forissier 183e18f934SJerome Forissier #define UART_IEL 0x04 /* Interrupt enable register */ 193e18f934SJerome Forissier #define UART_DLH 0x04 /* Upper-bit frequency divider register */ 203e18f934SJerome Forissier 213e18f934SJerome Forissier #define UART_FCR 0x08 /* FIFO control register */ 223e18f934SJerome Forissier 233e18f934SJerome Forissier #define UART_LCR 0x0C /* Line control register */ 243e18f934SJerome Forissier 253e18f934SJerome Forissier #define UART_LSR 0x14 /* Line status register */ 263e18f934SJerome Forissier 273e18f934SJerome Forissier #define UART_USR 0x7C /* Status register */ 283e18f934SJerome Forissier 293e18f934SJerome Forissier /* 303e18f934SJerome Forissier * Line control register 313e18f934SJerome Forissier */ 323e18f934SJerome Forissier 333e18f934SJerome Forissier /* Data length selection */ 343e18f934SJerome Forissier #define UART_LCR_DLS5 0x0 /* 5 bits */ 353e18f934SJerome Forissier #define UART_LCR_DLS6 0x1 /* 6 bits */ 363e18f934SJerome Forissier #define UART_LCR_DLS7 0x2 /* 7 bits */ 373e18f934SJerome Forissier #define UART_LCR_DLS8 0x3 /* 8 bits */ 383e18f934SJerome Forissier 393e18f934SJerome Forissier /* Enable access to UART_DLL and UART_DLH */ 403e18f934SJerome Forissier #define UART_LCR_DLAB 0x80 413e18f934SJerome Forissier 423e18f934SJerome Forissier /* 433e18f934SJerome Forissier * FIFO control register 443e18f934SJerome Forissier */ 453e18f934SJerome Forissier 463e18f934SJerome Forissier #define UART_FCR_FIFO_EN 0x1 /* Enable FIFO (depth: 32 bytes) */ 473e18f934SJerome Forissier #define UART_FCR_RX_FIFO_RST 0x2 /* Clear receive FIFO (auto reset) */ 483e18f934SJerome Forissier #define UART_FCR_TX_FIFO_RST 0x4 /* Clear send FIFO (auto reset) */ 493e18f934SJerome Forissier 503e18f934SJerome Forissier 513e18f934SJerome Forissier /* 523e18f934SJerome Forissier * Status register 533e18f934SJerome Forissier */ 543e18f934SJerome Forissier 553e18f934SJerome Forissier #define UART_USR_BUSY_BIT 0 /* 0: idle/non-activated, 1: busy */ 563e18f934SJerome Forissier #define UART_USR_TFNF_BIT 1 /* Transmit FIFO not full bit */ 573e18f934SJerome Forissier #define UART_USR_TFE_BIT 2 /* Transmit FIFO empty bit */ 583e18f934SJerome Forissier #define UART_USR_RFNE_BIT 3 /* Receive FIFO not empty bit */ 593e18f934SJerome Forissier #define UART_USR_RFF_BIT 4 /* Receive FIFO full bit */ 603e18f934SJerome Forissier 61ed7617dfSJerome Forissier static vaddr_t chip_to_base(struct serial_chip *chip) 623e18f934SJerome Forissier { 63ed7617dfSJerome Forissier struct hi16xx_uart_data *pd = 64ed7617dfSJerome Forissier container_of(chip, struct hi16xx_uart_data, chip); 65ed7617dfSJerome Forissier 66ed7617dfSJerome Forissier return io_pa_or_va(&pd->base); 67ed7617dfSJerome Forissier } 68ed7617dfSJerome Forissier 69ed7617dfSJerome Forissier static void hi16xx_uart_flush(struct serial_chip *chip) 70ed7617dfSJerome Forissier { 71ed7617dfSJerome Forissier vaddr_t base = chip_to_base(chip); 72ed7617dfSJerome Forissier 73918bb3a5SEtienne Carriere while (!(io_read32(base + UART_USR) & UART_USR_TFE_BIT)) 743e18f934SJerome Forissier ; 753e18f934SJerome Forissier } 763e18f934SJerome Forissier 77ed7617dfSJerome Forissier static void hi16xx_uart_putc(struct serial_chip *chip, int ch) 78ed7617dfSJerome Forissier { 79ed7617dfSJerome Forissier vaddr_t base = chip_to_base(chip); 80ed7617dfSJerome Forissier 81ed7617dfSJerome Forissier /* Wait until TX FIFO is empty */ 82918bb3a5SEtienne Carriere while (!(io_read32(base + UART_USR) & UART_USR_TFE_BIT)) 83ed7617dfSJerome Forissier ; 84ed7617dfSJerome Forissier 85ed7617dfSJerome Forissier /* Put character into TX FIFO */ 86918bb3a5SEtienne Carriere io_write32(base + UART_THR, ch & 0xFF); 87ed7617dfSJerome Forissier } 88ed7617dfSJerome Forissier 89ed7617dfSJerome Forissier static bool hi16xx_uart_have_rx_data(struct serial_chip *chip) 90ed7617dfSJerome Forissier { 91ed7617dfSJerome Forissier vaddr_t base = chip_to_base(chip); 92ed7617dfSJerome Forissier 93918bb3a5SEtienne Carriere return (io_read32(base + UART_USR) & UART_USR_RFNE_BIT); 94ed7617dfSJerome Forissier } 95ed7617dfSJerome Forissier 96ed7617dfSJerome Forissier static int hi16xx_uart_getchar(struct serial_chip *chip) 97ed7617dfSJerome Forissier { 98ed7617dfSJerome Forissier vaddr_t base = chip_to_base(chip); 99ed7617dfSJerome Forissier 100ed7617dfSJerome Forissier while (!hi16xx_uart_have_rx_data(chip)) 101ed7617dfSJerome Forissier ; 102918bb3a5SEtienne Carriere return io_read32(base + UART_RBR) & 0xFF; 103ed7617dfSJerome Forissier } 104ed7617dfSJerome Forissier 105ed7617dfSJerome Forissier static const struct serial_ops hi16xx_uart_ops = { 106ed7617dfSJerome Forissier .flush = hi16xx_uart_flush, 107ed7617dfSJerome Forissier .getchar = hi16xx_uart_getchar, 108ed7617dfSJerome Forissier .have_rx_data = hi16xx_uart_have_rx_data, 109ed7617dfSJerome Forissier .putc = hi16xx_uart_putc, 110ed7617dfSJerome Forissier }; 111*3639b55fSJerome Forissier DECLARE_KEEP_PAGER(hi16xx_uart_ops); 112ed7617dfSJerome Forissier 113ed7617dfSJerome Forissier void hi16xx_uart_init(struct hi16xx_uart_data *pd, paddr_t base, 114ed7617dfSJerome Forissier uint32_t uart_clk, uint32_t baud_rate) 1153e18f934SJerome Forissier { 1163e18f934SJerome Forissier uint16_t freq_div = uart_clk / (16 * baud_rate); 1173e18f934SJerome Forissier 118ed7617dfSJerome Forissier pd->base.pa = base; 119ed7617dfSJerome Forissier pd->chip.ops = &hi16xx_uart_ops; 120ed7617dfSJerome Forissier 12130376c57SJerome Forissier /* Enable (and clear) FIFOs */ 122918bb3a5SEtienne Carriere io_write32(base + UART_FCR, UART_FCR_FIFO_EN); 1233e18f934SJerome Forissier 1243e18f934SJerome Forissier /* Enable access to _DLL and _DLH */ 125918bb3a5SEtienne Carriere io_write32(base + UART_LCR, UART_LCR_DLAB); 1263e18f934SJerome Forissier 1273e18f934SJerome Forissier /* Calculate and set UART_DLL */ 128918bb3a5SEtienne Carriere io_write32(base + UART_DLL, freq_div & 0xFF); 1293e18f934SJerome Forissier 1303e18f934SJerome Forissier /* Calculate and set UART_DLH */ 131918bb3a5SEtienne Carriere io_write32(base + UART_DLH, (freq_div >> 8) & 0xFF); 1323e18f934SJerome Forissier 133faca937bSJerome Forissier /* Clear _DLL/_DLH access bit, set data size (8 bits), parity etc. */ 134918bb3a5SEtienne Carriere io_write32(base + UART_LCR, UART_LCR_DLS8); 1353e18f934SJerome Forissier 1363e18f934SJerome Forissier /* Disable interrupt mode */ 137918bb3a5SEtienne Carriere io_write32(base + UART_IEL, 0); 1383e18f934SJerome Forissier 139ed7617dfSJerome Forissier hi16xx_uart_flush(&pd->chip); 1403e18f934SJerome Forissier } 1413e18f934SJerome Forissier 142