132cd2512SLokesh Vutla // SPDX-License-Identifier: GPL-2.0+ 232cd2512SLokesh Vutla /* 332cd2512SLokesh Vutla * Texas Instruments System Control Interface Protocol Driver 432cd2512SLokesh Vutla * Based on drivers/firmware/ti_sci.c from Linux. 532cd2512SLokesh Vutla * 632cd2512SLokesh Vutla * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/ 732cd2512SLokesh Vutla * Lokesh Vutla <lokeshvutla@ti.com> 832cd2512SLokesh Vutla */ 932cd2512SLokesh Vutla 1032cd2512SLokesh Vutla #include <common.h> 1132cd2512SLokesh Vutla #include <dm.h> 1232cd2512SLokesh Vutla #include <errno.h> 1332cd2512SLokesh Vutla #include <mailbox.h> 1432cd2512SLokesh Vutla #include <dm/device.h> 1532cd2512SLokesh Vutla #include <linux/err.h> 1632cd2512SLokesh Vutla #include <linux/soc/ti/k3-sec-proxy.h> 1732cd2512SLokesh Vutla #include <linux/soc/ti/ti_sci_protocol.h> 1832cd2512SLokesh Vutla 1932cd2512SLokesh Vutla #include "ti_sci.h" 2032cd2512SLokesh Vutla 2132cd2512SLokesh Vutla /* List of all TI SCI devices active in system */ 2232cd2512SLokesh Vutla static LIST_HEAD(ti_sci_list); 2332cd2512SLokesh Vutla 2432cd2512SLokesh Vutla /** 2532cd2512SLokesh Vutla * struct ti_sci_xfer - Structure representing a message flow 2632cd2512SLokesh Vutla * @tx_message: Transmit message 2732cd2512SLokesh Vutla * @rx_len: Receive message length 2832cd2512SLokesh Vutla */ 2932cd2512SLokesh Vutla struct ti_sci_xfer { 3032cd2512SLokesh Vutla struct k3_sec_proxy_msg tx_message; 3132cd2512SLokesh Vutla u8 rx_len; 3232cd2512SLokesh Vutla }; 3332cd2512SLokesh Vutla 3432cd2512SLokesh Vutla /** 3532cd2512SLokesh Vutla * struct ti_sci_desc - Description of SoC integration 3632cd2512SLokesh Vutla * @host_id: Host identifier representing the compute entity 3732cd2512SLokesh Vutla * @max_rx_timeout_us: Timeout for communication with SoC (in Microseconds) 3832cd2512SLokesh Vutla * @max_msg_size: Maximum size of data per message that can be handled. 3932cd2512SLokesh Vutla */ 4032cd2512SLokesh Vutla struct ti_sci_desc { 4132cd2512SLokesh Vutla u8 host_id; 4232cd2512SLokesh Vutla int max_rx_timeout_us; 4332cd2512SLokesh Vutla int max_msg_size; 4432cd2512SLokesh Vutla }; 4532cd2512SLokesh Vutla 4632cd2512SLokesh Vutla /** 4732cd2512SLokesh Vutla * struct ti_sci_info - Structure representing a TI SCI instance 4832cd2512SLokesh Vutla * @dev: Device pointer 4932cd2512SLokesh Vutla * @desc: SoC description for this instance 5032cd2512SLokesh Vutla * @handle: Instance of TI SCI handle to send to clients. 5132cd2512SLokesh Vutla * @chan_tx: Transmit mailbox channel 5232cd2512SLokesh Vutla * @chan_rx: Receive mailbox channel 5332cd2512SLokesh Vutla * @xfer: xfer info 5432cd2512SLokesh Vutla * @list: list head 5532cd2512SLokesh Vutla * @is_secure: Determines if the communication is through secure threads. 5632cd2512SLokesh Vutla * @host_id: Host identifier representing the compute entity 5732cd2512SLokesh Vutla * @seq: Seq id used for verification for tx and rx message. 5832cd2512SLokesh Vutla */ 5932cd2512SLokesh Vutla struct ti_sci_info { 6032cd2512SLokesh Vutla struct udevice *dev; 6132cd2512SLokesh Vutla const struct ti_sci_desc *desc; 6232cd2512SLokesh Vutla struct ti_sci_handle handle; 6332cd2512SLokesh Vutla struct mbox_chan chan_tx; 6432cd2512SLokesh Vutla struct mbox_chan chan_rx; 6532cd2512SLokesh Vutla struct mbox_chan chan_notify; 6632cd2512SLokesh Vutla struct ti_sci_xfer xfer; 6732cd2512SLokesh Vutla struct list_head list; 6832cd2512SLokesh Vutla bool is_secure; 6932cd2512SLokesh Vutla u8 host_id; 7032cd2512SLokesh Vutla u8 seq; 7132cd2512SLokesh Vutla }; 7232cd2512SLokesh Vutla 7332cd2512SLokesh Vutla #define handle_to_ti_sci_info(h) container_of(h, struct ti_sci_info, handle) 7432cd2512SLokesh Vutla 7532cd2512SLokesh Vutla /** 7632cd2512SLokesh Vutla * ti_sci_setup_one_xfer() - Setup one message type 7732cd2512SLokesh Vutla * @info: Pointer to SCI entity information 7832cd2512SLokesh Vutla * @msg_type: Message type 7932cd2512SLokesh Vutla * @msg_flags: Flag to set for the message 8032cd2512SLokesh Vutla * @buf: Buffer to be send to mailbox channel 8132cd2512SLokesh Vutla * @tx_message_size: transmit message size 8232cd2512SLokesh Vutla * @rx_message_size: receive message size 8332cd2512SLokesh Vutla * 8432cd2512SLokesh Vutla * Helper function which is used by various command functions that are 8532cd2512SLokesh Vutla * exposed to clients of this driver for allocating a message traffic event. 8632cd2512SLokesh Vutla * 8732cd2512SLokesh Vutla * Return: Corresponding ti_sci_xfer pointer if all went fine, 8832cd2512SLokesh Vutla * else appropriate error pointer. 8932cd2512SLokesh Vutla */ 9032cd2512SLokesh Vutla static struct ti_sci_xfer *ti_sci_setup_one_xfer(struct ti_sci_info *info, 9132cd2512SLokesh Vutla u16 msg_type, u32 msg_flags, 9232cd2512SLokesh Vutla u32 *buf, 9332cd2512SLokesh Vutla size_t tx_message_size, 9432cd2512SLokesh Vutla size_t rx_message_size) 9532cd2512SLokesh Vutla { 9632cd2512SLokesh Vutla struct ti_sci_xfer *xfer = &info->xfer; 9732cd2512SLokesh Vutla struct ti_sci_msg_hdr *hdr; 9832cd2512SLokesh Vutla 9932cd2512SLokesh Vutla /* Ensure we have sane transfer sizes */ 10032cd2512SLokesh Vutla if (rx_message_size > info->desc->max_msg_size || 10132cd2512SLokesh Vutla tx_message_size > info->desc->max_msg_size || 10232cd2512SLokesh Vutla rx_message_size < sizeof(*hdr) || tx_message_size < sizeof(*hdr)) 10332cd2512SLokesh Vutla return ERR_PTR(-ERANGE); 10432cd2512SLokesh Vutla 10532cd2512SLokesh Vutla info->seq = ~info->seq; 10632cd2512SLokesh Vutla xfer->tx_message.buf = buf; 10732cd2512SLokesh Vutla xfer->tx_message.len = tx_message_size; 10832cd2512SLokesh Vutla xfer->rx_len = (u8)rx_message_size; 10932cd2512SLokesh Vutla 11032cd2512SLokesh Vutla hdr = (struct ti_sci_msg_hdr *)buf; 11132cd2512SLokesh Vutla hdr->seq = info->seq; 11232cd2512SLokesh Vutla hdr->type = msg_type; 11332cd2512SLokesh Vutla hdr->host = info->host_id; 11432cd2512SLokesh Vutla hdr->flags = msg_flags; 11532cd2512SLokesh Vutla 11632cd2512SLokesh Vutla return xfer; 11732cd2512SLokesh Vutla } 11832cd2512SLokesh Vutla 11932cd2512SLokesh Vutla /** 12032cd2512SLokesh Vutla * ti_sci_get_response() - Receive response from mailbox channel 12132cd2512SLokesh Vutla * @info: Pointer to SCI entity information 12232cd2512SLokesh Vutla * @xfer: Transfer to initiate and wait for response 12332cd2512SLokesh Vutla * @chan: Channel to receive the response 12432cd2512SLokesh Vutla * 12532cd2512SLokesh Vutla * Return: -ETIMEDOUT in case of no response, if transmit error, 12632cd2512SLokesh Vutla * return corresponding error, else if all goes well, 12732cd2512SLokesh Vutla * return 0. 12832cd2512SLokesh Vutla */ 12932cd2512SLokesh Vutla static inline int ti_sci_get_response(struct ti_sci_info *info, 13032cd2512SLokesh Vutla struct ti_sci_xfer *xfer, 13132cd2512SLokesh Vutla struct mbox_chan *chan) 13232cd2512SLokesh Vutla { 13332cd2512SLokesh Vutla struct k3_sec_proxy_msg *msg = &xfer->tx_message; 13432cd2512SLokesh Vutla struct ti_sci_secure_msg_hdr *secure_hdr; 13532cd2512SLokesh Vutla struct ti_sci_msg_hdr *hdr; 13632cd2512SLokesh Vutla int ret; 13732cd2512SLokesh Vutla 13832cd2512SLokesh Vutla /* Receive the response */ 13932cd2512SLokesh Vutla ret = mbox_recv(chan, msg, info->desc->max_rx_timeout_us); 14032cd2512SLokesh Vutla if (ret) { 14132cd2512SLokesh Vutla dev_err(info->dev, "%s: Message receive failed. ret = %d\n", 14232cd2512SLokesh Vutla __func__, ret); 14332cd2512SLokesh Vutla return ret; 14432cd2512SLokesh Vutla } 14532cd2512SLokesh Vutla 14632cd2512SLokesh Vutla /* ToDo: Verify checksum */ 14732cd2512SLokesh Vutla if (info->is_secure) { 14832cd2512SLokesh Vutla secure_hdr = (struct ti_sci_secure_msg_hdr *)msg->buf; 14932cd2512SLokesh Vutla msg->buf = (u32 *)((void *)msg->buf + sizeof(*secure_hdr)); 15032cd2512SLokesh Vutla } 15132cd2512SLokesh Vutla 15232cd2512SLokesh Vutla /* msg is updated by mailbox driver */ 15332cd2512SLokesh Vutla hdr = (struct ti_sci_msg_hdr *)msg->buf; 15432cd2512SLokesh Vutla 15532cd2512SLokesh Vutla /* Sanity check for message response */ 15632cd2512SLokesh Vutla if (hdr->seq != info->seq) { 15732cd2512SLokesh Vutla dev_dbg(info->dev, "%s: Message for %d is not expected\n", 15832cd2512SLokesh Vutla __func__, hdr->seq); 15932cd2512SLokesh Vutla return ret; 16032cd2512SLokesh Vutla } 16132cd2512SLokesh Vutla 16232cd2512SLokesh Vutla if (msg->len > info->desc->max_msg_size) { 16332cd2512SLokesh Vutla dev_err(info->dev, "%s: Unable to handle %zu xfer (max %d)\n", 16432cd2512SLokesh Vutla __func__, msg->len, info->desc->max_msg_size); 16532cd2512SLokesh Vutla return -EINVAL; 16632cd2512SLokesh Vutla } 16732cd2512SLokesh Vutla 16832cd2512SLokesh Vutla if (msg->len < xfer->rx_len) { 16932cd2512SLokesh Vutla dev_err(info->dev, "%s: Recv xfer %zu < expected %d length\n", 17032cd2512SLokesh Vutla __func__, msg->len, xfer->rx_len); 17132cd2512SLokesh Vutla } 17232cd2512SLokesh Vutla 17332cd2512SLokesh Vutla return ret; 17432cd2512SLokesh Vutla } 17532cd2512SLokesh Vutla 17632cd2512SLokesh Vutla /** 17732cd2512SLokesh Vutla * ti_sci_do_xfer() - Do one transfer 17832cd2512SLokesh Vutla * @info: Pointer to SCI entity information 17932cd2512SLokesh Vutla * @xfer: Transfer to initiate and wait for response 18032cd2512SLokesh Vutla * 18132cd2512SLokesh Vutla * Return: 0 if all went fine, else return appropriate error. 18232cd2512SLokesh Vutla */ 18332cd2512SLokesh Vutla static inline int ti_sci_do_xfer(struct ti_sci_info *info, 18432cd2512SLokesh Vutla struct ti_sci_xfer *xfer) 18532cd2512SLokesh Vutla { 18632cd2512SLokesh Vutla struct k3_sec_proxy_msg *msg = &xfer->tx_message; 18732cd2512SLokesh Vutla u8 secure_buf[info->desc->max_msg_size]; 18832cd2512SLokesh Vutla struct ti_sci_secure_msg_hdr secure_hdr; 18932cd2512SLokesh Vutla int ret; 19032cd2512SLokesh Vutla 19132cd2512SLokesh Vutla if (info->is_secure) { 19232cd2512SLokesh Vutla /* ToDo: get checksum of the entire message */ 19332cd2512SLokesh Vutla secure_hdr.checksum = 0; 19432cd2512SLokesh Vutla secure_hdr.reserved = 0; 19532cd2512SLokesh Vutla memcpy(&secure_buf[sizeof(secure_hdr)], xfer->tx_message.buf, 19632cd2512SLokesh Vutla xfer->tx_message.len); 19732cd2512SLokesh Vutla 19832cd2512SLokesh Vutla xfer->tx_message.buf = (u32 *)secure_buf; 19932cd2512SLokesh Vutla xfer->tx_message.len += sizeof(secure_hdr); 20032cd2512SLokesh Vutla xfer->rx_len += sizeof(secure_hdr); 20132cd2512SLokesh Vutla } 20232cd2512SLokesh Vutla 20332cd2512SLokesh Vutla /* Send the message */ 20432cd2512SLokesh Vutla ret = mbox_send(&info->chan_tx, msg); 20532cd2512SLokesh Vutla if (ret) { 20632cd2512SLokesh Vutla dev_err(info->dev, "%s: Message sending failed. ret = %d\n", 20732cd2512SLokesh Vutla __func__, ret); 20832cd2512SLokesh Vutla return ret; 20932cd2512SLokesh Vutla } 21032cd2512SLokesh Vutla 21132cd2512SLokesh Vutla return ti_sci_get_response(info, xfer, &info->chan_rx); 21232cd2512SLokesh Vutla } 21332cd2512SLokesh Vutla 21432cd2512SLokesh Vutla /** 21532cd2512SLokesh Vutla * ti_sci_cmd_get_revision() - command to get the revision of the SCI entity 21632cd2512SLokesh Vutla * @handle: pointer to TI SCI handle 21732cd2512SLokesh Vutla * 21832cd2512SLokesh Vutla * Updates the SCI information in the internal data structure. 21932cd2512SLokesh Vutla * 22032cd2512SLokesh Vutla * Return: 0 if all went fine, else return appropriate error. 22132cd2512SLokesh Vutla */ 22232cd2512SLokesh Vutla static int ti_sci_cmd_get_revision(struct ti_sci_handle *handle) 22332cd2512SLokesh Vutla { 22432cd2512SLokesh Vutla struct ti_sci_msg_resp_version *rev_info; 22532cd2512SLokesh Vutla struct ti_sci_version_info *ver; 22632cd2512SLokesh Vutla struct ti_sci_msg_hdr hdr; 22732cd2512SLokesh Vutla struct ti_sci_info *info; 22832cd2512SLokesh Vutla struct ti_sci_xfer *xfer; 22932cd2512SLokesh Vutla int ret; 23032cd2512SLokesh Vutla 23132cd2512SLokesh Vutla if (IS_ERR(handle)) 23232cd2512SLokesh Vutla return PTR_ERR(handle); 23332cd2512SLokesh Vutla if (!handle) 23432cd2512SLokesh Vutla return -EINVAL; 23532cd2512SLokesh Vutla 23632cd2512SLokesh Vutla info = handle_to_ti_sci_info(handle); 23732cd2512SLokesh Vutla 23832cd2512SLokesh Vutla xfer = ti_sci_setup_one_xfer(info, TI_SCI_MSG_VERSION, 0x0, 23932cd2512SLokesh Vutla (u32 *)&hdr, sizeof(struct ti_sci_msg_hdr), 24032cd2512SLokesh Vutla sizeof(*rev_info)); 24132cd2512SLokesh Vutla if (IS_ERR(xfer)) { 24232cd2512SLokesh Vutla ret = PTR_ERR(xfer); 24332cd2512SLokesh Vutla dev_err(info->dev, "Message alloc failed(%d)\n", ret); 24432cd2512SLokesh Vutla return ret; 24532cd2512SLokesh Vutla } 24632cd2512SLokesh Vutla 24732cd2512SLokesh Vutla ret = ti_sci_do_xfer(info, xfer); 24832cd2512SLokesh Vutla if (ret) { 24932cd2512SLokesh Vutla dev_err(info->dev, "Mbox communication fail %d\n", ret); 25032cd2512SLokesh Vutla return ret; 25132cd2512SLokesh Vutla } 25232cd2512SLokesh Vutla 25332cd2512SLokesh Vutla rev_info = (struct ti_sci_msg_resp_version *)xfer->tx_message.buf; 25432cd2512SLokesh Vutla 25532cd2512SLokesh Vutla ver = &handle->version; 25632cd2512SLokesh Vutla ver->abi_major = rev_info->abi_major; 25732cd2512SLokesh Vutla ver->abi_minor = rev_info->abi_minor; 25832cd2512SLokesh Vutla ver->firmware_revision = rev_info->firmware_revision; 25932cd2512SLokesh Vutla strncpy(ver->firmware_description, rev_info->firmware_description, 26032cd2512SLokesh Vutla sizeof(ver->firmware_description)); 26132cd2512SLokesh Vutla 26232cd2512SLokesh Vutla return 0; 26332cd2512SLokesh Vutla } 26432cd2512SLokesh Vutla 26532cd2512SLokesh Vutla /** 26632cd2512SLokesh Vutla * ti_sci_is_response_ack() - Generic ACK/NACK message checkup 26732cd2512SLokesh Vutla * @r: pointer to response buffer 26832cd2512SLokesh Vutla * 26932cd2512SLokesh Vutla * Return: true if the response was an ACK, else returns false. 27032cd2512SLokesh Vutla */ 27132cd2512SLokesh Vutla static inline bool ti_sci_is_response_ack(void *r) 27232cd2512SLokesh Vutla { 27332cd2512SLokesh Vutla struct ti_sci_msg_hdr *hdr = r; 27432cd2512SLokesh Vutla 27532cd2512SLokesh Vutla return hdr->flags & TI_SCI_FLAG_RESP_GENERIC_ACK ? true : false; 27632cd2512SLokesh Vutla } 27732cd2512SLokesh Vutla 27832cd2512SLokesh Vutla /** 279*dcfc52adSAndreas Dannenberg * cmd_set_board_config_using_msg() - Common command to send board configuration 280*dcfc52adSAndreas Dannenberg * message 281*dcfc52adSAndreas Dannenberg * @handle: pointer to TI SCI handle 282*dcfc52adSAndreas Dannenberg * @msg_type: One of the TISCI message types to set board configuration 283*dcfc52adSAndreas Dannenberg * @addr: Address where the board config structure is located 284*dcfc52adSAndreas Dannenberg * @size: Size of the board config structure 285*dcfc52adSAndreas Dannenberg * 286*dcfc52adSAndreas Dannenberg * Return: 0 if all went well, else returns appropriate error value. 287*dcfc52adSAndreas Dannenberg */ 288*dcfc52adSAndreas Dannenberg static int cmd_set_board_config_using_msg(const struct ti_sci_handle *handle, 289*dcfc52adSAndreas Dannenberg u16 msg_type, u64 addr, u32 size) 290*dcfc52adSAndreas Dannenberg { 291*dcfc52adSAndreas Dannenberg struct ti_sci_msg_board_config req; 292*dcfc52adSAndreas Dannenberg struct ti_sci_msg_hdr *resp; 293*dcfc52adSAndreas Dannenberg struct ti_sci_info *info; 294*dcfc52adSAndreas Dannenberg struct ti_sci_xfer *xfer; 295*dcfc52adSAndreas Dannenberg int ret = 0; 296*dcfc52adSAndreas Dannenberg 297*dcfc52adSAndreas Dannenberg if (IS_ERR(handle)) 298*dcfc52adSAndreas Dannenberg return PTR_ERR(handle); 299*dcfc52adSAndreas Dannenberg if (!handle) 300*dcfc52adSAndreas Dannenberg return -EINVAL; 301*dcfc52adSAndreas Dannenberg 302*dcfc52adSAndreas Dannenberg info = handle_to_ti_sci_info(handle); 303*dcfc52adSAndreas Dannenberg 304*dcfc52adSAndreas Dannenberg xfer = ti_sci_setup_one_xfer(info, msg_type, 305*dcfc52adSAndreas Dannenberg TI_SCI_FLAG_REQ_ACK_ON_PROCESSED, 306*dcfc52adSAndreas Dannenberg (u32 *)&req, sizeof(req), sizeof(*resp)); 307*dcfc52adSAndreas Dannenberg if (IS_ERR(xfer)) { 308*dcfc52adSAndreas Dannenberg ret = PTR_ERR(xfer); 309*dcfc52adSAndreas Dannenberg dev_err(info->dev, "Message alloc failed(%d)\n", ret); 310*dcfc52adSAndreas Dannenberg return ret; 311*dcfc52adSAndreas Dannenberg } 312*dcfc52adSAndreas Dannenberg req.boardcfgp_high = (addr >> 32) & 0xffffffff; 313*dcfc52adSAndreas Dannenberg req.boardcfgp_low = addr & 0xffffffff; 314*dcfc52adSAndreas Dannenberg req.boardcfg_size = size; 315*dcfc52adSAndreas Dannenberg 316*dcfc52adSAndreas Dannenberg ret = ti_sci_do_xfer(info, xfer); 317*dcfc52adSAndreas Dannenberg if (ret) { 318*dcfc52adSAndreas Dannenberg dev_err(info->dev, "Mbox send fail %d\n", ret); 319*dcfc52adSAndreas Dannenberg return ret; 320*dcfc52adSAndreas Dannenberg } 321*dcfc52adSAndreas Dannenberg 322*dcfc52adSAndreas Dannenberg resp = (struct ti_sci_msg_hdr *)xfer->tx_message.buf; 323*dcfc52adSAndreas Dannenberg 324*dcfc52adSAndreas Dannenberg if (!ti_sci_is_response_ack(resp)) 325*dcfc52adSAndreas Dannenberg return -ENODEV; 326*dcfc52adSAndreas Dannenberg 327*dcfc52adSAndreas Dannenberg return ret; 328*dcfc52adSAndreas Dannenberg } 329*dcfc52adSAndreas Dannenberg 330*dcfc52adSAndreas Dannenberg /** 331*dcfc52adSAndreas Dannenberg * ti_sci_cmd_set_board_config() - Command to send board configuration message 332*dcfc52adSAndreas Dannenberg * @handle: pointer to TI SCI handle 333*dcfc52adSAndreas Dannenberg * @addr: Address where the board config structure is located 334*dcfc52adSAndreas Dannenberg * @size: Size of the board config structure 335*dcfc52adSAndreas Dannenberg * 336*dcfc52adSAndreas Dannenberg * Return: 0 if all went well, else returns appropriate error value. 337*dcfc52adSAndreas Dannenberg */ 338*dcfc52adSAndreas Dannenberg static int ti_sci_cmd_set_board_config(const struct ti_sci_handle *handle, 339*dcfc52adSAndreas Dannenberg u64 addr, u32 size) 340*dcfc52adSAndreas Dannenberg { 341*dcfc52adSAndreas Dannenberg return cmd_set_board_config_using_msg(handle, 342*dcfc52adSAndreas Dannenberg TI_SCI_MSG_BOARD_CONFIG, 343*dcfc52adSAndreas Dannenberg addr, size); 344*dcfc52adSAndreas Dannenberg } 345*dcfc52adSAndreas Dannenberg 346*dcfc52adSAndreas Dannenberg /** 347*dcfc52adSAndreas Dannenberg * ti_sci_cmd_set_board_config_rm() - Command to send board resource 348*dcfc52adSAndreas Dannenberg * management configuration 349*dcfc52adSAndreas Dannenberg * @handle: pointer to TI SCI handle 350*dcfc52adSAndreas Dannenberg * @addr: Address where the board RM config structure is located 351*dcfc52adSAndreas Dannenberg * @size: Size of the RM config structure 352*dcfc52adSAndreas Dannenberg * 353*dcfc52adSAndreas Dannenberg * Return: 0 if all went well, else returns appropriate error value. 354*dcfc52adSAndreas Dannenberg */ 355*dcfc52adSAndreas Dannenberg static 356*dcfc52adSAndreas Dannenberg int ti_sci_cmd_set_board_config_rm(const struct ti_sci_handle *handle, 357*dcfc52adSAndreas Dannenberg u64 addr, u32 size) 358*dcfc52adSAndreas Dannenberg { 359*dcfc52adSAndreas Dannenberg return cmd_set_board_config_using_msg(handle, 360*dcfc52adSAndreas Dannenberg TI_SCI_MSG_BOARD_CONFIG_RM, 361*dcfc52adSAndreas Dannenberg addr, size); 362*dcfc52adSAndreas Dannenberg } 363*dcfc52adSAndreas Dannenberg 364*dcfc52adSAndreas Dannenberg /** 365*dcfc52adSAndreas Dannenberg * ti_sci_cmd_set_board_config_security() - Command to send board security 366*dcfc52adSAndreas Dannenberg * configuration message 367*dcfc52adSAndreas Dannenberg * @handle: pointer to TI SCI handle 368*dcfc52adSAndreas Dannenberg * @addr: Address where the board security config structure is located 369*dcfc52adSAndreas Dannenberg * @size: Size of the security config structure 370*dcfc52adSAndreas Dannenberg * 371*dcfc52adSAndreas Dannenberg * Return: 0 if all went well, else returns appropriate error value. 372*dcfc52adSAndreas Dannenberg */ 373*dcfc52adSAndreas Dannenberg static 374*dcfc52adSAndreas Dannenberg int ti_sci_cmd_set_board_config_security(const struct ti_sci_handle *handle, 375*dcfc52adSAndreas Dannenberg u64 addr, u32 size) 376*dcfc52adSAndreas Dannenberg { 377*dcfc52adSAndreas Dannenberg return cmd_set_board_config_using_msg(handle, 378*dcfc52adSAndreas Dannenberg TI_SCI_MSG_BOARD_CONFIG_SECURITY, 379*dcfc52adSAndreas Dannenberg addr, size); 380*dcfc52adSAndreas Dannenberg } 381*dcfc52adSAndreas Dannenberg 382*dcfc52adSAndreas Dannenberg /** 383*dcfc52adSAndreas Dannenberg * ti_sci_cmd_set_board_config_pm() - Command to send board power and clock 384*dcfc52adSAndreas Dannenberg * configuration message 385*dcfc52adSAndreas Dannenberg * @handle: pointer to TI SCI handle 386*dcfc52adSAndreas Dannenberg * @addr: Address where the board PM config structure is located 387*dcfc52adSAndreas Dannenberg * @size: Size of the PM config structure 388*dcfc52adSAndreas Dannenberg * 389*dcfc52adSAndreas Dannenberg * Return: 0 if all went well, else returns appropriate error value. 390*dcfc52adSAndreas Dannenberg */ 391*dcfc52adSAndreas Dannenberg static int ti_sci_cmd_set_board_config_pm(const struct ti_sci_handle *handle, 392*dcfc52adSAndreas Dannenberg u64 addr, u32 size) 393*dcfc52adSAndreas Dannenberg { 394*dcfc52adSAndreas Dannenberg return cmd_set_board_config_using_msg(handle, 395*dcfc52adSAndreas Dannenberg TI_SCI_MSG_BOARD_CONFIG_PM, 396*dcfc52adSAndreas Dannenberg addr, size); 397*dcfc52adSAndreas Dannenberg } 398*dcfc52adSAndreas Dannenberg 399*dcfc52adSAndreas Dannenberg /* 400*dcfc52adSAndreas Dannenberg * ti_sci_setup_ops() - Setup the operations structures 401*dcfc52adSAndreas Dannenberg * @info: pointer to TISCI pointer 402*dcfc52adSAndreas Dannenberg */ 403*dcfc52adSAndreas Dannenberg static void ti_sci_setup_ops(struct ti_sci_info *info) 404*dcfc52adSAndreas Dannenberg { 405*dcfc52adSAndreas Dannenberg struct ti_sci_ops *ops = &info->handle.ops; 406*dcfc52adSAndreas Dannenberg struct ti_sci_board_ops *bops = &ops->board_ops; 407*dcfc52adSAndreas Dannenberg 408*dcfc52adSAndreas Dannenberg bops->board_config = ti_sci_cmd_set_board_config; 409*dcfc52adSAndreas Dannenberg bops->board_config_rm = ti_sci_cmd_set_board_config_rm; 410*dcfc52adSAndreas Dannenberg bops->board_config_security = ti_sci_cmd_set_board_config_security; 411*dcfc52adSAndreas Dannenberg bops->board_config_pm = ti_sci_cmd_set_board_config_pm; 412*dcfc52adSAndreas Dannenberg } 413*dcfc52adSAndreas Dannenberg 414*dcfc52adSAndreas Dannenberg /** 41532cd2512SLokesh Vutla * ti_sci_get_handle_from_sysfw() - Get the TI SCI handle of the SYSFW 41632cd2512SLokesh Vutla * @dev: Pointer to the SYSFW device 41732cd2512SLokesh Vutla * 41832cd2512SLokesh Vutla * Return: pointer to handle if successful, else EINVAL if invalid conditions 41932cd2512SLokesh Vutla * are encountered. 42032cd2512SLokesh Vutla */ 42132cd2512SLokesh Vutla const 42232cd2512SLokesh Vutla struct ti_sci_handle *ti_sci_get_handle_from_sysfw(struct udevice *sci_dev) 42332cd2512SLokesh Vutla { 42432cd2512SLokesh Vutla if (!sci_dev) 42532cd2512SLokesh Vutla return ERR_PTR(-EINVAL); 42632cd2512SLokesh Vutla 42732cd2512SLokesh Vutla struct ti_sci_info *info = dev_get_priv(sci_dev); 42832cd2512SLokesh Vutla 42932cd2512SLokesh Vutla if (!info) 43032cd2512SLokesh Vutla return ERR_PTR(-EINVAL); 43132cd2512SLokesh Vutla 43232cd2512SLokesh Vutla struct ti_sci_handle *handle = &info->handle; 43332cd2512SLokesh Vutla 43432cd2512SLokesh Vutla if (!handle) 43532cd2512SLokesh Vutla return ERR_PTR(-EINVAL); 43632cd2512SLokesh Vutla 43732cd2512SLokesh Vutla return handle; 43832cd2512SLokesh Vutla } 43932cd2512SLokesh Vutla 44032cd2512SLokesh Vutla /** 44132cd2512SLokesh Vutla * ti_sci_get_handle() - Get the TI SCI handle for a device 44232cd2512SLokesh Vutla * @dev: Pointer to device for which we want SCI handle 44332cd2512SLokesh Vutla * 44432cd2512SLokesh Vutla * Return: pointer to handle if successful, else EINVAL if invalid conditions 44532cd2512SLokesh Vutla * are encountered. 44632cd2512SLokesh Vutla */ 44732cd2512SLokesh Vutla const struct ti_sci_handle *ti_sci_get_handle(struct udevice *dev) 44832cd2512SLokesh Vutla { 44932cd2512SLokesh Vutla if (!dev) 45032cd2512SLokesh Vutla return ERR_PTR(-EINVAL); 45132cd2512SLokesh Vutla 45232cd2512SLokesh Vutla struct udevice *sci_dev = dev_get_parent(dev); 45332cd2512SLokesh Vutla 45432cd2512SLokesh Vutla return ti_sci_get_handle_from_sysfw(sci_dev); 45532cd2512SLokesh Vutla } 45632cd2512SLokesh Vutla 45732cd2512SLokesh Vutla /** 45832cd2512SLokesh Vutla * ti_sci_get_by_phandle() - Get the TI SCI handle using DT phandle 45932cd2512SLokesh Vutla * @dev: device node 46032cd2512SLokesh Vutla * @propname: property name containing phandle on TISCI node 46132cd2512SLokesh Vutla * 46232cd2512SLokesh Vutla * Return: pointer to handle if successful, else appropriate error value. 46332cd2512SLokesh Vutla */ 46432cd2512SLokesh Vutla const struct ti_sci_handle *ti_sci_get_by_phandle(struct udevice *dev, 46532cd2512SLokesh Vutla const char *property) 46632cd2512SLokesh Vutla { 46732cd2512SLokesh Vutla struct ti_sci_info *entry, *info = NULL; 46832cd2512SLokesh Vutla u32 phandle, err; 46932cd2512SLokesh Vutla ofnode node; 47032cd2512SLokesh Vutla 47132cd2512SLokesh Vutla err = ofnode_read_u32(dev_ofnode(dev), property, &phandle); 47232cd2512SLokesh Vutla if (err) 47332cd2512SLokesh Vutla return ERR_PTR(err); 47432cd2512SLokesh Vutla 47532cd2512SLokesh Vutla node = ofnode_get_by_phandle(phandle); 47632cd2512SLokesh Vutla if (!ofnode_valid(node)) 47732cd2512SLokesh Vutla return ERR_PTR(-EINVAL); 47832cd2512SLokesh Vutla 47932cd2512SLokesh Vutla list_for_each_entry(entry, &ti_sci_list, list) 48032cd2512SLokesh Vutla if (ofnode_equal(dev_ofnode(entry->dev), node)) { 48132cd2512SLokesh Vutla info = entry; 48232cd2512SLokesh Vutla break; 48332cd2512SLokesh Vutla } 48432cd2512SLokesh Vutla 48532cd2512SLokesh Vutla if (!info) 48632cd2512SLokesh Vutla return ERR_PTR(-ENODEV); 48732cd2512SLokesh Vutla 48832cd2512SLokesh Vutla return &info->handle; 48932cd2512SLokesh Vutla } 49032cd2512SLokesh Vutla 49132cd2512SLokesh Vutla /** 49232cd2512SLokesh Vutla * ti_sci_of_to_info() - generate private data from device tree 49332cd2512SLokesh Vutla * @dev: corresponding system controller interface device 49432cd2512SLokesh Vutla * @info: pointer to driver specific private data 49532cd2512SLokesh Vutla * 49632cd2512SLokesh Vutla * Return: 0 if all goes good, else appropriate error message. 49732cd2512SLokesh Vutla */ 49832cd2512SLokesh Vutla static int ti_sci_of_to_info(struct udevice *dev, struct ti_sci_info *info) 49932cd2512SLokesh Vutla { 50032cd2512SLokesh Vutla int ret; 50132cd2512SLokesh Vutla 50232cd2512SLokesh Vutla ret = mbox_get_by_name(dev, "tx", &info->chan_tx); 50332cd2512SLokesh Vutla if (ret) { 50432cd2512SLokesh Vutla dev_err(dev, "%s: Acquiring Tx channel failed. ret = %d\n", 50532cd2512SLokesh Vutla __func__, ret); 50632cd2512SLokesh Vutla return ret; 50732cd2512SLokesh Vutla } 50832cd2512SLokesh Vutla 50932cd2512SLokesh Vutla ret = mbox_get_by_name(dev, "rx", &info->chan_rx); 51032cd2512SLokesh Vutla if (ret) { 51132cd2512SLokesh Vutla dev_err(dev, "%s: Acquiring Rx channel failed. ret = %d\n", 51232cd2512SLokesh Vutla __func__, ret); 51332cd2512SLokesh Vutla return ret; 51432cd2512SLokesh Vutla } 51532cd2512SLokesh Vutla 51632cd2512SLokesh Vutla /* Notify channel is optional. Enable only if populated */ 51732cd2512SLokesh Vutla ret = mbox_get_by_name(dev, "notify", &info->chan_notify); 51832cd2512SLokesh Vutla if (ret) { 51932cd2512SLokesh Vutla dev_dbg(dev, "%s: Acquiring notify channel failed. ret = %d\n", 52032cd2512SLokesh Vutla __func__, ret); 52132cd2512SLokesh Vutla } 52232cd2512SLokesh Vutla 52332cd2512SLokesh Vutla info->host_id = dev_read_u32_default(dev, "ti,host-id", 52432cd2512SLokesh Vutla info->desc->host_id); 52532cd2512SLokesh Vutla 52632cd2512SLokesh Vutla info->is_secure = dev_read_bool(dev, "ti,secure-host"); 52732cd2512SLokesh Vutla 52832cd2512SLokesh Vutla return 0; 52932cd2512SLokesh Vutla } 53032cd2512SLokesh Vutla 53132cd2512SLokesh Vutla /** 53232cd2512SLokesh Vutla * ti_sci_probe() - Basic probe 53332cd2512SLokesh Vutla * @dev: corresponding system controller interface device 53432cd2512SLokesh Vutla * 53532cd2512SLokesh Vutla * Return: 0 if all goes good, else appropriate error message. 53632cd2512SLokesh Vutla */ 53732cd2512SLokesh Vutla static int ti_sci_probe(struct udevice *dev) 53832cd2512SLokesh Vutla { 53932cd2512SLokesh Vutla struct ti_sci_info *info; 54032cd2512SLokesh Vutla int ret; 54132cd2512SLokesh Vutla 54232cd2512SLokesh Vutla debug("%s(dev=%p)\n", __func__, dev); 54332cd2512SLokesh Vutla 54432cd2512SLokesh Vutla info = dev_get_priv(dev); 54532cd2512SLokesh Vutla info->desc = (void *)dev_get_driver_data(dev); 54632cd2512SLokesh Vutla 54732cd2512SLokesh Vutla ret = ti_sci_of_to_info(dev, info); 54832cd2512SLokesh Vutla if (ret) { 54932cd2512SLokesh Vutla dev_err(dev, "%s: Probe failed with error %d\n", __func__, ret); 55032cd2512SLokesh Vutla return ret; 55132cd2512SLokesh Vutla } 55232cd2512SLokesh Vutla 55332cd2512SLokesh Vutla info->dev = dev; 55432cd2512SLokesh Vutla info->seq = 0xA; 55532cd2512SLokesh Vutla 55632cd2512SLokesh Vutla list_add_tail(&info->list, &ti_sci_list); 557*dcfc52adSAndreas Dannenberg ti_sci_setup_ops(info); 55832cd2512SLokesh Vutla 55932cd2512SLokesh Vutla ret = ti_sci_cmd_get_revision(&info->handle); 56032cd2512SLokesh Vutla 56132cd2512SLokesh Vutla return ret; 56232cd2512SLokesh Vutla } 56332cd2512SLokesh Vutla 56432cd2512SLokesh Vutla /* Description for AM654 */ 56532cd2512SLokesh Vutla static const struct ti_sci_desc ti_sci_sysfw_am654_desc = { 56632cd2512SLokesh Vutla .host_id = 4, 56732cd2512SLokesh Vutla .max_rx_timeout_us = 1000000, 56832cd2512SLokesh Vutla .max_msg_size = 60, 56932cd2512SLokesh Vutla }; 57032cd2512SLokesh Vutla 57132cd2512SLokesh Vutla static const struct udevice_id ti_sci_ids[] = { 57232cd2512SLokesh Vutla { 57332cd2512SLokesh Vutla .compatible = "ti,k2g-sci", 57432cd2512SLokesh Vutla .data = (ulong)&ti_sci_sysfw_am654_desc 57532cd2512SLokesh Vutla }, 57632cd2512SLokesh Vutla { /* Sentinel */ }, 57732cd2512SLokesh Vutla }; 57832cd2512SLokesh Vutla 57932cd2512SLokesh Vutla U_BOOT_DRIVER(ti_sci) = { 58032cd2512SLokesh Vutla .name = "ti_sci", 58132cd2512SLokesh Vutla .id = UCLASS_FIRMWARE, 58232cd2512SLokesh Vutla .of_match = ti_sci_ids, 58332cd2512SLokesh Vutla .probe = ti_sci_probe, 58432cd2512SLokesh Vutla .priv_auto_alloc_size = sizeof(struct ti_sci_info), 58532cd2512SLokesh Vutla }; 586