blob: 664062c4eff5b6ef16b7c04902ee77a5ff8890c8 [file] [log] [blame]
AKASHI Takahiro1cdcaed2023-11-14 11:14:26 +09001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * SCMI (System Control and Management Interface) utility command
4 *
5 * Copyright (c) 2023 Linaro Limited
6 * Author: AKASHI Takahiro
7 */
8
9#include <command.h>
10#include <exports.h>
11#include <scmi_agent.h>
12#include <scmi_agent-uclass.h>
13#include <stdlib.h>
14#include <asm/types.h>
15#include <dm/device.h>
16#include <dm/uclass.h> /* uclass_get_device */
17#include <linux/bitfield.h>
18#include <linux/bitops.h>
19
20struct {
21 enum scmi_std_protocol id;
22 const char *name;
23} protocol_name[] = {
24 {SCMI_PROTOCOL_ID_BASE, "Base"},
25 {SCMI_PROTOCOL_ID_POWER_DOMAIN, "Power domain management"},
26 {SCMI_PROTOCOL_ID_SYSTEM, "System power management"},
27 {SCMI_PROTOCOL_ID_PERF, "Performance domain management"},
28 {SCMI_PROTOCOL_ID_CLOCK, "Clock management"},
29 {SCMI_PROTOCOL_ID_SENSOR, "Sensor management"},
30 {SCMI_PROTOCOL_ID_RESET_DOMAIN, "Reset domain management"},
31 {SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN, "Voltage domain management"},
32};
33
34/**
35 * get_agent() - get SCMI agent device
36 *
37 * Return: Pointer to SCMI agent device on success, NULL on failure
38 */
39static struct udevice *get_agent(void)
40{
41 struct udevice *agent;
42
43 if (uclass_get_device(UCLASS_SCMI_AGENT, 0, &agent)) {
44 printf("Cannot find any SCMI agent\n");
45 return NULL;
46 }
47
48 return agent;
49}
50
51/**
52 * get_base_proto() - get SCMI base protocol device
53 * @agent: SCMI agent device
54 *
55 * Return: Pointer to SCMI base protocol device on success,
56 * NULL on failure
57 */
58static struct udevice *get_base_proto(struct udevice *agent)
59{
60 struct udevice *base_proto;
61
62 if (!agent) {
63 agent = get_agent();
64 if (!agent)
65 return NULL;
66 }
67
68 base_proto = scmi_get_protocol(agent, SCMI_PROTOCOL_ID_BASE);
69 if (!base_proto) {
70 printf("SCMI base protocol not found\n");
71 return NULL;
72 }
73
74 return base_proto;
75}
76
77/**
78 * get_proto_name() - get the name of SCMI protocol
79 *
80 * @id: SCMI Protocol ID
81 *
82 * Get the printable name of the protocol, @id
83 *
84 * Return: Name string on success, NULL on failure
85 */
86static const char *get_proto_name(enum scmi_std_protocol id)
87{
88 int i;
89
90 for (i = 0; i < ARRAY_SIZE(protocol_name); i++)
91 if (id == protocol_name[i].id)
92 return protocol_name[i].name;
93
94 return NULL;
95}
96
97/**
98 * do_scmi_info() - get the information of SCMI services
99 *
100 * @cmdtp: Command table
101 * @flag: Command flag
102 * @argc: Number of arguments
103 * @argv: Argument array
104 *
105 * Get the information of SCMI services using various interfaces
106 * provided by the Base protocol.
107 *
108 * Return: CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
109 */
110static int do_scmi_info(struct cmd_tbl *cmdtp, int flag, int argc,
111 char * const argv[])
112{
113 struct udevice *agent, *base_proto;
114 u32 agent_id, num_protocols;
115 u8 *agent_name, *protocols;
116 int i, ret;
117
118 if (argc != 1)
119 return CMD_RET_USAGE;
120
121 agent = get_agent();
122 if (!agent)
123 return CMD_RET_FAILURE;
124 base_proto = get_base_proto(agent);
125 if (!base_proto)
126 return CMD_RET_FAILURE;
127
128 printf("SCMI device: %s\n", agent->name);
129 printf(" protocol version: 0x%x\n", scmi_version(agent));
130 printf(" # of agents: %d\n", scmi_num_agents(agent));
131 for (i = 0; i < scmi_num_agents(agent); i++) {
132 ret = scmi_base_discover_agent(base_proto, i, &agent_id,
133 &agent_name);
134 if (ret) {
135 if (ret != -EOPNOTSUPP)
136 printf("base_discover_agent() failed for id: %d (%d)\n",
137 i, ret);
138 break;
139 }
140 printf(" %c%2d: %s\n", i == scmi_agent_id(agent) ? '>' : ' ',
141 i, agent_name);
142 free(agent_name);
143 }
144 printf(" # of protocols: %d\n", scmi_num_protocols(agent));
145 num_protocols = scmi_num_protocols(agent);
146 protocols = scmi_protocols(agent);
147 if (protocols)
148 for (i = 0; i < num_protocols; i++)
149 printf(" %s\n", get_proto_name(protocols[i]));
150 printf(" vendor: %s\n", scmi_vendor(agent));
151 printf(" sub vendor: %s\n", scmi_sub_vendor(agent));
152 printf(" impl version: 0x%x\n", scmi_impl_version(agent));
153
154 return CMD_RET_SUCCESS;
155}
156
157/**
158 * do_scmi_set_dev() - set access permission to device
159 *
160 * @cmdtp: Command table
161 * @flag: Command flag
162 * @argc: Number of arguments
163 * @argv: Argument array
164 *
165 * Set access permission to device with SCMI_BASE_SET_DEVICE_PERMISSIONS
166 *
167 * Return: CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
168 */
169static int do_scmi_set_dev(struct cmd_tbl *cmdtp, int flag, int argc,
170 char * const argv[])
171{
172 u32 agent_id, device_id, flags, attributes;
173 char *end;
174 struct udevice *base_proto;
175 int ret;
176
177 if (argc != 4)
178 return CMD_RET_USAGE;
179
180 agent_id = simple_strtoul(argv[1], &end, 16);
181 if (*end != '\0')
182 return CMD_RET_USAGE;
183
184 device_id = simple_strtoul(argv[2], &end, 16);
185 if (*end != '\0')
186 return CMD_RET_USAGE;
187
188 flags = simple_strtoul(argv[3], &end, 16);
189 if (*end != '\0')
190 return CMD_RET_USAGE;
191
192 base_proto = get_base_proto(NULL);
193 if (!base_proto)
194 return CMD_RET_FAILURE;
195
196 ret = scmi_base_protocol_message_attrs(base_proto,
197 SCMI_BASE_SET_DEVICE_PERMISSIONS,
198 &attributes);
199 if (ret) {
200 printf("This operation is not supported\n");
201 return CMD_RET_FAILURE;
202 }
203
204 ret = scmi_base_set_device_permissions(base_proto, agent_id,
205 device_id, flags);
206 if (ret) {
207 printf("%s access to device:%u failed (%d)\n",
208 flags ? "Allowing" : "Denying", device_id, ret);
209 return CMD_RET_FAILURE;
210 }
211
212 return CMD_RET_SUCCESS;
213}
214
215/**
216 * do_scmi_set_proto() - set protocol permission to device
217 *
218 * @cmdtp: Command table
219 * @flag: Command flag
220 * @argc: Number of arguments
221 * @argv: Argument array
222 *
223 * Set protocol permission to device with SCMI_BASE_SET_PROTOCOL_PERMISSIONS
224 *
225 * Return: CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
226 */
227static int do_scmi_set_proto(struct cmd_tbl *cmdtp, int flag, int argc,
228 char * const argv[])
229{
230 u32 agent_id, device_id, protocol_id, flags, attributes;
231 char *end;
232 struct udevice *base_proto;
233 int ret;
234
235 if (argc != 5)
236 return CMD_RET_USAGE;
237
238 agent_id = simple_strtoul(argv[1], &end, 16);
239 if (*end != '\0')
240 return CMD_RET_USAGE;
241
242 device_id = simple_strtoul(argv[2], &end, 16);
243 if (*end != '\0')
244 return CMD_RET_USAGE;
245
246 protocol_id = simple_strtoul(argv[3], &end, 16);
247 if (*end != '\0')
248 return CMD_RET_USAGE;
249
250 flags = simple_strtoul(argv[4], &end, 16);
251 if (*end != '\0')
252 return CMD_RET_USAGE;
253
254 base_proto = get_base_proto(NULL);
255 if (!base_proto)
256 return CMD_RET_FAILURE;
257
258 ret = scmi_base_protocol_message_attrs(base_proto,
259 SCMI_BASE_SET_PROTOCOL_PERMISSIONS,
260 &attributes);
261 if (ret) {
262 printf("This operation is not supported\n");
263 return CMD_RET_FAILURE;
264 }
265
266 ret = scmi_base_set_protocol_permissions(base_proto, agent_id,
267 device_id, protocol_id,
268 flags);
269 if (ret) {
270 printf("%s access to protocol:0x%x on device:%u failed (%d)\n",
271 flags ? "Allowing" : "Denying", protocol_id, device_id,
272 ret);
273 return CMD_RET_FAILURE;
274 }
275
276 return CMD_RET_SUCCESS;
277}
278
279/**
280 * do_scmi_reset() - reset platform resource settings
281 *
282 * @cmdtp: Command table
283 * @flag: Command flag
284 * @argc: Number of arguments
285 * @argv: Argument array
286 *
287 * Reset platform resource settings with BASE_RESET_AGENT_CONFIGURATION
288 *
289 * Return: CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
290 */
291static int do_scmi_reset(struct cmd_tbl *cmdtp, int flag, int argc,
292 char * const argv[])
293{
294 u32 agent_id, flags, attributes;
295 char *end;
296 struct udevice *base_proto;
297 int ret;
298
299 if (argc != 3)
300 return CMD_RET_USAGE;
301
302 agent_id = simple_strtoul(argv[1], &end, 16);
303 if (*end != '\0')
304 return CMD_RET_USAGE;
305
306 flags = simple_strtoul(argv[2], &end, 16);
307 if (*end != '\0')
308 return CMD_RET_USAGE;
309
310 base_proto = get_base_proto(NULL);
311 if (!base_proto)
312 return CMD_RET_FAILURE;
313
314 ret = scmi_base_protocol_message_attrs(base_proto,
315 SCMI_BASE_RESET_AGENT_CONFIGURATION,
316 &attributes);
317 if (ret) {
318 printf("Reset is not supported\n");
319 return CMD_RET_FAILURE;
320 }
321
322 ret = scmi_base_reset_agent_configuration(base_proto, agent_id, flags);
323 if (ret) {
324 printf("Reset failed (%d)\n", ret);
325 return CMD_RET_FAILURE;
326 }
327
328 return CMD_RET_SUCCESS;
329}
330
331static struct cmd_tbl cmd_scmi_sub[] = {
332 U_BOOT_CMD_MKENT(info, CONFIG_SYS_MAXARGS, 1,
333 do_scmi_info, "", ""),
334 U_BOOT_CMD_MKENT(perm_dev, CONFIG_SYS_MAXARGS, 1,
335 do_scmi_set_dev, "", ""),
336 U_BOOT_CMD_MKENT(perm_proto, CONFIG_SYS_MAXARGS, 1,
337 do_scmi_set_proto, "", ""),
338 U_BOOT_CMD_MKENT(reset, CONFIG_SYS_MAXARGS, 1,
339 do_scmi_reset, "", ""),
340};
341
342/**
343 * do_scmi() - SCMI utility
344 *
345 * @cmdtp: Command table
346 * @flag: Command flag
347 * @argc: Number of arguments
348 * @argv: Argument array
349 *
350 * Provide user interfaces to SCMI protocols.
351 *
352 * Return: CMD_RET_SUCCESS on success,
353 * CMD_RET_USAGE or CMD_RET_RET_FAILURE on failure
354 */
355static int do_scmi(struct cmd_tbl *cmdtp, int flag,
356 int argc, char *const argv[])
357{
358 struct cmd_tbl *cp;
359
360 if (argc < 2)
361 return CMD_RET_USAGE;
362
363 argc--; argv++;
364
365 cp = find_cmd_tbl(argv[0], cmd_scmi_sub, ARRAY_SIZE(cmd_scmi_sub));
366 if (!cp)
367 return CMD_RET_USAGE;
368
369 return cp->cmd(cmdtp, flag, argc, argv);
370}
371
372static char scmi_help_text[] =
373 " - SCMI utility\n"
374 " info - get the info of SCMI services\n"
375 " perm_dev <agent-id in hex> <device-id in hex> <flags in hex>\n"
376 " - set access permission to device\n"
377 " perm_proto <agent-id in hex> <device-id in hex> <protocol-id in hex> <flags in hex>\n"
378 " - set protocol permission to device\n"
379 " reset <agent-id in hex> <flags in hex>\n"
380 " - reset platform resource settings\n"
381 "";
382
383U_BOOT_CMD(scmi, CONFIG_SYS_MAXARGS, 0, do_scmi, "SCMI utility",
384 scmi_help_text);