1 // SPDX-License-Identifier: GPL-2.0
3 * System Control and Management Interface (SCMI) Base Protocol
5 * Copyright (C) 2018 ARM Ltd.
10 enum scmi_base_protocol_cmd
{
11 BASE_DISCOVER_VENDOR
= 0x3,
12 BASE_DISCOVER_SUB_VENDOR
= 0x4,
13 BASE_DISCOVER_IMPLEMENT_VERSION
= 0x5,
14 BASE_DISCOVER_LIST_PROTOCOLS
= 0x6,
15 BASE_DISCOVER_AGENT
= 0x7,
16 BASE_NOTIFY_ERRORS
= 0x8,
19 struct scmi_msg_resp_base_attributes
{
26 * scmi_base_attributes_get() - gets the implementation details
27 * that are associated with the base protocol.
29 * @handle: SCMI entity handle
31 * Return: 0 on success, else appropriate SCMI error.
33 static int scmi_base_attributes_get(const struct scmi_handle
*handle
)
37 struct scmi_msg_resp_base_attributes
*attr_info
;
38 struct scmi_revision_info
*rev
= handle
->version
;
40 ret
= scmi_xfer_get_init(handle
, PROTOCOL_ATTRIBUTES
,
41 SCMI_PROTOCOL_BASE
, 0, sizeof(*attr_info
), &t
);
45 ret
= scmi_do_xfer(handle
, t
);
47 attr_info
= t
->rx
.buf
;
48 rev
->num_protocols
= attr_info
->num_protocols
;
49 rev
->num_agents
= attr_info
->num_agents
;
52 scmi_xfer_put(handle
, t
);
58 * scmi_base_vendor_id_get() - gets vendor/subvendor identifier ASCII string.
60 * @handle: SCMI entity handle
61 * @sub_vendor: specify true if sub-vendor ID is needed
63 * Return: 0 on success, else appropriate SCMI error.
66 scmi_base_vendor_id_get(const struct scmi_handle
*handle
, bool sub_vendor
)
72 struct scmi_revision_info
*rev
= handle
->version
;
75 cmd
= BASE_DISCOVER_SUB_VENDOR
;
76 vendor_id
= rev
->sub_vendor_id
;
77 size
= ARRAY_SIZE(rev
->sub_vendor_id
);
79 cmd
= BASE_DISCOVER_VENDOR
;
80 vendor_id
= rev
->vendor_id
;
81 size
= ARRAY_SIZE(rev
->vendor_id
);
84 ret
= scmi_xfer_get_init(handle
, cmd
, SCMI_PROTOCOL_BASE
, 0, size
, &t
);
88 ret
= scmi_do_xfer(handle
, t
);
90 memcpy(vendor_id
, t
->rx
.buf
, size
);
92 scmi_xfer_put(handle
, t
);
98 * scmi_base_implementation_version_get() - gets a vendor-specific
99 * implementation 32-bit version. The format of the version number is
102 * @handle: SCMI entity handle
104 * Return: 0 on success, else appropriate SCMI error.
107 scmi_base_implementation_version_get(const struct scmi_handle
*handle
)
112 struct scmi_revision_info
*rev
= handle
->version
;
114 ret
= scmi_xfer_get_init(handle
, BASE_DISCOVER_IMPLEMENT_VERSION
,
115 SCMI_PROTOCOL_BASE
, 0, sizeof(*impl_ver
), &t
);
119 ret
= scmi_do_xfer(handle
, t
);
121 impl_ver
= t
->rx
.buf
;
122 rev
->impl_ver
= le32_to_cpu(*impl_ver
);
125 scmi_xfer_put(handle
, t
);
131 * scmi_base_implementation_list_get() - gets the list of protocols it is
132 * OSPM is allowed to access
134 * @handle: SCMI entity handle
135 * @protocols_imp: pointer to hold the list of protocol identifiers
137 * Return: 0 on success, else appropriate SCMI error.
139 static int scmi_base_implementation_list_get(const struct scmi_handle
*handle
,
145 __le32
*num_skip
, *num_ret
;
146 u32 tot_num_ret
= 0, loop_num_ret
;
147 struct device
*dev
= handle
->dev
;
149 ret
= scmi_xfer_get_init(handle
, BASE_DISCOVER_LIST_PROTOCOLS
,
150 SCMI_PROTOCOL_BASE
, sizeof(*num_skip
), 0, &t
);
154 num_skip
= t
->tx
.buf
;
156 list
= t
->rx
.buf
+ sizeof(*num_ret
);
159 /* Set the number of protocols to be skipped/already read */
160 *num_skip
= cpu_to_le32(tot_num_ret
);
162 ret
= scmi_do_xfer(handle
, t
);
166 loop_num_ret
= le32_to_cpu(*num_ret
);
167 if (tot_num_ret
+ loop_num_ret
> MAX_PROTOCOLS_IMP
) {
168 dev_err(dev
, "No. of Protocol > MAX_PROTOCOLS_IMP");
172 for (loop
= 0; loop
< loop_num_ret
; loop
++)
173 protocols_imp
[tot_num_ret
+ loop
] = *(list
+ loop
);
175 tot_num_ret
+= loop_num_ret
;
176 } while (loop_num_ret
);
178 scmi_xfer_put(handle
, t
);
184 * scmi_base_discover_agent_get() - discover the name of an agent
186 * @handle: SCMI entity handle
187 * @id: Agent identifier
188 * @name: Agent identifier ASCII string
190 * An agent id of 0 is reserved to identify the platform itself.
191 * Generally operating system is represented as "OSPM"
193 * Return: 0 on success, else appropriate SCMI error.
195 static int scmi_base_discover_agent_get(const struct scmi_handle
*handle
,
201 ret
= scmi_xfer_get_init(handle
, BASE_DISCOVER_AGENT
,
202 SCMI_PROTOCOL_BASE
, sizeof(__le32
),
203 SCMI_MAX_STR_SIZE
, &t
);
207 put_unaligned_le32(id
, t
->tx
.buf
);
209 ret
= scmi_do_xfer(handle
, t
);
211 strlcpy(name
, t
->rx
.buf
, SCMI_MAX_STR_SIZE
);
213 scmi_xfer_put(handle
, t
);
218 int scmi_base_protocol_init(struct scmi_handle
*h
)
223 char name
[SCMI_MAX_STR_SIZE
];
224 const struct scmi_handle
*handle
= h
;
225 struct device
*dev
= handle
->dev
;
226 struct scmi_revision_info
*rev
= handle
->version
;
228 ret
= scmi_version_get(handle
, SCMI_PROTOCOL_BASE
, &version
);
232 prot_imp
= devm_kcalloc(dev
, MAX_PROTOCOLS_IMP
, sizeof(u8
), GFP_KERNEL
);
236 rev
->major_ver
= PROTOCOL_REV_MAJOR(version
),
237 rev
->minor_ver
= PROTOCOL_REV_MINOR(version
);
239 scmi_base_attributes_get(handle
);
240 scmi_base_vendor_id_get(handle
, false);
241 scmi_base_vendor_id_get(handle
, true);
242 scmi_base_implementation_version_get(handle
);
243 scmi_base_implementation_list_get(handle
, prot_imp
);
244 scmi_setup_protocol_implemented(handle
, prot_imp
);
246 dev_info(dev
, "SCMI Protocol v%d.%d '%s:%s' Firmware version 0x%x\n",
247 rev
->major_ver
, rev
->minor_ver
, rev
->vendor_id
,
248 rev
->sub_vendor_id
, rev
->impl_ver
);
249 dev_dbg(dev
, "Found %d protocol(s) %d agent(s)\n", rev
->num_protocols
,
252 for (id
= 0; id
< rev
->num_agents
; id
++) {
253 scmi_base_discover_agent_get(handle
, id
, name
);
254 dev_dbg(dev
, "Agent %d: %s\n", id
, name
);