From patchwork Fri Feb 24 09:06:38 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Viresh Kumar X-Patchwork-Id: 94422 Delivered-To: patch@linaro.org Received: by 10.140.20.99 with SMTP id 90csp601431qgi; Fri, 24 Feb 2017 01:14:23 -0800 (PST) X-Received: by 10.98.81.6 with SMTP id f6mr2151914pfb.180.1487927663383; Fri, 24 Feb 2017 01:14:23 -0800 (PST) Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id e1si6807633pga.366.2017.02.24.01.14.23; Fri, 24 Feb 2017 01:14:23 -0800 (PST) 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; 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 S1751057AbdBXJOQ (ORCPT + 13 others); Fri, 24 Feb 2017 04:14:16 -0500 Received: from mail-pf0-f179.google.com ([209.85.192.179]:35520 "EHLO mail-pf0-f179.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751319AbdBXJOL (ORCPT ); Fri, 24 Feb 2017 04:14:11 -0500 Received: by mail-pf0-f179.google.com with SMTP id 68so1826701pfx.2 for ; Fri, 24 Feb 2017 01:14:11 -0800 (PST) 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=gsuCtws8MWOt/9zwkP5/cAhsYml+a2H42TdzieZaLUQ=; b=eQsb9JIouBnOinXRiKyPZwAwJcu/0gGPYH4suLTBe4RltxDGsZAtl445tE33uOo5B3 yUYfbgxBTNN7lsj3e0Hsj8jDK302Nk8sZwRjct2KGCpW7au+/iFloRg1iV/wtssAcF58 avygv8gg2hgDbm5i0mfWfr5WgEtg0IFGifmMI= 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=gsuCtws8MWOt/9zwkP5/cAhsYml+a2H42TdzieZaLUQ=; b=texgOpl+7L1VA09K27ZF3lsJGA0oBfkw968GX2IGkX6iWk4Prn7Drx2tngKa/M8jJY E7BQMFUdWMktOa98HVupi7jp3lZOKP6NP7Ztubrb+tPbaXWDIR8nYP8SR7jDUWuBMkPM H/WjocokBAgANFXrQLsFsrBcE3vfJ3BTy2jkwvGt+S4mm37Z9+ald9G5FGVcpsxyIJTr 53FPh8TIyYiJmfaTp8nkKLBJQE9aV4P9YyOCYy50zt8xpjwyPbZuyV/pVuS5xllXAZwI 3CEI4fLtWjeH1dWQysgOmLuusmqVcXQV+66sY6V5/6kArHdm13hPwM8E+uD1HOCZTaGc r7Cw== X-Gm-Message-State: AMke39lMWo0IiZ4yKJgWcEJThpf3mLBPh9Ikh2gYmMPjMzApu1AMu6IIrdoZ/czi6q810EZy X-Received: by 10.84.212.2 with SMTP id d2mr2410600pli.152.1487927224776; Fri, 24 Feb 2017 01:07:04 -0800 (PST) Received: from localhost ([122.172.165.189]) by smtp.gmail.com with ESMTPSA id t6sm14047990pgt.8.2017.02.24.01.07.03 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 24 Feb 2017 01:07:04 -0800 (PST) From: Viresh Kumar To: Rafael Wysocki , ulf.hansson@linaro.org, Kevin Hilman , Kevin Hilman , Len Brown , Pavel Machek Cc: linaro-kernel@lists.linaro.org, linux-pm@vger.kernel.org, linux-kernel@vger.kernel.org, Stephen Boyd , Nishanth Menon , Vincent Guittot , robh+dt@kernel.org, lina.iyer@linaro.org, rnayak@codeaurora.org, Viresh Kumar Subject: [PATCH V3 6/7] PM / Domains: Allow domain performance states to be read from DT Date: Fri, 24 Feb 2017 14:36:38 +0530 Message-Id: <84786c05d90e5f3c9dc41a65fe3b8ce6052a7628.1487926924.git.viresh.kumar@linaro.org> X-Mailer: git-send-email 2.7.1.410.g6faf27b 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 This patch allows SoC's to define domains performance states in the DT using the "performance-states" node in the domain provider node. Add API to read the performance states from DT by the domain specific drivers. Note that this information is only used by the domain specific drivers and the power domain core doesn't need to store it for now. Signed-off-by: Viresh Kumar Tested-by: Rajendra Nayak --- drivers/base/power/domain.c | 101 ++++++++++++++++++++++++++++++++++++++++++++ include/linux/pm_domain.h | 15 +++++++ 2 files changed, 116 insertions(+) -- 2.7.1.410.g6faf27b diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index 202effbebfd1..a7449c492990 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -2251,6 +2251,107 @@ int of_genpd_parse_idle_states(struct device_node *dn, } EXPORT_SYMBOL_GPL(of_genpd_parse_idle_states); +/* Power domain performance state management helpers */ +static const struct of_device_id performance_state_match[] = { + { .compatible = "domain-performance-state", }, + { } +}; + +static int genpd_parse_performance_state(struct genpd_performance_state *state, + struct device_node *np) +{ + int ret; + + ret = of_property_read_u32(np, "reg", &state->performance_state); + if (ret) { + pr_err(" * %s missing reg property\n", np->full_name); + return ret; + } + + ret = of_property_read_variable_u32_array(np, "domain-microvolt", + &state->u_volt, 1, 3); + if (ret >= 0) + return 0; + + /* Property not found */ + if (ret == -EINVAL) + return 0; + + pr_err(" * %s Invalid domain-microvolt property\n", np->full_name); + return ret; +} + +/** + * of_genpd_parse_performance_states: Return array of performance states for the + * genpd. + * + * @dn: The genpd device node + * @states: The pointer to which the state array will be saved. + * @n: The count of elements in the array returned from this function. + * + * Returns the device performance states parsed from the OF node. The memory for + * the states is allocated by this function and is the responsibility of the + * caller to free the memory after use. + */ +int of_genpd_parse_performance_states(struct device_node *dn, + struct genpd_performance_state **states, int *n) +{ + struct genpd_performance_state *st; + struct device_node *perf_np, *np; + int i = 0, ret, count; + + perf_np = of_get_child_by_name(dn, "performance-states"); + if (!perf_np) { + pr_err("performance-states node not found in %s node\n", + dn->full_name); + return -ENODEV; + } + + if (!of_match_node(performance_state_match, perf_np)) { + pr_err("performance-states node found in %s node isn't compatible\n", + dn->full_name); + ret = -EINVAL; + goto put_node; + } + + count = of_get_child_count(perf_np); + if (count <= 0) { + pr_err("performance-states node found in %s node doesn't have any child nodes\n", + dn->full_name); + ret = -EINVAL; + goto put_node; + } + + st = kcalloc(count, sizeof(*st), GFP_KERNEL); + if (!st) { + ret = -ENOMEM; + goto put_node; + } + + for_each_available_child_of_node(perf_np, np) { + ret = genpd_parse_performance_state(&st[i++], np); + if (ret) { + pr_err("Parsing of performance state node %s failed with err %d\n", + np->full_name, ret); + goto free_st; + } + } + + of_node_put(perf_np); + *n = count; + *states = st; + + return 0; + +free_st: + kfree(st); +put_node: + of_node_put(perf_np); + + return ret; +} +EXPORT_SYMBOL_GPL(of_genpd_parse_performance_states); + #endif /* CONFIG_PM_GENERIC_DOMAINS_OF */ diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h index 83795935709e..7659ce3968c7 100644 --- a/include/linux/pm_domain.h +++ b/include/linux/pm_domain.h @@ -44,6 +44,13 @@ struct genpd_power_state { struct fwnode_handle *fwnode; }; +struct genpd_performance_state { + unsigned int performance_state; + unsigned int u_volt; + unsigned int u_volt_min; + unsigned int u_volt_max; +}; + struct genpd_lock_ops; struct generic_pm_domain { @@ -226,6 +233,8 @@ extern int of_genpd_add_subdomain(struct of_phandle_args *parent, extern struct generic_pm_domain *of_genpd_remove_last(struct device_node *np); extern int of_genpd_parse_idle_states(struct device_node *dn, struct genpd_power_state **states, int *n); +extern int of_genpd_parse_performance_states(struct device_node *dn, + struct genpd_performance_state **states, int *n); int genpd_dev_pm_attach(struct device *dev); #else /* !CONFIG_PM_GENERIC_DOMAINS_OF */ @@ -261,6 +270,12 @@ static inline int of_genpd_parse_idle_states(struct device_node *dn, return -ENODEV; } +static inline int of_genpd_parse_performance_states(struct device_node *dn, + struct genpd_performance_state **states, int *n) +{ + return -ENODEV; +} + static inline int genpd_dev_pm_attach(struct device *dev) { return -ENODEV; From patchwork Fri Feb 24 09:06:39 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Viresh Kumar X-Patchwork-Id: 94427 Delivered-To: patch@linaro.org Received: by 10.140.20.99 with SMTP id 90csp602096qgi; Fri, 24 Feb 2017 01:16:19 -0800 (PST) X-Received: by 10.98.76.140 with SMTP id e12mr2184579pfj.82.1487927779881; Fri, 24 Feb 2017 01:16:19 -0800 (PST) Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id a36si6850054pli.42.2017.02.24.01.16.19; Fri, 24 Feb 2017 01:16:19 -0800 (PST) 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; 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 S1751304AbdBXJQS (ORCPT + 13 others); Fri, 24 Feb 2017 04:16:18 -0500 Received: from mail-pf0-f177.google.com ([209.85.192.177]:36491 "EHLO mail-pf0-f177.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751356AbdBXJQR (ORCPT ); Fri, 24 Feb 2017 04:16:17 -0500 Received: by mail-pf0-f177.google.com with SMTP id c193so1827341pfb.3 for ; Fri, 24 Feb 2017 01:16:17 -0800 (PST) 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=oWi5SBSY0XY2Ttb6kGJd1YiAE1LXQgF/FeEnOxxSukA=; b=eWOA9BRgt5lv25Uws58pyw5RDiingV5Sb2DFdMIWdk7WH4T+7PE6xjyzeKms4Cdoaw qpkplyMjd21TseiIGDOcPnMSp6FmDShcNvBXz4pi9qOOjcC38lQbttvDDX6OZ99WZykF PPSo3VqupVgKYlSrW8FSzskwPYawk0P6Q255Q= 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=oWi5SBSY0XY2Ttb6kGJd1YiAE1LXQgF/FeEnOxxSukA=; b=in7q45jubbivLD2fIjRf9bFtlQ7x/Sm+S2tXOTSF0/cTPmpg/lag4l5rH52CBiXPQc 3SrGczAbpYccLBgRZplGbvemldBSKZz1Emm6gXbUBjFSnfg1uiBYdcE1uNwClMy3m2R5 OhqmDeLlirCg7Xshgy4SldqQgvuOSThQeSrm8rBa6xkiCF176mHq2VlafTfiFGal36se Q0aqup+mrLWPu3iTiVGlFacAOZGQDwpOMCzy3KrsOrUPT2IJoNbqecN7sli11zEpQInP TqOBXO32lHTW2mrilTFkixQwSL1HXIG7EM4+j5mmrCCAblCjSQ1WQAVdcOGwI3wDQqVk D2Gw== X-Gm-Message-State: AMke39kew47py6DWSShIO/vzlZlVK6FHcMG9GMPsdwBK8CVrh8HvQ8rPobNkwg8K2ISnl5D8 X-Received: by 10.84.196.164 with SMTP id l33mr2401698pld.158.1487927228142; Fri, 24 Feb 2017 01:07:08 -0800 (PST) Received: from localhost ([122.172.165.189]) by smtp.gmail.com with ESMTPSA id x10sm13891331pfi.117.2017.02.24.01.07.07 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 24 Feb 2017 01:07:07 -0800 (PST) From: Viresh Kumar To: Rafael Wysocki , ulf.hansson@linaro.org, Kevin Hilman , Viresh Kumar , Nishanth Menon , Stephen Boyd Cc: linaro-kernel@lists.linaro.org, linux-pm@vger.kernel.org, linux-kernel@vger.kernel.org, Vincent Guittot , robh+dt@kernel.org, lina.iyer@linaro.org, rnayak@codeaurora.org, Viresh Kumar Subject: [PATCH V3 7/7] PM / OPP: Add support to parse domain-performance-state Date: Fri, 24 Feb 2017 14:36:39 +0530 Message-Id: X-Mailer: git-send-email 2.7.1.410.g6faf27b 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 This patch allows the OPP core to parse the "domain-performance-state" property in the OPP nodes. The nodes are allowed to have the "domain-performance-state" property, only if the device node contains a "power-domains" property. The OPP nodes aren't allowed to contain the property partially, i.e. Either all OPP nodes in the OPP table have the "domain-performance-state" property or none of them have it. Signed-off-by: Viresh Kumar Tested-by: Rajendra Nayak --- drivers/base/power/opp/core.c | 73 ++++++++++++++++++++++++++++++++++++++++ drivers/base/power/opp/debugfs.c | 4 +++ drivers/base/power/opp/of.c | 37 ++++++++++++++++++++ drivers/base/power/opp/opp.h | 12 +++++++ 4 files changed, 126 insertions(+) -- 2.7.1.410.g6faf27b diff --git a/drivers/base/power/opp/core.c b/drivers/base/power/opp/core.c index 91ec3232d630..211551f377e9 100644 --- a/drivers/base/power/opp/core.c +++ b/drivers/base/power/opp/core.c @@ -542,6 +542,63 @@ _generic_set_opp_clk_only(struct device *dev, struct clk *clk, return ret; } +static int _update_pm_qos_request(struct device *dev, + struct dev_pm_qos_request *req, + unsigned int perf) +{ + int ret; + + if (likely(dev_pm_qos_request_active(req))) + ret = dev_pm_qos_update_request(req, perf); + else + ret = dev_pm_qos_add_request(dev, req, DEV_PM_QOS_PERFORMANCE, + perf); + + if (ret < 0) + return ret; + + return 0; +} + +static int _generic_set_opp_pd(struct device *dev, struct clk *clk, + struct dev_pm_qos_request *req, + unsigned long old_freq, unsigned long freq, + unsigned int old_perf, unsigned int new_perf) +{ + int ret; + + /* Scaling up? Scale voltage before frequency */ + if (freq > old_freq) { + ret = _update_pm_qos_request(dev, req, new_perf); + if (ret) + return ret; + } + + /* Change frequency */ + ret = _generic_set_opp_clk_only(dev, clk, old_freq, freq); + if (ret) + goto restore_perf; + + /* Scaling down? Scale voltage after frequency */ + if (freq < old_freq) { + ret = _update_pm_qos_request(dev, req, new_perf); + if (ret) + goto restore_freq; + } + + return 0; + +restore_freq: + if (_generic_set_opp_clk_only(dev, clk, freq, old_freq)) + dev_err(dev, "%s: failed to restore old-freq (%lu Hz)\n", + __func__, old_freq); +restore_perf: + if (old_perf) + _update_pm_qos_request(dev, req, old_perf); + + return ret; +} + static int _generic_set_opp(struct dev_pm_set_opp_data *data) { struct dev_pm_opp_supply *old_supply = data->old_opp.supplies; @@ -662,6 +719,19 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq) regulators = opp_table->regulators; + /* Has power domains performance states */ + if (opp_table->has_pd_perf_states) { + unsigned int old_perf = 0, new_perf; + struct dev_pm_qos_request *req = &opp_table->qos_request; + + new_perf = opp->pd_perf_state; + if (!IS_ERR(old_opp)) + old_perf = old_opp->pd_perf_state; + + return _generic_set_opp_pd(dev, clk, req, old_freq, freq, + old_perf, new_perf); + } + /* Only frequency scaling */ if (!regulators) { ret = _generic_set_opp_clk_only(dev, clk, old_freq, freq); @@ -807,6 +877,9 @@ static void _opp_table_kref_release(struct kref *kref) struct opp_table *opp_table = container_of(kref, struct opp_table, kref); struct opp_device *opp_dev; + if (dev_pm_qos_request_active(&opp_table->qos_request)) + dev_pm_qos_remove_request(&opp_table->qos_request); + /* Release clk */ if (!IS_ERR(opp_table->clk)) clk_put(opp_table->clk); diff --git a/drivers/base/power/opp/debugfs.c b/drivers/base/power/opp/debugfs.c index 95f433db4ac7..264958ab3de9 100644 --- a/drivers/base/power/opp/debugfs.c +++ b/drivers/base/power/opp/debugfs.c @@ -104,6 +104,10 @@ int opp_debug_create_one(struct dev_pm_opp *opp, struct opp_table *opp_table) if (!debugfs_create_ulong("rate_hz", S_IRUGO, d, &opp->rate)) return -ENOMEM; + if (!debugfs_create_u32("power_domain_perf_state", S_IRUGO, d, + &opp->pd_perf_state)) + return -ENOMEM; + if (!opp_debug_create_supplies(opp, opp_table, d)) return -ENOMEM; diff --git a/drivers/base/power/opp/of.c b/drivers/base/power/opp/of.c index 779428676f63..e3b5f10e7f25 100644 --- a/drivers/base/power/opp/of.c +++ b/drivers/base/power/opp/of.c @@ -311,6 +311,38 @@ static int _opp_add_static_v2(struct opp_table *opp_table, struct device *dev, if (!of_property_read_u32(np, "clock-latency-ns", &val)) new_opp->clock_latency_ns = val; + /* + * Make sure that all information is present around domain power states + * and nothing is left out. + */ + if (!of_property_read_u32(np, "domain-performance-state", + &new_opp->pd_perf_state)) { + if (!opp_table->has_pd) { + ret = -EINVAL; + dev_err(dev, "%s: OPP node can't have performance state as device doesn't have power-domain\n", + __func__); + goto free_opp; + } + + if (opp_table->has_pd_perf_states == -1) { + opp_table->has_pd_perf_states = 1; + } else if (!opp_table->has_pd_perf_states) { + ret = -EINVAL; + dev_err(dev, "%s: Not all OPP nodes have performance state\n", + __func__); + goto free_opp; + } + } else { + if (opp_table->has_pd_perf_states == -1) { + opp_table->has_pd_perf_states = 0; + } else if (opp_table->has_pd_perf_states) { + ret = -EINVAL; + dev_err(dev, "%s: Not all OPP nodes have performance state\n", + __func__); + goto free_opp; + } + } + ret = opp_parse_supplies(new_opp, dev, opp_table); if (ret) goto free_opp; @@ -375,6 +407,11 @@ static int _of_add_opp_table_v2(struct device *dev, struct device_node *opp_np) if (!opp_table) return -ENOMEM; + if (of_find_property(dev->of_node, "power-domains", NULL)) { + opp_table->has_pd = true; + opp_table->has_pd_perf_states = -1; + } + /* We have opp-table node now, iterate over it and add OPPs */ for_each_available_child_of_node(opp_np, np) { count++; diff --git a/drivers/base/power/opp/opp.h b/drivers/base/power/opp/opp.h index 166eef990599..41a2c0a67031 100644 --- a/drivers/base/power/opp/opp.h +++ b/drivers/base/power/opp/opp.h @@ -20,6 +20,7 @@ #include #include #include +#include #include struct clk; @@ -58,6 +59,7 @@ extern struct list_head opp_tables; * @dynamic: not-created from static DT entries. * @turbo: true if turbo (boost) OPP * @suspend: true if suspend OPP + * @pd_perf_state: Performance state of power domain * @rate: Frequency in hertz * @supplies: Power supplies voltage/current values * @clock_latency_ns: Latency (in nanoseconds) of switching to this OPP's @@ -76,6 +78,7 @@ struct dev_pm_opp { bool dynamic; bool turbo; bool suspend; + unsigned int pd_perf_state; unsigned long rate; struct dev_pm_opp_supply *supplies; @@ -137,6 +140,11 @@ enum opp_table_access { * @regulator_count: Number of power supply regulators * @set_opp: Platform specific set_opp callback * @set_opp_data: Data to be passed to set_opp callback + * @has_pd: True if the device node contains power-domain property + * @has_pd_perf_states: Can have value of 0, 1 or -1. -1 means uninitialized + * state, 0 means that OPP nodes don't have perf states and 1 means that OPP + * nodes have perf states. + * @qos_request: Qos request. * @dentry: debugfs dentry pointer of the real device directory (not links). * @dentry_name: Name of the real dentry. * @@ -174,6 +182,10 @@ struct opp_table { int (*set_opp)(struct dev_pm_set_opp_data *data); struct dev_pm_set_opp_data *set_opp_data; + bool has_pd; + int has_pd_perf_states; + struct dev_pm_qos_request qos_request; + #ifdef CONFIG_DEBUG_FS struct dentry *dentry; char dentry_name[NAME_MAX];