blob: 83fc825185e9bc2bcd00c058fcee24513899f91b [file] [log] [blame]
Gabor Ambrus54a10082023-08-14 21:56:06 +02001/*
2 * Copyright (c) 2023, ARM Limited and Contributors. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 * Based on the driver found in trustedfirmware-a written in assembly (pl011_console.S)
7 */
8
9#include <stdint.h>
10
11#include "../../../common/mmio.h"
12#include "pl011.h"
13
14#define DEFAULT_CLK_IN_HZ 24000000
15#define DEFAULT_BAUDRATE 115200
16
17void uflush(uintptr_t addr)
18{
19 /* Loop until the transmit FIFO is empty */
20 while (mmio_read_32(addr + UARTFR) & PL011_UARTFR_BUSY) {
21 };
22}
23
24void uputc(uint8_t ch, uintptr_t addr)
25{
26 /* Prepend '\r' to '\n' */
27 if (ch == '\n') {
28 /* Check if the transmit FIFO is full */
29 while (mmio_read_32(addr + UARTFR) & PL011_UARTFR_TXFF) {
30 };
31 mmio_write_32(addr + UARTDR, '\r');
32 }
33
34 /* Print the actual character */
35 while (mmio_read_32(addr + UARTFR) & PL011_UARTFR_TXFF) {
36 };
37 mmio_write_32(addr + UARTDR, ch);
38}
39
40void uart_deinit(uintptr_t addr)
41{
42 /* Disable uart before programming */
43 mmio_write_32(addr + UARTCR, 0);
44
45 /* Wait for the end of transmission */
46 uflush(addr);
47
48 /* Flush the transmit FIFO by setting the FEN bit to 0 in the Line Control Register */
49 mmio_write_32(addr + UARTLCR_H, 0);
50}
51
52int uart_init(uintptr_t addr)
53{
54 if (!addr)
55 return -1;
56
57 uart_deinit(addr);
58
59 /* Program the baudrate */
60 uint32_t divisor = (DEFAULT_CLK_IN_HZ * 4) / DEFAULT_BAUDRATE;
61
62 mmio_write_32(addr + UARTIBRD, divisor >> 6);
63 mmio_write_32(addr + UARTFBRD, divisor & 0x3f);
64
65 /* FIFO Enabled / No Parity / 8 Data bit / One Stop Bit */
66 mmio_write_32(addr + UARTLCR_H, PL011_LINE_CONTROL);
67
68 /* Clear any pending errors */
69 mmio_write_32(addr + UARTECR, 0);
70
71 /* Enable tx, rx, and uart overall */
72 mmio_write_32(addr + UARTCR, PL011_UARTCR_RXE | PL011_UARTCR_TXE | PL011_UARTCR_UARTEN);
73
74 return 0;
75}
76