xref: /optee_os/core/drivers/ffa_console.c (revision 2186f9e04ecbc7f0026fb49065e951ffda87be98)
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