Skip to content

Commit

Permalink
firmware: arm_scmi: Add smc/hvc transport
Browse files Browse the repository at this point in the history
Use the value of "arm,smc-id" property from the device tree as the first
argument for SMCCC call leaving all the other arguments as zero for now.

There is no Rx, only Tx because of smc/hvc not support Rx.

Link: https://lore.kernel.org/r/1583673879-20714-3-git-send-email-peng.fan@nxp.com
Signed-off-by: Peng Fan <peng.fan@nxp.com>
[sudeep.holla: reworded commit log/subject and fixed !HAVE_ARM_SMCCC build]
Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>
  • Loading branch information
MrVan authored and sudeep-holla committed Apr 14, 2020
1 parent b953dce commit 1dc6558
Show file tree
Hide file tree
Showing 4 changed files with 161 additions and 1 deletion.
4 changes: 3 additions & 1 deletion drivers/firmware/arm_scmi/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
obj-y = scmi-bus.o scmi-driver.o scmi-protocols.o scmi-transport.o
scmi-bus-y = bus.o
scmi-driver-y = driver.o
scmi-transport-y = mailbox.o shmem.o
scmi-transport-y = shmem.o
scmi-transport-$(CONFIG_MAILBOX) += mailbox.o
scmi-transport-$(CONFIG_HAVE_ARM_SMCCC) += smc.o
scmi-protocols-y = base.o clock.o perf.o power.o reset.o sensors.o
obj-$(CONFIG_ARM_SCMI_POWER_DOMAIN) += scmi_pm_domain.o
3 changes: 3 additions & 0 deletions drivers/firmware/arm_scmi/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,9 @@ struct scmi_desc {
};

extern const struct scmi_desc scmi_mailbox_desc;
#ifdef CONFIG_HAVE_ARM_SMCCC
extern const struct scmi_desc scmi_smc_desc;
#endif

void scmi_rx_callback(struct scmi_chan_info *cinfo, u32 msg_hdr);
void scmi_free_channel(struct scmi_chan_info *cinfo, struct idr *idr, int id);
Expand Down
3 changes: 3 additions & 0 deletions drivers/firmware/arm_scmi/driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -827,6 +827,9 @@ ATTRIBUTE_GROUPS(versions);
/* Each compatible listed below must have descriptor associated with it */
static const struct of_device_id scmi_of_match[] = {
{ .compatible = "arm,scmi", .data = &scmi_mailbox_desc },
#ifdef CONFIG_HAVE_ARM_SMCCC
{ .compatible = "arm,scmi-smc", .data = &scmi_smc_desc},
#endif
{ /* Sentinel */ },
};

Expand Down
152 changes: 152 additions & 0 deletions drivers/firmware/arm_scmi/smc.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
// SPDX-License-Identifier: GPL-2.0
/*
* System Control and Management Interface (SCMI) Message SMC/HVC
* Transport driver
*
* Copyright 2020 NXP
*/

#include <linux/arm-smccc.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/slab.h>

#include "common.h"

/**
* struct scmi_smc - Structure representing a SCMI smc transport
*
* @cinfo: SCMI channel info
* @shmem: Transmit/Receive shared memory area
* @func_id: smc/hvc call function id
*/

struct scmi_smc {
struct scmi_chan_info *cinfo;
struct scmi_shared_mem __iomem *shmem;
u32 func_id;
};

static DEFINE_MUTEX(smc_mutex);

static bool smc_chan_available(struct device *dev, int idx)
{
return true;
}

static int smc_chan_setup(struct scmi_chan_info *cinfo, struct device *dev,
bool tx)
{
struct device *cdev = cinfo->dev;
struct scmi_smc *scmi_info;
resource_size_t size;
struct resource res;
struct device_node *np;
u32 func_id;
int ret;

if (!tx)
return -ENODEV;

scmi_info = devm_kzalloc(dev, sizeof(*scmi_info), GFP_KERNEL);
if (!scmi_info)
return -ENOMEM;

np = of_parse_phandle(cdev->of_node, "shmem", 0);
if (!np)
np = of_parse_phandle(dev->of_node, "shmem", 0);
ret = of_address_to_resource(np, 0, &res);
of_node_put(np);
if (ret) {
dev_err(cdev, "failed to get SCMI Tx shared memory\n");
return ret;
}

size = resource_size(&res);
scmi_info->shmem = devm_ioremap(dev, res.start, size);
if (!scmi_info->shmem) {
dev_err(dev, "failed to ioremap SCMI Tx shared memory\n");
return -EADDRNOTAVAIL;
}

ret = of_property_read_u32(dev->of_node, "arm,smc-id", &func_id);
if (ret < 0)
return ret;

scmi_info->func_id = func_id;
scmi_info->cinfo = cinfo;
cinfo->transport_info = scmi_info;

return 0;
}

static int smc_chan_free(int id, void *p, void *data)
{
struct scmi_chan_info *cinfo = p;
struct scmi_smc *scmi_info = cinfo->transport_info;

cinfo->transport_info = NULL;
scmi_info->cinfo = NULL;

scmi_free_channel(cinfo, data, id);

return 0;
}

static int smc_send_message(struct scmi_chan_info *cinfo,
struct scmi_xfer *xfer)
{
struct scmi_smc *scmi_info = cinfo->transport_info;
struct arm_smccc_res res;

mutex_lock(&smc_mutex);

shmem_tx_prepare(scmi_info->shmem, xfer);

arm_smccc_1_1_invoke(scmi_info->func_id, 0, 0, 0, 0, 0, 0, 0, &res);
scmi_rx_callback(scmi_info->cinfo, shmem_read_header(scmi_info->shmem));

mutex_unlock(&smc_mutex);

return res.a0;
}

static void smc_mark_txdone(struct scmi_chan_info *cinfo, int ret)
{
}

static void smc_fetch_response(struct scmi_chan_info *cinfo,
struct scmi_xfer *xfer)
{
struct scmi_smc *scmi_info = cinfo->transport_info;

shmem_fetch_response(scmi_info->shmem, xfer);
}

static bool
smc_poll_done(struct scmi_chan_info *cinfo, struct scmi_xfer *xfer)
{
struct scmi_smc *scmi_info = cinfo->transport_info;

return shmem_poll_done(scmi_info->shmem, xfer);
}

static struct scmi_transport_ops scmi_smc_ops = {
.chan_available = smc_chan_available,
.chan_setup = smc_chan_setup,
.chan_free = smc_chan_free,
.send_message = smc_send_message,
.mark_txdone = smc_mark_txdone,
.fetch_response = smc_fetch_response,
.poll_done = smc_poll_done,
};

const struct scmi_desc scmi_smc_desc = {
.ops = &scmi_smc_ops,
.max_rx_timeout_ms = 30,
.max_msg = 1,
.max_msg_size = 128,
};

0 comments on commit 1dc6558

Please sign in to comment.