blob: b1a9c36310c132773d9013a443e84fa0a6816cfc [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) {
AKASHI Takahiro410be2c2023-10-11 19:07:04 +090054 case SCMI_PROTOCOL_ID_BASE:
55 proto = priv->base_dev;
56 break;
AKASHI Takahiro6c90f822023-10-11 19:06:58 +090057 case SCMI_PROTOCOL_ID_CLOCK:
58 proto = priv->clock_dev;
59 break;
60 case SCMI_PROTOCOL_ID_RESET_DOMAIN:
61 proto = priv->resetdom_dev;
62 break;
63 case SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN:
64 proto = priv->voltagedom_dev;
65 break;
66 default:
67 dev_err(dev, "Protocol not supported\n");
68 proto = NULL;
69 break;
70 }
71 if (proto && device_probe(proto))
72 dev_err(dev, "Probe failed\n");
73
74 return proto;
75}
76
77/**
78 * scmi_add_protocol - add protocol to agent
79 * @dev: SCMI agent device
80 * @proto_id: SCMI protocol ID
81 * @proto: SCMI protocol device
82 *
83 * Associate the protocol instance, @proto, to the agent, @dev,
84 * for later use.
85 *
86 * Return: 0 on success, error code on failure
87 */
88static int scmi_add_protocol(struct udevice *dev,
89 enum scmi_std_protocol proto_id,
90 struct udevice *proto)
91{
92 struct scmi_agent_priv *priv;
93
94 priv = dev_get_uclass_plat(dev);
95 if (!priv) {
96 dev_err(dev, "No priv data found\n");
97 return -ENODEV;
98 }
99
100 switch (proto_id) {
AKASHI Takahiro410be2c2023-10-11 19:07:04 +0900101 case SCMI_PROTOCOL_ID_BASE:
102 priv->base_dev = proto;
103 break;
AKASHI Takahiro6c90f822023-10-11 19:06:58 +0900104 case SCMI_PROTOCOL_ID_CLOCK:
105 priv->clock_dev = proto;
106 break;
107 case SCMI_PROTOCOL_ID_RESET_DOMAIN:
108 priv->resetdom_dev = proto;
109 break;
110 case SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN:
111 priv->voltagedom_dev = proto;
112 break;
113 default:
114 dev_err(dev, "Protocol not supported\n");
115 return -EPROTO;
116 }
117
118 return 0;
119}
120
Etienne Carriere02fd1262020-09-09 18:44:00 +0200121int scmi_to_linux_errno(s32 scmi_code)
122{
123 int n;
124
125 if (!scmi_code)
126 return 0;
127
128 for (n = 0; n < ARRAY_SIZE(scmi_linux_errmap); n++)
129 if (scmi_code == scmi_linux_errmap[n].scmi)
AKASHI Takahiroc9371542023-06-13 10:30:45 +0900130 return scmi_linux_errmap[n].errno;
Etienne Carriere02fd1262020-09-09 18:44:00 +0200131
132 return -EPROTO;
133}
134
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900135static struct udevice *find_scmi_protocol_device(struct udevice *dev)
Etienne Carriere2ee64582022-05-31 18:09:20 +0200136{
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900137 struct udevice *parent = NULL, *protocol;
Etienne Carriere2ee64582022-05-31 18:09:20 +0200138
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900139 for (protocol = dev; protocol; protocol = parent) {
140 parent = dev_get_parent(protocol);
141 if (!parent ||
142 device_get_uclass_id(parent) == UCLASS_SCMI_AGENT)
143 break;
144 }
Etienne Carriere2ee64582022-05-31 18:09:20 +0200145
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900146 if (!parent) {
Etienne Carriere2ee64582022-05-31 18:09:20 +0200147 dev_err(dev, "Invalid SCMI device, agent not found\n");
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900148 return NULL;
149 }
Etienne Carriere2ee64582022-05-31 18:09:20 +0200150
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900151 return protocol;
Etienne Carriere2ee64582022-05-31 18:09:20 +0200152}
153
Etienne Carriere02fd1262020-09-09 18:44:00 +0200154static const struct scmi_agent_ops *transport_dev_ops(struct udevice *dev)
155{
156 return (const struct scmi_agent_ops *)dev->driver->ops;
157}
158
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900159/**
160 * scmi_of_get_channel() - Get SCMI channel handle
161 *
162 * @dev: SCMI agent device
163 * @channel: Output reference to the SCMI channel upon success
164 *
165 * On return, @channel will be set.
166 * Return 0 on success and a negative errno on failure
167 */
AKASHI Takahiro589ec9a2023-10-11 19:06:55 +0900168static int scmi_of_get_channel(struct udevice *dev, struct udevice *protocol,
169 struct scmi_channel **channel)
Etienne Carriere187cea12022-05-31 18:09:21 +0200170{
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900171 const struct scmi_agent_ops *ops;
Etienne Carriere187cea12022-05-31 18:09:21 +0200172
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900173 ops = transport_dev_ops(dev);
174 if (ops->of_get_channel)
AKASHI Takahiro589ec9a2023-10-11 19:06:55 +0900175 return ops->of_get_channel(dev, protocol, channel);
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900176 else
177 return -EPROTONOSUPPORT;
178}
179
180int devm_scmi_of_get_channel(struct udevice *dev)
181{
182 struct udevice *protocol;
183 struct scmi_agent_proto_priv *priv;
184 int ret;
185
186 protocol = find_scmi_protocol_device(dev);
187 if (!protocol)
Etienne Carriere187cea12022-05-31 18:09:21 +0200188 return -ENODEV;
189
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900190 priv = dev_get_parent_priv(protocol);
AKASHI Takahiro589ec9a2023-10-11 19:06:55 +0900191 ret = scmi_of_get_channel(protocol->parent, protocol, &priv->channel);
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900192 if (ret == -EPROTONOSUPPORT) {
193 /* Drivers without a get_channel operator don't need a channel ref */
194 priv->channel = NULL;
Etienne Carriere187cea12022-05-31 18:09:21 +0200195
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900196 return 0;
197 }
Etienne Carriere187cea12022-05-31 18:09:21 +0200198
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900199 return ret;
Etienne Carriere187cea12022-05-31 18:09:21 +0200200}
201
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900202/**
203 * scmi_process_msg() - Send and process an SCMI message
204 *
205 * Send a message to an SCMI server.
206 * Caller sets scmi_msg::out_msg_sz to the output message buffer size.
207 *
208 * @dev: SCMI agent device
209 * @channel: Communication channel for the device
210 * @msg: Message structure reference
211 *
212 * On return, scmi_msg::out_msg_sz stores the response payload size.
213 * Return: 0 on success and a negative errno on failure
214 */
215static int scmi_process_msg(struct udevice *dev, struct scmi_channel *channel,
216 struct scmi_msg *msg)
Etienne Carriere02fd1262020-09-09 18:44:00 +0200217{
Etienne Carriere2f26c042022-02-21 09:22:40 +0100218 const struct scmi_agent_ops *ops;
Etienne Carriere2f26c042022-02-21 09:22:40 +0100219
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900220 ops = transport_dev_ops(dev);
221 if (ops->process_msg)
222 return ops->process_msg(dev, channel, msg);
223 else
224 return -EPROTONOSUPPORT;
225}
Etienne Carriere2f26c042022-02-21 09:22:40 +0100226
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900227int devm_scmi_process_msg(struct udevice *dev, struct scmi_msg *msg)
228{
229 struct udevice *protocol;
230 struct scmi_agent_proto_priv *priv;
Etienne Carriere02fd1262020-09-09 18:44:00 +0200231
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900232 protocol = find_scmi_protocol_device(dev);
233 if (!protocol)
234 return -ENODEV;
235
236 priv = dev_get_parent_priv(protocol);
Etienne Carriere02fd1262020-09-09 18:44:00 +0200237
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900238 return scmi_process_msg(protocol->parent, priv->channel, msg);
Etienne Carriere02fd1262020-09-09 18:44:00 +0200239}
240
AKASHI Takahiro410be2c2023-10-11 19:07:04 +0900241/**
242 * scmi_fill_base_info - get base information about SCMI server
243 * @agent: SCMI agent device
244 * @dev: SCMI protocol device
245 *
246 * By using Base protocol commands, collect the base information
247 * about SCMI server.
248 *
249 * Return: 0 on success, error code on failure
250 */
251static int scmi_fill_base_info(struct udevice *agent, struct udevice *dev)
252{
253 struct scmi_agent_priv *priv = dev_get_uclass_plat(agent);
254 int ret;
255
256 ret = scmi_base_protocol_version(dev, &priv->version);
257 if (ret) {
258 dev_err(dev, "protocol_version() failed (%d)\n", ret);
259 return ret;
260 }
261 /* check for required version */
262 if (priv->version < SCMI_BASE_PROTOCOL_VERSION) {
263 dev_err(dev, "base protocol version (%d) lower than expected\n",
264 priv->version);
265 return -EPROTO;
266 }
267
268 ret = scmi_base_protocol_attrs(dev, &priv->num_agents,
269 &priv->num_protocols);
270 if (ret) {
271 dev_err(dev, "protocol_attrs() failed (%d)\n", ret);
272 return ret;
273 }
274 ret = scmi_base_discover_vendor(dev, &priv->vendor);
275 if (ret) {
276 dev_err(dev, "base_discover_vendor() failed (%d)\n", ret);
277 return ret;
278 }
279 ret = scmi_base_discover_sub_vendor(dev, &priv->sub_vendor);
280 if (ret) {
281 if (ret != -EOPNOTSUPP) {
282 dev_err(dev, "base_discover_sub_vendor() failed (%d)\n",
283 ret);
284 return ret;
285 }
286 priv->sub_vendor = "NA";
287 }
288 ret = scmi_base_discover_impl_version(dev, &priv->impl_version);
289 if (ret) {
290 dev_err(dev, "base_discover_impl_version() failed (%d)\n",
291 ret);
292 return ret;
293 }
294
295 ret = scmi_base_discover_agent(dev, 0xffffffff,
296 &priv->agent_id, &priv->agent_name);
297 if (ret) {
298 if (ret != -EOPNOTSUPP) {
299 dev_err(dev,
300 "base_discover_agent() failed for myself (%d)\n",
301 ret);
302 return ret;
303 }
304 priv->agent_id = 0xffffffff;
305 priv->agent_name = "NA";
306 }
307
308 ret = scmi_base_discover_list_protocols(dev, &priv->protocols);
309 if (ret != priv->num_protocols) {
310 dev_err(dev, "base_discover_list_protocols() failed (%d)\n",
311 ret);
312 return -EPROTO;
313 }
314
315 return 0;
316}
317
AKASHI Takahiro6d379152023-10-11 19:06:57 +0900318/*
319 * SCMI agent devices binds devices of various uclasses depending on
320 * the FDT description. scmi_bind_protocol() is a generic bind sequence
321 * called by the uclass at bind stage, that is uclass post_bind.
322 */
323static int scmi_bind_protocols(struct udevice *dev)
324{
325 int ret = 0;
326 ofnode node;
327 const char *name;
AKASHI Takahiro6c90f822023-10-11 19:06:58 +0900328 struct driver *drv;
AKASHI Takahiro410be2c2023-10-11 19:07:04 +0900329 struct udevice *agent, *proto;
330
331 if (!uclass_get_device(UCLASS_SCMI_AGENT, 1, &agent)) {
332 /* This is a second SCMI agent */
333 dev_err(dev, "Cannot have more than one SCMI agent\n");
334 return -EEXIST;
335 }
336
337 /* initialize the device from device tree */
338 drv = DM_DRIVER_GET(scmi_base_drv);
339 name = "scmi-base.0";
340 ret = device_bind(dev, drv, name, NULL, ofnode_null(), &proto);
341 if (ret) {
342 dev_err(dev, "failed to bind base protocol\n");
343 return ret;
344 }
345 ret = scmi_add_protocol(dev, SCMI_PROTOCOL_ID_BASE, proto);
346 if (ret) {
347 dev_err(dev, "failed to add protocol: %s, ret: %d\n",
348 proto->name, ret);
349 return ret;
350 }
351
352 ret = device_probe(proto);
353 if (ret) {
354 dev_err(dev, "failed to probe base protocol\n");
355 return ret;
356 }
357
358 ret = scmi_fill_base_info(dev, proto);
359 if (ret) {
360 dev_err(dev, "failed to get base information\n");
361 return ret;
362 }
AKASHI Takahiro6d379152023-10-11 19:06:57 +0900363
364 dev_for_each_subnode(node, dev) {
AKASHI Takahiro6d379152023-10-11 19:06:57 +0900365 u32 protocol_id;
366
367 if (!ofnode_is_enabled(node))
368 continue;
369
370 if (ofnode_read_u32(node, "reg", &protocol_id))
371 continue;
372
AKASHI Takahiro6c90f822023-10-11 19:06:58 +0900373 drv = NULL;
AKASHI Takahiro6d379152023-10-11 19:06:57 +0900374 name = ofnode_get_name(node);
375 switch (protocol_id) {
376 case SCMI_PROTOCOL_ID_CLOCK:
377 if (CONFIG_IS_ENABLED(CLK_SCMI))
378 drv = DM_DRIVER_GET(scmi_clock);
379 break;
380 case SCMI_PROTOCOL_ID_RESET_DOMAIN:
381 if (IS_ENABLED(CONFIG_RESET_SCMI))
382 drv = DM_DRIVER_GET(scmi_reset_domain);
383 break;
384 case SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN:
385 if (IS_ENABLED(CONFIG_DM_REGULATOR_SCMI)) {
386 node = ofnode_find_subnode(node, "regulators");
387 if (!ofnode_valid(node)) {
388 dev_err(dev, "no regulators node\n");
389 return -ENXIO;
390 }
391 drv = DM_DRIVER_GET(scmi_voltage_domain);
392 }
393 break;
394 default:
395 break;
396 }
397
398 if (!drv) {
399 dev_dbg(dev, "Ignore unsupported SCMI protocol %#x\n",
400 protocol_id);
401 continue;
402 }
403
AKASHI Takahiro6c90f822023-10-11 19:06:58 +0900404 ret = device_bind(dev, drv, name, NULL, node, &proto);
405 if (ret) {
406 dev_err(dev, "failed to bind %s protocol\n", drv->name);
AKASHI Takahiro6d379152023-10-11 19:06:57 +0900407 break;
AKASHI Takahiro6c90f822023-10-11 19:06:58 +0900408 }
409 ret = scmi_add_protocol(dev, protocol_id, proto);
410 if (ret) {
411 dev_err(dev, "failed to add protocol: %s, ret: %d\n",
412 proto->name, ret);
413 break;
414 }
AKASHI Takahiro6d379152023-10-11 19:06:57 +0900415 }
416
417 return ret;
418}
419
Etienne Carriere02fd1262020-09-09 18:44:00 +0200420UCLASS_DRIVER(scmi_agent) = {
421 .id = UCLASS_SCMI_AGENT,
422 .name = "scmi_agent",
423 .post_bind = scmi_bind_protocols,
AKASHI Takahiro6c90f822023-10-11 19:06:58 +0900424 .per_device_plat_auto = sizeof(struct scmi_agent_priv),
AKASHI Takahiro7b3aa372023-10-11 19:06:54 +0900425 .per_child_auto = sizeof(struct scmi_agent_proto_priv),
Etienne Carriere02fd1262020-09-09 18:44:00 +0200426};