firmware: qcom: move Qualcomm code into its own directory
authorBartosz Golaszewski <bartosz.golaszewski@linaro.org>
Tue, 17 Oct 2023 09:27:18 +0000 (11:27 +0200)
committerBjorn Andersson <andersson@kernel.org>
Sun, 22 Oct 2023 16:14:54 +0000 (09:14 -0700)
We're getting more and more qcom specific .c files in drivers/firmware/
and about to get even more. Create a separate directory for Qualcomm
firmware drivers and move existing sources in there.

Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
Acked-by: Elliot Berman <quic_eberman@quicinc.com>
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
Reviewed-by: Maximilian Luz <luzmaximilian@gmail.com>
Tested-by: Andrew Halaney <ahalaney@redhat.com> # sc8280xp-lenovo-thinkpad-x13s
Link: https://lore.kernel.org/r/20231017092732.19983-2-brgl@bgdev.pl
Signed-off-by: Bjorn Andersson <andersson@kernel.org>
17 files changed:
MAINTAINERS
drivers/firmware/Kconfig
drivers/firmware/Makefile
drivers/firmware/qcom/Kconfig [new file with mode: 0644]
drivers/firmware/qcom/Makefile [new file with mode: 0644]
drivers/firmware/qcom/qcom_qseecom.c [new file with mode: 0644]
drivers/firmware/qcom/qcom_qseecom_uefisecapp.c [new file with mode: 0644]
drivers/firmware/qcom/qcom_scm-legacy.c [new file with mode: 0644]
drivers/firmware/qcom/qcom_scm-smc.c [new file with mode: 0644]
drivers/firmware/qcom/qcom_scm.c [new file with mode: 0644]
drivers/firmware/qcom/qcom_scm.h [new file with mode: 0644]
drivers/firmware/qcom_qseecom.c [deleted file]
drivers/firmware/qcom_qseecom_uefisecapp.c [deleted file]
drivers/firmware/qcom_scm-legacy.c [deleted file]
drivers/firmware/qcom_scm-smc.c [deleted file]
drivers/firmware/qcom_scm.c [deleted file]
drivers/firmware/qcom_scm.h [deleted file]

index 01dde0acebd32044d4436875cc3e0b38c47bd459..2e28b5efc7fae0c0cb99682fe6c8f9321a67a15c 100644 (file)
@@ -17804,13 +17804,13 @@ QUALCOMM QSEECOM DRIVER
 M:     Maximilian Luz <luzmaximilian@gmail.com>
 L:     linux-arm-msm@vger.kernel.org
 S:     Maintained
-F:     drivers/firmware/qcom_qseecom.c
+F:     drivers/firmware/qcom/qcom_qseecom.c
 
 QUALCOMM QSEECOM UEFISECAPP DRIVER
 M:     Maximilian Luz <luzmaximilian@gmail.com>
 L:     linux-arm-msm@vger.kernel.org
 S:     Maintained
-F:     drivers/firmware/qcom_qseecom_uefisecapp.c
+F:     drivers/firmware/qcom/qcom_qseecom_uefisecapp.c
 
 QUALCOMM RMNET DRIVER
 M:     Subash Abhinov Kasiviswanathan <quic_subashab@quicinc.com>
index 8c608be300601f63eeaf6ccf26d5d63b37c43155..46949e9b748aeb375824f313591a2a66a68b1a2e 100644 (file)
@@ -212,53 +212,6 @@ config MTK_ADSP_IPC
          ADSP exists on some mtk processors.
          Client might use shared memory to exchange information with ADSP.
 
-config QCOM_SCM
-       tristate
-
-config QCOM_SCM_DOWNLOAD_MODE_DEFAULT
-       bool "Qualcomm download mode enabled by default"
-       depends on QCOM_SCM
-       help
-         A device with "download mode" enabled will upon an unexpected
-         warm-restart enter a special debug mode that allows the user to
-         "download" memory content over USB for offline postmortem analysis.
-         The feature can be enabled/disabled on the kernel command line.
-
-         Say Y here to enable "download mode" by default.
-
-config QCOM_QSEECOM
-       bool "Qualcomm QSEECOM interface driver"
-       depends on QCOM_SCM=y
-       select AUXILIARY_BUS
-       help
-         Various Qualcomm SoCs have a Secure Execution Environment (SEE) running
-         in the Trust Zone. This module provides an interface to that via the
-         QSEECOM mechanism, using SCM calls.
-
-         The QSEECOM interface allows, among other things, access to applications
-         running in the SEE. An example of such an application is 'uefisecapp',
-         which is required to access UEFI variables on certain systems. If
-         selected, the interface will also attempt to detect and register client
-         devices for supported applications.
-
-         Select Y here to enable the QSEECOM interface driver.
-
-config QCOM_QSEECOM_UEFISECAPP
-       bool "Qualcomm SEE UEFI Secure App client driver"
-       depends on QCOM_QSEECOM
-       depends on EFI
-       help
-         Various Qualcomm SoCs do not allow direct access to EFI variables.
-         Instead, these need to be accessed via the UEFI Secure Application
-         (uefisecapp), residing in the Secure Execution Environment (SEE).
-
-         This module provides a client driver for uefisecapp, installing efivar
-         operations to allow the kernel accessing EFI variables, and via that also
-         provide user-space with access to EFI variables via efivarfs.
-
-         Select Y here to provide access to EFI variables on the aforementioned
-         platforms.
-
 config SYSFB
        bool
        select BOOT_VESA_SUPPORT
@@ -344,6 +297,7 @@ source "drivers/firmware/efi/Kconfig"
 source "drivers/firmware/imx/Kconfig"
 source "drivers/firmware/meson/Kconfig"
 source "drivers/firmware/psci/Kconfig"
+source "drivers/firmware/qcom/Kconfig"
 source "drivers/firmware/smccc/Kconfig"
 source "drivers/firmware/tegra/Kconfig"
 source "drivers/firmware/xilinx/Kconfig"
index d41b094a5e580e92fb3be65bcc7668d98b3dfb60..ec454e9521682722193dec9b9c261e2ac0df4bd2 100644 (file)
@@ -18,10 +18,6 @@ obj-$(CONFIG_FIRMWARE_MEMMAP)        += memmap.o
 obj-$(CONFIG_MTK_ADSP_IPC)     += mtk-adsp-ipc.o
 obj-$(CONFIG_RASPBERRYPI_FIRMWARE) += raspberrypi.o
 obj-$(CONFIG_FW_CFG_SYSFS)     += qemu_fw_cfg.o
-obj-$(CONFIG_QCOM_SCM)         += qcom-scm.o
-qcom-scm-objs += qcom_scm.o qcom_scm-smc.o qcom_scm-legacy.o
-obj-$(CONFIG_QCOM_QSEECOM)     += qcom_qseecom.o
-obj-$(CONFIG_QCOM_QSEECOM_UEFISECAPP) += qcom_qseecom_uefisecapp.o
 obj-$(CONFIG_SYSFB)            += sysfb.o
 obj-$(CONFIG_SYSFB_SIMPLEFB)   += sysfb_simplefb.o
 obj-$(CONFIG_TI_SCI_PROTOCOL)  += ti_sci.o
@@ -37,6 +33,7 @@ obj-$(CONFIG_GOOGLE_FIRMWARE) += google/
 obj-y                          += efi/
 obj-y                          += imx/
 obj-y                          += psci/
+obj-y                          += qcom/
 obj-y                          += smccc/
 obj-y                          += tegra/
 obj-y                          += xilinx/
