mirror of
https://source.denx.de/u-boot/u-boot.git
synced 2025-12-19 08:21:27 +01:00
MMU region cache behavior configuration for SCMI/SMT mailboxes is
platform specific. Even on ARM systems, the mailbox memory may not
even be located in any cacheable MMU region and may instead reside
in some SRAM. Remove this non-generic cache behavior configuration
code from generic code path.
It is unlikely that any platform is affected by this change if it
did configure its MMU regions correctly on start up. Platforms
which might be affected are i.MX94/95 and STM32MP.
Fixes: 240720e9052f ("firmware: scmi: mailbox/smt agent device")
Fixes: 2a3f161c8b16 ("scmi: correctly configure MMU for SCMI buffer")
Fixes: b2ae10970d40 ("firmware: scmi: use PAGE_SIZE alignment for ARM64")
Signed-off-by: Marek Vasut <marek.vasut+renesas@mailbox.org>
Tested-by: Alice Guo <alice.guo@nxp.com>
Tested-by: Patrice Chotard <patrice.chotard@foss.st.com>
Signed-off-by: Peng Fan <peng.fan@nxp.com>
202 lines
5.6 KiB
C
202 lines
5.6 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Copyright (c) 2015-2019, Arm Limited and Contributors. All rights reserved.
|
|
* Copyright (C) 2019-2022 Linaro Limited.
|
|
*/
|
|
|
|
#define LOG_CATEGORY UCLASS_SCMI_AGENT
|
|
|
|
#include <cpu_func.h>
|
|
#include <dm.h>
|
|
#include <dm/device_compat.h>
|
|
#include <errno.h>
|
|
#include <scmi_agent.h>
|
|
#include <asm/cache.h>
|
|
#include <asm/system.h>
|
|
#include <dm/ofnode.h>
|
|
#include <linux/compat.h>
|
|
#include <linux/io.h>
|
|
#include <linux/ioport.h>
|
|
|
|
#include "smt.h"
|
|
|
|
static void scmi_smt_enable_intr(struct scmi_smt *smt, bool enable)
|
|
{
|
|
struct scmi_smt_header *hdr = (void *)smt->buf;
|
|
|
|
if (enable)
|
|
iowrite32(ioread32(&hdr->flags) | SCMI_SHMEM_FLAG_INTR_ENABLED, &hdr->flags);
|
|
else
|
|
iowrite32(ioread32(&hdr->flags) & ~SCMI_SHMEM_FLAG_INTR_ENABLED, &hdr->flags);
|
|
}
|
|
|
|
/**
|
|
* Get shared memory configuration defined by the referred DT phandle
|
|
* Return with a errno compliant value.
|
|
*/
|
|
int scmi_dt_get_smt_buffer(struct udevice *dev, struct scmi_smt *smt)
|
|
{
|
|
int ret;
|
|
struct ofnode_phandle_args args;
|
|
struct resource resource;
|
|
|
|
ret = dev_read_phandle_with_args(dev, "shmem", NULL, 0, 0, &args);
|
|
if (ret)
|
|
return ret;
|
|
|
|
ret = ofnode_read_resource(args.node, 0, &resource);
|
|
if (ret)
|
|
return ret;
|
|
|
|
smt->size = resource_size(&resource);
|
|
if (smt->size < sizeof(struct scmi_smt_header)) {
|
|
dev_err(dev, "Shared memory buffer too small\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
smt->buf = devm_ioremap(dev, resource.start, smt->size);
|
|
if (!smt->buf)
|
|
return -ENOMEM;
|
|
|
|
if (device_is_compatible(dev, "arm,scmi") && ofnode_has_property(dev_ofnode(dev), "mboxes"))
|
|
scmi_smt_enable_intr(smt, true);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Write SCMI message @msg into a SMT shared buffer @smt.
|
|
* Return 0 on success and with a negative errno in case of error.
|
|
*/
|
|
int scmi_write_msg_to_smt(struct udevice *dev, struct scmi_smt *smt,
|
|
struct scmi_msg *msg)
|
|
{
|
|
struct scmi_smt_header *hdr = (void *)smt->buf;
|
|
|
|
if ((!msg->in_msg && msg->in_msg_sz) ||
|
|
(!msg->out_msg && msg->out_msg_sz))
|
|
return -EINVAL;
|
|
|
|
if (!(ioread32(&hdr->channel_status) & SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE)) {
|
|
dev_dbg(dev, "Channel busy\n");
|
|
return -EBUSY;
|
|
}
|
|
|
|
if (smt->size < (sizeof(*hdr) + msg->in_msg_sz) ||
|
|
smt->size < (sizeof(*hdr) + msg->out_msg_sz)) {
|
|
dev_err(dev,
|
|
"Buffer write too small: mst->size:%zu, in_msg_sz:%zu, out_msg_sz:%zu\n",
|
|
smt->size, msg->in_msg_sz, msg->out_msg_sz);
|
|
return -ETOOSMALL;
|
|
}
|
|
|
|
/* Load message in shared memory */
|
|
iowrite32(ioread32(&hdr->channel_status) & ~SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE,
|
|
&hdr->channel_status);
|
|
iowrite32(msg->in_msg_sz + sizeof(hdr->msg_header), &hdr->length);
|
|
iowrite32(SMT_HEADER_TOKEN(0) |
|
|
SMT_HEADER_MESSAGE_TYPE(0) |
|
|
SMT_HEADER_PROTOCOL_ID(msg->protocol_id) |
|
|
SMT_HEADER_MESSAGE_ID(msg->message_id), &hdr->msg_header);
|
|
|
|
memcpy_toio(hdr->msg_payload, msg->in_msg, msg->in_msg_sz);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Read SCMI message from a SMT shared buffer @smt and copy it into @msg.
|
|
* Return 0 on success and with a negative errno in case of error.
|
|
*/
|
|
int scmi_read_resp_from_smt(struct udevice *dev, struct scmi_smt *smt,
|
|
struct scmi_msg *msg)
|
|
{
|
|
struct scmi_smt_header *hdr = (void *)smt->buf;
|
|
|
|
if (!(ioread32(&hdr->channel_status) & SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE)) {
|
|
dev_err(dev, "Channel unexpectedly busy\n");
|
|
return -EBUSY;
|
|
}
|
|
|
|
if (ioread32(&hdr->channel_status) & SCMI_SHMEM_CHAN_STAT_CHANNEL_ERROR) {
|
|
dev_err(dev, "Channel error reported, reset channel\n");
|
|
return -ECOMM;
|
|
}
|
|
|
|
if (ioread32(&hdr->length) > msg->out_msg_sz + sizeof(hdr->msg_header)) {
|
|
dev_err(dev, "Buffer too small: hdr->length:%u, out_msg_sz:%zu\n",
|
|
ioread32(&hdr->length), msg->out_msg_sz);
|
|
return -ETOOSMALL;
|
|
}
|
|
|
|
/* Get the data */
|
|
msg->out_msg_sz = ioread32(&hdr->length) - sizeof(hdr->msg_header);
|
|
memcpy_fromio(msg->out_msg, hdr->msg_payload, msg->out_msg_sz);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Clear SMT flags in shared buffer to allow further message exchange
|
|
*/
|
|
void scmi_clear_smt_channel(struct scmi_smt *smt)
|
|
{
|
|
struct scmi_smt_header *hdr = (void *)smt->buf;
|
|
|
|
iowrite32(ioread32(&hdr->channel_status) & ~SCMI_SHMEM_CHAN_STAT_CHANNEL_ERROR,
|
|
&hdr->channel_status);
|
|
}
|
|
|
|
/**
|
|
* Write SCMI message @msg into a SMT_MSG shared buffer @smt.
|
|
* Return 0 on success and with a negative errno in case of error.
|
|
*/
|
|
int scmi_msg_to_smt_msg(struct udevice *dev, struct scmi_smt *smt,
|
|
struct scmi_msg *msg, size_t *buf_size)
|
|
{
|
|
struct scmi_smt_msg_header *hdr = (void *)smt->buf;
|
|
|
|
if ((!msg->in_msg && msg->in_msg_sz) ||
|
|
(!msg->out_msg && msg->out_msg_sz))
|
|
return -EINVAL;
|
|
|
|
if (smt->size < (sizeof(*hdr) + msg->in_msg_sz) ||
|
|
smt->size < (sizeof(*hdr) + msg->out_msg_sz)) {
|
|
dev_err(dev, "Buffer too small: mst->size:%zu, in_msg_sz:%zu, out_msg_sz:%zu\n",
|
|
smt->size, msg->in_msg_sz, msg->out_msg_sz);
|
|
return -ETOOSMALL;
|
|
}
|
|
|
|
*buf_size = msg->in_msg_sz + sizeof(hdr->msg_header);
|
|
|
|
iowrite32(SMT_HEADER_TOKEN(0) |
|
|
SMT_HEADER_MESSAGE_TYPE(0) |
|
|
SMT_HEADER_PROTOCOL_ID(msg->protocol_id) |
|
|
SMT_HEADER_MESSAGE_ID(msg->message_id), &hdr->msg_header);
|
|
|
|
memcpy_fromio(hdr->msg_payload, msg->in_msg, msg->in_msg_sz);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Read SCMI message from a SMT shared buffer @smt and copy it into @msg.
|
|
* Return 0 on success and with a negative errno in case of error.
|
|
*/
|
|
int scmi_msg_from_smt_msg(struct udevice *dev, struct scmi_smt *smt,
|
|
struct scmi_msg *msg, size_t buf_size)
|
|
{
|
|
struct scmi_smt_msg_header *hdr = (void *)smt->buf;
|
|
|
|
if (buf_size > msg->out_msg_sz + sizeof(hdr->msg_header)) {
|
|
dev_err(dev, "Buffer too small: buf_size:%zu, out_msg_sz:%zu\n",
|
|
buf_size, msg->out_msg_sz);
|
|
return -ETOOSMALL;
|
|
}
|
|
|
|
msg->out_msg_sz = buf_size - sizeof(hdr->msg_header);
|
|
memcpy_toio(msg->out_msg, hdr->msg_payload, msg->out_msg_sz);
|
|
|
|
return 0;
|
|
}
|