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 * ti_sci_get_handle_from_sysfw() - Get the TI SCI handle of the SYSFW 280 * @dev: Pointer to the SYSFW device 281 * 282 * Return: pointer to handle if successful, else EINVAL if invalid conditions 283 * are encountered. 284 */ 285 const 286 struct ti_sci_handle *ti_sci_get_handle_from_sysfw(struct udevice *sci_dev) 287 { 288 if (!sci_dev) 289 return ERR_PTR(-EINVAL); 290 291 struct ti_sci_info *info = dev_get_priv(sci_dev); 292 293 if (!info) 294 return ERR_PTR(-EINVAL); 295 296 struct ti_sci_handle *handle = &info->handle; 297 298 if (!handle) 299 return ERR_PTR(-EINVAL); 300 301 return handle; 302 } 303 304 /** 305 * ti_sci_get_handle() - Get the TI SCI handle for a device 306 * @dev: Pointer to device for which we want SCI handle 307 * 308 * Return: pointer to handle if successful, else EINVAL if invalid conditions 309 * are encountered. 310 */ 311 const struct ti_sci_handle *ti_sci_get_handle(struct udevice *dev) 312 { 313 if (!dev) 314 return ERR_PTR(-EINVAL); 315 316 struct udevice *sci_dev = dev_get_parent(dev); 317 318 return ti_sci_get_handle_from_sysfw(sci_dev); 319 } 320 321 /** 322 * ti_sci_get_by_phandle() - Get the TI SCI handle using DT phandle 323 * @dev: device node 324 * @propname: property name containing phandle on TISCI node 325 * 326 * Return: pointer to handle if successful, else appropriate error value. 327 */ 328 const struct ti_sci_handle *ti_sci_get_by_phandle(struct udevice *dev, 329 const char *property) 330 { 331 struct ti_sci_info *entry, *info = NULL; 332 u32 phandle, err; 333 ofnode node; 334 335 err = ofnode_read_u32(dev_ofnode(dev), property, &phandle); 336 if (err) 337 return ERR_PTR(err); 338 339 node = ofnode_get_by_phandle(phandle); 340 if (!ofnode_valid(node)) 341 return ERR_PTR(-EINVAL); 342 343 list_for_each_entry(entry, &ti_sci_list, list) 344 if (ofnode_equal(dev_ofnode(entry->dev), node)) { 345 info = entry; 346 break; 347 } 348 349 if (!info) 350 return ERR_PTR(-ENODEV); 351 352 return &info->handle; 353 } 354 355 /** 356 * ti_sci_of_to_info() - generate private data from device tree 357 * @dev: corresponding system controller interface device 358 * @info: pointer to driver specific private data 359 * 360 * Return: 0 if all goes good, else appropriate error message. 361 */ 362 static int ti_sci_of_to_info(struct udevice *dev, struct ti_sci_info *info) 363 { 364 int ret; 365 366 ret = mbox_get_by_name(dev, "tx", &info->chan_tx); 367 if (ret) { 368 dev_err(dev, "%s: Acquiring Tx channel failed. ret = %d\n", 369 __func__, ret); 370 return ret; 371 } 372 373 ret = mbox_get_by_name(dev, "rx", &info->chan_rx); 374 if (ret) { 375 dev_err(dev, "%s: Acquiring Rx channel failed. ret = %d\n", 376 __func__, ret); 377 return ret; 378 } 379 380 /* Notify channel is optional. Enable only if populated */ 381 ret = mbox_get_by_name(dev, "notify", &info->chan_notify); 382 if (ret) { 383 dev_dbg(dev, "%s: Acquiring notify channel failed. ret = %d\n", 384 __func__, ret); 385 } 386 387 info->host_id = dev_read_u32_default(dev, "ti,host-id", 388 info->desc->host_id); 389 390 info->is_secure = dev_read_bool(dev, "ti,secure-host"); 391 392 return 0; 393 } 394 395 /** 396 * ti_sci_probe() - Basic probe 397 * @dev: corresponding system controller interface device 398 * 399 * Return: 0 if all goes good, else appropriate error message. 400 */ 401 static int ti_sci_probe(struct udevice *dev) 402 { 403 struct ti_sci_info *info; 404 int ret; 405 406 debug("%s(dev=%p)\n", __func__, dev); 407 408 info = dev_get_priv(dev); 409 info->desc = (void *)dev_get_driver_data(dev); 410 411 ret = ti_sci_of_to_info(dev, info); 412 if (ret) { 413 dev_err(dev, "%s: Probe failed with error %d\n", __func__, ret); 414 return ret; 415 } 416 417 info->dev = dev; 418 info->seq = 0xA; 419 420 list_add_tail(&info->list, &ti_sci_list); 421 422 ret = ti_sci_cmd_get_revision(&info->handle); 423 424 return ret; 425 } 426 427 /* Description for AM654 */ 428 static const struct ti_sci_desc ti_sci_sysfw_am654_desc = { 429 .host_id = 4, 430 .max_rx_timeout_us = 1000000, 431 .max_msg_size = 60, 432 }; 433 434 static const struct udevice_id ti_sci_ids[] = { 435 { 436 .compatible = "ti,k2g-sci", 437 .data = (ulong)&ti_sci_sysfw_am654_desc 438 }, 439 { /* Sentinel */ }, 440 }; 441 442 U_BOOT_DRIVER(ti_sci) = { 443 .name = "ti_sci", 444 .id = UCLASS_FIRMWARE, 445 .of_match = ti_sci_ids, 446 .probe = ti_sci_probe, 447 .priv_auto_alloc_size = sizeof(struct ti_sci_info), 448 }; 449