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
__dcc_getchar(void)56 static inline char __dcc_getchar(void)
57 {
58 char c;
59
60 c = read_dbgdtrrx_el0();
61
62 return c;
63 }
64
__dcc_putchar(char c)65 static inline void __dcc_putchar(char c)
66 {
67 /*
68 * The typecast is to make absolutely certain that 'c' is
69 * zero-extended.
70 */
71 write_dbgdtrtx_el0((unsigned char)c);
72 }
73
dcc_status_timeout(uint32_t mask)74 static int32_t dcc_status_timeout(uint32_t mask)
75 {
76 const unsigned int timeout_count = TIMEOUT_COUNT_US;
77 uint64_t timeout;
78 unsigned int status;
79
80 timeout = timeout_init_us(timeout_count);
81
82 do {
83 status = (__dcc_getstatus() & mask);
84 if (timeout_elapsed(timeout)) {
85 return -ETIMEDOUT;
86 }
87 } while ((status != 0U));
88
89 return 0;
90 }
91
dcc_console_putc(int32_t ch,struct console * console)92 static int32_t dcc_console_putc(int32_t ch, struct console *console)
93 {
94 unsigned int status;
95
96 status = dcc_status_timeout(DCC_STATUS_TX);
97 if (status != 0U) {
98 return status;
99 }
100 __dcc_putchar(ch);
101
102 return ch;
103 }
104
dcc_console_getc(struct console * console)105 static int32_t dcc_console_getc(struct console *console)
106 {
107 unsigned int status;
108
109 status = dcc_status_timeout(DCC_STATUS_RX);
110 if (status != 0U) {
111 return status;
112 }
113
114 return __dcc_getchar();
115 }
116
dcc_console_init(unsigned long base_addr,uint32_t uart_clk,uint32_t baud_rate)117 int32_t dcc_console_init(unsigned long base_addr, uint32_t uart_clk,
118 uint32_t baud_rate)
119 {
120 return 0; /* No init needed */
121 }
122
123 /**
124 * dcc_console_flush() - Function to force a write of all buffered data
125 * that hasn't been output.
126 * @console Console struct
127 *
128 */
dcc_console_flush(struct console * console)129 static void dcc_console_flush(struct console *console)
130 {
131 unsigned int status;
132
133 status = dcc_status_timeout(DCC_STATUS_TX);
134 if (status != 0U) {
135 return;
136 }
137 }
138
139 static struct dcc_console dcc_console = {
140 .console = {
141 .flags = CONSOLE_FLAG_BOOT |
142 CONSOLE_FLAG_RUNTIME,
143 .putc = dcc_console_putc,
144 .getc = dcc_console_getc,
145 .flush = dcc_console_flush,
146 },
147 };
148
console_dcc_register(void)149 int console_dcc_register(void)
150 {
151 return console_register(&dcc_console.console);
152 }
153