blob: e7137bd6da6901f756aff938a62077844e829090 [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
18/* PL011 registers (out of the SBSA specification) */
19#define UARTIBRD 0x24U
20#define UARTFBRD 0x28U
21#define UARTLCR_H 0x2CU
22#define UARTCR 0x30U
23
24/* Flag reg bits */
25
26/* Transmit FIFO full */
27#define PL011_UARTFR_TXFF (U(1) << 5)
28
29/* Control reg bits */
30#define PL011_UARTCR_RXE (U(1) << 9) /* Receive enable */
31#define PL011_UARTCR_TXE (U(1) << 8) /* Transmit enable */
32#define PL011_UARTCR_UARTEN (U(1) << 0) /* UART Enable */
33
34/* FIFO Enabled / No Parity / 8 Data bit / One Stop Bit */
35#define PL011_LINE_CONTROL (PL011_UARTLCR_H_FEN | PL011_UARTLCR_H_WLEN_8)
36
37/* Line Control Register Bits */
38#define PL011_UARTLCR_H_WLEN_8 (U(3) << 5)
39#define PL011_UARTLCR_H_FEN (U(1) << 4) /* FIFOs Enable */
40
41static inline void pl011_wait(uintptr_t base)
Soby Mathewb4c6df42022-11-09 11:13:29 +000042{
43 /* Wait until there is room in the Tx FIFO */
Soby Mathew8218e082024-02-26 14:09:28 +000044 while ((read32((void *)(base + UARTFR))
Soby Mathewb4c6df42022-11-09 11:13:29 +000045 & PL011_UARTFR_TXFF) != 0U) {
46 /* Do nothing */
47 }
48}
49
Soby Mathew8218e082024-02-26 14:09:28 +000050static void writechar(uintptr_t base, int ch)
51{
52 pl011_wait(base);
53 write8((uint8_t)ch, (void *)(base + UARTDR));
54}
55
56/* Serial output - called from console driver */
57/* coverity[misra_c_2012_rule_8_7_violation:SUPPRESS] */
Shruti Gupta0a0d4ee2024-04-22 21:37:25 +010058static int pl011_putc(int c, const struct console *csl)
Soby Mathew8218e082024-02-26 14:09:28 +000059{
60 assert(csl != NULL);
61
62 if ((char)c == '\n') {
63 /* NOLINTNEXTLINE(google-readability-casting) */
64 writechar(csl->base, (int)'\r');
65 }
66 writechar(csl->base, c);
67
68 return c;
69}
70
71static struct console pl011_csl = {
72 .putc = pl011_putc,
73 .flush = NULL
74};
75
76/* Function that initializes PL011 for console output */
77int pl011_init(uintptr_t base_addr,
Soby Mathewb4c6df42022-11-09 11:13:29 +000078 unsigned int uart_clk,
79 unsigned int baud_rate)
80{
81 unsigned int div;
82
83 /* Check Base address, baud rate and UART clock for sanity */
Soby Mathew8218e082024-02-26 14:09:28 +000084 if ((base_addr == 0UL) || (uart_clk == 0U) ||
85 (baud_rate == 0U)) {
86 return -EINVAL;
Soby Mathewb4c6df42022-11-09 11:13:29 +000087 }
88
89 /* Disable UART before programming */
Soby Mathew8218e082024-02-26 14:09:28 +000090 write32(0U, (void *)(base_addr + UARTCR));
Soby Mathewb4c6df42022-11-09 11:13:29 +000091
AlexeiFedorov33656a32023-08-30 11:51:41 +010092 /* Program the baud rate */
93 div = (uart_clk * 4U) / baud_rate;
Soby Mathewb4c6df42022-11-09 11:13:29 +000094
95 /* IBRD = Divisor >> 6 */
Soby Mathew8218e082024-02-26 14:09:28 +000096 write32(div >> 6, (void *)((base_addr) + UARTIBRD));
Soby Mathewb4c6df42022-11-09 11:13:29 +000097
98 /* FBRD = Divisor & 0x3F */
Soby Mathew8218e082024-02-26 14:09:28 +000099 write32(div & 0x3fU, (void *)((base_addr) + UARTFBRD));
Soby Mathewb4c6df42022-11-09 11:13:29 +0000100
101 /* Enable FIFO and set word length, parity and number of stop bits */
Soby Mathew8218e082024-02-26 14:09:28 +0000102 write32(PL011_LINE_CONTROL, (void *)((base_addr) + UARTLCR_H));
Soby Mathewb4c6df42022-11-09 11:13:29 +0000103
104 /* Clear any pending errors */
Soby Mathew8218e082024-02-26 14:09:28 +0000105 write32(0U, (void *)((base_addr) + UARTECR));
Soby Mathewb4c6df42022-11-09 11:13:29 +0000106
107 /* Enable Tx, Rx, and UART overall */
108 write32(PL011_UARTCR_RXE | PL011_UARTCR_TXE | PL011_UARTCR_UARTEN,
Soby Mathew8218e082024-02-26 14:09:28 +0000109 (void *)((base_addr) + UARTCR));
Soby Mathewb4c6df42022-11-09 11:13:29 +0000110
Soby Mathew8218e082024-02-26 14:09:28 +0000111 pl011_csl.base = base_addr;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000112
Soby Mathew8218e082024-02-26 14:09:28 +0000113 return console_register(&pl011_csl);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000114}