1 /*
2 * Copyright (C) 2018-2022 Intel Corporation.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 #include <types.h>
8 #include <asm/lib/spinlock.h>
9 #include <pci.h>
10 #include <uart16550.h>
11 #include <asm/io.h>
12 #include <asm/cpu.h>
13 #include <asm/mmu.h>
14
15 #define MAX_BDF_LEN 8
16
17 struct console_uart {
18 bool enabled;
19
20 enum serial_dev_type type;
21 uint16_t port_address;
22 void *mmio_base_vaddr;
23 union pci_bdf bdf;
24
25 spinlock_t rx_lock;
26 spinlock_t tx_lock;
27
28 uint32_t reg_width;
29 };
30
31 #if defined(CONFIG_SERIAL_PIO_BASE)
32 static struct console_uart uart = {
33 .enabled = true,
34 .type = PIO,
35 .port_address = CONFIG_SERIAL_PIO_BASE,
36 .reg_width = 1,
37 };
38 #elif defined(CONFIG_SERIAL_PCI_BDF)
39 static struct console_uart uart = {
40 .enabled = true,
41 .type = PCI,
42 .bdf.value = CONFIG_SERIAL_PCI_BDF,
43 .reg_width = 4,
44 };
45 #elif defined(CONFIG_SERIAL_MMIO_BASE)
46 static struct console_uart uart = {
47 .enabled = true,
48 .type = MMIO,
49 .mmio_base_vaddr = (void *)CONFIG_SERIAL_MMIO_BASE,
50 .reg_width = 1,
51 };
52 #endif
53
54 typedef uint32_t uart_reg_t;
55
56 /**
57 * @pre uart->enabled == true
58 */
uart16550_read_reg(struct console_uart uart,uint16_t reg_idx)59 static inline uint32_t uart16550_read_reg(struct console_uart uart, uint16_t reg_idx)
60 {
61 if (uart.type == PIO) {
62 return pio_read8(uart.port_address + (reg_idx * uart.reg_width));
63 } else {
64 if (uart.reg_width == 4U) {
65 return mmio_read32(uart.mmio_base_vaddr + (reg_idx * uart.reg_width));
66 } else {
67 return mmio_read8(uart.mmio_base_vaddr + (reg_idx * uart.reg_width));
68 }
69 }
70 }
71
72 /**
73 * @pre uart->enabled == true
74 */
uart16550_write_reg(struct console_uart uart,uint32_t val,uint16_t reg_idx)75 static inline void uart16550_write_reg(struct console_uart uart, uint32_t val, uint16_t reg_idx)
76 {
77 if (uart.type == PIO) {
78 pio_write8(val, uart.port_address + (reg_idx * uart.reg_width));
79 } else {
80 if (uart.reg_width == 4U) {
81 mmio_write32(val, uart.mmio_base_vaddr + (reg_idx * uart.reg_width));
82 } else {
83 mmio_write8(val, uart.mmio_base_vaddr + (reg_idx * uart.reg_width));
84 }
85 }
86 }
87
uart16550_calc_baud_div(uint32_t ref_freq,uint32_t * baud_div_ptr,uint32_t baud_rate_arg)88 static void uart16550_calc_baud_div(uint32_t ref_freq, uint32_t *baud_div_ptr, uint32_t baud_rate_arg)
89 {
90 uint32_t baud_rate = baud_rate_arg;
91 uint32_t baud_multiplier = baud_rate < BAUD_460800 ? 16U : 13U;
92
93 if (baud_rate == 0U) {
94 baud_rate = BAUD_115200;
95 }
96 *baud_div_ptr = ref_freq / (baud_multiplier * baud_rate);
97 }
98
99 /**
100 * @pre uart->enabled == true
101 */
uart16550_set_baud_rate(uint32_t baud_rate)102 static void uart16550_set_baud_rate(uint32_t baud_rate)
103 {
104 uint32_t baud_div, duart_clock = UART_CLOCK_RATE;
105 uart_reg_t temp_reg;
106
107 /* Calculate baud divisor */
108 uart16550_calc_baud_div(duart_clock, &baud_div, baud_rate);
109
110 /* Enable DLL and DLM registers for setting the Divisor */
111 temp_reg = uart16550_read_reg(uart, UART16550_LCR);
112 temp_reg |= LCR_DLAB;
113 uart16550_write_reg(uart, temp_reg, UART16550_LCR);
114
115 /* Write the appropriate divisor value */
116 uart16550_write_reg(uart, ((baud_div >> 8U) & 0xFFU), UART16550_DLM);
117 uart16550_write_reg(uart, (baud_div & 0xFFU), UART16550_DLL);
118
119 /* Disable DLL and DLM registers */
120 temp_reg &= ~LCR_DLAB;
121 uart16550_write_reg(uart, temp_reg, UART16550_LCR);
122 }
123
124 static uint8_t uart_pde_page[PAGE_SIZE]__aligned(PAGE_SIZE);
125 static uint8_t uart_pdpte_page[PAGE_SIZE]__aligned(PAGE_SIZE);
126
early_pgtable_map_uart(uint64_t addr)127 static void early_pgtable_map_uart(uint64_t addr)
128 {
129 uint64_t *pml4e, *pdpte, *pde;
130 uint64_t value;
131
132 CPU_CR_READ(cr3, &value);
133 /*assumpiton for map high mmio in early pagetable is that it is only used for
134 2MB page since 1G page may not available when memory width is 39bit */
135 pml4e = pml4e_offset((uint64_t *)value, addr);
136 /* address is above 512G */
137 if(!(*pml4e & PAGE_PRESENT)) {
138 *pml4e = hva2hpa_early(uart_pdpte_page) + (PAGE_PRESENT|PAGE_RW);
139 }
140 pdpte = pdpte_offset(pml4e, addr);
141 if(!(*pdpte & PAGE_PRESENT)) {
142 *(pdpte) = hva2hpa_early(uart_pde_page) + (PAGE_PRESENT|PAGE_RW);
143 pde = pde_offset(pdpte, addr);
144 *pde = (addr & PDE_MASK) + (PAGE_PRESENT|PAGE_RW|PAGE_PSE);
145 } else if(!(*pdpte & PAGE_PSE)) {
146 pde = pde_offset(pdpte, addr);
147 if(!(*pde & PAGE_PRESENT)) {
148 *pde = (addr & PDE_MASK) + (PAGE_PRESENT|PAGE_RW|PAGE_PSE);
149 }
150 }
151 }
152
uart16550_init(bool early_boot)153 void uart16550_init(bool early_boot)
154 {
155 void *mmio_base_va = NULL;
156
157 if (!uart.enabled) {
158 return;
159 }
160
161 if (!early_boot) {
162 if (uart.type == MMIO) {
163 mmio_base_va = hpa2hva(hva2hpa_early(uart.mmio_base_vaddr));
164 if (mmio_base_va != NULL) {
165 set_paging_supervisor((uint64_t)mmio_base_va, PDE_SIZE);
166 }
167 }
168 return;
169 }
170
171 /* if configure serial PCI BDF, get its base MMIO address */
172 if (uart.type == PCI) {
173 uint32_t bar0 = pci_pdev_read_cfg(uart.bdf, pci_bar_offset(0), 4U);
174
175 if ((bar0 & ~0xfU) == 0U) {
176 /* in case the PCI UART BAR is reset to 0 after boot */
177 uart.enabled = false;
178 return;
179 } else {
180 uint16_t cmd = (uint16_t)pci_pdev_read_cfg(uart.bdf, PCIR_COMMAND, 2U);
181 if ((bar0 & 0x3U) == PCIM_BAR_IO_SPACE) { /* IO Space */
182 uart.type = PIO;
183 uart.port_address = (uint16_t)(bar0 & PCI_BASE_ADDRESS_IO_MASK);
184 uart.reg_width = 1;
185 pci_pdev_write_cfg(uart.bdf, PCIR_COMMAND, 2U, cmd | PCIM_CMD_PORTEN);
186 } else if (((bar0 & 0x7U) == 0U) || ((bar0 & 0x7U) == 4U)) {
187 uart.type = MMIO;
188 uint32_t bar_hi = pci_pdev_read_cfg(uart.bdf, pci_bar_offset(1), 4U);
189 uint64_t addr = (bar0 & PCI_BASE_ADDRESS_MEM_MASK)|(((uint64_t)bar_hi) << 32U);
190 if (bar_hi != 0U) {
191 early_pgtable_map_uart(addr);
192 }
193 uart.mmio_base_vaddr = hpa2hva_early(addr);
194 pci_pdev_write_cfg(uart.bdf, PCIR_COMMAND, 2U, cmd | PCIM_CMD_MEMEN);
195 } else {
196 uart.enabled = false;
197 return;
198 }
199 }
200 }
201
202 spinlock_init(&uart.rx_lock);
203 spinlock_init(&uart.tx_lock);
204
205 /* Enable TX and RX FIFOs */
206 uart16550_write_reg(uart, FCR_FIFOE | FCR_RFR | FCR_TFR, UART16550_FCR);
207
208 /* Set-up data bits / parity / stop bits. */
209 uart16550_write_reg(uart, (LCR_WL8 | LCR_NB_STOP_BITS_1 | LCR_PARITY_NONE), UART16550_LCR);
210
211 /* Disable interrupts (we use polling) */
212 uart16550_write_reg(uart, UART_IER_DISABLE_ALL, UART16550_IER);
213
214 /* Set baud rate */
215 uart16550_set_baud_rate(BAUD_115200);
216
217 /* Data terminal ready + Request to send */
218 uart16550_write_reg(uart, MCR_RTS | MCR_DTR, UART16550_MCR);
219 }
220
uart16550_getc(void)221 char uart16550_getc(void)
222 {
223 char ret = -1;
224 uint64_t rflags;
225
226 if (!uart.enabled) {
227 return ret;
228 }
229
230 spinlock_irqsave_obtain(&uart.rx_lock, &rflags);
231 /* If a character has been received, read it */
232 if ((uart16550_read_reg(uart, UART16550_LSR) & LSR_DR) == LSR_DR) {
233 /* Read a character */
234 ret = uart16550_read_reg(uart, UART16550_RBR);
235
236 }
237 spinlock_irqrestore_release(&uart.rx_lock, rflags);
238 return ret;
239 }
240
241 /**
242 * @pre uart->enabled == true
243 */
uart16550_putc(char c)244 static void uart16550_putc(char c)
245 {
246 uint8_t temp;
247 uint32_t reg;
248
249 /* Ensure there are no further Transmit buffer write requests */
250 do {
251 reg = uart16550_read_reg(uart, UART16550_LSR);
252 } while ((reg & LSR_THRE) == 0U || (reg & LSR_TEMT) == 0U);
253
254 temp = (uint8_t)c;
255 /* Transmit the character. */
256 uart16550_write_reg(uart, (uint32_t)temp, UART16550_THR);
257 }
258
uart16550_puts(const char * buf,uint32_t len)259 size_t uart16550_puts(const char *buf, uint32_t len)
260 {
261 uint32_t i;
262 uint64_t rflags;
263
264 if (!uart.enabled) {
265 return len;
266 }
267
268 spinlock_irqsave_obtain(&uart.tx_lock, &rflags);
269 for (i = 0U; i < len; i++) {
270 /* Transmit character */
271 uart16550_putc(*buf);
272 if (*buf == '\n') {
273 /* Append '\r', no need change the len */
274 uart16550_putc('\r');
275 }
276 buf++;
277 }
278 spinlock_irqrestore_release(&uart.tx_lock, rflags);
279 return len;
280 }
281
uart16550_set_property(bool enabled,enum serial_dev_type uart_type,uint64_t data)282 void uart16550_set_property(bool enabled, enum serial_dev_type uart_type, uint64_t data)
283 {
284 uart.enabled = enabled;
285 uart.type = uart_type;
286 uart.bdf.value = 0U;
287
288 if (uart_type == PIO) {
289 uart.port_address = data;
290 } else if (uart_type == PCI) {
291 uart.bdf.value = data;
292 uart.reg_width = 4;
293 } else if (uart_type == MMIO) {
294 uart.mmio_base_vaddr = (void *)data;
295 uart.reg_width = 1;
296 }
297 }
298
is_pci_dbg_uart(union pci_bdf bdf_value)299 bool is_pci_dbg_uart(union pci_bdf bdf_value)
300 {
301 bool ret = false;
302
303 if (uart.enabled && (uart.bdf.value != 0)) {
304 if (bdf_value.value == uart.bdf.value) {
305 ret = true;
306 }
307 }
308
309 return ret;
310 }
311
get_pio_dbg_uart_cfg(uint16_t * pio_address,uint32_t * nbytes)312 bool get_pio_dbg_uart_cfg(uint16_t *pio_address, uint32_t *nbytes)
313 {
314 bool ret = false;
315
316 if (uart.enabled && (uart.type == PIO)) {
317 *pio_address = uart.port_address;
318 *nbytes = 8U;
319 ret = true;
320 }
321
322 return ret;
323 }
324