linux/drivers/firmware/qcom/qcom_scm.c

// SPDX-License-Identifier: GPL-2.0-only
/* Copyright (c) 2010,2015,2019 The Linux Foundation. All rights reserved.
 * Copyright (C) 2015 Linaro Ltd.
 */

#include <linux/arm-smccc.h>
#include <linux/bitfield.h>
#include <linux/bits.h>
#include <linux/cleanup.h>
#include <linux/clk.h>
#include <linux/completion.h>
#include <linux/cpumask.h>
#include <linux/dma-mapping.h>
#include <linux/err.h>
#include <linux/export.h>
#include <linux/firmware/qcom/qcom_scm.h>
#include <linux/firmware/qcom/qcom_tzmem.h>
#include <linux/init.h>
#include <linux/interconnect.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <linux/of_reserved_mem.h>
#include <linux/platform_device.h>
#include <linux/reset-controller.h>
#include <linux/sizes.h>
#include <linux/types.h>

#include "qcom_scm.h"
#include "qcom_tzmem.h"

static bool download_mode = IS_ENABLED();
module_param(download_mode, bool, 0);

struct qcom_scm {};

struct qcom_scm_current_perm_info {};

struct qcom_scm_mem_map_info {};

/**
 * struct qcom_scm_qseecom_resp - QSEECOM SCM call response.
 * @result:    Result or status of the SCM call. See &enum qcom_scm_qseecom_result.
 * @resp_type: Type of the response. See &enum qcom_scm_qseecom_resp_type.
 * @data:      Response data. The type of this data is given in @resp_type.
 */
struct qcom_scm_qseecom_resp {};

enum qcom_scm_qseecom_result {};

enum qcom_scm_qseecom_resp_type {};

enum qcom_scm_qseecom_tz_owner {};

enum qcom_scm_qseecom_tz_svc {};

enum qcom_scm_qseecom_tz_cmd_app {};

enum qcom_scm_qseecom_tz_cmd_info {};

#define QSEECOM_MAX_APP_NAME_SIZE

/* Each bit configures cold/warm boot address for one of the 4 CPUs */
static const u8 qcom_scm_cpu_cold_bits[QCOM_SCM_BOOT_MAX_CPUS] =;
static const u8 qcom_scm_cpu_warm_bits[QCOM_SCM_BOOT_MAX_CPUS] =;

#define QCOM_SMC_WAITQ_FLAG_WAKE_ONE

#define QCOM_DLOAD_MASK
#define QCOM_DLOAD_NODUMP
#define QCOM_DLOAD_FULLDUMP

static const char * const qcom_scm_convention_names[] =;

static struct qcom_scm *__scm;

static int qcom_scm_clk_enable(void)
{}

static void qcom_scm_clk_disable(void)
{}

static int qcom_scm_bw_enable(void)
{}

static void qcom_scm_bw_disable(void)
{}

enum qcom_scm_convention qcom_scm_convention =;
static DEFINE_SPINLOCK(scm_query_lock);

struct qcom_tzmem_pool *qcom_scm_get_tzmem_pool(void)
{}

static enum qcom_scm_convention __get_convention(void)
{}

/**
 * qcom_scm_call() - Invoke a syscall in the secure world
 * @dev:	device
 * @desc:	Descriptor structure containing arguments and return values
 * @res:        Structure containing results from SMC/HVC call
 *
 * Sends a command to the SCM and waits for the command to finish processing.
 * This should *only* be called in pre-emptible context.
 */
static int qcom_scm_call(struct device *dev, const struct qcom_scm_desc *desc,
			 struct qcom_scm_res *res)
{}

/**
 * qcom_scm_call_atomic() - atomic variation of qcom_scm_call()
 * @dev:	device
 * @desc:	Descriptor structure containing arguments and return values
 * @res:	Structure containing results from SMC/HVC call
 *
 * Sends a command to the SCM and waits for the command to finish processing.
 * This can be called in atomic context.
 */
static int qcom_scm_call_atomic(struct device *dev,
				const struct qcom_scm_desc *desc,
				struct qcom_scm_res *res)
{}

static bool __qcom_scm_is_call_available(struct device *dev, u32 svc_id,
					 u32 cmd_id)
{}

