blob: 524286b62a28e787237fa485a94fd8ef901b452d [file] [log] [blame]
Soby Mathewb4c6df42022-11-09 11:13:29 +00001/*
2 * SPDX-License-Identifier: BSD-3-Clause
3 * SPDX-FileCopyrightText: Copyright TF-RMM Contributors.
4 */
5
Soby Mathew8218e082024-02-26 14:09:28 +00006#include <assert.h>
7#include <console.h>
8#include <errno.h>
Soby Mathewb4c6df42022-11-09 11:13:29 +00009#include <mmio.h>
10#include <pl011.h>
11#include <utils_def.h>
12
Soby Mathew8218e082024-02-26 14:09:28 +000013/* PL011 Registers */
14#define UARTDR 0x00U
15#define UARTECR 0x04U
16#define UARTFR 0x18U
17
Jacob Man Chun Yiue143aea2025-02-26 16:11:18 +000018/* Transmit FIFO full */
19#define PL011_UARTFR_TXFF (U(1) << 5)
20
21#ifndef PL011_GENERIC_SBSA_UART
22
Soby Mathew8218e082024-02-26 14:09:28 +000023/* PL011 registers (out of the SBSA specification) */
24#define UARTIBRD 0x24U
25#define UARTFBRD 0x28U
26#define UARTLCR_H 0x2CU
27#define UARTCR 0x30U
Soby Mathew8218e082024-02-26 14:09:28 +000028/* Flag reg bits */
29
Soby Mathew8218e082024-02-26 14:09:28 +000030/* Control reg bits */
31#define PL011_UARTCR_RXE (U(1) << 9) /* Receive enable */
32#define PL011_UARTCR_TXE (U(1) << 8) /* Transmit enable */
33#define PL011_UARTCR_UARTEN (U(1) << 0) /* UART Enable */
34
35/* FIFO Enabled / No Parity / 8 Data bit / One Stop Bit */
36#define PL011_LINE_CONTROL (PL011_UARTLCR_H_FEN | PL011_UARTLCR_H_WLEN_8)
37
38/* Line Control Register Bits */
39#define PL011_UARTLCR_H_WLEN_8 (U(3) << 5)
40#define PL011_UARTLCR_H_FEN (U(1) << 4) /* FIFOs Enable */
41
Jacob Man Chun Yiue143aea2025-02-26 16:11:18 +000042#endif /* PL011_GENERIC_SBSA_UART */
43
Soby Mathew8218e082024-02-26 14:09:28 +000044static inline void pl011_wait(uintptr_t base)
Soby Mathewb4c6df42022-11-09 11:13:29 +000045{
46 /* Wait until there is room in the Tx FIFO */
Soby Mathew8218e082024-02-26 14:09:28 +000047 while ((read32((void *)(base + UARTFR))
Soby Mathewb4c6df42022-11-09 11:13:29 +000048 & PL011_UARTFR_TXFF) != 0U) {
49 /* Do nothing */
50 }
51}
52
Soby Mathew8218e082024-02-26 14:09:28 +000053static void writechar(uintptr_t base, int ch)
54{
55 pl011_wait(base);
56 write8((uint8_t)ch, (void *)(base + UARTDR));
57}
58
59/* Serial output - called from console driver */
60/* coverity[misra_c_2012_rule_8_7_violation:SUPPRESS] */
Shruti Gupta0a0d4ee2024-04-22 21:37:25 +010061static int pl011_putc(int c, const struct console *csl)
Soby Mathew8218e082024-02-26 14:09:28 +000062{
63 assert(csl != NULL);
64
65 if ((char)c == '\n') {
66 /* NOLINTNEXTLINE(google-readability-casting) */
67 writechar(csl->base, (int)'\r');
68 }
69 writechar(csl->base, c);
70
71 return c;
72}
73
74static struct console pl011_csl = {
75 .putc = pl011_putc,
76 .flush = NULL
77};
78
79/* Function that initializes PL011 for console output */
80int pl011_init(uintptr_t base_addr,
Soby Mathewb4c6df42022-11-09 11:13:29 +000081 unsigned int uart_clk,
82 unsigned int baud_rate)
83{
Soby Mathewb4c6df42022-11-09 11:13:29 +000084 /* Check Base address, baud rate and UART clock for sanity */
Soby Mathew8218e082024-02-26 14:09:28 +000085 if ((base_addr == 0UL) || (uart_clk == 0U) ||
86 (baud_rate == 0U)) {
87 return -EINVAL;
Soby Mathewb4c6df42022-11-09 11:13:29 +000088 }
Jacob Man Chun Yiue143aea2025-02-26 16:11:18 +000089#ifndef PL011_GENERIC_SBSA_UART
90 unsigned int div;
Soby Mathewb4c6df42022-11-09 11:13:29 +000091
92 /* Disable UART before programming */
Soby Mathew8218e082024-02-26 14:09:28 +000093 write32(0U, (void *)(base_addr + UARTCR));
Soby Mathewb4c6df42022-11-09 11:13:29 +000094
AlexeiFedorov33656a32023-08-30 11:51:41 +010095 /* Program the baud rate */
96 div = (uart_clk * 4U) / baud_rate;
Soby Mathewb4c6df42022-11-09 11:13:29 +000097
98 /* IBRD = Divisor >> 6 */
Soby Mathew8218e082024-02-26 14:09:28 +000099 write32(div >> 6, (void *)((base_addr) + UARTIBRD));
Soby Mathewb4c6df42022-11-09 11:13:29 +0000100
101 /* FBRD = Divisor & 0x3F */
Soby Mathew8218e082024-02-26 14:09:28 +0000102 write32(div & 0x3fU, (void *)((base_addr) + UARTFBRD));
Soby Mathewb4c6df42022-11-09 11:13:29 +0000103
104 /* Enable FIFO and set word length, parity and number of stop bits */
Soby Mathew8218e082024-02-26 14:09:28 +0000105 write32(PL011_LINE_CONTROL, (void *)((base_addr) + UARTLCR_H));
Jacob Man Chun Yiue143aea2025-02-26 16:11:18 +0000106#endif /* PL011_GENERIC_SBSA_UART */
Soby Mathewb4c6df42022-11-09 11:13:29 +0000107
108 /* Clear any pending errors */
Soby Mathew8218e082024-02-26 14:09:28 +0000109 write32(0U, (void *)((base_addr) + UARTECR));
Soby Mathewb4c6df42022-11-09 11:13:29 +0000110
Jacob Man Chun Yiue143aea2025-02-26 16:11:18 +0000111#ifndef PL011_GENERIC_SBSA_UART
Soby Mathewb4c6df42022-11-09 11:13:29 +0000112 /* Enable Tx, Rx, and UART overall */
113 write32(PL011_UARTCR_RXE | PL011_UARTCR_TXE | PL011_UARTCR_UARTEN,
Soby Mathew8218e082024-02-26 14:09:28 +0000114 (void *)((base_addr) + UARTCR));
Jacob Man Chun Yiue143aea2025-02-26 16:11:18 +0000115#endif /* PL011_GENERIC_SBSA_UART */
Soby Mathewb4c6df42022-11-09 11:13:29 +0000116
Soby Mathew8218e082024-02-26 14:09:28 +0000117 pl011_csl.base = base_addr;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000118
Soby Mathew8218e082024-02-26 14:09:28 +0000119 return console_register(&pl011_csl);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000120}