aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSudeep Holla <sudeep.holla@arm.com>2017-06-06 06:16:15 -0400
committerSudeep Holla <sudeep.holla@arm.com>2018-02-28 11:37:57 -0500
commitb6f20ff8bd94ad34032804a60bab5ee56752007e (patch)
tree0e03d268b946903fa9f2af685d38c89fc875f837
parentaa4f886f3893f88146e8e02fd1e9c5c9e43cbcc1 (diff)
firmware: arm_scmi: add common infrastructure and support for base protocol
The base protocol describes the properties of the implementation and provide generic error management. The base protocol provides commands to describe protocol version, discover implementation specific attributes and vendor/sub-vendor identification, list of protocols implemented and the various agents are in the system including OSPM and the platform. It also supports registering for notifications of platform errors. This protocol is mandatory. This patch adds support for the same along with some basic infrastructure to add support for other protocols. Cc: Arnd Bergmann <arnd@arndb.de> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>
-rw-r--r--drivers/firmware/arm_scmi/Makefile3
-rw-r--r--drivers/firmware/arm_scmi/base.c253
-rw-r--r--drivers/firmware/arm_scmi/common.h37
-rw-r--r--drivers/firmware/arm_scmi/driver.c53
-rw-r--r--include/linux/scmi_protocol.h37
5 files changed, 382 insertions, 1 deletions
diff --git a/drivers/firmware/arm_scmi/Makefile b/drivers/firmware/arm_scmi/Makefile
index b2a24ba2b636..5d9c7ef35f0f 100644
--- a/drivers/firmware/arm_scmi/Makefile
+++ b/drivers/firmware/arm_scmi/Makefile
@@ -1,2 +1,3 @@
1obj-y = scmi-driver.o 1obj-y = scmi-driver.o scmi-protocols.o
2scmi-driver-y = driver.o 2scmi-driver-y = driver.o
3scmi-protocols-y = base.o
diff --git a/drivers/firmware/arm_scmi/base.c b/drivers/firmware/arm_scmi/base.c
new file mode 100644
index 000000000000..0d3806c0d432
--- /dev/null
+++ b/drivers/firmware/arm_scmi/base.c
@@ -0,0 +1,253 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * System Control and Management Interface (SCMI) Base Protocol
4 *
5 * Copyright (C) 2018 ARM Ltd.
6 */
7
8#include "common.h"
9
10enum 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,
17};
18
19struct scmi_msg_resp_base_attributes {
20 u8 num_protocols;
21 u8 num_agents;
22 __le16 reserved;
23};
24
25/**
26 * scmi_base_attributes_get() - gets the implementation details
27 * that are associated with the base protocol.
28 *
29 * @handle - SCMI entity handle
30 *
31 * Return: 0 on success, else appropriate SCMI error.
32 */
33static int scmi_base_attributes_get(const struct scmi_handle *handle)
34{
35 int ret;
36 struct scmi_xfer *t;
37 struct scmi_msg_resp_base_attributes *attr_info;
38 struct scmi_revision_info *rev = handle->version;
39
40 ret = scmi_one_xfer_init(handle, PROTOCOL_ATTRIBUTES,
41 SCMI_PROTOCOL_BASE, 0, sizeof(*attr_info), &t);
42 if (ret)
43 return ret;
44
45 ret = scmi_do_xfer(handle, t);
46 if (!ret) {
47 attr_info = t->rx.buf;
48 rev->num_protocols = attr_info->num_protocols;
49 rev->num_agents = attr_info->num_agents;
50 }
51
52 scmi_one_xfer_put(handle, t);
53 return ret;
54}
55
56/**
57 * scmi_base_vendor_id_get() - gets vendor/subvendor identifier ASCII string.
58 *
59 * @handle - SCMI entity handle
60 * @sub_vendor - specify true if sub-vendor ID is needed
61 *
62 * Return: 0 on success, else appropriate SCMI error.
63 */
64static int
65scmi_base_vendor_id_get(const struct scmi_handle *handle, bool sub_vendor)
66{
67 u8 cmd;
68 int ret, size;
69 char *vendor_id;
70 struct scmi_xfer *t;
71 struct scmi_revision_info *rev = handle->version;
72
73 if (sub_vendor) {
74 cmd = BASE_DISCOVER_SUB_VENDOR;
75 vendor_id = rev->sub_vendor_id;
76 size = ARRAY_SIZE(rev->sub_vendor_id);
77 } else {
78 cmd = BASE_DISCOVER_VENDOR;
79 vendor_id = rev->vendor_id;
80 size = ARRAY_SIZE(rev->vendor_id);
81 }
82
83 ret = scmi_one_xfer_init(handle, cmd, SCMI_PROTOCOL_BASE, 0, size, &t);
84 if (ret)
85 return ret;
86
87 ret = scmi_do_xfer(handle, t);
88 if (!ret)
89 memcpy(vendor_id, t->rx.buf, size);
90
91 scmi_one_xfer_put(handle, t);
92 return ret;
93}
94
95/**
96 * scmi_base_implementation_version_get() - gets a vendor-specific
97 * implementation 32-bit version. The format of the version number is
98 * vendor-specific
99 *
100 * @handle - SCMI entity handle
101 *
102 * Return: 0 on success, else appropriate SCMI error.
103 */
104static int
105scmi_base_implementation_version_get(const struct scmi_handle *handle)
106{
107 int ret;
108 __le32 *impl_ver;
109 struct scmi_xfer *t;
110 struct scmi_revision_info *rev = handle->version;
111
112 ret = scmi_one_xfer_init(handle, BASE_DISCOVER_IMPLEMENT_VERSION,
113 SCMI_PROTOCOL_BASE, 0, sizeof(*impl_ver), &t);
114 if (ret)
115 return ret;
116
117 ret = scmi_do_xfer(handle, t);
118 if (!ret) {
119 impl_ver = t->rx.buf;
120 rev->impl_ver = le32_to_cpu(*impl_ver);
121 }
122
123 scmi_one_xfer_put(handle, t);
124 return ret;
125}
126
127/**
128 * scmi_base_implementation_list_get() - gets the list of protocols it is
129 * OSPM is allowed to access
130 *
131 * @handle - SCMI entity handle
132 * @protocols_imp - pointer to hold the list of protocol identifiers
133 *
134 * Return: 0 on success, else appropriate SCMI error.
135 */
136static int scmi_base_implementation_list_get(const struct scmi_handle *handle,
137 u8 *protocols_imp)
138{
139 u8 *list;
140 int ret, loop;
141 struct scmi_xfer *t;
142 __le32 *num_skip, *num_ret;
143 u32 tot_num_ret = 0, loop_num_ret;
144 struct device *dev = handle->dev;
145
146 ret = scmi_one_xfer_init(handle, BASE_DISCOVER_LIST_PROTOCOLS,
147 SCMI_PROTOCOL_BASE, sizeof(*num_skip), 0, &t);
148 if (ret)
149 return ret;
150
151 num_skip = t->tx.buf;
152 num_ret = t->rx.buf;
153 list = t->rx.buf + sizeof(*num_ret);
154
155 do {
156 /* Set the number of protocols to be skipped/already read */
157 *num_skip = cpu_to_le32(tot_num_ret);
158
159 ret = scmi_do_xfer(handle, t);
160 if (ret)
161 break;
162
163 loop_num_ret = le32_to_cpu(*num_ret);
164 if (tot_num_ret + loop_num_ret > MAX_PROTOCOLS_IMP) {
165 dev_err(dev, "No. of Protocol > MAX_PROTOCOLS_IMP");
166 break;
167 }
168
169 for (loop = 0; loop < loop_num_ret; loop++)
170 protocols_imp[tot_num_ret + loop] = *(list + loop);
171
172 tot_num_ret += loop_num_ret;
173 } while (loop_num_ret);
174
175 scmi_one_xfer_put(handle, t);
176 return ret;
177}
178
179/**
180 * scmi_base_discover_agent_get() - discover the name of an agent
181 *
182 * @handle - SCMI entity handle
183 * @id - Agent identifier
184 * @name - Agent identifier ASCII string
185 *
186 * An agent id of 0 is reserved to identify the platform itself.
187 * Generally operating system is represented as "OSPM"
188 *
189 * Return: 0 on success, else appropriate SCMI error.
190 */
191static int scmi_base_discover_agent_get(const struct scmi_handle *handle,
192 int id, char *name)
193{
194 int ret;
195 struct scmi_xfer *t;
196
197 ret = scmi_one_xfer_init(handle, BASE_DISCOVER_AGENT,
198 SCMI_PROTOCOL_BASE, sizeof(__le32),
199 SCMI_MAX_STR_SIZE, &t);
200 if (ret)
201 return ret;
202
203 *(__le32 *)t->tx.buf = cpu_to_le32(id);
204
205 ret = scmi_do_xfer(handle, t);
206 if (!ret)
207 memcpy(name, t->rx.buf, SCMI_MAX_STR_SIZE);
208
209 scmi_one_xfer_put(handle, t);
210 return ret;
211}
212
213int scmi_base_protocol_init(struct scmi_handle *h)
214{
215 int id, ret;
216 u8 *prot_imp;
217 u32 version;
218 char name[SCMI_MAX_STR_SIZE];
219 const struct scmi_handle *handle = h;
220 struct device *dev = handle->dev;
221 struct scmi_revision_info *rev = handle->version;
222
223 ret = scmi_version_get(handle, SCMI_PROTOCOL_BASE, &version);
224 if (ret)
225 return ret;
226
227 prot_imp = devm_kcalloc(dev, MAX_PROTOCOLS_IMP, sizeof(u8), GFP_KERNEL);
228 if (!prot_imp)
229 return -ENOMEM;
230
231 rev->major_ver = PROTOCOL_REV_MAJOR(version),
232 rev->minor_ver = PROTOCOL_REV_MINOR(version);
233
234 scmi_base_attributes_get(handle);
235 scmi_base_vendor_id_get(handle, false);
236 scmi_base_vendor_id_get(handle, true);
237 scmi_base_implementation_version_get(handle);
238 scmi_base_implementation_list_get(handle, prot_imp);
239 scmi_setup_protocol_implemented(handle, prot_imp);
240
241 dev_info(dev, "SCMI Protocol v%d.%d '%s:%s' Firmware version 0x%x\n",
242 rev->major_ver, rev->minor_ver, rev->vendor_id,
243 rev->sub_vendor_id, rev->impl_ver);
244 dev_dbg(dev, "Found %d protocol(s) %d agent(s)\n", rev->num_protocols,
245 rev->num_agents);
246
247 for (id = 0; id < rev->num_agents; id++) {
248 scmi_base_discover_agent_get(handle, id, name);
249 dev_dbg(dev, "Agent %d: %s\n", id, name);
250 }
251
252 return 0;
253}
diff --git a/drivers/firmware/arm_scmi/common.h b/drivers/firmware/arm_scmi/common.h
index d57eb1862f68..0fc9f5ae8684 100644
--- a/drivers/firmware/arm_scmi/common.h
+++ b/drivers/firmware/arm_scmi/common.h
@@ -8,9 +8,41 @@
8 */ 8 */
9 9
10#include <linux/completion.h> 10#include <linux/completion.h>
11#include <linux/device.h>
12#include <linux/errno.h>
13#include <linux/kernel.h>
11#include <linux/scmi_protocol.h> 14#include <linux/scmi_protocol.h>
12#include <linux/types.h> 15#include <linux/types.h>
13 16
17#define PROTOCOL_REV_MINOR_BITS 16
18#define PROTOCOL_REV_MINOR_MASK ((1U << PROTOCOL_REV_MINOR_BITS) - 1)
19#define PROTOCOL_REV_MAJOR(x) ((x) >> PROTOCOL_REV_MINOR_BITS)
20#define PROTOCOL_REV_MINOR(x) ((x) & PROTOCOL_REV_MINOR_MASK)
21#define MAX_PROTOCOLS_IMP 16
22
23enum scmi_common_cmd {
24 PROTOCOL_VERSION = 0x0,
25 PROTOCOL_ATTRIBUTES = 0x1,
26 PROTOCOL_MESSAGE_ATTRIBUTES = 0x2,
27};
28
29/**
30 * struct scmi_msg_resp_prot_version - Response for a message
31 *
32 * @major_version: Major version of the ABI that firmware supports
33 * @minor_version: Minor version of the ABI that firmware supports
34 *
35 * In general, ABI version changes follow the rule that minor version increments
36 * are backward compatible. Major revision changes in ABI may not be
37 * backward compatible.
38 *
39 * Response to a generic message with message type SCMI_MSG_VERSION
40 */
41struct scmi_msg_resp_prot_version {
42 __le16 minor_version;
43 __le16 major_version;
44};
45
14/** 46/**
15 * struct scmi_msg_hdr - Message(Tx/Rx) header 47 * struct scmi_msg_hdr - Message(Tx/Rx) header
16 * 48 *
@@ -64,3 +96,8 @@ int scmi_one_xfer_init(const struct scmi_handle *h, u8 msg_id, u8 prot_id,
64 size_t tx_size, size_t rx_size, struct scmi_xfer **p); 96 size_t tx_size, size_t rx_size, struct scmi_xfer **p);
65int scmi_handle_put(const struct scmi_handle *handle); 97int scmi_handle_put(const struct scmi_handle *handle);
66struct scmi_handle *scmi_handle_get(struct device *dev); 98struct scmi_handle *scmi_handle_get(struct device *dev);
99int scmi_version_get(const struct scmi_handle *h, u8 protocol, u32 *version);
100void scmi_setup_protocol_implemented(const struct scmi_handle *handle,
101 u8 *prot_imp);
102
103int scmi_base_protocol_init(struct scmi_handle *h);
diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c
index 7824cce54373..49875cd68365 100644
--- a/drivers/firmware/arm_scmi/driver.c
+++ b/drivers/firmware/arm_scmi/driver.c
@@ -94,21 +94,27 @@ struct scmi_desc {
94 * @dev: Device pointer 94 * @dev: Device pointer
95 * @desc: SoC description for this instance 95 * @desc: SoC description for this instance
96 * @handle: Instance of SCMI handle to send to clients 96 * @handle: Instance of SCMI handle to send to clients
97 * @version: SCMI revision information containing protocol version,
98 * implementation version and (sub-)vendor identification.
97 * @cl: Mailbox Client 99 * @cl: Mailbox Client
98 * @tx_chan: Transmit mailbox channel 100 * @tx_chan: Transmit mailbox channel
99 * @tx_payload: Transmit mailbox channel payload area 101 * @tx_payload: Transmit mailbox channel payload area
100 * @minfo: Message info 102 * @minfo: Message info
103 * @protocols_imp: list of protocols implemented, currently maximum of
104 * MAX_PROTOCOLS_IMP elements allocated by the base protocol
101 * @node: list head 105 * @node: list head
102 * @users: Number of users of this instance 106 * @users: Number of users of this instance
103 */ 107 */
104struct scmi_info { 108struct scmi_info {
105 struct device *dev; 109 struct device *dev;
106 const struct scmi_desc *desc; 110 const struct scmi_desc *desc;
111 struct scmi_revision_info version;
107 struct scmi_handle handle; 112 struct scmi_handle handle;
108 struct mbox_client cl; 113 struct mbox_client cl;
109 struct mbox_chan *tx_chan; 114 struct mbox_chan *tx_chan;
110 void __iomem *tx_payload; 115 void __iomem *tx_payload;
111 struct scmi_xfers_info minfo; 116 struct scmi_xfers_info minfo;
117 u8 *protocols_imp;
112 struct list_head node; 118 struct list_head node;
113 int users; 119 int users;
114}; 120};
@@ -422,6 +428,45 @@ int scmi_one_xfer_init(const struct scmi_handle *handle, u8 msg_id, u8 prot_id,
422} 428}
423 429
424/** 430/**
431 * scmi_version_get() - command to get the revision of the SCMI entity
432 *
433 * @handle: Handle to SCMI entity information
434 *
435 * Updates the SCMI information in the internal data structure.
436 *
437 * Return: 0 if all went fine, else return appropriate error.
438 */
439int scmi_version_get(const struct scmi_handle *handle, u8 protocol,
440 u32 *version)
441{
442 int ret;
443 __le32 *rev_info;
444 struct scmi_xfer *t;
445
446 ret = scmi_one_xfer_init(handle, PROTOCOL_VERSION, protocol, 0,
447 sizeof(*version), &t);
448 if (ret)
449 return ret;
450
451 ret = scmi_do_xfer(handle, t);
452 if (!ret) {
453 rev_info = t->rx.buf;
454 *version = le32_to_cpu(*rev_info);
455 }
456
457 scmi_one_xfer_put(handle, t);
458 return ret;
459}
460
461void scmi_setup_protocol_implemented(const struct scmi_handle *handle,
462 u8 *prot_imp)
463{
464 struct scmi_info *info = handle_to_scmi_info(handle);
465
466 info->protocols_imp = prot_imp;
467}
468
469/**
425 * scmi_handle_get() - Get the SCMI handle for a device 470 * scmi_handle_get() - Get the SCMI handle for a device
426 * 471 *
427 * @dev: pointer to device for which we want SCMI handle 472 * @dev: pointer to device for which we want SCMI handle
@@ -649,11 +694,19 @@ static int scmi_probe(struct platform_device *pdev)
649 694
650 handle = &info->handle; 695 handle = &info->handle;
651 handle->dev = info->dev; 696 handle->dev = info->dev;
697 handle->version = &info->version;
652 698
653 ret = scmi_mbox_chan_setup(info); 699 ret = scmi_mbox_chan_setup(info);
654 if (ret) 700 if (ret)
655 return ret; 701 return ret;
656 702
703 ret = scmi_base_protocol_init(handle);
704 if (ret) {
705 dev_err(dev, "unable to communicate with SCMI(%d)\n", ret);
706 scmi_mbox_free_channel(info);
707 return ret;
708 }
709
657 mutex_lock(&scmi_list_mutex); 710 mutex_lock(&scmi_list_mutex);
658 list_add_tail(&info->node, &scmi_list); 711 list_add_tail(&info->node, &scmi_list);
659 mutex_unlock(&scmi_list_mutex); 712 mutex_unlock(&scmi_list_mutex);
diff --git a/include/linux/scmi_protocol.h b/include/linux/scmi_protocol.h
index 1f0e89b270c6..08fcc1dd0276 100644
--- a/include/linux/scmi_protocol.h
+++ b/include/linux/scmi_protocol.h
@@ -6,11 +6,48 @@
6 */ 6 */
7#include <linux/types.h> 7#include <linux/types.h>
8 8
9#define SCMI_MAX_STR_SIZE 16
10
11/**
12 * struct scmi_revision_info - version information structure
13 *
14 * @major_ver: Major ABI version. Change here implies risk of backward
15 * compatibility break.
16 * @minor_ver: Minor ABI version. Change here implies new feature addition,
17 * or compatible change in ABI.
18 * @num_protocols: Number of protocols that are implemented, excluding the
19 * base protocol.
20 * @num_agents: Number of agents in the system.
21 * @impl_ver: A vendor-specific implementation version.
22 * @vendor_id: A vendor identifier(Null terminated ASCII string)
23 * @sub_vendor_id: A sub-vendor identifier(Null terminated ASCII string)
24 */
25struct scmi_revision_info {
26 u16 major_ver;
27 u16 minor_ver;
28 u8 num_protocols;
29 u8 num_agents;
30 u32 impl_ver;
31 char vendor_id[SCMI_MAX_STR_SIZE];
32 char sub_vendor_id[SCMI_MAX_STR_SIZE];
33};
34
9/** 35/**
10 * struct scmi_handle - Handle returned to ARM SCMI clients for usage. 36 * struct scmi_handle - Handle returned to ARM SCMI clients for usage.
11 * 37 *
12 * @dev: pointer to the SCMI device 38 * @dev: pointer to the SCMI device
39 * @version: pointer to the structure containing SCMI version information
13 */ 40 */
14struct scmi_handle { 41struct scmi_handle {
15 struct device *dev; 42 struct device *dev;
43 struct scmi_revision_info *version;
44};
45
46enum scmi_std_protocol {
47 SCMI_PROTOCOL_BASE = 0x10,
48 SCMI_PROTOCOL_POWER = 0x11,
49 SCMI_PROTOCOL_SYSTEM = 0x12,
50 SCMI_PROTOCOL_PERF = 0x13,
51 SCMI_PROTOCOL_CLOCK = 0x14,
52 SCMI_PROTOCOL_SENSOR = 0x15,
16}; 53};