1 /*
2 * Copyright (c) 2015-2021, Xilinx Inc.
3 * Written by Michal Simek.
4 *
5 * SPDX-License-Identifier: BSD-3-Clause
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
9 *
10 * Redistributions of source code must retain the above copyright notice, this
11 * list of conditions and the following disclaimer.
12 *
13 * Redistributions in binary form must reproduce the above copyright notice,
14 * this list of conditions and the following disclaimer in the documentation
15 * and/or other materials provided with the distribution.
16 *
17 * Neither the name of ARM nor the names of its contributors may be used
18 * to endorse or promote products derived from this software without specific
19 * prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 */
33
34 #include <errno.h>
35 #include <stddef.h>
36 #include <arch_helpers.h>
37 #include <drivers/arm/dcc.h>
38 #include <drivers/console.h>
39 #include <drivers/delay_timer.h>
40 #include <lib/mmio.h>
41
42 /* DCC Status Bits */
43 #define DCC_STATUS_RX BIT(30)
44 #define DCC_STATUS_TX BIT(29)
45 #define TIMEOUT_COUNT_US U(0x10624)
46
47 struct dcc_console {
48 struct console console;
49 };
50
__dcc_getstatus(void)51 static inline uint32_t __dcc_getstatus(void)
52 {
53 return read_mdccsr_el0();
54 }
55
56 #if ENABLE_CONSOLE_GETC
__dcc_getchar(void)57 static inline char __dcc_getchar(void)
58 {
59 char c;
60
61 c = read_dbgdtrrx_el0();
62
63 return c;
64 }
65 #endif
66
__dcc_putchar(char c)67 static inline void __dcc_putchar(char c)
68 {
69 /*
70 * The typecast is to make absolutely certain that 'c' is
71 * zero-extended.
72 */
73 write_dbgdtrtx_el0((unsigned char)c);
74 }
75
dcc_status_timeout(uint32_t mask)76 static int32_t dcc_status_timeout(uint32_t mask)
77 {
78 const unsigned int timeout_count = TIMEOUT_COUNT_US;
79 uint64_t timeout;
80 unsigned int status;
81
82 timeout = timeout_init_us(timeout_count);
83
84 do {
85 status = (__dcc_getstatus() & mask);
86 if (timeout_elapsed(timeout)) {
87 return -ETIMEDOUT;
88 }
89 } while ((status != 0U));
90
91 return 0;
92 }
93
dcc_console_putc(int32_t ch,struct console * console)94 static int32_t dcc_console_putc(int32_t ch, struct console *console)
95 {
96 unsigned int status;
97
98 status = dcc_status_timeout(DCC_STATUS_TX);
99 if (status != 0U) {
100 return status;
101 }
102 __dcc_putchar(ch);
103
104 return ch;
105 }
106
107 #if ENABLE_CONSOLE_GETC
dcc_console_getc(struct console * console)108 static int32_t dcc_console_getc(struct console *console)
109 {
110 unsigned int status;
111
112 status = dcc_status_timeout(DCC_STATUS_RX);
113 if (status != 0U) {
114 return status;
115 }
116
117 return __dcc_getchar();
118 }
119 #endif
120
121 /**
122 * dcc_console_flush() - Function to force a write of all buffered data
123 * that hasn't been output.
124 * @console Console struct
125 *
126 */
dcc_console_flush(struct console * console)127 static void dcc_console_flush(struct console *console)
128 {
129 unsigned int status;
130
131 status = dcc_status_timeout(DCC_STATUS_TX);
132 if (status != 0U) {
133 return;
134 }
135 }
136
137 static struct dcc_console dcc_console = {
138 .console = {
139 .flags = CONSOLE_FLAG_BOOT |
140 CONSOLE_FLAG_RUNTIME |
141 CONSOLE_FLAG_CRASH,
142 .putc = dcc_console_putc,
143 #if ENABLE_CONSOLE_GETC
144 .getc = dcc_console_getc,
145 #endif
146 .flush = dcc_console_flush,
147 },
148 };
149
console_dcc_register(void)150 int console_dcc_register(void)
151 {
152 return console_register(&dcc_console.console);
153 }
154
console_dcc_unregister(void)155 void console_dcc_unregister(void)
156 {
157 dcc_console_flush(&dcc_console.console);
158 (void)console_unregister(&dcc_console.console);
159 }
160