This adds the Peripheral Authentication Service (PAS) interface to the
Qualcomm SCM interface. The API is used to authenticate and boot a range
of external processors in various Qualcomm platforms.

Signed-off-by: Bjorn Andersson <bjorn.anders...@sonymobile.com>
---

Changes since v1:
- Big endian compatibility

 drivers/firmware/qcom_scm-32.c | 93 ++++++++++++++++++++++++++++++++++++++++++
 drivers/firmware/qcom_scm.c    | 78 +++++++++++++++++++++++++++++++++++
 drivers/firmware/qcom_scm.h    | 12 ++++++
 include/linux/qcom_scm.h       |  6 +++
 4 files changed, 189 insertions(+)

diff --git a/drivers/firmware/qcom_scm-32.c b/drivers/firmware/qcom_scm-32.c
index 1bd6f9c34331..81d9c59f3ccc 100644
--- a/drivers/firmware/qcom_scm-32.c
+++ b/drivers/firmware/qcom_scm-32.c
@@ -23,6 +23,7 @@
 #include <linux/errno.h>
 #include <linux/err.h>
 #include <linux/qcom_scm.h>
+#include <linux/dma-mapping.h>
 
 #include <asm/outercache.h>
 #include <asm/cacheflush.h>
@@ -501,3 +502,95 @@ int __qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 
req_cnt, u32 *resp)
        return qcom_scm_call(QCOM_SCM_SVC_HDCP, QCOM_SCM_CMD_HDCP,
                req, req_cnt * sizeof(*req), resp, sizeof(*resp));
 }
+
+bool __qcom_scm_pas_supported(u32 peripheral)
+{
+       u32 ret_val;
+       int ret;
+
+       ret = qcom_scm_call(QCOM_SCM_SVC_PIL, QCOM_SCM_PAS_IS_SUPPORTED_CMD,
+                           &peripheral, sizeof(peripheral),
+                           &ret_val, sizeof(ret_val));
+
+       return ret ? false : !!ret_val;
+}
+
+int __qcom_scm_pas_init_image(u32 peripheral, const void *metadata, size_t 
size)
+{
+       dma_addr_t mdata_phys;
+       void *mdata_buf;
+       __le32 scm_ret;
+       int ret;
+       struct pas_init_image_req {
+               __le32 proc;
+               __le32 image_addr;
+       } request;
+
+       /*
+        * During the scm call memory protection will be enabled for the meta
+        * data blob, so make sure it's physically contiguous, 4K aligned and
+        * non-cachable to avoid XPU violations.
+        */
+       mdata_buf = dma_alloc_coherent(NULL, size, &mdata_phys, GFP_KERNEL);
+       if (!mdata_buf) {
+               pr_err("Allocation of metadata buffer failed.\n");
+               return -ENOMEM;
+       }
+       memcpy(mdata_buf, metadata, size);
+
+       request.proc = cpu_to_le32(peripheral);
+       request.image_addr = cpu_to_le32(mdata_phys);
+
+       ret = qcom_scm_call(QCOM_SCM_SVC_PIL, QCOM_SCM_PAS_INIT_IMAGE_CMD,
+                           &request, sizeof(request),
+                           &scm_ret, sizeof(scm_ret));
+
+       dma_free_coherent(NULL, size, mdata_buf, mdata_phys);
+
+       return ret ? : le32_to_cpu(scm_ret);
+}
+
+int __qcom_scm_pas_mem_setup(u32 peripheral, phys_addr_t addr, phys_addr_t 
size)
+{
+       __le32 scm_ret;
+       int ret;
+       struct pas_init_image_req {
+               __le32 proc;
+               __le32 addr;
+               __le32 len;
+       } request;
+
+       request.proc = cpu_to_le32(peripheral);
+       request.addr = cpu_to_le32(addr);
+       request.len = cpu_to_le32(size);
+
+       ret = qcom_scm_call(QCOM_SCM_SVC_PIL, QCOM_SCM_PAS_MEM_SETUP_CMD,
+                           &request, sizeof(request),
+                           &scm_ret, sizeof(scm_ret));
+
+       return ret ? : le32_to_cpu(scm_ret);
+}
+
+int __qcom_scm_pas_auth_and_reset(u32 peripheral)
+{
+       __le32 scm_ret;
+       int ret;
+
+       ret = qcom_scm_call(QCOM_SCM_SVC_PIL, QCOM_SCM_PAS_AUTH_AND_RESET_CMD,
+                           &peripheral, sizeof(peripheral),
+                           &scm_ret, sizeof(scm_ret));
+
+       return ret ? : le32_to_cpu(scm_ret);
+}
+
+int __qcom_scm_pas_shutdown(u32 peripheral)
+{
+       __le32 scm_ret;
+       int ret;
+
+       ret = qcom_scm_call(QCOM_SCM_SVC_PIL, QCOM_SCM_PAS_SHUTDOWN_CMD,
+                           &peripheral, sizeof(peripheral),
+                           &scm_ret, sizeof(scm_ret));
+
+       return ret ? : le32_to_cpu(scm_ret);
+}
diff --git a/drivers/firmware/qcom_scm.c b/drivers/firmware/qcom_scm.c
index 45c008d68891..ee7150d93b29 100644
--- a/drivers/firmware/qcom_scm.c
+++ b/drivers/firmware/qcom_scm.c
@@ -94,3 +94,81 @@ int qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 
req_cnt, u32 *resp)
        return __qcom_scm_hdcp_req(req, req_cnt, resp);
 }
 EXPORT_SYMBOL(qcom_scm_hdcp_req);
