xref: /openbmc/linux/drivers/firmware/arm_scmi/shmem.c (revision 4ddfb4af07c82e7f63c28347e463046aa14c1837)
15c8a47a5SViresh Kumar // SPDX-License-Identifier: GPL-2.0
25c8a47a5SViresh Kumar /*
35c8a47a5SViresh Kumar  * For transport using shared mem structure.
45c8a47a5SViresh Kumar  *
55c8a47a5SViresh Kumar  * Copyright (C) 2019 ARM Ltd.
65c8a47a5SViresh Kumar  */
75c8a47a5SViresh Kumar 
85c8a47a5SViresh Kumar #include <linux/io.h>
95c8a47a5SViresh Kumar #include <linux/processor.h>
105c8a47a5SViresh Kumar #include <linux/types.h>
115c8a47a5SViresh Kumar 
125c8a47a5SViresh Kumar #include "common.h"
135c8a47a5SViresh Kumar 
145c8a47a5SViresh Kumar /*
155c8a47a5SViresh Kumar  * SCMI specification requires all parameters, message headers, return
165c8a47a5SViresh Kumar  * arguments or any protocol data to be expressed in little endian
175c8a47a5SViresh Kumar  * format only.
185c8a47a5SViresh Kumar  */
195c8a47a5SViresh Kumar struct scmi_shared_mem {
205c8a47a5SViresh Kumar 	__le32 reserved;
215c8a47a5SViresh Kumar 	__le32 channel_status;
225c8a47a5SViresh Kumar #define SCMI_SHMEM_CHAN_STAT_CHANNEL_ERROR	BIT(1)
235c8a47a5SViresh Kumar #define SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE	BIT(0)
245c8a47a5SViresh Kumar 	__le32 reserved1[2];
255c8a47a5SViresh Kumar 	__le32 flags;
265c8a47a5SViresh Kumar #define SCMI_SHMEM_FLAG_INTR_ENABLED	BIT(0)
275c8a47a5SViresh Kumar 	__le32 length;
285c8a47a5SViresh Kumar 	__le32 msg_header;
29*4ddfb4afSGustavo A. R. Silva 	u8 msg_payload[];
305c8a47a5SViresh Kumar };
315c8a47a5SViresh Kumar 
325c8a47a5SViresh Kumar void shmem_tx_prepare(struct scmi_shared_mem __iomem *shmem,
335c8a47a5SViresh Kumar 		      struct scmi_xfer *xfer)
345c8a47a5SViresh Kumar {
355c8a47a5SViresh Kumar 	/*
365c8a47a5SViresh Kumar 	 * Ideally channel must be free by now unless OS timeout last
375c8a47a5SViresh Kumar 	 * request and platform continued to process the same, wait
385c8a47a5SViresh Kumar 	 * until it releases the shared memory, otherwise we may endup
395c8a47a5SViresh Kumar 	 * overwriting its response with new message payload or vice-versa
405c8a47a5SViresh Kumar 	 */
415c8a47a5SViresh Kumar 	spin_until_cond(ioread32(&shmem->channel_status) &
425c8a47a5SViresh Kumar 			SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE);
435c8a47a5SViresh Kumar 	/* Mark channel busy + clear error */
445c8a47a5SViresh Kumar 	iowrite32(0x0, &shmem->channel_status);
455c8a47a5SViresh Kumar 	iowrite32(xfer->hdr.poll_completion ? 0 : SCMI_SHMEM_FLAG_INTR_ENABLED,
465c8a47a5SViresh Kumar 		  &shmem->flags);
475c8a47a5SViresh Kumar 	iowrite32(sizeof(shmem->msg_header) + xfer->tx.len, &shmem->length);
485c8a47a5SViresh Kumar 	iowrite32(pack_scmi_header(&xfer->hdr), &shmem->msg_header);
495c8a47a5SViresh Kumar 	if (xfer->tx.buf)
505c8a47a5SViresh Kumar 		memcpy_toio(shmem->msg_payload, xfer->tx.buf, xfer->tx.len);
515c8a47a5SViresh Kumar }
525c8a47a5SViresh Kumar 
535c8a47a5SViresh Kumar u32 shmem_read_header(struct scmi_shared_mem __iomem *shmem)
545c8a47a5SViresh Kumar {
555c8a47a5SViresh Kumar 	return ioread32(&shmem->msg_header);
565c8a47a5SViresh Kumar }
575c8a47a5SViresh Kumar 
585c8a47a5SViresh Kumar void shmem_fetch_response(struct scmi_shared_mem __iomem *shmem,
595c8a47a5SViresh Kumar 			  struct scmi_xfer *xfer)
605c8a47a5SViresh Kumar {
615c8a47a5SViresh Kumar 	xfer->hdr.status = ioread32(shmem->msg_payload);
625c8a47a5SViresh Kumar 	/* Skip the length of header and status in shmem area i.e 8 bytes */
635c8a47a5SViresh Kumar 	xfer->rx.len = min_t(size_t, xfer->rx.len,
645c8a47a5SViresh Kumar 			     ioread32(&shmem->length) - 8);
655c8a47a5SViresh Kumar 
665c8a47a5SViresh Kumar 	/* Take a copy to the rx buffer.. */
675c8a47a5SViresh Kumar 	memcpy_fromio(xfer->rx.buf, shmem->msg_payload + 4, xfer->rx.len);
685c8a47a5SViresh Kumar }
695c8a47a5SViresh Kumar 
705c8a47a5SViresh Kumar bool shmem_poll_done(struct scmi_shared_mem __iomem *shmem,
715c8a47a5SViresh Kumar 		     struct scmi_xfer *xfer)
725c8a47a5SViresh Kumar {
735c8a47a5SViresh Kumar 	u16 xfer_id;
745c8a47a5SViresh Kumar 
755c8a47a5SViresh Kumar 	xfer_id = MSG_XTRACT_TOKEN(ioread32(&shmem->msg_header));
765c8a47a5SViresh Kumar 
775c8a47a5SViresh Kumar 	if (xfer->hdr.seq != xfer_id)
785c8a47a5SViresh Kumar 		return false;
795c8a47a5SViresh Kumar 
805c8a47a5SViresh Kumar 	return ioread32(&shmem->channel_status) &
815c8a47a5SViresh Kumar 		(SCMI_SHMEM_CHAN_STAT_CHANNEL_ERROR |
825c8a47a5SViresh Kumar 		 SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE);
835c8a47a5SViresh Kumar }
84