diff --git a/drivers/firmware/qcom/Kconfig b/drivers/firmware/qcom/Kconfig
new file mode 100644 (file)
index 0000000..3f05d98
--- /dev/null
@@ -0,0 +1,56 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# For a description of the syntax of this configuration file,
+# see Documentation/kbuild/kconfig-language.rst.
+#
+
+menu "Qualcomm firmware drivers"
+
+config QCOM_SCM
+       tristate
+
+config QCOM_SCM_DOWNLOAD_MODE_DEFAULT
+       bool "Qualcomm download mode enabled by default"
+       depends on QCOM_SCM
+       help
+         A device with "download mode" enabled will upon an unexpected
+         warm-restart enter a special debug mode that allows the user to
+         "download" memory content over USB for offline postmortem analysis.
+         The feature can be enabled/disabled on the kernel command line.
+
+         Say Y here to enable "download mode" by default.
+
+config QCOM_QSEECOM
+       bool "Qualcomm QSEECOM interface driver"
+       depends on QCOM_SCM=y
+       select AUXILIARY_BUS
+       help
+         Various Qualcomm SoCs have a Secure Execution Environment (SEE) running
+         in the Trust Zone. This module provides an interface to that via the
+         QSEECOM mechanism, using SCM calls.
+
+         The QSEECOM interface allows, among other things, access to applications
+         running in the SEE. An example of such an application is 'uefisecapp',
+         which is required to access UEFI variables on certain systems. If
+         selected, the interface will also attempt to detect and register client
+         devices for supported applications.
+
+         Select Y here to enable the QSEECOM interface driver.
+
+config QCOM_QSEECOM_UEFISECAPP
+       bool "Qualcomm SEE UEFI Secure App client driver"
+       depends on QCOM_QSEECOM
+       depends on EFI
+       help
+         Various Qualcomm SoCs do not allow direct access to EFI variables.
+         Instead, these need to be accessed via the UEFI Secure Application
+         (uefisecapp), residing in the Secure Execution Environment (SEE).
+
+         This module provides a client driver for uefisecapp, installing efivar
+         operations to allow the kernel accessing EFI variables, and via that also
+         provide user-space with access to EFI variables via efivarfs.
+
+         Select Y here to provide access to EFI variables on the aforementioned
+         platforms.
+
+endmenu
diff --git a/drivers/firmware/qcom/Makefile b/drivers/firmware/qcom/Makefile
new file mode 100644 (file)
index 0000000..c9f12ee
--- /dev/null
@@ -0,0 +1,9 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Makefile for the linux kernel.
+#
+
+obj-$(CONFIG_QCOM_SCM)         += qcom-scm.o
+qcom-scm-objs += qcom_scm.o qcom_scm-smc.o qcom_scm-legacy.o
+obj-$(CONFIG_QCOM_QSEECOM)     += qcom_qseecom.o
+obj-$(CONFIG_QCOM_QSEECOM_UEFISECAPP) += qcom_qseecom_uefisecapp.o
diff --git a/drivers/firmware/qcom/qcom_qseecom.c b/drivers/firmware/qcom/qcom_qseecom.c
new file mode 100644 (file)
index 0000000..731e6d5
--- /dev/null
@@ -0,0 +1,120 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Driver for Qualcomm Secure Execution Environment (SEE) interface (QSEECOM).
+ * Responsible for setting up and managing QSEECOM client devices.
+ *
+ * Copyright (C) 2023 Maximilian Luz <luzmaximilian@gmail.com>
+ */
+#include <linux/auxiliary_bus.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+#include <linux/firmware/qcom/qcom_qseecom.h>
+#include <linux/firmware/qcom/qcom_scm.h>
+
+struct qseecom_app_desc {
+       const char *app_name;
+       const char *dev_name;
+};
+
+static void qseecom_client_release(struct device *dev)
+{
+       struct qseecom_client *client;
+
+       client = container_of(dev, struct qseecom_client, aux_dev.dev);
+       kfree(client);
+}
+
+static void qseecom_client_remove(void *data)
+{
+       struct qseecom_client *client = data;
+
+       auxiliary_device_delete(&client->aux_dev);
+       auxiliary_device_uninit(&client->aux_dev);
+}
+
+static int qseecom_client_register(struct platform_device *qseecom_dev,
+                                  const struct qseecom_app_desc *desc)
+{
+       struct qseecom_client *client;
+       u32 app_id;
+       int ret;
+
+       /* Try to find the app ID, skip device if not found */
+       ret = qcom_scm_qseecom_app_get_id(desc->app_name, &app_id);
+       if (ret)
+               return ret == -ENOENT ? 0 : ret;
+
+       dev_info(&qseecom_dev->dev, "setting up client for %s\n", desc->app_name);
+
+       /* Allocate and set-up the client device */
+       client = kzalloc(sizeof(*client), GFP_KERNEL);
+       if (!client)
+               return -ENOMEM;
+
+       client->aux_dev.name = desc->dev_name;
+       client->aux_dev.dev.parent = &qseecom_dev->dev;
+       client->aux_dev.dev.release = qseecom_client_release;
+       client->app_id = app_id;
+
+       ret = auxiliary_device_init(&client->aux_dev);
+       if (ret) {
+               kfree(client);
+               return ret;
+       }
+
+       ret = auxiliary_device_add(&client->aux_dev);
+       if (ret) {
+               auxiliary_device_uninit(&client->aux_dev);
+               return ret;
+       }
+
+       ret = devm_add_action_or_reset(&qseecom_dev->dev, qseecom_client_remove, client);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+/*
+ * List of supported applications. One client device will be created per entry,
+ * assuming the app has already been loaded (usually by firmware bootloaders)
+ * and its ID can be queried successfully.
+ */
+static const struct qseecom_app_desc qcom_qseecom_apps[] = {
+       { "qcom.tz.uefisecapp", "uefisecapp" },
+};
+
+static int qcom_qseecom_probe(struct platform_device *qseecom_dev)
+{
+       int ret;
+       int i;
+
+       /* Set up client devices for each base application */
+       for (i = 0; i < ARRAY_SIZE(qcom_qseecom_apps); i++) {
+               ret = qseecom_client_register(qseecom_dev, &qcom_qseecom_apps[i]);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+static struct platform_driver qcom_qseecom_driver = {
+       .driver = {
+               .name   = "qcom_qseecom",
+       },
+       .probe = qcom_qseecom_probe,
+};
+
+static int __init qcom_qseecom_init(void)
+{
+       return platform_driver_register(&qcom_qseecom_driver);
+}
+subsys_initcall(qcom_qseecom_init);
+
+MODULE_AUTHOR("Maximilian Luz <luzmaximilian@gmail.com>");
+MODULE_DESCRIPTION("Driver for the Qualcomm SEE (QSEECOM) interface");
+MODULE_LICENSE("GPL");
diff --git a/drivers/firmware/qcom/qcom_qseecom_uefisecapp.c b/drivers/firmware/qcom/qcom_qseecom_uefisecapp.c
new file mode 100644 (file)
index 0000000..a33acda
--- /dev/null
@@ -0,0 +1,871 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Client driver for Qualcomm UEFI Secure Application (qcom.tz.uefisecapp).
+ * Provides access to UEFI variables on platforms where they are secured by the
+ * aforementioned Secure Execution Environment (SEE) application.
+ *
+ * Copyright (C) 2023 Maximilian Luz <luzmaximilian@gmail.com>
+ */
+
+#include <linux/efi.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/ucs2_string.h>
+
+#include <linux/firmware/qcom/qcom_qseecom.h>
+
+/* -- Qualcomm "uefisecapp" interface definitions. -------------------------- */
+
+/* Maximum length of name string with null-terminator */
+#define QSEE_MAX_NAME_LEN                      1024
+
+#define QSEE_CMD_UEFI(x)                       (0x8000 | (x))
+#define QSEE_CMD_UEFI_GET_VARIABLE             QSEE_CMD_UEFI(0)
+#define QSEE_CMD_UEFI_SET_VARIABLE             QSEE_CMD_UEFI(1)
+#define QSEE_CMD_UEFI_GET_NEXT_VARIABLE                QSEE_CMD_UEFI(2)
+#define QSEE_CMD_UEFI_QUERY_VARIABLE_INFO      QSEE_CMD_UEFI(3)
+
+/**
+ * struct qsee_req_uefi_get_variable - Request for GetVariable command.
+ * @command_id:  The ID of the command. Must be %QSEE_CMD_UEFI_GET_VARIABLE.
+ * @length:      Length of the request in bytes, including this struct and any
+ *               parameters (name, GUID) stored after it as well as any padding
+ *               thereof for alignment.
+ * @name_offset: Offset from the start of this struct to where the variable
+ *               name is stored (as utf-16 string), in bytes.
+ * @name_size:   Size of the name parameter in bytes, including null-terminator.
+ * @guid_offset: Offset from the start of this struct to where the GUID
+ *               parameter is stored, in bytes.
+ * @guid_size:   Size of the GUID parameter in bytes, i.e. sizeof(efi_guid_t).
+ * @data_size:   Size of the output buffer, in bytes.
+ */
+struct qsee_req_uefi_get_variable {
+       u32 command_id;
+       u32 length;
+       u32 name_offset;
+       u32 name_size;
+       u32 guid_offset;
+       u32 guid_size;
+       u32 data_size;
+} __packed;
+
+/**
+ * struct qsee_rsp_uefi_get_variable - Response for GetVariable command.
+ * @command_id:  The ID of the command. Should be %QSEE_CMD_UEFI_GET_VARIABLE.
+ * @length:      Length of the response in bytes, including this struct and the
+ *               returned data.
+ * @status:      Status of this command.
+ * @attributes:  EFI variable attributes.
+ * @data_offset: Offset from the start of this struct to where the data is
+ *               stored, in bytes.
+ * @data_size:   Size of the returned data, in bytes. In case status indicates
+ *               that the buffer is too small, this will be the size required
+ *               to store the EFI variable data.
+ */
+struct qsee_rsp_uefi_get_variable {
+       u32 command_id;
+       u32 length;
+       u32 status;
+       u32 attributes;
+       u32 data_offset;
+       u32 data_size;
+} __packed;
+
+/**
+ * struct qsee_req_uefi_set_variable - Request for the SetVariable command.
+ * @command_id:  The ID of the command. Must be %QSEE_CMD_UEFI_SET_VARIABLE.
+ * @length:      Length of the request in bytes, including this struct and any
+ *               parameters (name, GUID, data) stored after it as well as any
+ *               padding thereof required for alignment.
+ * @name_offset: Offset from the start of this struct to where the variable
+ *               name is stored (as utf-16 string), in bytes.
+ * @name_size:   Size of the name parameter in bytes, including null-terminator.
+ * @guid_offset: Offset from the start of this struct to where the GUID
+ *               parameter is stored, in bytes.
+ * @guid_size:   Size of the GUID parameter in bytes, i.e. sizeof(efi_guid_t).
+ * @attributes:  The EFI variable attributes to set for this variable.
+ * @data_offset: Offset from the start of this struct to where the EFI variable
+ *               data is stored, in bytes.
+ * @data_size:   Size of EFI variable data, in bytes.
+ *
+ */
+struct qsee_req_uefi_set_variable {
+       u32 command_id;
+       u32 length;
+       u32 name_offset;
+       u32 name_size;
+       u32 guid_offset;
+       u32 guid_size;
+       u32 attributes;
+       u32 data_offset;
+       u32 data_size;
+} __packed;
+
+/**
+ * struct qsee_rsp_uefi_set_variable - Response for the SetVariable command.
+ * @command_id:  The ID of the command. Should be %QSEE_CMD_UEFI_SET_VARIABLE.
+ * @length:      The length of this response, i.e. the size of this struct in
+ *               bytes.
+ * @status:      Status of this command.
+ * @_unknown1:   Unknown response field.
+ * @_unknown2:   Unknown response field.
+ */
+struct qsee_rsp_uefi_set_variable {
+       u32 command_id;
+       u32 length;
+       u32 status;
+       u32 _unknown1;
+       u32 _unknown2;
+} __packed;
+
+/**
+ * struct qsee_req_uefi_get_next_variable - Request for the
+ * GetNextVariableName command.
+ * @command_id:  The ID of the command. Must be
+ *               %QSEE_CMD_UEFI_GET_NEXT_VARIABLE.
+ * @length:      Length of the request in bytes, including this struct and any
+ *               parameters (name, GUID) stored after it as well as any padding
+ *               thereof for alignment.
+ * @guid_offset: Offset from the start of this struct to where the GUID
+ *               parameter is stored, in bytes.
+ * @guid_size:   Size of the GUID parameter in bytes, i.e. sizeof(efi_guid_t).
+ * @name_offset: Offset from the start of this struct to where the variable
+ *               name is stored (as utf-16 string), in bytes.
+ * @name_size:   Size of the name parameter in bytes, including null-terminator.
+ */
+struct qsee_req_uefi_get_next_variable {
+       u32 command_id;
+       u32 length;
+       u32 guid_offset;
+       u32 guid_size;
+       u32 name_offset;
+       u32 name_size;
+} __packed;
+
+/**
+ * struct qsee_rsp_uefi_get_next_variable - Response for the
+ * GetNextVariableName command.
+ * @command_id:  The ID of the command. Should be
+ *               %QSEE_CMD_UEFI_GET_NEXT_VARIABLE.
+ * @length:      Length of the response in bytes, including this struct and any
+ *               parameters (name, GUID) stored after it as well as any padding
+ *               thereof for alignment.
+ * @status:      Status of this command.
+ * @guid_offset: Offset from the start of this struct to where the GUID
+ *               parameter is stored, in bytes.
+ * @guid_size:   Size of the GUID parameter in bytes, i.e. sizeof(efi_guid_t).
+ * @name_offset: Offset from the start of this struct to where the variable
+ *               name is stored (as utf-16 string), in bytes.
+ * @name_size:   Size of the name parameter in bytes, including null-terminator.
+ */
+struct qsee_rsp_uefi_get_next_variable {
+       u32 command_id;
+       u32 length;
+       u32 status;
+       u32 guid_offset;
+       u32 guid_size;
+       u32 name_offset;
+       u32 name_size;
+} __packed;
+
+/**
+ * struct qsee_req_uefi_query_variable_info - Response for the
+ * GetNextVariableName command.
+ * @command_id: The ID of the command. Must be
+ *              %QSEE_CMD_UEFI_QUERY_VARIABLE_INFO.
+ * @length:     The length of this request, i.e. the size of this struct in
+ *              bytes.
+ * @attributes: The storage attributes to query the info for.
+ */
+struct qsee_req_uefi_query_variable_info {
+       u32 command_id;
+       u32 length;
+       u32 attributes;
+} __packed;
+
+/**
+ * struct qsee_rsp_uefi_query_variable_info - Response for the
+ * GetNextVariableName command.
+ * @command_id:        The ID of the command. Must be
+ *                     %QSEE_CMD_UEFI_QUERY_VARIABLE_INFO.
+ * @length:            The length of this response, i.e. the size of this
+ *                     struct in bytes.
+ * @status:            Status of this command.
+ * @_pad:              Padding.
+ * @storage_space:     Full storage space size, in bytes.
+ * @remaining_space:   Free storage space available, in bytes.
+ * @max_variable_size: Maximum variable data size, in bytes.
+ */
+struct qsee_rsp_uefi_query_variable_info {
+       u32 command_id;
+       u32 length;
+       u32 status;
+       u32 _pad;
+       u64 storage_space;
+       u64 remaining_space;
+       u64 max_variable_size;
+} __packed;
+
+/* -- Alignment helpers ----------------------------------------------------- */
+
+/*
+ * Helper macro to ensure proper alignment of types (fields and arrays) when
+ * stored in some (contiguous) buffer.
+ *
+ * Note: The driver from which this one has been reverse-engineered expects an
+ * alignment of 8 bytes (64 bits) for GUIDs. Our definition of efi_guid_t,
+ * however, has an alignment of 4 byte (32 bits). So far, this seems to work
+ * fine here. See also the comment on the typedef of efi_guid_t.
+ */
+#define qcuefi_buf_align_fields(fields...)                                     \
+       ({                                                                      \
+               size_t __len = 0;                                               \
+               fields                                                          \
+               __len;                                                          \
+       })
+
+#define __field_impl(size, align, offset)                                      \
+       ({                                                                      \
+               size_t *__offset = (offset);                                    \
+               size_t __aligned;                                               \
+                                                                               \
+               __aligned = ALIGN(__len, align);                                \
+               __len = __aligned + (size);                                     \
+                                                                               \
+               if (__offset)                                                   \
+                       *__offset = __aligned;                                  \
+       });
+
+#define __array_offs(type, count, offset)                                      \
+       __field_impl(sizeof(type) * (count), __alignof__(type), offset)
+
+#define __array(type, count)           __array_offs(type, count, NULL)
+#define __field_offs(type, offset)     __array_offs(type, 1, offset)
+#define __field(type)                  __array_offs(type, 1, NULL)
+
+/* -- UEFI app interface. --------------------------------------------------- */
+
+struct qcuefi_client {
+       struct qseecom_client *client;
+       struct efivars efivars;
+};
+
+static struct device *qcuefi_dev(struct qcuefi_client *qcuefi)
+{
+       return &qcuefi->client->aux_dev.dev;
+}
+
+static efi_status_t qsee_uefi_status_to_efi(u32 status)
+{
+       u64 category = status & 0xf0000000;
+       u64 code = status & 0x0fffffff;
+
+       return category << (BITS_PER_LONG - 32) | code;
+}
+
+static efi_status_t qsee_uefi_get_variable(struct qcuefi_client *qcuefi, const efi_char16_t *name,
+                                          const efi_guid_t *guid, u32 *attributes,
+                                          unsigned long *data_size, void *data)
+{
+       struct qsee_req_uefi_get_variable *req_data;
+       struct qsee_rsp_uefi_get_variable *rsp_data;
+       unsigned long buffer_size = *data_size;
+       efi_status_t efi_status = EFI_SUCCESS;
+       unsigned long name_length;
+       size_t guid_offs;
+       size_t name_offs;
+       size_t req_size;
+       size_t rsp_size;
+       ssize_t status;
+
+       if (!name || !guid)
+               return EFI_INVALID_PARAMETER;
+
+       name_length = ucs2_strnlen(name, QSEE_MAX_NAME_LEN) + 1;
+       if (name_length > QSEE_MAX_NAME_LEN)
+               return EFI_INVALID_PARAMETER;
+
+       if (buffer_size && !data)
+               return EFI_INVALID_PARAMETER;
+
+       req_size = qcuefi_buf_align_fields(
+               __field(*req_data)
+               __array_offs(*name, name_length, &name_offs)
+               __field_offs(*guid, &guid_offs)
+       );
+
+       rsp_size = qcuefi_buf_align_fields(
+               __field(*rsp_data)
+               __array(u8, buffer_size)
+       );
+
+       req_data = kzalloc(req_size, GFP_KERNEL);
+       if (!req_data) {
+               efi_status = EFI_OUT_OF_RESOURCES;
+               goto out;
+       }
+
+       rsp_data = kzalloc(rsp_size, GFP_KERNEL);
+       if (!rsp_data) {
+               efi_status = EFI_OUT_OF_RESOURCES;
+               goto out_free_req;
+       }
+
+       req_data->command_id = QSEE_CMD_UEFI_GET_VARIABLE;
+       req_data->data_size = buffer_size;
+       req_data->name_offset = name_offs;
+       req_data->name_size = name_length * sizeof(*name);
+       req_data->guid_offset = guid_offs;
+       req_data->guid_size = sizeof(*guid);
+       req_data->length = req_size;
+
+       status = ucs2_strscpy(((void *)req_data) + req_data->name_offset, name, name_length);
+       if (status < 0)
+               return EFI_INVALID_PARAMETER;
+
+       memcpy(((void *)req_data) + req_data->guid_offset, guid, req_data->guid_size);
+
+       status = qcom_qseecom_app_send(qcuefi->client, req_data, req_size, rsp_data, rsp_size);
+       if (status) {
+               efi_status = EFI_DEVICE_ERROR;
+               goto out_free;
+       }
+
+       if (rsp_data->command_id != QSEE_CMD_UEFI_GET_VARIABLE) {
+               efi_status = EFI_DEVICE_ERROR;
+               goto out_free;
+       }
+
+       if (rsp_data->length < sizeof(*rsp_data)) {
+               efi_status = EFI_DEVICE_ERROR;
+               goto out_free;
+       }
+
+       if (rsp_data->status) {
+               dev_dbg(qcuefi_dev(qcuefi), "%s: uefisecapp error: 0x%x\n",
+                       __func__, rsp_data->status);
+               efi_status = qsee_uefi_status_to_efi(rsp_data->status);
+
+               /* Update size and attributes in case buffer is too small. */
+               if (efi_status == EFI_BUFFER_TOO_SMALL) {
+                       *data_size = rsp_data->data_size;
+                       if (attributes)
+                               *attributes = rsp_data->attributes;
+               }
+
+               goto out_free;
+       }
+
+       if (rsp_data->length > rsp_size) {
+               efi_status = EFI_DEVICE_ERROR;
+               goto out_free;
+       }
+
+       if (rsp_data->data_offset + rsp_data->data_size > rsp_data->length) {
+               efi_status = EFI_DEVICE_ERROR;
+               goto out_free;
+       }
+
+       /*
+        * Note: We need to set attributes and data size even if the buffer is
+        * too small and we won't copy any data. This is described in spec, so
+        * that callers can either allocate a buffer properly (with two calls
+        * to this function) or just read back attributes withouth having to
+        * deal with that.
+        *
+        * Specifically:
+        * - If we have a buffer size of zero and no buffer, just return the
+        *   attributes, required size, and indicate success.
+        * - If the buffer size is nonzero but too small, indicate that as an
+        *   error.
+        * - Otherwise, we are good to copy the data.
+        *
+        * Note that we have already ensured above that the buffer pointer is
+        * non-NULL if its size is nonzero.
+        */
+       *data_size = rsp_data->data_size;
+       if (attributes)
+               *attributes = rsp_data->attributes;
+
+       if (buffer_size == 0 && !data) {
+               efi_status = EFI_SUCCESS;
+               goto out_free;
+       }
+
+       if (buffer_size < rsp_data->data_size) {
+               efi_status = EFI_BUFFER_TOO_SMALL;
+               goto out_free;
+       }
+
+       memcpy(data, ((void *)rsp_data) + rsp_data->data_offset, rsp_data->data_size);
+
+out_free:
+       kfree(rsp_data);
+out_free_req:
+       kfree(req_data);
+out:
+       return efi_status;
+}
+
+static efi_status_t qsee_uefi_set_variable(struct qcuefi_client *qcuefi, const efi_char16_t *name,
+                                          const efi_guid_t *guid, u32 attributes,
+                                          unsigned long data_size, const void *data)
+{
+       struct qsee_req_uefi_set_variable *req_data;
+       struct qsee_rsp_uefi_set_variable *rsp_data;
+       efi_status_t efi_status = EFI_SUCCESS;
+       unsigned long name_length;
+       size_t name_offs;
+       size_t guid_offs;
+       size_t data_offs;
+       size_t req_size;
+       ssize_t status;
+
+       if (!name || !guid)
+               return EFI_INVALID_PARAMETER;
+
+       name_length = ucs2_strnlen(name, QSEE_MAX_NAME_LEN) + 1;
+       if (name_length > QSEE_MAX_NAME_LEN)
+               return EFI_INVALID_PARAMETER;
+
+       /*
+        * Make sure we have some data if data_size is nonzero. Note that using
+        * a size of zero is a valid use-case described in spec and deletes the
+        * variable.
+        */
+       if (data_size && !data)
+               return EFI_INVALID_PARAMETER;
+
+       req_size = qcuefi_buf_align_fields(
+               __field(*req_data)
+               __array_offs(*name, name_length, &name_offs)
+               __field_offs(*guid, &guid_offs)
+               __array_offs(u8, data_size, &data_offs)
+       );
+
+       req_data = kzalloc(req_size, GFP_KERNEL);
+       if (!req_data) {
+               efi_status = EFI_OUT_OF_RESOURCES;
+               goto out;
+       }
+
+       rsp_data = kzalloc(sizeof(*rsp_data), GFP_KERNEL);
+       if (!rsp_data) {
+               efi_status = EFI_OUT_OF_RESOURCES;
+               goto out_free_req;
+       }
+
+       req_data->command_id = QSEE_CMD_UEFI_SET_VARIABLE;
+       req_data->attributes = attributes;
+       req_data->name_offset = name_offs;
+       req_data->name_size = name_length * sizeof(*name);
+       req_data->guid_offset = guid_offs;
+       req_data->guid_size = sizeof(*guid);
+       req_data->data_offset = data_offs;
+       req_data->data_size = data_size;
+       req_data->length = req_size;
+
+       status = ucs2_strscpy(((void *)req_data) + req_data->name_offset, name, name_length);
+       if (status < 0)
+               return EFI_INVALID_PARAMETER;
+
+       memcpy(((void *)req_data) + req_data->guid_offset, guid, req_data->guid_size);
+
+       if (data_size)
+               memcpy(((void *)req_data) + req_data->data_offset, data, req_data->data_size);
+
+       status = qcom_qseecom_app_send(qcuefi->client, req_data, req_size, rsp_data,
+                                      sizeof(*rsp_data));
+       if (status) {
+               efi_status = EFI_DEVICE_ERROR;
+               goto out_free;
+       }
+
+       if (rsp_data->command_id != QSEE_CMD_UEFI_SET_VARIABLE) {
+               efi_status = EFI_DEVICE_ERROR;
+               goto out_free;
+       }
+
+       if (rsp_data->length != sizeof(*rsp_data)) {
+               efi_status = EFI_DEVICE_ERROR;
+               goto out_free;
+       }
+
+       if (rsp_data->status) {
+               dev_dbg(qcuefi_dev(qcuefi), "%s: uefisecapp error: 0x%x\n",
+                       __func__, rsp_data->status);
+               efi_status = qsee_uefi_status_to_efi(rsp_data->status);
+       }
+
+out_free:
+       kfree(rsp_data);
+out_free_req:
+       kfree(req_data);
+out:
+       return efi_status;
+}
+
+static efi_status_t qsee_uefi_get_next_variable(struct qcuefi_client *qcuefi,
+                                               unsigned long *name_size, efi_char16_t *name,
+                                               efi_guid_t *guid)
+{
+       struct qsee_req_uefi_get_next_variable *req_data;
+       struct qsee_rsp_uefi_get_next_variable *rsp_data;
+       efi_status_t efi_status = EFI_SUCCESS;
+       size_t guid_offs;
+       size_t name_offs;
+       size_t req_size;
+       size_t rsp_size;
+       ssize_t status;
+
+       if (!name_size || !name || !guid)
+               return EFI_INVALID_PARAMETER;
+
+       if (*name_size == 0)
+               return EFI_INVALID_PARAMETER;
+
+       req_size = qcuefi_buf_align_fields(
+               __field(*req_data)
+               __field_offs(*guid, &guid_offs)
+               __array_offs(*name, *name_size / sizeof(*name), &name_offs)
+       );
+
+       rsp_size = qcuefi_buf_align_fields(
+               __field(*rsp_data)
+               __field(*guid)
+               __array(*name, *name_size / sizeof(*name))
+       );
+
+       req_data = kzalloc(req_size, GFP_KERNEL);
+       if (!req_data) {
+               efi_status = EFI_OUT_OF_RESOURCES;
+               goto out;
+       }
+
+       rsp_data = kzalloc(rsp_size, GFP_KERNEL);
+       if (!rsp_data) {
+               efi_status = EFI_OUT_OF_RESOURCES;
+               goto out_free_req;
+       }
+
+       req_data->command_id = QSEE_CMD_UEFI_GET_NEXT_VARIABLE;
+       req_data->guid_offset = guid_offs;
+       req_data->guid_size = sizeof(*guid);
+       req_data->name_offset = name_offs;
+       req_data->name_size = *name_size;
+       req_data->length = req_size;
+
+       memcpy(((void *)req_data) + req_data->guid_offset, guid, req_data->guid_size);
+       status = ucs2_strscpy(((void *)req_data) + req_data->name_offset, name,
+                             *name_size / sizeof(*name));
+       if (status < 0)
+               return EFI_INVALID_PARAMETER;
+
+       status = qcom_qseecom_app_send(qcuefi->client, req_data, req_size, rsp_data, rsp_size);
+       if (status) {
+               efi_status = EFI_DEVICE_ERROR;
+               goto out_free;
+       }
+
+       if (rsp_data->command_id != QSEE_CMD_UEFI_GET_NEXT_VARIABLE) {
+               efi_status = EFI_DEVICE_ERROR;
+               goto out_free;
+       }
+
+       if (rsp_data->length < sizeof(*rsp_data)) {
+               efi_status = EFI_DEVICE_ERROR;
+               goto out_free;
+       }
+
+       if (rsp_data->status) {
+               dev_dbg(qcuefi_dev(qcuefi), "%s: uefisecapp error: 0x%x\n",
+                       __func__, rsp_data->status);
+               efi_status = qsee_uefi_status_to_efi(rsp_data->status);
+
+               /*
+                * If the buffer to hold the name is too small, update the
+                * name_size with the required size, so that callers can
+                * reallocate it accordingly.
+                */
+               if (efi_status == EFI_BUFFER_TOO_SMALL)
+                       *name_size = rsp_data->name_size;
+
+               goto out_free;
+       }
+
+       if (rsp_data->length > rsp_size) {
+               efi_status = EFI_DEVICE_ERROR;
+               goto out_free;
+       }
+
+       if (rsp_data->name_offset + rsp_data->name_size > rsp_data->length) {
+               efi_status = EFI_DEVICE_ERROR;
+               goto out_free;
+       }
+
+       if (rsp_data->guid_offset + rsp_data->guid_size > rsp_data->length) {
+               efi_status = EFI_DEVICE_ERROR;
+               goto out_free;
+       }
+
+       if (rsp_data->name_size > *name_size) {
+               *name_size = rsp_data->name_size;
+               efi_status = EFI_BUFFER_TOO_SMALL;
+               goto out_free;
+       }
+
+       if (rsp_data->guid_size != sizeof(*guid)) {
+               efi_status = EFI_DEVICE_ERROR;
+               goto out_free;
+       }
+
+       memcpy(guid, ((void *)rsp_data) + rsp_data->guid_offset, rsp_data->guid_size);
+       status = ucs2_strscpy(name, ((void *)rsp_data) + rsp_data->name_offset,
+                             rsp_data->name_size / sizeof(*name));
+       *name_size = rsp_data->name_size;
+
+       if (status < 0) {
+               /*
+                * Return EFI_DEVICE_ERROR here because the buffer size should
+                * have already been validated above, causing this function to
+                * bail with EFI_BUFFER_TOO_SMALL.
+                */
+               return EFI_DEVICE_ERROR;
+       }
+
+out_free:
+       kfree(rsp_data);
+out_free_req:
+       kfree(req_data);
+out:
+       return efi_status;
+}
+
+static efi_status_t qsee_uefi_query_variable_info(struct qcuefi_client *qcuefi, u32 attr,
+                                                 u64 *storage_space, u64 *remaining_space,
+                                                 u64 *max_variable_size)
+{
+       struct qsee_req_uefi_query_variable_info *req_data;
+       struct qsee_rsp_uefi_query_variable_info *rsp_data;
+       efi_status_t efi_status = EFI_SUCCESS;
+       int status;
+
+       req_data = kzalloc(sizeof(*req_data), GFP_KERNEL);
+       if (!req_data) {
+               efi_status = EFI_OUT_OF_RESOURCES;
+               goto out;
+       }
+
+       rsp_data = kzalloc(sizeof(*rsp_data), GFP_KERNEL);
+       if (!rsp_data) {
+               efi_status = EFI_OUT_OF_RESOURCES;
+               goto out_free_req;
+       }
+
+       req_data->command_id = QSEE_CMD_UEFI_QUERY_VARIABLE_INFO;
+       req_data->attributes = attr;
+       req_data->length = sizeof(*req_data);
+
+       status = qcom_qseecom_app_send(qcuefi->client, req_data, sizeof(*req_data), rsp_data,
+                                      sizeof(*rsp_data));
+       if (status) {
+               efi_status = EFI_DEVICE_ERROR;
+               goto out_free;
+       }
+
+       if (rsp_data->command_id != QSEE_CMD_UEFI_QUERY_VARIABLE_INFO) {
+               efi_status = EFI_DEVICE_ERROR;
+               goto out_free;
+       }
+
+       if (rsp_data->length != sizeof(*rsp_data)) {
+               efi_status = EFI_DEVICE_ERROR;
+               goto out_free;
+       }
+
+       if (rsp_data->status) {
+               dev_dbg(qcuefi_dev(qcuefi), "%s: uefisecapp error: 0x%x\n",
+                       __func__, rsp_data->status);
+               efi_status = qsee_uefi_status_to_efi(rsp_data->status);
+               goto out_free;
+       }
+
+       if (storage_space)
+               *storage_space = rsp_data->storage_space;
+
+       if (remaining_space)
+               *remaining_space = rsp_data->remaining_space;
+
+       if (max_variable_size)
+               *max_variable_size = rsp_data->max_variable_size;
+
+out_free:
+       kfree(rsp_data);
+out_free_req:
+       kfree(req_data);
+out:
+       return efi_status;
+}
+
+/* -- Global efivar interface. ---------------------------------------------- */
+
+static struct qcuefi_client *__qcuefi;
+static DEFINE_MUTEX(__qcuefi_lock);
+
+static int qcuefi_set_reference(struct qcuefi_client *qcuefi)
+{
+       mutex_lock(&__qcuefi_lock);
+
+       if (qcuefi && __qcuefi) {
+               mutex_unlock(&__qcuefi_lock);
+               return -EEXIST;
+       }
+
+       __qcuefi = qcuefi;
+
+       mutex_unlock(&__qcuefi_lock);
+       return 0;
+}
+
+static struct qcuefi_client *qcuefi_acquire(void)
+{
+       mutex_lock(&__qcuefi_lock);
+       return __qcuefi;
+}
+
+static void qcuefi_release(void)
+{
+       mutex_unlock(&__qcuefi_lock);
+}
+
+static efi_status_t qcuefi_get_variable(efi_char16_t *name, efi_guid_t *vendor, u32 *attr,
+                                       unsigned long *data_size, void *data)
+{
+       struct qcuefi_client *qcuefi;
+       efi_status_t status;
+
+       qcuefi = qcuefi_acquire();
+       if (!qcuefi)
+               return EFI_NOT_READY;
+
+       status = qsee_uefi_get_variable(qcuefi, name, vendor, attr, data_size, data);
+
+       qcuefi_release();
+       return status;
+}
+
+static efi_status_t qcuefi_set_variable(efi_char16_t *name, efi_guid_t *vendor,
+                                       u32 attr, unsigned long data_size, void *data)
+{
+       struct qcuefi_client *qcuefi;
+       efi_status_t status;
+
+       qcuefi = qcuefi_acquire();
+       if (!qcuefi)
+               return EFI_NOT_READY;
+
+       status = qsee_uefi_set_variable(qcuefi, name, vendor, attr, data_size, data);
+
+       qcuefi_release();
+       return status;
+}
+
+static efi_status_t qcuefi_get_next_variable(unsigned long *name_size, efi_char16_t *name,
+                                            efi_guid_t *vendor)
+{
+       struct qcuefi_client *qcuefi;
+       efi_status_t status;
+
+       qcuefi = qcuefi_acquire();
+       if (!qcuefi)
+               return EFI_NOT_READY;
+
+       status = qsee_uefi_get_next_variable(qcuefi, name_size, name, vendor);
+
+       qcuefi_release();
+       return status;
+}
+
+static efi_status_t qcuefi_query_variable_info(u32 attr, u64 *storage_space, u64 *remaining_space,
+                                              u64 *max_variable_size)
+{
+       struct qcuefi_client *qcuefi;
+       efi_status_t status;
+
+       qcuefi = qcuefi_acquire();
+       if (!qcuefi)
+               return EFI_NOT_READY;
+
+       status = qsee_uefi_query_variable_info(qcuefi, attr, storage_space, remaining_space,
+                                              max_variable_size);
+
+       qcuefi_release();
+       return status;
+}
+
+static const struct efivar_operations qcom_efivar_ops = {
+       .get_variable = qcuefi_get_variable,
+       .set_variable = qcuefi_set_variable,
+       .get_next_variable = qcuefi_get_next_variable,
+       .query_variable_info = qcuefi_query_variable_info,
+};
+
+/* -- Driver setup. --------------------------------------------------------- */
+
+static int qcom_uefisecapp_probe(struct auxiliary_device *aux_dev,
+                                const struct auxiliary_device_id *aux_dev_id)
+{
+       struct qcuefi_client *qcuefi;
+       int status;
+
+       qcuefi = devm_kzalloc(&aux_dev->dev, sizeof(*qcuefi), GFP_KERNEL);
+       if (!qcuefi)
+               return -ENOMEM;
+
+       qcuefi->client = container_of(aux_dev, struct qseecom_client, aux_dev);
+
+       auxiliary_set_drvdata(aux_dev, qcuefi);
+       status = qcuefi_set_reference(qcuefi);
+       if (status)
+               return status;
+
+       status = efivars_register(&qcuefi->efivars, &qcom_efivar_ops);
+       if (status)
+               qcuefi_set_reference(NULL);
+
+       return status;
+}
+
+static void qcom_uefisecapp_remove(struct auxiliary_device *aux_dev)
+{
+       struct qcuefi_client *qcuefi = auxiliary_get_drvdata(aux_dev);
+
+       efivars_unregister(&qcuefi->efivars);
+       qcuefi_set_reference(NULL);
+}
+
+static const struct auxiliary_device_id qcom_uefisecapp_id_table[] = {
+       { .name = "qcom_qseecom.uefisecapp" },
+       {}
+};
+MODULE_DEVICE_TABLE(auxiliary, qcom_uefisecapp_id_table);
+
+static struct auxiliary_driver qcom_uefisecapp_driver = {
+       .probe = qcom_uefisecapp_probe,
+       .remove = qcom_uefisecapp_remove,
+       .id_table = qcom_uefisecapp_id_table,
+       .driver = {
+               .name = "qcom_qseecom_uefisecapp",
+               .probe_type = PROBE_PREFER_ASYNCHRONOUS,
+       },
+};
+module_auxiliary_driver(qcom_uefisecapp_driver);
+
+MODULE_AUTHOR("Maximilian Luz <luzmaximilian@gmail.com>");
+MODULE_DESCRIPTION("Client driver for Qualcomm SEE UEFI Secure App");
+MODULE_LICENSE("GPL");
diff --git a/drivers/firmware/qcom/qcom_scm-legacy.c b/drivers/firmware/qcom/qcom_scm-legacy.c
new file mode 100644 (file)
index 0000000..029e6d1
--- /dev/null
@@ -0,0 +1,246 @@
+// 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/firmware/qcom/qcom_scm.h>
+#include <linux/arm-smccc.h>
+#include <linux/dma-mapping.h>
+
+#include "qcom_scm.h"
+
+static DEFINE_MUTEX(qcom_scm_lock);
+
+
+/**
+ * struct arm_smccc_args
+ * @args:      The array of values used in registers in smc instruction
+ */
+struct arm_smccc_args {
+       unsigned long args[8];
+};
+
+
+/**
+ * struct scm_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 scm_legacy_get_command_buffer()
+ *
+ * An SCM command is laid out in memory as follows:
+ *
+ *     ------------------- <--- struct scm_legacy_command
+ *     | command header  |
+ *     ------------------- <--- scm_legacy_get_command_buffer()
+ *     | command buffer  |
+ *     ------------------- <--- struct scm_legacy_response and
+ *     | response header |      scm_legacy_command_to_response()
+ *     ------------------- <--- scm_legacy_get_response_buffer()
+ *     | response buffer |
+ *     -------------------
+ *
+ * There can be arbitrary padding between the headers and buffers so
+ * you should always use the appropriate scm_legacy_get_*_buffer() routines
+ * to access the buffers in a safe manner.
+ */
+struct scm_legacy_command {
+       __le32 len;
+       __le32 buf_offset;
+       __le32 resp_hdr_offset;
+       __le32 id;
+       __le32 buf[];
+};
+
+/**
+ * struct scm_legacy_response - one SCM response buffer
+ * @len: total available memory for response
+ * @buf_offset: start of response data relative to start of scm_legacy_response
+ * @is_complete: indicates if the command has finished processing
+ */
+struct scm_legacy_response {
+       __le32 len;
+       __le32 buf_offset;
+       __le32 is_complete;
+};
+
+/**
+ * scm_legacy_command_to_response() - Get a pointer to a scm_legacy_response
+ * @cmd: command
+ *
+ * Returns a pointer to a response for a command.
+ */
+static inline struct scm_legacy_response *scm_legacy_command_to_response(
+               const struct scm_legacy_command *cmd)
+{
+       return (void *)cmd + le32_to_cpu(cmd->resp_hdr_offset);
+}
+
+/**
+ * scm_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 *scm_legacy_get_command_buffer(
+               const struct scm_legacy_command *cmd)
+{
+       return (void *)cmd->buf;
+}
+
+/**
+ * scm_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 *scm_legacy_get_response_buffer(
+               const struct scm_legacy_response *rsp)
+{
+       return (void *)rsp + le32_to_cpu(rsp->buf_offset);
+}
+
+static void __scm_legacy_do(const struct arm_smccc_args *smc,
+                           struct arm_smccc_res *res)
+{
+       do {
+               arm_smccc_smc(smc->args[0], smc->args[1], smc->args[2],
+                             smc->args[3], smc->args[4], smc->args[5],
+                             smc->args[6], smc->args[7], res);
+       } while (res->a0 == QCOM_SCM_INTERRUPTED);
+}
+
+/**
+ * scm_legacy_call() - Sends a command to the SCM and waits for the command to
+ * finish processing.
+ * @dev:       device
+ * @desc:      descriptor structure containing arguments and return values
+ * @res:        results from SMC call
+ *
+ * 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.
+ */
+int scm_legacy_call(struct device *dev, const struct qcom_scm_desc *desc,
+                   struct qcom_scm_res *res)
+{
+       u8 arglen = desc->arginfo & 0xf;
+       int ret = 0, context_id;
+       unsigned int i;
+       struct scm_legacy_command *cmd;
+       struct scm_legacy_response *rsp;
+       struct arm_smccc_args smc = {0};
+       struct arm_smccc_res smc_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;
+       const __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(SCM_LEGACY_FNID(desc->svc, desc->cmd));
+
+       arg_buf = scm_legacy_get_command_buffer(cmd);
+       for (i = 0; i < arglen; i++)
+               arg_buf[i] = cpu_to_le32(desc->args[i]);
+
+       rsp = scm_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.args[0] = 1;
+       smc.args[1] = (unsigned long)&context_id;
+       smc.args[2] = cmd_phys;
+
+       mutex_lock(&qcom_scm_lock);
+       __scm_legacy_do(&smc, &smc_res);
+       if (smc_res.a0)
+               ret = qcom_scm_remap_error(smc_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);
+
+       if (res) {
+               res_buf = scm_legacy_get_response_buffer(rsp);
+               for (i = 0; i < MAX_QCOM_SCM_RETS; i++)
+                       res->result[i] = le32_to_cpu(res_buf[i]);
+       }
+out:
+       dma_unmap_single(dev, cmd_phys, alloc_len, DMA_TO_DEVICE);
+       kfree(cmd);
+       return ret;
+}
+
+#define SCM_LEGACY_ATOMIC_N_REG_ARGS   5
+#define SCM_LEGACY_ATOMIC_FIRST_REG_IDX        2
+#define SCM_LEGACY_CLASS_REGISTER              (0x2 << 8)
+#define SCM_LEGACY_MASK_IRQS           BIT(5)
+#define SCM_LEGACY_ATOMIC_ID(svc, cmd, n) \
+                               ((SCM_LEGACY_FNID(svc, cmd) << 12) | \
+                               SCM_LEGACY_CLASS_REGISTER | \
+                               SCM_LEGACY_MASK_IRQS | \
+                               (n & 0xf))
+
+/**
+ * scm_legacy_call_atomic() - Send an atomic SCM command with up to 5 arguments
+ * and 3 return values
+ * @unused: device, legacy argument, not used, can be NULL
+ * @desc: SCM call descriptor containing arguments
+ * @res:  SCM call return values
+ *
+ * This shall only be used with commands that are guaranteed to be
+ * uninterruptable, atomic and SMP safe.
+ */
+int scm_legacy_call_atomic(struct device *unused,
+                          const struct qcom_scm_desc *desc,
+                          struct qcom_scm_res *res)
+{
+       int context_id;
+       struct arm_smccc_res smc_res;
+       size_t arglen = desc->arginfo & 0xf;
+
+       BUG_ON(arglen > SCM_LEGACY_ATOMIC_N_REG_ARGS);
+
+       arm_smccc_smc(SCM_LEGACY_ATOMIC_ID(desc->svc, desc->cmd, arglen),
+                     (unsigned long)&context_id,
+                     desc->args[0], desc->args[1], desc->args[2],
+                     desc->args[3], desc->args[4], 0, &smc_res);
+
+       if (res) {
+               res->result[0] = smc_res.a1;
+               res->result[1] = smc_res.a2;
+               res->result[2] = smc_res.a3;
+       }
+
+       return smc_res.a0;
+}
diff --git a/drivers/firmware/qcom/qcom_scm-smc.c b/drivers/firmware/qcom/qcom_scm-smc.c
new file mode 100644 (file)
index 0000000..16cf88a
--- /dev/null
@@ -0,0 +1,225 @@
+// 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/firmware/qcom/qcom_scm.h>
+#include <linux/arm-smccc.h>
+#include <linux/dma-mapping.h>
+
+#include "qcom_scm.h"
+
+/**
+ * struct arm_smccc_args
+ * @args:      The array of values used in registers in smc instruction
+ */
+struct arm_smccc_args {
+       unsigned long args[8];
+};
+
+static DEFINE_MUTEX(qcom_scm_lock);
+
+#define QCOM_SCM_EBUSY_WAIT_MS 30
+#define QCOM_SCM_EBUSY_MAX_RETRY 20
+
+#define SCM_SMC_N_REG_ARGS     4
+#define SCM_SMC_FIRST_EXT_IDX  (SCM_SMC_N_REG_ARGS - 1)
+#define SCM_SMC_N_EXT_ARGS     (MAX_QCOM_SCM_ARGS - SCM_SMC_N_REG_ARGS + 1)
+#define SCM_SMC_FIRST_REG_IDX  2
+#define SCM_SMC_LAST_REG_IDX   (SCM_SMC_FIRST_REG_IDX + SCM_SMC_N_REG_ARGS - 1)
+
+static void __scm_smc_do_quirk(const struct arm_smccc_args *smc,
+                              struct arm_smccc_res *res)
+{
+       unsigned long a0 = smc->args[0];
+       struct arm_smccc_quirk quirk = { .id = ARM_SMCCC_QUIRK_QCOM_A6 };
+
+       quirk.state.a6 = 0;
+
+       do {
+               arm_smccc_smc_quirk(a0, smc->args[1], smc->args[2],
+                                   smc->args[3], smc->args[4], smc->args[5],
+                                   quirk.state.a6, smc->args[7], res, &quirk);
+
+               if (res->a0 == QCOM_SCM_INTERRUPTED)
+                       a0 = res->a0;
+
+       } while (res->a0 == QCOM_SCM_INTERRUPTED);
+}
+
+static void fill_wq_resume_args(struct arm_smccc_args *resume, u32 smc_call_ctx)
+{
+       memset(resume->args, 0, sizeof(resume->args[0]) * ARRAY_SIZE(resume->args));
+
+       resume->args[0] = ARM_SMCCC_CALL_VAL(ARM_SMCCC_STD_CALL,
+                                       ARM_SMCCC_SMC_64, ARM_SMCCC_OWNER_SIP,
+                                       SCM_SMC_FNID(QCOM_SCM_SVC_WAITQ, QCOM_SCM_WAITQ_RESUME));
+
+       resume->args[1] = QCOM_SCM_ARGS(1);
+
+       resume->args[2] = smc_call_ctx;
+}
+
+int scm_get_wq_ctx(u32 *wq_ctx, u32 *flags, u32 *more_pending)
+{
+       int ret;
+       struct arm_smccc_res get_wq_res;
+       struct arm_smccc_args get_wq_ctx = {0};
+
+       get_wq_ctx.args[0] = ARM_SMCCC_CALL_VAL(ARM_SMCCC_STD_CALL,
+                               ARM_SMCCC_SMC_64, ARM_SMCCC_OWNER_SIP,
+                               SCM_SMC_FNID(QCOM_SCM_SVC_WAITQ, QCOM_SCM_WAITQ_GET_WQ_CTX));
+
+       /* Guaranteed to return only success or error, no WAITQ_* */
+       __scm_smc_do_quirk(&get_wq_ctx, &get_wq_res);
+       ret = get_wq_res.a0;
+       if (ret)
+               return ret;
+
+       *wq_ctx = get_wq_res.a1;
+       *flags  = get_wq_res.a2;
+       *more_pending = get_wq_res.a3;
+
+       return 0;
+}
+
+static int __scm_smc_do_quirk_handle_waitq(struct device *dev, struct arm_smccc_args *waitq,
+                                          struct arm_smccc_res *res)
+{
+       int ret;
+       u32 wq_ctx, smc_call_ctx;
+       struct arm_smccc_args resume;
+       struct arm_smccc_args *smc = waitq;
+
+       do {
+               __scm_smc_do_quirk(smc, res);
+
+               if (res->a0 == QCOM_SCM_WAITQ_SLEEP) {
+                       wq_ctx = res->a1;
+                       smc_call_ctx = res->a2;
+
+                       ret = qcom_scm_wait_for_wq_completion(wq_ctx);
+                       if (ret)
+                               return ret;
+
+                       fill_wq_resume_args(&resume, smc_call_ctx);
+                       smc = &resume;
+               }
+       } while (res->a0 == QCOM_SCM_WAITQ_SLEEP);
+
+       return 0;
+}
+
+static int __scm_smc_do(struct device *dev, struct arm_smccc_args *smc,
+                       struct arm_smccc_res *res, bool atomic)
+{
+       int ret, retry_count = 0;
+
+       if (atomic) {
+               __scm_smc_do_quirk(smc, res);
+               return 0;
+       }
+
+       do {
+               mutex_lock(&qcom_scm_lock);
+
+               ret = __scm_smc_do_quirk_handle_waitq(dev, smc, res);
+
+               mutex_unlock(&qcom_scm_lock);
+
+               if (ret)
+                       return ret;
+
+               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);
+
+       return 0;
+}
+
+
+int __scm_smc_call(struct device *dev, const struct qcom_scm_desc *desc,
+                  enum qcom_scm_convention qcom_convention,
+                  struct qcom_scm_res *res, bool atomic)
+{
+       int arglen = desc->arginfo & 0xf;
+       int i, ret;
+       dma_addr_t args_phys = 0;
+       void *args_virt = NULL;
+       size_t alloc_len;
+       gfp_t flag = atomic ? GFP_ATOMIC : GFP_KERNEL;
+       u32 smccc_call_type = atomic ? ARM_SMCCC_FAST_CALL : ARM_SMCCC_STD_CALL;
+       u32 qcom_smccc_convention = (qcom_convention == SMC_CONVENTION_ARM_32) ?
+                                   ARM_SMCCC_SMC_32 : ARM_SMCCC_SMC_64;
+       struct arm_smccc_res smc_res;
+       struct arm_smccc_args smc = {0};
+
+       smc.args[0] = ARM_SMCCC_CALL_VAL(
+               smccc_call_type,
+               qcom_smccc_convention,
+               desc->owner,
+               SCM_SMC_FNID(desc->svc, desc->cmd));
+       smc.args[1] = desc->arginfo;
+       for (i = 0; i < SCM_SMC_N_REG_ARGS; i++)
+               smc.args[i + SCM_SMC_FIRST_REG_IDX] = desc->args[i];
+
+       if (unlikely(arglen > SCM_SMC_N_REG_ARGS)) {
+               alloc_len = SCM_SMC_N_EXT_ARGS * sizeof(u64);
+               args_virt = kzalloc(PAGE_ALIGN(alloc_len), flag);
+
+               if (!args_virt)
+                       return -ENOMEM;
+
+               if (qcom_smccc_convention == ARM_SMCCC_SMC_32) {
+                       __le32 *args = args_virt;
+
+                       for (i = 0; i < SCM_SMC_N_EXT_ARGS; i++)
+                               args[i] = cpu_to_le32(desc->args[i +
+                                                     SCM_SMC_FIRST_EXT_IDX]);
+               } else {
+                       __le64 *args = args_virt;
+
+                       for (i = 0; i < SCM_SMC_N_EXT_ARGS; i++)
+                               args[i] = cpu_to_le64(desc->args[i +
+                                                     SCM_SMC_FIRST_EXT_IDX]);
+               }
+
+               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.args[SCM_SMC_LAST_REG_IDX] = args_phys;
+       }
+
+       /* ret error check follows after args_virt cleanup*/
+       ret = __scm_smc_do(dev, &smc, &smc_res, atomic);
+
+       if (args_virt) {
+               dma_unmap_single(dev, args_phys, alloc_len, DMA_TO_DEVICE);
+               kfree(args_virt);
+       }
+
+       if (ret)
+               return ret;
+
+       if (res) {
+               res->result[0] = smc_res.a1;
+               res->result[1] = smc_res.a2;
+               res->result[2] = smc_res.a3;
+       }
+
+       return (long)smc_res.a0 ? qcom_scm_remap_error(smc_res.a0) : 0;
+
+}
diff --git a/drivers/firmware/qcom/qcom_scm.c b/drivers/firmware/qcom/qcom_scm.c
new file mode 100644 (file)
index 0000000..520de9b
--- /dev/null
@@ -0,0 +1,1943 @@
+// 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/arm-smccc.h>
+#include <linux/clk.h>
+#include <linux/completion.h>
+#include <linux/cpumask.h>
+#include <linux/dma-mapping.h>
+#include <linux/export.h>
+#include <linux/firmware/qcom/qcom_scm.h>
+#include <linux/init.h>
+#include <linux/interconnect.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/reset-controller.h>
+#include <linux/types.h>
+
+#include "qcom_scm.h"
+
+static bool download_mode = IS_ENABLED(CONFIG_QCOM_SCM_DOWNLOAD_MODE_DEFAULT);
+module_param(download_mode, bool, 0);
+
+struct qcom_scm {
+       struct device *dev;
+       struct clk *core_clk;
+       struct clk *iface_clk;
+       struct clk *bus_clk;
+       struct icc_path *path;
+       struct completion waitq_comp;
+       struct reset_controller_dev reset;
+
+       /* control access to the interconnect path */
+       struct mutex scm_bw_lock;
+       int scm_vote_count;
+
+       u64 dload_mode_addr;
+};
+
+struct qcom_scm_current_perm_info {
+       __le32 vmid;
+       __le32 perm;
+       __le64 ctx;
+       __le32 ctx_size;
+       __le32 unused;
+};
+
+struct qcom_scm_mem_map_info {
+       __le64 mem_addr;
+       __le64 mem_size;
+};
+
+/**
+ * struct qcom_scm_qseecom_resp - QSEECOM SCM call response.
+ * @result:    Result or status of the SCM call. See &enum qcom_scm_qseecom_result.
+ * @resp_type: Type of the response. See &enum qcom_scm_qseecom_resp_type.
+ * @data:      Response data. The type of this data is given in @resp_type.
+ */
+struct qcom_scm_qseecom_resp {
+       u64 result;
+       u64 resp_type;
+       u64 data;
+};
+
+enum qcom_scm_qseecom_result {
+       QSEECOM_RESULT_SUCCESS                  = 0,
+       QSEECOM_RESULT_INCOMPLETE               = 1,
+       QSEECOM_RESULT_BLOCKED_ON_LISTENER      = 2,
+       QSEECOM_RESULT_FAILURE                  = 0xFFFFFFFF,
+};
+
+enum qcom_scm_qseecom_resp_type {
+       QSEECOM_SCM_RES_APP_ID                  = 0xEE01,
+       QSEECOM_SCM_RES_QSEOS_LISTENER_ID       = 0xEE02,
+};
+
+enum qcom_scm_qseecom_tz_owner {
+       QSEECOM_TZ_OWNER_SIP                    = 2,
+       QSEECOM_TZ_OWNER_TZ_APPS                = 48,
+       QSEECOM_TZ_OWNER_QSEE_OS                = 50
+};
+
+enum qcom_scm_qseecom_tz_svc {
+       QSEECOM_TZ_SVC_APP_ID_PLACEHOLDER       = 0,
+       QSEECOM_TZ_SVC_APP_MGR                  = 1,
+       QSEECOM_TZ_SVC_INFO                     = 6,
+};
+
+enum qcom_scm_qseecom_tz_cmd_app {
+       QSEECOM_TZ_CMD_APP_SEND                 = 1,
+       QSEECOM_TZ_CMD_APP_LOOKUP               = 3,
+};
+
+enum qcom_scm_qseecom_tz_cmd_info {
+       QSEECOM_TZ_CMD_INFO_VERSION             = 3,
+};
+
+#define QSEECOM_MAX_APP_NAME_SIZE              64
+
+/* Each bit configures cold/warm boot address for one of the 4 CPUs */
+static const u8 qcom_scm_cpu_cold_bits[QCOM_SCM_BOOT_MAX_CPUS] = {
+       0, BIT(0), BIT(3), BIT(5)
+};
+static const u8 qcom_scm_cpu_warm_bits[QCOM_SCM_BOOT_MAX_CPUS] = {
+       BIT(2), BIT(1), BIT(4), BIT(6)
+};
+
+#define QCOM_SMC_WAITQ_FLAG_WAKE_ONE   BIT(0)
+#define QCOM_SMC_WAITQ_FLAG_WAKE_ALL   BIT(1)
+
+static const char * const qcom_scm_convention_names[] = {
+       [SMC_CONVENTION_UNKNOWN] = "unknown",
+       [SMC_CONVENTION_ARM_32] = "smc arm 32",
+       [SMC_CONVENTION_ARM_64] = "smc arm 64",
+       [SMC_CONVENTION_LEGACY] = "smc legacy",
+};
+
+static struct qcom_scm *__scm;
+
+static int qcom_scm_clk_enable(void)
+{
+       int ret;
+
+       ret = clk_prepare_enable(__scm->core_clk);
+       if (ret)
+               goto bail;
+
+       ret = clk_prepare_enable(__scm->iface_clk);
+       if (ret)
+               goto disable_core;
+
+       ret = clk_prepare_enable(__scm->bus_clk);
+       if (ret)
+               goto disable_iface;
+
+       return 0;
+
+disable_iface:
+       clk_disable_unprepare(__scm->iface_clk);
+disable_core:
+       clk_disable_unprepare(__scm->core_clk);
+bail:
+       return ret;
+}
+
+static void qcom_scm_clk_disable(void)
+{
+       clk_disable_unprepare(__scm->core_clk);
+       clk_disable_unprepare(__scm->iface_clk);
+       clk_disable_unprepare(__scm->bus_clk);
+}
+
+static int qcom_scm_bw_enable(void)
+{
+       int ret = 0;
+
+       if (!__scm->path)
+               return 0;
+
+       if (IS_ERR(__scm->path))
+               return -EINVAL;
+
+       mutex_lock(&__scm->scm_bw_lock);
+       if (!__scm->scm_vote_count) {
+               ret = icc_set_bw(__scm->path, 0, UINT_MAX);
+               if (ret < 0) {
+                       dev_err(__scm->dev, "failed to set bandwidth request\n");
+                       goto err_bw;
+               }
+       }
+       __scm->scm_vote_count++;
+err_bw:
+       mutex_unlock(&__scm->scm_bw_lock);
+
+       return ret;
+}
+
+static void qcom_scm_bw_disable(void)
+{
+       if (IS_ERR_OR_NULL(__scm->path))
+               return;
+
+       mutex_lock(&__scm->scm_bw_lock);
+       if (__scm->scm_vote_count-- == 1)
+               icc_set_bw(__scm->path, 0, 0);
+       mutex_unlock(&__scm->scm_bw_lock);
+}
+
+enum qcom_scm_convention qcom_scm_convention = SMC_CONVENTION_UNKNOWN;
+static DEFINE_SPINLOCK(scm_query_lock);
+
+static enum qcom_scm_convention __get_convention(void)
+{
+       unsigned long flags;
+       struct qcom_scm_desc desc = {
+               .svc = QCOM_SCM_SVC_INFO,
+               .cmd = QCOM_SCM_INFO_IS_CALL_AVAIL,
+               .args[0] = SCM_SMC_FNID(QCOM_SCM_SVC_INFO,
+                                          QCOM_SCM_INFO_IS_CALL_AVAIL) |
+                          (ARM_SMCCC_OWNER_SIP << ARM_SMCCC_OWNER_SHIFT),
+               .arginfo = QCOM_SCM_ARGS(1),
+               .owner = ARM_SMCCC_OWNER_SIP,
+       };
+       struct qcom_scm_res res;
+       enum qcom_scm_convention probed_convention;
+       int ret;
+       bool forced = false;
+
+       if (likely(qcom_scm_convention != SMC_CONVENTION_UNKNOWN))
+               return qcom_scm_convention;
+
+       /*
+        * Per the "SMC calling convention specification", the 64-bit calling
+        * convention can only be used when the client is 64-bit, otherwise
+        * system will encounter the undefined behaviour.
+        */
+#if IS_ENABLED(CONFIG_ARM64)
+       /*
+        * Device isn't required as there is only one argument - no device
+        * needed to dma_map_single to secure world
+        */
+       probed_convention = SMC_CONVENTION_ARM_64;
+       ret = __scm_smc_call(NULL, &desc, probed_convention, &res, true);
+       if (!ret && res.result[0] == 1)
+               goto found;
+
+       /*
+        * Some SC7180 firmwares didn't implement the
+        * QCOM_SCM_INFO_IS_CALL_AVAIL call, so we fallback to forcing ARM_64
+        * calling conventions on these firmwares. Luckily we don't make any
+        * early calls into the firmware on these SoCs so the device pointer
+        * will be valid here to check if the compatible matches.
+        */
+       if (of_device_is_compatible(__scm ? __scm->dev->of_node : NULL, "qcom,scm-sc7180")) {
+               forced = true;
+               goto found;
+       }
+#endif
+
+       probed_convention = SMC_CONVENTION_ARM_32;
+       ret = __scm_smc_call(NULL, &desc, probed_convention, &res, true);
+       if (!ret && res.result[0] == 1)
+               goto found;
+
+       probed_convention = SMC_CONVENTION_LEGACY;
+found:
+       spin_lock_irqsave(&scm_query_lock, flags);
+       if (probed_convention != qcom_scm_convention) {
+               qcom_scm_convention = probed_convention;
+               pr_info("qcom_scm: convention: %s%s\n",
+                       qcom_scm_convention_names[qcom_scm_convention],
+                       forced ? " (forced)" : "");
+       }
+       spin_unlock_irqrestore(&scm_query_lock, flags);
+
+       return qcom_scm_convention;
+}
+
+/**
+ * qcom_scm_call() - Invoke a syscall in the secure world
+ * @dev:       device
+ * @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 should *only* be called in pre-emptible context.
+ */
+static int qcom_scm_call(struct device *dev, const struct qcom_scm_desc *desc,
+                        struct qcom_scm_res *res)
+{
+       might_sleep();
+       switch (__get_convention()) {
+       case SMC_CONVENTION_ARM_32:
+       case SMC_CONVENTION_ARM_64:
+               return scm_smc_call(dev, desc, res, false);
+       case SMC_CONVENTION_LEGACY:
+               return scm_legacy_call(dev, desc, res);
+       default:
+               pr_err("Unknown current SCM calling convention.\n");
+               return -EINVAL;
+       }
+}
+
+/**
+ * qcom_scm_call_atomic() - atomic variation of qcom_scm_call()
+ * @dev:       device
+ * @desc:      Descriptor structure containing arguments and return values
+ * @res:       Structure containing results from SMC/HVC call
+ *
+ * Sends a command to the SCM and waits for the command to finish processing.
+ * This can be called in atomic context.
+ */
+static int qcom_scm_call_atomic(struct device *dev,
+                               const struct qcom_scm_desc *desc,
+                               struct qcom_scm_res *res)
+{
+       switch (__get_convention()) {
+       case SMC_CONVENTION_ARM_32:
+       case SMC_CONVENTION_ARM_64:
+               return scm_smc_call(dev, desc, res, true);
+       case SMC_CONVENTION_LEGACY:
+               return scm_legacy_call_atomic(dev, desc, res);
+       default:
+               pr_err("Unknown current SCM calling convention.\n");
+               return -EINVAL;
+       }
+}
+
+static bool __qcom_scm_is_call_available(struct device *dev, u32 svc_id,
+                                        u32 cmd_id)
+{
+       int ret;
+       struct qcom_scm_desc desc = {
+               .svc = QCOM_SCM_SVC_INFO,
+               .cmd = QCOM_SCM_INFO_IS_CALL_AVAIL,
+               .owner = ARM_SMCCC_OWNER_SIP,
+       };
+       struct qcom_scm_res res;
+
+       desc.arginfo = QCOM_SCM_ARGS(1);
+       switch (__get_convention()) {
+       case SMC_CONVENTION_ARM_32:
+       case SMC_CONVENTION_ARM_64:
+               desc.args[0] = SCM_SMC_FNID(svc_id, cmd_id) |
+                               (ARM_SMCCC_OWNER_SIP << ARM_SMCCC_OWNER_SHIFT);
+               break;
+       case SMC_CONVENTION_LEGACY:
+               desc.args[0] = SCM_LEGACY_FNID(svc_id, cmd_id);
+               break;
+       default:
+               pr_err("Unknown SMC convention being used\n");
+               return false;
+       }
+
+       ret = qcom_scm_call(dev, &desc, &res);
+
+       return ret ? false : !!res.result[0];
+}
+
+static int qcom_scm_set_boot_addr(void *entry, const u8 *cpu_bits)
+{
+       int cpu;
+       unsigned int flags = 0;
+       struct qcom_scm_desc desc = {
+               .svc = QCOM_SCM_SVC_BOOT,
+               .cmd = QCOM_SCM_BOOT_SET_ADDR,
+               .arginfo = QCOM_SCM_ARGS(2),
+               .owner = ARM_SMCCC_OWNER_SIP,
+       };
+
+       for_each_present_cpu(cpu) {
+               if (cpu >= QCOM_SCM_BOOT_MAX_CPUS)
+                       return -EINVAL;
+               flags |= cpu_bits[cpu];
+       }
+
+       desc.args[0] = flags;
+       desc.args[1] = virt_to_phys(entry);
+
+       return qcom_scm_call_atomic(__scm ? __scm->dev : NULL, &desc, NULL);
+}
+
+static int qcom_scm_set_boot_addr_mc(void *entry, unsigned int flags)
+{
+       struct qcom_scm_desc desc = {
+               .svc = QCOM_SCM_SVC_BOOT,
+               .cmd = QCOM_SCM_BOOT_SET_ADDR_MC,
+               .owner = ARM_SMCCC_OWNER_SIP,
+               .arginfo = QCOM_SCM_ARGS(6),
+               .args = {
+                       virt_to_phys(entry),
+                       /* Apply to all CPUs in all affinity levels */
+                       ~0ULL, ~0ULL, ~0ULL, ~0ULL,
+                       flags,
+               },
+       };
+
+       /* Need a device for DMA of the additional arguments */
+       if (!__scm || __get_convention() == SMC_CONVENTION_LEGACY)
+               return -EOPNOTSUPP;
+
+       return qcom_scm_call(__scm->dev, &desc, NULL);
+}
+
+/**
+ * qcom_scm_set_warm_boot_addr() - Set the warm boot address for all cpus
+ * @entry: Entry point function for the cpus
+ *
+ * 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(void *entry)
+{
+       if (qcom_scm_set_boot_addr_mc(entry, QCOM_SCM_BOOT_MC_FLAG_WARMBOOT))
+               /* Fallback to old SCM call */
+               return qcom_scm_set_boot_addr(entry, qcom_scm_cpu_warm_bits);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(qcom_scm_set_warm_boot_addr);
+
+/**
+ * qcom_scm_set_cold_boot_addr() - Set the cold boot address for all cpus
+ * @entry: Entry point function for the cpus
+ */
+int qcom_scm_set_cold_boot_addr(void *entry)
+{
+       if (qcom_scm_set_boot_addr_mc(entry, QCOM_SCM_BOOT_MC_FLAG_COLDBOOT))
+               /* Fallback to old SCM call */
+               return qcom_scm_set_boot_addr(entry, qcom_scm_cpu_cold_bits);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(qcom_scm_set_cold_boot_addr);
+
+/**
+ * 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(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(__scm ? __scm->dev : NULL, &desc, NULL);
+}
+EXPORT_SYMBOL_GPL(qcom_scm_cpu_power_down);
+
+int qcom_scm_set_remote_state(u32 state, u32 id)
+{
+       struct qcom_scm_desc desc = {
+               .svc = QCOM_SCM_SVC_BOOT,
+               .cmd = QCOM_SCM_BOOT_SET_REMOTE_STATE,
+               .arginfo = QCOM_SCM_ARGS(2),
+               .args[0] = state,
+               .args[1] = id,
+               .owner = ARM_SMCCC_OWNER_SIP,
+       };
+       struct qcom_scm_res res;
+       int ret;
+
+       ret = qcom_scm_call(__scm->dev, &desc, &res);
+
+       return ret ? : res.result[0];
+}
+EXPORT_SYMBOL_GPL(qcom_scm_set_remote_state);
+
+static int qcom_scm_disable_sdi(void)
+{
+       int ret;
+       struct qcom_scm_desc desc = {
+               .svc = QCOM_SCM_SVC_BOOT,
+               .cmd = QCOM_SCM_BOOT_SDI_CONFIG,
+               .args[0] = 1, /* Disable watchdog debug */
+               .args[1] = 0, /* Disable SDI */
+               .arginfo = QCOM_SCM_ARGS(2),
+               .owner = ARM_SMCCC_OWNER_SIP,
+       };
+       struct qcom_scm_res res;
+
+       ret = qcom_scm_clk_enable();
+       if (ret)
+               return ret;
+       ret = qcom_scm_call(__scm->dev, &desc, &res);
+
+       qcom_scm_clk_disable();
+
+       return ret ? : res.result[0];
+}
+
+static 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,
+               .arginfo = QCOM_SCM_ARGS(2),
+               .args[0] = QCOM_SCM_BOOT_SET_DLOAD_MODE,
+               .owner = ARM_SMCCC_OWNER_SIP,
+       };
+
+       desc.args[1] = enable ? QCOM_SCM_BOOT_SET_DLOAD_MODE : 0;
+
+       return qcom_scm_call_atomic(__scm->dev, &desc, NULL);
+}
+
+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->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);
+}
+
+/**
+ * qcom_scm_pas_init_image() - Initialize peripheral authentication service
+ *                            state machine for a given peripheral, using the
+ *                            metadata
+ * @peripheral: peripheral id
+ * @metadata:  pointer to memory containing ELF header, program header table
+ *             and optional blob of data used for authenticating the metadata
+ *             and the rest of the firmware
+ * @size:      size of the metadata
+ * @ctx:       optional metadata context
+ *
+ * Return: 0 on success.
+ *
+ * Upon successful return, the PAS metadata context (@ctx) will be used to
+ * track the metadata allocation, this needs to be released by invoking
+ * qcom_scm_pas_metadata_release() by the caller.
+ */
+int qcom_scm_pas_init_image(u32 peripheral, const void *metadata, size_t size,
+                           struct qcom_scm_pas_metadata *ctx)
+{
+       dma_addr_t mdata_phys;
+       void *mdata_buf;
+       int ret;
+       struct qcom_scm_desc desc = {
+               .svc = QCOM_SCM_SVC_PIL,
+               .cmd = QCOM_SCM_PIL_PAS_INIT_IMAGE,
+               .arginfo = QCOM_SCM_ARGS(2, QCOM_SCM_VAL, QCOM_SCM_RW),
+               .args[0] = peripheral,
+               .owner = ARM_SMCCC_OWNER_SIP,
+       };
+       struct qcom_scm_res res;
+
+       /*
+        * During the scm call memory protection will be enabled for the meta
+        * data blob, so make sure it's physically contiguous, 4K aligned and
+        * non-cachable to avoid XPU violations.
+        */
+       mdata_buf = dma_alloc_coherent(__scm->dev, size, &mdata_phys,
+                                      GFP_KERNEL);
+       if (!mdata_buf) {
+               dev_err(__scm->dev, "Allocation of metadata buffer failed.\n");
+               return -ENOMEM;
+       }
+       memcpy(mdata_buf, metadata, size);
+
+       ret = qcom_scm_clk_enable();
+       if (ret)
+               goto out;
+
+       ret = qcom_scm_bw_enable();
+       if (ret)
+               return ret;
+
+       desc.args[1] = mdata_phys;
+
+       ret = qcom_scm_call(__scm->dev, &desc, &res);
+
+       qcom_scm_bw_disable();
+       qcom_scm_clk_disable();
+
+out:
+       if (ret < 0 || !ctx) {
+               dma_free_coherent(__scm->dev, size, mdata_buf, mdata_phys);
+       } else if (ctx) {
+               ctx->ptr = mdata_buf;
+               ctx->phys = mdata_phys;
+               ctx->size = size;
+       }
+
+       return ret ? : res.result[0];
+}
+EXPORT_SYMBOL_GPL(qcom_scm_pas_init_image);
+
+/**
+ * qcom_scm_pas_metadata_release() - release metadata context
+ * @ctx:       metadata context
+ */
+void qcom_scm_pas_metadata_release(struct qcom_scm_pas_metadata *ctx)
+{
+       if (!ctx->ptr)
+               return;
+
+       dma_free_coherent(__scm->dev, ctx->size, ctx->ptr, ctx->phys);
+
+       ctx->ptr = NULL;
+       ctx->phys = 0;
+       ctx->size = 0;
+}
+EXPORT_SYMBOL_GPL(qcom_scm_pas_metadata_release);
+
+/**
+ * qcom_scm_pas_mem_setup() - Prepare the memory related to a given peripheral
+ *                           for firmware loading
+ * @peripheral:        peripheral id
+ * @addr:      start address of memory area to prepare
+ * @size:      size of the memory area to prepare
+ *
+ * Returns 0 on success.
+ */
+int qcom_scm_pas_mem_setup(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,
+               .arginfo = QCOM_SCM_ARGS(3),
+               .args[0] = peripheral,
+               .args[1] = addr,
+               .args[2] = size,
+               .owner = ARM_SMCCC_OWNER_SIP,
+       };
+       struct qcom_scm_res res;
+
+       ret = qcom_scm_clk_enable();
+       if (ret)
+               return ret;
+
+       ret = qcom_scm_bw_enable();
+       if (ret)
+               return ret;
+
+       ret = qcom_scm_call(__scm->dev, &desc, &res);
+       qcom_scm_bw_disable();
+       qcom_scm_clk_disable();
+
+       return ret ? : res.result[0];
+}
+EXPORT_SYMBOL_GPL(qcom_scm_pas_mem_setup);
+
+/**
+ * qcom_scm_pas_auth_and_reset() - Authenticate the given peripheral firmware
+ *                                and reset the remote processor
+ * @peripheral:        peripheral id
+ *
+ * Return 0 on success.
+ */
+int qcom_scm_pas_auth_and_reset(u32 peripheral)
+{
+       int ret;
+       struct qcom_scm_desc desc = {
+               .svc = QCOM_SCM_SVC_PIL,
+               .cmd = QCOM_SCM_PIL_PAS_AUTH_AND_RESET,
+               .arginfo = QCOM_SCM_ARGS(1),
+               .args[0] = peripheral,
+               .owner = ARM_SMCCC_OWNER_SIP,
+       };
+       struct qcom_scm_res res;
+
+       ret = qcom_scm_clk_enable();
+       if (ret)
+               return ret;
+
+       ret = qcom_scm_bw_enable();
+       if (ret)
+               return ret;
+
+       ret = qcom_scm_call(__scm->dev, &desc, &res);
+       qcom_scm_bw_disable();
+       qcom_scm_clk_disable();
+
+       return ret ? : res.result[0];
+}
+EXPORT_SYMBOL_GPL(qcom_scm_pas_auth_and_reset);
+
+/**
+ * qcom_scm_pas_shutdown() - Shut down the remote processor
+ * @peripheral: peripheral id
+ *
+ * Returns 0 on success.
+ */
+int qcom_scm_pas_shutdown(u32 peripheral)
+{
+       int ret;
+       struct qcom_scm_desc desc = {
+               .svc = QCOM_SCM_SVC_PIL,
+               .cmd = QCOM_SCM_PIL_PAS_SHUTDOWN,
+               .arginfo = QCOM_SCM_ARGS(1),
+               .args[0] = peripheral,
+               .owner = ARM_SMCCC_OWNER_SIP,
+       };
+       struct qcom_scm_res res;
+
+       ret = qcom_scm_clk_enable();
+       if (ret)
+               return ret;
+
+       ret = qcom_scm_bw_enable();
+       if (ret)
+               return ret;
+
+       ret = qcom_scm_call(__scm->dev, &desc, &res);
+
+       qcom_scm_bw_disable();
+       qcom_scm_clk_disable();
+
+       return ret ? : res.result[0];
+}
+EXPORT_SYMBOL_GPL(qcom_scm_pas_shutdown);
+
+/**
+ * qcom_scm_pas_supported() - Check if the peripheral authentication service is
+ *                           available for the given peripherial
+ * @peripheral:        peripheral id
+ *
+ * Returns true if PAS is supported for this peripheral, otherwise false.
+ */
+bool qcom_scm_pas_supported(u32 peripheral)
+{
+       int ret;
+       struct qcom_scm_desc desc = {
+               .svc = QCOM_SCM_SVC_PIL,
+               .cmd = QCOM_SCM_PIL_PAS_IS_SUPPORTED,
+               .arginfo = QCOM_SCM_ARGS(1),
+               .args[0] = peripheral,
+               .owner = ARM_SMCCC_OWNER_SIP,
+       };
+       struct qcom_scm_res res;
+
+       if (!__qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_PIL,
+                                         QCOM_SCM_PIL_PAS_IS_SUPPORTED))
+               return false;
+
+       ret = qcom_scm_call(__scm->dev, &desc, &res);
+
+       return ret ? false : !!res.result[0];
+}
+EXPORT_SYMBOL_GPL(qcom_scm_pas_supported);
+
+static 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,
+               .arginfo = QCOM_SCM_ARGS(2),
+               .args[0] = reset,
+               .args[1] = 0,
+               .owner = ARM_SMCCC_OWNER_SIP,
+       };
+       struct qcom_scm_res res;
+       int ret;
+
+       ret = qcom_scm_call(__scm->dev, &desc, &res);
+
+       return ret ? : res.result[0];
+}
+
+static int qcom_scm_pas_reset_assert(struct reset_controller_dev *rcdev,
+                                    unsigned long idx)
+{
+       if (idx != 0)
+               return -EINVAL;
+
+       return __qcom_scm_pas_mss_reset(__scm->dev, 1);
+}
+
+static int qcom_scm_pas_reset_deassert(struct reset_controller_dev *rcdev,
+                                      unsigned long idx)
+{
+       if (idx != 0)
+               return -EINVAL;
+
+       return __qcom_scm_pas_mss_reset(__scm->dev, 0);
+}
+
+static const struct reset_control_ops qcom_scm_pas_reset_ops = {
+       .assert = qcom_scm_pas_reset_assert,
+       .deassert = qcom_scm_pas_reset_deassert,
+};
+
+int qcom_scm_io_readl(phys_addr_t addr, unsigned int *val)
+{
+       struct qcom_scm_desc desc = {
+               .svc = QCOM_SCM_SVC_IO,
+               .cmd = QCOM_SCM_IO_READ,
+               .arginfo = QCOM_SCM_ARGS(1),
+               .args[0] = addr,
+               .owner = ARM_SMCCC_OWNER_SIP,
+       };
+       struct qcom_scm_res res;
+       int ret;
+
+
+       ret = qcom_scm_call_atomic(__scm->dev, &desc, &res);
+       if (ret >= 0)
+               *val = res.result[0];
+
+       return ret < 0 ? ret : 0;
+}
+EXPORT_SYMBOL_GPL(qcom_scm_io_readl);
+
+int qcom_scm_io_writel(phys_addr_t addr, unsigned int val)
+{
+       struct qcom_scm_desc desc = {
+               .svc = QCOM_SCM_SVC_IO,
+               .cmd = QCOM_SCM_IO_WRITE,
+               .arginfo = QCOM_SCM_ARGS(2),
+               .args[0] = addr,
+               .args[1] = val,
+               .owner = ARM_SMCCC_OWNER_SIP,
+       };
+
+       return qcom_scm_call_atomic(__scm->dev, &desc, NULL);
+}
+EXPORT_SYMBOL_GPL(qcom_scm_io_writel);
+
+/**
+ * qcom_scm_restore_sec_cfg_available() - Check if secure environment
+ * supports restore security config interface.
+ *
+ * Return true if restore-cfg interface is supported, false if not.
+ */
+bool qcom_scm_restore_sec_cfg_available(void)
+{
+       return __qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_MP,
+                                           QCOM_SCM_MP_RESTORE_SEC_CFG);
+}
+EXPORT_SYMBOL_GPL(qcom_scm_restore_sec_cfg_available);
+
+int qcom_scm_restore_sec_cfg(u32 device_id, u32 spare)
+{
+       struct qcom_scm_desc desc = {
+               .svc = QCOM_SCM_SVC_MP,
+               .cmd = QCOM_SCM_MP_RESTORE_SEC_CFG,
+               .arginfo = QCOM_SCM_ARGS(2),
+               .args[0] = device_id,
+               .args[1] = spare,
+               .owner = ARM_SMCCC_OWNER_SIP,
+       };
+       struct qcom_scm_res res;
+       int ret;
+
+       ret = qcom_scm_call(__scm->dev, &desc, &res);
+
+       return ret ? : res.result[0];
+}
+EXPORT_SYMBOL_GPL(qcom_scm_restore_sec_cfg);
+
+int qcom_scm_iommu_secure_ptbl_size(u32 spare, size_t *size)
+{
+       struct qcom_scm_desc desc = {
+               .svc = QCOM_SCM_SVC_MP,
+               .cmd = QCOM_SCM_MP_IOMMU_SECURE_PTBL_SIZE,
+               .arginfo = QCOM_SCM_ARGS(1),
+               .args[0] = spare,
+               .owner = ARM_SMCCC_OWNER_SIP,
+       };
+       struct qcom_scm_res res;
+       int ret;
+
+       ret = qcom_scm_call(__scm->dev, &desc, &res);
+
+       if (size)
+               *size = res.result[0];
+
+       return ret ? : res.result[1];
+}
+EXPORT_SYMBOL_GPL(qcom_scm_iommu_secure_ptbl_size);
+
+int qcom_scm_iommu_secure_ptbl_init(u64 addr, u32 size, u32 spare)
+{
+       struct qcom_scm_desc desc = {
+               .svc = QCOM_SCM_SVC_MP,
+               .cmd = QCOM_SCM_MP_IOMMU_SECURE_PTBL_INIT,
+               .arginfo = QCOM_SCM_ARGS(3, QCOM_SCM_RW, QCOM_SCM_VAL,
+                                        QCOM_SCM_VAL),
+               .args[0] = addr,
+               .args[1] = size,
+               .args[2] = spare,
+               .owner = ARM_SMCCC_OWNER_SIP,
+       };
+       int ret;
+
+       ret = qcom_scm_call(__scm->dev, &desc, NULL);
+
+       /* the pg table has been initialized already, ignore the error */
+       if (ret == -EPERM)
+               ret = 0;
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(qcom_scm_iommu_secure_ptbl_init);
+
+int qcom_scm_iommu_set_cp_pool_size(u32 spare, u32 size)
+{
+       struct qcom_scm_desc desc = {
+               .svc = QCOM_SCM_SVC_MP,
+               .cmd = QCOM_SCM_MP_IOMMU_SET_CP_POOL_SIZE,
+               .arginfo = QCOM_SCM_ARGS(2),
+               .args[0] = size,
+               .args[1] = spare,
+               .owner = ARM_SMCCC_OWNER_SIP,
+       };
+
+       return qcom_scm_call(__scm->dev, &desc, NULL);
+}
+EXPORT_SYMBOL_GPL(qcom_scm_iommu_set_cp_pool_size);
+
+int qcom_scm_mem_protect_video_var(u32 cp_start, u32 cp_size,
+                                  u32 cp_nonpixel_start,
+                                  u32 cp_nonpixel_size)
+{
+       int ret;
+       struct qcom_scm_desc desc = {
+               .svc = QCOM_SCM_SVC_MP,
+               .cmd = QCOM_SCM_MP_VIDEO_VAR,
+               .arginfo = QCOM_SCM_ARGS(4, QCOM_SCM_VAL, QCOM_SCM_VAL,
+                                        QCOM_SCM_VAL, QCOM_SCM_VAL),
+               .args[0] = cp_start,
+               .args[1] = cp_size,
+               .args[2] = cp_nonpixel_start,
+               .args[3] = cp_nonpixel_size,
+               .owner = ARM_SMCCC_OWNER_SIP,
+       };
+       struct qcom_scm_res res;
+
+       ret = qcom_scm_call(__scm->dev, &desc, &res);
+
+       return ret ? : res.result[0];
+}
+EXPORT_SYMBOL_GPL(qcom_scm_mem_protect_video_var);
+
+static int __qcom_scm_assign_mem(struct device *dev, phys_addr_t mem_region,
+                                size_t mem_sz, phys_addr_t src, size_t src_sz,
+                                phys_addr_t dest, size_t dest_sz)
+{
+       int ret;
+       struct qcom_scm_desc desc = {
+               .svc = QCOM_SCM_SVC_MP,
+               .cmd = QCOM_SCM_MP_ASSIGN,
+               .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),
+               .args[0] = mem_region,
+               .args[1] = mem_sz,
+               .args[2] = src,
+               .args[3] = src_sz,
+               .args[4] = dest,
+               .args[5] = dest_sz,
+               .args[6] = 0,
+               .owner = ARM_SMCCC_OWNER_SIP,
+       };
+       struct qcom_scm_res res;
+
+       ret = qcom_scm_call(dev, &desc, &res);
+
+       return ret ? : res.result[0];
+}
+
+/**
+ * qcom_scm_assign_mem() - Make a secure call to reassign memory ownership
+ * @mem_addr: mem region whose ownership need to be reassigned
+ * @mem_sz:   size of the region.
+ * @srcvm:    vmid for current set of owners, each set bit in
+ *            flag indicate a unique owner
+ * @newvm:    array having new owners and corresponding permission
+ *            flags
+ * @dest_cnt: number of owners in next set.
+ *
+ * Return negative errno on failure or 0 on success with @srcvm updated.
+ */
+int qcom_scm_assign_mem(phys_addr_t mem_addr, size_t mem_sz,
+                       u64 *srcvm,
+                       const struct qcom_scm_vmperm *newvm,
+                       unsigned int dest_cnt)
+{
+       struct qcom_scm_current_perm_info *destvm;
+       struct qcom_scm_mem_map_info *mem_to_map;
+       phys_addr_t mem_to_map_phys;
+       phys_addr_t dest_phys;
+       dma_addr_t ptr_phys;
+       size_t mem_to_map_sz;
+       size_t dest_sz;
+       size_t src_sz;
+       size_t ptr_sz;
+       int next_vm;
+       __le32 *src;
+       void *ptr;
+       int ret, i, b;
+       u64 srcvm_bits = *srcvm;
+
+       src_sz = hweight64(srcvm_bits) * sizeof(*src);
+       mem_to_map_sz = sizeof(*mem_to_map);
+       dest_sz = dest_cnt * sizeof(*destvm);
+       ptr_sz = ALIGN(src_sz, SZ_64) + ALIGN(mem_to_map_sz, SZ_64) +
+                       ALIGN(dest_sz, SZ_64);
+
+       ptr = dma_alloc_coherent(__scm->dev, ptr_sz, &ptr_phys, GFP_KERNEL);
+       if (!ptr)
+               return -ENOMEM;
+
+       /* Fill source vmid detail */
+       src = ptr;
+       i = 0;
+       for (b = 0; b < BITS_PER_TYPE(u64); b++) {
+               if (srcvm_bits & BIT(b))
+                       src[i++] = cpu_to_le32(b);
+       }
+
+       /* Fill details of mem buff to map */
+       mem_to_map = ptr + ALIGN(src_sz, SZ_64);
+       mem_to_map_phys = ptr_phys + ALIGN(src_sz, SZ_64);
+       mem_to_map->mem_addr = cpu_to_le64(mem_addr);
+       mem_to_map->mem_size = cpu_to_le64(mem_sz);
+
+       next_vm = 0;
+       /* Fill details of next vmid detail */
+       destvm = ptr + ALIGN(mem_to_map_sz, SZ_64) + ALIGN(src_sz, SZ_64);
+       dest_phys = ptr_phys + ALIGN(mem_to_map_sz, SZ_64) + ALIGN(src_sz, SZ_64);
+       for (i = 0; i < dest_cnt; i++, destvm++, newvm++) {
+               destvm->vmid = cpu_to_le32(newvm->vmid);
+               destvm->perm = cpu_to_le32(newvm->perm);
+               destvm->ctx = 0;
+               destvm->ctx_size = 0;
+               next_vm |= BIT(newvm->vmid);
+       }
+
+       ret = __qcom_scm_assign_mem(__scm->dev, mem_to_map_phys, mem_to_map_sz,
+                                   ptr_phys, src_sz, dest_phys, dest_sz);
+       dma_free_coherent(__scm->dev, ptr_sz, ptr, ptr_phys);
+       if (ret) {
+               dev_err(__scm->dev,
+                       "Assign memory protection call failed %d\n", ret);
+               return -EINVAL;
+       }
+
+       *srcvm = next_vm;
+       return 0;
+}
+EXPORT_SYMBOL_GPL(qcom_scm_assign_mem);
+
+/**
+ * qcom_scm_ocmem_lock_available() - is OCMEM lock/unlock interface available
+ */
+bool qcom_scm_ocmem_lock_available(void)
+{
+       return __qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_OCMEM,
+                                           QCOM_SCM_OCMEM_LOCK_CMD);
+}
+EXPORT_SYMBOL_GPL(qcom_scm_ocmem_lock_available);
+
+/**
+ * qcom_scm_ocmem_lock() - call OCMEM lock interface to assign an OCMEM
+ * region to the specified initiator
+ *
+ * @id:     tz initiator id
+ * @offset: OCMEM offset
+ * @size:   OCMEM size
+ * @mode:   access mode (WIDE/NARROW)
+ */
+int qcom_scm_ocmem_lock(enum qcom_scm_ocmem_client id, u32 offset, u32 size,
+                       u32 mode)
+{
+       struct qcom_scm_desc desc = {
+               .svc = QCOM_SCM_SVC_OCMEM,
+               .cmd = QCOM_SCM_OCMEM_LOCK_CMD,
+               .args[0] = id,
+               .args[1] = offset,
+               .args[2] = size,
+               .args[3] = mode,
+               .arginfo = QCOM_SCM_ARGS(4),
+       };
+
+       return qcom_scm_call(__scm->dev, &desc, NULL);
+}
+EXPORT_SYMBOL_GPL(qcom_scm_ocmem_lock);
+
+/**
+ * qcom_scm_ocmem_unlock() - call OCMEM unlock interface to release an OCMEM
+ * region from the specified initiator
+ *
+ * @id:     tz initiator id
+ * @offset: OCMEM offset
+ * @size:   OCMEM size
+ */
+int qcom_scm_ocmem_unlock(enum qcom_scm_ocmem_client id, u32 offset, u32 size)
+{
+       struct qcom_scm_desc desc = {
+               .svc = QCOM_SCM_SVC_OCMEM,
+               .cmd = QCOM_SCM_OCMEM_UNLOCK_CMD,
+               .args[0] = id,
+               .args[1] = offset,
+               .args[2] = size,
+               .arginfo = QCOM_SCM_ARGS(3),
+       };
+
+       return qcom_scm_call(__scm->dev, &desc, NULL);
+}
+EXPORT_SYMBOL_GPL(qcom_scm_ocmem_unlock);
+
+/**
+ * qcom_scm_ice_available() - Is the ICE key programming interface available?
+ *
+ * Return: true iff the SCM calls wrapped by qcom_scm_ice_invalidate_key() and
+ *        qcom_scm_ice_set_key() are available.
+ */
+bool qcom_scm_ice_available(void)
+{
+       return __qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_ES,
+                                           QCOM_SCM_ES_INVALIDATE_ICE_KEY) &&
+               __qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_ES,
+                                            QCOM_SCM_ES_CONFIG_SET_ICE_KEY);
+}
+EXPORT_SYMBOL_GPL(qcom_scm_ice_available);
+
+/**
+ * qcom_scm_ice_invalidate_key() - Invalidate an inline encryption key
+ * @index: the keyslot to invalidate
+ *
+ * The UFSHCI and eMMC standards define a standard way to do this, but it
+ * doesn't work on these SoCs; only this SCM call does.
+ *
+ * It is assumed that the SoC has only one ICE instance being used, as this SCM
+ * call doesn't specify which ICE instance the keyslot belongs to.
+ *
+ * Return: 0 on success; -errno on failure.
+ */
+int qcom_scm_ice_invalidate_key(u32 index)
+{
+       struct qcom_scm_desc desc = {
+               .svc = QCOM_SCM_SVC_ES,
+               .cmd = QCOM_SCM_ES_INVALIDATE_ICE_KEY,
+               .arginfo = QCOM_SCM_ARGS(1),
+               .args[0] = index,
+               .owner = ARM_SMCCC_OWNER_SIP,
+       };
+
+       return qcom_scm_call(__scm->dev, &desc, NULL);
+}
+EXPORT_SYMBOL_GPL(qcom_scm_ice_invalidate_key);
+
+/**
+ * qcom_scm_ice_set_key() - Set an inline encryption key
+ * @index: the keyslot into which to set the key
+ * @key: the key to program
+ * @key_size: the size of the key in bytes
+ * @cipher: the encryption algorithm the key is for
+ * @data_unit_size: the encryption data unit size, i.e. the size of each
+ *                 individual plaintext and ciphertext.  Given in 512-byte
+ *                 units, e.g. 1 = 512 bytes, 8 = 4096 bytes, etc.
+ *
+ * Program a key into a keyslot of Qualcomm ICE (Inline Crypto Engine), where it
+ * can then be used to encrypt/decrypt UFS or eMMC I/O requests inline.
+ *
+ * The UFSHCI and eMMC standards define a standard way to do this, but it
+ * doesn't work on these SoCs; only this SCM call does.
+ *
+ * It is assumed that the SoC has only one ICE instance being used, as this SCM
+ * call doesn't specify which ICE instance the keyslot belongs to.
+ *
+ * Return: 0 on success; -errno on failure.
+ */
+int qcom_scm_ice_set_key(u32 index, const u8 *key, u32 key_size,
+                        enum qcom_scm_ice_cipher cipher, u32 data_unit_size)
+{
+       struct qcom_scm_desc desc = {
+               .svc = QCOM_SCM_SVC_ES,
+               .cmd = QCOM_SCM_ES_CONFIG_SET_ICE_KEY,
+               .arginfo = QCOM_SCM_ARGS(5, QCOM_SCM_VAL, QCOM_SCM_RW,
+                                        QCOM_SCM_VAL, QCOM_SCM_VAL,
+                                        QCOM_SCM_VAL),
+               .args[0] = index,
+               .args[2] = key_size,
+               .args[3] = cipher,
+               .args[4] = data_unit_size,
+               .owner = ARM_SMCCC_OWNER_SIP,
+       };
+       void *keybuf;
+       dma_addr_t key_phys;
+       int ret;
+
+       /*
+        * 'key' may point to vmalloc()'ed memory, but we need to pass a
+        * physical address that's been properly flushed.  The sanctioned way to
+        * do this is by using the DMA API.  But as is best practice for crypto
+        * keys, we also must wipe the key after use.  This makes kmemdup() +
+        * dma_map_single() not clearly correct, since the DMA API can use
+        * bounce buffers.  Instead, just use dma_alloc_coherent().  Programming
+        * keys is normally rare and thus not performance-critical.
+        */
+
+       keybuf = dma_alloc_coherent(__scm->dev, key_size, &key_phys,
+                                   GFP_KERNEL);
+       if (!keybuf)
+               return -ENOMEM;
+       memcpy(keybuf, key, key_size);
+       desc.args[1] = key_phys;
+
+       ret = qcom_scm_call(__scm->dev, &desc, NULL);
+
+       memzero_explicit(keybuf, key_size);
+
+       dma_free_coherent(__scm->dev, key_size, keybuf, key_phys);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(qcom_scm_ice_set_key);
+
+/**
+ * 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)
+{
+       bool avail;
+       int ret = qcom_scm_clk_enable();
+
+       if (ret)
+               return ret;
+
+       avail = __qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_HDCP,
+                                               QCOM_SCM_HDCP_INVOKE);
+
+       qcom_scm_clk_disable();
+
+       return avail;
+}
+EXPORT_SYMBOL_GPL(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;
+       struct qcom_scm_desc desc = {
+               .svc = QCOM_SCM_SVC_HDCP,
+               .cmd = QCOM_SCM_HDCP_INVOKE,
+               .arginfo = QCOM_SCM_ARGS(10),
+               .args = {
+                       req[0].addr,
+                       req[0].val,
+                       req[1].addr,
+                       req[1].val,
+                       req[2].addr,
+                       req[2].val,
+                       req[3].addr,
+                       req[3].val,
+                       req[4].addr,
+                       req[4].val
+               },
+               .owner = ARM_SMCCC_OWNER_SIP,
+       };
+       struct qcom_scm_res res;
+
+       if (req_cnt > QCOM_SCM_HDCP_MAX_REQ_CNT)
+               return -ERANGE;
+
+       ret = qcom_scm_clk_enable();
+       if (ret)
+               return ret;
+
+       ret = qcom_scm_call(__scm->dev, &desc, &res);
+       *resp = res.result[0];
+
+       qcom_scm_clk_disable();
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(qcom_scm_hdcp_req);
+
+int qcom_scm_iommu_set_pt_format(u32 sec_id, u32 ctx_num, u32 pt_fmt)
+{
+       struct qcom_scm_desc desc = {
+               .svc = QCOM_SCM_SVC_SMMU_PROGRAM,
+               .cmd = QCOM_SCM_SMMU_PT_FORMAT,
+               .arginfo = QCOM_SCM_ARGS(3),
+               .args[0] = sec_id,
+               .args[1] = ctx_num,
+               .args[2] = pt_fmt, /* 0: LPAE AArch32 - 1: AArch64 */
+               .owner = ARM_SMCCC_OWNER_SIP,
+       };
+
+       return qcom_scm_call(__scm->dev, &desc, NULL);
+}
+EXPORT_SYMBOL_GPL(qcom_scm_iommu_set_pt_format);
+
+int qcom_scm_qsmmu500_wait_safe_toggle(bool en)
+{
+       struct qcom_scm_desc desc = {
+               .svc = QCOM_SCM_SVC_SMMU_PROGRAM,
+               .cmd = QCOM_SCM_SMMU_CONFIG_ERRATA1,
+               .arginfo = QCOM_SCM_ARGS(2),
+               .args[0] = QCOM_SCM_SMMU_CONFIG_ERRATA1_CLIENT_ALL,
+               .args[1] = en,
+               .owner = ARM_SMCCC_OWNER_SIP,
+       };
+
+
+       return qcom_scm_call_atomic(__scm->dev, &desc, NULL);
+}
+EXPORT_SYMBOL_GPL(qcom_scm_qsmmu500_wait_safe_toggle);
+
+bool qcom_scm_lmh_dcvsh_available(void)
+{
+       return __qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_LMH, QCOM_SCM_LMH_LIMIT_DCVSH);
+}
+EXPORT_SYMBOL_GPL(qcom_scm_lmh_dcvsh_available);
+
+int qcom_scm_lmh_profile_change(u32 profile_id)
+{
+       struct qcom_scm_desc desc = {
+               .svc = QCOM_SCM_SVC_LMH,
+               .cmd = QCOM_SCM_LMH_LIMIT_PROFILE_CHANGE,
+               .arginfo = QCOM_SCM_ARGS(1, QCOM_SCM_VAL),
+               .args[0] = profile_id,
+               .owner = ARM_SMCCC_OWNER_SIP,
+       };
+
+       return qcom_scm_call(__scm->dev, &desc, NULL);
+}
+EXPORT_SYMBOL_GPL(qcom_scm_lmh_profile_change);
+
+int qcom_scm_lmh_dcvsh(u32 payload_fn, u32 payload_reg, u32 payload_val,
+                      u64 limit_node, u32 node_id, u64 version)
+{
+       dma_addr_t payload_phys;
+       u32 *payload_buf;
+       int ret, payload_size = 5 * sizeof(u32);
+
+       struct qcom_scm_desc desc = {
+               .svc = QCOM_SCM_SVC_LMH,
+               .cmd = QCOM_SCM_LMH_LIMIT_DCVSH,
+               .arginfo = QCOM_SCM_ARGS(5, QCOM_SCM_RO, QCOM_SCM_VAL, QCOM_SCM_VAL,
+                                       QCOM_SCM_VAL, QCOM_SCM_VAL),
+               .args[1] = payload_size,
+               .args[2] = limit_node,
+               .args[3] = node_id,
+               .args[4] = version,
+               .owner = ARM_SMCCC_OWNER_SIP,
+       };
+
+       payload_buf = dma_alloc_coherent(__scm->dev, payload_size, &payload_phys, GFP_KERNEL);
+       if (!payload_buf)
+               return -ENOMEM;
+
+       payload_buf[0] = payload_fn;
+       payload_buf[1] = 0;
+       payload_buf[2] = payload_reg;
+       payload_buf[3] = 1;
+       payload_buf[4] = payload_val;
+
+       desc.args[0] = payload_phys;
+
+       ret = qcom_scm_call(__scm->dev, &desc, NULL);
+
+       dma_free_coherent(__scm->dev, payload_size, payload_buf, payload_phys);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(qcom_scm_lmh_dcvsh);
+
+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;
+}
+
+#ifdef CONFIG_QCOM_QSEECOM
+
+/* Lock for QSEECOM SCM call executions */
+static DEFINE_MUTEX(qcom_scm_qseecom_call_lock);
+
+static int __qcom_scm_qseecom_call(const struct qcom_scm_desc *desc,
+                                  struct qcom_scm_qseecom_resp *res)
+{
+       struct qcom_scm_res scm_res = {};
+       int status;
+
+       /*
+        * QSEECOM SCM calls should not be executed concurrently. Therefore, we
+        * require the respective call lock to be held.
+        */
+       lockdep_assert_held(&qcom_scm_qseecom_call_lock);
+
+       status = qcom_scm_call(__scm->dev, desc, &scm_res);
+
+       res->result = scm_res.result[0];
+       res->resp_type = scm_res.result[1];
+       res->data = scm_res.result[2];
+
+       if (status)
+               return status;
+
+       return 0;
+}
+
+/**
+ * qcom_scm_qseecom_call() - Perform a QSEECOM SCM call.
+ * @desc: SCM call descriptor.
+ * @res:  SCM call response (output).
+ *
+ * Performs the QSEECOM SCM call described by @desc, returning the response in
+ * @rsp.
+ *
+ * Return: Zero on success, nonzero on failure.
+ */
+static int qcom_scm_qseecom_call(const struct qcom_scm_desc *desc,
+                                struct qcom_scm_qseecom_resp *res)
+{
+       int status;
+
+       /*
+        * Note: Multiple QSEECOM SCM calls should not be executed same time,
+        * so lock things here. This needs to be extended to callback/listener
+        * handling when support for that is implemented.
+        */
+
+       mutex_lock(&qcom_scm_qseecom_call_lock);
+       status = __qcom_scm_qseecom_call(desc, res);
+       mutex_unlock(&qcom_scm_qseecom_call_lock);
+
+       dev_dbg(__scm->dev, "%s: owner=%x, svc=%x, cmd=%x, result=%lld, type=%llx, data=%llx\n",
+               __func__, desc->owner, desc->svc, desc->cmd, res->result,
+               res->resp_type, res->data);
+
+       if (status) {
+               dev_err(__scm->dev, "qseecom: scm call failed with error %d\n", status);
+               return status;
+       }
+
+       /*
+        * TODO: Handle incomplete and blocked calls:
+        *
+        * Incomplete and blocked calls are not supported yet. Some devices
+        * and/or commands require those, some don't. Let's warn about them
+        * prominently in case someone attempts to try these commands with a
+        * device/command combination that isn't supported yet.
+        */
+       WARN_ON(res->result == QSEECOM_RESULT_INCOMPLETE);
+       WARN_ON(res->result == QSEECOM_RESULT_BLOCKED_ON_LISTENER);
+
+       return 0;
+}
+
+/**
+ * qcom_scm_qseecom_get_version() - Query the QSEECOM version.
+ * @version: Pointer where the QSEECOM version will be stored.
+ *
+ * Performs the QSEECOM SCM querying the QSEECOM version currently running in
+ * the TrustZone.
+ *
+ * Return: Zero on success, nonzero on failure.
+ */
+static int qcom_scm_qseecom_get_version(u32 *version)
+{
+       struct qcom_scm_desc desc = {};
+       struct qcom_scm_qseecom_resp res = {};
+       u32 feature = 10;
+       int ret;
+
+       desc.owner = QSEECOM_TZ_OWNER_SIP;
+       desc.svc = QSEECOM_TZ_SVC_INFO;
+       desc.cmd = QSEECOM_TZ_CMD_INFO_VERSION;
+       desc.arginfo = QCOM_SCM_ARGS(1, QCOM_SCM_VAL);
+       desc.args[0] = feature;
+
+       ret = qcom_scm_qseecom_call(&desc, &res);
+       if (ret)
+               return ret;
+
+       *version = res.result;
+       return 0;
+}
+
+/**
+ * qcom_scm_qseecom_app_get_id() - Query the app ID for a given QSEE app name.
+ * @app_name: The name of the app.
+ * @app_id:   The returned app ID.
+ *
+ * Query and return the application ID of the SEE app identified by the given
+ * name. This returned ID is the unique identifier of the app required for
+ * subsequent communication.
+ *
+ * Return: Zero on success, nonzero on failure, -ENOENT if the app has not been
+ * loaded or could not be found.
+ */
+int qcom_scm_qseecom_app_get_id(const char *app_name, u32 *app_id)
+{
+       unsigned long name_buf_size = QSEECOM_MAX_APP_NAME_SIZE;
+       unsigned long app_name_len = strlen(app_name);
+       struct qcom_scm_desc desc = {};
+       struct qcom_scm_qseecom_resp res = {};
+       dma_addr_t name_buf_phys;
+       char *name_buf;
+       int status;
+
+       if (app_name_len >= name_buf_size)
+               return -EINVAL;
+
+       name_buf = kzalloc(name_buf_size, GFP_KERNEL);
+       if (!name_buf)
+               return -ENOMEM;
+
+       memcpy(name_buf, app_name, app_name_len);
+
+       name_buf_phys = dma_map_single(__scm->dev, name_buf, name_buf_size, DMA_TO_DEVICE);
+       status = dma_mapping_error(__scm->dev, name_buf_phys);
+       if (status) {
+               kfree(name_buf);
+               dev_err(__scm->dev, "qseecom: failed to map dma address\n");
+               return status;
+       }
+
+       desc.owner = QSEECOM_TZ_OWNER_QSEE_OS;
+       desc.svc = QSEECOM_TZ_SVC_APP_MGR;
+       desc.cmd = QSEECOM_TZ_CMD_APP_LOOKUP;
+       desc.arginfo = QCOM_SCM_ARGS(2, QCOM_SCM_RW, QCOM_SCM_VAL);
+       desc.args[0] = name_buf_phys;
+       desc.args[1] = app_name_len;
+
+       status = qcom_scm_qseecom_call(&desc, &res);
+       dma_unmap_single(__scm->dev, name_buf_phys, name_buf_size, DMA_TO_DEVICE);
+       kfree(name_buf);
+
+       if (status)
+               return status;
+
+       if (res.result == QSEECOM_RESULT_FAILURE)
+               return -ENOENT;
+
+       if (res.result != QSEECOM_RESULT_SUCCESS)
+               return -EINVAL;
+
+       if (res.resp_type != QSEECOM_SCM_RES_APP_ID)
+               return -EINVAL;
+
+       *app_id = res.data;
+       return 0;
+}
+EXPORT_SYMBOL_GPL(qcom_scm_qseecom_app_get_id);
+
+/**
+ * qcom_scm_qseecom_app_send() - Send to and receive data from a given QSEE app.
+ * @app_id:   The ID of the target app.
+ * @req:      Request buffer sent to the app (must be DMA-mappable).
+ * @req_size: Size of the request buffer.
+ * @rsp:      Response buffer, written to by the app (must be DMA-mappable).
+ * @rsp_size: Size of the response buffer.
+ *
+ * Sends a request to the QSEE app associated with the given ID and read back
+ * its response. The caller must provide two DMA memory regions, one for the
+ * request and one for the response, and fill out the @req region with the
+ * respective (app-specific) request data. The QSEE app reads this and returns
+ * its response in the @rsp region.
+ *
+ * Return: Zero on success, nonzero on failure.
+ */
+int qcom_scm_qseecom_app_send(u32 app_id, void *req, size_t req_size, void *rsp,
+                             size_t rsp_size)
+{
+       struct qcom_scm_qseecom_resp res = {};
+       struct qcom_scm_desc desc = {};
+       dma_addr_t req_phys;
+       dma_addr_t rsp_phys;
+       int status;
+
+       /* Map request buffer */
+       req_phys = dma_map_single(__scm->dev, req, req_size, DMA_TO_DEVICE);
+       status = dma_mapping_error(__scm->dev, req_phys);
+       if (status) {
+               dev_err(__scm->dev, "qseecom: failed to map request buffer\n");
+               return status;
+       }
+
+       /* Map response buffer */
+       rsp_phys = dma_map_single(__scm->dev, rsp, rsp_size, DMA_FROM_DEVICE);
+       status = dma_mapping_error(__scm->dev, rsp_phys);
+       if (status) {
+               dma_unmap_single(__scm->dev, req_phys, req_size, DMA_TO_DEVICE);
+               dev_err(__scm->dev, "qseecom: failed to map response buffer\n");
+               return status;
+       }
+
+       /* Set up SCM call data */
+       desc.owner = QSEECOM_TZ_OWNER_TZ_APPS;
+       desc.svc = QSEECOM_TZ_SVC_APP_ID_PLACEHOLDER;
+       desc.cmd = QSEECOM_TZ_CMD_APP_SEND;
+       desc.arginfo = QCOM_SCM_ARGS(5, QCOM_SCM_VAL,
+                                    QCOM_SCM_RW, QCOM_SCM_VAL,
+                                    QCOM_SCM_RW, QCOM_SCM_VAL);
+       desc.args[0] = app_id;
+       desc.args[1] = req_phys;
+       desc.args[2] = req_size;
+       desc.args[3] = rsp_phys;
+       desc.args[4] = rsp_size;
+
+       /* Perform call */
+       status = qcom_scm_qseecom_call(&desc, &res);
+
+       /* Unmap buffers */
+       dma_unmap_single(__scm->dev, rsp_phys, rsp_size, DMA_FROM_DEVICE);
+       dma_unmap_single(__scm->dev, req_phys, req_size, DMA_TO_DEVICE);
+
+       if (status)
+               return status;
+
+       if (res.result != QSEECOM_RESULT_SUCCESS)
+               return -EIO;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(qcom_scm_qseecom_app_send);
+
+/*
+ * We do not yet support re-entrant calls via the qseecom interface. To prevent
+ + any potential issues with this, only allow validated machines for now.
+ */
+static const struct of_device_id qcom_scm_qseecom_allowlist[] = {
+       { .compatible = "lenovo,thinkpad-x13s", },
+       { }
+};
+
+static bool qcom_scm_qseecom_machine_is_allowed(void)
+{
+       struct device_node *np;
+       bool match;
+
+       np = of_find_node_by_path("/");
+       if (!np)
+               return false;
+
+       match = of_match_node(qcom_scm_qseecom_allowlist, np);
+       of_node_put(np);
+
+       return match;
+}
+
+static void qcom_scm_qseecom_free(void *data)
+{
+       struct platform_device *qseecom_dev = data;
+
+       platform_device_del(qseecom_dev);
+       platform_device_put(qseecom_dev);
+}
+
+static int qcom_scm_qseecom_init(struct qcom_scm *scm)
+{
+       struct platform_device *qseecom_dev;
+       u32 version;
+       int ret;
+
+       /*
+        * Note: We do two steps of validation here: First, we try to query the
+        * QSEECOM version as a check to see if the interface exists on this
+        * device. Second, we check against known good devices due to current
+        * driver limitations (see comment in qcom_scm_qseecom_allowlist).
+        *
+        * Note that we deliberately do the machine check after the version
+        * check so that we can log potentially supported devices. This should
+        * be safe as downstream sources indicate that the version query is
+        * neither blocking nor reentrant.
+        */
+       ret = qcom_scm_qseecom_get_version(&version);
+       if (ret)
+               return 0;
+
+       dev_info(scm->dev, "qseecom: found qseecom with version 0x%x\n", version);
+
+       if (!qcom_scm_qseecom_machine_is_allowed()) {
+               dev_info(scm->dev, "qseecom: untested machine, skipping\n");
+               return 0;
+       }
+
+       /*
+        * Set up QSEECOM interface device. All application clients will be
+        * set up and managed by the corresponding driver for it.
+        */
+       qseecom_dev = platform_device_alloc("qcom_qseecom", -1);
+       if (!qseecom_dev)
+               return -ENOMEM;
+
+       qseecom_dev->dev.parent = scm->dev;
+
+       ret = platform_device_add(qseecom_dev);
+       if (ret) {
+               platform_device_put(qseecom_dev);
+               return ret;
+       }
+
+       return devm_add_action_or_reset(scm->dev, qcom_scm_qseecom_free, qseecom_dev);
+}
+
+#else /* CONFIG_QCOM_QSEECOM */
+
+static int qcom_scm_qseecom_init(struct qcom_scm *scm)
+{
+       return 0;
+}
+
+#endif /* CONFIG_QCOM_QSEECOM */
+
+/**
+ * qcom_scm_is_available() - Checks if SCM is available
+ */
+bool qcom_scm_is_available(void)
+{
+       return !!__scm;
+}
+EXPORT_SYMBOL_GPL(qcom_scm_is_available);
+
+static int qcom_scm_assert_valid_wq_ctx(u32 wq_ctx)
+{
+       /* FW currently only supports a single wq_ctx (zero).
+        * TODO: Update this logic to include dynamic allocation and lookup of
+        * completion structs when FW supports more wq_ctx values.
+        */
+       if (wq_ctx != 0) {
+               dev_err(__scm->dev, "Firmware unexpectedly passed non-zero wq_ctx\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+int qcom_scm_wait_for_wq_completion(u32 wq_ctx)
+{
+       int ret;
+
+       ret = qcom_scm_assert_valid_wq_ctx(wq_ctx);
+       if (ret)
+               return ret;
+
+       wait_for_completion(&__scm->waitq_comp);
+
+       return 0;
+}
+
+static int qcom_scm_waitq_wakeup(struct qcom_scm *scm, unsigned int wq_ctx)
+{
+       int ret;
+
+       ret = qcom_scm_assert_valid_wq_ctx(wq_ctx);
+       if (ret)
+               return ret;
+
+       complete(&__scm->waitq_comp);
+
+       return 0;
+}
+
+static irqreturn_t qcom_scm_irq_handler(int irq, void *data)
+{
+       int ret;
+       struct qcom_scm *scm = data;
+       u32 wq_ctx, flags, more_pending = 0;
+
+       do {
+               ret = scm_get_wq_ctx(&wq_ctx, &flags, &more_pending);
+               if (ret) {
+                       dev_err(scm->dev, "GET_WQ_CTX SMC call failed: %d\n", ret);
+                       goto out;
+               }
+
+               if (flags != QCOM_SMC_WAITQ_FLAG_WAKE_ONE &&
+                   flags != QCOM_SMC_WAITQ_FLAG_WAKE_ALL) {
+                       dev_err(scm->dev, "Invalid flags found for wq_ctx: %u\n", flags);
+                       goto out;
+               }
+
+               ret = qcom_scm_waitq_wakeup(scm, wq_ctx);
+               if (ret)
+                       goto out;
+       } while (more_pending);
+
+out:
+       return IRQ_HANDLED;
+}
+
+static int qcom_scm_probe(struct platform_device *pdev)
+{
+       struct qcom_scm *scm;
+       int irq, ret;
+
+       scm = devm_kzalloc(&pdev->dev, sizeof(*scm), GFP_KERNEL);
+       if (!scm)
+               return -ENOMEM;
+
+       ret = qcom_scm_find_dload_address(&pdev->dev, &scm->dload_mode_addr);
+       if (ret < 0)
+               return ret;
+
+       mutex_init(&scm->scm_bw_lock);
+
+       scm->path = devm_of_icc_get(&pdev->dev, NULL);
+       if (IS_ERR(scm->path))
+               return dev_err_probe(&pdev->dev, PTR_ERR(scm->path),
+                                    "failed to acquire interconnect path\n");
+
+       scm->core_clk = devm_clk_get_optional(&pdev->dev, "core");
+       if (IS_ERR(scm->core_clk))
+               return PTR_ERR(scm->core_clk);
+
+       scm->iface_clk = devm_clk_get_optional(&pdev->dev, "iface");
+       if (IS_ERR(scm->iface_clk))
+               return PTR_ERR(scm->iface_clk);
+
+       scm->bus_clk = devm_clk_get_optional(&pdev->dev, "bus");
+       if (IS_ERR(scm->bus_clk))
+               return PTR_ERR(scm->bus_clk);
+
+       scm->reset.ops = &qcom_scm_pas_reset_ops;
+       scm->reset.nr_resets = 1;
+       scm->reset.of_node = pdev->dev.of_node;
+       ret = devm_reset_controller_register(&pdev->dev, &scm->reset);
+       if (ret)
+               return ret;
+
+       /* vote for max clk rate for highest performance */
+       ret = clk_set_rate(scm->core_clk, INT_MAX);
+       if (ret)
+               return ret;
+
+       __scm = scm;
+       __scm->dev = &pdev->dev;
+
+       init_completion(&__scm->waitq_comp);
+
+       irq = platform_get_irq_optional(pdev, 0);
+       if (irq < 0) {
+               if (irq != -ENXIO)
+                       return irq;
+       } else {
+               ret = devm_request_threaded_irq(__scm->dev, irq, NULL, qcom_scm_irq_handler,
+                                               IRQF_ONESHOT, "qcom-scm", __scm);
+               if (ret < 0)
+                       return dev_err_probe(scm->dev, ret, "Failed to request qcom-scm irq\n");
+       }
+
+       __get_convention();
+
+       /*
+        * If requested enable "download mode", from this point on warmboot
+        * will cause the boot stages to enter download mode, unless
+        * disabled below by a clean shutdown/reboot.
+        */
+       if (download_mode)
+               qcom_scm_set_download_mode(true);
+
+
+       /*
+        * Disable SDI if indicated by DT that it is enabled by default.
+        */
+       if (of_property_read_bool(pdev->dev.of_node, "qcom,sdi-enabled"))
+               qcom_scm_disable_sdi();
+
+       /*
+        * Initialize the QSEECOM interface.
+        *
+        * Note: QSEECOM is fairly self-contained and this only adds the
+        * interface device (the driver of which does most of the heavy
+        * lifting). So any errors returned here should be either -ENOMEM or
+        * -EINVAL (with the latter only in case there's a bug in our code).
+        * This means that there is no need to bring down the whole SCM driver.
+        * Just log the error instead and let SCM live.
+        */
+       ret = qcom_scm_qseecom_init(scm);
+       WARN(ret < 0, "failed to initialize qseecom: %d\n", ret);
+
+       return 0;
+}
+
+static void qcom_scm_shutdown(struct platform_device *pdev)
+{
+       /* Clean shutdown, disable download mode to allow normal restart */
+       qcom_scm_set_download_mode(false);
+}
+
+static const struct of_device_id qcom_scm_dt_match[] = {
+       { .compatible = "qcom,scm" },
+
+       /* Legacy entries kept for backwards compatibility */
+       { .compatible = "qcom,scm-apq8064" },
+       { .compatible = "qcom,scm-apq8084" },
+       { .compatible = "qcom,scm-ipq4019" },
+       { .compatible = "qcom,scm-msm8953" },
+       { .compatible = "qcom,scm-msm8974" },
+       { .compatible = "qcom,scm-msm8996" },
+       {}
+};
+MODULE_DEVICE_TABLE(of, qcom_scm_dt_match);
+
+static struct platform_driver qcom_scm_driver = {
+       .driver = {
+               .name   = "qcom_scm",
+               .of_match_table = qcom_scm_dt_match,
+               .suppress_bind_attrs = true,
+       },
+       .probe = qcom_scm_probe,
+       .shutdown = qcom_scm_shutdown,
+};
+
+static int __init qcom_scm_init(void)
+{
+       return platform_driver_register(&qcom_scm_driver);
+}
+subsys_initcall(qcom_scm_init);
+
+MODULE_DESCRIPTION("Qualcomm Technologies, Inc. SCM driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/firmware/qcom/qcom_scm.h b/drivers/firmware/qcom/qcom_scm.h
new file mode 100644 (file)
index 0000000..7b68fa8
--- /dev/null
@@ -0,0 +1,168 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright (c) 2010-2015,2019 The Linux Foundation. All rights reserved.
+ */
+#ifndef __QCOM_SCM_INT_H
+#define __QCOM_SCM_INT_H
+
+enum qcom_scm_convention {
+       SMC_CONVENTION_UNKNOWN,
+       SMC_CONVENTION_LEGACY,
+       SMC_CONVENTION_ARM_32,
+       SMC_CONVENTION_ARM_64,
+};
+
+extern enum qcom_scm_convention qcom_scm_convention;
+
+#define MAX_QCOM_SCM_ARGS 10
+#define MAX_QCOM_SCM_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
+ */
+struct qcom_scm_desc {
+       u32 svc;
+       u32 cmd;
+       u32 arginfo;
+       u64 args[MAX_QCOM_SCM_ARGS];
+       u32 owner;
+};
+
+/**
+ * struct qcom_scm_res
+ * @result:    The values returned by the secure syscall
+ */
+struct qcom_scm_res {
+       u64 result[MAX_QCOM_SCM_RETS];
+};
+
+int qcom_scm_wait_for_wq_completion(u32 wq_ctx);
+int scm_get_wq_ctx(u32 *wq_ctx, u32 *flags, u32 *more_pending);
+
+#define SCM_SMC_FNID(s, c)     ((((s) & 0xFF) << 8) | ((c) & 0xFF))
+extern int __scm_smc_call(struct device *dev, const struct qcom_scm_desc *desc,
+                         enum qcom_scm_convention qcom_convention,
+                         struct qcom_scm_res *res, bool atomic);
+#define scm_smc_call(dev, desc, res, atomic) \
+       __scm_smc_call((dev), (desc), qcom_scm_convention, (res), (atomic))
+
+#define SCM_LEGACY_FNID(s, c)  (((s) << 10) | ((c) & 0x3ff))
+extern int scm_legacy_call_atomic(struct device *dev,
+                                 const struct qcom_scm_desc *desc,
+                                 struct qcom_scm_res *res);
+extern int scm_legacy_call(struct device *dev, const struct qcom_scm_desc *desc,
+                          struct qcom_scm_res *res);
+
+#define QCOM_SCM_SVC_BOOT              0x01
+#define QCOM_SCM_BOOT_SET_ADDR         0x01
+#define QCOM_SCM_BOOT_TERMINATE_PC     0x02
+#define QCOM_SCM_BOOT_SDI_CONFIG       0x09
+#define QCOM_SCM_BOOT_SET_DLOAD_MODE   0x10
+#define QCOM_SCM_BOOT_SET_ADDR_MC      0x11
+#define QCOM_SCM_BOOT_SET_REMOTE_STATE 0x0a
+#define QCOM_SCM_FLUSH_FLAG_MASK       0x3
+#define QCOM_SCM_BOOT_MAX_CPUS         4
+#define QCOM_SCM_BOOT_MC_FLAG_AARCH64  BIT(0)
+#define QCOM_SCM_BOOT_MC_FLAG_COLDBOOT BIT(1)
+#define QCOM_SCM_BOOT_MC_FLAG_WARMBOOT BIT(2)
+
+#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
+
+#define QCOM_SCM_SVC_IO                        0x05
+#define QCOM_SCM_IO_READ               0x01
+#define QCOM_SCM_IO_WRITE              0x02
+
+#define QCOM_SCM_SVC_INFO              0x06
+#define QCOM_SCM_INFO_IS_CALL_AVAIL    0x01
+
+#define QCOM_SCM_SVC_MP                                0x0c
+#define QCOM_SCM_MP_RESTORE_SEC_CFG            0x02
+#define QCOM_SCM_MP_IOMMU_SECURE_PTBL_SIZE     0x03
+#define QCOM_SCM_MP_IOMMU_SECURE_PTBL_INIT     0x04
+#define QCOM_SCM_MP_IOMMU_SET_CP_POOL_SIZE     0x05
+#define QCOM_SCM_MP_VIDEO_VAR                  0x08
+#define QCOM_SCM_MP_ASSIGN                     0x16
+
+#define QCOM_SCM_SVC_OCMEM             0x0f
+#define QCOM_SCM_OCMEM_LOCK_CMD                0x01
+#define QCOM_SCM_OCMEM_UNLOCK_CMD      0x02
+
+#define QCOM_SCM_SVC_ES                        0x10    /* Enterprise Security */
+#define QCOM_SCM_ES_INVALIDATE_ICE_KEY 0x03
+#define QCOM_SCM_ES_CONFIG_SET_ICE_KEY 0x04
+
+#define QCOM_SCM_SVC_HDCP              0x11
+#define QCOM_SCM_HDCP_INVOKE           0x01
+
+#define QCOM_SCM_SVC_LMH                       0x13
+#define QCOM_SCM_LMH_LIMIT_PROFILE_CHANGE      0x01
+#define QCOM_SCM_LMH_LIMIT_DCVSH               0x10
+
+#define QCOM_SCM_SVC_SMMU_PROGRAM              0x15
+#define QCOM_SCM_SMMU_PT_FORMAT                        0x01
+#define QCOM_SCM_SMMU_CONFIG_ERRATA1           0x03
+#define QCOM_SCM_SMMU_CONFIG_ERRATA1_CLIENT_ALL        0x02
+
+#define QCOM_SCM_SVC_WAITQ                     0x24
+#define QCOM_SCM_WAITQ_RESUME                  0x02
+#define QCOM_SCM_WAITQ_GET_WQ_CTX              0x03
+
+/* common error codes */
+#define QCOM_SCM_V2_EBUSY      -12
+#define QCOM_SCM_ENOMEM                -5
+#define QCOM_SCM_EOPNOTSUPP    -4
+#define QCOM_SCM_EINVAL_ADDR   -3
+#define QCOM_SCM_EINVAL_ARG    -2
+#define QCOM_SCM_ERROR         -1
+#define QCOM_SCM_INTERRUPTED   1
+#define QCOM_SCM_WAITQ_SLEEP   2
+
+static inline int qcom_scm_remap_error(int err)
+{
+       switch (err) {
+       case QCOM_SCM_ERROR:
+               return -EIO;
+       case QCOM_SCM_EINVAL_ADDR:
+       case QCOM_SCM_EINVAL_ARG:
+               return -EINVAL;
+       case QCOM_SCM_EOPNOTSUPP:
+               return -EOPNOTSUPP;
+       case QCOM_SCM_ENOMEM:
+               return -ENOMEM;
+       case QCOM_SCM_V2_EBUSY:
+               return -EBUSY;
+       }
+       return -EINVAL;
+}
+
+#endif
diff --git a/drivers/firmware/qcom_qseecom.c b/drivers/firmware/qcom_qseecom.c
deleted file mode 100644 (file)
index 731e6d5..0000000
+++ /dev/null
@@ -1,120 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Driver for Qualcomm Secure Execution Environment (SEE) interface (QSEECOM).
- * Responsible for setting up and managing QSEECOM client devices.
- *
- * Copyright (C) 2023 Maximilian Luz <luzmaximilian@gmail.com>
- */
-#include <linux/auxiliary_bus.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <linux/types.h>
-
-#include <linux/firmware/qcom/qcom_qseecom.h>
-#include <linux/firmware/qcom/qcom_scm.h>
-
-struct qseecom_app_desc {
-       const char *app_name;
-       const char *dev_name;
-};
-
-static void qseecom_client_release(struct device *dev)
-{
-       struct qseecom_client *client;
-
-       client = container_of(dev, struct qseecom_client, aux_dev.dev);
-       kfree(client);
-}
-
-static void qseecom_client_remove(void *data)
-{
-       struct qseecom_client *client = data;
-
-       auxiliary_device_delete(&client->aux_dev);
-       auxiliary_device_uninit(&client->aux_dev);
-}
-
-static int qseecom_client_register(struct platform_device *qseecom_dev,
-                                  const struct qseecom_app_desc *desc)
-{
-       struct qseecom_client *client;
-       u32 app_id;
-       int ret;
-
-       /* Try to find the app ID, skip device if not found */
-       ret = qcom_scm_qseecom_app_get_id(desc->app_name, &app_id);
-       if (ret)
-               return ret == -ENOENT ? 0 : ret;
-
-       dev_info(&qseecom_dev->dev, "setting up client for %s\n", desc->app_name);
-
-       /* Allocate and set-up the client device */
-       client = kzalloc(sizeof(*client), GFP_KERNEL);
-       if (!client)
-               return -ENOMEM;
-
-       client->aux_dev.name = desc->dev_name;
-       client->aux_dev.dev.parent = &qseecom_dev->dev;
-       client->aux_dev.dev.release = qseecom_client_release;
-       client->app_id = app_id;
-
-       ret = auxiliary_device_init(&client->aux_dev);
-       if (ret) {
-               kfree(client);
-               return ret;
-       }
-
-       ret = auxiliary_device_add(&client->aux_dev);
-       if (ret) {
-               auxiliary_device_uninit(&client->aux_dev);
-               return ret;
-       }
-
-       ret = devm_add_action_or_reset(&qseecom_dev->dev, qseecom_client_remove, client);
-       if (ret)
-               return ret;
-
-       return 0;
-}
-
-/*
- * List of supported applications. One client device will be created per entry,
- * assuming the app has already been loaded (usually by firmware bootloaders)
- * and its ID can be queried successfully.
- */
-static const struct qseecom_app_desc qcom_qseecom_apps[] = {
-       { "qcom.tz.uefisecapp", "uefisecapp" },
-};
-
-static int qcom_qseecom_probe(struct platform_device *qseecom_dev)
-{
-       int ret;
-       int i;
-
-       /* Set up client devices for each base application */
-       for (i = 0; i < ARRAY_SIZE(qcom_qseecom_apps); i++) {
-               ret = qseecom_client_register(qseecom_dev, &qcom_qseecom_apps[i]);
-               if (ret)
-                       return ret;
-       }
-
-       return 0;
-}
-
-static struct platform_driver qcom_qseecom_driver = {
-       .driver = {
-               .name   = "qcom_qseecom",
-       },
-       .probe = qcom_qseecom_probe,
-};
-
-static int __init qcom_qseecom_init(void)
-{
-       return platform_driver_register(&qcom_qseecom_driver);
-}
-subsys_initcall(qcom_qseecom_init);
-
-MODULE_AUTHOR("Maximilian Luz <luzmaximilian@gmail.com>");
-MODULE_DESCRIPTION("Driver for the Qualcomm SEE (QSEECOM) interface");
-MODULE_LICENSE("GPL");
diff --git a/drivers/firmware/qcom_qseecom_uefisecapp.c b/drivers/firmware/qcom_qseecom_uefisecapp.c
deleted file mode 100644 (file)
index a33acda..0000000
+++ /dev/null
@@ -1,871 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Client driver for Qualcomm UEFI Secure Application (qcom.tz.uefisecapp).
- * Provides access to UEFI variables on platforms where they are secured by the
- * aforementioned Secure Execution Environment (SEE) application.
- *
- * Copyright (C) 2023 Maximilian Luz <luzmaximilian@gmail.com>
- */
-
-#include <linux/efi.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/mutex.h>
-#include <linux/of.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <linux/types.h>
-#include <linux/ucs2_string.h>
-
-#include <linux/firmware/qcom/qcom_qseecom.h>
-
-/* -- Qualcomm "uefisecapp" interface definitions. -------------------------- */
-
-/* Maximum length of name string with null-terminator */
-#define QSEE_MAX_NAME_LEN                      1024
-
-#define QSEE_CMD_UEFI(x)                       (0x8000 | (x))
-#define QSEE_CMD_UEFI_GET_VARIABLE             QSEE_CMD_UEFI(0)
-#define QSEE_CMD_UEFI_SET_VARIABLE             QSEE_CMD_UEFI(1)
-#define QSEE_CMD_UEFI_GET_NEXT_VARIABLE                QSEE_CMD_UEFI(2)
-#define QSEE_CMD_UEFI_QUERY_VARIABLE_INFO      QSEE_CMD_UEFI(3)
-
-/**
- * struct qsee_req_uefi_get_variable - Request for GetVariable command.
- * @command_id:  The ID of the command. Must be %QSEE_CMD_UEFI_GET_VARIABLE.
- * @length:      Length of the request in bytes, including this struct and any
- *               parameters (name, GUID) stored after it as well as any padding
- *               thereof for alignment.
- * @name_offset: Offset from the start of this struct to where the variable
- *               name is stored (as utf-16 string), in bytes.
- * @name_size:   Size of the name parameter in bytes, including null-terminator.
- * @guid_offset: Offset from the start of this struct to where the GUID
- *               parameter is stored, in bytes.
- * @guid_size:   Size of the GUID parameter in bytes, i.e. sizeof(efi_guid_t).
- * @data_size:   Size of the output buffer, in bytes.
- */
-struct qsee_req_uefi_get_variable {
-       u32 command_id;
-       u32 length;
-       u32 name_offset;
-       u32 name_size;
-       u32 guid_offset;
-       u32 guid_size;
-       u32 data_size;
-} __packed;
-
-/**
- * struct qsee_rsp_uefi_get_variable - Response for GetVariable command.
- * @command_id:  The ID of the command. Should be %QSEE_CMD_UEFI_GET_VARIABLE.
- * @length:      Length of the response in bytes, including this struct and the
- *               returned data.
- * @status:      Status of this command.
- * @attributes:  EFI variable attributes.
- * @data_offset: Offset from the start of this struct to where the data is
- *               stored, in bytes.
- * @data_size:   Size of the returned data, in bytes. In case status indicates
- *               that the buffer is too small, this will be the size required
- *               to store the EFI variable data.
- */
-struct qsee_rsp_uefi_get_variable {
-       u32 command_id;
-       u32 length;
-       u32 status;
-       u32 attributes;
-       u32 data_offset;
-       u32 data_size;
-} __packed;
-
-/**
- * struct qsee_req_uefi_set_variable - Request for the SetVariable command.
- * @command_id:  The ID of the command. Must be %QSEE_CMD_UEFI_SET_VARIABLE.
- * @length:      Length of the request in bytes, including this struct and any
- *               parameters (name, GUID, data) stored after it as well as any
- *               padding thereof required for alignment.
- * @name_offset: Offset from the start of this struct to where the variable
- *               name is stored (as utf-16 string), in bytes.
- * @name_size:   Size of the name parameter in bytes, including null-terminator.
- * @guid_offset: Offset from the start of this struct to where the GUID
- *               parameter is stored, in bytes.
- * @guid_size:   Size of the GUID parameter in bytes, i.e. sizeof(efi_guid_t).
- * @attributes:  The EFI variable attributes to set for this variable.
- * @data_offset: Offset from the start of this struct to where the EFI variable
- *               data is stored, in bytes.
- * @data_size:   Size of EFI variable data, in bytes.
- *
- */
-struct qsee_req_uefi_set_variable {
-       u32 command_id;
-       u32 length;
-       u32 name_offset;
-       u32 name_size;
-       u32 guid_offset;
-       u32 guid_size;
-       u32 attributes;
-       u32 data_offset;
-       u32 data_size;
-} __packed;
-
-/**
- * struct qsee_rsp_uefi_set_variable - Response for the SetVariable command.
- * @command_id:  The ID of the command. Should be %QSEE_CMD_UEFI_SET_VARIABLE.
- * @length:      The length of this response, i.e. the size of this struct in
- *               bytes.
- * @status:      Status of this command.
- * @_unknown1:   Unknown response field.
- * @_unknown2:   Unknown response field.
- */
-struct qsee_rsp_uefi_set_variable {
-       u32 command_id;
-       u32 length;
-       u32 status;
-       u32 _unknown1;
-       u32 _unknown2;
-} __packed;
-
-/**
- * struct qsee_req_uefi_get_next_variable - Request for the
- * GetNextVariableName command.
- * @command_id:  The ID of the command. Must be
- *               %QSEE_CMD_UEFI_GET_NEXT_VARIABLE.
- * @length:      Length of the request in bytes, including this struct and any
- *               parameters (name, GUID) stored after it as well as any padding
- *               thereof for alignment.
- * @guid_offset: Offset from the start of this struct to where the GUID
- *               parameter is stored, in bytes.
- * @guid_size:   Size of the GUID parameter in bytes, i.e. sizeof(efi_guid_t).
- * @name_offset: Offset from the start of this struct to where the variable
- *               name is stored (as utf-16 string), in bytes.
- * @name_size:   Size of the name parameter in bytes, including null-terminator.
- */
-struct qsee_req_uefi_get_next_variable {
-       u32 command_id;
-       u32 length;
-       u32 guid_offset;
-       u32 guid_size;
-       u32 name_offset;
-       u32 name_size;
-} __packed;
-
-/**
- * struct qsee_rsp_uefi_get_next_variable - Response for the
- * GetNextVariableName command.
- * @command_id:  The ID of the command. Should be
- *               %QSEE_CMD_UEFI_GET_NEXT_VARIABLE.
- * @length:      Length of the response in bytes, including this struct and any
- *               parameters (name, GUID) stored after it as well as any padding
- *               thereof for alignment.
- * @status:      Status of this command.
- * @guid_offset: Offset from the start of this struct to where the GUID
- *               parameter is stored, in bytes.
- * @guid_size:   Size of the GUID parameter in bytes, i.e. sizeof(efi_guid_t).
- * @name_offset: Offset from the start of this struct to where the variable
- *               name is stored (as utf-16 string), in bytes.
- * @name_size:   Size of the name parameter in bytes, including null-terminator.
- */
-struct qsee_rsp_uefi_get_next_variable {
-       u32 command_id;
-       u32 length;
-       u32 status;
-       u32 guid_offset;
-       u32 guid_size;
-       u32 name_offset;
-       u32 name_size;
-} __packed;
-
-/**
- * struct qsee_req_uefi_query_variable_info - Response for the
- * GetNextVariableName command.
- * @command_id: The ID of the command. Must be
- *              %QSEE_CMD_UEFI_QUERY_VARIABLE_INFO.
- * @length:     The length of this request, i.e. the size of this struct in
- *              bytes.
- * @attributes: The storage attributes to query the info for.
- */
-struct qsee_req_uefi_query_variable_info {
-       u32 command_id;
-       u32 length;
-       u32 attributes;
-} __packed;
-
-/**
- * struct qsee_rsp_uefi_query_variable_info - Response for the
- * GetNextVariableName command.
- * @command_id:        The ID of the command. Must be
- *                     %QSEE_CMD_UEFI_QUERY_VARIABLE_INFO.
- * @length:            The length of this response, i.e. the size of this
- *                     struct in bytes.
- * @status:            Status of this command.
- * @_pad:              Padding.
- * @storage_space:     Full storage space size, in bytes.
- * @remaining_space:   Free storage space available, in bytes.
- * @max_variable_size: Maximum variable data size, in bytes.
- */
-struct qsee_rsp_uefi_query_variable_info {
-       u32 command_id;
-       u32 length;
-       u32 status;
-       u32 _pad;
-       u64 storage_space;
-       u64 remaining_space;
-       u64 max_variable_size;
-} __packed;
-
-/* -- Alignment helpers ----------------------------------------------------- */
-
-/*
- * Helper macro to ensure proper alignment of types (fields and arrays) when
- * stored in some (contiguous) buffer.
- *
- * Note: The driver from which this one has been reverse-engineered expects an
- * alignment of 8 bytes (64 bits) for GUIDs. Our definition of efi_guid_t,
- * however, has an alignment of 4 byte (32 bits). So far, this seems to work
- * fine here. See also the comment on the typedef of efi_guid_t.
- */
-#define qcuefi_buf_align_fields(fields...)                                     \
-       ({                                                                      \
-               size_t __len = 0;                                               \
-               fields                                                          \
-               __len;                                                          \
-       })
-
-#define __field_impl(size, align, offset)                                      \
-       ({                                                                      \
-               size_t *__offset = (offset);                                    \
-               size_t __aligned;                                               \
-                                                                               \
-               __aligned = ALIGN(__len, align);                                \
-               __len = __aligned + (size);                                     \
-                                                                               \
-               if (__offset)                                                   \
-                       *__offset = __aligned;                                  \
-       });
-
-#define __array_offs(type, count, offset)                                      \
-       __field_impl(sizeof(type) * (count), __alignof__(type), offset)
-
-#define __array(type, count)           __array_offs(type, count, NULL)
-#define __field_offs(type, offset)     __array_offs(type, 1, offset)
-#define __field(type)                  __array_offs(type, 1, NULL)
-
-/* -- UEFI app interface. --------------------------------------------------- */
-
-struct qcuefi_client {
-       struct qseecom_client *client;
-       struct efivars efivars;
-};
-
-static struct device *qcuefi_dev(struct qcuefi_client *qcuefi)
-{
-       return &qcuefi->client->aux_dev.dev;
-}
-
-static efi_status_t qsee_uefi_status_to_efi(u32 status)
-{
-       u64 category = status & 0xf0000000;
-       u64 code = status & 0x0fffffff;
-
-       return category << (BITS_PER_LONG - 32) | code;
-}
-
-static efi_status_t qsee_uefi_get_variable(struct qcuefi_client *qcuefi, const efi_char16_t *name,
-                                          const efi_guid_t *guid, u32 *attributes,
-                                          unsigned long *data_size, void *data)
-{
-       struct qsee_req_uefi_get_variable *req_data;
-       struct qsee_rsp_uefi_get_variable *rsp_data;
-       unsigned long buffer_size = *data_size;
-       efi_status_t efi_status = EFI_SUCCESS;
-       unsigned long name_length;
-       size_t guid_offs;
-       size_t name_offs;
-       size_t req_size;
-       size_t rsp_size;
-       ssize_t status;
-
-       if (!name || !guid)
-               return EFI_INVALID_PARAMETER;
-
-       name_length = ucs2_strnlen(name, QSEE_MAX_NAME_LEN) + 1;
-       if (name_length > QSEE_MAX_NAME_LEN)
-               return EFI_INVALID_PARAMETER;
-
-       if (buffer_size && !data)
-               return EFI_INVALID_PARAMETER;
-
-       req_size = qcuefi_buf_align_fields(
-               __field(*req_data)
-               __array_offs(*name, name_length, &name_offs)
-               __field_offs(*guid, &guid_offs)
-       );
-
-       rsp_size = qcuefi_buf_align_fields(
-               __field(*rsp_data)
-               __array(u8, buffer_size)
-       );
-
-       req_data = kzalloc(req_size, GFP_KERNEL);
-       if (!req_data) {
-               efi_status = EFI_OUT_OF_RESOURCES;
-               goto out;
-       }
-
-       rsp_data = kzalloc(rsp_size, GFP_KERNEL);
-       if (!rsp_data) {
-               efi_status = EFI_OUT_OF_RESOURCES;
-               goto out_free_req;
-       }
-
-       req_data->command_id = QSEE_CMD_UEFI_GET_VARIABLE;
-       req_data->data_size = buffer_size;
-       req_data->name_offset = name_offs;
-       req_data->name_size = name_length * sizeof(*name);
-       req_data->guid_offset = guid_offs;
-       req_data->guid_size = sizeof(*guid);
-       req_data->length = req_size;
-
-       status = ucs2_strscpy(((void *)req_data) + req_data->name_offset, name, name_length);
-       if (status < 0)
-               return EFI_INVALID_PARAMETER;
-
-       memcpy(((void *)req_data) + req_data->guid_offset, guid, req_data->guid_size);
-
-       status = qcom_qseecom_app_send(qcuefi->client, req_data, req_size, rsp_data, rsp_size);
-       if (status) {
-               efi_status = EFI_DEVICE_ERROR;
-               goto out_free;
-       }
-
-       if (rsp_data->command_id != QSEE_CMD_UEFI_GET_VARIABLE) {
-               efi_status = EFI_DEVICE_ERROR;
-               goto out_free;
-       }
-
-       if (rsp_data->length < sizeof(*rsp_data)) {
-               efi_status = EFI_DEVICE_ERROR;
-               goto out_free;
-       }
-
-       if (rsp_data->status) {
-               dev_dbg(qcuefi_dev(qcuefi), "%s: uefisecapp error: 0x%x\n",
-                       __func__, rsp_data->status);
-               efi_status = qsee_uefi_status_to_efi(rsp_data->status);
-
-               /* Update size and attributes in case buffer is too small. */
-               if (efi_status == EFI_BUFFER_TOO_SMALL) {
-                       *data_size = rsp_data->data_size;
-                       if (attributes)
-                               *attributes = rsp_data->attributes;
-               }
-
-               goto out_free;
-       }
-
-       if (rsp_data->length > rsp_size) {
-               efi_status = EFI_DEVICE_ERROR;
-               goto out_free;
-       }
-
-       if (rsp_data->data_offset + rsp_data->data_size > rsp_data->length) {
-               efi_status = EFI_DEVICE_ERROR;
-               goto out_free;
-       }
-
-       /*
-        * Note: We need to set attributes and data size even if the buffer is
-        * too small and we won't copy any data. This is described in spec, so
-        * that callers can either allocate a buffer properly (with two calls
-        * to this function) or just read back attributes withouth having to
-        * deal with that.
-        *
-        * Specifically:
-        * - If we have a buffer size of zero and no buffer, just return the
-        *   attributes, required size, and indicate success.
-        * - If the buffer size is nonzero but too small, indicate that as an
-        *   error.
-        * - Otherwise, we are good to copy the data.
-        *
-        * Note that we have already ensured above that the buffer pointer is
-        * non-NULL if its size is nonzero.
-        */
-       *data_size = rsp_data->data_size;
-       if (attributes)
-               *attributes = rsp_data->attributes;
-
-       if (buffer_size == 0 && !data) {
-               efi_status = EFI_SUCCESS;
-               goto out_free;
-       }
-
-       if (buffer_size < rsp_data->data_size) {
-               efi_status = EFI_BUFFER_TOO_SMALL;
-               goto out_free;
-       }
-
-       memcpy(data, ((void *)rsp_data) + rsp_data->data_offset, rsp_data->data_size);
-
-out_free:
-       kfree(rsp_data);
-out_free_req:
-       kfree(req_data);
-out:
-       return efi_status;
-}
-
-static efi_status_t qsee_uefi_set_variable(struct qcuefi_client *qcuefi, const efi_char16_t *name,
-                                          const efi_guid_t *guid, u32 attributes,
-                                          unsigned long data_size, const void *data)
-{
-       struct qsee_req_uefi_set_variable *req_data;
-       struct qsee_rsp_uefi_set_variable *rsp_data;
-       efi_status_t efi_status = EFI_SUCCESS;
-       unsigned long name_length;
-       size_t name_offs;
-       size_t guid_offs;
-       size_t data_offs;
-       size_t req_size;
-       ssize_t status;
-
-       if (!name || !guid)
-               return EFI_INVALID_PARAMETER;
-
-       name_length = ucs2_strnlen(name, QSEE_MAX_NAME_LEN) + 1;
-       if (name_length > QSEE_MAX_NAME_LEN)
-               return EFI_INVALID_PARAMETER;
-
-       /*
-        * Make sure we have some data if data_size is nonzero. Note that using
-        * a size of zero is a valid use-case described in spec and deletes the
-        * variable.
-        */
-       if (data_size && !data)
-               return EFI_INVALID_PARAMETER;
-
-       req_size = qcuefi_buf_align_fields(
-               __field(*req_data)
-               __array_offs(*name, name_length, &name_offs)
-               __field_offs(*guid, &guid_offs)
-               __array_offs(u8, data_size, &data_offs)
-       );
-
-       req_data = kzalloc(req_size, GFP_KERNEL);
-       if (!req_data) {
-               efi_status = EFI_OUT_OF_RESOURCES;
-               goto out;
-       }
-
-       rsp_data = kzalloc(sizeof(*rsp_data), GFP_KERNEL);
-       if (!rsp_data) {
-               efi_status = EFI_OUT_OF_RESOURCES;
-               goto out_free_req;
-       }
-
-       req_data->command_id = QSEE_CMD_UEFI_SET_VARIABLE;
-       req_data->attributes = attributes;
-       req_data->name_offset = name_offs;
-       req_data->name_size = name_length * sizeof(*name);
-       req_data->guid_offset = guid_offs;
-       req_data->guid_size = sizeof(*guid);
-       req_data->data_offset = data_offs;
-       req_data->data_size = data_size;
-       req_data->length = req_size;
-
-       status = ucs2_strscpy(((void *)req_data) + req_data->name_offset, name, name_length);
-       if (status < 0)
-               return EFI_INVALID_PARAMETER;
-
-       memcpy(((void *)req_data) + req_data->guid_offset, guid, req_data->guid_size);
-
-       if (data_size)
-               memcpy(((void *)req_data) + req_data->data_offset, data, req_data->data_size);
-
-       status = qcom_qseecom_app_send(qcuefi->client, req_data, req_size, rsp_data,
-                                      sizeof(*rsp_data));
-       if (status) {
-               efi_status = EFI_DEVICE_ERROR;
-               goto out_free;
-       }
-
-       if (rsp_data->command_id != QSEE_CMD_UEFI_SET_VARIABLE) {
-               efi_status = EFI_DEVICE_ERROR;
-               goto out_free;
-       }
-
-       if (rsp_data->length != sizeof(*rsp_data)) {
-               efi_status = EFI_DEVICE_ERROR;
-               goto out_free;
-       }
-
-       if (rsp_data->status) {
-               dev_dbg(qcuefi_dev(qcuefi), "%s: uefisecapp error: 0x%x\n",
-                       __func__, rsp_data->status);
-               efi_status = qsee_uefi_status_to_efi(rsp_data->status);
-       }
-
-out_free:
-       kfree(rsp_data);
-out_free_req:
-       kfree(req_data);
-out:
-       return efi_status;
-}
-
-static efi_status_t qsee_uefi_get_next_variable(struct qcuefi_client *qcuefi,
-                                               unsigned long *name_size, efi_char16_t *name,
-                                               efi_guid_t *guid)
-{
-       struct qsee_req_uefi_get_next_variable *req_data;
-       struct qsee_rsp_uefi_get_next_variable *rsp_data;
-       efi_status_t efi_status = EFI_SUCCESS;
-       size_t guid_offs;
-       size_t name_offs;
-       size_t req_size;
-       size_t rsp_size;
-       ssize_t status;
-
-       if (!name_size || !name || !guid)
-               return EFI_INVALID_PARAMETER;
-
-       if (*name_size == 0)
-               return EFI_INVALID_PARAMETER;
-
-       req_size = qcuefi_buf_align_fields(
-               __field(*req_data)
-               __field_offs(*guid, &guid_offs)
-               __array_offs(*name, *name_size / sizeof(*name), &name_offs)
-       );
-
-       rsp_size = qcuefi_buf_align_fields(
-               __field(*rsp_data)
-               __field(*guid)
-               __array(*name, *name_size / sizeof(*name))
-       );
-
-       req_data = kzalloc(req_size, GFP_KERNEL);
-       if (!req_data) {
-               efi_status = EFI_OUT_OF_RESOURCES;
-               goto out;
-       }
-
-       rsp_data = kzalloc(rsp_size, GFP_KERNEL);
-       if (!rsp_data) {
-               efi_status = EFI_OUT_OF_RESOURCES;
-               goto out_free_req;
-       }
-
-       req_data->command_id = QSEE_CMD_UEFI_GET_NEXT_VARIABLE;
-       req_data->guid_offset = guid_offs;
-       req_data->guid_size = sizeof(*guid);
-       req_data->name_offset = name_offs;
-       req_data->name_size = *name_size;
-       req_data->length = req_size;
-
-       memcpy(((void *)req_data) + req_data->guid_offset, guid, req_data->guid_size);
-       status = ucs2_strscpy(((void *)req_data) + req_data->name_offset, name,
-                             *name_size / sizeof(*name));
-       if (status < 0)
-               return EFI_INVALID_PARAMETER;
-
-       status = qcom_qseecom_app_send(qcuefi->client, req_data, req_size, rsp_data, rsp_size);
-       if (status) {
-               efi_status = EFI_DEVICE_ERROR;
-               goto out_free;
-       }
-
-       if (rsp_data->command_id != QSEE_CMD_UEFI_GET_NEXT_VARIABLE) {
-               efi_status = EFI_DEVICE_ERROR;
-               goto out_free;
-       }
-
-       if (rsp_data->length < sizeof(*rsp_data)) {
-               efi_status = EFI_DEVICE_ERROR;
-               goto out_free;
-       }
-
-       if (rsp_data->status) {
-               dev_dbg(qcuefi_dev(qcuefi), "%s: uefisecapp error: 0x%x\n",
-                       __func__, rsp_data->status);
-               efi_status = qsee_uefi_status_to_efi(rsp_data->status);
-
-               /*
-                * If the buffer to hold the name is too small, update the
-                * name_size with the required size, so that callers can
-                * reallocate it accordingly.
-                */
-               if (efi_status == EFI_BUFFER_TOO_SMALL)
-                       *name_size = rsp_data->name_size;
-
-               goto out_free;
-       }
-
-       if (rsp_data->length > rsp_size) {
-               efi_status = EFI_DEVICE_ERROR;
-               goto out_free;
-       }
-
-       if (rsp_data->name_offset + rsp_data->name_size > rsp_data->length) {
-               efi_status = EFI_DEVICE_ERROR;
-               goto out_free;
-       }
-
-       if (rsp_data->guid_offset + rsp_data->guid_size > rsp_data->length) {
-               efi_status = EFI_DEVICE_ERROR;
-               goto out_free;
-       }
-
-       if (rsp_data->name_size > *name_size) {
-               *name_size = rsp_data->name_size;
-               efi_status = EFI_BUFFER_TOO_SMALL;
-               goto out_free;
-       }
-
-       if (rsp_data->guid_size != sizeof(*guid)) {
-               efi_status = EFI_DEVICE_ERROR;
-               goto out_free;
-       }
-
-       memcpy(guid, ((void *)rsp_data) + rsp_data->guid_offset, rsp_data->guid_size);
-       status = ucs2_strscpy(name, ((void *)rsp_data) + rsp_data->name_offset,
-                             rsp_data->name_size / sizeof(*name));
-       *name_size = rsp_data->name_size;
-
-       if (status < 0) {
-               /*
-                * Return EFI_DEVICE_ERROR here because the buffer size should
-                * have already been validated above, causing this function to
-                * bail with EFI_BUFFER_TOO_SMALL.
-                */
-               return EFI_DEVICE_ERROR;
-       }
-
-out_free:
-       kfree(rsp_data);
-out_free_req:
-       kfree(req_data);
-out:
-       return efi_status;
-}
-
-static efi_status_t qsee_uefi_query_variable_info(struct qcuefi_client *qcuefi, u32 attr,
-                                                 u64 *storage_space, u64 *remaining_space,
-                                                 u64 *max_variable_size)
-{
-       struct qsee_req_uefi_query_variable_info *req_data;
-       struct qsee_rsp_uefi_query_variable_info *rsp_data;
-       efi_status_t efi_status = EFI_SUCCESS;
-       int status;
-
-       req_data = kzalloc(sizeof(*req_data), GFP_KERNEL);
-       if (!req_data) {
-               efi_status = EFI_OUT_OF_RESOURCES;
-               goto out;
-       }
-
-       rsp_data = kzalloc(sizeof(*rsp_data), GFP_KERNEL);
-       if (!rsp_data) {
-               efi_status = EFI_OUT_OF_RESOURCES;
-               goto out_free_req;
-       }
-
-       req_data->command_id = QSEE_CMD_UEFI_QUERY_VARIABLE_INFO;
-       req_data->attributes = attr;
-       req_data->length = sizeof(*req_data);
-
-       status = qcom_qseecom_app_send(qcuefi->client, req_data, sizeof(*req_data), rsp_data,
-                                      sizeof(*rsp_data));
-       if (status) {
-               efi_status = EFI_DEVICE_ERROR;
-               goto out_free;
-       }
-
-       if (rsp_data->command_id != QSEE_CMD_UEFI_QUERY_VARIABLE_INFO) {
-               efi_status = EFI_DEVICE_ERROR;
-               goto out_free;
-       }
-
-       if (rsp_data->length != sizeof(*rsp_data)) {
-               efi_status = EFI_DEVICE_ERROR;
-               goto out_free;
-       }
-
-       if (rsp_data->status) {
-               dev_dbg(qcuefi_dev(qcuefi), "%s: uefisecapp error: 0x%x\n",
-                       __func__, rsp_data->status);
-               efi_status = qsee_uefi_status_to_efi(rsp_data->status);
-               goto out_free;
-       }
-
-       if (storage_space)
-               *storage_space = rsp_data->storage_space;
-
-       if (remaining_space)
-               *remaining_space = rsp_data->remaining_space;
-
-       if (max_variable_size)
-               *max_variable_size = rsp_data->max_variable_size;
-
-out_free:
-       kfree(rsp_data);
-out_free_req:
-       kfree(req_data);
-out:
-       return efi_status;
-}
-
-/* -- Global efivar interface. ---------------------------------------------- */
-
-static struct qcuefi_client *__qcuefi;
-static DEFINE_MUTEX(__qcuefi_lock);
-
-static int qcuefi_set_reference(struct qcuefi_client *qcuefi)
-{
-       mutex_lock(&__qcuefi_lock);
-
-       if (qcuefi && __qcuefi) {
-               mutex_unlock(&__qcuefi_lock);
-               return -EEXIST;
-       }
-
-       __qcuefi = qcuefi;
-
-       mutex_unlock(&__qcuefi_lock);
-       return 0;
-}
-
-static struct qcuefi_client *qcuefi_acquire(void)
-{
-       mutex_lock(&__qcuefi_lock);
-       return __qcuefi;
-}
-
-static void qcuefi_release(void)
-{
-       mutex_unlock(&__qcuefi_lock);
-}
-
-static efi_status_t qcuefi_get_variable(efi_char16_t *name, efi_guid_t *vendor, u32 *attr,
-                                       unsigned long *data_size, void *data)
-{
-       struct qcuefi_client *qcuefi;
-       efi_status_t status;
-
-       qcuefi = qcuefi_acquire();
-       if (!qcuefi)
-               return EFI_NOT_READY;
-
-       status = qsee_uefi_get_variable(qcuefi, name, vendor, attr, data_size, data);
-
-       qcuefi_release();
-       return status;
-}
-
-static efi_status_t qcuefi_set_variable(efi_char16_t *name, efi_guid_t *vendor,
-                                       u32 attr, unsigned long data_size, void *data)
-{
-       struct qcuefi_client *qcuefi;
-       efi_status_t status;
-
-       qcuefi = qcuefi_acquire();
-       if (!qcuefi)
-               return EFI_NOT_READY;
-
-       status = qsee_uefi_set_variable(qcuefi, name, vendor, attr, data_size, data);
-
-       qcuefi_release();
-       return status;
-}
-
-static efi_status_t qcuefi_get_next_variable(unsigned long *name_size, efi_char16_t *name,
-                                            efi_guid_t *vendor)
-{
-       struct qcuefi_client *qcuefi;
-       efi_status_t status;
-
-       qcuefi = qcuefi_acquire();
-       if (!qcuefi)
-               return EFI_NOT_READY;
-
-       status = qsee_uefi_get_next_variable(qcuefi, name_size, name, vendor);
-
-       qcuefi_release();
-       return status;
-}
-
-static efi_status_t qcuefi_query_variable_info(u32 attr, u64 *storage_space, u64 *remaining_space,
-                                              u64 *max_variable_size)
-{
-       struct qcuefi_client *qcuefi;
-       efi_status_t status;
-
-       qcuefi = qcuefi_acquire();
-       if (!qcuefi)
-               return EFI_NOT_READY;
-
-       status = qsee_uefi_query_variable_info(qcuefi, attr, storage_space, remaining_space,
-                                              max_variable_size);
-
-       qcuefi_release();
-       return status;
-}
-
-static const struct efivar_operations qcom_efivar_ops = {
-       .get_variable = qcuefi_get_variable,
-       .set_variable = qcuefi_set_variable,
-       .get_next_variable = qcuefi_get_next_variable,
-       .query_variable_info = qcuefi_query_variable_info,
-};
-
-/* -- Driver setup. --------------------------------------------------------- */
-
-static int qcom_uefisecapp_probe(struct auxiliary_device *aux_dev,
-                                const struct auxiliary_device_id *aux_dev_id)
-{
-       struct qcuefi_client *qcuefi;
-       int status;
-
-       qcuefi = devm_kzalloc(&aux_dev->dev, sizeof(*qcuefi), GFP_KERNEL);
-       if (!qcuefi)
-               return -ENOMEM;
-
-       qcuefi->client = container_of(aux_dev, struct qseecom_client, aux_dev);
-
-       auxiliary_set_drvdata(aux_dev, qcuefi);
-       status = qcuefi_set_reference(qcuefi);
-       if (status)
-               return status;
-
-       status = efivars_register(&qcuefi->efivars, &qcom_efivar_ops);
-       if (status)
-               qcuefi_set_reference(NULL);
-
-       return status;
-}
-
-static void qcom_uefisecapp_remove(struct auxiliary_device *aux_dev)
-{
-       struct qcuefi_client *qcuefi = auxiliary_get_drvdata(aux_dev);
-
-       efivars_unregister(&qcuefi->efivars);
-       qcuefi_set_reference(NULL);
-}
-
-static const struct auxiliary_device_id qcom_uefisecapp_id_table[] = {
-       { .name = "qcom_qseecom.uefisecapp" },
-       {}
-};
-MODULE_DEVICE_TABLE(auxiliary, qcom_uefisecapp_id_table);
-
-static struct auxiliary_driver qcom_uefisecapp_driver = {
-       .probe = qcom_uefisecapp_probe,
-       .remove = qcom_uefisecapp_remove,
-       .id_table = qcom_uefisecapp_id_table,
-       .driver = {
-               .name = "qcom_qseecom_uefisecapp",
-               .probe_type = PROBE_PREFER_ASYNCHRONOUS,
-       },
-};
-module_auxiliary_driver(qcom_uefisecapp_driver);
-
-MODULE_AUTHOR("Maximilian Luz <luzmaximilian@gmail.com>");
-MODULE_DESCRIPTION("Client driver for Qualcomm SEE UEFI Secure App");
-MODULE_LICENSE("GPL");
diff --git a/drivers/firmware/qcom_scm-legacy.c b/drivers/firmware/qcom_scm-legacy.c
deleted file mode 100644 (file)
index 029e6d1..0000000
+++ /dev/null
@@ -1,246 +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/firmware/qcom/qcom_scm.h>
-#include <linux/arm-smccc.h>
-#include <linux/dma-mapping.h>
-
-#include "qcom_scm.h"
-
-static DEFINE_MUTEX(qcom_scm_lock);
-
-
-/**
- * struct arm_smccc_args
- * @args:      The array of values used in registers in smc instruction
- */
-struct arm_smccc_args {
-       unsigned long args[8];
-};
-
-
-/**
- * struct scm_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 scm_legacy_get_command_buffer()
- *
- * An SCM command is laid out in memory as follows:
- *
- *     ------------------- <--- struct scm_legacy_command
- *     | command header  |
- *     ------------------- <--- scm_legacy_get_command_buffer()
- *     | command buffer  |
- *     ------------------- <--- struct scm_legacy_response and
- *     | response header |      scm_legacy_command_to_response()
- *     ------------------- <--- scm_legacy_get_response_buffer()
- *     | response buffer |
- *     -------------------
- *
- * There can be arbitrary padding between the headers and buffers so
- * you should always use the appropriate scm_legacy_get_*_buffer() routines
- * to access the buffers in a safe manner.
- */
-struct scm_legacy_command {
-       __le32 len;
-       __le32 buf_offset;
-       __le32 resp_hdr_offset;
-       __le32 id;
-       __le32 buf[];
-};
-
-/**
- * struct scm_legacy_response - one SCM response buffer
- * @len: total available memory for response
- * @buf_offset: start of response data relative to start of scm_legacy_response
- * @is_complete: indicates if the command has finished processing
- */
-struct scm_legacy_response {
-       __le32 len;
-       __le32 buf_offset;
-       __le32 is_complete;
-};
-
-/**
- * scm_legacy_command_to_response() - Get a pointer to a scm_legacy_response
- * @cmd: command
- *
- * Returns a pointer to a response for a command.
- */
-static inline struct scm_legacy_response *scm_legacy_command_to_response(
-               const struct scm_legacy_command *cmd)
-{
-       return (void *)cmd + le32_to_cpu(cmd->resp_hdr_offset);
-}
-
-/**
- * scm_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 *scm_legacy_get_command_buffer(
-               const struct scm_legacy_command *cmd)
-{
-       return (void *)cmd->buf;
-}
-
-/**
- * scm_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 *scm_legacy_get_response_buffer(
-               const struct scm_legacy_response *rsp)
-{
-       return (void *)rsp + le32_to_cpu(rsp->buf_offset);
-}
-
-static void __scm_legacy_do(const struct arm_smccc_args *smc,
-                           struct arm_smccc_res *res)
-{
-       do {
-               arm_smccc_smc(smc->args[0], smc->args[1], smc->args[2],
-                             smc->args[3], smc->args[4], smc->args[5],
-                             smc->args[6], smc->args[7], res);
-       } while (res->a0 == QCOM_SCM_INTERRUPTED);
-}
-
-/**
- * scm_legacy_call() - Sends a command to the SCM and waits for the command to
- * finish processing.
- * @dev:       device
- * @desc:      descriptor structure containing arguments and return values
- * @res:        results from SMC call
- *
- * 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.
- */
-int scm_legacy_call(struct device *dev, const struct qcom_scm_desc *desc,
-                   struct qcom_scm_res *res)
-{
-       u8 arglen = desc->arginfo & 0xf;
-       int ret = 0, context_id;
-       unsigned int i;
-       struct scm_legacy_command *cmd;
-       struct scm_legacy_response *rsp;
-       struct arm_smccc_args smc = {0};
-       struct arm_smccc_res smc_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;
-       const __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(SCM_LEGACY_FNID(desc->svc, desc->cmd));
-
-       arg_buf = scm_legacy_get_command_buffer(cmd);
-       for (i = 0; i < arglen; i++)
-               arg_buf[i] = cpu_to_le32(desc->args[i]);
-
-       rsp = scm_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.args[0] = 1;
-       smc.args[1] = (unsigned long)&context_id;
-       smc.args[2] = cmd_phys;
-
-       mutex_lock(&qcom_scm_lock);
-       __scm_legacy_do(&smc, &smc_res);
-       if (smc_res.a0)
-               ret = qcom_scm_remap_error(smc_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);
-
-       if (res) {
-               res_buf = scm_legacy_get_response_buffer(rsp);
-               for (i = 0; i < MAX_QCOM_SCM_RETS; i++)
-                       res->result[i] = le32_to_cpu(res_buf[i]);
-       }
-out:
-       dma_unmap_single(dev, cmd_phys, alloc_len, DMA_TO_DEVICE);
-       kfree(cmd);
-       return ret;
-}
-
-#define SCM_LEGACY_ATOMIC_N_REG_ARGS   5
-#define SCM_LEGACY_ATOMIC_FIRST_REG_IDX        2
-#define SCM_LEGACY_CLASS_REGISTER              (0x2 << 8)
-#define SCM_LEGACY_MASK_IRQS           BIT(5)
-#define SCM_LEGACY_ATOMIC_ID(svc, cmd, n) \
-                               ((SCM_LEGACY_FNID(svc, cmd) << 12) | \
-                               SCM_LEGACY_CLASS_REGISTER | \
-                               SCM_LEGACY_MASK_IRQS | \
-                               (n & 0xf))
-
-/**
- * scm_legacy_call_atomic() - Send an atomic SCM command with up to 5 arguments
- * and 3 return values
- * @unused: device, legacy argument, not used, can be NULL
- * @desc: SCM call descriptor containing arguments
- * @res:  SCM call return values
- *
- * This shall only be used with commands that are guaranteed to be
- * uninterruptable, atomic and SMP safe.
- */
-int scm_legacy_call_atomic(struct device *unused,
-                          const struct qcom_scm_desc *desc,
-                          struct qcom_scm_res *res)
-{
-       int context_id;
-       struct arm_smccc_res smc_res;
-       size_t arglen = desc->arginfo & 0xf;
-
-       BUG_ON(arglen > SCM_LEGACY_ATOMIC_N_REG_ARGS);
-
-       arm_smccc_smc(SCM_LEGACY_ATOMIC_ID(desc->svc, desc->cmd, arglen),
-                     (unsigned long)&context_id,
-                     desc->args[0], desc->args[1], desc->args[2],
-                     desc->args[3], desc->args[4], 0, &smc_res);
-
-       if (res) {
-               res->result[0] = smc_res.a1;
-               res->result[1] = smc_res.a2;
-               res->result[2] = smc_res.a3;
-       }
-
-       return smc_res.a0;
-}
diff --git a/drivers/firmware/qcom_scm-smc.c b/drivers/firmware/qcom_scm-smc.c
deleted file mode 100644 (file)
index 16cf88a..0000000
+++ /dev/null
@@ -1,225 +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/firmware/qcom/qcom_scm.h>
-#include <linux/arm-smccc.h>
-#include <linux/dma-mapping.h>
-
-#include "qcom_scm.h"
-
-/**
- * struct arm_smccc_args
- * @args:      The array of values used in registers in smc instruction
- */
-struct arm_smccc_args {
-       unsigned long args[8];
-};
-
-static DEFINE_MUTEX(qcom_scm_lock);
-
-#define QCOM_SCM_EBUSY_WAIT_MS 30
-#define QCOM_SCM_EBUSY_MAX_RETRY 20
-
-#define SCM_SMC_N_REG_ARGS     4
-#define SCM_SMC_FIRST_EXT_IDX  (SCM_SMC_N_REG_ARGS - 1)
-#define SCM_SMC_N_EXT_ARGS     (MAX_QCOM_SCM_ARGS - SCM_SMC_N_REG_ARGS + 1)
-#define SCM_SMC_FIRST_REG_IDX  2
-#define SCM_SMC_LAST_REG_IDX   (SCM_SMC_FIRST_REG_IDX + SCM_SMC_N_REG_ARGS - 1)
-
-static void __scm_smc_do_quirk(const struct arm_smccc_args *smc,
-                              struct arm_smccc_res *res)
-{
-       unsigned long a0 = smc->args[0];
-       struct arm_smccc_quirk quirk = { .id = ARM_SMCCC_QUIRK_QCOM_A6 };
-
-       quirk.state.a6 = 0;
-
-       do {
-               arm_smccc_smc_quirk(a0, smc->args[1], smc->args[2],
-                                   smc->args[3], smc->args[4], smc->args[5],
-                                   quirk.state.a6, smc->args[7], res, &quirk);
-
-               if (res->a0 == QCOM_SCM_INTERRUPTED)
-                       a0 = res->a0;
-
-       } while (res->a0 == QCOM_SCM_INTERRUPTED);
-}
-
-static void fill_wq_resume_args(struct arm_smccc_args *resume, u32 smc_call_ctx)
-{
-       memset(resume->args, 0, sizeof(resume->args[0]) * ARRAY_SIZE(resume->args));
-
-       resume->args[0] = ARM_SMCCC_CALL_VAL(ARM_SMCCC_STD_CALL,
-                                       ARM_SMCCC_SMC_64, ARM_SMCCC_OWNER_SIP,
-                                       SCM_SMC_FNID(QCOM_SCM_SVC_WAITQ, QCOM_SCM_WAITQ_RESUME));
-
-       resume->args[1] = QCOM_SCM_ARGS(1);
-
-       resume->args[2] = smc_call_ctx;
-}
-
-int scm_get_wq_ctx(u32 *wq_ctx, u32 *flags, u32 *more_pending)
-{
-       int ret;
-       struct arm_smccc_res get_wq_res;
-       struct arm_smccc_args get_wq_ctx = {0};
-
-       get_wq_ctx.args[0] = ARM_SMCCC_CALL_VAL(ARM_SMCCC_STD_CALL,
-                               ARM_SMCCC_SMC_64, ARM_SMCCC_OWNER_SIP,
-                               SCM_SMC_FNID(QCOM_SCM_SVC_WAITQ, QCOM_SCM_WAITQ_GET_WQ_CTX));
-
-       /* Guaranteed to return only success or error, no WAITQ_* */
-       __scm_smc_do_quirk(&get_wq_ctx, &get_wq_res);
-       ret = get_wq_res.a0;
-       if (ret)
-               return ret;
-
-       *wq_ctx = get_wq_res.a1;
-       *flags  = get_wq_res.a2;
-       *more_pending = get_wq_res.a3;
-
-       return 0;
-}
-
-static int __scm_smc_do_quirk_handle_waitq(struct device *dev, struct arm_smccc_args *waitq,
-                                          struct arm_smccc_res *res)
-{
-       int ret;
-       u32 wq_ctx, smc_call_ctx;
-       struct arm_smccc_args resume;
-       struct arm_smccc_args *smc = waitq;
-
-       do {
-               __scm_smc_do_quirk(smc, res);
-
-               if (res->a0 == QCOM_SCM_WAITQ_SLEEP) {
-                       wq_ctx = res->a1;
-                       smc_call_ctx = res->a2;
-
-                       ret = qcom_scm_wait_for_wq_completion(wq_ctx);
-                       if (ret)
-                               return ret;
-
-                       fill_wq_resume_args(&resume, smc_call_ctx);
-                       smc = &resume;
-               }
-       } while (res->a0 == QCOM_SCM_WAITQ_SLEEP);
-
-       return 0;
-}
-
-static int __scm_smc_do(struct device *dev, struct arm_smccc_args *smc,
-                       struct arm_smccc_res *res, bool atomic)
-{
-       int ret, retry_count = 0;
-
-       if (atomic) {
-               __scm_smc_do_quirk(smc, res);
-               return 0;
-       }
-
-       do {
-               mutex_lock(&qcom_scm_lock);
-
-               ret = __scm_smc_do_quirk_handle_waitq(dev, smc, res);
-
-               mutex_unlock(&qcom_scm_lock);
-
-               if (ret)
-                       return ret;
-
-               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);
-
-       return 0;
-}
-
-
-int __scm_smc_call(struct device *dev, const struct qcom_scm_desc *desc,
-                  enum qcom_scm_convention qcom_convention,
-                  struct qcom_scm_res *res, bool atomic)
-{
-       int arglen = desc->arginfo & 0xf;
-       int i, ret;
-       dma_addr_t args_phys = 0;
-       void *args_virt = NULL;
-       size_t alloc_len;
-       gfp_t flag = atomic ? GFP_ATOMIC : GFP_KERNEL;
-       u32 smccc_call_type = atomic ? ARM_SMCCC_FAST_CALL : ARM_SMCCC_STD_CALL;
-       u32 qcom_smccc_convention = (qcom_convention == SMC_CONVENTION_ARM_32) ?
-                                   ARM_SMCCC_SMC_32 : ARM_SMCCC_SMC_64;
-       struct arm_smccc_res smc_res;
-       struct arm_smccc_args smc = {0};
-
-       smc.args[0] = ARM_SMCCC_CALL_VAL(
-               smccc_call_type,
-               qcom_smccc_convention,
-               desc->owner,
-               SCM_SMC_FNID(desc->svc, desc->cmd));
-       smc.args[1] = desc->arginfo;
-       for (i = 0; i < SCM_SMC_N_REG_ARGS; i++)
-               smc.args[i + SCM_SMC_FIRST_REG_IDX] = desc->args[i];
-
-       if (unlikely(arglen > SCM_SMC_N_REG_ARGS)) {
-               alloc_len = SCM_SMC_N_EXT_ARGS * sizeof(u64);
-               args_virt = kzalloc(PAGE_ALIGN(alloc_len), flag);
-
-               if (!args_virt)
-                       return -ENOMEM;
-
-               if (qcom_smccc_convention == ARM_SMCCC_SMC_32) {
-                       __le32 *args = args_virt;
-
-                       for (i = 0; i < SCM_SMC_N_EXT_ARGS; i++)
-                               args[i] = cpu_to_le32(desc->args[i +
-                                                     SCM_SMC_FIRST_EXT_IDX]);
-               } else {
-                       __le64 *args = args_virt;
-
-                       for (i = 0; i < SCM_SMC_N_EXT_ARGS; i++)
-                               args[i] = cpu_to_le64(desc->args[i +
-                                                     SCM_SMC_FIRST_EXT_IDX]);
-               }
-
-               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.args[SCM_SMC_LAST_REG_IDX] = args_phys;
-       }
-
-       /* ret error check follows after args_virt cleanup*/
-       ret = __scm_smc_do(dev, &smc, &smc_res, atomic);
-
-       if (args_virt) {
-               dma_unmap_single(dev, args_phys, alloc_len, DMA_TO_DEVICE);
-               kfree(args_virt);
-       }
-
-       if (ret)
-               return ret;
-
-       if (res) {
-               res->result[0] = smc_res.a1;
-               res->result[1] = smc_res.a2;
-               res->result[2] = smc_res.a3;
-       }
-
-       return (long)smc_res.a0 ? qcom_scm_remap_error(smc_res.a0) : 0;
-
-}
diff --git a/drivers/firmware/qcom_scm.c b/drivers/firmware/qcom_scm.c
deleted file mode 100644 (file)
index 520de9b..0000000
+++ /dev/null
@@ -1,1943 +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/arm-smccc.h>
-#include <linux/clk.h>
-#include <linux/completion.h>
-#include <linux/cpumask.h>
-#include <linux/dma-mapping.h>
-#include <linux/export.h>
-#include <linux/firmware/qcom/qcom_scm.h>
-#include <linux/init.h>
-#include <linux/interconnect.h>
-#include <linux/interrupt.h>
-#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/of_address.h>
-#include <linux/of_irq.h>
-#include <linux/of_platform.h>
-#include <linux/platform_device.h>
-#include <linux/reset-controller.h>
-#include <linux/types.h>
-
-#include "qcom_scm.h"
-
-static bool download_mode = IS_ENABLED(CONFIG_QCOM_SCM_DOWNLOAD_MODE_DEFAULT);
-module_param(download_mode, bool, 0);
-
-struct qcom_scm {
-       struct device *dev;
-       struct clk *core_clk;
-       struct clk *iface_clk;
-       struct clk *bus_clk;
-       struct icc_path *path;
-       struct completion waitq_comp;
-       struct reset_controller_dev reset;
-
-       /* control access to the interconnect path */
-       struct mutex scm_bw_lock;
-       int scm_vote_count;
-
-       u64 dload_mode_addr;
-};
-
-struct qcom_scm_current_perm_info {
-       __le32 vmid;
-       __le32 perm;
-       __le64 ctx;
-       __le32 ctx_size;
-       __le32 unused;
-};
-
-struct qcom_scm_mem_map_info {
-       __le64 mem_addr;
-       __le64 mem_size;
-};
-
-/**
- * struct qcom_scm_qseecom_resp - QSEECOM SCM call response.
- * @result:    Result or status of the SCM call. See &enum qcom_scm_qseecom_result.
- * @resp_type: Type of the response. See &enum qcom_scm_qseecom_resp_type.
- * @data:      Response data. The type of this data is given in @resp_type.
- */
-struct qcom_scm_qseecom_resp {
-       u64 result;
-       u64 resp_type;
-       u64 data;
-};
-
-enum qcom_scm_qseecom_result {
-       QSEECOM_RESULT_SUCCESS                  = 0,
-       QSEECOM_RESULT_INCOMPLETE               = 1,
-       QSEECOM_RESULT_BLOCKED_ON_LISTENER      = 2,
-       QSEECOM_RESULT_FAILURE                  = 0xFFFFFFFF,
-};
-
-enum qcom_scm_qseecom_resp_type {
-       QSEECOM_SCM_RES_APP_ID                  = 0xEE01,
-       QSEECOM_SCM_RES_QSEOS_LISTENER_ID       = 0xEE02,
-};
-
-enum qcom_scm_qseecom_tz_owner {
-       QSEECOM_TZ_OWNER_SIP                    = 2,
-       QSEECOM_TZ_OWNER_TZ_APPS                = 48,
-       QSEECOM_TZ_OWNER_QSEE_OS                = 50
-};
-
-enum qcom_scm_qseecom_tz_svc {
-       QSEECOM_TZ_SVC_APP_ID_PLACEHOLDER       = 0,
-       QSEECOM_TZ_SVC_APP_MGR                  = 1,
-       QSEECOM_TZ_SVC_INFO                     = 6,
-};
-
-enum qcom_scm_qseecom_tz_cmd_app {
-       QSEECOM_TZ_CMD_APP_SEND                 = 1,
-       QSEECOM_TZ_CMD_APP_LOOKUP               = 3,
-};
-
-enum qcom_scm_qseecom_tz_cmd_info {
-       QSEECOM_TZ_CMD_INFO_VERSION             = 3,
-};
-
-#define QSEECOM_MAX_APP_NAME_SIZE              64
-
-/* Each bit configures cold/warm boot address for one of the 4 CPUs */
-static const u8 qcom_scm_cpu_cold_bits[QCOM_SCM_BOOT_MAX_CPUS] = {
-       0, BIT(0), BIT(3), BIT(5)
-};
-static const u8 qcom_scm_cpu_warm_bits[QCOM_SCM_BOOT_MAX_CPUS] = {
-       BIT(2), BIT(1), BIT(4), BIT(6)
-};
-
-#define QCOM_SMC_WAITQ_FLAG_WAKE_ONE   BIT(0)
-#define QCOM_SMC_WAITQ_FLAG_WAKE_ALL   BIT(1)
-
-static const char * const qcom_scm_convention_names[] = {
-       [SMC_CONVENTION_UNKNOWN] = "unknown",
-       [SMC_CONVENTION_ARM_32] = "smc arm 32",
-       [SMC_CONVENTION_ARM_64] = "smc arm 64",
-       [SMC_CONVENTION_LEGACY] = "smc legacy",
-};
-
-static struct qcom_scm *__scm;
-
-static int qcom_scm_clk_enable(void)
-{
-       int ret;
-
-       ret = clk_prepare_enable(__scm->core_clk);
-       if (ret)
-               goto bail;
-
-       ret = clk_prepare_enable(__scm->iface_clk);
-       if (ret)
-               goto disable_core;
-
-       ret = clk_prepare_enable(__scm->bus_clk);
-       if (ret)
-               goto disable_iface;
-
-       return 0;
-
-disable_iface:
-       clk_disable_unprepare(__scm->iface_clk);
-disable_core:
-       clk_disable_unprepare(__scm->core_clk);
-bail:
-       return ret;
-}
-
-static void qcom_scm_clk_disable(void)
-{
-       clk_disable_unprepare(__scm->core_clk);
-       clk_disable_unprepare(__scm->iface_clk);
-       clk_disable_unprepare(__scm->bus_clk);
-}
-
-static int qcom_scm_bw_enable(void)
-{
-       int ret = 0;
-
-       if (!__scm->path)
-               return 0;
-
-       if (IS_ERR(__scm->path))
-               return -EINVAL;
-
-       mutex_lock(&__scm->scm_bw_lock);
-       if (!__scm->scm_vote_count) {
-               ret = icc_set_bw(__scm->path, 0, UINT_MAX);
-               if (ret < 0) {
-                       dev_err(__scm->dev, "failed to set bandwidth request\n");
-                       goto err_bw;
-               }
-       }
-       __scm->scm_vote_count++;
-err_bw:
-       mutex_unlock(&__scm->scm_bw_lock);
-
-       return ret;
-}
-
-static void qcom_scm_bw_disable(void)
-{
-       if (IS_ERR_OR_NULL(__scm->path))
-               return;
-
-       mutex_lock(&__scm->scm_bw_lock);
-       if (__scm->scm_vote_count-- == 1)
-               icc_set_bw(__scm->path, 0, 0);
-       mutex_unlock(&__scm->scm_bw_lock);
-}
-
-enum qcom_scm_convention qcom_scm_convention = SMC_CONVENTION_UNKNOWN;
-static DEFINE_SPINLOCK(scm_query_lock);
-
-static enum qcom_scm_convention __get_convention(void)
-{
-       unsigned long flags;
-       struct qcom_scm_desc desc = {
-               .svc = QCOM_SCM_SVC_INFO,
-               .cmd = QCOM_SCM_INFO_IS_CALL_AVAIL,
-               .args[0] = SCM_SMC_FNID(QCOM_SCM_SVC_INFO,
-                                          QCOM_SCM_INFO_IS_CALL_AVAIL) |
-                          (ARM_SMCCC_OWNER_SIP << ARM_SMCCC_OWNER_SHIFT),
-               .arginfo = QCOM_SCM_ARGS(1),
-               .owner = ARM_SMCCC_OWNER_SIP,
-       };
-       struct qcom_scm_res res;
-       enum qcom_scm_convention probed_convention;
-       int ret;
-       bool forced = false;
-
-       if (likely(qcom_scm_convention != SMC_CONVENTION_UNKNOWN))
-               return qcom_scm_convention;
-
-       /*
-        * Per the "SMC calling convention specification", the 64-bit calling
-        * convention can only be used when the client is 64-bit, otherwise
-        * system will encounter the undefined behaviour.
-        */
-#if IS_ENABLED(CONFIG_ARM64)
-       /*
-        * Device isn't required as there is only one argument - no device
-        * needed to dma_map_single to secure world
-        */
-       probed_convention = SMC_CONVENTION_ARM_64;
-       ret = __scm_smc_call(NULL, &desc, probed_convention, &res, true);
-       if (!ret && res.result[0] == 1)
-               goto found;
-
-       /*
-        * Some SC7180 firmwares didn't implement the
-        * QCOM_SCM_INFO_IS_CALL_AVAIL call, so we fallback to forcing ARM_64
-        * calling conventions on these firmwares. Luckily we don't make any
-        * early calls into the firmware on these SoCs so the device pointer
-        * will be valid here to check if the compatible matches.
-        */
-       if (of_device_is_compatible(__scm ? __scm->dev->of_node : NULL, "qcom,scm-sc7180")) {
-               forced = true;
-               goto found;
-       }
-#endif
-
-       probed_convention = SMC_CONVENTION_ARM_32;
-       ret = __scm_smc_call(NULL, &desc, probed_convention, &res, true);
-       if (!ret && res.result[0] == 1)
-               goto found;
-
-       probed_convention = SMC_CONVENTION_LEGACY;
-found:
-       spin_lock_irqsave(&scm_query_lock, flags);
-       if (probed_convention != qcom_scm_convention) {
-               qcom_scm_convention = probed_convention;
-               pr_info("qcom_scm: convention: %s%s\n",
-                       qcom_scm_convention_names[qcom_scm_convention],
-                       forced ? " (forced)" : "");
-       }
-       spin_unlock_irqrestore(&scm_query_lock, flags);
-
-       return qcom_scm_convention;
-}
-
-/**
- * qcom_scm_call() - Invoke a syscall in the secure world
- * @dev:       device
- * @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 should *only* be called in pre-emptible context.
- */
-static int qcom_scm_call(struct device *dev, const struct qcom_scm_desc *desc,
-                        struct qcom_scm_res *res)
-{
-       might_sleep();
-       switch (__get_convention()) {
-       case SMC_CONVENTION_ARM_32:
-       case SMC_CONVENTION_ARM_64:
-               return scm_smc_call(dev, desc, res, false);
-       case SMC_CONVENTION_LEGACY:
-               return scm_legacy_call(dev, desc, res);
-       default:
-               pr_err("Unknown current SCM calling convention.\n");
-               return -EINVAL;
-       }
-}
-
-/**
- * qcom_scm_call_atomic() - atomic variation of qcom_scm_call()
- * @dev:       device
- * @desc:      Descriptor structure containing arguments and return values
- * @res:       Structure containing results from SMC/HVC call
- *
- * Sends a command to the SCM and waits for the command to finish processing.
- * This can be called in atomic context.
- */
-static int qcom_scm_call_atomic(struct device *dev,
-                               const struct qcom_scm_desc *desc,
-                               struct qcom_scm_res *res)
-{
-       switch (__get_convention()) {
-       case SMC_CONVENTION_ARM_32:
-       case SMC_CONVENTION_ARM_64:
-               return scm_smc_call(dev, desc, res, true);
-       case SMC_CONVENTION_LEGACY:
-               return scm_legacy_call_atomic(dev, desc, res);
-       default:
-               pr_err("Unknown current SCM calling convention.\n");
-               return -EINVAL;
-       }
-}
-
-static bool __qcom_scm_is_call_available(struct device *dev, u32 svc_id,
-                                        u32 cmd_id)
-{
-       int ret;
-       struct qcom_scm_desc desc = {
-               .svc = QCOM_SCM_SVC_INFO,
-               .cmd = QCOM_SCM_INFO_IS_CALL_AVAIL,
-               .owner = ARM_SMCCC_OWNER_SIP,
-       };
-       struct qcom_scm_res res;
-
-       desc.arginfo = QCOM_SCM_ARGS(1);
-       switch (__get_convention()) {
-       case SMC_CONVENTION_ARM_32:
-       case SMC_CONVENTION_ARM_64:
-               desc.args[0] = SCM_SMC_FNID(svc_id, cmd_id) |
-                               (ARM_SMCCC_OWNER_SIP << ARM_SMCCC_OWNER_SHIFT);
-               break;
-       case SMC_CONVENTION_LEGACY:
-               desc.args[0] = SCM_LEGACY_FNID(svc_id, cmd_id);
-               break;
-       default:
-               pr_err("Unknown SMC convention being used\n");
-               return false;
-       }
-
-       ret = qcom_scm_call(dev, &desc, &res);
-
-       return ret ? false : !!res.result[0];
-}
-
-static int qcom_scm_set_boot_addr(void *entry, const u8 *cpu_bits)
-{
-       int cpu;
-       unsigned int flags = 0;
-       struct qcom_scm_desc desc = {
-               .svc = QCOM_SCM_SVC_BOOT,
-               .cmd = QCOM_SCM_BOOT_SET_ADDR,
-               .arginfo = QCOM_SCM_ARGS(2),
-               .owner = ARM_SMCCC_OWNER_SIP,
-       };
-
-       for_each_present_cpu(cpu) {
-               if (cpu >= QCOM_SCM_BOOT_MAX_CPUS)
-                       return -EINVAL;
-               flags |= cpu_bits[cpu];
-       }
-
-       desc.args[0] = flags;
-       desc.args[1] = virt_to_phys(entry);
-
-       return qcom_scm_call_atomic(__scm ? __scm->dev : NULL, &desc, NULL);
-}
-
-static int qcom_scm_set_boot_addr_mc(void *entry, unsigned int flags)
-{
-       struct qcom_scm_desc desc = {
-               .svc = QCOM_SCM_SVC_BOOT,
-               .cmd = QCOM_SCM_BOOT_SET_ADDR_MC,
-               .owner = ARM_SMCCC_OWNER_SIP,
-               .arginfo = QCOM_SCM_ARGS(6),
-               .args = {
-                       virt_to_phys(entry),
-                       /* Apply to all CPUs in all affinity levels */
-                       ~0ULL, ~0ULL, ~0ULL, ~0ULL,
-                       flags,
-               },
-       };
-
-       /* Need a device for DMA of the additional arguments */
-       if (!__scm || __get_convention() == SMC_CONVENTION_LEGACY)
-               return -EOPNOTSUPP;
-
-       return qcom_scm_call(__scm->dev, &desc, NULL);
-}
-
-/**
- * qcom_scm_set_warm_boot_addr() - Set the warm boot address for all cpus
- * @entry: Entry point function for the cpus
- *
- * 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(void *entry)
-{
-       if (qcom_scm_set_boot_addr_mc(entry, QCOM_SCM_BOOT_MC_FLAG_WARMBOOT))
-               /* Fallback to old SCM call */
-               return qcom_scm_set_boot_addr(entry, qcom_scm_cpu_warm_bits);
-       return 0;
-}
-EXPORT_SYMBOL_GPL(qcom_scm_set_warm_boot_addr);
-
-/**
- * qcom_scm_set_cold_boot_addr() - Set the cold boot address for all cpus
- * @entry: Entry point function for the cpus
- */
-int qcom_scm_set_cold_boot_addr(void *entry)
-{
-       if (qcom_scm_set_boot_addr_mc(entry, QCOM_SCM_BOOT_MC_FLAG_COLDBOOT))
-               /* Fallback to old SCM call */
-               return qcom_scm_set_boot_addr(entry, qcom_scm_cpu_cold_bits);
-       return 0;
-}
-EXPORT_SYMBOL_GPL(qcom_scm_set_cold_boot_addr);
-
-/**
- * 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(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(__scm ? __scm->dev : NULL, &desc, NULL);
-}
-EXPORT_SYMBOL_GPL(qcom_scm_cpu_power_down);
-
-int qcom_scm_set_remote_state(u32 state, u32 id)
-{
-       struct qcom_scm_desc desc = {
-               .svc = QCOM_SCM_SVC_BOOT,
-               .cmd = QCOM_SCM_BOOT_SET_REMOTE_STATE,
-               .arginfo = QCOM_SCM_ARGS(2),
-               .args[0] = state,
-               .args[1] = id,
-               .owner = ARM_SMCCC_OWNER_SIP,
-       };
-       struct qcom_scm_res res;
-       int ret;
-
-       ret = qcom_scm_call(__scm->dev, &desc, &res);
-
-       return ret ? : res.result[0];
-}
-EXPORT_SYMBOL_GPL(qcom_scm_set_remote_state);
-
-static int qcom_scm_disable_sdi(void)
-{
-       int ret;
-       struct qcom_scm_desc desc = {
-               .svc = QCOM_SCM_SVC_BOOT,
-               .cmd = QCOM_SCM_BOOT_SDI_CONFIG,
-               .args[0] = 1, /* Disable watchdog debug */
-               .args[1] = 0, /* Disable SDI */
-               .arginfo = QCOM_SCM_ARGS(2),
-               .owner = ARM_SMCCC_OWNER_SIP,
-       };
-       struct qcom_scm_res res;
-
-       ret = qcom_scm_clk_enable();
-       if (ret)
-               return ret;
-       ret = qcom_scm_call(__scm->dev, &desc, &res);
-
-       qcom_scm_clk_disable();
-
-       return ret ? : res.result[0];
-}
-
-static 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,
-               .arginfo = QCOM_SCM_ARGS(2),
-               .args[0] = QCOM_SCM_BOOT_SET_DLOAD_MODE,
-               .owner = ARM_SMCCC_OWNER_SIP,
-       };
-
-       desc.args[1] = enable ? QCOM_SCM_BOOT_SET_DLOAD_MODE : 0;
-
-       return qcom_scm_call_atomic(__scm->dev, &desc, NULL);
-}
-
-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->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);
-}
-
-/**
- * qcom_scm_pas_init_image() - Initialize peripheral authentication service
- *                            state machine for a given peripheral, using the
- *                            metadata
- * @peripheral: peripheral id
- * @metadata:  pointer to memory containing ELF header, program header table
- *             and optional blob of data used for authenticating the metadata
- *             and the rest of the firmware
- * @size:      size of the metadata
- * @ctx:       optional metadata context
- *
- * Return: 0 on success.
- *
- * Upon successful return, the PAS metadata context (@ctx) will be used to
- * track the metadata allocation, this needs to be released by invoking
- * qcom_scm_pas_metadata_release() by the caller.
- */
-int qcom_scm_pas_init_image(u32 peripheral, const void *metadata, size_t size,
-                           struct qcom_scm_pas_metadata *ctx)
-{
-       dma_addr_t mdata_phys;
-       void *mdata_buf;
-       int ret;
-       struct qcom_scm_desc desc = {
-               .svc = QCOM_SCM_SVC_PIL,
-               .cmd = QCOM_SCM_PIL_PAS_INIT_IMAGE,
-               .arginfo = QCOM_SCM_ARGS(2, QCOM_SCM_VAL, QCOM_SCM_RW),
-               .args[0] = peripheral,
-               .owner = ARM_SMCCC_OWNER_SIP,
-       };
-       struct qcom_scm_res res;
-
-       /*
-        * During the scm call memory protection will be enabled for the meta
-        * data blob, so make sure it's physically contiguous, 4K aligned and
-        * non-cachable to avoid XPU violations.
-        */
-       mdata_buf = dma_alloc_coherent(__scm->dev, size, &mdata_phys,
-                                      GFP_KERNEL);
-       if (!mdata_buf) {
-               dev_err(__scm->dev, "Allocation of metadata buffer failed.\n");
-               return -ENOMEM;
-       }
-       memcpy(mdata_buf, metadata, size);
-
-       ret = qcom_scm_clk_enable();
-       if (ret)
-               goto out;
-
-       ret = qcom_scm_bw_enable();
-       if (ret)
-               return ret;
-
-       desc.args[1] = mdata_phys;
-
-       ret = qcom_scm_call(__scm->dev, &desc, &res);
-
-       qcom_scm_bw_disable();
-       qcom_scm_clk_disable();
-
-out:
-       if (ret < 0 || !ctx) {
-               dma_free_coherent(__scm->dev, size, mdata_buf, mdata_phys);
-       } else if (ctx) {
-               ctx->ptr = mdata_buf;
-               ctx->phys = mdata_phys;
-               ctx->size = size;
-       }
-
-       return ret ? : res.result[0];
-}
-EXPORT_SYMBOL_GPL(qcom_scm_pas_init_image);
-
-/**
- * qcom_scm_pas_metadata_release() - release metadata context
- * @ctx:       metadata context
- */
-void qcom_scm_pas_metadata_release(struct qcom_scm_pas_metadata *ctx)
-{
-       if (!ctx->ptr)
-               return;
-
-       dma_free_coherent(__scm->dev, ctx->size, ctx->ptr, ctx->phys);
-
-       ctx->ptr = NULL;
-       ctx->phys = 0;
-       ctx->size = 0;
-}
-EXPORT_SYMBOL_GPL(qcom_scm_pas_metadata_release);
-
-/**
- * qcom_scm_pas_mem_setup() - Prepare the memory related to a given peripheral
- *                           for firmware loading
- * @peripheral:        peripheral id
- * @addr:      start address of memory area to prepare
- * @size:      size of the memory area to prepare
- *
- * Returns 0 on success.
- */
-int qcom_scm_pas_mem_setup(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,
-               .arginfo = QCOM_SCM_ARGS(3),
-               .args[0] = peripheral,
-               .args[1] = addr,
-               .args[2] = size,
-               .owner = ARM_SMCCC_OWNER_SIP,
-       };
-       struct qcom_scm_res res;
-
-       ret = qcom_scm_clk_enable();
-       if (ret)
-               return ret;
-
-       ret = qcom_scm_bw_enable();
-       if (ret)
-               return ret;
-
-       ret = qcom_scm_call(__scm->dev, &desc, &res);
-       qcom_scm_bw_disable();
-       qcom_scm_clk_disable();
-
-       return ret ? : res.result[0];
-}
-EXPORT_SYMBOL_GPL(qcom_scm_pas_mem_setup);
-
-/**
- * qcom_scm_pas_auth_and_reset() - Authenticate the given peripheral firmware
- *                                and reset the remote processor
- * @peripheral:        peripheral id
- *
- * Return 0 on success.
- */
-int qcom_scm_pas_auth_and_reset(u32 peripheral)
-{
-       int ret;
-       struct qcom_scm_desc desc = {
-               .svc = QCOM_SCM_SVC_PIL,
-               .cmd = QCOM_SCM_PIL_PAS_AUTH_AND_RESET,
-               .arginfo = QCOM_SCM_ARGS(1),
-               .args[0] = peripheral,
-               .owner = ARM_SMCCC_OWNER_SIP,
-       };
-       struct qcom_scm_res res;
-
-       ret = qcom_scm_clk_enable();
-       if (ret)
-               return ret;
-
-       ret = qcom_scm_bw_enable();
-       if (ret)
-               return ret;
-
-       ret = qcom_scm_call(__scm->dev, &desc, &res);
-       qcom_scm_bw_disable();
-       qcom_scm_clk_disable();
-
-       return ret ? : res.result[0];
-}
-EXPORT_SYMBOL_GPL(qcom_scm_pas_auth_and_reset);
-
-/**
- * qcom_scm_pas_shutdown() - Shut down the remote processor
- * @peripheral: peripheral id
- *
- * Returns 0 on success.
- */
-int qcom_scm_pas_shutdown(u32 peripheral)
-{
-       int ret;
-       struct qcom_scm_desc desc = {
-               .svc = QCOM_SCM_SVC_PIL,
-               .cmd = QCOM_SCM_PIL_PAS_SHUTDOWN,
-               .arginfo = QCOM_SCM_ARGS(1),
-               .args[0] = peripheral,
-               .owner = ARM_SMCCC_OWNER_SIP,
-       };
-       struct qcom_scm_res res;
-
-       ret = qcom_scm_clk_enable();
-       if (ret)
-               return ret;
-
-       ret = qcom_scm_bw_enable();
-       if (ret)
-               return ret;
-
-       ret = qcom_scm_call(__scm->dev, &desc, &res);
-
-       qcom_scm_bw_disable();
-       qcom_scm_clk_disable();
-
-       return ret ? : res.result[0];
-}
-EXPORT_SYMBOL_GPL(qcom_scm_pas_shutdown);
-
-/**
- * qcom_scm_pas_supported() - Check if the peripheral authentication service is
- *                           available for the given peripherial
- * @peripheral:        peripheral id
- *
- * Returns true if PAS is supported for this peripheral, otherwise false.
- */
-bool qcom_scm_pas_supported(u32 peripheral)
-{
-       int ret;
-       struct qcom_scm_desc desc = {
-               .svc = QCOM_SCM_SVC_PIL,
-               .cmd = QCOM_SCM_PIL_PAS_IS_SUPPORTED,
-               .arginfo = QCOM_SCM_ARGS(1),
-               .args[0] = peripheral,
-               .owner = ARM_SMCCC_OWNER_SIP,
-       };
-       struct qcom_scm_res res;
-
-       if (!__qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_PIL,
-                                         QCOM_SCM_PIL_PAS_IS_SUPPORTED))
-               return false;
-
-       ret = qcom_scm_call(__scm->dev, &desc, &res);
-
-       return ret ? false : !!res.result[0];
-}
-EXPORT_SYMBOL_GPL(qcom_scm_pas_supported);
-
-static 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,
-               .arginfo = QCOM_SCM_ARGS(2),
-               .args[0] = reset,
-               .args[1] = 0,
-               .owner = ARM_SMCCC_OWNER_SIP,
-       };
-       struct qcom_scm_res res;
-       int ret;
-
-       ret = qcom_scm_call(__scm->dev, &desc, &res);
-
-       return ret ? : res.result[0];
-}
-
-static int qcom_scm_pas_reset_assert(struct reset_controller_dev *rcdev,
-                                    unsigned long idx)
-{
-       if (idx != 0)
-               return -EINVAL;
-
-       return __qcom_scm_pas_mss_reset(__scm->dev, 1);
-}
-
-static int qcom_scm_pas_reset_deassert(struct reset_controller_dev *rcdev,
-                                      unsigned long idx)
-{
-       if (idx != 0)
-               return -EINVAL;
-
-       return __qcom_scm_pas_mss_reset(__scm->dev, 0);
-}
-
-static const struct reset_control_ops qcom_scm_pas_reset_ops = {
-       .assert = qcom_scm_pas_reset_assert,
-       .deassert = qcom_scm_pas_reset_deassert,
-};
-
-int qcom_scm_io_readl(phys_addr_t addr, unsigned int *val)
-{
-       struct qcom_scm_desc desc = {
-               .svc = QCOM_SCM_SVC_IO,
-               .cmd = QCOM_SCM_IO_READ,
-               .arginfo = QCOM_SCM_ARGS(1),
-               .args[0] = addr,
-               .owner = ARM_SMCCC_OWNER_SIP,
-       };
-       struct qcom_scm_res res;
-       int ret;
-
-
-       ret = qcom_scm_call_atomic(__scm->dev, &desc, &res);
-       if (ret >= 0)
-               *val = res.result[0];
-
-       return ret < 0 ? ret : 0;
-}
-EXPORT_SYMBOL_GPL(qcom_scm_io_readl);
-
-int qcom_scm_io_writel(phys_addr_t addr, unsigned int val)
-{
-       struct qcom_scm_desc desc = {
-               .svc = QCOM_SCM_SVC_IO,
-               .cmd = QCOM_SCM_IO_WRITE,
-               .arginfo = QCOM_SCM_ARGS(2),
-               .args[0] = addr,
-               .args[1] = val,
-               .owner = ARM_SMCCC_OWNER_SIP,
-       };
-
-       return qcom_scm_call_atomic(__scm->dev, &desc, NULL);
-}
-EXPORT_SYMBOL_GPL(qcom_scm_io_writel);
-
-/**
- * qcom_scm_restore_sec_cfg_available() - Check if secure environment
- * supports restore security config interface.
- *
- * Return true if restore-cfg interface is supported, false if not.
- */
-bool qcom_scm_restore_sec_cfg_available(void)
-{
-       return __qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_MP,
-                                           QCOM_SCM_MP_RESTORE_SEC_CFG);
-}
-EXPORT_SYMBOL_GPL(qcom_scm_restore_sec_cfg_available);
-
-int qcom_scm_restore_sec_cfg(u32 device_id, u32 spare)
-{
-       struct qcom_scm_desc desc = {
-               .svc = QCOM_SCM_SVC_MP,
-               .cmd = QCOM_SCM_MP_RESTORE_SEC_CFG,
-               .arginfo = QCOM_SCM_ARGS(2),
-               .args[0] = device_id,
-               .args[1] = spare,
-               .owner = ARM_SMCCC_OWNER_SIP,
-       };
-       struct qcom_scm_res res;
-       int ret;
-
-       ret = qcom_scm_call(__scm->dev, &desc, &res);
-
-       return ret ? : res.result[0];
-}
-EXPORT_SYMBOL_GPL(qcom_scm_restore_sec_cfg);
-
-int qcom_scm_iommu_secure_ptbl_size(u32 spare, size_t *size)
-{
-       struct qcom_scm_desc desc = {
-               .svc = QCOM_SCM_SVC_MP,
-               .cmd = QCOM_SCM_MP_IOMMU_SECURE_PTBL_SIZE,
-               .arginfo = QCOM_SCM_ARGS(1),
-               .args[0] = spare,
-               .owner = ARM_SMCCC_OWNER_SIP,
-       };
-       struct qcom_scm_res res;
-       int ret;
-
-       ret = qcom_scm_call(__scm->dev, &desc, &res);
-
-       if (size)
-               *size = res.result[0];
-
-       return ret ? : res.result[1];
-}
-EXPORT_SYMBOL_GPL(qcom_scm_iommu_secure_ptbl_size);
-
-int qcom_scm_iommu_secure_ptbl_init(u64 addr, u32 size, u32 spare)
-{
-       struct qcom_scm_desc desc = {
-               .svc = QCOM_SCM_SVC_MP,
-               .cmd = QCOM_SCM_MP_IOMMU_SECURE_PTBL_INIT,
-               .arginfo = QCOM_SCM_ARGS(3, QCOM_SCM_RW, QCOM_SCM_VAL,
-                                        QCOM_SCM_VAL),
-               .args[0] = addr,
-               .args[1] = size,
-               .args[2] = spare,
-               .owner = ARM_SMCCC_OWNER_SIP,
-       };
-       int ret;
-
-       ret = qcom_scm_call(__scm->dev, &desc, NULL);
-
-       /* the pg table has been initialized already, ignore the error */
-       if (ret == -EPERM)
-               ret = 0;
-
-       return ret;
-}
-EXPORT_SYMBOL_GPL(qcom_scm_iommu_secure_ptbl_init);
-
-int qcom_scm_iommu_set_cp_pool_size(u32 spare, u32 size)
-{
-       struct qcom_scm_desc desc = {
-               .svc = QCOM_SCM_SVC_MP,
-               .cmd = QCOM_SCM_MP_IOMMU_SET_CP_POOL_SIZE,
-               .arginfo = QCOM_SCM_ARGS(2),
-               .args[0] = size,
-               .args[1] = spare,
-               .owner = ARM_SMCCC_OWNER_SIP,
-       };
-
-       return qcom_scm_call(__scm->dev, &desc, NULL);
-}
-EXPORT_SYMBOL_GPL(qcom_scm_iommu_set_cp_pool_size);
-
-int qcom_scm_mem_protect_video_var(u32 cp_start, u32 cp_size,
-                                  u32 cp_nonpixel_start,
-                                  u32 cp_nonpixel_size)
-{
-       int ret;
-       struct qcom_scm_desc desc = {
-               .svc = QCOM_SCM_SVC_MP,
-               .cmd = QCOM_SCM_MP_VIDEO_VAR,
-               .arginfo = QCOM_SCM_ARGS(4, QCOM_SCM_VAL, QCOM_SCM_VAL,
-                                        QCOM_SCM_VAL, QCOM_SCM_VAL),
-               .args[0] = cp_start,
-               .args[1] = cp_size,
-               .args[2] = cp_nonpixel_start,
-               .args[3] = cp_nonpixel_size,
-               .owner = ARM_SMCCC_OWNER_SIP,
-       };
-       struct qcom_scm_res res;
-
-       ret = qcom_scm_call(__scm->dev, &desc, &res);
-
-       return ret ? : res.result[0];
-}
-EXPORT_SYMBOL_GPL(qcom_scm_mem_protect_video_var);
-
-static int __qcom_scm_assign_mem(struct device *dev, phys_addr_t mem_region,
-                                size_t mem_sz, phys_addr_t src, size_t src_sz,
-                                phys_addr_t dest, size_t dest_sz)
-{
-       int ret;
-       struct qcom_scm_desc desc = {
-               .svc = QCOM_SCM_SVC_MP,
-               .cmd = QCOM_SCM_MP_ASSIGN,
-               .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),
-               .args[0] = mem_region,
-               .args[1] = mem_sz,
-               .args[2] = src,
-               .args[3] = src_sz,
-               .args[4] = dest,
-               .args[5] = dest_sz,
-               .args[6] = 0,
-               .owner = ARM_SMCCC_OWNER_SIP,
-       };
-       struct qcom_scm_res res;
-
-       ret = qcom_scm_call(dev, &desc, &res);
-
-       return ret ? : res.result[0];
-}
-
-/**
- * qcom_scm_assign_mem() - Make a secure call to reassign memory ownership
- * @mem_addr: mem region whose ownership need to be reassigned
- * @mem_sz:   size of the region.
- * @srcvm:    vmid for current set of owners, each set bit in
- *            flag indicate a unique owner
- * @newvm:    array having new owners and corresponding permission
- *            flags
- * @dest_cnt: number of owners in next set.
- *
- * Return negative errno on failure or 0 on success with @srcvm updated.
- */
-int qcom_scm_assign_mem(phys_addr_t mem_addr, size_t mem_sz,
-                       u64 *srcvm,
-                       const struct qcom_scm_vmperm *newvm,
-                       unsigned int dest_cnt)
-{
-       struct qcom_scm_current_perm_info *destvm;
-       struct qcom_scm_mem_map_info *mem_to_map;
-       phys_addr_t mem_to_map_phys;
-       phys_addr_t dest_phys;
-       dma_addr_t ptr_phys;
-       size_t mem_to_map_sz;
-       size_t dest_sz;
-       size_t src_sz;
-       size_t ptr_sz;
-       int next_vm;
-       __le32 *src;
-       void *ptr;
-       int ret, i, b;
-       u64 srcvm_bits = *srcvm;
-
-       src_sz = hweight64(srcvm_bits) * sizeof(*src);
-       mem_to_map_sz = sizeof(*mem_to_map);
-       dest_sz = dest_cnt * sizeof(*destvm);
-       ptr_sz = ALIGN(src_sz, SZ_64) + ALIGN(mem_to_map_sz, SZ_64) +
-                       ALIGN(dest_sz, SZ_64);
-
-       ptr = dma_alloc_coherent(__scm->dev, ptr_sz, &ptr_phys, GFP_KERNEL);
-       if (!ptr)
-               return -ENOMEM;
-
-       /* Fill source vmid detail */
-       src = ptr;
-       i = 0;
-       for (b = 0; b < BITS_PER_TYPE(u64); b++) {
-               if (srcvm_bits & BIT(b))
-                       src[i++] = cpu_to_le32(b);
-       }
-
-       /* Fill details of mem buff to map */
-       mem_to_map = ptr + ALIGN(src_sz, SZ_64);
-       mem_to_map_phys = ptr_phys + ALIGN(src_sz, SZ_64);
-       mem_to_map->mem_addr = cpu_to_le64(mem_addr);
-       mem_to_map->mem_size = cpu_to_le64(mem_sz);
-
-       next_vm = 0;
-       /* Fill details of next vmid detail */
-       destvm = ptr + ALIGN(mem_to_map_sz, SZ_64) + ALIGN(src_sz, SZ_64);
-       dest_phys = ptr_phys + ALIGN(mem_to_map_sz, SZ_64) + ALIGN(src_sz, SZ_64);
-       for (i = 0; i < dest_cnt; i++, destvm++, newvm++) {
-               destvm->vmid = cpu_to_le32(newvm->vmid);
-               destvm->perm = cpu_to_le32(newvm->perm);
-               destvm->ctx = 0;
-               destvm->ctx_size = 0;
-               next_vm |= BIT(newvm->vmid);
-       }
-
-       ret = __qcom_scm_assign_mem(__scm->dev, mem_to_map_phys, mem_to_map_sz,
-                                   ptr_phys, src_sz, dest_phys, dest_sz);
-       dma_free_coherent(__scm->dev, ptr_sz, ptr, ptr_phys);
-       if (ret) {
-               dev_err(__scm->dev,
-                       "Assign memory protection call failed %d\n", ret);
-               return -EINVAL;
-       }
-
-       *srcvm = next_vm;
-       return 0;
-}
-EXPORT_SYMBOL_GPL(qcom_scm_assign_mem);
-
-/**
- * qcom_scm_ocmem_lock_available() - is OCMEM lock/unlock interface available
- */
-bool qcom_scm_ocmem_lock_available(void)
-{
-       return __qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_OCMEM,
-                                           QCOM_SCM_OCMEM_LOCK_CMD);
-}
-EXPORT_SYMBOL_GPL(qcom_scm_ocmem_lock_available);
-
-/**
- * qcom_scm_ocmem_lock() - call OCMEM lock interface to assign an OCMEM
- * region to the specified initiator
- *
- * @id:     tz initiator id
- * @offset: OCMEM offset
- * @size:   OCMEM size
- * @mode:   access mode (WIDE/NARROW)
- */
-int qcom_scm_ocmem_lock(enum qcom_scm_ocmem_client id, u32 offset, u32 size,
-                       u32 mode)
-{
-       struct qcom_scm_desc desc = {
-               .svc = QCOM_SCM_SVC_OCMEM,
-               .cmd = QCOM_SCM_OCMEM_LOCK_CMD,
-               .args[0] = id,
-               .args[1] = offset,
-               .args[2] = size,
-               .args[3] = mode,
-               .arginfo = QCOM_SCM_ARGS(4),
-       };
-
-       return qcom_scm_call(__scm->dev, &desc, NULL);
-}
-EXPORT_SYMBOL_GPL(qcom_scm_ocmem_lock);
-
-/**
- * qcom_scm_ocmem_unlock() - call OCMEM unlock interface to release an OCMEM
- * region from the specified initiator
- *
- * @id:     tz initiator id
- * @offset: OCMEM offset
- * @size:   OCMEM size
- */
-int qcom_scm_ocmem_unlock(enum qcom_scm_ocmem_client id, u32 offset, u32 size)
-{
-       struct qcom_scm_desc desc = {
-               .svc = QCOM_SCM_SVC_OCMEM,
-               .cmd = QCOM_SCM_OCMEM_UNLOCK_CMD,
-               .args[0] = id,
-               .args[1] = offset,
-               .args[2] = size,
-               .arginfo = QCOM_SCM_ARGS(3),
-       };
-
-       return qcom_scm_call(__scm->dev, &desc, NULL);
-}
-EXPORT_SYMBOL_GPL(qcom_scm_ocmem_unlock);
-
-/**
- * qcom_scm_ice_available() - Is the ICE key programming interface available?
- *
- * Return: true iff the SCM calls wrapped by qcom_scm_ice_invalidate_key() and
- *        qcom_scm_ice_set_key() are available.
- */
-bool qcom_scm_ice_available(void)
-{
-       return __qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_ES,
-                                           QCOM_SCM_ES_INVALIDATE_ICE_KEY) &&
-               __qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_ES,
-                                            QCOM_SCM_ES_CONFIG_SET_ICE_KEY);
-}
-EXPORT_SYMBOL_GPL(qcom_scm_ice_available);
-
-/**
- * qcom_scm_ice_invalidate_key() - Invalidate an inline encryption key
- * @index: the keyslot to invalidate
- *
- * The UFSHCI and eMMC standards define a standard way to do this, but it
- * doesn't work on these SoCs; only this SCM call does.
- *
- * It is assumed that the SoC has only one ICE instance being used, as this SCM
- * call doesn't specify which ICE instance the keyslot belongs to.
- *
- * Return: 0 on success; -errno on failure.
- */
-int qcom_scm_ice_invalidate_key(u32 index)
-{
-       struct qcom_scm_desc desc = {
-               .svc = QCOM_SCM_SVC_ES,
-               .cmd = QCOM_SCM_ES_INVALIDATE_ICE_KEY,
-               .arginfo = QCOM_SCM_ARGS(1),
-               .args[0] = index,
-               .owner = ARM_SMCCC_OWNER_SIP,
-       };
-
-       return qcom_scm_call(__scm->dev, &desc, NULL);
-}
-EXPORT_SYMBOL_GPL(qcom_scm_ice_invalidate_key);
-
-/**
- * qcom_scm_ice_set_key() - Set an inline encryption key
- * @index: the keyslot into which to set the key
- * @key: the key to program
- * @key_size: the size of the key in bytes
- * @cipher: the encryption algorithm the key is for
- * @data_unit_size: the encryption data unit size, i.e. the size of each
- *                 individual plaintext and ciphertext.  Given in 512-byte
- *                 units, e.g. 1 = 512 bytes, 8 = 4096 bytes, etc.
- *
- * Program a key into a keyslot of Qualcomm ICE (Inline Crypto Engine), where it
- * can then be used to encrypt/decrypt UFS or eMMC I/O requests inline.
- *
- * The UFSHCI and eMMC standards define a standard way to do this, but it
- * doesn't work on these SoCs; only this SCM call does.
- *
- * It is assumed that the SoC has only one ICE instance being used, as this SCM
- * call doesn't specify which ICE instance the keyslot belongs to.
- *
- * Return: 0 on success; -errno on failure.
- */
-int qcom_scm_ice_set_key(u32 index, const u8 *key, u32 key_size,
-                        enum qcom_scm_ice_cipher cipher, u32 data_unit_size)
-{
-       struct qcom_scm_desc desc = {
-               .svc = QCOM_SCM_SVC_ES,
-               .cmd = QCOM_SCM_ES_CONFIG_SET_ICE_KEY,
-               .arginfo = QCOM_SCM_ARGS(5, QCOM_SCM_VAL, QCOM_SCM_RW,
-                                        QCOM_SCM_VAL, QCOM_SCM_VAL,
-                                        QCOM_SCM_VAL),
-               .args[0] = index,
-               .args[2] = key_size,
-               .args[3] = cipher,
-               .args[4] = data_unit_size,
-               .owner = ARM_SMCCC_OWNER_SIP,
-       };
-       void *keybuf;
-       dma_addr_t key_phys;
-       int ret;
-
-       /*
-        * 'key' may point to vmalloc()'ed memory, but we need to pass a
-        * physical address that's been properly flushed.  The sanctioned way to
-        * do this is by using the DMA API.  But as is best practice for crypto
-        * keys, we also must wipe the key after use.  This makes kmemdup() +
-        * dma_map_single() not clearly correct, since the DMA API can use
-        * bounce buffers.  Instead, just use dma_alloc_coherent().  Programming
-        * keys is normally rare and thus not performance-critical.
-        */
-
-       keybuf = dma_alloc_coherent(__scm->dev, key_size, &key_phys,
-                                   GFP_KERNEL);
-       if (!keybuf)
-               return -ENOMEM;
-       memcpy(keybuf, key, key_size);
-       desc.args[1] = key_phys;
-
-       ret = qcom_scm_call(__scm->dev, &desc, NULL);
-
-       memzero_explicit(keybuf, key_size);
-
-       dma_free_coherent(__scm->dev, key_size, keybuf, key_phys);
-       return ret;
-}
-EXPORT_SYMBOL_GPL(qcom_scm_ice_set_key);
-
-/**
- * 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)
-{
-       bool avail;
-       int ret = qcom_scm_clk_enable();
-
-       if (ret)
-               return ret;
-
-       avail = __qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_HDCP,
-                                               QCOM_SCM_HDCP_INVOKE);
-
-       qcom_scm_clk_disable();
-
-       return avail;
-}
-EXPORT_SYMBOL_GPL(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;
-       struct qcom_scm_desc desc = {
-               .svc = QCOM_SCM_SVC_HDCP,
-               .cmd = QCOM_SCM_HDCP_INVOKE,
-               .arginfo = QCOM_SCM_ARGS(10),
-               .args = {
-                       req[0].addr,
-                       req[0].val,
-                       req[1].addr,
-                       req[1].val,
-                       req[2].addr,
-                       req[2].val,
-                       req[3].addr,
-                       req[3].val,
-                       req[4].addr,
-                       req[4].val
-               },
-               .owner = ARM_SMCCC_OWNER_SIP,
-       };
-       struct qcom_scm_res res;
-
-       if (req_cnt > QCOM_SCM_HDCP_MAX_REQ_CNT)
-               return -ERANGE;
-
-       ret = qcom_scm_clk_enable();
-       if (ret)
-               return ret;
-
-       ret = qcom_scm_call(__scm->dev, &desc, &res);
-       *resp = res.result[0];
-
-       qcom_scm_clk_disable();
-
-       return ret;
-}
-EXPORT_SYMBOL_GPL(qcom_scm_hdcp_req);
-
-int qcom_scm_iommu_set_pt_format(u32 sec_id, u32 ctx_num, u32 pt_fmt)
-{
-       struct qcom_scm_desc desc = {
-               .svc = QCOM_SCM_SVC_SMMU_PROGRAM,
-               .cmd = QCOM_SCM_SMMU_PT_FORMAT,
-               .arginfo = QCOM_SCM_ARGS(3),
-               .args[0] = sec_id,
-               .args[1] = ctx_num,
-               .args[2] = pt_fmt, /* 0: LPAE AArch32 - 1: AArch64 */
-               .owner = ARM_SMCCC_OWNER_SIP,
-       };
-
-       return qcom_scm_call(__scm->dev, &desc, NULL);
-}
-EXPORT_SYMBOL_GPL(qcom_scm_iommu_set_pt_format);
-
-int qcom_scm_qsmmu500_wait_safe_toggle(bool en)
-{
-       struct qcom_scm_desc desc = {
-               .svc = QCOM_SCM_SVC_SMMU_PROGRAM,
-               .cmd = QCOM_SCM_SMMU_CONFIG_ERRATA1,
-               .arginfo = QCOM_SCM_ARGS(2),
-               .args[0] = QCOM_SCM_SMMU_CONFIG_ERRATA1_CLIENT_ALL,
-               .args[1] = en,
-               .owner = ARM_SMCCC_OWNER_SIP,
-       };
-
-
-       return qcom_scm_call_atomic(__scm->dev, &desc, NULL);
-}
-EXPORT_SYMBOL_GPL(qcom_scm_qsmmu500_wait_safe_toggle);
-
-bool qcom_scm_lmh_dcvsh_available(void)
-{
-       return __qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_LMH, QCOM_SCM_LMH_LIMIT_DCVSH);
-}
-EXPORT_SYMBOL_GPL(qcom_scm_lmh_dcvsh_available);
-
-int qcom_scm_lmh_profile_change(u32 profile_id)
-{
-       struct qcom_scm_desc desc = {
-               .svc = QCOM_SCM_SVC_LMH,
-               .cmd = QCOM_SCM_LMH_LIMIT_PROFILE_CHANGE,
-               .arginfo = QCOM_SCM_ARGS(1, QCOM_SCM_VAL),
-               .args[0] = profile_id,
-               .owner = ARM_SMCCC_OWNER_SIP,
-       };
-
-       return qcom_scm_call(__scm->dev, &desc, NULL);
-}
-EXPORT_SYMBOL_GPL(qcom_scm_lmh_profile_change);
-
-int qcom_scm_lmh_dcvsh(u32 payload_fn, u32 payload_reg, u32 payload_val,
-                      u64 limit_node, u32 node_id, u64 version)
-{
-       dma_addr_t payload_phys;
-       u32 *payload_buf;
-       int ret, payload_size = 5 * sizeof(u32);
-
-       struct qcom_scm_desc desc = {
-               .svc = QCOM_SCM_SVC_LMH,
-               .cmd = QCOM_SCM_LMH_LIMIT_DCVSH,
-               .arginfo = QCOM_SCM_ARGS(5, QCOM_SCM_RO, QCOM_SCM_VAL, QCOM_SCM_VAL,
-                                       QCOM_SCM_VAL, QCOM_SCM_VAL),
-               .args[1] = payload_size,
-               .args[2] = limit_node,
-               .args[3] = node_id,
-               .args[4] = version,
-               .owner = ARM_SMCCC_OWNER_SIP,
-       };
-
-       payload_buf = dma_alloc_coherent(__scm->dev, payload_size, &payload_phys, GFP_KERNEL);
-       if (!payload_buf)
-               return -ENOMEM;
-
-       payload_buf[0] = payload_fn;
-       payload_buf[1] = 0;
-       payload_buf[2] = payload_reg;
-       payload_buf[3] = 1;
-       payload_buf[4] = payload_val;
-
-       desc.args[0] = payload_phys;
-
-       ret = qcom_scm_call(__scm->dev, &desc, NULL);
-
-       dma_free_coherent(__scm->dev, payload_size, payload_buf, payload_phys);
-       return ret;
-}
-EXPORT_SYMBOL_GPL(qcom_scm_lmh_dcvsh);
-
-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;
-}
-
-#ifdef CONFIG_QCOM_QSEECOM
-
-/* Lock for QSEECOM SCM call executions */
-static DEFINE_MUTEX(qcom_scm_qseecom_call_lock);
-
-static int __qcom_scm_qseecom_call(const struct qcom_scm_desc *desc,
-                                  struct qcom_scm_qseecom_resp *res)
-{
-       struct qcom_scm_res scm_res = {};
-       int status;
-
-       /*
-        * QSEECOM SCM calls should not be executed concurrently. Therefore, we
-        * require the respective call lock to be held.
-        */
-       lockdep_assert_held(&qcom_scm_qseecom_call_lock);
-
-       status = qcom_scm_call(__scm->dev, desc, &scm_res);
-
-       res->result = scm_res.result[0];
-       res->resp_type = scm_res.result[1];
-       res->data = scm_res.result[2];
-
-       if (status)
-               return status;
-
-       return 0;
-}
-
-/**
- * qcom_scm_qseecom_call() - Perform a QSEECOM SCM call.
- * @desc: SCM call descriptor.
- * @res:  SCM call response (output).
- *
- * Performs the QSEECOM SCM call described by @desc, returning the response in
- * @rsp.
- *
- * Return: Zero on success, nonzero on failure.
- */
-static int qcom_scm_qseecom_call(const struct qcom_scm_desc *desc,
-                                struct qcom_scm_qseecom_resp *res)
-{
-       int status;
-
-       /*
-        * Note: Multiple QSEECOM SCM calls should not be executed same time,
-        * so lock things here. This needs to be extended to callback/listener
-        * handling when support for that is implemented.
-        */
-
-       mutex_lock(&qcom_scm_qseecom_call_lock);
-       status = __qcom_scm_qseecom_call(desc, res);
-       mutex_unlock(&qcom_scm_qseecom_call_lock);
-
-       dev_dbg(__scm->dev, "%s: owner=%x, svc=%x, cmd=%x, result=%lld, type=%llx, data=%llx\n",
-               __func__, desc->owner, desc->svc, desc->cmd, res->result,
-               res->resp_type, res->data);
-
-       if (status) {
-               dev_err(__scm->dev, "qseecom: scm call failed with error %d\n", status);
-               return status;
-       }
-
-       /*
-        * TODO: Handle incomplete and blocked calls:
-        *
-        * Incomplete and blocked calls are not supported yet. Some devices
-        * and/or commands require those, some don't. Let's warn about them
-        * prominently in case someone attempts to try these commands with a
-        * device/command combination that isn't supported yet.
-        */
-       WARN_ON(res->result == QSEECOM_RESULT_INCOMPLETE);
-       WARN_ON(res->result == QSEECOM_RESULT_BLOCKED_ON_LISTENER);
-
-       return 0;
-}
-
-/**
- * qcom_scm_qseecom_get_version() - Query the QSEECOM version.
- * @version: Pointer where the QSEECOM version will be stored.
- *
- * Performs the QSEECOM SCM querying the QSEECOM version currently running in
- * the TrustZone.
- *
- * Return: Zero on success, nonzero on failure.
- */
-static int qcom_scm_qseecom_get_version(u32 *version)
-{
-       struct qcom_scm_desc desc = {};
-       struct qcom_scm_qseecom_resp res = {};
-       u32 feature = 10;
-       int ret;
-
-       desc.owner = QSEECOM_TZ_OWNER_SIP;
-       desc.svc = QSEECOM_TZ_SVC_INFO;
-       desc.cmd = QSEECOM_TZ_CMD_INFO_VERSION;
-       desc.arginfo = QCOM_SCM_ARGS(1, QCOM_SCM_VAL);
-       desc.args[0] = feature;
-
-       ret = qcom_scm_qseecom_call(&desc, &res);
-       if (ret)
-               return ret;
-
-       *version = res.result;
-       return 0;
-}
-
-/**
- * qcom_scm_qseecom_app_get_id() - Query the app ID for a given QSEE app name.
- * @app_name: The name of the app.
- * @app_id:   The returned app ID.
- *
- * Query and return the application ID of the SEE app identified by the given
- * name. This returned ID is the unique identifier of the app required for
- * subsequent communication.
- *
- * Return: Zero on success, nonzero on failure, -ENOENT if the app has not been
- * loaded or could not be found.
- */
-int qcom_scm_qseecom_app_get_id(const char *app_name, u32 *app_id)
-{
-       unsigned long name_buf_size = QSEECOM_MAX_APP_NAME_SIZE;
-       unsigned long app_name_len = strlen(app_name);
-       struct qcom_scm_desc desc = {};
-       struct qcom_scm_qseecom_resp res = {};
-       dma_addr_t name_buf_phys;
-       char *name_buf;
-       int status;
-
-       if (app_name_len >= name_buf_size)
-               return -EINVAL;
-
-       name_buf = kzalloc(name_buf_size, GFP_KERNEL);
-       if (!name_buf)
-               return -ENOMEM;
-
-       memcpy(name_buf, app_name, app_name_len);
-
-       name_buf_phys = dma_map_single(__scm->dev, name_buf, name_buf_size, DMA_TO_DEVICE);
-       status = dma_mapping_error(__scm->dev, name_buf_phys);
-       if (status) {
-               kfree(name_buf);
-               dev_err(__scm->dev, "qseecom: failed to map dma address\n");
-               return status;
-       }
-
-       desc.owner = QSEECOM_TZ_OWNER_QSEE_OS;
-       desc.svc = QSEECOM_TZ_SVC_APP_MGR;
-       desc.cmd = QSEECOM_TZ_CMD_APP_LOOKUP;
-       desc.arginfo = QCOM_SCM_ARGS(2, QCOM_SCM_RW, QCOM_SCM_VAL);
-       desc.args[0] = name_buf_phys;
-       desc.args[1] = app_name_len;
-
-       status = qcom_scm_qseecom_call(&desc, &res);
-       dma_unmap_single(__scm->dev, name_buf_phys, name_buf_size, DMA_TO_DEVICE);
-       kfree(name_buf);
-
-       if (status)
-               return status;
-
-       if (res.result == QSEECOM_RESULT_FAILURE)
-               return -ENOENT;
-
-       if (res.result != QSEECOM_RESULT_SUCCESS)
-               return -EINVAL;
-
-       if (res.resp_type != QSEECOM_SCM_RES_APP_ID)
-               return -EINVAL;
-
-       *app_id = res.data;
-       return 0;
-}
-EXPORT_SYMBOL_GPL(qcom_scm_qseecom_app_get_id);
-
-/**
- * qcom_scm_qseecom_app_send() - Send to and receive data from a given QSEE app.
- * @app_id:   The ID of the target app.
- * @req:      Request buffer sent to the app (must be DMA-mappable).
- * @req_size: Size of the request buffer.
- * @rsp:      Response buffer, written to by the app (must be DMA-mappable).
- * @rsp_size: Size of the response buffer.
- *
- * Sends a request to the QSEE app associated with the given ID and read back
- * its response. The caller must provide two DMA memory regions, one for the
- * request and one for the response, and fill out the @req region with the
- * respective (app-specific) request data. The QSEE app reads this and returns
- * its response in the @rsp region.
- *
- * Return: Zero on success, nonzero on failure.
- */
-int qcom_scm_qseecom_app_send(u32 app_id, void *req, size_t req_size, void *rsp,
-                             size_t rsp_size)
-{
-       struct qcom_scm_qseecom_resp res = {};
-       struct qcom_scm_desc desc = {};
-       dma_addr_t req_phys;
-       dma_addr_t rsp_phys;
-       int status;
-
-       /* Map request buffer */
-       req_phys = dma_map_single(__scm->dev, req, req_size, DMA_TO_DEVICE);
-       status = dma_mapping_error(__scm->dev, req_phys);
-       if (status) {
-               dev_err(__scm->dev, "qseecom: failed to map request buffer\n");
-               return status;
-       }
-
-       /* Map response buffer */
-       rsp_phys = dma_map_single(__scm->dev, rsp, rsp_size, DMA_FROM_DEVICE);
-       status = dma_mapping_error(__scm->dev, rsp_phys);
-       if (status) {
-               dma_unmap_single(__scm->dev, req_phys, req_size, DMA_TO_DEVICE);
-               dev_err(__scm->dev, "qseecom: failed to map response buffer\n");
-               return status;
-       }
-
-       /* Set up SCM call data */
-       desc.owner = QSEECOM_TZ_OWNER_TZ_APPS;
-       desc.svc = QSEECOM_TZ_SVC_APP_ID_PLACEHOLDER;
-       desc.cmd = QSEECOM_TZ_CMD_APP_SEND;
-       desc.arginfo = QCOM_SCM_ARGS(5, QCOM_SCM_VAL,
-                                    QCOM_SCM_RW, QCOM_SCM_VAL,
-                                    QCOM_SCM_RW, QCOM_SCM_VAL);
-       desc.args[0] = app_id;
-       desc.args[1] = req_phys;
-       desc.args[2] = req_size;
-       desc.args[3] = rsp_phys;
-       desc.args[4] = rsp_size;
-
-       /* Perform call */
-       status = qcom_scm_qseecom_call(&desc, &res);
-
-       /* Unmap buffers */
-       dma_unmap_single(__scm->dev, rsp_phys, rsp_size, DMA_FROM_DEVICE);
-       dma_unmap_single(__scm->dev, req_phys, req_size, DMA_TO_DEVICE);
-
-       if (status)
-               return status;
-
-       if (res.result != QSEECOM_RESULT_SUCCESS)
-               return -EIO;
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(qcom_scm_qseecom_app_send);
-
-/*
- * We do not yet support re-entrant calls via the qseecom interface. To prevent
- + any potential issues with this, only allow validated machines for now.
- */
-static const struct of_device_id qcom_scm_qseecom_allowlist[] = {
-       { .compatible = "lenovo,thinkpad-x13s", },
-       { }
-};
-
-static bool qcom_scm_qseecom_machine_is_allowed(void)
-{
-       struct device_node *np;
-       bool match;
-
-       np = of_find_node_by_path("/");
-       if (!np)
-               return false;
-
-       match = of_match_node(qcom_scm_qseecom_allowlist, np);
-       of_node_put(np);
-
-       return match;
-}
-
-static void qcom_scm_qseecom_free(void *data)
-{
-       struct platform_device *qseecom_dev = data;
-
-       platform_device_del(qseecom_dev);
-       platform_device_put(qseecom_dev);
-}
-
-static int qcom_scm_qseecom_init(struct qcom_scm *scm)
-{
-       struct platform_device *qseecom_dev;
-       u32 version;
-       int ret;
-
-       /*
-        * Note: We do two steps of validation here: First, we try to query the
-        * QSEECOM version as a check to see if the interface exists on this
-        * device. Second, we check against known good devices due to current
-        * driver limitations (see comment in qcom_scm_qseecom_allowlist).
-        *
-        * Note that we deliberately do the machine check after the version
-        * check so that we can log potentially supported devices. This should
-        * be safe as downstream sources indicate that the version query is
-        * neither blocking nor reentrant.
-        */
-       ret = qcom_scm_qseecom_get_version(&version);
-       if (ret)
-               return 0;
-
-       dev_info(scm->dev, "qseecom: found qseecom with version 0x%x\n", version);
-
-       if (!qcom_scm_qseecom_machine_is_allowed()) {
-               dev_info(scm->dev, "qseecom: untested machine, skipping\n");
-               return 0;
-       }
-
-       /*
-        * Set up QSEECOM interface device. All application clients will be
-        * set up and managed by the corresponding driver for it.
-        */
-       qseecom_dev = platform_device_alloc("qcom_qseecom", -1);
-       if (!qseecom_dev)
-               return -ENOMEM;
-
-       qseecom_dev->dev.parent = scm->dev;
-
-       ret = platform_device_add(qseecom_dev);
-       if (ret) {
-               platform_device_put(qseecom_dev);
-               return ret;
-       }
-
-       return devm_add_action_or_reset(scm->dev, qcom_scm_qseecom_free, qseecom_dev);
-}
-
-#else /* CONFIG_QCOM_QSEECOM */
-
-static int qcom_scm_qseecom_init(struct qcom_scm *scm)
-{
-       return 0;
-}
-
-#endif /* CONFIG_QCOM_QSEECOM */
-
-/**
- * qcom_scm_is_available() - Checks if SCM is available
- */
-bool qcom_scm_is_available(void)
-{
-       return !!__scm;
-}
-EXPORT_SYMBOL_GPL(qcom_scm_is_available);
-
-static int qcom_scm_assert_valid_wq_ctx(u32 wq_ctx)
-{
-       /* FW currently only supports a single wq_ctx (zero).
-        * TODO: Update this logic to include dynamic allocation and lookup of
-        * completion structs when FW supports more wq_ctx values.
-        */
-       if (wq_ctx != 0) {
-               dev_err(__scm->dev, "Firmware unexpectedly passed non-zero wq_ctx\n");
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-int qcom_scm_wait_for_wq_completion(u32 wq_ctx)
-{
-       int ret;
-
-       ret = qcom_scm_assert_valid_wq_ctx(wq_ctx);
-       if (ret)
-               return ret;
-
-       wait_for_completion(&__scm->waitq_comp);
-
-       return 0;
-}
-
-static int qcom_scm_waitq_wakeup(struct qcom_scm *scm, unsigned int wq_ctx)
-{
-       int ret;
-
-       ret = qcom_scm_assert_valid_wq_ctx(wq_ctx);
-       if (ret)
-               return ret;
-
-       complete(&__scm->waitq_comp);
-
-       return 0;
-}
-
-static irqreturn_t qcom_scm_irq_handler(int irq, void *data)
-{
-       int ret;
-       struct qcom_scm *scm = data;
-       u32 wq_ctx, flags, more_pending = 0;
-
-       do {
-               ret = scm_get_wq_ctx(&wq_ctx, &flags, &more_pending);
-               if (ret) {
-                       dev_err(scm->dev, "GET_WQ_CTX SMC call failed: %d\n", ret);
-                       goto out;
-               }
-
-               if (flags != QCOM_SMC_WAITQ_FLAG_WAKE_ONE &&
-                   flags != QCOM_SMC_WAITQ_FLAG_WAKE_ALL) {
-                       dev_err(scm->dev, "Invalid flags found for wq_ctx: %u\n", flags);
-                       goto out;
-               }
-
-               ret = qcom_scm_waitq_wakeup(scm, wq_ctx);
-               if (ret)
-                       goto out;
-       } while (more_pending);
-
-out:
-       return IRQ_HANDLED;
-}
-
-static int qcom_scm_probe(struct platform_device *pdev)
-{
-       struct qcom_scm *scm;
-       int irq, ret;
-
-       scm = devm_kzalloc(&pdev->dev, sizeof(*scm), GFP_KERNEL);
-       if (!scm)
-               return -ENOMEM;
-
-       ret = qcom_scm_find_dload_address(&pdev->dev, &scm->dload_mode_addr);
-       if (ret < 0)
-               return ret;
-
-       mutex_init(&scm->scm_bw_lock);
-
-       scm->path = devm_of_icc_get(&pdev->dev, NULL);
-       if (IS_ERR(scm->path))
-               return dev_err_probe(&pdev->dev, PTR_ERR(scm->path),
-                                    "failed to acquire interconnect path\n");
-
-       scm->core_clk = devm_clk_get_optional(&pdev->dev, "core");
-       if (IS_ERR(scm->core_clk))
-               return PTR_ERR(scm->core_clk);
-
-       scm->iface_clk = devm_clk_get_optional(&pdev->dev, "iface");
-       if (IS_ERR(scm->iface_clk))
-               return PTR_ERR(scm->iface_clk);
-
-       scm->bus_clk = devm_clk_get_optional(&pdev->dev, "bus");
-       if (IS_ERR(scm->bus_clk))
-               return PTR_ERR(scm->bus_clk);
-
-       scm->reset.ops = &qcom_scm_pas_reset_ops;
-       scm->reset.nr_resets = 1;
-       scm->reset.of_node = pdev->dev.of_node;
-       ret = devm_reset_controller_register(&pdev->dev, &scm->reset);
-       if (ret)
-               return ret;
-
-       /* vote for max clk rate for highest performance */
-       ret = clk_set_rate(scm->core_clk, INT_MAX);
-       if (ret)
-               return ret;
-
-       __scm = scm;
-       __scm->dev = &pdev->dev;
-
-       init_completion(&__scm->waitq_comp);
-
-       irq = platform_get_irq_optional(pdev, 0);
-       if (irq < 0) {
-               if (irq != -ENXIO)
-                       return irq;
-       } else {
-               ret = devm_request_threaded_irq(__scm->dev, irq, NULL, qcom_scm_irq_handler,
-                                               IRQF_ONESHOT, "qcom-scm", __scm);
-               if (ret < 0)
-                       return dev_err_probe(scm->dev, ret, "Failed to request qcom-scm irq\n");
-       }
-
-       __get_convention();
-
-       /*
-        * If requested enable "download mode", from this point on warmboot
-        * will cause the boot stages to enter download mode, unless
-        * disabled below by a clean shutdown/reboot.
-        */
-       if (download_mode)
-               qcom_scm_set_download_mode(true);
-
-
-       /*
-        * Disable SDI if indicated by DT that it is enabled by default.
-        */
-       if (of_property_read_bool(pdev->dev.of_node, "qcom,sdi-enabled"))
-               qcom_scm_disable_sdi();
-
-       /*
-        * Initialize the QSEECOM interface.
-        *
-        * Note: QSEECOM is fairly self-contained and this only adds the
-        * interface device (the driver of which does most of the heavy
-        * lifting). So any errors returned here should be either -ENOMEM or
-        * -EINVAL (with the latter only in case there's a bug in our code).
-        * This means that there is no need to bring down the whole SCM driver.
-        * Just log the error instead and let SCM live.
-        */
-       ret = qcom_scm_qseecom_init(scm);
-       WARN(ret < 0, "failed to initialize qseecom: %d\n", ret);
-
-       return 0;
-}
-
-static void qcom_scm_shutdown(struct platform_device *pdev)
-{
-       /* Clean shutdown, disable download mode to allow normal restart */
-       qcom_scm_set_download_mode(false);
-}
-
-static const struct of_device_id qcom_scm_dt_match[] = {
-       { .compatible = "qcom,scm" },
-
-       /* Legacy entries kept for backwards compatibility */
-       { .compatible = "qcom,scm-apq8064" },
-       { .compatible = "qcom,scm-apq8084" },
-       { .compatible = "qcom,scm-ipq4019" },
-       { .compatible = "qcom,scm-msm8953" },
-       { .compatible = "qcom,scm-msm8974" },
-       { .compatible = "qcom,scm-msm8996" },
-       {}
-};
-MODULE_DEVICE_TABLE(of, qcom_scm_dt_match);
-
-static struct platform_driver qcom_scm_driver = {
-       .driver = {
-               .name   = "qcom_scm",
-               .of_match_table = qcom_scm_dt_match,
-               .suppress_bind_attrs = true,
-       },
-       .probe = qcom_scm_probe,
-       .shutdown = qcom_scm_shutdown,
-};
-
-static int __init qcom_scm_init(void)
-{
-       return platform_driver_register(&qcom_scm_driver);
-}
-subsys_initcall(qcom_scm_init);
-
-MODULE_DESCRIPTION("Qualcomm Technologies, Inc. SCM driver");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/firmware/qcom_scm.h b/drivers/firmware/qcom_scm.h
deleted file mode 100644 (file)
index 7b68fa8..0000000
+++ /dev/null
@@ -1,168 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/* Copyright (c) 2010-2015,2019 The Linux Foundation. All rights reserved.
- */
-#ifndef __QCOM_SCM_INT_H
-#define __QCOM_SCM_INT_H
-
-enum qcom_scm_convention {
-       SMC_CONVENTION_UNKNOWN,
-       SMC_CONVENTION_LEGACY,
-       SMC_CONVENTION_ARM_32,
-       SMC_CONVENTION_ARM_64,
-};
-
-extern enum qcom_scm_convention qcom_scm_convention;
-
-#define MAX_QCOM_SCM_ARGS 10
-#define MAX_QCOM_SCM_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
- */
-struct qcom_scm_desc {
-       u32 svc;
-       u32 cmd;
-       u32 arginfo;
-       u64 args[MAX_QCOM_SCM_ARGS];
-       u32 owner;
-};
-
-/**
- * struct qcom_scm_res
- * @result:    The values returned by the secure syscall
- */
-struct qcom_scm_res {
-       u64 result[MAX_QCOM_SCM_RETS];
-};
-
-int qcom_scm_wait_for_wq_completion(u32 wq_ctx);
-int scm_get_wq_ctx(u32 *wq_ctx, u32 *flags, u32 *more_pending);
-
-#define SCM_SMC_FNID(s, c)     ((((s) & 0xFF) << 8) | ((c) & 0xFF))
-extern int __scm_smc_call(struct device *dev, const struct qcom_scm_desc *desc,
-                         enum qcom_scm_convention qcom_convention,
-                         struct qcom_scm_res *res, bool atomic);
-#define scm_smc_call(dev, desc, res, atomic) \
-       __scm_smc_call((dev), (desc), qcom_scm_convention, (res), (atomic))
-
-#define SCM_LEGACY_FNID(s, c)  (((s) << 10) | ((c) & 0x3ff))
-extern int scm_legacy_call_atomic(struct device *dev,
-                                 const struct qcom_scm_desc *desc,
-                                 struct qcom_scm_res *res);
-extern int scm_legacy_call(struct device *dev, const struct qcom_scm_desc *desc,
-                          struct qcom_scm_res *res);
-
-#define QCOM_SCM_SVC_BOOT              0x01
-#define QCOM_SCM_BOOT_SET_ADDR         0x01
-#define QCOM_SCM_BOOT_TERMINATE_PC     0x02
-#define QCOM_SCM_BOOT_SDI_CONFIG       0x09
-#define QCOM_SCM_BOOT_SET_DLOAD_MODE   0x10
-#define QCOM_SCM_BOOT_SET_ADDR_MC      0x11
-#define QCOM_SCM_BOOT_SET_REMOTE_STATE 0x0a
-#define QCOM_SCM_FLUSH_FLAG_MASK       0x3
-#define QCOM_SCM_BOOT_MAX_CPUS         4
-#define QCOM_SCM_BOOT_MC_FLAG_AARCH64  BIT(0)
-#define QCOM_SCM_BOOT_MC_FLAG_COLDBOOT BIT(1)
-#define QCOM_SCM_BOOT_MC_FLAG_WARMBOOT BIT(2)
-
-#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
-
-#define QCOM_SCM_SVC_IO                        0x05
-#define QCOM_SCM_IO_READ               0x01
-#define QCOM_SCM_IO_WRITE              0x02
-
-#define QCOM_SCM_SVC_INFO              0x06
-#define QCOM_SCM_INFO_IS_CALL_AVAIL    0x01
-
-#define QCOM_SCM_SVC_MP                                0x0c
-#define QCOM_SCM_MP_RESTORE_SEC_CFG            0x02
-#define QCOM_SCM_MP_IOMMU_SECURE_PTBL_SIZE     0x03
-#define QCOM_SCM_MP_IOMMU_SECURE_PTBL_INIT     0x04
-#define QCOM_SCM_MP_IOMMU_SET_CP_POOL_SIZE     0x05
-#define QCOM_SCM_MP_VIDEO_VAR                  0x08
-#define QCOM_SCM_MP_ASSIGN                     0x16
-
-#define QCOM_SCM_SVC_OCMEM             0x0f
-#define QCOM_SCM_OCMEM_LOCK_CMD                0x01
-#define QCOM_SCM_OCMEM_UNLOCK_CMD      0x02
-
-#define QCOM_SCM_SVC_ES                        0x10    /* Enterprise Security */
-#define QCOM_SCM_ES_INVALIDATE_ICE_KEY 0x03
-#define QCOM_SCM_ES_CONFIG_SET_ICE_KEY 0x04
-
-#define QCOM_SCM_SVC_HDCP              0x11
-#define QCOM_SCM_HDCP_INVOKE           0x01
-
-#define QCOM_SCM_SVC_LMH                       0x13
-#define QCOM_SCM_LMH_LIMIT_PROFILE_CHANGE      0x01
-#define QCOM_SCM_LMH_LIMIT_DCVSH               0x10
-
-#define QCOM_SCM_SVC_SMMU_PROGRAM              0x15
-#define QCOM_SCM_SMMU_PT_FORMAT                        0x01
-#define QCOM_SCM_SMMU_CONFIG_ERRATA1           0x03
-#define QCOM_SCM_SMMU_CONFIG_ERRATA1_CLIENT_ALL        0x02
-
-#define QCOM_SCM_SVC_WAITQ                     0x24
-#define QCOM_SCM_WAITQ_RESUME                  0x02
-#define QCOM_SCM_WAITQ_GET_WQ_CTX              0x03
-
-/* common error codes */
-#define QCOM_SCM_V2_EBUSY      -12
-#define QCOM_SCM_ENOMEM                -5
-#define QCOM_SCM_EOPNOTSUPP    -4
-#define QCOM_SCM_EINVAL_ADDR   -3
-#define QCOM_SCM_EINVAL_ARG    -2
-#define QCOM_SCM_ERROR         -1
-#define QCOM_SCM_INTERRUPTED   1
-#define QCOM_SCM_WAITQ_SLEEP   2
-
-static inline int qcom_scm_remap_error(int err)
-{
-       switch (err) {
-       case QCOM_SCM_ERROR:
-               return -EIO;
-       case QCOM_SCM_EINVAL_ADDR:
-       case QCOM_SCM_EINVAL_ARG:
-               return -EINVAL;
-       case QCOM_SCM_EOPNOTSUPP:
-               return -EOPNOTSUPP;
-       case QCOM_SCM_ENOMEM:
-               return -ENOMEM;
-       case QCOM_SCM_V2_EBUSY:
-               return -EBUSY;
-       }
-       return -EINVAL;
-}
-
-#endif