Angel Pons | 1ddb894 | 2020-04-04 18:51:26 +0200 | [diff] [blame] | 1 | /* SPDX-License-Identifier: GPL-2.0-only */ |
Stefan Reinauer | 9fe20cb | 2012-12-07 17:18:43 -0800 | [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 | 1ed0c8c | 2014-10-20 13:16:29 -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> |
Stefan Reinauer | 9fe20cb | 2012-12-07 17:18:43 -0800 | [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) |
Stefan Reinauer | 9fe20cb | 2012-12-07 17:18:43 -0800 | [diff] [blame] | 17 | { |
Stefan Reinauer | 9fe20cb | 2012-12-07 17:18:43 -0800 | [diff] [blame] | 18 | u32 uclk; |
Stefan Reinauer | 9fe20cb | 2012-12-07 17:18:43 -0800 | [diff] [blame] | 19 | u32 val; |
Stefan Reinauer | 9fe20cb | 2012-12-07 17:18:43 -0800 | [diff] [blame] | 20 | |
Stefan Reinauer | 08dc357 | 2013-05-14 16:57:50 -0700 | [diff] [blame] | 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(); |
Stefan Reinauer | 9fe20cb | 2012-12-07 17:18:43 -0800 | [diff] [blame] | 24 | |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 25 | write32(&uart->ubrdiv, val / 16 - 1); |
Stefan Reinauer | 9fe20cb | 2012-12-07 17:18:43 -0800 | [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) |
Stefan Reinauer | 9fe20cb | 2012-12-07 17:18:43 -0800 | [diff] [blame] | 33 | { |
Hung-Te Lin | 31bb2df | 2013-02-07 19:30:40 +0800 | [diff] [blame] | 34 | // TODO initialize with correct peripheral id by base_port. |
Gabe Black | fe64060 | 2013-06-15 20:33:05 -0700 | [diff] [blame] | 35 | exynos_pinmux_uart3(); |
Hung-Te Lin | 31bb2df | 2013-02-07 19:30:40 +0800 | [diff] [blame] | 36 | |
Stefan Reinauer | 9fe20cb | 2012-12-07 17:18:43 -0800 | [diff] [blame] | 37 | /* enable FIFOs */ |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 38 | write32(&uart->ufcon, 0x1); |
| 39 | write32(&uart->umcon, 0); |
Stefan Reinauer | 9fe20cb | 2012-12-07 17:18:43 -0800 | [diff] [blame] | 40 | /* 8N1 */ |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 41 | write32(&uart->ulcon, 0x3); |
Stefan Reinauer | 9fe20cb | 2012-12-07 17:18:43 -0800 | [diff] [blame] | 42 | /* No interrupts, no DMA, pure polling */ |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 43 | write32(&uart->ucon, 0x245); |
Stefan Reinauer | 9fe20cb | 2012-12-07 17:18:43 -0800 | [diff] [blame] | 44 | |
Kyösti Mälkki | c2610a4 | 2014-02-24 20:51:30 +0200 | [diff] [blame] | 45 | serial_setbrg_dev(uart); |
Stefan Reinauer | 9fe20cb | 2012-12-07 17:18:43 -0800 | [diff] [blame] | 46 | } |
| 47 | |
Kyösti Mälkki | c2610a4 | 2014-02-24 20:51:30 +0200 | [diff] [blame] | 48 | static int exynos5_uart_err_check(struct s5p_uart *uart, int op) |
Stefan Reinauer | 9fe20cb | 2012-12-07 17:18:43 -0800 | [diff] [blame] | 49 | { |
Stefan Reinauer | 9fe20cb | 2012-12-07 17:18:43 -0800 | [diff] [blame] | 50 | unsigned int mask; |
| 51 | |
| 52 | /* |
| 53 | * UERSTAT |
| 54 | * Break Detect [3] |
| 55 | * Frame Err [2] : receive operation |
| 56 | * Parity Err [1] : receive operation |
| 57 | * Overrun Err [0] : receive operation |
| 58 | */ |
| 59 | if (op) |
| 60 | mask = 0x8; |
| 61 | else |
| 62 | mask = 0xf; |
| 63 | |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 64 | return read32(&uart->uerstat) & mask; |
Stefan Reinauer | 9fe20cb | 2012-12-07 17:18:43 -0800 | [diff] [blame] | 65 | } |
| 66 | |
| 67 | /* |
| 68 | * Read a single byte from the serial port. Returns 1 on success, 0 |
Martin Roth | 4c3ab73 | 2013-07-08 16:23:54 -0600 | [diff] [blame] | 69 | * otherwise. When the function is successful, the character read is |
Stefan Reinauer | 9fe20cb | 2012-12-07 17:18:43 -0800 | [diff] [blame] | 70 | * written into its argument c. |
| 71 | */ |
Kyösti Mälkki | c2610a4 | 2014-02-24 20:51:30 +0200 | [diff] [blame] | 72 | static unsigned char exynos5_uart_rx_byte(struct s5p_uart *uart) |
Stefan Reinauer | 9fe20cb | 2012-12-07 17:18:43 -0800 | [diff] [blame] | 73 | { |
Stefan Reinauer | 9fe20cb | 2012-12-07 17:18:43 -0800 | [diff] [blame] | 74 | /* wait for character to arrive */ |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 75 | while (!(read32(&uart->ufstat) & (RX_FIFO_COUNT_MASK | |
Stefan Reinauer | 9fe20cb | 2012-12-07 17:18:43 -0800 | [diff] [blame] | 76 | RX_FIFO_FULL_MASK))) { |
Kyösti Mälkki | c2610a4 | 2014-02-24 20:51:30 +0200 | [diff] [blame] | 77 | if (exynos5_uart_err_check(uart, 0)) |
Stefan Reinauer | 9fe20cb | 2012-12-07 17:18:43 -0800 | [diff] [blame] | 78 | return 0; |
| 79 | } |
| 80 | |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 81 | return read8(&uart->urxh) & 0xff; |
Stefan Reinauer | 9fe20cb | 2012-12-07 17:18:43 -0800 | [diff] [blame] | 82 | } |
| 83 | |
| 84 | /* |
| 85 | * Output a single byte to the serial port. |
| 86 | */ |
Kyösti Mälkki | c2610a4 | 2014-02-24 20:51:30 +0200 | [diff] [blame] | 87 | static void exynos5_uart_tx_byte(struct s5p_uart *uart, unsigned char data) |
Stefan Reinauer | 9fe20cb | 2012-12-07 17:18:43 -0800 | [diff] [blame] | 88 | { |
Stefan Reinauer | 9fe20cb | 2012-12-07 17:18:43 -0800 | [diff] [blame] | 89 | /* wait for room in the tx FIFO */ |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 90 | while ((read32(&uart->ufstat) & TX_FIFO_FULL_MASK)) { |
Kyösti Mälkki | c2610a4 | 2014-02-24 20:51:30 +0200 | [diff] [blame] | 91 | if (exynos5_uart_err_check(uart, 1)) |
Stefan Reinauer | 9fe20cb | 2012-12-07 17:18:43 -0800 | [diff] [blame] | 92 | return; |
| 93 | } |
| 94 | |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 95 | write8(&uart->utxh, data); |
Stefan Reinauer | 9fe20cb | 2012-12-07 17:18:43 -0800 | [diff] [blame] | 96 | } |
| 97 | |
Kyösti Mälkki | c2610a4 | 2014-02-24 20:51:30 +0200 | [diff] [blame] | 98 | static void exynos5_uart_tx_flush(struct s5p_uart *uart) |
Hung-Te Lin | 7dd5814 | 2013-06-05 14:06:55 -0700 | [diff] [blame] | 99 | { |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 100 | while (read32(&uart->ufstat) & 0x1ff0000); |
Hung-Te Lin | 7dd5814 | 2013-06-05 14:06:55 -0700 | [diff] [blame] | 101 | } |
| 102 | |
Felix Held | e3a1247 | 2020-09-11 15:47:09 +0200 | [diff] [blame] | 103 | uintptr_t uart_platform_base(unsigned int idx) |
Kyösti Mälkki | c2610a4 | 2014-02-24 20:51:30 +0200 | [diff] [blame] | 104 | { |
Kyösti Mälkki | 70342a7 | 2014-03-14 22:28:29 +0200 | [diff] [blame] | 105 | if (idx < 4) |
| 106 | return 0x12c00000 + idx * 0x10000; |
| 107 | else |
| 108 | return 0; |
Kyösti Mälkki | c2610a4 | 2014-02-24 20:51:30 +0200 | [diff] [blame] | 109 | } |
| 110 | |
Felix Held | e3a1247 | 2020-09-11 15:47:09 +0200 | [diff] [blame] | 111 | void uart_init(unsigned int idx) |
Stefan Reinauer | 9fe20cb | 2012-12-07 17:18:43 -0800 | [diff] [blame] | 112 | { |
Kyösti Mälkki | 70342a7 | 2014-03-14 22:28:29 +0200 | [diff] [blame] | 113 | struct s5p_uart *uart = uart_platform_baseptr(idx); |
Kyösti Mälkki | c2610a4 | 2014-02-24 20:51:30 +0200 | [diff] [blame] | 114 | exynos5_init_dev(uart); |
Stefan Reinauer | 9fe20cb | 2012-12-07 17:18:43 -0800 | [diff] [blame] | 115 | } |
| 116 | |
Felix Held | e3a1247 | 2020-09-11 15:47:09 +0200 | [diff] [blame] | 117 | unsigned char uart_rx_byte(unsigned int idx) |
Stefan Reinauer | 9fe20cb | 2012-12-07 17:18:43 -0800 | [diff] [blame] | 118 | { |
Kyösti Mälkki | 70342a7 | 2014-03-14 22:28:29 +0200 | [diff] [blame] | 119 | struct s5p_uart *uart = uart_platform_baseptr(idx); |
Kyösti Mälkki | c2610a4 | 2014-02-24 20:51:30 +0200 | [diff] [blame] | 120 | return exynos5_uart_rx_byte(uart); |
Stefan Reinauer | 9fe20cb | 2012-12-07 17:18:43 -0800 | [diff] [blame] | 121 | } |
| 122 | |
Felix Held | e3a1247 | 2020-09-11 15:47:09 +0200 | [diff] [blame] | 123 | void uart_tx_byte(unsigned int idx, unsigned char data) |
Stefan Reinauer | 9fe20cb | 2012-12-07 17:18:43 -0800 | [diff] [blame] | 124 | { |
Kyösti Mälkki | 70342a7 | 2014-03-14 22:28:29 +0200 | [diff] [blame] | 125 | struct s5p_uart *uart = uart_platform_baseptr(idx); |
Kyösti Mälkki | c2610a4 | 2014-02-24 20:51:30 +0200 | [diff] [blame] | 126 | exynos5_uart_tx_byte(uart, data); |
Stefan Reinauer | 9fe20cb | 2012-12-07 17:18:43 -0800 | [diff] [blame] | 127 | } |
Hung-Te Lin | 5f83f6c | 2013-02-04 14:38:03 +0800 | [diff] [blame] | 128 | |
Felix Held | e3a1247 | 2020-09-11 15:47:09 +0200 | [diff] [blame] | 129 | void uart_tx_flush(unsigned int idx) |
Stefan Reinauer | 08dc357 | 2013-05-14 16:57:50 -0700 | [diff] [blame] | 130 | { |
Kyösti Mälkki | 70342a7 | 2014-03-14 22:28:29 +0200 | [diff] [blame] | 131 | struct s5p_uart *uart = uart_platform_baseptr(idx); |
Kyösti Mälkki | c2610a4 | 2014-02-24 20:51:30 +0200 | [diff] [blame] | 132 | exynos5_uart_tx_flush(uart); |
Hung-Te Lin | 5f83f6c | 2013-02-04 14:38:03 +0800 | [diff] [blame] | 133 | } |
Kyösti Mälkki | bbf6f3d | 2014-03-15 01:32:55 +0200 | [diff] [blame] | 134 | |
Kyösti Mälkki | bbf6f3d | 2014-03-15 01:32:55 +0200 | [diff] [blame] | 135 | void uart_fill_lb(void *data) |
| 136 | { |
| 137 | struct lb_serial serial; |
| 138 | serial.type = LB_SERIAL_TYPE_MEMORY_MAPPED; |
Kyösti Mälkki | 70342a7 | 2014-03-14 22:28:29 +0200 | [diff] [blame] | 139 | serial.baseaddr = uart_platform_base(CONFIG_UART_FOR_CONSOLE); |
Julien Viard de Galbert | 235daa4 | 2018-02-20 11:45:48 +0100 | [diff] [blame] | 140 | serial.baud = get_uart_baudrate(); |
Patrick Georgi | a7cac0c | 2016-02-19 17:33:26 +0100 | [diff] [blame] | 141 | serial.regwidth = 4; |
Jacob Garber | 7839827 | 2019-07-24 11:12:09 -0600 | [diff] [blame] | 142 | serial.input_hertz = uart_platform_refclk(); |
| 143 | serial.uart_pci_addr = CONFIG_UART_PCI_ADDR; |
Kyösti Mälkki | bbf6f3d | 2014-03-15 01:32:55 +0200 | [diff] [blame] | 144 | lb_add_serial(&serial, data); |
| 145 | |
| 146 | lb_add_console(LB_TAG_CONSOLE_SERIAL8250MEM, data); |
| 147 | } |