blob: e7ec2c108e69022ff3744c0b9d26809171307bee [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 <dm.h>
9#include <errno.h>
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +090010#include <scmi_agent.h>
Etienne Carriere02fd1262020-09-09 18:44:00 +020011#include <scmi_agent-uclass.h>
12#include <scmi_protocols.h>
Patrick Delaunayd4c9f682021-02-24 11:19:45 +010013#include <dm/device_compat.h>
Etienne Carriere02fd1262020-09-09 18:44:00 +020014#include <dm/device-internal.h>
15#include <linux/compat.h>
16
17/**
18 * struct error_code - Helper structure for SCMI error code conversion
19 * @scmi: SCMI error code
20 * @errno: Related standard error number
21 */
22struct error_code {
23 int scmi;
24 int errno;
25};
26
27static const struct error_code scmi_linux_errmap[] = {
28 { .scmi = SCMI_NOT_SUPPORTED, .errno = -EOPNOTSUPP, },
29 { .scmi = SCMI_INVALID_PARAMETERS, .errno = -EINVAL, },
30 { .scmi = SCMI_DENIED, .errno = -EACCES, },
31 { .scmi = SCMI_NOT_FOUND, .errno = -ENOENT, },
32 { .scmi = SCMI_OUT_OF_RANGE, .errno = -ERANGE, },
33 { .scmi = SCMI_BUSY, .errno = -EBUSY, },
34 { .scmi = SCMI_COMMS_ERROR, .errno = -ECOMM, },
35 { .scmi = SCMI_GENERIC_ERROR, .errno = -EIO, },
36 { .scmi = SCMI_HARDWARE_ERROR, .errno = -EREMOTEIO, },
37 { .scmi = SCMI_PROTOCOL_ERROR, .errno = -EPROTO, },
38};
39
AKASHI Takahirofa744002023-10-11 19:07:07 +090040/**
41 * scmi_protocol_is_supported - check availability of protocol
42 * @dev: SCMI agent device
43 * @proto_id: Identifier of protocol
44 *
45 * check if the protocol, @proto_id, is provided by the SCMI agent,
46 * @dev.
47 *
48 * Return: 0 on success, error code otherwise
49 */
50static bool scmi_protocol_is_supported(struct udevice *dev,
51 enum scmi_std_protocol proto_id)
52{
53 struct scmi_agent_priv *priv;
54 int i;
55
56 if (proto_id == SCMI_PROTOCOL_ID_BASE)
57 return true;
58
59 priv = dev_get_uclass_plat(dev);
60 if (!priv) {
61 dev_err(dev, "No priv data found\n");
62 return false;
63 }
64
65 for (i = 0; i < priv->num_protocols; i++)
66 if (priv->protocols[i] == proto_id)
67 return true;
68
69 return false;
70}
71
AKASHI Takahiro6c90f822023-10-11 19:06:58 +090072struct udevice *scmi_get_protocol(struct udevice *dev,
73 enum scmi_std_protocol id)
74{
75 struct scmi_agent_priv *priv;
76 struct udevice *proto;
77
78 priv = dev_get_uclass_plat(dev);
79 if (!priv) {
80 dev_err(dev, "No priv data found\n");
81 return NULL;
82 }
83
84 switch (id) {
AKASHI Takahiro410be2c2023-10-11 19:07:04 +090085 case SCMI_PROTOCOL_ID_BASE:
86 proto = priv->base_dev;
87 break;
AKASHI Takahirodf234cf2023-10-16 14:39:44 +090088 case SCMI_PROTOCOL_ID_POWER_DOMAIN:
89 proto = priv->pwdom_dev;
90 break;
AKASHI Takahiro6c90f822023-10-11 19:06:58 +090091 case SCMI_PROTOCOL_ID_CLOCK:
92 proto = priv->clock_dev;
93 break;
94 case SCMI_PROTOCOL_ID_RESET_DOMAIN:
95 proto = priv->resetdom_dev;
96 break;
97 case SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN:
98 proto = priv->voltagedom_dev;
99 break;
Alice Guo52291d52025-04-28 18:37:27 +0800100 case SCMI_PROTOCOL_ID_PINCTRL:
101 proto = priv->pinctrl_dev;
102 break;
AKASHI Takahiro6c90f822023-10-11 19:06:58 +0900103 default:
104 dev_err(dev, "Protocol not supported\n");
105 proto = NULL;
106 break;
107 }
108 if (proto && device_probe(proto))
109 dev_err(dev, "Probe failed\n");
110
111 return proto;
112}
113
114/**
115 * scmi_add_protocol - add protocol to agent
116 * @dev: SCMI agent device
117 * @proto_id: SCMI protocol ID
118 * @proto: SCMI protocol device
119 *
120 * Associate the protocol instance, @proto, to the agent, @dev,
121 * for later use.
122 *
123 * Return: 0 on success, error code on failure
124 */
125static int scmi_add_protocol(struct udevice *dev,
126 enum scmi_std_protocol proto_id,
127 struct udevice *proto)
128{
129 struct scmi_agent_priv *priv;
130
131 priv = dev_get_uclass_plat(dev);
132 if (!priv) {
133 dev_err(dev, "No priv data found\n");
134 return -ENODEV;
135 }
136
137 switch (proto_id) {
AKASHI Takahiro410be2c2023-10-11 19:07:04 +0900138 case SCMI_PROTOCOL_ID_BASE:
139 priv->base_dev = proto;
140 break;
AKASHI Takahirodf234cf2023-10-16 14:39:44 +0900141 case SCMI_PROTOCOL_ID_POWER_DOMAIN:
142 priv->pwdom_dev = proto;
143 break;
AKASHI Takahiro6c90f822023-10-11 19:06:58 +0900144 case SCMI_PROTOCOL_ID_CLOCK:
145 priv->clock_dev = proto;
146 break;
147 case SCMI_PROTOCOL_ID_RESET_DOMAIN:
148 priv->resetdom_dev = proto;
149 break;
150 case SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN:
151 priv->voltagedom_dev = proto;
152 break;
Alice Guo52291d52025-04-28 18:37:27 +0800153 case SCMI_PROTOCOL_ID_PINCTRL:
154 priv->pinctrl_dev = proto;
155 break;
AKASHI Takahiro6c90f822023-10-11 19:06:58 +0900156 default:
157 dev_err(dev, "Protocol not supported\n");
158 return -EPROTO;
159 }
160
161 return 0;
162}
163
Etienne Carriere02fd1262020-09-09 18:44:00 +0200164int scmi_to_linux_errno(s32 scmi_code)
165{
166 int n;
167
168 if (!scmi_code)
169 return 0;
170
171 for (n = 0; n < ARRAY_SIZE(scmi_linux_errmap); n++)
172 if (scmi_code == scmi_linux_errmap[n].scmi)
AKASHI Takahiroc9371542023-06-13 10:30:45 +0900173 return scmi_linux_errmap[n].errno;
Etienne Carriere02fd1262020-09-09 18:44:00 +0200174
175 return -EPROTO;
176}
177
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900178static struct udevice *find_scmi_protocol_device(struct udevice *dev)
Etienne Carriere2ee64582022-05-31 18:09:20 +0200179{
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900180 struct udevice *parent = NULL, *protocol;
Etienne Carriere2ee64582022-05-31 18:09:20 +0200181
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900182 for (protocol = dev; protocol; protocol = parent) {
183 parent = dev_get_parent(protocol);
184 if (!parent ||
185 device_get_uclass_id(parent) == UCLASS_SCMI_AGENT)
186 break;
187 }
Etienne Carriere2ee64582022-05-31 18:09:20 +0200188
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900189 if (!parent) {
Etienne Carriere2ee64582022-05-31 18:09:20 +0200190 dev_err(dev, "Invalid SCMI device, agent not found\n");
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900191 return NULL;
192 }
Etienne Carriere2ee64582022-05-31 18:09:20 +0200193
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900194 return protocol;
Etienne Carriere2ee64582022-05-31 18:09:20 +0200195}
196
Etienne Carriere02fd1262020-09-09 18:44:00 +0200197static const struct scmi_agent_ops *transport_dev_ops(struct udevice *dev)
198{
199 return (const struct scmi_agent_ops *)dev->driver->ops;
200}
201
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900202/**
203 * scmi_of_get_channel() - Get SCMI channel handle
204 *
205 * @dev: SCMI agent device
206 * @channel: Output reference to the SCMI channel upon success
207 *
208 * On return, @channel will be set.
209 * Return 0 on success and a negative errno on failure
210 */
AKASHI Takahiro589ec9a2023-10-11 19:06:55 +0900211static int scmi_of_get_channel(struct udevice *dev, struct udevice *protocol,
212 struct scmi_channel **channel)
Etienne Carriere187cea12022-05-31 18:09:21 +0200213{
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900214 const struct scmi_agent_ops *ops;
Etienne Carriere187cea12022-05-31 18:09:21 +0200215
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900216 ops = transport_dev_ops(dev);
217 if (ops->of_get_channel)
AKASHI Takahiro589ec9a2023-10-11 19:06:55 +0900218 return ops->of_get_channel(dev, protocol, channel);
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900219 else
220 return -EPROTONOSUPPORT;
221}
222
223int devm_scmi_of_get_channel(struct udevice *dev)
224{
225 struct udevice *protocol;
226 struct scmi_agent_proto_priv *priv;
227 int ret;
228
229 protocol = find_scmi_protocol_device(dev);
230 if (!protocol)
Etienne Carriere187cea12022-05-31 18:09:21 +0200231 return -ENODEV;
232
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900233 priv = dev_get_parent_priv(protocol);
AKASHI Takahiro589ec9a2023-10-11 19:06:55 +0900234 ret = scmi_of_get_channel(protocol->parent, protocol, &priv->channel);
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900235 if (ret == -EPROTONOSUPPORT) {
236 /* Drivers without a get_channel operator don't need a channel ref */
237 priv->channel = NULL;
Etienne Carriere187cea12022-05-31 18:09:21 +0200238
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900239 return 0;
240 }
Etienne Carriere187cea12022-05-31 18:09:21 +0200241
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900242 return ret;
Etienne Carriere187cea12022-05-31 18:09:21 +0200243}
244
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900245/**
246 * scmi_process_msg() - Send and process an SCMI message
247 *
248 * Send a message to an SCMI server.
249 * Caller sets scmi_msg::out_msg_sz to the output message buffer size.
250 *
251 * @dev: SCMI agent device
252 * @channel: Communication channel for the device
253 * @msg: Message structure reference
254 *
255 * On return, scmi_msg::out_msg_sz stores the response payload size.
256 * Return: 0 on success and a negative errno on failure
257 */
258static int scmi_process_msg(struct udevice *dev, struct scmi_channel *channel,
259 struct scmi_msg *msg)
Etienne Carriere02fd1262020-09-09 18:44:00 +0200260{
Etienne Carriere2f26c042022-02-21 09:22:40 +0100261 const struct scmi_agent_ops *ops;
Etienne Carriere2f26c042022-02-21 09:22:40 +0100262
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900263 ops = transport_dev_ops(dev);
264 if (ops->process_msg)
265 return ops->process_msg(dev, channel, msg);
266 else
267 return -EPROTONOSUPPORT;
268}
Etienne Carriere2f26c042022-02-21 09:22:40 +0100269
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900270int devm_scmi_process_msg(struct udevice *dev, struct scmi_msg *msg)
271{
272 struct udevice *protocol;
273 struct scmi_agent_proto_priv *priv;
Etienne Carriere02fd1262020-09-09 18:44:00 +0200274
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900275 protocol = find_scmi_protocol_device(dev);
276 if (!protocol)
277 return -ENODEV;
278
279 priv = dev_get_parent_priv(protocol);
Etienne Carriere02fd1262020-09-09 18:44:00 +0200280
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900281 return scmi_process_msg(protocol->parent, priv->channel, msg);
Etienne Carriere02fd1262020-09-09 18:44:00 +0200282}
283
AKASHI Takahiro410be2c2023-10-11 19:07:04 +0900284/**
285 * scmi_fill_base_info - get base information about SCMI server
286 * @agent: SCMI agent device
287 * @dev: SCMI protocol device
288 *
289 * By using Base protocol commands, collect the base information
290 * about SCMI server.
291 *
292 * Return: 0 on success, error code on failure
293 */
294static int scmi_fill_base_info(struct udevice *agent, struct udevice *dev)
295{
296 struct scmi_agent_priv *priv = dev_get_uclass_plat(agent);
297 int ret;
298
299 ret = scmi_base_protocol_version(dev, &priv->version);
300 if (ret) {
301 dev_err(dev, "protocol_version() failed (%d)\n", ret);
302 return ret;
303 }
304 /* check for required version */
305 if (priv->version < SCMI_BASE_PROTOCOL_VERSION) {
306 dev_err(dev, "base protocol version (%d) lower than expected\n",
307 priv->version);
308 return -EPROTO;
309 }
310
311 ret = scmi_base_protocol_attrs(dev, &priv->num_agents,
312 &priv->num_protocols);
313 if (ret) {
314 dev_err(dev, "protocol_attrs() failed (%d)\n", ret);
315 return ret;
316 }
317 ret = scmi_base_discover_vendor(dev, &priv->vendor);
318 if (ret) {
319 dev_err(dev, "base_discover_vendor() failed (%d)\n", ret);
320 return ret;
321 }
322 ret = scmi_base_discover_sub_vendor(dev, &priv->sub_vendor);
323 if (ret) {
324 if (ret != -EOPNOTSUPP) {
325 dev_err(dev, "base_discover_sub_vendor() failed (%d)\n",
326 ret);
327 return ret;
328 }
329 priv->sub_vendor = "NA";
330 }
331 ret = scmi_base_discover_impl_version(dev, &priv->impl_version);
332 if (ret) {
333 dev_err(dev, "base_discover_impl_version() failed (%d)\n",
334 ret);
335 return ret;
336 }
337
338 ret = scmi_base_discover_agent(dev, 0xffffffff,
339 &priv->agent_id, &priv->agent_name);
340 if (ret) {
341 if (ret != -EOPNOTSUPP) {
342 dev_err(dev,
343 "base_discover_agent() failed for myself (%d)\n",
344 ret);
345 return ret;
346 }
347 priv->agent_id = 0xffffffff;
348 priv->agent_name = "NA";
349 }
350
351 ret = scmi_base_discover_list_protocols(dev, &priv->protocols);
352 if (ret != priv->num_protocols) {
353 dev_err(dev, "base_discover_list_protocols() failed (%d)\n",
354 ret);
355 return -EPROTO;
356 }
357
358 return 0;
359}
360
Alice Guoc783b622025-04-28 18:37:24 +0800361static struct driver *scmi_proto_driver_get(unsigned int proto_id)
362{
363 struct scmi_proto_driver *start, *entry;
364 int n_ents;
365
366 start = ll_entry_start(struct scmi_proto_driver, scmi_proto_driver);
367 n_ents = ll_entry_count(struct scmi_proto_driver, scmi_proto_driver);
368
369 for (entry = start; entry != start + n_ents; entry++) {
370 if (entry->match->proto_id == proto_id)
371 return entry->driver;
372 }
373
374 return NULL;
375}
376
AKASHI Takahiro6d379152023-10-11 19:06:57 +0900377/*
378 * SCMI agent devices binds devices of various uclasses depending on
379 * the FDT description. scmi_bind_protocol() is a generic bind sequence
380 * called by the uclass at bind stage, that is uclass post_bind.
381 */
382static int scmi_bind_protocols(struct udevice *dev)
383{
384 int ret = 0;
385 ofnode node;
386 const char *name;
AKASHI Takahiro6c90f822023-10-11 19:06:58 +0900387 struct driver *drv;
AKASHI Takahiro410be2c2023-10-11 19:07:04 +0900388 struct udevice *agent, *proto;
389
390 if (!uclass_get_device(UCLASS_SCMI_AGENT, 1, &agent)) {
391 /* This is a second SCMI agent */
392 dev_err(dev, "Cannot have more than one SCMI agent\n");
393 return -EEXIST;
394 }
395
396 /* initialize the device from device tree */
397 drv = DM_DRIVER_GET(scmi_base_drv);
398 name = "scmi-base.0";
399 ret = device_bind(dev, drv, name, NULL, ofnode_null(), &proto);
400 if (ret) {
401 dev_err(dev, "failed to bind base protocol\n");
402 return ret;
403 }
404 ret = scmi_add_protocol(dev, SCMI_PROTOCOL_ID_BASE, proto);
405 if (ret) {
406 dev_err(dev, "failed to add protocol: %s, ret: %d\n",
407 proto->name, ret);
408 return ret;
409 }
410
411 ret = device_probe(proto);
412 if (ret) {
413 dev_err(dev, "failed to probe base protocol\n");
414 return ret;
415 }
416
417 ret = scmi_fill_base_info(dev, proto);
418 if (ret) {
419 dev_err(dev, "failed to get base information\n");
420 return ret;
421 }
AKASHI Takahiro6d379152023-10-11 19:06:57 +0900422
423 dev_for_each_subnode(node, dev) {
AKASHI Takahiro6d379152023-10-11 19:06:57 +0900424 u32 protocol_id;
425
426 if (!ofnode_is_enabled(node))
427 continue;
428
429 if (ofnode_read_u32(node, "reg", &protocol_id))
430 continue;
431
AKASHI Takahiro6c90f822023-10-11 19:06:58 +0900432 drv = NULL;
AKASHI Takahiro6d379152023-10-11 19:06:57 +0900433 name = ofnode_get_name(node);
Alice Guof71894b2025-04-28 18:37:25 +0800434
435 if (!scmi_protocol_is_supported(dev, protocol_id))
436 continue;
AKASHI Takahiro6d379152023-10-11 19:06:57 +0900437
Alice Guof71894b2025-04-28 18:37:25 +0800438 drv = scmi_proto_driver_get(protocol_id);
AKASHI Takahiro6d379152023-10-11 19:06:57 +0900439 if (!drv) {
440 dev_dbg(dev, "Ignore unsupported SCMI protocol %#x\n",
441 protocol_id);
442 continue;
443 }
444
AKASHI Takahiro6c90f822023-10-11 19:06:58 +0900445 ret = device_bind(dev, drv, name, NULL, node, &proto);
446 if (ret) {
447 dev_err(dev, "failed to bind %s protocol\n", drv->name);
AKASHI Takahiro6d379152023-10-11 19:06:57 +0900448 break;
AKASHI Takahiro6c90f822023-10-11 19:06:58 +0900449 }
450 ret = scmi_add_protocol(dev, protocol_id, proto);
451 if (ret) {
452 dev_err(dev, "failed to add protocol: %s, ret: %d\n",
453 proto->name, ret);
454 break;
455 }
AKASHI Takahiro6d379152023-10-11 19:06:57 +0900456 }
457
458 return ret;
459}
460
Etienne Carriere02fd1262020-09-09 18:44:00 +0200461UCLASS_DRIVER(scmi_agent) = {
462 .id = UCLASS_SCMI_AGENT,
463 .name = "scmi_agent",
464 .post_bind = scmi_bind_protocols,
AKASHI Takahiro6c90f822023-10-11 19:06:58 +0900465 .per_device_plat_auto = sizeof(struct scmi_agent_priv),
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900466 .per_child_auto = sizeof(struct scmi_agent_proto_priv),
Etienne Carriere02fd1262020-09-09 18:44:00 +0200467};