• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
3 #include <types.h>
4 #include <console/uart.h>
5 #include <device/mmio.h>
6 #include <boot/coreboot_tables.h>
7 #include <soc/ti/am335x/uart.h>
8 
9 #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)
17 
18 /*
19  * Initialise the serial port with the given baudrate divisor. The settings
20  * are always 8 data bits, no parity, 1 stop bit, no start bits.
21  */
am335x_uart_init(struct am335x_uart * uart,uint16_t div)22 static void am335x_uart_init(struct am335x_uart *uart, uint16_t div)
23 {
24 	uint16_t lcr_orig, efr_orig, mcr_orig;
25 
26 	/* reset the UART */
27 	write16(&uart->sysc, uart->sysc | SYSC_SOFTRESET);
28 	while (!(read16(&uart->syss) & SYSS_RESETDONE))
29 		;
30 
31 	/* 1. switch to register config mode B */
32 	lcr_orig = read16(&uart->lcr);
33 	write16(&uart->lcr, 0xbf);
34 
35 	/*
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);
40 	write16(&uart->efr, efr_orig | EFR_ENHANCED_EN);
41 
42 	/* 3. Switch to register config mode A */
43 	write16(&uart->lcr, 0x80);
44 
45 	/* 4. Enable register submode TCR_TLR to access the UARTi.UART_TLR */
46 	mcr_orig = read16(&uart->mcr);
47 	write16(&uart->mcr, mcr_orig | MCR_TCR_TLR);
48 
49 	/* 5. Enable the FIFO. For now we'll ignore FIFO triggers and DMA */
50 	write16(&uart->fcr, FCR_FIFO_EN);
51 
52 	/* 6. Switch to configuration mode B */
53 	write16(&uart->lcr, 0xbf);
54 	/* Skip steps 7 and 8 (setting up FIFO triggers for DMA) */
55 
56 	/* 9. Restore original EFR value */
57 	write16(&uart->efr, efr_orig);
58 
59 	/* 10. Switch to config mode A */
60 	write16(&uart->lcr, 0x80);
61 
62 	/* 11. Restore original MCR value */
63 	write16(&uart->mcr, mcr_orig);
64 
65 	/* 12. Restore original LCR value */
66 	write16(&uart->lcr, lcr_orig);
67 
68 	/* Protocol, baud rate and interrupt settings */
69 
70 	/* 1. Disable UART access to DLL and DLH registers */
71 	write16(&uart->mdr1, read16(&uart->mdr1) | 0x7);
72 
73 	/* 2. Switch to config mode B */
74 	write16(&uart->lcr, 0xbf);
75 
76 	/* 3. Enable access to IER[7:4] */
77 	write16(&uart->efr, efr_orig | EFR_ENHANCED_EN);
78 
79 	/* 4. Switch to operational mode */
80 	write16(&uart->lcr, 0x0);
81 
82 	/* 5. Clear IER */
83 	write16(&uart->ier, 0x0);
84 
85 	/* 6. Switch to config mode B */
86 	write16(&uart->lcr, 0xbf);
87 
88 	/* 7. Set dll and dlh to the desired values (table 19-25) */
89 	write16(&uart->dlh, (div >> 8));
90 	write16(&uart->dll, (div & 0xff));
91 
92 	/* 8. Switch to operational mode to access ier */
93 	write16(&uart->lcr, 0x0);
94 
95 	/* 9. Clear ier to disable all interrupts */
96 	write16(&uart->ier, 0x0);
97 
98 	/* 10. Switch to config mode B */
99 	write16(&uart->lcr, 0xbf);
100 
101 	/* 11. Restore efr */
102 	write16(&uart->efr, efr_orig);
103 
104 	/* 12. Set protocol formatting 8n1 (8 bit data, no parity, 1 stop bit) */
105 	write16(&uart->lcr, 0x3);
106 
107 	/* 13. Load the new UART mode */
108 	write16(&uart->mdr1, 0x0);
109 }
110 
111 /*
112  * Read a single byte from the serial port. Returns 1 on success, 0
113  * otherwise. When the function is successful, the character read is
114  * written into its argument c.
115  */
am335x_uart_rx_byte(struct am335x_uart * uart)116 static unsigned char am335x_uart_rx_byte(struct am335x_uart *uart)
117 {
118 	while (!(read16(&uart->lsr) & LSR_RXFIFOE));
119 
120 	return read8(&uart->rhr);
121 }
122 
123 /*
124  * Output a single byte to the serial port.
125  */
am335x_uart_tx_byte(struct am335x_uart * uart,unsigned char data)126 static void am335x_uart_tx_byte(struct am335x_uart *uart, unsigned char data)
127 {
128 	while (!(read16(&uart->lsr) & LSR_TXFIFOE));
129 
130 	return write8(&uart->thr, data);
131 }
132 
uart_platform_refclk(void)133 unsigned int uart_platform_refclk(void)
134 {
135 	return 48000000;
136 }
137 
uart_platform_base(unsigned int idx)138 uintptr_t uart_platform_base(unsigned int idx)
139 {
140 	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;
147 }
148 
uart_init(unsigned int idx)149 void uart_init(unsigned int idx)
150 {
151 	struct am335x_uart *uart = uart_platform_baseptr(idx);
152 	uint16_t div = (uint16_t)uart_baudrate_divisor(
153 		get_uart_baudrate(), uart_platform_refclk(), 16);
154 	am335x_uart_init(uart, div);
155 }
156 
uart_rx_byte(unsigned int idx)157 unsigned char uart_rx_byte(unsigned int idx)
158 {
159 	struct am335x_uart *uart = uart_platform_baseptr(idx);
160 	return am335x_uart_rx_byte(uart);
161 }
162 
uart_tx_byte(unsigned int idx,unsigned char data)163 void uart_tx_byte(unsigned int idx, unsigned char data)
164 {
165 	struct am335x_uart *uart = uart_platform_baseptr(idx);
166 	am335x_uart_tx_byte(uart, data);
167 }
168 
uart_tx_flush(unsigned int idx)169 void uart_tx_flush(unsigned int idx)
170 {
171 }
172 
fill_lb_serial(struct lb_serial * serial)173 enum cb_err fill_lb_serial(struct lb_serial *serial)
174 {
175 	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();
180 
181 	return CB_SUCCESS;
182 }
183