123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285 |
- /*
- * This file is part of the coreboot project.
- *
- * Copyright (C) 2003 Eric Biederman
- * Copyright (C) 2006-2010 coresystems GmbH
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
- #include "u.h"
- #include "../port/lib.h"
- #include "mem.h"
- #include "dat.h"
- #include "fns.h"
- extern void *uart;
- void udelay(int d)
- {
- volatile int i;
- for(i = 0; i < 1*d; i++)
- ;
- }
- // Note: this was a separate file in coreboot. The Plan 9 convention
- // is to keep constants in the files that need them. This avoids the
- // proliferation of files and their use seen in other projects.
- /* Data */
- #define UART8250_RBR 0x00
- #define UART8250_TBR 0x00
- /* Control */
- #define UART8250_IER 0x01
- #define UART8250_IER_MSI 0x08 /* Enable Modem status interrupt */
- #define UART8250_IER_RLSI 0x04 /* Enable receiver line status interrupt */
- #define UART8250_IER_THRI 0x02 /* Enable Transmitter holding register int. */
- #define UART8250_IER_RDI 0x01 /* Enable receiver data interrupt */
- #define UART8250_IIR 0x02
- #define UART8250_IIR_NO_INT 0x01 /* No interrupts pending */
- #define UART8250_IIR_ID 0x06 /* Mask for the interrupt ID */
- #define UART8250_IIR_MSI 0x00 /* Modem status interrupt */
- #define UART8250_IIR_THRI 0x02 /* Transmitter holding register empty */
- #define UART8250_IIR_RDI 0x04 /* Receiver data interrupt */
- #define UART8250_IIR_RLSI 0x06 /* Receiver line status interrupt */
- #define UART8250_FCR 0x02
- #define UART8250_FCR_FIFO_EN 0x01 /* Fifo enable */
- #define UART8250_FCR_CLEAR_RCVR 0x02 /* Clear the RCVR FIFO */
- #define UART8250_FCR_CLEAR_XMIT 0x04 /* Clear the XMIT FIFO */
- #define UART8250_FCR_DMA_SELECT 0x08 /* For DMA applications */
- #define UART8250_FCR_TRIGGER_MASK 0xC0 /* Mask for the FIFO trigger range */
- #define UART8250_FCR_TRIGGER_1 0x00 /* Mask for trigger set at 1 */
- #define UART8250_FCR_TRIGGER_4 0x40 /* Mask for trigger set at 4 */
- #define UART8250_FCR_TRIGGER_8 0x80 /* Mask for trigger set at 8 */
- #define UART8250_FCR_TRIGGER_14 0xC0 /* Mask for trigger set at 14 */
- #define UART8250_FCR_RXSR 0x02 /* Receiver soft reset */
- #define UART8250_FCR_TXSR 0x04 /* Transmitter soft reset */
- #define UART8250_LCR 0x03
- #define UART8250_LCR_WLS_MSK 0x03 /* character length select mask */
- #define UART8250_LCR_WLS_5 0x00 /* 5 bit character length */
- #define UART8250_LCR_WLS_6 0x01 /* 6 bit character length */
- #define UART8250_LCR_WLS_7 0x02 /* 7 bit character length */
- #define UART8250_LCR_WLS_8 0x03 /* 8 bit character length */
- #define UART8250_LCR_STB 0x04 /* Number of stop Bits, off = 1, on = 1.5 or 2) */
- #define UART8250_LCR_PEN 0x08 /* Parity enable */
- #define UART8250_LCR_EPS 0x10 /* Even Parity Select */
- #define UART8250_LCR_STKP 0x20 /* Stick Parity */
- #define UART8250_LCR_SBRK 0x40 /* Set Break */
- #define UART8250_LCR_BKSE 0x80 /* Bank select enable */
- #define UART8250_LCR_DLAB 0x80 /* Divisor latch access bit */
- #define UART8250_MCR 0x04
- #define UART8250_MCR_DTR 0x01 /* DTR */
- #define UART8250_MCR_RTS 0x02 /* RTS */
- #define UART8250_MCR_OUT1 0x04 /* Out 1 */
- #define UART8250_MCR_OUT2 0x08 /* Out 2 */
- #define UART8250_MCR_LOOP 0x10 /* Enable loopback test mode */
- #define UART8250_MCR_DMA_EN 0x04
- #define UART8250_MCR_TX_DFR 0x08
- #define UART8250_DLL 0x00
- #define UART8250_DLM 0x01
- /* Status */
- #define UART8250_LSR 0x05
- #define UART8250_LSR_DR 0x01 /* Data ready */
- #define UART8250_LSR_OE 0x02 /* Overrun */
- #define UART8250_LSR_PE 0x04 /* Parity error */
- #define UART8250_LSR_FE 0x08 /* Framing error */
- #define UART8250_LSR_BI 0x10 /* Break */
- #define UART8250_LSR_THRE 0x20 /* Xmit holding register empty */
- #define UART8250_LSR_TEMT 0x40 /* Xmitter empty */
- #define UART8250_LSR_ERR 0x80 /* Error */
- #define UART8250_MSR 0x06
- #define UART8250_MSR_DCD 0x80 /* Data Carrier Detect */
- #define UART8250_MSR_RI 0x40 /* Ring Indicator */
- #define UART8250_MSR_DSR 0x20 /* Data Set Ready */
- #define UART8250_MSR_CTS 0x10 /* Clear to Send */
- #define UART8250_MSR_DDCD 0x08 /* Delta DCD */
- #define UART8250_MSR_TERI 0x04 /* Trailing edge ring indicator */
- #define UART8250_MSR_DDSR 0x02 /* Delta DSR */
- #define UART8250_MSR_DCTS 0x01 /* Delta CTS */
- #define UART8250_SCR 0x07
- #define UART8250_SPR 0x07
- /* Should support 8250, 16450, 16550, 16550A type UARTs */
- /* Expected character delay at 1200bps is 9ms for a working UART
- * and no flow-control. Assume UART as stuck if shift register
- * or FIFO takes more than 50ms per character to appear empty.
- */
- #define SINGLE_CHAR_TIMEOUT (50 * 1000)
- #define FIFO_TIMEOUT (16 * SINGLE_CHAR_TIMEOUT)
- /* Other essential constants. TODO: make these all plan 9 style */
- #define CONFIG_TTYS0_LCS 0x3
- // These functions are here as we may need to get tricky
- // for riscv with memory barriers and such.
- uint8_t read8(uint32_t *p)
- {
- return *p;
- }
- void write8(uint32_t *p, uint8_t val)
- {
- *p = val;
- }
- static uint8_t uart8250_read(uint32_t *base, uint8_t reg)
- {
- return read8(base + reg);
- }
- static void uart8250_write(uint32_t *base, uint8_t reg, uint8_t data)
- {
- write8(base + reg, data);
- }
- static int uart8250_mem_can_tx_byte(void *base)
- {
- return uart8250_read(base, UART8250_LSR) & UART8250_LSR_THRE;
- }
- static void uart8250_mem_tx_byte(void *base, unsigned char data)
- {
- unsigned long int i = SINGLE_CHAR_TIMEOUT;
- while (i-- && !uart8250_mem_can_tx_byte(base))
- udelay(1);
- uart8250_write(base, UART8250_TBR, data);
- }
- static void uart8250_mem_tx_flush(void *base)
- {
- unsigned long int i = FIFO_TIMEOUT;
- while (i-- && !(uart8250_read(base, UART8250_LSR) & UART8250_LSR_TEMT))
- udelay(1);
- }
- static int uart8250_mem_can_rx_byte(void *base)
- {
- return uart8250_read(base, UART8250_LSR) & UART8250_LSR_DR;
- }
- static int uart8250_mem_rx_byte(void *base)
- {
- unsigned long int i = SINGLE_CHAR_TIMEOUT;
- uint8_t c;
- while (i-- && !uart8250_mem_can_rx_byte(base))
- udelay(1);
- if (0) print("rx_byte, register is 0x%x LSR 0x%x\n", uart8250_read(base, UART8250_LSR) , UART8250_LSR_DR);
- if (i) {
- c = uart8250_read(base, UART8250_RBR);
- if (0) print("c is 0x%x\n", c);
- return c;
- }
- else
- return -1;
- }
- static void uart8250_mem_init(void *base, unsigned divisor)
- {
- /* Disable interrupts */
- uart8250_write(base, UART8250_IER, 0x0);
- /* Enable FIFOs */
- uart8250_write(base, UART8250_FCR, UART8250_FCR_FIFO_EN);
- /* Assert DTR and RTS so the other end is happy */
- uart8250_write(base, UART8250_MCR, UART8250_MCR_DTR | UART8250_MCR_RTS);
- /* Divisor Latch Access Bit -- DLAB -- on */
- uart8250_write(base, UART8250_LCR, UART8250_LCR_DLAB | CONFIG_TTYS0_LCS);
- uart8250_write(base, UART8250_DLL, divisor & 0xFF);
- uart8250_write(base, UART8250_DLM, (divisor >> 8) & 0xFF);
- /* Set to 3 for 8N1 */
- uart8250_write(base, UART8250_LCR, CONFIG_TTYS0_LCS);
- }
- // We don't use idx at present but it's a reasonable API to preserve
- // should someone ever add more than one uart.
- static void *uart_platform_baseptr(int idx)
- {
- return uart;
- }
- /* Calculate divisor. Do not floor but round to nearest integer. */
- static unsigned int uart_baudrate_divisor(unsigned int baudrate,
- unsigned int refclk, unsigned int oversample)
- {
- return (1 + (2 * refclk) / (baudrate * oversample)) / 2;
- }
- static unsigned int uart_platform_refclk(void)
- {
- return 25 * 1000 * 1000;
- }
- static unsigned int uart_input_clock_divider(void)
- {
- /* Specify the default oversample rate for the UART.
- *
- * UARTs oversample the receive data. The UART's input clock first
- * enters the baud-rate divider to generate the oversample clock. Then
- * the UART typically divides the result by 16. The asynchronous
- * receive data is synchronized with the oversample clock and when a
- * start bit is detected the UART delays half a bit time using the
- * oversample clock. Samples are then taken to verify the start bit and
- * if present, samples are taken for the rest of the frame.
- */
- return 16;
- }
- void lowrisc_uart_init(int idx)
- {
- void *base = uart_platform_baseptr(idx);
- if (!base)
- return;
- unsigned int div;
- div = uart_baudrate_divisor(115200,
- uart_platform_refclk(), uart_input_clock_divider());
- uart8250_mem_init(base, div);
- }
- void lowrisc_putchar(int data)
- {
- void *base = uart_platform_baseptr(0);
- if (!base)
- return;
- uart8250_mem_tx_byte(base, data);
- }
- int lowrisc_getchar(int idx)
- {
- void *base = uart_platform_baseptr(idx);
- if (!base)
- return -1;
- return uart8250_mem_rx_byte(base);
- }
- void lowrisc_flush(int idx)
- {
- void *base = uart_platform_baseptr(idx);
- if (!base)
- return;
- uart8250_mem_tx_flush(base);
- }
|