soc: qcom: pil: Allow the MBA memory to be dynamic or a carveout

Currently, the MBA is expected to be loadable at any
region in DDR. However, due to limitations in the modem
PBL or MBA image, this is not always possible. Allow
the modem to be loaded in a carved out CMA heap if specified
in device tree. Current memory APIs do not allow the association
of more than one memory region with a device; therefore
allow the existence of an optional sub-device node that
will contain the memory region property for the MBA.

CRs-Fixed: 2006100
Change-Id: Ia2b52be55f0b3f23278e1f71106fdb46de1d0fe1
Signed-off-by: Vikram Mulukutla <markivx@codeaurora.org>
Signed-off-by: Puja Gupta <pujag@codeaurora.org>
This commit is contained in:
Puja Gupta 2016-05-04 12:03:31 -07:00
parent 3a7e752617
commit 11bc358160
4 changed files with 80 additions and 23 deletions

View file

@ -89,6 +89,13 @@ Optional properties:
- qcom,cx-ipeak-vote: Boolean- Present if we need to set bit 5 of cxip_lm_vote_clear
during modem shutdown
One child node to represent the MBA image may be specified, when the MBA image
needs to be loaded in a specifically carved out memory region.
Required properties:
- compatible: Must be "qcom,pil-mba-mem"
- memory-region: A phandle that points to a reserved memory where the MBA image will be loaded.
Example:
qcom,mss@fc880000 {
compatible = "qcom,pil-q6v5-mss";
@ -128,4 +135,9 @@ Example:
qcom,gpio-force-stop = <&smp2pgpio_ssr_smp2p_1_out 0 0>;
qcom,ssctl-instance-id = <12>;
qcom,sysmon-id = <0>;
qcom,mba-mem@0 {
compatible = "qcom,pil-mba-mem";
memory-region = <&peripheral_mem>;
};
};

View file

