]>
Commit | Line | Data |
---|---|---|
1e35913a EC |
1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* | |
3 | * Copyright (C) 2020 Linaro Limited. | |
4 | */ | |
5 | ||
9f5e4aa6 PD |
6 | #define LOG_CATEGORY UCLASS_SCMI_AGENT |
7 | ||
d678a59d | 8 | #include <common.h> |
1e35913a EC |
9 | #include <dm.h> |
10 | #include <errno.h> | |
11 | #include <scmi_agent.h> | |
12 | #include <scmi_agent-uclass.h> | |
13 | #include <dm/devres.h> | |
1b9ad519 | 14 | #include <dm/device_compat.h> |
1e35913a EC |
15 | #include <dm/device-internal.h> |
16 | #include <linux/arm-smccc.h> | |
17 | #include <linux/compat.h> | |
18 | ||
19 | #include "smt.h" | |
20 | ||
21 | #define SMCCC_RET_NOT_SUPPORTED ((unsigned long)-1) | |
22 | ||
23 | /** | |
24 | * struct scmi_smccc_channel - Description of an SCMI SMCCC transport | |
25 | * @func_id: SMCCC function ID used by the SCMI transport | |
26 | * @smt: Shared memory buffer | |
27 | */ | |
28 | struct scmi_smccc_channel { | |
29 | ulong func_id; | |
30 | struct scmi_smt smt; | |
31 | }; | |
32 | ||
57b812fc EC |
33 | /** |
34 | * struct scmi_channel - Channel instance referenced in SCMI drivers | |
35 | * @ref: Reference to local channel instance | |
36 | **/ | |
37 | struct scmi_channel { | |
38 | struct scmi_smccc_channel ref; | |
39 | }; | |
40 | ||
85dc5828 EC |
41 | static int scmi_smccc_process_msg(struct udevice *dev, |
42 | struct scmi_channel *channel, | |
43 | struct scmi_msg *msg) | |
1e35913a | 44 | { |
c08decd2 | 45 | struct scmi_smccc_channel *chan = &channel->ref; |
1e35913a EC |
46 | struct arm_smccc_res res; |
47 | int ret; | |
48 | ||
49 | ret = scmi_write_msg_to_smt(dev, &chan->smt, msg); | |
50 | if (ret) | |
51 | return ret; | |
52 | ||
53 | arm_smccc_smc(chan->func_id, 0, 0, 0, 0, 0, 0, 0, &res); | |
54 | if (res.a0 == SMCCC_RET_NOT_SUPPORTED) | |
55 | ret = -ENXIO; | |
56 | else | |
57 | ret = scmi_read_resp_from_smt(dev, &chan->smt, msg); | |
58 | ||
59 | scmi_clear_smt_channel(&chan->smt); | |
60 | ||
61 | return ret; | |
62 | } | |
63 | ||
57b812fc | 64 | static int setup_channel(struct udevice *dev, struct scmi_smccc_channel *chan) |
1e35913a | 65 | { |
1e35913a EC |
66 | u32 func_id; |
67 | int ret; | |
68 | ||
69 | if (dev_read_u32(dev, "arm,smc-id", &func_id)) { | |
70 | dev_err(dev, "Missing property func-id\n"); | |
71 | return -EINVAL; | |
72 | } | |
73 | ||
74 | chan->func_id = func_id; | |
75 | ||
76 | ret = scmi_dt_get_smt_buffer(dev, &chan->smt); | |
32190a95 | 77 | if (ret) |
1e35913a | 78 | dev_err(dev, "Failed to get smt resources: %d\n", ret); |
1e35913a | 79 | |
32190a95 | 80 | return ret; |
1e35913a EC |
81 | } |
82 | ||
57b812fc | 83 | static int scmi_smccc_get_channel(struct udevice *dev, |
689204be | 84 | struct udevice *protocol, |
57b812fc EC |
85 | struct scmi_channel **channel) |
86 | { | |
eebb967d | 87 | struct scmi_smccc_channel *base_chan = dev_get_plat(dev); |
57b812fc EC |
88 | struct scmi_smccc_channel *chan; |
89 | u32 func_id; | |
90 | int ret; | |
91 | ||
689204be | 92 | if (dev_read_u32(protocol, "arm,smc-id", &func_id)) { |
57b812fc EC |
93 | /* Uses agent base channel */ |
94 | *channel = container_of(base_chan, struct scmi_channel, ref); | |
95 | ||
96 | return 0; | |
97 | } | |
98 | ||
99 | /* Setup a dedicated channel */ | |
100 | chan = calloc(1, sizeof(*chan)); | |
101 | if (!chan) | |
102 | return -ENOMEM; | |
103 | ||
689204be | 104 | ret = setup_channel(protocol, chan); |
57b812fc EC |
105 | if (ret) { |
106 | free(chan); | |
107 | return ret; | |
108 | } | |
109 | ||
110 | *channel = container_of(chan, struct scmi_channel, ref); | |
111 | ||
112 | return 0; | |
113 | } | |
114 | ||
115 | static int scmi_smccc_of_to_plat(struct udevice *dev) | |
116 | { | |
117 | struct scmi_smccc_channel *chan = dev_get_plat(dev); | |
118 | ||
119 | return setup_channel(dev, chan); | |
120 | } | |
121 | ||
1e35913a EC |
122 | static const struct udevice_id scmi_smccc_ids[] = { |
123 | { .compatible = "arm,scmi-smc" }, | |
124 | { } | |
125 | }; | |
126 | ||
127 | static const struct scmi_agent_ops scmi_smccc_ops = { | |
57b812fc | 128 | .of_get_channel = scmi_smccc_get_channel, |
1e35913a EC |
129 | .process_msg = scmi_smccc_process_msg, |
130 | }; | |
131 | ||
132 | U_BOOT_DRIVER(scmi_smccc) = { | |
133 | .name = "scmi-over-smccc", | |
134 | .id = UCLASS_SCMI_AGENT, | |
135 | .of_match = scmi_smccc_ids, | |
3de5aef4 EC |
136 | .plat_auto = sizeof(struct scmi_smccc_channel), |
137 | .of_to_plat = scmi_smccc_of_to_plat, | |
1e35913a EC |
138 | .ops = &scmi_smccc_ops, |
139 | }; |