static int qcom_scm_set_boot_addr(void *entry, const u8 *cpu_bits)
{}

static int qcom_scm_set_boot_addr_mc(void *entry, unsigned int flags)
{}

/**
 * qcom_scm_set_warm_boot_addr() - Set the warm boot address for all cpus
 * @entry: Entry point function for the cpus
 *
 * Set the Linux entry point for the SCM to transfer control to when coming
 * out of a power down. CPU power down may be executed on cpuidle or hotplug.
 */
int qcom_scm_set_warm_boot_addr(void *entry)
{}
EXPORT_SYMBOL_GPL();

/**
 * qcom_scm_set_cold_boot_addr() - Set the cold boot address for all cpus
 * @entry: Entry point function for the cpus
 */
int qcom_scm_set_cold_boot_addr(void *entry)
{}
EXPORT_SYMBOL_GPL();

/**
 * qcom_scm_cpu_power_down() - Power down the cpu
 * @flags:	Flags to flush cache
 *
 * This is an end point to power down cpu. If there was a pending interrupt,
 * the control would return from this function, otherwise, the cpu jumps to the
 * warm boot entry point set for this cpu upon reset.
 */
void qcom_scm_cpu_power_down(u32 flags)
{}
EXPORT_SYMBOL_GPL();

int qcom_scm_set_remote_state(u32 state, u32 id)
{}
EXPORT_SYMBOL_GPL();

static int qcom_scm_disable_sdi(void)
{}

static int __qcom_scm_set_dload_mode(struct device *dev, bool enable)
{}

static int qcom_scm_io_rmw(phys_addr_t addr, unsigned int mask, unsigned int val)
{}

static void qcom_scm_set_download_mode(bool enable)
{}

/**
 * qcom_scm_pas_init_image() - Initialize peripheral authentication service
 *			       state machine for a given peripheral, using the
 *			       metadata
 * @peripheral: peripheral id
 * @metadata:	pointer to memory containing ELF header, program header table
 *		and optional blob of data used for authenticating the metadata
 *		and the rest of the firmware
 * @size:	size of the metadata
 * @ctx:	optional metadata context
 *
 * Return: 0 on success.
 *
 * Upon successful return, the PAS metadata context (@ctx) will be used to
 * track the metadata allocation, this needs to be released by invoking
 * qcom_scm_pas_metadata_release() by the caller.
 */
int qcom_scm_pas_init_image(u32 peripheral, const void *metadata, size_t size,
			    struct qcom_scm_pas_metadata *ctx)
{}
EXPORT_SYMBOL_GPL();

/**
 * qcom_scm_pas_metadata_release() - release metadata context
 * @ctx:	metadata context
 */
void qcom_scm_pas_metadata_release(struct qcom_scm_pas_metadata *ctx)
{}
EXPORT_SYMBOL_GPL();

/**
 * qcom_scm_pas_mem_setup() - Prepare the memory related to a given peripheral
 *			      for firmware loading
 * @peripheral:	peripheral id
 * @addr:	start address of memory area to prepare
 * @size:	size of the memory area to prepare
 *
 * Returns 0 on success.
 */
int qcom_scm_pas_mem_setup(u32 peripheral, phys_addr_t addr, phys_addr_t size)
{}
EXPORT_SYMBOL_GPL();

/**
 * qcom_scm_pas_auth_and_reset() - Authenticate the given peripheral firmware
 *				   and reset the remote processor
 * @peripheral:	peripheral id
 *
 * Return 0 on success.
 */
int qcom_scm_pas_auth_and_reset(u32 peripheral)
{}
EXPORT_SYMBOL_GPL();

/**
 * qcom_scm_pas_shutdown() - Shut down the remote processor
 * @peripheral: peripheral id
 *
 * Returns 0 on success.
 */
int qcom_scm_pas_shutdown(u32 peripheral)
{}
EXPORT_SYMBOL_GPL();

/**
 * qcom_scm_pas_supported() - Check if the peripheral authentication service is
 *			      available for the given peripherial
 * @peripheral:	peripheral id
 *
 * Returns true if PAS is supported for this peripheral, otherwise false.
 */
