[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <1488996202-1546-2-git-send-email-akdwived@codeaurora.org>
Date: Wed, 8 Mar 2017 23:33:21 +0530
From: Avaneesh Kumar Dwivedi <akdwived@...eaurora.org>
To: bjorn.andersson@...aro.org
Cc: sboyd@...eaurora.org, agross@...eaurora.org,
linux-arm-msm@...r.kernel.org, linux-kernel@...r.kernel.org,
linux-remoteproc@...r.kernel.org,
Avaneesh Kumar Dwivedi <akdwived@...eaurora.org>
Subject: [PATCH v3 1/2] soc: qcom: Add support of scm call for mss rproc to share access of ddr
This patch add scm call support to make hypervisor call to enable access
of fw regions in ddr to mss subsystem on arm-v8 arch soc's.
Signed-off-by: Avaneesh Kumar Dwivedi <akdwived@...eaurora.org>
---
drivers/firmware/qcom_scm-64.c | 25 +++++++
drivers/firmware/qcom_scm.c | 93 ++++++++++++++++++++++++++
drivers/firmware/qcom_scm.h | 3 +
drivers/remoteproc/qcom_q6v5_pil.c | 129 ++++++++++++++++++++++++++++++++++++-
include/linux/qcom_scm.h | 14 ++++
5 files changed, 262 insertions(+), 2 deletions(-)
diff --git a/drivers/firmware/qcom_scm-64.c b/drivers/firmware/qcom_scm-64.c
index 4a0f5ea..187fc00 100644
--- a/drivers/firmware/qcom_scm-64.c
+++ b/drivers/firmware/qcom_scm-64.c
@@ -358,3 +358,28 @@ int __qcom_scm_pas_mss_reset(struct device *dev, bool reset)
return ret ? : res.a1;
}
+
+int __qcom_scm_assign_mem(struct device *dev, struct vmid_detail vmid)
+{
+ int ret;
+ struct qcom_scm_desc desc = {0};
+ struct arm_smccc_res res;
+
+ desc.args[0] = vmid.fw_phy;
+ desc.args[1] = vmid.size_fw;
+ desc.args[2] = vmid.from_phy;
+ desc.args[3] = vmid.size_from;
+ desc.args[4] = vmid.to_phy;
+ desc.args[5] = vmid.size_to;
+ desc.args[6] = 0;
+
+ desc.arginfo = QCOM_SCM_ARGS(7, QCOM_SCM_RO, QCOM_SCM_VAL,
+ QCOM_SCM_RO, QCOM_SCM_VAL, QCOM_SCM_RO,
+ QCOM_SCM_VAL, QCOM_SCM_VAL);
+
+ ret = qcom_scm_call(dev, QCOM_SCM_SVC_MP,
+ QCOM_MEM_PROT_ASSIGN_ID,
+ &desc, &res);
+
+ return ret ? : res.a1;
+}
diff --git a/drivers/firmware/qcom_scm.c b/drivers/firmware/qcom_scm.c
index 893f953ea..f137f34 100644
--- a/drivers/firmware/qcom_scm.c
+++ b/drivers/firmware/qcom_scm.c
@@ -42,6 +42,18 @@ struct qcom_scm {
static struct qcom_scm *__scm;
+struct dest_vm_and_perm_info {
+ __le32 vm;
+ __le32 perm;
+ __le32 *ctx;
+ __le32 ctx_size;
+};
+
+struct fw_region_info {
+ __le64 addr;
+ __le64 size;
+};
+
static int qcom_scm_clk_enable(void)
{
int ret;
@@ -292,6 +304,87 @@ int qcom_scm_pas_shutdown(u32 peripheral)
}
EXPORT_SYMBOL(qcom_scm_pas_shutdown);
+/**
+ * qcom_scm_assign_mem() - Allocate and fill vmid detail of old
+ * new owners of memory region for fw and metadata etc, Which is
+ * further passed to hypervisor, which does translate intermediate
+ * physical address used by subsystems.
+ * @vmid: structure with pointers and size detail of old and new
+ * owners vmid detail.
+ * Return 0 on success.
+ */
+int qcom_scm_assign_mem(struct vmid_detail vmid)
+{
+ unsigned long dma_attrs = DMA_ATTR_FORCE_CONTIGUOUS;
+ struct dest_vm_and_perm_info *to;
+ struct fw_region_info *fw_info;
+ __le64 fw_phy;
+ __le32 *from;
+ int ret = -ENOMEM;
+ int i;
+
+ from = dma_alloc_attrs(__scm->dev, vmid.size_from,
+ &vmid.from_phy, GFP_KERNEL, dma_attrs);
+ if (!from) {
+ dev_err(__scm->dev,
+ "failed to allocate buffer to pass source vmid detail\n");
+ return -ENOMEM;
+ }
+ to = dma_alloc_attrs(__scm->dev, vmid.size_to,
+ &vmid.to_phy, GFP_KERNEL, dma_attrs);
+ if (!to) {
+ dev_err(__scm->dev,
+ "failed to allocate buffer to pass destination vmid detail\n");
+ goto free_src_buff;
+ }
+ fw_info = dma_alloc_attrs(__scm->dev, sizeof(*fw_info),
+ &fw_phy, GFP_KERNEL, dma_attrs);
+ if (!fw_info) {
+ dev_err(__scm->dev,
+ "failed to allocate buffer to pass firmware detail\n");
+ goto free_dest_buff;
+ }
+
+ /* copy detail of original owner of ddr region */
+ /* in physically contigious buffer */
+ memcpy(from, vmid.from, vmid.size_from);
+
+ /* fill details of new owners of ddr region*/
+ /* in physically contigious buffer */
+ for (i = 0; i < (vmid.size_to / sizeof(__le32)); i++) {
+ to[i].vm = vmid.to[i];
+ to[i].perm = vmid.permission[i];
+ to[i].ctx = NULL;
+ to[i].ctx_size = 0;
+ }
+
+ /* copy detail of firmware region whose mapping need to be done */
+ /* in physically contigious buffer */
+ fw_info->addr = vmid.fw_phy;
+ fw_info->size = vmid.size_fw;
+
+ /* reuse fw_phy and size_fw members to fill address and size of */
+ /* fw_info buffer */
+ vmid.fw_phy = fw_phy;
+ vmid.size_to = sizeof(*to) * (vmid.size_to / sizeof(__le32));
+ vmid.size_fw = sizeof(*fw_info);
+ ret = __qcom_scm_assign_mem(__scm->dev, vmid);
+ if (!ret)
+ goto free_fw_buff;
+ return ret;
+free_fw_buff:
+ dma_free_attrs(__scm->dev, sizeof(*fw_info), fw_info,
+ fw_phy, dma_attrs);
+free_dest_buff:
+ dma_free_attrs(__scm->dev, vmid.size_to, to,
+ vmid.to_phy, dma_attrs);
+free_src_buff:
+ dma_free_attrs(__scm->dev, vmid.size_from, from,
+ vmid.from_phy, dma_attrs);
+ return ret;
+}
+EXPORT_SYMBOL(qcom_scm_assign_mem);
+
static int qcom_scm_pas_reset_assert(struct reset_controller_dev *rcdev,
unsigned long idx)
{
diff --git a/drivers/firmware/qcom_scm.h b/drivers/firmware/qcom_scm.h
index 3584b00..4665a11 100644
--- a/drivers/firmware/qcom_scm.h
+++ b/drivers/firmware/qcom_scm.h
@@ -55,6 +55,9 @@ extern int __qcom_scm_pas_mem_setup(struct device *dev, u32 peripheral,
extern int __qcom_scm_pas_auth_and_reset(struct device *dev, u32 peripheral);
extern int __qcom_scm_pas_shutdown(struct device *dev, u32 peripheral);
extern int __qcom_scm_pas_mss_reset(struct device *dev, bool reset);
+#define QCOM_SCM_SVC_MP 0xc
+#define QCOM_MEM_PROT_ASSIGN_ID 0x16
+extern int __qcom_scm_assign_mem(struct device *dev, struct vmid_detail vmid);
/* common error codes */
#define QCOM_SCM_V2_EBUSY -12
diff --git a/drivers/remoteproc/qcom_q6v5_pil.c b/drivers/remoteproc/qcom_q6v5_pil.c
index 8fd697a..62ad976 100644
--- a/drivers/remoteproc/qcom_q6v5_pil.c
+++ b/drivers/remoteproc/qcom_q6v5_pil.c
@@ -110,6 +110,7 @@ struct rproc_hexagon_res {
struct qcom_mss_reg_res *active_supply;
char **proxy_clk_names;
char **active_clk_names;
+ int version;
};
struct q6v5 {
@@ -153,8 +154,28 @@ struct q6v5 {
size_t mpss_size;
struct qcom_rproc_subdev smd_subdev;
+ int version;
};
+enum {
+ MSS_MSM8916,
+ MSS_MSM8974,
+ MSS_MSM8996,
+};
+
+enum {
+ ASSIGN_ACCESS_MSA,
+ REMOVE_ACCESS_MSA,
+ ASSIGN_SHARED_ACCESS_MSA,
+ REMOVE_SHARED_ACCESS_MSA,
+};
+
+#define VMID_HLOS 0x3
+#define VMID_MSS_MSA 0xF
+#define PERM_READ 0x4
+#define PERM_WRITE 0x2
+#define PERM_EXEC 0x1
+#define PERM_RW (PERM_READ | PERM_WRITE)
static int q6v5_regulator_init(struct device *dev, struct reg_info *regs,
const struct qcom_mss_reg_res *reg_res)
{
@@ -288,6 +309,54 @@ static struct resource_table *q6v5_find_rsc_table(struct rproc *rproc,
return &table;
}
+int hyp_mem_access(int id, phys_addr_t addr, size_t size)
+{
+ struct vmid_detail vmid;
+ int ret;
+
+ switch (id) {
+ case ASSIGN_ACCESS_MSA:
+ vmid.from = (int[]) { VMID_HLOS };
+ vmid.to = (int[]) { VMID_MSS_MSA };
+ vmid.permission = (int[]) { PERM_READ | PERM_WRITE };
+ vmid.size_from = vmid.size_to = 1 * sizeof(__le32);
+ break;
+ case REMOVE_ACCESS_MSA:
+ vmid.from = (int[]) { VMID_MSS_MSA };
+ vmid.to = (int[]) { VMID_HLOS };
+ vmid.permission =
+ (int[]) { PERM_READ | PERM_WRITE | PERM_EXEC };
+ vmid.size_from = vmid.size_to = 1 * sizeof(__le32);
+ break;
+ case ASSIGN_SHARED_ACCESS_MSA:
+ vmid.from = (int[]) { VMID_HLOS };
+ vmid.to = (int[]) { VMID_HLOS, VMID_MSS_MSA };
+ vmid.permission = (int[]) { PERM_RW, PERM_RW };
+ vmid.size_from = 1 * sizeof(__le32);
+ vmid.size_to = 2 * sizeof(__le32);
+ break;
+ case REMOVE_SHARED_ACCESS_MSA:
+ vmid.from = (int[]) { VMID_HLOS, VMID_MSS_MSA };
+ vmid.to = (int[]) { VMID_HLOS };
+ vmid.permission =
+ (int[]) { PERM_READ | PERM_WRITE | PERM_EXEC };
+ vmid.size_from = 2 * sizeof(__le32);
+ vmid.size_to = 1 * sizeof(__le32);
+ break;
+ default:
+ break;
+ }
+
+ vmid.fw_phy = addr;
+ vmid.size_fw = size;
+ ret = qcom_scm_assign_mem(vmid);
+ if (ret)
+ pr_err("%s: Failed to assign memory protection, ret = %d\n",
+ __func__, ret);
+
+ return ret;
+}
+
static int q6v5_load(struct rproc *rproc, const struct firmware *fw)
{
struct q6v5 *qproc = rproc->priv;
@@ -461,6 +530,15 @@ static int q6v5_mpss_init_image(struct q6v5 *qproc, const struct firmware *fw)
memcpy(ptr, fw->data, fw->size);
+ /* Hypervisor mapping to access metadata by modem */
+ ret = qproc->version == MSS_MSM8996 ?
+ hyp_mem_access(ASSIGN_ACCESS_MSA, phys,
+ ALIGN(fw->size, SZ_4K)) : 0;
+ if (ret) {
+ dev_err(qproc->dev,
+ "Failed to assign metadata memory, ret - %d\n", ret);
+ return -ENOMEM;
+ }
writel(phys, qproc->rmb_base + RMB_PMI_META_DATA_REG);
writel(RMB_CMD_META_DATA_READY, qproc->rmb_base + RMB_MBA_COMMAND_REG);
@@ -470,6 +548,13 @@ static int q6v5_mpss_init_image(struct q6v5 *qproc, const struct firmware *fw)
else if (ret < 0)
dev_err(qproc->dev, "MPSS header authentication failed: %d\n", ret);
+ /* Metadata authentication done, remove modem access */
+ ret = qproc->version == MSS_MSM8996 ?
+ hyp_mem_access(REMOVE_ACCESS_MSA, phys,
+ ALIGN(fw->size, SZ_4K)) : 0;
+ if (ret)
+ dev_err(qproc->dev,
+ "Failed to reclaim metadata memory, ret - %d\n", ret);
dma_free_attrs(qproc->dev, fw->size, ptr, phys, dma_attrs);
return ret < 0 ? ret : 0;
@@ -578,6 +663,16 @@ static int q6v5_mpss_load(struct q6v5 *qproc)
size = readl(qproc->rmb_base + RMB_PMI_CODE_LENGTH_REG);
if (!size) {
boot_addr = relocate ? qproc->mpss_phys : min_addr;
+ /* Hypervisor mapping of modem fw */
+ ret = qproc->version == MSS_MSM8996 ?
+ hyp_mem_access(ASSIGN_SHARED_ACCESS_MSA,
+ boot_addr, qproc->mpss_size) : 0;
+ if (ret) {
+ dev_err(qproc->dev,
+ "Failed to assign fw memory access, ret - %d\n",
+ ret);
+ return -ENOMEM;
+ }
writel(boot_addr, qproc->rmb_base + RMB_PMI_CODE_START_REG);
writel(RMB_CMD_LOAD_READY, qproc->rmb_base + RMB_MBA_COMMAND_REG);
}
@@ -636,6 +731,14 @@ static int q6v5_start(struct rproc *rproc)
goto assert_reset;
}
+ ret = qproc->version == MSS_MSM8996 ?
+ hyp_mem_access(ASSIGN_ACCESS_MSA, qproc->mba_phys,
+ qproc->mba_size) : 0;
+ if (ret) {
+ dev_err(qproc->dev,
+ "Failed to assign mba memory access, ret - %d\n", ret);
+ goto assert_reset;
+ }
writel(qproc->mba_phys, qproc->rmb_base + RMB_MBA_IMAGE_REG);
ret = q6v5proc_reset(qproc);
@@ -657,16 +760,22 @@ static int q6v5_start(struct rproc *rproc)
ret = q6v5_mpss_load(qproc);
if (ret)
- goto halt_axi_ports;
+ goto reclaim_mem;
ret = wait_for_completion_timeout(&qproc->start_done,
msecs_to_jiffies(5000));
if (ret == 0) {
dev_err(qproc->dev, "start timed out\n");
ret = -ETIMEDOUT;
- goto halt_axi_ports;
+ goto reclaim_mem;
}
+ ret = qproc->version == MSS_MSM8996 ?
+ hyp_mem_access(REMOVE_ACCESS_MSA, qproc->mba_phys,
+ qproc->mba_size) : 0;
+ if (ret)
+ dev_err(qproc->dev,
+ "Failed to reclaim mba memory, ret - %d\n", ret);
qproc->running = true;
q6v5_clk_disable(qproc->dev, qproc->proxy_clks,
@@ -676,7 +785,20 @@ static int q6v5_start(struct rproc *rproc)
return 0;
+reclaim_mem:
+ ret = qproc->version == MSS_MSM8996 ?
+ hyp_mem_access(REMOVE_SHARED_ACCESS_MSA,
+ qproc->mpss_phys, qproc->mpss_size) : 0;
+ if (ret)
+ dev_err(qproc->dev,
+ "Failed to reclaim fw memory, ret - %d\n", ret);
halt_axi_ports:
+ ret = qproc->version == MSS_MSM8996 ?
+ hyp_mem_access(REMOVE_ACCESS_MSA, qproc->mba_phys,
+ qproc->mba_size) : 0;
+ if (ret)
+ dev_err(qproc->dev,
+ "Failed to reclaim mba memory, ret - %d\n", ret);
q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_q6);
q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_modem);
q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_nc);
@@ -1015,6 +1137,7 @@ static int q6v5_probe(struct platform_device *pdev)
if (ret)
goto free_rproc;
+ qproc->version = desc->version;
ret = q6v5_request_irq(qproc, pdev, "wdog", q6v5_wdog_interrupt);
if (ret < 0)
goto free_rproc;
@@ -1090,6 +1213,7 @@ static int q6v5_remove(struct platform_device *pdev)
"mem",
NULL
},
+ .version = MSS_MSM8916,
};
static const struct rproc_hexagon_res msm8974_mss = {
@@ -1127,6 +1251,7 @@ static int q6v5_remove(struct platform_device *pdev)
"mem",
NULL
},
+ .version = MSS_MSM8974,
};
static const struct of_device_id q6v5_of_match[] = {
diff --git a/include/linux/qcom_scm.h b/include/linux/qcom_scm.h
index cc32ab8..cb0b7ee 100644
--- a/include/linux/qcom_scm.h
+++ b/include/linux/qcom_scm.h
@@ -23,6 +23,19 @@ struct qcom_scm_hdcp_req {
u32 val;
};
+struct vmid_detail {
+ __le32 *from;
+ __le32 *to;
+ __le32 *permission;
+ __le32 size_from;
+ __le32 size_to;
+ __le32 size_fw;
+ __le64 fw_phy;
+ __le64 from_phy;
+ __le64 to_phy;
+
+};
+
extern bool qcom_scm_is_available(void);
extern bool qcom_scm_hdcp_available(void);
@@ -36,6 +49,7 @@ 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);
+extern int qcom_scm_assign_mem(struct vmid_detail vmid);
#define QCOM_SCM_CPU_PWR_DOWN_L2_ON 0x0
#define QCOM_SCM_CPU_PWR_DOWN_L2_OFF 0x1
--
Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project.
Powered by blists - more mailing lists