From: Sumit Garg sumit.garg@oss.qualcomm.com
Qcom platforms has the legacy of using non-standard SCM calls splintered over the various kernel drivers. These SCM calls aren't compliant with the standard SMC calling conventions which is a prerequisite to enable migration to the FF-A specifications from Arm.
OP-TEE as an alternative trusted OS to QTEE can't support these non- standard SCM calls. And even for newer architectures QTEE won't be able to support SCM calls either with FF-A requirements coming in. And with both OP-TEE and QTEE drivers well integrated in the TEE subsystem, it makes further sense to reuse the TEE bus client drivers infrastructure.
The added benefit of TEE bus infrastructure is that there is support for discoverable/enumerable services. With that client drivers don't have to manually invoke a special SCM call to know the service status.
So enable the generic Peripheral Authentication Service (PAS) provided by the firmware. It acts as the common layer with different TZ backends plugged in whether it's an SCM implementation or a proper TEE bus based PAS service implementation.
The TEE PAS service ABI is designed to be extensible with additional API as PTA_QCOM_PAS_CAPABILITIES. This allows to accommodate any future extensions of the PAS service needed while still maintaining backwards compatibility.
Currently OP-TEE support is being added to provide the backend PAS service implementation which can be found as part of this PR [1]. This implementation has been tested on Kodiak/RB3Gen2 board with lemans EVK board being the next target. In addition to that WIN/IPQ targets planning to use OP-TEE will use this service too.
Patch summary: - Patch #1: adds Kodiak EL2 overlay since boot stack with TF-A/OP-TEE only allow UEFI and Linux to boot in EL2. - Patch #2: adds generic PAS service. - Patch #3: migrates SCM backend to generic PAS service. - Patch #4: adds TEE/OP-TEE backend for generic PAS service. - Patch #5-#13: migrates all client drivers to generic PAS service. - Patch #14: drops legacy PAS SCM exported APIs.
The patch-set is based on v7.0-rc2 tag and can be found in git tree here [2].
Merge strategy: ----------------
It is expected due to APIs dependency, the entire patch-set to go via the Qcom tree. All other subsystem maintainers, it will be great if I can get acks for the corresponding subsystem patches.
[1] https://github.com/OP-TEE/optee_os/pull/7721 [2] https://git.kernel.org/pub/scm/linux/kernel/git/sumit.garg/linux.git/log/?h=...
Mukesh Ojha (1): arm64: dts: qcom: kodiak: Add EL2 overlay
Sumit Garg (13): firmware: qcom: Add a generic PAS service firmware: qcom_scm: Migrate to generic PAS service firmware: qcom: Add a PAS TEE service remoteproc: qcom_q6v5_pas: Switch over to generic PAS TZ APIs remoteproc: qcom_q6v5_mss: Switch to generic PAS TZ APIs soc: qcom: mdtloader: Switch to generic PAS TZ APIs remoteproc: qcom_wcnss: Switch to generic PAS TZ APIs remoteproc: qcom: Select QCOM_PAS_TEE service backend drm/msm: Switch to generic PAS TZ APIs media: qcom: Switch to generic PAS TZ APIs net: ipa: Switch to generic PAS TZ APIs wifi: ath12k: Switch to generic PAS TZ APIs firmware: qcom_scm: Remove SCM PAS wrappers
arch/arm64/boot/dts/qcom/Makefile | 2 + arch/arm64/boot/dts/qcom/kodiak-el2.dtso | 35 ++ drivers/firmware/qcom/Kconfig | 18 + drivers/firmware/qcom/Makefile | 2 + drivers/firmware/qcom/qcom_pas.c | 295 +++++++++++ drivers/firmware/qcom/qcom_pas.h | 53 ++ drivers/firmware/qcom/qcom_pas_tee.c | 478 ++++++++++++++++++ drivers/firmware/qcom/qcom_scm.c | 304 ++++------- drivers/gpu/drm/msm/adreno/a5xx_gpu.c | 4 +- drivers/gpu/drm/msm/adreno/adreno_gpu.c | 11 +- .../media/platform/qcom/iris/iris_firmware.c | 9 +- drivers/media/platform/qcom/venus/firmware.c | 11 +- drivers/net/ipa/ipa_main.c | 13 +- drivers/net/wireless/ath/ath12k/ahb.c | 8 +- drivers/remoteproc/Kconfig | 1 + drivers/remoteproc/qcom_q6v5_mss.c | 5 +- drivers/remoteproc/qcom_q6v5_pas.c | 51 +- drivers/remoteproc/qcom_wcnss.c | 12 +- drivers/soc/qcom/mdt_loader.c | 12 +- include/linux/firmware/qcom/qcom_pas.h | 41 ++ include/linux/firmware/qcom/qcom_scm.h | 29 -- include/linux/soc/qcom/mdt_loader.h | 6 +- 22 files changed, 1097 insertions(+), 303 deletions(-) create mode 100644 arch/arm64/boot/dts/qcom/kodiak-el2.dtso create mode 100644 drivers/firmware/qcom/qcom_pas.c create mode 100644 drivers/firmware/qcom/qcom_pas.h create mode 100644 drivers/firmware/qcom/qcom_pas_tee.c create mode 100644 include/linux/firmware/qcom/qcom_pas.h
From: Mukesh Ojha mukesh.ojha@oss.qualcomm.com
All the existing variants Kodiak boards are using Gunyah hypervisor which means that, so far, Linux-based OS could only boot in EL1 on those devices. However, it is possible for us to boot Linux at EL2 on these devices [1].
When running under Gunyah, the remote processor firmware IOMMU streams are controlled by Gunyah. However, without Gunyah, the IOMMU is managed by the consumer of this DeviceTree. Therefore, describe the firmware streams for each remote processor.
Add a EL2-specific DT overlay and apply it to Kodiak IOT variant devices to create -el2.dtb for each of them alongside "normal" dtb.
[1] https://docs.qualcomm.com/bundle/publicresource/topics/80-70020-4/boot-devel...
Signed-off-by: Mukesh Ojha mukesh.ojha@oss.qualcomm.com [SG: watchdog fixup] Signed-off-by: Sumit Garg sumit.garg@oss.qualcomm.com --- arch/arm64/boot/dts/qcom/Makefile | 2 ++ arch/arm64/boot/dts/qcom/kodiak-el2.dtso | 35 ++++++++++++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 arch/arm64/boot/dts/qcom/kodiak-el2.dtso
diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile index f80b5d9cf1e8..09a7f943190e 100644 --- a/arch/arm64/boot/dts/qcom/Makefile +++ b/arch/arm64/boot/dts/qcom/Makefile @@ -139,6 +139,8 @@ dtb-$(CONFIG_ARCH_QCOM) += qcs404-evb-4000.dtb dtb-$(CONFIG_ARCH_QCOM) += qcs615-ride.dtb dtb-$(CONFIG_ARCH_QCOM) += qcs6490-radxa-dragon-q6a.dtb dtb-$(CONFIG_ARCH_QCOM) += qcs6490-rb3gen2.dtb +qcs6490-rb3gen2-el2-dtbs := qcs6490-rb3gen2.dtb kodiak-el2.dtbo +dtb-$(CONFIG_ARCH_QCOM) += qcs6490-rb3gen2-el2.dtb
qcs6490-rb3gen2-vision-mezzanine-dtbs := qcs6490-rb3gen2.dtb qcs6490-rb3gen2-vision-mezzanine.dtbo qcs6490-rb3gen2-industrial-mezzanine-dtbs := qcs6490-rb3gen2.dtb qcs6490-rb3gen2-industrial-mezzanine.dtbo diff --git a/arch/arm64/boot/dts/qcom/kodiak-el2.dtso b/arch/arm64/boot/dts/qcom/kodiak-el2.dtso new file mode 100644 index 000000000000..0b3a69a0d765 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/kodiak-el2.dtso @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * + * Kodiak specific modifications required to boot in EL2. + */ + + +/dts-v1/; +/plugin/; + +&gpu_zap_shader { + status = "disabled"; +}; + +&remoteproc_adsp { + iommus = <&apps_smmu 0x1800 0x0>; +}; + +&remoteproc_cdsp { + iommus = <&apps_smmu 0x11a0 0x0400>; +}; + +&remoteproc_wpss { + iommus = <&apps_smmu 0x1c03 0x1>, + <&apps_smmu 0x1c83 0x1>; +}; + +&venus { + status = "disabled"; +}; + +&watchdog { + status = "okay"; +};
On Fri, Mar 06, 2026 at 04:20:14PM +0530, Sumit Garg wrote:
From: Mukesh Ojha mukesh.ojha@oss.qualcomm.com
All the existing variants Kodiak boards are using Gunyah hypervisor which means that, so far, Linux-based OS could only boot in EL1 on those devices. However, it is possible for us to boot Linux at EL2 on these devices [1].
When running under Gunyah, the remote processor firmware IOMMU streams are controlled by Gunyah. However, without Gunyah, the IOMMU is managed by the consumer of this DeviceTree. Therefore, describe the firmware streams for each remote processor.
Add a EL2-specific DT overlay and apply it to Kodiak IOT variant devices to create -el2.dtb for each of them alongside "normal" dtb.
[1] https://docs.qualcomm.com/bundle/publicresource/topics/80-70020-4/boot-devel...
Signed-off-by: Mukesh Ojha mukesh.ojha@oss.qualcomm.com [SG: watchdog fixup] Signed-off-by: Sumit Garg sumit.garg@oss.qualcomm.com
Thanks for posting, I was about to add kodiak to the already existing list monaco, talos here https://lore.kernel.org/lkml/20260127-talos-el2-overlay-v2-0-b6a2266532c4@os...
but did you really miss linux-kernel@vger.kernel.org or is it intentional ?
-Mukesh
arch/arm64/boot/dts/qcom/Makefile | 2 ++ arch/arm64/boot/dts/qcom/kodiak-el2.dtso | 35 ++++++++++++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 arch/arm64/boot/dts/qcom/kodiak-el2.dtso
diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile index f80b5d9cf1e8..09a7f943190e 100644 --- a/arch/arm64/boot/dts/qcom/Makefile +++ b/arch/arm64/boot/dts/qcom/Makefile @@ -139,6 +139,8 @@ dtb-$(CONFIG_ARCH_QCOM) += qcs404-evb-4000.dtb dtb-$(CONFIG_ARCH_QCOM) += qcs615-ride.dtb dtb-$(CONFIG_ARCH_QCOM) += qcs6490-radxa-dragon-q6a.dtb dtb-$(CONFIG_ARCH_QCOM) += qcs6490-rb3gen2.dtb +qcs6490-rb3gen2-el2-dtbs := qcs6490-rb3gen2.dtb kodiak-el2.dtbo +dtb-$(CONFIG_ARCH_QCOM) += qcs6490-rb3gen2-el2.dtb qcs6490-rb3gen2-vision-mezzanine-dtbs := qcs6490-rb3gen2.dtb qcs6490-rb3gen2-vision-mezzanine.dtbo qcs6490-rb3gen2-industrial-mezzanine-dtbs := qcs6490-rb3gen2.dtb qcs6490-rb3gen2-industrial-mezzanine.dtbo diff --git a/arch/arm64/boot/dts/qcom/kodiak-el2.dtso b/arch/arm64/boot/dts/qcom/kodiak-el2.dtso new file mode 100644 index 000000000000..0b3a69a0d765 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/kodiak-el2.dtso @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: BSD-3-Clause +/*
- Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
- Kodiak specific modifications required to boot in EL2.
- */
+/dts-v1/; +/plugin/;
+&gpu_zap_shader {
- status = "disabled";
+};
+&remoteproc_adsp {
- iommus = <&apps_smmu 0x1800 0x0>;
+};
+&remoteproc_cdsp {
- iommus = <&apps_smmu 0x11a0 0x0400>;
+};
+&remoteproc_wpss {
- iommus = <&apps_smmu 0x1c03 0x1>,
<&apps_smmu 0x1c83 0x1>;+};
+&venus {
- status = "disabled";
+};
+&watchdog {
- status = "okay";
+};
2.51.0
On Mon, Mar 09, 2026 at 01:30:49PM +0530, Mukesh Ojha wrote:
On Fri, Mar 06, 2026 at 04:20:14PM +0530, Sumit Garg wrote:
From: Mukesh Ojha mukesh.ojha@oss.qualcomm.com
All the existing variants Kodiak boards are using Gunyah hypervisor which means that, so far, Linux-based OS could only boot in EL1 on those devices. However, it is possible for us to boot Linux at EL2 on these devices [1].
When running under Gunyah, the remote processor firmware IOMMU streams are controlled by Gunyah. However, without Gunyah, the IOMMU is managed by the consumer of this DeviceTree. Therefore, describe the firmware streams for each remote processor.
Add a EL2-specific DT overlay and apply it to Kodiak IOT variant devices to create -el2.dtb for each of them alongside "normal" dtb.
[1] https://docs.qualcomm.com/bundle/publicresource/topics/80-70020-4/boot-devel...
Signed-off-by: Mukesh Ojha mukesh.ojha@oss.qualcomm.com [SG: watchdog fixup] Signed-off-by: Sumit Garg sumit.garg@oss.qualcomm.com
Thanks for posting, I was about to add kodiak to the already existing list monaco, talos here https://lore.kernel.org/lkml/20260127-talos-el2-overlay-v2-0-b6a2266532c4@os...
but did you really miss linux-kernel@vger.kernel.org or is it intentional ?
Ah I see, I missed that list. Will add in v2. BTW, this patch in the series can be applied independently since it will work with existing SCM interfaces provided by QTEE.
-Sumit
arch/arm64/boot/dts/qcom/Makefile | 2 ++ arch/arm64/boot/dts/qcom/kodiak-el2.dtso | 35 ++++++++++++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 arch/arm64/boot/dts/qcom/kodiak-el2.dtso
diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile index f80b5d9cf1e8..09a7f943190e 100644 --- a/arch/arm64/boot/dts/qcom/Makefile +++ b/arch/arm64/boot/dts/qcom/Makefile @@ -139,6 +139,8 @@ dtb-$(CONFIG_ARCH_QCOM) += qcs404-evb-4000.dtb dtb-$(CONFIG_ARCH_QCOM) += qcs615-ride.dtb dtb-$(CONFIG_ARCH_QCOM) += qcs6490-radxa-dragon-q6a.dtb dtb-$(CONFIG_ARCH_QCOM) += qcs6490-rb3gen2.dtb +qcs6490-rb3gen2-el2-dtbs := qcs6490-rb3gen2.dtb kodiak-el2.dtbo +dtb-$(CONFIG_ARCH_QCOM) += qcs6490-rb3gen2-el2.dtb qcs6490-rb3gen2-vision-mezzanine-dtbs := qcs6490-rb3gen2.dtb qcs6490-rb3gen2-vision-mezzanine.dtbo qcs6490-rb3gen2-industrial-mezzanine-dtbs := qcs6490-rb3gen2.dtb qcs6490-rb3gen2-industrial-mezzanine.dtbo diff --git a/arch/arm64/boot/dts/qcom/kodiak-el2.dtso b/arch/arm64/boot/dts/qcom/kodiak-el2.dtso new file mode 100644 index 000000000000..0b3a69a0d765 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/kodiak-el2.dtso @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: BSD-3-Clause +/*
- Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
- Kodiak specific modifications required to boot in EL2.
- */
+/dts-v1/; +/plugin/;
+&gpu_zap_shader {
- status = "disabled";
+};
+&remoteproc_adsp {
- iommus = <&apps_smmu 0x1800 0x0>;
+};
+&remoteproc_cdsp {
- iommus = <&apps_smmu 0x11a0 0x0400>;
+};
+&remoteproc_wpss {
- iommus = <&apps_smmu 0x1c03 0x1>,
<&apps_smmu 0x1c83 0x1>;+};
+&venus {
- status = "disabled";
+};
+&watchdog {
- status = "okay";
+};
2.51.0
-- -Mukesh Ojha
From: Sumit Garg sumit.garg@oss.qualcomm.com
Qcom platforms has the legacy of using non-standard SCM calls splintered over the various kernel drivers. These SCM calls aren't compliant with the standard SMC calling conventions which is a prerequisite to enable migration to the FF-A specifications from Arm.
OP-TEE as an alternative trusted OS to QTEE can't support these non- standard SCM calls. And even for newer architectures QTEE won't be able to support SCM calls either with FF-A requirements coming in. And with both OP-TEE and QTEE drivers well integrated in the TEE subsystem, it makes further sense to reuse the TEE bus client drivers infrastructure.
The added benefit of TEE bus infrastructure is that there is support for discoverable/enumerable services. With that client drivers don't have to manually invoke a special SCM call to know the service status.
So enable the generic Peripheral Authentication Service (PAS) provided by the firmware. It acts as the common layer with different TZ backends plugged in whether it's an SCM implementation or a proper TEE bus based PAS service implementation.
Signed-off-by: Sumit Garg sumit.garg@oss.qualcomm.com --- drivers/firmware/qcom/Kconfig | 8 + drivers/firmware/qcom/Makefile | 1 + drivers/firmware/qcom/qcom_pas.c | 295 +++++++++++++++++++++++++ drivers/firmware/qcom/qcom_pas.h | 53 +++++ include/linux/firmware/qcom/qcom_pas.h | 41 ++++ 5 files changed, 398 insertions(+) create mode 100644 drivers/firmware/qcom/qcom_pas.c create mode 100644 drivers/firmware/qcom/qcom_pas.h create mode 100644 include/linux/firmware/qcom/qcom_pas.h
diff --git a/drivers/firmware/qcom/Kconfig b/drivers/firmware/qcom/Kconfig index b477d54b495a..8653639d06db 100644 --- a/drivers/firmware/qcom/Kconfig +++ b/drivers/firmware/qcom/Kconfig @@ -6,6 +6,14 @@
menu "Qualcomm firmware drivers"
+config QCOM_PAS + tristate + help + Enable the generic Peripheral Authentication Service (PAS) provided + by the firmware. It acts as the common layer with different TZ + backends plugged in whether it's an SCM implementation or a proper + TEE bus based PAS service implementation. + config QCOM_SCM select QCOM_TZMEM tristate diff --git a/drivers/firmware/qcom/Makefile b/drivers/firmware/qcom/Makefile index 0be40a1abc13..dc5ab45f906a 100644 --- a/drivers/firmware/qcom/Makefile +++ b/drivers/firmware/qcom/Makefile @@ -8,3 +8,4 @@ qcom-scm-objs += qcom_scm.o qcom_scm-smc.o qcom_scm-legacy.o obj-$(CONFIG_QCOM_TZMEM) += qcom_tzmem.o obj-$(CONFIG_QCOM_QSEECOM) += qcom_qseecom.o obj-$(CONFIG_QCOM_QSEECOM_UEFISECAPP) += qcom_qseecom_uefisecapp.o +obj-$(CONFIG_QCOM_PAS) += qcom_pas.o diff --git a/drivers/firmware/qcom/qcom_pas.c b/drivers/firmware/qcom/qcom_pas.c new file mode 100644 index 000000000000..dc04ff1b6be0 --- /dev/null +++ b/drivers/firmware/qcom/qcom_pas.c @@ -0,0 +1,295 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#include <linux/delay.h> +#include <linux/device/devres.h> +#include <linux/firmware/qcom/qcom_pas.h> +#include <linux/of.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/slab.h> + +#include "qcom_pas.h" +#include "qcom_scm.h" + +static struct qcom_pas_ops *ops_ptr; + +/** + * devm_qcom_pas_context_alloc() - Allocate peripheral authentication service + * context for a given peripheral + * + * PAS context is device-resource managed, so the caller does not need + * to worry about freeing the context memory. + * + * @dev: PAS firmware device + * @pas_id: peripheral authentication service id + * @mem_phys: Subsystem reserve memory start address + * @mem_size: Subsystem reserve memory size + * + * Returns: The new PAS context, or ERR_PTR() on failure. + */ +struct qcom_pas_context *devm_qcom_pas_context_alloc(struct device *dev, + u32 pas_id, + phys_addr_t mem_phys, + size_t mem_size) +{ + struct qcom_pas_context *ctx; + + ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return ERR_PTR(-ENOMEM); + + ctx->dev = dev; + ctx->pas_id = pas_id; + ctx->mem_phys = mem_phys; + ctx->mem_size = mem_size; + + return ctx; +} +EXPORT_SYMBOL_GPL(devm_qcom_pas_context_alloc); + +/** + * qcom_pas_init_image() - Initialize peripheral authentication service state + * machine for a given peripheral, using the metadata + * @pas_id: peripheral authentication service 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 pas 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_pas_metadata_release() by the caller. + */ +int qcom_pas_init_image(u32 pas_id, const void *metadata, size_t size, + struct qcom_pas_context *ctx) +{ + if (ops_ptr) + return ops_ptr->init_image(ops_ptr->dev, pas_id, + metadata, size, ctx); + + return -ENODEV; +} +EXPORT_SYMBOL_GPL(qcom_pas_init_image); + +/** + * qcom_pas_metadata_release() - release metadata context + * @ctx: pas context + */ +void qcom_pas_metadata_release(struct qcom_pas_context *ctx) +{ + if (!ctx || !ctx->ptr) + return; + + if (ops_ptr) + ops_ptr->metadata_release(ops_ptr->dev, ctx); +} +EXPORT_SYMBOL_GPL(qcom_pas_metadata_release); + +/** + * qcom_pas_mem_setup() - Prepare the memory related to a given peripheral + * for firmware loading + * @pas_id: peripheral authentication service id + * @addr: start address of memory area to prepare + * @size: size of the memory area to prepare + * + * Returns 0 on success. + */ +int qcom_pas_mem_setup(u32 pas_id, phys_addr_t addr, phys_addr_t size) +{ + if (ops_ptr) + return ops_ptr->mem_setup(ops_ptr->dev, pas_id, addr, size); + + return -ENODEV; +} +EXPORT_SYMBOL_GPL(qcom_pas_mem_setup); + +/** + * qcom_pas_get_rsc_table() - Retrieve the resource table in passed output buffer + * for a given peripheral. + * + * Qualcomm remote processor may rely on both static and dynamic resources for + * its functionality. Static resources typically refer to memory-mapped + * addresses required by the subsystem and are often embedded within the + * firmware binary and dynamic resources, such as shared memory in DDR etc., + * are determined at runtime during the boot process. + * + * On Qualcomm Technologies devices, it's possible that static resources are + * not embedded in the firmware binary and instead are provided by TrustZone. + * However, dynamic resources are always expected to come from TrustZone. This + * indicates that for Qualcomm devices, all resources (static and dynamic) will + * be provided by TrustZone PAS service. + * + * If the remote processor firmware binary does contain static resources, they + * should be passed in input_rt. These will be forwarded to TrustZone for + * authentication. TrustZone will then append the dynamic resources and return + * the complete resource table in output_rt_tzm. + * + * If the remote processor firmware binary does not include a resource table, + * the caller of this function should set input_rt as NULL and input_rt_size + * as zero respectively. + * + * More about documentation on resource table data structures can be found in + * include/linux/remoteproc.h + * + * @ctx: PAS context + * @pas_id: peripheral authentication service id + * @input_rt: resource table buffer which is present in firmware binary + * @input_rt_size: size of the resource table present in firmware binary + * @output_rt_size: TrustZone expects caller should pass worst case size for + * the output_rt_tzm. + * + * Return: + * On success, returns a pointer to the allocated buffer containing the final + * resource table and output_rt_size will have actual resource table size from + * TrustZone. The caller is responsible for freeing the buffer. On failure, + * returns ERR_PTR(-errno). + */ +struct resource_table *qcom_pas_get_rsc_table(struct qcom_pas_context *ctx, + void *input_rt, + size_t input_rt_size, + size_t *output_rt_size) +{ + if (ops_ptr) + return ops_ptr->get_rsc_table(ops_ptr->dev, ctx, input_rt, + input_rt_size, output_rt_size); + + return ERR_PTR(-ENODEV); +} +EXPORT_SYMBOL_GPL(qcom_pas_get_rsc_table); + +/** + * qcom_scm_pas_auth_and_reset() - Authenticate the given peripheral firmware + * and reset the remote processor + * @pas_id: peripheral authentication service id + * + * Return 0 on success. + */ +int qcom_pas_auth_and_reset(u32 pas_id) +{ + if (ops_ptr) + return ops_ptr->auth_and_reset(ops_ptr->dev, pas_id); + + return -ENODEV; +} +EXPORT_SYMBOL_GPL(qcom_pas_auth_and_reset); + +/** + * qcom_pas_prepare_and_auth_reset() - Prepare, authenticate, and reset the + * remote processor + * + * @ctx: Context saved during call to qcom_scm_pas_context_init() + * + * This function performs the necessary steps to prepare a PAS subsystem, + * authenticate it using the provided metadata, and initiate a reset sequence. + * + * It should be used when Linux is in control setting up the IOMMU hardware + * for remote subsystem during secure firmware loading processes. The + * preparation step sets up a shmbridge over the firmware memory before + * TrustZone accesses the firmware memory region for authentication. The + * authentication step verifies the integrity and authenticity of the firmware + * or configuration using secure metadata. Finally, the reset step ensures the + * subsystem starts in a clean and sane state. + * + * Return: 0 on success, negative errno on failure. + */ +int qcom_pas_prepare_and_auth_reset(struct qcom_pas_context *ctx) +{ + if (ops_ptr) + return ops_ptr->prepare_and_auth_reset(ops_ptr->dev, ctx); + + return -ENODEV; +} +EXPORT_SYMBOL_GPL(qcom_pas_prepare_and_auth_reset); + +/** + * qcom_pas_set_remote_state() - Set the remote processor state + * @state: peripheral state + * @pas_id: peripheral authentication service id + * + * Returns 0 on success. + */ +int qcom_pas_set_remote_state(u32 state, u32 pas_id) +{ + if (ops_ptr) + return ops_ptr->set_remote_state(ops_ptr->dev, state, pas_id); + + return -ENODEV; +} +EXPORT_SYMBOL_GPL(qcom_pas_set_remote_state); + +/** + * qcom_pas_shutdown() - Shut down the remote processor + * @pas_id: peripheral authentication service id + * + * Returns 0 on success. + */ +int qcom_pas_shutdown(u32 pas_id) +{ + if (ops_ptr) + return ops_ptr->shutdown(ops_ptr->dev, pas_id); + + return -ENODEV; +} +EXPORT_SYMBOL_GPL(qcom_pas_shutdown); + +/** + * qcom_pas_supported() - Check if the peripheral authentication service is + * available for the given peripheral + * @pas_id: peripheral authentication service id + * + * Returns true if PAS is supported for this peripheral, otherwise false. + */ +bool qcom_pas_supported(u32 pas_id) +{ + if (ops_ptr) + return ops_ptr->supported(ops_ptr->dev, pas_id); + + return false; +} +EXPORT_SYMBOL_GPL(qcom_pas_supported); + +/** + * qcom_pas_is_available() - Check for PAS service + * + * Returns true on success. + */ +bool qcom_pas_is_available(void) +{ + /* The barrier is needed to synchronize with client drivers. */ + return !!smp_load_acquire(&ops_ptr); +} +EXPORT_SYMBOL_GPL(qcom_pas_is_available); + +/** + * qcom_pas_ops_register() - Register PAS service ops + * @ops: PAS service ops pointer + */ +void qcom_pas_ops_register(struct qcom_pas_ops *ops) +{ + if (!qcom_pas_is_available()) + /* The barrier is needed to synchronize with client drivers. */ + smp_store_release(&ops_ptr, ops); + else + pr_err("qcom_pas: ops already registered\n"); +} +EXPORT_SYMBOL_GPL(qcom_pas_ops_register); + +/** + * qcom_pas_ops_unregister() - Unregister PAS service ops + */ +void qcom_pas_ops_unregister(void) +{ + /* The barrier is needed to synchronize with client drivers. */ + smp_store_release(&ops_ptr, NULL); +} +EXPORT_SYMBOL_GPL(qcom_pas_ops_unregister); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Sumit Garg sumit.garg@oss.qualcomm.com"); +MODULE_DESCRIPTION("Qualcomm common TZ PAS driver"); diff --git a/drivers/firmware/qcom/qcom_pas.h b/drivers/firmware/qcom/qcom_pas.h new file mode 100644 index 000000000000..4ebed22178f8 --- /dev/null +++ b/drivers/firmware/qcom/qcom_pas.h @@ -0,0 +1,53 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#ifndef __QCOM_PAS_INT_H +#define __QCOM_PAS_INT_H + +struct device; + +/** + * struct qcom_pas_ops - Qcom Peripheral Authentication Service (PAS) ops + * @drv_name: PAS driver name. + * @dev: PAS device pointer. + * @supported: Peripheral supported callback. + * @init_image: Peripheral image initialization callback. + * @mem_setup: Peripheral memory setup callback. + * @get_rsc_table: Peripheral get resource table callback. + * @prepare_and_auth_reset: Peripheral prepare firmware authentication and + * reset callback. + * @auth_and_reset: Peripheral firmware authentication and reset + * callback. + * @set_remote_state: Peripheral set remote state callback. + * @shutdown: Peripheral shutdown callback. + * @metadata_release: Image metadata release callback. + */ +struct qcom_pas_ops { + const char *drv_name; + struct device *dev; + bool (*supported)(struct device *dev, u32 pas_id); + int (*init_image)(struct device *dev, u32 pas_id, + const void *metadata, size_t size, + struct qcom_pas_context *ctx); + int (*mem_setup)(struct device *dev, u32 pas_id, + phys_addr_t addr, phys_addr_t size); + void *(*get_rsc_table)(struct device *dev, + struct qcom_pas_context *ctx, + void *input_rt, + size_t input_rt_size, + size_t *output_rt_size); + int (*prepare_and_auth_reset)(struct device *dev, + struct qcom_pas_context *ctx); + int (*auth_and_reset)(struct device *dev, u32 pas_id); + int (*set_remote_state)(struct device *dev, u32 state, u32 pas_id); + int (*shutdown)(struct device *dev, u32 pas_id); + void (*metadata_release)(struct device *dev, + struct qcom_pas_context *ctx); +}; + +void qcom_pas_ops_register(struct qcom_pas_ops *ops); +void qcom_pas_ops_unregister(void); + +#endif /* __QCOM_PAS_INT_H */ diff --git a/include/linux/firmware/qcom/qcom_pas.h b/include/linux/firmware/qcom/qcom_pas.h new file mode 100644 index 000000000000..ef7328ecfa47 --- /dev/null +++ b/include/linux/firmware/qcom/qcom_pas.h @@ -0,0 +1,41 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#ifndef __QCOM_PAS_H +#define __QCOM_PAS_H + +#include <linux/err.h> +#include <linux/types.h> + +struct qcom_pas_context { + struct device *dev; + u32 pas_id; + phys_addr_t mem_phys; + size_t mem_size; + void *ptr; + dma_addr_t phys; + ssize_t size; + bool use_tzmem; +}; + +bool qcom_pas_is_available(void); +struct qcom_pas_context *devm_qcom_pas_context_alloc(struct device *dev, + u32 pas_id, + phys_addr_t mem_phys, + size_t mem_size); +int qcom_pas_init_image(u32 pas_id, const void *metadata, size_t size, + struct qcom_pas_context *ctx); +struct resource_table *qcom_pas_get_rsc_table(struct qcom_pas_context *ctx, + void *input_rt, size_t input_rt_size, + size_t *output_rt_size); +int qcom_pas_mem_setup(u32 pas_id, phys_addr_t addr, phys_addr_t size); +int qcom_pas_auth_and_reset(u32 pas_id); +int qcom_pas_prepare_and_auth_reset(struct qcom_pas_context *ctx); +int qcom_pas_set_remote_state(u32 state, u32 pas_id); +int qcom_pas_shutdown(u32 pas_id); +bool qcom_pas_supported(u32 pas_id); +void qcom_pas_metadata_release(struct qcom_pas_context *ctx); + +#endif /* __QCOM_PAS_H */
On 06/03/2026 11:50, Sumit Garg wrote:
From: Sumit Garg sumit.garg@oss.qualcomm.com
Qcom platforms has the legacy of using non-standard SCM calls splintered over the various kernel drivers. These SCM calls aren't compliant with the standard SMC calling conventions which is a prerequisite to enable migration to the FF-A specifications from Arm.
OP-TEE as an alternative trusted OS to QTEE can't support these non- standard SCM calls. And even for newer architectures QTEE won't be able to support SCM calls either with FF-A requirements coming in. And with both OP-TEE and QTEE drivers well integrated in the TEE subsystem, it makes further sense to reuse the TEE bus client drivers infrastructure.
The added benefit of TEE bus infrastructure is that there is support for discoverable/enumerable services. With that client drivers don't have to manually invoke a special SCM call to know the service status.
So enable the generic Peripheral Authentication Service (PAS) provided by the firmware. It acts as the common layer with different TZ backends plugged in whether it's an SCM implementation or a proper TEE bus based PAS service implementation.
Signed-off-by: Sumit Garg sumit.garg@oss.qualcomm.com
drivers/firmware/qcom/Kconfig | 8 + drivers/firmware/qcom/Makefile | 1 + drivers/firmware/qcom/qcom_pas.c | 295 +++++++++++++++++++++++++ drivers/firmware/qcom/qcom_pas.h | 53 +++++ include/linux/firmware/qcom/qcom_pas.h | 41 ++++ 5 files changed, 398 insertions(+) create mode 100644 drivers/firmware/qcom/qcom_pas.c create mode 100644 drivers/firmware/qcom/qcom_pas.h create mode 100644 include/linux/firmware/qcom/qcom_pas.h
diff --git a/drivers/firmware/qcom/Kconfig b/drivers/firmware/qcom/Kconfig index b477d54b495a..8653639d06db 100644 --- a/drivers/firmware/qcom/Kconfig +++ b/drivers/firmware/qcom/Kconfig @@ -6,6 +6,14 @@ menu "Qualcomm firmware drivers" +config QCOM_PAS
- tristate
- help
Enable the generic Peripheral Authentication Service (PAS) providedby the firmware. It acts as the common layer with different TZbackends plugged in whether it's an SCM implementation or a properTEE bus based PAS service implementation.config QCOM_SCM select QCOM_TZMEM tristate diff --git a/drivers/firmware/qcom/Makefile b/drivers/firmware/qcom/Makefile index 0be40a1abc13..dc5ab45f906a 100644 --- a/drivers/firmware/qcom/Makefile +++ b/drivers/firmware/qcom/Makefile @@ -8,3 +8,4 @@ qcom-scm-objs += qcom_scm.o qcom_scm-smc.o qcom_scm-legacy.o obj-$(CONFIG_QCOM_TZMEM) += qcom_tzmem.o obj-$(CONFIG_QCOM_QSEECOM) += qcom_qseecom.o obj-$(CONFIG_QCOM_QSEECOM_UEFISECAPP) += qcom_qseecom_uefisecapp.o +obj-$(CONFIG_QCOM_PAS) += qcom_pas.o diff --git a/drivers/firmware/qcom/qcom_pas.c b/drivers/firmware/qcom/qcom_pas.c new file mode 100644 index 000000000000..dc04ff1b6be0 --- /dev/null +++ b/drivers/firmware/qcom/qcom_pas.c @@ -0,0 +1,295 @@ +// SPDX-License-Identifier: GPL-2.0 +/*
- Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
- */
+#include <linux/delay.h> +#include <linux/device/devres.h> +#include <linux/firmware/qcom/qcom_pas.h> +#include <linux/of.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/slab.h>
+#include "qcom_pas.h" +#include "qcom_scm.h"
+static struct qcom_pas_ops *ops_ptr;
I really dislike this singleton design. And it is not even needed! If you were storing here some allocated instance of SCM/PAS I could understand, but singleton for only ops? Just implement one driver (so SCM + whatever you have here) which will decide which ops to use, through the probe. Really, this is neither needed nor beneficial.
It actually leads to more problems with this barrier handling, see further comments. ...
+/**
- qcom_pas_shutdown() - Shut down the remote processor
- @pas_id: peripheral authentication service id
- Returns 0 on success.
- */
+int qcom_pas_shutdown(u32 pas_id) +{
- if (ops_ptr)
return ops_ptr->shutdown(ops_ptr->dev, pas_id);- return -ENODEV;
+} +EXPORT_SYMBOL_GPL(qcom_pas_shutdown);
+/**
- qcom_pas_supported() - Check if the peripheral authentication service is
available for the given peripheral
- @pas_id: peripheral authentication service id
- Returns true if PAS is supported for this peripheral, otherwise false.
- */
+bool qcom_pas_supported(u32 pas_id) +{
- if (ops_ptr)
Lack of barriers here is not looking right. Existing/old code is not a good example, I fixed only the obvious issue, but new code should be correct from the beginning.
Barriers should normally be always paired, unless you have some clear path no concurrent execution can happen here, but such explanation is missing, look:
return ops_ptr->supported(ops_ptr->dev, pas_id);- return false;
+} +EXPORT_SYMBOL_GPL(qcom_pas_supported);
+/**
- qcom_pas_is_available() - Check for PAS service
- Returns true on success.
- */
+bool qcom_pas_is_available(void) +{
- /* The barrier is needed to synchronize with client drivers. */
Here. This is pretty pointless/redundant comment. Obviously barriers are to synchronize with whoever is calling this and only clients are calling.
You must say something useful, not just barrier is a barrier... It's like documenting mutex "to synchronize".
- return !!smp_load_acquire(&ops_ptr);
Best regards, Krzysztof
On Fri, Mar 06, 2026 at 12:15:01PM +0100, Krzysztof Kozlowski wrote:
On 06/03/2026 11:50, Sumit Garg wrote:
From: Sumit Garg sumit.garg@oss.qualcomm.com
Qcom platforms has the legacy of using non-standard SCM calls splintered over the various kernel drivers. These SCM calls aren't compliant with the standard SMC calling conventions which is a prerequisite to enable migration to the FF-A specifications from Arm.
OP-TEE as an alternative trusted OS to QTEE can't support these non- standard SCM calls. And even for newer architectures QTEE won't be able to support SCM calls either with FF-A requirements coming in. And with both OP-TEE and QTEE drivers well integrated in the TEE subsystem, it makes further sense to reuse the TEE bus client drivers infrastructure.
The added benefit of TEE bus infrastructure is that there is support for discoverable/enumerable services. With that client drivers don't have to manually invoke a special SCM call to know the service status.
So enable the generic Peripheral Authentication Service (PAS) provided by the firmware. It acts as the common layer with different TZ backends plugged in whether it's an SCM implementation or a proper TEE bus based PAS service implementation.
Signed-off-by: Sumit Garg sumit.garg@oss.qualcomm.com
drivers/firmware/qcom/Kconfig | 8 + drivers/firmware/qcom/Makefile | 1 + drivers/firmware/qcom/qcom_pas.c | 295 +++++++++++++++++++++++++ drivers/firmware/qcom/qcom_pas.h | 53 +++++ include/linux/firmware/qcom/qcom_pas.h | 41 ++++ 5 files changed, 398 insertions(+) create mode 100644 drivers/firmware/qcom/qcom_pas.c create mode 100644 drivers/firmware/qcom/qcom_pas.h create mode 100644 include/linux/firmware/qcom/qcom_pas.h
diff --git a/drivers/firmware/qcom/Kconfig b/drivers/firmware/qcom/Kconfig index b477d54b495a..8653639d06db 100644 --- a/drivers/firmware/qcom/Kconfig +++ b/drivers/firmware/qcom/Kconfig @@ -6,6 +6,14 @@ menu "Qualcomm firmware drivers" +config QCOM_PAS
- tristate
- help
Enable the generic Peripheral Authentication Service (PAS) providedby the firmware. It acts as the common layer with different TZbackends plugged in whether it's an SCM implementation or a properTEE bus based PAS service implementation.config QCOM_SCM select QCOM_TZMEM tristate diff --git a/drivers/firmware/qcom/Makefile b/drivers/firmware/qcom/Makefile index 0be40a1abc13..dc5ab45f906a 100644 --- a/drivers/firmware/qcom/Makefile +++ b/drivers/firmware/qcom/Makefile @@ -8,3 +8,4 @@ qcom-scm-objs += qcom_scm.o qcom_scm-smc.o qcom_scm-legacy.o obj-$(CONFIG_QCOM_TZMEM) += qcom_tzmem.o obj-$(CONFIG_QCOM_QSEECOM) += qcom_qseecom.o obj-$(CONFIG_QCOM_QSEECOM_UEFISECAPP) += qcom_qseecom_uefisecapp.o +obj-$(CONFIG_QCOM_PAS) += qcom_pas.o diff --git a/drivers/firmware/qcom/qcom_pas.c b/drivers/firmware/qcom/qcom_pas.c new file mode 100644 index 000000000000..dc04ff1b6be0 --- /dev/null +++ b/drivers/firmware/qcom/qcom_pas.c @@ -0,0 +1,295 @@ +// SPDX-License-Identifier: GPL-2.0 +/*
- Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
- */
+#include <linux/delay.h> +#include <linux/device/devres.h> +#include <linux/firmware/qcom/qcom_pas.h> +#include <linux/of.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/slab.h>
+#include "qcom_pas.h" +#include "qcom_scm.h"
+static struct qcom_pas_ops *ops_ptr;
I really dislike this singleton design. And it is not even needed! If you were storing here some allocated instance of SCM/PAS I could understand, but singleton for only ops? Just implement one driver (so SCM + whatever you have here) which will decide which ops to use, through the probe. Really, this is neither needed nor beneficial.
The motivation here is rather quite opposite to the single monolithic SCM driver design. The TZ services like PAS, ICE and so on are going to be implemented as independent discoverable devices on TEE bus which rather needs independent kernel client drivers.
Also, the single driver probe can't work here since the SCM driver is bound to the platform bus whereas the TEE PAS driver is bound to the TEE bus. So there is a reason for the current design.
It actually leads to more problems with this barrier handling, see further comments.
The barrier handling is something that I carried over from existing implmentation but I can't see a reason why it can't be replaced with a simple mutex. See diff below for mutex.
...
+/**
- qcom_pas_shutdown() - Shut down the remote processor
- @pas_id: peripheral authentication service id
- Returns 0 on success.
- */
+int qcom_pas_shutdown(u32 pas_id) +{
- if (ops_ptr)
return ops_ptr->shutdown(ops_ptr->dev, pas_id);- return -ENODEV;
+} +EXPORT_SYMBOL_GPL(qcom_pas_shutdown);
+/**
- qcom_pas_supported() - Check if the peripheral authentication service is
available for the given peripheral
- @pas_id: peripheral authentication service id
- Returns true if PAS is supported for this peripheral, otherwise false.
- */
+bool qcom_pas_supported(u32 pas_id) +{
- if (ops_ptr)
Lack of barriers here is not looking right. Existing/old code is not a good example, I fixed only the obvious issue, but new code should be correct from the beginning.
Barriers should normally be always paired, unless you have some clear path no concurrent execution can happen here, but such explanation is missing, look:
Actually concurrent execution is rather required here since TZ can support parallel bring-up of co-processors. The synchonization is only needed when PAS client drivers are performing a deferred probe waiting for the service to be available. However, you are right explanation is missing here which I will add in the next version.
return ops_ptr->supported(ops_ptr->dev, pas_id);- return false;
+} +EXPORT_SYMBOL_GPL(qcom_pas_supported);
+/**
- qcom_pas_is_available() - Check for PAS service
- Returns true on success.
- */
+bool qcom_pas_is_available(void) +{
- /* The barrier is needed to synchronize with client drivers. */
Here. This is pretty pointless/redundant comment. Obviously barriers are to synchronize with whoever is calling this and only clients are calling.
You must say something useful, not just barrier is a barrier... It's like documenting mutex "to synchronize".
Sure, I can expand the comments.
- return !!smp_load_acquire(&ops_ptr);
diff --git a/drivers/firmware/qcom/qcom_pas.c b/drivers/firmware/qcom/qcom_pas.c index dc04ff1b6be0..82312ff5a1d0 100644 --- a/drivers/firmware/qcom/qcom_pas.c +++ b/drivers/firmware/qcom/qcom_pas.c @@ -14,6 +14,7 @@ #include "qcom_pas.h" #include "qcom_scm.h"
+static DEFINE_MUTEX(ops_mutex); static struct qcom_pas_ops *ops_ptr;
/** @@ -261,8 +262,8 @@ EXPORT_SYMBOL_GPL(qcom_pas_supported); */ bool qcom_pas_is_available(void) { - /* The barrier is needed to synchronize with client drivers. */ - return !!smp_load_acquire(&ops_ptr); + guard(mutex)(&ops_mutex); + return !!ops_ptr; } EXPORT_SYMBOL_GPL(qcom_pas_is_available);
@@ -272,11 +273,12 @@ EXPORT_SYMBOL_GPL(qcom_pas_is_available); */ void qcom_pas_ops_register(struct qcom_pas_ops *ops) { - if (!qcom_pas_is_available()) - /* The barrier is needed to synchronize with client drivers. */ - smp_store_release(&ops_ptr, ops); - else + if (!qcom_pas_is_available()) { + guard(mutex)(&ops_mutex); + ops_ptr = ops; + } else { pr_err("qcom_pas: ops already registered\n"); + } } EXPORT_SYMBOL_GPL(qcom_pas_ops_register);
@@ -285,8 +287,8 @@ EXPORT_SYMBOL_GPL(qcom_pas_ops_register); */ void qcom_pas_ops_unregister(void) { - /* The barrier is needed to synchronize with client drivers. */ - smp_store_release(&ops_ptr, NULL); + guard(mutex)(&ops_mutex); + ops_ptr = NULL; } EXPORT_SYMBOL_GPL(qcom_pas_ops_unregister);
-Sumit
On 09/03/2026 05:55, Sumit Garg wrote:
On Fri, Mar 06, 2026 at 12:15:01PM +0100, Krzysztof Kozlowski wrote:
On 06/03/2026 11:50, Sumit Garg wrote:
From: Sumit Garg sumit.garg@oss.qualcomm.com
Qcom platforms has the legacy of using non-standard SCM calls splintered over the various kernel drivers. These SCM calls aren't compliant with the standard SMC calling conventions which is a prerequisite to enable migration to the FF-A specifications from Arm.
OP-TEE as an alternative trusted OS to QTEE can't support these non- standard SCM calls. And even for newer architectures QTEE won't be able to support SCM calls either with FF-A requirements coming in. And with both OP-TEE and QTEE drivers well integrated in the TEE subsystem, it makes further sense to reuse the TEE bus client drivers infrastructure.
The added benefit of TEE bus infrastructure is that there is support for discoverable/enumerable services. With that client drivers don't have to manually invoke a special SCM call to know the service status.
So enable the generic Peripheral Authentication Service (PAS) provided by the firmware. It acts as the common layer with different TZ backends plugged in whether it's an SCM implementation or a proper TEE bus based PAS service implementation.
Signed-off-by: Sumit Garg sumit.garg@oss.qualcomm.com
drivers/firmware/qcom/Kconfig | 8 + drivers/firmware/qcom/Makefile | 1 + drivers/firmware/qcom/qcom_pas.c | 295 +++++++++++++++++++++++++ drivers/firmware/qcom/qcom_pas.h | 53 +++++ include/linux/firmware/qcom/qcom_pas.h | 41 ++++ 5 files changed, 398 insertions(+) create mode 100644 drivers/firmware/qcom/qcom_pas.c create mode 100644 drivers/firmware/qcom/qcom_pas.h create mode 100644 include/linux/firmware/qcom/qcom_pas.h
diff --git a/drivers/firmware/qcom/Kconfig b/drivers/firmware/qcom/Kconfig index b477d54b495a..8653639d06db 100644 --- a/drivers/firmware/qcom/Kconfig +++ b/drivers/firmware/qcom/Kconfig @@ -6,6 +6,14 @@ menu "Qualcomm firmware drivers" +config QCOM_PAS
- tristate
- help
Enable the generic Peripheral Authentication Service (PAS) providedby the firmware. It acts as the common layer with different TZbackends plugged in whether it's an SCM implementation or a properTEE bus based PAS service implementation.config QCOM_SCM select QCOM_TZMEM tristate diff --git a/drivers/firmware/qcom/Makefile b/drivers/firmware/qcom/Makefile index 0be40a1abc13..dc5ab45f906a 100644 --- a/drivers/firmware/qcom/Makefile +++ b/drivers/firmware/qcom/Makefile @@ -8,3 +8,4 @@ qcom-scm-objs += qcom_scm.o qcom_scm-smc.o qcom_scm-legacy.o obj-$(CONFIG_QCOM_TZMEM) += qcom_tzmem.o obj-$(CONFIG_QCOM_QSEECOM) += qcom_qseecom.o obj-$(CONFIG_QCOM_QSEECOM_UEFISECAPP) += qcom_qseecom_uefisecapp.o +obj-$(CONFIG_QCOM_PAS) += qcom_pas.o diff --git a/drivers/firmware/qcom/qcom_pas.c b/drivers/firmware/qcom/qcom_pas.c new file mode 100644 index 000000000000..dc04ff1b6be0 --- /dev/null +++ b/drivers/firmware/qcom/qcom_pas.c @@ -0,0 +1,295 @@ +// SPDX-License-Identifier: GPL-2.0 +/*
- Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
- */
+#include <linux/delay.h> +#include <linux/device/devres.h> +#include <linux/firmware/qcom/qcom_pas.h> +#include <linux/of.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/slab.h>
+#include "qcom_pas.h" +#include "qcom_scm.h"
+static struct qcom_pas_ops *ops_ptr;
I really dislike this singleton design. And it is not even needed! If you were storing here some allocated instance of SCM/PAS I could understand, but singleton for only ops? Just implement one driver (so SCM + whatever you have here) which will decide which ops to use, through the probe. Really, this is neither needed nor beneficial.
The motivation here is rather quite opposite to the single monolithic SCM driver design. The TZ services like PAS, ICE and so on are going to be implemented as independent discoverable devices on TEE bus which rather needs independent kernel client drivers.
You still have singleton here. So if you think you do opposite to singleton, then drop this static.
Also, the single driver probe can't work here since the SCM driver is bound to the platform bus whereas the TEE PAS driver is bound to the TEE bus. So there is a reason for the current design.
It actually leads to more problems with this barrier handling, see further comments.
The barrier handling is something that I carried over from existing implmentation but I can't see a reason why it can't be replaced with a simple mutex. See diff below for mutex.
...
+/**
- qcom_pas_shutdown() - Shut down the remote processor
- @pas_id: peripheral authentication service id
- Returns 0 on success.
- */
+int qcom_pas_shutdown(u32 pas_id) +{
- if (ops_ptr)
return ops_ptr->shutdown(ops_ptr->dev, pas_id);- return -ENODEV;
+} +EXPORT_SYMBOL_GPL(qcom_pas_shutdown);
+/**
- qcom_pas_supported() - Check if the peripheral authentication service is
available for the given peripheral
- @pas_id: peripheral authentication service id
- Returns true if PAS is supported for this peripheral, otherwise false.
- */
+bool qcom_pas_supported(u32 pas_id) +{
- if (ops_ptr)
Lack of barriers here is not looking right. Existing/old code is not a good example, I fixed only the obvious issue, but new code should be correct from the beginning.
Barriers should normally be always paired, unless you have some clear path no concurrent execution can happen here, but such explanation is missing, look:
Actually concurrent execution is rather required here since TZ can support parallel bring-up of co-processors. The synchonization is only needed when PAS client drivers are performing a deferred probe waiting for the service to be available. However, you are right explanation is missing here which I will add in the next version.
Hm? Existing comments are completely useless. Your comment said just "barrier" basically... That's nothing useful.
Best regards, Krzysztof
On Mon, Mar 09, 2026 at 08:10:02AM +0100, Krzysztof Kozlowski wrote:
On 09/03/2026 05:55, Sumit Garg wrote:
On Fri, Mar 06, 2026 at 12:15:01PM +0100, Krzysztof Kozlowski wrote:
On 06/03/2026 11:50, Sumit Garg wrote:
From: Sumit Garg sumit.garg@oss.qualcomm.com
Qcom platforms has the legacy of using non-standard SCM calls splintered over the various kernel drivers. These SCM calls aren't compliant with the standard SMC calling conventions which is a prerequisite to enable migration to the FF-A specifications from Arm.
OP-TEE as an alternative trusted OS to QTEE can't support these non- standard SCM calls. And even for newer architectures QTEE won't be able to support SCM calls either with FF-A requirements coming in. And with both OP-TEE and QTEE drivers well integrated in the TEE subsystem, it makes further sense to reuse the TEE bus client drivers infrastructure.
The added benefit of TEE bus infrastructure is that there is support for discoverable/enumerable services. With that client drivers don't have to manually invoke a special SCM call to know the service status.
So enable the generic Peripheral Authentication Service (PAS) provided by the firmware. It acts as the common layer with different TZ backends plugged in whether it's an SCM implementation or a proper TEE bus based PAS service implementation.
Signed-off-by: Sumit Garg sumit.garg@oss.qualcomm.com
drivers/firmware/qcom/Kconfig | 8 + drivers/firmware/qcom/Makefile | 1 + drivers/firmware/qcom/qcom_pas.c | 295 +++++++++++++++++++++++++ drivers/firmware/qcom/qcom_pas.h | 53 +++++ include/linux/firmware/qcom/qcom_pas.h | 41 ++++ 5 files changed, 398 insertions(+) create mode 100644 drivers/firmware/qcom/qcom_pas.c create mode 100644 drivers/firmware/qcom/qcom_pas.h create mode 100644 include/linux/firmware/qcom/qcom_pas.h
diff --git a/drivers/firmware/qcom/Kconfig b/drivers/firmware/qcom/Kconfig index b477d54b495a..8653639d06db 100644 --- a/drivers/firmware/qcom/Kconfig +++ b/drivers/firmware/qcom/Kconfig @@ -6,6 +6,14 @@ menu "Qualcomm firmware drivers" +config QCOM_PAS
- tristate
- help
Enable the generic Peripheral Authentication Service (PAS) providedby the firmware. It acts as the common layer with different TZbackends plugged in whether it's an SCM implementation or a properTEE bus based PAS service implementation.config QCOM_SCM select QCOM_TZMEM tristate diff --git a/drivers/firmware/qcom/Makefile b/drivers/firmware/qcom/Makefile index 0be40a1abc13..dc5ab45f906a 100644 --- a/drivers/firmware/qcom/Makefile +++ b/drivers/firmware/qcom/Makefile @@ -8,3 +8,4 @@ qcom-scm-objs += qcom_scm.o qcom_scm-smc.o qcom_scm-legacy.o obj-$(CONFIG_QCOM_TZMEM) += qcom_tzmem.o obj-$(CONFIG_QCOM_QSEECOM) += qcom_qseecom.o obj-$(CONFIG_QCOM_QSEECOM_UEFISECAPP) += qcom_qseecom_uefisecapp.o +obj-$(CONFIG_QCOM_PAS) += qcom_pas.o diff --git a/drivers/firmware/qcom/qcom_pas.c b/drivers/firmware/qcom/qcom_pas.c new file mode 100644 index 000000000000..dc04ff1b6be0 --- /dev/null +++ b/drivers/firmware/qcom/qcom_pas.c @@ -0,0 +1,295 @@ +// SPDX-License-Identifier: GPL-2.0 +/*
- Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
- */
+#include <linux/delay.h> +#include <linux/device/devres.h> +#include <linux/firmware/qcom/qcom_pas.h> +#include <linux/of.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/slab.h>
+#include "qcom_pas.h" +#include "qcom_scm.h"
+static struct qcom_pas_ops *ops_ptr;
I really dislike this singleton design. And it is not even needed! If you were storing here some allocated instance of SCM/PAS I could understand, but singleton for only ops? Just implement one driver (so SCM + whatever you have here) which will decide which ops to use, through the probe. Really, this is neither needed nor beneficial.
The motivation here is rather quite opposite to the single monolithic SCM driver design. The TZ services like PAS, ICE and so on are going to be implemented as independent discoverable devices on TEE bus which rather needs independent kernel client drivers.
You still have singleton here. So if you think you do opposite to singleton, then drop this static.
Sure.
Also, the single driver probe can't work here since the SCM driver is bound to the platform bus whereas the TEE PAS driver is bound to the TEE bus. So there is a reason for the current design.
It actually leads to more problems with this barrier handling, see further comments.
The barrier handling is something that I carried over from existing implmentation but I can't see a reason why it can't be replaced with a simple mutex. See diff below for mutex.
...
+/**
- qcom_pas_shutdown() - Shut down the remote processor
- @pas_id: peripheral authentication service id
- Returns 0 on success.
- */
+int qcom_pas_shutdown(u32 pas_id) +{
- if (ops_ptr)
return ops_ptr->shutdown(ops_ptr->dev, pas_id);- return -ENODEV;
+} +EXPORT_SYMBOL_GPL(qcom_pas_shutdown);
+/**
- qcom_pas_supported() - Check if the peripheral authentication service is
available for the given peripheral
- @pas_id: peripheral authentication service id
- Returns true if PAS is supported for this peripheral, otherwise false.
- */
+bool qcom_pas_supported(u32 pas_id) +{
- if (ops_ptr)
Lack of barriers here is not looking right. Existing/old code is not a good example, I fixed only the obvious issue, but new code should be correct from the beginning.
Barriers should normally be always paired, unless you have some clear path no concurrent execution can happen here, but such explanation is missing, look:
Actually concurrent execution is rather required here since TZ can support parallel bring-up of co-processors. The synchonization is only needed when PAS client drivers are performing a deferred probe waiting for the service to be available. However, you are right explanation is missing here which I will add in the next version.
Hm? Existing comments are completely useless. Your comment said just "barrier" basically... That's nothing useful.
Agree, following is something I plan for v2 (using mutex instead of a barrier):
/* * The ops mutex here is only intended to synchronize when client drivers * are in parallel checking for PAS service availability. However, once the * PAS backend becomes available, it is allowed for multiple threads to enter * TZ for parallel bringup of co-processors during boot. */ static DEFINE_MUTEX(ops_mutex);
-Sumit
On Mon, Mar 09, 2026 at 12:46:43PM +0530, Sumit Garg wrote:
On Mon, Mar 09, 2026 at 08:10:02AM +0100, Krzysztof Kozlowski wrote:
On 09/03/2026 05:55, Sumit Garg wrote:
On Fri, Mar 06, 2026 at 12:15:01PM +0100, Krzysztof Kozlowski wrote:
On 06/03/2026 11:50, Sumit Garg wrote:
From: Sumit Garg sumit.garg@oss.qualcomm.com
Qcom platforms has the legacy of using non-standard SCM calls splintered over the various kernel drivers. These SCM calls aren't compliant with the standard SMC calling conventions which is a prerequisite to enable migration to the FF-A specifications from Arm.
OP-TEE as an alternative trusted OS to QTEE can't support these non- standard SCM calls. And even for newer architectures QTEE won't be able to support SCM calls either with FF-A requirements coming in. And with both OP-TEE and QTEE drivers well integrated in the TEE subsystem, it makes further sense to reuse the TEE bus client drivers infrastructure.
The added benefit of TEE bus infrastructure is that there is support for discoverable/enumerable services. With that client drivers don't have to manually invoke a special SCM call to know the service status.
So enable the generic Peripheral Authentication Service (PAS) provided by the firmware. It acts as the common layer with different TZ backends plugged in whether it's an SCM implementation or a proper TEE bus based PAS service implementation.
Signed-off-by: Sumit Garg sumit.garg@oss.qualcomm.com
drivers/firmware/qcom/Kconfig | 8 + drivers/firmware/qcom/Makefile | 1 + drivers/firmware/qcom/qcom_pas.c | 295 +++++++++++++++++++++++++ drivers/firmware/qcom/qcom_pas.h | 53 +++++ include/linux/firmware/qcom/qcom_pas.h | 41 ++++ 5 files changed, 398 insertions(+) create mode 100644 drivers/firmware/qcom/qcom_pas.c create mode 100644 drivers/firmware/qcom/qcom_pas.h create mode 100644 include/linux/firmware/qcom/qcom_pas.h
diff --git a/drivers/firmware/qcom/Kconfig b/drivers/firmware/qcom/Kconfig index b477d54b495a..8653639d06db 100644 --- a/drivers/firmware/qcom/Kconfig +++ b/drivers/firmware/qcom/Kconfig @@ -6,6 +6,14 @@ menu "Qualcomm firmware drivers" +config QCOM_PAS
- tristate
- help
Enable the generic Peripheral Authentication Service (PAS) providedby the firmware. It acts as the common layer with different TZbackends plugged in whether it's an SCM implementation or a properTEE bus based PAS service implementation.config QCOM_SCM select QCOM_TZMEM tristate diff --git a/drivers/firmware/qcom/Makefile b/drivers/firmware/qcom/Makefile index 0be40a1abc13..dc5ab45f906a 100644 --- a/drivers/firmware/qcom/Makefile +++ b/drivers/firmware/qcom/Makefile @@ -8,3 +8,4 @@ qcom-scm-objs += qcom_scm.o qcom_scm-smc.o qcom_scm-legacy.o obj-$(CONFIG_QCOM_TZMEM) += qcom_tzmem.o obj-$(CONFIG_QCOM_QSEECOM) += qcom_qseecom.o obj-$(CONFIG_QCOM_QSEECOM_UEFISECAPP) += qcom_qseecom_uefisecapp.o +obj-$(CONFIG_QCOM_PAS) += qcom_pas.o diff --git a/drivers/firmware/qcom/qcom_pas.c b/drivers/firmware/qcom/qcom_pas.c new file mode 100644 index 000000000000..dc04ff1b6be0 --- /dev/null +++ b/drivers/firmware/qcom/qcom_pas.c @@ -0,0 +1,295 @@ +// SPDX-License-Identifier: GPL-2.0 +/*
- Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
- */
+#include <linux/delay.h> +#include <linux/device/devres.h> +#include <linux/firmware/qcom/qcom_pas.h> +#include <linux/of.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/slab.h>
+#include "qcom_pas.h" +#include "qcom_scm.h"
+static struct qcom_pas_ops *ops_ptr;
I really dislike this singleton design. And it is not even needed! If you were storing here some allocated instance of SCM/PAS I could understand, but singleton for only ops? Just implement one driver (so SCM + whatever you have here) which will decide which ops to use, through the probe. Really, this is neither needed nor beneficial.
The motivation here is rather quite opposite to the single monolithic SCM driver design. The TZ services like PAS, ICE and so on are going to be implemented as independent discoverable devices on TEE bus which rather needs independent kernel client drivers.
You still have singleton here. So if you think you do opposite to singleton, then drop this static.
Sure.
Also, the single driver probe can't work here since the SCM driver is bound to the platform bus whereas the TEE PAS driver is bound to the TEE bus. So there is a reason for the current design.
It actually leads to more problems with this barrier handling, see further comments.
The barrier handling is something that I carried over from existing implmentation but I can't see a reason why it can't be replaced with a simple mutex. See diff below for mutex.
...
+/**
- qcom_pas_shutdown() - Shut down the remote processor
- @pas_id: peripheral authentication service id
- Returns 0 on success.
- */
+int qcom_pas_shutdown(u32 pas_id) +{
- if (ops_ptr)
return ops_ptr->shutdown(ops_ptr->dev, pas_id);- return -ENODEV;
+} +EXPORT_SYMBOL_GPL(qcom_pas_shutdown);
+/**
- qcom_pas_supported() - Check if the peripheral authentication service is
available for the given peripheral
- @pas_id: peripheral authentication service id
- Returns true if PAS is supported for this peripheral, otherwise false.
- */
+bool qcom_pas_supported(u32 pas_id) +{
- if (ops_ptr)
Lack of barriers here is not looking right. Existing/old code is not a good example, I fixed only the obvious issue, but new code should be correct from the beginning.
Barriers should normally be always paired, unless you have some clear path no concurrent execution can happen here, but such explanation is missing, look:
Actually concurrent execution is rather required here since TZ can support parallel bring-up of co-processors. The synchonization is only needed when PAS client drivers are performing a deferred probe waiting for the service to be available. However, you are right explanation is missing here which I will add in the next version.
Hm? Existing comments are completely useless. Your comment said just "barrier" basically... That's nothing useful.
Agree, following is something I plan for v2 (using mutex instead of a barrier):
/*
- The ops mutex here is only intended to synchronize when client drivers
- are in parallel checking for PAS service availability. However, once the
- PAS backend becomes available, it is allowed for multiple threads to enter
- TZ for parallel bringup of co-processors during boot.
*/ static DEFINE_MUTEX(ops_mutex);
After more testing, it came out that there are corner cases where the registered ops structure writes aren't visible to other cores. So indeed a data barrier is needed instead of mutex. I will add relevant code comments.
-Sumit
On 3/6/2026 2:50 AM, Sumit Garg wrote:
drivers/firmware/qcom/Kconfig | 8 + drivers/firmware/qcom/Makefile | 1 + drivers/firmware/qcom/qcom_pas.c | 295 +++++++++++++++++++++++++
kernel-doc is throwing some warnings in this file which I've listed below. kernel-doc is also throwing warnings in some of the other files touched by this series, but since those are presumably preexisting I didn't bother to mention them. Just want to avoid adding new warnings.
drivers/firmware/qcom/qcom_pas.h | 53 +++++ include/linux/firmware/qcom/qcom_pas.h | 41 ++++ 5 files changed, 398 insertions(+) create mode 100644 drivers/firmware/qcom/qcom_pas.c create mode 100644 drivers/firmware/qcom/qcom_pas.h create mode 100644 include/linux/firmware/qcom/qcom_pas.h
...
+/**
- qcom_pas_mem_setup() - Prepare the memory related to a given peripheral
for firmware loading
- @pas_id: peripheral authentication service id
- @addr: start address of memory area to prepare
- @size: size of the memory area to prepare
- Returns 0 on success.
kernel-doc complains: Warning: drivers/firmware/qcom/qcom_pas.c:103 No description found for return value of 'qcom_pas_mem_setup'
should use the kernel-doc Return: tag
* Return: 0 on success
(Returns: is also accepted although not documented)
- */
...
+/**
- qcom_scm_pas_auth_and_reset() - Authenticate the given peripheral firmware
and reset the remote processor
- @pas_id: peripheral authentication service id
- Return 0 on success.
hmmm, kernel-doc didn't complain about this one so the script must accept 'Return' without the ":" (but not 'Returns' without the ":").
Suggest changing to Return: to be conformant with the actual documentation: https://www.kernel.org/doc/html/latest/doc-guide/kernel-doc.html#function-documentation
- */
+int qcom_pas_auth_and_reset(u32 pas_id) +{
- if (ops_ptr)
return ops_ptr->auth_and_reset(ops_ptr->dev, pas_id);- return -ENODEV;
+} +EXPORT_SYMBOL_GPL(qcom_pas_auth_and_reset);
...
+/**
- qcom_pas_set_remote_state() - Set the remote processor state
- @state: peripheral state
- @pas_id: peripheral authentication service id
- Returns 0 on success.
Warning: drivers/firmware/qcom/qcom_pas.c:217 No description found for return value of 'qcom_pas_set_remote_state'
- */
...
+/**
- qcom_pas_shutdown() - Shut down the remote processor
- @pas_id: peripheral authentication service id
- Returns 0 on success.
Warning: drivers/firmware/qcom/qcom_pas.c:232 No description found for return value of 'qcom_pas_shutdown'
- */
...
+/**
- qcom_pas_supported() - Check if the peripheral authentication service is
available for the given peripheral
- @pas_id: peripheral authentication service id
- Returns true if PAS is supported for this peripheral, otherwise false.
Warning: drivers/firmware/qcom/qcom_pas.c:248 No description found for return value of 'qcom_pas_supported'
- */
...
+/**
- qcom_pas_is_available() - Check for PAS service
- Returns true on success.
Warning: drivers/firmware/qcom/qcom_pas.c:262 No description found for return value of 'qcom_pas_is_available'
- */
On 3/6/2026 2:50 AM, Sumit Garg wrote:
I missed one k-doc warning...
+/**
- qcom_scm_pas_auth_and_reset() - Authenticate the given peripheral firmware
s/scm_//
Warning: drivers/firmware/qcom/qcom_pas.c:173 expecting prototype for qcom_scm_pas_auth_and_reset(). Prototype was for qcom_pas_auth_and_reset() instead
and reset the remote processor
- @pas_id: peripheral authentication service id
- Return 0 on success.
- */
+int qcom_pas_auth_and_reset(u32 pas_id) +{
- if (ops_ptr)
return ops_ptr->auth_and_reset(ops_ptr->dev, pas_id);- return -ENODEV;
+}
On Fri, Mar 06, 2026 at 07:49:07AM -0800, Jeff Johnson wrote:
On 3/6/2026 2:50 AM, Sumit Garg wrote:
I missed one k-doc warning...
+/**
- qcom_scm_pas_auth_and_reset() - Authenticate the given peripheral firmware
s/scm_//
Warning: drivers/firmware/qcom/qcom_pas.c:173 expecting prototype for qcom_scm_pas_auth_and_reset(). Prototype was for qcom_pas_auth_and_reset() instead
Thanks for the k-doc warnings report, I will fix them in the next version.
-Sumit
and reset the remote processor
- @pas_id: peripheral authentication service id
- Return 0 on success.
- */
+int qcom_pas_auth_and_reset(u32 pas_id) +{
- if (ops_ptr)
return ops_ptr->auth_and_reset(ops_ptr->dev, pas_id);- return -ENODEV;
+}
On 3/6/2026 2:50 AM, Sumit Garg wrote:
From: Sumit Garg sumit.garg@oss.qualcomm.com
Qcom platforms has the legacy of using non-standard SCM calls splintered over the various kernel drivers.
You are using multiple conflicting terminologies here. In the first statement you have used "non-standard" and immediately you have used "aren't complaint".
Which ARM document dictates that "standard" and "compliance" here? Are these SCM calls are using the vendor space per the spec, and if yes what does non-standard means here.
These SCM calls aren't
compliant with the standard SMC calling conventions which is a prerequisite to enable migration to the FF-A specifications from Arm.
OP-TEE as an alternative trusted OS to QTEE can't support these non-
What is QTEE?
standard SCM calls. And even for newer architectures QTEE won't be able
meaning of architecture please? Are you referring ARMv9.x or SOC architecture or software architecture? What does "newer" means? Is there any example available in public or are you ready to share?
to support SCM calls either with FF-A requirements coming in. And with both OP-TEE and QTEE drivers well integrated in the TEE subsystem, it makes further sense to reuse the TEE bus client drivers infrastructure.
The added benefit of TEE bus infrastructure is that there is support for discoverable/enumerable services. With that client drivers don't have to manually invoke a special SCM call to know the service status.
So enable the generic Peripheral Authentication Service (PAS) provided by the firmware. It acts as the common layer with different TZ backends plugged in whether it's an SCM implementation or a proper TEE bus based PAS service implementation.
I haven't checked cover letter in detail, but did you tested these patches w/ the devices which doesn't support these new facilities?
Signed-off-by: Sumit Garg sumit.garg@oss.qualcomm.com
drivers/firmware/qcom/Kconfig | 8 + drivers/firmware/qcom/Makefile | 1 + drivers/firmware/qcom/qcom_pas.c | 295 +++++++++++++++++++++++++ drivers/firmware/qcom/qcom_pas.h | 53 +++++ include/linux/firmware/qcom/qcom_pas.h | 41 ++++ 5 files changed, 398 insertions(+) create mode 100644 drivers/firmware/qcom/qcom_pas.c create mode 100644 drivers/firmware/qcom/qcom_pas.h create mode 100644 include/linux/firmware/qcom/qcom_pas.h
diff --git a/drivers/firmware/qcom/Kconfig b/drivers/firmware/qcom/Kconfig index b477d54b495a..8653639d06db 100644 --- a/drivers/firmware/qcom/Kconfig +++ b/drivers/firmware/qcom/Kconfig @@ -6,6 +6,14 @@ menu "Qualcomm firmware drivers" +config QCOM_PAS
- tristate
- help
Enable the generic Peripheral Authentication Service (PAS) providedby the firmware. It acts as the common layer with different TZbackends plugged in whether it's an SCM implementation or a properTEE bus based PAS service implementation.config QCOM_SCM select QCOM_TZMEM tristate diff --git a/drivers/firmware/qcom/Makefile b/drivers/firmware/qcom/Makefile index 0be40a1abc13..dc5ab45f906a 100644 --- a/drivers/firmware/qcom/Makefile +++ b/drivers/firmware/qcom/Makefile @@ -8,3 +8,4 @@ qcom-scm-objs += qcom_scm.o qcom_scm-smc.o qcom_scm-legacy.o obj-$(CONFIG_QCOM_TZMEM) += qcom_tzmem.o obj-$(CONFIG_QCOM_QSEECOM) += qcom_qseecom.o obj-$(CONFIG_QCOM_QSEECOM_UEFISECAPP) += qcom_qseecom_uefisecapp.o +obj-$(CONFIG_QCOM_PAS) += qcom_pas.o diff --git a/drivers/firmware/qcom/qcom_pas.c b/drivers/firmware/qcom/qcom_pas.c new file mode 100644 index 000000000000..dc04ff1b6be0 --- /dev/null +++ b/drivers/firmware/qcom/qcom_pas.c @@ -0,0 +1,295 @@ +// SPDX-License-Identifier: GPL-2.0 +/*
- Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
- */
+#include <linux/delay.h> +#include <linux/device/devres.h> +#include <linux/firmware/qcom/qcom_pas.h> +#include <linux/of.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/slab.h>
are you sure you are using functionalities from these header files?
I couldn't find slab.h usage quickly and also qcom_scm.h. Can you please confirm?
+#include "qcom_pas.h" +#include "qcom_scm.h"
+static struct qcom_pas_ops *ops_ptr;
+/**
- devm_qcom_pas_context_alloc() - Allocate peripheral authentication service
context for a given peripheral
- PAS context is device-resource managed, so the caller does not need
- to worry about freeing the context memory.
- @dev: PAS firmware device
- @pas_id: peripheral authentication service id
- @mem_phys: Subsystem reserve memory start address
- @mem_size: Subsystem reserve memory size
- Returns: The new PAS context, or ERR_PTR() on failure.
- */
+struct qcom_pas_context *devm_qcom_pas_context_alloc(struct device *dev,
u32 pas_id,phys_addr_t mem_phys,size_t mem_size)+{
- struct qcom_pas_context *ctx;
- ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
- if (!ctx)
return ERR_PTR(-ENOMEM);- ctx->dev = dev;
- ctx->pas_id = pas_id;
- ctx->mem_phys = mem_phys;
- ctx->mem_size = mem_size;
- return ctx;
+} +EXPORT_SYMBOL_GPL(devm_qcom_pas_context_alloc);
+/**
- qcom_pas_init_image() - Initialize peripheral authentication service state
machine for a given peripheral, using the metadata
- @pas_id: peripheral authentication service 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 pas 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_pas_metadata_release() by the caller.
- */
+int qcom_pas_init_image(u32 pas_id, const void *metadata, size_t size,
struct qcom_pas_context *ctx)+{
- if (ops_ptr)
return ops_ptr->init_image(ops_ptr->dev, pas_id,metadata, size, ctx);- return -ENODEV;
+} +EXPORT_SYMBOL_GPL(qcom_pas_init_image);
+/**
- qcom_pas_metadata_release() - release metadata context
- @ctx: pas context
- */
+void qcom_pas_metadata_release(struct qcom_pas_context *ctx) +{
- if (!ctx || !ctx->ptr)
return;- if (ops_ptr)
ops_ptr->metadata_release(ops_ptr->dev, ctx);+} +EXPORT_SYMBOL_GPL(qcom_pas_metadata_release);
+/**
- qcom_pas_mem_setup() - Prepare the memory related to a given peripheral
for firmware loading
- @pas_id: peripheral authentication service id
- @addr: start address of memory area to prepare
- @size: size of the memory area to prepare
- Returns 0 on success.
- */
+int qcom_pas_mem_setup(u32 pas_id, phys_addr_t addr, phys_addr_t size) +{
- if (ops_ptr)
return ops_ptr->mem_setup(ops_ptr->dev, pas_id, addr, size);- return -ENODEV;
+} +EXPORT_SYMBOL_GPL(qcom_pas_mem_setup);
+/**
- qcom_pas_get_rsc_table() - Retrieve the resource table in passed output buffer
for a given peripheral.
- Qualcomm remote processor may rely on both static and dynamic resources for
- its functionality. Static resources typically refer to memory-mapped
- addresses required by the subsystem and are often embedded within the
- firmware binary and dynamic resources, such as shared memory in DDR etc.,
- are determined at runtime during the boot process.
- On Qualcomm Technologies devices, it's possible that static resources are
- not embedded in the firmware binary and instead are provided by TrustZone.
- However, dynamic resources are always expected to come from TrustZone. This
Is it confirmed that it will always come from Trustzone? Is it not possible that it can come from trusted controller - bypassing the trustzone? Assuming that such controller is never modified by anyone else including final device makers and blessed by the trust boundaries.
Is this design going to scale if we put the MCU doing the heavy lifting instead?
- indicates that for Qualcomm devices, all resources (static and dynamic) will
- be provided by TrustZone PAS service.
- If the remote processor firmware binary does contain static resources, they
- should be passed in input_rt. These will be forwarded to TrustZone for
- authentication. TrustZone will then append the dynamic resources and return
- the complete resource table in output_rt_tzm.
- If the remote processor firmware binary does not include a resource table,
- the caller of this function should set input_rt as NULL and input_rt_size
- as zero respectively.
- More about documentation on resource table data structures can be found in
- include/linux/remoteproc.h
- @ctx: PAS context
- @pas_id: peripheral authentication service id
- @input_rt: resource table buffer which is present in firmware binary
- @input_rt_size: size of the resource table present in firmware binary
- @output_rt_size: TrustZone expects caller should pass worst case size for
the output_rt_tzm.
- Return:
- On success, returns a pointer to the allocated buffer containing the final
- resource table and output_rt_size will have actual resource table size from
- TrustZone. The caller is responsible for freeing the buffer. On failure,
- returns ERR_PTR(-errno).
- */
+struct resource_table *qcom_pas_get_rsc_table(struct qcom_pas_context *ctx,
void *input_rt,size_t input_rt_size,size_t *output_rt_size)+{
- if (ops_ptr)
return ops_ptr->get_rsc_table(ops_ptr->dev, ctx, input_rt,input_rt_size, output_rt_size);- return ERR_PTR(-ENODEV);
+} +EXPORT_SYMBOL_GPL(qcom_pas_get_rsc_table);
+/**
- qcom_scm_pas_auth_and_reset() - Authenticate the given peripheral firmware
and reset the remote processor
- @pas_id: peripheral authentication service id
- Return 0 on success.
- */
+int qcom_pas_auth_and_reset(u32 pas_id) +{
- if (ops_ptr)
return ops_ptr->auth_and_reset(ops_ptr->dev, pas_id);- return -ENODEV;
+} +EXPORT_SYMBOL_GPL(qcom_pas_auth_and_reset);
+/**
- qcom_pas_prepare_and_auth_reset() - Prepare, authenticate, and reset the
remote processor
- @ctx: Context saved during call to qcom_scm_pas_context_init()
- This function performs the necessary steps to prepare a PAS subsystem,
- authenticate it using the provided metadata, and initiate a reset sequence.
- It should be used when Linux is in control setting up the IOMMU hardware
- for remote subsystem during secure firmware loading processes. The
- preparation step sets up a shmbridge over the firmware memory before
- TrustZone accesses the firmware memory region for authentication. The
- authentication step verifies the integrity and authenticity of the firmware
- or configuration using secure metadata. Finally, the reset step ensures the
- subsystem starts in a clean and sane state.
- Return: 0 on success, negative errno on failure.
- */
+int qcom_pas_prepare_and_auth_reset(struct qcom_pas_context *ctx) +{
- if (ops_ptr)
return ops_ptr->prepare_and_auth_reset(ops_ptr->dev, ctx);- return -ENODEV;
+} +EXPORT_SYMBOL_GPL(qcom_pas_prepare_and_auth_reset);
+/**
- qcom_pas_set_remote_state() - Set the remote processor state
- @state: peripheral state
- @pas_id: peripheral authentication service id
- Returns 0 on success.
- */
+int qcom_pas_set_remote_state(u32 state, u32 pas_id) +{
- if (ops_ptr)
return ops_ptr->set_remote_state(ops_ptr->dev, state, pas_id);- return -ENODEV;
+} +EXPORT_SYMBOL_GPL(qcom_pas_set_remote_state);
+/**
- qcom_pas_shutdown() - Shut down the remote processor
- @pas_id: peripheral authentication service id
- Returns 0 on success.
- */
+int qcom_pas_shutdown(u32 pas_id) +{
- if (ops_ptr)
return ops_ptr->shutdown(ops_ptr->dev, pas_id);- return -ENODEV;
+} +EXPORT_SYMBOL_GPL(qcom_pas_shutdown);
+/**
- qcom_pas_supported() - Check if the peripheral authentication service is
available for the given peripheral
- @pas_id: peripheral authentication service id
- Returns true if PAS is supported for this peripheral, otherwise false.
- */
+bool qcom_pas_supported(u32 pas_id) +{
- if (ops_ptr)
return ops_ptr->supported(ops_ptr->dev, pas_id);- return false;
+} +EXPORT_SYMBOL_GPL(qcom_pas_supported);
+/**
- qcom_pas_is_available() - Check for PAS service
- Returns true on success.
- */
+bool qcom_pas_is_available(void) +{
- /* The barrier is needed to synchronize with client drivers. */
- return !!smp_load_acquire(&ops_ptr);
+} +EXPORT_SYMBOL_GPL(qcom_pas_is_available);
+/**
- qcom_pas_ops_register() - Register PAS service ops
- @ops: PAS service ops pointer
- */
+void qcom_pas_ops_register(struct qcom_pas_ops *ops) +{
- if (!qcom_pas_is_available())
/* The barrier is needed to synchronize with client drivers. */smp_store_release(&ops_ptr, ops);- else
pr_err("qcom_pas: ops already registered\n");+} +EXPORT_SYMBOL_GPL(qcom_pas_ops_register);
+/**
- qcom_pas_ops_unregister() - Unregister PAS service ops
- */
+void qcom_pas_ops_unregister(void) +{
- /* The barrier is needed to synchronize with client drivers. */
- smp_store_release(&ops_ptr, NULL);
+} +EXPORT_SYMBOL_GPL(qcom_pas_ops_unregister);
+MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Sumit Garg sumit.garg@oss.qualcomm.com");
What is the convention for Qualcomm authored drivers? In some drivers I find that Qualcomm doesn't add MODULE_AUTHOR. Can Qualcomm community clarify it here. I prefer consistency here for the Qualcomm submissions.
+MODULE_DESCRIPTION("Qualcomm common TZ PAS driver"); diff --git a/drivers/firmware/qcom/qcom_pas.h b/drivers/firmware/qcom/qcom_pas.h new file mode 100644 index 000000000000..4ebed22178f8 --- /dev/null +++ b/drivers/firmware/qcom/qcom_pas.h @@ -0,0 +1,53 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/*
- Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
- */
+#ifndef __QCOM_PAS_INT_H +#define __QCOM_PAS_INT_H
+struct device;
+/**
- struct qcom_pas_ops - Qcom Peripheral Authentication Service (PAS) ops
- @drv_name: PAS driver name.
- @dev: PAS device pointer.
- @supported: Peripheral supported callback.
- @init_image: Peripheral image initialization callback.
- @mem_setup: Peripheral memory setup callback.
- @get_rsc_table: Peripheral get resource table callback.
- @prepare_and_auth_reset: Peripheral prepare firmware authentication and
reset callback.
- @auth_and_reset: Peripheral firmware authentication and reset
callback.
- @set_remote_state: Peripheral set remote state callback.
- @shutdown: Peripheral shutdown callback.
- @metadata_release: Image metadata release callback.
- */
+struct qcom_pas_ops {
- const char *drv_name;
- struct device *dev;
- bool (*supported)(struct device *dev, u32 pas_id);
- int (*init_image)(struct device *dev, u32 pas_id,
const void *metadata, size_t size,struct qcom_pas_context *ctx);- int (*mem_setup)(struct device *dev, u32 pas_id,
phys_addr_t addr, phys_addr_t size);- void *(*get_rsc_table)(struct device *dev,
struct qcom_pas_context *ctx,void *input_rt,size_t input_rt_size,size_t *output_rt_size);
void * or resource_table * as return?
- int (*prepare_and_auth_reset)(struct device *dev,
struct qcom_pas_context *ctx);- int (*auth_and_reset)(struct device *dev, u32 pas_id);
- int (*set_remote_state)(struct device *dev, u32 state, u32 pas_id);
- int (*shutdown)(struct device *dev, u32 pas_id);
- void (*metadata_release)(struct device *dev,
struct qcom_pas_context *ctx);+};
+void qcom_pas_ops_register(struct qcom_pas_ops *ops); +void qcom_pas_ops_unregister(void);
+#endif /* __QCOM_PAS_INT_H */ diff --git a/include/linux/firmware/qcom/qcom_pas.h b/include/linux/firmware/qcom/qcom_pas.h new file mode 100644 index 000000000000..ef7328ecfa47 --- /dev/null +++ b/include/linux/firmware/qcom/qcom_pas.h @@ -0,0 +1,41 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/*
- Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
- */
+#ifndef __QCOM_PAS_H +#define __QCOM_PAS_H
+#include <linux/err.h> +#include <linux/types.h>
+struct qcom_pas_context {
- struct device *dev;
- u32 pas_id;
- phys_addr_t mem_phys;
- size_t mem_size;
- void *ptr;
- dma_addr_t phys;
- ssize_t size;
- bool use_tzmem;
+};
+bool qcom_pas_is_available(void); +struct qcom_pas_context *devm_qcom_pas_context_alloc(struct device *dev,
u32 pas_id,phys_addr_t mem_phys,size_t mem_size);+int qcom_pas_init_image(u32 pas_id, const void *metadata, size_t size,
struct qcom_pas_context *ctx);+struct resource_table *qcom_pas_get_rsc_table(struct qcom_pas_context *ctx,
void *input_rt, size_t input_rt_size,size_t *output_rt_size);+int qcom_pas_mem_setup(u32 pas_id, phys_addr_t addr, phys_addr_t size); +int qcom_pas_auth_and_reset(u32 pas_id); +int qcom_pas_prepare_and_auth_reset(struct qcom_pas_context *ctx); +int qcom_pas_set_remote_state(u32 state, u32 pas_id); +int qcom_pas_shutdown(u32 pas_id); +bool qcom_pas_supported(u32 pas_id); +void qcom_pas_metadata_release(struct qcom_pas_context *ctx);
+#endif /* __QCOM_PAS_H */
On 3/6/2026 11:47 AM, Trilok Soni wrote:
diff --git a/drivers/firmware/qcom/qcom_pas.c b/drivers/firmware/qcom/qcom_pas.c new file mode 100644 index 000000000000..dc04ff1b6be0 --- /dev/null +++ b/drivers/firmware/qcom/qcom_pas.c @@ -0,0 +1,295 @@ +// SPDX-License-Identifier: GPL-2.0 +/*
- Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
- */
+#include <linux/delay.h> +#include <linux/device/devres.h> +#include <linux/firmware/qcom/qcom_pas.h> +#include <linux/of.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/slab.h>
are you sure you are using functionalities from these header files?
I couldn't find slab.h usage quickly and also qcom_scm.h. Can you please confirm?
I scrolled this patch too fast. I can see slab.h usage, but not sure about qcom_scm.h.
On 3/6/2026 11:47 AM, Trilok Soni wrote:
On 3/6/2026 2:50 AM, Sumit Garg wrote:
+MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Sumit Garg sumit.garg@oss.qualcomm.com");
What is the convention for Qualcomm authored drivers? In some drivers I find that Qualcomm doesn't add MODULE_AUTHOR. Can Qualcomm community clarify it here. I prefer consistency here for the Qualcomm submissions.
WLAN team was told to not have MODULE_AUTHOR(), so ath10k was the last WLAN driver that had a MODULE_AUTHOR() -- ath11k and ath12k do not have one.
And in reality it is very rare for a given module, over time, to only have a single author. The git history contains the real authorship. So just for that reason I'd drop it.
/jeff
On 3/6/2026 2:00 PM, Jeff Johnson wrote:
On 3/6/2026 11:47 AM, Trilok Soni wrote:
On 3/6/2026 2:50 AM, Sumit Garg wrote:
+MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Sumit Garg sumit.garg@oss.qualcomm.com");
What is the convention for Qualcomm authored drivers? In some drivers I find that Qualcomm doesn't add MODULE_AUTHOR. Can Qualcomm community clarify it here. I prefer consistency here for the Qualcomm submissions.
WLAN team was told to not have MODULE_AUTHOR(), so ath10k was the last WLAN driver that had a MODULE_AUTHOR() -- ath11k and ath12k do not have one.
And in reality it is very rare for a given module, over time, to only have a single author. The git history contains the real authorship. So just for that reason I'd drop it.
I agree and that is the same guideline I follow for the drivers we write downstream. I just want to make sure that we discuss it here. We may not be able to find one single solution, but I prefer to get consistency for Qualcomm submissions.
---Trilok Soni
On Fri, Mar 06, 2026 at 02:00:48PM -0800, Jeff Johnson wrote:
On 3/6/2026 11:47 AM, Trilok Soni wrote:
On 3/6/2026 2:50 AM, Sumit Garg wrote:
+MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Sumit Garg sumit.garg@oss.qualcomm.com");
What is the convention for Qualcomm authored drivers? In some drivers I find that Qualcomm doesn't add MODULE_AUTHOR. Can Qualcomm community clarify it here. I prefer consistency here for the Qualcomm submissions.
WLAN team was told to not have MODULE_AUTHOR(), so ath10k was the last WLAN driver that had a MODULE_AUTHOR() -- ath11k and ath12k do not have one.
As I said in my other reply, it is quite subsystem specific.
And in reality it is very rare for a given module, over time, to only have a single author. The git history contains the real authorship. So just for that reason I'd drop it.
Sure, but you would like the driver author to be involved in future maintenence of the driver. In my experience that's how usually the kernel development process works. If a separate maintainer's entry is fine then I can switch to that instead.
-Sumit
On 3/8/2026 11:36 PM, Sumit Garg wrote:
On Fri, Mar 06, 2026 at 02:00:48PM -0800, Jeff Johnson wrote:
On 3/6/2026 11:47 AM, Trilok Soni wrote:
On 3/6/2026 2:50 AM, Sumit Garg wrote:
+MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Sumit Garg sumit.garg@oss.qualcomm.com");
What is the convention for Qualcomm authored drivers? In some drivers I find that Qualcomm doesn't add MODULE_AUTHOR. Can Qualcomm community clarify it here. I prefer consistency here for the Qualcomm submissions.
WLAN team was told to not have MODULE_AUTHOR(), so ath10k was the last WLAN driver that had a MODULE_AUTHOR() -- ath11k and ath12k do not have one.
As I said in my other reply, it is quite subsystem specific.
And in reality it is very rare for a given module, over time, to only have a single author. The git history contains the real authorship. So just for that reason I'd drop it.
Sure, but you would like the driver author to be involved in future maintenence of the driver. In my experience that's how usually the kernel development process works. If a separate maintainer's entry is fine then I can switch to that instead.
I would prefer the maintainers entry than MODULE_AUTHOR.
---Trilok Soni
On Fri, Mar 06, 2026 at 11:47:55AM -0800, Trilok Soni wrote:
On 3/6/2026 2:50 AM, Sumit Garg wrote:
From: Sumit Garg sumit.garg@oss.qualcomm.com
Qcom platforms has the legacy of using non-standard SCM calls splintered over the various kernel drivers.
You are using multiple conflicting terminologies here. In the first statement you have used "non-standard" and immediately you have used "aren't complaint".
Here non-standard means the SCM calls aren't compliant with SMCCC specifications here [1].
Which ARM document dictates that "standard" and "compliance" here?
It's SMCCC spec here [1].
Are these SCM calls are using the vendor space per the spec, and if yes what does non-standard means here.
See detailed explanation of non-standard SCM calls as part of OP-TEE review here [2].
[1] https://developer.arm.com/documentation/den0028/latest/ [2] https://github.com/OP-TEE/optee_os/pull/7311#discussion_r2106654868
These SCM calls aren't
compliant with the standard SMC calling conventions which is a prerequisite to enable migration to the FF-A specifications from Arm.
OP-TEE as an alternative trusted OS to QTEE can't support these non-
What is QTEE?
Okay, I can expand that to Qualcomm TEE.
standard SCM calls. And even for newer architectures QTEE won't be able
meaning of architecture please? Are you referring ARMv9.x or SOC architecture or software architecture? What does "newer" means? Is there any example available in public or are you ready to share?
Okay, I should have mentioned newer architectures with SEL2 and Hafnium support where FF-A is only going to be the supported communication method.
to support SCM calls either with FF-A requirements coming in. And with both OP-TEE and QTEE drivers well integrated in the TEE subsystem, it makes further sense to reuse the TEE bus client drivers infrastructure.
The added benefit of TEE bus infrastructure is that there is support for discoverable/enumerable services. With that client drivers don't have to manually invoke a special SCM call to know the service status.
So enable the generic Peripheral Authentication Service (PAS) provided by the firmware. It acts as the common layer with different TZ backends plugged in whether it's an SCM implementation or a proper TEE bus based PAS service implementation.
I haven't checked cover letter in detail, but did you tested these patches w/ the devices which doesn't support these new facilities?
Yeah, the patch-set has been tested to be backwards compatible with SCM APIs too.
Signed-off-by: Sumit Garg sumit.garg@oss.qualcomm.com
drivers/firmware/qcom/Kconfig | 8 + drivers/firmware/qcom/Makefile | 1 + drivers/firmware/qcom/qcom_pas.c | 295 +++++++++++++++++++++++++ drivers/firmware/qcom/qcom_pas.h | 53 +++++ include/linux/firmware/qcom/qcom_pas.h | 41 ++++ 5 files changed, 398 insertions(+) create mode 100644 drivers/firmware/qcom/qcom_pas.c create mode 100644 drivers/firmware/qcom/qcom_pas.h create mode 100644 include/linux/firmware/qcom/qcom_pas.h
diff --git a/drivers/firmware/qcom/Kconfig b/drivers/firmware/qcom/Kconfig index b477d54b495a..8653639d06db 100644 --- a/drivers/firmware/qcom/Kconfig +++ b/drivers/firmware/qcom/Kconfig @@ -6,6 +6,14 @@ menu "Qualcomm firmware drivers" +config QCOM_PAS
- tristate
- help
Enable the generic Peripheral Authentication Service (PAS) providedby the firmware. It acts as the common layer with different TZbackends plugged in whether it's an SCM implementation or a properTEE bus based PAS service implementation.config QCOM_SCM select QCOM_TZMEM tristate diff --git a/drivers/firmware/qcom/Makefile b/drivers/firmware/qcom/Makefile index 0be40a1abc13..dc5ab45f906a 100644 --- a/drivers/firmware/qcom/Makefile +++ b/drivers/firmware/qcom/Makefile @@ -8,3 +8,4 @@ qcom-scm-objs += qcom_scm.o qcom_scm-smc.o qcom_scm-legacy.o obj-$(CONFIG_QCOM_TZMEM) += qcom_tzmem.o obj-$(CONFIG_QCOM_QSEECOM) += qcom_qseecom.o obj-$(CONFIG_QCOM_QSEECOM_UEFISECAPP) += qcom_qseecom_uefisecapp.o +obj-$(CONFIG_QCOM_PAS) += qcom_pas.o diff --git a/drivers/firmware/qcom/qcom_pas.c b/drivers/firmware/qcom/qcom_pas.c new file mode 100644 index 000000000000..dc04ff1b6be0 --- /dev/null +++ b/drivers/firmware/qcom/qcom_pas.c @@ -0,0 +1,295 @@ +// SPDX-License-Identifier: GPL-2.0 +/*
- Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
- */
+#include <linux/delay.h> +#include <linux/device/devres.h> +#include <linux/firmware/qcom/qcom_pas.h> +#include <linux/of.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/slab.h>
are you sure you are using functionalities from these header files?
I couldn't find slab.h usage quickly and also qcom_scm.h. Can you please confirm?
You are right, I will drop the redundant header includes.
+#include "qcom_pas.h" +#include "qcom_scm.h"
+static struct qcom_pas_ops *ops_ptr;
+/**
- devm_qcom_pas_context_alloc() - Allocate peripheral authentication service
context for a given peripheral
- PAS context is device-resource managed, so the caller does not need
- to worry about freeing the context memory.
- @dev: PAS firmware device
- @pas_id: peripheral authentication service id
- @mem_phys: Subsystem reserve memory start address
- @mem_size: Subsystem reserve memory size
- Returns: The new PAS context, or ERR_PTR() on failure.
- */
+struct qcom_pas_context *devm_qcom_pas_context_alloc(struct device *dev,
u32 pas_id,phys_addr_t mem_phys,size_t mem_size)+{
- struct qcom_pas_context *ctx;
- ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
- if (!ctx)
return ERR_PTR(-ENOMEM);- ctx->dev = dev;
- ctx->pas_id = pas_id;
- ctx->mem_phys = mem_phys;
- ctx->mem_size = mem_size;
- return ctx;
+} +EXPORT_SYMBOL_GPL(devm_qcom_pas_context_alloc);
+/**
- qcom_pas_init_image() - Initialize peripheral authentication service state
machine for a given peripheral, using the metadata
- @pas_id: peripheral authentication service 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 pas 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_pas_metadata_release() by the caller.
- */
+int qcom_pas_init_image(u32 pas_id, const void *metadata, size_t size,
struct qcom_pas_context *ctx)+{
- if (ops_ptr)
return ops_ptr->init_image(ops_ptr->dev, pas_id,metadata, size, ctx);- return -ENODEV;
+} +EXPORT_SYMBOL_GPL(qcom_pas_init_image);
+/**
- qcom_pas_metadata_release() - release metadata context
- @ctx: pas context
- */
+void qcom_pas_metadata_release(struct qcom_pas_context *ctx) +{
- if (!ctx || !ctx->ptr)
return;- if (ops_ptr)
ops_ptr->metadata_release(ops_ptr->dev, ctx);+} +EXPORT_SYMBOL_GPL(qcom_pas_metadata_release);
+/**
- qcom_pas_mem_setup() - Prepare the memory related to a given peripheral
for firmware loading
- @pas_id: peripheral authentication service id
- @addr: start address of memory area to prepare
- @size: size of the memory area to prepare
- Returns 0 on success.
- */
+int qcom_pas_mem_setup(u32 pas_id, phys_addr_t addr, phys_addr_t size) +{
- if (ops_ptr)
return ops_ptr->mem_setup(ops_ptr->dev, pas_id, addr, size);- return -ENODEV;
+} +EXPORT_SYMBOL_GPL(qcom_pas_mem_setup);
+/**
- qcom_pas_get_rsc_table() - Retrieve the resource table in passed output buffer
for a given peripheral.
- Qualcomm remote processor may rely on both static and dynamic resources for
- its functionality. Static resources typically refer to memory-mapped
- addresses required by the subsystem and are often embedded within the
- firmware binary and dynamic resources, such as shared memory in DDR etc.,
- are determined at runtime during the boot process.
- On Qualcomm Technologies devices, it's possible that static resources are
- not embedded in the firmware binary and instead are provided by TrustZone.
- However, dynamic resources are always expected to come from TrustZone. This
Is it confirmed that it will always come from Trustzone? Is it not possible that it can come from trusted controller - bypassing the trustzone? Assuming that such controller is never modified by anyone else including final device makers and blessed by the trust boundaries.
Is this design going to scale if we put the MCU doing the heavy lifting instead?
I am not aware of such an MCU implementation already but surely when such implementation comes to life, we can always revisit the APIs needed. The comments here reflects the implementations which exists as of now.
- indicates that for Qualcomm devices, all resources (static and dynamic) will
- be provided by TrustZone PAS service.
- If the remote processor firmware binary does contain static resources, they
- should be passed in input_rt. These will be forwarded to TrustZone for
- authentication. TrustZone will then append the dynamic resources and return
- the complete resource table in output_rt_tzm.
- If the remote processor firmware binary does not include a resource table,
- the caller of this function should set input_rt as NULL and input_rt_size
- as zero respectively.
- More about documentation on resource table data structures can be found in
- include/linux/remoteproc.h
- @ctx: PAS context
- @pas_id: peripheral authentication service id
- @input_rt: resource table buffer which is present in firmware binary
- @input_rt_size: size of the resource table present in firmware binary
- @output_rt_size: TrustZone expects caller should pass worst case size for
the output_rt_tzm.
- Return:
- On success, returns a pointer to the allocated buffer containing the final
- resource table and output_rt_size will have actual resource table size from
- TrustZone. The caller is responsible for freeing the buffer. On failure,
- returns ERR_PTR(-errno).
- */
+struct resource_table *qcom_pas_get_rsc_table(struct qcom_pas_context *ctx,
void *input_rt,size_t input_rt_size,size_t *output_rt_size)+{
- if (ops_ptr)
return ops_ptr->get_rsc_table(ops_ptr->dev, ctx, input_rt,input_rt_size, output_rt_size);- return ERR_PTR(-ENODEV);
+} +EXPORT_SYMBOL_GPL(qcom_pas_get_rsc_table);
+/**
- qcom_scm_pas_auth_and_reset() - Authenticate the given peripheral firmware
and reset the remote processor
- @pas_id: peripheral authentication service id
- Return 0 on success.
- */
+int qcom_pas_auth_and_reset(u32 pas_id) +{
- if (ops_ptr)
return ops_ptr->auth_and_reset(ops_ptr->dev, pas_id);- return -ENODEV;
+} +EXPORT_SYMBOL_GPL(qcom_pas_auth_and_reset);
+/**
- qcom_pas_prepare_and_auth_reset() - Prepare, authenticate, and reset the
remote processor
- @ctx: Context saved during call to qcom_scm_pas_context_init()
- This function performs the necessary steps to prepare a PAS subsystem,
- authenticate it using the provided metadata, and initiate a reset sequence.
- It should be used when Linux is in control setting up the IOMMU hardware
- for remote subsystem during secure firmware loading processes. The
- preparation step sets up a shmbridge over the firmware memory before
- TrustZone accesses the firmware memory region for authentication. The
- authentication step verifies the integrity and authenticity of the firmware
- or configuration using secure metadata. Finally, the reset step ensures the
- subsystem starts in a clean and sane state.
- Return: 0 on success, negative errno on failure.
- */
+int qcom_pas_prepare_and_auth_reset(struct qcom_pas_context *ctx) +{
- if (ops_ptr)
return ops_ptr->prepare_and_auth_reset(ops_ptr->dev, ctx);- return -ENODEV;
+} +EXPORT_SYMBOL_GPL(qcom_pas_prepare_and_auth_reset);
+/**
- qcom_pas_set_remote_state() - Set the remote processor state
- @state: peripheral state
- @pas_id: peripheral authentication service id
- Returns 0 on success.
- */
+int qcom_pas_set_remote_state(u32 state, u32 pas_id) +{
- if (ops_ptr)
return ops_ptr->set_remote_state(ops_ptr->dev, state, pas_id);- return -ENODEV;
+} +EXPORT_SYMBOL_GPL(qcom_pas_set_remote_state);
+/**
- qcom_pas_shutdown() - Shut down the remote processor
- @pas_id: peripheral authentication service id
- Returns 0 on success.
- */
+int qcom_pas_shutdown(u32 pas_id) +{
- if (ops_ptr)
return ops_ptr->shutdown(ops_ptr->dev, pas_id);- return -ENODEV;
+} +EXPORT_SYMBOL_GPL(qcom_pas_shutdown);
+/**
- qcom_pas_supported() - Check if the peripheral authentication service is
available for the given peripheral
- @pas_id: peripheral authentication service id
- Returns true if PAS is supported for this peripheral, otherwise false.
- */
+bool qcom_pas_supported(u32 pas_id) +{
- if (ops_ptr)
return ops_ptr->supported(ops_ptr->dev, pas_id);- return false;
+} +EXPORT_SYMBOL_GPL(qcom_pas_supported);
+/**
- qcom_pas_is_available() - Check for PAS service
- Returns true on success.
- */
+bool qcom_pas_is_available(void) +{
- /* The barrier is needed to synchronize with client drivers. */
- return !!smp_load_acquire(&ops_ptr);
+} +EXPORT_SYMBOL_GPL(qcom_pas_is_available);
+/**
- qcom_pas_ops_register() - Register PAS service ops
- @ops: PAS service ops pointer
- */
+void qcom_pas_ops_register(struct qcom_pas_ops *ops) +{
- if (!qcom_pas_is_available())
/* The barrier is needed to synchronize with client drivers. */smp_store_release(&ops_ptr, ops);- else
pr_err("qcom_pas: ops already registered\n");+} +EXPORT_SYMBOL_GPL(qcom_pas_ops_register);
+/**
- qcom_pas_ops_unregister() - Unregister PAS service ops
- */
+void qcom_pas_ops_unregister(void) +{
- /* The barrier is needed to synchronize with client drivers. */
- smp_store_release(&ops_ptr, NULL);
+} +EXPORT_SYMBOL_GPL(qcom_pas_ops_unregister);
+MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Sumit Garg sumit.garg@oss.qualcomm.com");
What is the convention for Qualcomm authored drivers? In some drivers I find that Qualcomm doesn't add MODULE_AUTHOR. Can Qualcomm community clarify it here. I prefer consistency here for the Qualcomm submissions.
Not sure if there can be a single Qualcomm policy across the upstream kernel contributions. Generally I have seen this to vary from one sub-system to another. In case of drivers/firmware/
$ git grep -nr MODULE_AUTHOR drivers/firmware/ | wc -l 54
whereas other subsystems prefer a maintainer's entry for new driver code. The general idea is to keep module authors involved as part of maintenence, reviews and bug reports. So I will leave this dicision to Bjorn and Konrad being maintainers for drivers/firmware/qcom/.
+MODULE_DESCRIPTION("Qualcomm common TZ PAS driver"); diff --git a/drivers/firmware/qcom/qcom_pas.h b/drivers/firmware/qcom/qcom_pas.h new file mode 100644 index 000000000000..4ebed22178f8 --- /dev/null +++ b/drivers/firmware/qcom/qcom_pas.h @@ -0,0 +1,53 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/*
- Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
- */
+#ifndef __QCOM_PAS_INT_H +#define __QCOM_PAS_INT_H
+struct device;
+/**
- struct qcom_pas_ops - Qcom Peripheral Authentication Service (PAS) ops
- @drv_name: PAS driver name.
- @dev: PAS device pointer.
- @supported: Peripheral supported callback.
- @init_image: Peripheral image initialization callback.
- @mem_setup: Peripheral memory setup callback.
- @get_rsc_table: Peripheral get resource table callback.
- @prepare_and_auth_reset: Peripheral prepare firmware authentication and
reset callback.
- @auth_and_reset: Peripheral firmware authentication and reset
callback.
- @set_remote_state: Peripheral set remote state callback.
- @shutdown: Peripheral shutdown callback.
- @metadata_release: Image metadata release callback.
- */
+struct qcom_pas_ops {
- const char *drv_name;
- struct device *dev;
- bool (*supported)(struct device *dev, u32 pas_id);
- int (*init_image)(struct device *dev, u32 pas_id,
const void *metadata, size_t size,struct qcom_pas_context *ctx);- int (*mem_setup)(struct device *dev, u32 pas_id,
phys_addr_t addr, phys_addr_t size);- void *(*get_rsc_table)(struct device *dev,
struct qcom_pas_context *ctx,void *input_rt,size_t input_rt_size,size_t *output_rt_size);void * or resource_table * as return?
The generic wrapper qcom_pas_get_rsc_table() returns that. From TZ interface perspective it's just a data buffer.
-Sumit
From: Sumit Garg sumit.garg@oss.qualcomm.com
With the availability of generic PAS service, let's add SCM calls as a backend to keep supporting legacy QTEE interfaces. The exported qcom_scm* wrappers will get dropped once all the client drivers get migrated as part of future patches.
Signed-off-by: Sumit Garg sumit.garg@oss.qualcomm.com --- drivers/firmware/qcom/Kconfig | 1 + drivers/firmware/qcom/qcom_scm.c | 336 ++++++++++++++----------------- 2 files changed, 156 insertions(+), 181 deletions(-)
diff --git a/drivers/firmware/qcom/Kconfig b/drivers/firmware/qcom/Kconfig index 8653639d06db..9a12ae2b639d 100644 --- a/drivers/firmware/qcom/Kconfig +++ b/drivers/firmware/qcom/Kconfig @@ -15,6 +15,7 @@ config QCOM_PAS TEE bus based PAS service implementation.
config QCOM_SCM + select QCOM_PAS select QCOM_TZMEM tristate
diff --git a/drivers/firmware/qcom/qcom_scm.c b/drivers/firmware/qcom/qcom_scm.c index 8fbc96693a55..2d7937ae7c8f 100644 --- a/drivers/firmware/qcom/qcom_scm.c +++ b/drivers/firmware/qcom/qcom_scm.c @@ -13,6 +13,7 @@ #include <linux/dma-mapping.h> #include <linux/err.h> #include <linux/export.h> +#include <linux/firmware/qcom/qcom_pas.h> #include <linux/firmware/qcom/qcom_scm.h> #include <linux/firmware/qcom/qcom_tzmem.h> #include <linux/init.h> @@ -33,6 +34,7 @@
#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include "qcom_pas.h" #include "qcom_scm.h" #include "qcom_tzmem.h"
@@ -480,25 +482,6 @@ void qcom_scm_cpu_power_down(u32 flags) } 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; @@ -571,26 +554,12 @@ static void qcom_scm_set_download_mode(u32 dload_mode) dev_err(__scm->dev, "failed to set download mode: %d\n", ret); }
-/** - * devm_qcom_scm_pas_context_alloc() - Allocate peripheral authentication service - * context for a given peripheral - * - * PAS context is device-resource managed, so the caller does not need - * to worry about freeing the context memory. - * - * @dev: PAS firmware device - * @pas_id: peripheral authentication service id - * @mem_phys: Subsystem reserve memory start address - * @mem_size: Subsystem reserve memory size - * - * Returns: The new PAS context, or ERR_PTR() on failure. - */ struct qcom_scm_pas_context *devm_qcom_scm_pas_context_alloc(struct device *dev, u32 pas_id, phys_addr_t mem_phys, size_t mem_size) { - struct qcom_scm_pas_context *ctx; + struct qcom_pas_context *ctx;
ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); if (!ctx) @@ -601,11 +570,12 @@ struct qcom_scm_pas_context *devm_qcom_scm_pas_context_alloc(struct device *dev, ctx->mem_phys = mem_phys; ctx->mem_size = mem_size;
- return ctx; + return (struct qcom_scm_pas_context *)ctx; } EXPORT_SYMBOL_GPL(devm_qcom_scm_pas_context_alloc);
-static int __qcom_scm_pas_init_image(u32 pas_id, dma_addr_t mdata_phys, +static int __qcom_scm_pas_init_image(struct device *dev, u32 pas_id, + dma_addr_t mdata_phys, struct qcom_scm_res *res) { struct qcom_scm_desc desc = { @@ -627,7 +597,7 @@ static int __qcom_scm_pas_init_image(u32 pas_id, dma_addr_t mdata_phys,
desc.args[1] = mdata_phys;
- ret = qcom_scm_call(__scm->dev, &desc, res); + ret = qcom_scm_call(dev, &desc, res); qcom_scm_bw_disable();
disable_clk: @@ -636,7 +606,8 @@ static int __qcom_scm_pas_init_image(u32 pas_id, dma_addr_t mdata_phys, return ret; }
-static int qcom_scm_pas_prep_and_init_image(struct qcom_scm_pas_context *ctx, +static int qcom_scm_pas_prep_and_init_image(struct device *dev, + struct qcom_pas_context *ctx, const void *metadata, size_t size) { struct qcom_scm_res res; @@ -651,7 +622,7 @@ static int qcom_scm_pas_prep_and_init_image(struct qcom_scm_pas_context *ctx, memcpy(mdata_buf, metadata, size); mdata_phys = qcom_tzmem_to_phys(mdata_buf);
- ret = __qcom_scm_pas_init_image(ctx->pas_id, mdata_phys, &res); + ret = __qcom_scm_pas_init_image(dev, ctx->pas_id, mdata_phys, &res); if (ret < 0) qcom_tzmem_free(mdata_buf); else @@ -660,25 +631,9 @@ static int qcom_scm_pas_prep_and_init_image(struct qcom_scm_pas_context *ctx, return ret ? : res.result[0]; }
-/** - * qcom_scm_pas_init_image() - Initialize peripheral authentication service - * state machine for a given peripheral, using the - * metadata - * @pas_id: peripheral authentication service 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 pas 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 pas_id, const void *metadata, size_t size, - struct qcom_scm_pas_context *ctx) +static int __qcom_scm_pas_init_image2(struct device *dev, u32 pas_id, + const void *metadata, size_t size, + struct qcom_pas_context *ctx) { struct qcom_scm_res res; dma_addr_t mdata_phys; @@ -686,7 +641,8 @@ int qcom_scm_pas_init_image(u32 pas_id, const void *metadata, size_t size, int ret;
if (ctx && ctx->use_tzmem) - return qcom_scm_pas_prep_and_init_image(ctx, metadata, size); + return qcom_scm_pas_prep_and_init_image(dev, ctx, metadata, + size);
/* * During the scm call memory protection will be enabled for the meta @@ -700,16 +656,15 @@ int qcom_scm_pas_init_image(u32 pas_id, const void *metadata, size_t size, * If we pass a buffer that is already part of an SHM Bridge to this * call, it will fail. */ - mdata_buf = dma_alloc_coherent(__scm->dev, size, &mdata_phys, - GFP_KERNEL); + mdata_buf = dma_alloc_coherent(dev, size, &mdata_phys, GFP_KERNEL); if (!mdata_buf) return -ENOMEM;
memcpy(mdata_buf, metadata, size);
- ret = __qcom_scm_pas_init_image(pas_id, mdata_phys, &res); + ret = __qcom_scm_pas_init_image(dev, pas_id, mdata_phys, &res); if (ret < 0 || !ctx) { - dma_free_coherent(__scm->dev, size, mdata_buf, mdata_phys); + dma_free_coherent(dev, size, mdata_buf, mdata_phys); } else if (ctx) { ctx->ptr = mdata_buf; ctx->phys = mdata_phys; @@ -718,36 +673,35 @@ int qcom_scm_pas_init_image(u32 pas_id, const void *metadata, size_t size,
return ret ? : res.result[0]; } -EXPORT_SYMBOL_GPL(qcom_scm_pas_init_image);
-/** - * qcom_scm_pas_metadata_release() - release metadata context - * @ctx: pas context - */ -void qcom_scm_pas_metadata_release(struct qcom_scm_pas_context *ctx) +int qcom_scm_pas_init_image(u32 pas_id, const void *metadata, size_t size, + struct qcom_scm_pas_context *ctx) { - if (!ctx->ptr) - return; + return __qcom_scm_pas_init_image2(__scm->dev, pas_id, metadata, size, + (struct qcom_pas_context *)ctx); +} +EXPORT_SYMBOL_GPL(qcom_scm_pas_init_image);
+static void __qcom_scm_pas_metadata_release(struct device *dev, + struct qcom_pas_context *ctx) +{ if (ctx->use_tzmem) qcom_tzmem_free(ctx->ptr); else - dma_free_coherent(__scm->dev, ctx->size, ctx->ptr, ctx->phys); + dma_free_coherent(dev, ctx->size, ctx->ptr, ctx->phys);
ctx->ptr = NULL; } + +void qcom_scm_pas_metadata_release(struct qcom_scm_pas_context *ctx) +{ + __qcom_scm_pas_metadata_release(__scm->dev, + (struct qcom_pas_context *)ctx); +} EXPORT_SYMBOL_GPL(qcom_scm_pas_metadata_release);
-/** - * qcom_scm_pas_mem_setup() - Prepare the memory related to a given peripheral - * for firmware loading - * @pas_id: peripheral authentication service 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 pas_id, phys_addr_t addr, phys_addr_t size) +static int __qcom_scm_pas_mem_setup(struct device *dev, u32 pas_id, + phys_addr_t addr, phys_addr_t size) { int ret; struct qcom_scm_desc desc = { @@ -769,7 +723,7 @@ int qcom_scm_pas_mem_setup(u32 pas_id, phys_addr_t addr, phys_addr_t size) if (ret) goto disable_clk;
- ret = qcom_scm_call(__scm->dev, &desc, &res); + ret = qcom_scm_call(dev, &desc, &res); qcom_scm_bw_disable();
disable_clk: @@ -777,9 +731,15 @@ int qcom_scm_pas_mem_setup(u32 pas_id, phys_addr_t addr, phys_addr_t size)
return ret ? : res.result[0]; } + +int qcom_scm_pas_mem_setup(u32 pas_id, phys_addr_t addr, phys_addr_t size) +{ + return __qcom_scm_pas_mem_setup(__scm->dev, pas_id, addr, size); +} EXPORT_SYMBOL_GPL(qcom_scm_pas_mem_setup);
-static void *__qcom_scm_pas_get_rsc_table(u32 pas_id, void *input_rt_tzm, +static void *__qcom_scm_pas_get_rsc_table(struct device *dev, u32 pas_id, + void *input_rt_tzm, size_t input_rt_size, size_t *output_rt_size) { @@ -814,7 +774,7 @@ static void *__qcom_scm_pas_get_rsc_table(u32 pas_id, void *input_rt_tzm, * with output_rt_tzm buffer with res.result[2] size however, It should not * be of unresonable size. */ - ret = qcom_scm_call(__scm->dev, &desc, &res); + ret = qcom_scm_call(dev, &desc, &res); if (!ret && res.result[2] > SZ_1G) { ret = -E2BIG; goto free_output_rt; @@ -831,51 +791,11 @@ static void *__qcom_scm_pas_get_rsc_table(u32 pas_id, void *input_rt_tzm, return ret ? ERR_PTR(ret) : output_rt_tzm; }
-/** - * qcom_scm_pas_get_rsc_table() - Retrieve the resource table in passed output buffer - * for a given peripheral. - * - * Qualcomm remote processor may rely on both static and dynamic resources for - * its functionality. Static resources typically refer to memory-mapped addresses - * required by the subsystem and are often embedded within the firmware binary - * and dynamic resources, such as shared memory in DDR etc., are determined at - * runtime during the boot process. - * - * On Qualcomm Technologies devices, it's possible that static resources are not - * embedded in the firmware binary and instead are provided by TrustZone However, - * dynamic resources are always expected to come from TrustZone. This indicates - * that for Qualcomm devices, all resources (static and dynamic) will be provided - * by TrustZone via the SMC call. - * - * If the remote processor firmware binary does contain static resources, they - * should be passed in input_rt. These will be forwarded to TrustZone for - * authentication. TrustZone will then append the dynamic resources and return - * the complete resource table in output_rt_tzm. - * - * If the remote processor firmware binary does not include a resource table, - * the caller of this function should set input_rt as NULL and input_rt_size - * as zero respectively. - * - * More about documentation on resource table data structures can be found in - * include/linux/remoteproc.h - * - * @ctx: PAS context - * @pas_id: peripheral authentication service id - * @input_rt: resource table buffer which is present in firmware binary - * @input_rt_size: size of the resource table present in firmware binary - * @output_rt_size: TrustZone expects caller should pass worst case size for - * the output_rt_tzm. - * - * Return: - * On success, returns a pointer to the allocated buffer containing the final - * resource table and output_rt_size will have actual resource table size from - * TrustZone. The caller is responsible for freeing the buffer. On failure, - * returns ERR_PTR(-errno). - */ -struct resource_table *qcom_scm_pas_get_rsc_table(struct qcom_scm_pas_context *ctx, - void *input_rt, - size_t input_rt_size, - size_t *output_rt_size) +static void *__qcom_scm_pas_get_rsc_table2(struct device *dev, + struct qcom_pas_context *ctx, + void *input_rt, + size_t input_rt_size, + size_t *output_rt_size) { struct resource_table empty_rsc = {}; size_t size = SZ_16K; @@ -910,11 +830,12 @@ struct resource_table *qcom_scm_pas_get_rsc_table(struct qcom_scm_pas_context *c
memcpy(input_rt_tzm, input_rt, input_rt_size);
- output_rt_tzm = __qcom_scm_pas_get_rsc_table(ctx->pas_id, input_rt_tzm, + output_rt_tzm = __qcom_scm_pas_get_rsc_table(dev, ctx->pas_id, + input_rt_tzm, input_rt_size, &size); if (PTR_ERR(output_rt_tzm) == -EOVERFLOW) /* Try again with the size requested by the TZ */ - output_rt_tzm = __qcom_scm_pas_get_rsc_table(ctx->pas_id, + output_rt_tzm = __qcom_scm_pas_get_rsc_table(dev, ctx->pas_id, input_rt_tzm, input_rt_size, &size); @@ -945,16 +866,20 @@ struct resource_table *qcom_scm_pas_get_rsc_table(struct qcom_scm_pas_context *c
return ret ? ERR_PTR(ret) : tbl_ptr; } + +struct resource_table *qcom_scm_pas_get_rsc_table(struct qcom_scm_pas_context *ctx, + void *input_rt, + size_t input_rt_size, + size_t *output_rt_size) +{ + return __qcom_scm_pas_get_rsc_table2(__scm->dev, + (struct qcom_pas_context *)ctx, + input_rt, input_rt_size, + output_rt_size); +} EXPORT_SYMBOL_GPL(qcom_scm_pas_get_rsc_table);
-/** - * qcom_scm_pas_auth_and_reset() - Authenticate the given peripheral firmware - * and reset the remote processor - * @pas_id: peripheral authentication service id - * - * Return 0 on success. - */ -int qcom_scm_pas_auth_and_reset(u32 pas_id) +static int __qcom_scm_pas_auth_and_reset(struct device *dev, u32 pas_id) { int ret; struct qcom_scm_desc desc = { @@ -974,7 +899,7 @@ int qcom_scm_pas_auth_and_reset(u32 pas_id) if (ret) goto disable_clk;
- ret = qcom_scm_call(__scm->dev, &desc, &res); + ret = qcom_scm_call(dev, &desc, &res); qcom_scm_bw_disable();
disable_clk: @@ -982,28 +907,15 @@ int qcom_scm_pas_auth_and_reset(u32 pas_id)
return ret ? : res.result[0]; } + +int qcom_scm_pas_auth_and_reset(u32 pas_id) +{ + return __qcom_scm_pas_auth_and_reset(__scm->dev, pas_id); +} EXPORT_SYMBOL_GPL(qcom_scm_pas_auth_and_reset);
-/** - * qcom_scm_pas_prepare_and_auth_reset() - Prepare, authenticate, and reset the - * remote processor - * - * @ctx: Context saved during call to qcom_scm_pas_context_init() - * - * This function performs the necessary steps to prepare a PAS subsystem, - * authenticate it using the provided metadata, and initiate a reset sequence. - * - * It should be used when Linux is in control setting up the IOMMU hardware - * for remote subsystem during secure firmware loading processes. The preparation - * step sets up a shmbridge over the firmware memory before TrustZone accesses the - * firmware memory region for authentication. The authentication step verifies - * the integrity and authenticity of the firmware or configuration using secure - * metadata. Finally, the reset step ensures the subsystem starts in a clean and - * sane state. - * - * Return: 0 on success, negative errno on failure. - */ -int qcom_scm_pas_prepare_and_auth_reset(struct qcom_scm_pas_context *ctx) +static int __qcom_scm_pas_prepare_and_auth_reset(struct device *dev, + struct qcom_pas_context *ctx) { u64 handle; int ret; @@ -1014,7 +926,7 @@ int qcom_scm_pas_prepare_and_auth_reset(struct qcom_scm_pas_context *ctx) * memory region and then invokes a call to TrustZone to authenticate. */ if (!ctx->use_tzmem) - return qcom_scm_pas_auth_and_reset(ctx->pas_id); + return __qcom_scm_pas_auth_and_reset(dev, ctx->pas_id);
/* * When Linux runs @ EL2 Linux must create the shmbridge itself and then @@ -1024,20 +936,45 @@ int qcom_scm_pas_prepare_and_auth_reset(struct qcom_scm_pas_context *ctx) if (ret) return ret;
- ret = qcom_scm_pas_auth_and_reset(ctx->pas_id); + ret = __qcom_scm_pas_auth_and_reset(dev, ctx->pas_id); qcom_tzmem_shm_bridge_delete(handle);
return ret; } + +int qcom_scm_pas_prepare_and_auth_reset(struct qcom_scm_pas_context *ctx) +{ + return __qcom_scm_pas_prepare_and_auth_reset(__scm->dev, + (struct qcom_pas_context *)ctx); +} EXPORT_SYMBOL_GPL(qcom_scm_pas_prepare_and_auth_reset);
-/** - * qcom_scm_pas_shutdown() - Shut down the remote processor - * @pas_id: peripheral authentication service id - * - * Returns 0 on success. - */ -int qcom_scm_pas_shutdown(u32 pas_id) +static int __qcom_scm_pas_set_remote_state(struct device *dev, u32 state, + u32 pas_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] = pas_id, + .owner = ARM_SMCCC_OWNER_SIP, + }; + struct qcom_scm_res res; + int ret; + + ret = qcom_scm_call(dev, &desc, &res); + + return ret ? : res.result[0]; +} + +int qcom_scm_set_remote_state(u32 state, u32 id) +{ + return __qcom_scm_pas_set_remote_state(__scm->dev, state, id); +} +EXPORT_SYMBOL_GPL(qcom_scm_set_remote_state); + +static int __qcom_scm_pas_shutdown(struct device *dev, u32 pas_id) { int ret; struct qcom_scm_desc desc = { @@ -1057,7 +994,7 @@ int qcom_scm_pas_shutdown(u32 pas_id) if (ret) goto disable_clk;
- ret = qcom_scm_call(__scm->dev, &desc, &res); + ret = qcom_scm_call(dev, &desc, &res); qcom_scm_bw_disable();
disable_clk: @@ -1065,16 +1002,14 @@ int qcom_scm_pas_shutdown(u32 pas_id)
return ret ? : res.result[0]; } + +int qcom_scm_pas_shutdown(u32 pas_id) +{ + return __qcom_scm_pas_shutdown(__scm->dev, pas_id); +} EXPORT_SYMBOL_GPL(qcom_scm_pas_shutdown);
-/** - * qcom_scm_pas_supported() - Check if the peripheral authentication service is - * available for the given peripherial - * @pas_id: peripheral authentication service id - * - * Returns true if PAS is supported for this peripheral, otherwise false. - */ -bool qcom_scm_pas_supported(u32 pas_id) +static bool __qcom_scm_pas_supported(struct device *dev, u32 pas_id) { int ret; struct qcom_scm_desc desc = { @@ -1086,16 +1021,49 @@ bool qcom_scm_pas_supported(u32 pas_id) }; struct qcom_scm_res res;
- if (!__qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_PIL, + if (!__qcom_scm_is_call_available(dev, QCOM_SCM_SVC_PIL, QCOM_SCM_PIL_PAS_IS_SUPPORTED)) return false;
- ret = qcom_scm_call(__scm->dev, &desc, &res); + ret = qcom_scm_call(dev, &desc, &res);
return ret ? false : !!res.result[0]; } + +bool qcom_scm_pas_supported(u32 pas_id) +{ + return __qcom_scm_pas_supported(__scm->dev, pas_id); +} EXPORT_SYMBOL_GPL(qcom_scm_pas_supported);
+static struct qcom_pas_ops qcom_pas_ops_scm = { + .drv_name = "qcom_scm", + .supported = __qcom_scm_pas_supported, + .init_image = __qcom_scm_pas_init_image2, + .mem_setup = __qcom_scm_pas_mem_setup, + .get_rsc_table = __qcom_scm_pas_get_rsc_table2, + .auth_and_reset = __qcom_scm_pas_auth_and_reset, + .prepare_and_auth_reset = __qcom_scm_pas_prepare_and_auth_reset, + .set_remote_state = __qcom_scm_pas_set_remote_state, + .shutdown = __qcom_scm_pas_shutdown, + .metadata_release = __qcom_scm_pas_metadata_release, +}; + +/** + * qcom_scm_is_pas_available() - Check if the peripheral authentication service + * is available via SCM or not + * + * Returns true if PAS is available, otherwise false. + */ +static bool qcom_scm_is_pas_available(void) +{ + if (!__qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_PIL, + QCOM_SCM_PIL_PAS_AUTH_AND_RESET)) + return false; + + return true; +} + static int __qcom_scm_pas_mss_reset(struct device *dev, bool reset) { struct qcom_scm_desc desc = { @@ -2782,6 +2750,11 @@ static int qcom_scm_probe(struct platform_device *pdev)
__get_convention();
+ if (qcom_scm_is_pas_available()) { + qcom_pas_ops_scm.dev = scm->dev; + qcom_pas_ops_register(&qcom_pas_ops_scm); + } + /* * If "download mode" is requested, from this point on warmboot * will cause the boot stages to enter download mode, unless @@ -2818,6 +2791,7 @@ static void qcom_scm_shutdown(struct platform_device *pdev) { /* Clean shutdown, disable download mode to allow normal restart */ qcom_scm_set_download_mode(QCOM_DLOAD_NODUMP); + qcom_pas_ops_unregister(); }
static const struct of_device_id qcom_scm_dt_match[] = {
From: Sumit Garg sumit.garg@oss.qualcomm.com
Add support for Peripheral Authentication Service (PAS) driver based on TEE bus with OP-TEE providing the backend PAS service implementation.
The TEE PAS service ABI is designed to be extensible with additional API as PTA_QCOM_PAS_CAPABILITIES. This allows to accommodate any future extensions of the PAS service needed while still maintaining backwards compatibility.
Signed-off-by: Sumit Garg sumit.garg@oss.qualcomm.com --- drivers/firmware/qcom/Kconfig | 9 + drivers/firmware/qcom/Makefile | 1 + drivers/firmware/qcom/qcom_pas_tee.c | 478 +++++++++++++++++++++++++++ 3 files changed, 488 insertions(+) create mode 100644 drivers/firmware/qcom/qcom_pas_tee.c
diff --git a/drivers/firmware/qcom/Kconfig b/drivers/firmware/qcom/Kconfig index 9a12ae2b639d..fff47abdaafd 100644 --- a/drivers/firmware/qcom/Kconfig +++ b/drivers/firmware/qcom/Kconfig @@ -14,6 +14,15 @@ config QCOM_PAS backends plugged in whether it's an SCM implementation or a proper TEE bus based PAS service implementation.
+config QCOM_PAS_TEE + tristate + select QCOM_PAS + depends on TEE + depends on !CPU_BIG_ENDIAN + help + Enable the generic Peripheral Authentication Service (PAS) provided + by the firmware TEE implementation as the backend. + config QCOM_SCM select QCOM_PAS select QCOM_TZMEM diff --git a/drivers/firmware/qcom/Makefile b/drivers/firmware/qcom/Makefile index dc5ab45f906a..48801d18f37b 100644 --- a/drivers/firmware/qcom/Makefile +++ b/drivers/firmware/qcom/Makefile @@ -9,3 +9,4 @@ obj-$(CONFIG_QCOM_TZMEM) += qcom_tzmem.o obj-$(CONFIG_QCOM_QSEECOM) += qcom_qseecom.o obj-$(CONFIG_QCOM_QSEECOM_UEFISECAPP) += qcom_qseecom_uefisecapp.o obj-$(CONFIG_QCOM_PAS) += qcom_pas.o +obj-$(CONFIG_QCOM_PAS_TEE) += qcom_pas_tee.o diff --git a/drivers/firmware/qcom/qcom_pas_tee.c b/drivers/firmware/qcom/qcom_pas_tee.c new file mode 100644 index 000000000000..84cd4d62058c --- /dev/null +++ b/drivers/firmware/qcom/qcom_pas_tee.c @@ -0,0 +1,478 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#include <linux/delay.h> +#include <linux/of.h> +#include <linux/firmware/qcom/qcom_pas.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/tee_drv.h> +#include <linux/uuid.h> + +#include "qcom_pas.h" + +/* + * Peripheral Authentication Service (PAS) supported. + * + * [in] params[0].value.a: Unique 32bit remote processor identifier + */ +#define PTA_QCOM_PAS_IS_SUPPORTED 1 + +/* + * PAS capabilities. + * + * [in] params[0].value.a: Unique 32bit remote processor identifier + * [out] params[1].value.a: PAS capability flags + */ +#define PTA_QCOM_PAS_CAPABILITIES 2 + +/* + * PAS image initialization. + * + * [in] params[0].value.a: Unique 32bit remote processor identifier + * [in] params[1].memref: Loadable firmware metadata + */ +#define PTA_QCOM_PAS_INIT_IMAGE 3 + +/* + * PAS memory setup. + * + * [in] params[0].value.a: Unique 32bit remote processor identifier + * [in] params[0].value.b: Relocatable firmware size + * [in] params[1].value.a: 32bit LSB relocatable firmware memory address + * [in] params[1].value.b: 32bit MSB relocatable firmware memory address + */ +#define PTA_QCOM_PAS_MEM_SETUP 4 + +/* + * PAS get resource table. + * + * [in] params[0].value.a: Unique 32bit remote processor identifier + * [inout] params[1].memref: Resource table config + */ +#define PTA_QCOM_PAS_GET_RESOURCE_TABLE 5 + +/* + * PAS image authentication and co-processor reset. + * + * [in] params[0].value.a: Unique 32bit remote processor identifier + * [in] params[0].value.b: Firmware size + * [in] params[1].value.a: 32bit LSB firmware memory address + * [in] params[1].value.b: 32bit MSB firmware memory address + * [in] params[2].memref: Optional fw memory space shared/lent + */ +#define PTA_QCOM_PAS_AUTH_AND_RESET 6 + +/* + * PAS co-processor set suspend/resume state. + * + * [in] params[0].value.a: Unique 32bit remote processor identifier + * [in] params[0].value.b: Co-processor state identifier + */ +#define PTA_QCOM_PAS_SET_REMOTE_STATE 7 + +/* + * PAS co-processor shutdown. + * + * [in] params[0].value.a: Unique 32bit remote processor identifier + */ +#define PTA_QCOM_PAS_SHUTDOWN 8 + +#define TEE_NUM_PARAMS 4 + +/** + * struct qcom_pas_tee_private - PAS service private data + * @dev: PAS service device. + * @ctx: TEE context handler. + * @session_id: PAS TA session identifier. + */ +struct qcom_pas_tee_private { + struct device *dev; + struct tee_context *ctx; + u32 session_id; +}; + +static bool qcom_pas_tee_supported(struct device *dev, u32 pas_id) +{ + struct qcom_pas_tee_private *data = dev_get_drvdata(dev); + struct tee_ioctl_invoke_arg inv_arg = { + .func = PTA_QCOM_PAS_IS_SUPPORTED, + .session = data->session_id, + .num_params = TEE_NUM_PARAMS + }; + struct tee_param param[4] = { + [0] = { + .attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT, + .u.value.a = pas_id + } + }; + int ret; + + ret = tee_client_invoke_func(data->ctx, &inv_arg, param); + if (ret < 0 || inv_arg.ret != 0) { + dev_err(dev, "PAS not supported, pas_id: %d, err: %x\n", + pas_id, inv_arg.ret); + return false; + } + + return true; +} + +static int qcom_pas_tee_init_image(struct device *dev, u32 pas_id, + const void *metadata, size_t size, + struct qcom_pas_context *ctx) +{ + struct qcom_pas_tee_private *data = dev_get_drvdata(dev); + struct tee_ioctl_invoke_arg inv_arg = { + .func = PTA_QCOM_PAS_INIT_IMAGE, + .session = data->session_id, + .num_params = TEE_NUM_PARAMS + }; + struct tee_param param[4] = { + [0] = { + .attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT, + .u.value.a = pas_id + }, + [1] = { + .attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT, + } + }; + struct tee_shm *mdata_shm; + u8 *mdata_buf = NULL; + int ret; + + mdata_shm = tee_shm_alloc_kernel_buf(data->ctx, size); + if (IS_ERR(mdata_shm)) { + dev_err(dev, "mdata_shm allocation failed\n"); + return PTR_ERR(mdata_shm); + } + + mdata_buf = tee_shm_get_va(mdata_shm, 0); + if (IS_ERR(mdata_buf)) { + dev_err(dev, "mdata_buf get VA failed\n"); + tee_shm_free(mdata_shm); + return PTR_ERR(mdata_buf); + } + memcpy(mdata_buf, metadata, size); + + param[1].u.memref.shm = mdata_shm; + param[1].u.memref.size = size; + + ret = tee_client_invoke_func(data->ctx, &inv_arg, param); + if (ret < 0 || inv_arg.ret != 0) { + dev_err(dev, "PAS init image failed, pas_id: %d, err: %x\n", + pas_id, inv_arg.ret); + tee_shm_free(mdata_shm); + return -EINVAL; + } + ctx->ptr = (void *)mdata_shm; + + return 0; +} + +static int qcom_pas_tee_mem_setup(struct device *dev, u32 pas_id, + phys_addr_t addr, phys_addr_t size) +{ + struct qcom_pas_tee_private *data = dev_get_drvdata(dev); + struct tee_ioctl_invoke_arg inv_arg = { + .func = PTA_QCOM_PAS_MEM_SETUP, + .session = data->session_id, + .num_params = TEE_NUM_PARAMS + }; + struct tee_param param[4] = { + [0] = { + .attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT, + .u.value.a = pas_id, + .u.value.b = size, + }, + [1] = { + .attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT, + .u.value.a = lower_32_bits(addr), + .u.value.b = upper_32_bits(addr), + } + }; + int ret; + + ret = tee_client_invoke_func(data->ctx, &inv_arg, param); + if (ret < 0 || inv_arg.ret != 0) { + dev_err(dev, "PAS mem setup failed, pas_id: %d, err: %x\n", + pas_id, inv_arg.ret); + return -EINVAL; + } + + return 0; +} + +DEFINE_FREE(shm_free, struct tee_shm *, tee_shm_free(_T)) + +static void *qcom_pas_tee_get_rsc_table(struct device *dev, + struct qcom_pas_context *ctx, + void *input_rt, size_t input_rt_size, + size_t *output_rt_size) +{ + struct qcom_pas_tee_private *data = dev_get_drvdata(dev); + struct tee_ioctl_invoke_arg inv_arg = { + .func = PTA_QCOM_PAS_GET_RESOURCE_TABLE, + .session = data->session_id, + .num_params = TEE_NUM_PARAMS + }; + struct tee_param param[4] = { + [0] = { + .attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT, + .u.value.a = ctx->pas_id, + }, + [1] = { + .attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT, + .u.memref.size = input_rt_size, + } + }; + void *rt_buf = NULL; + int ret; + + ret = tee_client_invoke_func(data->ctx, &inv_arg, param); + if (ret < 0 || inv_arg.ret != 0) { + dev_err(dev, "PAS get RT failed, pas_id: %d, err: %x\n", + ctx->pas_id, inv_arg.ret); + return ERR_PTR(-EINVAL); + } + + if (param[1].u.memref.size) { + struct tee_shm *rt_shm __free(shm_free) = + tee_shm_alloc_kernel_buf(data->ctx, + param[1].u.memref.size); + void *rt_shm_va; + + if (IS_ERR(rt_shm)) { + dev_err(dev, "rt_shm allocation failed\n"); + return rt_shm; + } + + rt_shm_va = tee_shm_get_va(rt_shm, 0); + if (IS_ERR_OR_NULL(rt_shm_va)) { + dev_err(dev, "rt_shm get VA failed\n"); + return ERR_PTR(-EINVAL); + } + memcpy(rt_shm_va, input_rt, input_rt_size); + + param[1].u.memref.shm = rt_shm; + ret = tee_client_invoke_func(data->ctx, &inv_arg, param); + if (ret < 0 || inv_arg.ret != 0) { + dev_err(dev, "PAS get RT failed, pas_id: %d, err: %x\n", + ctx->pas_id, inv_arg.ret); + return ERR_PTR(-EINVAL); + } + + if (param[1].u.memref.size) { + *output_rt_size = param[1].u.memref.size; + rt_buf = kmalloc(param[1].u.memref.size, GFP_KERNEL); + if (!rt_buf) + return ERR_PTR(-ENOMEM); + + memcpy(rt_buf, rt_shm_va, *output_rt_size); + } + } + + return rt_buf; +} + +static int __qcom_pas_tee_auth_and_reset(struct device *dev, u32 pas_id, + phys_addr_t mem_phys, size_t mem_size) +{ + struct qcom_pas_tee_private *data = dev_get_drvdata(dev); + struct tee_ioctl_invoke_arg inv_arg = { + .func = PTA_QCOM_PAS_AUTH_AND_RESET, + .session = data->session_id, + .num_params = TEE_NUM_PARAMS + }; + struct tee_param param[4] = { + [0] = { + .attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT, + .u.value.a = pas_id, + .u.value.b = mem_size, + }, + [1] = { + .attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT, + .u.value.a = lower_32_bits(mem_phys), + .u.value.b = upper_32_bits(mem_phys), + }, + /* Reserved for fw memory space to be shared or lent */ + [2] = { + .attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT, + } + }; + int ret; + + ret = tee_client_invoke_func(data->ctx, &inv_arg, param); + if (ret < 0 || inv_arg.ret != 0) { + dev_err(dev, "PAS auth reset failed, pas_id: %d, err: %x\n", + pas_id, inv_arg.ret); + return -EINVAL; + } + + return 0; +} + +static int qcom_pas_tee_auth_and_reset(struct device *dev, u32 pas_id) +{ + return __qcom_pas_tee_auth_and_reset(dev, pas_id, 0, 0); +} + +static int qcom_pas_tee_prepare_and_auth_reset(struct device *dev, + struct qcom_pas_context *ctx) +{ + return __qcom_pas_tee_auth_and_reset(dev, ctx->pas_id, ctx->mem_phys, + ctx->mem_size); +} + +static int qcom_pas_tee_set_remote_state(struct device *dev, u32 state, + u32 pas_id) +{ + struct qcom_pas_tee_private *data = dev_get_drvdata(dev); + struct tee_ioctl_invoke_arg inv_arg = { + .func = PTA_QCOM_PAS_SET_REMOTE_STATE, + .session = data->session_id, + .num_params = TEE_NUM_PARAMS + }; + struct tee_param param[4] = { + [0] = { + .attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT, + .u.value.a = pas_id, + .u.value.b = state, + } + }; + int ret; + + ret = tee_client_invoke_func(data->ctx, &inv_arg, param); + if (ret < 0 || inv_arg.ret != 0) { + dev_err(dev, "PAS shutdown failed, pas_id: %d, err: %x\n", + pas_id, inv_arg.ret); + return -EINVAL; + } + + return 0; +} + +static int qcom_pas_tee_shutdown(struct device *dev, u32 pas_id) +{ + struct qcom_pas_tee_private *data = dev_get_drvdata(dev); + struct tee_ioctl_invoke_arg inv_arg = { + .func = PTA_QCOM_PAS_SHUTDOWN, + .session = data->session_id, + .num_params = TEE_NUM_PARAMS + }; + struct tee_param param[4] = { + [0] = { + .attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT, + .u.value.a = pas_id + } + }; + int ret = 0; + + ret = tee_client_invoke_func(data->ctx, &inv_arg, param); + if (ret < 0 || inv_arg.ret != 0) { + dev_err(dev, "PAS shutdown failed, pas_id: %d, err: %x\n", + pas_id, inv_arg.ret); + return -EINVAL; + } + + return 0; +} + +static void qcom_pas_tee_metadata_release(struct device *dev, + struct qcom_pas_context *ctx) +{ + struct tee_shm *mdata_shm = ctx->ptr; + + tee_shm_free(mdata_shm); +} + +static struct qcom_pas_ops qcom_pas_ops_tee = { + .drv_name = "qcom-pas-tee", + .supported = qcom_pas_tee_supported, + .init_image = qcom_pas_tee_init_image, + .mem_setup = qcom_pas_tee_mem_setup, + .get_rsc_table = qcom_pas_tee_get_rsc_table, + .auth_and_reset = qcom_pas_tee_auth_and_reset, + .prepare_and_auth_reset = qcom_pas_tee_prepare_and_auth_reset, + .set_remote_state = qcom_pas_tee_set_remote_state, + .shutdown = qcom_pas_tee_shutdown, + .metadata_release = qcom_pas_tee_metadata_release, +}; + +static int optee_ctx_match(struct tee_ioctl_version_data *ver, const void *data) +{ + return ver->impl_id == TEE_IMPL_ID_OPTEE; +} + +static int qcom_pas_tee_probe(struct tee_client_device *pas_dev) +{ + struct device *dev = &pas_dev->dev; + struct qcom_pas_tee_private *data; + struct tee_ioctl_open_session_arg sess_arg = { + .clnt_login = TEE_IOCTL_LOGIN_REE_KERNEL + }; + int ret, err = -ENODEV; + + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->ctx = tee_client_open_context(NULL, optee_ctx_match, NULL, NULL); + if (IS_ERR(data->ctx)) + return -ENODEV; + + export_uuid(sess_arg.uuid, &pas_dev->id.uuid); + ret = tee_client_open_session(data->ctx, &sess_arg, NULL); + if ((ret < 0) || (sess_arg.ret != 0)) { + dev_err(dev, "tee_client_open_session failed, err: %x\n", + sess_arg.ret); + err = -EINVAL; + goto out_ctx; + } + + data->session_id = sess_arg.session; + dev_set_drvdata(dev, data); + qcom_pas_ops_tee.dev = dev; + qcom_pas_ops_register(&qcom_pas_ops_tee); + + return 0; +out_ctx: + tee_client_close_context(data->ctx); + + return err; +} + +static void qcom_pas_tee_remove(struct tee_client_device *pas_dev) +{ + struct device *dev = &pas_dev->dev; + struct qcom_pas_tee_private *data = dev_get_drvdata(dev); + + qcom_pas_ops_unregister(); + tee_client_close_session(data->ctx, data->session_id); + tee_client_close_context(data->ctx); +} + +static const struct tee_client_device_id qcom_pas_tee_id_table[] = { + {UUID_INIT(0xcff7d191, 0x7ca0, 0x4784, + 0xaf, 0x13, 0x48, 0x22, 0x3b, 0x9a, 0x4f, 0xbe)}, + {} +}; +MODULE_DEVICE_TABLE(tee, qcom_pas_tee_id_table); + +static struct tee_client_driver optee_pas_tee_driver = { + .probe = qcom_pas_tee_probe, + .remove = qcom_pas_tee_remove, + .id_table = qcom_pas_tee_id_table, + .driver = { + .name = "qcom-pas-tee", + }, +}; + +module_tee_client_driver(optee_pas_tee_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Sumit Garg sumit.garg@oss.qualcomm.com"); +MODULE_DESCRIPTION("TEE bus based Qualcomm PAS driver");
From: Sumit Garg sumit.garg@oss.qualcomm.com
Switch qcom_q6v5_pas client driver over to generic PAS TZ APIs. Generic PAS TZ service allows to support multiple TZ implementation backends like QTEE based SCM PAS service, OP-TEE based PAS service and any further future TZ backend service.
Signed-off-by: Sumit Garg sumit.garg@oss.qualcomm.com --- drivers/remoteproc/qcom_q6v5_pas.c | 51 +++++++++++++++--------------- 1 file changed, 26 insertions(+), 25 deletions(-)
diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c index 46204da046fa..8c4313f5bbc2 100644 --- a/drivers/remoteproc/qcom_q6v5_pas.c +++ b/drivers/remoteproc/qcom_q6v5_pas.c @@ -20,6 +20,7 @@ #include <linux/platform_device.h> #include <linux/pm_domain.h> #include <linux/pm_runtime.h> +#include <linux/firmware/qcom/qcom_pas.h> #include <linux/firmware/qcom/qcom_scm.h> #include <linux/regulator/consumer.h> #include <linux/remoteproc.h> @@ -118,8 +119,8 @@ struct qcom_pas { struct qcom_rproc_ssr ssr_subdev; struct qcom_sysmon *sysmon;
- struct qcom_scm_pas_context *pas_ctx; - struct qcom_scm_pas_context *dtb_pas_ctx; + struct qcom_pas_context *pas_ctx; + struct qcom_pas_context *dtb_pas_ctx; };
static void qcom_pas_segment_dump(struct rproc *rproc, @@ -196,7 +197,7 @@ static int qcom_pas_shutdown_poll_decrypt(struct qcom_pas *pas)
do { msleep(QCOM_PAS_DECRYPT_SHUTDOWN_DELAY_MS); - ret = qcom_scm_pas_shutdown(pas->pas_id); + ret = qcom_pas_shutdown(pas->pas_id); } while (ret == -EINVAL && --retry_num);
return ret; @@ -212,9 +213,9 @@ static int qcom_pas_unprepare(struct rproc *rproc) * auth_and_reset() was successful, but in other cases clean it up * here. */ - qcom_scm_pas_metadata_release(pas->pas_ctx); + qcom_pas_metadata_release(pas->pas_ctx); if (pas->dtb_pas_id) - qcom_scm_pas_metadata_release(pas->dtb_pas_ctx); + qcom_pas_metadata_release(pas->dtb_pas_ctx);
return 0; } @@ -228,9 +229,9 @@ static int qcom_pas_load(struct rproc *rproc, const struct firmware *fw) pas->firmware = fw;
if (pas->lite_pas_id) - qcom_scm_pas_shutdown(pas->lite_pas_id); + qcom_pas_shutdown(pas->lite_pas_id); if (pas->lite_dtb_pas_id) - qcom_scm_pas_shutdown(pas->lite_dtb_pas_id); + qcom_pas_shutdown(pas->lite_dtb_pas_id);
if (pas->dtb_pas_id) { ret = request_firmware(&pas->dtb_firmware, pas->dtb_firmware_name, pas->dev); @@ -250,7 +251,7 @@ static int qcom_pas_load(struct rproc *rproc, const struct firmware *fw) return 0;
release_dtb_metadata: - qcom_scm_pas_metadata_release(pas->dtb_pas_ctx); + qcom_pas_metadata_release(pas->dtb_pas_ctx); release_firmware(pas->dtb_firmware);
return ret; @@ -310,7 +311,7 @@ static int qcom_pas_start(struct rproc *rproc) if (ret) goto disable_px_supply;
- ret = qcom_scm_pas_prepare_and_auth_reset(pas->dtb_pas_ctx); + ret = qcom_pas_prepare_and_auth_reset(pas->dtb_pas_ctx); if (ret) { dev_err(pas->dev, "failed to authenticate dtb image and release reset\n"); @@ -329,7 +330,7 @@ static int qcom_pas_start(struct rproc *rproc) if (ret) goto release_pas_metadata;
- ret = qcom_scm_pas_prepare_and_auth_reset(pas->pas_ctx); + ret = qcom_pas_prepare_and_auth_reset(pas->pas_ctx); if (ret) { dev_err(pas->dev, "failed to authenticate image and release reset\n"); @@ -339,13 +340,13 @@ static int qcom_pas_start(struct rproc *rproc) ret = qcom_q6v5_wait_for_start(&pas->q6v5, msecs_to_jiffies(5000)); if (ret == -ETIMEDOUT) { dev_err(pas->dev, "start timed out\n"); - qcom_scm_pas_shutdown(pas->pas_id); + qcom_pas_shutdown(pas->pas_id); goto unmap_carveout; }
- qcom_scm_pas_metadata_release(pas->pas_ctx); + qcom_pas_metadata_release(pas->pas_ctx); if (pas->dtb_pas_id) - qcom_scm_pas_metadata_release(pas->dtb_pas_ctx); + qcom_pas_metadata_release(pas->dtb_pas_ctx);
/* firmware is used to pass reference from qcom_pas_start(), drop it now */ pas->firmware = NULL; @@ -355,9 +356,9 @@ static int qcom_pas_start(struct rproc *rproc) unmap_carveout: qcom_pas_unmap_carveout(rproc, pas->mem_phys, pas->mem_size); release_pas_metadata: - qcom_scm_pas_metadata_release(pas->pas_ctx); + qcom_pas_metadata_release(pas->pas_ctx); if (pas->dtb_pas_id) - qcom_scm_pas_metadata_release(pas->dtb_pas_ctx); + qcom_pas_metadata_release(pas->dtb_pas_ctx);
unmap_dtb_carveout: if (pas->dtb_pas_id) @@ -406,7 +407,7 @@ static int qcom_pas_stop(struct rproc *rproc) if (ret == -ETIMEDOUT) dev_err(pas->dev, "timed out on wait\n");
- ret = qcom_scm_pas_shutdown(pas->pas_id); + ret = qcom_pas_shutdown(pas->pas_id); if (ret && pas->decrypt_shutdown) ret = qcom_pas_shutdown_poll_decrypt(pas);
@@ -414,7 +415,7 @@ static int qcom_pas_stop(struct rproc *rproc) dev_err(pas->dev, "failed to shutdown: %d\n", ret);
if (pas->dtb_pas_id) { - ret = qcom_scm_pas_shutdown(pas->dtb_pas_id); + ret = qcom_pas_shutdown(pas->dtb_pas_id); if (ret) dev_err(pas->dev, "failed to shutdown dtb: %d\n", ret);
@@ -484,11 +485,11 @@ static int qcom_pas_parse_firmware(struct rproc *rproc, const struct firmware *f * * Here, we call rproc_elf_load_rsc_table() to check firmware binary has resources * or not and if it is not having then we pass NULL and zero as input resource - * table pointer and size respectively to the argument of qcom_scm_pas_get_rsc_table() + * table pointer and size respectively to the argument of qcom_pas_get_rsc_table() * and this is even true for Qualcomm remote processor who does follow remoteproc * framework. */ - output_rt = qcom_scm_pas_get_rsc_table(pas->pas_ctx, table, table_sz, &output_rt_size); + output_rt = qcom_pas_get_rsc_table(pas->pas_ctx, table, table_sz, &output_rt_size); ret = IS_ERR(output_rt) ? PTR_ERR(output_rt) : 0; if (ret) { dev_err(pas->dev, "Error in getting resource table: %d\n", ret); @@ -746,7 +747,7 @@ static int qcom_pas_probe(struct platform_device *pdev) if (!desc) return -EINVAL;
- if (!qcom_scm_is_available()) + if (!qcom_pas_is_available()) return -EPROBE_DEFER;
fw_name = desc->firmware_name; @@ -838,16 +839,16 @@ static int qcom_pas_probe(struct platform_device *pdev)
qcom_add_ssr_subdev(rproc, &pas->ssr_subdev, desc->ssr_name);
- pas->pas_ctx = devm_qcom_scm_pas_context_alloc(pas->dev, pas->pas_id, - pas->mem_phys, pas->mem_size); + pas->pas_ctx = devm_qcom_pas_context_alloc(pas->dev, pas->pas_id, + pas->mem_phys, pas->mem_size); if (IS_ERR(pas->pas_ctx)) { ret = PTR_ERR(pas->pas_ctx); goto remove_ssr_sysmon; }
- pas->dtb_pas_ctx = devm_qcom_scm_pas_context_alloc(pas->dev, pas->dtb_pas_id, - pas->dtb_mem_phys, - pas->dtb_mem_size); + pas->dtb_pas_ctx = devm_qcom_pas_context_alloc(pas->dev, pas->dtb_pas_id, + pas->dtb_mem_phys, + pas->dtb_mem_size); if (IS_ERR(pas->dtb_pas_ctx)) { ret = PTR_ERR(pas->dtb_pas_ctx); goto remove_ssr_sysmon;
From: Sumit Garg sumit.garg@oss.qualcomm.com
Switch qcom_q6v5_mss client driver over to generic PAS TZ APIs. Generic PAS TZ service allows to support multiple TZ implementation backends like QTEE based SCM PAS service, OP-TEE based PAS service and any further future TZ backend service.
Signed-off-by: Sumit Garg sumit.garg@oss.qualcomm.com --- drivers/remoteproc/qcom_q6v5_mss.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/drivers/remoteproc/qcom_q6v5_mss.c b/drivers/remoteproc/qcom_q6v5_mss.c index 91940977ca89..4d81b4af097f 100644 --- a/drivers/remoteproc/qcom_q6v5_mss.c +++ b/drivers/remoteproc/qcom_q6v5_mss.c @@ -34,6 +34,7 @@ #include "qcom_pil_info.h" #include "qcom_q6v5.h"
+#include <linux/firmware/qcom/qcom_pas.h> #include <linux/firmware/qcom/qcom_scm.h>
#define MPSS_CRASH_REASON_SMEM 421 @@ -1442,7 +1443,7 @@ static int q6v5_mpss_load(struct q6v5 *qproc) }
if (qproc->version == MSS_MSM8953) { - ret = qcom_scm_pas_mem_setup(MPSS_PAS_ID, qproc->mpss_phys, qproc->mpss_size); + ret = qcom_pas_mem_setup(MPSS_PAS_ID, qproc->mpss_phys, qproc->mpss_size); if (ret) { dev_err(qproc->dev, "setting up mpss memory failed: %d\n", ret); @@ -2039,7 +2040,7 @@ static int q6v5_probe(struct platform_device *pdev) if (!desc) return -EINVAL;
- if (desc->need_mem_protection && !qcom_scm_is_available()) + if (desc->need_mem_protection && !qcom_pas_is_available()) return -EPROBE_DEFER;
mba_image = desc->hexagon_mba_image;
From: Sumit Garg sumit.garg@oss.qualcomm.com
Switch mdtloader client driver over to generic PAS TZ APIs. Generic PAS TZ service allows to support multiple TZ implementation backends like QTEE based SCM PAS service, OP-TEE based PAS service and any further future TZ backend service.
Signed-off-by: Sumit Garg sumit.garg@oss.qualcomm.com --- drivers/soc/qcom/mdt_loader.c | 12 ++++++------ include/linux/soc/qcom/mdt_loader.h | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/drivers/soc/qcom/mdt_loader.c b/drivers/soc/qcom/mdt_loader.c index c004d444d698..fdde7eda538a 100644 --- a/drivers/soc/qcom/mdt_loader.c +++ b/drivers/soc/qcom/mdt_loader.c @@ -13,7 +13,7 @@ #include <linux/firmware.h> #include <linux/kernel.h> #include <linux/module.h> -#include <linux/firmware/qcom/qcom_scm.h> +#include <linux/firmware/qcom/qcom_pas.h> #include <linux/sizes.h> #include <linux/slab.h> #include <linux/soc/qcom/mdt_loader.h> @@ -229,7 +229,7 @@ EXPORT_SYMBOL_GPL(qcom_mdt_read_metadata);
static int __qcom_mdt_pas_init(struct device *dev, const struct firmware *fw, const char *fw_name, int pas_id, phys_addr_t mem_phys, - struct qcom_scm_pas_context *ctx) + struct qcom_pas_context *ctx) { const struct elf32_phdr *phdrs; const struct elf32_phdr *phdr; @@ -271,7 +271,7 @@ static int __qcom_mdt_pas_init(struct device *dev, const struct firmware *fw, goto out; }
- ret = qcom_scm_pas_init_image(pas_id, metadata, metadata_len, ctx); + ret = qcom_pas_init_image(pas_id, metadata, metadata_len, ctx); kfree(metadata); if (ret) { /* Invalid firmware metadata */ @@ -280,7 +280,7 @@ static int __qcom_mdt_pas_init(struct device *dev, const struct firmware *fw, }
if (relocate) { - ret = qcom_scm_pas_mem_setup(pas_id, mem_phys, max_addr - min_addr); + ret = qcom_pas_mem_setup(pas_id, mem_phys, max_addr - min_addr); if (ret) { /* Unable to set up relocation */ dev_err(dev, "error %d setting up firmware %s\n", ret, fw_name); @@ -472,7 +472,7 @@ EXPORT_SYMBOL_GPL(qcom_mdt_load); * firmware segments (e.g., .bXX files). Authentication of the segments done * by a separate call. * - * The PAS context must be initialized using qcom_scm_pas_context_init() + * The PAS context must be initialized using qcom_pas_context_init() * prior to invoking this function. * * @ctx: Pointer to the PAS (Peripheral Authentication Service) context @@ -483,7 +483,7 @@ EXPORT_SYMBOL_GPL(qcom_mdt_load); * * Return: 0 on success or a negative error code on failure. */ -int qcom_mdt_pas_load(struct qcom_scm_pas_context *ctx, const struct firmware *fw, +int qcom_mdt_pas_load(struct qcom_pas_context *ctx, const struct firmware *fw, const char *firmware, void *mem_region, phys_addr_t *reloc_base) { int ret; diff --git a/include/linux/soc/qcom/mdt_loader.h b/include/linux/soc/qcom/mdt_loader.h index 82372e0db0a1..142409555425 100644 --- a/include/linux/soc/qcom/mdt_loader.h +++ b/include/linux/soc/qcom/mdt_loader.h @@ -10,7 +10,7 @@
struct device; struct firmware; -struct qcom_scm_pas_context; +struct qcom_pas_context;
#if IS_ENABLED(CONFIG_QCOM_MDT_LOADER)
@@ -20,7 +20,7 @@ int qcom_mdt_load(struct device *dev, const struct firmware *fw, phys_addr_t mem_phys, size_t mem_size, phys_addr_t *reloc_base);
-int qcom_mdt_pas_load(struct qcom_scm_pas_context *ctx, const struct firmware *fw, +int qcom_mdt_pas_load(struct qcom_pas_context *ctx, const struct firmware *fw, const char *firmware, void *mem_region, phys_addr_t *reloc_base);
int qcom_mdt_load_no_init(struct device *dev, const struct firmware *fw, @@ -45,7 +45,7 @@ static inline int qcom_mdt_load(struct device *dev, const struct firmware *fw, return -ENODEV; }
-static inline int qcom_mdt_pas_load(struct qcom_scm_pas_context *ctx, +static inline int qcom_mdt_pas_load(struct qcom_pas_context *ctx, const struct firmware *fw, const char *firmware, void *mem_region, phys_addr_t *reloc_base) {
From: Sumit Garg sumit.garg@oss.qualcomm.com
Switch qcom_wcnss client driver over to generic PAS TZ APIs. Generic PAS TZ service allows to support multiple TZ implementation backends like QTEE based SCM PAS service, OP-TEE based PAS service and any further future TZ backend service.
Signed-off-by: Sumit Garg sumit.garg@oss.qualcomm.com --- drivers/remoteproc/qcom_wcnss.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/drivers/remoteproc/qcom_wcnss.c b/drivers/remoteproc/qcom_wcnss.c index ee18bf2e8054..1fd9344b0956 100644 --- a/drivers/remoteproc/qcom_wcnss.c +++ b/drivers/remoteproc/qcom_wcnss.c @@ -19,7 +19,7 @@ #include <linux/platform_device.h> #include <linux/pm_domain.h> #include <linux/pm_runtime.h> -#include <linux/firmware/qcom/qcom_scm.h> +#include <linux/firmware/qcom/qcom_pas.h> #include <linux/regulator/consumer.h> #include <linux/remoteproc.h> #include <linux/soc/qcom/mdt_loader.h> @@ -257,7 +257,7 @@ static int wcnss_start(struct rproc *rproc) wcnss_indicate_nv_download(wcnss); wcnss_configure_iris(wcnss);
- ret = qcom_scm_pas_auth_and_reset(WCNSS_PAS_ID); + ret = qcom_pas_auth_and_reset(WCNSS_PAS_ID); if (ret) { dev_err(wcnss->dev, "failed to authenticate image and release reset\n"); @@ -269,7 +269,7 @@ static int wcnss_start(struct rproc *rproc) if (wcnss->ready_irq > 0 && ret == 0) { /* We have a ready_irq, but it didn't fire in time. */ dev_err(wcnss->dev, "start timed out\n"); - qcom_scm_pas_shutdown(WCNSS_PAS_ID); + qcom_pas_shutdown(WCNSS_PAS_ID); ret = -ETIMEDOUT; goto disable_iris; } @@ -311,7 +311,7 @@ static int wcnss_stop(struct rproc *rproc) 0); }
- ret = qcom_scm_pas_shutdown(WCNSS_PAS_ID); + ret = qcom_pas_shutdown(WCNSS_PAS_ID); if (ret) dev_err(wcnss->dev, "failed to shutdown: %d\n", ret);
@@ -557,10 +557,10 @@ static int wcnss_probe(struct platform_device *pdev)
data = of_device_get_match_data(&pdev->dev);
- if (!qcom_scm_is_available()) + if (!qcom_pas_is_available()) return -EPROBE_DEFER;
- if (!qcom_scm_pas_supported(WCNSS_PAS_ID)) { + if (!qcom_pas_supported(WCNSS_PAS_ID)) { dev_err(&pdev->dev, "PAS is not available for WCNSS\n"); return -ENXIO; }
From: Sumit Garg sumit.garg@oss.qualcomm.com
Select PAS TEE service backend driver for the generic PAS service to enable support for OP-TEE based PAS service.
Signed-off-by: Sumit Garg sumit.garg@oss.qualcomm.com --- drivers/remoteproc/Kconfig | 1 + 1 file changed, 1 insertion(+)
diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig index ee54436fea5a..0411a38530d8 100644 --- a/drivers/remoteproc/Kconfig +++ b/drivers/remoteproc/Kconfig @@ -230,6 +230,7 @@ config QCOM_Q6V5_PAS select QCOM_Q6V5_COMMON select QCOM_RPROC_COMMON select QCOM_SCM + select QCOM_PAS_TEE help Say y here to support the TrustZone based Peripheral Image Loader for the Qualcomm remote processors. This is commonly used to control
From: Sumit Garg sumit.garg@oss.qualcomm.com
Switch drm/msm client drivers over to generic PAS TZ APIs. Generic PAS TZ service allows to support multiple TZ implementation backends like QTEE based SCM PAS service, OP-TEE based PAS service and any further future TZ backend service.
Signed-off-by: Sumit Garg sumit.garg@oss.qualcomm.com --- drivers/gpu/drm/msm/adreno/a5xx_gpu.c | 4 ++-- drivers/gpu/drm/msm/adreno/adreno_gpu.c | 11 ++++++----- 2 files changed, 8 insertions(+), 7 deletions(-)
diff --git a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c index ef9fd6171af7..3283852f9a14 100644 --- a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c @@ -5,7 +5,7 @@ #include <linux/kernel.h> #include <linux/types.h> #include <linux/cpumask.h> -#include <linux/firmware/qcom/qcom_scm.h> +#include <linux/firmware/qcom/qcom_pas.h> #include <linux/pm_opp.h> #include <linux/nvmem-consumer.h> #include <linux/slab.h> @@ -653,7 +653,7 @@ static int a5xx_zap_shader_resume(struct msm_gpu *gpu) if (adreno_is_a506(adreno_gpu)) return 0;
- ret = qcom_scm_set_remote_state(SCM_GPU_ZAP_SHADER_RESUME, GPU_PAS_ID); + ret = qcom_pas_set_remote_state(SCM_GPU_ZAP_SHADER_RESUME, GPU_PAS_ID); if (ret) DRM_ERROR("%s: zap-shader resume failed: %d\n", gpu->name, ret); diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c index d5fe6f6f0dec..047df0393128 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c @@ -8,6 +8,7 @@
#include <linux/ascii85.h> #include <linux/interconnect.h> +#include <linux/firmware/qcom/qcom_pas.h> #include <linux/firmware/qcom/qcom_scm.h> #include <linux/kernel.h> #include <linux/of_reserved_mem.h> @@ -146,10 +147,10 @@ static int zap_shader_load_mdt(struct msm_gpu *gpu, const char *fwname, goto out;
/* Send the image to the secure world */ - ret = qcom_scm_pas_auth_and_reset(pasid); + ret = qcom_pas_auth_and_reset(pasid);
/* - * If the scm call returns -EOPNOTSUPP we assume that this target + * If the pas call returns -EOPNOTSUPP we assume that this target * doesn't need/support the zap shader so quietly fail */ if (ret == -EOPNOTSUPP) @@ -175,9 +176,9 @@ int adreno_zap_shader_load(struct msm_gpu *gpu, u32 pasid) if (!zap_available) return -ENODEV;
- /* We need SCM to be able to load the firmware */ - if (!qcom_scm_is_available()) { - DRM_DEV_ERROR(&pdev->dev, "SCM is not available\n"); + /* We need PAS to be able to load the firmware */ + if (!qcom_pas_is_available()) { + DRM_DEV_ERROR(&pdev->dev, "Qcom PAS is not available\n"); return -EPROBE_DEFER; }
From: Sumit Garg sumit.garg@oss.qualcomm.com
Switch qcom media client drivers over to generic PAS TZ APIs. Generic PAS TZ service allows to support multiple TZ implementation backends like QTEE based SCM PAS service, OP-TEE based PAS service and any further future TZ backend service.
Signed-off-by: Sumit Garg sumit.garg@oss.qualcomm.com --- drivers/media/platform/qcom/iris/iris_firmware.c | 9 +++++---- drivers/media/platform/qcom/venus/firmware.c | 11 ++++++----- 2 files changed, 11 insertions(+), 9 deletions(-)
diff --git a/drivers/media/platform/qcom/iris/iris_firmware.c b/drivers/media/platform/qcom/iris/iris_firmware.c index 5f408024e967..b3c5281aea91 100644 --- a/drivers/media/platform/qcom/iris/iris_firmware.c +++ b/drivers/media/platform/qcom/iris/iris_firmware.c @@ -4,6 +4,7 @@ */
#include <linux/firmware.h> +#include <linux/firmware/qcom/qcom_pas.h> #include <linux/firmware/qcom/qcom_scm.h> #include <linux/of_address.h> #include <linux/of_reserved_mem.h> @@ -79,7 +80,7 @@ int iris_fw_load(struct iris_core *core) return -ENOMEM; }
- ret = qcom_scm_pas_auth_and_reset(core->iris_platform_data->pas_id); + ret = qcom_pas_auth_and_reset(core->iris_platform_data->pas_id); if (ret) { dev_err(core->dev, "auth and reset failed: %d\n", ret); return ret; @@ -93,7 +94,7 @@ int iris_fw_load(struct iris_core *core) cp_config->cp_nonpixel_size); if (ret) { dev_err(core->dev, "qcom_scm_mem_protect_video_var failed: %d\n", ret); - qcom_scm_pas_shutdown(core->iris_platform_data->pas_id); + qcom_pas_shutdown(core->iris_platform_data->pas_id); return ret; } } @@ -103,10 +104,10 @@ int iris_fw_load(struct iris_core *core)
int iris_fw_unload(struct iris_core *core) { - return qcom_scm_pas_shutdown(core->iris_platform_data->pas_id); + return qcom_pas_shutdown(core->iris_platform_data->pas_id); }
int iris_set_hw_state(struct iris_core *core, bool resume) { - return qcom_scm_set_remote_state(resume, 0); + return qcom_pas_set_remote_state(resume, 0); } diff --git a/drivers/media/platform/qcom/venus/firmware.c b/drivers/media/platform/qcom/venus/firmware.c index 1de7436713ed..3a38ff985822 100644 --- a/drivers/media/platform/qcom/venus/firmware.c +++ b/drivers/media/platform/qcom/venus/firmware.c @@ -12,6 +12,7 @@ #include <linux/of_reserved_mem.h> #include <linux/platform_device.h> #include <linux/of_device.h> +#include <linux/firmware/qcom/qcom_pas.h> #include <linux/firmware/qcom/qcom_scm.h> #include <linux/sizes.h> #include <linux/soc/qcom/mdt_loader.h> @@ -58,7 +59,7 @@ int venus_set_hw_state(struct venus_core *core, bool resume) int ret;
if (core->use_tz) { - ret = qcom_scm_set_remote_state(resume, 0); + ret = qcom_pas_set_remote_state(resume, 0); if (resume && ret == -EINVAL) ret = 0; return ret; @@ -218,7 +219,7 @@ int venus_boot(struct venus_core *core) int ret;
if (!IS_ENABLED(CONFIG_QCOM_MDT_LOADER) || - (core->use_tz && !qcom_scm_is_available())) + (core->use_tz && !qcom_pas_is_available())) return -EPROBE_DEFER;
ret = of_property_read_string_index(dev->of_node, "firmware-name", 0, @@ -236,7 +237,7 @@ int venus_boot(struct venus_core *core) core->fw.mem_phys = mem_phys;
if (core->use_tz) - ret = qcom_scm_pas_auth_and_reset(VENUS_PAS_ID); + ret = qcom_pas_auth_and_reset(VENUS_PAS_ID); else ret = venus_boot_no_tz(core, mem_phys, mem_size);
@@ -259,7 +260,7 @@ int venus_boot(struct venus_core *core) res->cp_nonpixel_start, res->cp_nonpixel_size); if (ret) { - qcom_scm_pas_shutdown(VENUS_PAS_ID); + qcom_pas_shutdown(VENUS_PAS_ID); dev_err(dev, "set virtual address ranges fail (%d)\n", ret); return ret; @@ -274,7 +275,7 @@ int venus_shutdown(struct venus_core *core) int ret;
if (core->use_tz) - ret = qcom_scm_pas_shutdown(VENUS_PAS_ID); + ret = qcom_pas_shutdown(VENUS_PAS_ID); else ret = venus_shutdown_no_tz(core);
On 06/03/26 16:20:24, Sumit Garg wrote:
From: Sumit Garg sumit.garg@oss.qualcomm.com
Switch qcom media client drivers over to generic PAS TZ APIs. Generic PAS TZ service allows to support multiple TZ implementation backends like QTEE based SCM PAS service, OP-TEE based PAS service and any further future TZ backend service.
Signed-off-by: Sumit Garg sumit.garg@oss.qualcomm.com
drivers/media/platform/qcom/iris/iris_firmware.c | 9 +++++---- drivers/media/platform/qcom/venus/firmware.c | 11 ++++++----- 2 files changed, 11 insertions(+), 9 deletions(-)
diff --git a/drivers/media/platform/qcom/iris/iris_firmware.c b/drivers/media/platform/qcom/iris/iris_firmware.c index 5f408024e967..b3c5281aea91 100644 --- a/drivers/media/platform/qcom/iris/iris_firmware.c +++ b/drivers/media/platform/qcom/iris/iris_firmware.c @@ -4,6 +4,7 @@ */ #include <linux/firmware.h> +#include <linux/firmware/qcom/qcom_pas.h> #include <linux/firmware/qcom/qcom_scm.h> #include <linux/of_address.h> #include <linux/of_reserved_mem.h> @@ -79,7 +80,7 @@ int iris_fw_load(struct iris_core *core) return -ENOMEM; }
- ret = qcom_scm_pas_auth_and_reset(core->iris_platform_data->pas_id);
- ret = qcom_pas_auth_and_reset(core->iris_platform_data->pas_id); if (ret) { dev_err(core->dev, "auth and reset failed: %d\n", ret); return ret;
@@ -93,7 +94,7 @@ int iris_fw_load(struct iris_core *core) cp_config->cp_nonpixel_size); if (ret) { dev_err(core->dev, "qcom_scm_mem_protect_video_var failed: %d\n", ret);
qcom_scm_pas_shutdown(core->iris_platform_data->pas_id);
} }qcom_pas_shutdown(core->iris_platform_data->pas_id); return ret;@@ -103,10 +104,10 @@ int iris_fw_load(struct iris_core *core) int iris_fw_unload(struct iris_core *core) {
- return qcom_scm_pas_shutdown(core->iris_platform_data->pas_id);
- return qcom_pas_shutdown(core->iris_platform_data->pas_id);
}
are the calls to set_remote_state required? 0 is not the IRIS/VENUS remote processor.
If it is legacy, maybe they can be phased out?
int iris_set_hw_state(struct iris_core *core, bool resume) {
- return qcom_scm_set_remote_state(resume, 0);
- return qcom_pas_set_remote_state(resume, 0);
} diff --git a/drivers/media/platform/qcom/venus/firmware.c b/drivers/media/platform/qcom/venus/firmware.c index 1de7436713ed..3a38ff985822 100644 --- a/drivers/media/platform/qcom/venus/firmware.c +++ b/drivers/media/platform/qcom/venus/firmware.c @@ -12,6 +12,7 @@ #include <linux/of_reserved_mem.h> #include <linux/platform_device.h> #include <linux/of_device.h> +#include <linux/firmware/qcom/qcom_pas.h> #include <linux/firmware/qcom/qcom_scm.h> #include <linux/sizes.h> #include <linux/soc/qcom/mdt_loader.h> @@ -58,7 +59,7 @@ int venus_set_hw_state(struct venus_core *core, bool resume) int ret; if (core->use_tz) {
ret = qcom_scm_set_remote_state(resume, 0);
if (resume && ret == -EINVAL) ret = 0; return ret;ret = qcom_pas_set_remote_state(resume, 0);
On Mon, Mar 09, 2026 at 10:12:06AM +0100, Jorge Ramirez wrote:
On 06/03/26 16:20:24, Sumit Garg wrote:
From: Sumit Garg sumit.garg@oss.qualcomm.com
Switch qcom media client drivers over to generic PAS TZ APIs. Generic PAS TZ service allows to support multiple TZ implementation backends like QTEE based SCM PAS service, OP-TEE based PAS service and any further future TZ backend service.
Signed-off-by: Sumit Garg sumit.garg@oss.qualcomm.com
drivers/media/platform/qcom/iris/iris_firmware.c | 9 +++++---- drivers/media/platform/qcom/venus/firmware.c | 11 ++++++----- 2 files changed, 11 insertions(+), 9 deletions(-)
diff --git a/drivers/media/platform/qcom/iris/iris_firmware.c b/drivers/media/platform/qcom/iris/iris_firmware.c index 5f408024e967..b3c5281aea91 100644 --- a/drivers/media/platform/qcom/iris/iris_firmware.c +++ b/drivers/media/platform/qcom/iris/iris_firmware.c @@ -4,6 +4,7 @@ */ #include <linux/firmware.h> +#include <linux/firmware/qcom/qcom_pas.h> #include <linux/firmware/qcom/qcom_scm.h> #include <linux/of_address.h> #include <linux/of_reserved_mem.h> @@ -79,7 +80,7 @@ int iris_fw_load(struct iris_core *core) return -ENOMEM; }
- ret = qcom_scm_pas_auth_and_reset(core->iris_platform_data->pas_id);
- ret = qcom_pas_auth_and_reset(core->iris_platform_data->pas_id); if (ret) { dev_err(core->dev, "auth and reset failed: %d\n", ret); return ret;
@@ -93,7 +94,7 @@ int iris_fw_load(struct iris_core *core) cp_config->cp_nonpixel_size); if (ret) { dev_err(core->dev, "qcom_scm_mem_protect_video_var failed: %d\n", ret);
qcom_scm_pas_shutdown(core->iris_platform_data->pas_id);
} }qcom_pas_shutdown(core->iris_platform_data->pas_id); return ret;@@ -103,10 +104,10 @@ int iris_fw_load(struct iris_core *core) int iris_fw_unload(struct iris_core *core) {
- return qcom_scm_pas_shutdown(core->iris_platform_data->pas_id);
- return qcom_pas_shutdown(core->iris_platform_data->pas_id);
}
are the calls to set_remote_state required? 0 is not the IRIS/VENUS remote processor.
If it is legacy, maybe they can be phased out?
Vikash, Dikshita,
Do you know the background of this set_remote_state calls?
BTW, the scope of this patch-set is to not change existing subsystem drivers behaviour but just to enable the generic PAS interface. So any driver changes can be taken as a follow up work.
-Sumit
int iris_set_hw_state(struct iris_core *core, bool resume) {
- return qcom_scm_set_remote_state(resume, 0);
- return qcom_pas_set_remote_state(resume, 0);
} diff --git a/drivers/media/platform/qcom/venus/firmware.c b/drivers/media/platform/qcom/venus/firmware.c index 1de7436713ed..3a38ff985822 100644 --- a/drivers/media/platform/qcom/venus/firmware.c +++ b/drivers/media/platform/qcom/venus/firmware.c @@ -12,6 +12,7 @@ #include <linux/of_reserved_mem.h> #include <linux/platform_device.h> #include <linux/of_device.h> +#include <linux/firmware/qcom/qcom_pas.h> #include <linux/firmware/qcom/qcom_scm.h> #include <linux/sizes.h> #include <linux/soc/qcom/mdt_loader.h> @@ -58,7 +59,7 @@ int venus_set_hw_state(struct venus_core *core, bool resume) int ret; if (core->use_tz) {
ret = qcom_scm_set_remote_state(resume, 0);
if (resume && ret == -EINVAL) ret = 0; return ret;ret = qcom_pas_set_remote_state(resume, 0);
On 3/9/26 10:12 AM, Jorge Ramirez wrote:
On 06/03/26 16:20:24, Sumit Garg wrote:
From: Sumit Garg sumit.garg@oss.qualcomm.com
Switch qcom media client drivers over to generic PAS TZ APIs. Generic PAS TZ service allows to support multiple TZ implementation backends like QTEE based SCM PAS service, OP-TEE based PAS service and any further future TZ backend service.
Signed-off-by: Sumit Garg sumit.garg@oss.qualcomm.com
[...]
are the calls to set_remote_state required? 0 is not the IRIS/VENUS remote processor.
If it is legacy, maybe they can be phased out?
FWIW, in msm-3.10 (yes) QCOM_SCM_SVC_BOOT/0x0a used to be called 'TZBSP_VIDEO_SET_STATE', taking the arguments:
args[0] = suspend->0, resume->1 args[1] = spare=0
seems like sdm845/msm-4.9 still had that and so did 8250/msm-4.19
Konrad
On Tue, Mar 10, 2026 at 12:18:29PM +0100, Konrad Dybcio wrote:
On 3/9/26 10:12 AM, Jorge Ramirez wrote:
On 06/03/26 16:20:24, Sumit Garg wrote:
From: Sumit Garg sumit.garg@oss.qualcomm.com
Switch qcom media client drivers over to generic PAS TZ APIs. Generic PAS TZ service allows to support multiple TZ implementation backends like QTEE based SCM PAS service, OP-TEE based PAS service and any further future TZ backend service.
Signed-off-by: Sumit Garg sumit.garg@oss.qualcomm.com
[...]
are the calls to set_remote_state required? 0 is not the IRIS/VENUS remote processor.
If it is legacy, maybe they can be phased out?
FWIW, in msm-3.10 (yes) QCOM_SCM_SVC_BOOT/0x0a used to be called 'TZBSP_VIDEO_SET_STATE', taking the arguments:
args[0] = suspend->0, resume->1 args[1] = spare=0
seems like sdm845/msm-4.9 still had that and so did 8250/msm-4.19
I would assume passing actual PAS ID in that spare argument shouldn't cause any issues for QTEE as it could just ignore that. Let me try to see in my testing on RB3Gen2 if it causes any ABI issues. Since with OP-TEE we would like to not deal with ABI inconsistencies.
-Sumit
From: Sumit Garg sumit.garg@oss.qualcomm.com
Switch ipa client driver over to generic PAS TZ APIs. Generic PAS TZ service allows to support multiple TZ implementation backends like QTEE based SCM PAS service, OP-TEE based PAS service and any further future TZ backend service.
Signed-off-by: Sumit Garg sumit.garg@oss.qualcomm.com --- drivers/net/ipa/ipa_main.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-)
diff --git a/drivers/net/ipa/ipa_main.c b/drivers/net/ipa/ipa_main.c index edead9c48d1f..8feb8493d5b5 100644 --- a/drivers/net/ipa/ipa_main.c +++ b/drivers/net/ipa/ipa_main.c @@ -14,7 +14,7 @@ #include <linux/pm_runtime.h> #include <linux/types.h>
-#include <linux/firmware/qcom/qcom_scm.h> +#include <linux/firmware/qcom/qcom_pas.h> #include <linux/soc/qcom/mdt_loader.h>
#include "ipa.h" @@ -624,10 +624,13 @@ static int ipa_firmware_load(struct device *dev) }
ret = qcom_mdt_load(dev, fw, path, IPA_PAS_ID, virt, phys, size, NULL); - if (ret) + if (ret) { dev_err(dev, "error %d loading "%s"\n", ret, path); - else if ((ret = qcom_scm_pas_auth_and_reset(IPA_PAS_ID))) - dev_err(dev, "error %d authenticating "%s"\n", ret, path); + } else { + ret = qcom_pas_auth_and_reset(IPA_PAS_ID); + if (ret) + dev_err(dev, "error %d authenticating "%s"\n", ret, path); + }
memunmap(virt); out_release_firmware: @@ -754,7 +757,7 @@ static enum ipa_firmware_loader ipa_firmware_loader(struct device *dev) return IPA_LOADER_INVALID; out_self: /* We need Trust Zone to load firmware; make sure it's available */ - if (qcom_scm_is_available()) + if (qcom_pas_is_available()) return IPA_LOADER_SELF;
return IPA_LOADER_DEFER;
From: Sumit Garg sumit.garg@oss.qualcomm.com
Switch ath12k client driver over to generic PAS TZ APIs. Generic PAS TZ service allows to support multiple TZ implementation backends like QTEE based SCM PAS service, OP-TEE based PAS service and any further future TZ backend service.
Signed-off-by: Sumit Garg sumit.garg@oss.qualcomm.com --- drivers/net/wireless/ath/ath12k/ahb.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/net/wireless/ath/ath12k/ahb.c b/drivers/net/wireless/ath/ath12k/ahb.c index 9a4d34e49104..935f893d04ef 100644 --- a/drivers/net/wireless/ath/ath12k/ahb.c +++ b/drivers/net/wireless/ath/ath12k/ahb.c @@ -5,7 +5,7 @@ */
#include <linux/dma-mapping.h> -#include <linux/firmware/qcom/qcom_scm.h> +#include <linux/firmware/qcom/qcom_pas.h> #include <linux/of.h> #include <linux/of_device.h> #include <linux/platform_device.h> @@ -415,7 +415,7 @@ static int ath12k_ahb_power_up(struct ath12k_base *ab) }
/* Authenticate FW image using peripheral ID */ - ret = qcom_scm_pas_auth_and_reset(pasid); + ret = qcom_pas_auth_and_reset(pasid); if (ret) { ath12k_err(ab, "failed to boot the remote processor %d\n", ret); goto err_fw2; @@ -478,9 +478,9 @@ static void ath12k_ahb_power_down(struct ath12k_base *ab, bool is_suspend) pasid = (u32_encode_bits(ab_ahb->userpd_id, ATH12K_USERPD_ID_MASK)) | ATH12K_AHB_UPD_SWID; /* Release the firmware */ - ret = qcom_scm_pas_shutdown(pasid); + ret = qcom_pas_shutdown(pasid); if (ret) - ath12k_err(ab, "scm pas shutdown failed for userPD%d: %d\n", + ath12k_err(ab, "pas shutdown failed for userPD%d: %d\n", ab_ahb->userpd_id, ret); }
On 3/6/2026 2:50 AM, Sumit Garg wrote:
From: Sumit Garg sumit.garg@oss.qualcomm.com
Switch ath12k client driver over to generic PAS TZ APIs. Generic PAS TZ service allows to support multiple TZ implementation backends like QTEE based SCM PAS service, OP-TEE based PAS service and any further future TZ backend service.
Signed-off-by: Sumit Garg sumit.garg@oss.qualcomm.com
Acked-by: Jeff Johnson jjohnson@kernel.org
From: Sumit Garg sumit.garg@oss.qualcomm.com
Now since all the Qcom SCM client drivers have been migrated over to generic PAS TZ service, let's drop the exported SCM PAS wrappers.
Signed-off-by: Sumit Garg sumit.garg@oss.qualcomm.com --- drivers/firmware/qcom/qcom_scm.c | 84 -------------------------- include/linux/firmware/qcom/qcom_scm.h | 29 --------- 2 files changed, 113 deletions(-)
diff --git a/drivers/firmware/qcom/qcom_scm.c b/drivers/firmware/qcom/qcom_scm.c index 2d7937ae7c8f..ce68ed294d78 100644 --- a/drivers/firmware/qcom/qcom_scm.c +++ b/drivers/firmware/qcom/qcom_scm.c @@ -554,26 +554,6 @@ static void qcom_scm_set_download_mode(u32 dload_mode) dev_err(__scm->dev, "failed to set download mode: %d\n", ret); }
-struct qcom_scm_pas_context *devm_qcom_scm_pas_context_alloc(struct device *dev, - u32 pas_id, - phys_addr_t mem_phys, - size_t mem_size) -{ - struct qcom_pas_context *ctx; - - ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return ERR_PTR(-ENOMEM); - - ctx->dev = dev; - ctx->pas_id = pas_id; - ctx->mem_phys = mem_phys; - ctx->mem_size = mem_size; - - return (struct qcom_scm_pas_context *)ctx; -} -EXPORT_SYMBOL_GPL(devm_qcom_scm_pas_context_alloc); - static int __qcom_scm_pas_init_image(struct device *dev, u32 pas_id, dma_addr_t mdata_phys, struct qcom_scm_res *res) @@ -674,14 +654,6 @@ static int __qcom_scm_pas_init_image2(struct device *dev, u32 pas_id, return ret ? : res.result[0]; }
-int qcom_scm_pas_init_image(u32 pas_id, const void *metadata, size_t size, - struct qcom_scm_pas_context *ctx) -{ - return __qcom_scm_pas_init_image2(__scm->dev, pas_id, metadata, size, - (struct qcom_pas_context *)ctx); -} -EXPORT_SYMBOL_GPL(qcom_scm_pas_init_image); - static void __qcom_scm_pas_metadata_release(struct device *dev, struct qcom_pas_context *ctx) { @@ -693,13 +665,6 @@ static void __qcom_scm_pas_metadata_release(struct device *dev, ctx->ptr = NULL; }
-void qcom_scm_pas_metadata_release(struct qcom_scm_pas_context *ctx) -{ - __qcom_scm_pas_metadata_release(__scm->dev, - (struct qcom_pas_context *)ctx); -} -EXPORT_SYMBOL_GPL(qcom_scm_pas_metadata_release); - static int __qcom_scm_pas_mem_setup(struct device *dev, u32 pas_id, phys_addr_t addr, phys_addr_t size) { @@ -732,12 +697,6 @@ static int __qcom_scm_pas_mem_setup(struct device *dev, u32 pas_id, return ret ? : res.result[0]; }
-int qcom_scm_pas_mem_setup(u32 pas_id, phys_addr_t addr, phys_addr_t size) -{ - return __qcom_scm_pas_mem_setup(__scm->dev, pas_id, addr, size); -} -EXPORT_SYMBOL_GPL(qcom_scm_pas_mem_setup); - static void *__qcom_scm_pas_get_rsc_table(struct device *dev, u32 pas_id, void *input_rt_tzm, size_t input_rt_size, @@ -867,18 +826,6 @@ static void *__qcom_scm_pas_get_rsc_table2(struct device *dev, return ret ? ERR_PTR(ret) : tbl_ptr; }
-struct resource_table *qcom_scm_pas_get_rsc_table(struct qcom_scm_pas_context *ctx, - void *input_rt, - size_t input_rt_size, - size_t *output_rt_size) -{ - return __qcom_scm_pas_get_rsc_table2(__scm->dev, - (struct qcom_pas_context *)ctx, - input_rt, input_rt_size, - output_rt_size); -} -EXPORT_SYMBOL_GPL(qcom_scm_pas_get_rsc_table); - static int __qcom_scm_pas_auth_and_reset(struct device *dev, u32 pas_id) { int ret; @@ -908,12 +855,6 @@ static int __qcom_scm_pas_auth_and_reset(struct device *dev, u32 pas_id) return ret ? : res.result[0]; }
-int qcom_scm_pas_auth_and_reset(u32 pas_id) -{ - return __qcom_scm_pas_auth_and_reset(__scm->dev, pas_id); -} -EXPORT_SYMBOL_GPL(qcom_scm_pas_auth_and_reset); - static int __qcom_scm_pas_prepare_and_auth_reset(struct device *dev, struct qcom_pas_context *ctx) { @@ -942,13 +883,6 @@ static int __qcom_scm_pas_prepare_and_auth_reset(struct device *dev, return ret; }
-int qcom_scm_pas_prepare_and_auth_reset(struct qcom_scm_pas_context *ctx) -{ - return __qcom_scm_pas_prepare_and_auth_reset(__scm->dev, - (struct qcom_pas_context *)ctx); -} -EXPORT_SYMBOL_GPL(qcom_scm_pas_prepare_and_auth_reset); - static int __qcom_scm_pas_set_remote_state(struct device *dev, u32 state, u32 pas_id) { @@ -968,12 +902,6 @@ static int __qcom_scm_pas_set_remote_state(struct device *dev, u32 state, return ret ? : res.result[0]; }
-int qcom_scm_set_remote_state(u32 state, u32 id) -{ - return __qcom_scm_pas_set_remote_state(__scm->dev, state, id); -} -EXPORT_SYMBOL_GPL(qcom_scm_set_remote_state); - static int __qcom_scm_pas_shutdown(struct device *dev, u32 pas_id) { int ret; @@ -1003,12 +931,6 @@ static int __qcom_scm_pas_shutdown(struct device *dev, u32 pas_id) return ret ? : res.result[0]; }
-int qcom_scm_pas_shutdown(u32 pas_id) -{ - return __qcom_scm_pas_shutdown(__scm->dev, pas_id); -} -EXPORT_SYMBOL_GPL(qcom_scm_pas_shutdown); - static bool __qcom_scm_pas_supported(struct device *dev, u32 pas_id) { int ret; @@ -1030,12 +952,6 @@ static bool __qcom_scm_pas_supported(struct device *dev, u32 pas_id) return ret ? false : !!res.result[0]; }
-bool qcom_scm_pas_supported(u32 pas_id) -{ - return __qcom_scm_pas_supported(__scm->dev, pas_id); -} -EXPORT_SYMBOL_GPL(qcom_scm_pas_supported); - static struct qcom_pas_ops qcom_pas_ops_scm = { .drv_name = "qcom_scm", .supported = __qcom_scm_pas_supported, diff --git a/include/linux/firmware/qcom/qcom_scm.h b/include/linux/firmware/qcom/qcom_scm.h index 5747bd191bf1..a0a6bc0229c4 100644 --- a/include/linux/firmware/qcom/qcom_scm.h +++ b/include/linux/firmware/qcom/qcom_scm.h @@ -64,35 +64,6 @@ bool qcom_scm_is_available(void); int qcom_scm_set_cold_boot_addr(void *entry); int qcom_scm_set_warm_boot_addr(void *entry); void qcom_scm_cpu_power_down(u32 flags); -int qcom_scm_set_remote_state(u32 state, u32 id); - -struct qcom_scm_pas_context { - struct device *dev; - u32 pas_id; - phys_addr_t mem_phys; - size_t mem_size; - void *ptr; - dma_addr_t phys; - ssize_t size; - bool use_tzmem; -}; - -struct qcom_scm_pas_context *devm_qcom_scm_pas_context_alloc(struct device *dev, - u32 pas_id, - phys_addr_t mem_phys, - size_t mem_size); -int qcom_scm_pas_init_image(u32 pas_id, const void *metadata, size_t size, - struct qcom_scm_pas_context *ctx); -void qcom_scm_pas_metadata_release(struct qcom_scm_pas_context *ctx); -int qcom_scm_pas_mem_setup(u32 pas_id, phys_addr_t addr, phys_addr_t size); -int qcom_scm_pas_auth_and_reset(u32 pas_id); -int qcom_scm_pas_shutdown(u32 pas_id); -bool qcom_scm_pas_supported(u32 pas_id); -struct resource_table *qcom_scm_pas_get_rsc_table(struct qcom_scm_pas_context *ctx, - void *input_rt, size_t input_rt_size, - size_t *output_rt_size); - -int qcom_scm_pas_prepare_and_auth_reset(struct qcom_scm_pas_context *ctx);
int qcom_scm_io_readl(phys_addr_t addr, unsigned int *val); int qcom_scm_io_writel(phys_addr_t addr, unsigned int val);
op-tee@lists.trustedfirmware.org