+
+/**
+ * qcom_scm_pas_supported() - Check if the peripheral authentication service is
+ *                           available for the given peripherial
+ * @peripheral:        peripheral id
+ *
+ * Returns true if PAS is supported for this peripheral, otherwise false.
+ */
+bool qcom_scm_pas_supported(u32 peripheral)
+{
+       int ret;
+
+       ret = __qcom_scm_is_call_available(QCOM_SCM_SVC_PIL,
+                                          QCOM_SCM_PAS_IS_SUPPORTED_CMD);
+       if (ret <= 0)
+               return false;
+
+       return __qcom_scm_pas_supported(peripheral);
+}
+EXPORT_SYMBOL(qcom_scm_pas_supported);
+
+/**
+ * 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
+ *
+ * Returns 0 on success.
+ */
+int qcom_scm_pas_init_image(u32 peripheral, const void *metadata, size_t size)
+{
+       return __qcom_scm_pas_init_image(peripheral, metadata, size);
+}
+EXPORT_SYMBOL(qcom_scm_pas_init_image);
+
+/**
+ * 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)
+{
+       return __qcom_scm_pas_mem_setup(peripheral, addr, size);
+}
+EXPORT_SYMBOL(qcom_scm_pas_mem_setup);
+
+/**
+ * qcom_scm_pas_auth_and_reset() - Authenticate the given peripheral firmware
+ *                                and reset the remote processor
+ * @peripheral:        peripheral id
+ *
+ * Return 0 on success.
+ */
+int qcom_scm_pas_auth_and_reset(u32 peripheral)
+{
+       return __qcom_scm_pas_auth_and_reset(peripheral);
+}
+EXPORT_SYMBOL(qcom_scm_pas_auth_and_reset);
+
+/**
+ * qcom_scm_pas_shutdown() - Shut down the remote processor
+ * @peripheral: peripheral id
+ *
+ * Returns 0 on success.
+ */
+int qcom_scm_pas_shutdown(u32 peripheral)
+{
+       return __qcom_scm_pas_shutdown(peripheral);
+}
+EXPORT_SYMBOL(qcom_scm_pas_shutdown);
diff --git a/drivers/firmware/qcom_scm.h b/drivers/firmware/qcom_scm.h
index 2cce75c08b99..c0700590193a 100644
--- a/drivers/firmware/qcom_scm.h
+++ b/drivers/firmware/qcom_scm.h
@@ -36,6 +36,18 @@ extern int __qcom_scm_is_call_available(u32 svc_id, u32 
cmd_id);
 extern int __qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt,
                u32 *resp);
 
+#define QCOM_SCM_SVC_PIL               0x2
+#define QCOM_SCM_PAS_INIT_IMAGE_CMD    0x1
+#define QCOM_SCM_PAS_MEM_SETUP_CMD     0x2
+#define QCOM_SCM_PAS_AUTH_AND_RESET_CMD        0x5
+#define QCOM_SCM_PAS_SHUTDOWN_CMD      0x6
+#define QCOM_SCM_PAS_IS_SUPPORTED_CMD  0x7
+extern bool __qcom_scm_pas_supported(u32 peripheral);
+extern int  __qcom_scm_pas_init_image(u32 peripheral, const void *metadata, 
size_t size);
+extern int  __qcom_scm_pas_mem_setup(u32 peripheral, phys_addr_t addr, 
phys_addr_t size);
+extern int  __qcom_scm_pas_auth_and_reset(u32 peripheral);
+extern int  __qcom_scm_pas_shutdown(u32 peripheral);
+
 /* common error codes */
 #define QCOM_SCM_ENOMEM                -5
 #define QCOM_SCM_EOPNOTSUPP    -4
diff --git a/include/linux/qcom_scm.h b/include/linux/qcom_scm.h
index 6e7d5ec65838..46d41e44d432 100644
--- a/include/linux/qcom_scm.h
+++ b/include/linux/qcom_scm.h
@@ -27,6 +27,12 @@ extern bool qcom_scm_hdcp_available(void);
 extern int qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt,
                u32 *resp);
 
+extern bool qcom_scm_pas_supported(u32 peripheral);
+extern int qcom_scm_pas_init_image(u32 peripheral, const void *metadata, 
size_t size);
+extern int qcom_scm_pas_mem_setup(u32 peripheral, phys_addr_t addr, 
phys_addr_t size);
+extern int qcom_scm_pas_auth_and_reset(u32 peripheral);
+extern int qcom_scm_pas_shutdown(u32 peripheral);
+
 #define QCOM_SCM_CPU_PWR_DOWN_L2_ON    0x0
 #define QCOM_SCM_CPU_PWR_DOWN_L2_OFF   0x1
 
-- 
1.8.2.2

--
To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to