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
859172b21SCristian Marussi #include <linux/ktime.h>
95c8a47a5SViresh Kumar #include <linux/io.h>
105c8a47a5SViresh Kumar #include <linux/processor.h>
115c8a47a5SViresh Kumar #include <linux/types.h>
125c8a47a5SViresh Kumar
1359172b21SCristian Marussi #include <asm-generic/bug.h>
1459172b21SCristian Marussi
155c8a47a5SViresh Kumar #include "common.h"
165c8a47a5SViresh Kumar
175c8a47a5SViresh Kumar /*
185c8a47a5SViresh Kumar * SCMI specification requires all parameters, message headers, return
195c8a47a5SViresh Kumar * arguments or any protocol data to be expressed in little endian
205c8a47a5SViresh Kumar * format only.
215c8a47a5SViresh Kumar */
225c8a47a5SViresh Kumar struct scmi_shared_mem {
235c8a47a5SViresh Kumar __le32 reserved;
245c8a47a5SViresh Kumar __le32 channel_status;
255c8a47a5SViresh Kumar #define SCMI_SHMEM_CHAN_STAT_CHANNEL_ERROR BIT(1)
265c8a47a5SViresh Kumar #define SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE BIT(0)
275c8a47a5SViresh Kumar __le32 reserved1[2];
285c8a47a5SViresh Kumar __le32 flags;
295c8a47a5SViresh Kumar #define SCMI_SHMEM_FLAG_INTR_ENABLED BIT(0)
305c8a47a5SViresh Kumar __le32 length;
315c8a47a5SViresh Kumar __le32 msg_header;
324ddfb4afSGustavo A. R. Silva u8 msg_payload[];
335c8a47a5SViresh Kumar };
345c8a47a5SViresh Kumar
shmem_tx_prepare(struct scmi_shared_mem __iomem * shmem,struct scmi_xfer * xfer,struct scmi_chan_info * cinfo)355c8a47a5SViresh Kumar void shmem_tx_prepare(struct scmi_shared_mem __iomem *shmem,
3659172b21SCristian Marussi struct scmi_xfer *xfer, struct scmi_chan_info *cinfo)
375c8a47a5SViresh Kumar {
3859172b21SCristian Marussi ktime_t stop;
3959172b21SCristian Marussi
405c8a47a5SViresh Kumar /*
415c8a47a5SViresh Kumar * Ideally channel must be free by now unless OS timeout last
425c8a47a5SViresh Kumar * request and platform continued to process the same, wait
435c8a47a5SViresh Kumar * until it releases the shared memory, otherwise we may endup
4459172b21SCristian Marussi * overwriting its response with new message payload or vice-versa.
4559172b21SCristian Marussi * Giving up anyway after twice the expected channel timeout so as
4659172b21SCristian Marussi * not to bail-out on intermittent issues where the platform is
4759172b21SCristian Marussi * occasionally a bit slower to answer.
4859172b21SCristian Marussi *
4959172b21SCristian Marussi * Note that after a timeout is detected we bail-out and carry on but
5059172b21SCristian Marussi * the transport functionality is probably permanently compromised:
5159172b21SCristian Marussi * this is just to ease debugging and avoid complete hangs on boot
5259172b21SCristian Marussi * due to a misbehaving SCMI firmware.
535c8a47a5SViresh Kumar */
5459172b21SCristian Marussi stop = ktime_add_ms(ktime_get(), 2 * cinfo->rx_timeout_ms);
5559172b21SCristian Marussi spin_until_cond((ioread32(&shmem->channel_status) &
5659172b21SCristian Marussi SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE) ||
5759172b21SCristian Marussi ktime_after(ktime_get(), stop));
5859172b21SCristian Marussi if (!(ioread32(&shmem->channel_status) &
5959172b21SCristian Marussi SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE)) {
6059172b21SCristian Marussi WARN_ON_ONCE(1);
6159172b21SCristian Marussi dev_err(cinfo->dev,
6259172b21SCristian Marussi "Timeout waiting for a free TX channel !\n");
6359172b21SCristian Marussi return;
6459172b21SCristian Marussi }
6559172b21SCristian Marussi
665c8a47a5SViresh Kumar /* Mark channel busy + clear error */
675c8a47a5SViresh Kumar iowrite32(0x0, &shmem->channel_status);
685c8a47a5SViresh Kumar iowrite32(xfer->hdr.poll_completion ? 0 : SCMI_SHMEM_FLAG_INTR_ENABLED,
695c8a47a5SViresh Kumar &shmem->flags);
705c8a47a5SViresh Kumar iowrite32(sizeof(shmem->msg_header) + xfer->tx.len, &shmem->length);
715c8a47a5SViresh Kumar iowrite32(pack_scmi_header(&xfer->hdr), &shmem->msg_header);
725c8a47a5SViresh Kumar if (xfer->tx.buf)
735c8a47a5SViresh Kumar memcpy_toio(shmem->msg_payload, xfer->tx.buf, xfer->tx.len);
745c8a47a5SViresh Kumar }
755c8a47a5SViresh Kumar
shmem_read_header(struct scmi_shared_mem __iomem * shmem)765c8a47a5SViresh Kumar u32 shmem_read_header(struct scmi_shared_mem __iomem *shmem)
775c8a47a5SViresh Kumar {
785c8a47a5SViresh Kumar return ioread32(&shmem->msg_header);
795c8a47a5SViresh Kumar }
805c8a47a5SViresh Kumar
shmem_fetch_response(struct scmi_shared_mem __iomem * shmem,struct scmi_xfer * xfer)815c8a47a5SViresh Kumar void shmem_fetch_response(struct scmi_shared_mem __iomem *shmem,
825c8a47a5SViresh Kumar struct scmi_xfer *xfer)
835c8a47a5SViresh Kumar {
84ad78b81aSCristian Marussi size_t len = ioread32(&shmem->length);
85ad78b81aSCristian Marussi
865c8a47a5SViresh Kumar xfer->hdr.status = ioread32(shmem->msg_payload);
875c8a47a5SViresh Kumar /* Skip the length of header and status in shmem area i.e 8 bytes */
88ad78b81aSCristian Marussi xfer->rx.len = min_t(size_t, xfer->rx.len, len > 8 ? len - 8 : 0);
895c8a47a5SViresh Kumar
905c8a47a5SViresh Kumar /* Take a copy to the rx buffer.. */
915c8a47a5SViresh Kumar memcpy_fromio(xfer->rx.buf, shmem->msg_payload + 4, xfer->rx.len);
925c8a47a5SViresh Kumar }
935c8a47a5SViresh Kumar
shmem_fetch_notification(struct scmi_shared_mem __iomem * shmem,size_t max_len,struct scmi_xfer * xfer)94d5141f37SCristian Marussi void shmem_fetch_notification(struct scmi_shared_mem __iomem *shmem,
95d5141f37SCristian Marussi size_t max_len, struct scmi_xfer *xfer)
96d5141f37SCristian Marussi {
979bae076cSCristian Marussi size_t len = ioread32(&shmem->length);
989bae076cSCristian Marussi
99d5141f37SCristian Marussi /* Skip only the length of header in shmem area i.e 4 bytes */
1009bae076cSCristian Marussi xfer->rx.len = min_t(size_t, max_len, len > 4 ? len - 4 : 0);
101d5141f37SCristian Marussi
102d5141f37SCristian Marussi /* Take a copy to the rx buffer.. */
103d5141f37SCristian Marussi memcpy_fromio(xfer->rx.buf, shmem->msg_payload, xfer->rx.len);
104d5141f37SCristian Marussi }
105d5141f37SCristian Marussi
shmem_clear_channel(struct scmi_shared_mem __iomem * shmem)10687dff4e6SCristian Marussi void shmem_clear_channel(struct scmi_shared_mem __iomem *shmem)
107d5141f37SCristian Marussi {
108d5141f37SCristian Marussi iowrite32(SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE, &shmem->channel_status);
109d5141f37SCristian Marussi }
110d5141f37SCristian Marussi
shmem_poll_done(struct scmi_shared_mem __iomem * shmem,struct scmi_xfer * xfer)1115c8a47a5SViresh Kumar bool shmem_poll_done(struct scmi_shared_mem __iomem *shmem,
1125c8a47a5SViresh Kumar struct scmi_xfer *xfer)
1135c8a47a5SViresh Kumar {
1145c8a47a5SViresh Kumar u16 xfer_id;
1155c8a47a5SViresh Kumar
1165c8a47a5SViresh Kumar xfer_id = MSG_XTRACT_TOKEN(ioread32(&shmem->msg_header));
1175c8a47a5SViresh Kumar
1185c8a47a5SViresh Kumar if (xfer->hdr.seq != xfer_id)
1195c8a47a5SViresh Kumar return false;
1205c8a47a5SViresh Kumar
1215c8a47a5SViresh Kumar return ioread32(&shmem->channel_status) &
1225c8a47a5SViresh Kumar (SCMI_SHMEM_CHAN_STAT_CHANNEL_ERROR |
1235c8a47a5SViresh Kumar SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE);
1245c8a47a5SViresh Kumar }
125*9b5e1b93SCristian Marussi
shmem_channel_free(struct scmi_shared_mem __iomem * shmem)126*9b5e1b93SCristian Marussi bool shmem_channel_free(struct scmi_shared_mem __iomem *shmem)
127*9b5e1b93SCristian Marussi {
128*9b5e1b93SCristian Marussi return (ioread32(&shmem->channel_status) &
129*9b5e1b93SCristian Marussi SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE);
130*9b5e1b93SCristian Marussi }
131