blob: b4d008835180f9a1bf6530cc9604bdd05bfd7e68 [file] [log] [blame]
Etienne Carriere02fd1262020-09-09 18:44:00 +02001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (C) 2020 Linaro Limited.
4 */
5
Patrick Delaunay5dd84d42021-02-24 11:19:44 +01006#define LOG_CATEGORY UCLASS_SCMI_AGENT
7
Etienne Carriere02fd1262020-09-09 18:44:00 +02008#include <common.h>
9#include <dm.h>
10#include <errno.h>
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +090011#include <scmi_agent.h>
Etienne Carriere02fd1262020-09-09 18:44:00 +020012#include <scmi_agent-uclass.h>
13#include <scmi_protocols.h>
Patrick Delaunayd4c9f682021-02-24 11:19:45 +010014#include <dm/device_compat.h>
Etienne Carriere02fd1262020-09-09 18:44:00 +020015#include <dm/device-internal.h>
16#include <linux/compat.h>
17
18/**
19 * struct error_code - Helper structure for SCMI error code conversion
20 * @scmi: SCMI error code
21 * @errno: Related standard error number
22 */
23struct error_code {
24 int scmi;
25 int errno;
26};
27
28static const struct error_code scmi_linux_errmap[] = {
29 { .scmi = SCMI_NOT_SUPPORTED, .errno = -EOPNOTSUPP, },
30 { .scmi = SCMI_INVALID_PARAMETERS, .errno = -EINVAL, },
31 { .scmi = SCMI_DENIED, .errno = -EACCES, },
32 { .scmi = SCMI_NOT_FOUND, .errno = -ENOENT, },
33 { .scmi = SCMI_OUT_OF_RANGE, .errno = -ERANGE, },
34 { .scmi = SCMI_BUSY, .errno = -EBUSY, },
35 { .scmi = SCMI_COMMS_ERROR, .errno = -ECOMM, },
36 { .scmi = SCMI_GENERIC_ERROR, .errno = -EIO, },
37 { .scmi = SCMI_HARDWARE_ERROR, .errno = -EREMOTEIO, },
38 { .scmi = SCMI_PROTOCOL_ERROR, .errno = -EPROTO, },
39};
40
AKASHI Takahiro6c90f822023-10-11 19:06:58 +090041struct udevice *scmi_get_protocol(struct udevice *dev,
42 enum scmi_std_protocol id)
43{
44 struct scmi_agent_priv *priv;
45 struct udevice *proto;
46
47 priv = dev_get_uclass_plat(dev);
48 if (!priv) {
49 dev_err(dev, "No priv data found\n");
50 return NULL;
51 }
52
53 switch (id) {
54 case SCMI_PROTOCOL_ID_CLOCK:
55 proto = priv->clock_dev;
56 break;
57 case SCMI_PROTOCOL_ID_RESET_DOMAIN:
58 proto = priv->resetdom_dev;
59 break;
60 case SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN:
61 proto = priv->voltagedom_dev;
62 break;
63 default:
64 dev_err(dev, "Protocol not supported\n");
65 proto = NULL;
66 break;
67 }
68 if (proto && device_probe(proto))
69 dev_err(dev, "Probe failed\n");
70
71 return proto;
72}
73
74/**
75 * scmi_add_protocol - add protocol to agent
76 * @dev: SCMI agent device
77 * @proto_id: SCMI protocol ID
78 * @proto: SCMI protocol device
79 *
80 * Associate the protocol instance, @proto, to the agent, @dev,
81 * for later use.
82 *
83 * Return: 0 on success, error code on failure
84 */
85static int scmi_add_protocol(struct udevice *dev,
86 enum scmi_std_protocol proto_id,
87 struct udevice *proto)
88{
89 struct scmi_agent_priv *priv;
90
91 priv = dev_get_uclass_plat(dev);
92 if (!priv) {
93 dev_err(dev, "No priv data found\n");
94 return -ENODEV;
95 }
96
97 switch (proto_id) {
98 case SCMI_PROTOCOL_ID_CLOCK:
99 priv->clock_dev = proto;
100 break;
101 case SCMI_PROTOCOL_ID_RESET_DOMAIN:
102 priv->resetdom_dev = proto;
103 break;
104 case SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN:
105 priv->voltagedom_dev = proto;
106 break;
107 default:
108 dev_err(dev, "Protocol not supported\n");
109 return -EPROTO;
110 }
111
112 return 0;
113}
114
Etienne Carriere02fd1262020-09-09 18:44:00 +0200115int scmi_to_linux_errno(s32 scmi_code)
116{
117 int n;
118
119 if (!scmi_code)
120 return 0;
121
122 for (n = 0; n < ARRAY_SIZE(scmi_linux_errmap); n++)
123 if (scmi_code == scmi_linux_errmap[n].scmi)
AKASHI Takahiroc9371542023-06-13 10:30:45 +0900124 return scmi_linux_errmap[n].errno;
Etienne Carriere02fd1262020-09-09 18:44:00 +0200125
126 return -EPROTO;
127}
128
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900129static struct udevice *find_scmi_protocol_device(struct udevice *dev)
Etienne Carriere2ee64582022-05-31 18:09:20 +0200130{
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900131 struct udevice *parent = NULL, *protocol;
Etienne Carriere2ee64582022-05-31 18:09:20 +0200132
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900133 for (protocol = dev; protocol; protocol = parent) {
134 parent = dev_get_parent(protocol);
135 if (!parent ||
136 device_get_uclass_id(parent) == UCLASS_SCMI_AGENT)
137 break;
138 }
Etienne Carriere2ee64582022-05-31 18:09:20 +0200139
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900140 if (!parent) {
Etienne Carriere2ee64582022-05-31 18:09:20 +0200141 dev_err(dev, "Invalid SCMI device, agent not found\n");
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900142 return NULL;
143 }
Etienne Carriere2ee64582022-05-31 18:09:20 +0200144
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900145 return protocol;
Etienne Carriere2ee64582022-05-31 18:09:20 +0200146}
147
Etienne Carriere02fd1262020-09-09 18:44:00 +0200148static const struct scmi_agent_ops *transport_dev_ops(struct udevice *dev)
149{
150 return (const struct scmi_agent_ops *)dev->driver->ops;
151}
152
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900153/**
154 * scmi_of_get_channel() - Get SCMI channel handle
155 *
156 * @dev: SCMI agent device
157 * @channel: Output reference to the SCMI channel upon success
158 *
159 * On return, @channel will be set.
160 * Return 0 on success and a negative errno on failure
161 */
AKASHI Takahiro589ec9a2023-10-11 19:06:55 +0900162static int scmi_of_get_channel(struct udevice *dev, struct udevice *protocol,
163 struct scmi_channel **channel)
Etienne Carriere187cea12022-05-31 18:09:21 +0200164{
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900165 const struct scmi_agent_ops *ops;
Etienne Carriere187cea12022-05-31 18:09:21 +0200166
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900167 ops = transport_dev_ops(dev);
168 if (ops->of_get_channel)
AKASHI Takahiro589ec9a2023-10-11 19:06:55 +0900169 return ops->of_get_channel(dev, protocol, channel);
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900170 else
171 return -EPROTONOSUPPORT;
172}
173
174int devm_scmi_of_get_channel(struct udevice *dev)
175{
176 struct udevice *protocol;
177 struct scmi_agent_proto_priv *priv;
178 int ret;
179
180 protocol = find_scmi_protocol_device(dev);
181 if (!protocol)
Etienne Carriere187cea12022-05-31 18:09:21 +0200182 return -ENODEV;
183
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900184 priv = dev_get_parent_priv(protocol);
AKASHI Takahiro589ec9a2023-10-11 19:06:55 +0900185 ret = scmi_of_get_channel(protocol->parent, protocol, &priv->channel);
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900186 if (ret == -EPROTONOSUPPORT) {
187 /* Drivers without a get_channel operator don't need a channel ref */
188 priv->channel = NULL;
Etienne Carriere187cea12022-05-31 18:09:21 +0200189
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900190 return 0;
191 }
Etienne Carriere187cea12022-05-31 18:09:21 +0200192
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900193 return ret;
Etienne Carriere187cea12022-05-31 18:09:21 +0200194}
195
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900196/**
197 * scmi_process_msg() - Send and process an SCMI message
198 *
199 * Send a message to an SCMI server.
200 * Caller sets scmi_msg::out_msg_sz to the output message buffer size.
201 *
202 * @dev: SCMI agent device
203 * @channel: Communication channel for the device
204 * @msg: Message structure reference
205 *
206 * On return, scmi_msg::out_msg_sz stores the response payload size.
207 * Return: 0 on success and a negative errno on failure
208 */
209static int scmi_process_msg(struct udevice *dev, struct scmi_channel *channel,
210 struct scmi_msg *msg)
Etienne Carriere02fd1262020-09-09 18:44:00 +0200211{
Etienne Carriere2f26c042022-02-21 09:22:40 +0100212 const struct scmi_agent_ops *ops;
Etienne Carriere2f26c042022-02-21 09:22:40 +0100213
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900214 ops = transport_dev_ops(dev);
215 if (ops->process_msg)
216 return ops->process_msg(dev, channel, msg);
217 else
218 return -EPROTONOSUPPORT;
219}
Etienne Carriere2f26c042022-02-21 09:22:40 +0100220
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900221int devm_scmi_process_msg(struct udevice *dev, struct scmi_msg *msg)
222{
223 struct udevice *protocol;
224 struct scmi_agent_proto_priv *priv;
Etienne Carriere02fd1262020-09-09 18:44:00 +0200225
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900226 protocol = find_scmi_protocol_device(dev);
227 if (!protocol)
228 return -ENODEV;
229
230 priv = dev_get_parent_priv(protocol);
Etienne Carriere02fd1262020-09-09 18:44:00 +0200231
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900232 return scmi_process_msg(protocol->parent, priv->channel, msg);
Etienne Carriere02fd1262020-09-09 18:44:00 +0200233}
234
AKASHI Takahiro6d379152023-10-11 19:06:57 +0900235/*
236 * SCMI agent devices binds devices of various uclasses depending on
237 * the FDT description. scmi_bind_protocol() is a generic bind sequence
238 * called by the uclass at bind stage, that is uclass post_bind.
239 */
240static int scmi_bind_protocols(struct udevice *dev)
241{
242 int ret = 0;
243 ofnode node;
244 const char *name;
AKASHI Takahiro6c90f822023-10-11 19:06:58 +0900245 struct driver *drv;
246 struct udevice *proto;
AKASHI Takahiro6d379152023-10-11 19:06:57 +0900247
248 dev_for_each_subnode(node, dev) {
AKASHI Takahiro6d379152023-10-11 19:06:57 +0900249 u32 protocol_id;
250
251 if (!ofnode_is_enabled(node))
252 continue;
253
254 if (ofnode_read_u32(node, "reg", &protocol_id))
255 continue;
256
AKASHI Takahiro6c90f822023-10-11 19:06:58 +0900257 drv = NULL;
AKASHI Takahiro6d379152023-10-11 19:06:57 +0900258 name = ofnode_get_name(node);
259 switch (protocol_id) {
260 case SCMI_PROTOCOL_ID_CLOCK:
261 if (CONFIG_IS_ENABLED(CLK_SCMI))
262 drv = DM_DRIVER_GET(scmi_clock);
263 break;
264 case SCMI_PROTOCOL_ID_RESET_DOMAIN:
265 if (IS_ENABLED(CONFIG_RESET_SCMI))
266 drv = DM_DRIVER_GET(scmi_reset_domain);
267 break;
268 case SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN:
269 if (IS_ENABLED(CONFIG_DM_REGULATOR_SCMI)) {
270 node = ofnode_find_subnode(node, "regulators");
271 if (!ofnode_valid(node)) {
272 dev_err(dev, "no regulators node\n");
273 return -ENXIO;
274 }
275 drv = DM_DRIVER_GET(scmi_voltage_domain);
276 }
277 break;
278 default:
279 break;
280 }
281
282 if (!drv) {
283 dev_dbg(dev, "Ignore unsupported SCMI protocol %#x\n",
284 protocol_id);
285 continue;
286 }
287
AKASHI Takahiro6c90f822023-10-11 19:06:58 +0900288 ret = device_bind(dev, drv, name, NULL, node, &proto);
289 if (ret) {
290 dev_err(dev, "failed to bind %s protocol\n", drv->name);
AKASHI Takahiro6d379152023-10-11 19:06:57 +0900291 break;
AKASHI Takahiro6c90f822023-10-11 19:06:58 +0900292 }
293 ret = scmi_add_protocol(dev, protocol_id, proto);
294 if (ret) {
295 dev_err(dev, "failed to add protocol: %s, ret: %d\n",
296 proto->name, ret);
297 break;
298 }
AKASHI Takahiro6d379152023-10-11 19:06:57 +0900299 }
300
301 return ret;
302}
303
Etienne Carriere02fd1262020-09-09 18:44:00 +0200304UCLASS_DRIVER(scmi_agent) = {
305 .id = UCLASS_SCMI_AGENT,
306 .name = "scmi_agent",
307 .post_bind = scmi_bind_protocols,
AKASHI Takahiro6c90f822023-10-11 19:06:58 +0900308 .per_device_plat_auto = sizeof(struct scmi_agent_priv),
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900309 .per_child_auto = sizeof(struct scmi_agent_proto_priv),
Etienne Carriere02fd1262020-09-09 18:44:00 +0200310};