bool qcom_scm_pas_supported(u32 peripheral)
{}
EXPORT_SYMBOL_GPL();

static int __qcom_scm_pas_mss_reset(struct device *dev, bool reset)
{}

static int qcom_scm_pas_reset_assert(struct reset_controller_dev *rcdev,
				     unsigned long idx)
{}

static int qcom_scm_pas_reset_deassert(struct reset_controller_dev *rcdev,
				       unsigned long idx)
{}

static const struct reset_control_ops qcom_scm_pas_reset_ops =;

int qcom_scm_io_readl(phys_addr_t addr, unsigned int *val)
{}
EXPORT_SYMBOL_GPL();

int qcom_scm_io_writel(phys_addr_t addr, unsigned int val)
{}
EXPORT_SYMBOL_GPL();

/**
 * qcom_scm_restore_sec_cfg_available() - Check if secure environment
 * supports restore security config interface.
 *
 * Return true if restore-cfg interface is supported, false if not.
 */
bool qcom_scm_restore_sec_cfg_available(void)
{}
EXPORT_SYMBOL_GPL();

int qcom_scm_restore_sec_cfg(u32 device_id, u32 spare)
{}
EXPORT_SYMBOL_GPL();

int qcom_scm_iommu_secure_ptbl_size(u32 spare, size_t *size)
{}
EXPORT_SYMBOL_GPL();

int qcom_scm_iommu_secure_ptbl_init(u64 addr, u32 size, u32 spare)
{}
EXPORT_SYMBOL_GPL();

int qcom_scm_iommu_set_cp_pool_size(u32 spare, u32 size)
{}
EXPORT_SYMBOL_GPL();

int qcom_scm_mem_protect_video_var(u32 cp_start, u32 cp_size,
				   u32 cp_nonpixel_start,
				   u32 cp_nonpixel_size)
{}
EXPORT_SYMBOL_GPL();

static int __qcom_scm_assign_mem(struct device *dev, phys_addr_t mem_region,
				 size_t mem_sz, phys_addr_t src, size_t src_sz,
				 phys_addr_t dest, size_t dest_sz)
{}

/**
 * qcom_scm_assign_mem() - Make a secure call to reassign memory ownership
 * @mem_addr: mem region whose ownership need to be reassigned
 * @mem_sz:   size of the region.
 * @srcvm:    vmid for current set of owners, each set bit in
 *            flag indicate a unique owner
 * @newvm:    array having new owners and corresponding permission
 *            flags
 * @dest_cnt: number of owners in next set.
 *
 * Return negative errno on failure or 0 on success with @srcvm updated.
 */
int qcom_scm_assign_mem(phys_addr_t mem_addr, size_t mem_sz,
			u64 *srcvm,
			const struct qcom_scm_vmperm *newvm,
			unsigned int dest_cnt)
{}
EXPORT_SYMBOL_GPL();

/**
 * qcom_scm_ocmem_lock_available() - is OCMEM lock/unlock interface available
 */
bool qcom_scm_ocmem_lock_available(void)
{}
EXPORT_SYMBOL_GPL();

/**
 * qcom_scm_ocmem_lock() - call OCMEM lock interface to assign an OCMEM
 * region to the specified initiator
 *
 * @id:     tz initiator id
 * @offset: OCMEM offset
 * @size:   OCMEM size
 * @mode:   access mode (WIDE/NARROW)
 */
int qcom_scm_ocmem_lock(enum qcom_scm_ocmem_client id, u32 offset, u32 size,
			u32 mode)
{}
EXPORT_SYMBOL_GPL();

/**
 * qcom_scm_ocmem_unlock() - call OCMEM unlock interface to release an OCMEM
 * region from the specified initiator
 *
 * @id:     tz initiator id
 * @offset: OCMEM offset
 * @size:   OCMEM size
 */
int qcom_scm_ocmem_unlock(enum qcom_scm_ocmem_client id, u32 offset, u32 size)
{}
EXPORT_SYMBOL_GPL();

/**
 * qcom_scm_ice_available() - Is the ICE key programming interface available?
 *
 * Return: true iff the SCM calls wrapped by qcom_scm_ice_invalidate_key() and
 *	   qcom_scm_ice_set_key() are available.
 */
