2019-11-05 01:28:52

by Elliot Berman

[permalink] [raw]
Subject: [PATCH 00/17] Restructure, improve target support for qcom_scm driver

This series improves support for 32-bit Qualcomm targets on qcom_scm driver.

Currently, the qcom_scm driver supports only 64-bit Qualcomm targets and very
old 32-bit Qualcomm targets. Newer 32-bit targets use ARM's SMC Calling
Convention to communicate with secure world. Older 32-bit targets use a
"buffer-based" legacy approach for communicating with secure world (as
implemented in qcom_scm-32.c). All arm64 Qualcomm targets use ARM SMCCC.
Currently, SMCCC-based communication is enabled only on ARM64 config and
buffer-based communication only on ARM config. This patch-series combines SMCCC
and legacy conventions and selects the correct convention by querying the secure
world [1].

We decided to take the opportunity as well to clean up the driver rather than
try to patch together qcom_scm-32 and qcom_scm-64.

Patches 1-4 improve macro names, reorder macros/functions, and prune unused
macros/functions. No functional changes were introduced.
Patches 5-9 clears up the SCM abstraction in qcom_scm-64.
Patches 10-14 clears up the SCM abstraction in qcom_scm-32.
Patches 9 and 15-16 enable dynamically using the different calling conventions.

This series is based on https://lore.kernel.org/patchwork/cover/1129991/

[1]: https://source.codeaurora.org/quic/la/kernel/msm-4.9/tree/drivers/soc/qcom/scm.c?h=kernel.lnx.4.9.r28-rel#n555

Changes since RFC:
- Fixed missing return values in qcom_scm_call_smccc
- Fixed order of arguments in qcom_scm_set_warm_boot_addr
- Adjusted logic of SMC convention to properly support older QCOM secure worlds
- Boot tested on IFC6410 based on linaro kernel tag:
debian-qcom-dragonboard410c-18.01 (which does basic verification of legacy
SCM calls: at least warm_boot_addr, cold_boot_addr, and power_down)

Elliot Berman (17):
firmware: qcom_scm: Rename macros and structures
firmware: qcom_scm: Apply consistent naming scheme to command IDs
firmware: qcom_scm: Order functions, definitions by service/command
firmware: qcom_scm: Remove unused qcom_scm_get_version
firmware: qcom_scm-64: Move svc/cmd/owner into qcom_scm_desc
firmware: qcom_scm-64: Add SCM results to descriptor
firmware: qcom_scm-64: Remove qcom_scm_call_do_smccc
firmware: qcom_scm-64: Move SMC register filling to
qcom_scm_call_smccc
firmware: qcom_scm-64: Improve SMC convention detection
firmware: qcom_scm-32: Use SMC arch wrappers
firmware: qcom_scm-32: Use qcom_scm_desc in non-atomic calls
firmware: qcom_scm-32: Move SMCCC register filling to qcom_scm_call
firmware: qcom_scm-32: Create common legacy atomic call
firmware: qcom_scm-32: Add device argument to atomic calls
firmware: qcom_scm: Merge legacy and SMCCC conventions
firmware: qcom_scm: Enable legacy calling convention in qcom_scm-64.c
firmware: qcom_scm: Rename -64 -> -smc, remove -32

drivers/firmware/Kconfig | 18 +-
drivers/firmware/Makefile | 4 +-
drivers/firmware/qcom_scm-32.c | 621 --------------------------
drivers/firmware/qcom_scm-64.c | 567 ------------------------
drivers/firmware/qcom_scm-smc.c | 949 ++++++++++++++++++++++++++++++++++++++++
drivers/firmware/qcom_scm.c | 235 +++++-----
drivers/firmware/qcom_scm.h | 115 +++--
include/linux/qcom_scm.h | 72 +--
8 files changed, 1169 insertions(+), 1412 deletions(-)
delete mode 100644 drivers/firmware/qcom_scm-32.c
delete mode 100644 drivers/firmware/qcom_scm-64.c
create mode 100644 drivers/firmware/qcom_scm-smc.c

--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project


2019-11-05 01:29:06

by Elliot Berman

[permalink] [raw]
Subject: [PATCH 02/17] firmware: qcom_scm: Apply consistent naming scheme to command IDs

Create a consistent naming scheme for command IDs. The scheme is
QCOM_SCM_##svc_##cmd. Remove unused macros QCOM_SCM_FLAG_HLOS,
QCOM_SCM_FLAG_COLDBOOT_MC, QCOM_SCM_FLAG_WARMBOOT_MC,
QCOM_SCM_CMD_CORE_HOTPLUGGED, and QCOM_SCM_BOOT_ADDR_MC.

Signed-off-by: Elliot Berman <[email protected]>
---
drivers/firmware/qcom_scm-32.c | 28 ++++++++++++++--------------
drivers/firmware/qcom_scm-64.c | 38 +++++++++++++++++++-------------------
drivers/firmware/qcom_scm.c | 8 ++++----
drivers/firmware/qcom_scm.h | 41 ++++++++++++++++++-----------------------
4 files changed, 55 insertions(+), 60 deletions(-)

diff --git a/drivers/firmware/qcom_scm-32.c b/drivers/firmware/qcom_scm-32.c
index d416efc..87b520f 100644
--- a/drivers/firmware/qcom_scm-32.c
+++ b/drivers/firmware/qcom_scm-32.c
@@ -356,7 +356,7 @@ int __qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus)
set_cpu_present(cpu, false);
}

- return qcom_scm_call_atomic2(QCOM_SCM_SVC_BOOT, QCOM_SCM_BOOT_ADDR,
+ return qcom_scm_call_atomic2(QCOM_SCM_SVC_BOOT, QCOM_SCM_BOOT_SET_ADDR,
flags, virt_to_phys(entry));
}

@@ -395,7 +395,7 @@ int __qcom_scm_set_warm_boot_addr(struct device *dev, void *entry,

cmd.addr = cpu_to_le32(virt_to_phys(entry));
cmd.flags = cpu_to_le32(flags);
- ret = qcom_scm_call(dev, QCOM_SCM_SVC_BOOT, QCOM_SCM_BOOT_ADDR,
+ ret = qcom_scm_call(dev, QCOM_SCM_SVC_BOOT, QCOM_SCM_BOOT_SET_ADDR,
&cmd, sizeof(cmd), NULL, 0);
if (!ret) {
for_each_cpu(cpu, cpus)
@@ -415,7 +415,7 @@ int __qcom_scm_set_warm_boot_addr(struct device *dev, void *entry,
*/
void __qcom_scm_cpu_power_down(u32 flags)
{
- qcom_scm_call_atomic1(QCOM_SCM_SVC_BOOT, QCOM_SCM_CMD_TERMINATE_PC,
+ qcom_scm_call_atomic1(QCOM_SCM_SVC_BOOT, QCOM_SCM_BOOT_TERMINATE_PC,
flags & QCOM_SCM_FLUSH_FLAG_MASK);
}

@@ -425,7 +425,7 @@ int __qcom_scm_is_call_available(struct device *dev, u32 svc_id, u32 cmd_id)
__le32 svc_cmd = cpu_to_le32((svc_id << 10) | cmd_id);
__le32 ret_val = 0;

- ret = qcom_scm_call(dev, QCOM_SCM_SVC_INFO, QCOM_IS_CALL_AVAIL_CMD,
+ ret = qcom_scm_call(dev, QCOM_SCM_SVC_INFO, QCOM_SCM_INFO_IS_CALL_AVAIL,
&svc_cmd, sizeof(svc_cmd), &ret_val,
sizeof(ret_val));
if (ret)
@@ -440,7 +440,7 @@ int __qcom_scm_hdcp_req(struct device *dev, struct qcom_scm_hdcp_req *req,
if (req_cnt > QCOM_SCM_HDCP_MAX_REQ_CNT)
return -ERANGE;

- return qcom_scm_call(dev, QCOM_SCM_SVC_HDCP, QCOM_SCM_CMD_HDCP,
+ return qcom_scm_call(dev, QCOM_SCM_SVC_HDCP, QCOM_SCM_HDCP_INVOKE,
req, req_cnt * sizeof(*req), resp, sizeof(*resp));
}

@@ -456,7 +456,7 @@ bool __qcom_scm_pas_supported(struct device *dev, u32 peripheral)

in = cpu_to_le32(peripheral);
ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL,
- QCOM_SCM_PAS_IS_SUPPORTED_CMD,
+ QCOM_SCM_PIL_PAS_IS_SUPPORTED,
&in, sizeof(in),
&out, sizeof(out));

@@ -477,7 +477,7 @@ int __qcom_scm_pas_init_image(struct device *dev, u32 peripheral,
request.image_addr = cpu_to_le32(metadata_phys);

ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL,
- QCOM_SCM_PAS_INIT_IMAGE_CMD,
+ QCOM_SCM_PIL_PAS_INIT_IMAGE,
&request, sizeof(request),
&scm_ret, sizeof(scm_ret));

@@ -500,7 +500,7 @@ int __qcom_scm_pas_mem_setup(struct device *dev, u32 peripheral,
request.len = cpu_to_le32(size);

ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL,
- QCOM_SCM_PAS_MEM_SETUP_CMD,
+ QCOM_SCM_PIL_PAS_MEM_SETUP,
&request, sizeof(request),
&scm_ret, sizeof(scm_ret));

@@ -515,7 +515,7 @@ int __qcom_scm_pas_auth_and_reset(struct device *dev, u32 peripheral)

in = cpu_to_le32(peripheral);
ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL,
- QCOM_SCM_PAS_AUTH_AND_RESET_CMD,
+ QCOM_SCM_PIL_PAS_AUTH_AND_RESET,
&in, sizeof(in),
&out, sizeof(out));

@@ -530,7 +530,7 @@ int __qcom_scm_pas_shutdown(struct device *dev, u32 peripheral)

in = cpu_to_le32(peripheral);
ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL,
- QCOM_SCM_PAS_SHUTDOWN_CMD,
+ QCOM_SCM_PIL_PAS_SHUTDOWN,
&in, sizeof(in),
&out, sizeof(out));

@@ -543,7 +543,7 @@ int __qcom_scm_pas_mss_reset(struct device *dev, bool reset)
__le32 in = cpu_to_le32(reset);
int ret;

- ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL, QCOM_SCM_PAS_MSS_RESET,
+ ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL, QCOM_SCM_PIL_PAS_MSS_RESET,
&in, sizeof(in),
&out, sizeof(out));

@@ -552,8 +552,8 @@ int __qcom_scm_pas_mss_reset(struct device *dev, bool reset)

int __qcom_scm_set_dload_mode(struct device *dev, bool enable)
{
- return qcom_scm_call_atomic2(QCOM_SCM_SVC_BOOT, QCOM_SCM_SET_DLOAD_MODE,
- enable ? QCOM_SCM_SET_DLOAD_MODE : 0, 0);
+ return qcom_scm_call_atomic2(QCOM_SCM_SVC_BOOT, QCOM_SCM_BOOT_SET_DLOAD_MODE,
+ enable ? QCOM_SCM_BOOT_SET_DLOAD_MODE : 0, 0);
}

int __qcom_scm_set_remote_state(struct device *dev, u32 state, u32 id)
@@ -568,7 +568,7 @@ int __qcom_scm_set_remote_state(struct device *dev, u32 state, u32 id)
req.state = cpu_to_le32(state);
req.id = cpu_to_le32(id);

- ret = qcom_scm_call(dev, QCOM_SCM_SVC_BOOT, QCOM_SCM_SET_REMOTE_STATE,
+ ret = qcom_scm_call(dev, QCOM_SCM_SVC_BOOT, QCOM_SCM_BOOT_SET_REMOTE_STATE,
&req, sizeof(req), &scm_ret, sizeof(scm_ret));

return ret ? : le32_to_cpu(scm_ret);
diff --git a/drivers/firmware/qcom_scm-64.c b/drivers/firmware/qcom_scm-64.c
index e6721b5..f0b4853 100644
--- a/drivers/firmware/qcom_scm-64.c
+++ b/drivers/firmware/qcom_scm-64.c
@@ -256,7 +256,7 @@ int __qcom_scm_is_call_available(struct device *dev, u32 svc_id, u32 cmd_id)
desc.args[0] = SMCCC_FUNCNUM(svc_id, cmd_id) |
(ARM_SMCCC_OWNER_SIP << ARM_SMCCC_OWNER_SHIFT);

- ret = qcom_scm_call(dev, QCOM_SCM_SVC_INFO, QCOM_IS_CALL_AVAIL_CMD,
+ ret = qcom_scm_call(dev, QCOM_SCM_SVC_INFO, QCOM_SCM_INFO_IS_CALL_AVAIL,
&desc, &res);

return ret ? : res.a1;
@@ -284,7 +284,7 @@ int __qcom_scm_hdcp_req(struct device *dev, struct qcom_scm_hdcp_req *req,
desc.args[9] = req[4].val;
desc.arginfo = QCOM_SCM_ARGS(10);

- ret = qcom_scm_call(dev, QCOM_SCM_SVC_HDCP, QCOM_SCM_CMD_HDCP, &desc,
+ ret = qcom_scm_call(dev, QCOM_SCM_SVC_HDCP, QCOM_SCM_HDCP_INVOKE, &desc,
&res);
*resp = res.a1;

@@ -295,7 +295,7 @@ void __qcom_scm_init(void)
{
u64 cmd;
struct arm_smccc_res res;
- u32 function = SMCCC_FUNCNUM(QCOM_SCM_SVC_INFO, QCOM_IS_CALL_AVAIL_CMD);
+ u32 function = SMCCC_FUNCNUM(QCOM_SCM_SVC_INFO, QCOM_SCM_INFO_IS_CALL_AVAIL);

/* First try a SMC64 call */
cmd = ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, ARM_SMCCC_SMC_64,
@@ -320,7 +320,7 @@ bool __qcom_scm_pas_supported(struct device *dev, u32 peripheral)
desc.arginfo = QCOM_SCM_ARGS(1);

ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL,
- QCOM_SCM_PAS_IS_SUPPORTED_CMD,
+ QCOM_SCM_PIL_PAS_IS_SUPPORTED,
&desc, &res);

return ret ? false : !!res.a1;
@@ -337,7 +337,7 @@ int __qcom_scm_pas_init_image(struct device *dev, u32 peripheral,
desc.args[1] = metadata_phys;
desc.arginfo = QCOM_SCM_ARGS(2, QCOM_SCM_VAL, QCOM_SCM_RW);

- ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL, QCOM_SCM_PAS_INIT_IMAGE_CMD,
+ ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL, QCOM_SCM_PIL_PAS_INIT_IMAGE,
&desc, &res);

return ret ? : res.a1;
@@ -355,7 +355,7 @@ int __qcom_scm_pas_mem_setup(struct device *dev, u32 peripheral,
desc.args[2] = size;
desc.arginfo = QCOM_SCM_ARGS(3);

- ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL, QCOM_SCM_PAS_MEM_SETUP_CMD,
+ ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL, QCOM_SCM_PIL_PAS_MEM_SETUP,
&desc, &res);

return ret ? : res.a1;
@@ -371,7 +371,7 @@ int __qcom_scm_pas_auth_and_reset(struct device *dev, u32 peripheral)
desc.arginfo = QCOM_SCM_ARGS(1);

ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL,
- QCOM_SCM_PAS_AUTH_AND_RESET_CMD,
+ QCOM_SCM_PIL_PAS_AUTH_AND_RESET,
&desc, &res);

return ret ? : res.a1;
@@ -386,7 +386,7 @@ int __qcom_scm_pas_shutdown(struct device *dev, u32 peripheral)
desc.args[0] = peripheral;
desc.arginfo = QCOM_SCM_ARGS(1);

- ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL, QCOM_SCM_PAS_SHUTDOWN_CMD,
+ ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL, QCOM_SCM_PIL_PAS_SHUTDOWN,
&desc, &res);

return ret ? : res.a1;
@@ -402,7 +402,7 @@ int __qcom_scm_pas_mss_reset(struct device *dev, bool reset)
desc.args[1] = 0;
desc.arginfo = QCOM_SCM_ARGS(2);

- ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL, QCOM_SCM_PAS_MSS_RESET, &desc,
+ ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL, QCOM_SCM_PIL_PAS_MSS_RESET, &desc,
&res);

return ret ? : res.a1;
@@ -418,7 +418,7 @@ int __qcom_scm_set_remote_state(struct device *dev, u32 state, u32 id)
desc.args[1] = id;
desc.arginfo = QCOM_SCM_ARGS(2);

- ret = qcom_scm_call(dev, QCOM_SCM_SVC_BOOT, QCOM_SCM_SET_REMOTE_STATE,
+ ret = qcom_scm_call(dev, QCOM_SCM_SVC_BOOT, QCOM_SCM_BOOT_SET_REMOTE_STATE,
&desc, &res);

return ret ? : res.a1;
@@ -445,7 +445,7 @@ int __qcom_scm_assign_mem(struct device *dev, phys_addr_t mem_region,
QCOM_SCM_VAL, QCOM_SCM_VAL);

ret = qcom_scm_call(dev, QCOM_SCM_SVC_MP,
- QCOM_MEM_PROT_ASSIGN_ID,
+ QCOM_SCM_MP_ASSIGN,
&desc, &res);

return ret ? : res.a1;
@@ -461,7 +461,7 @@ int __qcom_scm_restore_sec_cfg(struct device *dev, u32 device_id, u32 spare)
desc.args[1] = spare;
desc.arginfo = QCOM_SCM_ARGS(2);

- ret = qcom_scm_call(dev, QCOM_SCM_SVC_MP, QCOM_SCM_RESTORE_SEC_CFG,
+ ret = qcom_scm_call(dev, QCOM_SCM_SVC_MP, QCOM_SCM_MP_RESTORE_SEC_CFG,
&desc, &res);

return ret ? : res.a1;
@@ -478,7 +478,7 @@ int __qcom_scm_iommu_secure_ptbl_size(struct device *dev, u32 spare,
desc.arginfo = QCOM_SCM_ARGS(1);

ret = qcom_scm_call(dev, QCOM_SCM_SVC_MP,
- QCOM_SCM_IOMMU_SECURE_PTBL_SIZE, &desc, &res);
+ QCOM_SCM_MP_IOMMU_SECURE_PTBL_SIZE, &desc, &res);

if (size)
*size = res.a1;
@@ -500,7 +500,7 @@ int __qcom_scm_iommu_secure_ptbl_init(struct device *dev, u64 addr, u32 size,
QCOM_SCM_VAL);

ret = qcom_scm_call(dev, QCOM_SCM_SVC_MP,
- QCOM_SCM_IOMMU_SECURE_PTBL_INIT, &desc, &res);
+ QCOM_SCM_MP_IOMMU_SECURE_PTBL_INIT, &desc, &res);

/* the pg table has been initialized already, ignore the error */
if (ret == -EPERM)
@@ -514,11 +514,11 @@ int __qcom_scm_set_dload_mode(struct device *dev, bool enable)
struct qcom_scm_desc desc = {0};
struct arm_smccc_res res;

- desc.args[0] = QCOM_SCM_SET_DLOAD_MODE;
- desc.args[1] = enable ? QCOM_SCM_SET_DLOAD_MODE : 0;
+ desc.args[0] = QCOM_SCM_BOOT_SET_DLOAD_MODE;
+ desc.args[1] = enable ? QCOM_SCM_BOOT_SET_DLOAD_MODE : 0;
desc.arginfo = QCOM_SCM_ARGS(2);

- return qcom_scm_call(dev, QCOM_SCM_SVC_BOOT, QCOM_SCM_SET_DLOAD_MODE,
+ return qcom_scm_call(dev, QCOM_SCM_SVC_BOOT, QCOM_SCM_BOOT_SET_DLOAD_MODE,
&desc, &res);
}

@@ -558,10 +558,10 @@ int __qcom_scm_qsmmu500_wait_safe_toggle(struct device *dev, bool en)
struct qcom_scm_desc desc = {0};
struct arm_smccc_res res;

- desc.args[0] = QCOM_SCM_CONFIG_ERRATA1_CLIENT_ALL;
+ desc.args[0] = QCOM_SCM_SMMU_CONFIG_ERRATA1_CLIENT_ALL;
desc.args[1] = en;
desc.arginfo = QCOM_SCM_ARGS(2);

return qcom_scm_call_atomic(dev, QCOM_SCM_SVC_SMMU_PROGRAM,
- QCOM_SCM_CONFIG_ERRATA1, &desc, &res);
+ QCOM_SCM_SMMU_CONFIG_ERRATA1, &desc, &res);
}
diff --git a/drivers/firmware/qcom_scm.c b/drivers/firmware/qcom_scm.c
index 40222b1..450d6d6 100644
--- a/drivers/firmware/qcom_scm.c
+++ b/drivers/firmware/qcom_scm.c
@@ -140,7 +140,7 @@ bool qcom_scm_hdcp_available(void)
return ret;

ret = __qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_HDCP,
- QCOM_SCM_CMD_HDCP);
+ QCOM_SCM_HDCP_INVOKE);

qcom_scm_clk_disable();

@@ -181,7 +181,7 @@ bool qcom_scm_pas_supported(u32 peripheral)
int ret;

ret = __qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_PIL,
- QCOM_SCM_PAS_IS_SUPPORTED_CMD);
+ QCOM_SCM_PIL_PAS_IS_SUPPORTED);
if (ret <= 0)
return false;

@@ -368,12 +368,12 @@ static void qcom_scm_set_download_mode(bool enable)

avail = __qcom_scm_is_call_available(__scm->dev,
QCOM_SCM_SVC_BOOT,
- QCOM_SCM_SET_DLOAD_MODE);
+ QCOM_SCM_BOOT_SET_DLOAD_MODE);
if (avail) {
ret = __qcom_scm_set_dload_mode(__scm->dev, enable);
} else if (__scm->dload_mode_addr) {
ret = __qcom_scm_io_writel(__scm->dev, __scm->dload_mode_addr,
- enable ? QCOM_SCM_SET_DLOAD_MODE : 0);
+ enable ? QCOM_SCM_BOOT_SET_DLOAD_MODE : 0);
} else {
dev_err(__scm->dev,
"No available mechanism for setting download mode\n");
diff --git a/drivers/firmware/qcom_scm.h b/drivers/firmware/qcom_scm.h
index baee744..99e91ba 100644
--- a/drivers/firmware/qcom_scm.h
+++ b/drivers/firmware/qcom_scm.h
@@ -5,23 +5,18 @@
#define __QCOM_SCM_INT_H

#define QCOM_SCM_SVC_BOOT 0x1
-#define QCOM_SCM_BOOT_ADDR 0x1
-#define QCOM_SCM_SET_DLOAD_MODE 0x10
-#define QCOM_SCM_BOOT_ADDR_MC 0x11
-#define QCOM_SCM_SET_REMOTE_STATE 0xa
+#define QCOM_SCM_BOOT_SET_ADDR 0x1
+#define QCOM_SCM_BOOT_SET_DLOAD_MODE 0x10
+#define QCOM_SCM_BOOT_SET_REMOTE_STATE 0xa
extern int __qcom_scm_set_remote_state(struct device *dev, u32 state, u32 id);
extern int __qcom_scm_set_dload_mode(struct device *dev, bool enable);

-#define QCOM_SCM_FLAG_HLOS 0x01
-#define QCOM_SCM_FLAG_COLDBOOT_MC 0x02
-#define QCOM_SCM_FLAG_WARMBOOT_MC 0x04
extern int __qcom_scm_set_warm_boot_addr(struct device *dev, void *entry,
const cpumask_t *cpus);
extern int __qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus);

-#define QCOM_SCM_CMD_TERMINATE_PC 0x2
+#define QCOM_SCM_BOOT_TERMINATE_PC 0x2
#define QCOM_SCM_FLUSH_FLAG_MASK 0x3
-#define QCOM_SCM_CMD_CORE_HOTPLUGGED 0x10
extern void __qcom_scm_cpu_power_down(u32 flags);

#define QCOM_SCM_SVC_IO 0x5
@@ -31,24 +26,24 @@ extern int __qcom_scm_io_readl(struct device *dev, phys_addr_t addr, unsigned in
extern int __qcom_scm_io_writel(struct device *dev, phys_addr_t addr, unsigned int val);

#define QCOM_SCM_SVC_INFO 0x6
-#define QCOM_IS_CALL_AVAIL_CMD 0x1
+#define QCOM_SCM_INFO_IS_CALL_AVAIL 0x1
extern int __qcom_scm_is_call_available(struct device *dev, u32 svc_id,
u32 cmd_id);

#define QCOM_SCM_SVC_HDCP 0x11
-#define QCOM_SCM_CMD_HDCP 0x01
+#define QCOM_SCM_HDCP_INVOKE 0x01
extern int __qcom_scm_hdcp_req(struct device *dev,
struct qcom_scm_hdcp_req *req, u32 req_cnt, u32 *resp);

extern void __qcom_scm_init(void);

#define QCOM_SCM_SVC_PIL 0x2
-#define QCOM_SCM_PAS_INIT_IMAGE_CMD 0x1
-#define QCOM_SCM_PAS_MEM_SETUP_CMD 0x2
-#define QCOM_SCM_PAS_AUTH_AND_RESET_CMD 0x5
-#define QCOM_SCM_PAS_SHUTDOWN_CMD 0x6
-#define QCOM_SCM_PAS_IS_SUPPORTED_CMD 0x7
-#define QCOM_SCM_PAS_MSS_RESET 0xa
+#define QCOM_SCM_PIL_PAS_INIT_IMAGE 0x1
+#define QCOM_SCM_PIL_PAS_MEM_SETUP 0x2
+#define QCOM_SCM_PIL_PAS_AUTH_AND_RESET 0x5
+#define QCOM_SCM_PIL_PAS_SHUTDOWN 0x6
+#define QCOM_SCM_PIL_PAS_IS_SUPPORTED 0x7
+#define QCOM_SCM_PIL_PAS_MSS_RESET 0xa
extern bool __qcom_scm_pas_supported(struct device *dev, u32 peripheral);
extern int __qcom_scm_pas_init_image(struct device *dev, u32 peripheral,
dma_addr_t metadata_phys);
@@ -86,21 +81,21 @@ static inline int qcom_scm_remap_error(int err)
}

#define QCOM_SCM_SVC_MP 0xc
-#define QCOM_SCM_RESTORE_SEC_CFG 2
+#define QCOM_SCM_MP_RESTORE_SEC_CFG 2
extern int __qcom_scm_restore_sec_cfg(struct device *dev, u32 device_id,
u32 spare);
-#define QCOM_SCM_IOMMU_SECURE_PTBL_SIZE 3
-#define QCOM_SCM_IOMMU_SECURE_PTBL_INIT 4
+#define QCOM_SCM_MP_IOMMU_SECURE_PTBL_SIZE 3
+#define QCOM_SCM_MP_IOMMU_SECURE_PTBL_INIT 4
#define QCOM_SCM_SVC_SMMU_PROGRAM 0x15
-#define QCOM_SCM_CONFIG_ERRATA1 0x3
-#define QCOM_SCM_CONFIG_ERRATA1_CLIENT_ALL 0x2
+#define QCOM_SCM_SMMU_CONFIG_ERRATA1 0x3
+#define QCOM_SCM_SMMU_CONFIG_ERRATA1_CLIENT_ALL 0x2
extern int __qcom_scm_iommu_secure_ptbl_size(struct device *dev, u32 spare,
size_t *size);
extern int __qcom_scm_iommu_secure_ptbl_init(struct device *dev, u64 addr,
u32 size, u32 spare);
extern int __qcom_scm_qsmmu500_wait_safe_toggle(struct device *dev,
bool enable);
-#define QCOM_MEM_PROT_ASSIGN_ID 0x16
+#define QCOM_SCM_MP_ASSIGN 0x16
extern int __qcom_scm_assign_mem(struct device *dev,
phys_addr_t mem_region, size_t mem_sz,
phys_addr_t src, size_t src_sz,
--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project

2019-11-05 01:29:17

by Elliot Berman

[permalink] [raw]
Subject: [PATCH 06/17] firmware: qcom_scm-64: Add SCM results to descriptor

Remove knowledge of arm_smccc_res struct from client wrappers so that
client wrappers only work QCOM SCM data structures. SCM calls may have
up to 3 arguments, so qcom_scm_call_smccc is responsible now for filling
those 3 arguments accordingly.

Signed-off-by: Elliot Berman <[email protected]>
---
drivers/firmware/qcom_scm-64.c | 105 ++++++++++++++++++-----------------------
1 file changed, 45 insertions(+), 60 deletions(-)

diff --git a/drivers/firmware/qcom_scm-64.c b/drivers/firmware/qcom_scm-64.c
index 76412a5..f6536fa 100644
--- a/drivers/firmware/qcom_scm-64.c
+++ b/drivers/firmware/qcom_scm-64.c
@@ -50,6 +50,7 @@ struct qcom_scm_desc {
u32 cmd;
u32 arginfo;
u64 args[MAX_QCOM_SCM_ARGS];
+ u64 res[MAX_QCOM_SCM_RETS];
u32 owner;
};

@@ -115,8 +116,7 @@ static void qcom_scm_call_do_smccc(const struct qcom_scm_desc *desc,
}

static int ___qcom_scm_call_smccc(struct device *dev,
- const struct qcom_scm_desc *desc,
- struct arm_smccc_res *res, bool atomic)
+ struct qcom_scm_desc *desc, bool atomic)
{
int arglen = desc->arginfo & 0xf;
int i;
@@ -125,6 +125,7 @@ static int ___qcom_scm_call_smccc(struct device *dev,
void *args_virt = NULL;
size_t alloc_len;
gfp_t flag = atomic ? GFP_ATOMIC : GFP_KERNEL;
+ struct arm_smccc_res res;

if (unlikely(arglen > SMCCC_N_REG_ARGS)) {
alloc_len = SMCCC_N_EXT_ARGS * sizeof(u64);
@@ -158,15 +159,19 @@ static int ___qcom_scm_call_smccc(struct device *dev,
x5 = args_phys;
}

- qcom_scm_call_do_smccc(desc, res, x5, atomic);
+ qcom_scm_call_do_smccc(desc, &res, x5, atomic);

if (args_virt) {
dma_unmap_single(dev, args_phys, alloc_len, DMA_TO_DEVICE);
kfree(args_virt);
}

- if (res->a0 < 0)
- return qcom_scm_remap_error(res->a0);
+ desc->res[0] = res.a1;
+ desc->res[1] = res.a2;
+ desc->res[2] = res.a3;
+
+ if (res.a0 < 0)
+ return qcom_scm_remap_error(res.a0);

return 0;
}
@@ -181,11 +186,10 @@ static int ___qcom_scm_call_smccc(struct device *dev,
* 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 arm_smccc_res *res)
+static int qcom_scm_call(struct device *dev, struct qcom_scm_desc *desc)
{
might_sleep();
- return ___qcom_scm_call_smccc(dev, desc, res, false);
+ return ___qcom_scm_call_smccc(dev, desc, false);
}

/**
@@ -199,11 +203,9 @@ static int qcom_scm_call(struct device *dev, const struct qcom_scm_desc *desc,
* 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 arm_smccc_res *res)
+static int qcom_scm_call_atomic(struct device *dev, struct qcom_scm_desc *desc)
{
- return ___qcom_scm_call_smccc(dev, desc, res, true);
+ return ___qcom_scm_call_smccc(dev, desc, true);
}

/**
@@ -253,16 +255,15 @@ int __qcom_scm_set_remote_state(struct device *dev, u32 state, u32 id)
.cmd = QCOM_SCM_BOOT_SET_REMOTE_STATE,
.owner = ARM_SMCCC_OWNER_SIP,
};
- struct arm_smccc_res res;
int ret;

desc.args[0] = state;
desc.args[1] = id;
desc.arginfo = QCOM_SCM_ARGS(2);

- ret = qcom_scm_call(dev, &desc, &res);
+ ret = qcom_scm_call(dev, &desc);

- return ret ? : res.a1;
+ return ret ? : desc.res[0];
}

int __qcom_scm_set_dload_mode(struct device *dev, bool enable)
@@ -272,13 +273,12 @@ int __qcom_scm_set_dload_mode(struct device *dev, bool enable)
.cmd = QCOM_SCM_BOOT_SET_DLOAD_MODE,
.owner = ARM_SMCCC_OWNER_SIP,
};
- struct arm_smccc_res res;

desc.args[0] = QCOM_SCM_BOOT_SET_DLOAD_MODE;
desc.args[1] = enable ? QCOM_SCM_BOOT_SET_DLOAD_MODE : 0;
desc.arginfo = QCOM_SCM_ARGS(2);

- return qcom_scm_call(dev, &desc, &res);
+ return qcom_scm_call(dev, &desc);
}

bool __qcom_scm_pas_supported(struct device *dev, u32 peripheral)
@@ -289,14 +289,13 @@ bool __qcom_scm_pas_supported(struct device *dev, u32 peripheral)
.cmd = QCOM_SCM_PIL_PAS_IS_SUPPORTED,
.owner = ARM_SMCCC_OWNER_SIP,
};
- struct arm_smccc_res res;

desc.args[0] = peripheral;
desc.arginfo = QCOM_SCM_ARGS(1);

- ret = qcom_scm_call(dev, &desc, &res);
+ ret = qcom_scm_call(dev, &desc);

- return ret ? false : !!res.a1;
+ return ret ? false : !!desc.res[0];
}

int __qcom_scm_pas_init_image(struct device *dev, u32 peripheral,
@@ -308,15 +307,14 @@ int __qcom_scm_pas_init_image(struct device *dev, u32 peripheral,
.cmd = QCOM_SCM_PIL_PAS_INIT_IMAGE,
.owner = ARM_SMCCC_OWNER_SIP,
};
- struct arm_smccc_res res;

desc.args[0] = peripheral;
desc.args[1] = metadata_phys;
desc.arginfo = QCOM_SCM_ARGS(2, QCOM_SCM_VAL, QCOM_SCM_RW);

- ret = qcom_scm_call(dev, &desc, &res);
+ ret = qcom_scm_call(dev, &desc);

- return ret ? : res.a1;
+ return ret ? : desc.res[0];
}

int __qcom_scm_pas_mem_setup(struct device *dev, u32 peripheral,
@@ -328,16 +326,15 @@ int __qcom_scm_pas_mem_setup(struct device *dev, u32 peripheral,
.cmd = QCOM_SCM_PIL_PAS_MEM_SETUP,
.owner = ARM_SMCCC_OWNER_SIP,
};
- struct arm_smccc_res res;

desc.args[0] = peripheral;
desc.args[1] = addr;
desc.args[2] = size;
desc.arginfo = QCOM_SCM_ARGS(3);

- ret = qcom_scm_call(dev, &desc, &res);
+ ret = qcom_scm_call(dev, &desc);

- return ret ? : res.a1;
+ return ret ? : desc.res[0];
}

int __qcom_scm_pas_auth_and_reset(struct device *dev, u32 peripheral)
@@ -348,14 +345,13 @@ int __qcom_scm_pas_auth_and_reset(struct device *dev, u32 peripheral)
.cmd = QCOM_SCM_PIL_PAS_AUTH_AND_RESET,
.owner = ARM_SMCCC_OWNER_SIP,
};
- struct arm_smccc_res res;

desc.args[0] = peripheral;
desc.arginfo = QCOM_SCM_ARGS(1);

- ret = qcom_scm_call(dev, &desc, &res);
+ ret = qcom_scm_call(dev, &desc);

- return ret ? : res.a1;
+ return ret ? : desc.res[0];
}

int __qcom_scm_pas_shutdown(struct device *dev, u32 peripheral)
@@ -366,14 +362,13 @@ int __qcom_scm_pas_shutdown(struct device *dev, u32 peripheral)
.cmd = QCOM_SCM_PIL_PAS_SHUTDOWN,
.owner = ARM_SMCCC_OWNER_SIP,
};
- struct arm_smccc_res res;

desc.args[0] = peripheral;
desc.arginfo = QCOM_SCM_ARGS(1);

- ret = qcom_scm_call(dev, &desc, &res);
+ ret = qcom_scm_call(dev, &desc);

- return ret ? : res.a1;
+ return ret ? : desc.res[0];
}

int __qcom_scm_pas_mss_reset(struct device *dev, bool reset)
@@ -383,16 +378,15 @@ int __qcom_scm_pas_mss_reset(struct device *dev, bool reset)
.cmd = QCOM_SCM_PIL_PAS_MSS_RESET,
.owner = ARM_SMCCC_OWNER_SIP,
};
- struct arm_smccc_res res;
int ret;

desc.args[0] = reset;
desc.args[1] = 0;
desc.arginfo = QCOM_SCM_ARGS(2);

- ret = qcom_scm_call(dev, &desc, &res);
+ ret = qcom_scm_call(dev, &desc);

- return ret ? : res.a1;
+ return ret ? : desc.res[0];
}

int __qcom_scm_io_readl(struct device *dev, phys_addr_t addr,
@@ -403,15 +397,14 @@ int __qcom_scm_io_readl(struct device *dev, phys_addr_t addr,
.cmd = QCOM_SCM_IO_READ,
.owner = ARM_SMCCC_OWNER_SIP,
};
- struct arm_smccc_res res;
int ret;

desc.args[0] = addr;
desc.arginfo = QCOM_SCM_ARGS(1);

- ret = qcom_scm_call(dev, &desc, &res);
+ ret = qcom_scm_call(dev, &desc);
if (ret >= 0)
- *val = res.a1;
+ *val = desc.res[0];

return ret < 0 ? ret : 0;
}
@@ -423,13 +416,12 @@ int __qcom_scm_io_writel(struct device *dev, phys_addr_t addr, unsigned int val)
.cmd = QCOM_SCM_IO_WRITE,
.owner = ARM_SMCCC_OWNER_SIP,
};
- struct arm_smccc_res res;

desc.args[0] = addr;
desc.args[1] = val;
desc.arginfo = QCOM_SCM_ARGS(2);

- return qcom_scm_call(dev, &desc, &res);
+ return qcom_scm_call(dev, &desc);
}

int __qcom_scm_is_call_available(struct device *dev, u32 svc_id, u32 cmd_id)
@@ -440,15 +432,14 @@ int __qcom_scm_is_call_available(struct device *dev, u32 svc_id, u32 cmd_id)
.cmd = QCOM_SCM_INFO_IS_CALL_AVAIL,
.owner = ARM_SMCCC_OWNER_SIP,
};
- struct arm_smccc_res res;

desc.arginfo = QCOM_SCM_ARGS(1);
desc.args[0] = SMCCC_FUNCNUM(svc_id, cmd_id) |
(ARM_SMCCC_OWNER_SIP << ARM_SMCCC_OWNER_SHIFT);

- ret = qcom_scm_call(dev, &desc, &res);
+ ret = qcom_scm_call(dev, &desc);

- return ret ? : res.a1;
+ return ret ? : desc.res[0];
}

int __qcom_scm_restore_sec_cfg(struct device *dev, u32 device_id, u32 spare)
@@ -458,16 +449,15 @@ int __qcom_scm_restore_sec_cfg(struct device *dev, u32 device_id, u32 spare)
.cmd = QCOM_SCM_MP_RESTORE_SEC_CFG,
.owner = ARM_SMCCC_OWNER_SIP,
};
- struct arm_smccc_res res;
int ret;

desc.args[0] = device_id;
desc.args[1] = spare;
desc.arginfo = QCOM_SCM_ARGS(2);

- ret = qcom_scm_call(dev, &desc, &res);
+ ret = qcom_scm_call(dev, &desc);

- return ret ? : res.a1;
+ return ret ? : desc.res[0];
}

int __qcom_scm_iommu_secure_ptbl_size(struct device *dev, u32 spare,
@@ -478,18 +468,17 @@ int __qcom_scm_iommu_secure_ptbl_size(struct device *dev, u32 spare,
.cmd = QCOM_SCM_MP_IOMMU_SECURE_PTBL_SIZE,
.owner = ARM_SMCCC_OWNER_SIP,
};
- struct arm_smccc_res res;
int ret;

desc.args[0] = spare;
desc.arginfo = QCOM_SCM_ARGS(1);

- ret = qcom_scm_call(dev, &desc, &res);
+ ret = qcom_scm_call(dev, &desc);

if (size)
- *size = res.a1;
+ *size = desc.res[0];

- return ret ? : res.a2;
+ return ret ? : desc.res[1];
}

int __qcom_scm_iommu_secure_ptbl_init(struct device *dev, u64 addr, u32 size,
@@ -500,7 +489,6 @@ int __qcom_scm_iommu_secure_ptbl_init(struct device *dev, u64 addr, u32 size,
.cmd = QCOM_SCM_MP_IOMMU_SECURE_PTBL_INIT,
.owner = ARM_SMCCC_OWNER_SIP,
};
- struct arm_smccc_res res;
int ret;

desc.args[0] = addr;
@@ -509,7 +497,7 @@ int __qcom_scm_iommu_secure_ptbl_init(struct device *dev, u64 addr, u32 size,
desc.arginfo = QCOM_SCM_ARGS(3, QCOM_SCM_RW, QCOM_SCM_VAL,
QCOM_SCM_VAL);

- ret = qcom_scm_call(dev, &desc, &res);
+ ret = qcom_scm_call(dev, &desc);

/* the pg table has been initialized already, ignore the error */
if (ret == -EPERM)
@@ -528,7 +516,6 @@ int __qcom_scm_assign_mem(struct device *dev, phys_addr_t mem_region,
.cmd = QCOM_SCM_MP_ASSIGN,
.owner = ARM_SMCCC_OWNER_SIP,
};
- struct arm_smccc_res res;

desc.args[0] = mem_region;
desc.args[1] = mem_sz;
@@ -542,9 +529,9 @@ int __qcom_scm_assign_mem(struct device *dev, phys_addr_t mem_region,
QCOM_SCM_RO, QCOM_SCM_VAL, QCOM_SCM_RO,
QCOM_SCM_VAL, QCOM_SCM_VAL);

- ret = qcom_scm_call(dev, &desc, &res);
+ ret = qcom_scm_call(dev, &desc);

- return ret ? : res.a1;
+ return ret ? : desc.res[0];
}

int __qcom_scm_hdcp_req(struct device *dev, struct qcom_scm_hdcp_req *req,
@@ -556,7 +543,6 @@ int __qcom_scm_hdcp_req(struct device *dev, struct qcom_scm_hdcp_req *req,
.cmd = QCOM_SCM_HDCP_INVOKE,
.owner = ARM_SMCCC_OWNER_SIP,
};
- struct arm_smccc_res res;

if (req_cnt > QCOM_SCM_HDCP_MAX_REQ_CNT)
return -ERANGE;
@@ -573,8 +559,8 @@ int __qcom_scm_hdcp_req(struct device *dev, struct qcom_scm_hdcp_req *req,
desc.args[9] = req[4].val;
desc.arginfo = QCOM_SCM_ARGS(10);

- ret = qcom_scm_call(dev, &desc, &res);
- *resp = res.a1;
+ ret = qcom_scm_call(dev, &desc);
+ *resp = desc.res[0];

return ret;
}
@@ -586,13 +572,12 @@ int __qcom_scm_qsmmu500_wait_safe_toggle(struct device *dev, bool en)
.cmd = QCOM_SCM_SMMU_CONFIG_ERRATA1,
.owner = ARM_SMCCC_OWNER_SIP,
};
- struct arm_smccc_res res;

desc.args[0] = QCOM_SCM_SMMU_CONFIG_ERRATA1_CLIENT_ALL;
desc.args[1] = en;
desc.arginfo = QCOM_SCM_ARGS(2);

- return qcom_scm_call_atomic(dev, &desc, &res);
+ return qcom_scm_call_atomic(dev, &desc);
}

void __qcom_scm_init(void)
--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project

2019-11-05 01:29:17

by Elliot Berman

[permalink] [raw]
Subject: [PATCH 03/17] firmware: qcom_scm: Order functions, definitions by service/command

Definitions throughout qcom_scm are loosely grouped and loosely ordered.
Sort all the functions/definitions by service ID/command ID to improve
sanity when needing to add new functionality to this driver.

Signed-off-by: Elliot Berman <[email protected]>
---
drivers/firmware/qcom_scm-32.c | 104 +++++++++----------
drivers/firmware/qcom_scm-64.c | 192 +++++++++++++++++------------------
drivers/firmware/qcom_scm.c | 224 ++++++++++++++++++++---------------------
drivers/firmware/qcom_scm.h | 107 ++++++++++----------
include/linux/qcom_scm.h | 72 ++++++-------
5 files changed, 350 insertions(+), 349 deletions(-)

diff --git a/drivers/firmware/qcom_scm-32.c b/drivers/firmware/qcom_scm-32.c
index 87b520f..b09fddf 100644
--- a/drivers/firmware/qcom_scm-32.c
+++ b/drivers/firmware/qcom_scm-32.c
@@ -419,33 +419,28 @@ void __qcom_scm_cpu_power_down(u32 flags)
flags & QCOM_SCM_FLUSH_FLAG_MASK);
}

-int __qcom_scm_is_call_available(struct device *dev, u32 svc_id, u32 cmd_id)
+int __qcom_scm_set_remote_state(struct device *dev, u32 state, u32 id)
{
+ struct {
+ __le32 state;
+ __le32 id;
+ } req;
+ __le32 scm_ret = 0;
int ret;
- __le32 svc_cmd = cpu_to_le32((svc_id << 10) | cmd_id);
- __le32 ret_val = 0;
-
- ret = qcom_scm_call(dev, QCOM_SCM_SVC_INFO, QCOM_SCM_INFO_IS_CALL_AVAIL,
- &svc_cmd, sizeof(svc_cmd), &ret_val,
- sizeof(ret_val));
- if (ret)
- return ret;

- return le32_to_cpu(ret_val);
-}
+ req.state = cpu_to_le32(state);
+ req.id = cpu_to_le32(id);

-int __qcom_scm_hdcp_req(struct device *dev, struct qcom_scm_hdcp_req *req,
- u32 req_cnt, u32 *resp)
-{
- if (req_cnt > QCOM_SCM_HDCP_MAX_REQ_CNT)
- return -ERANGE;
+ ret = qcom_scm_call(dev, QCOM_SCM_SVC_BOOT, QCOM_SCM_BOOT_SET_REMOTE_STATE,
+ &req, sizeof(req), &scm_ret, sizeof(scm_ret));

- return qcom_scm_call(dev, QCOM_SCM_SVC_HDCP, QCOM_SCM_HDCP_INVOKE,
- req, req_cnt * sizeof(*req), resp, sizeof(*resp));
+ return ret ? : le32_to_cpu(scm_ret);
}

-void __qcom_scm_init(void)
+int __qcom_scm_set_dload_mode(struct device *dev, bool enable)
{
+ return qcom_scm_call_atomic2(QCOM_SCM_SVC_BOOT, QCOM_SCM_BOOT_SET_DLOAD_MODE,
+ enable ? QCOM_SCM_BOOT_SET_DLOAD_MODE : 0, 0);
}

bool __qcom_scm_pas_supported(struct device *dev, u32 peripheral)
@@ -550,35 +545,37 @@ int __qcom_scm_pas_mss_reset(struct device *dev, bool reset)
return ret ? : le32_to_cpu(out);
}

-int __qcom_scm_set_dload_mode(struct device *dev, bool enable)
-{
- return qcom_scm_call_atomic2(QCOM_SCM_SVC_BOOT, QCOM_SCM_BOOT_SET_DLOAD_MODE,
- enable ? QCOM_SCM_BOOT_SET_DLOAD_MODE : 0, 0);
-}
-
-int __qcom_scm_set_remote_state(struct device *dev, u32 state, u32 id)
+int __qcom_scm_io_readl(struct device *dev, phys_addr_t addr,
+ unsigned int *val)
{
- struct {
- __le32 state;
- __le32 id;
- } req;
- __le32 scm_ret = 0;
int ret;

- req.state = cpu_to_le32(state);
- req.id = cpu_to_le32(id);
+ ret = qcom_scm_call_atomic1(QCOM_SCM_SVC_IO, QCOM_SCM_IO_READ, addr);
+ if (ret >= 0)
+ *val = ret;

- ret = qcom_scm_call(dev, QCOM_SCM_SVC_BOOT, QCOM_SCM_BOOT_SET_REMOTE_STATE,
- &req, sizeof(req), &scm_ret, sizeof(scm_ret));
+ return ret < 0 ? ret : 0;
+}

- return ret ? : le32_to_cpu(scm_ret);
+int __qcom_scm_io_writel(struct device *dev, phys_addr_t addr, unsigned int val)
+{
+ return qcom_scm_call_atomic2(QCOM_SCM_SVC_IO, QCOM_SCM_IO_WRITE,
+ addr, val);
}

-int __qcom_scm_assign_mem(struct device *dev, phys_addr_t mem_region,
- size_t mem_sz, phys_addr_t src, size_t src_sz,
- phys_addr_t dest, size_t dest_sz)
+int __qcom_scm_is_call_available(struct device *dev, u32 svc_id, u32 cmd_id)
{
- return -ENODEV;
+ int ret;
+ __le32 svc_cmd = cpu_to_le32((svc_id << 10) | cmd_id);
+ __le32 ret_val = 0;
+
+ ret = qcom_scm_call(dev, QCOM_SCM_SVC_INFO, QCOM_SCM_INFO_IS_CALL_AVAIL,
+ &svc_cmd, sizeof(svc_cmd), &ret_val,
+ sizeof(ret_val));
+ if (ret)
+ return ret;
+
+ return le32_to_cpu(ret_val);
}

int __qcom_scm_restore_sec_cfg(struct device *dev, u32 device_id,
@@ -599,25 +596,28 @@ int __qcom_scm_iommu_secure_ptbl_init(struct device *dev, u64 addr, u32 size,
return -ENODEV;
}

-int __qcom_scm_io_readl(struct device *dev, phys_addr_t addr,
- unsigned int *val)
+int __qcom_scm_assign_mem(struct device *dev, phys_addr_t mem_region,
+ size_t mem_sz, phys_addr_t src, size_t src_sz,
+ phys_addr_t dest, size_t dest_sz)
{
- int ret;
-
- ret = qcom_scm_call_atomic1(QCOM_SCM_SVC_IO, QCOM_SCM_IO_READ, addr);
- if (ret >= 0)
- *val = ret;
-
- return ret < 0 ? ret : 0;
+ return -ENODEV;
}

-int __qcom_scm_io_writel(struct device *dev, phys_addr_t addr, unsigned int val)
+int __qcom_scm_hdcp_req(struct device *dev, struct qcom_scm_hdcp_req *req,
+ u32 req_cnt, u32 *resp)
{
- return qcom_scm_call_atomic2(QCOM_SCM_SVC_IO, QCOM_SCM_IO_WRITE,
- addr, val);
+ if (req_cnt > QCOM_SCM_HDCP_MAX_REQ_CNT)
+ return -ERANGE;
+
+ return qcom_scm_call(dev, QCOM_SCM_SVC_HDCP, QCOM_SCM_HDCP_INVOKE,
+ req, req_cnt * sizeof(*req), resp, sizeof(*resp));
}

int __qcom_scm_qsmmu500_wait_safe_toggle(struct device *dev, bool enable)
{
return -ENODEV;
}
+
+void __qcom_scm_init(void)
+{
+}
\ No newline at end of file
diff --git a/drivers/firmware/qcom_scm-64.c b/drivers/firmware/qcom_scm-64.c
index f0b4853..ead0b5f 100644
--- a/drivers/firmware/qcom_scm-64.c
+++ b/drivers/firmware/qcom_scm-64.c
@@ -246,68 +246,33 @@ void __qcom_scm_cpu_power_down(u32 flags)
{
}

-int __qcom_scm_is_call_available(struct device *dev, u32 svc_id, u32 cmd_id)
+int __qcom_scm_set_remote_state(struct device *dev, u32 state, u32 id)
{
- int ret;
struct qcom_scm_desc desc = {0};
struct arm_smccc_res res;
+ int ret;

- desc.arginfo = QCOM_SCM_ARGS(1);
- desc.args[0] = SMCCC_FUNCNUM(svc_id, cmd_id) |
- (ARM_SMCCC_OWNER_SIP << ARM_SMCCC_OWNER_SHIFT);
+ desc.args[0] = state;
+ desc.args[1] = id;
+ desc.arginfo = QCOM_SCM_ARGS(2);

- ret = qcom_scm_call(dev, QCOM_SCM_SVC_INFO, QCOM_SCM_INFO_IS_CALL_AVAIL,
+ ret = qcom_scm_call(dev, QCOM_SCM_SVC_BOOT, QCOM_SCM_BOOT_SET_REMOTE_STATE,
&desc, &res);

return ret ? : res.a1;
}

-int __qcom_scm_hdcp_req(struct device *dev, struct qcom_scm_hdcp_req *req,
- u32 req_cnt, u32 *resp)
+int __qcom_scm_set_dload_mode(struct device *dev, bool enable)
{
- int ret;
struct qcom_scm_desc desc = {0};
struct arm_smccc_res res;

- if (req_cnt > QCOM_SCM_HDCP_MAX_REQ_CNT)
- return -ERANGE;
-
- desc.args[0] = req[0].addr;
- desc.args[1] = req[0].val;
- desc.args[2] = req[1].addr;
- desc.args[3] = req[1].val;
- desc.args[4] = req[2].addr;
- desc.args[5] = req[2].val;
- desc.args[6] = req[3].addr;
- desc.args[7] = req[3].val;
- desc.args[8] = req[4].addr;
- desc.args[9] = req[4].val;
- desc.arginfo = QCOM_SCM_ARGS(10);
-
- ret = qcom_scm_call(dev, QCOM_SCM_SVC_HDCP, QCOM_SCM_HDCP_INVOKE, &desc,
- &res);
- *resp = res.a1;
-
- return ret;
-}
-
-void __qcom_scm_init(void)
-{
- u64 cmd;
- struct arm_smccc_res res;
- u32 function = SMCCC_FUNCNUM(QCOM_SCM_SVC_INFO, QCOM_SCM_INFO_IS_CALL_AVAIL);
-
- /* First try a SMC64 call */
- cmd = ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, ARM_SMCCC_SMC_64,
- ARM_SMCCC_OWNER_SIP, function);
-
- arm_smccc_smc(cmd, QCOM_SCM_ARGS(1), cmd & (~BIT(ARM_SMCCC_TYPE_SHIFT)),
- 0, 0, 0, 0, 0, &res);
+ desc.args[0] = QCOM_SCM_BOOT_SET_DLOAD_MODE;
+ desc.args[1] = enable ? QCOM_SCM_BOOT_SET_DLOAD_MODE : 0;
+ desc.arginfo = QCOM_SCM_ARGS(2);

- if (!res.a0 && res.a1)
- qcom_smccc_convention = ARM_SMCCC_SMC_64;
- else
- qcom_smccc_convention = ARM_SMCCC_SMC_32;
+ return qcom_scm_call(dev, QCOM_SCM_SVC_BOOT, QCOM_SCM_BOOT_SET_DLOAD_MODE,
+ &desc, &res);
}

bool __qcom_scm_pas_supported(struct device *dev, u32 peripheral)
@@ -408,44 +373,48 @@ int __qcom_scm_pas_mss_reset(struct device *dev, bool reset)
return ret ? : res.a1;
}

-int __qcom_scm_set_remote_state(struct device *dev, u32 state, u32 id)
+int __qcom_scm_io_readl(struct device *dev, phys_addr_t addr,
+ unsigned int *val)
{
struct qcom_scm_desc desc = {0};
struct arm_smccc_res res;
int ret;

- desc.args[0] = state;
- desc.args[1] = id;
- desc.arginfo = QCOM_SCM_ARGS(2);
+ desc.args[0] = addr;
+ desc.arginfo = QCOM_SCM_ARGS(1);

- ret = qcom_scm_call(dev, QCOM_SCM_SVC_BOOT, QCOM_SCM_BOOT_SET_REMOTE_STATE,
+ ret = qcom_scm_call(dev, QCOM_SCM_SVC_IO, QCOM_SCM_IO_READ,
&desc, &res);
+ if (ret >= 0)
+ *val = res.a1;

- return ret ? : res.a1;
+ return ret < 0 ? ret : 0;
}

-int __qcom_scm_assign_mem(struct device *dev, phys_addr_t mem_region,
- size_t mem_sz, phys_addr_t src, size_t src_sz,
- phys_addr_t dest, size_t dest_sz)
+int __qcom_scm_io_writel(struct device *dev, phys_addr_t addr, unsigned int val)
{
- int ret;
struct qcom_scm_desc desc = {0};
struct arm_smccc_res res;

- desc.args[0] = mem_region;
- desc.args[1] = mem_sz;
- desc.args[2] = src;
- desc.args[3] = src_sz;
- desc.args[4] = dest;
- desc.args[5] = dest_sz;
- desc.args[6] = 0;
+ desc.args[0] = addr;
+ desc.args[1] = val;
+ desc.arginfo = QCOM_SCM_ARGS(2);

- desc.arginfo = QCOM_SCM_ARGS(7, QCOM_SCM_RO, QCOM_SCM_VAL,
- QCOM_SCM_RO, QCOM_SCM_VAL, QCOM_SCM_RO,
- QCOM_SCM_VAL, QCOM_SCM_VAL);
+ return qcom_scm_call(dev, QCOM_SCM_SVC_IO, QCOM_SCM_IO_WRITE,
+ &desc, &res);
+}

- ret = qcom_scm_call(dev, QCOM_SCM_SVC_MP,
- QCOM_SCM_MP_ASSIGN,
+int __qcom_scm_is_call_available(struct device *dev, u32 svc_id, u32 cmd_id)
+{
+ int ret;
+ struct qcom_scm_desc desc = {0};
+ struct arm_smccc_res res;
+
+ desc.arginfo = QCOM_SCM_ARGS(1);
+ desc.args[0] = SMCCC_FUNCNUM(svc_id, cmd_id) |
+ (ARM_SMCCC_OWNER_SIP << ARM_SMCCC_OWNER_SHIFT);
+
+ ret = qcom_scm_call(dev, QCOM_SCM_SVC_INFO, QCOM_SCM_INFO_IS_CALL_AVAIL,
&desc, &res);

return ret ? : res.a1;
@@ -509,48 +478,60 @@ int __qcom_scm_iommu_secure_ptbl_init(struct device *dev, u64 addr, u32 size,
return ret;
}

-int __qcom_scm_set_dload_mode(struct device *dev, bool enable)
+int __qcom_scm_assign_mem(struct device *dev, phys_addr_t mem_region,
+ size_t mem_sz, phys_addr_t src, size_t src_sz,
+ phys_addr_t dest, size_t dest_sz)
{
+ int ret;
struct qcom_scm_desc desc = {0};
struct arm_smccc_res res;

- desc.args[0] = QCOM_SCM_BOOT_SET_DLOAD_MODE;
- desc.args[1] = enable ? QCOM_SCM_BOOT_SET_DLOAD_MODE : 0;
- desc.arginfo = QCOM_SCM_ARGS(2);
-
- return qcom_scm_call(dev, QCOM_SCM_SVC_BOOT, QCOM_SCM_BOOT_SET_DLOAD_MODE,
- &desc, &res);
-}
-
-int __qcom_scm_io_readl(struct device *dev, phys_addr_t addr,
- unsigned int *val)
-{
- struct qcom_scm_desc desc = {0};
- struct arm_smccc_res res;
- int ret;
+ desc.args[0] = mem_region;
+ desc.args[1] = mem_sz;
+ desc.args[2] = src;
+ desc.args[3] = src_sz;
+ desc.args[4] = dest;
+ desc.args[5] = dest_sz;
+ desc.args[6] = 0;

- desc.args[0] = addr;
- desc.arginfo = QCOM_SCM_ARGS(1);
+ desc.arginfo = QCOM_SCM_ARGS(7, QCOM_SCM_RO, QCOM_SCM_VAL,
+ QCOM_SCM_RO, QCOM_SCM_VAL, QCOM_SCM_RO,
+ QCOM_SCM_VAL, QCOM_SCM_VAL);

- ret = qcom_scm_call(dev, QCOM_SCM_SVC_IO, QCOM_SCM_IO_READ,
+ ret = qcom_scm_call(dev, QCOM_SCM_SVC_MP,
+ QCOM_SCM_MP_ASSIGN,
&desc, &res);
- if (ret >= 0)
- *val = res.a1;

- return ret < 0 ? ret : 0;
+ return ret ? : res.a1;
}

-int __qcom_scm_io_writel(struct device *dev, phys_addr_t addr, unsigned int val)
+int __qcom_scm_hdcp_req(struct device *dev, struct qcom_scm_hdcp_req *req,
+ u32 req_cnt, u32 *resp)
{
+ int ret;
struct qcom_scm_desc desc = {0};
struct arm_smccc_res res;

- desc.args[0] = addr;
- desc.args[1] = val;
- desc.arginfo = QCOM_SCM_ARGS(2);
+ if (req_cnt > QCOM_SCM_HDCP_MAX_REQ_CNT)
+ return -ERANGE;

- return qcom_scm_call(dev, QCOM_SCM_SVC_IO, QCOM_SCM_IO_WRITE,
- &desc, &res);
+ desc.args[0] = req[0].addr;
+ desc.args[1] = req[0].val;
+ desc.args[2] = req[1].addr;
+ desc.args[3] = req[1].val;
+ desc.args[4] = req[2].addr;
+ desc.args[5] = req[2].val;
+ desc.args[6] = req[3].addr;
+ desc.args[7] = req[3].val;
+ desc.args[8] = req[4].addr;
+ desc.args[9] = req[4].val;
+ desc.arginfo = QCOM_SCM_ARGS(10);
+
+ ret = qcom_scm_call(dev, QCOM_SCM_SVC_HDCP, QCOM_SCM_HDCP_INVOKE, &desc,
+ &res);
+ *resp = res.a1;
+
+ return ret;
}

int __qcom_scm_qsmmu500_wait_safe_toggle(struct device *dev, bool en)
@@ -565,3 +546,22 @@ int __qcom_scm_qsmmu500_wait_safe_toggle(struct device *dev, bool en)
return qcom_scm_call_atomic(dev, QCOM_SCM_SVC_SMMU_PROGRAM,
QCOM_SCM_SMMU_CONFIG_ERRATA1, &desc, &res);
}
+
+void __qcom_scm_init(void)
+{
+ u64 cmd;
+ struct arm_smccc_res res;
+ u32 function = SMCCC_FUNCNUM(QCOM_SCM_SVC_INFO, QCOM_SCM_INFO_IS_CALL_AVAIL);
+
+ /* First try a SMC64 call */
+ cmd = ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, ARM_SMCCC_SMC_64,
+ ARM_SMCCC_OWNER_SIP, function);
+
+ arm_smccc_smc(cmd, QCOM_SCM_ARGS(1), cmd & (~BIT(ARM_SMCCC_TYPE_SHIFT)),
+ 0, 0, 0, 0, 0, &res);
+
+ if (!res.a0 && res.a1)
+ qcom_smccc_convention = ARM_SMCCC_SMC_64;
+ else
+ qcom_smccc_convention = ARM_SMCCC_SMC_32;
+}
diff --git a/drivers/firmware/qcom_scm.c b/drivers/firmware/qcom_scm.c
index 450d6d6..83fc049 100644
--- a/drivers/firmware/qcom_scm.c
+++ b/drivers/firmware/qcom_scm.c
@@ -127,47 +127,33 @@ void qcom_scm_cpu_power_down(u32 flags)
}
EXPORT_SYMBOL(qcom_scm_cpu_power_down);

-/**
- * qcom_scm_hdcp_available() - Check if secure environment supports HDCP.
- *
- * Return true if HDCP is supported, false if not.
- */
-bool qcom_scm_hdcp_available(void)
+int qcom_scm_set_remote_state(u32 state, u32 id)
{
- int ret = qcom_scm_clk_enable();
-
- if (ret)
- return ret;
-
- ret = __qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_HDCP,
- QCOM_SCM_HDCP_INVOKE);
-
- qcom_scm_clk_disable();
-
- return ret > 0 ? true : false;
+ return __qcom_scm_set_remote_state(__scm->dev, state, id);
}
-EXPORT_SYMBOL(qcom_scm_hdcp_available);
+EXPORT_SYMBOL(qcom_scm_set_remote_state);

-/**
- * qcom_scm_hdcp_req() - Send HDCP request.
- * @req: HDCP request array
- * @req_cnt: HDCP request array count
- * @resp: response buffer passed to SCM
- *
- * Write HDCP register(s) through SCM.
- */
-int qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt, u32 *resp)
+static void qcom_scm_set_download_mode(bool enable)
{
- int ret = qcom_scm_clk_enable();
+ bool avail;
+ int ret = 0;

- if (ret)
- return ret;
+ avail = __qcom_scm_is_call_available(__scm->dev,
+ QCOM_SCM_SVC_BOOT,
+ QCOM_SCM_BOOT_SET_DLOAD_MODE);
+ if (avail) {
+ ret = __qcom_scm_set_dload_mode(__scm->dev, enable);
+ } else if (__scm->dload_mode_addr) {
+ ret = __qcom_scm_io_writel(__scm->dev, __scm->dload_mode_addr,
+ enable ? QCOM_SCM_BOOT_SET_DLOAD_MODE : 0);
+ } else {
+ dev_err(__scm->dev,
+ "No available mechanism for setting download mode\n");
+ }

- ret = __qcom_scm_hdcp_req(__scm->dev, req, req_cnt, resp);
- qcom_scm_clk_disable();
- return ret;
+ if (ret)
+ dev_err(__scm->dev, "failed to set download mode: %d\n", ret);
}
-EXPORT_SYMBOL(qcom_scm_hdcp_req);

/**
* qcom_scm_pas_supported() - Check if the peripheral authentication service is
@@ -325,30 +311,6 @@ static const struct reset_control_ops qcom_scm_pas_reset_ops = {
.deassert = qcom_scm_pas_reset_deassert,
};

-int qcom_scm_restore_sec_cfg(u32 device_id, u32 spare)
-{
- return __qcom_scm_restore_sec_cfg(__scm->dev, device_id, spare);
-}
-EXPORT_SYMBOL(qcom_scm_restore_sec_cfg);
-
-int qcom_scm_iommu_secure_ptbl_size(u32 spare, size_t *size)
-{
- return __qcom_scm_iommu_secure_ptbl_size(__scm->dev, spare, size);
-}
-EXPORT_SYMBOL(qcom_scm_iommu_secure_ptbl_size);
-
-int qcom_scm_iommu_secure_ptbl_init(u64 addr, u32 size, u32 spare)
-{
- return __qcom_scm_iommu_secure_ptbl_init(__scm->dev, addr, size, spare);
-}
-EXPORT_SYMBOL(qcom_scm_iommu_secure_ptbl_init);
-
-int qcom_scm_qsmmu500_wait_safe_toggle(bool en)
-{
- return __qcom_scm_qsmmu500_wait_safe_toggle(__scm->dev, en);
-}
-EXPORT_SYMBOL(qcom_scm_qsmmu500_wait_safe_toggle);
-
int qcom_scm_io_readl(phys_addr_t addr, unsigned int *val)
{
return __qcom_scm_io_readl(__scm->dev, addr, val);
@@ -361,68 +323,23 @@ int qcom_scm_io_writel(phys_addr_t addr, unsigned int val)
}
EXPORT_SYMBOL(qcom_scm_io_writel);

-static void qcom_scm_set_download_mode(bool enable)
-{
- bool avail;
- int ret = 0;
-
- avail = __qcom_scm_is_call_available(__scm->dev,
- QCOM_SCM_SVC_BOOT,
- QCOM_SCM_BOOT_SET_DLOAD_MODE);
- if (avail) {
- ret = __qcom_scm_set_dload_mode(__scm->dev, enable);
- } else if (__scm->dload_mode_addr) {
- ret = __qcom_scm_io_writel(__scm->dev, __scm->dload_mode_addr,
- enable ? QCOM_SCM_BOOT_SET_DLOAD_MODE : 0);
- } else {
- dev_err(__scm->dev,
- "No available mechanism for setting download mode\n");
- }
-
- if (ret)
- dev_err(__scm->dev, "failed to set download mode: %d\n", ret);
-}
-
-static int qcom_scm_find_dload_address(struct device *dev, u64 *addr)
+int qcom_scm_restore_sec_cfg(u32 device_id, u32 spare)
{
- struct device_node *tcsr;
- struct device_node *np = dev->of_node;
- struct resource res;
- u32 offset;
- int ret;
-
- tcsr = of_parse_phandle(np, "qcom,dload-mode", 0);
- if (!tcsr)
- return 0;
-
- ret = of_address_to_resource(tcsr, 0, &res);
- of_node_put(tcsr);
- if (ret)
- return ret;
-
- ret = of_property_read_u32_index(np, "qcom,dload-mode", 1, &offset);
- if (ret < 0)
- return ret;
-
- *addr = res.start + offset;
-
- return 0;
+ return __qcom_scm_restore_sec_cfg(__scm->dev, device_id, spare);
}
+EXPORT_SYMBOL(qcom_scm_restore_sec_cfg);

-/**
- * qcom_scm_is_available() - Checks if SCM is available
- */
-bool qcom_scm_is_available(void)
+int qcom_scm_iommu_secure_ptbl_size(u32 spare, size_t *size)
{
- return !!__scm;
+ return __qcom_scm_iommu_secure_ptbl_size(__scm->dev, spare, size);
}
-EXPORT_SYMBOL(qcom_scm_is_available);
+EXPORT_SYMBOL(qcom_scm_iommu_secure_ptbl_size);

-int qcom_scm_set_remote_state(u32 state, u32 id)
+int qcom_scm_iommu_secure_ptbl_init(u64 addr, u32 size, u32 spare)
{
- return __qcom_scm_set_remote_state(__scm->dev, state, id);
+ return __qcom_scm_iommu_secure_ptbl_init(__scm->dev, addr, size, spare);
}
-EXPORT_SYMBOL(qcom_scm_set_remote_state);
+EXPORT_SYMBOL(qcom_scm_iommu_secure_ptbl_init);

/**
* qcom_scm_assign_mem() - Make a secure call to reassign memory ownership
@@ -506,6 +423,89 @@ int qcom_scm_assign_mem(phys_addr_t mem_addr, size_t mem_sz,
}
EXPORT_SYMBOL(qcom_scm_assign_mem);

+/**
+ * qcom_scm_hdcp_available() - Check if secure environment supports HDCP.
+ *
+ * Return true if HDCP is supported, false if not.
+ */
+bool qcom_scm_hdcp_available(void)
+{
+ int ret = qcom_scm_clk_enable();
+
+ if (ret)
+ return ret;
+
+ ret = __qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_HDCP,
+ QCOM_SCM_HDCP_INVOKE);
+
+ qcom_scm_clk_disable();
+
+ return ret > 0 ? true : false;
+}
+EXPORT_SYMBOL(qcom_scm_hdcp_available);
+
+/**
+ * qcom_scm_hdcp_req() - Send HDCP request.
+ * @req: HDCP request array
+ * @req_cnt: HDCP request array count
+ * @resp: response buffer passed to SCM
+ *
+ * Write HDCP register(s) through SCM.
+ */
+int qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt, u32 *resp)
+{
+ int ret = qcom_scm_clk_enable();
+
+ if (ret)
+ return ret;
+
+ ret = __qcom_scm_hdcp_req(__scm->dev, req, req_cnt, resp);
+ qcom_scm_clk_disable();
+ return ret;
+}
+EXPORT_SYMBOL(qcom_scm_hdcp_req);
+
+int qcom_scm_qsmmu500_wait_safe_toggle(bool en)
+{
+ return __qcom_scm_qsmmu500_wait_safe_toggle(__scm->dev, en);
+}
+EXPORT_SYMBOL(qcom_scm_qsmmu500_wait_safe_toggle);
+
+/**
+ * qcom_scm_is_available() - Checks if SCM is available
+ */
+bool qcom_scm_is_available(void)
+{
+ return !!__scm;
+}
+EXPORT_SYMBOL(qcom_scm_is_available);
+
+static int qcom_scm_find_dload_address(struct device *dev, u64 *addr)
+{
+ struct device_node *tcsr;
+ struct device_node *np = dev->of_node;
+ struct resource res;
+ u32 offset;
+ int ret;
+
+ tcsr = of_parse_phandle(np, "qcom,dload-mode", 0);
+ if (!tcsr)
+ return 0;
+
+ ret = of_address_to_resource(tcsr, 0, &res);
+ of_node_put(tcsr);
+ if (ret)
+ return ret;
+
+ ret = of_property_read_u32_index(np, "qcom,dload-mode", 1, &offset);
+ if (ret < 0)
+ return ret;
+
+ *addr = res.start + offset;
+
+ return 0;
+}
+
static int qcom_scm_probe(struct platform_device *pdev)
{
struct qcom_scm *scm;
diff --git a/drivers/firmware/qcom_scm.h b/drivers/firmware/qcom_scm.h
index 99e91ba..4be482f 100644
--- a/drivers/firmware/qcom_scm.h
+++ b/drivers/firmware/qcom_scm.h
@@ -4,54 +4,74 @@
#ifndef __QCOM_SCM_INT_H
#define __QCOM_SCM_INT_H

-#define QCOM_SCM_SVC_BOOT 0x1
-#define QCOM_SCM_BOOT_SET_ADDR 0x1
+#define QCOM_SCM_SVC_BOOT 0x01
+#define QCOM_SCM_BOOT_SET_ADDR 0x01
+#define QCOM_SCM_BOOT_TERMINATE_PC 0x02
+#define QCOM_SCM_BOOT_SET_REMOTE_STATE 0x0a
#define QCOM_SCM_BOOT_SET_DLOAD_MODE 0x10
-#define QCOM_SCM_BOOT_SET_REMOTE_STATE 0xa
-extern int __qcom_scm_set_remote_state(struct device *dev, u32 state, u32 id);
-extern int __qcom_scm_set_dload_mode(struct device *dev, bool enable);
-
+extern int __qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus);
extern int __qcom_scm_set_warm_boot_addr(struct device *dev, void *entry,
const cpumask_t *cpus);
-extern int __qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus);
-
-#define QCOM_SCM_BOOT_TERMINATE_PC 0x2
-#define QCOM_SCM_FLUSH_FLAG_MASK 0x3
extern void __qcom_scm_cpu_power_down(u32 flags);
+extern int __qcom_scm_set_remote_state(struct device *dev, u32 state, u32 id);
+extern int __qcom_scm_set_dload_mode(struct device *dev, bool enable);
+#define QCOM_SCM_FLUSH_FLAG_MASK 0x3
+
+#define QCOM_SCM_SVC_PIL 0x02
+#define QCOM_SCM_PIL_PAS_INIT_IMAGE 0x01
+#define QCOM_SCM_PIL_PAS_MEM_SETUP 0x02
+#define QCOM_SCM_PIL_PAS_AUTH_AND_RESET 0x05
+#define QCOM_SCM_PIL_PAS_SHUTDOWN 0x06
+#define QCOM_SCM_PIL_PAS_IS_SUPPORTED 0x07
+#define QCOM_SCM_PIL_PAS_MSS_RESET 0x0a
+extern bool __qcom_scm_pas_supported(struct device *dev, u32 peripheral);
+extern int __qcom_scm_pas_init_image(struct device *dev, u32 peripheral,
+ dma_addr_t metadata_phys);
+extern int __qcom_scm_pas_mem_setup(struct device *dev, u32 peripheral,
+ phys_addr_t addr, phys_addr_t size);
+extern int __qcom_scm_pas_auth_and_reset(struct device *dev, u32 peripheral);
+extern int __qcom_scm_pas_shutdown(struct device *dev, u32 peripheral);
+extern int __qcom_scm_pas_mss_reset(struct device *dev, bool reset);

-#define QCOM_SCM_SVC_IO 0x5
-#define QCOM_SCM_IO_READ 0x1
-#define QCOM_SCM_IO_WRITE 0x2
+#define QCOM_SCM_SVC_IO 0x05
+#define QCOM_SCM_IO_READ 0x01
+#define QCOM_SCM_IO_WRITE 0x02
extern int __qcom_scm_io_readl(struct device *dev, phys_addr_t addr, unsigned int *val);
extern int __qcom_scm_io_writel(struct device *dev, phys_addr_t addr, unsigned int val);

-#define QCOM_SCM_SVC_INFO 0x6
-#define QCOM_SCM_INFO_IS_CALL_AVAIL 0x1
+#define QCOM_SCM_SVC_INFO 0x06
+#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_HDCP 0x11
-#define QCOM_SCM_HDCP_INVOKE 0x01
+#define QCOM_SCM_SVC_MP 0x0c
+#define QCOM_SCM_MP_RESTORE_SEC_CFG 0x02
+#define QCOM_SCM_MP_IOMMU_SECURE_PTBL_SIZE 0x03
+#define QCOM_SCM_MP_IOMMU_SECURE_PTBL_INIT 0x04
+#define QCOM_SCM_MP_ASSIGN 0x16
+extern int __qcom_scm_restore_sec_cfg(struct device *dev, u32 device_id,
+ u32 spare);
+extern int __qcom_scm_iommu_secure_ptbl_size(struct device *dev, u32 spare,
+ size_t *size);
+extern int __qcom_scm_iommu_secure_ptbl_init(struct device *dev, u64 addr,
+ u32 size, u32 spare);
+extern int __qcom_scm_assign_mem(struct device *dev,
+ phys_addr_t mem_region, size_t mem_sz,
+ phys_addr_t src, size_t src_sz,
+ phys_addr_t dest, size_t dest_sz);
+
+#define QCOM_SCM_SVC_HDCP 0x11
+#define QCOM_SCM_HDCP_INVOKE 0x01
extern int __qcom_scm_hdcp_req(struct device *dev,
struct qcom_scm_hdcp_req *req, u32 req_cnt, u32 *resp);

-extern void __qcom_scm_init(void);
+#define QCOM_SCM_SVC_SMMU_PROGRAM 0x15
+#define QCOM_SCM_SMMU_CONFIG_ERRATA1 0x3
+extern int __qcom_scm_qsmmu500_wait_safe_toggle(struct device *dev,
+ bool enable);
+#define QCOM_SCM_SMMU_CONFIG_ERRATA1_CLIENT_ALL 0x2

-#define QCOM_SCM_SVC_PIL 0x2
-#define QCOM_SCM_PIL_PAS_INIT_IMAGE 0x1
-#define QCOM_SCM_PIL_PAS_MEM_SETUP 0x2
-#define QCOM_SCM_PIL_PAS_AUTH_AND_RESET 0x5
-#define QCOM_SCM_PIL_PAS_SHUTDOWN 0x6
-#define QCOM_SCM_PIL_PAS_IS_SUPPORTED 0x7
-#define QCOM_SCM_PIL_PAS_MSS_RESET 0xa
-extern bool __qcom_scm_pas_supported(struct device *dev, u32 peripheral);
-extern int __qcom_scm_pas_init_image(struct device *dev, u32 peripheral,
- dma_addr_t metadata_phys);
-extern int __qcom_scm_pas_mem_setup(struct device *dev, u32 peripheral,
- phys_addr_t addr, phys_addr_t size);
-extern int __qcom_scm_pas_auth_and_reset(struct device *dev, u32 peripheral);
-extern int __qcom_scm_pas_shutdown(struct device *dev, u32 peripheral);
-extern int __qcom_scm_pas_mss_reset(struct device *dev, bool reset);
+extern void __qcom_scm_init(void);

/* common error codes */
#define QCOM_SCM_V2_EBUSY -12
@@ -80,25 +100,4 @@ static inline int qcom_scm_remap_error(int err)
return -EINVAL;
}

-#define QCOM_SCM_SVC_MP 0xc
-#define QCOM_SCM_MP_RESTORE_SEC_CFG 2
-extern int __qcom_scm_restore_sec_cfg(struct device *dev, u32 device_id,
- u32 spare);
-#define QCOM_SCM_MP_IOMMU_SECURE_PTBL_SIZE 3
-#define QCOM_SCM_MP_IOMMU_SECURE_PTBL_INIT 4
-#define QCOM_SCM_SVC_SMMU_PROGRAM 0x15
-#define QCOM_SCM_SMMU_CONFIG_ERRATA1 0x3
-#define QCOM_SCM_SMMU_CONFIG_ERRATA1_CLIENT_ALL 0x2
-extern int __qcom_scm_iommu_secure_ptbl_size(struct device *dev, u32 spare,
- size_t *size);
-extern int __qcom_scm_iommu_secure_ptbl_init(struct device *dev, u64 addr,
- u32 size, u32 spare);
-extern int __qcom_scm_qsmmu500_wait_safe_toggle(struct device *dev,
- bool enable);
-#define QCOM_SCM_MP_ASSIGN 0x16
-extern int __qcom_scm_assign_mem(struct device *dev,
- phys_addr_t mem_region, size_t mem_sz,
- phys_addr_t src, size_t src_sz,
- phys_addr_t dest, size_t dest_sz);
-
#endif
diff --git a/include/linux/qcom_scm.h b/include/linux/qcom_scm.h
index ffd72b3..f8b6525 100644
--- a/include/linux/qcom_scm.h
+++ b/include/linux/qcom_scm.h
@@ -37,10 +37,8 @@ struct qcom_scm_vmperm {
#if IS_ENABLED(CONFIG_QCOM_SCM)
extern int qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus);
extern int qcom_scm_set_warm_boot_addr(void *entry, const cpumask_t *cpus);
-extern bool qcom_scm_is_available(void);
-extern bool qcom_scm_hdcp_available(void);
-extern int qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt,
- u32 *resp);
+extern void qcom_scm_cpu_power_down(u32 flags);
+extern int qcom_scm_set_remote_state(u32 state, u32 id);
extern bool qcom_scm_pas_supported(u32 peripheral);
extern int qcom_scm_pas_init_image(u32 peripheral, const void *metadata,
size_t size);
@@ -48,58 +46,62 @@ extern int qcom_scm_pas_mem_setup(u32 peripheral, phys_addr_t addr,
phys_addr_t size);
extern int qcom_scm_pas_auth_and_reset(u32 peripheral);
extern int qcom_scm_pas_shutdown(u32 peripheral);
-extern int qcom_scm_assign_mem(phys_addr_t mem_addr, size_t mem_sz,
- unsigned int *src,
- const struct qcom_scm_vmperm *newvm,
- unsigned int dest_cnt);
-extern void qcom_scm_cpu_power_down(u32 flags);
-extern u32 qcom_scm_get_version(void);
-extern int qcom_scm_set_remote_state(u32 state, u32 id);
+extern int qcom_scm_io_readl(phys_addr_t addr, unsigned int *val);
+extern int qcom_scm_io_writel(phys_addr_t addr, unsigned int val);
extern int qcom_scm_restore_sec_cfg(u32 device_id, u32 spare);
extern int qcom_scm_iommu_secure_ptbl_size(u32 spare, size_t *size);
extern int qcom_scm_iommu_secure_ptbl_init(u64 addr, u32 size, u32 spare);
+extern int qcom_scm_assign_mem(phys_addr_t mem_addr, size_t mem_sz,
+ unsigned int *src,
+ const struct qcom_scm_vmperm *newvm,
+ int dest_cnt);
+extern bool qcom_scm_hdcp_available(void);
+extern int qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt,
+ u32 *resp);
extern int qcom_scm_qsmmu500_wait_safe_toggle(bool en);
-extern int qcom_scm_io_readl(phys_addr_t addr, unsigned int *val);
-extern int qcom_scm_io_writel(phys_addr_t addr, unsigned int val);
+extern u32 qcom_scm_get_version(void);
+extern bool qcom_scm_is_available(void);
#else

#include <linux/errno.h>

static inline
int qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus)
-{
- return -ENODEV;
-}
+ { return -ENODEV; }
static inline
int qcom_scm_set_warm_boot_addr(void *entry, const cpumask_t *cpus)
-{
- return -ENODEV;
-}
-static inline bool qcom_scm_is_available(void) { return false; }
-static inline bool qcom_scm_hdcp_available(void) { return false; }
-static inline int qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt,
- u32 *resp) { return -ENODEV; }
+ { return -ENODEV; }
+static inline void qcom_scm_cpu_power_down(u32 flags) {}
+static inline u32 qcom_scm_set_remote_state(u32 state, u32 id)
+ { return -ENODEV; }
static inline bool qcom_scm_pas_supported(u32 peripheral) { return false; }
static inline int qcom_scm_pas_init_image(u32 peripheral, const void *metadata,
size_t size) { return -ENODEV; }
static inline int qcom_scm_pas_mem_setup(u32 peripheral, phys_addr_t addr,
phys_addr_t size) { return -ENODEV; }
-static inline int
-qcom_scm_pas_auth_and_reset(u32 peripheral) { return -ENODEV; }
+static inline int qcom_scm_pas_auth_and_reset(u32 peripheral)
+ { return -ENODEV; }
static inline int qcom_scm_pas_shutdown(u32 peripheral) { return -ENODEV; }
+static inline int qcom_scm_io_readl(phys_addr_t addr, unsigned int *val)
+ { return -ENODEV; }
+static inline int qcom_scm_io_writel(phys_addr_t addr, unsigned int val)
+ { return -ENODEV; }
+static inline int qcom_scm_restore_sec_cfg(u32 device_id, u32 spare)
+ { return -ENODEV; }
+static inline int qcom_scm_iommu_secure_ptbl_size(u32 spare, size_t *size)
+ { return -ENODEV; }
+static inline int qcom_scm_iommu_secure_ptbl_init(u64 addr, u32 size, u32 spare)
+ { return -ENODEV; }
static inline int qcom_scm_assign_mem(phys_addr_t mem_addr, size_t mem_sz,
unsigned int *src,
const struct qcom_scm_vmperm *newvm,
- unsigned int dest_cnt) { return -ENODEV; }
-static inline void qcom_scm_cpu_power_down(u32 flags) {}
+ int dest_cnt) { return -ENODEV; }
+static inline bool qcom_scm_hdcp_available(void) { return false; }
+static inline int qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt,
+ u32 *resp) { return -ENODEV; }
+static inline int qcom_scm_qsmmu500_wait_safe_toggle(bool en)
+ { return -ENODEV; }
static inline u32 qcom_scm_get_version(void) { return 0; }
-static inline u32
-qcom_scm_set_remote_state(u32 state,u32 id) { return -ENODEV; }
-static inline int qcom_scm_restore_sec_cfg(u32 device_id, u32 spare) { return -ENODEV; }
-static inline int qcom_scm_iommu_secure_ptbl_size(u32 spare, size_t *size) { return -ENODEV; }
-static inline int qcom_scm_iommu_secure_ptbl_init(u64 addr, u32 size, u32 spare) { return -ENODEV; }
-static inline int qcom_scm_qsmmu500_wait_safe_toggle(bool en) { return -ENODEV; }
-static inline int qcom_scm_io_readl(phys_addr_t addr, unsigned int *val) { return -ENODEV; }
-static inline int qcom_scm_io_writel(phys_addr_t addr, unsigned int val) { return -ENODEV; }
+static inline bool qcom_scm_is_available(void) { return false; }
#endif
#endif
--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project

2019-11-05 01:29:20

by Elliot Berman

[permalink] [raw]
Subject: [PATCH 09/17] firmware: qcom_scm-64: Improve SMC convention detection

- Use enum to describe SMC convention.
- Improve SMC convention detection to use __qcom_scm_is_call_available
instead of circumventing qcom_scm_call_smccc.
- Improve SMC convention detection to check that SMCCC-32 works, instead
of just assuming it does of SMCCC-64 does not.

Signed-off-by: Elliot Berman <[email protected]>
---
drivers/firmware/qcom_scm-64.c | 42 ++++++++++++++++++++++++------------------
1 file changed, 24 insertions(+), 18 deletions(-)

diff --git a/drivers/firmware/qcom_scm-64.c b/drivers/firmware/qcom_scm-64.c
index f79b0dc..2579246 100644
--- a/drivers/firmware/qcom_scm-64.c
+++ b/drivers/firmware/qcom_scm-64.c
@@ -58,7 +58,13 @@ struct arm_smccc_args {
unsigned long a[8];
};

-static u64 qcom_smccc_convention = -1;
+enum qcom_smc_convention {
+ SMC_CONVENTION_UNKNOWN,
+ SMC_CONVENTION_ARM_32,
+ SMC_CONVENTION_ARM_64,
+};
+
+static enum qcom_smc_convention qcom_smc_convention = SMC_CONVENTION_UNKNOWN;
static DEFINE_MUTEX(qcom_scm_lock);

#define QCOM_SCM_EBUSY_WAIT_MS 30
@@ -103,7 +109,9 @@ static int ___qcom_scm_call_smccc(struct device *dev,

smc.a[0] = ARM_SMCCC_CALL_VAL(
atomic ? ARM_SMCCC_FAST_CALL : ARM_SMCCC_STD_CALL,
- qcom_smccc_convention,
+ (qcom_smc_convention == SMC_CONVENTION_ARM_64) ?
+ ARM_SMCCC_SMC_64 :
+ ARM_SMCCC_SMC_32,
desc->owner,
SMCCC_FUNCNUM(desc->svc, desc->cmd));
smc.a[1] = desc->arginfo;
@@ -117,7 +125,7 @@ static int ___qcom_scm_call_smccc(struct device *dev,
if (!args_virt)
return -ENOMEM;

- if (qcom_smccc_convention == ARM_SMCCC_SMC_32) {
+ if (qcom_smc_convention == SMC_CONVENTION_ARM_32) {
__le32 *args = args_virt;

for (i = 0; i < SMCCC_N_EXT_ARGS; i++)
@@ -583,19 +591,17 @@ int __qcom_scm_qsmmu500_wait_safe_toggle(struct device *dev, bool en)

void __qcom_scm_init(void)
{
- u64 cmd;
- struct arm_smccc_res res;
- u32 function = SMCCC_FUNCNUM(QCOM_SCM_SVC_INFO, QCOM_SCM_INFO_IS_CALL_AVAIL);
-
- /* First try a SMC64 call */
- cmd = ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, ARM_SMCCC_SMC_64,
- ARM_SMCCC_OWNER_SIP, function);
-
- arm_smccc_smc(cmd, QCOM_SCM_ARGS(1), cmd & (~BIT(ARM_SMCCC_TYPE_SHIFT)),
- 0, 0, 0, 0, 0, &res);
-
- if (!res.a0 && res.a1)
- qcom_smccc_convention = ARM_SMCCC_SMC_64;
- else
- qcom_smccc_convention = ARM_SMCCC_SMC_32;
+ qcom_smc_convention = SMC_CONVENTION_ARM_64;
+ if (__qcom_scm_is_call_available(NULL, QCOM_SCM_SVC_INFO,
+ QCOM_SCM_INFO_IS_CALL_AVAIL) == 1)
+ goto out;
+
+ qcom_smc_convention = SMC_CONVENTION_ARM_32;
+ if (__qcom_scm_is_call_available(NULL, QCOM_SCM_SVC_INFO,
+ QCOM_SCM_INFO_IS_CALL_AVAIL) == 1)
+ goto out;
+
+ qcom_smc_convention = SMC_CONVENTION_UNKNOWN;
+out:
+ pr_debug("QCOM SCM SMC Convention: %d\n", qcom_smc_convention);
}
--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project

2019-11-05 01:29:31

by Elliot Berman

[permalink] [raw]
Subject: [PATCH 16/17] firmware: qcom_scm: Enable legacy calling convention in qcom_scm-64.c

Enable legacy calling convention in qcom_scm-64. Update
is_call_available to use legacy function numbers when using legacy
convention.

Signed-off-by: Elliot Berman <[email protected]>
---
drivers/firmware/qcom_scm-64.c | 43 ++++++++++++++++++++++++++++++++++++++----
1 file changed, 39 insertions(+), 4 deletions(-)

diff --git a/drivers/firmware/qcom_scm-64.c b/drivers/firmware/qcom_scm-64.c
index 7bb68f2..355d9d7 100644
--- a/drivers/firmware/qcom_scm-64.c
+++ b/drivers/firmware/qcom_scm-64.c
@@ -60,6 +60,7 @@ struct arm_smccc_args {

enum qcom_smc_convention {
SMC_CONVENTION_UNKNOWN,
+ SMC_CONVENTION_LEGACY,
SMC_CONVENTION_ARM_32,
SMC_CONVENTION_ARM_64,
};
@@ -415,7 +416,16 @@ static int qcom_scm_call_atomic_legacy(struct device *dev,
static int qcom_scm_call(struct device *dev, struct qcom_scm_desc *desc)
{
might_sleep();
- return qcom_scm_call_smccc(dev, desc, false);
+ switch (qcom_smc_convention) {
+ case SMC_CONVENTION_ARM_32:
+ case SMC_CONVENTION_ARM_64:
+ return qcom_scm_call_smccc(dev, desc, false);
+ case SMC_CONVENTION_LEGACY:
+ return qcom_scm_call_legacy(dev, desc);
+ default:
+ pr_err("Unknown current SCM calling convention.\n");
+ return -EINVAL;
+ }
}

/**
@@ -431,7 +441,16 @@ static int qcom_scm_call(struct device *dev, struct qcom_scm_desc *desc)
*/
static int qcom_scm_call_atomic(struct device *dev, struct qcom_scm_desc *desc)
{
- return qcom_scm_call_smccc(dev, desc, true);
+ switch (qcom_smc_convention) {
+ case SMC_CONVENTION_ARM_32:
+ case SMC_CONVENTION_ARM_64:
+ return qcom_scm_call_smccc(dev, desc, true);
+ case SMC_CONVENTION_LEGACY:
+ return qcom_scm_call_atomic_legacy(dev, desc);
+ default:
+ pr_err("Unknown current SCM calling convention.\n");
+ return -EINVAL;
+ }
}

#define QCOM_SCM_FLAG_COLDBOOT_CPU0 0x00
@@ -750,8 +769,19 @@ int __qcom_scm_is_call_available(struct device *dev, u32 svc_id, u32 cmd_id)
};

desc.arginfo = QCOM_SCM_ARGS(1);
- desc.args[0] = SMCCC_FUNCNUM(svc_id, cmd_id) |
- (ARM_SMCCC_OWNER_SIP << ARM_SMCCC_OWNER_SHIFT);
+ switch (qcom_smc_convention) {
+ case SMC_CONVENTION_ARM_32:
+ case SMC_CONVENTION_ARM_64:
+ desc.args[0] = SMCCC_FUNCNUM(svc_id, cmd_id) |
+ (ARM_SMCCC_OWNER_SIP << ARM_SMCCC_OWNER_SHIFT);
+ break;
+ case SMC_CONVENTION_LEGACY:
+ desc.args[0] = LEGACY_FUNCNUM(svc_id, cmd_id);
+ break;
+ default:
+ pr_err("Unknown SMC convention being used\n");
+ return -EINVAL;
+ }

ret = qcom_scm_call(dev, &desc);

@@ -898,6 +928,11 @@ int __qcom_scm_qsmmu500_wait_safe_toggle(struct device *dev, bool en)

void __qcom_scm_init(void)
{
+ qcom_smc_convention = SMC_CONVENTION_LEGACY;
+ if (__qcom_scm_is_call_available(NULL, QCOM_SCM_SVC_INFO,
+ QCOM_SCM_INFO_IS_CALL_AVAIL) == 1)
+ goto out;
+
qcom_smc_convention = SMC_CONVENTION_ARM_64;
if (__qcom_scm_is_call_available(NULL, QCOM_SCM_SVC_INFO,
QCOM_SCM_INFO_IS_CALL_AVAIL) == 1)
--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project

2019-11-05 01:29:33

by Elliot Berman

[permalink] [raw]
Subject: [PATCH 11/17] firmware: qcom_scm-32: Use qcom_scm_desc in non-atomic calls

Use qcom_scm_desc in non-atomic calls to remove legacy convention
details from every SCM wrapper function.

Signed-off-by: Elliot Berman <[email protected]>
---
drivers/firmware/qcom_scm-32.c | 271 ++++++++++++++++++++++++++---------------
1 file changed, 170 insertions(+), 101 deletions(-)

diff --git a/drivers/firmware/qcom_scm-32.c b/drivers/firmware/qcom_scm-32.c
index e3dc9a7..33effed 100644
--- a/drivers/firmware/qcom_scm-32.c
+++ b/drivers/firmware/qcom_scm-32.c
@@ -39,6 +39,46 @@ static struct qcom_scm_entry qcom_scm_wb[] = {

static DEFINE_MUTEX(qcom_scm_lock);

+#define MAX_QCOM_SCM_ARGS 10
+#define MAX_QCOM_SCM_RETS 3
+
+enum qcom_scm_arg_types {
+ QCOM_SCM_VAL,
+ QCOM_SCM_RO,
+ QCOM_SCM_RW,
+ QCOM_SCM_BUFVAL,
+};
+
+#define QCOM_SCM_ARGS_IMPL(num, a, b, c, d, e, f, g, h, i, j, ...) (\
+ (((a) & 0x3) << 4) | \
+ (((b) & 0x3) << 6) | \
+ (((c) & 0x3) << 8) | \
+ (((d) & 0x3) << 10) | \
+ (((e) & 0x3) << 12) | \
+ (((f) & 0x3) << 14) | \
+ (((g) & 0x3) << 16) | \
+ (((h) & 0x3) << 18) | \
+ (((i) & 0x3) << 20) | \
+ (((j) & 0x3) << 22) | \
+ ((num) & 0xf))
+
+#define QCOM_SCM_ARGS(...) QCOM_SCM_ARGS_IMPL(__VA_ARGS__, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
+
+/**
+ * struct qcom_scm_desc
+ * @arginfo: Metadata describing the arguments in args[]
+ * @args: The array of arguments for the secure syscall
+ * @res: The values returned by the secure syscall
+ */
+struct qcom_scm_desc {
+ u32 svc;
+ u32 cmd;
+ u32 arginfo;
+ u64 args[MAX_QCOM_SCM_ARGS];
+ u64 res[MAX_QCOM_SCM_RETS];
+ u32 owner;
+};
+
#define LEGACY_FUNCNUM(s, c) (((s) << 10) | ((c) & 0x3ff))

/**
@@ -150,15 +190,19 @@ static u32 __qcom_scm_call_do(u32 cmd_addr)
* 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.
*/
-static int qcom_scm_call(struct device *dev, u32 svc_id, u32 cmd_id,
- const void *cmd_buf, size_t cmd_len, void *resp_buf,
- size_t resp_len)
+static int qcom_scm_call(struct device *dev, struct qcom_scm_desc *desc)
{
+ int arglen = desc->arginfo & 0xf;
int ret;
+ size_t i;
struct legacy_command *cmd;
struct legacy_response *rsp;
+ const size_t cmd_len = arglen * sizeof(__le32);
+ const size_t resp_len = MAX_QCOM_SCM_RETS * sizeof(__le32);
size_t alloc_len = sizeof(*cmd) + cmd_len + sizeof(*rsp) + resp_len;
dma_addr_t cmd_phys;
+ __le32 *arg_buf;
+ __le32 *res_buf;

cmd = kzalloc(PAGE_ALIGN(alloc_len), GFP_KERNEL);
if (!cmd)
@@ -167,10 +211,11 @@ static int qcom_scm_call(struct device *dev, u32 svc_id, u32 cmd_id,
cmd->len = cpu_to_le32(alloc_len);
cmd->buf_offset = cpu_to_le32(sizeof(*cmd));
cmd->resp_hdr_offset = cpu_to_le32(sizeof(*cmd) + cmd_len);
+ cmd->id = cpu_to_le32(LEGACY_FUNCNUM(desc->svc, desc->cmd));

- cmd->id = cpu_to_le32(LEGACY_FUNCNUM(svc_id, cmd_id));
- if (cmd_buf)
- memcpy(legacy_get_command_buffer(cmd), cmd_buf, cmd_len);
+ arg_buf = legacy_get_command_buffer(cmd);
+ for (i = 0; i < arglen; i++)
+ arg_buf[i] = cpu_to_le32(desc->args[i]);

rsp = legacy_command_to_response(cmd);

@@ -193,13 +238,13 @@ static int qcom_scm_call(struct device *dev, u32 svc_id, u32 cmd_id,
sizeof(*rsp), DMA_FROM_DEVICE);
} while (!rsp->is_complete);

- if (resp_buf) {
- dma_sync_single_for_cpu(dev, cmd_phys + sizeof(*cmd) + cmd_len +
- le32_to_cpu(rsp->buf_offset),
- resp_len, DMA_FROM_DEVICE);
- memcpy(resp_buf, legacy_get_response_buffer(rsp),
- resp_len);
- }
+ dma_sync_single_for_cpu(dev, cmd_phys + sizeof(*cmd) + cmd_len +
+ le32_to_cpu(rsp->buf_offset),
+ resp_len, DMA_FROM_DEVICE);
+
+ res_buf = legacy_get_response_buffer(rsp);
+ for (i = 0; i < MAX_QCOM_SCM_RETS; i++)
+ desc->res[i] = le32_to_cpu(res_buf[i]);
out:
dma_unmap_single(dev, cmd_phys, alloc_len, DMA_TO_DEVICE);
kfree(cmd);
@@ -301,10 +346,11 @@ int __qcom_scm_set_warm_boot_addr(struct device *dev, void *entry,
int ret;
int flags = 0;
int cpu;
- struct {
- __le32 flags;
- __le32 addr;
- } cmd;
+ struct qcom_scm_desc desc = {
+ .svc = QCOM_SCM_SVC_BOOT,
+ .cmd = QCOM_SCM_BOOT_SET_ADDR,
+ .arginfo = QCOM_SCM_ARGS(2),
+ };

/*
* Reassign only if we are switching from hotplug entry point
@@ -320,10 +366,9 @@ int __qcom_scm_set_warm_boot_addr(struct device *dev, void *entry,
if (!flags)
return 0;

- cmd.addr = cpu_to_le32(virt_to_phys(entry));
- cmd.flags = cpu_to_le32(flags);
- ret = qcom_scm_call(dev, QCOM_SCM_SVC_BOOT, QCOM_SCM_BOOT_SET_ADDR,
- &cmd, sizeof(cmd), NULL, 0);
+ desc.args[0] = flags;
+ desc.args[1] = virt_to_phys(entry);
+ ret = qcom_scm_call(dev, &desc);
if (!ret) {
for_each_cpu(cpu, cpus)
qcom_scm_wb[cpu].entry = entry;
@@ -348,20 +393,20 @@ void __qcom_scm_cpu_power_down(u32 flags)

int __qcom_scm_set_remote_state(struct device *dev, u32 state, u32 id)
{
- struct {
- __le32 state;
- __le32 id;
- } req;
- __le32 scm_ret = 0;
+ struct qcom_scm_desc desc = {
+ .svc = QCOM_SCM_SVC_BOOT,
+ .cmd = QCOM_SCM_BOOT_SET_REMOTE_STATE,
+ .owner = ARM_SMCCC_OWNER_SIP,
+ };
int ret;

- req.state = cpu_to_le32(state);
- req.id = cpu_to_le32(id);
+ desc.args[0] = state;
+ desc.args[1] = id;
+ desc.arginfo = QCOM_SCM_ARGS(2);

- ret = qcom_scm_call(dev, QCOM_SCM_SVC_BOOT, QCOM_SCM_BOOT_SET_REMOTE_STATE,
- &req, sizeof(req), &scm_ret, sizeof(scm_ret));
+ ret = qcom_scm_call(dev, &desc);

- return ret ? : le32_to_cpu(scm_ret);
+ return ret ? : desc.res[0];
}

int __qcom_scm_set_dload_mode(struct device *dev, bool enable)
@@ -372,104 +417,107 @@ int __qcom_scm_set_dload_mode(struct device *dev, bool enable)

bool __qcom_scm_pas_supported(struct device *dev, u32 peripheral)
{
- __le32 out;
- __le32 in;
int ret;
+ struct qcom_scm_desc desc = {
+ .svc = QCOM_SCM_SVC_PIL,
+ .cmd = QCOM_SCM_PIL_PAS_IS_SUPPORTED,
+ .owner = ARM_SMCCC_OWNER_SIP,
+ };

- in = cpu_to_le32(peripheral);
- ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL,
- QCOM_SCM_PIL_PAS_IS_SUPPORTED,
- &in, sizeof(in),
- &out, sizeof(out));
+ desc.args[0] = peripheral;
+ desc.arginfo = QCOM_SCM_ARGS(1);

- return ret ? false : !!out;
+ ret = qcom_scm_call(dev, &desc);
+
+ return ret ? false : !!desc.res[0];
}

int __qcom_scm_pas_init_image(struct device *dev, u32 peripheral,
dma_addr_t metadata_phys)
{
- __le32 scm_ret;
int ret;
- struct {
- __le32 proc;
- __le32 image_addr;
- } request;
+ struct qcom_scm_desc desc = {
+ .svc = QCOM_SCM_SVC_PIL,
+ .cmd = QCOM_SCM_PIL_PAS_INIT_IMAGE,
+ .owner = ARM_SMCCC_OWNER_SIP,
+ };

- request.proc = cpu_to_le32(peripheral);
- request.image_addr = cpu_to_le32(metadata_phys);
+ desc.args[0] = peripheral;
+ desc.args[1] = metadata_phys;
+ desc.arginfo = QCOM_SCM_ARGS(2, QCOM_SCM_VAL, QCOM_SCM_RW);

- ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL,
- QCOM_SCM_PIL_PAS_INIT_IMAGE,
- &request, sizeof(request),
- &scm_ret, sizeof(scm_ret));
+ ret = qcom_scm_call(dev, &desc);

- return ret ? : le32_to_cpu(scm_ret);
+ return ret ? : desc.res[0];
}

int __qcom_scm_pas_mem_setup(struct device *dev, u32 peripheral,
- phys_addr_t addr, phys_addr_t size)
+ phys_addr_t addr, phys_addr_t size)
{
- __le32 scm_ret;
int ret;
- struct {
- __le32 proc;
- __le32 addr;
- __le32 len;
- } request;
-
- request.proc = cpu_to_le32(peripheral);
- request.addr = cpu_to_le32(addr);
- request.len = cpu_to_le32(size);
-
- ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL,
- QCOM_SCM_PIL_PAS_MEM_SETUP,
- &request, sizeof(request),
- &scm_ret, sizeof(scm_ret));
-
- return ret ? : le32_to_cpu(scm_ret);
+ struct qcom_scm_desc desc = {
+ .svc = QCOM_SCM_SVC_PIL,
+ .cmd = QCOM_SCM_PIL_PAS_MEM_SETUP,
+ .owner = ARM_SMCCC_OWNER_SIP,
+ };
+
+ desc.args[0] = peripheral;
+ desc.args[1] = addr;
+ desc.args[2] = size;
+ desc.arginfo = QCOM_SCM_ARGS(3);
+
+ ret = qcom_scm_call(dev, &desc);
+
+ return ret ? : desc.res[0];
}

int __qcom_scm_pas_auth_and_reset(struct device *dev, u32 peripheral)
{
- __le32 out;
- __le32 in;
int ret;
+ struct qcom_scm_desc desc = {
+ .svc = QCOM_SCM_SVC_PIL,
+ .cmd = QCOM_SCM_PIL_PAS_AUTH_AND_RESET,
+ .owner = ARM_SMCCC_OWNER_SIP,
+ };

- in = cpu_to_le32(peripheral);
- ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL,
- QCOM_SCM_PIL_PAS_AUTH_AND_RESET,
- &in, sizeof(in),
- &out, sizeof(out));
+ ret = qcom_scm_call(dev, &desc);

- return ret ? : le32_to_cpu(out);
+ return ret ? : desc.res[0];
}

int __qcom_scm_pas_shutdown(struct device *dev, u32 peripheral)
{
- __le32 out;
- __le32 in;
+ struct qcom_scm_desc desc = {
+ .svc = QCOM_SCM_SVC_PIL,
+ .cmd = QCOM_SCM_PIL_PAS_SHUTDOWN,
+ .owner = ARM_SMCCC_OWNER_SIP,
+ };
int ret;

- in = cpu_to_le32(peripheral);
- ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL,
- QCOM_SCM_PIL_PAS_SHUTDOWN,
- &in, sizeof(in),
- &out, sizeof(out));
+ desc.args[0] = peripheral;
+ desc.arginfo = QCOM_SCM_ARGS(1);
+
+ ret = qcom_scm_call(dev, &desc);

- return ret ? : le32_to_cpu(out);
+ return ret ? : desc.res[0];
}

int __qcom_scm_pas_mss_reset(struct device *dev, bool reset)
{
- __le32 out;
- __le32 in = cpu_to_le32(reset);
+ struct qcom_scm_desc desc = {
+ .svc = QCOM_SCM_SVC_PIL,
+ .cmd = QCOM_SCM_PIL_PAS_MSS_RESET,
+ .owner = ARM_SMCCC_OWNER_SIP,
+ };
int ret;

- ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL, QCOM_SCM_PIL_PAS_MSS_RESET,
- &in, sizeof(in),
- &out, sizeof(out));
+ desc.args[0] = reset;
+ desc.args[1] = 0;
+ desc.arginfo = QCOM_SCM_ARGS(2);
+
+ ret = qcom_scm_call(dev, &desc);

- return ret ? : le32_to_cpu(out);
+ return ret ? : desc.res[0];
}

int __qcom_scm_io_readl(struct device *dev, phys_addr_t addr,
@@ -493,16 +541,16 @@ int __qcom_scm_io_writel(struct device *dev, phys_addr_t addr, unsigned int val)
int __qcom_scm_is_call_available(struct device *dev, u32 svc_id, u32 cmd_id)
{
int ret;
- __le32 svc_cmd = cpu_to_le32((svc_id << 10) | cmd_id);
- __le32 ret_val = 0;
+ struct qcom_scm_desc desc = {
+ .svc = QCOM_SCM_SVC_INFO,
+ .cmd = QCOM_SCM_INFO_IS_CALL_AVAIL,
+ .args[0] = (svc_id << 10) | cmd_id,
+ .arginfo = QCOM_SCM_ARGS(1),
+ };

- ret = qcom_scm_call(dev, QCOM_SCM_SVC_INFO, QCOM_SCM_INFO_IS_CALL_AVAIL,
- &svc_cmd, sizeof(svc_cmd), &ret_val,
- sizeof(ret_val));
- if (ret)
- return ret;
+ ret = qcom_scm_call(dev, &desc);

- return le32_to_cpu(ret_val);
+ return ret ? : desc.res[0];
}

int __qcom_scm_restore_sec_cfg(struct device *dev, u32 device_id,
@@ -533,11 +581,32 @@ int __qcom_scm_assign_mem(struct device *dev, phys_addr_t mem_region,
int __qcom_scm_hdcp_req(struct device *dev, struct qcom_scm_hdcp_req *req,
u32 req_cnt, u32 *resp)
{
+ int ret;
+ struct qcom_scm_desc desc = {
+ .svc = QCOM_SCM_SVC_HDCP,
+ .cmd = QCOM_SCM_HDCP_INVOKE,
+ .owner = ARM_SMCCC_OWNER_SIP,
+ };
+
if (req_cnt > QCOM_SCM_HDCP_MAX_REQ_CNT)
return -ERANGE;

- return qcom_scm_call(dev, QCOM_SCM_SVC_HDCP, QCOM_SCM_HDCP_INVOKE,
- req, req_cnt * sizeof(*req), resp, sizeof(*resp));
+ desc.args[0] = req[0].addr;
+ desc.args[1] = req[0].val;
+ desc.args[2] = req[1].addr;
+ desc.args[3] = req[1].val;
+ desc.args[4] = req[2].addr;
+ desc.args[5] = req[2].val;
+ desc.args[6] = req[3].addr;
+ desc.args[7] = req[3].val;
+ desc.args[8] = req[4].addr;
+ desc.args[9] = req[4].val;
+ desc.arginfo = QCOM_SCM_ARGS(req_cnt * 2);
+
+ ret = qcom_scm_call(dev, &desc);
+ *resp = desc.res[0];
+
+ return ret;
}

int __qcom_scm_qsmmu500_wait_safe_toggle(struct device *dev, bool enable)
--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project

2019-11-05 01:29:40

by Elliot Berman

[permalink] [raw]
Subject: [PATCH 12/17] firmware: qcom_scm-32: Move SMCCC register filling to qcom_scm_call

- Move SMCCC register filling to qcom_scm_call so that qcom_scm_call_do
only needs to concern itself with retry mechanism.
- Use arm_smccc_args struct in atomic variants as well.

Signed-off-by: Elliot Berman <[email protected]>
---
drivers/firmware/qcom_scm-32.c | 47 ++++++++++++++++++++++++++++--------------
1 file changed, 31 insertions(+), 16 deletions(-)

diff --git a/drivers/firmware/qcom_scm-32.c b/drivers/firmware/qcom_scm-32.c
index 33effed..9811560 100644
--- a/drivers/firmware/qcom_scm-32.c
+++ b/drivers/firmware/qcom_scm-32.c
@@ -78,6 +78,9 @@ struct qcom_scm_desc {
u64 res[MAX_QCOM_SCM_RETS];
u32 owner;
};
+struct arm_smccc_args {
+ unsigned long a[8];
+};

#define LEGACY_FUNCNUM(s, c) (((s) << 10) | ((c) & 0x3ff))

@@ -159,16 +162,13 @@ static inline void *legacy_get_response_buffer(const struct legacy_response *rsp
return (void *)rsp + le32_to_cpu(rsp->buf_offset);
}

-static u32 __qcom_scm_call_do(u32 cmd_addr)
+static void __qcom_scm_call_do(const struct arm_smccc_args *smc,
+ struct arm_smccc_res *res)
{
- int context_id;
- struct arm_smccc_res res;
do {
- arm_smccc_smc(1, (unsigned long)&context_id, cmd_addr,
- 0, 0, 0, 0, 0, &res);
- } while (res.a0 == QCOM_SCM_INTERRUPTED);
-
- return res.a0;
+ arm_smccc_smc(smc->a[0], smc->a[1], smc->a[2], smc->a[3],
+ smc->a[4], smc->a[5], smc->a[6], smc->a[7], res);
+ } while (res->a0 == QCOM_SCM_INTERRUPTED);
}

/**
@@ -193,10 +193,12 @@ static u32 __qcom_scm_call_do(u32 cmd_addr)
static int qcom_scm_call(struct device *dev, struct qcom_scm_desc *desc)
{
int arglen = desc->arginfo & 0xf;
- int ret;
+ int ret = 0, context_id;
size_t i;
struct legacy_command *cmd;
struct legacy_response *rsp;
+ struct arm_smccc_args smc = {0};
+ struct arm_smccc_res res;
const size_t cmd_len = arglen * sizeof(__le32);
const size_t resp_len = MAX_QCOM_SCM_RETS * sizeof(__le32);
size_t alloc_len = sizeof(*cmd) + cmd_len + sizeof(*rsp) + resp_len;
@@ -225,10 +227,14 @@ static int qcom_scm_call(struct device *dev, struct qcom_scm_desc *desc)
return -ENOMEM;
}

+ smc.a[0] = 1;
+ smc.a[1] = (unsigned long)&context_id;
+ smc.a[2] = cmd_phys;
+
mutex_lock(&qcom_scm_lock);
- ret = __qcom_scm_call_do(cmd_phys);
- if (ret < 0)
- ret = qcom_scm_remap_error(ret);
+ __qcom_scm_call_do(&smc, &res);
+ if (res.a0 < 0)
+ ret = qcom_scm_remap_error(res.a0);
mutex_unlock(&qcom_scm_lock);
if (ret)
goto out;
@@ -270,10 +276,14 @@ static int qcom_scm_call(struct device *dev, struct qcom_scm_desc *desc)
static s32 qcom_scm_call_atomic1(u32 svc, u32 cmd, u32 arg1)
{
int context_id;
+ struct arm_smccc_args smc = {0};
struct arm_smccc_res res;

- arm_smccc_smc(LEGACY_ATOMIC(svc, cmd, 1), (unsigned long)&context_id,
- arg1, 0, 0, 0, 0, 0, &res);
+ smc.a[0] = LEGACY_ATOMIC(svc, cmd, 1);
+ smc.a[1] = (unsigned long)&context_id;
+ smc.a[2] = arg1;
+ arm_smccc_smc(smc.a[0], smc.a[1], smc.a[2], smc.a[3],
+ smc.a[4], smc.a[5], smc.a[6], smc.a[7], &res);

return res.a0;
}
@@ -291,10 +301,15 @@ static s32 qcom_scm_call_atomic1(u32 svc, u32 cmd, u32 arg1)
static s32 qcom_scm_call_atomic2(u32 svc, u32 cmd, u32 arg1, u32 arg2)
{
int context_id;
+ struct arm_smccc_args smc = {0};
struct arm_smccc_res res;

- arm_smccc_smc(LEGACY_ATOMIC(svc, cmd, 2), (unsigned long)&context_id,
- arg1, arg2, 0, 0, 0, 0, &res);
+ smc.a[0] = LEGACY_ATOMIC(svc, cmd, 2);
+ smc.a[1] = (unsigned long)&context_id;
+ smc.a[2] = arg1;
+ smc.a[3] = arg2;
+ arm_smccc_smc(smc.a[0], smc.a[1], smc.a[2], smc.a[3],
+ smc.a[4], smc.a[5], smc.a[6], smc.a[7], &res);

return res.a0;
}
--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project

2019-11-05 01:29:51

by Elliot Berman

[permalink] [raw]
Subject: [PATCH 15/17] firmware: qcom_scm: Merge legacy and SMCCC conventions

Copy/paste legacy SCM driver into qcom_scm-64 with the following notes:
- Renamed qcom_scm_call in qcom_scm-32 to qcom_scm_call_legacy in the
copy.
- Renamed qcom_scm_call_atomic in qcom_scm 32 to
qcom_scm_call_atomic_legacy in the copy.
- Rename __qcom_scm_call_smccc to qcom_scm_call_smccc.
- Filled in implementations set_cold_boot_addr, set_warm_boot_addr, and
cpu_power_down from qcom_scm-32.c.
- set_dload_mode, io_writel, io_readl now use atomic variants as in
qcom_scm-32.

Signed-off-by: Elliot Berman <[email protected]>
---
drivers/firmware/qcom_scm-64.c | 322 ++++++++++++++++++++++++++++++++++++++++-
1 file changed, 314 insertions(+), 8 deletions(-)

diff --git a/drivers/firmware/qcom_scm-64.c b/drivers/firmware/qcom_scm-64.c
index d10845a..7bb68f2 100644
--- a/drivers/firmware/qcom_scm-64.c
+++ b/drivers/firmware/qcom_scm-64.c
@@ -95,7 +95,7 @@ static void __qcom_scm_call_do_quirk(const struct arm_smccc_args *smc,
} while (res->a0 == QCOM_SCM_INTERRUPTED);
}

-static int ___qcom_scm_call_smccc(struct device *dev,
+static int qcom_scm_call_smccc(struct device *dev,
struct qcom_scm_desc *desc, bool atomic)
{
int arglen = desc->arginfo & 0xf;
@@ -185,6 +185,223 @@ static int ___qcom_scm_call_smccc(struct device *dev,
return 0;
}

+#define LEGACY_FUNCNUM(s, c) (((s) << 10) | ((c) & 0x3ff))
+
+/**
+ * struct legacy_command - one SCM command buffer
+ * @len: total available memory for command and response
+ * @buf_offset: start of command buffer
+ * @resp_hdr_offset: start of response buffer
+ * @id: command to be executed
+ * @buf: buffer returned from legacy_get_command_buffer()
+ *
+ * An SCM command is laid out in memory as follows:
+ *
+ * ------------------- <--- struct legacy_command
+ * | command header |
+ * ------------------- <--- legacy_get_command_buffer()
+ * | command buffer |
+ * ------------------- <--- struct legacy_response and
+ * | response header | legacy_command_to_response()
+ * ------------------- <--- legacy_get_response_buffer()
+ * | response buffer |
+ * -------------------
+ *
+ * There can be arbitrary padding between the headers and buffers so
+ * you should always use the appropriate qcom_scm_get_*_buffer() routines
+ * to access the buffers in a safe manner.
+ */
+struct legacy_command {
+ __le32 len;
+ __le32 buf_offset;
+ __le32 resp_hdr_offset;
+ __le32 id;
+ __le32 buf[0];
+};
+
+/**
+ * struct legacy_response - one SCM response buffer
+ * @len: total available memory for response
+ * @buf_offset: start of response data relative to start of legacy_response
+ * @is_complete: indicates if the command has finished processing
+ */
+struct legacy_response {
+ __le32 len;
+ __le32 buf_offset;
+ __le32 is_complete;
+};
+
+/**
+ * legacy_command_to_response() - Get a pointer to a legacy_response
+ * @cmd: command
+ *
+ * Returns a pointer to a response for a command.
+ */
+static inline struct legacy_response *legacy_command_to_response(
+ const struct legacy_command *cmd)
+{
+ return (void *)cmd + le32_to_cpu(cmd->resp_hdr_offset);
+}
+
+/**
+ * legacy_get_command_buffer() - Get a pointer to a command buffer
+ * @cmd: command
+ *
+ * Returns a pointer to the command buffer of a command.
+ */
+static inline void *legacy_get_command_buffer(const struct legacy_command *cmd)
+{
+ return (void *)cmd->buf;
+}
+
+/**
+ * legacy_get_response_buffer() - Get a pointer to a response buffer
+ * @rsp: response
+ *
+ * Returns a pointer to a response buffer of a response.
+ */
+static inline void *legacy_get_response_buffer(const struct legacy_response *rsp)
+{
+ return (void *)rsp + le32_to_cpu(rsp->buf_offset);
+}
+
+static void __qcom_scm_call_do(const struct arm_smccc_args *smc,
+ struct arm_smccc_res *res)
+{
+ do {
+ arm_smccc_smc(smc->a[0], smc->a[1], smc->a[2], smc->a[3],
+ smc->a[4], smc->a[5], smc->a[6], smc->a[7], res);
+ } while (res->a0 == QCOM_SCM_INTERRUPTED);
+}
+
+/**
+ * qcom_scm_call_legacy() - Send an SCM command
+ * @dev: struct device
+ * @svc_id: service identifier
+ * @cmd_id: command identifier
+ * @cmd_buf: command buffer
+ * @cmd_len: length of the command buffer
+ * @resp_buf: response buffer
+ * @resp_len: length of the response buffer
+ *
+ * Sends a command to the SCM and waits for the command to finish processing.
+ *
+ * A note on cache maintenance:
+ * Note that any buffers that are expected to be accessed by the secure world
+ * must be flushed before invoking qcom_scm_call and invalidated in the cache
+ * immediately after qcom_scm_call returns. Cache maintenance on the command
+ * 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.
+ */
+static int qcom_scm_call_legacy(struct device *dev, struct qcom_scm_desc *desc)
+{
+ int arglen = desc->arginfo & 0xf;
+ int ret = 0, context_id;
+ size_t i;
+ struct legacy_command *cmd;
+ struct legacy_response *rsp;
+ struct arm_smccc_args smc = {0};
+ struct arm_smccc_res res;
+ const size_t cmd_len = arglen * sizeof(__le32);
+ const size_t resp_len = MAX_QCOM_SCM_RETS * sizeof(__le32);
+ size_t alloc_len = sizeof(*cmd) + cmd_len + sizeof(*rsp) + resp_len;
+ dma_addr_t cmd_phys;
+ __le32 *arg_buf;
+ __le32 *res_buf;
+
+ cmd = kzalloc(PAGE_ALIGN(alloc_len), GFP_KERNEL);
+ if (!cmd)
+ return -ENOMEM;
+
+ cmd->len = cpu_to_le32(alloc_len);
+ cmd->buf_offset = cpu_to_le32(sizeof(*cmd));
+ cmd->resp_hdr_offset = cpu_to_le32(sizeof(*cmd) + cmd_len);
+ cmd->id = cpu_to_le32(LEGACY_FUNCNUM(desc->svc, desc->cmd));
+
+ arg_buf = legacy_get_command_buffer(cmd);
+ for (i = 0; i < arglen; i++)
+ arg_buf[i] = cpu_to_le32(desc->args[i]);
+
+ rsp = legacy_command_to_response(cmd);
+
+ cmd_phys = dma_map_single(dev, cmd, alloc_len, DMA_TO_DEVICE);
+ if (dma_mapping_error(dev, cmd_phys)) {
+ kfree(cmd);
+ return -ENOMEM;
+ }
+
+ smc.a[0] = 1;
+ smc.a[1] = (unsigned long)&context_id;
+ smc.a[2] = cmd_phys;
+
+ mutex_lock(&qcom_scm_lock);
+ __qcom_scm_call_do(&smc, &res);
+ if (res.a0 < 0)
+ ret = qcom_scm_remap_error(res.a0);
+ mutex_unlock(&qcom_scm_lock);
+ if (ret)
+ goto out;
+
+ do {
+ dma_sync_single_for_cpu(dev, cmd_phys + sizeof(*cmd) + cmd_len,
+ sizeof(*rsp), DMA_FROM_DEVICE);
+ } while (!rsp->is_complete);
+
+ dma_sync_single_for_cpu(dev, cmd_phys + sizeof(*cmd) + cmd_len +
+ le32_to_cpu(rsp->buf_offset),
+ resp_len, DMA_FROM_DEVICE);
+
+ res_buf = legacy_get_response_buffer(rsp);
+ for (i = 0; i < MAX_QCOM_SCM_RETS; i++)
+ desc->res[i] = le32_to_cpu(res_buf[i]);
+out:
+ dma_unmap_single(dev, cmd_phys, alloc_len, DMA_TO_DEVICE);
+ kfree(cmd);
+ return ret;
+}
+
+#define LEGACY_ATOMIC_N_REG_ARGS 5
+#define LEGACY_ATOMIC_FIRST_REG_IDX 2
+#define LEGACY_CLASS_REGISTER (0x2 << 8)
+#define LEGACY_MASK_IRQS BIT(5)
+#define LEGACY_ATOMIC(svc, cmd, n) ((LEGACY_FUNCNUM(svc, cmd) << 12) | \
+ LEGACY_CLASS_REGISTER | \
+ LEGACY_MASK_IRQS | \
+ (n & 0xf))
+
+/**
+ * qcom_scm_call_atomic_legacy() - Send an atomic SCM command with up to
+ * 5 arguments and 3 return values
+ *
+ * This shall only be used with commands that are guaranteed to be
+ * uninterruptable, atomic and SMP safe.
+ */
+static int qcom_scm_call_atomic_legacy(struct device *dev,
+ struct qcom_scm_desc *desc)
+{
+ int context_id;
+ struct arm_smccc_args smc = {0};
+ struct arm_smccc_res res;
+ size_t i, arglen = desc->arginfo & 0xf;
+
+ BUG_ON(arglen > LEGACY_ATOMIC_N_REG_ARGS);
+
+ smc.a[0] = LEGACY_ATOMIC(desc->svc, desc->cmd, arglen);
+ smc.a[1] = (unsigned long)&context_id;
+
+ for (i = 0; i < arglen; i++)
+ smc.a[i + LEGACY_ATOMIC_FIRST_REG_IDX] = desc->args[i];
+
+ arm_smccc_smc(smc.a[0], smc.a[1], smc.a[2], smc.a[3],
+ smc.a[4], smc.a[5], smc.a[6], smc.a[7], &res);
+
+ desc->res[0] = res.a1;
+ desc->res[1] = res.a2;
+ desc->res[2] = res.a3;
+
+ return res.a0;
+}
+
/**
* qcom_scm_call() - Invoke a syscall in the secure world
* @dev: device
@@ -198,7 +415,7 @@ static int ___qcom_scm_call_smccc(struct device *dev,
static int qcom_scm_call(struct device *dev, struct qcom_scm_desc *desc)
{
might_sleep();
- return ___qcom_scm_call_smccc(dev, desc, false);
+ return qcom_scm_call_smccc(dev, desc, false);
}

/**
@@ -214,9 +431,14 @@ static int qcom_scm_call(struct device *dev, struct qcom_scm_desc *desc)
*/
static int qcom_scm_call_atomic(struct device *dev, struct qcom_scm_desc *desc)
{
- return ___qcom_scm_call_smccc(dev, desc, true);
+ return qcom_scm_call_smccc(dev, desc, true);
}

+#define QCOM_SCM_FLAG_COLDBOOT_CPU0 0x00
+#define QCOM_SCM_FLAG_COLDBOOT_CPU1 0x01
+#define QCOM_SCM_FLAG_COLDBOOT_CPU2 0x08
+#define QCOM_SCM_FLAG_COLDBOOT_CPU3 0x20
+
/**
* qcom_scm_set_cold_boot_addr() - Set the cold boot address for cpus
* @entry: Entry point function for the cpus
@@ -228,9 +450,54 @@ static int qcom_scm_call_atomic(struct device *dev, struct qcom_scm_desc *desc)
int __qcom_scm_set_cold_boot_addr(struct device *dev, void *entry,
const cpumask_t *cpus)
{
- return -ENOTSUPP;
+ int flags = 0;
+ int cpu;
+ int scm_cb_flags[] = {
+ QCOM_SCM_FLAG_COLDBOOT_CPU0,
+ QCOM_SCM_FLAG_COLDBOOT_CPU1,
+ QCOM_SCM_FLAG_COLDBOOT_CPU2,
+ QCOM_SCM_FLAG_COLDBOOT_CPU3,
+ };
+ struct qcom_scm_desc desc = {
+ .svc = QCOM_SCM_SVC_BOOT,
+ .cmd = QCOM_SCM_BOOT_SET_ADDR,
+ .owner = ARM_SMCCC_OWNER_SIP,
+ };
+
+ if (!cpus || (cpus && cpumask_empty(cpus)))
+ return -EINVAL;
+
+ for_each_cpu(cpu, cpus) {
+ if (cpu < ARRAY_SIZE(scm_cb_flags))
+ flags |= scm_cb_flags[cpu];
+ else
+ set_cpu_present(cpu, false);
+ }
+
+ desc.args[0] = flags;
+ desc.args[1] = virt_to_phys(entry);
+ desc.arginfo = QCOM_SCM_ARGS(2);
+
+ return qcom_scm_call_atomic(dev, &desc);
}

+#define QCOM_SCM_FLAG_WARMBOOT_CPU0 0x04
+#define QCOM_SCM_FLAG_WARMBOOT_CPU1 0x02
+#define QCOM_SCM_FLAG_WARMBOOT_CPU2 0x10
+#define QCOM_SCM_FLAG_WARMBOOT_CPU3 0x40
+
+struct qcom_scm_entry {
+ int flag;
+ void *entry;
+};
+
+static struct qcom_scm_entry qcom_scm_wb[] = {
+ { .flag = QCOM_SCM_FLAG_WARMBOOT_CPU0 },
+ { .flag = QCOM_SCM_FLAG_WARMBOOT_CPU1 },
+ { .flag = QCOM_SCM_FLAG_WARMBOOT_CPU2 },
+ { .flag = QCOM_SCM_FLAG_WARMBOOT_CPU3 },
+};
+
/**
* qcom_scm_set_warm_boot_addr() - Set the warm boot address for cpus
* @dev: Device pointer
@@ -243,7 +510,37 @@ int __qcom_scm_set_cold_boot_addr(struct device *dev, void *entry,
int __qcom_scm_set_warm_boot_addr(struct device *dev, void *entry,
const cpumask_t *cpus)
{
- return -ENOTSUPP;
+ int ret;
+ int flags = 0;
+ int cpu;
+ struct qcom_scm_desc desc = {
+ .svc = QCOM_SCM_SVC_BOOT,
+ .cmd = QCOM_SCM_BOOT_SET_ADDR,
+ };
+
+ /*
+ * Reassign only if we are switching from hotplug entry point
+ * to cpuidle entry point or vice versa.
+ */
+ for_each_cpu(cpu, cpus) {
+ if (entry == qcom_scm_wb[cpu].entry)
+ continue;
+ flags |= qcom_scm_wb[cpu].flag;
+ }
+
+ /* No change in entry function */
+ if (!flags)
+ return 0;
+
+ desc.args[0] = flags;
+ desc.args[1] = virt_to_phys(entry);
+ ret = qcom_scm_call(dev, &desc);
+ if (!ret) {
+ for_each_cpu(cpu, cpus)
+ qcom_scm_wb[cpu].entry = entry;
+ }
+
+ return ret;
}

/**
@@ -256,6 +553,15 @@ int __qcom_scm_set_warm_boot_addr(struct device *dev, void *entry,
*/
void __qcom_scm_cpu_power_down(struct device *dev, u32 flags)
{
+ struct qcom_scm_desc desc = {
+ .svc = QCOM_SCM_SVC_BOOT,
+ .cmd = QCOM_SCM_BOOT_TERMINATE_PC,
+ .args[0] = flags & QCOM_SCM_FLUSH_FLAG_MASK,
+ .arginfo = QCOM_SCM_ARGS(1),
+ .owner = ARM_SMCCC_OWNER_SIP,
+ };
+
+ qcom_scm_call_atomic(dev, &desc);
}

int __qcom_scm_set_remote_state(struct device *dev, u32 state, u32 id)
@@ -288,7 +594,7 @@ int __qcom_scm_set_dload_mode(struct device *dev, bool enable)
desc.args[1] = enable ? QCOM_SCM_BOOT_SET_DLOAD_MODE : 0;
desc.arginfo = QCOM_SCM_ARGS(2);

- return qcom_scm_call(dev, &desc);
+ return qcom_scm_call_atomic(dev, &desc);
}

bool __qcom_scm_pas_supported(struct device *dev, u32 peripheral)
@@ -412,7 +718,7 @@ int __qcom_scm_io_readl(struct device *dev, phys_addr_t addr,
desc.args[0] = addr;
desc.arginfo = QCOM_SCM_ARGS(1);

- ret = qcom_scm_call(dev, &desc);
+ ret = qcom_scm_call_atomic(dev, &desc);
if (ret >= 0)
*val = desc.res[0];

@@ -431,7 +737,7 @@ int __qcom_scm_io_writel(struct device *dev, phys_addr_t addr, unsigned int val)
desc.args[1] = val;
desc.arginfo = QCOM_SCM_ARGS(2);

- return qcom_scm_call(dev, &desc);
+ return qcom_scm_call_atomic(dev, &desc);
}

int __qcom_scm_is_call_available(struct device *dev, u32 svc_id, u32 cmd_id)
--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project

2019-11-05 01:29:53

by Elliot Berman

[permalink] [raw]
Subject: [PATCH 14/17] firmware: qcom_scm-32: Add device argument to atomic calls

Add this unused parameter to reduce merge friction between SMCCC and
legacy based conventions.

Signed-off-by: Elliot Berman <[email protected]>
---
drivers/firmware/qcom_scm-32.c | 17 +++++++++--------
drivers/firmware/qcom_scm-64.c | 5 +++--
drivers/firmware/qcom_scm.c | 5 +++--
drivers/firmware/qcom_scm.h | 5 +++--
4 files changed, 18 insertions(+), 14 deletions(-)

diff --git a/drivers/firmware/qcom_scm-32.c b/drivers/firmware/qcom_scm-32.c
index 533c68a..3325c21 100644
--- a/drivers/firmware/qcom_scm-32.c
+++ b/drivers/firmware/qcom_scm-32.c
@@ -273,7 +273,7 @@ static int qcom_scm_call(struct device *dev, struct qcom_scm_desc *desc)
* This shall only be used with commands that are guaranteed to be
* uninterruptable, atomic and SMP safe.
*/
-static int qcom_scm_call_atomic(struct qcom_scm_desc *desc)
+static int qcom_scm_call_atomic(struct device *dev, struct qcom_scm_desc *desc)
{
int context_id;
struct arm_smccc_args smc = {0};
@@ -306,7 +306,8 @@ static int qcom_scm_call_atomic(struct qcom_scm_desc *desc)
* Set the cold boot address of the cpus. Any cpu outside the supported
* range would be removed from the cpu present mask.
*/
-int __qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus)
+int __qcom_scm_set_cold_boot_addr(struct device *dev, void *entry,
+ const cpumask_t *cpus)
{
int flags = 0;
int cpu;
@@ -336,7 +337,7 @@ int __qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus)
desc.args[1] = virt_to_phys(entry);
desc.arginfo = QCOM_SCM_ARGS(2);

- return qcom_scm_call_atomic(&desc);
+ return qcom_scm_call_atomic(dev, &desc);
}

/**
@@ -392,7 +393,7 @@ int __qcom_scm_set_warm_boot_addr(struct device *dev, void *entry,
* the control would return from this function, otherwise, the cpu jumps to the
* warm boot entry point set for this cpu upon reset.
*/
-void __qcom_scm_cpu_power_down(u32 flags)
+void __qcom_scm_cpu_power_down(struct device *dev, u32 flags)
{
struct qcom_scm_desc desc = {
.svc = QCOM_SCM_SVC_BOOT,
@@ -402,7 +403,7 @@ void __qcom_scm_cpu_power_down(u32 flags)
.owner = ARM_SMCCC_OWNER_SIP,
};

- qcom_scm_call_atomic(&desc);
+ qcom_scm_call_atomic(dev, &desc);
}

int __qcom_scm_set_remote_state(struct device *dev, u32 state, u32 id)
@@ -435,7 +436,7 @@ int __qcom_scm_set_dload_mode(struct device *dev, bool enable)
desc.args[1] = enable ? QCOM_SCM_BOOT_SET_DLOAD_MODE : 0;
desc.arginfo = QCOM_SCM_ARGS(2);

- return qcom_scm_call_atomic(&desc);
+ return qcom_scm_call_atomic(dev, &desc);
}

bool __qcom_scm_pas_supported(struct device *dev, u32 peripheral)
@@ -556,7 +557,7 @@ int __qcom_scm_io_readl(struct device *dev, phys_addr_t addr,
desc.args[0] = addr;
desc.arginfo = QCOM_SCM_ARGS(1);

- ret = qcom_scm_call_atomic(&desc);
+ ret = qcom_scm_call_atomic(dev, &desc);
if (ret >= 0)
*val = desc.res[0];

@@ -575,7 +576,7 @@ int __qcom_scm_io_writel(struct device *dev, phys_addr_t addr, unsigned int val)
desc.args[1] = val;
desc.arginfo = QCOM_SCM_ARGS(2);

- return qcom_scm_call_atomic(&desc);
+ return qcom_scm_call_atomic(dev, &desc);
}

int __qcom_scm_is_call_available(struct device *dev, u32 svc_id, u32 cmd_id)
diff --git a/drivers/firmware/qcom_scm-64.c b/drivers/firmware/qcom_scm-64.c
index 2579246..d10845a 100644
--- a/drivers/firmware/qcom_scm-64.c
+++ b/drivers/firmware/qcom_scm-64.c
@@ -225,7 +225,8 @@ static int qcom_scm_call_atomic(struct device *dev, struct qcom_scm_desc *desc)
* Set the cold boot address of the cpus. Any cpu outside the supported
* range would be removed from the cpu present mask.
*/
-int __qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus)
+int __qcom_scm_set_cold_boot_addr(struct device *dev, void *entry,
+ const cpumask_t *cpus)
{
return -ENOTSUPP;
}
@@ -253,7 +254,7 @@ int __qcom_scm_set_warm_boot_addr(struct device *dev, void *entry,
* the control would return from this function, otherwise, the cpu jumps to the
* warm boot entry point set for this cpu upon reset.
*/
-void __qcom_scm_cpu_power_down(u32 flags)
+void __qcom_scm_cpu_power_down(struct device *dev, u32 flags)
{
}

diff --git a/drivers/firmware/qcom_scm.c b/drivers/firmware/qcom_scm.c
index 83fc049..ffad61b 100644
--- a/drivers/firmware/qcom_scm.c
+++ b/drivers/firmware/qcom_scm.c
@@ -95,7 +95,8 @@ static void qcom_scm_clk_disable(void)
*/
int qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus)
{
- return __qcom_scm_set_cold_boot_addr(entry, cpus);
+ return __qcom_scm_set_cold_boot_addr(__scm ? __scm->dev : NULL, entry,
+ cpus);
}
EXPORT_SYMBOL(qcom_scm_set_cold_boot_addr);

@@ -123,7 +124,7 @@ EXPORT_SYMBOL(qcom_scm_set_warm_boot_addr);
*/
void qcom_scm_cpu_power_down(u32 flags)
{
- __qcom_scm_cpu_power_down(flags);
+ __qcom_scm_cpu_power_down(__scm ? __scm->dev : NULL, flags);
}
EXPORT_SYMBOL(qcom_scm_cpu_power_down);

diff --git a/drivers/firmware/qcom_scm.h b/drivers/firmware/qcom_scm.h
index 4be482f..20220db 100644
--- a/drivers/firmware/qcom_scm.h
+++ b/drivers/firmware/qcom_scm.h
@@ -9,10 +9,11 @@
#define QCOM_SCM_BOOT_TERMINATE_PC 0x02
#define QCOM_SCM_BOOT_SET_REMOTE_STATE 0x0a
#define QCOM_SCM_BOOT_SET_DLOAD_MODE 0x10
-extern int __qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus);
+extern int __qcom_scm_set_cold_boot_addr(struct device *dev, void *entry,
+ const cpumask_t *cpus);
extern int __qcom_scm_set_warm_boot_addr(struct device *dev, void *entry,
const cpumask_t *cpus);
-extern void __qcom_scm_cpu_power_down(u32 flags);
+extern void __qcom_scm_cpu_power_down(struct device *dev, u32 flags);
extern int __qcom_scm_set_remote_state(struct device *dev, u32 state, u32 id);
extern int __qcom_scm_set_dload_mode(struct device *dev, bool enable);
#define QCOM_SCM_FLUSH_FLAG_MASK 0x3
--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project

2019-11-05 01:30:18

by Elliot Berman

[permalink] [raw]
Subject: [PATCH 08/17] firmware: qcom_scm-64: Move SMC register filling to qcom_scm_call_smccc

qcom_scm_call_smccc should be responsible for converting qcom_scm_desc
into arguments for smc call. Consolidate the dispersed logic to convert
qcom_scm_desc into smc arguments inside qcom_scm_call_smccc.

Signed-off-by: Elliot Berman <[email protected]>
---
drivers/firmware/qcom_scm-64.c | 43 ++++++++++++++++++++++++------------------
1 file changed, 25 insertions(+), 18 deletions(-)

diff --git a/drivers/firmware/qcom_scm-64.c b/drivers/firmware/qcom_scm-64.c
index c013c24..f79b0dc 100644
--- a/drivers/firmware/qcom_scm-64.c
+++ b/drivers/firmware/qcom_scm-64.c
@@ -54,6 +54,10 @@ struct qcom_scm_desc {
u32 owner;
};

+struct arm_smccc_args {
+ unsigned long a[8];
+};
+
static u64 qcom_smccc_convention = -1;
static DEFINE_MUTEX(qcom_scm_lock);

@@ -64,28 +68,23 @@ static DEFINE_MUTEX(qcom_scm_lock);
#define SMCCC_N_REG_ARGS 4
#define SMCCC_FIRST_REG_IDX 2
#define SMCCC_N_EXT_ARGS (MAX_QCOM_SCM_ARGS - SMCCC_N_REG_ARGS + 1)
+#define SMCCC_LAST_REG_IDX (SMCCC_FIRST_REG_IDX + SMCCC_N_REG_ARGS - 1)

-static void __qcom_scm_call_do_quirk(const struct qcom_scm_desc *desc,
- struct arm_smccc_res *res, u64 x5, u32 type)
+static void __qcom_scm_call_do_quirk(const struct arm_smccc_args *smc,
+ struct arm_smccc_res *res)
{
- u64 cmd;
+ unsigned long a0 = smc->a[0];
struct arm_smccc_quirk quirk = { .id = ARM_SMCCC_QUIRK_QCOM_A6 };

- cmd = ARM_SMCCC_CALL_VAL(
- type,
- qcom_smccc_convention,
- desc->owner,
- SMCCC_FUNCNUM(desc->svc, desc->cmd));
-
quirk.state.a6 = 0;

do {
- arm_smccc_smc_quirk(cmd, desc->arginfo, desc->args[0],
- desc->args[1], desc->args[2], x5,
- quirk.state.a6, 0, res, &quirk);
+ arm_smccc_smc_quirk(a0, smc->a[1], smc->a[2], smc->a[3],
+ smc->a[4], smc->a[5], quirk.state.a6,
+ smc->a[7], res, &quirk);

if (res->a0 == QCOM_SCM_INTERRUPTED)
- cmd = res->a0;
+ a0 = res->a0;

} while (res->a0 == QCOM_SCM_INTERRUPTED);
}
@@ -95,12 +94,21 @@ static int ___qcom_scm_call_smccc(struct device *dev,
{
int arglen = desc->arginfo & 0xf;
int i;
- u64 x5 = desc->args[SMCCC_N_REG_ARGS - 1];
dma_addr_t args_phys = 0;
void *args_virt = NULL;
size_t alloc_len;
gfp_t flag = atomic ? GFP_ATOMIC : GFP_KERNEL;
struct arm_smccc_res res;
+ struct arm_smccc_args smc = {0};
+
+ smc.a[0] = ARM_SMCCC_CALL_VAL(
+ atomic ? ARM_SMCCC_FAST_CALL : ARM_SMCCC_STD_CALL,
+ qcom_smccc_convention,
+ desc->owner,
+ SMCCC_FUNCNUM(desc->svc, desc->cmd));
+ smc.a[1] = desc->arginfo;
+ for (i = 0; i < SMCCC_N_REG_ARGS; i++)
+ smc.a[i + SMCCC_FIRST_REG_IDX] = desc->args[i];

if (unlikely(arglen > SMCCC_N_REG_ARGS)) {
alloc_len = SMCCC_N_EXT_ARGS * sizeof(u64);
@@ -131,19 +139,18 @@ static int ___qcom_scm_call_smccc(struct device *dev,
return -ENOMEM;
}

- x5 = args_phys;
+ smc.a[SMCCC_LAST_REG_IDX] = args_phys;
}

if (atomic) {
- __qcom_scm_call_do_quirk(desc, &res, x5, ARM_SMCCC_FAST_CALL);
+ __qcom_scm_call_do_quirk(&smc, &res);
} else {
int retry_count = 0;

do {
mutex_lock(&qcom_scm_lock);

- __qcom_scm_call_do_quirk(desc, &res, x5,
- ARM_SMCCC_STD_CALL);
+ __qcom_scm_call_do_quirk(&smc, &res);

mutex_unlock(&qcom_scm_lock);

--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project

2019-11-05 01:30:22

by Elliot Berman

[permalink] [raw]
Subject: [PATCH 07/17] firmware: qcom_scm-64: Remove qcom_scm_call_do_smccc

Remove thin wrapper to qcom_scm_call_do_smccc because it doesn't do
enough of anything interesting to dedicate its own function.

Signed-off-by: Elliot Berman <[email protected]>
---
drivers/firmware/qcom_scm-64.c | 46 ++++++++++++++++++------------------------
1 file changed, 20 insertions(+), 26 deletions(-)

diff --git a/drivers/firmware/qcom_scm-64.c b/drivers/firmware/qcom_scm-64.c
index f6536fa..c013c24 100644
--- a/drivers/firmware/qcom_scm-64.c
+++ b/drivers/firmware/qcom_scm-64.c
@@ -90,31 +90,6 @@ static void __qcom_scm_call_do_quirk(const struct qcom_scm_desc *desc,
} while (res->a0 == QCOM_SCM_INTERRUPTED);
}

-static void qcom_scm_call_do_smccc(const struct qcom_scm_desc *desc,
- struct arm_smccc_res *res, u64 x5, bool atomic)
-{
- int retry_count = 0;
-
- if (atomic) {
- __qcom_scm_call_do_quirk(desc, res, x5, ARM_SMCCC_FAST_CALL);
- return;
- }
-
- do {
- mutex_lock(&qcom_scm_lock);
-
- __qcom_scm_call_do_quirk(desc, res, x5, ARM_SMCCC_STD_CALL);
-
- mutex_unlock(&qcom_scm_lock);
-
- if (res->a0 == QCOM_SCM_V2_EBUSY) {
- if (retry_count++ > QCOM_SCM_EBUSY_MAX_RETRY)
- break;
- msleep(QCOM_SCM_EBUSY_WAIT_MS);
- }
- } while (res->a0 == QCOM_SCM_V2_EBUSY);
-}
-
static int ___qcom_scm_call_smccc(struct device *dev,
struct qcom_scm_desc *desc, bool atomic)
{
@@ -159,7 +134,26 @@ static int ___qcom_scm_call_smccc(struct device *dev,
x5 = args_phys;
}

- qcom_scm_call_do_smccc(desc, &res, x5, atomic);
+ if (atomic) {
+ __qcom_scm_call_do_quirk(desc, &res, x5, ARM_SMCCC_FAST_CALL);
+ } else {
+ int retry_count = 0;
+
+ do {
+ mutex_lock(&qcom_scm_lock);
+
+ __qcom_scm_call_do_quirk(desc, &res, x5,
+ ARM_SMCCC_STD_CALL);
+
+ mutex_unlock(&qcom_scm_lock);
+
+ if (res.a0 == QCOM_SCM_V2_EBUSY) {
+ if (retry_count++ > QCOM_SCM_EBUSY_MAX_RETRY)
+ break;
+ msleep(QCOM_SCM_EBUSY_WAIT_MS);
+ }
+ } while (res.a0 == QCOM_SCM_V2_EBUSY);
+ }

if (args_virt) {
dma_unmap_single(dev, args_phys, alloc_len, DMA_TO_DEVICE);
--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project

2019-11-05 01:30:37

by Elliot Berman

[permalink] [raw]
Subject: [PATCH 10/17] firmware: qcom_scm-32: Use SMC arch wrappers

Use SMC arch wrappers instead of inline assembly.

Signed-off-by: Elliot Berman <[email protected]>
---
drivers/firmware/qcom_scm-32.c | 71 ++++++++++--------------------------------
1 file changed, 17 insertions(+), 54 deletions(-)

diff --git a/drivers/firmware/qcom_scm-32.c b/drivers/firmware/qcom_scm-32.c
index b7f9f28..e3dc9a7 100644
--- a/drivers/firmware/qcom_scm-32.c
+++ b/drivers/firmware/qcom_scm-32.c
@@ -10,6 +10,7 @@
#include <linux/errno.h>
#include <linux/err.h>
#include <linux/qcom_scm.h>
+#include <linux/arm-smccc.h>
#include <linux/dma-mapping.h>

#include "qcom_scm.h"
@@ -121,25 +122,13 @@ static inline void *legacy_get_response_buffer(const struct legacy_response *rsp
static u32 __qcom_scm_call_do(u32 cmd_addr)
{
int context_id;
- register u32 r0 asm("r0") = 1;
- register u32 r1 asm("r1") = (u32)&context_id;
- register u32 r2 asm("r2") = cmd_addr;
+ struct arm_smccc_res res;
do {
- asm volatile(
- __asmeq("%0", "r0")
- __asmeq("%1", "r0")
- __asmeq("%2", "r1")
- __asmeq("%3", "r2")
-#ifdef REQUIRES_SEC
- ".arch_extension sec\n"
-#endif
- "smc #0 @ switch to secure world\n"
- : "=r" (r0)
- : "r" (r0), "r" (r1), "r" (r2)
- : "r3", "r12");
- } while (r0 == QCOM_SCM_INTERRUPTED);
-
- return r0;
+ arm_smccc_smc(1, (unsigned long)&context_id, cmd_addr,
+ 0, 0, 0, 0, 0, &res);
+ } while (res.a0 == QCOM_SCM_INTERRUPTED);
+
+ return res.a0;
}

/**
@@ -236,24 +225,12 @@ static int qcom_scm_call(struct device *dev, u32 svc_id, u32 cmd_id,
static s32 qcom_scm_call_atomic1(u32 svc, u32 cmd, u32 arg1)
{
int context_id;
+ struct arm_smccc_res res;
+
+ arm_smccc_smc(LEGACY_ATOMIC(svc, cmd, 1), (unsigned long)&context_id,
+ arg1, 0, 0, 0, 0, 0, &res);

- register u32 r0 asm("r0") = LEGACY_ATOMIC(svc, cmd, 1);
- register u32 r1 asm("r1") = (u32)&context_id;
- register u32 r2 asm("r2") = arg1;
-
- asm volatile(
- __asmeq("%0", "r0")
- __asmeq("%1", "r0")
- __asmeq("%2", "r1")
- __asmeq("%3", "r2")
-#ifdef REQUIRES_SEC
- ".arch_extension sec\n"
-#endif
- "smc #0 @ switch to secure world\n"
- : "=r" (r0)
- : "r" (r0), "r" (r1), "r" (r2)
- : "r3", "r12");
- return r0;
+ return res.a0;
}

/**
@@ -269,26 +246,12 @@ static s32 qcom_scm_call_atomic1(u32 svc, u32 cmd, u32 arg1)
static s32 qcom_scm_call_atomic2(u32 svc, u32 cmd, u32 arg1, u32 arg2)
{
int context_id;
+ struct arm_smccc_res res;
+
+ arm_smccc_smc(LEGACY_ATOMIC(svc, cmd, 2), (unsigned long)&context_id,
+ arg1, arg2, 0, 0, 0, 0, &res);

- register u32 r0 asm("r0") = LEGACY_ATOMIC(svc, cmd, 2);
- register u32 r1 asm("r1") = (u32)&context_id;
- register u32 r2 asm("r2") = arg1;
- register u32 r3 asm("r3") = arg2;
-
- asm volatile(
- __asmeq("%0", "r0")
- __asmeq("%1", "r0")
- __asmeq("%2", "r1")
- __asmeq("%3", "r2")
- __asmeq("%4", "r3")
-#ifdef REQUIRES_SEC
- ".arch_extension sec\n"
-#endif
- "smc #0 @ switch to secure world\n"
- : "=r" (r0)
- : "r" (r0), "r" (r1), "r" (r2), "r" (r3)
- : "r12");
- return r0;
+ return res.a0;
}

/**
--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project

2019-11-05 01:30:52

by Elliot Berman

[permalink] [raw]
Subject: [PATCH 01/17] firmware: qcom_scm: Rename macros and structures

- Rename legacy-specific structures and macros with "legacy_" prefix.
- Rename smccc-specific structures and macros with "smccc_" prefix.
- Flip calculation of SMCCC_N_EXT_ARGS to be a function of N_REG_ARGS
(not the other way around). N_REG_ARGS is fixed based off the SMC
instruction and shouldn't be computed from the SCM abstraction.
- Move SMCCC_FUNCNUM closer to other smccc-specific macros.
- Add LEGACY_FUNCNUM macro to qcom_scm-32.c

Signed-off-by: Elliot Berman <[email protected]>
---
drivers/firmware/qcom_scm-32.c | 72 ++++++++++++++++++++++--------------------
drivers/firmware/qcom_scm-64.c | 54 +++++++++++++++----------------
drivers/firmware/qcom_scm.c | 4 +--
3 files changed, 65 insertions(+), 65 deletions(-)

diff --git a/drivers/firmware/qcom_scm-32.c b/drivers/firmware/qcom_scm-32.c
index bee8729..d416efc 100644
--- a/drivers/firmware/qcom_scm-32.c
+++ b/drivers/firmware/qcom_scm-32.c
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
-/* Copyright (c) 2010,2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010,2015,2019 The Linux Foundation. All rights reserved.
* Copyright (C) 2015 Linaro Ltd.
*/

@@ -38,23 +38,25 @@ static struct qcom_scm_entry qcom_scm_wb[] = {

static DEFINE_MUTEX(qcom_scm_lock);

+#define LEGACY_FUNCNUM(s, c) (((s) << 10) | ((c) & 0x3ff))
+
/**
- * struct qcom_scm_command - one SCM command buffer
+ * struct legacy_command - one SCM command buffer
* @len: total available memory for command and response
* @buf_offset: start of command buffer
* @resp_hdr_offset: start of response buffer
* @id: command to be executed
- * @buf: buffer returned from qcom_scm_get_command_buffer()
+ * @buf: buffer returned from legacy_get_command_buffer()
*
* An SCM command is laid out in memory as follows:
*
- * ------------------- <--- struct qcom_scm_command
+ * ------------------- <--- struct legacy_command
* | command header |
- * ------------------- <--- qcom_scm_get_command_buffer()
+ * ------------------- <--- legacy_get_command_buffer()
* | command buffer |
- * ------------------- <--- struct qcom_scm_response and
- * | response header | qcom_scm_command_to_response()
- * ------------------- <--- qcom_scm_get_response_buffer()
+ * ------------------- <--- struct legacy_response and
+ * | response header | legacy_command_to_response()
+ * ------------------- <--- legacy_get_response_buffer()
* | response buffer |
* -------------------
*
@@ -62,7 +64,7 @@ static DEFINE_MUTEX(qcom_scm_lock);
* you should always use the appropriate qcom_scm_get_*_buffer() routines
* to access the buffers in a safe manner.
*/
-struct qcom_scm_command {
+struct legacy_command {
__le32 len;
__le32 buf_offset;
__le32 resp_hdr_offset;
@@ -71,52 +73,52 @@ struct qcom_scm_command {
};

/**
- * struct qcom_scm_response - one SCM response buffer
+ * struct legacy_response - one SCM response buffer
* @len: total available memory for response
- * @buf_offset: start of response data relative to start of qcom_scm_response
+ * @buf_offset: start of response data relative to start of legacy_response
* @is_complete: indicates if the command has finished processing
*/
-struct qcom_scm_response {
+struct legacy_response {
__le32 len;
__le32 buf_offset;
__le32 is_complete;
};

/**
- * qcom_scm_command_to_response() - Get a pointer to a qcom_scm_response
+ * legacy_command_to_response() - Get a pointer to a legacy_response
* @cmd: command
*
* Returns a pointer to a response for a command.
*/
-static inline struct qcom_scm_response *qcom_scm_command_to_response(
- const struct qcom_scm_command *cmd)
+static inline struct legacy_response *legacy_command_to_response(
+ const struct legacy_command *cmd)
{
return (void *)cmd + le32_to_cpu(cmd->resp_hdr_offset);
}

/**
- * qcom_scm_get_command_buffer() - Get a pointer to a command buffer
+ * legacy_get_command_buffer() - Get a pointer to a command buffer
* @cmd: command
*
* Returns a pointer to the command buffer of a command.
*/
-static inline void *qcom_scm_get_command_buffer(const struct qcom_scm_command *cmd)
+static inline void *legacy_get_command_buffer(const struct legacy_command *cmd)
{
return (void *)cmd->buf;
}

/**
- * qcom_scm_get_response_buffer() - Get a pointer to a response buffer
+ * legacy_get_response_buffer() - Get a pointer to a response buffer
* @rsp: response
*
* Returns a pointer to a response buffer of a response.
*/
-static inline void *qcom_scm_get_response_buffer(const struct qcom_scm_response *rsp)
+static inline void *legacy_get_response_buffer(const struct legacy_response *rsp)
{
return (void *)rsp + le32_to_cpu(rsp->buf_offset);
}

-static u32 smc(u32 cmd_addr)
+static u32 __qcom_scm_call_do(u32 cmd_addr)
{
int context_id;
register u32 r0 asm("r0") = 1;
@@ -164,8 +166,8 @@ static int qcom_scm_call(struct device *dev, u32 svc_id, u32 cmd_id,
size_t resp_len)
{
int ret;
- struct qcom_scm_command *cmd;
- struct qcom_scm_response *rsp;
+ struct legacy_command *cmd;
+ struct legacy_response *rsp;
size_t alloc_len = sizeof(*cmd) + cmd_len + sizeof(*rsp) + resp_len;
dma_addr_t cmd_phys;

@@ -177,11 +179,11 @@ static int qcom_scm_call(struct device *dev, u32 svc_id, u32 cmd_id,
cmd->buf_offset = cpu_to_le32(sizeof(*cmd));
cmd->resp_hdr_offset = cpu_to_le32(sizeof(*cmd) + cmd_len);

- cmd->id = cpu_to_le32((svc_id << 10) | cmd_id);
+ cmd->id = cpu_to_le32(LEGACY_FUNCNUM(svc_id, cmd_id));
if (cmd_buf)
- memcpy(qcom_scm_get_command_buffer(cmd), cmd_buf, cmd_len);
+ memcpy(legacy_get_command_buffer(cmd), cmd_buf, cmd_len);

- rsp = qcom_scm_command_to_response(cmd);
+ rsp = legacy_command_to_response(cmd);

cmd_phys = dma_map_single(dev, cmd, alloc_len, DMA_TO_DEVICE);
if (dma_mapping_error(dev, cmd_phys)) {
@@ -190,7 +192,7 @@ static int qcom_scm_call(struct device *dev, u32 svc_id, u32 cmd_id,
}

mutex_lock(&qcom_scm_lock);
- ret = smc(cmd_phys);
+ ret = __qcom_scm_call_do(cmd_phys);
if (ret < 0)
ret = qcom_scm_remap_error(ret);
mutex_unlock(&qcom_scm_lock);
@@ -206,7 +208,7 @@ static int qcom_scm_call(struct device *dev, u32 svc_id, u32 cmd_id,
dma_sync_single_for_cpu(dev, cmd_phys + sizeof(*cmd) + cmd_len +
le32_to_cpu(rsp->buf_offset),
resp_len, DMA_FROM_DEVICE);
- memcpy(resp_buf, qcom_scm_get_response_buffer(rsp),
+ memcpy(resp_buf, legacy_get_response_buffer(rsp),
resp_len);
}
out:
@@ -215,12 +217,12 @@ static int qcom_scm_call(struct device *dev, u32 svc_id, u32 cmd_id,
return ret;
}

-#define SCM_CLASS_REGISTER (0x2 << 8)
-#define SCM_MASK_IRQS BIT(5)
-#define SCM_ATOMIC(svc, cmd, n) (((((svc) << 10)|((cmd) & 0x3ff)) << 12) | \
- SCM_CLASS_REGISTER | \
- SCM_MASK_IRQS | \
- (n & 0xf))
+#define LEGACY_CLASS_REGISTER (0x2 << 8)
+#define LEGACY_MASK_IRQS BIT(5)
+#define LEGACY_ATOMIC(svc, cmd, n) ((LEGACY_FUNCNUM(svc, cmd) << 12) | \
+ LEGACY_CLASS_REGISTER | \
+ LEGACY_MASK_IRQS | \
+ (n & 0xf))

/**
* qcom_scm_call_atomic1() - Send an atomic SCM command with one argument
@@ -235,7 +237,7 @@ static s32 qcom_scm_call_atomic1(u32 svc, u32 cmd, u32 arg1)
{
int context_id;

- register u32 r0 asm("r0") = SCM_ATOMIC(svc, cmd, 1);
+ register u32 r0 asm("r0") = LEGACY_ATOMIC(svc, cmd, 1);
register u32 r1 asm("r1") = (u32)&context_id;
register u32 r2 asm("r2") = arg1;

@@ -268,7 +270,7 @@ static s32 qcom_scm_call_atomic2(u32 svc, u32 cmd, u32 arg1, u32 arg2)
{
int context_id;

- register u32 r0 asm("r0") = SCM_ATOMIC(svc, cmd, 2);
+ register u32 r0 asm("r0") = LEGACY_ATOMIC(svc, cmd, 2);
register u32 r1 asm("r1") = (u32)&context_id;
register u32 r2 asm("r2") = arg1;
register u32 r3 asm("r3") = arg2;
diff --git a/drivers/firmware/qcom_scm-64.c b/drivers/firmware/qcom_scm-64.c
index 7686786..e6721b5 100644
--- a/drivers/firmware/qcom_scm-64.c
+++ b/drivers/firmware/qcom_scm-64.c
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
-/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015,2019 The Linux Foundation. All rights reserved.
*/

#include <linux/io.h>
@@ -14,8 +14,6 @@

#include "qcom_scm.h"

-#define QCOM_SCM_FNID(s, c) ((((s) & 0xFF) << 8) | ((c) & 0xFF))
-
#define MAX_QCOM_SCM_ARGS 10
#define MAX_QCOM_SCM_RETS 3

@@ -58,11 +56,12 @@ static DEFINE_MUTEX(qcom_scm_lock);
#define QCOM_SCM_EBUSY_WAIT_MS 30
#define QCOM_SCM_EBUSY_MAX_RETRY 20

-#define N_EXT_QCOM_SCM_ARGS 7
-#define FIRST_EXT_ARG_IDX 3
-#define N_REGISTER_ARGS (MAX_QCOM_SCM_ARGS - N_EXT_QCOM_SCM_ARGS + 1)
+#define SMCCC_FUNCNUM(s, c) ((((s) & 0xFF) << 8) | ((c) & 0xFF))
+#define SMCCC_N_REG_ARGS 4
+#define SMCCC_FIRST_REG_IDX 2
+#define SMCCC_N_EXT_ARGS (MAX_QCOM_SCM_ARGS - SMCCC_N_REG_ARGS + 1)

-static void __qcom_scm_call_do(const struct qcom_scm_desc *desc,
+static void __qcom_scm_call_do_quirk(const struct qcom_scm_desc *desc,
struct arm_smccc_res *res, u32 fn_id,
u64 x5, u32 type)
{
@@ -85,22 +84,23 @@ static void __qcom_scm_call_do(const struct qcom_scm_desc *desc,
} while (res->a0 == QCOM_SCM_INTERRUPTED);
}

-static void qcom_scm_call_do(const struct qcom_scm_desc *desc,
+static void qcom_scm_call_do_smccc(const struct qcom_scm_desc *desc,
struct arm_smccc_res *res, u32 fn_id,
u64 x5, bool atomic)
{
int retry_count = 0;

if (atomic) {
- __qcom_scm_call_do(desc, res, fn_id, x5, ARM_SMCCC_FAST_CALL);
+ __qcom_scm_call_do_quirk(desc, res, fn_id, x5,
+ ARM_SMCCC_FAST_CALL);
return;
}

do {
mutex_lock(&qcom_scm_lock);

- __qcom_scm_call_do(desc, res, fn_id, x5,
- ARM_SMCCC_STD_CALL);
+ __qcom_scm_call_do_quirk(desc, res, fn_id, x5,
+ ARM_SMCCC_STD_CALL);

mutex_unlock(&qcom_scm_lock);

@@ -112,21 +112,21 @@ static void qcom_scm_call_do(const struct qcom_scm_desc *desc,
} while (res->a0 == QCOM_SCM_V2_EBUSY);
}

-static int ___qcom_scm_call(struct device *dev, u32 svc_id, u32 cmd_id,
- const struct qcom_scm_desc *desc,
- struct arm_smccc_res *res, bool atomic)
+static int ___qcom_scm_call_smccc(struct device *dev, u32 svc_id, u32 cmd_id,
+ const struct qcom_scm_desc *desc,
+ struct arm_smccc_res *res, bool atomic)
{
int arglen = desc->arginfo & 0xf;
int i;
- u32 fn_id = QCOM_SCM_FNID(svc_id, cmd_id);
- u64 x5 = desc->args[FIRST_EXT_ARG_IDX];
+ u32 fn_id = SMCCC_FUNCNUM(svc_id, cmd_id);
+ u64 x5 = desc->args[SMCCC_N_REG_ARGS - 1];
dma_addr_t args_phys = 0;
void *args_virt = NULL;
size_t alloc_len;
gfp_t flag = atomic ? GFP_ATOMIC : GFP_KERNEL;

- if (unlikely(arglen > N_REGISTER_ARGS)) {
- alloc_len = N_EXT_QCOM_SCM_ARGS * sizeof(u64);
+ if (unlikely(arglen > SMCCC_N_REG_ARGS)) {
+ alloc_len = SMCCC_N_EXT_ARGS * sizeof(u64);
args_virt = kzalloc(PAGE_ALIGN(alloc_len), flag);

if (!args_virt)
@@ -135,15 +135,15 @@ static int ___qcom_scm_call(struct device *dev, u32 svc_id, u32 cmd_id,
if (qcom_smccc_convention == ARM_SMCCC_SMC_32) {
__le32 *args = args_virt;

- for (i = 0; i < N_EXT_QCOM_SCM_ARGS; i++)
+ for (i = 0; i < SMCCC_N_EXT_ARGS; i++)
args[i] = cpu_to_le32(desc->args[i +
- FIRST_EXT_ARG_IDX]);
+ SMCCC_N_REG_ARGS - 1]);
} else {
__le64 *args = args_virt;

- for (i = 0; i < N_EXT_QCOM_SCM_ARGS; i++)
+ for (i = 0; i < SMCCC_N_EXT_ARGS; i++)
args[i] = cpu_to_le64(desc->args[i +
- FIRST_EXT_ARG_IDX]);
+ SMCCC_N_REG_ARGS - 1]);
}

args_phys = dma_map_single(dev, args_virt, alloc_len,
@@ -157,7 +157,7 @@ static int ___qcom_scm_call(struct device *dev, u32 svc_id, u32 cmd_id,
x5 = args_phys;
}

- qcom_scm_call_do(desc, res, fn_id, x5, atomic);
+ qcom_scm_call_do_smccc(desc, res, fn_id, x5, atomic);

if (args_virt) {
dma_unmap_single(dev, args_phys, alloc_len, DMA_TO_DEVICE);
@@ -185,7 +185,7 @@ static int qcom_scm_call(struct device *dev, u32 svc_id, u32 cmd_id,
struct arm_smccc_res *res)
{
might_sleep();
- return ___qcom_scm_call(dev, svc_id, cmd_id, desc, res, false);
+ return ___qcom_scm_call_smccc(dev, svc_id, cmd_id, desc, res, false);
}

/**
@@ -203,7 +203,7 @@ static int qcom_scm_call_atomic(struct device *dev, u32 svc_id, u32 cmd_id,
const struct qcom_scm_desc *desc,
struct arm_smccc_res *res)
{
- return ___qcom_scm_call(dev, svc_id, cmd_id, desc, res, true);
+ return ___qcom_scm_call_smccc(dev, svc_id, cmd_id, desc, res, true);
}

/**
@@ -253,7 +253,7 @@ int __qcom_scm_is_call_available(struct device *dev, u32 svc_id, u32 cmd_id)
struct arm_smccc_res res;

desc.arginfo = QCOM_SCM_ARGS(1);
- desc.args[0] = QCOM_SCM_FNID(svc_id, cmd_id) |
+ desc.args[0] = SMCCC_FUNCNUM(svc_id, cmd_id) |
(ARM_SMCCC_OWNER_SIP << ARM_SMCCC_OWNER_SHIFT);

ret = qcom_scm_call(dev, QCOM_SCM_SVC_INFO, QCOM_IS_CALL_AVAIL_CMD,
@@ -295,7 +295,7 @@ void __qcom_scm_init(void)
{
u64 cmd;
struct arm_smccc_res res;
- u32 function = QCOM_SCM_FNID(QCOM_SCM_SVC_INFO, QCOM_IS_CALL_AVAIL_CMD);
+ u32 function = SMCCC_FUNCNUM(QCOM_SCM_SVC_INFO, QCOM_IS_CALL_AVAIL_CMD);

/* First try a SMC64 call */
cmd = ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, ARM_SMCCC_SMC_64,
diff --git a/drivers/firmware/qcom_scm.c b/drivers/firmware/qcom_scm.c
index a729e05..40222b1 100644
--- a/drivers/firmware/qcom_scm.c
+++ b/drivers/firmware/qcom_scm.c
@@ -1,8 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Qualcomm SCM driver
- *
- * Copyright (c) 2010,2015, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2010,2015,2019 The Linux Foundation. All rights reserved.
* Copyright (C) 2015 Linaro Ltd.
*/
#include <linux/platform_device.h>
--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project

2019-11-05 01:30:53

by Elliot Berman

[permalink] [raw]
Subject: [PATCH 04/17] firmware: qcom_scm: Remove unused qcom_scm_get_version

Remove unused qcom_scm_get_version.

Signed-off-by: Elliot Berman <[email protected]>
---
drivers/firmware/qcom_scm-32.c | 36 ------------------------------------
include/linux/qcom_scm.h | 2 --
2 files changed, 38 deletions(-)

diff --git a/drivers/firmware/qcom_scm-32.c b/drivers/firmware/qcom_scm-32.c
index b09fddf..b7f9f28 100644
--- a/drivers/firmware/qcom_scm-32.c
+++ b/drivers/firmware/qcom_scm-32.c
@@ -291,42 +291,6 @@ static s32 qcom_scm_call_atomic2(u32 svc, u32 cmd, u32 arg1, u32 arg2)
return r0;
}

-u32 qcom_scm_get_version(void)
-{
- int context_id;
- static u32 version = -1;
- register u32 r0 asm("r0");
- register u32 r1 asm("r1");
-
- if (version != -1)
- return version;
-
- mutex_lock(&qcom_scm_lock);
-
- r0 = 0x1 << 8;
- r1 = (u32)&context_id;
- do {
- asm volatile(
- __asmeq("%0", "r0")
- __asmeq("%1", "r1")
- __asmeq("%2", "r0")
- __asmeq("%3", "r1")
-#ifdef REQUIRES_SEC
- ".arch_extension sec\n"
-#endif
- "smc #0 @ switch to secure world\n"
- : "=r" (r0), "=r" (r1)
- : "r" (r0), "r" (r1)
- : "r2", "r3", "r12");
- } while (r0 == QCOM_SCM_INTERRUPTED);
-
- version = r1;
- mutex_unlock(&qcom_scm_lock);
-
- return version;
-}
-EXPORT_SYMBOL(qcom_scm_get_version);
-
/**
* qcom_scm_set_cold_boot_addr() - Set the cold boot address for cpus
* @entry: Entry point function for the cpus
diff --git a/include/linux/qcom_scm.h b/include/linux/qcom_scm.h
index f8b6525..05a1c7a 100644
--- a/include/linux/qcom_scm.h
+++ b/include/linux/qcom_scm.h
@@ -59,7 +59,6 @@ extern bool qcom_scm_hdcp_available(void);
extern int qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt,
u32 *resp);
extern int qcom_scm_qsmmu500_wait_safe_toggle(bool en);
-extern u32 qcom_scm_get_version(void);
extern bool qcom_scm_is_available(void);
#else

@@ -101,7 +100,6 @@ static inline int qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt,
u32 *resp) { return -ENODEV; }
static inline int qcom_scm_qsmmu500_wait_safe_toggle(bool en)
{ return -ENODEV; }
-static inline u32 qcom_scm_get_version(void) { return 0; }
static inline bool qcom_scm_is_available(void) { return false; }
#endif
#endif
--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project

2019-11-05 01:32:25

by Elliot Berman

[permalink] [raw]
Subject: [PATCH 13/17] firmware: qcom_scm-32: Create common legacy atomic call

Per [1], legacy calling convention supports up to 5 arguments and
3 return values. Create one function to support this combination.

[1]: https://source.codeaurora.org/quic/la/kernel/msm-4.9/tree/drivers/soc/qcom/scm.c?h=kernel.lnx.4.9.r28-rel#n1024

Signed-off-by: Elliot Berman <[email protected]>
---
drivers/firmware/qcom_scm-32.c | 109 +++++++++++++++++++++++++----------------
1 file changed, 67 insertions(+), 42 deletions(-)

diff --git a/drivers/firmware/qcom_scm-32.c b/drivers/firmware/qcom_scm-32.c
index 9811560..533c68a 100644
--- a/drivers/firmware/qcom_scm-32.c
+++ b/drivers/firmware/qcom_scm-32.c
@@ -257,6 +257,8 @@ static int qcom_scm_call(struct device *dev, struct qcom_scm_desc *desc)
return ret;
}

+#define LEGACY_ATOMIC_N_REG_ARGS 5
+#define LEGACY_ATOMIC_FIRST_REG_IDX 2
#define LEGACY_CLASS_REGISTER (0x2 << 8)
#define LEGACY_MASK_IRQS BIT(5)
#define LEGACY_ATOMIC(svc, cmd, n) ((LEGACY_FUNCNUM(svc, cmd) << 12) | \
@@ -265,52 +267,34 @@ static int qcom_scm_call(struct device *dev, struct qcom_scm_desc *desc)
(n & 0xf))

/**
- * qcom_scm_call_atomic1() - Send an atomic SCM command with one argument
- * @svc_id: service identifier
- * @cmd_id: command identifier
- * @arg1: first argument
+ * qcom_scm_call_atomic() - Send an atomic SCM command with up to 5 arguments
+ * and 3 return values
*
* This shall only be used with commands that are guaranteed to be
* uninterruptable, atomic and SMP safe.
*/
-static s32 qcom_scm_call_atomic1(u32 svc, u32 cmd, u32 arg1)
+static int qcom_scm_call_atomic(struct qcom_scm_desc *desc)
{
int context_id;
struct arm_smccc_args smc = {0};
struct arm_smccc_res res;
+ size_t i, arglen = desc->arginfo & 0xf;

- smc.a[0] = LEGACY_ATOMIC(svc, cmd, 1);
- smc.a[1] = (unsigned long)&context_id;
- smc.a[2] = arg1;
- arm_smccc_smc(smc.a[0], smc.a[1], smc.a[2], smc.a[3],
- smc.a[4], smc.a[5], smc.a[6], smc.a[7], &res);
+ BUG_ON(arglen > LEGACY_ATOMIC_N_REG_ARGS);

- return res.a0;
-}
+ smc.a[0] = LEGACY_ATOMIC(desc->svc, desc->cmd, arglen);
+ smc.a[1] = (unsigned long)&context_id;

-/**
- * qcom_scm_call_atomic2() - Send an atomic SCM command with two arguments
- * @svc_id: service identifier
- * @cmd_id: command identifier
- * @arg1: first argument
- * @arg2: second argument
- *
- * This shall only be used with commands that are guaranteed to be
- * uninterruptable, atomic and SMP safe.
- */
-static s32 qcom_scm_call_atomic2(u32 svc, u32 cmd, u32 arg1, u32 arg2)
-{
- int context_id;
- struct arm_smccc_args smc = {0};
- struct arm_smccc_res res;
+ for (i = 0; i < arglen; i++)
+ smc.a[i + LEGACY_ATOMIC_FIRST_REG_IDX] = desc->args[i];

- smc.a[0] = LEGACY_ATOMIC(svc, cmd, 2);
- smc.a[1] = (unsigned long)&context_id;
- smc.a[2] = arg1;
- smc.a[3] = arg2;
arm_smccc_smc(smc.a[0], smc.a[1], smc.a[2], smc.a[3],
smc.a[4], smc.a[5], smc.a[6], smc.a[7], &res);

+ desc->res[0] = res.a1;
+ desc->res[1] = res.a2;
+ desc->res[2] = res.a3;
+
return res.a0;
}

@@ -332,6 +316,11 @@ int __qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus)
QCOM_SCM_FLAG_COLDBOOT_CPU2,
QCOM_SCM_FLAG_COLDBOOT_CPU3,
};
+ struct qcom_scm_desc desc = {
+ .svc = QCOM_SCM_SVC_BOOT,
+ .cmd = QCOM_SCM_BOOT_SET_ADDR,
+ .owner = ARM_SMCCC_OWNER_SIP,
+ };

if (!cpus || (cpus && cpumask_empty(cpus)))
return -EINVAL;
@@ -343,8 +332,11 @@ int __qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus)
set_cpu_present(cpu, false);
}

- return qcom_scm_call_atomic2(QCOM_SCM_SVC_BOOT, QCOM_SCM_BOOT_SET_ADDR,
- flags, virt_to_phys(entry));
+ desc.args[0] = flags;
+ desc.args[1] = virt_to_phys(entry);
+ desc.arginfo = QCOM_SCM_ARGS(2);
+
+ return qcom_scm_call_atomic(&desc);
}

/**
@@ -402,8 +394,15 @@ int __qcom_scm_set_warm_boot_addr(struct device *dev, void *entry,
*/
void __qcom_scm_cpu_power_down(u32 flags)
{
- qcom_scm_call_atomic1(QCOM_SCM_SVC_BOOT, QCOM_SCM_BOOT_TERMINATE_PC,
- flags & QCOM_SCM_FLUSH_FLAG_MASK);
+ struct qcom_scm_desc desc = {
+ .svc = QCOM_SCM_SVC_BOOT,
+ .cmd = QCOM_SCM_BOOT_TERMINATE_PC,
+ .args[0] = flags & QCOM_SCM_FLUSH_FLAG_MASK,
+ .arginfo = QCOM_SCM_ARGS(1),
+ .owner = ARM_SMCCC_OWNER_SIP,
+ };
+
+ qcom_scm_call_atomic(&desc);
}

int __qcom_scm_set_remote_state(struct device *dev, u32 state, u32 id)
@@ -426,8 +425,17 @@ int __qcom_scm_set_remote_state(struct device *dev, u32 state, u32 id)

int __qcom_scm_set_dload_mode(struct device *dev, bool enable)
{
- return qcom_scm_call_atomic2(QCOM_SCM_SVC_BOOT, QCOM_SCM_BOOT_SET_DLOAD_MODE,
- enable ? QCOM_SCM_BOOT_SET_DLOAD_MODE : 0, 0);
+ struct qcom_scm_desc desc = {
+ .svc = QCOM_SCM_SVC_BOOT,
+ .cmd = QCOM_SCM_BOOT_SET_DLOAD_MODE,
+ .owner = ARM_SMCCC_OWNER_SIP,
+ };
+
+ desc.args[0] = QCOM_SCM_BOOT_SET_DLOAD_MODE;
+ desc.args[1] = enable ? QCOM_SCM_BOOT_SET_DLOAD_MODE : 0;
+ desc.arginfo = QCOM_SCM_ARGS(2);
+
+ return qcom_scm_call_atomic(&desc);
}

bool __qcom_scm_pas_supported(struct device *dev, u32 peripheral)
@@ -539,18 +547,35 @@ int __qcom_scm_io_readl(struct device *dev, phys_addr_t addr,
unsigned int *val)
{
int ret;
+ struct qcom_scm_desc desc = {
+ .svc = QCOM_SCM_SVC_IO,
+ .cmd = QCOM_SCM_IO_READ,
+ .owner = ARM_SMCCC_OWNER_SIP,
+ };

- ret = qcom_scm_call_atomic1(QCOM_SCM_SVC_IO, QCOM_SCM_IO_READ, addr);
+ desc.args[0] = addr;
+ desc.arginfo = QCOM_SCM_ARGS(1);
+
+ ret = qcom_scm_call_atomic(&desc);
if (ret >= 0)
- *val = ret;
+ *val = desc.res[0];

return ret < 0 ? ret : 0;
}

int __qcom_scm_io_writel(struct device *dev, phys_addr_t addr, unsigned int val)
{
- return qcom_scm_call_atomic2(QCOM_SCM_SVC_IO, QCOM_SCM_IO_WRITE,
- addr, val);
+ struct qcom_scm_desc desc = {
+ .svc = QCOM_SCM_SVC_IO,
+ .cmd = QCOM_SCM_IO_WRITE,
+ .owner = ARM_SMCCC_OWNER_SIP,
+ };
+
+ desc.args[0] = addr;
+ desc.args[1] = val;
+ desc.arginfo = QCOM_SCM_ARGS(2);
+
+ return qcom_scm_call_atomic(&desc);
}

int __qcom_scm_is_call_available(struct device *dev, u32 svc_id, u32 cmd_id)
@@ -631,4 +656,4 @@ int __qcom_scm_qsmmu500_wait_safe_toggle(struct device *dev, bool enable)

void __qcom_scm_init(void)
{
-}
\ No newline at end of file
+}
--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project

2019-11-05 01:32:52

by Elliot Berman

[permalink] [raw]
Subject: [PATCH 05/17] firmware: qcom_scm-64: Move svc/cmd/owner into qcom_scm_desc

Service, command, and owner IDs are all part of qcom_scm_desc struct and
have no special reason to be a function argument (or hard-coded in the
case of owner). Moving them to be part of qcom_scm_desc struct improves
readability.

Signed-off-by: Elliot Berman <[email protected]>
---
drivers/firmware/qcom_scm-64.c | 192 +++++++++++++++++++++++++----------------
1 file changed, 120 insertions(+), 72 deletions(-)

diff --git a/drivers/firmware/qcom_scm-64.c b/drivers/firmware/qcom_scm-64.c
index ead0b5f..76412a5 100644
--- a/drivers/firmware/qcom_scm-64.c
+++ b/drivers/firmware/qcom_scm-64.c
@@ -46,8 +46,11 @@ enum qcom_scm_arg_types {
* @res: The values returned by the secure syscall
*/
struct qcom_scm_desc {
+ u32 svc;
+ u32 cmd;
u32 arginfo;
u64 args[MAX_QCOM_SCM_ARGS];
+ u32 owner;
};

static u64 qcom_smccc_convention = -1;
@@ -62,14 +65,16 @@ static DEFINE_MUTEX(qcom_scm_lock);
#define SMCCC_N_EXT_ARGS (MAX_QCOM_SCM_ARGS - SMCCC_N_REG_ARGS + 1)

static void __qcom_scm_call_do_quirk(const struct qcom_scm_desc *desc,
- struct arm_smccc_res *res, u32 fn_id,
- u64 x5, u32 type)
+ struct arm_smccc_res *res, u64 x5, u32 type)
{
u64 cmd;
struct arm_smccc_quirk quirk = { .id = ARM_SMCCC_QUIRK_QCOM_A6 };

- cmd = ARM_SMCCC_CALL_VAL(type, qcom_smccc_convention,
- ARM_SMCCC_OWNER_SIP, fn_id);
+ cmd = ARM_SMCCC_CALL_VAL(
+ type,
+ qcom_smccc_convention,
+ desc->owner,
+ SMCCC_FUNCNUM(desc->svc, desc->cmd));

quirk.state.a6 = 0;

@@ -85,22 +90,19 @@ static void __qcom_scm_call_do_quirk(const struct qcom_scm_desc *desc,
}

static void qcom_scm_call_do_smccc(const struct qcom_scm_desc *desc,
- struct arm_smccc_res *res, u32 fn_id,
- u64 x5, bool atomic)
+ struct arm_smccc_res *res, u64 x5, bool atomic)
{
int retry_count = 0;

if (atomic) {
- __qcom_scm_call_do_quirk(desc, res, fn_id, x5,
- ARM_SMCCC_FAST_CALL);
+ __qcom_scm_call_do_quirk(desc, res, x5, ARM_SMCCC_FAST_CALL);
return;
}

do {
mutex_lock(&qcom_scm_lock);

- __qcom_scm_call_do_quirk(desc, res, fn_id, x5,
- ARM_SMCCC_STD_CALL);
+ __qcom_scm_call_do_quirk(desc, res, x5, ARM_SMCCC_STD_CALL);

mutex_unlock(&qcom_scm_lock);

@@ -112,13 +114,12 @@ static void qcom_scm_call_do_smccc(const struct qcom_scm_desc *desc,
} while (res->a0 == QCOM_SCM_V2_EBUSY);
}

-static int ___qcom_scm_call_smccc(struct device *dev, u32 svc_id, u32 cmd_id,
+static int ___qcom_scm_call_smccc(struct device *dev,
const struct qcom_scm_desc *desc,
struct arm_smccc_res *res, bool atomic)
{
int arglen = desc->arginfo & 0xf;
int i;
- u32 fn_id = SMCCC_FUNCNUM(svc_id, cmd_id);
u64 x5 = desc->args[SMCCC_N_REG_ARGS - 1];
dma_addr_t args_phys = 0;
void *args_virt = NULL;
@@ -157,7 +158,7 @@ static int ___qcom_scm_call_smccc(struct device *dev, u32 svc_id, u32 cmd_id,
x5 = args_phys;
}

- qcom_scm_call_do_smccc(desc, res, fn_id, x5, atomic);
+ qcom_scm_call_do_smccc(desc, res, x5, atomic);

if (args_virt) {
dma_unmap_single(dev, args_phys, alloc_len, DMA_TO_DEVICE);
@@ -180,12 +181,11 @@ static int ___qcom_scm_call_smccc(struct device *dev, u32 svc_id, u32 cmd_id,
* 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, u32 svc_id, u32 cmd_id,
- const struct qcom_scm_desc *desc,
+static int qcom_scm_call(struct device *dev, const struct qcom_scm_desc *desc,
struct arm_smccc_res *res)
{
might_sleep();
- return ___qcom_scm_call_smccc(dev, svc_id, cmd_id, desc, res, false);
+ return ___qcom_scm_call_smccc(dev, desc, res, false);
}

/**
@@ -199,11 +199,11 @@ static int qcom_scm_call(struct device *dev, u32 svc_id, u32 cmd_id,
* 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, u32 svc_id, u32 cmd_id,
+static int qcom_scm_call_atomic(struct device *dev,
const struct qcom_scm_desc *desc,
struct arm_smccc_res *res)
{
- return ___qcom_scm_call_smccc(dev, svc_id, cmd_id, desc, res, true);
+ return ___qcom_scm_call_smccc(dev, desc, res, true);
}

/**
@@ -248,7 +248,11 @@ void __qcom_scm_cpu_power_down(u32 flags)

int __qcom_scm_set_remote_state(struct device *dev, u32 state, u32 id)
{
- struct qcom_scm_desc desc = {0};
+ struct qcom_scm_desc desc = {
+ .svc = QCOM_SCM_SVC_BOOT,
+ .cmd = QCOM_SCM_BOOT_SET_REMOTE_STATE,
+ .owner = ARM_SMCCC_OWNER_SIP,
+ };
struct arm_smccc_res res;
int ret;

@@ -256,37 +260,41 @@ int __qcom_scm_set_remote_state(struct device *dev, u32 state, u32 id)
desc.args[1] = id;
desc.arginfo = QCOM_SCM_ARGS(2);

- ret = qcom_scm_call(dev, QCOM_SCM_SVC_BOOT, QCOM_SCM_BOOT_SET_REMOTE_STATE,
- &desc, &res);
+ ret = qcom_scm_call(dev, &desc, &res);

return ret ? : res.a1;
}

int __qcom_scm_set_dload_mode(struct device *dev, bool enable)
{
- struct qcom_scm_desc desc = {0};
+ struct qcom_scm_desc desc = {
+ .svc = QCOM_SCM_SVC_BOOT,
+ .cmd = QCOM_SCM_BOOT_SET_DLOAD_MODE,
+ .owner = ARM_SMCCC_OWNER_SIP,
+ };
struct arm_smccc_res res;

desc.args[0] = QCOM_SCM_BOOT_SET_DLOAD_MODE;
desc.args[1] = enable ? QCOM_SCM_BOOT_SET_DLOAD_MODE : 0;
desc.arginfo = QCOM_SCM_ARGS(2);

- return qcom_scm_call(dev, QCOM_SCM_SVC_BOOT, QCOM_SCM_BOOT_SET_DLOAD_MODE,
- &desc, &res);
+ return qcom_scm_call(dev, &desc, &res);
}

bool __qcom_scm_pas_supported(struct device *dev, u32 peripheral)
{
int ret;
- struct qcom_scm_desc desc = {0};
+ struct qcom_scm_desc desc = {
+ .svc = QCOM_SCM_SVC_PIL,
+ .cmd = QCOM_SCM_PIL_PAS_IS_SUPPORTED,
+ .owner = ARM_SMCCC_OWNER_SIP,
+ };
struct arm_smccc_res res;

desc.args[0] = peripheral;
desc.arginfo = QCOM_SCM_ARGS(1);

- ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL,
- QCOM_SCM_PIL_PAS_IS_SUPPORTED,
- &desc, &res);
+ ret = qcom_scm_call(dev, &desc, &res);

return ret ? false : !!res.a1;
}
@@ -295,15 +303,18 @@ int __qcom_scm_pas_init_image(struct device *dev, u32 peripheral,
dma_addr_t metadata_phys)
{
int ret;
- struct qcom_scm_desc desc = {0};
+ struct qcom_scm_desc desc = {
+ .svc = QCOM_SCM_SVC_PIL,
+ .cmd = QCOM_SCM_PIL_PAS_INIT_IMAGE,
+ .owner = ARM_SMCCC_OWNER_SIP,
+ };
struct arm_smccc_res res;

desc.args[0] = peripheral;
desc.args[1] = metadata_phys;
desc.arginfo = QCOM_SCM_ARGS(2, QCOM_SCM_VAL, QCOM_SCM_RW);

- ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL, QCOM_SCM_PIL_PAS_INIT_IMAGE,
- &desc, &res);
+ ret = qcom_scm_call(dev, &desc, &res);

return ret ? : res.a1;
}
@@ -312,7 +323,11 @@ int __qcom_scm_pas_mem_setup(struct device *dev, u32 peripheral,
phys_addr_t addr, phys_addr_t size)
{
int ret;
- struct qcom_scm_desc desc = {0};
+ struct qcom_scm_desc desc = {
+ .svc = QCOM_SCM_SVC_PIL,
+ .cmd = QCOM_SCM_PIL_PAS_MEM_SETUP,
+ .owner = ARM_SMCCC_OWNER_SIP,
+ };
struct arm_smccc_res res;

desc.args[0] = peripheral;
@@ -320,8 +335,7 @@ int __qcom_scm_pas_mem_setup(struct device *dev, u32 peripheral,
desc.args[2] = size;
desc.arginfo = QCOM_SCM_ARGS(3);

- ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL, QCOM_SCM_PIL_PAS_MEM_SETUP,
- &desc, &res);
+ ret = qcom_scm_call(dev, &desc, &res);

return ret ? : res.a1;
}
@@ -329,15 +343,17 @@ int __qcom_scm_pas_mem_setup(struct device *dev, u32 peripheral,
int __qcom_scm_pas_auth_and_reset(struct device *dev, u32 peripheral)
{
int ret;
- struct qcom_scm_desc desc = {0};
+ struct qcom_scm_desc desc = {
+ .svc = QCOM_SCM_SVC_PIL,
+ .cmd = QCOM_SCM_PIL_PAS_AUTH_AND_RESET,
+ .owner = ARM_SMCCC_OWNER_SIP,
+ };
struct arm_smccc_res res;

desc.args[0] = peripheral;
desc.arginfo = QCOM_SCM_ARGS(1);

- ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL,
- QCOM_SCM_PIL_PAS_AUTH_AND_RESET,
- &desc, &res);
+ ret = qcom_scm_call(dev, &desc, &res);

return ret ? : res.a1;
}
@@ -345,21 +361,28 @@ int __qcom_scm_pas_auth_and_reset(struct device *dev, u32 peripheral)
int __qcom_scm_pas_shutdown(struct device *dev, u32 peripheral)
{
int ret;
- struct qcom_scm_desc desc = {0};
+ struct qcom_scm_desc desc = {
+ .svc = QCOM_SCM_SVC_PIL,
+ .cmd = QCOM_SCM_PIL_PAS_SHUTDOWN,
+ .owner = ARM_SMCCC_OWNER_SIP,
+ };
struct arm_smccc_res res;

desc.args[0] = peripheral;
desc.arginfo = QCOM_SCM_ARGS(1);

- ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL, QCOM_SCM_PIL_PAS_SHUTDOWN,
- &desc, &res);
+ ret = qcom_scm_call(dev, &desc, &res);

return ret ? : res.a1;
}

int __qcom_scm_pas_mss_reset(struct device *dev, bool reset)
{
- struct qcom_scm_desc desc = {0};
+ struct qcom_scm_desc desc = {
+ .svc = QCOM_SCM_SVC_PIL,
+ .cmd = QCOM_SCM_PIL_PAS_MSS_RESET,
+ .owner = ARM_SMCCC_OWNER_SIP,
+ };
struct arm_smccc_res res;
int ret;

@@ -367,8 +390,7 @@ int __qcom_scm_pas_mss_reset(struct device *dev, bool reset)
desc.args[1] = 0;
desc.arginfo = QCOM_SCM_ARGS(2);

- ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL, QCOM_SCM_PIL_PAS_MSS_RESET, &desc,
- &res);
+ ret = qcom_scm_call(dev, &desc, &res);

return ret ? : res.a1;
}
@@ -376,15 +398,18 @@ int __qcom_scm_pas_mss_reset(struct device *dev, bool reset)
int __qcom_scm_io_readl(struct device *dev, phys_addr_t addr,
unsigned int *val)
{
- struct qcom_scm_desc desc = {0};
+ struct qcom_scm_desc desc = {
+ .svc = QCOM_SCM_SVC_IO,
+ .cmd = QCOM_SCM_IO_READ,
+ .owner = ARM_SMCCC_OWNER_SIP,
+ };
struct arm_smccc_res res;
int ret;

desc.args[0] = addr;
desc.arginfo = QCOM_SCM_ARGS(1);

- ret = qcom_scm_call(dev, QCOM_SCM_SVC_IO, QCOM_SCM_IO_READ,
- &desc, &res);
+ ret = qcom_scm_call(dev, &desc, &res);
if (ret >= 0)
*val = res.a1;

@@ -393,36 +418,46 @@ int __qcom_scm_io_readl(struct device *dev, phys_addr_t addr,

int __qcom_scm_io_writel(struct device *dev, phys_addr_t addr, unsigned int val)
{
- struct qcom_scm_desc desc = {0};
+ struct qcom_scm_desc desc = {
+ .svc = QCOM_SCM_SVC_IO,
+ .cmd = QCOM_SCM_IO_WRITE,
+ .owner = ARM_SMCCC_OWNER_SIP,
+ };
struct arm_smccc_res res;

desc.args[0] = addr;
desc.args[1] = val;
desc.arginfo = QCOM_SCM_ARGS(2);

- return qcom_scm_call(dev, QCOM_SCM_SVC_IO, QCOM_SCM_IO_WRITE,
- &desc, &res);
+ return qcom_scm_call(dev, &desc, &res);
}

int __qcom_scm_is_call_available(struct device *dev, u32 svc_id, u32 cmd_id)
{
int ret;
- struct qcom_scm_desc desc = {0};
+ struct qcom_scm_desc desc = {
+ .svc = QCOM_SCM_SVC_INFO,
+ .cmd = QCOM_SCM_INFO_IS_CALL_AVAIL,
+ .owner = ARM_SMCCC_OWNER_SIP,
+ };
struct arm_smccc_res res;

desc.arginfo = QCOM_SCM_ARGS(1);
desc.args[0] = SMCCC_FUNCNUM(svc_id, cmd_id) |
(ARM_SMCCC_OWNER_SIP << ARM_SMCCC_OWNER_SHIFT);

- ret = qcom_scm_call(dev, QCOM_SCM_SVC_INFO, QCOM_SCM_INFO_IS_CALL_AVAIL,
- &desc, &res);
+ ret = qcom_scm_call(dev, &desc, &res);

return ret ? : res.a1;
}

int __qcom_scm_restore_sec_cfg(struct device *dev, u32 device_id, u32 spare)
{
- struct qcom_scm_desc desc = {0};
+ struct qcom_scm_desc desc = {
+ .svc = QCOM_SCM_SVC_MP,
+ .cmd = QCOM_SCM_MP_RESTORE_SEC_CFG,
+ .owner = ARM_SMCCC_OWNER_SIP,
+ };
struct arm_smccc_res res;
int ret;

@@ -430,8 +465,7 @@ int __qcom_scm_restore_sec_cfg(struct device *dev, u32 device_id, u32 spare)
desc.args[1] = spare;
desc.arginfo = QCOM_SCM_ARGS(2);

- ret = qcom_scm_call(dev, QCOM_SCM_SVC_MP, QCOM_SCM_MP_RESTORE_SEC_CFG,
- &desc, &res);
+ ret = qcom_scm_call(dev, &desc, &res);

return ret ? : res.a1;
}
@@ -439,15 +473,18 @@ int __qcom_scm_restore_sec_cfg(struct device *dev, u32 device_id, u32 spare)
int __qcom_scm_iommu_secure_ptbl_size(struct device *dev, u32 spare,
size_t *size)
{
- struct qcom_scm_desc desc = {0};
+ struct qcom_scm_desc desc = {
+ .svc = QCOM_SCM_SVC_MP,
+ .cmd = QCOM_SCM_MP_IOMMU_SECURE_PTBL_SIZE,
+ .owner = ARM_SMCCC_OWNER_SIP,
+ };
struct arm_smccc_res res;
int ret;

desc.args[0] = spare;
desc.arginfo = QCOM_SCM_ARGS(1);

- ret = qcom_scm_call(dev, QCOM_SCM_SVC_MP,
- QCOM_SCM_MP_IOMMU_SECURE_PTBL_SIZE, &desc, &res);
+ ret = qcom_scm_call(dev, &desc, &res);

if (size)
*size = res.a1;
@@ -458,7 +495,11 @@ int __qcom_scm_iommu_secure_ptbl_size(struct device *dev, u32 spare,
int __qcom_scm_iommu_secure_ptbl_init(struct device *dev, u64 addr, u32 size,
u32 spare)
{
- struct qcom_scm_desc desc = {0};
+ struct qcom_scm_desc desc = {
+ .svc = QCOM_SCM_SVC_MP,
+ .cmd = QCOM_SCM_MP_IOMMU_SECURE_PTBL_INIT,
+ .owner = ARM_SMCCC_OWNER_SIP,
+ };
struct arm_smccc_res res;
int ret;

@@ -468,8 +509,7 @@ int __qcom_scm_iommu_secure_ptbl_init(struct device *dev, u64 addr, u32 size,
desc.arginfo = QCOM_SCM_ARGS(3, QCOM_SCM_RW, QCOM_SCM_VAL,
QCOM_SCM_VAL);

- ret = qcom_scm_call(dev, QCOM_SCM_SVC_MP,
- QCOM_SCM_MP_IOMMU_SECURE_PTBL_INIT, &desc, &res);
+ ret = qcom_scm_call(dev, &desc, &res);

/* the pg table has been initialized already, ignore the error */
if (ret == -EPERM)
@@ -483,7 +523,11 @@ int __qcom_scm_assign_mem(struct device *dev, phys_addr_t mem_region,
phys_addr_t dest, size_t dest_sz)
{
int ret;
- struct qcom_scm_desc desc = {0};
+ struct qcom_scm_desc desc = {
+ .svc = QCOM_SCM_SVC_MP,
+ .cmd = QCOM_SCM_MP_ASSIGN,
+ .owner = ARM_SMCCC_OWNER_SIP,
+ };
struct arm_smccc_res res;

desc.args[0] = mem_region;
@@ -498,9 +542,7 @@ int __qcom_scm_assign_mem(struct device *dev, phys_addr_t mem_region,
QCOM_SCM_RO, QCOM_SCM_VAL, QCOM_SCM_RO,
QCOM_SCM_VAL, QCOM_SCM_VAL);

- ret = qcom_scm_call(dev, QCOM_SCM_SVC_MP,
- QCOM_SCM_MP_ASSIGN,
- &desc, &res);
+ ret = qcom_scm_call(dev, &desc, &res);

return ret ? : res.a1;
}
@@ -509,7 +551,11 @@ int __qcom_scm_hdcp_req(struct device *dev, struct qcom_scm_hdcp_req *req,
u32 req_cnt, u32 *resp)
{
int ret;
- struct qcom_scm_desc desc = {0};
+ struct qcom_scm_desc desc = {
+ .svc = QCOM_SCM_SVC_HDCP,
+ .cmd = QCOM_SCM_HDCP_INVOKE,
+ .owner = ARM_SMCCC_OWNER_SIP,
+ };
struct arm_smccc_res res;

if (req_cnt > QCOM_SCM_HDCP_MAX_REQ_CNT)
@@ -527,8 +573,7 @@ int __qcom_scm_hdcp_req(struct device *dev, struct qcom_scm_hdcp_req *req,
desc.args[9] = req[4].val;
desc.arginfo = QCOM_SCM_ARGS(10);

- ret = qcom_scm_call(dev, QCOM_SCM_SVC_HDCP, QCOM_SCM_HDCP_INVOKE, &desc,
- &res);
+ ret = qcom_scm_call(dev, &desc, &res);
*resp = res.a1;

return ret;
@@ -536,15 +581,18 @@ int __qcom_scm_hdcp_req(struct device *dev, struct qcom_scm_hdcp_req *req,

int __qcom_scm_qsmmu500_wait_safe_toggle(struct device *dev, bool en)
{
- struct qcom_scm_desc desc = {0};
+ struct qcom_scm_desc desc = {
+ .svc = QCOM_SCM_SVC_SMMU_PROGRAM,
+ .cmd = QCOM_SCM_SMMU_CONFIG_ERRATA1,
+ .owner = ARM_SMCCC_OWNER_SIP,
+ };
struct arm_smccc_res res;

desc.args[0] = QCOM_SCM_SMMU_CONFIG_ERRATA1_CLIENT_ALL;
desc.args[1] = en;
desc.arginfo = QCOM_SCM_ARGS(2);

- return qcom_scm_call_atomic(dev, QCOM_SCM_SVC_SMMU_PROGRAM,
- QCOM_SCM_SMMU_CONFIG_ERRATA1, &desc, &res);
+ return qcom_scm_call_atomic(dev, &desc, &res);
}

void __qcom_scm_init(void)
--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project

2019-11-05 01:32:52

by Elliot Berman

[permalink] [raw]
Subject: [PATCH 17/17] firmware: qcom_scm: Rename -64 -> -smc, remove -32

- Rename qcom_scm-64.c to qcom_scm-smc as it supports SMC-based calling conventions
for 32 and 64-bit targets
- Remove qcom_scm-32.c as it has been superceded by qcom_scm-smc.c
- Update Kconfig to select QCOM_SCM_TRANSPORT_SMC on ARM and ARM64
targets

Signed-off-by: Elliot Berman <[email protected]>
---
drivers/firmware/Kconfig | 18 +-
drivers/firmware/Makefile | 4 +-
drivers/firmware/qcom_scm-32.c | 660 ----------------------------
drivers/firmware/qcom_scm-64.c | 949 ----------------------------------------
drivers/firmware/qcom_scm-smc.c | 949 ++++++++++++++++++++++++++++++++++++++++
5 files changed, 961 insertions(+), 1619 deletions(-)
delete mode 100644 drivers/firmware/qcom_scm-32.c
delete mode 100644 drivers/firmware/qcom_scm-64.c
create mode 100644 drivers/firmware/qcom_scm-smc.c

diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig
index e40a77b..ad477ca 100644
--- a/drivers/firmware/Kconfig
+++ b/drivers/firmware/Kconfig
@@ -236,16 +236,20 @@ config INTEL_STRATIX10_RSU

config QCOM_SCM
bool
- depends on ARM || ARM64
+ depends on QCOM_SCM_TRANSPORT_SMC
select RESET_CONTROLLER
+ help
+ This option enables support for communicating with
+ Qualcomm secure worlds.

-config QCOM_SCM_32
- def_bool y
- depends on QCOM_SCM && ARM
-
-config QCOM_SCM_64
+config QCOM_SCM_TRANSPORT_SMC
def_bool y
- depends on QCOM_SCM && ARM64
+ depends on ARM || ARM64
+ help
+ This option enables support for communicating with
+ Qualcomm secure worlds via the SMC instruction, using
+ either ARM SMCCC or legacy calling convention by querying
+ the Qualcomm secure world.

config QCOM_SCM_DOWNLOAD_MODE_DEFAULT
bool "Qualcomm download mode enabled by default"
diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile
index 3fcb919..fc250f0 100644
--- a/drivers/firmware/Makefile
+++ b/drivers/firmware/Makefile
@@ -18,9 +18,7 @@ obj-$(CONFIG_FIRMWARE_MEMMAP) += memmap.o
obj-$(CONFIG_RASPBERRYPI_FIRMWARE) += raspberrypi.o
obj-$(CONFIG_FW_CFG_SYSFS) += qemu_fw_cfg.o
obj-$(CONFIG_QCOM_SCM) += qcom_scm.o
-obj-$(CONFIG_QCOM_SCM_64) += qcom_scm-64.o
-obj-$(CONFIG_QCOM_SCM_32) += qcom_scm-32.o
-CFLAGS_qcom_scm-32.o :=$(call as-instr,.arch armv7-a\n.arch_extension sec,-DREQUIRES_SEC=1) -march=armv7-a
+obj-$(CONFIG_QCOM_SCM_TRANSPORT_SMC) += qcom_scm-smc.o
obj-$(CONFIG_TI_SCI_PROTOCOL) += ti_sci.o
obj-$(CONFIG_TRUSTED_FOUNDATIONS) += trusted_foundations.o
obj-$(CONFIG_TURRIS_MOX_RWTM) += turris-mox-rwtm.o
diff --git a/drivers/firmware/qcom_scm-32.c b/drivers/firmware/qcom_scm-32.c
deleted file mode 100644
index 3325c21..0000000
--- a/drivers/firmware/qcom_scm-32.c
+++ /dev/null
@@ -1,660 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/* Copyright (c) 2010,2015,2019 The Linux Foundation. All rights reserved.
- * Copyright (C) 2015 Linaro Ltd.
- */
-
-#include <linux/slab.h>
-#include <linux/io.h>
-#include <linux/module.h>
-#include <linux/mutex.h>
-#include <linux/errno.h>
-#include <linux/err.h>
-#include <linux/qcom_scm.h>
-#include <linux/arm-smccc.h>
-#include <linux/dma-mapping.h>
-
-#include "qcom_scm.h"
-
-#define QCOM_SCM_FLAG_COLDBOOT_CPU0 0x00
-#define QCOM_SCM_FLAG_COLDBOOT_CPU1 0x01
-#define QCOM_SCM_FLAG_COLDBOOT_CPU2 0x08
-#define QCOM_SCM_FLAG_COLDBOOT_CPU3 0x20
-
-#define QCOM_SCM_FLAG_WARMBOOT_CPU0 0x04
-#define QCOM_SCM_FLAG_WARMBOOT_CPU1 0x02
-#define QCOM_SCM_FLAG_WARMBOOT_CPU2 0x10
-#define QCOM_SCM_FLAG_WARMBOOT_CPU3 0x40
-
-struct qcom_scm_entry {
- int flag;
- void *entry;
-};
-
-static struct qcom_scm_entry qcom_scm_wb[] = {
- { .flag = QCOM_SCM_FLAG_WARMBOOT_CPU0 },
- { .flag = QCOM_SCM_FLAG_WARMBOOT_CPU1 },
- { .flag = QCOM_SCM_FLAG_WARMBOOT_CPU2 },
- { .flag = QCOM_SCM_FLAG_WARMBOOT_CPU3 },
-};
-
-static DEFINE_MUTEX(qcom_scm_lock);
-
-#define MAX_QCOM_SCM_ARGS 10
-#define MAX_QCOM_SCM_RETS 3
-
-enum qcom_scm_arg_types {
- QCOM_SCM_VAL,
- QCOM_SCM_RO,
- QCOM_SCM_RW,
- QCOM_SCM_BUFVAL,
-};
-
-#define QCOM_SCM_ARGS_IMPL(num, a, b, c, d, e, f, g, h, i, j, ...) (\
- (((a) & 0x3) << 4) | \
- (((b) & 0x3) << 6) | \
- (((c) & 0x3) << 8) | \
- (((d) & 0x3) << 10) | \
- (((e) & 0x3) << 12) | \
- (((f) & 0x3) << 14) | \
- (((g) & 0x3) << 16) | \
- (((h) & 0x3) << 18) | \
- (((i) & 0x3) << 20) | \
- (((j) & 0x3) << 22) | \
- ((num) & 0xf))
-
-#define QCOM_SCM_ARGS(...) QCOM_SCM_ARGS_IMPL(__VA_ARGS__, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
-
-/**
- * struct qcom_scm_desc
- * @arginfo: Metadata describing the arguments in args[]
- * @args: The array of arguments for the secure syscall
- * @res: The values returned by the secure syscall
- */
-struct qcom_scm_desc {
- u32 svc;
- u32 cmd;
- u32 arginfo;
- u64 args[MAX_QCOM_SCM_ARGS];
- u64 res[MAX_QCOM_SCM_RETS];
- u32 owner;
-};
-struct arm_smccc_args {
- unsigned long a[8];
-};
-
-#define LEGACY_FUNCNUM(s, c) (((s) << 10) | ((c) & 0x3ff))
-
-/**
- * struct legacy_command - one SCM command buffer
- * @len: total available memory for command and response
- * @buf_offset: start of command buffer
- * @resp_hdr_offset: start of response buffer
- * @id: command to be executed
- * @buf: buffer returned from legacy_get_command_buffer()
- *
- * An SCM command is laid out in memory as follows:
- *
- * ------------------- <--- struct legacy_command
- * | command header |
- * ------------------- <--- legacy_get_command_buffer()
- * | command buffer |
- * ------------------- <--- struct legacy_response and
- * | response header | legacy_command_to_response()
- * ------------------- <--- legacy_get_response_buffer()
- * | response buffer |
- * -------------------
- *
- * There can be arbitrary padding between the headers and buffers so
- * you should always use the appropriate qcom_scm_get_*_buffer() routines
- * to access the buffers in a safe manner.
- */
-struct legacy_command {
- __le32 len;
- __le32 buf_offset;
- __le32 resp_hdr_offset;
- __le32 id;
- __le32 buf[0];
-};
-
-/**
- * struct legacy_response - one SCM response buffer
- * @len: total available memory for response
- * @buf_offset: start of response data relative to start of legacy_response
- * @is_complete: indicates if the command has finished processing
- */
-struct legacy_response {
- __le32 len;
- __le32 buf_offset;
- __le32 is_complete;
-};
-
-/**
- * legacy_command_to_response() - Get a pointer to a legacy_response
- * @cmd: command
- *
- * Returns a pointer to a response for a command.
- */
-static inline struct legacy_response *legacy_command_to_response(
- const struct legacy_command *cmd)
-{
- return (void *)cmd + le32_to_cpu(cmd->resp_hdr_offset);
-}
-
-/**
- * legacy_get_command_buffer() - Get a pointer to a command buffer
- * @cmd: command
- *
- * Returns a pointer to the command buffer of a command.
- */
-static inline void *legacy_get_command_buffer(const struct legacy_command *cmd)
-{
- return (void *)cmd->buf;
-}
-
-/**
- * legacy_get_response_buffer() - Get a pointer to a response buffer
- * @rsp: response
- *
- * Returns a pointer to a response buffer of a response.
- */
-static inline void *legacy_get_response_buffer(const struct legacy_response *rsp)
-{
- return (void *)rsp + le32_to_cpu(rsp->buf_offset);
-}
-
-static void __qcom_scm_call_do(const struct arm_smccc_args *smc,
- struct arm_smccc_res *res)
-{
- do {
- arm_smccc_smc(smc->a[0], smc->a[1], smc->a[2], smc->a[3],
- smc->a[4], smc->a[5], smc->a[6], smc->a[7], res);
- } while (res->a0 == QCOM_SCM_INTERRUPTED);
-}
-
-/**
- * qcom_scm_call() - Send an SCM command
- * @dev: struct device
- * @svc_id: service identifier
- * @cmd_id: command identifier
- * @cmd_buf: command buffer
- * @cmd_len: length of the command buffer
- * @resp_buf: response buffer
- * @resp_len: length of the response buffer
- *
- * Sends a command to the SCM and waits for the command to finish processing.
- *
- * A note on cache maintenance:
- * Note that any buffers that are expected to be accessed by the secure world
- * must be flushed before invoking qcom_scm_call and invalidated in the cache
- * immediately after qcom_scm_call returns. Cache maintenance on the command
- * 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.
- */
-static int qcom_scm_call(struct device *dev, struct qcom_scm_desc *desc)
-{
- int arglen = desc->arginfo & 0xf;
- int ret = 0, context_id;
- size_t i;
- struct legacy_command *cmd;
- struct legacy_response *rsp;
- struct arm_smccc_args smc = {0};
- struct arm_smccc_res res;
- const size_t cmd_len = arglen * sizeof(__le32);
- const size_t resp_len = MAX_QCOM_SCM_RETS * sizeof(__le32);
- size_t alloc_len = sizeof(*cmd) + cmd_len + sizeof(*rsp) + resp_len;
- dma_addr_t cmd_phys;
- __le32 *arg_buf;
- __le32 *res_buf;
-
- cmd = kzalloc(PAGE_ALIGN(alloc_len), GFP_KERNEL);
- if (!cmd)
- return -ENOMEM;
-
- cmd->len = cpu_to_le32(alloc_len);
- cmd->buf_offset = cpu_to_le32(sizeof(*cmd));
- cmd->resp_hdr_offset = cpu_to_le32(sizeof(*cmd) + cmd_len);
- cmd->id = cpu_to_le32(LEGACY_FUNCNUM(desc->svc, desc->cmd));
-
- arg_buf = legacy_get_command_buffer(cmd);
- for (i = 0; i < arglen; i++)
- arg_buf[i] = cpu_to_le32(desc->args[i]);
-
- rsp = legacy_command_to_response(cmd);
-
- cmd_phys = dma_map_single(dev, cmd, alloc_len, DMA_TO_DEVICE);
- if (dma_mapping_error(dev, cmd_phys)) {
- kfree(cmd);
- return -ENOMEM;
- }
-
- smc.a[0] = 1;
- smc.a[1] = (unsigned long)&context_id;
- smc.a[2] = cmd_phys;
-
- mutex_lock(&qcom_scm_lock);
- __qcom_scm_call_do(&smc, &res);
- if (res.a0 < 0)
- ret = qcom_scm_remap_error(res.a0);
- mutex_unlock(&qcom_scm_lock);
- if (ret)
- goto out;
-
- do {
- dma_sync_single_for_cpu(dev, cmd_phys + sizeof(*cmd) + cmd_len,
- sizeof(*rsp), DMA_FROM_DEVICE);
- } while (!rsp->is_complete);
-
- dma_sync_single_for_cpu(dev, cmd_phys + sizeof(*cmd) + cmd_len +
- le32_to_cpu(rsp->buf_offset),
- resp_len, DMA_FROM_DEVICE);
-
- res_buf = legacy_get_response_buffer(rsp);
- for (i = 0; i < MAX_QCOM_SCM_RETS; i++)
- desc->res[i] = le32_to_cpu(res_buf[i]);
-out:
- dma_unmap_single(dev, cmd_phys, alloc_len, DMA_TO_DEVICE);
- kfree(cmd);
- return ret;
-}
-
-#define LEGACY_ATOMIC_N_REG_ARGS 5
-#define LEGACY_ATOMIC_FIRST_REG_IDX 2
-#define LEGACY_CLASS_REGISTER (0x2 << 8)
-#define LEGACY_MASK_IRQS BIT(5)
-#define LEGACY_ATOMIC(svc, cmd, n) ((LEGACY_FUNCNUM(svc, cmd) << 12) | \
- LEGACY_CLASS_REGISTER | \
- LEGACY_MASK_IRQS | \
- (n & 0xf))
-
-/**
- * qcom_scm_call_atomic() - Send an atomic SCM command with up to 5 arguments
- * and 3 return values
- *
- * This shall only be used with commands that are guaranteed to be
- * uninterruptable, atomic and SMP safe.
- */
-static int qcom_scm_call_atomic(struct device *dev, struct qcom_scm_desc *desc)
-{
- int context_id;
- struct arm_smccc_args smc = {0};
- struct arm_smccc_res res;
- size_t i, arglen = desc->arginfo & 0xf;
-
- BUG_ON(arglen > LEGACY_ATOMIC_N_REG_ARGS);
-
- smc.a[0] = LEGACY_ATOMIC(desc->svc, desc->cmd, arglen);
- smc.a[1] = (unsigned long)&context_id;
-
- for (i = 0; i < arglen; i++)
- smc.a[i + LEGACY_ATOMIC_FIRST_REG_IDX] = desc->args[i];
-
- arm_smccc_smc(smc.a[0], smc.a[1], smc.a[2], smc.a[3],
- smc.a[4], smc.a[5], smc.a[6], smc.a[7], &res);
-
- desc->res[0] = res.a1;
- desc->res[1] = res.a2;
- desc->res[2] = res.a3;
-
- return res.a0;
-}
-
-/**
- * qcom_scm_set_cold_boot_addr() - Set the cold boot address for cpus
- * @entry: Entry point function for the cpus
- * @cpus: The cpumask of cpus that will use the entry point
- *
- * Set the cold boot address of the cpus. Any cpu outside the supported
- * range would be removed from the cpu present mask.
- */
-int __qcom_scm_set_cold_boot_addr(struct device *dev, void *entry,
- const cpumask_t *cpus)
-{
- int flags = 0;
- int cpu;
- int scm_cb_flags[] = {
- QCOM_SCM_FLAG_COLDBOOT_CPU0,
- QCOM_SCM_FLAG_COLDBOOT_CPU1,
- QCOM_SCM_FLAG_COLDBOOT_CPU2,
- QCOM_SCM_FLAG_COLDBOOT_CPU3,
- };
- struct qcom_scm_desc desc = {
- .svc = QCOM_SCM_SVC_BOOT,
- .cmd = QCOM_SCM_BOOT_SET_ADDR,
- .owner = ARM_SMCCC_OWNER_SIP,
- };
-
- if (!cpus || (cpus && cpumask_empty(cpus)))
- return -EINVAL;
-
- for_each_cpu(cpu, cpus) {
- if (cpu < ARRAY_SIZE(scm_cb_flags))
- flags |= scm_cb_flags[cpu];
- else
- set_cpu_present(cpu, false);
- }
-
- desc.args[0] = flags;
- desc.args[1] = virt_to_phys(entry);
- desc.arginfo = QCOM_SCM_ARGS(2);
-
- return qcom_scm_call_atomic(dev, &desc);
-}
-
-/**
- * qcom_scm_set_warm_boot_addr() - Set the warm boot address for cpus
- * @entry: Entry point function for the cpus
- * @cpus: The cpumask of cpus that will use the entry point
- *
- * Set the Linux entry point for the SCM to transfer control to when coming
- * out of a power down. CPU power down may be executed on cpuidle or hotplug.
- */
-int __qcom_scm_set_warm_boot_addr(struct device *dev, void *entry,
- const cpumask_t *cpus)
-{
- int ret;
- int flags = 0;
- int cpu;
- struct qcom_scm_desc desc = {
- .svc = QCOM_SCM_SVC_BOOT,
- .cmd = QCOM_SCM_BOOT_SET_ADDR,
- .arginfo = QCOM_SCM_ARGS(2),
- };
-
- /*
- * Reassign only if we are switching from hotplug entry point
- * to cpuidle entry point or vice versa.
- */
- for_each_cpu(cpu, cpus) {
- if (entry == qcom_scm_wb[cpu].entry)
- continue;
- flags |= qcom_scm_wb[cpu].flag;
- }
-
- /* No change in entry function */
- if (!flags)
- return 0;
-
- desc.args[0] = flags;
- desc.args[1] = virt_to_phys(entry);
- ret = qcom_scm_call(dev, &desc);
- if (!ret) {
- for_each_cpu(cpu, cpus)
- qcom_scm_wb[cpu].entry = entry;
- }
-
- return ret;
-}
-
-/**
- * qcom_scm_cpu_power_down() - Power down the cpu
- * @flags - Flags to flush cache
- *
- * This is an end point to power down cpu. If there was a pending interrupt,
- * the control would return from this function, otherwise, the cpu jumps to the
- * warm boot entry point set for this cpu upon reset.
- */
-void __qcom_scm_cpu_power_down(struct device *dev, u32 flags)
-{
- struct qcom_scm_desc desc = {
- .svc = QCOM_SCM_SVC_BOOT,
- .cmd = QCOM_SCM_BOOT_TERMINATE_PC,
- .args[0] = flags & QCOM_SCM_FLUSH_FLAG_MASK,
- .arginfo = QCOM_SCM_ARGS(1),
- .owner = ARM_SMCCC_OWNER_SIP,
- };
-
- qcom_scm_call_atomic(dev, &desc);
-}
-
-int __qcom_scm_set_remote_state(struct device *dev, u32 state, u32 id)
-{
- struct qcom_scm_desc desc = {
- .svc = QCOM_SCM_SVC_BOOT,
- .cmd = QCOM_SCM_BOOT_SET_REMOTE_STATE,
- .owner = ARM_SMCCC_OWNER_SIP,
- };
- int ret;
-
- desc.args[0] = state;
- desc.args[1] = id;
- desc.arginfo = QCOM_SCM_ARGS(2);
-
- ret = qcom_scm_call(dev, &desc);
-
- return ret ? : desc.res[0];
-}
-
-int __qcom_scm_set_dload_mode(struct device *dev, bool enable)
-{
- struct qcom_scm_desc desc = {
- .svc = QCOM_SCM_SVC_BOOT,
- .cmd = QCOM_SCM_BOOT_SET_DLOAD_MODE,
- .owner = ARM_SMCCC_OWNER_SIP,
- };
-
- desc.args[0] = QCOM_SCM_BOOT_SET_DLOAD_MODE;
- desc.args[1] = enable ? QCOM_SCM_BOOT_SET_DLOAD_MODE : 0;
- desc.arginfo = QCOM_SCM_ARGS(2);
-
- return qcom_scm_call_atomic(dev, &desc);
-}
-
-bool __qcom_scm_pas_supported(struct device *dev, u32 peripheral)
-{
- int ret;
- struct qcom_scm_desc desc = {
- .svc = QCOM_SCM_SVC_PIL,
- .cmd = QCOM_SCM_PIL_PAS_IS_SUPPORTED,
- .owner = ARM_SMCCC_OWNER_SIP,
- };
-
- desc.args[0] = peripheral;
- desc.arginfo = QCOM_SCM_ARGS(1);
-
- ret = qcom_scm_call(dev, &desc);
-
- return ret ? false : !!desc.res[0];
-}
-
-int __qcom_scm_pas_init_image(struct device *dev, u32 peripheral,
- dma_addr_t metadata_phys)
-{
- int ret;
- struct qcom_scm_desc desc = {
- .svc = QCOM_SCM_SVC_PIL,
- .cmd = QCOM_SCM_PIL_PAS_INIT_IMAGE,
- .owner = ARM_SMCCC_OWNER_SIP,
- };
-
- desc.args[0] = peripheral;
- desc.args[1] = metadata_phys;
- desc.arginfo = QCOM_SCM_ARGS(2, QCOM_SCM_VAL, QCOM_SCM_RW);
-
- ret = qcom_scm_call(dev, &desc);
-
- return ret ? : desc.res[0];
-}
-
-int __qcom_scm_pas_mem_setup(struct device *dev, u32 peripheral,
- phys_addr_t addr, phys_addr_t size)
-{
- int ret;
- struct qcom_scm_desc desc = {
- .svc = QCOM_SCM_SVC_PIL,
- .cmd = QCOM_SCM_PIL_PAS_MEM_SETUP,
- .owner = ARM_SMCCC_OWNER_SIP,
- };
-
- desc.args[0] = peripheral;
- desc.args[1] = addr;
- desc.args[2] = size;
- desc.arginfo = QCOM_SCM_ARGS(3);
-
- ret = qcom_scm_call(dev, &desc);
-
- return ret ? : desc.res[0];
-}
-
-int __qcom_scm_pas_auth_and_reset(struct device *dev, u32 peripheral)
-{
- int ret;
- struct qcom_scm_desc desc = {
- .svc = QCOM_SCM_SVC_PIL,
- .cmd = QCOM_SCM_PIL_PAS_AUTH_AND_RESET,
- .owner = ARM_SMCCC_OWNER_SIP,
- };
-
- ret = qcom_scm_call(dev, &desc);
-
- return ret ? : desc.res[0];
-}
-
-int __qcom_scm_pas_shutdown(struct device *dev, u32 peripheral)
-{
- struct qcom_scm_desc desc = {
- .svc = QCOM_SCM_SVC_PIL,
- .cmd = QCOM_SCM_PIL_PAS_SHUTDOWN,
- .owner = ARM_SMCCC_OWNER_SIP,
- };
- int ret;
-
- desc.args[0] = peripheral;
- desc.arginfo = QCOM_SCM_ARGS(1);
-
- ret = qcom_scm_call(dev, &desc);
-
- return ret ? : desc.res[0];
-}
-
-int __qcom_scm_pas_mss_reset(struct device *dev, bool reset)
-{
- struct qcom_scm_desc desc = {
- .svc = QCOM_SCM_SVC_PIL,
- .cmd = QCOM_SCM_PIL_PAS_MSS_RESET,
- .owner = ARM_SMCCC_OWNER_SIP,
- };
- int ret;
-
- desc.args[0] = reset;
- desc.args[1] = 0;
- desc.arginfo = QCOM_SCM_ARGS(2);
-
- ret = qcom_scm_call(dev, &desc);
-
- return ret ? : desc.res[0];
-}
-
-int __qcom_scm_io_readl(struct device *dev, phys_addr_t addr,
- unsigned int *val)
-{
- int ret;
- struct qcom_scm_desc desc = {
- .svc = QCOM_SCM_SVC_IO,
- .cmd = QCOM_SCM_IO_READ,
- .owner = ARM_SMCCC_OWNER_SIP,
- };
-
- desc.args[0] = addr;
- desc.arginfo = QCOM_SCM_ARGS(1);
-
- ret = qcom_scm_call_atomic(dev, &desc);
- if (ret >= 0)
- *val = desc.res[0];
-
- return ret < 0 ? ret : 0;
-}
-
-int __qcom_scm_io_writel(struct device *dev, phys_addr_t addr, unsigned int val)
-{
- struct qcom_scm_desc desc = {
- .svc = QCOM_SCM_SVC_IO,
- .cmd = QCOM_SCM_IO_WRITE,
- .owner = ARM_SMCCC_OWNER_SIP,
- };
-
- desc.args[0] = addr;
- desc.args[1] = val;
- desc.arginfo = QCOM_SCM_ARGS(2);
-
- return qcom_scm_call_atomic(dev, &desc);
-}
-
-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] = (svc_id << 10) | cmd_id,
- .arginfo = QCOM_SCM_ARGS(1),
- };
-
- ret = qcom_scm_call(dev, &desc);
-
- return ret ? : desc.res[0];
-}
-
-int __qcom_scm_restore_sec_cfg(struct device *dev, u32 device_id,
- u32 spare)
-{
- return -ENODEV;
-}
-
-int __qcom_scm_iommu_secure_ptbl_size(struct device *dev, u32 spare,
- size_t *size)
-{
- return -ENODEV;
-}
-
-int __qcom_scm_iommu_secure_ptbl_init(struct device *dev, u64 addr, u32 size,
- u32 spare)
-{
- return -ENODEV;
-}
-
-int __qcom_scm_assign_mem(struct device *dev, phys_addr_t mem_region,
- size_t mem_sz, phys_addr_t src, size_t src_sz,
- phys_addr_t dest, size_t dest_sz)
-{
- return -ENODEV;
-}
-
-int __qcom_scm_hdcp_req(struct device *dev, struct qcom_scm_hdcp_req *req,
- u32 req_cnt, u32 *resp)
-{
- int ret;
- struct qcom_scm_desc desc = {
- .svc = QCOM_SCM_SVC_HDCP,
- .cmd = QCOM_SCM_HDCP_INVOKE,
- .owner = ARM_SMCCC_OWNER_SIP,
- };
-
- if (req_cnt > QCOM_SCM_HDCP_MAX_REQ_CNT)
- return -ERANGE;
-
- desc.args[0] = req[0].addr;
- desc.args[1] = req[0].val;
- desc.args[2] = req[1].addr;
- desc.args[3] = req[1].val;
- desc.args[4] = req[2].addr;
- desc.args[5] = req[2].val;
- desc.args[6] = req[3].addr;
- desc.args[7] = req[3].val;
- desc.args[8] = req[4].addr;
- desc.args[9] = req[4].val;
- desc.arginfo = QCOM_SCM_ARGS(req_cnt * 2);
-
- ret = qcom_scm_call(dev, &desc);
- *resp = desc.res[0];
-
- return ret;
-}
-
-int __qcom_scm_qsmmu500_wait_safe_toggle(struct device *dev, bool enable)
-{
- return -ENODEV;
-}
-
-void __qcom_scm_init(void)
-{
-}
diff --git a/drivers/firmware/qcom_scm-64.c b/drivers/firmware/qcom_scm-64.c
deleted file mode 100644
index 355d9d7..0000000
--- a/drivers/firmware/qcom_scm-64.c
+++ /dev/null
@@ -1,949 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/* Copyright (c) 2015,2019 The Linux Foundation. All rights reserved.
- */
-
-#include <linux/io.h>
-#include <linux/errno.h>
-#include <linux/delay.h>
-#include <linux/mutex.h>
-#include <linux/slab.h>
-#include <linux/types.h>
-#include <linux/qcom_scm.h>
-#include <linux/arm-smccc.h>
-#include <linux/dma-mapping.h>
-
-#include "qcom_scm.h"
-
-#define MAX_QCOM_SCM_ARGS 10
-#define MAX_QCOM_SCM_RETS 3
-
-enum qcom_scm_arg_types {
- QCOM_SCM_VAL,
- QCOM_SCM_RO,
- QCOM_SCM_RW,
- QCOM_SCM_BUFVAL,
-};
-
-#define QCOM_SCM_ARGS_IMPL(num, a, b, c, d, e, f, g, h, i, j, ...) (\
- (((a) & 0x3) << 4) | \
- (((b) & 0x3) << 6) | \
- (((c) & 0x3) << 8) | \
- (((d) & 0x3) << 10) | \
- (((e) & 0x3) << 12) | \
- (((f) & 0x3) << 14) | \
- (((g) & 0x3) << 16) | \
- (((h) & 0x3) << 18) | \
- (((i) & 0x3) << 20) | \
- (((j) & 0x3) << 22) | \
- ((num) & 0xf))
-
-#define QCOM_SCM_ARGS(...) QCOM_SCM_ARGS_IMPL(__VA_ARGS__, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
-
-/**
- * struct qcom_scm_desc
- * @arginfo: Metadata describing the arguments in args[]
- * @args: The array of arguments for the secure syscall
- * @res: The values returned by the secure syscall
- */
-struct qcom_scm_desc {
- u32 svc;
- u32 cmd;
- u32 arginfo;
- u64 args[MAX_QCOM_SCM_ARGS];
- u64 res[MAX_QCOM_SCM_RETS];
- u32 owner;
-};
-
-struct arm_smccc_args {
- unsigned long a[8];
-};
-
-enum qcom_smc_convention {
- SMC_CONVENTION_UNKNOWN,
- SMC_CONVENTION_LEGACY,
- SMC_CONVENTION_ARM_32,
- SMC_CONVENTION_ARM_64,
-};
-
-static enum qcom_smc_convention qcom_smc_convention = SMC_CONVENTION_UNKNOWN;
-static DEFINE_MUTEX(qcom_scm_lock);
-
-#define QCOM_SCM_EBUSY_WAIT_MS 30
-#define QCOM_SCM_EBUSY_MAX_RETRY 20
-
-#define SMCCC_FUNCNUM(s, c) ((((s) & 0xFF) << 8) | ((c) & 0xFF))
-#define SMCCC_N_REG_ARGS 4
-#define SMCCC_FIRST_REG_IDX 2
-#define SMCCC_N_EXT_ARGS (MAX_QCOM_SCM_ARGS - SMCCC_N_REG_ARGS + 1)
-#define SMCCC_LAST_REG_IDX (SMCCC_FIRST_REG_IDX + SMCCC_N_REG_ARGS - 1)
-
-static void __qcom_scm_call_do_quirk(const struct arm_smccc_args *smc,
- struct arm_smccc_res *res)
-{
- unsigned long a0 = smc->a[0];
- struct arm_smccc_quirk quirk = { .id = ARM_SMCCC_QUIRK_QCOM_A6 };
-
- quirk.state.a6 = 0;
-
- do {
- arm_smccc_smc_quirk(a0, smc->a[1], smc->a[2], smc->a[3],
- smc->a[4], smc->a[5], quirk.state.a6,
- smc->a[7], res, &quirk);
-
- if (res->a0 == QCOM_SCM_INTERRUPTED)
- a0 = res->a0;
-
- } while (res->a0 == QCOM_SCM_INTERRUPTED);
-}
-
-static int qcom_scm_call_smccc(struct device *dev,
- struct qcom_scm_desc *desc, bool atomic)
-{
- int arglen = desc->arginfo & 0xf;
- int i;
- dma_addr_t args_phys = 0;
- void *args_virt = NULL;
- size_t alloc_len;
- gfp_t flag = atomic ? GFP_ATOMIC : GFP_KERNEL;
- struct arm_smccc_res res;
- struct arm_smccc_args smc = {0};
-
- smc.a[0] = ARM_SMCCC_CALL_VAL(
- atomic ? ARM_SMCCC_FAST_CALL : ARM_SMCCC_STD_CALL,
- (qcom_smc_convention == SMC_CONVENTION_ARM_64) ?
- ARM_SMCCC_SMC_64 :
- ARM_SMCCC_SMC_32,
- desc->owner,
- SMCCC_FUNCNUM(desc->svc, desc->cmd));
- smc.a[1] = desc->arginfo;
- for (i = 0; i < SMCCC_N_REG_ARGS; i++)
- smc.a[i + SMCCC_FIRST_REG_IDX] = desc->args[i];
-
- if (unlikely(arglen > SMCCC_N_REG_ARGS)) {
- alloc_len = SMCCC_N_EXT_ARGS * sizeof(u64);
- args_virt = kzalloc(PAGE_ALIGN(alloc_len), flag);
-
- if (!args_virt)
- return -ENOMEM;
-
- if (qcom_smc_convention == SMC_CONVENTION_ARM_32) {
- __le32 *args = args_virt;
-
- for (i = 0; i < SMCCC_N_EXT_ARGS; i++)
- args[i] = cpu_to_le32(desc->args[i +
- SMCCC_N_REG_ARGS - 1]);
- } else {
- __le64 *args = args_virt;
-
- for (i = 0; i < SMCCC_N_EXT_ARGS; i++)
- args[i] = cpu_to_le64(desc->args[i +
- SMCCC_N_REG_ARGS - 1]);
- }
-
- args_phys = dma_map_single(dev, args_virt, alloc_len,
- DMA_TO_DEVICE);
-
- if (dma_mapping_error(dev, args_phys)) {
- kfree(args_virt);
- return -ENOMEM;
- }
-
- smc.a[SMCCC_LAST_REG_IDX] = args_phys;
- }
-
- if (atomic) {
- __qcom_scm_call_do_quirk(&smc, &res);
- } else {
- int retry_count = 0;
-
- do {
- mutex_lock(&qcom_scm_lock);
-
- __qcom_scm_call_do_quirk(&smc, &res);
-
- mutex_unlock(&qcom_scm_lock);
-
- if (res.a0 == QCOM_SCM_V2_EBUSY) {
- if (retry_count++ > QCOM_SCM_EBUSY_MAX_RETRY)
- break;
- msleep(QCOM_SCM_EBUSY_WAIT_MS);
- }
- } while (res.a0 == QCOM_SCM_V2_EBUSY);
- }
-
- if (args_virt) {
- dma_unmap_single(dev, args_phys, alloc_len, DMA_TO_DEVICE);
- kfree(args_virt);
- }
-
- desc->res[0] = res.a1;
- desc->res[1] = res.a2;
- desc->res[2] = res.a3;
-
- if (res.a0 < 0)
- return qcom_scm_remap_error(res.a0);
-
- return 0;
-}
-
-#define LEGACY_FUNCNUM(s, c) (((s) << 10) | ((c) & 0x3ff))
-
-/**
- * struct legacy_command - one SCM command buffer
- * @len: total available memory for command and response
- * @buf_offset: start of command buffer
- * @resp_hdr_offset: start of response buffer
- * @id: command to be executed
- * @buf: buffer returned from legacy_get_command_buffer()
- *
- * An SCM command is laid out in memory as follows:
- *
- * ------------------- <--- struct legacy_command
- * | command header |
- * ------------------- <--- legacy_get_command_buffer()
- * | command buffer |
- * ------------------- <--- struct legacy_response and
- * | response header | legacy_command_to_response()
- * ------------------- <--- legacy_get_response_buffer()
- * | response buffer |
- * -------------------
- *
- * There can be arbitrary padding between the headers and buffers so
- * you should always use the appropriate qcom_scm_get_*_buffer() routines
- * to access the buffers in a safe manner.
- */
-struct legacy_command {
- __le32 len;
- __le32 buf_offset;
- __le32 resp_hdr_offset;
- __le32 id;
- __le32 buf[0];
-};
-
-/**
- * struct legacy_response - one SCM response buffer
- * @len: total available memory for response
- * @buf_offset: start of response data relative to start of legacy_response
- * @is_complete: indicates if the command has finished processing
- */
-struct legacy_response {
- __le32 len;
- __le32 buf_offset;
- __le32 is_complete;
-};
-
-/**
- * legacy_command_to_response() - Get a pointer to a legacy_response
- * @cmd: command
- *
- * Returns a pointer to a response for a command.
- */
-static inline struct legacy_response *legacy_command_to_response(
- const struct legacy_command *cmd)
-{
- return (void *)cmd + le32_to_cpu(cmd->resp_hdr_offset);
-}
-
-/**
- * legacy_get_command_buffer() - Get a pointer to a command buffer
- * @cmd: command
- *
- * Returns a pointer to the command buffer of a command.
- */
-static inline void *legacy_get_command_buffer(const struct legacy_command *cmd)
-{
- return (void *)cmd->buf;
-}
-
-/**
- * legacy_get_response_buffer() - Get a pointer to a response buffer
- * @rsp: response
- *
- * Returns a pointer to a response buffer of a response.
- */
-static inline void *legacy_get_response_buffer(const struct legacy_response *rsp)
-{
- return (void *)rsp + le32_to_cpu(rsp->buf_offset);
-}
-
-static void __qcom_scm_call_do(const struct arm_smccc_args *smc,
- struct arm_smccc_res *res)
-{
- do {
- arm_smccc_smc(smc->a[0], smc->a[1], smc->a[2], smc->a[3],
- smc->a[4], smc->a[5], smc->a[6], smc->a[7], res);
- } while (res->a0 == QCOM_SCM_INTERRUPTED);
-}
-
-/**
- * qcom_scm_call_legacy() - Send an SCM command
- * @dev: struct device
- * @svc_id: service identifier
- * @cmd_id: command identifier
- * @cmd_buf: command buffer
- * @cmd_len: length of the command buffer
- * @resp_buf: response buffer
- * @resp_len: length of the response buffer
- *
- * Sends a command to the SCM and waits for the command to finish processing.
- *
- * A note on cache maintenance:
- * Note that any buffers that are expected to be accessed by the secure world
- * must be flushed before invoking qcom_scm_call and invalidated in the cache
- * immediately after qcom_scm_call returns. Cache maintenance on the command
- * 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.
- */
-static int qcom_scm_call_legacy(struct device *dev, struct qcom_scm_desc *desc)
-{
- int arglen = desc->arginfo & 0xf;
- int ret = 0, context_id;
- size_t i;
- struct legacy_command *cmd;
- struct legacy_response *rsp;
- struct arm_smccc_args smc = {0};
- struct arm_smccc_res res;
- const size_t cmd_len = arglen * sizeof(__le32);
- const size_t resp_len = MAX_QCOM_SCM_RETS * sizeof(__le32);
- size_t alloc_len = sizeof(*cmd) + cmd_len + sizeof(*rsp) + resp_len;
- dma_addr_t cmd_phys;
- __le32 *arg_buf;
- __le32 *res_buf;
-
- cmd = kzalloc(PAGE_ALIGN(alloc_len), GFP_KERNEL);
- if (!cmd)
- return -ENOMEM;
-
- cmd->len = cpu_to_le32(alloc_len);
- cmd->buf_offset = cpu_to_le32(sizeof(*cmd));
- cmd->resp_hdr_offset = cpu_to_le32(sizeof(*cmd) + cmd_len);
- cmd->id = cpu_to_le32(LEGACY_FUNCNUM(desc->svc, desc->cmd));
-
- arg_buf = legacy_get_command_buffer(cmd);
- for (i = 0; i < arglen; i++)
- arg_buf[i] = cpu_to_le32(desc->args[i]);
-
- rsp = legacy_command_to_response(cmd);
-
- cmd_phys = dma_map_single(dev, cmd, alloc_len, DMA_TO_DEVICE);
- if (dma_mapping_error(dev, cmd_phys)) {
- kfree(cmd);
- return -ENOMEM;
- }
-
- smc.a[0] = 1;
- smc.a[1] = (unsigned long)&context_id;
- smc.a[2] = cmd_phys;
-
- mutex_lock(&qcom_scm_lock);
- __qcom_scm_call_do(&smc, &res);
- if (res.a0 < 0)
- ret = qcom_scm_remap_error(res.a0);
- mutex_unlock(&qcom_scm_lock);
- if (ret)
- goto out;
-
- do {
- dma_sync_single_for_cpu(dev, cmd_phys + sizeof(*cmd) + cmd_len,
- sizeof(*rsp), DMA_FROM_DEVICE);
- } while (!rsp->is_complete);
-
- dma_sync_single_for_cpu(dev, cmd_phys + sizeof(*cmd) + cmd_len +
- le32_to_cpu(rsp->buf_offset),
- resp_len, DMA_FROM_DEVICE);
-
- res_buf = legacy_get_response_buffer(rsp);
- for (i = 0; i < MAX_QCOM_SCM_RETS; i++)
- desc->res[i] = le32_to_cpu(res_buf[i]);
-out:
- dma_unmap_single(dev, cmd_phys, alloc_len, DMA_TO_DEVICE);
- kfree(cmd);
- return ret;
-}
-
-#define LEGACY_ATOMIC_N_REG_ARGS 5
-#define LEGACY_ATOMIC_FIRST_REG_IDX 2
-#define LEGACY_CLASS_REGISTER (0x2 << 8)
-#define LEGACY_MASK_IRQS BIT(5)
-#define LEGACY_ATOMIC(svc, cmd, n) ((LEGACY_FUNCNUM(svc, cmd) << 12) | \
- LEGACY_CLASS_REGISTER | \
- LEGACY_MASK_IRQS | \
- (n & 0xf))
-
-/**
- * qcom_scm_call_atomic_legacy() - Send an atomic SCM command with up to
- * 5 arguments and 3 return values
- *
- * This shall only be used with commands that are guaranteed to be
- * uninterruptable, atomic and SMP safe.
- */
-static int qcom_scm_call_atomic_legacy(struct device *dev,
- struct qcom_scm_desc *desc)
-{
- int context_id;
- struct arm_smccc_args smc = {0};
- struct arm_smccc_res res;
- size_t i, arglen = desc->arginfo & 0xf;
-
- BUG_ON(arglen > LEGACY_ATOMIC_N_REG_ARGS);
-
- smc.a[0] = LEGACY_ATOMIC(desc->svc, desc->cmd, arglen);
- smc.a[1] = (unsigned long)&context_id;
-
- for (i = 0; i < arglen; i++)
- smc.a[i + LEGACY_ATOMIC_FIRST_REG_IDX] = desc->args[i];
-
- arm_smccc_smc(smc.a[0], smc.a[1], smc.a[2], smc.a[3],
- smc.a[4], smc.a[5], smc.a[6], smc.a[7], &res);
-
- desc->res[0] = res.a1;
- desc->res[1] = res.a2;
- desc->res[2] = res.a3;
-
- return res.a0;
-}
-
-/**
- * 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, struct qcom_scm_desc *desc)
-{
- might_sleep();
- switch (qcom_smc_convention) {
- case SMC_CONVENTION_ARM_32:
- case SMC_CONVENTION_ARM_64:
- return qcom_scm_call_smccc(dev, desc, false);
- case SMC_CONVENTION_LEGACY:
- return qcom_scm_call_legacy(dev, desc);
- 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, struct qcom_scm_desc *desc)
-{
- switch (qcom_smc_convention) {
- case SMC_CONVENTION_ARM_32:
- case SMC_CONVENTION_ARM_64:
- return qcom_scm_call_smccc(dev, desc, true);
- case SMC_CONVENTION_LEGACY:
- return qcom_scm_call_atomic_legacy(dev, desc);
- default:
- pr_err("Unknown current SCM calling convention.\n");
- return -EINVAL;
- }
-}
-
-#define QCOM_SCM_FLAG_COLDBOOT_CPU0 0x00
-#define QCOM_SCM_FLAG_COLDBOOT_CPU1 0x01
-#define QCOM_SCM_FLAG_COLDBOOT_CPU2 0x08
-#define QCOM_SCM_FLAG_COLDBOOT_CPU3 0x20
-
-/**
- * qcom_scm_set_cold_boot_addr() - Set the cold boot address for cpus
- * @entry: Entry point function for the cpus
- * @cpus: The cpumask of cpus that will use the entry point
- *
- * Set the cold boot address of the cpus. Any cpu outside the supported
- * range would be removed from the cpu present mask.
- */
-int __qcom_scm_set_cold_boot_addr(struct device *dev, void *entry,
- const cpumask_t *cpus)
-{
- int flags = 0;
- int cpu;
- int scm_cb_flags[] = {
- QCOM_SCM_FLAG_COLDBOOT_CPU0,
- QCOM_SCM_FLAG_COLDBOOT_CPU1,
- QCOM_SCM_FLAG_COLDBOOT_CPU2,
- QCOM_SCM_FLAG_COLDBOOT_CPU3,
- };
- struct qcom_scm_desc desc = {
- .svc = QCOM_SCM_SVC_BOOT,
- .cmd = QCOM_SCM_BOOT_SET_ADDR,
- .owner = ARM_SMCCC_OWNER_SIP,
- };
-
- if (!cpus || (cpus && cpumask_empty(cpus)))
- return -EINVAL;
-
- for_each_cpu(cpu, cpus) {
- if (cpu < ARRAY_SIZE(scm_cb_flags))
- flags |= scm_cb_flags[cpu];
- else
- set_cpu_present(cpu, false);
- }
-
- desc.args[0] = flags;
- desc.args[1] = virt_to_phys(entry);
- desc.arginfo = QCOM_SCM_ARGS(2);
-
- return qcom_scm_call_atomic(dev, &desc);
-}
-
-#define QCOM_SCM_FLAG_WARMBOOT_CPU0 0x04
-#define QCOM_SCM_FLAG_WARMBOOT_CPU1 0x02
-#define QCOM_SCM_FLAG_WARMBOOT_CPU2 0x10
-#define QCOM_SCM_FLAG_WARMBOOT_CPU3 0x40
-
-struct qcom_scm_entry {
- int flag;
- void *entry;
-};
-
-static struct qcom_scm_entry qcom_scm_wb[] = {
- { .flag = QCOM_SCM_FLAG_WARMBOOT_CPU0 },
- { .flag = QCOM_SCM_FLAG_WARMBOOT_CPU1 },
- { .flag = QCOM_SCM_FLAG_WARMBOOT_CPU2 },
- { .flag = QCOM_SCM_FLAG_WARMBOOT_CPU3 },
-};
-
-/**
- * qcom_scm_set_warm_boot_addr() - Set the warm boot address for cpus
- * @dev: Device pointer
- * @entry: Entry point function for the cpus
- * @cpus: The cpumask of cpus that will use the entry point
- *
- * Set the Linux entry point for the SCM to transfer control to when coming
- * out of a power down. CPU power down may be executed on cpuidle or hotplug.
- */
-int __qcom_scm_set_warm_boot_addr(struct device *dev, void *entry,
- const cpumask_t *cpus)
-{
- int ret;
- int flags = 0;
- int cpu;
- struct qcom_scm_desc desc = {
- .svc = QCOM_SCM_SVC_BOOT,
- .cmd = QCOM_SCM_BOOT_SET_ADDR,
- };
-
- /*
- * Reassign only if we are switching from hotplug entry point
- * to cpuidle entry point or vice versa.
- */
- for_each_cpu(cpu, cpus) {
- if (entry == qcom_scm_wb[cpu].entry)
- continue;
- flags |= qcom_scm_wb[cpu].flag;
- }
-
- /* No change in entry function */
- if (!flags)
- return 0;
-
- desc.args[0] = flags;
- desc.args[1] = virt_to_phys(entry);
- ret = qcom_scm_call(dev, &desc);
- if (!ret) {
- for_each_cpu(cpu, cpus)
- qcom_scm_wb[cpu].entry = entry;
- }
-
- return ret;
-}
-
-/**
- * qcom_scm_cpu_power_down() - Power down the cpu
- * @flags - Flags to flush cache
- *
- * This is an end point to power down cpu. If there was a pending interrupt,
- * the control would return from this function, otherwise, the cpu jumps to the
- * warm boot entry point set for this cpu upon reset.
- */
-void __qcom_scm_cpu_power_down(struct device *dev, u32 flags)
-{
- struct qcom_scm_desc desc = {
- .svc = QCOM_SCM_SVC_BOOT,
- .cmd = QCOM_SCM_BOOT_TERMINATE_PC,
- .args[0] = flags & QCOM_SCM_FLUSH_FLAG_MASK,
- .arginfo = QCOM_SCM_ARGS(1),
- .owner = ARM_SMCCC_OWNER_SIP,
- };
-
- qcom_scm_call_atomic(dev, &desc);
-}
-
-int __qcom_scm_set_remote_state(struct device *dev, u32 state, u32 id)
-{
- struct qcom_scm_desc desc = {
- .svc = QCOM_SCM_SVC_BOOT,
- .cmd = QCOM_SCM_BOOT_SET_REMOTE_STATE,
- .owner = ARM_SMCCC_OWNER_SIP,
- };
- int ret;
-
- desc.args[0] = state;
- desc.args[1] = id;
- desc.arginfo = QCOM_SCM_ARGS(2);
-
- ret = qcom_scm_call(dev, &desc);
-
- return ret ? : desc.res[0];
-}
-
-int __qcom_scm_set_dload_mode(struct device *dev, bool enable)
-{
- struct qcom_scm_desc desc = {
- .svc = QCOM_SCM_SVC_BOOT,
- .cmd = QCOM_SCM_BOOT_SET_DLOAD_MODE,
- .owner = ARM_SMCCC_OWNER_SIP,
- };
-
- desc.args[0] = QCOM_SCM_BOOT_SET_DLOAD_MODE;
- desc.args[1] = enable ? QCOM_SCM_BOOT_SET_DLOAD_MODE : 0;
- desc.arginfo = QCOM_SCM_ARGS(2);
-
- return qcom_scm_call_atomic(dev, &desc);
-}
-
-bool __qcom_scm_pas_supported(struct device *dev, u32 peripheral)
-{
- int ret;
- struct qcom_scm_desc desc = {
- .svc = QCOM_SCM_SVC_PIL,
- .cmd = QCOM_SCM_PIL_PAS_IS_SUPPORTED,
- .owner = ARM_SMCCC_OWNER_SIP,
- };
-
- desc.args[0] = peripheral;
- desc.arginfo = QCOM_SCM_ARGS(1);
-
- ret = qcom_scm_call(dev, &desc);
-
- return ret ? false : !!desc.res[0];
-}
-
-int __qcom_scm_pas_init_image(struct device *dev, u32 peripheral,
- dma_addr_t metadata_phys)
-{
- int ret;
- struct qcom_scm_desc desc = {
- .svc = QCOM_SCM_SVC_PIL,
- .cmd = QCOM_SCM_PIL_PAS_INIT_IMAGE,
- .owner = ARM_SMCCC_OWNER_SIP,
- };
-
- desc.args[0] = peripheral;
- desc.args[1] = metadata_phys;
- desc.arginfo = QCOM_SCM_ARGS(2, QCOM_SCM_VAL, QCOM_SCM_RW);
-
- ret = qcom_scm_call(dev, &desc);
-
- return ret ? : desc.res[0];
-}
-
-int __qcom_scm_pas_mem_setup(struct device *dev, u32 peripheral,
- phys_addr_t addr, phys_addr_t size)
-{
- int ret;
- struct qcom_scm_desc desc = {
- .svc = QCOM_SCM_SVC_PIL,
- .cmd = QCOM_SCM_PIL_PAS_MEM_SETUP,
- .owner = ARM_SMCCC_OWNER_SIP,
- };
-
- desc.args[0] = peripheral;
- desc.args[1] = addr;
- desc.args[2] = size;
- desc.arginfo = QCOM_SCM_ARGS(3);
-
- ret = qcom_scm_call(dev, &desc);
-
- return ret ? : desc.res[0];
-}
-
-int __qcom_scm_pas_auth_and_reset(struct device *dev, u32 peripheral)
-{
- int ret;
- struct qcom_scm_desc desc = {
- .svc = QCOM_SCM_SVC_PIL,
- .cmd = QCOM_SCM_PIL_PAS_AUTH_AND_RESET,
- .owner = ARM_SMCCC_OWNER_SIP,
- };
-
- desc.args[0] = peripheral;
- desc.arginfo = QCOM_SCM_ARGS(1);
-
- ret = qcom_scm_call(dev, &desc);
-
- return ret ? : desc.res[0];
-}
-
-int __qcom_scm_pas_shutdown(struct device *dev, u32 peripheral)
-{
- int ret;
- struct qcom_scm_desc desc = {
- .svc = QCOM_SCM_SVC_PIL,
- .cmd = QCOM_SCM_PIL_PAS_SHUTDOWN,
- .owner = ARM_SMCCC_OWNER_SIP,
- };
-
- desc.args[0] = peripheral;
- desc.arginfo = QCOM_SCM_ARGS(1);
-
- ret = qcom_scm_call(dev, &desc);
-
- return ret ? : desc.res[0];
-}
-
-int __qcom_scm_pas_mss_reset(struct device *dev, bool reset)
-{
- struct qcom_scm_desc desc = {
- .svc = QCOM_SCM_SVC_PIL,
- .cmd = QCOM_SCM_PIL_PAS_MSS_RESET,
- .owner = ARM_SMCCC_OWNER_SIP,
- };
- int ret;
-
- desc.args[0] = reset;
- desc.args[1] = 0;
- desc.arginfo = QCOM_SCM_ARGS(2);
-
- ret = qcom_scm_call(dev, &desc);
-
- return ret ? : desc.res[0];
-}
-
-int __qcom_scm_io_readl(struct device *dev, phys_addr_t addr,
- unsigned int *val)
-{
- struct qcom_scm_desc desc = {
- .svc = QCOM_SCM_SVC_IO,
- .cmd = QCOM_SCM_IO_READ,
- .owner = ARM_SMCCC_OWNER_SIP,
- };
- int ret;
-
- desc.args[0] = addr;
- desc.arginfo = QCOM_SCM_ARGS(1);
-
- ret = qcom_scm_call_atomic(dev, &desc);
- if (ret >= 0)
- *val = desc.res[0];
-
- return ret < 0 ? ret : 0;
-}
-
-int __qcom_scm_io_writel(struct device *dev, phys_addr_t addr, unsigned int val)
-{
- struct qcom_scm_desc desc = {
- .svc = QCOM_SCM_SVC_IO,
- .cmd = QCOM_SCM_IO_WRITE,
- .owner = ARM_SMCCC_OWNER_SIP,
- };
-
- desc.args[0] = addr;
- desc.args[1] = val;
- desc.arginfo = QCOM_SCM_ARGS(2);
-
- return qcom_scm_call_atomic(dev, &desc);
-}
-
-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,
- };
-
- desc.arginfo = QCOM_SCM_ARGS(1);
- switch (qcom_smc_convention) {
- case SMC_CONVENTION_ARM_32:
- case SMC_CONVENTION_ARM_64:
- desc.args[0] = SMCCC_FUNCNUM(svc_id, cmd_id) |
- (ARM_SMCCC_OWNER_SIP << ARM_SMCCC_OWNER_SHIFT);
- break;
- case SMC_CONVENTION_LEGACY:
- desc.args[0] = LEGACY_FUNCNUM(svc_id, cmd_id);
- break;
- default:
- pr_err("Unknown SMC convention being used\n");
- return -EINVAL;
- }
-
- ret = qcom_scm_call(dev, &desc);
-
- return ret ? : desc.res[0];
-}
-
-int __qcom_scm_restore_sec_cfg(struct device *dev, u32 device_id, u32 spare)
-{
- struct qcom_scm_desc desc = {
- .svc = QCOM_SCM_SVC_MP,
- .cmd = QCOM_SCM_MP_RESTORE_SEC_CFG,
- .owner = ARM_SMCCC_OWNER_SIP,
- };
- int ret;
-
- desc.args[0] = device_id;
- desc.args[1] = spare;
- desc.arginfo = QCOM_SCM_ARGS(2);
-
- ret = qcom_scm_call(dev, &desc);
-
- return ret ? : desc.res[0];
-}
-
-int __qcom_scm_iommu_secure_ptbl_size(struct device *dev, u32 spare,
- size_t *size)
-{
- struct qcom_scm_desc desc = {
- .svc = QCOM_SCM_SVC_MP,
- .cmd = QCOM_SCM_MP_IOMMU_SECURE_PTBL_SIZE,
- .owner = ARM_SMCCC_OWNER_SIP,
- };
- int ret;
-
- desc.args[0] = spare;
- desc.arginfo = QCOM_SCM_ARGS(1);
-
- ret = qcom_scm_call(dev, &desc);
-
- if (size)
- *size = desc.res[0];
-
- return ret ? : desc.res[1];
-}
-
-int __qcom_scm_iommu_secure_ptbl_init(struct device *dev, u64 addr, u32 size,
- u32 spare)
-{
- struct qcom_scm_desc desc = {
- .svc = QCOM_SCM_SVC_MP,
- .cmd = QCOM_SCM_MP_IOMMU_SECURE_PTBL_INIT,
- .owner = ARM_SMCCC_OWNER_SIP,
- };
- int ret;
-
- desc.args[0] = addr;
- desc.args[1] = size;
- desc.args[2] = spare;
- desc.arginfo = QCOM_SCM_ARGS(3, QCOM_SCM_RW, QCOM_SCM_VAL,
- QCOM_SCM_VAL);
-
- ret = qcom_scm_call(dev, &desc);
-
- /* the pg table has been initialized already, ignore the error */
- if (ret == -EPERM)
- ret = 0;
-
- return ret;
-}
-
-int __qcom_scm_assign_mem(struct device *dev, phys_addr_t mem_region,
- size_t mem_sz, phys_addr_t src, size_t src_sz,
- phys_addr_t dest, size_t dest_sz)
-{
- int ret;
- struct qcom_scm_desc desc = {
- .svc = QCOM_SCM_SVC_MP,
- .cmd = QCOM_SCM_MP_ASSIGN,
- .owner = ARM_SMCCC_OWNER_SIP,
- };
-
- desc.args[0] = mem_region;
- desc.args[1] = mem_sz;
- desc.args[2] = src;
- desc.args[3] = src_sz;
- desc.args[4] = dest;
- desc.args[5] = dest_sz;
- desc.args[6] = 0;
-
- desc.arginfo = QCOM_SCM_ARGS(7, QCOM_SCM_RO, QCOM_SCM_VAL,
- QCOM_SCM_RO, QCOM_SCM_VAL, QCOM_SCM_RO,
- QCOM_SCM_VAL, QCOM_SCM_VAL);
-
- ret = qcom_scm_call(dev, &desc);
-
- return ret ? : desc.res[0];
-}
-
-int __qcom_scm_hdcp_req(struct device *dev, struct qcom_scm_hdcp_req *req,
- u32 req_cnt, u32 *resp)
-{
- int ret;
- struct qcom_scm_desc desc = {
- .svc = QCOM_SCM_SVC_HDCP,
- .cmd = QCOM_SCM_HDCP_INVOKE,
- .owner = ARM_SMCCC_OWNER_SIP,
- };
-
- if (req_cnt > QCOM_SCM_HDCP_MAX_REQ_CNT)
- return -ERANGE;
-
- desc.args[0] = req[0].addr;
- desc.args[1] = req[0].val;
- desc.args[2] = req[1].addr;
- desc.args[3] = req[1].val;
- desc.args[4] = req[2].addr;
- desc.args[5] = req[2].val;
- desc.args[6] = req[3].addr;
- desc.args[7] = req[3].val;
- desc.args[8] = req[4].addr;
- desc.args[9] = req[4].val;
- desc.arginfo = QCOM_SCM_ARGS(10);
-
- ret = qcom_scm_call(dev, &desc);
- *resp = desc.res[0];
-
- return ret;
-}
-
-int __qcom_scm_qsmmu500_wait_safe_toggle(struct device *dev, bool en)
-{
- struct qcom_scm_desc desc = {
- .svc = QCOM_SCM_SVC_SMMU_PROGRAM,
- .cmd = QCOM_SCM_SMMU_CONFIG_ERRATA1,
- .owner = ARM_SMCCC_OWNER_SIP,
- };
-
- desc.args[0] = QCOM_SCM_SMMU_CONFIG_ERRATA1_CLIENT_ALL;
- desc.args[1] = en;
- desc.arginfo = QCOM_SCM_ARGS(2);
-
- return qcom_scm_call_atomic(dev, &desc);
-}
-
-void __qcom_scm_init(void)
-{
- qcom_smc_convention = SMC_CONVENTION_LEGACY;
- if (__qcom_scm_is_call_available(NULL, QCOM_SCM_SVC_INFO,
- QCOM_SCM_INFO_IS_CALL_AVAIL) == 1)
- goto out;
-
- qcom_smc_convention = SMC_CONVENTION_ARM_64;
- if (__qcom_scm_is_call_available(NULL, QCOM_SCM_SVC_INFO,
- QCOM_SCM_INFO_IS_CALL_AVAIL) == 1)
- goto out;
-
- qcom_smc_convention = SMC_CONVENTION_ARM_32;
- if (__qcom_scm_is_call_available(NULL, QCOM_SCM_SVC_INFO,
- QCOM_SCM_INFO_IS_CALL_AVAIL) == 1)
- goto out;
-
- qcom_smc_convention = SMC_CONVENTION_UNKNOWN;
-out:
- pr_debug("QCOM SCM SMC Convention: %d\n", qcom_smc_convention);
-}
diff --git a/drivers/firmware/qcom_scm-smc.c b/drivers/firmware/qcom_scm-smc.c
new file mode 100644
index 0000000..355d9d7
--- /dev/null
+++ b/drivers/firmware/qcom_scm-smc.c
@@ -0,0 +1,949 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (c) 2015,2019 The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/io.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/qcom_scm.h>
+#include <linux/arm-smccc.h>
+#include <linux/dma-mapping.h>
+
+#include "qcom_scm.h"
+
+#define MAX_QCOM_SCM_ARGS 10
+#define MAX_QCOM_SCM_RETS 3
+
+enum qcom_scm_arg_types {
+ QCOM_SCM_VAL,
+ QCOM_SCM_RO,
+ QCOM_SCM_RW,
+ QCOM_SCM_BUFVAL,
+};
+
+#define QCOM_SCM_ARGS_IMPL(num, a, b, c, d, e, f, g, h, i, j, ...) (\
+ (((a) & 0x3) << 4) | \
+ (((b) & 0x3) << 6) | \
+ (((c) & 0x3) << 8) | \
+ (((d) & 0x3) << 10) | \
+ (((e) & 0x3) << 12) | \
+ (((f) & 0x3) << 14) | \
+ (((g) & 0x3) << 16) | \
+ (((h) & 0x3) << 18) | \
+ (((i) & 0x3) << 20) | \
+ (((j) & 0x3) << 22) | \
+ ((num) & 0xf))
+
+#define QCOM_SCM_ARGS(...) QCOM_SCM_ARGS_IMPL(__VA_ARGS__, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
+
+/**
+ * struct qcom_scm_desc
+ * @arginfo: Metadata describing the arguments in args[]
+ * @args: The array of arguments for the secure syscall
+ * @res: The values returned by the secure syscall
+ */
+struct qcom_scm_desc {
+ u32 svc;
+ u32 cmd;
+ u32 arginfo;
+ u64 args[MAX_QCOM_SCM_ARGS];
+ u64 res[MAX_QCOM_SCM_RETS];
+ u32 owner;
+};
+
+struct arm_smccc_args {
+ unsigned long a[8];
+};
+
+enum qcom_smc_convention {
+ SMC_CONVENTION_UNKNOWN,
+ SMC_CONVENTION_LEGACY,
+ SMC_CONVENTION_ARM_32,
+ SMC_CONVENTION_ARM_64,
+};
+
+static enum qcom_smc_convention qcom_smc_convention = SMC_CONVENTION_UNKNOWN;
+static DEFINE_MUTEX(qcom_scm_lock);
+
+#define QCOM_SCM_EBUSY_WAIT_MS 30
+#define QCOM_SCM_EBUSY_MAX_RETRY 20
+
+#define SMCCC_FUNCNUM(s, c) ((((s) & 0xFF) << 8) | ((c) & 0xFF))
+#define SMCCC_N_REG_ARGS 4
+#define SMCCC_FIRST_REG_IDX 2
+#define SMCCC_N_EXT_ARGS (MAX_QCOM_SCM_ARGS - SMCCC_N_REG_ARGS + 1)
+#define SMCCC_LAST_REG_IDX (SMCCC_FIRST_REG_IDX + SMCCC_N_REG_ARGS - 1)
+
+static void __qcom_scm_call_do_quirk(const struct arm_smccc_args *smc,
+ struct arm_smccc_res *res)
+{
+ unsigned long a0 = smc->a[0];
+ struct arm_smccc_quirk quirk = { .id = ARM_SMCCC_QUIRK_QCOM_A6 };
+
+ quirk.state.a6 = 0;
+
+ do {
+ arm_smccc_smc_quirk(a0, smc->a[1], smc->a[2], smc->a[3],
+ smc->a[4], smc->a[5], quirk.state.a6,
+ smc->a[7], res, &quirk);
+
+ if (res->a0 == QCOM_SCM_INTERRUPTED)
+ a0 = res->a0;
+
+ } while (res->a0 == QCOM_SCM_INTERRUPTED);
+}
+
+static int qcom_scm_call_smccc(struct device *dev,
+ struct qcom_scm_desc *desc, bool atomic)
+{
+ int arglen = desc->arginfo & 0xf;
+ int i;
+ dma_addr_t args_phys = 0;
+ void *args_virt = NULL;
+ size_t alloc_len;
+ gfp_t flag = atomic ? GFP_ATOMIC : GFP_KERNEL;
+ struct arm_smccc_res res;
+ struct arm_smccc_args smc = {0};
+
+ smc.a[0] = ARM_SMCCC_CALL_VAL(
+ atomic ? ARM_SMCCC_FAST_CALL : ARM_SMCCC_STD_CALL,
+ (qcom_smc_convention == SMC_CONVENTION_ARM_64) ?
+ ARM_SMCCC_SMC_64 :
+ ARM_SMCCC_SMC_32,
+ desc->owner,
+ SMCCC_FUNCNUM(desc->svc, desc->cmd));
+ smc.a[1] = desc->arginfo;
+ for (i = 0; i < SMCCC_N_REG_ARGS; i++)
+ smc.a[i + SMCCC_FIRST_REG_IDX] = desc->args[i];
+
+ if (unlikely(arglen > SMCCC_N_REG_ARGS)) {
+ alloc_len = SMCCC_N_EXT_ARGS * sizeof(u64);
+ args_virt = kzalloc(PAGE_ALIGN(alloc_len), flag);
+
+ if (!args_virt)
+ return -ENOMEM;
+
+ if (qcom_smc_convention == SMC_CONVENTION_ARM_32) {
+ __le32 *args = args_virt;
+
+ for (i = 0; i < SMCCC_N_EXT_ARGS; i++)
+ args[i] = cpu_to_le32(desc->args[i +
+ SMCCC_N_REG_ARGS - 1]);
+ } else {
+ __le64 *args = args_virt;
+
+ for (i = 0; i < SMCCC_N_EXT_ARGS; i++)
+ args[i] = cpu_to_le64(desc->args[i +
+ SMCCC_N_REG_ARGS - 1]);
+ }
+
+ args_phys = dma_map_single(dev, args_virt, alloc_len,
+ DMA_TO_DEVICE);
+
+ if (dma_mapping_error(dev, args_phys)) {
+ kfree(args_virt);
+ return -ENOMEM;
+ }
+
+ smc.a[SMCCC_LAST_REG_IDX] = args_phys;
+ }
+
+ if (atomic) {
+ __qcom_scm_call_do_quirk(&smc, &res);
+ } else {
+ int retry_count = 0;
+
+ do {
+ mutex_lock(&qcom_scm_lock);
+
+ __qcom_scm_call_do_quirk(&smc, &res);
+
+ mutex_unlock(&qcom_scm_lock);
+
+ if (res.a0 == QCOM_SCM_V2_EBUSY) {
+ if (retry_count++ > QCOM_SCM_EBUSY_MAX_RETRY)
+ break;
+ msleep(QCOM_SCM_EBUSY_WAIT_MS);
+ }
+ } while (res.a0 == QCOM_SCM_V2_EBUSY);
+ }
+
+ if (args_virt) {
+ dma_unmap_single(dev, args_phys, alloc_len, DMA_TO_DEVICE);
+ kfree(args_virt);
+ }
+
+ desc->res[0] = res.a1;
+ desc->res[1] = res.a2;
+ desc->res[2] = res.a3;
+
+ if (res.a0 < 0)
+ return qcom_scm_remap_error(res.a0);
+
+ return 0;
+}
+
+#define LEGACY_FUNCNUM(s, c) (((s) << 10) | ((c) & 0x3ff))
+
+/**
+ * struct legacy_command - one SCM command buffer
+ * @len: total available memory for command and response
+ * @buf_offset: start of command buffer
+ * @resp_hdr_offset: start of response buffer
+ * @id: command to be executed
+ * @buf: buffer returned from legacy_get_command_buffer()
+ *
+ * An SCM command is laid out in memory as follows:
+ *
+ * ------------------- <--- struct legacy_command
+ * | command header |
+ * ------------------- <--- legacy_get_command_buffer()
+ * | command buffer |
+ * ------------------- <--- struct legacy_response and
+ * | response header | legacy_command_to_response()
+ * ------------------- <--- legacy_get_response_buffer()
+ * | response buffer |
+ * -------------------
+ *
+ * There can be arbitrary padding between the headers and buffers so
+ * you should always use the appropriate qcom_scm_get_*_buffer() routines
+ * to access the buffers in a safe manner.
+ */
+struct legacy_command {
+ __le32 len;
+ __le32 buf_offset;
+ __le32 resp_hdr_offset;
+ __le32 id;
+ __le32 buf[0];
+};
+
+/**
+ * struct legacy_response - one SCM response buffer
+ * @len: total available memory for response
+ * @buf_offset: start of response data relative to start of legacy_response
+ * @is_complete: indicates if the command has finished processing
+ */
+struct legacy_response {
+ __le32 len;
+ __le32 buf_offset;
+ __le32 is_complete;
+};
+
+/**
+ * legacy_command_to_response() - Get a pointer to a legacy_response
+ * @cmd: command
+ *
+ * Returns a pointer to a response for a command.
+ */
+static inline struct legacy_response *legacy_command_to_response(
+ const struct legacy_command *cmd)
+{
+ return (void *)cmd + le32_to_cpu(cmd->resp_hdr_offset);
+}
+
+/**
+ * legacy_get_command_buffer() - Get a pointer to a command buffer
+ * @cmd: command
+ *
+ * Returns a pointer to the command buffer of a command.
+ */
+static inline void *legacy_get_command_buffer(const struct legacy_command *cmd)
+{
+ return (void *)cmd->buf;
+}
+
+/**
+ * legacy_get_response_buffer() - Get a pointer to a response buffer
+ * @rsp: response
+ *
+ * Returns a pointer to a response buffer of a response.
+ */
+static inline void *legacy_get_response_buffer(const struct legacy_response *rsp)
+{
+ return (void *)rsp + le32_to_cpu(rsp->buf_offset);
+}
+
+static void __qcom_scm_call_do(const struct arm_smccc_args *smc,
+ struct arm_smccc_res *res)
+{
+ do {
+ arm_smccc_smc(smc->a[0], smc->a[1], smc->a[2], smc->a[3],
+ smc->a[4], smc->a[5], smc->a[6], smc->a[7], res);
+ } while (res->a0 == QCOM_SCM_INTERRUPTED);
+}
+
+/**
+ * qcom_scm_call_legacy() - Send an SCM command
+ * @dev: struct device
+ * @svc_id: service identifier
+ * @cmd_id: command identifier
+ * @cmd_buf: command buffer
+ * @cmd_len: length of the command buffer
+ * @resp_buf: response buffer
+ * @resp_len: length of the response buffer
+ *
+ * Sends a command to the SCM and waits for the command to finish processing.
+ *
+ * A note on cache maintenance:
+ * Note that any buffers that are expected to be accessed by the secure world
+ * must be flushed before invoking qcom_scm_call and invalidated in the cache
+ * immediately after qcom_scm_call returns. Cache maintenance on the command
+ * 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.
+ */
+static int qcom_scm_call_legacy(struct device *dev, struct qcom_scm_desc *desc)
+{
+ int arglen = desc->arginfo & 0xf;
+ int ret = 0, context_id;
+ size_t i;
+ struct legacy_command *cmd;
+ struct legacy_response *rsp;
+ struct arm_smccc_args smc = {0};
+ struct arm_smccc_res res;
+ const size_t cmd_len = arglen * sizeof(__le32);
+ const size_t resp_len = MAX_QCOM_SCM_RETS * sizeof(__le32);
+ size_t alloc_len = sizeof(*cmd) + cmd_len + sizeof(*rsp) + resp_len;
+ dma_addr_t cmd_phys;
+ __le32 *arg_buf;
+ __le32 *res_buf;
+
+ cmd = kzalloc(PAGE_ALIGN(alloc_len), GFP_KERNEL);
+ if (!cmd)
+ return -ENOMEM;
+
+ cmd->len = cpu_to_le32(alloc_len);
+ cmd->buf_offset = cpu_to_le32(sizeof(*cmd));
+ cmd->resp_hdr_offset = cpu_to_le32(sizeof(*cmd) + cmd_len);
+ cmd->id = cpu_to_le32(LEGACY_FUNCNUM(desc->svc, desc->cmd));
+
+ arg_buf = legacy_get_command_buffer(cmd);
+ for (i = 0; i < arglen; i++)
+ arg_buf[i] = cpu_to_le32(desc->args[i]);
+
+ rsp = legacy_command_to_response(cmd);
+
+ cmd_phys = dma_map_single(dev, cmd, alloc_len, DMA_TO_DEVICE);
+ if (dma_mapping_error(dev, cmd_phys)) {
+ kfree(cmd);
+ return -ENOMEM;
+ }
+
+ smc.a[0] = 1;
+ smc.a[1] = (unsigned long)&context_id;
+ smc.a[2] = cmd_phys;
+
+ mutex_lock(&qcom_scm_lock);
+ __qcom_scm_call_do(&smc, &res);
+ if (res.a0 < 0)
+ ret = qcom_scm_remap_error(res.a0);
+ mutex_unlock(&qcom_scm_lock);
+ if (ret)
+ goto out;
+
+ do {
+ dma_sync_single_for_cpu(dev, cmd_phys + sizeof(*cmd) + cmd_len,
+ sizeof(*rsp), DMA_FROM_DEVICE);
+ } while (!rsp->is_complete);
+
+ dma_sync_single_for_cpu(dev, cmd_phys + sizeof(*cmd) + cmd_len +
+ le32_to_cpu(rsp->buf_offset),
+ resp_len, DMA_FROM_DEVICE);
+
+ res_buf = legacy_get_response_buffer(rsp);
+ for (i = 0; i < MAX_QCOM_SCM_RETS; i++)
+ desc->res[i] = le32_to_cpu(res_buf[i]);
+out:
+ dma_unmap_single(dev, cmd_phys, alloc_len, DMA_TO_DEVICE);
+ kfree(cmd);
+ return ret;
+}
+
+#define LEGACY_ATOMIC_N_REG_ARGS 5
+#define LEGACY_ATOMIC_FIRST_REG_IDX 2
+#define LEGACY_CLASS_REGISTER (0x2 << 8)
+#define LEGACY_MASK_IRQS BIT(5)
+#define LEGACY_ATOMIC(svc, cmd, n) ((LEGACY_FUNCNUM(svc, cmd) << 12) | \
+ LEGACY_CLASS_REGISTER | \
+ LEGACY_MASK_IRQS | \
+ (n & 0xf))
+
+/**
+ * qcom_scm_call_atomic_legacy() - Send an atomic SCM command with up to
+ * 5 arguments and 3 return values
+ *
+ * This shall only be used with commands that are guaranteed to be
+ * uninterruptable, atomic and SMP safe.
+ */
+static int qcom_scm_call_atomic_legacy(struct device *dev,
+ struct qcom_scm_desc *desc)
+{
+ int context_id;
+ struct arm_smccc_args smc = {0};
+ struct arm_smccc_res res;
+ size_t i, arglen = desc->arginfo & 0xf;
+
+ BUG_ON(arglen > LEGACY_ATOMIC_N_REG_ARGS);
+
+ smc.a[0] = LEGACY_ATOMIC(desc->svc, desc->cmd, arglen);
+ smc.a[1] = (unsigned long)&context_id;
+
+ for (i = 0; i < arglen; i++)
+ smc.a[i + LEGACY_ATOMIC_FIRST_REG_IDX] = desc->args[i];
+
+ arm_smccc_smc(smc.a[0], smc.a[1], smc.a[2], smc.a[3],
+ smc.a[4], smc.a[5], smc.a[6], smc.a[7], &res);
+
+ desc->res[0] = res.a1;
+ desc->res[1] = res.a2;
+ desc->res[2] = res.a3;
+
+ return res.a0;
+}
+
+/**
+ * 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, struct qcom_scm_desc *desc)
+{
+ might_sleep();
+ switch (qcom_smc_convention) {
+ case SMC_CONVENTION_ARM_32:
+ case SMC_CONVENTION_ARM_64:
+ return qcom_scm_call_smccc(dev, desc, false);
+ case SMC_CONVENTION_LEGACY:
+ return qcom_scm_call_legacy(dev, desc);
+ 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, struct qcom_scm_desc *desc)
+{
+ switch (qcom_smc_convention) {
+ case SMC_CONVENTION_ARM_32:
+ case SMC_CONVENTION_ARM_64:
+ return qcom_scm_call_smccc(dev, desc, true);
+ case SMC_CONVENTION_LEGACY:
+ return qcom_scm_call_atomic_legacy(dev, desc);
+ default:
+ pr_err("Unknown current SCM calling convention.\n");
+ return -EINVAL;
+ }
+}
+
+#define QCOM_SCM_FLAG_COLDBOOT_CPU0 0x00
+#define QCOM_SCM_FLAG_COLDBOOT_CPU1 0x01
+#define QCOM_SCM_FLAG_COLDBOOT_CPU2 0x08
+#define QCOM_SCM_FLAG_COLDBOOT_CPU3 0x20
+
+/**
+ * qcom_scm_set_cold_boot_addr() - Set the cold boot address for cpus
+ * @entry: Entry point function for the cpus
+ * @cpus: The cpumask of cpus that will use the entry point
+ *
+ * Set the cold boot address of the cpus. Any cpu outside the supported
+ * range would be removed from the cpu present mask.
+ */
+int __qcom_scm_set_cold_boot_addr(struct device *dev, void *entry,
+ const cpumask_t *cpus)
+{
+ int flags = 0;
+ int cpu;
+ int scm_cb_flags[] = {
+ QCOM_SCM_FLAG_COLDBOOT_CPU0,
+ QCOM_SCM_FLAG_COLDBOOT_CPU1,
+ QCOM_SCM_FLAG_COLDBOOT_CPU2,
+ QCOM_SCM_FLAG_COLDBOOT_CPU3,
+ };
+ struct qcom_scm_desc desc = {
+ .svc = QCOM_SCM_SVC_BOOT,
+ .cmd = QCOM_SCM_BOOT_SET_ADDR,
+ .owner = ARM_SMCCC_OWNER_SIP,
+ };
+
+ if (!cpus || (cpus && cpumask_empty(cpus)))
+ return -EINVAL;
+
+ for_each_cpu(cpu, cpus) {
+ if (cpu < ARRAY_SIZE(scm_cb_flags))
+ flags |= scm_cb_flags[cpu];
+ else
+ set_cpu_present(cpu, false);
+ }
+
+ desc.args[0] = flags;
+ desc.args[1] = virt_to_phys(entry);
+ desc.arginfo = QCOM_SCM_ARGS(2);
+
+ return qcom_scm_call_atomic(dev, &desc);
+}
+
+#define QCOM_SCM_FLAG_WARMBOOT_CPU0 0x04
+#define QCOM_SCM_FLAG_WARMBOOT_CPU1 0x02
+#define QCOM_SCM_FLAG_WARMBOOT_CPU2 0x10
+#define QCOM_SCM_FLAG_WARMBOOT_CPU3 0x40
+
+struct qcom_scm_entry {
+ int flag;
+ void *entry;
+};
+
+static struct qcom_scm_entry qcom_scm_wb[] = {
+ { .flag = QCOM_SCM_FLAG_WARMBOOT_CPU0 },
+ { .flag = QCOM_SCM_FLAG_WARMBOOT_CPU1 },
+ { .flag = QCOM_SCM_FLAG_WARMBOOT_CPU2 },
+ { .flag = QCOM_SCM_FLAG_WARMBOOT_CPU3 },
+};
+
+/**
+ * qcom_scm_set_warm_boot_addr() - Set the warm boot address for cpus
+ * @dev: Device pointer
+ * @entry: Entry point function for the cpus
+ * @cpus: The cpumask of cpus that will use the entry point
+ *
+ * Set the Linux entry point for the SCM to transfer control to when coming
+ * out of a power down. CPU power down may be executed on cpuidle or hotplug.
+ */
+int __qcom_scm_set_warm_boot_addr(struct device *dev, void *entry,
+ const cpumask_t *cpus)
+{
+ int ret;
+ int flags = 0;
+ int cpu;
+ struct qcom_scm_desc desc = {
+ .svc = QCOM_SCM_SVC_BOOT,
+ .cmd = QCOM_SCM_BOOT_SET_ADDR,
+ };
+
+ /*
+ * Reassign only if we are switching from hotplug entry point
+ * to cpuidle entry point or vice versa.
+ */
+ for_each_cpu(cpu, cpus) {
+ if (entry == qcom_scm_wb[cpu].entry)
+ continue;
+ flags |= qcom_scm_wb[cpu].flag;
+ }
+
+ /* No change in entry function */
+ if (!flags)
+ return 0;
+
+ desc.args[0] = flags;
+ desc.args[1] = virt_to_phys(entry);
+ ret = qcom_scm_call(dev, &desc);
+ if (!ret) {
+ for_each_cpu(cpu, cpus)
+ qcom_scm_wb[cpu].entry = entry;
+ }
+
+ return ret;
+}
+
+/**
+ * qcom_scm_cpu_power_down() - Power down the cpu
+ * @flags - Flags to flush cache
+ *
+ * This is an end point to power down cpu. If there was a pending interrupt,
+ * the control would return from this function, otherwise, the cpu jumps to the
+ * warm boot entry point set for this cpu upon reset.
+ */
+void __qcom_scm_cpu_power_down(struct device *dev, u32 flags)
+{
+ struct qcom_scm_desc desc = {
+ .svc = QCOM_SCM_SVC_BOOT,
+ .cmd = QCOM_SCM_BOOT_TERMINATE_PC,
+ .args[0] = flags & QCOM_SCM_FLUSH_FLAG_MASK,
+ .arginfo = QCOM_SCM_ARGS(1),
+ .owner = ARM_SMCCC_OWNER_SIP,
+ };
+
+ qcom_scm_call_atomic(dev, &desc);
+}
+
+int __qcom_scm_set_remote_state(struct device *dev, u32 state, u32 id)
+{
+ struct qcom_scm_desc desc = {
+ .svc = QCOM_SCM_SVC_BOOT,
+ .cmd = QCOM_SCM_BOOT_SET_REMOTE_STATE,
+ .owner = ARM_SMCCC_OWNER_SIP,
+ };
+ int ret;
+
+ desc.args[0] = state;
+ desc.args[1] = id;
+ desc.arginfo = QCOM_SCM_ARGS(2);
+
+ ret = qcom_scm_call(dev, &desc);
+
+ return ret ? : desc.res[0];
+}
+
+int __qcom_scm_set_dload_mode(struct device *dev, bool enable)
+{
+ struct qcom_scm_desc desc = {
+ .svc = QCOM_SCM_SVC_BOOT,
+ .cmd = QCOM_SCM_BOOT_SET_DLOAD_MODE,
+ .owner = ARM_SMCCC_OWNER_SIP,
+ };
+
+ desc.args[0] = QCOM_SCM_BOOT_SET_DLOAD_MODE;
+ desc.args[1] = enable ? QCOM_SCM_BOOT_SET_DLOAD_MODE : 0;
+ desc.arginfo = QCOM_SCM_ARGS(2);
+
+ return qcom_scm_call_atomic(dev, &desc);
+}
+
+bool __qcom_scm_pas_supported(struct device *dev, u32 peripheral)
+{
+ int ret;
+ struct qcom_scm_desc desc = {
+ .svc = QCOM_SCM_SVC_PIL,
+ .cmd = QCOM_SCM_PIL_PAS_IS_SUPPORTED,
+ .owner = ARM_SMCCC_OWNER_SIP,
+ };
+
+ desc.args[0] = peripheral;
+ desc.arginfo = QCOM_SCM_ARGS(1);
+
+ ret = qcom_scm_call(dev, &desc);
+
+ return ret ? false : !!desc.res[0];
+}
+
+int __qcom_scm_pas_init_image(struct device *dev, u32 peripheral,
+ dma_addr_t metadata_phys)
+{
+ int ret;
+ struct qcom_scm_desc desc = {
+ .svc = QCOM_SCM_SVC_PIL,
+ .cmd = QCOM_SCM_PIL_PAS_INIT_IMAGE,
+ .owner = ARM_SMCCC_OWNER_SIP,
+ };
+
+ desc.args[0] = peripheral;
+ desc.args[1] = metadata_phys;
+ desc.arginfo = QCOM_SCM_ARGS(2, QCOM_SCM_VAL, QCOM_SCM_RW);
+
+ ret = qcom_scm_call(dev, &desc);
+
+ return ret ? : desc.res[0];
+}
+
+int __qcom_scm_pas_mem_setup(struct device *dev, u32 peripheral,
+ phys_addr_t addr, phys_addr_t size)
+{
+ int ret;
+ struct qcom_scm_desc desc = {
+ .svc = QCOM_SCM_SVC_PIL,
+ .cmd = QCOM_SCM_PIL_PAS_MEM_SETUP,
+ .owner = ARM_SMCCC_OWNER_SIP,
+ };
+
+ desc.args[0] = peripheral;
+ desc.args[1] = addr;
+ desc.args[2] = size;
+ desc.arginfo = QCOM_SCM_ARGS(3);
+
+ ret = qcom_scm_call(dev, &desc);
+
+ return ret ? : desc.res[0];
+}
+
+int __qcom_scm_pas_auth_and_reset(struct device *dev, u32 peripheral)
+{
+ int ret;
+ struct qcom_scm_desc desc = {
+ .svc = QCOM_SCM_SVC_PIL,
+ .cmd = QCOM_SCM_PIL_PAS_AUTH_AND_RESET,
+ .owner = ARM_SMCCC_OWNER_SIP,
+ };
+
+ desc.args[0] = peripheral;
+ desc.arginfo = QCOM_SCM_ARGS(1);
+
+ ret = qcom_scm_call(dev, &desc);
+
+ return ret ? : desc.res[0];
+}
+
+int __qcom_scm_pas_shutdown(struct device *dev, u32 peripheral)
+{
+ int ret;
+ struct qcom_scm_desc desc = {
+ .svc = QCOM_SCM_SVC_PIL,
+ .cmd = QCOM_SCM_PIL_PAS_SHUTDOWN,
+ .owner = ARM_SMCCC_OWNER_SIP,
+ };
+
+ desc.args[0] = peripheral;
+ desc.arginfo = QCOM_SCM_ARGS(1);
+
+ ret = qcom_scm_call(dev, &desc);
+
+ return ret ? : desc.res[0];
+}
+
+int __qcom_scm_pas_mss_reset(struct device *dev, bool reset)
+{
+ struct qcom_scm_desc desc = {
+ .svc = QCOM_SCM_SVC_PIL,
+ .cmd = QCOM_SCM_PIL_PAS_MSS_RESET,
+ .owner = ARM_SMCCC_OWNER_SIP,
+ };
+ int ret;
+
+ desc.args[0] = reset;
+ desc.args[1] = 0;
+ desc.arginfo = QCOM_SCM_ARGS(2);
+
+ ret = qcom_scm_call(dev, &desc);
+
+ return ret ? : desc.res[0];
+}
+
+int __qcom_scm_io_readl(struct device *dev, phys_addr_t addr,
+ unsigned int *val)
+{
+ struct qcom_scm_desc desc = {
+ .svc = QCOM_SCM_SVC_IO,
+ .cmd = QCOM_SCM_IO_READ,
+ .owner = ARM_SMCCC_OWNER_SIP,
+ };
+ int ret;
+
+ desc.args[0] = addr;
+ desc.arginfo = QCOM_SCM_ARGS(1);
+
+ ret = qcom_scm_call_atomic(dev, &desc);
+ if (ret >= 0)
+ *val = desc.res[0];
+
+ return ret < 0 ? ret : 0;
+}
+
+int __qcom_scm_io_writel(struct device *dev, phys_addr_t addr, unsigned int val)
+{
+ struct qcom_scm_desc desc = {
+ .svc = QCOM_SCM_SVC_IO,
+ .cmd = QCOM_SCM_IO_WRITE,
+ .owner = ARM_SMCCC_OWNER_SIP,
+ };
+
+ desc.args[0] = addr;
+ desc.args[1] = val;
+ desc.arginfo = QCOM_SCM_ARGS(2);
+
+ return qcom_scm_call_atomic(dev, &desc);
+}
+
+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,
+ };
+
+ desc.arginfo = QCOM_SCM_ARGS(1);
+ switch (qcom_smc_convention) {
+ case SMC_CONVENTION_ARM_32:
+ case SMC_CONVENTION_ARM_64:
+ desc.args[0] = SMCCC_FUNCNUM(svc_id, cmd_id) |
+ (ARM_SMCCC_OWNER_SIP << ARM_SMCCC_OWNER_SHIFT);
+ break;
+ case SMC_CONVENTION_LEGACY:
+ desc.args[0] = LEGACY_FUNCNUM(svc_id, cmd_id);
+ break;
+ default:
+ pr_err("Unknown SMC convention being used\n");
+ return -EINVAL;
+ }
+
+ ret = qcom_scm_call(dev, &desc);
+
+ return ret ? : desc.res[0];
+}
+
+int __qcom_scm_restore_sec_cfg(struct device *dev, u32 device_id, u32 spare)
+{
+ struct qcom_scm_desc desc = {
+ .svc = QCOM_SCM_SVC_MP,
+ .cmd = QCOM_SCM_MP_RESTORE_SEC_CFG,
+ .owner = ARM_SMCCC_OWNER_SIP,
+ };
+ int ret;
+
+ desc.args[0] = device_id;
+ desc.args[1] = spare;
+ desc.arginfo = QCOM_SCM_ARGS(2);
+
+ ret = qcom_scm_call(dev, &desc);
+
+ return ret ? : desc.res[0];
+}
+
+int __qcom_scm_iommu_secure_ptbl_size(struct device *dev, u32 spare,
+ size_t *size)
+{
+ struct qcom_scm_desc desc = {
+ .svc = QCOM_SCM_SVC_MP,
+ .cmd = QCOM_SCM_MP_IOMMU_SECURE_PTBL_SIZE,
+ .owner = ARM_SMCCC_OWNER_SIP,
+ };
+ int ret;
+
+ desc.args[0] = spare;
+ desc.arginfo = QCOM_SCM_ARGS(1);
+
+ ret = qcom_scm_call(dev, &desc);
+
+ if (size)
+ *size = desc.res[0];
+
+ return ret ? : desc.res[1];
+}
+
+int __qcom_scm_iommu_secure_ptbl_init(struct device *dev, u64 addr, u32 size,
+ u32 spare)
+{
+ struct qcom_scm_desc desc = {
+ .svc = QCOM_SCM_SVC_MP,
+ .cmd = QCOM_SCM_MP_IOMMU_SECURE_PTBL_INIT,
+ .owner = ARM_SMCCC_OWNER_SIP,
+ };
+ int ret;
+
+ desc.args[0] = addr;
+ desc.args[1] = size;
+ desc.args[2] = spare;
+ desc.arginfo = QCOM_SCM_ARGS(3, QCOM_SCM_RW, QCOM_SCM_VAL,
+ QCOM_SCM_VAL);
+
+ ret = qcom_scm_call(dev, &desc);
+
+ /* the pg table has been initialized already, ignore the error */
+ if (ret == -EPERM)
+ ret = 0;
+
+ return ret;
+}
+
+int __qcom_scm_assign_mem(struct device *dev, phys_addr_t mem_region,
+ size_t mem_sz, phys_addr_t src, size_t src_sz,
+ phys_addr_t dest, size_t dest_sz)
+{
+ int ret;
+ struct qcom_scm_desc desc = {
+ .svc = QCOM_SCM_SVC_MP,
+ .cmd = QCOM_SCM_MP_ASSIGN,
+ .owner = ARM_SMCCC_OWNER_SIP,
+ };
+
+ desc.args[0] = mem_region;
+ desc.args[1] = mem_sz;
+ desc.args[2] = src;
+ desc.args[3] = src_sz;
+ desc.args[4] = dest;
+ desc.args[5] = dest_sz;
+ desc.args[6] = 0;
+
+ desc.arginfo = QCOM_SCM_ARGS(7, QCOM_SCM_RO, QCOM_SCM_VAL,
+ QCOM_SCM_RO, QCOM_SCM_VAL, QCOM_SCM_RO,
+ QCOM_SCM_VAL, QCOM_SCM_VAL);
+
+ ret = qcom_scm_call(dev, &desc);
+
+ return ret ? : desc.res[0];
+}
+
+int __qcom_scm_hdcp_req(struct device *dev, struct qcom_scm_hdcp_req *req,
+ u32 req_cnt, u32 *resp)
+{
+ int ret;
+ struct qcom_scm_desc desc = {
+ .svc = QCOM_SCM_SVC_HDCP,
+ .cmd = QCOM_SCM_HDCP_INVOKE,
+ .owner = ARM_SMCCC_OWNER_SIP,
+ };
+
+ if (req_cnt > QCOM_SCM_HDCP_MAX_REQ_CNT)
+ return -ERANGE;
+
+ desc.args[0] = req[0].addr;
+ desc.args[1] = req[0].val;
+ desc.args[2] = req[1].addr;
+ desc.args[3] = req[1].val;
+ desc.args[4] = req[2].addr;
+ desc.args[5] = req[2].val;
+ desc.args[6] = req[3].addr;
+ desc.args[7] = req[3].val;
+ desc.args[8] = req[4].addr;
+ desc.args[9] = req[4].val;
+ desc.arginfo = QCOM_SCM_ARGS(10);
+
+ ret = qcom_scm_call(dev, &desc);
+ *resp = desc.res[0];
+
+ return ret;
+}
+
+int __qcom_scm_qsmmu500_wait_safe_toggle(struct device *dev, bool en)
+{
+ struct qcom_scm_desc desc = {
+ .svc = QCOM_SCM_SVC_SMMU_PROGRAM,
+ .cmd = QCOM_SCM_SMMU_CONFIG_ERRATA1,
+ .owner = ARM_SMCCC_OWNER_SIP,
+ };
+
+ desc.args[0] = QCOM_SCM_SMMU_CONFIG_ERRATA1_CLIENT_ALL;
+ desc.args[1] = en;
+ desc.arginfo = QCOM_SCM_ARGS(2);
+
+ return qcom_scm_call_atomic(dev, &desc);
+}
+
+void __qcom_scm_init(void)
+{
+ qcom_smc_convention = SMC_CONVENTION_LEGACY;
+ if (__qcom_scm_is_call_available(NULL, QCOM_SCM_SVC_INFO,
+ QCOM_SCM_INFO_IS_CALL_AVAIL) == 1)
+ goto out;
+
+ qcom_smc_convention = SMC_CONVENTION_ARM_64;
+ if (__qcom_scm_is_call_available(NULL, QCOM_SCM_SVC_INFO,
+ QCOM_SCM_INFO_IS_CALL_AVAIL) == 1)
+ goto out;
+
+ qcom_smc_convention = SMC_CONVENTION_ARM_32;
+ if (__qcom_scm_is_call_available(NULL, QCOM_SCM_SVC_INFO,
+ QCOM_SCM_INFO_IS_CALL_AVAIL) == 1)
+ goto out;
+
+ qcom_smc_convention = SMC_CONVENTION_UNKNOWN;
+out:
+ pr_debug("QCOM SCM SMC Convention: %d\n", qcom_smc_convention);
+}
--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project

2019-11-05 02:16:37

by Sai Prakash Ranjan

[permalink] [raw]
Subject: Re: [PATCH 00/17] Restructure, improve target support for qcom_scm driver

On 2019-11-05 06:57, Elliot Berman wrote:
> This series improves support for 32-bit Qualcomm targets on qcom_scm
> driver.
>
> Currently, the qcom_scm driver supports only 64-bit Qualcomm targets
> and very
> old 32-bit Qualcomm targets. Newer 32-bit targets use ARM's SMC Calling
> Convention to communicate with secure world. Older 32-bit targets use a
> "buffer-based" legacy approach for communicating with secure world (as
> implemented in qcom_scm-32.c). All arm64 Qualcomm targets use ARM
> SMCCC.
> Currently, SMCCC-based communication is enabled only on ARM64 config
> and
> buffer-based communication only on ARM config. This patch-series
> combines SMCCC
> and legacy conventions and selects the correct convention by querying
> the secure
> world [1].
>
> We decided to take the opportunity as well to clean up the driver
> rather than
> try to patch together qcom_scm-32 and qcom_scm-64.
>
> Patches 1-4 improve macro names, reorder macros/functions, and prune
> unused
> macros/functions. No functional changes were introduced.
> Patches 5-9 clears up the SCM abstraction in qcom_scm-64.
> Patches 10-14 clears up the SCM abstraction in qcom_scm-32.
> Patches 9 and 15-16 enable dynamically using the different calling
> conventions.
>
> This series is based on
> https://lore.kernel.org/patchwork/cover/1129991/
>
> [1]:
> https://source.codeaurora.org/quic/la/kernel/msm-4.9/tree/drivers/soc/qcom/scm.c?h=kernel.lnx.4.9.r28-rel#n555
>
> Changes since RFC:
> - Fixed missing return values in qcom_scm_call_smccc
> - Fixed order of arguments in qcom_scm_set_warm_boot_addr
> - Adjusted logic of SMC convention to properly support older QCOM
> secure worlds
> - Boot tested on IFC6410 based on linaro kernel tag:
> debian-qcom-dragonboard410c-18.01 (which does basic verification of
> legacy
> SCM calls: at least warm_boot_addr, cold_boot_addr, and power_down)
>
> Elliot Berman (17):
> firmware: qcom_scm: Rename macros and structures
> firmware: qcom_scm: Apply consistent naming scheme to command IDs
> firmware: qcom_scm: Order functions, definitions by service/command
> firmware: qcom_scm: Remove unused qcom_scm_get_version
> firmware: qcom_scm-64: Move svc/cmd/owner into qcom_scm_desc
> firmware: qcom_scm-64: Add SCM results to descriptor
> firmware: qcom_scm-64: Remove qcom_scm_call_do_smccc
> firmware: qcom_scm-64: Move SMC register filling to
> qcom_scm_call_smccc
> firmware: qcom_scm-64: Improve SMC convention detection
> firmware: qcom_scm-32: Use SMC arch wrappers
> firmware: qcom_scm-32: Use qcom_scm_desc in non-atomic calls
> firmware: qcom_scm-32: Move SMCCC register filling to qcom_scm_call
> firmware: qcom_scm-32: Create common legacy atomic call
> firmware: qcom_scm-32: Add device argument to atomic calls
> firmware: qcom_scm: Merge legacy and SMCCC conventions
> firmware: qcom_scm: Enable legacy calling convention in qcom_scm-64.c
> firmware: qcom_scm: Rename -64 -> -smc, remove -32
>
> drivers/firmware/Kconfig | 18 +-
> drivers/firmware/Makefile | 4 +-
> drivers/firmware/qcom_scm-32.c | 621 --------------------------
> drivers/firmware/qcom_scm-64.c | 567 ------------------------
> drivers/firmware/qcom_scm-smc.c | 949
> ++++++++++++++++++++++++++++++++++++++++
> drivers/firmware/qcom_scm.c | 235 +++++-----
> drivers/firmware/qcom_scm.h | 115 +++--
> include/linux/qcom_scm.h | 72 +--
> 8 files changed, 1169 insertions(+), 1412 deletions(-)
> delete mode 100644 drivers/firmware/qcom_scm-32.c
> delete mode 100644 drivers/firmware/qcom_scm-64.c
> create mode 100644 drivers/firmware/qcom_scm-smc.c

++Stephen

--
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a
member
of Code Aurora Forum, hosted by The Linux Foundation

2019-11-06 06:04:08

by Bjorn Andersson

[permalink] [raw]
Subject: Re: [PATCH 02/17] firmware: qcom_scm: Apply consistent naming scheme to command IDs

On Mon 04 Nov 17:27 PST 2019, Elliot Berman wrote:

> Create a consistent naming scheme for command IDs. The scheme is
> QCOM_SCM_##svc_##cmd. Remove unused macros QCOM_SCM_FLAG_HLOS,
> QCOM_SCM_FLAG_COLDBOOT_MC, QCOM_SCM_FLAG_WARMBOOT_MC,
> QCOM_SCM_CMD_CORE_HOTPLUGGED, and QCOM_SCM_BOOT_ADDR_MC.
>
> Signed-off-by: Elliot Berman <[email protected]>

Reviewed-by: Bjorn Andersson <[email protected]>

> ---
> drivers/firmware/qcom_scm-32.c | 28 ++++++++++++++--------------
> drivers/firmware/qcom_scm-64.c | 38 +++++++++++++++++++-------------------
> drivers/firmware/qcom_scm.c | 8 ++++----
> drivers/firmware/qcom_scm.h | 41 ++++++++++++++++++-----------------------
> 4 files changed, 55 insertions(+), 60 deletions(-)
>
> diff --git a/drivers/firmware/qcom_scm-32.c b/drivers/firmware/qcom_scm-32.c
> index d416efc..87b520f 100644
> --- a/drivers/firmware/qcom_scm-32.c
> +++ b/drivers/firmware/qcom_scm-32.c
> @@ -356,7 +356,7 @@ int __qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus)
> set_cpu_present(cpu, false);
> }
>
> - return qcom_scm_call_atomic2(QCOM_SCM_SVC_BOOT, QCOM_SCM_BOOT_ADDR,
> + return qcom_scm_call_atomic2(QCOM_SCM_SVC_BOOT, QCOM_SCM_BOOT_SET_ADDR,
> flags, virt_to_phys(entry));
> }
>
> @@ -395,7 +395,7 @@ int __qcom_scm_set_warm_boot_addr(struct device *dev, void *entry,
>
> cmd.addr = cpu_to_le32(virt_to_phys(entry));
> cmd.flags = cpu_to_le32(flags);
> - ret = qcom_scm_call(dev, QCOM_SCM_SVC_BOOT, QCOM_SCM_BOOT_ADDR,
> + ret = qcom_scm_call(dev, QCOM_SCM_SVC_BOOT, QCOM_SCM_BOOT_SET_ADDR,
> &cmd, sizeof(cmd), NULL, 0);
> if (!ret) {
> for_each_cpu(cpu, cpus)
> @@ -415,7 +415,7 @@ int __qcom_scm_set_warm_boot_addr(struct device *dev, void *entry,
> */
> void __qcom_scm_cpu_power_down(u32 flags)
> {
> - qcom_scm_call_atomic1(QCOM_SCM_SVC_BOOT, QCOM_SCM_CMD_TERMINATE_PC,
> + qcom_scm_call_atomic1(QCOM_SCM_SVC_BOOT, QCOM_SCM_BOOT_TERMINATE_PC,
> flags & QCOM_SCM_FLUSH_FLAG_MASK);
> }
>
> @@ -425,7 +425,7 @@ int __qcom_scm_is_call_available(struct device *dev, u32 svc_id, u32 cmd_id)
> __le32 svc_cmd = cpu_to_le32((svc_id << 10) | cmd_id);
> __le32 ret_val = 0;
>
> - ret = qcom_scm_call(dev, QCOM_SCM_SVC_INFO, QCOM_IS_CALL_AVAIL_CMD,
> + ret = qcom_scm_call(dev, QCOM_SCM_SVC_INFO, QCOM_SCM_INFO_IS_CALL_AVAIL,
> &svc_cmd, sizeof(svc_cmd), &ret_val,
> sizeof(ret_val));
> if (ret)
> @@ -440,7 +440,7 @@ int __qcom_scm_hdcp_req(struct device *dev, struct qcom_scm_hdcp_req *req,
> if (req_cnt > QCOM_SCM_HDCP_MAX_REQ_CNT)
> return -ERANGE;
>
> - return qcom_scm_call(dev, QCOM_SCM_SVC_HDCP, QCOM_SCM_CMD_HDCP,
> + return qcom_scm_call(dev, QCOM_SCM_SVC_HDCP, QCOM_SCM_HDCP_INVOKE,
> req, req_cnt * sizeof(*req), resp, sizeof(*resp));
> }
>
> @@ -456,7 +456,7 @@ bool __qcom_scm_pas_supported(struct device *dev, u32 peripheral)
>
> in = cpu_to_le32(peripheral);
> ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL,
> - QCOM_SCM_PAS_IS_SUPPORTED_CMD,
> + QCOM_SCM_PIL_PAS_IS_SUPPORTED,
> &in, sizeof(in),
> &out, sizeof(out));
>
> @@ -477,7 +477,7 @@ int __qcom_scm_pas_init_image(struct device *dev, u32 peripheral,
> request.image_addr = cpu_to_le32(metadata_phys);
>
> ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL,
> - QCOM_SCM_PAS_INIT_IMAGE_CMD,
> + QCOM_SCM_PIL_PAS_INIT_IMAGE,
> &request, sizeof(request),
> &scm_ret, sizeof(scm_ret));
>
> @@ -500,7 +500,7 @@ int __qcom_scm_pas_mem_setup(struct device *dev, u32 peripheral,
> request.len = cpu_to_le32(size);
>
> ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL,
> - QCOM_SCM_PAS_MEM_SETUP_CMD,
> + QCOM_SCM_PIL_PAS_MEM_SETUP,
> &request, sizeof(request),
> &scm_ret, sizeof(scm_ret));
>
> @@ -515,7 +515,7 @@ int __qcom_scm_pas_auth_and_reset(struct device *dev, u32 peripheral)
>
> in = cpu_to_le32(peripheral);
> ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL,
> - QCOM_SCM_PAS_AUTH_AND_RESET_CMD,
> + QCOM_SCM_PIL_PAS_AUTH_AND_RESET,
> &in, sizeof(in),
> &out, sizeof(out));
>
> @@ -530,7 +530,7 @@ int __qcom_scm_pas_shutdown(struct device *dev, u32 peripheral)
>
> in = cpu_to_le32(peripheral);
> ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL,
> - QCOM_SCM_PAS_SHUTDOWN_CMD,
> + QCOM_SCM_PIL_PAS_SHUTDOWN,
> &in, sizeof(in),
> &out, sizeof(out));
>
> @@ -543,7 +543,7 @@ int __qcom_scm_pas_mss_reset(struct device *dev, bool reset)
> __le32 in = cpu_to_le32(reset);
> int ret;
>
> - ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL, QCOM_SCM_PAS_MSS_RESET,
> + ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL, QCOM_SCM_PIL_PAS_MSS_RESET,
> &in, sizeof(in),
> &out, sizeof(out));
>
> @@ -552,8 +552,8 @@ int __qcom_scm_pas_mss_reset(struct device *dev, bool reset)
>
> int __qcom_scm_set_dload_mode(struct device *dev, bool enable)
> {
> - return qcom_scm_call_atomic2(QCOM_SCM_SVC_BOOT, QCOM_SCM_SET_DLOAD_MODE,
> - enable ? QCOM_SCM_SET_DLOAD_MODE : 0, 0);
> + return qcom_scm_call_atomic2(QCOM_SCM_SVC_BOOT, QCOM_SCM_BOOT_SET_DLOAD_MODE,
> + enable ? QCOM_SCM_BOOT_SET_DLOAD_MODE : 0, 0);
> }
>
> int __qcom_scm_set_remote_state(struct device *dev, u32 state, u32 id)
> @@ -568,7 +568,7 @@ int __qcom_scm_set_remote_state(struct device *dev, u32 state, u32 id)
> req.state = cpu_to_le32(state);
> req.id = cpu_to_le32(id);
>
> - ret = qcom_scm_call(dev, QCOM_SCM_SVC_BOOT, QCOM_SCM_SET_REMOTE_STATE,
> + ret = qcom_scm_call(dev, QCOM_SCM_SVC_BOOT, QCOM_SCM_BOOT_SET_REMOTE_STATE,
> &req, sizeof(req), &scm_ret, sizeof(scm_ret));
>
> return ret ? : le32_to_cpu(scm_ret);
> diff --git a/drivers/firmware/qcom_scm-64.c b/drivers/firmware/qcom_scm-64.c
> index e6721b5..f0b4853 100644
> --- a/drivers/firmware/qcom_scm-64.c
> +++ b/drivers/firmware/qcom_scm-64.c
> @@ -256,7 +256,7 @@ int __qcom_scm_is_call_available(struct device *dev, u32 svc_id, u32 cmd_id)
> desc.args[0] = SMCCC_FUNCNUM(svc_id, cmd_id) |
> (ARM_SMCCC_OWNER_SIP << ARM_SMCCC_OWNER_SHIFT);
>
> - ret = qcom_scm_call(dev, QCOM_SCM_SVC_INFO, QCOM_IS_CALL_AVAIL_CMD,
> + ret = qcom_scm_call(dev, QCOM_SCM_SVC_INFO, QCOM_SCM_INFO_IS_CALL_AVAIL,
> &desc, &res);
>
> return ret ? : res.a1;
> @@ -284,7 +284,7 @@ int __qcom_scm_hdcp_req(struct device *dev, struct qcom_scm_hdcp_req *req,
> desc.args[9] = req[4].val;
> desc.arginfo = QCOM_SCM_ARGS(10);
>
> - ret = qcom_scm_call(dev, QCOM_SCM_SVC_HDCP, QCOM_SCM_CMD_HDCP, &desc,
> + ret = qcom_scm_call(dev, QCOM_SCM_SVC_HDCP, QCOM_SCM_HDCP_INVOKE, &desc,
> &res);
> *resp = res.a1;
>
> @@ -295,7 +295,7 @@ void __qcom_scm_init(void)
> {
> u64 cmd;
> struct arm_smccc_res res;
> - u32 function = SMCCC_FUNCNUM(QCOM_SCM_SVC_INFO, QCOM_IS_CALL_AVAIL_CMD);
> + u32 function = SMCCC_FUNCNUM(QCOM_SCM_SVC_INFO, QCOM_SCM_INFO_IS_CALL_AVAIL);
>
> /* First try a SMC64 call */
> cmd = ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, ARM_SMCCC_SMC_64,
> @@ -320,7 +320,7 @@ bool __qcom_scm_pas_supported(struct device *dev, u32 peripheral)
> desc.arginfo = QCOM_SCM_ARGS(1);
>
> ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL,
> - QCOM_SCM_PAS_IS_SUPPORTED_CMD,
> + QCOM_SCM_PIL_PAS_IS_SUPPORTED,
> &desc, &res);
>
> return ret ? false : !!res.a1;
> @@ -337,7 +337,7 @@ int __qcom_scm_pas_init_image(struct device *dev, u32 peripheral,
> desc.args[1] = metadata_phys;
> desc.arginfo = QCOM_SCM_ARGS(2, QCOM_SCM_VAL, QCOM_SCM_RW);
>
> - ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL, QCOM_SCM_PAS_INIT_IMAGE_CMD,
> + ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL, QCOM_SCM_PIL_PAS_INIT_IMAGE,
> &desc, &res);
>
> return ret ? : res.a1;
> @@ -355,7 +355,7 @@ int __qcom_scm_pas_mem_setup(struct device *dev, u32 peripheral,
> desc.args[2] = size;
> desc.arginfo = QCOM_SCM_ARGS(3);
>
> - ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL, QCOM_SCM_PAS_MEM_SETUP_CMD,
> + ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL, QCOM_SCM_PIL_PAS_MEM_SETUP,
> &desc, &res);
>
> return ret ? : res.a1;
> @@ -371,7 +371,7 @@ int __qcom_scm_pas_auth_and_reset(struct device *dev, u32 peripheral)
> desc.arginfo = QCOM_SCM_ARGS(1);
>
> ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL,
> - QCOM_SCM_PAS_AUTH_AND_RESET_CMD,
> + QCOM_SCM_PIL_PAS_AUTH_AND_RESET,
> &desc, &res);
>
> return ret ? : res.a1;
> @@ -386,7 +386,7 @@ int __qcom_scm_pas_shutdown(struct device *dev, u32 peripheral)
> desc.args[0] = peripheral;
> desc.arginfo = QCOM_SCM_ARGS(1);
>
> - ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL, QCOM_SCM_PAS_SHUTDOWN_CMD,
> + ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL, QCOM_SCM_PIL_PAS_SHUTDOWN,
> &desc, &res);
>
> return ret ? : res.a1;
> @@ -402,7 +402,7 @@ int __qcom_scm_pas_mss_reset(struct device *dev, bool reset)
> desc.args[1] = 0;
> desc.arginfo = QCOM_SCM_ARGS(2);
>
> - ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL, QCOM_SCM_PAS_MSS_RESET, &desc,
> + ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL, QCOM_SCM_PIL_PAS_MSS_RESET, &desc,
> &res);
>
> return ret ? : res.a1;
> @@ -418,7 +418,7 @@ int __qcom_scm_set_remote_state(struct device *dev, u32 state, u32 id)
> desc.args[1] = id;
> desc.arginfo = QCOM_SCM_ARGS(2);
>
> - ret = qcom_scm_call(dev, QCOM_SCM_SVC_BOOT, QCOM_SCM_SET_REMOTE_STATE,
> + ret = qcom_scm_call(dev, QCOM_SCM_SVC_BOOT, QCOM_SCM_BOOT_SET_REMOTE_STATE,
> &desc, &res);
>
> return ret ? : res.a1;
> @@ -445,7 +445,7 @@ int __qcom_scm_assign_mem(struct device *dev, phys_addr_t mem_region,
> QCOM_SCM_VAL, QCOM_SCM_VAL);
>
> ret = qcom_scm_call(dev, QCOM_SCM_SVC_MP,
> - QCOM_MEM_PROT_ASSIGN_ID,
> + QCOM_SCM_MP_ASSIGN,
> &desc, &res);
>
> return ret ? : res.a1;
> @@ -461,7 +461,7 @@ int __qcom_scm_restore_sec_cfg(struct device *dev, u32 device_id, u32 spare)
> desc.args[1] = spare;
> desc.arginfo = QCOM_SCM_ARGS(2);
>
> - ret = qcom_scm_call(dev, QCOM_SCM_SVC_MP, QCOM_SCM_RESTORE_SEC_CFG,
> + ret = qcom_scm_call(dev, QCOM_SCM_SVC_MP, QCOM_SCM_MP_RESTORE_SEC_CFG,
> &desc, &res);
>
> return ret ? : res.a1;
> @@ -478,7 +478,7 @@ int __qcom_scm_iommu_secure_ptbl_size(struct device *dev, u32 spare,
> desc.arginfo = QCOM_SCM_ARGS(1);
>
> ret = qcom_scm_call(dev, QCOM_SCM_SVC_MP,
> - QCOM_SCM_IOMMU_SECURE_PTBL_SIZE, &desc, &res);
> + QCOM_SCM_MP_IOMMU_SECURE_PTBL_SIZE, &desc, &res);
>
> if (size)
> *size = res.a1;
> @@ -500,7 +500,7 @@ int __qcom_scm_iommu_secure_ptbl_init(struct device *dev, u64 addr, u32 size,
> QCOM_SCM_VAL);
>
> ret = qcom_scm_call(dev, QCOM_SCM_SVC_MP,
> - QCOM_SCM_IOMMU_SECURE_PTBL_INIT, &desc, &res);
> + QCOM_SCM_MP_IOMMU_SECURE_PTBL_INIT, &desc, &res);
>
> /* the pg table has been initialized already, ignore the error */
> if (ret == -EPERM)
> @@ -514,11 +514,11 @@ int __qcom_scm_set_dload_mode(struct device *dev, bool enable)
> struct qcom_scm_desc desc = {0};
> struct arm_smccc_res res;
>
> - desc.args[0] = QCOM_SCM_SET_DLOAD_MODE;
> - desc.args[1] = enable ? QCOM_SCM_SET_DLOAD_MODE : 0;
> + desc.args[0] = QCOM_SCM_BOOT_SET_DLOAD_MODE;
> + desc.args[1] = enable ? QCOM_SCM_BOOT_SET_DLOAD_MODE : 0;
> desc.arginfo = QCOM_SCM_ARGS(2);
>
> - return qcom_scm_call(dev, QCOM_SCM_SVC_BOOT, QCOM_SCM_SET_DLOAD_MODE,
> + return qcom_scm_call(dev, QCOM_SCM_SVC_BOOT, QCOM_SCM_BOOT_SET_DLOAD_MODE,
> &desc, &res);
> }
>
> @@ -558,10 +558,10 @@ int __qcom_scm_qsmmu500_wait_safe_toggle(struct device *dev, bool en)
> struct qcom_scm_desc desc = {0};
> struct arm_smccc_res res;
>
> - desc.args[0] = QCOM_SCM_CONFIG_ERRATA1_CLIENT_ALL;
> + desc.args[0] = QCOM_SCM_SMMU_CONFIG_ERRATA1_CLIENT_ALL;
> desc.args[1] = en;
> desc.arginfo = QCOM_SCM_ARGS(2);
>
> return qcom_scm_call_atomic(dev, QCOM_SCM_SVC_SMMU_PROGRAM,
> - QCOM_SCM_CONFIG_ERRATA1, &desc, &res);
> + QCOM_SCM_SMMU_CONFIG_ERRATA1, &desc, &res);
> }
> diff --git a/drivers/firmware/qcom_scm.c b/drivers/firmware/qcom_scm.c
> index 40222b1..450d6d6 100644
> --- a/drivers/firmware/qcom_scm.c
> +++ b/drivers/firmware/qcom_scm.c
> @@ -140,7 +140,7 @@ bool qcom_scm_hdcp_available(void)
> return ret;
>
> ret = __qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_HDCP,
> - QCOM_SCM_CMD_HDCP);
> + QCOM_SCM_HDCP_INVOKE);
>
> qcom_scm_clk_disable();
>
> @@ -181,7 +181,7 @@ bool qcom_scm_pas_supported(u32 peripheral)
> int ret;
>
> ret = __qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_PIL,
> - QCOM_SCM_PAS_IS_SUPPORTED_CMD);
> + QCOM_SCM_PIL_PAS_IS_SUPPORTED);
> if (ret <= 0)
> return false;
>
> @@ -368,12 +368,12 @@ static void qcom_scm_set_download_mode(bool enable)
>
> avail = __qcom_scm_is_call_available(__scm->dev,
> QCOM_SCM_SVC_BOOT,
> - QCOM_SCM_SET_DLOAD_MODE);
> + QCOM_SCM_BOOT_SET_DLOAD_MODE);
> if (avail) {
> ret = __qcom_scm_set_dload_mode(__scm->dev, enable);
> } else if (__scm->dload_mode_addr) {
> ret = __qcom_scm_io_writel(__scm->dev, __scm->dload_mode_addr,
> - enable ? QCOM_SCM_SET_DLOAD_MODE : 0);
> + enable ? QCOM_SCM_BOOT_SET_DLOAD_MODE : 0);
> } else {
> dev_err(__scm->dev,
> "No available mechanism for setting download mode\n");
> diff --git a/drivers/firmware/qcom_scm.h b/drivers/firmware/qcom_scm.h
> index baee744..99e91ba 100644
> --- a/drivers/firmware/qcom_scm.h
> +++ b/drivers/firmware/qcom_scm.h
> @@ -5,23 +5,18 @@
> #define __QCOM_SCM_INT_H
>
> #define QCOM_SCM_SVC_BOOT 0x1
> -#define QCOM_SCM_BOOT_ADDR 0x1
> -#define QCOM_SCM_SET_DLOAD_MODE 0x10
> -#define QCOM_SCM_BOOT_ADDR_MC 0x11
> -#define QCOM_SCM_SET_REMOTE_STATE 0xa
> +#define QCOM_SCM_BOOT_SET_ADDR 0x1
> +#define QCOM_SCM_BOOT_SET_DLOAD_MODE 0x10
> +#define QCOM_SCM_BOOT_SET_REMOTE_STATE 0xa
> extern int __qcom_scm_set_remote_state(struct device *dev, u32 state, u32 id);
> extern int __qcom_scm_set_dload_mode(struct device *dev, bool enable);
>
> -#define QCOM_SCM_FLAG_HLOS 0x01
> -#define QCOM_SCM_FLAG_COLDBOOT_MC 0x02
> -#define QCOM_SCM_FLAG_WARMBOOT_MC 0x04
> extern int __qcom_scm_set_warm_boot_addr(struct device *dev, void *entry,
> const cpumask_t *cpus);
> extern int __qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus);
>
> -#define QCOM_SCM_CMD_TERMINATE_PC 0x2
> +#define QCOM_SCM_BOOT_TERMINATE_PC 0x2
> #define QCOM_SCM_FLUSH_FLAG_MASK 0x3
> -#define QCOM_SCM_CMD_CORE_HOTPLUGGED 0x10
> extern void __qcom_scm_cpu_power_down(u32 flags);
>
> #define QCOM_SCM_SVC_IO 0x5
> @@ -31,24 +26,24 @@ extern int __qcom_scm_io_readl(struct device *dev, phys_addr_t addr, unsigned in
> extern int __qcom_scm_io_writel(struct device *dev, phys_addr_t addr, unsigned int val);
>
> #define QCOM_SCM_SVC_INFO 0x6
> -#define QCOM_IS_CALL_AVAIL_CMD 0x1
> +#define QCOM_SCM_INFO_IS_CALL_AVAIL 0x1
> extern int __qcom_scm_is_call_available(struct device *dev, u32 svc_id,
> u32 cmd_id);
>
> #define QCOM_SCM_SVC_HDCP 0x11
> -#define QCOM_SCM_CMD_HDCP 0x01
> +#define QCOM_SCM_HDCP_INVOKE 0x01
> extern int __qcom_scm_hdcp_req(struct device *dev,
> struct qcom_scm_hdcp_req *req, u32 req_cnt, u32 *resp);
>
> extern void __qcom_scm_init(void);
>
> #define QCOM_SCM_SVC_PIL 0x2
> -#define QCOM_SCM_PAS_INIT_IMAGE_CMD 0x1
> -#define QCOM_SCM_PAS_MEM_SETUP_CMD 0x2
> -#define QCOM_SCM_PAS_AUTH_AND_RESET_CMD 0x5
> -#define QCOM_SCM_PAS_SHUTDOWN_CMD 0x6
> -#define QCOM_SCM_PAS_IS_SUPPORTED_CMD 0x7
> -#define QCOM_SCM_PAS_MSS_RESET 0xa
> +#define QCOM_SCM_PIL_PAS_INIT_IMAGE 0x1
> +#define QCOM_SCM_PIL_PAS_MEM_SETUP 0x2
> +#define QCOM_SCM_PIL_PAS_AUTH_AND_RESET 0x5
> +#define QCOM_SCM_PIL_PAS_SHUTDOWN 0x6
> +#define QCOM_SCM_PIL_PAS_IS_SUPPORTED 0x7
> +#define QCOM_SCM_PIL_PAS_MSS_RESET 0xa
> extern bool __qcom_scm_pas_supported(struct device *dev, u32 peripheral);
> extern int __qcom_scm_pas_init_image(struct device *dev, u32 peripheral,
> dma_addr_t metadata_phys);
> @@ -86,21 +81,21 @@ static inline int qcom_scm_remap_error(int err)
> }
>
> #define QCOM_SCM_SVC_MP 0xc
> -#define QCOM_SCM_RESTORE_SEC_CFG 2
> +#define QCOM_SCM_MP_RESTORE_SEC_CFG 2
> extern int __qcom_scm_restore_sec_cfg(struct device *dev, u32 device_id,
> u32 spare);
> -#define QCOM_SCM_IOMMU_SECURE_PTBL_SIZE 3
> -#define QCOM_SCM_IOMMU_SECURE_PTBL_INIT 4
> +#define QCOM_SCM_MP_IOMMU_SECURE_PTBL_SIZE 3
> +#define QCOM_SCM_MP_IOMMU_SECURE_PTBL_INIT 4
> #define QCOM_SCM_SVC_SMMU_PROGRAM 0x15
> -#define QCOM_SCM_CONFIG_ERRATA1 0x3
> -#define QCOM_SCM_CONFIG_ERRATA1_CLIENT_ALL 0x2
> +#define QCOM_SCM_SMMU_CONFIG_ERRATA1 0x3
> +#define QCOM_SCM_SMMU_CONFIG_ERRATA1_CLIENT_ALL 0x2
> extern int __qcom_scm_iommu_secure_ptbl_size(struct device *dev, u32 spare,
> size_t *size);
> extern int __qcom_scm_iommu_secure_ptbl_init(struct device *dev, u64 addr,
> u32 size, u32 spare);
> extern int __qcom_scm_qsmmu500_wait_safe_toggle(struct device *dev,
> bool enable);
> -#define QCOM_MEM_PROT_ASSIGN_ID 0x16
> +#define QCOM_SCM_MP_ASSIGN 0x16
> extern int __qcom_scm_assign_mem(struct device *dev,
> phys_addr_t mem_region, size_t mem_sz,
> phys_addr_t src, size_t src_sz,
> --
> The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
> a Linux Foundation Collaborative Project
>

2019-11-06 06:06:58

by Bjorn Andersson

[permalink] [raw]
Subject: Re: [PATCH 03/17] firmware: qcom_scm: Order functions, definitions by service/command

On Mon 04 Nov 17:27 PST 2019, Elliot Berman wrote:

> Definitions throughout qcom_scm are loosely grouped and loosely ordered.
> Sort all the functions/definitions by service ID/command ID to improve
> sanity when needing to add new functionality to this driver.
>
> Signed-off-by: Elliot Berman <[email protected]>

Acked-by: Bjorn Andersson <[email protected]>

> ---
> drivers/firmware/qcom_scm-32.c | 104 +++++++++----------
> drivers/firmware/qcom_scm-64.c | 192 +++++++++++++++++------------------
> drivers/firmware/qcom_scm.c | 224 ++++++++++++++++++++---------------------
> drivers/firmware/qcom_scm.h | 107 ++++++++++----------
> include/linux/qcom_scm.h | 72 ++++++-------
> 5 files changed, 350 insertions(+), 349 deletions(-)
>
> diff --git a/drivers/firmware/qcom_scm-32.c b/drivers/firmware/qcom_scm-32.c
> index 87b520f..b09fddf 100644
> --- a/drivers/firmware/qcom_scm-32.c
> +++ b/drivers/firmware/qcom_scm-32.c
> @@ -419,33 +419,28 @@ void __qcom_scm_cpu_power_down(u32 flags)
> flags & QCOM_SCM_FLUSH_FLAG_MASK);
> }
>
> -int __qcom_scm_is_call_available(struct device *dev, u32 svc_id, u32 cmd_id)
> +int __qcom_scm_set_remote_state(struct device *dev, u32 state, u32 id)
> {
> + struct {
> + __le32 state;
> + __le32 id;
> + } req;
> + __le32 scm_ret = 0;
> int ret;
> - __le32 svc_cmd = cpu_to_le32((svc_id << 10) | cmd_id);
> - __le32 ret_val = 0;
> -
> - ret = qcom_scm_call(dev, QCOM_SCM_SVC_INFO, QCOM_SCM_INFO_IS_CALL_AVAIL,
> - &svc_cmd, sizeof(svc_cmd), &ret_val,
> - sizeof(ret_val));
> - if (ret)
> - return ret;
>
> - return le32_to_cpu(ret_val);
> -}
> + req.state = cpu_to_le32(state);
> + req.id = cpu_to_le32(id);
>
> -int __qcom_scm_hdcp_req(struct device *dev, struct qcom_scm_hdcp_req *req,
> - u32 req_cnt, u32 *resp)
> -{
> - if (req_cnt > QCOM_SCM_HDCP_MAX_REQ_CNT)
> - return -ERANGE;
> + ret = qcom_scm_call(dev, QCOM_SCM_SVC_BOOT, QCOM_SCM_BOOT_SET_REMOTE_STATE,
> + &req, sizeof(req), &scm_ret, sizeof(scm_ret));
>
> - return qcom_scm_call(dev, QCOM_SCM_SVC_HDCP, QCOM_SCM_HDCP_INVOKE,
> - req, req_cnt * sizeof(*req), resp, sizeof(*resp));
> + return ret ? : le32_to_cpu(scm_ret);
> }
>
> -void __qcom_scm_init(void)
> +int __qcom_scm_set_dload_mode(struct device *dev, bool enable)
> {
> + return qcom_scm_call_atomic2(QCOM_SCM_SVC_BOOT, QCOM_SCM_BOOT_SET_DLOAD_MODE,
> + enable ? QCOM_SCM_BOOT_SET_DLOAD_MODE : 0, 0);
> }
>
> bool __qcom_scm_pas_supported(struct device *dev, u32 peripheral)
> @@ -550,35 +545,37 @@ int __qcom_scm_pas_mss_reset(struct device *dev, bool reset)
> return ret ? : le32_to_cpu(out);
> }
>
> -int __qcom_scm_set_dload_mode(struct device *dev, bool enable)
> -{
> - return qcom_scm_call_atomic2(QCOM_SCM_SVC_BOOT, QCOM_SCM_BOOT_SET_DLOAD_MODE,
> - enable ? QCOM_SCM_BOOT_SET_DLOAD_MODE : 0, 0);
> -}
> -
> -int __qcom_scm_set_remote_state(struct device *dev, u32 state, u32 id)
> +int __qcom_scm_io_readl(struct device *dev, phys_addr_t addr,
> + unsigned int *val)
> {
> - struct {
> - __le32 state;
> - __le32 id;
> - } req;
> - __le32 scm_ret = 0;
> int ret;
>
> - req.state = cpu_to_le32(state);
> - req.id = cpu_to_le32(id);
> + ret = qcom_scm_call_atomic1(QCOM_SCM_SVC_IO, QCOM_SCM_IO_READ, addr);
> + if (ret >= 0)
> + *val = ret;
>
> - ret = qcom_scm_call(dev, QCOM_SCM_SVC_BOOT, QCOM_SCM_BOOT_SET_REMOTE_STATE,
> - &req, sizeof(req), &scm_ret, sizeof(scm_ret));
> + return ret < 0 ? ret : 0;
> +}
>
> - return ret ? : le32_to_cpu(scm_ret);
> +int __qcom_scm_io_writel(struct device *dev, phys_addr_t addr, unsigned int val)
> +{
> + return qcom_scm_call_atomic2(QCOM_SCM_SVC_IO, QCOM_SCM_IO_WRITE,
> + addr, val);
> }
>
> -int __qcom_scm_assign_mem(struct device *dev, phys_addr_t mem_region,
> - size_t mem_sz, phys_addr_t src, size_t src_sz,
> - phys_addr_t dest, size_t dest_sz)
> +int __qcom_scm_is_call_available(struct device *dev, u32 svc_id, u32 cmd_id)
> {
> - return -ENODEV;
> + int ret;
> + __le32 svc_cmd = cpu_to_le32((svc_id << 10) | cmd_id);
> + __le32 ret_val = 0;
> +
> + ret = qcom_scm_call(dev, QCOM_SCM_SVC_INFO, QCOM_SCM_INFO_IS_CALL_AVAIL,
> + &svc_cmd, sizeof(svc_cmd), &ret_val,
> + sizeof(ret_val));
> + if (ret)
> + return ret;
> +
> + return le32_to_cpu(ret_val);
> }
>
> int __qcom_scm_restore_sec_cfg(struct device *dev, u32 device_id,
> @@ -599,25 +596,28 @@ int __qcom_scm_iommu_secure_ptbl_init(struct device *dev, u64 addr, u32 size,
> return -ENODEV;
> }
>
> -int __qcom_scm_io_readl(struct device *dev, phys_addr_t addr,
> - unsigned int *val)
> +int __qcom_scm_assign_mem(struct device *dev, phys_addr_t mem_region,
> + size_t mem_sz, phys_addr_t src, size_t src_sz,
> + phys_addr_t dest, size_t dest_sz)
> {
> - int ret;
> -
> - ret = qcom_scm_call_atomic1(QCOM_SCM_SVC_IO, QCOM_SCM_IO_READ, addr);
> - if (ret >= 0)
> - *val = ret;
> -
> - return ret < 0 ? ret : 0;
> + return -ENODEV;
> }
>
> -int __qcom_scm_io_writel(struct device *dev, phys_addr_t addr, unsigned int val)
> +int __qcom_scm_hdcp_req(struct device *dev, struct qcom_scm_hdcp_req *req,
> + u32 req_cnt, u32 *resp)
> {
> - return qcom_scm_call_atomic2(QCOM_SCM_SVC_IO, QCOM_SCM_IO_WRITE,
> - addr, val);
> + if (req_cnt > QCOM_SCM_HDCP_MAX_REQ_CNT)
> + return -ERANGE;
> +
> + return qcom_scm_call(dev, QCOM_SCM_SVC_HDCP, QCOM_SCM_HDCP_INVOKE,
> + req, req_cnt * sizeof(*req), resp, sizeof(*resp));
> }
>
> int __qcom_scm_qsmmu500_wait_safe_toggle(struct device *dev, bool enable)
> {
> return -ENODEV;
> }
> +
> +void __qcom_scm_init(void)
> +{
> +}
> \ No newline at end of file
> diff --git a/drivers/firmware/qcom_scm-64.c b/drivers/firmware/qcom_scm-64.c
> index f0b4853..ead0b5f 100644
> --- a/drivers/firmware/qcom_scm-64.c
> +++ b/drivers/firmware/qcom_scm-64.c
> @@ -246,68 +246,33 @@ void __qcom_scm_cpu_power_down(u32 flags)
> {
> }
>
> -int __qcom_scm_is_call_available(struct device *dev, u32 svc_id, u32 cmd_id)
> +int __qcom_scm_set_remote_state(struct device *dev, u32 state, u32 id)
> {
> - int ret;
> struct qcom_scm_desc desc = {0};
> struct arm_smccc_res res;
> + int ret;
>
> - desc.arginfo = QCOM_SCM_ARGS(1);
> - desc.args[0] = SMCCC_FUNCNUM(svc_id, cmd_id) |
> - (ARM_SMCCC_OWNER_SIP << ARM_SMCCC_OWNER_SHIFT);
> + desc.args[0] = state;
> + desc.args[1] = id;
> + desc.arginfo = QCOM_SCM_ARGS(2);
>
> - ret = qcom_scm_call(dev, QCOM_SCM_SVC_INFO, QCOM_SCM_INFO_IS_CALL_AVAIL,
> + ret = qcom_scm_call(dev, QCOM_SCM_SVC_BOOT, QCOM_SCM_BOOT_SET_REMOTE_STATE,
> &desc, &res);
>
> return ret ? : res.a1;
> }
>
> -int __qcom_scm_hdcp_req(struct device *dev, struct qcom_scm_hdcp_req *req,
> - u32 req_cnt, u32 *resp)
> +int __qcom_scm_set_dload_mode(struct device *dev, bool enable)
> {
> - int ret;
> struct qcom_scm_desc desc = {0};
> struct arm_smccc_res res;
>
> - if (req_cnt > QCOM_SCM_HDCP_MAX_REQ_CNT)
> - return -ERANGE;
> -
> - desc.args[0] = req[0].addr;
> - desc.args[1] = req[0].val;
> - desc.args[2] = req[1].addr;
> - desc.args[3] = req[1].val;
> - desc.args[4] = req[2].addr;
> - desc.args[5] = req[2].val;
> - desc.args[6] = req[3].addr;
> - desc.args[7] = req[3].val;
> - desc.args[8] = req[4].addr;
> - desc.args[9] = req[4].val;
> - desc.arginfo = QCOM_SCM_ARGS(10);
> -
> - ret = qcom_scm_call(dev, QCOM_SCM_SVC_HDCP, QCOM_SCM_HDCP_INVOKE, &desc,
> - &res);
> - *resp = res.a1;
> -
> - return ret;
> -}
> -
> -void __qcom_scm_init(void)
> -{
> - u64 cmd;
> - struct arm_smccc_res res;
> - u32 function = SMCCC_FUNCNUM(QCOM_SCM_SVC_INFO, QCOM_SCM_INFO_IS_CALL_AVAIL);
> -
> - /* First try a SMC64 call */
> - cmd = ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, ARM_SMCCC_SMC_64,
> - ARM_SMCCC_OWNER_SIP, function);
> -
> - arm_smccc_smc(cmd, QCOM_SCM_ARGS(1), cmd & (~BIT(ARM_SMCCC_TYPE_SHIFT)),
> - 0, 0, 0, 0, 0, &res);
> + desc.args[0] = QCOM_SCM_BOOT_SET_DLOAD_MODE;
> + desc.args[1] = enable ? QCOM_SCM_BOOT_SET_DLOAD_MODE : 0;
> + desc.arginfo = QCOM_SCM_ARGS(2);
>
> - if (!res.a0 && res.a1)
> - qcom_smccc_convention = ARM_SMCCC_SMC_64;
> - else
> - qcom_smccc_convention = ARM_SMCCC_SMC_32;
> + return qcom_scm_call(dev, QCOM_SCM_SVC_BOOT, QCOM_SCM_BOOT_SET_DLOAD_MODE,
> + &desc, &res);
> }
>
> bool __qcom_scm_pas_supported(struct device *dev, u32 peripheral)
> @@ -408,44 +373,48 @@ int __qcom_scm_pas_mss_reset(struct device *dev, bool reset)
> return ret ? : res.a1;
> }
>
> -int __qcom_scm_set_remote_state(struct device *dev, u32 state, u32 id)
> +int __qcom_scm_io_readl(struct device *dev, phys_addr_t addr,
> + unsigned int *val)
> {
> struct qcom_scm_desc desc = {0};
> struct arm_smccc_res res;
> int ret;
>
> - desc.args[0] = state;
> - desc.args[1] = id;
> - desc.arginfo = QCOM_SCM_ARGS(2);
> + desc.args[0] = addr;
> + desc.arginfo = QCOM_SCM_ARGS(1);
>
> - ret = qcom_scm_call(dev, QCOM_SCM_SVC_BOOT, QCOM_SCM_BOOT_SET_REMOTE_STATE,
> + ret = qcom_scm_call(dev, QCOM_SCM_SVC_IO, QCOM_SCM_IO_READ,
> &desc, &res);
> + if (ret >= 0)
> + *val = res.a1;
>
> - return ret ? : res.a1;
> + return ret < 0 ? ret : 0;
> }
>
> -int __qcom_scm_assign_mem(struct device *dev, phys_addr_t mem_region,
> - size_t mem_sz, phys_addr_t src, size_t src_sz,
> - phys_addr_t dest, size_t dest_sz)
> +int __qcom_scm_io_writel(struct device *dev, phys_addr_t addr, unsigned int val)
> {
> - int ret;
> struct qcom_scm_desc desc = {0};
> struct arm_smccc_res res;
>
> - desc.args[0] = mem_region;
> - desc.args[1] = mem_sz;
> - desc.args[2] = src;
> - desc.args[3] = src_sz;
> - desc.args[4] = dest;
> - desc.args[5] = dest_sz;
> - desc.args[6] = 0;
> + desc.args[0] = addr;
> + desc.args[1] = val;
> + desc.arginfo = QCOM_SCM_ARGS(2);
>
> - desc.arginfo = QCOM_SCM_ARGS(7, QCOM_SCM_RO, QCOM_SCM_VAL,
> - QCOM_SCM_RO, QCOM_SCM_VAL, QCOM_SCM_RO,
> - QCOM_SCM_VAL, QCOM_SCM_VAL);
> + return qcom_scm_call(dev, QCOM_SCM_SVC_IO, QCOM_SCM_IO_WRITE,
> + &desc, &res);
> +}
>
> - ret = qcom_scm_call(dev, QCOM_SCM_SVC_MP,
> - QCOM_SCM_MP_ASSIGN,
> +int __qcom_scm_is_call_available(struct device *dev, u32 svc_id, u32 cmd_id)
> +{
> + int ret;
> + struct qcom_scm_desc desc = {0};
> + struct arm_smccc_res res;
> +
> + desc.arginfo = QCOM_SCM_ARGS(1);
> + desc.args[0] = SMCCC_FUNCNUM(svc_id, cmd_id) |
> + (ARM_SMCCC_OWNER_SIP << ARM_SMCCC_OWNER_SHIFT);
> +
> + ret = qcom_scm_call(dev, QCOM_SCM_SVC_INFO, QCOM_SCM_INFO_IS_CALL_AVAIL,
> &desc, &res);
>
> return ret ? : res.a1;
> @@ -509,48 +478,60 @@ int __qcom_scm_iommu_secure_ptbl_init(struct device *dev, u64 addr, u32 size,
> return ret;
> }
>
> -int __qcom_scm_set_dload_mode(struct device *dev, bool enable)
> +int __qcom_scm_assign_mem(struct device *dev, phys_addr_t mem_region,
> + size_t mem_sz, phys_addr_t src, size_t src_sz,
> + phys_addr_t dest, size_t dest_sz)
> {
> + int ret;
> struct qcom_scm_desc desc = {0};
> struct arm_smccc_res res;
>
> - desc.args[0] = QCOM_SCM_BOOT_SET_DLOAD_MODE;
> - desc.args[1] = enable ? QCOM_SCM_BOOT_SET_DLOAD_MODE : 0;
> - desc.arginfo = QCOM_SCM_ARGS(2);
> -
> - return qcom_scm_call(dev, QCOM_SCM_SVC_BOOT, QCOM_SCM_BOOT_SET_DLOAD_MODE,
> - &desc, &res);
> -}
> -
> -int __qcom_scm_io_readl(struct device *dev, phys_addr_t addr,
> - unsigned int *val)
> -{
> - struct qcom_scm_desc desc = {0};
> - struct arm_smccc_res res;
> - int ret;
> + desc.args[0] = mem_region;
> + desc.args[1] = mem_sz;
> + desc.args[2] = src;
> + desc.args[3] = src_sz;
> + desc.args[4] = dest;
> + desc.args[5] = dest_sz;
> + desc.args[6] = 0;
>
> - desc.args[0] = addr;
> - desc.arginfo = QCOM_SCM_ARGS(1);
> + desc.arginfo = QCOM_SCM_ARGS(7, QCOM_SCM_RO, QCOM_SCM_VAL,
> + QCOM_SCM_RO, QCOM_SCM_VAL, QCOM_SCM_RO,
> + QCOM_SCM_VAL, QCOM_SCM_VAL);
>
> - ret = qcom_scm_call(dev, QCOM_SCM_SVC_IO, QCOM_SCM_IO_READ,
> + ret = qcom_scm_call(dev, QCOM_SCM_SVC_MP,
> + QCOM_SCM_MP_ASSIGN,
> &desc, &res);
> - if (ret >= 0)
> - *val = res.a1;
>
> - return ret < 0 ? ret : 0;
> + return ret ? : res.a1;
> }
>
> -int __qcom_scm_io_writel(struct device *dev, phys_addr_t addr, unsigned int val)
> +int __qcom_scm_hdcp_req(struct device *dev, struct qcom_scm_hdcp_req *req,
> + u32 req_cnt, u32 *resp)
> {
> + int ret;
> struct qcom_scm_desc desc = {0};
> struct arm_smccc_res res;
>
> - desc.args[0] = addr;
> - desc.args[1] = val;
> - desc.arginfo = QCOM_SCM_ARGS(2);
> + if (req_cnt > QCOM_SCM_HDCP_MAX_REQ_CNT)
> + return -ERANGE;
>
> - return qcom_scm_call(dev, QCOM_SCM_SVC_IO, QCOM_SCM_IO_WRITE,
> - &desc, &res);
> + desc.args[0] = req[0].addr;
> + desc.args[1] = req[0].val;
> + desc.args[2] = req[1].addr;
> + desc.args[3] = req[1].val;
> + desc.args[4] = req[2].addr;
> + desc.args[5] = req[2].val;
> + desc.args[6] = req[3].addr;
> + desc.args[7] = req[3].val;
> + desc.args[8] = req[4].addr;
> + desc.args[9] = req[4].val;
> + desc.arginfo = QCOM_SCM_ARGS(10);
> +
> + ret = qcom_scm_call(dev, QCOM_SCM_SVC_HDCP, QCOM_SCM_HDCP_INVOKE, &desc,
> + &res);
> + *resp = res.a1;
> +
> + return ret;
> }
>
> int __qcom_scm_qsmmu500_wait_safe_toggle(struct device *dev, bool en)
> @@ -565,3 +546,22 @@ int __qcom_scm_qsmmu500_wait_safe_toggle(struct device *dev, bool en)
> return qcom_scm_call_atomic(dev, QCOM_SCM_SVC_SMMU_PROGRAM,
> QCOM_SCM_SMMU_CONFIG_ERRATA1, &desc, &res);
> }
> +
> +void __qcom_scm_init(void)
> +{
> + u64 cmd;
> + struct arm_smccc_res res;
> + u32 function = SMCCC_FUNCNUM(QCOM_SCM_SVC_INFO, QCOM_SCM_INFO_IS_CALL_AVAIL);
> +
> + /* First try a SMC64 call */
> + cmd = ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, ARM_SMCCC_SMC_64,
> + ARM_SMCCC_OWNER_SIP, function);
> +
> + arm_smccc_smc(cmd, QCOM_SCM_ARGS(1), cmd & (~BIT(ARM_SMCCC_TYPE_SHIFT)),
> + 0, 0, 0, 0, 0, &res);
> +
> + if (!res.a0 && res.a1)
> + qcom_smccc_convention = ARM_SMCCC_SMC_64;
> + else
> + qcom_smccc_convention = ARM_SMCCC_SMC_32;
> +}
> diff --git a/drivers/firmware/qcom_scm.c b/drivers/firmware/qcom_scm.c
> index 450d6d6..83fc049 100644
> --- a/drivers/firmware/qcom_scm.c
> +++ b/drivers/firmware/qcom_scm.c
> @@ -127,47 +127,33 @@ void qcom_scm_cpu_power_down(u32 flags)
> }
> EXPORT_SYMBOL(qcom_scm_cpu_power_down);
>
> -/**
> - * qcom_scm_hdcp_available() - Check if secure environment supports HDCP.
> - *
> - * Return true if HDCP is supported, false if not.
> - */
> -bool qcom_scm_hdcp_available(void)
> +int qcom_scm_set_remote_state(u32 state, u32 id)
> {
> - int ret = qcom_scm_clk_enable();
> -
> - if (ret)
> - return ret;
> -
> - ret = __qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_HDCP,
> - QCOM_SCM_HDCP_INVOKE);
> -
> - qcom_scm_clk_disable();
> -
> - return ret > 0 ? true : false;
> + return __qcom_scm_set_remote_state(__scm->dev, state, id);
> }
> -EXPORT_SYMBOL(qcom_scm_hdcp_available);
> +EXPORT_SYMBOL(qcom_scm_set_remote_state);
>
> -/**
> - * qcom_scm_hdcp_req() - Send HDCP request.
> - * @req: HDCP request array
> - * @req_cnt: HDCP request array count
> - * @resp: response buffer passed to SCM
> - *
> - * Write HDCP register(s) through SCM.
> - */
> -int qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt, u32 *resp)
> +static void qcom_scm_set_download_mode(bool enable)
> {
> - int ret = qcom_scm_clk_enable();
> + bool avail;
> + int ret = 0;
>
> - if (ret)
> - return ret;
> + avail = __qcom_scm_is_call_available(__scm->dev,
> + QCOM_SCM_SVC_BOOT,
> + QCOM_SCM_BOOT_SET_DLOAD_MODE);
> + if (avail) {
> + ret = __qcom_scm_set_dload_mode(__scm->dev, enable);
> + } else if (__scm->dload_mode_addr) {
> + ret = __qcom_scm_io_writel(__scm->dev, __scm->dload_mode_addr,
> + enable ? QCOM_SCM_BOOT_SET_DLOAD_MODE : 0);
> + } else {
> + dev_err(__scm->dev,
> + "No available mechanism for setting download mode\n");
> + }
>
> - ret = __qcom_scm_hdcp_req(__scm->dev, req, req_cnt, resp);
> - qcom_scm_clk_disable();
> - return ret;
> + if (ret)
> + dev_err(__scm->dev, "failed to set download mode: %d\n", ret);
> }
> -EXPORT_SYMBOL(qcom_scm_hdcp_req);
>
> /**
> * qcom_scm_pas_supported() - Check if the peripheral authentication service is
> @@ -325,30 +311,6 @@ static const struct reset_control_ops qcom_scm_pas_reset_ops = {
> .deassert = qcom_scm_pas_reset_deassert,
> };
>
> -int qcom_scm_restore_sec_cfg(u32 device_id, u32 spare)
> -{
> - return __qcom_scm_restore_sec_cfg(__scm->dev, device_id, spare);
> -}
> -EXPORT_SYMBOL(qcom_scm_restore_sec_cfg);
> -
> -int qcom_scm_iommu_secure_ptbl_size(u32 spare, size_t *size)
> -{
> - return __qcom_scm_iommu_secure_ptbl_size(__scm->dev, spare, size);
> -}
> -EXPORT_SYMBOL(qcom_scm_iommu_secure_ptbl_size);
> -
> -int qcom_scm_iommu_secure_ptbl_init(u64 addr, u32 size, u32 spare)
> -{
> - return __qcom_scm_iommu_secure_ptbl_init(__scm->dev, addr, size, spare);
> -}
> -EXPORT_SYMBOL(qcom_scm_iommu_secure_ptbl_init);
> -
> -int qcom_scm_qsmmu500_wait_safe_toggle(bool en)
> -{
> - return __qcom_scm_qsmmu500_wait_safe_toggle(__scm->dev, en);
> -}
> -EXPORT_SYMBOL(qcom_scm_qsmmu500_wait_safe_toggle);
> -
> int qcom_scm_io_readl(phys_addr_t addr, unsigned int *val)
> {
> return __qcom_scm_io_readl(__scm->dev, addr, val);
> @@ -361,68 +323,23 @@ int qcom_scm_io_writel(phys_addr_t addr, unsigned int val)
> }
> EXPORT_SYMBOL(qcom_scm_io_writel);
>
> -static void qcom_scm_set_download_mode(bool enable)
> -{
> - bool avail;
> - int ret = 0;
> -
> - avail = __qcom_scm_is_call_available(__scm->dev,
> - QCOM_SCM_SVC_BOOT,
> - QCOM_SCM_BOOT_SET_DLOAD_MODE);
> - if (avail) {
> - ret = __qcom_scm_set_dload_mode(__scm->dev, enable);
> - } else if (__scm->dload_mode_addr) {
> - ret = __qcom_scm_io_writel(__scm->dev, __scm->dload_mode_addr,
> - enable ? QCOM_SCM_BOOT_SET_DLOAD_MODE : 0);
> - } else {
> - dev_err(__scm->dev,
> - "No available mechanism for setting download mode\n");
> - }
> -
> - if (ret)
> - dev_err(__scm->dev, "failed to set download mode: %d\n", ret);
> -}
> -
> -static int qcom_scm_find_dload_address(struct device *dev, u64 *addr)
> +int qcom_scm_restore_sec_cfg(u32 device_id, u32 spare)
> {
> - struct device_node *tcsr;
> - struct device_node *np = dev->of_node;
> - struct resource res;
> - u32 offset;
> - int ret;
> -
> - tcsr = of_parse_phandle(np, "qcom,dload-mode", 0);
> - if (!tcsr)
> - return 0;
> -
> - ret = of_address_to_resource(tcsr, 0, &res);
> - of_node_put(tcsr);
> - if (ret)
> - return ret;
> -
> - ret = of_property_read_u32_index(np, "qcom,dload-mode", 1, &offset);
> - if (ret < 0)
> - return ret;
> -
> - *addr = res.start + offset;
> -
> - return 0;
> + return __qcom_scm_restore_sec_cfg(__scm->dev, device_id, spare);
> }
> +EXPORT_SYMBOL(qcom_scm_restore_sec_cfg);
>
> -/**
> - * qcom_scm_is_available() - Checks if SCM is available
> - */
> -bool qcom_scm_is_available(void)
> +int qcom_scm_iommu_secure_ptbl_size(u32 spare, size_t *size)
> {
> - return !!__scm;
> + return __qcom_scm_iommu_secure_ptbl_size(__scm->dev, spare, size);
> }
> -EXPORT_SYMBOL(qcom_scm_is_available);
> +EXPORT_SYMBOL(qcom_scm_iommu_secure_ptbl_size);
>
> -int qcom_scm_set_remote_state(u32 state, u32 id)
> +int qcom_scm_iommu_secure_ptbl_init(u64 addr, u32 size, u32 spare)
> {
> - return __qcom_scm_set_remote_state(__scm->dev, state, id);
> + return __qcom_scm_iommu_secure_ptbl_init(__scm->dev, addr, size, spare);
> }
> -EXPORT_SYMBOL(qcom_scm_set_remote_state);
> +EXPORT_SYMBOL(qcom_scm_iommu_secure_ptbl_init);
>
> /**
> * qcom_scm_assign_mem() - Make a secure call to reassign memory ownership
> @@ -506,6 +423,89 @@ int qcom_scm_assign_mem(phys_addr_t mem_addr, size_t mem_sz,
> }
> EXPORT_SYMBOL(qcom_scm_assign_mem);
>
> +/**
> + * qcom_scm_hdcp_available() - Check if secure environment supports HDCP.
> + *
> + * Return true if HDCP is supported, false if not.
> + */
> +bool qcom_scm_hdcp_available(void)
> +{
> + int ret = qcom_scm_clk_enable();
> +
> + if (ret)
> + return ret;
> +
> + ret = __qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_HDCP,
> + QCOM_SCM_HDCP_INVOKE);
> +
> + qcom_scm_clk_disable();
> +
> + return ret > 0 ? true : false;
> +}
> +EXPORT_SYMBOL(qcom_scm_hdcp_available);
> +
> +/**
> + * qcom_scm_hdcp_req() - Send HDCP request.
> + * @req: HDCP request array
> + * @req_cnt: HDCP request array count
> + * @resp: response buffer passed to SCM
> + *
> + * Write HDCP register(s) through SCM.
> + */
> +int qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt, u32 *resp)
> +{
> + int ret = qcom_scm_clk_enable();
> +
> + if (ret)
> + return ret;
> +
> + ret = __qcom_scm_hdcp_req(__scm->dev, req, req_cnt, resp);
> + qcom_scm_clk_disable();
> + return ret;
> +}
> +EXPORT_SYMBOL(qcom_scm_hdcp_req);
> +
> +int qcom_scm_qsmmu500_wait_safe_toggle(bool en)
> +{
> + return __qcom_scm_qsmmu500_wait_safe_toggle(__scm->dev, en);
> +}
> +EXPORT_SYMBOL(qcom_scm_qsmmu500_wait_safe_toggle);
> +
> +/**
> + * qcom_scm_is_available() - Checks if SCM is available
> + */
> +bool qcom_scm_is_available(void)
> +{
> + return !!__scm;
> +}
> +EXPORT_SYMBOL(qcom_scm_is_available);
> +
> +static int qcom_scm_find_dload_address(struct device *dev, u64 *addr)
> +{
> + struct device_node *tcsr;
> + struct device_node *np = dev->of_node;
> + struct resource res;
> + u32 offset;
> + int ret;
> +
> + tcsr = of_parse_phandle(np, "qcom,dload-mode", 0);
> + if (!tcsr)
> + return 0;
> +
> + ret = of_address_to_resource(tcsr, 0, &res);
> + of_node_put(tcsr);
> + if (ret)
> + return ret;
> +
> + ret = of_property_read_u32_index(np, "qcom,dload-mode", 1, &offset);
> + if (ret < 0)
> + return ret;
> +
> + *addr = res.start + offset;
> +
> + return 0;
> +}
> +
> static int qcom_scm_probe(struct platform_device *pdev)
> {
> struct qcom_scm *scm;
> diff --git a/drivers/firmware/qcom_scm.h b/drivers/firmware/qcom_scm.h
> index 99e91ba..4be482f 100644
> --- a/drivers/firmware/qcom_scm.h
> +++ b/drivers/firmware/qcom_scm.h
> @@ -4,54 +4,74 @@
> #ifndef __QCOM_SCM_INT_H
> #define __QCOM_SCM_INT_H
>
> -#define QCOM_SCM_SVC_BOOT 0x1
> -#define QCOM_SCM_BOOT_SET_ADDR 0x1
> +#define QCOM_SCM_SVC_BOOT 0x01
> +#define QCOM_SCM_BOOT_SET_ADDR 0x01
> +#define QCOM_SCM_BOOT_TERMINATE_PC 0x02
> +#define QCOM_SCM_BOOT_SET_REMOTE_STATE 0x0a
> #define QCOM_SCM_BOOT_SET_DLOAD_MODE 0x10
> -#define QCOM_SCM_BOOT_SET_REMOTE_STATE 0xa
> -extern int __qcom_scm_set_remote_state(struct device *dev, u32 state, u32 id);
> -extern int __qcom_scm_set_dload_mode(struct device *dev, bool enable);
> -
> +extern int __qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus);
> extern int __qcom_scm_set_warm_boot_addr(struct device *dev, void *entry,
> const cpumask_t *cpus);
> -extern int __qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus);
> -
> -#define QCOM_SCM_BOOT_TERMINATE_PC 0x2
> -#define QCOM_SCM_FLUSH_FLAG_MASK 0x3
> extern void __qcom_scm_cpu_power_down(u32 flags);
> +extern int __qcom_scm_set_remote_state(struct device *dev, u32 state, u32 id);
> +extern int __qcom_scm_set_dload_mode(struct device *dev, bool enable);
> +#define QCOM_SCM_FLUSH_FLAG_MASK 0x3
> +
> +#define QCOM_SCM_SVC_PIL 0x02
> +#define QCOM_SCM_PIL_PAS_INIT_IMAGE 0x01
> +#define QCOM_SCM_PIL_PAS_MEM_SETUP 0x02
> +#define QCOM_SCM_PIL_PAS_AUTH_AND_RESET 0x05
> +#define QCOM_SCM_PIL_PAS_SHUTDOWN 0x06
> +#define QCOM_SCM_PIL_PAS_IS_SUPPORTED 0x07
> +#define QCOM_SCM_PIL_PAS_MSS_RESET 0x0a
> +extern bool __qcom_scm_pas_supported(struct device *dev, u32 peripheral);
> +extern int __qcom_scm_pas_init_image(struct device *dev, u32 peripheral,
> + dma_addr_t metadata_phys);
> +extern int __qcom_scm_pas_mem_setup(struct device *dev, u32 peripheral,
> + phys_addr_t addr, phys_addr_t size);
> +extern int __qcom_scm_pas_auth_and_reset(struct device *dev, u32 peripheral);
> +extern int __qcom_scm_pas_shutdown(struct device *dev, u32 peripheral);
> +extern int __qcom_scm_pas_mss_reset(struct device *dev, bool reset);
>
> -#define QCOM_SCM_SVC_IO 0x5
> -#define QCOM_SCM_IO_READ 0x1
> -#define QCOM_SCM_IO_WRITE 0x2
> +#define QCOM_SCM_SVC_IO 0x05
> +#define QCOM_SCM_IO_READ 0x01
> +#define QCOM_SCM_IO_WRITE 0x02
> extern int __qcom_scm_io_readl(struct device *dev, phys_addr_t addr, unsigned int *val);
> extern int __qcom_scm_io_writel(struct device *dev, phys_addr_t addr, unsigned int val);
>
> -#define QCOM_SCM_SVC_INFO 0x6
> -#define QCOM_SCM_INFO_IS_CALL_AVAIL 0x1
> +#define QCOM_SCM_SVC_INFO 0x06
> +#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_HDCP 0x11
> -#define QCOM_SCM_HDCP_INVOKE 0x01
> +#define QCOM_SCM_SVC_MP 0x0c
> +#define QCOM_SCM_MP_RESTORE_SEC_CFG 0x02
> +#define QCOM_SCM_MP_IOMMU_SECURE_PTBL_SIZE 0x03
> +#define QCOM_SCM_MP_IOMMU_SECURE_PTBL_INIT 0x04
> +#define QCOM_SCM_MP_ASSIGN 0x16
> +extern int __qcom_scm_restore_sec_cfg(struct device *dev, u32 device_id,
> + u32 spare);
> +extern int __qcom_scm_iommu_secure_ptbl_size(struct device *dev, u32 spare,
> + size_t *size);
> +extern int __qcom_scm_iommu_secure_ptbl_init(struct device *dev, u64 addr,
> + u32 size, u32 spare);
> +extern int __qcom_scm_assign_mem(struct device *dev,
> + phys_addr_t mem_region, size_t mem_sz,
> + phys_addr_t src, size_t src_sz,
> + phys_addr_t dest, size_t dest_sz);
> +
> +#define QCOM_SCM_SVC_HDCP 0x11
> +#define QCOM_SCM_HDCP_INVOKE 0x01
> extern int __qcom_scm_hdcp_req(struct device *dev,
> struct qcom_scm_hdcp_req *req, u32 req_cnt, u32 *resp);
>
> -extern void __qcom_scm_init(void);
> +#define QCOM_SCM_SVC_SMMU_PROGRAM 0x15
> +#define QCOM_SCM_SMMU_CONFIG_ERRATA1 0x3
> +extern int __qcom_scm_qsmmu500_wait_safe_toggle(struct device *dev,
> + bool enable);
> +#define QCOM_SCM_SMMU_CONFIG_ERRATA1_CLIENT_ALL 0x2
>
> -#define QCOM_SCM_SVC_PIL 0x2
> -#define QCOM_SCM_PIL_PAS_INIT_IMAGE 0x1
> -#define QCOM_SCM_PIL_PAS_MEM_SETUP 0x2
> -#define QCOM_SCM_PIL_PAS_AUTH_AND_RESET 0x5
> -#define QCOM_SCM_PIL_PAS_SHUTDOWN 0x6
> -#define QCOM_SCM_PIL_PAS_IS_SUPPORTED 0x7
> -#define QCOM_SCM_PIL_PAS_MSS_RESET 0xa
> -extern bool __qcom_scm_pas_supported(struct device *dev, u32 peripheral);
> -extern int __qcom_scm_pas_init_image(struct device *dev, u32 peripheral,
> - dma_addr_t metadata_phys);
> -extern int __qcom_scm_pas_mem_setup(struct device *dev, u32 peripheral,
> - phys_addr_t addr, phys_addr_t size);
> -extern int __qcom_scm_pas_auth_and_reset(struct device *dev, u32 peripheral);
> -extern int __qcom_scm_pas_shutdown(struct device *dev, u32 peripheral);
> -extern int __qcom_scm_pas_mss_reset(struct device *dev, bool reset);
> +extern void __qcom_scm_init(void);
>
> /* common error codes */
> #define QCOM_SCM_V2_EBUSY -12
> @@ -80,25 +100,4 @@ static inline int qcom_scm_remap_error(int err)
> return -EINVAL;
> }
>
> -#define QCOM_SCM_SVC_MP 0xc
> -#define QCOM_SCM_MP_RESTORE_SEC_CFG 2
> -extern int __qcom_scm_restore_sec_cfg(struct device *dev, u32 device_id,
> - u32 spare);
> -#define QCOM_SCM_MP_IOMMU_SECURE_PTBL_SIZE 3
> -#define QCOM_SCM_MP_IOMMU_SECURE_PTBL_INIT 4
> -#define QCOM_SCM_SVC_SMMU_PROGRAM 0x15
> -#define QCOM_SCM_SMMU_CONFIG_ERRATA1 0x3
> -#define QCOM_SCM_SMMU_CONFIG_ERRATA1_CLIENT_ALL 0x2
> -extern int __qcom_scm_iommu_secure_ptbl_size(struct device *dev, u32 spare,
> - size_t *size);
> -extern int __qcom_scm_iommu_secure_ptbl_init(struct device *dev, u64 addr,
> - u32 size, u32 spare);
> -extern int __qcom_scm_qsmmu500_wait_safe_toggle(struct device *dev,
> - bool enable);
> -#define QCOM_SCM_MP_ASSIGN 0x16
> -extern int __qcom_scm_assign_mem(struct device *dev,
> - phys_addr_t mem_region, size_t mem_sz,
> - phys_addr_t src, size_t src_sz,
> - phys_addr_t dest, size_t dest_sz);
> -
> #endif
> diff --git a/include/linux/qcom_scm.h b/include/linux/qcom_scm.h
> index ffd72b3..f8b6525 100644
> --- a/include/linux/qcom_scm.h
> +++ b/include/linux/qcom_scm.h
> @@ -37,10 +37,8 @@ struct qcom_scm_vmperm {
> #if IS_ENABLED(CONFIG_QCOM_SCM)
> extern int qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus);
> extern int qcom_scm_set_warm_boot_addr(void *entry, const cpumask_t *cpus);
> -extern bool qcom_scm_is_available(void);
> -extern bool qcom_scm_hdcp_available(void);
> -extern int qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt,
> - u32 *resp);
> +extern void qcom_scm_cpu_power_down(u32 flags);
> +extern int qcom_scm_set_remote_state(u32 state, u32 id);
> extern bool qcom_scm_pas_supported(u32 peripheral);
> extern int qcom_scm_pas_init_image(u32 peripheral, const void *metadata,
> size_t size);
> @@ -48,58 +46,62 @@ extern int qcom_scm_pas_mem_setup(u32 peripheral, phys_addr_t addr,
> phys_addr_t size);
> extern int qcom_scm_pas_auth_and_reset(u32 peripheral);
> extern int qcom_scm_pas_shutdown(u32 peripheral);
> -extern int qcom_scm_assign_mem(phys_addr_t mem_addr, size_t mem_sz,
> - unsigned int *src,
> - const struct qcom_scm_vmperm *newvm,
> - unsigned int dest_cnt);
> -extern void qcom_scm_cpu_power_down(u32 flags);
> -extern u32 qcom_scm_get_version(void);
> -extern int qcom_scm_set_remote_state(u32 state, u32 id);
> +extern int qcom_scm_io_readl(phys_addr_t addr, unsigned int *val);
> +extern int qcom_scm_io_writel(phys_addr_t addr, unsigned int val);
> extern int qcom_scm_restore_sec_cfg(u32 device_id, u32 spare);
> extern int qcom_scm_iommu_secure_ptbl_size(u32 spare, size_t *size);
> extern int qcom_scm_iommu_secure_ptbl_init(u64 addr, u32 size, u32 spare);
> +extern int qcom_scm_assign_mem(phys_addr_t mem_addr, size_t mem_sz,
> + unsigned int *src,
> + const struct qcom_scm_vmperm *newvm,
> + int dest_cnt);
> +extern bool qcom_scm_hdcp_available(void);
> +extern int qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt,
> + u32 *resp);
> extern int qcom_scm_qsmmu500_wait_safe_toggle(bool en);
> -extern int qcom_scm_io_readl(phys_addr_t addr, unsigned int *val);
> -extern int qcom_scm_io_writel(phys_addr_t addr, unsigned int val);
> +extern u32 qcom_scm_get_version(void);
> +extern bool qcom_scm_is_available(void);
> #else
>
> #include <linux/errno.h>
>
> static inline
> int qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus)
> -{
> - return -ENODEV;
> -}
> + { return -ENODEV; }
> static inline
> int qcom_scm_set_warm_boot_addr(void *entry, const cpumask_t *cpus)
> -{
> - return -ENODEV;
> -}
> -static inline bool qcom_scm_is_available(void) { return false; }
> -static inline bool qcom_scm_hdcp_available(void) { return false; }
> -static inline int qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt,
> - u32 *resp) { return -ENODEV; }
> + { return -ENODEV; }
> +static inline void qcom_scm_cpu_power_down(u32 flags) {}
> +static inline u32 qcom_scm_set_remote_state(u32 state, u32 id)
> + { return -ENODEV; }
> static inline bool qcom_scm_pas_supported(u32 peripheral) { return false; }
> static inline int qcom_scm_pas_init_image(u32 peripheral, const void *metadata,
> size_t size) { return -ENODEV; }
> static inline int qcom_scm_pas_mem_setup(u32 peripheral, phys_addr_t addr,
> phys_addr_t size) { return -ENODEV; }
> -static inline int
> -qcom_scm_pas_auth_and_reset(u32 peripheral) { return -ENODEV; }
> +static inline int qcom_scm_pas_auth_and_reset(u32 peripheral)
> + { return -ENODEV; }
> static inline int qcom_scm_pas_shutdown(u32 peripheral) { return -ENODEV; }
> +static inline int qcom_scm_io_readl(phys_addr_t addr, unsigned int *val)
> + { return -ENODEV; }
> +static inline int qcom_scm_io_writel(phys_addr_t addr, unsigned int val)
> + { return -ENODEV; }
> +static inline int qcom_scm_restore_sec_cfg(u32 device_id, u32 spare)
> + { return -ENODEV; }
> +static inline int qcom_scm_iommu_secure_ptbl_size(u32 spare, size_t *size)
> + { return -ENODEV; }
> +static inline int qcom_scm_iommu_secure_ptbl_init(u64 addr, u32 size, u32 spare)
> + { return -ENODEV; }
> static inline int qcom_scm_assign_mem(phys_addr_t mem_addr, size_t mem_sz,
> unsigned int *src,
> const struct qcom_scm_vmperm *newvm,
> - unsigned int dest_cnt) { return -ENODEV; }
> -static inline void qcom_scm_cpu_power_down(u32 flags) {}
> + int dest_cnt) { return -ENODEV; }
> +static inline bool qcom_scm_hdcp_available(void) { return false; }
> +static inline int qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt,
> + u32 *resp) { return -ENODEV; }
> +static inline int qcom_scm_qsmmu500_wait_safe_toggle(bool en)
> + { return -ENODEV; }
> static inline u32 qcom_scm_get_version(void) { return 0; }
> -static inline u32
> -qcom_scm_set_remote_state(u32 state,u32 id) { return -ENODEV; }
> -static inline int qcom_scm_restore_sec_cfg(u32 device_id, u32 spare) { return -ENODEV; }
> -static inline int qcom_scm_iommu_secure_ptbl_size(u32 spare, size_t *size) { return -ENODEV; }
> -static inline int qcom_scm_iommu_secure_ptbl_init(u64 addr, u32 size, u32 spare) { return -ENODEV; }
> -static inline int qcom_scm_qsmmu500_wait_safe_toggle(bool en) { return -ENODEV; }
> -static inline int qcom_scm_io_readl(phys_addr_t addr, unsigned int *val) { return -ENODEV; }
> -static inline int qcom_scm_io_writel(phys_addr_t addr, unsigned int val) { return -ENODEV; }
> +static inline bool qcom_scm_is_available(void) { return false; }
> #endif
> #endif
> --
> The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
> a Linux Foundation Collaborative Project
>

2019-11-06 06:08:07

by Bjorn Andersson

[permalink] [raw]
Subject: Re: [PATCH 04/17] firmware: qcom_scm: Remove unused qcom_scm_get_version

On Mon 04 Nov 17:27 PST 2019, Elliot Berman wrote:

> Remove unused qcom_scm_get_version.
>
> Signed-off-by: Elliot Berman <[email protected]>

Reviewed-by: Bjorn Andersson <[email protected]>

> ---
> drivers/firmware/qcom_scm-32.c | 36 ------------------------------------
> include/linux/qcom_scm.h | 2 --
> 2 files changed, 38 deletions(-)
>
> diff --git a/drivers/firmware/qcom_scm-32.c b/drivers/firmware/qcom_scm-32.c
> index b09fddf..b7f9f28 100644
> --- a/drivers/firmware/qcom_scm-32.c
> +++ b/drivers/firmware/qcom_scm-32.c
> @@ -291,42 +291,6 @@ static s32 qcom_scm_call_atomic2(u32 svc, u32 cmd, u32 arg1, u32 arg2)
> return r0;
> }
>
> -u32 qcom_scm_get_version(void)
> -{
> - int context_id;
> - static u32 version = -1;
> - register u32 r0 asm("r0");
> - register u32 r1 asm("r1");
> -
> - if (version != -1)
> - return version;
> -
> - mutex_lock(&qcom_scm_lock);
> -
> - r0 = 0x1 << 8;
> - r1 = (u32)&context_id;
> - do {
> - asm volatile(
> - __asmeq("%0", "r0")
> - __asmeq("%1", "r1")
> - __asmeq("%2", "r0")
> - __asmeq("%3", "r1")
> -#ifdef REQUIRES_SEC
> - ".arch_extension sec\n"
> -#endif
> - "smc #0 @ switch to secure world\n"
> - : "=r" (r0), "=r" (r1)
> - : "r" (r0), "r" (r1)
> - : "r2", "r3", "r12");
> - } while (r0 == QCOM_SCM_INTERRUPTED);
> -
> - version = r1;
> - mutex_unlock(&qcom_scm_lock);
> -
> - return version;
> -}
> -EXPORT_SYMBOL(qcom_scm_get_version);
> -
> /**
> * qcom_scm_set_cold_boot_addr() - Set the cold boot address for cpus
> * @entry: Entry point function for the cpus
> diff --git a/include/linux/qcom_scm.h b/include/linux/qcom_scm.h
> index f8b6525..05a1c7a 100644
> --- a/include/linux/qcom_scm.h
> +++ b/include/linux/qcom_scm.h
> @@ -59,7 +59,6 @@ extern bool qcom_scm_hdcp_available(void);
> extern int qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt,
> u32 *resp);
> extern int qcom_scm_qsmmu500_wait_safe_toggle(bool en);
> -extern u32 qcom_scm_get_version(void);
> extern bool qcom_scm_is_available(void);
> #else
>
> @@ -101,7 +100,6 @@ static inline int qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt,
> u32 *resp) { return -ENODEV; }
> static inline int qcom_scm_qsmmu500_wait_safe_toggle(bool en)
> { return -ENODEV; }
> -static inline u32 qcom_scm_get_version(void) { return 0; }
> static inline bool qcom_scm_is_available(void) { return false; }
> #endif
> #endif
> --
> The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
> a Linux Foundation Collaborative Project
>

2019-11-07 16:23:40

by Vinod Koul

[permalink] [raw]
Subject: Re: [PATCH 01/17] firmware: qcom_scm: Rename macros and structures

On 04-11-19, 17:27, Elliot Berman wrote:
> - Rename legacy-specific structures and macros with "legacy_" prefix.
> - Rename smccc-specific structures and macros with "smccc_" prefix.
> - Flip calculation of SMCCC_N_EXT_ARGS to be a function of N_REG_ARGS
> (not the other way around). N_REG_ARGS is fixed based off the SMC
> instruction and shouldn't be computed from the SCM abstraction.
> - Move SMCCC_FUNCNUM closer to other smccc-specific macros.
> - Add LEGACY_FUNCNUM macro to qcom_scm-32.c

My preference is one change per patch :) That also makes it easier to
review!

> +#define LEGACY_FUNCNUM(s, c) (((s) << 10) | ((c) & 0x3ff))
> +
> /**
> - * struct qcom_scm_command - one SCM command buffer
> + * struct legacy_command - one SCM command buffer

can we keep the qcom_ tag in this?

> /**
> - * struct qcom_scm_response - one SCM response buffer
> + * struct legacy_response - one SCM response buffer
> * @len: total available memory for response
> - * @buf_offset: start of response data relative to start of qcom_scm_response
> + * @buf_offset: start of response data relative to start of legacy_response
> * @is_complete: indicates if the command has finished processing
> */
> -struct qcom_scm_response {
> +struct legacy_response {

here as well

> diff --git a/drivers/firmware/qcom_scm.c b/drivers/firmware/qcom_scm.c
> index a729e05..40222b1 100644
> --- a/drivers/firmware/qcom_scm.c
> +++ b/drivers/firmware/qcom_scm.c
> @@ -1,8 +1,6 @@
> // SPDX-License-Identifier: GPL-2.0-only
> /*
> - * Qualcomm SCM driver
> - *
> - * Copyright (c) 2010,2015, The Linux Foundation. All rights reserved.
> + * Copyright (c) 2010,2015,2019 The Linux Foundation. All rights reserved.
> * Copyright (C) 2015 Linaro Ltd.

I don't feel this belongs to this patch, please move it to patch
touching this file

--
~Vinod

2019-11-07 16:43:45

by Vinod Koul

[permalink] [raw]
Subject: Re: [PATCH 02/17] firmware: qcom_scm: Apply consistent naming scheme to command IDs

On 04-11-19, 17:27, Elliot Berman wrote:
> Create a consistent naming scheme for command IDs. The scheme is
> QCOM_SCM_##svc_##cmd. Remove unused macros QCOM_SCM_FLAG_HLOS,
> QCOM_SCM_FLAG_COLDBOOT_MC, QCOM_SCM_FLAG_WARMBOOT_MC,
> QCOM_SCM_CMD_CORE_HOTPLUGGED, and QCOM_SCM_BOOT_ADDR_MC.

Reviewed-by: Vinod Koul <[email protected]>

--
~Vinod

2019-11-07 16:52:42

by Vinod Koul

[permalink] [raw]
Subject: Re: [PATCH 03/17] firmware: qcom_scm: Order functions, definitions by service/command

On 04-11-19, 17:27, Elliot Berman wrote:
> Definitions throughout qcom_scm are loosely grouped and loosely ordered.
> Sort all the functions/definitions by service ID/command ID to improve
> sanity when needing to add new functionality to this driver.

Reviewed-by: Vinod Koul <[email protected]>

--
~Vinod

2019-11-07 19:23:18

by Bjorn Andersson

[permalink] [raw]
Subject: Re: [PATCH 09/17] firmware: qcom_scm-64: Improve SMC convention detection

On Mon 04 Nov 17:27 PST 2019, Elliot Berman wrote:

> - Use enum to describe SMC convention.
> - Improve SMC convention detection to use __qcom_scm_is_call_available
> instead of circumventing qcom_scm_call_smccc.
> - Improve SMC convention detection to check that SMCCC-32 works, instead
> of just assuming it does of SMCCC-64 does not.

I was about to tell you that your list represent individual changes, but
I think you should rewrite the commit message instead. Something like:

"""
Improve the calling convention detection to use
__qcom_scm_is_call_available() and not blindly assume 32-bit mode if
the checks fails.
"""

>
> Signed-off-by: Elliot Berman <[email protected]>
> ---
> drivers/firmware/qcom_scm-64.c | 42 ++++++++++++++++++++++++------------------
> 1 file changed, 24 insertions(+), 18 deletions(-)
>
> diff --git a/drivers/firmware/qcom_scm-64.c b/drivers/firmware/qcom_scm-64.c
> index f79b0dc..2579246 100644
> --- a/drivers/firmware/qcom_scm-64.c
> +++ b/drivers/firmware/qcom_scm-64.c
> @@ -58,7 +58,13 @@ struct arm_smccc_args {
> unsigned long a[8];
> };
>
> -static u64 qcom_smccc_convention = -1;
> +enum qcom_smc_convention {
> + SMC_CONVENTION_UNKNOWN,
> + SMC_CONVENTION_ARM_32,
> + SMC_CONVENTION_ARM_64,
> +};
> +
> +static enum qcom_smc_convention qcom_smc_convention = SMC_CONVENTION_UNKNOWN;
> static DEFINE_MUTEX(qcom_scm_lock);
>
> #define QCOM_SCM_EBUSY_WAIT_MS 30
> @@ -103,7 +109,9 @@ static int ___qcom_scm_call_smccc(struct device *dev,
>
> smc.a[0] = ARM_SMCCC_CALL_VAL(
> atomic ? ARM_SMCCC_FAST_CALL : ARM_SMCCC_STD_CALL,
> - qcom_smccc_convention,

Use a local variable instead of using a ternary operator in the middle
of the arguments.

> + (qcom_smc_convention == SMC_CONVENTION_ARM_64) ?
> + ARM_SMCCC_SMC_64 :
> + ARM_SMCCC_SMC_32,

Here SMC_CONVENTION_UNKNOWN would mean ARM_SMCCC_SMC_32...

> desc->owner,
> SMCCC_FUNCNUM(desc->svc, desc->cmd));
> smc.a[1] = desc->arginfo;
> @@ -117,7 +125,7 @@ static int ___qcom_scm_call_smccc(struct device *dev,
> if (!args_virt)
> return -ENOMEM;
>
> - if (qcom_smccc_convention == ARM_SMCCC_SMC_32) {
> + if (qcom_smc_convention == SMC_CONVENTION_ARM_32) {

...but here it would mean ARM_SMCCC_SMC_64.

> __le32 *args = args_virt;
>
> for (i = 0; i < SMCCC_N_EXT_ARGS; i++)
> @@ -583,19 +591,17 @@ int __qcom_scm_qsmmu500_wait_safe_toggle(struct device *dev, bool en)
>
> void __qcom_scm_init(void)
> {
> - u64 cmd;
> - struct arm_smccc_res res;
> - u32 function = SMCCC_FUNCNUM(QCOM_SCM_SVC_INFO, QCOM_SCM_INFO_IS_CALL_AVAIL);
> -
> - /* First try a SMC64 call */
> - cmd = ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, ARM_SMCCC_SMC_64,
> - ARM_SMCCC_OWNER_SIP, function);
> -
> - arm_smccc_smc(cmd, QCOM_SCM_ARGS(1), cmd & (~BIT(ARM_SMCCC_TYPE_SHIFT)),
> - 0, 0, 0, 0, 0, &res);
> -
> - if (!res.a0 && res.a1)
> - qcom_smccc_convention = ARM_SMCCC_SMC_64;
> - else
> - qcom_smccc_convention = ARM_SMCCC_SMC_32;
> + qcom_smc_convention = SMC_CONVENTION_ARM_64;
> + if (__qcom_scm_is_call_available(NULL, QCOM_SCM_SVC_INFO,
> + QCOM_SCM_INFO_IS_CALL_AVAIL) == 1)
> + goto out;
> +
> + qcom_smc_convention = SMC_CONVENTION_ARM_32;
> + if (__qcom_scm_is_call_available(NULL, QCOM_SCM_SVC_INFO,
> + QCOM_SCM_INFO_IS_CALL_AVAIL) == 1)
> + goto out;
> +
> + qcom_smc_convention = SMC_CONVENTION_UNKNOWN;

If above two tests can be considered reliable I would suggest that you
fail hard here instead.

And if so I think you should postpone the introduction of the enum until
you actually need it to represent the legacy mode.

Regards,
Bjorn

> +out:
> + pr_debug("QCOM SCM SMC Convention: %d\n", qcom_smc_convention);
> }
> --
> The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
> a Linux Foundation Collaborative Project
>

2019-11-07 20:22:14

by Elliot Berman

[permalink] [raw]
Subject: Re: [PATCH 09/17] firmware: qcom_scm-64: Improve SMC convention detection

On 2019-11-07 11:18, Bjorn Andersson wrote:
>> + (qcom_smc_convention == SMC_CONVENTION_ARM_64) ?
>> + ARM_SMCCC_SMC_64 :
>> + ARM_SMCCC_SMC_32,
>
> Here SMC_CONVENTION_UNKNOWN would mean ARM_SMCCC_SMC_32...

Idea is that __qcom_scm_call_smccc would only be called if
qcom_smc_convention
is SMC_CONVENTION_ARM_64 or _32. It should not be possible to get into
__qcom_scm_call_smccc with the current convention being
SMC_CONVENTION_UNKNOWN.

>
>> desc->owner,
>> SMCCC_FUNCNUM(desc->svc, desc->cmd));
>> smc.a[1] = desc->arginfo;
>> @@ -117,7 +125,7 @@ static int ___qcom_scm_call_smccc(struct device
>> *dev,
>> if (!args_virt)
>> return -ENOMEM;
>>
>> - if (qcom_smccc_convention == ARM_SMCCC_SMC_32) {
>> + if (qcom_smc_convention == SMC_CONVENTION_ARM_32) {
>
> ...but here it would mean ARM_SMCCC_SMC_64.

I will clean up to be consistent what the "else" case is.


>> @@ -583,19 +591,17 @@ int __qcom_scm_qsmmu500_wait_safe_toggle(struct
>> device *dev, bool en)
>>
>> void __qcom_scm_init(void)
>> {
>> - u64 cmd;
>> - struct arm_smccc_res res;
>> - u32 function = SMCCC_FUNCNUM(QCOM_SCM_SVC_INFO,
>> QCOM_SCM_INFO_IS_CALL_AVAIL);
>> -
>> - /* First try a SMC64 call */
>> - cmd = ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, ARM_SMCCC_SMC_64,
>> - ARM_SMCCC_OWNER_SIP, function);
>> -
>> - arm_smccc_smc(cmd, QCOM_SCM_ARGS(1), cmd &
>> (~BIT(ARM_SMCCC_TYPE_SHIFT)),
>> - 0, 0, 0, 0, 0, &res);
>> -
>> - if (!res.a0 && res.a1)
>> - qcom_smccc_convention = ARM_SMCCC_SMC_64;
>> - else
>> - qcom_smccc_convention = ARM_SMCCC_SMC_32;
>> + qcom_smc_convention = SMC_CONVENTION_ARM_64;
>> + if (__qcom_scm_is_call_available(NULL, QCOM_SCM_SVC_INFO,
>> + QCOM_SCM_INFO_IS_CALL_AVAIL) == 1)
>> + goto out;
>> +
>> + qcom_smc_convention = SMC_CONVENTION_ARM_32;
>> + if (__qcom_scm_is_call_available(NULL, QCOM_SCM_SVC_INFO,
>> + QCOM_SCM_INFO_IS_CALL_AVAIL) == 1)
>> + goto out;
>> +
>> + qcom_smc_convention = SMC_CONVENTION_UNKNOWN;
>
> If above two tests can be considered reliable I would suggest that you
> fail hard here instead.

Is the suggestion here to BUG out?

Thanks,

Elliot


--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora
Forum,
a Linux Foundation Collaborative Project

2019-11-07 23:45:52

by Bjorn Andersson

[permalink] [raw]
Subject: Re: [PATCH 09/17] firmware: qcom_scm-64: Improve SMC convention detection

On Thu 07 Nov 12:20 PST 2019, [email protected] wrote:
> On 2019-11-07 11:18, Bjorn Andersson wrote:
[..]
> > > @@ -583,19 +591,17 @@ int
> > > __qcom_scm_qsmmu500_wait_safe_toggle(struct device *dev, bool en)
> > >
> > > void __qcom_scm_init(void)
> > > {
> > > - u64 cmd;
> > > - struct arm_smccc_res res;
> > > - u32 function = SMCCC_FUNCNUM(QCOM_SCM_SVC_INFO,
> > > QCOM_SCM_INFO_IS_CALL_AVAIL);
> > > -
> > > - /* First try a SMC64 call */
> > > - cmd = ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, ARM_SMCCC_SMC_64,
> > > - ARM_SMCCC_OWNER_SIP, function);
> > > -
> > > - arm_smccc_smc(cmd, QCOM_SCM_ARGS(1), cmd &
> > > (~BIT(ARM_SMCCC_TYPE_SHIFT)),
> > > - 0, 0, 0, 0, 0, &res);
> > > -
> > > - if (!res.a0 && res.a1)
> > > - qcom_smccc_convention = ARM_SMCCC_SMC_64;
> > > - else
> > > - qcom_smccc_convention = ARM_SMCCC_SMC_32;
> > > + qcom_smc_convention = SMC_CONVENTION_ARM_64;
> > > + if (__qcom_scm_is_call_available(NULL, QCOM_SCM_SVC_INFO,
> > > + QCOM_SCM_INFO_IS_CALL_AVAIL) == 1)
> > > + goto out;
> > > +
> > > + qcom_smc_convention = SMC_CONVENTION_ARM_32;
> > > + if (__qcom_scm_is_call_available(NULL, QCOM_SCM_SVC_INFO,
> > > + QCOM_SCM_INFO_IS_CALL_AVAIL) == 1)
> > > + goto out;
> > > +
> > > + qcom_smc_convention = SMC_CONVENTION_UNKNOWN;
> >
> > If above two tests can be considered reliable I would suggest that you
> > fail hard here instead.
>
> Is the suggestion here to BUG out?
>

We generally do not want that, but leaving it "unknown" feels like the
next scm call will have similar outcome to calling BUG() here, but be
harder to debug...

So I would be willing to accept a BUG() here.

Regards,
Bjorn

2019-11-08 00:08:29

by Bjorn Andersson

[permalink] [raw]
Subject: Re: [PATCH 10/17] firmware: qcom_scm-32: Use SMC arch wrappers

On Mon 04 Nov 17:27 PST 2019, Elliot Berman wrote:

> Use SMC arch wrappers instead of inline assembly.
>

I presume this is the point in the series where you can drop the
CFLAGS_qcom_scm-32.o from the Makefile? Please include that in this
patch.

Regards,
Bjorn

> Signed-off-by: Elliot Berman <[email protected]>
> ---
> drivers/firmware/qcom_scm-32.c | 71 ++++++++++--------------------------------
> 1 file changed, 17 insertions(+), 54 deletions(-)
>
> diff --git a/drivers/firmware/qcom_scm-32.c b/drivers/firmware/qcom_scm-32.c
> index b7f9f28..e3dc9a7 100644
> --- a/drivers/firmware/qcom_scm-32.c
> +++ b/drivers/firmware/qcom_scm-32.c
> @@ -10,6 +10,7 @@
> #include <linux/errno.h>
> #include <linux/err.h>
> #include <linux/qcom_scm.h>
> +#include <linux/arm-smccc.h>
> #include <linux/dma-mapping.h>
>
> #include "qcom_scm.h"
> @@ -121,25 +122,13 @@ static inline void *legacy_get_response_buffer(const struct legacy_response *rsp
> static u32 __qcom_scm_call_do(u32 cmd_addr)
> {
> int context_id;
> - register u32 r0 asm("r0") = 1;
> - register u32 r1 asm("r1") = (u32)&context_id;
> - register u32 r2 asm("r2") = cmd_addr;
> + struct arm_smccc_res res;
> do {
> - asm volatile(
> - __asmeq("%0", "r0")
> - __asmeq("%1", "r0")
> - __asmeq("%2", "r1")
> - __asmeq("%3", "r2")
> -#ifdef REQUIRES_SEC
> - ".arch_extension sec\n"
> -#endif
> - "smc #0 @ switch to secure world\n"
> - : "=r" (r0)
> - : "r" (r0), "r" (r1), "r" (r2)
> - : "r3", "r12");
> - } while (r0 == QCOM_SCM_INTERRUPTED);
> -
> - return r0;
> + arm_smccc_smc(1, (unsigned long)&context_id, cmd_addr,
> + 0, 0, 0, 0, 0, &res);
> + } while (res.a0 == QCOM_SCM_INTERRUPTED);
> +
> + return res.a0;
> }
>
> /**
> @@ -236,24 +225,12 @@ static int qcom_scm_call(struct device *dev, u32 svc_id, u32 cmd_id,
> static s32 qcom_scm_call_atomic1(u32 svc, u32 cmd, u32 arg1)
> {
> int context_id;
> + struct arm_smccc_res res;
> +
> + arm_smccc_smc(LEGACY_ATOMIC(svc, cmd, 1), (unsigned long)&context_id,
> + arg1, 0, 0, 0, 0, 0, &res);
>
> - register u32 r0 asm("r0") = LEGACY_ATOMIC(svc, cmd, 1);
> - register u32 r1 asm("r1") = (u32)&context_id;
> - register u32 r2 asm("r2") = arg1;
> -
> - asm volatile(
> - __asmeq("%0", "r0")
> - __asmeq("%1", "r0")
> - __asmeq("%2", "r1")
> - __asmeq("%3", "r2")
> -#ifdef REQUIRES_SEC
> - ".arch_extension sec\n"
> -#endif
> - "smc #0 @ switch to secure world\n"
> - : "=r" (r0)
> - : "r" (r0), "r" (r1), "r" (r2)
> - : "r3", "r12");
> - return r0;
> + return res.a0;
> }
>
> /**
> @@ -269,26 +246,12 @@ static s32 qcom_scm_call_atomic1(u32 svc, u32 cmd, u32 arg1)
> static s32 qcom_scm_call_atomic2(u32 svc, u32 cmd, u32 arg1, u32 arg2)
> {
> int context_id;
> + struct arm_smccc_res res;
> +
> + arm_smccc_smc(LEGACY_ATOMIC(svc, cmd, 2), (unsigned long)&context_id,
> + arg1, arg2, 0, 0, 0, 0, &res);
>
> - register u32 r0 asm("r0") = LEGACY_ATOMIC(svc, cmd, 2);
> - register u32 r1 asm("r1") = (u32)&context_id;
> - register u32 r2 asm("r2") = arg1;
> - register u32 r3 asm("r3") = arg2;
> -
> - asm volatile(
> - __asmeq("%0", "r0")
> - __asmeq("%1", "r0")
> - __asmeq("%2", "r1")
> - __asmeq("%3", "r2")
> - __asmeq("%4", "r3")
> -#ifdef REQUIRES_SEC
> - ".arch_extension sec\n"
> -#endif
> - "smc #0 @ switch to secure world\n"
> - : "=r" (r0)
> - : "r" (r0), "r" (r1), "r" (r2), "r" (r3)
> - : "r12");
> - return r0;
> + return res.a0;
> }
>
> /**
> --
> The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
> a Linux Foundation Collaborative Project
>

2019-11-08 00:22:07

by Bjorn Andersson

[permalink] [raw]
Subject: Re: [PATCH 17/17] firmware: qcom_scm: Rename -64 -> -smc, remove -32

On Mon 04 Nov 17:27 PST 2019, Elliot Berman wrote:

> - Rename qcom_scm-64.c to qcom_scm-smc as it supports SMC-based calling conventions
> for 32 and 64-bit targets
> - Remove qcom_scm-32.c as it has been superceded by qcom_scm-smc.c
> - Update Kconfig to select QCOM_SCM_TRANSPORT_SMC on ARM and ARM64
> targets
>

I really like the end result of this series, it's much cleaner than the
previous 32 vs 64 split, need for wrappers and risk of introducing build
errors when adding new functions.

I do think we you can improve this even more by inlining the __functions
from qcom_scm-smc.c into qcom_scm.c directly and provide the bottom
parts in separate files; qcom_scm-legacy.c and qcom_scm-smccc.c


Right now it doesn't look bad, but if qcom_scm.c grows too big I think
we can, as discussed, split it up in per-service implementation (still
link it all together as one module).

> Signed-off-by: Elliot Berman <[email protected]>
> ---
> drivers/firmware/Kconfig | 18 +-
> drivers/firmware/Makefile | 4 +-
> drivers/firmware/qcom_scm-32.c | 660 ----------------------------
> drivers/firmware/qcom_scm-64.c | 949 ----------------------------------------
> drivers/firmware/qcom_scm-smc.c | 949 ++++++++++++++++++++++++++++++++++++++++

Pass -M to format-patch and it will describe renames.

> 5 files changed, 961 insertions(+), 1619 deletions(-)
> delete mode 100644 drivers/firmware/qcom_scm-32.c
> delete mode 100644 drivers/firmware/qcom_scm-64.c
> create mode 100644 drivers/firmware/qcom_scm-smc.c
>
> diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig
> index e40a77b..ad477ca 100644
> --- a/drivers/firmware/Kconfig
> +++ b/drivers/firmware/Kconfig
> @@ -236,16 +236,20 @@ config INTEL_STRATIX10_RSU
>
> config QCOM_SCM
> bool
> - depends on ARM || ARM64
> + depends on QCOM_SCM_TRANSPORT_SMC
> select RESET_CONTROLLER
> + help
> + This option enables support for communicating with
> + Qualcomm secure worlds.
>
> -config QCOM_SCM_32
> - def_bool y
> - depends on QCOM_SCM && ARM
> -
> -config QCOM_SCM_64
> +config QCOM_SCM_TRANSPORT_SMC

No need for a separate option, rely on QCOM_SCM and build everything
into one module.

Regards,
Bjorn

> def_bool y
> - depends on QCOM_SCM && ARM64
> + depends on ARM || ARM64
> + help
> + This option enables support for communicating with
> + Qualcomm secure worlds via the SMC instruction, using
> + either ARM SMCCC or legacy calling convention by querying
> + the Qualcomm secure world.
>
> config QCOM_SCM_DOWNLOAD_MODE_DEFAULT
> bool "Qualcomm download mode enabled by default"
> diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile
> index 3fcb919..fc250f0 100644
> --- a/drivers/firmware/Makefile
> +++ b/drivers/firmware/Makefile
> @@ -18,9 +18,7 @@ obj-$(CONFIG_FIRMWARE_MEMMAP) += memmap.o
> obj-$(CONFIG_RASPBERRYPI_FIRMWARE) += raspberrypi.o
> obj-$(CONFIG_FW_CFG_SYSFS) += qemu_fw_cfg.o
> obj-$(CONFIG_QCOM_SCM) += qcom_scm.o
> -obj-$(CONFIG_QCOM_SCM_64) += qcom_scm-64.o
> -obj-$(CONFIG_QCOM_SCM_32) += qcom_scm-32.o
> -CFLAGS_qcom_scm-32.o :=$(call as-instr,.arch armv7-a\n.arch_extension sec,-DREQUIRES_SEC=1) -march=armv7-a
> +obj-$(CONFIG_QCOM_SCM_TRANSPORT_SMC) += qcom_scm-smc.o
> obj-$(CONFIG_TI_SCI_PROTOCOL) += ti_sci.o
> obj-$(CONFIG_TRUSTED_FOUNDATIONS) += trusted_foundations.o
> obj-$(CONFIG_TURRIS_MOX_RWTM) += turris-mox-rwtm.o
> diff --git a/drivers/firmware/qcom_scm-32.c b/drivers/firmware/qcom_scm-32.c
> deleted file mode 100644
> index 3325c21..0000000
> --- a/drivers/firmware/qcom_scm-32.c
> +++ /dev/null
> @@ -1,660 +0,0 @@
> -// SPDX-License-Identifier: GPL-2.0-only
> -/* Copyright (c) 2010,2015,2019 The Linux Foundation. All rights reserved.
> - * Copyright (C) 2015 Linaro Ltd.
> - */
> -
> -#include <linux/slab.h>
> -#include <linux/io.h>
> -#include <linux/module.h>
> -#include <linux/mutex.h>
> -#include <linux/errno.h>
> -#include <linux/err.h>
> -#include <linux/qcom_scm.h>
> -#include <linux/arm-smccc.h>
> -#include <linux/dma-mapping.h>
> -
> -#include "qcom_scm.h"
> -
> -#define QCOM_SCM_FLAG_COLDBOOT_CPU0 0x00
> -#define QCOM_SCM_FLAG_COLDBOOT_CPU1 0x01
> -#define QCOM_SCM_FLAG_COLDBOOT_CPU2 0x08
> -#define QCOM_SCM_FLAG_COLDBOOT_CPU3 0x20
> -
> -#define QCOM_SCM_FLAG_WARMBOOT_CPU0 0x04
> -#define QCOM_SCM_FLAG_WARMBOOT_CPU1 0x02
> -#define QCOM_SCM_FLAG_WARMBOOT_CPU2 0x10
> -#define QCOM_SCM_FLAG_WARMBOOT_CPU3 0x40
> -
> -struct qcom_scm_entry {
> - int flag;
> - void *entry;
> -};
> -
> -static struct qcom_scm_entry qcom_scm_wb[] = {
> - { .flag = QCOM_SCM_FLAG_WARMBOOT_CPU0 },
> - { .flag = QCOM_SCM_FLAG_WARMBOOT_CPU1 },
> - { .flag = QCOM_SCM_FLAG_WARMBOOT_CPU2 },
> - { .flag = QCOM_SCM_FLAG_WARMBOOT_CPU3 },
> -};
> -
> -static DEFINE_MUTEX(qcom_scm_lock);
> -
> -#define MAX_QCOM_SCM_ARGS 10
> -#define MAX_QCOM_SCM_RETS 3
> -
> -enum qcom_scm_arg_types {
> - QCOM_SCM_VAL,
> - QCOM_SCM_RO,
> - QCOM_SCM_RW,
> - QCOM_SCM_BUFVAL,
> -};
> -
> -#define QCOM_SCM_ARGS_IMPL(num, a, b, c, d, e, f, g, h, i, j, ...) (\
> - (((a) & 0x3) << 4) | \
> - (((b) & 0x3) << 6) | \
> - (((c) & 0x3) << 8) | \
> - (((d) & 0x3) << 10) | \
> - (((e) & 0x3) << 12) | \
> - (((f) & 0x3) << 14) | \
> - (((g) & 0x3) << 16) | \
> - (((h) & 0x3) << 18) | \
> - (((i) & 0x3) << 20) | \
> - (((j) & 0x3) << 22) | \
> - ((num) & 0xf))
> -
> -#define QCOM_SCM_ARGS(...) QCOM_SCM_ARGS_IMPL(__VA_ARGS__, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
> -
> -/**
> - * struct qcom_scm_desc
> - * @arginfo: Metadata describing the arguments in args[]
> - * @args: The array of arguments for the secure syscall
> - * @res: The values returned by the secure syscall
> - */
> -struct qcom_scm_desc {
> - u32 svc;
> - u32 cmd;
> - u32 arginfo;
> - u64 args[MAX_QCOM_SCM_ARGS];
> - u64 res[MAX_QCOM_SCM_RETS];
> - u32 owner;
> -};
> -struct arm_smccc_args {
> - unsigned long a[8];
> -};
> -
> -#define LEGACY_FUNCNUM(s, c) (((s) << 10) | ((c) & 0x3ff))
> -
> -/**
> - * struct legacy_command - one SCM command buffer
> - * @len: total available memory for command and response
> - * @buf_offset: start of command buffer
> - * @resp_hdr_offset: start of response buffer
> - * @id: command to be executed
> - * @buf: buffer returned from legacy_get_command_buffer()
> - *
> - * An SCM command is laid out in memory as follows:
> - *
> - * ------------------- <--- struct legacy_command
> - * | command header |
> - * ------------------- <--- legacy_get_command_buffer()
> - * | command buffer |
> - * ------------------- <--- struct legacy_response and
> - * | response header | legacy_command_to_response()
> - * ------------------- <--- legacy_get_response_buffer()
> - * | response buffer |
> - * -------------------
> - *
> - * There can be arbitrary padding between the headers and buffers so
> - * you should always use the appropriate qcom_scm_get_*_buffer() routines
> - * to access the buffers in a safe manner.
> - */
> -struct legacy_command {
> - __le32 len;
> - __le32 buf_offset;
> - __le32 resp_hdr_offset;
> - __le32 id;
> - __le32 buf[0];
> -};
> -
> -/**
> - * struct legacy_response - one SCM response buffer
> - * @len: total available memory for response
> - * @buf_offset: start of response data relative to start of legacy_response
> - * @is_complete: indicates if the command has finished processing
> - */
> -struct legacy_response {
> - __le32 len;
> - __le32 buf_offset;
> - __le32 is_complete;
> -};
> -
> -/**
> - * legacy_command_to_response() - Get a pointer to a legacy_response
> - * @cmd: command
> - *
> - * Returns a pointer to a response for a command.
> - */
> -static inline struct legacy_response *legacy_command_to_response(
> - const struct legacy_command *cmd)
> -{
> - return (void *)cmd + le32_to_cpu(cmd->resp_hdr_offset);
> -}
> -
> -/**
> - * legacy_get_command_buffer() - Get a pointer to a command buffer
> - * @cmd: command
> - *
> - * Returns a pointer to the command buffer of a command.
> - */
> -static inline void *legacy_get_command_buffer(const struct legacy_command *cmd)
> -{
> - return (void *)cmd->buf;
> -}
> -
> -/**
> - * legacy_get_response_buffer() - Get a pointer to a response buffer
> - * @rsp: response
> - *
> - * Returns a pointer to a response buffer of a response.
> - */
> -static inline void *legacy_get_response_buffer(const struct legacy_response *rsp)
> -{
> - return (void *)rsp + le32_to_cpu(rsp->buf_offset);
> -}
> -
> -static void __qcom_scm_call_do(const struct arm_smccc_args *smc,
> - struct arm_smccc_res *res)
> -{
> - do {
> - arm_smccc_smc(smc->a[0], smc->a[1], smc->a[2], smc->a[3],
> - smc->a[4], smc->a[5], smc->a[6], smc->a[7], res);
> - } while (res->a0 == QCOM_SCM_INTERRUPTED);
> -}
> -
> -/**
> - * qcom_scm_call() - Send an SCM command
> - * @dev: struct device
> - * @svc_id: service identifier
> - * @cmd_id: command identifier
> - * @cmd_buf: command buffer
> - * @cmd_len: length of the command buffer
> - * @resp_buf: response buffer
> - * @resp_len: length of the response buffer
> - *
> - * Sends a command to the SCM and waits for the command to finish processing.
> - *
> - * A note on cache maintenance:
> - * Note that any buffers that are expected to be accessed by the secure world
> - * must be flushed before invoking qcom_scm_call and invalidated in the cache
> - * immediately after qcom_scm_call returns. Cache maintenance on the command
> - * 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.
> - */
> -static int qcom_scm_call(struct device *dev, struct qcom_scm_desc *desc)
> -{
> - int arglen = desc->arginfo & 0xf;
> - int ret = 0, context_id;
> - size_t i;
> - struct legacy_command *cmd;
> - struct legacy_response *rsp;
> - struct arm_smccc_args smc = {0};
> - struct arm_smccc_res res;
> - const size_t cmd_len = arglen * sizeof(__le32);
> - const size_t resp_len = MAX_QCOM_SCM_RETS * sizeof(__le32);
> - size_t alloc_len = sizeof(*cmd) + cmd_len + sizeof(*rsp) + resp_len;
> - dma_addr_t cmd_phys;
> - __le32 *arg_buf;
> - __le32 *res_buf;
> -
> - cmd = kzalloc(PAGE_ALIGN(alloc_len), GFP_KERNEL);
> - if (!cmd)
> - return -ENOMEM;
> -
> - cmd->len = cpu_to_le32(alloc_len);
> - cmd->buf_offset = cpu_to_le32(sizeof(*cmd));
> - cmd->resp_hdr_offset = cpu_to_le32(sizeof(*cmd) + cmd_len);
> - cmd->id = cpu_to_le32(LEGACY_FUNCNUM(desc->svc, desc->cmd));
> -
> - arg_buf = legacy_get_command_buffer(cmd);
> - for (i = 0; i < arglen; i++)
> - arg_buf[i] = cpu_to_le32(desc->args[i]);
> -
> - rsp = legacy_command_to_response(cmd);
> -
> - cmd_phys = dma_map_single(dev, cmd, alloc_len, DMA_TO_DEVICE);
> - if (dma_mapping_error(dev, cmd_phys)) {
> - kfree(cmd);
> - return -ENOMEM;
> - }
> -
> - smc.a[0] = 1;
> - smc.a[1] = (unsigned long)&context_id;
> - smc.a[2] = cmd_phys;
> -
> - mutex_lock(&qcom_scm_lock);
> - __qcom_scm_call_do(&smc, &res);
> - if (res.a0 < 0)
> - ret = qcom_scm_remap_error(res.a0);
> - mutex_unlock(&qcom_scm_lock);
> - if (ret)
> - goto out;
> -
> - do {
> - dma_sync_single_for_cpu(dev, cmd_phys + sizeof(*cmd) + cmd_len,
> - sizeof(*rsp), DMA_FROM_DEVICE);
> - } while (!rsp->is_complete);
> -
> - dma_sync_single_for_cpu(dev, cmd_phys + sizeof(*cmd) + cmd_len +
> - le32_to_cpu(rsp->buf_offset),
> - resp_len, DMA_FROM_DEVICE);
> -
> - res_buf = legacy_get_response_buffer(rsp);
> - for (i = 0; i < MAX_QCOM_SCM_RETS; i++)
> - desc->res[i] = le32_to_cpu(res_buf[i]);
> -out:
> - dma_unmap_single(dev, cmd_phys, alloc_len, DMA_TO_DEVICE);
> - kfree(cmd);
> - return ret;
> -}
> -
> -#define LEGACY_ATOMIC_N_REG_ARGS 5
> -#define LEGACY_ATOMIC_FIRST_REG_IDX 2
> -#define LEGACY_CLASS_REGISTER (0x2 << 8)
> -#define LEGACY_MASK_IRQS BIT(5)
> -#define LEGACY_ATOMIC(svc, cmd, n) ((LEGACY_FUNCNUM(svc, cmd) << 12) | \
> - LEGACY_CLASS_REGISTER | \
> - LEGACY_MASK_IRQS | \
> - (n & 0xf))
> -
> -/**
> - * qcom_scm_call_atomic() - Send an atomic SCM command with up to 5 arguments
> - * and 3 return values
> - *
> - * This shall only be used with commands that are guaranteed to be
> - * uninterruptable, atomic and SMP safe.
> - */
> -static int qcom_scm_call_atomic(struct device *dev, struct qcom_scm_desc *desc)
> -{
> - int context_id;
> - struct arm_smccc_args smc = {0};
> - struct arm_smccc_res res;
> - size_t i, arglen = desc->arginfo & 0xf;
> -
> - BUG_ON(arglen > LEGACY_ATOMIC_N_REG_ARGS);
> -
> - smc.a[0] = LEGACY_ATOMIC(desc->svc, desc->cmd, arglen);
> - smc.a[1] = (unsigned long)&context_id;
> -
> - for (i = 0; i < arglen; i++)
> - smc.a[i + LEGACY_ATOMIC_FIRST_REG_IDX] = desc->args[i];
> -
> - arm_smccc_smc(smc.a[0], smc.a[1], smc.a[2], smc.a[3],
> - smc.a[4], smc.a[5], smc.a[6], smc.a[7], &res);
> -
> - desc->res[0] = res.a1;
> - desc->res[1] = res.a2;
> - desc->res[2] = res.a3;
> -
> - return res.a0;
> -}
> -
> -/**
> - * qcom_scm_set_cold_boot_addr() - Set the cold boot address for cpus
> - * @entry: Entry point function for the cpus
> - * @cpus: The cpumask of cpus that will use the entry point
> - *
> - * Set the cold boot address of the cpus. Any cpu outside the supported
> - * range would be removed from the cpu present mask.
> - */
> -int __qcom_scm_set_cold_boot_addr(struct device *dev, void *entry,
> - const cpumask_t *cpus)
> -{
> - int flags = 0;
> - int cpu;
> - int scm_cb_flags[] = {
> - QCOM_SCM_FLAG_COLDBOOT_CPU0,
> - QCOM_SCM_FLAG_COLDBOOT_CPU1,
> - QCOM_SCM_FLAG_COLDBOOT_CPU2,
> - QCOM_SCM_FLAG_COLDBOOT_CPU3,
> - };
> - struct qcom_scm_desc desc = {
> - .svc = QCOM_SCM_SVC_BOOT,
> - .cmd = QCOM_SCM_BOOT_SET_ADDR,
> - .owner = ARM_SMCCC_OWNER_SIP,
> - };
> -
> - if (!cpus || (cpus && cpumask_empty(cpus)))
> - return -EINVAL;
> -
> - for_each_cpu(cpu, cpus) {
> - if (cpu < ARRAY_SIZE(scm_cb_flags))
> - flags |= scm_cb_flags[cpu];
> - else
> - set_cpu_present(cpu, false);
> - }
> -
> - desc.args[0] = flags;
> - desc.args[1] = virt_to_phys(entry);
> - desc.arginfo = QCOM_SCM_ARGS(2);
> -
> - return qcom_scm_call_atomic(dev, &desc);
> -}
> -
> -/**
> - * qcom_scm_set_warm_boot_addr() - Set the warm boot address for cpus
> - * @entry: Entry point function for the cpus
> - * @cpus: The cpumask of cpus that will use the entry point
> - *
> - * Set the Linux entry point for the SCM to transfer control to when coming
> - * out of a power down. CPU power down may be executed on cpuidle or hotplug.
> - */
> -int __qcom_scm_set_warm_boot_addr(struct device *dev, void *entry,
> - const cpumask_t *cpus)
> -{
> - int ret;
> - int flags = 0;
> - int cpu;
> - struct qcom_scm_desc desc = {
> - .svc = QCOM_SCM_SVC_BOOT,
> - .cmd = QCOM_SCM_BOOT_SET_ADDR,
> - .arginfo = QCOM_SCM_ARGS(2),
> - };
> -
> - /*
> - * Reassign only if we are switching from hotplug entry point
> - * to cpuidle entry point or vice versa.
> - */
> - for_each_cpu(cpu, cpus) {
> - if (entry == qcom_scm_wb[cpu].entry)
> - continue;
> - flags |= qcom_scm_wb[cpu].flag;
> - }
> -
> - /* No change in entry function */
> - if (!flags)
> - return 0;
> -
> - desc.args[0] = flags;
> - desc.args[1] = virt_to_phys(entry);
> - ret = qcom_scm_call(dev, &desc);
> - if (!ret) {
> - for_each_cpu(cpu, cpus)
> - qcom_scm_wb[cpu].entry = entry;
> - }
> -
> - return ret;
> -}
> -
> -/**
> - * qcom_scm_cpu_power_down() - Power down the cpu
> - * @flags - Flags to flush cache
> - *
> - * This is an end point to power down cpu. If there was a pending interrupt,
> - * the control would return from this function, otherwise, the cpu jumps to the
> - * warm boot entry point set for this cpu upon reset.
> - */
> -void __qcom_scm_cpu_power_down(struct device *dev, u32 flags)
> -{
> - struct qcom_scm_desc desc = {
> - .svc = QCOM_SCM_SVC_BOOT,
> - .cmd = QCOM_SCM_BOOT_TERMINATE_PC,
> - .args[0] = flags & QCOM_SCM_FLUSH_FLAG_MASK,
> - .arginfo = QCOM_SCM_ARGS(1),
> - .owner = ARM_SMCCC_OWNER_SIP,
> - };
> -
> - qcom_scm_call_atomic(dev, &desc);
> -}
> -
> -int __qcom_scm_set_remote_state(struct device *dev, u32 state, u32 id)
> -{
> - struct qcom_scm_desc desc = {
> - .svc = QCOM_SCM_SVC_BOOT,
> - .cmd = QCOM_SCM_BOOT_SET_REMOTE_STATE,
> - .owner = ARM_SMCCC_OWNER_SIP,
> - };
> - int ret;
> -
> - desc.args[0] = state;
> - desc.args[1] = id;
> - desc.arginfo = QCOM_SCM_ARGS(2);
> -
> - ret = qcom_scm_call(dev, &desc);
> -
> - return ret ? : desc.res[0];
> -}
> -
> -int __qcom_scm_set_dload_mode(struct device *dev, bool enable)
> -{
> - struct qcom_scm_desc desc = {
> - .svc = QCOM_SCM_SVC_BOOT,
> - .cmd = QCOM_SCM_BOOT_SET_DLOAD_MODE,
> - .owner = ARM_SMCCC_OWNER_SIP,
> - };
> -
> - desc.args[0] = QCOM_SCM_BOOT_SET_DLOAD_MODE;
> - desc.args[1] = enable ? QCOM_SCM_BOOT_SET_DLOAD_MODE : 0;
> - desc.arginfo = QCOM_SCM_ARGS(2);
> -
> - return qcom_scm_call_atomic(dev, &desc);
> -}
> -
> -bool __qcom_scm_pas_supported(struct device *dev, u32 peripheral)
> -{
> - int ret;
> - struct qcom_scm_desc desc = {
> - .svc = QCOM_SCM_SVC_PIL,
> - .cmd = QCOM_SCM_PIL_PAS_IS_SUPPORTED,
> - .owner = ARM_SMCCC_OWNER_SIP,
> - };
> -
> - desc.args[0] = peripheral;
> - desc.arginfo = QCOM_SCM_ARGS(1);
> -
> - ret = qcom_scm_call(dev, &desc);
> -
> - return ret ? false : !!desc.res[0];
> -}
> -
> -int __qcom_scm_pas_init_image(struct device *dev, u32 peripheral,
> - dma_addr_t metadata_phys)
> -{
> - int ret;
> - struct qcom_scm_desc desc = {
> - .svc = QCOM_SCM_SVC_PIL,
> - .cmd = QCOM_SCM_PIL_PAS_INIT_IMAGE,
> - .owner = ARM_SMCCC_OWNER_SIP,
> - };
> -
> - desc.args[0] = peripheral;
> - desc.args[1] = metadata_phys;
> - desc.arginfo = QCOM_SCM_ARGS(2, QCOM_SCM_VAL, QCOM_SCM_RW);
> -
> - ret = qcom_scm_call(dev, &desc);
> -
> - return ret ? : desc.res[0];
> -}
> -
> -int __qcom_scm_pas_mem_setup(struct device *dev, u32 peripheral,
> - phys_addr_t addr, phys_addr_t size)
> -{
> - int ret;
> - struct qcom_scm_desc desc = {
> - .svc = QCOM_SCM_SVC_PIL,
> - .cmd = QCOM_SCM_PIL_PAS_MEM_SETUP,
> - .owner = ARM_SMCCC_OWNER_SIP,
> - };
> -
> - desc.args[0] = peripheral;
> - desc.args[1] = addr;
> - desc.args[2] = size;
> - desc.arginfo = QCOM_SCM_ARGS(3);
> -
> - ret = qcom_scm_call(dev, &desc);
> -
> - return ret ? : desc.res[0];
> -}
> -
> -int __qcom_scm_pas_auth_and_reset(struct device *dev, u32 peripheral)
> -{
> - int ret;
> - struct qcom_scm_desc desc = {
> - .svc = QCOM_SCM_SVC_PIL,
> - .cmd = QCOM_SCM_PIL_PAS_AUTH_AND_RESET,
> - .owner = ARM_SMCCC_OWNER_SIP,
> - };
> -
> - ret = qcom_scm_call(dev, &desc);
> -
> - return ret ? : desc.res[0];
> -}
> -
> -int __qcom_scm_pas_shutdown(struct device *dev, u32 peripheral)
> -{
> - struct qcom_scm_desc desc = {
> - .svc = QCOM_SCM_SVC_PIL,
> - .cmd = QCOM_SCM_PIL_PAS_SHUTDOWN,
> - .owner = ARM_SMCCC_OWNER_SIP,
> - };
> - int ret;
> -
> - desc.args[0] = peripheral;
> - desc.arginfo = QCOM_SCM_ARGS(1);
> -
> - ret = qcom_scm_call(dev, &desc);
> -
> - return ret ? : desc.res[0];
> -}
> -
> -int __qcom_scm_pas_mss_reset(struct device *dev, bool reset)
> -{
> - struct qcom_scm_desc desc = {
> - .svc = QCOM_SCM_SVC_PIL,
> - .cmd = QCOM_SCM_PIL_PAS_MSS_RESET,
> - .owner = ARM_SMCCC_OWNER_SIP,
> - };
> - int ret;
> -
> - desc.args[0] = reset;
> - desc.args[1] = 0;
> - desc.arginfo = QCOM_SCM_ARGS(2);
> -
> - ret = qcom_scm_call(dev, &desc);
> -
> - return ret ? : desc.res[0];
> -}
> -
> -int __qcom_scm_io_readl(struct device *dev, phys_addr_t addr,
> - unsigned int *val)
> -{
> - int ret;
> - struct qcom_scm_desc desc = {
> - .svc = QCOM_SCM_SVC_IO,
> - .cmd = QCOM_SCM_IO_READ,
> - .owner = ARM_SMCCC_OWNER_SIP,
> - };
> -
> - desc.args[0] = addr;
> - desc.arginfo = QCOM_SCM_ARGS(1);
> -
> - ret = qcom_scm_call_atomic(dev, &desc);
> - if (ret >= 0)
> - *val = desc.res[0];
> -
> - return ret < 0 ? ret : 0;
> -}
> -
> -int __qcom_scm_io_writel(struct device *dev, phys_addr_t addr, unsigned int val)
> -{
> - struct qcom_scm_desc desc = {
> - .svc = QCOM_SCM_SVC_IO,
> - .cmd = QCOM_SCM_IO_WRITE,
> - .owner = ARM_SMCCC_OWNER_SIP,
> - };
> -
> - desc.args[0] = addr;
> - desc.args[1] = val;
> - desc.arginfo = QCOM_SCM_ARGS(2);
> -
> - return qcom_scm_call_atomic(dev, &desc);
> -}
> -
> -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] = (svc_id << 10) | cmd_id,
> - .arginfo = QCOM_SCM_ARGS(1),
> - };
> -
> - ret = qcom_scm_call(dev, &desc);
> -
> - return ret ? : desc.res[0];
> -}
> -
> -int __qcom_scm_restore_sec_cfg(struct device *dev, u32 device_id,
> - u32 spare)
> -{
> - return -ENODEV;
> -}
> -
> -int __qcom_scm_iommu_secure_ptbl_size(struct device *dev, u32 spare,
> - size_t *size)
> -{
> - return -ENODEV;
> -}
> -
> -int __qcom_scm_iommu_secure_ptbl_init(struct device *dev, u64 addr, u32 size,
> - u32 spare)
> -{
> - return -ENODEV;
> -}
> -
> -int __qcom_scm_assign_mem(struct device *dev, phys_addr_t mem_region,
> - size_t mem_sz, phys_addr_t src, size_t src_sz,
> - phys_addr_t dest, size_t dest_sz)
> -{
> - return -ENODEV;
> -}
> -
> -int __qcom_scm_hdcp_req(struct device *dev, struct qcom_scm_hdcp_req *req,
> - u32 req_cnt, u32 *resp)
> -{
> - int ret;
> - struct qcom_scm_desc desc = {
> - .svc = QCOM_SCM_SVC_HDCP,
> - .cmd = QCOM_SCM_HDCP_INVOKE,
> - .owner = ARM_SMCCC_OWNER_SIP,
> - };
> -
> - if (req_cnt > QCOM_SCM_HDCP_MAX_REQ_CNT)
> - return -ERANGE;
> -
> - desc.args[0] = req[0].addr;
> - desc.args[1] = req[0].val;
> - desc.args[2] = req[1].addr;
> - desc.args[3] = req[1].val;
> - desc.args[4] = req[2].addr;
> - desc.args[5] = req[2].val;
> - desc.args[6] = req[3].addr;
> - desc.args[7] = req[3].val;
> - desc.args[8] = req[4].addr;
> - desc.args[9] = req[4].val;
> - desc.arginfo = QCOM_SCM_ARGS(req_cnt * 2);
> -
> - ret = qcom_scm_call(dev, &desc);
> - *resp = desc.res[0];
> -
> - return ret;
> -}
> -
> -int __qcom_scm_qsmmu500_wait_safe_toggle(struct device *dev, bool enable)
> -{
> - return -ENODEV;
> -}
> -
> -void __qcom_scm_init(void)
> -{
> -}
> diff --git a/drivers/firmware/qcom_scm-64.c b/drivers/firmware/qcom_scm-64.c
> deleted file mode 100644
> index 355d9d7..0000000
> --- a/drivers/firmware/qcom_scm-64.c
> +++ /dev/null
> @@ -1,949 +0,0 @@
> -// SPDX-License-Identifier: GPL-2.0-only
> -/* Copyright (c) 2015,2019 The Linux Foundation. All rights reserved.
> - */
> -
> -#include <linux/io.h>
> -#include <linux/errno.h>
> -#include <linux/delay.h>
> -#include <linux/mutex.h>
> -#include <linux/slab.h>
> -#include <linux/types.h>
> -#include <linux/qcom_scm.h>
> -#include <linux/arm-smccc.h>
> -#include <linux/dma-mapping.h>
> -
> -#include "qcom_scm.h"
> -
> -#define MAX_QCOM_SCM_ARGS 10
> -#define MAX_QCOM_SCM_RETS 3
> -
> -enum qcom_scm_arg_types {
> - QCOM_SCM_VAL,
> - QCOM_SCM_RO,
> - QCOM_SCM_RW,
> - QCOM_SCM_BUFVAL,
> -};
> -
> -#define QCOM_SCM_ARGS_IMPL(num, a, b, c, d, e, f, g, h, i, j, ...) (\
> - (((a) & 0x3) << 4) | \
> - (((b) & 0x3) << 6) | \
> - (((c) & 0x3) << 8) | \
> - (((d) & 0x3) << 10) | \
> - (((e) & 0x3) << 12) | \
> - (((f) & 0x3) << 14) | \
> - (((g) & 0x3) << 16) | \
> - (((h) & 0x3) << 18) | \
> - (((i) & 0x3) << 20) | \
> - (((j) & 0x3) << 22) | \
> - ((num) & 0xf))
> -
> -#define QCOM_SCM_ARGS(...) QCOM_SCM_ARGS_IMPL(__VA_ARGS__, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
> -
> -/**
> - * struct qcom_scm_desc
> - * @arginfo: Metadata describing the arguments in args[]
> - * @args: The array of arguments for the secure syscall
> - * @res: The values returned by the secure syscall
> - */
> -struct qcom_scm_desc {
> - u32 svc;
> - u32 cmd;
> - u32 arginfo;
> - u64 args[MAX_QCOM_SCM_ARGS];
> - u64 res[MAX_QCOM_SCM_RETS];
> - u32 owner;
> -};
> -
> -struct arm_smccc_args {
> - unsigned long a[8];
> -};
> -
> -enum qcom_smc_convention {
> - SMC_CONVENTION_UNKNOWN,
> - SMC_CONVENTION_LEGACY,
> - SMC_CONVENTION_ARM_32,
> - SMC_CONVENTION_ARM_64,
> -};
> -
> -static enum qcom_smc_convention qcom_smc_convention = SMC_CONVENTION_UNKNOWN;
> -static DEFINE_MUTEX(qcom_scm_lock);
> -
> -#define QCOM_SCM_EBUSY_WAIT_MS 30
> -#define QCOM_SCM_EBUSY_MAX_RETRY 20
> -
> -#define SMCCC_FUNCNUM(s, c) ((((s) & 0xFF) << 8) | ((c) & 0xFF))
> -#define SMCCC_N_REG_ARGS 4
> -#define SMCCC_FIRST_REG_IDX 2
> -#define SMCCC_N_EXT_ARGS (MAX_QCOM_SCM_ARGS - SMCCC_N_REG_ARGS + 1)
> -#define SMCCC_LAST_REG_IDX (SMCCC_FIRST_REG_IDX + SMCCC_N_REG_ARGS - 1)
> -
> -static void __qcom_scm_call_do_quirk(const struct arm_smccc_args *smc,
> - struct arm_smccc_res *res)
> -{
> - unsigned long a0 = smc->a[0];
> - struct arm_smccc_quirk quirk = { .id = ARM_SMCCC_QUIRK_QCOM_A6 };
> -
> - quirk.state.a6 = 0;
> -
> - do {
> - arm_smccc_smc_quirk(a0, smc->a[1], smc->a[2], smc->a[3],
> - smc->a[4], smc->a[5], quirk.state.a6,
> - smc->a[7], res, &quirk);
> -
> - if (res->a0 == QCOM_SCM_INTERRUPTED)
> - a0 = res->a0;
> -
> - } while (res->a0 == QCOM_SCM_INTERRUPTED);
> -}
> -
> -static int qcom_scm_call_smccc(struct device *dev,
> - struct qcom_scm_desc *desc, bool atomic)
> -{
> - int arglen = desc->arginfo & 0xf;
> - int i;
> - dma_addr_t args_phys = 0;
> - void *args_virt = NULL;
> - size_t alloc_len;
> - gfp_t flag = atomic ? GFP_ATOMIC : GFP_KERNEL;
> - struct arm_smccc_res res;
> - struct arm_smccc_args smc = {0};
> -
> - smc.a[0] = ARM_SMCCC_CALL_VAL(
> - atomic ? ARM_SMCCC_FAST_CALL : ARM_SMCCC_STD_CALL,
> - (qcom_smc_convention == SMC_CONVENTION_ARM_64) ?
> - ARM_SMCCC_SMC_64 :
> - ARM_SMCCC_SMC_32,
> - desc->owner,
> - SMCCC_FUNCNUM(desc->svc, desc->cmd));
> - smc.a[1] = desc->arginfo;
> - for (i = 0; i < SMCCC_N_REG_ARGS; i++)
> - smc.a[i + SMCCC_FIRST_REG_IDX] = desc->args[i];
> -
> - if (unlikely(arglen > SMCCC_N_REG_ARGS)) {
> - alloc_len = SMCCC_N_EXT_ARGS * sizeof(u64);
> - args_virt = kzalloc(PAGE_ALIGN(alloc_len), flag);
> -
> - if (!args_virt)
> - return -ENOMEM;
> -
> - if (qcom_smc_convention == SMC_CONVENTION_ARM_32) {
> - __le32 *args = args_virt;
> -
> - for (i = 0; i < SMCCC_N_EXT_ARGS; i++)
> - args[i] = cpu_to_le32(desc->args[i +
> - SMCCC_N_REG_ARGS - 1]);
> - } else {
> - __le64 *args = args_virt;
> -
> - for (i = 0; i < SMCCC_N_EXT_ARGS; i++)
> - args[i] = cpu_to_le64(desc->args[i +
> - SMCCC_N_REG_ARGS - 1]);
> - }
> -
> - args_phys = dma_map_single(dev, args_virt, alloc_len,
> - DMA_TO_DEVICE);
> -
> - if (dma_mapping_error(dev, args_phys)) {
> - kfree(args_virt);
> - return -ENOMEM;
> - }
> -
> - smc.a[SMCCC_LAST_REG_IDX] = args_phys;
> - }
> -
> - if (atomic) {
> - __qcom_scm_call_do_quirk(&smc, &res);
> - } else {
> - int retry_count = 0;
> -
> - do {
> - mutex_lock(&qcom_scm_lock);
> -
> - __qcom_scm_call_do_quirk(&smc, &res);
> -
> - mutex_unlock(&qcom_scm_lock);
> -
> - if (res.a0 == QCOM_SCM_V2_EBUSY) {
> - if (retry_count++ > QCOM_SCM_EBUSY_MAX_RETRY)
> - break;
> - msleep(QCOM_SCM_EBUSY_WAIT_MS);
> - }
> - } while (res.a0 == QCOM_SCM_V2_EBUSY);
> - }
> -
> - if (args_virt) {
> - dma_unmap_single(dev, args_phys, alloc_len, DMA_TO_DEVICE);
> - kfree(args_virt);
> - }
> -
> - desc->res[0] = res.a1;
> - desc->res[1] = res.a2;
> - desc->res[2] = res.a3;
> -
> - if (res.a0 < 0)
> - return qcom_scm_remap_error(res.a0);
> -
> - return 0;
> -}
> -
> -#define LEGACY_FUNCNUM(s, c) (((s) << 10) | ((c) & 0x3ff))
> -
> -/**
> - * struct legacy_command - one SCM command buffer
> - * @len: total available memory for command and response
> - * @buf_offset: start of command buffer
> - * @resp_hdr_offset: start of response buffer
> - * @id: command to be executed
> - * @buf: buffer returned from legacy_get_command_buffer()
> - *
> - * An SCM command is laid out in memory as follows:
> - *
> - * ------------------- <--- struct legacy_command
> - * | command header |
> - * ------------------- <--- legacy_get_command_buffer()
> - * | command buffer |
> - * ------------------- <--- struct legacy_response and
> - * | response header | legacy_command_to_response()
> - * ------------------- <--- legacy_get_response_buffer()
> - * | response buffer |
> - * -------------------
> - *
> - * There can be arbitrary padding between the headers and buffers so
> - * you should always use the appropriate qcom_scm_get_*_buffer() routines
> - * to access the buffers in a safe manner.
> - */
> -struct legacy_command {
> - __le32 len;
> - __le32 buf_offset;
> - __le32 resp_hdr_offset;
> - __le32 id;
> - __le32 buf[0];
> -};
> -
> -/**
> - * struct legacy_response - one SCM response buffer
> - * @len: total available memory for response
> - * @buf_offset: start of response data relative to start of legacy_response
> - * @is_complete: indicates if the command has finished processing
> - */
> -struct legacy_response {
> - __le32 len;
> - __le32 buf_offset;
> - __le32 is_complete;
> -};
> -
> -/**
> - * legacy_command_to_response() - Get a pointer to a legacy_response
> - * @cmd: command
> - *
> - * Returns a pointer to a response for a command.
> - */
> -static inline struct legacy_response *legacy_command_to_response(
> - const struct legacy_command *cmd)
> -{
> - return (void *)cmd + le32_to_cpu(cmd->resp_hdr_offset);
> -}
> -
> -/**
> - * legacy_get_command_buffer() - Get a pointer to a command buffer
> - * @cmd: command
> - *
> - * Returns a pointer to the command buffer of a command.
> - */
> -static inline void *legacy_get_command_buffer(const struct legacy_command *cmd)
> -{
> - return (void *)cmd->buf;
> -}
> -
> -/**
> - * legacy_get_response_buffer() - Get a pointer to a response buffer
> - * @rsp: response
> - *
> - * Returns a pointer to a response buffer of a response.
> - */
> -static inline void *legacy_get_response_buffer(const struct legacy_response *rsp)
> -{
> - return (void *)rsp + le32_to_cpu(rsp->buf_offset);
> -}
> -
> -static void __qcom_scm_call_do(const struct arm_smccc_args *smc,
> - struct arm_smccc_res *res)
> -{
> - do {
> - arm_smccc_smc(smc->a[0], smc->a[1], smc->a[2], smc->a[3],
> - smc->a[4], smc->a[5], smc->a[6], smc->a[7], res);
> - } while (res->a0 == QCOM_SCM_INTERRUPTED);
> -}
> -
> -/**
> - * qcom_scm_call_legacy() - Send an SCM command
> - * @dev: struct device
> - * @svc_id: service identifier
> - * @cmd_id: command identifier
> - * @cmd_buf: command buffer
> - * @cmd_len: length of the command buffer
> - * @resp_buf: response buffer
> - * @resp_len: length of the response buffer
> - *
> - * Sends a command to the SCM and waits for the command to finish processing.
> - *
> - * A note on cache maintenance:
> - * Note that any buffers that are expected to be accessed by the secure world
> - * must be flushed before invoking qcom_scm_call and invalidated in the cache
> - * immediately after qcom_scm_call returns. Cache maintenance on the command
> - * 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.
> - */
> -static int qcom_scm_call_legacy(struct device *dev, struct qcom_scm_desc *desc)
> -{
> - int arglen = desc->arginfo & 0xf;
> - int ret = 0, context_id;
> - size_t i;
> - struct legacy_command *cmd;
> - struct legacy_response *rsp;
> - struct arm_smccc_args smc = {0};
> - struct arm_smccc_res res;
> - const size_t cmd_len = arglen * sizeof(__le32);
> - const size_t resp_len = MAX_QCOM_SCM_RETS * sizeof(__le32);
> - size_t alloc_len = sizeof(*cmd) + cmd_len + sizeof(*rsp) + resp_len;
> - dma_addr_t cmd_phys;
> - __le32 *arg_buf;
> - __le32 *res_buf;
> -
> - cmd = kzalloc(PAGE_ALIGN(alloc_len), GFP_KERNEL);
> - if (!cmd)
> - return -ENOMEM;
> -
> - cmd->len = cpu_to_le32(alloc_len);
> - cmd->buf_offset = cpu_to_le32(sizeof(*cmd));
> - cmd->resp_hdr_offset = cpu_to_le32(sizeof(*cmd) + cmd_len);
> - cmd->id = cpu_to_le32(LEGACY_FUNCNUM(desc->svc, desc->cmd));
> -
> - arg_buf = legacy_get_command_buffer(cmd);
> - for (i = 0; i < arglen; i++)
> - arg_buf[i] = cpu_to_le32(desc->args[i]);
> -
> - rsp = legacy_command_to_response(cmd);
> -
> - cmd_phys = dma_map_single(dev, cmd, alloc_len, DMA_TO_DEVICE);
> - if (dma_mapping_error(dev, cmd_phys)) {
> - kfree(cmd);
> - return -ENOMEM;
> - }
> -
> - smc.a[0] = 1;
> - smc.a[1] = (unsigned long)&context_id;
> - smc.a[2] = cmd_phys;
> -
> - mutex_lock(&qcom_scm_lock);
> - __qcom_scm_call_do(&smc, &res);
> - if (res.a0 < 0)
> - ret = qcom_scm_remap_error(res.a0);
> - mutex_unlock(&qcom_scm_lock);
> - if (ret)
> - goto out;
> -
> - do {
> - dma_sync_single_for_cpu(dev, cmd_phys + sizeof(*cmd) + cmd_len,
> - sizeof(*rsp), DMA_FROM_DEVICE);
> - } while (!rsp->is_complete);
> -
> - dma_sync_single_for_cpu(dev, cmd_phys + sizeof(*cmd) + cmd_len +
> - le32_to_cpu(rsp->buf_offset),
> - resp_len, DMA_FROM_DEVICE);
> -
> - res_buf = legacy_get_response_buffer(rsp);
> - for (i = 0; i < MAX_QCOM_SCM_RETS; i++)
> - desc->res[i] = le32_to_cpu(res_buf[i]);
> -out:
> - dma_unmap_single(dev, cmd_phys, alloc_len, DMA_TO_DEVICE);
> - kfree(cmd);
> - return ret;
> -}
> -
> -#define LEGACY_ATOMIC_N_REG_ARGS 5
> -#define LEGACY_ATOMIC_FIRST_REG_IDX 2
> -#define LEGACY_CLASS_REGISTER (0x2 << 8)
> -#define LEGACY_MASK_IRQS BIT(5)
> -#define LEGACY_ATOMIC(svc, cmd, n) ((LEGACY_FUNCNUM(svc, cmd) << 12) | \
> - LEGACY_CLASS_REGISTER | \
> - LEGACY_MASK_IRQS | \
> - (n & 0xf))
> -
> -/**
> - * qcom_scm_call_atomic_legacy() - Send an atomic SCM command with up to
> - * 5 arguments and 3 return values
> - *
> - * This shall only be used with commands that are guaranteed to be
> - * uninterruptable, atomic and SMP safe.
> - */
> -static int qcom_scm_call_atomic_legacy(struct device *dev,
> - struct qcom_scm_desc *desc)
> -{
> - int context_id;
> - struct arm_smccc_args smc = {0};
> - struct arm_smccc_res res;
> - size_t i, arglen = desc->arginfo & 0xf;
> -
> - BUG_ON(arglen > LEGACY_ATOMIC_N_REG_ARGS);
> -
> - smc.a[0] = LEGACY_ATOMIC(desc->svc, desc->cmd, arglen);
> - smc.a[1] = (unsigned long)&context_id;
> -
> - for (i = 0; i < arglen; i++)
> - smc.a[i + LEGACY_ATOMIC_FIRST_REG_IDX] = desc->args[i];
> -
> - arm_smccc_smc(smc.a[0], smc.a[1], smc.a[2], smc.a[3],
> - smc.a[4], smc.a[5], smc.a[6], smc.a[7], &res);
> -
> - desc->res[0] = res.a1;
> - desc->res[1] = res.a2;
> - desc->res[2] = res.a3;
> -
> - return res.a0;
> -}
> -
> -/**
> - * 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, struct qcom_scm_desc *desc)
> -{
> - might_sleep();
> - switch (qcom_smc_convention) {
> - case SMC_CONVENTION_ARM_32:
> - case SMC_CONVENTION_ARM_64:
> - return qcom_scm_call_smccc(dev, desc, false);
> - case SMC_CONVENTION_LEGACY:
> - return qcom_scm_call_legacy(dev, desc);
> - 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, struct qcom_scm_desc *desc)
> -{
> - switch (qcom_smc_convention) {
> - case SMC_CONVENTION_ARM_32:
> - case SMC_CONVENTION_ARM_64:
> - return qcom_scm_call_smccc(dev, desc, true);
> - case SMC_CONVENTION_LEGACY:
> - return qcom_scm_call_atomic_legacy(dev, desc);
> - default:
> - pr_err("Unknown current SCM calling convention.\n");
> - return -EINVAL;
> - }
> -}
> -
> -#define QCOM_SCM_FLAG_COLDBOOT_CPU0 0x00
> -#define QCOM_SCM_FLAG_COLDBOOT_CPU1 0x01
> -#define QCOM_SCM_FLAG_COLDBOOT_CPU2 0x08
> -#define QCOM_SCM_FLAG_COLDBOOT_CPU3 0x20
> -
> -/**
> - * qcom_scm_set_cold_boot_addr() - Set the cold boot address for cpus
> - * @entry: Entry point function for the cpus
> - * @cpus: The cpumask of cpus that will use the entry point
> - *
> - * Set the cold boot address of the cpus. Any cpu outside the supported
> - * range would be removed from the cpu present mask.
> - */
> -int __qcom_scm_set_cold_boot_addr(struct device *dev, void *entry,
> - const cpumask_t *cpus)
> -{
> - int flags = 0;
> - int cpu;
> - int scm_cb_flags[] = {
> - QCOM_SCM_FLAG_COLDBOOT_CPU0,
> - QCOM_SCM_FLAG_COLDBOOT_CPU1,
> - QCOM_SCM_FLAG_COLDBOOT_CPU2,
> - QCOM_SCM_FLAG_COLDBOOT_CPU3,
> - };
> - struct qcom_scm_desc desc = {
> - .svc = QCOM_SCM_SVC_BOOT,
> - .cmd = QCOM_SCM_BOOT_SET_ADDR,
> - .owner = ARM_SMCCC_OWNER_SIP,
> - };
> -
> - if (!cpus || (cpus && cpumask_empty(cpus)))
> - return -EINVAL;
> -
> - for_each_cpu(cpu, cpus) {
> - if (cpu < ARRAY_SIZE(scm_cb_flags))
> - flags |= scm_cb_flags[cpu];
> - else
> - set_cpu_present(cpu, false);
> - }
> -
> - desc.args[0] = flags;
> - desc.args[1] = virt_to_phys(entry);
> - desc.arginfo = QCOM_SCM_ARGS(2);
> -
> - return qcom_scm_call_atomic(dev, &desc);
> -}
> -
> -#define QCOM_SCM_FLAG_WARMBOOT_CPU0 0x04
> -#define QCOM_SCM_FLAG_WARMBOOT_CPU1 0x02
> -#define QCOM_SCM_FLAG_WARMBOOT_CPU2 0x10
> -#define QCOM_SCM_FLAG_WARMBOOT_CPU3 0x40
> -
> -struct qcom_scm_entry {
> - int flag;
> - void *entry;
> -};
> -
> -static struct qcom_scm_entry qcom_scm_wb[] = {
> - { .flag = QCOM_SCM_FLAG_WARMBOOT_CPU0 },
> - { .flag = QCOM_SCM_FLAG_WARMBOOT_CPU1 },
> - { .flag = QCOM_SCM_FLAG_WARMBOOT_CPU2 },
> - { .flag = QCOM_SCM_FLAG_WARMBOOT_CPU3 },
> -};
> -
> -/**
> - * qcom_scm_set_warm_boot_addr() - Set the warm boot address for cpus
> - * @dev: Device pointer
> - * @entry: Entry point function for the cpus
> - * @cpus: The cpumask of cpus that will use the entry point
> - *
> - * Set the Linux entry point for the SCM to transfer control to when coming
> - * out of a power down. CPU power down may be executed on cpuidle or hotplug.
> - */
> -int __qcom_scm_set_warm_boot_addr(struct device *dev, void *entry,
> - const cpumask_t *cpus)
> -{
> - int ret;
> - int flags = 0;
> - int cpu;
> - struct qcom_scm_desc desc = {
> - .svc = QCOM_SCM_SVC_BOOT,
> - .cmd = QCOM_SCM_BOOT_SET_ADDR,
> - };
> -
> - /*
> - * Reassign only if we are switching from hotplug entry point
> - * to cpuidle entry point or vice versa.
> - */
> - for_each_cpu(cpu, cpus) {
> - if (entry == qcom_scm_wb[cpu].entry)
> - continue;
> - flags |= qcom_scm_wb[cpu].flag;
> - }
> -
> - /* No change in entry function */
> - if (!flags)
> - return 0;
> -
> - desc.args[0] = flags;
> - desc.args[1] = virt_to_phys(entry);
> - ret = qcom_scm_call(dev, &desc);
> - if (!ret) {
> - for_each_cpu(cpu, cpus)
> - qcom_scm_wb[cpu].entry = entry;
> - }
> -
> - return ret;
> -}
> -
> -/**
> - * qcom_scm_cpu_power_down() - Power down the cpu
> - * @flags - Flags to flush cache
> - *
> - * This is an end point to power down cpu. If there was a pending interrupt,
> - * the control would return from this function, otherwise, the cpu jumps to the
> - * warm boot entry point set for this cpu upon reset.
> - */
> -void __qcom_scm_cpu_power_down(struct device *dev, u32 flags)
> -{
> - struct qcom_scm_desc desc = {
> - .svc = QCOM_SCM_SVC_BOOT,
> - .cmd = QCOM_SCM_BOOT_TERMINATE_PC,
> - .args[0] = flags & QCOM_SCM_FLUSH_FLAG_MASK,
> - .arginfo = QCOM_SCM_ARGS(1),
> - .owner = ARM_SMCCC_OWNER_SIP,
> - };
> -
> - qcom_scm_call_atomic(dev, &desc);
> -}
> -
> -int __qcom_scm_set_remote_state(struct device *dev, u32 state, u32 id)
> -{
> - struct qcom_scm_desc desc = {
> - .svc = QCOM_SCM_SVC_BOOT,
> - .cmd = QCOM_SCM_BOOT_SET_REMOTE_STATE,
> - .owner = ARM_SMCCC_OWNER_SIP,
> - };
> - int ret;
> -
> - desc.args[0] = state;
> - desc.args[1] = id;
> - desc.arginfo = QCOM_SCM_ARGS(2);
> -
> - ret = qcom_scm_call(dev, &desc);
> -
> - return ret ? : desc.res[0];
> -}
> -
> -int __qcom_scm_set_dload_mode(struct device *dev, bool enable)
> -{
> - struct qcom_scm_desc desc = {
> - .svc = QCOM_SCM_SVC_BOOT,
> - .cmd = QCOM_SCM_BOOT_SET_DLOAD_MODE,
> - .owner = ARM_SMCCC_OWNER_SIP,
> - };
> -
> - desc.args[0] = QCOM_SCM_BOOT_SET_DLOAD_MODE;
> - desc.args[1] = enable ? QCOM_SCM_BOOT_SET_DLOAD_MODE : 0;
> - desc.arginfo = QCOM_SCM_ARGS(2);
> -
> - return qcom_scm_call_atomic(dev, &desc);
> -}
> -
> -bool __qcom_scm_pas_supported(struct device *dev, u32 peripheral)
> -{
> - int ret;
> - struct qcom_scm_desc desc = {
> - .svc = QCOM_SCM_SVC_PIL,
> - .cmd = QCOM_SCM_PIL_PAS_IS_SUPPORTED,
> - .owner = ARM_SMCCC_OWNER_SIP,
> - };
> -
> - desc.args[0] = peripheral;
> - desc.arginfo = QCOM_SCM_ARGS(1);
> -
> - ret = qcom_scm_call(dev, &desc);
> -
> - return ret ? false : !!desc.res[0];
> -}
> -
> -int __qcom_scm_pas_init_image(struct device *dev, u32 peripheral,
> - dma_addr_t metadata_phys)
> -{
> - int ret;
> - struct qcom_scm_desc desc = {
> - .svc = QCOM_SCM_SVC_PIL,
> - .cmd = QCOM_SCM_PIL_PAS_INIT_IMAGE,
> - .owner = ARM_SMCCC_OWNER_SIP,
> - };
> -
> - desc.args[0] = peripheral;
> - desc.args[1] = metadata_phys;
> - desc.arginfo = QCOM_SCM_ARGS(2, QCOM_SCM_VAL, QCOM_SCM_RW);
> -
> - ret = qcom_scm_call(dev, &desc);
> -
> - return ret ? : desc.res[0];
> -}
> -
> -int __qcom_scm_pas_mem_setup(struct device *dev, u32 peripheral,
> - phys_addr_t addr, phys_addr_t size)
> -{
> - int ret;
> - struct qcom_scm_desc desc = {
> - .svc = QCOM_SCM_SVC_PIL,
> - .cmd = QCOM_SCM_PIL_PAS_MEM_SETUP,
> - .owner = ARM_SMCCC_OWNER_SIP,
> - };
> -
> - desc.args[0] = peripheral;
> - desc.args[1] = addr;
> - desc.args[2] = size;
> - desc.arginfo = QCOM_SCM_ARGS(3);
> -
> - ret = qcom_scm_call(dev, &desc);
> -
> - return ret ? : desc.res[0];
> -}
> -
> -int __qcom_scm_pas_auth_and_reset(struct device *dev, u32 peripheral)
> -{
> - int ret;
> - struct qcom_scm_desc desc = {
> - .svc = QCOM_SCM_SVC_PIL,
> - .cmd = QCOM_SCM_PIL_PAS_AUTH_AND_RESET,
> - .owner = ARM_SMCCC_OWNER_SIP,
> - };
> -
> - desc.args[0] = peripheral;
> - desc.arginfo = QCOM_SCM_ARGS(1);
> -
> - ret = qcom_scm_call(dev, &desc);
> -
> - return ret ? : desc.res[0];
> -}
> -
> -int __qcom_scm_pas_shutdown(struct device *dev, u32 peripheral)
> -{
> - int ret;
> - struct qcom_scm_desc desc = {
> - .svc = QCOM_SCM_SVC_PIL,
> - .cmd = QCOM_SCM_PIL_PAS_SHUTDOWN,
> - .owner = ARM_SMCCC_OWNER_SIP,
> - };
> -
> - desc.args[0] = peripheral;
> - desc.arginfo = QCOM_SCM_ARGS(1);
> -
> - ret = qcom_scm_call(dev, &desc);
> -
> - return ret ? : desc.res[0];
> -}
> -
> -int __qcom_scm_pas_mss_reset(struct device *dev, bool reset)
> -{
> - struct qcom_scm_desc desc = {
> - .svc = QCOM_SCM_SVC_PIL,
> - .cmd = QCOM_SCM_PIL_PAS_MSS_RESET,
> - .owner = ARM_SMCCC_OWNER_SIP,
> - };
> - int ret;
> -
> - desc.args[0] = reset;
> - desc.args[1] = 0;
> - desc.arginfo = QCOM_SCM_ARGS(2);
> -
> - ret = qcom_scm_call(dev, &desc);
> -
> - return ret ? : desc.res[0];
> -}
> -
> -int __qcom_scm_io_readl(struct device *dev, phys_addr_t addr,
> - unsigned int *val)
> -{
> - struct qcom_scm_desc desc = {
> - .svc = QCOM_SCM_SVC_IO,
> - .cmd = QCOM_SCM_IO_READ,
> - .owner = ARM_SMCCC_OWNER_SIP,
> - };
> - int ret;
> -
> - desc.args[0] = addr;
> - desc.arginfo = QCOM_SCM_ARGS(1);
> -
> - ret = qcom_scm_call_atomic(dev, &desc);
> - if (ret >= 0)
> - *val = desc.res[0];
> -
> - return ret < 0 ? ret : 0;
> -}
> -
> -int __qcom_scm_io_writel(struct device *dev, phys_addr_t addr, unsigned int val)
> -{
> - struct qcom_scm_desc desc = {
> - .svc = QCOM_SCM_SVC_IO,
> - .cmd = QCOM_SCM_IO_WRITE,
> - .owner = ARM_SMCCC_OWNER_SIP,
> - };
> -
> - desc.args[0] = addr;
> - desc.args[1] = val;
> - desc.arginfo = QCOM_SCM_ARGS(2);
> -
> - return qcom_scm_call_atomic(dev, &desc);
> -}
> -
> -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,
> - };
> -
> - desc.arginfo = QCOM_SCM_ARGS(1);
> - switch (qcom_smc_convention) {
> - case SMC_CONVENTION_ARM_32:
> - case SMC_CONVENTION_ARM_64:
> - desc.args[0] = SMCCC_FUNCNUM(svc_id, cmd_id) |
> - (ARM_SMCCC_OWNER_SIP << ARM_SMCCC_OWNER_SHIFT);
> - break;
> - case SMC_CONVENTION_LEGACY:
> - desc.args[0] = LEGACY_FUNCNUM(svc_id, cmd_id);
> - break;
> - default:
> - pr_err("Unknown SMC convention being used\n");
> - return -EINVAL;
> - }
> -
> - ret = qcom_scm_call(dev, &desc);
> -
> - return ret ? : desc.res[0];
> -}
> -
> -int __qcom_scm_restore_sec_cfg(struct device *dev, u32 device_id, u32 spare)
> -{
> - struct qcom_scm_desc desc = {
> - .svc = QCOM_SCM_SVC_MP,
> - .cmd = QCOM_SCM_MP_RESTORE_SEC_CFG,
> - .owner = ARM_SMCCC_OWNER_SIP,
> - };
> - int ret;
> -
> - desc.args[0] = device_id;
> - desc.args[1] = spare;
> - desc.arginfo = QCOM_SCM_ARGS(2);
> -
> - ret = qcom_scm_call(dev, &desc);
> -
> - return ret ? : desc.res[0];
> -}
> -
> -int __qcom_scm_iommu_secure_ptbl_size(struct device *dev, u32 spare,
> - size_t *size)
> -{
> - struct qcom_scm_desc desc = {
> - .svc = QCOM_SCM_SVC_MP,
> - .cmd = QCOM_SCM_MP_IOMMU_SECURE_PTBL_SIZE,
> - .owner = ARM_SMCCC_OWNER_SIP,
> - };
> - int ret;
> -
> - desc.args[0] = spare;
> - desc.arginfo = QCOM_SCM_ARGS(1);
> -
> - ret = qcom_scm_call(dev, &desc);
> -
> - if (size)
> - *size = desc.res[0];
> -
> - return ret ? : desc.res[1];
> -}
> -
> -int __qcom_scm_iommu_secure_ptbl_init(struct device *dev, u64 addr, u32 size,
> - u32 spare)
> -{
> - struct qcom_scm_desc desc = {
> - .svc = QCOM_SCM_SVC_MP,
> - .cmd = QCOM_SCM_MP_IOMMU_SECURE_PTBL_INIT,
> - .owner = ARM_SMCCC_OWNER_SIP,
> - };
> - int ret;
> -
> - desc.args[0] = addr;
> - desc.args[1] = size;
> - desc.args[2] = spare;
> - desc.arginfo = QCOM_SCM_ARGS(3, QCOM_SCM_RW, QCOM_SCM_VAL,
> - QCOM_SCM_VAL);
> -
> - ret = qcom_scm_call(dev, &desc);
> -
> - /* the pg table has been initialized already, ignore the error */
> - if (ret == -EPERM)
> - ret = 0;
> -
> - return ret;
> -}
> -
> -int __qcom_scm_assign_mem(struct device *dev, phys_addr_t mem_region,
> - size_t mem_sz, phys_addr_t src, size_t src_sz,
> - phys_addr_t dest, size_t dest_sz)
> -{
> - int ret;
> - struct qcom_scm_desc desc = {
> - .svc = QCOM_SCM_SVC_MP,
> - .cmd = QCOM_SCM_MP_ASSIGN,
> - .owner = ARM_SMCCC_OWNER_SIP,
> - };
> -
> - desc.args[0] = mem_region;
> - desc.args[1] = mem_sz;
> - desc.args[2] = src;
> - desc.args[3] = src_sz;
> - desc.args[4] = dest;
> - desc.args[5] = dest_sz;
> - desc.args[6] = 0;
> -
> - desc.arginfo = QCOM_SCM_ARGS(7, QCOM_SCM_RO, QCOM_SCM_VAL,
> - QCOM_SCM_RO, QCOM_SCM_VAL, QCOM_SCM_RO,
> - QCOM_SCM_VAL, QCOM_SCM_VAL);
> -
> - ret = qcom_scm_call(dev, &desc);
> -
> - return ret ? : desc.res[0];
> -}
> -
> -int __qcom_scm_hdcp_req(struct device *dev, struct qcom_scm_hdcp_req *req,
> - u32 req_cnt, u32 *resp)
> -{
> - int ret;
> - struct qcom_scm_desc desc = {
> - .svc = QCOM_SCM_SVC_HDCP,
> - .cmd = QCOM_SCM_HDCP_INVOKE,
> - .owner = ARM_SMCCC_OWNER_SIP,
> - };
> -
> - if (req_cnt > QCOM_SCM_HDCP_MAX_REQ_CNT)
> - return -ERANGE;
> -
> - desc.args[0] = req[0].addr;
> - desc.args[1] = req[0].val;
> - desc.args[2] = req[1].addr;
> - desc.args[3] = req[1].val;
> - desc.args[4] = req[2].addr;
> - desc.args[5] = req[2].val;
> - desc.args[6] = req[3].addr;
> - desc.args[7] = req[3].val;
> - desc.args[8] = req[4].addr;
> - desc.args[9] = req[4].val;
> - desc.arginfo = QCOM_SCM_ARGS(10);
> -
> - ret = qcom_scm_call(dev, &desc);
> - *resp = desc.res[0];
> -
> - return ret;
> -}
> -
> -int __qcom_scm_qsmmu500_wait_safe_toggle(struct device *dev, bool en)
> -{
> - struct qcom_scm_desc desc = {
> - .svc = QCOM_SCM_SVC_SMMU_PROGRAM,
> - .cmd = QCOM_SCM_SMMU_CONFIG_ERRATA1,
> - .owner = ARM_SMCCC_OWNER_SIP,
> - };
> -
> - desc.args[0] = QCOM_SCM_SMMU_CONFIG_ERRATA1_CLIENT_ALL;
> - desc.args[1] = en;
> - desc.arginfo = QCOM_SCM_ARGS(2);
> -
> - return qcom_scm_call_atomic(dev, &desc);
> -}
> -
> -void __qcom_scm_init(void)
> -{
> - qcom_smc_convention = SMC_CONVENTION_LEGACY;
> - if (__qcom_scm_is_call_available(NULL, QCOM_SCM_SVC_INFO,
> - QCOM_SCM_INFO_IS_CALL_AVAIL) == 1)
> - goto out;
> -
> - qcom_smc_convention = SMC_CONVENTION_ARM_64;
> - if (__qcom_scm_is_call_available(NULL, QCOM_SCM_SVC_INFO,
> - QCOM_SCM_INFO_IS_CALL_AVAIL) == 1)
> - goto out;
> -
> - qcom_smc_convention = SMC_CONVENTION_ARM_32;
> - if (__qcom_scm_is_call_available(NULL, QCOM_SCM_SVC_INFO,
> - QCOM_SCM_INFO_IS_CALL_AVAIL) == 1)
> - goto out;
> -
> - qcom_smc_convention = SMC_CONVENTION_UNKNOWN;
> -out:
> - pr_debug("QCOM SCM SMC Convention: %d\n", qcom_smc_convention);
> -}
> diff --git a/drivers/firmware/qcom_scm-smc.c b/drivers/firmware/qcom_scm-smc.c
> new file mode 100644
> index 0000000..355d9d7
> --- /dev/null
> +++ b/drivers/firmware/qcom_scm-smc.c
> @@ -0,0 +1,949 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/* Copyright (c) 2015,2019 The Linux Foundation. All rights reserved.
> + */
> +
> +#include <linux/io.h>
> +#include <linux/errno.h>
> +#include <linux/delay.h>
> +#include <linux/mutex.h>
> +#include <linux/slab.h>
> +#include <linux/types.h>
> +#include <linux/qcom_scm.h>
> +#include <linux/arm-smccc.h>
> +#include <linux/dma-mapping.h>
> +
> +#include "qcom_scm.h"
> +
> +#define MAX_QCOM_SCM_ARGS 10
> +#define MAX_QCOM_SCM_RETS 3
> +
> +enum qcom_scm_arg_types {
> + QCOM_SCM_VAL,
> + QCOM_SCM_RO,
> + QCOM_SCM_RW,
> + QCOM_SCM_BUFVAL,
> +};
> +
> +#define QCOM_SCM_ARGS_IMPL(num, a, b, c, d, e, f, g, h, i, j, ...) (\
> + (((a) & 0x3) << 4) | \
> + (((b) & 0x3) << 6) | \
> + (((c) & 0x3) << 8) | \
> + (((d) & 0x3) << 10) | \
> + (((e) & 0x3) << 12) | \
> + (((f) & 0x3) << 14) | \
> + (((g) & 0x3) << 16) | \
> + (((h) & 0x3) << 18) | \
> + (((i) & 0x3) << 20) | \
> + (((j) & 0x3) << 22) | \
> + ((num) & 0xf))
> +
> +#define QCOM_SCM_ARGS(...) QCOM_SCM_ARGS_IMPL(__VA_ARGS__, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
> +
> +/**
> + * struct qcom_scm_desc
> + * @arginfo: Metadata describing the arguments in args[]
> + * @args: The array of arguments for the secure syscall
> + * @res: The values returned by the secure syscall
> + */
> +struct qcom_scm_desc {
> + u32 svc;
> + u32 cmd;
> + u32 arginfo;
> + u64 args[MAX_QCOM_SCM_ARGS];
> + u64 res[MAX_QCOM_SCM_RETS];
> + u32 owner;
> +};
> +
> +struct arm_smccc_args {
> + unsigned long a[8];
> +};
> +
> +enum qcom_smc_convention {
> + SMC_CONVENTION_UNKNOWN,
> + SMC_CONVENTION_LEGACY,
> + SMC_CONVENTION_ARM_32,
> + SMC_CONVENTION_ARM_64,
> +};
> +
> +static enum qcom_smc_convention qcom_smc_convention = SMC_CONVENTION_UNKNOWN;
> +static DEFINE_MUTEX(qcom_scm_lock);
> +
> +#define QCOM_SCM_EBUSY_WAIT_MS 30
> +#define QCOM_SCM_EBUSY_MAX_RETRY 20
> +
> +#define SMCCC_FUNCNUM(s, c) ((((s) & 0xFF) << 8) | ((c) & 0xFF))
> +#define SMCCC_N_REG_ARGS 4
> +#define SMCCC_FIRST_REG_IDX 2
> +#define SMCCC_N_EXT_ARGS (MAX_QCOM_SCM_ARGS - SMCCC_N_REG_ARGS + 1)
> +#define SMCCC_LAST_REG_IDX (SMCCC_FIRST_REG_IDX + SMCCC_N_REG_ARGS - 1)
> +
> +static void __qcom_scm_call_do_quirk(const struct arm_smccc_args *smc,
> + struct arm_smccc_res *res)
> +{
> + unsigned long a0 = smc->a[0];
> + struct arm_smccc_quirk quirk = { .id = ARM_SMCCC_QUIRK_QCOM_A6 };
> +
> + quirk.state.a6 = 0;
> +
> + do {
> + arm_smccc_smc_quirk(a0, smc->a[1], smc->a[2], smc->a[3],
> + smc->a[4], smc->a[5], quirk.state.a6,
> + smc->a[7], res, &quirk);
> +
> + if (res->a0 == QCOM_SCM_INTERRUPTED)
> + a0 = res->a0;
> +
> + } while (res->a0 == QCOM_SCM_INTERRUPTED);
> +}
> +
> +static int qcom_scm_call_smccc(struct device *dev,
> + struct qcom_scm_desc *desc, bool atomic)
> +{
> + int arglen = desc->arginfo & 0xf;
> + int i;
> + dma_addr_t args_phys = 0;
> + void *args_virt = NULL;
> + size_t alloc_len;
> + gfp_t flag = atomic ? GFP_ATOMIC : GFP_KERNEL;
> + struct arm_smccc_res res;
> + struct arm_smccc_args smc = {0};
> +
> + smc.a[0] = ARM_SMCCC_CALL_VAL(
> + atomic ? ARM_SMCCC_FAST_CALL : ARM_SMCCC_STD_CALL,
> + (qcom_smc_convention == SMC_CONVENTION_ARM_64) ?
> + ARM_SMCCC_SMC_64 :
> + ARM_SMCCC_SMC_32,
> + desc->owner,
> + SMCCC_FUNCNUM(desc->svc, desc->cmd));
> + smc.a[1] = desc->arginfo;
> + for (i = 0; i < SMCCC_N_REG_ARGS; i++)
> + smc.a[i + SMCCC_FIRST_REG_IDX] = desc->args[i];
> +
> + if (unlikely(arglen > SMCCC_N_REG_ARGS)) {
> + alloc_len = SMCCC_N_EXT_ARGS * sizeof(u64);
> + args_virt = kzalloc(PAGE_ALIGN(alloc_len), flag);
> +
> + if (!args_virt)
> + return -ENOMEM;
> +
> + if (qcom_smc_convention == SMC_CONVENTION_ARM_32) {
> + __le32 *args = args_virt;
> +
> + for (i = 0; i < SMCCC_N_EXT_ARGS; i++)
> + args[i] = cpu_to_le32(desc->args[i +
> + SMCCC_N_REG_ARGS - 1]);
> + } else {
> + __le64 *args = args_virt;
> +
> + for (i = 0; i < SMCCC_N_EXT_ARGS; i++)
> + args[i] = cpu_to_le64(desc->args[i +
> + SMCCC_N_REG_ARGS - 1]);
> + }
> +
> + args_phys = dma_map_single(dev, args_virt, alloc_len,
> + DMA_TO_DEVICE);
> +
> + if (dma_mapping_error(dev, args_phys)) {
> + kfree(args_virt);
> + return -ENOMEM;
> + }
> +
> + smc.a[SMCCC_LAST_REG_IDX] = args_phys;
> + }
> +
> + if (atomic) {
> + __qcom_scm_call_do_quirk(&smc, &res);
> + } else {
> + int retry_count = 0;
> +
> + do {
> + mutex_lock(&qcom_scm_lock);
> +
> + __qcom_scm_call_do_quirk(&smc, &res);
> +
> + mutex_unlock(&qcom_scm_lock);
> +
> + if (res.a0 == QCOM_SCM_V2_EBUSY) {
> + if (retry_count++ > QCOM_SCM_EBUSY_MAX_RETRY)
> + break;
> + msleep(QCOM_SCM_EBUSY_WAIT_MS);
> + }
> + } while (res.a0 == QCOM_SCM_V2_EBUSY);
> + }
> +
> + if (args_virt) {
> + dma_unmap_single(dev, args_phys, alloc_len, DMA_TO_DEVICE);
> + kfree(args_virt);
> + }
> +
> + desc->res[0] = res.a1;
> + desc->res[1] = res.a2;
> + desc->res[2] = res.a3;
> +
> + if (res.a0 < 0)
> + return qcom_scm_remap_error(res.a0);
> +
> + return 0;
> +}
> +
> +#define LEGACY_FUNCNUM(s, c) (((s) << 10) | ((c) & 0x3ff))
> +
> +/**
> + * struct legacy_command - one SCM command buffer
> + * @len: total available memory for command and response
> + * @buf_offset: start of command buffer
> + * @resp_hdr_offset: start of response buffer
> + * @id: command to be executed
> + * @buf: buffer returned from legacy_get_command_buffer()
> + *
> + * An SCM command is laid out in memory as follows:
> + *
> + * ------------------- <--- struct legacy_command
> + * | command header |
> + * ------------------- <--- legacy_get_command_buffer()
> + * | command buffer |
> + * ------------------- <--- struct legacy_response and
> + * | response header | legacy_command_to_response()
> + * ------------------- <--- legacy_get_response_buffer()
> + * | response buffer |
> + * -------------------
> + *
> + * There can be arbitrary padding between the headers and buffers so
> + * you should always use the appropriate qcom_scm_get_*_buffer() routines
> + * to access the buffers in a safe manner.
> + */
> +struct legacy_command {
> + __le32 len;
> + __le32 buf_offset;
> + __le32 resp_hdr_offset;
> + __le32 id;
> + __le32 buf[0];
> +};
> +
> +/**
> + * struct legacy_response - one SCM response buffer
> + * @len: total available memory for response
> + * @buf_offset: start of response data relative to start of legacy_response
> + * @is_complete: indicates if the command has finished processing
> + */
> +struct legacy_response {
> + __le32 len;
> + __le32 buf_offset;
> + __le32 is_complete;
> +};
> +
> +/**
> + * legacy_command_to_response() - Get a pointer to a legacy_response
> + * @cmd: command
> + *
> + * Returns a pointer to a response for a command.
> + */
> +static inline struct legacy_response *legacy_command_to_response(
> + const struct legacy_command *cmd)
> +{
> + return (void *)cmd + le32_to_cpu(cmd->resp_hdr_offset);
> +}
> +
> +/**
> + * legacy_get_command_buffer() - Get a pointer to a command buffer
> + * @cmd: command
> + *
> + * Returns a pointer to the command buffer of a command.
> + */
> +static inline void *legacy_get_command_buffer(const struct legacy_command *cmd)
> +{
> + return (void *)cmd->buf;
> +}
> +
> +/**
> + * legacy_get_response_buffer() - Get a pointer to a response buffer
> + * @rsp: response
> + *
> + * Returns a pointer to a response buffer of a response.
> + */
> +static inline void *legacy_get_response_buffer(const struct legacy_response *rsp)
> +{
> + return (void *)rsp + le32_to_cpu(rsp->buf_offset);
> +}
> +
> +static void __qcom_scm_call_do(const struct arm_smccc_args *smc,
> + struct arm_smccc_res *res)
> +{
> + do {
> + arm_smccc_smc(smc->a[0], smc->a[1], smc->a[2], smc->a[3],
> + smc->a[4], smc->a[5], smc->a[6], smc->a[7], res);
> + } while (res->a0 == QCOM_SCM_INTERRUPTED);
> +}
> +
> +/**
> + * qcom_scm_call_legacy() - Send an SCM command
> + * @dev: struct device
> + * @svc_id: service identifier
> + * @cmd_id: command identifier
> + * @cmd_buf: command buffer
> + * @cmd_len: length of the command buffer
> + * @resp_buf: response buffer
> + * @resp_len: length of the response buffer
> + *
> + * Sends a command to the SCM and waits for the command to finish processing.
> + *
> + * A note on cache maintenance:
> + * Note that any buffers that are expected to be accessed by the secure world
> + * must be flushed before invoking qcom_scm_call and invalidated in the cache
> + * immediately after qcom_scm_call returns. Cache maintenance on the command
> + * 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.
> + */
> +static int qcom_scm_call_legacy(struct device *dev, struct qcom_scm_desc *desc)
> +{
> + int arglen = desc->arginfo & 0xf;
> + int ret = 0, context_id;
> + size_t i;
> + struct legacy_command *cmd;
> + struct legacy_response *rsp;
> + struct arm_smccc_args smc = {0};
> + struct arm_smccc_res res;
> + const size_t cmd_len = arglen * sizeof(__le32);
> + const size_t resp_len = MAX_QCOM_SCM_RETS * sizeof(__le32);
> + size_t alloc_len = sizeof(*cmd) + cmd_len + sizeof(*rsp) + resp_len;
> + dma_addr_t cmd_phys;
> + __le32 *arg_buf;
> + __le32 *res_buf;
> +
> + cmd = kzalloc(PAGE_ALIGN(alloc_len), GFP_KERNEL);
> + if (!cmd)
> + return -ENOMEM;
> +
> + cmd->len = cpu_to_le32(alloc_len);
> + cmd->buf_offset = cpu_to_le32(sizeof(*cmd));
> + cmd->resp_hdr_offset = cpu_to_le32(sizeof(*cmd) + cmd_len);
> + cmd->id = cpu_to_le32(LEGACY_FUNCNUM(desc->svc, desc->cmd));
> +
> + arg_buf = legacy_get_command_buffer(cmd);
> + for (i = 0; i < arglen; i++)
> + arg_buf[i] = cpu_to_le32(desc->args[i]);
> +
> + rsp = legacy_command_to_response(cmd);
> +
> + cmd_phys = dma_map_single(dev, cmd, alloc_len, DMA_TO_DEVICE);
> + if (dma_mapping_error(dev, cmd_phys)) {
> + kfree(cmd);
> + return -ENOMEM;
> + }
> +
> + smc.a[0] = 1;
> + smc.a[1] = (unsigned long)&context_id;
> + smc.a[2] = cmd_phys;
> +
> + mutex_lock(&qcom_scm_lock);
> + __qcom_scm_call_do(&smc, &res);
> + if (res.a0 < 0)
> + ret = qcom_scm_remap_error(res.a0);
> + mutex_unlock(&qcom_scm_lock);
> + if (ret)
> + goto out;
> +
> + do {
> + dma_sync_single_for_cpu(dev, cmd_phys + sizeof(*cmd) + cmd_len,
> + sizeof(*rsp), DMA_FROM_DEVICE);
> + } while (!rsp->is_complete);
> +
> + dma_sync_single_for_cpu(dev, cmd_phys + sizeof(*cmd) + cmd_len +
> + le32_to_cpu(rsp->buf_offset),
> + resp_len, DMA_FROM_DEVICE);
> +
> + res_buf = legacy_get_response_buffer(rsp);
> + for (i = 0; i < MAX_QCOM_SCM_RETS; i++)
> + desc->res[i] = le32_to_cpu(res_buf[i]);
> +out:
> + dma_unmap_single(dev, cmd_phys, alloc_len, DMA_TO_DEVICE);
> + kfree(cmd);
> + return ret;
> +}
> +
> +#define LEGACY_ATOMIC_N_REG_ARGS 5
> +#define LEGACY_ATOMIC_FIRST_REG_IDX 2
> +#define LEGACY_CLASS_REGISTER (0x2 << 8)
> +#define LEGACY_MASK_IRQS BIT(5)
> +#define LEGACY_ATOMIC(svc, cmd, n) ((LEGACY_FUNCNUM(svc, cmd) << 12) | \
> + LEGACY_CLASS_REGISTER | \
> + LEGACY_MASK_IRQS | \
> + (n & 0xf))
> +
> +/**
> + * qcom_scm_call_atomic_legacy() - Send an atomic SCM command with up to
> + * 5 arguments and 3 return values
> + *
> + * This shall only be used with commands that are guaranteed to be
> + * uninterruptable, atomic and SMP safe.
> + */
> +static int qcom_scm_call_atomic_legacy(struct device *dev,
> + struct qcom_scm_desc *desc)
> +{
> + int context_id;
> + struct arm_smccc_args smc = {0};
> + struct arm_smccc_res res;
> + size_t i, arglen = desc->arginfo & 0xf;
> +
> + BUG_ON(arglen > LEGACY_ATOMIC_N_REG_ARGS);
> +
> + smc.a[0] = LEGACY_ATOMIC(desc->svc, desc->cmd, arglen);
> + smc.a[1] = (unsigned long)&context_id;
> +
> + for (i = 0; i < arglen; i++)
> + smc.a[i + LEGACY_ATOMIC_FIRST_REG_IDX] = desc->args[i];
> +
> + arm_smccc_smc(smc.a[0], smc.a[1], smc.a[2], smc.a[3],
> + smc.a[4], smc.a[5], smc.a[6], smc.a[7], &res);
> +
> + desc->res[0] = res.a1;
> + desc->res[1] = res.a2;
> + desc->res[2] = res.a3;
> +
> + return res.a0;
> +}
> +
> +/**
> + * 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, struct qcom_scm_desc *desc)
> +{
> + might_sleep();
> + switch (qcom_smc_convention) {
> + case SMC_CONVENTION_ARM_32:
> + case SMC_CONVENTION_ARM_64:
> + return qcom_scm_call_smccc(dev, desc, false);
> + case SMC_CONVENTION_LEGACY:
> + return qcom_scm_call_legacy(dev, desc);
> + 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, struct qcom_scm_desc *desc)
> +{
> + switch (qcom_smc_convention) {
> + case SMC_CONVENTION_ARM_32:
> + case SMC_CONVENTION_ARM_64:
> + return qcom_scm_call_smccc(dev, desc, true);
> + case SMC_CONVENTION_LEGACY:
> + return qcom_scm_call_atomic_legacy(dev, desc);
> + default:
> + pr_err("Unknown current SCM calling convention.\n");
> + return -EINVAL;
> + }
> +}
> +
> +#define QCOM_SCM_FLAG_COLDBOOT_CPU0 0x00
> +#define QCOM_SCM_FLAG_COLDBOOT_CPU1 0x01
> +#define QCOM_SCM_FLAG_COLDBOOT_CPU2 0x08
> +#define QCOM_SCM_FLAG_COLDBOOT_CPU3 0x20
> +
> +/**
> + * qcom_scm_set_cold_boot_addr() - Set the cold boot address for cpus
> + * @entry: Entry point function for the cpus
> + * @cpus: The cpumask of cpus that will use the entry point
> + *
> + * Set the cold boot address of the cpus. Any cpu outside the supported
> + * range would be removed from the cpu present mask.
> + */
> +int __qcom_scm_set_cold_boot_addr(struct device *dev, void *entry,
> + const cpumask_t *cpus)
> +{
> + int flags = 0;
> + int cpu;
> + int scm_cb_flags[] = {
> + QCOM_SCM_FLAG_COLDBOOT_CPU0,
> + QCOM_SCM_FLAG_COLDBOOT_CPU1,
> + QCOM_SCM_FLAG_COLDBOOT_CPU2,
> + QCOM_SCM_FLAG_COLDBOOT_CPU3,
> + };
> + struct qcom_scm_desc desc = {
> + .svc = QCOM_SCM_SVC_BOOT,
> + .cmd = QCOM_SCM_BOOT_SET_ADDR,
> + .owner = ARM_SMCCC_OWNER_SIP,
> + };
> +
> + if (!cpus || (cpus && cpumask_empty(cpus)))
> + return -EINVAL;
> +
> + for_each_cpu(cpu, cpus) {
> + if (cpu < ARRAY_SIZE(scm_cb_flags))
> + flags |= scm_cb_flags[cpu];
> + else
> + set_cpu_present(cpu, false);
> + }
> +
> + desc.args[0] = flags;
> + desc.args[1] = virt_to_phys(entry);
> + desc.arginfo = QCOM_SCM_ARGS(2);
> +
> + return qcom_scm_call_atomic(dev, &desc);
> +}
> +
> +#define QCOM_SCM_FLAG_WARMBOOT_CPU0 0x04
> +#define QCOM_SCM_FLAG_WARMBOOT_CPU1 0x02
> +#define QCOM_SCM_FLAG_WARMBOOT_CPU2 0x10
> +#define QCOM_SCM_FLAG_WARMBOOT_CPU3 0x40
> +
> +struct qcom_scm_entry {
> + int flag;
> + void *entry;
> +};
> +
> +static struct qcom_scm_entry qcom_scm_wb[] = {
> + { .flag = QCOM_SCM_FLAG_WARMBOOT_CPU0 },
> + { .flag = QCOM_SCM_FLAG_WARMBOOT_CPU1 },
> + { .flag = QCOM_SCM_FLAG_WARMBOOT_CPU2 },
> + { .flag = QCOM_SCM_FLAG_WARMBOOT_CPU3 },
> +};
> +
> +/**
> + * qcom_scm_set_warm_boot_addr() - Set the warm boot address for cpus
> + * @dev: Device pointer
> + * @entry: Entry point function for the cpus
> + * @cpus: The cpumask of cpus that will use the entry point
> + *
> + * Set the Linux entry point for the SCM to transfer control to when coming
> + * out of a power down. CPU power down may be executed on cpuidle or hotplug.
> + */
> +int __qcom_scm_set_warm_boot_addr(struct device *dev, void *entry,
> + const cpumask_t *cpus)
> +{
> + int ret;
> + int flags = 0;
> + int cpu;
> + struct qcom_scm_desc desc = {
> + .svc = QCOM_SCM_SVC_BOOT,
> + .cmd = QCOM_SCM_BOOT_SET_ADDR,
> + };
> +
> + /*
> + * Reassign only if we are switching from hotplug entry point
> + * to cpuidle entry point or vice versa.
> + */
> + for_each_cpu(cpu, cpus) {
> + if (entry == qcom_scm_wb[cpu].entry)
> + continue;
> + flags |= qcom_scm_wb[cpu].flag;
> + }
> +
> + /* No change in entry function */
> + if (!flags)
> + return 0;
> +
> + desc.args[0] = flags;
> + desc.args[1] = virt_to_phys(entry);
> + ret = qcom_scm_call(dev, &desc);
> + if (!ret) {
> + for_each_cpu(cpu, cpus)
> + qcom_scm_wb[cpu].entry = entry;
> + }
> +
> + return ret;
> +}
> +
> +/**
> + * qcom_scm_cpu_power_down() - Power down the cpu
> + * @flags - Flags to flush cache
> + *
> + * This is an end point to power down cpu. If there was a pending interrupt,
> + * the control would return from this function, otherwise, the cpu jumps to the
> + * warm boot entry point set for this cpu upon reset.
> + */
> +void __qcom_scm_cpu_power_down(struct device *dev, u32 flags)
> +{
> + struct qcom_scm_desc desc = {
> + .svc = QCOM_SCM_SVC_BOOT,
> + .cmd = QCOM_SCM_BOOT_TERMINATE_PC,
> + .args[0] = flags & QCOM_SCM_FLUSH_FLAG_MASK,
> + .arginfo = QCOM_SCM_ARGS(1),
> + .owner = ARM_SMCCC_OWNER_SIP,
> + };
> +
> + qcom_scm_call_atomic(dev, &desc);
> +}
> +
> +int __qcom_scm_set_remote_state(struct device *dev, u32 state, u32 id)
> +{
> + struct qcom_scm_desc desc = {
> + .svc = QCOM_SCM_SVC_BOOT,
> + .cmd = QCOM_SCM_BOOT_SET_REMOTE_STATE,
> + .owner = ARM_SMCCC_OWNER_SIP,
> + };
> + int ret;
> +
> + desc.args[0] = state;
> + desc.args[1] = id;
> + desc.arginfo = QCOM_SCM_ARGS(2);
> +
> + ret = qcom_scm_call(dev, &desc);
> +
> + return ret ? : desc.res[0];
> +}
> +
> +int __qcom_scm_set_dload_mode(struct device *dev, bool enable)
> +{
> + struct qcom_scm_desc desc = {
> + .svc = QCOM_SCM_SVC_BOOT,
> + .cmd = QCOM_SCM_BOOT_SET_DLOAD_MODE,
> + .owner = ARM_SMCCC_OWNER_SIP,
> + };
> +
> + desc.args[0] = QCOM_SCM_BOOT_SET_DLOAD_MODE;
> + desc.args[1] = enable ? QCOM_SCM_BOOT_SET_DLOAD_MODE : 0;
> + desc.arginfo = QCOM_SCM_ARGS(2);
> +
> + return qcom_scm_call_atomic(dev, &desc);
> +}
> +
> +bool __qcom_scm_pas_supported(struct device *dev, u32 peripheral)
> +{
> + int ret;
> + struct qcom_scm_desc desc = {
> + .svc = QCOM_SCM_SVC_PIL,
> + .cmd = QCOM_SCM_PIL_PAS_IS_SUPPORTED,
> + .owner = ARM_SMCCC_OWNER_SIP,
> + };
> +
> + desc.args[0] = peripheral;
> + desc.arginfo = QCOM_SCM_ARGS(1);
> +
> + ret = qcom_scm_call(dev, &desc);
> +
> + return ret ? false : !!desc.res[0];
> +}
> +
> +int __qcom_scm_pas_init_image(struct device *dev, u32 peripheral,
> + dma_addr_t metadata_phys)
> +{
> + int ret;
> + struct qcom_scm_desc desc = {
> + .svc = QCOM_SCM_SVC_PIL,
> + .cmd = QCOM_SCM_PIL_PAS_INIT_IMAGE,
> + .owner = ARM_SMCCC_OWNER_SIP,
> + };
> +
> + desc.args[0] = peripheral;
> + desc.args[1] = metadata_phys;
> + desc.arginfo = QCOM_SCM_ARGS(2, QCOM_SCM_VAL, QCOM_SCM_RW);
> +
> + ret = qcom_scm_call(dev, &desc);
> +
> + return ret ? : desc.res[0];
> +}
> +
> +int __qcom_scm_pas_mem_setup(struct device *dev, u32 peripheral,
> + phys_addr_t addr, phys_addr_t size)
> +{
> + int ret;
> + struct qcom_scm_desc desc = {
> + .svc = QCOM_SCM_SVC_PIL,
> + .cmd = QCOM_SCM_PIL_PAS_MEM_SETUP,
> + .owner = ARM_SMCCC_OWNER_SIP,
> + };
> +
> + desc.args[0] = peripheral;
> + desc.args[1] = addr;
> + desc.args[2] = size;
> + desc.arginfo = QCOM_SCM_ARGS(3);
> +
> + ret = qcom_scm_call(dev, &desc);
> +
> + return ret ? : desc.res[0];
> +}
> +
> +int __qcom_scm_pas_auth_and_reset(struct device *dev, u32 peripheral)
> +{
> + int ret;
> + struct qcom_scm_desc desc = {
> + .svc = QCOM_SCM_SVC_PIL,
> + .cmd = QCOM_SCM_PIL_PAS_AUTH_AND_RESET,
> + .owner = ARM_SMCCC_OWNER_SIP,
> + };
> +
> + desc.args[0] = peripheral;
> + desc.arginfo = QCOM_SCM_ARGS(1);
> +
> + ret = qcom_scm_call(dev, &desc);
> +
> + return ret ? : desc.res[0];
> +}
> +
> +int __qcom_scm_pas_shutdown(struct device *dev, u32 peripheral)
> +{
> + int ret;
> + struct qcom_scm_desc desc = {
> + .svc = QCOM_SCM_SVC_PIL,
> + .cmd = QCOM_SCM_PIL_PAS_SHUTDOWN,
> + .owner = ARM_SMCCC_OWNER_SIP,
> + };
> +
> + desc.args[0] = peripheral;
> + desc.arginfo = QCOM_SCM_ARGS(1);
> +
> + ret = qcom_scm_call(dev, &desc);
> +
> + return ret ? : desc.res[0];
> +}
> +
> +int __qcom_scm_pas_mss_reset(struct device *dev, bool reset)
> +{
> + struct qcom_scm_desc desc = {
> + .svc = QCOM_SCM_SVC_PIL,
> + .cmd = QCOM_SCM_PIL_PAS_MSS_RESET,
> + .owner = ARM_SMCCC_OWNER_SIP,
> + };
> + int ret;
> +
> + desc.args[0] = reset;
> + desc.args[1] = 0;
> + desc.arginfo = QCOM_SCM_ARGS(2);
> +
> + ret = qcom_scm_call(dev, &desc);
> +
> + return ret ? : desc.res[0];
> +}
> +
> +int __qcom_scm_io_readl(struct device *dev, phys_addr_t addr,
> + unsigned int *val)
> +{
> + struct qcom_scm_desc desc = {
> + .svc = QCOM_SCM_SVC_IO,
> + .cmd = QCOM_SCM_IO_READ,
> + .owner = ARM_SMCCC_OWNER_SIP,
> + };
> + int ret;
> +
> + desc.args[0] = addr;
> + desc.arginfo = QCOM_SCM_ARGS(1);
> +
> + ret = qcom_scm_call_atomic(dev, &desc);
> + if (ret >= 0)
> + *val = desc.res[0];
> +
> + return ret < 0 ? ret : 0;
> +}
> +
> +int __qcom_scm_io_writel(struct device *dev, phys_addr_t addr, unsigned int val)
> +{
> + struct qcom_scm_desc desc = {
> + .svc = QCOM_SCM_SVC_IO,
> + .cmd = QCOM_SCM_IO_WRITE,
> + .owner = ARM_SMCCC_OWNER_SIP,
> + };
> +
> + desc.args[0] = addr;
> + desc.args[1] = val;
> + desc.arginfo = QCOM_SCM_ARGS(2);
> +
> + return qcom_scm_call_atomic(dev, &desc);
> +}
> +
> +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,
> + };
> +
> + desc.arginfo = QCOM_SCM_ARGS(1);
> + switch (qcom_smc_convention) {
> + case SMC_CONVENTION_ARM_32:
> + case SMC_CONVENTION_ARM_64:
> + desc.args[0] = SMCCC_FUNCNUM(svc_id, cmd_id) |
> + (ARM_SMCCC_OWNER_SIP << ARM_SMCCC_OWNER_SHIFT);
> + break;
> + case SMC_CONVENTION_LEGACY:
> + desc.args[0] = LEGACY_FUNCNUM(svc_id, cmd_id);
> + break;
> + default:
> + pr_err("Unknown SMC convention being used\n");
> + return -EINVAL;
> + }
> +
> + ret = qcom_scm_call(dev, &desc);
> +
> + return ret ? : desc.res[0];
> +}
> +
> +int __qcom_scm_restore_sec_cfg(struct device *dev, u32 device_id, u32 spare)
> +{
> + struct qcom_scm_desc desc = {
> + .svc = QCOM_SCM_SVC_MP,
> + .cmd = QCOM_SCM_MP_RESTORE_SEC_CFG,
> + .owner = ARM_SMCCC_OWNER_SIP,
> + };
> + int ret;
> +
> + desc.args[0] = device_id;
> + desc.args[1] = spare;
> + desc.arginfo = QCOM_SCM_ARGS(2);
> +
> + ret = qcom_scm_call(dev, &desc);
> +
> + return ret ? : desc.res[0];
> +}
> +
> +int __qcom_scm_iommu_secure_ptbl_size(struct device *dev, u32 spare,
> + size_t *size)
> +{
> + struct qcom_scm_desc desc = {
> + .svc = QCOM_SCM_SVC_MP,
> + .cmd = QCOM_SCM_MP_IOMMU_SECURE_PTBL_SIZE,
> + .owner = ARM_SMCCC_OWNER_SIP,
> + };
> + int ret;
> +
> + desc.args[0] = spare;
> + desc.arginfo = QCOM_SCM_ARGS(1);
> +
> + ret = qcom_scm_call(dev, &desc);
> +
> + if (size)
> + *size = desc.res[0];
> +
> + return ret ? : desc.res[1];
> +}
> +
> +int __qcom_scm_iommu_secure_ptbl_init(struct device *dev, u64 addr, u32 size,
> + u32 spare)
> +{
> + struct qcom_scm_desc desc = {
> + .svc = QCOM_SCM_SVC_MP,
> + .cmd = QCOM_SCM_MP_IOMMU_SECURE_PTBL_INIT,
> + .owner = ARM_SMCCC_OWNER_SIP,
> + };
> + int ret;
> +
> + desc.args[0] = addr;
> + desc.args[1] = size;
> + desc.args[2] = spare;
> + desc.arginfo = QCOM_SCM_ARGS(3, QCOM_SCM_RW, QCOM_SCM_VAL,
> + QCOM_SCM_VAL);
> +
> + ret = qcom_scm_call(dev, &desc);
> +
> + /* the pg table has been initialized already, ignore the error */
> + if (ret == -EPERM)
> + ret = 0;
> +
> + return ret;
> +}
> +
> +int __qcom_scm_assign_mem(struct device *dev, phys_addr_t mem_region,
> + size_t mem_sz, phys_addr_t src, size_t src_sz,
> + phys_addr_t dest, size_t dest_sz)
> +{
> + int ret;
> + struct qcom_scm_desc desc = {
> + .svc = QCOM_SCM_SVC_MP,
> + .cmd = QCOM_SCM_MP_ASSIGN,
> + .owner = ARM_SMCCC_OWNER_SIP,
> + };
> +
> + desc.args[0] = mem_region;
> + desc.args[1] = mem_sz;
> + desc.args[2] = src;
> + desc.args[3] = src_sz;
> + desc.args[4] = dest;
> + desc.args[5] = dest_sz;
> + desc.args[6] = 0;
> +
> + desc.arginfo = QCOM_SCM_ARGS(7, QCOM_SCM_RO, QCOM_SCM_VAL,
> + QCOM_SCM_RO, QCOM_SCM_VAL, QCOM_SCM_RO,
> + QCOM_SCM_VAL, QCOM_SCM_VAL);
> +
> + ret = qcom_scm_call(dev, &desc);
> +
> + return ret ? : desc.res[0];
> +}
> +
> +int __qcom_scm_hdcp_req(struct device *dev, struct qcom_scm_hdcp_req *req,
> + u32 req_cnt, u32 *resp)
> +{
> + int ret;
> + struct qcom_scm_desc desc = {
> + .svc = QCOM_SCM_SVC_HDCP,
> + .cmd = QCOM_SCM_HDCP_INVOKE,
> + .owner = ARM_SMCCC_OWNER_SIP,
> + };
> +
> + if (req_cnt > QCOM_SCM_HDCP_MAX_REQ_CNT)
> + return -ERANGE;
> +
> + desc.args[0] = req[0].addr;
> + desc.args[1] = req[0].val;
> + desc.args[2] = req[1].addr;
> + desc.args[3] = req[1].val;
> + desc.args[4] = req[2].addr;
> + desc.args[5] = req[2].val;
> + desc.args[6] = req[3].addr;
> + desc.args[7] = req[3].val;
> + desc.args[8] = req[4].addr;
> + desc.args[9] = req[4].val;
> + desc.arginfo = QCOM_SCM_ARGS(10);
> +
> + ret = qcom_scm_call(dev, &desc);
> + *resp = desc.res[0];
> +
> + return ret;
> +}
> +
> +int __qcom_scm_qsmmu500_wait_safe_toggle(struct device *dev, bool en)
> +{
> + struct qcom_scm_desc desc = {
> + .svc = QCOM_SCM_SVC_SMMU_PROGRAM,
> + .cmd = QCOM_SCM_SMMU_CONFIG_ERRATA1,
> + .owner = ARM_SMCCC_OWNER_SIP,
> + };
> +
> + desc.args[0] = QCOM_SCM_SMMU_CONFIG_ERRATA1_CLIENT_ALL;
> + desc.args[1] = en;
> + desc.arginfo = QCOM_SCM_ARGS(2);
> +
> + return qcom_scm_call_atomic(dev, &desc);
> +}
> +
> +void __qcom_scm_init(void)
> +{
> + qcom_smc_convention = SMC_CONVENTION_LEGACY;
> + if (__qcom_scm_is_call_available(NULL, QCOM_SCM_SVC_INFO,
> + QCOM_SCM_INFO_IS_CALL_AVAIL) == 1)
> + goto out;
> +
> + qcom_smc_convention = SMC_CONVENTION_ARM_64;
> + if (__qcom_scm_is_call_available(NULL, QCOM_SCM_SVC_INFO,
> + QCOM_SCM_INFO_IS_CALL_AVAIL) == 1)
> + goto out;
> +
> + qcom_smc_convention = SMC_CONVENTION_ARM_32;
> + if (__qcom_scm_is_call_available(NULL, QCOM_SCM_SVC_INFO,
> + QCOM_SCM_INFO_IS_CALL_AVAIL) == 1)
> + goto out;
> +
> + qcom_smc_convention = SMC_CONVENTION_UNKNOWN;
> +out:
> + pr_debug("QCOM SCM SMC Convention: %d\n", qcom_smc_convention);
> +}
> --
> The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
> a Linux Foundation Collaborative Project
>

2019-11-08 04:37:43

by Vinod Koul

[permalink] [raw]
Subject: Re: [PATCH 04/17] firmware: qcom_scm: Remove unused qcom_scm_get_version

On 04-11-19, 17:27, Elliot Berman wrote:
> Remove unused qcom_scm_get_version.

Reviewed-by: Vinod Koul <[email protected]>

--
~Vinod

2019-11-08 06:05:12

by Vinod Koul

[permalink] [raw]
Subject: Re: [PATCH 05/17] firmware: qcom_scm-64: Move svc/cmd/owner into qcom_scm_desc

On 04-11-19, 17:27, Elliot Berman wrote:
> Service, command, and owner IDs are all part of qcom_scm_desc struct and
> have no special reason to be a function argument (or hard-coded in the
> case of owner). Moving them to be part of qcom_scm_desc struct improves
> readability.
>
> Signed-off-by: Elliot Berman <[email protected]>
> ---
> drivers/firmware/qcom_scm-64.c | 192 +++++++++++++++++++++++++----------------
> 1 file changed, 120 insertions(+), 72 deletions(-)
>
> diff --git a/drivers/firmware/qcom_scm-64.c b/drivers/firmware/qcom_scm-64.c
> index ead0b5f..76412a5 100644
> --- a/drivers/firmware/qcom_scm-64.c
> +++ b/drivers/firmware/qcom_scm-64.c
> @@ -46,8 +46,11 @@ enum qcom_scm_arg_types {
> * @res: The values returned by the secure syscall
> */
> struct qcom_scm_desc {
> + u32 svc;
> + u32 cmd;
> u32 arginfo;
> u64 args[MAX_QCOM_SCM_ARGS];
> + u32 owner;
> };
>
> static u64 qcom_smccc_convention = -1;
> @@ -62,14 +65,16 @@ static DEFINE_MUTEX(qcom_scm_lock);
> #define SMCCC_N_EXT_ARGS (MAX_QCOM_SCM_ARGS - SMCCC_N_REG_ARGS + 1)
>
> static void __qcom_scm_call_do_quirk(const struct qcom_scm_desc *desc,
> - struct arm_smccc_res *res, u32 fn_id,
> - u64 x5, u32 type)
> + struct arm_smccc_res *res, u64 x5, u32 type)
> {
> u64 cmd;
> struct arm_smccc_quirk quirk = { .id = ARM_SMCCC_QUIRK_QCOM_A6 };
>
> - cmd = ARM_SMCCC_CALL_VAL(type, qcom_smccc_convention,
> - ARM_SMCCC_OWNER_SIP, fn_id);
> + cmd = ARM_SMCCC_CALL_VAL(
> + type,
> + qcom_smccc_convention,
> + desc->owner,
> + SMCCC_FUNCNUM(desc->svc, desc->cmd));
>
> quirk.state.a6 = 0;
>
> @@ -85,22 +90,19 @@ static void __qcom_scm_call_do_quirk(const struct qcom_scm_desc *desc,
> }
>
> static void qcom_scm_call_do_smccc(const struct qcom_scm_desc *desc,
> - struct arm_smccc_res *res, u32 fn_id,
> - u64 x5, bool atomic)
> + struct arm_smccc_res *res, u64 x5, bool atomic)
> {
> int retry_count = 0;
>
> if (atomic) {
> - __qcom_scm_call_do_quirk(desc, res, fn_id, x5,
> - ARM_SMCCC_FAST_CALL);
> + __qcom_scm_call_do_quirk(desc, res, x5, ARM_SMCCC_FAST_CALL);
> return;
> }
>
> do {
> mutex_lock(&qcom_scm_lock);
>
> - __qcom_scm_call_do_quirk(desc, res, fn_id, x5,
> - ARM_SMCCC_STD_CALL);
> + __qcom_scm_call_do_quirk(desc, res, x5, ARM_SMCCC_STD_CALL);
>
> mutex_unlock(&qcom_scm_lock);
>
> @@ -112,13 +114,12 @@ static void qcom_scm_call_do_smccc(const struct qcom_scm_desc *desc,
> } while (res->a0 == QCOM_SCM_V2_EBUSY);
> }
>
> -static int ___qcom_scm_call_smccc(struct device *dev, u32 svc_id, u32 cmd_id,
> +static int ___qcom_scm_call_smccc(struct device *dev,
> const struct qcom_scm_desc *desc,
> struct arm_smccc_res *res, bool atomic)
> {
> int arglen = desc->arginfo & 0xf;
> int i;
> - u32 fn_id = SMCCC_FUNCNUM(svc_id, cmd_id);
> u64 x5 = desc->args[SMCCC_N_REG_ARGS - 1];
> dma_addr_t args_phys = 0;
> void *args_virt = NULL;
> @@ -157,7 +158,7 @@ static int ___qcom_scm_call_smccc(struct device *dev, u32 svc_id, u32 cmd_id,
> x5 = args_phys;
> }
>
> - qcom_scm_call_do_smccc(desc, res, fn_id, x5, atomic);
> + qcom_scm_call_do_smccc(desc, res, x5, atomic);
>
> if (args_virt) {
> dma_unmap_single(dev, args_phys, alloc_len, DMA_TO_DEVICE);
> @@ -180,12 +181,11 @@ static int ___qcom_scm_call_smccc(struct device *dev, u32 svc_id, u32 cmd_id,
> * 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, u32 svc_id, u32 cmd_id,
> - const struct qcom_scm_desc *desc,
> +static int qcom_scm_call(struct device *dev, const struct qcom_scm_desc *desc,
> struct arm_smccc_res *res)
> {
> might_sleep();
> - return ___qcom_scm_call_smccc(dev, svc_id, cmd_id, desc, res, false);
> + return ___qcom_scm_call_smccc(dev, desc, res, false);
> }
>
> /**
> @@ -199,11 +199,11 @@ static int qcom_scm_call(struct device *dev, u32 svc_id, u32 cmd_id,
> * 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, u32 svc_id, u32 cmd_id,
> +static int qcom_scm_call_atomic(struct device *dev,
> const struct qcom_scm_desc *desc,
> struct arm_smccc_res *res)
> {
> - return ___qcom_scm_call_smccc(dev, svc_id, cmd_id, desc, res, true);
> + return ___qcom_scm_call_smccc(dev, desc, res, true);
> }
>
> /**
> @@ -248,7 +248,11 @@ void __qcom_scm_cpu_power_down(u32 flags)
>
> int __qcom_scm_set_remote_state(struct device *dev, u32 state, u32 id)
> {
> - struct qcom_scm_desc desc = {0};
> + struct qcom_scm_desc desc = {
> + .svc = QCOM_SCM_SVC_BOOT,
> + .cmd = QCOM_SCM_BOOT_SET_REMOTE_STATE,
> + .owner = ARM_SMCCC_OWNER_SIP,

Does this not leave some fields of desc uninitialized? Would it make
sense to do memset here first and then initialize. And since this
pattern seems used repeatedly, why not do:

struct qcom_scm_desc desc;
...
ACOM_INIT_SCM_DESC(desc, QCOM_SCM_SVC_BOOT,
QCOM_SCM_BOOT_SET_REMOTE_STATE,
ARM_SMCCC_OWNER_SIP);

Where:

#define ACOM_INIT_SCM_DESC(_desc, arg1, arg2, arg3) \
{ \
memset(_desc, 0, sizeof(*_desc)); \
desc->svc = arg1; \
desc->cmd = arg2; \
desc->wner = arg3; \
}

Or a function to do so...

--
~Vinod

2019-11-08 06:13:05

by Vinod Koul

[permalink] [raw]
Subject: Re: [PATCH 06/17] firmware: qcom_scm-64: Add SCM results to descriptor

On 04-11-19, 17:27, Elliot Berman wrote:
> Remove knowledge of arm_smccc_res struct from client wrappers so that
> client wrappers only work QCOM SCM data structures. SCM calls may have
> up to 3 arguments, so qcom_scm_call_smccc is responsible now for filling
> those 3 arguments accordingly.
>
> Signed-off-by: Elliot Berman <[email protected]>
> ---
> drivers/firmware/qcom_scm-64.c | 105 ++++++++++++++++++-----------------------
> 1 file changed, 45 insertions(+), 60 deletions(-)
>
> diff --git a/drivers/firmware/qcom_scm-64.c b/drivers/firmware/qcom_scm-64.c
> index 76412a5..f6536fa 100644
> --- a/drivers/firmware/qcom_scm-64.c
> +++ b/drivers/firmware/qcom_scm-64.c
> @@ -50,6 +50,7 @@ struct qcom_scm_desc {
> u32 cmd;
> u32 arginfo;
> u64 args[MAX_QCOM_SCM_ARGS];
> + u64 res[MAX_QCOM_SCM_RETS];
> u32 owner;
> };
>
> @@ -115,8 +116,7 @@ static void qcom_scm_call_do_smccc(const struct qcom_scm_desc *desc,
> }
>
> static int ___qcom_scm_call_smccc(struct device *dev,
> - const struct qcom_scm_desc *desc,
> - struct arm_smccc_res *res, bool atomic)
> + struct qcom_scm_desc *desc, bool atomic)
> {
> int arglen = desc->arginfo & 0xf;
> int i;
> @@ -125,6 +125,7 @@ static int ___qcom_scm_call_smccc(struct device *dev,
> void *args_virt = NULL;
> size_t alloc_len;
> gfp_t flag = atomic ? GFP_ATOMIC : GFP_KERNEL;
> + struct arm_smccc_res res;
>
> if (unlikely(arglen > SMCCC_N_REG_ARGS)) {
> alloc_len = SMCCC_N_EXT_ARGS * sizeof(u64);
> @@ -158,15 +159,19 @@ static int ___qcom_scm_call_smccc(struct device *dev,
> x5 = args_phys;
> }
>
> - qcom_scm_call_do_smccc(desc, res, x5, atomic);
> + qcom_scm_call_do_smccc(desc, &res, x5, atomic);
>
> if (args_virt) {
> dma_unmap_single(dev, args_phys, alloc_len, DMA_TO_DEVICE);
> kfree(args_virt);
> }
>
> - if (res->a0 < 0)
> - return qcom_scm_remap_error(res->a0);
> + desc->res[0] = res.a1;
> + desc->res[1] = res.a2;
> + desc->res[2] = res.a3;

res represents result, so can we rename this here and in qcom_scm_desc
as result, somehow I kept on reading this as res and got confused ;/ or
maybe it is just me!

--
~Vinod

2019-11-08 22:05:04

by Bjorn Andersson

[permalink] [raw]
Subject: Re: [PATCH 03/17] firmware: qcom_scm: Order functions, definitions by service/command

On Mon 04 Nov 17:27 PST 2019, Elliot Berman wrote:

> Definitions throughout qcom_scm are loosely grouped and loosely ordered.
> Sort all the functions/definitions by service ID/command ID to improve
> sanity when needing to add new functionality to this driver.
>
> Signed-off-by: Elliot Berman <[email protected]>
> ---
> drivers/firmware/qcom_scm-32.c | 104 +++++++++----------

Given this some more thought. I think you should try to postpone the
cleanup/make-tidy pieces until the end of the series; in particular all
of -32.c is going to be dropped at the end anyways.

And if you inline the -64 wrappers into qcom_scm.c per my request most
of those functions will be gone as well.

Regards,
Bjorn

> drivers/firmware/qcom_scm-64.c | 192 +++++++++++++++++------------------
> drivers/firmware/qcom_scm.c | 224 ++++++++++++++++++++---------------------
> drivers/firmware/qcom_scm.h | 107 ++++++++++----------
> include/linux/qcom_scm.h | 72 ++++++-------
> 5 files changed, 350 insertions(+), 349 deletions(-)
>
> diff --git a/drivers/firmware/qcom_scm-32.c b/drivers/firmware/qcom_scm-32.c
> index 87b520f..b09fddf 100644
> --- a/drivers/firmware/qcom_scm-32.c
> +++ b/drivers/firmware/qcom_scm-32.c
> @@ -419,33 +419,28 @@ void __qcom_scm_cpu_power_down(u32 flags)
> flags & QCOM_SCM_FLUSH_FLAG_MASK);
> }
>
> -int __qcom_scm_is_call_available(struct device *dev, u32 svc_id, u32 cmd_id)
> +int __qcom_scm_set_remote_state(struct device *dev, u32 state, u32 id)
> {
> + struct {
> + __le32 state;
> + __le32 id;
> + } req;
> + __le32 scm_ret = 0;
> int ret;
> - __le32 svc_cmd = cpu_to_le32((svc_id << 10) | cmd_id);
> - __le32 ret_val = 0;
> -
> - ret = qcom_scm_call(dev, QCOM_SCM_SVC_INFO, QCOM_SCM_INFO_IS_CALL_AVAIL,
> - &svc_cmd, sizeof(svc_cmd), &ret_val,
> - sizeof(ret_val));
> - if (ret)
> - return ret;
>
> - return le32_to_cpu(ret_val);
> -}
> + req.state = cpu_to_le32(state);
> + req.id = cpu_to_le32(id);
>
> -int __qcom_scm_hdcp_req(struct device *dev, struct qcom_scm_hdcp_req *req,
> - u32 req_cnt, u32 *resp)
> -{
> - if (req_cnt > QCOM_SCM_HDCP_MAX_REQ_CNT)
> - return -ERANGE;
> + ret = qcom_scm_call(dev, QCOM_SCM_SVC_BOOT, QCOM_SCM_BOOT_SET_REMOTE_STATE,
> + &req, sizeof(req), &scm_ret, sizeof(scm_ret));
>
> - return qcom_scm_call(dev, QCOM_SCM_SVC_HDCP, QCOM_SCM_HDCP_INVOKE,
> - req, req_cnt * sizeof(*req), resp, sizeof(*resp));
> + return ret ? : le32_to_cpu(scm_ret);
> }
>
> -void __qcom_scm_init(void)
> +int __qcom_scm_set_dload_mode(struct device *dev, bool enable)
> {
> + return qcom_scm_call_atomic2(QCOM_SCM_SVC_BOOT, QCOM_SCM_BOOT_SET_DLOAD_MODE,
> + enable ? QCOM_SCM_BOOT_SET_DLOAD_MODE : 0, 0);
> }
>
> bool __qcom_scm_pas_supported(struct device *dev, u32 peripheral)
> @@ -550,35 +545,37 @@ int __qcom_scm_pas_mss_reset(struct device *dev, bool reset)
> return ret ? : le32_to_cpu(out);
> }
>
> -int __qcom_scm_set_dload_mode(struct device *dev, bool enable)
> -{
> - return qcom_scm_call_atomic2(QCOM_SCM_SVC_BOOT, QCOM_SCM_BOOT_SET_DLOAD_MODE,
> - enable ? QCOM_SCM_BOOT_SET_DLOAD_MODE : 0, 0);
> -}
> -
> -int __qcom_scm_set_remote_state(struct device *dev, u32 state, u32 id)
> +int __qcom_scm_io_readl(struct device *dev, phys_addr_t addr,
> + unsigned int *val)
> {
> - struct {
> - __le32 state;
> - __le32 id;
> - } req;
> - __le32 scm_ret = 0;
> int ret;
>
> - req.state = cpu_to_le32(state);
> - req.id = cpu_to_le32(id);
> + ret = qcom_scm_call_atomic1(QCOM_SCM_SVC_IO, QCOM_SCM_IO_READ, addr);
> + if (ret >= 0)
> + *val = ret;
>
> - ret = qcom_scm_call(dev, QCOM_SCM_SVC_BOOT, QCOM_SCM_BOOT_SET_REMOTE_STATE,
> - &req, sizeof(req), &scm_ret, sizeof(scm_ret));
> + return ret < 0 ? ret : 0;
> +}
>
> - return ret ? : le32_to_cpu(scm_ret);
> +int __qcom_scm_io_writel(struct device *dev, phys_addr_t addr, unsigned int val)
> +{
> + return qcom_scm_call_atomic2(QCOM_SCM_SVC_IO, QCOM_SCM_IO_WRITE,
> + addr, val);
> }
>
> -int __qcom_scm_assign_mem(struct device *dev, phys_addr_t mem_region,
> - size_t mem_sz, phys_addr_t src, size_t src_sz,
> - phys_addr_t dest, size_t dest_sz)
> +int __qcom_scm_is_call_available(struct device *dev, u32 svc_id, u32 cmd_id)
> {
> - return -ENODEV;
> + int ret;
> + __le32 svc_cmd = cpu_to_le32((svc_id << 10) | cmd_id);
> + __le32 ret_val = 0;
> +
> + ret = qcom_scm_call(dev, QCOM_SCM_SVC_INFO, QCOM_SCM_INFO_IS_CALL_AVAIL,
> + &svc_cmd, sizeof(svc_cmd), &ret_val,
> + sizeof(ret_val));
> + if (ret)
> + return ret;
> +
> + return le32_to_cpu(ret_val);
> }
>
> int __qcom_scm_restore_sec_cfg(struct device *dev, u32 device_id,
> @@ -599,25 +596,28 @@ int __qcom_scm_iommu_secure_ptbl_init(struct device *dev, u64 addr, u32 size,
> return -ENODEV;
> }
>
> -int __qcom_scm_io_readl(struct device *dev, phys_addr_t addr,
> - unsigned int *val)
> +int __qcom_scm_assign_mem(struct device *dev, phys_addr_t mem_region,
> + size_t mem_sz, phys_addr_t src, size_t src_sz,
> + phys_addr_t dest, size_t dest_sz)
> {
> - int ret;
> -
> - ret = qcom_scm_call_atomic1(QCOM_SCM_SVC_IO, QCOM_SCM_IO_READ, addr);
> - if (ret >= 0)
> - *val = ret;
> -
> - return ret < 0 ? ret : 0;
> + return -ENODEV;
> }
>
> -int __qcom_scm_io_writel(struct device *dev, phys_addr_t addr, unsigned int val)
> +int __qcom_scm_hdcp_req(struct device *dev, struct qcom_scm_hdcp_req *req,
> + u32 req_cnt, u32 *resp)
> {
> - return qcom_scm_call_atomic2(QCOM_SCM_SVC_IO, QCOM_SCM_IO_WRITE,
> - addr, val);
> + if (req_cnt > QCOM_SCM_HDCP_MAX_REQ_CNT)
> + return -ERANGE;
> +
> + return qcom_scm_call(dev, QCOM_SCM_SVC_HDCP, QCOM_SCM_HDCP_INVOKE,
> + req, req_cnt * sizeof(*req), resp, sizeof(*resp));
> }
>
> int __qcom_scm_qsmmu500_wait_safe_toggle(struct device *dev, bool enable)
> {
> return -ENODEV;
> }
> +
> +void __qcom_scm_init(void)
> +{
> +}
> \ No newline at end of file
> diff --git a/drivers/firmware/qcom_scm-64.c b/drivers/firmware/qcom_scm-64.c
> index f0b4853..ead0b5f 100644
> --- a/drivers/firmware/qcom_scm-64.c
> +++ b/drivers/firmware/qcom_scm-64.c
> @@ -246,68 +246,33 @@ void __qcom_scm_cpu_power_down(u32 flags)
> {
> }
>
> -int __qcom_scm_is_call_available(struct device *dev, u32 svc_id, u32 cmd_id)
> +int __qcom_scm_set_remote_state(struct device *dev, u32 state, u32 id)
> {
> - int ret;
> struct qcom_scm_desc desc = {0};
> struct arm_smccc_res res;
> + int ret;
>
> - desc.arginfo = QCOM_SCM_ARGS(1);
> - desc.args[0] = SMCCC_FUNCNUM(svc_id, cmd_id) |
> - (ARM_SMCCC_OWNER_SIP << ARM_SMCCC_OWNER_SHIFT);
> + desc.args[0] = state;
> + desc.args[1] = id;
> + desc.arginfo = QCOM_SCM_ARGS(2);
>
> - ret = qcom_scm_call(dev, QCOM_SCM_SVC_INFO, QCOM_SCM_INFO_IS_CALL_AVAIL,
> + ret = qcom_scm_call(dev, QCOM_SCM_SVC_BOOT, QCOM_SCM_BOOT_SET_REMOTE_STATE,
> &desc, &res);
>
> return ret ? : res.a1;
> }
>
> -int __qcom_scm_hdcp_req(struct device *dev, struct qcom_scm_hdcp_req *req,
> - u32 req_cnt, u32 *resp)
> +int __qcom_scm_set_dload_mode(struct device *dev, bool enable)
> {
> - int ret;
> struct qcom_scm_desc desc = {0};
> struct arm_smccc_res res;
>
> - if (req_cnt > QCOM_SCM_HDCP_MAX_REQ_CNT)
> - return -ERANGE;
> -
> - desc.args[0] = req[0].addr;
> - desc.args[1] = req[0].val;
> - desc.args[2] = req[1].addr;
> - desc.args[3] = req[1].val;
> - desc.args[4] = req[2].addr;
> - desc.args[5] = req[2].val;
> - desc.args[6] = req[3].addr;
> - desc.args[7] = req[3].val;
> - desc.args[8] = req[4].addr;
> - desc.args[9] = req[4].val;
> - desc.arginfo = QCOM_SCM_ARGS(10);
> -
> - ret = qcom_scm_call(dev, QCOM_SCM_SVC_HDCP, QCOM_SCM_HDCP_INVOKE, &desc,
> - &res);
> - *resp = res.a1;
> -
> - return ret;
> -}
> -
> -void __qcom_scm_init(void)
> -{
> - u64 cmd;
> - struct arm_smccc_res res;
> - u32 function = SMCCC_FUNCNUM(QCOM_SCM_SVC_INFO, QCOM_SCM_INFO_IS_CALL_AVAIL);
> -
> - /* First try a SMC64 call */
> - cmd = ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, ARM_SMCCC_SMC_64,
> - ARM_SMCCC_OWNER_SIP, function);
> -
> - arm_smccc_smc(cmd, QCOM_SCM_ARGS(1), cmd & (~BIT(ARM_SMCCC_TYPE_SHIFT)),
> - 0, 0, 0, 0, 0, &res);
> + desc.args[0] = QCOM_SCM_BOOT_SET_DLOAD_MODE;
> + desc.args[1] = enable ? QCOM_SCM_BOOT_SET_DLOAD_MODE : 0;
> + desc.arginfo = QCOM_SCM_ARGS(2);
>
> - if (!res.a0 && res.a1)
> - qcom_smccc_convention = ARM_SMCCC_SMC_64;
> - else
> - qcom_smccc_convention = ARM_SMCCC_SMC_32;
> + return qcom_scm_call(dev, QCOM_SCM_SVC_BOOT, QCOM_SCM_BOOT_SET_DLOAD_MODE,
> + &desc, &res);
> }
>
> bool __qcom_scm_pas_supported(struct device *dev, u32 peripheral)
> @@ -408,44 +373,48 @@ int __qcom_scm_pas_mss_reset(struct device *dev, bool reset)
> return ret ? : res.a1;
> }
>
> -int __qcom_scm_set_remote_state(struct device *dev, u32 state, u32 id)
> +int __qcom_scm_io_readl(struct device *dev, phys_addr_t addr,
> + unsigned int *val)
> {
> struct qcom_scm_desc desc = {0};
> struct arm_smccc_res res;
> int ret;
>
> - desc.args[0] = state;
> - desc.args[1] = id;
> - desc.arginfo = QCOM_SCM_ARGS(2);
> + desc.args[0] = addr;
> + desc.arginfo = QCOM_SCM_ARGS(1);
>
> - ret = qcom_scm_call(dev, QCOM_SCM_SVC_BOOT, QCOM_SCM_BOOT_SET_REMOTE_STATE,
> + ret = qcom_scm_call(dev, QCOM_SCM_SVC_IO, QCOM_SCM_IO_READ,
> &desc, &res);
> + if (ret >= 0)
> + *val = res.a1;
>
> - return ret ? : res.a1;
> + return ret < 0 ? ret : 0;
> }
>
> -int __qcom_scm_assign_mem(struct device *dev, phys_addr_t mem_region,
> - size_t mem_sz, phys_addr_t src, size_t src_sz,
> - phys_addr_t dest, size_t dest_sz)
> +int __qcom_scm_io_writel(struct device *dev, phys_addr_t addr, unsigned int val)
> {
> - int ret;
> struct qcom_scm_desc desc = {0};
> struct arm_smccc_res res;
>
> - desc.args[0] = mem_region;
> - desc.args[1] = mem_sz;
> - desc.args[2] = src;
> - desc.args[3] = src_sz;
> - desc.args[4] = dest;
> - desc.args[5] = dest_sz;
> - desc.args[6] = 0;
> + desc.args[0] = addr;
> + desc.args[1] = val;
> + desc.arginfo = QCOM_SCM_ARGS(2);
>
> - desc.arginfo = QCOM_SCM_ARGS(7, QCOM_SCM_RO, QCOM_SCM_VAL,
> - QCOM_SCM_RO, QCOM_SCM_VAL, QCOM_SCM_RO,
> - QCOM_SCM_VAL, QCOM_SCM_VAL);
> + return qcom_scm_call(dev, QCOM_SCM_SVC_IO, QCOM_SCM_IO_WRITE,
> + &desc, &res);
> +}
>
> - ret = qcom_scm_call(dev, QCOM_SCM_SVC_MP,
> - QCOM_SCM_MP_ASSIGN,
> +int __qcom_scm_is_call_available(struct device *dev, u32 svc_id, u32 cmd_id)
> +{
> + int ret;
> + struct qcom_scm_desc desc = {0};
> + struct arm_smccc_res res;
> +
> + desc.arginfo = QCOM_SCM_ARGS(1);
> + desc.args[0] = SMCCC_FUNCNUM(svc_id, cmd_id) |
> + (ARM_SMCCC_OWNER_SIP << ARM_SMCCC_OWNER_SHIFT);
> +
> + ret = qcom_scm_call(dev, QCOM_SCM_SVC_INFO, QCOM_SCM_INFO_IS_CALL_AVAIL,
> &desc, &res);
>
> return ret ? : res.a1;
> @@ -509,48 +478,60 @@ int __qcom_scm_iommu_secure_ptbl_init(struct device *dev, u64 addr, u32 size,
> return ret;
> }
>
> -int __qcom_scm_set_dload_mode(struct device *dev, bool enable)
> +int __qcom_scm_assign_mem(struct device *dev, phys_addr_t mem_region,
> + size_t mem_sz, phys_addr_t src, size_t src_sz,
> + phys_addr_t dest, size_t dest_sz)
> {
> + int ret;
> struct qcom_scm_desc desc = {0};
> struct arm_smccc_res res;
>
> - desc.args[0] = QCOM_SCM_BOOT_SET_DLOAD_MODE;
> - desc.args[1] = enable ? QCOM_SCM_BOOT_SET_DLOAD_MODE : 0;
> - desc.arginfo = QCOM_SCM_ARGS(2);
> -
> - return qcom_scm_call(dev, QCOM_SCM_SVC_BOOT, QCOM_SCM_BOOT_SET_DLOAD_MODE,
> - &desc, &res);
> -}
> -
> -int __qcom_scm_io_readl(struct device *dev, phys_addr_t addr,
> - unsigned int *val)
> -{
> - struct qcom_scm_desc desc = {0};
> - struct arm_smccc_res res;
> - int ret;
> + desc.args[0] = mem_region;
> + desc.args[1] = mem_sz;
> + desc.args[2] = src;
> + desc.args[3] = src_sz;
> + desc.args[4] = dest;
> + desc.args[5] = dest_sz;
> + desc.args[6] = 0;
>
> - desc.args[0] = addr;
> - desc.arginfo = QCOM_SCM_ARGS(1);
> + desc.arginfo = QCOM_SCM_ARGS(7, QCOM_SCM_RO, QCOM_SCM_VAL,
> + QCOM_SCM_RO, QCOM_SCM_VAL, QCOM_SCM_RO,
> + QCOM_SCM_VAL, QCOM_SCM_VAL);
>
> - ret = qcom_scm_call(dev, QCOM_SCM_SVC_IO, QCOM_SCM_IO_READ,
> + ret = qcom_scm_call(dev, QCOM_SCM_SVC_MP,
> + QCOM_SCM_MP_ASSIGN,
> &desc, &res);
> - if (ret >= 0)
> - *val = res.a1;
>
> - return ret < 0 ? ret : 0;
> + return ret ? : res.a1;
> }
>
> -int __qcom_scm_io_writel(struct device *dev, phys_addr_t addr, unsigned int val)
> +int __qcom_scm_hdcp_req(struct device *dev, struct qcom_scm_hdcp_req *req,
> + u32 req_cnt, u32 *resp)
> {
> + int ret;
> struct qcom_scm_desc desc = {0};
> struct arm_smccc_res res;
>
> - desc.args[0] = addr;
> - desc.args[1] = val;
> - desc.arginfo = QCOM_SCM_ARGS(2);
> + if (req_cnt > QCOM_SCM_HDCP_MAX_REQ_CNT)
> + return -ERANGE;
>
> - return qcom_scm_call(dev, QCOM_SCM_SVC_IO, QCOM_SCM_IO_WRITE,
> - &desc, &res);
> + desc.args[0] = req[0].addr;
> + desc.args[1] = req[0].val;
> + desc.args[2] = req[1].addr;
> + desc.args[3] = req[1].val;
> + desc.args[4] = req[2].addr;
> + desc.args[5] = req[2].val;
> + desc.args[6] = req[3].addr;
> + desc.args[7] = req[3].val;
> + desc.args[8] = req[4].addr;
> + desc.args[9] = req[4].val;
> + desc.arginfo = QCOM_SCM_ARGS(10);
> +
> + ret = qcom_scm_call(dev, QCOM_SCM_SVC_HDCP, QCOM_SCM_HDCP_INVOKE, &desc,
> + &res);
> + *resp = res.a1;
> +
> + return ret;
> }
>
> int __qcom_scm_qsmmu500_wait_safe_toggle(struct device *dev, bool en)
> @@ -565,3 +546,22 @@ int __qcom_scm_qsmmu500_wait_safe_toggle(struct device *dev, bool en)
> return qcom_scm_call_atomic(dev, QCOM_SCM_SVC_SMMU_PROGRAM,
> QCOM_SCM_SMMU_CONFIG_ERRATA1, &desc, &res);
> }
> +
> +void __qcom_scm_init(void)
> +{
> + u64 cmd;
> + struct arm_smccc_res res;
> + u32 function = SMCCC_FUNCNUM(QCOM_SCM_SVC_INFO, QCOM_SCM_INFO_IS_CALL_AVAIL);
> +
> + /* First try a SMC64 call */
> + cmd = ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, ARM_SMCCC_SMC_64,
> + ARM_SMCCC_OWNER_SIP, function);
> +
> + arm_smccc_smc(cmd, QCOM_SCM_ARGS(1), cmd & (~BIT(ARM_SMCCC_TYPE_SHIFT)),
> + 0, 0, 0, 0, 0, &res);
> +
> + if (!res.a0 && res.a1)
> + qcom_smccc_convention = ARM_SMCCC_SMC_64;
> + else
> + qcom_smccc_convention = ARM_SMCCC_SMC_32;
> +}
> diff --git a/drivers/firmware/qcom_scm.c b/drivers/firmware/qcom_scm.c
> index 450d6d6..83fc049 100644
> --- a/drivers/firmware/qcom_scm.c
> +++ b/drivers/firmware/qcom_scm.c
> @@ -127,47 +127,33 @@ void qcom_scm_cpu_power_down(u32 flags)
> }
> EXPORT_SYMBOL(qcom_scm_cpu_power_down);
>
> -/**
> - * qcom_scm_hdcp_available() - Check if secure environment supports HDCP.
> - *
> - * Return true if HDCP is supported, false if not.
> - */
> -bool qcom_scm_hdcp_available(void)
> +int qcom_scm_set_remote_state(u32 state, u32 id)
> {
> - int ret = qcom_scm_clk_enable();
> -
> - if (ret)
> - return ret;
> -
> - ret = __qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_HDCP,
> - QCOM_SCM_HDCP_INVOKE);
> -
> - qcom_scm_clk_disable();
> -
> - return ret > 0 ? true : false;
> + return __qcom_scm_set_remote_state(__scm->dev, state, id);
> }
> -EXPORT_SYMBOL(qcom_scm_hdcp_available);
> +EXPORT_SYMBOL(qcom_scm_set_remote_state);
>
> -/**
> - * qcom_scm_hdcp_req() - Send HDCP request.
> - * @req: HDCP request array
> - * @req_cnt: HDCP request array count
> - * @resp: response buffer passed to SCM
> - *
> - * Write HDCP register(s) through SCM.
> - */
> -int qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt, u32 *resp)
> +static void qcom_scm_set_download_mode(bool enable)
> {
> - int ret = qcom_scm_clk_enable();
> + bool avail;
> + int ret = 0;
>
> - if (ret)
> - return ret;
> + avail = __qcom_scm_is_call_available(__scm->dev,
> + QCOM_SCM_SVC_BOOT,
> + QCOM_SCM_BOOT_SET_DLOAD_MODE);
> + if (avail) {
> + ret = __qcom_scm_set_dload_mode(__scm->dev, enable);
> + } else if (__scm->dload_mode_addr) {
> + ret = __qcom_scm_io_writel(__scm->dev, __scm->dload_mode_addr,
> + enable ? QCOM_SCM_BOOT_SET_DLOAD_MODE : 0);
> + } else {
> + dev_err(__scm->dev,
> + "No available mechanism for setting download mode\n");
> + }
>
> - ret = __qcom_scm_hdcp_req(__scm->dev, req, req_cnt, resp);
> - qcom_scm_clk_disable();
> - return ret;
> + if (ret)
> + dev_err(__scm->dev, "failed to set download mode: %d\n", ret);
> }
> -EXPORT_SYMBOL(qcom_scm_hdcp_req);
>
> /**
> * qcom_scm_pas_supported() - Check if the peripheral authentication service is
> @@ -325,30 +311,6 @@ static const struct reset_control_ops qcom_scm_pas_reset_ops = {
> .deassert = qcom_scm_pas_reset_deassert,
> };
>
> -int qcom_scm_restore_sec_cfg(u32 device_id, u32 spare)
> -{
> - return __qcom_scm_restore_sec_cfg(__scm->dev, device_id, spare);
> -}
> -EXPORT_SYMBOL(qcom_scm_restore_sec_cfg);
> -
> -int qcom_scm_iommu_secure_ptbl_size(u32 spare, size_t *size)
> -{
> - return __qcom_scm_iommu_secure_ptbl_size(__scm->dev, spare, size);
> -}
> -EXPORT_SYMBOL(qcom_scm_iommu_secure_ptbl_size);
> -
> -int qcom_scm_iommu_secure_ptbl_init(u64 addr, u32 size, u32 spare)
> -{
> - return __qcom_scm_iommu_secure_ptbl_init(__scm->dev, addr, size, spare);
> -}
> -EXPORT_SYMBOL(qcom_scm_iommu_secure_ptbl_init);
> -
> -int qcom_scm_qsmmu500_wait_safe_toggle(bool en)
> -{
> - return __qcom_scm_qsmmu500_wait_safe_toggle(__scm->dev, en);
> -}
> -EXPORT_SYMBOL(qcom_scm_qsmmu500_wait_safe_toggle);
> -
> int qcom_scm_io_readl(phys_addr_t addr, unsigned int *val)
> {
> return __qcom_scm_io_readl(__scm->dev, addr, val);
> @@ -361,68 +323,23 @@ int qcom_scm_io_writel(phys_addr_t addr, unsigned int val)
> }
> EXPORT_SYMBOL(qcom_scm_io_writel);
>
> -static void qcom_scm_set_download_mode(bool enable)
> -{
> - bool avail;
> - int ret = 0;
> -
> - avail = __qcom_scm_is_call_available(__scm->dev,
> - QCOM_SCM_SVC_BOOT,
> - QCOM_SCM_BOOT_SET_DLOAD_MODE);
> - if (avail) {
> - ret = __qcom_scm_set_dload_mode(__scm->dev, enable);
> - } else if (__scm->dload_mode_addr) {
> - ret = __qcom_scm_io_writel(__scm->dev, __scm->dload_mode_addr,
> - enable ? QCOM_SCM_BOOT_SET_DLOAD_MODE : 0);
> - } else {
> - dev_err(__scm->dev,
> - "No available mechanism for setting download mode\n");
> - }
> -
> - if (ret)
> - dev_err(__scm->dev, "failed to set download mode: %d\n", ret);
> -}
> -
> -static int qcom_scm_find_dload_address(struct device *dev, u64 *addr)
> +int qcom_scm_restore_sec_cfg(u32 device_id, u32 spare)
> {
> - struct device_node *tcsr;
> - struct device_node *np = dev->of_node;
> - struct resource res;
> - u32 offset;
> - int ret;
> -
> - tcsr = of_parse_phandle(np, "qcom,dload-mode", 0);
> - if (!tcsr)
> - return 0;
> -
> - ret = of_address_to_resource(tcsr, 0, &res);
> - of_node_put(tcsr);
> - if (ret)
> - return ret;
> -
> - ret = of_property_read_u32_index(np, "qcom,dload-mode", 1, &offset);
> - if (ret < 0)
> - return ret;
> -
> - *addr = res.start + offset;
> -
> - return 0;
> + return __qcom_scm_restore_sec_cfg(__scm->dev, device_id, spare);
> }
> +EXPORT_SYMBOL(qcom_scm_restore_sec_cfg);
>
> -/**
> - * qcom_scm_is_available() - Checks if SCM is available
> - */
> -bool qcom_scm_is_available(void)
> +int qcom_scm_iommu_secure_ptbl_size(u32 spare, size_t *size)
> {
> - return !!__scm;
> + return __qcom_scm_iommu_secure_ptbl_size(__scm->dev, spare, size);
> }
> -EXPORT_SYMBOL(qcom_scm_is_available);
> +EXPORT_SYMBOL(qcom_scm_iommu_secure_ptbl_size);
>
> -int qcom_scm_set_remote_state(u32 state, u32 id)
> +int qcom_scm_iommu_secure_ptbl_init(u64 addr, u32 size, u32 spare)
> {
> - return __qcom_scm_set_remote_state(__scm->dev, state, id);
> + return __qcom_scm_iommu_secure_ptbl_init(__scm->dev, addr, size, spare);
> }
> -EXPORT_SYMBOL(qcom_scm_set_remote_state);
> +EXPORT_SYMBOL(qcom_scm_iommu_secure_ptbl_init);
>
> /**
> * qcom_scm_assign_mem() - Make a secure call to reassign memory ownership
> @@ -506,6 +423,89 @@ int qcom_scm_assign_mem(phys_addr_t mem_addr, size_t mem_sz,
> }
> EXPORT_SYMBOL(qcom_scm_assign_mem);
>
> +/**
> + * qcom_scm_hdcp_available() - Check if secure environment supports HDCP.
> + *
> + * Return true if HDCP is supported, false if not.
> + */
> +bool qcom_scm_hdcp_available(void)
> +{
> + int ret = qcom_scm_clk_enable();
> +
> + if (ret)
> + return ret;
> +
> + ret = __qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_HDCP,
> + QCOM_SCM_HDCP_INVOKE);
> +
> + qcom_scm_clk_disable();
> +
> + return ret > 0 ? true : false;
> +}
> +EXPORT_SYMBOL(qcom_scm_hdcp_available);
> +
> +/**
> + * qcom_scm_hdcp_req() - Send HDCP request.
> + * @req: HDCP request array
> + * @req_cnt: HDCP request array count
> + * @resp: response buffer passed to SCM
> + *
> + * Write HDCP register(s) through SCM.
> + */
> +int qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt, u32 *resp)
> +{
> + int ret = qcom_scm_clk_enable();
> +
> + if (ret)
> + return ret;
> +
> + ret = __qcom_scm_hdcp_req(__scm->dev, req, req_cnt, resp);
> + qcom_scm_clk_disable();
> + return ret;
> +}
> +EXPORT_SYMBOL(qcom_scm_hdcp_req);
> +
> +int qcom_scm_qsmmu500_wait_safe_toggle(bool en)
> +{
> + return __qcom_scm_qsmmu500_wait_safe_toggle(__scm->dev, en);
> +}
> +EXPORT_SYMBOL(qcom_scm_qsmmu500_wait_safe_toggle);
> +
> +/**
> + * qcom_scm_is_available() - Checks if SCM is available
> + */
> +bool qcom_scm_is_available(void)
> +{
> + return !!__scm;
> +}
> +EXPORT_SYMBOL(qcom_scm_is_available);
> +
> +static int qcom_scm_find_dload_address(struct device *dev, u64 *addr)
> +{
> + struct device_node *tcsr;
> + struct device_node *np = dev->of_node;
> + struct resource res;
> + u32 offset;
> + int ret;
> +
> + tcsr = of_parse_phandle(np, "qcom,dload-mode", 0);
> + if (!tcsr)
> + return 0;
> +
> + ret = of_address_to_resource(tcsr, 0, &res);
> + of_node_put(tcsr);
> + if (ret)
> + return ret;
> +
> + ret = of_property_read_u32_index(np, "qcom,dload-mode", 1, &offset);
> + if (ret < 0)
> + return ret;
> +
> + *addr = res.start + offset;
> +
> + return 0;
> +}
> +
> static int qcom_scm_probe(struct platform_device *pdev)
> {
> struct qcom_scm *scm;
> diff --git a/drivers/firmware/qcom_scm.h b/drivers/firmware/qcom_scm.h
> index 99e91ba..4be482f 100644
> --- a/drivers/firmware/qcom_scm.h
> +++ b/drivers/firmware/qcom_scm.h
> @@ -4,54 +4,74 @@
> #ifndef __QCOM_SCM_INT_H
> #define __QCOM_SCM_INT_H
>
> -#define QCOM_SCM_SVC_BOOT 0x1
> -#define QCOM_SCM_BOOT_SET_ADDR 0x1
> +#define QCOM_SCM_SVC_BOOT 0x01
> +#define QCOM_SCM_BOOT_SET_ADDR 0x01
> +#define QCOM_SCM_BOOT_TERMINATE_PC 0x02
> +#define QCOM_SCM_BOOT_SET_REMOTE_STATE 0x0a
> #define QCOM_SCM_BOOT_SET_DLOAD_MODE 0x10
> -#define QCOM_SCM_BOOT_SET_REMOTE_STATE 0xa
> -extern int __qcom_scm_set_remote_state(struct device *dev, u32 state, u32 id);
> -extern int __qcom_scm_set_dload_mode(struct device *dev, bool enable);
> -
> +extern int __qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus);
> extern int __qcom_scm_set_warm_boot_addr(struct device *dev, void *entry,
> const cpumask_t *cpus);
> -extern int __qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus);
> -
> -#define QCOM_SCM_BOOT_TERMINATE_PC 0x2
> -#define QCOM_SCM_FLUSH_FLAG_MASK 0x3
> extern void __qcom_scm_cpu_power_down(u32 flags);
> +extern int __qcom_scm_set_remote_state(struct device *dev, u32 state, u32 id);
> +extern int __qcom_scm_set_dload_mode(struct device *dev, bool enable);
> +#define QCOM_SCM_FLUSH_FLAG_MASK 0x3
> +
> +#define QCOM_SCM_SVC_PIL 0x02
> +#define QCOM_SCM_PIL_PAS_INIT_IMAGE 0x01
> +#define QCOM_SCM_PIL_PAS_MEM_SETUP 0x02
> +#define QCOM_SCM_PIL_PAS_AUTH_AND_RESET 0x05
> +#define QCOM_SCM_PIL_PAS_SHUTDOWN 0x06
> +#define QCOM_SCM_PIL_PAS_IS_SUPPORTED 0x07
> +#define QCOM_SCM_PIL_PAS_MSS_RESET 0x0a
> +extern bool __qcom_scm_pas_supported(struct device *dev, u32 peripheral);
> +extern int __qcom_scm_pas_init_image(struct device *dev, u32 peripheral,
> + dma_addr_t metadata_phys);
> +extern int __qcom_scm_pas_mem_setup(struct device *dev, u32 peripheral,
> + phys_addr_t addr, phys_addr_t size);
> +extern int __qcom_scm_pas_auth_and_reset(struct device *dev, u32 peripheral);
> +extern int __qcom_scm_pas_shutdown(struct device *dev, u32 peripheral);
> +extern int __qcom_scm_pas_mss_reset(struct device *dev, bool reset);
>
> -#define QCOM_SCM_SVC_IO 0x5
> -#define QCOM_SCM_IO_READ 0x1
> -#define QCOM_SCM_IO_WRITE 0x2
> +#define QCOM_SCM_SVC_IO 0x05
> +#define QCOM_SCM_IO_READ 0x01
> +#define QCOM_SCM_IO_WRITE 0x02
> extern int __qcom_scm_io_readl(struct device *dev, phys_addr_t addr, unsigned int *val);
> extern int __qcom_scm_io_writel(struct device *dev, phys_addr_t addr, unsigned int val);
>
> -#define QCOM_SCM_SVC_INFO 0x6
> -#define QCOM_SCM_INFO_IS_CALL_AVAIL 0x1
> +#define QCOM_SCM_SVC_INFO 0x06
> +#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_HDCP 0x11
> -#define QCOM_SCM_HDCP_INVOKE 0x01
> +#define QCOM_SCM_SVC_MP 0x0c
> +#define QCOM_SCM_MP_RESTORE_SEC_CFG 0x02
> +#define QCOM_SCM_MP_IOMMU_SECURE_PTBL_SIZE 0x03
> +#define QCOM_SCM_MP_IOMMU_SECURE_PTBL_INIT 0x04
> +#define QCOM_SCM_MP_ASSIGN 0x16
> +extern int __qcom_scm_restore_sec_cfg(struct device *dev, u32 device_id,
> + u32 spare);
> +extern int __qcom_scm_iommu_secure_ptbl_size(struct device *dev, u32 spare,
> + size_t *size);
> +extern int __qcom_scm_iommu_secure_ptbl_init(struct device *dev, u64 addr,
> + u32 size, u32 spare);
> +extern int __qcom_scm_assign_mem(struct device *dev,
> + phys_addr_t mem_region, size_t mem_sz,
> + phys_addr_t src, size_t src_sz,
> + phys_addr_t dest, size_t dest_sz);
> +
> +#define QCOM_SCM_SVC_HDCP 0x11
> +#define QCOM_SCM_HDCP_INVOKE 0x01
> extern int __qcom_scm_hdcp_req(struct device *dev,
> struct qcom_scm_hdcp_req *req, u32 req_cnt, u32 *resp);
>
> -extern void __qcom_scm_init(void);
> +#define QCOM_SCM_SVC_SMMU_PROGRAM 0x15
> +#define QCOM_SCM_SMMU_CONFIG_ERRATA1 0x3
> +extern int __qcom_scm_qsmmu500_wait_safe_toggle(struct device *dev,
> + bool enable);
> +#define QCOM_SCM_SMMU_CONFIG_ERRATA1_CLIENT_ALL 0x2
>
> -#define QCOM_SCM_SVC_PIL 0x2
> -#define QCOM_SCM_PIL_PAS_INIT_IMAGE 0x1
> -#define QCOM_SCM_PIL_PAS_MEM_SETUP 0x2
> -#define QCOM_SCM_PIL_PAS_AUTH_AND_RESET 0x5
> -#define QCOM_SCM_PIL_PAS_SHUTDOWN 0x6
> -#define QCOM_SCM_PIL_PAS_IS_SUPPORTED 0x7
> -#define QCOM_SCM_PIL_PAS_MSS_RESET 0xa
> -extern bool __qcom_scm_pas_supported(struct device *dev, u32 peripheral);
> -extern int __qcom_scm_pas_init_image(struct device *dev, u32 peripheral,
> - dma_addr_t metadata_phys);
> -extern int __qcom_scm_pas_mem_setup(struct device *dev, u32 peripheral,
> - phys_addr_t addr, phys_addr_t size);
> -extern int __qcom_scm_pas_auth_and_reset(struct device *dev, u32 peripheral);
> -extern int __qcom_scm_pas_shutdown(struct device *dev, u32 peripheral);
> -extern int __qcom_scm_pas_mss_reset(struct device *dev, bool reset);
> +extern void __qcom_scm_init(void);
>
> /* common error codes */
> #define QCOM_SCM_V2_EBUSY -12
> @@ -80,25 +100,4 @@ static inline int qcom_scm_remap_error(int err)
> return -EINVAL;
> }
>
> -#define QCOM_SCM_SVC_MP 0xc
> -#define QCOM_SCM_MP_RESTORE_SEC_CFG 2
> -extern int __qcom_scm_restore_sec_cfg(struct device *dev, u32 device_id,
> - u32 spare);
> -#define QCOM_SCM_MP_IOMMU_SECURE_PTBL_SIZE 3
> -#define QCOM_SCM_MP_IOMMU_SECURE_PTBL_INIT 4
> -#define QCOM_SCM_SVC_SMMU_PROGRAM 0x15
> -#define QCOM_SCM_SMMU_CONFIG_ERRATA1 0x3
> -#define QCOM_SCM_SMMU_CONFIG_ERRATA1_CLIENT_ALL 0x2
> -extern int __qcom_scm_iommu_secure_ptbl_size(struct device *dev, u32 spare,
> - size_t *size);
> -extern int __qcom_scm_iommu_secure_ptbl_init(struct device *dev, u64 addr,
> - u32 size, u32 spare);
> -extern int __qcom_scm_qsmmu500_wait_safe_toggle(struct device *dev,
> - bool enable);
> -#define QCOM_SCM_MP_ASSIGN 0x16
> -extern int __qcom_scm_assign_mem(struct device *dev,
> - phys_addr_t mem_region, size_t mem_sz,
> - phys_addr_t src, size_t src_sz,
> - phys_addr_t dest, size_t dest_sz);
> -
> #endif
> diff --git a/include/linux/qcom_scm.h b/include/linux/qcom_scm.h
> index ffd72b3..f8b6525 100644
> --- a/include/linux/qcom_scm.h
> +++ b/include/linux/qcom_scm.h
> @@ -37,10 +37,8 @@ struct qcom_scm_vmperm {
> #if IS_ENABLED(CONFIG_QCOM_SCM)
> extern int qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus);
> extern int qcom_scm_set_warm_boot_addr(void *entry, const cpumask_t *cpus);
> -extern bool qcom_scm_is_available(void);
> -extern bool qcom_scm_hdcp_available(void);
> -extern int qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt,
> - u32 *resp);
> +extern void qcom_scm_cpu_power_down(u32 flags);
> +extern int qcom_scm_set_remote_state(u32 state, u32 id);
> extern bool qcom_scm_pas_supported(u32 peripheral);
> extern int qcom_scm_pas_init_image(u32 peripheral, const void *metadata,
> size_t size);
> @@ -48,58 +46,62 @@ extern int qcom_scm_pas_mem_setup(u32 peripheral, phys_addr_t addr,
> phys_addr_t size);
> extern int qcom_scm_pas_auth_and_reset(u32 peripheral);
> extern int qcom_scm_pas_shutdown(u32 peripheral);
> -extern int qcom_scm_assign_mem(phys_addr_t mem_addr, size_t mem_sz,
> - unsigned int *src,
> - const struct qcom_scm_vmperm *newvm,
> - unsigned int dest_cnt);
> -extern void qcom_scm_cpu_power_down(u32 flags);
> -extern u32 qcom_scm_get_version(void);
> -extern int qcom_scm_set_remote_state(u32 state, u32 id);
> +extern int qcom_scm_io_readl(phys_addr_t addr, unsigned int *val);
> +extern int qcom_scm_io_writel(phys_addr_t addr, unsigned int val);
> extern int qcom_scm_restore_sec_cfg(u32 device_id, u32 spare);
> extern int qcom_scm_iommu_secure_ptbl_size(u32 spare, size_t *size);
> extern int qcom_scm_iommu_secure_ptbl_init(u64 addr, u32 size, u32 spare);
> +extern int qcom_scm_assign_mem(phys_addr_t mem_addr, size_t mem_sz,
> + unsigned int *src,
> + const struct qcom_scm_vmperm *newvm,
> + int dest_cnt);
> +extern bool qcom_scm_hdcp_available(void);
> +extern int qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt,
> + u32 *resp);
> extern int qcom_scm_qsmmu500_wait_safe_toggle(bool en);
> -extern int qcom_scm_io_readl(phys_addr_t addr, unsigned int *val);
> -extern int qcom_scm_io_writel(phys_addr_t addr, unsigned int val);
> +extern u32 qcom_scm_get_version(void);
> +extern bool qcom_scm_is_available(void);
> #else
>
> #include <linux/errno.h>
>
> static inline
> int qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus)
> -{
> - return -ENODEV;
> -}
> + { return -ENODEV; }
> static inline
> int qcom_scm_set_warm_boot_addr(void *entry, const cpumask_t *cpus)
> -{
> - return -ENODEV;
> -}
> -static inline bool qcom_scm_is_available(void) { return false; }
> -static inline bool qcom_scm_hdcp_available(void) { return false; }
> -static inline int qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt,
> - u32 *resp) { return -ENODEV; }
> + { return -ENODEV; }
> +static inline void qcom_scm_cpu_power_down(u32 flags) {}
> +static inline u32 qcom_scm_set_remote_state(u32 state, u32 id)
> + { return -ENODEV; }
> static inline bool qcom_scm_pas_supported(u32 peripheral) { return false; }
> static inline int qcom_scm_pas_init_image(u32 peripheral, const void *metadata,
> size_t size) { return -ENODEV; }
> static inline int qcom_scm_pas_mem_setup(u32 peripheral, phys_addr_t addr,
> phys_addr_t size) { return -ENODEV; }
> -static inline int
> -qcom_scm_pas_auth_and_reset(u32 peripheral) { return -ENODEV; }
> +static inline int qcom_scm_pas_auth_and_reset(u32 peripheral)
> + { return -ENODEV; }
> static inline int qcom_scm_pas_shutdown(u32 peripheral) { return -ENODEV; }
> +static inline int qcom_scm_io_readl(phys_addr_t addr, unsigned int *val)
> + { return -ENODEV; }
> +static inline int qcom_scm_io_writel(phys_addr_t addr, unsigned int val)
> + { return -ENODEV; }
> +static inline int qcom_scm_restore_sec_cfg(u32 device_id, u32 spare)
> + { return -ENODEV; }
> +static inline int qcom_scm_iommu_secure_ptbl_size(u32 spare, size_t *size)
> + { return -ENODEV; }
> +static inline int qcom_scm_iommu_secure_ptbl_init(u64 addr, u32 size, u32 spare)
> + { return -ENODEV; }
> static inline int qcom_scm_assign_mem(phys_addr_t mem_addr, size_t mem_sz,
> unsigned int *src,
> const struct qcom_scm_vmperm *newvm,
> - unsigned int dest_cnt) { return -ENODEV; }
> -static inline void qcom_scm_cpu_power_down(u32 flags) {}
> + int dest_cnt) { return -ENODEV; }
> +static inline bool qcom_scm_hdcp_available(void) { return false; }
> +static inline int qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt,
> + u32 *resp) { return -ENODEV; }
> +static inline int qcom_scm_qsmmu500_wait_safe_toggle(bool en)
> + { return -ENODEV; }
> static inline u32 qcom_scm_get_version(void) { return 0; }
> -static inline u32
> -qcom_scm_set_remote_state(u32 state,u32 id) { return -ENODEV; }
> -static inline int qcom_scm_restore_sec_cfg(u32 device_id, u32 spare) { return -ENODEV; }
> -static inline int qcom_scm_iommu_secure_ptbl_size(u32 spare, size_t *size) { return -ENODEV; }
> -static inline int qcom_scm_iommu_secure_ptbl_init(u64 addr, u32 size, u32 spare) { return -ENODEV; }
> -static inline int qcom_scm_qsmmu500_wait_safe_toggle(bool en) { return -ENODEV; }
> -static inline int qcom_scm_io_readl(phys_addr_t addr, unsigned int *val) { return -ENODEV; }
> -static inline int qcom_scm_io_writel(phys_addr_t addr, unsigned int val) { return -ENODEV; }
> +static inline bool qcom_scm_is_available(void) { return false; }
> #endif
> #endif
> --
> The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
> a Linux Foundation Collaborative Project
>