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
copy_buf_to_args(struct thread_smc_args * args,const char * buf,size_t len,size_t reg_size)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
ffa_console_32_flush(struct serial_chip * chip)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
ffa_console_32_putc(struct serial_chip * chip,int ch)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
ffa_console_64_flush(struct serial_chip * chip)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
ffa_console_64_putc(struct serial_chip * chip,int ch)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
ffa_feature_console_64bit(void)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
ffa_console_init(void)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
ffa_console_dev_alloc(void)120 static struct serial_chip *ffa_console_dev_alloc(void)
121 {
122 return &ffa_console.chip;
123 }
124
ffa_console_dev_init(struct serial_chip * chip __unused,const void * fdt __unused,int offs __unused,const char * params __unused)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
ffa_console_dev_free(struct serial_chip * chip __unused)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