#include <linux/of_reserved_mem.h>
#include <linux/platform_device.h>
#include <linux/reset-controller.h>
+#include <linux/remoteproc.h>
#include <linux/sizes.h>
#include <linux/types.h>
QSEECOM_TZ_CMD_INFO_VERSION = 3,
};
+#define RSCTABLE_BUFFER_NOT_SUFFICIENT 20
+
#define QSEECOM_MAX_APP_NAME_SIZE 64
#define SHMBRIDGE_RESULT_NOTSUPP 4
}
EXPORT_SYMBOL_GPL(qcom_scm_pas_mem_setup);
+static void *__qcom_scm_pas_get_rsc_table(u32 pas_id, void *input_rt_tzm,
+ size_t input_rt_size,
+ size_t *output_rt_size)
+{
+ struct qcom_scm_desc desc = {
+ .svc = QCOM_SCM_SVC_PIL,
+ .cmd = QCOM_SCM_PIL_PAS_GET_RSCTABLE,
+ .arginfo = QCOM_SCM_ARGS(5, QCOM_SCM_VAL, QCOM_SCM_RO, QCOM_SCM_VAL,
+ QCOM_SCM_RW, QCOM_SCM_VAL),
+ .args[0] = pas_id,
+ .owner = ARM_SMCCC_OWNER_SIP,
+ };
+ struct qcom_scm_res res;
+ void *output_rt_tzm;
+ int ret;
+
+ output_rt_tzm = qcom_tzmem_alloc(__scm->mempool, *output_rt_size, GFP_KERNEL);
+ if (!output_rt_tzm)
+ return ERR_PTR(-ENOMEM);
+
+ desc.args[1] = qcom_tzmem_to_phys(input_rt_tzm);
+ desc.args[2] = input_rt_size;
+ desc.args[3] = qcom_tzmem_to_phys(output_rt_tzm);
+ desc.args[4] = *output_rt_size;
+
+ /*
+ * Whether SMC fail or pass, res.result[2] will hold actual resource table
+ * size.
+ *
+ * If passed 'output_rt_size' buffer size is not sufficient to hold the
+ * resource table TrustZone sends, response code in res.result[1] as
+ * RSCTABLE_BUFFER_NOT_SUFFICIENT so that caller can retry this SMC call
+ * 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);
+ if (!ret && res.result[2] > SZ_1G) {
+ ret = -E2BIG;
+ goto free_output_rt;
+ }
+
+ *output_rt_size = res.result[2];
+ if (ret && res.result[1] == RSCTABLE_BUFFER_NOT_SUFFICIENT)
+ ret = -EOVERFLOW;
+
+free_output_rt:
+ if (ret)
+ qcom_tzmem_free(output_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)
+{
+ struct resource_table empty_rsc = {};
+ size_t size = SZ_16K;
+ void *output_rt_tzm;
+ void *input_rt_tzm;
+ void *tbl_ptr;
+ int ret;
+
+ ret = qcom_scm_clk_enable();
+ if (ret)
+ return ERR_PTR(ret);
+
+ ret = qcom_scm_bw_enable();
+ if (ret)
+ goto disable_clk;
+
+ /*
+ * TrustZone can not accept buffer as NULL value as argument hence,
+ * we need to pass a input buffer indicating that subsystem firmware
+ * does not have resource table by filling resource table structure.
+ */
+ if (!input_rt) {
+ input_rt = &empty_rsc;
+ input_rt_size = sizeof(empty_rsc);
+ }
+
+ input_rt_tzm = qcom_tzmem_alloc(__scm->mempool, input_rt_size, GFP_KERNEL);
+ if (!input_rt_tzm) {
+ ret = -ENOMEM;
+ goto disable_scm_bw;
+ }
+
+ memcpy(input_rt_tzm, input_rt, input_rt_size);
+
+ output_rt_tzm = __qcom_scm_pas_get_rsc_table(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,
+ input_rt_tzm,
+ input_rt_size,
+ &size);
+ if (IS_ERR(output_rt_tzm)) {
+ ret = PTR_ERR(output_rt_tzm);
+ goto free_input_rt;
+ }
+
+ tbl_ptr = kzalloc(size, GFP_KERNEL);
+ if (!tbl_ptr) {
+ qcom_tzmem_free(output_rt_tzm);
+ ret = -ENOMEM;
+ goto free_input_rt;
+ }
+
+ memcpy(tbl_ptr, output_rt_tzm, size);
+ *output_rt_size = size;
+ qcom_tzmem_free(output_rt_tzm);
+
+free_input_rt:
+ qcom_tzmem_free(input_rt_tzm);
+
+disable_scm_bw:
+ qcom_scm_bw_disable();
+
+disable_clk:
+ qcom_scm_clk_disable();
+
+ return ret ? ERR_PTR(ret) : tbl_ptr;
+}
+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