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 u_register_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 u_register_t 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 int32_t status; 98 99 (void)console; 100 101 status = dcc_status_timeout(DCC_STATUS_TX); 102 if (status != 0U) { 103 return status; 104 } 105 __dcc_putchar(ch); 106 107 return ch; 108 } 109 110 #if ENABLE_CONSOLE_GETC 111 static int32_t dcc_console_getc(console_t *console) 112 { 113 int32_t status; 114 115 status = dcc_status_timeout(DCC_STATUS_RX); 116 if (status != 0U) { 117 return status; 118 } 119 120 return __dcc_getchar(); 121 } 122 #endif 123 124 /** 125 * dcc_console_flush() - Function to force a write of all buffered data 126 * that hasn't been output. 127 * @console Console struct 128 * 129 */ 130 static void dcc_console_flush(console_t *console) 131 { 132 int32_t status; 133 134 (void)console; 135 136 status = dcc_status_timeout(DCC_STATUS_TX); 137 if (status != 0U) { 138 return; 139 } 140 } 141 142 static struct dcc_console dcc_console = { 143 .console = { 144 .flags = CONSOLE_FLAG_BOOT | 145 CONSOLE_FLAG_RUNTIME | 146 CONSOLE_FLAG_CRASH, 147 .putc = dcc_console_putc, 148 #if ENABLE_CONSOLE_GETC 149 .getc = dcc_console_getc, 150 #endif 151 .flush = dcc_console_flush, 152 }, 153 }; 154 155 int console_dcc_register(console_t *console) 156 { 157 memcpy(console, &dcc_console.console, sizeof(console_t)); 158 return console_register(console); 159 } 160 161 void console_dcc_unregister(console_t *console) 162 { 163 dcc_console_flush(console); 164 (void)console_unregister(console); 165 } 166