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