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 /** 279dcfc52adSAndreas Dannenberg * cmd_set_board_config_using_msg() - Common command to send board configuration 280dcfc52adSAndreas Dannenberg * message 281dcfc52adSAndreas Dannenberg * @handle: pointer to TI SCI handle 282dcfc52adSAndreas Dannenberg * @msg_type: One of the TISCI message types to set board configuration 283dcfc52adSAndreas Dannenberg * @addr: Address where the board config structure is located 284dcfc52adSAndreas Dannenberg * @size: Size of the board config structure 285dcfc52adSAndreas Dannenberg * 286dcfc52adSAndreas Dannenberg * Return: 0 if all went well, else returns appropriate error value. 287dcfc52adSAndreas Dannenberg */ 288dcfc52adSAndreas Dannenberg static int cmd_set_board_config_using_msg(const struct ti_sci_handle *handle, 289dcfc52adSAndreas Dannenberg u16 msg_type, u64 addr, u32 size) 290dcfc52adSAndreas Dannenberg { 291dcfc52adSAndreas Dannenberg struct ti_sci_msg_board_config req; 292dcfc52adSAndreas Dannenberg struct ti_sci_msg_hdr *resp; 293dcfc52adSAndreas Dannenberg struct ti_sci_info *info; 294dcfc52adSAndreas Dannenberg struct ti_sci_xfer *xfer; 295dcfc52adSAndreas Dannenberg int ret = 0; 296dcfc52adSAndreas Dannenberg 297dcfc52adSAndreas Dannenberg if (IS_ERR(handle)) 298dcfc52adSAndreas Dannenberg return PTR_ERR(handle); 299dcfc52adSAndreas Dannenberg if (!handle) 300dcfc52adSAndreas Dannenberg return -EINVAL; 301dcfc52adSAndreas Dannenberg 302dcfc52adSAndreas Dannenberg info = handle_to_ti_sci_info(handle); 303dcfc52adSAndreas Dannenberg 304dcfc52adSAndreas Dannenberg xfer = ti_sci_setup_one_xfer(info, msg_type, 305dcfc52adSAndreas Dannenberg TI_SCI_FLAG_REQ_ACK_ON_PROCESSED, 306dcfc52adSAndreas Dannenberg (u32 *)&req, sizeof(req), sizeof(*resp)); 307dcfc52adSAndreas Dannenberg if (IS_ERR(xfer)) { 308dcfc52adSAndreas Dannenberg ret = PTR_ERR(xfer); 309dcfc52adSAndreas Dannenberg dev_err(info->dev, "Message alloc failed(%d)\n", ret); 310dcfc52adSAndreas Dannenberg return ret; 311dcfc52adSAndreas Dannenberg } 312dcfc52adSAndreas Dannenberg req.boardcfgp_high = (addr >> 32) & 0xffffffff; 313dcfc52adSAndreas Dannenberg req.boardcfgp_low = addr & 0xffffffff; 314dcfc52adSAndreas Dannenberg req.boardcfg_size = size; 315dcfc52adSAndreas Dannenberg 316dcfc52adSAndreas Dannenberg ret = ti_sci_do_xfer(info, xfer); 317dcfc52adSAndreas Dannenberg if (ret) { 318dcfc52adSAndreas Dannenberg dev_err(info->dev, "Mbox send fail %d\n", ret); 319dcfc52adSAndreas Dannenberg return ret; 320dcfc52adSAndreas Dannenberg } 321dcfc52adSAndreas Dannenberg 322dcfc52adSAndreas Dannenberg resp = (struct ti_sci_msg_hdr *)xfer->tx_message.buf; 323dcfc52adSAndreas Dannenberg 324dcfc52adSAndreas Dannenberg if (!ti_sci_is_response_ack(resp)) 325dcfc52adSAndreas Dannenberg return -ENODEV; 326dcfc52adSAndreas Dannenberg 327dcfc52adSAndreas Dannenberg return ret; 328dcfc52adSAndreas Dannenberg } 329dcfc52adSAndreas Dannenberg 330dcfc52adSAndreas Dannenberg /** 331dcfc52adSAndreas Dannenberg * ti_sci_cmd_set_board_config() - Command to send board configuration message 332dcfc52adSAndreas Dannenberg * @handle: pointer to TI SCI handle 333dcfc52adSAndreas Dannenberg * @addr: Address where the board config structure is located 334dcfc52adSAndreas Dannenberg * @size: Size of the board config structure 335dcfc52adSAndreas Dannenberg * 336dcfc52adSAndreas Dannenberg * Return: 0 if all went well, else returns appropriate error value. 337dcfc52adSAndreas Dannenberg */ 338dcfc52adSAndreas Dannenberg static int ti_sci_cmd_set_board_config(const struct ti_sci_handle *handle, 339dcfc52adSAndreas Dannenberg u64 addr, u32 size) 340dcfc52adSAndreas Dannenberg { 341dcfc52adSAndreas Dannenberg return cmd_set_board_config_using_msg(handle, 342dcfc52adSAndreas Dannenberg TI_SCI_MSG_BOARD_CONFIG, 343dcfc52adSAndreas Dannenberg addr, size); 344dcfc52adSAndreas Dannenberg } 345dcfc52adSAndreas Dannenberg 346dcfc52adSAndreas Dannenberg /** 347dcfc52adSAndreas Dannenberg * ti_sci_cmd_set_board_config_rm() - Command to send board resource 348dcfc52adSAndreas Dannenberg * management configuration 349dcfc52adSAndreas Dannenberg * @handle: pointer to TI SCI handle 350dcfc52adSAndreas Dannenberg * @addr: Address where the board RM config structure is located 351dcfc52adSAndreas Dannenberg * @size: Size of the RM config structure 352dcfc52adSAndreas Dannenberg * 353dcfc52adSAndreas Dannenberg * Return: 0 if all went well, else returns appropriate error value. 354dcfc52adSAndreas Dannenberg */ 355dcfc52adSAndreas Dannenberg static 356dcfc52adSAndreas Dannenberg int ti_sci_cmd_set_board_config_rm(const struct ti_sci_handle *handle, 357dcfc52adSAndreas Dannenberg u64 addr, u32 size) 358dcfc52adSAndreas Dannenberg { 359dcfc52adSAndreas Dannenberg return cmd_set_board_config_using_msg(handle, 360dcfc52adSAndreas Dannenberg TI_SCI_MSG_BOARD_CONFIG_RM, 361dcfc52adSAndreas Dannenberg addr, size); 362dcfc52adSAndreas Dannenberg } 363dcfc52adSAndreas Dannenberg 364dcfc52adSAndreas Dannenberg /** 365dcfc52adSAndreas Dannenberg * ti_sci_cmd_set_board_config_security() - Command to send board security 366dcfc52adSAndreas Dannenberg * configuration message 367dcfc52adSAndreas Dannenberg * @handle: pointer to TI SCI handle 368dcfc52adSAndreas Dannenberg * @addr: Address where the board security config structure is located 369dcfc52adSAndreas Dannenberg * @size: Size of the security config structure 370dcfc52adSAndreas Dannenberg * 371dcfc52adSAndreas Dannenberg * Return: 0 if all went well, else returns appropriate error value. 372dcfc52adSAndreas Dannenberg */ 373dcfc52adSAndreas Dannenberg static 374dcfc52adSAndreas Dannenberg int ti_sci_cmd_set_board_config_security(const struct ti_sci_handle *handle, 375dcfc52adSAndreas Dannenberg u64 addr, u32 size) 376dcfc52adSAndreas Dannenberg { 377dcfc52adSAndreas Dannenberg return cmd_set_board_config_using_msg(handle, 378dcfc52adSAndreas Dannenberg TI_SCI_MSG_BOARD_CONFIG_SECURITY, 379dcfc52adSAndreas Dannenberg addr, size); 380dcfc52adSAndreas Dannenberg } 381dcfc52adSAndreas Dannenberg 382dcfc52adSAndreas Dannenberg /** 383dcfc52adSAndreas Dannenberg * ti_sci_cmd_set_board_config_pm() - Command to send board power and clock 384dcfc52adSAndreas Dannenberg * configuration message 385dcfc52adSAndreas Dannenberg * @handle: pointer to TI SCI handle 386dcfc52adSAndreas Dannenberg * @addr: Address where the board PM config structure is located 387dcfc52adSAndreas Dannenberg * @size: Size of the PM config structure 388dcfc52adSAndreas Dannenberg * 389dcfc52adSAndreas Dannenberg * Return: 0 if all went well, else returns appropriate error value. 390dcfc52adSAndreas Dannenberg */ 391dcfc52adSAndreas Dannenberg static int ti_sci_cmd_set_board_config_pm(const struct ti_sci_handle *handle, 392dcfc52adSAndreas Dannenberg u64 addr, u32 size) 393dcfc52adSAndreas Dannenberg { 394dcfc52adSAndreas Dannenberg return cmd_set_board_config_using_msg(handle, 395dcfc52adSAndreas Dannenberg TI_SCI_MSG_BOARD_CONFIG_PM, 396dcfc52adSAndreas Dannenberg addr, size); 397dcfc52adSAndreas Dannenberg } 398dcfc52adSAndreas Dannenberg 399*7bc33045SAndreas Dannenberg /** 400*7bc33045SAndreas Dannenberg * ti_sci_set_device_state() - Set device state helper 401*7bc33045SAndreas Dannenberg * @handle: pointer to TI SCI handle 402*7bc33045SAndreas Dannenberg * @id: Device identifier 403*7bc33045SAndreas Dannenberg * @flags: flags to setup for the device 404*7bc33045SAndreas Dannenberg * @state: State to move the device to 405*7bc33045SAndreas Dannenberg * 406*7bc33045SAndreas Dannenberg * Return: 0 if all went well, else returns appropriate error value. 407*7bc33045SAndreas Dannenberg */ 408*7bc33045SAndreas Dannenberg static int ti_sci_set_device_state(const struct ti_sci_handle *handle, 409*7bc33045SAndreas Dannenberg u32 id, u32 flags, u8 state) 410*7bc33045SAndreas Dannenberg { 411*7bc33045SAndreas Dannenberg struct ti_sci_msg_req_set_device_state req; 412*7bc33045SAndreas Dannenberg struct ti_sci_msg_hdr *resp; 413*7bc33045SAndreas Dannenberg struct ti_sci_info *info; 414*7bc33045SAndreas Dannenberg struct ti_sci_xfer *xfer; 415*7bc33045SAndreas Dannenberg int ret = 0; 416*7bc33045SAndreas Dannenberg 417*7bc33045SAndreas Dannenberg if (IS_ERR(handle)) 418*7bc33045SAndreas Dannenberg return PTR_ERR(handle); 419*7bc33045SAndreas Dannenberg if (!handle) 420*7bc33045SAndreas Dannenberg return -EINVAL; 421*7bc33045SAndreas Dannenberg 422*7bc33045SAndreas Dannenberg info = handle_to_ti_sci_info(handle); 423*7bc33045SAndreas Dannenberg 424*7bc33045SAndreas Dannenberg xfer = ti_sci_setup_one_xfer(info, TI_SCI_MSG_SET_DEVICE_STATE, 425*7bc33045SAndreas Dannenberg flags | TI_SCI_FLAG_REQ_ACK_ON_PROCESSED, 426*7bc33045SAndreas Dannenberg (u32 *)&req, sizeof(req), sizeof(*resp)); 427*7bc33045SAndreas Dannenberg if (IS_ERR(xfer)) { 428*7bc33045SAndreas Dannenberg ret = PTR_ERR(xfer); 429*7bc33045SAndreas Dannenberg dev_err(info->dev, "Message alloc failed(%d)\n", ret); 430*7bc33045SAndreas Dannenberg return ret; 431*7bc33045SAndreas Dannenberg } 432*7bc33045SAndreas Dannenberg req.id = id; 433*7bc33045SAndreas Dannenberg req.state = state; 434*7bc33045SAndreas Dannenberg 435*7bc33045SAndreas Dannenberg ret = ti_sci_do_xfer(info, xfer); 436*7bc33045SAndreas Dannenberg if (ret) { 437*7bc33045SAndreas Dannenberg dev_err(info->dev, "Mbox send fail %d\n", ret); 438*7bc33045SAndreas Dannenberg return ret; 439*7bc33045SAndreas Dannenberg } 440*7bc33045SAndreas Dannenberg 441*7bc33045SAndreas Dannenberg resp = (struct ti_sci_msg_hdr *)xfer->tx_message.buf; 442*7bc33045SAndreas Dannenberg 443*7bc33045SAndreas Dannenberg if (!ti_sci_is_response_ack(resp)) 444*7bc33045SAndreas Dannenberg return -ENODEV; 445*7bc33045SAndreas Dannenberg 446*7bc33045SAndreas Dannenberg return ret; 447*7bc33045SAndreas Dannenberg } 448*7bc33045SAndreas Dannenberg 449*7bc33045SAndreas Dannenberg /** 450*7bc33045SAndreas Dannenberg * ti_sci_get_device_state() - Get device state helper 451*7bc33045SAndreas Dannenberg * @handle: Handle to the device 452*7bc33045SAndreas Dannenberg * @id: Device Identifier 453*7bc33045SAndreas Dannenberg * @clcnt: Pointer to Context Loss Count 454*7bc33045SAndreas Dannenberg * @resets: pointer to resets 455*7bc33045SAndreas Dannenberg * @p_state: pointer to p_state 456*7bc33045SAndreas Dannenberg * @c_state: pointer to c_state 457*7bc33045SAndreas Dannenberg * 458*7bc33045SAndreas Dannenberg * Return: 0 if all went fine, else return appropriate error. 459*7bc33045SAndreas Dannenberg */ 460*7bc33045SAndreas Dannenberg static int ti_sci_get_device_state(const struct ti_sci_handle *handle, 461*7bc33045SAndreas Dannenberg u32 id, u32 *clcnt, u32 *resets, 462*7bc33045SAndreas Dannenberg u8 *p_state, u8 *c_state) 463*7bc33045SAndreas Dannenberg { 464*7bc33045SAndreas Dannenberg struct ti_sci_msg_resp_get_device_state *resp; 465*7bc33045SAndreas Dannenberg struct ti_sci_msg_req_get_device_state req; 466*7bc33045SAndreas Dannenberg struct ti_sci_info *info; 467*7bc33045SAndreas Dannenberg struct ti_sci_xfer *xfer; 468*7bc33045SAndreas Dannenberg int ret = 0; 469*7bc33045SAndreas Dannenberg 470*7bc33045SAndreas Dannenberg if (IS_ERR(handle)) 471*7bc33045SAndreas Dannenberg return PTR_ERR(handle); 472*7bc33045SAndreas Dannenberg if (!handle) 473*7bc33045SAndreas Dannenberg return -EINVAL; 474*7bc33045SAndreas Dannenberg 475*7bc33045SAndreas Dannenberg if (!clcnt && !resets && !p_state && !c_state) 476*7bc33045SAndreas Dannenberg return -EINVAL; 477*7bc33045SAndreas Dannenberg 478*7bc33045SAndreas Dannenberg info = handle_to_ti_sci_info(handle); 479*7bc33045SAndreas Dannenberg 480*7bc33045SAndreas Dannenberg /* Response is expected, so need of any flags */ 481*7bc33045SAndreas Dannenberg xfer = ti_sci_setup_one_xfer(info, TI_SCI_MSG_GET_DEVICE_STATE, 0, 482*7bc33045SAndreas Dannenberg (u32 *)&req, sizeof(req), sizeof(*resp)); 483*7bc33045SAndreas Dannenberg if (IS_ERR(xfer)) { 484*7bc33045SAndreas Dannenberg ret = PTR_ERR(xfer); 485*7bc33045SAndreas Dannenberg dev_err(info->dev, "Message alloc failed(%d)\n", ret); 486*7bc33045SAndreas Dannenberg return ret; 487*7bc33045SAndreas Dannenberg } 488*7bc33045SAndreas Dannenberg req.id = id; 489*7bc33045SAndreas Dannenberg 490*7bc33045SAndreas Dannenberg ret = ti_sci_do_xfer(info, xfer); 491*7bc33045SAndreas Dannenberg if (ret) { 492*7bc33045SAndreas Dannenberg dev_err(dev, "Mbox send fail %d\n", ret); 493*7bc33045SAndreas Dannenberg return ret; 494*7bc33045SAndreas Dannenberg } 495*7bc33045SAndreas Dannenberg 496*7bc33045SAndreas Dannenberg resp = (struct ti_sci_msg_resp_get_device_state *)xfer->tx_message.buf; 497*7bc33045SAndreas Dannenberg if (!ti_sci_is_response_ack(resp)) 498*7bc33045SAndreas Dannenberg return -ENODEV; 499*7bc33045SAndreas Dannenberg 500*7bc33045SAndreas Dannenberg if (clcnt) 501*7bc33045SAndreas Dannenberg *clcnt = resp->context_loss_count; 502*7bc33045SAndreas Dannenberg if (resets) 503*7bc33045SAndreas Dannenberg *resets = resp->resets; 504*7bc33045SAndreas Dannenberg if (p_state) 505*7bc33045SAndreas Dannenberg *p_state = resp->programmed_state; 506*7bc33045SAndreas Dannenberg if (c_state) 507*7bc33045SAndreas Dannenberg *c_state = resp->current_state; 508*7bc33045SAndreas Dannenberg 509*7bc33045SAndreas Dannenberg return ret; 510*7bc33045SAndreas Dannenberg } 511*7bc33045SAndreas Dannenberg 512*7bc33045SAndreas Dannenberg /** 513*7bc33045SAndreas Dannenberg * ti_sci_cmd_get_device() - command to request for device managed by TISCI 514*7bc33045SAndreas Dannenberg * @handle: Pointer to TISCI handle as retrieved by *ti_sci_get_handle 515*7bc33045SAndreas Dannenberg * @id: Device Identifier 516*7bc33045SAndreas Dannenberg * 517*7bc33045SAndreas Dannenberg * Request for the device - NOTE: the client MUST maintain integrity of 518*7bc33045SAndreas Dannenberg * usage count by balancing get_device with put_device. No refcounting is 519*7bc33045SAndreas Dannenberg * managed by driver for that purpose. 520*7bc33045SAndreas Dannenberg * 521*7bc33045SAndreas Dannenberg * NOTE: The request is for exclusive access for the processor. 522*7bc33045SAndreas Dannenberg * 523*7bc33045SAndreas Dannenberg * Return: 0 if all went fine, else return appropriate error. 524*7bc33045SAndreas Dannenberg */ 525*7bc33045SAndreas Dannenberg static int ti_sci_cmd_get_device(const struct ti_sci_handle *handle, u32 id) 526*7bc33045SAndreas Dannenberg { 527*7bc33045SAndreas Dannenberg return ti_sci_set_device_state(handle, id, 528*7bc33045SAndreas Dannenberg MSG_FLAG_DEVICE_EXCLUSIVE, 529*7bc33045SAndreas Dannenberg MSG_DEVICE_SW_STATE_ON); 530*7bc33045SAndreas Dannenberg } 531*7bc33045SAndreas Dannenberg 532*7bc33045SAndreas Dannenberg /** 533*7bc33045SAndreas Dannenberg * ti_sci_cmd_idle_device() - Command to idle a device managed by TISCI 534*7bc33045SAndreas Dannenberg * @handle: Pointer to TISCI handle as retrieved by *ti_sci_get_handle 535*7bc33045SAndreas Dannenberg * @id: Device Identifier 536*7bc33045SAndreas Dannenberg * 537*7bc33045SAndreas Dannenberg * Request for the device - NOTE: the client MUST maintain integrity of 538*7bc33045SAndreas Dannenberg * usage count by balancing get_device with put_device. No refcounting is 539*7bc33045SAndreas Dannenberg * managed by driver for that purpose. 540*7bc33045SAndreas Dannenberg * 541*7bc33045SAndreas Dannenberg * Return: 0 if all went fine, else return appropriate error. 542*7bc33045SAndreas Dannenberg */ 543*7bc33045SAndreas Dannenberg static int ti_sci_cmd_idle_device(const struct ti_sci_handle *handle, u32 id) 544*7bc33045SAndreas Dannenberg { 545*7bc33045SAndreas Dannenberg return ti_sci_set_device_state(handle, id, 546*7bc33045SAndreas Dannenberg MSG_FLAG_DEVICE_EXCLUSIVE, 547*7bc33045SAndreas Dannenberg MSG_DEVICE_SW_STATE_RETENTION); 548*7bc33045SAndreas Dannenberg } 549*7bc33045SAndreas Dannenberg 550*7bc33045SAndreas Dannenberg /** 551*7bc33045SAndreas Dannenberg * ti_sci_cmd_put_device() - command to release a device managed by TISCI 552*7bc33045SAndreas Dannenberg * @handle: Pointer to TISCI handle as retrieved by *ti_sci_get_handle 553*7bc33045SAndreas Dannenberg * @id: Device Identifier 554*7bc33045SAndreas Dannenberg * 555*7bc33045SAndreas Dannenberg * Request for the device - NOTE: the client MUST maintain integrity of 556*7bc33045SAndreas Dannenberg * usage count by balancing get_device with put_device. No refcounting is 557*7bc33045SAndreas Dannenberg * managed by driver for that purpose. 558*7bc33045SAndreas Dannenberg * 559*7bc33045SAndreas Dannenberg * Return: 0 if all went fine, else return appropriate error. 560*7bc33045SAndreas Dannenberg */ 561*7bc33045SAndreas Dannenberg static int ti_sci_cmd_put_device(const struct ti_sci_handle *handle, u32 id) 562*7bc33045SAndreas Dannenberg { 563*7bc33045SAndreas Dannenberg return ti_sci_set_device_state(handle, id, 564*7bc33045SAndreas Dannenberg 0, MSG_DEVICE_SW_STATE_AUTO_OFF); 565*7bc33045SAndreas Dannenberg } 566*7bc33045SAndreas Dannenberg 567*7bc33045SAndreas Dannenberg /** 568*7bc33045SAndreas Dannenberg * ti_sci_cmd_dev_is_valid() - Is the device valid 569*7bc33045SAndreas Dannenberg * @handle: Pointer to TISCI handle as retrieved by *ti_sci_get_handle 570*7bc33045SAndreas Dannenberg * @id: Device Identifier 571*7bc33045SAndreas Dannenberg * 572*7bc33045SAndreas Dannenberg * Return: 0 if all went fine and the device ID is valid, else return 573*7bc33045SAndreas Dannenberg * appropriate error. 574*7bc33045SAndreas Dannenberg */ 575*7bc33045SAndreas Dannenberg static int ti_sci_cmd_dev_is_valid(const struct ti_sci_handle *handle, u32 id) 576*7bc33045SAndreas Dannenberg { 577*7bc33045SAndreas Dannenberg u8 unused; 578*7bc33045SAndreas Dannenberg 579*7bc33045SAndreas Dannenberg /* check the device state which will also tell us if the ID is valid */ 580*7bc33045SAndreas Dannenberg return ti_sci_get_device_state(handle, id, NULL, NULL, NULL, &unused); 581*7bc33045SAndreas Dannenberg } 582*7bc33045SAndreas Dannenberg 583*7bc33045SAndreas Dannenberg /** 584*7bc33045SAndreas Dannenberg * ti_sci_cmd_dev_get_clcnt() - Get context loss counter 585*7bc33045SAndreas Dannenberg * @handle: Pointer to TISCI handle 586*7bc33045SAndreas Dannenberg * @id: Device Identifier 587*7bc33045SAndreas Dannenberg * @count: Pointer to Context Loss counter to populate 588*7bc33045SAndreas Dannenberg * 589*7bc33045SAndreas Dannenberg * Return: 0 if all went fine, else return appropriate error. 590*7bc33045SAndreas Dannenberg */ 591*7bc33045SAndreas Dannenberg static int ti_sci_cmd_dev_get_clcnt(const struct ti_sci_handle *handle, u32 id, 592*7bc33045SAndreas Dannenberg u32 *count) 593*7bc33045SAndreas Dannenberg { 594*7bc33045SAndreas Dannenberg return ti_sci_get_device_state(handle, id, count, NULL, NULL, NULL); 595*7bc33045SAndreas Dannenberg } 596*7bc33045SAndreas Dannenberg 597*7bc33045SAndreas Dannenberg /** 598*7bc33045SAndreas Dannenberg * ti_sci_cmd_dev_is_idle() - Check if the device is requested to be idle 599*7bc33045SAndreas Dannenberg * @handle: Pointer to TISCI handle 600*7bc33045SAndreas Dannenberg * @id: Device Identifier 601*7bc33045SAndreas Dannenberg * @r_state: true if requested to be idle 602*7bc33045SAndreas Dannenberg * 603*7bc33045SAndreas Dannenberg * Return: 0 if all went fine, else return appropriate error. 604*7bc33045SAndreas Dannenberg */ 605*7bc33045SAndreas Dannenberg static int ti_sci_cmd_dev_is_idle(const struct ti_sci_handle *handle, u32 id, 606*7bc33045SAndreas Dannenberg bool *r_state) 607*7bc33045SAndreas Dannenberg { 608*7bc33045SAndreas Dannenberg int ret; 609*7bc33045SAndreas Dannenberg u8 state; 610*7bc33045SAndreas Dannenberg 611*7bc33045SAndreas Dannenberg if (!r_state) 612*7bc33045SAndreas Dannenberg return -EINVAL; 613*7bc33045SAndreas Dannenberg 614*7bc33045SAndreas Dannenberg ret = ti_sci_get_device_state(handle, id, NULL, NULL, &state, NULL); 615*7bc33045SAndreas Dannenberg if (ret) 616*7bc33045SAndreas Dannenberg return ret; 617*7bc33045SAndreas Dannenberg 618*7bc33045SAndreas Dannenberg *r_state = (state == MSG_DEVICE_SW_STATE_RETENTION); 619*7bc33045SAndreas Dannenberg 620*7bc33045SAndreas Dannenberg return 0; 621*7bc33045SAndreas Dannenberg } 622*7bc33045SAndreas Dannenberg 623*7bc33045SAndreas Dannenberg /** 624*7bc33045SAndreas Dannenberg * ti_sci_cmd_dev_is_stop() - Check if the device is requested to be stopped 625*7bc33045SAndreas Dannenberg * @handle: Pointer to TISCI handle 626*7bc33045SAndreas Dannenberg * @id: Device Identifier 627*7bc33045SAndreas Dannenberg * @r_state: true if requested to be stopped 628*7bc33045SAndreas Dannenberg * @curr_state: true if currently stopped. 629*7bc33045SAndreas Dannenberg * 630*7bc33045SAndreas Dannenberg * Return: 0 if all went fine, else return appropriate error. 631*7bc33045SAndreas Dannenberg */ 632*7bc33045SAndreas Dannenberg static int ti_sci_cmd_dev_is_stop(const struct ti_sci_handle *handle, u32 id, 633*7bc33045SAndreas Dannenberg bool *r_state, bool *curr_state) 634*7bc33045SAndreas Dannenberg { 635*7bc33045SAndreas Dannenberg int ret; 636*7bc33045SAndreas Dannenberg u8 p_state, c_state; 637*7bc33045SAndreas Dannenberg 638*7bc33045SAndreas Dannenberg if (!r_state && !curr_state) 639*7bc33045SAndreas Dannenberg return -EINVAL; 640*7bc33045SAndreas Dannenberg 641*7bc33045SAndreas Dannenberg ret = 642*7bc33045SAndreas Dannenberg ti_sci_get_device_state(handle, id, NULL, NULL, &p_state, &c_state); 643*7bc33045SAndreas Dannenberg if (ret) 644*7bc33045SAndreas Dannenberg return ret; 645*7bc33045SAndreas Dannenberg 646*7bc33045SAndreas Dannenberg if (r_state) 647*7bc33045SAndreas Dannenberg *r_state = (p_state == MSG_DEVICE_SW_STATE_AUTO_OFF); 648*7bc33045SAndreas Dannenberg if (curr_state) 649*7bc33045SAndreas Dannenberg *curr_state = (c_state == MSG_DEVICE_HW_STATE_OFF); 650*7bc33045SAndreas Dannenberg 651*7bc33045SAndreas Dannenberg return 0; 652*7bc33045SAndreas Dannenberg } 653*7bc33045SAndreas Dannenberg 654*7bc33045SAndreas Dannenberg /** 655*7bc33045SAndreas Dannenberg * ti_sci_cmd_dev_is_on() - Check if the device is requested to be ON 656*7bc33045SAndreas Dannenberg * @handle: Pointer to TISCI handle 657*7bc33045SAndreas Dannenberg * @id: Device Identifier 658*7bc33045SAndreas Dannenberg * @r_state: true if requested to be ON 659*7bc33045SAndreas Dannenberg * @curr_state: true if currently ON and active 660*7bc33045SAndreas Dannenberg * 661*7bc33045SAndreas Dannenberg * Return: 0 if all went fine, else return appropriate error. 662*7bc33045SAndreas Dannenberg */ 663*7bc33045SAndreas Dannenberg static int ti_sci_cmd_dev_is_on(const struct ti_sci_handle *handle, u32 id, 664*7bc33045SAndreas Dannenberg bool *r_state, bool *curr_state) 665*7bc33045SAndreas Dannenberg { 666*7bc33045SAndreas Dannenberg int ret; 667*7bc33045SAndreas Dannenberg u8 p_state, c_state; 668*7bc33045SAndreas Dannenberg 669*7bc33045SAndreas Dannenberg if (!r_state && !curr_state) 670*7bc33045SAndreas Dannenberg return -EINVAL; 671*7bc33045SAndreas Dannenberg 672*7bc33045SAndreas Dannenberg ret = 673*7bc33045SAndreas Dannenberg ti_sci_get_device_state(handle, id, NULL, NULL, &p_state, &c_state); 674*7bc33045SAndreas Dannenberg if (ret) 675*7bc33045SAndreas Dannenberg return ret; 676*7bc33045SAndreas Dannenberg 677*7bc33045SAndreas Dannenberg if (r_state) 678*7bc33045SAndreas Dannenberg *r_state = (p_state == MSG_DEVICE_SW_STATE_ON); 679*7bc33045SAndreas Dannenberg if (curr_state) 680*7bc33045SAndreas Dannenberg *curr_state = (c_state == MSG_DEVICE_HW_STATE_ON); 681*7bc33045SAndreas Dannenberg 682*7bc33045SAndreas Dannenberg return 0; 683*7bc33045SAndreas Dannenberg } 684*7bc33045SAndreas Dannenberg 685*7bc33045SAndreas Dannenberg /** 686*7bc33045SAndreas Dannenberg * ti_sci_cmd_dev_is_trans() - Check if the device is currently transitioning 687*7bc33045SAndreas Dannenberg * @handle: Pointer to TISCI handle 688*7bc33045SAndreas Dannenberg * @id: Device Identifier 689*7bc33045SAndreas Dannenberg * @curr_state: true if currently transitioning. 690*7bc33045SAndreas Dannenberg * 691*7bc33045SAndreas Dannenberg * Return: 0 if all went fine, else return appropriate error. 692*7bc33045SAndreas Dannenberg */ 693*7bc33045SAndreas Dannenberg static int ti_sci_cmd_dev_is_trans(const struct ti_sci_handle *handle, u32 id, 694*7bc33045SAndreas Dannenberg bool *curr_state) 695*7bc33045SAndreas Dannenberg { 696*7bc33045SAndreas Dannenberg int ret; 697*7bc33045SAndreas Dannenberg u8 state; 698*7bc33045SAndreas Dannenberg 699*7bc33045SAndreas Dannenberg if (!curr_state) 700*7bc33045SAndreas Dannenberg return -EINVAL; 701*7bc33045SAndreas Dannenberg 702*7bc33045SAndreas Dannenberg ret = ti_sci_get_device_state(handle, id, NULL, NULL, NULL, &state); 703*7bc33045SAndreas Dannenberg if (ret) 704*7bc33045SAndreas Dannenberg return ret; 705*7bc33045SAndreas Dannenberg 706*7bc33045SAndreas Dannenberg *curr_state = (state == MSG_DEVICE_HW_STATE_TRANS); 707*7bc33045SAndreas Dannenberg 708*7bc33045SAndreas Dannenberg return 0; 709*7bc33045SAndreas Dannenberg } 710*7bc33045SAndreas Dannenberg 711*7bc33045SAndreas Dannenberg /** 712*7bc33045SAndreas Dannenberg * ti_sci_cmd_set_device_resets() - command to set resets for device managed 713*7bc33045SAndreas Dannenberg * by TISCI 714*7bc33045SAndreas Dannenberg * @handle: Pointer to TISCI handle as retrieved by *ti_sci_get_handle 715*7bc33045SAndreas Dannenberg * @id: Device Identifier 716*7bc33045SAndreas Dannenberg * @reset_state: Device specific reset bit field 717*7bc33045SAndreas Dannenberg * 718*7bc33045SAndreas Dannenberg * Return: 0 if all went fine, else return appropriate error. 719*7bc33045SAndreas Dannenberg */ 720*7bc33045SAndreas Dannenberg static int ti_sci_cmd_set_device_resets(const struct ti_sci_handle *handle, 721*7bc33045SAndreas Dannenberg u32 id, u32 reset_state) 722*7bc33045SAndreas Dannenberg { 723*7bc33045SAndreas Dannenberg struct ti_sci_msg_req_set_device_resets req; 724*7bc33045SAndreas Dannenberg struct ti_sci_msg_hdr *resp; 725*7bc33045SAndreas Dannenberg struct ti_sci_info *info; 726*7bc33045SAndreas Dannenberg struct ti_sci_xfer *xfer; 727*7bc33045SAndreas Dannenberg int ret = 0; 728*7bc33045SAndreas Dannenberg 729*7bc33045SAndreas Dannenberg if (IS_ERR(handle)) 730*7bc33045SAndreas Dannenberg return PTR_ERR(handle); 731*7bc33045SAndreas Dannenberg if (!handle) 732*7bc33045SAndreas Dannenberg return -EINVAL; 733*7bc33045SAndreas Dannenberg 734*7bc33045SAndreas Dannenberg info = handle_to_ti_sci_info(handle); 735*7bc33045SAndreas Dannenberg 736*7bc33045SAndreas Dannenberg xfer = ti_sci_setup_one_xfer(info, TI_SCI_MSG_SET_DEVICE_RESETS, 737*7bc33045SAndreas Dannenberg TI_SCI_FLAG_REQ_ACK_ON_PROCESSED, 738*7bc33045SAndreas Dannenberg (u32 *)&req, sizeof(req), sizeof(*resp)); 739*7bc33045SAndreas Dannenberg if (IS_ERR(xfer)) { 740*7bc33045SAndreas Dannenberg ret = PTR_ERR(xfer); 741*7bc33045SAndreas Dannenberg dev_err(info->dev, "Message alloc failed(%d)\n", ret); 742*7bc33045SAndreas Dannenberg return ret; 743*7bc33045SAndreas Dannenberg } 744*7bc33045SAndreas Dannenberg req.id = id; 745*7bc33045SAndreas Dannenberg req.resets = reset_state; 746*7bc33045SAndreas Dannenberg 747*7bc33045SAndreas Dannenberg ret = ti_sci_do_xfer(info, xfer); 748*7bc33045SAndreas Dannenberg if (ret) { 749*7bc33045SAndreas Dannenberg dev_err(info->dev, "Mbox send fail %d\n", ret); 750*7bc33045SAndreas Dannenberg return ret; 751*7bc33045SAndreas Dannenberg } 752*7bc33045SAndreas Dannenberg 753*7bc33045SAndreas Dannenberg resp = (struct ti_sci_msg_hdr *)xfer->tx_message.buf; 754*7bc33045SAndreas Dannenberg 755*7bc33045SAndreas Dannenberg if (!ti_sci_is_response_ack(resp)) 756*7bc33045SAndreas Dannenberg return -ENODEV; 757*7bc33045SAndreas Dannenberg 758*7bc33045SAndreas Dannenberg return ret; 759*7bc33045SAndreas Dannenberg } 760*7bc33045SAndreas Dannenberg 761*7bc33045SAndreas Dannenberg /** 762*7bc33045SAndreas Dannenberg * ti_sci_cmd_get_device_resets() - Get reset state for device managed 763*7bc33045SAndreas Dannenberg * by TISCI 764*7bc33045SAndreas Dannenberg * @handle: Pointer to TISCI handle 765*7bc33045SAndreas Dannenberg * @id: Device Identifier 766*7bc33045SAndreas Dannenberg * @reset_state: Pointer to reset state to populate 767*7bc33045SAndreas Dannenberg * 768*7bc33045SAndreas Dannenberg * Return: 0 if all went fine, else return appropriate error. 769*7bc33045SAndreas Dannenberg */ 770*7bc33045SAndreas Dannenberg static int ti_sci_cmd_get_device_resets(const struct ti_sci_handle *handle, 771*7bc33045SAndreas Dannenberg u32 id, u32 *reset_state) 772*7bc33045SAndreas Dannenberg { 773*7bc33045SAndreas Dannenberg return ti_sci_get_device_state(handle, id, NULL, reset_state, NULL, 774*7bc33045SAndreas Dannenberg NULL); 775*7bc33045SAndreas Dannenberg } 776*7bc33045SAndreas Dannenberg 777dcfc52adSAndreas Dannenberg /* 778dcfc52adSAndreas Dannenberg * ti_sci_setup_ops() - Setup the operations structures 779dcfc52adSAndreas Dannenberg * @info: pointer to TISCI pointer 780dcfc52adSAndreas Dannenberg */ 781dcfc52adSAndreas Dannenberg static void ti_sci_setup_ops(struct ti_sci_info *info) 782dcfc52adSAndreas Dannenberg { 783dcfc52adSAndreas Dannenberg struct ti_sci_ops *ops = &info->handle.ops; 784dcfc52adSAndreas Dannenberg struct ti_sci_board_ops *bops = &ops->board_ops; 785*7bc33045SAndreas Dannenberg struct ti_sci_dev_ops *dops = &ops->dev_ops; 786dcfc52adSAndreas Dannenberg 787dcfc52adSAndreas Dannenberg bops->board_config = ti_sci_cmd_set_board_config; 788dcfc52adSAndreas Dannenberg bops->board_config_rm = ti_sci_cmd_set_board_config_rm; 789dcfc52adSAndreas Dannenberg bops->board_config_security = ti_sci_cmd_set_board_config_security; 790dcfc52adSAndreas Dannenberg bops->board_config_pm = ti_sci_cmd_set_board_config_pm; 791*7bc33045SAndreas Dannenberg 792*7bc33045SAndreas Dannenberg dops->get_device = ti_sci_cmd_get_device; 793*7bc33045SAndreas Dannenberg dops->idle_device = ti_sci_cmd_idle_device; 794*7bc33045SAndreas Dannenberg dops->put_device = ti_sci_cmd_put_device; 795*7bc33045SAndreas Dannenberg dops->is_valid = ti_sci_cmd_dev_is_valid; 796*7bc33045SAndreas Dannenberg dops->get_context_loss_count = ti_sci_cmd_dev_get_clcnt; 797*7bc33045SAndreas Dannenberg dops->is_idle = ti_sci_cmd_dev_is_idle; 798*7bc33045SAndreas Dannenberg dops->is_stop = ti_sci_cmd_dev_is_stop; 799*7bc33045SAndreas Dannenberg dops->is_on = ti_sci_cmd_dev_is_on; 800*7bc33045SAndreas Dannenberg dops->is_transitioning = ti_sci_cmd_dev_is_trans; 801*7bc33045SAndreas Dannenberg dops->set_device_resets = ti_sci_cmd_set_device_resets; 802*7bc33045SAndreas Dannenberg dops->get_device_resets = ti_sci_cmd_get_device_resets; 803dcfc52adSAndreas Dannenberg } 804dcfc52adSAndreas Dannenberg 805dcfc52adSAndreas Dannenberg /** 80632cd2512SLokesh Vutla * ti_sci_get_handle_from_sysfw() - Get the TI SCI handle of the SYSFW 80732cd2512SLokesh Vutla * @dev: Pointer to the SYSFW device 80832cd2512SLokesh Vutla * 80932cd2512SLokesh Vutla * Return: pointer to handle if successful, else EINVAL if invalid conditions 81032cd2512SLokesh Vutla * are encountered. 81132cd2512SLokesh Vutla */ 81232cd2512SLokesh Vutla const 81332cd2512SLokesh Vutla struct ti_sci_handle *ti_sci_get_handle_from_sysfw(struct udevice *sci_dev) 81432cd2512SLokesh Vutla { 81532cd2512SLokesh Vutla if (!sci_dev) 81632cd2512SLokesh Vutla return ERR_PTR(-EINVAL); 81732cd2512SLokesh Vutla 81832cd2512SLokesh Vutla struct ti_sci_info *info = dev_get_priv(sci_dev); 81932cd2512SLokesh Vutla 82032cd2512SLokesh Vutla if (!info) 82132cd2512SLokesh Vutla return ERR_PTR(-EINVAL); 82232cd2512SLokesh Vutla 82332cd2512SLokesh Vutla struct ti_sci_handle *handle = &info->handle; 82432cd2512SLokesh Vutla 82532cd2512SLokesh Vutla if (!handle) 82632cd2512SLokesh Vutla return ERR_PTR(-EINVAL); 82732cd2512SLokesh Vutla 82832cd2512SLokesh Vutla return handle; 82932cd2512SLokesh Vutla } 83032cd2512SLokesh Vutla 83132cd2512SLokesh Vutla /** 83232cd2512SLokesh Vutla * ti_sci_get_handle() - Get the TI SCI handle for a device 83332cd2512SLokesh Vutla * @dev: Pointer to device for which we want SCI handle 83432cd2512SLokesh Vutla * 83532cd2512SLokesh Vutla * Return: pointer to handle if successful, else EINVAL if invalid conditions 83632cd2512SLokesh Vutla * are encountered. 83732cd2512SLokesh Vutla */ 83832cd2512SLokesh Vutla const struct ti_sci_handle *ti_sci_get_handle(struct udevice *dev) 83932cd2512SLokesh Vutla { 84032cd2512SLokesh Vutla if (!dev) 84132cd2512SLokesh Vutla return ERR_PTR(-EINVAL); 84232cd2512SLokesh Vutla 84332cd2512SLokesh Vutla struct udevice *sci_dev = dev_get_parent(dev); 84432cd2512SLokesh Vutla 84532cd2512SLokesh Vutla return ti_sci_get_handle_from_sysfw(sci_dev); 84632cd2512SLokesh Vutla } 84732cd2512SLokesh Vutla 84832cd2512SLokesh Vutla /** 84932cd2512SLokesh Vutla * ti_sci_get_by_phandle() - Get the TI SCI handle using DT phandle 85032cd2512SLokesh Vutla * @dev: device node 85132cd2512SLokesh Vutla * @propname: property name containing phandle on TISCI node 85232cd2512SLokesh Vutla * 85332cd2512SLokesh Vutla * Return: pointer to handle if successful, else appropriate error value. 85432cd2512SLokesh Vutla */ 85532cd2512SLokesh Vutla const struct ti_sci_handle *ti_sci_get_by_phandle(struct udevice *dev, 85632cd2512SLokesh Vutla const char *property) 85732cd2512SLokesh Vutla { 85832cd2512SLokesh Vutla struct ti_sci_info *entry, *info = NULL; 85932cd2512SLokesh Vutla u32 phandle, err; 86032cd2512SLokesh Vutla ofnode node; 86132cd2512SLokesh Vutla 86232cd2512SLokesh Vutla err = ofnode_read_u32(dev_ofnode(dev), property, &phandle); 86332cd2512SLokesh Vutla if (err) 86432cd2512SLokesh Vutla return ERR_PTR(err); 86532cd2512SLokesh Vutla 86632cd2512SLokesh Vutla node = ofnode_get_by_phandle(phandle); 86732cd2512SLokesh Vutla if (!ofnode_valid(node)) 86832cd2512SLokesh Vutla return ERR_PTR(-EINVAL); 86932cd2512SLokesh Vutla 87032cd2512SLokesh Vutla list_for_each_entry(entry, &ti_sci_list, list) 87132cd2512SLokesh Vutla if (ofnode_equal(dev_ofnode(entry->dev), node)) { 87232cd2512SLokesh Vutla info = entry; 87332cd2512SLokesh Vutla break; 87432cd2512SLokesh Vutla } 87532cd2512SLokesh Vutla 87632cd2512SLokesh Vutla if (!info) 87732cd2512SLokesh Vutla return ERR_PTR(-ENODEV); 87832cd2512SLokesh Vutla 87932cd2512SLokesh Vutla return &info->handle; 88032cd2512SLokesh Vutla } 88132cd2512SLokesh Vutla 88232cd2512SLokesh Vutla /** 88332cd2512SLokesh Vutla * ti_sci_of_to_info() - generate private data from device tree 88432cd2512SLokesh Vutla * @dev: corresponding system controller interface device 88532cd2512SLokesh Vutla * @info: pointer to driver specific private data 88632cd2512SLokesh Vutla * 88732cd2512SLokesh Vutla * Return: 0 if all goes good, else appropriate error message. 88832cd2512SLokesh Vutla */ 88932cd2512SLokesh Vutla static int ti_sci_of_to_info(struct udevice *dev, struct ti_sci_info *info) 89032cd2512SLokesh Vutla { 89132cd2512SLokesh Vutla int ret; 89232cd2512SLokesh Vutla 89332cd2512SLokesh Vutla ret = mbox_get_by_name(dev, "tx", &info->chan_tx); 89432cd2512SLokesh Vutla if (ret) { 89532cd2512SLokesh Vutla dev_err(dev, "%s: Acquiring Tx channel failed. ret = %d\n", 89632cd2512SLokesh Vutla __func__, ret); 89732cd2512SLokesh Vutla return ret; 89832cd2512SLokesh Vutla } 89932cd2512SLokesh Vutla 90032cd2512SLokesh Vutla ret = mbox_get_by_name(dev, "rx", &info->chan_rx); 90132cd2512SLokesh Vutla if (ret) { 90232cd2512SLokesh Vutla dev_err(dev, "%s: Acquiring Rx channel failed. ret = %d\n", 90332cd2512SLokesh Vutla __func__, ret); 90432cd2512SLokesh Vutla return ret; 90532cd2512SLokesh Vutla } 90632cd2512SLokesh Vutla 90732cd2512SLokesh Vutla /* Notify channel is optional. Enable only if populated */ 90832cd2512SLokesh Vutla ret = mbox_get_by_name(dev, "notify", &info->chan_notify); 90932cd2512SLokesh Vutla if (ret) { 91032cd2512SLokesh Vutla dev_dbg(dev, "%s: Acquiring notify channel failed. ret = %d\n", 91132cd2512SLokesh Vutla __func__, ret); 91232cd2512SLokesh Vutla } 91332cd2512SLokesh Vutla 91432cd2512SLokesh Vutla info->host_id = dev_read_u32_default(dev, "ti,host-id", 91532cd2512SLokesh Vutla info->desc->host_id); 91632cd2512SLokesh Vutla 91732cd2512SLokesh Vutla info->is_secure = dev_read_bool(dev, "ti,secure-host"); 91832cd2512SLokesh Vutla 91932cd2512SLokesh Vutla return 0; 92032cd2512SLokesh Vutla } 92132cd2512SLokesh Vutla 92232cd2512SLokesh Vutla /** 92332cd2512SLokesh Vutla * ti_sci_probe() - Basic probe 92432cd2512SLokesh Vutla * @dev: corresponding system controller interface device 92532cd2512SLokesh Vutla * 92632cd2512SLokesh Vutla * Return: 0 if all goes good, else appropriate error message. 92732cd2512SLokesh Vutla */ 92832cd2512SLokesh Vutla static int ti_sci_probe(struct udevice *dev) 92932cd2512SLokesh Vutla { 93032cd2512SLokesh Vutla struct ti_sci_info *info; 93132cd2512SLokesh Vutla int ret; 93232cd2512SLokesh Vutla 93332cd2512SLokesh Vutla debug("%s(dev=%p)\n", __func__, dev); 93432cd2512SLokesh Vutla 93532cd2512SLokesh Vutla info = dev_get_priv(dev); 93632cd2512SLokesh Vutla info->desc = (void *)dev_get_driver_data(dev); 93732cd2512SLokesh Vutla 93832cd2512SLokesh Vutla ret = ti_sci_of_to_info(dev, info); 93932cd2512SLokesh Vutla if (ret) { 94032cd2512SLokesh Vutla dev_err(dev, "%s: Probe failed with error %d\n", __func__, ret); 94132cd2512SLokesh Vutla return ret; 94232cd2512SLokesh Vutla } 94332cd2512SLokesh Vutla 94432cd2512SLokesh Vutla info->dev = dev; 94532cd2512SLokesh Vutla info->seq = 0xA; 94632cd2512SLokesh Vutla 94732cd2512SLokesh Vutla list_add_tail(&info->list, &ti_sci_list); 948dcfc52adSAndreas Dannenberg ti_sci_setup_ops(info); 94932cd2512SLokesh Vutla 95032cd2512SLokesh Vutla ret = ti_sci_cmd_get_revision(&info->handle); 95132cd2512SLokesh Vutla 95232cd2512SLokesh Vutla return ret; 95332cd2512SLokesh Vutla } 95432cd2512SLokesh Vutla 95532cd2512SLokesh Vutla /* Description for AM654 */ 95632cd2512SLokesh Vutla static const struct ti_sci_desc ti_sci_sysfw_am654_desc = { 95732cd2512SLokesh Vutla .host_id = 4, 95832cd2512SLokesh Vutla .max_rx_timeout_us = 1000000, 95932cd2512SLokesh Vutla .max_msg_size = 60, 96032cd2512SLokesh Vutla }; 96132cd2512SLokesh Vutla 96232cd2512SLokesh Vutla static const struct udevice_id ti_sci_ids[] = { 96332cd2512SLokesh Vutla { 96432cd2512SLokesh Vutla .compatible = "ti,k2g-sci", 96532cd2512SLokesh Vutla .data = (ulong)&ti_sci_sysfw_am654_desc 96632cd2512SLokesh Vutla }, 96732cd2512SLokesh Vutla { /* Sentinel */ }, 96832cd2512SLokesh Vutla }; 96932cd2512SLokesh Vutla 97032cd2512SLokesh Vutla U_BOOT_DRIVER(ti_sci) = { 97132cd2512SLokesh Vutla .name = "ti_sci", 97232cd2512SLokesh Vutla .id = UCLASS_FIRMWARE, 97332cd2512SLokesh Vutla .of_match = ti_sci_ids, 97432cd2512SLokesh Vutla .probe = ti_sci_probe, 97532cd2512SLokesh Vutla .priv_auto_alloc_size = sizeof(struct ti_sci_info), 97632cd2512SLokesh Vutla }; 977