From patchwork Tue Apr 2 11:20:07 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Joseph Lo X-Patchwork-Id: 2377141 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork2.kernel.org Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) by patchwork2.kernel.org (Postfix) with ESMTP id 68579DF2A1 for ; Tue, 2 Apr 2013 11:27:53 +0000 (UTC) Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1UMzKj-0001HW-4C; Tue, 02 Apr 2013 11:24:57 +0000 Received: from hqemgate04.nvidia.com ([216.228.121.35]) by merlin.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1UMzGb-00077G-Td for linux-arm-kernel@lists.infradead.org; Tue, 02 Apr 2013 11:20:44 +0000 Received: from hqnvupgp07.nvidia.com (Not Verified[216.228.121.13]) by hqemgate04.nvidia.com id ; Tue, 02 Apr 2013 04:20:30 -0700 Received: from hqemhub01.nvidia.com ([172.20.12.94]) by hqnvupgp07.nvidia.com (PGP Universal service); Tue, 02 Apr 2013 04:19:42 -0700 X-PGP-Universal: processed; by hqnvupgp07.nvidia.com on Tue, 02 Apr 2013 04:19:42 -0700 Received: from jlo-ubuntu-64.nvidia.com (172.20.144.16) by hqemhub01.nvidia.com (172.20.150.30) with Microsoft SMTP Server (TLS) id 8.3.298.1; Tue, 2 Apr 2013 04:20:29 -0700 From: Joseph Lo To: Stephen Warren Subject: [PATCH V5 3/9] ARM: dt: tegra: add bindings of power management configurations for PMC Date: Tue, 2 Apr 2013 19:20:07 +0800 Message-ID: <1364901613-25080-4-git-send-email-josephl@nvidia.com> X-Mailer: git-send-email 1.8.2 In-Reply-To: <1364901613-25080-1-git-send-email-josephl@nvidia.com> References: <1364901613-25080-1-git-send-email-josephl@nvidia.com> X-NVConfidentiality: public MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20130402_072042_143670_359554E8 X-CRM114-Status: GOOD ( 21.55 ) X-Spam-Score: -9.2 (---------) X-Spam-Report: SpamAssassin version 3.3.2 on merlin.infradead.org summary: Content analysis details: (-9.2 points) pts rule name description ---- ---------------------- -------------------------------------------------- -5.0 RCVD_IN_DNSWL_HI RBL: Sender listed at http://www.dnswl.org/, high trust [216.228.121.35 listed in list.dnswl.org] -0.0 SPF_HELO_PASS SPF: HELO matches SPF record -0.0 SPF_PASS SPF: sender matches SPF record -2.3 RP_MATCHES_RCVD Envelope sender domain matches handover relay domain -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] Cc: devicetree-discuss@lists.ozlabs.org, Rob Herring , Grant Likely , Joseph Lo , linux-tegra@vger.kernel.org, linux-arm-kernel@lists.infradead.org X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org The PMC mostly controls the entry and exit of the system from different sleep modes. Different platform or system may have different configurations. The power management configurations of PMC is represented as some properties. The system needs to define the properties when the system supports deep sleep mode (i.e. suspend). Cc: Grant Likely Cc: Rob Herring Cc: devicetree-discuss@lists.ozlabs.org Signed-off-by: Joseph Lo --- V5: * fix typos V4: * no change V3: * fix typos V2: * squash the patches that defined the PM bindings for PMC and the implementation * replace the "unsigned long" with "u32" for the variables that are parsed from DT --- .../bindings/arm/tegra/nvidia,tegra20-pmc.txt | 42 ++++++++++- arch/arm/mach-tegra/pmc.c | 83 ++++++++++++++++++++++ arch/arm/mach-tegra/pmc.h | 8 +++ 3 files changed, 132 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.txt b/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.txt index 1cb8f6b..79b8390 100644 --- a/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.txt +++ b/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.txt @@ -1,9 +1,15 @@ NVIDIA Tegra Power Management Controller (PMC) -Properties: +The PMC block interacts with an external Power Management Unit. The PMC +mostly controls the entry and exit of the system from different sleep +modes. It provides power-gating controllers for SoC and CPU power-islands. + +Required properties: - name : Should be pmc - compatible : Should contain "nvidia,tegra-pmc". - reg : Offset and length of the register set for the device + +Optional properties: - nvidia,invert-interrupt : If present, inverts the PMU interrupt signal. The PMU is an external Power Management Unit, whose interrupt output signal is fed into the PMC. This signal is optionally inverted, and then @@ -11,6 +17,32 @@ Properties: handling of this interrupt signal, merely its inversion. - clocks : the source clock of PMC - clock-names : the name of source clock of PMC +- nvidia,suspend-mode : The suspend mode that the platform should use. + Valid values are 0, 1 and 2: + 0 (LP0): CPU + Core voltage off and DRAM in self-refresh + 1 (LP1): CPU voltage off and DRAM in self-refresh + 2 (LP2): CPU voltage off +- nvidia,core-power-req-active-high : Boolean, core power request active-high +- nvidia,sys-clock-req-active-high : Boolean, system clock request active-high +- nvidia,combined-power-req : Boolean, combined power request for CPU & Core +- nvidia,cpu-pwr-good-en : Boolean, CPU power good signal (from PMIC to PMC) + is enabled. + +Required properties when nvidia,suspend-mode is specified: +- nvidia,cpu-pwr-good-time : CPU power good time in uS. +- nvidia,cpu-pwr-off-time : CPU power off time in uS. +- nvidia,core-pwr-good-time : + Core power good time in uS. +- nvidia,core-pwr-off-time : Core power off time in uS. + +Required properties when nvidia,suspend-mode=<0>: +- nvidia,lp0-vec : Starting address and length of LP0 vector + The LP0 vector contains the warm boot code that is executed by AVP when + resuming from the LP0 state. The AVP (Audio-Video Processor) is an ARM7 + processor and always being the first boot processor when chip is power on + or resume from deep sleep mode. When the system is resumed from the deep + sleep mode, the warm boot code will restore some PLLs, clocks and then + bring up CPU0 for resuming the system. Example: @@ -21,6 +53,14 @@ pmc@7000f400 { nvidia,invert-interrupt; clocks = <&tegra_car 110>, <&clk32k_in>; clock-names = "pclk", "clk32k_in"; + nvidia,suspend-mode = <1>; + nvidia,cpu-pwr-good-time = <2000>; + nvidia,cpu-pwr-off-time = <100>; + nvidia,core-pwr-good-time = <3845 3845>; + nvidia,core-pwr-off-time = <458>; + nvidia,core-power-req-active-high; + nvidia,sys-clock-req-active-high; + nvidia,lp0-vec = <0xbdffd000 0x2000>; }; / Tegra board dts file diff --git a/arch/arm/mach-tegra/pmc.c b/arch/arm/mach-tegra/pmc.c index 8abf02f..5323bca 100644 --- a/arch/arm/mach-tegra/pmc.c +++ b/arch/arm/mach-tegra/pmc.c @@ -21,6 +21,8 @@ #include #include +#include "pmc.h" + #define PMC_CTRL 0x0 #define PMC_CTRL_INTR_LOW (1 << 17) #define PMC_PWRGATE_TOGGLE 0x30 @@ -49,6 +51,22 @@ static void __iomem *tegra_pmc_base; static bool tegra_pmc_invert_interrupt; static struct clk *tegra_pclk; +struct pmc_pm_data { + u32 cpu_good_time; /* CPU power good time in uS */ + u32 cpu_off_time; /* CPU power off time in uS */ + u32 core_osc_time; /* Core power good osc time in uS */ + u32 core_pmu_time; /* Core power good pmu time in uS */ + u32 core_off_time; /* Core power off time in uS */ + bool corereq_high; /* Core power request active-high */ + bool sysclkreq_high; /* System clock request active-high */ + bool combined_req; /* Combined pwr req for CPU & Core */ + bool cpu_pwr_good_en; /* CPU power good signal is enabled */ + u32 lp0_vec_phy_addr; /* The phy addr of LP0 warm boot code */ + u32 lp0_vec_size; /* The size of LP0 warm boot code */ + enum tegra_suspend_mode suspend_mode; +}; +static struct pmc_pm_data pmc_pm_data; + static inline u32 tegra_pmc_readl(u32 reg) { return readl(tegra_pmc_base + reg); @@ -177,6 +195,10 @@ static const struct of_device_id matches[] __initconst = { static void tegra_pmc_parse_dt(void) { struct device_node *np; + u32 prop; + enum tegra_suspend_mode suspend_mode; + u32 core_good_time[2] = {0, 0}; + u32 lp0_vec[2] = {0, 0}; np = of_find_matching_node(NULL, matches); BUG_ON(!np); @@ -187,6 +209,67 @@ static void tegra_pmc_parse_dt(void) "nvidia,invert-interrupt"); tegra_pclk = of_clk_get_by_name(np, "pclk"); WARN_ON(IS_ERR(tegra_pclk)); + + /* Grabbing the power management configurations */ + if (of_property_read_u32(np, "nvidia,suspend-mode", &prop)) { + suspend_mode = TEGRA_SUSPEND_NONE; + } else { + switch (prop) { + case 0: + suspend_mode = TEGRA_SUSPEND_LP0; + break; + case 1: + suspend_mode = TEGRA_SUSPEND_LP1; + break; + case 2: + suspend_mode = TEGRA_SUSPEND_LP2; + break; + default: + suspend_mode = TEGRA_SUSPEND_NONE; + break; + } + } + + if (of_property_read_u32(np, "nvidia,cpu-pwr-good-time", &prop)) + suspend_mode = TEGRA_SUSPEND_NONE; + pmc_pm_data.cpu_good_time = prop; + + if (of_property_read_u32(np, "nvidia,cpu-pwr-off-time", &prop)) + suspend_mode = TEGRA_SUSPEND_NONE; + pmc_pm_data.cpu_off_time = prop; + + if (of_property_read_u32_array(np, "nvidia,core-pwr-good-time", + core_good_time, ARRAY_SIZE(core_good_time))) + suspend_mode = TEGRA_SUSPEND_NONE; + pmc_pm_data.core_osc_time = core_good_time[0]; + pmc_pm_data.core_pmu_time = core_good_time[1]; + + if (of_property_read_u32(np, "nvidia,core-pwr-off-time", + &prop)) + suspend_mode = TEGRA_SUSPEND_NONE; + pmc_pm_data.core_off_time = prop; + + pmc_pm_data.corereq_high = of_property_read_bool(np, + "nvidia,core-power-req-active-high"); + + pmc_pm_data.sysclkreq_high = of_property_read_bool(np, + "nvidia,sys-clock-req-active-high"); + + pmc_pm_data.combined_req = of_property_read_bool(np, + "nvidia,combined-power-req"); + + pmc_pm_data.cpu_pwr_good_en = of_property_read_bool(np, + "nvidia,cpu-pwr-good-en"); + + if (of_property_read_u32_array(np, "nvidia,lp0-vec", lp0_vec, + ARRAY_SIZE(lp0_vec))) + if (suspend_mode == TEGRA_SUSPEND_LP0) + suspend_mode = TEGRA_SUSPEND_LP1; + + pmc_pm_data.lp0_vec_phy_addr = lp0_vec[0]; + pmc_pm_data.lp0_vec_size = lp0_vec[1]; + + pmc_pm_data.suspend_mode = suspend_mode; } void __init tegra_pmc_init(void) diff --git a/arch/arm/mach-tegra/pmc.h b/arch/arm/mach-tegra/pmc.h index 22f16c9..6bc0fc09 100644 --- a/arch/arm/mach-tegra/pmc.h +++ b/arch/arm/mach-tegra/pmc.h @@ -18,6 +18,14 @@ #ifndef __MACH_TEGRA_PMC_H #define __MACH_TEGRA_PMC_H +enum tegra_suspend_mode { + TEGRA_SUSPEND_NONE = 0, + TEGRA_SUSPEND_LP2, /* CPU voltage off */ + TEGRA_SUSPEND_LP1, /* CPU voltage off, DRAM self-refresh */ + TEGRA_SUSPEND_LP0, /* CPU + core voltage off, DRAM self-refresh */ + TEGRA_MAX_SUSPEND_MODE, +}; + #ifdef CONFIG_PM_SLEEP void set_power_timers(unsigned long us_on, unsigned long us_off); #endif