1// 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); 385