summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStanimir Varbanov <stanimir.varbanov@linaro.org>2015-04-28 14:05:33 +0300
committerSrinivas Kandagatla <srinivas.kandagatla@linaro.org>2015-09-01 09:22:29 +0100
commitd4cc3b9c3ae62fa3b495e617f469dcf1f5f399bc (patch)
treefce489ae190d36326a4ea34a7470f33783c93f56
parent6d313411b55e770091b6401622292f373b1e701b (diff)
downloadlinux-d4cc3b9c3ae62fa3b495e617f469dcf1f5f399bc.tar.gz
firmware: qcom: scm: Support IOMMU scm calls
Signed-off-by: Stanimir Varbanov <stanimir.varbanov@linaro.org> Conflicts: drivers/firmware/qcom_scm-64.c drivers/firmware/qcom_scm.c
-rw-r--r--drivers/firmware/qcom_scm-32.c177
-rw-r--r--drivers/firmware/qcom_scm-64.c161
-rw-r--r--drivers/firmware/qcom_scm.c59
-rw-r--r--drivers/firmware/qcom_scm.h20
-rw-r--r--include/linux/qcom_scm.h15
5 files changed, 430 insertions, 2 deletions
diff --git a/drivers/firmware/qcom_scm-32.c b/drivers/firmware/qcom_scm-32.c
index cb321992b582..9864e120c9c9 100644
--- a/drivers/firmware/qcom_scm-32.c
+++ b/drivers/firmware/qcom_scm-32.c
@@ -48,6 +48,15 @@
#define QCOM_SCM_FLAG_WARMBOOT_CPU2 0x10
#define QCOM_SCM_FLAG_WARMBOOT_CPU3 0x40
+#define IOMMU_SECURE_PTBL_SIZE 3
+#define IOMMU_SECURE_PTBL_INIT 4
+#define IOMMU_SET_CP_POOL_SIZE 5
+#define IOMMU_SECURE_MAP 6
+#define IOMMU_SECURE_UNMAP 7
+#define IOMMU_SECURE_MAP2 0xb
+#define IOMMU_SECURE_MAP2_FLAT 0x12
+#define IOMMU_SECURE_UNMAP2 0xc
+
struct qcom_scm_entry {
int flag;
void *entry;
@@ -660,3 +669,171 @@ int __qcom_scm_pil_shutdown_cmd(u32 proc)
return scm_ret;
}
+
+#define SCM_SVC_UTIL 0x3
+#define SCM_SVC_MP 0xc
+#define IOMMU_DUMP_SMMU_FAULT_REGS 0x0c
+
+int __qcom_scm_iommu_dump_fault_regs(u32 id, u32 context, u64 addr, u32 len)
+{
+ struct {
+ u32 id;
+ u32 cb_num;
+ u32 buff;
+ u32 len;
+ } req;
+ int resp = 0;
+
+ return qcom_scm_call(SCM_SVC_UTIL, IOMMU_DUMP_SMMU_FAULT_REGS,
+ &req, sizeof(req), &resp, 1);
+}
+
+int __qcom_scm_iommu_set_cp_pool_size(u32 size, u32 spare)
+{
+ struct {
+ u32 size;
+ u32 spare;
+ } req;
+ int retval;
+
+ req.size = size;
+ req.spare = spare;
+
+ return qcom_scm_call(SCM_SVC_MP, IOMMU_SET_CP_POOL_SIZE,
+ &req, sizeof(req), &retval, sizeof(retval));
+}
+
+int __qcom_scm_iommu_secure_ptbl_size(u32 spare, int psize[2])
+{
+ struct {
+ u32 spare;
+ } req;
+
+ req.spare = spare;
+
+ return qcom_scm_call(SCM_SVC_MP, IOMMU_SECURE_PTBL_SIZE, &req,
+ sizeof(req), psize, sizeof(psize));
+}
+
+int __qcom_scm_iommu_secure_ptbl_init(u64 addr, u32 size, u32 spare)
+{
+ struct {
+ u32 addr;
+ u32 size;
+ u32 spare;
+ } req = {0};
+ int ret, ptbl_ret = 0;
+
+ req.addr = addr;
+ req.size = size;
+ req.spare = spare;
+
+ ret = qcom_scm_call(SCM_SVC_MP, IOMMU_SECURE_PTBL_INIT, &req,
+ sizeof(req), &ptbl_ret, sizeof(ptbl_ret));
+
+ if (ret)
+ return ret;
+
+ if (ptbl_ret)
+ return ptbl_ret;
+
+ return 0;
+}
+
+int __qcom_scm_iommu_secure_map(u64 list, u32 list_size, u32 size,
+ u32 id, u32 ctx_id, u64 va, u32 info_size,
+ u32 flags)
+{
+ struct {
+ struct {
+ unsigned int list;
+ unsigned int list_size;
+ unsigned int size;
+ } plist;
+ struct {
+ unsigned int id;
+ unsigned int ctx_id;
+ unsigned int va;
+ unsigned int size;
+ } info;
+ unsigned int flags;
+ } req;
+ u32 resp;
+ int ret;
+
+ req.plist.list = list;
+ req.plist.list_size = list_size;
+ req.plist.size = size;
+ req.info.id = id;
+ req.info.ctx_id = ctx_id;
+ req.info.va = va;
+ req.info.size = info_size;
+ req.flags = flags;
+
+ ret = qcom_scm_call(SCM_SVC_MP, IOMMU_SECURE_MAP2, &req, sizeof(req),
+ &resp, sizeof(resp));
+
+ if (ret || resp)
+ return -EINVAL;
+
+ return 0;
+}
+
+int __qcom_scm_iommu_secure_unmap(u32 id, u32 ctx_id, u64 va,
+ u32 size, u32 flags)
+{
+ struct {
+ struct {
+ unsigned int id;
+ unsigned int ctx_id;
+ unsigned int va;
+ unsigned int size;
+ } info;
+ unsigned int flags;
+ } req;
+ int ret, scm_ret;
+
+ req.info.id = id;
+ req.info.ctx_id = ctx_id;
+ req.info.va = va;
+ req.info.size = size;
+ req.flags = flags;
+
+ return qcom_scm_call(SCM_SVC_MP, IOMMU_SECURE_UNMAP2, &req,
+ sizeof(req), &scm_ret, sizeof(scm_ret));
+}
+
+int __qcom_scm_get_feat_version(u32 feat)
+{
+ int ret;
+
+ if (__qcom_scm_is_call_available(SCM_SVC_INFO, GET_FEAT_VERSION_CMD)) {
+ u32 version;
+
+ if (!qcom_scm_call(SCM_SVC_INFO, GET_FEAT_VERSION_CMD, &feat,
+ sizeof(feat), &version, sizeof(version)))
+ return version;
+ }
+
+ return 0;
+}
+
+#define RESTORE_SEC_CFG 2
+int __qcom_scm_restore_sec_cfg(u32 device_id, u32 spare)
+{
+ struct {
+ u32 device_id;
+ u32 spare;
+ } req;
+ int ret, scm_ret = 0;
+
+ req.device_id = device_id;
+ req.spare = spare;
+
+ ret = qcom_scm_call(SCM_SVC_MP, RESTORE_SEC_CFG, &req, sizeof(req),
+ scm_ret, sizeof(scm_ret));
+ if (ret || scm_ret)
+ return ret ? ret : -EINVAL;
+
+ return 0;
+}
diff --git a/drivers/firmware/qcom_scm-64.c b/drivers/firmware/qcom_scm-64.c
index e6c006999d9f..d8d9bd66ab08 100644
--- a/drivers/firmware/qcom_scm-64.c
+++ b/drivers/firmware/qcom_scm-64.c
@@ -635,6 +635,167 @@ int __qcom_scm_pil_shutdown_cmd(u32 proc)
return scm_ret;
}
+
+#define SCM_SVC_UTIL 0x3
+#define SCM_SVC_MP 0xc
+#define IOMMU_DUMP_SMMU_FAULT_REGS 0xc
+
+#define IOMMU_SECURE_PTBL_SIZE 3
+#define IOMMU_SECURE_PTBL_INIT 4
+#define IOMMU_SET_CP_POOL_SIZE 5
+#define IOMMU_SECURE_MAP 6
+#define IOMMU_SECURE_UNMAP 7
+#define IOMMU_SECURE_MAP2 0xb
+#define IOMMU_SECURE_MAP2_FLAT 0x12
+#define IOMMU_SECURE_UNMAP2 0xc
+#define IOMMU_SECURE_UNMAP2_FLAT 0x13
+
+int __qcom_scm_iommu_dump_fault_regs(u32 id, u32 context, u64 addr, u32 len)
+{
+ struct qcom_scm_desc desc = {0};
+
+ desc.args[0] = id;
+ desc.args[1] = context;
+ desc.args[2] = addr;
+ desc.args[3] = len;
+ desc.arginfo = QCOM_SCM_ARGS(4, QCOM_SCM_VAL, QCOM_SCM_VAL, QCOM_SCM_RW, QCOM_SCM_VAL);
+
+ return qcom_scm_call(SCM_SVC_UTIL, IOMMU_DUMP_SMMU_FAULT_REGS, &desc);
+}
+
+int __qcom_scm_iommu_set_cp_pool_size(u32 size, u32 spare)
+{
+ struct qcom_scm_desc desc = {0};
+
+ desc.args[0] = size;
+ desc.args[1] = spare;
+ desc.arginfo = QCOM_SCM_ARGS(2);
+
+ return qcom_scm_call(SCM_SVC_MP, IOMMU_SET_CP_POOL_SIZE, &desc);
+}
+
+int __qcom_scm_iommu_secure_ptbl_size(u32 spare, int psize[2])
+{
+ struct qcom_scm_desc desc = {0};
+ int ret;
+ desc.args[0] = spare;
+ desc.arginfo = QCOM_SCM_ARGS(1);
+
+ ret = qcom_scm_call(SCM_SVC_MP, IOMMU_SECURE_PTBL_SIZE, &desc);
+
+ psize[0] = desc.ret[0];
+ psize[1] = desc.ret[1];
+
+ return ret;
+}
+
+int __qcom_scm_iommu_secure_ptbl_init(u64 addr, u32 size, u32 spare)
+{
+ struct qcom_scm_desc desc = {0};
+ int ret;
+ u64 ptbl_ret;
+
+ desc.args[0] = addr;
+ desc.args[1] = size;
+ desc.args[2] = spare;
+ desc.arginfo = QCOM_SCM_ARGS(3, QCOM_SCM_RW, QCOM_SCM_VAL, QCOM_SCM_VAL);
+
+ ret = qcom_scm_call(SCM_SVC_MP, IOMMU_SECURE_PTBL_INIT, &desc);
+
+ ptbl_ret = desc.ret[0];
+
+ if (ret)
+ return ret;
+
+ if (ptbl_ret)
+ return ptbl_ret;
+
+ return 0;
+}
+
+int __qcom_scm_iommu_secure_map(u64 list, u32 list_size, u32 size,
+ u32 id, u32 ctx_id, u64 va, u32 info_size,
+ u32 flags)
+{
+ struct qcom_scm_desc desc = {0};
+ u32 resp;
+ int ret;
+
+ desc.args[0] = list;
+ desc.args[1] = list_size;
+ desc.args[2] = size;
+ desc.args[3] = id;
+ desc.args[4] = ctx_id;
+ desc.args[5] = va;
+ desc.args[6] = info_size;
+ desc.args[7] = flags;
+ desc.arginfo = QCOM_SCM_ARGS(8, QCOM_SCM_RW, QCOM_SCM_VAL, QCOM_SCM_VAL, QCOM_SCM_VAL,
+ QCOM_SCM_VAL, QCOM_SCM_VAL, QCOM_SCM_VAL, QCOM_SCM_VAL);
+
+ ret = qcom_scm_call(SCM_SVC_MP, IOMMU_SECURE_MAP2_FLAT, &desc);
+
+ resp = desc.ret[0];
+
+ if (ret || resp)
+ return -EINVAL;
+
+ return 0;
+}
+
+int __qcom_scm_iommu_secure_unmap(u32 id, u32 ctx_id, u64 va,
+ u32 size, u32 flags)
+{
+ struct qcom_scm_desc desc = {0};
+
+ desc.args[0] = id;
+ desc.args[1] = ctx_id;
+ desc.args[2] = va;
+ desc.args[3] = size;
+ desc.args[4] = flags;
+ desc.arginfo = QCOM_SCM_ARGS(5);
+
+ return qcom_scm_call(SCM_SVC_MP, IOMMU_SECURE_UNMAP2_FLAT, &desc);
+}
+
+int __qcom_scm_get_feat_version(u32 feat)
+{
+ struct qcom_scm_desc desc = {0};
+ int ret;
+
+ ret = __qcom_scm_is_call_available(SCM_SVC_INFO, GET_FEAT_VERSION_CMD);
+ if (ret <= 0)
+ return 0;
+
+ desc.args[0] = feat;
+ desc.arginfo = QCOM_SCM_ARGS(1);
+
+ ret = qcom_scm_call(SCM_SVC_INFO, GET_FEAT_VERSION_CMD, &desc);
+ if (!ret)
+ return desc.ret[0];
+
+ return 0;
+}
+
+#define RESTORE_SEC_CFG 2
+int __qcom_scm_restore_sec_cfg(u32 device_id, u32 spare)
+{
+ struct qcom_scm_desc desc = {0};
+ int ret, scm_ret = 0;
+
+ desc.args[0] = device_id;
+ desc.args[1] = spare;
+ desc.arginfo = QCOM_SCM_ARGS(2);
+
+ ret = qcom_scm_call(SCM_SVC_MP, RESTORE_SEC_CFG, &desc);
+
+ scm_ret = desc.ret[0];
+
+ if (ret || scm_ret)
+ return ret ? ret : -EINVAL;
+
+ return 0;
+}
+
#define QCOM_SCM_SVC_INFO 0x6
static int __init qcom_scm_init(void)
{
diff --git a/drivers/firmware/qcom_scm.c b/drivers/firmware/qcom_scm.c
index 655550b402a7..34477a827836 100644
--- a/drivers/firmware/qcom_scm.c
+++ b/drivers/firmware/qcom_scm.c
@@ -196,4 +196,61 @@ int qcom_scm_pil_shutdown_cmd(u32 proc)
{
return __qcom_scm_pil_shutdown_cmd(proc);
}
-EXPORT_SYMBOL(qcom_scm_pil_shutdown_cmd); \ No newline at end of file
+EXPORT_SYMBOL(qcom_scm_pil_shutdown_cmd);
+
+int qcom_scm_iommu_dump_fault_regs(u32 id, u32 context, u64 addr, u32 len)
+{
+ return __qcom_scm_iommu_dump_fault_regs(id, context, addr, len);
+}
+EXPORT_SYMBOL(qcom_scm_iommu_dump_fault_regs);
+
+int qcom_scm_iommu_set_cp_pool_size(u32 size, u32 spare)
+{
+ return __qcom_scm_iommu_set_cp_pool_size(size, spare);
+}
+EXPORT_SYMBOL(qcom_scm_iommu_set_cp_pool_size);
+
+int qcom_scm_iommu_secure_ptbl_size(u32 spare, int psize[2])
+{
+ return __qcom_scm_iommu_secure_ptbl_size(spare, psize);
+}
+EXPORT_SYMBOL(qcom_scm_iommu_secure_ptbl_size);
+
+int qcom_scm_iommu_secure_ptbl_init(u64 addr, u32 size, u32 spare)
+{
+ return __qcom_scm_iommu_secure_ptbl_init(addr, size, spare);
+}
+EXPORT_SYMBOL(qcom_scm_iommu_secure_ptbl_init);
+
+int qcom_scm_iommu_secure_map(u64 list, u32 list_size, u32 size,
+ u32 id, u32 ctx_id, u64 va, u32 info_size,
+ u32 flags)
+{
+ return __qcom_scm_iommu_secure_map(list, list_size, size, id,
+ ctx_id, va, info_size, flags);
+}
+EXPORT_SYMBOL(qcom_scm_iommu_secure_map);
+
+int qcom_scm_iommu_secure_unmap(u32 id, u32 ctx_id, u64 va, u32 size, u32 flags)
+{
+ return __qcom_scm_iommu_secure_unmap(id, ctx_id, va, size, flags);
+}
+EXPORT_SYMBOL(qcom_scm_iommu_secure_unmap);
+
+int qcom_scm_is_call_available(u32 svc_id, u32 cmd_id)
+{
+ return __qcom_scm_is_call_available(svc_id, cmd_id);
+}
+EXPORT_SYMBOL(qcom_scm_is_call_available);
+
+int qcom_scm_get_feat_version(u32 feat)
+{
+ return __qcom_scm_get_feat_version(feat);
+}
+EXPORT_SYMBOL(qcom_scm_get_feat_version);
+
+int qcom_scm_restore_sec_cfg(u32 device_id, u32 spare)
+{
+ return __qcom_scm_restore_sec_cfg(device_id, spare);
+}
+EXPORT_SYMBOL(qcom_scm_restore_sec_cfg);
diff --git a/drivers/firmware/qcom_scm.h b/drivers/firmware/qcom_scm.h
index c91ddbba701e..3730201661c4 100644
--- a/drivers/firmware/qcom_scm.h
+++ b/drivers/firmware/qcom_scm.h
@@ -86,11 +86,29 @@ enum scm_cmd {
PAS_SHUTDOWN_CMD,
};
-#define SCM_SVC_PIL 0x2
+#define SCM_SVC_PIL 0x2
+#define SCM_SVC_INFO 0x6
+
+#define GET_FEAT_VERSION_CMD 3
extern int __qcom_scm_pil_init_image_cmd(u32 proc, u64 image_addr);
extern int __qcom_scm_pil_mem_setup_cmd(u32 proc, u64 start_addr, u32 len);
extern int __qcom_scm_pil_auth_and_reset_cmd(u32 proc);
extern int __qcom_scm_pil_shutdown_cmd(u32 proc);
+extern int __qcom_scm_iommu_dump_fault_regs(u32 id, u32 context, u64 addr,
+ u32 len);
+extern int __qcom_scm_iommu_set_cp_pool_size(u32 size, u32 spare);
+extern int __qcom_scm_iommu_secure_ptbl_size(u32 spare, int psize[2]);
+extern int __qcom_scm_iommu_secure_ptbl_init(u64 addr, u32 size, u32 spare);
+extern int __qcom_scm_iommu_secure_map(u64 list, u32 list_size, u32 size,
+ u32 id, u32 ctx_id, u64 va,
+ u32 info_size, u32 flags);
+extern int __qcom_scm_iommu_secure_unmap(u32 id, u32 ctx_id, u64 va,
+ u32 size, u32 flags);
+
+extern int __qcom_scm_is_call_available(u32 svc_id, u32 cmd_id);
+extern int __qcom_scm_get_feat_version(u32 feat);
+extern int __qcom_scm_restore_sec_cfg(u32 device_id, u32 spare);
+
#endif
diff --git a/include/linux/qcom_scm.h b/include/linux/qcom_scm.h
index 4c1e43c74f18..8ef9217082a6 100644
--- a/include/linux/qcom_scm.h
+++ b/include/linux/qcom_scm.h
@@ -49,4 +49,19 @@ extern int qcom_scm_pil_mem_setup_cmd(u32 proc, u64 start_addr, u32 len);
extern int qcom_scm_pil_auth_and_reset_cmd(u32 proc);
extern int qcom_scm_pil_shutdown_cmd(u32 proc);
+extern int qcom_scm_iommu_dump_fault_regs(u32 id, u32 context, u64 addr,
+ u32 len);
+extern int qcom_scm_iommu_set_cp_pool_size(u32 size, u32 spare);
+extern int qcom_scm_iommu_secure_ptbl_size(u32 spare, int psize[2]);
+extern int qcom_scm_iommu_secure_ptbl_init(u64 addr, u32 size, u32 spare);
+extern int qcom_scm_iommu_secure_map(u64 list, u32 list_size, u32 size,
+ u32 id, u32 ctx_id, u64 va,
+ u32 info_size, u32 flags);
+extern int qcom_scm_iommu_secure_unmap(u32 id, u32 ctx_id, u64 va,
+ u32 size, u32 flags);
+
+extern int qcom_scm_is_call_available(u32 svc_id, u32 cmd_id);
+extern int qcom_scm_get_feat_version(u32 feat);
+extern int qcom_scm_restore_sec_cfg(u32 device_id, u32 spare);
+
#endif