2019-10-29 20:08:56

by Elliot Berman

[permalink] [raw]
Subject: [RFC 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

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 | 938 ++++++++++++++++++++++++++++++++++++++++
drivers/firmware/qcom_scm.c | 232 +++++-----
drivers/firmware/qcom_scm.h | 117 +++--
include/linux/qcom_scm.h | 74 ++--
8 files changed, 1159 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-10-29 20:09:02

by Elliot Berman

[permalink] [raw]
Subject: [RFC 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 | 2 +-
drivers/firmware/qcom_scm.h | 2 +-
include/linux/qcom_scm.h | 2 +-
5 files changed, 67 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..f83b94d 100644
--- a/drivers/firmware/qcom_scm.c
+++ b/drivers/firmware/qcom_scm.c
@@ -2,7 +2,7 @@
/*
* 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>
diff --git a/drivers/firmware/qcom_scm.h b/drivers/firmware/qcom_scm.h
index baee744..3c7b74d 100644
--- a/drivers/firmware/qcom_scm.h
+++ b/drivers/firmware/qcom_scm.h
@@ -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.
*/
#ifndef __QCOM_SCM_INT_H
#define __QCOM_SCM_INT_H
diff --git a/include/linux/qcom_scm.h b/include/linux/qcom_scm.h
index ffd72b3..122cca6 100644
--- a/include/linux/qcom_scm.h
+++ b/include/linux/qcom_scm.h
@@ -1,5 +1,5 @@
/* SPDX-License-Identifier: GPL-2.0-only */
-/* Copyright (c) 2010-2015, 2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2015,2019 The Linux Foundation. All rights reserved.
* Copyright (C) 2015 Linaro Ltd.
*/
#ifndef __QCOM_SCM_H
--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project

2019-10-29 20:09:12

by Elliot Berman

[permalink] [raw]
Subject: [RFC 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 | 107 +++++++++++++++++++++++++----------------
1 file changed, 66 insertions(+), 41 deletions(-)

diff --git a/drivers/firmware/qcom_scm-32.c b/drivers/firmware/qcom_scm-32.c
index 88d1755..f9eb490 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);
+ 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;
- 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;
-}
+ for(i = 0; i < arglen; i++)
+ smc.a[i + LEGACY_ATOMIC_FIRST_REG_IDX] = desc->args[i];

-/**
- * 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;
-
- 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);
}

/**
@@ -401,8 +393,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)
@@ -425,8 +424,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)
@@ -538,18 +546,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,
+ };
+
+ desc.args[0] = addr;
+ desc.arginfo = QCOM_SCM_ARGS(1);

- ret = qcom_scm_call_atomic1(QCOM_SCM_SVC_IO, QCOM_SCM_IO_READ, addr);
+ 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)
--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project

2019-10-29 20:09:55

by Elliot Berman

[permalink] [raw]
Subject: [RFC 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 cd694a2..6660539 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)
{
@@ -160,7 +135,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-10-29 22:09:06

by Elliot Berman

[permalink] [raw]
Subject: [RFC 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 9f39483..71b07b8 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;
@@ -181,6 +181,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
@@ -194,7 +411,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);
}

/**
@@ -210,9 +427,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
@@ -224,9 +446,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
@@ -239,7 +506,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] = virt_to_phys(entry);
+ desc.args[1] = flags;
+ ret = qcom_scm_call(dev, &desc);
+ if (!ret) {
+ for_each_cpu(cpu, cpus)
+ qcom_scm_wb[cpu].entry = entry;
+ }
+
+ return ret;
}

/**
@@ -252,6 +549,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)
@@ -284,7 +590,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)
@@ -408,7 +714,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];

@@ -427,7 +733,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-10-29 22:09:07

by Elliot Berman

[permalink] [raw]
Subject: [RFC 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 | 44 ++++++++++++++++++++++++------------------
1 file changed, 25 insertions(+), 19 deletions(-)

diff --git a/drivers/firmware/qcom_scm-64.c b/drivers/firmware/qcom_scm-64.c
index 6660539..c83eb1d 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,13 +94,21 @@ static int ___qcom_scm_call_smccc(struct device *dev,
{
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;
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);
@@ -132,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-10-29 22:09:08

by Elliot Berman

[permalink] [raw]
Subject: [RFC 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 dee2129..240adfd 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_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_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 520925d..ee0c950 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_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_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_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_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_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_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 0fc5c94..7244236 100644
--- a/drivers/firmware/qcom_scm.c
+++ b/drivers/firmware/qcom_scm.c
@@ -129,47 +129,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
@@ -327,30 +313,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);
@@ -363,68 +325,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
@@ -508,6 +425,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 7bc8566..6f63ca6 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_INFO_IS_CALL_AVAIL 0x1
+#define QCOM_SCM_SVC_INFO 0x06
+#define QCOM_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_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_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 122cca6..a4dfab0 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-10-29 22:09:56

by Elliot Berman

[permalink] [raw]
Subject: [RFC 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..dee2129 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_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..520925d 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_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_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_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 f83b94d..0fc5c94 100644
--- a/drivers/firmware/qcom_scm.c
+++ b/drivers/firmware/qcom_scm.c
@@ -142,7 +142,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();

@@ -183,7 +183,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;

@@ -370,12 +370,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 3c7b74d..7bc8566 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_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_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-10-29 22:10:41

by Elliot Berman

[permalink] [raw]
Subject: [RFC 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 240adfd..b2805de 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 a4dfab0..1e95080 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-10-29 22:10:48

by Elliot Berman

[permalink] [raw]
Subject: [RFC 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 | 18 ++++++++++--------
drivers/firmware/qcom_scm-64.c | 5 +++--
drivers/firmware/qcom_scm.c | 4 ++--
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 f9eb490..a33fdf1 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);
}

/**
@@ -391,7 +392,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,
@@ -401,7 +402,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)
@@ -434,7 +435,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)
@@ -555,11 +556,12 @@ 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];

return ret < 0 ? ret : 0;
+
}

int __qcom_scm_io_writel(struct device *dev, phys_addr_t addr, unsigned int val)
@@ -574,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 4d7fd3e..9f39483 100644
--- a/drivers/firmware/qcom_scm-64.c
+++ b/drivers/firmware/qcom_scm-64.c
@@ -221,7 +221,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;
}
@@ -249,7 +250,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 7244236..bb57fad 100644
--- a/drivers/firmware/qcom_scm.c
+++ b/drivers/firmware/qcom_scm.c
@@ -97,7 +97,7 @@ 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->dev, entry, cpus);
}
EXPORT_SYMBOL(qcom_scm_set_cold_boot_addr);

@@ -125,7 +125,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->dev, flags);
}
EXPORT_SYMBOL(qcom_scm_cpu_power_down);

diff --git a/drivers/firmware/qcom_scm.h b/drivers/firmware/qcom_scm.h
index 6f63ca6..ce2c396 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-10-29 22:10:46

by Elliot Berman

[permalink] [raw]
Subject: [RFC 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 | 938 ----------------------------------------
drivers/firmware/qcom_scm-smc.c | 938 ++++++++++++++++++++++++++++++++++++++++
5 files changed, 950 insertions(+), 1608 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 a33fdf1..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,
- };
-
- /*
- * 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] = virt_to_phys(entry);
- desc.args[1] = flags;
- 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_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)
-{
-}
\ No newline at end of file
diff --git a/drivers/firmware/qcom_scm-64.c b/drivers/firmware/qcom_scm-64.c
deleted file mode 100644
index 18f0bf5..0000000
--- a/drivers/firmware/qcom_scm-64.c
+++ /dev/null
@@ -1,938 +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);
- }
-
- 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] = virt_to_phys(entry);
- desc.args[1] = flags;
- 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_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_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)
-{
- /* First try a SMC64 call */
- qcom_smc_convention = SMC_CONVENTION_ARM_64;
- if (__qcom_scm_is_call_available(NULL, QCOM_SCM_SVC_INFO,
- QCOM_INFO_IS_CALL_AVAIL) <= 0) {
- /* Now try a SMC32 call */
- qcom_smc_convention = SMC_CONVENTION_ARM_32;
- if (__qcom_scm_is_call_available(NULL, QCOM_SCM_SVC_INFO,
- QCOM_INFO_IS_CALL_AVAIL) <= 0) {
- qcom_smc_convention = SMC_CONVENTION_LEGACY;
- }
- }
-}
diff --git a/drivers/firmware/qcom_scm-smc.c b/drivers/firmware/qcom_scm-smc.c
new file mode 100644
index 0000000..18f0bf5
--- /dev/null
+++ b/drivers/firmware/qcom_scm-smc.c
@@ -0,0 +1,938 @@
+// 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);
+ }
+
+ 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] = virt_to_phys(entry);
+ desc.args[1] = flags;
+ 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_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_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)
+{
+ /* First try a SMC64 call */
+ qcom_smc_convention = SMC_CONVENTION_ARM_64;
+ if (__qcom_scm_is_call_available(NULL, QCOM_SCM_SVC_INFO,
+ QCOM_INFO_IS_CALL_AVAIL) <= 0) {
+ /* Now try a SMC32 call */
+ qcom_smc_convention = SMC_CONVENTION_ARM_32;
+ if (__qcom_scm_is_call_available(NULL, QCOM_SCM_SVC_INFO,
+ QCOM_INFO_IS_CALL_AVAIL) <= 0) {
+ qcom_smc_convention = SMC_CONVENTION_LEGACY;
+ }
+ }
+}
--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project