1 // SPDX-License-Identifier: BSD-2-Clause 2 /* 3 * Copyright (c) 2024-2025, NVIDIA CORPORATION 4 */ 5 6 #include <compiler.h> 7 #include <console.h> 8 #include <ffa.h> 9 #include <string.h> 10 #include <drivers/serial.h> 11 #include <drivers/ffa_console.h> 12 #include <kernel/dt_driver.h> 13 #include <kernel/thread_arch.h> 14 15 struct ffa_console_data { 16 struct serial_chip chip; 17 char buf[FFA_CONSOLE_LOG_64_MAX_MSG_LEN]; 18 size_t pos; 19 }; 20 21 static struct ffa_console_data ffa_console __nex_bss; 22 23 static void copy_buf_to_args(struct thread_smc_args *args, 24 const char *buf, size_t len, 25 size_t reg_size) 26 { 27 size_t i = 0; 28 size_t j = 0; 29 30 args->a1 = len; 31 32 for (i = 0, j = 0; j < len; i++, j += reg_size) 33 memcpy(&args->a2 + i, buf + j, MIN(len - j, reg_size)); 34 } 35 36 static void ffa_console_32_flush(struct serial_chip *chip) 37 { 38 struct ffa_console_data *pd = 39 container_of(chip, struct ffa_console_data, chip); 40 struct thread_smc_args args = { 41 .a0 = FFA_CONSOLE_LOG_32 42 }; 43 44 copy_buf_to_args(&args, pd->buf, pd->pos, sizeof(uint32_t)); 45 thread_smccc(&args); 46 pd->pos = 0; 47 } 48 49 static void ffa_console_32_putc(struct serial_chip *chip, int ch) 50 { 51 struct ffa_console_data *pd = 52 container_of(chip, struct ffa_console_data, chip); 53 54 pd->buf[pd->pos++] = ch; 55 56 if (pd->pos == FFA_CONSOLE_LOG_32_MAX_MSG_LEN) 57 ffa_console_32_flush(chip); 58 } 59 60 static const struct serial_ops ffa_console_32_ops = { 61 .putc = ffa_console_32_putc, 62 .flush = ffa_console_32_flush, 63 }; 64 65 static void ffa_console_64_flush(struct serial_chip *chip) 66 { 67 struct ffa_console_data *pd = 68 container_of(chip, struct ffa_console_data, chip); 69 struct thread_smc_args args = { 70 .a0 = FFA_CONSOLE_LOG_64 71 }; 72 73 copy_buf_to_args(&args, pd->buf, pd->pos, sizeof(uint64_t)); 74 thread_smccc(&args); 75 pd->pos = 0; 76 } 77 78 static void ffa_console_64_putc(struct serial_chip *chip, int ch) 79 { 80 struct ffa_console_data *pd = 81 container_of(chip, struct ffa_console_data, chip); 82 83 pd->buf[pd->pos++] = ch; 84 85 if (pd->pos == FFA_CONSOLE_LOG_64_V1_1_MAX_MSG_LEN) 86 ffa_console_64_flush(chip); 87 } 88 89 static const struct serial_ops ffa_console_64_ops = { 90 .putc = ffa_console_64_putc, 91 .flush = ffa_console_64_flush, 92 }; 93 94 static bool ffa_feature_console_64bit(void) 95 { 96 struct thread_smc_args args = { 97 .a0 = FFA_FEATURES, 98 .a1 = FFA_CONSOLE_LOG_64 99 }; 100 101 thread_smccc(&args); 102 103 return args.a0 == FFA_SUCCESS_64 || args.a0 == FFA_SUCCESS_32; 104 } 105 106 void ffa_console_init(void) 107 { 108 if (ffa_feature_console_64bit()) 109 ffa_console.chip.ops = &ffa_console_64_ops; 110 else 111 ffa_console.chip.ops = &ffa_console_32_ops; 112 113 ffa_console.pos = 0; 114 115 register_serial_console(&ffa_console.chip); 116 } 117 118 #ifdef CFG_DT 119 120 static struct serial_chip *ffa_console_dev_alloc(void) 121 { 122 return &ffa_console.chip; 123 } 124 125 static int ffa_console_dev_init(struct serial_chip *chip __unused, 126 const void *fdt __unused, int offs __unused, 127 const char *params __unused) 128 { 129 return 0; 130 } 131 132 static void ffa_console_dev_free(struct serial_chip *chip __unused) 133 { 134 } 135 136 static const struct serial_driver ffa_console_driver = { 137 .dev_alloc = ffa_console_dev_alloc, 138 .dev_init = ffa_console_dev_init, 139 .dev_free = ffa_console_dev_free, 140 }; 141 142 static const struct dt_device_match ffa_console_match_table[] = { 143 { .compatible = "arm,ffa-console" }, 144 { } 145 }; 146 147 DEFINE_DT_DRIVER(ffa_console_dt_driver) = { 148 .name = "ffa-console", 149 .type = DT_DRIVER_UART, 150 .match_table = ffa_console_match_table, 151 .driver = &ffa_console_driver, 152 }; 153 154 #endif /* CFG_DT */ 155