@ -1,4 +1,4 @@
/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@ -332,6 +332,7 @@ int __pil_mss_deinit_image(struct pil_desc *pil, bool err_path)
struct modem_data *drv = dev_get_drvdata(pil->dev);
struct q6v5_data *q6_drv = container_of(pil, struct q6v5_data, desc);
int ret = 0;
struct device *dma_dev = drv->mba_mem_dev_fixed ?: &drv->mba_mem_dev;
s32 status;
u64 val = is_timeout_disabled() ? 0 : pbl_mba_boot_timeout_ms * 1000;
@ -360,7 +361,7 @@ int __pil_mss_deinit_image(struct pil_desc *pil, bool err_path)
if (pil->subsys_vmid > 0)
pil_assign_mem_to_linux(pil, drv->q6->mba_dp_phys,
drv->q6->mba_dp_size);
dma_free_attrs(&drv->mba_mem_dev, drv->q6->mba_dp_size,
dma_free_attrs(dma_dev, drv->q6->mba_dp_size,
drv->q6->mba_dp_virt, drv->q6->mba_dp_phys,
&drv->attrs_dma);
drv->q6->mba_dp_virt = NULL;
@ -552,6 +553,7 @@ int pil_mss_reset_load_mba(struct pil_desc *pil)
dma_addr_t mba_dp_phys, mba_dp_phys_end;
int ret, count;
const u8 *data;
struct device *dma_dev = md->mba_mem_dev_fixed ?: &md->mba_mem_dev;
fw_name_p = drv->non_elf_image ? fw_name_legacy : fw_name;
ret = request_firmware(&fw, fw_name_p, pil->dev);
@ -570,11 +572,12 @@ int pil_mss_reset_load_mba(struct pil_desc *pil)
drv->mba_dp_size = SZ_1M;
arch_setup_dma_ops(&md->mba_mem_dev, 0, 0, NULL, 0);
arch_setup_dma_ops(dma_dev, 0, 0, NULL, 0);
dma_dev->coherent_dma_mask = DMA_BIT_MASK(sizeof(dma_addr_t) * 8);
md->mba_mem_dev.coherent_dma_mask =
DMA_BIT_MASK(sizeof(dma_addr_t) * 8);
init_dma_attrs(&md->attrs_dma);
dma_set_attr(DMA_ATTR_SKIP_ZEROING, &md->attrs_dma);
dma_set_attr(DMA_ATTR_STRONGLY_ORDERED, &md->attrs_dma);
ret = request_firmware(&dp_fw, dp_name, pil->dev);
@ -591,10 +594,10 @@ int pil_mss_reset_load_mba(struct pil_desc *pil)
drv->mba_dp_size += drv->dp_size;
}
mba_dp_virt = dma_alloc_attrs(&md->mba_mem_dev, drv->mba_dp_size,
&mba_dp_phys, GFP_KERNEL, &md->attrs_dma);
mba_dp_virt = dma_alloc_attrs(dma_dev, drv->mba_dp_size, &mba_dp_phys,
GFP_KERNEL, &md->attrs_dma);
if (!mba_dp_virt) {
dev_err(pil->dev, "%s MBA metadata buffer allocation %zx bytes failed\n",
dev_err(pil->dev, "%s MBA/DP buffer allocation %zx bytes failed\n",
__func__, drv->mba_dp_size);
ret = -ENOMEM;
goto err_invalid_fw;
@ -651,7 +654,7 @@ err_mss_reset:
pil_assign_mem_to_linux(pil, drv->mba_dp_phys,
drv->mba_dp_size);
err_mba_data:
dma_free_attrs(&md->mba_mem_dev, drv->mba_dp_size, drv->mba_dp_virt,
dma_free_attrs(dma_dev, drv->mba_dp_size, drv->mba_dp_virt,
drv->mba_dp_phys, &md->attrs_dma);
err_invalid_fw:
if (dp_fw)
@ -670,14 +673,16 @@ static int pil_msa_auth_modem_mdt(struct pil_desc *pil, const u8 *metadata,
s32 status;
int ret;
u64 val = is_timeout_disabled() ? 0 : modem_auth_timeout_ms * 1000;
struct device *dma_dev = drv->mba_mem_dev_fixed ?: &drv->mba_mem_dev;
DEFINE_DMA_ATTRS(attrs);
drv->mba_mem_dev.coherent_dma_mask =
DMA_BIT_MASK(sizeof(dma_addr_t) * 8);
dma_dev->coherent_dma_mask = DMA_BIT_MASK(sizeof(dma_addr_t) * 8);
dma_set_attr(DMA_ATTR_SKIP_ZEROING, &attrs);
dma_set_attr(DMA_ATTR_STRONGLY_ORDERED, &attrs);
/* Make metadata physically contiguous and 4K aligned. */
mdata_virt = dma_alloc_attrs(&drv->mba_mem_dev, size, &mdata_phys,
GFP_KERNEL, &attrs);
mdata_virt = dma_alloc_attrs(dma_dev, size, &mdata_phys, GFP_KERNEL,
&attrs);
if (!mdata_virt) {
dev_err(pil->dev, "%s MBA metadata buffer allocation %zx bytes failed\n",
__func__, size);
@ -694,8 +699,8 @@ static int pil_msa_auth_modem_mdt(struct pil_desc *pil, const u8 *metadata,
if (ret) {
pr_err("scm_call to unprotect modem metadata mem failed(rc:%d)\n",
ret);
dma_free_attrs(&drv->mba_mem_dev, size, mdata_virt,
mdata_phys, &attrs);
dma_free_attrs(dma_dev, size, mdata_virt, mdata_phys,
&attrs);
goto fail;
}
}
@ -721,7 +726,7 @@ static int pil_msa_auth_modem_mdt(struct pil_desc *pil, const u8 *metadata,
if (pil->subsys_vmid > 0)
pil_assign_mem_to_linux(pil, mdata_phys, ALIGN(size, SZ_4K));
dma_free_attrs(&drv->mba_mem_dev, size, mdata_virt, mdata_phys, &attrs);
dma_free_attrs(dma_dev, size, mdata_virt, mdata_phys, &attrs);
if (!ret)
return ret;
@ -733,7 +738,7 @@ fail:
if (pil->subsys_vmid > 0)
pil_assign_mem_to_linux(pil, drv->q6->mba_dp_phys,
drv->q6->mba_dp_size);
dma_free_attrs(&drv->mba_mem_dev, drv->q6->mba_dp_size,
dma_free_attrs(dma_dev, drv->q6->mba_dp_size,
drv->q6->mba_dp_virt, drv->q6->mba_dp_phys,
&drv->attrs_dma);
drv->q6->mba_dp_virt = NULL;
@ -785,6 +790,7 @@ static int pil_msa_mba_auth(struct pil_desc *pil)
struct modem_data *drv = dev_get_drvdata(pil->dev);
struct q6v5_data *q6_drv = container_of(pil, struct q6v5_data, desc);
int ret;
struct device *dma_dev = drv->mba_mem_dev_fixed ?: &drv->mba_mem_dev;
s32 status;
u64 val = is_timeout_disabled() ? 0 : modem_auth_timeout_ms * 1000;
@ -806,9 +812,9 @@ static int pil_msa_mba_auth(struct pil_desc *pil)
pil_assign_mem_to_linux(pil,
drv->q6->mba_dp_phys,
drv->q6->mba_dp_size);
dma_free_attrs(&drv->mba_mem_dev, drv->q6->mba_dp_size,
drv->q6->mba_dp_virt,
drv->q6->mba_dp_phys, &drv->attrs_dma);
dma_free_attrs(dma_dev, drv->q6->mba_dp_size,
drv->q6->mba_dp_virt, drv->q6->mba_dp_phys,
&drv->attrs_dma);
drv->q6->mba_dp_virt = NULL;
}

View file

@ -1,4 +1,4 @@
/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@ -32,6 +32,7 @@ struct modem_data {
struct clk *xo;
struct pil_desc desc;
struct device mba_mem_dev;
struct device *mba_mem_dev_fixed;
struct dma_attrs attrs_dma;
};

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@ -14,6 +14,7 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/of_platform.h>
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/ioport.h>
@ -394,6 +395,11 @@ static int pil_mss_driver_probe(struct platform_device *pdev)
}
init_completion(&drv->stop_ack);
/* Probe the MBA mem device if present */
ret = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
if (ret)
return ret;
return pil_subsys_init(drv, pdev);
}
@ -407,6 +413,33 @@ static int pil_mss_driver_exit(struct platform_device *pdev)
return 0;
}
static int pil_mba_mem_driver_probe(struct platform_device *pdev)
{
struct modem_data *drv;
if (!pdev->dev.parent) {
pr_err("No parent found.\n");
return -EINVAL;
}
drv = dev_get_drvdata(pdev->dev.parent);
drv->mba_mem_dev_fixed = &pdev->dev;
return 0;
}
static const struct of_device_id mba_mem_match_table[] = {
{ .compatible = "qcom,pil-mba-mem" },
{}
};
static struct platform_driver pil_mba_mem_driver = {
.probe = pil_mba_mem_driver_probe,
.driver = {
.name = "pil-mba-mem",
.of_match_table = mba_mem_match_table,
.owner = THIS_MODULE,
},
};
static struct of_device_id mss_match_table[] = {
{ .compatible = "qcom,pil-q6v5-mss" },
{ .compatible = "qcom,pil-q6v55-mss" },
@ -426,7 +459,12 @@ static struct platform_driver pil_mss_driver = {
static int __init pil_mss_init(void)
{
return platform_driver_register(&pil_mss_driver);
int ret;
ret = platform_driver_register(&pil_mba_mem_driver);
if (!ret)
ret = platform_driver_register(&pil_mss_driver);
return ret;
}
module_init(pil_mss_init);