mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-08-30 14:33:24 -04:00
Merge qcom PAS TZ service series (20260702115835.167602-2-sumit.garg@kernel.org)
Bjorn Andersson says: > 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. > > [...] Applied, thanks! [01/14] firmware: qcom: Add a generic PAS service commit:08314e7c2c[02/14] firmware: qcom_scm: Migrate to generic PAS service commit:5c1a2975d2[03/14] firmware: qcom: Add a PAS TEE service commit:b6f7978da0[14/14] MAINTAINERS: Add maintainer entry for Qualcomm PAS TZ service commit:6701259025This is available as an immutable branch, for other subsystems to pull at: https://git.kernel.org/pub/scm/linux/kernel/git/qcom/linux.git 20260702115835.167602-2-sumit.garg@kernel.org Link: https://lore.kernel.org/all/178362521364.2422497.1305957434056184382.b4-ty@kernel.org/
This commit is contained in:
@@ -22315,6 +22315,15 @@ F: Documentation/devicetree/bindings/media/*qcom*
|
||||
F: drivers/media/platform/qcom
|
||||
F: include/dt-bindings/media/*qcom*
|
||||
|
||||
QUALCOMM PAS TZ SERVICE
|
||||
M: Sumit Garg <sumit.garg@oss.qualcomm.com>
|
||||
L: linux-arm-msm@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/firmware/qcom/qcom_pas.c
|
||||
F: drivers/firmware/qcom/qcom_pas.h
|
||||
F: drivers/firmware/qcom/qcom_pas_tee.c
|
||||
F: include/linux/firmware/qcom/qcom_pas.h
|
||||
|
||||
QUALCOMM SMB CHARGER DRIVER
|
||||
M: Casey Connolly <casey.connolly@linaro.org>
|
||||
L: linux-arm-msm@vger.kernel.org
|
||||
|
||||
@@ -6,9 +6,29 @@
|
||||
|
||||
menu "Qualcomm firmware drivers"
|
||||
|
||||
config QCOM_PAS
|
||||
tristate "Qualcomm generic PAS interface driver"
|
||||
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_PAS_TEE
|
||||
tristate "Qualcomm PAS TEE interface driver"
|
||||
select QCOM_PAS
|
||||
depends on TEE
|
||||
depends on !CPU_BIG_ENDIAN
|
||||
default m if ARCH_QCOM
|
||||
help
|
||||
Enable the generic Peripheral Authentication Service (PAS) provided
|
||||
by the firmware TEE implementation as the backend.
|
||||
|
||||
config QCOM_SCM
|
||||
tristate "Qualcomm PAS SCM interface driver"
|
||||
select QCOM_PAS
|
||||
select QCOM_TZMEM
|
||||
tristate
|
||||
default y if ARCH_QCOM
|
||||
|
||||
config QCOM_TZMEM
|
||||
tristate
|
||||
|
||||
@@ -8,3 +8,5 @@ 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
|
||||
obj-$(CONFIG_QCOM_PAS_TEE) += qcom_pas_tee.o
|
||||
|
||||
298
drivers/firmware/qcom/qcom_pas.c
Normal file
298
drivers/firmware/qcom/qcom_pas.c
Normal file
@@ -0,0 +1,298 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (c) 2010,2015,2019 The Linux Foundation. All rights reserved.
|
||||
* Copyright (C) 2015 Linaro Ltd.
|
||||
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
|
||||
*/
|
||||
|
||||
#include <linux/device/devres.h>
|
||||
#include <linux/firmware/qcom/qcom_pas.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include "qcom_pas.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
|
||||
*
|
||||
* Return: 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 -ENODEV;
|
||||
|
||||
return ops_ptr->init_image(ops_ptr->dev, pas_id, metadata, size, ctx);
|
||||
}
|
||||
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 (!ops_ptr || !ctx || !ctx->ptr)
|
||||
return;
|
||||
|
||||
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
|
||||
*
|
||||
* Return: 0 on success.
|
||||
*/
|
||||
int qcom_pas_mem_setup(u32 pas_id, phys_addr_t addr, phys_addr_t size)
|
||||
{
|
||||
if (!ops_ptr)
|
||||
return -ENODEV;
|
||||
|
||||
return ops_ptr->mem_setup(ops_ptr->dev, pas_id, addr, size);
|
||||
}
|
||||
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
|
||||
* @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 ERR_PTR(-ENODEV);
|
||||
if (!ctx)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
return ops_ptr->get_rsc_table(ops_ptr->dev, ctx, input_rt,
|
||||
input_rt_size, output_rt_size);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qcom_pas_get_rsc_table);
|
||||
|
||||
/**
|
||||
* qcom_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 -ENODEV;
|
||||
|
||||
return ops_ptr->auth_and_reset(ops_ptr->dev, pas_id);
|
||||
}
|
||||
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 devm_qcom_pas_context_alloc()
|
||||
*
|
||||
* 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 -ENODEV;
|
||||
if (!ctx)
|
||||
return -EINVAL;
|
||||
|
||||
return ops_ptr->prepare_and_auth_reset(ops_ptr->dev, ctx);
|
||||
}
|
||||
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
|
||||
*
|
||||
* Return: 0 on success.
|
||||
*/
|
||||
int qcom_pas_set_remote_state(u32 state, u32 pas_id)
|
||||
{
|
||||
if (!ops_ptr)
|
||||
return -ENODEV;
|
||||
|
||||
return ops_ptr->set_remote_state(ops_ptr->dev, state, pas_id);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qcom_pas_set_remote_state);
|
||||
|
||||
/**
|
||||
* qcom_pas_shutdown() - Shut down the remote processor
|
||||
* @pas_id: peripheral authentication service id
|
||||
*
|
||||
* Return: 0 on success.
|
||||
*/
|
||||
int qcom_pas_shutdown(u32 pas_id)
|
||||
{
|
||||
if (!ops_ptr)
|
||||
return -ENODEV;
|
||||
|
||||
return ops_ptr->shutdown(ops_ptr->dev, pas_id);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qcom_pas_shutdown);
|
||||
|
||||
/**
|
||||
* qcom_pas_supported() - Check if the peripheral authentication service is
|
||||
* supported for the given peripheral
|
||||
* @pas_id: peripheral authentication service id
|
||||
*
|
||||
* Return: true if PAS is supported for this peripheral, otherwise false.
|
||||
*/
|
||||
bool qcom_pas_supported(u32 pas_id)
|
||||
{
|
||||
if (!ops_ptr)
|
||||
return false;
|
||||
|
||||
return ops_ptr->supported(ops_ptr->dev, pas_id);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qcom_pas_supported);
|
||||
|
||||
/**
|
||||
* qcom_pas_is_available() - Check if the peripheral authentication service is
|
||||
* available. Note that it is mandatory for any PAS
|
||||
* client to invoke this API. If it returns true then
|
||||
* only any other PAS API can be invoked.
|
||||
*
|
||||
* Return: true if PAS is available, otherwise false.
|
||||
*/
|
||||
bool qcom_pas_is_available(void)
|
||||
{
|
||||
/*
|
||||
* The barrier for ops_ptr is intended to synchronize the data stores
|
||||
* for the ops data structure when client drivers are in parallel
|
||||
* checking for PAS service availability.
|
||||
*
|
||||
* Once the PAS backend becomes available, it is allowed for multiple
|
||||
* threads to enter TZ for parallel bringup of co-processors during
|
||||
* boot.
|
||||
*/
|
||||
return !!smp_load_acquire(&ops_ptr);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qcom_pas_is_available);
|
||||
|
||||
void qcom_pas_ops_register(struct qcom_pas_ops *ops)
|
||||
{
|
||||
if (!qcom_pas_is_available())
|
||||
/* Paired with smp_load_acquire() in qcom_pas_is_available() */
|
||||
smp_store_release(&ops_ptr, ops);
|
||||
else
|
||||
pr_err("qcom_pas: ops already registered by %s\n",
|
||||
ops_ptr->drv_name);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qcom_pas_ops_register);
|
||||
|
||||
void qcom_pas_ops_unregister(void)
|
||||
{
|
||||
/* Paired with smp_load_acquire() in qcom_pas_is_available() */
|
||||
smp_store_release(&ops_ptr, NULL);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qcom_pas_ops_unregister);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("Qualcomm generic TZ PAS driver");
|
||||
50
drivers/firmware/qcom/qcom_pas.h
Normal file
50
drivers/firmware/qcom/qcom_pas.h
Normal file
@@ -0,0 +1,50 @@
|
||||
/* 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 */
|
||||
479
drivers/firmware/qcom/qcom_pas_tee.c
Normal file
479
drivers/firmware/qcom/qcom_pas_tee.c
Normal file
@@ -0,0 +1,479 @@
|
||||
// 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 TA_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 TA_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 TA_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 TA_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 TA_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 TA_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 TA_QCOM_PAS_SET_REMOTE_STATE 7
|
||||
|
||||
/*
|
||||
* PAS co-processor shutdown.
|
||||
*
|
||||
* [in] params[0].value.a: Unique 32bit remote processor identifier
|
||||
*/
|
||||
#define TA_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 = TA_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, ret: %d, err: 0x%x\n",
|
||||
pas_id, ret, 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 = TA_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, ret: %d, err: 0x%x\n",
|
||||
pas_id, ret, inv_arg.ret);
|
||||
tee_shm_free(mdata_shm);
|
||||
return ret ?: -EINVAL;
|
||||
}
|
||||
|
||||
if (ctx)
|
||||
ctx->ptr = (void *)mdata_shm;
|
||||
else
|
||||
tee_shm_free(mdata_shm);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
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 = TA_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, ret: %d, err: 0x%x\n",
|
||||
pas_id, ret, inv_arg.ret);
|
||||
return ret ?: -EINVAL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
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 = TA_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, ret: %d, err: 0x%x\n",
|
||||
ctx->pas_id, ret, inv_arg.ret);
|
||||
return ret ? ERR_PTR(ret) : ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
if (param[1].u.memref.size >= input_rt_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_OR_NULL(rt_shm)) {
|
||||
dev_err(dev, "rt_shm allocation failed\n");
|
||||
rt_shm = NULL;
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
rt_shm_va = tee_shm_get_va(rt_shm, 0);
|
||||
if (IS_ERR(rt_shm_va)) {
|
||||
dev_err(dev, "rt_shm get VA failed\n");
|
||||
return ERR_CAST(rt_shm_va);
|
||||
}
|
||||
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, ret: %d, err: 0x%x\n",
|
||||
ctx->pas_id, ret, inv_arg.ret);
|
||||
return ret ? ERR_PTR(ret) : ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
if (param[1].u.memref.size) {
|
||||
*output_rt_size = param[1].u.memref.size;
|
||||
rt_buf = kmemdup(rt_shm_va, *output_rt_size, GFP_KERNEL);
|
||||
if (!rt_buf)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
} else {
|
||||
*output_rt_size = 0;
|
||||
}
|
||||
|
||||
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 = TA_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, ret: %d, err: 0x%x\n",
|
||||
pas_id, ret, inv_arg.ret);
|
||||
return ret ?: -EINVAL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
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 = TA_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 set remote state failed, pas_id: %d, ret: %d, err: 0x%x\n",
|
||||
pas_id, ret, inv_arg.ret);
|
||||
return ret ?: -EINVAL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
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 = TA_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;
|
||||
|
||||
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, ret: %d, err: 0x%x\n",
|
||||
pas_id, ret, inv_arg.ret);
|
||||
return ret ?: -EINVAL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
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);
|
||||
ctx->ptr = NULL;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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, ret: %d, err: 0x%x\n",
|
||||
ret, sess_arg.ret);
|
||||
tee_client_close_context(data->ctx);
|
||||
return ret ?: -EINVAL;
|
||||
}
|
||||
|
||||
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 ret;
|
||||
}
|
||||
|
||||
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_DESCRIPTION("Qualcomm PAS TEE driver");
|
||||
@@ -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"
|
||||
|
||||
@@ -479,25 +481,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;
|
||||
@@ -570,26 +553,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)
|
||||
@@ -600,11 +569,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 = {
|
||||
@@ -626,7 +596,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:
|
||||
@@ -635,7 +605,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;
|
||||
@@ -650,7 +621,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
|
||||
@@ -659,25 +630,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;
|
||||
@@ -685,7 +640,7 @@ 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
|
||||
@@ -699,16 +654,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;
|
||||
@@ -717,36 +671,35 @@ int qcom_scm_pas_init_image(u32 pas_id, const void *metadata, size_t size,
|
||||
|
||||
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);
|
||||
|
||||
/**
|
||||
* qcom_scm_pas_metadata_release() - release metadata context
|
||||
* @ctx: pas context
|
||||
*/
|
||||
void qcom_scm_pas_metadata_release(struct qcom_scm_pas_context *ctx)
|
||||
static void __qcom_scm_pas_metadata_release(struct device *dev,
|
||||
struct qcom_pas_context *ctx)
|
||||
{
|
||||
if (!ctx->ptr)
|
||||
return;
|
||||
|
||||
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 = {
|
||||
@@ -768,7 +721,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:
|
||||
@@ -776,9 +729,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)
|
||||
{
|
||||
@@ -813,7 +772,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;
|
||||
@@ -830,51 +789,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;
|
||||
@@ -909,11 +828,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);
|
||||
@@ -943,16 +863,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 = {
|
||||
@@ -972,7 +896,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:
|
||||
@@ -980,28 +904,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;
|
||||
@@ -1012,7 +923,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
|
||||
@@ -1022,20 +933,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 = {
|
||||
@@ -1055,7 +991,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:
|
||||
@@ -1063,16 +999,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 = {
|
||||
@@ -1084,16 +1018,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 = {
|
||||
@@ -2837,6 +2804,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
|
||||
@@ -2876,6 +2848,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[] = {
|
||||
|
||||
43
include/linux/firmware/qcom/qcom_pas.h
Normal file
43
include/linux/firmware/qcom/qcom_pas.h
Normal file
@@ -0,0 +1,43 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2010-2015, 2018-2019 The Linux Foundation. All rights reserved.
|
||||
* Copyright (C) 2015 Linaro Ltd.
|
||||
* 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 */
|
||||
Reference in New Issue
Block a user