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 51 static inline uint32_t __dcc_getstatus(void) 52 { 53 return read_mdccsr_el0(); 54 } 55 56 #if ENABLE_CONSOLE_GETC 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 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 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 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 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 */ 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 150 int console_dcc_register(void) 151 { 152 return console_register(&dcc_console.console); 153 } 154 155 void console_dcc_unregister(void) 156 { 157 dcc_console_flush(&dcc_console.console); 158 (void)console_unregister(&dcc_console.console); 159 } 160