bool qcom_scm_ice_available(void)
{}
EXPORT_SYMBOL_GPL();

/**
 * qcom_scm_ice_invalidate_key() - Invalidate an inline encryption key
 * @index: the keyslot to invalidate
 *
 * The UFSHCI and eMMC standards define a standard way to do this, but it
 * doesn't work on these SoCs; only this SCM call does.
 *
 * It is assumed that the SoC has only one ICE instance being used, as this SCM
 * call doesn't specify which ICE instance the keyslot belongs to.
 *
 * Return: 0 on success; -errno on failure.
 */
int qcom_scm_ice_invalidate_key(u32 index)
{}
EXPORT_SYMBOL_GPL();

/**
 * qcom_scm_ice_set_key() - Set an inline encryption key
 * @index: the keyslot into which to set the key
 * @key: the key to program
 * @key_size: the size of the key in bytes
 * @cipher: the encryption algorithm the key is for
 * @data_unit_size: the encryption data unit size, i.e. the size of each
 *		    individual plaintext and ciphertext.  Given in 512-byte
 *		    units, e.g. 1 = 512 bytes, 8 = 4096 bytes, etc.
 *
 * Program a key into a keyslot of Qualcomm ICE (Inline Crypto Engine), where it
 * can then be used to encrypt/decrypt UFS or eMMC I/O requests inline.
 *
 * The UFSHCI and eMMC standards define a standard way to do this, but it
 * doesn't work on these SoCs; only this SCM call does.
 *
 * It is assumed that the SoC has only one ICE instance being used, as this SCM
 * call doesn't specify which ICE instance the keyslot belongs to.
 *
 * Return: 0 on success; -errno on failure.
 */
int qcom_scm_ice_set_key(u32 index, const u8 *key, u32 key_size,
			 enum qcom_scm_ice_cipher cipher, u32 data_unit_size)
{}
EXPORT_SYMBOL_GPL();

/**
 * qcom_scm_hdcp_available() - Check if secure environment supports HDCP.
 *
 * Return true if HDCP is supported, false if not.
 */
bool qcom_scm_hdcp_available(void)
{}
EXPORT_SYMBOL_GPL();

/**
 * qcom_scm_hdcp_req() - Send HDCP request.
 * @req: HDCP request array
 * @req_cnt: HDCP request array count
 * @resp: response buffer passed to SCM
 *
 * Write HDCP register(s) through SCM.
 */
int qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt, u32 *resp)
{}
EXPORT_SYMBOL_GPL();

int qcom_scm_iommu_set_pt_format(u32 sec_id, u32 ctx_num, u32 pt_fmt)
{}
EXPORT_SYMBOL_GPL();

int qcom_scm_qsmmu500_wait_safe_toggle(bool en)
{}
EXPORT_SYMBOL_GPL();

bool qcom_scm_lmh_dcvsh_available(void)
{}
EXPORT_SYMBOL_GPL();

int qcom_scm_shm_bridge_enable(void)
{}
EXPORT_SYMBOL_GPL();

int qcom_scm_shm_bridge_create(struct device *dev, u64 pfn_and_ns_perm_flags,
			       u64 ipfn_and_s_perm_flags, u64 size_and_flags,
			       u64 ns_vmids, u64 *handle)
{}
EXPORT_SYMBOL_GPL();

int qcom_scm_shm_bridge_delete(struct device *dev, u64 handle)
{}
EXPORT_SYMBOL_GPL();

int qcom_scm_lmh_profile_change(u32 profile_id)
{}
EXPORT_SYMBOL_GPL();

int qcom_scm_lmh_dcvsh(u32 payload_fn, u32 payload_reg, u32 payload_val,
		       u64 limit_node, u32 node_id, u64 version)
{}
EXPORT_SYMBOL_GPL();

int qcom_scm_gpu_init_regs(u32 gpu_req)
{}
EXPORT_SYMBOL_GPL();

static int qcom_scm_find_dload_address(struct device *dev, u64 *addr)
{}

#ifdef CONFIG_QCOM_QSEECOM

/* Lock for QSEECOM SCM call executions */
static DEFINE_MUTEX(qcom_scm_qseecom_call_lock);

