From patchwork Tue Jun 12 04:40:46 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rajendra Nayak X-Patchwork-Id: 928071 Return-Path: X-Original-To: incoming-dt@patchwork.ozlabs.org Delivered-To: patchwork-incoming-dt@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=devicetree-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=codeaurora.org Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=codeaurora.org header.i=@codeaurora.org header.b="gEshqsMa"; dkim=fail reason="signature verification failed" (1024-bit key) header.d=codeaurora.org header.i=@codeaurora.org header.b="PHIb62OA"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 414ch81JSrz9s0W for ; Tue, 12 Jun 2018 14:43:04 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932490AbeFLElK (ORCPT ); Tue, 12 Jun 2018 00:41:10 -0400 Received: from smtp.codeaurora.org ([198.145.29.96]:35398 "EHLO smtp.codeaurora.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932334AbeFLElI (ORCPT ); Tue, 12 Jun 2018 00:41:08 -0400 Received: by smtp.codeaurora.org (Postfix, from userid 1000) id 10C8060791; Tue, 12 Jun 2018 04:41:08 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=codeaurora.org; s=default; t=1528778468; bh=KCAGd1RvOczUH/aWijumf4oODSSjeRJw3HwytpYLFC0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=gEshqsMayCv9kl2DdEKTsHPh7hZb8wr32scJldsluLsecZwPoLL8OBa3h2xCz0SvF 47EWLaBCj33u+IfIhmPRUKX8zes1vJwLTgyZuk7BWg38moSvYH8e2qtjH33a4BW94y zIGPoL4gT9ZuotkNOVXOXnqAoC7HxlIGrtg6OTj8= X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on pdx-caf-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-2.8 required=2.0 tests=ALL_TRUSTED,BAYES_00, DKIM_SIGNED, T_DKIM_INVALID autolearn=no autolearn_force=no version=3.4.0 Received: from blr-ubuntu-173.qualcomm.com (blr-bdr-fw-01_globalnat_allzones-outside.qualcomm.com [103.229.18.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-SHA256 (128/128 bits)) (No client certificate requested) (Authenticated sender: rnayak@smtp.codeaurora.org) by smtp.codeaurora.org (Postfix) with ESMTPSA id AE648606DB; Tue, 12 Jun 2018 04:41:04 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=codeaurora.org; s=default; t=1528778467; bh=KCAGd1RvOczUH/aWijumf4oODSSjeRJw3HwytpYLFC0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=PHIb62OAM7XImfRd9IjvuTdMxPe9Ne5/TJopAJRouh6AiE0OcyD+zsJwmdzi3kWny VtOYtnpRman2aNdgB51fnAcNewVsO+yYEW1tNYRiOTUkh5f+52TQsYNYkxQTLCggpr weICIOiwpA6L4cZ1r+JD7meYSs3jlIv5ySxl9rfk= DMARC-Filter: OpenDMARC Filter v1.3.2 smtp.codeaurora.org AE648606DB 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=rnayak@codeaurora.org From: Rajendra Nayak To: viresh.kumar@linaro.org, sboyd@kernel.org, andy.gross@linaro.org, ulf.hansson@linaro.org, collinsd@codeaurora.org Cc: devicetree@vger.kernel.org, linux-arm-msm@vger.kernel.org, linux-kernel@vger.kernel.org, Rajendra Nayak Subject: [PATCH v3 1/7] dt-bindings: power: Add qcom rpm power domain driver bindings Date: Tue, 12 Jun 2018 10:10:46 +0530 Message-Id: <20180612044052.4402-2-rnayak@codeaurora.org> X-Mailer: git-send-email 2.17.0 In-Reply-To: <20180612044052.4402-1-rnayak@codeaurora.org> References: <20180612044052.4402-1-rnayak@codeaurora.org> Sender: devicetree-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org Add DT bindings to describe the rpm power domains found on Qualcomm Technologies, Inc. SoCs. These power domains communicate a performance state to RPM, which then translates it into corresponding voltage on a PMIC rail. Signed-off-by: Rajendra Nayak Signed-off-by: Viresh Kumar --- .../devicetree/bindings/power/qcom,rpmpd.txt | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 Documentation/devicetree/bindings/power/qcom,rpmpd.txt diff --git a/Documentation/devicetree/bindings/power/qcom,rpmpd.txt b/Documentation/devicetree/bindings/power/qcom,rpmpd.txt new file mode 100644 index 000000000000..61a0e2687940 --- /dev/null +++ b/Documentation/devicetree/bindings/power/qcom,rpmpd.txt @@ -0,0 +1,49 @@ +Qualcomm RPM Power domains + +For RPM Power domains, we communicate a performance state to RPM +which then translates it into a corresponding voltage on a rail + +Required Properties: + - compatible: Should be one of the following + * qcom,msm8996-rpmpd: RPM Power domain for the msm8996 family of SoC + - power-domain-cells: number of cells in Power domain specifier + must be 1. + - operating-points-v2: Phandle to the OPP table for the Power domain. + Refer to Documentation/devicetree/bindings/power/power_domain.txt + and Documentation/devicetree/bindings/opp/qcom-opp.txt for more details + +Example: + + rpmpd: power-controller { + compatible = "qcom,msm8996-rpmpd"; + #power-domain-cells = <1>; + operating-points-v2 = <&rpmpd_opp_table>; + }; + + rpmpd_opp_table: opp-table { + compatible = "operating-points-v2-qcom-level"; + + rpmpd_opp1: opp1 { + qcom,level = <1>; + }; + + rpmpd_opp2: opp2 { + qcom,level = <2>; + }; + + rpmpd_opp3: opp3 { + qcom,level = <3>; + }; + + rpmpd_opp4: opp4 { + qcom,level = <4>; + }; + + rpmpd_opp5: opp5 { + qcom,level = <5>; + }; + + rpmpd_opp6: opp6 { + qcom,level = <6>; + }; + }; From patchwork Tue Jun 12 04:40:47 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rajendra Nayak X-Patchwork-Id: 928070 Return-Path: X-Original-To: incoming-dt@patchwork.ozlabs.org Delivered-To: patchwork-incoming-dt@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=devicetree-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=codeaurora.org Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=codeaurora.org header.i=@codeaurora.org header.b="bighUakt"; dkim=fail reason="signature verification failed" (1024-bit key) header.d=codeaurora.org header.i=@codeaurora.org header.b="RvZONzzd"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 414cgz0CBYz9s0w for ; Tue, 12 Jun 2018 14:42:55 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932626AbeFLElR (ORCPT ); Tue, 12 Jun 2018 00:41:17 -0400 Received: from smtp.codeaurora.org ([198.145.29.96]:35506 "EHLO smtp.codeaurora.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932584AbeFLElN (ORCPT ); Tue, 12 Jun 2018 00:41:13 -0400 Received: by smtp.codeaurora.org (Postfix, from userid 1000) id B0CCC602B8; Tue, 12 Jun 2018 04:41:12 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=codeaurora.org; s=default; t=1528778472; bh=kcEoKzvq4bj5Ym701mwZwutvLoMbOCaDK9hSPXA5a6k=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=bighUaktbo/GFHzdQPh1XXVgoVAlXqCSSOZZxMlP0VyUOrMyLKZ26Ym2uAPEFyalC ZjPiUMWYOSvOrNDQbMTc2Hj1qO7lWfLbi+ZHWX72KhuqrHZ5n2pAf6ZHZrH88q0D/K 0wBTXzTAMNm/LoPYyTk1kkULqbZAtpw2SwqHT4/A= X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on pdx-caf-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-2.8 required=2.0 tests=ALL_TRUSTED,BAYES_00, DKIM_SIGNED, T_DKIM_INVALID autolearn=no autolearn_force=no version=3.4.0 Received: from blr-ubuntu-173.qualcomm.com (blr-bdr-fw-01_globalnat_allzones-outside.qualcomm.com [103.229.18.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-SHA256 (128/128 bits)) (No client certificate requested) (Authenticated sender: rnayak@smtp.codeaurora.org) by smtp.codeaurora.org (Postfix) with ESMTPSA id 59B39606DB; Tue, 12 Jun 2018 04:41:08 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=codeaurora.org; s=default; t=1528778471; bh=kcEoKzvq4bj5Ym701mwZwutvLoMbOCaDK9hSPXA5a6k=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=RvZONzzdukusM3UYrkBl56XrhtsLurA+JjZzvIEyBLQ+zxxFs3O8zXJj3ILhohKwc LvXNPs5GyW2QCpD88hfmRj8X9SXnHCeK3MRq6TWfgt3Ay4a8q6WqyiJ4sc1TBK5E26 UarzkfBT/9wYjDFRC+RmgmUuRJLN1XJwYaUYJaLs= DMARC-Filter: OpenDMARC Filter v1.3.2 smtp.codeaurora.org 59B39606DB 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=rnayak@codeaurora.org From: Rajendra Nayak To: viresh.kumar@linaro.org, sboyd@kernel.org, andy.gross@linaro.org, ulf.hansson@linaro.org, collinsd@codeaurora.org Cc: devicetree@vger.kernel.org, linux-arm-msm@vger.kernel.org, linux-kernel@vger.kernel.org, Rajendra Nayak Subject: [PATCH v3 2/7] soc: qcom: rpmpd: Add a Power domain driver to model corners Date: Tue, 12 Jun 2018 10:10:47 +0530 Message-Id: <20180612044052.4402-3-rnayak@codeaurora.org> X-Mailer: git-send-email 2.17.0 In-Reply-To: <20180612044052.4402-1-rnayak@codeaurora.org> References: <20180612044052.4402-1-rnayak@codeaurora.org> Sender: devicetree-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org The Power domains for corners just pass the performance state set by the consumers to the RPM (Remote Power manager) which then takes care of setting the appropriate voltage on the corresponding rails to meet the performance needs. We add all Power domain data needed on msm8996 here. This driver can easily be extended by adding data for other qualcomm SoCs as well. Signed-off-by: Rajendra Nayak Signed-off-by: Viresh Kumar Reviewed-by: Ulf Hansson Acked-by: Rob Herring --- drivers/soc/qcom/Kconfig | 9 + drivers/soc/qcom/Makefile | 1 + drivers/soc/qcom/rpmpd.c | 301 +++++++++++++++++++++++++ include/dt-bindings/power/qcom-rpmpd.h | 16 ++ 4 files changed, 327 insertions(+) create mode 100644 drivers/soc/qcom/rpmpd.c create mode 100644 include/dt-bindings/power/qcom-rpmpd.h diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index 9dc02f390ba3..5c54931a7b99 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -74,6 +74,15 @@ config QCOM_RMTFS_MEM Say y here if you intend to boot the modem remoteproc. +config QCOM_RPMPD + tristate "Qualcomm RPM Power domain driver" + depends on MFD_QCOM_RPM && QCOM_SMD_RPM + help + QCOM RPM Power domain driver to support power-domains with + performance states. The driver communicates a performance state + value to RPM which then translates it into corresponding voltage + for the voltage rail. + config QCOM_SMEM tristate "Qualcomm Shared Memory Manager (SMEM)" depends on ARCH_QCOM diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile index 19dcf957cb3a..9550c170de93 100644 --- a/drivers/soc/qcom/Makefile +++ b/drivers/soc/qcom/Makefile @@ -15,3 +15,4 @@ obj-$(CONFIG_QCOM_SMP2P) += smp2p.o obj-$(CONFIG_QCOM_SMSM) += smsm.o obj-$(CONFIG_QCOM_WCNSS_CTRL) += wcnss_ctrl.o obj-$(CONFIG_QCOM_APR) += apr.o +obj-$(CONFIG_QCOM_RPMPD) += rpmpd.o diff --git a/drivers/soc/qcom/rpmpd.c b/drivers/soc/qcom/rpmpd.c new file mode 100644 index 000000000000..c5e7a91f278c --- /dev/null +++ b/drivers/soc/qcom/rpmpd.c @@ -0,0 +1,301 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define domain_to_rpmpd(domain) container_of(domain, struct rpmpd, pd) + +/* Resource types */ +#define RPMPD_SMPA 0x61706d73 +#define RPMPD_LDOA 0x616f646c + +/* Operation Keys */ +#define KEY_CORNER 0x6e726f63 /* corn */ +#define KEY_ENABLE 0x6e657773 /* swen */ +#define KEY_FLOOR_CORNER 0x636676 /* vfc */ + +#define DEFINE_RPMPD_CORN_SMPA(_platform, _name, _active, r_id) \ + static struct rpmpd _platform##_##_active; \ + static struct rpmpd _platform##_##_name = { \ + .pd = { .name = #_name, }, \ + .peer = &_platform##_##_active, \ + .res_type = RPMPD_SMPA, \ + .res_id = r_id, \ + .key = KEY_CORNER, \ + }; \ + static struct rpmpd _platform##_##_active = { \ + .pd = { .name = #_active, }, \ + .peer = &_platform##_##_name, \ + .active_only = true, \ + .res_type = RPMPD_SMPA, \ + .res_id = r_id, \ + .key = KEY_CORNER, \ + } + +#define DEFINE_RPMPD_CORN_LDOA(_platform, _name, r_id) \ + static struct rpmpd _platform##_##_name = { \ + .pd = { .name = #_name, }, \ + .res_type = RPMPD_LDOA, \ + .res_id = r_id, \ + .key = KEY_CORNER, \ + } + +#define DEFINE_RPMPD_VFC(_platform, _name, r_id, r_type) \ + static struct rpmpd _platform##_##_name = { \ + .pd = { .name = #_name, }, \ + .res_type = r_type, \ + .res_id = r_id, \ + .key = KEY_FLOOR_CORNER, \ + } + +#define DEFINE_RPMPD_VFC_SMPA(_platform, _name, r_id) \ + DEFINE_RPMPD_VFC(_platform, _name, r_id, RPMPD_SMPA) + +#define DEFINE_RPMPD_VFC_LDOA(_platform, _name, r_id) \ + DEFINE_RPMPD_VFC(_platform, _name, r_id, RPMPD_LDOA) + +struct rpmpd_req { + __le32 key; + __le32 nbytes; + __le32 value; +}; + +struct rpmpd { + struct generic_pm_domain pd; + struct rpmpd *peer; + const bool active_only; + unsigned int corner; + bool enabled; + const char *res_name; + const int res_type; + const int res_id; + struct qcom_smd_rpm *rpm; + __le32 key; +}; + +struct rpmpd_desc { + struct rpmpd **rpmpds; + size_t num_pds; +}; + +static DEFINE_MUTEX(rpmpd_lock); + +/* msm8996 RPM Power domains */ +DEFINE_RPMPD_CORN_SMPA(msm8996, vddcx, vddcx_ao, 1); +DEFINE_RPMPD_CORN_SMPA(msm8996, vddmx, vddmx_ao, 2); +DEFINE_RPMPD_CORN_LDOA(msm8996, vddsscx, 26); + +DEFINE_RPMPD_VFC_SMPA(msm8996, vddcx_vfc, 1); +DEFINE_RPMPD_VFC_LDOA(msm8996, vddsscx_vfc, 26); + +static struct rpmpd *msm8996_rpmpds[] = { + [MSM8996_VDDCX] = &msm8996_vddcx, + [MSM8996_VDDCX_AO] = &msm8996_vddcx_ao, + [MSM8996_VDDCX_VFC] = &msm8996_vddcx_vfc, + [MSM8996_VDDMX] = &msm8996_vddmx, + [MSM8996_VDDMX_AO] = &msm8996_vddmx_ao, + [MSM8996_VDDSSCX] = &msm8996_vddsscx, + [MSM8996_VDDSSCX_VFC] = &msm8996_vddsscx_vfc, +}; + +static const struct rpmpd_desc msm8996_desc = { + .rpmpds = msm8996_rpmpds, + .num_pds = ARRAY_SIZE(msm8996_rpmpds), +}; + +static const struct of_device_id rpmpd_match_table[] = { + { .compatible = "qcom,msm8996-rpmpd", .data = &msm8996_desc }, + { } +}; +MODULE_DEVICE_TABLE(of, rpmpd_match_table); + +static int rpmpd_send_enable(struct rpmpd *pd, bool enable) +{ + struct rpmpd_req req = { + .key = KEY_ENABLE, + .nbytes = cpu_to_le32(sizeof(u32)), + .value = cpu_to_le32(enable), + }; + + return qcom_rpm_smd_write(pd->rpm, QCOM_RPM_ACTIVE_STATE, pd->res_type, + pd->res_id, &req, sizeof(req)); +} + +static int rpmpd_send_corner(struct rpmpd *pd, int state, unsigned int corner) +{ + struct rpmpd_req req = { + .key = pd->key, + .nbytes = cpu_to_le32(sizeof(u32)), + .value = cpu_to_le32(corner), + }; + + return qcom_rpm_smd_write(pd->rpm, state, pd->res_type, pd->res_id, + &req, sizeof(req)); +}; + +static void to_active_sleep(struct rpmpd *pd, unsigned int corner, + unsigned int *active, unsigned int *sleep) +{ + *active = corner; + + if (pd->active_only) + *sleep = 0; + else + *sleep = *active; +} + +static int rpmpd_aggregate_corner(struct rpmpd *pd) +{ + int ret; + struct rpmpd *peer = pd->peer; + unsigned int active_corner, sleep_corner; + unsigned int this_active_corner = 0, this_sleep_corner = 0; + unsigned int peer_active_corner = 0, peer_sleep_corner = 0; + + to_active_sleep(pd, pd->corner, &this_active_corner, &this_sleep_corner); + + if (peer && peer->enabled) + to_active_sleep(peer, peer->corner, &peer_active_corner, + &peer_sleep_corner); + + active_corner = max(this_active_corner, peer_active_corner); + + ret = rpmpd_send_corner(pd, QCOM_RPM_ACTIVE_STATE, active_corner); + if (ret) + return ret; + + sleep_corner = max(this_sleep_corner, peer_sleep_corner); + + return rpmpd_send_corner(pd, QCOM_RPM_SLEEP_STATE, sleep_corner); +} + +static int rpmpd_power_on(struct generic_pm_domain *domain) +{ + int ret; + struct rpmpd *pd = domain_to_rpmpd(domain); + + mutex_lock(&rpmpd_lock); + + ret = rpmpd_send_enable(pd, true); + if (ret) + goto out; + + pd->enabled = true; + + if (pd->corner) + ret = rpmpd_aggregate_corner(pd); + +out: + mutex_unlock(&rpmpd_lock); + + return ret; +} + +static int rpmpd_power_off(struct generic_pm_domain *domain) +{ + int ret; + struct rpmpd *pd = domain_to_rpmpd(domain); + + mutex_lock(&rpmpd_lock); + + ret = rpmpd_send_enable(pd, false); + if (!ret) + pd->enabled = false; + + mutex_unlock(&rpmpd_lock); + + return ret; +} + +static int rpmpd_probe(struct platform_device *pdev) +{ + int i; + size_t num; + struct genpd_onecell_data *data; + struct qcom_smd_rpm *rpm; + struct rpmpd **rpmpds; + const struct rpmpd_desc *desc; + + rpm = dev_get_drvdata(pdev->dev.parent); + if (!rpm) { + dev_err(&pdev->dev, "Unable to retrieve handle to RPM\n"); + return -ENODEV; + } + + desc = of_device_get_match_data(&pdev->dev); + if (!desc) + return -EINVAL; + + rpmpds = desc->rpmpds; + num = desc->num_pds; + + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->domains = devm_kcalloc(&pdev->dev, num, sizeof(*data->domains), + GFP_KERNEL); + data->num_domains = num; + + for (i = 0; i < num; i++) { + if (!rpmpds[i]) { + dev_warn(&pdev->dev, "rpmpds[] with empty entry at index=%d\n", + i); + continue; + } + + rpmpds[i]->rpm = rpm; + rpmpds[i]->pd.power_off = rpmpd_power_off; + rpmpds[i]->pd.power_on = rpmpd_power_on; + pm_genpd_init(&rpmpds[i]->pd, NULL, true); + + data->domains[i] = &rpmpds[i]->pd; + } + + return of_genpd_add_provider_onecell(pdev->dev.of_node, data); +} + +static int rpmpd_remove(struct platform_device *pdev) +{ + of_genpd_del_provider(pdev->dev.of_node); + return 0; +} + +static struct platform_driver rpmpd_driver = { + .driver = { + .name = "qcom-rpmpd", + .of_match_table = rpmpd_match_table, + }, + .probe = rpmpd_probe, + .remove = rpmpd_remove, +}; + +static int __init rpmpd_init(void) +{ + return platform_driver_register(&rpmpd_driver); +} +core_initcall(rpmpd_init); + +static void __exit rpmpd_exit(void) +{ + platform_driver_unregister(&rpmpd_driver); +} +module_exit(rpmpd_exit); + +MODULE_DESCRIPTION("Qualcomm Technologies, Inc. RPM Power Domain Driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:qcom-rpmpd"); diff --git a/include/dt-bindings/power/qcom-rpmpd.h b/include/dt-bindings/power/qcom-rpmpd.h new file mode 100644 index 000000000000..59f47317b81f --- /dev/null +++ b/include/dt-bindings/power/qcom-rpmpd.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. */ + +#ifndef _DT_BINDINGS_POWER_QCOM_RPMPD_H +#define _DT_BINDINGS_POWER_QCOM_RPMPD_H + +/* MSM8996 Power Domain Indexes */ +#define MSM8996_VDDCX 0 +#define MSM8996_VDDCX_AO 1 +#define MSM8996_VDDCX_VFC 2 +#define MSM8996_VDDMX 3 +#define MSM8996_VDDMX_AO 4 +#define MSM8996_VDDSSCX 5 +#define MSM8996_VDDSSCX_VFC 6 + +#endif From patchwork Tue Jun 12 04:40:50 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rajendra Nayak X-Patchwork-Id: 928069 Return-Path: X-Original-To: incoming-dt@patchwork.ozlabs.org Delivered-To: patchwork-incoming-dt@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=devicetree-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=codeaurora.org Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=codeaurora.org header.i=@codeaurora.org header.b="Se7L2WQE"; dkim=fail reason="signature verification failed" (1024-bit key) header.d=codeaurora.org header.i=@codeaurora.org header.b="Se7L2WQE"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 414cgM1xjGz9s0W for ; Tue, 12 Jun 2018 14:42:23 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932762AbeFLElY (ORCPT ); Tue, 12 Jun 2018 00:41:24 -0400 Received: from smtp.codeaurora.org ([198.145.29.96]:35732 "EHLO smtp.codeaurora.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932592AbeFLElX (ORCPT ); Tue, 12 Jun 2018 00:41:23 -0400 Received: by smtp.codeaurora.org (Postfix, from userid 1000) id 92FF1606DB; Tue, 12 Jun 2018 04:41:22 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=codeaurora.org; s=default; t=1528778482; bh=oltgX3MV2Km3blGMQjBAhFbOERkJWYDc0oNmCOPMe8E=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Se7L2WQEaqFYVJXD/kPCkj8uTXiODtlNGCLOLu/N/DyyH2BY7VXzzb7UbbF1s8G2G Y7SFZcyfGaVUmAGx9AICHg6PN1KngCArigUeeg6MNt9F5XgFAAr1yTTqib09BtUNgq rQSh8L2QWvhl0pCxszptt5BVQn6xNSnCdx5Nr7VI= X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on pdx-caf-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-2.8 required=2.0 tests=ALL_TRUSTED,BAYES_00, DKIM_SIGNED, T_DKIM_INVALID autolearn=no autolearn_force=no version=3.4.0 Received: from blr-ubuntu-173.qualcomm.com (blr-bdr-fw-01_globalnat_allzones-outside.qualcomm.com [103.229.18.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-SHA256 (128/128 bits)) (No client certificate requested) (Authenticated sender: rnayak@smtp.codeaurora.org) by smtp.codeaurora.org (Postfix) with ESMTPSA id 2769E602BD; Tue, 12 Jun 2018 04:41:18 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=codeaurora.org; s=default; t=1528778482; bh=oltgX3MV2Km3blGMQjBAhFbOERkJWYDc0oNmCOPMe8E=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Se7L2WQEaqFYVJXD/kPCkj8uTXiODtlNGCLOLu/N/DyyH2BY7VXzzb7UbbF1s8G2G Y7SFZcyfGaVUmAGx9AICHg6PN1KngCArigUeeg6MNt9F5XgFAAr1yTTqib09BtUNgq rQSh8L2QWvhl0pCxszptt5BVQn6xNSnCdx5Nr7VI= DMARC-Filter: OpenDMARC Filter v1.3.2 smtp.codeaurora.org 2769E602BD 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=rnayak@codeaurora.org From: Rajendra Nayak To: viresh.kumar@linaro.org, sboyd@kernel.org, andy.gross@linaro.org, ulf.hansson@linaro.org, collinsd@codeaurora.org Cc: devicetree@vger.kernel.org, linux-arm-msm@vger.kernel.org, linux-kernel@vger.kernel.org, Rajendra Nayak Subject: [PATCH v3 5/7] dt-bindings: power: Add qcom rpmh power domain driver bindings Date: Tue, 12 Jun 2018 10:10:50 +0530 Message-Id: <20180612044052.4402-6-rnayak@codeaurora.org> X-Mailer: git-send-email 2.17.0 In-Reply-To: <20180612044052.4402-1-rnayak@codeaurora.org> References: <20180612044052.4402-1-rnayak@codeaurora.org> Sender: devicetree-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org Add DT bindings to describe the rpmh powerdomains found on Qualcomm Technologies, Inc. SoCs. These power domains communicate a performance state to RPMh, which then translates it into corresponding voltage on a PMIC rail. Signed-off-by: Rajendra Nayak --- .../devicetree/bindings/power/qcom,rpmhpd.txt | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 Documentation/devicetree/bindings/power/qcom,rpmhpd.txt diff --git a/Documentation/devicetree/bindings/power/qcom,rpmhpd.txt b/Documentation/devicetree/bindings/power/qcom,rpmhpd.txt new file mode 100644 index 000000000000..41ef7afa6b24 --- /dev/null +++ b/Documentation/devicetree/bindings/power/qcom,rpmhpd.txt @@ -0,0 +1,65 @@ +Qualcomm RPMh Power domains + +For RPMh Power domains, we communicate a performance state to RPMh +which then translates it into a corresponding voltage on a rail + +Required Properties: + - compatible: Should be one of the following + * qcom,sdm845-rpmhpd: RPMh Power domain for the sdm845 family of SoC + - power-domain-cells: number of cells in power domain specifier + must be 1 + - operating-points-v2: Phandle to the OPP table for the power-domain. + Refer to Documentation/devicetree/bindings/power/power_domain.txt + and Documentation/devicetree/bindings/opp/qcom-opp.txt for more details + +Example: + + rpmhpd: power-controller { + compatible = "qcom,sdm845-rpmhpd"; + #power-domain-cells = <1>; + operating-points-v2 = <&rpmhpd_opp_table>; + }; + + rpmhpd_opp_table: opp-table { + compatible = "operating-points-v2-qcom-level"; + + rpmhpd_opp_ret: opp1 { + qcom-level = <16>; + }; + + rpmhpd_opp_min_svs: opp2 { + qcom-level = <48>; + }; + + rpmhpd_opp_low_svs: opp3 { + qcom-level = <64>; + }; + + rpmhpd_opp_svs: opp4 { + qcom-level = <128>; + }; + + rpmhpd_opp_svs_l1: opp5 { + qcom-level = <192>; + }; + + rpmhpd_opp_nom: opp6 { + qcom-level = <256>; + }; + + rpmhpd_opp_nom_l1: opp7 { + qcom-level = <320>; + }; + + rpmhpd_opp_nom_l2: opp8 { + qcom-level = <336>; + }; + + rpmhpd_opp_turbo: opp9 { + qcom-level = <384>; + }; + + rpmhpd_opp_turbo_l1: opp10 { + qcom-level = <416>; + }; + }; From patchwork Tue Jun 12 04:40:51 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rajendra Nayak X-Patchwork-Id: 928068 Return-Path: X-Original-To: incoming-dt@patchwork.ozlabs.org Delivered-To: patchwork-incoming-dt@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=devicetree-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=codeaurora.org Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=codeaurora.org header.i=@codeaurora.org header.b="e3hZeu1m"; dkim=fail reason="signature verification failed" (1024-bit key) header.d=codeaurora.org header.i=@codeaurora.org header.b="jslwzKXn"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 414cfd2S8wz9s0w for ; Tue, 12 Jun 2018 14:41:45 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932916AbeFLElc (ORCPT ); Tue, 12 Jun 2018 00:41:32 -0400 Received: from smtp.codeaurora.org ([198.145.29.96]:35822 "EHLO smtp.codeaurora.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932866AbeFLEl2 (ORCPT ); Tue, 12 Jun 2018 00:41:28 -0400 Received: by smtp.codeaurora.org (Postfix, from userid 1000) id DBE2A60791; Tue, 12 Jun 2018 04:41:27 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=codeaurora.org; s=default; t=1528778487; bh=x3U2Nu61gclh7eyxDmWXcdLOicVCV+HLnmpppx2raT4=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=e3hZeu1mxE7IMP0N/QDqFFkocA4OHN6efeG4+1GzuL5FhJxXLvNQtOaMIdF9hXrZN mJJhy+jADQLaZVg5dsAX7+JLeUIhRgT+pNYQRJ8SufY0dFCM7qevq4K/2o6IdV4Noz RtsX8bIsxbN4f3tNA+KmmYOmU3s90RuF3joUr63c= X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on pdx-caf-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-2.8 required=2.0 tests=ALL_TRUSTED,BAYES_00, DKIM_SIGNED, T_DKIM_INVALID autolearn=no autolearn_force=no version=3.4.0 Received: from blr-ubuntu-173.qualcomm.com (blr-bdr-fw-01_globalnat_allzones-outside.qualcomm.com [103.229.18.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-SHA256 (128/128 bits)) (No client certificate requested) (Authenticated sender: rnayak@smtp.codeaurora.org) by smtp.codeaurora.org (Postfix) with ESMTPSA id BFDC46074D; Tue, 12 Jun 2018 04:41:22 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=codeaurora.org; s=default; t=1528778486; bh=x3U2Nu61gclh7eyxDmWXcdLOicVCV+HLnmpppx2raT4=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=jslwzKXns0QDp4jXRiL6H6y4c9wFRZcGRlWAsrA0Rab683FjtPmVwxQA8fNUA8CWI gooKk43/A3ULKKKauPBr+MsUpPfShS4T46AkkX27l78xBCTXfOTEfI8U9nh59gdw17 sCB85CQNCMGMEnqyNGSmQzy2xklLTMs+O4wrcLok= DMARC-Filter: OpenDMARC Filter v1.3.2 smtp.codeaurora.org BFDC46074D 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=rnayak@codeaurora.org From: Rajendra Nayak To: viresh.kumar@linaro.org, sboyd@kernel.org, andy.gross@linaro.org, ulf.hansson@linaro.org, collinsd@codeaurora.org Cc: devicetree@vger.kernel.org, linux-arm-msm@vger.kernel.org, linux-kernel@vger.kernel.org, Rajendra Nayak Subject: [PATCH v3 6/7] soc: qcom: Add RPMh Power domain driver Date: Tue, 12 Jun 2018 10:10:51 +0530 Message-Id: <20180612044052.4402-7-rnayak@codeaurora.org> X-Mailer: git-send-email 2.17.0 In-Reply-To: <20180612044052.4402-1-rnayak@codeaurora.org> References: <20180612044052.4402-1-rnayak@codeaurora.org> Sender: devicetree-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org The RPMh Power domain driver aggregates the corner votes from various consumers for the ARC resources and communicates it to RPMh. We also add data for all power domains on sdm845 SoC as part of the patch. The driver can be extended to support other SoCs which support RPMh Signed-off-by: Rajendra Nayak Reviewed-by: Ulf Hansson --- drivers/soc/qcom/Kconfig | 9 + drivers/soc/qcom/Makefile | 1 + drivers/soc/qcom/rpmhpd.c | 427 ++++++++++++++++++++++++ include/dt-bindings/power/qcom-rpmhpd.h | 31 ++ 4 files changed, 468 insertions(+) create mode 100644 drivers/soc/qcom/rpmhpd.c create mode 100644 include/dt-bindings/power/qcom-rpmhpd.h diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index 5c54931a7b99..7cb7eba2b997 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -74,6 +74,15 @@ config QCOM_RMTFS_MEM Say y here if you intend to boot the modem remoteproc. +config QCOM_RPMHPD + tristate "Qualcomm RPMh Power domain driver" + depends on QCOM_RPMH && QCOM_COMMAND_DB + help + QCOM RPMh Power domain driver to support power-domains with + performance states. The driver communicates a performance state + value to RPMh which then translates it into corresponding voltage + for the voltage rail. + config QCOM_RPMPD tristate "Qualcomm RPM Power domain driver" depends on MFD_QCOM_RPM && QCOM_SMD_RPM diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile index 9550c170de93..499513f63bef 100644 --- a/drivers/soc/qcom/Makefile +++ b/drivers/soc/qcom/Makefile @@ -16,3 +16,4 @@ obj-$(CONFIG_QCOM_SMSM) += smsm.o obj-$(CONFIG_QCOM_WCNSS_CTRL) += wcnss_ctrl.o obj-$(CONFIG_QCOM_APR) += apr.o obj-$(CONFIG_QCOM_RPMPD) += rpmpd.o +obj-$(CONFIG_QCOM_RPMHPD) += rpmhpd.o diff --git a/drivers/soc/qcom/rpmhpd.c b/drivers/soc/qcom/rpmhpd.c new file mode 100644 index 000000000000..7083ec1590ff --- /dev/null +++ b/drivers/soc/qcom/rpmhpd.c @@ -0,0 +1,427 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2018, The Linux Foundation. All rights reserved.*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define domain_to_rpmhpd(domain) container_of(domain, struct rpmhpd, pd) + +#define DEFINE_RPMHPD_AO(_platform, _name, _active) \ + static struct rpmhpd _platform##_##_active; \ + static struct rpmhpd _platform##_##_name = { \ + .pd = { .name = #_name, }, \ + .peer = &_platform##_##_active, \ + .res_name = #_name".lvl", \ + .valid_state_mask = (BIT(RPMH_ACTIVE_ONLY_STATE) | \ + BIT(RPMH_WAKE_ONLY_STATE) | \ + BIT(RPMH_SLEEP_STATE)), \ + }; \ + static struct rpmhpd _platform##_##_active = { \ + .pd = { .name = #_active, }, \ + .peer = &_platform##_##_name, \ + .active_only = true, \ + .res_name = #_name".lvl", \ + .valid_state_mask = (BIT(RPMH_ACTIVE_ONLY_STATE) | \ + BIT(RPMH_WAKE_ONLY_STATE) | \ + BIT(RPMH_SLEEP_STATE)), \ + } + +#define DEFINE_RPMHPD(_platform, _name) \ + static struct rpmhpd _platform##_##_name = { \ + .pd = { .name = #_name, }, \ + .res_name = #_name".lvl", \ + .valid_state_mask = BIT(RPMH_ACTIVE_ONLY_STATE), \ + } + +/* + * This is the number of bytes used for each command DB aux data entry of an + * ARC resource. + */ +#define RPMH_ARC_LEVEL_SIZE 2 +#define RPMH_ARC_MAX_LEVELS 16 + +struct rpmhpd { + struct device *dev; + struct generic_pm_domain pd; + struct rpmhpd *peer; + const bool active_only; + unsigned int corner; + unsigned int active_corner; + u32 level[RPMH_ARC_MAX_LEVELS]; + int level_count; + bool enabled; + const char *res_name; + u32 addr; + u8 valid_state_mask; +}; + +struct rpmhpd_desc { + struct rpmhpd **rpmhpds; + size_t num_pds; +}; + +static DEFINE_MUTEX(rpmhpd_lock); + +/* sdm845 RPMh Power domains */ +DEFINE_RPMHPD(sdm845, ebi); +DEFINE_RPMHPD_AO(sdm845, mx, mx_ao); +DEFINE_RPMHPD_AO(sdm845, cx, cx_ao); +DEFINE_RPMHPD(sdm845, lmx); +DEFINE_RPMHPD(sdm845, lcx); +DEFINE_RPMHPD(sdm845, gfx); +DEFINE_RPMHPD(sdm845, mss); + +static struct rpmhpd *sdm845_rpmhpds[] = { + [SDM845_EBI] = &sdm845_ebi, + [SDM845_MX] = &sdm845_mx, + [SDM845_MX_AO] = &sdm845_mx_ao, + [SDM845_CX] = &sdm845_cx, + [SDM845_CX_AO] = &sdm845_cx_ao, + [SDM845_LMX] = &sdm845_lmx, + [SDM845_LCX] = &sdm845_lcx, + [SDM845_GFX] = &sdm845_gfx, + [SDM845_MSS] = &sdm845_mss, +}; + +static const struct rpmhpd_desc sdm845_desc = { + .rpmhpds = sdm845_rpmhpds, + .num_pds = ARRAY_SIZE(sdm845_rpmhpds), +}; + +static const struct of_device_id rpmhpd_match_table[] = { + { .compatible = "qcom,sdm845-rpmhpd", .data = &sdm845_desc }, + { } +}; +MODULE_DEVICE_TABLE(of, rpmhpd_match_table); + +static int rpmhpd_send_corner(struct rpmhpd *pd, int state, + unsigned int corner, bool sync) +{ + struct tcs_cmd cmd = { + .addr = pd->addr, + .data = corner, + }; + + if (sync) + return rpmh_write(pd->dev, state, &cmd, 1); + else + return rpmh_write_async(pd->dev, state, &cmd, 1); +} + +static int rpmhpd_send_corner_sync(struct rpmhpd *pd, int state, + unsigned int corner) +{ + return rpmhpd_send_corner(pd, state, corner, true); +} + +static int rpmhpd_send_corner_async(struct rpmhpd *pd, int state, + unsigned int corner) +{ + return rpmhpd_send_corner(pd, state, corner, false); +}; + +static void to_active_sleep(struct rpmhpd *pd, unsigned int corner, + unsigned int *active, unsigned int *sleep) +{ + *active = corner; + + if (pd->active_only) + *sleep = 0; + else + *sleep = *active; +} + +/* + * This function is used to aggregate the votes across the active only + * resources and its peers. The aggregated votes are send to RPMh as + * ACTIVE_ONLY votes (which take effect immediately), as WAKE_ONLY votes + * (applied by RPMh on system wakeup) and as SLEEP votes (applied by RPMh + * on system sleep). + * We send ACTIVE_ONLY votes for resources without any peers. For others, + * which have an active only peer, all 3 Votes are sent. + */ +static int rpmhpd_aggregate_corner(struct rpmhpd *pd, unsigned int corner) +{ + int ret = -EINVAL; + struct rpmhpd *peer = pd->peer; + unsigned int active_corner, sleep_corner; + unsigned int this_active_corner = 0, this_sleep_corner = 0; + unsigned int peer_active_corner = 0, peer_sleep_corner = 0; + + to_active_sleep(pd, corner, &this_active_corner, &this_sleep_corner); + + if (peer && peer->enabled) + to_active_sleep(peer, peer->corner, &peer_active_corner, + &peer_sleep_corner); + + active_corner = max(this_active_corner, peer_active_corner); + + if (pd->valid_state_mask & BIT(RPMH_ACTIVE_ONLY_STATE)) { + /* + * Wait for an ack only when we are increasing the + * perf state of the power domain + */ + if (active_corner > pd->active_corner) + ret = rpmhpd_send_corner_sync(pd, + RPMH_ACTIVE_ONLY_STATE, + active_corner); + else + ret = rpmhpd_send_corner_async(pd, + RPMH_ACTIVE_ONLY_STATE, + active_corner); + if (ret) + return ret; + pd->active_corner = active_corner; + if (peer) + peer->active_corner = active_corner; + } + + if (pd->valid_state_mask & BIT(RPMH_WAKE_ONLY_STATE)) { + ret = rpmhpd_send_corner_async(pd, RPMH_WAKE_ONLY_STATE, + active_corner); + if (ret) + return ret; + } + + sleep_corner = max(this_sleep_corner, peer_sleep_corner); + + if (pd->valid_state_mask & BIT(RPMH_SLEEP_STATE)) + ret = rpmhpd_send_corner_async(pd, RPMH_SLEEP_STATE, + sleep_corner); + + return ret; +} + +static int rpmhpd_power_on(struct generic_pm_domain *domain) +{ + struct rpmhpd *pd = domain_to_rpmhpd(domain); + int ret = 0; + + mutex_lock(&rpmhpd_lock); + + pd->enabled = true; + + if (pd->corner) + ret = rpmhpd_aggregate_corner(pd, pd->corner); + + mutex_unlock(&rpmhpd_lock); + + return ret; +} + +static int rpmhpd_power_off(struct generic_pm_domain *domain) +{ + struct rpmhpd *pd = domain_to_rpmhpd(domain); + int ret = 0; + + mutex_lock(&rpmhpd_lock); + + if (pd->level[0] == 0) + ret = rpmhpd_aggregate_corner(pd, 0); + + if (!ret) + pd->enabled = false; + + mutex_unlock(&rpmhpd_lock); + + return ret; +} + +static int rpmhpd_set_performance(struct generic_pm_domain *domain, + unsigned int state) +{ + struct rpmhpd *pd = domain_to_rpmhpd(domain); + int ret = 0, i; + + mutex_lock(&rpmhpd_lock); + + for (i = 0; i < pd->level_count; i++) + if (state <= pd->level[i]) + break; + + if (i == pd->level_count) { + ret = -EINVAL; + dev_err(pd->dev, "invalid state=%u for domain %s", + state, pd->pd.name); + goto out; + } + + pd->corner = i; + + if (!pd->enabled) + goto out; + + ret = rpmhpd_aggregate_corner(pd, i); +out: + mutex_unlock(&rpmhpd_lock); + + return ret; +} + +static unsigned int rpmhpd_get_performance(struct generic_pm_domain *genpd, + struct dev_pm_opp *opp) +{ + struct device_node *np; + unsigned int corner = 0; + + np = dev_pm_opp_get_of_node(opp); + if (of_property_read_u32(np, "qcom,level", &corner)) { + pr_err("%s: missing 'qcom,level' property\n", __func__); + return 0; + } + + of_node_put(np); + + return corner; +} + +static int rpmhpd_update_level_mapping(struct rpmhpd *rpmhpd) +{ + int i, j, len, ret; + u8 buf[RPMH_ARC_MAX_LEVELS * RPMH_ARC_LEVEL_SIZE]; + + len = cmd_db_read_aux_data_len(rpmhpd->res_name); + if (len <= 0) + return len; + + if (len > RPMH_ARC_MAX_LEVELS * RPMH_ARC_LEVEL_SIZE) + return -EINVAL; + + ret = cmd_db_read_aux_data(rpmhpd->res_name, buf, len); + if (ret < 0) + return ret; + + rpmhpd->level_count = len / RPMH_ARC_LEVEL_SIZE; + + for (i = 0; i < rpmhpd->level_count; i++) { + rpmhpd->level[i] = 0; + for (j = 0; j < RPMH_ARC_LEVEL_SIZE; j++) + rpmhpd->level[i] |= + buf[i * RPMH_ARC_LEVEL_SIZE + j] << (8 * j); + + /* + * The AUX data may be zero padded. These 0 valued entries at + * the end of the map must be ignored. + */ + if (i > 0 && rpmhpd->level[i] == 0) { + rpmhpd->level_count = i; + break; + } + pr_dbg("%s: ARC hlvl=%2d --> vlvl=%4u\n", rpmhpd->res_name, i, + rpmhpd->level[i]); + } + + return 0; +} + +static int rpmhpd_probe(struct platform_device *pdev) +{ + int i, ret; + size_t num; + struct genpd_onecell_data *data; + struct rpmhpd **rpmhpds; + const struct rpmhpd_desc *desc; + + desc = of_device_get_match_data(&pdev->dev); + if (!desc) + return -EINVAL; + + rpmhpds = desc->rpmhpds; + num = desc->num_pds; + + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->domains = devm_kcalloc(&pdev->dev, num, sizeof(*data->domains), + GFP_KERNEL); + data->num_domains = num; + + ret = cmd_db_ready(); + if (ret) { + if (ret != -EPROBE_DEFER) + dev_err(&pdev->dev, "Command DB unavailable, ret=%d\n", + ret); + return ret; + } + + for (i = 0; i < num; i++) { + if (!rpmhpds[i]) { + dev_warn(&pdev->dev, "rpmhpds[] with empty entry at index=%d\n", + i); + continue; + } + + rpmhpds[i]->dev = &pdev->dev; + rpmhpds[i]->addr = cmd_db_read_addr(rpmhpds[i]->res_name); + if (!rpmhpds[i]->addr) { + dev_err(&pdev->dev, "Could not find RPMh address for resource %s\n", + rpmhpds[i]->res_name); + return -ENODEV; + } + + ret = cmd_db_read_slave_id(rpmhpds[i]->res_name); + if (ret != CMD_DB_HW_ARC) { + dev_err(&pdev->dev, "RPMh slave ID mismatch\n"); + return -EINVAL; + } + + ret = rpmhpd_update_level_mapping(rpmhpds[i]); + if (ret) + return ret; + + rpmhpds[i]->pd.power_off = rpmhpd_power_off; + rpmhpds[i]->pd.power_on = rpmhpd_power_on; + rpmhpds[i]->pd.set_performance_state = rpmhpd_set_performance; + rpmhpds[i]->pd.opp_to_performance_state = rpmhpd_get_performance; + pm_genpd_init(&rpmhpds[i]->pd, NULL, true); + + data->domains[i] = &rpmhpds[i]->pd; + } + + return of_genpd_add_provider_onecell(pdev->dev.of_node, data); +} + +static int rpmhpd_remove(struct platform_device *pdev) +{ + of_genpd_del_provider(pdev->dev.of_node); + return 0; +} + +static struct platform_driver rpmhpd_driver = { + .driver = { + .name = "qcom-rpmhpd", + .of_match_table = rpmhpd_match_table, + }, + .probe = rpmhpd_probe, + .remove = rpmhpd_remove, +}; + +static int __init rpmhpd_init(void) +{ + return platform_driver_register(&rpmhpd_driver); +} +core_initcall(rpmhpd_init); + +static void __exit rpmhpd_exit(void) +{ + platform_driver_unregister(&rpmhpd_driver); +} +module_exit(rpmhpd_exit); + +MODULE_DESCRIPTION("Qualcomm Technologies, Inc. RPMh Power Domain Driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:qcom-rpmhpd"); diff --git a/include/dt-bindings/power/qcom-rpmhpd.h b/include/dt-bindings/power/qcom-rpmhpd.h new file mode 100644 index 000000000000..b01ae2452603 --- /dev/null +++ b/include/dt-bindings/power/qcom-rpmhpd.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. */ + +#ifndef _DT_BINDINGS_POWER_QCOM_RPMHPD_H +#define _DT_BINDINGS_POWER_QCOM_RPMHPD_H + +/* SDM845 Power Domain Indexes */ +#define SDM845_EBI 0 +#define SDM845_MX 1 +#define SDM845_MX_AO 2 +#define SDM845_CX 3 +#define SDM845_CX_AO 4 +#define SDM845_LMX 5 +#define SDM845_LCX 6 +#define SDM845_GFX 7 +#define SDM845_MSS 8 + +/* SDM845 Power Domain performance levels */ +#define RPMH_REGULATOR_LEVEL_OFF 0 +#define RPMH_REGULATOR_LEVEL_RETENTION 16 +#define RPMH_REGULATOR_LEVEL_MIN_SVS 48 +#define RPMH_REGULATOR_LEVEL_LOW_SVS 64 +#define RPMH_REGULATOR_LEVEL_SVS 128 +#define RPMH_REGULATOR_LEVEL_SVS_L1 192 +#define RPMH_REGULATOR_LEVEL_NOM 256 +#define RPMH_REGULATOR_LEVEL_NOM_L1 320 +#define RPMH_REGULATOR_LEVEL_NOM_L2 336 +#define RPMH_REGULATOR_LEVEL_TURBO 384 +#define RPMH_REGULATOR_LEVEL_TURBO_L1 416 + +#endif