From patchwork Wed Oct 11 07:24:16 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Viresh Kumar X-Patchwork-Id: 115518 Delivered-To: patch@linaro.org Received: by 10.140.22.163 with SMTP id 32csp438654qgn; Wed, 11 Oct 2017 00:26:10 -0700 (PDT) X-Received: by 10.99.100.70 with SMTP id y67mr14673307pgb.161.1507706770275; Wed, 11 Oct 2017 00:26:10 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1507706770; cv=none; d=google.com; s=arc-20160816; b=C08U9pA9YpssW29hn/F+vcndX19tTOkV1LZu9PNmwm54cNazhpnXx0/1H4IYyr6RMi v9GLTbIloRUmrzFJmpyJEqknLwQEgOY0k1FTIU2n4qsGGB0aI8WRWHZK8tVJKS+p0p7j svi/KoIDja16Vyh5SsTCcZJ/wWkKpY87SJUY4Im5G73HLulVs2gpZqHEE9f/eipmtefo JPWjg6BiMBwAP61D37oiNMqc0e7+xGE3AHJn0Oc93NOCjRHZDtfL6whl0mWDPbX7YFyD eYXBtKduFAQO7+chElQefmxyfu/moT0eusYXU+w65yM8S+1btLqrqZTsg437TDij3rg/ ezkQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:references :in-reply-to:message-id:date:subject:cc:to:from:dkim-signature :arc-authentication-results; bh=fYuCyIeG/EsPqN7nwQg6LhoVny+f3iBsz7/KCUqKBWs=; b=cGh9NPevHWNdn7E2j6Qil7ZOznJ6czxMrkl2xdZizmzl6k1mJUuUZLfo+9LPS1bseo 5GSGHjBl3ckt/xqUVlS/Srhu0eeSmBWq2e7oUJdDY5D9yzDVZgv5MNtuS752dd7szETR vKwrQkQeVC4vd6u0YRfXKhm2ELPKktaniqlJyaFtz9Sdesvq5xHYwTOseezRhmsbRdVn +L0F5EUDillyfECYb/L0EsokDSTmgDas63ZxC8f0XX2HrwW0WWZpuSpj4t5d2/wPwHwt qGe/B9+oQfwv3RSlzd5H2pu3MDUxseFeqANYNgTi+6TT1xTp60zBcOFF89WNzJZFmlGo xwvg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=QCiKUqGL; spf=pass (google.com: best guess record for domain of linux-pm-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-pm-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id d128si9735969pgc.0.2017.10.11.00.26.10; Wed, 11 Oct 2017 00:26:10 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-pm-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=QCiKUqGL; spf=pass (google.com: best guess record for domain of linux-pm-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-pm-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1757278AbdJKH0I (ORCPT + 12 others); Wed, 11 Oct 2017 03:26:08 -0400 Received: from mail-pf0-f181.google.com ([209.85.192.181]:43562 "EHLO mail-pf0-f181.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1757036AbdJKHY6 (ORCPT ); Wed, 11 Oct 2017 03:24:58 -0400 Received: by mail-pf0-f181.google.com with SMTP id a8so238462pfc.0 for ; Wed, 11 Oct 2017 00:24:58 -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 :in-reply-to:references; bh=fYuCyIeG/EsPqN7nwQg6LhoVny+f3iBsz7/KCUqKBWs=; b=QCiKUqGLvkYNB2aXPD1r0jE7PRb7d2eMA+wasdb36mqGFgphZZaT16Ho39Rw1crI7C AJ81V2xsB/YWUL0bBAVeqAMTL6LuoGxNKwJeRsuoOk3bFc43QdUy8bMMU6ENXfGz3eYo DLk1K90rG70hkLRMlC9PF5TRZTB5TH2XHb0PY= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:in-reply-to:references; bh=fYuCyIeG/EsPqN7nwQg6LhoVny+f3iBsz7/KCUqKBWs=; b=RdvxNx9BiE6nJzqoAfcGrmIR2Fr6bb88QrBnsfJHim50j54M3XN741ASCagTD464ci 8oYxLGjMytmyd5mnmmJQEVrIBX8JmLtSREigolvPcj3XxOmDUu39OtzSls0pNbhK2PEe ZtH9iRtt02Yoye7dMqsGl1PAK5SHgWFDy8mjymfwRU7iUhghts4CdsQTGb3TU2LfvsRx 48JEyzqCWo9lcLqa/w+nCaOkODeO9k70I4oU8AGn+5SUWIWxcquOlQ6IzHVkjHf+hEez JRBHT5ab/fl12c/JpLjz3nfd7LJV9V6A1dMggWD3rgXwfY+x6eujjwqIaJf9vUvaMMZO db5Q== X-Gm-Message-State: AMCzsaVRcDWJYZdNF6Qw/Ao0thFl6obFRhoGTubdN8KLf+gSc0QEgNwC +nctB00yNcfzbGLU4SI9u8vdHw== X-Google-Smtp-Source: AOwi7QBfigL4l+r9nMw2JB7+vmGYsRNRPxG29Uu2kbpHM6pS8IVa0D3rz2FqQ0SsFYuEwmQgzawT7g== X-Received: by 10.98.95.1 with SMTP id t1mr15726903pfb.217.1507706697782; Wed, 11 Oct 2017 00:24:57 -0700 (PDT) Received: from localhost ([122.172.169.205]) by smtp.gmail.com with ESMTPSA id c22sm7472797pfe.177.2017.10.11.00.24.56 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 11 Oct 2017 00:24:57 -0700 (PDT) From: Viresh Kumar To: Rafael Wysocki , ulf.hansson@linaro.org, Kevin Hilman , Stephen Boyd Cc: Viresh Kumar , linux-pm@vger.kernel.org, Vincent Guittot , Nishanth Menon , robh+dt@kernel.org, lina.iyer@linaro.org, rnayak@codeaurora.org, sudeep.holla@arm.com, linux-kernel@vger.kernel.org, Len Brown , Pavel Machek , Andy Gross , David Brown Subject: [PATCH V11 4/7] soc: qcom: rpmpd: Add driver to model cx/mx power domains Date: Wed, 11 Oct 2017 12:54:16 +0530 Message-Id: X-Mailer: git-send-email 2.15.0.rc1.236.g92ea95045093 In-Reply-To: References: In-Reply-To: References: Sender: linux-pm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pm@vger.kernel.org From: Rajendra Nayak NOT FOR MERGE. The cx/mx power domains 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. Add data for all power domains on msm8996. Signed-off-by: Rajendra Nayak Signed-off-by: Viresh Kumar --- .../devicetree/bindings/power/qcom,rpmpd.txt | 9 + arch/arm64/boot/dts/qcom/msm8996.dtsi | 5 + drivers/soc/qcom/Kconfig | 9 + drivers/soc/qcom/Makefile | 1 + drivers/soc/qcom/rpmpd.c | 307 +++++++++++++++++++++ 5 files changed, 331 insertions(+) create mode 100644 Documentation/devicetree/bindings/power/qcom,rpmpd.txt create mode 100644 drivers/soc/qcom/rpmpd.c -- 2.7.4 diff --git a/Documentation/devicetree/bindings/power/qcom,rpmpd.txt b/Documentation/devicetree/bindings/power/qcom,rpmpd.txt new file mode 100644 index 000000000000..1b8b3b849e47 --- /dev/null +++ b/Documentation/devicetree/bindings/power/qcom,rpmpd.txt @@ -0,0 +1,9 @@ +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,rpmpd-msm8996: RPM Powerdomain for the msm8996 family of SoC. + - power-domain-cells: number of cells in power domain specifier must be 1. diff --git a/arch/arm64/boot/dts/qcom/msm8996.dtsi b/arch/arm64/boot/dts/qcom/msm8996.dtsi index 887b61c872dd..0be1db559d61 100644 --- a/arch/arm64/boot/dts/qcom/msm8996.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8996.dtsi @@ -496,6 +496,11 @@ status = "disabled"; }; + rpmpd: qcom,rpmpd { + compatible = "qcom,rpmpd-msm8996", "qcom,rpmpd"; + #power-domain-cells = <1>; + }; + sdhc2: sdhci@74a4900 { status = "disabled"; compatible = "qcom,sdhci-msm-v4"; diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index b00bccddcd3b..48bc7c358dd7 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -35,6 +35,15 @@ config QCOM_PM modes. It interface with various system drivers to put the cores in low power modes. +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 domain 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 f151de41eb93..3fa9af1e2c93 100644 --- a/drivers/soc/qcom/Makefile +++ b/drivers/soc/qcom/Makefile @@ -8,3 +8,4 @@ obj-$(CONFIG_QCOM_SMEM_STATE) += smem_state.o obj-$(CONFIG_QCOM_SMP2P) += smp2p.o obj-$(CONFIG_QCOM_SMSM) += smsm.o obj-$(CONFIG_QCOM_WCNSS_CTRL) += wcnss_ctrl.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..0958d7693c4f --- /dev/null +++ b/drivers/soc/qcom/rpmpd.c @@ -0,0 +1,307 @@ +/* + * Copyright (c) 2017, The Linux Foundation. All rights reserved. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#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 long 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 powerdomains */ +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[] = { + [0] = &msm8996_vddcx, + [1] = &msm8996_vddcx_ao, + [2] = &msm8996_vddcx_vfc, + [3] = &msm8996_vddmx, + [4] = &msm8996_vddmx_ao, + [5] = &msm8996_vddsscx, + [6] = &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,rpmpd-msm8996", .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 long corner, + unsigned long *active, unsigned long *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 long active_corner, sleep_corner; + unsigned long this_corner = 0, this_sleep_corner = 0; + unsigned long peer_corner = 0, peer_sleep_corner = 0; + + to_active_sleep(pd, pd->corner, &this_corner, &this_sleep_corner); + + if (peer && peer->enabled) + to_active_sleep(peer, peer->corner, &peer_corner, + &peer_sleep_corner); + + active_corner = max(this_corner, peer_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]) + 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 RPM Power Domain Driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:qcom-rpmpd");