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