Introduce core voltage scaling for NVIDIA Tegra20/30 SoCs
Subsystems (16)
v2 cover Introduce core voltage scaling for NVIDIA Tegra20/30 SoCs
Introduce core voltage scaling for NVIDIA Tegra20/30 SoCs, which reduces power consumption and heating of the Tegra chips. Tegra SoC has multiple hardware units which belong to a core power domain of the SoC and share the core voltage. The voltage must be selected in accordance to a minimum requirement of every core hardware unit.
The minimum core voltage requirement depends on:
1. Clock enable state of a hardware unit.
2. Clock frequency.
3. Unit's internal idling/active state.
This series is tested on Acer A500 (T20), AC100 (T20), Nexus 7 (T30), Ouya (T30), TK1 (T124) and some others. I also added voltage scaling to the Ventana (T20) and Cardhu (T30) boards which are tested by NVIDIA's CI farm. Tegra30 is now couple degrees cooler on Nexus 7 and stays cool on Ouya (instead of becoming burning hot) while system is idling. It should be possible to improve this further by implementing a more advanced power management features for the kernel drivers.
The DVFS support is opt-in for all boards, meaning that older DTBs will continue to work like they did it before this series. It should be possible to easily add the core voltage scaling support for Tegra114+ SoCs based on this grounding work later on, if anyone will want to implement it.
Changelog:
v2: - Replaced Core voltage regulator with a Core power domain. The voltage
control is now done using GENPD API. This was suggested by Ulf Hansson.
- Added basic runtime PM and GENPD support to 2d, 3d, host1x and clk drivers.
- Added new core-power-domain and clk-device drivers. Some high-freq PLLs and clocks require a higher minimum core voltage and the new clk-device driver manages the voltage for these clocks based on the clock state.
- Moved voltage scaling entirely to the new clk-device driver for devices which don't require advanced power management, like PWM for example.
- Added devm_tegra_core_dev_init_opp_table() common helper which sets up OPP table for Tegra drivers.
- Added resource-managed version for OPP API functions, as it was discussed previously in the comments to v1.
- Added new APIs, features and fixed various bugs related to voltage scaling and power management done via GENPD API.
Dmitry Osipenko (48):
dt-bindings: memory: tegra20: emc: Replace core regulator with power
domain
dt-bindings: memory: tegra30: emc: Replace core regulator with power
domain
dt-bindings: memory: tegra124: emc: Replace core regulator with power
domain
dt-bindings: host1x: Document OPP and power domain properties
media: dt: bindings: tegra-vde: Document OPP and power domain
properties
dt-bindings: clock: tegra: Document clocks sub-node
dt-bindings: arm: tegra: Add binding for core power domain
regulator: Make regulator_sync_voltage() usable by coupled regulators
opp: Add dev_pm_opp_sync_regulators()
opp: Add dev_pm_opp_set_voltage()
opp: Add dev_pm_opp_find_level_ceil()
opp: Add dev_pm_opp_get_required_pstate()
opp: Add resource-managed versions of OPP API functions
opp: Filter out OPPs based on availability of a required-OPP
opp: Support set_opp() customization without requiring to use
regulators
opp: Handle missing OPP table in dev_pm_opp_xlate_performance_state()
opp: Correct debug message in _opp_add_static_v2()
opp: Print OPP level in debug message of _opp_add_static_v2()
opp: Fix adding OPP entries in a wrong order if rate is unavailable
PM: domains: Make set_performance_state() callback optional
PM: domains: Add "performance" column to debug summary soc/tegra: pmc: Fix imbalanced clock disabling in error code path soc/tegra: pmc: Pulse resets after removing power clamp soc/tegra: pmc: Ensure that clock rates aren't too high soc/tegra: pmc: Print out domain name when reset fails to acquire soc/tegra: Add devm_tegra_core_dev_init_opp_table() soc/tegra: Add CONFIG_SOC_TEGRA_COMMON and select PM_OPP by default soc/tegra: Introduce core power domain driver
soc/tegra: pmc: Link domains to the parent Core domain soc/tegra: regulators: Fix locking up when voltage-spread is out of
range
soc/tegra: regulators: Support Core domain state syncing
clk: tegra: Support runtime PM, power domain and OPP
gpu: host1x: Add host1x_channel_stop()
gpu: host1x: Support power management
drm/tegra: dc: Support OPP and SoC core voltage scaling drm/tegra: gr2d: Correct swapped device-tree compatibles drm/tegra: gr2d: Support OPP and power management drm/tegra: g3d: Support OPP and power management drm/tegra: vic: Stop channel before suspending
media: staging: tegra-vde: Support OPP and generic power domain
memory: tegra20-emc: Use devm_tegra_core_dev_init_opp_table()
memory: tegra30-emc: Use devm_tegra_core_dev_init_opp_table()
ARM: tegra: Add OPP tables and power domains to Tegra20 device-tree
ARM: tegra: Add OPP tables and power domains to Tegra30 device-tree
ARM: tegra: acer-a500: Enable core voltage scaling
ARM: tegra: ventana: Enable core voltage scaling
ARM: tegra: ventana: Support CPU voltage scaling and thermal
throttling
ARM: tegra: cardhu: Support CPU voltage scaling and thermal throttling
.../arm/tegra/nvidia,tegra20-core-domain.yaml | 48 + .../bindings/clock/nvidia,tegra20-car.txt | 26 + .../bindings/clock/nvidia,tegra30-car.txt | 26 + .../display/tegra/nvidia,tegra20-host1x.txt | 49 + .../bindings/media/nvidia,tegra-vde.txt | 12 + .../nvidia,tegra124-emc.yaml | 6 +- .../memory-controllers/nvidia,tegra20-emc.txt | 4 +- .../nvidia,tegra30-emc.yaml | 6 +- .../boot/dts/tegra20-acer-a500-picasso.dts | 8 +- arch/arm/boot/dts/tegra20-colibri.dtsi | 6 +- arch/arm/boot/dts/tegra20-harmony.dts | 6 +- arch/arm/boot/dts/tegra20-paz00.dts | 46 +- .../arm/boot/dts/tegra20-peripherals-opp.dtsi | 941 +++++++++++ arch/arm/boot/dts/tegra20-seaboard.dts | 6 +- arch/arm/boot/dts/tegra20-tamonten.dtsi | 6 +- arch/arm/boot/dts/tegra20-trimslice.dts | 12 + arch/arm/boot/dts/tegra20-ventana.dts | 78 +- arch/arm/boot/dts/tegra20.dtsi | 220 +++ .../tegra30-asus-nexus7-grouper-common.dtsi | 4 + arch/arm/boot/dts/tegra30-beaver.dts | 4 + arch/arm/boot/dts/tegra30-cardhu.dtsi | 81 +- arch/arm/boot/dts/tegra30-colibri.dtsi | 20 +- arch/arm/boot/dts/tegra30-ouya.dts | 4 + .../arm/boot/dts/tegra30-peripherals-opp.dtsi | 1412 +++++++++++++++++ arch/arm/boot/dts/tegra30.dtsi | 358 +++++ drivers/base/power/domain.c | 33 +- drivers/clk/tegra/Makefile | 1 + drivers/clk/tegra/clk-device.c | 222 +++ drivers/clk/tegra/clk-divider.c | 2 +- drivers/clk/tegra/clk-periph-gate.c | 2 +- drivers/clk/tegra/clk-periph.c | 2 +- drivers/clk/tegra/clk-pll.c | 2 +- drivers/clk/tegra/clk-super.c | 4 +- drivers/clk/tegra/clk-tegra-periph.c | 140 +- drivers/clk/tegra/clk-tegra114.c | 1 + drivers/clk/tegra/clk-tegra124.c | 1 + drivers/clk/tegra/clk-tegra20-emc.c | 2 +- drivers/clk/tegra/clk-tegra20.c | 123 +- drivers/clk/tegra/clk-tegra210.c | 1 + drivers/clk/tegra/clk-tegra30.c | 133 +- drivers/clk/tegra/clk.c | 89 ++ drivers/clk/tegra/clk.h | 7 + drivers/gpu/drm/tegra/dc.c | 66 +- drivers/gpu/drm/tegra/gr2d.c | 77 +- drivers/gpu/drm/tegra/gr3d.c | 264 ++- drivers/gpu/drm/tegra/vic.c | 15 + drivers/gpu/host1x/channel.c | 8 + drivers/gpu/host1x/dev.c | 102 +- drivers/memory/tegra/tegra20-emc.c | 57 +- drivers/memory/tegra/tegra30-emc.c | 57 +- drivers/opp/core.c | 390 ++++- drivers/opp/of.c | 34 +- drivers/opp/opp.h | 2 +- drivers/regulator/core.c | 6 + drivers/soc/tegra/Kconfig | 19 + drivers/soc/tegra/Makefile | 1 + drivers/soc/tegra/common.c | 137 ++ drivers/soc/tegra/core-power-domain.c | 125 ++ drivers/soc/tegra/pmc.c | 122 +- drivers/soc/tegra/regulators-tegra20.c | 19 +- drivers/soc/tegra/regulators-tegra30.c | 20 +- drivers/staging/media/tegra-vde/vde.c | 63 +- include/linux/host1x.h | 1 + include/linux/pm_opp.h | 81 + include/soc/tegra/common.h | 41 + 65 files changed, 5458 insertions(+), 403 deletions(-) create mode 100644 Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-core-domain.yaml create mode 100644 drivers/clk/tegra/clk-device.c create mode 100644 drivers/soc/tegra/core-power-domain.c
Signature · 1 line
2.29.2
PATCH v2 1/48 dt-bindings: memory: tegra20: emc: Replace core regulator with power domain
Power domain fits much better than a voltage regulator in regards to a proper hardware description and from a software perspective as well. Hence replace the core regulator with the power domain. Note that this doesn't affect any existing DTBs because we haven't started to use the regulator yet, and thus, it's okay to change it.
--- .../bindings/memory-controllers/nvidia,tegra20-emc.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
Documentation/devicetree/bindings/memory-controllers/nvidia,tegra20-emc.txt +2 -2
@@ -23,7 +23,7 @@ For each opp entry in 'operating-points-v2' table: matches, the OPP gets enabled. Optional properties: -- core-supply: Phandle of voltage regulator of the SoC "core" power domain. +- power-domains: Phandle to the SoC "core" power domain. Child device nodes describe the memory settings for different configurations and clock rates.
@@ -48,7 +48,7 @@ Example: interrupts = <0 78 0x04>; clocks = <&tegra_car TEGRA20_CLK_EMC>; nvidia,memory-controller = <&mc>; - core-supply = <&core_vdd_reg>; + power-domains = <&domain>; operating-points-v2 = <&opp_table>; }
Signature · 1 line
2.29.2
Re: [PATCH v2 01/48] dt-bindings: memory: tegra20: emc: Replace core regulator with power domain
Quoted 11 lines · Dmitry Osipenko
Power domain fits much better than a voltage regulator in regards to a proper hardware description and from a software perspective as well. Hence replace the core regulator with the power domain. Note that this doesn't affect any existing DTBs because we haven't started to use the regulator yet, and thus, it's okay to change it.
Signed-off-by Dmitry Osipenko <[email protected]>--- .../bindings/memory-controllers/nvidia,tegra20-emc.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel
PATCH v2 2/48 dt-bindings: memory: tegra30: emc: Replace core regulator with power domain
In reply to Dmitry OsipenkoPower domain fits much better than a voltage regulator in regards to a proper hardware description and from a software perspective as well. Hence replace the core regulator with the power domain. Note that this doesn't affect any existing DTBs because we haven't started to use the regulator yet, and thus, it's okay to change it.
--- .../bindings/memory-controllers/nvidia,tegra30-emc.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
Documentation/devicetree/bindings/memory-controllers/nvidia,tegra30-emc.yaml +3 -3
@@ -39,9 +39,9 @@ properties: description: Phandle of the Memory Controller node. - core-supply: + power-domains: description: - Phandle of voltage regulator of the SoC "core" power domain. + Phandle to the SoC "core" power domain. operating-points-v2: description:
@@ -241,7 +241,7 @@ examples: nvidia,memory-controller = <&mc>; operating-points-v2 = <&dvfs_opp_table>; - core-supply = <&vdd_core>; + power-domains = <&domain>; #interconnect-cells = <0>;
Signature · 1 line
2.29.2
Rob Herring
maintainerRe: [PATCH v2 02/48] dt-bindings: memory: tegra30: emc: Replace core regulator with power domain
Quoted 16 lines · Dmitry Osipenko
Power domain fits much better than a voltage regulator in regards to a proper hardware description and from a software perspective as well. Hence replace the core regulator with the power domain. Note that this doesn't affect any existing DTBs because we haven't started to use the regulator yet, and thus, it's okay to change it.
Signed-off-by Dmitry Osipenko <[email protected]>--- .../bindings/memory-controllers/nvidia,tegra30-emc.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)Documentation/devicetree/bindings/memory-controllers/nvidia,tegra30-emc.yaml +0
-0
Documentation/devicetree/bindings/memory-controllers/nvidia,tegra30-emc.yaml properties: · line 44
Quoted 8 lines
Documentation/devicetree/bindings/memory-controllers/nvidia,tegra30-emc.yaml +2
-2@@ -39,9 +39,9 @@ properties: description: Phandle of the Memory Controller node. - core-supply: + power-domains: description: - Phandle of voltage regulator of the SoC "core" power domain. + Phandle to the SoC "core" power domain.
power-domains needs to define how many (maxItems).
Quoted 15 lines
Documentation/devicetree/bindings/memory-controllers/nvidia,tegra30-emc.yaml +1
-1operating-points-v2: description:@@ -241,7 +241,7 @@ examples: nvidia,memory-controller = <&mc>; operating-points-v2 = <&dvfs_opp_table>; - core-supply = <&vdd_core>; + power-domains = <&domain>; #interconnect-cells = <0>;Signature · 1 line
2.29.2
_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel
Re: [PATCH v2 02/48] dt-bindings: memory: tegra30: emc: Replace core regulator with power domain
22.12.2020 01:54, Rob Herring пишет:
Quoted 20 lines · Dmitry Osipenko
Quoted 19 lines
Power domain fits much better than a voltage regulator in regards to a proper hardware description and from a software perspective as well. Hence replace the core regulator with the power domain. Note that this doesn't affect any existing DTBs because we haven't started to use the regulator yet, and thus, it's okay to change it.
Signed-off-by Dmitry Osipenko <[email protected]>--- .../bindings/memory-controllers/nvidia,tegra30-emc.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)Documentation/devicetree/bindings/memory-controllers/nvidia,tegra30-emc.yaml +0
-0@@ -39,9 +39,9 @@ properties: description: Phandle of the Memory Controller node.
Quoted 7 lines
Documentation/devicetree/bindings/memory-controllers/nvidia,tegra30-emc.yaml properties: · line 44
Quoted 5 lines
Documentation/devicetree/bindings/memory-controllers/nvidia,tegra30-emc.yaml +2
-2- core-supply: + power-domains: description: - Phandle of voltage regulator of the SoC "core" power domain. + Phandle to the SoC "core" power domain.power-domains needs to define how many (maxItems).
Okay, thanks.
PATCH v2 3/48 dt-bindings: memory: tegra124: emc: Replace core regulator with power domain
In reply to Dmitry OsipenkoPower domain fits much better than a voltage regulator in regards to a proper hardware description and from a software perspective as well. Hence replace the core regulator with the power domain. Note that this doesn't affect any existing DTBs because we haven't started to use the regulator yet, and thus, it's okay to change it.
--- .../bindings/memory-controllers/nvidia,tegra124-emc.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
Documentation/devicetree/bindings/memory-controllers/nvidia,tegra124-emc.yaml +3 -3
@@ -37,9 +37,9 @@ properties: description: phandle of the memory controller node - core-supply: + power-domains: description: - Phandle of voltage regulator of the SoC "core" power domain. + Phandle to the SoC "core" power domain. operating-points-v2: description:
@@ -370,7 +370,7 @@ examples: nvidia,memory-controller = <&mc>; operating-points-v2 = <&dvfs_opp_table>; - core-supply = <&vdd_core>; + power-domains = <&domain>; #interconnect-cells = <0>;
Signature · 1 line
2.29.2
PATCH v2 4/48 dt-bindings: host1x: Document OPP and power domain properties
In reply to Dmitry OsipenkoDocument new DVFS OPP table and power domain properties of the Host1x bus and devices sitting on the bus.
--- .../display/tegra/nvidia,tegra20-host1x.txt | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+)
Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-host1x.txt +49 -0
@@ -20,6 +20,18 @@ Required properties: - reset-names: Must include the following entries: - host1x +Optional properties: +- operating-points-v2: See ../bindings/opp/opp.txt for details. + - power-domains: Phandle to HEG or core power domain. + +For each opp entry in 'operating-points-v2' table of host1x and its modules: +- opp-supported-hw: One bitfield indicating: + On Tegra20: SoC process ID mask + On Tegra30+: SoC speedo ID mask + + A bitwise AND is performed against the value and if any bit + matches, the OPP gets enabled. + Each host1x client module having to perform DMA through the Memory Controller should have the interconnect endpoints set to the Memory Client and External Memory respectively.
@@ -45,6 +57,8 @@ of the following host1x client modules: - interconnect-names: Must include name of the interconnect path for each interconnect entry. Consult TRM documentation for information about available memory clients, see MEMORY CONTROLLER section. + - operating-points-v2: See ../bindings/opp/opp.txt for details. + - power-domains: Phandle to MPE power domain. - vi: video input
@@ -128,6 +142,8 @@ of the following host1x client modules: - interconnect-names: Must include name of the interconnect path for each interconnect entry. Consult TRM documentation for information about available memory clients, see MEMORY CONTROLLER section. + - operating-points-v2: See ../bindings/opp/opp.txt for details. + - power-domains: Phandle to VENC power domain. - epp: encoder pre-processor
@@ -147,6 +163,8 @@ of the following host1x client modules: - interconnect-names: Must include name of the interconnect path for each interconnect entry. Consult TRM documentation for information about available memory clients, see MEMORY CONTROLLER section. + - operating-points-v2: See ../bindings/opp/opp.txt for details. + - power-domains: Phandle to HEG or core power domain. - isp: image signal processor
@@ -166,6 +184,7 @@ of the following host1x client modules: - interconnect-names: Must include name of the interconnect path for each interconnect entry. Consult TRM documentation for information about available memory clients, see MEMORY CONTROLLER section. + - power-domains: Phandle to VENC or core power domain. - gr2d: 2D graphics engine
@@ -185,6 +204,8 @@ of the following host1x client modules: - interconnect-names: Must include name of the interconnect path for each interconnect entry. Consult TRM documentation for information about available memory clients, see MEMORY CONTROLLER section. + - operating-points-v2: See ../bindings/opp/opp.txt for details. + - power-domains: Phandle to HEG or core power domain. - gr3d: 3D graphics engine
@@ -209,6 +230,8 @@ of the following host1x client modules: - interconnect-names: Must include name of the interconnect path for each interconnect entry. Consult TRM documentation for information about available memory clients, see MEMORY CONTROLLER section. + - operating-points-v2: See ../bindings/opp/opp.txt for details. + - power-domains: Phandles to 3D or core power domain. - dc: display controller
@@ -241,6 +264,8 @@ of the following host1x client modules: - interconnect-names: Must include name of the interconnect path for each interconnect entry. Consult TRM documentation for information about available memory clients, see MEMORY CONTROLLER section. + - operating-points-v2: See ../bindings/opp/opp.txt for details. + - power-domains: Phandle to core power domain. - hdmi: High Definition Multimedia Interface
@@ -267,6 +292,7 @@ of the following host1x client modules: - nvidia,hpd-gpio: specifies a GPIO used for hotplug detection - nvidia,edid: supplies a binary EDID blob - nvidia,panel: phandle of a display panel + - operating-points-v2: See ../bindings/opp/opp.txt for details. - tvo: TV encoder output
@@ -277,6 +303,10 @@ of the following host1x client modules: - clocks: Must contain one entry, for the module clock. See ../clocks/clock-bindings.txt for details. + Optional properties: + - operating-points-v2: See ../bindings/opp/opp.txt for details. + - power-domains: Phandle to core power domain. + - dsi: display serial interface Required properties:
@@ -305,6 +335,7 @@ of the following host1x client modules: - nvidia,panel: phandle of a display panel - nvidia,ganged-mode: contains a phandle to a second DSI controller to gang up with in order to support up to 8 data lanes + - operating-points-v2: See ../bindings/opp/opp.txt for details. - sor: serial output resource
@@ -408,6 +439,8 @@ Example: clocks = <&tegra_car TEGRA20_CLK_HOST1X>; resets = <&tegra_car 28>; reset-names = "host1x"; + operating-points-v2 = <&dvfs_opp_table>; + power-domains = <&domain>; #address-cells = <1>; #size-cells = <1>;
@@ -421,6 +454,8 @@ Example: clocks = <&tegra_car TEGRA20_CLK_MPE>; resets = <&tegra_car 60>; reset-names = "mpe"; + operating-points-v2 = <&dvfs_opp_table>; + power-domains = <&domain>; }; vi@54080000 {
@@ -429,6 +464,7 @@ Example: interrupts = <GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>; assigned-clocks = <&tegra_car TEGRA210_CLK_VI>; assigned-clock-parents = <&tegra_car TEGRA210_CLK_PLL_C4_OUT0>; + operating-points-v2 = <&dvfs_opp_table>; clocks = <&tegra_car TEGRA210_CLK_VI>; power-domains = <&pd_venc>;
@@ -510,6 +546,8 @@ Example: clocks = <&tegra_car TEGRA20_CLK_EPP>; resets = <&tegra_car 19>; reset-names = "epp"; + operating-points-v2 = <&dvfs_opp_table>; + power-domains = <&domain>; }; isp {
@@ -528,6 +566,8 @@ Example: clocks = <&tegra_car TEGRA20_CLK_GR2D>; resets = <&tegra_car 21>; reset-names = "2d"; + operating-points-v2 = <&dvfs_opp_table>; + power-domains = <&domain>; }; gr3d {
@@ -536,6 +576,8 @@ Example: clocks = <&tegra_car TEGRA20_CLK_GR3D>; resets = <&tegra_car 24>; reset-names = "3d"; + operating-points-v2 = <&dvfs_opp_table>; + power-domains = <&domain>; }; dc@54200000 {
@@ -547,6 +589,8 @@ Example: clock-names = "dc", "parent"; resets = <&tegra_car 27>; reset-names = "dc"; + operating-points-v2 = <&dvfs_opp_table>; + power-domains = <&domain>; interconnects = <&mc TEGRA20_MC_DISPLAY0A &emc>, <&mc TEGRA20_MC_DISPLAY0B &emc>,
@@ -571,6 +615,8 @@ Example: clock-names = "dc", "parent"; resets = <&tegra_car 26>; reset-names = "dc"; + operating-points-v2 = <&dvfs_opp_table>; + power-domains = <&domain>; interconnects = <&mc TEGRA20_MC_DISPLAY0AB &emc>, <&mc TEGRA20_MC_DISPLAY0BB &emc>,
@@ -596,6 +642,7 @@ Example: resets = <&tegra_car 51>; reset-names = "hdmi"; status = "disabled"; + operating-points-v2 = <&dvfs_opp_table>; }; tvo {
@@ -604,6 +651,7 @@ Example: interrupts = <0 76 0x04>; clocks = <&tegra_car TEGRA20_CLK_TVO>; status = "disabled"; + operating-points-v2 = <&dvfs_opp_table>; }; dsi {
@@ -615,6 +663,7 @@ Example: resets = <&tegra_car 48>; reset-names = "dsi"; status = "disabled"; + operating-points-v2 = <&dvfs_opp_table>; }; };
Signature · 1 line
2.29.2
Re: [PATCH v2 04/48] dt-bindings: host1x: Document OPP and power domain properties
Quoted 8 lines · Dmitry Osipenko
Document new DVFS OPP table and power domain properties of the Host1x bus and devices sitting on the bus.
Signed-off-by Dmitry Osipenko <[email protected]>--- .../display/tegra/nvidia,tegra20-host1x.txt | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+)
_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel
PATCH v2 5/48 media: dt: bindings: tegra-vde: Document OPP and power domain properties
In reply to Dmitry OsipenkoDocument new DVFS OPP table and power domain properties of the video decoder engine.
--- .../devicetree/bindings/media/nvidia,tegra-vde.txt | 12 ++++++++++++ 1 file changed, 12 insertions(+)
Documentation/devicetree/bindings/media/nvidia,tegra-vde.txt +12 -0
@@ -36,6 +36,16 @@ Optional properties: - reset-names : Must include the following entries: - mc - iommus: Must contain phandle to the IOMMU device node. +- operating-points-v2: See ../bindings/opp/opp.txt for details. +- power-domains: Phandle to VDEC power domain. + +For each opp entry in 'operating-points-v2' table: +- opp-supported-hw: One bitfield indicating: + On Tegra20: SoC process ID mask + On Tegra30+: SoC speedo ID mask + + A bitwise AND is performed against the value and if any bit + matches, the OPP gets enabled. Example:
@@ -61,4 +71,6 @@ video-codec@6001a000 { reset-names = "vde", "mc"; resets = <&tegra_car 61>, <&mc TEGRA20_MC_RESET_VDE>; iommus = <&mc TEGRA_SWGROUP_VDE>; + operating-points-v2 = <&dvfs_opp_table>; + power-domains = <&domain>; };
Signature · 1 line
2.29.2
Re: [PATCH v2 05/48] media: dt: bindings: tegra-vde: Document OPP and power domain properties
Quoted 8 lines · Dmitry Osipenko
Document new DVFS OPP table and power domain properties of the video decoder engine.
Signed-off-by Dmitry Osipenko <[email protected]>--- .../devicetree/bindings/media/nvidia,tegra-vde.txt | 12 ++++++++++++ 1 file changed, 12 insertions(+)
_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel
PATCH v2 6/48 dt-bindings: clock: tegra: Document clocks sub-node
In reply to Dmitry OsipenkoDocument "clocks" sub-node which describes Tegra SoC clocks that require a higher voltage of the core power domain in order to operate properly on a higher rates.
--- .../bindings/clock/nvidia,tegra20-car.txt | 26 +++++++++++++++++++ .../bindings/clock/nvidia,tegra30-car.txt | 26 +++++++++++++++++++ 2 files changed, 52 insertions(+)
Documentation/devicetree/bindings/clock/nvidia,tegra20-car.txt +26 -0
@@ -19,6 +19,16 @@ Required properties : In clock consumers, this cell represents the bit number in the CAR's array of CLK_RST_CONTROLLER_RST_DEVICES_* registers. +Optional child sub-node "clocks" should contain nodes matching the clocks +on the Tegra SoC. Refer to Tegra TRM for mode details on the clock nodes. + +Required properties : +- compatible : Should be "nvidia,tegra20-clock". +- operating-points-v2: See ../bindings/opp/opp.txt for details. +- clocks : Should contain clock which corresponds to the node. +- power-domains: Phandle to a power domain node as described by generic + PM domain bindings. + Example SoC include file: / {
@@ -27,6 +37,22 @@ Example SoC include file: reg = <0x60006000 0x1000>; #clock-cells = <1>; #reset-cells = <1>; + + clocks { + hdmi { + compatible = "nvidia,tegra20-clock"; + operating-points-v2 = <&hdmi_opp_table>; + clocks = <&tegra_car TEGRA20_CLK_HDMI>; + power-domains = <&domain>; + }; + + pll_m { + compatible = "nvidia,tegra20-clock"; + operating-points-v2 = <&pll_m_opp_table>; + clocks = <&tegra_car TEGRA20_CLK_PLL_M>; + power-domains = <&domain>; + }; + }; }; usb@c5004000 {
Documentation/devicetree/bindings/clock/nvidia,tegra30-car.txt +26 -0
@@ -19,6 +19,16 @@ Required properties : In clock consumers, this cell represents the bit number in the CAR's array of CLK_RST_CONTROLLER_RST_DEVICES_* registers. +Optional child sub-node "clocks" should contain nodes matching the clocks +on the Tegra SoC. Refer to Tegra TRM for mode details on the clock nodes. + +Required properties : +- compatible : Should be "nvidia,tegra30-clock". +- operating-points-v2: See ../bindings/opp/opp.txt for details. +- clocks : Should contain clock which corresponds to the node. +- power-domains: Phandle to a power domain node as described by generic + PM domain bindings. + Example SoC include file: / {
@@ -31,6 +41,22 @@ Example SoC include file: usb@c5004000 { clocks = <&tegra_car TEGRA30_CLK_USB2>; + + clocks { + hdmi { + compatible = "nvidia,tegra30-clock"; + operating-points-v2 = <&hdmi_opp_table>; + clocks = <&tegra_car TEGRA30_CLK_HDMI>; + power-domains = <&domain>; + }; + + pll_m { + compatible = "nvidia,tegra30-clock"; + operating-points-v2 = <&pll_m_opp_table>; + clocks = <&tegra_car TEGRA30_CLK_PLL_M>; + power-domains = <&domain>; + }; + }; }; };
Signature · 1 line
2.29.2
Rob Herring
maintainerRe: [PATCH v2 06/48] dt-bindings: clock: tegra: Document clocks sub-node
Quoted 3 lines · Dmitry Osipenko
Document "clocks" sub-node which describes Tegra SoC clocks that require a higher voltage of the core power domain in order to operate properly on a higher rates.
Seems like an odd reason to have a bunch of child nodes. It very much seems like a problem you'd need to solve after you design the binding which should be fixed within the kernel.
This is also above my threshold for 'convert to schema' first...
Quoted 98 lines
Signed-off-by Dmitry Osipenko <[email protected]>--- .../bindings/clock/nvidia,tegra20-car.txt | 26 +++++++++++++++++++ .../bindings/clock/nvidia,tegra30-car.txt | 26 +++++++++++++++++++ 2 files changed, 52 insertions(+)Documentation/devicetree/bindings/clock/nvidia,tegra20-car.txt +26
-0@@ -19,6 +19,16 @@ Required properties : In clock consumers, this cell represents the bit number in the CAR's array of CLK_RST_CONTROLLER_RST_DEVICES_* registers. +Optional child sub-node "clocks" should contain nodes matching the clocks +on the Tegra SoC. Refer to Tegra TRM for mode details on the clock nodes. + +Required properties : +- compatible : Should be "nvidia,tegra20-clock". +- operating-points-v2: See ../bindings/opp/opp.txt for details. +- clocks : Should contain clock which corresponds to the node. +- power-domains: Phandle to a power domain node as described by generic + PM domain bindings. + Example SoC include file: / {@@ -27,6 +37,22 @@ Example SoC include file: reg = <0x60006000 0x1000>; #clock-cells = <1>; #reset-cells = <1>; + + clocks { + hdmi { + compatible = "nvidia,tegra20-clock"; + operating-points-v2 = <&hdmi_opp_table>; + clocks = <&tegra_car TEGRA20_CLK_HDMI>; + power-domains = <&domain>; + }; + + pll_m { + compatible = "nvidia,tegra20-clock"; + operating-points-v2 = <&pll_m_opp_table>; + clocks = <&tegra_car TEGRA20_CLK_PLL_M>; + power-domains = <&domain>; + }; + }; }; usb@c5004000 {Documentation/devicetree/bindings/clock/nvidia,tegra30-car.txt +26
-0@@ -19,6 +19,16 @@ Required properties : In clock consumers, this cell represents the bit number in the CAR's array of CLK_RST_CONTROLLER_RST_DEVICES_* registers. +Optional child sub-node "clocks" should contain nodes matching the clocks +on the Tegra SoC. Refer to Tegra TRM for mode details on the clock nodes. + +Required properties : +- compatible : Should be "nvidia,tegra30-clock". +- operating-points-v2: See ../bindings/opp/opp.txt for details. +- clocks : Should contain clock which corresponds to the node. +- power-domains: Phandle to a power domain node as described by generic + PM domain bindings. + Example SoC include file: / {@@ -31,6 +41,22 @@ Example SoC include file: usb@c5004000 { clocks = <&tegra_car TEGRA30_CLK_USB2>; + + clocks { + hdmi { + compatible = "nvidia,tegra30-clock"; + operating-points-v2 = <&hdmi_opp_table>; + clocks = <&tegra_car TEGRA30_CLK_HDMI>; + power-domains = <&domain>; + }; + + pll_m { + compatible = "nvidia,tegra30-clock"; + operating-points-v2 = <&pll_m_opp_table>; + clocks = <&tegra_car TEGRA30_CLK_PLL_M>; + power-domains = <&domain>; + }; + }; }; };Signature · 1 line
2.29.2
_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel
Re: [PATCH v2 06/48] dt-bindings: clock: tegra: Document clocks sub-node
22.12.2020 03:14, Rob Herring пишет:
Quoted 8 lines · Dmitry Osipenko
Quoted 3 lines
Document "clocks" sub-node which describes Tegra SoC clocks that require a higher voltage of the core power domain in order to operate properly on a higher rates.
Seems like an odd reason to have a bunch of child nodes. It very much seems like a problem you'd need to solve after you design the binding which should be fixed within the kernel.
The reason is that multiple root SoC PLL clocks need to have individual OPP table because proper voltage should be maintained for these clocks based on the clock rate.
Some of the clocks do not belong to any specific device and there is a need to specify the OPP table for them. Each child node represents an individual clock with the clock's OPP table and power domain.
Some clocks belong to a specific device, but don't require high voltages and it's very convenient that clk device could manage voltage for these clocks, instead of populating each device with OPP support (PWM, MMC and etc).
I'll update the commit message with a better explanation in v3.
Quoted 1 line
This is also above my threshold for 'convert to schema' first...
Alright, will convert it in v3.
PATCH v2 7/48 dt-bindings: arm: 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.
--- .../arm/tegra/nvidia,tegra20-core-domain.yaml | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-core-domain.yaml
Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-core-domain.yaml new file +48 -0
@@ -0,0 +1,48 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/arm/tegra/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]> + +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: + 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: + - | + core-domain { + compatible = "nvidia,tegra20-core-domain"; + operating-points-v2 = <&opp_table>; + power-supply = <®ulator>; + #power-domain-cells = <0>; + };
Signature · 1 line
2.29.2
Krzysztof Kozlowski
maintainerRe: [PATCH v2 07/48] dt-bindings: arm: tegra: Add binding for core power domain
Quoted 23 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]>--- .../arm/tegra/nvidia,tegra20-core-domain.yaml | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-core-domain.yamlDocumentation/devicetree/bindings/arm/tegra/nvidia,tegra20-core-domain.yaml new file +8
-0@@ -0,0 +1,48 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/arm/tegra/nvidia,tegra20-core-domain.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NVIDIA Tegra Core Power Domain +
Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-core-domain.yaml line 18
Quoted 10 lines
Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-core-domain.yaml new file +10
-0+maintainers: + - Dmitry Osipenko <[email protected]> + - Jon Hunter <[email protected]> + - Thierry Reding <[email protected]> + +properties: + compatible: + enum: + - nvidia,tegra20-core-domain + - nvidia,tegra30-core-domain
The file should be in bindings/power.
Include also the power-domain.yaml schema.
Quoted 15 lines
Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-core-domain.yaml new file +15
-0+ + 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: + description: + Phandle to voltage regulator connected to the SoC Core power rail. + +required:
Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-core-domain.yaml line 43
Quoted 10 lines
Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-core-domain.yaml new file +10
-0+ - compatible + - operating-points-v2 + - "#power-domain-cells" + - power-supply + +additionalProperties: false + +examples: + - | + core-domain {
power-domain (to follow schema and devicetree spec)
Best regards,
Krzysztof
Quoted 8 lines
Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-core-domain.yaml new file +5
-0+ compatible = "nvidia,tegra20-core-domain"; + operating-points-v2 = <&opp_table>; + power-supply = <®ulator>; + #power-domain-cells = <0>; + };Signature · 1 line
2.29.2
_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel
Re: [PATCH v2 07/48] dt-bindings: arm: tegra: Add binding for core power domain
19.12.2020 13:57, Krzysztof Kozlowski пишет:
Quoted 57 lines · Dmitry Osipenko
Quoted 23 lines
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]>--- .../arm/tegra/nvidia,tegra20-core-domain.yaml | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-core-domain.yamlDocumentation/devicetree/bindings/arm/tegra/nvidia,tegra20-core-domain.yaml new file +8
-0@@ -0,0 +1,48 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/arm/tegra/nvidia,tegra20-core-domain.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NVIDIA Tegra Core Power Domain +Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-core-domain.yaml line 18
Quoted 10 lines
Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-core-domain.yaml new file +10
-0+maintainers: + - Dmitry Osipenko <[email protected]> + - Jon Hunter <[email protected]> + - Thierry Reding <[email protected]> + +properties: + compatible: + enum: + - nvidia,tegra20-core-domain + - nvidia,tegra30-core-domainThe file should be in bindings/power.
Include also thepower-domain.yamlschema.Quoted 19 lines
Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-core-domain.yaml new file +19
-0+ + 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: + description: + Phandle to voltage regulator connected to the SoC Core power rail. + +required: + - compatible + - operating-points-v2 + - "#power-domain-cells" + - power-supply
Quoted 8 lines
Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-core-domain.yaml line 43
Quoted 6 lines
Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-core-domain.yaml new file +6
-0+ +additionalProperties: false + +examples: + - | + core-domain {power-domain (to follow schema and devicetree spec)
Thanks for the suggestion, I'll update it in v3.
PATCH v2 8/48 regulator: Make regulator_sync_voltage() usable by coupled regulators
In reply to Dmitry OsipenkoMake regulator_sync_voltage() to re-balance voltage state of a coupled regulators instead of changing the voltage directly.
--- drivers/regulator/core.c | 6 ++++++ 1 file changed, 6 insertions(+)
drivers/regulator/core.c +6 -0
@@ -4131,6 +4131,12 @@ int regulator_sync_voltage(struct regulator *regulator)if (ret <0 ) goto out; +/* balance only if there are regulators coupled */ +if (rdev->coupling_desc.n_coupled >1 ) { + ret =regulator_balance_voltage (rdev,PM_SUSPEND_ON ); + goto out; + } + ret =_regulator_do_set_voltage (rdev, min_uV, max_uV); out:
Signature · 1 line
2.29.2
PATCH v2 9/48 opp: Add dev_pm_opp_sync_regulators()
In reply to Dmitry OsipenkoExtend OPP API with dev_pm_opp_sync_regulators() function, which syncs voltage state of regulators.
--- drivers/opp/core.c | 42 ++++++++++++++++++++++++++++++++++++++++++ include/linux/pm_opp.h | 11 +++++++++++ 2 files changed, 53 insertions(+)
drivers/opp/core.c +42 -0
@@ -2499,3 +2499,45 @@ void dev_pm_opp_remove_table(struct device *dev)dev_pm_opp_put_opp_table (opp_table); }EXPORT_SYMBOL_GPL (dev_pm_opp_remove_table); + +/** +* dev_pm_opp_sync_regulators() - Sync state of voltage regulators +* @dev: device for which we do this operation +* +* Sync voltage state of the OPP table regulators. +* +* Return: 0 on success or a negative error value. +*/ +int dev_pm_opp_sync_regulators (struct device *dev) +{ +struct opp_table *opp_table; +struct regulator *reg; +int i, ret =0 ; + +/* Device may not have OPP table */ + opp_table =_find_opp_table (dev); +if (IS_ERR (opp_table)) +return 0 ; + +/* Regulator may not be required for the device */ +if (!opp_table->regulators) + goto put_table; + +/* Nothing to sync if voltage wasn't changed */ +if (!opp_table->enabled) + goto put_table; + +for (i =0 ; i < opp_table->regulator_count; i++) { + reg = opp_table->regulators[i]; + ret =regulator_sync_voltage (reg); +if (ret) +break ; + } + +put_table: +/* Drop reference taken by _find_opp_table() */ +dev_pm_opp_put_opp_table (opp_table); + +return ret; +} +EXPORT_SYMBOL_GPL (dev_pm_opp_sync_regulators);
include/linux/pm_opp.h +11 -0
@@ -156,6 +156,7 @@ int dev_pm_opp_set_sharing_cpus(struct device *cpu_dev, const struct cpumask *cpint dev_pm_opp_get_sharing_cpus (struct device *cpu_dev,struct cpumask *cpumask);void dev_pm_opp_remove_table (struct device *dev);void dev_pm_opp_cpumask_remove_table (const struct cpumask *cpumask); +int dev_pm_opp_sync_regulators (struct device *dev);#else static inline struct opp_table *dev_pm_opp_get_opp_table (struct device *dev) {
@@ -366,6 +367,11 @@ static inline void dev_pm_opp_cpumask_remove_table(const struct cpumask *cpumask { } +static inline int dev_pm_opp_sync_regulators (struct device *dev) +{ +return -ENOTSUPP ; +} +#endif /* CONFIG_PM_OPP */ #if defined(CONFIG_PM_OPP ) && defined(CONFIG_OF )
@@ -442,6 +448,11 @@ static inline int dev_pm_opp_of_find_icc_paths(struct device *dev, struct opp_ta {return -ENOTSUPP ; } + +static inline int dev_pm_opp_sync_regulators (struct device *dev) +{ +return -ENOTSUPP ; +}#endif #endif /* __LINUX_OPP_H__ */
Signature · 1 line
2.29.2
Re: [PATCH v2 09/48] opp: Add dev_pm_opp_sync_regulators()
Quoted 4 lines · Dmitry Osipenko
Extend OPP API with
dev_pm_opp_sync_regulators()function, which syncs voltage state of regulators.Signed-off-by Dmitry Osipenko <[email protected]>
We shouldn't be doing this, details in patch 28.
Signature · 1 line
viresh
PATCH v2 10/48 opp: Add dev_pm_opp_set_voltage()
In reply to Dmitry OsipenkoAdd dev_pm_opp_set_voltage() which allows OPP table users to set voltage in accordance to a given OPP. In particular this is needed for driving voltage of a generic power domain which uses OPPs and doesn't have a clock.
--- drivers/opp/core.c | 52 ++++++++++++++++++++++++++++++++++++++++++ include/linux/pm_opp.h | 11 +++++---- 2 files changed, 58 insertions(+), 5 deletions(-)
drivers/opp/core.c +52 -0
@@ -2541,3 +2541,55 @@ int dev_pm_opp_sync_regulators(struct device *dev)return ret; }EXPORT_SYMBOL_GPL (dev_pm_opp_sync_regulators); + +/** +* dev_pm_opp_set_voltage() - Change voltage of regulators +* @dev: device for which we do this operation +* @opp: opp based on which the voltages are to be configured +* +* Change voltage of the OPP table regulators. +* +* Return: 0 on success or a negative error value. +*/ +int dev_pm_opp_set_voltage (struct device *dev,struct dev_pm_opp *opp) +{ +struct opp_table *opp_table; +struct regulator *reg; +int ret =0 ; + +/* Device may not have OPP table */ + opp_table =_find_opp_table (dev); +if (IS_ERR (opp_table)) +return 0 ; + +/* Regulator may not be required for the device */ +if (!opp_table->regulators) + goto put_table; + +/* This function only supports single regulator per device */ +if (WARN_ON (opp_table->regulator_count >1 )) { +dev_err (dev,"multiple regulators are not supported\n" ); + ret = -EINVAL ; + goto put_table; + } + + reg = opp_table->regulators[0 ]; + ret =_set_opp_voltage (dev, reg, opp->supplies); + +if (!opp_table->enabled) { + ret =regulator_enable (reg); +if (ret <0 ) { +dev_warn (dev,"Failed to enable regulator: %d" , ret); + goto put_table; + } + + opp_table->enabled = true; + } + +put_table: +/* Drop reference taken by _find_opp_table() */ +dev_pm_opp_put_opp_table (opp_table); + +return ret; +} +EXPORT_SYMBOL_GPL (dev_pm_opp_set_voltage);
include/linux/pm_opp.h +6 -5
@@ -157,6 +157,7 @@ int dev_pm_opp_get_sharing_cpus(struct device *cpu_dev, struct cpumask *cpumask)void dev_pm_opp_remove_table (struct device *dev);void dev_pm_opp_cpumask_remove_table (const struct cpumask *cpumask);int dev_pm_opp_sync_regulators (struct device *dev); +int dev_pm_opp_set_voltage (struct device *dev,struct dev_pm_opp *opp);#else static inline struct opp_table *dev_pm_opp_get_opp_table (struct device *dev) {
@@ -372,6 +373,11 @@ static inline int dev_pm_opp_sync_regulators(struct device *dev) return -ENOTSUPP; } +static inline int dev_pm_opp_set_voltage (struct device *dev,struct dev_pm_opp *opp) +{ +return -ENOTSUPP ; +} +#endif /* CONFIG_PM_OPP */ #if defined(CONFIG_PM_OPP ) && defined(CONFIG_OF )
@@ -448,11 +454,6 @@ static inline int dev_pm_opp_of_find_icc_paths(struct device *dev, struct opp_ta {return -ENOTSUPP ; } - -static inline int dev_pm_opp_sync_regulators (struct device *dev) -{ -return -ENOTSUPP ; -}#endif #endif /* __LINUX_OPP_H__ */
Signature · 1 line
2.29.2
Re: [PATCH v2 10/48] opp: Add dev_pm_opp_set_voltage()
Quoted 6 lines · Dmitry Osipenko
Add
dev_pm_opp_set_voltage()which allows OPP table users to set voltage in accordance to a given OPP. In particular this is needed for driving voltage of a generic power domain which uses OPPs and doesn't have a clock.Signed-off-by Dmitry Osipenko <[email protected]>
We shouldn't be doing this, details in patch 28.
Signature · 1 line
viresh
PATCH v2 11/48 opp: Add dev_pm_opp_find_level_ceil()
In reply to Dmitry OsipenkoAdd a ceil version of the dev_pm_opp_find_level(). It's handy to have if levels don't start from 0 in OPP table and zero usually means a minimal level.
--- drivers/opp/core.c | 49 ++++++++++++++++++++++++++++++++++++++++++ include/linux/pm_opp.h | 8 +++++++ 2 files changed, 57 insertions(+)
drivers/opp/core.c +49 -0
@@ -449,6 +449,55 @@ struct dev_pm_opp *dev_pm_opp_find_level_exact(struct device *dev, }EXPORT_SYMBOL_GPL (dev_pm_opp_find_level_exact); +/** +* dev_pm_opp_find_level_ceil() - search for an rounded up level +* @dev: device for which we do this operation +* @level: level to search for +* +* Return: Searches for rounded up match in the opp table and returns pointer +* to the matching opp if found, else returns ERR_PTR in case of error and +* should be handled using IS_ERR. Error return values can be: +* EINVAL: for bad pointer +* ERANGE: no match found for search +* ENODEV: if device not found in list of registered devices +* +* The callers are required to call dev_pm_opp_put() for the returned OPP after +* use. +*/ +struct dev_pm_opp *dev_pm_opp_find_level_ceil (struct device *dev, +unsigned int *level) +{ +struct opp_table *opp_table; +struct dev_pm_opp *temp_opp, *opp =ERR_PTR (-ERANGE ); + + opp_table =_find_opp_table (dev); +if (IS_ERR (opp_table)) { +int r =PTR_ERR (opp_table); + +dev_err (dev,"%s: OPP table not found (%d)\n" , __func__, r); +return ERR_PTR (r); + } + +mutex_lock (&opp_table->lock); + +list_for_each_entry (temp_opp, &opp_table->opp_list, node) { +if (temp_opp->available && temp_opp->level >= *level) { + opp = temp_opp; + *level = opp->level; + +/* Increment the reference count of OPP */ +dev_pm_opp_get (opp); +break ; + } + } + +mutex_unlock (&opp_table->lock); +dev_pm_opp_put_opp_table (opp_table); + +return opp; +} +EXPORT_SYMBOL_GPL (dev_pm_opp_find_level_ceil); + static noinline struct dev_pm_opp *_find_freq_ceil(struct opp_table *opp_table,unsigned long *freq) {
include/linux/pm_opp.h +8 -0
@@ -111,6 +111,8 @@ struct dev_pm_opp *dev_pm_opp_find_freq_exact(struct device *dev, bool available);struct dev_pm_opp *dev_pm_opp_find_level_exact (struct device *dev,unsigned int level); +struct dev_pm_opp *dev_pm_opp_find_level_ceil (struct device *dev, +unsigned int *level);struct dev_pm_opp *dev_pm_opp_find_freq_floor (struct device *dev,unsigned long *freq);
@@ -228,6 +230,12 @@ static inline struct dev_pm_opp *dev_pm_opp_find_level_exact(struct device *dev,return ERR_PTR (-ENOTSUPP ); } +static inline struct dev_pm_opp *dev_pm_opp_find_level_ceil (struct device *dev, +unsigned int *level) +{ +return ERR_PTR (-ENOTSUPP ); +} +static inline struct dev_pm_opp *dev_pm_opp_find_freq_floor (struct device *dev,unsigned long *freq) {
Signature · 1 line
2.29.2
Re: [PATCH v2 11/48] opp: Add dev_pm_opp_find_level_ceil()
Quoted 5 lines · Dmitry Osipenko
Add a ceil version of the
dev_pm_opp_find_level(). It's handy to have if levels don't start from 0 in OPP table and zero usually means a minimal level.Signed-off-by Dmitry Osipenko <[email protected]>
Why doesn't the exact version work for you here ?
Signature · 1 line
viresh
Re: [PATCH v2 11/48] opp: Add dev_pm_opp_find_level_ceil()
22.12.2020 09:42, Viresh Kumar пишет:
Quoted 9 lines · Dmitry Osipenko
Quoted 5 lines
Add a ceil version of the
dev_pm_opp_find_level(). It's handy to have if levels don't start from 0 in OPP table and zero usually means a minimal level.Signed-off-by Dmitry Osipenko <[email protected]>Why doesn't the exact version work for you here ?
The exact version won't find OPP for level=0 if levels don't start with 0, where 0 means that minimal level is desired.
Re: [PATCH v2 11/48] opp: Add dev_pm_opp_find_level_ceil()
Quoted 6 lines · Dmitry Osipenko
22.12.2020 09:42, Viresh Kumar пишет:
Quoted 5 lines · Dmitry Osipenko
Quoted 4 lines
Add a ceil version of the
dev_pm_opp_find_level(). It's handy to have if levels don't start from 0 in OPP table and zero usually means a minimal level.
Quoted 7 lines
Quoted 4 lines
Quoted 1 line
Signed-off-by Dmitry Osipenko <[email protected]>Why doesn't the exact version work for you here ?
The exact version won't find OPP for level=0 if levels don't start with 0, where 0 means that minimal level is desired.
Right, but why do you need to send 0 for your platform ?
Signature · 1 line
viresh
Re: [PATCH v2 11/48] opp: Add dev_pm_opp_find_level_ceil()
23.12.2020 07:19, Viresh Kumar пишет:
Quoted 9 lines · Dmitry Osipenko
Quoted 8 lines
22.12.2020 09:42, Viresh Kumar пишет:
Quoted 7 lines · Dmitry Osipenko
Quoted 5 lines
Add a ceil version of the
dev_pm_opp_find_level(). It's handy to have if levels don't start from 0 in OPP table and zero usually means a minimal level.Signed-off-by Dmitry Osipenko <[email protected]>
Quoted 8 lines
Quoted 5 lines
Quoted 2 lines
Why doesn't the exact version work for you here ?
The exact version won't find OPP for level=0 if levels don't start with 0, where 0 means that minimal level is desired.
Right, but why do you need to send 0 for your platform ?
To put power domain into the lowest performance state when device is idling.
https://elixir.bootlin.com/linux/v5.10-rc2/source/drivers/opp/core.c#L897
https://elixir.bootlin.com/linux/v5.10-rc2/source/drivers/opp/core.c#L785
Also please see patch 32, tegra_clock_runtime_suspend().
Re: [PATCH v2 11/48] opp: Add dev_pm_opp_find_level_ceil()
Quoted 13 lines · Dmitry Osipenko
23.12.2020 07:19, Viresh Kumar пишет:
Quoted 12 lines · Dmitry Osipenko
Quoted 11 lines
22.12.2020 09:42, Viresh Kumar пишет:
Quoted 9 lines · Dmitry Osipenko
Quoted 5 lines
Add a ceil version of the
dev_pm_opp_find_level(). It's handy to have if levels don't start from 0 in OPP table and zero usually means a minimal level.Signed-off-by Dmitry Osipenko <[email protected]>Why doesn't the exact version work for you here ?
Quoted 7 lines
Quoted 5 lines
Quoted 2 lines
The exact version won't find OPP for level=0 if levels don't start with 0, where 0 means that minimal level is desired.
Right, but why do you need to send 0 for your platform ?
To put power domain into the lowest performance state when device is idling.
I see. So you really want to set it to the lowest state or just take the vote out ? Which may end up powering off the domain in the worst case ?
Signature · 1 line
viresh
Re: [PATCH v2 11/48] opp: Add dev_pm_opp_find_level_ceil()
24.12.2020 09:43, Viresh Kumar пишет:
Quoted 17 lines · Dmitry Osipenko
Quoted 16 lines
23.12.2020 07:19, Viresh Kumar пишет:
Quoted 15 lines · Dmitry Osipenko
Quoted 13 lines
22.12.2020 09:42, Viresh Kumar пишет:
Quoted 9 lines · Dmitry Osipenko
Quoted 5 lines
Add a ceil version of the
dev_pm_opp_find_level(). It's handy to have if levels don't start from 0 in OPP table and zero usually means a minimal level.Signed-off-by Dmitry Osipenko <[email protected]>Why doesn't the exact version work for you here ?
The exact version won't find OPP for level=0 if levels don't start with 0, where 0 means that minimal level is desired.
Quoted 8 lines
Quoted 4 lines
Quoted 2 lines
Right, but why do you need to send 0 for your platform ?
To put power domain into the lowest performance state when device is idling.
I see. So you really want to set it to the lowest state or just take the vote out ? Which may end up powering off the domain in the worst case ?
In a device driver I want to set PD to the lowest performance state by removing the performance vote when dev_pm_opp_set_rate(dev, 0) is invoked by the driver.
The OPP core already does this, but if OPP levels don't start from 0 in a device-tree for PD, then it currently doesn't work since there is a need to get a rounded-up performance state because dev_pm_opp_set_voltage() takes OPP entry for the argument (patches 9 and 28).
The PD powering off and performance-changes are separate from each other in the GENPD core. The GENPD core automatically turns off domain when all devices within the domain are suspended by system-suspend or RPM.
The performance state of a power domain is controlled solely by a device driver. GENPD core only aggregates the performance requests, it doesn't change the performance state of a domain by itself when device is suspended or resumed, IIUC this is intentional. And I want to put domain into lowest performance state when device is suspended.
Re: [PATCH v2 11/48] opp: Add dev_pm_opp_find_level_ceil()
Quoted 14 lines · Dmitry Osipenko
In a device driver I want to set PD to the lowest performance state by removing the performance vote when
dev_pm_opp_set_rate(dev, 0)is invoked by the driver.The OPP core already does this, but if OPP levels don't start from 0 in a device-tree for PD, then it currently doesn't work since there is a need to get a rounded-up performance state because
dev_pm_opp_set_voltage()takes OPP entry for the argument (patches 9 and 28).The PD powering off and performance-changes are separate from each other in the GENPD core. The GENPD core automatically turns off domain when all devices within the domain are suspended by system-suspend or RPM.
Quoted 5 lines
The performance state of a power domain is controlled solely by a device driver. GENPD core only aggregates the performance requests, it doesn't change the performance state of a domain by itself when device is suspended or resumed, IIUC this is intentional. And I want to put domain into lowest performance state when device is suspended.
Right, so if you really want to just drop the performance vote, then with a value of 0 for the performance state the call will reach to your genpd's callback ->set_performance_state(). Just as dev_pm_opp_set_rate() accepts the frequency to be 0, I would expect dev_pm_opp_set_rate() to accept opp argument as NULL and in that case set voltage to 0 and do regulator_disable() as well. Won't that work better than going for the lowest voltage ?
Signature · 1 line
viresh
Re: [PATCH v2 11/48] opp: Add dev_pm_opp_find_level_ceil()
28.12.2020 09:22, Viresh Kumar пишет:
Quoted 21 lines · Dmitry Osipenko
Quoted 14 lines
In a device driver I want to set PD to the lowest performance state by removing the performance vote when
dev_pm_opp_set_rate(dev, 0)is invoked by the driver.The OPP core already does this, but if OPP levels don't start from 0 in a device-tree for PD, then it currently doesn't work since there is a need to get a rounded-up performance state because
dev_pm_opp_set_voltage()takes OPP entry for the argument (patches 9 and 28).The PD powering off and performance-changes are separate from each other in the GENPD core. The GENPD core automatically turns off domain when all devices within the domain are suspended by system-suspend or RPM.
Quoted 5 lines
The performance state of a power domain is controlled solely by a device driver. GENPD core only aggregates the performance requests, it doesn't change the performance state of a domain by itself when device is suspended or resumed, IIUC this is intentional. And I want to put domain into lowest performance state when device is suspended.
Quoted 7 lines
Right, so if you really want to just drop the performance vote, then with a value of 0 for the performance state the call will reach to your genpd's callback ->set_performance_state(). Just as
dev_pm_opp_set_rate()accepts the frequency to be 0, I would expectdev_pm_opp_set_rate()to accept opp argument as NULL and in that case set voltage to 0 and doregulator_disable()as well. Won't that work better than going for the lowest voltage ?
We can make dev_pm_opp_set_voltage() to accept OPP=NULL in order to disable the regulator, like it's done for dev_pm_opp_set_rate(dev, 0). Although, I don't need this kind of behaviour for the Tegra PD driver, and thus, would prefer to leave this for somebody else to implement in the future, once it will be really needed.
Still we need the dev_pm_opp_find_level_ceil() because level=0 means that we want to set PD to the lowest (minimal) performance state, i.e. it doesn't necessarily mean that we want to set the voltage to 0 and disable the PD entirely. GENPD has a separate controls for on/off.
Re: [PATCH v2 11/48] opp: Add dev_pm_opp_find_level_ceil()
Quoted 36 lines · Dmitry Osipenko
28.12.2020 09:22, Viresh Kumar пишет:
Quoted 21 lines · Dmitry Osipenko
Quoted 14 lines
In a device driver I want to set PD to the lowest performance state by removing the performance vote when
dev_pm_opp_set_rate(dev, 0)is invoked by the driver.The OPP core already does this, but if OPP levels don't start from 0 in a device-tree for PD, then it currently doesn't work since there is a need to get a rounded-up performance state because
dev_pm_opp_set_voltage()takes OPP entry for the argument (patches 9 and 28).The PD powering off and performance-changes are separate from each other in the GENPD core. The GENPD core automatically turns off domain when all devices within the domain are suspended by system-suspend or RPM.
Quoted 5 lines
The performance state of a power domain is controlled solely by a device driver. GENPD core only aggregates the performance requests, it doesn't change the performance state of a domain by itself when device is suspended or resumed, IIUC this is intentional. And I want to put domain into lowest performance state when device is suspended.
Quoted 7 lines
Right, so if you really want to just drop the performance vote, then with a value of 0 for the performance state the call will reach to your genpd's callback ->set_performance_state(). Just as
dev_pm_opp_set_rate()accepts the frequency to be 0, I would expectdev_pm_opp_set_rate()to accept opp argument as NULL and in that case set voltage to 0 and doregulator_disable()as well. Won't that work better than going for the lowest voltage ?We can make
dev_pm_opp_set_voltage()to accept OPP=NULL in order to disable the regulator, like it's done fordev_pm_opp_set_rate(dev, 0). Although, I don't need this kind of behaviour for the Tegra PD driver, and thus, would prefer to leave this for somebody else to implement in the future, once it will be really needed.
Quoted 4 lines
Still we need the
dev_pm_opp_find_level_ceil()because level=0 means that we want to set PD to the lowest (minimal) performance state, i.e. it doesn't necessarily mean that we want to set the voltage to 0 and disable the PD entirely. GENPD has a separate controls for on/off.
Ok.
Signature · 1 line
viresh
Re: [PATCH v2 11/48] opp: Add dev_pm_opp_find_level_ceil()
30.12.2020 07:46, Viresh Kumar пишет:
Quoted 37 lines · Dmitry Osipenko
Quoted 36 lines
28.12.2020 09:22, Viresh Kumar пишет:
Quoted 21 lines · Dmitry Osipenko
Quoted 14 lines
In a device driver I want to set PD to the lowest performance state by removing the performance vote when
dev_pm_opp_set_rate(dev, 0)is invoked by the driver.The OPP core already does this, but if OPP levels don't start from 0 in a device-tree for PD, then it currently doesn't work since there is a need to get a rounded-up performance state because
dev_pm_opp_set_voltage()takes OPP entry for the argument (patches 9 and 28).The PD powering off and performance-changes are separate from each other in the GENPD core. The GENPD core automatically turns off domain when all devices within the domain are suspended by system-suspend or RPM.
Quoted 5 lines
The performance state of a power domain is controlled solely by a device driver. GENPD core only aggregates the performance requests, it doesn't change the performance state of a domain by itself when device is suspended or resumed, IIUC this is intentional. And I want to put domain into lowest performance state when device is suspended.
Quoted 7 lines
Right, so if you really want to just drop the performance vote, then with a value of 0 for the performance state the call will reach to your genpd's callback ->set_performance_state(). Just as
dev_pm_opp_set_rate()accepts the frequency to be 0, I would expectdev_pm_opp_set_rate()to accept opp argument as NULL and in that case set voltage to 0 and doregulator_disable()as well. Won't that work better than going for the lowest voltage ?We can make
dev_pm_opp_set_voltage()to accept OPP=NULL in order to disable the regulator, like it's done fordev_pm_opp_set_rate(dev, 0). Although, I don't need this kind of behaviour for the Tegra PD driver, and thus, would prefer to leave this for somebody else to implement in the future, once it will be really needed.
Quoted 7 lines
Quoted 4 lines
Still we need the
dev_pm_opp_find_level_ceil()because level=0 means that we want to set PD to the lowest (minimal) performance state, i.e. it doesn't necessarily mean that we want to set the voltage to 0 and disable the PD entirely. GENPD has a separate controls for on/off.Ok.
I'll separate the OPP patches from this series and will prepare v3, thank you for the review!
PATCH v2 12/48 opp: Add dev_pm_opp_get_required_pstate()
In reply to Dmitry OsipenkoAdd dev_pm_opp_get_required_pstate() which allows OPP users to retrieve required performance state of a given OPP.
--- drivers/opp/core.c | 22 ++++++++++++++++++++++ include/linux/pm_opp.h | 10 ++++++++++ 2 files changed, 32 insertions(+)
drivers/opp/core.c +22 -0
@@ -145,6 +145,28 @@ unsigned int dev_pm_opp_get_level(struct dev_pm_opp *opp) }EXPORT_SYMBOL_GPL (dev_pm_opp_get_level); +/** +* dev_pm_opp_get_required_pstate() - Gets the required performance state +* corresponding to an available opp +* @opp: opp for which performance state has to be returned for +* @index: index of the required opp +* +* Return: performance state read from device tree corresponding to the +* required opp, else return 0. +*/ +unsigned int dev_pm_opp_get_required_pstate (struct dev_pm_opp *opp, +unsigned int index) +{ +if (IS_ERR_OR_NULL (opp) || !opp->available || + index >= opp->opp_table->required_opp_count) { +pr_err ("%s: Invalid parameters\n" , __func__); +return 0 ; + } + +return opp->required_opps[index]->pstate; +} +EXPORT_SYMBOL_GPL (dev_pm_opp_get_required_pstate); +/** * dev_pm_opp_is_turbo() - Returns if opp is turbo OPP or not * @opp: opp for which turbo mode is being verified
include/linux/pm_opp.h +10 -0
@@ -98,6 +98,9 @@ unsigned long dev_pm_opp_get_freq(struct dev_pm_opp *opp);unsigned int dev_pm_opp_get_level (struct dev_pm_opp *opp); +unsigned int dev_pm_opp_get_required_pstate (struct dev_pm_opp *opp, +unsigned int index); +bool dev_pm_opp_is_turbo (struct dev_pm_opp *opp);int dev_pm_opp_get_opp_count (struct device *dev);
@@ -188,6 +191,13 @@ static inline unsigned int dev_pm_opp_get_level(struct dev_pm_opp *opp)return 0 ; } +static inline +unsigned int dev_pm_opp_get_required_pstate (struct dev_pm_opp *opp, +unsigned int index) +{ +return 0 ; +} +static inline bool dev_pm_opp_is_turbo (struct dev_pm_opp *opp) {return false;
Signature · 1 line
2.29.2
PATCH v2 13/48 opp: Add resource-managed versions of OPP API functions
In reply to Dmitry OsipenkoAdd resource-managed versions of OPP API functions. This removes a need from drivers to store and manage OPP table pointers.
--- drivers/opp/core.c | 173 +++++++++++++++++++++++++++++++++++++++++ drivers/opp/of.c | 25 ++++++ include/linux/pm_opp.h | 51 ++++++++++++ 3 files changed, 249 insertions(+)
drivers/opp/core.c +173 -0
@@ -2664,3 +2664,176 @@ int dev_pm_opp_set_voltage(struct device *dev, struct dev_pm_opp *opp)return ret; }EXPORT_SYMBOL_GPL (dev_pm_opp_set_voltage); + +/** +* devm_pm_opp_get_opp_table() - Get OPP table of a device +* @dev: device for which we do this operation +* +* This is a resource-managed version of dev_pm_opp_get_opp_table(). +* +* Return: pointer to 'struct opp_table' if found and -ENODEV otherwise. +*/ +struct opp_table *devm_pm_opp_get_opp_table (struct device *dev) +{ +struct opp_table *opp_table; +int err; + + opp_table =dev_pm_opp_get_opp_table (dev); +if (IS_ERR (opp_table)) +return opp_table; + + err =devm_add_action_or_reset (dev, (void *)dev_pm_opp_put_opp_table, + opp_table); +if (err) +return ERR_PTR (err); + +return opp_table; +} +EXPORT_SYMBOL_GPL (devm_pm_opp_get_opp_table); + +/** +* devm_pm_opp_set_regulators() - Set regulator names for the device +* @dev: Device for which regulator name is being set. +* @names: Array of pointers to the names of the regulator. +* @count: Number of regulators. +* +* This is a resource-managed version of dev_pm_opp_set_regulators(). +* +* Return: pointer to 'struct opp_table' on success and errorno otherwise. +*/ +struct opp_table * +devm_pm_opp_set_regulators (struct device *dev,const char *const names[], +unsigned int count) +{ +struct opp_table *opp_table; +int err; + + opp_table =dev_pm_opp_set_regulators (dev, names, count); +if (IS_ERR (opp_table)) +return opp_table; + + err =devm_add_action_or_reset (dev, (void *)dev_pm_opp_put_regulators, + opp_table); +if (err) +return ERR_PTR (err); + +return opp_table; +} +EXPORT_SYMBOL_GPL (devm_pm_opp_set_regulators); + +/** +* devm_pm_opp_set_supported_hw() - Set supported platforms +* @dev: Device for which supported-hw has to be set. +* @versions: Array of hierarchy of versions to match. +* @count: Number of elements in the array. +* +* This is a resource-managed version of dev_pm_opp_set_supported_hw(). +* +* Return: pointer to 'struct opp_table' on success and errorno otherwise. +*/ +struct opp_table * +devm_pm_opp_set_supported_hw (struct device *dev,const u32 *versions, +unsigned int count) +{ +struct opp_table *opp_table; +int err; + + opp_table =dev_pm_opp_set_supported_hw (dev, versions, count); +if (IS_ERR (opp_table)) +return opp_table; + + err =devm_add_action_or_reset (dev, (void *)dev_pm_opp_put_supported_hw, + opp_table); +if (err) +return ERR_PTR (err); + +return opp_table; +} +EXPORT_SYMBOL_GPL (devm_pm_opp_set_supported_hw); + +/** +* devm_pm_opp_set_clkname() - Set clk name for the device +* @dev: Device for which clk name is being set. +* @name: Clk name. +* +* This is a resource-managed version of dev_pm_opp_set_clkname(). +* +* Return: pointer to 'struct opp_table' on success and errorno otherwise. +*/ +struct opp_table * +devm_pm_opp_set_clkname (struct device *dev,const char *name) +{ +struct opp_table *opp_table; +int err; + + opp_table =dev_pm_opp_set_clkname (dev, name); +if (IS_ERR (opp_table)) +return opp_table; + + err =devm_add_action_or_reset (dev, (void *)dev_pm_opp_put_clkname, + opp_table); +if (err) +return ERR_PTR (err); + +return opp_table; +} +EXPORT_SYMBOL_GPL (devm_pm_opp_set_clkname); + +/** +* devm_pm_opp_register_set_opp_helper() - Register custom set OPP helper +* @dev: Device for which the helper is getting registered. +* @set_opp: Custom set OPP helper. +* +* This is a resource-managed version of dev_pm_opp_register_set_opp_helper(). +* +* Return: pointer to 'struct opp_table' on success and errorno otherwise. +*/ +struct opp_table * +devm_pm_opp_register_set_opp_helper (struct device *dev, +int (*set_opp)(struct dev_pm_set_opp_data *data)) +{ +struct opp_table *opp_table; +int err; + + opp_table =dev_pm_opp_register_set_opp_helper (dev, set_opp); +if (IS_ERR (opp_table)) +return opp_table; + + err =devm_add_action_or_reset (dev, (void *)dev_pm_opp_unregister_set_opp_helper, + opp_table); +if (err) +return ERR_PTR (err); + +return opp_table; +} +EXPORT_SYMBOL_GPL (devm_pm_opp_register_set_opp_helper); + +/** +* devm_pm_opp_attach_genpd - Attach genpd(s) for the device and save virtual device pointer +* @dev: Consumer device for which the genpd is getting attached. +* @names: Null terminated array of pointers containing names of genpd to attach. +* @virt_devs: Pointer to return the array of virtual devices. +* +* This is a resource-managed version of dev_pm_opp_attach_genpd(). +* +* Return: pointer to 'struct opp_table' on success and errorno otherwise. +*/ +struct opp_table * +devm_pm_opp_attach_genpd (struct device *dev,const char **names, +struct device ***virt_devs) +{ +struct opp_table *opp_table; +int err; + + opp_table =dev_pm_opp_attach_genpd (dev, names, virt_devs); +if (IS_ERR (opp_table)) +return opp_table; + + err =devm_add_action_or_reset (dev, (void *)dev_pm_opp_detach_genpd, + opp_table); +if (err) +return ERR_PTR (err); + +return opp_table; +} +EXPORT_SYMBOL_GPL (devm_pm_opp_attach_genpd);
drivers/opp/of.c +25 -0
@@ -1350,3 +1350,28 @@ int dev_pm_opp_of_register_em(struct device *dev, struct cpumask *cpus)return ret; }EXPORT_SYMBOL_GPL (dev_pm_opp_of_register_em); + +/** +* devm_pm_opp_of_add_table() - Initialize opp table from device tree +* @dev: device pointer used to lookup OPP table. +* +* This is a resource-managed version of dev_pm_opp_of_add_table(). +* +* Return: 0 on success and errorno otherwise. +*/ +int devm_pm_opp_of_add_table (struct device *dev) +{ +int err; + + err =dev_pm_opp_of_add_table (dev); +if (err) +return err; + + err =devm_add_action_or_reset (dev, (void *)dev_pm_opp_remove_table, + dev); +if (err) +return err; + +return 0 ; +} +EXPORT_SYMBOL_GPL (devm_pm_opp_of_add_table);
include/linux/pm_opp.h +51 -0
72 lines not on this page · raw message
Signature · 1 line
2.29.2
Re: [PATCH v2 13/48] opp: Add resource-managed versions of OPP API functions
Quoted 9 lines · Dmitry Osipenko
Add resource-managed versions of OPP API functions. This removes a need from drivers to store and manage OPP table pointers.
Signed-off-by Dmitry Osipenko <[email protected]>--- drivers/opp/core.c | 173 +++++++++++++++++++++++++++++++++++++++++ drivers/opp/of.c | 25 ++++++ include/linux/pm_opp.h | 51 ++++++++++++ 3 files changed, 249 insertions(+)
Please send a patchset of its own for this patch, along with updates to all the existing code that can make use of these.
Signature · 1 line
viresh
Re: [PATCH v2 13/48] opp: Add resource-managed versions of OPP API functions
22.12.2020 11:55, Viresh Kumar пишет:
Quoted 11 lines · Dmitry Osipenko
Quoted 9 lines
Add resource-managed versions of OPP API functions. This removes a need from drivers to store and manage OPP table pointers.
Signed-off-by Dmitry Osipenko <[email protected]>--- drivers/opp/core.c | 173 +++++++++++++++++++++++++++++++++++++++++ drivers/opp/of.c | 25 ++++++ include/linux/pm_opp.h | 51 ++++++++++++ 3 files changed, 249 insertions(+)
Quoted 3 lines
Please send a patchset of its own for this patch, along with updates to all the existing code that can make use of these.
ok
PATCH v2 14/48 opp: Filter out OPPs based on availability of a required-OPP
In reply to Dmitry OsipenkoA required OPP may not be available, and thus, all OPPs which are using this required OPP should be unavailable too.
--- drivers/opp/core.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-)
drivers/opp/core.c +10 -1
@@ -1588,7 +1588,7 @@ int _opp_add(struct device *dev, struct dev_pm_opp *new_opp, struct opp_table *opp_table, bool rate_not_available) {struct list_head *head; -int ret; +int i, ret;mutex_lock (&opp_table->lock); head = &opp_table->opp_list;
@@ -1615,6 +1615,15 @@ int _opp_add(struct device *dev, struct dev_pm_opp *new_opp, __func__, new_opp->rate); } +for (i =0 ; i < opp_table->required_opp_count && new_opp->available; i++) { +if (new_opp->required_opps[i]->available) +continue ; + + new_opp->available = false; +dev_warn (dev,"%s: OPP not supported by required OPP %pOF (%lu)\n" , + __func__, new_opp->required_opps[i]->np, new_opp->rate); + } +return 0 ; }
Signature · 1 line
2.29.2
Re: [PATCH v2 14/48] opp: Filter out OPPs based on availability of a required-OPP
Quoted 7 lines · Dmitry Osipenko
A required OPP may not be available, and thus, all OPPs which are using this required OPP should be unavailable too.
Signed-off-by Dmitry Osipenko <[email protected]>--- drivers/opp/core.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-)
Please send a separate patchset for fixes, as these can also go to 5.11 itself.
Quoted 14 lines
drivers/opp/core.c +1
-1@@ -1588,7 +1588,7 @@ int _opp_add(struct device *dev, struct dev_pm_opp *new_opp, struct opp_table *opp_table, bool rate_not_available) {struct list_head *head; -int ret; +int i, ret;mutex_lock (&opp_table->lock); head = &opp_table->opp_list;
drivers/opp/core.c int _opp_add(struct device *dev, struct dev_pm_opp *new_opp, · line 1624
Quoted 10 lines
drivers/opp/core.c +7
-0@@ -1615,6 +1615,15 @@ int _opp_add(struct device *dev, struct dev_pm_opp *new_opp, __func__, new_opp->rate); } +for (i =0 ; i < opp_table->required_opp_count && new_opp->available; i++) { +if (new_opp->required_opps[i]->available) +continue ; + + new_opp->available = false; +dev_warn (dev,"%s: OPP not supported by required OPP %pOF (%lu)\n" , + __func__, new_opp->required_opps[i]->np, new_opp->rate);
Why not just break from here ?
Quoted 7 lines
drivers/opp/core.c +2
-0+ } +return 0 ; }Signature · 1 line
2.29.2
Signature · 1 line
viresh
Re: [PATCH v2 14/48] opp: Filter out OPPs based on availability of a required-OPP
22.12.2020 11:59, Viresh Kumar пишет:
Quoted 10 lines · Dmitry Osipenko
Quoted 7 lines
A required OPP may not be available, and thus, all OPPs which are using this required OPP should be unavailable too.
Signed-off-by Dmitry Osipenko <[email protected]>--- drivers/opp/core.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-)Please send a separate patchset for fixes, as these can also go to 5.11 itself.
Alright, although I don't think that this patch fixes any problems for existing OPP users.
Quoted 17 lines
Quoted 17 lines
drivers/opp/core.c +1
-1@@ -1588,7 +1588,7 @@ int _opp_add(struct device *dev, struct dev_pm_opp *new_opp, struct opp_table *opp_table, bool rate_not_available) {struct list_head *head; -int ret; +int i, ret;mutex_lock (&opp_table->lock); head = &opp_table->opp_list;@@ -1615,6 +1615,15 @@ int _opp_add(struct device *dev, struct dev_pm_opp *new_opp, __func__, new_opp->rate); }
Quoted 9 lines
drivers/opp/core.c int _opp_add(struct device *dev, struct dev_pm_opp *new_opp, · line 1624
Quoted 7 lines
drivers/opp/core.c +7
-0+for (i =0 ; i < opp_table->required_opp_count && new_opp->available; i++) { +if (new_opp->required_opps[i]->available) +continue ; + + new_opp->available = false; +dev_warn (dev,"%s: OPP not supported by required OPP %pOF (%lu)\n" , + __func__, new_opp->required_opps[i]->np, new_opp->rate);Why not just break from here ?
The new_opp could be already marked as unavailable by a previous voltage check, hence this loop should be skipped entirely in that case.
Re: [PATCH v2 14/48] opp: Filter out OPPs based on availability of a required-OPP
Quoted 10 lines · Dmitry Osipenko
22.12.2020 11:59, Viresh Kumar пишет:
Quoted 9 lines · Dmitry Osipenko
Quoted 7 lines
A required OPP may not be available, and thus, all OPPs which are using this required OPP should be unavailable too.
Signed-off-by Dmitry Osipenko <[email protected]>--- drivers/opp/core.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-)
Quoted 4 lines
Quoted 1 line
Please send a separate patchset for fixes, as these can also go to 5.11 itself.
Alright, although I don't think that this patch fixes any problems for existing OPP users.
Because nobody is using this feature, but otherwise this is a fix for me.
Quoted 27 lines
Quoted 17 lines
Quoted 17 lines
drivers/opp/core.c +1
-1@@ -1588,7 +1588,7 @@ int _opp_add(struct device *dev, struct dev_pm_opp *new_opp, struct opp_table *opp_table, bool rate_not_available) {struct list_head *head; -int ret; +int i, ret;mutex_lock (&opp_table->lock); head = &opp_table->opp_list;@@ -1615,6 +1615,15 @@ int _opp_add(struct device *dev, struct dev_pm_opp *new_opp, __func__, new_opp->rate); }Quoted 9 lines
drivers/opp/core.c int _opp_add(struct device *dev, struct dev_pm_opp *new_opp, · line 1624
Quoted 7 lines
drivers/opp/core.c +7
-0+for (i =0 ; i < opp_table->required_opp_count && new_opp->available; i++) { +if (new_opp->required_opps[i]->available) +continue ; + + new_opp->available = false; +dev_warn (dev,"%s: OPP not supported by required OPP %pOF (%lu)\n" , + __func__, new_opp->required_opps[i]->np, new_opp->rate);Why not just break from here ?
Quoted 2 lines
The
new_oppcould be already marked as unavailable by a previous voltage check, hence this loop should be skipped entirely in that case.
Then add a separate check for that before the loop as we don't need that check on every iteration here.
Signature · 1 line
viresh
Re: [PATCH v2 14/48] opp: Filter out OPPs based on availability of a required-OPP
23.12.2020 07:22, Viresh Kumar пишет:
Quoted 45 lines · Dmitry Osipenko
Quoted 10 lines
22.12.2020 11:59, Viresh Kumar пишет:
Quoted 9 lines · Dmitry Osipenko
Quoted 7 lines
A required OPP may not be available, and thus, all OPPs which are using this required OPP should be unavailable too.
Signed-off-by Dmitry Osipenko <[email protected]>--- drivers/opp/core.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-)Quoted 4 lines
Quoted 1 line
Please send a separate patchset for fixes, as these can also go to 5.11 itself.
Alright, although I don't think that this patch fixes any problems for existing OPP users.
Because nobody is using this feature, but otherwise this is a fix for me.
Quoted 27 lines
Quoted 26 lines
Quoted 14 lines
drivers/opp/core.c +1
-1@@ -1588,7 +1588,7 @@ int _opp_add(struct device *dev, struct dev_pm_opp *new_opp, struct opp_table *opp_table, bool rate_not_available) {struct list_head *head; -int ret; +int i, ret;mutex_lock (&opp_table->lock); head = &opp_table->opp_list;drivers/opp/core.c int _opp_add(struct device *dev, struct dev_pm_opp *new_opp, · line 1624
Quoted 10 lines
drivers/opp/core.c +7
-0@@ -1615,6 +1615,15 @@ int _opp_add(struct device *dev, struct dev_pm_opp *new_opp, __func__, new_opp->rate); } +for (i =0 ; i < opp_table->required_opp_count && new_opp->available; i++) { +if (new_opp->required_opps[i]->available) +continue ; + + new_opp->available = false; +dev_warn (dev,"%s: OPP not supported by required OPP %pOF (%lu)\n" , + __func__, new_opp->required_opps[i]->np, new_opp->rate);Why not just break from here ?
Quoted 6 lines
Quoted 2 lines
The
new_oppcould be already marked as unavailable by a previous voltage check, hence this loop should be skipped entirely in that case.Then add a separate check for that before the loop as we don't need that check on every iteration here.
Perhaps the break will be a better option in this case, since it won't hurt at all to print the additional message even if OPP was already disabled by another check. I'll update it in next revision, thanks.
PATCH v2 15/48 opp: Support set_opp() customization without requiring to use regulators
In reply to Dmitry OsipenkoSupport set_opp() customization without requiring to use regulators. This is needed by drivers which want to use dev_pm_opp_set_rate() for changing rates of a multiple clocks and don't need to touch regulator.
One example is NVIDIA Tegra30/114 SoCs which have two sibling 3D hardware units which should be use to the same clock rate, meanwhile voltage scaling is done using a power domain. In this case OPP table doesn't have a regulator, causing a NULL dereference in _set_opp_custom().
--- drivers/opp/core.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-)
drivers/opp/core.c +12 -4
@@ -828,17 +828,25 @@ static int _set_opp_custom(const struct opp_table *opp_table,struct dev_pm_opp_supply *old_supply, struct dev_pm_opp_supply *new_supply) { - struct dev_pm_set_opp_data *data; + struct dev_pm_set_opp_data *data, tmp_data; +unsigned int regulator_count;int size; - data = opp_table->set_opp_data; +if (opp_table->set_opp_data) { + data = opp_table->set_opp_data; + regulator_count = opp_table->regulator_count; + }else { + data = &tmp_data; + regulator_count =0 ; + } + data->regulators = opp_table->regulators; - data->regulator_count = opp_table->regulator_count; + data->regulator_count = regulator_count; data->clk = opp_table->clk; data->dev = dev; data->old_opp.rate = old_freq; - size =sizeof (*old_supply) * opp_table->regulator_count; + size =sizeof (*old_supply) * regulator_count;if (!old_supply)memset (data->old_opp.supplies,0 , size);else
Signature · 1 line
2.29.2
Re: [PATCH v2 15/48] opp: Support set_opp() customization without requiring to use regulators
Quoted 38 lines · Dmitry Osipenko
Support
set_opp()customization without requiring to use regulators. This is needed by drivers which want to usedev_pm_opp_set_rate()for changing rates of a multiple clocks and don't need to touch regulator.One example is NVIDIA Tegra30/114 SoCs which have two sibling 3D hardware units which should be use to the same clock rate, meanwhile voltage scaling is done using a power domain. In this case OPP table doesn't have a regulator, causing a NULL dereference in
_set_opp_custom().Signed-off-by Dmitry Osipenko <[email protected]>--- drivers/opp/core.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-)drivers/opp/core.c +10
-3@@ -828,17 +828,25 @@ static int _set_opp_custom(const struct opp_table *opp_table,struct dev_pm_opp_supply *old_supply, struct dev_pm_opp_supply *new_supply) { - struct dev_pm_set_opp_data *data; + struct dev_pm_set_opp_data *data, tmp_data; +unsigned int regulator_count;int size; - data = opp_table->set_opp_data; +if (opp_table->set_opp_data) { + data = opp_table->set_opp_data; + regulator_count = opp_table->regulator_count; + }else { + data = &tmp_data; + regulator_count =0 ; + } + data->regulators = opp_table->regulators; - data->regulator_count = opp_table->regulator_count;
drivers/opp/core.c static int _set_opp_custom(const struct opp_table *opp_table, · line 852
Quoted 10 lines
drivers/opp/core.c +2
-1+ data->regulator_count = regulator_count; data->clk = opp_table->clk; data->dev = dev; data->old_opp.rate = old_freq; - size =sizeof (*old_supply) * opp_table->regulator_count; + size =sizeof (*old_supply) * regulator_count;if (!old_supply)memset (data->old_opp.supplies,0 , size);else
I don't see you making use of this in this patchset. How did you get this to crash ?
Signature · 1 line
viresh
Re: [PATCH v2 15/48] opp: Support set_opp() customization without requiring to use regulators
22.12.2020 12:01, Viresh Kumar пишет:
Quoted 43 lines · Dmitry Osipenko
Quoted 42 lines
Support
set_opp()customization without requiring to use regulators. This is needed by drivers which want to usedev_pm_opp_set_rate()for changing rates of a multiple clocks and don't need to touch regulator.One example is NVIDIA Tegra30/114 SoCs which have two sibling 3D hardware units which should be use to the same clock rate, meanwhile voltage scaling is done using a power domain. In this case OPP table doesn't have a regulator, causing a NULL dereference in
_set_opp_custom().Signed-off-by Dmitry Osipenko <[email protected]>--- drivers/opp/core.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-)drivers/opp/core.c +11
-3@@ -828,17 +828,25 @@ static int _set_opp_custom(const struct opp_table *opp_table,struct dev_pm_opp_supply *old_supply, struct dev_pm_opp_supply *new_supply) { - struct dev_pm_set_opp_data *data; + struct dev_pm_set_opp_data *data, tmp_data; +unsigned int regulator_count;int size; - data = opp_table->set_opp_data; +if (opp_table->set_opp_data) { + data = opp_table->set_opp_data; + regulator_count = opp_table->regulator_count; + }else { + data = &tmp_data; + regulator_count =0 ; + } + data->regulators = opp_table->regulators; - data->regulator_count = opp_table->regulator_count; + data->regulator_count = regulator_count; data->clk = opp_table->clk; data->dev = dev;
Quoted 10 lines
drivers/opp/core.c static int _set_opp_custom(const struct opp_table *opp_table, · line 852
Quoted 6 lines
drivers/opp/core.c +1
-1data->old_opp.rate = old_freq; - size =sizeof (*old_supply) * opp_table->regulator_count; + size =sizeof (*old_supply) * regulator_count;if (!old_supply)memset (data->old_opp.supplies,0 , size);else I don't see you making use of this in this patchset. How did you get this to crash ?
Please see patch 38 where 3d driver makes use ofdevm_pm_opp_register_set_opp_helper().
The opp_table->set_opp_data=NULL and opp_table->regulator_count=-1 if OPP table doesn't use a regulator, hence the crash happens.
Re: [PATCH v2 15/48] opp: Support set_opp() customization without requiring to use regulators
In reply to Dmitry OsipenkoQuoted 26 lines · Dmitry Osipenko
Support
set_opp()customization without requiring to use regulators. This is needed by drivers which want to usedev_pm_opp_set_rate()for changing rates of a multiple clocks and don't need to touch regulator.One example is NVIDIA Tegra30/114 SoCs which have two sibling 3D hardware units which should be use to the same clock rate, meanwhile voltage scaling is done using a power domain. In this case OPP table doesn't have a regulator, causing a NULL dereference in
_set_opp_custom().Signed-off-by Dmitry Osipenko <[email protected]>--- drivers/opp/core.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-)drivers/opp/core.c +2
-1@@ -828,17 +828,25 @@ static int _set_opp_custom(const struct opp_table *opp_table,struct dev_pm_opp_supply *old_supply, struct dev_pm_opp_supply *new_supply) { - struct dev_pm_set_opp_data *data; + struct dev_pm_set_opp_data *data, tmp_data; +unsigned int regulator_count;int size;
drivers/opp/core.c static int _set_opp_custom(const struct opp_table *opp_table, · line 842
Quoted 10 lines
drivers/opp/core.c +8
-1- data = opp_table->set_opp_data; +if (opp_table->set_opp_data) { + data = opp_table->set_opp_data; + regulator_count = opp_table->regulator_count; + }else { + data = &tmp_data; + regulator_count =0 ; + } +
We should use the same structure, you can add some checks but not replace the structure altogether.
Quoted 12 lines
drivers/opp/core.c +2
-2data->regulators = opp_table->regulators; - data->regulator_count = opp_table->regulator_count; + data->regulator_count = regulator_count; data->clk = opp_table->clk; data->dev = dev; data->old_opp.rate = old_freq; - size =sizeof (*old_supply) * opp_table->regulator_count; + size =sizeof (*old_supply) * regulator_count;if (!old_supply)memset (data->old_opp.supplies,0 , size);else
Signature · 1 line
viresh
Re: [PATCH v2 15/48] opp: Support set_opp() customization without requiring to use regulators
23.12.2020 09:01, Viresh Kumar пишет:
Quoted 28 lines · Dmitry Osipenko
Quoted 27 lines
Support
set_opp()customization without requiring to use regulators. This is needed by drivers which want to usedev_pm_opp_set_rate()for changing rates of a multiple clocks and don't need to touch regulator.One example is NVIDIA Tegra30/114 SoCs which have two sibling 3D hardware units which should be use to the same clock rate, meanwhile voltage scaling is done using a power domain. In this case OPP table doesn't have a regulator, causing a NULL dereference in
_set_opp_custom().Signed-off-by Dmitry Osipenko <[email protected]>--- drivers/opp/core.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-)drivers/opp/core.c +2
-1@@ -828,17 +828,25 @@ static int _set_opp_custom(const struct opp_table *opp_table,struct dev_pm_opp_supply *old_supply, struct dev_pm_opp_supply *new_supply) { - struct dev_pm_set_opp_data *data; + struct dev_pm_set_opp_data *data, tmp_data; +unsigned int regulator_count;int size;
Quoted 12 lines
drivers/opp/core.c static int _set_opp_custom(const struct opp_table *opp_table, · line 842
Quoted 9 lines
drivers/opp/core.c +8
-1- data = opp_table->set_opp_data; +if (opp_table->set_opp_data) { + data = opp_table->set_opp_data; + regulator_count = opp_table->regulator_count; + }else { + data = &tmp_data; + regulator_count =0 ; + } +We should use the same structure, you can add some checks but not replace the structure altogether.
Well, there is no "same structure", the opp_table->set_opp_data is NULL there.
I can re-write it like this if it looks better to you:
static int _set_opp_custom(...)
{
struct dev_pm_set_opp_data *data;
unsigned int regulator_count;
int size;+ if (!opp_table->set_opp_data) {
+ struct dev_pm_set_opp_data freq_data = {};
+
+ freq_data.dev = dev;
+ freq_data.clk = opp_table->clk;
+ freq_data.new_opp.rate = freq;
+ freq_data.old_opp.rate = old_freq;
+
+ return opp_table->set_opp(&freq_data);
+ }
Re: [PATCH v2 15/48] opp: Support set_opp() customization without requiring to use regulators
Quoted 2 lines · Dmitry Osipenko
Well, there is no "same structure", the
opp_table->set_opp_datais NULL there.
Right, I saw that yesterday. What I meant was that we need to start allocating the structure for this case now.
Signature · 1 line
viresh
Re: [PATCH v2 15/48] opp: Support set_opp() customization without requiring to use regulators
24.12.2020 07:10, Viresh Kumar пишет:
Quoted 7 lines · Dmitry Osipenko
Quoted 2 lines
Well, there is no "same structure", the
opp_table->set_opp_datais NULL there.Right, I saw that yesterday. What I meant was that we need to start allocating the structure for this case now.
Okay, that will be a bit bigger change than this v2. I'll try it implement yours suggestion in the next revision, thanks.
PATCH v2 16/48 opp: Handle missing OPP table in dev_pm_opp_xlate_performance_state()
In reply to Dmitry OsipenkoNVIDIA Tegra SoCs have a power domains topology such that child domains only clamp a power rail, while parent domain controls shared performance state of the multiple child domains. In this case child's domain doesn't need to have OPP table. Hence we want to allow children power domains to pass performance state to the parent domain if child's domain doesn't have OPP table.
The dev_pm_opp_xlate_performance_state() gets src_table=NULL if a child power domain doesn't have OPP table and in this case we should pass the performance state to the parent domain.
--- drivers/opp/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/opp/core.c +1 -1
@@ -2255,7 +2255,7 @@ int dev_pm_opp_xlate_performance_state(struct opp_table *src_table,* and so none of them have the "required-opps" property set. Return the * pstate of the src_table as it is in such cases. */ -if (!src_table->required_opp_count) +if (!src_table || !src_table->required_opp_count)return pstate;for (i =0 ; i < src_table->required_opp_count; i++) {
Signature · 1 line
2.29.2
PATCH v2 17/48 opp: Correct debug message in _opp_add_static_v2()
In reply to Dmitry OsipenkoThe debug message always prints rate=0 instead of a proper value, fix it.
--- drivers/opp/of.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/opp/of.c +2 -2
@@ -755,7 +755,6 @@ static struct dev_pm_opp *_opp_add_static_v2(struct opp_table *opp_table, struct device *dev, struct device_node *np) { struct dev_pm_opp *new_opp; -u64 rate =0 ;u32 val;int ret;bool rate_not_available = false;
@@ -772,7 +771,8 @@ static struct dev_pm_opp *_opp_add_static_v2(struct opp_table *opp_table,/* Check if the OPP supports hardware's hierarchy of versions or not */ if (!_opp_is_supported (dev, opp_table, np)) { -dev_dbg (dev,"OPP not supported by hardware: %llu\n" , rate); +dev_dbg (dev,"OPP not supported by hardware: %lu\n" , + new_opp->rate); goto free_opp; }
Signature · 1 line
2.29.2
PATCH v2 18/48 opp: Print OPP level in debug message of _opp_add_static_v2()
In reply to Dmitry OsipenkoPrint OPP level in debug message of _opp_add_static_v2(). This helps to chase GENPD bugs.
--- drivers/opp/of.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
drivers/opp/of.c +3 -2
@@ -822,10 +822,11 @@ static struct dev_pm_opp *_opp_add_static_v2(struct opp_table *opp_table,if (new_opp->clock_latency_ns > opp_table->clock_latency_ns_max) opp_table->clock_latency_ns_max = new_opp->clock_latency_ns; -pr_debug ("%s: turbo:%d rate:%lu uv:%lu uvmin:%lu uvmax:%lu latency:%lu\n" , +pr_debug ("%s: turbo:%d rate:%lu uv:%lu uvmin:%lu uvmax:%lu latency:%lu level:%u\n" , __func__, new_opp->turbo, new_opp->rate, new_opp->supplies[0 ].u_volt, new_opp->supplies[0 ].u_volt_min, - new_opp->supplies[0 ].u_volt_max, new_opp->clock_latency_ns); + new_opp->supplies[0 ].u_volt_max, new_opp->clock_latency_ns, + new_opp->level);/* * Notify the changes in the availability of the operable
Signature · 1 line
2.29.2
PATCH v2 19/48 opp: Fix adding OPP entries in a wrong order if rate is unavailable
In reply to Dmitry OsipenkoFix adding OPP entries in a wrong (opposite) order if OPP rate is unavailable. The OPP comparison is erroneously skipped if OPP rate is missing, thus OPPs are left unsorted.
--- drivers/opp/core.c | 23 ++++++++++++----------- drivers/opp/opp.h | 2 +- 2 files changed, 13 insertions(+), 12 deletions(-)
drivers/opp/core.c +12 -11
@@ -1531,9 +1531,10 @@ static bool _opp_supported_by_regulators(struct dev_pm_opp *opp,return true; } -int _opp_compare_key (struct dev_pm_opp *opp1,struct dev_pm_opp *opp2) +int _opp_compare_key (struct dev_pm_opp *opp1,struct dev_pm_opp *opp2, +bool rate_not_available) { -if (opp1->rate != opp2->rate) +if (!rate_not_available && opp1->rate != opp2->rate)return opp1->rate < opp2->rate ?-1 :1 ;if (opp1->bandwidth && opp2->bandwidth && opp1->bandwidth[0 ].peak != opp2->bandwidth[0 ].peak)
@@ -1545,7 +1546,8 @@ int _opp_compare_key(struct dev_pm_opp *opp1, struct dev_pm_opp *opp2)static int _opp_is_duplicate (struct device *dev,struct dev_pm_opp *new_opp,struct opp_table *opp_table, -struct list_head **head) +struct list_head **head, +bool rate_not_available) {struct dev_pm_opp *opp;int opp_cmp;
@@ -1559,13 +1561,13 @@ static int _opp_is_duplicate(struct device *dev, struct dev_pm_opp *new_opp,* loop. */ list_for_each_entry (opp, &opp_table->opp_list, node) { - opp_cmp =_opp_compare_key (new_opp, opp); + opp_cmp =_opp_compare_key (new_opp, opp, rate_not_available);if (opp_cmp >0 ) { *head = &opp->node;continue ; } -if (opp_cmp <0 ) +if (opp_cmp <0 || rate_not_available)return 0 ;/* Duplicate OPPs */
@@ -1601,12 +1603,11 @@ int _opp_add(struct device *dev, struct dev_pm_opp *new_opp,mutex_lock (&opp_table->lock); head = &opp_table->opp_list; -if (likely (!rate_not_available)) { - ret =_opp_is_duplicate (dev, new_opp, opp_table, &head); -if (ret) { -mutex_unlock (&opp_table->lock); -return ret; - } + ret =_opp_is_duplicate (dev, new_opp, opp_table, &head, + rate_not_available); +if (ret) { +mutex_unlock (&opp_table->lock); +return ret; }list_add (&new_opp->node, head);
drivers/opp/opp.h +1 -1
@@ -219,7 +219,7 @@ struct opp_table *_find_opp_table(struct device *dev);struct opp_device *_add_opp_dev (const struct device *dev,struct opp_table *opp_table);struct dev_pm_opp *_opp_allocate (struct opp_table *opp_table);void _opp_free (struct dev_pm_opp *opp); -int _opp_compare_key (struct dev_pm_opp *opp1,struct dev_pm_opp *opp2); +int _opp_compare_key (struct dev_pm_opp *opp1,struct dev_pm_opp *opp2,bool rate_not_available);int _opp_add (struct device *dev,struct dev_pm_opp *new_opp,struct opp_table *opp_table,bool rate_not_available);int _opp_add_v1 (struct opp_table *opp_table,struct device *dev,unsigned long freq,long u_volt,bool dynamic);void _dev_pm_opp_cpumask_remove_table (const struct cpumask *cpumask,int last_cpu);
Signature · 1 line
2.29.2
Re: [PATCH v2 19/48] opp: Fix adding OPP entries in a wrong order if rate is unavailable
Quoted 15 lines · Dmitry Osipenko
Fix adding OPP entries in a wrong (opposite) order if OPP rate is unavailable. The OPP comparison is erroneously skipped if OPP rate is missing, thus OPPs are left unsorted.
Signed-off-by Dmitry Osipenko <[email protected]>--- drivers/opp/core.c | 23 ++++++++++++----------- drivers/opp/opp.h | 2 +- 2 files changed, 13 insertions(+), 12 deletions(-)drivers/opp/core.c +0
-0
drivers/opp/core.c static bool _opp_supported_by_regulators(struct dev_pm_opp *opp, · line 1537
Quoted 9 lines
drivers/opp/core.c +3
-2@@ -1531,9 +1531,10 @@ static bool _opp_supported_by_regulators(struct dev_pm_opp *opp,return true; } -int _opp_compare_key (struct dev_pm_opp *opp1,struct dev_pm_opp *opp2) +int _opp_compare_key (struct dev_pm_opp *opp1,struct dev_pm_opp *opp2, +bool rate_not_available) { -if (opp1->rate != opp2->rate) +if (!rate_not_available && opp1->rate != opp2->rate)
rate will be 0 for both the OPPs here if rate_not_available is true and so this change shouldn't be required.
Quoted 17 lines
drivers/opp/core.c +2
-1return opp1->rate < opp2->rate ?-1 :1 ;if (opp1->bandwidth && opp2->bandwidth && opp1->bandwidth[0 ].peak != opp2->bandwidth[0 ].peak)@@ -1545,7 +1546,8 @@ int _opp_compare_key(struct dev_pm_opp *opp1, struct dev_pm_opp *opp2)static int _opp_is_duplicate (struct device *dev,struct dev_pm_opp *new_opp,struct opp_table *opp_table, -struct list_head **head) +struct list_head **head, +bool rate_not_available) {struct dev_pm_opp *opp;int opp_cmp;@@ -1559,13 +1561,13 @@ static int _opp_is_duplicate(struct device *dev, struct dev_pm_opp *new_opp,* loop. */ list_for_each_entry (opp, &opp_table->opp_list, node) {
drivers/opp/core.c static int _opp_is_duplicate(struct device *dev, struct dev_pm_opp *new_opp, · line 1571
Quoted 10 lines
drivers/opp/core.c +2
-2- opp_cmp =_opp_compare_key (new_opp, opp); + opp_cmp =_opp_compare_key (new_opp, opp, rate_not_available);if (opp_cmp >0 ) { *head = &opp->node;continue ; } -if (opp_cmp <0 ) +if (opp_cmp <0 || rate_not_available)return 0 ;
This shouldn't be required as well, isn't it ?
Quoted 4 lines
drivers/opp/core.c +0
-0/* Duplicate OPPs */ @@ -1601,12 +1603,11 @@ int _opp_add(struct device *dev, struct dev_pm_opp *new_opp,mutex_lock (&opp_table->lock);
drivers/opp/core.c int _opp_add(struct device *dev, struct dev_pm_opp *new_opp, · line 1607
Quoted 10 lines
drivers/opp/core.c +2
-6head = &opp_table->opp_list; -if (likely (!rate_not_available)) { - ret =_opp_is_duplicate (dev, new_opp, opp_table, &head); -if (ret) { -mutex_unlock (&opp_table->lock); -return ret; - } + ret =_opp_is_duplicate (dev, new_opp, opp_table, &head, + rate_not_available);
This is the only thing we need to do here I believe.
Quoted 21 lines
drivers/opp/core.c +3
-0+if (ret) { +mutex_unlock (&opp_table->lock); +return ret; }list_add (&new_opp->node, head);drivers/opp/opp.h +1
-1@@ -219,7 +219,7 @@ struct opp_table *_find_opp_table(struct device *dev);struct opp_device *_add_opp_dev (const struct device *dev,struct opp_table *opp_table);struct dev_pm_opp *_opp_allocate (struct opp_table *opp_table);void _opp_free (struct dev_pm_opp *opp); -int _opp_compare_key (struct dev_pm_opp *opp1,struct dev_pm_opp *opp2); +int _opp_compare_key (struct dev_pm_opp *opp1,struct dev_pm_opp *opp2,bool rate_not_available);int _opp_add (struct device *dev,struct dev_pm_opp *new_opp,struct opp_table *opp_table,bool rate_not_available);int _opp_add_v1 (struct opp_table *opp_table,struct device *dev,unsigned long freq,long u_volt,bool dynamic);void _dev_pm_opp_cpumask_remove_table (const struct cpumask *cpumask,int last_cpu);Signature · 1 line
2.29.2
Signature · 1 line
viresh
Re: [PATCH v2 19/48] opp: Fix adding OPP entries in a wrong order if rate is unavailable
22.12.2020 12:12, Viresh Kumar пишет:
Quoted 19 lines · Dmitry Osipenko
Quoted 18 lines
Fix adding OPP entries in a wrong (opposite) order if OPP rate is unavailable. The OPP comparison is erroneously skipped if OPP rate is missing, thus OPPs are left unsorted.
Signed-off-by Dmitry Osipenko <[email protected]>--- drivers/opp/core.c | 23 ++++++++++++----------- drivers/opp/opp.h | 2 +- 2 files changed, 13 insertions(+), 12 deletions(-)drivers/opp/core.c +0
-0@@ -1531,9 +1531,10 @@ static bool _opp_supported_by_regulators(struct dev_pm_opp *opp,return true; }
Quoted 9 lines
drivers/opp/core.c static bool _opp_supported_by_regulators(struct dev_pm_opp *opp, · line 1537
Quoted 6 lines
drivers/opp/core.c +3
-2-int _opp_compare_key (struct dev_pm_opp *opp1,struct dev_pm_opp *opp2) +int _opp_compare_key (struct dev_pm_opp *opp1,struct dev_pm_opp *opp2, +bool rate_not_available) { -if (opp1->rate != opp2->rate) +if (!rate_not_available && opp1->rate != opp2->rate)rate will be 0 for both the OPPs here if
rate_not_availableis true and so this change shouldn't be required.
The rate_not_available is negated in the condition. This change is required because both rates are 0 and then we should proceed to the levels comparison.
I guess it's not clear by looking at this patch, please see a full version of the function:
int _opp_compare_key(struct dev_pm_opp *opp1, struct dev_pm_opp *opp2,
bool rate_not_available)
{
if (!rate_not_available && opp1->rate != opp2->rate)
return opp1->rate < opp2->rate ? -1 : 1;
if (opp1->bandwidth && opp2->bandwidth &&
opp1->bandwidth[0].peak != opp2->bandwidth[0].peak)
return opp1->bandwidth[0].peak < opp2->bandwidth[0].peak ? -1 : 1;
if (opp1->level != opp2->level)
return opp1->level < opp2->level ? -1 : 1; return 0;
}
Perhaps we could check whether opp1->rate=0, like it's done for the opp1->bandwidth. I'll consider this variant for v3, thanks.
Re: [PATCH v2 19/48] opp: Fix adding OPP entries in a wrong order if rate is unavailable
Quoted 30 lines · Dmitry Osipenko
22.12.2020 12:12, Viresh Kumar пишет:
Quoted 19 lines · Dmitry Osipenko
Quoted 18 lines
Fix adding OPP entries in a wrong (opposite) order if OPP rate is unavailable. The OPP comparison is erroneously skipped if OPP rate is missing, thus OPPs are left unsorted.
Signed-off-by Dmitry Osipenko <[email protected]>--- drivers/opp/core.c | 23 ++++++++++++----------- drivers/opp/opp.h | 2 +- 2 files changed, 13 insertions(+), 12 deletions(-)drivers/opp/core.c +0
-0@@ -1531,9 +1531,10 @@ static bool _opp_supported_by_regulators(struct dev_pm_opp *opp,return true; }Quoted 9 lines
drivers/opp/core.c static bool _opp_supported_by_regulators(struct dev_pm_opp *opp, · line 1537
Quoted 6 lines
drivers/opp/core.c +3
-2-int _opp_compare_key (struct dev_pm_opp *opp1,struct dev_pm_opp *opp2) +int _opp_compare_key (struct dev_pm_opp *opp1,struct dev_pm_opp *opp2, +bool rate_not_available) { -if (opp1->rate != opp2->rate) +if (!rate_not_available && opp1->rate != opp2->rate)rate will be 0 for both the OPPs here if
rate_not_availableis true and so this change shouldn't be required.
Quoted 3 lines
The
rate_not_availableis negated in the condition. This change is required because both rates are 0 and then we should proceed to the levels comparison.
Won't that happen without this patch ?
Quoted 18 lines
I guess it's not clear by looking at this patch, please see a full version of the function:
int _opp_compare_key(struct
dev_pm_opp*opp1, structdev_pm_opp*opp2,
boolrate_not_available)
{
if (!rate_not_available &&opp1->rate!=opp2->rate)return opp1->rate < opp2->rate ? -1 : 1; if (opp1->bandwidth && opp2->bandwidth && opp1->bandwidth[0].peak != opp2->bandwidth[0].peak) return opp1->bandwidth[0].peak < opp2->bandwidth[0].peak ? -1 : 1; if (opp1->level != opp2->level) return opp1->level < opp2->level ? -1 : 1;return 0;
}Perhaps we could check whether opp1->rate=0, like it's done for the
opp1->bandwidth. I'll consider this variant for v3, thanks.
Signature · 1 line
viresh
Re: [PATCH v2 19/48] opp: Fix adding OPP entries in a wrong order if rate is unavailable
23.12.2020 07:34, Viresh Kumar пишет:
Quoted 31 lines · Dmitry Osipenko
Quoted 30 lines
22.12.2020 12:12, Viresh Kumar пишет:
Quoted 28 lines · Dmitry Osipenko
Quoted 15 lines
Fix adding OPP entries in a wrong (opposite) order if OPP rate is unavailable. The OPP comparison is erroneously skipped if OPP rate is missing, thus OPPs are left unsorted.
Signed-off-by Dmitry Osipenko <[email protected]>--- drivers/opp/core.c | 23 ++++++++++++----------- drivers/opp/opp.h | 2 +- 2 files changed, 13 insertions(+), 12 deletions(-)drivers/opp/core.c +0
-0drivers/opp/core.c static bool _opp_supported_by_regulators(struct dev_pm_opp *opp, · line 1537
Quoted 9 lines
drivers/opp/core.c +3
-2@@ -1531,9 +1531,10 @@ static bool _opp_supported_by_regulators(struct dev_pm_opp *opp,return true; } -int _opp_compare_key (struct dev_pm_opp *opp1,struct dev_pm_opp *opp2) +int _opp_compare_key (struct dev_pm_opp *opp1,struct dev_pm_opp *opp2, +bool rate_not_available) { -if (opp1->rate != opp2->rate) +if (!rate_not_available && opp1->rate != opp2->rate)rate will be 0 for both the OPPs here if
rate_not_availableis true and so this change shouldn't be required.
Quoted 5 lines
Quoted 3 lines
The
rate_not_availableis negated in the condition. This change is required because both rates are 0 and then we should proceed to the levels comparison.Won't that happen without this patch ?
No
Re: [PATCH v2 19/48] opp: Fix adding OPP entries in a wrong order if rate is unavailable
Quoted 6 lines · Dmitry Osipenko
23.12.2020 07:34, Viresh Kumar пишет:
Quoted 5 lines · Dmitry Osipenko
Quoted 4 lines
22.12.2020 12:12, Viresh Kumar пишет:
Quoted 2 lines
rate will be 0 for both the OPPs here if
rate_not_availableis true and so this change shouldn't be required.
Quoted 7 lines
Quoted 5 lines
Quoted 3 lines
The
rate_not_availableis negated in the condition. This change is required because both rates are 0 and then we should proceed to the levels comparison.Won't that happen without this patch ?
No
This is how the code looks like currently:
int _opp_compare_key(struct dev_pm_opp *opp1, struct dev_pm_opp *opp2)
{
if (opp1->rate != opp2->rate)
return opp1->rate < opp2->rate ? -1 : 1;
if (opp1->bandwidth && opp2->bandwidth &&
opp1->bandwidth[0].peak != opp2->bandwidth[0].peak)
return opp1->bandwidth[0].peak < opp2->bandwidth[0].peak ? -1 : 1;
if (opp1->level != opp2->level)
return opp1->level < opp2->level ? -1 : 1;
return 0;
}Lets consider the case you are focussing on, where rate is 0 for both the OPPs, bandwidth isn't there and we want to run the level comparison here.
Since both the rates are 0, (opp1->rate != opp2->rate) will fail and so we will move to bandwidth check which will fail too. And so we will get to the level comparison.
What am I missing here ? I am sure there is something for sure as you won't have missed this..
Signature · 1 line
viresh
Re: [PATCH v2 19/48] opp: Fix adding OPP entries in a wrong order if rate is unavailable
24.12.2020 09:28, Viresh Kumar пишет:
Quoted 32 lines · Dmitry Osipenko
Quoted 6 lines
23.12.2020 07:34, Viresh Kumar пишет:
Quoted 5 lines · Dmitry Osipenko
Quoted 4 lines
22.12.2020 12:12, Viresh Kumar пишет:
Quoted 2 lines
rate will be 0 for both the OPPs here if
rate_not_availableis true and so this change shouldn't be required.Quoted 7 lines
Quoted 5 lines
Quoted 3 lines
The
rate_not_availableis negated in the condition. This change is required because both rates are 0 and then we should proceed to the levels comparison.Won't that happen without this patch ?
No
This is how the code looks like currently:
int
_opp_compare_key(struct dev_pm_opp *opp1, struct dev_pm_opp *opp2){ if (opp1->rate != opp2->rate) return opp1->rate < opp2->rate ? -1 : 1; if (opp1->bandwidth && opp2->bandwidth && opp1->bandwidth[0].peak != opp2->bandwidth[0].peak) return opp1->bandwidth[0].peak < opp2->bandwidth[0].peak ? -1 : 1; if (opp1->level != opp2->level) return opp1->level < opp2->level ? -1 : 1; return 0; }Lets consider the case you are focussing on, where rate is 0 for both the OPPs, bandwidth isn't there and we want to run the level comparison here.
Quoted 7 lines
Since both the rates are 0, (
opp1->rate!=opp2->rate) will fail and so we will move to bandwidth check which will fail too. And so we will get to the level comparison.What am I missing here ? I am sure there is something for sure as you won't have missed this..
Ah, you're right. It was me who was missing something as I see now, after taking a closer look and trying to implement yours suggestion, my bad. I'll improve this patch in the next revision, thanks!
PATCH v2 20/48 PM: domains: Make set_performance_state() callback optional
In reply to Dmitry OsipenkoMake set_performance_state() callback optional in order to remove the need from power domain drivers to implement a dummy callback. If callback isn't implemented by a GENPD driver, then the performance state is passed to the parent domain.
--- drivers/base/power/domain.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-)
drivers/base/power/domain.c +5 -6
@@ -339,9 +339,11 @@ static int _genpd_set_performance_state(struct generic_pm_domain *genpd, goto err; } - ret = genpd->set_performance_state (genpd, state); -if (ret) - goto err; +if (genpd->set_performance_state) { + ret = genpd->set_performance_state (genpd, state); +if (ret) + goto err; + } genpd->performance_state = state;return 0 ;
@@ -399,9 +401,6 @@ int dev_pm_genpd_set_performance_state(struct device *dev, unsigned int state)if (!genpd)return -ENODEV ; -if (unlikely (!genpd->set_performance_state)) -return -EINVAL ; -if (WARN_ON (!dev->power.subsys_data || !dev->power.subsys_data->domain_data))return -EINVAL ;
Signature · 1 line
2.29.2
Re: [PATCH v2 20/48] PM: domains: Make set_performance_state() callback optional
Quoted 7 lines · Dmitry Osipenko
Make
set_performance_state()callback optional in order to remove the need from power domain drivers to implement a dummy callback. If callback isn't implemented by a GENPD driver, then the performance state is passed to the parent domain.Signed-off-by Dmitry Osipenko <[email protected]>
This should be ready to be picked up, but maybe it's easier if you could send this to the linux-pm mailing list separately. Then Rafael can pick it up.
Kind regards
Uffe
Quoted 36 lines
--- drivers/base/power/domain.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-)drivers/base/power/domain.c +5
-7@@ -339,9 +339,11 @@ static int _genpd_set_performance_state(struct generic_pm_domain *genpd, goto err; } - ret = genpd->set_performance_state (genpd, state); -if (ret) - goto err; +if (genpd->set_performance_state) { + ret = genpd->set_performance_state (genpd, state); +if (ret) + goto err; + } genpd->performance_state = state;return 0 ;@@ -399,9 +401,6 @@ int dev_pm_genpd_set_performance_state(struct device *dev, unsigned int state)if (!genpd)return -ENODEV ; -if (unlikely (!genpd->set_performance_state)) -return -EINVAL ; -if (WARN_ON (!dev->power.subsys_data || !dev->power.subsys_data->domain_data))return -EINVAL ; --2.29.2
PATCH v2 21/48 PM: domains: Add "performance" column to debug summary
In reply to Dmitry OsipenkoAdd "performance" column to debug summary which shows performance state of all power domains and theirs devices.
--- drivers/base/power/domain.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-)
drivers/base/power/domain.c +17 -5
@@ -2951,7 +2951,15 @@ static void rtpm_status_str(struct seq_file *s, struct device *dev)else WARN_ON (1 ); -seq_puts (s, p); +seq_printf (s,"%-25s " , p); +} + +static void perf_status_str (struct seq_file *s,struct device *dev) +{ +struct generic_pm_domain_data *gpd_data; + + gpd_data =to_gpd_data (dev->power.subsys_data->domain_data); +seq_put_decimal_ull (s,"" , gpd_data->performance_state); } static int genpd_summary_one(struct seq_file *s,
@@ -2979,7 +2987,7 @@ static int genpd_summary_one(struct seq_file *s,else snprintf (state,sizeof (state),"%s" , status_lookup[genpd->status]); -seq_printf (s,"%-30s %-15s " , genpd->name, state); +seq_printf (s,"%-30s %-50s %u" , genpd->name, state, genpd->performance_state);/* * Modifications on the list require holding locks on both
@@ -2987,7 +2995,10 @@ static int genpd_summary_one(struct seq_file *s,* Also genpd->name is immutable. */ list_for_each_entry (link, &genpd->parent_links, parent_node) { -seq_printf (s,"%s" , link->child->name); +if (list_is_first (&link->parent_node, &genpd->parent_links)) +seq_printf (s,"\n%50s " , link->child->name); +else +seq_printf (s,"%s" , link->child->name);if (!list_is_last (&link->parent_node, &genpd->parent_links))seq_puts (s,", " ); }
@@ -3001,6 +3012,7 @@ static int genpd_summary_one(struct seq_file *s,seq_printf (s,"\n %-50s " , kobj_path);rtpm_status_str (s, pm_data->dev); +perf_status_str (s, pm_data->dev);kfree (kobj_path); }
@@ -3016,9 +3028,9 @@ static int summary_show(struct seq_file *s, void *data)struct generic_pm_domain *genpd;int ret =0 ; -seq_puts (s,"domain status children\n" ); +seq_puts (s,"domain status children performance\n" );seq_puts (s," /device runtime status\n" ); -seq_puts (s,"----------------------------------------------------------------------\n" ); +seq_puts (s,"----------------------------------------------------------------------------------------------\n" ); ret =mutex_lock_interruptible (&gpd_list_lock);if (ret)
Signature · 1 line
2.29.2
Re: [PATCH v2 21/48] PM: domains: Add "performance" column to debug summary
Quoted 5 lines · Dmitry Osipenko
Add "performance" column to debug summary which shows performance state of all power domains and theirs devices.
Signed-off-by Dmitry Osipenko <[email protected]>
As I stated for patch 20, I suggest you resend this to the linux-pm mailing list so it can be picked up by Rafael.
Kind regards
Uffe
Quoted 69 lines
--- drivers/base/power/domain.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-)drivers/base/power/domain.c +17
-6@@ -2951,7 +2951,15 @@ static void rtpm_status_str(struct seq_file *s, struct device *dev)else WARN_ON (1 ); -seq_puts (s, p); +seq_printf (s,"%-25s " , p); +} + +static void perf_status_str (struct seq_file *s,struct device *dev) +{ +struct generic_pm_domain_data *gpd_data; + + gpd_data =to_gpd_data (dev->power.subsys_data->domain_data); +seq_put_decimal_ull (s,"" , gpd_data->performance_state); } static int genpd_summary_one(struct seq_file *s,@@ -2979,7 +2987,7 @@ static int genpd_summary_one(struct seq_file *s,else snprintf (state,sizeof (state),"%s" , status_lookup[genpd->status]); -seq_printf (s,"%-30s %-15s " , genpd->name, state); +seq_printf (s,"%-30s %-50s %u" , genpd->name, state, genpd->performance_state);/* * Modifications on the list require holding locks on both @@ -2987,7 +2995,10 @@ static int genpd_summary_one(struct seq_file *s,* Also genpd->name is immutable. */ list_for_each_entry (link, &genpd->parent_links, parent_node) { -seq_printf (s,"%s" , link->child->name); +if (list_is_first (&link->parent_node, &genpd->parent_links)) +seq_printf (s,"\n%50s " , link->child->name); +else +seq_printf (s,"%s" , link->child->name);if (!list_is_last (&link->parent_node, &genpd->parent_links))seq_puts (s,", " ); }@@ -3001,6 +3012,7 @@ static int genpd_summary_one(struct seq_file *s,seq_printf (s,"\n %-50s " , kobj_path);rtpm_status_str (s, pm_data->dev); +perf_status_str (s, pm_data->dev);kfree (kobj_path); }@@ -3016,9 +3028,9 @@ static int summary_show(struct seq_file *s, void *data)struct generic_pm_domain *genpd;int ret =0 ; -seq_puts (s,"domain status children\n" ); +seq_puts (s,"domain status children performance\n" );seq_puts (s," /device runtime status\n" ); -seq_puts (s,"----------------------------------------------------------------------\n" ); +seq_puts (s,"----------------------------------------------------------------------------------------------\n" ); ret =mutex_lock_interruptible (&gpd_list_lock);if (ret) --2.29.2
Re: [PATCH v2 21/48] PM: domains: Add "performance" column to debug summary
11.01.2021 12:13, Ulf Hansson пишет:
Quoted 11 lines · Dmitry Osipenko
Quoted 5 lines
Add "performance" column to debug summary which shows performance state of all power domains and theirs devices.
Signed-off-by Dmitry Osipenko <[email protected]>Reviewed-by Ulf Hansson <[email protected]>As I stated for patch 20, I suggest you resend this to the linux-pm mailing list so it can be picked up by Rafael.
Thanks, I'm finalizing v3 with various fixes and improvements over all the patches, including this one, which will get a slightly improved seq_printf formatting.
PATCH v2 22/48 soc/tegra: pmc: Fix imbalanced clock disabling in error code path
In reply to Dmitry OsipenkoThe tegra_powergate_power_up() has a typo in the error code path where it will try to disable clocks twice, fix it. In practice that error never happens, so this is a minor correction.
--- drivers/soc/tegra/pmc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/soc/tegra/pmc.c +1 -1
@@ -638,7 +638,7 @@ static int tegra_powergate_power_up(struct tegra_powergate *pg, err =tegra_powergate_enable_clocks (pg);if (err) - goto disable_clks; + goto powergate_off;usleep_range (10 ,20 );
Signature · 1 line
2.29.2
PATCH v2 23/48 soc/tegra: pmc: Pulse resets after removing power clamp
In reply to Dmitry OsipenkoThe GR3D1 hardware unit needs to pulse hardware reset after removing power clamp, otherwise reset won't be deasserted. Hence give reset a pulse after removing the clamp. This stayed unnoticed previously because power management wasn't supported by the 3D driver until recently and all power gates are usually ungated after bootloader by default.
--- drivers/soc/tegra/pmc.c | 8 ++++++++ 1 file changed, 8 insertions(+)
drivers/soc/tegra/pmc.c +8 -0
@@ -654,6 +654,14 @@ static int tegra_powergate_power_up(struct tegra_powergate *pg,usleep_range (10 ,20 ); +/* +* Some hardware blocks may need a 0->1->0 reset pulse in order +* to propagate the reset, Tegra30 3D1 is one example. +*/ + err =reset_control_reset (pg->reset); +if (err) + goto powergate_off; +if (pg->pmc->soc->needs_mbist_war) err =tegra210_clk_handle_mbist_war (pg->id);if (err)
Signature · 1 line
2.29.2
Re: [PATCH v2 23/48] soc/tegra: pmc: Pulse resets after removing power clamp
17.12.2020 21:06, Dmitry Osipenko пишет:
Quoted 21 lines
The GR3D1 hardware unit needs to pulse hardware reset after removing power clamp, otherwise reset won't be deasserted. Hence give reset a pulse after removing the clamp. This stayed unnoticed previously because power management wasn't supported by the 3D driver until recently and all power gates are usually ungated after bootloader by default.
Signed-off-by Dmitry Osipenko <[email protected]>--- drivers/soc/tegra/pmc.c | 8 ++++++++ 1 file changed, 8 insertions(+)drivers/soc/tegra/pmc.c +1
-0@@ -654,6 +654,14 @@ static int tegra_powergate_power_up(struct tegra_powergate *pg,usleep_range (10 ,20 ); +/*
drivers/soc/tegra/pmc.c static int tegra_powergate_power_up(struct tegra_powergate *pg, · line 667
Quoted 10 lines
drivers/soc/tegra/pmc.c +7
-0+* Some hardware blocks may need a 0->1->0 reset pulse in order +* to propagate the reset, Tegra30 3D1 is one example. +*/ + err =reset_control_reset (pg->reset); +if (err) + goto powergate_off; +if (pg->pmc->soc->needs_mbist_war) err =tegra210_clk_handle_mbist_war (pg->id);if (err)
After some more testing, I found that 3D1 is reset properly if its memory client is placed in reset before power domain is turned off. The memory client resetting is completely missed in v2. I'll improve it in v3 and then this PMC workaround-patch won't be needed anymore.
PATCH v2 24/48 soc/tegra: pmc: Ensure that clock rates aren't too high
In reply to Dmitry OsipenkoSwitch all clocks of a power domain to a safe rate which is suitable for all possible voltages in order to ensure that hardware constraints aren't violated when power domain state toggles.
--- drivers/soc/tegra/pmc.c | 92 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 90 insertions(+), 2 deletions(-)
drivers/soc/tegra/pmc.c +90 -2
@@ -237,6 +237,7 @@ struct tegra_powergate {unsigned int id;struct clk **clks;unsigned int num_clks; +unsigned long *clk_rates;struct reset_control *reset; };
@@ -586,6 +587,57 @@ static int __tegra_powergate_remove_clamping(struct tegra_pmc *pmc,return 0 ; } +static int tegra_powergate_prepare_clocks (struct tegra_powergate *pg) +{ +unsigned long safe_rate =100 *1000 *1000 ; +unsigned int i; +int err; + +for (i =0 ; i < pg->num_clks; i++) { + pg->clk_rates[i] =clk_get_rate (pg->clks[i]); + +if (!pg->clk_rates[i]) { + err = -EINVAL ; + goto out; + } + +if (pg->clk_rates[i] <= safe_rate) +continue ; + +/* +* We don't know whether voltage state is okay for the +* current clock rate, hence it's better to temporally +* switch clock to a safe rate which is suitable for +* all voltages, before enabling the clock. +*/ + err =clk_set_rate (pg->clks[i], safe_rate); +if (err) + goto out; + } + +return 0 ; + +out: +while (i--) +clk_set_rate (pg->clks[i], pg->clk_rates[i]); + +return err; +} + +static int tegra_powergate_unprepare_clocks (struct tegra_powergate *pg) +{ +unsigned int i; +int err; + +for (i =0 ; i < pg->num_clks; i++) { + err =clk_set_rate (pg->clks[i], pg->clk_rates[i]); +if (err) +return err; + } + +return 0 ; +} +static void tegra_powergate_disable_clocks (struct tegra_powergate *pg) {unsigned int i;
@@ -636,10 +688,14 @@ static int tegra_powergate_power_up(struct tegra_powergate *pg,usleep_range (10 ,20 ); - err =tegra_powergate_enable_clocks (pg); + err =tegra_powergate_prepare_clocks (pg);if (err) goto powergate_off; + err =tegra_powergate_enable_clocks (pg); +if (err) + goto unprepare_clks; +usleep_range (10 ,20 ); err =__tegra_powergate_remove_clamping (pg->pmc, pg->id);
@@ -670,12 +726,19 @@ static int tegra_powergate_power_up(struct tegra_powergate *pg,if (disable_clocks)tegra_powergate_disable_clocks (pg); + err =tegra_powergate_unprepare_clocks (pg); +if (err) +return err; +return 0 ; disable_clks:tegra_powergate_disable_clocks (pg);usleep_range (10 ,20 ); +unprepare_clks: +tegra_powergate_unprepare_clocks (pg); + powergate_off:tegra_powergate_set (pg->pmc, pg->id, false);
@@ -686,10 +749,14 @@ static int tegra_powergate_power_down(struct tegra_powergate *pg) {int err; - err =tegra_powergate_enable_clocks (pg); + err =tegra_powergate_prepare_clocks (pg);if (err)return err; + err =tegra_powergate_enable_clocks (pg); +if (err) + goto unprepare_clks; +usleep_range (10 ,20 ); err =reset_control_assert (pg->reset);
@@ -706,6 +773,10 @@ static int tegra_powergate_power_down(struct tegra_powergate *pg)if (err) goto assert_resets; + err =tegra_powergate_unprepare_clocks (pg); +if (err) +return err; +return 0 ; assert_resets:
@@ -717,6 +788,9 @@ static int tegra_powergate_power_down(struct tegra_powergate *pg) disable_clks:tegra_powergate_disable_clocks (pg); +unprepare_clks: +tegra_powergate_unprepare_clocks (pg); +return err; }
@@ -834,6 +908,12 @@ int tegra_powergate_sequence_power_up(unsigned int id, struct clk *clk,if (!pg)return -ENOMEM ; + pg->clk_rates =kzalloc (sizeof (*pg->clk_rates),GFP_KERNEL ); +if (!pg->clk_rates) { +kfree (pg->clks); +return -ENOMEM ; + } + pg->id = id; pg->clks = &clk; pg->num_clks =1 ;
@@ -845,6 +925,7 @@ int tegra_powergate_sequence_power_up(unsigned int id, struct clk *clk,dev_err (pmc->dev,"failed to turn on partition %d: %d\n" , id, err); +kfree (pg->clk_rates);kfree (pg);return err;
@@ -995,6 +1076,12 @@ static int tegra_powergate_of_get_clks(struct tegra_powergate *pg,if (!pg->clks)return -ENOMEM ; + pg->clk_rates =kcalloc (count,sizeof (*pg->clk_rates),GFP_KERNEL ); +if (!pg->clk_rates) { +kfree (pg->clks); +return -ENOMEM ; + } +for (i =0 ; i < count; i++) { pg->clks[i] =of_clk_get (np, i);if (IS_ERR (pg->clks[i])) {
@@ -1011,6 +1098,7 @@ static int tegra_powergate_of_get_clks(struct tegra_powergate *pg,while (i--)clk_put (pg->clks[i]); +kfree (pg->clk_rates);kfree (pg->clks);return err;
Signature · 1 line
2.29.2
PATCH v2 25/48 soc/tegra: pmc: Print out domain name when reset fails to acquire
In reply to Dmitry OsipenkoPrint out domain name when reset fails to acquire for debugging purposes and to make formatting of GENPD errors consistent in the driver.
--- drivers/soc/tegra/pmc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/soc/tegra/pmc.c +2 -1
@@ -821,7 +821,8 @@ static int tegra_genpd_power_off(struct generic_pm_domain *domain) err =reset_control_acquire (pg->reset);if (err <0 ) { -pr_err ("failed to acquire resets: %d\n" , err); +dev_err (dev,"failed to acquire resets for PM domain %s: %d\n" , + pg->genpd.name, err);return err; }
Signature · 1 line
2.29.2
PATCH v2 26/48 soc/tegra: Add devm_tegra_core_dev_init_opp_table()
In reply to Dmitry OsipenkoAdd common helper which initializes OPP table for Tegra SoC core devices.
--- drivers/soc/tegra/common.c | 137 +++++++++++++++++++++++++++++++++++++ include/soc/tegra/common.h | 35 ++++++++++ 2 files changed, 172 insertions(+)
drivers/soc/tegra/common.c +137 -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,133 @@ 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 +* @cfg: 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+ don'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 +35 -0
@@ -6,6 +6,41 @@#ifndef __SOC_TEGRA_COMMON_H__#define __SOC_TEGRA_COMMON_H__ +#include <linux/errno.h> +#include <linux/types.h> + +struct clk ; +struct device ; + +/** +* Tegra SoC core device OPP table configuration +* +* @dev: pointer to the core device +* @clkname: name of clock used for DVFS +* @init_state: pre-initialize OPP state of a device +*/ +struct tegra_core_opp_params { +struct device *dev; +const char *clkname; +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 *cfg); +#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 *cfg) +{ +return -ENODEV ; +} +#endif #endif /* __SOC_TEGRA_COMMON_H__ */
Signature · 1 line
2.29.2
PATCH v2 27/48 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 v2 28/48 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 in order to manage 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 | 125 ++++++++++++++++++++++++++ include/soc/tegra/common.h | 6 ++ 4 files changed, 138 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 +125 -0
125 lines not on this page · raw message
include/soc/tegra/common.h +6 -0
@@ -27,6 +27,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 *cfg);#else
@@ -35,6 +36,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 *cfg)
Signature · 1 line
2.29.2
Re: [PATCH v2 28/48] soc/tegra: Introduce core power domain driver
Quoted 15 lines · Dmitry Osipenko
+++
b/drivers/soc/tegra/core-power-domain.cdrivers/soc/tegra/core-power-domain.c new file +13
-0@@ -0,0 +1,125 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* +* NVIDIA Tegra SoC Core Power Domain Driver +*/ + +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/pm_domain.h> +#include <linux/pm_opp.h> +#include <linux/slab.h> + +#include <soc/tegra/common.h> +
drivers/soc/tegra/core-power-domain.c line 23
Quoted 10 lines
drivers/soc/tegra/core-power-domain.c new file +10
-0+static struct lock_class_key tegra_core_domain_lock_class; +static bool tegra_core_domain_state_synced; + +static int tegra_genpd_set_performance_state (struct generic_pm_domain *genpd, +unsigned int level) +{ +struct dev_pm_opp *opp; +int err; + + opp =dev_pm_opp_find_level_ceil (&genpd->dev, &level);
We don't need ceil or floor versions for level, but rather _exact() version. Or maybe just call it dev_pm_opp_find_level().
drivers/soc/tegra/core-power-domain.c line 30
Quoted 7 lines
drivers/soc/tegra/core-power-domain.c new file +7
-0+if (IS_ERR (opp)) { +dev_err (&genpd->dev,"failed to find OPP for level %u: %pe\n" , + level, opp); +return PTR_ERR (opp); + } + + err =dev_pm_opp_set_voltage (&genpd->dev, opp);
IIUC, you implemented this callback because you want to use the voltage triplet present in the OPP table ?
And so you are setting the regulator ("power") later in this patch ?
I am not in favor of implementing this routine, as it just adds a wrapper above the regulator API. What you should be doing rather is get the regulator by yourself here (instead of depending on the OPP core). And then you can do dev_pm_opp_get_voltage() here and set the voltage yourself. You may want to implement a version supporting triplet here though for the same.
And you won't require the sync version of the API as well then.
Signature · 1 line
viresh
Re: [PATCH v2 28/48] soc/tegra: Introduce core power domain driver
22.12.2020 09:40, Viresh Kumar пишет:
Quoted 21 lines · Dmitry Osipenko
Quoted 20 lines
+++
b/drivers/soc/tegra/core-power-domain.cdrivers/soc/tegra/core-power-domain.c new file +18
-0@@ -0,0 +1,125 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* +* NVIDIA Tegra SoC Core Power Domain Driver +*/ + +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/pm_domain.h> +#include <linux/pm_opp.h> +#include <linux/slab.h> + +#include <soc/tegra/common.h> + +static struct lock_class_key tegra_core_domain_lock_class; +static bool tegra_core_domain_state_synced; + +static int tegra_genpd_set_performance_state (struct generic_pm_domain *genpd, +unsigned int level)
Quoted 8 lines
drivers/soc/tegra/core-power-domain.c line 23
Quoted 5 lines
drivers/soc/tegra/core-power-domain.c new file +5
-0+{ +struct dev_pm_opp *opp; +int err; + + opp =dev_pm_opp_find_level_ceil (&genpd->dev, &level);We don't need ceil or floor versions for level, but rather
_exact()version. Or maybe just call itdev_pm_opp_find_level().
The _exact() version won't find OPP for level=0 if levels don't start with 0.
Quoted 11 lines
drivers/soc/tegra/core-power-domain.c line 30
Quoted 7 lines
drivers/soc/tegra/core-power-domain.c new file +7
-0+if (IS_ERR (opp)) { +dev_err (&genpd->dev,"failed to find OPP for level %u: %pe\n" , + level, opp); +return PTR_ERR (opp); + } + + err =dev_pm_opp_set_voltage (&genpd->dev, opp);IIUC, you implemented this callback because you want to use the voltage triplet present in the OPP table ?
Quoted 1 line
And so you are setting the regulator ("power") later in this patch ?
yes
Quoted 8 lines
I am not in favor of implementing this routine, as it just adds a wrapper above the regulator API. What you should be doing rather is get the regulator by yourself here (instead of depending on the OPP core). And then you can do
dev_pm_opp_get_voltage()here and set the voltage yourself. You may want to implement a version supporting triplet here though for the same.And you won't require the sync version of the API as well then.
That's what I initially did for this driver. I don't mind to revert back to the initial variant in v3, it appeared to me that it will be nicer and cleaner to have OPP API managing everything here.
Re: [PATCH v2 28/48] soc/tegra: Introduce core power domain driver
22.12.2020 22:21, Dmitry Osipenko пишет:
Quoted 19 lines
Quoted 11 lines
drivers/soc/tegra/core-power-domain.c line 30
Quoted 7 lines
drivers/soc/tegra/core-power-domain.c new file +7
-0+if (IS_ERR (opp)) { +dev_err (&genpd->dev,"failed to find OPP for level %u: %pe\n" , + level, opp); +return PTR_ERR (opp); + } + + err =dev_pm_opp_set_voltage (&genpd->dev, opp);IIUC, you implemented this callback because you want to use the voltage triplet present in the OPP table ?
And so you are setting the regulator ("power") later in this patch ?
yes
Quoted 6 lines
I am not in favor of implementing this routine, as it just adds a wrapper above the regulator API. What you should be doing rather is get the regulator by yourself here (instead of depending on the OPP core). And then you can do
dev_pm_opp_get_voltage()here and set the voltage yourself. You may want to implement a version supporting triplet here though for the same.
Quoted 5 lines
Quoted 2 lines
And you won't require the sync version of the API as well then.
That's what I initially did for this driver. I don't mind to revert back to the initial variant in v3, it appeared to me that it will be nicer and cleaner to have OPP API managing everything here.
I forgot one important detail (why the initial variant wasn't good).. OPP entries that have unsupportable voltages should be filtered out and OPP core performs the filtering only if regulator is assigned to the OPP table.
If regulator is assigned to the OPP table, then we need to use OPP API for driving the regulator, hence that's why I added dev_pm_opp_sync_regulators() and dev_pm_opp_set_voltage().
Perhaps it should be possible to add dev_pm_opp_get_regulator() that will return the OPP table regulator in order to allow driver to use the regulator directly. But I'm not sure whether this is a much better option than the opp_sync_regulators() and opp_set_voltage() APIs.
Re: [PATCH v2 28/48] soc/tegra: Introduce core power domain driver
Quoted 31 lines · Dmitry Osipenko
22.12.2020 22:21, Dmitry Osipenko пишет:
Quoted 19 lines
Quoted 11 lines
drivers/soc/tegra/core-power-domain.c line 30
Quoted 7 lines
drivers/soc/tegra/core-power-domain.c new file +7
-0+if (IS_ERR (opp)) { +dev_err (&genpd->dev,"failed to find OPP for level %u: %pe\n" , + level, opp); +return PTR_ERR (opp); + } + + err =dev_pm_opp_set_voltage (&genpd->dev, opp);IIUC, you implemented this callback because you want to use the voltage triplet present in the OPP table ?
And so you are setting the regulator ("power") later in this patch ?
yes
Quoted 6 lines
I am not in favor of implementing this routine, as it just adds a wrapper above the regulator API. What you should be doing rather is get the regulator by yourself here (instead of depending on the OPP core). And then you can do
dev_pm_opp_get_voltage()here and set the voltage yourself. You may want to implement a version supporting triplet here though for the same.Quoted 5 lines
Quoted 2 lines
And you won't require the sync version of the API as well then.
That's what I initially did for this driver. I don't mind to revert back to the initial variant in v3, it appeared to me that it will be nicer and cleaner to have OPP API managing everything here.
I forgot one important detail (why the initial variant wasn't good).. OPP entries that have unsupportable voltages should be filtered out and OPP core performs the filtering only if regulator is assigned to the OPP table.
Quoted 5 lines
If regulator is assigned to the OPP table, then we need to use OPP API for driving the regulator, hence that's why I added
dev_pm_opp_sync_regulators()anddev_pm_opp_set_voltage().Perhaps it should be possible to add
dev_pm_opp_get_regulator()that
What's wrong with getting the regulator in the driver as well ? Apart from the OPP core ?
Quoted 3 lines
will return the OPP table regulator in order to allow driver to use the regulator directly. But I'm not sure whether this is a much better option than the
opp_sync_regulators()andopp_set_voltage()APIs.
set_voltage() is still fine as there is some data that the OPP core has, but sync_regulator() has nothing to do with OPP core.
And this may lead to more wrapper helpers in the OPP core, which I am afraid of. And so even if it is not the best, I would like the OPP core to provide the data and not get into this. Ofcourse there is an exception to this, opp_set_rate.
Signature · 1 line
viresh
Re: [PATCH v2 28/48] soc/tegra: Introduce core power domain driver
23.12.2020 08:57, Viresh Kumar пишет:
Quoted 32 lines · Dmitry Osipenko
Quoted 31 lines
22.12.2020 22:21, Dmitry Osipenko пишет:
Quoted 19 lines
Quoted 11 lines
drivers/soc/tegra/core-power-domain.c line 30
Quoted 7 lines
drivers/soc/tegra/core-power-domain.c new file +7
-0+if (IS_ERR (opp)) { +dev_err (&genpd->dev,"failed to find OPP for level %u: %pe\n" , + level, opp); +return PTR_ERR (opp); + } + + err =dev_pm_opp_set_voltage (&genpd->dev, opp);IIUC, you implemented this callback because you want to use the voltage triplet present in the OPP table ?
And so you are setting the regulator ("power") later in this patch ?
yes
Quoted 6 lines
I am not in favor of implementing this routine, as it just adds a wrapper above the regulator API. What you should be doing rather is get the regulator by yourself here (instead of depending on the OPP core). And then you can do
dev_pm_opp_get_voltage()here and set the voltage yourself. You may want to implement a version supporting triplet here though for the same.Quoted 5 lines
Quoted 2 lines
And you won't require the sync version of the API as well then.
That's what I initially did for this driver. I don't mind to revert back to the initial variant in v3, it appeared to me that it will be nicer and cleaner to have OPP API managing everything here.
I forgot one important detail (why the initial variant wasn't good).. OPP entries that have unsupportable voltages should be filtered out and OPP core performs the filtering only if regulator is assigned to the OPP table.
Quoted 8 lines
Quoted 5 lines
If regulator is assigned to the OPP table, then we need to use OPP API for driving the regulator, hence that's why I added
dev_pm_opp_sync_regulators()anddev_pm_opp_set_voltage().Perhaps it should be possible to add
dev_pm_opp_get_regulator()thatWhat's wrong with getting the regulator in the driver as well ? Apart from the OPP core ?
The voltage syncing should be done for each consumer regulator individually [1].
Secondly, regulator core doesn't work well today if the same regulator is requested more than one time for the same device.
Quoted 11 lines
Quoted 3 lines
will return the OPP table regulator in order to allow driver to use the regulator directly. But I'm not sure whether this is a much better option than the
opp_sync_regulators()andopp_set_voltage()APIs.
set_voltage()is still fine as there is some data that the OPP core has, butsync_regulator()has nothing to do with OPP core.And this may lead to more wrapper helpers in the OPP core, which I am afraid of. And so even if it is not the best, I would like the OPP core to provide the data and not get into this. Ofcourse there is an exception to this,
opp_set_rate.
The regulator_sync_voltage() should be invoked only if voltage was changed previously [1].
The OPP core already has the info about whether voltage was changed and it provides the necessary locking for both set_voltage() and sync_regulator(). Perhaps I'll need to duplicate that functionality in the PD driver, instead of making it all generic and re-usable by other drivers.
[1]
https://elixir.bootlin.com/linux/v5.10.2/source/drivers/regulator/core.c#L4107
Re: [PATCH v2 28/48] soc/tegra: Introduce core power domain driver
23.12.2020 23:37, Dmitry Osipenko пишет:
Quoted 63 lines
23.12.2020 08:57, Viresh Kumar пишет:
Quoted 32 lines · Dmitry Osipenko
Quoted 31 lines
22.12.2020 22:21, Dmitry Osipenko пишет:
Quoted 19 lines
Quoted 11 lines
drivers/soc/tegra/core-power-domain.c line 30
Quoted 7 lines
drivers/soc/tegra/core-power-domain.c new file +7
-0+if (IS_ERR (opp)) { +dev_err (&genpd->dev,"failed to find OPP for level %u: %pe\n" , + level, opp); +return PTR_ERR (opp); + } + + err =dev_pm_opp_set_voltage (&genpd->dev, opp);IIUC, you implemented this callback because you want to use the voltage triplet present in the OPP table ?
And so you are setting the regulator ("power") later in this patch ?
yes
Quoted 6 lines
I am not in favor of implementing this routine, as it just adds a wrapper above the regulator API. What you should be doing rather is get the regulator by yourself here (instead of depending on the OPP core). And then you can do
dev_pm_opp_get_voltage()here and set the voltage yourself. You may want to implement a version supporting triplet here though for the same.Quoted 5 lines
Quoted 2 lines
And you won't require the sync version of the API as well then.
That's what I initially did for this driver. I don't mind to revert back to the initial variant in v3, it appeared to me that it will be nicer and cleaner to have OPP API managing everything here.
I forgot one important detail (why the initial variant wasn't good).. OPP entries that have unsupportable voltages should be filtered out and OPP core performs the filtering only if regulator is assigned to the OPP table.
Quoted 8 lines
Quoted 5 lines
If regulator is assigned to the OPP table, then we need to use OPP API for driving the regulator, hence that's why I added
dev_pm_opp_sync_regulators()anddev_pm_opp_set_voltage().Perhaps it should be possible to add
dev_pm_opp_get_regulator()thatWhat's wrong with getting the regulator in the driver as well ? Apart from the OPP core ?
The voltage syncing should be done for each consumer regulator individually [1].
Secondly, regulator core doesn't work well today if the same regulator is requested more than one time for the same device.
Quoted 11 lines
Quoted 3 lines
will return the OPP table regulator in order to allow driver to use the regulator directly. But I'm not sure whether this is a much better option than the
opp_sync_regulators()andopp_set_voltage()APIs.
set_voltage()is still fine as there is some data that the OPP core has, butsync_regulator()has nothing to do with OPP core.And this may lead to more wrapper helpers in the OPP core, which I am afraid of. And so even if it is not the best, I would like the OPP core to provide the data and not get into this. Ofcourse there is an exception to this,
opp_set_rate.The
regulator_sync_voltage()should be invoked only if voltage was changed previously [1].
Quoted 9 lines
The OPP core already has the info about whether voltage was changed and it provides the necessary locking for both
set_voltage()andsync_regulator(). Perhaps I'll need to duplicate that functionality in the PD driver, instead of making it all generic and re-usable by other drivers.[1]
https://elixir.bootlin.com/linux/v5.10.2/source/drivers/regulator/core.c#L4107
I just realized that the locking is missing in the v2 patches, something to fix in the next revision :)
Still I'm in favor of extending the OPP API with the new common functions. But if you have a strong opinion about that, then I'll try to work around it in the PD driver in v3.
Re: [PATCH v2 28/48] soc/tegra: Introduce core power domain driver
In reply to Dmitry OsipenkoQuoted 9 lines · Dmitry Osipenko
23.12.2020 08:57, Viresh Kumar пишет:
Quoted 2 lines
What's wrong with getting the regulator in the driver as well ? Apart from the OPP core ?
The voltage syncing should be done for each consumer regulator individually [1].
Secondly, regulator core doesn't work well today if the same regulator is requested more than one time for the same device.
Hmm...
Quoted 15 lines
Quoted 11 lines
Quoted 3 lines
will return the OPP table regulator in order to allow driver to use the regulator directly. But I'm not sure whether this is a much better option than the
opp_sync_regulators()andopp_set_voltage()APIs.
set_voltage()is still fine as there is some data that the OPP core has, butsync_regulator()has nothing to do with OPP core.And this may lead to more wrapper helpers in the OPP core, which I am afraid of. And so even if it is not the best, I would like the OPP core to provide the data and not get into this. Ofcourse there is an exception to this,
opp_set_rate.The
regulator_sync_voltage()should be invoked only if voltage was changed previously [1].
Quoted 8 lines
The OPP core already has the info about whether voltage was changed and it provides the necessary locking for both
set_voltage()andsync_regulator(). Perhaps I'll need to duplicate that functionality in the PD driver, instead of making it all generic and re-usable by other drivers.[1]
https://elixir.bootlin.com/linux/v5.10.2/source/drivers/regulator/core.c#L4107
Lets do it in the OPP core and see where we go.
Signature · 1 line
viresh
Re: [PATCH v2 28/48] soc/tegra: Introduce core power domain driver
24.12.2020 09:51, Viresh Kumar пишет:
Quoted 34 lines · Dmitry Osipenko
Quoted 9 lines
23.12.2020 08:57, Viresh Kumar пишет:
Quoted 2 lines
What's wrong with getting the regulator in the driver as well ? Apart from the OPP core ?
The voltage syncing should be done for each consumer regulator individually [1].
Secondly, regulator core doesn't work well today if the same regulator is requested more than one time for the same device.
Hmm...
Quoted 21 lines
Quoted 11 lines
Quoted 3 lines
will return the OPP table regulator in order to allow driver to use the regulator directly. But I'm not sure whether this is a much better option than the
opp_sync_regulators()andopp_set_voltage()APIs.
set_voltage()is still fine as there is some data that the OPP core has, butsync_regulator()has nothing to do with OPP core.And this may lead to more wrapper helpers in the OPP core, which I am afraid of. And so even if it is not the best, I would like the OPP core to provide the data and not get into this. Ofcourse there is an exception to this,
opp_set_rate.The
regulator_sync_voltage()should be invoked only if voltage was changed previously [1].The OPP core already has the info about whether voltage was changed and it provides the necessary locking for both
set_voltage()andsync_regulator(). Perhaps I'll need to duplicate that functionality in the PD driver, instead of making it all generic and re-usable by other drivers.
Quoted 5 lines
Lets do it in the OPP core and see where we go.
Alright, thank you.
Re: [PATCH v2 28/48] soc/tegra: Introduce core power domain driver
In reply to Dmitry OsipenkoQuoted 9 lines · Dmitry Osipenko
NVIDIA 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 in order to manage the voltage state of the domain. This allows us to support a system-wide DVFS on Tegra.
Signed-off-by Dmitry Osipenko <[email protected]>
FYI: from a genpd provider driver point of view, this looks good to me. However, withholding my ack for the next version, just to make sure I take a second look.
Kind regards
Uffe
Quoted 203 lines
--- drivers/soc/tegra/Kconfig | 6 ++ drivers/soc/tegra/Makefile | 1 + drivers/soc/tegra/core-power-domain.c | 125 ++++++++++++++++++++++++++ include/soc/tegra/common.h | 6 ++ 4 files changed, 138 insertions(+) create mode 100644 drivers/soc/tegra/core-power-domain.cdrivers/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_DOMAINSdrivers/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.odrivers/soc/tegra/core-power-domain.c new file +125
-0@@ -0,0 +1,125 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* +* NVIDIA Tegra SoC Core Power Domain Driver +*/ + +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/pm_domain.h> +#include <linux/pm_opp.h> +#include <linux/slab.h> + +#include <soc/tegra/common.h> + +static struct lock_class_key tegra_core_domain_lock_class; +static bool tegra_core_domain_state_synced; + +static int tegra_genpd_set_performance_state (struct generic_pm_domain *genpd, +unsigned int level) +{ +struct dev_pm_opp *opp; +int err; + + opp =dev_pm_opp_find_level_ceil (&genpd->dev, &level); +if (IS_ERR (opp)) { +dev_err (&genpd->dev,"failed to find OPP for level %u: %pe\n" , + level, opp); +return PTR_ERR (opp); + } + + err =dev_pm_opp_set_voltage (&genpd->dev, opp); +dev_pm_opp_put (opp); + +if (err) { +dev_err (&genpd->dev,"failed to set voltage to %duV: %d\n" , + level, err); +return err; + } + +return 0 ; +} + +static unsigned int +tegra_genpd_opp_to_performance_state (struct generic_pm_domain *genpd, +struct dev_pm_opp *opp) +{ +return dev_pm_opp_get_level (opp); +} + +static int tegra_core_domain_probe (struct platform_device *pdev) +{ +struct generic_pm_domain *genpd; +struct opp_table *opp_table; +const char *rname ="power" ; +int err; + + genpd =devm_kzalloc (&pdev->dev,sizeof (*genpd),GFP_KERNEL ); +if (!genpd) +return -ENOMEM ; + + genpd->name = pdev->dev.of_node->name; + genpd->set_performance_state = tegra_genpd_set_performance_state; + genpd->opp_to_performance_state = tegra_genpd_opp_to_performance_state; + + opp_table =devm_pm_opp_set_regulators (&pdev->dev, &rname,1 ); +if (IS_ERR (opp_table)) +return dev_err_probe (&pdev->dev,PTR_ERR (opp_table), +"failed to set OPP regulator\n" ); + + err =pm_genpd_init (genpd,NULL , false); +if (err) { +dev_err (&pdev->dev,"failed to init genpd: %d\n" , err); +return err; + } + +/* +* We have a "PMC -> Core" hierarchy of the power domains where +* PMC needs to resume and change performance (voltage) of the +* Core domain from the PMC GENPD on/off callbacks, hence we need +* to annotate the lock in order to remove confusion from the +* lockdep checker when a nested access happens. +*/ +lockdep_set_class (&genpd->mlock, &tegra_core_domain_lock_class); + + err =of_genpd_add_provider_simple (pdev->dev.of_node, genpd); +if (err) { +dev_err (&pdev->dev,"failed to add genpd: %d\n" , err); + goto remove_genpd; + } + +return 0 ; + +remove_genpd: +pm_genpd_remove (genpd); + +return err; +} + +bool tegra_soc_core_domain_state_synced (void ) +{ +return tegra_core_domain_state_synced; +} + +static void tegra_core_domain_sync_state (struct device *dev) +{ + tegra_core_domain_state_synced = true; + +dev_pm_opp_sync_regulators (dev); +} + +static const struct of_device_id tegra_core_domain_match[] = { + { .compatible ="nvidia,tegra20-core-domain" , }, + { .compatible ="nvidia,tegra30-core-domain" , }, + { } +}; + +static struct platform_driver tegra_core_domain_driver = { + .driver = { + .name ="tegra-core-power" , + .of_match_table = tegra_core_domain_match, + .suppress_bind_attrs = true, + .sync_state = tegra_core_domain_sync_state, + }, + .probe = tegra_core_domain_probe, +}; +builtin_platform_driver (tegra_core_domain_driver);include/soc/tegra/common.h +6
-1@@ -27,6 +27,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 *cfg);#else @@ -35,6 +36,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 *cfg) --2.29.2
PATCH v2 29/48 soc/tegra: pmc: Link domains to the parent Core 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 PMC domain.
--- drivers/soc/tegra/pmc.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+)
drivers/soc/tegra/pmc.c +19 -0
@@ -1236,6 +1236,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 ;
@@ -1249,6 +1250,24 @@ 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) { +if (err == -ENOENT ) + err = -EPROBE_DEFER ; + +of_node_put (child); +break ; + } }of_node_put (np);
Signature · 1 line
2.29.2
Re: [PATCH v2 29/48] soc/tegra: pmc: Link domains to the parent Core domain
- trimmed cc-list
Quoted 33 lines · Dmitry Osipenko
The 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 PMC domain.
Signed-off-by Dmitry Osipenko <[email protected]>--- drivers/soc/tegra/pmc.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+)drivers/soc/tegra/pmc.c +5
-0@@ -1236,6 +1236,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 ;@@ -1249,6 +1250,24 @@ 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))
drivers/soc/tegra/pmc.c static int tegra_powergate_init(struct tegra_pmc *pmc, · line 1266
Quoted 10 lines
drivers/soc/tegra/pmc.c +10
-0+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) { +if (err == -ENOENT ) + err = -EPROBE_DEFER ;
Okay. So this special error treatment is needed because of_genpd_add_subdomain may return -ENOENT, in case the providers for the parent-domain and child-domain haven't been registered yet.
I suggest we move this into of_genpd_add_subdomain() instead, thus letting it return -EPROBE_DEFER when there are parent/child nodes specified in DT, but the providers are lacking.
Quoted 10 lines
drivers/soc/tegra/pmc.c +4
-1+ +of_node_put (child); +break ; + } }of_node_put (np); --2.29.2
Kind regards
Uffe
Re: [PATCH v2 29/48] soc/tegra: pmc: Link domains to the parent Core domain
12.01.2021 16:30, Ulf Hansson пишет:
Quoted 51 lines
- trimmed cc-list
Quoted 33 lines · Dmitry Osipenko
The 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 PMC domain.
Signed-off-by Dmitry Osipenko <[email protected]>--- drivers/soc/tegra/pmc.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+)drivers/soc/tegra/pmc.c +5
-0@@ -1236,6 +1236,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 ;@@ -1249,6 +1250,24 @@ 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))drivers/soc/tegra/pmc.c static int tegra_powergate_init(struct tegra_pmc *pmc, · line 1266
Quoted 10 lines
drivers/soc/tegra/pmc.c +10
-0+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) { +if (err == -ENOENT ) + err = -EPROBE_DEFER ;Okay. So this special error treatment is needed because
of_genpd_add_subdomainmay return-ENOENT, in case the providers for the parent-domain and child-domain haven't been registered yet.
Quoted 3 lines
I suggest we move this into
of_genpd_add_subdomain()instead, thus letting it return -EPROBE_DEFER when there are parent/child nodes specified in DT, but the providers are lacking.
Alright
PATCH v2 30/48 soc/tegra: regulators: Fix locking up when voltage-spread is out of range
In reply to Dmitry OsipenkoFix voltage coupler lockup which happens when voltage-spread is out of range due to a bug in the code. The max-spread requirement shall be accounted when CPU regulator doesn't have consumers. This problem is observed on Tegra30 Ouya game console once system-wide DVFS is enabled in a device-tree.
--- drivers/soc/tegra/regulators-tegra30.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/soc/tegra/regulators-tegra30.c +1 -1
@@ -178,7 +178,7 @@ static int tegra30_voltage_update(struct tegra_regulator_coupler *tegra,* survive the voltage drop if it's running on a higher frequency. */ if (!cpu_min_uV_consumers) - cpu_min_uV = cpu_uV; + cpu_min_uV =max (cpu_uV, cpu_min_uV);/* * Bootloader shall set up voltages correctly, but if it
Signature · 1 line
2.29.2
PATCH v2 31/48 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.
--- 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
Re: [PATCH v2 31/48] soc/tegra: regulators: Support Core domain state syncing
Quoted 9 lines · Dmitry Osipenko
The 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.
Signed-off-by Dmitry Osipenko <[email protected]>
This looks reasonable to me, feel free to add:
Kind regards
Uffe
Quoted 95 lines
--- 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
-2@@ -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; } --2.29.2
PATCH v2 32/48 clk: tegra: Support runtime PM, power domain and OPP
In reply to Dmitry OsipenkoThe Clock-and-Reset controller resides in a "core" power domain on NVIDIA Tegra SoCs. In order to support voltage scaling of the core power rail, we need to hook up some clocks (which can't operate properly on a lower voltages above certain clock rates) to the core power domain in order to ensure that a proper core voltage is maintained.
The clocks are registered very early during kernel boot when the driver core isn't available yet. Hence clk-device can't be created very early and we need to split the registration of the clocks in two phases:
1. Register all essential clocks which don't use RPM and may be needed during early boot.
2. Register all clocks that use RPM (and not needed early) at a later boot time, once driver core is available.
That's the reason why this patch reshuffles registration of a few clocks.
--- drivers/clk/tegra/Makefile | 1 + drivers/clk/tegra/clk-device.c | 222 +++++++++++++++++++++++++++ drivers/clk/tegra/clk-divider.c | 2 +- drivers/clk/tegra/clk-periph-gate.c | 2 +- drivers/clk/tegra/clk-periph.c | 2 +- drivers/clk/tegra/clk-pll.c | 2 +- drivers/clk/tegra/clk-super.c | 4 +- drivers/clk/tegra/clk-tegra-periph.c | 140 ++++++++++++----- drivers/clk/tegra/clk-tegra114.c | 1 + drivers/clk/tegra/clk-tegra124.c | 1 + drivers/clk/tegra/clk-tegra20-emc.c | 2 +- drivers/clk/tegra/clk-tegra20.c | 123 ++++++++------- drivers/clk/tegra/clk-tegra210.c | 1 + drivers/clk/tegra/clk-tegra30.c | 133 ++++++++-------- drivers/clk/tegra/clk.c | 89 +++++++++++ drivers/clk/tegra/clk.h | 7 + 16 files changed, 568 insertions(+), 164 deletions(-) create mode 100644 drivers/clk/tegra/clk-device.c
drivers/clk/tegra/Makefile +1 -0
@@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 obj-y += clk.o obj-y += clk-audio-sync.o +obj-y += clk-device.o obj-y += clk-dfll.o obj-y += clk-divider.o obj-y += clk-periph.o
drivers/clk/tegra/clk-device.c new file +222 -0
222 lines not on this page · raw message
drivers/clk/tegra/clk-divider.c +1 -1
@@ -163,7 +163,7 @@ struct clk *tegra_clk_register_divider(const char *name,/* Data in .init is copied by clk_register(), so stack variable OK */ divider->hw.init = &init; - clk =clk_register (NULL , ÷r->hw); + clk =tegra_clk_register (÷r->hw);if (IS_ERR (clk))kfree (divider);
drivers/clk/tegra/clk-periph-gate.c +1 -1
@@ -176,7 +176,7 @@ struct clk *tegra_clk_register_periph_gate(const char *name,/* Data in .init is copied by clk_register(), so stack variable OK */ gate->hw.init = &init; - clk =clk_register (NULL , &gate->hw); + clk =tegra_clk_register (&gate->hw);if (IS_ERR (clk))kfree (gate);
drivers/clk/tegra/clk-periph.c +1 -1
@@ -195,7 +195,7 @@ static struct clk *_tegra_clk_register_periph(const char *name, periph->gate.regs = bank; periph->gate.enable_refcnt = periph_clk_enb_refcnt; - clk =clk_register (NULL , &periph->hw); + clk =tegra_clk_register (&periph->hw);if (IS_ERR (clk))return clk;
drivers/clk/tegra/clk-pll.c +1 -1
@@ -1911,7 +1911,7 @@ static struct clk *_tegra_clk_register_pll(struct tegra_clk_pll *pll,/* Data in .init is copied by clk_register(), so stack variable OK */ pll->hw.init = &init; -return clk_register (NULL , &pll->hw); +return tegra_clk_register (&pll->hw); } struct clk *tegra_clk_register_pll(const char *name, const char *parent_name,
drivers/clk/tegra/clk-super.c +2 -2
@@ -226,7 +226,7 @@ struct clk *tegra_clk_register_super_mux(const char *name,/* Data in .init is copied by clk_register(), so stack variable OK */ super->hw.init = &init; - clk =clk_register (NULL , &super->hw); + clk =tegra_clk_register (&super->hw);if (IS_ERR (clk))kfree (super);
@@ -266,7 +266,7 @@ struct clk *tegra_clk_register_super_clk(const char *name,/* Data in .init is copied by clk_register(), so stack variable OK */ super->hw.init = &init; - clk =clk_register (NULL , &super->hw); + clk =tegra_clk_register (&super->hw);if (IS_ERR (clk))kfree (super);
drivers/clk/tegra/clk-tegra-periph.c +102 -38
243 lines not on this page · raw message
drivers/clk/tegra/clk-tegra114.c +1 -0
@@ -1069,6 +1069,7 @@ static __init void tegra114_periph_clk_init(void __iomem *clk_base,tegra_periph_clk_init (clk_base, pmc_base, tegra114_clks, &pll_p_params); +tegra_periph_clk_rpm_init (clk_base, tegra114_clks); }/* Tegra114 CPU clock and reset control functions */
drivers/clk/tegra/clk-tegra124.c +1 -0
@@ -1081,6 +1081,7 @@ static __init void tegra124_periph_clk_init(void __iomem *clk_base, }tegra_periph_clk_init (clk_base, pmc_base, tegra124_clks, &pll_p_params); +tegra_periph_clk_rpm_init (clk_base, tegra124_clks); } static void __init tegra124_pll_init(void __iomem *clk_base,
drivers/clk/tegra/clk-tegra20-emc.c +1 -1
@@ -270,7 +270,7 @@ struct clk *tegra20_clk_register_emc(void __iomem *ioaddr, bool low_jitter) emc->hw.init = &init; emc->want_low_jitter = low_jitter; - clk =clk_register (NULL , &emc->hw); + clk =tegra_clk_register (&emc->hw);if (IS_ERR (clk)) {kfree (emc);return NULL ;
drivers/clk/tegra/clk-tegra20.c +65 -58
185 lines not on this page · raw message
drivers/clk/tegra/clk-tegra210.c +1 -0
@@ -3131,6 +3131,7 @@ static __init void tegra210_periph_clk_init(struct device_node *np, }tegra_periph_clk_init (clk_base, pmc_base, tegra210_clks, &pll_p_params); +tegra_periph_clk_rpm_init (clk_base, tegra210_clks);/* emc */ clk =tegra210_clk_register_emc (np, clk_base);
drivers/clk/tegra/clk-tegra30.c +72 -61
185 lines not on this page · raw message
drivers/clk/tegra/clk.c +89 -0
118 lines not on this page · raw message
drivers/clk/tegra/clk.h +7 -0
@@ -869,6 +869,9 @@ void tegra_periph_clk_init(void __iomem *clk_base, void __iomem *pmc_base,struct tegra_clk *tegra_clks, struct tegra_clk_pll_params *pll_params); +void tegra_periph_clk_rpm_init (void __iomem *clk_base, +struct tegra_clk *tegra_clks); +void tegra_fixed_clk_init (struct tegra_clk *tegra_clks); int tegra_osc_clk_init(void __iomem *clk_base, struct tegra_clk *clks, unsigned long *input_freqs, unsigned int num,
@@ -907,6 +910,8 @@ void tegra114_clock_deassert_dfll_dvco_reset(void);typedef void (*tegra_clk_apply_init_table_func )(void );extern tegra_clk_apply_init_table_func tegra_clk_apply_init_table; +typedef void (*tegra_clk_apply_rpm_init_table_func )(void ); +extern tegra_clk_apply_rpm_init_table_func tegra_clk_apply_rpm_clocks;int tegra_pll_wait_for_lock (struct tegra_clk_pll *pll);u16 tegra_pll_get_fixed_mdiv (struct clk_hw *hw,unsigned long input_rate);int tegra_pll_p_div_to_hw (struct tegra_clk_pll *pll,u8 p_div);
@@ -931,4 +936,6 @@ struct clk *tegra20_clk_register_emc(void __iomem *ioaddr, bool low_jitter);struct clk *tegra210_clk_register_emc (struct device_node *np,void __iomem *regs); +struct clk *tegra_clk_register (struct clk_hw *hw); +#endif /* TEGRA_CLK_H */
Signature · 1 line
2.29.2
PATCH v2 33/48 gpu: host1x: Add host1x_channel_stop()
In reply to Dmitry OsipenkoAdd host1x_channel_stop() which waits till channel becomes idle and then stops the channel hardware. This is needed for supporting suspend/resume by host1x drivers since the hardware state is lost after power-gating, thus the channel needs to be stopped before entering into suspend.
--- drivers/gpu/host1x/channel.c | 8 ++++++++ include/linux/host1x.h | 1 + 2 files changed, 9 insertions(+)
drivers/gpu/host1x/channel.c +8 -0
@@ -75,6 +75,14 @@ struct host1x_channel *host1x_channel_get_index(struct host1x *host,return ch; } +void host1x_channel_stop (struct host1x_channel *channel) +{ +struct host1x *host =dev_get_drvdata (channel->dev->parent); + +host1x_hw_cdma_stop (host, &channel->cdma); +} +EXPORT_SYMBOL (host1x_channel_stop); +static void release_channel (struct kref *kref) { struct host1x_channel *channel =
include/linux/host1x.h +1 -0
@@ -167,6 +167,7 @@ struct host1x_job;struct host1x_channel *host1x_channel_request (struct host1x_client *client);struct host1x_channel *host1x_channel_get (struct host1x_channel *channel); +void host1x_channel_stop (struct host1x_channel *channel);void host1x_channel_put (struct host1x_channel *channel);int host1x_job_submit (struct host1x_job *job);
Signature · 1 line
2.29.2
PATCH v2 34/48 gpu: host1x: Support power management
In reply to Dmitry OsipenkoAdd suspend/resume and generic power domain support to the Host1x driver. This is required for enabling system-wide DVFS and supporting dynamic power management using a generic power domain.
--- drivers/gpu/host1x/dev.c | 102 ++++++++++++++++++++++++++++++++++----- 1 file changed, 91 insertions(+), 11 deletions(-)
drivers/gpu/host1x/dev.c +91 -11
@@ -12,6 +12,7 @@#include <linux/module.h> #include <linux/of_device.h> #include <linux/of.h> +#include <linux/pm_runtime.h> #include <linux/slab.h> #define CREATE_TRACE_POINTS
@@ -417,7 +418,7 @@ static int host1x_probe(struct platform_device *pdev)return err; } - host->rst =devm_reset_control_get (&pdev->dev,"host1x" ); + host->rst =devm_reset_control_get_exclusive_released (&pdev->dev,"host1x" );if (IS_ERR (host->rst)) { err =PTR_ERR (host->rst);dev_err (&pdev->dev,"failed to get reset: %d\n" , err);
@@ -437,16 +438,15 @@ static int host1x_probe(struct platform_device *pdev) goto iommu_exit; } - err =clk_prepare_enable (host->clk); -if (err <0 ) { -dev_err (&pdev->dev,"failed to enable clock\n" ); - goto free_channels; - } +pm_runtime_enable (&pdev->dev); + err =pm_runtime_get_sync (&pdev->dev); +if (err <0 ) + goto rpm_disable; err =reset_control_deassert (host->rst);if (err <0 ) {dev_err (&pdev->dev,"failed to deassert reset: %d\n" , err); - goto unprepare_disable; + goto rpm_disable; } err =host1x_syncpt_init (host);
@@ -485,9 +485,10 @@ static int host1x_probe(struct platform_device *pdev)host1x_syncpt_deinit (host); reset_assert:reset_control_assert (host->rst); -unprepare_disable: -clk_disable_unprepare (host->clk); -free_channels: +rpm_disable: +pm_runtime_put (&pdev->dev); +pm_runtime_disable (&pdev->dev); +host1x_channel_list_free (&host->channel_list); iommu_exit:host1x_iommu_exit (host);
@@ -504,16 +505,95 @@ static int host1x_remove(struct platform_device *pdev)host1x_intr_deinit (host);host1x_syncpt_deinit (host);reset_control_assert (host->rst); -clk_disable_unprepare (host->clk); +pm_runtime_put (&pdev->dev); +pm_runtime_disable (&pdev->dev);host1x_iommu_exit (host);return 0 ; } +static int __maybe_unused host1x_runtime_suspend (struct device *dev) +{ +struct host1x *host =dev_get_drvdata (dev); + +clk_disable_unprepare (host->clk); +reset_control_release (host->rst); + +return 0 ; +} + +static int __maybe_unused host1x_runtime_resume (struct device *dev) +{ +struct host1x *host =dev_get_drvdata (dev); +int err; + + err =reset_control_acquire (host->rst); +if (err) { +dev_err (dev,"failed to acquire reset: %d\n" , err); +return err; + } + + err =clk_prepare_enable (host->clk); +if (err) { +dev_err (dev,"failed to enable clock: %d\n" , err); + goto release_reset; + } + +return 0 ; + +release_reset: +reset_control_release (host->rst); + +return err; +} + +static __maybe_unused int host1x_suspend (struct device *dev) +{ +struct host1x *host =dev_get_drvdata (dev); +int err; + +host1x_syncpt_save (host); + + err =pm_runtime_force_suspend (dev); +if (err <0 ) +return err; + +return 0 ; +} + +static __maybe_unused int host1x_resume (struct device *dev) +{ +struct host1x *host =dev_get_drvdata (dev); +struct host1x_channel *channel; +unsigned int index; +int err; + + err =pm_runtime_force_resume (dev); +if (err <0 ) +return err; + +host1x_syncpt_restore (host); + +for_each_set_bit (index, host->channel_list.allocated_channels, + host->info->nb_channels) { + channel = &host->channel_list.channels[index]; +host1x_hw_channel_init (host, channel, channel->id); + } + +return 0 ; +} + +static const struct dev_pm_ops host1x_pm = { + SET_RUNTIME_PM_OPS(host1x_runtime_suspend, host1x_runtime_resume, + NULL) +SET_SYSTEM_SLEEP_PM_OPS (host1x_suspend, host1x_resume) +}; +static struct platform_driver tegra_host1x_driver = { .driver = { .name ="tegra-host1x" , .of_match_table = host1x_of_match, + .pm = &host1x_pm, }, .probe = host1x_probe, .remove = host1x_remove,
Signature · 1 line
2.29.2
Re: [PATCH v2 34/48] gpu: host1x: Support power management
Quoted 131 lines · Dmitry Osipenko
Add suspend/resume and generic power domain support to the Host1x driver. This is required for enabling system-wide DVFS and supporting dynamic power management using a generic power domain.
Tested-by Peter Geis <[email protected]>Tested-by Nicolas Chauvet <[email protected]>Signed-off-by Dmitry Osipenko <[email protected]>--- drivers/gpu/host1x/dev.c | 102 ++++++++++++++++++++++++++++++++++----- 1 file changed, 91 insertions(+), 11 deletions(-)drivers/gpu/host1x/dev.c +64
-11@@ -12,6 +12,7 @@#include <linux/module.h> #include <linux/of_device.h> #include <linux/of.h> +#include <linux/pm_runtime.h> #include <linux/slab.h> #define CREATE_TRACE_POINTS @@ -417,7 +418,7 @@ static int host1x_probe(struct platform_device *pdev)return err; } - host->rst =devm_reset_control_get (&pdev->dev,"host1x" ); + host->rst =devm_reset_control_get_exclusive_released (&pdev->dev,"host1x" );if (IS_ERR (host->rst)) { err =PTR_ERR (host->rst);dev_err (&pdev->dev,"failed to get reset: %d\n" , err);@@ -437,16 +438,15 @@ static int host1x_probe(struct platform_device *pdev) goto iommu_exit; } - err =clk_prepare_enable (host->clk); -if (err <0 ) { -dev_err (&pdev->dev,"failed to enable clock\n" ); - goto free_channels; - } +pm_runtime_enable (&pdev->dev); + err =pm_runtime_get_sync (&pdev->dev); +if (err <0 ) + goto rpm_disable; err =reset_control_deassert (host->rst);if (err <0 ) {dev_err (&pdev->dev,"failed to deassert reset: %d\n" , err); - goto unprepare_disable; + goto rpm_disable; } err =host1x_syncpt_init (host);@@ -485,9 +485,10 @@ static int host1x_probe(struct platform_device *pdev)host1x_syncpt_deinit (host); reset_assert:reset_control_assert (host->rst); -unprepare_disable: -clk_disable_unprepare (host->clk); -free_channels: +rpm_disable: +pm_runtime_put (&pdev->dev); +pm_runtime_disable (&pdev->dev); +host1x_channel_list_free (&host->channel_list); iommu_exit:host1x_iommu_exit (host);@@ -504,16 +505,95 @@ static int host1x_remove(struct platform_device *pdev)host1x_intr_deinit (host);host1x_syncpt_deinit (host);reset_control_assert (host->rst); -clk_disable_unprepare (host->clk); +pm_runtime_put (&pdev->dev); +pm_runtime_disable (&pdev->dev);host1x_iommu_exit (host);return 0 ; } +static int __maybe_unused host1x_runtime_suspend (struct device *dev) +{ +struct host1x *host =dev_get_drvdata (dev); + +clk_disable_unprepare (host->clk); +reset_control_release (host->rst); + +return 0 ; +} + +static int __maybe_unused host1x_runtime_resume (struct device *dev) +{ +struct host1x *host =dev_get_drvdata (dev); +int err; + + err =reset_control_acquire (host->rst); +if (err) { +dev_err (dev,"failed to acquire reset: %d\n" , err); +return err; + } + + err =clk_prepare_enable (host->clk); +if (err) { +dev_err (dev,"failed to enable clock: %d\n" , err); + goto release_reset; + } + +return 0 ; + +release_reset: +reset_control_release (host->rst); + +return err; +} + +static __maybe_unused int host1x_suspend (struct device *dev) +{ +struct host1x *host =dev_get_drvdata (dev); +int err; + +host1x_syncpt_save (host); + + err =pm_runtime_force_suspend (dev); +if (err <0 ) +return err; + +return 0 ; +} + +static __maybe_unused int host1x_resume (struct device *dev) +{
drivers/gpu/host1x/dev.c static int host1x_remove(struct platform_device *pdev) · line 575
Quoted 10 lines
drivers/gpu/host1x/dev.c +10
-0+struct host1x *host =dev_get_drvdata (dev); +struct host1x_channel *channel; +unsigned int index; +int err; + + err =pm_runtime_force_resume (dev); +if (err <0 ) +return err; + +host1x_syncpt_restore (host);
We also need to execute 'host1x_setup_sid_table' upon resume.
cheers,
Mikko
Quoted 15 lines
drivers/gpu/host1x/dev.c +14
-0+ +for_each_set_bit (index, host->channel_list.allocated_channels, + host->info->nb_channels) { + channel = &host->channel_list.channels[index]; +host1x_hw_channel_init (host, channel, channel->id); + } + +return 0 ; +} + +static const struct dev_pm_ops host1x_pm = { + SET_RUNTIME_PM_OPS(host1x_runtime_suspend, host1x_runtime_resume, + NULL) +SET_SYSTEM_SLEEP_PM_OPS (host1x_suspend, host1x_resume)
drivers/gpu/host1x/dev.c static int host1x_remove(struct platform_device *pdev) · line 599
Quoted 10 lines
drivers/gpu/host1x/dev.c +3
-0+}; +static struct platform_driver tegra_host1x_driver = { .driver = { .name ="tegra-host1x" , .of_match_table = host1x_of_match, + .pm = &host1x_pm, }, .probe = host1x_probe, .remove = host1x_remove,
_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel
Re: [PATCH v2 34/48] gpu: host1x: Support power management
17.12.2020 21:21, Mikko Perttunen пишет:
Quoted 133 lines · Dmitry Osipenko
Quoted 132 lines
Add suspend/resume and generic power domain support to the Host1x driver. This is required for enabling system-wide DVFS and supporting dynamic power management using a generic power domain.
Tested-by Peter Geis <[email protected]>Tested-by Nicolas Chauvet <[email protected]>Signed-off-by Dmitry Osipenko <[email protected]>---
drivers/gpu/host1x/dev.c| 102 ++++++++++++++++++++++++++++++++++-----1 file changed, 91 insertions(+), 11 deletions(-)drivers/gpu/host1x/dev.c +2
-0@@ -12,6 +12,7 @@ #include <linux/module.h> #include <linux/of_device.h> #include <linux/of.h> +#include <linux/pm_runtime.h> #include <linux/slab.h> #define CREATE_TRACE_POINTS@@ -417,7 +418,7 @@ static int host1x_probe(struct platform_device *pdev) return err; } - host->rst = devm_reset_control_get(&pdev->dev, "host1x"); + host->rst = devm_reset_control_get_exclusive_released(&pdev->dev,"host1x" ); if (IS_ERR(host->rst)) { err = PTR_ERR(host->rst);
dev_err(&pdev->dev, "failed to get reset: %d\n", err);drivers/gpu/host1x/dev.c +5
-5@@ -437,16 +438,15 @@ static int host1x_probe(struct platform_device *pdev) goto iommu_exit; } - err = clk_prepare_enable(host->clk); - if (err < 0) { - dev_err(&pdev->dev, "failed to enable clock\n"); - goto free_channels; - } + pm_runtime_enable(&pdev->dev); + err = pm_runtime_get_sync(&pdev->dev); + if (err < 0) + goto rpm_disable; err = reset_control_deassert(host->rst); if (err < 0) { dev_err(&pdev->dev, "failed to deassert reset: %d\n", err); - goto unprepare_disable; + goto rpm_disable; } err = host1x_syncpt_init(host);@@ -485,9 +485,10 @@ static int host1x_probe(struct platform_device *pdev) host1x_syncpt_deinit(host);
reset_assert:
reset_control_assert(host->rst);drivers/gpu/host1x/dev.c +4
-3-unprepare_disable: - clk_disable_unprepare(host->clk); -free_channels: +rpm_disable: + pm_runtime_put(&pdev->dev); + pm_runtime_disable(&pdev->dev); +
host1x_channel_list_free(&host->channel_list);iommu_exit:
host1x_iommu_exit(host);drivers/gpu/host1x/dev.c +56
-1@@ -504,16 +505,95 @@ static int host1x_remove(struct platform_device *pdev) host1x_intr_deinit(host); host1x_syncpt_deinit(host); reset_control_assert(host->rst); - clk_disable_unprepare(host->clk); + pm_runtime_put(&pdev->dev); + pm_runtime_disable(&pdev->dev); host1x_iommu_exit(host); return 0; } +static int __maybe_unused host1x_runtime_suspend(struct device *dev) +{ + struct host1x *host = dev_get_drvdata(dev); + + clk_disable_unprepare(host->clk); + reset_control_release(host->rst); + + return 0; +} + +static int __maybe_unused host1x_runtime_resume (struct device *dev) +{ + struct host1x *host = dev_get_drvdata(dev); + int err; + + err = reset_control_acquire(host->rst); + if (err) { + dev_err(dev, "failed to acquire reset: %d\n", err); + return err; + } + + err = clk_prepare_enable(host->clk); + if (err) { + dev_err(dev, "failed to enable clock: %d\n", err); + goto release_reset; + } + + return 0; + +release_reset: + reset_control_release(host->rst); + + return err; +} + +static __maybe_unused int host1x_suspend (struct device *dev) +{ + struct host1x *host = dev_get_drvdata(dev); + int err; + + host1x_syncpt_save(host); + + err = pm_runtime_force_suspend(dev); + if (err < 0) + return err; + + return 0; +} + +static __maybe_unused int host1x_resume (struct device *dev) +{ + struct host1x *host = dev_get_drvdata(dev); + struct host1x_channel *channel; + unsigned int index; + int err;
Quoted 8 lines
drivers/gpu/host1x/dev.c static int host1x_remove(struct platform_device *pdev) · line 575
Quoted 6 lines
drivers/gpu/host1x/dev.c +6
-0+ + err = pm_runtime_force_resume(dev); + if (err < 0) + return err; + + host1x_syncpt_restore(host);We also need to execute '
host1x_setup_sid_table' upon resume.
Indeed, thanks. I'll correct it in the next revision.
Perhaps the actual save/restore needs to be moved to the runtime callbacks. At least I can't remember right now why this wasn't done in the first place.
Re: [PATCH v2 34/48] gpu: host1x: Support power management
17.12.2020 21:45, Dmitry Osipenko пишет:
Quoted 143 lines
17.12.2020 21:21, Mikko Perttunen пишет:
Quoted 133 lines · Dmitry Osipenko
Quoted 132 lines
Add suspend/resume and generic power domain support to the Host1x driver. This is required for enabling system-wide DVFS and supporting dynamic power management using a generic power domain.
Tested-by Peter Geis <[email protected]>Tested-by Nicolas Chauvet <[email protected]>Signed-off-by Dmitry Osipenko <[email protected]>---
drivers/gpu/host1x/dev.c| 102 ++++++++++++++++++++++++++++++++++-----1 file changed, 91 insertions(+), 11 deletions(-)drivers/gpu/host1x/dev.c +2
-0@@ -12,6 +12,7 @@ #include <linux/module.h> #include <linux/of_device.h> #include <linux/of.h> +#include <linux/pm_runtime.h> #include <linux/slab.h> #define CREATE_TRACE_POINTS@@ -417,7 +418,7 @@ static int host1x_probe(struct platform_device *pdev) return err; } - host->rst = devm_reset_control_get(&pdev->dev, "host1x"); + host->rst = devm_reset_control_get_exclusive_released(&pdev->dev,"host1x" ); if (IS_ERR(host->rst)) { err = PTR_ERR(host->rst);
dev_err(&pdev->dev, "failed to get reset: %d\n", err);drivers/gpu/host1x/dev.c +5
-5@@ -437,16 +438,15 @@ static int host1x_probe(struct platform_device *pdev) goto iommu_exit; } - err = clk_prepare_enable(host->clk); - if (err < 0) { - dev_err(&pdev->dev, "failed to enable clock\n"); - goto free_channels; - } + pm_runtime_enable(&pdev->dev); + err = pm_runtime_get_sync(&pdev->dev); + if (err < 0) + goto rpm_disable; err = reset_control_deassert(host->rst); if (err < 0) { dev_err(&pdev->dev, "failed to deassert reset: %d\n", err); - goto unprepare_disable; + goto rpm_disable; } err = host1x_syncpt_init(host);@@ -485,9 +485,10 @@ static int host1x_probe(struct platform_device *pdev) host1x_syncpt_deinit(host);
reset_assert:
reset_control_assert(host->rst);drivers/gpu/host1x/dev.c +4
-3-unprepare_disable: - clk_disable_unprepare(host->clk); -free_channels: +rpm_disable: + pm_runtime_put(&pdev->dev); + pm_runtime_disable(&pdev->dev); +
host1x_channel_list_free(&host->channel_list);iommu_exit:
host1x_iommu_exit(host);drivers/gpu/host1x/dev.c +56
-1@@ -504,16 +505,95 @@ static int host1x_remove(struct platform_device *pdev) host1x_intr_deinit(host); host1x_syncpt_deinit(host); reset_control_assert(host->rst); - clk_disable_unprepare(host->clk); + pm_runtime_put(&pdev->dev); + pm_runtime_disable(&pdev->dev); host1x_iommu_exit(host); return 0; } +static int __maybe_unused host1x_runtime_suspend(struct device *dev) +{ + struct host1x *host = dev_get_drvdata(dev); + + clk_disable_unprepare(host->clk); + reset_control_release(host->rst); + + return 0; +} + +static int __maybe_unused host1x_runtime_resume (struct device *dev) +{ + struct host1x *host = dev_get_drvdata(dev); + int err; + + err = reset_control_acquire(host->rst); + if (err) { + dev_err(dev, "failed to acquire reset: %d\n", err); + return err; + } + + err = clk_prepare_enable(host->clk); + if (err) { + dev_err(dev, "failed to enable clock: %d\n", err); + goto release_reset; + } + + return 0; + +release_reset: + reset_control_release(host->rst); + + return err; +} + +static __maybe_unused int host1x_suspend (struct device *dev) +{ + struct host1x *host = dev_get_drvdata(dev); + int err; + + host1x_syncpt_save(host); + + err = pm_runtime_force_suspend(dev); + if (err < 0) + return err; + + return 0; +} + +static __maybe_unused int host1x_resume (struct device *dev) +{ + struct host1x *host = dev_get_drvdata(dev); + struct host1x_channel *channel; + unsigned int index; + int err;Quoted 8 lines
drivers/gpu/host1x/dev.c static int host1x_remove(struct platform_device *pdev) · line 575
Quoted 6 lines
drivers/gpu/host1x/dev.c +6
-0+ + err = pm_runtime_force_resume(dev); + if (err < 0) + return err; + + host1x_syncpt_restore(host);We also need to execute '
host1x_setup_sid_table' upon resume.
Quoted 6 lines
Indeed, thanks. I'll correct it in the next revision.
Perhaps the actual save/restore needs to be moved to the runtime callbacks. At least I can't remember right now why this wasn't done in the first place.
I looked at the save/restore once again and recalled why it's done so. The reason is that the host1x touches hardware during the driver probe, and thus, RPM needs to be resumed first. It will be a bigger change to properly decouple the hardware initialization so that it all could be put it into the RPM callback. I'll try to do it in v3.
PATCH v2 35/48 drm/tegra: dc: Support OPP and SoC core voltage scaling
In reply to Dmitry OsipenkoAdd OPP and SoC core voltage scaling support to the display controller driver. This is required for enabling system-wide DVFS on pre-Tegra186 SoCs.
--- drivers/gpu/drm/tegra/dc.c | 66 +++++++++++++++++++++++++++++++++++++- 1 file changed, 65 insertions(+), 1 deletion(-)
drivers/gpu/drm/tegra/dc.c +65 -1
@@ -11,9 +11,12 @@#include <linux/interconnect.h> #include <linux/module.h> #include <linux/of_device.h> +#include <linux/pm_domain.h> +#include <linux/pm_opp.h> #include <linux/pm_runtime.h> #include <linux/reset.h> +#include <soc/tegra/common.h> #include <soc/tegra/pmc.h> #include <drm/drm_atomic.h>
@@ -1699,6 +1702,48 @@ int tegra_dc_state_setup_clock(struct tegra_dc *dc,return 0 ; } +static void tegra_dc_update_voltage_state (struct tegra_dc *dc, +struct tegra_dc_state *state) +{ +unsigned long rate, pstate; +struct dev_pm_opp *opp; +int err; + +/* calculate actual pixel clock rate which depends on internal divider */ + rate =DIV_ROUND_UP (clk_get_rate (dc->clk) *2 , state->div +2 ); + +/* find suitable OPP for the rate */ + opp =dev_pm_opp_find_freq_ceil (dc->dev, &rate); + +if (opp ==ERR_PTR (-ERANGE )) + opp =dev_pm_opp_find_freq_floor (dc->dev, &rate); + +/* -ENOENT means that this device-tree doesn't have OPP table */ +if (opp ==ERR_PTR (-ENOENT )) +return ; + +if (IS_ERR (opp)) { +dev_err (dc->dev,"failed to find OPP for %luHz: %pe\n" , + rate, opp); +return ; + } + + pstate =dev_pm_opp_get_voltage (opp); +dev_pm_opp_put (opp); + +/* +* The minimum core voltage depends on the pixel clock rate (which +* depends on internal clock divider of the CRTC) and not on the +* rate of the display controller clock. This is why we're not using +* dev_pm_opp_set_rate() API and instead controlling the power domain +* directly. +*/ + err =dev_pm_genpd_set_performance_state (dc->dev, pstate); +if (err) +dev_err (dc->dev,"failed to set power domain state to %lu: %d\n" , + pstate, err); +} +static void tegra_dc_commit_state (struct tegra_dc *dc,struct tegra_dc_state *state) {
@@ -1738,6 +1783,8 @@ static void tegra_dc_commit_state(struct tegra_dc *dc,if (err <0 )dev_err (dc->dev,"failed to set clock %pC to %lu Hz: %d\n" , dc->clk, state->pclk, err); + +tegra_dc_update_voltage_state (dc, state); }static void tegra_dc_stop (struct tegra_dc *dc)
@@ -1931,6 +1978,8 @@ static void tegra_crtc_atomic_disable(struct drm_crtc *crtc, err =host1x_client_suspend (&dc->client);if (err <0 )dev_err (dc->dev,"failed to suspend: %d\n" , err); + +dev_pm_genpd_set_performance_state (dc->dev,0 ); } static void tegra_crtc_atomic_enable(struct drm_crtc *crtc,
@@ -2523,7 +2572,6 @@ static int tegra_dc_runtime_suspend(struct host1x_client *client)clk_disable_unprepare (dc->clk);pm_runtime_put_sync (dev); -return 0 ; }
@@ -2881,6 +2929,18 @@ static int tegra_dc_couple(struct tegra_dc *dc)return 0 ; } +static int tegra_dc_init_opp_table (struct tegra_dc *dc) +{ +struct tegra_core_opp_params opp_params = {}; +int err; + + err =devm_tegra_core_dev_init_opp_table (dc->dev, &opp_params); +if (err && err != -ENODEV ) +return err; + +return 0 ; +} +static int tegra_dc_probe (struct platform_device *pdev) {struct tegra_dc *dc;
@@ -2939,6 +2999,10 @@ static int tegra_dc_probe(struct platform_device *pdev)tegra_powergate_power_off (dc->powergate); } + err =tegra_dc_init_opp_table (dc); +if (err <0 ) +return err; + dc->regs =devm_platform_ioremap_resource (pdev,0 );if (IS_ERR (dc->regs))return PTR_ERR (dc->regs);
Signature · 1 line
2.29.2
Re: [PATCH v2 35/48] drm/tegra: dc: Support OPP and SoC core voltage scaling
- trimmed cc-list
Quoted 60 lines · Dmitry Osipenko
Add OPP and SoC core voltage scaling support to the display controller driver. This is required for enabling system-wide DVFS on pre-Tegra186 SoCs.
Tested-by Peter Geis <[email protected]>Tested-by Nicolas Chauvet <[email protected]>Signed-off-by Dmitry Osipenko <[email protected]>--- drivers/gpu/drm/tegra/dc.c | 66 +++++++++++++++++++++++++++++++++++++- 1 file changed, 65 insertions(+), 1 deletion(-)drivers/gpu/drm/tegra/dc.c +30
-0@@ -11,9 +11,12 @@#include <linux/interconnect.h> #include <linux/module.h> #include <linux/of_device.h> +#include <linux/pm_domain.h> +#include <linux/pm_opp.h> #include <linux/pm_runtime.h> #include <linux/reset.h> +#include <soc/tegra/common.h> #include <soc/tegra/pmc.h> #include <drm/drm_atomic.h> @@ -1699,6 +1702,48 @@ int tegra_dc_state_setup_clock(struct tegra_dc *dc,return 0 ; } +static void tegra_dc_update_voltage_state (struct tegra_dc *dc, +struct tegra_dc_state *state) +{ +unsigned long rate, pstate; +struct dev_pm_opp *opp; +int err; + +/* calculate actual pixel clock rate which depends on internal divider */ + rate =DIV_ROUND_UP (clk_get_rate (dc->clk) *2 , state->div +2 ); + +/* find suitable OPP for the rate */ + opp =dev_pm_opp_find_freq_ceil (dc->dev, &rate); + +if (opp ==ERR_PTR (-ERANGE )) + opp =dev_pm_opp_find_freq_floor (dc->dev, &rate); + +/* -ENOENT means that this device-tree doesn't have OPP table */ +if (opp ==ERR_PTR (-ENOENT )) +return ; + +if (IS_ERR (opp)) { +dev_err (dc->dev,"failed to find OPP for %luHz: %pe\n" , + rate, opp); +return ; + } + + pstate =dev_pm_opp_get_voltage (opp);
drivers/gpu/drm/tegra/dc.c int tegra_dc_state_setup_clock(struct tegra_dc *dc, · line 1741
Quoted 10 lines
drivers/gpu/drm/tegra/dc.c +10
-0+dev_pm_opp_put (opp); + +/* +* The minimum core voltage depends on the pixel clock rate (which +* depends on internal clock divider of the CRTC) and not on the +* rate of the display controller clock. This is why we're not using +* dev_pm_opp_set_rate() API and instead controlling the power domain +* directly. +*/ + err =dev_pm_genpd_set_performance_state (dc->dev, pstate);
As you state above, in general we should not need to call the dev_pm_genpd_set_performance_state() directly for the consumer driver.
Even if this looks like a special case to me, I would appreciate a confirmation from Viresh that this is the way he also would like to move forward from the opp library perspective.
drivers/gpu/drm/tegra/dc.c int tegra_dc_state_setup_clock(struct tegra_dc *dc, · line 1746
Quoted 5 lines
drivers/gpu/drm/tegra/dc.c +5
-0+if (err) +dev_err (dc->dev,"failed to set power domain state to %lu: %d\n" , + pstate, err); +} +
[...]
Kind regards
Uffe
PATCH v2 36/48 drm/tegra: gr2d: Correct swapped device-tree compatibles
In reply to Dmitry OsipenkoThe device-tree compatibles are swapped in the code, correct them.
--- drivers/gpu/drm/tegra/gr2d.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/gpu/drm/tegra/gr2d.c +2 -2
@@ -162,8 +162,8 @@ static const struct gr2d_soc tegra30_gr2d_soc = { };static const struct of_device_id gr2d_match[] = { - { .compatible ="nvidia,tegra30-gr2d" , .data = &tegra20_gr2d_soc }, - { .compatible ="nvidia,tegra20-gr2d" , .data = &tegra30_gr2d_soc }, + { .compatible ="nvidia,tegra30-gr2d" , .data = &tegra30_gr2d_soc }, + { .compatible ="nvidia,tegra20-gr2d" , .data = &tegra20_gr2d_soc }, { }, };MODULE_DEVICE_TABLE (of, gr2d_match);
Signature · 1 line
2.29.2
PATCH v2 37/48 drm/tegra: gr2d: Support OPP and power management
In reply to Dmitry OsipenkoAdd OPP and PM support to the GR2D driver. This is required for enabling system-wide DVFS and supporting dynamic power management using a generic power domain.
--- drivers/gpu/drm/tegra/gr2d.c | 73 +++++++++++++++++++++++++++++++++--- 1 file changed, 67 insertions(+), 6 deletions(-)
drivers/gpu/drm/tegra/gr2d.c +67 -6
@@ -7,6 +7,9 @@#include <linux/iommu.h> #include <linux/module.h> #include <linux/of_device.h> +#include <linux/pm_runtime.h> + +#include <soc/tegra/common.h> #include "drm.h" #include "gem.h"
@@ -185,8 +188,15 @@ static const u32 gr2d_addr_regs[] = { GR2D_VA_BASE_ADDR_SB, }; +static void gr2d_pm_runtime_release (void *dev) +{ +pm_runtime_put (dev); +pm_runtime_disable (dev); +} +static int gr2d_probe (struct platform_device *pdev) { +struct tegra_core_opp_params opp_params = {};struct device *dev = &pdev->dev;struct host1x_syncpt **syncpts;struct gr2d *gr2d;
@@ -197,6 +207,8 @@ static int gr2d_probe(struct platform_device *pdev)if (!gr2d)return -ENOMEM ; +platform_set_drvdata (pdev, gr2d); + gr2d->soc =of_device_get_match_data (dev); syncpts =devm_kzalloc (dev,sizeof (*syncpts),GFP_KERNEL );
@@ -209,12 +221,23 @@ static int gr2d_probe(struct platform_device *pdev)return PTR_ERR (gr2d->clk); } - err =clk_prepare_enable (gr2d->clk); -if (err) { -dev_err (dev,"cannot turn on clock\n" ); + opp_params.init_state = true; + + err =devm_tegra_core_dev_init_opp_table (dev, &opp_params); +if (err && err != -ENODEV ) +return err; + +pm_runtime_enable (dev); + err =pm_runtime_get_sync (dev); +if (err <0 ) { +gr2d_pm_runtime_release (dev);return err; } + err =devm_add_action_or_reset (dev, gr2d_pm_runtime_release, dev); +if (err) +return err; +INIT_LIST_HEAD (&gr2d->client.base.list); gr2d->client.base.ops = &gr2d_client_ops; gr2d->client.base.dev = dev;
@@ -229,7 +252,6 @@ static int gr2d_probe(struct platform_device *pdev) err =host1x_client_register (&gr2d->client.base);if (err <0 ) {dev_err (dev,"failed to register host1x client: %d\n" , err); -clk_disable_unprepare (gr2d->clk);return err; }
@@ -237,8 +259,6 @@ static int gr2d_probe(struct platform_device *pdev)for (i =0 ; i <ARRAY_SIZE (gr2d_addr_regs); i++)set_bit (gr2d_addr_regs[i], gr2d->addr_regs); -platform_set_drvdata (pdev, gr2d); -return 0 ; }
@@ -254,15 +274,56 @@ static int gr2d_remove(struct platform_device *pdev)return err; } +return 0 ; +} + +static int __maybe_unused gr2d_runtime_suspend (struct device *dev) +{ +struct gr2d *gr2d =dev_get_drvdata (dev); +clk_disable_unprepare (gr2d->clk);return 0 ; } +static int __maybe_unused gr2d_runtime_resume (struct device *dev) +{ +struct gr2d *gr2d =dev_get_drvdata (dev); +int err; + + err =clk_prepare_enable (gr2d->clk); +if (err) { +dev_err (dev,"failed to enable clock: %d\n" , err); +return err; + } + +return 0 ; +} + +static __maybe_unused int gr2d_suspend (struct device *dev) +{ +struct gr2d *gr2d =dev_get_drvdata (dev); +int err; + +host1x_channel_stop (gr2d->channel); + + err =pm_runtime_force_suspend (dev); +if (err <0 ) +return err; + +return 0 ; +} + +static const struct dev_pm_ops tegra_gr2d_pm = { + SET_RUNTIME_PM_OPS(gr2d_runtime_suspend, gr2d_runtime_resume, NULL) +SET_SYSTEM_SLEEP_PM_OPS (gr2d_suspend, pm_runtime_force_resume) +}; +struct platform_driver tegra_gr2d_driver = { .driver = { .name ="tegra-gr2d" , .of_match_table = gr2d_match, + .pm = &tegra_gr2d_pm, }, .probe = gr2d_probe, .remove = gr2d_remove,
Signature · 1 line
2.29.2
PATCH v2 38/48 drm/tegra: g3d: Support OPP and power management
In reply to Dmitry OsipenkoAdd OPP and add PM support to the GR3D driver. This is required for enabling system-wide DVFS and supporting dynamic power management using a generic power domain.
--- drivers/gpu/drm/tegra/gr3d.c | 264 +++++++++++++++++++++++++++++++---- 1 file changed, 238 insertions(+), 26 deletions(-)
drivers/gpu/drm/tegra/gr3d.c +238 -26
@@ -10,8 +10,12 @@#include <linux/module.h> #include <linux/of_device.h> #include <linux/platform_device.h> +#include <linux/pm_domain.h> +#include <linux/pm_opp.h> +#include <linux/pm_runtime.h> #include <linux/reset.h> +#include <soc/tegra/common.h> #include <soc/tegra/pmc.h> #include "drm.h"
@@ -31,6 +35,9 @@ struct gr3d {struct reset_control *rst;const struct gr3d_soc *soc; +struct clk_bulk_data clocks[2 ]; +unsigned int nclocks; +bool legacy_pd;DECLARE_BITMAP (addr_regs,GR3D_NUM_REGS ); };
@@ -278,10 +285,120 @@ static const u32 gr3d_addr_regs[] = { GR3D_GLOBAL_SAMP23SURFADDR(15), }; +static void gr3d_pm_runtime_release (void *dev) +{ +pm_runtime_put (dev); +pm_runtime_disable (dev); +} + +static int gr3d_link_power_domain (struct device *dev,struct device *pd_dev) +{ +const u32 link_flags =DL_FLAG_STATELESS |DL_FLAG_PM_RUNTIME ; +struct device_link *link; +int err; + + link =device_link_add (dev, pd_dev, link_flags); +if (!link) { +dev_err (dev,"failed to link to %s\n" ,dev_name (pd_dev)); +return -EINVAL ; + } + + err =devm_add_action_or_reset (dev, (void *)device_link_del, link); +if (err) +return err; + +return 0 ; +} + +static int devm_gr3d_init_power (struct device *dev,struct gr3d *gr3d) +{ +const char *opp_genpd_names[] = {"3d0" ,"3d1" ,NULL }; +struct device **opp_virt_dev; +struct opp_table *opp_table; +unsigned int i, num_domains; +struct device *pd_dev; +int err; + + err =of_count_phandle_with_args (dev->of_node,"power-domains" , +"#power-domain-cells" ); +if (err <0 ) { +if (err != -ENOENT ) +return err; + +/* +* Older device-trees don't use GENPD. In this case we should +* toggle power domain manually. +*/ + gr3d->legacy_pd = true; + goto power_up; + } + + num_domains = err; + +/* +* The PM domain core automatically attaches a single power domain, +* otherwise it skips attaching completely. We have a single domain +* on Tegra20 and two domains on Tegra30+. +*/ +if (dev->pm_domain) + goto power_up; + + opp_table =devm_pm_opp_attach_genpd (dev, opp_genpd_names, &opp_virt_dev); +if (IS_ERR (opp_table)) +return PTR_ERR (opp_table); + +for (i =0 ; opp_genpd_names[i]; i++) { + pd_dev = opp_virt_dev[i]; +if (!pd_dev) { +dev_err (dev,"failed to get %s power domain\n" , + opp_genpd_names[i]); +return -EINVAL ; + } + + err =gr3d_link_power_domain (dev, pd_dev); +if (err) +return err; + } + +power_up: +pm_runtime_enable (dev); + err =pm_runtime_get_sync (dev); +if (err <0 ) { +gr3d_pm_runtime_release (dev); +return err; + } + + err =devm_add_action_or_reset (dev, gr3d_pm_runtime_release, dev); +if (err) +return err; + +return 0 ; +} + +static int gr3d_set_opp (struct dev_pm_set_opp_data *data) +{ +struct gr3d *gr3d =dev_get_drvdata (data->dev); +unsigned int i; +int err; + +for (i =0 ; i < gr3d->nclocks; i++) { + err =clk_set_rate (gr3d->clocks[i].clk, data->new_opp.rate); +if (err) { +dev_err (data->dev,"failed to set %s rate to %lu: %d\n" , + gr3d->clocks[i].id, data->new_opp.rate, err); +return err; + } + } + +return 0 ; +} +static int gr3d_probe (struct platform_device *pdev) { +struct tegra_core_opp_params opp_params = {};struct device_node *np = pdev->dev.of_node;struct host1x_syncpt **syncpts; +struct opp_table *opp_table;struct gr3d *gr3d;unsigned int i;int err;
@@ -290,6 +407,8 @@ static int gr3d_probe(struct platform_device *pdev)if (!gr3d)return -ENOMEM ; +platform_set_drvdata (pdev, gr3d); + gr3d->soc =of_device_get_match_data (&pdev->dev); syncpts =devm_kzalloc (&pdev->dev,sizeof (*syncpts),GFP_KERNEL );
@@ -302,7 +421,11 @@ static int gr3d_probe(struct platform_device *pdev)return PTR_ERR (gr3d->clk); } - gr3d->rst =devm_reset_control_get (&pdev->dev,"3d" ); + gr3d->clocks[gr3d->nclocks].id ="3d" ; + gr3d->clocks[gr3d->nclocks].clk = gr3d->clk; + gr3d->nclocks++; + + gr3d->rst =devm_reset_control_get_exclusive_released (&pdev->dev,"3d" );if (IS_ERR (gr3d->rst)) {dev_err (&pdev->dev,"cannot get reset\n" );return PTR_ERR (gr3d->rst);
@@ -315,31 +438,31 @@ static int gr3d_probe(struct platform_device *pdev)return PTR_ERR (gr3d->clk_secondary); } - gr3d->rst_secondary =devm_reset_control_get (&pdev->dev, -"3d2" ); + gr3d->clocks[gr3d->nclocks].id ="3d2" ; + gr3d->clocks[gr3d->nclocks].clk = gr3d->clk_secondary; + gr3d->nclocks++; + + gr3d->rst_secondary = +devm_reset_control_get_exclusive_released (&pdev->dev,"3d2" );if (IS_ERR (gr3d->rst_secondary)) {dev_err (&pdev->dev,"cannot get secondary reset\n" );return PTR_ERR (gr3d->rst_secondary); } } - err =tegra_powergate_sequence_power_up (TEGRA_POWERGATE_3D , gr3d->clk, - gr3d->rst); -if (err <0 ) { -dev_err (&pdev->dev,"failed to power up 3D unit\n" ); + err =devm_gr3d_init_power (&pdev->dev, gr3d); +if (err)return err; - } -if (gr3d->clk_secondary) { - err =tegra_powergate_sequence_power_up (TEGRA_POWERGATE_3D1 , - gr3d->clk_secondary, - gr3d->rst_secondary); -if (err <0 ) { -dev_err (&pdev->dev, -"failed to power up secondary 3D unit\n" ); -return err; - } - } + opp_table =devm_pm_opp_register_set_opp_helper (&pdev->dev, gr3d_set_opp); +if (IS_ERR (opp_table)) +return PTR_ERR (opp_table); + + opp_params.init_state = true; + + err =devm_tegra_core_dev_init_opp_table (&pdev->dev, &opp_params); +if (err && err != -ENODEV ) +return err;INIT_LIST_HEAD (&gr3d->client.base.list); gr3d->client.base.ops = &gr3d_client_ops;
@@ -363,8 +486,6 @@ static int gr3d_probe(struct platform_device *pdev)for (i =0 ; i <ARRAY_SIZE (gr3d_addr_regs); i++)set_bit (gr3d_addr_regs[i], gr3d->addr_regs); -platform_set_drvdata (pdev, gr3d); -return 0 ; }
@@ -380,23 +501,114 @@ static int gr3d_remove(struct platform_device *pdev)return err; } -if (gr3d->clk_secondary) { -reset_control_assert (gr3d->rst_secondary); +return 0 ; +} + +static int __maybe_unused gr3d_runtime_suspend (struct device *dev) +{ +struct gr3d *gr3d =dev_get_drvdata (dev); +int err; + +if (gr3d->legacy_pd && gr3d->clk_secondary) { + err =reset_control_assert (gr3d->rst_secondary); +if (err) { +dev_err (dev,"failed to assert secondary reset: %d\n" , err); +return err; + } +tegra_powergate_power_off (TEGRA_POWERGATE_3D1 ); -clk_disable_unprepare (gr3d->clk_secondary); } -reset_control_assert (gr3d->rst); -tegra_powergate_power_off (TEGRA_POWERGATE_3D ); -clk_disable_unprepare (gr3d->clk); +if (gr3d->legacy_pd) { + err =reset_control_assert (gr3d->rst); +if (err) { +dev_err (dev,"failed to assert reset: %d\n" , err); +return err; + } + +tegra_powergate_power_off (TEGRA_POWERGATE_3D ); + } + +clk_bulk_disable_unprepare (gr3d->nclocks, gr3d->clocks); +reset_control_release (gr3d->rst_secondary); +reset_control_release (gr3d->rst); + +return 0 ; +} + +static int __maybe_unused gr3d_runtime_resume (struct device *dev) +{ +struct gr3d *gr3d =dev_get_drvdata (dev); +int err; + + err =reset_control_acquire (gr3d->rst); +if (err) { +dev_err (dev,"failed to acquire reset: %d\n" , err); +return err; + } + + err =reset_control_acquire (gr3d->rst_secondary); +if (err) { +dev_err (dev,"failed to acquire secondary reset: %d\n" , err); + goto release_reset_primary; + } + +if (gr3d->legacy_pd) { + err =tegra_powergate_sequence_power_up (TEGRA_POWERGATE_3D , + gr3d->clk, gr3d->rst); +if (err) + goto release_reset_secondary; + } + +if (gr3d->legacy_pd && gr3d->clk_secondary) { + err =tegra_powergate_sequence_power_up (TEGRA_POWERGATE_3D1 , + gr3d->clk_secondary, + gr3d->rst_secondary); +if (err) + goto release_reset_secondary; + } + + err =clk_bulk_prepare_enable (gr3d->nclocks, gr3d->clocks); +if (err) { +dev_err (dev,"failed to enable clock: %d\n" , err); + goto release_reset_secondary; + } + +return 0 ; + +release_reset_secondary: +reset_control_release (gr3d->rst_secondary); + +release_reset_primary: +reset_control_release (gr3d->rst); + +return err; +} + +static __maybe_unused int gr3d_suspend (struct device *dev) +{ +struct gr3d *gr3d =dev_get_drvdata (dev); +int err; + +host1x_channel_stop (gr3d->channel); + + err =pm_runtime_force_suspend (dev); +if (err <0 ) +return err;return 0 ; } +static const struct dev_pm_ops tegra_gr3d_pm = { + SET_RUNTIME_PM_OPS(gr3d_runtime_suspend, gr3d_runtime_resume, NULL) +SET_SYSTEM_SLEEP_PM_OPS (gr3d_suspend, pm_runtime_force_resume) +}; +struct platform_driver tegra_gr3d_driver = { .driver = { .name ="tegra-gr3d" , .of_match_table = tegra_gr3d_match, + .pm = &tegra_gr3d_pm, }, .probe = gr3d_probe, .remove = gr3d_remove,
Signature · 1 line
2.29.2
PATCH v2 39/48 drm/tegra: vic: Stop channel before suspending
In reply to Dmitry OsipenkoHost1x channel should be idling before hardware is turned off, hence stop the channel in the suspend callback.
--- drivers/gpu/drm/tegra/vic.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+)
drivers/gpu/drm/tegra/vic.c +15 -0
@@ -510,8 +510,23 @@ static int vic_remove(struct platform_device *pdev)return 0 ; } +static __maybe_unused int vic_suspend (struct device *dev) +{ +struct vic *vic =dev_get_drvdata (dev); +int err; + +host1x_channel_stop (vic->channel); + + err =pm_runtime_force_suspend (dev); +if (err <0 ) +return err; + +return 0 ; +} +static const struct dev_pm_ops vic_pm_ops = { SET_RUNTIME_PM_OPS(vic_runtime_suspend, vic_runtime_resume, NULL) +SET_SYSTEM_SLEEP_PM_OPS (vic_suspend, pm_runtime_force_resume) };struct platform_driver tegra_vic_driver = {
Signature · 1 line
2.29.2
PATCH v2 40/48 media: staging: tegra-vde: Support OPP and generic power domain
In reply to Dmitry OsipenkoAdd OPP and generic power domain support to the video decoder driver. This allows us to utilize a modern GENPD API for newer device-trees and support DVFS of the decoder hardware. Note that older DTBs will continue to work like they did it before this patch.
--- drivers/staging/media/tegra-vde/vde.c | 63 ++++++++++++++++++++++----- 1 file changed, 53 insertions(+), 10 deletions(-)
drivers/staging/media/tegra-vde/vde.c +53 -10
@@ -15,11 +15,14 @@#include <linux/miscdevice.h> #include <linux/module.h> #include <linux/of_device.h> +#include <linux/pm_domain.h> +#include <linux/pm_opp.h> #include <linux/pm_runtime.h> #include <linux/reset.h> #include <linux/slab.h> #include <linux/uaccess.h> +#include <soc/tegra/common.h> #include <soc/tegra/pmc.h> #include "uapi.h"
@@ -918,13 +921,17 @@ static __maybe_unused int tegra_vde_runtime_suspend(struct device *dev)struct tegra_vde *vde =dev_get_drvdata (dev);int err; - err =tegra_powergate_power_off (TEGRA_POWERGATE_VDEC ); -if (err) { -dev_err (dev,"Failed to power down HW: %d\n" , err); -return err; +if (!dev->pm_domain) { + err =tegra_powergate_power_off (TEGRA_POWERGATE_VDEC ); +if (err) { +dev_err (dev,"Failed to power down HW: %d\n" , err); +return err; + } }clk_disable_unprepare (vde->clk); +reset_control_release (vde->rst); +dev_pm_opp_set_rate (dev,0 );return 0 ; }
@@ -934,18 +941,44 @@ static __maybe_unused int tegra_vde_runtime_resume(struct device *dev)struct tegra_vde *vde =dev_get_drvdata (dev);int err; - err =tegra_powergate_sequence_power_up (TEGRA_POWERGATE_VDEC , - vde->clk, vde->rst); + err =dev_pm_opp_set_rate (dev,clk_get_rate (vde->clk)); +if (err) { +dev_err (dev,"Failed to prepare OPP: %d\n" , err); +return err; + } + + err =reset_control_acquire (vde->rst);if (err) { -dev_err (dev,"Failed to power up HW : %d\n" , err); +dev_err (dev,"Failed to acquire reset: %d\n" , err);return err; } +if (!dev->pm_domain) { + err =tegra_powergate_sequence_power_up (TEGRA_POWERGATE_VDEC , + vde->clk, vde->rst); +if (err) { +dev_err (dev,"Failed to power up HW : %d\n" , err); + goto release_reset; + } + } + + err =clk_prepare_enable (vde->clk); +if (err) { +dev_err (dev,"Failed to enable clock: %d\n" , err); + goto release_reset; + } +return 0 ; + +release_reset: +reset_control_release (vde->rst); + +return err; }static int tegra_vde_probe (struct platform_device *pdev) { +struct tegra_core_opp_params opp_params = {};struct device *dev = &pdev->dev;struct tegra_vde *vde;int irq, err;
@@ -999,7 +1032,7 @@ static int tegra_vde_probe(struct platform_device *pdev)return err; } - vde->rst =devm_reset_control_get (dev,NULL ); + vde->rst =devm_reset_control_get_exclusive_released (dev,NULL );if (IS_ERR (vde->rst)) { err =PTR_ERR (vde->rst);dev_err (dev,"Could not get VDE reset %d\n" , err);
@@ -1024,6 +1057,12 @@ static int tegra_vde_probe(struct platform_device *pdev)return err; } + opp_params.init_state = true; + + err =devm_tegra_core_dev_init_opp_table (dev, &opp_params); +if (err && err != -ENODEV ) +return err; + vde->iram_pool =of_gen_pool_get (dev->of_node,"iram" ,0 );if (!vde->iram_pool) {dev_err (dev,"Could not get IRAM pool\n" );
@@ -1117,8 +1156,12 @@ static void tegra_vde_shutdown(struct platform_device *pdev)* On some devices bootloader isn't ready to a power-gated VDE on * a warm-reboot, machine will hang in that case. */ -if (pm_runtime_status_suspended (&pdev->dev)) -tegra_vde_runtime_resume (&pdev->dev); +if (pm_runtime_status_suspended (&pdev->dev)) { +if (pdev->dev.pm_domain) +dev_pm_genpd_resume (&pdev->dev); +else +tegra_vde_runtime_resume (&pdev->dev); + } }static __maybe_unused int tegra_vde_pm_suspend (struct device *dev)
Signature · 1 line
2.29.2
PATCH v2 41/48 memory: tegra20-emc: Use devm_tegra_core_dev_init_opp_table()
In reply to Dmitry OsipenkoUse common devm_tegra_core_dev_init_opp_table() helper for the OPP table initialization.
--- drivers/memory/tegra/tegra20-emc.c | 57 +++--------------------------- 1 file changed, 4 insertions(+), 53 deletions(-)
drivers/memory/tegra/tegra20-emc.c +4 -53
@@ -908,58 +908,6 @@ static int tegra_emc_interconnect_init(struct tegra_emc *emc)return err; } -static int tegra_emc_opp_table_init (struct tegra_emc *emc) -{ -u32 hw_version =BIT (tegra_sku_info.soc_process_id); -struct opp_table *clk_opp_table, *hw_opp_table; -int err; - - clk_opp_table =dev_pm_opp_set_clkname (emc->dev,NULL ); - err =PTR_ERR_OR_ZERO (clk_opp_table); -if (err) { -dev_err (emc->dev,"failed to set OPP clk: %d\n" , err); -return err; - } - - hw_opp_table =dev_pm_opp_set_supported_hw (emc->dev, &hw_version,1 ); - err =PTR_ERR_OR_ZERO (hw_opp_table); -if (err) { -dev_err (emc->dev,"failed to set OPP supported HW: %d\n" , err); - goto put_clk_table; - } - - err =dev_pm_opp_of_add_table (emc->dev); -if (err) { -if (err == -ENODEV ) -dev_err (emc->dev,"OPP table not found, please update your device tree\n" ); -else -dev_err (emc->dev,"failed to add OPP table: %d\n" , err); - - goto put_hw_table; - } - -dev_info (emc->dev,"OPP HW ver. 0x%x, current clock rate %lu MHz\n" , - hw_version,clk_get_rate (emc->clk) /1000000 ); - -/* first dummy rate-set initializes voltage state */ - err =dev_pm_opp_set_rate (emc->dev,clk_get_rate (emc->clk)); -if (err) { -dev_err (emc->dev,"failed to initialize OPP clock: %d\n" , err); - goto remove_table; - } - -return 0 ; - -remove_table: -dev_pm_opp_of_remove_table (emc->dev); -put_hw_table: -dev_pm_opp_put_supported_hw (hw_opp_table); -put_clk_table: -dev_pm_opp_put_clkname (clk_opp_table); - -return err; -} -static void devm_tegra_emc_unset_callback (void *data) {tegra20_clk_set_emc_round_callback (NULL ,NULL );
@@ -1086,6 +1034,7 @@ static int tegra_emc_devfreq_init(struct tegra_emc *emc)static int tegra_emc_probe (struct platform_device *pdev) { +struct tegra_core_opp_params opp_params = {};struct device_node *np;struct tegra_emc *emc;int irq, err;
@@ -1131,7 +1080,9 @@ static int tegra_emc_probe(struct platform_device *pdev)if (err)return err; - err =tegra_emc_opp_table_init (emc); + opp_params.init_state = true; + + err =devm_tegra_core_dev_init_opp_table (&pdev->dev, &opp_params);if (err)return err;
Signature · 1 line
2.29.2
Krzysztof Kozlowski
maintainerRe: [PATCH v2 41/48] memory: tegra20-emc: Use devm_tegra_core_dev_init_opp_table()
Quoted 7 lines · Dmitry Osipenko
Use common
devm_tegra_core_dev_init_opp_table()helper for the OPP table initialization.Signed-off-by Dmitry Osipenko <[email protected]>--- drivers/memory/tegra/tegra20-emc.c | 57 +++--------------------------- 1 file changed, 4 insertions(+), 53 deletions(-)
If there was no more Tegra MC work planned, this could easily go via Tegra SoC tree. However I expect still work of your interconnect patches, so maybe it's better to stick these in same tree.
In such case I would need a stable tag with the devm_tegra_core_dev_init_opp_table() helper for memory controller tree.
Best regards,
Krzysztof
_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel
Re: [PATCH v2 41/48] memory: tegra20-emc: Use devm_tegra_core_dev_init_opp_table()
19.12.2020 14:02, Krzysztof Kozlowski пишет:
Quoted 12 lines · Dmitry Osipenko
Quoted 7 lines
Use common
devm_tegra_core_dev_init_opp_table()helper for the OPP table initialization.Signed-off-by Dmitry Osipenko <[email protected]>--- drivers/memory/tegra/tegra20-emc.c | 57 +++--------------------------- 1 file changed, 4 insertions(+), 53 deletions(-)If there was no more Tegra MC work planned, this could easily go via Tegra SoC tree. However I expect still work of your interconnect patches, so maybe it's better to stick these in same tree.
I'll re-send the remaining interconnect patches soon.
Quoted 2 lines
In such case I would need a stable tag with the
devm_tegra_core_dev_init_opp_table()helper for memory controller tree.
Perhaps will be better to drop these memory changes for now from this series since they are optional, i.e. memory drivers will work properly because voltage changes are done by the OPP core and these patches just replace the duplicated code with a new common helper which doesn't add new features to the memory drivers. It should be fine to get back to these memory patches once interconnect patchset will be fully merged. I'll take it into account in v3, thanks.
PATCH v2 42/48 memory: tegra30-emc: Use devm_tegra_core_dev_init_opp_table()
In reply to Dmitry OsipenkoUse common devm_tegra_core_dev_init_opp_table() helper for the OPP table initialization.
--- drivers/memory/tegra/tegra30-emc.c | 57 +++--------------------------- 1 file changed, 4 insertions(+), 53 deletions(-)
drivers/memory/tegra/tegra30-emc.c +4 -53
@@ -1480,58 +1480,6 @@ static int tegra_emc_interconnect_init(struct tegra_emc *emc)return err; } -static int tegra_emc_opp_table_init (struct tegra_emc *emc) -{ -u32 hw_version =BIT (tegra_sku_info.soc_speedo_id); -struct opp_table *clk_opp_table, *hw_opp_table; -int err; - - clk_opp_table =dev_pm_opp_set_clkname (emc->dev,NULL ); - err =PTR_ERR_OR_ZERO (clk_opp_table); -if (err) { -dev_err (emc->dev,"failed to set OPP clk: %d\n" , err); -return err; - } - - hw_opp_table =dev_pm_opp_set_supported_hw (emc->dev, &hw_version,1 ); - err =PTR_ERR_OR_ZERO (hw_opp_table); -if (err) { -dev_err (emc->dev,"failed to set OPP supported HW: %d\n" , err); - goto put_clk_table; - } - - err =dev_pm_opp_of_add_table (emc->dev); -if (err) { -if (err == -ENODEV ) -dev_err (emc->dev,"OPP table not found, please update your device tree\n" ); -else -dev_err (emc->dev,"failed to add OPP table: %d\n" , err); - - goto put_hw_table; - } - -dev_info (emc->dev,"OPP HW ver. 0x%x, current clock rate %lu MHz\n" , - hw_version,clk_get_rate (emc->clk) /1000000 ); - -/* first dummy rate-set initializes voltage state */ - err =dev_pm_opp_set_rate (emc->dev,clk_get_rate (emc->clk)); -if (err) { -dev_err (emc->dev,"failed to initialize OPP clock: %d\n" , err); - goto remove_table; - } - -return 0 ; - -remove_table: -dev_pm_opp_of_remove_table (emc->dev); -put_hw_table: -dev_pm_opp_put_supported_hw (hw_opp_table); -put_clk_table: -dev_pm_opp_put_clkname (clk_opp_table); - -return err; -} -static void devm_tegra_emc_unset_callback (void *data) {tegra20_clk_set_emc_round_callback (NULL ,NULL );
@@ -1577,6 +1525,7 @@ static int tegra_emc_init_clk(struct tegra_emc *emc)static int tegra_emc_probe (struct platform_device *pdev) { +struct tegra_core_opp_params opp_params = {};struct device_node *np;struct tegra_emc *emc;int err;
@@ -1626,7 +1575,9 @@ static int tegra_emc_probe(struct platform_device *pdev)if (err)return err; - err =tegra_emc_opp_table_init (emc); + opp_params.init_state = true; + + err =devm_tegra_core_dev_init_opp_table (&pdev->dev, &opp_params);if (err)return err;
Signature · 1 line
2.29.2
PATCH v2 43/48 ARM: tegra: Add OPP tables and power domains to Tegra20 device-tree
In reply to Dmitry OsipenkoAdd OPP tables and power domains to the Tegra20 device-tree.
--- .../boot/dts/tegra20-acer-a500-picasso.dts | 4 + arch/arm/boot/dts/tegra20-colibri.dtsi | 6 +- arch/arm/boot/dts/tegra20-harmony.dts | 6 +- arch/arm/boot/dts/tegra20-paz00.dts | 46 +- .../arm/boot/dts/tegra20-peripherals-opp.dtsi | 941 ++++++++++++++++++ arch/arm/boot/dts/tegra20-seaboard.dts | 6 +- arch/arm/boot/dts/tegra20-tamonten.dtsi | 6 +- arch/arm/boot/dts/tegra20-trimslice.dts | 12 + arch/arm/boot/dts/tegra20-ventana.dts | 6 +- arch/arm/boot/dts/tegra20.dtsi | 220 ++++ 10 files changed, 1241 insertions(+), 12 deletions(-)
arch/arm/boot/dts/tegra20-acer-a500-picasso.dts +4 -0
@@ -834,6 +834,10 @@ rtc_32k_wifi: clock@1 { clock-output-names = "kk3270032"; }; + core-domain { + power-supply = <&vdd_core>; + }; + cpus { cpu0: cpu@0 { cpu-supply = <&vdd_cpu>;
arch/arm/boot/dts/tegra20-colibri.dtsi +5 -1
@@ -495,7 +495,7 @@ reg_3v3_vsys: sys { regulator-always-on; }; - sm0 { + vdd_core: sm0 { regulator-name = "VDD_CORE_1.2V"; regulator-min-microvolt = <1200000>; regulator-max-microvolt = <1200000>;
@@ -701,6 +701,10 @@ usb-phy@c5004000 { vbus-supply = <®_lan_v_bus>; }; + core-domain { + power-supply = <&vdd_core>; + }; + clk32k_in: xtal3 { compatible = "fixed-clock"; #clock-cells = <0>;
arch/arm/boot/dts/tegra20-harmony.dts +5 -1
@@ -339,7 +339,7 @@ sys_reg: sys { regulator-always-on; }; - sm0 { + vdd_core: sm0 { regulator-name = "vdd_sm0,vdd_core"; regulator-min-microvolt = <1200000>; regulator-max-microvolt = <1200000>;
@@ -640,6 +640,10 @@ backlight: backlight { default-brightness-level = <6>; }; + core-domain { + power-supply = <&vdd_core>; + }; + clk32k_in: clock@0 { compatible = "fixed-clock"; clock-frequency = <32768>;
arch/arm/boot/dts/tegra20-paz00.dts +39 -7
132 lines not on this page · raw message
arch/arm/boot/dts/tegra20-peripherals-opp.dtsi +941 -0
1,049 lines not on this page · raw message
arch/arm/boot/dts/tegra20-seaboard.dts +5 -1
@@ -444,7 +444,7 @@ sys_reg: sys { regulator-always-on; }; - sm0 { + vdd_core: sm0 { regulator-name = "vdd_sm0,vdd_core"; regulator-min-microvolt = <1300000>; regulator-max-microvolt = <1300000>;
@@ -792,6 +792,10 @@ backlight: backlight { default-brightness-level = <6>; }; + core-domain { + power-supply = <&vdd_core>; + }; + clk32k_in: clock@0 { compatible = "fixed-clock"; clock-frequency = <32768>;
arch/arm/boot/dts/tegra20-tamonten.dtsi +5 -1
@@ -357,7 +357,7 @@ sys_reg: sys { regulator-always-on; }; - sm0 { + vdd_core: sm0 { regulator-name = "vdd_sys_sm0,vdd_core"; regulator-min-microvolt = <1200000>; regulator-max-microvolt = <1200000>;
@@ -502,6 +502,10 @@ mmc@c8000600 { status = "okay"; }; + core-domain { + power-supply = <&vdd_core>; + }; + clk32k_in: clock@0 { compatible = "fixed-clock"; clock-frequency = <32768>;
arch/arm/boot/dts/tegra20-trimslice.dts +12 -0
@@ -379,6 +379,10 @@ mmc@c8000600 { bus-width = <4>; }; + core-domain { + power-supply = <&vdd_core>; + }; + clk32k_in: clock@0 { compatible = "fixed-clock"; clock-frequency = <32768>;
@@ -444,6 +448,14 @@ pci_vdd_reg: regulator@4 { regulator-always-on; }; + vdd_core: regulator@5 { + compatible = "regulator-fixed"; + regulator-name = "vdd_core"; + regulator-min-microvolt = <1300000>; + regulator-max-microvolt = <1300000>; + regulator-always-on; + }; + sound { compatible = "nvidia,tegra-audio-trimslice"; nvidia,i2s-controller = <&tegra_i2s1>;
arch/arm/boot/dts/tegra20-ventana.dts +5 -1
@@ -420,7 +420,7 @@ sys_reg: sys { regulator-always-on; }; - sm0 { + vdd_core: sm0 { regulator-name = "vdd_sm0,vdd_core"; regulator-min-microvolt = <1200000>; regulator-max-microvolt = <1200000>;
@@ -587,6 +587,10 @@ backlight: backlight { default-brightness-level = <6>; }; + core-domain { + power-supply = <&vdd_core>; + }; + clk32k_in: clock@0 { compatible = "fixed-clock"; clock-frequency = <32768>;
arch/arm/boot/dts/tegra20.dtsi +220 -0
304 lines not on this page · raw message
Signature · 1 line
2.29.2
Re: [PATCH v2 43/48] ARM: tegra: Add OPP tables and power domains to Tegra20 device-tree
Quoted 6 lines · Dmitry Osipenko
arch/arm/boot/dts/tegra20-peripherals-opp.dtsi +0
-0@@ -1,6 +1,46 @@ // SPDX-License-Identifier: GPL-2.0
arch/arm/boot/dts/tegra20-peripherals-opp.dtsi line 11
Quoted 10 lines
arch/arm/boot/dts/tegra20-peripherals-opp.dtsi +8
-0/ { + core_opp_table: core-power-domain-opp-table { + compatible = "operating-points-v2"; + opp-shared; + + core_opp_950: opp@950000 { + opp-microvolt = <950000 950000 1300000>; + opp-level = <950000>; + };
I am not sure I fully understand this, why does it have both microvolt and level properties ?
Signature · 1 line
viresh
Re: [PATCH v2 43/48] ARM: tegra: Add OPP tables and power domains to Tegra20 device-tree
22.12.2020 08:47, Viresh Kumar пишет:
Quoted 8 lines · Dmitry Osipenko
Quoted 7 lines
arch/arm/boot/dts/tegra20-peripherals-opp.dtsi +0
-0@@ -1,6 +1,46 @@ // SPDX-License-Identifier: GPL-2.0
Quoted 13 lines
arch/arm/boot/dts/tegra20-peripherals-opp.dtsi line 11
Quoted 9 lines
arch/arm/boot/dts/tegra20-peripherals-opp.dtsi +8
-0/ { + core_opp_table: core-power-domain-opp-table { + compatible = "operating-points-v2"; + opp-shared; + + core_opp_950: opp@950000 { + opp-microvolt = <950000 950000 1300000>; + opp-level = <950000>; + };I am not sure I fully understand this, why does it have both microvolt and level properties ?
The level is used by everything related to GENPD, while voltage is used by the domain driver.
I think it's cleaner to separate the level from voltage, even though they are set to the same values, which is done purely for convenience. The 0,1,2,3 levels are meaningless in the context of this power domain, while voltages make total sense.
PATCH v2 44/48 ARM: tegra: Add OPP tables and power domains to Tegra30 device-tree
In reply to Dmitry OsipenkoAdd OPP tables and power domains to Tegra30 device-tree.
--- .../tegra30-asus-nexus7-grouper-common.dtsi | 4 + arch/arm/boot/dts/tegra30-beaver.dts | 4 + arch/arm/boot/dts/tegra30-cardhu.dtsi | 20 +- arch/arm/boot/dts/tegra30-colibri.dtsi | 20 +- arch/arm/boot/dts/tegra30-ouya.dts | 4 + .../arm/boot/dts/tegra30-peripherals-opp.dtsi | 1412 +++++++++++++++++ arch/arm/boot/dts/tegra30.dtsi | 358 +++++ 7 files changed, 1816 insertions(+), 6 deletions(-)
arch/arm/boot/dts/tegra30-asus-nexus7-grouper-common.dtsi +4 -0
@@ -1047,6 +1047,10 @@ battery_cell: battery-cell { operating-range-celsius = <0 45>; }; + core-domain { + power-supply = <&vdd_core>; + }; + /* PMIC has a built-in 32KHz oscillator which is used by PMC */ clk32k_in: clock@0 { compatible = "fixed-clock";
arch/arm/boot/dts/tegra30-beaver.dts +4 -0
@@ -1965,6 +1965,10 @@ usb-phy@7d008000 { status = "okay"; }; + core-domain { + power-supply = <&core_vdd_reg>; + }; + clk32k_in: clock@0 { compatible = "fixed-clock"; clock-frequency = <32768>;
arch/arm/boot/dts/tegra30-cardhu.dtsi +17 -3
@@ -272,9 +272,14 @@ vdd2_reg: vdd2 { vddctrl_reg: vddctrl { regulator-name = "vdd_cpu,vdd_sys"; - regulator-min-microvolt = <1000000>; - regulator-max-microvolt = <1000000>; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <1250000>; + regulator-coupled-with = <&vdd_core>; + regulator-coupled-max-spread = <300000>; + regulator-max-step-microvolt = <100000>; regulator-always-on; + + nvidia,tegra-cpu-regulator; }; vio_reg: vio {
@@ -342,17 +347,22 @@ temperature-sensor@4c { interrupts = <TEGRA_GPIO(CC, 2) IRQ_TYPE_LEVEL_LOW>; }; - tps62361@60 { + vdd_core: tps62361@60 { compatible = "ti,tps62361"; reg = <0x60>; regulator-name = "tps62361-vout"; regulator-min-microvolt = <500000>; regulator-max-microvolt = <1500000>; + regulator-coupled-with = <&vddctrl_reg>; + regulator-coupled-max-spread = <300000>; + regulator-max-step-microvolt = <100000>; regulator-boot-on; regulator-always-on; ti,vsel0-state-high; ti,vsel1-state-high; + + nvidia,tegra-core-regulator; }; };
@@ -418,6 +428,10 @@ backlight: backlight { default-brightness-level = <6>; }; + core-domain { + power-supply = <&vdd_core>; + }; + clk32k_in: clock@0 { compatible = "fixed-clock"; clock-frequency = <32768>;
arch/arm/boot/dts/tegra30-colibri.dtsi +17 -3
@@ -764,9 +764,14 @@ vdd1_reg: vdd1 { vddctrl_reg: vddctrl { regulator-name = "+V1.0_VDD_CPU"; - regulator-min-microvolt = <1150000>; - regulator-max-microvolt = <1150000>; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <1250000>; + regulator-coupled-with = <&vdd_core>; + regulator-coupled-max-spread = <300000>; + regulator-max-step-microvolt = <100000>; regulator-always-on; + + nvidia,tegra-cpu-regulator; }; reg_1v8_vio: vio {
@@ -889,18 +894,23 @@ temp-sensor@4c { }; /* SW: +V1.2_VDD_CORE */ - regulator@60 { + vdd_core: regulator@60 { compatible = "ti,tps62362"; reg = <0x60>; regulator-name = "tps62362-vout"; regulator-min-microvolt = <900000>; regulator-max-microvolt = <1400000>; + regulator-coupled-with = <&vddctrl_reg>; + regulator-coupled-max-spread = <300000>; + regulator-max-step-microvolt = <100000>; regulator-boot-on; regulator-always-on; ti,vsel0-state-low; /* VSEL1: EN_CORE_DVFS_N low for DVFS */ ti,vsel1-state-low; + + nvidia,tegra-core-regulator; }; };
@@ -960,6 +970,10 @@ usb-phy@7d004000 { vbus-supply = <®_lan_v_bus>; }; + core-domain { + power-supply = <&vdd_core>; + }; + clk32k_in: xtal1 { compatible = "fixed-clock"; #clock-cells = <0>;
arch/arm/boot/dts/tegra30-ouya.dts +4 -0
@@ -377,6 +377,10 @@ usb-phy@7d008000 { status = "okay"; }; + core-domain { + power-supply = <&vdd_core>; + }; + /* PMIC has a built-in 32KHz oscillator which is used by PMC */ clk32k_in: clock { compatible = "fixed-clock";
arch/arm/boot/dts/tegra30-peripherals-opp.dtsi +1412 -0
1,680 lines not on this page · raw message
arch/arm/boot/dts/tegra30.dtsi +358 -0
442 lines not on this page · raw message
Signature · 1 line
2.29.2
Re: [PATCH v2 44/48] ARM: tegra: Add OPP tables and power domains to Tegra30 device-tree
Quoted 5 lines · Dmitry Osipenko
arch/arm/boot/dts/tegra30-peripherals-opp.dtsi +0
-0
arch/arm/boot/dts/tegra30-peripherals-opp.dtsi line 10
Quoted 10 lines
arch/arm/boot/dts/tegra30-peripherals-opp.dtsi +7
-0@@ -1,6 +1,56 @@ // SPDX-License-Identifier: GPL-2.0 / { + core_opp_table: core-power-domain-opp-table { + compatible = "operating-points-v2"; + opp-shared; + + core_opp_950: opp@950000 { + opp-microvolt = <950000 950000 1350000>; + opp-level = <950000>;
Perhaps you don't need to exactly copy the voltage value into the level field. The level field can just be kept to 0, 1,2, 3, etc..
Quoted 42 lines
arch/arm/boot/dts/tegra30-peripherals-opp.dtsi +42
-0+ }; + + core_opp_1000: opp@1000000 { + opp-microvolt = <1000000 1000000 1350000>; + opp-level = <1000000>; + }; + + core_opp_1050: opp@1050000 { + opp-microvolt = <1050000 1050000 1350000>; + opp-level = <1050000>; + }; + + core_opp_1100: opp@1100000 { + opp-microvolt = <1100000 1100000 1350000>; + opp-level = <1100000>; + }; + + core_opp_1150: opp@1150000 { + opp-microvolt = <1150000 1150000 1350000>; + opp-level = <1150000>; + }; + + core_opp_1200: opp@1200000 { + opp-microvolt = <1200000 1200000 1350000>; + opp-level = <1200000>; + }; + + core_opp_1250: opp@1250000 { + opp-microvolt = <1250000 1250000 1350000>; + opp-level = <1250000>; + }; + + core_opp_1300: opp@1300000 { + opp-microvolt = <1300000 1300000 1350000>; + opp-level = <1300000>; + }; + + core_opp_1350: opp@1350000 { + opp-microvolt = <1350000 1350000 1350000>; + opp-level = <1350000>; + }; + };
Signature · 1 line
viresh
Re: [PATCH v2 44/48] ARM: tegra: Add OPP tables and power domains to Tegra30 device-tree
22.12.2020 12:14, Viresh Kumar пишет:
Quoted 8 lines · Dmitry Osipenko
Quoted 7 lines
arch/arm/boot/dts/tegra30-peripherals-opp.dtsi +0
-0@@ -1,6 +1,56 @@ // SPDX-License-Identifier: GPL-2.0
Quoted 11 lines
arch/arm/boot/dts/tegra30-peripherals-opp.dtsi line 10
Quoted 8 lines
arch/arm/boot/dts/tegra30-peripherals-opp.dtsi +7
-0/ { + core_opp_table: core-power-domain-opp-table { + compatible = "operating-points-v2"; + opp-shared; + + core_opp_950: opp@950000 { + opp-microvolt = <950000 950000 1350000>; + opp-level = <950000>;Perhaps you don't need to exactly copy the voltage value into the level field. The level field can just be kept to 0, 1,2, 3, etc..
It's much more convenient to set both fields to the same value because the level values are shown in GENPD debugfs and the 0,1,2 values are meaningless from the debugging perspective.
PATCH v2 45/48 ARM: tegra: acer-a500: Enable core voltage scaling
In reply to Dmitry OsipenkoAllow lower core voltages on Acer A500.
--- arch/arm/boot/dts/tegra20-acer-a500-picasso.dts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
arch/arm/boot/dts/tegra20-acer-a500-picasso.dts +2 -2
@@ -578,7 +578,7 @@ sys_reg: sys { vdd_core: sm0 { regulator-name = "vdd_sm0,vdd_core"; - regulator-min-microvolt = <1200000>; + regulator-min-microvolt = <950000>; regulator-max-microvolt = <1300000>; regulator-coupled-with = <&rtc_vdd &vdd_cpu>; regulator-coupled-max-spread = <170000 550000>;
@@ -619,7 +619,7 @@ ldo1 { rtc_vdd: ldo2 { regulator-name = "vdd_ldo2,vdd_rtc"; - regulator-min-microvolt = <1200000>; + regulator-min-microvolt = <950000>; regulator-max-microvolt = <1300000>; regulator-coupled-with = <&vdd_core &vdd_cpu>; regulator-coupled-max-spread = <170000 550000>;
Signature · 1 line
2.29.2
PATCH v2 46/48 ARM: tegra: ventana: Enable core voltage scaling
In reply to Dmitry OsipenkoAllow lower core voltages on Ventana board.
--- arch/arm/boot/dts/tegra20-ventana.dts | 32 ++++++++++++++++++++------- 1 file changed, 24 insertions(+), 8 deletions(-)
arch/arm/boot/dts/tegra20-ventana.dts +24 -8
@@ -422,16 +422,26 @@ sys_reg: sys { vdd_core: sm0 { regulator-name = "vdd_sm0,vdd_core"; - regulator-min-microvolt = <1200000>; - regulator-max-microvolt = <1200000>; + regulator-min-microvolt = <950000>; + regulator-max-microvolt = <1300000>; + regulator-coupled-with = <&rtc_vdd &vdd_cpu>; + regulator-coupled-max-spread = <170000 550000>; regulator-always-on; + regulator-boot-on; + + nvidia,tegra-core-regulator; }; - sm1 { + vdd_cpu: sm1 { regulator-name = "vdd_sm1,vdd_cpu"; - regulator-min-microvolt = <1000000>; - regulator-max-microvolt = <1000000>; + regulator-min-microvolt = <750000>; + regulator-max-microvolt = <1125000>; + regulator-coupled-with = <&vdd_core &rtc_vdd>; + regulator-coupled-max-spread = <550000 550000>; regulator-always-on; + regulator-boot-on; + + nvidia,tegra-cpu-regulator; }; sm2_reg: sm2 {
@@ -450,10 +460,16 @@ ldo1 { regulator-always-on; }; - ldo2 { + rtc_vdd: ldo2 { regulator-name = "vdd_ldo2,vdd_rtc"; - regulator-min-microvolt = <1200000>; - regulator-max-microvolt = <1200000>; + regulator-min-microvolt = <950000>; + regulator-max-microvolt = <1300000>; + regulator-coupled-with = <&vdd_core &vdd_cpu>; + regulator-coupled-max-spread = <170000 550000>; + regulator-always-on; + regulator-boot-on; + + nvidia,tegra-rtc-regulator; }; ldo3 {
Signature · 1 line
2.29.2
PATCH v2 47/48 ARM: tegra: ventana: Support CPU voltage scaling and thermal throttling
In reply to Dmitry OsipenkoEnable CPU voltage scaling and thermal throttling on Tegra20 Ventana board.
--- arch/arm/boot/dts/tegra20-ventana.dts | 40 ++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-)
arch/arm/boot/dts/tegra20-ventana.dts +39 -1
@@ -2,8 +2,10 @@ /dts-v1/; #include <dt-bindings/input/input.h> +#include <dt-bindings/thermal/thermal.h> #include "tegra20.dtsi" #include "tegra20-cpu-opp.dtsi" +#include "tegra20-cpu-opp-microvolt.dtsi" / { model = "NVIDIA Tegra20 Ventana evaluation board";
@@ -527,9 +529,10 @@ ldo_rtc { }; }; - temperature-sensor@4c { + nct1008: temperature-sensor@4c { compatible = "onnn,nct1008"; reg = <0x4c>; + #thermal-sensor-cells = <1>; }; };
@@ -615,10 +618,13 @@ clk32k_in: clock@0 { cpus { cpu0: cpu@0 { + cpu-supply = <&vdd_cpu>; operating-points-v2 = <&cpu0_opp_table>; + #cooling-cells = <2>; }; cpu@1 { + cpu-supply = <&vdd_cpu>; operating-points-v2 = <&cpu0_opp_table>; }; };
@@ -717,4 +723,36 @@ sound { <&tegra_car TEGRA20_CLK_CDEV1>; clock-names = "pll_a", "pll_a_out0", "mclk"; }; + + thermal-zones { + cpu-thermal { + polling-delay-passive = <1000>; /* milliseconds */ + polling-delay = <5000>; /* milliseconds */ + + thermal-sensors = <&nct1008 1>; + + trips { + trip0: cpu-alert0 { + /* start throttling at 50C */ + temperature = <50000>; + hysteresis = <200>; + type = "passive"; + }; + + trip1: cpu-crit { + /* shut down at 60C */ + temperature = <60000>; + hysteresis = <2000>; + type = "critical"; + }; + }; + + cooling-maps { + map0 { + trip = <&trip0>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + }; + }; + }; };
Signature · 1 line
2.29.2
Re: [PATCH v2 47/48] ARM: tegra: ventana: Support CPU voltage scaling and thermal throttling
Quoted 55 lines · Dmitry Osipenko
Enable CPU voltage scaling and thermal throttling on Tegra20 Ventana board.
Signed-off-by Dmitry Osipenko <[email protected]>--- arch/arm/boot/dts/tegra20-ventana.dts | 40 ++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-)arch/arm/boot/dts/tegra20-ventana.dts +10
-1@@ -2,8 +2,10 @@ /dts-v1/; #include <dt-bindings/input/input.h> +#include <dt-bindings/thermal/thermal.h> #include "tegra20.dtsi" #include "tegra20-cpu-opp.dtsi" +#include "tegra20-cpu-opp-microvolt.dtsi" / { model = "NVIDIA Tegra20 Ventana evaluation board";@@ -527,9 +529,10 @@ ldo_rtc { }; }; - temperature-sensor@4c { + nct1008: temperature-sensor@4c { compatible = "onnn,nct1008"; reg = <0x4c>; + #thermal-sensor-cells = <1>; }; };@@ -615,10 +618,13 @@ clk32k_in: clock@0 { cpus { cpu0: cpu@0 { + cpu-supply = <&vdd_cpu>; operating-points-v2 = <&cpu0_opp_table>; + #cooling-cells = <2>; }; cpu@1 { + cpu-supply = <&vdd_cpu>; operating-points-v2 = <&cpu0_opp_table>; }; };@@ -717,4 +723,36 @@ sound { <&tegra_car TEGRA20_CLK_CDEV1>; clock-names = "pll_a", "pll_a_out0", "mclk"; }; + + thermal-zones { + cpu-thermal {
arch/arm/boot/dts/tegra20-ventana.dts sound { · line 738
Quoted 10 lines
arch/arm/boot/dts/tegra20-ventana.dts +10
-0+ polling-delay-passive = <1000>; /* milliseconds */ + polling-delay = <5000>; /* milliseconds */ + + thermal-sensors = <&nct1008 1>; + + trips { + trip0: cpu-alert0 { + /* start throttling at 50C */ + temperature = <50000>; + hysteresis = <200>;
Did you mean <2000> ?
arch/arm/boot/dts/tegra20-ventana.dts sound { · line 745
Quoted 7 lines
arch/arm/boot/dts/tegra20-ventana.dts +7
-0+ type = "passive"; + }; + + trip1: cpu-crit { + /* shut down at 60C */ + temperature = <60000>; + hysteresis = <2000>;
I think you can drop the hysteresis here, when the critical temperature is reached, there is an emergency shutdown.
50°C and 60°C sound very low values, no ?
arch/arm/boot/dts/tegra20-ventana.dts sound { · line 753
Quoted 8 lines
arch/arm/boot/dts/tegra20-ventana.dts +8
-0+ type = "critical"; + }; + }; + + cooling-maps { + map0 { + trip = <&trip0>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
You should add all CPUs here.
Quoted 6 lines
arch/arm/boot/dts/tegra20-ventana.dts +4
-0+ }; + }; + }; + }; };
Signature · 5 lines
<http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs Follow Linaro: <http://www.facebook.com/pages/Linaro> Facebook | <http://twitter.com/#!/linaroorg> Twitter | <http://www.linaro.org/linaro-blog/> Blog
Re: [PATCH v2 47/48] ARM: tegra: ventana: Support CPU voltage scaling and thermal throttling
17.12.2020 21:28, Daniel Lezcano пишет:
Quoted 60 lines · Dmitry Osipenko
Quoted 59 lines
Enable CPU voltage scaling and thermal throttling on Tegra20 Ventana board.
Signed-off-by Dmitry Osipenko <[email protected]>--- arch/arm/boot/dts/tegra20-ventana.dts | 40 ++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-)arch/arm/boot/dts/tegra20-ventana.dts +14
-1@@ -2,8 +2,10 @@ /dts-v1/; #include <dt-bindings/input/input.h> +#include <dt-bindings/thermal/thermal.h> #include "tegra20.dtsi" #include "tegra20-cpu-opp.dtsi" +#include "tegra20-cpu-opp-microvolt.dtsi" / { model = "NVIDIA Tegra20 Ventana evaluation board";@@ -527,9 +529,10 @@ ldo_rtc { }; }; - temperature-sensor@4c { + nct1008: temperature-sensor@4c { compatible = "onnn,nct1008"; reg = <0x4c>; + #thermal-sensor-cells = <1>; }; };@@ -615,10 +618,13 @@ clk32k_in: clock@0 { cpus { cpu0: cpu@0 { + cpu-supply = <&vdd_cpu>; operating-points-v2 = <&cpu0_opp_table>; + #cooling-cells = <2>; }; cpu@1 { + cpu-supply = <&vdd_cpu>; operating-points-v2 = <&cpu0_opp_table>; }; };@@ -717,4 +723,36 @@ sound { <&tegra_car TEGRA20_CLK_CDEV1>; clock-names = "pll_a", "pll_a_out0", "mclk"; }; + + thermal-zones { + cpu-thermal { + polling-delay-passive = <1000>; /* milliseconds */ + polling-delay = <5000>; /* milliseconds */ + + thermal-sensors = <&nct1008 1>;
Quoted 8 lines
arch/arm/boot/dts/tegra20-ventana.dts sound { · line 738
Quoted 6 lines
arch/arm/boot/dts/tegra20-ventana.dts +6
-0+ + trips { + trip0: cpu-alert0 { + /* start throttling at 50C */ + temperature = <50000>; + hysteresis = <200>;Did you mean <2000> ?
The <200> is correct.
Please see this commit for example:
Quoted 10 lines
arch/arm/boot/dts/tegra20-ventana.dts sound { · line 745
Quoted 7 lines
arch/arm/boot/dts/tegra20-ventana.dts +7
-0+ type = "passive"; + }; + + trip1: cpu-crit { + /* shut down at 60C */ + temperature = <60000>; + hysteresis = <2000>;I think you can drop the hysteresis here, when the critical temperature is reached, there is an emergency shutdown.
Yes, perhaps you're right. Hysteresis doesn't make sense for a critical trip. I'll improve it in the next revision, thanks.
Quoted 1 line
50°C and 60°C sound very low values, no ?
Tegra20 CPU is very cold in comparison to later generations, it should stay under 50°C even at a full load.
Quoted 10 lines
arch/arm/boot/dts/tegra20-ventana.dts sound { · line 753
Quoted 8 lines
arch/arm/boot/dts/tegra20-ventana.dts +8
-0+ type = "critical"; + }; + }; + + cooling-maps { + map0 { + trip = <&trip0>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;You should add all CPUs here.
All CPU cores are coupled on Tegra in regards to CPUFreq, hence I think it won't make any difference if secondary CPU cores will be added here, isn't it?
Re: [PATCH v2 47/48] ARM: tegra: ventana: Support CPU voltage scaling and thermal throttling
Quoted 70 lines · Dmitry Osipenko
17.12.2020 21:28, Daniel Lezcano пишет:
Quoted 60 lines · Dmitry Osipenko
Quoted 59 lines
Enable CPU voltage scaling and thermal throttling on Tegra20 Ventana board.
Signed-off-by Dmitry Osipenko <[email protected]>--- arch/arm/boot/dts/tegra20-ventana.dts | 40 ++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-)arch/arm/boot/dts/tegra20-ventana.dts +14
-1@@ -2,8 +2,10 @@ /dts-v1/; #include <dt-bindings/input/input.h> +#include <dt-bindings/thermal/thermal.h> #include "tegra20.dtsi" #include "tegra20-cpu-opp.dtsi" +#include "tegra20-cpu-opp-microvolt.dtsi" / { model = "NVIDIA Tegra20 Ventana evaluation board";@@ -527,9 +529,10 @@ ldo_rtc { }; }; - temperature-sensor@4c { + nct1008: temperature-sensor@4c { compatible = "onnn,nct1008"; reg = <0x4c>; + #thermal-sensor-cells = <1>; }; };@@ -615,10 +618,13 @@ clk32k_in: clock@0 { cpus { cpu0: cpu@0 { + cpu-supply = <&vdd_cpu>; operating-points-v2 = <&cpu0_opp_table>; + #cooling-cells = <2>; }; cpu@1 { + cpu-supply = <&vdd_cpu>; operating-points-v2 = <&cpu0_opp_table>; }; };@@ -717,4 +723,36 @@ sound { <&tegra_car TEGRA20_CLK_CDEV1>; clock-names = "pll_a", "pll_a_out0", "mclk"; }; + + thermal-zones { + cpu-thermal { + polling-delay-passive = <1000>; /* milliseconds */ + polling-delay = <5000>; /* milliseconds */ + + thermal-sensors = <&nct1008 1>;Quoted 8 lines
arch/arm/boot/dts/tegra20-ventana.dts sound { · line 738
Quoted 6 lines
arch/arm/boot/dts/tegra20-ventana.dts +6
-0+ + trips { + trip0: cpu-alert0 { + /* start throttling at 50C */ + temperature = <50000>; + hysteresis = <200>;Did you mean <2000> ?
Quoted 5 lines
The <200> is correct.
Please see this commit for example:
Ok, thanks for the pointer.
Quoted 11 lines
Quoted 10 lines
arch/arm/boot/dts/tegra20-ventana.dts sound { · line 745
Quoted 7 lines
arch/arm/boot/dts/tegra20-ventana.dts +7
-0+ type = "passive"; + }; + + trip1: cpu-crit { + /* shut down at 60C */ + temperature = <60000>; + hysteresis = <2000>;I think you can drop the hysteresis here, when the critical temperature is reached, there is an emergency shutdown.
Quoted 7 lines
Yes, perhaps you're right. Hysteresis doesn't make sense for a critical trip. I'll improve it in the next revision, thanks.
Quoted 1 line
50°C and 60°C sound very low values, no ?
Tegra20 CPU is very cold in comparison to later generations, it should stay under 50°C even at a full load.
Interesting, thanks.
Quoted 12 lines
Quoted 10 lines
arch/arm/boot/dts/tegra20-ventana.dts sound { · line 753
Quoted 8 lines
arch/arm/boot/dts/tegra20-ventana.dts +8
-0+ type = "critical"; + }; + }; + + cooling-maps { + map0 { + trip = <&trip0>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;You should add all CPUs here.
Quoted 3 lines
All CPU cores are coupled on Tegra in regards to CPUFreq, hence I think it won't make any difference if secondary CPU cores will be added here, isn't it?
The explanation is in the description of commit ef4734500407ce4d
Signature · 5 lines
<http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs Follow Linaro: <http://www.facebook.com/pages/Linaro> Facebook | <http://twitter.com/#!/linaroorg> Twitter | <http://www.linaro.org/linaro-blog/> Blog
Re: [PATCH v2 47/48] ARM: tegra: ventana: Support CPU voltage scaling and thermal throttling
17.12.2020 22:36, Daniel Lezcano пишет:
Quoted 10 lines
Quoted 10 lines
Quoted 9 lines
arch/arm/boot/dts/tegra20-ventana.dts sound { · line 753
Quoted 8 lines
arch/arm/boot/dts/tegra20-ventana.dts +8
-0+ type = "critical"; + }; + }; + + cooling-maps { + map0 { + trip = <&trip0>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;You should add all CPUs here.
Quoted 4 lines
Quoted 3 lines
All CPU cores are coupled on Tegra in regards to CPUFreq, hence I think it won't make any difference if secondary CPU cores will be added here, isn't it?
The explanation is in the description of commit
ef4734500407ce4d
I think that really only makes sense if CPU cores have independent clock rate management. IIRC, I actually made some research about this in the past and intentionally removed the secondary cores from the cooling-device since they didn't make any difference for a coupled CPU cores.
That commit also says:
"But as soon as this CPU ordering changes and any other CPU is used to bring up the cooling device, we will start seeing failures."
I don't quite understand to what "failures" that commit referrers. I tried to change the cpu0 to cpu1 in the cooling-device and don't see any failures. Could you please clarify this?
In general it should be fine to add all the cores to the cooling-device and I'll do it in v3, but I want to make it clear why this is needed.
Re: [PATCH v2 47/48] ARM: tegra: ventana: Support CPU voltage scaling and thermal throttling
Quoted 11 lines · Dmitry Osipenko
17.12.2020 22:36, Daniel Lezcano пишет:
Quoted 10 lines
Quoted 10 lines
Quoted 9 lines
arch/arm/boot/dts/tegra20-ventana.dts sound { · line 753
Quoted 8 lines
arch/arm/boot/dts/tegra20-ventana.dts +8
-0+ type = "critical"; + }; + }; + + cooling-maps { + map0 { + trip = <&trip0>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;You should add all CPUs here.
Quoted 7 lines
Quoted 4 lines
Quoted 3 lines
All CPU cores are coupled on Tegra in regards to CPUFreq, hence I think it won't make any difference if secondary CPU cores will be added here, isn't it?
The explanation is in the description of commit
ef4734500407ce4dI think that really only makes sense if CPU cores have independent clock rate management.
ATM I did not see any ARM platform having a clock line per CPU but I may be wrong.
Quoted 10 lines
IIRC, I actually made some research about this in the
past and intentionally removed the secondary cores from the cooling-device since they didn't make any difference for a coupled CPU cores.That commit also says:
"But as soon as this CPU ordering changes and any other CPU is used to bring up the cooling device, we will start seeing failures."
Quoted 6 lines
I don't quite understand to what "failures" that commit referrers. I tried to change the cpu0 to cpu1 in the cooling-device and don't see any failures. Could you please clarify this?
In general it should be fine to add all the cores to the cooling-device and I'll do it in v3, but I want to make it clear why this is needed.
AFAIR, if CPU0 is unplugged the cooling device can not rebind to CPU1. And if CPU0 is plugged in again, the cooling device fails to initialize.
And, if the CPUs are mapped with the physical CPU0 to Linux numbering CPU1, the cooling device mapping will fail.
Signature · 5 lines
<http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs Follow Linaro: <http://www.facebook.com/pages/Linaro> Facebook | <http://twitter.com/#!/linaroorg> Twitter | <http://www.linaro.org/linaro-blog/> Blog
Re: [PATCH v2 47/48] ARM: tegra: ventana: Support CPU voltage scaling and thermal throttling
18.12.2020 00:19, Daniel Lezcano пишет:
Quoted 37 lines · Dmitry Osipenko
Quoted 11 lines
17.12.2020 22:36, Daniel Lezcano пишет:
Quoted 10 lines
Quoted 10 lines
Quoted 9 lines
arch/arm/boot/dts/tegra20-ventana.dts sound { · line 753
Quoted 8 lines
arch/arm/boot/dts/tegra20-ventana.dts +8
-0+ type = "critical"; + }; + }; + + cooling-maps { + map0 { + trip = <&trip0>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;You should add all CPUs here.
Quoted 7 lines
Quoted 4 lines
Quoted 3 lines
All CPU cores are coupled on Tegra in regards to CPUFreq, hence I think it won't make any difference if secondary CPU cores will be added here, isn't it?
The explanation is in the description of commit
ef4734500407ce4dI think that really only makes sense if CPU cores have independent clock rate management.
ATM I did not see any ARM platform having a clock line per CPU but I may be wrong.
Quoted 14 lines
IIRC, I actually made some research about this in the
past and intentionally removed the secondary cores from the cooling-device since they didn't make any difference for a coupled CPU cores.That commit also says:
"But as soon as this CPU ordering changes and any other CPU is used to bring up the cooling device, we will start seeing failures."
I don't quite understand to what "failures" that commit referrers. I tried to change the cpu0 to cpu1 in the cooling-device and don't see any failures. Could you please clarify this?
Quoted 8 lines
Quoted 2 lines
In general it should be fine to add all the cores to the cooling-device and I'll do it in v3, but I want to make it clear why this is needed.
AFAIR, if CPU0 is unplugged the cooling device can not rebind to CPU1. And if CPU0 is plugged in again, the cooling device fails to initialize.
And, if the CPUs are mapped with the physical CPU0 to Linux numbering CPU1, the cooling device mapping will fail.
Alright, thank you.
PATCH v2 48/48 ARM: tegra: cardhu: Support CPU voltage scaling and thermal throttling
In reply to Dmitry OsipenkoEnable CPU voltage scaling and thermal throttling on Tegra30 Cardhu board.
--- arch/arm/boot/dts/tegra30-cardhu.dtsi | 61 ++++++++++++++++++++++++++- 1 file changed, 60 insertions(+), 1 deletion(-)
arch/arm/boot/dts/tegra30-cardhu.dtsi +60 -1
@@ -1,6 +1,9 @@ // SPDX-License-Identifier: GPL-2.0 #include <dt-bindings/input/input.h> +#include <dt-bindings/thermal/thermal.h> #include "tegra30.dtsi" +#include "tegra30-cpu-opp.dtsi" +#include "tegra30-cpu-opp-microvolt.dtsi" /** * This file contains common DT entry for all fab version of Cardhu.
@@ -339,12 +342,13 @@ ldo8_reg: ldo8 { }; }; - temperature-sensor@4c { + nct1008: temperature-sensor@4c { compatible = "onnn,nct1008"; reg = <0x4c>; vcc-supply = <&sys_3v3_reg>; interrupt-parent = <&gpio>; interrupts = <TEGRA_GPIO(CC, 2) IRQ_TYPE_LEVEL_LOW>; + #thermal-sensor-cells = <1>; }; vdd_core: tps62361@60 {
@@ -438,6 +442,29 @@ clk32k_in: clock@0 { #clock-cells = <0>; }; + cpus { + cpu0: cpu@0 { + cpu-supply = <&vddctrl_reg>; + operating-points-v2 = <&cpu0_opp_table>; + #cooling-cells = <2>; + }; + + cpu@1 { + cpu-supply = <&vddctrl_reg>; + operating-points-v2 = <&cpu0_opp_table>; + }; + + cpu@2 { + cpu-supply = <&vddctrl_reg>; + operating-points-v2 = <&cpu0_opp_table>; + }; + + cpu@3 { + cpu-supply = <&vddctrl_reg>; + operating-points-v2 = <&cpu0_opp_table>; + }; + }; + panel: panel { compatible = "chunghwa,claa101wb01"; ddc-i2c-bus = <&panelddc>;
@@ -617,6 +644,38 @@ sound { <&tegra_car TEGRA30_CLK_EXTERN1>; }; + thermal-zones { + cpu-thermal { + polling-delay-passive = <1000>; /* milliseconds */ + polling-delay = <5000>; /* milliseconds */ + + thermal-sensors = <&nct1008 1>; + + trips { + trip0: cpu-alert0 { + /* throttle at 57C until temperature drops to 56.8C */ + temperature = <57000>; + hysteresis = <200>; + type = "passive"; + }; + + trip1: cpu-crit { + /* shut down at 60C */ + temperature = <60000>; + hysteresis = <2000>; + type = "critical"; + }; + }; + + cooling-maps { + map0 { + trip = <&trip0>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + }; + }; + }; + gpio-keys { compatible = "gpio-keys";
Signature · 1 line
2.29.2
Re: [PATCH v2 48/48] ARM: tegra: cardhu: Support CPU voltage scaling and thermal throttling
Quoted 4 lines · Dmitry Osipenko
Enable CPU voltage scaling and thermal throttling on Tegra30 Cardhu board.
Signed-off-by Dmitry Osipenko <[email protected]>---
Same comments as 47/48
Quoted 102 lines
arch/arm/boot/dts/tegra30-cardhu.dtsi | 61 ++++++++++++++++++++++++++- 1 file changed, 60 insertions(+), 1 deletion(-)arch/arm/boot/dts/tegra30-cardhu.dtsi +60
-1@@ -1,6 +1,9 @@ // SPDX-License-Identifier: GPL-2.0 #include <dt-bindings/input/input.h> +#include <dt-bindings/thermal/thermal.h> #include "tegra30.dtsi" +#include "tegra30-cpu-opp.dtsi" +#include "tegra30-cpu-opp-microvolt.dtsi" /** * This file contains common DT entry for all fab version of Cardhu.@@ -339,12 +342,13 @@ ldo8_reg: ldo8 { }; }; - temperature-sensor@4c { + nct1008: temperature-sensor@4c { compatible = "onnn,nct1008"; reg = <0x4c>; vcc-supply = <&sys_3v3_reg>; interrupt-parent = <&gpio>; interrupts = <TEGRA_GPIO(CC, 2) IRQ_TYPE_LEVEL_LOW>; + #thermal-sensor-cells = <1>; }; vdd_core: tps62361@60 {@@ -438,6 +442,29 @@ clk32k_in: clock@0 { #clock-cells = <0>; }; + cpus { + cpu0: cpu@0 { + cpu-supply = <&vddctrl_reg>; + operating-points-v2 = <&cpu0_opp_table>; + #cooling-cells = <2>; + }; + + cpu@1 { + cpu-supply = <&vddctrl_reg>; + operating-points-v2 = <&cpu0_opp_table>; + }; + + cpu@2 { + cpu-supply = <&vddctrl_reg>; + operating-points-v2 = <&cpu0_opp_table>; + }; + + cpu@3 { + cpu-supply = <&vddctrl_reg>; + operating-points-v2 = <&cpu0_opp_table>; + }; + }; + panel: panel { compatible = "chunghwa,claa101wb01"; ddc-i2c-bus = <&panelddc>;@@ -617,6 +644,38 @@ sound { <&tegra_car TEGRA30_CLK_EXTERN1>; }; + thermal-zones { + cpu-thermal { + polling-delay-passive = <1000>; /* milliseconds */ + polling-delay = <5000>; /* milliseconds */ + + thermal-sensors = <&nct1008 1>; + + trips { + trip0: cpu-alert0 { + /* throttle at 57C until temperature drops to 56.8C */ + temperature = <57000>; + hysteresis = <200>; + type = "passive"; + }; + + trip1: cpu-crit { + /* shut down at 60C */ + temperature = <60000>; + hysteresis = <2000>; + type = "critical"; + }; + }; + + cooling-maps { + map0 { + trip = <&trip0>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + }; + }; + }; + gpio-keys { compatible = "gpio-keys";
Signature · 5 lines
<http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs Follow Linaro: <http://www.facebook.com/pages/Linaro> Facebook | <http://twitter.com/#!/linaroorg> Twitter | <http://www.linaro.org/linaro-blog/> Blog
Quoted 5 lines · Dmitry Osipenko
Introduce core voltage scaling for NVIDIA Tegra20/30 SoCs, which reduces power consumption and heating of the Tegra chips. Tegra SoC has multiple hardware units which belong to a core power domain of the SoC and share the core voltage. The voltage must be selected in accordance to a minimum requirement of every core hardware unit.
Please submit the OPP changes separately (alone), it will never get merged this way. Send fixes at the top, any features you want later in the series. It is fine for you to base your series of patches which are under review, you just need to mention that in your cover letter for your platform's patchset.
Signature · 1 line
viresh
18.12.2020 10:14, Viresh Kumar пишет:
Quoted 7 lines · Dmitry Osipenko
Quoted 5 lines
Introduce core voltage scaling for NVIDIA Tegra20/30 SoCs, which reduces power consumption and heating of the Tegra chips. Tegra SoC has multiple hardware units which belong to a core power domain of the SoC and share the core voltage. The voltage must be selected in accordance to a minimum requirement of every core hardware unit.
Quoted 6 lines
Please submit the OPP changes separately (alone), it will never get merged this way. Send fixes at the top, any features you want later in the series. It is fine for you to base your series of patches which are under review, you just need to mention that in your cover letter for your platform's patchset.
Alright, although I haven't pretended that v2 patches should be merged right away since they are fundamentally different from v1, and thus, all patches need to be reviewed first.
If the current OPP changes look good to you, then please give yours r-b to the patches. Thanks in advance!
Quoted 3 lines · Dmitry Osipenko
Alright, although I haven't pretended that v2 patches should be merged right away since they are fundamentally different from v1, and thus, all patches need to be reviewed first.
I agree. I have done some basic review for the stuff.
Quoted 2 lines
If the current OPP changes look good to you, then please give yours r-b to the patches. Thanks in advance!
r-b-y isn't required as they will go through my tree itself. So if everyone is happy with the idea, please submit the patches separately (fixes, improvements, devm_*, etc).
Signature · 1 line
viresh
22.12.2020 12:15, Viresh Kumar пишет:
Quoted 6 lines · Dmitry Osipenko
Quoted 3 lines
Alright, although I haven't pretended that v2 patches should be merged right away since they are fundamentally different from v1, and thus, all patches need to be reviewed first.
I agree. I have done some basic review for the stuff.
Thank you for the review.
Quoted 6 lines
Quoted 2 lines
If the current OPP changes look good to you, then please give yours r-b to the patches. Thanks in advance!
r-b-y isn't required as they will go through my tree itself. So if everyone is happy with the idea, please submit the patches separately (fixes, improvements, devm_*, etc).
okay
Krzysztof Kozlowski
maintainerQuoted 20 lines · Dmitry Osipenko
Introduce core voltage scaling for NVIDIA Tegra20/30 SoCs, which reduces power consumption and heating of the Tegra chips. Tegra SoC has multiple hardware units which belong to a core power domain of the SoC and share the core voltage. The voltage must be selected in accordance to a minimum requirement of every core hardware unit.
The minimum core voltage requirement depends on:
1. Clock enable state of a hardware unit.
2. Clock frequency.
3. Unit's internal idling/active state.This series is tested on Acer A500 (T20), AC100 (T20), Nexus 7 (T30), Ouya (T30), TK1 (T124) and some others. I also added voltage scaling to the Ventana (T20) and Cardhu (T30) boards which are tested by NVIDIA's CI farm. Tegra30 is now couple degrees cooler on Nexus 7 and stays cool on Ouya (instead of becoming burning hot) while system is idling. It should be possible to improve this further by implementing a more advanced power management features for the kernel drivers.
Quoted 4 lines
The DVFS support is opt-in for all boards, meaning that older DTBs will continue to work like they did it before this series. It should be possible to easily add the core voltage scaling support for Tegra114+ SoCs based on this grounding work later on, if anyone will want to implement it.
The same comment as for your interconnect work: for sets touching multiple systems please mention the dependencies between patches in the cover letter. Not as a reply to such remark like I make here, but as a separate entry in the cover letter.
Best regards,
Krzysztof
_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel
05.01.2021 20:11, Krzysztof Kozlowski пишет:
Quoted 26 lines · Dmitry Osipenko
Quoted 20 lines
Introduce core voltage scaling for NVIDIA Tegra20/30 SoCs, which reduces power consumption and heating of the Tegra chips. Tegra SoC has multiple hardware units which belong to a core power domain of the SoC and share the core voltage. The voltage must be selected in accordance to a minimum requirement of every core hardware unit.
The minimum core voltage requirement depends on:
1. Clock enable state of a hardware unit.
2. Clock frequency.
3. Unit's internal idling/active state.This series is tested on Acer A500 (T20), AC100 (T20), Nexus 7 (T30), Ouya (T30), TK1 (T124) and some others. I also added voltage scaling to the Ventana (T20) and Cardhu (T30) boards which are tested by NVIDIA's CI farm. Tegra30 is now couple degrees cooler on Nexus 7 and stays cool on Ouya (instead of becoming burning hot) while system is idling. It should be possible to improve this further by implementing a more advanced power management features for the kernel drivers.
Quoted 4 lines
The DVFS support is opt-in for all boards, meaning that older DTBs will continue to work like they did it before this series. It should be possible to easily add the core voltage scaling support for Tegra114+ SoCs based on this grounding work later on, if anyone will want to implement it.
Quoted 4 lines
The same comment as for your interconnect work: for sets touching multiple systems please mention the dependencies between patches in the cover letter. Not as a reply to such remark like I make here, but as a separate entry in the cover letter.
I'll describe all the dependencies in the next revision, thanks.