-
Notifications
You must be signed in to change notification settings - Fork 5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
firmware: arm_scmi: Add smc/hvc transport
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
1 parent
b953dce
commit 1dc6558
Showing
4 changed files
with
161 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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, | ||
}; |