1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright 2022-2023 Arm Limited and/or its affiliates <open-source-office@arm.com>
4 *
5 * Authors:
6 *   Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
7 */
8#include <common.h>
9#include <arm_ffa.h>
10#include <command.h>
11#include <dm.h>
12#include <mapmem.h>
13#include <stdlib.h>
14#include <asm/io.h>
15
16/* Select the right physical address formatting according to the platform */
17#ifdef CONFIG_PHYS_64BIT
18#define PhysAddrLength "ll"
19#else
20#define PhysAddrLength ""
21#endif
22#define PHYS_ADDR_LN "%" PhysAddrLength "x"
23
24/**
25 * ffa_get_dev() - Return the FF-A device
26 * @devp:	pointer to the FF-A device
27 *
28 * Search for the FF-A device.
29 *
30 * Return:
31 * 0 on success. Otherwise, failure
32 */
33static int ffa_get_dev(struct udevice **devp)
34{
35	int ret;
36
37	ret = uclass_first_device_err(UCLASS_FFA, devp);
38	if (ret) {
39		log_err("Cannot find FF-A bus device\n");
40		return ret;
41	}
42
43	return 0;
44}
45
46/**
47 * do_ffa_getpart() - implementation of the getpart subcommand
48 * @cmdtp:		Command Table
49 * @flag:		flags
50 * @argc:		number of arguments
51 * @argv:		arguments
52 *
53 * Query a secure partition information. The secure partition UUID is provided
54 * as an argument. The function uses the arm_ffa driver
55 * partition_info_get operation which implements FFA_PARTITION_INFO_GET
56 * ABI to retrieve the data. The input UUID string is expected to be in big
57 * endian format.
58 *
59 * Return:
60 *
61 * CMD_RET_SUCCESS: on success, otherwise failure
62 */
63static int do_ffa_getpart(struct cmd_tbl *cmdtp, int flag, int argc,
64			  char *const argv[])
65{
66	u32 count = 0;
67	int ret;
68	struct ffa_partition_desc *descs;
69	u32 i;
70	struct udevice *dev;
71
72	if (argc != 2) {
73		log_err("Missing argument\n");
74		return CMD_RET_USAGE;
75	}
76
77	ret = ffa_get_dev(&dev);
78	if (ret)
79		return CMD_RET_FAILURE;
80
81	/* Ask the driver to fill the buffer with the SPs info */
82
83	ret = ffa_partition_info_get(dev, argv[1], &count, &descs);
84	if (ret) {
85		log_err("Failure in querying partition(s) info (error code: %d)\n", ret);
86		return CMD_RET_FAILURE;
87	}
88
89	/* SPs found , show the partition information */
90	for (i = 0; i < count ; i++) {
91		log_info("Partition: id = %x , exec_ctxt %x , properties %x\n",
92			 descs[i].info.id,
93			 descs[i].info.exec_ctxt,
94			 descs[i].info.properties);
95	}
96
97	return CMD_RET_SUCCESS;
98}
99
100/**
101 * do_ffa_ping() - implementation of the ping subcommand
102 * @cmdtp:		Command Table
103 * @flag:		flags
104 * @argc:		number of arguments
105 * @argv:		arguments
106 *
107 * Send data to a secure partition. The secure partition UUID is provided
108 * as an argument. Use the arm_ffa driver sync_send_receive operation
109 * which implements FFA_MSG_SEND_DIRECT_{REQ,RESP} ABIs to send/receive data.
110 *
111 * Return:
112 *
113 * CMD_RET_SUCCESS: on success, otherwise failure
114 */
115static int do_ffa_ping(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
116{
117	struct ffa_send_direct_data msg = {
118			.data0 = 0xaaaaaaaa,
119			.data1 = 0xbbbbbbbb,
120			.data2 = 0xcccccccc,
121			.data3 = 0xdddddddd,
122			.data4 = 0xeeeeeeee,
123	};
124	u16 part_id;
125	int ret;
126	struct udevice *dev;
127
128	if (argc != 2) {
129		log_err("Missing argument\n");
130		return CMD_RET_USAGE;
131	}
132
133	part_id = strtoul(argv[1], NULL, 16);
134	if (!part_id) {
135		log_err("Partition ID can not be 0\n");
136		return CMD_RET_USAGE;
137	}
138
139	ret = ffa_get_dev(&dev);
140	if (ret)
141		return CMD_RET_FAILURE;
142
143	ret = ffa_sync_send_receive(dev, part_id, &msg, 1);
144	if (!ret) {
145		u8 cnt;
146
147		log_info("SP response:\n[LSB]\n");
148		for (cnt = 0;
149		     cnt < sizeof(struct ffa_send_direct_data) / sizeof(u64);
150		     cnt++)
151			log_info("%llx\n", ((u64 *)&msg)[cnt]);
152		return CMD_RET_SUCCESS;
153	}
154
155	log_err("Sending direct request error (%d)\n", ret);
156	return CMD_RET_FAILURE;
157}
158
159/**
160 *do_ffa_devlist() - implementation of the devlist subcommand
161 * @cmdtp: [in]		Command Table
162 * @flag:		flags
163 * @argc:		number of arguments
164 * @argv:		arguments
165 *
166 * Query the device belonging to the UCLASS_FFA
167 * class.
168 *
169 * Return:
170 *
171 * CMD_RET_SUCCESS: on success, otherwise failure
172 */
173static int do_ffa_devlist(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
174{
175	struct udevice *dev;
176	int ret;
177
178	ret = ffa_get_dev(&dev);
179	if (ret)
180		return CMD_RET_FAILURE;
181
182	log_info("device %s, addr " PHYS_ADDR_LN ", driver %s, ops " PHYS_ADDR_LN "\n",
183		 dev->name,
184		 map_to_sysmem(dev),
185		 dev->driver->name,
186		 map_to_sysmem(dev->driver->ops));
187
188	return CMD_RET_SUCCESS;
189}
190
191U_BOOT_LONGHELP(armffa,
192	"getpart <partition UUID>\n"
193	"       - lists the partition(s) info\n"
194	"ping <partition ID>\n"
195	"       - sends a data pattern to the specified partition\n"
196	"devlist\n"
197	"       - displays information about the FF-A device/driver\n");
198
199U_BOOT_CMD_WITH_SUBCMDS(armffa, "Arm FF-A test command", armffa_help_text,
200			U_BOOT_SUBCMD_MKENT(getpart, 2, 1, do_ffa_getpart),
201			U_BOOT_SUBCMD_MKENT(ping, 2, 1, do_ffa_ping),
202			U_BOOT_SUBCMD_MKENT(devlist, 1, 1, do_ffa_devlist));
203