1 // SPDX-License-Identifier: GPL-2.0
3 * System Control and Management Interface (SCMI) Voltage Protocol
5 * Copyright (C) 2020-2022 ARM Ltd.
8 #include <linux/module.h>
9 #include <linux/scmi_protocol.h>
11 #include "protocols.h"
13 /* Updated only after ALL the mandatory features for that version are merged */
14 #define SCMI_PROTOCOL_SUPPORTED_VERSION 0x20001
16 #define VOLTAGE_DOMS_NUM_MASK GENMASK(15, 0)
17 #define REMAINING_LEVELS_MASK GENMASK(31, 16)
18 #define RETURNED_LEVELS_MASK GENMASK(11, 0)
20 enum scmi_voltage_protocol_cmd
{
21 VOLTAGE_DOMAIN_ATTRIBUTES
= 0x3,
22 VOLTAGE_DESCRIBE_LEVELS
= 0x4,
23 VOLTAGE_CONFIG_SET
= 0x5,
24 VOLTAGE_CONFIG_GET
= 0x6,
25 VOLTAGE_LEVEL_SET
= 0x7,
26 VOLTAGE_LEVEL_GET
= 0x8,
27 VOLTAGE_DOMAIN_NAME_GET
= 0x09,
30 #define NUM_VOLTAGE_DOMAINS(x) ((u16)(FIELD_GET(VOLTAGE_DOMS_NUM_MASK, (x))))
32 struct scmi_msg_resp_domain_attributes
{
34 #define SUPPORTS_ASYNC_LEVEL_SET(x) ((x) & BIT(31))
35 #define SUPPORTS_EXTENDED_NAMES(x) ((x) & BIT(30))
36 u8 name
[SCMI_SHORT_NAME_MAX_SIZE
];
39 struct scmi_msg_cmd_describe_levels
{
44 struct scmi_msg_resp_describe_levels
{
46 #define NUM_REMAINING_LEVELS(f) ((u16)(FIELD_GET(REMAINING_LEVELS_MASK, (f))))
47 #define NUM_RETURNED_LEVELS(f) ((u16)(FIELD_GET(RETURNED_LEVELS_MASK, (f))))
48 #define SUPPORTS_SEGMENTED_LEVELS(f) ((f) & BIT(12))
52 struct scmi_msg_cmd_config_set
{
57 struct scmi_msg_cmd_level_set
{
63 struct scmi_resp_voltage_level_set_complete
{
70 unsigned int num_domains
;
71 struct scmi_voltage_info
*domains
;
74 static int scmi_protocol_attributes_get(const struct scmi_protocol_handle
*ph
,
75 struct voltage_info
*vinfo
)
80 ret
= ph
->xops
->xfer_get_init(ph
, PROTOCOL_ATTRIBUTES
, 0,
85 ret
= ph
->xops
->do_xfer(ph
, t
);
88 NUM_VOLTAGE_DOMAINS(get_unaligned_le32(t
->rx
.buf
));
90 ph
->xops
->xfer_put(ph
, t
);
94 static int scmi_init_voltage_levels(struct device
*dev
,
95 struct scmi_voltage_info
*v
,
96 u32 num_returned
, u32 num_remaining
,
101 num_levels
= num_returned
+ num_remaining
;
103 * segmented levels entries are represented by a single triplet
104 * returned all in one go.
107 (segmented
&& (num_remaining
|| num_returned
!= 3))) {
109 "Invalid level descriptor(%d/%d/%d) for voltage dom %d\n",
110 num_levels
, num_returned
, num_remaining
, v
->id
);
114 v
->levels_uv
= devm_kcalloc(dev
, num_levels
, sizeof(u32
), GFP_KERNEL
);
118 v
->num_levels
= num_levels
;
119 v
->segmented
= segmented
;
124 struct scmi_volt_ipriv
{
126 struct scmi_voltage_info
*v
;
129 static void iter_volt_levels_prepare_message(void *message
,
130 unsigned int desc_index
,
133 struct scmi_msg_cmd_describe_levels
*msg
= message
;
134 const struct scmi_volt_ipriv
*p
= priv
;
136 msg
->domain_id
= cpu_to_le32(p
->v
->id
);
137 msg
->level_index
= cpu_to_le32(desc_index
);
140 static int iter_volt_levels_update_state(struct scmi_iterator_state
*st
,
141 const void *response
, void *priv
)
145 const struct scmi_msg_resp_describe_levels
*r
= response
;
146 struct scmi_volt_ipriv
*p
= priv
;
148 flags
= le32_to_cpu(r
->flags
);
149 st
->num_returned
= NUM_RETURNED_LEVELS(flags
);
150 st
->num_remaining
= NUM_REMAINING_LEVELS(flags
);
152 /* Allocate space for num_levels if not already done */
153 if (!p
->v
->num_levels
) {
154 ret
= scmi_init_voltage_levels(p
->dev
, p
->v
, st
->num_returned
,
156 SUPPORTS_SEGMENTED_LEVELS(flags
));
158 st
->max_resources
= p
->v
->num_levels
;
165 iter_volt_levels_process_response(const struct scmi_protocol_handle
*ph
,
166 const void *response
,
167 struct scmi_iterator_state
*st
, void *priv
)
170 const struct scmi_msg_resp_describe_levels
*r
= response
;
171 struct scmi_volt_ipriv
*p
= priv
;
173 val
= (s32
)le32_to_cpu(r
->voltage
[st
->loop_idx
]);
174 p
->v
->levels_uv
[st
->desc_index
+ st
->loop_idx
] = val
;
176 p
->v
->negative_volts_allowed
= true;
181 static int scmi_voltage_levels_get(const struct scmi_protocol_handle
*ph
,
182 struct scmi_voltage_info
*v
)
186 struct scmi_iterator_ops ops
= {
187 .prepare_message
= iter_volt_levels_prepare_message
,
188 .update_state
= iter_volt_levels_update_state
,
189 .process_response
= iter_volt_levels_process_response
,
191 struct scmi_volt_ipriv vpriv
= {
196 iter
= ph
->hops
->iter_response_init(ph
, &ops
, v
->num_levels
,
197 VOLTAGE_DESCRIBE_LEVELS
,
198 sizeof(struct scmi_msg_cmd_describe_levels
),
201 return PTR_ERR(iter
);
203 ret
= ph
->hops
->iter_response_run(iter
);
206 devm_kfree(ph
->dev
, v
->levels_uv
);
212 static int scmi_voltage_descriptors_get(const struct scmi_protocol_handle
*ph
,
213 struct voltage_info
*vinfo
)
216 struct scmi_xfer
*td
;
217 struct scmi_msg_resp_domain_attributes
*resp_dom
;
219 ret
= ph
->xops
->xfer_get_init(ph
, VOLTAGE_DOMAIN_ATTRIBUTES
,
220 sizeof(__le32
), sizeof(*resp_dom
), &td
);
223 resp_dom
= td
->rx
.buf
;
225 for (dom
= 0; dom
< vinfo
->num_domains
; dom
++) {
227 struct scmi_voltage_info
*v
;
229 /* Retrieve domain attributes at first ... */
230 put_unaligned_le32(dom
, td
->tx
.buf
);
231 /* Skip domain on comms error */
232 if (ph
->xops
->do_xfer(ph
, td
)) {
233 ph
->xops
->reset_rx_to_maxsz(ph
, td
);
237 v
= vinfo
->domains
+ dom
;
239 attributes
= le32_to_cpu(resp_dom
->attr
);
240 strscpy(v
->name
, resp_dom
->name
, SCMI_SHORT_NAME_MAX_SIZE
);
243 * If supported overwrite short name with the extended one;
244 * on error just carry on and use already provided short name.
246 if (PROTOCOL_REV_MAJOR(vinfo
->version
) >= 0x2) {
247 if (SUPPORTS_EXTENDED_NAMES(attributes
))
248 ph
->hops
->extended_name_get(ph
,
249 VOLTAGE_DOMAIN_NAME_GET
,
250 v
->id
, NULL
, v
->name
,
252 if (SUPPORTS_ASYNC_LEVEL_SET(attributes
))
253 v
->async_level_set
= true;
256 /* Skip invalid voltage descriptors */
257 scmi_voltage_levels_get(ph
, v
);
260 ph
->xops
->xfer_put(ph
, td
);
265 static int __scmi_voltage_get_u32(const struct scmi_protocol_handle
*ph
,
266 u8 cmd_id
, u32 domain_id
, u32
*value
)
270 struct voltage_info
*vinfo
= ph
->get_priv(ph
);
272 if (domain_id
>= vinfo
->num_domains
)
275 ret
= ph
->xops
->xfer_get_init(ph
, cmd_id
, sizeof(__le32
), 0, &t
);
279 put_unaligned_le32(domain_id
, t
->tx
.buf
);
280 ret
= ph
->xops
->do_xfer(ph
, t
);
282 *value
= get_unaligned_le32(t
->rx
.buf
);
284 ph
->xops
->xfer_put(ph
, t
);
288 static int scmi_voltage_config_set(const struct scmi_protocol_handle
*ph
,
289 u32 domain_id
, u32 config
)
293 struct voltage_info
*vinfo
= ph
->get_priv(ph
);
294 struct scmi_msg_cmd_config_set
*cmd
;
296 if (domain_id
>= vinfo
->num_domains
)
299 ret
= ph
->xops
->xfer_get_init(ph
, VOLTAGE_CONFIG_SET
,
300 sizeof(*cmd
), 0, &t
);
305 cmd
->domain_id
= cpu_to_le32(domain_id
);
306 cmd
->config
= cpu_to_le32(config
& GENMASK(3, 0));
308 ret
= ph
->xops
->do_xfer(ph
, t
);
310 ph
->xops
->xfer_put(ph
, t
);
314 static int scmi_voltage_config_get(const struct scmi_protocol_handle
*ph
,
315 u32 domain_id
, u32
*config
)
317 return __scmi_voltage_get_u32(ph
, VOLTAGE_CONFIG_GET
,
321 static int scmi_voltage_level_set(const struct scmi_protocol_handle
*ph
,
323 enum scmi_voltage_level_mode mode
,
328 struct voltage_info
*vinfo
= ph
->get_priv(ph
);
329 struct scmi_msg_cmd_level_set
*cmd
;
330 struct scmi_voltage_info
*v
;
332 if (domain_id
>= vinfo
->num_domains
)
335 ret
= ph
->xops
->xfer_get_init(ph
, VOLTAGE_LEVEL_SET
,
336 sizeof(*cmd
), 0, &t
);
340 v
= vinfo
->domains
+ domain_id
;
343 cmd
->domain_id
= cpu_to_le32(domain_id
);
344 cmd
->voltage_level
= cpu_to_le32(volt_uV
);
346 if (!v
->async_level_set
|| mode
!= SCMI_VOLTAGE_LEVEL_SET_AUTO
) {
347 cmd
->flags
= cpu_to_le32(0x0);
348 ret
= ph
->xops
->do_xfer(ph
, t
);
350 cmd
->flags
= cpu_to_le32(0x1);
351 ret
= ph
->xops
->do_xfer_with_response(ph
, t
);
353 struct scmi_resp_voltage_level_set_complete
*resp
;
356 if (le32_to_cpu(resp
->domain_id
) == domain_id
)
358 "Voltage domain %d set async to %d\n",
360 le32_to_cpu(resp
->voltage_level
));
366 ph
->xops
->xfer_put(ph
, t
);
370 static int scmi_voltage_level_get(const struct scmi_protocol_handle
*ph
,
371 u32 domain_id
, s32
*volt_uV
)
373 return __scmi_voltage_get_u32(ph
, VOLTAGE_LEVEL_GET
,
374 domain_id
, (u32
*)volt_uV
);
377 static const struct scmi_voltage_info
* __must_check
378 scmi_voltage_info_get(const struct scmi_protocol_handle
*ph
, u32 domain_id
)
380 struct voltage_info
*vinfo
= ph
->get_priv(ph
);
382 if (domain_id
>= vinfo
->num_domains
||
383 !vinfo
->domains
[domain_id
].num_levels
)
386 return vinfo
->domains
+ domain_id
;
389 static int scmi_voltage_domains_num_get(const struct scmi_protocol_handle
*ph
)
391 struct voltage_info
*vinfo
= ph
->get_priv(ph
);
393 return vinfo
->num_domains
;
396 static struct scmi_voltage_proto_ops voltage_proto_ops
= {
397 .num_domains_get
= scmi_voltage_domains_num_get
,
398 .info_get
= scmi_voltage_info_get
,
399 .config_set
= scmi_voltage_config_set
,
400 .config_get
= scmi_voltage_config_get
,
401 .level_set
= scmi_voltage_level_set
,
402 .level_get
= scmi_voltage_level_get
,
405 static int scmi_voltage_protocol_init(const struct scmi_protocol_handle
*ph
)
409 struct voltage_info
*vinfo
;
411 ret
= ph
->xops
->version_get(ph
, &version
);
415 dev_dbg(ph
->dev
, "Voltage Version %d.%d\n",
416 PROTOCOL_REV_MAJOR(version
), PROTOCOL_REV_MINOR(version
));
418 vinfo
= devm_kzalloc(ph
->dev
, sizeof(*vinfo
), GFP_KERNEL
);
421 vinfo
->version
= version
;
423 ret
= scmi_protocol_attributes_get(ph
, vinfo
);
427 if (vinfo
->num_domains
) {
428 vinfo
->domains
= devm_kcalloc(ph
->dev
, vinfo
->num_domains
,
429 sizeof(*vinfo
->domains
),
433 ret
= scmi_voltage_descriptors_get(ph
, vinfo
);
437 dev_warn(ph
->dev
, "No Voltage domains found.\n");
440 return ph
->set_priv(ph
, vinfo
, version
);
443 static const struct scmi_protocol scmi_voltage
= {
444 .id
= SCMI_PROTOCOL_VOLTAGE
,
445 .owner
= THIS_MODULE
,
446 .instance_init
= &scmi_voltage_protocol_init
,
447 .ops
= &voltage_proto_ops
,
448 .supported_version
= SCMI_PROTOCOL_SUPPORTED_VERSION
,
451 DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(voltage
, scmi_voltage
)