blob: 8c907c3b0328095c4b35ba089ed608fcda48b567 [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;
100 default:
101 dev_err(dev, "Protocol not supported\n");
102 proto = NULL;
103 break;
104 }
105 if (proto && device_probe(proto))
106 dev_err(dev, "Probe failed\n");
107
108 return proto;
109}
110
111/**
112 * scmi_add_protocol - add protocol to agent
113 * @dev: SCMI agent device
114 * @proto_id: SCMI protocol ID
115 * @proto: SCMI protocol device
116 *
117 * Associate the protocol instance, @proto, to the agent, @dev,
118 * for later use.
119 *
120 * Return: 0 on success, error code on failure
121 */
122static int scmi_add_protocol(struct udevice *dev,
123 enum scmi_std_protocol proto_id,
124 struct udevice *proto)
125{
126 struct scmi_agent_priv *priv;
127
128 priv = dev_get_uclass_plat(dev);
129 if (!priv) {
130 dev_err(dev, "No priv data found\n");
131 return -ENODEV;
132 }
133
134 switch (proto_id) {
AKASHI Takahiro410be2c2023-10-11 19:07:04 +0900135 case SCMI_PROTOCOL_ID_BASE:
136 priv->base_dev = proto;
137 break;
AKASHI Takahirodf234cf2023-10-16 14:39:44 +0900138 case SCMI_PROTOCOL_ID_POWER_DOMAIN:
139 priv->pwdom_dev = proto;
140 break;
AKASHI Takahiro6c90f822023-10-11 19:06:58 +0900141 case SCMI_PROTOCOL_ID_CLOCK:
142 priv->clock_dev = proto;
143 break;
144 case SCMI_PROTOCOL_ID_RESET_DOMAIN:
145 priv->resetdom_dev = proto;
146 break;
147 case SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN:
148 priv->voltagedom_dev = proto;
149 break;
150 default:
151 dev_err(dev, "Protocol not supported\n");
152 return -EPROTO;
153 }
154
155 return 0;
156}
157
Etienne Carriere02fd1262020-09-09 18:44:00 +0200158int scmi_to_linux_errno(s32 scmi_code)
159{
160 int n;
161
162 if (!scmi_code)
163 return 0;
164
165 for (n = 0; n < ARRAY_SIZE(scmi_linux_errmap); n++)
166 if (scmi_code == scmi_linux_errmap[n].scmi)
AKASHI Takahiroc9371542023-06-13 10:30:45 +0900167 return scmi_linux_errmap[n].errno;
Etienne Carriere02fd1262020-09-09 18:44:00 +0200168
169 return -EPROTO;
170}
171
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900172static struct udevice *find_scmi_protocol_device(struct udevice *dev)
Etienne Carriere2ee64582022-05-31 18:09:20 +0200173{
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900174 struct udevice *parent = NULL, *protocol;
Etienne Carriere2ee64582022-05-31 18:09:20 +0200175
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900176 for (protocol = dev; protocol; protocol = parent) {
177 parent = dev_get_parent(protocol);
178 if (!parent ||
179 device_get_uclass_id(parent) == UCLASS_SCMI_AGENT)
180 break;
181 }
Etienne Carriere2ee64582022-05-31 18:09:20 +0200182
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900183 if (!parent) {
Etienne Carriere2ee64582022-05-31 18:09:20 +0200184 dev_err(dev, "Invalid SCMI device, agent not found\n");
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900185 return NULL;
186 }
Etienne Carriere2ee64582022-05-31 18:09:20 +0200187
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900188 return protocol;
Etienne Carriere2ee64582022-05-31 18:09:20 +0200189}
190
Etienne Carriere02fd1262020-09-09 18:44:00 +0200191static const struct scmi_agent_ops *transport_dev_ops(struct udevice *dev)
192{
193 return (const struct scmi_agent_ops *)dev->driver->ops;
194}
195
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900196/**
197 * scmi_of_get_channel() - Get SCMI channel handle
198 *
199 * @dev: SCMI agent device
200 * @channel: Output reference to the SCMI channel upon success
201 *
202 * On return, @channel will be set.
203 * Return 0 on success and a negative errno on failure
204 */
AKASHI Takahiro589ec9a2023-10-11 19:06:55 +0900205static int scmi_of_get_channel(struct udevice *dev, struct udevice *protocol,
206 struct scmi_channel **channel)
Etienne Carriere187cea12022-05-31 18:09:21 +0200207{
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900208 const struct scmi_agent_ops *ops;
Etienne Carriere187cea12022-05-31 18:09:21 +0200209
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900210 ops = transport_dev_ops(dev);
211 if (ops->of_get_channel)
AKASHI Takahiro589ec9a2023-10-11 19:06:55 +0900212 return ops->of_get_channel(dev, protocol, channel);
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900213 else
214 return -EPROTONOSUPPORT;
215}
216
217int devm_scmi_of_get_channel(struct udevice *dev)
218{
219 struct udevice *protocol;
220 struct scmi_agent_proto_priv *priv;
221 int ret;
222
223 protocol = find_scmi_protocol_device(dev);
224 if (!protocol)
Etienne Carriere187cea12022-05-31 18:09:21 +0200225 return -ENODEV;
226
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900227 priv = dev_get_parent_priv(protocol);
AKASHI Takahiro589ec9a2023-10-11 19:06:55 +0900228 ret = scmi_of_get_channel(protocol->parent, protocol, &priv->channel);
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900229 if (ret == -EPROTONOSUPPORT) {
230 /* Drivers without a get_channel operator don't need a channel ref */
231 priv->channel = NULL;
Etienne Carriere187cea12022-05-31 18:09:21 +0200232
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900233 return 0;
234 }
Etienne Carriere187cea12022-05-31 18:09:21 +0200235
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900236 return ret;
Etienne Carriere187cea12022-05-31 18:09:21 +0200237}
238
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900239/**
240 * scmi_process_msg() - Send and process an SCMI message
241 *
242 * Send a message to an SCMI server.
243 * Caller sets scmi_msg::out_msg_sz to the output message buffer size.
244 *
245 * @dev: SCMI agent device
246 * @channel: Communication channel for the device
247 * @msg: Message structure reference
248 *
249 * On return, scmi_msg::out_msg_sz stores the response payload size.
250 * Return: 0 on success and a negative errno on failure
251 */
252static int scmi_process_msg(struct udevice *dev, struct scmi_channel *channel,
253 struct scmi_msg *msg)
Etienne Carriere02fd1262020-09-09 18:44:00 +0200254{
Etienne Carriere2f26c042022-02-21 09:22:40 +0100255 const struct scmi_agent_ops *ops;
Etienne Carriere2f26c042022-02-21 09:22:40 +0100256
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900257 ops = transport_dev_ops(dev);
258 if (ops->process_msg)
259 return ops->process_msg(dev, channel, msg);
260 else
261 return -EPROTONOSUPPORT;
262}
Etienne Carriere2f26c042022-02-21 09:22:40 +0100263
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900264int devm_scmi_process_msg(struct udevice *dev, struct scmi_msg *msg)
265{
266 struct udevice *protocol;
267 struct scmi_agent_proto_priv *priv;
Etienne Carriere02fd1262020-09-09 18:44:00 +0200268
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900269 protocol = find_scmi_protocol_device(dev);
270 if (!protocol)
271 return -ENODEV;
272
273 priv = dev_get_parent_priv(protocol);
Etienne Carriere02fd1262020-09-09 18:44:00 +0200274
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900275 return scmi_process_msg(protocol->parent, priv->channel, msg);
Etienne Carriere02fd1262020-09-09 18:44:00 +0200276}
277
AKASHI Takahiro410be2c2023-10-11 19:07:04 +0900278/**
279 * scmi_fill_base_info - get base information about SCMI server
280 * @agent: SCMI agent device
281 * @dev: SCMI protocol device
282 *
283 * By using Base protocol commands, collect the base information
284 * about SCMI server.
285 *
286 * Return: 0 on success, error code on failure
287 */
288static int scmi_fill_base_info(struct udevice *agent, struct udevice *dev)
289{
290 struct scmi_agent_priv *priv = dev_get_uclass_plat(agent);
291 int ret;
292
293 ret = scmi_base_protocol_version(dev, &priv->version);
294 if (ret) {
295 dev_err(dev, "protocol_version() failed (%d)\n", ret);
296 return ret;
297 }
298 /* check for required version */
299 if (priv->version < SCMI_BASE_PROTOCOL_VERSION) {
300 dev_err(dev, "base protocol version (%d) lower than expected\n",
301 priv->version);
302 return -EPROTO;
303 }
304
305 ret = scmi_base_protocol_attrs(dev, &priv->num_agents,
306 &priv->num_protocols);
307 if (ret) {
308 dev_err(dev, "protocol_attrs() failed (%d)\n", ret);
309 return ret;
310 }
311 ret = scmi_base_discover_vendor(dev, &priv->vendor);
312 if (ret) {
313 dev_err(dev, "base_discover_vendor() failed (%d)\n", ret);
314 return ret;
315 }
316 ret = scmi_base_discover_sub_vendor(dev, &priv->sub_vendor);
317 if (ret) {
318 if (ret != -EOPNOTSUPP) {
319 dev_err(dev, "base_discover_sub_vendor() failed (%d)\n",
320 ret);
321 return ret;
322 }
323 priv->sub_vendor = "NA";
324 }
325 ret = scmi_base_discover_impl_version(dev, &priv->impl_version);
326 if (ret) {
327 dev_err(dev, "base_discover_impl_version() failed (%d)\n",
328 ret);
329 return ret;
330 }
331
332 ret = scmi_base_discover_agent(dev, 0xffffffff,
333 &priv->agent_id, &priv->agent_name);
334 if (ret) {
335 if (ret != -EOPNOTSUPP) {
336 dev_err(dev,
337 "base_discover_agent() failed for myself (%d)\n",
338 ret);
339 return ret;
340 }
341 priv->agent_id = 0xffffffff;
342 priv->agent_name = "NA";
343 }
344
345 ret = scmi_base_discover_list_protocols(dev, &priv->protocols);
346 if (ret != priv->num_protocols) {
347 dev_err(dev, "base_discover_list_protocols() failed (%d)\n",
348 ret);
349 return -EPROTO;
350 }
351
352 return 0;
353}
354
AKASHI Takahiro6d379152023-10-11 19:06:57 +0900355/*
356 * SCMI agent devices binds devices of various uclasses depending on
357 * the FDT description. scmi_bind_protocol() is a generic bind sequence
358 * called by the uclass at bind stage, that is uclass post_bind.
359 */
360static int scmi_bind_protocols(struct udevice *dev)
361{
362 int ret = 0;
363 ofnode node;
364 const char *name;
AKASHI Takahiro6c90f822023-10-11 19:06:58 +0900365 struct driver *drv;
AKASHI Takahiro410be2c2023-10-11 19:07:04 +0900366 struct udevice *agent, *proto;
367
368 if (!uclass_get_device(UCLASS_SCMI_AGENT, 1, &agent)) {
369 /* This is a second SCMI agent */
370 dev_err(dev, "Cannot have more than one SCMI agent\n");
371 return -EEXIST;
372 }
373
374 /* initialize the device from device tree */
375 drv = DM_DRIVER_GET(scmi_base_drv);
376 name = "scmi-base.0";
377 ret = device_bind(dev, drv, name, NULL, ofnode_null(), &proto);
378 if (ret) {
379 dev_err(dev, "failed to bind base protocol\n");
380 return ret;
381 }
382 ret = scmi_add_protocol(dev, SCMI_PROTOCOL_ID_BASE, proto);
383 if (ret) {
384 dev_err(dev, "failed to add protocol: %s, ret: %d\n",
385 proto->name, ret);
386 return ret;
387 }
388
389 ret = device_probe(proto);
390 if (ret) {
391 dev_err(dev, "failed to probe base protocol\n");
392 return ret;
393 }
394
395 ret = scmi_fill_base_info(dev, proto);
396 if (ret) {
397 dev_err(dev, "failed to get base information\n");
398 return ret;
399 }
AKASHI Takahiro6d379152023-10-11 19:06:57 +0900400
401 dev_for_each_subnode(node, dev) {
AKASHI Takahiro6d379152023-10-11 19:06:57 +0900402 u32 protocol_id;
403
404 if (!ofnode_is_enabled(node))
405 continue;
406
407 if (ofnode_read_u32(node, "reg", &protocol_id))
408 continue;
409
AKASHI Takahiro6c90f822023-10-11 19:06:58 +0900410 drv = NULL;
AKASHI Takahiro6d379152023-10-11 19:06:57 +0900411 name = ofnode_get_name(node);
412 switch (protocol_id) {
AKASHI Takahirodf234cf2023-10-16 14:39:44 +0900413 case SCMI_PROTOCOL_ID_POWER_DOMAIN:
414 if (CONFIG_IS_ENABLED(SCMI_POWER_DOMAIN) &&
415 scmi_protocol_is_supported(dev, protocol_id))
416 drv = DM_DRIVER_GET(scmi_power_domain);
417 break;
AKASHI Takahiro6d379152023-10-11 19:06:57 +0900418 case SCMI_PROTOCOL_ID_CLOCK:
AKASHI Takahirofa744002023-10-11 19:07:07 +0900419 if (CONFIG_IS_ENABLED(CLK_SCMI) &&
420 scmi_protocol_is_supported(dev, protocol_id))
AKASHI Takahiro6d379152023-10-11 19:06:57 +0900421 drv = DM_DRIVER_GET(scmi_clock);
422 break;
423 case SCMI_PROTOCOL_ID_RESET_DOMAIN:
AKASHI Takahirofa744002023-10-11 19:07:07 +0900424 if (IS_ENABLED(CONFIG_RESET_SCMI) &&
425 scmi_protocol_is_supported(dev, protocol_id))
AKASHI Takahiro6d379152023-10-11 19:06:57 +0900426 drv = DM_DRIVER_GET(scmi_reset_domain);
427 break;
428 case SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN:
AKASHI Takahirofa744002023-10-11 19:07:07 +0900429 if (IS_ENABLED(CONFIG_DM_REGULATOR_SCMI) &&
430 scmi_protocol_is_supported(dev, protocol_id)) {
AKASHI Takahiro6d379152023-10-11 19:06:57 +0900431 node = ofnode_find_subnode(node, "regulators");
432 if (!ofnode_valid(node)) {
433 dev_err(dev, "no regulators node\n");
434 return -ENXIO;
435 }
436 drv = DM_DRIVER_GET(scmi_voltage_domain);
437 }
438 break;
439 default:
440 break;
441 }
442
443 if (!drv) {
444 dev_dbg(dev, "Ignore unsupported SCMI protocol %#x\n",
445 protocol_id);
446 continue;
447 }
448
AKASHI Takahiro6c90f822023-10-11 19:06:58 +0900449 ret = device_bind(dev, drv, name, NULL, node, &proto);
450 if (ret) {
451 dev_err(dev, "failed to bind %s protocol\n", drv->name);
AKASHI Takahiro6d379152023-10-11 19:06:57 +0900452 break;
AKASHI Takahiro6c90f822023-10-11 19:06:58 +0900453 }
454 ret = scmi_add_protocol(dev, protocol_id, proto);
455 if (ret) {
456 dev_err(dev, "failed to add protocol: %s, ret: %d\n",
457 proto->name, ret);
458 break;
459 }
AKASHI Takahiro6d379152023-10-11 19:06:57 +0900460 }
461
462 return ret;
463}
464
Etienne Carriere02fd1262020-09-09 18:44:00 +0200465UCLASS_DRIVER(scmi_agent) = {
466 .id = UCLASS_SCMI_AGENT,
467 .name = "scmi_agent",
468 .post_bind = scmi_bind_protocols,
AKASHI Takahiro6c90f822023-10-11 19:06:58 +0900469 .per_device_plat_auto = sizeof(struct scmi_agent_priv),
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900470 .per_child_auto = sizeof(struct scmi_agent_proto_priv),
Etienne Carriere02fd1262020-09-09 18:44:00 +0200471};