From patchwork Fri Jun 3 23:25:22 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andy Gross X-Patchwork-Id: 9154321 X-Patchwork-Delegate: agross@codeaurora.org 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 B487A60751 for ; Fri, 3 Jun 2016 23:28:46 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id A5B4D28334 for ; Fri, 3 Jun 2016 23:28:46 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 9A27528345; Fri, 3 Jun 2016 23:28:46 +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=-6.8 required=2.0 tests=BAYES_00,DKIM_SIGNED, 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 2982328334 for ; Fri, 3 Jun 2016 23:28:46 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1750974AbcFCX2b (ORCPT ); Fri, 3 Jun 2016 19:28:31 -0400 Received: from mail-oi0-f50.google.com ([209.85.218.50]:35363 "EHLO mail-oi0-f50.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1750826AbcFCXZr (ORCPT ); Fri, 3 Jun 2016 19:25:47 -0400 Received: by mail-oi0-f50.google.com with SMTP id w184so149829402oiw.2 for ; Fri, 03 Jun 2016 16:25:46 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=nA1y7bhJoh1CKr4Ffmat1HTv5jZvfBdY4nOULObOSYw=; b=hAWcs3IVa6aNQaFgXm1CMr0ujrjl4uZ3abC49tXH6UUK2XUn1X5KehGMVGwB0cdbgf a/83X2xlHWN0In006SSDJkK+KRgCmVMu3rOyeHFMVEy+7PeGXll8GVT/TVZh7elScyGF L0XyEudYaDz/koOYNbIUdwk6wLkRTWZU67YNQ= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=nA1y7bhJoh1CKr4Ffmat1HTv5jZvfBdY4nOULObOSYw=; b=DhBqnrgv5KdSc0vaRDSQKSX8UKB37L9pTuMG2qFlun4UaYZHST2bwwroDjKcqRIVop Dxe2pNzQ49vSh5TjMDllim6+uJ3NpgYUuL2UJCHff4C7gNhSzpFQ69gJRzlF2hKZuLDs SoDH2gZ4IL4yG4/T0tvymoBPJ3D6Q93F4j9djGpWSliUPLPD6XyglX2OVPvB2iLSDAv/ 0TSclqSh60UjeiEYyUKAsMOrniFbC2BgN0aAwHFT/0V26nI5xZYz7b+TrAN4SxKg9/Ac 9L+FBhii46DSW/PmDl7C92uqEOQ8aQ2pkF87QsDfXyTlJYdmv3TNSjToeD4O/Fu2mDaz iEpA== X-Gm-Message-State: ALyK8tImwB2DYnebtQy7sHABykWEgWUzD2Ad1EA564zV+NX/C4h1RaQVCtClocifaeYDI0mu X-Received: by 10.202.89.68 with SMTP id n65mr2992365oib.138.1464996345791; Fri, 03 Jun 2016 16:25:45 -0700 (PDT) Received: from localhost ([2602:306:c558:19b0:a575:d8f4:7700:e330]) by smtp.gmail.com with ESMTPSA id k3sm4382931oih.27.2016.06.03.16.25.45 (version=TLS1_2 cipher=AES128-SHA bits=128/128); Fri, 03 Jun 2016 16:25:45 -0700 (PDT) From: Andy Gross To: linux-arm-msm@vger.kernel.org Cc: linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, Bjorn Andersson , Stephen Boyd , devicetree@vger.kernel.org, jilai wang , Andy Gross Subject: [Patch v6 02/10] firmware: qcom: scm: Convert SCM to platform driver Date: Fri, 3 Jun 2016 18:25:22 -0500 Message-Id: <1464996330-16952-3-git-send-email-andy.gross@linaro.org> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1464996330-16952-1-git-send-email-andy.gross@linaro.org> References: <1464996330-16952-1-git-send-email-andy.gross@linaro.org> Sender: linux-arm-msm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-arm-msm@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP This patch converts the Qualcomm SCM firmware driver into a platform driver. It also adds clock management for firmware calls which require clocks to be enabled during the duration of their execution. Rate setting of the core clock is also in place for higher performance. Signed-off-by: Andy Gross Acked-by: Bjorn Andersson Reviewed-by: Stephen Boyd --- drivers/firmware/qcom_scm.c | 174 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 165 insertions(+), 9 deletions(-) diff --git a/drivers/firmware/qcom_scm.c b/drivers/firmware/qcom_scm.c index 45c008d..c4ec60d 100644 --- a/drivers/firmware/qcom_scm.c +++ b/drivers/firmware/qcom_scm.c @@ -10,19 +10,61 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. */ - +#include +#include #include #include #include #include +#include +#include +#include #include "qcom_scm.h" +struct qcom_scm { + struct device *dev; + struct clk *core_clk; + struct clk *iface_clk; + struct clk *bus_clk; +}; + +static struct qcom_scm *__scm; + +static int qcom_scm_clk_enable(void) +{ + int ret; + + ret = clk_prepare_enable(__scm->core_clk); + if (ret) + goto bail; + + ret = clk_prepare_enable(__scm->iface_clk); + if (ret) + goto disable_core; + + ret = clk_prepare_enable(__scm->bus_clk); + if (ret) + goto disable_iface; + + return 0; + +disable_iface: + clk_disable_unprepare(__scm->iface_clk); +disable_core: + clk_disable_unprepare(__scm->core_clk); +bail: + return ret; +} + +static void qcom_scm_clk_disable(void) +{ + clk_disable_unprepare(__scm->core_clk); + clk_disable_unprepare(__scm->iface_clk); + clk_disable_unprepare(__scm->bus_clk); +} + /** * qcom_scm_set_cold_boot_addr() - Set the cold boot address for cpus * @entry: Entry point function for the cpus @@ -72,12 +114,17 @@ EXPORT_SYMBOL(qcom_scm_cpu_power_down); */ bool qcom_scm_hdcp_available(void) { - int ret; + int ret = qcom_scm_clk_enable(); + + if (ret) + return ret; ret = __qcom_scm_is_call_available(QCOM_SCM_SVC_HDCP, - QCOM_SCM_CMD_HDCP); + QCOM_SCM_CMD_HDCP); + + qcom_scm_clk_disable(); - return (ret > 0) ? true : false; + return ret > 0 ? true : false; } EXPORT_SYMBOL(qcom_scm_hdcp_available); @@ -91,6 +138,115 @@ EXPORT_SYMBOL(qcom_scm_hdcp_available); */ int qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt, u32 *resp) { - return __qcom_scm_hdcp_req(req, req_cnt, resp); + int ret = qcom_scm_clk_enable(); + + if (ret) + return ret; + + ret = __qcom_scm_hdcp_req(req, req_cnt, resp); + qcom_scm_clk_disable(); + return ret; } EXPORT_SYMBOL(qcom_scm_hdcp_req); + +static int qcom_scm_probe(struct platform_device *pdev) +{ + struct qcom_scm *scm; + int ret; + + scm = devm_kzalloc(&pdev->dev, sizeof(*scm), GFP_KERNEL); + if (!scm) + return -ENOMEM; + + scm->core_clk = devm_clk_get(&pdev->dev, "core"); + if (IS_ERR(scm->core_clk)) { + if (PTR_ERR(scm->core_clk) == -EPROBE_DEFER) + return PTR_ERR(scm->core_clk); + + scm->core_clk = NULL; + } + + if (of_device_is_compatible(pdev->dev.of_node, "qcom,scm")) { + scm->iface_clk = devm_clk_get(&pdev->dev, "iface"); + if (IS_ERR(scm->iface_clk)) { + if (PTR_ERR(scm->iface_clk) != -EPROBE_DEFER) + dev_err(&pdev->dev, "failed to acquire iface clk\n"); + return PTR_ERR(scm->iface_clk); + } + + scm->bus_clk = devm_clk_get(&pdev->dev, "bus"); + if (IS_ERR(scm->bus_clk)) { + if (PTR_ERR(scm->bus_clk) != -EPROBE_DEFER) + dev_err(&pdev->dev, "failed to acquire bus clk\n"); + return PTR_ERR(scm->bus_clk); + } + } + + /* vote for max clk rate for highest performance */ + ret = clk_set_rate(scm->core_clk, INT_MAX); + if (ret) + return ret; + + __scm = scm; + __scm->dev = &pdev->dev; + + return 0; +} + +static const struct of_device_id qcom_scm_dt_match[] = { + { .compatible = "qcom,scm-apq8064",}, + { .compatible = "qcom,scm-msm8660",}, + { .compatible = "qcom,scm-msm8960",}, + { .compatible = "qcom,scm",}, + {} +}; + +MODULE_DEVICE_TABLE(of, qcom_scm_dt_match); + +static struct platform_driver qcom_scm_driver = { + .driver = { + .name = "qcom_scm", + .of_match_table = qcom_scm_dt_match, + }, + .probe = qcom_scm_probe, +}; + +static int __init qcom_scm_init(void) +{ + struct device_node *np, *fw_np; + int ret; + + fw_np = of_find_node_by_name(NULL, "firmware"); + + if (!fw_np) + return -ENODEV; + + np = of_find_matching_node(fw_np, qcom_scm_dt_match); + + if (!np) { + of_node_put(fw_np); + return -ENODEV; + } + + of_node_put(np); + + ret = of_platform_populate(fw_np, qcom_scm_dt_match, NULL, NULL); + + of_node_put(fw_np); + + if (ret) + return ret; + + return platform_driver_register(&qcom_scm_driver); +} + +arch_initcall(qcom_scm_init); + +static void __exit qcom_scm_exit(void) +{ + platform_driver_unregister(&qcom_scm_driver); +} +module_exit(qcom_scm_exit); + +MODULE_DESCRIPTION("Qualcomm SCM driver"); +MODULE_LICENSE("GPL v2");