xref: /rk3399_rockchip-uboot/drivers/firmware/scmi/mailbox_agent.c (revision c2abcd78e97ff7668d953bffb983ccfd72d47714)
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