* Copyright (c) 2016, Linaro Limited
*/
#include <assert.h>
#include <drivers/hi16xx_uart.h>
#include <io.h>
#include <keep.h>
#include <mm/core_mmu.h>
#include <util.h>
#define UART_RBR 0x00
#define UART_THR 0x00
#define UART_DLL 0x00
#define UART_IEL 0x04
#define UART_DLH 0x04
#define UART_FCR 0x08
#define UART_LCR 0x0C
#define UART_LSR 0x14
#define UART_USR 0x7C
* Line control register
*/
#define UART_LCR_DLS5 0x0
#define UART_LCR_DLS6 0x1
#define UART_LCR_DLS7 0x2
#define UART_LCR_DLS8 0x3
#define UART_LCR_DLAB 0x80
* FIFO control register
*/
#define UART_FCR_FIFO_EN 0x1
#define UART_FCR_RX_FIFO_RST 0x2
#define UART_FCR_TX_FIFO_RST 0x4
* Status register
*/
#define UART_USR_BUSY_BIT 0
#define UART_USR_TFNF_BIT 1
#define UART_USR_TFE_BIT 2
#define UART_USR_RFNE_BIT 3
#define UART_USR_RFF_BIT 4
static vaddr_t chip_to_base(struct serial_chip *chip)
{
struct hi16xx_uart_data *pd =
container_of(chip, struct hi16xx_uart_data, chip);
return io_pa_or_va(&pd->base, HI16XX_UART_REG_SIZE);
}
static void hi16xx_uart_flush(struct serial_chip *chip)
{
vaddr_t base = chip_to_base(chip);
while (!(io_read32(base + UART_USR) & UART_USR_TFE_BIT))
;
}
static void hi16xx_uart_putc(struct serial_chip *chip, int ch)
{
vaddr_t base = chip_to_base(chip);
while (!(io_read32(base + UART_USR) & UART_USR_TFE_BIT))
;
io_write32(base + UART_THR, ch & 0xFF);
}
static bool hi16xx_uart_have_rx_data(struct serial_chip *chip)
{
vaddr_t base = chip_to_base(chip);
return (io_read32(base + UART_USR) & UART_USR_RFNE_BIT);
}
static int hi16xx_uart_getchar(struct serial_chip *chip)
{
vaddr_t base = chip_to_base(chip);
while (!hi16xx_uart_have_rx_data(chip))
;
return io_read32(base + UART_RBR) & 0xFF;
}
static const struct serial_ops hi16xx_uart_ops = {
.flush = hi16xx_uart_flush,
.getchar = hi16xx_uart_getchar,
.have_rx_data = hi16xx_uart_have_rx_data,
.putc = hi16xx_uart_putc,
};
DECLARE_KEEP_PAGER(hi16xx_uart_ops);
void hi16xx_uart_init(struct hi16xx_uart_data *pd, paddr_t base,
uint32_t uart_clk, uint32_t baud_rate)
{
uint16_t freq_div = uart_clk / (16 * baud_rate);
pd->base.pa = base;
pd->chip.ops = &hi16xx_uart_ops;
io_write32(base + UART_FCR, UART_FCR_FIFO_EN);
io_write32(base + UART_LCR, UART_LCR_DLAB);
io_write32(base + UART_DLL, freq_div & 0xFF);
io_write32(base + UART_DLH, (freq_div >> 8) & 0xFF);
io_write32(base + UART_LCR, UART_LCR_DLS8);
io_write32(base + UART_IEL, 0);
hi16xx_uart_flush(&pd->chip);
}