From patchwork Tue Nov 17 22:37:26 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lina Iyer X-Patchwork-Id: 7642631 X-Patchwork-Delegate: agross@codeaurora.org Return-Path: X-Original-To: patchwork-linux-arm-msm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 96E989F7CA for ; Tue, 17 Nov 2015 22:38:28 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 3E54F20523 for ; Tue, 17 Nov 2015 22:38:27 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id E6B6820524 for ; Tue, 17 Nov 2015 22:38:25 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932216AbbKQWiW (ORCPT ); Tue, 17 Nov 2015 17:38:22 -0500 Received: from mail-pa0-f50.google.com ([209.85.220.50]:33486 "EHLO mail-pa0-f50.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754972AbbKQWiV (ORCPT ); Tue, 17 Nov 2015 17:38:21 -0500 Received: by pabfh17 with SMTP id fh17so22922295pab.0 for ; Tue, 17 Nov 2015 14:38:20 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro_org.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=3phZ8pHusHjziEZyA2w6M16sZX1ZNZC90h6tbbRN/7o=; b=HA55IdhbBkWLAGGbTulG6N4H3q1F0AbxgUZ4uSkzMuH9tDovdWoE17v/GNsA8dNtqK zk9UWp4gUeUN9Yokwj7mEPHl4NJhyVz+/MVz7D7+mb676/WPIvno3jQm3UCXSHbLnR3x lzC1gPcBO5QIzKGRTUpLZ7fO/t3iGQsysQAAMUzxZ0gGG/Mi9XWBYRLKhetU6F46B9wB 6CcIwp786V7C8+8bVfGi/lOuUnoOYeWRfOCiBYhheAQOx/cCm2K1XvIxQ0oa8CsPyMx1 D61skRK1cFDSm6T9InWWlbc6btW8CeWi5lcmPge3rUBTXZfiofBfG3czqa6/WFDD4fUg UkxA== 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=3phZ8pHusHjziEZyA2w6M16sZX1ZNZC90h6tbbRN/7o=; b=LDzrG62VneCZu+ERhWCUB8DSsYx76uPYXKw/JMzpHeEvKDM8iC9ied7SFsZB2g+y4s /0o9oLJ7g66x0qnJ8qEvqxSMhs9I88aqg5sjbgpL+9XATUwfsm3sKxfOrBg5tbV2zQ3i 1BDfTsNenisXQVZc/n8m3i6BY9S7PTUGG3vLCVSCm/oh6/281N+HdeV5tk/4qnltpfK6 VYP7hziUCcxdYN0EDM/NQDP/H6XgAC5WNvvneXpvbWBfW1w3UaLAtkt4bu5UvQZHpU8/ Zf6o009NDQIjubJoDRqPUbdr4Ri8nkAmsYPWaIu8EfcqNcB2dUsVMBDZfkJyc3PWgiRS SUUA== X-Gm-Message-State: ALoCoQkbAdDnNxoVEYlPEt7cW+bYGqzqxVTx6CR6ValLBCJPODsQOhL0IPqPHHpVmXny6prCIgQf X-Received: by 10.66.100.166 with SMTP id ez6mr67428464pab.49.1447799900415; Tue, 17 Nov 2015 14:38:20 -0800 (PST) Received: from ubuntu.localdomain ([8.42.77.226]) by smtp.gmail.com with ESMTPSA id hy1sm14875199pbb.63.2015.11.17.14.38.18 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Tue, 17 Nov 2015 14:38:19 -0800 (PST) From: Lina Iyer To: ulf.hansson@linaro.org, khilman@linaro.org, linux-pm@vger.kernel.org, linux-arm-kernel@lists.infradead.org Cc: geert@linux-m68k.org, k.kozlowski@samsung.com, msivasub@codeaurora.org, agross@codeaurora.org, sboyd@codeaurora.org, linux-arm-msm@vger.kernel.org, lorenzo.pieralisi@arm.com, ahaslam@baylibre.com, mtitinger@baylibre.com, Marc Titinger , Lina Iyer Subject: [PATCH RFC 02/27] PM / Domains: Allow domain power states to be read from DT Date: Tue, 17 Nov 2015 15:37:26 -0700 Message-Id: <1447799871-56374-3-git-send-email-lina.iyer@linaro.org> X-Mailer: git-send-email 2.1.4 In-Reply-To: <1447799871-56374-1-git-send-email-lina.iyer@linaro.org> References: <1447799871-56374-1-git-send-email-lina.iyer@linaro.org> Sender: linux-arm-msm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-arm-msm@vger.kernel.org X-Spam-Status: No, score=-7.4 required=5.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_HI,RP_MATCHES_RCVD,T_DKIM_INVALID,UNPARSEABLE_RELAY autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Marc Titinger From: Marc Titinger This patch allows cluster-level idle-states to being soaked in as generic domain power states, in order for the domain governor to chose the most efficient power state compatible with the device constraints. Similarly, devices can register power-states into the cluster domain, in a manner consistent with idle-states. This is a attempt to address device-retention states for devices that are not hooked to runtime-pm, but feature a retention state handled by the same firmware that handles idle-states. For instance a L2 caches. With Juno, in this example the idle-state 'cluster-sleep-0 ' is known from each cluster generic domain, as the deepest sate. cat /sys/kernel/debug/pm_genpd/* Domain State name Enter (ns) / Exit (ns) ------------------------------------------------------------- a53_pd cluster-sleep-0 1500000 / 800000 a57_pd cluster-sleep-0 1500000 / 800000 domain status pstate slaves /device runtime status ----------------------------------------------------------------------- a53_pd on /devices/system/cpu/cpu0 active /devices/system/cpu/cpu3 suspended /devices/system/cpu/cpu4 suspended /devices/system/cpu/cpu5 suspended /devices/platform/D1 suspended a57_pd cluster-sleep-0 /devices/system/cpu/cpu1 suspended /devices/system/cpu/cpu2 suspended Signed-off-by: Marc Titinger Signed-off-by: Lina Iyer [Lina: removed dependency on dynamic states, simplified initalization, added of_pm_genpd_init() API] --- .../devicetree/bindings/power/power_domain.txt | 63 ++++++++++ drivers/base/power/domain.c | 128 +++++++++++++++++++++ include/linux/pm_domain.h | 6 + 3 files changed, 197 insertions(+) diff --git a/Documentation/devicetree/bindings/power/power_domain.txt b/Documentation/devicetree/bindings/power/power_domain.txt index 025b5e7..e2f542e 100644 --- a/Documentation/devicetree/bindings/power/power_domain.txt +++ b/Documentation/devicetree/bindings/power/power_domain.txt @@ -29,6 +29,44 @@ Optional properties: specified by this binding. More details about power domain specifier are available in the next section. +- power-states : A phandle of an idle-state that shall be soaked into a + generic domain power state. The power-state shall be + compatible with "linux,domain-state". + +==Power state== + +A PM domain power state describes an idle state of a domain and must be +have the following properties - + + - compatible + Usage: Required + Value type: + Definition: Must be "linux,domain-state" + + - entry-latency-us + Usage: Not required if wakeup-latency-us is provided. + Value type: + Definition: u32 value representing worst case latency in + microseconds required to enter the idle state. + The exit-latency-us duration may be guaranteed + only after entry-latency-us has passed. + + - exit-latency-us + Usage: Not required if wakeup-latency-us is provided. + Value type: + Definition: u32 value representing worst case latency + in microseconds required to exit the idle state. + + - wakeup-latency-us: + Usage: Not required if entry-latency-us and exit-latency-us + are provided. + Value type: + Definition: u32 value representing maximum delay between the + signaling the wakeup of the domain and the domain resuming + regular operation. + If omitted, this is assumed to be equal to: + entry-latency-us + exit-latency-us + Example: power: power-controller@12340000 { @@ -55,6 +93,31 @@ Example 2: #power-domain-cells = <1>; }; +Example 3: + + pm-domains { + a57_pd: a57_pd@ { + /* will have a57 platform ARM_PD_METHOD_OF_DECLARE*/ + compatible = "arm,pd","arm,cortex-a57"; + #power-domain-cells = <0>; + power-states = <&CLUSTER_SLEEP_0>; + }; + + a53_pd: a53_pd@ { + /* will have a a53 platform ARM_PD_METHOD_OF_DECLARE*/ + compatible = "arm,pd","arm,cortex-a53"; + #power-domain-cells = <0>; + power-states = <&CLUSTER_SLEEP_0>; + }; + + CLUSTER_SLEEP_0: power-state@0 { + compatible = "pm-domain,power-state"; + entry-latency-us = <1000>; + exit-latency-us = <2000>; + }; + }; + + The nodes above define two power controllers: 'parent' and 'child'. Domains created by the 'child' power controller are subdomains of '0' power domain provided by the 'parent' power controller. diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index 3242854..fe1be88 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -35,6 +35,7 @@ }) #define GENPD_MAX_NAME_SIZE 20 +#define GENPD_MAX_DOMAIN_STATES 10 static int pm_genpd_alloc_states_names(struct generic_pm_domain *genpd, const struct genpd_power_state *st, @@ -1515,6 +1516,105 @@ static int pm_genpd_default_restore_state(struct device *dev) return cb ? cb(dev) : 0; } +static const struct of_device_id power_state_match[] = { + { .compatible = "linux,domain-state" }, + { } +}; + +static int of_get_genpd_power_state(struct genpd_power_state *genpd_state, + struct device_node *state_node) +{ + const struct of_device_id *match_id; + int err = 0; + u32 latency; + + match_id = of_match_node(power_state_match, state_node); + if (!match_id) + return -ENODEV; + + err = of_property_read_u32(state_node, "wakeup-latency-us", &latency); + if (err) { + u32 entry_latency, exit_latency; + + err = of_property_read_u32(state_node, "entry-latency-us", + &entry_latency); + if (err) { + pr_debug(" * %s missing entry-latency-us property\n", + state_node->full_name); + return -EINVAL; + } + + err = of_property_read_u32(state_node, "exit-latency-us", + &exit_latency); + if (err) { + pr_debug(" * %s missing exit-latency-us property\n", + state_node->full_name); + return -EINVAL; + } + /* + * If wakeup-latency-us is missing, default to entry+exit + * latencies as defined in idle states bindings + */ + latency = entry_latency + exit_latency; + } + + genpd_state->power_on_latency_ns = 1000 * latency; + + err = of_property_read_u32(state_node, "entry-latency-us", &latency); + if (err) { + pr_debug(" * %s missing min-residency-us property\n", + state_node->full_name); + return -EINVAL; + } + + genpd_state->power_off_latency_ns = 1000 * latency; + + return 0; +} + +static int of_genpd_device_parse_states(struct device_node *np, + struct genpd_power_state *genpd_states, + int *state_count) +{ + struct device_node *state_node; + int i, err = 0; + + for (i = 0;; i++) { + struct genpd_power_state genpd_state; + + state_node = of_parse_phandle(np, "power-states", i); + if (!state_node) + break; + + if (i == GENPD_MAX_DOMAIN_STATES) { + err = -ENOMEM; + break; + } + + err = of_get_genpd_power_state(&genpd_state, state_node); + if (err) { + pr_err + ("Parsing idle state node %s failed with err %d\n", + state_node->full_name, err); + err = -EINVAL; + break; + } +#ifdef CONFIG_PM_ADVANCED_DEBUG + genpd_state.name = kstrndup(state_node->full_name, + GENPD_MAX_NAME_SIZE, GFP_KERNEL); + if (!genpd_state.name) + err = -ENOMEM; +#endif + of_node_put(state_node); + memcpy(&genpd_states[i], &genpd_state, sizeof(genpd_state)); +#ifdef CONFIG_PM_ADVANCED_DEBUG + kfree(genpd_state.name); +#endif + } + *state_count = i; + return err; +} + /** * pm_genpd_init - Initialize a generic I/O PM domain object. * @genpd: PM domain object to initialize. @@ -1596,6 +1696,34 @@ void pm_genpd_init(struct generic_pm_domain *genpd, } EXPORT_SYMBOL_GPL(pm_genpd_init); +int of_pm_genpd_init(struct device_node *dn, struct generic_pm_domain *genpd, + struct dev_power_governor *gov, bool is_off) +{ + struct genpd_power_state states[GENPD_MAX_DOMAIN_STATES] = { { 0 } }; + int state_count = GENPD_MAX_DOMAIN_STATES; + int ret; + + if (IS_ERR_OR_NULL(genpd)) + return -EINVAL; + + ret = of_genpd_device_parse_states(dn, states, &state_count); + if (ret) { + pr_err("Error parsing genpd states for %s\n", genpd->name); + return ret; + } + + ret = genpd_alloc_states_data(genpd, states, state_count); + if (ret) { + pr_err("Failed to allocate states for %s\n", genpd->name); + return ret; + } + + pm_genpd_init(genpd, gov, is_off); + + return 0; +} +EXPORT_SYMBOL_GPL(of_pm_genpd_init); + #ifdef CONFIG_PM_GENERIC_DOMAINS_OF /* * Device Tree based PM domain providers. diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h index 11763cf..e425911 100644 --- a/include/linux/pm_domain.h +++ b/include/linux/pm_domain.h @@ -213,6 +213,8 @@ struct generic_pm_domain *__of_genpd_xlate_onecell( void *data); int genpd_dev_pm_attach(struct device *dev); +int of_pm_genpd_init(struct device_node *dn, struct generic_pm_domain *genpd, + struct dev_power_governor *gov, bool is_off); #else /* !CONFIG_PM_GENERIC_DOMAINS_OF */ static inline int __of_genpd_add_provider(struct device_node *np, genpd_xlate_t xlate, void *data) @@ -234,6 +236,10 @@ static inline int genpd_dev_pm_attach(struct device *dev) { return -ENODEV; } + +static inline int of_pm_genpd_init(struct device_node *dn, + struct generic_pm_domain *genpd, + struct dev_power_governor *gov, bool is_off) {} #endif /* CONFIG_PM_GENERIC_DOMAINS_OF */ static inline int of_genpd_add_provider_simple(struct device_node *np,