diff --git a/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt b/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt index be5633024986..47a6fdd300ca 100644 --- a/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt +++ b/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt @@ -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>; + }; }; diff --git a/drivers/soc/qcom/pil-msa.c b/drivers/soc/qcom/pil-msa.c index bbd77d8e0650..53bddc5987df 100644 --- a/drivers/soc/qcom/pil-msa.c +++ b/drivers/soc/qcom/pil-msa.c @@ -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; } diff --git a/drivers/soc/qcom/pil-msa.h b/drivers/soc/qcom/pil-msa.h index fea8e1f9db37..896f0c7c232b 100644 --- a/drivers/soc/qcom/pil-msa.h +++ b/drivers/soc/qcom/pil-msa.h @@ -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; }; diff --git a/drivers/soc/qcom/pil-q6v5-mss.c b/drivers/soc/qcom/pil-q6v5-mss.c index 5f01d30de8d9..0e023a019280 100644 --- a/drivers/soc/qcom/pil-q6v5-mss.c +++ b/drivers/soc/qcom/pil-q6v5-mss.c @@ -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 #include #include +#include #include #include #include @@ -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);