1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Texas Instruments System Control Interface Protocol Driver 4 * Based on drivers/firmware/ti_sci.c from Linux. 5 * 6 * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/ 7 * Lokesh Vutla <lokeshvutla@ti.com> 8 */ 9 10 #include <common.h> 11 #include <dm.h> 12 #include <errno.h> 13 #include <mailbox.h> 14 #include <dm/device.h> 15 #include <linux/err.h> 16 #include <linux/soc/ti/k3-sec-proxy.h> 17 #include <linux/soc/ti/ti_sci_protocol.h> 18 19 #include "ti_sci.h" 20 21 /* List of all TI SCI devices active in system */ 22 static LIST_HEAD(ti_sci_list); 23 24 /** 25 * struct ti_sci_xfer - Structure representing a message flow 26 * @tx_message: Transmit message 27 * @rx_len: Receive message length 28 */ 29 struct ti_sci_xfer { 30 struct k3_sec_proxy_msg tx_message; 31 u8 rx_len; 32 }; 33 34 /** 35 * struct ti_sci_desc - Description of SoC integration 36 * @host_id: Host identifier representing the compute entity 37 * @max_rx_timeout_us: Timeout for communication with SoC (in Microseconds) 38 * @max_msg_size: Maximum size of data per message that can be handled. 39 */ 40 struct ti_sci_desc { 41 u8 host_id; 42 int max_rx_timeout_us; 43 int max_msg_size; 44 }; 45 46 /** 47 * struct ti_sci_info - Structure representing a TI SCI instance 48 * @dev: Device pointer 49 * @desc: SoC description for this instance 50 * @handle: Instance of TI SCI handle to send to clients. 51 * @chan_tx: Transmit mailbox channel 52 * @chan_rx: Receive mailbox channel 53 * @xfer: xfer info 54 * @list: list head 55 * @is_secure: Determines if the communication is through secure threads. 56 * @host_id: Host identifier representing the compute entity 57 * @seq: Seq id used for verification for tx and rx message. 58 */ 59 struct ti_sci_info { 60 struct udevice *dev; 61 const struct ti_sci_desc *desc; 62 struct ti_sci_handle handle; 63 struct mbox_chan chan_tx; 64 struct mbox_chan chan_rx; 65 struct mbox_chan chan_notify; 66 struct ti_sci_xfer xfer; 67 struct list_head list; 68 bool is_secure; 69 u8 host_id; 70 u8 seq; 71 }; 72 73 #define handle_to_ti_sci_info(h) container_of(h, struct ti_sci_info, handle) 74 75 /** 76 * ti_sci_setup_one_xfer() - Setup one message type 77 * @info: Pointer to SCI entity information 78 * @msg_type: Message type 79 * @msg_flags: Flag to set for the message 80 * @buf: Buffer to be send to mailbox channel 81 * @tx_message_size: transmit message size 82 * @rx_message_size: receive message size 83 * 84 * Helper function which is used by various command functions that are 85 * exposed to clients of this driver for allocating a message traffic event. 86 * 87 * Return: Corresponding ti_sci_xfer pointer if all went fine, 88 * else appropriate error pointer. 89 */ 90 static struct ti_sci_xfer *ti_sci_setup_one_xfer(struct ti_sci_info *info, 91 u16 msg_type, u32 msg_flags, 92 u32 *buf, 93 size_t tx_message_size, 94 size_t rx_message_size) 95 { 96 struct ti_sci_xfer *xfer = &info->xfer; 97 struct ti_sci_msg_hdr *hdr; 98 99 /* Ensure we have sane transfer sizes */ 100 if (rx_message_size > info->desc->max_msg_size || 101 tx_message_size > info->desc->max_msg_size || 102 rx_message_size < sizeof(*hdr) || tx_message_size < sizeof(*hdr)) 103 return ERR_PTR(-ERANGE); 104 105 info->seq = ~info->seq; 106 xfer->tx_message.buf = buf; 107 xfer->tx_message.len = tx_message_size; 108 xfer->rx_len = (u8)rx_message_size; 109 110 hdr = (struct ti_sci_msg_hdr *)buf; 111 hdr->seq = info->seq; 112 hdr->type = msg_type; 113 hdr->host = info->host_id; 114 hdr->flags = msg_flags; 115 116 return xfer; 117 } 118 119 /** 120 * ti_sci_get_response() - Receive response from mailbox channel 121 * @info: Pointer to SCI entity information 122 * @xfer: Transfer to initiate and wait for response 123 * @chan: Channel to receive the response 124 * 125 * Return: -ETIMEDOUT in case of no response, if transmit error, 126 * return corresponding error, else if all goes well, 127 * return 0. 128 */ 129 static inline int ti_sci_get_response(struct ti_sci_info *info, 130 struct ti_sci_xfer *xfer, 131 struct mbox_chan *chan) 132 { 133 struct k3_sec_proxy_msg *msg = &xfer->tx_message; 134 struct ti_sci_secure_msg_hdr *secure_hdr; 135 struct ti_sci_msg_hdr *hdr; 136 int ret; 137 138 /* Receive the response */ 139 ret = mbox_recv(chan, msg, info->desc->max_rx_timeout_us); 140 if (ret) { 141 dev_err(info->dev, "%s: Message receive failed. ret = %d\n", 142 __func__, ret); 143 return ret; 144 } 145 146 /* ToDo: Verify checksum */ 147 if (info->is_secure) { 148 secure_hdr = (struct ti_sci_secure_msg_hdr *)msg->buf; 149 msg->buf = (u32 *)((void *)msg->buf + sizeof(*secure_hdr)); 150 } 151 152 /* msg is updated by mailbox driver */ 153 hdr = (struct ti_sci_msg_hdr *)msg->buf; 154 155 /* Sanity check for message response */ 156 if (hdr->seq != info->seq) { 157 dev_dbg(info->dev, "%s: Message for %d is not expected\n", 158 __func__, hdr->seq); 159 return ret; 160 } 161 162 if (msg->len > info->desc->max_msg_size) { 163 dev_err(info->dev, "%s: Unable to handle %zu xfer (max %d)\n", 164 __func__, msg->len, info->desc->max_msg_size); 165 return -EINVAL; 166 } 167 168 if (msg->len < xfer->rx_len) { 169 dev_err(info->dev, "%s: Recv xfer %zu < expected %d length\n", 170 __func__, msg->len, xfer->rx_len); 171 } 172 173 return ret; 174 } 175 176 /** 177 * ti_sci_do_xfer() - Do one transfer 178 * @info: Pointer to SCI entity information 179 * @xfer: Transfer to initiate and wait for response 180 * 181 * Return: 0 if all went fine, else return appropriate error. 182 */ 183 static inline int ti_sci_do_xfer(struct ti_sci_info *info, 184 struct ti_sci_xfer *xfer) 185 { 186 struct k3_sec_proxy_msg *msg = &xfer->tx_message; 187 u8 secure_buf[info->desc->max_msg_size]; 188 struct ti_sci_secure_msg_hdr secure_hdr; 189 int ret; 190 191 if (info->is_secure) { 192 /* ToDo: get checksum of the entire message */ 193 secure_hdr.checksum = 0; 194 secure_hdr.reserved = 0; 195 memcpy(&secure_buf[sizeof(secure_hdr)], xfer->tx_message.buf, 196 xfer->tx_message.len); 197 198 xfer->tx_message.buf = (u32 *)secure_buf; 199 xfer->tx_message.len += sizeof(secure_hdr); 200 xfer->rx_len += sizeof(secure_hdr); 201 } 202 203 /* Send the message */ 204 ret = mbox_send(&info->chan_tx, msg); 205 if (ret) { 206 dev_err(info->dev, "%s: Message sending failed. ret = %d\n", 207 __func__, ret); 208 return ret; 209 } 210 211 return ti_sci_get_response(info, xfer, &info->chan_rx); 212 } 213 214 /** 215 * ti_sci_cmd_get_revision() - command to get the revision of the SCI entity 216 * @handle: pointer to TI SCI handle 217 * 218 * Updates the SCI information in the internal data structure. 219 * 220 * Return: 0 if all went fine, else return appropriate error. 221 */ 222 static int ti_sci_cmd_get_revision(struct ti_sci_handle *handle) 223 { 224 struct ti_sci_msg_resp_version *rev_info; 225 struct ti_sci_version_info *ver; 226 struct ti_sci_msg_hdr hdr; 227 struct ti_sci_info *info; 228 struct ti_sci_xfer *xfer; 229 int ret; 230 231 if (IS_ERR(handle)) 232 return PTR_ERR(handle); 233 if (!handle) 234 return -EINVAL; 235 236 info = handle_to_ti_sci_info(handle); 237 238 xfer = ti_sci_setup_one_xfer(info, TI_SCI_MSG_VERSION, 0x0, 239 (u32 *)&hdr, sizeof(struct ti_sci_msg_hdr), 240 sizeof(*rev_info)); 241 if (IS_ERR(xfer)) { 242 ret = PTR_ERR(xfer); 243 dev_err(info->dev, "Message alloc failed(%d)\n", ret); 244 return ret; 245 } 246 247 ret = ti_sci_do_xfer(info, xfer); 248 if (ret) { 249 dev_err(info->dev, "Mbox communication fail %d\n", ret); 250 return ret; 251 } 252 253 rev_info = (struct ti_sci_msg_resp_version *)xfer->tx_message.buf; 254 255 ver = &handle->version; 256 ver->abi_major = rev_info->abi_major; 257 ver->abi_minor = rev_info->abi_minor; 258 ver->firmware_revision = rev_info->firmware_revision; 259 strncpy(ver->firmware_description, rev_info->firmware_description, 260 sizeof(ver->firmware_description)); 261 262 return 0; 263 } 264 265 /** 266 * ti_sci_is_response_ack() - Generic ACK/NACK message checkup 267 * @r: pointer to response buffer 268 * 269 * Return: true if the response was an ACK, else returns false. 270 */ 271 static inline bool ti_sci_is_response_ack(void *r) 272 { 273 struct ti_sci_msg_hdr *hdr = r; 274 275 return hdr->flags & TI_SCI_FLAG_RESP_GENERIC_ACK ? true : false; 276 } 277 278 /** 279 * cmd_set_board_config_using_msg() - Common command to send board configuration 280 * message 281 * @handle: pointer to TI SCI handle 282 * @msg_type: One of the TISCI message types to set board configuration 283 * @addr: Address where the board config structure is located 284 * @size: Size of the board config structure 285 * 286 * Return: 0 if all went well, else returns appropriate error value. 287 */ 288 static int cmd_set_board_config_using_msg(const struct ti_sci_handle *handle, 289 u16 msg_type, u64 addr, u32 size) 290 { 291 struct ti_sci_msg_board_config req; 292 struct ti_sci_msg_hdr *resp; 293 struct ti_sci_info *info; 294 struct ti_sci_xfer *xfer; 295 int ret = 0; 296 297 if (IS_ERR(handle)) 298 return PTR_ERR(handle); 299 if (!handle) 300 return -EINVAL; 301 302 info = handle_to_ti_sci_info(handle); 303 304 xfer = ti_sci_setup_one_xfer(info, msg_type, 305 TI_SCI_FLAG_REQ_ACK_ON_PROCESSED, 306 (u32 *)&req, sizeof(req), sizeof(*resp)); 307 if (IS_ERR(xfer)) { 308 ret = PTR_ERR(xfer); 309 dev_err(info->dev, "Message alloc failed(%d)\n", ret); 310 return ret; 311 } 312 req.boardcfgp_high = (addr >> 32) & 0xffffffff; 313 req.boardcfgp_low = addr & 0xffffffff; 314 req.boardcfg_size = size; 315 316 ret = ti_sci_do_xfer(info, xfer); 317 if (ret) { 318 dev_err(info->dev, "Mbox send fail %d\n", ret); 319 return ret; 320 } 321 322 resp = (struct ti_sci_msg_hdr *)xfer->tx_message.buf; 323 324 if (!ti_sci_is_response_ack(resp)) 325 return -ENODEV; 326 327 return ret; 328 } 329 330 /** 331 * ti_sci_cmd_set_board_config() - Command to send board configuration message 332 * @handle: pointer to TI SCI handle 333 * @addr: Address where the board config structure is located 334 * @size: Size of the board config structure 335 * 336 * Return: 0 if all went well, else returns appropriate error value. 337 */ 338 static int ti_sci_cmd_set_board_config(const struct ti_sci_handle *handle, 339 u64 addr, u32 size) 340 { 341 return cmd_set_board_config_using_msg(handle, 342 TI_SCI_MSG_BOARD_CONFIG, 343 addr, size); 344 } 345 346 /** 347 * ti_sci_cmd_set_board_config_rm() - Command to send board resource 348 * management configuration 349 * @handle: pointer to TI SCI handle 350 * @addr: Address where the board RM config structure is located 351 * @size: Size of the RM config structure 352 * 353 * Return: 0 if all went well, else returns appropriate error value. 354 */ 355 static 356 int ti_sci_cmd_set_board_config_rm(const struct ti_sci_handle *handle, 357 u64 addr, u32 size) 358 { 359 return cmd_set_board_config_using_msg(handle, 360 TI_SCI_MSG_BOARD_CONFIG_RM, 361 addr, size); 362 } 363 364 /** 365 * ti_sci_cmd_set_board_config_security() - Command to send board security 366 * configuration message 367 * @handle: pointer to TI SCI handle 368 * @addr: Address where the board security config structure is located 369 * @size: Size of the security config structure 370 * 371 * Return: 0 if all went well, else returns appropriate error value. 372 */ 373 static 374 int ti_sci_cmd_set_board_config_security(const struct ti_sci_handle *handle, 375 u64 addr, u32 size) 376 { 377 return cmd_set_board_config_using_msg(handle, 378 TI_SCI_MSG_BOARD_CONFIG_SECURITY, 379 addr, size); 380 } 381 382 /** 383 * ti_sci_cmd_set_board_config_pm() - Command to send board power and clock 384 * configuration message 385 * @handle: pointer to TI SCI handle 386 * @addr: Address where the board PM config structure is located 387 * @size: Size of the PM config structure 388 * 389 * Return: 0 if all went well, else returns appropriate error value. 390 */ 391 static int ti_sci_cmd_set_board_config_pm(const struct ti_sci_handle *handle, 392 u64 addr, u32 size) 393 { 394 return cmd_set_board_config_using_msg(handle, 395 TI_SCI_MSG_BOARD_CONFIG_PM, 396 addr, size); 397 } 398 399 /* 400 * ti_sci_setup_ops() - Setup the operations structures 401 * @info: pointer to TISCI pointer 402 */ 403 static void ti_sci_setup_ops(struct ti_sci_info *info) 404 { 405 struct ti_sci_ops *ops = &info->handle.ops; 406 struct ti_sci_board_ops *bops = &ops->board_ops; 407 408 bops->board_config = ti_sci_cmd_set_board_config; 409 bops->board_config_rm = ti_sci_cmd_set_board_config_rm; 410 bops->board_config_security = ti_sci_cmd_set_board_config_security; 411 bops->board_config_pm = ti_sci_cmd_set_board_config_pm; 412 } 413 414 /** 415 * ti_sci_get_handle_from_sysfw() - Get the TI SCI handle of the SYSFW 416 * @dev: Pointer to the SYSFW device 417 * 418 * Return: pointer to handle if successful, else EINVAL if invalid conditions 419 * are encountered. 420 */ 421 const 422 struct ti_sci_handle *ti_sci_get_handle_from_sysfw(struct udevice *sci_dev) 423 { 424 if (!sci_dev) 425 return ERR_PTR(-EINVAL); 426 427 struct ti_sci_info *info = dev_get_priv(sci_dev); 428 429 if (!info) 430 return ERR_PTR(-EINVAL); 431 432 struct ti_sci_handle *handle = &info->handle; 433 434 if (!handle) 435 return ERR_PTR(-EINVAL); 436 437 return handle; 438 } 439 440 /** 441 * ti_sci_get_handle() - Get the TI SCI handle for a device 442 * @dev: Pointer to device for which we want SCI handle 443 * 444 * Return: pointer to handle if successful, else EINVAL if invalid conditions 445 * are encountered. 446 */ 447 const struct ti_sci_handle *ti_sci_get_handle(struct udevice *dev) 448 { 449 if (!dev) 450 return ERR_PTR(-EINVAL); 451 452 struct udevice *sci_dev = dev_get_parent(dev); 453 454 return ti_sci_get_handle_from_sysfw(sci_dev); 455 } 456 457 /** 458 * ti_sci_get_by_phandle() - Get the TI SCI handle using DT phandle 459 * @dev: device node 460 * @propname: property name containing phandle on TISCI node 461 * 462 * Return: pointer to handle if successful, else appropriate error value. 463 */ 464 const struct ti_sci_handle *ti_sci_get_by_phandle(struct udevice *dev, 465 const char *property) 466 { 467 struct ti_sci_info *entry, *info = NULL; 468 u32 phandle, err; 469 ofnode node; 470 471 err = ofnode_read_u32(dev_ofnode(dev), property, &phandle); 472 if (err) 473 return ERR_PTR(err); 474 475 node = ofnode_get_by_phandle(phandle); 476 if (!ofnode_valid(node)) 477 return ERR_PTR(-EINVAL); 478 479 list_for_each_entry(entry, &ti_sci_list, list) 480 if (ofnode_equal(dev_ofnode(entry->dev), node)) { 481 info = entry; 482 break; 483 } 484 485 if (!info) 486 return ERR_PTR(-ENODEV); 487 488 return &info->handle; 489 } 490 491 /** 492 * ti_sci_of_to_info() - generate private data from device tree 493 * @dev: corresponding system controller interface device 494 * @info: pointer to driver specific private data 495 * 496 * Return: 0 if all goes good, else appropriate error message. 497 */ 498 static int ti_sci_of_to_info(struct udevice *dev, struct ti_sci_info *info) 499 { 500 int ret; 501 502 ret = mbox_get_by_name(dev, "tx", &info->chan_tx); 503 if (ret) { 504 dev_err(dev, "%s: Acquiring Tx channel failed. ret = %d\n", 505 __func__, ret); 506 return ret; 507 } 508 509 ret = mbox_get_by_name(dev, "rx", &info->chan_rx); 510 if (ret) { 511 dev_err(dev, "%s: Acquiring Rx channel failed. ret = %d\n", 512 __func__, ret); 513 return ret; 514 } 515 516 /* Notify channel is optional. Enable only if populated */ 517 ret = mbox_get_by_name(dev, "notify", &info->chan_notify); 518 if (ret) { 519 dev_dbg(dev, "%s: Acquiring notify channel failed. ret = %d\n", 520 __func__, ret); 521 } 522 523 info->host_id = dev_read_u32_default(dev, "ti,host-id", 524 info->desc->host_id); 525 526 info->is_secure = dev_read_bool(dev, "ti,secure-host"); 527 528 return 0; 529 } 530 531 /** 532 * ti_sci_probe() - Basic probe 533 * @dev: corresponding system controller interface device 534 * 535 * Return: 0 if all goes good, else appropriate error message. 536 */ 537 static int ti_sci_probe(struct udevice *dev) 538 { 539 struct ti_sci_info *info; 540 int ret; 541 542 debug("%s(dev=%p)\n", __func__, dev); 543 544 info = dev_get_priv(dev); 545 info->desc = (void *)dev_get_driver_data(dev); 546 547 ret = ti_sci_of_to_info(dev, info); 548 if (ret) { 549 dev_err(dev, "%s: Probe failed with error %d\n", __func__, ret); 550 return ret; 551 } 552 553 info->dev = dev; 554 info->seq = 0xA; 555 556 list_add_tail(&info->list, &ti_sci_list); 557 ti_sci_setup_ops(info); 558 559 ret = ti_sci_cmd_get_revision(&info->handle); 560 561 return ret; 562 } 563 564 /* Description for AM654 */ 565 static const struct ti_sci_desc ti_sci_sysfw_am654_desc = { 566 .host_id = 4, 567 .max_rx_timeout_us = 1000000, 568 .max_msg_size = 60, 569 }; 570 571 static const struct udevice_id ti_sci_ids[] = { 572 { 573 .compatible = "ti,k2g-sci", 574 .data = (ulong)&ti_sci_sysfw_am654_desc 575 }, 576 { /* Sentinel */ }, 577 }; 578 579 U_BOOT_DRIVER(ti_sci) = { 580 .name = "ti_sci", 581 .id = UCLASS_FIRMWARE, 582 .of_match = ti_sci_ids, 583 .probe = ti_sci_probe, 584 .priv_auto_alloc_size = sizeof(struct ti_sci_info), 585 }; 586