Merge patch series "firmware: scmi: various update"
Peng Fan (OSS) <peng.fan@oss.nxp.com> says: Misc update on firmware scmi: - Typo fix - Use io helpers - Use PAGE_SIZE for arm64 - Add IN_USE error code - Add more error info - Support scmi max rx timeout in mailbox - Add myself as scmi maintainer, AKASHI contributed most code, but seems he is not invovled in the developement anymore, I volunteer to help here. Some items on list that I am thinking to add: - align with linux kernel to use cpu_to_le32 and le32_to_cpu, but have not find a good way to use the helpers. - Add SCMI version negotiation as Linux Kernel Link: https://lore.kernel.org/r/20250927-scmi-v1-0-5e9354fb3bff@nxp.com
This commit is contained in:
@@ -1626,6 +1626,13 @@ F: drivers/*/*sandbox*.c
|
||||
F: include/dt-bindings/*/sandbox*.h
|
||||
F: include/os.h
|
||||
|
||||
SCMI
|
||||
M: Peng Fan <peng.fan@nxp.com>
|
||||
S: Maintained
|
||||
F: drivers/firmware/scmi/
|
||||
F: include/scmi*
|
||||
N: scmi
|
||||
|
||||
SEAMA
|
||||
M: Linus Walleij <linus.walleij@linaro.org>
|
||||
S: Maintained
|
||||
|
||||
@@ -29,6 +29,7 @@ struct {
|
||||
{SCMI_PROTOCOL_ID_SENSOR, "Sensor management"},
|
||||
{SCMI_PROTOCOL_ID_RESET_DOMAIN, "Reset domain management"},
|
||||
{SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN, "Voltage domain management"},
|
||||
{SCMI_PROTOCOL_ID_PINCTRL, "Pin control management"},
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
#include <clk-uclass.h>
|
||||
#include <dm.h>
|
||||
#include <dm/device_compat.h>
|
||||
#include <scmi_agent.h>
|
||||
#include <scmi_agent-uclass.h>
|
||||
#include <scmi_protocols.h>
|
||||
@@ -41,19 +42,21 @@ static int scmi_clk_get_permissions(struct udevice *dev, int clkid, u32 *perm)
|
||||
};
|
||||
|
||||
if (priv->version < CLOCK_PROTOCOL_VERSION_3_0) {
|
||||
log_debug("%s: SCMI clock management protocol version is less than 3.0.\n", __func__);
|
||||
dev_dbg(dev,
|
||||
"%s: SCMI clock management protocol version is less than 3.0.\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = devm_scmi_process_msg(dev, &msg);
|
||||
if (ret) {
|
||||
log_debug("%s: get SCMI clock management protocol permissions failed\n", __func__);
|
||||
dev_dbg(dev,
|
||||
"%s: get SCMI clock management protocol permissions failed\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = scmi_to_linux_errno(out.status);
|
||||
if (ret < 0) {
|
||||
log_debug("%s: the status code of getting permissions: %d\n", __func__, ret);
|
||||
dev_dbg(dev, "%s: the status code of getting permissions: %d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -167,7 +170,7 @@ static int scmi_clk_enable(struct clk *clk)
|
||||
return scmi_clk_gate(clk, 1);
|
||||
|
||||
/* Following Linux drivers/clk/clk-scmi.c, directly return 0 if agent has no permission. */
|
||||
log_debug("%s: SCMI CLOCK: the clock cannot be enabled by the agent.\n", __func__);
|
||||
dev_dbg(clk->dev, "%s: SCMI CLOCK: the clock cannot be enabled by the agent.\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -190,7 +193,8 @@ static int scmi_clk_disable(struct clk *clk)
|
||||
return scmi_clk_gate(clk, 0);
|
||||
|
||||
/* Following Linux drivers/clk/clk-scmi.c, directly return 0 if agent has no permission. */
|
||||
log_debug("%s: SCMI CLOCK: the clock cannot be disabled by the agent.\n", __func__);
|
||||
dev_dbg(clk->dev,
|
||||
"%s: SCMI CLOCK: the clock cannot be disabled by the agent.\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -260,7 +264,8 @@ static ulong scmi_clk_set_rate(struct clk *clk, ulong rate)
|
||||
return __scmi_clk_set_rate(clk, rate);
|
||||
|
||||
/* Following Linux drivers/clk/clk-scmi.c, directly return 0 if agent has no permission. */
|
||||
log_debug("%s: SCMI CLOCK: the clock rate cannot be changed by the agent.\n", __func__);
|
||||
dev_dbg(clk->dev,
|
||||
"%s: SCMI CLOCK: the clock rate cannot be changed by the agent.\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -291,7 +296,7 @@ static int scmi_clk_probe(struct udevice *dev)
|
||||
|
||||
ret = scmi_generic_protocol_version(dev, SCMI_PROTOCOL_ID_CLOCK, &priv->version);
|
||||
if (ret) {
|
||||
log_debug("%s: get SCMI clock management protocol version failed\n", __func__);
|
||||
dev_dbg(dev, "%s: get SCMI clock management protocol version failed\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -371,7 +376,8 @@ static int scmi_clk_set_parent(struct clk *clk, struct clk *parent)
|
||||
return __scmi_clk_set_parent(clk, parent);
|
||||
|
||||
/* Following Linux drivers/clk/clk-scmi.c, directly return 0 if agent has no permission. */
|
||||
log_debug("%s: SCMI CLOCK: the clock's parent cannot be changed by the agent.\n", __func__);
|
||||
dev_dbg(clk->dev,
|
||||
"%s: SCMI CLOCK: the clock's parent cannot be changed by the agent.\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
#include "smt.h"
|
||||
|
||||
#define TIMEOUT_US_10MS 10000
|
||||
#define TIMEOUT_30MS 30
|
||||
|
||||
/**
|
||||
* struct scmi_mbox_channel - Description of an SCMI mailbox transport
|
||||
@@ -73,6 +73,7 @@ out:
|
||||
|
||||
static int setup_channel(struct udevice *dev, struct scmi_mbox_channel *chan)
|
||||
{
|
||||
struct scmi_mbox_channel *base_chan = dev_get_plat(dev);
|
||||
int ret;
|
||||
|
||||
ret = mbox_get_by_index(dev, 0, &chan->mbox);
|
||||
@@ -87,7 +88,7 @@ static int setup_channel(struct udevice *dev, struct scmi_mbox_channel *chan)
|
||||
return ret;
|
||||
}
|
||||
|
||||
chan->timeout_us = TIMEOUT_US_10MS;
|
||||
chan->timeout_us = base_chan->timeout_us;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -127,6 +128,9 @@ int scmi_mbox_of_to_plat(struct udevice *dev)
|
||||
{
|
||||
struct scmi_mbox_channel *chan = dev_get_plat(dev);
|
||||
|
||||
chan->timeout_us = dev_read_u32_default(dev, "arm,max-rx-timeout-ms",
|
||||
TIMEOUT_30MS) * 1000;
|
||||
|
||||
return setup_channel(dev, chan);
|
||||
}
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@ static const struct error_code scmi_linux_errmap[] = {
|
||||
{ .scmi = SCMI_GENERIC_ERROR, .errno = -EIO, },
|
||||
{ .scmi = SCMI_HARDWARE_ERROR, .errno = -EREMOTEIO, },
|
||||
{ .scmi = SCMI_PROTOCOL_ERROR, .errno = -EPROTO, },
|
||||
{ .scmi = SCMI_IN_USE, .errno = -EADDRINUSE, },
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -25,9 +25,9 @@ static void scmi_smt_enable_intr(struct scmi_smt *smt, bool enable)
|
||||
struct scmi_smt_header *hdr = (void *)smt->buf;
|
||||
|
||||
if (enable)
|
||||
hdr->flags |= SCMI_SHMEM_FLAG_INTR_ENABLED;
|
||||
iowrite32(ioread32(&hdr->flags) | SCMI_SHMEM_FLAG_INTR_ENABLED, &hdr->flags);
|
||||
else
|
||||
hdr->flags &= ~SCMI_SHMEM_FLAG_INTR_ENABLED;
|
||||
iowrite32(ioread32(&hdr->flags) & ~SCMI_SHMEM_FLAG_INTR_ENABLED, &hdr->flags);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -62,11 +62,17 @@ int scmi_dt_get_smt_buffer(struct udevice *dev, struct scmi_smt *smt)
|
||||
scmi_smt_enable_intr(smt, true);
|
||||
|
||||
#ifdef CONFIG_ARM
|
||||
if (dcache_status())
|
||||
mmu_set_region_dcache_behaviour(ALIGN_DOWN((uintptr_t)smt->buf, MMU_SECTION_SIZE),
|
||||
ALIGN(smt->size, MMU_SECTION_SIZE),
|
||||
DCACHE_OFF);
|
||||
if (dcache_status()) {
|
||||
u32 align_size;
|
||||
|
||||
if (IS_ENABLED(CONFIG_ARM64))
|
||||
align_size = PAGE_SIZE;
|
||||
else
|
||||
align_size = MMU_SECTION_SIZE;
|
||||
|
||||
mmu_set_region_dcache_behaviour(ALIGN_DOWN((uintptr_t)smt->buf, align_size),
|
||||
ALIGN(smt->size, align_size), DCACHE_OFF);
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
@@ -85,24 +91,27 @@ int scmi_write_msg_to_smt(struct udevice *dev, struct scmi_smt *smt,
|
||||
(!msg->out_msg && msg->out_msg_sz))
|
||||
return -EINVAL;
|
||||
|
||||
if (!(hdr->channel_status & SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE)) {
|
||||
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_dbg(dev, "Buffer too small\n");
|
||||
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 */
|
||||
hdr->channel_status &= ~SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE;
|
||||
hdr->length = msg->in_msg_sz + sizeof(hdr->msg_header);
|
||||
hdr->msg_header = SMT_HEADER_TOKEN(0) |
|
||||
SMT_HEADER_MESSAGE_TYPE(0) |
|
||||
SMT_HEADER_PROTOCOL_ID(msg->protocol_id) |
|
||||
SMT_HEADER_MESSAGE_ID(msg->message_id);
|
||||
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);
|
||||
|
||||
@@ -118,23 +127,24 @@ int scmi_read_resp_from_smt(struct udevice *dev, struct scmi_smt *smt,
|
||||
{
|
||||
struct scmi_smt_header *hdr = (void *)smt->buf;
|
||||
|
||||
if (!(hdr->channel_status & SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE)) {
|
||||
if (!(ioread32(&hdr->channel_status) & SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE)) {
|
||||
dev_err(dev, "Channel unexpectedly busy\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
if (hdr->channel_status & SCMI_SHMEM_CHAN_STAT_CHANNEL_ERROR) {
|
||||
if (ioread32(&hdr->channel_status) & SCMI_SHMEM_CHAN_STAT_CHANNEL_ERROR) {
|
||||
dev_err(dev, "Channel error reported, reset channel\n");
|
||||
return -ECOMM;
|
||||
}
|
||||
|
||||
if (hdr->length > msg->out_msg_sz + sizeof(hdr->msg_header)) {
|
||||
dev_err(dev, "Buffer to small\n");
|
||||
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 = hdr->length - sizeof(hdr->msg_header);
|
||||
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;
|
||||
@@ -147,7 +157,8 @@ void scmi_clear_smt_channel(struct scmi_smt *smt)
|
||||
{
|
||||
struct scmi_smt_header *hdr = (void *)smt->buf;
|
||||
|
||||
hdr->channel_status &= ~SCMI_SHMEM_CHAN_STAT_CHANNEL_ERROR;
|
||||
iowrite32(ioread32(&hdr->channel_status) & ~SCMI_SHMEM_CHAN_STAT_CHANNEL_ERROR,
|
||||
&hdr->channel_status);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -165,18 +176,19 @@ int scmi_msg_to_smt_msg(struct udevice *dev, struct scmi_smt *smt,
|
||||
|
||||
if (smt->size < (sizeof(*hdr) + msg->in_msg_sz) ||
|
||||
smt->size < (sizeof(*hdr) + msg->out_msg_sz)) {
|
||||
dev_dbg(dev, "Buffer too small\n");
|
||||
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);
|
||||
|
||||
hdr->msg_header = SMT_HEADER_TOKEN(0) |
|
||||
SMT_HEADER_MESSAGE_TYPE(0) |
|
||||
SMT_HEADER_PROTOCOL_ID(msg->protocol_id) |
|
||||
SMT_HEADER_MESSAGE_ID(msg->message_id);
|
||||
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(hdr->msg_payload, msg->in_msg, msg->in_msg_sz);
|
||||
memcpy_fromio(hdr->msg_payload, msg->in_msg, msg->in_msg_sz);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -191,12 +203,13 @@ int scmi_msg_from_smt_msg(struct udevice *dev, struct scmi_smt *smt,
|
||||
struct scmi_smt_msg_header *hdr = (void *)smt->buf;
|
||||
|
||||
if (buf_size > msg->out_msg_sz + sizeof(hdr->msg_header)) {
|
||||
dev_err(dev, "Buffer to small\n");
|
||||
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(msg->out_msg, hdr->msg_payload, msg->out_msg_sz);
|
||||
memcpy_toio(msg->out_msg, hdr->msg_payload, msg->out_msg_sz);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -40,6 +40,7 @@ enum scmi_status_code {
|
||||
SCMI_GENERIC_ERROR = -8,
|
||||
SCMI_HARDWARE_ERROR = -9,
|
||||
SCMI_PROTOCOL_ERROR = -10,
|
||||
SCMI_IN_USE = -11,
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
Reference in New Issue
Block a user