From patchwork Thu May 17 11:32:20 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vikash Garodia X-Patchwork-Id: 10406651 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id CCF1460155 for ; Thu, 17 May 2018 11:34:04 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id BBF6126E98 for ; Thu, 17 May 2018 11:34:04 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id AFA7328A60; Thu, 17 May 2018 11:34:04 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.8 required=2.0 tests=BAYES_00,DKIM_SIGNED, MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI, T_DKIM_INVALID autolearn=unavailable version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id CFDA826E98 for ; Thu, 17 May 2018 11:34:03 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752232AbeEQLdu (ORCPT ); Thu, 17 May 2018 07:33:50 -0400 Received: from smtp.codeaurora.org ([198.145.29.96]:60786 "EHLO smtp.codeaurora.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751379AbeEQLdZ (ORCPT ); Thu, 17 May 2018 07:33:25 -0400 Received: by smtp.codeaurora.org (Postfix, from userid 1000) id 9739A60881; Thu, 17 May 2018 11:33:24 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=codeaurora.org; s=default; t=1526556804; bh=QsdRtUSXrCAfFlzemeXiNeBjHE7O2v1L73hO34XVe6I=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Nyu57S3+nsAlmy5ATlxlSsgrpqbGLxbG3LKP/Lw5N4JXAY718l6ZPSo7NtFgkq+ZH AzzGkAdT1WWCjBreX/Kg3NgM4R3h9yIIdrWLmQu6SIGrlUmkqzboVewVK8Hoi6TT8w Y65o3ox6kCCrkydmYc5ZaUznemLoDdLjmYVODjxk= Received: from vgarodia-linux.qualcomm.com (blr-c-bdr-fw-01_globalnat_allzones-outside.qualcomm.com [103.229.19.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-SHA256 (128/128 bits)) (No client certificate requested) (Authenticated sender: vgarodia@smtp.codeaurora.org) by smtp.codeaurora.org (Postfix) with ESMTPSA id 743D360A00; Thu, 17 May 2018 11:33:16 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=codeaurora.org; s=default; t=1526556803; bh=QsdRtUSXrCAfFlzemeXiNeBjHE7O2v1L73hO34XVe6I=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=eFgYHS9+oNoMmsAOiNqJZak+Rt0fOWlKhLi0zSaAkjuUlTGlU8lkcrCQj50KpaUBn VLfL70hbutfnKZ69axN1OVEDVHFavvDoBpUmA7d+uumHiHkNb3Hkaeb2HWTUfWF76n CUQa+dbiNSktn6Y4Y+WpCw8Y7+kbXJIGCqVE5UWs= DMARC-Filter: OpenDMARC Filter v1.3.2 smtp.codeaurora.org 743D360A00 Authentication-Results: pdx-caf-mail.web.codeaurora.org; dmarc=none (p=none dis=none) header.from=codeaurora.org Authentication-Results: pdx-caf-mail.web.codeaurora.org; spf=none smtp.mailfrom=vgarodia@codeaurora.org From: Vikash Garodia To: hverkuil@xs4all.nl, mchehab@kernel.org, andy.gross@linaro.org, bjorn.andersson@linaro.org, stanimir.varbanov@linaro.org Cc: linux-media@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-msm@vger.kernel.org, linux-soc@vger.kernel.org, acourbot@google.com, Vikash Garodia Subject: [PATCH 4/4] media: venus: add PIL support Date: Thu, 17 May 2018 17:02:20 +0530 Message-Id: <1526556740-25494-5-git-send-email-vgarodia@codeaurora.org> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1526556740-25494-1-git-send-email-vgarodia@codeaurora.org> References: <1526556740-25494-1-git-send-email-vgarodia@codeaurora.org> Sender: linux-media-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP This adds support to load the video firmware and bring ARM9 out of reset. This is useful for platforms which does not have trustzone to reset the ARM9. Signed-off-by: Vikash Garodia --- .../devicetree/bindings/media/qcom,venus.txt | 8 +- drivers/media/platform/qcom/venus/core.c | 67 +++++++-- drivers/media/platform/qcom/venus/core.h | 6 + drivers/media/platform/qcom/venus/firmware.c | 163 +++++++++++++++++---- drivers/media/platform/qcom/venus/firmware.h | 10 +- 5 files changed, 217 insertions(+), 37 deletions(-) diff --git a/Documentation/devicetree/bindings/media/qcom,venus.txt b/Documentation/devicetree/bindings/media/qcom,venus.txt index 00d0d1b..0ff0f2d 100644 --- a/Documentation/devicetree/bindings/media/qcom,venus.txt +++ b/Documentation/devicetree/bindings/media/qcom,venus.txt @@ -53,7 +53,7 @@ * Subnodes The Venus video-codec node must contain two subnodes representing -video-decoder and video-encoder. +video-decoder and video-encoder, one optional firmware subnode. Every of video-encoder or video-decoder subnode should have: @@ -79,6 +79,8 @@ Every of video-encoder or video-decoder subnode should have: power domain which is responsible for collapsing and restoring power to the subcore. +The firmware sub node must contain the iommus specifiers for ARM9. + * An Example video-codec@1d00000 { compatible = "qcom,msm8916-venus"; @@ -105,4 +107,8 @@ Every of video-encoder or video-decoder subnode should have: clock-names = "core"; power-domains = <&mmcc VENUS_CORE1_GDSC>; }; + firmware { + compatible = "qcom,venus-pil-no-tz"; + iommus = <&apps_smmu 0x10b2 0x0>; + } }; diff --git a/drivers/media/platform/qcom/venus/core.c b/drivers/media/platform/qcom/venus/core.c index 1308488..16910558 100644 --- a/drivers/media/platform/qcom/venus/core.c +++ b/drivers/media/platform/qcom/venus/core.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -30,6 +31,7 @@ #include "vdec.h" #include "venc.h" #include "firmware.h" +#include "hfi_venus.h" static void venus_event_notify(struct venus_core *core, u32 event) { @@ -76,7 +78,7 @@ static void venus_sys_error_handler(struct work_struct *work) hfi_core_deinit(core, true); hfi_destroy(core); mutex_lock(&core->lock); - venus_shutdown(core->dev); + venus_shutdown(core); pm_runtime_put_sync(core->dev); @@ -84,7 +86,7 @@ static void venus_sys_error_handler(struct work_struct *work) pm_runtime_get_sync(core->dev); - ret |= venus_boot(core->dev, core->res->fwname); + ret |= venus_boot(core); ret |= hfi_core_resume(core, true); @@ -179,6 +181,20 @@ static u32 to_v4l2_codec_type(u32 codec) } } +static int store_firmware_dev(struct device *dev, void *data) +{ + struct venus_core *core; + + core = (struct venus_core *)data; + if (!core) + return -EINVAL; + + if (of_device_is_compatible(dev->of_node, "qcom,venus-pil-no-tz")) + core->fw.dev = dev; + + return 0; +} + static int venus_enumerate_codecs(struct venus_core *core, u32 type) { const struct hfi_inst_ops dummy_ops = {}; @@ -229,6 +245,7 @@ static int venus_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct venus_core *core; struct resource *r; + struct iommu_domain *iommu_domain; int ret; core = devm_kzalloc(dev, sizeof(*core), GFP_KERNEL); @@ -279,7 +296,14 @@ static int venus_probe(struct platform_device *pdev) if (ret < 0) goto err_runtime_disable; - ret = venus_boot(dev, core->res->fwname); + ret = of_platform_populate(dev->of_node, NULL, NULL, dev); + if (ret) + goto err_runtime_disable; + + /* Attempt to register child devices */ + ret = device_for_each_child(dev, core, store_firmware_dev); + + ret = venus_boot(core); if (ret) goto err_runtime_disable; @@ -303,14 +327,17 @@ static int venus_probe(struct platform_device *pdev) if (ret) goto err_core_deinit; - ret = of_platform_populate(dev->of_node, NULL, NULL, dev); + ret = pm_runtime_put_sync(dev); if (ret) goto err_dev_unregister; - ret = pm_runtime_put_sync(dev); - if (ret) + iommu_domain = iommu_get_domain_for_dev(dev); + if (!iommu_domain) goto err_dev_unregister; + iommu_domain->geometry.aperture_start = VENUS_FW_MEM_SIZE; + iommu_domain->geometry.aperture_end = VENUS_MAX_MEM_REGION; + return 0; err_dev_unregister: @@ -318,7 +345,7 @@ static int venus_probe(struct platform_device *pdev) err_core_deinit: hfi_core_deinit(core, false); err_venus_shutdown: - venus_shutdown(dev); + venus_shutdown(core); err_runtime_disable: pm_runtime_set_suspended(dev); pm_runtime_disable(dev); @@ -339,7 +366,7 @@ static int venus_remove(struct platform_device *pdev) WARN_ON(ret); hfi_destroy(core); - venus_shutdown(dev); + venus_shutdown(core); of_platform_depopulate(dev); pm_runtime_put_sync(dev); @@ -483,7 +510,29 @@ static __maybe_unused int venus_runtime_resume(struct device *dev) .pm = &venus_pm_ops, }, }; -module_platform_driver(qcom_venus_driver); + +static int __init venus_init(void) +{ + int ret; + + ret = platform_driver_register(&qcom_video_firmware_driver); + if (ret) + return ret; + + ret = platform_driver_register(&qcom_venus_driver); + if (ret) + platform_driver_unregister(&qcom_video_firmware_driver); + + return ret; +} +module_init(venus_init); + +static void __exit venus_exit(void) +{ + platform_driver_unregister(&qcom_venus_driver); + platform_driver_unregister(&qcom_video_firmware_driver); +} +module_exit(venus_exit); MODULE_ALIAS("platform:qcom-venus"); MODULE_DESCRIPTION("Qualcomm Venus video encoder and decoder driver"); diff --git a/drivers/media/platform/qcom/venus/core.h b/drivers/media/platform/qcom/venus/core.h index 85e66e2..68fc8af 100644 --- a/drivers/media/platform/qcom/venus/core.h +++ b/drivers/media/platform/qcom/venus/core.h @@ -80,6 +80,11 @@ struct venus_caps { bool valid; }; +struct video_firmware { + struct device *dev; + dma_addr_t iova; + struct iommu_domain *iommu_domain; +}; /** * struct venus_core - holds core parameters valid for all instances * @@ -124,6 +129,7 @@ struct venus_core { struct device *dev; struct device *dev_dec; struct device *dev_enc; + struct video_firmware fw; struct mutex lock; struct list_head instances; atomic_t insts_count; diff --git a/drivers/media/platform/qcom/venus/firmware.c b/drivers/media/platform/qcom/venus/firmware.c index 8f25375..614c805 100644 --- a/drivers/media/platform/qcom/venus/firmware.c +++ b/drivers/media/platform/qcom/venus/firmware.c @@ -12,8 +12,12 @@ * */ +#include +#include +#include #include #include +#include #include #include #include @@ -27,8 +31,10 @@ #include "firmware.h" #include "hfi_venus_io.h" -#define VENUS_PAS_ID 9 -#define VENUS_FW_MEM_SIZE (6 * SZ_1M) +static const struct of_device_id firmware_dt_match[] = { + { .compatible = "qcom,venus-pil-no-tz" }, + { } +}; void venus_reset_hw(struct venus_core *core) { @@ -53,40 +59,37 @@ void venus_reset_hw(struct venus_core *core) /* Bring Arm9 out of reset */ writel_relaxed(0, reg_base + WRAPPER_A9SS_SW_RESET); } -int venus_boot(struct device *dev, const char *fwname) +EXPORT_SYMBOL_GPL(venus_reset_hw); + +int venus_load_fw(struct device *dev, const char *fwname, + phys_addr_t *mem_phys, size_t *mem_size) { const struct firmware *mdt; struct device_node *node; - phys_addr_t mem_phys; struct resource r; ssize_t fw_size; - size_t mem_size; void *mem_va; int ret; - if (!IS_ENABLED(CONFIG_QCOM_MDT_LOADER) || !qcom_scm_is_available()) - return -EPROBE_DEFER; - node = of_parse_phandle(dev->of_node, "memory-region", 0); if (!node) { dev_err(dev, "no memory-region specified\n"); return -EINVAL; } - ret = of_address_to_resource(node, 0, &r); if (ret) return ret; - mem_phys = r.start; - mem_size = resource_size(&r); + *mem_phys = r.start; + *mem_size = resource_size(&r); - if (mem_size < VENUS_FW_MEM_SIZE) + if (*mem_size < VENUS_FW_MEM_SIZE) return -EINVAL; - mem_va = memremap(r.start, mem_size, MEMREMAP_WC); + mem_va = memremap(r.start, *mem_size, MEMREMAP_WC); if (!mem_va) { dev_err(dev, "unable to map memory region: %pa+%zx\n", - &r.start, mem_size); + &r.start, *mem_size); return -ENOMEM; } @@ -101,24 +104,134 @@ int venus_boot(struct device *dev, const char *fwname) goto err_unmap; } - ret = qcom_mdt_load(dev, mdt, fwname, VENUS_PAS_ID, mem_va, mem_phys, - mem_size, NULL); + ret = qcom_mdt_load(dev, mdt, fwname, VENUS_PAS_ID, mem_va, *mem_phys, + *mem_size, NULL); release_firmware(mdt); - if (ret) - goto err_unmap; - - ret = qcom_scm_pas_auth_and_reset(VENUS_PAS_ID); - if (ret) - goto err_unmap; - err_unmap: memunmap(mem_va); return ret; } -int venus_shutdown(struct device *dev) +int venus_boot_noTZ(struct venus_core *core, phys_addr_t mem_phys, + size_t mem_size) { - return qcom_scm_pas_shutdown(VENUS_PAS_ID); + struct iommu_domain *iommu; + struct device *dev; + int ret; + + if (!core->fw.dev) + return -EPROBE_DEFER; + + dev = core->fw.dev; + + iommu = iommu_domain_alloc(&platform_bus_type); + if (!iommu) { + dev_err(dev, "Failed to allocate iommu domain\n"); + return -ENOMEM; + } + + iommu->geometry.aperture_start = 0x0; + iommu->geometry.aperture_end = VENUS_FW_MEM_SIZE; + + ret = iommu_attach_device(iommu, dev); + if (ret) { + dev_err(dev, "could not attach device\n"); + goto err_attach; + } + + ret = iommu_map(iommu, core->fw.iova, mem_phys, mem_size, + IOMMU_READ|IOMMU_WRITE|IOMMU_PRIV); + if (ret) { + dev_err(dev, "could not map video firmware region\n"); + goto err_map; + } + core->fw.iommu_domain = iommu; + venus_reset_hw(core); + + return 0; + +err_map: + iommu_detach_device(iommu, dev); +err_attach: + iommu_domain_free(iommu); + return ret; } + +int venus_shutdown_noTZ(struct venus_core *core) +{ + struct iommu_domain *iommu; + u32 reg; + struct device *dev = core->fw.dev; + void __iomem *reg_base = core->base; + + /* Assert the reset to ARM9 */ + reg = readl_relaxed(reg_base + WRAPPER_A9SS_SW_RESET); + reg |= BIT(4); + writel_relaxed(reg, reg_base + WRAPPER_A9SS_SW_RESET); + + /* Make sure reset is asserted before the mapping is removed */ + mb(); + + iommu = core->fw.iommu_domain; + + iommu_unmap(iommu, core->fw.iova, VENUS_FW_MEM_SIZE); + iommu_detach_device(iommu, dev); + iommu_domain_free(iommu); + + return 0; +} + +int venus_boot(struct venus_core *core) +{ + phys_addr_t mem_phys; + size_t mem_size; + int ret; + struct device *dev; + + if (!IS_ENABLED(CONFIG_QCOM_MDT_LOADER)) + return -EPROBE_DEFER; + + dev = core->dev; + + ret = venus_load_fw(dev, core->res->fwname, &mem_phys, &mem_size); + if (ret) { + dev_err(dev, "fail to load video firmware\n"); + return -EINVAL; + } + + if (qcom_scm_is_available()) + ret = qcom_scm_pas_auth_and_reset(VENUS_PAS_ID); + else + ret = venus_boot_noTZ(core, mem_phys, mem_size); + + return ret; +} +EXPORT_SYMBOL_GPL(venus_boot); + +int venus_shutdown(struct venus_core *core) +{ + int ret = 0; + + if (qcom_scm_is_available()) + qcom_scm_pas_shutdown(VENUS_PAS_ID); + else + ret = venus_shutdown_noTZ(core); + + return ret; +} +EXPORT_SYMBOL_GPL(venus_shutdown); + +MODULE_DEVICE_TABLE(of, firmware_dt_match); + +struct platform_driver qcom_video_firmware_driver = { + .driver = { + .name = "qcom-video-firmware", + .of_match_table = firmware_dt_match, + }, +}; + +MODULE_ALIAS("platform:qcom-video-firmware"); +MODULE_DESCRIPTION("Qualcomm Venus firmware driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/qcom/venus/firmware.h b/drivers/media/platform/qcom/venus/firmware.h index d56f5b2..bce8f0a 100644 --- a/drivers/media/platform/qcom/venus/firmware.h +++ b/drivers/media/platform/qcom/venus/firmware.h @@ -14,10 +14,16 @@ #ifndef __VENUS_FIRMWARE_H__ #define __VENUS_FIRMWARE_H__ +#define VENUS_PAS_ID 9 +#define VENUS_FW_MEM_SIZE (6 * SZ_1M) +#define VENUS_MAX_MEM_REGION 0xE0000000 + struct device; -int venus_boot(struct device *dev, const char *fwname); -int venus_shutdown(struct device *dev); +extern struct platform_driver qcom_video_firmware_driver; + +int venus_boot(struct venus_core *core); +int venus_shutdown(struct venus_core *core); void venus_reset_hw(struct venus_core *core); #endif