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