blob: 0543475d84f8a725cbed822a9d75b157a01aa843 [file] [log] [blame]
Patrick Georgiac959032020-05-05 22:49:26 +02001/* SPDX-License-Identifier: GPL-2.0-or-later */
Gabe Black3c7e9392013-05-26 07:15:57 -07002
3#include <types.h>
Kyösti Mälkki1d7541f2014-02-17 21:34:42 +02004#include <console/uart.h>
Kyösti Mälkki13f66502019-03-03 08:01:05 +02005#include <device/mmio.h>
Kyösti Mälkkibbf6f3d2014-03-15 01:32:55 +02006#include <boot/coreboot_tables.h>
Sam Lewisad7b2e22020-08-03 20:18:29 +10007#include <soc/ti/am335x/uart.h>
Gabe Black3c7e9392013-05-26 07:15:57 -07008
Gabe Black8cfa33e2013-06-11 21:58:18 -04009#define EFR_ENHANCED_EN (1 << 4)
10#define FCR_FIFO_EN (1 << 0)
11#define MCR_TCR_TLR (1 << 6)
12#define SYSC_SOFTRESET (1 << 1)
13#define SYSS_RESETDONE (1 << 0)
14
15#define LSR_RXFIFOE (1 << 0)
16#define LSR_TXFIFOE (1 << 5)
Gabe Black3c7e9392013-05-26 07:15:57 -070017
18/*
Kyösti Mälkki2cbcd2b2014-02-19 08:58:12 +020019 * Initialise the serial port with the given baudrate divisor. The settings
Gabe Black3c7e9392013-05-26 07:15:57 -070020 * are always 8 data bits, no parity, 1 stop bit, no start bits.
21 */
Kyösti Mälkkic2610a42014-02-24 20:51:30 +020022static void am335x_uart_init(struct am335x_uart *uart, uint16_t div)
Gabe Black3c7e9392013-05-26 07:15:57 -070023{
Gabe Black8cfa33e2013-06-11 21:58:18 -040024 uint16_t lcr_orig, efr_orig, mcr_orig;
Gabe Black3c7e9392013-05-26 07:15:57 -070025
Gabe Black8cfa33e2013-06-11 21:58:18 -040026 /* reset the UART */
Julius Werner2f37bd62015-02-19 14:51:15 -080027 write16(&uart->sysc, uart->sysc | SYSC_SOFTRESET);
Gabe Black8cfa33e2013-06-11 21:58:18 -040028 while (!(read16(&uart->syss) & SYSS_RESETDONE))
29 ;
Gabe Black3c7e9392013-05-26 07:15:57 -070030
Gabe Black8cfa33e2013-06-11 21:58:18 -040031 /* 1. switch to register config mode B */
32 lcr_orig = read16(&uart->lcr);
Julius Werner2f37bd62015-02-19 14:51:15 -080033 write16(&uart->lcr, 0xbf);
Gabe Black3c7e9392013-05-26 07:15:57 -070034
Gabe Black8cfa33e2013-06-11 21:58:18 -040035 /*
36 * 2. Set EFR ENHANCED_EN bit. To access this bit, registers must
37 * be in TCR_TLR submode, meaning EFR[4] = 1 and MCR[6] = 1.
38 */
39 efr_orig = read16(&uart->efr);
Julius Werner2f37bd62015-02-19 14:51:15 -080040 write16(&uart->efr, efr_orig | EFR_ENHANCED_EN);
Gabe Black8cfa33e2013-06-11 21:58:18 -040041
42 /* 3. Switch to register config mode A */
Julius Werner2f37bd62015-02-19 14:51:15 -080043 write16(&uart->lcr, 0x80);
Gabe Black8cfa33e2013-06-11 21:58:18 -040044
45 /* 4. Enable register submode TCR_TLR to access the UARTi.UART_TLR */
46 mcr_orig = read16(&uart->mcr);
Julius Werner2f37bd62015-02-19 14:51:15 -080047 write16(&uart->mcr, mcr_orig | MCR_TCR_TLR);
Gabe Black8cfa33e2013-06-11 21:58:18 -040048
49 /* 5. Enable the FIFO. For now we'll ignore FIFO triggers and DMA */
Julius Werner2f37bd62015-02-19 14:51:15 -080050 write16(&uart->fcr, FCR_FIFO_EN);
Gabe Black8cfa33e2013-06-11 21:58:18 -040051
52 /* 6. Switch to configuration mode B */
Julius Werner2f37bd62015-02-19 14:51:15 -080053 write16(&uart->lcr, 0xbf);
Gabe Black8cfa33e2013-06-11 21:58:18 -040054 /* Skip steps 7 and 8 (setting up FIFO triggers for DMA) */
55
56 /* 9. Restore original EFR value */
Julius Werner2f37bd62015-02-19 14:51:15 -080057 write16(&uart->efr, efr_orig);
Gabe Black8cfa33e2013-06-11 21:58:18 -040058
59 /* 10. Switch to config mode A */
Julius Werner2f37bd62015-02-19 14:51:15 -080060 write16(&uart->lcr, 0x80);
Gabe Black8cfa33e2013-06-11 21:58:18 -040061
62 /* 11. Restore original MCR value */
Julius Werner2f37bd62015-02-19 14:51:15 -080063 write16(&uart->mcr, mcr_orig);
Gabe Black8cfa33e2013-06-11 21:58:18 -040064
65 /* 12. Restore original LCR value */
Julius Werner2f37bd62015-02-19 14:51:15 -080066 write16(&uart->lcr, lcr_orig);
Gabe Black8cfa33e2013-06-11 21:58:18 -040067
68 /* Protocol, baud rate and interrupt settings */
69
70 /* 1. Disable UART access to DLL and DLH registers */
Julius Werner2f37bd62015-02-19 14:51:15 -080071 write16(&uart->mdr1, read16(&uart->mdr1) | 0x7);
Gabe Black8cfa33e2013-06-11 21:58:18 -040072
73 /* 2. Switch to config mode B */
Julius Werner2f37bd62015-02-19 14:51:15 -080074 write16(&uart->lcr, 0xbf);
Gabe Black8cfa33e2013-06-11 21:58:18 -040075
76 /* 3. Enable access to IER[7:4] */
Julius Werner2f37bd62015-02-19 14:51:15 -080077 write16(&uart->efr, efr_orig | EFR_ENHANCED_EN);
Gabe Black8cfa33e2013-06-11 21:58:18 -040078
79 /* 4. Switch to operational mode */
Julius Werner2f37bd62015-02-19 14:51:15 -080080 write16(&uart->lcr, 0x0);
Gabe Black8cfa33e2013-06-11 21:58:18 -040081
82 /* 5. Clear IER */
Julius Werner2f37bd62015-02-19 14:51:15 -080083 write16(&uart->ier, 0x0);
Gabe Black8cfa33e2013-06-11 21:58:18 -040084
85 /* 6. Switch to config mode B */
Julius Werner2f37bd62015-02-19 14:51:15 -080086 write16(&uart->lcr, 0xbf);
Gabe Black8cfa33e2013-06-11 21:58:18 -040087
88 /* 7. Set dll and dlh to the desired values (table 19-25) */
Julius Werner2f37bd62015-02-19 14:51:15 -080089 write16(&uart->dlh, (div >> 8));
90 write16(&uart->dll, (div & 0xff));
Gabe Black8cfa33e2013-06-11 21:58:18 -040091
92 /* 8. Switch to operational mode to access ier */
Julius Werner2f37bd62015-02-19 14:51:15 -080093 write16(&uart->lcr, 0x0);
Gabe Black8cfa33e2013-06-11 21:58:18 -040094
95 /* 9. Clear ier to disable all interrupts */
Julius Werner2f37bd62015-02-19 14:51:15 -080096 write16(&uart->ier, 0x0);
Gabe Black8cfa33e2013-06-11 21:58:18 -040097
98 /* 10. Switch to config mode B */
Julius Werner2f37bd62015-02-19 14:51:15 -080099 write16(&uart->lcr, 0xbf);
Gabe Black8cfa33e2013-06-11 21:58:18 -0400100
101 /* 11. Restore efr */
Julius Werner2f37bd62015-02-19 14:51:15 -0800102 write16(&uart->efr, efr_orig);
Gabe Black8cfa33e2013-06-11 21:58:18 -0400103
104 /* 12. Set protocol formatting 8n1 (8 bit data, no parity, 1 stop bit) */
Julius Werner2f37bd62015-02-19 14:51:15 -0800105 write16(&uart->lcr, 0x3);
Gabe Black8cfa33e2013-06-11 21:58:18 -0400106
107 /* 13. Load the new UART mode */
Julius Werner2f37bd62015-02-19 14:51:15 -0800108 write16(&uart->mdr1, 0x0);
Gabe Black3c7e9392013-05-26 07:15:57 -0700109}
110
111/*
112 * Read a single byte from the serial port. Returns 1 on success, 0
Martin Roth4c3ab732013-07-08 16:23:54 -0600113 * otherwise. When the function is successful, the character read is
Gabe Black3c7e9392013-05-26 07:15:57 -0700114 * written into its argument c.
115 */
Kyösti Mälkkic2610a42014-02-24 20:51:30 +0200116static unsigned char am335x_uart_rx_byte(struct am335x_uart *uart)
Gabe Black3c7e9392013-05-26 07:15:57 -0700117{
Gabe Black8cfa33e2013-06-11 21:58:18 -0400118 while (!(read16(&uart->lsr) & LSR_RXFIFOE));
Gabe Black3c7e9392013-05-26 07:15:57 -0700119
Gabe Black8cfa33e2013-06-11 21:58:18 -0400120 return read8(&uart->rhr);
Gabe Black3c7e9392013-05-26 07:15:57 -0700121}
122
123/*
124 * Output a single byte to the serial port.
125 */
Kyösti Mälkkic2610a42014-02-24 20:51:30 +0200126static void am335x_uart_tx_byte(struct am335x_uart *uart, unsigned char data)
Gabe Black3c7e9392013-05-26 07:15:57 -0700127{
Gabe Black8cfa33e2013-06-11 21:58:18 -0400128 while (!(read16(&uart->lsr) & LSR_TXFIFOE));
Gabe Black3c7e9392013-05-26 07:15:57 -0700129
Julius Werner2f37bd62015-02-19 14:51:15 -0800130 return write8(&uart->thr, data);
Gabe Black3c7e9392013-05-26 07:15:57 -0700131}
132
Kyösti Mälkki2cbcd2b2014-02-19 08:58:12 +0200133unsigned int uart_platform_refclk(void)
134{
135 return 48000000;
136}
137
Felix Helde3a12472020-09-11 15:47:09 +0200138uintptr_t uart_platform_base(unsigned int idx)
Kyösti Mälkkic2610a42014-02-24 20:51:30 +0200139{
Kyösti Mälkki70342a72014-03-14 22:28:29 +0200140 const unsigned int bases[] = {
141 0x44e09000, 0x48022000, 0x48024000,
142 0x481a6000, 0x481a8000, 0x481aa000
143 };
144 if (idx < ARRAY_SIZE(bases))
145 return bases[idx];
146 return 0;
Kyösti Mälkkic2610a42014-02-24 20:51:30 +0200147}
148
Felix Helde3a12472020-09-11 15:47:09 +0200149void uart_init(unsigned int idx)
Gabe Black3c7e9392013-05-26 07:15:57 -0700150{
Kyösti Mälkki70342a72014-03-14 22:28:29 +0200151 struct am335x_uart *uart = uart_platform_baseptr(idx);
Elyes Haouas816dbbc2022-11-18 15:08:44 +0100152 uint16_t div = (uint16_t)uart_baudrate_divisor(
Julien Viard de Galbert235daa42018-02-20 11:45:48 +0100153 get_uart_baudrate(), uart_platform_refclk(), 16);
Kyösti Mälkkic2610a42014-02-24 20:51:30 +0200154 am335x_uart_init(uart, div);
Gabe Black3c7e9392013-05-26 07:15:57 -0700155}
156
Felix Helde3a12472020-09-11 15:47:09 +0200157unsigned char uart_rx_byte(unsigned int idx)
Gabe Black3c7e9392013-05-26 07:15:57 -0700158{
Kyösti Mälkki70342a72014-03-14 22:28:29 +0200159 struct am335x_uart *uart = uart_platform_baseptr(idx);
Kyösti Mälkkic2610a42014-02-24 20:51:30 +0200160 return am335x_uart_rx_byte(uart);
Gabe Black3c7e9392013-05-26 07:15:57 -0700161}
162
Felix Helde3a12472020-09-11 15:47:09 +0200163void uart_tx_byte(unsigned int idx, unsigned char data)
Gabe Black3c7e9392013-05-26 07:15:57 -0700164{
Kyösti Mälkki70342a72014-03-14 22:28:29 +0200165 struct am335x_uart *uart = uart_platform_baseptr(idx);
Kyösti Mälkkic2610a42014-02-24 20:51:30 +0200166 am335x_uart_tx_byte(uart, data);
Gabe Black3c7e9392013-05-26 07:15:57 -0700167}
168
Felix Helde3a12472020-09-11 15:47:09 +0200169void uart_tx_flush(unsigned int idx)
Kyösti Mälkki0567c912014-02-14 10:31:38 +0200170{
Gabe Black3c7e9392013-05-26 07:15:57 -0700171}
Kyösti Mälkkibbf6f3d2014-03-15 01:32:55 +0200172
Arthur Heymans9948c522022-10-24 14:37:40 +0200173enum cb_err fill_lb_serial(struct lb_serial *serial)
Kyösti Mälkkibbf6f3d2014-03-15 01:32:55 +0200174{
Arthur Heymans9948c522022-10-24 14:37:40 +0200175 serial->type = LB_SERIAL_TYPE_MEMORY_MAPPED;
176 serial->baseaddr = uart_platform_base(CONFIG_UART_FOR_CONSOLE);
177 serial->baud = get_uart_baudrate();
178 serial->regwidth = 2;
179 serial->input_hertz = uart_platform_refclk();
Kyösti Mälkkibbf6f3d2014-03-15 01:32:55 +0200180
Arthur Heymans9948c522022-10-24 14:37:40 +0200181 return CB_SUCCESS;
Kyösti Mälkkibbf6f3d2014-03-15 01:32:55 +0200182}