mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-05-24 10:39:52 +00:00
firmware: qcom_scm: Dynamically support SMCCC and legacy conventions
Dynamically support SMCCCC and legacy conventions by detecting which convention to use at runtime. qcom_scm_call_atomic and qcom_scm_call can then be moved in qcom_scm.c and use underlying convention backend as appropriate. Thus, rename qcom_scm-64,-32 to reflect that they are backends for -smc and -legacy, respectively. Also add support for making SCM calls earlier than when SCM driver probes to support use cases such as qcom_scm_set_cold_boot_addr. Support is added by lazily initializing the convention and guarding the query with a spin lock. The limitation of these early SCM calls is that they cannot use DMA, as in the case of >4 arguments for SMC convention and any non-atomic call for legacy convention. Tested-by: Brian Masney <masneyb@onstation.org> # arm32 Tested-by: Stephan Gerhold <stephan@gerhold.net> Signed-off-by: Elliot Berman <eberman@codeaurora.org> Link: https://lore.kernel.org/r/1578431066-19600-18-git-send-email-eberman@codeaurora.org Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
This commit is contained in:
parent
57d3b81671
commit
9a434cee77
6 changed files with 176 additions and 135 deletions
|
@ -239,14 +239,6 @@ config QCOM_SCM
|
||||||
depends on ARM || ARM64
|
depends on ARM || ARM64
|
||||||
select RESET_CONTROLLER
|
select RESET_CONTROLLER
|
||||||
|
|
||||||
config QCOM_SCM_32
|
|
||||||
def_bool y
|
|
||||||
depends on QCOM_SCM && ARM
|
|
||||||
|
|
||||||
config QCOM_SCM_64
|
|
||||||
def_bool y
|
|
||||||
depends on QCOM_SCM && ARM64
|
|
||||||
|
|
||||||
config QCOM_SCM_DOWNLOAD_MODE_DEFAULT
|
config QCOM_SCM_DOWNLOAD_MODE_DEFAULT
|
||||||
bool "Qualcomm download mode enabled by default"
|
bool "Qualcomm download mode enabled by default"
|
||||||
depends on QCOM_SCM
|
depends on QCOM_SCM
|
||||||
|
|
|
@ -17,9 +17,7 @@ obj-$(CONFIG_ISCSI_IBFT) += iscsi_ibft.o
|
||||||
obj-$(CONFIG_FIRMWARE_MEMMAP) += memmap.o
|
obj-$(CONFIG_FIRMWARE_MEMMAP) += memmap.o
|
||||||
obj-$(CONFIG_RASPBERRYPI_FIRMWARE) += raspberrypi.o
|
obj-$(CONFIG_RASPBERRYPI_FIRMWARE) += raspberrypi.o
|
||||||
obj-$(CONFIG_FW_CFG_SYSFS) += qemu_fw_cfg.o
|
obj-$(CONFIG_FW_CFG_SYSFS) += qemu_fw_cfg.o
|
||||||
obj-$(CONFIG_QCOM_SCM) += qcom_scm.o
|
obj-$(CONFIG_QCOM_SCM) += qcom_scm.o qcom_scm-smc.o qcom_scm-legacy.o
|
||||||
obj-$(CONFIG_QCOM_SCM_64) += qcom_scm-64.o
|
|
||||||
obj-$(CONFIG_QCOM_SCM_32) += qcom_scm-32.o
|
|
||||||
obj-$(CONFIG_TI_SCI_PROTOCOL) += ti_sci.o
|
obj-$(CONFIG_TI_SCI_PROTOCOL) += ti_sci.o
|
||||||
obj-$(CONFIG_TRUSTED_FOUNDATIONS) += trusted_foundations.o
|
obj-$(CONFIG_TRUSTED_FOUNDATIONS) += trusted_foundations.o
|
||||||
obj-$(CONFIG_TURRIS_MOX_RWTM) += turris-mox-rwtm.o
|
obj-$(CONFIG_TURRIS_MOX_RWTM) += turris-mox-rwtm.o
|
||||||
|
|
|
@ -26,7 +26,6 @@ struct arm_smccc_args {
|
||||||
unsigned long args[8];
|
unsigned long args[8];
|
||||||
};
|
};
|
||||||
|
|
||||||
#define SCM_LEGACY_FNID(s, c) (((s) << 10) | ((c) & 0x3ff))
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct scm_legacy_command - one SCM command buffer
|
* struct scm_legacy_command - one SCM command buffer
|
||||||
|
@ -129,7 +128,7 @@ static void __scm_legacy_do(const struct arm_smccc_args *smc,
|
||||||
* and response buffers is taken care of by qcom_scm_call; however, callers are
|
* and response buffers is taken care of by qcom_scm_call; however, callers are
|
||||||
* responsible for any other cached buffers passed over to the secure world.
|
* responsible for any other cached buffers passed over to the secure world.
|
||||||
*/
|
*/
|
||||||
int qcom_scm_call(struct device *dev, const struct qcom_scm_desc *desc,
|
int scm_legacy_call(struct device *dev, const struct qcom_scm_desc *desc,
|
||||||
struct qcom_scm_res *res)
|
struct qcom_scm_res *res)
|
||||||
{
|
{
|
||||||
u8 arglen = desc->arginfo & 0xf;
|
u8 arglen = desc->arginfo & 0xf;
|
||||||
|
@ -218,7 +217,7 @@ out:
|
||||||
* This shall only be used with commands that are guaranteed to be
|
* This shall only be used with commands that are guaranteed to be
|
||||||
* uninterruptable, atomic and SMP safe.
|
* uninterruptable, atomic and SMP safe.
|
||||||
*/
|
*/
|
||||||
int qcom_scm_call_atomic(struct device *unused,
|
int scm_legacy_call_atomic(struct device *unused,
|
||||||
const struct qcom_scm_desc *desc,
|
const struct qcom_scm_desc *desc,
|
||||||
struct qcom_scm_res *res)
|
struct qcom_scm_res *res)
|
||||||
{
|
{
|
||||||
|
@ -241,23 +240,3 @@ int qcom_scm_call_atomic(struct device *unused,
|
||||||
|
|
||||||
return smc_res.a0;
|
return smc_res.a0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int __qcom_scm_is_call_available(struct device *dev, u32 svc_id, u32 cmd_id)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
struct qcom_scm_desc desc = {
|
|
||||||
.svc = QCOM_SCM_SVC_INFO,
|
|
||||||
.cmd = QCOM_SCM_INFO_IS_CALL_AVAIL,
|
|
||||||
.args[0] = SCM_LEGACY_FNID(svc_id, cmd_id),
|
|
||||||
.arginfo = QCOM_SCM_ARGS(1),
|
|
||||||
};
|
|
||||||
struct qcom_scm_res res;
|
|
||||||
|
|
||||||
ret = qcom_scm_call(dev, &desc, &res);
|
|
||||||
|
|
||||||
return ret ? : res.result[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
void __qcom_scm_init(void)
|
|
||||||
{
|
|
||||||
}
|
|
|
@ -14,8 +14,6 @@
|
||||||
|
|
||||||
#include "qcom_scm.h"
|
#include "qcom_scm.h"
|
||||||
|
|
||||||
#define SCM_SMC_FNID(s, c) ((((s) & 0xFF) << 8) | ((c) & 0xFF))
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct arm_smccc_args
|
* struct arm_smccc_args
|
||||||
* @args: The array of values used in registers in smc instruction
|
* @args: The array of values used in registers in smc instruction
|
||||||
|
@ -24,7 +22,6 @@ struct arm_smccc_args {
|
||||||
unsigned long args[8];
|
unsigned long args[8];
|
||||||
};
|
};
|
||||||
|
|
||||||
static u64 qcom_smccc_convention = -1;
|
|
||||||
static DEFINE_MUTEX(qcom_scm_lock);
|
static DEFINE_MUTEX(qcom_scm_lock);
|
||||||
|
|
||||||
#define QCOM_SCM_EBUSY_WAIT_MS 30
|
#define QCOM_SCM_EBUSY_WAIT_MS 30
|
||||||
|
@ -80,7 +77,7 @@ static void __scm_smc_do(const struct arm_smccc_args *smc,
|
||||||
} while (res->a0 == QCOM_SCM_V2_EBUSY);
|
} while (res->a0 == QCOM_SCM_V2_EBUSY);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __scm_smc_call(struct device *dev, const struct qcom_scm_desc *desc,
|
int scm_smc_call(struct device *dev, const struct qcom_scm_desc *desc,
|
||||||
struct qcom_scm_res *res, bool atomic)
|
struct qcom_scm_res *res, bool atomic)
|
||||||
{
|
{
|
||||||
int arglen = desc->arginfo & 0xf;
|
int arglen = desc->arginfo & 0xf;
|
||||||
|
@ -90,6 +87,9 @@ static int __scm_smc_call(struct device *dev, const struct qcom_scm_desc *desc,
|
||||||
size_t alloc_len;
|
size_t alloc_len;
|
||||||
gfp_t flag = atomic ? GFP_ATOMIC : GFP_KERNEL;
|
gfp_t flag = atomic ? GFP_ATOMIC : GFP_KERNEL;
|
||||||
u32 smccc_call_type = atomic ? ARM_SMCCC_FAST_CALL : ARM_SMCCC_STD_CALL;
|
u32 smccc_call_type = atomic ? ARM_SMCCC_FAST_CALL : ARM_SMCCC_STD_CALL;
|
||||||
|
u32 qcom_smccc_convention =
|
||||||
|
(qcom_scm_convention == SMC_CONVENTION_ARM_32) ?
|
||||||
|
ARM_SMCCC_SMC_32 : ARM_SMCCC_SMC_64;
|
||||||
struct arm_smccc_res smc_res;
|
struct arm_smccc_res smc_res;
|
||||||
struct arm_smccc_args smc = {0};
|
struct arm_smccc_args smc = {0};
|
||||||
|
|
||||||
|
@ -149,88 +149,3 @@ static int __scm_smc_call(struct device *dev, const struct qcom_scm_desc *desc,
|
||||||
|
|
||||||
return (long)smc_res.a0 ? qcom_scm_remap_error(smc_res.a0) : 0;
|
return (long)smc_res.a0 ? qcom_scm_remap_error(smc_res.a0) : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* qcom_scm_call() - Invoke a syscall in the secure world
|
|
||||||
* @dev: device
|
|
||||||
* @svc_id: service identifier
|
|
||||||
* @cmd_id: command identifier
|
|
||||||
* @desc: Descriptor structure containing arguments and return values
|
|
||||||
*
|
|
||||||
* Sends a command to the SCM and waits for the command to finish processing.
|
|
||||||
* This should *only* be called in pre-emptible context.
|
|
||||||
*/
|
|
||||||
int qcom_scm_call(struct device *dev, const struct qcom_scm_desc *desc,
|
|
||||||
struct qcom_scm_res *res)
|
|
||||||
{
|
|
||||||
might_sleep();
|
|
||||||
return __scm_smc_call(dev, desc, res, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* qcom_scm_call_atomic() - atomic variation of qcom_scm_call()
|
|
||||||
* @dev: device
|
|
||||||
* @svc_id: service identifier
|
|
||||||
* @cmd_id: command identifier
|
|
||||||
* @desc: Descriptor structure containing arguments and return values
|
|
||||||
* @res: Structure containing results from SMC/HVC call
|
|
||||||
*
|
|
||||||
* Sends a command to the SCM and waits for the command to finish processing.
|
|
||||||
* This can be called in atomic context.
|
|
||||||
*/
|
|
||||||
int qcom_scm_call_atomic(struct device *dev, const struct qcom_scm_desc *desc,
|
|
||||||
struct qcom_scm_res *res)
|
|
||||||
{
|
|
||||||
return __scm_smc_call(dev, desc, res, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
int __qcom_scm_is_call_available(struct device *dev, u32 svc_id, u32 cmd_id)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
struct qcom_scm_desc desc = {
|
|
||||||
.svc = QCOM_SCM_SVC_INFO,
|
|
||||||
.cmd = QCOM_SCM_INFO_IS_CALL_AVAIL,
|
|
||||||
.owner = ARM_SMCCC_OWNER_SIP,
|
|
||||||
};
|
|
||||||
struct qcom_scm_res res;
|
|
||||||
|
|
||||||
desc.arginfo = QCOM_SCM_ARGS(1);
|
|
||||||
desc.args[0] = SCM_SMC_FNID(svc_id, cmd_id) |
|
|
||||||
(ARM_SMCCC_OWNER_SIP << ARM_SMCCC_OWNER_SHIFT);
|
|
||||||
|
|
||||||
ret = qcom_scm_call(dev, &desc, &res);
|
|
||||||
|
|
||||||
return ret ? : res.result[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
void __qcom_scm_init(void)
|
|
||||||
{
|
|
||||||
struct qcom_scm_desc desc = {
|
|
||||||
.svc = QCOM_SCM_SVC_INFO,
|
|
||||||
.cmd = QCOM_SCM_INFO_IS_CALL_AVAIL,
|
|
||||||
.args[0] = SCM_SMC_FNID(QCOM_SCM_SVC_INFO,
|
|
||||||
QCOM_SCM_INFO_IS_CALL_AVAIL) |
|
|
||||||
(ARM_SMCCC_OWNER_SIP << ARM_SMCCC_OWNER_SHIFT),
|
|
||||||
.arginfo = QCOM_SCM_ARGS(1),
|
|
||||||
.owner = ARM_SMCCC_OWNER_SIP,
|
|
||||||
};
|
|
||||||
struct qcom_scm_res res;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
qcom_smccc_convention = ARM_SMCCC_SMC_64;
|
|
||||||
// Device isn't required as there is only one argument - no device
|
|
||||||
// needed to dma_map_single to secure world
|
|
||||||
ret = qcom_scm_call_atomic(NULL, &desc, &res);
|
|
||||||
if (!ret && res.result[0] == 1)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
qcom_smccc_convention = ARM_SMCCC_SMC_32;
|
|
||||||
ret = qcom_scm_call_atomic(NULL, &desc, &res);
|
|
||||||
if (!ret && res.result[0] == 1)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
qcom_smccc_convention = -1;
|
|
||||||
BUG();
|
|
||||||
out:
|
|
||||||
pr_info("QCOM SCM SMC Convention: %lld\n", qcom_smccc_convention);
|
|
||||||
}
|
|
|
@ -72,6 +72,13 @@ static struct qcom_scm_wb_entry qcom_scm_wb[] = {
|
||||||
{ .flag = QCOM_SCM_FLAG_WARMBOOT_CPU3 },
|
{ .flag = QCOM_SCM_FLAG_WARMBOOT_CPU3 },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const char *qcom_scm_convention_names[] = {
|
||||||
|
[SMC_CONVENTION_UNKNOWN] = "unknown",
|
||||||
|
[SMC_CONVENTION_ARM_32] = "smc arm 32",
|
||||||
|
[SMC_CONVENTION_ARM_64] = "smc arm 64",
|
||||||
|
[SMC_CONVENTION_LEGACY] = "smc legacy",
|
||||||
|
};
|
||||||
|
|
||||||
static struct qcom_scm *__scm;
|
static struct qcom_scm *__scm;
|
||||||
|
|
||||||
static int qcom_scm_clk_enable(void)
|
static int qcom_scm_clk_enable(void)
|
||||||
|
@ -107,6 +114,143 @@ static void qcom_scm_clk_disable(void)
|
||||||
clk_disable_unprepare(__scm->bus_clk);
|
clk_disable_unprepare(__scm->bus_clk);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int __qcom_scm_is_call_available(struct device *dev, u32 svc_id,
|
||||||
|
u32 cmd_id);
|
||||||
|
|
||||||
|
enum qcom_scm_convention qcom_scm_convention;
|
||||||
|
static bool has_queried __read_mostly;
|
||||||
|
static DEFINE_SPINLOCK(query_lock);
|
||||||
|
|
||||||
|
static void __query_convention(void)
|
||||||
|
{
|
||||||
|
unsigned long flags;
|
||||||
|
struct qcom_scm_desc desc = {
|
||||||
|
.svc = QCOM_SCM_SVC_INFO,
|
||||||
|
.cmd = QCOM_SCM_INFO_IS_CALL_AVAIL,
|
||||||
|
.args[0] = SCM_SMC_FNID(QCOM_SCM_SVC_INFO,
|
||||||
|
QCOM_SCM_INFO_IS_CALL_AVAIL) |
|
||||||
|
(ARM_SMCCC_OWNER_SIP << ARM_SMCCC_OWNER_SHIFT),
|
||||||
|
.arginfo = QCOM_SCM_ARGS(1),
|
||||||
|
.owner = ARM_SMCCC_OWNER_SIP,
|
||||||
|
};
|
||||||
|
struct qcom_scm_res res;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&query_lock, flags);
|
||||||
|
if (has_queried)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
qcom_scm_convention = SMC_CONVENTION_ARM_64;
|
||||||
|
// Device isn't required as there is only one argument - no device
|
||||||
|
// needed to dma_map_single to secure world
|
||||||
|
ret = scm_smc_call(NULL, &desc, &res, true);
|
||||||
|
if (!ret && res.result[0] == 1)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
qcom_scm_convention = SMC_CONVENTION_ARM_32;
|
||||||
|
ret = scm_smc_call(NULL, &desc, &res, true);
|
||||||
|
if (!ret && res.result[0] == 1)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
qcom_scm_convention = SMC_CONVENTION_LEGACY;
|
||||||
|
out:
|
||||||
|
has_queried = true;
|
||||||
|
spin_unlock_irqrestore(&query_lock, flags);
|
||||||
|
pr_info("qcom_scm: convention: %s\n",
|
||||||
|
qcom_scm_convention_names[qcom_scm_convention]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline enum qcom_scm_convention __get_convention(void)
|
||||||
|
{
|
||||||
|
if (unlikely(!has_queried))
|
||||||
|
__query_convention();
|
||||||
|
return qcom_scm_convention;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* qcom_scm_call() - Invoke a syscall in the secure world
|
||||||
|
* @dev: device
|
||||||
|
* @svc_id: service identifier
|
||||||
|
* @cmd_id: command identifier
|
||||||
|
* @desc: Descriptor structure containing arguments and return values
|
||||||
|
*
|
||||||
|
* Sends a command to the SCM and waits for the command to finish processing.
|
||||||
|
* This should *only* be called in pre-emptible context.
|
||||||
|
*/
|
||||||
|
static int qcom_scm_call(struct device *dev, const struct qcom_scm_desc *desc,
|
||||||
|
struct qcom_scm_res *res)
|
||||||
|
{
|
||||||
|
might_sleep();
|
||||||
|
switch (__get_convention()) {
|
||||||
|
case SMC_CONVENTION_ARM_32:
|
||||||
|
case SMC_CONVENTION_ARM_64:
|
||||||
|
return scm_smc_call(dev, desc, res, false);
|
||||||
|
case SMC_CONVENTION_LEGACY:
|
||||||
|
return scm_legacy_call(dev, desc, res);
|
||||||
|
default:
|
||||||
|
pr_err("Unknown current SCM calling convention.\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* qcom_scm_call_atomic() - atomic variation of qcom_scm_call()
|
||||||
|
* @dev: device
|
||||||
|
* @svc_id: service identifier
|
||||||
|
* @cmd_id: command identifier
|
||||||
|
* @desc: Descriptor structure containing arguments and return values
|
||||||
|
* @res: Structure containing results from SMC/HVC call
|
||||||
|
*
|
||||||
|
* Sends a command to the SCM and waits for the command to finish processing.
|
||||||
|
* This can be called in atomic context.
|
||||||
|
*/
|
||||||
|
static int qcom_scm_call_atomic(struct device *dev,
|
||||||
|
const struct qcom_scm_desc *desc,
|
||||||
|
struct qcom_scm_res *res)
|
||||||
|
{
|
||||||
|
switch (__get_convention()) {
|
||||||
|
case SMC_CONVENTION_ARM_32:
|
||||||
|
case SMC_CONVENTION_ARM_64:
|
||||||
|
return scm_smc_call(dev, desc, res, true);
|
||||||
|
case SMC_CONVENTION_LEGACY:
|
||||||
|
return scm_legacy_call_atomic(dev, desc, res);
|
||||||
|
default:
|
||||||
|
pr_err("Unknown current SCM calling convention.\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __qcom_scm_is_call_available(struct device *dev, u32 svc_id,
|
||||||
|
u32 cmd_id)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
struct qcom_scm_desc desc = {
|
||||||
|
.svc = QCOM_SCM_SVC_INFO,
|
||||||
|
.cmd = QCOM_SCM_INFO_IS_CALL_AVAIL,
|
||||||
|
.owner = ARM_SMCCC_OWNER_SIP,
|
||||||
|
};
|
||||||
|
struct qcom_scm_res res;
|
||||||
|
|
||||||
|
desc.arginfo = QCOM_SCM_ARGS(1);
|
||||||
|
switch (__get_convention()) {
|
||||||
|
case SMC_CONVENTION_ARM_32:
|
||||||
|
case SMC_CONVENTION_ARM_64:
|
||||||
|
desc.args[0] = SCM_SMC_FNID(svc_id, cmd_id) |
|
||||||
|
(ARM_SMCCC_OWNER_SIP << ARM_SMCCC_OWNER_SHIFT);
|
||||||
|
break;
|
||||||
|
case SMC_CONVENTION_LEGACY:
|
||||||
|
desc.args[0] = SCM_LEGACY_FNID(svc_id, cmd_id);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
pr_err("Unknown SMC convention being used\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = qcom_scm_call(dev, &desc, &res);
|
||||||
|
|
||||||
|
return ret ? : res.result[0];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* qcom_scm_set_warm_boot_addr() - Set the warm boot address for cpus
|
* qcom_scm_set_warm_boot_addr() - Set the warm boot address for cpus
|
||||||
* @entry: Entry point function for the cpus
|
* @entry: Entry point function for the cpus
|
||||||
|
@ -971,7 +1115,7 @@ static int qcom_scm_probe(struct platform_device *pdev)
|
||||||
__scm = scm;
|
__scm = scm;
|
||||||
__scm->dev = &pdev->dev;
|
__scm->dev = &pdev->dev;
|
||||||
|
|
||||||
__qcom_scm_init();
|
__query_convention();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If requested enable "download mode", from this point on warmboot
|
* If requested enable "download mode", from this point on warmboot
|
||||||
|
|
|
@ -3,6 +3,16 @@
|
||||||
*/
|
*/
|
||||||
#ifndef __QCOM_SCM_INT_H
|
#ifndef __QCOM_SCM_INT_H
|
||||||
#define __QCOM_SCM_INT_H
|
#define __QCOM_SCM_INT_H
|
||||||
|
|
||||||
|
enum qcom_scm_convention {
|
||||||
|
SMC_CONVENTION_UNKNOWN,
|
||||||
|
SMC_CONVENTION_LEGACY,
|
||||||
|
SMC_CONVENTION_ARM_32,
|
||||||
|
SMC_CONVENTION_ARM_64,
|
||||||
|
};
|
||||||
|
|
||||||
|
extern enum qcom_scm_convention qcom_scm_convention;
|
||||||
|
|
||||||
#define MAX_QCOM_SCM_ARGS 10
|
#define MAX_QCOM_SCM_ARGS 10
|
||||||
#define MAX_QCOM_SCM_RETS 3
|
#define MAX_QCOM_SCM_RETS 3
|
||||||
|
|
||||||
|
@ -50,11 +60,16 @@ struct qcom_scm_res {
|
||||||
u64 result[MAX_QCOM_SCM_RETS];
|
u64 result[MAX_QCOM_SCM_RETS];
|
||||||
};
|
};
|
||||||
|
|
||||||
extern int qcom_scm_call(struct device *dev, const struct qcom_scm_desc *desc,
|
#define SCM_SMC_FNID(s, c) ((((s) & 0xFF) << 8) | ((c) & 0xFF))
|
||||||
struct qcom_scm_res *res);
|
extern int scm_smc_call(struct device *dev, const struct qcom_scm_desc *desc,
|
||||||
extern int qcom_scm_call_atomic(struct device *dev,
|
struct qcom_scm_res *res, bool atomic);
|
||||||
|
|
||||||
|
#define SCM_LEGACY_FNID(s, c) (((s) << 10) | ((c) & 0x3ff))
|
||||||
|
extern int scm_legacy_call_atomic(struct device *dev,
|
||||||
const struct qcom_scm_desc *desc,
|
const struct qcom_scm_desc *desc,
|
||||||
struct qcom_scm_res *res);
|
struct qcom_scm_res *res);
|
||||||
|
extern int scm_legacy_call(struct device *dev, const struct qcom_scm_desc *desc,
|
||||||
|
struct qcom_scm_res *res);
|
||||||
|
|
||||||
#define QCOM_SCM_SVC_BOOT 0x01
|
#define QCOM_SCM_SVC_BOOT 0x01
|
||||||
#define QCOM_SCM_BOOT_SET_ADDR 0x01
|
#define QCOM_SCM_BOOT_SET_ADDR 0x01
|
||||||
|
@ -77,8 +92,6 @@ extern int qcom_scm_call_atomic(struct device *dev,
|
||||||
|
|
||||||
#define QCOM_SCM_SVC_INFO 0x06
|
#define QCOM_SCM_SVC_INFO 0x06
|
||||||
#define QCOM_SCM_INFO_IS_CALL_AVAIL 0x01
|
#define QCOM_SCM_INFO_IS_CALL_AVAIL 0x01
|
||||||
extern int __qcom_scm_is_call_available(struct device *dev, u32 svc_id,
|
|
||||||
u32 cmd_id);
|
|
||||||
|
|
||||||
#define QCOM_SCM_SVC_MP 0x0c
|
#define QCOM_SCM_SVC_MP 0x0c
|
||||||
#define QCOM_SCM_MP_RESTORE_SEC_CFG 0x02
|
#define QCOM_SCM_MP_RESTORE_SEC_CFG 0x02
|
||||||
|
|
Loading…
Add table
Reference in a new issue