1533e551cSEtienne Carriere // SPDX-License-Identifier: GPL-2.0+
2533e551cSEtienne Carriere /*
3533e551cSEtienne Carriere * Copyright (C) 2020 Linaro Limited.
4533e551cSEtienne Carriere */
5533e551cSEtienne Carriere
6533e551cSEtienne Carriere #include <common.h>
7533e551cSEtienne Carriere #include <dm.h>
8*c2abcd78SSean Anderson #include <dm/device_compat.h>
9533e551cSEtienne Carriere #include <errno.h>
10533e551cSEtienne Carriere #include <mailbox.h>
11533e551cSEtienne Carriere #include <scmi_agent.h>
12533e551cSEtienne Carriere #include <scmi_agent-uclass.h>
13533e551cSEtienne Carriere #include <dm/devres.h>
14533e551cSEtienne Carriere #include <linux/compat.h>
15533e551cSEtienne Carriere
16533e551cSEtienne Carriere #include "smt.h"
17533e551cSEtienne Carriere
18533e551cSEtienne Carriere #define TIMEOUT_US_10MS 10000
19533e551cSEtienne Carriere
20533e551cSEtienne Carriere /**
21533e551cSEtienne Carriere * struct scmi_mbox_channel - Description of an SCMI mailbox transport
22533e551cSEtienne Carriere * @smt: Shared memory buffer
23533e551cSEtienne Carriere * @mbox: Mailbox channel description
24533e551cSEtienne Carriere * @timeout_us: Timeout in microseconds for the mailbox transfer
25533e551cSEtienne Carriere */
26533e551cSEtienne Carriere struct scmi_mbox_channel {
27533e551cSEtienne Carriere struct scmi_smt smt;
28533e551cSEtienne Carriere struct mbox_chan mbox;
29533e551cSEtienne Carriere ulong timeout_us;
30533e551cSEtienne Carriere };
31533e551cSEtienne Carriere
scmi_mbox_process_msg(struct udevice * dev,struct scmi_msg * msg)32533e551cSEtienne Carriere static int scmi_mbox_process_msg(struct udevice *dev, struct scmi_msg *msg)
33533e551cSEtienne Carriere {
34533e551cSEtienne Carriere struct scmi_mbox_channel *chan = dev_get_priv(dev);
35533e551cSEtienne Carriere int ret;
36533e551cSEtienne Carriere
37533e551cSEtienne Carriere ret = scmi_write_msg_to_smt(dev, &chan->smt, msg);
38533e551cSEtienne Carriere if (ret)
39533e551cSEtienne Carriere return ret;
40533e551cSEtienne Carriere
41533e551cSEtienne Carriere /* Give shm addr to mbox in case it is meaningful */
42533e551cSEtienne Carriere ret = mbox_send(&chan->mbox, chan->smt.buf);
43533e551cSEtienne Carriere if (ret) {
44533e551cSEtienne Carriere dev_err(dev, "Message send failed: %d\n", ret);
45533e551cSEtienne Carriere goto out;
46533e551cSEtienne Carriere }
47533e551cSEtienne Carriere
48533e551cSEtienne Carriere /* Receive the response */
49533e551cSEtienne Carriere ret = mbox_recv(&chan->mbox, chan->smt.buf, chan->timeout_us);
50533e551cSEtienne Carriere if (ret) {
51533e551cSEtienne Carriere dev_err(dev, "Response failed: %d, abort\n", ret);
52533e551cSEtienne Carriere goto out;
53533e551cSEtienne Carriere }
54533e551cSEtienne Carriere
55533e551cSEtienne Carriere ret = scmi_read_resp_from_smt(dev, &chan->smt, msg);
56533e551cSEtienne Carriere
57533e551cSEtienne Carriere out:
58533e551cSEtienne Carriere scmi_clear_smt_channel(&chan->smt);
59533e551cSEtienne Carriere
60533e551cSEtienne Carriere return ret;
61533e551cSEtienne Carriere }
62533e551cSEtienne Carriere
scmi_mbox_probe(struct udevice * dev)63533e551cSEtienne Carriere int scmi_mbox_probe(struct udevice *dev)
64533e551cSEtienne Carriere {
65533e551cSEtienne Carriere struct scmi_mbox_channel *chan = dev_get_priv(dev);
66533e551cSEtienne Carriere int ret;
67533e551cSEtienne Carriere
68533e551cSEtienne Carriere chan->timeout_us = TIMEOUT_US_10MS;
69533e551cSEtienne Carriere
70533e551cSEtienne Carriere ret = mbox_get_by_index(dev, 0, &chan->mbox);
71533e551cSEtienne Carriere if (ret) {
72533e551cSEtienne Carriere dev_err(dev, "Failed to find mailbox: %d\n", ret);
73533e551cSEtienne Carriere goto out;
74533e551cSEtienne Carriere }
75533e551cSEtienne Carriere
76533e551cSEtienne Carriere ret = scmi_dt_get_smt_buffer(dev, &chan->smt);
77533e551cSEtienne Carriere if (ret)
78533e551cSEtienne Carriere dev_err(dev, "Failed to get shm resources: %d\n", ret);
79533e551cSEtienne Carriere
80533e551cSEtienne Carriere out:
81533e551cSEtienne Carriere if (ret)
82533e551cSEtienne Carriere devm_kfree(dev, chan);
83533e551cSEtienne Carriere
84533e551cSEtienne Carriere return ret;
85533e551cSEtienne Carriere }
86533e551cSEtienne Carriere
87533e551cSEtienne Carriere static const struct udevice_id scmi_mbox_ids[] = {
88533e551cSEtienne Carriere { .compatible = "arm,scmi" },
89533e551cSEtienne Carriere { }
90533e551cSEtienne Carriere };
91533e551cSEtienne Carriere
92533e551cSEtienne Carriere static const struct scmi_agent_ops scmi_mbox_ops = {
93533e551cSEtienne Carriere .process_msg = scmi_mbox_process_msg,
94533e551cSEtienne Carriere };
95533e551cSEtienne Carriere
96533e551cSEtienne Carriere U_BOOT_DRIVER(scmi_mbox) = {
97533e551cSEtienne Carriere .name = "scmi-over-mailbox",
98533e551cSEtienne Carriere .id = UCLASS_SCMI_AGENT,
99533e551cSEtienne Carriere .of_match = scmi_mbox_ids,
100533e551cSEtienne Carriere .priv_auto_alloc_size = sizeof(struct scmi_mbox_channel),
101533e551cSEtienne Carriere .probe = scmi_mbox_probe,
102533e551cSEtienne Carriere .ops = &scmi_mbox_ops,
103533e551cSEtienne Carriere };
104