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