1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Copyright (C) 2020 Linaro Limited. 4 */ 5 6 #include <common.h> 7 #include <dm.h> 8 #include <errno.h> 9 #include <mailbox.h> 10 #include <scmi_agent.h> 11 #include <scmi_agent-uclass.h> 12 #include <dm/devres.h> 13 #include <linux/compat.h> 14 15 #include "smt.h" 16 17 #define TIMEOUT_US_10MS 10000 18 19 /** 20 * struct scmi_mbox_channel - Description of an SCMI mailbox transport 21 * @smt: Shared memory buffer 22 * @mbox: Mailbox channel description 23 * @timeout_us: Timeout in microseconds for the mailbox transfer 24 */ 25 struct scmi_mbox_channel { 26 struct scmi_smt smt; 27 struct mbox_chan mbox; 28 ulong timeout_us; 29 }; 30 31 static int scmi_mbox_process_msg(struct udevice *dev, struct scmi_msg *msg) 32 { 33 struct scmi_mbox_channel *chan = dev_get_priv(dev); 34 int ret; 35 36 ret = scmi_write_msg_to_smt(dev, &chan->smt, msg); 37 if (ret) 38 return ret; 39 40 /* Give shm addr to mbox in case it is meaningful */ 41 ret = mbox_send(&chan->mbox, chan->smt.buf); 42 if (ret) { 43 dev_err(dev, "Message send failed: %d\n", ret); 44 goto out; 45 } 46 47 /* Receive the response */ 48 ret = mbox_recv(&chan->mbox, chan->smt.buf, chan->timeout_us); 49 if (ret) { 50 dev_err(dev, "Response failed: %d, abort\n", ret); 51 goto out; 52 } 53 54 ret = scmi_read_resp_from_smt(dev, &chan->smt, msg); 55 56 out: 57 scmi_clear_smt_channel(&chan->smt); 58 59 return ret; 60 } 61 62 int scmi_mbox_probe(struct udevice *dev) 63 { 64 struct scmi_mbox_channel *chan = dev_get_priv(dev); 65 int ret; 66 67 chan->timeout_us = TIMEOUT_US_10MS; 68 69 ret = mbox_get_by_index(dev, 0, &chan->mbox); 70 if (ret) { 71 dev_err(dev, "Failed to find mailbox: %d\n", ret); 72 goto out; 73 } 74 75 ret = scmi_dt_get_smt_buffer(dev, &chan->smt); 76 if (ret) 77 dev_err(dev, "Failed to get shm resources: %d\n", ret); 78 79 out: 80 if (ret) 81 devm_kfree(dev, chan); 82 83 return ret; 84 } 85 86 static const struct udevice_id scmi_mbox_ids[] = { 87 { .compatible = "arm,scmi" }, 88 { } 89 }; 90 91 static const struct scmi_agent_ops scmi_mbox_ops = { 92 .process_msg = scmi_mbox_process_msg, 93 }; 94 95 U_BOOT_DRIVER(scmi_mbox) = { 96 .name = "scmi-over-mailbox", 97 .id = UCLASS_SCMI_AGENT, 98 .of_match = scmi_mbox_ids, 99 .priv_auto_alloc_size = sizeof(struct scmi_mbox_channel), 100 .probe = scmi_mbox_probe, 101 .ops = &scmi_mbox_ops, 102 }; 103