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