blob: 0f1003e167e6ba207c0eb93540b0508e6f3083d6 [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 Takahirofa744002023-10-11 19:07:07 +090041/**
42 * scmi_protocol_is_supported - check availability of protocol
43 * @dev: SCMI agent device
44 * @proto_id: Identifier of protocol
45 *
46 * check if the protocol, @proto_id, is provided by the SCMI agent,
47 * @dev.
48 *
49 * Return: 0 on success, error code otherwise
50 */
51static bool scmi_protocol_is_supported(struct udevice *dev,
52 enum scmi_std_protocol proto_id)
53{
54 struct scmi_agent_priv *priv;
55 int i;
56
57 if (proto_id == SCMI_PROTOCOL_ID_BASE)
58 return true;
59
60 priv = dev_get_uclass_plat(dev);
61 if (!priv) {
62 dev_err(dev, "No priv data found\n");
63 return false;
64 }
65
66 for (i = 0; i < priv->num_protocols; i++)
67 if (priv->protocols[i] == proto_id)
68 return true;
69
70 return false;
71}
72
AKASHI Takahiro6c90f822023-10-11 19:06:58 +090073struct udevice *scmi_get_protocol(struct udevice *dev,
74 enum scmi_std_protocol id)
75{
76 struct scmi_agent_priv *priv;
77 struct udevice *proto;
78
79 priv = dev_get_uclass_plat(dev);
80 if (!priv) {
81 dev_err(dev, "No priv data found\n");
82 return NULL;
83 }
84
85 switch (id) {
AKASHI Takahiro410be2c2023-10-11 19:07:04 +090086 case SCMI_PROTOCOL_ID_BASE:
87 proto = priv->base_dev;
88 break;
AKASHI Takahirodf234cf2023-10-16 14:39:44 +090089 case SCMI_PROTOCOL_ID_POWER_DOMAIN:
90 proto = priv->pwdom_dev;
91 break;
AKASHI Takahiro6c90f822023-10-11 19:06:58 +090092 case SCMI_PROTOCOL_ID_CLOCK:
93 proto = priv->clock_dev;
94 break;
95 case SCMI_PROTOCOL_ID_RESET_DOMAIN:
96 proto = priv->resetdom_dev;
97 break;
98 case SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN:
99 proto = priv->voltagedom_dev;
100 break;
101 default:
102 dev_err(dev, "Protocol not supported\n");
103 proto = NULL;
104 break;
105 }
106 if (proto && device_probe(proto))
107 dev_err(dev, "Probe failed\n");
108
109 return proto;
110}
111
112/**
113 * scmi_add_protocol - add protocol to agent
114 * @dev: SCMI agent device
115 * @proto_id: SCMI protocol ID
116 * @proto: SCMI protocol device
117 *
118 * Associate the protocol instance, @proto, to the agent, @dev,
119 * for later use.
120 *
121 * Return: 0 on success, error code on failure
122 */
123static int scmi_add_protocol(struct udevice *dev,
124 enum scmi_std_protocol proto_id,
125 struct udevice *proto)
126{
127 struct scmi_agent_priv *priv;
128
129 priv = dev_get_uclass_plat(dev);
130 if (!priv) {
131 dev_err(dev, "No priv data found\n");
132 return -ENODEV;
133 }
134
135 switch (proto_id) {
AKASHI Takahiro410be2c2023-10-11 19:07:04 +0900136 case SCMI_PROTOCOL_ID_BASE:
137 priv->base_dev = proto;
138 break;
AKASHI Takahirodf234cf2023-10-16 14:39:44 +0900139 case SCMI_PROTOCOL_ID_POWER_DOMAIN:
140 priv->pwdom_dev = proto;
141 break;
AKASHI Takahiro6c90f822023-10-11 19:06:58 +0900142 case SCMI_PROTOCOL_ID_CLOCK:
143 priv->clock_dev = proto;
144 break;
145 case SCMI_PROTOCOL_ID_RESET_DOMAIN:
146 priv->resetdom_dev = proto;
147 break;
148 case SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN:
149 priv->voltagedom_dev = proto;
150 break;
151 default:
152 dev_err(dev, "Protocol not supported\n");
153 return -EPROTO;
154 }
155
156 return 0;
157}
158
Etienne Carriere02fd1262020-09-09 18:44:00 +0200159int scmi_to_linux_errno(s32 scmi_code)
160{
161 int n;
162
163 if (!scmi_code)
164 return 0;
165
166 for (n = 0; n < ARRAY_SIZE(scmi_linux_errmap); n++)
167 if (scmi_code == scmi_linux_errmap[n].scmi)
AKASHI Takahiroc9371542023-06-13 10:30:45 +0900168 return scmi_linux_errmap[n].errno;
Etienne Carriere02fd1262020-09-09 18:44:00 +0200169
170 return -EPROTO;
171}
172
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900173static struct udevice *find_scmi_protocol_device(struct udevice *dev)
Etienne Carriere2ee64582022-05-31 18:09:20 +0200174{
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900175 struct udevice *parent = NULL, *protocol;
Etienne Carriere2ee64582022-05-31 18:09:20 +0200176
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900177 for (protocol = dev; protocol; protocol = parent) {
178 parent = dev_get_parent(protocol);
179 if (!parent ||
180 device_get_uclass_id(parent) == UCLASS_SCMI_AGENT)
181 break;
182 }
Etienne Carriere2ee64582022-05-31 18:09:20 +0200183
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900184 if (!parent) {
Etienne Carriere2ee64582022-05-31 18:09:20 +0200185 dev_err(dev, "Invalid SCMI device, agent not found\n");
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900186 return NULL;
187 }
Etienne Carriere2ee64582022-05-31 18:09:20 +0200188
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900189 return protocol;
Etienne Carriere2ee64582022-05-31 18:09:20 +0200190}
191
Etienne Carriere02fd1262020-09-09 18:44:00 +0200192static const struct scmi_agent_ops *transport_dev_ops(struct udevice *dev)
193{
194 return (const struct scmi_agent_ops *)dev->driver->ops;
195}
196
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900197/**
198 * scmi_of_get_channel() - Get SCMI channel handle
199 *
200 * @dev: SCMI agent device
201 * @channel: Output reference to the SCMI channel upon success
202 *
203 * On return, @channel will be set.
204 * Return 0 on success and a negative errno on failure
205 */
AKASHI Takahiro589ec9a2023-10-11 19:06:55 +0900206static int scmi_of_get_channel(struct udevice *dev, struct udevice *protocol,
207 struct scmi_channel **channel)
Etienne Carriere187cea12022-05-31 18:09:21 +0200208{
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900209 const struct scmi_agent_ops *ops;
Etienne Carriere187cea12022-05-31 18:09:21 +0200210
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900211 ops = transport_dev_ops(dev);
212 if (ops->of_get_channel)
AKASHI Takahiro589ec9a2023-10-11 19:06:55 +0900213 return ops->of_get_channel(dev, protocol, channel);
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900214 else
215 return -EPROTONOSUPPORT;
216}
217
218int devm_scmi_of_get_channel(struct udevice *dev)
219{
220 struct udevice *protocol;
221 struct scmi_agent_proto_priv *priv;
222 int ret;
223
224 protocol = find_scmi_protocol_device(dev);
225 if (!protocol)
Etienne Carriere187cea12022-05-31 18:09:21 +0200226 return -ENODEV;
227
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900228 priv = dev_get_parent_priv(protocol);
AKASHI Takahiro589ec9a2023-10-11 19:06:55 +0900229 ret = scmi_of_get_channel(protocol->parent, protocol, &priv->channel);
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900230 if (ret == -EPROTONOSUPPORT) {
231 /* Drivers without a get_channel operator don't need a channel ref */
232 priv->channel = NULL;
Etienne Carriere187cea12022-05-31 18:09:21 +0200233
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900234 return 0;
235 }
Etienne Carriere187cea12022-05-31 18:09:21 +0200236
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900237 return ret;
Etienne Carriere187cea12022-05-31 18:09:21 +0200238}
239
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900240/**
241 * scmi_process_msg() - Send and process an SCMI message
242 *
243 * Send a message to an SCMI server.
244 * Caller sets scmi_msg::out_msg_sz to the output message buffer size.
245 *
246 * @dev: SCMI agent device
247 * @channel: Communication channel for the device
248 * @msg: Message structure reference
249 *
250 * On return, scmi_msg::out_msg_sz stores the response payload size.
251 * Return: 0 on success and a negative errno on failure
252 */
253static int scmi_process_msg(struct udevice *dev, struct scmi_channel *channel,
254 struct scmi_msg *msg)
Etienne Carriere02fd1262020-09-09 18:44:00 +0200255{
Etienne Carriere2f26c042022-02-21 09:22:40 +0100256 const struct scmi_agent_ops *ops;
Etienne Carriere2f26c042022-02-21 09:22:40 +0100257
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900258 ops = transport_dev_ops(dev);
259 if (ops->process_msg)
260 return ops->process_msg(dev, channel, msg);
261 else
262 return -EPROTONOSUPPORT;
263}
Etienne Carriere2f26c042022-02-21 09:22:40 +0100264
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900265int devm_scmi_process_msg(struct udevice *dev, struct scmi_msg *msg)
266{
267 struct udevice *protocol;
268 struct scmi_agent_proto_priv *priv;
Etienne Carriere02fd1262020-09-09 18:44:00 +0200269
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900270 protocol = find_scmi_protocol_device(dev);
271 if (!protocol)
272 return -ENODEV;
273
274 priv = dev_get_parent_priv(protocol);
Etienne Carriere02fd1262020-09-09 18:44:00 +0200275
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900276 return scmi_process_msg(protocol->parent, priv->channel, msg);
Etienne Carriere02fd1262020-09-09 18:44:00 +0200277}
278
AKASHI Takahiro410be2c2023-10-11 19:07:04 +0900279/**
280 * scmi_fill_base_info - get base information about SCMI server
281 * @agent: SCMI agent device
282 * @dev: SCMI protocol device
283 *
284 * By using Base protocol commands, collect the base information
285 * about SCMI server.
286 *
287 * Return: 0 on success, error code on failure
288 */
289static int scmi_fill_base_info(struct udevice *agent, struct udevice *dev)
290{
291 struct scmi_agent_priv *priv = dev_get_uclass_plat(agent);
292 int ret;
293
294 ret = scmi_base_protocol_version(dev, &priv->version);
295 if (ret) {
296 dev_err(dev, "protocol_version() failed (%d)\n", ret);
297 return ret;
298 }
299 /* check for required version */
300 if (priv->version < SCMI_BASE_PROTOCOL_VERSION) {
301 dev_err(dev, "base protocol version (%d) lower than expected\n",
302 priv->version);
303 return -EPROTO;
304 }
305
306 ret = scmi_base_protocol_attrs(dev, &priv->num_agents,
307 &priv->num_protocols);
308 if (ret) {
309 dev_err(dev, "protocol_attrs() failed (%d)\n", ret);
310 return ret;
311 }
312 ret = scmi_base_discover_vendor(dev, &priv->vendor);
313 if (ret) {
314 dev_err(dev, "base_discover_vendor() failed (%d)\n", ret);
315 return ret;
316 }
317 ret = scmi_base_discover_sub_vendor(dev, &priv->sub_vendor);
318 if (ret) {
319 if (ret != -EOPNOTSUPP) {
320 dev_err(dev, "base_discover_sub_vendor() failed (%d)\n",
321 ret);
322 return ret;
323 }
324 priv->sub_vendor = "NA";
325 }
326 ret = scmi_base_discover_impl_version(dev, &priv->impl_version);
327 if (ret) {
328 dev_err(dev, "base_discover_impl_version() failed (%d)\n",
329 ret);
330 return ret;
331 }
332
333 ret = scmi_base_discover_agent(dev, 0xffffffff,
334 &priv->agent_id, &priv->agent_name);
335 if (ret) {
336 if (ret != -EOPNOTSUPP) {
337 dev_err(dev,
338 "base_discover_agent() failed for myself (%d)\n",
339 ret);
340 return ret;
341 }
342 priv->agent_id = 0xffffffff;
343 priv->agent_name = "NA";
344 }
345
346 ret = scmi_base_discover_list_protocols(dev, &priv->protocols);
347 if (ret != priv->num_protocols) {
348 dev_err(dev, "base_discover_list_protocols() failed (%d)\n",
349 ret);
350 return -EPROTO;
351 }
352
353 return 0;
354}
355
AKASHI Takahiro6d379152023-10-11 19:06:57 +0900356/*
357 * SCMI agent devices binds devices of various uclasses depending on
358 * the FDT description. scmi_bind_protocol() is a generic bind sequence
359 * called by the uclass at bind stage, that is uclass post_bind.
360 */
361static int scmi_bind_protocols(struct udevice *dev)
362{
363 int ret = 0;
364 ofnode node;
365 const char *name;
AKASHI Takahiro6c90f822023-10-11 19:06:58 +0900366 struct driver *drv;
AKASHI Takahiro410be2c2023-10-11 19:07:04 +0900367 struct udevice *agent, *proto;
368
369 if (!uclass_get_device(UCLASS_SCMI_AGENT, 1, &agent)) {
370 /* This is a second SCMI agent */
371 dev_err(dev, "Cannot have more than one SCMI agent\n");
372 return -EEXIST;
373 }
374
375 /* initialize the device from device tree */
376 drv = DM_DRIVER_GET(scmi_base_drv);
377 name = "scmi-base.0";
378 ret = device_bind(dev, drv, name, NULL, ofnode_null(), &proto);
379 if (ret) {
380 dev_err(dev, "failed to bind base protocol\n");
381 return ret;
382 }
383 ret = scmi_add_protocol(dev, SCMI_PROTOCOL_ID_BASE, proto);
384 if (ret) {
385 dev_err(dev, "failed to add protocol: %s, ret: %d\n",
386 proto->name, ret);
387 return ret;
388 }
389
390 ret = device_probe(proto);
391 if (ret) {
392 dev_err(dev, "failed to probe base protocol\n");
393 return ret;
394 }
395
396 ret = scmi_fill_base_info(dev, proto);
397 if (ret) {
398 dev_err(dev, "failed to get base information\n");
399 return ret;
400 }
AKASHI Takahiro6d379152023-10-11 19:06:57 +0900401
402 dev_for_each_subnode(node, dev) {
AKASHI Takahiro6d379152023-10-11 19:06:57 +0900403 u32 protocol_id;
404
405 if (!ofnode_is_enabled(node))
406 continue;
407
408 if (ofnode_read_u32(node, "reg", &protocol_id))
409 continue;
410
AKASHI Takahiro6c90f822023-10-11 19:06:58 +0900411 drv = NULL;
AKASHI Takahiro6d379152023-10-11 19:06:57 +0900412 name = ofnode_get_name(node);
413 switch (protocol_id) {
AKASHI Takahirodf234cf2023-10-16 14:39:44 +0900414 case SCMI_PROTOCOL_ID_POWER_DOMAIN:
415 if (CONFIG_IS_ENABLED(SCMI_POWER_DOMAIN) &&
416 scmi_protocol_is_supported(dev, protocol_id))
417 drv = DM_DRIVER_GET(scmi_power_domain);
418 break;
AKASHI Takahiro6d379152023-10-11 19:06:57 +0900419 case SCMI_PROTOCOL_ID_CLOCK:
AKASHI Takahirofa744002023-10-11 19:07:07 +0900420 if (CONFIG_IS_ENABLED(CLK_SCMI) &&
421 scmi_protocol_is_supported(dev, protocol_id))
AKASHI Takahiro6d379152023-10-11 19:06:57 +0900422 drv = DM_DRIVER_GET(scmi_clock);
423 break;
424 case SCMI_PROTOCOL_ID_RESET_DOMAIN:
AKASHI Takahirofa744002023-10-11 19:07:07 +0900425 if (IS_ENABLED(CONFIG_RESET_SCMI) &&
426 scmi_protocol_is_supported(dev, protocol_id))
AKASHI Takahiro6d379152023-10-11 19:06:57 +0900427 drv = DM_DRIVER_GET(scmi_reset_domain);
428 break;
429 case SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN:
AKASHI Takahirofa744002023-10-11 19:07:07 +0900430 if (IS_ENABLED(CONFIG_DM_REGULATOR_SCMI) &&
431 scmi_protocol_is_supported(dev, protocol_id)) {
AKASHI Takahiro6d379152023-10-11 19:06:57 +0900432 node = ofnode_find_subnode(node, "regulators");
433 if (!ofnode_valid(node)) {
434 dev_err(dev, "no regulators node\n");
435 return -ENXIO;
436 }
437 drv = DM_DRIVER_GET(scmi_voltage_domain);
438 }
439 break;
440 default:
441 break;
442 }
443
444 if (!drv) {
445 dev_dbg(dev, "Ignore unsupported SCMI protocol %#x\n",
446 protocol_id);
447 continue;
448 }
449
AKASHI Takahiro6c90f822023-10-11 19:06:58 +0900450 ret = device_bind(dev, drv, name, NULL, node, &proto);
451 if (ret) {
452 dev_err(dev, "failed to bind %s protocol\n", drv->name);
AKASHI Takahiro6d379152023-10-11 19:06:57 +0900453 break;
AKASHI Takahiro6c90f822023-10-11 19:06:58 +0900454 }
455 ret = scmi_add_protocol(dev, protocol_id, proto);
456 if (ret) {
457 dev_err(dev, "failed to add protocol: %s, ret: %d\n",
458 proto->name, ret);
459 break;
460 }
AKASHI Takahiro6d379152023-10-11 19:06:57 +0900461 }
462
463 return ret;
464}
465
Etienne Carriere02fd1262020-09-09 18:44:00 +0200466UCLASS_DRIVER(scmi_agent) = {
467 .id = UCLASS_SCMI_AGENT,
468 .name = "scmi_agent",
469 .post_bind = scmi_bind_protocols,
AKASHI Takahiro6c90f822023-10-11 19:06:58 +0900470 .per_device_plat_auto = sizeof(struct scmi_agent_priv),
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900471 .per_child_auto = sizeof(struct scmi_agent_proto_priv),
Etienne Carriere02fd1262020-09-09 18:44:00 +0200472};