blob: 16a4b11da314d5e4f4f59e301c54eab523cad7e6 [file] [log] [blame]
Angel Pons1ddb8942020-04-04 18:51:26 +02001/* SPDX-License-Identifier: GPL-2.0-only */
Gabe Black607c0b62013-05-16 05:45:57 -07002
Kyösti Mälkki13f66502019-03-03 08:01:05 +02003#include <device/mmio.h>
Kyösti Mälkkibbf6f3d2014-03-15 01:32:55 +02004#include <boot/coreboot_tables.h>
Julius Werner80af4422014-10-20 13:18:56 -07005#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 Black607c0b62013-05-16 05:45:57 -070011
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älkkic2610a42014-02-24 20:51:30 +020016static void serial_setbrg_dev(struct s5p_uart *uart)
Gabe Black607c0b62013-05-16 05:45:57 -070017{
Gabe Black607c0b62013-05-16 05:45:57 -070018 u32 uclk;
Gabe Black607c0b62013-05-16 05:45:57 -070019 u32 val;
20
21 // All UARTs share the same clock.
22 uclk = clock_get_periph_rate(PERIPH_ID_UART3);
Julien Viard de Galbert235daa42018-02-20 11:45:48 +010023 val = uclk / get_uart_baudrate();
Gabe Black607c0b62013-05-16 05:45:57 -070024
Julius Werner2f37bd62015-02-19 14:51:15 -080025 write32(&uart->ubrdiv, val / 16 - 1);
Gabe Black607c0b62013-05-16 05:45:57 -070026}
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älkkic2610a42014-02-24 20:51:30 +020032static void exynos5_init_dev(struct s5p_uart *uart)
Gabe Black607c0b62013-05-16 05:45:57 -070033{
Gabe Black607c0b62013-05-16 05:45:57 -070034 /* enable FIFOs */
Julius Werner2f37bd62015-02-19 14:51:15 -080035 write32(&uart->ufcon, 0x1);
36 write32(&uart->umcon, 0);
Gabe Black607c0b62013-05-16 05:45:57 -070037 /* 8N1 */
Julius Werner2f37bd62015-02-19 14:51:15 -080038 write32(&uart->ulcon, 0x3);
Gabe Black607c0b62013-05-16 05:45:57 -070039 /* No interrupts, no DMA, pure polling */
Julius Werner2f37bd62015-02-19 14:51:15 -080040 write32(&uart->ucon, 0x245);
Gabe Black607c0b62013-05-16 05:45:57 -070041
Kyösti Mälkkic2610a42014-02-24 20:51:30 +020042 serial_setbrg_dev(uart);
Gabe Black607c0b62013-05-16 05:45:57 -070043}
44
Kyösti Mälkkic2610a42014-02-24 20:51:30 +020045static int exynos5_uart_err_check(struct s5p_uart *uart, int op)
Gabe Black607c0b62013-05-16 05:45:57 -070046{
Gabe Black607c0b62013-05-16 05:45:57 -070047 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 Werner2f37bd62015-02-19 14:51:15 -080061 return read32(&uart->uerstat) & mask;
Gabe Black607c0b62013-05-16 05:45:57 -070062}
63
64/*
65 * Read a single byte from the serial port. Returns 1 on success, 0
Martin Roth1fc2ba52014-12-07 14:59:11 -070066 * otherwise. When the function is successful, the character read is
Gabe Black607c0b62013-05-16 05:45:57 -070067 * written into its argument c.
68 */
Kyösti Mälkkic2610a42014-02-24 20:51:30 +020069static unsigned char exynos5_uart_rx_byte(struct s5p_uart *uart)
Gabe Black607c0b62013-05-16 05:45:57 -070070{
Gabe Black607c0b62013-05-16 05:45:57 -070071 /* wait for character to arrive */
Julius Werner2f37bd62015-02-19 14:51:15 -080072 while (!(read32(&uart->ufstat) & (RX_FIFO_COUNT_MASK |
Gabe Black607c0b62013-05-16 05:45:57 -070073 RX_FIFO_FULL_MASK))) {
Kyösti Mälkkic2610a42014-02-24 20:51:30 +020074 if (exynos5_uart_err_check(uart, 0))
Gabe Black607c0b62013-05-16 05:45:57 -070075 return 0;
76 }
77
Julius Werner2f37bd62015-02-19 14:51:15 -080078 return read8(&uart->urxh) & 0xff;
Gabe Black607c0b62013-05-16 05:45:57 -070079}
80
81/*
82 * Output a single byte to the serial port.
83 */
Kyösti Mälkkic2610a42014-02-24 20:51:30 +020084static void exynos5_uart_tx_byte(struct s5p_uart *uart, unsigned char data)
Gabe Black607c0b62013-05-16 05:45:57 -070085{
Gabe Black607c0b62013-05-16 05:45:57 -070086 /* wait for room in the tx FIFO */
Julius Werner2f37bd62015-02-19 14:51:15 -080087 while ((read32(&uart->ufstat) & TX_FIFO_FULL_MASK)) {
Kyösti Mälkkic2610a42014-02-24 20:51:30 +020088 if (exynos5_uart_err_check(uart, 1))
Gabe Black607c0b62013-05-16 05:45:57 -070089 return;
90 }
91
Julius Werner2f37bd62015-02-19 14:51:15 -080092 write8(&uart->utxh, data);
Gabe Black607c0b62013-05-16 05:45:57 -070093}
94
Felix Helde3a12472020-09-11 15:47:09 +020095uintptr_t uart_platform_base(unsigned int idx)
Kyösti Mälkkic2610a42014-02-24 20:51:30 +020096{
Kyösti Mälkki70342a72014-03-14 22:28:29 +020097 if (idx < 4)
98 return 0x12c00000 + idx * 0x10000;
99 else
100 return 0;
Kyösti Mälkkic2610a42014-02-24 20:51:30 +0200101}
102
Felix Helde3a12472020-09-11 15:47:09 +0200103void uart_init(unsigned int idx)
Gabe Black607c0b62013-05-16 05:45:57 -0700104{
Kyösti Mälkki70342a72014-03-14 22:28:29 +0200105 struct s5p_uart *uart = uart_platform_baseptr(idx);
Kyösti Mälkkic2610a42014-02-24 20:51:30 +0200106 exynos5_init_dev(uart);
Gabe Black607c0b62013-05-16 05:45:57 -0700107}
108
Felix Helde3a12472020-09-11 15:47:09 +0200109unsigned char uart_rx_byte(unsigned int idx)
Gabe Black607c0b62013-05-16 05:45:57 -0700110{
Kyösti Mälkki70342a72014-03-14 22:28:29 +0200111 struct s5p_uart *uart = uart_platform_baseptr(idx);
Kyösti Mälkkic2610a42014-02-24 20:51:30 +0200112 return exynos5_uart_rx_byte(uart);
Gabe Black607c0b62013-05-16 05:45:57 -0700113}
114
Felix Helde3a12472020-09-11 15:47:09 +0200115void uart_tx_byte(unsigned int idx, unsigned char data)
Gabe Black607c0b62013-05-16 05:45:57 -0700116{
Kyösti Mälkki70342a72014-03-14 22:28:29 +0200117 struct s5p_uart *uart = uart_platform_baseptr(idx);
Kyösti Mälkkic2610a42014-02-24 20:51:30 +0200118 exynos5_uart_tx_byte(uart, data);
Gabe Black607c0b62013-05-16 05:45:57 -0700119}
120
Felix Helde3a12472020-09-11 15:47:09 +0200121void uart_tx_flush(unsigned int idx)
Gabe Black607c0b62013-05-16 05:45:57 -0700122{
Kyösti Mälkkic2610a42014-02-24 20:51:30 +0200123 /* Exynos5250 implements this too. */
Gabe Black607c0b62013-05-16 05:45:57 -0700124}
Kyösti Mälkkibbf6f3d2014-03-15 01:32:55 +0200125
Kyösti Mälkkibbf6f3d2014-03-15 01:32:55 +0200126void uart_fill_lb(void *data)
127{
128 struct lb_serial serial;
129 serial.type = LB_SERIAL_TYPE_MEMORY_MAPPED;
Kyösti Mälkki70342a72014-03-14 22:28:29 +0200130 serial.baseaddr = uart_platform_base(CONFIG_UART_FOR_CONSOLE);
Julien Viard de Galbert235daa42018-02-20 11:45:48 +0100131 serial.baud = get_uart_baudrate();
Patrick Georgia7cac0c2016-02-19 17:33:26 +0100132 serial.regwidth = 4;
Martin Rothff94e002016-11-18 10:34:24 -0700133 serial.input_hertz = uart_platform_refclk();
134 serial.uart_pci_addr = 0;
Kyösti Mälkkibbf6f3d2014-03-15 01:32:55 +0200135 lb_add_serial(&serial, data);
136
137 lb_add_console(LB_TAG_CONSOLE_SERIAL8250MEM, data);
138}