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