1 /*
2 * Copyright 2018 The Hafnium Authors.
3 *
4 * Use of this source code is governed by a BSD-style
5 * license that can be found in the LICENSE file or at
6 * https://opensource.org/licenses/BSD-3-Clause.
7 */
8
9 #include "hf/io.h"
10 #include "hf/mm.h"
11 #include "hf/mpool.h"
12 #include "hf/plat/console.h"
13
14 /* UART Data Register. */
15 #define UART_DR IO32_C(PL011_BASE + 0x0)
16
17 /* Receive Status or Error Clear Register. */
18 #define UART_RSR_ECR IO32_C(PL011_BASE + 0x4)
19
20 /* UART Flag Register. */
21 #define UART_FR IO32_C(PL011_BASE + 0x018)
22
23 /* UART IBRD (Integer Baudrate) Register. */
24 #define UART_IBRD IO32_C(PL011_BASE + 0x024)
25
26 /* UART FBRD (Fractional Baudrate) Register. */
27 #define UART_FBRD IO32_C(PL011_BASE + 0x028)
28
29 /* UART Line Control Register. */
30 #define UART_LCR_H IO32_C(PL011_BASE + 0x02C)
31
32 /* UART Control Register. */
33 #define UART_CR IO32_C(PL011_BASE + 0x030)
34
35 /* UART Interrupt Mask Set/Clear Register. */
36 #define UART_IMSC IO32_C(PL011_BASE + 0x038)
37
38 /* UART Flag Register bit: transmit fifo is full. */
39 #define UART_FR_TXFF (1 << 5)
40
41 /* UART Flag Register bit: receive fifo is empty */
42 #define UART_FR_RXFE (1 << 4)
43
44 /* UART Flag Register bit: UART is busy. */
45 #define UART_FR_BUSY (1 << 3)
46
47 /* UART transmit/receive line register bits. */
48 #define UART_LCRH_WLEN_8 (3 << 5)
49
50 /* UART control register bits. */
51 #define UART_CR_RXE (1 << 9)
52 #define UART_CR_TXE (1 << 8)
53 #define UART_CR_UARTEN (1 << 0)
54
55 #define UART_IMSC_RTIM (1 << 6)
56 #define UART_IMSC_RXIM (1 << 4)
57
plat_console_init(void)58 void plat_console_init(void)
59 {
60 /*
61 * If pl011 clock frequency is 0 or not specified, then don't set
62 * baudrate as it can't be calculated without clock frequency.
63 * Assumption is that the default rate is fine for the system.
64 */
65 #if PL011_CLOCK != 0
66
67 unsigned int quotient = PL011_CLOCK * 4 / PL011_BAUDRATE;
68
69 /* Disable everything */
70 io_write32(UART_CR, 0);
71 /* Clear all errors */
72 io_write32(UART_RSR_ECR, 0);
73
74 /* Set baud rate */
75 io_write32(UART_FBRD, quotient & 0x3f);
76 io_write32(UART_IBRD, quotient >> 6);
77
78 /* Configure TX to 8 bits, 1 stop bit, no parity, fifo disabled. */
79 io_write32(UART_LCR_H, UART_LCRH_WLEN_8);
80
81 /* Enable interrupts for receive and receive timeout */
82 io_write32(UART_IMSC, UART_IMSC_RXIM | UART_IMSC_RTIM);
83
84 /* Enable UART and RX/TX */
85 io_write32(UART_CR, UART_CR_UARTEN | UART_CR_TXE | UART_CR_RXE);
86 #endif
87 }
88
plat_console_mm_init(struct mm_stage1_locked stage1_locked,struct mpool * ppool)89 void plat_console_mm_init(struct mm_stage1_locked stage1_locked,
90 struct mpool *ppool)
91 {
92 /* Map page for UART. */
93 mm_identity_map(stage1_locked, pa_init(PL011_BASE),
94 pa_add(pa_init(PL011_BASE), PAGE_SIZE),
95 MM_MODE_R | MM_MODE_W | MM_MODE_D, ppool);
96 }
97
98 /*
99 * Since the recursion is only one level disable the clang tidy recursion check
100 */
101 // NOLINTNEXTLINE(misc-no-recursion)
plat_console_putchar(char c)102 void plat_console_putchar(char c)
103 {
104 /* Print a carriage-return as well. */
105 if (c == '\n') {
106 plat_console_putchar('\r');
107 }
108
109 /* Wait until there is room in the tx buffer. */
110 while (io_read32(UART_FR) & UART_FR_TXFF) {
111 /* do nothing */
112 }
113
114 /* Write the character out, force memory access ordering. */
115 memory_ordering_barrier();
116 io_write32(UART_DR, c);
117 memory_ordering_barrier();
118
119 /* Wait until the UART is no longer busy. */
120 while (io_read32_mb(UART_FR) & UART_FR_BUSY) {
121 /* do nothing */
122 }
123 }
124
plat_console_getchar(void)125 char plat_console_getchar(void)
126 {
127 /* Wait until the UART is no longer busy and has data to read. */
128 while (io_read32_mb(UART_FR) & UART_FR_BUSY ||
129 io_read32_mb(UART_FR) & UART_FR_RXFE) {
130 /* do nothing */
131 }
132
133 return (char)(io_read32(UART_DR) & 0xFF);
134 }
135