xref: /openbmc/linux/drivers/firmware/arm_scmi/shmem.c (revision 5c8a47a5a91d4d6e185f758d61997613d9c5d6ac)
1*5c8a47a5SViresh Kumar // SPDX-License-Identifier: GPL-2.0
2*5c8a47a5SViresh Kumar /*
3*5c8a47a5SViresh Kumar  * For transport using shared mem structure.
4*5c8a47a5SViresh Kumar  *
5*5c8a47a5SViresh Kumar  * Copyright (C) 2019 ARM Ltd.
6*5c8a47a5SViresh Kumar  */
7*5c8a47a5SViresh Kumar 
8*5c8a47a5SViresh Kumar #include <linux/io.h>
9*5c8a47a5SViresh Kumar #include <linux/processor.h>
10*5c8a47a5SViresh Kumar #include <linux/types.h>
11*5c8a47a5SViresh Kumar 
12*5c8a47a5SViresh Kumar #include "common.h"
13*5c8a47a5SViresh Kumar 
14*5c8a47a5SViresh Kumar /*
15*5c8a47a5SViresh Kumar  * SCMI specification requires all parameters, message headers, return
16*5c8a47a5SViresh Kumar  * arguments or any protocol data to be expressed in little endian
17*5c8a47a5SViresh Kumar  * format only.
18*5c8a47a5SViresh Kumar  */
19*5c8a47a5SViresh Kumar struct scmi_shared_mem {
20*5c8a47a5SViresh Kumar 	__le32 reserved;
21*5c8a47a5SViresh Kumar 	__le32 channel_status;
22*5c8a47a5SViresh Kumar #define SCMI_SHMEM_CHAN_STAT_CHANNEL_ERROR	BIT(1)
23*5c8a47a5SViresh Kumar #define SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE	BIT(0)
24*5c8a47a5SViresh Kumar 	__le32 reserved1[2];
25*5c8a47a5SViresh Kumar 	__le32 flags;
26*5c8a47a5SViresh Kumar #define SCMI_SHMEM_FLAG_INTR_ENABLED	BIT(0)
27*5c8a47a5SViresh Kumar 	__le32 length;
28*5c8a47a5SViresh Kumar 	__le32 msg_header;
29*5c8a47a5SViresh Kumar 	u8 msg_payload[0];
30*5c8a47a5SViresh Kumar };
31*5c8a47a5SViresh Kumar 
32*5c8a47a5SViresh Kumar void shmem_tx_prepare(struct scmi_shared_mem __iomem *shmem,
33*5c8a47a5SViresh Kumar 		      struct scmi_xfer *xfer)
34*5c8a47a5SViresh Kumar {
35*5c8a47a5SViresh Kumar 	/*
36*5c8a47a5SViresh Kumar 	 * Ideally channel must be free by now unless OS timeout last
37*5c8a47a5SViresh Kumar 	 * request and platform continued to process the same, wait
38*5c8a47a5SViresh Kumar 	 * until it releases the shared memory, otherwise we may endup
39*5c8a47a5SViresh Kumar 	 * overwriting its response with new message payload or vice-versa
40*5c8a47a5SViresh Kumar 	 */
41*5c8a47a5SViresh Kumar 	spin_until_cond(ioread32(&shmem->channel_status) &
42*5c8a47a5SViresh Kumar 			SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE);
43*5c8a47a5SViresh Kumar 	/* Mark channel busy + clear error */
44*5c8a47a5SViresh Kumar 	iowrite32(0x0, &shmem->channel_status);
45*5c8a47a5SViresh Kumar 	iowrite32(xfer->hdr.poll_completion ? 0 : SCMI_SHMEM_FLAG_INTR_ENABLED,
46*5c8a47a5SViresh Kumar 		  &shmem->flags);
47*5c8a47a5SViresh Kumar 	iowrite32(sizeof(shmem->msg_header) + xfer->tx.len, &shmem->length);
48*5c8a47a5SViresh Kumar 	iowrite32(pack_scmi_header(&xfer->hdr), &shmem->msg_header);
49*5c8a47a5SViresh Kumar 	if (xfer->tx.buf)
50*5c8a47a5SViresh Kumar 		memcpy_toio(shmem->msg_payload, xfer->tx.buf, xfer->tx.len);
51*5c8a47a5SViresh Kumar }
52*5c8a47a5SViresh Kumar 
53*5c8a47a5SViresh Kumar u32 shmem_read_header(struct scmi_shared_mem __iomem *shmem)
54*5c8a47a5SViresh Kumar {
55*5c8a47a5SViresh Kumar 	return ioread32(&shmem->msg_header);
56*5c8a47a5SViresh Kumar }
57*5c8a47a5SViresh Kumar 
58*5c8a47a5SViresh Kumar void shmem_fetch_response(struct scmi_shared_mem __iomem *shmem,
59*5c8a47a5SViresh Kumar 			  struct scmi_xfer *xfer)
60*5c8a47a5SViresh Kumar {
61*5c8a47a5SViresh Kumar 	xfer->hdr.status = ioread32(shmem->msg_payload);
62*5c8a47a5SViresh Kumar 	/* Skip the length of header and status in shmem area i.e 8 bytes */
63*5c8a47a5SViresh Kumar 	xfer->rx.len = min_t(size_t, xfer->rx.len,
64*5c8a47a5SViresh Kumar 			     ioread32(&shmem->length) - 8);
65*5c8a47a5SViresh Kumar 
66*5c8a47a5SViresh Kumar 	/* Take a copy to the rx buffer.. */
67*5c8a47a5SViresh Kumar 	memcpy_fromio(xfer->rx.buf, shmem->msg_payload + 4, xfer->rx.len);
68*5c8a47a5SViresh Kumar }
69*5c8a47a5SViresh Kumar 
70*5c8a47a5SViresh Kumar bool shmem_poll_done(struct scmi_shared_mem __iomem *shmem,
71*5c8a47a5SViresh Kumar 		     struct scmi_xfer *xfer)
72*5c8a47a5SViresh Kumar {
73*5c8a47a5SViresh Kumar 	u16 xfer_id;
74*5c8a47a5SViresh Kumar 
75*5c8a47a5SViresh Kumar 	xfer_id = MSG_XTRACT_TOKEN(ioread32(&shmem->msg_header));
76*5c8a47a5SViresh Kumar 
77*5c8a47a5SViresh Kumar 	if (xfer->hdr.seq != xfer_id)
78*5c8a47a5SViresh Kumar 		return false;
79*5c8a47a5SViresh Kumar 
80*5c8a47a5SViresh Kumar 	return ioread32(&shmem->channel_status) &
81*5c8a47a5SViresh Kumar 		(SCMI_SHMEM_CHAN_STAT_CHANNEL_ERROR |
82*5c8a47a5SViresh Kumar 		 SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE);
83*5c8a47a5SViresh Kumar }
84