static int __qcom_scm_qseecom_call(const struct qcom_scm_desc *desc,
				   struct qcom_scm_qseecom_resp *res)
{}

/**
 * qcom_scm_qseecom_call() - Perform a QSEECOM SCM call.
 * @desc: SCM call descriptor.
 * @res:  SCM call response (output).
 *
 * Performs the QSEECOM SCM call described by @desc, returning the response in
 * @rsp.
 *
 * Return: Zero on success, nonzero on failure.
 */
static int qcom_scm_qseecom_call(const struct qcom_scm_desc *desc,
				 struct qcom_scm_qseecom_resp *res)
{}

/**
 * qcom_scm_qseecom_get_version() - Query the QSEECOM version.
 * @version: Pointer where the QSEECOM version will be stored.
 *
 * Performs the QSEECOM SCM querying the QSEECOM version currently running in
 * the TrustZone.
 *
 * Return: Zero on success, nonzero on failure.
 */
static int qcom_scm_qseecom_get_version(u32 *version)
{}

/**
 * qcom_scm_qseecom_app_get_id() - Query the app ID for a given QSEE app name.
 * @app_name: The name of the app.
 * @app_id:   The returned app ID.
 *
 * Query and return the application ID of the SEE app identified by the given
 * name. This returned ID is the unique identifier of the app required for
 * subsequent communication.
 *
 * Return: Zero on success, nonzero on failure, -ENOENT if the app has not been
 * loaded or could not be found.
 */
int qcom_scm_qseecom_app_get_id(const char *app_name, u32 *app_id)
{}
EXPORT_SYMBOL_GPL();

/**
 * qcom_scm_qseecom_app_send() - Send to and receive data from a given QSEE app.
 * @app_id:   The ID of the target app.
 * @req:      Request buffer sent to the app (must be TZ memory)
 * @req_size: Size of the request buffer.
 * @rsp:      Response buffer, written to by the app (must be TZ memory)
 * @rsp_size: Size of the response buffer.
 *
 * Sends a request to the QSEE app associated with the given ID and read back
 * its response. The caller must provide two DMA memory regions, one for the
 * request and one for the response, and fill out the @req region with the
 * respective (app-specific) request data. The QSEE app reads this and returns
 * its response in the @rsp region.
 *
 * Return: Zero on success, nonzero on failure.
 */
int qcom_scm_qseecom_app_send(u32 app_id, void *req, size_t req_size,
			      void *rsp, size_t rsp_size)
{}
EXPORT_SYMBOL_GPL();

/*
 * We do not yet support re-entrant calls via the qseecom interface. To prevent
 + any potential issues with this, only allow validated machines for now.
 */
static const struct of_device_id qcom_scm_qseecom_allowlist[] __maybe_unused =;

static bool qcom_scm_qseecom_machine_is_allowed(void)
{}

static void qcom_scm_qseecom_free(void *data)
{}

static int qcom_scm_qseecom_init(struct qcom_scm *scm)
{}

#else /* CONFIG_QCOM_QSEECOM */

static int qcom_scm_qseecom_init(struct qcom_scm *scm)
{
	return 0;
}

#endif /* CONFIG_QCOM_QSEECOM */

/**
 * qcom_scm_is_available() - Checks if SCM is available
 */
bool qcom_scm_is_available(void)
{}
EXPORT_SYMBOL_GPL();

static int qcom_scm_assert_valid_wq_ctx(u32 wq_ctx)
{}

int qcom_scm_wait_for_wq_completion(u32 wq_ctx)
{}

static int qcom_scm_waitq_wakeup(unsigned int wq_ctx)
{}

static irqreturn_t qcom_scm_irq_handler(int irq, void *data)
{}

static int qcom_scm_probe(struct platform_device *pdev)
{}

static void qcom_scm_shutdown(struct platform_device *pdev)
{}

static const struct of_device_id qcom_scm_dt_match[] =;
MODULE_DEVICE_TABLE(of, qcom_scm_dt_match);

static struct platform_driver qcom_scm_driver =;

static int __init qcom_scm_init(void)
{}
subsys_initcall(qcom_scm_init);

MODULE_DESCRIPTION();
MODULE_LICENSE();