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