xref: /optee_os/core/drivers/ffa_console.c (revision 2186f9e04ecbc7f0026fb49065e951ffda87be98)
1d4a87690SSungbae Yoo // SPDX-License-Identifier: BSD-2-Clause
2d4a87690SSungbae Yoo /*
35836737aSSungbae Yoo  * Copyright (c) 2024-2025, NVIDIA CORPORATION
4d4a87690SSungbae Yoo  */
5d4a87690SSungbae Yoo 
6d4a87690SSungbae Yoo #include <compiler.h>
7d4a87690SSungbae Yoo #include <console.h>
8*2186f9e0SSungbae Yoo #include <ffa.h>
9*2186f9e0SSungbae Yoo #include <string.h>
10d4a87690SSungbae Yoo #include <drivers/serial.h>
11*2186f9e0SSungbae Yoo #include <drivers/ffa_console.h>
125836737aSSungbae Yoo #include <kernel/dt_driver.h>
13d4a87690SSungbae Yoo #include <kernel/thread_arch.h>
14d4a87690SSungbae Yoo 
15*2186f9e0SSungbae Yoo struct ffa_console_data {
16*2186f9e0SSungbae Yoo 	struct serial_chip chip;
17*2186f9e0SSungbae Yoo 	char buf[FFA_CONSOLE_LOG_64_MAX_MSG_LEN];
18*2186f9e0SSungbae Yoo 	size_t pos;
19*2186f9e0SSungbae Yoo };
20d4a87690SSungbae Yoo 
21*2186f9e0SSungbae Yoo static struct ffa_console_data ffa_console __nex_bss;
22*2186f9e0SSungbae Yoo 
copy_buf_to_args(struct thread_smc_args * args,const char * buf,size_t len,size_t reg_size)23*2186f9e0SSungbae Yoo static void copy_buf_to_args(struct thread_smc_args *args,
24*2186f9e0SSungbae Yoo 			     const char *buf, size_t len,
25*2186f9e0SSungbae Yoo 			     size_t reg_size)
26d4a87690SSungbae Yoo {
27*2186f9e0SSungbae Yoo 	size_t i = 0;
28*2186f9e0SSungbae Yoo 	size_t j = 0;
29*2186f9e0SSungbae Yoo 
30*2186f9e0SSungbae Yoo 	args->a1 = len;
31*2186f9e0SSungbae Yoo 
32*2186f9e0SSungbae Yoo 	for (i = 0, j = 0; j < len; i++, j += reg_size)
33*2186f9e0SSungbae Yoo 		memcpy(&args->a2 + i, buf + j, MIN(len - j, reg_size));
34d4a87690SSungbae Yoo }
35d4a87690SSungbae Yoo 
ffa_console_32_flush(struct serial_chip * chip)36*2186f9e0SSungbae Yoo static void ffa_console_32_flush(struct serial_chip *chip)
37*2186f9e0SSungbae Yoo {
38*2186f9e0SSungbae Yoo 	struct ffa_console_data *pd =
39*2186f9e0SSungbae Yoo 		container_of(chip, struct ffa_console_data, chip);
40*2186f9e0SSungbae Yoo 	struct thread_smc_args args = {
41*2186f9e0SSungbae Yoo 		.a0 = FFA_CONSOLE_LOG_32
42d4a87690SSungbae Yoo 	};
43d4a87690SSungbae Yoo 
44*2186f9e0SSungbae Yoo 	copy_buf_to_args(&args, pd->buf, pd->pos, sizeof(uint32_t));
45*2186f9e0SSungbae Yoo 	thread_smccc(&args);
46*2186f9e0SSungbae Yoo 	pd->pos = 0;
47*2186f9e0SSungbae Yoo }
48*2186f9e0SSungbae Yoo 
ffa_console_32_putc(struct serial_chip * chip,int ch)49*2186f9e0SSungbae Yoo static void ffa_console_32_putc(struct serial_chip *chip, int ch)
50*2186f9e0SSungbae Yoo {
51*2186f9e0SSungbae Yoo 	struct ffa_console_data *pd =
52*2186f9e0SSungbae Yoo 		container_of(chip, struct ffa_console_data, chip);
53*2186f9e0SSungbae Yoo 
54*2186f9e0SSungbae Yoo 	pd->buf[pd->pos++] = ch;
55*2186f9e0SSungbae Yoo 
56*2186f9e0SSungbae Yoo 	if (pd->pos == FFA_CONSOLE_LOG_32_MAX_MSG_LEN)
57*2186f9e0SSungbae Yoo 		ffa_console_32_flush(chip);
58*2186f9e0SSungbae Yoo }
59*2186f9e0SSungbae Yoo 
60*2186f9e0SSungbae Yoo static const struct serial_ops ffa_console_32_ops = {
61*2186f9e0SSungbae Yoo 	.putc = ffa_console_32_putc,
62*2186f9e0SSungbae Yoo 	.flush = ffa_console_32_flush,
63d4a87690SSungbae Yoo };
64d4a87690SSungbae Yoo 
ffa_console_64_flush(struct serial_chip * chip)65*2186f9e0SSungbae Yoo static void ffa_console_64_flush(struct serial_chip *chip)
66*2186f9e0SSungbae Yoo {
67*2186f9e0SSungbae Yoo 	struct ffa_console_data *pd =
68*2186f9e0SSungbae Yoo 		container_of(chip, struct ffa_console_data, chip);
69*2186f9e0SSungbae Yoo 	struct thread_smc_args args = {
70*2186f9e0SSungbae Yoo 		.a0 = FFA_CONSOLE_LOG_64
71*2186f9e0SSungbae Yoo 	};
72*2186f9e0SSungbae Yoo 
73*2186f9e0SSungbae Yoo 	copy_buf_to_args(&args, pd->buf, pd->pos, sizeof(uint64_t));
74*2186f9e0SSungbae Yoo 	thread_smccc(&args);
75*2186f9e0SSungbae Yoo 	pd->pos = 0;
76*2186f9e0SSungbae Yoo }
77*2186f9e0SSungbae Yoo 
ffa_console_64_putc(struct serial_chip * chip,int ch)78*2186f9e0SSungbae Yoo static void ffa_console_64_putc(struct serial_chip *chip, int ch)
79*2186f9e0SSungbae Yoo {
80*2186f9e0SSungbae Yoo 	struct ffa_console_data *pd =
81*2186f9e0SSungbae Yoo 		container_of(chip, struct ffa_console_data, chip);
82*2186f9e0SSungbae Yoo 
83*2186f9e0SSungbae Yoo 	pd->buf[pd->pos++] = ch;
84*2186f9e0SSungbae Yoo 
85*2186f9e0SSungbae Yoo 	if (pd->pos == FFA_CONSOLE_LOG_64_V1_1_MAX_MSG_LEN)
86*2186f9e0SSungbae Yoo 		ffa_console_64_flush(chip);
87*2186f9e0SSungbae Yoo }
88*2186f9e0SSungbae Yoo 
89*2186f9e0SSungbae Yoo static const struct serial_ops ffa_console_64_ops = {
90*2186f9e0SSungbae Yoo 	.putc = ffa_console_64_putc,
91*2186f9e0SSungbae Yoo 	.flush = ffa_console_64_flush,
92*2186f9e0SSungbae Yoo };
93*2186f9e0SSungbae Yoo 
ffa_feature_console_64bit(void)94*2186f9e0SSungbae Yoo static bool ffa_feature_console_64bit(void)
95*2186f9e0SSungbae Yoo {
96*2186f9e0SSungbae Yoo 	struct thread_smc_args args = {
97*2186f9e0SSungbae Yoo 		.a0 = FFA_FEATURES,
98*2186f9e0SSungbae Yoo 		.a1 = FFA_CONSOLE_LOG_64
99*2186f9e0SSungbae Yoo 	};
100*2186f9e0SSungbae Yoo 
101*2186f9e0SSungbae Yoo 	thread_smccc(&args);
102*2186f9e0SSungbae Yoo 
103*2186f9e0SSungbae Yoo 	return args.a0 == FFA_SUCCESS_64 || args.a0 == FFA_SUCCESS_32;
104*2186f9e0SSungbae Yoo }
105*2186f9e0SSungbae Yoo 
ffa_console_init(void)106d4a87690SSungbae Yoo void ffa_console_init(void)
107d4a87690SSungbae Yoo {
108*2186f9e0SSungbae Yoo 	if (ffa_feature_console_64bit())
109*2186f9e0SSungbae Yoo 		ffa_console.chip.ops = &ffa_console_64_ops;
110*2186f9e0SSungbae Yoo 	else
111*2186f9e0SSungbae Yoo 		ffa_console.chip.ops = &ffa_console_32_ops;
112*2186f9e0SSungbae Yoo 
113*2186f9e0SSungbae Yoo 	ffa_console.pos = 0;
114*2186f9e0SSungbae Yoo 
115*2186f9e0SSungbae Yoo 	register_serial_console(&ffa_console.chip);
116d4a87690SSungbae Yoo }
1175836737aSSungbae Yoo 
1185836737aSSungbae Yoo #ifdef CFG_DT
1195836737aSSungbae Yoo 
ffa_console_dev_alloc(void)1205836737aSSungbae Yoo static struct serial_chip *ffa_console_dev_alloc(void)
1215836737aSSungbae Yoo {
122*2186f9e0SSungbae Yoo 	return &ffa_console.chip;
1235836737aSSungbae Yoo }
1245836737aSSungbae Yoo 
ffa_console_dev_init(struct serial_chip * chip __unused,const void * fdt __unused,int offs __unused,const char * params __unused)1255836737aSSungbae Yoo static int ffa_console_dev_init(struct serial_chip *chip __unused,
1265836737aSSungbae Yoo 				const void *fdt __unused, int offs __unused,
1275836737aSSungbae Yoo 				const char *params __unused)
1285836737aSSungbae Yoo {
1295836737aSSungbae Yoo 	return 0;
1305836737aSSungbae Yoo }
1315836737aSSungbae Yoo 
ffa_console_dev_free(struct serial_chip * chip __unused)1325836737aSSungbae Yoo static void ffa_console_dev_free(struct serial_chip *chip __unused)
1335836737aSSungbae Yoo {
1345836737aSSungbae Yoo }
1355836737aSSungbae Yoo 
1365836737aSSungbae Yoo static const struct serial_driver ffa_console_driver = {
1375836737aSSungbae Yoo 	.dev_alloc = ffa_console_dev_alloc,
1385836737aSSungbae Yoo 	.dev_init = ffa_console_dev_init,
1395836737aSSungbae Yoo 	.dev_free = ffa_console_dev_free,
1405836737aSSungbae Yoo };
1415836737aSSungbae Yoo 
1425836737aSSungbae Yoo static const struct dt_device_match ffa_console_match_table[] = {
1435836737aSSungbae Yoo 	{ .compatible = "arm,ffa-console" },
1445836737aSSungbae Yoo 	{ }
1455836737aSSungbae Yoo };
1465836737aSSungbae Yoo 
1475836737aSSungbae Yoo DEFINE_DT_DRIVER(ffa_console_dt_driver) = {
1485836737aSSungbae Yoo 	.name = "ffa-console",
1495836737aSSungbae Yoo 	.type = DT_DRIVER_UART,
1505836737aSSungbae Yoo 	.match_table = ffa_console_match_table,
1515836737aSSungbae Yoo 	.driver = &ffa_console_driver,
1525836737aSSungbae Yoo };
1535836737aSSungbae Yoo 
1545836737aSSungbae Yoo #endif /* CFG_DT */
155