NVIDIA Tegra core power domain driver and OPP helper
Subsystems (2)
v3 cover NVIDIA Tegra core power domain driver and OPP helper
Hello,
This series adds Core power domain driver for NVIDIA Tegra SoCs and a common OPP helper which initializes OPP table specifically for Tegra drivers. The patches depend on the ongoing series [1] which adds resource-managed OPP API.
[1] https://patchwork.kernel.org/project/linux-pm/list/?series=446525
NVIDIA Tegra SoCs have a dedicated "Core" power domain to which majority of SoC peripherals belong. The core domain is connected to a dedicated voltage rail, which is exposed as a voltage regulator to the Linux kernel. Adding support for power management (i.e. voltage scaling) of the Core domain allows to significantly improve power consumption of the Tegra chip.
In particular this PM work solves the overheating problem on Tegra30 devices. It allows Ouya Tegra30 game console to run at 40C during system idle in oppose to going over 60C. Matt Merhar collected temperature stats on his Ouya [2] which show a very significant improvement.
[2] https://imgur.com/a/z4NDWqk
Changelog:
v3: - This series is a continuation of [3][4]. I factored out and grouped
these soc/tegra patches since they have a common dependency on the OPP API patches [1] and the rest of PM patches depend on this series.
[3] https://lore.kernel.org/lkml/[email protected]/
[4] https://lore.kernel.org/linux-pm/[email protected]/
- Added locking around regulators syncing, which was previously done by the OPP core, but then we (me and Viresh) figured out that it will be better to do it within the PD driver.
- The Core-PD driver now restores the boot voltage level before shutdown/reboot, which may help some devices not to hang on reboot, like Nexus 7 for example.
- Added r-b from Ulf Hansson to "regulators: Support Core domain state syncing" patch, which he gave to v2.
- It should be cleaner to add the Core OPP tables and power domain to the device-trees once all drivers will get the PM support, so this series adds the driver and the binding for now.
- Added t-b from Paul Fertser, who tested the complete patchset on his AC100 netbook and helped to spot compatibility problem with older DTBs in the patch that will add PM support to the GPU driver.
- The DT binding now follows the power-domain spec, which was suggested by Krzysztof Kozlowski in his comment to v2.
Dmitry Osipenko (6):
soc/tegra: Add devm_tegra_core_dev_init_opp_table() soc/tegra: Add CONFIG_SOC_TEGRA_COMMON and select PM_OPP by default
dt-bindings: power: tegra: Add binding for core power domain soc/tegra: Introduce core power domain driver
soc/tegra: regulators: Support Core domain state syncing soc/tegra: pmc: Link children power domains to the parent domain
.../power/nvidia,tegra20-core-domain.yaml | 52 ++++++ drivers/soc/tegra/Kconfig | 19 +++ drivers/soc/tegra/Makefile | 1 + drivers/soc/tegra/common.c | 138 ++++++++++++++++ drivers/soc/tegra/core-power-domain.c | 154 ++++++++++++++++++ drivers/soc/tegra/pmc.c | 16 ++ drivers/soc/tegra/regulators-tegra20.c | 19 ++- drivers/soc/tegra/regulators-tegra30.c | 18 +- include/soc/tegra/common.h | 36 ++++ 9 files changed, 451 insertions(+), 2 deletions(-) create mode 100644 Documentation/devicetree/bindings/power/nvidia,tegra20-core-domain.yaml create mode 100644 drivers/soc/tegra/core-power-domain.c
Signature · 1 line
2.29.2
PATCH v3 1/6 soc/tegra: Add devm_tegra_core_dev_init_opp_table()
Add common helper which initializes OPP table for Tegra SoC core devices.
--- drivers/soc/tegra/common.c | 138 +++++++++++++++++++++++++++++++++++++ include/soc/tegra/common.h | 30 ++++++++ 2 files changed, 168 insertions(+)
drivers/soc/tegra/common.c +138 -0
@@ -3,9 +3,16 @@* Copyright (C) 2014 NVIDIA CORPORATION. All rights reserved. */ +#define dev_fmt (fmt) "tegra-soc: " fmt + +#include <linux/clk.h> +#include <linux/device.h> +#include <linux/export.h> #include <linux/of.h> +#include <linux/pm_opp.h> #include <soc/tegra/common.h> +#include <soc/tegra/fuse.h> static const struct of_device_id tegra_machine_match[] = { { .compatible ="nvidia,tegra20" , },
@@ -31,3 +38,134 @@ bool soc_is_tegra(void)return match !=NULL ; } + +static int tegra_core_dev_init_opp_state (struct device *dev) +{ +struct dev_pm_opp *opp; +unsigned long rate; +struct clk *clk; +int err; + + clk =devm_clk_get (dev,NULL ); +if (IS_ERR (clk)) { +dev_err (dev,"failed to get clk: %pe\n" , clk); +return PTR_ERR (clk); + } + +/* +* If voltage regulator presents, then we could select the fastest +* clock rate, but driver doesn't support power management and +* frequency scaling yet, hence the top freq OPP will vote for a +* very high voltage that will produce lot's of heat. Let's select +* OPP for the current/default rate for now. +* +* Clock rate should be pre-initialized (i.e. it's non-zero) either +* by clock driver or by assigned clocks in a device-tree. +*/ + rate =clk_get_rate (clk); +if (!rate) { +dev_err (dev,"failed to get clk rate\n" ); +return -EINVAL ; + } + +/* find suitable OPP for the clock rate and supportable by hardware */ + opp =dev_pm_opp_find_freq_ceil (dev, &rate); + +/* +* dev_pm_opp_set_rate() doesn't search for a floor clock rate and it +* will error out if default clock rate is too high, i.e. unsupported +* by a SoC hardware version. Hence will find floor rate by ourselves. +*/ +if (opp ==ERR_PTR (-ERANGE )) + opp =dev_pm_opp_find_freq_floor (dev, &rate); + + err =PTR_ERR_OR_ZERO (opp); +if (err) { +dev_err (dev,"failed to get OPP for %ld Hz: %d\n" , + rate, err); +return err; + } + +dev_pm_opp_put (opp); + +/* +* First dummy rate-set initializes voltage vote by setting voltage +* in accordance to the clock rate. We need to do this because some +* drivers currently don't support power management and clock is +* permanently enabled. +*/ + err =dev_pm_opp_set_rate (dev, rate); +if (err) { +dev_err (dev,"failed to initialize OPP clock: %d\n" , err); +return err; + } + +return 0 ; +} + +/** +* devm_tegra_core_dev_init_opp_table() - initialize OPP table +* @dev: device for which OPP table is initialized +* @params: pointer to the OPP table configuration +* +* This function will initialize OPP table and sync OPP state of a Tegra SoC +* core device. +* +* Return: 0 on success or errorno. +*/ +int devm_tegra_core_dev_init_opp_table (struct device *dev, +struct tegra_core_opp_params *params) +{ +struct opp_table *opp_table; +u32 hw_version; +int err; + + opp_table =devm_pm_opp_set_clkname (dev,NULL ); +if (IS_ERR (opp_table)) { +dev_err (dev,"failed to set OPP clk %pe\n" , opp_table); +return PTR_ERR (opp_table); + } + +/* Tegra114+ doesn't support OPP yet */ +if (!of_machine_is_compatible ("nvidia,tegra20" ) && + !of_machine_is_compatible ("nvidia,tegra30" )) +return -ENODEV ; + +if (of_machine_is_compatible ("nvidia,tegra20" )) + hw_version =BIT (tegra_sku_info.soc_process_id); +else + hw_version =BIT (tegra_sku_info.soc_speedo_id); + + opp_table =devm_pm_opp_set_supported_hw (dev, &hw_version,1 ); +if (IS_ERR (opp_table)) { +dev_err (dev,"failed to set OPP supported HW: %pe\n" , opp_table); +return PTR_ERR (opp_table); + } + +/* +* Older device-trees have an empty OPP table, hence we will get +* -ENODEV from devm_pm_opp_of_add_table() for the older DTBs. +* +* The OPP table presence also varies per-device and depending +* on a SoC generation, hence -ENODEV is expected to happen for +* the newer DTs as well. +*/ + err =devm_pm_opp_of_add_table (dev); +if (err) { +if (err == -ENODEV ) +dev_err_once (dev,"OPP table not found, please update device-tree\n" ); +else +dev_err (dev,"failed to add OPP table: %d\n" , err); + +return err; + } + +if (params->init_state) { + err =tegra_core_dev_init_opp_state (dev); +if (err) +return err; + } + +return 0 ; +} +EXPORT_SYMBOL_GPL (devm_tegra_core_dev_init_opp_table);
include/soc/tegra/common.h +30 -0
@@ -6,6 +6,36 @@#ifndef __SOC_TEGRA_COMMON_H__#define __SOC_TEGRA_COMMON_H__ +#include <linux/errno.h> +#include <linux/types.h> + +struct device ; + +/** +* Tegra SoC core device OPP table configuration +* +* @init_state: pre-initialize OPP state of a device +*/ +struct tegra_core_opp_params { +bool init_state; +}; + +#ifdef CONFIG_ARCH_TEGRA bool soc_is_tegra (void ); +int devm_tegra_core_dev_init_opp_table (struct device *dev, +struct tegra_core_opp_params *params); +#else +static inline bool soc_is_tegra (void ) +{ +return false; +} + +static inline int +devm_tegra_core_dev_init_opp_table (struct device *dev, +struct tegra_core_opp_params *params) +{ +return -ENODEV ; +} +#endif #endif /* __SOC_TEGRA_COMMON_H__ */
Signature · 1 line
2.29.2
kernel test robot
build botRe: [PATCH v3 1/6] soc/tegra: Add devm_tegra_core_dev_init_opp_table()
I love your patch! Perhaps something to improve:
Hi Dmitry,
I love your patch! Perhaps something to improve:
[auto build test WARNING on tegra/for-next]
[also build test WARNING on v5.12-rc2 next-20210311]
[If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]
url: https://github.com/0day-ci/linux/commits/Dmitry-Osipenko/soc-tegra-Add-devm_tegra_core_dev_init_opp_table/20210312-081244 base: https://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux.git for-next config: arm-defconfig (attached as .config) compiler: arm-linux-gnueabi-gcc (GCC) 9.3.0
reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross
# https://github.com/0day-ci/linux/commit/8d5ea5b946a1399d7490fa992733a737c4bbd594
git remote add linux-review https://github.com/0day-ci/linux
git fetch --no-tags linux-review Dmitry-Osipenko/soc-tegra-Add-devm_tegra_core_dev_init_opp_table/20210312-081244 git checkout 8d5ea5b946a1399d7490fa992733a737c4bbd594
# save the attached .config to linux build tree
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross ARCH=arm
If you fix the issue, kindly add following tag as appropriate
All warnings (new ones prefixed by >>):
drivers/soc/tegra/common.c: In function 'devm_tegra_core_dev_init_opp_table':
drivers/soc/tegra/common.c:123:14: error: implicit declaration of function 'devm_pm_opp_set_clkname'; did you mean 'dev_pm_opp_set_clkname'? [-Werror=implicit-function-declaration]
123 | opp_table = devm_pm_opp_set_clkname(dev, NULL);
| ^~~~~~~~~~~~~~~~~~~~~~~
| dev_pm_opp_set_clkname
>> drivers/soc/tegra/common.c:123:12: warning: assignment to 'struct opp_table *' from 'int' makes pointer from integer without a cast [-Wint-conversion]
123 | opp_table = devm_pm_opp_set_clkname(dev, NULL);
| ^
drivers/soc/tegra/common.c:139:14: error: implicit declaration of function 'devm_pm_opp_set_supported_hw'; did you mean 'dev_pm_opp_set_supported_hw'? [-Werror=implicit-function-declaration]
139 | opp_table = devm_pm_opp_set_supported_hw(dev, &hw_version, 1);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
| dev_pm_opp_set_supported_hw
drivers/soc/tegra/common.c:139:12: warning: assignment to 'struct opp_table *' from 'int' makes pointer from integer without a cast [-Wint-conversion]
139 | opp_table = devm_pm_opp_set_supported_hw(dev, &hw_version, 1);
| ^
drivers/soc/tegra/common.c:153:8: error: implicit declaration of function 'devm_pm_opp_of_add_table'; did you mean 'dev_pm_opp_of_add_table'? [-Werror=implicit-function-declaration]
153 | err = devm_pm_opp_of_add_table(dev);
| ^~~~~~~~~~~~~~~~~~~~~~~~
| dev_pm_opp_of_add_tablecc1: some warnings being treated as errors
vim +123 drivers/soc/tegra/common.c
105
106 /**
107 * devm_tegra_core_dev_init_opp_table() - initialize OPP table
108 * @dev: device for which OPP table is initialized
109 * @params: pointer to the OPP table configuration
110 *
111 * This function will initialize OPP table and sync OPP state of a Tegra SoC
112 * core device.
113 *
114 * Return: 0 on success or errorno.
115 */
116 int devm_tegra_core_dev_init_opp_table(struct device *dev,
117 struct tegra_core_opp_params *params)
118 {
119 struct opp_table *opp_table;
120 u32 hw_version;
121 int err;
122
> 123 opp_table = devm_pm_opp_set_clkname(dev, NULL);
---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org
kernel test robot
build botRe: [PATCH v3 1/6] soc/tegra: Add devm_tegra_core_dev_init_opp_table()
In reply to Dmitry OsipenkoI love your patch! Yet something to improve:
Hi Dmitry,
I love your patch! Yet something to improve:
[auto build test ERROR on tegra/for-next]
[also build test ERROR on v5.12-rc2 next-20210311]
[If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]
url: https://github.com/0day-ci/linux/commits/Dmitry-Osipenko/soc-tegra-Add-devm_tegra_core_dev_init_opp_table/20210312-081244 base: https://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux.git for-next config: arm-defconfig (attached as .config) compiler: arm-linux-gnueabi-gcc (GCC) 9.3.0
reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross
# https://github.com/0day-ci/linux/commit/8d5ea5b946a1399d7490fa992733a737c4bbd594
git remote add linux-review https://github.com/0day-ci/linux
git fetch --no-tags linux-review Dmitry-Osipenko/soc-tegra-Add-devm_tegra_core_dev_init_opp_table/20210312-081244 git checkout 8d5ea5b946a1399d7490fa992733a737c4bbd594
# save the attached .config to linux build tree
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross ARCH=arm
If you fix the issue, kindly add following tag as appropriate
All errors (new ones prefixed by >>):
drivers/soc/tegra/common.c: In function 'devm_tegra_core_dev_init_opp_table':
>> drivers/soc/tegra/common.c:123:14: error: implicit declaration of function 'devm_pm_opp_set_clkname'; did you mean 'dev_pm_opp_set_clkname'? [-Werror=implicit-function-declaration]
123 | opp_table = devm_pm_opp_set_clkname(dev, NULL);
| ^~~~~~~~~~~~~~~~~~~~~~~
| dev_pm_opp_set_clkname
drivers/soc/tegra/common.c:123:12: warning: assignment to 'struct opp_table *' from 'int' makes pointer from integer without a cast [-Wint-conversion]
123 | opp_table = devm_pm_opp_set_clkname(dev, NULL);
| ^
>> drivers/soc/tegra/common.c:139:14: error: implicit declaration of function 'devm_pm_opp_set_supported_hw'; did you mean 'dev_pm_opp_set_supported_hw'? [-Werror=implicit-function-declaration]
139 | opp_table = devm_pm_opp_set_supported_hw(dev, &hw_version, 1);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
| dev_pm_opp_set_supported_hw
drivers/soc/tegra/common.c:139:12: warning: assignment to 'struct opp_table *' from 'int' makes pointer from integer without a cast [-Wint-conversion]
139 | opp_table = devm_pm_opp_set_supported_hw(dev, &hw_version, 1);
| ^
>> drivers/soc/tegra/common.c:153:8: error: implicit declaration of function 'devm_pm_opp_of_add_table'; did you mean 'dev_pm_opp_of_add_table'? [-Werror=implicit-function-declaration]
153 | err = devm_pm_opp_of_add_table(dev);
| ^~~~~~~~~~~~~~~~~~~~~~~~
| dev_pm_opp_of_add_tablecc1: some warnings being treated as errors
vim +123 drivers/soc/tegra/common.c
105
106 /**
107 * devm_tegra_core_dev_init_opp_table() - initialize OPP table
108 * @dev: device for which OPP table is initialized
109 * @params: pointer to the OPP table configuration
110 *
111 * This function will initialize OPP table and sync OPP state of a Tegra SoC
112 * core device.
113 *
114 * Return: 0 on success or errorno.
115 */
116 int devm_tegra_core_dev_init_opp_table(struct device *dev,
117 struct tegra_core_opp_params *params)
118 {
119 struct opp_table *opp_table;
120 u32 hw_version;
121 int err;
122
> 123 opp_table = devm_pm_opp_set_clkname(dev, NULL);
124 if (IS_ERR(opp_table)) {
125 dev_err(dev, "failed to set OPP clk %pe\n", opp_table);
126 return PTR_ERR(opp_table);
127 }
128
129 /* Tegra114+ doesn't support OPP yet */
130 if (!of_machine_is_compatible("nvidia,tegra20") &&
131 !of_machine_is_compatible("nvidia,tegra30"))
132 return -ENODEV;
133
134 if (of_machine_is_compatible("nvidia,tegra20"))
135 hw_version = BIT(tegra_sku_info.soc_process_id);
136 else
137 hw_version = BIT(tegra_sku_info.soc_speedo_id);
138
> 139 opp_table = devm_pm_opp_set_supported_hw(dev, &hw_version, 1);
140 if (IS_ERR(opp_table)) {
141 dev_err(dev, "failed to set OPP supported HW: %pe\n", opp_table);
142 return PTR_ERR(opp_table);
143 }
144
145 /*
146 * Older device-trees have an empty OPP table, hence we will get
147 * -ENODEV from devm_pm_opp_of_add_table() for the older DTBs.
148 *
149 * The OPP table presence also varies per-device and depending
150 * on a SoC generation, hence -ENODEV is expected to happen for
151 * the newer DTs as well.
152 */
> 153 err = devm_pm_opp_of_add_table(dev);---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org
PATCH v3 2/6 soc/tegra: Add CONFIG_SOC_TEGRA_COMMON and select PM_OPP by default
In reply to Dmitry OsipenkoAdd new Kconfig SOC_TEGRA_COMMON option which selects configuration options that are common for all Tegra SoCs. Select PM_OPP by default since from now on OPPs will be used by Tegra drivers which present on all SoC generations, like display controller driver for example.
--- drivers/soc/tegra/Kconfig | 13 +++++++++++++ 1 file changed, 13 insertions(+)
drivers/soc/tegra/Kconfig +13 -0
@@ -13,6 +13,7 @@ config ARCH_TEGRA_2x_SOC select PINCTRL_TEGRA20 select PL310_ERRATA_727915 if CACHE_L2X0 select PL310_ERRATA_769419 if CACHE_L2X0 + select SOC_TEGRA_COMMON select SOC_TEGRA_FLOWCTRL select SOC_TEGRA_PMC select SOC_TEGRA20_VOLTAGE_COUPLER
@@ -27,6 +28,7 @@ config ARCH_TEGRA_3x_SOC select ARM_ERRATA_764369 if SMP select PINCTRL_TEGRA30 select PL310_ERRATA_769419 if CACHE_L2X0 + select SOC_TEGRA_COMMON select SOC_TEGRA_FLOWCTRL select SOC_TEGRA_PMC select SOC_TEGRA30_VOLTAGE_COUPLER
@@ -40,6 +42,7 @@ config ARCH_TEGRA_114_SOC select ARM_ERRATA_798181 if SMP select HAVE_ARM_ARCH_TIMER select PINCTRL_TEGRA114 + select SOC_TEGRA_COMMON select SOC_TEGRA_FLOWCTRL select SOC_TEGRA_PMC select TEGRA_TIMER
@@ -51,6 +54,7 @@ config ARCH_TEGRA_124_SOC bool "Enable support for Tegra124 family" select HAVE_ARM_ARCH_TIMER select PINCTRL_TEGRA124 + select SOC_TEGRA_COMMON select SOC_TEGRA_FLOWCTRL select SOC_TEGRA_PMC select TEGRA_TIMER
@@ -66,6 +70,7 @@ if ARM64 config ARCH_TEGRA_132_SOC bool "NVIDIA Tegra132 SoC" select PINCTRL_TEGRA124 + select SOC_TEGRA_COMMON select SOC_TEGRA_FLOWCTRL select SOC_TEGRA_PMC help
@@ -77,6 +82,7 @@ config ARCH_TEGRA_132_SOC config ARCH_TEGRA_210_SOC bool "NVIDIA Tegra210 SoC" select PINCTRL_TEGRA210 + select SOC_TEGRA_COMMON select SOC_TEGRA_FLOWCTRL select SOC_TEGRA_PMC select TEGRA_TIMER
@@ -99,6 +105,7 @@ config ARCH_TEGRA_186_SOC select TEGRA_BPMP select TEGRA_HSP_MBOX select TEGRA_IVC + select SOC_TEGRA_COMMON select SOC_TEGRA_PMC help Enable support for the NVIDIA Tegar186 SoC. The Tegra186 features a
@@ -115,6 +122,7 @@ config ARCH_TEGRA_194_SOC select TEGRA_BPMP select TEGRA_HSP_MBOX select TEGRA_IVC + select SOC_TEGRA_COMMON select SOC_TEGRA_PMC help Enable support for the NVIDIA Tegra194 SoC.
@@ -125,6 +133,7 @@ config ARCH_TEGRA_234_SOC select TEGRA_BPMP select TEGRA_HSP_MBOX select TEGRA_IVC + select SOC_TEGRA_COMMON select SOC_TEGRA_PMC help Enable support for the NVIDIA Tegra234 SoC.
@@ -132,6 +141,10 @@ config ARCH_TEGRA_234_SOC endif endif +config SOC_TEGRA_COMMON + bool + select PM_OPP + config SOC_TEGRA_FUSE def_bool y depends on ARCH_TEGRA
Signature · 1 line
2.29.2
PATCH v3 3/6 dt-bindings: power: tegra: Add binding for core power domain
In reply to Dmitry OsipenkoAll NVIDIA Tegra SoCs have a core power domain where majority of hardware blocks reside. Add binding for the core power domain.
--- .../power/nvidia,tegra20-core-domain.yaml | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 Documentation/devicetree/bindings/power/nvidia,tegra20-core-domain.yaml
Documentation/devicetree/bindings/power/nvidia,tegra20-core-domain.yaml new file +52 -0
@@ -0,0 +1,52 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/power/nvidia,tegra20-core-domain.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NVIDIA Tegra Core Power Domain + +maintainers: + - Dmitry Osipenko <[email protected]> + - Jon Hunter <[email protected]> + - Thierry Reding <[email protected]> + +allOf: + - $ref: power-domain.yaml# + +properties: + compatible: + enum: + - nvidia,tegra20-core-domain + - nvidia,tegra30-core-domain + + operating-points-v2: + description: + Should contain level, voltages and opp-supported-hw property. + The supported-hw is a bitfield indicating SoC speedo or process + ID mask. + + "#power-domain-cells": + const: 0 + + power-supply: + $ref: /schemas/types.yaml#/definitions/phandle + description: + Phandle to voltage regulator connected to the SoC Core power rail. + +required: + - compatible + - operating-points-v2 + - "#power-domain-cells" + - power-supply + +additionalProperties: false + +examples: + - | + power-domain { + compatible = "nvidia,tegra20-core-domain"; + operating-points-v2 = <&opp_table>; + power-supply = <®ulator>; + #power-domain-cells = <0>; + };
Signature · 1 line
2.29.2
Rob Herring
maintainerRe: [PATCH v3 3/6] dt-bindings: power: tegra: Add binding for core power domain
Quoted 9 lines · Dmitry Osipenko
All NVIDIA Tegra SoCs have a core power domain where majority of hardware blocks reside. Add binding for the core power domain.
Signed-off-by Dmitry Osipenko <[email protected]>--- .../power/nvidia,tegra20-core-domain.yaml | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 Documentation/devicetree/bindings/power/nvidia,tegra20-core-domain.yaml
My bot found errors running 'make dt_binding_check' on your patch:
yamllint warnings/errors:
dtschema/dtc warnings/errors:
/builds/robherring/linux-dt-review/Documentation/devicetree/bindings/power/nvidia,tegra20-core-domain.yaml: properties:power-supply: '$ref' is not one of ['description', 'deprecated'] /builds/robherring/linux-dt-review/Documentation/devicetree/bindings/power/nvidia,tegra20-core-domain.yaml: ignoring, error in schema: properties: power-supply
warning: no schema found in file: ./Documentation/devicetree/bindings/power/nvidia,tegra20-core-domain.yaml
See https://patchwork.ozlabs.org/patch/1451596
This check can fail if there are any dependencies. The base for a patch series is generally the most recent rc1.
If you already ran 'make dt_binding_check' and didn't see the above error(s), then make sure 'yamllint' is installed and dt-schema is up to date:
pip3 install dtschema --upgrade
Please check and re-submit.
PATCH v3 4/6 soc/tegra: Introduce core power domain driver
In reply to Dmitry OsipenkoNVIDIA Tegra SoCs have multiple power domains, each domain corresponds to an external SoC power rail. Core power domain covers vast majority of hardware blocks within a Tegra SoC. The voltage of a power domain should be set to a value which satisfies all devices within a power domain. Add driver for the core power domain which manages the voltage state of the domain. This allows us to support a system-wide DVFS on Tegra.
--- drivers/soc/tegra/Kconfig | 6 + drivers/soc/tegra/Makefile | 1 + drivers/soc/tegra/core-power-domain.c | 154 ++++++++++++++++++++++++++ include/soc/tegra/common.h | 6 + 4 files changed, 167 insertions(+) create mode 100644 drivers/soc/tegra/core-power-domain.c
drivers/soc/tegra/Kconfig +6 -0
@@ -16,6 +16,7 @@ config ARCH_TEGRA_2x_SOC select SOC_TEGRA_COMMON select SOC_TEGRA_FLOWCTRL select SOC_TEGRA_PMC + select SOC_TEGRA_CORE_POWER_DOMAIN select SOC_TEGRA20_VOLTAGE_COUPLER select TEGRA_TIMER help
@@ -31,6 +32,7 @@ config ARCH_TEGRA_3x_SOC select SOC_TEGRA_COMMON select SOC_TEGRA_FLOWCTRL select SOC_TEGRA_PMC + select SOC_TEGRA_CORE_POWER_DOMAIN select SOC_TEGRA30_VOLTAGE_COUPLER select TEGRA_TIMER help
@@ -170,3 +172,7 @@ config SOC_TEGRA20_VOLTAGE_COUPLER config SOC_TEGRA30_VOLTAGE_COUPLER bool "Voltage scaling support for Tegra30 SoCs" depends on ARCH_TEGRA_3x_SOC || COMPILE_TEST + +config SOC_TEGRA_CORE_POWER_DOMAIN + bool + select PM_GENERIC_DOMAINS
drivers/soc/tegra/Makefile +1 -0
@@ -7,3 +7,4 @@ obj-$(CONFIG_SOC_TEGRA_PMC) += pmc.o obj-$(CONFIG_SOC_TEGRA_POWERGATE_BPMP) += powergate-bpmp.o obj-$(CONFIG_SOC_TEGRA20_VOLTAGE_COUPLER) += regulators-tegra20.o obj-$(CONFIG_SOC_TEGRA30_VOLTAGE_COUPLER) += regulators-tegra30.o +obj-$(CONFIG_SOC_TEGRA_CORE_POWER_DOMAIN) += core-power-domain.o
drivers/soc/tegra/core-power-domain.c new file +154 -0
154 lines not on this page · raw message
include/soc/tegra/common.h +6 -0
@@ -22,6 +22,7 @@ struct tegra_core_opp_params {#ifdef CONFIG_ARCH_TEGRA bool soc_is_tegra (void ); +bool tegra_soc_core_domain_state_synced (void );int devm_tegra_core_dev_init_opp_table (struct device *dev,struct tegra_core_opp_params *params);#else
@@ -30,6 +31,11 @@ static inline bool soc_is_tegra(void)return false; } +static inline bool tegra_soc_core_domain_state_synced (void ) +{ +return false; +} +static inline int devm_tegra_core_dev_init_opp_table (struct device *dev,struct tegra_core_opp_params *params)
Signature · 1 line
2.29.2
kernel test robot
build botRe: [PATCH v3 4/6] soc/tegra: Introduce core power domain driver
I love your patch! Perhaps something to improve:
Hi Dmitry,
I love your patch! Perhaps something to improve:
[auto build test WARNING on tegra/for-next]
[also build test WARNING on v5.12-rc2 next-20210311]
[If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]
url: https://github.com/0day-ci/linux/commits/Dmitry-Osipenko/soc-tegra-Add-devm_tegra_core_dev_init_opp_table/20210312-081244 base: https://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux.git for-next config: arm-defconfig (attached as .config) compiler: arm-linux-gnueabi-gcc (GCC) 9.3.0
reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross
# https://github.com/0day-ci/linux/commit/5ff989fef87fd532be096fb0c86f7f866655f34c
git remote add linux-review https://github.com/0day-ci/linux
git fetch --no-tags linux-review Dmitry-Osipenko/soc-tegra-Add-devm_tegra_core_dev_init_opp_table/20210312-081244 git checkout 5ff989fef87fd532be096fb0c86f7f866655f34c
# save the attached .config to linux build tree
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross ARCH=arm
If you fix the issue, kindly add following tag as appropriate
All warnings (new ones prefixed by >>):
drivers/soc/tegra/core-power-domain.c: In function 'tegra_genpd_set_performance_state':
drivers/soc/tegra/core-power-domain.c:30:8: error: implicit declaration of function 'dev_pm_opp_find_level_ceil'; did you mean 'dev_pm_opp_find_freq_ceil'? [-Werror=implicit-function-declaration]
30 | opp = dev_pm_opp_find_level_ceil(&genpd->dev, &level);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~
| dev_pm_opp_find_freq_ceil
>> drivers/soc/tegra/core-power-domain.c:30:6: warning: assignment to 'struct dev_pm_opp *' from 'int' makes pointer from integer without a cast [-Wint-conversion]
30 | opp = dev_pm_opp_find_level_ceil(&genpd->dev, &level);
| ^
drivers/soc/tegra/core-power-domain.c:38:8: error: implicit declaration of function 'dev_pm_opp_set_opp'; did you mean 'dev_pm_opp_set_bw'? [-Werror=implicit-function-declaration]
38 | err = dev_pm_opp_set_opp(&genpd->dev, opp);
| ^~~~~~~~~~~~~~~~~~
| dev_pm_opp_set_bw
drivers/soc/tegra/core-power-domain.c: In function 'tegra_core_domain_probe':
drivers/soc/tegra/core-power-domain.c:74:14: error: implicit declaration of function 'devm_pm_opp_set_regulators'; did you mean 'dev_pm_opp_set_regulators'? [-Werror=implicit-function-declaration]
74 | opp_table = devm_pm_opp_set_regulators(&pdev->dev, &rname, 1);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~
| dev_pm_opp_set_regulators
>> drivers/soc/tegra/core-power-domain.c:74:12: warning: assignment to 'struct opp_table *' from 'int' makes pointer from integer without a cast [-Wint-conversion]
74 | opp_table = devm_pm_opp_set_regulators(&pdev->dev, &rname, 1);
| ^
drivers/soc/tegra/core-power-domain.c: In function 'tegra_core_domain_set_synced':
drivers/soc/tegra/core-power-domain.c:115:8: error: implicit declaration of function 'dev_pm_opp_sync_regulators'; did you mean 'dev_pm_opp_set_regulators'? [-Werror=implicit-function-declaration]
115 | err = dev_pm_opp_sync_regulators(dev);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~
| dev_pm_opp_set_regulatorscc1: some warnings being treated as errors
vim +30 drivers/soc/tegra/core-power-domain.c
23
24 static int tegra_genpd_set_performance_state(struct generic_pm_domain *genpd,
25 unsigned int level)
26 {
27 struct dev_pm_opp *opp;
28 int err;
29
> 30 opp = dev_pm_opp_find_level_ceil(&genpd->dev, &level);
31 if (IS_ERR(opp)) {
32 dev_err(&genpd->dev, "failed to find OPP for level %u: %pe\n",
33 level, opp);
34 return PTR_ERR(opp);
35 }
36
37 mutex_lock(&tegra_core_lock);
38 err = dev_pm_opp_set_opp(&genpd->dev, opp);
39 mutex_unlock(&tegra_core_lock);
40
41 dev_pm_opp_put(opp);
42
43 if (err) {
44 dev_err(&genpd->dev, "failed to set voltage to %duV: %d\n",
45 level, err);
46 return err;
47 }
48
49 return 0;
50 }
51
52 static unsigned int
53 tegra_genpd_opp_to_performance_state(struct generic_pm_domain *genpd,
54 struct dev_pm_opp *opp)
55 {
56 return dev_pm_opp_get_level(opp);
57 }
58
59 static int tegra_core_domain_probe(struct platform_device *pdev)
60 {
61 struct generic_pm_domain *genpd;
62 struct opp_table *opp_table;
63 const char *rname = "power";
64 int err;
65
66 genpd = devm_kzalloc(&pdev->dev, sizeof(*genpd), GFP_KERNEL);
67 if (!genpd)
68 return -ENOMEM;
69
70 genpd->name = pdev->dev.of_node->name;
71 genpd->set_performance_state = tegra_genpd_set_performance_state;
72 genpd->opp_to_performance_state = tegra_genpd_opp_to_performance_state;
73
> 74 opp_table = devm_pm_opp_set_regulators(&pdev->dev, &rname, 1);
75 if (IS_ERR(opp_table))
76 return dev_err_probe(&pdev->dev, PTR_ERR(opp_table),
77 "failed to set OPP regulator\n");
78
79 err = pm_genpd_init(genpd, NULL, false);
80 if (err) {
81 dev_err(&pdev->dev, "failed to init genpd: %d\n", err);
82 return err;
83 }
84
85 /*
86 * We have a "PMC -> Core" hierarchy of the power domains where
87 * PMC needs to resume and change performance (voltage) of the
88 * Core domain from the PMC GENPD on/off callbacks, hence we need
89 * to annotate the lock in order to remove confusion from the
90 * lockdep checker when a nested access happens.
91 */
92 lockdep_set_class(&genpd->mlock, &tegra_core_domain_lock_class);
93
94 err = of_genpd_add_provider_simple(pdev->dev.of_node, genpd);
95 if (err) {
96 dev_err(&pdev->dev, "failed to add genpd: %d\n", err);
97 goto remove_genpd;
98 }
99 100 return 0;
101
102 remove_genpd:
103 pm_genpd_remove(genpd);
104
105 return err;
106 }
107
---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org
Re: [PATCH v3 4/6] soc/tegra: Introduce core power domain driver
12.03.2021 07:00, kernel test robot пишет:
Quoted 30 lines
[auto build test WARNING on tegra/for-next]
[also build test WARNING on v5.12-rc2 next-20210311]
[If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]url: https://github.com/0day-ci/linux/commits/Dmitry-Osipenko/soc-tegra-Add-devm_tegra_core_dev_init_opp_table/20210312-081244 base: https://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux.git for-next config: arm-defconfig (attached as .config) compiler: arm-linux-gnueabi-gcc (GCC) 9.3.0reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross
# https://github.com/0day-ci/linux/commit/5ff989fef87fd532be096fb0c86f7f866655f34c
git remote add linux-review https://github.com/0day-ci/linux
git fetch --no-tags linux-review Dmitry-Osipenko/soc-tegra-Add-devm_tegra_core_dev_init_opp_table/20210312-081244 git checkout5ff989fef87fd532be096fb0c86f7f866655f34c
# save the attached .config to linux build tree
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross ARCH=armIf you fix the issue, kindly add following tag as appropriate
Reported-by kernel test robot <[email protected]>All warnings (new ones prefixed by >>):
drivers/soc/tegra/core-power-domain.c: In function 'tegra_genpd_set_performance_state':drivers/soc/tegra/core-power-domain.c:30:8: error: implicit declaration of function 'dev_pm_opp_find_level_ceil'; did you mean 'dev_pm_opp_find_freq_ceil'? [-Werror=implicit-function-declaration] 30 | opp = dev_pm_opp_find_level_ceil(&genpd->dev, &level); | ^~~~~~~~~~~~~~~~~~~~~~~~~~ | dev_pm_opp_find_freq_ceil
Quoted 7 lines
Quoted 1 line
Quoted 1 line
drivers/soc/tegra/core-power-domain.c:30:6: warning: assignment to 'structdev_pm_opp*' from 'int' makes pointer from integer without a cast [-Wint-conversion]30 | opp = dev_pm_opp_find_level_ceil(&genpd->dev, &level); | ^ drivers/soc/tegra/core-power-domain.c:38:8: error: implicit declaration of function 'dev_pm_opp_set_opp'; did you mean 'dev_pm_opp_set_bw'? [-Werror=implicit-function-declaration] 38 | err = dev_pm_opp_set_opp(&genpd->dev, opp); | ^~~~~~~~~~~~~~~~~~ | dev_pm_opp_set_bw
The dev_pm_opp_find_level_ceil() and dev_pm_opp_set_opp() present in both v5.12-rc2 and next-20210311, but not in tegra/for-next.
Thierry, will be great if you could keep the for-next up-to-date a bit more proactively. Will be also great if you could pick up all the current patches that are good to you from the ML into the -next, thanks in advance.
PATCH v3 5/6 soc/tegra: regulators: Support Core domain state syncing
In reply to Dmitry OsipenkoThe core voltage shall not drop until state of Core domain is synced, i.e. all device drivers that use Core domain are loaded and ready.
Support Core domain state syncing. The Core domain driver invokes the core-regulator voltage syncing once the state of domain is synced, at this point the Core voltage is allowed to go lower than the level left after bootloader.
--- drivers/soc/tegra/regulators-tegra20.c | 19 ++++++++++++++++++- drivers/soc/tegra/regulators-tegra30.c | 18 +++++++++++++++++- 2 files changed, 35 insertions(+), 2 deletions(-)
drivers/soc/tegra/regulators-tegra20.c +18 -1
@@ -16,6 +16,8 @@#include <linux/regulator/driver.h> #include <linux/regulator/machine.h> +#include <soc/tegra/common.h> +struct tegra_regulator_coupler {struct regulator_coupler coupler;struct regulator_dev *core_rdev;
@@ -38,6 +40,21 @@ static int tegra20_core_limit(struct tegra_regulator_coupler *tegra,int core_cur_uV;int err; +/* +* Tegra20 SoC has critical DVFS-capable devices that are +* permanently-active or active at a boot time, like EMC +* (DRAM controller) or Display controller for example. +* +* The voltage of a CORE SoC power domain shall not be dropped below +* a minimum level, which is determined by device's clock rate. +* This means that we can't fully allow CORE voltage scaling until +* the state of all DVFS-critical CORE devices is synced. +*/ +if (tegra_soc_core_domain_state_synced ()) { +pr_info_once ("voltage state synced\n" ); +return 0 ; + } +if (tegra->core_min_uV >0 )return tegra->core_min_uV;
@@ -58,7 +75,7 @@ static int tegra20_core_limit(struct tegra_regulator_coupler *tegra,*/ tegra->core_min_uV = core_max_uV; -pr_info ("core minimum voltage limited to %duV\n" , tegra->core_min_uV); +pr_info ("core voltage initialized to %duV\n" , tegra->core_min_uV);return tegra->core_min_uV; }
drivers/soc/tegra/regulators-tegra30.c +17 -1
@@ -16,6 +16,7 @@#include <linux/regulator/driver.h> #include <linux/regulator/machine.h> +#include <soc/tegra/common.h> #include <soc/tegra/fuse.h> struct tegra_regulator_coupler {
@@ -39,6 +40,21 @@ static int tegra30_core_limit(struct tegra_regulator_coupler *tegra,int core_cur_uV;int err; +/* +* Tegra30 SoC has critical DVFS-capable devices that are +* permanently-active or active at a boot time, like EMC +* (DRAM controller) or Display controller for example. +* +* The voltage of a CORE SoC power domain shall not be dropped below +* a minimum level, which is determined by device's clock rate. +* This means that we can't fully allow CORE voltage scaling until +* the state of all DVFS-critical CORE devices is synced. +*/ +if (tegra_soc_core_domain_state_synced ()) { +pr_info_once ("voltage state synced\n" ); +return 0 ; + } +if (tegra->core_min_uV >0 )return tegra->core_min_uV;
@@ -59,7 +75,7 @@ static int tegra30_core_limit(struct tegra_regulator_coupler *tegra,*/ tegra->core_min_uV = core_max_uV; -pr_info ("core minimum voltage limited to %duV\n" , tegra->core_min_uV); +pr_info ("core voltage initialized to %duV\n" , tegra->core_min_uV);return tegra->core_min_uV; }
Signature · 1 line
2.29.2
PATCH v3 6/6 soc/tegra: pmc: Link children power domains to the parent domain
In reply to Dmitry OsipenkoThe Core domain is a parent of PMC power domains, hence PMC domains should be set up as a sub-domains of the parent (Core) domain if "power-domains" phandle presents in a device-tree node of PMC domain.
This allows to propagate GENPD performance changes to the parent Core domain if performance change is applied to a PMC domain.
--- drivers/soc/tegra/pmc.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+)
drivers/soc/tegra/pmc.c +16 -0
@@ -1283,6 +1283,7 @@ static int tegra_powergate_add(struct tegra_pmc *pmc, struct device_node *np)static int tegra_powergate_init (struct tegra_pmc *pmc,struct device_node *parent) { +struct of_phandle_args child_args, parent_args;struct device_node *np, *child;int err =0 ;
@@ -1296,6 +1297,21 @@ static int tegra_powergate_init(struct tegra_pmc *pmc,of_node_put (child);break ; } + +if (of_parse_phandle_with_args (child,"power-domains" , +"#power-domain-cells" , +0 , &parent_args)) +continue ; + + child_args.np = child; + child_args.args_count =0 ; + + err =of_genpd_add_subdomain (&parent_args, &child_args); +of_node_put (parent_args.np); +if (err) { +of_node_put (child); +break ; + } }of_node_put (np);
Signature · 1 line
2.29.2