blob: 0508567d6d36eabb6013acbc4fd4fd3b701a6ef7 [file] [log] [blame]
Gabe Black607c0b62013-05-16 05:45:57 -07001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2009 Samsung Electronics
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
Gabe Black607c0b62013-05-16 05:45:57 -070014 */
15
Gabe Black607c0b62013-05-16 05:45:57 -070016#include <arch/io.h>
Kyösti Mälkkibbf6f3d2014-03-15 01:32:55 +020017#include <boot/coreboot_tables.h>
Julius Werner80af4422014-10-20 13:18:56 -070018#include <console/uart.h>
19#include <soc/clk.h>
20#include <soc/cpu.h>
21#include <soc/periph.h>
22#include <soc/uart.h>
23#include <types.h>
Gabe Black607c0b62013-05-16 05:45:57 -070024
25#define RX_FIFO_COUNT_MASK 0xff
26#define RX_FIFO_FULL_MASK (1 << 8)
27#define TX_FIFO_FULL_MASK (1 << 24)
28
Gabe Black607c0b62013-05-16 05:45:57 -070029
30/*
31 * The coefficient, used to calculate the baudrate on S5P UARTs is
32 * calculated as
33 * C = UBRDIV * 16 + number_of_set_bits_in_UDIVSLOT
Martin Roth1fc2ba52014-12-07 14:59:11 -070034 * however, section 31.6.11 of the datasheet doesn't recommend using 1 for 1,
Gabe Black607c0b62013-05-16 05:45:57 -070035 * 3 for 2, ... (2^n - 1) for n, instead, they suggest using these constants:
36 */
37static const int udivslot[] = {
38 0,
39 0x0080,
40 0x0808,
41 0x0888,
42 0x2222,
43 0x4924,
44 0x4a52,
45 0x54aa,
46 0x5555,
47 0xd555,
48 0xd5d5,
49 0xddd5,
50 0xdddd,
51 0xdfdd,
52 0xdfdf,
53 0xffdf,
54};
55
Kyösti Mälkkic2610a42014-02-24 20:51:30 +020056static void serial_setbrg_dev(struct s5p_uart *uart)
Gabe Black607c0b62013-05-16 05:45:57 -070057{
Gabe Black607c0b62013-05-16 05:45:57 -070058 u32 uclk;
Gabe Black607c0b62013-05-16 05:45:57 -070059 u32 val;
60
61 // All UARTs share the same clock.
62 uclk = clock_get_periph_rate(PERIPH_ID_UART3);
Kyösti Mälkkic5332e32014-02-19 08:58:12 +020063 val = uclk / default_baudrate();
Gabe Black607c0b62013-05-16 05:45:57 -070064
Julius Werner2f37bd62015-02-19 14:51:15 -080065 write32(&uart->ubrdiv, val / 16 - 1);
Gabe Black607c0b62013-05-16 05:45:57 -070066
67 /*
68 * FIXME(dhendrix): the original uart.h had a "br_rest" value which
69 * does not seem relevant to the exynos5420... not entirely sure
70 * where/if we need to worry about it here
71 */
72#if 0
73 if (s5p_uart_divslot())
74 writel(udivslot[val % 16], &uart->rest.slot);
75 else
76 writeb(val % 16, &uart->rest.value);
77#endif
78}
79
80/*
81 * Initialise the serial port with the given baudrate. The settings
82 * are always 8 data bits, no parity, 1 stop bit, no start bits.
83 */
Kyösti Mälkkic2610a42014-02-24 20:51:30 +020084static void exynos5_init_dev(struct s5p_uart *uart)
Gabe Black607c0b62013-05-16 05:45:57 -070085{
Gabe Black607c0b62013-05-16 05:45:57 -070086 /* enable FIFOs */
Julius Werner2f37bd62015-02-19 14:51:15 -080087 write32(&uart->ufcon, 0x1);
88 write32(&uart->umcon, 0);
Gabe Black607c0b62013-05-16 05:45:57 -070089 /* 8N1 */
Julius Werner2f37bd62015-02-19 14:51:15 -080090 write32(&uart->ulcon, 0x3);
Gabe Black607c0b62013-05-16 05:45:57 -070091 /* No interrupts, no DMA, pure polling */
Julius Werner2f37bd62015-02-19 14:51:15 -080092 write32(&uart->ucon, 0x245);
Gabe Black607c0b62013-05-16 05:45:57 -070093
Kyösti Mälkkic2610a42014-02-24 20:51:30 +020094 serial_setbrg_dev(uart);
Gabe Black607c0b62013-05-16 05:45:57 -070095}
96
Kyösti Mälkkic2610a42014-02-24 20:51:30 +020097static int exynos5_uart_err_check(struct s5p_uart *uart, int op)
Gabe Black607c0b62013-05-16 05:45:57 -070098{
Gabe Black607c0b62013-05-16 05:45:57 -070099 unsigned int mask;
100
101 /*
102 * UERSTAT
103 * Break Detect [3]
104 * Frame Err [2] : receive operation
105 * Parity Err [1] : receive operation
106 * Overrun Err [0] : receive operation
107 */
108 if (op)
109 mask = 0x8;
110 else
111 mask = 0xf;
112
Julius Werner2f37bd62015-02-19 14:51:15 -0800113 return read32(&uart->uerstat) & mask;
Gabe Black607c0b62013-05-16 05:45:57 -0700114}
115
116/*
117 * Read a single byte from the serial port. Returns 1 on success, 0
Martin Roth1fc2ba52014-12-07 14:59:11 -0700118 * otherwise. When the function is successful, the character read is
Gabe Black607c0b62013-05-16 05:45:57 -0700119 * written into its argument c.
120 */
Kyösti Mälkkic2610a42014-02-24 20:51:30 +0200121static unsigned char exynos5_uart_rx_byte(struct s5p_uart *uart)
Gabe Black607c0b62013-05-16 05:45:57 -0700122{
Gabe Black607c0b62013-05-16 05:45:57 -0700123 /* wait for character to arrive */
Julius Werner2f37bd62015-02-19 14:51:15 -0800124 while (!(read32(&uart->ufstat) & (RX_FIFO_COUNT_MASK |
Gabe Black607c0b62013-05-16 05:45:57 -0700125 RX_FIFO_FULL_MASK))) {
Kyösti Mälkkic2610a42014-02-24 20:51:30 +0200126 if (exynos5_uart_err_check(uart, 0))
Gabe Black607c0b62013-05-16 05:45:57 -0700127 return 0;
128 }
129
Julius Werner2f37bd62015-02-19 14:51:15 -0800130 return read8(&uart->urxh) & 0xff;
Gabe Black607c0b62013-05-16 05:45:57 -0700131}
132
133/*
134 * Output a single byte to the serial port.
135 */
Kyösti Mälkkic2610a42014-02-24 20:51:30 +0200136static void exynos5_uart_tx_byte(struct s5p_uart *uart, unsigned char data)
Gabe Black607c0b62013-05-16 05:45:57 -0700137{
Gabe Black607c0b62013-05-16 05:45:57 -0700138 /* wait for room in the tx FIFO */
Julius Werner2f37bd62015-02-19 14:51:15 -0800139 while ((read32(&uart->ufstat) & TX_FIFO_FULL_MASK)) {
Kyösti Mälkkic2610a42014-02-24 20:51:30 +0200140 if (exynos5_uart_err_check(uart, 1))
Gabe Black607c0b62013-05-16 05:45:57 -0700141 return;
142 }
143
Julius Werner2f37bd62015-02-19 14:51:15 -0800144 write8(&uart->utxh, data);
Gabe Black607c0b62013-05-16 05:45:57 -0700145}
146
Ronald G. Minnich2adb2972014-10-16 10:53:48 +0000147uintptr_t uart_platform_base(int idx)
Kyösti Mälkkic2610a42014-02-24 20:51:30 +0200148{
Kyösti Mälkki70342a72014-03-14 22:28:29 +0200149 if (idx < 4)
150 return 0x12c00000 + idx * 0x10000;
151 else
152 return 0;
Kyösti Mälkkic2610a42014-02-24 20:51:30 +0200153}
154
Kyösti Mälkki70342a72014-03-14 22:28:29 +0200155void uart_init(int idx)
Gabe Black607c0b62013-05-16 05:45:57 -0700156{
Kyösti Mälkki70342a72014-03-14 22:28:29 +0200157 struct s5p_uart *uart = uart_platform_baseptr(idx);
Kyösti Mälkkic2610a42014-02-24 20:51:30 +0200158 exynos5_init_dev(uart);
Gabe Black607c0b62013-05-16 05:45:57 -0700159}
160
Kyösti Mälkki70342a72014-03-14 22:28:29 +0200161unsigned char uart_rx_byte(int idx)
Gabe Black607c0b62013-05-16 05:45:57 -0700162{
Kyösti Mälkki70342a72014-03-14 22:28:29 +0200163 struct s5p_uart *uart = uart_platform_baseptr(idx);
Kyösti Mälkkic2610a42014-02-24 20:51:30 +0200164 return exynos5_uart_rx_byte(uart);
Gabe Black607c0b62013-05-16 05:45:57 -0700165}
166
Kyösti Mälkki70342a72014-03-14 22:28:29 +0200167void uart_tx_byte(int idx, unsigned char data)
Gabe Black607c0b62013-05-16 05:45:57 -0700168{
Kyösti Mälkki70342a72014-03-14 22:28:29 +0200169 struct s5p_uart *uart = uart_platform_baseptr(idx);
Kyösti Mälkkic2610a42014-02-24 20:51:30 +0200170 exynos5_uart_tx_byte(uart, data);
Gabe Black607c0b62013-05-16 05:45:57 -0700171}
172
Kyösti Mälkki70342a72014-03-14 22:28:29 +0200173void uart_tx_flush(int idx)
Gabe Black607c0b62013-05-16 05:45:57 -0700174{
Kyösti Mälkkic2610a42014-02-24 20:51:30 +0200175 /* Exynos5250 implements this too. */
Gabe Black607c0b62013-05-16 05:45:57 -0700176}
Kyösti Mälkkibbf6f3d2014-03-15 01:32:55 +0200177
178#ifndef __PRE_RAM__
179void uart_fill_lb(void *data)
180{
181 struct lb_serial serial;
182 serial.type = LB_SERIAL_TYPE_MEMORY_MAPPED;
Kyösti Mälkki70342a72014-03-14 22:28:29 +0200183 serial.baseaddr = uart_platform_base(CONFIG_UART_FOR_CONSOLE);
Kyösti Mälkkibbf6f3d2014-03-15 01:32:55 +0200184 serial.baud = default_baudrate();
Vadim Bendebury9dccf1c2015-01-09 16:54:19 -0800185 serial.regwidth = 1;
Kyösti Mälkkibbf6f3d2014-03-15 01:32:55 +0200186 lb_add_serial(&serial, data);
187
188 lb_add_console(LB_TAG_CONSOLE_SERIAL8250MEM, data);
189}
190#endif