Angel Pons | 1ddb894 | 2020-04-04 18:51:26 +0200 | [diff] [blame] | 1 | /* SPDX-License-Identifier: GPL-2.0-only */ |
Gabe Black | 607c0b6 | 2013-05-16 05:45:57 -0700 | [diff] [blame] | 2 | |
Kyösti Mälkki | 13f6650 | 2019-03-03 08:01:05 +0200 | [diff] [blame] | 3 | #include <device/mmio.h> |
Kyösti Mälkki | bbf6f3d | 2014-03-15 01:32:55 +0200 | [diff] [blame] | 4 | #include <boot/coreboot_tables.h> |
Julius Werner | 80af442 | 2014-10-20 13:18:56 -0700 | [diff] [blame] | 5 | #include <console/uart.h> |
| 6 | #include <soc/clk.h> |
| 7 | #include <soc/cpu.h> |
| 8 | #include <soc/periph.h> |
| 9 | #include <soc/uart.h> |
| 10 | #include <types.h> |
Gabe Black | 607c0b6 | 2013-05-16 05:45:57 -0700 | [diff] [blame] | 11 | |
| 12 | #define RX_FIFO_COUNT_MASK 0xff |
| 13 | #define RX_FIFO_FULL_MASK (1 << 8) |
| 14 | #define TX_FIFO_FULL_MASK (1 << 24) |
| 15 | |
Kyösti Mälkki | c2610a4 | 2014-02-24 20:51:30 +0200 | [diff] [blame] | 16 | static void serial_setbrg_dev(struct s5p_uart *uart) |
Gabe Black | 607c0b6 | 2013-05-16 05:45:57 -0700 | [diff] [blame] | 17 | { |
Gabe Black | 607c0b6 | 2013-05-16 05:45:57 -0700 | [diff] [blame] | 18 | u32 uclk; |
Gabe Black | 607c0b6 | 2013-05-16 05:45:57 -0700 | [diff] [blame] | 19 | u32 val; |
| 20 | |
| 21 | // All UARTs share the same clock. |
| 22 | uclk = clock_get_periph_rate(PERIPH_ID_UART3); |
Julien Viard de Galbert | 235daa4 | 2018-02-20 11:45:48 +0100 | [diff] [blame] | 23 | val = uclk / get_uart_baudrate(); |
Gabe Black | 607c0b6 | 2013-05-16 05:45:57 -0700 | [diff] [blame] | 24 | |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 25 | write32(&uart->ubrdiv, val / 16 - 1); |
Gabe Black | 607c0b6 | 2013-05-16 05:45:57 -0700 | [diff] [blame] | 26 | } |
| 27 | |
| 28 | /* |
| 29 | * Initialise the serial port with the given baudrate. The settings |
| 30 | * are always 8 data bits, no parity, 1 stop bit, no start bits. |
| 31 | */ |
Kyösti Mälkki | c2610a4 | 2014-02-24 20:51:30 +0200 | [diff] [blame] | 32 | static void exynos5_init_dev(struct s5p_uart *uart) |
Gabe Black | 607c0b6 | 2013-05-16 05:45:57 -0700 | [diff] [blame] | 33 | { |
Gabe Black | 607c0b6 | 2013-05-16 05:45:57 -0700 | [diff] [blame] | 34 | /* enable FIFOs */ |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 35 | write32(&uart->ufcon, 0x1); |
| 36 | write32(&uart->umcon, 0); |
Gabe Black | 607c0b6 | 2013-05-16 05:45:57 -0700 | [diff] [blame] | 37 | /* 8N1 */ |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 38 | write32(&uart->ulcon, 0x3); |
Gabe Black | 607c0b6 | 2013-05-16 05:45:57 -0700 | [diff] [blame] | 39 | /* No interrupts, no DMA, pure polling */ |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 40 | write32(&uart->ucon, 0x245); |
Gabe Black | 607c0b6 | 2013-05-16 05:45:57 -0700 | [diff] [blame] | 41 | |
Kyösti Mälkki | c2610a4 | 2014-02-24 20:51:30 +0200 | [diff] [blame] | 42 | serial_setbrg_dev(uart); |
Gabe Black | 607c0b6 | 2013-05-16 05:45:57 -0700 | [diff] [blame] | 43 | } |
| 44 | |
Kyösti Mälkki | c2610a4 | 2014-02-24 20:51:30 +0200 | [diff] [blame] | 45 | static int exynos5_uart_err_check(struct s5p_uart *uart, int op) |
Gabe Black | 607c0b6 | 2013-05-16 05:45:57 -0700 | [diff] [blame] | 46 | { |
Gabe Black | 607c0b6 | 2013-05-16 05:45:57 -0700 | [diff] [blame] | 47 | unsigned int mask; |
| 48 | |
| 49 | /* |
| 50 | * UERSTAT |
| 51 | * Break Detect [3] |
| 52 | * Frame Err [2] : receive operation |
| 53 | * Parity Err [1] : receive operation |
| 54 | * Overrun Err [0] : receive operation |
| 55 | */ |
| 56 | if (op) |
| 57 | mask = 0x8; |
| 58 | else |
| 59 | mask = 0xf; |
| 60 | |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 61 | return read32(&uart->uerstat) & mask; |
Gabe Black | 607c0b6 | 2013-05-16 05:45:57 -0700 | [diff] [blame] | 62 | } |
| 63 | |
| 64 | /* |
| 65 | * Read a single byte from the serial port. Returns 1 on success, 0 |
Martin Roth | 1fc2ba5 | 2014-12-07 14:59:11 -0700 | [diff] [blame] | 66 | * otherwise. When the function is successful, the character read is |
Gabe Black | 607c0b6 | 2013-05-16 05:45:57 -0700 | [diff] [blame] | 67 | * written into its argument c. |
| 68 | */ |
Kyösti Mälkki | c2610a4 | 2014-02-24 20:51:30 +0200 | [diff] [blame] | 69 | static unsigned char exynos5_uart_rx_byte(struct s5p_uart *uart) |
Gabe Black | 607c0b6 | 2013-05-16 05:45:57 -0700 | [diff] [blame] | 70 | { |
Gabe Black | 607c0b6 | 2013-05-16 05:45:57 -0700 | [diff] [blame] | 71 | /* wait for character to arrive */ |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 72 | while (!(read32(&uart->ufstat) & (RX_FIFO_COUNT_MASK | |
Gabe Black | 607c0b6 | 2013-05-16 05:45:57 -0700 | [diff] [blame] | 73 | RX_FIFO_FULL_MASK))) { |
Kyösti Mälkki | c2610a4 | 2014-02-24 20:51:30 +0200 | [diff] [blame] | 74 | if (exynos5_uart_err_check(uart, 0)) |
Gabe Black | 607c0b6 | 2013-05-16 05:45:57 -0700 | [diff] [blame] | 75 | return 0; |
| 76 | } |
| 77 | |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 78 | return read8(&uart->urxh) & 0xff; |
Gabe Black | 607c0b6 | 2013-05-16 05:45:57 -0700 | [diff] [blame] | 79 | } |
| 80 | |
| 81 | /* |
| 82 | * Output a single byte to the serial port. |
| 83 | */ |
Kyösti Mälkki | c2610a4 | 2014-02-24 20:51:30 +0200 | [diff] [blame] | 84 | static void exynos5_uart_tx_byte(struct s5p_uart *uart, unsigned char data) |
Gabe Black | 607c0b6 | 2013-05-16 05:45:57 -0700 | [diff] [blame] | 85 | { |
Gabe Black | 607c0b6 | 2013-05-16 05:45:57 -0700 | [diff] [blame] | 86 | /* wait for room in the tx FIFO */ |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 87 | while ((read32(&uart->ufstat) & TX_FIFO_FULL_MASK)) { |
Kyösti Mälkki | c2610a4 | 2014-02-24 20:51:30 +0200 | [diff] [blame] | 88 | if (exynos5_uart_err_check(uart, 1)) |
Gabe Black | 607c0b6 | 2013-05-16 05:45:57 -0700 | [diff] [blame] | 89 | return; |
| 90 | } |
| 91 | |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 92 | write8(&uart->utxh, data); |
Gabe Black | 607c0b6 | 2013-05-16 05:45:57 -0700 | [diff] [blame] | 93 | } |
| 94 | |
Felix Held | e3a1247 | 2020-09-11 15:47:09 +0200 | [diff] [blame] | 95 | uintptr_t uart_platform_base(unsigned int idx) |
Kyösti Mälkki | c2610a4 | 2014-02-24 20:51:30 +0200 | [diff] [blame] | 96 | { |
Kyösti Mälkki | 70342a7 | 2014-03-14 22:28:29 +0200 | [diff] [blame] | 97 | if (idx < 4) |
| 98 | return 0x12c00000 + idx * 0x10000; |
| 99 | else |
| 100 | return 0; |
Kyösti Mälkki | c2610a4 | 2014-02-24 20:51:30 +0200 | [diff] [blame] | 101 | } |
| 102 | |
Felix Held | e3a1247 | 2020-09-11 15:47:09 +0200 | [diff] [blame] | 103 | void uart_init(unsigned int idx) |
Gabe Black | 607c0b6 | 2013-05-16 05:45:57 -0700 | [diff] [blame] | 104 | { |
Kyösti Mälkki | 70342a7 | 2014-03-14 22:28:29 +0200 | [diff] [blame] | 105 | struct s5p_uart *uart = uart_platform_baseptr(idx); |
Kyösti Mälkki | c2610a4 | 2014-02-24 20:51:30 +0200 | [diff] [blame] | 106 | exynos5_init_dev(uart); |
Gabe Black | 607c0b6 | 2013-05-16 05:45:57 -0700 | [diff] [blame] | 107 | } |
| 108 | |
Felix Held | e3a1247 | 2020-09-11 15:47:09 +0200 | [diff] [blame] | 109 | unsigned char uart_rx_byte(unsigned int idx) |
Gabe Black | 607c0b6 | 2013-05-16 05:45:57 -0700 | [diff] [blame] | 110 | { |
Kyösti Mälkki | 70342a7 | 2014-03-14 22:28:29 +0200 | [diff] [blame] | 111 | struct s5p_uart *uart = uart_platform_baseptr(idx); |
Kyösti Mälkki | c2610a4 | 2014-02-24 20:51:30 +0200 | [diff] [blame] | 112 | return exynos5_uart_rx_byte(uart); |
Gabe Black | 607c0b6 | 2013-05-16 05:45:57 -0700 | [diff] [blame] | 113 | } |
| 114 | |
Felix Held | e3a1247 | 2020-09-11 15:47:09 +0200 | [diff] [blame] | 115 | void uart_tx_byte(unsigned int idx, unsigned char data) |
Gabe Black | 607c0b6 | 2013-05-16 05:45:57 -0700 | [diff] [blame] | 116 | { |
Kyösti Mälkki | 70342a7 | 2014-03-14 22:28:29 +0200 | [diff] [blame] | 117 | struct s5p_uart *uart = uart_platform_baseptr(idx); |
Kyösti Mälkki | c2610a4 | 2014-02-24 20:51:30 +0200 | [diff] [blame] | 118 | exynos5_uart_tx_byte(uart, data); |
Gabe Black | 607c0b6 | 2013-05-16 05:45:57 -0700 | [diff] [blame] | 119 | } |
| 120 | |
Felix Held | e3a1247 | 2020-09-11 15:47:09 +0200 | [diff] [blame] | 121 | void uart_tx_flush(unsigned int idx) |
Gabe Black | 607c0b6 | 2013-05-16 05:45:57 -0700 | [diff] [blame] | 122 | { |
Kyösti Mälkki | c2610a4 | 2014-02-24 20:51:30 +0200 | [diff] [blame] | 123 | /* Exynos5250 implements this too. */ |
Gabe Black | 607c0b6 | 2013-05-16 05:45:57 -0700 | [diff] [blame] | 124 | } |
Kyösti Mälkki | bbf6f3d | 2014-03-15 01:32:55 +0200 | [diff] [blame] | 125 | |
Kyösti Mälkki | bbf6f3d | 2014-03-15 01:32:55 +0200 | [diff] [blame] | 126 | void uart_fill_lb(void *data) |
| 127 | { |
| 128 | struct lb_serial serial; |
| 129 | serial.type = LB_SERIAL_TYPE_MEMORY_MAPPED; |
Kyösti Mälkki | 70342a7 | 2014-03-14 22:28:29 +0200 | [diff] [blame] | 130 | serial.baseaddr = uart_platform_base(CONFIG_UART_FOR_CONSOLE); |
Julien Viard de Galbert | 235daa4 | 2018-02-20 11:45:48 +0100 | [diff] [blame] | 131 | serial.baud = get_uart_baudrate(); |
Patrick Georgi | a7cac0c | 2016-02-19 17:33:26 +0100 | [diff] [blame] | 132 | serial.regwidth = 4; |
Martin Roth | ff94e00 | 2016-11-18 10:34:24 -0700 | [diff] [blame] | 133 | serial.input_hertz = uart_platform_refclk(); |
| 134 | serial.uart_pci_addr = 0; |
Kyösti Mälkki | bbf6f3d | 2014-03-15 01:32:55 +0200 | [diff] [blame] | 135 | lb_add_serial(&serial, data); |
| 136 | |
| 137 | lb_add_console(LB_TAG_CONSOLE_SERIAL8250MEM, data); |
| 138 | } |