1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * SCMI Base protocol as U-Boot device 4 * 5 * Copyright (C) 2023 Linaro Limited 6 * author: AKASHI Takahiro <takahiro.akashi@linaro.org> 7 */ 8 9#include <dm.h> 10#include <scmi_agent.h> 11#include <scmi_protocols.h> 12#include <stdlib.h> 13#include <string.h> 14#include <asm/types.h> 15#include <dm/device_compat.h> 16#include <linux/kernel.h> 17 18/** 19 * scmi_generic_protocol_version - get protocol version 20 * @dev: SCMI device 21 * @id: SCMI protocol ID 22 * @version: Pointer to SCMI protocol version 23 * 24 * Obtain the protocol version number in @version. 25 * 26 * Return: 0 on success, error code on failure 27 */ 28int scmi_generic_protocol_version(struct udevice *dev, 29 enum scmi_std_protocol id, u32 *version) 30{ 31 struct scmi_protocol_version_out out; 32 struct scmi_msg msg = { 33 .protocol_id = id, 34 .message_id = SCMI_PROTOCOL_VERSION, 35 .out_msg = (u8 *)&out, 36 .out_msg_sz = sizeof(out), 37 }; 38 int ret; 39 40 ret = devm_scmi_process_msg(dev, &msg); 41 if (ret) 42 return ret; 43 if (out.status) 44 return scmi_to_linux_errno(out.status); 45 46 *version = out.version; 47 48 return 0; 49} 50 51/** 52 * scmi_base_protocol_version_int - get Base protocol version 53 * @dev: SCMI device 54 * @version: Pointer to SCMI protocol version 55 * 56 * Obtain the protocol version number in @version for Base protocol. 57 * 58 * Return: 0 on success, error code on failure 59 */ 60static int scmi_base_protocol_version_int(struct udevice *dev, u32 *version) 61{ 62 return scmi_generic_protocol_version(dev, SCMI_PROTOCOL_ID_BASE, 63 version); 64} 65 66/** 67 * scmi_protocol_attrs_int - get protocol attributes 68 * @dev: SCMI device 69 * @num_agents: Number of SCMI agents 70 * @num_protocols: Number of SCMI protocols 71 * 72 * Obtain the protocol attributes, the number of agents and the number 73 * of protocols, in @num_agents and @num_protocols respectively, that 74 * the device provides. 75 * 76 * Return: 0 on success, error code on failure 77 */ 78static int scmi_protocol_attrs_int(struct udevice *dev, u32 *num_agents, 79 u32 *num_protocols) 80{ 81 struct scmi_protocol_attrs_out out; 82 struct scmi_msg msg = { 83 .protocol_id = SCMI_PROTOCOL_ID_BASE, 84 .message_id = SCMI_PROTOCOL_ATTRIBUTES, 85 .out_msg = (u8 *)&out, 86 .out_msg_sz = sizeof(out), 87 }; 88 int ret; 89 90 ret = devm_scmi_process_msg(dev, &msg); 91 if (ret) 92 return ret; 93 if (out.status) 94 return scmi_to_linux_errno(out.status); 95 96 *num_agents = SCMI_PROTOCOL_ATTRS_NUM_AGENTS(out.attributes); 97 *num_protocols = SCMI_PROTOCOL_ATTRS_NUM_PROTOCOLS(out.attributes); 98 99 return 0; 100} 101 102/** 103 * scmi_protocol_message_attrs_int - get message-specific attributes 104 * @dev: SCMI device 105 * @message_id: SCMI message ID 106 * @attributes: Message-specific attributes 107 * 108 * Obtain the message-specific attributes in @attributes. 109 * This command succeeds if the message is implemented and available. 110 * 111 * Return: 0 on success, error code on failure 112 */ 113static int scmi_protocol_message_attrs_int(struct udevice *dev, u32 message_id, 114 u32 *attributes) 115{ 116 struct scmi_protocol_msg_attrs_out out; 117 struct scmi_msg msg = { 118 .protocol_id = SCMI_PROTOCOL_ID_BASE, 119 .message_id = SCMI_PROTOCOL_MESSAGE_ATTRIBUTES, 120 .in_msg = (u8 *)&message_id, 121 .in_msg_sz = sizeof(message_id), 122 .out_msg = (u8 *)&out, 123 .out_msg_sz = sizeof(out), 124 }; 125 int ret; 126 127 ret = devm_scmi_process_msg(dev, &msg); 128 if (ret) 129 return ret; 130 if (out.status) 131 return scmi_to_linux_errno(out.status); 132 133 *attributes = out.attributes; 134 135 return 0; 136} 137 138/** 139 * scmi_base_discover_vendor_int - get vendor name 140 * @dev: SCMI device 141 * @vendor: Pointer to vendor name 142 * 143 * Obtain the vendor's name in @vendor. 144 * It is a caller's responsibility to free @vendor. 145 * 146 * Return: 0 on success, error code on failure 147 */ 148static int scmi_base_discover_vendor_int(struct udevice *dev, u8 **vendor) 149{ 150 struct scmi_base_discover_vendor_out out; 151 struct scmi_msg msg = { 152 .protocol_id = SCMI_PROTOCOL_ID_BASE, 153 .message_id = SCMI_BASE_DISCOVER_VENDOR, 154 .out_msg = (u8 *)&out, 155 .out_msg_sz = sizeof(out), 156 }; 157 int ret; 158 159 if (!vendor) 160 return -EINVAL; 161 162 ret = devm_scmi_process_msg(dev, &msg); 163 if (ret) 164 return ret; 165 if (out.status) 166 return scmi_to_linux_errno(out.status); 167 168 *vendor = strdup(out.vendor_identifier); 169 if (!*vendor) 170 return -ENOMEM; 171 172 return 0; 173} 174 175/** 176 * scmi_base_discover_sub_vendor_int - get sub-vendor name 177 * @dev: SCMI device 178 * @sub_vendor: Pointer to sub-vendor name 179 * 180 * Obtain the sub-vendor's name in @sub_vendor. 181 * It is a caller's responsibility to free @sub_vendor. 182 * 183 * Return: 0 on success, error code on failure 184 */ 185static int scmi_base_discover_sub_vendor_int(struct udevice *dev, 186 u8 **sub_vendor) 187{ 188 struct scmi_base_discover_vendor_out out; 189 struct scmi_msg msg = { 190 .protocol_id = SCMI_PROTOCOL_ID_BASE, 191 .message_id = SCMI_BASE_DISCOVER_SUB_VENDOR, 192 .out_msg = (u8 *)&out, 193 .out_msg_sz = sizeof(out), 194 }; 195 int ret; 196 197 if (!sub_vendor) 198 return -EINVAL; 199 200 ret = devm_scmi_process_msg(dev, &msg); 201 if (ret) 202 return ret; 203 if (out.status) 204 return scmi_to_linux_errno(out.status); 205 206 *sub_vendor = strdup(out.vendor_identifier); 207 if (!*sub_vendor) 208 return -ENOMEM; 209 210 return 0; 211} 212 213/** 214 * scmi_base_discover_impl_version_int - get implementation version 215 * @dev: SCMI device 216 * @impl_version: Pointer to implementation version 217 * 218 * Obtain the implementation version number in @impl_version. 219 * 220 * Return: 0 on success, error code on failure 221 */ 222static int scmi_base_discover_impl_version_int(struct udevice *dev, 223 u32 *impl_version) 224{ 225 struct scmi_base_discover_impl_version_out out; 226 struct scmi_msg msg = { 227 .protocol_id = SCMI_PROTOCOL_ID_BASE, 228 .message_id = SCMI_BASE_DISCOVER_IMPL_VERSION, 229 .out_msg = (u8 *)&out, 230 .out_msg_sz = sizeof(out), 231 }; 232 int ret; 233 234 ret = devm_scmi_process_msg(dev, &msg); 235 if (ret) 236 return ret; 237 if (out.status) 238 return scmi_to_linux_errno(out.status); 239 240 *impl_version = out.impl_version; 241 242 return 0; 243} 244 245/** 246 * scmi_base_discover_list_protocols_int - get list of protocols 247 * @dev: SCMI device 248 * @protocols: Pointer to array of SCMI protocols 249 * 250 * Obtain the list of protocols provided in @protocols. 251 * The number of elements in @protocols always match to the number of 252 * protocols returned by smci_protocol_attrs() when this function succeeds. 253 * It is a caller's responsibility to free @protocols. 254 * 255 * Return: the number of protocols in @protocols on success, error code on 256 * failure 257 */ 258static int scmi_base_discover_list_protocols_int(struct udevice *dev, 259 u8 **protocols) 260{ 261 struct scmi_base_discover_list_protocols_out out; 262 int cur; 263 struct scmi_msg msg = { 264 .protocol_id = SCMI_PROTOCOL_ID_BASE, 265 .message_id = SCMI_BASE_DISCOVER_LIST_PROTOCOLS, 266 .in_msg = (u8 *)&cur, 267 .in_msg_sz = sizeof(cur), 268 .out_msg = (u8 *)&out, 269 .out_msg_sz = sizeof(out), 270 }; 271 u32 num_agents, num_protocols; 272 u8 *buf; 273 int i, ret; 274 275 ret = scmi_base_protocol_attrs(dev, &num_agents, &num_protocols); 276 if (ret) 277 return ret; 278 279 buf = calloc(sizeof(u8), num_protocols); 280 if (!buf) 281 return -ENOMEM; 282 283 cur = 0; 284 do { 285 ret = devm_scmi_process_msg(dev, &msg); 286 if (ret) 287 goto err; 288 if (out.status) { 289 ret = scmi_to_linux_errno(out.status); 290 goto err; 291 } 292 293 for (i = 0; i < out.num_protocols; i++, cur++) 294 buf[cur] = out.protocols[i / 4] >> ((i % 4) * 8); 295 } while (cur < num_protocols); 296 297 *protocols = buf; 298 299 return num_protocols; 300err: 301 free(buf); 302 303 return ret; 304} 305 306/** 307 * scmi_base_discover_agent_int - identify agent 308 * @dev: SCMI device 309 * @agent_id: SCMI agent ID 310 * @ret_agent_id: Pointer to SCMI agent ID 311 * @name: Pointer to SCMI agent name 312 * 313 * Obtain the agent's name in @name. If @agent_id is equal to 0xffffffff, 314 * this function returns the caller's agent id in @ret_agent_id. 315 * It is a caller's responsibility to free @name. 316 * 317 * Return: 0 on success, error code on failure 318 */ 319static int scmi_base_discover_agent_int(struct udevice *dev, u32 agent_id, 320 u32 *ret_agent_id, u8 **name) 321{ 322 struct scmi_base_discover_agent_out out; 323 struct scmi_msg msg = { 324 .protocol_id = SCMI_PROTOCOL_ID_BASE, 325 .message_id = SCMI_BASE_DISCOVER_AGENT, 326 .in_msg = (u8 *)&agent_id, 327 .in_msg_sz = sizeof(agent_id), 328 .out_msg = (u8 *)&out, 329 .out_msg_sz = sizeof(out), 330 }; 331 int ret; 332 333 ret = devm_scmi_process_msg(dev, &msg); 334 if (ret) 335 return ret; 336 if (out.status) 337 return scmi_to_linux_errno(out.status); 338 339 if (ret_agent_id) 340 *ret_agent_id = out.agent_id; 341 if (name) { 342 *name = strdup(out.name); 343 if (!*name) 344 return -ENOMEM; 345 } 346 347 return 0; 348} 349 350/** 351 * scmi_base_set_device_permissions_int - configure access permission to device 352 * @dev: SCMI device 353 * @agent_id: SCMI agent ID 354 * @device_id: ID of device to access 355 * @flags: A set of flags 356 * 357 * Ask for allowing or denying access permission to the device, @device_id. 358 * The meaning of @flags is defined in SCMI specification. 359 * 360 * Return: 0 on success, error code on failure 361 */ 362static int scmi_base_set_device_permissions_int(struct udevice *dev, u32 agent_id, 363 u32 device_id, u32 flags) 364{ 365 struct scmi_base_set_device_permissions_in in = { 366 .agent_id = agent_id, 367 .device_id = device_id, 368 .flags = flags, 369 }; 370 s32 status; 371 struct scmi_msg msg = { 372 .protocol_id = SCMI_PROTOCOL_ID_BASE, 373 .message_id = SCMI_BASE_SET_DEVICE_PERMISSIONS, 374 .in_msg = (u8 *)&in, 375 .in_msg_sz = sizeof(in), 376 .out_msg = (u8 *)&status, 377 .out_msg_sz = sizeof(status), 378 }; 379 int ret; 380 381 ret = devm_scmi_process_msg(dev, &msg); 382 if (ret) 383 return ret; 384 if (status) 385 return scmi_to_linux_errno(status); 386 387 return 0; 388} 389 390/** 391 * scmi_base_set_protocol_permissions_int - configure access permission to 392 * protocol on device 393 * @dev: SCMI device 394 * @agent_id: SCMI agent ID 395 * @device_id: ID of device to access 396 * @command_id: SCMI command ID 397 * @flags: A set of flags 398 * 399 * Ask for allowing or denying access permission to the protocol, @command_id, 400 * on the device, @device_id. 401 * The meaning of @flags is defined in SCMI specification. 402 * 403 * Return: 0 on success, error code on failure 404 */ 405static int scmi_base_set_protocol_permissions_int(struct udevice *dev, 406 u32 agent_id, u32 device_id, 407 u32 command_id, u32 flags) 408{ 409 struct scmi_base_set_protocol_permissions_in in = { 410 .agent_id = agent_id, 411 .device_id = device_id, 412 .command_id = command_id, 413 .flags = flags, 414 }; 415 s32 status; 416 struct scmi_msg msg = { 417 .protocol_id = SCMI_PROTOCOL_ID_BASE, 418 .message_id = SCMI_BASE_SET_PROTOCOL_PERMISSIONS, 419 .in_msg = (u8 *)&in, 420 .in_msg_sz = sizeof(in), 421 .out_msg = (u8 *)&status, 422 .out_msg_sz = sizeof(status), 423 }; 424 int ret; 425 426 ret = devm_scmi_process_msg(dev, &msg); 427 if (ret) 428 return ret; 429 if (status) 430 return scmi_to_linux_errno(status); 431 432 return 0; 433} 434 435/** 436 * scmi_base_reset_agent_configuration_int - reset resource settings 437 * @dev: SCMI device 438 * @agent_id: SCMI agent ID 439 * @flags: A set of flags 440 * 441 * Reset all the resource settings against @agent_id. 442 * The meaning of @flags is defined in SCMI specification. 443 * 444 * Return: 0 on success, error code on failure 445 */ 446static int scmi_base_reset_agent_configuration_int(struct udevice *dev, 447 u32 agent_id, u32 flags) 448{ 449 struct scmi_base_reset_agent_configuration_in in = { 450 .agent_id = agent_id, 451 .flags = flags, 452 }; 453 s32 status; 454 struct scmi_msg msg = { 455 .protocol_id = SCMI_PROTOCOL_ID_BASE, 456 .message_id = SCMI_BASE_RESET_AGENT_CONFIGURATION, 457 .in_msg = (u8 *)&in, 458 .in_msg_sz = sizeof(in), 459 .out_msg = (u8 *)&status, 460 .out_msg_sz = sizeof(status), 461 }; 462 int ret; 463 464 ret = devm_scmi_process_msg(dev, &msg); 465 if (ret) 466 return ret; 467 if (status) 468 return scmi_to_linux_errno(status); 469 470 return 0; 471} 472 473/** 474 * scmi_base_probe - probe base protocol device 475 * @dev: SCMI device 476 * 477 * Probe the device for SCMI base protocol and initialize the private data. 478 * 479 * Return: 0 on success, error code on failure 480 */ 481static int scmi_base_probe(struct udevice *dev) 482{ 483 u32 version; 484 int ret; 485 486 ret = devm_scmi_of_get_channel(dev); 487 if (ret) { 488 dev_err(dev, "get_channel failed\n"); 489 return ret; 490 } 491 ret = scmi_base_protocol_version_int(dev, &version); 492 if (ret) { 493 dev_err(dev, "getting protocol version failed\n"); 494 return ret; 495 } 496 if (version < SCMI_BASE_PROTOCOL_VERSION) 497 return -EINVAL; 498 499 return ret; 500} 501 502static struct scmi_base_ops scmi_base_ops = { 503 /* Commands */ 504 .protocol_version = scmi_base_protocol_version_int, 505 .protocol_attrs = scmi_protocol_attrs_int, 506 .protocol_message_attrs = scmi_protocol_message_attrs_int, 507 .base_discover_vendor = scmi_base_discover_vendor_int, 508 .base_discover_sub_vendor = scmi_base_discover_sub_vendor_int, 509 .base_discover_impl_version = scmi_base_discover_impl_version_int, 510 .base_discover_list_protocols = scmi_base_discover_list_protocols_int, 511 .base_discover_agent = scmi_base_discover_agent_int, 512 .base_notify_errors = NULL, 513 .base_set_device_permissions = scmi_base_set_device_permissions_int, 514 .base_set_protocol_permissions = scmi_base_set_protocol_permissions_int, 515 .base_reset_agent_configuration = 516 scmi_base_reset_agent_configuration_int, 517}; 518 519int scmi_base_protocol_version(struct udevice *dev, u32 *version) 520{ 521 const struct scmi_base_ops *ops = device_get_ops(dev); 522 523 if (ops->protocol_version) 524 return (*ops->protocol_version)(dev, version); 525 526 return -EOPNOTSUPP; 527} 528 529int scmi_base_protocol_attrs(struct udevice *dev, u32 *num_agents, 530 u32 *num_protocols) 531{ 532 const struct scmi_base_ops *ops = device_get_ops(dev); 533 534 if (ops->protocol_attrs) 535 return (*ops->protocol_attrs)(dev, num_agents, num_protocols); 536 537 return -EOPNOTSUPP; 538} 539 540int scmi_base_protocol_message_attrs(struct udevice *dev, u32 message_id, 541 u32 *attributes) 542{ 543 const struct scmi_base_ops *ops = device_get_ops(dev); 544 545 if (ops->protocol_message_attrs) 546 return (*ops->protocol_message_attrs)(dev, message_id, 547 attributes); 548 549 return -EOPNOTSUPP; 550} 551 552int scmi_base_discover_vendor(struct udevice *dev, u8 **vendor) 553{ 554 const struct scmi_base_ops *ops = device_get_ops(dev); 555 556 if (ops->base_discover_vendor) 557 return (*ops->base_discover_vendor)(dev, vendor); 558 559 return -EOPNOTSUPP; 560} 561 562int scmi_base_discover_sub_vendor(struct udevice *dev, u8 **sub_vendor) 563{ 564 const struct scmi_base_ops *ops = device_get_ops(dev); 565 566 if (ops->base_discover_sub_vendor) 567 return (*ops->base_discover_sub_vendor)(dev, sub_vendor); 568 569 return -EOPNOTSUPP; 570} 571 572int scmi_base_discover_impl_version(struct udevice *dev, u32 *impl_version) 573{ 574 const struct scmi_base_ops *ops = device_get_ops(dev); 575 576 if (ops->base_discover_impl_version) 577 return (*ops->base_discover_impl_version)(dev, impl_version); 578 579 return -EOPNOTSUPP; 580} 581 582int scmi_base_discover_list_protocols(struct udevice *dev, u8 **protocols) 583{ 584 const struct scmi_base_ops *ops = device_get_ops(dev); 585 586 if (ops->base_discover_list_protocols) 587 return (*ops->base_discover_list_protocols)(dev, protocols); 588 589 return -EOPNOTSUPP; 590} 591 592int scmi_base_discover_agent(struct udevice *dev, u32 agent_id, 593 u32 *ret_agent_id, u8 **name) 594{ 595 const struct scmi_base_ops *ops = device_get_ops(dev); 596 597 if (ops->base_discover_agent) 598 return (*ops->base_discover_agent)(dev, agent_id, ret_agent_id, 599 name); 600 601 return -EOPNOTSUPP; 602} 603 604int scmi_base_notify_errors(struct udevice *dev, u32 enable) 605{ 606 const struct scmi_base_ops *ops = device_get_ops(dev); 607 608 if (ops->base_notify_errors) 609 return (*ops->base_notify_errors)(dev, enable); 610 611 return -EOPNOTSUPP; 612} 613 614int scmi_base_set_device_permissions(struct udevice *dev, u32 agent_id, 615 u32 device_id, u32 flags) 616{ 617 const struct scmi_base_ops *ops = device_get_ops(dev); 618 619 if (ops->base_set_device_permissions) 620 return (*ops->base_set_device_permissions)(dev, agent_id, 621 device_id, flags); 622 623 return -EOPNOTSUPP; 624} 625 626int scmi_base_set_protocol_permissions(struct udevice *dev, 627 u32 agent_id, u32 device_id, 628 u32 command_id, u32 flags) 629{ 630 const struct scmi_base_ops *ops = device_get_ops(dev); 631 632 if (ops->base_set_protocol_permissions) 633 return (*ops->base_set_protocol_permissions)(dev, agent_id, 634 device_id, 635 command_id, 636 flags); 637 638 return -EOPNOTSUPP; 639} 640 641int scmi_base_reset_agent_configuration(struct udevice *dev, u32 agent_id, 642 u32 flags) 643{ 644 const struct scmi_base_ops *ops = device_get_ops(dev); 645 646 if (ops->base_reset_agent_configuration) 647 return (*ops->base_reset_agent_configuration)(dev, agent_id, 648 flags); 649 650 return -EOPNOTSUPP; 651} 652 653U_BOOT_DRIVER(scmi_base_drv) = { 654 .id = UCLASS_SCMI_BASE, 655 .name = "scmi_base_drv", 656 .ops = &scmi_base_ops, 657 .probe = scmi_base_probe, 658}; 659 660UCLASS_DRIVER(scmi_base) = { 661 .id = UCLASS_SCMI_BASE, 662 .name = "scmi_base", 663}; 664