aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSudeep Holla <sudeep.holla@arm.com>2017-03-28 06:36:07 -0400
committerSudeep Holla <sudeep.holla@arm.com>2018-02-28 11:37:57 -0500
commitaa4f886f3893f88146e8e02fd1e9c5c9e43cbcc1 (patch)
treec5e8d6adccd1c673f26463891ad39852d05fe785
parentfe7be8b297b279189260f8ce084ea16fab0c2be0 (diff)
firmware: arm_scmi: add basic driver infrastructure for SCMI
The SCMI is intended to allow OSPM to manage various functions that are provided by the hardware platform it is running on, including power and performance functions. SCMI provides two levels of abstraction, protocols and transports. Protocols define individual groups of system control and management messages. A protocol specification describes the messages that it supports. Transports describe the method by which protocol messages are communicated between agents and the platform. This patch adds basic infrastructure to manage the message allocation, initialisation, packing/unpacking and shared memory management. 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--MAINTAINERS3
-rw-r--r--drivers/firmware/Kconfig21
-rw-r--r--drivers/firmware/Makefile1
-rw-r--r--drivers/firmware/arm_scmi/Makefile2
-rw-r--r--drivers/firmware/arm_scmi/common.h66
-rw-r--r--drivers/firmware/arm_scmi/driver.c678
-rw-r--r--include/linux/scmi_protocol.h16
7 files changed, 786 insertions, 1 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index 5c8c55ba22a3..7cede6e7dfed 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -13387,7 +13387,8 @@ F: Documentation/devicetree/bindings/arm/arm,sc[mp]i.txt
13387F: drivers/clk/clk-scpi.c 13387F: drivers/clk/clk-scpi.c
13388F: drivers/cpufreq/scpi-cpufreq.c 13388F: drivers/cpufreq/scpi-cpufreq.c
13389F: drivers/firmware/arm_scpi.c 13389F: drivers/firmware/arm_scpi.c
13390F: include/linux/scpi_protocol.h 13390F: drivers/firmware/arm_scmi/
13391F: include/linux/sc[mp]i_protocol.h
13391 13392
13392SYSTEM RESET/SHUTDOWN DRIVERS 13393SYSTEM RESET/SHUTDOWN DRIVERS
13393M: Sebastian Reichel <sre@kernel.org> 13394M: Sebastian Reichel <sre@kernel.org>
diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig
index b7c748248e53..704961e0473a 100644
--- a/drivers/firmware/Kconfig
+++ b/drivers/firmware/Kconfig
@@ -19,6 +19,27 @@ config ARM_PSCI_CHECKER
19 on and off through hotplug, so for now torture tests and PSCI checker 19 on and off through hotplug, so for now torture tests and PSCI checker
20 are mutually exclusive. 20 are mutually exclusive.
21 21
22config ARM_SCMI_PROTOCOL
23 bool "ARM System Control and Management Interface (SCMI) Message Protocol"
24 depends on ARM || ARM64 || COMPILE_TEST
25 depends on MAILBOX
26 help
27 ARM System Control and Management Interface (SCMI) protocol is a
28 set of operating system-independent software interfaces that are
29 used in system management. SCMI is extensible and currently provides
30 interfaces for: Discovery and self-description of the interfaces
31 it supports, Power domain management which is the ability to place
32 a given device or domain into the various power-saving states that
33 it supports, Performance management which is the ability to control
34 the performance of a domain that is composed of compute engines
35 such as application processors and other accelerators, Clock
36 management which is the ability to set and inquire rates on platform
37 managed clocks and Sensor management which is the ability to read
38 sensor data, and be notified of sensor value.
39
40 This protocol library provides interface for all the client drivers
41 making use of the features offered by the SCMI.
42
22config ARM_SCPI_PROTOCOL 43config ARM_SCPI_PROTOCOL
23 tristate "ARM System Control and Power Interface (SCPI) Message Protocol" 44 tristate "ARM System Control and Power Interface (SCPI) Message Protocol"
24 depends on ARM || ARM64 || COMPILE_TEST 45 depends on ARM || ARM64 || COMPILE_TEST
diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile
index b248238ddc6a..e18a041cfc53 100644
--- a/drivers/firmware/Makefile
+++ b/drivers/firmware/Makefile
@@ -25,6 +25,7 @@ obj-$(CONFIG_QCOM_SCM_32) += qcom_scm-32.o
25CFLAGS_qcom_scm-32.o :=$(call as-instr,.arch armv7-a\n.arch_extension sec,-DREQUIRES_SEC=1) -march=armv7-a 25CFLAGS_qcom_scm-32.o :=$(call as-instr,.arch armv7-a\n.arch_extension sec,-DREQUIRES_SEC=1) -march=armv7-a
26obj-$(CONFIG_TI_SCI_PROTOCOL) += ti_sci.o 26obj-$(CONFIG_TI_SCI_PROTOCOL) += ti_sci.o
27 27
28obj-$(CONFIG_ARM_SCMI_PROTOCOL) += arm_scmi/
28obj-y += broadcom/ 29obj-y += broadcom/
29obj-y += meson/ 30obj-y += meson/
30obj-$(CONFIG_GOOGLE_FIRMWARE) += google/ 31obj-$(CONFIG_GOOGLE_FIRMWARE) += google/
diff --git a/drivers/firmware/arm_scmi/Makefile b/drivers/firmware/arm_scmi/Makefile
new file mode 100644
index 000000000000..b2a24ba2b636
--- /dev/null
+++ b/drivers/firmware/arm_scmi/Makefile
@@ -0,0 +1,2 @@
1obj-y = scmi-driver.o
2scmi-driver-y = driver.o
diff --git a/drivers/firmware/arm_scmi/common.h b/drivers/firmware/arm_scmi/common.h
new file mode 100644
index 000000000000..d57eb1862f68
--- /dev/null
+++ b/drivers/firmware/arm_scmi/common.h
@@ -0,0 +1,66 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * System Control and Management Interface (SCMI) Message Protocol
4 * driver common header file containing some definitions, structures
5 * and function prototypes used in all the different SCMI protocols.
6 *
7 * Copyright (C) 2018 ARM Ltd.
8 */
9
10#include <linux/completion.h>
11#include <linux/scmi_protocol.h>
12#include <linux/types.h>
13
14/**
15 * struct scmi_msg_hdr - Message(Tx/Rx) header
16 *
17 * @id: The identifier of the command being sent
18 * @protocol_id: The identifier of the protocol used to send @id command
19 * @seq: The token to identify the message. when a message/command returns,
20 * the platform returns the whole message header unmodified including
21 * the token.
22 */
23struct scmi_msg_hdr {
24 u8 id;
25 u8 protocol_id;
26 u16 seq;
27 u32 status;
28 bool poll_completion;
29};
30
31/**
32 * struct scmi_msg - Message(Tx/Rx) structure
33 *
34 * @buf: Buffer pointer
35 * @len: Length of data in the Buffer
36 */
37struct scmi_msg {
38 void *buf;
39 size_t len;
40};
41
42/**
43 * struct scmi_xfer - Structure representing a message flow
44 *
45 * @hdr: Transmit message header
46 * @tx: Transmit message
47 * @rx: Receive message, the buffer should be pre-allocated to store
48 * message. If request-ACK protocol is used, we can reuse the same
49 * buffer for the rx path as we use for the tx path.
50 * @done: completion event
51 */
52
53struct scmi_xfer {
54 void *con_priv;
55 struct scmi_msg_hdr hdr;
56 struct scmi_msg tx;
57 struct scmi_msg rx;
58 struct completion done;
59};
60
61void scmi_one_xfer_put(const struct scmi_handle *h, struct scmi_xfer *xfer);
62int scmi_do_xfer(const struct scmi_handle *h, struct scmi_xfer *xfer);
63int 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);
65int scmi_handle_put(const struct scmi_handle *handle);
66struct scmi_handle *scmi_handle_get(struct device *dev);
diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c
new file mode 100644
index 000000000000..7824cce54373
--- /dev/null
+++ b/drivers/firmware/arm_scmi/driver.c
@@ -0,0 +1,678 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * System Control and Management Interface (SCMI) Message Protocol driver
4 *
5 * SCMI Message Protocol is used between the System Control Processor(SCP)
6 * and the Application Processors(AP). The Message Handling Unit(MHU)
7 * provides a mechanism for inter-processor communication between SCP's
8 * Cortex M3 and AP.
9 *
10 * SCP offers control and management of the core/cluster power states,
11 * various power domain DVFS including the core/cluster, certain system
12 * clocks configuration, thermal sensors and many others.
13 *
14 * Copyright (C) 2018 ARM Ltd.
15 */
16
17#include <linux/bitmap.h>
18#include <linux/export.h>
19#include <linux/io.h>
20#include <linux/kernel.h>
21#include <linux/mailbox_client.h>
22#include <linux/module.h>
23#include <linux/of_address.h>
24#include <linux/of_device.h>
25#include <linux/semaphore.h>
26#include <linux/slab.h>
27
28#include "common.h"
29
30#define MSG_ID_SHIFT 0
31#define MSG_ID_MASK 0xff
32#define MSG_TYPE_SHIFT 8
33#define MSG_TYPE_MASK 0x3
34#define MSG_PROTOCOL_ID_SHIFT 10
35#define MSG_PROTOCOL_ID_MASK 0xff
36#define MSG_TOKEN_ID_SHIFT 18
37#define MSG_TOKEN_ID_MASK 0x3ff
38#define MSG_XTRACT_TOKEN(header) \
39 (((header) >> MSG_TOKEN_ID_SHIFT) & MSG_TOKEN_ID_MASK)
40
41enum scmi_error_codes {
42 SCMI_SUCCESS = 0, /* Success */
43 SCMI_ERR_SUPPORT = -1, /* Not supported */
44 SCMI_ERR_PARAMS = -2, /* Invalid Parameters */
45 SCMI_ERR_ACCESS = -3, /* Invalid access/permission denied */
46 SCMI_ERR_ENTRY = -4, /* Not found */
47 SCMI_ERR_RANGE = -5, /* Value out of range */
48 SCMI_ERR_BUSY = -6, /* Device busy */
49 SCMI_ERR_COMMS = -7, /* Communication Error */
50 SCMI_ERR_GENERIC = -8, /* Generic Error */
51 SCMI_ERR_HARDWARE = -9, /* Hardware Error */
52 SCMI_ERR_PROTOCOL = -10,/* Protocol Error */
53 SCMI_ERR_MAX
54};
55
56/* List of all SCMI devices active in system */
57static LIST_HEAD(scmi_list);
58/* Protection for the entire list */
59static DEFINE_MUTEX(scmi_list_mutex);
60
61/**
62 * struct scmi_xfers_info - Structure to manage transfer information
63 *
64 * @xfer_block: Preallocated Message array
65 * @xfer_alloc_table: Bitmap table for allocated messages.
66 * Index of this bitmap table is also used for message
67 * sequence identifier.
68 * @xfer_lock: Protection for message allocation
69 */
70struct scmi_xfers_info {
71 struct scmi_xfer *xfer_block;
72 unsigned long *xfer_alloc_table;
73 /* protect transfer allocation */
74 spinlock_t xfer_lock;
75};
76
77/**
78 * struct scmi_desc - Description of SoC integration
79 *
80 * @max_rx_timeout_ms: Timeout for communication with SoC (in Milliseconds)
81 * @max_msg: Maximum number of messages that can be pending
82 * simultaneously in the system
83 * @max_msg_size: Maximum size of data per message that can be handled.
84 */
85struct scmi_desc {
86 int max_rx_timeout_ms;
87 int max_msg;
88 int max_msg_size;
89};
90
91/**
92 * struct scmi_info - Structure representing a SCMI instance
93 *
94 * @dev: Device pointer
95 * @desc: SoC description for this instance
96 * @handle: Instance of SCMI handle to send to clients
97 * @cl: Mailbox Client
98 * @tx_chan: Transmit mailbox channel
99 * @tx_payload: Transmit mailbox channel payload area
100 * @minfo: Message info
101 * @node: list head
102 * @users: Number of users of this instance
103 */
104struct scmi_info {
105 struct device *dev;
106 const struct scmi_desc *desc;
107 struct scmi_handle handle;
108 struct mbox_client cl;
109 struct mbox_chan *tx_chan;
110 void __iomem *tx_payload;
111 struct scmi_xfers_info minfo;
112 struct list_head node;
113 int users;
114};
115
116#define client_to_scmi_info(c) container_of(c, struct scmi_info, cl)
117#define handle_to_scmi_info(h) container_of(h, struct scmi_info, handle)
118
119/*
120 * SCMI specification requires all parameters, message headers, return
121 * arguments or any protocol data to be expressed in little endian
122 * format only.
123 */
124struct scmi_shared_mem {
125 __le32 reserved;
126 __le32 channel_status;
127#define SCMI_SHMEM_CHAN_STAT_CHANNEL_ERROR BIT(1)
128#define SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE BIT(0)
129 __le32 reserved1[2];
130 __le32 flags;
131#define SCMI_SHMEM_FLAG_INTR_ENABLED BIT(0)
132 __le32 length;
133 __le32 msg_header;
134 u8 msg_payload[0];
135};
136
137static const int scmi_linux_errmap[] = {
138 /* better than switch case as long as return value is continuous */
139 0, /* SCMI_SUCCESS */
140 -EOPNOTSUPP, /* SCMI_ERR_SUPPORT */
141 -EINVAL, /* SCMI_ERR_PARAM */
142 -EACCES, /* SCMI_ERR_ACCESS */
143 -ENOENT, /* SCMI_ERR_ENTRY */
144 -ERANGE, /* SCMI_ERR_RANGE */
145 -EBUSY, /* SCMI_ERR_BUSY */
146 -ECOMM, /* SCMI_ERR_COMMS */
147 -EIO, /* SCMI_ERR_GENERIC */
148 -EREMOTEIO, /* SCMI_ERR_HARDWARE */
149 -EPROTO, /* SCMI_ERR_PROTOCOL */
150};
151
152static inline int scmi_to_linux_errno(int errno)
153{
154 if (errno < SCMI_SUCCESS && errno > SCMI_ERR_MAX)
155 return scmi_linux_errmap[-errno];
156 return -EIO;
157}
158
159/**
160 * scmi_dump_header_dbg() - Helper to dump a message header.
161 *
162 * @dev: Device pointer corresponding to the SCMI entity
163 * @hdr: pointer to header.
164 */
165static inline void scmi_dump_header_dbg(struct device *dev,
166 struct scmi_msg_hdr *hdr)
167{
168 dev_dbg(dev, "Command ID: %x Sequence ID: %x Protocol: %x\n",
169 hdr->id, hdr->seq, hdr->protocol_id);
170}
171
172static void scmi_fetch_response(struct scmi_xfer *xfer,
173 struct scmi_shared_mem __iomem *mem)
174{
175 xfer->hdr.status = ioread32(mem->msg_payload);
176 /* Skip the length of header and statues in payload area i.e 8 bytes*/
177 xfer->rx.len = min_t(size_t, xfer->rx.len, ioread32(&mem->length) - 8);
178
179 /* Take a copy to the rx buffer.. */
180 memcpy_fromio(xfer->rx.buf, mem->msg_payload + 4, xfer->rx.len);
181}
182
183/**
184 * scmi_rx_callback() - mailbox client callback for receive messages
185 *
186 * @cl: client pointer
187 * @m: mailbox message
188 *
189 * Processes one received message to appropriate transfer information and
190 * signals completion of the transfer.
191 *
192 * NOTE: This function will be invoked in IRQ context, hence should be
193 * as optimal as possible.
194 */
195static void scmi_rx_callback(struct mbox_client *cl, void *m)
196{
197 u16 xfer_id;
198 struct scmi_xfer *xfer;
199 struct scmi_info *info = client_to_scmi_info(cl);
200 struct scmi_xfers_info *minfo = &info->minfo;
201 struct device *dev = info->dev;
202 struct scmi_shared_mem __iomem *mem = info->tx_payload;
203
204 xfer_id = MSG_XTRACT_TOKEN(ioread32(&mem->msg_header));
205
206 /*
207 * Are we even expecting this?
208 */
209 if (!test_bit(xfer_id, minfo->xfer_alloc_table)) {
210 dev_err(dev, "message for %d is not expected!\n", xfer_id);
211 return;
212 }
213
214 xfer = &minfo->xfer_block[xfer_id];
215
216 scmi_dump_header_dbg(dev, &xfer->hdr);
217 /* Is the message of valid length? */
218 if (xfer->rx.len > info->desc->max_msg_size) {
219 dev_err(dev, "unable to handle %zu xfer(max %d)\n",
220 xfer->rx.len, info->desc->max_msg_size);
221 return;
222 }
223
224 scmi_fetch_response(xfer, mem);
225 complete(&xfer->done);
226}
227
228/**
229 * pack_scmi_header() - packs and returns 32-bit header
230 *
231 * @hdr: pointer to header containing all the information on message id,
232 * protocol id and sequence id.
233 */
234static inline u32 pack_scmi_header(struct scmi_msg_hdr *hdr)
235{
236 return ((hdr->id & MSG_ID_MASK) << MSG_ID_SHIFT) |
237 ((hdr->seq & MSG_TOKEN_ID_MASK) << MSG_TOKEN_ID_SHIFT) |
238 ((hdr->protocol_id & MSG_PROTOCOL_ID_MASK) << MSG_PROTOCOL_ID_SHIFT);
239}
240
241/**
242 * scmi_tx_prepare() - mailbox client callback to prepare for the transfer
243 *
244 * @cl: client pointer
245 * @m: mailbox message
246 *
247 * This function prepares the shared memory which contains the header and the
248 * payload.
249 */
250static void scmi_tx_prepare(struct mbox_client *cl, void *m)
251{
252 struct scmi_xfer *t = m;
253 struct scmi_info *info = client_to_scmi_info(cl);
254 struct scmi_shared_mem __iomem *mem = info->tx_payload;
255
256 /* Mark channel busy + clear error */
257 iowrite32(0x0, &mem->channel_status);
258 iowrite32(t->hdr.poll_completion ? 0 : SCMI_SHMEM_FLAG_INTR_ENABLED,
259 &mem->flags);
260 iowrite32(sizeof(mem->msg_header) + t->tx.len, &mem->length);
261 iowrite32(pack_scmi_header(&t->hdr), &mem->msg_header);
262 if (t->tx.buf)
263 memcpy_toio(mem->msg_payload, t->tx.buf, t->tx.len);
264}
265
266/**
267 * scmi_one_xfer_get() - Allocate one message
268 *
269 * @handle: SCMI entity handle
270 *
271 * Helper function which is used by various command functions that are
272 * exposed to clients of this driver for allocating a message traffic event.
273 *
274 * This function can sleep depending on pending requests already in the system
275 * for the SCMI entity. Further, this also holds a spinlock to maintain
276 * integrity of internal data structures.
277 *
278 * Return: 0 if all went fine, else corresponding error.
279 */
280static struct scmi_xfer *scmi_one_xfer_get(const struct scmi_handle *handle)
281{
282 u16 xfer_id;
283 struct scmi_xfer *xfer;
284 unsigned long flags, bit_pos;
285 struct scmi_info *info = handle_to_scmi_info(handle);
286 struct scmi_xfers_info *minfo = &info->minfo;
287
288 /* Keep the locked section as small as possible */
289 spin_lock_irqsave(&minfo->xfer_lock, flags);
290 bit_pos = find_first_zero_bit(minfo->xfer_alloc_table,
291 info->desc->max_msg);
292 if (bit_pos == info->desc->max_msg) {
293 spin_unlock_irqrestore(&minfo->xfer_lock, flags);
294 return ERR_PTR(-ENOMEM);
295 }
296 set_bit(bit_pos, minfo->xfer_alloc_table);
297 spin_unlock_irqrestore(&minfo->xfer_lock, flags);
298
299 xfer_id = bit_pos;
300
301 xfer = &minfo->xfer_block[xfer_id];
302 xfer->hdr.seq = xfer_id;
303 reinit_completion(&xfer->done);
304
305 return xfer;
306}
307
308/**
309 * scmi_one_xfer_put() - Release a message
310 *
311 * @minfo: transfer info pointer
312 * @xfer: message that was reserved by scmi_one_xfer_get
313 *
314 * This holds a spinlock to maintain integrity of internal data structures.
315 */
316void scmi_one_xfer_put(const struct scmi_handle *handle, struct scmi_xfer *xfer)
317{
318 unsigned long flags;
319 struct scmi_info *info = handle_to_scmi_info(handle);
320 struct scmi_xfers_info *minfo = &info->minfo;
321
322 /*
323 * Keep the locked section as small as possible
324 * NOTE: we might escape with smp_mb and no lock here..
325 * but just be conservative and symmetric.
326 */
327 spin_lock_irqsave(&minfo->xfer_lock, flags);
328 clear_bit(xfer->hdr.seq, minfo->xfer_alloc_table);
329 spin_unlock_irqrestore(&minfo->xfer_lock, flags);
330}
331
332/**
333 * scmi_do_xfer() - Do one transfer
334 *
335 * @info: Pointer to SCMI entity information
336 * @xfer: Transfer to initiate and wait for response
337 *
338 * Return: -ETIMEDOUT in case of no response, if transmit error,
339 * return corresponding error, else if all goes well,
340 * return 0.
341 */
342int scmi_do_xfer(const struct scmi_handle *handle, struct scmi_xfer *xfer)
343{
344 int ret;
345 int timeout;
346 struct scmi_info *info = handle_to_scmi_info(handle);
347 struct device *dev = info->dev;
348
349 ret = mbox_send_message(info->tx_chan, xfer);
350 if (ret < 0) {
351 dev_dbg(dev, "mbox send fail %d\n", ret);
352 return ret;
353 }
354
355 /* mbox_send_message returns non-negative value on success, so reset */
356 ret = 0;
357
358 /* And we wait for the response. */
359 timeout = msecs_to_jiffies(info->desc->max_rx_timeout_ms);
360 if (!wait_for_completion_timeout(&xfer->done, timeout)) {
361 dev_err(dev, "mbox timed out in resp(caller: %pS)\n",
362 (void *)_RET_IP_);
363 ret = -ETIMEDOUT;
364 } else if (xfer->hdr.status) {
365 ret = scmi_to_linux_errno(xfer->hdr.status);
366 }
367 /*
368 * NOTE: we might prefer not to need the mailbox ticker to manage the
369 * transfer queueing since the protocol layer queues things by itself.
370 * Unfortunately, we have to kick the mailbox framework after we have
371 * received our message.
372 */
373 mbox_client_txdone(info->tx_chan, ret);
374
375 return ret;
376}
377
378/**
379 * scmi_one_xfer_init() - Allocate and initialise one message
380 *
381 * @handle: SCMI entity handle
382 * @msg_id: Message identifier
383 * @msg_prot_id: Protocol identifier for the message
384 * @tx_size: transmit message size
385 * @rx_size: receive message size
386 * @p: pointer to the allocated and initialised message
387 *
388 * This function allocates the message using @scmi_one_xfer_get and
389 * initialise the header.
390 *
391 * Return: 0 if all went fine with @p pointing to message, else
392 * corresponding error.
393 */
394int scmi_one_xfer_init(const struct scmi_handle *handle, u8 msg_id, u8 prot_id,
395 size_t tx_size, size_t rx_size, struct scmi_xfer **p)
396{
397 int ret;
398 struct scmi_xfer *xfer;
399 struct scmi_info *info = handle_to_scmi_info(handle);
400 struct device *dev = info->dev;
401
402 /* Ensure we have sane transfer sizes */
403 if (rx_size > info->desc->max_msg_size ||
404 tx_size > info->desc->max_msg_size)
405 return -ERANGE;
406
407 xfer = scmi_one_xfer_get(handle);
408 if (IS_ERR(xfer)) {
409 ret = PTR_ERR(xfer);
410 dev_err(dev, "failed to get free message slot(%d)\n", ret);
411 return ret;
412 }
413
414 xfer->tx.len = tx_size;
415 xfer->rx.len = rx_size ? : info->desc->max_msg_size;
416 xfer->hdr.id = msg_id;
417 xfer->hdr.protocol_id = prot_id;
418 xfer->hdr.poll_completion = false;
419
420 *p = xfer;
421 return 0;
422}
423
424/**
425 * scmi_handle_get() - Get the SCMI handle for a device
426 *
427 * @dev: pointer to device for which we want SCMI handle
428 *
429 * NOTE: The function does not track individual clients of the framework
430 * and is expected to be maintained by caller of SCMI protocol library.
431 * scmi_handle_put must be balanced with successful scmi_handle_get
432 *
433 * Return: pointer to handle if successful, NULL on error
434 */
435struct scmi_handle *scmi_handle_get(struct device *dev)
436{
437 struct list_head *p;
438 struct scmi_info *info;
439 struct scmi_handle *handle = NULL;
440
441 mutex_lock(&scmi_list_mutex);
442 list_for_each(p, &scmi_list) {
443 info = list_entry(p, struct scmi_info, node);
444 if (dev->parent == info->dev) {
445 handle = &info->handle;
446 info->users++;
447 break;
448 }
449 }
450 mutex_unlock(&scmi_list_mutex);
451
452 return handle;
453}
454
455/**
456 * scmi_handle_put() - Release the handle acquired by scmi_handle_get
457 *
458 * @handle: handle acquired by scmi_handle_get
459 *
460 * NOTE: The function does not track individual clients of the framework
461 * and is expected to be maintained by caller of SCMI protocol library.
462 * scmi_handle_put must be balanced with successful scmi_handle_get
463 *
464 * Return: 0 is successfully released
465 * if null was passed, it returns -EINVAL;
466 */
467int scmi_handle_put(const struct scmi_handle *handle)
468{
469 struct scmi_info *info;
470
471 if (!handle)
472 return -EINVAL;
473
474 info = handle_to_scmi_info(handle);
475 mutex_lock(&scmi_list_mutex);
476 if (!WARN_ON(!info->users))
477 info->users--;
478 mutex_unlock(&scmi_list_mutex);
479
480 return 0;
481}
482
483static const struct scmi_desc scmi_generic_desc = {
484 .max_rx_timeout_ms = 30, /* we may increase this if required */
485 .max_msg = 20, /* Limited by MBOX_TX_QUEUE_LEN */
486 .max_msg_size = 128,
487};
488
489/* Each compatible listed below must have descriptor associated with it */
490static const struct of_device_id scmi_of_match[] = {
491 { .compatible = "arm,scmi", .data = &scmi_generic_desc },
492 { /* Sentinel */ },
493};
494
495MODULE_DEVICE_TABLE(of, scmi_of_match);
496
497static int scmi_xfer_info_init(struct scmi_info *sinfo)
498{
499 int i;
500 struct scmi_xfer *xfer;
501 struct device *dev = sinfo->dev;
502 const struct scmi_desc *desc = sinfo->desc;
503 struct scmi_xfers_info *info = &sinfo->minfo;
504
505 /* Pre-allocated messages, no more than what hdr.seq can support */
506 if (WARN_ON(desc->max_msg >= (MSG_TOKEN_ID_MASK + 1))) {
507 dev_err(dev, "Maximum message of %d exceeds supported %d\n",
508 desc->max_msg, MSG_TOKEN_ID_MASK + 1);
509 return -EINVAL;
510 }
511
512 info->xfer_block = devm_kcalloc(dev, desc->max_msg,
513 sizeof(*info->xfer_block), GFP_KERNEL);
514 if (!info->xfer_block)
515 return -ENOMEM;
516
517 info->xfer_alloc_table = devm_kcalloc(dev, BITS_TO_LONGS(desc->max_msg),
518 sizeof(long), GFP_KERNEL);
519 if (!info->xfer_alloc_table)
520 return -ENOMEM;
521
522 bitmap_zero(info->xfer_alloc_table, desc->max_msg);
523
524 /* Pre-initialize the buffer pointer to pre-allocated buffers */
525 for (i = 0, xfer = info->xfer_block; i < desc->max_msg; i++, xfer++) {
526 xfer->rx.buf = devm_kcalloc(dev, sizeof(u8), desc->max_msg_size,
527 GFP_KERNEL);
528 if (!xfer->rx.buf)
529 return -ENOMEM;
530
531 xfer->tx.buf = xfer->rx.buf;
532 init_completion(&xfer->done);
533 }
534
535 spin_lock_init(&info->xfer_lock);
536
537 return 0;
538}
539
540static int scmi_mailbox_check(struct device_node *np)
541{
542 struct of_phandle_args arg;
543
544 return of_parse_phandle_with_args(np, "mboxes", "#mbox-cells", 0, &arg);
545}
546
547static int scmi_mbox_free_channel(struct scmi_info *info)
548{
549 if (!IS_ERR_OR_NULL(info->tx_chan)) {
550 mbox_free_channel(info->tx_chan);
551 info->tx_chan = NULL;
552 }
553
554 return 0;
555}
556
557static int scmi_remove(struct platform_device *pdev)
558{
559 int ret = 0;
560 struct scmi_info *info = platform_get_drvdata(pdev);
561
562 mutex_lock(&scmi_list_mutex);
563 if (info->users)
564 ret = -EBUSY;
565 else
566 list_del(&info->node);
567 mutex_unlock(&scmi_list_mutex);
568
569 if (!ret)
570 /* Safe to free channels since no more users */
571 return scmi_mbox_free_channel(info);
572
573 return ret;
574}
575
576static inline int scmi_mbox_chan_setup(struct scmi_info *info)
577{
578 int ret;
579 struct resource res;
580 resource_size_t size;
581 struct device *dev = info->dev;
582 struct device_node *shmem, *np = dev->of_node;
583 struct mbox_client *cl;
584
585 cl = &info->cl;
586 cl->dev = dev;
587 cl->rx_callback = scmi_rx_callback;
588 cl->tx_prepare = scmi_tx_prepare;
589 cl->tx_block = false;
590 cl->knows_txdone = true;
591
592 shmem = of_parse_phandle(np, "shmem", 0);
593 ret = of_address_to_resource(shmem, 0, &res);
594 of_node_put(shmem);
595 if (ret) {
596 dev_err(dev, "failed to get SCMI Tx payload mem resource\n");
597 return ret;
598 }
599
600 size = resource_size(&res);
601 info->tx_payload = devm_ioremap(dev, res.start, size);
602 if (!info->tx_payload) {
603 dev_err(dev, "failed to ioremap SCMI Tx payload\n");
604 return -EADDRNOTAVAIL;
605 }
606
607 /* Transmit channel is first entry i.e. index 0 */
608 info->tx_chan = mbox_request_channel(cl, 0);
609 if (IS_ERR(info->tx_chan)) {
610 ret = PTR_ERR(info->tx_chan);
611 if (ret != -EPROBE_DEFER)
612 dev_err(dev, "failed to request SCMI Tx mailbox\n");
613 return ret;
614 }
615
616 return 0;
617}
618
619static int scmi_probe(struct platform_device *pdev)
620{
621 int ret;
622 struct scmi_handle *handle;
623 const struct scmi_desc *desc;
624 struct scmi_info *info;
625 struct device *dev = &pdev->dev;
626 struct device_node *np = dev->of_node;
627
628 /* Only mailbox method supported, check for the presence of one */
629 if (scmi_mailbox_check(np)) {
630 dev_err(dev, "no mailbox found in %pOF\n", np);
631 return -EINVAL;
632 }
633
634 desc = of_match_device(scmi_of_match, dev)->data;
635
636 info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL);
637 if (!info)
638 return -ENOMEM;
639
640 info->dev = dev;
641 info->desc = desc;
642 INIT_LIST_HEAD(&info->node);
643
644 ret = scmi_xfer_info_init(info);
645 if (ret)
646 return ret;
647
648 platform_set_drvdata(pdev, info);
649
650 handle = &info->handle;
651 handle->dev = info->dev;
652
653 ret = scmi_mbox_chan_setup(info);
654 if (ret)
655 return ret;
656
657 mutex_lock(&scmi_list_mutex);
658 list_add_tail(&info->node, &scmi_list);
659 mutex_unlock(&scmi_list_mutex);
660
661 return 0;
662}
663
664static struct platform_driver scmi_driver = {
665 .driver = {
666 .name = "arm-scmi",
667 .of_match_table = scmi_of_match,
668 },
669 .probe = scmi_probe,
670 .remove = scmi_remove,
671};
672
673module_platform_driver(scmi_driver);
674
675MODULE_ALIAS("platform: arm-scmi");
676MODULE_AUTHOR("Sudeep Holla <sudeep.holla@arm.com>");
677MODULE_DESCRIPTION("ARM SCMI protocol driver");
678MODULE_LICENSE("GPL v2");
diff --git a/include/linux/scmi_protocol.h b/include/linux/scmi_protocol.h
new file mode 100644
index 000000000000..1f0e89b270c6
--- /dev/null
+++ b/include/linux/scmi_protocol.h
@@ -0,0 +1,16 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * SCMI Message Protocol driver header
4 *
5 * Copyright (C) 2018 ARM Ltd.
6 */
7#include <linux/types.h>
8
9/**
10 * struct scmi_handle - Handle returned to ARM SCMI clients for usage.
11 *
12 * @dev: pointer to the SCMI device
13 */
14struct scmi_handle {
15 struct device *dev;
16};