123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137 |
- /*
- * SPDX-License-Identifier: BSD-2-Clause
- *
- * Copyright (c) 2019 Western Digital Corporation or its affiliates.
- *
- * Authors:
- * Anup Patel <anup.patel@wdc.com>
- */
- #include <sbi/riscv_io.h>
- #include <sbi/sbi_console.h>
- #include <sbi_utils/serial/uart8250.h>
- /* clang-format off */
- #define UART_RBR_OFFSET 0 /* In: Recieve Buffer Register */
- #define UART_THR_OFFSET 0 /* Out: Transmitter Holding Register */
- #define UART_DLL_OFFSET 0 /* Out: Divisor Latch Low */
- #define UART_IER_OFFSET 1 /* I/O: Interrupt Enable Register */
- #define UART_DLM_OFFSET 1 /* Out: Divisor Latch High */
- #define UART_FCR_OFFSET 2 /* Out: FIFO Control Register */
- #define UART_IIR_OFFSET 2 /* I/O: Interrupt Identification Register */
- #define UART_LCR_OFFSET 3 /* Out: Line Control Register */
- #define UART_MCR_OFFSET 4 /* Out: Modem Control Register */
- #define UART_LSR_OFFSET 5 /* In: Line Status Register */
- #define UART_MSR_OFFSET 6 /* In: Modem Status Register */
- #define UART_SCR_OFFSET 7 /* I/O: Scratch Register */
- #define UART_MDR1_OFFSET 8 /* I/O: Mode Register */
- #define UART_LSR_FIFOE 0x80 /* Fifo error */
- #define UART_LSR_TEMT 0x40 /* Transmitter empty */
- #define UART_LSR_THRE 0x20 /* Transmit-hold-register empty */
- #define UART_LSR_BI 0x10 /* Break interrupt indicator */
- #define UART_LSR_FE 0x08 /* Frame error indicator */
- #define UART_LSR_PE 0x04 /* Parity error indicator */
- #define UART_LSR_OE 0x02 /* Overrun error indicator */
- #define UART_LSR_DR 0x01 /* Receiver data ready */
- #define UART_LSR_BRK_ERROR_BITS 0x1E /* BI, FE, PE, OE bits */
- /* clang-format on */
- static volatile char *uart8250_base;
- static u32 uart8250_in_freq;
- static u32 uart8250_baudrate;
- static u32 uart8250_reg_width;
- static u32 uart8250_reg_shift;
- static u32 get_reg(u32 num)
- {
- u32 offset = num << uart8250_reg_shift;
- if (uart8250_reg_width == 1)
- return readb(uart8250_base + offset);
- else if (uart8250_reg_width == 2)
- return readw(uart8250_base + offset);
- else
- return readl(uart8250_base + offset);
- }
- static void set_reg(u32 num, u32 val)
- {
- u32 offset = num << uart8250_reg_shift;
- if (uart8250_reg_width == 1)
- writeb(val, uart8250_base + offset);
- else if (uart8250_reg_width == 2)
- writew(val, uart8250_base + offset);
- else
- writel(val, uart8250_base + offset);
- }
- static void uart8250_putc(char ch)
- {
- while ((get_reg(UART_LSR_OFFSET) & UART_LSR_THRE) == 0)
- ;
- set_reg(UART_THR_OFFSET, ch);
- }
- static int uart8250_getc(void)
- {
- if (get_reg(UART_LSR_OFFSET) & UART_LSR_DR)
- return get_reg(UART_RBR_OFFSET);
- return -1;
- }
- static struct sbi_console_device uart8250_console = {
- .name = "uart8250",
- .console_putc = uart8250_putc,
- .console_getc = uart8250_getc
- };
- int uart8250_init(unsigned long base, u32 in_freq, u32 baudrate, u32 reg_shift,
- u32 reg_width, u32 reg_offset)
- {
- u16 bdiv = 0;
- uart8250_base = (volatile char *)base + reg_offset;
- uart8250_reg_shift = reg_shift;
- uart8250_reg_width = reg_width;
- uart8250_in_freq = in_freq;
- uart8250_baudrate = baudrate;
- if (uart8250_baudrate) {
- bdiv = (uart8250_in_freq + 8 * uart8250_baudrate) /
- (16 * uart8250_baudrate);
- }
- /* Disable all interrupts */
- set_reg(UART_IER_OFFSET, 0x00);
- /* Enable DLAB */
- set_reg(UART_LCR_OFFSET, 0x80);
- if (bdiv) {
- /* Set divisor low byte */
- set_reg(UART_DLL_OFFSET, bdiv & 0xff);
- /* Set divisor high byte */
- set_reg(UART_DLM_OFFSET, (bdiv >> 8) & 0xff);
- }
- /* 8 bits, no parity, one stop bit */
- set_reg(UART_LCR_OFFSET, 0x03);
- /* Enable FIFO */
- set_reg(UART_FCR_OFFSET, 0x01);
- /* No modem control DTR RTS */
- set_reg(UART_MCR_OFFSET, 0x00);
- /* Clear line status */
- get_reg(UART_LSR_OFFSET);
- /* Read receive buffer */
- get_reg(UART_RBR_OFFSET);
- /* Set scratchpad */
- set_reg(UART_SCR_OFFSET, 0x00);
- sbi_console_set_device(&uart8250_console);
- return 0;
- }
|